Skip to content

Commit deb4da4

Browse files
feat: add two new rules around class transformer decorators
1 parent b850159 commit deb4da4

File tree

10 files changed

+599
-73
lines changed

10 files changed

+599
-73
lines changed

README.md

Lines changed: 125 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ Version 3.x supports Eslint version >=8.x and typescript eslint parser 5+
66

77
There were many breaking changes between these versions.
88

9-
## Index of Available rules
9+
## Index of available rules
1010

11-
Details for each rule are available in sections below.
11+
(more details for each specific rule are available in sections below)
1212

13-
Nest Modules
13+
Nest Modules and Dependency Injection
1414

1515
- provided-injected-should-match-factory-parameters
1616
- injectable-should-be-provided
@@ -26,14 +26,16 @@ Nest Swagger
2626
Preventing bugs
2727

2828
- param-decorator-name-matches-route-param
29+
- validate-nested-of-array-should-set-each
30+
- validated-non-primitive-property-needs-type-decorator
2931

3032
Security
3133

3234
- should-specify-forbid-unknown-values
3335

3436
## Why use this package?
3537

36-
If you use NestJs (https://nestjs.com/) then these rules will help keep you usage of decorators consistent.
38+
If you use NestJs (https://nestjs.com/) then these rules will help you to prevent common bugs and issues. They mostly check that you are using decorators correctly.
3739

3840
See the following summaries
3941

@@ -101,13 +103,123 @@ Note: You can easily turn off all the swagger rules if you don't use swagger by
101103
// more config
102104
```
103105

106+
Disable a single rule with the full name e.g. in your eslint configuration...
107+
108+
```
109+
rules: {
110+
"@darraghor/nestjs-typed/api-property-returning-array-should-set-array":
111+
"off",
112+
}
113+
```
114+
104115
## Rule Details
105116

117+
### Rule: validate-nested-of-array-should-set-each
118+
119+
If you use the `@ValidateNested` decorator you should specify the `{each: true}` option if the property is an array.
120+
121+
This PASSES because it's an array and each is set
122+
123+
```ts
124+
export class CreateOrganisationDto {
125+
@ApiProperty({type: Person, isArray: true})
126+
@ValidateNested({each: true})
127+
members!: MyClass[];
128+
}
129+
```
130+
131+
This PASSES because it's an array and each is set
132+
133+
```ts
134+
export class CreateOrganisationDto {
135+
@ApiProperty({type: Person, isArray: true})
136+
@ValidateNested({each: true})
137+
members!: Array<MyClass>;
138+
}
139+
```
140+
141+
This PASSES because it's not an array and each is not set
142+
143+
```ts
144+
export class CreateOrganisationDto {
145+
@ApiProperty({type: Person, isArray: true})
146+
@ValidateNested()
147+
members!: MyClass;
148+
}
149+
```
150+
151+
This FAILS because it's not an array and each is set
152+
153+
```ts
154+
export class CreateOrganisationDto {
155+
@ApiProperty({type: Person, isArray: true})
156+
@ValidateNested({each: true})
157+
members!: MyClass;
158+
}
159+
```
160+
161+
### Rule: validated-non-primitive-property-needs-type-decorator
162+
163+
If you use any of the class validator decorators on a property that is not a primitive, you should tell class-transformer how to transform it into a class first.
164+
165+
This PASSES because we're validating a Person class and we have added the @Type decorator.
166+
167+
```ts
168+
export class CreateOrganisationDto {
169+
@ApiProperty({type: Person, isArray: true})
170+
@IsDefined()
171+
@Type(() => Person)
172+
members!: Person;
173+
}
174+
```
175+
176+
This PASSES because it is a primitive type (boolean, string, number). We don't need to tell class-transformer how to transform those.
177+
178+
```ts
179+
export class CreateOrganisationDto {
180+
@ApiProperty({type: Person, isArray: true})
181+
@ValidateNested({each: true})
182+
@IsBoolean()
183+
members!: boolean;
184+
}
185+
```
186+
187+
This PASSES because we only check properties that have a class-validator decorator (e.g. `@IsDefined()`)
188+
189+
```ts
190+
export class CreateOrganisationDto {
191+
@ApiProperty({type: Person, isArray: true})
192+
members!: Person | Date;
193+
}
194+
```
195+
196+
This FAILS because you should always tell class-transformer the type for an array
197+
198+
```ts
199+
export class CreateOrganisationDto {
200+
@ApiProperty({type: Person, isArray: true})
201+
@ValidateNested({each: true})
202+
@IsArray()
203+
members!: (Person | Date)[];
204+
}
205+
```
206+
207+
This FAILS because Date is not a primitive type (string, number, boolean)
208+
209+
```ts
210+
export class CreateOrganisationDto {
211+
@ApiProperty({type: Person, isArray: true})
212+
@ValidateNested({each: true})
213+
@IsDate()
214+
members!: Date;
215+
}
216+
```
217+
106218
### Rule: param-decorator-name-matches-route-param
107219

108220
This rule will verify you have entered a `Param("name")` that has a matching url parameter in a controller or method decorator
109221

110-
e.g. this passes because the uuid param is in the `Get()` decorator
222+
this PASSES because the uuid param is in the `Get()` decorator
111223

112224
```ts
113225
@Controller("custom-bot")
@@ -125,7 +237,7 @@ export class CustomBotController {
125237
}
126238
```
127239

128-
this passes because the uuid param is in the `Controller()` decorator
240+
this PASSES because the uuid param is in the `Controller()` decorator
129241

130242
```ts
131243
@Controller("custom-bot/:uuid")
@@ -143,7 +255,7 @@ export class CustomBotController {
143255
}
144256
```
145257

146-
This fails because there is a typo in the param decorator
258+
This FAILS because there is a typo in the param decorator
147259

148260
```ts
149261
@Controller("custom-bot")
@@ -161,7 +273,7 @@ export class CustomBotController {
161273
}
162274
```
163275

164-
this fails because you shouldn't put the `:` in the param decorator
276+
this FAILS because you shouldn't put the `:` in the param decorator
165277

166278
```ts
167279
@Controller("custom-bot")
@@ -183,7 +295,7 @@ export class CustomBotController {
183295

184296
This checks when if you are setting ValidationPipe parameters you set forbidUnknownValues to true.
185297

186-
e.g. this passes
298+
e.g. this PASSES because the property is set
187299

188300
```ts
189301
const validationPipeB = new ValidationPipe({
@@ -192,23 +304,23 @@ const validationPipeB = new ValidationPipe({
192304
});
193305
```
194306

195-
this fails because property is not set
307+
this FAILS because property is not set
196308

197309
```ts
198310
const validationPipeB = new ValidationPipe({
199311
forbidNonWhitelisted: true,
200312
});
201313
```
202314

203-
this fails because property is set to false
315+
this FAILS because property is set to false
204316

205317
```ts
206318
const validationPipeB = new ValidationPipe({
207319
forbidNonWhitelisted: false,
208320
});
209321
```
210322

211-
this passes because the default values seem to work ok
323+
this PASSES because the default values seem to work ok
212324

213325
```ts
214326
const validationPipeB = new ValidationPipe();
@@ -218,7 +330,7 @@ const validationPipeB = new ValidationPipe();
218330

219331
Checks that there are the same number of injected items in a Provider that are passed to the factory method
220332

221-
Passes (Myservide injected and myservice used in factory params)
333+
PASSES because `Myservice` injected and `myservice` used in factory params
222334

223335
```ts
224336
export const MyOtherInjectableProvider: NotAProvider = {

src/configs/recommended.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,9 @@ export = {
2323
"@darraghor/nestjs-typed/should-specify-forbid-unknown-values": "error",
2424
"@darraghor/nestjs-typed/param-decorator-name-matches-route-param":
2525
"error",
26+
"@darraghor/nestjs-typed/validated-non-primitive-property-needs-type-decorator":
27+
"error",
28+
"@darraghor/nestjs-typed/validate-nested-of-array-should-set-each":
29+
"error",
2630
},
2731
};

src/rules/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import apiEnumPropertyBestPractices from "./apiEnumPropertyBestPractices/apiEnum
77
import apiPropertyReturningArrayShouldSetArray from "./apiPropertyReturningArrayShouldSetArray/apiPropertyReturningArrayShouldSetArray";
88
import shouldSpecifyForbidUnknownValues from "./shouldSpecifyForbidUnknownValues/shouldSpecifyForbidUnknownValuesRule";
99
import parameterDecoratorNameMatchesRouteParam from "./paramDecoratorNameMatchesRouteParam/paramDecoratorNameMatchesRouteParam";
10+
import validateNonPrimitiveNeedsDecorators from "./validate-non-primitves-needs-type-decorator/validateNonPrimitiveNeedsDecorators";
11+
import validateNestedOfArrayShouldSetEach from "./validateNestedOfArrayShouldSetEach/validateNestedOfArrayShouldSetEach";
1012

1113
const allRules = {
1214
"api-property-matches-property-optionality":
@@ -23,6 +25,10 @@ const allRules = {
2325
"should-specify-forbid-unknown-values": shouldSpecifyForbidUnknownValues,
2426
"param-decorator-name-matches-route-param":
2527
parameterDecoratorNameMatchesRouteParam,
28+
"validated-non-primitive-property-needs-type-decorator":
29+
validateNonPrimitiveNeedsDecorators,
30+
"validate-nested-of-array-should-set-each":
31+
validateNestedOfArrayShouldSetEach,
2632
};
2733

2834
export default allRules;

src/rules/validate-non-primitves-needs-decorators/validateNonPrimitiveNeedsDecorators.ts

Lines changed: 0 additions & 60 deletions
This file was deleted.

0 commit comments

Comments
 (0)