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:
Huáng Jùnliàng 2021-08-18 10:28:40 -04:00 committed by GitHub
parent fc66d4dd05
commit 614b486780
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
65 changed files with 1283 additions and 787 deletions

View File

@ -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) &&

View File

@ -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 = {};

View File

@ -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) {

View File

@ -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,

View File

@ -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) {

View 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,

View File

@ -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" ||

View File

@ -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");
}

View File

@ -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);

View File

@ -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("(");

View File

@ -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") {

View File

@ -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();

View File

@ -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,

View File

@ -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);

View File

@ -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(":");

View File

@ -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]);

View File

@ -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,

View File

@ -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;

View File

@ -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 = {

View File

@ -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);
}

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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));
}
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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)),
);
}
}

View File

@ -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));
},
},
]);

View File

@ -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,
]);

View File

@ -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 })
);

View File

@ -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() {

View File

@ -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 = "=";

View File

@ -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)
);
}

View File

@ -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);

View File

@ -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"));

View File

@ -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(
{

View File

@ -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\`

View File

@ -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;
}

View File

@ -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;
},
};

View File

@ -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";

View File

@ -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;
}
}

View File

@ -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!

View File

@ -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;
};

View File

@ -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];

View File

@ -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);
}

View File

@ -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);
});
}

View File

@ -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;

View File

@ -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];

View File

@ -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 })
);
}

View File

@ -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,
};
}

View File

@ -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) {

View File

@ -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;

View File

@ -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")

View File

@ -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;

View File

@ -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(

View File

@ -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");

View File

@ -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"),
),
t.identifier("slice"),
if (isIdentifier(node, { name: "arguments" })) {
return callExpression(
memberExpression(
memberExpression(
memberExpression(identifier("Array"), identifier("prototype")),
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());
}

View File

@ -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);
}

View File

@ -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";

View File

@ -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`,
);