diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e0e60ee6a3e..93652acb3e8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + + +### Bug Fixes + +* **eslint-plugin:** method-signature-style respect getter signature ([#4777](https://github.com/typescript-eslint/typescript-eslint/issues/4777)) ([12dd670](https://github.com/typescript-eslint/typescript-eslint/commit/12dd670bc8621867c5105d8892dba9f9550a2f35)) +* **visitor-keys:** add missing visitor keys ([#4731](https://github.com/typescript-eslint/typescript-eslint/issues/4731)) ([bb575a0](https://github.com/typescript-eslint/typescript-eslint/commit/bb575a0763f39b9b988a7c20afee7b5eeb64cba7)) + + +### Features + +* **eslint-plugin:** [no-shadow] ignoreOnInitialization option ([#4603](https://github.com/typescript-eslint/typescript-eslint/issues/4603)) ([068ea9b](https://github.com/typescript-eslint/typescript-eslint/commit/068ea9b8eb3072fb46a6035f29c68ce96a69008d)) +* **eslint-plugin:** [no-this-alias] report on assignment expressions ([#4718](https://github.com/typescript-eslint/typescript-eslint/issues/4718)) ([8329498](https://github.com/typescript-eslint/typescript-eslint/commit/83294989dad543351a26e95be8d11a91d348679a)) + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) diff --git a/docs/README.md b/docs/README.md index aa14517ebd62..dfac81e925a2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -4,7 +4,7 @@ sidebar_label: Getting Started slug: / --- -These docs will give you a quick overview of the project and all of its the pieces, as well as provide guides to help you get set up. +These docs will give you a quick overview of the project and all of its pieces, as well as provide guides to help you get set up. The docs are broken down into the following categories: diff --git a/docs/development/CUSTOM_RULES.md b/docs/development/CUSTOM_RULES.md index a101dadbd297..345e42c289ec 100644 --- a/docs/development/CUSTOM_RULES.md +++ b/docs/development/CUSTOM_RULES.md @@ -46,20 +46,23 @@ export const rule = createRule({ create(context) { return { FunctionDeclaration(node) { - if (/^[a-z]/.test(node.id.name)) { - context.report({ - messageId: 'uppercase', - node: node.id, - }); + if (node.id != null) { + if (/^[a-z]/.test(node.id.name)) { + context.report({ + messageId: 'uppercase', + node: node.id, + }); + } } }, }; }, + name: 'uppercase-first-declarations', meta: { docs: { - category: 'Best Practices', description: 'Function declaration names should start with an upper-case letter.', + recommended: 'warn', }, messages: { uppercase: 'Start this name with an upper-case letter.', @@ -67,6 +70,7 @@ export const rule = createRule({ type: 'suggestion', schema: [], }, + defaultOptions: [], }); ``` diff --git a/lerna.json b/lerna.json index fde7ffaa6778..89f5ea3e2164 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "5.17.0", + "version": "5.18.0", "npmClient": "yarn", "useWorkspaces": true, "stream": true diff --git a/packages/ast-spec/CHANGELOG.md b/packages/ast-spec/CHANGELOG.md index 96b7ebf5217b..3efccf0ffa5f 100644 --- a/packages/ast-spec/CHANGELOG.md +++ b/packages/ast-spec/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/ast-spec + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/ast-spec diff --git a/packages/ast-spec/package.json b/packages/ast-spec/package.json index 6dd8d4503f6d..e2bd51c4c2d6 100644 --- a/packages/ast-spec/package.json +++ b/packages/ast-spec/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/ast-spec", - "version": "5.17.0", + "version": "5.18.0", "description": "TypeScript-ESTree AST spec", "private": true, "keywords": [ diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index 2e9ca4f037bc..e88c909009d1 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index 6f9a82cde1a7..156c9ba148de 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-internal", - "version": "5.17.0", + "version": "5.18.0", "private": true, "main": "dist/index.js", "scripts": { @@ -14,8 +14,8 @@ }, "dependencies": { "@types/prettier": "*", - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/utils": "5.17.0", + "@typescript-eslint/scope-manager": "5.18.0", + "@typescript-eslint/utils": "5.18.0", "prettier": "*" } } diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index b603de44ba5a..e356a4514ace 100644 --- a/packages/eslint-plugin-tslint/CHANGELOG.md +++ b/packages/eslint-plugin-tslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint diff --git a/packages/eslint-plugin-tslint/package.json b/packages/eslint-plugin-tslint/package.json index 0231788b4f6b..aaaa072aa8c0 100644 --- a/packages/eslint-plugin-tslint/package.json +++ b/packages/eslint-plugin-tslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-tslint", - "version": "5.17.0", + "version": "5.18.0", "main": "dist/index.js", "typings": "src/index.ts", "description": "TSLint wrapper plugin for ESLint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "5.17.0", + "@typescript-eslint/utils": "5.18.0", "lodash": "^4.17.21" }, "peerDependencies": { @@ -48,6 +48,6 @@ }, "devDependencies": { "@types/lodash": "*", - "@typescript-eslint/parser": "5.17.0" + "@typescript-eslint/parser": "5.18.0" } } diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index d2dbffd033ef..d54b733b40f1 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + + +### Bug Fixes + +* **eslint-plugin:** method-signature-style respect getter signature ([#4777](https://github.com/typescript-eslint/typescript-eslint/issues/4777)) ([12dd670](https://github.com/typescript-eslint/typescript-eslint/commit/12dd670bc8621867c5105d8892dba9f9550a2f35)) + + +### Features + +* **eslint-plugin:** [no-shadow] ignoreOnInitialization option ([#4603](https://github.com/typescript-eslint/typescript-eslint/issues/4603)) ([068ea9b](https://github.com/typescript-eslint/typescript-eslint/commit/068ea9b8eb3072fb46a6035f29c68ce96a69008d)) +* **eslint-plugin:** [no-this-alias] report on assignment expressions ([#4718](https://github.com/typescript-eslint/typescript-eslint/issues/4718)) ([8329498](https://github.com/typescript-eslint/typescript-eslint/commit/83294989dad543351a26e95be8d11a91d348679a)) + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index d09ac65a7e7b..ac1a8e5a2ad6 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "5.17.0", + "version": "5.18.0", "description": "TypeScript plugin for ESLint", "keywords": [ "eslint", @@ -44,9 +44,9 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/type-utils": "5.17.0", - "@typescript-eslint/utils": "5.17.0", + "@typescript-eslint/scope-manager": "5.18.0", + "@typescript-eslint/type-utils": "5.18.0", + "@typescript-eslint/utils": "5.18.0", "debug": "^4.3.2", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.8", diff --git a/packages/eslint-plugin/src/rules/method-signature-style.ts b/packages/eslint-plugin/src/rules/method-signature-style.ts index d9dfbdac4bd6..39ed66cd0729 100644 --- a/packages/eslint-plugin/src/rules/method-signature-style.ts +++ b/packages/eslint-plugin/src/rules/method-signature-style.ts @@ -115,6 +115,10 @@ export default util.createRule({ return { ...(mode === 'property' && { TSMethodSignature(methodNode): void { + if (methodNode.kind !== 'method') { + return; + } + const parent = methodNode.parent; const members = parent?.type === AST_NODE_TYPES.TSInterfaceBody diff --git a/packages/eslint-plugin/src/rules/no-shadow.ts b/packages/eslint-plugin/src/rules/no-shadow.ts index 3f13f587de16..a80a1b506732 100644 --- a/packages/eslint-plugin/src/rules/no-shadow.ts +++ b/packages/eslint-plugin/src/rules/no-shadow.ts @@ -18,6 +18,7 @@ type Options = [ allow?: string[]; builtinGlobals?: boolean; hoist?: 'all' | 'functions' | 'never'; + ignoreOnInitialization?: boolean; ignoreTypeValueShadow?: boolean; ignoreFunctionTypeParameterNameValueShadow?: boolean; }, @@ -49,6 +50,9 @@ export default util.createRule({ type: 'string', }, }, + ignoreOnInitialization: { + type: 'boolean', + }, ignoreTypeValueShadow: { type: 'boolean', }, @@ -68,6 +72,7 @@ export default util.createRule({ allow: [], builtinGlobals: false, hoist: 'functions', + ignoreOnInitialization: false, ignoreTypeValueShadow: true, ignoreFunctionTypeParameterNameValueShadow: true, }, @@ -314,6 +319,135 @@ export default util.createRule({ ); } + /** + * Checks whether or not a given location is inside of the range of a given node. + * @param node An node to check. + * @param location A location to check. + * @returns `true` if the location is inside of the range of the node. + */ + function isInRange( + node: TSESTree.Node | null, + location: number, + ): boolean | null { + return node && node.range[0] <= location && location <= node.range[1]; + } + + /** + * Searches from the current node through its ancestry to find a matching node. + * @param node a node to get. + * @param match a callback that checks whether or not the node verifies its condition or not. + * @returns the matching node. + */ + function findSelfOrAncestor( + node: TSESTree.Node | undefined, + match: (node: TSESTree.Node) => boolean, + ): TSESTree.Node | undefined { + let currentNode = node; + + while (currentNode && !match(currentNode)) { + currentNode = currentNode.parent; + } + return currentNode; + } + + /** + * Finds function's outer scope. + * @param scope Function's own scope. + * @returns Function's outer scope. + */ + function getOuterScope( + scope: TSESLint.Scope.Scope, + ): TSESLint.Scope.Scope | null { + const upper = scope.upper; + + if (upper?.type === 'function-expression-name') { + return upper.upper; + } + return upper; + } + + /** + * Checks if a variable and a shadowedVariable have the same init pattern ancestor. + * @param variable a variable to check. + * @param shadowedVariable a shadowedVariable to check. + * @returns Whether or not the variable and the shadowedVariable have the same init pattern ancestor. + */ + function isInitPatternNode( + variable: TSESLint.Scope.Variable, + shadowedVariable: TSESLint.Scope.Variable, + ): boolean { + const outerDef = shadowedVariable.defs[0]; + + if (!outerDef) { + return false; + } + + const { variableScope } = variable.scope; + + if ( + !( + (variableScope.block.type === + AST_NODE_TYPES.ArrowFunctionExpression || + variableScope.block.type === AST_NODE_TYPES.FunctionExpression) && + getOuterScope(variableScope) === shadowedVariable.scope + ) + ) { + return false; + } + + const fun = variableScope.block; + const { parent } = fun; + + const callExpression = findSelfOrAncestor( + parent, + node => node.type === AST_NODE_TYPES.CallExpression, + ); + + if (!callExpression) { + return false; + } + + let node: TSESTree.Node | undefined = outerDef.name; + const location = callExpression.range[1]; + + while (node) { + if (node.type === AST_NODE_TYPES.VariableDeclarator) { + if (isInRange(node.init, location)) { + return true; + } + if ( + (node.parent?.parent?.type === AST_NODE_TYPES.ForInStatement || + node.parent?.parent?.type === AST_NODE_TYPES.ForOfStatement) && + isInRange(node.parent.parent.right, location) + ) { + return true; + } + break; + } else if (node.type === AST_NODE_TYPES.AssignmentPattern) { + if (isInRange(node.right, location)) { + return true; + } + } else if ( + [ + AST_NODE_TYPES.FunctionDeclaration, + AST_NODE_TYPES.ClassDeclaration, + AST_NODE_TYPES.FunctionExpression, + AST_NODE_TYPES.ClassExpression, + AST_NODE_TYPES.ArrowFunctionExpression, + AST_NODE_TYPES.CatchClause, + AST_NODE_TYPES.ImportDeclaration, + AST_NODE_TYPES.ExportNamedDeclaration, + ].includes(node.type) + ) { + break; + } + + node = node.parent; + } + + return false; + } + /** * Checks if a variable is inside the initializer of scopeVar. * @@ -455,6 +589,10 @@ export default util.createRule({ (shadowed.identifiers.length > 0 || (options.builtinGlobals && isESLintGlobal)) && !isOnInitializer(variable, shadowed) && + !( + options.ignoreOnInitialization && + isInitPatternNode(variable, shadowed) + ) && !(options.hoist !== 'all' && isInTdz(variable, shadowed)) ) { context.report({ diff --git a/packages/eslint-plugin/src/rules/no-this-alias.ts b/packages/eslint-plugin/src/rules/no-this-alias.ts index 5c9c9f568811..5750b8209b11 100644 --- a/packages/eslint-plugin/src/rules/no-this-alias.ts +++ b/packages/eslint-plugin/src/rules/no-this-alias.ts @@ -48,11 +48,11 @@ export default util.createRule({ ], create(context, [{ allowDestructuring, allowedNames }]) { return { - "VariableDeclarator[init.type='ThisExpression']"( - node: TSESTree.VariableDeclarator, + "VariableDeclarator[init.type='ThisExpression'], AssignmentExpression[right.type='ThisExpression']"( + node: TSESTree.VariableDeclarator | TSESTree.AssignmentExpression, ): void { - const { id } = node; - + const id = + node.type === AST_NODE_TYPES.VariableDeclarator ? node.id : node.left; if (allowDestructuring && id.type !== AST_NODE_TYPES.Identifier) { return; } diff --git a/packages/eslint-plugin/tests/rules/method-signature-style.test.ts b/packages/eslint-plugin/tests/rules/method-signature-style.test.ts index e82ee2e750bd..065d15c61801 100644 --- a/packages/eslint-plugin/tests/rules/method-signature-style.test.ts +++ b/packages/eslint-plugin/tests/rules/method-signature-style.test.ts @@ -30,12 +30,24 @@ interface Test { ` interface Test { 'f!': (/* b */ x: any /* c */) => void; +} + `, + ` +interface Test { + get f(): number; +} + `, + ` +interface Test { + set f(value: number): void; } `, 'type Test = { readonly f: (a: string) => number };', "type Test = { ['f']?: (a: boolean) => void };", 'type Test = { readonly f?: (a?: T) => T };', "type Test = { readonly ['f']?: (a: T, b: T) => T };", + 'type Test = { get f(): number };', + 'type Test = { set f(value: number): void };', ...batchedSingleLineTests({ options: ['method'], code: noFormat` @@ -44,10 +56,14 @@ interface Test { interface Test { f(a: T): T } interface Test { ['f'](a: T, b: T): T } interface Test { 'f!'(/* b */ x: any /* c */): void } + interface Test { get f(): number } + interface Test { set f(value: number): void } type Test = { readonly f(a: string): number } type Test = { ['f']?(a: boolean): void } type Test = { readonly f?(a?: T): T } type Test = { readonly ['f']?(a: T, b: T): T } + type Test = { get f(): number } + type Test = { set f(value: number): void } `, }), ], diff --git a/packages/eslint-plugin/tests/rules/no-shadow.test.ts b/packages/eslint-plugin/tests/rules/no-shadow.test.ts index 635dff307e1f..69a69f2f70eb 100644 --- a/packages/eslint-plugin/tests/rules/no-shadow.test.ts +++ b/packages/eslint-plugin/tests/rules/no-shadow.test.ts @@ -202,6 +202,156 @@ function doThing(foo: number) {} `, options: [{ ignoreTypeValueShadow: true }], }, + { + code: 'const a = [].find(a => a);', + options: [{ ignoreOnInitialization: true }], + }, + { + code: ` +const a = [].find(function (a) { + return a; +}); + `, + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'const [a = [].find(a => true)] = dummy;', + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'const { a = [].find(a => true) } = dummy;', + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'function func(a = [].find(a => true)) {}', + options: [{ ignoreOnInitialization: true }], + }, + { + code: ` +for (const a in [].find(a => true)) { +} + `, + options: [{ ignoreOnInitialization: true }], + }, + { + code: ` +for (const a of [].find(a => true)) { +} + `, + options: [{ ignoreOnInitialization: true }], + }, + { + code: "const a = [].map(a => true).filter(a => a === 'b');", + options: [{ ignoreOnInitialization: true }], + }, + { + code: ` +const a = [] + .map(a => true) + .filter(a => a === 'b') + .find(a => a === 'c'); + `, + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'const { a } = (({ a }) => ({ a }))();', + options: [{ ignoreOnInitialization: true }], + }, + { + code: ` +const person = people.find(item => { + const person = item.name; + return person === 'foo'; +}); + `, + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'var y = bar || foo(y => y);', + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'var y = bar && foo(y => y);', + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'var z = bar(foo(z => z));', + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'var z = boo(bar(foo(z => z)));', + options: [{ ignoreOnInitialization: true }], + }, + { + code: ` +var match = function (person) { + return person.name === 'foo'; +}; +const person = [].find(match); + `, + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'const a = foo(x || (a => {}));', + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'const { a = 1 } = foo(a => {});', + options: [{ ignoreOnInitialization: true }], + }, + { + code: "const person = { ...people.find(person => person.firstName.startsWith('s')) };", + options: [{ ignoreOnInitialization: true }], + parserOptions: { ecmaVersion: 2021 }, + }, + { + code: ` +const person = { + firstName: people + .filter(person => person.firstName.startsWith('s')) + .map(person => person.firstName)[0], +}; + `, + options: [{ ignoreOnInitialization: true }], + parserOptions: { ecmaVersion: 2021 }, + }, + { + code: ` +() => { + const y = foo(y => y); +}; + `, + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'const x = (x => x)();', + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'var y = bar || (y => y)();', + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'var y = bar && (y => y)();', + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'var x = (x => x)((y => y)());', + options: [{ ignoreOnInitialization: true }], + }, + { + code: 'const { a = 1 } = (a => {})();', + options: [{ ignoreOnInitialization: true }], + }, + { + code: ` +() => { + const y = (y => y)(); +}; + `, + options: [{ ignoreOnInitialization: true }], + }, + { code: 'const [x = y => y] = [].map(y => y);' }, ], invalid: [ { @@ -1612,5 +1762,265 @@ declare module 'bar' { }, ], }, + { + code: ` +let x = foo((x, y) => {}); +let y; + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ hoist: 'all' }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'x' }, + type: AST_NODE_TYPES.Identifier, + }, + { + messageId: 'noShadow', + data: { + name: 'y', + shadowedLine: 2, + shadowedColumn: 5, + }, + type: AST_NODE_TYPES.Identifier, + }, + ], + }, + { + code: ` +const a = fn(() => { + class C { + fn() { + const a = 42; + return a; + } + } + return new C(); +}); + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'a' }, + type: AST_NODE_TYPES.Identifier, + line: 5, + column: 13, + }, + ], + }, + { + code: 'function a() {}\nfoo(a => {});', + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'a' }, + type: AST_NODE_TYPES.Identifier, + line: 2, + column: 5, + }, + ], + }, + { + code: ` +const a = fn(() => { + function C() { + this.fn = function () { + const a = 42; + return a; + }; + } + return new C(); +}); + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'a' }, + type: AST_NODE_TYPES.Identifier, + line: 5, + column: 13, + }, + ], + }, + { + code: ` +const x = foo(() => { + const bar = () => { + return x => {}; + }; + return bar; +}); + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'x' }, + type: AST_NODE_TYPES.Identifier, + line: 4, + column: 12, + }, + ], + }, + { + code: ` +const x = foo(() => { + return { bar(x) {} }; +}); + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'x' }, + type: AST_NODE_TYPES.Identifier, + line: 3, + column: 16, + }, + ], + }, + { + code: ` +const x = () => { + foo(x => x); +}; + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'x' }, + type: AST_NODE_TYPES.Identifier, + line: 3, + column: 7, + }, + ], + }, + { + code: ` +const foo = () => { + let x; + bar(x => x); +}; + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'x' }, + type: AST_NODE_TYPES.Identifier, + line: 4, + column: 7, + }, + ], + }, + { + code: ` +foo(() => { + const x = x => x; +}); + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'x' }, + type: AST_NODE_TYPES.Identifier, + line: 3, + column: 13, + }, + ], + }, + { + code: ` +const foo = x => { + bar(x => {}); +}; + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'x' }, + type: AST_NODE_TYPES.Identifier, + line: 3, + column: 7, + }, + ], + }, + { + code: ` +let x = ((x, y) => {})(); +let y; + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ hoist: 'all' }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'x' }, + type: AST_NODE_TYPES.Identifier, + }, + { + messageId: 'noShadow', + data: { name: 'y' }, + type: AST_NODE_TYPES.Identifier, + }, + ], + }, + { + code: ` +const a = (() => { + class C { + fn() { + const a = 42; + return a; + } + } + return new C(); +})(); + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'a' }, + type: AST_NODE_TYPES.Identifier, + line: 5, + column: 13, + }, + ], + }, + { + code: ` +const x = () => { + (x => x)(); +}; + `, + parserOptions: { ecmaVersion: 6 }, + options: [{ ignoreOnInitialization: true }], + errors: [ + { + messageId: 'noShadow', + data: { name: 'x' }, + type: AST_NODE_TYPES.Identifier, + line: 3, + column: 4, + }, + ], + }, ], }); diff --git a/packages/eslint-plugin/tests/rules/no-this-alias.test.ts b/packages/eslint-plugin/tests/rules/no-this-alias.test.ts index 0a8f7340bca8..0d2832ec2ef1 100644 --- a/packages/eslint-plugin/tests/rules/no-this-alias.test.ts +++ b/packages/eslint-plugin/tests/rules/no-this-alias.test.ts @@ -66,6 +66,13 @@ declare module 'foo' { code: 'const self = this;', errors: [idError], }, + { + code: ` +let that; +that = this; + `, + errors: [idError], + }, { code: 'const { props, state } = this;', options: [ diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 7e3b9db43e36..4c7b71a67ae9 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -374,6 +374,7 @@ declare module 'eslint/lib/rules/no-shadow' { builtinGlobals?: boolean; hoist?: 'all' | 'functions' | 'never'; allow?: string[]; + ignoreOnInitialization?: boolean; }, ], { diff --git a/packages/experimental-utils/CHANGELOG.md b/packages/experimental-utils/CHANGELOG.md index 3ec1fb5f0deb..71d730f80fc0 100644 --- a/packages/experimental-utils/CHANGELOG.md +++ b/packages/experimental-utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/experimental-utils + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/experimental-utils diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index 6461573e61a9..252ce0aa61f8 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/experimental-utils", - "version": "5.17.0", + "version": "5.18.0", "description": "(Experimental) Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "5.17.0" + "@typescript-eslint/utils": "5.18.0" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index 54af23a02a56..8eb61aaeea5f 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/parser + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/parser diff --git a/packages/parser/package.json b/packages/parser/package.json index 966628d108e9..b7eeeac1478d 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "5.17.0", + "version": "5.18.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -44,9 +44,9 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "dependencies": { - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/typescript-estree": "5.17.0", + "@typescript-eslint/scope-manager": "5.18.0", + "@typescript-eslint/types": "5.18.0", + "@typescript-eslint/typescript-estree": "5.18.0", "debug": "^4.3.2" }, "devDependencies": { diff --git a/packages/scope-manager/CHANGELOG.md b/packages/scope-manager/CHANGELOG.md index 44a49da0e4f5..303997c57562 100644 --- a/packages/scope-manager/CHANGELOG.md +++ b/packages/scope-manager/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/scope-manager + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/scope-manager diff --git a/packages/scope-manager/package.json b/packages/scope-manager/package.json index 7133c16639be..d06efe9e579a 100644 --- a/packages/scope-manager/package.json +++ b/packages/scope-manager/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/scope-manager", - "version": "5.17.0", + "version": "5.18.0", "description": "TypeScript scope analyser for ESLint", "keywords": [ "eslint", @@ -39,12 +39,12 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/visitor-keys": "5.17.0" + "@typescript-eslint/types": "5.18.0", + "@typescript-eslint/visitor-keys": "5.18.0" }, "devDependencies": { "@types/glob": "*", - "@typescript-eslint/typescript-estree": "5.17.0", + "@typescript-eslint/typescript-estree": "5.18.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/shared-fixtures/CHANGELOG.md b/packages/shared-fixtures/CHANGELOG.md index 039a09d58bb1..c38dbd00a11f 100644 --- a/packages/shared-fixtures/CHANGELOG.md +++ b/packages/shared-fixtures/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/shared-fixtures + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/shared-fixtures diff --git a/packages/shared-fixtures/package.json b/packages/shared-fixtures/package.json index 0ac5e65ed2b2..71cf26927113 100644 --- a/packages/shared-fixtures/package.json +++ b/packages/shared-fixtures/package.json @@ -1,5 +1,5 @@ { "name": "@typescript-eslint/shared-fixtures", - "version": "5.17.0", + "version": "5.18.0", "private": true } diff --git a/packages/type-utils/CHANGELOG.md b/packages/type-utils/CHANGELOG.md index dc7c1a037742..78a895f4620f 100644 --- a/packages/type-utils/CHANGELOG.md +++ b/packages/type-utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/type-utils + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/type-utils diff --git a/packages/type-utils/package.json b/packages/type-utils/package.json index 1fe0b75177ab..f790577c9a31 100644 --- a/packages/type-utils/package.json +++ b/packages/type-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/type-utils", - "version": "5.17.0", + "version": "5.18.0", "description": "Type utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -39,12 +39,12 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "5.17.0", + "@typescript-eslint/utils": "5.18.0", "debug": "^4.3.2", "tsutils": "^3.21.0" }, "devDependencies": { - "@typescript-eslint/parser": "5.17.0", + "@typescript-eslint/parser": "5.18.0", "typescript": "*" }, "peerDependencies": { diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 05bab9244e96..254fecadcb36 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/types + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/types diff --git a/packages/types/package.json b/packages/types/package.json index 5779b1d502a1..e0c5c4ed6d51 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/types", - "version": "5.17.0", + "version": "5.18.0", "description": "Types for the TypeScript-ESTree AST spec", "keywords": [ "eslint", diff --git a/packages/typescript-estree/CHANGELOG.md b/packages/typescript-estree/CHANGELOG.md index e03a57d7bc81..b17e479f930a 100644 --- a/packages/typescript-estree/CHANGELOG.md +++ b/packages/typescript-estree/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/typescript-estree + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/typescript-estree diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 93474d4d8dc8..4d0e47c465d7 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "5.17.0", + "version": "5.18.0", "description": "A parser that converts TypeScript source code into an ESTree compatible form", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -41,8 +41,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/visitor-keys": "5.17.0", + "@typescript-eslint/types": "5.18.0", + "@typescript-eslint/visitor-keys": "5.18.0", "debug": "^4.3.2", "globby": "^11.0.4", "is-glob": "^4.0.3", @@ -58,7 +58,7 @@ "@types/is-glob": "*", "@types/semver": "*", "@types/tmp": "*", - "@typescript-eslint/shared-fixtures": "5.17.0", + "@typescript-eslint/shared-fixtures": "5.18.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index bdb3c35770da..7051abc014a8 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/utils + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/utils diff --git a/packages/utils/package.json b/packages/utils/package.json index 72894210f46f..4d301b5e40b3 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/utils", - "version": "5.17.0", + "version": "5.18.0", "description": "Utilities for working with TypeScript + ESLint together", "keywords": [ "eslint", @@ -40,9 +40,9 @@ }, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/typescript-estree": "5.17.0", + "@typescript-eslint/scope-manager": "5.18.0", + "@typescript-eslint/types": "5.18.0", + "@typescript-eslint/typescript-estree": "5.18.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, diff --git a/packages/visitor-keys/CHANGELOG.md b/packages/visitor-keys/CHANGELOG.md index 01701e3e95d1..5bd5a308f7b4 100644 --- a/packages/visitor-keys/CHANGELOG.md +++ b/packages/visitor-keys/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + + +### Bug Fixes + +* **visitor-keys:** add missing visitor keys ([#4731](https://github.com/typescript-eslint/typescript-eslint/issues/4731)) ([bb575a0](https://github.com/typescript-eslint/typescript-eslint/commit/bb575a0763f39b9b988a7c20afee7b5eeb64cba7)) + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/visitor-keys diff --git a/packages/visitor-keys/package.json b/packages/visitor-keys/package.json index efdf324e80a0..b7c9846355c2 100644 --- a/packages/visitor-keys/package.json +++ b/packages/visitor-keys/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/visitor-keys", - "version": "5.17.0", + "version": "5.18.0", "description": "Visitor keys used to help traverse the TypeScript-ESTree AST", "keywords": [ "eslint", @@ -38,7 +38,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "5.17.0", + "@typescript-eslint/types": "5.18.0", "eslint-visitor-keys": "^3.0.0" }, "devDependencies": { diff --git a/packages/visitor-keys/src/visitor-keys.ts b/packages/visitor-keys/src/visitor-keys.ts index 85e424308197..3e49d2d1b484 100644 --- a/packages/visitor-keys/src/visitor-keys.ts +++ b/packages/visitor-keys/src/visitor-keys.ts @@ -49,7 +49,7 @@ const additionalKeys: AdditionalKeys = { Identifier: ['decorators', 'typeAnnotation'], ImportDeclaration: ['specifiers', 'source', 'assertions'], ImportExpression: ['source', 'attributes'], - MethodDefinition: ['decorators', 'key', 'value'], + MethodDefinition: ['decorators', 'key', 'value', 'typeParameters'], NewExpression: ['callee', 'typeParameters', 'arguments'], ObjectPattern: ['decorators', 'properties', 'typeAnnotation'], PropertyDefinition: ['decorators', 'key', 'typeAnnotation', 'value'], @@ -110,7 +110,7 @@ const additionalKeys: AdditionalKeys = { TSMethodSignature: ['typeParameters', 'key', 'params', 'returnType'], TSModuleBlock: ['body'], TSModuleDeclaration: ['id', 'body'], - TSNamedTupleMember: ['elementType'], + TSNamedTupleMember: ['label', 'elementType'], TSNamespaceExportDeclaration: ['id'], TSNeverKeyword: [], TSNonNullExpression: ['expression'], diff --git a/packages/website-eslint/CHANGELOG.md b/packages/website-eslint/CHANGELOG.md index 2c1a65156eae..c3bd98cf7ea5 100644 --- a/packages/website-eslint/CHANGELOG.md +++ b/packages/website-eslint/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package @typescript-eslint/website-eslint + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) **Note:** Version bump only for package @typescript-eslint/website-eslint diff --git a/packages/website-eslint/package.json b/packages/website-eslint/package.json index 9fb83656e647..2883fd831f9d 100644 --- a/packages/website-eslint/package.json +++ b/packages/website-eslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/website-eslint", - "version": "5.17.0", + "version": "5.18.0", "private": true, "description": "ESLint which works in browsers.", "engines": { @@ -16,19 +16,19 @@ "format": "prettier --write \"./**/*.{ts,js,json,md}\" --ignore-path ../../.prettierignore" }, "dependencies": { - "@typescript-eslint/types": "5.17.0", - "@typescript-eslint/utils": "5.17.0" + "@typescript-eslint/types": "5.18.0", + "@typescript-eslint/utils": "5.18.0" }, "devDependencies": { "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^13.0.6", "@rollup/pluginutils": "^4.1.1", - "@typescript-eslint/eslint-plugin": "5.17.0", - "@typescript-eslint/parser": "5.17.0", - "@typescript-eslint/scope-manager": "5.17.0", - "@typescript-eslint/typescript-estree": "5.17.0", - "@typescript-eslint/visitor-keys": "5.17.0", + "@typescript-eslint/eslint-plugin": "5.18.0", + "@typescript-eslint/parser": "5.18.0", + "@typescript-eslint/scope-manager": "5.18.0", + "@typescript-eslint/typescript-estree": "5.18.0", + "@typescript-eslint/visitor-keys": "5.18.0", "eslint": "*", "rollup": "^2.59.0", "semver": "^7.3.5" diff --git a/packages/website-eslint/src/linter/CompilerHost.js b/packages/website-eslint/src/linter/CompilerHost.js index 2b7fdec25d07..f48c77109c96 100644 --- a/packages/website-eslint/src/linter/CompilerHost.js +++ b/packages/website-eslint/src/linter/CompilerHost.js @@ -1,9 +1,43 @@ -import { getDefaultLibFileName } from 'typescript'; +import { + getDefaultLibFileName, + ScriptKind, + createSourceFile, + ScriptTarget, +} from 'typescript'; + +function getScriptKind(isJsx, filePath) { + const extension = (/(\.[a-z]+)$/.exec(filePath)?.[0] || '').toLowerCase(); + + switch (extension) { + case '.ts': + return ScriptKind.TS; + case '.tsx': + return ScriptKind.TSX; + case '.js': + return ScriptKind.JS; + + case '.jsx': + return ScriptKind.JSX; + + case '.json': + return ScriptKind.JSON; + + default: + // unknown extension, force typescript to ignore the file extension, and respect the user's setting + return isJsx ? ScriptKind.TSX : ScriptKind.TS; + } +} export class CompilerHost { - constructor(files, sourceFiles) { - this.files = files; - this.sourceFiles = sourceFiles; + constructor(libs, isJsx) { + this.files = []; + this.isJsx = isJsx || false; + + if (libs) { + for (const [key, value] of libs) { + this.files[key] = value; + } + } } fileExists(name) { @@ -39,10 +73,20 @@ export class CompilerHost { } readFile(name) { - return this.files[name]; + if (this.fileExists(name)) { + return this.files[name]; + } else { + return ''; // fallback, in case if file is not available + } } getSourceFile(name) { - return this.sourceFiles[name]; + return createSourceFile( + name, + this.readFile(name), + ScriptTarget.Latest, + /* setParentNodes */ true, + getScriptKind(this.isJsx, name), + ); } } diff --git a/packages/website-eslint/src/linter/create-ast-program.js b/packages/website-eslint/src/linter/create-ast-program.js deleted file mode 100644 index ea0444fd2491..000000000000 --- a/packages/website-eslint/src/linter/create-ast-program.js +++ /dev/null @@ -1,44 +0,0 @@ -import { - createProgram, - createSourceFile, - ScriptTarget, - ScriptKind, - JsxEmit, - ModuleKind, -} from 'typescript'; -import { CompilerHost } from './CompilerHost'; - -export function createASTProgram(code, parserOptions) { - const isJsx = !!parserOptions?.ecmaFeatures?.jsx; - const fileName = isJsx ? '/demo.tsx' : '/demo.ts'; - const files = { - [fileName]: code, - }; - const sourceFiles = { - [fileName]: createSourceFile( - fileName, - code, - ScriptTarget.Latest, - true, - isJsx ? ScriptKind.TSX : ScriptKind.TS, - ), - }; - const compilerHost = new CompilerHost(files, sourceFiles); - const compilerOptions = { - noResolve: true, - strict: true, - target: ScriptTarget.Latest, - jsx: isJsx ? JsxEmit.React : undefined, - module: ModuleKind.ES2015, - }; - const program = createProgram( - Object.keys(files), - compilerOptions, - compilerHost, - ); - const ast = program.getSourceFile(fileName); - return { - ast, - program, - }; -} diff --git a/packages/website-eslint/src/linter/linter.js b/packages/website-eslint/src/linter/linter.js index aae8ecc0feda..6d88c341f9c0 100644 --- a/packages/website-eslint/src/linter/linter.js +++ b/packages/website-eslint/src/linter/linter.js @@ -5,15 +5,20 @@ import rules from '@typescript-eslint/eslint-plugin/dist/rules'; const PARSER_NAME = '@typescript-eslint/parser'; -export function loadLinter() { +export function loadLinter(libs, compilerOptions) { const linter = new Linter(); let storedAST; let storedTsAST; let storedScope; linter.defineParser(PARSER_NAME, { - parseForESLint(code, options) { - const toParse = parseForESLint(code, options); + parseForESLint(code, eslintOptions) { + const toParse = parseForESLint( + code, + eslintOptions, + compilerOptions, + libs, + ); storedAST = toParse.ast; storedTsAST = toParse.tsAst; storedScope = toParse.scopeManager; diff --git a/packages/website-eslint/src/linter/parser.js b/packages/website-eslint/src/linter/parser.js index 41c0b24baf10..fc637fe65b7d 100644 --- a/packages/website-eslint/src/linter/parser.js +++ b/packages/website-eslint/src/linter/parser.js @@ -1,42 +1,55 @@ import { analyze } from '@typescript-eslint/scope-manager/dist/analyze'; import { visitorKeys } from '@typescript-eslint/visitor-keys/dist/visitor-keys'; import { astConverter } from '@typescript-eslint/typescript-estree/dist/ast-converter'; -import { createASTProgram } from './create-ast-program.js'; import { extra } from './config.js'; +import { CompilerHost } from './CompilerHost'; +import { createProgram } from 'typescript'; -function parseAndGenerateServices(code, options) { - const { ast, program } = createASTProgram(code, options); - const { estree, astMaps } = astConverter( - ast, - { ...extra, code, jsx: options.jsx ?? false }, - true, - ); +export function createASTProgram(code, isJsx, compilerOptions, libs) { + const fileName = isJsx ? '/demo.tsx' : '/demo.ts'; + const compilerHost = new CompilerHost(libs, isJsx); + compilerHost.files[fileName] = code; + const program = createProgram( + Object.keys(compilerHost.files), + compilerOptions, + compilerHost, + ); + const ast = program.getSourceFile(fileName); return { - ast: estree, - tsAst: ast, - services: { - hasFullTypeInformation: true, - program, - esTreeNodeToTSNodeMap: astMaps.esTreeNodeToTSNodeMap, - tsNodeToESTreeNodeMap: astMaps.tsNodeToESTreeNodeMap, - }, + ast, + program, }; } -export function parseForESLint(code, parserOptions) { - const { ast, tsAst, services } = parseAndGenerateServices(code, { - ...parserOptions, - jsx: parserOptions.ecmaFeatures?.jsx ?? false, - useJSXTextNode: true, - projectFolderIgnoreList: [], - }); +export function parseForESLint(code, eslintOptions, compilerOptions, libs) { + const isJsx = eslintOptions.ecmaFeatures?.jsx ?? false; + + const { ast: tsAst, program } = createASTProgram( + code, + isJsx, + compilerOptions, + libs, + ); + + const { estree: ast, astMaps } = astConverter( + tsAst, + { ...extra, code, jsx: isJsx }, + true, + ); + + const services = { + hasFullTypeInformation: true, + program, + esTreeNodeToTSNodeMap: astMaps.esTreeNodeToTSNodeMap, + tsNodeToESTreeNodeMap: astMaps.tsNodeToESTreeNodeMap, + }; const scopeManager = analyze(ast, { ecmaVersion: - parserOptions.ecmaVersion === 'latest' ? 1e8 : parserOptions.ecmaVersion, - globalReturn: parserOptions.ecmaFeatures?.globalReturn ?? false, - sourceType: parserOptions.sourceType ?? 'script', + eslintOptions.ecmaVersion === 'latest' ? 1e8 : eslintOptions.ecmaVersion, + globalReturn: eslintOptions.ecmaFeatures?.globalReturn ?? false, + sourceType: eslintOptions.sourceType ?? 'script', }); return { diff --git a/packages/website-eslint/types/index.d.ts b/packages/website-eslint/types/index.d.ts index ed3e1e2422f8..429de7388fa4 100644 --- a/packages/website-eslint/types/index.d.ts +++ b/packages/website-eslint/types/index.d.ts @@ -1,6 +1,6 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import type { ParserOptions } from '@typescript-eslint/types'; -import type { SourceFile } from 'typescript'; +import type { SourceFile, CompilerOptions } from 'typescript'; export type LintMessage = TSESLint.Linter.LintMessage; export type RuleFix = TSESLint.RuleFix; @@ -22,7 +22,10 @@ export interface WebLinter { } export interface LinterLoader { - loadLinter(): WebLinter; + loadLinter( + libMap: Map, + compilerOptions: CompilerOptions, + ): WebLinter; } export type { diff --git a/packages/website/CHANGELOG.md b/packages/website/CHANGELOG.md index db3ac9ab9b99..7de164212c93 100644 --- a/packages/website/CHANGELOG.md +++ b/packages/website/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [5.18.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.17.0...v5.18.0) (2022-04-04) + +**Note:** Version bump only for package website + + + + + # [5.17.0](https://github.com/typescript-eslint/typescript-eslint/compare/v5.16.0...v5.17.0) (2022-03-28) diff --git a/packages/website/package.json b/packages/website/package.json index 9ebc0a790a5f..86d5a8a0bcd3 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "website", - "version": "5.17.0", + "version": "5.18.0", "private": true, "scripts": { "build": "docusaurus build", @@ -24,7 +24,7 @@ "@docusaurus/theme-common": "^2.0.0-beta.15", "@docusaurus/theme-search-algolia": "^2.0.0-beta.15", "@mdx-js/react": "1.6.22", - "@typescript-eslint/website-eslint": "5.17.0", + "@typescript-eslint/website-eslint": "5.18.0", "clsx": "^1.1.1", "eslint": "*", "json5": "^2.2.0", diff --git a/packages/website/src/components/ast/serializer/serializerTS.ts b/packages/website/src/components/ast/serializer/serializerTS.ts index fd03d983ba76..b89d6e0e1a44 100644 --- a/packages/website/src/components/ast/serializer/serializerTS.ts +++ b/packages/website/src/components/ast/serializer/serializerTS.ts @@ -24,6 +24,8 @@ export const propsToFilter = [ 'transformFlags', 'resolvedModules', 'imports', + 'antecedent', + 'antecedents', ]; function isTsNode(value: unknown): value is Node { diff --git a/packages/website/src/components/config/ConfigTypeScript.tsx b/packages/website/src/components/config/ConfigTypeScript.tsx index 27cc2cbdd97b..b2c215c6b577 100644 --- a/packages/website/src/components/config/ConfigTypeScript.tsx +++ b/packages/website/src/components/config/ConfigTypeScript.tsx @@ -1,7 +1,6 @@ -import React, { useCallback } from 'react'; -import tsConfigOptions from '../tsConfigOptions.json'; +import React, { useCallback, useEffect, useState } from 'react'; -import ConfigEditor from './ConfigEditor'; +import ConfigEditor, { ConfigOptionsType } from './ConfigEditor'; import type { CompilerFlags } from '../types'; import { shallowEqual } from '../lib/shallowEqual'; @@ -11,11 +10,59 @@ interface ModalTypeScriptProps { readonly config?: CompilerFlags; } +interface OptionDeclarations { + name: string; + type?: unknown; + category?: { message: string }; + description?: { message: string }; +} + function checkOptions(item: [string, unknown]): item is [string, boolean] { return typeof item[1] === 'boolean'; } function ConfigTypeScript(props: ModalTypeScriptProps): JSX.Element { + const [tsConfigOptions, updateOptions] = useState([]); + + useEffect(() => { + if (window.ts) { + updateOptions( + Object.values( + // @ts-expect-error: definition is not fully correct + (window.ts.optionDeclarations as OptionDeclarations[]) + .filter( + item => + item.type === 'boolean' && + item.description && + item.category && + ![ + 'Command-line Options', + 'Modules', + 'Projects', + 'Compiler Diagnostics', + 'Editor Support', + 'Output Formatting', + 'Watch and Build Modes', + 'Source Map Options', + ].includes(item.category.message), + ) + .reduce>((group, item) => { + const category = item.category!.message; + group[category] = group[category] ?? { + heading: category, + fields: [], + }; + group[category].fields.push({ + key: item.name, + label: item.description!.message, + }); + return group; + }, {}), + ), + ); + } + }, [props.isOpen]); + const onClose = useCallback( (newConfig: Record) => { const cfg = Object.fromEntries( diff --git a/packages/website/src/components/editor/LoadedEditor.tsx b/packages/website/src/components/editor/LoadedEditor.tsx index a3e8395bc3d7..880cf79a8a7a 100644 --- a/packages/website/src/components/editor/LoadedEditor.tsx +++ b/packages/website/src/components/editor/LoadedEditor.tsx @@ -139,8 +139,12 @@ export const LoadedEditor: React.FC = ({ useEffect(() => { sandboxInstance.setCompilerSettings({ + noResolve: true, + strict: true, + target: main.languages.typescript.ScriptTarget.ESNext, + module: main.languages.typescript.ModuleKind.ESNext, ...tsConfig, - jsx: jsx ? 2 : 0, + jsx: jsx ? main.languages.typescript.JsxEmit.React : undefined, }); }, [jsx, sandboxInstance, JSON.stringify(tsConfig) /* todo: better way? */]); diff --git a/packages/website/src/components/editor/useSandboxServices.ts b/packages/website/src/components/editor/useSandboxServices.ts index ffd6aa686ffb..b64345124b87 100644 --- a/packages/website/src/components/editor/useSandboxServices.ts +++ b/packages/website/src/components/editor/useSandboxServices.ts @@ -47,7 +47,16 @@ export const useSandboxServices = ( setLoadedTs(props.ts); sandboxSingleton(props.ts) - .then(({ main, sandboxFactory, ts, linter }) => { + .then(async ({ main, sandboxFactory, ts, linter }) => { + const compilerOptions = { + noResolve: true, + strict: true, + target: main.languages.typescript.ScriptTarget.ESNext, + jsx: props.jsx ? main.languages.typescript.JsxEmit.React : undefined, + lib: ['ESNext'], + module: main.languages.typescript.ModuleKind.ESNext, + }; + const sandboxConfig: Partial = { text: '', monacoSettings: { @@ -57,15 +66,7 @@ export const useSandboxServices = ( scrollBeyondLastLine: false, smoothScrolling: true, }, - compilerOptions: { - noResolve: true, - strict: true, - target: main.languages.typescript.ScriptTarget.ESNext, - jsx: props.jsx - ? main.languages.typescript.JsxEmit.React - : undefined, - module: main.languages.typescript.ModuleKind.ESNext, - }, + compilerOptions: compilerOptions, domID: editorEmbedId, }; @@ -75,7 +76,14 @@ export const useSandboxServices = ( ts, ); - const webLinter = linter.loadLinter(); + const libMap = await sandboxInstance.tsvfs.createDefaultMapFromCDN( + sandboxInstance.getCompilerOptions(), + props.ts, + true, + window.ts, + ); + + const webLinter = linter.loadLinter(libMap, compilerOptions); props.onLoaded(webLinter.ruleNames, sandboxInstance.supportedVersions); diff --git a/packages/website/src/components/tsConfigOptions.json b/packages/website/src/components/tsConfigOptions.json deleted file mode 100644 index 8ddd3b6d35df..000000000000 --- a/packages/website/src/components/tsConfigOptions.json +++ /dev/null @@ -1,97 +0,0 @@ -[ - { - "heading": "Interop Constraints", - "fields": [ - { - "key": "isolatedModules", - "label": "Ensure that each file can be safely transpiled without relying on other imports." - }, - { - "key": "allowSyntheticDefaultImports", - "label": "Allow `import x from y` when a module doesn't have a default export." - }, - { - "key": "esModuleInterop", - "label": "Emit additional JavaScript to ease support for importing CommonJS modules. This enables allowSyntheticDefaultImports for type compatibility." - } - ] - }, - { - "heading": "Type Checking", - "fields": [ - { - "key": "strict", - "label": "Enable all strict type-checking options." - }, - { - "key": "noImplicitAny", - "label": "Enable error reporting for expressions and declarations with an implied any type.." - }, - { - "key": "strictNullChecks", - "label": "When type checking, take into account null and undefined." - }, - { - "key": "strictFunctionTypes", - "label": "When assigning functions, check to ensure parameters and the return values are subtype-compatible." - }, - { - "key": "strictBindCallApply", - "label": "Check that the arguments for bind, call, and apply methods match the original function." - }, - { - "key": "strictPropertyInitialization", - "label": "Check for class properties that are declared but not set in the constructor." - }, - { - "key": "noImplicitThis", - "label": "Enable error reporting when this is given the type any." - }, - { - "key": "alwaysStrict", - "label": "Ensure `use strict` is always emitted." - }, - { - "key": "noUnusedLocals", - "label": "Enable error reporting when a local variables aren't read." - }, - { - "key": "noUnusedParameters", - "label": "Raise an error when a function parameter isn't read." - }, - { - "key": "noImplicitReturns", - "label": "Enable error reporting for codepaths that do not explicitly return in a function." - }, - { - "key": "noFallthroughCasesInSwitch", - "label": "Enable error reporting for fallthrough cases in switch statements." - }, - { - "key": "allowUnusedLabels", - "label": "Disable error reporting for unused labels." - }, - { - "key": "allowUnreachableCode", - "label": "Disable error reporting for unreachable code." - } - ] - }, - { - "heading": "Language and Environment", - "fields": [ - { - "key": "experimentalDecorators", - "label": "Enable experimental support for TC39 stage 2 draft decorators." - }, - { - "key": "emitDecoratorMetadata", - "label": "Emit design-type metadata for decorated declarations in source files." - }, - { - "key": "noLib", - "label": "Disable including any library files, including the default lib.d.ts." - } - ] - } -] diff --git a/packages/website/src/css/custom.css b/packages/website/src/css/custom.css index ade3524adb2f..fc3611513ce3 100644 --- a/packages/website/src/css/custom.css +++ b/packages/website/src/css/custom.css @@ -19,7 +19,6 @@ html:root { --ifm-code-font-size: 95%; --ifm-color-info: var(--ifm-color-primary-dark); --ifm-link-color: var(--ifm-color-primary-dark); - --ifm-link-color: var(--ifm-color-primary-dark); --code-line-decoration: rgba(53, 120, 229, 0.1); --code-editor-bg: #ffffff; @@ -27,7 +26,7 @@ html:root { --docsearch-muted-color: #666; } -html[data-theme='dark'] { +html[data-theme='dark']:root { --ifm-color-feedback-background: #f0f8ff; --ifm-color-primary: #4e89e8; --ifm-color-primary-dark: #144697; @@ -41,7 +40,6 @@ html[data-theme='dark'] { --ifm-code-color: rgb(248, 248, 242); --ifm-color-info: var(--ifm-color-primary-light); --ifm-link-color: var(--ifm-color-primary-light); - --ifm-link-color: var(--ifm-color-primary-light); --ifm-menu-color-active: var(--ifm-color-primary-light); --ifm-navbar-link-hover-color: var(--ifm-color-primary-light); diff --git a/yarn.lock b/yarn.lock index 05ea3f1c11ba..a86d7ab53d08 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3578,9 +3578,9 @@ integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== "@rollup/plugin-commonjs@^21.0.1": - version "21.0.2" - resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.2.tgz#0b9c539aa1837c94abfaf87945838b0fc8564891" - integrity sha512-d/OmjaLVO4j/aQX69bwpWPpbvI3TJkQuxoAk7BH8ew1PyoMBLTOuvJTjzG8oEoW7drIIqB0KCJtfFLu/2GClWg== + version "21.0.3" + resolved "https://registry.yarnpkg.com/@rollup/plugin-commonjs/-/plugin-commonjs-21.0.3.tgz#287896c64926ef3d7f0013708dcdcc1223576ef0" + integrity sha512-ThGfwyvcLc6cfP/MWxA5ACF+LZCvsuhUq7V5134Az1oQWsiC7lNpLT4mJI86WQunK7BYmpUiHmMk2Op6OAHs0g== dependencies: "@rollup/pluginutils" "^3.1.0" commondir "^1.0.1"