Code Monkey home page Code Monkey logo

eslint-plugin-nestjs-typed's Introduction

commit npm npm-tag size types

A note on versions

  • Version 5.x supports Eslint version >=8.x and typescript eslint parser ^7
  • Version 4.x supports Eslint version >=8.x and typescript eslint parser ^6
  • Version 3.x supports Eslint version >=8.x and typescript eslint parser ^5
  • Version 2.x supports Eslint version <=7.x and typescript eslint parser ^4

There are breaking changes between versions ofr ts-eslint.

typescript eslint parser supports a range of typescript versions but there can be a delay in supporting the latest versions.

This plugin only supports typescript up to the version typescript eslint parser supports. See https://github.com/typescript-eslint/typescript-eslint#supported-typescript-version for the versions.

Have an idea for a rule?

Awsome! Click here to submit a new issue!

Index of available rules

Category Rule is on in recommended ruleset?
Nest Modules and Dependency Injection provided-injected-should-match-factory-parameters Y
injectable-should-be-provided Y
Nest Swagger api-property-matches-property-optionality Y
controllers-should-supply-api-tags Y
api-method-should-specify-api-response N
api-method-should-specify-api-operation Y
api-enum-property-best-practices Y
api-property-returning-array-should-set-array Y
Preventing bugs param-decorator-name-matches-route-param Y
validate-nested-of-array-should-set-each Y
validated-non-primitive-property-needs-type-decorator Y
all-properties-are-whitelisted Y
all-properties-have-explicit-defined Y
no-duplicate-decorators Y
Security validation-pipe-should-forbid-unknown Y
api-methods-should-be-guarded N
Code Consistency sort-module-metadata-arrays N

The "recommended" ruleset are the default rules that are turned on when you configure the plugin as described in this document.

The name "recommended" is an eslint convention. Some rules in this plugin are opinionated and have to be turned on explicitly in your eslintrc file.

Who is this package for?

If you use NestJs (https://nestjs.com/) these ESLint rules will help you to prevent common bugs and issues in NestJs applications.

They mostly check that you are using decorators correctly.

The primary groupings of rules in this plugin are...

1. Detect Nest Dependency Injection issues

The Nest DI is declarative and if you forget to provide an injectable you wont see an error until run time. Nest is good at telling you where these are but sometimes it's not.

In particular if you're using custom providers the errors can be really tricky to figure out because they won't explicitly error about mismatched injected items, you will just get unexpected operation.

These are described in the "Common Errors" section of the nest js docs.

2. Using Open Api / Swagger decorators and automatically generating a clients

When working with NestJS I generate my front end client and models using the swagger/Open API specification generated directly from the nest controllers and models.

I have a bunch of rules here that enforce strict Open API typing with decorators for NestJs controllers and models.

These rules are opinionated, but necessary for clean model generation if using an Open Api client generator later in your build.

3. Helping prevent bugs

There are some tightly coupled but untyped decorators and things like that in nest that will catch you out if your not careful. There are some rules to help prevent issues that have caught me out before.

4. Security

There is a CVE for class-transformer when using random javascript objects. You need to be careful about configuring the ValidationPipe in NestJs. See https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18413 typestack/class-validator#438

To install

The plugin is on npm here: https://www.npmjs.com/package/@darraghor/eslint-plugin-nestjs-typed You can see how the rules are used in this NestJS project: https://github.com/darraghoriordan/use-miller

npm install --save-dev @darraghor/eslint-plugin-nestjs-typed

// or

yarn add -D @darraghor/eslint-plugin-nestjs-typed
// or

pnpm add -D @darraghor/eslint-plugin-nestjs-typed

If you don't already have class-validator you should install that

npm install class-validator

// or

yarn add class-validator

// or

pnpm add class-validator

To configure

Update your eslint with the plugin import and add the recommended rule set

module.exports = {
    env: {
        es6: true,
    },
    extends: ["plugin:@darraghor/nestjs-typed/recommended"],
    parser: "@typescript-eslint/parser",
    parserOptions: {
        project: ["./tsconfig.json"],
        sourceType: "module",
        ecmaVersion: "es2019",
    },
    plugins: ["@darraghor/nestjs-typed"],
};

Note: the injectables test scans your whole project. It's best to filter out ts things that don't matter - use filterFromPaths configuration setting for this. See the rule documentation for more info.

There are some defaults already applied.

Note: You can easily turn off all the swagger rules if you don't use swagger by adding the no-swagger rule set AFTER the recommended rule set.

// all the other config
    extends: ["plugin:@darraghor/nestjs-typed/recommended",
    "plugin:@darraghor/nestjs-typed/no-swagger"
    ],
 // more config

Disable a single rule with the full name e.g. in your eslint configuration...

   rules: {
   "@darraghor/nestjs-typed/api-property-returning-array-should-set-array":
            "off",
   }

eslint-plugin-nestjs-typed's People

Contributors

adamvandenhoven avatar austinwoon avatar benbarbersmith avatar darraghoriordan avatar darraghoriordan-roam avatar foo-bar-sketch avatar iddan avatar iddan-flycode avatar jalorenz avatar lucas-gregoire avatar micalevisk avatar spotlesscoder avatar thilllon avatar unlomtrois avatar wilfridhcl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

eslint-plugin-nestjs-typed's Issues

New Rule Suggestion: forbids `app.get()` for APP_* tokens

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

Can't install the latest version

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

Invalid tests ?

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 ;-)

