darraghoriordan / eslint-plugin-nestjs-typed Goto Github PK
View Code? Open in Web Editor NEWSome eslint rules for working with NestJs projects
Home Page: http://www.darraghoriordan.com
Some eslint rules for working with NestJs projects
Home Page: http://www.darraghoriordan.com
Controllers and Services should not have properties, apart from the ones injected via DI (e.g. in the constructor).
There was a similar rule in this POC, I think it's a very nice rule: https://github.com/unlight/eslint-plugin-nestjs/blob/master/src/use-dependency-injection/use-dependency-injection.md
Would it be possible to expand the module to use it to enforce rest naming conventions for endpoints?
https://restfulapi.net/resource-naming/
Essentially to check the Controller
, Get
, Post
, Put
, Delete
.. decorators if a proper naming was used for the endpoint:
This PASSES
@Controller('tests')
class TestClass {
@Get()
public getAll() {
}
}
This FAILS, because the resource is not plural
@Controller('test')
class TestClass {
@Get()
public getAll() {
}
}
This PASSES
@Controller('tests')
class TestClass {
@Get('some-param/:someParam')
public getByParam(@Param('someParam') param) {
}
}
This FAILS, because camel case was used to name the resource
@Controller('tests')
class TestClass {
@Get('getByParam/:someParam')
public getByParam(@Param('someParam') param) {
}
}
I have next rule:
'@darraghor/nestjs-typed/injectable-should-be-provided': [
'error',
{
src: ['src/**/*.ts'],
filterFromPaths: ['node_modules', '.test.', '.spec.', 'jest.config.ts', 'tsconfig.spec.json', 'tsconfig.scripts.json'],
},
],
and got next error
> nx run api:lint
Linting "api"...
> NX Error while loading rule '@darraghor/nestjs-typed/injectable-should-be-provided': No files matching 'src/**/*.ts' were found.
Occurred while linting /..****../..[projectRootfolder]../apps/api/jest.config.ts
Pass --verbose to see the stacktrace.
--verbose add stacktrace, here is first lines:
Error: Error while loading rule '@darraghor/nestjs-typed/injectable-should-be-provided': All files matched by '**/*.ts' are ignored.
Occurred while linting /..****../..[projectRootfolder]../apps/api/jest.config.ts
at FileEnumerator.iterateFiles (/..****../..[projectRootfolder]../node_modules/eslint/lib/cli-engine/file-enumerator.js:326:27)
We use this lint rule to ensure all of our API methods define their response types. We also have an additional decorator we want the linter to recognize: @ApiPaginatedResponse(SomeDataType)
that defines a paginated response of some data type. What do you think about adding some way to include custom decorators in this linter?
The usage of @Inject()
without some provider's token on parameters is invalid (due to TS limitations, AFIAK). And I didn't succeded on making it fail at build time. So, as of now, we will see a 'dependency not found' error at runtime. This could confuse people.
My suggestion is adding a rule to forbids such usage
import { Module, Inject, forwardRef } from '@nestjs/common';
class FooService {}
@Module({
providers: [FooService]
})
export class AppModule {
@Inject(forwardRef(() => FooService))
public readonly service: FooService;
@Inject() private readonly validInjectUsage: FooService
constructor(
/*
@Inject(forwardRef(() => FooService)) private valid: FooService
,
@Inject(undefined) private valid2: FooService
,
@Inject('') private valid3: FooService
// ,
*/
@Inject() private invalid: FooService // <<< this should error out as 'you must pass a token'
) {}
}
We do have routes which have the URL put into a variable like @Put(FILTERS_URL)
leading to Param decorators with identifiers e.g. Param("myvar") should match a specified route parameter - e.g. Get(":myvar")
The value of FILTERS_URL
is ":employerId/major-medical-plans/filters"
and the param is @Param('employerId', new ParseUUIDPipe()) employerId: string
I would recommend to just not report on issues like there were no certainty is guaranteed.
The other edge case is similar: it's a route with template literals like
@Put(`onboarding-periods/:id/${MAJOR_MEDICAL_PLAN_URL}`)
where the param is @Param('id') periodId: string
. Changing the template literal temporarily to double or single quotes removes the eslint issue.
since @nestjs/core
v10.2.0 we can use the DiscoveryService.createDecorator
to create type-safe decorators
but we shouldn't be using them multiple times like this:
I'm not sure if this is feasbile to achieve as a lint rule.
sample code: https://stackblitz.com/edit/nestjs-discovery-service-issue-bt5oae
I don't know what's wrong with this, but it requires me to use @ApiPropertyOptional, even If I use it, it still gives me an error
@ApiPropertyOptional()
@ApiProperty({ description: 'If it is an event, use dateFrom and dateTo' })
@IsOptional()
@IsDate()
dateFrom?: Date;
@ApiPropertyOptional({})
@IsOptional()
@ApiProperty({ description: 'If it is an event, use dateFrom and dateTo' })
dateTo?: Date;
ESLint: Property marked as optional should use @ApiPropertyOptional decorator(@darraghor/nestjs-typed/api-property-matches-property-optionality
The lint rule mentioned above encounters this code and fails:
searchProvidersReturn = (providers: IdeonProvider[]) => {
return providers.map((provider) => {
const entity: Provider = { // THIS LINE
id: provider.id,
firstName: provider.first_name,
middleName: provider.middle_name,
lastName: provider.last_name,
suffix: provider.suffix,
title: provider.title,
presentationName: provider.presentation_name,
gender: provider.gender,
npis: provider.npis,
phone: provider.phone,
email: provider.email,
specialty: provider.specialty,
addresses: provider.addresses,
};
return entity;
});
};
The stacktrace is as follows:
> nx run backend:lint
Linting "backend"...
> NX Cannot read properties of undefined (reading 'params')
Occurred while linting /home/user/Webdevelopment/Freelancing/Client/repository/apps/backend/src/insurance/insurance.service.ts:77
Rule: "@darraghor/nestjs-typed/provided-injected-should-match-factory-parameters"
TypeError: Cannot read properties of undefined (reading 'params')
Occurred while linting /home/user/Webdevelopment/Freelancing/Client/repository/apps/backend/src/insurance/insurance.service.ts:77
Rule: "@darraghor/nestjs-typed/provided-injected-should-match-factory-parameters"
at hasMismatchedInjected (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/@[email protected]_@[email protected]_class-validator_h7qfkjnhkslhix4uwhkjr3zqvq/node_modules/@darraghor/eslint-plugin-nestjs-typed/dist/rules/providerInjectedShouldMatchFactory/ProviderInjectedShouldMatchFactory.js:19:182)
at VariableDeclarator (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/@[email protected]_@[email protected]_class-validator_h7qfkjnhkslhix4uwhkjr3zqvq/node_modules/@darraghor/eslint-plugin-nestjs-typed/dist/rules/providerInjectedShouldMatchFactory/ProviderInjectedShouldMatchFactory.js:48:55)
at ruleErrorHandler (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/linter.js:1045:28)
at /home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/safe-emitter.js:45:58
at Array.forEach (<anonymous>)
at Object.emit (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
at NodeEventGenerator.applySelector (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
at NodeEventGenerator.applySelectors (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
at NodeEventGenerator.enterNode (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/node-event-generator.js:340:14)
at CodePathAnalyzer.enterNode (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js:795:23)
injectable-should-be-provided
expect providers to be an array, otherwise it may fail with NPE:
TypeError: Cannot read properties of undefined (reading 'map')
https://github.com/WiseBird/eslint-plugin-nestjs-issue-shorthand (commit)
Works:
@Module({
imports: [],
controllers: [AppController],
providers: [AppService],
})
Moving the array into a variable doesn't:
let providers = [AppService];
@Module({
imports: [],
controllers: [AppController],
providers: providers, <--
})
Shorthand syntax doesn't work as well:
let providers = [AppService];
@Module({
imports: [],
controllers: [AppController],
providers, <--
})
The error happens when we try to iterate the elements:
if (optionProperty) {
return new Set(
(
(optionProperty as unknown as TSESTree.Property)
.value as TSESTree.ArrayExpression
).elements.map( <--
(element) => (element as TSESTree.Identifier).name
)
);
}
I understand that's it's a rabbit hole. You also can import providers array from somewhere or construct it dynamically or whatever.
But maybe covering a case when providers array is moved to a variable (which is often done to use it in exports
) worth doing.
The rule validated-non-primitive-property-needs-type-decorator
is erroring for optional enum properties.
This is a regression from previous versions which prevents me from updating the package for quite some time now.
For example:
enum Bar {}
export class Foo {
@ApiProperty({
enum: Bar,
enumName: "Bar",
})
@IsOptional()
baz!: Bar | null;
}
Or:
enum Baz {}
class Foo {
@ApiPropertyOptional({
enum: Baz,
enumName: "Baz",
required: false,
isArray: true,
})
@IsOptional()
bar?: Baz[];
}
We use the same validation pipe for the application code and unit tests. To make it reusable, we created an object to store the validation pipe options like this:
app.useGlobalPipes(
new ValidationPipe({
...validationPipeOptions,
})
);
This breaks the linting, the stack trace looks like this:
> nx run backend:lint
Linting "backend"...
> NX Cannot read properties of undefined (reading 'name')
Occurred while linting /home/user/Webdevelopment/Freelancing/Client/repository/apps/backend/src/test/controller-utils.ts:76
Rule: "@darraghor/nestjs-typed/should-specify-forbid-unknown-values"
TypeError: Cannot read properties of undefined (reading 'name')
Occurred while linting /home/user/Webdevelopment/Freelancing/Client/repository/apps/backend/src/test/controller-utils.ts:76
Rule: "@darraghor/nestjs-typed/should-specify-forbid-unknown-values"
at /home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/@[email protected]_@[email protected]_class-validator_h7qfkjnhkslhix4uwhkjr3zqvq/node_modules/@darraghor/eslint-plugin-nestjs-typed/dist/rules/shouldSpecifyForbidUnknownValues/shouldSpecifyForbidUnknownValuesRule.js:19:160
at Array.find (<anonymous>)
at checkObjectExpression (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/@[email protected]_@[email protected]_class-validator_h7qfkjnhkslhix4uwhkjr3zqvq/node_modules/@darraghor/eslint-plugin-nestjs-typed/dist/rules/shouldSpecifyForbidUnknownValues/shouldSpecifyForbidUnknownValuesRule.js:19:142)
at shouldTriggerNewExpressionHasProperty (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/@[email protected]_@[email protected]_class-validator_h7qfkjnhkslhix4uwhkjr3zqvq/node_modules/@darraghor/eslint-plugin-nestjs-typed/dist/rules/shouldSpecifyForbidUnknownValues/shouldSpecifyForbidUnknownValuesRule.js:49:46)
at NewExpression (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/@[email protected]_@[email protected]_class-validator_h7qfkjnhkslhix4uwhkjr3zqvq/node_modules/@darraghor/eslint-plugin-nestjs-typed/dist/rules/shouldSpecifyForbidUnknownValues/shouldSpecifyForbidUnknownValuesRule.js:86:82)
at ruleErrorHandler (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/linter.js:1045:28)
at /home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/safe-emitter.js:45:58
at Array.forEach (<anonymous>)
at Object.emit (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
at NodeEventGenerator.applySelector (/home/user/Webdevelopment/Freelancing/Client/repository/node_modules/.pnpm/[email protected]/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
It works fine when using it as intended like:
app.useGlobalPipes(
new ValidationPipe({
forbidUnknownValues: false
})
);
can you please participate on Hacktoberfest 2023? I'm looking for nestjs-related repos that I could contribute to on October.
You just need to add the hacktoberfest
topic to this repository
thanks anyway!
Currently this rule will skip if the parameter is of type Identifier or TemplateLiteral. Along the same lines, I believe it should skip if the parameter is of type MemberExpression (Enum or Static Class Method).
For example, the below will trigger an error.
enum AppRoutes {
Root = 'app',
VerifyParams = ':id',
}
@Controller(AppRoutes.Root)
export class AppController {
@Post(AppRoutes.VerifyParams)
verifyParams(@Param('id', ParseUUIDPipe) id: string): VerifyParamsResponseDto {
return new VerifyParamsResponseDto({ token: id });
}
}
Another option would be to skip if the parameter is not of type Literal, ArrayExpression, or ObjectExpression.
First I have to say "Amazing plugin !!"
Get this error in the VSCode ESlint output when running your plugin with the recommended settings.
Error while loading rule '@darraghor/nestjs-typed/injectable-should-be-provided': No files matching 'src/**/*.ts' were found. Occurred while linting /Users/vic1707/Desktop/TESTS/monorepo/apps/monorepo-api/src/app.controller.spec.ts
here are my configs:
{
"$schema": "https://json.schemastore.org/eslintrc",
"parserOptions": {
"sourceType": "module",
"ecmaVersion": "latest",
"project": ["tsconfig.json"]
},
"plugins": [
"@darraghor/nestjs-typed"
],
"extends": [
"../.eslintrc",
"plugin:@darraghor/nestjs-typed/recommended"
],
"rules": {
"@darraghor/nestjs-typed/injectable-should-be-provided": "off" // <- only way to prevent the error
}
}
the .eslintrc
it's extending
{
"$schema": "https://json.schemastore.org/eslintrc",
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint",
"import",
"prettier",
"simple-import-sort",
"unused-imports"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"prettier"
],
"env": {
"browser": false,
"jest": true,
"es6": true
},
"rules": {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/indent": "off",
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{
"varsIgnorePattern": "_"
}
],
"import/no-deprecated": "error",
"import/no-duplicates": [
"error",
{
"considerQueryString": true
}
],
"no-duplicate-imports": "off",
"prettier/prettier": "error",
"simple-import-sort/exports": "error",
"simple-import-sort/imports": "error",
"unused-imports/no-unused-imports": "error"
}
}
the file structure in case you need it
.
├── .eslintrc
├── .gitignore
├── README.md
├── nest-cli.json
├── package.json
├── src
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ └── main.ts
├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
I have some custom class-validator decorators that I would like to enforce this rule on. Currently, we detect if an import is a class-validator
import by detecting if the import is from class-validator
. This prevents the rule from being enforced when custom validators are applied.
customClassValidatorDecorators
which will take in a list of decorator names to check. This is a simple string match check, but has the con of naming collisions if for whatever reason we have other decorators of the same name within the project not meant for validation. It is also consistent with the current additionalTypeDecorators
options api.injectable-should-be-provided
fails if a class has a not callable decorator:
@boundClass
@Injectable()
export class AppService {
The error:
TypeError: Cannot read properties of undefined (reading 'name')
happens when we try to get the name of the decorator:
const decorators = n.decorators?.filter((d) =>
decoratorNames.includes(
(
(d.expression as TSESTree.CallExpression)
.callee as TSESTree.Identifier
).name <--
)
);
https://github.com/WiseBird/eslint-plugin-nestjs-issue-decorator (commit)
as mentioned here: nestjs/docs.nestjs.com#2178 we can't do app.get(APP_GUARD)
/app.get(APP_PIPE)
/app.get(APP_FILTER)
/app.get(APP_INTERCEPTOR)
due to how those "providers" works. I tested it myself.
thus I'd like to have a rule that forbids calling app.get
over then so we can prevent misusages that will lead to runtime errors
Also, I believe we can extend this to @Inject(APP_*)
as well due to the same reason
Hi,
I'm just playing with your project (thank you very much to share it ;-) )
And I'm just thinking there is maybe an issue with a test in all-properties-are-whitelisted rule.
If I'm right, this rule checks all properties have at least one validation decorator.
However in this valid test in allPropertiesAreWhitelisted.spec.ts (line ~53)
import { IsInt } from 'sequelize-typescript';
class A {
@IsInt()
b: string
b: string
}
I expect this piece of code to be invalid because a validator is missing in second b class member.
Watching at the code, I think this condition is invalid in some cases:
if (withDecorator.length > 0 && withoutDecorator.length > 0) {
If all properties have no class-validator decorator, withDecorator
array will contain nothing and the nested statement won't be called event if withoutDecorator contains some values. So no error will be reported.
If this is correct there are other valid tests that are invalid
What do you think ?
Thank you ;-)
if I have the following:
@Get(":app?")
@ApiOperation({ summary: "Return Releases" })
@ApiResponse({
isArray: true,
status: 200,
description: "Releases list is returned successfully."
})
async getReleases(@Param("app") app: SomeApp | undefined): Promise<ReleaseDto[]> {
return this.queryBus.execute<ReleasesQuery, ReleaseDto[]>(new ReleasesQuery(app));
}
list produces an error saying:
Param decorators with identifiers e.g. Param("myvar") should match a specified route parameter - e.g. Get(":myvar")
but this if I add '?' to the @Param("app?")
, the controller doesn't work anymore (actual param value is always undefined).
Thanks for this library, it's really useful and great.
I have a task on my job to add @ApiOperation decorators throughout the whole api...
So I expected there is a rule to lint lack of this kind of decorator, but didn't find it
// valid
class Example {
@ApiProperty({ isArray: true })
@ValidateNested({ each: true })
// @Type(() => Foo)
repositories!: Foo[];
}
// invalid
class Example {
@ApiProperty()
@ValidateNested()
// @Type(() => Foo)
repositories!: Foo;
}
Here's a property of some union type with a validation decorator:
@ApiProperty({
enum: ["planned", "failed", "blocked", "in-progress"]
})
@IsIn(RELEASE_STATUSES)
status!: ReleaseStatus;
and the ReleaseStatus
defined as follows:
export const RELEASE_STATUSES = ["planned", "failed", "blocked", "in-progress", "released"];
export type ReleaseStatus = typeof RELEASE_STATUSES[number];
When I run lint I get:
A non-primitve property with validation should probably use a @type decorator @darraghor/nestjs-typed/validated-non-primitive-property-needs-type-decorator
I'm not sure if I'm wrong somewhere or the rule doesn't work here...
Another variant is with a simple type aliasing:
export type ReleaseManager = string;
@IsNotEmpty()
releaseManager!: ReleaseManager;
This produces same error.
enum Foo {
BAR
}
// invalid
class Example
@ApiProperty({ enum: Foo, enumName: 'Foo' })
@Allow()
format!: Foo;
}
I got here after reading your https://www.darraghoriordan.com/2021/11/06/how-to-write-an-eslint-plugin-typescript/ article, which was a huge help. However, the piece that's missing for me is once I'm done, how to publish to an npm repo so it's usable. Looking at this repo I don't see publish details.
For example, your NPM module, when I install it, looks quite different than my structure. Where'd the index.d.ts file you publish come from? If you would be willing to update your tutorial, that would be really helpful. Thanks.
Some rules from this plugin are named in singular:
while others are named in plural
this is a bit misleading when configuring the rule severity in the eslintrc
I was trying "api-methods-should-specify-api-response" instead of the singular form
Consider the following classes
@Injectable()
export class MyClassA {
constructor(private readonly myInstaceB : MyClassB) {}
//[...] implementation
}
export class MyClassB {
//[...] implementation
}
Note that class B is not injectable.
In the constructor line in class A, I want the eslint check to highlight that the myInstanceB cannot be instantiated because MyClassB is not injectable
I'm new to NestJS but have learned a lot in the past few weeks. One of those things is that it's possible to set route params using the built-in RouterModule.register()
function.
Now, I noticed in the TicketController (which is the Controller used by the TicketModule), I cannot access the declared :columnid
param. I've checked the express req.params
object and it does contain this param with the correct value. Is it possible for this rule to be updated to check if any Module uses the RouterModule.register()
function and, if so, check for any registered params?
I understand my request may be a relatively specific use-case, maybe even an edge-case, but given the scalability of my application it would make it much harder to manage if I needed to specify each path-piece in every submodule or controller.
In many codebases I see code like
@ApiProperty({
required: true
// other properties like description, example etc.
})
required: true
is by default in @ApiProperty
, no need to override it. It provides unnecessary complexity and it's just a boilerplate. As we already have api-property-matches-property-optionality
it would be nice to have something like api-property-no-redundant-required
. Or we can expand api-property-matches-property-optionality
and add option like "no-redundant-required".
WDYT?
@darraghor/nestjs-typed/validated-non-primitive-property-needs-type-decorator does not understand that types of primitive array | null
does not need a @type decorator
Example
class GetUserReq {
@IsString({each: true})
emails: string[] | null
}
Linter would tell us we need to have a Type
decorator when we do not need it. The error disappears when i remove the union with null
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates are awaiting their schedule. Click on a checkbox to get an update now.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
actions/checkout
, renovatebot/github-action
)@types/eslint
, @types/node
, lint-staged
, semantic-release
, ts-jest
, typescript
)@typescript-eslint/eslint-plugin
, @typescript-eslint/parser
, @typescript-eslint/rule-tester
, @typescript-eslint/scope-manager
, @typescript-eslint/utils
, semantic-release
)eslint
, eslint-plugin-unicorn
).github/workflows/build-test.yaml
actions/checkout v4@0ad4b8fadaa221de15dcec353f45205ec38ea70b
actions/setup-node v4@60edb5dd545a775178f52524783378180af0d1f8
.github/workflows/lintPrTitle.yaml
amannn/action-semantic-pull-request v5.5.2@cfb60706e18bc85e8aec535e3c577abe8f70378e
.github/workflows/publishToNpm.yaml
actions/checkout v4@0ad4b8fadaa221de15dcec353f45205ec38ea70b
actions/setup-node v4@60edb5dd545a775178f52524783378180af0d1f8
.github/workflows/rennovate.yaml
actions/checkout v4.1.1@b4ffde65f46336ab88eb53be808477a3936bae11
renovatebot/github-action v40.1.9@74811c93da74bf38cb37f41489065619930fba44
package.json
@typescript-eslint/scope-manager 7.7.1
@typescript-eslint/utils 7.7.1
eslint-module-utils 2.8.1
reflect-metadata 0.2.2
@commitlint/cli 19.3.0
@commitlint/config-conventional 19.2.2
@semantic-release/changelog 6.0.3
@semantic-release/exec 6.0.3
@types/eslint 8.56.7
@types/jest 29.5.12
@types/node 20.12.3
@typescript-eslint/eslint-plugin 7.7.1
@typescript-eslint/parser 7.7.1
@typescript-eslint/rule-tester 7.7.1
class-validator ^0.14.1
eslint 8.57.0
eslint-config-prettier 9.1.0
eslint-plugin-prefer-arrow 1.2.3
eslint-plugin-unicorn 51.0.1
husky 9.0.11
jest 29.7.0
jest-create-mock-instance 2.0.0
jest-junit 16.0.0
lint-staged 15.2.2
prettier 3.2.5
semantic-release 23.0.6
ts-jest 29.1.2
ts-node 10.9.2
typescript 5.4.3
node ^18.18.0 || >=20.0.0
.nvmrc
Hey,
first of all, thanks a lot for this perfect library :) After taking a look into the documentation of the rule: api-method-should-specify-api-operation, i noticed that there might be an error regarding the expected decorator. The corresponding implementation checks for the right decorators: ApiResponse(...), ...
, but the title of the rule is confusing. I would assume a rule title like api-method-should-specify-api-response not api-method-should-specify-api-operation.
Can i create a pull request for it?
main
branch failed. 🚨I recommend you give this issue a high priority, so other packages depending on you can benefit from your bug fixes and new features again.
You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can fix this 💪.
Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.
Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the main
branch. You can also manually restart the failed CI job that runs semantic-release.
If you are not sure how to resolve this, here are some links that can help you:
If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.
semantic-release cannot push the version tag to the branch main
on the remote Git repository with URL https://[secure]@github.com/darraghoriordan/eslint-plugin-nestjs-typed
.
This can be caused by:
Good luck with your project ✨
Your semantic-release bot 📦🚀
It is helpful if we are able to exclude some data types or list decorators that are identical in functionality to the @Type
decorator.
For example, we are currently using custom transformers for Map<>
and Date
, and altho these decorators take care of all these, this rule still nags about not having the Type
decorator which is not required at all; but for this reason, we had to disable it which is unfortunate since it is a very good rule to have active.
Here, TransformDate
takes care of transformation and no Type
decorator is required:
@ApiPropertyOptional(
{
description: "Filter by date",
required: false,
writeOnly: true,
}
)
@Expose()
@IsOptional()
@TransformDate()
@IsDate()
public fromDate?: Date;
Having options to disable this rule for one or more data types, or disable it when another decorator is used will be very useful for more complex projects.
And thanks for this plugin, very useful for staying away from possible pitfalls.
When executing the ESLint in my NestJS project the following error occurs:
Y esta es mi configuracion de ESLint:
module.exports = {
env: {
es6: true,
},
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:@darraghor/nestjs-typed/recommended', "plugin:prettier/recommended", "prettier"],
parser: '@typescript-eslint/parser',
parserOptions: {
project: ['./tsconfig.json'],
sourceType: 'module',
ecmaVersion: 'es2019',
},
rules: {
eqeqeq: 'off',
curly: 'error',
quotes: ['error', 'single'],
indent: [2, 2, { SwitchCase: 1 }],
semi: ['error', 'never'],
'array-callback-return': ['error', { allowImplicit: true }],
'no-irregular-whitespace': ['error', { skipComments: true, skipRegExps: true, skipTemplates: true }],
'no-multi-spaces': ['error'],
'block-spacing': 'error',
'keyword-spacing': ['error', { before: true, after: true }],
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 1, maxBOF: 1 }],
'sort-imports': [
'error',
{
ignoreCase: true,
ignoreDeclarationSort: true,
ignoreMemberSort: false,
memberSyntaxSortOrder: ['none', 'all', 'single', 'multiple'],
allowSeparatedGroups: false
}
],
'object-curly-newline': ['error', { multiline: true }],
'object-curly-spacing': ['error', 'always'],
'no-unused-vars': ['error', { vars: 'all', args: 'none', ignoreRestSiblings: false }],
'max-len': ['error', { tabWidth: 4, comments: 120, code: 5000 }],
'@typescript-eslint/no-explicit-any': 'off',
'prettier/prettier': [
'error',
{
trailingComma: 'none',
tabWidth: 2,
semi: false,
singleQuote: true,
parser: 'typescript',
eslintIntegration: true,
endOfLine: 'auto',
printWidth: 160,
bracketSpacing: true
}
]
},
plugins: ['@darraghor/nestjs-typed', 'eslint-plugin-import', 'eslint-plugin-n', 'eslint-plugin-promise'],
ignorePatterns: ['.eslintrc.js'],
};
Something like this: https://github.com/angular-eslint/angular-eslint/blob/master/packages/eslint-plugin/docs/rules/sort-ngmodule-metadata-arrays.md
Very good package, i was going to create something like this for nestjs but found your package! I'll try to colaborate soon, i have a lot of good nestjs rule ideas
@ApiProperty({
enum: BotStatusEnum,
enumName: 'BotStatusEnum',
name: 'status',
description: `
Current status of the bot:
* '${BotStatusEnum.ComingSoon}' - Bot will be available soon (in development)
* '${BotStatusEnum.Working}' - Bot is functional and available for use
* '${BotStatusEnum.Updating}' - Bot is currently being updated`,
})
@Column({
type: 'enum',
enum: BotStatusEnum,
})
status: BotStatusEnum;
If I remove enumName
, then I can see the description:
This code errors with the error: A non-primitve property with validation should probably use a @Type decorator
class ExampleDto {
@ApiPropertyOptional({
isArray: true,
})
@Allow()
exampleProperty?: string[];
}
while this code doesn't error:
class ExampleDto {
@ApiProperty({
isArray: true,
})
@Allow()
exampleProperty!: string[];
}
If you use ValidateIf in combination with IsDefined on an optional marked property in TS, the linter shows missing IsOptional decorator.
@ValidateIf((o) => !o.id)
@IsDefined()
@IsString()
key?: string
This should be valid.
Currently @darraghor/nestjs-typed/all-properties-have-explicit-defined throws: Optional properties must have @IsOptional() decorator
I currently get the following error when linting:
Cannot read properties of undefined (reading 'name')
Occurred while linting [...]/add-job.dto.ts:36
Rule: "@darraghor/nestjs-typed/api-property-returning-array-should-set-array"
Pass --verbose to see the stacktrace.
It seems to be a problem to use any constant inside of @ApiProperty
, as both {...swaggerImportDefinitionTypeOptions}
and swaggerImportDefinitionTypeOptions
will result in the same error.
here is the content of add-job.dto.ts
:
import { ApiProperty, ApiPropertyOptional, getSchemaPath } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { IsOptional, ValidateNested } from 'class-validator';
import { CronStringWithSeconds, IsCronStringWithSeconds } from '[...]';
import {
classTransformerImportDefinitionTypeOptions,
FromDate,
FromLastSuccessfulImport,
FullImport,
ImportDefinition,
ImportDefinitionBase,
swaggerImportDefinitionTypeOptions,
} from './import-definition.dto';
export class JobSchedule {
@ApiProperty({
description:
'The cron pattern to use for the automatic import interval. Optionally you can add seconds to the pattern.',
example: {
everyMinute: '0 * * ? * * *',
},
type: 'string',
})
@IsCronStringWithSeconds()
@Type(() => String)
pattern!: CronStringWithSeconds;
}
export class AddJobDto {
@ApiProperty({ // It fails here
...swaggerImportDefinitionTypeOptions,
})
@ValidateNested()
@Type(() => ImportDefinitionBase, classTransformerImportDefinitionTypeOptions)
importDefinition!: ImportDefinition;
@ApiPropertyOptional({
description: 'If you define this property, the job will not be executed immediately, but on the defined schedule.',
type: JobSchedule,
})
@ValidateNested()
@Type(() => JobSchedule)
@IsOptional()
jobSchedule?: JobSchedule;
}
swaggerImportDefinitionTypeOptions
is defined as follows:
export const swaggerImportDefinitionTypeOptions = {
oneOf: [
{
$ref: getSchemaPath(FullImport),
},
{
$ref: getSchemaPath(FromDate),
},
{
$ref: getSchemaPath(FromLastSuccessfulImport),
},
],
discriminator: {
propertyName: 'kind' satisfies keyof Pick<ImportDefinitionBase, 'kind'>,
},
} satisfies ApiPropertyOptions;
I'm using:
"@darraghor/eslint-plugin-nestjs-typed": "^3.22.4",
After upgrading to 3.8.0 the rule @darraghor/nestjs-typed/validated-non-primitive-property-needs-type-decorator
is throwing:
TypeError: Cannot read properties of undefined (reading 'type')
Occurred while linting /Users/iddan/flycode/continuous-content-app/backend/src/github-app-events/dto/installation-created.dto.ts:139
Rule: "@darraghor/nestjs-typed/validated-non-primitive-property-needs-type-decorator"
at PropertyDefinition (/Users/iddan/flycode/continuous-content-app/backend/node_modules/@darraghor/eslint-plugin-nestjs-typed/dist/rules/validate-non-primitves-needs-type-decorator/validateNonPrimitiveNeedsDecorators.js:47:173)
at ruleErrorHandler (/Users/iddan/flycode/continuous-content-app/backend/node_modules/eslint/lib/linter/linter.js:966:28)
at /Users/iddan/flycode/continuous-content-app/backend/node_modules/eslint/lib/linter/safe-emitter.js:45:58
at Array.forEach (<anonymous>)
at Object.emit (/Users/iddan/flycode/continuous-content-app/backend/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
at NodeEventGenerator.applySelector (/Users/iddan/flycode/continuous-content-app/backend/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
at NodeEventGenerator.applySelectors (/Users/iddan/flycode/continuous-content-app/backend/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
at NodeEventGenerator.enterNode (/Users/iddan/flycode/continuous-content-app/backend/node_modules/eslint/lib/linter/node-event-generator.js:340:14)
at CodePathAnalyzer.enterNode (/Users/iddan/flycode/continuous-content-app/backend/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js:790:23)
at /Users/iddan/flycode/continuous-content-app/backend/node_modules/eslint/lib/linter/linter.js:997:32
The compiled plugin code where the error occurs:
if (isAnArray) {
mainType = (_b = (_a = node.typeAnnotation) === null || _a === void 0 ? void 0 : _a.typeAnnotation) === null || _b === void 0 ? void 0 : _b.elementType.type;
}
The failing code:
class ExampleDto {
@ApiProperty({ isArray: true })
@Allow()
@Type(() => Array)
events!: Array<string>;
}
Getting:
Found: @typescript-eslint/[email protected]
npm ERR! node_modules/@typescript-eslint/parser
npm ERR! dev @typescript-eslint/parser@"^5.3.1" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @typescript-eslint/parser@"5.1.0" from @darraghor/[email protected]
npm ERR! node_modules/@darraghor/eslint-plugin-nestjs-typed
npm ERR! dev @darraghor/eslint-plugin-nestjs-typed@"*" from the root project
We would like to enforce well-defined swagger docs for all queries and params. It would be great if any presence of a @Param()
or @Query()
decorator on an argument could enforce a @ApiParam
or @ApiQuery
which match the parameter name.
Chances are good I will be submitting a PR for this myself. We are currently in the trial phases of checking out nestjs and this is a big sticking point to us. It might be a while before I can get to it though, so I wanted to bring this up early to check out if its something that this library would be interested in having.
Fine ESLint plugin, it should be considered required for using class-validator. :)
I'm using this with a non-NestJS project, though, where null
values on JSON objects need to be defined explicitly as null
rather than being left as undefined
.
The all-properties-have-explicit-defined
rule is triggering on lines in my class such as this:
@IsString()
externalId!: string | null;
I'm currently littering my project with eslint-disable-next-line
, but that never sits well with me. I do not want to disable the rule as I do have other properties that can be undefined and the rule is helping me find and assign them IsOptional
.
Would it be possible to add an option to the rule, e.g. null-is-required
, to work around my situation?
We have a dto that can take a free form object
type, and we use the @IsObject
decorator to check if its an object
The rule should not raise an explicit transformation requirement for such cases
Since I didn't see any issues regarding this yet :)
@typescript-eslint/parser was released recently https://github.com/typescript-eslint/typescript-eslint/releases/tag/v6.0.0 and I guess we are not the only ones that would like to upgrade (at least our renovate would like to 😅). Currently the peerDependency
mentioned here is preventing us from upgrading while using this package. I haven't tested whether this requires any code changes to this package.
Besides that, thanks for the package :)
We would like to enforce well-defined swagger docs for all queries and params. It would be great if any presence of a @Param()
or @Query()
decorator on an argument could enforce a @ApiParam
or @ApiQuery
on the model itself.
Chances are good I will be submitting a PR for this myself. We are currently in the trial phases of checking out nestjs and this is a big sticking point to us. It might be a while before I can get to it though, so I wanted to bring this up early to check out if its something that this library would be interested in having.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.