-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #93 from getlarge/feat-create-eslint-rules-library
feat: create ESLint rules library
- Loading branch information
Showing
21 changed files
with
1,579 additions
and
152 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
{ | ||
"extends": ["../../.eslintrc.json"], | ||
"ignorePatterns": ["!**/*"], | ||
"overrides": [ | ||
{ | ||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.ts", "*.tsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.js", "*.jsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.json"], | ||
"parser": "jsonc-eslint-parser", | ||
"rules": { | ||
"@nx/dependency-checks": [ | ||
"error", | ||
{ | ||
"buildTargets": ["build"], | ||
"checkMissingDependencies": true, | ||
"checkObsoleteDependencies": true, | ||
"checkVersionMismatches": true | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# eslint-rules | ||
|
||
[![npm][npm-image]][npm-url] | ||
|
||
[npm-image]: https://img.shields.io/npm/v/@getlarge/nestjs-tools-eslint-rules.svg?style=flat | ||
[npm-url]: https://npmjs.org/package/@getlarge/nestjs-tools-eslint-rules | ||
|
||
This set of ESLint rules is provided to enforce a consistent patterns and practices across all NestJS projects. | ||
|
||
## Installation | ||
|
||
```bash | ||
npm install --save @getlarge/nestjs-tools-eslint-rules | ||
``` | ||
|
||
## Usage | ||
|
||
### return-class-instance | ||
|
||
This rule enforces that all public Service methods return a class instance of the same return type. | ||
The purpose of this rule is to ensure you return class instances instead of plain objects, which is essentials when using the [`ClassSerializerInterceptor`](https://docs.nestjs.com/techniques/serialization#class-serializer-interceptor). | ||
|
||
```json | ||
{ | ||
"rules": { | ||
"@getlarge/nestjs-tools-eslint-rules/return-class-instance": "error" | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/* eslint-disable */ | ||
export default { | ||
displayName: 'eslint-rules', | ||
preset: '../../jest.preset.js', | ||
testEnvironment: 'node', | ||
transform: { | ||
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }], | ||
}, | ||
moduleFileExtensions: ['ts', 'js', 'html'], | ||
coverageDirectory: '../../coverage/packages/eslint-rules', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"name": "@getlarge/nestjs-tools-eslint-rules", | ||
"version": "0.0.0", | ||
"description": "ESLint rules for NestJS applications", | ||
"keywords": [ | ||
"eslint", | ||
"nestjs", | ||
"rules", | ||
"typescript", | ||
"lint", | ||
"style" | ||
], | ||
"license": "Apache-2.0", | ||
"author": "Edouard Maleix <[email protected]>", | ||
"homepage": "https://github.com/getlarge/nestjs-tools/tree/main/packages/eslint-rules", | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"dependencies": {}, | ||
"peerDependencies": { | ||
"eslint": "7 || 8 || 9" | ||
}, | ||
"type": "commonjs", | ||
"main": "./src/index.js", | ||
"typings": "./src/index.d.ts" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"name": "nestjs-tools-eslint-rules", | ||
"$schema": "../../node_modules/nx/schemas/project-schema.json", | ||
"sourceRoot": "packages/eslint-rules/src", | ||
"projectType": "library", | ||
"tags": [], | ||
"// targets": "to see all targets run: nx show project eslint-rules --web", | ||
"targets": {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { rule as returnClassInstance, RULE_NAME as returnClassInstanceName } from './lib/return-class-instance'; | ||
|
||
module.exports = { | ||
rules: { [returnClassInstanceName]: returnClassInstance }, | ||
}; |
162 changes: 162 additions & 0 deletions
162
packages/eslint-rules/src/lib/return-class-instance.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
import { TSESLint } from '@typescript-eslint/utils'; | ||
|
||
import { rule, RULE_NAME } from './return-class-instance'; | ||
|
||
const ruleTester = new TSESLint.RuleTester({ | ||
parser: require.resolve('@typescript-eslint/parser'), | ||
}); | ||
|
||
ruleTester.run(RULE_NAME, rule, { | ||
valid: [ | ||
// basic test case | ||
`import { Injectable } from '@nestjs/common'; | ||
class Test { | ||
constructor(params) { | ||
Object.assign(this, params); | ||
} | ||
message: string; | ||
} | ||
@Injectable() | ||
export class AppService { | ||
getData(): Test { | ||
return new Test({ message: 'Hello API' }); | ||
} | ||
}`, | ||
// promise test case | ||
`import { Injectable } from '@nestjs/common'; | ||
class Test { | ||
constructor(params) { | ||
Object.assign(this, params); | ||
} | ||
message: string; | ||
} | ||
@Injectable() | ||
export class AppService { | ||
getData(): Promise<Test> { | ||
return Promise.resolve(new Test({ message: 'Hello API' })); | ||
} | ||
}`, | ||
// constructor are not checked | ||
`import { Injectable } from '@nestjs/common'; | ||
@Injectable() | ||
export class AppService { | ||
constructor() {} | ||
}`, | ||
// check when return statement is coming from another service method | ||
`import { Injectable } from '@nestjs/common'; | ||
class Test { | ||
constructor(params) { | ||
Object.assign(this, params); | ||
} | ||
message: string; | ||
} | ||
@Injectable() | ||
export class InternalService { | ||
getData(): Test { | ||
return new Test({ message: 'Hello API' }); | ||
} | ||
} | ||
@Injectable() | ||
export class AppService { | ||
constructor(private readonly internalService: InternalService = new InternalService()) {} | ||
getData(): Test { | ||
return this.internalService.getData(); | ||
} | ||
}`, | ||
// lifecycle methods are ignored | ||
`import { Injectable } from '@nestjs/common'; | ||
@Injectable() | ||
export class AppService { | ||
onModuleInit() { | ||
console.log('Module initialized.'); | ||
} | ||
}`, | ||
// getter return type | ||
`import { Injectable } from '@nestjs/common'; | ||
@Injectable() | ||
export class AppService { | ||
get data() { | ||
return { message: 'Hello API' }; | ||
} | ||
}`, | ||
// primitive return type | ||
`import { Injectable } from '@nestjs/common'; | ||
@Injectable() | ||
export class AppService { | ||
getData(): string { | ||
return 'Hello API'; | ||
} | ||
}`, | ||
// primitive union return type | ||
`import { Injectable } from '@nestjs/common'; | ||
@Injectable() | ||
export class AppService { | ||
getData(): 'OK' | 'ERROR' { | ||
return 'OK'; | ||
} | ||
}`, | ||
// union with null return type | ||
`import { Injectable } from '@nestjs/common'; | ||
class Test { | ||
constructor(params) { | ||
Object.assign(this, params); | ||
} | ||
message: string; | ||
} | ||
@Injectable() | ||
export class AppService { | ||
getData(doIt: boolean): Test | null { | ||
if (doIt) { | ||
return new Test({ message: 'Hello API' }); | ||
} | ||
return null; | ||
} | ||
}`, | ||
// TODO: class instance is modified before being returned | ||
// `import { Injectable } from '@nestjs/common'; | ||
// class Test { | ||
// constructor(params) { | ||
// Object.assign(this, params); | ||
// } | ||
// message: string; | ||
// } | ||
// @Injectable() | ||
// export class AppService { | ||
// getData(): Test { | ||
// const test = new Test({ message: 'Hello API' }); | ||
// test.message = 'Hello API'; | ||
// return test; | ||
// } | ||
// }`, | ||
], | ||
invalid: [ | ||
{ | ||
errors: [{ messageId: 'missingReturnType' }], | ||
code: ` | ||
import { Injectable } from '@nestjs/common'; | ||
@Injectable() | ||
export class AppService { | ||
getData() { | ||
return { message: 'Hello API' }; | ||
} | ||
}`, | ||
}, | ||
{ | ||
errors: [{ messageId: 'returnClassInstance' }], | ||
code: ` | ||
import { Injectable } from '@nestjs/common'; | ||
class Test { | ||
constructor(params) { | ||
Object.assign(this, params); | ||
} | ||
message: string; | ||
} | ||
@Injectable() | ||
export class AppService { | ||
getData(): Test { | ||
return { message: 'Hello API' }; | ||
} | ||
}`, | ||
}, | ||
], | ||
}); |
Oops, something went wrong.