| "use strict"; |
| var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { |
| if (k2 === undefined) k2 = k; |
| Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); |
| }) : (function(o, m, k, k2) { |
| if (k2 === undefined) k2 = k; |
| o[k2] = m[k]; |
| })); |
| var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { |
| Object.defineProperty(o, "default", { enumerable: true, value: v }); |
| }) : function(o, v) { |
| o["default"] = v; |
| }); |
| var __importStar = (this && this.__importStar) || function (mod) { |
| if (mod && mod.__esModule) return mod; |
| var result = {}; |
| if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); |
| __setModuleDefault(result, mod); |
| return result; |
| }; |
| var __importDefault = (this && this.__importDefault) || function (mod) { |
| return (mod && mod.__esModule) ? mod : { "default": mod }; |
| }; |
| Object.defineProperty(exports, "__esModule", { value: true }); |
| exports.parseAndGenerateServices = exports.parse = void 0; |
| const debug_1 = __importDefault(require("debug")); |
| const globby_1 = require("globby"); |
| const is_glob_1 = __importDefault(require("is-glob")); |
| const semver_1 = __importDefault(require("semver")); |
| const ts = __importStar(require("typescript")); |
| const ast_converter_1 = require("./ast-converter"); |
| const convert_1 = require("./convert"); |
| const createDefaultProgram_1 = require("./create-program/createDefaultProgram"); |
| const createIsolatedProgram_1 = require("./create-program/createIsolatedProgram"); |
| const createProjectProgram_1 = require("./create-program/createProjectProgram"); |
| const createSourceFile_1 = require("./create-program/createSourceFile"); |
| const semantic_or_syntactic_errors_1 = require("./semantic-or-syntactic-errors"); |
| const shared_1 = require("./create-program/shared"); |
| const log = debug_1.default('typescript-eslint:typescript-estree:parser'); |
| /** |
| * This needs to be kept in sync with the top-level README.md in the |
| * typescript-eslint monorepo |
| */ |
| const SUPPORTED_TYPESCRIPT_VERSIONS = '>=3.3.1 <4.1.0'; |
| /* |
| * The semver package will ignore prerelease ranges, and we don't want to explicitly document every one |
| * List them all separately here, so we can automatically create the full string |
| */ |
| const SUPPORTED_PRERELEASE_RANGES = []; |
| const ACTIVE_TYPESCRIPT_VERSION = ts.version; |
| const isRunningSupportedTypeScriptVersion = semver_1.default.satisfies(ACTIVE_TYPESCRIPT_VERSION, [SUPPORTED_TYPESCRIPT_VERSIONS] |
| .concat(SUPPORTED_PRERELEASE_RANGES) |
| .join(' || ')); |
| let extra; |
| let warnedAboutTSVersion = false; |
| function enforceString(code) { |
| /** |
| * Ensure the source code is a string |
| */ |
| if (typeof code !== 'string') { |
| return String(code); |
| } |
| return code; |
| } |
| /** |
| * @param code The code of the file being linted |
| * @param shouldProvideParserServices True if the program should be attempted to be calculated from provided tsconfig files |
| * @param shouldCreateDefaultProgram True if the program should be created from compiler host |
| * @returns Returns a source file and program corresponding to the linted code |
| */ |
| function getProgramAndAST(code, shouldProvideParserServices, shouldCreateDefaultProgram) { |
| return ((shouldProvideParserServices && |
| createProjectProgram_1.createProjectProgram(code, shouldCreateDefaultProgram, extra)) || |
| (shouldProvideParserServices && |
| shouldCreateDefaultProgram && |
| createDefaultProgram_1.createDefaultProgram(code, extra)) || |
| createIsolatedProgram_1.createIsolatedProgram(code, extra)); |
| } |
| /** |
| * Compute the filename based on the parser options. |
| * |
| * Even if jsx option is set in typescript compiler, filename still has to |
| * contain .tsx file extension. |
| * |
| * @param options Parser options |
| */ |
| function getFileName({ jsx } = {}) { |
| return jsx ? 'estree.tsx' : 'estree.ts'; |
| } |
| /** |
| * Resets the extra config object |
| */ |
| function resetExtra() { |
| extra = { |
| code: '', |
| comment: false, |
| comments: [], |
| createDefaultProgram: false, |
| debugLevel: new Set(), |
| errorOnTypeScriptSyntacticAndSemanticIssues: false, |
| errorOnUnknownASTType: false, |
| extraFileExtensions: [], |
| filePath: getFileName(), |
| jsx: false, |
| loc: false, |
| log: console.log, |
| preserveNodeMaps: true, |
| projects: [], |
| range: false, |
| strict: false, |
| tokens: null, |
| tsconfigRootDir: process.cwd(), |
| useJSXTextNode: false, |
| }; |
| } |
| /** |
| * Normalizes, sanitizes, resolves and filters the provided |
| */ |
| function prepareAndTransformProjects(projectsInput, ignoreListInput) { |
| let projects = []; |
| // Normalize and sanitize the project paths |
| if (typeof projectsInput === 'string') { |
| projects.push(projectsInput); |
| } |
| else if (Array.isArray(projectsInput)) { |
| for (const project of projectsInput) { |
| if (typeof project === 'string') { |
| projects.push(project); |
| } |
| } |
| } |
| if (projects.length === 0) { |
| return projects; |
| } |
| // Transform glob patterns into paths |
| const globbedProjects = projects.filter(project => is_glob_1.default(project)); |
| projects = projects |
| .filter(project => !is_glob_1.default(project)) |
| .concat(globby_1.sync([...globbedProjects, ...ignoreListInput], { |
| cwd: extra.tsconfigRootDir, |
| })); |
| log('parserOptions.project (excluding ignored) matched projects: %s', projects); |
| return projects; |
| } |
| function applyParserOptionsToExtra(options) { |
| var _a; |
| /** |
| * Configure Debug logging |
| */ |
| if (options.debugLevel === true) { |
| extra.debugLevel = new Set(['typescript-eslint']); |
| } |
| else if (Array.isArray(options.debugLevel)) { |
| extra.debugLevel = new Set(options.debugLevel); |
| } |
| if (extra.debugLevel.size > 0) { |
| // debug doesn't support multiple `enable` calls, so have to do it all at once |
| const namespaces = []; |
| if (extra.debugLevel.has('typescript-eslint')) { |
| namespaces.push('typescript-eslint:*'); |
| } |
| if (extra.debugLevel.has('eslint') || |
| // make sure we don't turn off the eslint debug if it was enabled via --debug |
| debug_1.default.enabled('eslint:*')) { |
| // https://github.com/eslint/eslint/blob/9dfc8501fb1956c90dc11e6377b4cb38a6bea65d/bin/eslint.js#L25 |
| namespaces.push('eslint:*,-eslint:code-path'); |
| } |
| debug_1.default.enable(namespaces.join(',')); |
| } |
| /** |
| * Track range information in the AST |
| */ |
| extra.range = typeof options.range === 'boolean' && options.range; |
| extra.loc = typeof options.loc === 'boolean' && options.loc; |
| /** |
| * Track tokens in the AST |
| */ |
| if (typeof options.tokens === 'boolean' && options.tokens) { |
| extra.tokens = []; |
| } |
| /** |
| * Track comments in the AST |
| */ |
| if (typeof options.comment === 'boolean' && options.comment) { |
| extra.comment = true; |
| extra.comments = []; |
| } |
| /** |
| * Enable JSX - note the applicable file extension is still required |
| */ |
| if (typeof options.jsx === 'boolean' && options.jsx) { |
| extra.jsx = true; |
| } |
| /** |
| * Get the file path |
| */ |
| if (typeof options.filePath === 'string' && options.filePath !== '<input>') { |
| extra.filePath = options.filePath; |
| } |
| else { |
| extra.filePath = getFileName(extra); |
| } |
| /** |
| * The JSX AST changed the node type for string literals |
| * inside a JSX Element from `Literal` to `JSXText`. |
| * |
| * When value is `true`, these nodes will be parsed as type `JSXText`. |
| * When value is `false`, these nodes will be parsed as type `Literal`. |
| */ |
| if (typeof options.useJSXTextNode === 'boolean' && options.useJSXTextNode) { |
| extra.useJSXTextNode = true; |
| } |
| /** |
| * Allow the user to cause the parser to error if it encounters an unknown AST Node Type |
| * (used in testing) |
| */ |
| if (typeof options.errorOnUnknownASTType === 'boolean' && |
| options.errorOnUnknownASTType) { |
| extra.errorOnUnknownASTType = true; |
| } |
| /** |
| * Allow the user to override the function used for logging |
| */ |
| if (typeof options.loggerFn === 'function') { |
| extra.log = options.loggerFn; |
| } |
| else if (options.loggerFn === false) { |
| extra.log = () => { }; |
| } |
| if (typeof options.tsconfigRootDir === 'string') { |
| extra.tsconfigRootDir = options.tsconfigRootDir; |
| } |
| // NOTE - ensureAbsolutePath relies upon having the correct tsconfigRootDir in extra |
| extra.filePath = shared_1.ensureAbsolutePath(extra.filePath, extra); |
| // NOTE - prepareAndTransformProjects relies upon having the correct tsconfigRootDir in extra |
| const projectFolderIgnoreList = ((_a = options.projectFolderIgnoreList) !== null && _a !== void 0 ? _a : []) |
| .reduce((acc, folder) => { |
| if (typeof folder === 'string') { |
| acc.push(folder); |
| } |
| return acc; |
| }, []) |
| // prefix with a ! for not match glob |
| .map(folder => (folder.startsWith('!') ? folder : `!${folder}`)); |
| extra.projects = prepareAndTransformProjects(options.project, projectFolderIgnoreList); |
| if (Array.isArray(options.extraFileExtensions) && |
| options.extraFileExtensions.every(ext => typeof ext === 'string')) { |
| extra.extraFileExtensions = options.extraFileExtensions; |
| } |
| /** |
| * Allow the user to enable or disable the preservation of the AST node maps |
| * during the conversion process. |
| */ |
| if (typeof options.preserveNodeMaps === 'boolean') { |
| extra.preserveNodeMaps = options.preserveNodeMaps; |
| } |
| extra.createDefaultProgram = |
| typeof options.createDefaultProgram === 'boolean' && |
| options.createDefaultProgram; |
| } |
| function warnAboutTSVersion() { |
| var _a; |
| if (!isRunningSupportedTypeScriptVersion && !warnedAboutTSVersion) { |
| const isTTY = typeof process === undefined ? false : (_a = process.stdout) === null || _a === void 0 ? void 0 : _a.isTTY; |
| if (isTTY) { |
| const border = '============='; |
| const versionWarning = [ |
| border, |
| 'WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.', |
| 'You may find that it works just fine, or you may not.', |
| `SUPPORTED TYPESCRIPT VERSIONS: ${SUPPORTED_TYPESCRIPT_VERSIONS}`, |
| `YOUR TYPESCRIPT VERSION: ${ACTIVE_TYPESCRIPT_VERSION}`, |
| 'Please only submit bug reports when using the officially supported version.', |
| border, |
| ]; |
| extra.log(versionWarning.join('\n\n')); |
| } |
| warnedAboutTSVersion = true; |
| } |
| } |
| function parse(code, options) { |
| /** |
| * Reset the parse configuration |
| */ |
| resetExtra(); |
| /** |
| * Ensure users do not attempt to use parse() when they need parseAndGenerateServices() |
| */ |
| if (options === null || options === void 0 ? void 0 : options.errorOnTypeScriptSyntacticAndSemanticIssues) { |
| throw new Error(`"errorOnTypeScriptSyntacticAndSemanticIssues" is only supported for parseAndGenerateServices()`); |
| } |
| /** |
| * Ensure the source code is a string, and store a reference to it |
| */ |
| code = enforceString(code); |
| extra.code = code; |
| /** |
| * Apply the given parser options |
| */ |
| if (typeof options !== 'undefined') { |
| applyParserOptionsToExtra(options); |
| } |
| /** |
| * Warn if the user is using an unsupported version of TypeScript |
| */ |
| warnAboutTSVersion(); |
| /** |
| * Create a ts.SourceFile directly, no ts.Program is needed for a simple |
| * parse |
| */ |
| const ast = createSourceFile_1.createSourceFile(code, extra); |
| /** |
| * Convert the TypeScript AST to an ESTree-compatible one |
| */ |
| const { estree } = ast_converter_1.astConverter(ast, extra, false); |
| return estree; |
| } |
| exports.parse = parse; |
| function parseAndGenerateServices(code, options) { |
| /** |
| * Reset the parse configuration |
| */ |
| resetExtra(); |
| /** |
| * Ensure the source code is a string, and store a reference to it |
| */ |
| code = enforceString(code); |
| extra.code = code; |
| /** |
| * Apply the given parser options |
| */ |
| if (typeof options !== 'undefined') { |
| applyParserOptionsToExtra(options); |
| if (typeof options.errorOnTypeScriptSyntacticAndSemanticIssues === |
| 'boolean' && |
| options.errorOnTypeScriptSyntacticAndSemanticIssues) { |
| extra.errorOnTypeScriptSyntacticAndSemanticIssues = true; |
| } |
| } |
| /** |
| * Warn if the user is using an unsupported version of TypeScript |
| */ |
| warnAboutTSVersion(); |
| /** |
| * Generate a full ts.Program in order to be able to provide parser |
| * services, such as type-checking |
| */ |
| const shouldProvideParserServices = extra.projects && extra.projects.length > 0; |
| const { ast, program } = getProgramAndAST(code, shouldProvideParserServices, extra.createDefaultProgram); |
| /** |
| * Convert the TypeScript AST to an ESTree-compatible one, and optionally preserve |
| * mappings between converted and original AST nodes |
| */ |
| const preserveNodeMaps = typeof extra.preserveNodeMaps === 'boolean' ? extra.preserveNodeMaps : true; |
| const { estree, astMaps } = ast_converter_1.astConverter(ast, extra, preserveNodeMaps); |
| /** |
| * Even if TypeScript parsed the source code ok, and we had no problems converting the AST, |
| * there may be other syntactic or semantic issues in the code that we can optionally report on. |
| */ |
| if (program && extra.errorOnTypeScriptSyntacticAndSemanticIssues) { |
| const error = semantic_or_syntactic_errors_1.getFirstSemanticOrSyntacticError(program, ast); |
| if (error) { |
| throw convert_1.convertError(error); |
| } |
| } |
| /** |
| * Return the converted AST and additional parser services |
| */ |
| return { |
| ast: estree, |
| services: { |
| hasFullTypeInformation: shouldProvideParserServices, |
| program, |
| esTreeNodeToTSNodeMap: astMaps.esTreeNodeToTSNodeMap, |
| tsNodeToESTreeNodeMap: astMaps.tsNodeToESTreeNodeMap, |
| }, |
| }; |
| } |
| exports.parseAndGenerateServices = parseAndGenerateServices; |
| //# sourceMappingURL=parser.js.map |