"use strict"; const path = require("path"); function normalize(src) { return src.replace(/\//, path.sep); } module.exports = function (api) { const env = api.env(); const includeCoverage = process.env.BABEL_COVERAGE === "true"; const envOptsNoTargets = { loose: true, shippedProposals: true, modules: false, }; const envOpts = Object.assign({}, envOptsNoTargets); let convertESM = true; let ignoreLib = true; let includeRegeneratorRuntime = false; let polyfillRequireResolve = false; let transformRuntimeOptions; const nodeVersion = "6.9"; // The vast majority of our src files are modules, but we use // unambiguous to keep things simple until we get around to renaming // the modules to be more easily distinguished from CommonJS const unambiguousSources = [ "packages/*/src", "packages/*/test", "codemods/*/src", "codemods/*/test", "eslint/*/src", "eslint/*/test", ]; switch (env) { // Configs used during bundling builds. case "standalone": includeRegeneratorRuntime = true; unambiguousSources.push("packages/babel-runtime/regenerator"); // fall through case "rollup": convertESM = false; ignoreLib = false; // rollup-commonjs will converts node_modules to ESM unambiguousSources.push( "**/node_modules", "packages/babel-preset-env/data", "packages/babel-compat-data" ); if (env === "rollup") envOpts.targets = { node: nodeVersion }; polyfillRequireResolve = true; break; case "test-legacy": // In test-legacy environment, we build babel on latest node but test on minimum supported legacy versions case "production": // Config during builds before publish. envOpts.targets = { node: nodeVersion, }; polyfillRequireResolve = true; break; case "development": envOpts.debug = true; envOpts.targets = { node: "current", }; break; case "test": envOpts.targets = { node: "current", }; break; } if (process.env.STRIP_BABEL_8_FLAG && bool(process.env.BABEL_8_BREAKING)) { // Never apply polyfills when compiling for Babel 8 polyfillRequireResolve = false; } if (includeRegeneratorRuntime) { const babelRuntimePkgPath = require.resolve("@babel/runtime/package.json"); transformRuntimeOptions = { helpers: false, // Helpers are handled by rollup when needed regenerator: true, version: require(babelRuntimePkgPath).version, }; } const config = { // Our dependencies are all standard CommonJS, along with all sorts of // other random files in Babel's codebase, so we use script as the default, // and then mark actual modules as modules farther down. sourceType: "script", comments: false, ignore: [ // These may not be strictly necessary with the newly-limited scope of // babelrc searching, but including them for now because we had them // in our .babelignore before. "packages/*/test/fixtures", ignoreLib ? "packages/*/lib" : null, "packages/babel-standalone/babel.js", ] .filter(Boolean) .map(normalize), presets: [ [ "@babel/preset-typescript", { onlyRemoveTypeImports: true, allowDeclareFields: true }, ], ["@babel/env", envOpts], ["@babel/preset-flow", { allowDeclareFields: true }], ], plugins: [ [ "@babel/proposal-object-rest-spread", { useBuiltIns: true, loose: true }, ], convertESM ? "@babel/proposal-export-namespace-from" : null, convertESM ? "@babel/transform-modules-commonjs" : null, process.env.STRIP_BABEL_8_FLAG && [ pluginToggleBabel8Breaking, { breaking: bool(process.env.BABEL_8_BREAKING) }, ], polyfillRequireResolve && pluginPolyfillRequireResolve, ].filter(Boolean), overrides: [ { test: [ "packages/babel-parser", "packages/babel-helper-validator-identifier", ].map(normalize), plugins: [ "babel-plugin-transform-charcodes", ["@babel/transform-for-of", { assumeArray: true }], ], }, { test: ["./packages/babel-cli", "./packages/babel-core"].map(normalize), plugins: [ // Explicitly use the lazy version of CommonJS modules. convertESM ? ["@babel/transform-modules-commonjs", { lazy: true }] : null, ].filter(Boolean), }, { test: normalize("./packages/babel-polyfill"), presets: [["@babel/env", envOptsNoTargets]], }, { test: unambiguousSources.map(normalize), sourceType: "unambiguous", }, includeRegeneratorRuntime && { exclude: /regenerator-runtime/, plugins: [["@babel/transform-runtime", transformRuntimeOptions]], }, ].filter(Boolean), }; // we need to do this as long as we do not test everything from source if (includeCoverage) { config.auxiliaryCommentBefore = "istanbul ignore next"; config.plugins.push("babel-plugin-istanbul"); } return config; }; // env vars from the cli are always strings, so !!ENV_VAR returns true for "false" function bool(value) { return value && value !== "false" && value !== "0"; } // TODO(Babel 8) This polyfill is only needed for Node.js 6 and 8 function pluginPolyfillRequireResolve({ template, types: t }) { return { visitor: { MemberExpression(path) { if (!path.matchesPattern("require.resolve")) return; if (!t.isCallExpression(path.parent, { callee: path.node })) return; const args = path.parent.arguments; if (args.length < 2) return; if ( !t.isObjectExpression(args[1]) || args[1].properties.length !== 1 || !t.isIdentifier(args[1].properties[0].key, { name: "paths" }) || !t.isArrayExpression(args[1].properties[0].value) || args[1].properties[0].value.elements.length !== 1 ) { throw path.parentPath.buildCodeFrameError( "This 'require.resolve' usage is not supported by the inline polyfill." ); } // require.resolve's paths option has been introduced in Node.js 8.9 // https://nodejs.org/api/modules.html#modules_require_resolve_request_options path.replaceWith(template.ast` parseFloat(process.versions.node) >= 8.9 ? require.resolve : (/* request */ r, { paths: [/* base */ b] }, M = require("module")) => { let /* filename */ f = M._findPath(r, M._nodeModulePaths(b).concat(b)); if (f) return f; f = new Error(\`Cannot resolve module '\${r}'\`); f.code = "MODULE_NOT_FOUND"; throw f; } `); }, }, }; } function pluginToggleBabel8Breaking({ types: t }, { breaking }) { return { visitor: { "IfStatement|ConditionalExpression"(path) { let test = path.get("test"); let keepConsequent = breaking; if (test.isUnaryExpression({ operator: "!" })) { test = test.get("argument"); keepConsequent = !keepConsequent; } if (!test.matchesPattern("process.env.BABEL_8_BREAKING")) return; path.replaceWith( keepConsequent ? path.node.consequent : path.node.alternate || t.emptyStatement() ); }, MemberExpression(path) { if (path.matchesPattern("process.env.BABEL_8_BREAKING")) { throw path.buildCodeFrameError("This check could not be stripped."); } }, }, }; }