diff --git a/Gulpfile.mjs b/Gulpfile.mjs index b4b49425bc25..7cc77ee2780e 100644 --- a/Gulpfile.mjs +++ b/Gulpfile.mjs @@ -47,6 +47,11 @@ const buildTypingsWatchGlob = [ "./packages/babel-types/scripts/generators/*.js", ]; +// env vars from the cli are always strings, so !!ENV_VAR returns true for "false" +function bool(value) { + return value && value !== "false" && value !== "0"; +} + /** * map source code path to the generated artifacts path * @example @@ -312,23 +317,49 @@ if (process.env.CIRCLE_PR_NUMBER) { const babelVersion = require("./packages/babel-core/package.json").version + versionSuffix; -function buildRollup(packages, targetBrowsers) { +function buildRollup(packages, buildStandalone) { const sourcemap = process.env.NODE_ENV === "production"; return Promise.all( packages.map( - async ({ src, format, dest, name, filename, envName = "rollup" }) => { + async ({ + src, + format, + input, + dest, + name, + filename, + envName = "rollup", + }) => { const pkgJSON = require("./" + src + "/package.json"); const version = pkgJSON.version + versionSuffix; const { dependencies = {}, peerDependencies = {} } = pkgJSON; - const external = Object.keys(dependencies).concat( - Object.keys(peerDependencies) - ); + const external = [ + ...Object.keys(dependencies), + ...Object.keys(peerDependencies), + // @babel/compat-data sub exports + "@babel/compat-data/overlapping-plugins", + "@babel/compat-data/plugins", + "@babel/compat-data/plugin-bugfixes", + "@babel/compat-data/native-modules", + "@babel/compat-data/corejs2-built-ins", + // Ideally they should be constructed from package.json exports + // required by modules-commonjs + "babel-plugin-dynamic-import-node/utils", + // required by preset-env + "@babel/preset-modules/lib/plugins/transform-async-arrows-in-class", + "@babel/preset-modules/lib/plugins/transform-edge-default-parameters", + "@babel/preset-modules/lib/plugins/transform-edge-function-name", + "@babel/preset-modules/lib/plugins/transform-tagged-template-caching", + "@babel/preset-modules/lib/plugins/transform-safari-block-shadowing", + "@babel/preset-modules/lib/plugins/transform-safari-for-shadowing", + ]; - const input = getIndexFromPackage(src); log(`Compiling '${chalk.cyan(input)}' with rollup ...`); const bundle = await rollup({ input, - external, + external: buildStandalone ? [] : external, + // all node modules are resolved as if they were placed in the n_m folder of package root + preserveSymlinks: true, onwarn(warning, warn) { switch (warning.code) { case "CIRCULAR_DEPENDENCY": @@ -374,7 +405,8 @@ function buildRollup(packages, targetBrowsers) { }), rollupCommonJs({ include: [ - /node_modules/, + // Bundle node_modules only when building standalone + buildStandalone ? /node_modules/ : "./node_modules/*/*.js", "packages/babel-runtime/regenerator/**", "packages/babel-runtime/helpers/*.js", "packages/babel-preset-env/data/*.js", @@ -406,19 +438,23 @@ function buildRollup(packages, targetBrowsers) { }), rollupNodeResolve({ extensions: [".ts", ".js", ".mjs", ".cjs", ".json"], - browser: targetBrowsers, - exportConditions: targetBrowsers ? ["browser"] : [], + browser: buildStandalone, + exportConditions: buildStandalone ? ["browser"] : [], // It needs to be set to 'false' when using rollupNodePolyfills // https://github.com/rollup/plugins/issues/772 - preferBuiltins: !targetBrowsers, + preferBuiltins: !buildStandalone, }), rollupJson(), - targetBrowsers && + buildStandalone && rollupPolyfillNode({ sourceMap: sourcemap, - include: "**/*.{js,cjs,ts}", + include: "**/*.{js,mjs,cjs,ts}", }), ].filter(Boolean), + acorn: { + // babel-cli/src/babel/index.ts has shebang + allowHashBang: true, + }, }); const outputFile = path.join(src, dest, filename || "index.js"); @@ -428,8 +464,30 @@ function buildRollup(packages, targetBrowsers) { name, sourcemap: sourcemap, exports: "named", + interop(id) { + // We have manually applied commonjs-esm interop to the source + // for library not in this monorepo + // https://github.com/babel/babel/pull/12795 + if (!id.startsWith("@babel/")) return false; + + // Some syntax plugins have been archived + if (id.includes("plugin-syntax")) { + const srcPath = new URL( + "./packages/" + id.replace("@babel/", "babel-"), + import.meta.url + ); + if (!fs.existsSync(srcPath)) return false; + } + + return true; + }, }); + // Only minify @babel/standalone + if (!buildStandalone) { + return; + } + if (!process.env.IS_PUBLISH) { log( chalk.yellow( @@ -495,22 +553,90 @@ function copyDts(packages) { .pipe(gulp.dest(monorepoRoot)); } -const libBundles = [ - "packages/babel-parser", - "packages/babel-plugin-proposal-destructuring-private", - "packages/babel-plugin-proposal-object-rest-spread", - "packages/babel-plugin-proposal-optional-chaining", - "packages/babel-preset-react", - "packages/babel-plugin-transform-destructuring", - "packages/babel-preset-typescript", - "packages/babel-helper-member-expression-to-functions", - "packages/babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining", - "packages/babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression", -].map(src => ({ - src, - format: USE_ESM ? "esm" : "cjs", - dest: "lib", -})); +function* libBundlesIterator() { + const noBundle = new Set([ + // @rollup/plugin-commonjs will mess up with babel-helper-fixtures + "babel-helper-fixtures", + // babel-standalone is handled by rollup-babel-standalone task + "babel-standalone", + // todo: Rollup hangs on allowHashBang: true with babel-cli/src/babel/index.ts hashbang + "babel-cli", + // todo: @rollup/node-resolve 'browsers' option does not work when package.json contains `exports` + // https://github.com/rollup/plugins/tree/master/packages/node-resolve#browser + "babel-register", + "babel-core", + "babel-plugin-transform-runtime", + // @babel/node invokes internal lib/_babel-node.js + "babel-node", + // todo: test/helpers/define-helper requires internal lib/helpers access + "babel-helpers", + // multiple exports + "babel-plugin-transform-react-jsx", + ]); + for (const packageDir of ["packages", "codemods"]) { + for (const dir of fs.readdirSync(new URL(packageDir, import.meta.url))) { + if (noBundle.has(dir)) continue; + + const src = `${packageDir}/${dir}`; + + let pkgJSON; + try { + pkgJSON = JSON.parse( + fs.readFileSync(new URL(`${src}/package.json`, import.meta.url)) + ); + } catch (err) { + if (err.code !== "ENOENT" && err.code !== "ENOTDIR") throw err; + continue; + } + if (pkgJSON.main) { + yield { + src, + format: USE_ESM ? "esm" : "cjs", + dest: "lib", + input: getIndexFromPackage(src), + }; + } else if (pkgJSON.bin) { + for (const binPath of Object.values(pkgJSON.bin)) { + const filename = binPath.slice(binPath.lastIndexOf("/") + 1); + const input = + dir === "babel-cli" && filename === "babel.js" + ? `${src}/src/babel/index.ts` + : `${src}/src/${filename.slice(0, -3) + ".ts"}`; + yield { + src, + format: USE_ESM ? "esm" : "cjs", + dest: "lib", + filename, + input, + }; + } + } + } + } +} + +let libBundles; +if (bool(process.env.BABEL_8_BREAKING)) { + libBundles = Array.from(libBundlesIterator()); +} else { + libBundles = [ + "packages/babel-parser", + "packages/babel-plugin-proposal-destructuring-private", + "packages/babel-plugin-proposal-object-rest-spread", + "packages/babel-plugin-proposal-optional-chaining", + "packages/babel-preset-react", + "packages/babel-plugin-transform-destructuring", + "packages/babel-preset-typescript", + "packages/babel-helper-member-expression-to-functions", + "packages/babel-plugin-bugfix-v8-spread-parameters-in-optional-chaining", + "packages/babel-plugin-bugfix-safari-id-destructuring-collision-in-function-expression", + ].map(src => ({ + src, + format: USE_ESM ? "esm" : "cjs", + dest: "lib", + input: getIndexFromPackage(src), + })); +} const cjsBundles = [ // This is used by @babel/register and @babel/eslint-parser @@ -528,6 +654,7 @@ const standaloneBundle = [ dest: "", version: babelVersion, envName: "standalone", + input: getIndexFromPackage("packages/babel-standalone"), }, ]; diff --git a/packages/babel-generator/test/index.js b/packages/babel-generator/test/index.js index cd0151be5da2..b32847f2cdfe 100644 --- a/packages/babel-generator/test/index.js +++ b/packages/babel-generator/test/index.js @@ -6,23 +6,10 @@ import fixtures from "@babel/helper-fixtures"; import { TraceMap, originalPositionFor } from "@jridgewell/trace-mapping"; import { fileURLToPath } from "url"; -import _Printer from "../lib/printer.js"; import _generate, { CodeGenerator } from "../lib/index.js"; -const Printer = _Printer.default || _Printer; const generate = _generate.default || _generate; describe("generation", function () { - it("completeness", function () { - Object.keys(t.VISITOR_KEYS).forEach(function (type) { - expect(Printer.prototype[type]).toBeTruthy(); - }); - - Object.keys(Printer.prototype).forEach(function (type) { - if (!/[A-Z]/.test(type[0])) return; - expect(t.VISITOR_KEYS[type]).toBeTruthy(); - }); - }); - it("multiple sources", function () { const sources = { "a.js": "function hi (msg) { console.log(msg); }\n", diff --git a/packages/babel-generator/test/printer.skip-bundled.js b/packages/babel-generator/test/printer.skip-bundled.js new file mode 100644 index 000000000000..dbb594da2a1f --- /dev/null +++ b/packages/babel-generator/test/printer.skip-bundled.js @@ -0,0 +1,16 @@ +import * as t from "@babel/types"; +import _Printer from "../lib/printer.js"; +const Printer = _Printer.default || _Printer; + +describe("Printer", () => { + it("completeness", function () { + Object.keys(t.VISITOR_KEYS).forEach(function (type) { + expect(Printer.prototype[type]).toBeTruthy(); + }); + + Object.keys(Printer.prototype).forEach(function (type) { + if (!/[A-Z]/.test(type[0])) return; + expect(t.VISITOR_KEYS[type]).toBeTruthy(); + }); + }); +}); diff --git a/packages/babel-helper-compilation-targets/test/pretty.spec.js b/packages/babel-helper-compilation-targets/test/pretty.skip-bundled.js similarity index 100% rename from packages/babel-helper-compilation-targets/test/pretty.spec.js rename to packages/babel-helper-compilation-targets/test/pretty.skip-bundled.js diff --git a/packages/babel-helper-compilation-targets/test/targets-supported.js b/packages/babel-helper-compilation-targets/test/targets-supported.skip-bundled.js similarity index 100% rename from packages/babel-helper-compilation-targets/test/targets-supported.js rename to packages/babel-helper-compilation-targets/test/targets-supported.skip-bundled.js diff --git a/packages/babel-helper-compilation-targets/test/utils.spec.js b/packages/babel-helper-compilation-targets/test/utils.skip-bundled.js similarity index 100% rename from packages/babel-helper-compilation-targets/test/utils.spec.js rename to packages/babel-helper-compilation-targets/test/utils.skip-bundled.js diff --git a/packages/babel-preset-env/test/get-option-specific-excludes.spec.js b/packages/babel-preset-env/test/get-option-specific-excludes.skip-bundled.js similarity index 100% rename from packages/babel-preset-env/test/get-option-specific-excludes.spec.js rename to packages/babel-preset-env/test/get-option-specific-excludes.skip-bundled.js diff --git a/packages/babel-preset-env/test/index.spec.js b/packages/babel-preset-env/test/index.skip-bundled.js similarity index 100% rename from packages/babel-preset-env/test/index.spec.js rename to packages/babel-preset-env/test/index.skip-bundled.js diff --git a/packages/babel-preset-env/test/normalize-options.spec.js b/packages/babel-preset-env/test/normalize-options.skip-bundled.js similarity index 100% rename from packages/babel-preset-env/test/normalize-options.spec.js rename to packages/babel-preset-env/test/normalize-options.skip-bundled.js diff --git a/packages/babel-preset-flow/test/normalize-options.spec.js b/packages/babel-preset-flow/test/normalize-options.skip-bundled.js similarity index 100% rename from packages/babel-preset-flow/test/normalize-options.spec.js rename to packages/babel-preset-flow/test/normalize-options.skip-bundled.js diff --git a/packages/babel-types/scripts/generators/asserts.js b/packages/babel-types/scripts/generators/asserts.js index 1d862e417601..34e4e57e9543 100644 --- a/packages/babel-types/scripts/generators/asserts.js +++ b/packages/babel-types/scripts/generators/asserts.js @@ -1,8 +1,13 @@ -import * as definitions from "../../lib/definitions/index.js"; +import { + DEPRECATED_KEYS, + FLIPPED_ALIAS_KEYS, + NODE_FIELDS, + VISITOR_KEYS, +} from "../../lib/index.js"; function addAssertHelper(type) { const result = - definitions.NODE_FIELDS[type] || definitions.FLIPPED_ALIAS_KEYS[type] + NODE_FIELDS[type] || FLIPPED_ALIAS_KEYS[type] ? `node is t.${type}` : "boolean"; @@ -30,16 +35,16 @@ function assert(type: string, node: any, opts?: any): void { } }\n\n`; - Object.keys(definitions.VISITOR_KEYS).forEach(type => { + Object.keys(VISITOR_KEYS).forEach(type => { output += addAssertHelper(type); }); - Object.keys(definitions.FLIPPED_ALIAS_KEYS).forEach(type => { + Object.keys(FLIPPED_ALIAS_KEYS).forEach(type => { output += addAssertHelper(type); }); - Object.keys(definitions.DEPRECATED_KEYS).forEach(type => { - const newType = definitions.DEPRECATED_KEYS[type]; + Object.keys(DEPRECATED_KEYS).forEach(type => { + const newType = DEPRECATED_KEYS[type]; output += `export function assert${type}(node: any, opts: any): void { console.trace("The node type ${type} has been renamed to ${newType}"); assert("${type}", node, opts); diff --git a/packages/babel-types/scripts/generators/builders.js b/packages/babel-types/scripts/generators/builders.js index 46566f58c4c6..9e2bc0e7aea6 100644 --- a/packages/babel-types/scripts/generators/builders.js +++ b/packages/babel-types/scripts/generators/builders.js @@ -1,5 +1,9 @@ -import * as t from "../../lib/index.js"; -import * as definitions from "../../lib/definitions/index.js"; +import { + BUILDER_KEYS, + DEPRECATED_KEYS, + NODE_FIELDS, + toBindingIdentifierName, +} from "../../lib/index.js"; import formatBuilderName from "../utils/formatBuilderName.js"; import lowerFirst from "../utils/lowerFirst.js"; import stringifyValidator from "../utils/stringifyValidator.js"; @@ -19,8 +23,8 @@ function isNullable(field) { function sortFieldNames(fields, type) { return fields.sort((fieldA, fieldB) => { - const indexA = t.BUILDER_KEYS[type].indexOf(fieldA); - const indexB = t.BUILDER_KEYS[type].indexOf(fieldB); + const indexA = BUILDER_KEYS[type].indexOf(fieldA); + const indexB = BUILDER_KEYS[type].indexOf(fieldB); if (indexA === indexB) return fieldA < fieldB ? -1 : 1; if (indexA === -1) return 1; if (indexB === -1) return -1; @@ -29,9 +33,9 @@ function sortFieldNames(fields, type) { } function generateBuilderArgs(type) { - const fields = t.NODE_FIELDS[type]; - const fieldNames = sortFieldNames(Object.keys(t.NODE_FIELDS[type]), type); - const builderNames = t.BUILDER_KEYS[type]; + const fields = NODE_FIELDS[type]; + const fieldNames = sortFieldNames(Object.keys(NODE_FIELDS[type]), type); + const builderNames = BUILDER_KEYS[type]; const args = []; @@ -51,9 +55,9 @@ function generateBuilderArgs(type) { } if (builderNames.includes(fieldName)) { - const field = definitions.NODE_FIELDS[type][fieldName]; + const field = NODE_FIELDS[type][fieldName]; const def = JSON.stringify(field.default); - const bindingIdentifierName = t.toBindingIdentifierName(fieldName); + const bindingIdentifierName = toBindingIdentifierName(fieldName); let arg; if (areAllRemainingFieldsNullable(fieldName, builderNames, fields)) { arg = `${bindingIdentifierName}${ @@ -90,23 +94,20 @@ import type * as t from "../.."; `; const reservedNames = new Set(["super", "import"]); - Object.keys(definitions.BUILDER_KEYS).forEach(type => { + Object.keys(BUILDER_KEYS).forEach(type => { const defArgs = generateBuilderArgs(type); const formatedBuilderName = formatBuilderName(type); const formatedBuilderNameLocal = reservedNames.has(formatedBuilderName) ? `_${formatedBuilderName}` : formatedBuilderName; - const fieldNames = sortFieldNames( - Object.keys(definitions.NODE_FIELDS[type]), - type - ); - const builderNames = definitions.BUILDER_KEYS[type]; + const fieldNames = sortFieldNames(Object.keys(NODE_FIELDS[type]), type); + const builderNames = BUILDER_KEYS[type]; const objectFields = [["type", JSON.stringify(type)]]; fieldNames.forEach(fieldName => { - const field = definitions.NODE_FIELDS[type][fieldName]; + const field = NODE_FIELDS[type][fieldName]; if (builderNames.includes(fieldName)) { - const bindingIdentifierName = t.toBindingIdentifierName(fieldName); + const bindingIdentifierName = toBindingIdentifierName(fieldName); objectFields.push([fieldName, bindingIdentifierName]); } else if (!field.optional) { const def = JSON.stringify(field.default); @@ -143,14 +144,14 @@ import type * as t from "../.."; } }); - Object.keys(definitions.DEPRECATED_KEYS).forEach(type => { - const newType = definitions.DEPRECATED_KEYS[type]; + Object.keys(DEPRECATED_KEYS).forEach(type => { + const newType = DEPRECATED_KEYS[type]; const formatedBuilderName = formatBuilderName(type); const formatedNewBuilderName = formatBuilderName(newType); output += `/** @deprecated */ function ${type}(${generateBuilderArgs(newType).join(", ")}) { console.trace("The node type ${type} has been renamed to ${newType}"); - return ${formatedNewBuilderName}(${t.BUILDER_KEYS[newType].join(", ")}); + return ${formatedNewBuilderName}(${BUILDER_KEYS[newType].join(", ")}); } export { ${type} as ${formatedBuilderName} };\n`; // This is needed for backwards compatibility. @@ -177,12 +178,12 @@ function generateUppercaseBuilders() { export {\n`; - Object.keys(definitions.BUILDER_KEYS).forEach(type => { + Object.keys(BUILDER_KEYS).forEach(type => { const formatedBuilderName = formatBuilderName(type); output += ` ${formatedBuilderName} as ${type},\n`; }); - Object.keys(definitions.DEPRECATED_KEYS).forEach(type => { + Object.keys(DEPRECATED_KEYS).forEach(type => { const formatedBuilderName = formatBuilderName(type); output += ` ${formatedBuilderName} as ${type},\n`; }); diff --git a/packages/babel-types/scripts/generators/constants.js b/packages/babel-types/scripts/generators/constants.js index 65b7a905d77e..afa9009d695f 100644 --- a/packages/babel-types/scripts/generators/constants.js +++ b/packages/babel-types/scripts/generators/constants.js @@ -1,4 +1,4 @@ -import * as definitions from "../../lib/definitions/index.js"; +import { FLIPPED_ALIAS_KEYS } from "../../lib/index.js"; export default function generateConstants() { let output = `/* @@ -7,7 +7,7 @@ export default function generateConstants() { */ import { FLIPPED_ALIAS_KEYS } from "../../definitions";\n\n`; - Object.keys(definitions.FLIPPED_ALIAS_KEYS).forEach(type => { + Object.keys(FLIPPED_ALIAS_KEYS).forEach(type => { output += `export const ${type.toUpperCase()}_TYPES = FLIPPED_ALIAS_KEYS["${type}"];\n`; }); diff --git a/packages/babel-types/scripts/generators/validators.js b/packages/babel-types/scripts/generators/validators.js index 85c8b4906c8d..f7ac23a51830 100644 --- a/packages/babel-types/scripts/generators/validators.js +++ b/packages/babel-types/scripts/generators/validators.js @@ -1,4 +1,11 @@ -import * as definitions from "../../lib/definitions/index.js"; +import { + DEPRECATED_KEYS, + FLIPPED_ALIAS_KEYS, + NODE_FIELDS, + PLACEHOLDERS, + PLACEHOLDERS_FLIPPED_ALIAS, + VISITOR_KEYS, +} from "../../lib/index.js"; const has = Function.call.bind(Object.prototype.hasOwnProperty); @@ -17,14 +24,11 @@ function addIsHelper(type, aliasKeys, deprecated) { let placeholderSource = ""; const placeholderTypes = []; - if ( - definitions.PLACEHOLDERS.includes(type) && - has(definitions.FLIPPED_ALIAS_KEYS, type) - ) { + if (PLACEHOLDERS.includes(type) && has(FLIPPED_ALIAS_KEYS, type)) { placeholderTypes.push(type); } - if (has(definitions.PLACEHOLDERS_FLIPPED_ALIAS, type)) { - placeholderTypes.push(...definitions.PLACEHOLDERS_FLIPPED_ALIAS[type]); + if (has(PLACEHOLDERS_FLIPPED_ALIAS, type)) { + placeholderTypes.push(...PLACEHOLDERS_FLIPPED_ALIAS[type]); } if (placeholderTypes.length > 0) { placeholderSource = @@ -37,7 +41,7 @@ function addIsHelper(type, aliasKeys, deprecated) { } const result = - definitions.NODE_FIELDS[type] || definitions.FLIPPED_ALIAS_KEYS[type] + NODE_FIELDS[type] || FLIPPED_ALIAS_KEYS[type] ? `node is t.${type}` : "boolean"; @@ -69,16 +73,16 @@ export default function generateValidators() { import shallowEqual from "../../utils/shallowEqual"; import type * as t from "../..";\n\n`; - Object.keys(definitions.VISITOR_KEYS).forEach(type => { + Object.keys(VISITOR_KEYS).forEach(type => { output += addIsHelper(type); }); - Object.keys(definitions.FLIPPED_ALIAS_KEYS).forEach(type => { - output += addIsHelper(type, definitions.FLIPPED_ALIAS_KEYS[type]); + Object.keys(FLIPPED_ALIAS_KEYS).forEach(type => { + output += addIsHelper(type, FLIPPED_ALIAS_KEYS[type]); }); - Object.keys(definitions.DEPRECATED_KEYS).forEach(type => { - const newType = definitions.DEPRECATED_KEYS[type]; + Object.keys(DEPRECATED_KEYS).forEach(type => { + const newType = DEPRECATED_KEYS[type]; const deprecated = `console.trace("The node type ${type} has been renamed to ${newType}");`; output += addIsHelper(type, null, deprecated); });