From 6dfb11c56d84466f3f58759fa00f06118a545fe4 Mon Sep 17 00:00:00 2001 From: liuxingbaoyu <30521560+liuxingbaoyu@users.noreply.github.com> Date: Fri, 26 Jan 2024 00:16:24 +0800 Subject: [PATCH] Migrate `eslint-parser` to cts (#16222) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Nicolò Ribaudo --- Gulpfile.mjs | 7 +- babel.config.js | 4 + eslint.config.js | 2 +- eslint/babel-eslint-parser/package.json | 3 + .../{analyze-scope.cjs => analyze-scope.cts} | 82 ++++----- .../src/{client.cjs => client.cts} | 50 +++--- .../{configuration.cjs => configuration.cts} | 6 +- .../{convertAST.cjs => convertAST.cts} | 51 ++++-- .../src/convert/convertComments.cjs | 14 -- .../src/convert/convertComments.cts | 14 ++ .../{convertTokens.cjs => convertTokens.cts} | 107 ++++++----- .../babel-eslint-parser/src/convert/index.cjs | 18 -- .../babel-eslint-parser/src/convert/index.cts | 26 +++ ...tal-worker.cjs => experimental-worker.cts} | 15 +- .../src/{index.cjs => index.cts} | 19 +- .../src/{parse.cjs => parse.cts} | 14 +- eslint/babel-eslint-parser/src/types.d.cts | 168 ++++++++++++++++++ .../src/utils/eslint-version.cjs | 1 - .../src/utils/eslint-version.cts | 1 + .../src/worker/{ast-info.cjs => ast-info.cts} | 19 +- .../worker/{babel-core.cjs => babel-core.cts} | 6 +- .../{configuration.cjs => configuration.cts} | 34 ++-- .../worker/extract-parser-options-plugin.cjs | 7 - .../worker/extract-parser-options-plugin.cts | 7 + ...{handle-message.cjs => handle-message.cts} | 26 +-- .../babel-eslint-parser/src/worker/index.cjs | 28 --- .../babel-eslint-parser/src/worker/index.cts | 31 ++++ .../worker/{maybeParse.cjs => maybeParse.cts} | 30 +++- package.json | 4 +- packages/babel-core/src/config/index.ts | 1 + packages/babel-core/src/index.ts | 1 + .../src/tools/build-external-helpers.ts | 4 +- .../src/plugins/typescript/index.ts | 1 - packages/babel-template/src/index.ts | 5 + scripts/generators/tsconfig.js | 2 + tsconfig.base.json | 9 +- tsconfig.json | 1 + yarn.lock | 74 +++++--- 38 files changed, 599 insertions(+), 293 deletions(-) rename eslint/babel-eslint-parser/src/{analyze-scope.cjs => analyze-scope.cts} (84%) rename eslint/babel-eslint-parser/src/{client.cjs => client.cts} (76%) rename eslint/babel-eslint-parser/src/{configuration.cjs => configuration.cts} (78%) rename eslint/babel-eslint-parser/src/convert/{convertAST.cjs => convertAST.cts} (73%) delete mode 100644 eslint/babel-eslint-parser/src/convert/convertComments.cjs create mode 100644 eslint/babel-eslint-parser/src/convert/convertComments.cts rename eslint/babel-eslint-parser/src/convert/{convertTokens.cjs => convertTokens.cts} (70%) delete mode 100644 eslint/babel-eslint-parser/src/convert/index.cjs create mode 100644 eslint/babel-eslint-parser/src/convert/index.cts rename eslint/babel-eslint-parser/src/{experimental-worker.cjs => experimental-worker.cts} (67%) rename eslint/babel-eslint-parser/src/{index.cjs => index.cts} (51%) rename eslint/babel-eslint-parser/src/{parse.cjs => parse.cts} (74%) create mode 100644 eslint/babel-eslint-parser/src/types.d.cts delete mode 100644 eslint/babel-eslint-parser/src/utils/eslint-version.cjs create mode 100644 eslint/babel-eslint-parser/src/utils/eslint-version.cts rename eslint/babel-eslint-parser/src/worker/{ast-info.cjs => ast-info.cts} (76%) rename eslint/babel-eslint-parser/src/worker/{babel-core.cjs => babel-core.cts} (83%) rename eslint/babel-eslint-parser/src/worker/{configuration.cjs => configuration.cts} (76%) delete mode 100644 eslint/babel-eslint-parser/src/worker/extract-parser-options-plugin.cjs create mode 100644 eslint/babel-eslint-parser/src/worker/extract-parser-options-plugin.cts rename eslint/babel-eslint-parser/src/worker/{handle-message.cjs => handle-message.cts} (57%) delete mode 100644 eslint/babel-eslint-parser/src/worker/index.cjs create mode 100644 eslint/babel-eslint-parser/src/worker/index.cts rename eslint/babel-eslint-parser/src/worker/{maybeParse.cjs => maybeParse.cts} (53%) diff --git a/Gulpfile.mjs b/Gulpfile.mjs index c724bca9852f..a724de1a9d85 100644 --- a/Gulpfile.mjs +++ b/Gulpfile.mjs @@ -36,7 +36,7 @@ const { require, __dirname: monorepoRoot } = commonJS(import.meta.url); const defaultPackagesGlob = "./@(codemods|packages|eslint)/*"; const defaultSourcesGlob = [ - `${defaultPackagesGlob}/src/**/{*.js,*.cjs,!(*.d).ts}`, + `${defaultPackagesGlob}/src/**/{*.js,*.cjs,!(*.d).ts,!(*.d).cts}`, "!./packages/babel-helpers/src/helpers/*", ]; @@ -68,7 +68,10 @@ function bool(value) { * @returns {string} */ function mapSrcToLib(srcPath) { - const parts = srcPath.replace(/(? { return { ...config, - files: ["**/*.ts"], + files: ["**/*.{ts,cts}"], languageOptions: { parser: parserTypeScriptESLint, parserOptions: { diff --git a/eslint/babel-eslint-parser/package.json b/eslint/babel-eslint-parser/package.json index 0cbc1979731f..4f674a58cff0 100644 --- a/eslint/babel-eslint-parser/package.json +++ b/eslint/babel-eslint-parser/package.json @@ -38,6 +38,9 @@ }, "devDependencies": { "@babel/core": "workspace:^", + "@types/eslint": "^8.56.2", + "@types/estree": "^1.0.5", + "@typescript-eslint/scope-manager": "^6.19.0", "dedent": "^0.7.0", "eslint": "^8.22.0" }, diff --git a/eslint/babel-eslint-parser/src/analyze-scope.cjs b/eslint/babel-eslint-parser/src/analyze-scope.cts similarity index 84% rename from eslint/babel-eslint-parser/src/analyze-scope.cjs rename to eslint/babel-eslint-parser/src/analyze-scope.cts index ea8f7f31429c..fa2583cfaff4 100644 --- a/eslint/babel-eslint-parser/src/analyze-scope.cjs +++ b/eslint/babel-eslint-parser/src/analyze-scope.cts @@ -1,16 +1,20 @@ +import type { Client } from "./client.cts"; + const { Definition, PatternVisitor: OriginalPatternVisitor, Referencer: OriginalReferencer, Scope, ScopeManager, -} = process.env.BABEL_8_BREAKING - ? require("eslint-scope") - : require("@nicolo-ribaudo/eslint-scope-5-internals"); +} = ( + process.env.BABEL_8_BREAKING + ? require("eslint-scope") + : require("@nicolo-ribaudo/eslint-scope-5-internals") +) as import("./types.cts").Scope; const { getKeys: fallback } = require("eslint-visitor-keys"); -let visitorKeysMap; -function getVisitorValues(nodeType, client) { +let visitorKeysMap: Record; +function getVisitorValues(nodeType: string, client: Client) { if (visitorKeysMap) return visitorKeysMap[nodeType]; const { FLOW_FLIPPED_ALIAS_KEYS, VISITOR_KEYS } = client.getTypesInfo(); @@ -28,6 +32,7 @@ function getVisitorValues(nodeType, client) { visitorKeysMap = Object.entries(VISITOR_KEYS).reduce((acc, [key, value]) => { if (!flowFlippedAliasKeys.includes(value)) { + // @ts-expect-error FIXME: value is not assignable to type string[] acc[key] = value; } return acc; @@ -56,11 +61,11 @@ const propertyTypes = { }; class PatternVisitor extends OriginalPatternVisitor { - ArrayPattern(node) { + ArrayPattern(node: any) { node.elements.forEach(this.visit, this); } - ObjectPattern(node) { + ObjectPattern(node: any) { node.properties.forEach(this.visit, this); } } @@ -68,13 +73,13 @@ class PatternVisitor extends OriginalPatternVisitor { class Referencer extends OriginalReferencer { #client; - constructor(options, scopeManager, client) { + constructor(options: any, scopeManager: any, client: Client) { super(options, scopeManager); this.#client = client; } // inherits. - visitPattern(node, options, callback) { + visitPattern(node: any, options: any, callback: any) { if (!node) { return; } @@ -101,7 +106,7 @@ class Referencer extends OriginalReferencer { } // inherits. - visitClass(node) { + visitClass(node: any) { // Decorators. this._visitArray(node.decorators); @@ -110,9 +115,7 @@ class Referencer extends OriginalReferencer { // Flow super types. this._visitTypeAnnotation(node.implements); - this._visitTypeAnnotation( - node.superTypeParameters && node.superTypeParameters.params, - ); + this._visitTypeAnnotation(node.superTypeParameters?.params); // Basic. super.visitClass(node); @@ -124,7 +127,7 @@ class Referencer extends OriginalReferencer { } // inherits. - visitFunction(node) { + visitFunction(node: any) { const typeParamScope = this._nestTypeParamScope(node); // Flow return types. @@ -140,7 +143,7 @@ class Referencer extends OriginalReferencer { } // inherits. - visitProperty(node) { + visitProperty(node: any) { if (node.value?.type === "TypeCastExpression") { this._visitTypeAnnotation(node.value); } @@ -148,7 +151,7 @@ class Referencer extends OriginalReferencer { super.visitProperty(node); } - InterfaceDeclaration(node) { + InterfaceDeclaration(node: any) { this._createScopeVariable(node, node.id); const typeParamScope = this._nestTypeParamScope(node); @@ -162,7 +165,7 @@ class Referencer extends OriginalReferencer { } } - TypeAlias(node) { + TypeAlias(node: any) { this._createScopeVariable(node, node.id); const typeParamScope = this._nestTypeParamScope(node); @@ -174,45 +177,45 @@ class Referencer extends OriginalReferencer { } } - ClassProperty(node) { + ClassProperty(node: any) { this._visitClassProperty(node); } - ClassPrivateProperty(node) { + ClassPrivateProperty(node: any) { this._visitClassProperty(node); } - PropertyDefinition(node) { + PropertyDefinition(node: any) { this._visitClassProperty(node); } // TODO: Update to visit type annotations when TypeScript/Flow support this syntax. - ClassPrivateMethod(node) { + ClassPrivateMethod(node: any) { super.MethodDefinition(node); } - DeclareModule(node) { + DeclareModule(node: any) { this._visitDeclareX(node); } - DeclareFunction(node) { + DeclareFunction(node: any) { this._visitDeclareX(node); } - DeclareVariable(node) { + DeclareVariable(node: any) { this._visitDeclareX(node); } - DeclareClass(node) { + DeclareClass(node: any) { this._visitDeclareX(node); } // visit OptionalMemberExpression as a MemberExpression. - OptionalMemberExpression(node) { + OptionalMemberExpression(node: any) { super.MemberExpression(node); } - _visitClassProperty(node) { + _visitClassProperty(node: any) { const { computed, key, typeAnnotation, value } = node; if (computed) this.visit(key); @@ -239,7 +242,7 @@ class Referencer extends OriginalReferencer { } } - _visitDeclareX(node) { + _visitDeclareX(node: any) { if (node.id) { this._createScopeVariable(node, node.id); } @@ -250,14 +253,14 @@ class Referencer extends OriginalReferencer { } } - _createScopeVariable(node, name) { + _createScopeVariable(node: any, name: any) { this.currentScope().variableScope.__define( name, new Definition("Variable", name, node, null, null, null), ); } - _nestTypeParamScope(node) { + _nestTypeParamScope(node: any) { if (!node.typeParameters) { return null; } @@ -279,14 +282,12 @@ class Referencer extends OriginalReferencer { this._checkIdentifierOrVisit(name); } } - scope.__define = function () { - return parentScope.__define.apply(parentScope, arguments); - }; + scope.__define = parentScope.__define.bind(parentScope); return scope; } - _visitTypeAnnotation(node) { + _visitTypeAnnotation(node: any) { if (!node) { return; } @@ -304,7 +305,7 @@ class Referencer extends OriginalReferencer { // can have multiple properties for (let i = 0; i < visitorValues.length; i++) { const visitorValue = visitorValues[i]; - const propertyType = propertyTypes[visitorValue]; + const propertyType = (propertyTypes as Record)[visitorValue]; const nodeProperty = node[visitorValue]; // check if property or type is defined if (propertyType == null || nodeProperty == null) { @@ -341,7 +342,7 @@ class Referencer extends OriginalReferencer { } } - _checkIdentifierOrVisit(node) { + _checkIdentifierOrVisit(node: any) { if (node?.typeAnnotation) { this._visitTypeAnnotation(node.typeAnnotation); } else if (node?.type === "Identifier") { @@ -351,7 +352,7 @@ class Referencer extends OriginalReferencer { } } - _visitArray(nodeList) { + _visitArray(nodeList: any[]) { if (nodeList) { for (const node of nodeList) { this.visit(node); @@ -360,7 +361,7 @@ class Referencer extends OriginalReferencer { } } -module.exports = function analyzeScope(ast, parserOptions, client) { +export = function analyzeScope(ast: any, parserOptions: any, client: Client) { const options = { ignoreEval: true, optimistic: false, @@ -372,14 +373,13 @@ module.exports = function analyzeScope(ast, parserOptions, client) { sourceType: ast.sourceType, ecmaVersion: parserOptions.ecmaVersion, fallback, + childVisitorKeys: client.getVisitorKeys(), }; - options.childVisitorKeys = client.getVisitorKeys(); - const scopeManager = new ScopeManager(options); const referencer = new Referencer(options, scopeManager, client); referencer.visit(ast); - return scopeManager; + return scopeManager as any; }; diff --git a/eslint/babel-eslint-parser/src/client.cjs b/eslint/babel-eslint-parser/src/client.cts similarity index 76% rename from eslint/babel-eslint-parser/src/client.cjs rename to eslint/babel-eslint-parser/src/client.cts index 40d491af1ee0..1d2cbffe9715 100644 --- a/eslint/babel-eslint-parser/src/client.cjs +++ b/eslint/babel-eslint-parser/src/client.cts @@ -1,42 +1,44 @@ -const path = require("path"); - -const ACTIONS = { - GET_VERSION: "GET_VERSION", - GET_TYPES_INFO: "GET_TYPES_INFO", - GET_VISITOR_KEYS: "GET_VISITOR_KEYS", - GET_TOKEN_LABELS: "GET_TOKEN_LABELS", - MAYBE_PARSE: "MAYBE_PARSE", - MAYBE_PARSE_SYNC: "MAYBE_PARSE_SYNC", -}; - -class Client { +import type { Options } from "./types.cts"; + +import path = require("path"); + +export const enum ACTIONS { + GET_VERSION = "GET_VERSION", + GET_TYPES_INFO = "GET_TYPES_INFO", + GET_VISITOR_KEYS = "GET_VISITOR_KEYS", + GET_TOKEN_LABELS = "GET_TOKEN_LABELS", + MAYBE_PARSE = "MAYBE_PARSE", + MAYBE_PARSE_SYNC = "MAYBE_PARSE_SYNC", +} + +export class Client { #send; - constructor(send) { + constructor(send: Function) { this.#send = send; } - #vCache; + #vCache: string; getVersion() { return (this.#vCache ??= this.#send(ACTIONS.GET_VERSION, undefined)); } - #tiCache; + #tiCache: any; getTypesInfo() { return (this.#tiCache ??= this.#send(ACTIONS.GET_TYPES_INFO, undefined)); } - #vkCache; + #vkCache: any; getVisitorKeys() { return (this.#vkCache ??= this.#send(ACTIONS.GET_VISITOR_KEYS, undefined)); } - #tlCache; + #tlCache: any; getTokLabels() { return (this.#tlCache ??= this.#send(ACTIONS.GET_TOKEN_LABELS, undefined)); } - maybeParse(code, options) { + maybeParse(code: string, options: Options) { return this.#send(ACTIONS.MAYBE_PARSE, { code, options }); } } @@ -49,8 +51,8 @@ class Client { // can be asynchronous // If ESLint starts supporting async parsers, we can move // everything back to the main thread. -exports.WorkerClient = class WorkerClient extends Client { - static #worker_threads_cache; +export class WorkerClient extends Client { + static #worker_threads_cache: typeof import("worker_threads"); static get #worker_threads() { return (WorkerClient.#worker_threads_cache ??= require("worker_threads")); } @@ -61,7 +63,7 @@ exports.WorkerClient = class WorkerClient extends Client { ); constructor() { - super((action, payload) => { + super((action: ACTIONS, payload: any) => { // We create a new SharedArrayBuffer every time rather than reusing // the same one, otherwise sometimes its contents get corrupted and // Atomics.wait wakes up too early. @@ -88,16 +90,16 @@ exports.WorkerClient = class WorkerClient extends Client { // the main process alive. this.#worker.unref(); } -}; +} if (!USE_ESM) { exports.LocalClient = class LocalClient extends Client { - static #handleMessage; + static #handleMessage: Function; constructor() { LocalClient.#handleMessage ??= require("./worker/handle-message.cjs"); - super((action, payload) => { + super((action: ACTIONS, payload: any) => { return LocalClient.#handleMessage( action === ACTIONS.MAYBE_PARSE ? ACTIONS.MAYBE_PARSE_SYNC : action, payload, diff --git a/eslint/babel-eslint-parser/src/configuration.cjs b/eslint/babel-eslint-parser/src/configuration.cts similarity index 78% rename from eslint/babel-eslint-parser/src/configuration.cjs rename to eslint/babel-eslint-parser/src/configuration.cts index f273bc1db067..c4d3e7f2a657 100644 --- a/eslint/babel-eslint-parser/src/configuration.cjs +++ b/eslint/babel-eslint-parser/src/configuration.cts @@ -1,4 +1,6 @@ -exports.normalizeESLintConfig = function (options) { +import type { Options } from "./types.cts"; + +export = function normalizeESLintConfig(options: any) { const { babelOptions = {}, // ESLint sets ecmaVersion: undefined when ecmaVersion is not set in the config. @@ -14,5 +16,5 @@ exports.normalizeESLintConfig = function (options) { sourceType, requireConfigFile, ...otherOptions, - }; + } as Options; }; diff --git a/eslint/babel-eslint-parser/src/convert/convertAST.cjs b/eslint/babel-eslint-parser/src/convert/convertAST.cts similarity index 73% rename from eslint/babel-eslint-parser/src/convert/convertAST.cjs rename to eslint/babel-eslint-parser/src/convert/convertAST.cts index 1bc12d077e1d..c79c8a0db695 100644 --- a/eslint/babel-eslint-parser/src/convert/convertAST.cjs +++ b/eslint/babel-eslint-parser/src/convert/convertAST.cts @@ -1,18 +1,26 @@ -const ESLINT_VERSION = require("../utils/eslint-version.cjs"); +import type * as t from "@babel/types"; +import ESLINT_VERSION = require("../utils/eslint-version.cts"); +import type { ParseResult } from "../types.d.cts"; -function* it(children) { +function* it(children: T | T[]) { if (Array.isArray(children)) yield* children; else yield children; } -function traverse(node, visitorKeys, visitor) { +function traverse( + node: t.Node, + visitorKeys: Record, + visitor: typeof convertNodesVisitor, +) { const { type } = node; if (!type) return; const keys = visitorKeys[type]; if (!keys) return; for (const key of keys) { - for (const child of it(node[key])) { + for (const child of it( + node[key as keyof t.Node] as unknown as t.Node | t.Node[], + )) { if (child && typeof child === "object") { visitor.enter(child); traverse(child, visitorKeys, visitor); @@ -23,7 +31,7 @@ function traverse(node, visitorKeys, visitor) { } const convertNodesVisitor = { - enter(node) { + enter(node: t.Node) { if (node.innerComments) { delete node.innerComments; } @@ -36,7 +44,7 @@ const convertNodesVisitor = { delete node.leadingComments; } }, - exit(node) { + exit(node: t.Node) { // Used internally by @babel/parser. if (node.extra) { delete node.extra; @@ -47,7 +55,9 @@ const convertNodesVisitor = { } if (node.type === "TypeParameter") { + // @ts-expect-error eslint node.type = "Identifier"; + // @ts-expect-error eslint node.typeAnnotation = node.bound; delete node.bound; } @@ -72,6 +82,7 @@ const convertNodesVisitor = { // modules if (node.type === "ImportDeclaration") { + // @ts-expect-error legacy? delete node.isType; } @@ -105,14 +116,17 @@ const convertNodesVisitor = { }, }; -function convertNodes(ast, visitorKeys) { - traverse(ast, visitorKeys, convertNodesVisitor); +function convertNodes(ast: ParseResult, visitorKeys: Record) { + traverse(ast as unknown as t.Program, visitorKeys, convertNodesVisitor); } -function convertProgramNode(ast) { - ast.type = "Program"; - ast.sourceType = ast.program.sourceType; - ast.body = ast.program.body; +function convertProgramNode(ast: ParseResult) { + const body = ast.program.body; + Object.assign(ast, { + type: "Program", + sourceType: ast.program.sourceType, + body, + }); delete ast.program; delete ast.errors; @@ -141,17 +155,20 @@ function convertProgramNode(ast) { } } - if (ast.body && ast.body.length > 0) { - ast.loc.start.line = ast.body[0].loc.start.line; - ast.range[0] = ast.body[0].start; + if (body?.length) { + ast.loc.start.line = body[0].loc.start.line; + ast.range[0] = body[0].start; if (ESLINT_VERSION >= 8) { - ast.start = ast.body[0].start; + ast.start = body[0].start; } } } -module.exports = function convertAST(ast, visitorKeys) { +export = function convertAST( + ast: ParseResult, + visitorKeys: Record, +) { convertNodes(ast, visitorKeys); convertProgramNode(ast); }; diff --git a/eslint/babel-eslint-parser/src/convert/convertComments.cjs b/eslint/babel-eslint-parser/src/convert/convertComments.cjs deleted file mode 100644 index bcdda9170572..000000000000 --- a/eslint/babel-eslint-parser/src/convert/convertComments.cjs +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = function convertComments(comments) { - for (const comment of comments) { - if (comment.type === "CommentBlock") { - comment.type = "Block"; - } else if (comment.type === "CommentLine") { - comment.type = "Line"; - } - // sometimes comments don't get ranges computed, - // even with options.ranges === true - if (!comment.range) { - comment.range = [comment.start, comment.end]; - } - } -}; diff --git a/eslint/babel-eslint-parser/src/convert/convertComments.cts b/eslint/babel-eslint-parser/src/convert/convertComments.cts new file mode 100644 index 000000000000..9017fb571322 --- /dev/null +++ b/eslint/babel-eslint-parser/src/convert/convertComments.cts @@ -0,0 +1,14 @@ +import type { Comment } from "@babel/types"; + +export = function convertComments(comments: Comment[]) { + for (const comment of comments) { + // @ts-expect-error eslint + comment.type = comment.type === "CommentBlock" ? "Block" : "Line"; + + // sometimes comments don't get ranges computed, + // even with options.ranges === true + + // @ts-expect-error eslint + comment.range ||= [comment.start, comment.end]; + } +}; diff --git a/eslint/babel-eslint-parser/src/convert/convertTokens.cjs b/eslint/babel-eslint-parser/src/convert/convertTokens.cts similarity index 70% rename from eslint/babel-eslint-parser/src/convert/convertTokens.cjs rename to eslint/babel-eslint-parser/src/convert/convertTokens.cts index 39bdd2f6ee25..2ae7e81fba4f 100644 --- a/eslint/babel-eslint-parser/src/convert/convertTokens.cjs +++ b/eslint/babel-eslint-parser/src/convert/convertTokens.cts @@ -1,9 +1,10 @@ -const ESLINT_VERSION = require("../utils/eslint-version.cjs"); +import type { BabelToken } from "../types.cts"; +import ESLINT_VERSION = require("../utils/eslint-version.cjs"); -function convertTemplateType(tokens, tl) { - let curlyBrace = null; - let templateTokens = []; - const result = []; +function convertTemplateType(tokens: BabelToken[], tl: Record) { + let curlyBrace: BabelToken = null; + let templateTokens: BabelToken[] = []; + const result: any[] = []; function addTemplateType() { const start = templateTokens[0]; @@ -84,16 +85,30 @@ function convertTemplateType(tokens, tl) { return result; } -function convertToken(token, source, tl) { +function convertToken( + token: BabelToken, + source: string, + tl: Record, +) { const { type } = token; const { label } = type; - token.range = [token.start, token.end]; + + const newToken: { + type: string; + range?: [number, number]; + value?: string; + regex?: { + pattern: string; + flags: string; + }; + } = token as any; + newToken.range = [token.start, token.end]; if (label === tl.name) { if (token.value === "static") { - token.type = "Keyword"; + newToken.type = "Keyword"; } else { - token.type = "Identifier"; + newToken.type = "Identifier"; } } else if ( label === tl.semi || @@ -144,58 +159,62 @@ function convertToken(token, source, tl) { label === tl.doubleAt || type.isAssign ) { - token.type = "Punctuator"; - token.value ??= label; + newToken.type = "Punctuator"; + newToken.value ??= label; } else if (label === tl.jsxTagStart) { - token.type = "Punctuator"; - token.value = "<"; + newToken.type = "Punctuator"; + newToken.value = "<"; } else if (label === tl.jsxTagEnd) { - token.type = "Punctuator"; - token.value = ">"; + newToken.type = "Punctuator"; + newToken.value = ">"; } else if (label === tl.jsxName) { - token.type = "JSXIdentifier"; + newToken.type = "JSXIdentifier"; } else if (label === tl.jsxText) { - token.type = "JSXText"; + newToken.type = "JSXText"; } else if (type.keyword === "null") { - token.type = "Null"; + newToken.type = "Null"; } else if (type.keyword === "false" || type.keyword === "true") { - token.type = "Boolean"; + newToken.type = "Boolean"; } else if (type.keyword) { - token.type = "Keyword"; + newToken.type = "Keyword"; } else if (label === tl.num) { - token.type = "Numeric"; - token.value = source.slice(token.start, token.end); + newToken.type = "Numeric"; + newToken.value = source.slice(token.start, token.end); } else if (label === tl.string) { - token.type = "String"; - token.value = source.slice(token.start, token.end); + newToken.type = "String"; + newToken.value = source.slice(token.start, token.end); } else if (label === tl.regexp) { - token.type = "RegularExpression"; + newToken.type = "RegularExpression"; const value = token.value; - token.regex = { + newToken.regex = { pattern: value.pattern, flags: value.flags, }; - token.value = `/${value.pattern}/${value.flags}`; + newToken.value = `/${value.pattern}/${value.flags}`; } else if (label === tl.bigint) { - token.type = "Numeric"; - token.value = `${token.value}n`; + newToken.type = "Numeric"; + newToken.value = `${token.value}n`; } else if (label === tl.privateName) { - token.type = "PrivateIdentifier"; - } else if (label === tl.templateNonTail || label === tl.templateTail) { - token.type = "Template"; - } - - if (typeof token.type !== "string") { - // Acorn does not have rightAssociative - delete token.type.rightAssociative; + newToken.type = "PrivateIdentifier"; + } else if ( + label === tl.templateNonTail || + label === tl.templateTail || + label === tl.Template + ) { + newToken.type = "Template"; } + return newToken; } -module.exports = function convertTokens(tokens, code, tl) { +export = function convertTokens( + tokens: BabelToken[], + code: string, + tokLabels: Record, +) { const result = []; const templateTypeMergedTokens = process.env.BABEL_8_BREAKING ? tokens - : convertTemplateType(tokens, tl); + : convertTemplateType(tokens, tokLabels); // The last token is always tt.eof and should be skipped for (let i = 0, { length } = templateTypeMergedTokens; i < length - 1; i++) { const token = templateTypeMergedTokens[i]; @@ -210,12 +229,15 @@ module.exports = function convertTokens(tokens, code, tl) { if ( ESLINT_VERSION >= 8 && i + 1 < length && - tokenType.label === tl.hash + tokenType.label === tokLabels.hash ) { const nextToken = templateTypeMergedTokens[i + 1]; // We must disambiguate private identifier from the hack pipes topic token - if (nextToken.type.label === tl.name && token.end === nextToken.start) { + if ( + nextToken.type.label === tokLabels.name && + token.end === nextToken.start + ) { i++; nextToken.type = "PrivateIdentifier"; @@ -229,8 +251,7 @@ module.exports = function convertTokens(tokens, code, tl) { } } - convertToken(token, code, tl); - result.push(token); + result.push(convertToken(token, code, tokLabels)); } return result; diff --git a/eslint/babel-eslint-parser/src/convert/index.cjs b/eslint/babel-eslint-parser/src/convert/index.cjs deleted file mode 100644 index 1d5cec94b031..000000000000 --- a/eslint/babel-eslint-parser/src/convert/index.cjs +++ /dev/null @@ -1,18 +0,0 @@ -const convertTokens = require("./convertTokens.cjs"); -const convertComments = require("./convertComments.cjs"); -const convertAST = require("./convertAST.cjs"); - -exports.ast = function convert(ast, code, tokLabels, visitorKeys) { - ast.tokens = convertTokens(ast.tokens, code, tokLabels); - convertComments(ast.comments); - convertAST(ast, visitorKeys); - return ast; -}; - -exports.error = function convertError(err) { - if (err instanceof SyntaxError) { - err.lineNumber = err.loc.line; - err.column = err.loc.column; - } - return err; -}; diff --git a/eslint/babel-eslint-parser/src/convert/index.cts b/eslint/babel-eslint-parser/src/convert/index.cts new file mode 100644 index 000000000000..b7e02abcd4d3 --- /dev/null +++ b/eslint/babel-eslint-parser/src/convert/index.cts @@ -0,0 +1,26 @@ +import convertTokens = require("./convertTokens.cts"); +import convertComments = require("./convertComments.cts"); +import convertAST = require("./convertAST.cts"); +import type { AST, ParseResult } from "../types.cts"; + +export function convertFile( + ast: ParseResult, + code: string, + tokLabels: Record, + visitorKeys: Record, +) { + ast.tokens = convertTokens(ast.tokens as any, code, tokLabels); + convertComments(ast.comments); + convertAST(ast, visitorKeys); + return ast as unknown as AST.Program; +} + +export function convertError(err: Error) { + if (err instanceof SyntaxError) { + // @ts-expect-error eslint + err.lineNumber = err.loc.line; + // @ts-expect-error eslint + err.column = err.loc.column; + } + return err; +} diff --git a/eslint/babel-eslint-parser/src/experimental-worker.cjs b/eslint/babel-eslint-parser/src/experimental-worker.cts similarity index 67% rename from eslint/babel-eslint-parser/src/experimental-worker.cjs rename to eslint/babel-eslint-parser/src/experimental-worker.cts index 92904a9eeb98..0f1815810b00 100644 --- a/eslint/babel-eslint-parser/src/experimental-worker.cjs +++ b/eslint/babel-eslint-parser/src/experimental-worker.cts @@ -6,22 +6,23 @@ if (major < 12 || (major === 12 && minor < 3)) { ); } -const { normalizeESLintConfig } = require("./configuration.cjs"); -const analyzeScope = require("./analyze-scope.cjs"); -const baseParse = require("./parse.cjs"); +import normalizeESLintConfig = require("./configuration.cts"); +import analyzeScope = require("./analyze-scope.cts"); +import baseParse = require("./parse.cts"); + +import { WorkerClient } from "./client.cts"; -const { WorkerClient } = require("./client.cjs"); const client = new WorkerClient(); -exports.meta = { +export const meta = { name: "@babel/eslint-parser/experimental-worker", version: PACKAGE_JSON.version, }; -exports.parseForESLint = function (code, options = {}) { +export function parseForESLint(code: string, options = {}) { const normalizedOptions = normalizeESLintConfig(options); const ast = baseParse(code, normalizedOptions, client); const scopeManager = analyzeScope(ast, normalizedOptions, client); return { ast, scopeManager, visitorKeys: client.getVisitorKeys() }; -}; +} diff --git a/eslint/babel-eslint-parser/src/index.cjs b/eslint/babel-eslint-parser/src/index.cts similarity index 51% rename from eslint/babel-eslint-parser/src/index.cjs rename to eslint/babel-eslint-parser/src/index.cts index aa8d6bef6f2b..b6eb96c20a10 100644 --- a/eslint/babel-eslint-parser/src/index.cjs +++ b/eslint/babel-eslint-parser/src/index.cts @@ -1,23 +1,24 @@ -const { normalizeESLintConfig } = require("./configuration.cjs"); -const analyzeScope = require("./analyze-scope.cjs"); -const baseParse = require("./parse.cjs"); +import normalizeESLintConfig = require("./configuration.cts"); +import analyzeScope = require("./analyze-scope.cts"); +import baseParse = require("./parse.cts"); -const { LocalClient, WorkerClient } = require("./client.cjs"); +// @ts-expect-error LocalClient only exists in the cjs build +import { LocalClient, WorkerClient } from "./client.cts"; const client = new (USE_ESM ? WorkerClient : LocalClient)(); -exports.meta = { +export const meta = { name: PACKAGE_JSON.name, version: PACKAGE_JSON.version, }; -exports.parse = function (code, options = {}) { +export function parse(code: string, options = {}) { return baseParse(code, normalizeESLintConfig(options), client); -}; +} -exports.parseForESLint = function (code, options = {}) { +export function parseForESLint(code: string, options = {}) { const normalizedOptions = normalizeESLintConfig(options); const ast = baseParse(code, normalizedOptions, client); const scopeManager = analyzeScope(ast, normalizedOptions, client); return { ast, scopeManager, visitorKeys: client.getVisitorKeys() }; -}; +} diff --git a/eslint/babel-eslint-parser/src/parse.cjs b/eslint/babel-eslint-parser/src/parse.cts similarity index 74% rename from eslint/babel-eslint-parser/src/parse.cjs rename to eslint/babel-eslint-parser/src/parse.cts index dd2f29354e7c..7c4704bb9111 100644 --- a/eslint/babel-eslint-parser/src/parse.cjs +++ b/eslint/babel-eslint-parser/src/parse.cts @@ -1,7 +1,9 @@ "use strict"; -const semver = require("semver"); -const convert = require("./convert/index.cjs"); +import semver = require("semver"); +import convert = require("./convert/index.cts"); +import type { Options } from "./types.cts"; +import type { Client } from "./client.cts"; const babelParser = require( require.resolve("@babel/parser", { @@ -9,9 +11,9 @@ const babelParser = require( }), ); -let isRunningMinSupportedCoreVersion = null; +let isRunningMinSupportedCoreVersion: boolean = null; -module.exports = function parse(code, options, client) { +export = function parse(code: string, options: Options, client: Client) { // Ensure we're using a version of `@babel/core` that includes `parse()` and `tokTypes`. const minSupportedCoreVersion = process.env.BABEL_8_BREAKING && process.env.IS_PUBLISH @@ -38,13 +40,13 @@ module.exports = function parse(code, options, client) { if (ast) return ast; try { - return convert.ast( + return convert.convertFile( babelParser.parse(code, parserOptions), code, client.getTokLabels(), client.getVisitorKeys(), ); } catch (err) { - throw convert.error(err); + throw convert.convertError(err); } }; diff --git a/eslint/babel-eslint-parser/src/types.d.cts b/eslint/babel-eslint-parser/src/types.d.cts new file mode 100644 index 000000000000..1e2f32eb57ba --- /dev/null +++ b/eslint/babel-eslint-parser/src/types.d.cts @@ -0,0 +1,168 @@ +import type { Linter } from "eslint"; +import type { InputOptions } from "@babel/core"; +import type { Token as tokenizerToken } from "../../../packages/babel-parser/src/tokenizer"; +import type { ExportedTokenType } from "../../../packages/babel-parser/src/tokenizer/types"; +import type * as estree from "estree"; +// eslint-disable-next-line @typescript-eslint/consistent-type-imports +import type { + PatternVisitor, + Reference, + ScopeManager, + Variable, + Visitor, +} from "@typescript-eslint/scope-manager"; + +export type Options = Linter.ParserOptions & { babelOptions: InputOptions }; +export type BabelToken = tokenizerToken & { + type: ExportedTokenType; +}; +export type { ParseResult } from "../../../packages/babel-core/src/parser"; +export type { AST } from "eslint"; + +declare class ScopeDefinition { + constructor( + type: string, + name: estree.Identifier, + node: estree.Node, + parent?: estree.Node, + index?: number, + kind?: string, + ); + type: string; + name: estree.Identifier; + node: estree.Node; + parent?: estree.Node; + index?: number; + kind?: string; +} + +declare enum ReferenceFlag { + Read = 1, + Write = 2, + ReadWrite = 3, +} +interface ReferenceImplicitGlobal { + node: estree.Node; + pattern: estree.Identifier; + ref?: Reference; +} + +declare class ESLintScope { + declare type: string; + declare set: Map; + declare taints: Map; + declare dynamic: boolean; + declare block: estree.Node; + declare through: Reference[]; + declare variables: Variable[]; + declare references: Reference[]; + declare variableScope: ESLintScope; + declare functionExpressionScope: boolean; + declare directCallToEvalScope: boolean; + declare thisFound: boolean; + declare upper: ESLintScope; + declare isStrict: boolean; + declare childScopes: ESLintScope[]; + declare __declaredVariables: Map; + declare __left: Reference[]; + constructor( + scopeManager: ScopeManager, + type: string, + upperScope: ESLintScope, + block: estree.Node, + isMethodDefinition: boolean, + ); + + __shouldStaticallyClose(scopeManager: ScopeManager): boolean; + + __shouldStaticallyCloseForGlobal(ref: Reference): boolean; + + __staticCloseRef(ref: Reference): void; + + __dynamicCloseRef(ref: Reference): void; + + __globalCloseRef(ref: Reference): void; + + __close(scopeManager: ScopeManager): void; + + __isValidResolution(ref: Reference, variable: Variable): boolean; + + __resolve(ref: Reference): boolean; + + __delegateToUpperScope(ref: Reference): void; + + __addDeclaredVariablesOfNode(variable: Variable, node: estree.Node): void; + + __defineGeneric( + name: string, + set: Map, + variables: Variable[], + node: estree.Node, + def: ScopeDefinition, + ): void; + + __define(node: estree.Node, def: ScopeDefinition): void; + + __referencing( + node: estree.Node, + assign: ReferenceFlag.Write, + writeExpr: estree.Node | null, + maybeImplicitGlobal: ReferenceImplicitGlobal, + partial: any, + init: any, + ): void; + + __detectEval(): void; + + __detectThis(): void; + + __isClosed(): boolean; + + resolve(ident: estree.Identifier): Reference | null; + + isStatic(): boolean; + + isArgumentsMaterialized(): boolean; + + isThisMaterialized(): boolean; + + isUsedName(name: any): boolean; +} + +declare class Referencer extends Visitor { + readonly scopeManager: ScopeManager & { + __currentScope: ESLintScope; + __nestScope(scope: ESLintScope): ESLintScope; + __nestClassFieldInitializerScope?(scope: ESLintScope): ESLintScope; + }; + options: any; + + constructor(options: any, scopeManager: ScopeManager); + + currentScope(): ESLintScope; + currentScope(throwOnNull: true): ESLintScope | null; + close(node: estree.Node): void; + referencingDefaultValue( + pattern: estree.Identifier, + assignments: (estree.AssignmentExpression | estree.AssignmentPattern)[], + maybeImplicitGlobal: ReferenceImplicitGlobal | null, + init: boolean, + ): void; + + visitProperty(node: estree.Property): void; + visitClass(node: estree.ClassDeclaration | estree.ClassExpression): void; + visitFunction( + node: estree.FunctionDeclaration | estree.FunctionExpression, + ): void; + + MethodDefinition(node: estree.MethodDefinition): void; + MemberExpression(node: estree.MemberExpression): void; +} + +export type Scope = { + Definition: typeof ScopeDefinition; + PatternVisitor: typeof PatternVisitor; + Referencer: typeof Referencer; + Scope: typeof ESLintScope; + ScopeManager: typeof ScopeManager; +}; diff --git a/eslint/babel-eslint-parser/src/utils/eslint-version.cjs b/eslint/babel-eslint-parser/src/utils/eslint-version.cjs deleted file mode 100644 index 2afb5fc97550..000000000000 --- a/eslint/babel-eslint-parser/src/utils/eslint-version.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = parseInt(require("eslint/package.json").version, 10); diff --git a/eslint/babel-eslint-parser/src/utils/eslint-version.cts b/eslint/babel-eslint-parser/src/utils/eslint-version.cts new file mode 100644 index 000000000000..5e6419bea2a8 --- /dev/null +++ b/eslint/babel-eslint-parser/src/utils/eslint-version.cts @@ -0,0 +1 @@ +export = parseInt(require("eslint/package.json").version, 10); diff --git a/eslint/babel-eslint-parser/src/worker/ast-info.cjs b/eslint/babel-eslint-parser/src/worker/ast-info.cts similarity index 76% rename from eslint/babel-eslint-parser/src/worker/ast-info.cjs rename to eslint/babel-eslint-parser/src/worker/ast-info.cts index 5bd553854c7f..1bebeec25d69 100644 --- a/eslint/babel-eslint-parser/src/worker/ast-info.cjs +++ b/eslint/babel-eslint-parser/src/worker/ast-info.cts @@ -1,8 +1,11 @@ -const ESLINT_VISITOR_KEYS = require("eslint-visitor-keys").KEYS; -const babel = require("./babel-core.cjs"); +// @ts-expect-error no types +import _ESLINT_VISITOR_KEYS = require("eslint-visitor-keys"); +import babel = require("./babel-core.cts"); -let visitorKeys; -exports.getVisitorKeys = function getVisitorKeys() { +const ESLINT_VISITOR_KEYS = _ESLINT_VISITOR_KEYS.KEYS; + +let visitorKeys: Record; +export function getVisitorKeys() { if (!visitorKeys) { // AST Types that are not presented in Babel AST const newTypes = { @@ -34,13 +37,13 @@ exports.getVisitorKeys = function getVisitorKeys() { }; } return visitorKeys; -}; +} let tokLabels; -exports.getTokLabels = function getTokLabels() { +export function getTokLabels() { return (tokLabels ||= ( process.env.BABEL_8_BREAKING ? Object.fromEntries - : p => p.reduce((o, [k, v]) => ({ ...o, [k]: v }), {}) + : (p: any[]) => p.reduce((o, [k, v]) => ({ ...o, [k]: v }), {}) )(Object.entries(babel.tokTypes).map(([key, tok]) => [key, tok.label]))); -}; +} diff --git a/eslint/babel-eslint-parser/src/worker/babel-core.cjs b/eslint/babel-eslint-parser/src/worker/babel-core.cts similarity index 83% rename from eslint/babel-eslint-parser/src/worker/babel-core.cjs rename to eslint/babel-eslint-parser/src/worker/babel-core.cts index e04d658027c8..4ab88cb95376 100644 --- a/eslint/babel-eslint-parser/src/worker/babel-core.cjs +++ b/eslint/babel-eslint-parser/src/worker/babel-core.cts @@ -1,4 +1,8 @@ -function initialize(babel) { +export = exports as typeof import("@babel/core") & { + init: Promise | null; +}; + +function initialize(babel: typeof import("@babel/core")) { exports.init = null; exports.version = babel.version; exports.traverse = babel.traverse; diff --git a/eslint/babel-eslint-parser/src/worker/configuration.cjs b/eslint/babel-eslint-parser/src/worker/configuration.cts similarity index 76% rename from eslint/babel-eslint-parser/src/worker/configuration.cjs rename to eslint/babel-eslint-parser/src/worker/configuration.cts index 0908a8e03074..9f6bbdbd565a 100644 --- a/eslint/babel-eslint-parser/src/worker/configuration.cjs +++ b/eslint/babel-eslint-parser/src/worker/configuration.cts @@ -1,13 +1,17 @@ -const babel = require("./babel-core.cjs"); -const ESLINT_VERSION = require("../utils/eslint-version.cjs"); +import babel = require("./babel-core.cts"); +import ESLINT_VERSION = require("../utils/eslint-version.cts"); +import type { InputOptions } from "@babel/core"; +import type { Options } from "../types.cts"; +import type { PartialConfig } from "../../../../packages/babel-core/src/config"; /** * Merge user supplied estree plugin options to default estree plugin options * - * @param {*} babelOptions * @returns {Array} Merged parser plugin descriptors */ -function getParserPlugins(babelOptions) { +function getParserPlugins( + babelOptions: InputOptions, +): InputOptions["parserOpts"]["plugins"] { const babelParserPlugins = babelOptions.parserOpts?.plugins ?? []; const estreeOptions = { classFeatures: ESLINT_VERSION >= 8 }; for (const plugin of babelParserPlugins) { @@ -20,7 +24,9 @@ function getParserPlugins(babelOptions) { return [["estree", estreeOptions], ...babelParserPlugins]; } -function normalizeParserOptions(options) { +function normalizeParserOptions(options: Options): InputOptions & { + showIgnoredFiles?: boolean; +} { return { sourceType: options.sourceType, filename: options.filePath, @@ -50,7 +56,11 @@ function normalizeParserOptions(options) { }; } -function validateResolvedConfig(config, options, parseOptions) { +function validateResolvedConfig( + config: PartialConfig, + options: Options, + parseOptions: InputOptions, +) { if (config !== null) { if (options.requireConfigFile !== false) { if (!config.hasFilesystemConfig()) { @@ -69,7 +79,7 @@ function validateResolvedConfig(config, options, parseOptions) { return getDefaultParserOptions(parseOptions); } -function getDefaultParserOptions(options) { +function getDefaultParserOptions(options: InputOptions): InputOptions { return { plugins: [], ...options, @@ -81,14 +91,16 @@ function getDefaultParserOptions(options) { }; } -exports.normalizeBabelParseConfig = async function (options) { +export async function normalizeBabelParseConfig( + options: Options, +): Promise { const parseOptions = normalizeParserOptions(options); const config = await babel.loadPartialConfigAsync(parseOptions); return validateResolvedConfig(config, options, parseOptions); -}; +} -exports.normalizeBabelParseConfigSync = function (options) { +export function normalizeBabelParseConfigSync(options: Options): InputOptions { const parseOptions = normalizeParserOptions(options); const config = babel.loadPartialConfigSync(parseOptions); return validateResolvedConfig(config, options, parseOptions); -}; +} diff --git a/eslint/babel-eslint-parser/src/worker/extract-parser-options-plugin.cjs b/eslint/babel-eslint-parser/src/worker/extract-parser-options-plugin.cjs deleted file mode 100644 index bfe925676574..000000000000 --- a/eslint/babel-eslint-parser/src/worker/extract-parser-options-plugin.cjs +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = function extractParserOptionsPlugin() { - return { - parserOverride(code, opts) { - return opts; - }, - }; -}; diff --git a/eslint/babel-eslint-parser/src/worker/extract-parser-options-plugin.cts b/eslint/babel-eslint-parser/src/worker/extract-parser-options-plugin.cts new file mode 100644 index 000000000000..8fe459237537 --- /dev/null +++ b/eslint/babel-eslint-parser/src/worker/extract-parser-options-plugin.cts @@ -0,0 +1,7 @@ +export = function extractParserOptionsPlugin() { + return { + parserOverride(code: string, opts: any) { + return opts; + }, + }; +}; diff --git a/eslint/babel-eslint-parser/src/worker/handle-message.cjs b/eslint/babel-eslint-parser/src/worker/handle-message.cts similarity index 57% rename from eslint/babel-eslint-parser/src/worker/handle-message.cjs rename to eslint/babel-eslint-parser/src/worker/handle-message.cts index f2a82028840d..4ad9f5d6fdfb 100644 --- a/eslint/babel-eslint-parser/src/worker/handle-message.cjs +++ b/eslint/babel-eslint-parser/src/worker/handle-message.cts @@ -1,29 +1,31 @@ -const babel = require("./babel-core.cjs"); -const maybeParse = require("./maybeParse.cjs"); -const { getVisitorKeys, getTokLabels } = require("./ast-info.cjs"); -const { +import babel = require("./babel-core.cts"); +import maybeParse = require("./maybeParse.cts"); +import { getVisitorKeys, getTokLabels } from "./ast-info.cts"; +import { normalizeBabelParseConfig, normalizeBabelParseConfigSync, -} = require("./configuration.cjs"); +} from "./configuration.cts"; -module.exports = function handleMessage(action, payload) { +import { ACTIONS } from "../client.cts"; + +export = function handleMessage(action: ACTIONS, payload: any) { switch (action) { - case "GET_VERSION": + case ACTIONS.GET_VERSION: return babel.version; - case "GET_TYPES_INFO": + case ACTIONS.GET_TYPES_INFO: return { FLOW_FLIPPED_ALIAS_KEYS: babel.types.FLIPPED_ALIAS_KEYS.Flow, VISITOR_KEYS: babel.types.VISITOR_KEYS, }; - case "GET_TOKEN_LABELS": + case ACTIONS.GET_TOKEN_LABELS: return getTokLabels(); - case "GET_VISITOR_KEYS": + case ACTIONS.GET_VISITOR_KEYS: return getVisitorKeys(); - case "MAYBE_PARSE": + case ACTIONS.MAYBE_PARSE: return normalizeBabelParseConfig(payload.options).then(options => maybeParse(payload.code, options), ); - case "MAYBE_PARSE_SYNC": + case ACTIONS.MAYBE_PARSE_SYNC: if (!USE_ESM) { return maybeParse( payload.code, diff --git a/eslint/babel-eslint-parser/src/worker/index.cjs b/eslint/babel-eslint-parser/src/worker/index.cjs deleted file mode 100644 index 9f3293cb4177..000000000000 --- a/eslint/babel-eslint-parser/src/worker/index.cjs +++ /dev/null @@ -1,28 +0,0 @@ -const babel = require("./babel-core.cjs"); -const handleMessage = require("./handle-message.cjs"); - -const { parentPort } = require("worker_threads"); - -parentPort.addListener("message", async ({ signal, port, action, payload }) => { - let response; - - try { - if (babel.init) await babel.init; - - response = { result: await handleMessage(action, payload) }; - } catch (error) { - response = { error, errorData: { ...error } }; - } - - try { - port.postMessage(response); - } catch { - port.postMessage({ - error: new Error("Cannot serialize worker response"), - }); - } finally { - port.close(); - Atomics.store(signal, 0, 1); - Atomics.notify(signal, 0); - } -}); diff --git a/eslint/babel-eslint-parser/src/worker/index.cts b/eslint/babel-eslint-parser/src/worker/index.cts new file mode 100644 index 000000000000..24d1aab2fb20 --- /dev/null +++ b/eslint/babel-eslint-parser/src/worker/index.cts @@ -0,0 +1,31 @@ +import babel = require("./babel-core.cts"); +import handleMessage = require("./handle-message.cts"); + +import worker_threads = require("worker_threads"); + +worker_threads.parentPort.addListener( + "message", + async ({ signal, port, action, payload }) => { + let response; + + try { + if (babel.init) await babel.init; + + response = { result: await handleMessage(action, payload) }; + } catch (error) { + response = { error, errorData: { ...error } }; + } + + try { + port.postMessage(response); + } catch { + port.postMessage({ + error: new Error("Cannot serialize worker response"), + }); + } finally { + port.close(); + Atomics.store(signal, 0, 1); + Atomics.notify(signal, 0); + } + }, +); diff --git a/eslint/babel-eslint-parser/src/worker/maybeParse.cjs b/eslint/babel-eslint-parser/src/worker/maybeParse.cts similarity index 53% rename from eslint/babel-eslint-parser/src/worker/maybeParse.cjs rename to eslint/babel-eslint-parser/src/worker/maybeParse.cts index 0df690c512b8..9d1cfcd10f5a 100644 --- a/eslint/babel-eslint-parser/src/worker/maybeParse.cjs +++ b/eslint/babel-eslint-parser/src/worker/maybeParse.cts @@ -1,14 +1,25 @@ -const babel = require("./babel-core.cjs"); -const convert = require("../convert/index.cjs"); -const { getVisitorKeys, getTokLabels } = require("./ast-info.cjs"); -const extractParserOptionsPlugin = require("./extract-parser-options-plugin.cjs"); +import babel = require("./babel-core.cts"); +import convert = require("../convert/index.cts"); +import astInfo = require("./ast-info.cts"); +import extractParserOptionsPlugin = require("./extract-parser-options-plugin.cjs"); + +import type { InputOptions, ConfigItem } from "@babel/core"; +import type { AST, ParseResult } from "../types.cts"; + +const { getVisitorKeys, getTokLabels } = astInfo; const ref = {}; -let extractParserOptionsConfigItem; +let extractParserOptionsConfigItem: ConfigItem; const MULTIPLE_OVERRIDES = /More than one plugin attempted to override parsing/; -module.exports = function maybeParse(code, options) { +export = function maybeParse( + code: string, + options: InputOptions, +): { + ast: AST.Program | null; + parserOptions: ParseResult | null; +} { if (!extractParserOptionsConfigItem) { extractParserOptionsConfigItem = babel.createConfigItemSync( [extractParserOptionsPlugin, ref], @@ -18,6 +29,8 @@ module.exports = function maybeParse(code, options) { const { plugins } = options; options.plugins = plugins.concat(extractParserOptionsConfigItem); + let ast; + try { return { parserOptions: babel.parseSync(code, options), @@ -32,15 +45,14 @@ module.exports = function maybeParse(code, options) { // There was already a parserOverride, so remove our plugin. options.plugins = plugins; - let ast; try { ast = babel.parseSync(code, options); } catch (err) { - throw convert.error(err); + throw convert.convertError(err); } return { - ast: convert.ast(ast, code, getTokLabels(), getVisitorKeys()), + ast: convert.convertFile(ast, code, getTokLabels(), getVisitorKeys()), parserOptions: null, }; }; diff --git a/package.json b/package.json index 06133550d631..79984527b99e 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-terser": "^0.4.4", "@types/jest": "^29.5.11", - "@types/node": "^20.10.5", + "@types/node": "^20.11.5", "@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/parser": "^6.15.0", "@yarnpkg/types": "^4.0.0", @@ -81,7 +81,7 @@ "shelljs": "^0.8.5", "test262-stream": "^1.4.0", "through2": "^4.0.0", - "typescript": "^5.3.3" + "typescript": "5.4.0-dev.20240125" }, "workspaces": [ "codemods/*", diff --git a/packages/babel-core/src/config/index.ts b/packages/babel-core/src/config/index.ts index ed27669a2b9c..553038f6222b 100644 --- a/packages/babel-core/src/config/index.ts +++ b/packages/babel-core/src/config/index.ts @@ -34,6 +34,7 @@ export type { PartialConfig } from "./partial.ts"; import { createConfigItem as createConfigItemImpl } from "./item.ts"; import type { ConfigItem } from "./item.ts"; +export type { ConfigItem }; import { beginHiddenCallStack } from "../errors/rewrite-stack-trace.ts"; diff --git a/packages/babel-core/src/index.ts b/packages/babel-core/src/index.ts index 4e7ac315a82a..c6233f9e5149 100644 --- a/packages/babel-core/src/index.ts +++ b/packages/babel-core/src/index.ts @@ -44,6 +44,7 @@ export type { PluginObject, PresetAPI, PresetObject, + ConfigItem, } from "./config/index.ts"; export { diff --git a/packages/babel-core/src/tools/build-external-helpers.ts b/packages/babel-core/src/tools/build-external-helpers.ts index 93567eced5c2..8ccdb9bc6c79 100644 --- a/packages/babel-core/src/tools/build-external-helpers.ts +++ b/packages/babel-core/src/tools/build-external-helpers.ts @@ -24,11 +24,11 @@ import { } from "@babel/types"; import type * as t from "@babel/types"; import File from "../transformation/file/file.ts"; -import type { PublicReplacements } from "@babel/template/src/options"; +import type { Replacements } from "@babel/template"; // Wrapped to avoid wasting time parsing this when almost no-one uses // build-external-helpers. -const buildUmdWrapper = (replacements: PublicReplacements) => +const buildUmdWrapper = (replacements: Replacements) => template.statement` (function (root, factory) { if (typeof define === "function" && define.amd) { diff --git a/packages/babel-parser/src/plugins/typescript/index.ts b/packages/babel-parser/src/plugins/typescript/index.ts index 5696453556dc..68ae351f3afd 100644 --- a/packages/babel-parser/src/plugins/typescript/index.ts +++ b/packages/babel-parser/src/plugins/typescript/index.ts @@ -699,7 +699,6 @@ export default (superClass: ClassWithMixin) => node.params = this.tsParseBracketedList( "TypeParametersOrArguments", - // @ts-expect-error refine typings this.tsParseTypeParameter.bind(this, parseModifiers), /* bracket */ false, /* skipFirstToken */ true, diff --git a/packages/babel-template/src/index.ts b/packages/babel-template/src/index.ts index 15f1ecc82e4f..391d8e3ebc5e 100644 --- a/packages/babel-template/src/index.ts +++ b/packages/babel-template/src/index.ts @@ -23,3 +23,8 @@ export default Object.assign(smart.bind(undefined) as DefaultTemplateBuilder, { program, ast: smart.ast, }); + +export type { + PublicOpts as Options, + PublicReplacements as Replacements, +} from "./options.ts"; diff --git a/scripts/generators/tsconfig.js b/scripts/generators/tsconfig.js index 35f6c8649d8d..b4457c7c289e 100644 --- a/scripts/generators/tsconfig.js +++ b/scripts/generators/tsconfig.js @@ -104,6 +104,8 @@ fs.writeFileSync( include: tsPkgs .map(({ relative }) => `${relative}/src/**/*.ts`) .concat([ + "eslint/babel-eslint-parser/**/*.cts", + "./lib/globals.d.ts", "./scripts/repo-utils/*.d.ts", "./packages/babel-parser/typings/*.d.ts", diff --git a/tsconfig.base.json b/tsconfig.base.json index c811c02b567a..844b79b7dccd 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,13 +1,12 @@ { "compilerOptions": { - "target": "esnext", - "module": "esnext", - "lib": ["esnext"], + "target": "ESNext", + "module": "preserve", + "lib": ["ESNext"], "declaration": true, - "declarationMap": true, "emitDeclarationOnly": true, "declarationDir": "./dts", - "moduleResolution": "node", + "moduleResolution": "Bundler", "esModuleInterop": true, "isolatedModules": true, "allowImportingTsExtensions": true, diff --git a/tsconfig.json b/tsconfig.json index 67e2867923c4..9f198af7f3fc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -162,6 +162,7 @@ "./packages/babel-types/src/**/*.ts", "./codemods/babel-plugin-codemod-object-assign-to-object-spread/src/**/*.ts", "./codemods/babel-plugin-codemod-optional-catch-binding/src/**/*.ts", + "eslint/babel-eslint-parser/**/*.cts", "./lib/globals.d.ts", "./scripts/repo-utils/*.d.ts", "./packages/babel-parser/typings/*.d.ts" diff --git a/yarn.lock b/yarn.lock index 5471a813210b..7f4a52118559 100644 --- a/yarn.lock +++ b/yarn.lock @@ -419,6 +419,9 @@ __metadata: dependencies: "@babel/core": "workspace:^" "@nicolo-ribaudo/eslint-scope-5-internals": "condition:BABEL_8_BREAKING ? : 5.1.1-v1" + "@types/eslint": "npm:^8.56.2" + "@types/estree": "npm:^1.0.5" + "@typescript-eslint/scope-manager": "npm:^6.19.0" dedent: "npm:^0.7.0" eslint: "npm:^8.22.0" eslint-scope: "condition:BABEL_8_BREAKING ? ^7.1.1 : " @@ -5281,20 +5284,20 @@ __metadata: languageName: node linkType: hard -"@types/eslint@npm:*": - version: 7.2.6 - resolution: "@types/eslint@npm:7.2.6" +"@types/eslint@npm:*, @types/eslint@npm:^8.56.2": + version: 8.56.2 + resolution: "@types/eslint@npm:8.56.2" dependencies: "@types/estree": "npm:*" "@types/json-schema": "npm:*" - checksum: aeb587e8d88d3accb5155445b6f5e92403bdaa4be68eeafeff84925cedf13bf899071effeeeddc9acc5e7f891e40e90f02f9347193100f6df38ed5036992d715 + checksum: 9e4805e770ea90a561e1f69e5edce28b8f66e92e290705100e853c7c252cf87bef654168d0d47fc60c0effbe4517dd7a8d2fa6d3f04c7f831367d568009fd368 languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:^1.0.0": - version: 1.0.1 - resolution: "@types/estree@npm:1.0.1" - checksum: f252569c002506c61ad913e778aa69415908078c46c78c901ccad77bc66cd34f1e1b9babefb8ff0d27c07a15fb0824755edd7bb3fa7ea828f32ae0fe5faa9962 +"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.5": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: 7de6d928dd4010b0e20c6919e1a6c27b61f8d4567befa89252055fad503d587ecb9a1e3eab1b1901f923964d7019796db810b7fd6430acb26c32866d126fd408 languageName: node linkType: hard @@ -5392,12 +5395,12 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^20.10.5": - version: 20.10.5 - resolution: "@types/node@npm:20.10.5" +"@types/node@npm:*, @types/node@npm:^20.11.5": + version: 20.11.5 + resolution: "@types/node@npm:20.11.5" dependencies: undici-types: "npm:~5.26.4" - checksum: 4a378428d2c9f692b19801a5a3d20dc4c0ad5d4a3d103350f8b401af439941a9aa5efeadc8eb9db13c66c620318bc7f336abfc8934f82fd32c4a689d85068c6f + checksum: 9f31c471047d7b3e240ce7b77ff29b0d15e83be7e3feafb3d0b0d0931122b438b1eefa302a5a2e1e9849914ff3fd76aafbd8ccb372efb1331ba048da63bce6f8 languageName: node linkType: hard @@ -5515,6 +5518,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:^6.19.0": + version: 6.19.0 + resolution: "@typescript-eslint/scope-manager@npm:6.19.0" + dependencies: + "@typescript-eslint/types": "npm:6.19.0" + "@typescript-eslint/visitor-keys": "npm:6.19.0" + checksum: d36c51c05e14c51ce13181120eeea46d1edd59ed1ff16dc4ec1f5532a975b5faec5c10a373aaa90545f82a12330c6cba18ecedc734e18288f5874855c48ba808 + languageName: node + linkType: hard + "@typescript-eslint/type-utils@npm:6.15.0": version: 6.15.0 resolution: "@typescript-eslint/type-utils@npm:6.15.0" @@ -5546,6 +5559,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:6.19.0": + version: 6.19.0 + resolution: "@typescript-eslint/types@npm:6.19.0" + checksum: 396ad2ad9f2d759dd87bc880a1ffc9d11fda04db8af9402abb4e8eccd58c01fa2d26e38b186526d0b457012f7c912e7afdab2a3798a73aa0ae34abaf50d617ae + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:5.55.0": version: 5.55.0 resolution: "@typescript-eslint/typescript-estree@npm:5.55.0" @@ -5637,6 +5657,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:6.19.0": + version: 6.19.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.19.0" + dependencies: + "@typescript-eslint/types": "npm:6.19.0" + eslint-visitor-keys: "npm:^3.4.1" + checksum: 8d51c0b8d94c5df044fde958f62741cef55be97c6a3a16c47e4df9af7b2ff13aa1ee03ca5240777481dca53f3b7a9b00b329e50aff5e3ad829d96bc5f63ca2c3 + languageName: node + linkType: hard + "@ungap/structured-clone@npm:^1.2.0": version: 1.2.0 resolution: "@ungap/structured-clone@npm:1.2.0" @@ -6927,7 +6957,7 @@ __metadata: "@rollup/plugin-replace": "npm:^5.0.5" "@rollup/plugin-terser": "npm:^0.4.4" "@types/jest": "npm:^29.5.11" - "@types/node": "npm:^20.10.5" + "@types/node": "npm:^20.11.5" "@typescript-eslint/eslint-plugin": "npm:^6.15.0" "@typescript-eslint/parser": "npm:^6.15.0" "@yarnpkg/types": "npm:^4.0.0" @@ -6964,7 +6994,7 @@ __metadata: shelljs: "npm:^0.8.5" test262-stream: "npm:^1.4.0" through2: "npm:^4.0.0" - typescript: "npm:^5.3.3" + typescript: "npm:5.4.0-dev.20240125" languageName: unknown linkType: soft @@ -16457,23 +16487,23 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^5.3.3": - version: 5.3.3 - resolution: "typescript@npm:5.3.3" +"typescript@npm:5.4.0-dev.20240125": + version: 5.4.0-dev.20240125 + resolution: "typescript@npm:5.4.0-dev.20240125" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 6e4e6a14a50c222b3d14d4ea2f729e79f972fa536ac1522b91202a9a65af3605c2928c4a790a4a50aa13694d461c479ba92cedaeb1e7b190aadaa4e4b96b8e18 + checksum: 8e151cae1df9a2c4fd22d23148b88a7baf7b526a03e059e24c53ee775f88d8dde0a3326c3824c82ba262852098d3d8af1db6522d32c959059ba3bb7c5063f738 languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.3.3#optional!builtin": - version: 5.3.3 - resolution: "typescript@patch:typescript@npm%3A5.3.3#optional!builtin::version=5.3.3&hash=e012d7" +"typescript@patch:typescript@npm%3A5.4.0-dev.20240125#optional!builtin": + version: 5.4.0-dev.20240125 + resolution: "typescript@patch:typescript@npm%3A5.4.0-dev.20240125#optional!builtin::version=5.4.0-dev.20240125&hash=e012d7" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: c93786fcc9a70718ba1e3819bab56064ead5817004d1b8186f8ca66165f3a2d0100fee91fa64c840dcd45f994ca5d615d8e1f566d39a7470fc1e014dbb4cf15d + checksum: 93153df3fa2322f098d6cd24faa59224142a2fbac36fd9269f58423a3db114a2aaf0b447a03ffdad0e4c3bc14ba1771c76a332c9943e84e707436145f3625fe0 languageName: node linkType: hard