From 219b841206656d2364b7f1a9ce61ceeee68bbbe6 Mon Sep 17 00:00:00 2001 From: auvred <61150013+auvred@users.noreply.github.com> Date: Mon, 22 Apr 2024 23:10:56 +0300 Subject: [PATCH 01/15] chore: resolve lint issues on main branch (#8966) * chore(typescript-estree): resolve lint issue with explicit-function-return-type in createProjectService.ts * chore(eslint-plugin): fix lint issues --- .../prefer-optional-chain.test.ts | 96 +++++++++++++++++-- .../create-program/createProjectService.ts | 6 +- 2 files changed, 93 insertions(+), 9 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts index 91e908015fbb..eddfd57bb994 100644 --- a/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts @@ -1946,24 +1946,66 @@ describe('hand-crafted cases', () => { declare const thing1: string | null; thing1 && thing1.toString(); `, + output: null, options: [{ requireNullish: true }], - errors: [{ messageId: 'preferOptionalChain' }], + errors: [ + { + messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: ` + declare const thing1: string | null; + thing1?.toString(); + `, + }, + ], + }, + ], }, { code: ` declare const thing1: string | null; thing1 && thing1.toString() && true; `, + output: null, options: [{ requireNullish: true }], - errors: [{ messageId: 'preferOptionalChain' }], + errors: [ + { + messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: ` + declare const thing1: string | null; + thing1?.toString() && true; + `, + }, + ], + }, + ], }, { code: ` declare const foo: string | null; foo && foo.toString() && foo.toString(); `, + output: null, options: [{ requireNullish: true }], - errors: [{ messageId: 'preferOptionalChain' }], + errors: [ + { + messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: ` + declare const foo: string | null; + foo?.toString() && foo.toString(); + `, + }, + ], + }, + ], }, { code: ` @@ -1994,24 +2036,66 @@ describe('hand-crafted cases', () => { declare const foo: string | null; (foo || {}).toString(); `, + output: null, options: [{ requireNullish: true }], - errors: [{ messageId: 'preferOptionalChain' }], + errors: [ + { + messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: ` + declare const foo: string | null; + foo?.toString(); + `, + }, + ], + }, + ], }, { code: ` declare const foo: string; (foo || undefined || {}).toString(); `, + output: null, options: [{ requireNullish: true }], - errors: [{ messageId: 'preferOptionalChain' }], + errors: [ + { + messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: ` + declare const foo: string; + (foo || undefined)?.toString(); + `, + }, + ], + }, + ], }, { code: ` declare const foo: string | null; (foo || undefined || {}).toString(); `, + output: null, options: [{ requireNullish: true }], - errors: [{ messageId: 'preferOptionalChain' }], + errors: [ + { + messageId: 'preferOptionalChain', + suggestions: [ + { + messageId: 'optionalChainSuggest', + output: ` + declare const foo: string | null; + (foo || undefined)?.toString(); + `, + }, + ], + }, + ], }, // allowPotentiallyUnsafeFixesThatModifyTheReturnTypeIKnowWhatImDoing diff --git a/packages/typescript-estree/src/create-program/createProjectService.ts b/packages/typescript-estree/src/create-program/createProjectService.ts index c355033191c4..b63273ad1265 100644 --- a/packages/typescript-estree/src/create-program/createProjectService.ts +++ b/packages/typescript-estree/src/create-program/createProjectService.ts @@ -48,10 +48,10 @@ export function createProjectService( logger: { close: doNothing, endGroup: doNothing, - getLogFileName: () => undefined, - hasLevel: () => false, + getLogFileName: (): undefined => undefined, + hasLevel: (): boolean => false, info: doNothing, - loggingEnabled: () => false, + loggingEnabled: (): boolean => false, msg: doNothing, perftrc: doNothing, startGroup: doNothing, From 176388956abfe79df35a69f2ddd89e762b6d1b0d Mon Sep 17 00:00:00 2001 From: auvred <61150013+auvred@users.noreply.github.com> Date: Tue, 23 Apr 2024 22:56:04 +0300 Subject: [PATCH 02/15] fix(utils): export ESLint backwards-compat functions (#8976) --- packages/utils/src/eslint-utils/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/utils/src/eslint-utils/index.ts b/packages/utils/src/eslint-utils/index.ts index baf3e82bc653..29062e4e7083 100644 --- a/packages/utils/src/eslint-utils/index.ts +++ b/packages/utils/src/eslint-utils/index.ts @@ -1,4 +1,5 @@ export * from './applyDefault'; +export * from './context'; export * from './getParserServices'; export * from './InferTypesFromRule'; export * from './RuleCreator'; From ba1eb20aba99e32d16049e8cd0336fced98277ef Mon Sep 17 00:00:00 2001 From: Kim Sang Du Date: Wed, 24 Apr 2024 05:31:35 +0900 Subject: [PATCH 03/15] test(type-utils): add unit tests for requiresQuoting (#8691) * test: add testCase * test: fix test case result * docs: add comment in testcase and function --- packages/type-utils/src/requiresQuoting.ts | 2 +- .../type-utils/tests/requiresQuoting.test.ts | 86 +++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 packages/type-utils/tests/requiresQuoting.test.ts diff --git a/packages/type-utils/src/requiresQuoting.ts b/packages/type-utils/src/requiresQuoting.ts index 27c9a2ff77cf..dae27996df3d 100644 --- a/packages/type-utils/src/requiresQuoting.ts +++ b/packages/type-utils/src/requiresQuoting.ts @@ -1,5 +1,5 @@ import * as ts from 'typescript'; - +/*** Indicates whether identifiers require the use of quotation marks when accessing property definitions and dot notation. */ function requiresQuoting( name: string, target: ts.ScriptTarget = ts.ScriptTarget.ESNext, diff --git a/packages/type-utils/tests/requiresQuoting.test.ts b/packages/type-utils/tests/requiresQuoting.test.ts new file mode 100644 index 000000000000..59c7d02e60e4 --- /dev/null +++ b/packages/type-utils/tests/requiresQuoting.test.ts @@ -0,0 +1,86 @@ +import { requiresQuoting } from '../src'; + +describe('getDeclaration', () => { + describe('valid identifier', () => { + it('upper and lower case alphabet', () => { + const name = 'c'; + const result = requiresQuoting(name); + expect(result).toBe(false); + }); + + it('upper and lower case alphabet with number not first', () => { + const name = 'foo1234Bar'; + const result = requiresQuoting(name); + expect(result).toBe(false); + }); + + it('start with dollorSign', () => { + const name = '$bar'; + const result = requiresQuoting(name); + expect(result).toBe(false); + }); + it('include dollorSign not start position', () => { + const name = 'foo$bar'; + const result = requiresQuoting(name); + expect(result).toBe(false); + }); + + it('start with underScore', () => { + const name = '_bar'; + const result = requiresQuoting(name); + expect(result).toBe(false); + }); + it('include underScore not start position', () => { + const name = 'foo_bar'; + const result = requiresQuoting(name); + expect(result).toBe(false); + }); + + it('non-alphabet characters', () => { + const name = 'café'; + const result = requiresQuoting(name); + expect(result).toBe(false); + }); + }); + + describe('invalid identifier', () => { + // This test case is written because it is possible to access object properties, but dot annotation is not accessible. + it('only number', () => { + const name = '12345'; + const result = requiresQuoting(name); + expect(result).toBe(true); + }); + it('start with number', () => { + const name = '1axcef'; + const result = requiresQuoting(name); + expect(result).toBe(true); + }); + it('start with dash', () => { + const name = '-bar'; + const result = requiresQuoting(name); + expect(result).toBe(true); + }); + it('include dash not start position', () => { + const name = 'foo-bar'; + const result = requiresQuoting(name); + expect(result).toBe(true); + }); + it('empty string', () => { + const name = ''; + const result = requiresQuoting(name); + expect(result).toBe(true); + }); + it('include special symbol at first', () => { + const name = '!asdfs'; + const result = requiresQuoting(name); + expect(result).toBe(true); + }); + + it('include special symbol at middle', () => { + const name = 'asd!fs'; + const result = requiresQuoting(name); + + expect(result).toBe(true); + }); + }); +}); From b0f7aa469523357e17803d902a83f495bfa5f36e Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Wed, 24 Apr 2024 05:43:43 +0900 Subject: [PATCH 04/15] fix(eslint-plugin): [no-unsafe-argument] handle tagged templates (#8746) * feat(eslint-plugin): [no-unsafe-argument] handle tagged templates * add istanbul comment * add test cases * fix error loc * fix: add null throws --- .../src/rules/no-unsafe-argument.ts | 206 ++++++++++-------- .../tests/rules/no-unsafe-argument.test.ts | 99 +++++++++ 2 files changed, 211 insertions(+), 94 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-argument.ts b/packages/eslint-plugin/src/rules/no-unsafe-argument.ts index 177954392bb7..d55d8f75b06e 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-argument.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-argument.ts @@ -9,6 +9,7 @@ import { isTypeAnyArrayType, isTypeAnyType, isUnsafeAssignment, + nullThrows, } from '../util'; type MessageIds = @@ -162,114 +163,131 @@ export default createRule<[], MessageIds>({ const services = getParserServices(context); const checker = services.program.getTypeChecker(); - return { - 'CallExpression, NewExpression'( - node: TSESTree.CallExpression | TSESTree.NewExpression, - ): void { - if (node.arguments.length === 0) { - return; - } + function checkUnsafeArguments( + args: TSESTree.Expression[] | TSESTree.CallExpressionArgument[], + callee: TSESTree.LeftHandSideExpression, + node: + | TSESTree.CallExpression + | TSESTree.NewExpression + | TSESTree.TaggedTemplateExpression, + ): void { + if (args.length === 0) { + return; + } - // ignore any-typed calls as these are caught by no-unsafe-call - if (isTypeAnyType(services.getTypeAtLocation(node.callee))) { - return; - } + // ignore any-typed calls as these are caught by no-unsafe-call + if (isTypeAnyType(services.getTypeAtLocation(callee))) { + return; + } - const tsNode = services.esTreeNodeToTSNodeMap.get(node); - const signature = FunctionSignature.create(checker, tsNode); - if (!signature) { - return; - } + const tsNode = services.esTreeNodeToTSNodeMap.get(node); + const signature = nullThrows( + FunctionSignature.create(checker, tsNode), + 'Expected to a signature resolved', + ); - for (const argument of node.arguments) { - switch (argument.type) { - // spreads consume - case AST_NODE_TYPES.SpreadElement: { - const spreadArgType = services.getTypeAtLocation( - argument.argument, - ); + if (node.type === AST_NODE_TYPES.TaggedTemplateExpression) { + // Consumes the first parameter (TemplateStringsArray) of the function called with TaggedTemplateExpression. + signature.getNextParameterType(); + } + + for (const argument of args) { + switch (argument.type) { + // spreads consume + case AST_NODE_TYPES.SpreadElement: { + const spreadArgType = services.getTypeAtLocation(argument.argument); - if (isTypeAnyType(spreadArgType)) { - // foo(...any) - context.report({ - node: argument, - messageId: 'unsafeSpread', - }); - } else if (isTypeAnyArrayType(spreadArgType, checker)) { - // foo(...any[]) + if (isTypeAnyType(spreadArgType)) { + // foo(...any) + context.report({ + node: argument, + messageId: 'unsafeSpread', + }); + } else if (isTypeAnyArrayType(spreadArgType, checker)) { + // foo(...any[]) - // TODO - we could break down the spread and compare the array type against each argument - context.report({ - node: argument, - messageId: 'unsafeArraySpread', - }); - } else if (checker.isTupleType(spreadArgType)) { - // foo(...[tuple1, tuple2]) - const spreadTypeArguments = - checker.getTypeArguments(spreadArgType); - for (const tupleType of spreadTypeArguments) { - const parameterType = signature.getNextParameterType(); - if (parameterType == null) { - continue; - } - const result = isUnsafeAssignment( - tupleType, - parameterType, - checker, - // we can't pass the individual tuple members in here as this will most likely be a spread variable - // not a spread array - null, - ); - if (result) { - context.report({ - node: argument, - messageId: 'unsafeTupleSpread', - data: { - sender: checker.typeToString(tupleType), - receiver: checker.typeToString(parameterType), - }, - }); - } + // TODO - we could break down the spread and compare the array type against each argument + context.report({ + node: argument, + messageId: 'unsafeArraySpread', + }); + } else if (checker.isTupleType(spreadArgType)) { + // foo(...[tuple1, tuple2]) + const spreadTypeArguments = + checker.getTypeArguments(spreadArgType); + for (const tupleType of spreadTypeArguments) { + const parameterType = signature.getNextParameterType(); + if (parameterType == null) { + continue; } - if (spreadArgType.target.hasRestElement) { - // the last element was a rest - so all remaining defined arguments can be considered "consumed" - // all remaining arguments should be compared against the rest type (if one exists) - signature.consumeRemainingArguments(); + const result = isUnsafeAssignment( + tupleType, + parameterType, + checker, + // we can't pass the individual tuple members in here as this will most likely be a spread variable + // not a spread array + null, + ); + if (result) { + context.report({ + node: argument, + messageId: 'unsafeTupleSpread', + data: { + sender: checker.typeToString(tupleType), + receiver: checker.typeToString(parameterType), + }, + }); } - } else { - // something that's iterable - // handling this will be pretty complex - so we ignore it for now - // TODO - handle generic iterable case } - break; + if (spreadArgType.target.hasRestElement) { + // the last element was a rest - so all remaining defined arguments can be considered "consumed" + // all remaining arguments should be compared against the rest type (if one exists) + signature.consumeRemainingArguments(); + } + } else { + // something that's iterable + // handling this will be pretty complex - so we ignore it for now + // TODO - handle generic iterable case } + break; + } - default: { - const parameterType = signature.getNextParameterType(); - if (parameterType == null) { - continue; - } + default: { + const parameterType = signature.getNextParameterType(); + if (parameterType == null) { + continue; + } - const argumentType = services.getTypeAtLocation(argument); - const result = isUnsafeAssignment( - argumentType, - parameterType, - checker, - argument, - ); - if (result) { - context.report({ - node: argument, - messageId: 'unsafeArgument', - data: { - sender: checker.typeToString(argumentType), - receiver: checker.typeToString(parameterType), - }, - }); - } + const argumentType = services.getTypeAtLocation(argument); + const result = isUnsafeAssignment( + argumentType, + parameterType, + checker, + argument, + ); + if (result) { + context.report({ + node: argument, + messageId: 'unsafeArgument', + data: { + sender: checker.typeToString(argumentType), + receiver: checker.typeToString(parameterType), + }, + }); } } } + } + } + + return { + 'CallExpression, NewExpression'( + node: TSESTree.CallExpression | TSESTree.NewExpression, + ): void { + checkUnsafeArguments(node.arguments, node.callee, node); + }, + TaggedTemplateExpression(node: TSESTree.TaggedTemplateExpression): void { + checkUnsafeArguments(node.quasi.expressions, node.tag, node); }, }; }, diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-argument.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-argument.test.ts index e525ac428730..01b97cfb34b1 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-argument.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-argument.test.ts @@ -63,6 +63,10 @@ const x: string[] = []; foo(...x); `, ` +function foo(arg1: number, arg2: number) {} +foo(...([1, 1, 1] as [number, number, number])); + `, + ` declare function foo(arg1: Set, arg2: Map): void; const x = [new Map()] as const; @@ -105,6 +109,14 @@ declare function foo(t: T): T; const t: T = []; foo(t); `, + ` +function foo(templates: TemplateStringsArray) {} +foo\`\`; + `, + ` +function foo(templates: TemplateStringsArray, arg: any) {} +foo\`\${1 as any}\`; + `, ], invalid: [ { @@ -241,6 +253,20 @@ foo(...x); }, { code: ` +declare function foo(arg1: string, arg2: number): void; +foo(...(['foo', 1, 2] as [string, any, number])); + `, + errors: [ + { + messageId: 'unsafeTupleSpread', + line: 3, + column: 5, + endColumn: 48, + }, + ], + }, + { + code: ` declare function foo(arg1: string, arg2: number, arg2: string): void; const x = [1] as const; @@ -385,5 +411,78 @@ foo(t as any); }, ], }, + { + code: ` +function foo( + templates: TemplateStringsArray, + arg1: number, + arg2: any, + arg3: string, +) {} +declare const arg: any; +foo\`\${arg}\${arg}\${arg}\`; + `, + errors: [ + { + messageId: 'unsafeArgument', + line: 9, + column: 15, + endColumn: 18, + data: { + sender: 'any', + receiver: 'number', + }, + }, + { + messageId: 'unsafeArgument', + line: 9, + column: 27, + endColumn: 30, + data: { + sender: 'any', + receiver: 'string', + }, + }, + ], + }, + { + code: ` +function foo(templates: TemplateStringsArray, arg: number) {} +declare const arg: any; +foo\`\${arg}\`; + `, + errors: [ + { + messageId: 'unsafeArgument', + line: 4, + column: 7, + endColumn: 10, + data: { + sender: 'any', + receiver: 'number', + }, + }, + ], + }, + { + code: ` +type T = [number, T[]]; +function foo(templates: TemplateStringsArray, arg: T) {} +declare const arg: any; +foo\`\${arg}\`; + `, + errors: [ + { + messageId: 'unsafeArgument', + line: 5, + column: 7, + endColumn: 10, + data: { + sender: 'any', + receiver: 'T', + }, + }, + ], + }, ], }); From 4bed24d8d37ab066b6f3b988fd1ca7accec931c0 Mon Sep 17 00:00:00 2001 From: jsfm01 <145563295+jsfm01@users.noreply.github.com> Date: Wed, 24 Apr 2024 14:02:43 +0100 Subject: [PATCH 05/15] fix(eslint-plugin): [prefer-optional-chain] suggests optional chaining during strict null equality check (#8717) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix [prefer-optional-chain] suggests optional chaining during strict null equality * fix [prefer-optional-chain] suggests optional chaining during strict null equality * Fix lint * Add prefer-optional-chain test * Fix lint * rebase and fix prefer optional chain on strict null equality * fix prefer optional chain on strict null equality * fix lint * tests: code review suggestion * Update packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts --------- Co-authored-by: Marta Cardoso Co-authored-by: Marta Cardoso <145560260+up201304504@users.noreply.github.com> Co-authored-by: Josh Goldberg ✨ --- .../analyzeChain.ts | 21 ++++++++++++++----- .../prefer-optional-chain.test.ts | 2 ++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts index 24ba787dec77..af68f6e6c515 100644 --- a/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts +++ b/packages/eslint-plugin/src/rules/prefer-optional-chain-utils/analyzeChain.ts @@ -61,13 +61,24 @@ const analyzeAndChainOperand: OperandAnalyzer = ( chain, ) => { switch (operand.comparisonType) { - case NullishComparisonType.Boolean: + case NullishComparisonType.Boolean: { + const nextOperand = chain.at(index + 1); + if ( + nextOperand?.comparisonType === + NullishComparisonType.NotStrictEqualNull && + operand.comparedName.type === AST_NODE_TYPES.Identifier + ) { + return null; + } + return [operand]; + } + case NullishComparisonType.NotEqualNullOrUndefined: return [operand]; case NullishComparisonType.NotStrictEqualNull: { // handle `x !== null && x !== undefined` - const nextOperand = chain[index + 1] as ValidOperand | undefined; + const nextOperand = chain.at(index + 1); if ( nextOperand?.comparisonType === NullishComparisonType.NotStrictEqualUndefined && @@ -94,7 +105,7 @@ const analyzeAndChainOperand: OperandAnalyzer = ( case NullishComparisonType.NotStrictEqualUndefined: { // handle `x !== undefined && x !== null` - const nextOperand = chain[index + 1] as ValidOperand | undefined; + const nextOperand = chain.at(index + 1); if ( nextOperand?.comparisonType === NullishComparisonType.NotStrictEqualNull && @@ -132,7 +143,7 @@ const analyzeOrChainOperand: OperandAnalyzer = ( case NullishComparisonType.StrictEqualNull: { // handle `x === null || x === undefined` - const nextOperand = chain[index + 1] as ValidOperand | undefined; + const nextOperand = chain.at(index + 1); if ( nextOperand?.comparisonType === NullishComparisonType.StrictEqualUndefined && @@ -159,7 +170,7 @@ const analyzeOrChainOperand: OperandAnalyzer = ( case NullishComparisonType.StrictEqualUndefined: { // handle `x === undefined || x === null` - const nextOperand = chain[index + 1] as ValidOperand | undefined; + const nextOperand = chain.at(index + 1); if ( nextOperand?.comparisonType === NullishComparisonType.StrictEqualNull && compareNodes(operand.comparedName, nextOperand.comparedName) === diff --git a/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts b/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts index eddfd57bb994..fbab86a20910 100644 --- a/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-optional-chain/prefer-optional-chain.test.ts @@ -793,6 +793,8 @@ describe('hand-crafted cases', () => { '(function () {}) && function () {}.name;', '(class Foo {}) && class Foo {}.constructor;', "new Map().get('a') && new Map().get('a').what;", + // https://github.com/typescript-eslint/typescript-eslint/issues/7654 + 'data && data.value !== null;', { code: '
&& (
).wtf;', parserOptions: { ecmaFeatures: { jsx: true } }, From 3fd666f7ffac61d2ff61c8439b29201185ea8e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Thu, 25 Apr 2024 15:35:44 -0400 Subject: [PATCH 06/15] feat(typescript-estree): add maximumDefaultProjectFileMatchCount and wide allowDefaultProjectForFiles glob restrictions (#8925) * feat(typescript-estree): add maximumDefaultProjectFileMatchCount * lil touchup for the asterisk * Spelling and Windows normalization * Also reset new cache in persistentParse.test.ts --- .cspell.json | 2 + docs/packages/TypeScript_ESTree.mdx | 9 ++ docs/troubleshooting/FAQ.mdx | 36 +++++++- .../typescript-estree/src/clear-caches.ts | 6 +- .../create-program/createProjectService.ts | 19 ++-- .../validateDefaultProjectForFilesGlob.ts | 29 ++++++ .../typescript-estree/src/parser-options.ts | 9 ++ packages/typescript-estree/src/parser.ts | 7 ++ .../src/useProgramFromProjectService.ts | 22 ++++- .../tests/lib/persistentParse.test.ts | 8 +- .../lib/useProgramFromProjectService.test.ts | 91 +++++++++++++++++-- ...validateDefaultProjectForFilesGlob.test.ts | 35 +++++++ .../MDXComponents/HiddenHeading.module.css | 6 ++ .../src/theme/MDXComponents/HiddenHeading.tsx | 11 +++ .../website/src/theme/MDXComponents/index.tsx | 4 +- 15 files changed, 273 insertions(+), 21 deletions(-) create mode 100644 packages/typescript-estree/src/create-program/validateDefaultProjectForFilesGlob.ts create mode 100644 packages/typescript-estree/tests/lib/validateDefaultProjectForFilesGlob.test.ts create mode 100644 packages/website/src/theme/MDXComponents/HiddenHeading.module.css create mode 100644 packages/website/src/theme/MDXComponents/HiddenHeading.tsx diff --git a/.cspell.json b/.cspell.json index 279727a77428..dc41dd9403fb 100644 --- a/.cspell.json +++ b/.cspell.json @@ -50,6 +50,7 @@ "Airbnb", "Airbnb's", "ambiently", + "allowdefaultprojectforfiles", "Armano", "astexplorer", "Astro", @@ -150,6 +151,7 @@ "unoptimized", "unprefixed", "upsert", + "useprojectservice", "Waiblinger", "warnonunsupportedtypescriptversion", "Zacher" diff --git a/docs/packages/TypeScript_ESTree.mdx b/docs/packages/TypeScript_ESTree.mdx index 6454920b23c3..eb6a49c8a1bd 100644 --- a/docs/packages/TypeScript_ESTree.mdx +++ b/docs/packages/TypeScript_ESTree.mdx @@ -288,6 +288,15 @@ interface ProjectServiceOptions { * Path to a TSConfig to use instead of TypeScript's default project configuration. */ defaultProject?: string; + + /** + * The maximum number of files {@link allowDefaultProjectForFiles} may match. + * Each file match slows down linting, so if you do need to use this, please + * file an informative issue on typescript-eslint explaining why - so we can + * help you avoid using it! + * @default 8 + */ + maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING?: number; } interface ParserServices { diff --git a/docs/troubleshooting/FAQ.mdx b/docs/troubleshooting/FAQ.mdx index dd96a721bcc0..1ccc0d5a0210 100644 --- a/docs/troubleshooting/FAQ.mdx +++ b/docs/troubleshooting/FAQ.mdx @@ -32,6 +32,40 @@ If you don't find an existing extension rule, or the extension rule doesn't work > We release a new version our tooling every week. > _Please_ ensure that you [check our the latest list of "extension" rules](/rules/#extension-rules) **_before_** filing an issue. + + +## I get errors telling me "Having many files run with the default project is known to cause performance issues and slow down linting." + +These errors are caused by using the [`EXPERIMENTAL_useProjectService`](../packages/Parser.mdx#experimental_useprojectservice) `allowDefaultProjectForFiles` with an excessively wide glob. +`allowDefaultProjectForFiles` causes a new TypeScript "program" to be built for each "out of project" file it includes, which incurs a performance overhead for each file. + +To resolve this error, narrow the glob(s) used for `allowDefaultProjectForFiles` to include fewer files. +For example: + +```diff title="eslint.config.js" +parserOptions: { + EXPERIMENTAL_useProjectService: { + allowDefaultProjectForFiles: [ +- "**/*.js", ++ "./*.js" + ] + } +} +``` + +You may also need to include more files in your `tsconfig.json`. +For example: + +```diff title="tsconfig.json" +"include": [ + "src", ++ "*.js" +] +``` + +If you cannot do this, please [file an issue on typescript-eslint's typescript-estree package](https://github.com/typescript-eslint/typescript-eslint/issues/new?assignees=&labels=enhancement%2Ctriage&projects=&template=07-enhancement-other.yaml&title=Enhancement%3A+%3Ca+short+description+of+my+proposal%3E) telling us your use case and why you need more out-of-project files linted. +Be sure to include a minimal reproduction we can work with to understand your use case! + ## I get errors telling me "ESLint was configured to run ... However, that TSConfig does not / none of those TSConfigs include this file" These errors are caused by an ESLint config requesting type information be generated for a file that isn't included in the TypeScript configuration. @@ -499,6 +533,6 @@ If you think you're having issues with performance, see our [Performance Trouble ## Are TypeScript project references supported? -No, TypeScript project references are not yet supported. +Yes, but only with [`EXPERIMENTAL_useProjectService`](../packages/Parser.mdx#experimental_useprojectservice). See [issue #2094 discussing project references](https://github.com/typescript-eslint/typescript-eslint/issues/2094) for more details. diff --git a/packages/typescript-estree/src/clear-caches.ts b/packages/typescript-estree/src/clear-caches.ts index 015fd18e29c8..5e9867d3beab 100644 --- a/packages/typescript-estree/src/clear-caches.ts +++ b/packages/typescript-estree/src/clear-caches.ts @@ -1,5 +1,8 @@ import { clearWatchCaches } from './create-program/getWatchProgramsForProjects'; -import { clearProgramCache as clearProgramCacheOriginal } from './parser'; +import { + clearDefaultProjectMatchedFiles, + clearProgramCache as clearProgramCacheOriginal, +} from './parser'; import { clearTSConfigMatchCache, clearTSServerProjectService, @@ -14,6 +17,7 @@ import { clearGlobCache } from './parseSettings/resolveProjectList'; * - In custom lint tooling that iteratively lints one project at a time to prevent OOMs. */ export function clearCaches(): void { + clearDefaultProjectMatchedFiles(); clearProgramCacheOriginal(); clearWatchCaches(); clearTSConfigMatchCache(); diff --git a/packages/typescript-estree/src/create-program/createProjectService.ts b/packages/typescript-estree/src/create-program/createProjectService.ts index b63273ad1265..bad04c62e112 100644 --- a/packages/typescript-estree/src/create-program/createProjectService.ts +++ b/packages/typescript-estree/src/create-program/createProjectService.ts @@ -4,6 +4,9 @@ import os from 'node:os'; import type * as ts from 'typescript/lib/tsserverlibrary'; import type { ProjectServiceOptions } from '../parser-options'; +import { validateDefaultProjectForFilesGlob } from './validateDefaultProjectForFilesGlob'; + +const DEFAULT_PROJECT_MATCHED_FILES_THRESHOLD = 8; const doNothing = (): void => {}; @@ -15,13 +18,17 @@ export type TypeScriptProjectService = ts.server.ProjectService; export interface ProjectServiceSettings { allowDefaultProjectForFiles: string[] | undefined; + maximumDefaultProjectFileMatchCount: number; service: TypeScriptProjectService; } export function createProjectService( - options: boolean | ProjectServiceOptions | undefined, + optionsRaw: boolean | ProjectServiceOptions | undefined, jsDocParsingMode: ts.JSDocParsingMode | undefined, ): ProjectServiceSettings { + const options = typeof optionsRaw === 'object' ? optionsRaw : {}; + validateDefaultProjectForFilesGlob(options); + // We import this lazily to avoid its cost for users who don't use the service // TODO: Once we drop support for TS<5.3 we can import from "typescript" directly const tsserver = require('typescript/lib/tsserverlibrary') as typeof ts; @@ -60,7 +67,7 @@ export function createProjectService( jsDocParsingMode, }); - if (typeof options === 'object' && options.defaultProject) { + if (options.defaultProject) { let configRead; try { @@ -97,10 +104,10 @@ export function createProjectService( } return { - allowDefaultProjectForFiles: - typeof options === 'object' - ? options.allowDefaultProjectForFiles - : undefined, + allowDefaultProjectForFiles: options.allowDefaultProjectForFiles, + maximumDefaultProjectFileMatchCount: + options.maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING ?? + DEFAULT_PROJECT_MATCHED_FILES_THRESHOLD, service, }; } diff --git a/packages/typescript-estree/src/create-program/validateDefaultProjectForFilesGlob.ts b/packages/typescript-estree/src/create-program/validateDefaultProjectForFilesGlob.ts new file mode 100644 index 000000000000..598982bdc8e3 --- /dev/null +++ b/packages/typescript-estree/src/create-program/validateDefaultProjectForFilesGlob.ts @@ -0,0 +1,29 @@ +import type { ProjectServiceOptions } from '../parser-options'; + +export const DEFAULT_PROJECT_FILES_ERROR_EXPLANATION = ` + +Having many files run with the default project is known to cause performance issues and slow down linting. + +See https://typescript-eslint.io/troubleshooting/#allowdefaultprojectforfiles-glob-too-wide +`; + +export function validateDefaultProjectForFilesGlob( + options: ProjectServiceOptions, +): void { + if (!options.allowDefaultProjectForFiles?.length) { + return; + } + + for (const glob of options.allowDefaultProjectForFiles) { + if (glob === '*') { + throw new Error( + `allowDefaultProjectForFiles contains the overly wide '*'.${DEFAULT_PROJECT_FILES_ERROR_EXPLANATION}`, + ); + } + if (glob.includes('**')) { + throw new Error( + `allowDefaultProjectForFiles glob '${glob}' contains a disallowed '**'.${DEFAULT_PROJECT_FILES_ERROR_EXPLANATION}`, + ); + } + } +} diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts index b345dd72f030..8211f40f5446 100644 --- a/packages/typescript-estree/src/parser-options.ts +++ b/packages/typescript-estree/src/parser-options.ts @@ -114,6 +114,15 @@ export interface ProjectServiceOptions { * Path to a TSConfig to use instead of TypeScript's default project configuration. */ defaultProject?: string; + + /** + * The maximum number of files {@link allowDefaultProjectForFiles} may match. + * Each file match slows down linting, so if you do need to use this, please + * file an informative issue on typescript-eslint explaining why - so we can + * help you avoid using it! + * @default 8 + */ + maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING?: number; } interface ParseAndGenerateServicesOptions extends ParseOptions { diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index ffa0c4212295..b4931a6da36e 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -40,6 +40,11 @@ function clearProgramCache(): void { existingPrograms.clear(); } +const defaultProjectMatchedFiles = new Set(); +function clearDefaultProjectMatchedFiles(): void { + defaultProjectMatchedFiles.clear(); +} + /** * @param parseSettings Internal settings for parsing the file * @param hasFullTypeInformation True if the program should be attempted to be calculated from provided tsconfig files @@ -54,6 +59,7 @@ function getProgramAndAST( parseSettings.EXPERIMENTAL_projectService, parseSettings, hasFullTypeInformation, + defaultProjectMatchedFiles, ); if (fromProjectService) { return fromProjectService; @@ -286,6 +292,7 @@ export { parse, parseAndGenerateServices, ParseAndGenerateServicesResult, + clearDefaultProjectMatchedFiles, clearProgramCache, clearParseAndGenerateServicesCalls, }; diff --git a/packages/typescript-estree/src/useProgramFromProjectService.ts b/packages/typescript-estree/src/useProgramFromProjectService.ts index ba80e5599024..8f18b08ed788 100644 --- a/packages/typescript-estree/src/useProgramFromProjectService.ts +++ b/packages/typescript-estree/src/useProgramFromProjectService.ts @@ -5,6 +5,7 @@ import path from 'path'; import { createProjectProgram } from './create-program/createProjectProgram'; import type { ProjectServiceSettings } from './create-program/createProjectService'; import type { ASTAndDefiniteProgram } from './create-program/shared'; +import { DEFAULT_PROJECT_FILES_ERROR_EXPLANATION } from './create-program/validateDefaultProjectForFilesGlob'; import type { MutableParseSettings } from './parseSettings'; const log = debug( @@ -12,9 +13,14 @@ const log = debug( ); export function useProgramFromProjectService( - { allowDefaultProjectForFiles, service }: ProjectServiceSettings, + { + allowDefaultProjectForFiles, + maximumDefaultProjectFileMatchCount, + service, + }: ProjectServiceSettings, parseSettings: Readonly, hasFullTypeInformation: boolean, + defaultProjectMatchedFiles: Set, ): ASTAndDefiniteProgram | undefined { // We don't canonicalize the filename because it caused a performance regression. // See https://github.com/typescript-eslint/typescript-eslint/issues/8519 @@ -77,6 +83,20 @@ export function useProgramFromProjectService( return undefined; } + defaultProjectMatchedFiles.add(filePathAbsolute); + if (defaultProjectMatchedFiles.size > maximumDefaultProjectFileMatchCount) { + throw new Error( + `Too many files (>${maximumDefaultProjectFileMatchCount}) have matched the default project.${DEFAULT_PROJECT_FILES_ERROR_EXPLANATION} +Matching files: +${Array.from(defaultProjectMatchedFiles) + .map(file => `- ${file}`) + .join('\n')} + +If you absolutely need more files included, set parserOptions.EXPERIMENTAL_useProjectService.maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING to a larger value. +`, + ); + } + log('Found project service program for: %s', filePathAbsolute); return createProjectProgram(parseSettings, [program]); diff --git a/packages/typescript-estree/tests/lib/persistentParse.test.ts b/packages/typescript-estree/tests/lib/persistentParse.test.ts index dbfd2831dea5..2a55b63f09a0 100644 --- a/packages/typescript-estree/tests/lib/persistentParse.test.ts +++ b/packages/typescript-estree/tests/lib/persistentParse.test.ts @@ -4,7 +4,10 @@ import tmp from 'tmp'; import { clearCaches } from '../../src/clear-caches'; import { clearWatchCaches } from '../../src/create-program/getWatchProgramsForProjects'; -import { parseAndGenerateServices } from '../../src/parser'; +import { + clearDefaultProjectMatchedFiles, + parseAndGenerateServices, +} from '../../src/parser'; const CONTENTS = { foo: 'console.log("foo")', @@ -19,6 +22,9 @@ const CONTENTS = { const cwdCopy = process.cwd(); const tmpDirs = new Set(); afterEach(() => { + // reset project tracking + clearDefaultProjectMatchedFiles(); + // stop watching the files and folders clearWatchCaches(); diff --git a/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts b/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts index cec730d1cf74..5b4a9b8cabba 100644 --- a/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts +++ b/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts @@ -1,7 +1,10 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type -- Fancy mocks */ import path from 'path'; -import type { TypeScriptProjectService } from '../../src/create-program/createProjectService'; +import type { + ProjectServiceSettings, + TypeScriptProjectService, +} from '../../src/create-program/createProjectService'; import type { ParseSettings } from '../../src/parseSettings'; import { useProgramFromProjectService } from '../../src/useProgramFromProjectService'; @@ -42,14 +45,27 @@ const mockParseSettings = { filePath: 'path/PascalCaseDirectory/camelCaseFile.ts', } as ParseSettings; +const createProjectServiceSettings = < + T extends Partial, +>( + settings: T, +) => ({ + maximumDefaultProjectFileMatchCount: 8, + ...settings, +}); + describe('useProgramFromProjectService', () => { it('passes an absolute, case-matching file path to service.openClientFile', () => { const { service } = createMockProjectService(); useProgramFromProjectService( - { allowDefaultProjectForFiles: undefined, service }, + createProjectServiceSettings({ + allowDefaultProjectForFiles: undefined, + service, + }), mockParseSettings, false, + new Set(), ); expect(service.openClientFile).toHaveBeenCalledWith( @@ -69,9 +85,14 @@ describe('useProgramFromProjectService', () => { expect(() => useProgramFromProjectService( - { allowDefaultProjectForFiles: [mockParseSettings.filePath], service }, + { + allowDefaultProjectForFiles: [mockParseSettings.filePath], + maximumDefaultProjectFileMatchCount: 8, + service, + }, mockParseSettings, true, + new Set(), ), ).toThrow( `${mockParseSettings.filePath} was included by allowDefaultProjectForFiles but also was found in the project service. Consider removing it from allowDefaultProjectForFiles.`, @@ -85,28 +106,70 @@ describe('useProgramFromProjectService', () => { expect(() => useProgramFromProjectService( - { allowDefaultProjectForFiles: [], service }, + createProjectServiceSettings({ + allowDefaultProjectForFiles: [], + service, + }), mockParseSettings, true, + new Set(), ), ).toThrow( `${mockParseSettings.filePath} was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProjectForFiles.`, ); }); + it('throws an error when called more than the maximum allowed file count', () => { + const { service } = createMockProjectService(); + const program = { getSourceFile: jest.fn() }; + + mockGetProgram.mockReturnValueOnce(program); + + service.openClientFile.mockReturnValueOnce({}); + + expect(() => + useProgramFromProjectService( + createProjectServiceSettings({ + allowDefaultProjectForFiles: [mockParseSettings.filePath], + maximumDefaultProjectFileMatchCount: 2, + service, + }), + mockParseSettings, + true, + new Set(['a', 'b']), + ), + ).toThrow(`Too many files (>2) have matched the default project. + +Having many files run with the default project is known to cause performance issues and slow down linting. + +See https://typescript-eslint.io/troubleshooting/#allowdefaultprojectforfiles-glob-too-wide + +Matching files: +- a +- b +- ${path.normalize('/repos/repo/path/PascalCaseDirectory/camelCaseFile.ts')} + +If you absolutely need more files included, set parserOptions.EXPERIMENTAL_useProjectService.maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING to a larger value. +`); + }); + it('returns undefined when hasFullTypeInformation is disabled, the file is both in the project service and allowDefaultProjectForFiles, and the service does not have a matching program', () => { const { service } = createMockProjectService(); - mockGetProgram.mockReturnValue(undefined); + mockGetProgram.mockReturnValueOnce(undefined); service.openClientFile.mockReturnValueOnce({ configFileName: 'tsconfig.json', }); const actual = useProgramFromProjectService( - { allowDefaultProjectForFiles: [mockParseSettings.filePath], service }, + createProjectServiceSettings({ + allowDefaultProjectForFiles: [mockParseSettings.filePath], + service, + }), mockParseSettings, false, + new Set(), ); expect(actual).toBeUndefined(); @@ -116,7 +179,7 @@ describe('useProgramFromProjectService', () => { const { service } = createMockProjectService(); const program = { getSourceFile: jest.fn() }; - mockGetProgram.mockReturnValue(program); + mockGetProgram.mockReturnValueOnce(program); service.openClientFile.mockReturnValueOnce({ configFileName: 'tsconfig.json', @@ -124,9 +187,13 @@ describe('useProgramFromProjectService', () => { mockCreateProjectProgram.mockReturnValueOnce(program); const actual = useProgramFromProjectService( - { allowDefaultProjectForFiles: [mockParseSettings.filePath], service }, + createProjectServiceSettings({ + allowDefaultProjectForFiles: [mockParseSettings.filePath], + service, + }), mockParseSettings, false, + new Set(), ); expect(actual).toBe(program); @@ -136,15 +203,19 @@ describe('useProgramFromProjectService', () => { const { service } = createMockProjectService(); const program = { getSourceFile: jest.fn() }; - mockGetProgram.mockReturnValue(program); + mockGetProgram.mockReturnValueOnce(program); service.openClientFile.mockReturnValueOnce({}); mockCreateProjectProgram.mockReturnValueOnce(program); const actual = useProgramFromProjectService( - { allowDefaultProjectForFiles: [], service }, + createProjectServiceSettings({ + allowDefaultProjectForFiles: [], + service, + }), mockParseSettings, false, + new Set(), ); expect(actual).toBe(program); diff --git a/packages/typescript-estree/tests/lib/validateDefaultProjectForFilesGlob.test.ts b/packages/typescript-estree/tests/lib/validateDefaultProjectForFilesGlob.test.ts new file mode 100644 index 000000000000..6510182fefd9 --- /dev/null +++ b/packages/typescript-estree/tests/lib/validateDefaultProjectForFilesGlob.test.ts @@ -0,0 +1,35 @@ +import { validateDefaultProjectForFilesGlob } from '../../src/create-program/validateDefaultProjectForFilesGlob'; + +describe('validateDefaultProjectForFilesGlob', () => { + it('does not throw when options.allowDefaultProjectForFiles is an empty array', () => { + expect(() => + validateDefaultProjectForFilesGlob({ allowDefaultProjectForFiles: [] }), + ).not.toThrow(); + }); + + it('does not throw when options.allowDefaultProjectForFiles contains a non-** glob', () => { + expect(() => + validateDefaultProjectForFilesGlob({ + allowDefaultProjectForFiles: ['./*.js'], + }), + ).not.toThrow(); + }); + + it('throws when options.allowDefaultProjectForFiles contains a * glob', () => { + expect(() => + validateDefaultProjectForFilesGlob({ + allowDefaultProjectForFiles: ['*'], + }), + ).toThrow(/allowDefaultProjectForFiles contains the overly wide '\*'\./); + }); + + it('throws when options.allowDefaultProjectForFiles contains a ** glob', () => { + expect(() => + validateDefaultProjectForFilesGlob({ + allowDefaultProjectForFiles: ['**/*.js'], + }), + ).toThrow( + /allowDefaultProjectForFiles glob '\*\*\/\*\.js' contains a disallowed '\*\*'\./, + ); + }); +}); diff --git a/packages/website/src/theme/MDXComponents/HiddenHeading.module.css b/packages/website/src/theme/MDXComponents/HiddenHeading.module.css new file mode 100644 index 000000000000..79c1e7a6e7d3 --- /dev/null +++ b/packages/website/src/theme/MDXComponents/HiddenHeading.module.css @@ -0,0 +1,6 @@ +.hiddenHeading { + display: block; + position: relative; + top: calc(-1 * var(--ifm-navbar-height)); + visibility: hidden; +} diff --git a/packages/website/src/theme/MDXComponents/HiddenHeading.tsx b/packages/website/src/theme/MDXComponents/HiddenHeading.tsx new file mode 100644 index 000000000000..24ff9052f01d --- /dev/null +++ b/packages/website/src/theme/MDXComponents/HiddenHeading.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +import styles from './HiddenHeading.module.css'; + +export interface HiddenHeadingProps { + id: string; +} + +export function HiddenHeading({ id }: HiddenHeadingProps): React.JSX.Element { + return ; +} diff --git a/packages/website/src/theme/MDXComponents/index.tsx b/packages/website/src/theme/MDXComponents/index.tsx index f84c301edc35..787837995963 100644 --- a/packages/website/src/theme/MDXComponents/index.tsx +++ b/packages/website/src/theme/MDXComponents/index.tsx @@ -2,13 +2,15 @@ import Admonition from '@theme/Admonition'; import MDXComponents from '@theme-original/MDXComponents'; import { BaseRuleReference } from './BaseRuleReference'; +import { HiddenHeading } from './HiddenHeading'; import { RuleAttributes } from './RuleAttributes'; import { TryInPlayground } from './TryInPlayground'; export default { ...MDXComponents, + Admonition, BaseRuleReference, + HiddenHeading, RuleAttributes, TryInPlayground, - Admonition, }; From 4858afde147a5ff6fa20ac1e73bc1c04692cef7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Thu, 25 Apr 2024 20:55:31 -0400 Subject: [PATCH 07/15] chore: fix ci.yml canary releases to use nx, not lerna (#8962) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore: fix ci.yml canary releases to use nx, not lerna * chore: allow overriding major version for canaries * fix lint * nit: comment accuracy * Update Releases.mdx for latest command --------- Co-authored-by: “JamesHenry” --- .github/workflows/ci.yml | 4 +- docs/maintenance/Releases.mdx | 8 +- .../repo-tools/src/apply-canary-version.mts | 81 ++++++++++++------- 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05d3bc1f30e4..e4334d05a9c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -325,11 +325,11 @@ jobs: uses: ./.github/actions/prepare-build - name: Figure out and apply the next canary version - run: npx nx run repo-tools:apply-canary-version + run: OVERRIDE_MAJOR_VERSION=8 npx nx run repo-tools:apply-canary-version - name: Publish all packages to npm with the canary tag # NOTE: this needs to be npx, rather than yarn, to make sure the authenticated npm registry is used - run: npx lerna publish premajor --loglevel=verbose --canary --exact --force-publish --yes --dist-tag rc-v8 + run: npx nx release publish --tag rc-v8 --verbose env: NX_CLOUD_DISTRIBUTED_EXECUTION: false NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/docs/maintenance/Releases.mdx b/docs/maintenance/Releases.mdx index b26f933ad049..c33b2e841444 100644 --- a/docs/maintenance/Releases.mdx +++ b/docs/maintenance/Releases.mdx @@ -3,8 +3,6 @@ id: releases title: Releases --- - - [Users > Releases](../users/Releases.mdx) describes how our automatic releases are done. There is generally no maintenance activity we need to take for the weekly releases. @@ -26,7 +24,7 @@ Per [Users > Releases > Major Releases](../users/Releases.mdx#major-releases), w - Under `push:` > `branches:` at the beginning of the file, add an `- v${major}` list item. - Add a `publish_canary_version_v${major}` step the same as `publish_canary_version` except: - Change the `if` condition's branch check to: `if: github.ref == 'refs/heads/v${major}'`. - - Its publish command should be `npx lerna publish premajor --loglevel=verbose --canary --exact --force-publish --yes --dist-tag rc-v${major}`. + - Its publish command should be `npx nx release publish --tag rc-v${major} --verbose`. - Merge this into `main` once reviewed and rebase the `v${major}` branch. ### 2. Merging Breaking Changes @@ -34,7 +32,7 @@ Per [Users > Releases > Major Releases](../users/Releases.mdx#major-releases), w 1. Send a PR from `v${major}` to `main` [example: [v6.0.0](https://github.com/typescript-eslint/typescript-eslint/pull/5886)]. 1. Change all [breaking change PRs](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+is%3Aopen+label%3A%22breaking+change%22) to target the `v${major}` branch. - To signify these changes as breaking, the first line of the PR description must read as `BREAKING CHANGE:`, and second line should briefly summarize the changes. - - It is important to note that when merged the commit message must also include `BREAKING CHANGE:` as the first line in order for lerna to recognize it as a breaking change in the release notes. If you miss this it just means more manual work when writing the release documentation. + - It is important to note that when merged the commit message must also include `BREAKING CHANGE:` as the first line in order for nx to recognize it as a breaking change in the release notes. If you miss this it just means more manual work when writing the release documentation. 1. Wait until all required PRs have been merged 1. Let the release wait for **at least 1 week** to allow time for early adopters to help test it and discuss the changes. - Promote it on the [`@tseslint`](https://twitter.com/tseslint) twitter to get some additional attention. @@ -48,7 +46,7 @@ They don't need any special treatment. ### 3. Releasing the Version 1. Discuss with the maintainers to be ready for an [out-of-band](#out-of-band-releases) release. Doing this manually helps ensure someone is on-hand to action any issues that might arise from the major release. -1. Prepare the release notes. Lerna will automatically generate the release notes on GitHub, however this will be disorganized and unhelpful for users. We need to reorganize the release notes so that breaking changes are placed at the top to make them most visible. If any migrations are required, we must list the steps to make it easy for users. +1. Prepare the release notes. nx will automatically generate the release notes on GitHub, however this will be disorganized and unhelpful for users. We need to reorganize the release notes so that breaking changes are placed at the top to make them most visible. If any migrations are required, we must list the steps to make it easy for users. - Example release notes: [`v5.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v5.0.0), [`v4.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v4.0.0), [`v3.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v3.0.0) 1. Finally, tweet the release on the `@tseslint` twitter with a link to the GitHub release. Make sure you include additional information about the highlights of the release! diff --git a/packages/repo-tools/src/apply-canary-version.mts b/packages/repo-tools/src/apply-canary-version.mts index 1be37286cfe5..2696f1ccb061 100644 --- a/packages/repo-tools/src/apply-canary-version.mts +++ b/packages/repo-tools/src/apply-canary-version.mts @@ -2,8 +2,18 @@ import { workspaceRoot } from '@nx/devkit'; import { execaSync } from 'execa'; import semver from 'semver'; +// We are either releasing a canary version of the latest major version, or one for the next major. +const overrideMajorVersion = process.env.OVERRIDE_MAJOR_VERSION; + const preid = 'alpha'; -const distTag = 'canary'; + +let distTag = 'canary'; +if (overrideMajorVersion) { + console.log( + `Overriding canary major version base to v${overrideMajorVersion}`, + ); + distTag = `rc-v${overrideMajorVersion}`; +} const currentLatestVersion = execaSync('npm', [ 'view', @@ -11,11 +21,16 @@ const currentLatestVersion = execaSync('npm', [ 'version', ]).stdout.trim(); -const currentCanaryVersion = execaSync('npm', [ - 'view', - `@typescript-eslint/eslint-plugin@${distTag}`, - 'version', -]).stdout.trim(); +let currentCanaryVersion = null; +try { + currentCanaryVersion = execaSync('npm', [ + 'view', + `@typescript-eslint/eslint-plugin@${distTag}`, + 'version', + ]).stdout.trim(); +} catch { + // (ignored - currentCanaryVersion can be null) +} console.log('\nResolved current versions: ', { currentLatestVersion, @@ -24,28 +39,40 @@ console.log('\nResolved current versions: ', { let nextCanaryVersion: string | null; -if (semver.gte(currentLatestVersion, currentCanaryVersion)) { - console.log( - '\nLatest version is greater than or equal to the current canary version, starting new prerelease base...', - ); - // Determine next minor version above the currentLatestVersion - nextCanaryVersion = semver.inc( - currentLatestVersion, - 'prerelease', - undefined, - preid, - ); +if (overrideMajorVersion) { + nextCanaryVersion = currentCanaryVersion + ? semver.inc(currentCanaryVersion, 'prerelease', undefined, preid) + : semver.inc(currentLatestVersion, 'premajor', undefined, preid); } else { - console.log( - '\nLatest version is less than the current canary version, incrementing the existing prerelease base...', - ); - // Determine next prerelease version above the currentCanaryVersion - nextCanaryVersion = semver.inc( - currentCanaryVersion, - 'prerelease', - undefined, - preid, - ); + if (!currentCanaryVersion) { + throw new Error( + 'An unexpected error occurred, no current canary version could be read from the npm registry', + ); + } + + if (semver.gte(currentLatestVersion, currentCanaryVersion)) { + console.log( + '\nLatest version is greater than or equal to the current canary version, starting new prerelease base...', + ); + // Determine next minor version above the currentLatestVersion + nextCanaryVersion = semver.inc( + currentLatestVersion, + 'prerelease', + undefined, + preid, + ); + } else { + console.log( + '\nLatest version is less than the current canary version, incrementing the existing prerelease base...', + ); + // Determine next prerelease version above the currentCanaryVersion + nextCanaryVersion = semver.inc( + currentCanaryVersion, + 'prerelease', + undefined, + preid, + ); + } } if (!nextCanaryVersion) { From 2995be8752177c73d523ecef84896ebf60c198d6 Mon Sep 17 00:00:00 2001 From: Kirk Waiblinger <53019676+kirkwaiblinger@users.noreply.github.com> Date: Fri, 26 Apr 2024 05:19:36 -0600 Subject: [PATCH 08/15] docs: add eslint v9 tracking issue to main README (#8998) add eslint v9 tracking issue to main README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c9474769f51d..9e78bb7008ff 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,9 @@

👆

+

+ Using ESLint v9? See: ESLint v9 Support. +

## Code Contributors From 51d21931e31b642585414c3273870f5e628d89cb Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Fri, 26 Apr 2024 20:24:05 +0900 Subject: [PATCH 09/15] fix(eslint-plugin): [consistent-type-assertions] handle tagged templates (#8993) --- .../src/rules/consistent-type-assertions.ts | 5 +- .../rules/consistent-type-assertions.test.ts | 46 ++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts index e3d88fb69c7c..4a8ac4d4d794 100644 --- a/packages/eslint-plugin/src/rules/consistent-type-assertions.ts +++ b/packages/eslint-plugin/src/rules/consistent-type-assertions.ts @@ -223,7 +223,10 @@ export default createRule({ node.parent.type === AST_NODE_TYPES.CallExpression || node.parent.type === AST_NODE_TYPES.ThrowStatement || node.parent.type === AST_NODE_TYPES.AssignmentPattern || - node.parent.type === AST_NODE_TYPES.JSXExpressionContainer) + node.parent.type === AST_NODE_TYPES.JSXExpressionContainer || + (node.parent.type === AST_NODE_TYPES.TemplateLiteral && + node.parent.parent.type === + AST_NODE_TYPES.TaggedTemplateExpression)) ) { return; } diff --git a/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts b/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts index 3a6b28650c06..6d3b64bbfde3 100644 --- a/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts +++ b/packages/eslint-plugin/tests/rules/consistent-type-assertions.test.ts @@ -26,7 +26,8 @@ const x = new (Generic)(); const x = new (Generic)('string'); const x = () => { bar: 5 }; const x = () => ({ bar: 5 }); -const x = () => bar;`; +const x = () => bar; +const x = bar\`\${"baz"}\`;`; const ANGLE_BRACKET_TESTS = `${ANGLE_BRACKET_TESTS_EXCEPT_CONST_CASE} const x = { key: 'value' }; @@ -45,7 +46,8 @@ const x = new (Generic as Foo)(); const x = new (Generic as Foo)('string'); const x = () => ({ bar: 5 } as Foo); const x = () => ({ bar: 5 } as Foo); -const x = () => (bar as Foo);`; +const x = () => (bar as Foo); +const x = bar\`\${"baz"}\` as Foo;`; const AS_TESTS = `${AS_TESTS_EXCEPT_CONST_CASE} const x = { key: 'value' } as const; @@ -69,6 +71,7 @@ function b(x = {} as Foo.Bar) {} function c(x = {} as Foo) {} print?.({ bar: 5 } as Foo) print?.call({ bar: 5 } as Foo) +print\`\${{ bar: 5 } as Foo}\` `; const OBJECT_LITERAL_ARGUMENT_ANGLE_BRACKET_CASTS = ` print({ bar: 5 }) @@ -76,6 +79,7 @@ new print({ bar: 5 }) function foo() { throw { bar: 5 } } print?.({ bar: 5 }) print?.call({ bar: 5 }) +print\`\${{ bar: 5 }}\` `; ruleTester.run('consistent-type-assertions', rule, { @@ -230,6 +234,10 @@ ruleTester.run('consistent-type-assertions', rule, { messageId: 'angle-bracket', line: 15, }, + { + messageId: 'angle-bracket', + line: 16, + }, ], }), ...batchedSingleLineTests({ @@ -296,6 +304,10 @@ ruleTester.run('consistent-type-assertions', rule, { messageId: 'as', line: 15, }, + { + messageId: 'as', + line: 16, + }, ], output: AS_TESTS, }), @@ -359,6 +371,10 @@ ruleTester.run('consistent-type-assertions', rule, { messageId: 'never', line: 14, }, + { + messageId: 'never', + line: 15, + }, ], }), ...batchedSingleLineTests({ @@ -421,6 +437,10 @@ ruleTester.run('consistent-type-assertions', rule, { messageId: 'never', line: 14, }, + { + messageId: 'never', + line: 15, + }, ], }), ...batchedSingleLineTests({ @@ -660,6 +680,17 @@ ruleTester.run('consistent-type-assertions', rule, { }, ], }, + { + messageId: 'unexpectedObjectTypeAssertion', + line: 12, + suggestions: [ + { + messageId: 'replaceObjectTypeAssertionWithSatisfies', + data: { cast: 'Foo' }, + output: `print\`\${{ bar: 5 } satisfies Foo}\``, + }, + ], + }, ], }), ...batchedSingleLineTests({ @@ -769,6 +800,17 @@ ruleTester.run('consistent-type-assertions', rule, { }, ], }, + { + messageId: 'unexpectedObjectTypeAssertion', + line: 10, + suggestions: [ + { + messageId: 'replaceObjectTypeAssertionWithSatisfies', + data: { cast: 'Foo' }, + output: `print\`\${{ bar: 5 } satisfies Foo}\``, + }, + ], + }, ], }), { From 323daaea861fe27f7ac2464579c1f95e61c6572b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Fri, 26 Apr 2024 07:59:04 -0400 Subject: [PATCH 10/15] docs: mention strict and stylistic configs in Getting Started (#8916) * docs: mention strict and stylistic configs in Getting Started * small touchups * Update docs/packages/Parser.mdx Co-authored-by: Kirk Waiblinger <53019676+kirkwaiblinger@users.noreply.github.com> --------- Co-authored-by: Kirk Waiblinger <53019676+kirkwaiblinger@users.noreply.github.com> --- docs/getting-started/Legacy_ESLint_Setup.mdx | 34 ++++++++- docs/getting-started/Quickstart.mdx | 43 ++++++++--- docs/getting-started/Typed_Linting.mdx | 80 ++++++++++++++++---- docs/packages/Parser.mdx | 80 +++++++++++--------- docs/users/Shared_Configurations.mdx | 6 ++ 5 files changed, 177 insertions(+), 66 deletions(-) diff --git a/docs/getting-started/Legacy_ESLint_Setup.mdx b/docs/getting-started/Legacy_ESLint_Setup.mdx index c6dd1dbd70da..6fb80e014e68 100644 --- a/docs/getting-started/Legacy_ESLint_Setup.mdx +++ b/docs/getting-started/Legacy_ESLint_Setup.mdx @@ -84,10 +84,40 @@ ESLint will lint all TypeScript compatible files within the current folder, and ## Next Steps -We provide a plethora of powerful rules that utilize the power of TypeScript's type information. [Visit _Typed Rules_ for a setup guide](./Typed_Linting.mdx). - If you're having problems getting this working, please have a look at our [Troubleshooting & FAQs](../troubleshooting/FAQ.mdx). +### Additional Configs + +We recommend you consider enabling the following two configs: + +- [`strict`](../users/Shared_Configurations.mdx#strict): a superset of `recommended` that includes more opinionated rules which may also catch bugs. +- [`stylistic`](../users/Shared_Configurations.mdx#stylistic): additional rules that enforce consistent styling without significantly catching bugs or changing logic. + +```js title=".eslintrc.cjs" +/* eslint-env node */ +module.exports = { + extends: [ + 'eslint:recommended', + // Remove this line + 'plugin:@typescript-eslint/recommended', + // Added lines start + 'plugin:@typescript-eslint/strict', + 'plugin:@typescript-eslint/stylistic', + // Added lines end + ], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + root: true, +}; +``` + +You can read more about these in our [shared configurations docs](../users/Shared_Configurations.mdx). + +### Typed Linting + +We also provide a plethora of powerful rules that utilize the power of TypeScript's type information. +[Visit the next page for a typed rules setup guide](./Typed_Linting.mdx). + ### Documentation Resources - You can read more about configuring ESLint [in their documentation on configuration](https://eslint.org/docs/user-guide/configuring). diff --git a/docs/getting-started/Quickstart.mdx b/docs/getting-started/Quickstart.mdx index a5dbbac968a9..abb9bcb9ef6b 100644 --- a/docs/getting-started/Quickstart.mdx +++ b/docs/getting-started/Quickstart.mdx @@ -8,18 +8,17 @@ pagination_next: getting-started/typed-linting import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; +## Quickstart + +This page is a quick-start for [ESLint's new "flat" config format](https://eslint.org/docs/latest/use/configure/configuration-files-new) to go from zero to linting with our recommended rules on your TypeScript code as quickly as possible. + :::note -This page is a quick-start guide for [ESLint's new "flat" config format](https://eslint.org/docs/latest/use/configure/configuration-files-new) to help you go from zero to linting as quick as possible. - For the same guide but for [ESLint's legacy format](https://eslint.org/docs/latest/use/configure/configuration-files) — see [Legacy ESLint Setup](./Legacy_ESLint_Setup.mdx). - For quickstart information on linting with type information — see [Typed Linting](./Typed_Linting.mdx). ::: -## Quickstart - -These steps will get you running ESLint with our recommended rules on your TypeScript code as quickly as possible. - ### Step 1: Installation First, install the required packages for [ESLint](https://eslint.org), [TypeScript](https://typescriptlang.org), and [our tooling](../packages/TypeScript_ESLint.mdx): @@ -82,18 +81,38 @@ ESLint will lint all TypeScript compatible files within the current folder, and - `'@eslint/js'` / `eslint.configs.recommended` turns on [eslint's recommended config](https://www.npmjs.com/package/@eslint/js). - `...tseslint.configs.recommended` turns on [our recommended config](../users/Shared_Configurations.mdx#recommended). -See [ESLint's Configuration Files docs](https://eslint.org/docs/user-guide/configuring/configuration-files-new) for more details on configuring ESLint. - ## Next Steps -We provide a plethora of powerful rules that utilize the power of TypeScript's type information. +If you're having problems getting this working, please have a look at our [Troubleshooting & FAQs](../troubleshooting/FAQ.mdx). -[Visit the next page for a setup guide](./Typed_Linting.mdx 'Visit the next page for a typed rules setup guide'). +### Additional Configs -If you're having problems getting this working, please have a look at our [Troubleshooting & FAQs](../troubleshooting/FAQ.mdx). +We recommend you consider enabling the following two configs: + +- [`strict`](../users/Shared_Configurations.mdx#strict): a superset of `recommended` that includes more opinionated rules which may also catch bugs. +- [`stylistic`](../users/Shared_Configurations.mdx#stylistic): additional rules that enforce consistent styling without significantly catching bugs or changing logic. + +```js title="eslint.config.js" +export default tseslint.config( + eslint.configs.recommended, + // Remove this line + ...tseslint.configs.recommended, + // Add this line + ...tseslint.configs.strict, + // Add this line + ...tseslint.configs.stylistic, +); +``` + +You can read more about these in our [shared configurations docs](../users/Shared_Configurations.mdx). + +### Typed Linting + +We also provide a plethora of powerful rules that utilize the power of TypeScript's type information. +[Visit the next page for a typed rules setup guide](./Typed_Linting.mdx). -### Documentation Resources +## Documentation Resources - You can read more about configuring ESLint [in their documentation on configuration](https://eslint.org/docs/user-guide/configuring). - You can read more about the rules provided by ESLint [in their documentation on their rules](https://eslint.org/docs/rules/). -- You can read more about the rules provided by typescript-eslint in [our rules documentation](/rules). +- You can read more about the rules provided by typescript-eslint in our [rules documentation](/rules). diff --git a/docs/getting-started/Typed_Linting.mdx b/docs/getting-started/Typed_Linting.mdx index 4de4516968c3..9f1c89323366 100644 --- a/docs/getting-started/Typed_Linting.mdx +++ b/docs/getting-started/Typed_Linting.mdx @@ -13,6 +13,9 @@ To tap into TypeScript's additional powers, there are two small changes you need +1. Add `TypeChecked` to the name of any preset configs you're using, namely `recommended`, `strict`, and `stylistic`. +2. Add `languageOptions.parserOptions` to tell our parser how to find the TSConfig for each source file. + ```js title="eslint.config.js" export default tseslint.config( eslint.configs.recommended, @@ -39,13 +42,16 @@ For CommonJS modules and/or older versions of Node.js, [use `__dirname` or an al In more detail: -- `tseslint.configs.recommendedTypeChecked` is another [recommended configuration](../users/Shared_Configurations.mdx) we provide. This one contains recommended rules that additionally require type information. -- `parserOption.project` tells our parser how to find the TSConfig for each source file (`true` indicates to find the closest `tsconfig.json` for each source file) - - If your project is a multi-package monorepo, see [our docs on configuring a monorepo](./typed-linting/Monorepos.mdx). +- `tseslint.configs.recommendedTypeChecked` is another [shared configuration](../users/Shared_Configurations.mdx) we provide. This one contains recommended rules that additionally require type information. +- `parserOptions.project: true` indicates to find the closest `tsconfig.json` for each source file (see [Parser#project](../packages/Parser.mdx#project)). +- `parserOptions.tsconfigRootDir` tells our parser the absolute path of your project's root directory (see [Parser#tsconfigRootDir](../packages/Parser.mdx#tsconfigrootdir)). +1. Add `-type-checked` to the name of any preset configs you're using, namely `recommended`, `strict`, and `stylistic`. +2. Add `parserOptions` to tell our parser how to find the TSConfig for each source file. + ```js title=".eslintrc.cjs" /* eslint-env node */ module.exports = { @@ -70,9 +76,8 @@ module.exports = { In more detail: -- `plugin:@typescript-eslint/recommended-type-checked` is another [recommended configuration](../users/Shared_Configurations.mdx) we provide. This one contains recommended rules that additionally require type information. -- `parserOptions.project` tells our parser how to find the TSConfig for each source file (`true` indicates to find the closest `tsconfig.json` for each source file) - - If your project is a multi-package monorepo, see [our docs on configuring a monorepo](./typed-linting/Monorepos.mdx). +- `plugin:@typescript-eslint/recommended-type-checked` is another [shared configuration](../users/Shared_Configurations.mdx) we provide. This one contains recommended rules that additionally require type information. +- `parserOptions.project: true` indicates to find the closest `tsconfig.json` for each source file (see [Parser#project](../packages/Parser.mdx#project)). - `parserOptions.tsconfigRootDir` tells our parser the absolute path of your project's root directory (see [Parser#tsconfigRootDir](../packages/Parser.mdx#tsconfigrootdir)). @@ -86,7 +91,57 @@ See [our TSConfig inclusion FAQ](../troubleshooting/FAQ.mdx#i-get-errors-telling With that done, run the same lint command you ran before. You may see new rules reporting errors based on type information! -## Specifying TSConfigs +## Shared Configurations + +If you enabled the [`strict` shared config](../users/Shared_Configurations.mdx#strict) and/or [`stylistic` shared config](../users/Shared_Configurations.mdx#stylistic) in a previous step, be sure to replace them with [`strictTypeChecked`](../users/Shared_Configurations.mdx#strict-type-checked) and [`stylisticTypeChecked`](../users/Shared_Configurations.mdx#stylistic-type-checked) respectively to add their type-checked rules. + + + + +```js title="eslint.config.js" +export default tseslint.config( + eslint.configs.recommended, + // Removed lines start + ...tseslint.configs.strict, + ...tseslint.configs.stylistic, + // Removed lines end + // Added lines start + ...tseslint.configs.strictTypeChecked, + ...tseslint.configs.stylisticTypeChecked, + // Added lines end + // ... +); +``` + + + + +```js title=".eslintrc.cjs" +/* eslint-env node */ +module.exports = { + extends: [ + 'eslint:recommended', + // Removed lines start + 'plugin:@typescript-eslint/strict', + 'plugin:@typescript-eslint/stylistic', + // Removed lines end + // Added lines start + 'plugin:@typescript-eslint/strict-type-checked', + 'plugin:@typescript-eslint/stylistic-type-checked', + // Added lines end + ], + // ... +}; +``` + + + + +You can read more about the rules provided by typescript-eslint in our [rules docs](/rules) and [shared configurations docs](../users/Shared_Configurations.mdx). + +## FAQs + +### Can I customize the TSConfig used for typed linting? The `project` option can be turned on with either: @@ -134,8 +189,6 @@ See [the `@typescript-eslint/parser` docs for more details](../packages/Parser.m If your project is a multi-package monorepo, see [our docs on configuring a monorepo](./typed-linting/Monorepos.mdx). ::: -## FAQs - ### How can I disable type-aware linting for a subset of files? You can combine ESLint's [overrides](https://eslint.org/docs/latest/use/configure/configuration-files#configuration-based-on-glob-patterns) config in conjunction with our [`disable-type-checked`](../users/Shared_Configurations.mdx#disable-type-checked) config to turn off type-aware linting on specific subsets of files. @@ -147,6 +200,7 @@ You can combine ESLint's [overrides](https://eslint.org/docs/latest/use/configur export default tseslint.config( eslint.configs.recommended, ...tseslint.configs.recommendedTypeChecked, + ...tseslint.configs.stylisticTypeChecked, { languageOptions: { parserOptions: { @@ -156,7 +210,7 @@ export default tseslint.config( }, // Added lines start { - files: ['*.js'], + files: ['**/*.js'], ...tseslint.configs.disableTypeChecked, }, // Added lines end @@ -171,6 +225,7 @@ module.exports = { extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended-type-checked', + 'plugin:@typescript-eslint/stylistic-type-checked', ], plugins: ['@typescript-eslint'], parser: '@typescript-eslint/parser', @@ -209,11 +264,6 @@ This means that generally they usually only run a complete lint before a push, o **We strongly recommend you do use type-aware linting**, but the above information is included so that you can make your own, informed decision. -### I get errors telling me "The file must be included in at least one of the projects provided" - -You're using an outdated version of `@typescript-eslint/parser`. -Update to the latest version to see a more informative version of this error message, explained in our [Troubleshooting and FAQs page](../troubleshooting/FAQ.mdx#i-get-errors-telling-me-eslint-was-configured-to-run--however-that-tsconfig-does-not--none-of-those-tsconfigs-include-this-file). - ## Troubleshooting If you're having problems getting this working, please have a look at our [Troubleshooting and FAQs page](../troubleshooting/FAQ.mdx). diff --git a/docs/packages/Parser.mdx b/docs/packages/Parser.mdx index 3ea0d996cfc6..26b5fb80d200 100644 --- a/docs/packages/Parser.mdx +++ b/docs/packages/Parser.mdx @@ -169,7 +169,7 @@ The identifier that's used for JSX fragment elements (after transpilation). If `null`, assumes transpilation will always use a member of the configured `jsxPragma`. This should not be a member expression - just the root identifier (i.e. use `"h"` instead of `"h.Fragment"`). -If you provide `parserOptions.project`, you do not need to set this, as it will automatically detected from the compiler. +If you provide `parserOptions.project`, you do not need to set this, as it will be automatically detected from the compiler. ### `jsxPragma` @@ -180,7 +180,7 @@ If you're using a library other than React (like `preact`), then you should chan This should not be a member expression - just the root identifier (i.e. use `"React"` instead of `"React.createElement"`). -If you provide `parserOptions.project`, you do not need to set this, as it will automatically detected from the compiler. +If you provide `parserOptions.project`, you do not need to set this, as it will be automatically detected from the compiler. ### `lib` @@ -190,7 +190,7 @@ For valid options, see the [TypeScript compiler options](https://www.typescriptl Specifies the TypeScript `lib`s that are available. This is used by the scope analyser to ensure there are global variables declared for the types exposed by TypeScript. -If you provide `parserOptions.project`, you do not need to set this, as it will automatically detected from the compiler. +If you provide `parserOptions.project`, you do not need to set this, as it will be automatically detected from the compiler. ### `programs` @@ -206,27 +206,27 @@ All linted files must be part of the provided program(s). > Default `undefined`. -This option allows you to provide a path to your project's `tsconfig.json`. **This setting is required if you want to use rules which require type information**. Relative paths are interpreted relative to the current working directory if `tsconfigRootDir` is not set. If you intend on running ESLint from directories other than the project root, you should consider using `tsconfigRootDir`. +A path to your project's TSConfig. **This setting is required to use [rules which require type information](../getting-started/Typed_Linting.mdx)**. -- Accepted values: +Accepted value types: - ```js - // find the tsconfig.json nearest each source file - project: true, +```js +// find the tsconfig.json nearest to each source file +project: true, - // path - project: './tsconfig.json'; +// path +project: './tsconfig.json'; - // glob pattern - project: './packages/**/tsconfig.json'; +// glob pattern +project: './packages/**/tsconfig.json'; - // array of paths and/or glob patterns - project: ['./packages/**/tsconfig.json', './separate-package/tsconfig.json']; +// array of paths and/or glob patterns +project: ['./packages/**/tsconfig.json', './separate-package/tsconfig.json']; - // ways to disable type-aware linting (useful for overrides configs) - project: false; - project: null; - ``` +// ways to disable type-aware linting (useful for overrides configs) +project: false; +project: null; +``` - If `true`, each source file's parse will find the nearest `tsconfig.json` file to that source file. @@ -236,25 +236,31 @@ This option allows you to provide a path to your project's `tsconfig.json`. **Th - Note that using wide globs `**` in your `parserOptions.project` may cause performance implications. Instead of globs that use `**` to recursively check all folders, prefer paths that use a single `*` at a time. For more info see [#2611](https://github.com/typescript-eslint/typescript-eslint/issues/2611). -- TypeScript will ignore files with duplicate filenames in the same folder (for example, `src/file.ts` and `src/file.js`). TypeScript purposely ignore all but one of the files, only keeping the one file with the highest priority extension (the extension priority order (from highest to lowest) is `.ts`, `.tsx`, `.d.ts`, `.js`, `.jsx`). For more info see #955. - -- Note that if this setting is specified, you must only lint files that are included in the projects as defined by the provided `tsconfig.json` files. If your existing configuration does not include all of the files you would like to lint, you can create a separate `tsconfig.eslint.json` as follows: - - ```jsonc - { - // extend your base config so you don't have to redefine your compilerOptions - "extends": "./tsconfig.json", - "include": [ - "src/**/*.ts", - "test/**/*.ts", - "typings/**/*.ts", - // etc - - // if you have a mixed JS/TS codebase, don't forget to include your JS files - "src/**/*.js", - ], - } - ``` +- TypeScript will ignore files with duplicate filenames in the same folder (for example, `src/file.ts` and `src/file.js`). TypeScript purposely ignores all but one of the files, only keeping the one file with the highest priority extension (the extension priority order (from highest to lowest) is `.ts`, `.tsx`, `.d.ts`, `.js`, `.jsx`). For more info see [#955](https://github.com/typescript-eslint/typescript-eslint/issues/955). + +:::note +Relative paths are interpreted relative to the current working directory if [`tsconfigRootDir`](#tsconfigrootdir) is not set. +::: + +If this setting is specified, you must only lint files that are included in the projects as defined by the provided TSConfig file(s). If your existing configuration does not include all of the files you would like to lint, you can create a separate `tsconfig.eslint.json` as follows: + +```jsonc +{ + // extend your base config so you don't have to redefine your compilerOptions + "extends": "./tsconfig.json", + "include": [ + "src/**/*.ts", + "test/**/*.ts", + "typings/**/*.ts", + // etc + + // if you have a mixed JS/TS codebase, don't forget to include your JS files + "src/**/*.js", + ], +} +``` + +For an option that allows linting files outside of your TSConfig file(s), see [`EXPERIMENTAL_useProjectService`](#experimental_useprojectservice). ### `projectFolderIgnoreList` diff --git a/docs/users/Shared_Configurations.mdx b/docs/users/Shared_Configurations.mdx index 0069359ee1b9..feeefda3f80b 100644 --- a/docs/users/Shared_Configurations.mdx +++ b/docs/users/Shared_Configurations.mdx @@ -240,6 +240,9 @@ module.exports = { +Note that `stylistic` does not replace `recommended` or `strict`. +`stylistic` adds additional rules. + See [`configs/stylistic.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/stylistic.ts) for the exact contents of this config. ### `stylistic-type-checked` @@ -266,6 +269,9 @@ module.exports = { +Note that `stylistic-type-checked` does not replace `recommended-type-checked` or `strict-type-checked`. +`stylistic-type-checked` adds additional rules. + See [`configs/stylistic-type-checked.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/stylistic-type-checked.ts) for the exact contents of this config. ## Other Configurations From 9f3f2acadc561bfe0e286da71bbb61c1eec91542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Fri, 26 Apr 2024 10:10:08 -0400 Subject: [PATCH 11/15] docs: update major release instructions based on v6 release (#8913) * docs: update major release instructions based on v6 release * Mention searches too * Mention the Discord * Also mention deprecated code * Also mention dependency versions issue --- docs/maintenance/Releases.mdx | 61 +++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/docs/maintenance/Releases.mdx b/docs/maintenance/Releases.mdx index c33b2e841444..59737a7683b2 100644 --- a/docs/maintenance/Releases.mdx +++ b/docs/maintenance/Releases.mdx @@ -17,26 +17,69 @@ Per [Users > Releases > Major Releases](../users/Releases.mdx#major-releases), w 1. Create a milestone by the name of the release [example: [Milestone 6.0.0](https://github.com/typescript-eslint/typescript-eslint/milestone/8)]. 1. If an issue for changes to recommended rule configs doesn't yet exist, create one [example: [Changes to the `recommended` sets for 5.0.0](https://github.com/typescript-eslint/typescript-eslint/issues/5900)]. 1. Add any breaking changes intended for the release to that milestone. +1. Search for source code comments (excluding `CHANGELOG.md` files) that mention deprecated code and/or a todo for the new major version, and create corresponding issues in that milestone. + - For example, for a new major version 8, searches might include: + - `/deprecated|todo/i` + - `/v8/i` + - `/todo.*v?8/i` +1. Create an issue to raise the minimum versions of dependencies [example: [Enhancement: Raise minimum versions of dependencies for v8](https://github.com/typescript-eslint/typescript-eslint/issues/8929)] 1. Create two new branches off `main` in the project repository (not a personal fork): - `v${major}` - `v${major}-canary-auto-release` -1. Raise a PR from `v${major}-canary-auto-release` to `main` modifying the [`ci.yml` workflow](https://github.com/typescript-eslint/typescript-eslint/blob/main/.github/workflows/ci.yml) [example: [chore: add auto-canary release for v6](https://github.com/typescript-eslint/typescript-eslint/pull/5883)]: - - Under `push:` > `branches:` at the beginning of the file, add an `- v${major}` list item. - - Add a `publish_canary_version_v${major}` step the same as `publish_canary_version` except: - - Change the `if` condition's branch check to: `if: github.ref == 'refs/heads/v${major}'`. - - Its publish command should be `npx nx release publish --tag rc-v${major} --verbose`. +1. Raise a PR from `v${major}-canary-auto-release` to `main` modifying [`ci.yml` workflow](https://github.com/typescript-eslint/typescript-eslint/blob/main/.github/workflows/ci.yml) and README.md [example: [chore: add auto-canary release for v6](https://github.com/typescript-eslint/typescript-eslint/pull/5883)]: + - `ci.yml`: + - Under `push:` > `branches:` at the beginning of the file, add a `- v${major}` list item. + - Add a `publish_canary_version_v${major}` step the same as `publish_canary_version` except: + - Change the `if` condition's branch check to: `if: github.ref == 'refs/heads/v${major}'`. + - Its publish command should be `npx nx release publish --tag rc-v${major} --verbose`. + - `README.md`: + - Add a link to a `v${major}--typescript-eslint.netlify.app` preview deploy environment on Netlify that you create for the branch. - Merge this into `main` once reviewed and rebase the `v${major}` branch. +#### 1a. Shared Config Changes + +Major versions are our only real chance to change the values in our stable `recommended*` and `stylistic*` configs. +In parallel to the general PR flow of the major version: + +1. Create a `v${major}` channel on the typescript-eslint Discord +1. Create a discussion with a table summarizing any proposed rule changes [example: [Changes to configurations for 6.0.0](https://github.com/typescript-eslint/typescript-eslint/discussions/6014)] +1. Post that discussion on the typescript-eslint Discord and on social media +1. Once the greater of (1 month) and (discussion settling down) has passed, file an issue and send a corresponding PR to the `v${major}` branch making the corresponding changes [example: [Configs: Apply changes to config presets for v6](https://github.com/typescript-eslint/typescript-eslint/issues/6759)] + +#### 1b. Voluntary Community Testing + +In parallel to the shared config changes work, make sure to test out the beta version on popular community projects willing to try it out. + +1. Create a pinned issue offering to try out the new version's beta for consumers [example: [Try out v6 beta on various important community repos](https://github.com/typescript-eslint/typescript-eslint/issues/6760)] + - Ask each community project if they'd be interested in trying out the new version, such as in their Discord or on their issue tracker. + - Each community project that's indicated willingness to receive a PR should have one. +1. Once the proposed _Shared Config Changes_ are merged into the `v${major}` branch, send a draft PR to each project with the new beta version. + +#### 1c. Post Community Testing Config Touchups + +There may be additional changes to preset configs discovered as part of the community testing. +If that's the case: + +1. Create a discussion describing the suggested changes [example: [Configs: Last round of "final" changes to configs for v6](https://github.com/typescript-eslint/typescript-eslint/discussions/7130)]. +1. Post this new discussion in the previous config changes one, in the typescript-eslint Discord, and on social media. +1. Once the greater of (2 weeks) and (discussion settling down) has passed + +If possible, we prefer to avoid making a second round of config changes. +These should only be done for feedback that consistently comes up in community testing. + ### 2. Merging Breaking Changes 1. Send a PR from `v${major}` to `main` [example: [v6.0.0](https://github.com/typescript-eslint/typescript-eslint/pull/5886)]. 1. Change all [breaking change PRs](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+is%3Aopen+label%3A%22breaking+change%22) to target the `v${major}` branch. - To signify these changes as breaking, the first line of the PR description must read as `BREAKING CHANGE:`, and second line should briefly summarize the changes. - - It is important to note that when merged the commit message must also include `BREAKING CHANGE:` as the first line in order for nx to recognize it as a breaking change in the release notes. If you miss this it just means more manual work when writing the release documentation. + - It is important to note that when merged the commit message must also include `BREAKING CHANGE:` as the first line in order for `nx release` to recognize it as a breaking change in the release notes. If you miss this it just means more manual work when writing the release documentation. +1. Write and share out a blog post announcing the new beta [example: [Docs: Blog post describing changes & migration strategy for v5->v6](https://github.com/typescript-eslint/typescript-eslint/issues/6466)]. + - Keep this post up-to-date as changes land in the `v${major}` branch. 1. Wait until all required PRs have been merged +1. Write a blog post announcing the new release [example: [Docs: Release blog post for v6](https://github.com/typescript-eslint/typescript-eslint/issues/7153)], and land it in the `v${major}` branch. 1. Let the release wait for **at least 1 week** to allow time for early adopters to help test it and discuss the changes. - Promote it on the [`@tseslint`](https://twitter.com/tseslint) twitter to get some additional attention. -1. Once discussions have settled, rebase merge the PR on top of `main`. +1. Once discussions have settled, traditional merge commit the PR on top of `main` by temporarily enabling that merge setting for the repo. :::note _Non_-breaking changes can be merged to `main` or the major branch. @@ -46,8 +89,8 @@ They don't need any special treatment. ### 3. Releasing the Version 1. Discuss with the maintainers to be ready for an [out-of-band](#out-of-band-releases) release. Doing this manually helps ensure someone is on-hand to action any issues that might arise from the major release. -1. Prepare the release notes. nx will automatically generate the release notes on GitHub, however this will be disorganized and unhelpful for users. We need to reorganize the release notes so that breaking changes are placed at the top to make them most visible. If any migrations are required, we must list the steps to make it easy for users. - - Example release notes: [`v5.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v5.0.0), [`v4.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v4.0.0), [`v3.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v3.0.0) +1. Prepare the release notes. `nx release` will automatically generate the release notes on GitHub, however this will be disorganized and unhelpful for users. We need to reorganize the release notes so that breaking changes are placed at the top to make them most visible. If any migrations are required, we must list the steps to make it easy for users. + - Example release notes: [`v6.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v6.0.0), [`v5.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v5.0.0) 1. Finally, tweet the release on the `@tseslint` twitter with a link to the GitHub release. Make sure you include additional information about the highlights of the release! ## Out-of-Band Releases From 216d1b060e60e1270be0c12448a1b9385bde67e2 Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Sat, 27 Apr 2024 22:46:21 +0900 Subject: [PATCH 12/15] fix(eslint-plugin): [no-unsafe-return] handle union types (#9001) Co-authored-by: auvred <61150013+auvred@users.noreply.github.com> --- .../src/rules/no-unsafe-return.ts | 2 +- .../tests/rules/no-unsafe-return.test.ts | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/no-unsafe-return.ts b/packages/eslint-plugin/src/rules/no-unsafe-return.ts index fa301bafa652..ef308450bd80 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-return.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-return.ts @@ -104,7 +104,7 @@ export default createRule({ // If there is an explicit type annotation *and* that type matches the actual // function return type, we shouldn't complain (it's intentional, even if unsafe) if (functionTSNode.type) { - for (const signature of functionType.getCallSignatures()) { + for (const signature of tsutils.getCallSignaturesOfType(functionType)) { if ( returnNodeType === signature.getReturnType() || isTypeFlagSet( diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts index 42a798ffe117..36c6103bbc20 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-return.test.ts @@ -45,6 +45,14 @@ function foo() { function foo(): any { return {} as any; } + `, + ` +declare function foo(arg: () => any): void; +foo((): any => 'foo' as any); + `, + ` +declare function foo(arg: null | (() => any)): void; +foo((): any => 'foo' as any); `, // explicit any array return type is allowed, if you want to be unsafe like that ` @@ -408,5 +416,19 @@ function bar() { }, ], }, + { + code: ` +declare function foo(arg: null | (() => any)): void; +foo(() => 'foo' as any); + `, + errors: [ + { + messageId: 'unsafeReturn', + line: 3, + column: 11, + endColumn: 23, + }, + ], + }, ], }); From 812787313626c927c506c58e00aff3857f2c163c Mon Sep 17 00:00:00 2001 From: Kim Sang Du Date: Mon, 29 Apr 2024 00:36:32 +0900 Subject: [PATCH 13/15] fix(eslint-plugin): [no-unused-vars] clear error report range (#8640) * fix: clear error code range * test: add test code that cover end line * refactor: rename variable name and delete not effect property * test: add test case * fix: remove type property * fix: remove type property * fix: remove type property --------- Co-authored-by: Kirk Waiblinger --- .../eslint-plugin/src/rules/no-unused-vars.ts | 19 +++++++++++--- .../no-unused-vars-eslint.test.ts | 8 +----- .../no-unused-vars/no-unused-vars.test.ts | 25 +++++++++++++++++++ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-unused-vars.ts b/packages/eslint-plugin/src/rules/no-unused-vars.ts index d9117605c404..3f6c18f3f0c6 100644 --- a/packages/eslint-plugin/src/rules/no-unused-vars.ts +++ b/packages/eslint-plugin/src/rules/no-unused-vars.ts @@ -419,10 +419,23 @@ export default createRule({ ref.from.variableScope === unusedVar.scope.variableScope, ); + const id = writeReferences.length + ? writeReferences[writeReferences.length - 1].identifier + : unusedVar.identifiers[0]; + + const { start } = id.loc; + const idLength = id.name.length; + + const loc = { + start, + end: { + line: start.line, + column: start.column + idLength, + }, + }; + context.report({ - node: writeReferences.length - ? writeReferences[writeReferences.length - 1].identifier - : unusedVar.identifiers[0], + loc, messageId: 'unusedVar', data: unusedVar.references.some(ref => ref.isWrite()) ? getAssignedMessageData(unusedVar) diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars-eslint.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars-eslint.test.ts index 1ca02bd7add2..d83f23a8024a 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars-eslint.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars-eslint.test.ts @@ -4,7 +4,6 @@ import { RuleTester } from '@typescript-eslint/rule-tester'; import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; -import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import type { MessageIds } from '../../../src/rules/no-unused-vars'; import rule from '../../../src/rules/no-unused-vars'; @@ -40,7 +39,6 @@ ruleTester.defineRule('use-every-a', context => { function definedError( varName: string, additional = '', - type = AST_NODE_TYPES.Identifier, ): TSESLint.TestCaseError { return { messageId: 'unusedVar', @@ -49,7 +47,6 @@ function definedError( action: 'defined', additional, }, - type, }; } @@ -63,7 +60,6 @@ function definedError( function assignedError( varName: string, additional = '', - type = AST_NODE_TYPES.Identifier, ): TSESLint.TestCaseError { return { messageId: 'unusedVar', @@ -72,7 +68,6 @@ function assignedError( action: 'assigned a value', additional, }, - type, }; } @@ -1232,7 +1227,7 @@ function f() { }, { code: '/*global a */', - errors: [definedError('a', '', AST_NODE_TYPES.Program)], + errors: [definedError('a', '')], }, { code: ` @@ -1341,7 +1336,6 @@ function foo() { messageId: 'unusedVar', data: { varName: 'foo', action: 'defined', additional: '' }, line: 2, - type: AST_NODE_TYPES.Identifier, }, ], }, diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts index 04c218b7631e..c810f351c0ae 100644 --- a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts @@ -1140,7 +1140,9 @@ export class Foo {} additional: '', }, line: 2, + endLine: 2, column: 10, + endColumn: 31, }, ], }, @@ -1744,6 +1746,8 @@ declare module 'foo' { messageId: 'unusedVar', line: 3, column: 8, + endLine: 3, + endColumn: 12, data: { varName: 'Test', action: 'defined', @@ -1840,6 +1844,8 @@ x = foo(x); messageId: 'unusedVar', line: 3, column: 1, + endLine: 3, + endColumn: 2, data: { varName: 'x', action: 'assigned a value', @@ -1950,5 +1956,24 @@ export namespace Bar { }, ], }, + { + code: ` +const foo: number = 1; + `, + errors: [ + { + messageId: 'unusedVar', + data: { + varName: 'foo', + action: 'assigned a value', + additional: '', + }, + line: 2, + column: 7, + endLine: 2, + endColumn: 10, + }, + ], + }, ], }); From 277ee388f99218f0701d86a6b6fcd929f0088565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josh=20Goldberg=20=E2=9C=A8?= Date: Sun, 28 Apr 2024 11:59:57 -0400 Subject: [PATCH 14/15] feat(rule-tester): assert suggestion messages are unique (#8995) --- packages/rule-tester/src/RuleTester.ts | 17 ++++ .../tests/eslint-base/eslint-base.test.js | 33 +++++++ .../tests/eslint-base/fixtures/suggestions.js | 92 +++++++++++++++++++ 3 files changed, 142 insertions(+) diff --git a/packages/rule-tester/src/RuleTester.ts b/packages/rule-tester/src/RuleTester.ts index f0ac7ca3dcac..324700fa264a 100644 --- a/packages/rule-tester/src/RuleTester.ts +++ b/packages/rule-tester/src/RuleTester.ts @@ -704,6 +704,23 @@ export class RuleTester extends TestFramework { const result = this.runRuleForItem(ruleName, rule, item); const messages = result.messages; + for (const message of messages) { + if (hasOwnProperty(message, 'suggestions')) { + const seenMessageIndices = new Map(); + + for (let i = 0; i < message.suggestions.length; i += 1) { + const suggestionMessage = message.suggestions[i].desc; + const previous = seenMessageIndices.get(suggestionMessage); + + assert.ok( + !seenMessageIndices.has(suggestionMessage), + `Suggestion message '${suggestionMessage}' reported from suggestion ${i} was previously reported by suggestion ${previous}. Suggestion messages should be unique within an error.`, + ); + seenMessageIndices.set(suggestionMessage, i); + } + } + } + if (typeof item.errors === 'number') { if (item.errors === 0) { assert.fail("Invalid cases must have 'error' value greater than 0"); diff --git a/packages/rule-tester/tests/eslint-base/eslint-base.test.js b/packages/rule-tester/tests/eslint-base/eslint-base.test.js index b1dabac0bb4c..8304dee78f95 100644 --- a/packages/rule-tester/tests/eslint-base/eslint-base.test.js +++ b/packages/rule-tester/tests/eslint-base/eslint-base.test.js @@ -2226,6 +2226,39 @@ describe("RuleTester", () => { }, /Invalid suggestion property name 'outpt'/u); }); + it("should fail if a rule produces two suggestions with the same description", () => { + assert.throws(() => { + ruleTester.run("suggestions-with-duplicate-descriptions", require("../../fixtures/testers/rule-tester/suggestions").withDuplicateDescriptions, { + valid: [], + invalid: [ + { code: "var foo = bar;", errors: 1 } + ] + }); + }, "Suggestion message 'Rename 'foo' to 'bar'' reported from suggestion 1 was previously reported by suggestion 0. Suggestion messages should be unique within an error."); + }); + + it("should fail if a rule produces two suggestions with the same messageId without data", () => { + assert.throws(() => { + ruleTester.run("suggestions-with-duplicate-messageids-no-data", require("../../fixtures/testers/rule-tester/suggestions").withDuplicateMessageIdsNoData, { + valid: [], + invalid: [ + { code: "var foo = bar;", errors: 1 } + ] + }); + }, "Suggestion message 'Rename identifier' reported from suggestion 1 was previously reported by suggestion 0. Suggestion messages should be unique within an error."); + }); + + it("should fail if a rule produces two suggestions with the same messageId with data", () => { + assert.throws(() => { + ruleTester.run("suggestions-with-duplicate-messageids-with-data", require("../../fixtures/testers/rule-tester/suggestions").withDuplicateMessageIdsWithData, { + valid: [], + invalid: [ + { code: "var foo = bar;", errors: 1 } + ] + }); + }, "Suggestion message 'Rename identifier 'foo' to 'bar'' reported from suggestion 1 was previously reported by suggestion 0. Suggestion messages should be unique within an error."); + }); + it("should throw an error if a rule that doesn't have `meta.hasSuggestions` enabled produces suggestions", () => { assert.throws(() => { ruleTester.run("suggestions-missing-hasSuggestions-property", require("./fixtures/suggestions").withoutHasSuggestionsProperty, { diff --git a/packages/rule-tester/tests/eslint-base/fixtures/suggestions.js b/packages/rule-tester/tests/eslint-base/fixtures/suggestions.js index 4638ac2cacbf..d883167889e0 100644 --- a/packages/rule-tester/tests/eslint-base/fixtures/suggestions.js +++ b/packages/rule-tester/tests/eslint-base/fixtures/suggestions.js @@ -61,6 +61,98 @@ module.exports.withMessageIds = { } }; +module.exports.withDuplicateDescriptions = { + meta: { + hasSuggestions: true + }, + create(context) { + return { + Identifier(node) { + if (node.name === "foo") { + context.report({ + node, + message: "Avoid using identifiers name 'foo'.", + suggest: [{ + desc: "Rename 'foo' to 'bar'", + fix: fixer => fixer.replaceText(node, "bar") + }, { + desc: "Rename 'foo' to 'bar'", + fix: fixer => fixer.replaceText(node, "baz") + }] + }); + } + } + }; + } +}; + +module.exports.withDuplicateMessageIdsNoData = { + meta: { + messages: { + avoidFoo: "Avoid using identifiers named '{{ name }}'.", + renameFoo: "Rename identifier" + }, + hasSuggestions: true + }, + create(context) { + return { + Identifier(node) { + if (node.name === "foo") { + context.report({ + node, + messageId: "avoidFoo", + data: { + name: "foo" + }, + suggest: [{ + messageId: "renameFoo", + fix: fixer => fixer.replaceText(node, "bar") + }, { + messageId: "renameFoo", + fix: fixer => fixer.replaceText(node, "baz") + }] + }); + } + } + }; + } +}; + +module.exports.withDuplicateMessageIdsWithData = { + meta: { + messages: { + avoidFoo: "Avoid using identifiers named foo.", + renameFoo: "Rename identifier 'foo' to '{{ newName }}'" + }, + hasSuggestions: true + }, + create(context) { + return { + Identifier(node) { + if (node.name === "foo") { + context.report({ + node, + messageId: "avoidFoo", + suggest: [{ + messageId: "renameFoo", + data: { + newName: "bar" + }, + fix: fixer => fixer.replaceText(node, "bar") + }, { + messageId: "renameFoo", + data: { + newName: "bar" + }, + fix: fixer => fixer.replaceText(node, "baz") + }] + }); + } + } + }; + } +}; + module.exports.withoutHasSuggestionsProperty = { create(context) { return { From ee677f6f67259f0081ad1a87b1fd9c89692eda21 Mon Sep 17 00:00:00 2001 From: "typescript-eslint[bot]" Date: Mon, 29 Apr 2024 17:14:17 +0000 Subject: [PATCH 15/15] chore(release): publish 7.8.0 --- CHANGELOG.md | 27 ++++ packages/ast-spec/CHANGELOG.md | 6 + packages/ast-spec/package.json | 2 +- packages/eslint-plugin-internal/CHANGELOG.md | 6 + packages/eslint-plugin-internal/package.json | 10 +- packages/eslint-plugin/CHANGELOG.md | 26 ++++ packages/eslint-plugin/package.json | 14 +-- packages/integration-tests/CHANGELOG.md | 6 + packages/integration-tests/package.json | 2 +- packages/parser/CHANGELOG.md | 6 + packages/parser/package.json | 10 +- packages/repo-tools/CHANGELOG.md | 6 + packages/repo-tools/package.json | 2 +- .../CHANGELOG.md | 6 + .../package.json | 6 +- packages/rule-tester/CHANGELOG.md | 18 +++ packages/rule-tester/package.json | 8 +- packages/scope-manager/CHANGELOG.md | 6 + packages/scope-manager/package.json | 8 +- packages/type-utils/CHANGELOG.md | 6 + packages/type-utils/package.json | 8 +- packages/types/CHANGELOG.md | 6 + packages/types/package.json | 2 +- packages/typescript-eslint/CHANGELOG.md | 6 + packages/typescript-eslint/package.json | 8 +- packages/typescript-estree/CHANGELOG.md | 18 +++ packages/typescript-estree/package.json | 6 +- packages/utils/CHANGELOG.md | 18 +++ packages/utils/package.json | 10 +- packages/visitor-keys/CHANGELOG.md | 6 + packages/visitor-keys/package.json | 4 +- packages/website-eslint/CHANGELOG.md | 6 + packages/website-eslint/package.json | 16 +-- packages/website/CHANGELOG.md | 18 +++ packages/website/package.json | 12 +- yarn.lock | 116 +++++++++--------- 36 files changed, 319 insertions(+), 122 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c84e110e22c5..c371164fa2e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ +## 7.8.0 (2024-04-29) + + +### 🚀 Features + +- **rule-tester:** assert suggestion messages are unique ([#8995](https://github.com/typescript-eslint/typescript-eslint/pull/8995)) +- **typescript-estree:** add maximumDefaultProjectFileMatchCount and wide allowDefaultProjectForFiles glob restrictions ([#8925](https://github.com/typescript-eslint/typescript-eslint/pull/8925)) + +### 🩹 Fixes + +- **eslint-plugin:** [no-unsafe-argument] handle tagged templates ([#8746](https://github.com/typescript-eslint/typescript-eslint/pull/8746)) +- **eslint-plugin:** [prefer-optional-chain] suggests optional chaining during strict null equality check ([#8717](https://github.com/typescript-eslint/typescript-eslint/pull/8717)) +- **eslint-plugin:** [consistent-type-assertions] handle tagged templates ([#8993](https://github.com/typescript-eslint/typescript-eslint/pull/8993)) +- **eslint-plugin:** [no-unsafe-return] handle union types ([#9001](https://github.com/typescript-eslint/typescript-eslint/pull/9001)) +- **eslint-plugin:** [no-unused-vars] clear error report range ([#8640](https://github.com/typescript-eslint/typescript-eslint/pull/8640)) +- **utils:** export ESLint backwards-compat functions ([#8976](https://github.com/typescript-eslint/typescript-eslint/pull/8976)) + +### ❤️ Thank You + +- auvred @auvred +- Josh Goldberg ✨ +- jsfm01 @jsfm01 +- Kim Sang Du @developer-bandi +- YeonJuan @yeonjuan + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) diff --git a/packages/ast-spec/CHANGELOG.md b/packages/ast-spec/CHANGELOG.md index baf1d7f7804f..583d32ea8223 100644 --- a/packages/ast-spec/CHANGELOG.md +++ b/packages/ast-spec/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for ast-spec to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for ast-spec to align it with other projects, there were no code changes. diff --git a/packages/ast-spec/package.json b/packages/ast-spec/package.json index b8b43e86453b..9adf56e91219 100644 --- a/packages/ast-spec/package.json +++ b/packages/ast-spec/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/ast-spec", - "version": "7.7.1", + "version": "7.8.0", "description": "Complete specification for the TypeScript-ESTree AST", "private": true, "keywords": [ diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index 44420b2cfba0..7b3c31b879c3 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for eslint-plugin-internal to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for eslint-plugin-internal to align it with other projects, there were no code changes. diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index 55837d3e58a7..9293536a65a8 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": "7.7.1", + "version": "7.8.0", "private": true, "main": "dist/index.js", "types": "index.d.ts", @@ -15,10 +15,10 @@ }, "dependencies": { "@prettier/sync": "^0.5.1", - "@typescript-eslint/rule-tester": "7.7.1", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/type-utils": "7.7.1", - "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/rule-tester": "7.8.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "prettier": "^3.2.5" }, "devDependencies": { diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 440117f007ba..d9a49e3a07b9 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -1,3 +1,29 @@ +## 7.8.0 (2024-04-29) + + +### 🩹 Fixes + +- **eslint-plugin:** [no-unsafe-argument] handle tagged templates + +- **eslint-plugin:** [prefer-optional-chain] suggests optional chaining during strict null equality check + +- **eslint-plugin:** [consistent-type-assertions] handle tagged templates + +- **eslint-plugin:** [no-unsafe-return] handle union types + +- **eslint-plugin:** [no-unused-vars] clear error report range + + +### ❤️ Thank You + +- auvred +- Josh Goldberg ✨ +- jsfm01 +- Kim Sang Du +- YeonJuan + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index d6cd43c42f43..7fc935491509 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "7.7.1", + "version": "7.8.0", "description": "TypeScript plugin for ESLint", "files": [ "dist", @@ -62,10 +62,10 @@ }, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/type-utils": "7.7.1", - "@typescript-eslint/utils": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.3.1", @@ -78,8 +78,8 @@ "@types/marked": "*", "@types/mdast": "^4.0.3", "@types/natural-compare": "*", - "@typescript-eslint/rule-schema-to-typescript-types": "7.7.1", - "@typescript-eslint/rule-tester": "7.7.1", + "@typescript-eslint/rule-schema-to-typescript-types": "7.8.0", + "@typescript-eslint/rule-tester": "7.8.0", "ajv": "^6.12.6", "chalk": "^5.3.0", "cross-env": "^7.0.3", diff --git a/packages/integration-tests/CHANGELOG.md b/packages/integration-tests/CHANGELOG.md index eba18856f8e5..e78f680a14a0 100644 --- a/packages/integration-tests/CHANGELOG.md +++ b/packages/integration-tests/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for integration-tests to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for integration-tests to align it with other projects, there were no code changes. diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index d2b812c85797..a61f6924df21 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/integration-tests", - "version": "7.7.1", + "version": "7.8.0", "private": true, "scripts": { "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore", diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index 1c85a787e210..8a5414f2e012 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for parser to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for parser to align it with other projects, there were no code changes. diff --git a/packages/parser/package.json b/packages/parser/package.json index 46870b381203..d552dcc0e100 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "7.7.1", + "version": "7.8.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "files": [ "dist", @@ -52,10 +52,10 @@ "eslint": "^8.56.0" }, "dependencies": { - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4" }, "devDependencies": { diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index c41edbfeb087..350e1ccfede4 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for repo-tools to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for repo-tools to align it with other projects, there were no code changes. diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index bfc2baa1fef7..8e1ded99a681 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/repo-tools", - "version": "7.7.1", + "version": "7.8.0", "private": true, "scripts": { "//": "NOTE: intentionally no build step in this package", diff --git a/packages/rule-schema-to-typescript-types/CHANGELOG.md b/packages/rule-schema-to-typescript-types/CHANGELOG.md index 55317a5c3ddf..1e45b77d4f3b 100644 --- a/packages/rule-schema-to-typescript-types/CHANGELOG.md +++ b/packages/rule-schema-to-typescript-types/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for rule-schema-to-typescript-types to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for rule-schema-to-typescript-types to align it with other projects, there were no code changes. diff --git a/packages/rule-schema-to-typescript-types/package.json b/packages/rule-schema-to-typescript-types/package.json index 8ab24b92e711..44821ab65c2d 100644 --- a/packages/rule-schema-to-typescript-types/package.json +++ b/packages/rule-schema-to-typescript-types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/rule-schema-to-typescript-types", - "version": "7.7.1", + "version": "7.8.0", "private": true, "type": "commonjs", "exports": { @@ -34,8 +34,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/type-utils": "7.7.1", - "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/type-utils": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "natural-compare": "^1.4.0", "prettier": "^3.2.5" }, diff --git a/packages/rule-tester/CHANGELOG.md b/packages/rule-tester/CHANGELOG.md index 7d696f585491..f48c165b13fc 100644 --- a/packages/rule-tester/CHANGELOG.md +++ b/packages/rule-tester/CHANGELOG.md @@ -1,3 +1,21 @@ +## 7.8.0 (2024-04-29) + + +### 🚀 Features + +- **rule-tester:** assert suggestion messages are unique + + +### ❤️ Thank You + +- auvred +- Josh Goldberg ✨ +- jsfm01 +- Kim Sang Du +- YeonJuan + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for rule-tester to align it with other projects, there were no code changes. diff --git a/packages/rule-tester/package.json b/packages/rule-tester/package.json index 28f9fc92f11a..e929e8081e81 100644 --- a/packages/rule-tester/package.json +++ b/packages/rule-tester/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/rule-tester", - "version": "7.7.1", + "version": "7.8.0", "description": "Tooling to test ESLint rules", "files": [ "dist", @@ -48,8 +48,8 @@ }, "//": "NOTE - AJV is out-of-date, but it's intentionally synced with ESLint - https://github.com/eslint/eslint/blob/ad9dd6a933fd098a0d99c6a9aa059850535c23ee/package.json#L70", "dependencies": { - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "ajv": "^6.12.6", "lodash.merge": "4.6.2", "semver": "^7.6.0" @@ -60,7 +60,7 @@ }, "devDependencies": { "@types/lodash.merge": "4.6.9", - "@typescript-eslint/parser": "7.7.1", + "@typescript-eslint/parser": "7.8.0", "chai": "^4.4.1", "mocha": "^10.4.0", "sinon": "^16.1.3", diff --git a/packages/scope-manager/CHANGELOG.md b/packages/scope-manager/CHANGELOG.md index 3c8be80dd39f..d60b64e524b8 100644 --- a/packages/scope-manager/CHANGELOG.md +++ b/packages/scope-manager/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for scope-manager to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for scope-manager to align it with other projects, there were no code changes. diff --git a/packages/scope-manager/package.json b/packages/scope-manager/package.json index 5b7d1615a591..1ea6d9c32c64 100644 --- a/packages/scope-manager/package.json +++ b/packages/scope-manager/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/scope-manager", - "version": "7.7.1", + "version": "7.8.0", "description": "TypeScript scope analyser for ESLint", "files": [ "dist", @@ -46,12 +46,12 @@ "typecheck": "npx nx typecheck" }, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1" + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0" }, "devDependencies": { "@types/glob": "*", - "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/typescript-estree": "7.8.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/type-utils/CHANGELOG.md b/packages/type-utils/CHANGELOG.md index 0a68332b77cf..d6303d905aba 100644 --- a/packages/type-utils/CHANGELOG.md +++ b/packages/type-utils/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for type-utils to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) diff --git a/packages/type-utils/package.json b/packages/type-utils/package.json index f587e00c19cb..d5f71f74fba8 100644 --- a/packages/type-utils/package.json +++ b/packages/type-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/type-utils", - "version": "7.7.1", + "version": "7.8.0", "description": "Type utilities for working with TypeScript + ESLint together", "files": [ "dist", @@ -46,13 +46,13 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/utils": "7.7.1", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/utils": "7.8.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, "devDependencies": { - "@typescript-eslint/parser": "7.7.1", + "@typescript-eslint/parser": "7.8.0", "ajv": "^6.12.6", "downlevel-dts": "*", "jest": "29.7.0", diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index 39b17158868d..3c123e3ac4d3 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for types to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for types to align it with other projects, there were no code changes. diff --git a/packages/types/package.json b/packages/types/package.json index 2e9480978bb0..d1e87a4ad6f3 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/types", - "version": "7.7.1", + "version": "7.8.0", "description": "Types for the TypeScript-ESTree AST spec", "files": [ "dist", diff --git a/packages/typescript-eslint/CHANGELOG.md b/packages/typescript-eslint/CHANGELOG.md index a499f9b3d45c..57fd1e9c8fe9 100644 --- a/packages/typescript-eslint/CHANGELOG.md +++ b/packages/typescript-eslint/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for typescript-eslint to align it with other projects, there were no code changes. diff --git a/packages/typescript-eslint/package.json b/packages/typescript-eslint/package.json index 4b1fef4cf88c..4402f7e4820a 100644 --- a/packages/typescript-eslint/package.json +++ b/packages/typescript-eslint/package.json @@ -1,6 +1,6 @@ { "name": "typescript-eslint", - "version": "7.7.1", + "version": "7.8.0", "description": "Tooling which enables you to use TypeScript with ESLint", "files": [ "dist", @@ -55,9 +55,9 @@ "eslint": "^8.56.0" }, "dependencies": { - "@typescript-eslint/eslint-plugin": "7.7.1", - "@typescript-eslint/parser": "7.7.1", - "@typescript-eslint/utils": "7.7.1" + "@typescript-eslint/eslint-plugin": "7.8.0", + "@typescript-eslint/parser": "7.8.0", + "@typescript-eslint/utils": "7.8.0" }, "devDependencies": { "downlevel-dts": "*", diff --git a/packages/typescript-estree/CHANGELOG.md b/packages/typescript-estree/CHANGELOG.md index be372ee510b8..0eee2460cb1c 100644 --- a/packages/typescript-estree/CHANGELOG.md +++ b/packages/typescript-estree/CHANGELOG.md @@ -1,3 +1,21 @@ +## 7.8.0 (2024-04-29) + + +### 🚀 Features + +- **typescript-estree:** add maximumDefaultProjectFileMatchCount and wide allowDefaultProjectForFiles glob restrictions + + +### ❤️ Thank You + +- auvred +- Josh Goldberg ✨ +- jsfm01 +- Kim Sang Du +- YeonJuan + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for typescript-estree to align it with other projects, there were no code changes. diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 608c552e3073..6c9ed74ba133 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "7.7.1", + "version": "7.8.0", "description": "A parser that converts TypeScript source code into an ESTree compatible form", "files": [ "dist", @@ -54,8 +54,8 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index ddb435b7fd88..a058729eae0d 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -1,3 +1,21 @@ +## 7.8.0 (2024-04-29) + + +### 🩹 Fixes + +- **utils:** export ESLint backwards-compat functions + + +### ❤️ Thank You + +- auvred +- Josh Goldberg ✨ +- jsfm01 +- Kim Sang Du +- YeonJuan + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for utils to align it with other projects, there were no code changes. diff --git a/packages/utils/package.json b/packages/utils/package.json index 1d22762fcb7f..f9dde8dd21ef 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/utils", - "version": "7.7.1", + "version": "7.8.0", "description": "Utilities for working with TypeScript + ESLint together", "files": [ "dist", @@ -70,16 +70,16 @@ "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.15", "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", "semver": "^7.6.0" }, "peerDependencies": { "eslint": "^8.56.0" }, "devDependencies": { - "@typescript-eslint/parser": "7.7.1", + "@typescript-eslint/parser": "7.8.0", "downlevel-dts": "*", "jest": "29.7.0", "prettier": "^3.2.5", diff --git a/packages/visitor-keys/CHANGELOG.md b/packages/visitor-keys/CHANGELOG.md index f1d100f9dcf8..cf9ada26c597 100644 --- a/packages/visitor-keys/CHANGELOG.md +++ b/packages/visitor-keys/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for visitor-keys to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for visitor-keys to align it with other projects, there were no code changes. diff --git a/packages/visitor-keys/package.json b/packages/visitor-keys/package.json index a870779ce07e..30df303d2900 100644 --- a/packages/visitor-keys/package.json +++ b/packages/visitor-keys/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/visitor-keys", - "version": "7.7.1", + "version": "7.8.0", "description": "Visitor keys used to help traverse the TypeScript-ESTree AST", "files": [ "dist", @@ -47,7 +47,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/types": "7.8.0", "eslint-visitor-keys": "^3.4.3" }, "devDependencies": { diff --git a/packages/website-eslint/CHANGELOG.md b/packages/website-eslint/CHANGELOG.md index ea05941e7ca9..71d000353e17 100644 --- a/packages/website-eslint/CHANGELOG.md +++ b/packages/website-eslint/CHANGELOG.md @@ -1,3 +1,9 @@ +## 7.8.0 (2024-04-29) + +This was a version bump only for website-eslint to align it with other projects, there were no code changes. + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) This was a version bump only for website-eslint to align it with other projects, there were no code changes. diff --git a/packages/website-eslint/package.json b/packages/website-eslint/package.json index 18c67e2a89d1..449399978167 100644 --- a/packages/website-eslint/package.json +++ b/packages/website-eslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/website-eslint", - "version": "7.7.1", + "version": "7.8.0", "private": true, "description": "ESLint which works in browsers.", "files": [ @@ -23,16 +23,16 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@typescript-eslint/types": "7.7.1", - "@typescript-eslint/utils": "7.7.1" + "@typescript-eslint/types": "7.8.0", + "@typescript-eslint/utils": "7.8.0" }, "devDependencies": { "@eslint/js": "*", - "@typescript-eslint/eslint-plugin": "7.7.1", - "@typescript-eslint/parser": "7.7.1", - "@typescript-eslint/scope-manager": "7.7.1", - "@typescript-eslint/typescript-estree": "7.7.1", - "@typescript-eslint/visitor-keys": "7.7.1", + "@typescript-eslint/eslint-plugin": "7.8.0", + "@typescript-eslint/parser": "7.8.0", + "@typescript-eslint/scope-manager": "7.8.0", + "@typescript-eslint/typescript-estree": "7.8.0", + "@typescript-eslint/visitor-keys": "7.8.0", "esbuild": "~0.20.2", "eslint": "*", "esquery": "*", diff --git a/packages/website/CHANGELOG.md b/packages/website/CHANGELOG.md index 71d1be37c0bf..fb24be637e83 100644 --- a/packages/website/CHANGELOG.md +++ b/packages/website/CHANGELOG.md @@ -1,3 +1,21 @@ +## 7.8.0 (2024-04-29) + + +### 🚀 Features + +- **typescript-estree:** add maximumDefaultProjectFileMatchCount and wide allowDefaultProjectForFiles glob restrictions + + +### ❤️ Thank You + +- auvred +- Josh Goldberg ✨ +- jsfm01 +- Kim Sang Du +- YeonJuan + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + ## 7.7.1 (2024-04-22) diff --git a/packages/website/package.json b/packages/website/package.json index d8cb3f7c5549..07d5f9f92e0e 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "website", - "version": "7.7.1", + "version": "7.8.0", "private": true, "scripts": { "build": "docusaurus build", @@ -25,8 +25,8 @@ "@docusaurus/theme-common": "^3.2.1", "@mdx-js/react": "^3.0.1", "@prettier/sync": "*", - "@typescript-eslint/parser": "7.7.1", - "@typescript-eslint/website-eslint": "7.7.1", + "@typescript-eslint/parser": "7.8.0", + "@typescript-eslint/website-eslint": "7.8.0", "clsx": "^2.1.0", "eslint": "*", "json-schema": "^0.4.0", @@ -49,9 +49,9 @@ "@types/react": "*", "@types/react-helmet": "^6.1.11", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "7.7.1", - "@typescript-eslint/rule-schema-to-typescript-types": "7.7.1", - "@typescript-eslint/types": "7.7.1", + "@typescript-eslint/eslint-plugin": "7.8.0", + "@typescript-eslint/rule-schema-to-typescript-types": "7.8.0", + "@typescript-eslint/types": "7.8.0", "copy-webpack-plugin": "^12.0.0", "cross-fetch": "*", "globby": "^11.1.0", diff --git a/yarn.lock b/yarn.lock index 8261e0088d37..5fd1b3ac69cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5538,17 +5538,17 @@ __metadata: resolution: "@typescript-eslint/eslint-plugin-internal@workspace:packages/eslint-plugin-internal" dependencies: "@prettier/sync": ^0.5.1 - "@typescript-eslint/rule-tester": 7.7.1 - "@typescript-eslint/scope-manager": 7.7.1 - "@typescript-eslint/type-utils": 7.7.1 - "@typescript-eslint/utils": 7.7.1 + "@typescript-eslint/rule-tester": 7.8.0 + "@typescript-eslint/scope-manager": 7.8.0 + "@typescript-eslint/type-utils": 7.8.0 + "@typescript-eslint/utils": 7.8.0 jest: 29.7.0 prettier: ^3.2.5 rimraf: "*" languageName: unknown linkType: soft -"@typescript-eslint/eslint-plugin@7.7.1, @typescript-eslint/eslint-plugin@workspace:packages/eslint-plugin": +"@typescript-eslint/eslint-plugin@7.8.0, @typescript-eslint/eslint-plugin@workspace:packages/eslint-plugin": version: 0.0.0-use.local resolution: "@typescript-eslint/eslint-plugin@workspace:packages/eslint-plugin" dependencies: @@ -5557,12 +5557,12 @@ __metadata: "@types/marked": "*" "@types/mdast": ^4.0.3 "@types/natural-compare": "*" - "@typescript-eslint/rule-schema-to-typescript-types": 7.7.1 - "@typescript-eslint/rule-tester": 7.7.1 - "@typescript-eslint/scope-manager": 7.7.1 - "@typescript-eslint/type-utils": 7.7.1 - "@typescript-eslint/utils": 7.7.1 - "@typescript-eslint/visitor-keys": 7.7.1 + "@typescript-eslint/rule-schema-to-typescript-types": 7.8.0 + "@typescript-eslint/rule-tester": 7.8.0 + "@typescript-eslint/scope-manager": 7.8.0 + "@typescript-eslint/type-utils": 7.8.0 + "@typescript-eslint/utils": 7.8.0 + "@typescript-eslint/visitor-keys": 7.8.0 ajv: ^6.12.6 chalk: ^5.3.0 cross-env: ^7.0.3 @@ -5609,15 +5609,15 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/parser@7.7.1, @typescript-eslint/parser@workspace:packages/parser": +"@typescript-eslint/parser@7.8.0, @typescript-eslint/parser@workspace:packages/parser": version: 0.0.0-use.local resolution: "@typescript-eslint/parser@workspace:packages/parser" dependencies: "@types/glob": "*" - "@typescript-eslint/scope-manager": 7.7.1 - "@typescript-eslint/types": 7.7.1 - "@typescript-eslint/typescript-estree": 7.7.1 - "@typescript-eslint/visitor-keys": 7.7.1 + "@typescript-eslint/scope-manager": 7.8.0 + "@typescript-eslint/types": 7.8.0 + "@typescript-eslint/typescript-estree": 7.8.0 + "@typescript-eslint/visitor-keys": 7.8.0 debug: ^4.3.4 downlevel-dts: "*" glob: "*" @@ -5648,25 +5648,25 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/rule-schema-to-typescript-types@7.7.1, @typescript-eslint/rule-schema-to-typescript-types@workspace:packages/rule-schema-to-typescript-types": +"@typescript-eslint/rule-schema-to-typescript-types@7.8.0, @typescript-eslint/rule-schema-to-typescript-types@workspace:packages/rule-schema-to-typescript-types": version: 0.0.0-use.local resolution: "@typescript-eslint/rule-schema-to-typescript-types@workspace:packages/rule-schema-to-typescript-types" dependencies: - "@typescript-eslint/type-utils": 7.7.1 - "@typescript-eslint/utils": 7.7.1 + "@typescript-eslint/type-utils": 7.8.0 + "@typescript-eslint/utils": 7.8.0 natural-compare: ^1.4.0 prettier: ^3.2.5 languageName: unknown linkType: soft -"@typescript-eslint/rule-tester@7.7.1, @typescript-eslint/rule-tester@workspace:packages/rule-tester": +"@typescript-eslint/rule-tester@7.8.0, @typescript-eslint/rule-tester@workspace:packages/rule-tester": version: 0.0.0-use.local resolution: "@typescript-eslint/rule-tester@workspace:packages/rule-tester" dependencies: "@types/lodash.merge": 4.6.9 - "@typescript-eslint/parser": 7.7.1 - "@typescript-eslint/typescript-estree": 7.7.1 - "@typescript-eslint/utils": 7.7.1 + "@typescript-eslint/parser": 7.8.0 + "@typescript-eslint/typescript-estree": 7.8.0 + "@typescript-eslint/utils": 7.8.0 ajv: ^6.12.6 chai: ^4.4.1 lodash.merge: 4.6.2 @@ -5681,14 +5681,14 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/scope-manager@7.7.1, @typescript-eslint/scope-manager@workspace:packages/scope-manager": +"@typescript-eslint/scope-manager@7.8.0, @typescript-eslint/scope-manager@workspace:packages/scope-manager": version: 0.0.0-use.local resolution: "@typescript-eslint/scope-manager@workspace:packages/scope-manager" dependencies: "@types/glob": "*" - "@typescript-eslint/types": 7.7.1 - "@typescript-eslint/typescript-estree": 7.7.1 - "@typescript-eslint/visitor-keys": 7.7.1 + "@typescript-eslint/types": 7.8.0 + "@typescript-eslint/typescript-estree": 7.8.0 + "@typescript-eslint/visitor-keys": 7.8.0 glob: "*" jest-specific-snapshot: "*" make-dir: "*" @@ -5717,13 +5717,13 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@7.7.1, @typescript-eslint/type-utils@workspace:packages/type-utils": +"@typescript-eslint/type-utils@7.8.0, @typescript-eslint/type-utils@workspace:packages/type-utils": version: 0.0.0-use.local resolution: "@typescript-eslint/type-utils@workspace:packages/type-utils" dependencies: - "@typescript-eslint/parser": 7.7.1 - "@typescript-eslint/typescript-estree": 7.7.1 - "@typescript-eslint/utils": 7.7.1 + "@typescript-eslint/parser": 7.8.0 + "@typescript-eslint/typescript-estree": 7.8.0 + "@typescript-eslint/utils": 7.8.0 ajv: ^6.12.6 debug: ^4.3.4 downlevel-dts: "*" @@ -5740,7 +5740,7 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/types@7.7.1, @typescript-eslint/types@workspace:packages/types": +"@typescript-eslint/types@7.8.0, @typescript-eslint/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@typescript-eslint/types@workspace:packages/types" dependencies: @@ -5840,14 +5840,14 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/typescript-estree@7.7.1, @typescript-eslint/typescript-estree@workspace:packages/typescript-estree": +"@typescript-eslint/typescript-estree@7.8.0, @typescript-eslint/typescript-estree@workspace:packages/typescript-estree": version: 0.0.0-use.local resolution: "@typescript-eslint/typescript-estree@workspace:packages/typescript-estree" dependencies: "@babel/code-frame": "*" "@babel/parser": "*" - "@typescript-eslint/types": 7.7.1 - "@typescript-eslint/visitor-keys": 7.7.1 + "@typescript-eslint/types": 7.8.0 + "@typescript-eslint/visitor-keys": 7.8.0 debug: ^4.3.4 glob: "*" globby: ^11.1.0 @@ -5905,17 +5905,17 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@7.7.1, @typescript-eslint/utils@workspace:packages/utils": +"@typescript-eslint/utils@7.8.0, @typescript-eslint/utils@workspace:packages/utils": version: 0.0.0-use.local resolution: "@typescript-eslint/utils@workspace:packages/utils" dependencies: "@eslint-community/eslint-utils": ^4.4.0 "@types/json-schema": ^7.0.15 "@types/semver": ^7.5.8 - "@typescript-eslint/parser": 7.7.1 - "@typescript-eslint/scope-manager": 7.7.1 - "@typescript-eslint/types": 7.7.1 - "@typescript-eslint/typescript-estree": 7.7.1 + "@typescript-eslint/parser": 7.8.0 + "@typescript-eslint/scope-manager": 7.8.0 + "@typescript-eslint/types": 7.8.0 + "@typescript-eslint/typescript-estree": 7.8.0 downlevel-dts: "*" jest: 29.7.0 prettier: ^3.2.5 @@ -5962,12 +5962,12 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@7.7.1, @typescript-eslint/visitor-keys@workspace:packages/visitor-keys": +"@typescript-eslint/visitor-keys@7.8.0, @typescript-eslint/visitor-keys@workspace:packages/visitor-keys": version: 0.0.0-use.local resolution: "@typescript-eslint/visitor-keys@workspace:packages/visitor-keys" dependencies: "@types/eslint-visitor-keys": "*" - "@typescript-eslint/types": 7.7.1 + "@typescript-eslint/types": 7.8.0 downlevel-dts: "*" eslint-visitor-keys: ^3.4.3 jest: 29.7.0 @@ -5997,18 +5997,18 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/website-eslint@7.7.1, @typescript-eslint/website-eslint@workspace:packages/website-eslint": +"@typescript-eslint/website-eslint@7.8.0, @typescript-eslint/website-eslint@workspace:packages/website-eslint": version: 0.0.0-use.local resolution: "@typescript-eslint/website-eslint@workspace:packages/website-eslint" dependencies: "@eslint/js": "*" - "@typescript-eslint/eslint-plugin": 7.7.1 - "@typescript-eslint/parser": 7.7.1 - "@typescript-eslint/scope-manager": 7.7.1 - "@typescript-eslint/types": 7.7.1 - "@typescript-eslint/typescript-estree": 7.7.1 - "@typescript-eslint/utils": 7.7.1 - "@typescript-eslint/visitor-keys": 7.7.1 + "@typescript-eslint/eslint-plugin": 7.8.0 + "@typescript-eslint/parser": 7.8.0 + "@typescript-eslint/scope-manager": 7.8.0 + "@typescript-eslint/types": 7.8.0 + "@typescript-eslint/typescript-estree": 7.8.0 + "@typescript-eslint/utils": 7.8.0 + "@typescript-eslint/visitor-keys": 7.8.0 esbuild: ~0.20.2 eslint: "*" esquery: "*" @@ -19276,9 +19276,9 @@ __metadata: version: 0.0.0-use.local resolution: "typescript-eslint@workspace:packages/typescript-eslint" dependencies: - "@typescript-eslint/eslint-plugin": 7.7.1 - "@typescript-eslint/parser": 7.7.1 - "@typescript-eslint/utils": 7.7.1 + "@typescript-eslint/eslint-plugin": 7.8.0 + "@typescript-eslint/parser": 7.8.0 + "@typescript-eslint/utils": 7.8.0 downlevel-dts: "*" jest: 29.7.0 prettier: ^3.2.5 @@ -19983,11 +19983,11 @@ __metadata: "@types/react": "*" "@types/react-helmet": ^6.1.11 "@types/react-router-dom": ^5.3.3 - "@typescript-eslint/eslint-plugin": 7.7.1 - "@typescript-eslint/parser": 7.7.1 - "@typescript-eslint/rule-schema-to-typescript-types": 7.7.1 - "@typescript-eslint/types": 7.7.1 - "@typescript-eslint/website-eslint": 7.7.1 + "@typescript-eslint/eslint-plugin": 7.8.0 + "@typescript-eslint/parser": 7.8.0 + "@typescript-eslint/rule-schema-to-typescript-types": 7.8.0 + "@typescript-eslint/types": 7.8.0 + "@typescript-eslint/website-eslint": 7.8.0 clsx: ^2.1.0 copy-webpack-plugin: ^12.0.0 cross-fetch: "*"