UNPKG

@babel/core

Version:
1,423 lines (1,407 loc) 99.6 kB
import * as helpers from '@babel/helpers'; import traverse, { NodePath } from '@babel/traverse'; import { codeFrameColumns } from '@babel/code-frame'; import * as _t from '@babel/types'; import semver from 'semver'; import generate from '@babel/generator'; import template from '@babel/template'; import * as resolvers from '#config/files'; import { loadPlugin, loadPreset, loadConfig as loadConfig$1, findRootConfig, findPackageData, findRelativeConfig, resolveShowConfigPath, findConfigUpwards, ROOT_CONFIG_FILENAMES } from '#config/files'; import { parse as parse$1, tokTypes } from '@babel/parser'; import gensync from 'gensync'; import { isAsync, waitFor, makeWeakCacheSync, makeStrongCacheSync, makeStrongCache, assertSimpleType, mergeOptions, makeWeakCache, maybeAsync, isThenable, forwardAsync } from './caching-shared.js'; import path from 'node:path'; import convertSourceMap from 'convert-source-map'; import readInputSourceMapFile from '#transformation/read-input-source-map-file'; import { expectedError, injectVirtualStackFrame, endHiddenCallStack, beginHiddenCallStack } from './errors/rewrite-stack-trace.js'; import { transformFile as transformFile$1, transformFileAsync, transformFileSync } from '#transform-file'; import { resolveBrowserslistConfigFile } from './config/resolve-targets.js'; import { createDebug } from 'obug'; import { isBrowsersQueryValid, TargetNames } from '@babel/helper-compilation-targets'; import { resolveTargets } from '#config/resolve-targets'; const context = /*#__PURE__*/Object.defineProperty({ __proto__: null, get DEFAULT_EXTENSIONS () { return DEFAULT_EXTENSIONS; }, get File () { return File; }, get buildExternalHelpers () { return buildExternalHelpers; }, get createConfigItem () { return createConfigItem; }, get createConfigItemAsync () { return createConfigItemAsync; }, get createConfigItemSync () { return createConfigItemSync; }, get getEnv () { return getEnv; }, get loadOptions () { return loadOptions; }, get loadOptionsAsync () { return loadOptionsAsync; }, get loadOptionsSync () { return loadOptionsSync; }, get loadPartialConfig () { return loadPartialConfig; }, get loadPartialConfigAsync () { return loadPartialConfigAsync; }, get loadPartialConfigSync () { return loadPartialConfigSync; }, get parse () { return parse; }, get parseAsync () { return parseAsync; }, get parseSync () { return parseSync; }, get resolvePlugin () { return resolvePlugin; }, get resolvePreset () { return resolvePreset; }, get template () { return template; }, get tokTypes () { return tokTypes; }, get transform () { return transform; }, get transformAsync () { return transformAsync; }, get transformFile () { return transformFile$1; }, get transformFileAsync () { return transformFileAsync; }, get transformFileSync () { return transformFileSync; }, get transformFromAst () { return transformFromAst; }, get transformFromAstAsync () { return transformFromAstAsync; }, get transformFromAstSync () { return transformFromAstSync; }, get transformSync () { return transformSync; }, get traverse () { return traverse; }, get types () { return _t; }, get version () { return version; } }, Symbol.toStringTag, { value: 'Module' }); const { cloneNode: cloneNode$1, interpreterDirective, traverseFast } = _t; class File { _map = new Map(); opts; declarations = {}; path; ast; scope; metadata = {}; code = ""; inputMap; hub = { file: this, getCode: () => this.code, getScope: () => this.scope, addHelper: this.addHelper.bind(this), buildError: this.buildCodeFrameError.bind(this) }; constructor(options, { code, ast, inputMap }) { this.opts = options; this.code = code; this.ast = ast; this.inputMap = inputMap; this.path = NodePath.get({ hub: this.hub, parentPath: null, parent: this.ast, container: this.ast, key: "program" }).setContext(); this.scope = this.path.scope; } get shebang() { const { interpreter } = this.path.node; return interpreter ? interpreter.value : ""; } set shebang(value) { if (value) { this.path.get("interpreter").replaceWith(interpreterDirective(value)); } else { this.path.get("interpreter").remove(); } } set(key, val) { this._map.set(key, val); } get(key) { return this._map.get(key); } has(key) { return this._map.has(key); } availableHelper(name, versionRange) { if (helpers.isInternal(name)) return false; let minVersion; try { minVersion = helpers.minVersion(name); } catch (err) { if (err.code !== "BABEL_HELPER_UNKNOWN") throw err; return false; } if (typeof versionRange !== "string") return true; if (semver.valid(versionRange)) versionRange = `^${versionRange}`; return !semver.intersects(`<${minVersion}`, versionRange) && !semver.intersects(`>=9.0.0`, versionRange); } addHelper(name) { if (helpers.isInternal(name)) { throw new Error("Cannot use internal helper " + name); } return this._addHelper(name); } _addHelper(name) { const declar = this.declarations[name]; if (declar) return cloneNode$1(declar); const generator = this.get("helperGenerator"); if (generator) { const res = generator(name); if (res) return res; } helpers.minVersion(name); const uid = this.declarations[name] = this.scope.generateUidIdentifier(name); const dependencies = {}; for (const dep of helpers.getDependencies(name)) { dependencies[dep] = this._addHelper(dep); } const { nodes, globals } = helpers.get(name, dep => dependencies[dep], uid.name, Object.keys(this.scope.getAllBindings())); globals.forEach(name => { if (this.path.scope.hasBinding(name, true)) { this.path.scope.rename(name); } }); nodes.forEach(node => { node._compact = true; }); const added = this.path.unshiftContainer("body", nodes); for (const path of added) { if (path.isVariableDeclaration()) this.scope.registerDeclaration(path); } return uid; } buildCodeFrameError(node, msg, _Error = SyntaxError) { let loc = node?.loc; if (!loc && node) { traverseFast(node, function (node) { if (node.loc) { loc = node.loc; return traverseFast.stop; } }); let txt = "This is an error on an internal node. Probably an internal error."; if (loc) txt += " Location has been estimated."; msg += ` (${txt})`; } if (loc) { const { highlightCode = true } = this.opts; msg += "\n" + codeFrameColumns(this.code, { start: { line: loc.start.line, column: loc.start.column }, end: loc.end && loc.start.line === loc.end.line ? { line: loc.end.line, column: loc.end.column } : undefined }, { highlightCode }); } return new _Error(msg); } } const { arrayExpression, assignmentExpression, binaryExpression, blockStatement, callExpression, cloneNode, conditionalExpression, exportNamedDeclaration, exportSpecifier, expressionStatement, functionExpression, identifier, memberExpression, objectExpression, program, stringLiteral, unaryExpression, variableDeclaration, variableDeclarator } = _t; const buildUmdWrapper = replacements => template.statement` (function (root, factory) { if (typeof define === "function" && define.amd) { define(AMD_ARGUMENTS, factory); } else if (typeof exports === "object") { factory(COMMON_ARGUMENTS); } else { factory(BROWSER_ARGUMENTS); } })(UMD_ROOT, function (FACTORY_PARAMETERS) { FACTORY_BODY }); `(replacements); function buildGlobal(allowlist) { const namespace = identifier("babelHelpers"); const body = []; const container = functionExpression(null, [identifier("global")], blockStatement(body)); const tree = program([expressionStatement(callExpression(container, [conditionalExpression(binaryExpression("===", unaryExpression("typeof", identifier("global")), stringLiteral("undefined")), identifier("self"), identifier("global"))]))]); body.push(variableDeclaration("var", [variableDeclarator(namespace, assignmentExpression("=", memberExpression(identifier("global"), namespace), objectExpression([])))])); buildHelpers(body, namespace, allowlist); return tree; } function buildModule(allowlist) { const body = []; const refs = buildHelpers(body, null, allowlist); body.unshift(exportNamedDeclaration(null, Object.keys(refs).map(name => { return exportSpecifier(cloneNode(refs[name]), identifier(name)); }))); return program(body, [], "module"); } function buildUmd(allowlist) { const namespace = identifier("babelHelpers"); const body = []; body.push(variableDeclaration("var", [variableDeclarator(namespace, identifier("global"))])); buildHelpers(body, namespace, allowlist); return program([buildUmdWrapper({ FACTORY_PARAMETERS: identifier("global"), BROWSER_ARGUMENTS: assignmentExpression("=", memberExpression(identifier("root"), namespace), objectExpression([])), COMMON_ARGUMENTS: identifier("exports"), AMD_ARGUMENTS: arrayExpression([stringLiteral("exports")]), FACTORY_BODY: body, UMD_ROOT: identifier("this") })]); } function buildVar(allowlist) { const namespace = identifier("babelHelpers"); const body = []; body.push(variableDeclaration("var", [variableDeclarator(namespace, objectExpression([]))])); const tree = program(body); buildHelpers(body, namespace, allowlist); body.push(expressionStatement(namespace)); return tree; } function buildHelpers(body, namespace, allowlist) { const getHelperReference = name => { return namespace ? memberExpression(namespace, identifier(name)) : identifier(`_${name}`); }; const refs = {}; helpers.list.forEach(function (name) { if (allowlist && !allowlist.includes(name)) return; const ref = refs[name] = getHelperReference(name); const { nodes } = helpers.get(name, getHelperReference, namespace ? undefined : `_${name}`, [], namespace ? (ast, exportName, mapExportBindingAssignments) => { mapExportBindingAssignments(node => assignmentExpression("=", ref, node)); ast.body.push(expressionStatement(assignmentExpression("=", ref, identifier(exportName)))); } : undefined); body.push(...nodes); }); return refs; } function buildExternalHelpers (allowlist, outputType = "global") { let tree; const build = { global: buildGlobal, module: buildModule, umd: buildUmd, var: buildVar }[outputType]; if (build) { tree = build(allowlist); } else { throw new Error(`Unsupported output type ${outputType}`); } return generate(tree).code; } function getEnv(defaultValue = "development") { return process.env.BABEL_ENV || process.env.NODE_ENV || defaultValue; } function finalize(deepArr) { return Object.freeze(deepArr); } function flattenToSet(arr) { const result = new Set(); const stack = [arr]; while (stack.length > 0) { for (const el of stack.pop()) { if (Array.isArray(el)) stack.push(el);else result.add(el); } } return result; } class Plugin { key; manipulateOptions; post; pre; visitor; parserOverride; generatorOverride; options; externalDependencies; constructor(plugin, options, key, externalDependencies = finalize([])) { this.key = plugin.name || key; this.manipulateOptions = plugin.manipulateOptions; this.post = plugin.post; this.pre = plugin.pre; this.visitor = plugin.visitor || {}; this.parserOverride = plugin.parserOverride; this.generatorOverride = plugin.generatorOverride; this.options = options; this.externalDependencies = externalDependencies; } } function once(fn) { let result; let resultP; let promiseReferenced = false; return function* () { if (!result) { if (resultP) { promiseReferenced = true; return yield* waitFor(resultP); } if (!(yield* isAsync())) { try { result = { ok: true, value: yield* fn() }; } catch (error) { result = { ok: false, value: error }; } } else { let resolve, reject; resultP = new Promise((res, rej) => { resolve = res; reject = rej; }); try { result = { ok: true, value: yield* fn() }; resultP = null; if (promiseReferenced) resolve(result.value); } catch (error) { result = { ok: false, value: error }; resultP = null; if (promiseReferenced) reject(error); } } } if (result.ok) return result.value;else throw result.value; }; } function isEqualDescriptor(a, b) { return a.name === b.name && a.value === b.value && a.options === b.options && a.dirname === b.dirname && a.alias === b.alias && a.ownPass === b.ownPass && a.file?.request === b.file?.request && a.file?.resolved === b.file?.resolved; } function* handlerOf(value) { return value; } function optionsWithResolvedBrowserslistConfigFile(options, dirname) { if (typeof options.browserslistConfigFile === "string") { options.browserslistConfigFile = resolveBrowserslistConfigFile(options.browserslistConfigFile, dirname); } return options; } function createCachedDescriptors(dirname, options, alias) { const { plugins, presets, passPerPreset } = options; return { options: optionsWithResolvedBrowserslistConfigFile(options, dirname), plugins: plugins ? () => createCachedPluginDescriptors(plugins, dirname)(alias) : () => handlerOf([]), presets: presets ? () => createCachedPresetDescriptors(presets, dirname)(alias)(!!passPerPreset) : () => handlerOf([]) }; } function createUncachedDescriptors(dirname, options, alias) { return { options: optionsWithResolvedBrowserslistConfigFile(options, dirname), plugins: once(() => createPluginDescriptors(options.plugins || [], dirname, alias)), presets: once(() => createPresetDescriptors(options.presets || [], dirname, alias, !!options.passPerPreset)) }; } const PRESET_DESCRIPTOR_CACHE = new WeakMap(); const createCachedPresetDescriptors = makeWeakCacheSync((items, cache) => { const dirname = cache.using(dir => dir); return makeStrongCacheSync(alias => makeStrongCache(function* (passPerPreset) { const descriptors = yield* createPresetDescriptors(items, dirname, alias, passPerPreset); return descriptors.map(desc => loadCachedDescriptor(PRESET_DESCRIPTOR_CACHE, desc)); })); }); const PLUGIN_DESCRIPTOR_CACHE = new WeakMap(); const createCachedPluginDescriptors = makeWeakCacheSync((items, cache) => { const dirname = cache.using(dir => dir); return makeStrongCache(function* (alias) { const descriptors = yield* createPluginDescriptors(items, dirname, alias); return descriptors.map(desc => loadCachedDescriptor(PLUGIN_DESCRIPTOR_CACHE, desc)); }); }); const DEFAULT_OPTIONS = {}; function loadCachedDescriptor(cache, desc) { const { value, options = DEFAULT_OPTIONS } = desc; if (options === false) return desc; let cacheByOptions = cache.get(value); if (!cacheByOptions) { cacheByOptions = new WeakMap(); cache.set(value, cacheByOptions); } let possibilities = cacheByOptions.get(options); if (!possibilities) { possibilities = []; cacheByOptions.set(options, possibilities); } if (!possibilities.includes(desc)) { const matches = possibilities.filter(possibility => isEqualDescriptor(possibility, desc)); if (matches.length > 0) { return matches[0]; } possibilities.push(desc); } return desc; } function* createPresetDescriptors(items, dirname, alias, passPerPreset) { return yield* createDescriptors("preset", items, dirname, alias, passPerPreset); } function* createPluginDescriptors(items, dirname, alias) { return yield* createDescriptors("plugin", items, dirname, alias); } function* createDescriptors(type, items, dirname, alias, ownPass) { const descriptors = yield* gensync.all(items.map((item, index) => createDescriptor(item, dirname, { type, alias: `${alias}$${index}`, ownPass: !!ownPass }))); assertNoDuplicates(descriptors); return descriptors; } function* createDescriptor(pair, dirname, { type, alias, ownPass }) { const desc = getItemDescriptor(pair); if (desc) { return desc; } let name; let options; let value = pair; if (Array.isArray(value)) { if (value.length === 3) { [value, options, name] = value; } else { [value, options] = value; } } let file = undefined; let filepath = null; if (typeof value === "string") { if (typeof type !== "string") { throw new Error("To resolve a string-based item, the type of item must be given"); } const resolver = type === "plugin" ? loadPlugin : loadPreset; const request = value; ({ filepath, value } = yield* resolver(value, dirname)); file = { request, resolved: filepath }; } if (!value) { throw new Error(`Unexpected falsy value: ${String(value)}`); } if (typeof value === "object" && value.__esModule) { if (value.default) { value = value.default; } else { throw new Error("Must export a default export when using ES6 modules."); } } if (typeof value !== "object" && typeof value !== "function") { throw new Error(`Unsupported format: ${typeof value}. Expected an object or a function.`); } if (filepath !== null && typeof value === "object" && value) { throw new Error(`Plugin/Preset files are not allowed to export objects, only functions. In ${filepath}`); } return { name, alias: filepath || alias, value, options, dirname, ownPass, file }; } function assertNoDuplicates(items) { const map = new Map(); for (const item of items) { if (typeof item.value !== "function") continue; let nameMap = map.get(item.value); if (!nameMap) { nameMap = new Set(); map.set(item.value, nameMap); } if (nameMap.has(item.name)) { const conflicts = items.filter(i => i.value === item.value); throw new Error([`Duplicate plugin/preset detected.`, `If you'd like to use two separate instances of a plugin,`, `they need separate names, e.g.`, ``, ` plugins: [`, ` ['some-plugin', {}],`, ` ['some-plugin', {}, 'some unique name'],`, ` ]`, ``, `Duplicates detected are:`, `${JSON.stringify(conflicts, null, 2)}`].join("\n")); } nameMap.add(item.name); } } function createItemFromDescriptor(desc) { return new ConfigItem(desc); } function* createConfigItem$1(value, { dirname = ".", type } = {}) { const descriptor = yield* createDescriptor(value, path.resolve(dirname), { type, alias: "programmatic item" }); return createItemFromDescriptor(descriptor); } const CONFIG_ITEM_BRAND = Symbol.for("@babel/core@8 - ConfigItem"); function getItemDescriptor(item) { if (item?.[CONFIG_ITEM_BRAND]) { return item._descriptor; } return undefined; } class ConfigItem { _descriptor; [CONFIG_ITEM_BRAND] = true; value; options; dirname; name; file; constructor(descriptor) { this._descriptor = descriptor; Object.defineProperty(this, "_descriptor", { enumerable: false }); Object.defineProperty(this, CONFIG_ITEM_BRAND, { enumerable: false }); this.value = this._descriptor.value; this.options = this._descriptor.options; this.dirname = this._descriptor.dirname; this.name = this._descriptor.name; this.file = this._descriptor.file ? { request: this._descriptor.file.request, resolved: this._descriptor.file.resolved } : undefined; Object.freeze(this); } } Object.freeze(ConfigItem.prototype); const removed = { auxiliaryComment: { message: "Use `auxiliaryCommentBefore` or `auxiliaryCommentAfter`" }, blacklist: { message: "Put the specific transforms you want in the `plugins` option" }, breakConfig: { message: "This is not a necessary option in Babel 6" }, experimental: { message: "Put the specific transforms you want in the `plugins` option" }, externalHelpers: { message: "Use the `external-helpers` plugin instead. " + "Check out http://babeljs.io/docs/plugins/external-helpers/" }, extra: { message: "" }, jsxPragma: { message: "use the `pragma` option in the `react-jsx` plugin. " + "Check out http://babeljs.io/docs/plugins/transform-react-jsx/" }, loose: { message: "Specify the `loose` option for the relevant plugin you are using " + "or use a preset that sets the option." }, metadataUsedHelpers: { message: "Not required anymore as this is enabled by default" }, modules: { message: "Use the corresponding module transform plugin in the `plugins` option. " + "Check out http://babeljs.io/docs/plugins/#modules" }, nonStandard: { message: "Use the `react-jsx` and `flow-strip-types` plugins to support JSX and Flow. " + "Also check out the react preset http://babeljs.io/docs/plugins/preset-react/" }, optional: { message: "Put the specific transforms you want in the `plugins` option" }, sourceMapName: { message: "The `sourceMapName` option has been removed because it makes more sense for the " + "tooling that calls Babel to assign `map.file` themselves." }, stage: { message: "Check out the corresponding stage-x presets http://babeljs.io/docs/plugins/#presets" }, whitelist: { message: "Put the specific transforms you want in the `plugins` option" }, resolveModuleSource: { version: 6, message: "Use `babel-plugin-module-resolver@3`'s 'resolvePath' options" }, metadata: { version: 6, message: "Generated plugin metadata is always included in the output result" }, sourceMapTarget: { version: 6, message: "The `sourceMapTarget` option has been removed because it makes more sense for the tooling " + "that calls Babel to assign `map.file` themselves." } }; function msg(loc) { switch (loc.type) { case "root": return ``; case "env": return `${msg(loc.parent)}.env["${loc.name}"]`; case "overrides": return `${msg(loc.parent)}.overrides[${loc.index}]`; case "option": return `${msg(loc.parent)}.${loc.name}`; case "access": return `${msg(loc.parent)}[${JSON.stringify(loc.name)}]`; default: throw new Error(`Assertion failure: Unknown type ${loc.type}`); } } function access(loc, name) { return { type: "access", name, parent: loc }; } function assertRootMode(loc, value) { if (value !== undefined && value !== "root" && value !== "upward" && value !== "upward-optional") { throw new Error(`${msg(loc)} must be a "root", "upward", "upward-optional" or undefined`); } return value; } function assertSourceMaps(loc, value) { if (value !== undefined && typeof value !== "boolean" && value !== "inline" && value !== "both") { throw new Error(`${msg(loc)} must be a boolean, "inline", "both", or undefined`); } return value; } function assertCompact(loc, value) { if (value !== undefined && typeof value !== "boolean" && value !== "auto") { throw new Error(`${msg(loc)} must be a boolean, "auto", or undefined`); } return value; } function assertSourceType(loc, value) { if (value !== undefined && value !== "module" && value !== "commonjs" && value !== "script" && value !== "unambiguous") { throw new Error(`${msg(loc)} must be "module", "commonjs", "script", "unambiguous", or undefined`); } return value; } function assertCallerMetadata(loc, value) { const obj = assertObject(loc, value); if (obj) { if (typeof obj.name !== "string") { throw new Error(`${msg(loc)} set but does not contain "name" property string`); } for (const prop of Object.keys(obj)) { const propLoc = access(loc, prop); const value = obj[prop]; if (value != null && typeof value !== "boolean" && typeof value !== "string" && typeof value !== "number") { throw new Error(`${msg(propLoc)} must be null, undefined, a boolean, a string, or a number.`); } } } return value; } function assertInputSourceMap(loc, value) { if (value !== undefined && typeof value !== "boolean" && (typeof value !== "object" || !value)) { throw new Error(`${msg(loc)} must be a boolean, object, or undefined`); } return value; } function assertString(loc, value) { if (value !== undefined && typeof value !== "string") { throw new Error(`${msg(loc)} must be a string, or undefined`); } return value; } function assertFunction(loc, value) { if (value !== undefined && typeof value !== "function") { throw new Error(`${msg(loc)} must be a function, or undefined`); } return value; } function assertBoolean(loc, value) { if (value !== undefined && typeof value !== "boolean") { throw new Error(`${msg(loc)} must be a boolean, or undefined`); } return value; } function assertObject(loc, value) { if (value !== undefined && (typeof value !== "object" || Array.isArray(value) || !value)) { throw new Error(`${msg(loc)} must be an object, or undefined`); } return value; } function assertArray(loc, value) { if (value != null && !Array.isArray(value)) { throw new Error(`${msg(loc)} must be an array, or undefined`); } return value; } function assertIgnoreList(loc, value) { const arr = assertArray(loc, value); arr?.forEach((item, i) => assertIgnoreItem(access(loc, i), item)); return arr; } function assertIgnoreItem(loc, value) { if (typeof value !== "string" && typeof value !== "function" && !(value instanceof RegExp)) { throw new Error(`${msg(loc)} must be an array of string/Function/RegExp values, or undefined`); } return value; } function assertConfigApplicableTest(loc, value) { if (value === undefined) { return value; } if (Array.isArray(value)) { value.forEach((item, i) => { if (!checkValidTest(item)) { throw new Error(`${msg(access(loc, i))} must be a string/Function/RegExp.`); } }); } else if (!checkValidTest(value)) { throw new Error(`${msg(loc)} must be a string/Function/RegExp, or an array of those`); } return value; } function checkValidTest(value) { return typeof value === "string" || typeof value === "function" || value instanceof RegExp; } function assertConfigFileSearch(loc, value) { if (value !== undefined && typeof value !== "boolean" && typeof value !== "string") { throw new Error(`${msg(loc)} must be a undefined, a boolean, a string, ` + `got ${JSON.stringify(value)}`); } return value; } function assertBabelrcSearch(loc, value) { if (value === undefined || typeof value === "boolean") { return value; } if (Array.isArray(value)) { value.forEach((item, i) => { if (!checkValidTest(item)) { throw new Error(`${msg(access(loc, i))} must be a string/Function/RegExp.`); } }); } else if (!checkValidTest(value)) { throw new Error(`${msg(loc)} must be a undefined, a boolean, a string/Function/RegExp ` + `or an array of those, got ${JSON.stringify(value)}`); } return value; } function assertPluginList(loc, value) { const arr = assertArray(loc, value); if (arr) { arr.forEach((item, i) => assertPluginItem(access(loc, i), item)); } return arr; } function assertPluginItem(loc, value) { if (Array.isArray(value)) { if (value.length === 0) { throw new Error(`${msg(loc)} must include an object`); } if (value.length > 3) { throw new Error(`${msg(loc)} may only be a two-tuple or three-tuple`); } assertPluginTarget(access(loc, 0), value[0]); if (value.length > 1) { const opts = value[1]; if (opts !== undefined && opts !== false && (typeof opts !== "object" || Array.isArray(opts) || opts === null)) { throw new Error(`${msg(access(loc, 1))} must be an object, false, or undefined`); } } if (value.length === 3) { const name = value[2]; if (name !== undefined && typeof name !== "string") { throw new Error(`${msg(access(loc, 2))} must be a string, or undefined`); } } } else { assertPluginTarget(loc, value); } return value; } function assertPluginTarget(loc, value) { if ((typeof value !== "object" || !value) && typeof value !== "string" && typeof value !== "function") { throw new Error(`${msg(loc)} must be a string, object, function`); } return value; } function assertTargets(loc, value) { if (isBrowsersQueryValid(value)) return value; if (typeof value !== "object" || !value || Array.isArray(value)) { throw new Error(`${msg(loc)} must be a string, an array of strings or an object`); } const browsersLoc = access(loc, "browsers"); const esmodulesLoc = access(loc, "esmodules"); assertBrowsersList(browsersLoc, value.browsers); assertBoolean(esmodulesLoc, value.esmodules); for (const key of Object.keys(value)) { const val = value[key]; const subLoc = access(loc, key); if (key === "esmodules") assertBoolean(subLoc, val);else if (key === "browsers") assertBrowsersList(subLoc, val);else if (!Object.hasOwn(TargetNames, key)) { const validTargets = Object.keys(TargetNames).join(", "); throw new Error(`${msg(subLoc)} is not a valid target. Supported targets are ${validTargets}`); } else assertBrowserVersion(subLoc, val); } return value; } function assertBrowsersList(loc, value) { if (value !== undefined && !isBrowsersQueryValid(value)) { throw new Error(`${msg(loc)} must be undefined, a string or an array of strings`); } } function assertBrowserVersion(loc, value) { if (typeof value === "number" && Math.round(value) === value) return; if (typeof value === "string") return; throw new Error(`${msg(loc)} must be a string or an integer number`); } function assertAssumptions(loc, value) { if (value === undefined) return; if (typeof value !== "object" || value === null) { throw new Error(`${msg(loc)} must be an object or undefined.`); } let root = loc; do { root = root.parent; } while (root.type !== "root"); const inPreset = root.source === "preset"; for (const name of Object.keys(value)) { const subLoc = access(loc, name); if (!assumptionsNames.has(name)) { throw new Error(`${msg(subLoc)} is not a supported assumption.`); } if (typeof value[name] !== "boolean") { throw new Error(`${msg(subLoc)} must be a boolean.`); } if (inPreset && value[name] === false) { throw new Error(`${msg(subLoc)} cannot be set to 'false' inside presets.`); } } return value; } class ConfigError extends Error { constructor(message, filename) { super(message); expectedError(this); if (filename) injectVirtualStackFrame(this, filename); } } const ROOT_VALIDATORS = { cwd: assertString, root: assertString, rootMode: assertRootMode, configFile: assertConfigFileSearch, caller: assertCallerMetadata, filename: assertString, filenameRelative: assertString, code: assertBoolean, ast: assertBoolean, cloneInputAst: assertBoolean, envName: assertString }; const BABELRC_VALIDATORS = { babelrc: assertBoolean, babelrcRoots: assertBabelrcSearch }; const NONPRESET_VALIDATORS = { extends: assertString, ignore: assertIgnoreList, only: assertIgnoreList, targets: assertTargets, browserslistConfigFile: assertConfigFileSearch, browserslistEnv: assertString }; const COMMON_VALIDATORS = { inputSourceMap: assertInputSourceMap, presets: assertPluginList, plugins: assertPluginList, passPerPreset: assertBoolean, assumptions: assertAssumptions, env: assertEnvSet, overrides: assertOverridesList, test: assertConfigApplicableTest, include: assertConfigApplicableTest, exclude: assertConfigApplicableTest, retainLines: assertBoolean, comments: assertBoolean, shouldPrintComment: assertFunction, compact: assertCompact, minified: assertBoolean, auxiliaryCommentBefore: assertString, auxiliaryCommentAfter: assertString, sourceType: assertSourceType, wrapPluginVisitorMethod: assertFunction, highlightCode: assertBoolean, sourceMaps: assertSourceMaps, sourceMap: assertSourceMaps, sourceFileName: assertString, sourceRoot: assertString, parserOpts: assertObject, generatorOpts: assertObject }; const knownAssumptions = ["arrayLikeIsIterable", "constantReexports", "constantSuper", "enumerableModuleMeta", "ignoreFunctionLength", "ignoreToPrimitiveHint", "iterableIsArray", "mutableTemplateObject", "noClassCalls", "noDocumentAll", "noIncompleteNsImportDetection", "noNewArrows", "noUninitializedPrivateFieldAccess", "objectRestNoSymbols", "privateFieldsAsSymbols", "privateFieldsAsProperties", "pureGetters", "setClassMethods", "setComputedProperties", "setPublicClassFields", "setSpreadProperties", "skipForOfIteratorClosing", "superIsCallableConstructor"]; const assumptionsNames = new Set(knownAssumptions); function getSource(loc) { return loc.type === "root" ? loc.source : getSource(loc.parent); } function validate(type, opts, filename) { try { return validateNested({ type: "root", source: type }, opts); } catch (error) { const configError = new ConfigError(error.message, filename); if (error.code) configError.code = error.code; throw configError; } } function validateNested(loc, opts) { const type = getSource(loc); assertNoDuplicateSourcemap(opts); Object.keys(opts).forEach(key => { const optLoc = { type: "option", name: key, parent: loc }; if (type === "preset" && NONPRESET_VALIDATORS[key]) { throw new Error(`${msg(optLoc)} is not allowed in preset options`); } if (type !== "arguments" && ROOT_VALIDATORS[key]) { throw new Error(`${msg(optLoc)} is only allowed in root programmatic options`); } if (type !== "arguments" && type !== "configfile" && BABELRC_VALIDATORS[key]) { if (type === "babelrcfile" || type === "extendsfile") { throw new Error(`${msg(optLoc)} is not allowed in .babelrc or "extends"ed files, only in root programmatic options, ` + `or babel.config.js/config file options`); } throw new Error(`${msg(optLoc)} is only allowed in root programmatic options, or babel.config.js/config file options`); } const validator = COMMON_VALIDATORS[key] || NONPRESET_VALIDATORS[key] || BABELRC_VALIDATORS[key] || ROOT_VALIDATORS[key] || throwUnknownError; validator(optLoc, opts[key]); }); return opts; } function throwUnknownError(loc) { const key = loc.name; if (removed[key]) { const { message, version = 5 } = removed[key]; throw new Error(`Using removed Babel ${version} option: ${msg(loc)} - ${message}`); } else { const unknownOptErr = new Error(`Unknown option: ${msg(loc)}. Check out https://babeljs.io/docs/en/babel-core/#options for more information about options.`); unknownOptErr.code = "BABEL_UNKNOWN_OPTION"; throw unknownOptErr; } } function assertNoDuplicateSourcemap(opts) { if (Object.hasOwn(opts, "sourceMap") && Object.hasOwn(opts, "sourceMaps")) { throw new Error(".sourceMap is an alias for .sourceMaps, cannot use both"); } } function assertEnvSet(loc, value) { if (loc.parent.type === "env") { throw new Error(`${msg(loc)} is not allowed inside of another .env block`); } const parent = loc.parent; const obj = assertObject(loc, value); if (obj) { for (const envName of Object.keys(obj)) { const env = assertObject(access(loc, envName), obj[envName]); if (!env) continue; const envLoc = { type: "env", name: envName, parent }; validateNested(envLoc, env); } } return obj; } function assertOverridesList(loc, value) { if (loc.parent.type === "env") { throw new Error(`${msg(loc)} is not allowed inside an .env block`); } if (loc.parent.type === "overrides") { throw new Error(`${msg(loc)} is not allowed inside an .overrides block`); } const parent = loc.parent; const arr = assertArray(loc, value); if (arr) { for (const [index, item] of arr.entries()) { const objLoc = access(loc, index); const env = assertObject(objLoc, item); if (!env) throw new Error(`${msg(objLoc)} must be an object`); const overridesLoc = { type: "overrides", index, parent }; validateNested(overridesLoc, env); } } return arr; } function checkNoUnwrappedItemOptionPairs(items, index, type, e) { if (index === 0) return; const lastItem = items[index - 1]; const thisItem = items[index]; if (lastItem.file && lastItem.options === undefined && typeof thisItem.value === "object") { e.message += `\n- Maybe you meant to use\n` + `"${type}s": [\n ["${lastItem.file.request}", ${JSON.stringify(thisItem.value, undefined, 2)}]\n]\n` + `To be a valid ${type}, its name and options should be wrapped in a pair of brackets`; } } const sep = `\\${path.sep}`; const endSep = `(?:${sep}|$)`; const substitution = `[^${sep}]+`; const starPat = `(?:${substitution}${sep})`; const starPatLast = `(?:${substitution}${endSep})`; const starStarPat = `${starPat}*?`; const starStarPatLast = `${starPat}*?${starPatLast}?`; function escapeRegExp(string) { return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&"); } function pathToPattern(pattern, dirname) { const parts = path.resolve(dirname, pattern).split(path.sep); return new RegExp(["^", ...parts.map((part, i) => { const last = i === parts.length - 1; if (part === "**") return last ? starStarPatLast : starStarPat; if (part === "*") return last ? starPatLast : starPat; if (part.startsWith("*.")) { return substitution + escapeRegExp(part.slice(1)) + (last ? endSep : sep); } return escapeRegExp(part) + (last ? endSep : sep); })].join("")); } const ChainFormatter = { Programmatic: 0, Config: 1 }; const Formatter = { title(type, callerName, filepath) { let title; if (type === ChainFormatter.Programmatic) { title = "programmatic options"; if (callerName) { title += " from " + callerName; } } else { title = "config " + filepath; } return title; }, loc(index, envName) { let loc = ""; if (index != null) { loc += `.overrides[${index}]`; } if (envName != null) { loc += `.env["${envName}"]`; } return loc; }, *optionsAndDescriptors(opt) { const content = { ...opt.options }; delete content.overrides; delete content.env; const pluginDescriptors = [...(yield* opt.plugins())]; if (pluginDescriptors.length) { content.plugins = pluginDescriptors.map(d => descriptorToConfig(d)); } const presetDescriptors = [...(yield* opt.presets())]; if (presetDescriptors.length) { content.presets = [...presetDescriptors].map(d => descriptorToConfig(d)); } return JSON.stringify(content, undefined, 2); } }; function descriptorToConfig(d) { let name = d.file?.request; if (name == null) { if (typeof d.value === "object") { name = d.value; } else if (typeof d.value === "function") { name = `[Function: ${d.value.toString().slice(0, 50)} ... ]`; } } if (name == null) { name = "[Unknown]"; } if (d.options === undefined) { return name; } else if (d.name == null) { return [name, d.options]; } else { return [name, d.options, d.name]; } } class ConfigPrinter { _stack = []; configure(enabled, type, { callerName, filepath }) { if (!enabled) return () => {}; return (content, index, envName) => { this._stack.push({ type, callerName, filepath, content, index, envName }); }; } static *format(config) { let title = Formatter.title(config.type, config.callerName, config.filepath); const loc = Formatter.loc(config.index, config.envName); if (loc) title += ` ${loc}`; const content = yield* Formatter.optionsAndDescriptors(config.content); return `${title}\n${content}`; } *output() { if (this._stack.length === 0) return ""; const configs = yield* gensync.all(this._stack.map(s => ConfigPrinter.format(s))); return configs.join("\n\n"); } } const debug = createDebug("babel:config:config-chain"); function* buildPresetChain(arg, context) { const chain = yield* buildPresetChainWalker(arg, context); if (!chain) return null; return { plugins: dedupDescriptors(chain.plugins), presets: dedupDescriptors(chain.presets), options: chain.options.map(o => createConfigChainOptions(o)), files: new Set() }; } const buildPresetChainWalker = makeChainWalker({ root: preset => loadPresetDescriptors(preset), env: (preset, envName) => loadPresetEnvDescriptors(preset)(envName), overrides: (preset, index) => loadPresetOverridesDescriptors(preset)(index), overridesEnv: (preset, index, envName) => loadPresetOverridesEnvDescriptors(preset)(index)(envName), createLogger: () => () => {} }); const loadPresetDescriptors = makeWeakCacheSync(preset => buildRootDescriptors(preset, preset.alias, createUncachedDescriptors)); const loadPresetEnvDescriptors = makeWeakCacheSync(preset => makeStrongCacheSync(envName => buildEnvDescriptors(preset, preset.alias, createUncachedDescriptors, envName))); const loadPresetOverridesDescriptors = makeWeakCacheSync(preset => makeStrongCacheSync(index => buildOverrideDescriptors(preset, preset.alias, createUncachedDescriptors, index))); const loadPresetOverridesEnvDescriptors = makeWeakCacheSync(preset => makeStrongCacheSync(index => makeStrongCacheSync(envName => buildOverrideEnvDescriptors(preset, preset.alias, createUncachedDescriptors, index, envName)))); function* buildRootChain(opts, context) { let configReport, babelRcReport; const programmaticLogger = new ConfigPrinter(); const programmaticChain = yield* loadProgrammaticChain({ options: opts, dirname: context.cwd }, context, undefined, programmaticLogger); if (!programmaticChain) return null; const programmaticReport = yield* programmaticLogger.output(); let configFile; if (typeof opts.configFile === "string") { configFile = yield* loadConfig$1(opts.configFile, context.cwd, context.envName, context.caller); } else if (opts.configFile !== false) { configFile = yield* findRootConfig(context.root, context.envName, context.caller); } let { babelrc, babelrcRoots } = opts; let babelrcRootsDirectory = context.cwd; const configFileChain = emptyChain(); const configFileLogger = new ConfigPrinter(); if (configFile) { const validatedFile = validateConfigFile(configFile); const result = yield* loadFileChain(validatedFile, context, undefined, configFileLogger); if (!result) return null; configReport = yield* configFileLogger.output(); if (babelrc === undefined) { babelrc = validatedFile.options.babelrc; } if (babelrcRoots === undefined) { babelrcRootsDirectory = validatedFile.dirname; babelrcRoots = validatedFile.options.babelrcRoots; } mergeChain(configFileChain, result); } let ignoreFile, babelrcFile; let isIgnored = false; const fileChain = emptyChain(); if ((babelrc === true || babelrc === undefined) && typeof context.filename === "string") { const pkgData = yield* findPackageData(context.filename); if (pkgData && babelrcLoadEnabled(context, pkgData, babelrcRoots, babelrcRootsDirectory)) { ({ ignore: ignoreFile, config: babelrcFile } = yield* findRelativeConfig(pkgData, context.envName, context.caller)); if (ignoreFile) { fileChain.files.add(ignoreFile.filepath); } if (ignoreFile && shouldIgnore(context, ignoreFile.ignore, null, ignoreFile.dirname)) { isIgnored = true; } if (babelrcFile && !isIgnored) { const validatedFile = validateBabelrcFile(babelrcFile); const babelrcLogger = new ConfigPrinter(); const result = yield* loadFileChain(validatedFile, context, undefined, babelrcLogger); if (!result) { isIgnored = true; } else { babelRcReport = yield* babelrcLogger.output(); mergeChain(fileChain, result); } } if (babelrcFile && isIgnored) { fileChain.files.add(babelrcFile.filepath); } } } if (context.showConfig) { console.log(`Babel configs on "${context.filename}" (ascending priority):\n` + [configReport, babelRcReport, programmaticReport].filter(x => !!x).join("\n\n") + "\n-----End Babel configs-----"); } const chain = mergeChain(mergeChain(mergeChain(emptyChain(), configFileChain), fileChain), programmaticChain); return { plugins: isIgnored ? [] : dedupDescriptors(chain.plugins), presets: isIgnored ? [] : dedupDescriptors(chain.presets), options: isIgnored ? [] : chain.options.map(o => createConfigChainOptions(o)), fileHandling: isIgnored ? "ignored" : "transpile", ignore: ignoreFile || undefined, babelrc: babelrcFile || undefined, config: configFile || undefined, files: chain.files }; } function babelrcLoadEnabled(context, pkgData, babelrcRoots, babelrcRootsDirectory) { if (typeof babelrcRoots === "boolean") return babelrcRoots; const absoluteRoot = context.root; if (babelrcRoots === undefined) { return pkgData.directories.includes(absoluteRoot); } let babelrcPatterns = babelrcRoots; if (!Array.isArray(babelrcPatterns)) { babelrcPatterns = [babelrcPatterns]; } babelrcPatterns = babelrcPatterns.map(pat => { return typeof pat === "string" ? path.resolve(babelrcRootsDirectory, pat) : pat; }); if (babelrcPatterns.length === 1 && babelrcPatterns[0] === absoluteRoot) { return pkgData.directories.includes(absoluteRoot); } return babelrcPatterns.some(pat => { if (typeof pat === "string") { pat = pathToPattern(pat, babelrcRootsDirectory); } return pkgData.directories.some(directory => { return matchPattern(pat, babelrcRootsDirectory, directory, context); }); }); } const validateConfigFile = makeWeakCacheSync(file => ({ filepath: file.filepath, dirname: file.dirname, options: validate("configfile", file.options, file.filepath) })); const validateBabelrcFile = makeWeakCacheSync(file => ({ filepath: file.filepath, dirname: file.dirname, options: validate("babelrcfile", file.options, file.filepath) })); const validateExtendFile = makeWeakCacheSync(file => ({ filepath: file.filepath, dirname: file.dirname, options: validate("extendsfile", file.options, file.filepath) })); const loadProgrammaticChain = makeChainWalker({ root: input => buildRootDescriptors(input, "base", createCachedDescriptors), env: (input, envName) => buildEnvDescriptors(input, "base", createCachedDescriptors, envName), overrides: (input, index) => buildOverrideDescriptors(input, "base", createCachedDescriptors, index), overridesEnv: (input, index, envName) => buildOverrideEnvDescriptors(input, "base", createCachedDescriptors, index, envName), createLogger: (input, context, baseLogger) => buildProgrammaticLogger(input, context, baseLogger) }); const loadFileChainWalker = makeChainWalker({ root: file => loadFileDescriptors(file), env: (file, envName) => loadFileEnvDescriptors(file)(envName), overrides: (file, index) => loadFileOverridesDescriptors(file)(index), overridesEnv: (file, index, envName) => loadFileOverridesEnvDescriptors(file)(index)(envName), createLogger: (file, context, baseLogger) => buildFileLogger(file.filepath, context, baseLogger) }); function* loadFileChain(input, context, files, baseLogger) { const chain = yield* loadFileChainWalker(input, context, files, baseLogger); chain?.files.add(input.filepath); return chain; } const loadFileDescriptors = makeWeakCacheSync(file => buildRootDescriptors(file, file.filepath, createUncachedDescriptors)); const loadFileEnvDescriptors = makeWeakCacheSync(file => makeStrongCacheSync(envName => buildEnvDescriptors(file, file.filepath, createUncachedDescriptors, envName))); const loadFileOverridesDescriptors = makeWeakCacheSync(file => makeStrongCacheSync(index => buildOverrideDescriptors(file, file.filepath, createUncachedDescriptors, index))); const loadFileOverridesEnvDescriptors = makeWeakCacheSync(file => makeStrongCacheSync(index => makeStrongCacheSync(envName => buildOverrideEnvDescriptors(file, file.filepath, createUncachedDescriptors, index, envName)))); function buildFileLogger(filepath, context, baseLogger) { if (!baseLogger) { return () => {}; } return baseLogger.configure(context.showConfig, ChainFormatter.Config, { filepath }); } function buildRootDescriptors({ dirname, options }, alias, descriptors) { return descriptors(dirname, options, alias); } function buildProgrammaticLogger(_, context, baseLogger) { if (!baseLogger) { return () => {}; } return baseLogger.configure(context.showConfig, ChainFormatter.Programmatic, { callerName: context.caller?.name }); } function buildEnvDescriptors({ dirname, options }, alias, descriptors, envName) { const opts = options.env?.[envName]; return opts ? descriptors(dirname, opts, `${alias}.env["${envName}"]`) : null; } function buildOverrideDescriptors({ dirname, options }, alias, descriptors, index) { const opts = options.overrides?.[index]; if (!opts) throw new Error("Assertion failure - missing override"); return descriptors(dirname, opts, `${alias}.overrides[${index}]`); } function buildOverrideEnvDescriptors({ dirn