diff --git a/packages/babel-core/src/transformation/normalize-file.ts b/packages/babel-core/src/transformation/normalize-file.ts index 16eba97d3180..ce9c0ae2df1e 100644 --- a/packages/babel-core/src/transformation/normalize-file.ts +++ b/packages/babel-core/src/transformation/normalize-file.ts @@ -107,9 +107,9 @@ const EXTERNAL_SOURCEMAP_REGEX = function extractCommentsFromList( regex: RegExp, - comments: ReadonlyArray, + comments: t.Comment[], lastComment: string | null, -): [ReadonlyArray, string | null] { +): [t.Comment[], string | null] { if (comments) { comments = comments.filter(({ value }) => { if (regex.test(value)) { diff --git a/packages/babel-generator/src/generators/methods.ts b/packages/babel-generator/src/generators/methods.ts index 5459d1d71796..d86c676bdf3b 100644 --- a/packages/babel-generator/src/generators/methods.ts +++ b/packages/babel-generator/src/generators/methods.ts @@ -37,13 +37,7 @@ export function _parameters( export function _param( this: Printer, - parameter: - | t.Function["params"][number] - | t.TSIndexSignature["parameters"][number] - | t.TSDeclareMethod["params"][number] - | t.TSDeclareFunction["params"][number] - | t.TSFunctionType["parameters"][number] - | t.TSConstructorType["parameters"][number], + parameter: t.Identifier | t.RestElement | t.Pattern | t.TSParameterProperty, parent?: | t.Function | t.TSIndexSignature diff --git a/packages/babel-generator/src/generators/statements.ts b/packages/babel-generator/src/generators/statements.ts index 8b383817df76..aa0fad48867e 100644 --- a/packages/babel-generator/src/generators/statements.ts +++ b/packages/babel-generator/src/generators/statements.ts @@ -50,22 +50,14 @@ export function IfStatement(this: Printer, node: t.IfStatement) { } // Recursively get the last statement. -function getLastStatement( - statement: Exclude, -): t.Statement { - if ( - !isStatement( - // @ts-ignore body is not in BreakStatement - statement.body, - ) - ) { +function getLastStatement(statement: t.Statement): t.Statement { + // @ts-ignore: If statement.body is empty or not a Node, isStatement will return false + const { body } = statement; + if (isStatement(body) === false) { return statement; } - return getLastStatement( - // @ts-ignore body is not in BreakStatement - statement.body, - ); + return getLastStatement(body); } export function ForStatement(this: Printer, node: t.ForStatement) { diff --git a/packages/babel-generator/src/generators/typescript.ts b/packages/babel-generator/src/generators/typescript.ts index 9f0405b7b09f..0ffce6004dd3 100644 --- a/packages/babel-generator/src/generators/typescript.ts +++ b/packages/babel-generator/src/generators/typescript.ts @@ -239,9 +239,10 @@ export function tsPrintFunctionOrConstructorType( ) { const { typeParameters } = node; const parameters = process.env.BABEL_8_BREAKING - ? // @ts-expect-error Babel 8 AST shape + ? // @ts-ignore Babel 8 AST shape node.params - : node.parameters; + : // @ts-ignore Babel 7 AST shape + node.parameters; this.print(typeParameters, node); this.token("("); this._parameters(parameters, node); @@ -250,9 +251,10 @@ export function tsPrintFunctionOrConstructorType( this.token("=>"); this.space(); const returnType = process.env.BABEL_8_BREAKING - ? // @ts-expect-error Babel 8 AST shape + ? // @ts-ignore Babel 8 AST shape node.returnType - : node.typeAnnotation; + : // @ts-ignore Babel 7 AST shape + node.typeAnnotation; this.print(returnType.typeAnnotation, node); } diff --git a/packages/babel-generator/src/printer.ts b/packages/babel-generator/src/printer.ts index 62bf02c045a3..227fabe71aa6 100644 --- a/packages/babel-generator/src/printer.ts +++ b/packages/babel-generator/src/printer.ts @@ -669,9 +669,8 @@ class Printer { _printComment(comment: t.Comment, skipNewLines?: boolean) { if (!this.format.shouldPrintComment(comment.value)) return; - // Some plugins use this to mark comments as removed using the AST-root 'comments' property, + // Some plugins (such as flow-strip-types) use this to mark comments as removed using the AST-root 'comments' property, // where they can't manually mutate the AST node comment lists. - // @ts-ignore todo: which plugin? if (comment.ignore) return; if (this._printedComments.has(comment)) return; diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.ts b/packages/babel-helper-create-class-features-plugin/src/fields.ts index db9c201f614c..24e0a46ed0c4 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.ts +++ b/packages/babel-helper-create-class-features-plugin/src/fields.ts @@ -107,6 +107,7 @@ interface PrivateNameVisitorState { function privateNameVisitorFactory( visitor: Visitor, ) { + // @ts-ignore Fixme: TS complains _exploded: boolean does not satisfy visitor functions const privateNameVisitor: Visitor = { ...visitor, diff --git a/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.ts b/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.ts index e4a263831784..b0793cfcd0f7 100644 --- a/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.ts +++ b/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.ts @@ -580,7 +580,9 @@ function removeModuleDeclarations(programPath: NodePath) { ) { // @ts-expect-error todo(flow->ts): avoid mutations declaration._blockHoist = child.node._blockHoist; - child.replaceWith(declaration); + child.replaceWith( + declaration as NodePath, + ); } else { // These should have been removed by the nameAnonymousExports() call. throw declaration.buildCodeFrameError( diff --git a/packages/babel-helper-split-export-declaration/src/index.ts b/packages/babel-helper-split-export-declaration/src/index.ts index 5737527cece5..24565980f95f 100644 --- a/packages/babel-helper-split-export-declaration/src/index.ts +++ b/packages/babel-helper-split-export-declaration/src/index.ts @@ -51,7 +51,7 @@ export default function splitExportDeclaration( } const updatedDeclaration = standaloneDeclaration - ? declaration + ? declaration.node : variableDeclaration("var", [ variableDeclarator( cloneNode(id), diff --git a/packages/babel-helper-transform-fixture-test-runner/src/index.ts b/packages/babel-helper-transform-fixture-test-runner/src/index.ts index c4668c1823c3..da82eadae3a9 100644 --- a/packages/babel-helper-transform-fixture-test-runner/src/index.ts +++ b/packages/babel-helper-transform-fixture-test-runner/src/index.ts @@ -33,14 +33,16 @@ type Module = { }; if (!process.env.BABEL_8_BREAKING) { - // Introduced in Node.js 8 + // Introduced in Node.js 10 if (!assert.rejects) { assert.rejects = async function (block, validateError) { try { - await block(); + await (typeof block === "function" ? block() : block); return Promise.reject(new Error("Promise not rejected")); } catch (error) { - if (!validateError(error)) { + // @ts-ignore Fixme: validateError can be a string | object + // see https://nodejs.org/api/assert.html#assertrejectsasyncfn-error-message + if (typeof validateError === "function" && !validateError(error)) { return Promise.reject( new Error("Promise rejected with invalid error"), ); diff --git a/packages/babel-plugin-proposal-async-generator-functions/src/index.ts b/packages/babel-plugin-proposal-async-generator-functions/src/index.ts index 717f7ec18b96..b9cc7734baf2 100644 --- a/packages/babel-plugin-proposal-async-generator-functions/src/index.ts +++ b/packages/babel-plugin-proposal-async-generator-functions/src/index.ts @@ -3,7 +3,7 @@ import remapAsyncToGenerator from "@babel/helper-remap-async-to-generator"; import syntaxAsyncGenerators from "@babel/plugin-syntax-async-generators"; import { types as t } from "@babel/core"; import type { PluginPass } from "@babel/core"; -import type { Visitor } from "@babel/traverse"; +import type { NodePath, Visitor } from "@babel/traverse"; import rewriteForAwait from "./for-await"; export default declare(api => { @@ -29,7 +29,7 @@ export default declare(api => { path.skip(); }, - ForOfStatement(path, { file }) { + ForOfStatement(path: NodePath, { file }) { const { node } = path; if (!node.await) return; @@ -49,7 +49,7 @@ export default declare(api => { } // push the rest of the original loop body onto our new body - block.body.push(...(node.body as t.BlockStatement).body); + block.body.push(...path.node.body.body); t.inherits(loop, node); t.inherits(loop.body, node.body); diff --git a/packages/babel-plugin-proposal-decorators/src/transformer-2021-12.ts b/packages/babel-plugin-proposal-decorators/src/transformer-2021-12.ts index a136ddd2139a..10af52865a2f 100644 --- a/packages/babel-plugin-proposal-decorators/src/transformer-2021-12.ts +++ b/packages/babel-plugin-proposal-decorators/src/transformer-2021-12.ts @@ -143,7 +143,10 @@ function replaceClassWithVar( t.sequenceExpression([newClassExpr, varId]), ); - return [t.cloneNode(varId), newPath.get("expressions.0")]; + return [ + t.cloneNode(varId), + newPath.get("expressions.0") as NodePath, + ]; } } diff --git a/packages/babel-plugin-proposal-destructuring-private/src/index.ts b/packages/babel-plugin-proposal-destructuring-private/src/index.ts index 4270b44d0813..b4fda77cc40f 100644 --- a/packages/babel-plugin-proposal-destructuring-private/src/index.ts +++ b/packages/babel-plugin-proposal-destructuring-private/src/index.ts @@ -10,7 +10,8 @@ import { convertFunctionParams } from "@babel/plugin-transform-parameters"; import { unshiftForXStatementBody } from "@babel/plugin-transform-destructuring"; import type { PluginPass } from "@babel/core"; -import type { Visitor } from "@babel/traverse"; +import type { NodePath, Visitor } from "@babel/traverse"; +import type * as t from "@babel/types"; export default declare(function ({ assertVersion, assumption, types: t }) { assertVersion("^7.17.0"); @@ -51,7 +52,10 @@ export default declare(function ({ assertVersion, assumption, types: t }) { const { params: transformedParams, variableDeclaration } = buildVariableDeclarationFromParams(paramsAfterIndex, scope); - path.get("body").unshiftContainer("body", variableDeclaration); + (path.get("body") as NodePath).unshiftContainer( + "body", + variableDeclaration, + ); params.push(...transformedParams); // preserve function.length // (b, p1) => {} diff --git a/packages/babel-plugin-proposal-object-rest-spread/src/index.ts b/packages/babel-plugin-proposal-object-rest-spread/src/index.ts index d34d35d56b6c..33ad67f77abc 100644 --- a/packages/babel-plugin-proposal-object-rest-spread/src/index.ts +++ b/packages/babel-plugin-proposal-object-rest-spread/src/index.ts @@ -540,7 +540,7 @@ export default declare((api, opts: Options) => { }, // taken from transform-destructuring/src/index.js#visitor - ForXStatement(path) { + ForXStatement(path: NodePath) { const { node, scope } = path; const leftPath = path.get("left"); const left = node.left; @@ -558,7 +558,7 @@ export default declare((api, opts: Options) => { ]); path.ensureBlock(); - const body = node.body as t.BlockStatement; + const body = path.node.body; if (body.body.length === 0 && path.isCompletionRecord()) { body.body.unshift( diff --git a/packages/babel-plugin-transform-block-scoping/src/index.ts b/packages/babel-plugin-transform-block-scoping/src/index.ts index 02a78b553b51..bb927c6aca91 100644 --- a/packages/babel-plugin-transform-block-scoping/src/index.ts +++ b/packages/babel-plugin-transform-block-scoping/src/index.ts @@ -62,12 +62,12 @@ export default declare((api, opts: Options) => { } }, - Loop(path, state) { + Loop(path: NodePath, state) { const { parent, scope } = path; path.ensureBlock(); const blockScoping = new BlockScoping( path, - path.get("body") as NodePath, + path.get("body"), parent, scope, throwIfClosureRequired, @@ -534,6 +534,7 @@ class BlockScoping { ]), ); } else if (violation.isForXStatement()) { + // @ts-expect-error TS requires explicit annotation of "violation" violation.ensureBlock(); violation .get("left") diff --git a/packages/babel-plugin-transform-destructuring/src/index.ts b/packages/babel-plugin-transform-destructuring/src/index.ts index 6c2bc0fb8c5a..0e5398efe1ec 100644 --- a/packages/babel-plugin-transform-destructuring/src/index.ts +++ b/packages/babel-plugin-transform-destructuring/src/index.ts @@ -8,6 +8,7 @@ import { type DestructuringTransformerNode, } from "./util"; export { buildObjectExcludingKeys, unshiftForXStatementBody } from "./util"; +import type { NodePath } from "@babel/traverse"; /** * Test if a VariableDeclaration's declarations contains any Patterns. @@ -68,7 +69,7 @@ export default declare((api, options: Options) => { path.scope.crawl(); }, - ForXStatement(path) { + ForXStatement(path: NodePath) { const { node, scope } = path; const left = node.left; @@ -82,7 +83,7 @@ export default declare((api, options: Options) => { ]); path.ensureBlock(); - const statementBody = (node.body as t.BlockStatement).body; + const statementBody = path.node.body.body; const nodes = []; // todo: the completion of a for statement can only be observed from // a do block (or eval that we don't support), diff --git a/packages/babel-plugin-transform-modules-amd/src/index.ts b/packages/babel-plugin-transform-modules-amd/src/index.ts index 04e20d9c779c..b1a5e9f80243 100644 --- a/packages/babel-plugin-transform-modules-amd/src/index.ts +++ b/packages/babel-plugin-transform-modules-amd/src/index.ts @@ -32,9 +32,9 @@ function injectWrapper( const { body, directives } = path.node; path.node.directives = []; path.node.body = []; - const amdFactoryCall = ( - path.pushContainer("body", wrapper)[0] as NodePath - ).get("expression") as NodePath; + const amdFactoryCall = path + .pushContainer("body", wrapper)[0] + .get("expression") as NodePath; const amdFactoryCallArgs = amdFactoryCall.get("arguments"); const amdFactory = ( amdFactoryCallArgs[ diff --git a/packages/babel-plugin-transform-modules-umd/src/index.ts b/packages/babel-plugin-transform-modules-umd/src/index.ts index 072987e16db0..183eedb4895e 100644 --- a/packages/babel-plugin-transform-modules-umd/src/index.ts +++ b/packages/babel-plugin-transform-modules-umd/src/index.ts @@ -264,7 +264,7 @@ export default declare((api, options: Options) => { ])[0] as NodePath; const umdFactory = ( umdWrapper.get("expression.arguments")[1] as NodePath - ).get("body"); + ).get("body") as NodePath; umdFactory.pushContainer("directives", directives); umdFactory.pushContainer("body", body); }, diff --git a/packages/babel-plugin-transform-parameters/src/params.ts b/packages/babel-plugin-transform-parameters/src/params.ts index 76adffdd0746..9b21a95952ad 100644 --- a/packages/babel-plugin-transform-parameters/src/params.ts +++ b/packages/babel-plugin-transform-parameters/src/params.ts @@ -1,7 +1,7 @@ import { template, types as t } from "@babel/core"; import type { NodePath, Scope, Visitor } from "@babel/traverse"; -const buildDefaultParam = template(` +const buildDefaultParam = template.statement(` let VARIABLE_NAME = arguments.length > ARGUMENT_KEY && arguments[ARGUMENT_KEY] !== undefined ? arguments[ARGUMENT_KEY] @@ -9,17 +9,17 @@ const buildDefaultParam = template(` DEFAULT_VALUE; `); -const buildLooseDefaultParam = template(` +const buildLooseDefaultParam = template.statement(` if (ASSIGNMENT_IDENTIFIER === UNDEFINED) { ASSIGNMENT_IDENTIFIER = DEFAULT_VALUE; } `); -const buildLooseDestructuredDefaultParam = template(` +const buildLooseDestructuredDefaultParam = template.statement(` let ASSIGNMENT_IDENTIFIER = PARAMETER_NAME === UNDEFINED ? DEFAULT_VALUE : PARAMETER_NAME ; `); -const buildSafeArgumentsAccess = template(` +const buildSafeArgumentsAccess = template.statement(` let $0 = arguments.length > $1 ? arguments[$1] : undefined; `); @@ -238,7 +238,7 @@ export default function convertFunctionParams( // throws, it must reject asynchronously. path.node.generator = false; } else { - path.get("body").unshiftContainer("body", body as t.Statement[]); + path.get("body").unshiftContainer("body", body); } return true; diff --git a/packages/babel-preset-env/src/normalize-options.ts b/packages/babel-preset-env/src/normalize-options.ts index babae634c7d9..4c550303c7bd 100644 --- a/packages/babel-preset-env/src/normalize-options.ts +++ b/packages/babel-preset-env/src/normalize-options.ts @@ -1,5 +1,8 @@ import semver, { type SemVer } from "semver"; import corejs2Polyfills from "@babel/compat-data/corejs2-built-ins"; +// @ts-ignore Fixme: TS can not infer types from ../data/core-js-compat.js +// but we can't import core-js-compat/data.json because JSON imports does +// not work on Node 14 import corejs3Polyfills from "../data/core-js-compat"; import { plugins as pluginsList } from "./plugins-compat-data"; import moduleTransformations from "./module-transformations"; diff --git a/packages/babel-standalone/src/index.ts b/packages/babel-standalone/src/index.ts index f355b5f575ee..b56ba463b8aa 100644 --- a/packages/babel-standalone/src/index.ts +++ b/packages/babel-standalone/src/index.ts @@ -106,7 +106,7 @@ export function transform(code: string, options: InputOptions) { } export function transformFromAst( - ast: Parameters[0], + ast: Parameters[0], code: string, options: InputOptions, ) { diff --git a/packages/babel-traverse/src/context.ts b/packages/babel-traverse/src/context.ts index 4ac5f580d99b..0ad063102cf5 100644 --- a/packages/babel-traverse/src/context.ts +++ b/packages/babel-traverse/src/context.ts @@ -1,9 +1,17 @@ import NodePath from "./path"; import { VISITOR_KEYS } from "@babel/types"; import type Scope from "./scope"; - -export default class TraversalContext { - constructor(scope, opts, state, parentPath) { +import type { TraverseOptions } from "."; +import type * as t from "@babel/types"; +import type { Visitor } from "./types"; + +export default class TraversalContext { + constructor( + scope: Scope, + opts: TraverseOptions, + state: S, + parentPath: NodePath, + ) { this.parentPath = parentPath; this.scope = scope; this.state = state; @@ -12,8 +20,8 @@ export default class TraversalContext { declare parentPath: NodePath; declare scope: Scope; - declare state; - declare opts; + declare state: S; + declare opts: TraverseOptions; queue: Array | null = null; priorityQueue: Array | null = null; @@ -22,8 +30,8 @@ export default class TraversalContext { * visit a node. This will prevent us from constructing a NodePath. */ - shouldVisit(node): boolean { - const opts = this.opts; + shouldVisit(node: t.Node): boolean { + const opts = this.opts as Visitor; if (opts.enter || opts.exit) return true; // check if we have a visitor for this node @@ -35,25 +43,35 @@ export default class TraversalContext { // we need to traverse into this node so ensure that it has children to traverse into! for (const key of keys) { - if (node[key]) return true; + if ( + // @ts-ignore key is from visitor keys + node[key] + ) { + return true; + } } return false; } - create(node, obj, key, listKey?): NodePath { + create( + node: t.Node, + container: t.Node | t.Node[], + key: string | number, + listKey?: string, + ): NodePath { // We don't need to `.setContext()` here, since `.visitQueue()` already // calls `.pushContext`. return NodePath.get({ parentPath: this.parentPath, parent: node, - container: obj, + container, key: key, listKey, }); } - maybeQueue(path, notPriority?: boolean) { + maybeQueue(path: NodePath, notPriority?: boolean) { if (this.queue) { if (notPriority) { this.queue.push(path); @@ -63,7 +81,7 @@ export default class TraversalContext { } } - visitMultiple(container, parent, listKey) { + visitMultiple(container: t.Node[], parent: t.Node, listKey: string) { // nothing to traverse! if (container.length === 0) return false; @@ -80,15 +98,20 @@ export default class TraversalContext { return this.visitQueue(queue); } - visitSingle(node, key): boolean { - if (this.shouldVisit(node[key])) { + visitSingle(node: t.Node, key: string): boolean { + if ( + this.shouldVisit( + // @ts-expect-error + node[key], + ) + ) { return this.visitQueue([this.create(node, node, key)]); } else { return false; } } - visitQueue(queue: Array) { + visitQueue(queue: Array): boolean { // set queue this.queue = queue; this.priorityQueue = []; @@ -142,8 +165,9 @@ export default class TraversalContext { return stop; } - visit(node, key) { - const nodes = node[key]; + visit(node: t.Node, key: string) { + // @ts-expect-error + const nodes = node[key] as t.Node | t.Node[] | null; if (!nodes) return false; if (Array.isArray(nodes)) { diff --git a/packages/babel-traverse/src/hub.ts b/packages/babel-traverse/src/hub.ts index 1894d9930add..c3aa8add3bb8 100644 --- a/packages/babel-traverse/src/hub.ts +++ b/packages/babel-traverse/src/hub.ts @@ -1,10 +1,11 @@ import type Scope from "./scope"; +import type { Node } from "@babel/types"; export interface HubInterface { getCode(): string | void; getScope(): Scope | void; addHelper(name: string): any; - buildError(node: any, msg: string, Error: new () => Error): Error; + buildError(node: Node, msg: string, Error: new () => Error): Error; } export default class Hub implements HubInterface { @@ -16,7 +17,7 @@ export default class Hub implements HubInterface { throw new Error("Helpers are not supported by the default hub."); } - buildError(node, msg, Error = TypeError): Error { + buildError(node: Node, msg: string, Error = TypeError): Error { return new Error(msg); } } diff --git a/packages/babel-traverse/src/index.ts b/packages/babel-traverse/src/index.ts index 4cfaca7c07fa..d6c242994364 100644 --- a/packages/babel-traverse/src/index.ts +++ b/packages/babel-traverse/src/index.ts @@ -1,5 +1,10 @@ import * as visitors from "./visitors"; -import { VISITOR_KEYS, removeProperties, traverseFast } from "@babel/types"; +import { + VISITOR_KEYS, + removeProperties, + type RemovePropertiesOptions, + traverseFast, +} from "@babel/types"; import type * as t from "@babel/types"; import * as cache from "./cache"; import type NodePath from "./path"; @@ -15,6 +20,11 @@ export type { HubInterface } from "./hub"; export { visitors }; +// fixme: The TraverseOptions should have been { scope ... } & Visitor +// however TS does not support excluding certain string literals from general string +// type. If we change here to { scope ... } & Visitor, TS will throw +// noScope: boolean because it matched `noScope` to the [k in string]: VisitNode<> catch-all +// in Visitor export type TraverseOptions = | { scope?: Scope; @@ -39,9 +49,10 @@ function traverse( parentPath?: NodePath, ): void; -function traverse( +function traverse( parent: t.Node, - opts: TraverseOptions = {}, + // @ts-ignore provide {} as default value for Options + opts: Options = {}, scope?: Scope, state?: any, parentPath?: NodePath, @@ -62,7 +73,7 @@ function traverse( return; } - visitors.explode(opts); + visitors.explode(opts as Visitor); traverseNode(parent, opts, scope, state, parentPath); } @@ -73,7 +84,7 @@ traverse.visitors = visitors; traverse.verify = visitors.verify; traverse.explode = visitors.explode; -traverse.cheap = function (node, enter) { +traverse.cheap = function (node: t.Node, enter: (node: t.Node) => void) { return traverseFast(node, enter); }; @@ -83,24 +94,31 @@ traverse.node = function ( scope?: Scope, state?: any, path?: NodePath, - skipKeys?: string[], + skipKeys?: Record, ) { traverseNode(node, opts, scope, state, path, skipKeys); // traverse.node always returns undefined }; -traverse.clearNode = function (node: t.Node, opts?) { +traverse.clearNode = function (node: t.Node, opts?: RemovePropertiesOptions) { removeProperties(node, opts); cache.path.delete(node); }; -traverse.removeProperties = function (tree, opts?) { +traverse.removeProperties = function ( + tree: t.Node, + opts?: RemovePropertiesOptions, +) { traverseFast(tree, traverse.clearNode, opts); return tree; }; -function hasDenylistedType(path: NodePath, state) { +type HasDenylistedTypeState = { + has: boolean; + type: t.Node["type"]; +}; +function hasDenylistedType(path: NodePath, state: HasDenylistedTypeState) { if (path.node.type === state.type) { state.has = true; path.stop(); @@ -108,8 +126,8 @@ function hasDenylistedType(path: NodePath, state) { } traverse.hasType = function ( - tree: any, - type: any, + tree: t.Node, + type: t.Node["type"], denylistTypes?: Array, ): boolean { // the node we're searching in is denylisted @@ -118,7 +136,7 @@ traverse.hasType = function ( // the type we're looking for is the same as the passed node if (tree.type === type) return true; - const state = { + const state: HasDenylistedTypeState = { has: false, type: type, }; diff --git a/packages/babel-traverse/src/path/ancestry.ts b/packages/babel-traverse/src/path/ancestry.ts index 0381427724f7..742a49d2cf39 100644 --- a/packages/babel-traverse/src/path/ancestry.ts +++ b/packages/babel-traverse/src/path/ancestry.ts @@ -133,7 +133,7 @@ export function getEarliestCommonAncestorFrom( export function getDeepestCommonAncestorFrom( this: NodePath, paths: Array, - filter?: (deepest: t.Node, i: number, ancestries: NodePath[][]) => NodePath, + filter?: (deepest: NodePath, i: number, ancestries: NodePath[][]) => NodePath, ): NodePath { if (!paths.length) { return this; diff --git a/packages/babel-traverse/src/path/comments.ts b/packages/babel-traverse/src/path/comments.ts index 6e23a9be724f..8f7384794c43 100644 --- a/packages/babel-traverse/src/path/comments.ts +++ b/packages/babel-traverse/src/path/comments.ts @@ -48,7 +48,7 @@ export function addComment( export function addComments( this: NodePath, type: t.CommentTypeShorthand, - comments: readonly t.Comment[], + comments: t.Comment[], ) { _addComments(this.node, type, comments); } diff --git a/packages/babel-traverse/src/path/context.ts b/packages/babel-traverse/src/path/context.ts index f6cba6fe1b4f..de5d4bbc7d35 100644 --- a/packages/babel-traverse/src/path/context.ts +++ b/packages/babel-traverse/src/path/context.ts @@ -4,6 +4,7 @@ import { traverseNode } from "../traverse-node"; import { SHOULD_SKIP, SHOULD_STOP } from "./index"; import type TraversalContext from "../context"; import type NodePath from "./index"; +import type * as t from "@babel/types"; export function call(this: NodePath, key: string): boolean { const opts = this.opts; @@ -152,7 +153,10 @@ export function setScope(this: NodePath) { if (this.scope) this.scope.init(); } -export function setContext(this: NodePath, context?: TraversalContext) { +export function setContext( + this: NodePath, + context?: TraversalContext, +) { if (this.skipKeys != null) { this.skipKeys = {}; } @@ -194,7 +198,13 @@ export function _resyncParent(this: NodePath) { export function _resyncKey(this: NodePath) { if (!this.container) return; - if (this.node === this.container[this.key]) return; + if ( + this.node === + // @ts-expect-error this.key should present in this.container + this.container[this.key] + ) { + return; + } // grrr, path key is out of sync. this is likely due to a modification to the AST // not done through our path APIs @@ -207,6 +217,7 @@ export function _resyncKey(this: NodePath) { } } else { for (const key of Object.keys(this.container)) { + // @ts-expect-error this.key should present in this.container if (this.container[key] === this.node) { return this.setKey(key); } @@ -220,7 +231,9 @@ export function _resyncKey(this: NodePath) { export function _resyncList(this: NodePath) { if (!this.parent || !this.inList) return; - const newContainer = this.parent[this.listKey]; + const newContainer = + // @ts-expect-error this.listKey should present in this.parent + this.parent[this.listKey]; if (this.container === newContainer) return; // container is out of sync. this is likely the result of it being reassigned @@ -231,6 +244,7 @@ export function _resyncRemoved(this: NodePath) { if ( this.key == null || !this.container || + // @ts-expect-error this.key should present in this.container this.container[this.key] !== this.node ) { this._markRemoved(); @@ -251,7 +265,13 @@ export function pushContext(this: NodePath, context: TraversalContext) { this.setContext(context); } -export function setup(this: NodePath, parentPath, container, listKey, key) { +export function setup( + this: NodePath, + parentPath: NodePath | undefined, + container: t.Node, + listKey: string, + key: string | number, +) { this.listKey = listKey; this.container = container; @@ -259,9 +279,11 @@ export function setup(this: NodePath, parentPath, container, listKey, key) { this.setKey(key); } -export function setKey(this: NodePath, key) { +export function setKey(this: NodePath, key: string | number) { this.key = key; - this.node = this.container[this.key]; + this.node = + // @ts-expect-error this.key must present in this.container + this.container[this.key]; this.type = this.node?.type; } diff --git a/packages/babel-traverse/src/path/conversion.ts b/packages/babel-traverse/src/path/conversion.ts index e2740d9c19cd..d5156950d232 100644 --- a/packages/babel-traverse/src/path/conversion.ts +++ b/packages/babel-traverse/src/path/conversion.ts @@ -94,7 +94,10 @@ export function ensureBlock( const parentPath = this.get(stringPath) as NodePath; body.setup( parentPath, - listKey ? parentPath.node[listKey] : parentPath.node, + listKey + ? // @ts-expect-error listKey must present in parent path + parentPath.node[listKey] + : parentPath.node, listKey, key, ); @@ -136,7 +139,7 @@ export function unwrapFunctionEnvironment(this: NodePath) { * Convert a given arrow function into a normal ES5 function expression. */ export function arrowFunctionToExpression( - this: NodePath, + this: NodePath, { allowInsertArrow = true, /** @deprecated Use `noNewArrows` instead */ @@ -150,7 +153,7 @@ export function arrowFunctionToExpression( } = {}, ) { if (!this.isArrowFunctionExpression()) { - throw this.buildCodeFrameError( + throw (this as NodePath).buildCodeFrameError( "Cannot convert non-arrow function to a function expression.", ); } @@ -161,6 +164,7 @@ export function arrowFunctionToExpression( allowInsertArrow, ); + // @ts-expect-error TS requires explicit fn type annotation fn.ensureBlock(); fn.node.type = "FunctionExpression"; if (!noNewArrows) { @@ -174,7 +178,7 @@ export function arrowFunctionToExpression( }); } - fn.get("body").unshiftContainer( + (fn.get("body") as NodePath).unshiftContainer( "body", expressionStatement( callExpression(this.hub.addHelper("newArrowCheck"), [ @@ -189,6 +193,7 @@ export function arrowFunctionToExpression( fn.replaceWith( callExpression( memberExpression( + // @ts-expect-error TS can't infer nameFunction returns CallExpression | ArrowFunctionExpression here nameFunction(this, true) || fn.node, identifier("bind"), ), @@ -225,7 +230,7 @@ function hoistFunctionEnvironment( allowInsertArrow: boolean | void = true, ): { thisBinding: string; fnPath: NodePath } { let arrowParent; - let thisEnvFn = fnPath.findParent(p => { + let thisEnvFn: NodePath = fnPath.findParent(p => { if (p.isArrowFunctionExpression()) { arrowParent ??= p; return false; @@ -236,7 +241,7 @@ function hoistFunctionEnvironment( p.isClassProperty({ static: false }) || p.isClassPrivateProperty({ static: false }) ); - }); + }) as NodePath; const inConstructor = thisEnvFn.isClassMethod({ kind: "constructor" }); if (thisEnvFn.isClassProperty() || thisEnvFn.isClassPrivateProperty()) { @@ -253,8 +258,8 @@ function hoistFunctionEnvironment( [], ), ); - thisEnvFn = fnPath.get("callee"); - fnPath = thisEnvFn.get("body"); + thisEnvFn = fnPath.get("callee") as NodePath; + fnPath = thisEnvFn.get("body") as NodePath; } else { throw fnPath.buildCodeFrameError( "Unable to transform arrow inside class property", @@ -332,7 +337,7 @@ function hoistFunctionEnvironment( ); } - const flatSuperProps = superProps.reduce( + const flatSuperProps: NodePath[] = superProps.reduce( (acc, superProp) => acc.concat(standardizeSuperProperty(superProp)), [], ); @@ -340,36 +345,42 @@ function hoistFunctionEnvironment( flatSuperProps.forEach(superProp => { const key = superProp.node.computed ? "" - : superProp.get("property").node.name; + : // @ts-expect-error super property must not contain private name + superProp.get("property").node.name; + + const superParentPath = superProp.parentPath; - const isAssignment = superProp.parentPath.isAssignmentExpression({ + const isAssignment = superParentPath.isAssignmentExpression({ left: superProp.node, }); - const isCall = superProp.parentPath.isCallExpression({ + const isCall = superParentPath.isCallExpression({ callee: superProp.node, }); const superBinding = getSuperPropBinding(thisEnvFn, isAssignment, key); - const args = []; + const args: t.Expression[] = []; if (superProp.node.computed) { - args.push(superProp.get("property").node); + // SuperProperty must not be a private name + args.push(superProp.get("property").node as t.Expression); } if (isAssignment) { - const value = superProp.parentPath.node.right; + const value = superParentPath.node.right; args.push(value); } const call = callExpression(identifier(superBinding), args); if (isCall) { - superProp.parentPath.unshiftContainer("arguments", thisExpression()); + superParentPath.unshiftContainer("arguments", thisExpression()); superProp.replaceWith(memberExpression(call, identifier("call"))); - thisPaths.push(superProp.parentPath.get("arguments.0")); + thisPaths.push( + superParentPath.get("arguments.0") as NodePath, + ); } else if (isAssignment) { // Replace not only the super.prop, but the whole assignment - superProp.parentPath.replaceWith(call); + superParentPath.replaceWith(call); } else { superProp.replaceWith(call); } @@ -377,7 +388,7 @@ function hoistFunctionEnvironment( } // Convert all "this" references in the arrow to point at the alias. - let thisBinding; + let thisBinding: string | null; if (thisPaths.length > 0 || !noNewArrows) { thisBinding = getThisBinding(thisEnvFn, inConstructor); @@ -410,7 +421,11 @@ function isLogicalOp(op: string): op is LogicalOp { return LOGICAL_OPERATORS.includes(op); } -function standardizeSuperProperty(superProp: NodePath) { +function standardizeSuperProperty( + superProp: NodePath, +): + | [NodePath] + | [NodePath, NodePath] { if ( superProp.parentPath.isAssignmentExpression() && superProp.parentPath.node.operator !== "=" @@ -485,7 +500,7 @@ function standardizeSuperProperty(superProp: NodePath) { assignmentPath.replaceWith( logicalExpression( op, - assignmentPath.node.left as t.Expression, + assignmentPath.node.left as t.MemberExpression, assignmentPath.node.right as t.Expression, ), ); @@ -494,7 +509,7 @@ function standardizeSuperProperty(superProp: NodePath) { } return [ - assignmentPath.get("left"), + assignmentPath.get("left") as NodePath, assignmentPath.get("right").get("left"), ]; } else if (superProp.parentPath.isUpdateExpression()) { @@ -543,8 +558,12 @@ function standardizeSuperProperty(superProp: NodePath) { updateExpr.replaceWith(sequenceExpression(parts)); - const left = updateExpr.get("expressions.0.right"); - const right = updateExpr.get("expressions.1.left"); + const left = updateExpr.get( + "expressions.0.right", + ) as NodePath; + const right = updateExpr.get( + "expressions.1.left", + ) as NodePath; return [left, right]; } @@ -563,10 +582,10 @@ function standardizeSuperProperty(superProp: NodePath) { } } -function hasSuperClass(thisEnvFn) { +function hasSuperClass(thisEnvFn: NodePath) { return ( thisEnvFn.isClassMethod() && - !!thisEnvFn.parentPath.parentPath.node.superClass + !!(thisEnvFn.parentPath.parentPath.node as t.Class).superClass ); } @@ -590,7 +609,10 @@ const assignSuperThisVisitor = mergeVisitors<{ ]); // Create a binding that evaluates to the "this" of the given function. -function getThisBinding(thisEnvFn, inConstructor) { +function getThisBinding( + thisEnvFn: NodePath, + inConstructor: boolean, +) { return getBinding(thisEnvFn, "this", thisBinding => { if (!inConstructor || !hasSuperClass(thisEnvFn)) return thisExpression(); @@ -602,7 +624,7 @@ function getThisBinding(thisEnvFn, inConstructor) { } // Create a binding for a function that will call "super()" with arguments passed through. -function getSuperBinding(thisEnvFn) { +function getSuperBinding(thisEnvFn: NodePath) { return getBinding(thisEnvFn, "supercall", () => { const argsBinding = thisEnvFn.scope.generateUidIdentifier("args"); return arrowFunctionExpression( @@ -613,7 +635,11 @@ function getSuperBinding(thisEnvFn) { } // Create a binding for a function that will call "super.foo" or "super[foo]". -function getSuperPropBinding(thisEnvFn, isAssignment, propName) { +function getSuperPropBinding( + thisEnvFn: NodePath, + isAssignment: boolean, + propName: string, +) { const op = isAssignment ? "set" : "get"; return getBinding(thisEnvFn, `superprop_${op}:${propName || ""}`, () => { @@ -645,9 +671,13 @@ function getSuperPropBinding(thisEnvFn, isAssignment, propName) { }); } -function getBinding(thisEnvFn, key, init) { +function getBinding( + thisEnvFn: NodePath, + key: string, + init: (name: string) => t.Expression, +) { const cacheKey = "binding:" + key; - let data = thisEnvFn.getData(cacheKey); + let data: string | undefined = thisEnvFn.getData(cacheKey); if (!data) { const id = thisEnvFn.scope.generateUidIdentifier(key); data = id.name; @@ -662,13 +692,15 @@ function getBinding(thisEnvFn, key, init) { return data; } -const getScopeInformationVisitor = mergeVisitors<{ +type ScopeInfo = { thisPaths: NodePath[]; superCalls: NodePath[]; superProps: NodePath[]; argumentsPaths: NodePath[]; newTargetPaths: NodePath[]; -}>([ +}; + +const getScopeInformationVisitor = mergeVisitors([ { ThisExpression(child, { thisPaths }) { thisPaths.push(child); @@ -716,12 +748,12 @@ const getScopeInformationVisitor = mergeVisitors<{ environmentVisitor, ]); -function getScopeInformation(fnPath) { - const thisPaths = []; - const argumentsPaths = []; - const newTargetPaths = []; - const superProps = []; - const superCalls = []; +function getScopeInformation(fnPath: NodePath) { + const thisPaths: ScopeInfo["thisPaths"] = []; + const argumentsPaths: ScopeInfo["argumentsPaths"] = []; + const newTargetPaths: ScopeInfo["newTargetPaths"] = []; + const superProps: ScopeInfo["superProps"] = []; + const superCalls: ScopeInfo["superCalls"] = []; fnPath.traverse(getScopeInformationVisitor, { thisPaths, diff --git a/packages/babel-traverse/src/path/evaluation.ts b/packages/babel-traverse/src/path/evaluation.ts index 89541ccd78c8..0accebc030ae 100644 --- a/packages/babel-traverse/src/path/evaluation.ts +++ b/packages/babel-traverse/src/path/evaluation.ts @@ -1,9 +1,24 @@ import type NodePath from "./index"; +import type * as t from "@babel/types"; // This file contains Babels metainterpreter that can evaluate static code. -const VALID_CALLEES = ["String", "Number", "Math"]; -const INVALID_METHODS = ["random"]; +const VALID_CALLEES = ["String", "Number", "Math"] as const; +const INVALID_METHODS = ["random"] as const; + +function isValidCallee(val: string): val is typeof VALID_CALLEES[number] { + return VALID_CALLEES.includes( + // @ts-expect-error + val, + ); +} + +function isInvalidMethod(val: string): val is typeof INVALID_METHODS[number] { + return INVALID_METHODS.includes( + // @ts-expect-error + val, + ); +} /** * Walk the input `node` and statically evaluate if it's truthy. @@ -28,10 +43,20 @@ export function evaluateTruthy(this: NodePath): boolean { if (res.confident) return !!res.value; } +type State = { + confident: boolean; + deoptPath: NodePath | null; + seen: Map; +}; + +type Result = { + resolved: boolean; + value?: any; +}; /** * Deopts the evaluation */ -function deopt(path, state) { +function deopt(path: NodePath, state: State) { if (!state.confident) return; state.deoptPath = path; state.confident = false; @@ -45,7 +70,7 @@ function deopt(path, state) { * var g = a ? 1 : 2, * a = g * this.foo */ -function evaluateCached(path: NodePath, state) { +function evaluateCached(path: NodePath, state: State): any { const { node } = path; const { seen } = state; @@ -58,8 +83,7 @@ function evaluateCached(path: NodePath, state) { return; } } else { - // todo: create type annotation for state instead - const item: { resolved: boolean; value?: any } = { resolved: false }; + const item: Result = { resolved: false }; seen.set(node, item); const val = _evaluate(path, state); @@ -71,7 +95,7 @@ function evaluateCached(path: NodePath, state) { } } -function _evaluate(path: NodePath, state) { +function _evaluate(path: NodePath, state: State): any { if (!state.confident) return; if (path.isSequenceExpression()) { @@ -256,6 +280,7 @@ function _evaluate(path: NodePath, state) { return deopt(value.deopt, state); } value = value.value; + // @ts-expect-error obj[key] = value; } return obj; @@ -346,7 +371,7 @@ function _evaluate(path: NodePath, state) { if ( callee.isIdentifier() && !path.scope.getBinding(callee.node.name) && - VALID_CALLEES.indexOf(callee.node.name) >= 0 + isValidCallee(callee.node.name) ) { func = global[callee.node.name]; } @@ -359,10 +384,11 @@ function _evaluate(path: NodePath, state) { if ( object.isIdentifier() && property.isIdentifier() && - VALID_CALLEES.indexOf(object.node.name) >= 0 && - INVALID_METHODS.indexOf(property.node.name) < 0 + isValidCallee(object.node.name) && + !isInvalidMethod(property.node.name) ) { context = global[object.node.name]; + // @ts-ignore property may not exist in context object func = context[property.node.name]; } @@ -389,7 +415,12 @@ function _evaluate(path: NodePath, state) { deopt(path, state); } -function evaluateQuasis(path, quasis: Array, state, raw = false) { +function evaluateQuasis( + path: NodePath, + quasis: Array, + state: State, + raw = false, +) { let str = ""; let i = 0; @@ -432,7 +463,7 @@ export function evaluate(this: NodePath): { value: any; deopt?: NodePath; } { - const state = { + const state: State = { confident: true, deoptPath: null, seen: new Map(), diff --git a/packages/babel-traverse/src/path/index.ts b/packages/babel-traverse/src/path/index.ts index 4b999a3ab1da..ec9dceeaf560 100644 --- a/packages/babel-traverse/src/path/index.ts +++ b/packages/babel-traverse/src/path/index.ts @@ -43,7 +43,8 @@ class NodePath { declare parent: t.Node; declare hub: HubInterface; - declare data: object; + declare data: Record; + // TraversalContext is configured by setContext declare context: TraversalContext; declare scope: Scope; @@ -54,7 +55,7 @@ class NodePath { _traverseFlags: number = 0; skipKeys: any = null; parentPath: NodePath | null = null; - container: object | null | Array = null; + container: t.Node | Array | null = null; listKey: string | null = null; key: string | number | null = null; node: T = null; @@ -68,12 +69,12 @@ class NodePath { listKey, key, }: { - hub?; - parentPath; - parent; - container; - listKey?; - key; + hub?: HubInterface; + parentPath: NodePath | null; + parent: t.Node; + container: t.Node | t.Node[]; + listKey?: string; + key: string | number; }): NodePath { if (!hub && parentPath) { hub = parentPath.hub; @@ -83,7 +84,9 @@ class NodePath { throw new Error("To get a node path the parent needs to exist"); } - const targetNode = container[key]; + const targetNode = + // @ts-ignore key must present in container + container[key]; let paths = pathCache.get(parent); if (!paths) { @@ -102,7 +105,7 @@ class NodePath { return path; } - getScope(scope: Scope) { + getScope(scope: Scope): Scope { return this.isScope() ? new Scope(this) : scope; } @@ -141,6 +144,7 @@ class NodePath { set(key: string, node: any) { validate(this.node, key, node); + // @ts-expect-error key must present in this.node this.node[key] = node; } @@ -155,7 +159,7 @@ class NodePath { return parts.join("."); } - debug(message) { + debug(message: string) { if (!debug.enabled) return; debug(`${this.getPathLocation()} ${this.type}: ${message}`); } @@ -175,8 +179,8 @@ class NodePath { // ignore inList = true as it should depend on `listKey` } - get parentKey() { - return this.listKey || this.key; + get parentKey(): string { + return (this.listKey || this.key) as string; } get shouldSkip() { @@ -245,25 +249,29 @@ if (!process.env.BABEL_8_BREAKING) { // we can change to `import { TYPES }` when we are publishing ES modules only for (const type of t.TYPES) { const typeKey = `is${type}`; + // @ts-expect-error typeKey must present in t const fn = t[typeKey]; - NodePath.prototype[typeKey] = function (opts) { + // @ts-expect-error augmenting NodePath prototype + NodePath.prototype[typeKey] = function (opts: any) { return fn(this.node, opts); }; - NodePath.prototype[`assert${type}`] = function (opts) { + // @ts-expect-error augmenting NodePath prototype + NodePath.prototype[`assert${type}`] = function (opts: any) { if (!fn(this.node, opts)) { throw new TypeError(`Expected node path of type ${type}`); } }; } -for (const type of Object.keys(virtualTypes)) { +for (const type of Object.keys(virtualTypes) as (keyof typeof virtualTypes)[]) { if (type[0] === "_") continue; if (t.TYPES.indexOf(type) < 0) t.TYPES.push(type); const virtualType = virtualTypes[type]; NodePath.prototype[`is${type}`] = function (opts) { + // @ts-expect-error checkPath will throw when type is ExistentialTypeParam/NumericLiteralTypeAnnotation return virtualType.checkPath(this, opts); }; } @@ -280,10 +288,28 @@ type NodePathMixins = typeof NodePath_ancestry & typeof NodePath_family & typeof NodePath_comments; +// @ts-ignore TS throws because ensureBlock returns the body node path +// however, we don't use the return value and treat it as a transform and +// assertion utilities. For better type inference we annotate it as an +// assertion method // eslint-disable-next-line @typescript-eslint/no-unused-vars interface NodePath extends NodePathAssetions, NodePathValidators, - NodePathMixins {} + NodePathMixins { + /** + * @see ./conversion.ts for implementation + */ + ensureBlock< + T extends + | t.Loop + | t.WithStatement + | t.Function + | t.LabeledStatement + | t.CatchClause, + >( + this: NodePath, + ): asserts this is NodePath; +} export default NodePath; diff --git a/packages/babel-traverse/src/path/inference/index.ts b/packages/babel-traverse/src/path/inference/index.ts index 384ee29d3e42..ccc073292ccb 100644 --- a/packages/babel-traverse/src/path/inference/index.ts +++ b/packages/babel-traverse/src/path/inference/index.ts @@ -81,11 +81,14 @@ export function _getTypeAnnotation(this: NodePath): any { typeAnnotationInferringNodes.add(node); try { - let inferer = inferers[node.type]; + let inferer = + // @ts-expect-error inferers do not cover all AST types + inferers[node.type]; if (inferer) { return inferer.call(this, node); } + // @ts-expect-error inferers do not cover all AST types inferer = inferers[this.parentPath.type]; if (inferer?.validParent) { return this.parentPath.getTypeAnnotation(); @@ -103,7 +106,11 @@ export function isBaseType( return _isBaseType(baseName, this.getTypeAnnotation(), soft); } -function _isBaseType(baseName: string, type?, soft?): boolean { +function _isBaseType( + baseName: string, + type?: t.FlowType, + soft?: boolean, +): boolean { if (baseName === "string") { return isStringTypeAnnotation(type); } else if (baseName === "number") { diff --git a/packages/babel-traverse/src/path/inference/inferer-reference.ts b/packages/babel-traverse/src/path/inference/inferer-reference.ts index 5882abf9107f..baf9ecf17000 100644 --- a/packages/babel-traverse/src/path/inference/inferer-reference.ts +++ b/packages/babel-traverse/src/path/inference/inferer-reference.ts @@ -12,7 +12,7 @@ import { import type * as t from "@babel/types"; import type Binding from "../../scope/binding"; -export default function (this: NodePath, node: any) { +export default function (this: NodePath, node: t.Identifier) { if (!this.isReferenced()) return; // check if a binding exists of this value and if so then return a union type of all @@ -40,10 +40,14 @@ export default function (this: NodePath, node: any) { } } -function getTypeAnnotationBindingConstantViolations(binding, path, name) { +function getTypeAnnotationBindingConstantViolations( + binding: Binding, + path: NodePath, + name: string, +) { const types = []; - const functionConstantViolations = []; + const functionConstantViolations: NodePath[] = []; let constantViolations = getConstantViolationsBefore( binding, path, @@ -107,17 +111,24 @@ function getTypeAnnotationBindingConstantViolations(binding, path, name) { } if (isTSTypeAnnotation(types[0]) && createTSUnionType) { - return createTSUnionType(types); + return createTSUnionType( + // @ts-ignore fixme: createTSUnionType should handle voidTypeAnnotation + types as t.TSTypeAnnotation[], + ); } if (createFlowUnionType) { - return createFlowUnionType(types); + return createFlowUnionType(types as t.FlowType[]); } - return createUnionTypeAnnotation(types); + return createUnionTypeAnnotation(types as t.FlowType[]); } -function getConstantViolationsBefore(binding: Binding, path, functions?) { +function getConstantViolationsBefore( + binding: Binding, + path: NodePath, + functions?: NodePath[], +) { const violations = binding.constantViolations.slice(); violations.unshift(binding.path); return violations.filter(violation => { @@ -186,7 +197,11 @@ function inferAnnotationFromBinaryExpression( return createTypeAnnotationBasedOnTypeof(typeValue); } -function getParentConditionalPath(binding, path, name) { +function getParentConditionalPath( + binding: Binding, + path: NodePath, + name: string, +) { let parentPath; while ((parentPath = path.parentPath)) { if (parentPath.isIfStatement() || parentPath.isConditionalExpression()) { @@ -194,7 +209,7 @@ function getParentConditionalPath(binding, path, name) { return; } - return parentPath; + return parentPath as NodePath; } if (parentPath.isFunction()) { if (parentPath.parentPath.scope.getBinding(name) !== binding) return; @@ -207,8 +222,11 @@ function getParentConditionalPath(binding, path, name) { function getConditionalAnnotation( binding: Binding, path: NodePath, - name?, -) { + name?: string, +): { + typeAnnotation: t.FlowType | t.TSType; + ifStatement: NodePath; +} { const ifStatement = getParentConditionalPath(binding, path, name); if (!ifStatement) return; @@ -233,7 +251,10 @@ function getConditionalAnnotation( if (types.length) { if (isTSTypeAnnotation(types[0]) && createTSUnionType) { return { - typeAnnotation: createTSUnionType(types), + typeAnnotation: createTSUnionType( + // @ts-ignore fixme: createTSUnionType should handle voidTypeAnnotation + types as t.TSTypeAnnotation[], + ), ifStatement, }; } @@ -251,5 +272,5 @@ function getConditionalAnnotation( }; } - return getConditionalAnnotation(ifStatement, name); + return getConditionalAnnotation(binding, ifStatement, name); } diff --git a/packages/babel-traverse/src/path/inference/inferers.ts b/packages/babel-traverse/src/path/inference/inferers.ts index 14e95ebd99f5..c2d0813029be 100644 --- a/packages/babel-traverse/src/path/inference/inferers.ts +++ b/packages/babel-traverse/src/path/inference/inferers.ts @@ -49,14 +49,17 @@ export function VariableDeclarator(this: NodePath) { return type; } -export function TypeCastExpression(node) { +export function TypeCastExpression(node: t.TypeCastExpression) { return node.typeAnnotation; } TypeCastExpression.validParent = true; -export function NewExpression(this: NodePath, node) { - if (this.get("callee").isIdentifier()) { +export function NewExpression( + this: NodePath, + node: t.NewExpression, +) { + if (node.callee.type === "Identifier") { // only resolve identifier callee return genericTypeAnnotation(node.callee); } @@ -66,7 +69,7 @@ export function TemplateLiteral() { return stringTypeAnnotation(); } -export function UnaryExpression(node) { +export function UnaryExpression(node: t.UnaryExpression) { const operator = node.operator; if (operator === "void") { @@ -80,7 +83,10 @@ export function UnaryExpression(node) { } } -export function BinaryExpression(this: NodePath, node) { +export function BinaryExpression( + this: NodePath, + node: t.BinaryExpression, +) { const operator = node.operator; if (NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) { @@ -157,7 +163,10 @@ export function AssignmentExpression(this: NodePath) { return this.get("right").getTypeAnnotation(); } -export function UpdateExpression(this: NodePath, node) { +export function UpdateExpression( + this: NodePath, + node: t.UpdateExpression, +) { const operator = node.operator; if (operator === "++" || operator === "--") { return numberTypeAnnotation(); @@ -235,7 +244,7 @@ export function TaggedTemplateExpression( return resolveCall(this.get("tag")); } -function resolveCall(callee) { +function resolveCall(callee: NodePath) { callee = callee.resolve(); if (callee.isFunction()) { diff --git a/packages/babel-traverse/src/path/introspection.ts b/packages/babel-traverse/src/path/introspection.ts index 0fbf09a5b7d8..8fc635d7c6c6 100644 --- a/packages/babel-traverse/src/path/introspection.ts +++ b/packages/babel-traverse/src/path/introspection.ts @@ -35,7 +35,10 @@ export function matchesPattern( */ export function has(this: NodePath, key: string): boolean { - const val = this.node && this.node[key]; + const val = + this.node && + // @ts-ignore + this.node[key]; if (val && Array.isArray(val)) { return !!val.length; } else { @@ -69,7 +72,8 @@ export function isnt(this: NodePath, key: string): boolean { * Check whether the path node `key` strict equals `value`. */ -export function equals(this: NodePath, key: string, value): boolean { +export function equals(this: NodePath, key: string, value: any): boolean { + // @ts-ignore return this.node[key] === value; } @@ -249,15 +253,18 @@ export function getSource(this: NodePath): string { return ""; } -export function willIMaybeExecuteBefore(this: NodePath, target): boolean { +export function willIMaybeExecuteBefore( + this: NodePath, + target: NodePath, +): boolean { return this._guessExecutionStatusRelativeTo(target) !== "after"; } -function getOuterFunction(path) { +function getOuterFunction(path: NodePath) { return (path.scope.getFunctionParent() || path.scope.getProgramParent()).path; } -function isExecutionUncertain(type, key) { +function isExecutionUncertain(type: t.Node["type"], key: string) { switch (type) { // a && FOO // a || FOO @@ -306,7 +313,7 @@ function isExecutionUncertain(type, key) { } } -function isExecutionUncertainInList(paths, maxIndex) { +function isExecutionUncertainInList(paths: NodePath[], maxIndex: number) { for (let i = 0; i < maxIndex; i++) { const path = paths[i]; if (isExecutionUncertain(path.parent.type, path.parentKey)) { @@ -509,14 +516,18 @@ function _guessExecutionStatusRelativeToDifferentFunctionsCached( /** * Resolve a "pointer" `NodePath` to it's absolute path. */ -export function resolve(this: NodePath, dangerous?, resolved?) { +export function resolve( + this: NodePath, + dangerous?: boolean, + resolved?: NodePath[], +) { return this._resolve(dangerous, resolved) || this; } export function _resolve( this: NodePath, - dangerous?, - resolved?, + dangerous?: boolean, + resolved?: NodePath[], ): NodePath | undefined | null { // detect infinite recursion // todo: possibly have a max length on this just to be safe @@ -587,7 +598,7 @@ export function _resolve( } } -export function isConstantExpression(this: NodePath) { +export function isConstantExpression(this: NodePath): boolean { if (this.isIdentifier()) { const binding = this.scope.getBinding(this.node.name); if (!binding) return false; diff --git a/packages/babel-traverse/src/path/lib/hoister.ts b/packages/babel-traverse/src/path/lib/hoister.ts index 635b78f2feb3..c0876436d1f5 100644 --- a/packages/babel-traverse/src/path/lib/hoister.ts +++ b/packages/babel-traverse/src/path/lib/hoister.ts @@ -87,7 +87,7 @@ export default class PathHoister { } // A scope is compatible if all required bindings are reachable. - isCompatibleScope(scope) { + isCompatibleScope(scope: Scope) { for (const key of Object.keys(this.bindings)) { const binding = this.bindings[key]; if (!scope.bindingIdentifierEquals(key, binding.identifier)) { @@ -198,7 +198,7 @@ export default class PathHoister { } // Find an attachment for this path. - getAttachmentParentForPath(path) { + getAttachmentParentForPath(path: NodePath) { do { if ( // Beginning of the scope @@ -212,7 +212,7 @@ export default class PathHoister { } // Returns true if a scope has param bindings. - hasOwnParamBindings(scope) { + hasOwnParamBindings(scope: Scope) { for (const name of Object.keys(this.bindings)) { if (!scope.hasOwnBinding(name)) continue; @@ -238,7 +238,8 @@ export default class PathHoister { if (attachTo.getFunctionParent() === this.path.getFunctionParent()) return; // generate declaration and insert it to our point - let uid = attachTo.scope.generateUidIdentifier("ref"); + let uid: t.Identifier | t.JSXExpressionContainer = + attachTo.scope.generateUidIdentifier("ref"); // @ts-expect-error todo(flow->ts): more specific type for this.path const declarator = variableDeclarator(uid, this.path.node); diff --git a/packages/babel-traverse/src/path/lib/removal-hooks.ts b/packages/babel-traverse/src/path/lib/removal-hooks.ts index 20d7fba20e6e..7872299b4f0c 100644 --- a/packages/babel-traverse/src/path/lib/removal-hooks.ts +++ b/packages/babel-traverse/src/path/lib/removal-hooks.ts @@ -1,11 +1,13 @@ // this file contains hooks that handle ancestry cleanup of parent nodes when removing children +import NodePath from ".."; +import type * as t from "@babel/types"; /** * Pre hooks should be used for either rejecting removal or delegating removal */ export const hooks = [ - function (self, parent) { + function (self: NodePath, parent: NodePath) { const removeParent = // while (NODE); // removing the test of a while/switch, we can either just remove it entirely *or* turn the @@ -33,7 +35,7 @@ export const hooks = [ } }, - function (self, parent) { + function (self: NodePath, parent: NodePath) { if (parent.isSequenceExpression() && parent.node.expressions.length === 1) { // (node, NODE); // we've just removed the second element of a sequence expression so let's turn that sequence @@ -43,7 +45,7 @@ export const hooks = [ } }, - function (self, parent) { + function (self: NodePath, parent: NodePath) { if (parent.isBinary()) { // left + NODE; // NODE + right; @@ -58,7 +60,7 @@ export const hooks = [ } }, - function (self, parent) { + function (self: NodePath, parent: NodePath) { if ( (parent.isIfStatement() && (self.key === "consequent" || self.key === "alternate")) || @@ -68,7 +70,7 @@ export const hooks = [ self.replaceWith({ type: "BlockStatement", body: [], - }); + } as t.BlockStatement); return true; } }, diff --git a/packages/babel-traverse/src/path/lib/virtual-types.ts b/packages/babel-traverse/src/path/lib/virtual-types.ts index d08fd554eeef..3acf1ba5ebba 100644 --- a/packages/babel-traverse/src/path/lib/virtual-types.ts +++ b/packages/babel-traverse/src/path/lib/virtual-types.ts @@ -23,7 +23,14 @@ import { import type * as t from "@babel/types"; const { isCompatTag } = react; -export const ReferencedIdentifier = { +type NodeTypes = t.Node["type"] | t.Comment["type"] | keyof t.Aliases; + +export type Wrapper = { + types?: NodeTypes[]; + checkPath?(path: NodePath): boolean; +}; + +export const ReferencedIdentifier: Wrapper = { types: ["Identifier", "JSXIdentifier"], checkPath(path: NodePath, opts?: any): boolean { const { node, parent } = path; @@ -41,14 +48,14 @@ export const ReferencedIdentifier = { }, }; -export const ReferencedMemberExpression = { +export const ReferencedMemberExpression: Wrapper = { types: ["MemberExpression"], - checkPath({ node, parent }) { + checkPath({ node, parent }: NodePath) { return isMemberExpression(node) && isReferenced(node, parent); }, }; -export const BindingIdentifier = { +export const BindingIdentifier: Wrapper = { types: ["Identifier"], checkPath(path: NodePath): boolean { const { node, parent } = path; @@ -57,7 +64,7 @@ export const BindingIdentifier = { }, }; -export const Statement = { +export const Statement: Wrapper = { types: ["Statement"], checkPath({ node, parent }: NodePath): boolean { if (isStatement(node)) { @@ -73,7 +80,7 @@ export const Statement = { }, }; -export const Expression = { +export const Expression: Wrapper = { types: ["Expression"], checkPath(path: NodePath): boolean { if (path.isIdentifier()) { @@ -84,52 +91,52 @@ export const Expression = { }, }; -export const Scope = { +export const Scope: Wrapper = { // When pattern is inside the function params, it is a scope types: ["Scopable", "Pattern"], - checkPath(path) { + checkPath(path: NodePath) { return isScope(path.node, path.parent); }, }; -export const Referenced = { +export const Referenced: Wrapper = { checkPath(path: NodePath): boolean { return isReferenced(path.node, path.parent); }, }; -export const BlockScoped = { +export const BlockScoped: Wrapper = { checkPath(path: NodePath): boolean { return isBlockScoped(path.node); }, }; -export const Var = { +export const Var: Wrapper = { types: ["VariableDeclaration"], checkPath(path: NodePath): boolean { return isVar(path.node); }, }; -export const User = { +export const User: Wrapper = { checkPath(path: NodePath): boolean { return path.node && !!path.node.loc; }, }; -export const Generated = { +export const Generated: Wrapper = { checkPath(path: NodePath): boolean { return !path.isUser(); }, }; -export const Pure = { +export const Pure: Wrapper = { checkPath(path: NodePath, constantsOnly?: boolean): boolean { return path.scope.isPure(path.node, constantsOnly); }, }; -export const Flow = { +export const Flow: Wrapper = { types: ["Flow", "ImportDeclaration", "ExportDeclaration", "ImportSpecifier"], checkPath({ node }: NodePath): boolean { if (isFlow(node)) { @@ -147,29 +154,29 @@ export const Flow = { }; // TODO: 7.0 Backwards Compat -export const RestProperty = { +export const RestProperty: Wrapper = { types: ["RestElement"], checkPath(path: NodePath): boolean { return path.parentPath && path.parentPath.isObjectPattern(); }, }; -export const SpreadProperty = { +export const SpreadProperty: Wrapper = { types: ["RestElement"], checkPath(path: NodePath): boolean { return path.parentPath && path.parentPath.isObjectExpression(); }, }; -export const ExistentialTypeParam = { +export const ExistentialTypeParam: Wrapper = { types: ["ExistsTypeAnnotation"], }; -export const NumericLiteralTypeAnnotation = { +export const NumericLiteralTypeAnnotation: Wrapper = { types: ["NumberLiteralTypeAnnotation"], }; -export const ForAwaitStatement = { +export const ForAwaitStatement: Wrapper = { types: ["ForOfStatement"], checkPath({ node }: NodePath): boolean { return node.await === true; diff --git a/packages/babel-traverse/src/path/modification.ts b/packages/babel-traverse/src/path/modification.ts index e3308652a7c6..3b0bc6e5f36e 100644 --- a/packages/babel-traverse/src/path/modification.ts +++ b/packages/babel-traverse/src/path/modification.ts @@ -26,7 +26,10 @@ import type Scope from "../scope"; * Insert the provided nodes before the current one. */ -export function insertBefore(this: NodePath, nodes_: t.Node | t.Node[]) { +export function insertBefore( + this: NodePath, + nodes_: t.Node | t.Node[], +): NodePath[] { this._assertUnremoved(); const nodes = this._verifyNodeList(nodes_); @@ -57,7 +60,11 @@ export function insertBefore(this: NodePath, nodes_: t.Node | t.Node[]) { (node as t.ExpressionStatement).expression != null); this.replaceWith(blockStatement(shouldInsertCurrentNode ? [node] : [])); - return this.unshiftContainer("body", nodes); + return (this as NodePath).unshiftContainer( + "body", + // @ts-ignore Fixme: refine nodes to t.BlockStatement["body"] when this is a BlockStatement path + nodes, + ); } else { throw new Error( "We don't know what to do with this node type. " + @@ -66,16 +73,20 @@ export function insertBefore(this: NodePath, nodes_: t.Node | t.Node[]) { } } -export function _containerInsert(this: NodePath, from, nodes) { +export function _containerInsert( + this: NodePath, + from: number, + nodes: N[], +): NodePath[] { this.updateSiblingKeys(from, nodes.length); - const paths = []; + const paths: NodePath[] = []; // @ts-expect-error todo(flow->ts): this.container could be a NodePath this.container.splice(from, 0, ...nodes); for (let i = 0; i < nodes.length; i++) { const to = from + i; - const path = this.getSibling(to); + const path = this.getSibling(to) as NodePath; paths.push(path); if (this.context && this.context.queue) { @@ -97,18 +108,23 @@ export function _containerInsert(this: NodePath, from, nodes) { return paths; } -export function _containerInsertBefore(this: NodePath, nodes) { - return this._containerInsert(this.key, nodes); +export function _containerInsertBefore( + this: NodePath, + nodes: N[], +) { + return this._containerInsert(this.key as number, nodes); } -export function _containerInsertAfter(this: NodePath, nodes) { - // @ts-expect-error todo(flow->ts): this.key could be a string - return this._containerInsert(this.key + 1, nodes); +export function _containerInsertAfter( + this: NodePath, + nodes: N[], +) { + return this._containerInsert((this.key as number) + 1, nodes); } -const last = arr => arr[arr.length - 1]; +const last = (arr: T[]) => arr[arr.length - 1]; -function isHiddenInSequenceExpression(path: NodePath) { +function isHiddenInSequenceExpression(path: NodePath): boolean { return ( isSequenceExpression(path.parent) && (last(path.parent.expressions) !== path.node || @@ -185,7 +201,7 @@ export function insertAfter( assertExpression(node); this.replaceWith(callExpression(arrowFunctionExpression([], node), [])); - (this.get("callee.body") as NodePath).insertAfter(nodes); + (this.get("callee.body") as NodePath).insertAfter(nodes); return [this]; } @@ -233,6 +249,7 @@ export function insertAfter( (node as t.ExpressionStatement).expression != null); this.replaceWith(blockStatement(shouldInsertCurrentNode ? [node] : [])); + // @ts-ignore Fixme: refine nodes to t.BlockStatement["body"] when this is a BlockStatement path return this.pushContainer("body", nodes); } else { throw new Error( @@ -261,10 +278,10 @@ export function updateSiblingKeys( } } -export function _verifyNodeList( +export function _verifyNodeList( this: NodePath, - nodes: t.Node | t.Node[], -): t.Node[] { + nodes: N | N[], +): N[] { if (!nodes) { return []; } @@ -298,11 +315,17 @@ export function _verifyNodeList( return nodes; } -export function unshiftContainer( - this: NodePath, - listKey: string, - nodes: Nodes, -): NodePath[] { +export function unshiftContainer( + this: NodePath, + listKey: K, + nodes: N[K] extends (infer E)[] + ? E | E[] + : // todo: refine to t.Node[] + // ? E extends t.Node + // ? E | E[] + // : never + never, +) { // todo: NodePaths this._assertUnremoved(); @@ -314,22 +337,34 @@ export function unshiftContainer( const path = NodePath.get({ parentPath: this, parent: this.node, - container: this.node[listKey], + container: this.node[listKey] as unknown as t.Node | t.Node[], listKey, key: 0, }).setContext(this.context); - return path._containerInsertBefore(nodes); + return path._containerInsertBefore( + // @ts-expect-error typings needed to narrow down nodes as t.Node[] + nodes, + ); } -export function pushContainer( - this: NodePath, - listKey: string, - nodes: t.Node | t.Node[], +export function pushContainer( + this: NodePath, + listKey: K, + nodes: N[K] extends (infer E)[] + ? E | E[] + : // todo: refine to t.Node[] + // ? E extends t.Node + // ? E | E[] + // : never + never, ) { this._assertUnremoved(); - const verifiedNodes = this._verifyNodeList(nodes); + const verifiedNodes = this._verifyNodeList( + // @ts-expect-error refine typings + nodes, + ); // get an invisible path that represents the last node + 1 and replace it with our // nodes, effectively inlining it @@ -338,8 +373,9 @@ export function pushContainer( const path = NodePath.get({ parentPath: this, parent: this.node, - container: container, + container: container as unknown as t.Node | t.Node[], listKey, + // @ts-expect-error TS cannot infer that container is t.Node[] key: container.length, }).setContext(this.context); diff --git a/packages/babel-traverse/src/path/replacement.ts b/packages/babel-traverse/src/path/replacement.ts index 25dc6ad86f09..5c851f8183d5 100644 --- a/packages/babel-traverse/src/path/replacement.ts +++ b/packages/babel-traverse/src/path/replacement.ts @@ -48,7 +48,9 @@ export function replaceWithMultiple( inheritLeadingComments(nodes[0], this.node); inheritTrailingComments(nodes[nodes.length - 1], this.node); pathCache.get(this.parent)?.delete(this.node); - this.node = this.container[this.key] = null; + this.node = + // @ts-expect-error this.key must present in this.container + this.container[this.key] = null; const paths = this.insertAfter(nodes); if (this.node) { @@ -67,12 +69,13 @@ export function replaceWithMultiple( * easier to use, your transforms will be extremely brittle. */ -export function replaceWithSourceString(this: NodePath, replacement) { +export function replaceWithSourceString(this: NodePath, replacement: string) { this.resync(); + let ast: t.File; try { replacement = `(${replacement})`; - replacement = parse(replacement); + ast = parse(replacement); } catch (err) { const loc = err.loc; if (loc) { @@ -89,25 +92,30 @@ export function replaceWithSourceString(this: NodePath, replacement) { throw err; } - replacement = replacement.program.body[0].expression; - traverse.removeProperties(replacement); - return this.replaceWith(replacement); + const expressionAST = (ast.program.body[0] as t.ExpressionStatement) + .expression; + traverse.removeProperties(expressionAST); + return this.replaceWith(expressionAST); } /** * Replace the current node with another. */ -export function replaceWith(this: NodePath, replacement: t.Node | NodePath) { +export function replaceWith( + this: NodePath, + replacementPath: R | NodePath, +): [NodePath] { this.resync(); if (this.removed) { throw new Error("You can't replace this node, we've already removed it"); } - if (replacement instanceof NodePath) { - replacement = replacement.node; - } + let replacement: t.Node = + replacementPath instanceof NodePath + ? replacementPath.node + : replacementPath; if (!replacement) { throw new Error( @@ -116,7 +124,7 @@ export function replaceWith(this: NodePath, replacement: t.Node | NodePath) { } if (this.node === replacement) { - return [this]; + return [this as NodePath]; } if (this.isProgram() && !isProgram(replacement)) { @@ -157,7 +165,9 @@ export function replaceWith(this: NodePath, replacement: t.Node | NodePath) { !this.canSwapBetweenExpressionAndStatement(replacement) ) { // replacing an expression with a statement so let's explode it - return this.replaceExpressionWithStatements([replacement]); + return this.replaceExpressionWithStatements([replacement]) as [ + NodePath, + ]; } } @@ -177,14 +187,16 @@ export function replaceWith(this: NodePath, replacement: t.Node | NodePath) { // requeue for visiting this.requeue(); - return [nodePath ? this.get(nodePath) : this]; + return [ + nodePath ? (this.get(nodePath) as NodePath) : (this as NodePath), + ]; } /** * Description */ -export function _replaceWith(this: NodePath, node) { +export function _replaceWith(this: NodePath, node: t.Node) { if (!this.container) { throw new ReferenceError("Container is falsy"); } @@ -199,7 +211,9 @@ export function _replaceWith(this: NodePath, node) { this.debug(`Replace with ${node?.type}`); pathCache.get(this.parent)?.set(node, this).delete(this.node); - this.node = this.container[this.key] = node; + this.node = + // @ts-expect-error this.key must present in this.container + this.container[this.key] = node; } /** @@ -229,7 +243,9 @@ export function replaceExpressionWithStatements( this.replaceWith(callExpression(container, [])); // replaceWith changes the type of "this", but it isn't trackable by TS type ThisType = NodePath< - t.CallExpression & { callee: t.ArrowFunctionExpression } + t.CallExpression & { + callee: t.ArrowFunctionExpression & { body: t.BlockStatement }; + } >; // hoist variable declaration in do block diff --git a/packages/babel-traverse/src/scope/index.ts b/packages/babel-traverse/src/scope/index.ts index 1cfa5add854f..f2e6cff3a3b9 100644 --- a/packages/babel-traverse/src/scope/index.ts +++ b/packages/babel-traverse/src/scope/index.ts @@ -26,9 +26,11 @@ import { isMethod, isModuleDeclaration, isModuleSpecifier, + isNullLiteral, isObjectExpression, isProperty, isPureish, + isRegExpLiteral, isSuper, isTaggedTemplateExpression, isTemplateLiteral, @@ -53,8 +55,9 @@ import type * as t from "@babel/types"; import { scope as scopeCache } from "../cache"; import type { Visitor } from "../types"; +type NodePart = string | number | boolean; // Recursively gathers the identifying names of a node. -function gatherNodeParts(node: t.Node, parts: any[]) { +function gatherNodeParts(node: t.Node, parts: NodePart[]) { switch (node?.type) { default: if (isModuleDeclaration(node)) { @@ -89,14 +92,12 @@ function gatherNodeParts(node: t.Node, parts: any[]) { // allowing only nodes with `.local`? // @ts-expect-error todo(flow->ts) gatherNodeParts(node.local, parts); - } else if (isLiteral(node)) { - // todo(flow->ts): should condition be stricter to ensure value is there - // ``` - // !t.isNullLiteral(node) && - // !t.isRegExpLiteral(node) && - // !isTemplateLiteral(node) - // ``` - // @ts-expect-error todo(flow->ts) + } else if ( + isLiteral(node) && + !isNullLiteral(node) && + !isRegExpLiteral(node) && + !isTemplateLiteral(node) + ) { parts.push(node.value); } break; @@ -204,7 +205,7 @@ function gatherNodeParts(node: t.Node, parts: any[]) { break; case "JSXOpeningElement": - parts.push(node.name); + gatherNodeParts(node.name, parts); break; case "JSXFragment": @@ -353,6 +354,7 @@ const collectorVisitor: Visitor = { if ( path.isFunctionExpression() && path.has("id") && + // @ts-ignore Fixme: document symbol ast properties !path.get("id").node[NOT_LOCAL_BINDING] ) { path.scope.registerBinding("local", path.get("id"), path); @@ -360,7 +362,11 @@ const collectorVisitor: Visitor = { }, ClassExpression(path) { - if (path.has("id") && !path.get("id").node[NOT_LOCAL_BINDING]) { + if ( + path.has("id") && + // @ts-ignore Fixme: document symbol ast properties + !path.get("id").node[NOT_LOCAL_BINDING] + ) { path.scope.registerBinding("local", path); } }, @@ -374,7 +380,7 @@ export default class Scope { uid; path: NodePath; - block: t.Node; + block: t.Pattern | t.Scopable; labels; inited; @@ -382,15 +388,15 @@ export default class Scope { bindings: { [name: string]: Binding }; references: { [name: string]: true }; globals: { [name: string]: t.Identifier | t.JSXIdentifier }; - uids: { [name: string]: true }; - data: object; + uids: { [name: string]: boolean }; + data: { [key: string | symbol]: unknown }; crawling: boolean; /** * This searches the current "scope" and collects all references/bindings * within. */ - constructor(path: NodePath) { + constructor(path: NodePath) { const { node } = path; const cached = scopeCache.get(node); // Sometimes, a scopable path is placed higher in the AST tree. @@ -452,7 +458,7 @@ export default class Scope { /** * Traverse node with current scope and path. */ - traverse(node: any, opts: any, state?) { + traverse(node: any, opts: any, state?: S) { traverse(node, opts, this, state, this.path); } @@ -506,14 +512,14 @@ export default class Scope { * Generate an `_id1`. */ - _generateUid(name, i) { + _generateUid(name: string, i: number) { let id = name; if (i > 1) id += i; return `_${id}`; } generateUidBasedOnNode(node: t.Node, defaultName?: string) { - const parts = []; + const parts: NodePart[] = []; gatherNodeParts(node, parts); let id = parts.join("$"); @@ -605,7 +611,7 @@ export default class Scope { } } - rename(oldName: string, newName?: string, block?: t.Node) { + rename(oldName: string, newName?: string, block?: t.Pattern | t.Scopable) { const binding = this.getBinding(oldName); if (binding) { newName = newName || this.generateUidIdentifier(oldName).name; @@ -613,7 +619,13 @@ export default class Scope { } } - _renameFromMap(map, oldName, newName, value) { + /** @deprecated Not used in our codebase */ + _renameFromMap( + map: Record, + oldName: string | symbol, + newName: string | symbol, + value: unknown, + ) { if (map[oldName]) { map[newName] = value; map[oldName] = null; @@ -826,7 +838,7 @@ export default class Scope { return !!this.getProgramParent().references[name]; } - isPure(node: t.Node, constantsOnly?: boolean) { + isPure(node: t.Node, constantsOnly?: boolean): boolean { if (isIdentifier(node)) { const binding = this.getBinding(node.name); if (!binding) return false; @@ -1029,6 +1041,7 @@ export default class Scope { } if (path.isLoop() || path.isCatchClause() || path.isFunction()) { + // @ts-expect-error TS can not infer NodePath | NodePath as NodePath path.ensureBlock(); // @ts-expect-error todo(flow->ts): improve types path = path.get("body"); @@ -1046,7 +1059,10 @@ export default class Scope { // @ts-expect-error todo(flow->ts): avoid modifying nodes declar._blockHoist = blockHoist; - [declarPath] = path.unshiftContainer("body", [declar]); + [declarPath] = (path as NodePath).unshiftContainer( + "body", + [declar], + ); if (!unique) path.setData(dataKey, declarPath); } @@ -1218,7 +1234,7 @@ export default class Scope { return !!this.getOwnBinding(name); } - hasBinding(name: string, noGlobals?) { + hasBinding(name: string, noGlobals?: boolean) { if (!name) return false; if (this.hasOwnBinding(name)) return true; if (this.parentHasBinding(name, noGlobals)) return true; @@ -1228,7 +1244,7 @@ export default class Scope { return false; } - parentHasBinding(name: string, noGlobals?) { + parentHasBinding(name: string, noGlobals?: boolean) { return this.parent?.hasBinding(name, noGlobals); } diff --git a/packages/babel-traverse/src/scope/lib/renamer.ts b/packages/babel-traverse/src/scope/lib/renamer.ts index a2aefffab79b..d81e71b419b6 100644 --- a/packages/babel-traverse/src/scope/lib/renamer.ts +++ b/packages/babel-traverse/src/scope/lib/renamer.ts @@ -1,13 +1,7 @@ import Binding from "../binding"; import splitExportDeclaration from "@babel/helper-split-export-declaration"; -import { - assignmentExpression, - identifier, - toExpression, - variableDeclaration, - variableDeclarator, -} from "@babel/types"; -import type { Visitor } from "../../types"; +import * as t from "@babel/types"; +import type { NodePath, Visitor } from "../.."; import { requeueComputedKeyAndDecorators } from "@babel/helper-environment-visitor"; const renameVisitor: Visitor = { @@ -31,7 +25,10 @@ const renameVisitor: Visitor = { } }, - "AssignmentExpression|Declaration|VariableDeclarator"(path, state) { + "AssignmentExpression|Declaration|VariableDeclarator"( + path: NodePath, + state, + ) { if (path.isVariableDeclaration()) return; const ids = path.getOuterBindingIdentifiers(); @@ -52,63 +49,69 @@ export default class Renamer { declare newName: string; declare binding: Binding; - maybeConvertFromExportDeclaration(parentDeclar) { + maybeConvertFromExportDeclaration(parentDeclar: NodePath) { const maybeExportDeclar = parentDeclar.parentPath; if (!maybeExportDeclar.isExportDeclaration()) { return; } - if ( - maybeExportDeclar.isExportDefaultDeclaration() && - !maybeExportDeclar.get("declaration").node.id - ) { + if (maybeExportDeclar.isExportDefaultDeclaration()) { + const { declaration } = maybeExportDeclar.node; + if (t.isDeclaration(declaration) && !declaration.id) { + return; + } + } + + if (maybeExportDeclar.isExportAllDeclaration()) { return; } - splitExportDeclaration(maybeExportDeclar); + splitExportDeclaration( + maybeExportDeclar as NodePath< + Exclude + >, + ); } - maybeConvertFromClassFunctionDeclaration(path) { - return; // TODO + maybeConvertFromClassFunctionDeclaration(path: NodePath) { + return path; // TODO - // retain the `name` of a class/function declaration + // // retain the `name` of a class/function declaration - // eslint-disable-next-line no-unreachable - if (!path.isFunctionDeclaration() && !path.isClassDeclaration()) return; - if (this.binding.kind !== "hoisted") return; + // if (!path.isFunctionDeclaration() && !path.isClassDeclaration()) return; + // if (this.binding.kind !== "hoisted") return; - path.node.id = identifier(this.oldName); - path.node._blockHoist = 3; + // path.node.id = identifier(this.oldName); + // path.node._blockHoist = 3; - path.replaceWith( - variableDeclaration("let", [ - variableDeclarator(identifier(this.newName), toExpression(path.node)), - ]), - ); + // path.replaceWith( + // variableDeclaration("let", [ + // variableDeclarator(identifier(this.newName), toExpression(path.node)), + // ]), + // ); } - maybeConvertFromClassFunctionExpression(path) { - return; // TODO + maybeConvertFromClassFunctionExpression(path: NodePath) { + return path; // TODO - // retain the `name` of a class/function expression + // // retain the `name` of a class/function expression - // eslint-disable-next-line no-unreachable - if (!path.isFunctionExpression() && !path.isClassExpression()) return; - if (this.binding.kind !== "local") return; + // if (!path.isFunctionExpression() && !path.isClassExpression()) return; + // if (this.binding.kind !== "local") return; - path.node.id = identifier(this.oldName); + // path.node.id = identifier(this.oldName); - this.binding.scope.parent.push({ - id: identifier(this.newName), - }); + // this.binding.scope.parent.push({ + // id: identifier(this.newName), + // }); - path.replaceWith( - assignmentExpression("=", identifier(this.newName), path.node), - ); + // path.replaceWith( + // assignmentExpression("=", identifier(this.newName), path.node), + // ); } - rename(block?) { + rename(block?: t.Pattern | t.Scopable) { const { binding, oldName, newName } = this; const { scope, path } = binding; @@ -144,8 +147,8 @@ export default class Renamer { } if (parentDeclar) { - this.maybeConvertFromClassFunctionDeclaration(parentDeclar); - this.maybeConvertFromClassFunctionExpression(parentDeclar); + this.maybeConvertFromClassFunctionDeclaration(path); + this.maybeConvertFromClassFunctionExpression(path); } } } diff --git a/packages/babel-traverse/src/traverse-node.ts b/packages/babel-traverse/src/traverse-node.ts index 4bfd802ce75f..958664c77326 100644 --- a/packages/babel-traverse/src/traverse-node.ts +++ b/packages/babel-traverse/src/traverse-node.ts @@ -12,7 +12,7 @@ import { VISITOR_KEYS } from "@babel/types"; * @param {scope} scope A traversal scope used to create a new traversal context. When opts.noScope is true, scope should not be provided * @param {any} state A user data storage provided as the second callback argument for traversal visitors * @param {NodePath} path A NodePath of given node - * @param {string[]} skipKeys A list of key names that should be skipped during traversal. The skipKeys are applied to every descendants + * @param {Record} skipKeys A map from key names to whether that should be skipped during traversal. The skipKeys are applied to every descendants * @returns {boolean} Whether the traversal stops early * @note This function does not visit the given `node`. @@ -23,7 +23,7 @@ export function traverseNode( scope?: Scope, state?: any, path?: NodePath, - skipKeys?: string[], + skipKeys?: Record, ): boolean { const keys = VISITOR_KEYS[node.type]; if (!keys) return false; diff --git a/packages/babel-traverse/src/types.ts b/packages/babel-traverse/src/types.ts index 527de9f333ad..c0fadb16f8d4 100644 --- a/packages/babel-traverse/src/types.ts +++ b/packages/babel-traverse/src/types.ts @@ -8,10 +8,18 @@ export type Visitor = VisitNodeObject & { [K in keyof t.Aliases]?: VisitNode; } & { [K in keyof VirtualTypeAliases]?: VisitNode; +} & { + [K in keyof InternalVisitorFlags]?: InternalVisitorFlags[K]; } & { [k: string]: VisitNode; }; +/** @internal */ +type InternalVisitorFlags = { + _exploded?: boolean; + _verified?: boolean; +}; + export type VisitNode = | VisitNodeFunction | VisitNodeObject; diff --git a/packages/babel-traverse/src/visitors.ts b/packages/babel-traverse/src/visitors.ts index de2fe704b199..fe2504bdb766 100644 --- a/packages/babel-traverse/src/visitors.ts +++ b/packages/babel-traverse/src/visitors.ts @@ -1,6 +1,7 @@ import * as virtualTypes from "./path/lib/virtual-types"; +import type { Wrapper } from "./path/lib/virtual-types"; import { DEPRECATED_KEYS, FLIPPED_ALIAS_KEYS, TYPES } from "@babel/types"; -import type { Visitor } from "./types"; +import type { NodePath, Visitor } from "./index"; /** * explode() will take a visitor object with all of the various shorthands @@ -18,7 +19,7 @@ import type { Visitor } from "./types"; * * `enter` and `exit` functions are wrapped in arrays, to ease merging of * visitors */ -export function explode(visitor) { +export function explode(visitor: Visitor) { if (visitor._exploded) return visitor; visitor._exploded = true; @@ -54,12 +55,14 @@ export function explode(visitor) { for (const nodeType of Object.keys(visitor)) { if (shouldIgnoreKey(nodeType)) continue; + // @ts-expect-error Fixme: nodeType could index virtualTypes const wrapper = virtualTypes[nodeType]; if (!wrapper) continue; // wrap all the functions const fns = visitor[nodeType]; for (const type of Object.keys(fns)) { + // @ts-expect-error manipulating visitors fns[type] = wrapCheck(wrapper, fns[type]); } @@ -114,13 +117,16 @@ export function explode(visitor) { for (const nodeType of Object.keys(visitor)) { if (shouldIgnoreKey(nodeType)) continue; - ensureCallbackArrays(visitor[nodeType]); + ensureCallbackArrays( + // @ts-expect-error nodeType must present in visitor after previous validations + visitor[nodeType], + ); } return visitor; } -export function verify(visitor) { +export function verify(visitor: Visitor) { if (visitor._verified) return; if (typeof visitor === "function") { @@ -165,7 +171,10 @@ export function verify(visitor) { visitor._verified = true; } -function validateVisitorMethods(path, val) { +function validateVisitorMethods( + path: string, + val: any, +): asserts val is Function | Function[] { const fns = [].concat(val); for (const fn of fns) { if (typeof fn !== "function") { @@ -187,7 +196,7 @@ export function merge( states: any[] = [], wrapper?: Function | null, ) { - const rootVisitor = {}; + const rootVisitor: Visitor = {}; for (let i = 0; i < visitors.length; i++) { const visitor = visitors[i]; @@ -211,8 +220,12 @@ export function merge( return rootVisitor; } -function wrapWithStateOrWrapper(oldVisitor, state, wrapper?: Function | null) { - const newVisitor = {}; +function wrapWithStateOrWrapper( + oldVisitor: Visitor, + state: State, + wrapper?: Function | null, +) { + const newVisitor: Visitor = {}; for (const key of Object.keys(oldVisitor)) { let fns = oldVisitor[key]; @@ -220,16 +233,18 @@ function wrapWithStateOrWrapper(oldVisitor, state, wrapper?: Function | null) { // not an enter/exit array of callbacks if (!Array.isArray(fns)) continue; + // @ts-ignore manipulating visitors fns = fns.map(function (fn) { let newFn = fn; if (state) { - newFn = function (path) { + newFn = function (path: NodePath) { return fn.call(state, path, state); }; } if (wrapper) { + // @ts-ignore Fixme: document state.key newFn = wrapper(state.key, key, newFn); } @@ -247,7 +262,7 @@ function wrapWithStateOrWrapper(oldVisitor, state, wrapper?: Function | null) { return newVisitor; } -function ensureEntranceObjects(obj) { +function ensureEntranceObjects(obj: Visitor) { for (const key of Object.keys(obj)) { if (shouldIgnoreKey(key)) continue; @@ -258,13 +273,15 @@ function ensureEntranceObjects(obj) { } } -function ensureCallbackArrays(obj) { +function ensureCallbackArrays(obj: Visitor) { + // @ts-ignore normalizing enter property if (obj.enter && !Array.isArray(obj.enter)) obj.enter = [obj.enter]; + // @ts-ignore normalizing exit property if (obj.exit && !Array.isArray(obj.exit)) obj.exit = [obj.exit]; } -function wrapCheck(wrapper, fn) { - const newFn = function (this: unknown, path) { +function wrapCheck(wrapper: Wrapper, fn: Function) { + const newFn = function (this: unknown, path: NodePath) { if (wrapper.checkPath(path)) { return fn.apply(this, arguments); } @@ -273,7 +290,7 @@ function wrapCheck(wrapper, fn) { return newFn; } -function shouldIgnoreKey(key) { +function shouldIgnoreKey(key: string) { // internal/hidden key if (key[0] === "_") return true; @@ -294,7 +311,7 @@ function shouldIgnoreKey(key) { return false; } -function mergePair(dest, src) { +function mergePair(dest: any, src: any) { for (const key of Object.keys(src)) { dest[key] = [].concat(dest[key] || [], src[key]); } diff --git a/packages/babel-types/package.json b/packages/babel-types/package.json index 9e7a8dd87fce..a424bbd2f200 100644 --- a/packages/babel-types/package.json +++ b/packages/babel-types/package.json @@ -25,7 +25,7 @@ }, "dependencies": { "@babel/helper-validator-identifier": "workspace:^", - "to-fast-properties": "condition:BABEL_8_BREAKING ? ^4.0.0 : ^2.0.0" + "to-fast-properties": "condition:BABEL_8_BREAKING ? ^3.0.0 : ^2.0.0" }, "devDependencies": { "@babel/generator": "workspace:^", diff --git a/packages/babel-types/scripts/generators/ast-types.js b/packages/babel-types/scripts/generators/ast-types.js index 2b6e39ae6541..901e3d2d56d3 100644 --- a/packages/babel-types/scripts/generators/ast-types.js +++ b/packages/babel-types/scripts/generators/ast-types.js @@ -10,6 +10,8 @@ interface BaseComment { start?: number; end?: number; loc?: SourceLocation; + // generator will skip the comment if ignore is true + ignore?: boolean; type: "CommentBlock" | "CommentLine"; } diff --git a/packages/babel-types/src/ast-types/generated/index.ts b/packages/babel-types/src/ast-types/generated/index.ts index 6c4ac341328e..5203e07424b6 100644 --- a/packages/babel-types/src/ast-types/generated/index.ts +++ b/packages/babel-types/src/ast-types/generated/index.ts @@ -6,6 +6,8 @@ interface BaseComment { start?: number; end?: number; loc?: SourceLocation; + // generator will skip the comment if ignore is true + ignore?: boolean; type: "CommentBlock" | "CommentLine"; } diff --git a/packages/babel-types/src/definitions/core.ts b/packages/babel-types/src/definitions/core.ts index 213ed8c27c9f..bdd8fa61a794 100644 --- a/packages/babel-types/src/definitions/core.ts +++ b/packages/babel-types/src/definitions/core.ts @@ -381,7 +381,12 @@ export const functionTypeAnnotationCommon = { returnType: { validate: process.env.BABEL_8_BREAKING ? assertNodeType("TypeAnnotation", "TSTypeAnnotation") - : assertNodeType("TypeAnnotation", "TSTypeAnnotation", "Noop"), + : assertNodeType( + "TypeAnnotation", + "TSTypeAnnotation", + // @ts-ignore Babel 7 AST + "Noop", + ), optional: true, }, typeParameters: { @@ -390,6 +395,7 @@ export const functionTypeAnnotationCommon = { : assertNodeType( "TypeParameterDeclaration", "TSTypeParameterDeclaration", + // @ts-ignore Babel 7 AST "Noop", ), optional: true, @@ -475,7 +481,12 @@ export const patternLikeCommon = { typeAnnotation: { validate: process.env.BABEL_8_BREAKING ? assertNodeType("TypeAnnotation", "TSTypeAnnotation") - : assertNodeType("TypeAnnotation", "TSTypeAnnotation", "Noop"), + : assertNodeType( + "TypeAnnotation", + "TSTypeAnnotation", + // @ts-ignore Babel 7 AST + "Noop", + ), optional: true, }, decorators: { @@ -1354,6 +1365,7 @@ defineType("ClassExpression", { : assertNodeType( "TypeParameterDeclaration", "TSTypeParameterDeclaration", + // @ts-ignore Babel 7 AST "Noop", ), optional: true, @@ -1411,6 +1423,7 @@ defineType("ClassDeclaration", { : assertNodeType( "TypeParameterDeclaration", "TSTypeParameterDeclaration", + // @ts-ignore Babel 7 AST "Noop", ), optional: true, @@ -2159,7 +2172,12 @@ defineType("ClassProperty", { typeAnnotation: { validate: process.env.BABEL_8_BREAKING ? assertNodeType("TypeAnnotation", "TSTypeAnnotation") - : assertNodeType("TypeAnnotation", "TSTypeAnnotation", "Noop"), + : assertNodeType( + "TypeAnnotation", + "TSTypeAnnotation", + // @ts-ignore Babel 7 AST + "Noop", + ), optional: true, }, decorators: { @@ -2233,7 +2251,12 @@ defineType("ClassAccessorProperty", { typeAnnotation: { validate: process.env.BABEL_8_BREAKING ? assertNodeType("TypeAnnotation", "TSTypeAnnotation") - : assertNodeType("TypeAnnotation", "TSTypeAnnotation", "Noop"), + : assertNodeType( + "TypeAnnotation", + "TSTypeAnnotation", + // @ts-ignore Babel 7 AST + "Noop", + ), optional: true, }, decorators: { @@ -2273,7 +2296,12 @@ defineType("ClassPrivateProperty", { typeAnnotation: { validate: process.env.BABEL_8_BREAKING ? assertNodeType("TypeAnnotation", "TSTypeAnnotation") - : assertNodeType("TypeAnnotation", "TSTypeAnnotation", "Noop"), + : assertNodeType( + "TypeAnnotation", + "TSTypeAnnotation", + // @ts-ignore Babel 7 AST + "Noop", + ), optional: true, }, decorators: { diff --git a/packages/babel-types/src/definitions/typescript.ts b/packages/babel-types/src/definitions/typescript.ts index f480a461488d..c82ee224a214 100644 --- a/packages/babel-types/src/definitions/typescript.ts +++ b/packages/babel-types/src/definitions/typescript.ts @@ -26,13 +26,15 @@ const tSFunctionTypeAnnotationCommon = { returnType: { validate: process.env.BABEL_8_BREAKING ? assertNodeType("TSTypeAnnotation") - : assertNodeType("TSTypeAnnotation", "Noop"), + : // @ts-ignore Babel 7 AST + assertNodeType("TSTypeAnnotation", "Noop"), optional: true, }, typeParameters: { validate: process.env.BABEL_8_BREAKING ? assertNodeType("TSTypeParameterDeclaration") - : assertNodeType("TSTypeParameterDeclaration", "Noop"), + : // @ts-ignore Babel 7 AST + assertNodeType("TSTypeParameterDeclaration", "Noop"), optional: true, }, }; diff --git a/packages/babel-types/src/definitions/utils.ts b/packages/babel-types/src/definitions/utils.ts index 6a220887ef65..687b907ef07c 100644 --- a/packages/babel-types/src/definitions/utils.ts +++ b/packages/babel-types/src/definitions/utils.ts @@ -278,7 +278,7 @@ const validFieldKeys = ["default", "optional", "validate"]; // Wraps defineType to ensure these aliases are included. export function defineAliasedType(...aliases: string[]) { - return (type: NodeTypes, opts: DefineTypeOpts = {}) => { + return (type: string, opts: DefineTypeOpts = {}) => { let defined = opts.aliases; if (!defined) { if (opts.inherits) defined = store[opts.inherits].aliases?.slice(); @@ -291,7 +291,7 @@ export function defineAliasedType(...aliases: string[]) { }; } -export default function defineType(type: NodeTypes, opts: DefineTypeOpts = {}) { +export default function defineType(type: string, opts: DefineTypeOpts = {}) { const inherits = (opts.inherits && store[opts.inherits]) || {}; let fields = opts.fields; @@ -373,4 +373,4 @@ export default function defineType(type: NodeTypes, opts: DefineTypeOpts = {}) { store[type] = opts; } -const store = {} as Record; +const store = {} as Record; diff --git a/packages/babel-types/src/index.ts b/packages/babel-types/src/index.ts index d80b74ee7024..f7c1f083be07 100644 --- a/packages/babel-types/src/index.ts +++ b/packages/babel-types/src/index.ts @@ -54,7 +54,10 @@ export * from "./definitions"; export { default as appendToMemberExpression } from "./modifications/appendToMemberExpression"; export { default as inherits } from "./modifications/inherits"; export { default as prependToMemberExpression } from "./modifications/prependToMemberExpression"; -export { default as removeProperties } from "./modifications/removeProperties"; +export { + default as removeProperties, + type Options as RemovePropertiesOptions, +} from "./modifications/removeProperties"; export { default as removePropertiesDeep } from "./modifications/removePropertiesDeep"; export { default as removeTypeDuplicates } from "./modifications/flow/removeTypeDuplicates"; diff --git a/packages/babel-types/src/modifications/removeProperties.ts b/packages/babel-types/src/modifications/removeProperties.ts index 5faa4a1fb74d..75aa841dc9da 100644 --- a/packages/babel-types/src/modifications/removeProperties.ts +++ b/packages/babel-types/src/modifications/removeProperties.ts @@ -17,13 +17,14 @@ const CLEAR_KEYS_PLUS_COMMENTS = [ ...CLEAR_KEYS, ] as const; +export type Options = { preserveComments?: boolean }; /** * Remove all of the _* properties from a node along with the additional metadata * properties like location data and raw token data. */ export default function removeProperties( node: t.Node, - opts: { preserveComments?: boolean } = {}, + opts: Options = {}, ): void { const map = opts.preserveComments ? CLEAR_KEYS : CLEAR_KEYS_PLUS_COMMENTS; for (const key of map) { diff --git a/yarn.lock b/yarn.lock index 7d026edc691f..3b7c36d711ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3799,7 +3799,7 @@ __metadata: "@babel/parser": "workspace:^" chalk: ^4.1.0 glob: ^7.1.7 - to-fast-properties: "condition:BABEL_8_BREAKING ? ^4.0.0 : ^2.0.0" + to-fast-properties: "condition:BABEL_8_BREAKING ? ^3.0.0 : ^2.0.0" languageName: unknown linkType: soft @@ -14723,20 +14723,20 @@ fsevents@^1.2.7: languageName: node linkType: hard -"to-fast-properties-BABEL_8_BREAKING-true@npm:to-fast-properties@^4.0.0": - version: 4.0.0 - resolution: "to-fast-properties@npm:4.0.0" - checksum: c72297bdd126a7e7ffe9cc6230eee60182f0439a7abb19d281e73137880d87d12fc971a47ff4bd1e0dc68e17262344fbf98499400ff5e341db431715c3620346 +"to-fast-properties-BABEL_8_BREAKING-true@npm:to-fast-properties@^3.0.0": + version: 3.0.1 + resolution: "to-fast-properties@npm:3.0.1" + checksum: 66b79f2c0d420d116a4eeb781c87c8c6b2de426a15f16118759e706aa1111833b0c578355a1108514ada966c08f4dba0cb7994aca025d80a535a139f7a631e22 languageName: node linkType: hard -"to-fast-properties@condition:BABEL_8_BREAKING ? ^4.0.0 : ^2.0.0": - version: 0.0.0-condition-ce57b6 - resolution: "to-fast-properties@condition:BABEL_8_BREAKING?^4.0.0:^2.0.0#ce57b6" +"to-fast-properties@condition:BABEL_8_BREAKING ? ^3.0.0 : ^2.0.0": + version: 0.0.0-condition-8fb1fb + resolution: "to-fast-properties@condition:BABEL_8_BREAKING?^3.0.0:^2.0.0#8fb1fb" dependencies: to-fast-properties-BABEL_8_BREAKING-false: "npm:to-fast-properties@^2.0.0" - to-fast-properties-BABEL_8_BREAKING-true: "npm:to-fast-properties@^4.0.0" - checksum: e301950506020ee20ad9ebdf7da40174c08f441a9ac0fe89d0efeb70a7fcedefdb3079433eae3d5a840ee38d589c0c2c9e27774d93fb60cd5af9b22b8b95df67 + to-fast-properties-BABEL_8_BREAKING-true: "npm:to-fast-properties@^3.0.0" + checksum: 6c5259ab91c280bfa3d2db3edd2fa26be985fd06f63974d0c288391426523f9d70035a812d05b65fe0e3fef864d969fcc3630b441cb563693e3ec70c54def266 languageName: node linkType: hard