diff --git a/packages/babel-core/src/config/index.js b/packages/babel-core/src/config/index.js index ef5d5c4a66..05ac8e7ce9 100644 --- a/packages/babel-core/src/config/index.js +++ b/packages/babel-core/src/config/index.js @@ -3,7 +3,6 @@ import path from "path"; import * as context from "../index"; import Plugin from "./plugin"; -import merge from "lodash/merge"; import { buildRootChain, buildPresetChain, @@ -13,10 +12,9 @@ import { } from "./config-chain"; import type { UnloadedDescriptor } from "./config-descriptors"; import traverse from "@babel/traverse"; -import clone from "lodash/clone"; import { makeWeakCache, type CacheConfigurator } from "./caching"; import { getEnv } from "./helpers/environment"; -import { validate } from "./validation/options"; +import { validate, type ValidatedOptions } from "./validation/options"; import { validatePluginObject } from "./validation/plugins"; type LoadedDescriptor = { @@ -109,7 +107,7 @@ export default function loadConfig(inputOpts: mixed): ResolvedConfig | null { if (ignored) return true; preset.options.forEach(opts => { - merge(optionDefaults, opts); + mergeOptions(optionDefaults, opts); }); } } @@ -129,7 +127,7 @@ export default function loadConfig(inputOpts: mixed): ResolvedConfig | null { if (ignored) return null; configChain.options.forEach(opts => { - merge(options, opts); + mergeOptions(options, opts); }); } catch (e) { // There are a few case where thrown errors will try to annotate themselves multiple times, so @@ -141,7 +139,8 @@ export default function loadConfig(inputOpts: mixed): ResolvedConfig | null { throw e; } - const opts: Object = merge(optionDefaults, options); + const opts: Object = optionDefaults; + mergeOptions(opts, options); // Tack the passes onto the object itself so that, if this object is passed back to Babel a second time, // it will be in the right structure to not change behavior. @@ -161,6 +160,33 @@ export default function loadConfig(inputOpts: mixed): ResolvedConfig | null { }; } +function mergeOptions( + target: ValidatedOptions, + source: ValidatedOptions, +): void { + for (const k of Object.keys(source)) { + if (k === "parserOpts" && source.parserOpts) { + const parserOpts = source.parserOpts; + const targetObj = (target.parserOpts = target.parserOpts || {}); + mergeDefaultFields(targetObj, parserOpts); + } else if (k === "generatorOpts" && source.generatorOpts) { + const generatorOpts = source.generatorOpts; + const targetObj = (target.generatorOpts = target.generatorOpts || {}); + mergeDefaultFields(targetObj, generatorOpts); + } else { + const val = source[k]; + if (val !== undefined) target[k] = (val: any); + } + } +} + +function mergeDefaultFields(target: T, source: T) { + for (const k of Object.keys(source)) { + const val = source[k]; + if (val !== undefined) target[k] = (val: any); + } +} + /** * Load a generic plugin/preset from the given descriptor loaded from the config object. */ @@ -238,7 +264,7 @@ const instantiatePlugin = makeWeakCache( const plugin = Object.assign({}, pluginObj); if (plugin.visitor) { - plugin.visitor = traverse.explode(clone(plugin.visitor)); + plugin.visitor = traverse.explode(Object.assign({}, plugin.visitor)); } if (plugin.inherits) { diff --git a/packages/babel-core/src/tools/build-external-helpers.js b/packages/babel-core/src/tools/build-external-helpers.js index 2b6eba92a1..c6aa2bf6d2 100644 --- a/packages/babel-core/src/tools/build-external-helpers.js +++ b/packages/babel-core/src/tools/build-external-helpers.js @@ -3,19 +3,22 @@ import generator from "@babel/generator"; import template from "@babel/template"; import * as t from "@babel/types"; -const buildUmdWrapper = template(` - (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 - }); -`); +// Wrapped to avoid wasting time parsing this when almost no-one uses +// build-external-helpers. +const buildUmdWrapper = replacements => + template` + (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(whitelist) { const namespace = t.identifier("babelHelpers"); diff --git a/packages/babel-core/src/transformation/index.js b/packages/babel-core/src/transformation/index.js index a40b12f42c..038ea6d0c6 100644 --- a/packages/babel-core/src/transformation/index.js +++ b/packages/babel-core/src/transformation/index.js @@ -64,7 +64,7 @@ export function runSync( return { metadata: file.metadata, options: opts, - ast: opts.ast !== false ? file.ast : null, + ast: opts.ast === true ? file.ast : null, code: outputCode === undefined ? null : outputCode, map: outputMap === undefined ? null : outputMap, }; diff --git a/packages/babel-core/test/api.js b/packages/babel-core/test/api.js index a38ae5913c..6a63378083 100644 --- a/packages/babel-core/test/api.js +++ b/packages/babel-core/test/api.js @@ -34,6 +34,7 @@ describe("parser and generator options", function() { function newTransform(string) { return babel.transform(string, { + ast: true, parserOpts: { parser: recast.parse, plugins: ["flow"], @@ -47,7 +48,10 @@ describe("parser and generator options", function() { it("options", function() { const string = "original;"; - assert.deepEqual(newTransform(string).ast, babel.transform(string).ast); + assert.deepEqual( + newTransform(string).ast, + babel.transform(string, { ast: true }).ast, + ); assert.equal(newTransform(string).code, string); }); @@ -57,6 +61,7 @@ describe("parser and generator options", function() { assert.deepEqual( newTransform(experimental).ast, babel.transform(experimental, { + ast: true, parserOpts: { plugins: ["flow"], }, @@ -66,6 +71,7 @@ describe("parser and generator options", function() { function newTransformWithPlugins(string) { return babel.transform(string, { + ast: true, plugins: [__dirname + "/../../babel-plugin-syntax-flow"], parserOpts: { parser: recast.parse, @@ -79,6 +85,7 @@ describe("parser and generator options", function() { assert.deepEqual( newTransformWithPlugins(experimental).ast, babel.transform(experimental, { + ast: true, parserOpts: { plugins: ["flow"], }, @@ -93,6 +100,7 @@ describe("parser and generator options", function() { assert.notEqual( newTransform(experimental).ast, babel.transform(experimental, { + ast: true, parserOpts: { allowImportExportEverywhere: true, }, @@ -401,6 +409,18 @@ describe("api", function() { }); }); + it("ast option true", function() { + return transformAsync("foo('bar');", { ast: true }).then(function(result) { + assert.ok(result.ast); + }); + }); + + it("ast option default", function() { + return transformAsync("foo('bar');").then(function(result) { + assert.ok(!result.ast); + }); + }); + it("auxiliaryComment option", function() { return transformAsync("class Foo {}", { auxiliaryCommentBefore: "before", diff --git a/packages/babel-helpers/src/helpers.js b/packages/babel-helpers/src/helpers.js index 8cfabc8f64..8b89f2e55d 100644 --- a/packages/babel-helpers/src/helpers.js +++ b/packages/babel-helpers/src/helpers.js @@ -5,11 +5,7 @@ import template from "@babel/template"; const helpers = {}; export default helpers; -// Helpers never include placeholders, so we disable placeholder pattern -// matching to allow us to use pattern-like variable names. -const defineHelper = template.program({ placeholderPattern: false }); - -helpers.typeof = defineHelper(` +helpers.typeof = () => template.program.ast` export default function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function (obj) { return typeof obj; }; @@ -23,9 +19,9 @@ helpers.typeof = defineHelper(` return _typeof(obj); } -`); +`; -helpers.jsx = defineHelper(` +helpers.jsx = () => template.program.ast` var REACT_ELEMENT_TYPE; export default function _createRawReactElement(type, props, key, children) { @@ -72,9 +68,9 @@ helpers.jsx = defineHelper(` _owner: null, }; } -`); +`; -helpers.asyncIterator = defineHelper(` +helpers.asyncIterator = () => template.program.ast` export default function _asyncIterator(iterable) { if (typeof Symbol === "function") { if (Symbol.asyncIterator) { @@ -87,15 +83,15 @@ helpers.asyncIterator = defineHelper(` } throw new TypeError("Object is not async iterable"); } -`); +`; -helpers.AwaitValue = defineHelper(` +helpers.AwaitValue = () => template.program.ast` export default function _AwaitValue(value) { this.wrapped = value; } -`); +`; -helpers.AsyncGenerator = defineHelper(` +helpers.AsyncGenerator = () => template.program.ast` import AwaitValue from "AwaitValue"; export default function AsyncGenerator(gen) { @@ -177,9 +173,9 @@ helpers.AsyncGenerator = defineHelper(` AsyncGenerator.prototype.next = function (arg) { return this._invoke("next", arg); }; AsyncGenerator.prototype.throw = function (arg) { return this._invoke("throw", arg); }; AsyncGenerator.prototype.return = function (arg) { return this._invoke("return", arg); }; -`); +`; -helpers.wrapAsyncGenerator = defineHelper(` +helpers.wrapAsyncGenerator = () => template.program.ast` import AsyncGenerator from "AsyncGenerator"; export default function _wrapAsyncGenerator(fn) { @@ -187,17 +183,17 @@ helpers.wrapAsyncGenerator = defineHelper(` return new AsyncGenerator(fn.apply(this, arguments)); }; } -`); +`; -helpers.awaitAsyncGenerator = defineHelper(` +helpers.awaitAsyncGenerator = () => template.program.ast` import AwaitValue from "AwaitValue"; export default function _awaitAsyncGenerator(value) { return new AwaitValue(value); } -`); +`; -helpers.asyncGeneratorDelegate = defineHelper(` +helpers.asyncGeneratorDelegate = () => template.program.ast` export default function _asyncGeneratorDelegate(inner, awaitWrap) { var iter = {}, waiting = false; @@ -237,9 +233,9 @@ helpers.asyncGeneratorDelegate = defineHelper(` return iter; } -`); +`; -helpers.asyncToGenerator = defineHelper(` +helpers.asyncToGenerator = () => template.program.ast` export default function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; @@ -267,17 +263,17 @@ helpers.asyncToGenerator = defineHelper(` }); }; } -`); +`; -helpers.classCallCheck = defineHelper(` +helpers.classCallCheck = () => template.program.ast` export default function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } -`); +`; -helpers.createClass = defineHelper(` +helpers.createClass = () => template.program.ast` function _defineProperties(target, props) { for (var i = 0; i < props.length; i ++) { var descriptor = props[i]; @@ -293,9 +289,9 @@ helpers.createClass = defineHelper(` if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } -`); +`; -helpers.defineEnumerableProperties = defineHelper(` +helpers.defineEnumerableProperties = () => template.program.ast` export default function _defineEnumerableProperties(obj, descs) { for (var key in descs) { var desc = descs[key]; @@ -319,9 +315,9 @@ helpers.defineEnumerableProperties = defineHelper(` } return obj; } -`); +`; -helpers.defaults = defineHelper(` +helpers.defaults = () => template.program.ast` export default function _defaults(obj, defaults) { var keys = Object.getOwnPropertyNames(defaults); for (var i = 0; i < keys.length; i++) { @@ -333,9 +329,9 @@ helpers.defaults = defineHelper(` } return obj; } -`); +`; -helpers.defineProperty = defineHelper(` +helpers.defineProperty = () => template.program.ast` export default function _defineProperty(obj, key, value) { // Shortcircuit the slow defineProperty path when possible. // We are trying to avoid issues where setters defined on the @@ -354,9 +350,9 @@ helpers.defineProperty = defineHelper(` } return obj; } -`); +`; -helpers.extends = defineHelper(` +helpers.extends = () => template.program.ast` export default function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { @@ -372,9 +368,9 @@ helpers.extends = defineHelper(` return _extends.apply(this, arguments); } -`); +`; -helpers.objectSpread = defineHelper(` +helpers.objectSpread = () => template.program.ast` import defineProperty from "defineProperty"; export default function _objectSpread(target) { @@ -392,9 +388,9 @@ helpers.objectSpread = defineHelper(` } return target; } -`); +`; -helpers.get = defineHelper(` +helpers.get = () => template.program.ast` export default function _get(object, property, receiver) { if (object === null) object = Function.prototype; @@ -420,9 +416,9 @@ helpers.get = defineHelper(` return getter.call(receiver); } } -`); +`; -helpers.inherits = defineHelper(` +helpers.inherits = () => template.program.ast` export default function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); @@ -437,18 +433,18 @@ helpers.inherits = defineHelper(` }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } -`); +`; -helpers.inheritsLoose = defineHelper(` +helpers.inheritsLoose = () => template.program.ast` export default function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } -`); +`; // Based on https://github.com/WebReflection/babel-plugin-transform-builtin-classes -helpers.wrapNativeSuper = defineHelper(` +helpers.wrapNativeSuper = () => template.program.ast` var _gPO = Object.getPrototypeOf || function _gPO(o) { return o.__proto__ }; var _sPO = Object.setPrototypeOf || function _sPO(o, p) { o.__proto__ = p; return o }; var _construct = (typeof Reflect === "object" && Reflect.construct) || @@ -490,9 +486,9 @@ helpers.wrapNativeSuper = defineHelper(` ) ); } -`); +`; -helpers.instanceof = defineHelper(` +helpers.instanceof = () => template.program.ast` export default function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return right[Symbol.hasInstance](left); @@ -500,15 +496,15 @@ helpers.instanceof = defineHelper(` return left instanceof right; } } -`); +`; -helpers.interopRequireDefault = defineHelper(` +helpers.interopRequireDefault = () => template.program.ast` export default function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -`); +`; -helpers.interopRequireWildcard = defineHelper(` +helpers.interopRequireWildcard = () => template.program.ast` export default function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; @@ -532,23 +528,23 @@ helpers.interopRequireWildcard = defineHelper(` return newObj; } } -`); +`; -helpers.newArrowCheck = defineHelper(` +helpers.newArrowCheck = () => template.program.ast` export default function _newArrowCheck(innerThis, boundThis) { if (innerThis !== boundThis) { throw new TypeError("Cannot instantiate an arrow function"); } } -`); +`; -helpers.objectDestructuringEmpty = defineHelper(` +helpers.objectDestructuringEmpty = () => template.program.ast` export default function _objectDestructuringEmpty(obj) { if (obj == null) throw new TypeError("Cannot destructure undefined"); } -`); +`; -helpers.objectWithoutProperties = defineHelper(` +helpers.objectWithoutProperties = () => template.program.ast` export default function _objectWithoutProperties(source, excluded) { if (source == null) return {}; @@ -574,18 +570,18 @@ helpers.objectWithoutProperties = defineHelper(` return target; } -`); +`; -helpers.assertThisInitialized = defineHelper(` +helpers.assertThisInitialized = () => template.program.ast` export default function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } -`); +`; -helpers.possibleConstructorReturn = defineHelper(` +helpers.possibleConstructorReturn = () => template.program.ast` export default function _possibleConstructorReturn(self, call) { if (call && (typeof call === "object" || typeof call === "function")) { return call; @@ -598,9 +594,9 @@ helpers.possibleConstructorReturn = defineHelper(` } return self; } -`); +`; -helpers.set = defineHelper(` +helpers.set = () => template.program.ast` export default function _set(object, property, value, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); @@ -622,9 +618,9 @@ helpers.set = defineHelper(` return value; } -`); +`; -helpers.slicedToArray = defineHelper(` +helpers.slicedToArray = () => template.program.ast` // Broken out into a separate function to avoid deoptimizations due to the try/catch for the // array iterator case. function _sliceIterator(arr, i) { @@ -669,9 +665,9 @@ helpers.slicedToArray = defineHelper(` throw new TypeError("Invalid attempt to destructure non-iterable instance"); } } -`); +`; -helpers.slicedToArrayLoose = defineHelper(` +helpers.slicedToArrayLoose = () => template.program.ast` export default function _slicedToArrayLoose(arr, i) { if (Array.isArray(arr)) { return arr; @@ -686,26 +682,26 @@ helpers.slicedToArrayLoose = defineHelper(` throw new TypeError("Invalid attempt to destructure non-iterable instance"); } } -`); +`; -helpers.taggedTemplateLiteral = defineHelper(` +helpers.taggedTemplateLiteral = () => template.program.ast` export default function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } -`); +`; -helpers.taggedTemplateLiteralLoose = defineHelper(` +helpers.taggedTemplateLiteralLoose = () => template.program.ast` export default function _taggedTemplateLiteralLoose(strings, raw) { if (!raw) { raw = strings.slice(0); } strings.raw = raw; return strings; } -`); +`; -helpers.temporalRef = defineHelper(` +helpers.temporalRef = () => template.program.ast` import undef from "temporalUndefined"; export default function _temporalRef(val, name) { @@ -715,31 +711,31 @@ helpers.temporalRef = defineHelper(` return val; } } -`); +`; -helpers.readOnlyError = defineHelper(` +helpers.readOnlyError = () => template.program.ast` export default function _readOnlyError(name) { throw new Error("\\"" + name + "\\" is read-only"); } -`); +`; -helpers.classNameTDZError = defineHelper(` +helpers.classNameTDZError = () => template.program.ast` export default function _classNameTDZError(name) { throw new Error("Class \\"" + name + "\\" cannot be referenced in computed property keys."); } -`); +`; -helpers.temporalUndefined = defineHelper(` +helpers.temporalUndefined = () => template.program.ast` export default {}; -`); +`; -helpers.toArray = defineHelper(` +helpers.toArray = () => template.program.ast` export default function _toArray(arr) { return Array.isArray(arr) ? arr : Array.from(arr); } -`); +`; -helpers.toConsumableArray = defineHelper(` +helpers.toConsumableArray = () => template.program.ast` export default function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; @@ -748,9 +744,9 @@ helpers.toConsumableArray = defineHelper(` return Array.from(arr); } } -`); +`; -helpers.skipFirstGeneratorNext = defineHelper(` +helpers.skipFirstGeneratorNext = () => template.program.ast` export default function _skipFirstGeneratorNext(fn) { return function () { var it = fn.apply(this, arguments); @@ -758,9 +754,9 @@ helpers.skipFirstGeneratorNext = defineHelper(` return it; } } -`); +`; -helpers.toPropertyKey = defineHelper(` +helpers.toPropertyKey = () => template.program.ast` export default function _toPropertyKey(key) { if (typeof key === "symbol") { return key; @@ -768,13 +764,13 @@ helpers.toPropertyKey = defineHelper(` return String(key); } } -`); +`; /** * Add a helper that will throw a useful error if the transform fails to detect the class * property assignment, so users know something failed. */ -helpers.initializerWarningHelper = defineHelper(` +helpers.initializerWarningHelper = () => template.program.ast` export default function _initializerWarningHelper(descriptor, context){ throw new Error( 'Decorating class property failed. Please ensure that ' + @@ -783,12 +779,12 @@ helpers.initializerWarningHelper = defineHelper(` 'the next major version of decorators in stage 2.' ); } -`); +`; /** * Add a helper to call as a replacement for class property definition. */ -helpers.initializerDefineProperty = defineHelper(` +helpers.initializerDefineProperty = () => template.program.ast` export default function _initializerDefineProperty(target, property, descriptor, context){ if (!descriptor) return; @@ -799,13 +795,13 @@ helpers.initializerDefineProperty = defineHelper(` value: descriptor.initializer ? descriptor.initializer.call(context) : void 0, }); } -`); +`; /** * Add a helper to take an initial descriptor, apply some decorators to it, and optionally * define the property. */ -helpers.applyDecoratedDescriptor = defineHelper(` +helpers.applyDecoratedDescriptor = () => template.program.ast` export default function _applyDecoratedDescriptor(target, property, decorators, descriptor, context){ var desc = {}; Object['ke' + 'ys'](descriptor).forEach(function(key){ @@ -835,4 +831,4 @@ helpers.applyDecoratedDescriptor = defineHelper(` return desc; } -`); +`; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/copied-nodes.js b/packages/babel-plugin-transform-modules-commonjs/test/copied-nodes.js index 4bdcaa8953..f28341da50 100644 --- a/packages/babel-plugin-transform-modules-commonjs/test/copied-nodes.js +++ b/packages/babel-plugin-transform-modules-commonjs/test/copied-nodes.js @@ -5,6 +5,7 @@ test("Doesn't use the same object for two different nodes in the AST", function( const code = 'import Foo from "bar"; Foo; Foo;'; const ast = babel.transform(code, { + ast: true, plugins: [[require("../"), { loose: true }]], }).ast;