`param-decorator-name-matches-route-param` needs to handle certain edge cases

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.

Type Decorator Required for optional array fields

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[];
}

filterFromPaths doesn't work

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)

validated-non-primitive-property-needs-type-decorator is erroring for optional enum properties

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[];
}

feat(validated-non-primitive-property-needs-type-decorator): allow additional options for custom validator decorators to detect

Context

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.

Proposed solutions

  • Extend the available options to include an additional param 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.
  • Extend available options to take in a list of file paths for imports to check against. This file path will contain all the custom decorators we wrote. Con: This prevents naming collisions, and will not require us to update the decorator names whenever we add new decorators to the project.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Awaiting Schedule

These updates are awaiting their schedule. Click on a checkbox to get an update now.

  • chore(deps): lock file maintenance

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.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
npm
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
nvm
.nvmrc

Add custom decorators to api-method-should-specify-api-response

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?

hacktoberfest 2023

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!

New Rule: No redundant required on `@ApiProperty`

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?

nestjs-typed/validated-non-primitive-property-needs-type-decorator when using Union types

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.

Update tutorial on publishing

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.

Swagger, when I add `enumName` to ApiProperty options, description not display in Swagger UI

 @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;

image

If I remove enumName, then I can see the description:

image

Rule to detect that an injected dependency has no @Injectable() decorator on the defining class

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

Error loading rule

When executing the ESLint in my NestJS project the following error occurs:
image

these are my dependencies:
image

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'],
};

Should ignore non-verifiable types - param-decorator-name-matches-route-param

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.

Rule: api-method-should-specify-api-operation

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?

Swagger: Rule for requiring @ApiParam and @ApiQuery for every @Param() and @Query() used.

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.

injectable-should-be-provided doesn't work with not callable decorators

Description

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 <--
            )
        );

Reproduction

https://github.com/WiseBird/eslint-plugin-nestjs-issue-decorator (commit)

  • yarn install
  • yarn lint

error with `injectable-should-be-provided`

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

Using constants as options for `@ApiProperty` breaks `api-property-returning-array-should-set-array`

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",

injectable-should-be-provided works only with PropertyAssignment

Description

injectable-should-be-provided expect providers to be an array, otherwise it may fail with NPE:

TypeError: Cannot read properties of undefined (reading 'map')

Reproduction

https://github.com/WiseBird/eslint-plugin-nestjs-issue-shorthand (commit)

  • yarn install
  • yarn lint

Details

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
                )
            );
        }

Disclamer

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.

all-properties-have-explicit-defined should have option to not trigger on `null` values

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?

validated-non-primitive-property-needs-type-decorator Customization

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.

ValidateIf should be handled like IsOptional

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

Swagger: Rule for enforcing @ApiParam and @ApiQuery of @Param("...") or @Query("...") is used.

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.

ApiPropertOptional

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

Support for @typescript-eslint/parse v6

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 :)

add rule to disalow using `@Inject()` without some token when using it on `constructor`

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

image

code
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'
  ) {}
}

`provided-injected-should-match-factory-parameters` fails linting on unrelated code

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)


@darraghor/nestjs-typed/param-decorator-name-matches-route-param - doesn't handle '?'

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).

`should-specify-forbid-unknown-values` rule breaks when config options for `ValidationPipe` are passed as object spread

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
  })
);

rules should be consistently named in plural or singular form

Some rules from this plugin are named in singular:

  • api-method-should-specify-api-response

while others are named in plural

  • api-methods-should-be-guarded

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

Rule to enforce rest naming convention

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) {
    }
}

The automated release is failing 🚨

🚨 The automated release from the 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.


Cannot push to the Git repository.

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 πŸ“¦πŸš€

validated-non-primitive-property-needs-type-decorator: TypeError: Cannot read properties of undefined (reading 'type')

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>;
}

Extend rule: "param-decorator-name-matches-route-param"

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.

image

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?

image

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.