diff --git a/lib/util/get-parser-services.js b/lib/util/get-parser-services.js index 1d0be646..571b3fe8 100644 --- a/lib/util/get-parser-services.js +++ b/lib/util/get-parser-services.js @@ -1,24 +1,59 @@ "use strict" -const { - getParserServices: getParserServicesFromTsEslint, -} = require("@typescript-eslint/utils/eslint-utils") +const ERROR_MESSAGE_REQUIRES_PARSER_SERVICES = + "You have used a rule which requires type information, but don't have parserOptions set to generate type information for this file. See https://typescript-eslint.io/getting-started/typed-linting for enabling linting with type information." +const ERROR_MESSAGE_UNKNOWN_PARSER = + 'Note: detected a parser other than @typescript-eslint/parser. Make sure the parser is configured to forward "parserOptions.project" to @typescript-eslint/parser.' + +/** + * Checks if the parser seems to be `@typescript-eslint/parser`. + * - Implementation from `@typescript-eslint/utils`. @see https://github.com/typescript-eslint/typescript-eslint/blob/3e545207f0e34611f528128fc699b25091bc40b3/packages/utils/src/eslint-utils/parserSeemsToBeTSESLint.ts + * + * @param {string | undefined} parser - The parser to check. + * @returns {boolean} `true` if the parser seems to be `@typescript-eslint/parser`, `false` otherwise. + */ +function parserSeemsToBeTSESLint(parser) { + return !!parser && /(?:typescript-eslint|\.\.)[\w/\\]*parser/.test(parser) +} + +/** + * Throws a detailed error if parser services are not available. + * @param {string | undefined} parser - The parser name to mention in the error message. + */ +function throwError(parser) { + const messages = [ + ERROR_MESSAGE_REQUIRES_PARSER_SERVICES, + `Parser: ${parser || "(unknown)"}`, + !parserSeemsToBeTSESLint(parser) && ERROR_MESSAGE_UNKNOWN_PARSER, + ].filter(Boolean) + throw new Error(messages.join("\n")) +} /** * Get the TypeScript parser services. - * If TypeScript isn't present, returns `null`. + * - Partial implementation from `@typescript-eslint/utils`. @see https://github.com/typescript-eslint/typescript-eslint/blob/3e545207f0e34611f528128fc699b25091bc40b3/packages/utils/src/eslint-utils/getParserServices.ts * - * @param {import('eslint').Rule.RuleContext} context - rule context - * @returns {import('@typescript-eslint/parser').ParserServices | null} + * @param {import('eslint').Rule.RuleContext} context - Rule context. + * @returns {import('@typescript-eslint/parser').ParserServices | null} Parser services if TypeScript is being used, `null` otherwise. + * @throws {Error} If parser services are present but incomplete. */ module.exports = function getParserServices(context) { - // Not using tseslint parser? + const parserServices = context.sourceCode.parserServices + if ( - context.sourceCode.parserServices?.esTreeNodeToTSNodeMap == null || - context.sourceCode.parserServices.tsNodeToESTreeNodeMap == null + !parserServices || + parserServices.esTreeNodeToTSNodeMap == null || + parserServices.tsNodeToESTreeNodeMap == null ) { + // Not using TypeScript parser, or no type info: return null for legacy/JS support. return null } - return getParserServicesFromTsEslint(/** @type {any} */ (context), true) + if (parserServices.program == null) { + const parser = + context.parserPath || context.languageOptions?.parser?.meta?.name + throwError(parser) + } + + return parserServices } diff --git a/package.json b/package.json index c66c318a..99257f00 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ }, "dependencies": { "@eslint-community/eslint-utils": "^4.5.0", - "@typescript-eslint/utils": "^8.26.1", "enhanced-resolve": "^5.17.1", "eslint-plugin-es-x": "^7.8.0", "get-tsconfig": "^4.8.1", @@ -122,4 +121,4 @@ "imports": { "#test-helpers": "./tests/test-helpers.js" } -} \ No newline at end of file +}