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