Use named imports for babel types (#13685)
* migrate to named babel types imports * perf: transform babel types import to destructuring * fix merge errors * apply plugin to itself
This commit is contained in:
parent
fc66d4dd05
commit
614b486780
@ -202,6 +202,7 @@ module.exports = function (api) {
|
||||
{
|
||||
test: sources.map(normalize),
|
||||
assumptions: sourceAssumptions,
|
||||
plugins: [transformNamedBabelTypesImportToDestructuring],
|
||||
},
|
||||
{
|
||||
test: unambiguousSources.map(normalize),
|
||||
@ -455,6 +456,54 @@ function pluginPackageJsonMacro({ types: t }) {
|
||||
};
|
||||
}
|
||||
|
||||
// transform `import { x } from "@babel/types"` to `import * as _t from "@babel/types"; const { x } = _t;
|
||||
function transformNamedBabelTypesImportToDestructuring({
|
||||
types: {
|
||||
cloneNode,
|
||||
importNamespaceSpecifier,
|
||||
objectPattern,
|
||||
objectProperty,
|
||||
variableDeclarator,
|
||||
variableDeclaration,
|
||||
},
|
||||
}) {
|
||||
return {
|
||||
name: "transform-babel-types-named-imports",
|
||||
visitor: {
|
||||
ImportDeclaration(path) {
|
||||
const { node } = path;
|
||||
if (
|
||||
node.importKind === "value" &&
|
||||
node.source.value === "@babel/types" &&
|
||||
node.specifiers[0].type === "ImportSpecifier"
|
||||
) {
|
||||
const hoistedDestructuringProperties = [];
|
||||
for (const { imported, local } of node.specifiers) {
|
||||
hoistedDestructuringProperties.push(
|
||||
objectProperty(
|
||||
imported,
|
||||
local,
|
||||
false,
|
||||
imported.name === local.name
|
||||
)
|
||||
);
|
||||
}
|
||||
const babelTypeNsImport = path.scope.generateUidIdentifier("t");
|
||||
node.specifiers = [importNamespaceSpecifier(babelTypeNsImport)];
|
||||
path.insertAfter([
|
||||
variableDeclaration("const", [
|
||||
variableDeclarator(
|
||||
objectPattern(hoistedDestructuringProperties),
|
||||
cloneNode(babelTypeNsImport)
|
||||
),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function pluginImportMetaUrl({ types: t, template }) {
|
||||
const isImportMeta = node =>
|
||||
t.isMetaProperty(node) &&
|
||||
|
||||
@ -1,7 +1,28 @@
|
||||
import * as helpers from "@babel/helpers";
|
||||
import generator from "@babel/generator";
|
||||
import template from "@babel/template";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
arrayExpression,
|
||||
assignmentExpression,
|
||||
binaryExpression,
|
||||
blockStatement,
|
||||
callExpression,
|
||||
cloneNode,
|
||||
conditionalExpression,
|
||||
exportNamedDeclaration,
|
||||
exportSpecifier,
|
||||
expressionStatement,
|
||||
functionExpression,
|
||||
identifier,
|
||||
memberExpression,
|
||||
objectExpression,
|
||||
program,
|
||||
stringLiteral,
|
||||
unaryExpression,
|
||||
variableDeclaration,
|
||||
variableDeclarator,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import File from "../transformation/file/file";
|
||||
|
||||
// Wrapped to avoid wasting time parsing this when almost no-one uses
|
||||
@ -22,39 +43,39 @@ const buildUmdWrapper = replacements =>
|
||||
`(replacements);
|
||||
|
||||
function buildGlobal(allowlist?: Array<string>) {
|
||||
const namespace = t.identifier("babelHelpers");
|
||||
const namespace = identifier("babelHelpers");
|
||||
|
||||
const body: t.Statement[] = [];
|
||||
const container = t.functionExpression(
|
||||
const container = functionExpression(
|
||||
null,
|
||||
[t.identifier("global")],
|
||||
t.blockStatement(body),
|
||||
[identifier("global")],
|
||||
blockStatement(body),
|
||||
);
|
||||
const tree = t.program([
|
||||
t.expressionStatement(
|
||||
t.callExpression(container, [
|
||||
const tree = program([
|
||||
expressionStatement(
|
||||
callExpression(container, [
|
||||
// typeof global === "undefined" ? self : global
|
||||
t.conditionalExpression(
|
||||
t.binaryExpression(
|
||||
conditionalExpression(
|
||||
binaryExpression(
|
||||
"===",
|
||||
t.unaryExpression("typeof", t.identifier("global")),
|
||||
t.stringLiteral("undefined"),
|
||||
unaryExpression("typeof", identifier("global")),
|
||||
stringLiteral("undefined"),
|
||||
),
|
||||
t.identifier("self"),
|
||||
t.identifier("global"),
|
||||
identifier("self"),
|
||||
identifier("global"),
|
||||
),
|
||||
]),
|
||||
),
|
||||
]);
|
||||
|
||||
body.push(
|
||||
t.variableDeclaration("var", [
|
||||
t.variableDeclarator(
|
||||
variableDeclaration("var", [
|
||||
variableDeclarator(
|
||||
namespace,
|
||||
t.assignmentExpression(
|
||||
assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(t.identifier("global"), namespace),
|
||||
t.objectExpression([]),
|
||||
memberExpression(identifier("global"), namespace),
|
||||
objectExpression([]),
|
||||
),
|
||||
),
|
||||
]),
|
||||
@ -70,57 +91,57 @@ function buildModule(allowlist?: Array<string>) {
|
||||
const refs = buildHelpers(body, null, allowlist);
|
||||
|
||||
body.unshift(
|
||||
t.exportNamedDeclaration(
|
||||
exportNamedDeclaration(
|
||||
null,
|
||||
Object.keys(refs).map(name => {
|
||||
return t.exportSpecifier(t.cloneNode(refs[name]), t.identifier(name));
|
||||
return exportSpecifier(cloneNode(refs[name]), identifier(name));
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
return t.program(body, [], "module");
|
||||
return program(body, [], "module");
|
||||
}
|
||||
|
||||
function buildUmd(allowlist?: Array<string>) {
|
||||
const namespace = t.identifier("babelHelpers");
|
||||
const namespace = identifier("babelHelpers");
|
||||
|
||||
const body: t.Statement[] = [];
|
||||
body.push(
|
||||
t.variableDeclaration("var", [
|
||||
t.variableDeclarator(namespace, t.identifier("global")),
|
||||
variableDeclaration("var", [
|
||||
variableDeclarator(namespace, identifier("global")),
|
||||
]),
|
||||
);
|
||||
|
||||
buildHelpers(body, namespace, allowlist);
|
||||
|
||||
return t.program([
|
||||
return program([
|
||||
buildUmdWrapper({
|
||||
FACTORY_PARAMETERS: t.identifier("global"),
|
||||
BROWSER_ARGUMENTS: t.assignmentExpression(
|
||||
FACTORY_PARAMETERS: identifier("global"),
|
||||
BROWSER_ARGUMENTS: assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(t.identifier("root"), namespace),
|
||||
t.objectExpression([]),
|
||||
memberExpression(identifier("root"), namespace),
|
||||
objectExpression([]),
|
||||
),
|
||||
COMMON_ARGUMENTS: t.identifier("exports"),
|
||||
AMD_ARGUMENTS: t.arrayExpression([t.stringLiteral("exports")]),
|
||||
COMMON_ARGUMENTS: identifier("exports"),
|
||||
AMD_ARGUMENTS: arrayExpression([stringLiteral("exports")]),
|
||||
FACTORY_BODY: body,
|
||||
UMD_ROOT: t.identifier("this"),
|
||||
UMD_ROOT: identifier("this"),
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
function buildVar(allowlist?: Array<string>) {
|
||||
const namespace = t.identifier("babelHelpers");
|
||||
const namespace = identifier("babelHelpers");
|
||||
|
||||
const body: t.Statement[] = [];
|
||||
body.push(
|
||||
t.variableDeclaration("var", [
|
||||
t.variableDeclarator(namespace, t.objectExpression([])),
|
||||
variableDeclaration("var", [
|
||||
variableDeclarator(namespace, objectExpression([])),
|
||||
]),
|
||||
);
|
||||
const tree = t.program(body);
|
||||
const tree = program(body);
|
||||
buildHelpers(body, namespace, allowlist);
|
||||
body.push(t.expressionStatement(namespace));
|
||||
body.push(expressionStatement(namespace));
|
||||
return tree;
|
||||
}
|
||||
|
||||
@ -131,8 +152,8 @@ function buildHelpers(
|
||||
) {
|
||||
const getHelperReference = (name: string) => {
|
||||
return namespace
|
||||
? t.memberExpression(namespace, t.identifier(name))
|
||||
: t.identifier(`_${name}`);
|
||||
? memberExpression(namespace, identifier(name))
|
||||
: identifier(`_${name}`);
|
||||
};
|
||||
|
||||
const refs = {};
|
||||
|
||||
@ -3,7 +3,8 @@ import { NodePath, Scope } from "@babel/traverse";
|
||||
import type { HubInterface } from "@babel/traverse";
|
||||
import { codeFrameColumns } from "@babel/code-frame";
|
||||
import traverse from "@babel/traverse";
|
||||
import * as t from "@babel/types";
|
||||
import { cloneNode, interpreterDirective } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import { getModuleName } from "@babel/helper-module-transforms";
|
||||
import semver from "semver";
|
||||
|
||||
@ -89,7 +90,7 @@ export default class File {
|
||||
}
|
||||
set shebang(value: string) {
|
||||
if (value) {
|
||||
this.path.get("interpreter").replaceWith(t.interpreterDirective(value));
|
||||
this.path.get("interpreter").replaceWith(interpreterDirective(value));
|
||||
} else {
|
||||
this.path.get("interpreter").remove();
|
||||
}
|
||||
@ -176,7 +177,7 @@ export default class File {
|
||||
|
||||
addHelper(name: string): t.Identifier {
|
||||
const declar = this.declarations[name];
|
||||
if (declar) return t.cloneNode(declar);
|
||||
if (declar) return cloneNode(declar);
|
||||
|
||||
const generator = this.get("helperGenerator");
|
||||
if (generator) {
|
||||
|
||||
@ -2,7 +2,8 @@ import fs from "fs";
|
||||
import path from "path";
|
||||
import buildDebug from "debug";
|
||||
import type { Handler } from "gensync";
|
||||
import * as t from "@babel/types";
|
||||
import { file, traverseFast } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import type { PluginPasses } from "../config";
|
||||
import convertSourceMap from "convert-source-map";
|
||||
import type { SourceMapConverter as Converter } from "convert-source-map";
|
||||
@ -29,7 +30,7 @@ export default function* normalizeFile(
|
||||
|
||||
if (ast) {
|
||||
if (ast.type === "Program") {
|
||||
ast = t.file(ast, [], []);
|
||||
ast = file(ast, [], []);
|
||||
} else if (ast.type !== "File") {
|
||||
throw new Error("AST root must be a Program or File node");
|
||||
}
|
||||
@ -119,7 +120,7 @@ function extractCommentsFromList(regex, comments, lastComment) {
|
||||
|
||||
function extractComments(regex, ast) {
|
||||
let lastComment = null;
|
||||
t.traverseFast(ast, node => {
|
||||
traverseFast(ast, node => {
|
||||
[node.leadingComments, lastComment] = extractCommentsFromList(
|
||||
regex,
|
||||
node.leadingComments,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import * as charCodes from "charcodes";
|
||||
|
||||
export function File(this: Printer, node: t.File) {
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
isExportDefaultDeclaration,
|
||||
isExportNamedDeclaration,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import * as charCodes from "charcodes";
|
||||
|
||||
const { isExportDefaultDeclaration, isExportNamedDeclaration } = t;
|
||||
|
||||
export function ClassDeclaration(
|
||||
this: Printer,
|
||||
node: t.ClassDeclaration,
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
isCallExpression,
|
||||
isLiteral,
|
||||
isMemberExpression,
|
||||
isNewExpression,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import * as n from "../node";
|
||||
|
||||
const { isCallExpression, isLiteral, isMemberExpression, isNewExpression } = t;
|
||||
export function UnaryExpression(this: Printer, node: t.UnaryExpression) {
|
||||
if (
|
||||
node.operator === "void" ||
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
import { isDeclareExportDeclaration, isStatement } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import { ExportAllDeclaration } from "./modules";
|
||||
|
||||
const { isDeclareExportDeclaration, isStatement } = t;
|
||||
export function AnyTypeAnnotation(this: Printer) {
|
||||
this.word("any");
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
export function JSXAttribute(this: Printer, node: t.JSXAttribute) {
|
||||
this.print(node.name, node);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
import { isIdentifier } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
const { isIdentifier } = t;
|
||||
export function _params(this: Printer, node: any) {
|
||||
this.print(node.typeParameters, node);
|
||||
this.token("(");
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
|
||||
const {
|
||||
import {
|
||||
isClassDeclaration,
|
||||
isExportDefaultSpecifier,
|
||||
isExportNamespaceSpecifier,
|
||||
isImportDefaultSpecifier,
|
||||
isImportNamespaceSpecifier,
|
||||
isStatement,
|
||||
} = t;
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
export function ImportSpecifier(this: Printer, node: t.ImportSpecifier) {
|
||||
if (node.importKind === "type" || node.importKind === "typeof") {
|
||||
|
||||
@ -1,8 +1,13 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
isFor,
|
||||
isForStatement,
|
||||
isIfStatement,
|
||||
isStatement,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import * as charCodes from "charcodes";
|
||||
|
||||
const { isFor, isForStatement, isIfStatement, isStatement } = t;
|
||||
export function WithStatement(this: Printer, node: t.WithStatement) {
|
||||
this.word("with");
|
||||
this.space();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
export function TaggedTemplateExpression(
|
||||
this: Printer,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
import { isAssignmentPattern, isIdentifier } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import jsesc from "jsesc";
|
||||
|
||||
const { isAssignmentPattern, isIdentifier } = t;
|
||||
export function Identifier(this: Printer, node: t.Identifier) {
|
||||
this.exactSource(node.loc, () => {
|
||||
this.word(node.name);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type Printer from "../printer";
|
||||
import * as t from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
export function TSTypeAnnotation(this: Printer, node: t.TSTypeAnnotation) {
|
||||
this.token(":");
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
import * as whitespace from "./whitespace";
|
||||
import * as parens from "./parentheses";
|
||||
import * as t from "@babel/types";
|
||||
const {
|
||||
import {
|
||||
FLIPPED_ALIAS_KEYS,
|
||||
isCallExpression,
|
||||
isExpressionStatement,
|
||||
isMemberExpression,
|
||||
isNewExpression,
|
||||
} = t;
|
||||
} from "@babel/types";
|
||||
|
||||
function expandAliases(obj) {
|
||||
const newObj = {};
|
||||
|
||||
@ -22,7 +23,7 @@ function expandAliases(obj) {
|
||||
}
|
||||
|
||||
for (const type of Object.keys(obj)) {
|
||||
const aliases = t.FLIPPED_ALIAS_KEYS[type];
|
||||
const aliases = FLIPPED_ALIAS_KEYS[type];
|
||||
if (aliases) {
|
||||
for (const alias of aliases) {
|
||||
add(alias, obj[type]);
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
import * as t from "@babel/types";
|
||||
|
||||
const {
|
||||
import {
|
||||
isArrayTypeAnnotation,
|
||||
isArrowFunctionExpression,
|
||||
isAssignmentExpression,
|
||||
@ -48,7 +46,8 @@ const {
|
||||
isVariableDeclarator,
|
||||
isWhileStatement,
|
||||
isYieldExpression,
|
||||
} = t;
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
const PRECEDENCE = {
|
||||
"||": 0,
|
||||
"??": 0,
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import * as t from "@babel/types";
|
||||
|
||||
const {
|
||||
import {
|
||||
FLIPPED_ALIAS_KEYS,
|
||||
isArrayExpression,
|
||||
isAssignmentExpression,
|
||||
isBinary,
|
||||
@ -14,7 +13,9 @@ const {
|
||||
isOptionalCallExpression,
|
||||
isOptionalMemberExpression,
|
||||
isStringLiteral,
|
||||
} = t;
|
||||
} from "@babel/types";
|
||||
|
||||
import type * as t from "@babel/types";
|
||||
type WhitespaceObject = {
|
||||
before?: boolean;
|
||||
after?: boolean;
|
||||
@ -319,7 +320,7 @@ export const list = {
|
||||
amounts = { after: amounts, before: amounts };
|
||||
}
|
||||
[type as string]
|
||||
.concat(t.FLIPPED_ALIAS_KEYS[type] || [])
|
||||
.concat(FLIPPED_ALIAS_KEYS[type] || [])
|
||||
.forEach(function (type) {
|
||||
nodes[type] = function () {
|
||||
return amounts;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import Buffer from "./buffer";
|
||||
import * as n from "./node";
|
||||
import * as t from "@babel/types";
|
||||
import { isProgram, isFile, isEmptyStatement } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
import * as generatorFunctions from "./generators";
|
||||
import type SourceMap from "./source-map";
|
||||
@ -11,7 +12,6 @@ const ZERO_DECIMAL_INTEGER = /\.0+$/;
|
||||
const NON_DECIMAL_LITERAL = /^0[box]/;
|
||||
const PURE_ANNOTATION_RE = /^\s*[@#]__PURE__\s*$/;
|
||||
|
||||
const { isProgram, isFile, isEmptyStatement } = t;
|
||||
const { needsParens, needsWhitespaceAfter, needsWhitespaceBefore } = n;
|
||||
|
||||
export type Format = {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as t from "@babel/types";
|
||||
import { addComment } from "@babel/types";
|
||||
import type { Node } from "@babel/types";
|
||||
|
||||
const PURE_ANNOTATION = "#__PURE__";
|
||||
@ -14,5 +14,5 @@ export default function annotateAsPure(
|
||||
if (isPureAnnotated(node)) {
|
||||
return;
|
||||
}
|
||||
t.addComment(node, "leading", PURE_ANNOTATION);
|
||||
addComment(node, "leading", PURE_ANNOTATION);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import explode from "@babel/helper-explode-assignable-expression";
|
||||
import * as t from "@babel/types";
|
||||
import { assignmentExpression, sequenceExpression } from "@babel/types";
|
||||
|
||||
export default function (opts: { build: Function, operator: string }): Object {
|
||||
const { build, operator } = opts;
|
||||
@ -12,13 +12,13 @@ export default function (opts: { build: Function, operator: string }): Object {
|
||||
const nodes = [];
|
||||
const exploded = explode(node.left, nodes, this, scope);
|
||||
nodes.push(
|
||||
t.assignmentExpression(
|
||||
assignmentExpression(
|
||||
"=",
|
||||
exploded.ref,
|
||||
build(exploded.uid, node.right),
|
||||
),
|
||||
);
|
||||
path.replaceWith(t.sequenceExpression(nodes));
|
||||
path.replaceWith(sequenceExpression(nodes));
|
||||
},
|
||||
|
||||
BinaryExpression(path) {
|
||||
|
||||
@ -1,4 +1,28 @@
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
booleanLiteral,
|
||||
callExpression,
|
||||
identifier,
|
||||
inherits,
|
||||
isIdentifier,
|
||||
isJSXExpressionContainer,
|
||||
isJSXIdentifier,
|
||||
isJSXMemberExpression,
|
||||
isJSXNamespacedName,
|
||||
isJSXSpreadAttribute,
|
||||
isLiteral,
|
||||
isObjectExpression,
|
||||
isReferenced,
|
||||
isStringLiteral,
|
||||
isValidIdentifier,
|
||||
memberExpression,
|
||||
nullLiteral,
|
||||
objectExpression,
|
||||
objectProperty,
|
||||
react,
|
||||
spreadElement,
|
||||
stringLiteral,
|
||||
thisExpression,
|
||||
} from "@babel/types";
|
||||
import annotateAsPure from "@babel/helper-annotate-as-pure";
|
||||
|
||||
type ElementState = {
|
||||
@ -31,7 +55,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
exit(path, file) {
|
||||
const callExpr = buildElementCall(path, file);
|
||||
if (callExpr) {
|
||||
path.replaceWith(t.inherits(callExpr, path.node));
|
||||
path.replaceWith(inherits(callExpr, path.node));
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -45,7 +69,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
}
|
||||
const callExpr = buildFragmentCall(path, file);
|
||||
if (callExpr) {
|
||||
path.replaceWith(t.inherits(callExpr, path.node));
|
||||
path.replaceWith(inherits(callExpr, path.node));
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -53,32 +77,32 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
return visitor;
|
||||
|
||||
function convertJSXIdentifier(node, parent) {
|
||||
if (t.isJSXIdentifier(node)) {
|
||||
if (node.name === "this" && t.isReferenced(node, parent)) {
|
||||
return t.thisExpression();
|
||||
} else if (t.isValidIdentifier(node.name, false)) {
|
||||
if (isJSXIdentifier(node)) {
|
||||
if (node.name === "this" && isReferenced(node, parent)) {
|
||||
return thisExpression();
|
||||
} else if (isValidIdentifier(node.name, false)) {
|
||||
node.type = "Identifier";
|
||||
} else {
|
||||
return t.stringLiteral(node.name);
|
||||
return stringLiteral(node.name);
|
||||
}
|
||||
} else if (t.isJSXMemberExpression(node)) {
|
||||
return t.memberExpression(
|
||||
} else if (isJSXMemberExpression(node)) {
|
||||
return memberExpression(
|
||||
convertJSXIdentifier(node.object, node),
|
||||
convertJSXIdentifier(node.property, node),
|
||||
);
|
||||
} else if (t.isJSXNamespacedName(node)) {
|
||||
} else if (isJSXNamespacedName(node)) {
|
||||
/**
|
||||
* If there is flag "throwIfNamespace"
|
||||
* print XMLNamespace like string literal
|
||||
*/
|
||||
return t.stringLiteral(`${node.namespace.name}:${node.name.name}`);
|
||||
return stringLiteral(`${node.namespace.name}:${node.name.name}`);
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
function convertAttributeValue(node) {
|
||||
if (t.isJSXExpressionContainer(node)) {
|
||||
if (isJSXExpressionContainer(node)) {
|
||||
return node.expression;
|
||||
} else {
|
||||
return node;
|
||||
@ -86,37 +110,37 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
}
|
||||
|
||||
function convertAttribute(node) {
|
||||
const value = convertAttributeValue(node.value || t.booleanLiteral(true));
|
||||
const value = convertAttributeValue(node.value || booleanLiteral(true));
|
||||
|
||||
if (t.isJSXSpreadAttribute(node)) {
|
||||
return t.spreadElement(node.argument);
|
||||
if (isJSXSpreadAttribute(node)) {
|
||||
return spreadElement(node.argument);
|
||||
}
|
||||
|
||||
if (t.isStringLiteral(value) && !t.isJSXExpressionContainer(node.value)) {
|
||||
if (isStringLiteral(value) && !isJSXExpressionContainer(node.value)) {
|
||||
value.value = value.value.replace(/\n\s+/g, " ");
|
||||
|
||||
// "raw" JSXText should not be used from a StringLiteral because it needs to be escaped.
|
||||
delete value.extra?.raw;
|
||||
}
|
||||
|
||||
if (t.isJSXNamespacedName(node.name)) {
|
||||
node.name = t.stringLiteral(
|
||||
if (isJSXNamespacedName(node.name)) {
|
||||
node.name = stringLiteral(
|
||||
node.name.namespace.name + ":" + node.name.name.name,
|
||||
);
|
||||
} else if (t.isValidIdentifier(node.name.name, false)) {
|
||||
} else if (isValidIdentifier(node.name.name, false)) {
|
||||
node.name.type = "Identifier";
|
||||
} else {
|
||||
node.name = t.stringLiteral(node.name.name);
|
||||
node.name = stringLiteral(node.name.name);
|
||||
}
|
||||
|
||||
return t.inherits(t.objectProperty(node.name, value), node);
|
||||
return inherits(objectProperty(node.name, value), node);
|
||||
}
|
||||
|
||||
function buildElementCall(path, file) {
|
||||
if (opts.filter && !opts.filter(path.node, file)) return;
|
||||
|
||||
const openingPath = path.get("openingElement");
|
||||
openingPath.parent.children = t.react.buildChildren(openingPath.parent);
|
||||
openingPath.parent.children = react.buildChildren(openingPath.parent);
|
||||
|
||||
const tagExpr = convertJSXIdentifier(
|
||||
openingPath.node.name,
|
||||
@ -125,9 +149,9 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
const args = [];
|
||||
|
||||
let tagName;
|
||||
if (t.isIdentifier(tagExpr)) {
|
||||
if (isIdentifier(tagExpr)) {
|
||||
tagName = tagExpr.name;
|
||||
} else if (t.isLiteral(tagExpr)) {
|
||||
} else if (isLiteral(tagExpr)) {
|
||||
tagName = tagExpr.value;
|
||||
}
|
||||
|
||||
@ -145,12 +169,12 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
let attribs = openingPath.node.attributes;
|
||||
if (attribs.length) {
|
||||
if (process.env.BABEL_8_BREAKING) {
|
||||
attribs = t.objectExpression(attribs.map(convertAttribute));
|
||||
attribs = objectExpression(attribs.map(convertAttribute));
|
||||
} else {
|
||||
attribs = buildOpeningElementAttributes(attribs, file);
|
||||
}
|
||||
} else {
|
||||
attribs = t.nullLiteral();
|
||||
attribs = nullLiteral();
|
||||
}
|
||||
|
||||
args.push(attribs, ...path.node.children);
|
||||
@ -159,7 +183,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
opts.post(state, file);
|
||||
}
|
||||
|
||||
const call = state.call || t.callExpression(state.callee, args);
|
||||
const call = state.call || callExpression(state.callee, args);
|
||||
if (state.pure) annotateAsPure(call);
|
||||
|
||||
return call;
|
||||
@ -168,7 +192,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
function pushProps(_props, objs) {
|
||||
if (!_props.length) return _props;
|
||||
|
||||
objs.push(t.objectExpression(_props));
|
||||
objs.push(objectExpression(_props));
|
||||
return [];
|
||||
}
|
||||
|
||||
@ -208,12 +232,12 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
|
||||
if (useSpread) {
|
||||
const props = attribs.map(convertAttribute);
|
||||
return t.objectExpression(props);
|
||||
return objectExpression(props);
|
||||
}
|
||||
|
||||
while (attribs.length) {
|
||||
const prop = attribs.shift();
|
||||
if (t.isJSXSpreadAttribute(prop)) {
|
||||
if (isJSXSpreadAttribute(prop)) {
|
||||
_props = pushProps(_props, objs);
|
||||
objs.push(prop.argument);
|
||||
} else {
|
||||
@ -228,16 +252,16 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
attribs = objs[0];
|
||||
} else {
|
||||
// looks like we have multiple objects
|
||||
if (!t.isObjectExpression(objs[0])) {
|
||||
objs.unshift(t.objectExpression([]));
|
||||
if (!isObjectExpression(objs[0])) {
|
||||
objs.unshift(objectExpression([]));
|
||||
}
|
||||
|
||||
const helper = useBuiltIns
|
||||
? t.memberExpression(t.identifier("Object"), t.identifier("assign"))
|
||||
? memberExpression(identifier("Object"), identifier("assign"))
|
||||
: file.addHelper("extends");
|
||||
|
||||
// spread it
|
||||
attribs = t.callExpression(helper, objs);
|
||||
attribs = callExpression(helper, objs);
|
||||
}
|
||||
|
||||
return attribs;
|
||||
@ -247,7 +271,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
if (opts.filter && !opts.filter(path.node, file)) return;
|
||||
|
||||
const openingPath = path.get("openingElement");
|
||||
openingPath.parent.children = t.react.buildChildren(openingPath.parent);
|
||||
openingPath.parent.children = react.buildChildren(openingPath.parent);
|
||||
|
||||
const args = [];
|
||||
const tagName = null;
|
||||
@ -265,7 +289,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
}
|
||||
|
||||
// no attributes are allowed with <> syntax
|
||||
args.push(t.nullLiteral(), ...path.node.children);
|
||||
args.push(nullLiteral(), ...path.node.children);
|
||||
|
||||
if (opts.post) {
|
||||
opts.post(state, file);
|
||||
@ -273,7 +297,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
|
||||
|
||||
file.set("usedFragment", true);
|
||||
|
||||
const call = state.call || t.callExpression(state.callee, args);
|
||||
const call = state.call || callExpression(state.callee, args);
|
||||
if (state.pure) annotateAsPure(call);
|
||||
|
||||
return call;
|
||||
|
||||
@ -1,8 +1,25 @@
|
||||
import nameFunction from "@babel/helper-function-name";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
arrayExpression,
|
||||
booleanLiteral,
|
||||
functionExpression,
|
||||
identifier,
|
||||
inheritsComments,
|
||||
isClassMethod,
|
||||
isFunctionExpression,
|
||||
isObjectMethod,
|
||||
isObjectProperty,
|
||||
isProperty,
|
||||
isStringLiteral,
|
||||
objectExpression,
|
||||
objectProperty,
|
||||
removeComments,
|
||||
toComputedKey,
|
||||
toKeyAlias,
|
||||
} from "@babel/types";
|
||||
|
||||
function toKind(node: Object) {
|
||||
if (t.isClassMethod(node) || t.isObjectMethod(node)) {
|
||||
if (isClassMethod(node) || isObjectMethod(node)) {
|
||||
if (node.kind === "get" || node.kind === "set") {
|
||||
return node.kind;
|
||||
}
|
||||
@ -20,7 +37,7 @@ export function push(
|
||||
file,
|
||||
scope?,
|
||||
): Object {
|
||||
const alias = t.toKeyAlias(node);
|
||||
const alias = toKeyAlias(node);
|
||||
|
||||
//
|
||||
|
||||
@ -40,8 +57,7 @@ export function push(
|
||||
}
|
||||
|
||||
if (node.decorators) {
|
||||
const decorators = (map.decorators =
|
||||
map.decorators || t.arrayExpression([]));
|
||||
const decorators = (map.decorators = map.decorators || arrayExpression([]));
|
||||
decorators.elements.push(
|
||||
...node.decorators.map(dec => dec.expression).reverse(),
|
||||
);
|
||||
@ -54,18 +70,14 @@ export function push(
|
||||
let key, value;
|
||||
|
||||
// save the key so we can possibly do function name inferences
|
||||
if (
|
||||
t.isObjectProperty(node) ||
|
||||
t.isObjectMethod(node) ||
|
||||
t.isClassMethod(node)
|
||||
) {
|
||||
key = t.toComputedKey(node, node.key);
|
||||
if (isObjectProperty(node) || isObjectMethod(node) || isClassMethod(node)) {
|
||||
key = toComputedKey(node, node.key);
|
||||
}
|
||||
|
||||
if (t.isProperty(node)) {
|
||||
if (isProperty(node)) {
|
||||
value = node.value;
|
||||
} else if (t.isObjectMethod(node) || t.isClassMethod(node)) {
|
||||
value = t.functionExpression(
|
||||
} else if (isObjectMethod(node) || isClassMethod(node)) {
|
||||
value = functionExpression(
|
||||
null,
|
||||
node.params,
|
||||
node.body,
|
||||
@ -83,15 +95,15 @@ export function push(
|
||||
// infer function name
|
||||
if (
|
||||
scope &&
|
||||
t.isStringLiteral(key) &&
|
||||
isStringLiteral(key) &&
|
||||
(kind === "value" || kind === "initializer") &&
|
||||
t.isFunctionExpression(value)
|
||||
isFunctionExpression(value)
|
||||
) {
|
||||
value = nameFunction({ id: key, node: value, scope });
|
||||
}
|
||||
|
||||
if (value) {
|
||||
t.inheritsComments(value, node);
|
||||
inheritsComments(value, node);
|
||||
map[kind] = value;
|
||||
}
|
||||
|
||||
@ -108,13 +120,13 @@ export function hasComputed(mutatorMap: Object): boolean {
|
||||
}
|
||||
|
||||
export function toComputedObjectFromClass(obj: Object): Object {
|
||||
const objExpr = t.arrayExpression([]);
|
||||
const objExpr = arrayExpression([]);
|
||||
|
||||
for (let i = 0; i < obj.properties.length; i++) {
|
||||
const prop = obj.properties[i];
|
||||
const val = prop.value;
|
||||
val.properties.unshift(
|
||||
t.objectProperty(t.identifier("key"), t.toComputedKey(prop)),
|
||||
objectProperty(identifier("key"), toComputedKey(prop)),
|
||||
);
|
||||
objExpr.elements.push(val);
|
||||
}
|
||||
@ -123,21 +135,21 @@ export function toComputedObjectFromClass(obj: Object): Object {
|
||||
}
|
||||
|
||||
export function toClassObject(mutatorMap: Object): Object {
|
||||
const objExpr = t.objectExpression([]);
|
||||
const objExpr = objectExpression([]);
|
||||
|
||||
Object.keys(mutatorMap).forEach(function (mutatorMapKey) {
|
||||
const map = mutatorMap[mutatorMapKey];
|
||||
const mapNode = t.objectExpression([]);
|
||||
const mapNode = objectExpression([]);
|
||||
|
||||
const propNode = t.objectProperty(map._key, mapNode, map._computed);
|
||||
const propNode = objectProperty(map._key, mapNode, map._computed);
|
||||
|
||||
Object.keys(map).forEach(function (key) {
|
||||
const node = map[key];
|
||||
if (key[0] === "_") return;
|
||||
|
||||
const prop = t.objectProperty(t.identifier(key), node);
|
||||
t.inheritsComments(prop, node);
|
||||
t.removeComments(node);
|
||||
const prop = objectProperty(identifier(key), node);
|
||||
inheritsComments(prop, node);
|
||||
removeComments(node);
|
||||
|
||||
mapNode.properties.push(prop);
|
||||
});
|
||||
@ -151,9 +163,9 @@ export function toClassObject(mutatorMap: Object): Object {
|
||||
export function toDefineObject(mutatorMap: Object): Object {
|
||||
Object.keys(mutatorMap).forEach(function (key) {
|
||||
const map = mutatorMap[key];
|
||||
if (map.value) map.writable = t.booleanLiteral(true);
|
||||
map.configurable = t.booleanLiteral(true);
|
||||
map.enumerable = t.booleanLiteral(true);
|
||||
if (map.value) map.writable = booleanLiteral(true);
|
||||
map.configurable = booleanLiteral(true);
|
||||
map.enumerable = booleanLiteral(true);
|
||||
});
|
||||
|
||||
return toClassObject(mutatorMap);
|
||||
|
||||
@ -1,5 +1,17 @@
|
||||
import type { Scope } from "@babel/traverse";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
assignmentExpression,
|
||||
cloneNode,
|
||||
isIdentifier,
|
||||
isLiteral,
|
||||
isMemberExpression,
|
||||
isPrivateName,
|
||||
isPureish,
|
||||
isSuper,
|
||||
memberExpression,
|
||||
toComputedKey,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
function getObjRef(
|
||||
node: t.Identifier | t.MemberExpression,
|
||||
@ -7,7 +19,7 @@ function getObjRef(
|
||||
scope: Scope,
|
||||
): t.Identifier | t.Super {
|
||||
let ref;
|
||||
if (t.isIdentifier(node)) {
|
||||
if (isIdentifier(node)) {
|
||||
if (scope.hasBinding(node.name)) {
|
||||
// this variable is declared in scope so we can be 100% sure
|
||||
// that evaluating it multiple times wont trigger a getter
|
||||
@ -18,10 +30,10 @@ function getObjRef(
|
||||
// it once
|
||||
ref = node;
|
||||
}
|
||||
} else if (t.isMemberExpression(node)) {
|
||||
} else if (isMemberExpression(node)) {
|
||||
ref = node.object;
|
||||
|
||||
if (t.isSuper(ref) || (t.isIdentifier(ref) && scope.hasBinding(ref.name))) {
|
||||
if (isSuper(ref) || (isIdentifier(ref) && scope.hasBinding(ref.name))) {
|
||||
// the object reference that we need to save is locally declared
|
||||
// so as per the previous comment we can be 100% sure evaluating
|
||||
// it multiple times will be safe
|
||||
@ -34,7 +46,7 @@ function getObjRef(
|
||||
|
||||
const temp = scope.generateUidIdentifierBasedOnNode(ref);
|
||||
scope.push({ id: temp });
|
||||
nodes.push(t.assignmentExpression("=", t.cloneNode(temp), t.cloneNode(ref)));
|
||||
nodes.push(assignmentExpression("=", cloneNode(temp), cloneNode(ref)));
|
||||
return temp;
|
||||
}
|
||||
|
||||
@ -44,17 +56,17 @@ function getPropRef(
|
||||
scope: Scope,
|
||||
): t.Identifier | t.Literal {
|
||||
const prop = node.property;
|
||||
if (t.isPrivateName(prop)) {
|
||||
if (isPrivateName(prop)) {
|
||||
throw new Error(
|
||||
"We can't generate property ref for private name, please install `@babel/plugin-proposal-class-properties`",
|
||||
);
|
||||
}
|
||||
const key = t.toComputedKey(node, prop);
|
||||
if (t.isLiteral(key) && t.isPureish(key)) return key;
|
||||
const key = toComputedKey(node, prop);
|
||||
if (isLiteral(key) && isPureish(key)) return key;
|
||||
|
||||
const temp = scope.generateUidIdentifierBasedOnNode(prop);
|
||||
scope.push({ id: temp });
|
||||
nodes.push(t.assignmentExpression("=", t.cloneNode(temp), t.cloneNode(prop)));
|
||||
nodes.push(assignmentExpression("=", cloneNode(temp), cloneNode(prop)));
|
||||
return temp;
|
||||
}
|
||||
|
||||
@ -70,7 +82,7 @@ export default function (
|
||||
ref: t.Identifier | t.MemberExpression;
|
||||
} {
|
||||
let obj;
|
||||
if (t.isIdentifier(node) && allowedSingleIdent) {
|
||||
if (isIdentifier(node) && allowedSingleIdent) {
|
||||
obj = node;
|
||||
} else {
|
||||
obj = getObjRef(node, nodes, scope);
|
||||
@ -78,14 +90,14 @@ export default function (
|
||||
|
||||
let ref, uid;
|
||||
|
||||
if (t.isIdentifier(node)) {
|
||||
ref = t.cloneNode(node);
|
||||
if (isIdentifier(node)) {
|
||||
ref = cloneNode(node);
|
||||
uid = obj;
|
||||
} else {
|
||||
const prop = getPropRef(node, nodes, scope);
|
||||
const computed = node.computed || t.isLiteral(prop);
|
||||
uid = t.memberExpression(t.cloneNode(obj), t.cloneNode(prop), computed);
|
||||
ref = t.memberExpression(t.cloneNode(obj), t.cloneNode(prop), computed);
|
||||
const computed = node.computed || isLiteral(prop);
|
||||
uid = memberExpression(cloneNode(obj), cloneNode(prop), computed);
|
||||
ref = memberExpression(cloneNode(obj), cloneNode(prop), computed);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@ -1,6 +1,22 @@
|
||||
import getFunctionArity from "@babel/helper-get-function-arity";
|
||||
import template from "@babel/template";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
NOT_LOCAL_BINDING,
|
||||
cloneNode,
|
||||
identifier,
|
||||
isAssignmentExpression,
|
||||
isFunction,
|
||||
isIdentifier,
|
||||
isLiteral,
|
||||
isNullLiteral,
|
||||
isObjectMethod,
|
||||
isObjectProperty,
|
||||
isRegExpLiteral,
|
||||
isTemplateLiteral,
|
||||
isVariableDeclarator,
|
||||
toBindingIdentifierName,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
const buildPropertyMethodAssignmentWrapper = template(`
|
||||
(function (FUNCTION_KEY) {
|
||||
@ -46,15 +62,15 @@ const visitor = {
|
||||
};
|
||||
|
||||
function getNameFromLiteralId(id) {
|
||||
if (t.isNullLiteral(id)) {
|
||||
if (isNullLiteral(id)) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
if (t.isRegExpLiteral(id)) {
|
||||
if (isRegExpLiteral(id)) {
|
||||
return `_${id.pattern}_${id.flags}`;
|
||||
}
|
||||
|
||||
if (t.isTemplateLiteral(id)) {
|
||||
if (isTemplateLiteral(id)) {
|
||||
return id.quasis.map(quasi => quasi.value.raw).join("");
|
||||
}
|
||||
|
||||
@ -72,7 +88,7 @@ function wrap(state, method, id, scope) {
|
||||
scope.rename(id.name);
|
||||
} else {
|
||||
// we don't currently support wrapping class expressions
|
||||
if (!t.isFunction(method)) return;
|
||||
if (!isFunction(method)) return;
|
||||
|
||||
// need to add a wrapper since we can't change the references
|
||||
let build = buildPropertyMethodAssignmentWrapper;
|
||||
@ -170,18 +186,17 @@ export default function (
|
||||
if (node.id) return;
|
||||
|
||||
if (
|
||||
(t.isObjectProperty(parent) ||
|
||||
t.isObjectMethod(parent, { kind: "method" })) &&
|
||||
(!parent.computed || t.isLiteral(parent.key))
|
||||
(isObjectProperty(parent) || isObjectMethod(parent, { kind: "method" })) &&
|
||||
(!parent.computed || isLiteral(parent.key))
|
||||
) {
|
||||
// { foo() {} };
|
||||
id = parent.key;
|
||||
} else if (t.isVariableDeclarator(parent)) {
|
||||
} else if (isVariableDeclarator(parent)) {
|
||||
// let foo = function () {};
|
||||
id = parent.id;
|
||||
|
||||
// but not "let foo = () => {};" being converted to function expression
|
||||
if (t.isIdentifier(id) && !localBinding) {
|
||||
if (isIdentifier(id) && !localBinding) {
|
||||
const binding = scope.parent.getBinding(id.name);
|
||||
if (
|
||||
binding &&
|
||||
@ -189,12 +204,12 @@ export default function (
|
||||
scope.getBinding(id.name) === binding
|
||||
) {
|
||||
// always going to reference this method
|
||||
node.id = t.cloneNode(id);
|
||||
node.id[t.NOT_LOCAL_BINDING] = true;
|
||||
node.id = cloneNode(id);
|
||||
node.id[NOT_LOCAL_BINDING] = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (t.isAssignmentExpression(parent, { operator: "=" })) {
|
||||
} else if (isAssignmentExpression(parent, { operator: "=" })) {
|
||||
// foo = function () {};
|
||||
id = parent.left;
|
||||
} else if (!id) {
|
||||
@ -202,9 +217,9 @@ export default function (
|
||||
}
|
||||
|
||||
let name;
|
||||
if (id && t.isLiteral(id)) {
|
||||
if (id && isLiteral(id)) {
|
||||
name = getNameFromLiteralId(id);
|
||||
} else if (id && t.isIdentifier(id)) {
|
||||
} else if (id && isIdentifier(id)) {
|
||||
name = id.name;
|
||||
}
|
||||
|
||||
@ -212,13 +227,13 @@ export default function (
|
||||
return;
|
||||
}
|
||||
|
||||
name = t.toBindingIdentifierName(name);
|
||||
id = t.identifier(name);
|
||||
name = toBindingIdentifierName(name);
|
||||
id = identifier(name);
|
||||
|
||||
// The id shouldn't be considered a local binding to the function because
|
||||
// we are simply trying to set the function name and not actually create
|
||||
// a local binding.
|
||||
id[t.NOT_LOCAL_BINDING] = true;
|
||||
id[NOT_LOCAL_BINDING] = true;
|
||||
|
||||
const state = visit(node, name, scope);
|
||||
return wrap(state, node, id, scope) || node;
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import * as t from "@babel/types";
|
||||
import { isAssignmentPattern, isRestElement } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
export default function (node: t.Function): number {
|
||||
const params = node.params;
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const param = params[i];
|
||||
if (t.isAssignmentPattern(param) || t.isRestElement(param)) {
|
||||
if (isAssignmentPattern(param) || isRestElement(param)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
assignmentExpression,
|
||||
expressionStatement,
|
||||
identifier,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import type { NodePath } from "@babel/traverse";
|
||||
|
||||
export type EmitFunction = (
|
||||
@ -38,14 +43,14 @@ const visitor = {
|
||||
|
||||
if (declar.node.init) {
|
||||
nodes.push(
|
||||
t.expressionStatement(
|
||||
t.assignmentExpression("=", declar.node.id, declar.node.init),
|
||||
expressionStatement(
|
||||
assignmentExpression("=", declar.node.id, declar.node.init),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
for (const name of Object.keys(declar.getBindingIdentifiers())) {
|
||||
state.emit(t.identifier(name), name, declar.node.init !== null);
|
||||
state.emit(identifier(name), name, declar.node.init !== null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,28 @@
|
||||
import type { NodePath, Visitor } from "@babel/traverse";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
LOGICAL_OPERATORS,
|
||||
arrowFunctionExpression,
|
||||
assignmentExpression,
|
||||
binaryExpression,
|
||||
booleanLiteral,
|
||||
callExpression,
|
||||
cloneNode,
|
||||
conditionalExpression,
|
||||
identifier,
|
||||
isMemberExpression,
|
||||
isOptionalCallExpression,
|
||||
isOptionalMemberExpression,
|
||||
isUpdateExpression,
|
||||
logicalExpression,
|
||||
memberExpression,
|
||||
nullLiteral,
|
||||
numericLiteral,
|
||||
optionalCallExpression,
|
||||
optionalMemberExpression,
|
||||
sequenceExpression,
|
||||
unaryExpression,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import { willPathCastToBoolean } from "./util";
|
||||
|
||||
class AssignmentMemoiser {
|
||||
@ -22,7 +45,7 @@ class AssignmentMemoiser {
|
||||
if (record.count === 0) {
|
||||
// The `count` access is the outermost function call (hopefully), so it
|
||||
// does the assignment.
|
||||
return t.assignmentExpression("=", value, key);
|
||||
return assignmentExpression("=", value, key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@ -37,8 +60,8 @@ function toNonOptional(
|
||||
base: t.Expression,
|
||||
): t.Expression {
|
||||
const { node } = path;
|
||||
if (t.isOptionalMemberExpression(node)) {
|
||||
return t.memberExpression(base, node.property, node.computed);
|
||||
if (isOptionalMemberExpression(node)) {
|
||||
return memberExpression(base, node.property, node.computed);
|
||||
}
|
||||
|
||||
if (path.isOptionalCallExpression()) {
|
||||
@ -48,15 +71,15 @@ function toNonOptional(
|
||||
const context = path.scope.maybeGenerateMemoised(object) || object;
|
||||
callee
|
||||
.get("object")
|
||||
.replaceWith(t.assignmentExpression("=", context as t.LVal, object));
|
||||
.replaceWith(assignmentExpression("=", context as t.LVal, object));
|
||||
|
||||
return t.callExpression(t.memberExpression(base, t.identifier("call")), [
|
||||
return callExpression(memberExpression(base, identifier("call")), [
|
||||
context,
|
||||
...path.node.arguments,
|
||||
]);
|
||||
}
|
||||
|
||||
return t.callExpression(base, path.node.arguments);
|
||||
return callExpression(base, path.node.arguments);
|
||||
}
|
||||
|
||||
return path.node;
|
||||
@ -108,13 +131,13 @@ const handle = {
|
||||
// actually, we can consider the `baz` access to be the end. So we're
|
||||
// looking for the nearest optional chain that is `optional: true`.
|
||||
const endPath = member.find(({ node, parent }) => {
|
||||
if (t.isOptionalMemberExpression(parent)) {
|
||||
if (isOptionalMemberExpression(parent)) {
|
||||
// We need to check `parent.object` since we could be inside the
|
||||
// computed expression of a `bad?.[FOO?.BAR]`. In this case, the
|
||||
// endPath is the `FOO?.BAR` member itself.
|
||||
return parent.optional || parent.object !== node;
|
||||
}
|
||||
if (t.isOptionalCallExpression(parent)) {
|
||||
if (isOptionalCallExpression(parent)) {
|
||||
// Checking `parent.callee` since we could be in the arguments, eg
|
||||
// `bad?.(FOO?.BAR)`.
|
||||
// Also skip `FOO?.BAR` in `FOO?.BAR?.()` since we need to transform the optional call to ensure proper this
|
||||
@ -132,7 +155,7 @@ const handle = {
|
||||
if (scope.path.isPattern()) {
|
||||
endPath.replaceWith(
|
||||
// The injected member will be queued and eventually transformed when visited
|
||||
t.callExpression(t.arrowFunctionExpression([], endPath.node), []),
|
||||
callExpression(arrowFunctionExpression([], endPath.node), []),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -239,7 +262,7 @@ const handle = {
|
||||
let context: t.Identifier;
|
||||
const endParentPath = endPath.parentPath as NodePath<t.Expression>;
|
||||
if (
|
||||
t.isMemberExpression(regular) &&
|
||||
isMemberExpression(regular) &&
|
||||
endParentPath.isOptionalCallExpression({
|
||||
callee: endPath.node,
|
||||
optional: true,
|
||||
@ -248,7 +271,7 @@ const handle = {
|
||||
const { object } = regular;
|
||||
context = member.scope.maybeGenerateMemoised(object);
|
||||
if (context) {
|
||||
regular.object = t.assignmentExpression("=", context, object);
|
||||
regular.object = assignmentExpression("=", context, object);
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,60 +282,48 @@ const handle = {
|
||||
}
|
||||
|
||||
const baseMemoised = baseNeedsMemoised
|
||||
? t.assignmentExpression(
|
||||
"=",
|
||||
t.cloneNode(baseRef),
|
||||
t.cloneNode(startingNode),
|
||||
)
|
||||
: t.cloneNode(baseRef);
|
||||
? assignmentExpression("=", cloneNode(baseRef), cloneNode(startingNode))
|
||||
: cloneNode(baseRef);
|
||||
|
||||
if (willEndPathCastToBoolean) {
|
||||
let nonNullishCheck;
|
||||
if (noDocumentAll) {
|
||||
nonNullishCheck = t.binaryExpression(
|
||||
"!=",
|
||||
baseMemoised,
|
||||
t.nullLiteral(),
|
||||
);
|
||||
nonNullishCheck = binaryExpression("!=", baseMemoised, nullLiteral());
|
||||
} else {
|
||||
nonNullishCheck = t.logicalExpression(
|
||||
nonNullishCheck = logicalExpression(
|
||||
"&&",
|
||||
t.binaryExpression("!==", baseMemoised, t.nullLiteral()),
|
||||
t.binaryExpression(
|
||||
binaryExpression("!==", baseMemoised, nullLiteral()),
|
||||
binaryExpression(
|
||||
"!==",
|
||||
t.cloneNode(baseRef),
|
||||
cloneNode(baseRef),
|
||||
scope.buildUndefinedNode(),
|
||||
),
|
||||
);
|
||||
}
|
||||
replacementPath.replaceWith(
|
||||
t.logicalExpression("&&", nonNullishCheck, regular),
|
||||
logicalExpression("&&", nonNullishCheck, regular),
|
||||
);
|
||||
} else {
|
||||
let nullishCheck;
|
||||
if (noDocumentAll) {
|
||||
nullishCheck = t.binaryExpression(
|
||||
"==",
|
||||
baseMemoised,
|
||||
t.nullLiteral(),
|
||||
);
|
||||
nullishCheck = binaryExpression("==", baseMemoised, nullLiteral());
|
||||
} else {
|
||||
nullishCheck = t.logicalExpression(
|
||||
nullishCheck = logicalExpression(
|
||||
"||",
|
||||
t.binaryExpression("===", baseMemoised, t.nullLiteral()),
|
||||
t.binaryExpression(
|
||||
binaryExpression("===", baseMemoised, nullLiteral()),
|
||||
binaryExpression(
|
||||
"===",
|
||||
t.cloneNode(baseRef),
|
||||
cloneNode(baseRef),
|
||||
scope.buildUndefinedNode(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
replacementPath.replaceWith(
|
||||
t.conditionalExpression(
|
||||
conditionalExpression(
|
||||
nullishCheck,
|
||||
isDeleteOperation
|
||||
? t.booleanLiteral(true)
|
||||
? booleanLiteral(true)
|
||||
: scope.buildUndefinedNode(),
|
||||
regular,
|
||||
),
|
||||
@ -323,14 +334,14 @@ const handle = {
|
||||
if (context) {
|
||||
const endParent = endParentPath.node as t.OptionalCallExpression;
|
||||
endParentPath.replaceWith(
|
||||
t.optionalCallExpression(
|
||||
t.optionalMemberExpression(
|
||||
optionalCallExpression(
|
||||
optionalMemberExpression(
|
||||
endParent.callee,
|
||||
t.identifier("call"),
|
||||
identifier("call"),
|
||||
false,
|
||||
true,
|
||||
),
|
||||
[t.cloneNode(context), ...endParent.arguments],
|
||||
[cloneNode(context), ...endParent.arguments],
|
||||
false,
|
||||
),
|
||||
);
|
||||
@ -341,7 +352,7 @@ const handle = {
|
||||
|
||||
// MEMBER++ -> _set(MEMBER, (_ref = (+_get(MEMBER))) + 1), _ref
|
||||
// ++MEMBER -> _set(MEMBER, (+_get(MEMBER)) + 1)
|
||||
if (t.isUpdateExpression(parent, { argument: node })) {
|
||||
if (isUpdateExpression(parent, { argument: node })) {
|
||||
if (this.simpleSet) {
|
||||
member.replaceWith(this.simpleSet(member));
|
||||
return;
|
||||
@ -354,10 +365,10 @@ const handle = {
|
||||
// assignment.
|
||||
this.memoise(member, 2);
|
||||
|
||||
const value = t.binaryExpression(
|
||||
const value = binaryExpression(
|
||||
operator[0] as "+" | "-",
|
||||
t.unaryExpression("+", this.get(member)),
|
||||
t.numericLiteral(1),
|
||||
unaryExpression("+", this.get(member)),
|
||||
numericLiteral(1),
|
||||
);
|
||||
|
||||
if (prefix) {
|
||||
@ -367,15 +378,15 @@ const handle = {
|
||||
const ref = scope.generateUidIdentifierBasedOnNode(node);
|
||||
scope.push({ id: ref });
|
||||
|
||||
value.left = t.assignmentExpression(
|
||||
value.left = assignmentExpression(
|
||||
"=",
|
||||
t.cloneNode(ref),
|
||||
cloneNode(ref),
|
||||
// @ts-expect-error todo(flow->ts) value.left is possibly PrivateName, which is not usable here
|
||||
value.left,
|
||||
);
|
||||
|
||||
parentPath.replaceWith(
|
||||
t.sequenceExpression([this.set(member, value), t.cloneNode(ref)]),
|
||||
sequenceExpression([this.set(member, value), cloneNode(ref)]),
|
||||
);
|
||||
}
|
||||
return;
|
||||
@ -396,13 +407,13 @@ const handle = {
|
||||
parentPath.replaceWith(this.set(member, value));
|
||||
} else {
|
||||
const operatorTrunc = operator.slice(0, -1);
|
||||
if (t.LOGICAL_OPERATORS.includes(operatorTrunc)) {
|
||||
if (LOGICAL_OPERATORS.includes(operatorTrunc)) {
|
||||
// Give the state handler a chance to memoise the member, since we'll
|
||||
// reference it twice. The first access (the get) should do the memo
|
||||
// assignment.
|
||||
this.memoise(member, 1);
|
||||
parentPath.replaceWith(
|
||||
t.logicalExpression(
|
||||
logicalExpression(
|
||||
operatorTrunc as t.LogicalExpression["operator"],
|
||||
this.get(member),
|
||||
this.set(member, value),
|
||||
@ -414,7 +425,7 @@ const handle = {
|
||||
parentPath.replaceWith(
|
||||
this.set(
|
||||
member,
|
||||
t.binaryExpression(
|
||||
binaryExpression(
|
||||
operatorTrunc as t.BinaryExpression["operator"],
|
||||
this.get(member),
|
||||
value,
|
||||
@ -440,7 +451,7 @@ const handle = {
|
||||
if (scope.path.isPattern()) {
|
||||
parentPath.replaceWith(
|
||||
// The injected member will be queued and eventually transformed when visited
|
||||
t.callExpression(t.arrowFunctionExpression([], parentPath.node), []),
|
||||
callExpression(arrowFunctionExpression([], parentPath.node), []),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1,5 +1,18 @@
|
||||
import assert from "assert";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
callExpression,
|
||||
cloneNode,
|
||||
expressionStatement,
|
||||
identifier,
|
||||
importDeclaration,
|
||||
importDefaultSpecifier,
|
||||
importNamespaceSpecifier,
|
||||
importSpecifier,
|
||||
memberExpression,
|
||||
stringLiteral,
|
||||
variableDeclaration,
|
||||
variableDeclarator,
|
||||
} from "@babel/types";
|
||||
|
||||
/**
|
||||
* A class to track and accumulate mutations to the AST that will eventually
|
||||
@ -28,16 +41,16 @@ export default class ImportBuilder {
|
||||
|
||||
import() {
|
||||
this._statements.push(
|
||||
t.importDeclaration([], t.stringLiteral(this._importedSource)),
|
||||
importDeclaration([], stringLiteral(this._importedSource)),
|
||||
);
|
||||
return this;
|
||||
}
|
||||
|
||||
require() {
|
||||
this._statements.push(
|
||||
t.expressionStatement(
|
||||
t.callExpression(t.identifier("require"), [
|
||||
t.stringLiteral(this._importedSource),
|
||||
expressionStatement(
|
||||
callExpression(identifier("require"), [
|
||||
stringLiteral(this._importedSource),
|
||||
]),
|
||||
),
|
||||
);
|
||||
@ -50,8 +63,8 @@ export default class ImportBuilder {
|
||||
const statement = this._statements[this._statements.length - 1];
|
||||
assert(statement.type === "ImportDeclaration");
|
||||
assert(statement.specifiers.length === 0);
|
||||
statement.specifiers = [t.importNamespaceSpecifier(local)];
|
||||
this._resultName = t.cloneNode(local);
|
||||
statement.specifiers = [importNamespaceSpecifier(local)];
|
||||
this._resultName = cloneNode(local);
|
||||
return this;
|
||||
}
|
||||
default(name) {
|
||||
@ -59,8 +72,8 @@ export default class ImportBuilder {
|
||||
const statement = this._statements[this._statements.length - 1];
|
||||
assert(statement.type === "ImportDeclaration");
|
||||
assert(statement.specifiers.length === 0);
|
||||
statement.specifiers = [t.importDefaultSpecifier(name)];
|
||||
this._resultName = t.cloneNode(name);
|
||||
statement.specifiers = [importDefaultSpecifier(name)];
|
||||
this._resultName = cloneNode(name);
|
||||
return this;
|
||||
}
|
||||
named(name, importName) {
|
||||
@ -70,8 +83,8 @@ export default class ImportBuilder {
|
||||
const statement = this._statements[this._statements.length - 1];
|
||||
assert(statement.type === "ImportDeclaration");
|
||||
assert(statement.specifiers.length === 0);
|
||||
statement.specifiers = [t.importSpecifier(name, t.identifier(importName))];
|
||||
this._resultName = t.cloneNode(name);
|
||||
statement.specifiers = [importSpecifier(name, identifier(importName))];
|
||||
this._resultName = cloneNode(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -80,14 +93,13 @@ export default class ImportBuilder {
|
||||
let statement = this._statements[this._statements.length - 1];
|
||||
if (statement.type !== "ExpressionStatement") {
|
||||
assert(this._resultName);
|
||||
statement = t.expressionStatement(this._resultName);
|
||||
statement = expressionStatement(this._resultName);
|
||||
this._statements.push(statement);
|
||||
}
|
||||
this._statements[this._statements.length - 1] = t.variableDeclaration(
|
||||
"var",
|
||||
[t.variableDeclarator(name, statement.expression)],
|
||||
);
|
||||
this._resultName = t.cloneNode(name);
|
||||
this._statements[this._statements.length - 1] = variableDeclaration("var", [
|
||||
variableDeclarator(name, statement.expression),
|
||||
]);
|
||||
this._resultName = cloneNode(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -101,10 +113,10 @@ export default class ImportBuilder {
|
||||
_interop(callee) {
|
||||
const statement = this._statements[this._statements.length - 1];
|
||||
if (statement.type === "ExpressionStatement") {
|
||||
statement.expression = t.callExpression(callee, [statement.expression]);
|
||||
statement.expression = callExpression(callee, [statement.expression]);
|
||||
} else if (statement.type === "VariableDeclaration") {
|
||||
assert(statement.declarations.length === 1);
|
||||
statement.declarations[0].init = t.callExpression(callee, [
|
||||
statement.declarations[0].init = callExpression(callee, [
|
||||
statement.declarations[0].init,
|
||||
]);
|
||||
} else {
|
||||
@ -116,15 +128,15 @@ export default class ImportBuilder {
|
||||
prop(name) {
|
||||
const statement = this._statements[this._statements.length - 1];
|
||||
if (statement.type === "ExpressionStatement") {
|
||||
statement.expression = t.memberExpression(
|
||||
statement.expression = memberExpression(
|
||||
statement.expression,
|
||||
t.identifier(name),
|
||||
identifier(name),
|
||||
);
|
||||
} else if (statement.type === "VariableDeclaration") {
|
||||
assert(statement.declarations.length === 1);
|
||||
statement.declarations[0].init = t.memberExpression(
|
||||
statement.declarations[0].init = memberExpression(
|
||||
statement.declarations[0].init,
|
||||
t.identifier(name),
|
||||
identifier(name),
|
||||
);
|
||||
} else {
|
||||
assert.fail("Unexpected type:" + statement.type);
|
||||
@ -133,6 +145,6 @@ export default class ImportBuilder {
|
||||
}
|
||||
|
||||
read(name) {
|
||||
this._resultName = t.memberExpression(this._resultName, t.identifier(name));
|
||||
this._resultName = memberExpression(this._resultName, identifier(name));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import assert from "assert";
|
||||
import * as t from "@babel/types";
|
||||
import { numericLiteral, sequenceExpression } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import type { NodePath, Scope, HubInterface } from "@babel/traverse";
|
||||
|
||||
import ImportBuilder from "./import-builder";
|
||||
@ -416,7 +417,7 @@ export default class ImportInjector {
|
||||
ensureNoContext &&
|
||||
resultName.type !== "Identifier"
|
||||
) {
|
||||
return t.sequenceExpression([t.numericLiteral(0), resultName]);
|
||||
return sequenceExpression([numericLiteral(0), resultName]);
|
||||
}
|
||||
return resultName;
|
||||
}
|
||||
|
||||
@ -1,5 +1,20 @@
|
||||
import assert from "assert";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
booleanLiteral,
|
||||
callExpression,
|
||||
cloneNode,
|
||||
directive,
|
||||
directiveLiteral,
|
||||
expressionStatement,
|
||||
identifier,
|
||||
isIdentifier,
|
||||
memberExpression,
|
||||
stringLiteral,
|
||||
valueToNode,
|
||||
variableDeclaration,
|
||||
variableDeclarator,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import template from "@babel/template";
|
||||
|
||||
import { isModule } from "@babel/helper-module-imports";
|
||||
@ -85,7 +100,7 @@ export function rewriteModuleStatementsAndPrepareHeader(
|
||||
if (!hasStrict) {
|
||||
path.unshiftContainer(
|
||||
"directives",
|
||||
t.directive(t.directiveLiteral("use strict")),
|
||||
directive(directiveLiteral("use strict")),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -140,10 +155,10 @@ export function wrapInterop(
|
||||
}
|
||||
|
||||
if (type === "node-namespace") {
|
||||
return t.callExpression(
|
||||
programPath.hub.addHelper("interopRequireWildcard"),
|
||||
[expr, t.booleanLiteral(true)],
|
||||
);
|
||||
return callExpression(programPath.hub.addHelper("interopRequireWildcard"), [
|
||||
expr,
|
||||
booleanLiteral(true),
|
||||
]);
|
||||
} else if (type === "node-default") {
|
||||
return null;
|
||||
}
|
||||
@ -157,7 +172,7 @@ export function wrapInterop(
|
||||
throw new Error(`Unknown interop: ${type}`);
|
||||
}
|
||||
|
||||
return t.callExpression(programPath.hub.addHelper(helper), [expr]);
|
||||
return callExpression(programPath.hub.addHelper(helper), [expr]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -173,8 +188,8 @@ export function buildNamespaceInitStatements(
|
||||
) {
|
||||
const statements = [];
|
||||
|
||||
let srcNamespace: t.Node = t.identifier(sourceMetadata.name);
|
||||
if (sourceMetadata.lazy) srcNamespace = t.callExpression(srcNamespace, []);
|
||||
let srcNamespace: t.Node = identifier(sourceMetadata.name);
|
||||
if (sourceMetadata.lazy) srcNamespace = callExpression(srcNamespace, []);
|
||||
|
||||
for (const localName of sourceMetadata.importsNamespace) {
|
||||
if (localName === sourceMetadata.name) continue;
|
||||
@ -183,7 +198,7 @@ export function buildNamespaceInitStatements(
|
||||
statements.push(
|
||||
template.statement`var NAME = SOURCE;`({
|
||||
NAME: localName,
|
||||
SOURCE: t.cloneNode(srcNamespace),
|
||||
SOURCE: cloneNode(srcNamespace),
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -205,14 +220,14 @@ export function buildNamespaceInitStatements(
|
||||
: template.statement`EXPORTS.NAME = NAMESPACE;`)({
|
||||
EXPORTS: metadata.exportName,
|
||||
NAME: exportName,
|
||||
NAMESPACE: t.cloneNode(srcNamespace),
|
||||
NAMESPACE: cloneNode(srcNamespace),
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (sourceMetadata.reexportAll) {
|
||||
const statement = buildNamespaceReexport(
|
||||
metadata,
|
||||
t.cloneNode(srcNamespace),
|
||||
cloneNode(srcNamespace),
|
||||
constantReexports,
|
||||
);
|
||||
statement.loc = sourceMetadata.reexportAll.loc;
|
||||
@ -242,24 +257,24 @@ const buildReexportsFromMeta = (
|
||||
constantReexports: boolean,
|
||||
) => {
|
||||
const namespace = metadata.lazy
|
||||
? t.callExpression(t.identifier(metadata.name), [])
|
||||
: t.identifier(metadata.name);
|
||||
? callExpression(identifier(metadata.name), [])
|
||||
: identifier(metadata.name);
|
||||
|
||||
const { stringSpecifiers } = meta;
|
||||
return Array.from(metadata.reexports, ([exportName, importName]) => {
|
||||
let NAMESPACE_IMPORT: t.Expression = t.cloneNode(namespace);
|
||||
let NAMESPACE_IMPORT: t.Expression = cloneNode(namespace);
|
||||
if (importName === "default" && metadata.interop === "node-default") {
|
||||
// Nothing, it's ok as-is
|
||||
} else if (stringSpecifiers.has(importName)) {
|
||||
NAMESPACE_IMPORT = t.memberExpression(
|
||||
NAMESPACE_IMPORT = memberExpression(
|
||||
NAMESPACE_IMPORT,
|
||||
t.stringLiteral(importName),
|
||||
stringLiteral(importName),
|
||||
true,
|
||||
);
|
||||
} else {
|
||||
NAMESPACE_IMPORT = t.memberExpression(
|
||||
NAMESPACE_IMPORT = memberExpression(
|
||||
NAMESPACE_IMPORT,
|
||||
t.identifier(importName),
|
||||
identifier(importName),
|
||||
);
|
||||
}
|
||||
const astNodes = {
|
||||
@ -267,7 +282,7 @@ const buildReexportsFromMeta = (
|
||||
EXPORT_NAME: exportName,
|
||||
NAMESPACE_IMPORT,
|
||||
};
|
||||
if (constantReexports || t.isIdentifier(NAMESPACE_IMPORT)) {
|
||||
if (constantReexports || isIdentifier(NAMESPACE_IMPORT)) {
|
||||
if (stringSpecifiers.has(exportName)) {
|
||||
return ReexportTemplate.constantComputed(astNodes);
|
||||
} else {
|
||||
@ -381,8 +396,8 @@ function buildExportNameListDeclaration(
|
||||
|
||||
return {
|
||||
name: name.name,
|
||||
statement: t.variableDeclaration("var", [
|
||||
t.variableDeclarator(name, t.valueToNode(exportedVars)),
|
||||
statement: variableDeclaration("var", [
|
||||
variableDeclarator(name, valueToNode(exportedVars)),
|
||||
]),
|
||||
};
|
||||
}
|
||||
@ -405,7 +420,7 @@ function buildExportInitializationStatements(
|
||||
// No-open since these are explicitly set with the "reexports" block.
|
||||
} else if (data.kind === "hoisted") {
|
||||
initStatements.push(
|
||||
buildInitStatement(metadata, data.names, t.identifier(localName)),
|
||||
buildInitStatement(metadata, data.names, identifier(localName)),
|
||||
);
|
||||
} else {
|
||||
exportNames.push(...data.names);
|
||||
@ -447,7 +462,7 @@ const InitTemplate = {
|
||||
|
||||
function buildInitStatement(metadata: ModuleMetadata, exportNames, initExpr) {
|
||||
const { stringSpecifiers, exportName: EXPORTS } = metadata;
|
||||
return t.expressionStatement(
|
||||
return expressionStatement(
|
||||
exportNames.reduce((acc, exportName) => {
|
||||
const params = {
|
||||
EXPORTS,
|
||||
|
||||
@ -1,5 +1,23 @@
|
||||
import assert from "assert";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
assignmentExpression,
|
||||
callExpression,
|
||||
cloneNode,
|
||||
expressionStatement,
|
||||
getOuterBindingIdentifiers,
|
||||
identifier,
|
||||
isMemberExpression,
|
||||
isVariableDeclaration,
|
||||
jsxIdentifier,
|
||||
jsxMemberExpression,
|
||||
memberExpression,
|
||||
numericLiteral,
|
||||
sequenceExpression,
|
||||
stringLiteral,
|
||||
variableDeclaration,
|
||||
variableDeclarator,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import template from "@babel/template";
|
||||
import type { NodePath, Visitor, Scope } from "@babel/traverse";
|
||||
import simplifyAccess from "@babel/helper-simple-access";
|
||||
@ -89,12 +107,12 @@ export default function rewriteLiveReferences(
|
||||
const meta = metadata.source.get(source);
|
||||
|
||||
if (localName) {
|
||||
if (meta.lazy) identNode = t.callExpression(identNode, []);
|
||||
if (meta.lazy) identNode = callExpression(identNode, []);
|
||||
return identNode;
|
||||
}
|
||||
|
||||
let namespace: t.Expression = t.identifier(meta.name);
|
||||
if (meta.lazy) namespace = t.callExpression(namespace, []);
|
||||
let namespace: t.Expression = identifier(meta.name);
|
||||
if (meta.lazy) namespace = callExpression(namespace, []);
|
||||
|
||||
if (importName === "default" && meta.interop === "node-default") {
|
||||
return namespace;
|
||||
@ -102,9 +120,9 @@ export default function rewriteLiveReferences(
|
||||
|
||||
const computed = metadata.stringSpecifiers.has(importName);
|
||||
|
||||
return t.memberExpression(
|
||||
return memberExpression(
|
||||
namespace,
|
||||
computed ? t.stringLiteral(importName) : t.identifier(importName),
|
||||
computed ? stringLiteral(importName) : identifier(importName),
|
||||
computed,
|
||||
);
|
||||
},
|
||||
@ -128,11 +146,11 @@ const rewriteBindingInitVisitor: Visitor<RewriteBindingInitVisitorState> = {
|
||||
|
||||
const exportNames = exported.get(localName) || [];
|
||||
if (exportNames.length > 0) {
|
||||
const statement = t.expressionStatement(
|
||||
const statement = expressionStatement(
|
||||
buildBindingExportAssignmentExpression(
|
||||
metadata,
|
||||
exportNames,
|
||||
t.identifier(localName),
|
||||
identifier(localName),
|
||||
),
|
||||
);
|
||||
// @ts-expect-error todo(flow->ts): avoid mutations
|
||||
@ -148,11 +166,11 @@ const rewriteBindingInitVisitor: Visitor<RewriteBindingInitVisitorState> = {
|
||||
const exportNames = exported.get(localName) || [];
|
||||
|
||||
if (exportNames.length > 0) {
|
||||
const statement = t.expressionStatement(
|
||||
const statement = expressionStatement(
|
||||
buildBindingExportAssignmentExpression(
|
||||
metadata,
|
||||
exportNames,
|
||||
t.identifier(localName),
|
||||
identifier(localName),
|
||||
),
|
||||
);
|
||||
// @ts-expect-error todo(flow->ts): avoid mutations
|
||||
@ -175,11 +193,11 @@ const buildBindingExportAssignmentExpression = (
|
||||
// class Foo {} exports.Foo = exports.Bar = Foo;
|
||||
const { stringSpecifiers } = metadata;
|
||||
const computed = stringSpecifiers.has(exportName);
|
||||
return t.assignmentExpression(
|
||||
return assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(
|
||||
t.identifier(metadata.exportName),
|
||||
computed ? t.stringLiteral(exportName) : t.identifier(exportName),
|
||||
memberExpression(
|
||||
identifier(metadata.exportName),
|
||||
computed ? stringLiteral(exportName) : identifier(exportName),
|
||||
/* computed */ computed,
|
||||
),
|
||||
expr,
|
||||
@ -221,17 +239,17 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {
|
||||
(path.parentPath.isCallExpression({ callee: path.node }) ||
|
||||
path.parentPath.isOptionalCallExpression({ callee: path.node }) ||
|
||||
path.parentPath.isTaggedTemplateExpression({ tag: path.node })) &&
|
||||
t.isMemberExpression(ref)
|
||||
isMemberExpression(ref)
|
||||
) {
|
||||
path.replaceWith(t.sequenceExpression([t.numericLiteral(0), ref]));
|
||||
} else if (path.isJSXIdentifier() && t.isMemberExpression(ref)) {
|
||||
path.replaceWith(sequenceExpression([numericLiteral(0), ref]));
|
||||
} else if (path.isJSXIdentifier() && isMemberExpression(ref)) {
|
||||
const { object, property } = ref;
|
||||
path.replaceWith(
|
||||
t.jsxMemberExpression(
|
||||
jsxMemberExpression(
|
||||
// @ts-expect-error todo(flow->ts): possible bug `object` might not have a name
|
||||
t.jsxIdentifier(object.name),
|
||||
jsxIdentifier(object.name),
|
||||
// @ts-expect-error todo(flow->ts): possible bug `property` might not have a name
|
||||
t.jsxIdentifier(property.name),
|
||||
jsxIdentifier(property.name),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
@ -285,7 +303,7 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {
|
||||
if (importData) {
|
||||
assignment.left = buildImportReference(importData, assignment.left);
|
||||
|
||||
assignment.right = t.sequenceExpression([
|
||||
assignment.right = sequenceExpression([
|
||||
assignment.right,
|
||||
buildImportThrow(localName),
|
||||
]);
|
||||
@ -309,7 +327,7 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {
|
||||
const id = programScopeIds.find(localName => imported.has(localName));
|
||||
|
||||
if (id) {
|
||||
path.node.right = t.sequenceExpression([
|
||||
path.node.right = sequenceExpression([
|
||||
path.node.right,
|
||||
buildImportThrow(id),
|
||||
]);
|
||||
@ -325,16 +343,16 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {
|
||||
buildBindingExportAssignmentExpression(
|
||||
this.metadata,
|
||||
exportedNames,
|
||||
t.identifier(localName),
|
||||
identifier(localName),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
if (items.length > 0) {
|
||||
let node: t.Node = t.sequenceExpression(items);
|
||||
let node: t.Node = sequenceExpression(items);
|
||||
if (path.parentPath.isExpressionStatement()) {
|
||||
node = t.expressionStatement(node);
|
||||
node = expressionStatement(node);
|
||||
// @ts-expect-error todo(flow->ts): avoid mutations
|
||||
node._blockHoist = path.parentPath.node._blockHoist;
|
||||
}
|
||||
@ -352,11 +370,11 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {
|
||||
const { left } = node;
|
||||
const { exported, imported, scope: programScope } = this;
|
||||
|
||||
if (!t.isVariableDeclaration(left)) {
|
||||
if (!isVariableDeclaration(left)) {
|
||||
let didTransformExport = false,
|
||||
importConstViolationName;
|
||||
const loopBodyScope = path.get("body").scope;
|
||||
for (const name of Object.keys(t.getOuterBindingIdentifiers(left))) {
|
||||
for (const name of Object.keys(getOuterBindingIdentifiers(left))) {
|
||||
if (programScope.getBinding(name) === scope.getBinding(name)) {
|
||||
if (exported.has(name)) {
|
||||
didTransformExport = true;
|
||||
@ -380,8 +398,8 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {
|
||||
path
|
||||
.get("left")
|
||||
.replaceWith(
|
||||
t.variableDeclaration("let", [
|
||||
t.variableDeclarator(t.cloneNode(newLoopId)),
|
||||
variableDeclaration("let", [
|
||||
variableDeclarator(cloneNode(newLoopId)),
|
||||
]),
|
||||
);
|
||||
scope.registerDeclaration(path.get("left"));
|
||||
@ -389,13 +407,13 @@ const rewriteReferencesVisitor: Visitor<RewriteReferencesVisitorState> = {
|
||||
if (didTransformExport) {
|
||||
bodyPath.unshiftContainer(
|
||||
"body",
|
||||
t.expressionStatement(t.assignmentExpression("=", left, newLoopId)),
|
||||
expressionStatement(assignmentExpression("=", left, newLoopId)),
|
||||
);
|
||||
}
|
||||
if (importConstViolationName) {
|
||||
bodyPath.unshiftContainer(
|
||||
"body",
|
||||
t.expressionStatement(buildImportThrow(importConstViolationName)),
|
||||
expressionStatement(buildImportThrow(importConstViolationName)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { environmentVisitor } from "@babel/helper-replace-supers";
|
||||
import traverse from "@babel/traverse";
|
||||
import * as t from "@babel/types";
|
||||
import { numericLiteral, unaryExpression } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
import type { NodePath, Visitor } from "@babel/traverse";
|
||||
export default function rewriteThis(programPath: NodePath) {
|
||||
@ -16,7 +17,7 @@ const rewriteThisVisitor: Visitor = traverse.visitors.merge([
|
||||
environmentVisitor,
|
||||
{
|
||||
ThisExpression(path: NodePath<t.ThisExpression>) {
|
||||
path.replaceWith(t.unaryExpression("void", t.numericLiteral(0), true));
|
||||
path.replaceWith(unaryExpression("void", numericLiteral(0), true));
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
@ -1,4 +1,12 @@
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
callExpression,
|
||||
identifier,
|
||||
isIdentifier,
|
||||
isSpreadElement,
|
||||
memberExpression,
|
||||
optionalCallExpression,
|
||||
optionalMemberExpression,
|
||||
} from "@babel/types";
|
||||
import type {
|
||||
CallExpression,
|
||||
Expression,
|
||||
@ -25,33 +33,33 @@ export default function optimiseCallExpression(
|
||||
): CallExpression | OptionalCallExpression {
|
||||
if (
|
||||
args.length === 1 &&
|
||||
t.isSpreadElement(args[0]) &&
|
||||
t.isIdentifier(args[0].argument, { name: "arguments" })
|
||||
isSpreadElement(args[0]) &&
|
||||
isIdentifier(args[0].argument, { name: "arguments" })
|
||||
) {
|
||||
// a.b?.(...arguments);
|
||||
if (optional) {
|
||||
return t.optionalCallExpression(
|
||||
t.optionalMemberExpression(callee, t.identifier("apply"), false, true),
|
||||
return optionalCallExpression(
|
||||
optionalMemberExpression(callee, identifier("apply"), false, true),
|
||||
[thisNode, args[0].argument],
|
||||
false,
|
||||
);
|
||||
}
|
||||
// a.b(...arguments);
|
||||
return t.callExpression(t.memberExpression(callee, t.identifier("apply")), [
|
||||
return callExpression(memberExpression(callee, identifier("apply")), [
|
||||
thisNode,
|
||||
args[0].argument,
|
||||
]);
|
||||
} else {
|
||||
// a.b?.(arg1, arg2)
|
||||
if (optional) {
|
||||
return t.optionalCallExpression(
|
||||
t.optionalMemberExpression(callee, t.identifier("call"), false, true),
|
||||
return optionalCallExpression(
|
||||
optionalMemberExpression(callee, identifier("call"), false, true),
|
||||
[thisNode, ...args],
|
||||
false,
|
||||
);
|
||||
}
|
||||
// a.b(arg1, arg2)
|
||||
return t.callExpression(t.memberExpression(callee, t.identifier("call")), [
|
||||
return callExpression(memberExpression(callee, identifier("call")), [
|
||||
thisNode,
|
||||
...args,
|
||||
]);
|
||||
|
||||
@ -3,7 +3,13 @@
|
||||
import type { NodePath } from "@babel/traverse";
|
||||
import wrapFunction from "@babel/helper-wrap-function";
|
||||
import annotateAsPure from "@babel/helper-annotate-as-pure";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
callExpression,
|
||||
cloneNode,
|
||||
isIdentifier,
|
||||
isThisExpression,
|
||||
yieldExpression,
|
||||
} from "@babel/types";
|
||||
|
||||
const awaitVisitor = {
|
||||
Function(path) {
|
||||
@ -19,9 +25,9 @@ const awaitVisitor = {
|
||||
}
|
||||
|
||||
path.replaceWith(
|
||||
t.yieldExpression(
|
||||
yieldExpression(
|
||||
wrapAwait
|
||||
? t.callExpression(t.cloneNode(wrapAwait), [argument.node])
|
||||
? callExpression(cloneNode(wrapAwait), [argument.node])
|
||||
: argument.node,
|
||||
),
|
||||
);
|
||||
@ -42,7 +48,7 @@ export default function (
|
||||
path.node.async = false;
|
||||
path.node.generator = true;
|
||||
|
||||
wrapFunction(path, t.cloneNode(helpers.wrapAsync), noNewArrows);
|
||||
wrapFunction(path, cloneNode(helpers.wrapAsync), noNewArrows);
|
||||
|
||||
const isProperty =
|
||||
path.isObjectMethod() ||
|
||||
@ -64,7 +70,7 @@ export default function (
|
||||
const { parentPath } = path;
|
||||
if (
|
||||
parentPath.isMemberExpression() &&
|
||||
t.isIdentifier(parentPath.node.property, { name: "bind" })
|
||||
isIdentifier(parentPath.node.property, { name: "bind" })
|
||||
) {
|
||||
const { parentPath: bindCall } = parentPath;
|
||||
|
||||
@ -75,7 +81,7 @@ export default function (
|
||||
bindCall.isCallExpression() &&
|
||||
// and whether its sole argument is 'this'
|
||||
bindCall.node.arguments.length === 1 &&
|
||||
t.isThisExpression(bindCall.node.arguments[0]) &&
|
||||
isThisExpression(bindCall.node.arguments[0]) &&
|
||||
// and whether the result of the .bind(this) is being called
|
||||
bindCall.parentPath.isCallExpression({ callee: bindCall.node })
|
||||
);
|
||||
|
||||
@ -2,7 +2,20 @@ import type { HubInterface, NodePath, Scope } from "@babel/traverse";
|
||||
import traverse from "@babel/traverse";
|
||||
import memberExpressionToFunctions from "@babel/helper-member-expression-to-functions";
|
||||
import optimiseCall from "@babel/helper-optimise-call-expression";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
VISITOR_KEYS,
|
||||
assignmentExpression,
|
||||
booleanLiteral,
|
||||
callExpression,
|
||||
cloneNode,
|
||||
identifier,
|
||||
memberExpression,
|
||||
sequenceExpression,
|
||||
staticBlock,
|
||||
stringLiteral,
|
||||
thisExpression,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
/**
|
||||
* Creates an expression which result is the proto of objectRef.
|
||||
@ -16,13 +29,13 @@ import * as t from "@babel/types";
|
||||
* helpers.getPrototypeOf(CLASS.prototype)
|
||||
*/
|
||||
function getPrototypeOfExpression(objectRef, isStatic, file, isPrivateMethod) {
|
||||
objectRef = t.cloneNode(objectRef);
|
||||
objectRef = cloneNode(objectRef);
|
||||
const targetRef =
|
||||
isStatic || isPrivateMethod
|
||||
? objectRef
|
||||
: t.memberExpression(objectRef, t.identifier("prototype"));
|
||||
: memberExpression(objectRef, identifier("prototype"));
|
||||
|
||||
return t.callExpression(file.addHelper("getPrototypeOf"), [targetRef]);
|
||||
return callExpression(file.addHelper("getPrototypeOf"), [targetRef]);
|
||||
}
|
||||
|
||||
export function skipAllButComputedKey(
|
||||
@ -37,7 +50,7 @@ export function skipAllButComputedKey(
|
||||
|
||||
// So it's got a computed key. Make sure to skip every other key the
|
||||
// traversal would visit.
|
||||
const keys = t.VISITOR_KEYS[path.type];
|
||||
const keys = VISITOR_KEYS[path.type];
|
||||
for (const key of keys) {
|
||||
if (key !== "key") path.skipKey(key);
|
||||
}
|
||||
@ -48,7 +61,7 @@ export function skipAllButComputedKey(
|
||||
// Avoid using `path.scope` here
|
||||
export const environmentVisitor = {
|
||||
// todo (Babel 8): remove StaticBlock brand checks
|
||||
[`${t.staticBlock ? "StaticBlock|" : ""}ClassPrivateProperty|TypeAnnotation`](
|
||||
[`${staticBlock ? "StaticBlock|" : ""}ClassPrivateProperty|TypeAnnotation`](
|
||||
path: NodePath,
|
||||
) {
|
||||
path.skip();
|
||||
@ -110,14 +123,14 @@ const specHandlers = {
|
||||
prop(superMember) {
|
||||
const { computed, property } = superMember.node;
|
||||
if (this.memoiser.has(property)) {
|
||||
return t.cloneNode(this.memoiser.get(property));
|
||||
return cloneNode(this.memoiser.get(property));
|
||||
}
|
||||
|
||||
if (computed) {
|
||||
return t.cloneNode(property);
|
||||
return cloneNode(property);
|
||||
}
|
||||
|
||||
return t.stringLiteral(property.name);
|
||||
return stringLiteral(property.name);
|
||||
},
|
||||
|
||||
get(superMember) {
|
||||
@ -131,8 +144,8 @@ const specHandlers = {
|
||||
this.file,
|
||||
this.isPrivateMethod,
|
||||
);
|
||||
return t.callExpression(this.file.addHelper("get"), [
|
||||
thisRefs.memo ? t.sequenceExpression([thisRefs.memo, proto]) : proto,
|
||||
return callExpression(this.file.addHelper("get"), [
|
||||
thisRefs.memo ? sequenceExpression([thisRefs.memo, proto]) : proto,
|
||||
this.prop(superMember),
|
||||
thisRefs.this,
|
||||
]);
|
||||
@ -140,12 +153,12 @@ const specHandlers = {
|
||||
|
||||
_getThisRefs() {
|
||||
if (!this.isDerivedConstructor) {
|
||||
return { this: t.thisExpression() };
|
||||
return { this: thisExpression() };
|
||||
}
|
||||
const thisRef = this.scope.generateDeclaredUidIdentifier("thisSuper");
|
||||
return {
|
||||
memo: t.assignmentExpression("=", thisRef, t.thisExpression()),
|
||||
this: t.cloneNode(thisRef),
|
||||
memo: assignmentExpression("=", thisRef, thisExpression()),
|
||||
this: cloneNode(thisRef),
|
||||
};
|
||||
},
|
||||
|
||||
@ -157,12 +170,12 @@ const specHandlers = {
|
||||
this.file,
|
||||
this.isPrivateMethod,
|
||||
);
|
||||
return t.callExpression(this.file.addHelper("set"), [
|
||||
thisRefs.memo ? t.sequenceExpression([thisRefs.memo, proto]) : proto,
|
||||
return callExpression(this.file.addHelper("set"), [
|
||||
thisRefs.memo ? sequenceExpression([thisRefs.memo, proto]) : proto,
|
||||
this.prop(superMember),
|
||||
value,
|
||||
thisRefs.this,
|
||||
t.booleanLiteral(superMember.isInStrictMode()),
|
||||
booleanLiteral(superMember.isInStrictMode()),
|
||||
]);
|
||||
},
|
||||
|
||||
@ -176,7 +189,7 @@ const specHandlers = {
|
||||
const thisRefs = this._getThisRefs();
|
||||
return optimiseCall(
|
||||
this._get(superMember, thisRefs),
|
||||
t.cloneNode(thisRefs.this),
|
||||
cloneNode(thisRefs.this),
|
||||
args,
|
||||
false,
|
||||
);
|
||||
@ -186,7 +199,7 @@ const specHandlers = {
|
||||
const thisRefs = this._getThisRefs();
|
||||
return optimiseCall(
|
||||
this._get(superMember, thisRefs),
|
||||
t.cloneNode(thisRefs.this),
|
||||
cloneNode(thisRefs.this),
|
||||
args,
|
||||
true,
|
||||
);
|
||||
@ -199,10 +212,10 @@ const looseHandlers = {
|
||||
prop(superMember) {
|
||||
const { property } = superMember.node;
|
||||
if (this.memoiser.has(property)) {
|
||||
return t.cloneNode(this.memoiser.get(property));
|
||||
return cloneNode(this.memoiser.get(property));
|
||||
}
|
||||
|
||||
return t.cloneNode(property);
|
||||
return cloneNode(property);
|
||||
},
|
||||
|
||||
get(superMember) {
|
||||
@ -214,24 +227,24 @@ const looseHandlers = {
|
||||
if (isStatic) {
|
||||
object =
|
||||
getSuperRef() ??
|
||||
t.memberExpression(t.identifier("Function"), t.identifier("prototype"));
|
||||
memberExpression(identifier("Function"), identifier("prototype"));
|
||||
} else {
|
||||
object = t.memberExpression(
|
||||
getSuperRef() ?? t.identifier("Object"),
|
||||
t.identifier("prototype"),
|
||||
object = memberExpression(
|
||||
getSuperRef() ?? identifier("Object"),
|
||||
identifier("prototype"),
|
||||
);
|
||||
}
|
||||
|
||||
return t.memberExpression(object, prop, computed);
|
||||
return memberExpression(object, prop, computed);
|
||||
},
|
||||
|
||||
set(superMember, value) {
|
||||
const { computed } = superMember.node;
|
||||
const prop = this.prop(superMember);
|
||||
|
||||
return t.assignmentExpression(
|
||||
return assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(t.thisExpression(), prop, computed),
|
||||
memberExpression(thisExpression(), prop, computed),
|
||||
value,
|
||||
);
|
||||
},
|
||||
@ -240,15 +253,15 @@ const looseHandlers = {
|
||||
const { computed } = superMember.node;
|
||||
const prop = this.prop(superMember);
|
||||
|
||||
return t.memberExpression(t.thisExpression(), prop, computed);
|
||||
return memberExpression(thisExpression(), prop, computed);
|
||||
},
|
||||
|
||||
call(superMember, args) {
|
||||
return optimiseCall(this.get(superMember), t.thisExpression(), args, false);
|
||||
return optimiseCall(this.get(superMember), thisExpression(), args, false);
|
||||
},
|
||||
|
||||
optionalCall(superMember, args) {
|
||||
return optimiseCall(this.get(superMember), t.thisExpression(), args, true);
|
||||
return optimiseCall(this.get(superMember), thisExpression(), args, true);
|
||||
},
|
||||
};
|
||||
|
||||
@ -309,12 +322,12 @@ export default class ReplaceSupers {
|
||||
declare opts: ReplaceSupersOptions;
|
||||
|
||||
getObjectRef() {
|
||||
return t.cloneNode(this.opts.objectRef || this.opts.getObjectRef());
|
||||
return cloneNode(this.opts.objectRef || this.opts.getObjectRef());
|
||||
}
|
||||
|
||||
getSuperRef() {
|
||||
if (this.opts.superRef) return t.cloneNode(this.opts.superRef);
|
||||
if (this.opts.getSuperRef) return t.cloneNode(this.opts.getSuperRef());
|
||||
if (this.opts.superRef) return cloneNode(this.opts.superRef);
|
||||
if (this.opts.getSuperRef) return cloneNode(this.opts.getSuperRef());
|
||||
}
|
||||
|
||||
replace() {
|
||||
|
||||
@ -1,4 +1,14 @@
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
LOGICAL_OPERATORS,
|
||||
assignmentExpression,
|
||||
binaryExpression,
|
||||
cloneNode,
|
||||
identifier,
|
||||
logicalExpression,
|
||||
numericLiteral,
|
||||
sequenceExpression,
|
||||
unaryExpression,
|
||||
} from "@babel/types";
|
||||
import type { NodePath } from "@babel/traverse";
|
||||
|
||||
export default function simplifyAccess(path: NodePath, bindingNames) {
|
||||
@ -32,18 +42,18 @@ const simpleAssignmentVisitor = {
|
||||
// ++i => (i += 1);
|
||||
const operator = path.node.operator == "++" ? "+=" : "-=";
|
||||
path.replaceWith(
|
||||
t.assignmentExpression(operator, arg.node, t.numericLiteral(1)),
|
||||
assignmentExpression(operator, arg.node, numericLiteral(1)),
|
||||
);
|
||||
} else if (path.node.prefix) {
|
||||
// ++i => (i = (+i) + 1);
|
||||
path.replaceWith(
|
||||
t.assignmentExpression(
|
||||
assignmentExpression(
|
||||
"=",
|
||||
t.identifier(localName),
|
||||
t.binaryExpression(
|
||||
identifier(localName),
|
||||
binaryExpression(
|
||||
path.node.operator[0],
|
||||
t.unaryExpression("+", arg.node),
|
||||
t.numericLiteral(1),
|
||||
unaryExpression("+", arg.node),
|
||||
numericLiteral(1),
|
||||
),
|
||||
),
|
||||
);
|
||||
@ -55,22 +65,22 @@ const simpleAssignmentVisitor = {
|
||||
const varName = old.name;
|
||||
path.scope.push({ id: old });
|
||||
|
||||
const binary = t.binaryExpression(
|
||||
const binary = binaryExpression(
|
||||
path.node.operator[0],
|
||||
t.identifier(varName),
|
||||
t.numericLiteral(1),
|
||||
identifier(varName),
|
||||
numericLiteral(1),
|
||||
);
|
||||
|
||||
// i++ => (_old = (+i), i = _old + 1, _old)
|
||||
path.replaceWith(
|
||||
t.sequenceExpression([
|
||||
t.assignmentExpression(
|
||||
sequenceExpression([
|
||||
assignmentExpression(
|
||||
"=",
|
||||
t.identifier(varName),
|
||||
t.unaryExpression("+", arg.node),
|
||||
identifier(varName),
|
||||
unaryExpression("+", arg.node),
|
||||
),
|
||||
t.assignmentExpression("=", t.cloneNode(arg.node), binary),
|
||||
t.identifier(varName),
|
||||
assignmentExpression("=", cloneNode(arg.node), binary),
|
||||
identifier(varName),
|
||||
]),
|
||||
);
|
||||
}
|
||||
@ -101,25 +111,25 @@ const simpleAssignmentVisitor = {
|
||||
}
|
||||
|
||||
const operator = path.node.operator.slice(0, -1);
|
||||
if (t.LOGICAL_OPERATORS.includes(operator)) {
|
||||
if (LOGICAL_OPERATORS.includes(operator)) {
|
||||
// &&, ||, ??
|
||||
// (foo &&= bar) => (foo && foo = bar)
|
||||
path.replaceWith(
|
||||
t.logicalExpression(
|
||||
logicalExpression(
|
||||
operator,
|
||||
path.node.left,
|
||||
t.assignmentExpression(
|
||||
assignmentExpression(
|
||||
"=",
|
||||
t.cloneNode(path.node.left),
|
||||
cloneNode(path.node.left),
|
||||
path.node.right,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// (foo += bar) => (foo = foo + bar)
|
||||
path.node.right = t.binaryExpression(
|
||||
path.node.right = binaryExpression(
|
||||
operator,
|
||||
t.cloneNode(path.node.left),
|
||||
cloneNode(path.node.left),
|
||||
path.node.right,
|
||||
);
|
||||
path.node.operator = "=";
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
// @flow
|
||||
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
isParenthesizedExpression,
|
||||
isTSAsExpression,
|
||||
isTSNonNullExpression,
|
||||
isTSTypeAssertion,
|
||||
isTypeCastExpression,
|
||||
} from "@babel/types";
|
||||
import type { NodePath } from "@babel/traverse";
|
||||
|
||||
// A transparent expression wrapper is an AST node that most plugins will wish
|
||||
@ -10,11 +16,11 @@ import type { NodePath } from "@babel/traverse";
|
||||
// determining the callee.
|
||||
export function isTransparentExprWrapper(node: Node) {
|
||||
return (
|
||||
t.isTSAsExpression(node) ||
|
||||
t.isTSTypeAssertion(node) ||
|
||||
t.isTSNonNullExpression(node) ||
|
||||
t.isTypeCastExpression(node) ||
|
||||
t.isParenthesizedExpression(node)
|
||||
isTSAsExpression(node) ||
|
||||
isTSTypeAssertion(node) ||
|
||||
isTSNonNullExpression(node) ||
|
||||
isTypeCastExpression(node) ||
|
||||
isParenthesizedExpression(node)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,11 @@
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
cloneNode,
|
||||
exportNamedDeclaration,
|
||||
exportSpecifier,
|
||||
identifier,
|
||||
variableDeclaration,
|
||||
variableDeclarator,
|
||||
} from "@babel/types";
|
||||
|
||||
export default function splitExportDeclaration(exportDeclaration) {
|
||||
if (!exportDeclaration.isExportDeclaration()) {
|
||||
@ -31,18 +38,18 @@ export default function splitExportDeclaration(exportDeclaration) {
|
||||
declaration.isFunctionExpression() ||
|
||||
declaration.isClassExpression()
|
||||
) {
|
||||
declaration.node.id = t.cloneNode(id);
|
||||
declaration.node.id = cloneNode(id);
|
||||
}
|
||||
}
|
||||
|
||||
const updatedDeclaration = standaloneDeclaration
|
||||
? declaration
|
||||
: t.variableDeclaration("var", [
|
||||
t.variableDeclarator(t.cloneNode(id), declaration.node),
|
||||
: variableDeclaration("var", [
|
||||
variableDeclarator(cloneNode(id), declaration.node),
|
||||
]);
|
||||
|
||||
const updatedExportDeclaration = t.exportNamedDeclaration(null, [
|
||||
t.exportSpecifier(t.cloneNode(id), t.identifier("default")),
|
||||
const updatedExportDeclaration = exportNamedDeclaration(null, [
|
||||
exportSpecifier(cloneNode(id), identifier("default")),
|
||||
]);
|
||||
|
||||
exportDeclaration.insertAfter(updatedExportDeclaration);
|
||||
@ -62,10 +69,10 @@ export default function splitExportDeclaration(exportDeclaration) {
|
||||
const bindingIdentifiers = declaration.getOuterBindingIdentifiers();
|
||||
|
||||
const specifiers = Object.keys(bindingIdentifiers).map(name => {
|
||||
return t.exportSpecifier(t.identifier(name), t.identifier(name));
|
||||
return exportSpecifier(identifier(name), identifier(name));
|
||||
});
|
||||
|
||||
const aliasDeclar = t.exportNamedDeclaration(null, specifiers);
|
||||
const aliasDeclar = exportNamedDeclaration(null, specifiers);
|
||||
|
||||
exportDeclaration.insertAfter(aliasDeclar);
|
||||
exportDeclaration.replaceWith(declaration.node);
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
import type { NodePath } from "@babel/traverse";
|
||||
import nameFunction from "@babel/helper-function-name";
|
||||
import template from "@babel/template";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
blockStatement,
|
||||
callExpression,
|
||||
functionExpression,
|
||||
isAssignmentPattern,
|
||||
isRestElement,
|
||||
returnStatement,
|
||||
} from "@babel/types";
|
||||
|
||||
const buildAnonymousExpressionWrapper = template.expression(`
|
||||
(function () {
|
||||
@ -34,16 +41,14 @@ function classOrObjectMethod(path: NodePath, callId: Object) {
|
||||
const node = path.node;
|
||||
const body = node.body;
|
||||
|
||||
const container = t.functionExpression(
|
||||
const container = functionExpression(
|
||||
null,
|
||||
[],
|
||||
t.blockStatement(body.body),
|
||||
blockStatement(body.body),
|
||||
true,
|
||||
);
|
||||
body.body = [
|
||||
t.returnStatement(
|
||||
t.callExpression(t.callExpression(callId, [container]), []),
|
||||
),
|
||||
returnStatement(callExpression(callExpression(callId, [container]), [])),
|
||||
];
|
||||
|
||||
// Regardless of whether or not the wrapped function is a an async method
|
||||
@ -77,7 +82,7 @@ function plainFunction(path: NodePath, callId: Object, noNewArrows: boolean) {
|
||||
node.type = "FunctionExpression";
|
||||
}
|
||||
|
||||
const built = t.callExpression(callId, [node]);
|
||||
const built = callExpression(callId, [node]);
|
||||
const container = wrapper({
|
||||
NAME: functionId || null,
|
||||
REF: path.scope.generateUidIdentifier(functionId ? functionId.name : "ref"),
|
||||
@ -85,7 +90,7 @@ function plainFunction(path: NodePath, callId: Object, noNewArrows: boolean) {
|
||||
PARAMS: node.params.reduce(
|
||||
(acc, param) => {
|
||||
acc.done =
|
||||
acc.done || t.isAssignmentPattern(param) || t.isRestElement(param);
|
||||
acc.done || isAssignmentPattern(param) || isRestElement(param);
|
||||
|
||||
if (!acc.done) {
|
||||
acc.params.push(path.scope.generateUidIdentifier("x"));
|
||||
|
||||
@ -1,7 +1,16 @@
|
||||
import type { File } from "@babel/core";
|
||||
import type { NodePath, Visitor } from "@babel/traverse";
|
||||
import traverse from "@babel/traverse";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
assignmentExpression,
|
||||
cloneNode,
|
||||
expressionStatement,
|
||||
file as t_file,
|
||||
identifier,
|
||||
variableDeclaration,
|
||||
variableDeclarator,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import helpers from "./helpers";
|
||||
|
||||
function makePath(path: NodePath) {
|
||||
@ -213,8 +222,8 @@ function permuteHelperAST(
|
||||
exp.replaceWith(decl);
|
||||
} else {
|
||||
exp.replaceWith(
|
||||
t.variableDeclaration("var", [
|
||||
t.variableDeclarator(id, decl.node as t.Expression),
|
||||
variableDeclaration("var", [
|
||||
variableDeclarator(id, decl.node as t.Expression),
|
||||
]),
|
||||
);
|
||||
}
|
||||
@ -222,19 +231,19 @@ function permuteHelperAST(
|
||||
if (decl.isFunctionDeclaration()) {
|
||||
exportBindingAssignments.forEach(assignPath => {
|
||||
const assign: NodePath<t.Expression> = path.get(assignPath);
|
||||
assign.replaceWith(t.assignmentExpression("=", id, assign.node));
|
||||
assign.replaceWith(assignmentExpression("=", id, assign.node));
|
||||
});
|
||||
exp.replaceWith(decl);
|
||||
path.pushContainer(
|
||||
"body",
|
||||
t.expressionStatement(
|
||||
t.assignmentExpression("=", id, t.identifier(exportName)),
|
||||
expressionStatement(
|
||||
assignmentExpression("=", id, identifier(exportName)),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
exp.replaceWith(
|
||||
t.expressionStatement(
|
||||
t.assignmentExpression("=", id, decl.node as t.Expression),
|
||||
expressionStatement(
|
||||
assignmentExpression("=", id, decl.node as t.Expression),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -248,7 +257,7 @@ function permuteHelperAST(
|
||||
|
||||
for (const path of imps) path.remove();
|
||||
for (const path of impsBindingRefs) {
|
||||
const node = t.cloneNode(dependenciesRefs[path.node.name]);
|
||||
const node = cloneNode(dependenciesRefs[path.node.name]);
|
||||
path.replaceWith(node);
|
||||
}
|
||||
|
||||
@ -285,7 +294,7 @@ function loadHelper(name: string) {
|
||||
}
|
||||
|
||||
const fn = (): File => {
|
||||
const file = { ast: t.file(helper.ast()) };
|
||||
const file = { ast: t_file(helper.ast()) };
|
||||
if (fileClass) {
|
||||
return new fileClass(
|
||||
{
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { getImportSource, getRequireSource, isPolyfillSource } from "./utils";
|
||||
|
||||
import type { NodePath } from "@babel/traverse";
|
||||
import * as t from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
const BABEL_POLYFILL_DEPRECATION = `
|
||||
\`@babel/polyfill\` is deprecated. Please, use required parts of \`core-js\`
|
||||
|
||||
@ -1,4 +1,10 @@
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
isCallExpression,
|
||||
isExpressionStatement,
|
||||
isIdentifier,
|
||||
isStringLiteral,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import type { NodePath } from "@babel/traverse";
|
||||
|
||||
export function getImportSource({ node }: NodePath<t.ImportDeclaration>) {
|
||||
@ -6,14 +12,14 @@ export function getImportSource({ node }: NodePath<t.ImportDeclaration>) {
|
||||
}
|
||||
|
||||
export function getRequireSource({ node }: NodePath) {
|
||||
if (!t.isExpressionStatement(node)) return;
|
||||
if (!isExpressionStatement(node)) return;
|
||||
const { expression } = node;
|
||||
if (
|
||||
t.isCallExpression(expression) &&
|
||||
t.isIdentifier(expression.callee) &&
|
||||
isCallExpression(expression) &&
|
||||
isIdentifier(expression.callee) &&
|
||||
expression.callee.name === "require" &&
|
||||
expression.arguments.length === 1 &&
|
||||
t.isStringLiteral(expression.arguments[0])
|
||||
isStringLiteral(expression.arguments[0])
|
||||
) {
|
||||
return expression.arguments[0].value;
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import * as t from "@babel/types";
|
||||
import { assertExpressionStatement } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
export type Formatter<T> = {
|
||||
code: (source: string) => string;
|
||||
@ -58,7 +59,7 @@ export const expression: Formatter<t.Expression> = {
|
||||
},
|
||||
unwrap: ({ program }) => {
|
||||
const [stmt] = program.body;
|
||||
t.assertExpressionStatement(stmt);
|
||||
assertExpressionStatement(stmt);
|
||||
return stmt.expression;
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,4 +1,17 @@
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
isCallExpression,
|
||||
isExpressionStatement,
|
||||
isFunction,
|
||||
isIdentifier,
|
||||
isJSXIdentifier,
|
||||
isNewExpression,
|
||||
isPlaceholder,
|
||||
isStatement,
|
||||
isStringLiteral,
|
||||
removePropertiesDeep,
|
||||
traverse,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import type { TraversalAncestors, TraversalHandler } from "@babel/types";
|
||||
import { parse } from "@babel/parser";
|
||||
import { codeFrameColumns } from "@babel/code-frame";
|
||||
@ -35,7 +48,7 @@ export default function parseAndBuildMetadata<T>(
|
||||
|
||||
const ast = parseWithCodeFrame(code, opts.parser, syntacticPlaceholders);
|
||||
|
||||
t.removePropertiesDeep(ast, {
|
||||
removePropertiesDeep(ast, {
|
||||
preserveComments,
|
||||
});
|
||||
|
||||
@ -51,7 +64,7 @@ export default function parseAndBuildMetadata<T>(
|
||||
};
|
||||
const isLegacyRef = { value: undefined };
|
||||
|
||||
t.traverse(ast, placeholderVisitorHandler as TraversalHandler<any>, {
|
||||
traverse(ast, placeholderVisitorHandler as TraversalHandler<any>, {
|
||||
syntactic,
|
||||
legacy,
|
||||
isLegacyRef,
|
||||
@ -73,7 +86,7 @@ function placeholderVisitorHandler(
|
||||
) {
|
||||
let name: string;
|
||||
|
||||
if (t.isPlaceholder(node)) {
|
||||
if (isPlaceholder(node)) {
|
||||
if (state.syntacticPlaceholders === false) {
|
||||
throw new Error(
|
||||
"%%foo%%-style placeholders can't be used when " +
|
||||
@ -85,10 +98,10 @@ function placeholderVisitorHandler(
|
||||
}
|
||||
} else if (state.isLegacyRef.value === false || state.syntacticPlaceholders) {
|
||||
return;
|
||||
} else if (t.isIdentifier(node) || t.isJSXIdentifier(node)) {
|
||||
} else if (isIdentifier(node) || isJSXIdentifier(node)) {
|
||||
name = node.name;
|
||||
state.isLegacyRef.value = true;
|
||||
} else if (t.isStringLiteral(node)) {
|
||||
} else if (isStringLiteral(node)) {
|
||||
name = node.value;
|
||||
state.isLegacyRef.value = true;
|
||||
} else {
|
||||
@ -123,20 +136,20 @@ function placeholderVisitorHandler(
|
||||
|
||||
let type: PlaceholderType;
|
||||
if (
|
||||
t.isStringLiteral(node) ||
|
||||
t.isPlaceholder(node, { expectedNode: "StringLiteral" })
|
||||
isStringLiteral(node) ||
|
||||
isPlaceholder(node, { expectedNode: "StringLiteral" })
|
||||
) {
|
||||
type = "string";
|
||||
} else if (
|
||||
(t.isNewExpression(parent) && key === "arguments") ||
|
||||
(t.isCallExpression(parent) && key === "arguments") ||
|
||||
(t.isFunction(parent) && key === "params")
|
||||
(isNewExpression(parent) && key === "arguments") ||
|
||||
(isCallExpression(parent) && key === "arguments") ||
|
||||
(isFunction(parent) && key === "params")
|
||||
) {
|
||||
type = "param";
|
||||
} else if (t.isExpressionStatement(parent) && !t.isPlaceholder(node)) {
|
||||
} else if (isExpressionStatement(parent) && !isPlaceholder(node)) {
|
||||
type = "statement";
|
||||
ancestors = ancestors.slice(0, -1);
|
||||
} else if (t.isStatement(node) && t.isPlaceholder(node)) {
|
||||
} else if (isStatement(node) && isPlaceholder(node)) {
|
||||
type = "statement";
|
||||
} else {
|
||||
type = "other";
|
||||
|
||||
@ -1,4 +1,15 @@
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
blockStatement,
|
||||
cloneNode,
|
||||
emptyStatement,
|
||||
expressionStatement,
|
||||
identifier,
|
||||
isStatement,
|
||||
isStringLiteral,
|
||||
stringLiteral,
|
||||
validate,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
import type { TemplateReplacements } from "./options";
|
||||
import type { Metadata, Placeholder } from "./parse";
|
||||
@ -7,7 +18,7 @@ export default function populatePlaceholders(
|
||||
metadata: Metadata,
|
||||
replacements: TemplateReplacements,
|
||||
): t.File {
|
||||
const ast = t.cloneNode(metadata.ast);
|
||||
const ast = cloneNode(metadata.ast);
|
||||
|
||||
if (replacements) {
|
||||
metadata.placeholders.forEach(placeholder => {
|
||||
@ -61,9 +72,9 @@ function applyReplacement(
|
||||
// once to avoid injecting the same node multiple times.
|
||||
if (placeholder.isDuplicate) {
|
||||
if (Array.isArray(replacement)) {
|
||||
replacement = replacement.map(node => t.cloneNode(node));
|
||||
replacement = replacement.map(node => cloneNode(node));
|
||||
} else if (typeof replacement === "object") {
|
||||
replacement = t.cloneNode(replacement);
|
||||
replacement = cloneNode(replacement);
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,41 +82,41 @@ function applyReplacement(
|
||||
|
||||
if (placeholder.type === "string") {
|
||||
if (typeof replacement === "string") {
|
||||
replacement = t.stringLiteral(replacement);
|
||||
replacement = stringLiteral(replacement);
|
||||
}
|
||||
if (!replacement || !t.isStringLiteral(replacement)) {
|
||||
if (!replacement || !isStringLiteral(replacement)) {
|
||||
throw new Error("Expected string substitution");
|
||||
}
|
||||
} else if (placeholder.type === "statement") {
|
||||
if (index === undefined) {
|
||||
if (!replacement) {
|
||||
replacement = t.emptyStatement();
|
||||
replacement = emptyStatement();
|
||||
} else if (Array.isArray(replacement)) {
|
||||
replacement = t.blockStatement(replacement);
|
||||
replacement = blockStatement(replacement);
|
||||
} else if (typeof replacement === "string") {
|
||||
replacement = t.expressionStatement(t.identifier(replacement));
|
||||
} else if (!t.isStatement(replacement)) {
|
||||
replacement = t.expressionStatement(replacement as any);
|
||||
replacement = expressionStatement(identifier(replacement));
|
||||
} else if (!isStatement(replacement)) {
|
||||
replacement = expressionStatement(replacement as any);
|
||||
}
|
||||
} else {
|
||||
if (replacement && !Array.isArray(replacement)) {
|
||||
if (typeof replacement === "string") {
|
||||
replacement = t.identifier(replacement);
|
||||
replacement = identifier(replacement);
|
||||
}
|
||||
if (!t.isStatement(replacement)) {
|
||||
replacement = t.expressionStatement(replacement as any);
|
||||
if (!isStatement(replacement)) {
|
||||
replacement = expressionStatement(replacement as any);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (placeholder.type === "param") {
|
||||
if (typeof replacement === "string") {
|
||||
replacement = t.identifier(replacement);
|
||||
replacement = identifier(replacement);
|
||||
}
|
||||
|
||||
if (index === undefined) throw new Error("Assertion failure.");
|
||||
} else {
|
||||
if (typeof replacement === "string") {
|
||||
replacement = t.identifier(replacement);
|
||||
replacement = identifier(replacement);
|
||||
}
|
||||
if (Array.isArray(replacement)) {
|
||||
throw new Error("Cannot replace single expression with an array.");
|
||||
@ -113,7 +124,7 @@ function applyReplacement(
|
||||
}
|
||||
|
||||
if (index === undefined) {
|
||||
t.validate(parent, key, replacement);
|
||||
validate(parent, key, replacement);
|
||||
|
||||
(parent as any)[key] = replacement;
|
||||
} else {
|
||||
@ -131,7 +142,7 @@ function applyReplacement(
|
||||
items[index] = replacement;
|
||||
}
|
||||
|
||||
t.validate(parent, key, items);
|
||||
validate(parent, key, items);
|
||||
(parent as any)[key] = items;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import NodePath from "./path";
|
||||
import * as t from "@babel/types";
|
||||
import { VISITOR_KEYS } from "@babel/types";
|
||||
import type Scope from "./scope";
|
||||
|
||||
export default class TraversalContext {
|
||||
@ -30,7 +30,7 @@ export default class TraversalContext {
|
||||
if (opts[node.type]) return true;
|
||||
|
||||
// check if we're going to traverse into this node
|
||||
const keys: Array<string> | undefined = t.VISITOR_KEYS[node.type];
|
||||
const keys: Array<string> | undefined = VISITOR_KEYS[node.type];
|
||||
if (!keys?.length) return false;
|
||||
|
||||
// we need to traverse into this node so ensure that it has children to traverse into!
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import TraversalContext from "./context";
|
||||
import * as visitors from "./visitors";
|
||||
import * as t from "@babel/types";
|
||||
import { VISITOR_KEYS, removeProperties, traverseFast } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import * as cache from "./cache";
|
||||
import type NodePath from "./path";
|
||||
import type { default as Scope, Binding } from "./scope";
|
||||
@ -57,7 +58,7 @@ function traverse(
|
||||
}
|
||||
}
|
||||
|
||||
if (!t.VISITOR_KEYS[parent.type]) {
|
||||
if (!VISITOR_KEYS[parent.type]) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -73,7 +74,7 @@ traverse.verify = visitors.verify;
|
||||
traverse.explode = visitors.explode;
|
||||
|
||||
traverse.cheap = function (node, enter) {
|
||||
return t.traverseFast(node, enter);
|
||||
return traverseFast(node, enter);
|
||||
};
|
||||
|
||||
traverse.node = function (
|
||||
@ -84,7 +85,7 @@ traverse.node = function (
|
||||
parentPath?: NodePath,
|
||||
skipKeys?,
|
||||
) {
|
||||
const keys = t.VISITOR_KEYS[node.type];
|
||||
const keys = VISITOR_KEYS[node.type];
|
||||
if (!keys) return;
|
||||
|
||||
const context = new TraversalContext(scope, opts, state, parentPath);
|
||||
@ -95,13 +96,13 @@ traverse.node = function (
|
||||
};
|
||||
|
||||
traverse.clearNode = function (node: t.Node, opts?) {
|
||||
t.removeProperties(node, opts);
|
||||
removeProperties(node, opts);
|
||||
|
||||
cache.path.delete(node);
|
||||
};
|
||||
|
||||
traverse.removeProperties = function (tree, opts?) {
|
||||
t.traverseFast(tree, traverse.clearNode, opts);
|
||||
traverseFast(tree, traverse.clearNode, opts);
|
||||
return tree;
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
// This file contains that retrieve or validate anything related to the current paths ancestry.
|
||||
|
||||
import * as t from "@babel/types";
|
||||
import { VISITOR_KEYS } from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import NodePath from "./index";
|
||||
|
||||
/**
|
||||
@ -88,7 +89,7 @@ export function getEarliestCommonAncestorFrom(
|
||||
paths,
|
||||
function (deepest, i, ancestries) {
|
||||
let earliest;
|
||||
const keys = t.VISITOR_KEYS[deepest.type];
|
||||
const keys = VISITOR_KEYS[deepest.type];
|
||||
|
||||
for (const ancestry of ancestries) {
|
||||
const path = ancestry[i + 1];
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
// This file contains methods responsible for dealing with comments.
|
||||
import * as t from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import type NodePath from "./index";
|
||||
import {
|
||||
addComment as _addComment,
|
||||
addComments as _addComments,
|
||||
} from "@babel/types";
|
||||
|
||||
/**
|
||||
* Share comments amongst siblings.
|
||||
@ -34,7 +38,7 @@ export function addComment(
|
||||
content: string,
|
||||
line?: boolean,
|
||||
) {
|
||||
t.addComment(this.node, type, content, line);
|
||||
_addComment(this.node, type, content, line);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -46,5 +50,5 @@ export function addComments(
|
||||
type: t.CommentTypeShorthand,
|
||||
comments: readonly t.Comment[],
|
||||
) {
|
||||
t.addComments(this.node, type, comments);
|
||||
_addComments(this.node, type, comments);
|
||||
}
|
||||
|
||||
@ -1,6 +1,30 @@
|
||||
// This file contains methods that convert the path node into another node or some other type of data.
|
||||
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
arrowFunctionExpression,
|
||||
assignmentExpression,
|
||||
binaryExpression,
|
||||
blockStatement,
|
||||
callExpression,
|
||||
conditionalExpression,
|
||||
expressionStatement,
|
||||
identifier,
|
||||
isIdentifier,
|
||||
jsxIdentifier,
|
||||
memberExpression,
|
||||
metaProperty,
|
||||
numericLiteral,
|
||||
objectExpression,
|
||||
restElement,
|
||||
returnStatement,
|
||||
sequenceExpression,
|
||||
spreadElement,
|
||||
stringLiteral,
|
||||
super as _super,
|
||||
thisExpression,
|
||||
unaryExpression,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import nameFunction from "@babel/helper-function-name";
|
||||
import type NodePath from "./index";
|
||||
|
||||
@ -16,7 +40,7 @@ export function toComputedKey(this: NodePath) {
|
||||
|
||||
// @ts-expect-error todo(flow->ts) computed does not exist in ClassPrivateProperty
|
||||
if (!this.node.computed) {
|
||||
if (t.isIdentifier(key)) key = t.stringLiteral(key.name);
|
||||
if (isIdentifier(key)) key = stringLiteral(key.name);
|
||||
}
|
||||
|
||||
return key;
|
||||
@ -54,14 +78,14 @@ export function ensureBlock(
|
||||
stringPath += ".body.0";
|
||||
if (this.isFunction()) {
|
||||
key = "argument";
|
||||
statements.push(t.returnStatement(body.node as t.Expression));
|
||||
statements.push(returnStatement(body.node as t.Expression));
|
||||
} else {
|
||||
key = "expression";
|
||||
statements.push(t.expressionStatement(body.node as t.Expression));
|
||||
statements.push(expressionStatement(body.node as t.Expression));
|
||||
}
|
||||
}
|
||||
|
||||
this.node.body = t.blockStatement(statements);
|
||||
this.node.body = blockStatement(statements);
|
||||
const parentPath = this.get(stringPath) as NodePath;
|
||||
body.setup(
|
||||
parentPath,
|
||||
@ -138,29 +162,29 @@ export function arrowFunctionToExpression(
|
||||
if (checkBinding) {
|
||||
this.parentPath.scope.push({
|
||||
id: checkBinding,
|
||||
init: t.objectExpression([]),
|
||||
init: objectExpression([]),
|
||||
});
|
||||
}
|
||||
|
||||
this.get("body").unshiftContainer(
|
||||
"body",
|
||||
t.expressionStatement(
|
||||
t.callExpression(this.hub.addHelper("newArrowCheck"), [
|
||||
t.thisExpression(),
|
||||
expressionStatement(
|
||||
callExpression(this.hub.addHelper("newArrowCheck"), [
|
||||
thisExpression(),
|
||||
checkBinding
|
||||
? t.identifier(checkBinding.name)
|
||||
: t.identifier(thisBinding),
|
||||
? identifier(checkBinding.name)
|
||||
: identifier(thisBinding),
|
||||
]),
|
||||
),
|
||||
);
|
||||
|
||||
this.replaceWith(
|
||||
t.callExpression(
|
||||
t.memberExpression(
|
||||
callExpression(
|
||||
memberExpression(
|
||||
nameFunction(this, true) || this.node,
|
||||
t.identifier("bind"),
|
||||
identifier("bind"),
|
||||
),
|
||||
[checkBinding ? t.identifier(checkBinding.name) : t.thisExpression()],
|
||||
[checkBinding ? identifier(checkBinding.name) : thisExpression()],
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -217,7 +241,7 @@ function hoistFunctionEnvironment(
|
||||
});
|
||||
const superBinding = getSuperBinding(thisEnvFn);
|
||||
allSuperCalls.forEach(superCall => {
|
||||
const callee = t.identifier(superBinding);
|
||||
const callee = identifier(superBinding);
|
||||
callee.loc = superCall.node.callee.loc;
|
||||
|
||||
superCall.get("callee").replaceWith(callee);
|
||||
@ -227,13 +251,13 @@ function hoistFunctionEnvironment(
|
||||
// Convert all "arguments" references in the arrow to point at the alias.
|
||||
if (argumentsPaths.length > 0) {
|
||||
const argumentsBinding = getBinding(thisEnvFn, "arguments", () => {
|
||||
const args = () => t.identifier("arguments");
|
||||
const args = () => identifier("arguments");
|
||||
if (thisEnvFn.scope.path.isProgram()) {
|
||||
return t.conditionalExpression(
|
||||
t.binaryExpression(
|
||||
return conditionalExpression(
|
||||
binaryExpression(
|
||||
"===",
|
||||
t.unaryExpression("typeof", args()),
|
||||
t.stringLiteral("undefined"),
|
||||
unaryExpression("typeof", args()),
|
||||
stringLiteral("undefined"),
|
||||
),
|
||||
thisEnvFn.scope.buildUndefinedNode(),
|
||||
args(),
|
||||
@ -244,7 +268,7 @@ function hoistFunctionEnvironment(
|
||||
});
|
||||
|
||||
argumentsPaths.forEach(argumentsChild => {
|
||||
const argsRef = t.identifier(argumentsBinding);
|
||||
const argsRef = identifier(argumentsBinding);
|
||||
argsRef.loc = argumentsChild.node.loc;
|
||||
|
||||
argumentsChild.replaceWith(argsRef);
|
||||
@ -254,11 +278,11 @@ function hoistFunctionEnvironment(
|
||||
// Convert all "new.target" references in the arrow to point at the alias.
|
||||
if (newTargetPaths.length > 0) {
|
||||
const newTargetBinding = getBinding(thisEnvFn, "newtarget", () =>
|
||||
t.metaProperty(t.identifier("new"), t.identifier("target")),
|
||||
metaProperty(identifier("new"), identifier("target")),
|
||||
);
|
||||
|
||||
newTargetPaths.forEach(targetChild => {
|
||||
const targetRef = t.identifier(newTargetBinding);
|
||||
const targetRef = identifier(newTargetBinding);
|
||||
targetRef.loc = targetChild.node.loc;
|
||||
|
||||
targetChild.replaceWith(targetRef);
|
||||
@ -301,11 +325,11 @@ function hoistFunctionEnvironment(
|
||||
args.push(value);
|
||||
}
|
||||
|
||||
const call = t.callExpression(t.identifier(superBinding), args);
|
||||
const call = callExpression(identifier(superBinding), args);
|
||||
|
||||
if (isCall) {
|
||||
superProp.parentPath.unshiftContainer("arguments", t.thisExpression());
|
||||
superProp.replaceWith(t.memberExpression(call, t.identifier("call")));
|
||||
superProp.parentPath.unshiftContainer("arguments", thisExpression());
|
||||
superProp.replaceWith(memberExpression(call, identifier("call")));
|
||||
|
||||
thisPaths.push(superProp.parentPath.get("arguments.0"));
|
||||
} else if (isAssignment) {
|
||||
@ -330,8 +354,8 @@ function hoistFunctionEnvironment(
|
||||
) {
|
||||
thisPaths.forEach(thisChild => {
|
||||
const thisRef = thisChild.isJSX()
|
||||
? t.jsxIdentifier(thisBinding)
|
||||
: t.identifier(thisBinding);
|
||||
? jsxIdentifier(thisBinding)
|
||||
: identifier(thisBinding);
|
||||
|
||||
thisRef.loc = thisChild.node.loc;
|
||||
thisChild.replaceWith(thisRef);
|
||||
@ -361,9 +385,9 @@ function standardizeSuperProperty(superProp) {
|
||||
assignmentPath
|
||||
.get("left")
|
||||
.replaceWith(
|
||||
t.memberExpression(
|
||||
memberExpression(
|
||||
superProp.node.object,
|
||||
t.assignmentExpression("=", tmp, superProp.node.property),
|
||||
assignmentExpression("=", tmp, superProp.node.property),
|
||||
true /* computed */,
|
||||
),
|
||||
);
|
||||
@ -371,11 +395,11 @@ function standardizeSuperProperty(superProp) {
|
||||
assignmentPath
|
||||
.get("right")
|
||||
.replaceWith(
|
||||
t.binaryExpression(
|
||||
binaryExpression(
|
||||
op,
|
||||
t.memberExpression(
|
||||
memberExpression(
|
||||
superProp.node.object,
|
||||
t.identifier(tmp.name),
|
||||
identifier(tmp.name),
|
||||
true /* computed */,
|
||||
),
|
||||
value,
|
||||
@ -385,17 +409,17 @@ function standardizeSuperProperty(superProp) {
|
||||
assignmentPath
|
||||
.get("left")
|
||||
.replaceWith(
|
||||
t.memberExpression(superProp.node.object, superProp.node.property),
|
||||
memberExpression(superProp.node.object, superProp.node.property),
|
||||
);
|
||||
|
||||
assignmentPath
|
||||
.get("right")
|
||||
.replaceWith(
|
||||
t.binaryExpression(
|
||||
binaryExpression(
|
||||
op,
|
||||
t.memberExpression(
|
||||
memberExpression(
|
||||
superProp.node.object,
|
||||
t.identifier(superProp.node.property.name),
|
||||
identifier(superProp.node.property.name),
|
||||
),
|
||||
value,
|
||||
),
|
||||
@ -414,35 +438,33 @@ function standardizeSuperProperty(superProp) {
|
||||
: null;
|
||||
|
||||
const parts: t.Expression[] = [
|
||||
t.assignmentExpression(
|
||||
assignmentExpression(
|
||||
"=",
|
||||
tmp,
|
||||
t.memberExpression(
|
||||
memberExpression(
|
||||
superProp.node.object,
|
||||
computedKey
|
||||
? t.assignmentExpression("=", computedKey, superProp.node.property)
|
||||
? assignmentExpression("=", computedKey, superProp.node.property)
|
||||
: superProp.node.property,
|
||||
superProp.node.computed,
|
||||
),
|
||||
),
|
||||
t.assignmentExpression(
|
||||
assignmentExpression(
|
||||
"=",
|
||||
t.memberExpression(
|
||||
memberExpression(
|
||||
superProp.node.object,
|
||||
computedKey
|
||||
? t.identifier(computedKey.name)
|
||||
: superProp.node.property,
|
||||
computedKey ? identifier(computedKey.name) : superProp.node.property,
|
||||
superProp.node.computed,
|
||||
),
|
||||
t.binaryExpression("+", t.identifier(tmp.name), t.numericLiteral(1)),
|
||||
binaryExpression("+", identifier(tmp.name), numericLiteral(1)),
|
||||
),
|
||||
];
|
||||
|
||||
if (!superProp.parentPath.node.prefix) {
|
||||
parts.push(t.identifier(tmp.name));
|
||||
parts.push(identifier(tmp.name));
|
||||
}
|
||||
|
||||
updateExpr.replaceWith(t.sequenceExpression(parts));
|
||||
updateExpr.replaceWith(sequenceExpression(parts));
|
||||
|
||||
const left = updateExpr.get("expressions.0.right");
|
||||
const right = updateExpr.get("expressions.1.left");
|
||||
@ -462,7 +484,7 @@ function hasSuperClass(thisEnvFn) {
|
||||
// Create a binding that evaluates to the "this" of the given function.
|
||||
function getThisBinding(thisEnvFn, inConstructor) {
|
||||
return getBinding(thisEnvFn, "this", thisBinding => {
|
||||
if (!inConstructor || !hasSuperClass(thisEnvFn)) return t.thisExpression();
|
||||
if (!inConstructor || !hasSuperClass(thisEnvFn)) return thisExpression();
|
||||
|
||||
const supers = new WeakSet();
|
||||
thisEnvFn.traverse({
|
||||
@ -480,10 +502,10 @@ function getThisBinding(thisEnvFn, inConstructor) {
|
||||
|
||||
child.replaceWithMultiple([
|
||||
child.node,
|
||||
t.assignmentExpression(
|
||||
assignmentExpression(
|
||||
"=",
|
||||
t.identifier(thisBinding),
|
||||
t.identifier("this"),
|
||||
identifier(thisBinding),
|
||||
identifier("this"),
|
||||
),
|
||||
]);
|
||||
},
|
||||
@ -495,11 +517,9 @@ function getThisBinding(thisEnvFn, inConstructor) {
|
||||
function getSuperBinding(thisEnvFn) {
|
||||
return getBinding(thisEnvFn, "supercall", () => {
|
||||
const argsBinding = thisEnvFn.scope.generateUidIdentifier("args");
|
||||
return t.arrowFunctionExpression(
|
||||
[t.restElement(argsBinding)],
|
||||
t.callExpression(t.super(), [
|
||||
t.spreadElement(t.identifier(argsBinding.name)),
|
||||
]),
|
||||
return arrowFunctionExpression(
|
||||
[restElement(argsBinding)],
|
||||
callExpression(_super(), [spreadElement(identifier(argsBinding.name))]),
|
||||
);
|
||||
});
|
||||
}
|
||||
@ -514,14 +534,14 @@ function getSuperPropBinding(thisEnvFn, isAssignment, propName) {
|
||||
let fnBody;
|
||||
if (propName) {
|
||||
// () => super.foo
|
||||
fnBody = t.memberExpression(t.super(), t.identifier(propName));
|
||||
fnBody = memberExpression(_super(), identifier(propName));
|
||||
} else {
|
||||
const method = thisEnvFn.scope.generateUidIdentifier("prop");
|
||||
// (method) => super[method]
|
||||
argsList.unshift(method);
|
||||
fnBody = t.memberExpression(
|
||||
t.super(),
|
||||
t.identifier(method.name),
|
||||
fnBody = memberExpression(
|
||||
_super(),
|
||||
identifier(method.name),
|
||||
true /* computed */,
|
||||
);
|
||||
}
|
||||
@ -530,14 +550,10 @@ function getSuperPropBinding(thisEnvFn, isAssignment, propName) {
|
||||
const valueIdent = thisEnvFn.scope.generateUidIdentifier("value");
|
||||
argsList.push(valueIdent);
|
||||
|
||||
fnBody = t.assignmentExpression(
|
||||
"=",
|
||||
fnBody,
|
||||
t.identifier(valueIdent.name),
|
||||
);
|
||||
fnBody = assignmentExpression("=", fnBody, identifier(valueIdent.name));
|
||||
}
|
||||
|
||||
return t.arrowFunctionExpression(argsList, fnBody);
|
||||
return arrowFunctionExpression(argsList, fnBody);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -2,7 +2,14 @@
|
||||
|
||||
import type TraversalContext from "../context";
|
||||
import NodePath from "./index";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
getBindingIdentifiers as _getBindingIdentifiers,
|
||||
getOuterBindingIdentifiers as _getOuterBindingIdentifiers,
|
||||
isDeclaration,
|
||||
numericLiteral,
|
||||
unaryExpression,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
const NORMAL_COMPLETION = 0;
|
||||
const BREAK_COMPLETION = 1;
|
||||
@ -107,7 +114,7 @@ function replaceBreakStatementInBreakCompletion(
|
||||
completions.forEach(c => {
|
||||
if (c.path.isBreakStatement({ label: null })) {
|
||||
if (reachable) {
|
||||
c.path.replaceWith(t.unaryExpression("void", t.numericLiteral(0)));
|
||||
c.path.replaceWith(unaryExpression("void", numericLiteral(0)));
|
||||
} else {
|
||||
c.path.remove();
|
||||
}
|
||||
@ -463,7 +470,7 @@ function getBindingIdentifiers(
|
||||
function getBindingIdentifiers(
|
||||
duplicates?: boolean,
|
||||
): Record<string, t.Identifier[] | t.Identifier> {
|
||||
return t.getBindingIdentifiers(this.node, duplicates);
|
||||
return _getBindingIdentifiers(this.node, duplicates);
|
||||
}
|
||||
|
||||
export { getBindingIdentifiers };
|
||||
@ -481,7 +488,7 @@ function getOuterBindingIdentifiers(
|
||||
function getOuterBindingIdentifiers(
|
||||
duplicates?: boolean,
|
||||
): Record<string, t.Identifier[] | t.Identifier> {
|
||||
return t.getOuterBindingIdentifiers(this.node, duplicates);
|
||||
return _getOuterBindingIdentifiers(this.node, duplicates);
|
||||
}
|
||||
|
||||
export { getOuterBindingIdentifiers };
|
||||
@ -505,7 +512,7 @@ export function getBindingIdentifierPaths(
|
||||
if (!id) continue;
|
||||
if (!id.node) continue;
|
||||
|
||||
const keys = t.getBindingIdentifiers.keys[id.node.type];
|
||||
const keys = _getBindingIdentifiers.keys[id.node.type];
|
||||
|
||||
if (id.isIdentifier()) {
|
||||
if (duplicates) {
|
||||
@ -519,7 +526,7 @@ export function getBindingIdentifierPaths(
|
||||
|
||||
if (id.isExportDeclaration()) {
|
||||
const declaration = id.get("declaration");
|
||||
if (t.isDeclaration(declaration)) {
|
||||
if (isDeclaration(declaration)) {
|
||||
search.push(declaration);
|
||||
}
|
||||
continue;
|
||||
|
||||
@ -5,6 +5,7 @@ import buildDebug from "debug";
|
||||
import traverse from "../index";
|
||||
import type { Visitor } from "../types";
|
||||
import Scope from "../scope";
|
||||
import { validate } from "@babel/types";
|
||||
import * as t from "@babel/types";
|
||||
import { path as pathCache } from "../cache";
|
||||
import generator from "@babel/generator";
|
||||
@ -135,7 +136,7 @@ class NodePath<T extends t.Node = t.Node> {
|
||||
}
|
||||
|
||||
set(key: string, node: any) {
|
||||
t.validate(this.node, key, node);
|
||||
validate(this.node, key, node);
|
||||
this.node[key] = node;
|
||||
}
|
||||
|
||||
@ -225,6 +226,10 @@ Object.assign(
|
||||
NodePath_comments,
|
||||
);
|
||||
|
||||
// we can not use `import { TYPES } from "@babel/types"` here
|
||||
// because the transformNamedBabelTypesImportToDestructuring plugin in babel.config.js
|
||||
// does not offer live bindings for `TYPES`
|
||||
// we can change to `import { TYPES }` when we are publishing ES modules only
|
||||
for (const type of t.TYPES) {
|
||||
const typeKey = `is${type}`;
|
||||
const fn = t[typeKey];
|
||||
|
||||
@ -1,6 +1,23 @@
|
||||
import type NodePath from "../index";
|
||||
import * as inferers from "./inferers";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
anyTypeAnnotation,
|
||||
isAnyTypeAnnotation,
|
||||
isBooleanTypeAnnotation,
|
||||
isEmptyTypeAnnotation,
|
||||
isFlowBaseAnnotation,
|
||||
isGenericTypeAnnotation,
|
||||
isIdentifier,
|
||||
isMixedTypeAnnotation,
|
||||
isNumberTypeAnnotation,
|
||||
isStringTypeAnnotation,
|
||||
isTypeAnnotation,
|
||||
isUnionTypeAnnotation,
|
||||
isVoidTypeAnnotation,
|
||||
stringTypeAnnotation,
|
||||
voidTypeAnnotation,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
/**
|
||||
* Infer the type of the current `NodePath`.
|
||||
@ -9,8 +26,8 @@ import * as t from "@babel/types";
|
||||
export function getTypeAnnotation(): t.FlowType {
|
||||
if (this.typeAnnotation) return this.typeAnnotation;
|
||||
|
||||
let type = this._getTypeAnnotation() || t.anyTypeAnnotation();
|
||||
if (t.isTypeAnnotation(type)) type = type.typeAnnotation;
|
||||
let type = this._getTypeAnnotation() || anyTypeAnnotation();
|
||||
if (isTypeAnnotation(type)) type = type.typeAnnotation;
|
||||
return (this.typeAnnotation = type);
|
||||
}
|
||||
|
||||
@ -34,15 +51,15 @@ export function _getTypeAnnotation(): any {
|
||||
|
||||
// for (let NODE in bar) {}
|
||||
if (declar.key === "left" && declarParent.isForInStatement()) {
|
||||
return t.stringTypeAnnotation();
|
||||
return stringTypeAnnotation();
|
||||
}
|
||||
|
||||
// for (let NODE of bar) {}
|
||||
if (declar.key === "left" && declarParent.isForOfStatement()) {
|
||||
return t.anyTypeAnnotation();
|
||||
return anyTypeAnnotation();
|
||||
}
|
||||
|
||||
return t.voidTypeAnnotation();
|
||||
return voidTypeAnnotation();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@ -79,19 +96,19 @@ export function isBaseType(baseName: string, soft?: boolean): boolean {
|
||||
|
||||
function _isBaseType(baseName: string, type?, soft?): boolean {
|
||||
if (baseName === "string") {
|
||||
return t.isStringTypeAnnotation(type);
|
||||
return isStringTypeAnnotation(type);
|
||||
} else if (baseName === "number") {
|
||||
return t.isNumberTypeAnnotation(type);
|
||||
return isNumberTypeAnnotation(type);
|
||||
} else if (baseName === "boolean") {
|
||||
return t.isBooleanTypeAnnotation(type);
|
||||
return isBooleanTypeAnnotation(type);
|
||||
} else if (baseName === "any") {
|
||||
return t.isAnyTypeAnnotation(type);
|
||||
return isAnyTypeAnnotation(type);
|
||||
} else if (baseName === "mixed") {
|
||||
return t.isMixedTypeAnnotation(type);
|
||||
return isMixedTypeAnnotation(type);
|
||||
} else if (baseName === "empty") {
|
||||
return t.isEmptyTypeAnnotation(type);
|
||||
return isEmptyTypeAnnotation(type);
|
||||
} else if (baseName === "void") {
|
||||
return t.isVoidTypeAnnotation(type);
|
||||
return isVoidTypeAnnotation(type);
|
||||
} else {
|
||||
if (soft) {
|
||||
return false;
|
||||
@ -103,11 +120,11 @@ function _isBaseType(baseName: string, type?, soft?): boolean {
|
||||
|
||||
export function couldBeBaseType(name: string): boolean {
|
||||
const type = this.getTypeAnnotation();
|
||||
if (t.isAnyTypeAnnotation(type)) return true;
|
||||
if (isAnyTypeAnnotation(type)) return true;
|
||||
|
||||
if (t.isUnionTypeAnnotation(type)) {
|
||||
if (isUnionTypeAnnotation(type)) {
|
||||
for (const type2 of type.types) {
|
||||
if (t.isAnyTypeAnnotation(type2) || _isBaseType(name, type2, true)) {
|
||||
if (isAnyTypeAnnotation(type2) || _isBaseType(name, type2, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -121,7 +138,7 @@ export function baseTypeStrictlyMatches(rightArg: NodePath): boolean {
|
||||
const left = this.getTypeAnnotation();
|
||||
const right = rightArg.getTypeAnnotation();
|
||||
|
||||
if (!t.isAnyTypeAnnotation(left) && t.isFlowBaseAnnotation(left)) {
|
||||
if (!isAnyTypeAnnotation(left) && isFlowBaseAnnotation(left)) {
|
||||
return right.type === left.type;
|
||||
}
|
||||
return false;
|
||||
@ -130,7 +147,7 @@ export function baseTypeStrictlyMatches(rightArg: NodePath): boolean {
|
||||
export function isGenericType(genericName: string): boolean {
|
||||
const type = this.getTypeAnnotation();
|
||||
return (
|
||||
t.isGenericTypeAnnotation(type) &&
|
||||
t.isIdentifier(type.id, { name: genericName })
|
||||
isGenericTypeAnnotation(type) &&
|
||||
isIdentifier(type.id, { name: genericName })
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,5 +1,15 @@
|
||||
import type NodePath from "../index";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
BOOLEAN_NUMBER_BINARY_OPERATORS,
|
||||
createFlowUnionType,
|
||||
createTSUnionType,
|
||||
createTypeAnnotationBasedOnTypeof,
|
||||
createUnionTypeAnnotation,
|
||||
isTSTypeAnnotation,
|
||||
numberTypeAnnotation,
|
||||
voidTypeAnnotation,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import type Binding from "../../scope/binding";
|
||||
|
||||
export default function (node: any) {
|
||||
@ -22,9 +32,9 @@ export default function (node: any) {
|
||||
|
||||
// built-in values
|
||||
if (node.name === "undefined") {
|
||||
return t.voidTypeAnnotation();
|
||||
return voidTypeAnnotation();
|
||||
} else if (node.name === "NaN" || node.name === "Infinity") {
|
||||
return t.numberTypeAnnotation();
|
||||
return numberTypeAnnotation();
|
||||
} else if (node.name === "arguments") {
|
||||
// todo
|
||||
}
|
||||
@ -96,15 +106,15 @@ function getTypeAnnotationBindingConstantViolations(binding, path, name) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.isTSTypeAnnotation(types[0]) && t.createTSUnionType) {
|
||||
return t.createTSUnionType(types);
|
||||
if (isTSTypeAnnotation(types[0]) && createTSUnionType) {
|
||||
return createTSUnionType(types);
|
||||
}
|
||||
|
||||
if (t.createFlowUnionType) {
|
||||
return t.createFlowUnionType(types);
|
||||
if (createFlowUnionType) {
|
||||
return createFlowUnionType(types);
|
||||
}
|
||||
|
||||
return t.createUnionTypeAnnotation(types);
|
||||
return createUnionTypeAnnotation(types);
|
||||
}
|
||||
|
||||
function getConstantViolationsBefore(binding: Binding, path, functions?) {
|
||||
@ -138,8 +148,8 @@ function inferAnnotationFromBinaryExpression(
|
||||
if (operator === "===") {
|
||||
return target.getTypeAnnotation();
|
||||
}
|
||||
if (t.BOOLEAN_NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return t.numberTypeAnnotation();
|
||||
if (BOOLEAN_NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return numberTypeAnnotation();
|
||||
}
|
||||
|
||||
return;
|
||||
@ -173,7 +183,7 @@ function inferAnnotationFromBinaryExpression(
|
||||
|
||||
// turn type value into a type annotation
|
||||
// @ts-expect-error todo(flow->ts): move validation from helper or relax type constraint to just a string
|
||||
return t.createTypeAnnotationBasedOnTypeof(typeValue);
|
||||
return createTypeAnnotationBasedOnTypeof(typeValue);
|
||||
}
|
||||
|
||||
function getParentConditionalPath(binding, path, name) {
|
||||
@ -221,22 +231,22 @@ function getConditionalAnnotation<T extends t.Node>(
|
||||
}
|
||||
|
||||
if (types.length) {
|
||||
if (t.isTSTypeAnnotation(types[0]) && t.createTSUnionType) {
|
||||
if (isTSTypeAnnotation(types[0]) && createTSUnionType) {
|
||||
return {
|
||||
typeAnnotation: t.createTSUnionType(types),
|
||||
typeAnnotation: createTSUnionType(types),
|
||||
ifStatement,
|
||||
};
|
||||
}
|
||||
|
||||
if (t.createFlowUnionType) {
|
||||
if (createFlowUnionType) {
|
||||
return {
|
||||
typeAnnotation: t.createFlowUnionType(types),
|
||||
typeAnnotation: createFlowUnionType(types),
|
||||
ifStatement,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
typeAnnotation: t.createUnionTypeAnnotation(types),
|
||||
typeAnnotation: createUnionTypeAnnotation(types),
|
||||
ifStatement,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1,4 +1,26 @@
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
BOOLEAN_BINARY_OPERATORS,
|
||||
BOOLEAN_UNARY_OPERATORS,
|
||||
NUMBER_BINARY_OPERATORS,
|
||||
NUMBER_UNARY_OPERATORS,
|
||||
STRING_UNARY_OPERATORS,
|
||||
anyTypeAnnotation,
|
||||
arrayTypeAnnotation,
|
||||
booleanTypeAnnotation,
|
||||
buildMatchMemberExpression,
|
||||
createFlowUnionType,
|
||||
createTSUnionType,
|
||||
createUnionTypeAnnotation,
|
||||
genericTypeAnnotation,
|
||||
identifier,
|
||||
isTSTypeAnnotation,
|
||||
nullLiteralTypeAnnotation,
|
||||
numberTypeAnnotation,
|
||||
stringTypeAnnotation,
|
||||
tupleTypeAnnotation,
|
||||
unionTypeAnnotation,
|
||||
voidTypeAnnotation,
|
||||
} from "@babel/types";
|
||||
|
||||
export { default as Identifier } from "./inferer-reference";
|
||||
|
||||
@ -33,51 +55,51 @@ TypeCastExpression.validParent = true;
|
||||
export function NewExpression(node) {
|
||||
if (this.get("callee").isIdentifier()) {
|
||||
// only resolve identifier callee
|
||||
return t.genericTypeAnnotation(node.callee);
|
||||
return genericTypeAnnotation(node.callee);
|
||||
}
|
||||
}
|
||||
|
||||
export function TemplateLiteral() {
|
||||
return t.stringTypeAnnotation();
|
||||
return stringTypeAnnotation();
|
||||
}
|
||||
|
||||
export function UnaryExpression(node) {
|
||||
const operator = node.operator;
|
||||
|
||||
if (operator === "void") {
|
||||
return t.voidTypeAnnotation();
|
||||
} else if (t.NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return t.numberTypeAnnotation();
|
||||
} else if (t.STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return t.stringTypeAnnotation();
|
||||
} else if (t.BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return t.booleanTypeAnnotation();
|
||||
return voidTypeAnnotation();
|
||||
} else if (NUMBER_UNARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return numberTypeAnnotation();
|
||||
} else if (STRING_UNARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return stringTypeAnnotation();
|
||||
} else if (BOOLEAN_UNARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return booleanTypeAnnotation();
|
||||
}
|
||||
}
|
||||
|
||||
export function BinaryExpression(node) {
|
||||
const operator = node.operator;
|
||||
|
||||
if (t.NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return t.numberTypeAnnotation();
|
||||
} else if (t.BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return t.booleanTypeAnnotation();
|
||||
if (NUMBER_BINARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return numberTypeAnnotation();
|
||||
} else if (BOOLEAN_BINARY_OPERATORS.indexOf(operator) >= 0) {
|
||||
return booleanTypeAnnotation();
|
||||
} else if (operator === "+") {
|
||||
const right = this.get("right");
|
||||
const left = this.get("left");
|
||||
|
||||
if (left.isBaseType("number") && right.isBaseType("number")) {
|
||||
// both numbers so this will be a number
|
||||
return t.numberTypeAnnotation();
|
||||
return numberTypeAnnotation();
|
||||
} else if (left.isBaseType("string") || right.isBaseType("string")) {
|
||||
// one is a string so the result will be a string
|
||||
return t.stringTypeAnnotation();
|
||||
return stringTypeAnnotation();
|
||||
}
|
||||
|
||||
// unsure if left and right are strings or numbers so stay on the safe side
|
||||
return t.unionTypeAnnotation([
|
||||
t.stringTypeAnnotation(),
|
||||
t.numberTypeAnnotation(),
|
||||
return unionTypeAnnotation([
|
||||
stringTypeAnnotation(),
|
||||
numberTypeAnnotation(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -88,15 +110,15 @@ export function LogicalExpression() {
|
||||
this.get("right").getTypeAnnotation(),
|
||||
];
|
||||
|
||||
if (t.isTSTypeAnnotation(argumentTypes[0]) && t.createTSUnionType) {
|
||||
return t.createTSUnionType(argumentTypes);
|
||||
if (isTSTypeAnnotation(argumentTypes[0]) && createTSUnionType) {
|
||||
return createTSUnionType(argumentTypes);
|
||||
}
|
||||
|
||||
if (t.createFlowUnionType) {
|
||||
return t.createFlowUnionType(argumentTypes);
|
||||
if (createFlowUnionType) {
|
||||
return createFlowUnionType(argumentTypes);
|
||||
}
|
||||
|
||||
return t.createUnionTypeAnnotation(argumentTypes);
|
||||
return createUnionTypeAnnotation(argumentTypes);
|
||||
}
|
||||
|
||||
export function ConditionalExpression() {
|
||||
@ -105,15 +127,15 @@ export function ConditionalExpression() {
|
||||
this.get("alternate").getTypeAnnotation(),
|
||||
];
|
||||
|
||||
if (t.isTSTypeAnnotation(argumentTypes[0]) && t.createTSUnionType) {
|
||||
return t.createTSUnionType(argumentTypes);
|
||||
if (isTSTypeAnnotation(argumentTypes[0]) && createTSUnionType) {
|
||||
return createTSUnionType(argumentTypes);
|
||||
}
|
||||
|
||||
if (t.createFlowUnionType) {
|
||||
return t.createFlowUnionType(argumentTypes);
|
||||
if (createFlowUnionType) {
|
||||
return createFlowUnionType(argumentTypes);
|
||||
}
|
||||
|
||||
return t.createUnionTypeAnnotation(argumentTypes);
|
||||
return createUnionTypeAnnotation(argumentTypes);
|
||||
}
|
||||
|
||||
export function SequenceExpression() {
|
||||
@ -131,36 +153,36 @@ export function AssignmentExpression() {
|
||||
export function UpdateExpression(node) {
|
||||
const operator = node.operator;
|
||||
if (operator === "++" || operator === "--") {
|
||||
return t.numberTypeAnnotation();
|
||||
return numberTypeAnnotation();
|
||||
}
|
||||
}
|
||||
|
||||
export function StringLiteral() {
|
||||
return t.stringTypeAnnotation();
|
||||
return stringTypeAnnotation();
|
||||
}
|
||||
|
||||
export function NumericLiteral() {
|
||||
return t.numberTypeAnnotation();
|
||||
return numberTypeAnnotation();
|
||||
}
|
||||
|
||||
export function BooleanLiteral() {
|
||||
return t.booleanTypeAnnotation();
|
||||
return booleanTypeAnnotation();
|
||||
}
|
||||
|
||||
export function NullLiteral() {
|
||||
return t.nullLiteralTypeAnnotation();
|
||||
return nullLiteralTypeAnnotation();
|
||||
}
|
||||
|
||||
export function RegExpLiteral() {
|
||||
return t.genericTypeAnnotation(t.identifier("RegExp"));
|
||||
return genericTypeAnnotation(identifier("RegExp"));
|
||||
}
|
||||
|
||||
export function ObjectExpression() {
|
||||
return t.genericTypeAnnotation(t.identifier("Object"));
|
||||
return genericTypeAnnotation(identifier("Object"));
|
||||
}
|
||||
|
||||
export function ArrayExpression() {
|
||||
return t.genericTypeAnnotation(t.identifier("Array"));
|
||||
return genericTypeAnnotation(identifier("Array"));
|
||||
}
|
||||
|
||||
export function RestElement() {
|
||||
@ -170,7 +192,7 @@ export function RestElement() {
|
||||
RestElement.validParent = true;
|
||||
|
||||
function Func() {
|
||||
return t.genericTypeAnnotation(t.identifier("Function"));
|
||||
return genericTypeAnnotation(identifier("Function"));
|
||||
}
|
||||
|
||||
export {
|
||||
@ -181,19 +203,19 @@ export {
|
||||
Func as ClassDeclaration,
|
||||
};
|
||||
|
||||
const isArrayFrom = t.buildMatchMemberExpression("Array.from");
|
||||
const isObjectKeys = t.buildMatchMemberExpression("Object.keys");
|
||||
const isObjectValues = t.buildMatchMemberExpression("Object.values");
|
||||
const isObjectEntries = t.buildMatchMemberExpression("Object.entries");
|
||||
const isArrayFrom = buildMatchMemberExpression("Array.from");
|
||||
const isObjectKeys = buildMatchMemberExpression("Object.keys");
|
||||
const isObjectValues = buildMatchMemberExpression("Object.values");
|
||||
const isObjectEntries = buildMatchMemberExpression("Object.entries");
|
||||
export function CallExpression() {
|
||||
const { callee } = this.node;
|
||||
if (isObjectKeys(callee)) {
|
||||
return t.arrayTypeAnnotation(t.stringTypeAnnotation());
|
||||
return arrayTypeAnnotation(stringTypeAnnotation());
|
||||
} else if (isArrayFrom(callee) || isObjectValues(callee)) {
|
||||
return t.arrayTypeAnnotation(t.anyTypeAnnotation());
|
||||
return arrayTypeAnnotation(anyTypeAnnotation());
|
||||
} else if (isObjectEntries(callee)) {
|
||||
return t.arrayTypeAnnotation(
|
||||
t.tupleTypeAnnotation([t.stringTypeAnnotation(), t.anyTypeAnnotation()]),
|
||||
return arrayTypeAnnotation(
|
||||
tupleTypeAnnotation([stringTypeAnnotation(), anyTypeAnnotation()]),
|
||||
);
|
||||
}
|
||||
|
||||
@ -210,9 +232,9 @@ function resolveCall(callee) {
|
||||
if (callee.isFunction()) {
|
||||
if (callee.is("async")) {
|
||||
if (callee.is("generator")) {
|
||||
return t.genericTypeAnnotation(t.identifier("AsyncIterator"));
|
||||
return genericTypeAnnotation(identifier("AsyncIterator"));
|
||||
} else {
|
||||
return t.genericTypeAnnotation(t.identifier("Promise"));
|
||||
return genericTypeAnnotation(identifier("Promise"));
|
||||
}
|
||||
} else {
|
||||
if (callee.node.returnType) {
|
||||
|
||||
@ -1,7 +1,18 @@
|
||||
// This file contains methods responsible for introspecting the current path for certain values.
|
||||
|
||||
import type NodePath from "./index";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
STATEMENT_OR_BLOCK_KEYS,
|
||||
VISITOR_KEYS,
|
||||
isBlockStatement,
|
||||
isExpression,
|
||||
isIdentifier,
|
||||
isLiteral,
|
||||
isStringLiteral,
|
||||
isType,
|
||||
matchesPattern as _matchesPattern,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
|
||||
/**
|
||||
* Match the current node if it matches the provided `pattern`.
|
||||
@ -15,7 +26,7 @@ export function matchesPattern(
|
||||
pattern: string,
|
||||
allowPartial?: boolean,
|
||||
): boolean {
|
||||
return t.matchesPattern(this.node, pattern, allowPartial);
|
||||
return _matchesPattern(this.node, pattern, allowPartial);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -68,7 +79,7 @@ export function equals(this: NodePath, key: string, value): boolean {
|
||||
*/
|
||||
|
||||
export function isNodeType(this: NodePath, type: string): boolean {
|
||||
return t.isType(this.type, type);
|
||||
return isType(this.type, type);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,9 +115,9 @@ export function canSwapBetweenExpressionAndStatement(
|
||||
}
|
||||
|
||||
if (this.isExpression()) {
|
||||
return t.isBlockStatement(replacement);
|
||||
return isBlockStatement(replacement);
|
||||
} else if (this.isBlockStatement()) {
|
||||
return t.isExpression(replacement);
|
||||
return isExpression(replacement);
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -151,11 +162,11 @@ export function isCompletionRecord(
|
||||
export function isStatementOrBlock(this: NodePath): boolean {
|
||||
if (
|
||||
this.parentPath.isLabeledStatement() ||
|
||||
t.isBlockStatement(this.container)
|
||||
isBlockStatement(this.container)
|
||||
) {
|
||||
return false;
|
||||
} else {
|
||||
return t.STATEMENT_OR_BLOCK_KEYS.includes(this.key as string);
|
||||
return STATEMENT_OR_BLOCK_KEYS.includes(this.key as string);
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,7 +183,7 @@ export function referencesImport(
|
||||
if (
|
||||
(this.isMemberExpression() || this.isOptionalMemberExpression()) &&
|
||||
(this.node.computed
|
||||
? t.isStringLiteral(this.node.property, { value: importName })
|
||||
? isStringLiteral(this.node.property, { value: importName })
|
||||
: (this.node.property as t.Identifier).name === importName)
|
||||
) {
|
||||
const object = (
|
||||
@ -211,7 +222,7 @@ export function referencesImport(
|
||||
|
||||
if (
|
||||
path.isImportSpecifier() &&
|
||||
t.isIdentifier(path.node.imported, { name: importName })
|
||||
isIdentifier(path.node.imported, { name: importName })
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
@ -384,7 +395,7 @@ export function _guessExecutionStatusRelativeTo(
|
||||
}
|
||||
|
||||
// otherwise we're associated by a parent node, check which key comes before the other
|
||||
const keys = t.VISITOR_KEYS[commonPath.type];
|
||||
const keys = VISITOR_KEYS[commonPath.type];
|
||||
const keyPosition = {
|
||||
this: keys.indexOf(divergence.this.parentKey as string),
|
||||
target: keys.indexOf(divergence.target.parentKey as string),
|
||||
@ -503,7 +514,7 @@ export function _resolve(
|
||||
// making this resolution inaccurate
|
||||
|
||||
const targetKey = this.toComputedKey();
|
||||
if (!t.isLiteral(targetKey)) return;
|
||||
if (!isLiteral(targetKey)) return;
|
||||
|
||||
// @ts-expect-error todo(flow->ts): NullLiteral
|
||||
const targetName = targetKey.value;
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
import { react } from "@babel/types";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
cloneNode,
|
||||
jsxExpressionContainer,
|
||||
variableDeclaration,
|
||||
variableDeclarator,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import type Scope from "../../scope";
|
||||
import type NodePath from "../index";
|
||||
import type Binding from "../../scope/binding";
|
||||
@ -235,23 +241,23 @@ export default class PathHoister<T extends t.Node = t.Node> {
|
||||
let uid = attachTo.scope.generateUidIdentifier("ref");
|
||||
|
||||
// @ts-expect-error todo(flow->ts): more specific type for this.path
|
||||
const declarator = t.variableDeclarator(uid, this.path.node);
|
||||
const declarator = variableDeclarator(uid, this.path.node);
|
||||
|
||||
const insertFn = this.attachAfter ? "insertAfter" : "insertBefore";
|
||||
const [attached] = attachTo[insertFn]([
|
||||
attachTo.isVariableDeclarator()
|
||||
? declarator
|
||||
: t.variableDeclaration("var", [declarator]),
|
||||
: variableDeclaration("var", [declarator]),
|
||||
]);
|
||||
|
||||
const parent = this.path.parentPath;
|
||||
if (parent.isJSXElement() && this.path.container === parent.node.children) {
|
||||
// turning the `span` in `<div><span /></div>` to an expression so we need to wrap it with
|
||||
// an expression container
|
||||
uid = t.jsxExpressionContainer(uid);
|
||||
uid = jsxExpressionContainer(uid);
|
||||
}
|
||||
|
||||
this.path.replaceWith(t.cloneNode(uid));
|
||||
this.path.replaceWith(cloneNode(uid));
|
||||
|
||||
return attachTo.isVariableDeclarator()
|
||||
? attached.get("init")
|
||||
|
||||
@ -1,14 +1,35 @@
|
||||
import type NodePath from "../index";
|
||||
import { react } from "@babel/types";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
isBinding,
|
||||
isBlockScoped,
|
||||
isExportDeclaration,
|
||||
isExpression,
|
||||
isFlow,
|
||||
isForStatement,
|
||||
isForXStatement,
|
||||
isIdentifier,
|
||||
isImportDeclaration,
|
||||
isImportSpecifier,
|
||||
isJSXIdentifier,
|
||||
isJSXMemberExpression,
|
||||
isMemberExpression,
|
||||
isReferenced,
|
||||
isScope,
|
||||
isStatement,
|
||||
isVar,
|
||||
isVariableDeclaration,
|
||||
react,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
const { isCompatTag } = react;
|
||||
|
||||
export const ReferencedIdentifier = {
|
||||
types: ["Identifier", "JSXIdentifier"],
|
||||
checkPath(path: NodePath, opts?: any): boolean {
|
||||
const { node, parent } = path;
|
||||
if (!t.isIdentifier(node, opts) && !t.isJSXMemberExpression(parent, opts)) {
|
||||
if (t.isJSXIdentifier(node, opts)) {
|
||||
if (react.isCompatTag(node.name)) return false;
|
||||
if (!isIdentifier(node, opts) && !isJSXMemberExpression(parent, opts)) {
|
||||
if (isJSXIdentifier(node, opts)) {
|
||||
if (isCompatTag(node.name)) return false;
|
||||
} else {
|
||||
// not a JSXIdentifier or an Identifier
|
||||
return false;
|
||||
@ -16,14 +37,14 @@ export const ReferencedIdentifier = {
|
||||
}
|
||||
|
||||
// check if node is referenced
|
||||
return t.isReferenced(node, parent, path.parentPath.parent);
|
||||
return isReferenced(node, parent, path.parentPath.parent);
|
||||
},
|
||||
};
|
||||
|
||||
export const ReferencedMemberExpression = {
|
||||
types: ["MemberExpression"],
|
||||
checkPath({ node, parent }) {
|
||||
return t.isMemberExpression(node) && t.isReferenced(node, parent);
|
||||
return isMemberExpression(node) && isReferenced(node, parent);
|
||||
},
|
||||
};
|
||||
|
||||
@ -32,17 +53,17 @@ export const BindingIdentifier = {
|
||||
checkPath(path: NodePath): boolean {
|
||||
const { node, parent } = path;
|
||||
const grandparent = path.parentPath.parent;
|
||||
return t.isIdentifier(node) && t.isBinding(node, parent, grandparent);
|
||||
return isIdentifier(node) && isBinding(node, parent, grandparent);
|
||||
},
|
||||
};
|
||||
|
||||
export const Statement = {
|
||||
types: ["Statement"],
|
||||
checkPath({ node, parent }: NodePath): boolean {
|
||||
if (t.isStatement(node)) {
|
||||
if (t.isVariableDeclaration(node)) {
|
||||
if (t.isForXStatement(parent, { left: node })) return false;
|
||||
if (t.isForStatement(parent, { init: node })) return false;
|
||||
if (isStatement(node)) {
|
||||
if (isVariableDeclaration(node)) {
|
||||
if (isForXStatement(parent, { left: node })) return false;
|
||||
if (isForStatement(parent, { init: node })) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -58,7 +79,7 @@ export const Expression = {
|
||||
if (path.isIdentifier()) {
|
||||
return path.isReferencedIdentifier();
|
||||
} else {
|
||||
return t.isExpression(path.node);
|
||||
return isExpression(path.node);
|
||||
}
|
||||
},
|
||||
};
|
||||
@ -67,26 +88,26 @@ export const Scope = {
|
||||
// When pattern is inside the function params, it is a scope
|
||||
types: ["Scopable", "Pattern"],
|
||||
checkPath(path) {
|
||||
return t.isScope(path.node, path.parent);
|
||||
return isScope(path.node, path.parent);
|
||||
},
|
||||
};
|
||||
|
||||
export const Referenced = {
|
||||
checkPath(path: NodePath): boolean {
|
||||
return t.isReferenced(path.node, path.parent);
|
||||
return isReferenced(path.node, path.parent);
|
||||
},
|
||||
};
|
||||
|
||||
export const BlockScoped = {
|
||||
checkPath(path: NodePath): boolean {
|
||||
return t.isBlockScoped(path.node);
|
||||
return isBlockScoped(path.node);
|
||||
},
|
||||
};
|
||||
|
||||
export const Var = {
|
||||
types: ["VariableDeclaration"],
|
||||
checkPath(path: NodePath): boolean {
|
||||
return t.isVar(path.node);
|
||||
return isVar(path.node);
|
||||
},
|
||||
};
|
||||
|
||||
@ -111,13 +132,13 @@ export const Pure = {
|
||||
export const Flow = {
|
||||
types: ["Flow", "ImportDeclaration", "ExportDeclaration", "ImportSpecifier"],
|
||||
checkPath({ node }: NodePath): boolean {
|
||||
if (t.isFlow(node)) {
|
||||
if (isFlow(node)) {
|
||||
return true;
|
||||
} else if (t.isImportDeclaration(node)) {
|
||||
} else if (isImportDeclaration(node)) {
|
||||
return node.importKind === "type" || node.importKind === "typeof";
|
||||
} else if (t.isExportDeclaration(node)) {
|
||||
} else if (isExportDeclaration(node)) {
|
||||
return node.exportKind === "type";
|
||||
} else if (t.isImportSpecifier(node)) {
|
||||
} else if (isImportSpecifier(node)) {
|
||||
return node.importKind === "type" || node.importKind === "typeof";
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@ -3,7 +3,17 @@
|
||||
import { path as pathCache } from "../cache";
|
||||
import PathHoister from "./lib/hoister";
|
||||
import NodePath from "./index";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
arrowFunctionExpression,
|
||||
assertExpression,
|
||||
assignmentExpression,
|
||||
blockStatement,
|
||||
callExpression,
|
||||
cloneNode,
|
||||
expressionStatement,
|
||||
isExpression,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import type Scope from "../scope";
|
||||
|
||||
/**
|
||||
@ -40,7 +50,7 @@ export function insertBefore(this: NodePath, nodes_: t.Node | t.Node[]) {
|
||||
(!this.isExpressionStatement() ||
|
||||
(node as t.ExpressionStatement).expression != null);
|
||||
|
||||
this.replaceWith(t.blockStatement(shouldInsertCurrentNode ? [node] : []));
|
||||
this.replaceWith(blockStatement(shouldInsertCurrentNode ? [node] : []));
|
||||
return this.unshiftContainer("body", nodes);
|
||||
} else {
|
||||
throw new Error(
|
||||
@ -118,7 +128,7 @@ export function insertAfter(
|
||||
// If A is an expression statement, it isn't safe anymore so we need to
|
||||
// convert B to an expression statement
|
||||
// A; -> A; B // No semicolon! It could break if followed by [!
|
||||
return t.isExpression(node) ? t.expressionStatement(node) : node;
|
||||
return isExpression(node) ? expressionStatement(node) : node;
|
||||
}),
|
||||
);
|
||||
} else if (
|
||||
@ -132,11 +142,9 @@ export function insertAfter(
|
||||
let { scope } = this;
|
||||
|
||||
if (scope.path.isPattern()) {
|
||||
t.assertExpression(node);
|
||||
assertExpression(node);
|
||||
|
||||
this.replaceWith(
|
||||
t.callExpression(t.arrowFunctionExpression([], node), []),
|
||||
);
|
||||
this.replaceWith(callExpression(arrowFunctionExpression([], node), []));
|
||||
(this.get("callee.body") as NodePath).insertAfter(nodes);
|
||||
return [this];
|
||||
}
|
||||
@ -148,14 +156,14 @@ export function insertAfter(
|
||||
}
|
||||
const temp = scope.generateDeclaredUidIdentifier();
|
||||
nodes.unshift(
|
||||
t.expressionStatement(
|
||||
expressionStatement(
|
||||
// @ts-expect-error todo(flow->ts): This can be a variable
|
||||
// declaraion in the "init" of a for statement, but that's
|
||||
// invalid here.
|
||||
t.assignmentExpression("=", t.cloneNode(temp), node),
|
||||
assignmentExpression("=", cloneNode(temp), node),
|
||||
),
|
||||
);
|
||||
nodes.push(t.expressionStatement(t.cloneNode(temp)));
|
||||
nodes.push(expressionStatement(cloneNode(temp)));
|
||||
}
|
||||
// @ts-expect-error todo(flow->ts): check that nodes is an array of statements
|
||||
return this.replaceExpressionWithStatements(nodes);
|
||||
@ -168,7 +176,7 @@ export function insertAfter(
|
||||
(!this.isExpressionStatement() ||
|
||||
(node as t.ExpressionStatement).expression != null);
|
||||
|
||||
this.replaceWith(t.blockStatement(shouldInsertCurrentNode ? [node] : []));
|
||||
this.replaceWith(blockStatement(shouldInsertCurrentNode ? [node] : []));
|
||||
return this.pushContainer("body", nodes);
|
||||
} else {
|
||||
throw new Error(
|
||||
|
||||
@ -5,7 +5,29 @@ import traverse from "../index";
|
||||
import NodePath from "./index";
|
||||
import { path as pathCache } from "../cache";
|
||||
import { parse } from "@babel/parser";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
FUNCTION_TYPES,
|
||||
arrowFunctionExpression,
|
||||
assignmentExpression,
|
||||
awaitExpression,
|
||||
blockStatement,
|
||||
callExpression,
|
||||
cloneNode,
|
||||
expressionStatement,
|
||||
identifier,
|
||||
inheritLeadingComments,
|
||||
inheritTrailingComments,
|
||||
inheritsComments,
|
||||
isExpression,
|
||||
isProgram,
|
||||
isStatement,
|
||||
removeComments,
|
||||
returnStatement,
|
||||
toSequenceExpression,
|
||||
validate,
|
||||
yieldExpression,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import hoistVariables from "@babel/helper-hoist-variables";
|
||||
|
||||
/**
|
||||
@ -23,8 +45,8 @@ export function replaceWithMultiple<Nodes extends Array<t.Node>>(
|
||||
this.resync();
|
||||
|
||||
nodes = this._verifyNodeList(nodes);
|
||||
t.inheritLeadingComments(nodes[0], this.node);
|
||||
t.inheritTrailingComments(nodes[nodes.length - 1], this.node);
|
||||
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;
|
||||
const paths = this.insertAfter(nodes);
|
||||
@ -97,7 +119,7 @@ export function replaceWith(this: NodePath, replacement: t.Node | NodePath) {
|
||||
return [this];
|
||||
}
|
||||
|
||||
if (this.isProgram() && !t.isProgram(replacement)) {
|
||||
if (this.isProgram() && !isProgram(replacement)) {
|
||||
throw new Error(
|
||||
"You can only replace a Program root node with another Program node",
|
||||
);
|
||||
@ -117,19 +139,19 @@ export function replaceWith(this: NodePath, replacement: t.Node | NodePath) {
|
||||
|
||||
let nodePath = "";
|
||||
|
||||
if (this.isNodeType("Statement") && t.isExpression(replacement)) {
|
||||
if (this.isNodeType("Statement") && isExpression(replacement)) {
|
||||
if (
|
||||
!this.canHaveVariableDeclarationOrExpression() &&
|
||||
!this.canSwapBetweenExpressionAndStatement(replacement) &&
|
||||
!this.parentPath.isExportDefaultDeclaration()
|
||||
) {
|
||||
// replacing a statement with an expression so wrap it in an expression statement
|
||||
replacement = t.expressionStatement(replacement);
|
||||
replacement = expressionStatement(replacement);
|
||||
nodePath = "expression";
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isNodeType("Expression") && t.isStatement(replacement)) {
|
||||
if (this.isNodeType("Expression") && isStatement(replacement)) {
|
||||
if (
|
||||
!this.canHaveVariableDeclarationOrExpression() &&
|
||||
!this.canSwapBetweenExpressionAndStatement(replacement)
|
||||
@ -141,8 +163,8 @@ export function replaceWith(this: NodePath, replacement: t.Node | NodePath) {
|
||||
|
||||
const oldNode = this.node;
|
||||
if (oldNode) {
|
||||
t.inheritsComments(replacement, oldNode);
|
||||
t.removeComments(oldNode);
|
||||
inheritsComments(replacement, oldNode);
|
||||
removeComments(oldNode);
|
||||
}
|
||||
|
||||
// replace the node
|
||||
@ -168,10 +190,10 @@ export function _replaceWith(this: NodePath, node) {
|
||||
}
|
||||
|
||||
if (this.inList) {
|
||||
// @ts-expect-error todo(flow->ts): check if t.validate accepts a numeric key
|
||||
t.validate(this.parent, this.key, [node]);
|
||||
// @ts-expect-error todo(flow->ts): check if validate accepts a numeric key
|
||||
validate(this.parent, this.key, [node]);
|
||||
} else {
|
||||
t.validate(this.parent, this.key as string, node);
|
||||
validate(this.parent, this.key as string, node);
|
||||
}
|
||||
|
||||
this.debug(`Replace with ${node?.type}`);
|
||||
@ -192,19 +214,19 @@ export function replaceExpressionWithStatements(
|
||||
) {
|
||||
this.resync();
|
||||
|
||||
const toSequenceExpression = t.toSequenceExpression(nodes, this.scope);
|
||||
const nodesAsSequenceExpression = toSequenceExpression(nodes, this.scope);
|
||||
|
||||
if (toSequenceExpression) {
|
||||
return this.replaceWith(toSequenceExpression)[0].get("expressions");
|
||||
if (nodesAsSequenceExpression) {
|
||||
return this.replaceWith(nodesAsSequenceExpression)[0].get("expressions");
|
||||
}
|
||||
|
||||
const functionParent = this.getFunctionParent();
|
||||
const isParentAsync = functionParent?.is("async");
|
||||
const isParentGenerator = functionParent?.is("generator");
|
||||
|
||||
const container = t.arrowFunctionExpression([], t.blockStatement(nodes));
|
||||
const container = arrowFunctionExpression([], blockStatement(nodes));
|
||||
|
||||
this.replaceWith(t.callExpression(container, []));
|
||||
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 }
|
||||
@ -236,19 +258,19 @@ export function replaceExpressionWithStatements(
|
||||
uid = callee.scope.generateDeclaredUidIdentifier("ret");
|
||||
callee
|
||||
.get("body")
|
||||
.pushContainer("body", t.returnStatement(t.cloneNode(uid)));
|
||||
.pushContainer("body", returnStatement(cloneNode(uid)));
|
||||
loop.setData("expressionReplacementReturnUid", uid);
|
||||
} else {
|
||||
uid = t.identifier(uid.name);
|
||||
uid = identifier(uid.name);
|
||||
}
|
||||
|
||||
path
|
||||
.get("expression")
|
||||
.replaceWith(
|
||||
t.assignmentExpression("=", t.cloneNode(uid), path.node.expression),
|
||||
assignmentExpression("=", cloneNode(uid), path.node.expression),
|
||||
);
|
||||
} else {
|
||||
path.replaceWith(t.returnStatement(path.node.expression));
|
||||
path.replaceWith(returnStatement(path.node.expression));
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,25 +286,25 @@ export function replaceExpressionWithStatements(
|
||||
traverse.hasType(
|
||||
(this.get("callee.body") as NodePath<t.BlockStatement>).node,
|
||||
"AwaitExpression",
|
||||
t.FUNCTION_TYPES,
|
||||
FUNCTION_TYPES,
|
||||
);
|
||||
const needToYieldFunction =
|
||||
isParentGenerator &&
|
||||
traverse.hasType(
|
||||
(this.get("callee.body") as NodePath<t.BlockStatement>).node,
|
||||
"YieldExpression",
|
||||
t.FUNCTION_TYPES,
|
||||
FUNCTION_TYPES,
|
||||
);
|
||||
if (needToAwaitFunction) {
|
||||
newCallee.set("async", true);
|
||||
// yield* will await the generator return result
|
||||
if (!needToYieldFunction) {
|
||||
this.replaceWith(t.awaitExpression((this as ThisType).node));
|
||||
this.replaceWith(awaitExpression((this as ThisType).node));
|
||||
}
|
||||
}
|
||||
if (needToYieldFunction) {
|
||||
newCallee.set("generator", true);
|
||||
this.replaceWith(t.yieldExpression((this as ThisType).node, true));
|
||||
this.replaceWith(yieldExpression((this as ThisType).node, true));
|
||||
}
|
||||
|
||||
return newCallee.get("body.body");
|
||||
|
||||
@ -4,7 +4,46 @@ import traverse from "../index";
|
||||
import type { TraverseOptions } from "../index";
|
||||
import Binding from "./binding";
|
||||
import globals from "globals";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
FOR_INIT_KEYS,
|
||||
NOT_LOCAL_BINDING,
|
||||
callExpression,
|
||||
cloneNode,
|
||||
getBindingIdentifiers,
|
||||
identifier,
|
||||
isArrayExpression,
|
||||
isBinary,
|
||||
isClass,
|
||||
isClassBody,
|
||||
isClassDeclaration,
|
||||
isExportAllDeclaration,
|
||||
isExportDefaultDeclaration,
|
||||
isExportNamedDeclaration,
|
||||
isFunctionDeclaration,
|
||||
isIdentifier,
|
||||
isImportDeclaration,
|
||||
isLiteral,
|
||||
isMethod,
|
||||
isModuleDeclaration,
|
||||
isModuleSpecifier,
|
||||
isObjectExpression,
|
||||
isProperty,
|
||||
isPureish,
|
||||
isSuper,
|
||||
isTaggedTemplateExpression,
|
||||
isTemplateLiteral,
|
||||
isThisExpression,
|
||||
isUnaryExpression,
|
||||
isVariableDeclaration,
|
||||
matchesPattern,
|
||||
memberExpression,
|
||||
numericLiteral,
|
||||
toIdentifier,
|
||||
unaryExpression,
|
||||
variableDeclaration,
|
||||
variableDeclarator,
|
||||
} from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import { scope as scopeCache } from "../cache";
|
||||
import type { Visitor } from "../types";
|
||||
|
||||
@ -12,28 +51,28 @@ import type { Visitor } from "../types";
|
||||
function gatherNodeParts(node: t.Node, parts: any[]) {
|
||||
switch (node?.type) {
|
||||
default:
|
||||
if (t.isModuleDeclaration(node)) {
|
||||
if (isModuleDeclaration(node)) {
|
||||
if (
|
||||
(t.isExportAllDeclaration(node) ||
|
||||
t.isExportNamedDeclaration(node) ||
|
||||
t.isImportDeclaration(node)) &&
|
||||
(isExportAllDeclaration(node) ||
|
||||
isExportNamedDeclaration(node) ||
|
||||
isImportDeclaration(node)) &&
|
||||
node.source
|
||||
) {
|
||||
gatherNodeParts(node.source, parts);
|
||||
} else if (
|
||||
(t.isExportNamedDeclaration(node) || t.isImportDeclaration(node)) &&
|
||||
(isExportNamedDeclaration(node) || isImportDeclaration(node)) &&
|
||||
node.specifiers &&
|
||||
node.specifiers.length
|
||||
) {
|
||||
for (const e of node.specifiers) gatherNodeParts(e, parts);
|
||||
} else if (
|
||||
(t.isExportDefaultDeclaration(node) ||
|
||||
t.isExportNamedDeclaration(node)) &&
|
||||
(isExportDefaultDeclaration(node) ||
|
||||
isExportNamedDeclaration(node)) &&
|
||||
node.declaration
|
||||
) {
|
||||
gatherNodeParts(node.declaration, parts);
|
||||
}
|
||||
} else if (t.isModuleSpecifier(node)) {
|
||||
} else if (isModuleSpecifier(node)) {
|
||||
// todo(flow->ts): should condition instead be:
|
||||
// ```
|
||||
// t.isExportSpecifier(node) ||
|
||||
@ -44,12 +83,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 (t.isLiteral(node)) {
|
||||
} else if (isLiteral(node)) {
|
||||
// todo(flow->ts): should condition be stricter to ensure value is there
|
||||
// ```
|
||||
// !t.isNullLiteral(node) &&
|
||||
// !t.isRegExpLiteral(node) &&
|
||||
// !t.isTemplateLiteral(node)
|
||||
// !isTemplateLiteral(node)
|
||||
// ```
|
||||
// @ts-expect-error todo(flow->ts)
|
||||
parts.push(node.value);
|
||||
@ -186,7 +225,7 @@ interface CollectVisitorState {
|
||||
|
||||
const collectorVisitor: Visitor<CollectVisitorState> = {
|
||||
For(path) {
|
||||
for (const key of t.FOR_INIT_KEYS) {
|
||||
for (const key of FOR_INIT_KEYS) {
|
||||
// todo: might be not needed with improvement to babel-types
|
||||
const declar = path.get(key) as NodePath;
|
||||
// delegate block scope handling to the `BlockScoped` method
|
||||
@ -236,17 +275,17 @@ const collectorVisitor: Visitor<CollectVisitorState> = {
|
||||
exit(path) {
|
||||
const { node, scope } = path;
|
||||
// ExportAllDeclaration does not have `declaration`
|
||||
if (t.isExportAllDeclaration(node)) return;
|
||||
if (isExportAllDeclaration(node)) return;
|
||||
const declar = node.declaration;
|
||||
if (t.isClassDeclaration(declar) || t.isFunctionDeclaration(declar)) {
|
||||
if (isClassDeclaration(declar) || isFunctionDeclaration(declar)) {
|
||||
const id = declar.id;
|
||||
if (!id) return;
|
||||
|
||||
const binding = scope.getBinding(id.name);
|
||||
if (binding) binding.reference(path);
|
||||
} else if (t.isVariableDeclaration(declar)) {
|
||||
} else if (isVariableDeclaration(declar)) {
|
||||
for (const decl of declar.declarations) {
|
||||
for (const name of Object.keys(t.getBindingIdentifiers(decl))) {
|
||||
for (const name of Object.keys(getBindingIdentifiers(decl))) {
|
||||
const binding = scope.getBinding(name);
|
||||
if (binding) binding.reference(path);
|
||||
}
|
||||
@ -297,7 +336,7 @@ const collectorVisitor: Visitor<CollectVisitorState> = {
|
||||
if (
|
||||
path.isFunctionExpression() &&
|
||||
path.has("id") &&
|
||||
!path.get("id").node[t.NOT_LOCAL_BINDING]
|
||||
!path.get("id").node[NOT_LOCAL_BINDING]
|
||||
) {
|
||||
path.scope.registerBinding("local", path.get("id"), path);
|
||||
}
|
||||
@ -309,7 +348,7 @@ const collectorVisitor: Visitor<CollectVisitorState> = {
|
||||
},
|
||||
|
||||
ClassExpression(path) {
|
||||
if (path.has("id") && !path.get("id").node[t.NOT_LOCAL_BINDING]) {
|
||||
if (path.has("id") && !path.get("id").node[NOT_LOCAL_BINDING]) {
|
||||
path.scope.registerBinding("local", path);
|
||||
}
|
||||
},
|
||||
@ -412,7 +451,7 @@ export default class Scope {
|
||||
generateDeclaredUidIdentifier(name?: string) {
|
||||
const id = this.generateUidIdentifier(name);
|
||||
this.push({ id });
|
||||
return t.cloneNode(id);
|
||||
return cloneNode(id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -420,7 +459,7 @@ export default class Scope {
|
||||
*/
|
||||
|
||||
generateUidIdentifier(name?: string) {
|
||||
return t.identifier(this.generateUid(name));
|
||||
return identifier(this.generateUid(name));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -428,8 +467,7 @@ export default class Scope {
|
||||
*/
|
||||
|
||||
generateUid(name: string = "temp"): string {
|
||||
name = t
|
||||
.toIdentifier(name)
|
||||
name = toIdentifier(name)
|
||||
.replace(/^_+/, "")
|
||||
.replace(/[0-9]+$/g, "");
|
||||
|
||||
@ -477,7 +515,7 @@ export default class Scope {
|
||||
*/
|
||||
|
||||
generateUidIdentifierBasedOnNode(node: t.Node, defaultName?: string) {
|
||||
return t.identifier(this.generateUidBasedOnNode(node, defaultName));
|
||||
return identifier(this.generateUidBasedOnNode(node, defaultName));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -491,11 +529,11 @@ export default class Scope {
|
||||
*/
|
||||
|
||||
isStatic(node: t.Node): boolean {
|
||||
if (t.isThisExpression(node) || t.isSuper(node)) {
|
||||
if (isThisExpression(node) || isSuper(node)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isIdentifier(node)) {
|
||||
if (isIdentifier(node)) {
|
||||
const binding = this.getBinding(node.name);
|
||||
if (binding) {
|
||||
return binding.constant;
|
||||
@ -518,7 +556,7 @@ export default class Scope {
|
||||
const id = this.generateUidIdentifierBasedOnNode(node);
|
||||
if (!dontPush) {
|
||||
this.push({ id });
|
||||
return t.cloneNode(id);
|
||||
return cloneNode(id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
@ -591,28 +629,25 @@ export default class Scope {
|
||||
|
||||
// TODO: (Babel 8) Split i in two parameters, and use an object of flags
|
||||
toArray(node: t.Node, i?: number | boolean, arrayLikeIsIterable?: boolean) {
|
||||
if (t.isIdentifier(node)) {
|
||||
if (isIdentifier(node)) {
|
||||
const binding = this.getBinding(node.name);
|
||||
if (binding?.constant && binding.path.isGenericType("Array")) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isArrayExpression(node)) {
|
||||
if (isArrayExpression(node)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (t.isIdentifier(node, { name: "arguments" })) {
|
||||
return t.callExpression(
|
||||
t.memberExpression(
|
||||
t.memberExpression(
|
||||
t.memberExpression(
|
||||
t.identifier("Array"),
|
||||
t.identifier("prototype"),
|
||||
if (isIdentifier(node, { name: "arguments" })) {
|
||||
return callExpression(
|
||||
memberExpression(
|
||||
memberExpression(
|
||||
memberExpression(identifier("Array"), identifier("prototype")),
|
||||
identifier("slice"),
|
||||
),
|
||||
t.identifier("slice"),
|
||||
),
|
||||
t.identifier("call"),
|
||||
identifier("call"),
|
||||
),
|
||||
[node],
|
||||
);
|
||||
@ -624,7 +659,7 @@ export default class Scope {
|
||||
// Used in array-spread to create an array.
|
||||
helperName = "toConsumableArray";
|
||||
} else if (i) {
|
||||
args.push(t.numericLiteral(i));
|
||||
args.push(numericLiteral(i));
|
||||
|
||||
// Used in array-rest to create an array from a subset of an iterable.
|
||||
helperName = "slicedToArray";
|
||||
@ -640,7 +675,7 @@ export default class Scope {
|
||||
}
|
||||
|
||||
// @ts-expect-error todo(flow->ts): t.Node is not valid to use in args, function argument typeneeds to be clarified
|
||||
return t.callExpression(this.hub.addHelper(helperName), args);
|
||||
return callExpression(this.hub.addHelper(helperName), args);
|
||||
}
|
||||
|
||||
hasLabel(name: string) {
|
||||
@ -688,7 +723,7 @@ export default class Scope {
|
||||
}
|
||||
|
||||
buildUndefinedNode() {
|
||||
return t.unaryExpression("void", t.numericLiteral(0), true);
|
||||
return unaryExpression("void", numericLiteral(0), true);
|
||||
}
|
||||
|
||||
registerConstantViolation(path: NodePath) {
|
||||
@ -776,59 +811,59 @@ export default class Scope {
|
||||
}
|
||||
|
||||
isPure(node: t.Node, constantsOnly?: boolean) {
|
||||
if (t.isIdentifier(node)) {
|
||||
if (isIdentifier(node)) {
|
||||
const binding = this.getBinding(node.name);
|
||||
if (!binding) return false;
|
||||
if (constantsOnly) return binding.constant;
|
||||
return true;
|
||||
} else if (t.isClass(node)) {
|
||||
} else if (isClass(node)) {
|
||||
if (node.superClass && !this.isPure(node.superClass, constantsOnly)) {
|
||||
return false;
|
||||
}
|
||||
return this.isPure(node.body, constantsOnly);
|
||||
} else if (t.isClassBody(node)) {
|
||||
} else if (isClassBody(node)) {
|
||||
for (const method of node.body) {
|
||||
if (!this.isPure(method, constantsOnly)) return false;
|
||||
}
|
||||
return true;
|
||||
} else if (t.isBinary(node)) {
|
||||
} else if (isBinary(node)) {
|
||||
return (
|
||||
this.isPure(node.left, constantsOnly) &&
|
||||
this.isPure(node.right, constantsOnly)
|
||||
);
|
||||
} else if (t.isArrayExpression(node)) {
|
||||
} else if (isArrayExpression(node)) {
|
||||
for (const elem of node.elements) {
|
||||
if (!this.isPure(elem, constantsOnly)) return false;
|
||||
}
|
||||
return true;
|
||||
} else if (t.isObjectExpression(node)) {
|
||||
} else if (isObjectExpression(node)) {
|
||||
for (const prop of node.properties) {
|
||||
if (!this.isPure(prop, constantsOnly)) return false;
|
||||
}
|
||||
return true;
|
||||
} else if (t.isMethod(node)) {
|
||||
} else if (isMethod(node)) {
|
||||
if (node.computed && !this.isPure(node.key, constantsOnly)) return false;
|
||||
if (node.kind === "get" || node.kind === "set") return false;
|
||||
return true;
|
||||
} else if (t.isProperty(node)) {
|
||||
} else if (isProperty(node)) {
|
||||
// @ts-expect-error todo(flow->ts): computed in not present on private properties
|
||||
if (node.computed && !this.isPure(node.key, constantsOnly)) return false;
|
||||
return this.isPure(node.value, constantsOnly);
|
||||
} else if (t.isUnaryExpression(node)) {
|
||||
} else if (isUnaryExpression(node)) {
|
||||
return this.isPure(node.argument, constantsOnly);
|
||||
} else if (t.isTaggedTemplateExpression(node)) {
|
||||
} else if (isTaggedTemplateExpression(node)) {
|
||||
return (
|
||||
t.matchesPattern(node.tag, "String.raw") &&
|
||||
matchesPattern(node.tag, "String.raw") &&
|
||||
!this.hasBinding("String", true) &&
|
||||
this.isPure(node.quasi, constantsOnly)
|
||||
);
|
||||
} else if (t.isTemplateLiteral(node)) {
|
||||
} else if (isTemplateLiteral(node)) {
|
||||
for (const expression of node.expressions) {
|
||||
if (!this.isPure(expression, constantsOnly)) return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return t.isPureish(node);
|
||||
return isPureish(node);
|
||||
}
|
||||
}
|
||||
|
||||
@ -969,7 +1004,7 @@ export default class Scope {
|
||||
let declarPath = !unique && path.getData(dataKey);
|
||||
|
||||
if (!declarPath) {
|
||||
const declar = t.variableDeclaration(kind, []);
|
||||
const declar = variableDeclaration(kind, []);
|
||||
// @ts-expect-error todo(flow->ts): avoid modifying nodes
|
||||
declar._blockHoist = blockHoist;
|
||||
|
||||
@ -977,7 +1012,7 @@ export default class Scope {
|
||||
if (!unique) path.setData(dataKey, declarPath);
|
||||
}
|
||||
|
||||
const declarator = t.variableDeclarator(opts.id, opts.init);
|
||||
const declarator = variableDeclarator(opts.id, opts.init);
|
||||
declarPath.node.declarations.push(declarator);
|
||||
this.registerBinding(kind, declarPath.get("declarations").pop());
|
||||
}
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
import Binding from "../binding";
|
||||
import splitExportDeclaration from "@babel/helper-split-export-declaration";
|
||||
import * as t from "@babel/types";
|
||||
import {
|
||||
VISITOR_KEYS,
|
||||
assignmentExpression,
|
||||
identifier,
|
||||
toExpression,
|
||||
variableDeclaration,
|
||||
variableDeclarator,
|
||||
} from "@babel/types";
|
||||
import type { Visitor } from "../../types";
|
||||
|
||||
const renameVisitor: Visitor<Renamer> = {
|
||||
@ -68,15 +75,12 @@ export default class Renamer {
|
||||
if (!path.isFunctionDeclaration() && !path.isClassDeclaration()) return;
|
||||
if (this.binding.kind !== "hoisted") return;
|
||||
|
||||
path.node.id = t.identifier(this.oldName);
|
||||
path.node.id = identifier(this.oldName);
|
||||
path.node._blockHoist = 3;
|
||||
|
||||
path.replaceWith(
|
||||
t.variableDeclaration("let", [
|
||||
t.variableDeclarator(
|
||||
t.identifier(this.newName),
|
||||
t.toExpression(path.node),
|
||||
),
|
||||
variableDeclaration("let", [
|
||||
variableDeclarator(identifier(this.newName), toExpression(path.node)),
|
||||
]),
|
||||
);
|
||||
}
|
||||
@ -90,14 +94,14 @@ export default class Renamer {
|
||||
if (!path.isFunctionExpression() && !path.isClassExpression()) return;
|
||||
if (this.binding.kind !== "local") return;
|
||||
|
||||
path.node.id = t.identifier(this.oldName);
|
||||
path.node.id = identifier(this.oldName);
|
||||
|
||||
this.binding.scope.parent.push({
|
||||
id: t.identifier(this.newName),
|
||||
id: identifier(this.newName),
|
||||
});
|
||||
|
||||
path.replaceWith(
|
||||
t.assignmentExpression("=", t.identifier(this.newName), path.node),
|
||||
assignmentExpression("=", identifier(this.newName), path.node),
|
||||
);
|
||||
}
|
||||
|
||||
@ -152,7 +156,7 @@ function skipAllButComputedMethodKey(path) {
|
||||
|
||||
// So it's a method with a computed key. Make sure to skip every other key the
|
||||
// traversal would visit.
|
||||
const keys = t.VISITOR_KEYS[path.type];
|
||||
const keys = VISITOR_KEYS[path.type];
|
||||
for (const key of keys) {
|
||||
if (key !== "key") path.skipKey(key);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as t from "@babel/types";
|
||||
import type * as t from "@babel/types";
|
||||
import { NodePath } from "./index";
|
||||
import { VirtualTypeAliases } from "./path/generated/virtual-types";
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import * as virtualTypes from "./path/lib/virtual-types";
|
||||
import * as t from "@babel/types";
|
||||
import { DEPRECATED_KEYS, FLIPPED_ALIAS_KEYS, TYPES } from "@babel/types";
|
||||
|
||||
/**
|
||||
* explode() will take a visitor object with all of the various shorthands
|
||||
@ -85,9 +85,9 @@ export function explode(visitor) {
|
||||
|
||||
const fns = visitor[nodeType];
|
||||
|
||||
let aliases: Array<string> | undefined = t.FLIPPED_ALIAS_KEYS[nodeType];
|
||||
let aliases: Array<string> | undefined = FLIPPED_ALIAS_KEYS[nodeType];
|
||||
|
||||
const deprecatedKey = t.DEPRECATED_KEYS[nodeType];
|
||||
const deprecatedKey = DEPRECATED_KEYS[nodeType];
|
||||
if (deprecatedKey) {
|
||||
console.trace(
|
||||
`Visitor defined for ${nodeType} but it has been renamed to ${deprecatedKey}`,
|
||||
@ -136,7 +136,7 @@ export function verify(visitor) {
|
||||
|
||||
if (shouldIgnoreKey(nodeType)) continue;
|
||||
|
||||
if (t.TYPES.indexOf(nodeType) < 0) {
|
||||
if (TYPES.indexOf(nodeType) < 0) {
|
||||
throw new Error(
|
||||
`You gave us a visitor for the node type ${nodeType} but it's not a valid type`,
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user