diff --git a/packages/utils/src/eslint-utils/getParserServices.ts b/packages/utils/src/eslint-utils/getParserServices.ts index 0fd908f4a2ec..f105fbf9902a 100644 --- a/packages/utils/src/eslint-utils/getParserServices.ts +++ b/packages/utils/src/eslint-utils/getParserServices.ts @@ -3,7 +3,7 @@ import type { ParserServices, ParserServicesWithTypeInformation, } from '../ts-estree'; -import { parserPathSeemsToBeTSESLint } from './parserPathSeemsToBeTSESLint'; +import { parserSeemsToBeTSESLint } from './parserSeemsToBeTSESLint'; const ERROR_MESSAGE_REQUIRES_PARSER_SERVICES = 'You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.'; @@ -60,6 +60,9 @@ function getParserServices( context: Readonly>, allowWithoutFullTypeInformation = false, ): ParserServices { + const parser = + context.parserPath || context.languageOptions.parser?.meta?.name; + // This check is unnecessary if the user is using the latest version of our parser. // // However the world isn't perfect: @@ -74,7 +77,7 @@ function getParserServices( context.sourceCode.parserServices?.esTreeNodeToTSNodeMap == null || context.sourceCode.parserServices.tsNodeToESTreeNodeMap == null ) { - throwError(context.parserPath); + throwError(parser); } // if a rule requires full type information, then hard fail if it doesn't exist @@ -83,21 +86,20 @@ function getParserServices( context.sourceCode.parserServices.program == null && !allowWithoutFullTypeInformation ) { - throwError(context.parserPath); + throwError(parser); } return context.sourceCode.parserServices as ParserServices; } /* eslint-enable @typescript-eslint/unified-signatures */ -function throwError(parserPath: string): never { +function throwError(parser: string | undefined): never { const messages = [ ERROR_MESSAGE_REQUIRES_PARSER_SERVICES, - `Parser: ${parserPath}`, - ]; - if (!parserPathSeemsToBeTSESLint(parserPath)) { - messages.push(ERROR_MESSAGE_UNKNOWN_PARSER); - } + `Parser: ${parser || '(unknown)'}`, + !parserSeemsToBeTSESLint(parser) && ERROR_MESSAGE_UNKNOWN_PARSER, + ].filter(Boolean); + throw new Error(messages.join('\n')); } diff --git a/packages/utils/src/eslint-utils/parserPathSeemsToBeTSESLint.ts b/packages/utils/src/eslint-utils/parserPathSeemsToBeTSESLint.ts deleted file mode 100644 index ab68b4367ab7..000000000000 --- a/packages/utils/src/eslint-utils/parserPathSeemsToBeTSESLint.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function parserPathSeemsToBeTSESLint(parserPath: string): boolean { - return /(?:typescript-eslint|\.\.)[\w/\\]*parser/.test(parserPath); -} diff --git a/packages/utils/src/eslint-utils/parserSeemsToBeTSESLint.ts b/packages/utils/src/eslint-utils/parserSeemsToBeTSESLint.ts new file mode 100644 index 000000000000..386384b0d331 --- /dev/null +++ b/packages/utils/src/eslint-utils/parserSeemsToBeTSESLint.ts @@ -0,0 +1,3 @@ +export function parserSeemsToBeTSESLint(parser: string | undefined): boolean { + return !!parser && /(?:typescript-eslint|\.\.)[\w/\\]*parser/.test(parser); +} diff --git a/packages/utils/src/ts-eslint/Rule.ts b/packages/utils/src/ts-eslint/Rule.ts index 8ca4c7de2a72..d7e3562c8181 100644 --- a/packages/utils/src/ts-eslint/Rule.ts +++ b/packages/utils/src/ts-eslint/Rule.ts @@ -203,9 +203,9 @@ export interface RuleContext< */ options: Options; /** - * The name of the parser from configuration. + * The name of the parser from configuration, if in eslintrc (legacy) config. */ - parserPath: string; + parserPath: string | undefined; /** * The language options configured for this run */ diff --git a/packages/utils/tests/eslint-utils/getParserServices.test.ts b/packages/utils/tests/eslint-utils/getParserServices.test.ts index b247727786ae..2fe3c0c04c3c 100644 --- a/packages/utils/tests/eslint-utils/getParserServices.test.ts +++ b/packages/utils/tests/eslint-utils/getParserServices.test.ts @@ -3,6 +3,7 @@ import type * as ts from 'typescript'; import type { ParserServices, TSESLint, TSESTree } from '../../src'; import { ESLintUtils } from '../../src'; +import type { FlatConfig } from '../../src/ts-eslint'; type UnknownRuleContext = Readonly>; @@ -25,18 +26,20 @@ const createMockRuleContext = ( ...overrides, }) as unknown as UnknownRuleContext; -const requiresParserServicesMessageTemplate = +const requiresParserServicesMessageTemplate = (parser = '\\S*'): string => 'You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.\n' + - 'Parser: \\S*'; -const baseErrorRegex = new RegExp(requiresParserServicesMessageTemplate); -const unknownParserErrorRegex = new RegExp( - requiresParserServicesMessageTemplate + - '\n' + - 'Note: detected a parser other than @typescript-eslint/parser. Make sure the parser is configured to forward "parserOptions.project" to @typescript-eslint/parser.', -); + `Parser: ${parser}`; +const baseErrorRegex = (parser?: string): RegExp => + new RegExp(requiresParserServicesMessageTemplate(parser)); +const unknownParserErrorRegex = (parser?: string): RegExp => + new RegExp( + requiresParserServicesMessageTemplate(parser) + + '\n' + + 'Note: detected a parser other than @typescript-eslint/parser. Make sure the parser is configured to forward "parserOptions.project" to @typescript-eslint/parser.', + ); describe('getParserServices', () => { - it('throws a standard error when parserOptions.esTreeNodeToTSNodeMap is missing and the parser is known', () => { + it('throws a standard error with the parser when parserOptions.esTreeNodeToTSNodeMap is missing and the parser is typescript-eslint', () => { const context = createMockRuleContext({ sourceCode: { ...defaults.sourceCode, @@ -48,7 +51,69 @@ describe('getParserServices', () => { }); expect(() => ESLintUtils.getParserServices(context)).toThrow( - baseErrorRegex, + baseErrorRegex('@typescript-eslint[\\/]parser[\\/]dist[\\/]index\\.js'), + ); + }); + + it('throws a standard error with the parser when parserOptions.esTreeNodeToTSNodeMap is missing and the parser is custom', () => { + const context = createMockRuleContext({ + languageOptions: { + parser: { + meta: { + name: 'custom-parser', + }, + } as FlatConfig.Parser, + }, + parserPath: undefined, + sourceCode: { + ...defaults.sourceCode, + parserServices: { + ...defaults.sourceCode.parserServices, + esTreeNodeToTSNodeMap: undefined as any, + }, + }, + }); + + expect(() => ESLintUtils.getParserServices(context)).toThrow( + baseErrorRegex('custom-parser'), + ); + }); + + it('throws a standard error with an unknown parser when parserOptions.esTreeNodeToTSNodeMap is missing and the parser is missing', () => { + const context = createMockRuleContext({ + languageOptions: {}, + parserPath: undefined, + sourceCode: { + ...defaults.sourceCode, + parserServices: { + ...defaults.sourceCode.parserServices, + esTreeNodeToTSNodeMap: undefined as any, + }, + }, + }); + + expect(() => ESLintUtils.getParserServices(context)).toThrow( + baseErrorRegex('\\(unknown\\)'), + ); + }); + + it('throws a standard error with an unknown parser when parserOptions.esTreeNodeToTSNodeMap is missing and the parser is unknown', () => { + const context = createMockRuleContext({ + languageOptions: { + parser: {} as FlatConfig.Parser, + }, + parserPath: undefined, + sourceCode: { + ...defaults.sourceCode, + parserServices: { + ...defaults.sourceCode.parserServices, + esTreeNodeToTSNodeMap: undefined as any, + }, + }, + }); + + expect(() => ESLintUtils.getParserServices(context)).toThrow( + baseErrorRegex('\\(unknown\\)'), ); }); @@ -64,7 +129,7 @@ describe('getParserServices', () => { }, }); expect(() => ESLintUtils.getParserServices(context)).toThrow( - unknownParserErrorRegex, + unknownParserErrorRegex(), ); }); @@ -80,7 +145,7 @@ describe('getParserServices', () => { }); expect(() => ESLintUtils.getParserServices(context)).toThrow( - baseErrorRegex, + baseErrorRegex(), ); }); @@ -96,7 +161,7 @@ describe('getParserServices', () => { }); expect(() => ESLintUtils.getParserServices(context)).toThrow( - baseErrorRegex, + baseErrorRegex(), ); }); diff --git a/packages/utils/tests/eslint-utils/parserPathSeemsToBeTSESLint.test.ts b/packages/utils/tests/eslint-utils/parserSeemsToBeTSESLint.test.ts similarity index 79% rename from packages/utils/tests/eslint-utils/parserPathSeemsToBeTSESLint.test.ts rename to packages/utils/tests/eslint-utils/parserSeemsToBeTSESLint.test.ts index 0c11c1664005..fb70c5e644e6 100644 --- a/packages/utils/tests/eslint-utils/parserPathSeemsToBeTSESLint.test.ts +++ b/packages/utils/tests/eslint-utils/parserSeemsToBeTSESLint.test.ts @@ -1,7 +1,9 @@ -import { parserPathSeemsToBeTSESLint } from '../../src/eslint-utils/parserPathSeemsToBeTSESLint'; +import { parserSeemsToBeTSESLint } from '../../src/eslint-utils/parserSeemsToBeTSESLint'; -describe('parserPathSeemsToBeTSESLint', () => { +describe('parserSeemsToBeTSESLint', () => { test.each([ + [undefined, false], + ['espree', false], ['local.js', false], ['../other.js', false], ['@babel/eslint-parser/lib/index.cjs', false], @@ -19,6 +21,6 @@ describe('parserPathSeemsToBeTSESLint', () => { ['/path/to/@typescript-eslint/packages/parser/dist/index.js', true], ['/path/to/@typescript-eslint/packages/parser/index.js', true], ])('%s', (parserPath, expected) => { - expect(parserPathSeemsToBeTSESLint(parserPath)).toBe(expected); + expect(parserSeemsToBeTSESLint(parserPath)).toBe(expected); }); }); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy