summaryrefslogtreecommitdiff
path: root/node_modules/@babel/helpers/scripts
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2024-08-30 17:21:18 +0800
committerlittleblack111 <littleblack11111@gmail.com>2024-08-30 17:21:18 +0800
commitefbc2ffe6a1ee5ec38a4396305561d6515d0943e (patch)
tree2b4c94f18f2c792dfda813050755d5c0273fae22 /node_modules/@babel/helpers/scripts
parent43acceb75957c880a5ba5a31aae221394a36d5f6 (diff)
node fixes, updates
Diffstat (limited to 'node_modules/@babel/helpers/scripts')
-rw-r--r--node_modules/@babel/helpers/scripts/build-helper-metadata.js209
-rw-r--r--node_modules/@babel/helpers/scripts/generate-helpers.js108
-rw-r--r--node_modules/@babel/helpers/scripts/generate-regenerator-runtime.js2
-rw-r--r--node_modules/@babel/helpers/scripts/package.json1
4 files changed, 302 insertions, 18 deletions
diff --git a/node_modules/@babel/helpers/scripts/build-helper-metadata.js b/node_modules/@babel/helpers/scripts/build-helper-metadata.js
new file mode 100644
index 00000000..6a54fa0e
--- /dev/null
+++ b/node_modules/@babel/helpers/scripts/build-helper-metadata.js
@@ -0,0 +1,209 @@
+// NOTE: This file must be compatible with old Node.js versions, since it runs
+// during testing.
+
+/**
+ * @typedef {Object} HelperMetadata
+ * @property {string[]} globals
+ * @property {{ [name: string]: string[] }} locals
+ * @property {{ [name: string]: string[] }} dependencies
+ * @property {string[]} exportBindingAssignments
+ * @property {string} exportName
+ */
+
+/**
+ * Given a file AST for a given helper, get a bunch of metadata about it so that Babel can quickly render
+ * the helper is whatever context it is needed in.
+ *
+ * @param {typeof import("@babel/core")} babel
+ *
+ * @returns {HelperMetadata}
+ */
+export function getHelperMetadata(babel, code, helperName) {
+ const globals = new Set();
+ // Maps imported identifier name -> helper name
+ const dependenciesBindings = new Map();
+
+ let exportName;
+ const exportBindingAssignments = [];
+ // helper name -> reference paths
+ const dependencies = new Map();
+ // local variable name -> reference paths
+ const locals = new Map();
+
+ const spansToRemove = [];
+
+ const validateDefaultExport = decl => {
+ if (exportName) {
+ throw new Error(
+ `Helpers can have only one default export (in ${helperName})`
+ );
+ }
+
+ if (!decl.isFunctionDeclaration() || !decl.node.id) {
+ throw new Error(
+ `Helpers can only export named function declarations (in ${helperName})`
+ );
+ }
+ };
+
+ /** @type {import("@babel/traverse").Visitor} */
+ const dependencyVisitor = {
+ Program(path) {
+ for (const child of path.get("body")) {
+ if (child.isImportDeclaration()) {
+ if (
+ child.get("specifiers").length !== 1 ||
+ !child.get("specifiers.0").isImportDefaultSpecifier()
+ ) {
+ throw new Error(
+ `Helpers can only import a default value (in ${helperName})`
+ );
+ }
+ dependenciesBindings.set(
+ child.node.specifiers[0].local.name,
+ child.node.source.value
+ );
+ dependencies.set(child.node.source.value, []);
+ spansToRemove.push([child.node.start, child.node.end]);
+ child.remove();
+ }
+ }
+ for (const child of path.get("body")) {
+ if (child.isExportDefaultDeclaration()) {
+ const decl = child.get("declaration");
+ validateDefaultExport(decl);
+
+ exportName = decl.node.id.name;
+ spansToRemove.push([child.node.start, decl.node.start]);
+ child.replaceWith(decl.node);
+ } else if (
+ child.isExportNamedDeclaration() &&
+ child.node.specifiers.length === 1 &&
+ child.get("specifiers.0.exported").isIdentifier({ name: "default" })
+ ) {
+ const { name } = child.node.specifiers[0].local;
+
+ validateDefaultExport(child.scope.getBinding(name).path);
+
+ exportName = name;
+ spansToRemove.push([child.node.start, child.node.end]);
+ child.remove();
+ } else if (
+ process.env.IS_BABEL_OLD_E2E &&
+ child.isExportNamedDeclaration() &&
+ child.node.specifiers.length === 0
+ ) {
+ spansToRemove.push([child.node.start, child.node.end]);
+ child.remove();
+ } else if (
+ child.isExportAllDeclaration() ||
+ child.isExportNamedDeclaration()
+ ) {
+ throw new Error(`Helpers can only export default (in ${helperName})`);
+ }
+ }
+
+ path.scope.crawl();
+
+ const bindings = path.scope.getAllBindings();
+ Object.keys(bindings).forEach(name => {
+ if (dependencies.has(name)) return;
+
+ const binding = bindings[name];
+
+ const references = [
+ ...binding.path.getBindingIdentifierPaths(true)[name].map(makePath),
+ ...binding.referencePaths.map(makePath),
+ ];
+ for (const violation of binding.constantViolations) {
+ violation.getBindingIdentifierPaths(true)[name].forEach(path => {
+ references.push(makePath(path));
+ });
+ }
+
+ locals.set(name, references);
+ });
+ },
+ ReferencedIdentifier(child) {
+ const name = child.node.name;
+ const binding = child.scope.getBinding(name);
+ if (!binding) {
+ if (dependenciesBindings.has(name)) {
+ dependencies
+ .get(dependenciesBindings.get(name))
+ .push(makePath(child));
+ } else if (name !== "arguments" || child.scope.path.isProgram()) {
+ globals.add(name);
+ }
+ }
+ },
+ AssignmentExpression(child) {
+ const left = child.get("left");
+
+ if (!(exportName in left.getBindingIdentifiers())) return;
+
+ if (!left.isIdentifier()) {
+ throw new Error(
+ `Only simple assignments to exports are allowed in helpers (in ${helperName})`
+ );
+ }
+
+ const binding = child.scope.getBinding(exportName);
+
+ if (binding && binding.scope.path.isProgram()) {
+ exportBindingAssignments.push(makePath(child));
+ }
+ },
+ };
+
+ babel.transformSync(code, {
+ configFile: false,
+ babelrc: false,
+ plugins: [() => ({ visitor: dependencyVisitor })],
+ });
+
+ if (!exportName) throw new Error("Helpers must have a named default export.");
+
+ // Process these in reverse so that mutating the references does not invalidate any later paths in
+ // the list.
+ exportBindingAssignments.reverse();
+
+ spansToRemove.sort(([start1], [start2]) => start2 - start1);
+ for (const [start, end] of spansToRemove) {
+ code = code.slice(0, start) + code.slice(end);
+ }
+
+ return [
+ code,
+ {
+ globals: Array.from(globals),
+ locals: Object.fromEntries(locals),
+ dependencies: Object.fromEntries(dependencies),
+ exportBindingAssignments,
+ exportName,
+ },
+ ];
+}
+
+function makePath(path) {
+ const parts = [];
+
+ for (; path.parentPath; path = path.parentPath) {
+ parts.push(path.key);
+ if (path.inList) parts.push(path.listKey);
+ }
+
+ return parts.reverse().join(".");
+}
+
+export function stringifyMetadata(metadata) {
+ return `\
+ {
+ globals: ${JSON.stringify(metadata.globals)},
+ locals: ${JSON.stringify(metadata.locals)},
+ exportBindingAssignments: ${JSON.stringify(metadata.exportBindingAssignments)},
+ exportName: ${JSON.stringify(metadata.exportName)},
+ dependencies: ${JSON.stringify(metadata.dependencies)},
+ }
+ `;
+}
diff --git a/node_modules/@babel/helpers/scripts/generate-helpers.js b/node_modules/@babel/helpers/scripts/generate-helpers.js
index 45182c95..9eeb95a2 100644
--- a/node_modules/@babel/helpers/scripts/generate-helpers.js
+++ b/node_modules/@babel/helpers/scripts/generate-helpers.js
@@ -3,13 +3,17 @@ import fs from "fs";
import { join } from "path";
import { URL, fileURLToPath } from "url";
import { minify } from "terser";
-import { transformSync } from "@babel/core";
-import presetTypescript from "@babel/preset-typescript";
-import { gzipSync } from "zlib";
+import { babel, presetTypescript } from "$repo-utils/babel-top-level";
import { IS_BABEL_8 } from "$repo-utils";
+import { gzipSync } from "zlib";
+
+import {
+ getHelperMetadata,
+ stringifyMetadata,
+} from "./build-helper-metadata.js";
const HELPERS_FOLDER = new URL("../src/helpers", import.meta.url);
-const IGNORED_FILES = new Set(["package.json"]);
+const IGNORED_FILES = new Set(["package.json", "tsconfig.json"]);
export default async function generateHelpers() {
let output = `/*
@@ -18,17 +22,37 @@ export default async function generateHelpers() {
*/
import template from "@babel/template";
+import type * as t from "@babel/types";
+
+interface Helper {
+ minVersion: string;
+ ast: () => t.Program;
+ metadata: HelperMetadata;
+}
+
+export interface HelperMetadata {
+ globals: string[];
+ locals: { [name: string]: string[] };
+ dependencies: { [name: string]: string[] };
+ exportBindingAssignments: string[];
+ exportName: string;
+}
-function helper(minVersion: string, source: string) {
+function helper(minVersion: string, source: string, metadata: HelperMetadata): Helper {
return Object.freeze({
minVersion,
ast: () => template.program.ast(source, { preserveComments: true }),
+ metadata,
})
}
-export default Object.freeze({
+export { helpers as default };
+const helpers: Record<string, Helper> = {
+ __proto__: null,
`;
+ let babel7extraOutput = "";
+
for (const file of (await fs.promises.readdir(HELPERS_FOLDER)).sort()) {
if (IGNORED_FILES.has(file)) continue;
if (file.startsWith(".")) continue; // ignore e.g. vim swap files
@@ -52,14 +76,11 @@ export default Object.freeze({
}
const { minVersion } = minVersionMatch.groups;
- if (IS_BABEL_8() && code.includes("@onlyBabel7")) {
- continue;
- }
-
+ const onlyBabel7 = code.includes("@onlyBabel7");
const mangleFns = code.includes("@mangleFns");
const noMangleFns = [];
- code = transformSync(code, {
+ code = babel.transformSync(code, {
configFile: false,
babelrc: false,
filename: filePath,
@@ -76,7 +97,41 @@ export default Object.freeze({
/**
* @type {import("@babel/core").PluginObj}
*/
- {
+ ({ types: t }) => ({
+ // These pre/post hooks are needed because the TS transform is,
+ // when building in the old Babel e2e test, removing the
+ // `export { OverloadYield as default }` in the OverloadYield helper.
+ // TODO: Remove in Babel 8.
+ pre(file) {
+ if (!process.env.IS_BABEL_OLD_E2E) return;
+ file.metadata.exportName = null;
+ file.path.traverse({
+ ExportSpecifier(path) {
+ if (path.node.exported.name === "default") {
+ file.metadata.exportName = path.node.local.name;
+ }
+ },
+ });
+ },
+ post(file) {
+ if (!process.env.IS_BABEL_OLD_E2E) return;
+ if (!file.metadata.exportName) return;
+ file.path.traverse({
+ ExportNamedDeclaration(path) {
+ if (
+ !path.node.declaration &&
+ path.node.specifiers.length === 0
+ ) {
+ path.node.specifiers.push(
+ t.exportSpecifier(
+ t.identifier(file.metadata.exportName),
+ t.identifier("default")
+ )
+ );
+ }
+ },
+ });
+ },
visitor: {
ImportDeclaration(path) {
const source = path.node.source;
@@ -96,7 +151,7 @@ export default Object.freeze({
}
},
},
- },
+ }),
],
}).code;
code = (
@@ -115,15 +170,38 @@ export default Object.freeze({
})
).code;
- output += `\
+ let metadata;
+ // eslint-disable-next-line prefer-const
+ [code, metadata] = getHelperMetadata(babel, code, helperName);
+
+ const helperStr = `\
// size: ${code.length}, gzip size: ${gzipSync(code).length}
${JSON.stringify(helperName)}: helper(
${JSON.stringify(minVersion)},
${JSON.stringify(code)},
+ ${stringifyMetadata(metadata)}
),
`;
+
+ if (onlyBabel7) {
+ if (!IS_BABEL_8()) babel7extraOutput += helperStr;
+ } else {
+ output += helperStr;
+ }
+ }
+
+ output += "};";
+
+ if (babel7extraOutput) {
+ output += `
+
+if (!process.env.BABEL_8_BREAKING) {
+ Object.assign(helpers, {
+ ${babel7extraOutput}
+ });
+}
+`;
}
- output += "});";
return output;
}
diff --git a/node_modules/@babel/helpers/scripts/generate-regenerator-runtime.js b/node_modules/@babel/helpers/scripts/generate-regenerator-runtime.js
index 34a46d63..73c301ce 100644
--- a/node_modules/@babel/helpers/scripts/generate-regenerator-runtime.js
+++ b/node_modules/@babel/helpers/scripts/generate-regenerator-runtime.js
@@ -1,5 +1,3 @@
-/* eslint-disable import/no-extraneous-dependencies */
-
import fs from "fs";
import { createRequire } from "module";
diff --git a/node_modules/@babel/helpers/scripts/package.json b/node_modules/@babel/helpers/scripts/package.json
deleted file mode 100644
index 5ffd9800..00000000
--- a/node_modules/@babel/helpers/scripts/package.json
+++ /dev/null
@@ -1 +0,0 @@
-{ "type": "module" }