Add @babel/core support for the new assumptions option (#12219)
- Disallow setting assumptions to `false` in presets (#12498)
This commit is contained in:
parent
cb404e4776
commit
7965c15557
32
packages/babel-core/src/config/cache-contexts.js
Normal file
32
packages/babel-core/src/config/cache-contexts.js
Normal file
@ -0,0 +1,32 @@
|
||||
// @flow
|
||||
|
||||
import type { Targets } from "@babel/helper-compilation-targets";
|
||||
|
||||
import type { ConfigContext } from "./config-chain";
|
||||
import type { CallerMetadata } from "./validation/options";
|
||||
|
||||
export type { ConfigContext as FullConfig };
|
||||
|
||||
export type FullPreset = {
|
||||
...ConfigContext,
|
||||
targets: Targets,
|
||||
};
|
||||
export type FullPlugin = {
|
||||
...FullPreset,
|
||||
assumptions: { [name: string]: boolean },
|
||||
};
|
||||
|
||||
// Context not including filename since it is used in places that cannot
|
||||
// process 'ignore'/'only' and other filename-based logic.
|
||||
export type SimpleConfig = {
|
||||
envName: string,
|
||||
caller: CallerMetadata | void,
|
||||
};
|
||||
export type SimplePreset = {
|
||||
...SimpleConfig,
|
||||
targets: Targets,
|
||||
};
|
||||
export type SimplePlugin = {
|
||||
...SimplePreset,
|
||||
assumptions: { [name: string]: boolean },
|
||||
};
|
||||
@ -14,7 +14,6 @@ import {
|
||||
type PresetInstance,
|
||||
} from "./config-chain";
|
||||
import type { UnloadedDescriptor } from "./config-descriptors";
|
||||
import type { Targets } from "@babel/helper-compilation-targets";
|
||||
import traverse from "@babel/traverse";
|
||||
import {
|
||||
makeWeakCache,
|
||||
@ -23,16 +22,17 @@ import {
|
||||
} from "./caching";
|
||||
import {
|
||||
validate,
|
||||
type CallerMetadata,
|
||||
checkNoUnwrappedItemOptionPairs,
|
||||
type PluginItem,
|
||||
} from "./validation/options";
|
||||
import { validatePluginObject } from "./validation/plugins";
|
||||
import { makePluginAPI } from "./helpers/config-api";
|
||||
import { makePluginAPI, makePresetAPI } from "./helpers/config-api";
|
||||
|
||||
import loadPrivatePartialConfig from "./partial";
|
||||
import type { ValidatedOptions } from "./validation/options";
|
||||
|
||||
import * as Context from "./cache-contexts";
|
||||
|
||||
type LoadedDescriptor = {
|
||||
value: {},
|
||||
options: {},
|
||||
@ -40,11 +40,6 @@ type LoadedDescriptor = {
|
||||
alias: string,
|
||||
};
|
||||
|
||||
type PluginContext = {
|
||||
...ConfigContext,
|
||||
targets: Targets,
|
||||
};
|
||||
|
||||
export type { InputOptions } from "./validation/options";
|
||||
|
||||
export type ResolvedConfig = {
|
||||
@ -56,14 +51,6 @@ export type { Plugin };
|
||||
export type PluginPassList = Array<Plugin>;
|
||||
export type PluginPasses = Array<PluginPassList>;
|
||||
|
||||
// Context not including filename since it is used in places that cannot
|
||||
// process 'ignore'/'only' and other filename-based logic.
|
||||
type SimpleContext = {
|
||||
envName: string,
|
||||
caller: CallerMetadata | void,
|
||||
targets: Targets,
|
||||
};
|
||||
|
||||
export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig(
|
||||
inputOpts: mixed,
|
||||
): Handler<ResolvedConfig | null> {
|
||||
@ -85,9 +72,10 @@ export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig(
|
||||
throw new Error("Assertion failure - plugins and presets exist");
|
||||
}
|
||||
|
||||
const pluginContext: PluginContext = {
|
||||
const pluginContext: Context.FullPlugin = {
|
||||
...context,
|
||||
targets: options.targets,
|
||||
assumptions: options.assumptions ?? {},
|
||||
};
|
||||
|
||||
const toDescriptor = (item: PluginItem) => {
|
||||
@ -229,62 +217,72 @@ function enhanceError<T: Function>(context, fn: T): T {
|
||||
/**
|
||||
* Load a generic plugin/preset from the given descriptor loaded from the config object.
|
||||
*/
|
||||
const loadDescriptor = makeWeakCache(function* (
|
||||
{ value, options, dirname, alias }: UnloadedDescriptor,
|
||||
cache: CacheConfigurator<SimpleContext>,
|
||||
): Handler<LoadedDescriptor> {
|
||||
// Disabled presets should already have been filtered out
|
||||
if (options === false) throw new Error("Assertion failure");
|
||||
const makeDescriptorLoader = <Context, API>(
|
||||
apiFactory: (cache: CacheConfigurator<Context>) => API,
|
||||
): ((d: UnloadedDescriptor, c: Context) => Handler<LoadedDescriptor>) =>
|
||||
makeWeakCache(function* (
|
||||
{ value, options, dirname, alias }: UnloadedDescriptor,
|
||||
cache: CacheConfigurator<Context>,
|
||||
): Handler<LoadedDescriptor> {
|
||||
// Disabled presets should already have been filtered out
|
||||
if (options === false) throw new Error("Assertion failure");
|
||||
|
||||
options = options || {};
|
||||
options = options || {};
|
||||
|
||||
let item = value;
|
||||
if (typeof value === "function") {
|
||||
const factory = maybeAsync(
|
||||
value,
|
||||
`You appear to be using an async plugin/preset, but Babel has been called synchronously`,
|
||||
);
|
||||
let item = value;
|
||||
if (typeof value === "function") {
|
||||
const factory = maybeAsync(
|
||||
value,
|
||||
`You appear to be using an async plugin/preset, but Babel has been called synchronously`,
|
||||
);
|
||||
|
||||
const api = {
|
||||
...context,
|
||||
...makePluginAPI(cache),
|
||||
};
|
||||
try {
|
||||
item = yield* factory(api, options, dirname);
|
||||
} catch (e) {
|
||||
if (alias) {
|
||||
e.message += ` (While processing: ${JSON.stringify(alias)})`;
|
||||
const api = {
|
||||
...context,
|
||||
...apiFactory(cache),
|
||||
};
|
||||
try {
|
||||
item = yield* factory(api, options, dirname);
|
||||
} catch (e) {
|
||||
if (alias) {
|
||||
e.message += ` (While processing: ${JSON.stringify(alias)})`;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (!item || typeof item !== "object") {
|
||||
throw new Error("Plugin/Preset did not return an object.");
|
||||
}
|
||||
if (!item || typeof item !== "object") {
|
||||
throw new Error("Plugin/Preset did not return an object.");
|
||||
}
|
||||
|
||||
if (isThenable(item)) {
|
||||
yield* []; // if we want to support async plugins
|
||||
if (isThenable(item)) {
|
||||
yield* []; // if we want to support async plugins
|
||||
|
||||
throw new Error(
|
||||
`You appear to be using a promise as a plugin, ` +
|
||||
`which your current version of Babel does not support. ` +
|
||||
`If you're using a published plugin, ` +
|
||||
`you may need to upgrade your @babel/core version. ` +
|
||||
`As an alternative, you can prefix the promise with "await". ` +
|
||||
`(While processing: ${JSON.stringify(alias)})`,
|
||||
);
|
||||
}
|
||||
throw new Error(
|
||||
`You appear to be using a promise as a plugin, ` +
|
||||
`which your current version of Babel does not support. ` +
|
||||
`If you're using a published plugin, ` +
|
||||
`you may need to upgrade your @babel/core version. ` +
|
||||
`As an alternative, you can prefix the promise with "await". ` +
|
||||
`(While processing: ${JSON.stringify(alias)})`,
|
||||
);
|
||||
}
|
||||
|
||||
return { value: item, options, dirname, alias };
|
||||
});
|
||||
return { value: item, options, dirname, alias };
|
||||
});
|
||||
|
||||
const pluginDescriptorLoader = makeDescriptorLoader<Context.SimplePlugin, *>(
|
||||
makePluginAPI,
|
||||
);
|
||||
const presetDescriptorLoader = makeDescriptorLoader<Context.SimplePreset, *>(
|
||||
makePresetAPI,
|
||||
);
|
||||
|
||||
/**
|
||||
* Instantiate a plugin for the given descriptor, returning the plugin/options pair.
|
||||
*/
|
||||
function* loadPluginDescriptor(
|
||||
descriptor: UnloadedDescriptor,
|
||||
context: SimpleContext,
|
||||
context: Context.SimplePlugin,
|
||||
): Handler<Plugin> {
|
||||
if (descriptor.value instanceof Plugin) {
|
||||
if (descriptor.options) {
|
||||
@ -297,14 +295,14 @@ function* loadPluginDescriptor(
|
||||
}
|
||||
|
||||
return yield* instantiatePlugin(
|
||||
yield* loadDescriptor(descriptor, context),
|
||||
yield* pluginDescriptorLoader(descriptor, context),
|
||||
context,
|
||||
);
|
||||
}
|
||||
|
||||
const instantiatePlugin = makeWeakCache(function* (
|
||||
{ value, options, dirname, alias }: LoadedDescriptor,
|
||||
cache: CacheConfigurator<SimpleContext>,
|
||||
cache: CacheConfigurator<Context.SimplePlugin>,
|
||||
): Handler<Plugin> {
|
||||
const pluginObj = validatePluginObject(value);
|
||||
|
||||
@ -387,9 +385,11 @@ const validatePreset = (
|
||||
*/
|
||||
function* loadPresetDescriptor(
|
||||
descriptor: UnloadedDescriptor,
|
||||
context: PluginContext,
|
||||
context: Context.FullPreset,
|
||||
): Handler<ConfigChain | null> {
|
||||
const preset = instantiatePreset(yield* loadDescriptor(descriptor, context));
|
||||
const preset = instantiatePreset(
|
||||
yield* presetDescriptorLoader(descriptor, context),
|
||||
);
|
||||
validatePreset(preset, context, descriptor);
|
||||
return yield* buildPresetChain(preset, context);
|
||||
}
|
||||
|
||||
@ -13,6 +13,8 @@ import {
|
||||
|
||||
import type { CallerMetadata } from "../validation/options";
|
||||
|
||||
import * as Context from "../cache-contexts";
|
||||
|
||||
type EnvFunction = {
|
||||
(): string,
|
||||
<T>((string) => T): T,
|
||||
@ -24,6 +26,8 @@ type CallerFactory = ((CallerMetadata | void) => mixed) => SimpleType;
|
||||
|
||||
type TargetsFunction = () => Targets;
|
||||
|
||||
type AssumptionFunction = (name: string) => boolean | void;
|
||||
|
||||
export type ConfigAPI = {|
|
||||
version: string,
|
||||
cache: SimpleCacheConfigurator,
|
||||
@ -33,14 +37,19 @@ export type ConfigAPI = {|
|
||||
caller?: CallerFactory,
|
||||
|};
|
||||
|
||||
export type PluginAPI = {|
|
||||
export type PresetAPI = {|
|
||||
...ConfigAPI,
|
||||
targets: TargetsFunction,
|
||||
|};
|
||||
|
||||
export function makeConfigAPI<
|
||||
SideChannel: { envName: string, caller: CallerMetadata | void },
|
||||
>(cache: CacheConfigurator<SideChannel>): ConfigAPI {
|
||||
export type PluginAPI = {|
|
||||
...PresetAPI,
|
||||
assumption: AssumptionFunction,
|
||||
|};
|
||||
|
||||
export function makeConfigAPI<SideChannel: Context.SimpleConfig>(
|
||||
cache: CacheConfigurator<SideChannel>,
|
||||
): ConfigAPI {
|
||||
const env: any = value =>
|
||||
cache.using(data => {
|
||||
if (typeof value === "undefined") return data.envName;
|
||||
@ -70,13 +79,9 @@ export function makeConfigAPI<
|
||||
};
|
||||
}
|
||||
|
||||
export function makePluginAPI(
|
||||
cache: CacheConfigurator<{
|
||||
envName: string,
|
||||
caller: CallerMetadata | void,
|
||||
targets: Targets,
|
||||
}>,
|
||||
): PluginAPI {
|
||||
export function makePresetAPI<SideChannel: Context.SimplePreset>(
|
||||
cache: CacheConfigurator<SideChannel>,
|
||||
): PresetAPI {
|
||||
const targets = () =>
|
||||
// We are using JSON.parse/JSON.stringify because it's only possible to cache
|
||||
// primitive values. We can safely stringify the targets object because it
|
||||
@ -86,6 +91,14 @@ export function makePluginAPI(
|
||||
return { ...makeConfigAPI(cache), targets };
|
||||
}
|
||||
|
||||
export function makePluginAPI<SideChannel: Context.SimplePlugin>(
|
||||
cache: CacheConfigurator<SideChannel>,
|
||||
): PluginAPI {
|
||||
const assumption = name => cache.using(data => data.assumptions[name]);
|
||||
|
||||
return { ...makePresetAPI(cache), assumption };
|
||||
}
|
||||
|
||||
function assertVersion(range: string | number): void {
|
||||
if (typeof range === "number") {
|
||||
if (!Number.isInteger(range)) {
|
||||
|
||||
@ -117,7 +117,9 @@ export default function* loadPrivatePartialConfig(
|
||||
const configChain = yield* buildRootChain(args, context);
|
||||
if (!configChain) return null;
|
||||
|
||||
const merged: ValidatedOptions = {};
|
||||
const merged: ValidatedOptions = {
|
||||
assumptions: {},
|
||||
};
|
||||
configChain.options.forEach(opts => {
|
||||
mergeOptions((merged: any), opts);
|
||||
});
|
||||
|
||||
@ -7,14 +7,13 @@ export function mergeOptions(
|
||||
source: ValidatedOptions | NormalizedOptions,
|
||||
): void {
|
||||
for (const k of Object.keys(source)) {
|
||||
if (k === "parserOpts" && source.parserOpts) {
|
||||
const parserOpts = source.parserOpts;
|
||||
const targetObj = (target.parserOpts = target.parserOpts || {});
|
||||
if (
|
||||
(k === "parserOpts" || k === "generatorOpts" || k === "assumptions") &&
|
||||
source[k]
|
||||
) {
|
||||
const parserOpts = source[k];
|
||||
const targetObj = target[k] || (target[k] = {});
|
||||
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);
|
||||
|
||||
@ -24,6 +24,8 @@ import type {
|
||||
TargetsListOrObject,
|
||||
} from "./options";
|
||||
|
||||
import { assumptionsNames } from "./options";
|
||||
|
||||
export type { RootPath } from "./options";
|
||||
|
||||
export type ValidatorSet = {
|
||||
@ -431,3 +433,37 @@ function assertBrowserVersion(loc: GeneralPath, value: mixed) {
|
||||
|
||||
throw new Error(`${msg(loc)} must be a string or an integer number`);
|
||||
}
|
||||
|
||||
export function assertAssumptions(
|
||||
loc: GeneralPath,
|
||||
value: mixed,
|
||||
): { [name: string]: boolean } | void {
|
||||
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: any);
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ import {
|
||||
type ValidatorSet,
|
||||
type Validator,
|
||||
type OptionPath,
|
||||
assertAssumptions,
|
||||
} from "./option-assertions";
|
||||
import type { UnloadedDescriptor } from "../config-descriptors";
|
||||
|
||||
@ -108,6 +109,9 @@ const COMMON_VALIDATORS: ValidatorSet = {
|
||||
passPerPreset: (assertBoolean: Validator<
|
||||
$PropertyType<ValidatedOptions, "passPerPreset">,
|
||||
>),
|
||||
assumptions: (assertAssumptions: Validator<
|
||||
$PropertyType<ValidatedOptions, "assumptions">,
|
||||
>),
|
||||
|
||||
env: (assertEnvSet: Validator<$PropertyType<ValidatedOptions, "env">>),
|
||||
overrides: (assertOverridesList: Validator<
|
||||
@ -221,6 +225,8 @@ export type ValidatedOptions = {
|
||||
plugins?: PluginList,
|
||||
passPerPreset?: boolean,
|
||||
|
||||
assumptions?: { [name: string]: boolean },
|
||||
|
||||
// browserslists-related options
|
||||
targets?: TargetsListOrObject,
|
||||
browserslistConfigFile?: ConfigFileSearch,
|
||||
@ -325,6 +331,11 @@ type EnvPath = $ReadOnly<{
|
||||
}>;
|
||||
export type NestingPath = RootPath | OverridesPath | EnvPath;
|
||||
|
||||
export const assumptionsNames = new Set<string>([
|
||||
"mutableTemplateObject",
|
||||
"setPublicClassFields",
|
||||
]);
|
||||
|
||||
function getSource(loc: NestingPath): OptionsSource {
|
||||
return loc.type === "root" ? loc.source : getSource(loc.parent);
|
||||
}
|
||||
|
||||
188
packages/babel-core/test/assumptions.js
Normal file
188
packages/babel-core/test/assumptions.js
Normal file
@ -0,0 +1,188 @@
|
||||
import { loadOptions as loadOptionsOrig, transformSync } from "../lib";
|
||||
|
||||
function loadOptions(opts) {
|
||||
return loadOptionsOrig({ cwd: __dirname, ...opts });
|
||||
}
|
||||
|
||||
function withAssumptions(assumptions) {
|
||||
return loadOptions({ assumptions });
|
||||
}
|
||||
|
||||
describe("assumptions", () => {
|
||||
it("throws if invalid name", () => {
|
||||
expect(() => withAssumptions({ foo: true })).toThrow(
|
||||
`.assumptions["foo"] is not a supported assumption.`,
|
||||
);
|
||||
|
||||
expect(() => withAssumptions({ setPublicClassFields: true })).not.toThrow();
|
||||
});
|
||||
|
||||
it("throws if not boolean", () => {
|
||||
expect(() => withAssumptions({ setPublicClassFields: "yes" })).toThrow(
|
||||
`.assumptions["setPublicClassFields"] must be a boolean.`,
|
||||
);
|
||||
|
||||
expect(() => withAssumptions({ setPublicClassFields: true })).not.toThrow();
|
||||
expect(() =>
|
||||
withAssumptions({ setPublicClassFields: false }),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
it("can be enabled by presets", () => {
|
||||
expect(
|
||||
loadOptions({
|
||||
assumptions: {
|
||||
setPublicClassFields: true,
|
||||
},
|
||||
presets: [() => ({ assumptions: { mutableTemplateObject: true } })],
|
||||
}).assumptions,
|
||||
).toEqual({
|
||||
setPublicClassFields: true,
|
||||
mutableTemplateObject: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("cannot be disabled by presets", () => {
|
||||
expect(() =>
|
||||
loadOptions({
|
||||
presets: [() => ({ assumptions: { mutableTemplateObject: false } })],
|
||||
}),
|
||||
).toThrow(
|
||||
` .assumptions["mutableTemplateObject"] cannot be set to 'false' inside presets.`,
|
||||
);
|
||||
});
|
||||
|
||||
it("can be queried from plugins", () => {
|
||||
let setPublicClassFields;
|
||||
let unknownAssumption;
|
||||
|
||||
transformSync("", {
|
||||
configFile: false,
|
||||
browserslistConfigFile: false,
|
||||
assumptions: {
|
||||
setPublicClassFields: true,
|
||||
},
|
||||
plugins: [
|
||||
api => {
|
||||
setPublicClassFields = api.assumption("setPublicClassFields");
|
||||
|
||||
// Unknown assumptions don't throw, so that plugins can keep compat
|
||||
// with older @babel/core versions when they introduce support for
|
||||
// a new assumption.
|
||||
unknownAssumption = api.assumption("unknownAssumption");
|
||||
|
||||
return {};
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(setPublicClassFields).toBe(true);
|
||||
expect(unknownAssumption).toBe(undefined);
|
||||
});
|
||||
|
||||
it("cannot be queried from presets", () => {
|
||||
let assumptionFn;
|
||||
|
||||
transformSync("", {
|
||||
configFile: false,
|
||||
browserslistConfigFile: false,
|
||||
presets: [
|
||||
api => {
|
||||
assumptionFn = api.assumption;
|
||||
return {};
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expect(assumptionFn).toBeUndefined();
|
||||
});
|
||||
|
||||
describe("plugin cache", () => {
|
||||
const makePlugin = () =>
|
||||
jest.fn(api => {
|
||||
api.assumption("setPublicClassFields");
|
||||
return {};
|
||||
});
|
||||
|
||||
const run = (plugin, assumptions) =>
|
||||
transformSync("", {
|
||||
assumptions,
|
||||
configFile: false,
|
||||
browserslistConfigFile: false,
|
||||
plugins: [plugin],
|
||||
});
|
||||
|
||||
it("is not invalidated when assumptions don't change", () => {
|
||||
const plugin = makePlugin();
|
||||
|
||||
run(plugin, {
|
||||
setPublicClassFields: true,
|
||||
mutableTemplateObject: false,
|
||||
});
|
||||
run(plugin, {
|
||||
setPublicClassFields: true,
|
||||
mutableTemplateObject: false,
|
||||
});
|
||||
|
||||
expect(plugin).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("is not invalidated when unused assumptions change", () => {
|
||||
const plugin = makePlugin();
|
||||
|
||||
run(plugin, {
|
||||
setPublicClassFields: true,
|
||||
mutableTemplateObject: false,
|
||||
});
|
||||
run(plugin, {
|
||||
setPublicClassFields: true,
|
||||
mutableTemplateObject: true,
|
||||
});
|
||||
|
||||
expect(plugin).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("is invalidated when used assumptions change", () => {
|
||||
const plugin = makePlugin();
|
||||
|
||||
run(plugin, {
|
||||
setPublicClassFields: true,
|
||||
mutableTemplateObject: false,
|
||||
});
|
||||
run(plugin, {
|
||||
setPublicClassFields: false,
|
||||
mutableTemplateObject: true,
|
||||
});
|
||||
|
||||
expect(plugin).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("is invalidated when used assumptions are added", () => {
|
||||
const plugin = makePlugin();
|
||||
|
||||
run(plugin, {
|
||||
mutableTemplateObject: false,
|
||||
});
|
||||
run(plugin, {
|
||||
mutableTemplateObject: false,
|
||||
setPublicClassFields: true,
|
||||
});
|
||||
|
||||
expect(plugin).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("is invalidated when used assumptions are removed", () => {
|
||||
const plugin = makePlugin();
|
||||
|
||||
run(plugin, {
|
||||
setPublicClassFields: true,
|
||||
mutableTemplateObject: false,
|
||||
});
|
||||
run(plugin, {
|
||||
mutableTemplateObject: true,
|
||||
});
|
||||
|
||||
expect(plugin).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -985,6 +985,7 @@ describe("buildConfigChain", function () {
|
||||
presets: [],
|
||||
cloneInputAst: true,
|
||||
targets: {},
|
||||
assumptions: {},
|
||||
});
|
||||
const realEnv = process.env.NODE_ENV;
|
||||
const realBabelEnv = process.env.BABEL_ENV;
|
||||
|
||||
@ -26,6 +26,9 @@ const apiPolyfills = {
|
||||
targets: () => () => {
|
||||
return {};
|
||||
},
|
||||
// This is supported starting from Babel 7.13
|
||||
// TODO(Babel 8): Remove this polyfill
|
||||
assumption: () => () => {},
|
||||
};
|
||||
|
||||
function copyApiObject(api) {
|
||||
|
||||
@ -244,7 +244,7 @@ export default function normalizeOptions(opts: Options) {
|
||||
opts.ignoreBrowserslistConfig,
|
||||
false,
|
||||
),
|
||||
loose: v.validateBooleanOption(TopLevelOptions.loose, opts.loose, false),
|
||||
loose: v.validateBooleanOption(TopLevelOptions.loose, opts.loose),
|
||||
modules: validateModulesOption(opts.modules),
|
||||
shippedProposals: v.validateBooleanOption(
|
||||
TopLevelOptions.shippedProposals,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user