diff --git a/packages/babel-core/package.json b/packages/babel-core/package.json index 53f9558aa365..231b20b137d3 100644 --- a/packages/babel-core/package.json +++ b/packages/babel-core/package.json @@ -39,13 +39,16 @@ }, "browser": { "./lib/config/files/index.js": "./lib/config/files/index-browser.js", + "./lib/config/resolve-targets.js": "./lib/config/resolve-targets-browser.js", "./lib/transform-file.js": "./lib/transform-file-browser.js", "./src/config/files/index.js": "./src/config/files/index-browser.js", + "./src/config/resolve-targets.js": "./src/config/resolve-targets-browser.js", "./src/transform-file.js": "./src/transform-file-browser.js" }, "dependencies": { "@babel/code-frame": "workspace:^7.12.13", "@babel/generator": "workspace:^7.12.17", + "@babel/helper-compilation-targets": "workspace:^7.12.17", "@babel/helper-module-transforms": "workspace:^7.12.17", "@babel/helpers": "workspace:^7.12.17", "@babel/parser": "workspace:^7.12.17", @@ -55,7 +58,7 @@ "convert-source-map": "^1.7.0", "debug": "^4.1.0", "escape-string-regexp": "condition:BABEL_8_BREAKING ? ^4.0.0 : ", - "gensync": "^1.0.0-beta.1", + "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", "lodash": "^4.17.19", "semver": "^5.4.1", diff --git a/packages/babel-core/src/config/cache-contexts.js b/packages/babel-core/src/config/cache-contexts.js new file mode 100644 index 000000000000..969362c0c42c --- /dev/null +++ b/packages/babel-core/src/config/cache-contexts.js @@ -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 }, +}; diff --git a/packages/babel-core/src/config/config-chain.js b/packages/babel-core/src/config/config-chain.js index 350111a1a41b..79a3d517859c 100644 --- a/packages/babel-core/src/config/config-chain.js +++ b/packages/babel-core/src/config/config-chain.js @@ -154,7 +154,7 @@ export function* buildRootChain( programmaticLogger, ); if (!programmaticChain) return null; - const programmaticReport = programmaticLogger.output(); + const programmaticReport = yield* programmaticLogger.output(); let configFile; if (typeof opts.configFile === "string") { @@ -186,7 +186,7 @@ export function* buildRootChain( configFileLogger, ); if (!result) return null; - configReport = configFileLogger.output(); + configReport = yield* configFileLogger.output(); // Allow config files to toggle `.babelrc` resolution on and off and // specify where the roots are. @@ -244,7 +244,7 @@ export function* buildRootChain( if (!result) { isIgnored = true; } else { - babelRcReport = babelrcLogger.output(); + babelRcReport = yield* babelrcLogger.output(); mergeChain(fileChain, result); } } @@ -599,7 +599,7 @@ function makeChainWalker({ } logger(config, index, envName); - mergeChainOpts(chain, config); + yield* mergeChainOpts(chain, config); } return chain; }; @@ -657,13 +657,13 @@ function mergeChain(target: ConfigChain, source: ConfigChain): ConfigChain { return target; } -function mergeChainOpts( +function* mergeChainOpts( target: ConfigChain, { options, plugins, presets }: OptionsAndDescriptors, -): ConfigChain { +): Handler { target.options.push(options); - target.plugins.push(...plugins()); - target.presets.push(...presets()); + target.plugins.push(...(yield* plugins())); + target.presets.push(...(yield* presets())); return target; } diff --git a/packages/babel-core/src/config/config-descriptors.js b/packages/babel-core/src/config/config-descriptors.js index c203dbc74c46..59f9e462c7fe 100644 --- a/packages/babel-core/src/config/config-descriptors.js +++ b/packages/babel-core/src/config/config-descriptors.js @@ -1,5 +1,7 @@ // @flow +import gensync, { type Handler } from "gensync"; + import { loadPlugin, loadPreset } from "./files"; import { getItemDescriptor } from "./item"; @@ -7,6 +9,7 @@ import { getItemDescriptor } from "./item"; import { makeWeakCacheSync, makeStrongCacheSync, + makeStrongCache, type CacheConfigurator, } from "./caching"; @@ -21,8 +24,8 @@ import type { // the options object actually ends up being applicable. export type OptionsAndDescriptors = { options: ValidatedOptions, - plugins: () => Array, - presets: () => Array, + plugins: () => Handler>, + presets: () => Handler>, }; // Represents a plugin or presets at a given location in a config object. @@ -63,6 +66,11 @@ export type ValidatedFile = { options: ValidatedOptions, }; +// eslint-disable-next-line require-yield +function* handlerOf(value: T): Handler { + return value; +} + /** * Create a set of descriptors from a given options object, preserving * descriptor identity based on the identity of the plugin/preset arrays @@ -78,13 +86,13 @@ export function createCachedDescriptors( options, plugins: plugins ? () => createCachedPluginDescriptors(plugins, dirname)(alias) - : () => [], + : () => handlerOf([]), presets: presets ? () => createCachedPresetDescriptors(presets, dirname)(alias)( !!passPerPreset, ) - : () => [], + : () => handlerOf([]), }; } @@ -105,9 +113,9 @@ export function createUncachedDescriptors( return { options, - plugins: () => { + *plugins() { if (!plugins) { - plugins = createPluginDescriptors( + plugins = yield* createPluginDescriptors( options.plugins || [], dirname, alias, @@ -115,9 +123,9 @@ export function createUncachedDescriptors( } return plugins; }, - presets: () => { + *presets() { if (!presets) { - presets = createPresetDescriptors( + presets = yield* createPresetDescriptors( options.presets || [], dirname, alias, @@ -134,14 +142,22 @@ const createCachedPresetDescriptors = makeWeakCacheSync( (items: PluginList, cache: CacheConfigurator) => { const dirname = cache.using(dir => dir); return makeStrongCacheSync((alias: string) => - makeStrongCacheSync((passPerPreset: boolean) => - createPresetDescriptors(items, dirname, alias, passPerPreset).map( + makeStrongCache(function* ( + passPerPreset: boolean, + ): Handler> { + const descriptors = yield* createPresetDescriptors( + items, + dirname, + alias, + passPerPreset, + ); + return descriptors.map( // Items are cached using the overall preset array identity when // possibly, but individual descriptors are also cached if a match // can be found in the previously-used descriptor lists. desc => loadCachedDescriptor(PRESET_DESCRIPTOR_CACHE, desc), - ), - ), + ); + }), ); }, ); @@ -150,14 +166,17 @@ const PLUGIN_DESCRIPTOR_CACHE = new WeakMap(); const createCachedPluginDescriptors = makeWeakCacheSync( (items: PluginList, cache: CacheConfigurator) => { const dirname = cache.using(dir => dir); - return makeStrongCacheSync((alias: string) => - createPluginDescriptors(items, dirname, alias).map( + return makeStrongCache(function* ( + alias: string, + ): Handler> { + const descriptors = yield* createPluginDescriptors(items, dirname, alias); + return descriptors.map( // Items are cached using the overall plugin array identity when // possibly, but individual descriptors are also cached if a match // can be found in the previously-used descriptor lists. desc => loadCachedDescriptor(PLUGIN_DESCRIPTOR_CACHE, desc), - ), - ); + ); + }); }, ); @@ -205,36 +224,44 @@ function loadCachedDescriptor( return desc; } -function createPresetDescriptors( +function* createPresetDescriptors( items: PluginList, dirname: string, alias: string, passPerPreset: boolean, -): Array { - return createDescriptors("preset", items, dirname, alias, passPerPreset); +): Handler> { + return yield* createDescriptors( + "preset", + items, + dirname, + alias, + passPerPreset, + ); } -function createPluginDescriptors( +function* createPluginDescriptors( items: PluginList, dirname: string, alias: string, -): Array { - return createDescriptors("plugin", items, dirname, alias); +): Handler> { + return yield* createDescriptors("plugin", items, dirname, alias); } -function createDescriptors( +function* createDescriptors( type: "plugin" | "preset", items: PluginList, dirname: string, alias: string, ownPass?: boolean, -): Array { - const descriptors = items.map((item, index) => - createDescriptor(item, dirname, { - type, - alias: `${alias}$${index}`, - ownPass: !!ownPass, - }), +): Handler> { + const descriptors = yield* gensync.all( + items.map((item, index) => + createDescriptor(item, dirname, { + type, + alias: `${alias}$${index}`, + ownPass: !!ownPass, + }), + ), ); assertNoDuplicates(descriptors); @@ -245,7 +272,7 @@ function createDescriptors( /** * Given a plugin/preset item, resolve it into a standard format. */ -export function createDescriptor( +export function* createDescriptor( pair: PluginItem, dirname: string, { @@ -257,7 +284,7 @@ export function createDescriptor( alias: string, ownPass?: boolean, }, -): UnloadedDescriptor { +): Handler { const desc = getItemDescriptor(pair); if (desc) { return desc; @@ -285,7 +312,7 @@ export function createDescriptor( const resolver = type === "plugin" ? loadPlugin : loadPreset; const request = value; - ({ filepath, value } = resolver(value, dirname)); + ({ filepath, value } = yield* resolver(value, dirname)); file = { request, diff --git a/packages/babel-core/src/config/files/configuration.js b/packages/babel-core/src/config/files/configuration.js index 28ce05a380fc..45162669757e 100644 --- a/packages/babel-core/src/config/files/configuration.js +++ b/packages/babel-core/src/config/files/configuration.js @@ -9,7 +9,7 @@ import { makeWeakCacheSync, type CacheConfigurator, } from "../caching"; -import makeAPI, { type PluginAPI } from "../helpers/config-api"; +import { makeConfigAPI, type ConfigAPI } from "../helpers/config-api"; import { makeStaticFileCache } from "./utils"; import loadCjsOrMjsDefault from "./module-types"; import pathPatternToRegex from "../pattern-to-regex"; @@ -203,7 +203,7 @@ const readConfigJS = makeStrongCache(function* readConfigJS( let assertCache = false; if (typeof options === "function") { yield* []; // if we want to make it possible to use async configs - options = ((options: any): (api: PluginAPI) => {})(makeAPI(cache)); + options = ((options: any): (api: ConfigAPI) => {})(makeConfigAPI(cache)); assertCache = true; } diff --git a/packages/babel-core/src/config/files/index-browser.js b/packages/babel-core/src/config/files/index-browser.js index 2fb0b6eba1b8..cdac53a626c2 100644 --- a/packages/babel-core/src/config/files/index-browser.js +++ b/packages/babel-core/src/config/files/index-browser.js @@ -80,7 +80,7 @@ export function resolvePreset(name: string, dirname: string): string | null { export function loadPlugin( name: string, dirname: string, -): { filepath: string, value: mixed } { +): Handler<{ filepath: string, value: mixed }> { throw new Error( `Cannot load plugin ${name} relative to ${dirname} in a browser`, ); @@ -89,7 +89,7 @@ export function loadPlugin( export function loadPreset( name: string, dirname: string, -): { filepath: string, value: mixed } { +): Handler<{ filepath: string, value: mixed }> { throw new Error( `Cannot load preset ${name} relative to ${dirname} in a browser`, ); diff --git a/packages/babel-core/src/config/files/module-types.js b/packages/babel-core/src/config/files/module-types.js index 4c761597f9f1..0e6d4a431886 100644 --- a/packages/babel-core/src/config/files/module-types.js +++ b/packages/babel-core/src/config/files/module-types.js @@ -12,13 +12,15 @@ try { export default function* loadCjsOrMjsDefault( filepath: string, asyncError: string, + // TODO(Babel 8): Remove this + fallbackToTranspiledModule: boolean = false, ): Handler { switch (guessJSModuleType(filepath)) { case "cjs": - return loadCjsDefault(filepath); + return loadCjsDefault(filepath, fallbackToTranspiledModule); case "unknown": try { - return loadCjsDefault(filepath); + return loadCjsDefault(filepath, fallbackToTranspiledModule); } catch (e) { if (e.code !== "ERR_REQUIRE_ESM") throw e; } @@ -42,10 +44,12 @@ function guessJSModuleType(filename: string): "cjs" | "mjs" | "unknown" { } } -function loadCjsDefault(filepath: string) { +function loadCjsDefault(filepath: string, fallbackToTranspiledModule: boolean) { const module = (require(filepath): mixed); - // TODO (Babel 8): Remove "undefined" fallback - return module?.__esModule ? module.default || undefined : module; + return module?.__esModule + ? // TODO (Babel 8): Remove "module" and "undefined" fallback + module.default || (fallbackToTranspiledModule ? module : undefined) + : module; } async function loadMjsDefault(filepath: string) { diff --git a/packages/babel-core/src/config/files/plugins.js b/packages/babel-core/src/config/files/plugins.js index 298843e2d609..747592cad9bd 100644 --- a/packages/babel-core/src/config/files/plugins.js +++ b/packages/babel-core/src/config/files/plugins.js @@ -6,6 +6,8 @@ import buildDebug from "debug"; import path from "path"; +import { type Handler } from "gensync"; +import loadCjsOrMjsDefault from "./module-types"; const debug = buildDebug("babel:config:loading:files:plugins"); @@ -26,31 +28,31 @@ export function resolvePreset(name: string, dirname: string): string | null { return resolveStandardizedName("preset", name, dirname); } -export function loadPlugin( +export function* loadPlugin( name: string, dirname: string, -): { filepath: string, value: mixed } { +): Handler<{ filepath: string, value: mixed }> { const filepath = resolvePlugin(name, dirname); if (!filepath) { throw new Error(`Plugin ${name} not found relative to ${dirname}`); } - const value = requireModule("plugin", filepath); + const value = yield* requireModule("plugin", filepath); debug("Loaded plugin %o from %o.", name, dirname); return { filepath, value }; } -export function loadPreset( +export function* loadPreset( name: string, dirname: string, -): { filepath: string, value: mixed } { +): Handler<{ filepath: string, value: mixed }> { const filepath = resolvePreset(name, dirname); if (!filepath) { throw new Error(`Preset ${name} not found relative to ${dirname}`); } - const value = requireModule("preset", filepath); + const value = yield* requireModule("preset", filepath); debug("Loaded preset %o from %o.", name, dirname); @@ -145,7 +147,7 @@ function resolveStandardizedName( } const LOADING_MODULES = new Set(); -function requireModule(type: string, name: string): mixed { +function* requireModule(type: string, name: string): Handler { if (LOADING_MODULES.has(name)) { throw new Error( `Reentrant ${type} detected trying to load "${name}". This module is not ignored ` + @@ -156,7 +158,19 @@ function requireModule(type: string, name: string): mixed { try { LOADING_MODULES.add(name); - return require(name); + return (yield* loadCjsOrMjsDefault( + name, + `You appear to be using a native ECMAScript module ${type}, ` + + "which is only supported when running Babel asynchronously.", + // For backward compatiblity, we need to support malformed presets + // defined as separate named exports rather than a single default + // export. + // See packages/babel-core/test/fixtures/option-manager/presets/es2015_named.js + true, + ): mixed); + } catch (err) { + err.message = `[BABEL]: ${err.message} (While processing: ${name})`; + throw err; } finally { LOADING_MODULES.delete(name); } diff --git a/packages/babel-core/src/config/full.js b/packages/babel-core/src/config/full.js index 75fbe293c7c9..1e1855184e10 100644 --- a/packages/babel-core/src/config/full.js +++ b/packages/babel-core/src/config/full.js @@ -1,7 +1,7 @@ // @flow import gensync, { type Handler } from "gensync"; -import { forwardAsync } from "../gensync-utils/async"; +import { forwardAsync, maybeAsync, isThenable } from "../gensync-utils/async"; import { mergeOptions } from "./util"; import * as context from "../index"; @@ -22,16 +22,17 @@ import { } from "./caching"; import { validate, - type CallerMetadata, checkNoUnwrappedItemOptionPairs, type PluginItem, } from "./validation/options"; import { validatePluginObject } from "./validation/plugins"; -import makeAPI 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: {}, @@ -50,13 +51,6 @@ export type { Plugin }; export type PluginPassList = Array; export type PluginPasses = Array; -// 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, -}; - export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig( inputOpts: mixed, ): Handler { @@ -78,6 +72,12 @@ export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig( throw new Error("Assertion failure - plugins and presets exist"); } + const pluginContext: Context.FullPlugin = { + ...context, + targets: options.targets, + assumptions: options.assumptions ?? {}, + }; + const toDescriptor = (item: PluginItem) => { const desc = getItemDescriptor(item); if (!desc) { @@ -112,12 +112,12 @@ export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig( // in the previous pass. if (descriptor.ownPass) { presets.push({ - preset: yield* loadPresetDescriptor(descriptor, context), + preset: yield* loadPresetDescriptor(descriptor, pluginContext), pass: [], }); } else { presets.unshift({ - preset: yield* loadPresetDescriptor(descriptor, context), + preset: yield* loadPresetDescriptor(descriptor, pluginContext), pass: pluginDescriptorsPass, }); } @@ -172,7 +172,7 @@ export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig( const descriptor: UnloadedDescriptor = descs[i]; if (descriptor.options !== false) { try { - pass.push(yield* loadPluginDescriptor(descriptor, context)); + pass.push(yield* loadPluginDescriptor(descriptor, pluginContext)); } catch (e) { if (e.code === "BABEL_UNKNOWN_PLUGIN_PROPERTY") { // print special message for `plugins: ["@babel/foo", { foo: "option" }]` @@ -217,55 +217,72 @@ function enhanceError(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, -): Handler { - // Disabled presets should already have been filtered out - if (options === false) throw new Error("Assertion failure"); - - options = options || {}; - - let item = value; - if (typeof value === "function") { - const api = { - ...context, - ...makeAPI(cache), - }; - try { - item = value(api, options, dirname); - } catch (e) { - if (alias) { - e.message += ` (While processing: ${JSON.stringify(alias)})`; +const makeDescriptorLoader = ( + apiFactory: (cache: CacheConfigurator) => API, +): ((d: UnloadedDescriptor, c: Context) => Handler) => + makeWeakCache(function* ( + { value, options, dirname, alias }: UnloadedDescriptor, + cache: CacheConfigurator, + ): Handler { + // Disabled presets should already have been filtered out + if (options === false) throw new Error("Assertion failure"); + + 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`, + ); + + 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 (typeof item.then === "function") { - 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 an async 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.`, - ); - } + 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( + makePluginAPI, +); +const presetDescriptorLoader = makeDescriptorLoader( + makePresetAPI, +); /** * Instantiate a plugin for the given descriptor, returning the plugin/options pair. */ function* loadPluginDescriptor( descriptor: UnloadedDescriptor, - context: SimpleContext, + context: Context.SimplePlugin, ): Handler { if (descriptor.value instanceof Plugin) { if (descriptor.options) { @@ -278,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, + cache: CacheConfigurator, ): Handler { const pluginObj = validatePluginObject(value); @@ -368,9 +385,11 @@ const validatePreset = ( */ function* loadPresetDescriptor( descriptor: UnloadedDescriptor, - context: ConfigContext, + context: Context.FullPreset, ): Handler { - const preset = instantiatePreset(yield* loadDescriptor(descriptor, context)); + const preset = instantiatePreset( + yield* presetDescriptorLoader(descriptor, context), + ); validatePreset(preset, context, descriptor); return yield* buildPresetChain(preset, context); } diff --git a/packages/babel-core/src/config/helpers/config-api.js b/packages/babel-core/src/config/helpers/config-api.js index fea73139af68..24dfedc9f817 100644 --- a/packages/babel-core/src/config/helpers/config-api.js +++ b/packages/babel-core/src/config/helpers/config-api.js @@ -1,6 +1,8 @@ // @flow import semver from "semver"; +import type { Targets } from "@babel/helper-compilation-targets"; + import { version as coreVersion } from "../../"; import { assertSimpleType, @@ -11,6 +13,8 @@ import { import type { CallerMetadata } from "../validation/options"; +import * as Context from "../cache-contexts"; + type EnvFunction = { (): string, ((string) => T): T, @@ -20,7 +24,11 @@ type EnvFunction = { type CallerFactory = ((CallerMetadata | void) => mixed) => SimpleType; -export type PluginAPI = {| +type TargetsFunction = () => Targets; + +type AssumptionFunction = (name: string) => boolean | void; + +export type ConfigAPI = {| version: string, cache: SimpleCacheConfigurator, env: EnvFunction, @@ -29,9 +37,19 @@ export type PluginAPI = {| caller?: CallerFactory, |}; -export default function makeAPI( - cache: CacheConfigurator<{ envName: string, caller: CallerMetadata | void }>, -): PluginAPI { +export type PresetAPI = {| + ...ConfigAPI, + targets: TargetsFunction, +|}; + +export type PluginAPI = {| + ...PresetAPI, + assumption: AssumptionFunction, +|}; + +export function makeConfigAPI( + cache: CacheConfigurator, +): ConfigAPI { const env: any = value => cache.using(data => { if (typeof value === "undefined") return data.envName; @@ -61,6 +79,26 @@ export default function makeAPI( }; } +export function makePresetAPI( + cache: CacheConfigurator, +): 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 + // only contains strings as its properties. + // Please make the Record and Tuple proposal happen! + JSON.parse(cache.using(data => JSON.stringify(data.targets))); + return { ...makeConfigAPI(cache), targets }; +} + +export function makePluginAPI( + cache: CacheConfigurator, +): 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)) { diff --git a/packages/babel-core/src/config/item.js b/packages/babel-core/src/config/item.js index e344732454f5..cf04f1bc40d3 100644 --- a/packages/babel-core/src/config/item.js +++ b/packages/babel-core/src/config/item.js @@ -2,6 +2,7 @@ /*:: declare var invariant; */ +import type { Handler } from "gensync"; import type { PluginTarget, PluginOptions } from "./validation/options"; import path from "path"; @@ -20,7 +21,7 @@ export function createItemFromDescriptor(desc: UnloadedDescriptor): ConfigItem { * ideally, as recreating the config item will mean re-resolving the item * and re-evaluating the plugin/preset function. */ -export function createConfigItem( +export function* createConfigItem( value: | PluginTarget | [PluginTarget, PluginOptions] @@ -32,8 +33,8 @@ export function createConfigItem( dirname?: string, type?: "preset" | "plugin", } = {}, -): ConfigItem { - const descriptor = createDescriptor(value, path.resolve(dirname), { +): Handler { + const descriptor = yield* createDescriptor(value, path.resolve(dirname), { type, alias: "programmatic item", }); diff --git a/packages/babel-core/src/config/partial.js b/packages/babel-core/src/config/partial.js index b42b4ec042a3..5d74daa00ec0 100644 --- a/packages/babel-core/src/config/partial.js +++ b/packages/babel-core/src/config/partial.js @@ -14,6 +14,7 @@ import { getEnv } from "./helpers/environment"; import { validate, type ValidatedOptions, + type NormalizedOptions, type RootMode, } from "./validation/options"; @@ -24,6 +25,7 @@ import { type ConfigFile, type IgnoreFile, } from "./files"; +import { resolveTargets } from "./resolve-targets"; function* resolveRootMode( rootDir: string, @@ -61,7 +63,7 @@ function* resolveRootMode( } type PrivPartialConfig = { - options: ValidatedOptions, + options: NormalizedOptions, context: ConfigContext, fileHandling: FileHandling, ignore: IgnoreFile | void, @@ -115,30 +117,38 @@ export default function* loadPrivatePartialConfig( const configChain = yield* buildRootChain(args, context); if (!configChain) return null; - const options = {}; + const merged: ValidatedOptions = { + assumptions: {}, + }; configChain.options.forEach(opts => { - mergeOptions(options, opts); + mergeOptions((merged: any), opts); }); - // 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. - options.cloneInputAst = cloneInputAst; - options.babelrc = false; - options.configFile = false; - options.passPerPreset = false; - options.envName = context.envName; - options.cwd = context.cwd; - options.root = context.root; - options.filename = - typeof context.filename === "string" ? context.filename : undefined; - - options.plugins = configChain.plugins.map(descriptor => - createItemFromDescriptor(descriptor), - ); - options.presets = configChain.presets.map(descriptor => - createItemFromDescriptor(descriptor), - ); + const options: NormalizedOptions = { + ...merged, + targets: resolveTargets(merged, absoluteRootDir, filename), + + // 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. + cloneInputAst, + babelrc: false, + configFile: false, + browserslistConfigFile: false, + passPerPreset: false, + envName: context.envName, + cwd: context.cwd, + root: context.root, + filename: + typeof context.filename === "string" ? context.filename : undefined, + + plugins: configChain.plugins.map(descriptor => + createItemFromDescriptor(descriptor), + ), + presets: configChain.presets.map(descriptor => + createItemFromDescriptor(descriptor), + ), + }; return { options, @@ -201,7 +211,7 @@ class PartialConfig { * These properties are public, so any changes to them should be considered * a breaking change to Babel's API. */ - options: ValidatedOptions; + options: NormalizedOptions; babelrc: string | void; babelignore: string | void; config: string | void; @@ -209,7 +219,7 @@ class PartialConfig { files: Set; constructor( - options: ValidatedOptions, + options: NormalizedOptions, babelrc: string | void, ignore: string | void, config: string | void, diff --git a/packages/babel-core/src/config/printer.js b/packages/babel-core/src/config/printer.js index 9f9d65787694..b1f1072eddda 100644 --- a/packages/babel-core/src/config/printer.js +++ b/packages/babel-core/src/config/printer.js @@ -1,5 +1,7 @@ // @flow +import gensync, { type Handler } from "gensync"; + import type { OptionsAndDescriptors, UnloadedDescriptor, @@ -49,17 +51,17 @@ const Formatter = { return loc; }, - optionsAndDescriptors(opt: OptionsAndDescriptors) { + *optionsAndDescriptors(opt: OptionsAndDescriptors) { const content = { ...opt.options }; // overrides and env will be printed as separated config items delete content.overrides; delete content.env; // resolve to descriptors - const pluginDescriptors = [...opt.plugins()]; + const pluginDescriptors = [...(yield* opt.plugins())]; if (pluginDescriptors.length) { content.plugins = pluginDescriptors.map(d => descriptorToConfig(d)); } - const presetDescriptors = [...opt.presets()]; + const presetDescriptors = [...(yield* opt.presets())]; if (presetDescriptors.length) { content.presets = [...presetDescriptors].map(d => descriptorToConfig(d)); } @@ -114,7 +116,7 @@ export class ConfigPrinter { }); }; } - static format(config: PrintableConfig): string { + static *format(config: PrintableConfig): Handler { let title = Formatter.title( config.type, config.callerName, @@ -122,12 +124,15 @@ export class ConfigPrinter { ); const loc = Formatter.loc(config.index, config.envName); if (loc) title += ` ${loc}`; - const content = Formatter.optionsAndDescriptors(config.content); + const content = yield* Formatter.optionsAndDescriptors(config.content); return `${title}\n${content}`; } - output(): string { + *output(): Handler { if (this._stack.length === 0) return ""; - return this._stack.map(s => ConfigPrinter.format(s)).join("\n\n"); + const configs = yield* gensync.all( + this._stack.map(s => ConfigPrinter.format(s)), + ); + return configs.join("\n\n"); } } diff --git a/packages/babel-core/src/config/resolve-targets-browser.js b/packages/babel-core/src/config/resolve-targets-browser.js new file mode 100644 index 000000000000..751b4a2a160e --- /dev/null +++ b/packages/babel-core/src/config/resolve-targets-browser.js @@ -0,0 +1,26 @@ +// @flow + +import type { ValidatedOptions } from "./validation/options"; +import getTargets, { type Targets } from "@babel/helper-compilation-targets"; + +export function resolveTargets( + options: ValidatedOptions, + // eslint-disable-next-line no-unused-vars + root: string, + // eslint-disable-next-line no-unused-vars + filename: string | void, +): Targets { + let { targets } = options; + if (typeof targets === "string" || Array.isArray(targets)) { + targets = { browsers: targets }; + } + // $FlowIgnore it thinks that targets.esmodules doesn't exist. + if (targets && targets.esmodules) { + targets = { ...targets, esmodules: "intersect" }; + } + + return getTargets((targets: any), { + ignoreBrowserslistConfig: true, + browserslistEnv: options.browserslistEnv, + }); +} diff --git a/packages/babel-core/src/config/resolve-targets.js b/packages/babel-core/src/config/resolve-targets.js new file mode 100644 index 000000000000..b65bab7ff3e9 --- /dev/null +++ b/packages/babel-core/src/config/resolve-targets.js @@ -0,0 +1,39 @@ +// @flow + +import typeof * as browserType from "./resolve-targets-browser"; +import typeof * as nodeType from "./resolve-targets"; + +// Kind of gross, but essentially asserting that the exports of this module are the same as the +// exports of index-browser, since this file may be replaced at bundle time with index-browser. +((({}: any): $Exact): $Exact); + +import type { ValidatedOptions } from "./validation/options"; +import path from "path"; +import getTargets, { type Targets } from "@babel/helper-compilation-targets"; + +export function resolveTargets( + options: ValidatedOptions, + root: string, + filename: string | void, +): Targets { + let { targets } = options; + if (typeof targets === "string" || Array.isArray(targets)) { + targets = { browsers: targets }; + } + // $FlowIgnore it thinks that targets.esmodules doesn't exist. + if (targets && targets.esmodules) { + targets = { ...targets, esmodules: "intersect" }; + } + + let configFile; + if (typeof options.browserslistConfigFile === "string") { + configFile = path.resolve(root, options.browserslistConfigFile); + } + + return getTargets((targets: any), { + ignoreBrowserslistConfig: options.browserslistConfigFile === false, + configFile, + configPath: filename ?? root, + browserslistEnv: options.browserslistEnv, + }); +} diff --git a/packages/babel-core/src/config/util.js b/packages/babel-core/src/config/util.js index b9d3af143dd3..891e09c90975 100644 --- a/packages/babel-core/src/config/util.js +++ b/packages/babel-core/src/config/util.js @@ -1,20 +1,19 @@ // @flow -import type { ValidatedOptions } from "./validation/options"; +import type { ValidatedOptions, NormalizedOptions } from "./validation/options"; export function mergeOptions( target: ValidatedOptions, - source: ValidatedOptions, + 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); diff --git a/packages/babel-core/src/config/validation/option-assertions.js b/packages/babel-core/src/config/validation/option-assertions.js index f3962f18945f..4a3d5f7410dc 100644 --- a/packages/babel-core/src/config/validation/option-assertions.js +++ b/packages/babel-core/src/config/validation/option-assertions.js @@ -1,5 +1,10 @@ // @flow +import { + isBrowsersQueryValid, + TargetNames, +} from "@babel/helper-compilation-targets"; + import type { ConfigFileSearch, BabelrcSearch, @@ -16,8 +21,11 @@ import type { NestingPath, CallerMetadata, RootMode, + TargetsListOrObject, } from "./options"; +import { assumptionsNames } from "./options"; + export type { RootPath } from "./options"; export type ValidatorSet = { @@ -373,3 +381,89 @@ function assertPluginTarget(loc: GeneralPath, value: mixed): PluginTarget { } return value; } + +export function assertTargets( + loc: GeneralPath, + value: mixed, +): TargetsListOrObject { + if (isBrowsersQueryValid(value)) return (value: any); + + 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.hasOwnProperty.call(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: any); +} + +function assertBrowsersList(loc: GeneralPath, value: mixed) { + if (value !== undefined && !isBrowsersQueryValid(value)) { + throw new Error( + `${msg(loc)} must be undefined, a string or an array of strings`, + ); + } +} + +function assertBrowserVersion(loc: GeneralPath, value: mixed) { + 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`); +} + +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); +} diff --git a/packages/babel-core/src/config/validation/options.js b/packages/babel-core/src/config/validation/options.js index 27caf3bcc1e2..6289286e8ed5 100644 --- a/packages/babel-core/src/config/validation/options.js +++ b/packages/babel-core/src/config/validation/options.js @@ -1,5 +1,7 @@ // @flow +import type { InputTargets, Targets } from "@babel/helper-compilation-targets"; + import type { ConfigItem } from "../item"; import Plugin from "../plugin"; @@ -23,9 +25,11 @@ import { assertSourceMaps, assertCompact, assertSourceType, + assertTargets, type ValidatorSet, type Validator, type OptionPath, + assertAssumptions, } from "./option-assertions"; import type { UnloadedDescriptor } from "../config-descriptors"; @@ -77,6 +81,16 @@ const NONPRESET_VALIDATORS: ValidatorSet = { $PropertyType, >), only: (assertIgnoreList: Validator<$PropertyType>), + + targets: (assertTargets: Validator< + $PropertyType, + >), + browserslistConfigFile: (assertConfigFileSearch: Validator< + $PropertyType, + >), + browserslistEnv: (assertString: Validator< + $PropertyType, + >), }; const COMMON_VALIDATORS: ValidatorSet = { @@ -95,6 +109,9 @@ const COMMON_VALIDATORS: ValidatorSet = { passPerPreset: (assertBoolean: Validator< $PropertyType, >), + assumptions: (assertAssumptions: Validator< + $PropertyType, + >), env: (assertEnvSet: Validator<$PropertyType>), overrides: (assertOverridesList: Validator< @@ -208,6 +225,13 @@ export type ValidatedOptions = { plugins?: PluginList, passPerPreset?: boolean, + assumptions?: { [name: string]: boolean }, + + // browserslists-related options + targets?: TargetsListOrObject, + browserslistConfigFile?: ConfigFileSearch, + browserslistEnv?: string, + // Options for @babel/generator retainLines?: boolean, comments?: boolean, @@ -241,6 +265,11 @@ export type ValidatedOptions = { generatorOpts?: {}, }; +export type NormalizedOptions = { + ...$Diff, + +targets: Targets, +}; + export type CallerMetadata = { // If 'caller' is specified, require that the name is given for debugging // messages. @@ -273,6 +302,11 @@ export type CompactOption = boolean | "auto"; export type RootInputSourceMapOption = {} | boolean; export type RootMode = "root" | "upward" | "upward-optional"; +export type TargetsListOrObject = + | Targets + | InputTargets + | $PropertyType; + export type OptionsSource = | "arguments" | "configfile" @@ -297,6 +331,29 @@ type EnvPath = $ReadOnly<{ }>; export type NestingPath = RootPath | OverridesPath | EnvPath; +export const assumptionsNames = new Set([ + "arrayLikeIsIterable", + "constantReexports", + "constantSuper", + "enumerableModuleMeta", + "ignoreFunctionLength", + "ignoreToPrimitiveHint", + "iterableIsArray", + "mutableTemplateObject", + "noClassCalls", + "noDocumentAll", + "noNewArrows", + "objectRestNoSymbols", + "privateFieldsAsProperties", + "pureGetters", + "setClassMethods", + "setComputedProperties", + "setPublicClassFields", + "setSpreadProperties", + "skipForOfIteratorClosing", + "superIsCallableConstructor", +]); + function getSource(loc: NestingPath): OptionsSource { return loc.type === "root" ? loc.source : getSource(loc.parent); } diff --git a/packages/babel-core/test/api.js b/packages/babel-core/test/api.js index d715b63862a6..8f09a707c48d 100644 --- a/packages/babel-core/test/api.js +++ b/packages/babel-core/test/api.js @@ -15,6 +15,7 @@ function assertNotIgnored(result) { function parse(code, opts) { return babel.parse(code, { cwd: __dirname, + configFile: false, ...opts, }); } @@ -22,6 +23,7 @@ function parse(code, opts) { function transform(code, opts) { return babel.transform(code, { cwd: __dirname, + configFile: false, ...opts, }); } @@ -31,6 +33,7 @@ function transformFile(filename, opts, cb) { filename, { cwd: __dirname, + configFile: false, ...opts, }, cb, @@ -39,6 +42,7 @@ function transformFile(filename, opts, cb) { function transformFileSync(filename, opts) { return babel.transformFileSync(filename, { cwd: __dirname, + configFile: false, ...opts, }); } @@ -46,6 +50,7 @@ function transformFileSync(filename, opts) { function transformAsync(code, opts) { return babel.transformAsync(code, { cwd: __dirname, + configFile: false, ...opts, }); } @@ -53,6 +58,7 @@ function transformAsync(code, opts) { function transformFromAst(ast, code, opts) { return babel.transformFromAst(ast, code, { cwd: __dirname, + configFile: false, ...opts, }); } diff --git a/packages/babel-core/test/assumptions.js b/packages/babel-core/test/assumptions.js new file mode 100644 index 000000000000..322e728d6eea --- /dev/null +++ b/packages/babel-core/test/assumptions.js @@ -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); + }); + }); +}); diff --git a/packages/babel-core/test/async.js b/packages/babel-core/test/async.js index 0e2bbdce8c02..2dfafe1617f2 100644 --- a/packages/babel-core/test/async.js +++ b/packages/babel-core/test/async.js @@ -1,6 +1,12 @@ -import path from "path"; +import { join } from "path"; import * as babel from ".."; +import { + spawnTransformAsync, + spawnTransformSync, + supportsESM, +} from "./helpers/esm"; + const nodeGte8 = (...args) => { // "minNodeVersion": "8.0.0" <-- For Ctrl+F when dropping node 6 const testFn = process.version.slice(0, 3) === "v6." ? it.skip : it; @@ -8,7 +14,7 @@ const nodeGte8 = (...args) => { }; describe("asynchronicity", () => { - const base = path.join(__dirname, "fixtures", "async"); + const base = join(__dirname, "fixtures", "async"); let cwd; beforeEach(function () { @@ -111,25 +117,18 @@ describe("asynchronicity", () => { nodeGte8("called synchronously", () => { process.chdir("plugin"); - expect(() => - babel.transformSync(""), - ).toThrowErrorMatchingInlineSnapshot( - `"[BABEL] unknown: You appear to be using an async 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."`, + expect(() => babel.transformSync("")).toThrow( + `[BABEL] unknown: You appear to be using an async plugin/preset, but Babel` + + ` has been called synchronously`, ); }); nodeGte8("called asynchronously", async () => { process.chdir("plugin"); - await expect( - babel.transformAsync(""), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"[BABEL] unknown: You appear to be using an async 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."`, - ); + await expect(babel.transformAsync("")).resolves.toMatchObject({ + code: `"success"`, + }); }); }); @@ -189,24 +188,108 @@ describe("asynchronicity", () => { nodeGte8("called synchronously", () => { process.chdir("plugin-inherits"); - expect(() => - babel.transformSync(""), - ).toThrowErrorMatchingInlineSnapshot( - `"[BABEL] unknown: You appear to be using an async 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."`, + expect(() => babel.transformSync("")).toThrow( + `[BABEL] unknown: You appear to be using an async plugin/preset, but Babel has been` + + ` called synchronously`, ); }); nodeGte8("called asynchronously", async () => { process.chdir("plugin-inherits"); - await expect( - babel.transformAsync(""), - ).rejects.toThrowErrorMatchingInlineSnapshot( - `"[BABEL] unknown: You appear to be using an async 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."`, + await expect(babel.transformAsync("")).resolves.toMatchObject({ + code: `"success 2"\n"success"`, + }); + }); + }); + + (supportsESM ? describe : describe.skip)(".mjs files", () => { + it("called synchronously", async () => { + process.chdir("plugin-mjs-native"); + + await expect(spawnTransformSync()).rejects.toThrow( + `[BABEL]: You appear to be using a native ECMAScript module plugin, which is` + + ` only supported when running Babel asynchronously.`, + ); + }); + + it("called asynchronously", async () => { + process.chdir("plugin-mjs-native"); + + await expect(spawnTransformAsync()).resolves.toMatchObject({ + code: `"success"`, + }); + }); + }); + }); + + describe("preset", () => { + describe("factory function", () => { + nodeGte8("called synchronously", () => { + process.chdir("preset"); + + expect(() => babel.transformSync("")).toThrow( + `[BABEL] unknown: You appear to be using an async plugin/preset, ` + + `but Babel has been called synchronously`, + ); + }); + + nodeGte8("called asynchronously", async () => { + process.chdir("preset"); + + await expect(babel.transformAsync("")).resolves.toMatchObject({ + code: `"success"`, + }); + }); + }); + + describe("plugins", () => { + nodeGte8("called synchronously", () => { + process.chdir("preset-plugin-promise"); + + expect(() => babel.transformSync("")).toThrow( + `[BABEL] unknown: 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".`, + ); + }); + + nodeGte8("called asynchronously", async () => { + process.chdir("preset-plugin-promise"); + + await expect(babel.transformAsync("")).rejects.toThrow( + `[BABEL] unknown: 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".`, + ); + }); + }); + + (supportsESM ? describe : describe.skip)(".mjs files", () => { + it("called synchronously", async () => { + process.chdir("preset-mjs-native"); + + await expect(spawnTransformSync()).rejects.toThrow( + `[BABEL]: You appear to be using a native ECMAScript module preset, which is` + + ` only supported when running Babel asynchronously.`, + ); + }); + + it("called asynchronously", async () => { + process.chdir("preset-mjs-native"); + + await expect(spawnTransformAsync()).resolves.toMatchObject({ + code: `"success"`, + }); + }); + + it("must use the 'default' export", async () => { + process.chdir("preset-mjs-named-exports-native"); + + await expect(spawnTransformAsync()).rejects.toThrow( + `Unexpected falsy value: undefined`, ); }); }); diff --git a/packages/babel-core/test/config-chain.js b/packages/babel-core/test/config-chain.js index 8de2bc99d086..f710d347ed9e 100644 --- a/packages/babel-core/test/config-chain.js +++ b/packages/babel-core/test/config-chain.js @@ -1,32 +1,10 @@ -import cp from "child_process"; import fs from "fs"; import os from "os"; import path from "path"; -import util from "util"; import escapeRegExp from "lodash/escapeRegExp"; import * as babel from "../lib"; -// "minNodeVersion": "10.0.0" <-- For Ctrl+F when dropping node 10 -const supportsESM = parseInt(process.versions.node) >= 12; - -const isMJS = file => path.extname(file) === ".mjs"; - -const skipUnsupportedESM = (esm, name) => { - if (esm && !supportsESM) { - console.warn( - `Skipping "${name}" because native ECMAScript modules are not supported.`, - ); - return true; - } - // This can be removed when loadOptionsAsyncInSpawedProcess is removed. - if (esm && process.platform === "win32") { - console.warn( - `Skipping "${name}" because the ESM runner cannot be spawned on Windows.`, - ); - return true; - } - return false; -}; +import { isMJS, loadOptionsAsync, skipUnsupportedESM } from "./helpers/esm"; // TODO: In Babel 8, we can directly uses fs.promises which is supported by // node 8+ @@ -71,42 +49,6 @@ function loadOptions(opts) { return babel.loadOptions({ cwd: __dirname, ...opts }); } -function loadOptionsAsync({ filename, cwd = __dirname }, mjs) { - if (mjs) { - // import() crashes with jest - return loadOptionsAsyncInSpawedProcess({ filename, cwd }); - } - - return babel.loadOptionsAsync({ filename, cwd }); -} - -// !!!! hack is coming !!!! -// Remove this function when https://github.com/nodejs/node/issues/35889 is resolved. -// Jest supports dynamic import(), but Node.js segfaults when using it in our tests. -async function loadOptionsAsyncInSpawedProcess({ filename, cwd }) { - const { stdout, stderr } = await util.promisify(cp.execFile)( - require.resolve("./fixtures/babel-load-options-async.mjs"), - // pass `cwd` as params as `process.cwd()` will normalize `cwd` on macOS - [filename, cwd], - { - cwd, - env: process.env, - }, - ); - - const EXPERIMENTAL_WARNING = /\(node:\d+\) ExperimentalWarning: The ESM module loader is experimental\./; - - if (stderr.replace(EXPERIMENTAL_WARNING, "").trim()) { - throw new Error( - "error is thrown in babel-load-options-async.mjs: stdout\n" + - stdout + - "\nstderr:\n" + - stderr, - ); - } - return JSON.parse(stdout); -} - function pairs(items) { const pairs = []; for (let i = 0; i < items.length - 1; i++) { @@ -1034,6 +976,7 @@ describe("buildConfigChain", function () { const getDefaults = () => ({ babelrc: false, configFile: false, + browserslistConfigFile: false, cwd: process.cwd(), root: process.cwd(), envName: "development", @@ -1041,6 +984,8 @@ describe("buildConfigChain", function () { plugins: [], presets: [], cloneInputAst: true, + targets: {}, + assumptions: {}, }); const realEnv = process.env.NODE_ENV; const realBabelEnv = process.env.BABEL_ENV; diff --git a/packages/babel-core/test/fixtures/async/plugin-mjs-native/babel.config.js b/packages/babel-core/test/fixtures/async/plugin-mjs-native/babel.config.js new file mode 100644 index 000000000000..e5e5251080c0 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/plugin-mjs-native/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + plugins: ["./plugin.mjs"], +}; diff --git a/packages/babel-core/test/fixtures/async/plugin-mjs-native/plugin.mjs b/packages/babel-core/test/fixtures/async/plugin-mjs-native/plugin.mjs new file mode 100644 index 000000000000..10195347cc37 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/plugin-mjs-native/plugin.mjs @@ -0,0 +1,9 @@ +export default function plugin({ types: t }) { + return { + visitor: { + Program(path) { + path.pushContainer("body", t.stringLiteral("success")); + }, + }, + }; +} diff --git a/packages/babel-core/test/fixtures/async/plugin-mjs/babel.config.js b/packages/babel-core/test/fixtures/async/plugin-mjs/babel.config.js new file mode 100644 index 000000000000..e5e5251080c0 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/plugin-mjs/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + plugins: ["./plugin.mjs"], +}; diff --git a/packages/babel-core/test/fixtures/async/plugin-mjs/plugin.mjs b/packages/babel-core/test/fixtures/async/plugin-mjs/plugin.mjs new file mode 100644 index 000000000000..e26f86b27ed4 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/plugin-mjs/plugin.mjs @@ -0,0 +1,16 @@ +// Until Jest supports native mjs, we must simulate it 🤷 +module.exports = new Promise(resolve => + resolve({ + default: function plugin({ types: t }) { + return { + visitor: { + Program(path) { + path.pushContainer("body", t.stringLiteral("success")); + }, + }, + }; + }, + }) +); + +module.exports.__esModule = true; diff --git a/packages/babel-core/test/fixtures/async/preset-mjs-named-exports-native/babel.config.js b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports-native/babel.config.js new file mode 100644 index 000000000000..67c90fbdd7c0 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports-native/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ["./preset.mjs"], +}; diff --git a/packages/babel-core/test/fixtures/async/preset-mjs-named-exports-native/plugin.mjs b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports-native/plugin.mjs new file mode 100644 index 000000000000..10195347cc37 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports-native/plugin.mjs @@ -0,0 +1,9 @@ +export default function plugin({ types: t }) { + return { + visitor: { + Program(path) { + path.pushContainer("body", t.stringLiteral("success")); + }, + }, + }; +} diff --git a/packages/babel-core/test/fixtures/async/preset-mjs-named-exports-native/preset.mjs b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports-native/preset.mjs new file mode 100644 index 000000000000..66fe02a6b22b --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports-native/preset.mjs @@ -0,0 +1 @@ +export const plugins = ["./plugin.mjs"]; diff --git a/packages/babel-core/test/fixtures/async/preset-mjs-named-exports/babel.config.js b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports/babel.config.js new file mode 100644 index 000000000000..67c90fbdd7c0 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ["./preset.mjs"], +}; diff --git a/packages/babel-core/test/fixtures/async/preset-mjs-named-exports/plugin.mjs b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports/plugin.mjs new file mode 100644 index 000000000000..e26f86b27ed4 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports/plugin.mjs @@ -0,0 +1,16 @@ +// Until Jest supports native mjs, we must simulate it 🤷 +module.exports = new Promise(resolve => + resolve({ + default: function plugin({ types: t }) { + return { + visitor: { + Program(path) { + path.pushContainer("body", t.stringLiteral("success")); + }, + }, + }; + }, + }) +); + +module.exports.__esModule = true; diff --git a/packages/babel-core/test/fixtures/async/preset-mjs-named-exports/preset.mjs b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports/preset.mjs new file mode 100644 index 000000000000..52a1b915e17d --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs-named-exports/preset.mjs @@ -0,0 +1,8 @@ +// Until Jest supports native mjs, we must simulate it 🤷 +module.exports = new Promise(resolve => + resolve({ + plugins: ["./plugin.mjs"] + }) +); + +module.exports.__esModule = true; diff --git a/packages/babel-core/test/fixtures/async/preset-mjs-native/babel.config.js b/packages/babel-core/test/fixtures/async/preset-mjs-native/babel.config.js new file mode 100644 index 000000000000..67c90fbdd7c0 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs-native/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ["./preset.mjs"], +}; diff --git a/packages/babel-core/test/fixtures/async/preset-mjs-native/plugin.mjs b/packages/babel-core/test/fixtures/async/preset-mjs-native/plugin.mjs new file mode 100644 index 000000000000..10195347cc37 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs-native/plugin.mjs @@ -0,0 +1,9 @@ +export default function plugin({ types: t }) { + return { + visitor: { + Program(path) { + path.pushContainer("body", t.stringLiteral("success")); + }, + }, + }; +} diff --git a/packages/babel-core/test/fixtures/async/preset-mjs-native/preset.mjs b/packages/babel-core/test/fixtures/async/preset-mjs-native/preset.mjs new file mode 100644 index 000000000000..25474e1664cc --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs-native/preset.mjs @@ -0,0 +1,3 @@ +export default () => ({ + plugins: ["./plugin.mjs"] +}); diff --git a/packages/babel-core/test/fixtures/async/preset-mjs/babel.config.js b/packages/babel-core/test/fixtures/async/preset-mjs/babel.config.js new file mode 100644 index 000000000000..67c90fbdd7c0 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ["./preset.mjs"], +}; diff --git a/packages/babel-core/test/fixtures/async/preset-mjs/plugin.mjs b/packages/babel-core/test/fixtures/async/preset-mjs/plugin.mjs new file mode 100644 index 000000000000..e26f86b27ed4 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs/plugin.mjs @@ -0,0 +1,16 @@ +// Until Jest supports native mjs, we must simulate it 🤷 +module.exports = new Promise(resolve => + resolve({ + default: function plugin({ types: t }) { + return { + visitor: { + Program(path) { + path.pushContainer("body", t.stringLiteral("success")); + }, + }, + }; + }, + }) +); + +module.exports.__esModule = true; diff --git a/packages/babel-core/test/fixtures/async/preset-mjs/preset.mjs b/packages/babel-core/test/fixtures/async/preset-mjs/preset.mjs new file mode 100644 index 000000000000..8779954e9ee4 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-mjs/preset.mjs @@ -0,0 +1,10 @@ +// Until Jest supports native mjs, we must simulate it 🤷 +module.exports = new Promise(resolve => + resolve({ + default: () => ({ + plugins: ["./plugin.mjs"] + }) + }) +); + +module.exports.__esModule = true; diff --git a/packages/babel-core/test/fixtures/async/preset-plugin-promise/babel.config.js b/packages/babel-core/test/fixtures/async/preset-plugin-promise/babel.config.js new file mode 100644 index 000000000000..e7104f746f81 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-plugin-promise/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ["./preset"], +}; diff --git a/packages/babel-core/test/fixtures/async/preset-plugin-promise/plugin.js b/packages/babel-core/test/fixtures/async/preset-plugin-promise/plugin.js new file mode 100644 index 000000000000..9777dd80ae42 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-plugin-promise/plugin.js @@ -0,0 +1,13 @@ +const wait = t => new Promise(r => setTimeout(r, t)); + +module.exports = async function plugin({ types: t }) { + await wait(50); + + return { + visitor: { + Program(path) { + path.pushContainer("body", t.stringLiteral("success")); + }, + }, + }; +}; diff --git a/packages/babel-core/test/fixtures/async/preset-plugin-promise/preset.js b/packages/babel-core/test/fixtures/async/preset-plugin-promise/preset.js new file mode 100644 index 000000000000..aceef8a4c242 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset-plugin-promise/preset.js @@ -0,0 +1,10 @@ +const wait = t => new Promise(r => setTimeout(r, t)); + +// "Dynamic import" +const import_ = path => Promise.resolve(require(path)); + +module.exports = function preset(api) { + return { + plugins: [import_("./plugin")], + }; +}; diff --git a/packages/babel-core/test/fixtures/async/preset/babel.config.js b/packages/babel-core/test/fixtures/async/preset/babel.config.js new file mode 100644 index 000000000000..e7104f746f81 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: ["./preset"], +}; diff --git a/packages/babel-core/test/fixtures/async/preset/plugin.js b/packages/babel-core/test/fixtures/async/preset/plugin.js new file mode 100644 index 000000000000..9777dd80ae42 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset/plugin.js @@ -0,0 +1,13 @@ +const wait = t => new Promise(r => setTimeout(r, t)); + +module.exports = async function plugin({ types: t }) { + await wait(50); + + return { + visitor: { + Program(path) { + path.pushContainer("body", t.stringLiteral("success")); + }, + }, + }; +}; diff --git a/packages/babel-core/test/fixtures/async/preset/preset.js b/packages/babel-core/test/fixtures/async/preset/preset.js new file mode 100644 index 000000000000..a48e87783ef6 --- /dev/null +++ b/packages/babel-core/test/fixtures/async/preset/preset.js @@ -0,0 +1,9 @@ +const wait = t => new Promise(r => setTimeout(r, t)); + +module.exports = async function preset(api) { + await wait(50); + + return { + plugins: [require("./plugin")], + }; +}; diff --git a/packages/babel-core/test/fixtures/babel-compile-async.mjs b/packages/babel-core/test/fixtures/babel-compile-async.mjs new file mode 100755 index 000000000000..4f67829a74d0 --- /dev/null +++ b/packages/babel-core/test/fixtures/babel-compile-async.mjs @@ -0,0 +1,11 @@ +#!/usr/bin/env node + +// Usage: +// babel-compile-async.js [filename] +import babel from "../../lib/index.js"; + +(async () => { + process.stdout.write( + JSON.stringify(await babel.transformAsync("")) + ); +})(); diff --git a/packages/babel-core/test/fixtures/babel-compile-sync.mjs b/packages/babel-core/test/fixtures/babel-compile-sync.mjs new file mode 100755 index 000000000000..dd4152602f39 --- /dev/null +++ b/packages/babel-core/test/fixtures/babel-compile-sync.mjs @@ -0,0 +1,9 @@ +#!/usr/bin/env node + +// Usage: +// babel-compile-async.js [filename] +import babel from "../../lib/index.js"; + +process.stdout.write( + JSON.stringify(babel.transformSync("")) +); diff --git a/packages/babel-core/test/fixtures/plugins/targets/plugin/input.js b/packages/babel-core/test/fixtures/plugins/targets/plugin/input.js new file mode 100644 index 000000000000..092bc2b04126 --- /dev/null +++ b/packages/babel-core/test/fixtures/plugins/targets/plugin/input.js @@ -0,0 +1 @@ +; diff --git a/packages/babel-core/test/fixtures/plugins/targets/plugin/options.json b/packages/babel-core/test/fixtures/plugins/targets/plugin/options.json new file mode 100644 index 000000000000..ca5100967dc3 --- /dev/null +++ b/packages/babel-core/test/fixtures/plugins/targets/plugin/options.json @@ -0,0 +1,4 @@ +{ + "targets": ["firefox 64", "node 8"], + "plugins": ["./plugin"] +} diff --git a/packages/babel-core/test/fixtures/plugins/targets/plugin/output.js b/packages/babel-core/test/fixtures/plugins/targets/plugin/output.js new file mode 100644 index 000000000000..4ae652ed9fa8 --- /dev/null +++ b/packages/babel-core/test/fixtures/plugins/targets/plugin/output.js @@ -0,0 +1,2 @@ +; +"plugin: {\"firefox\":\"64.0.0\",\"node\":\"8.17.0\"}" diff --git a/packages/babel-core/test/fixtures/plugins/targets/plugin/plugin.js b/packages/babel-core/test/fixtures/plugins/targets/plugin/plugin.js new file mode 100644 index 000000000000..b268497cd97e --- /dev/null +++ b/packages/babel-core/test/fixtures/plugins/targets/plugin/plugin.js @@ -0,0 +1,14 @@ +module.exports = function (api) { + const { types: t } = api; + + const targets = api.targets(); + + return { + visitor: { + Program(path) { + const output = t.stringLiteral(`plugin: ${JSON.stringify(targets)}`); + path.pushContainer("body", output); + }, + }, + }; +}; diff --git a/packages/babel-core/test/fixtures/plugins/targets/preset/input.js b/packages/babel-core/test/fixtures/plugins/targets/preset/input.js new file mode 100644 index 000000000000..092bc2b04126 --- /dev/null +++ b/packages/babel-core/test/fixtures/plugins/targets/preset/input.js @@ -0,0 +1 @@ +; diff --git a/packages/babel-core/test/fixtures/plugins/targets/preset/options.json b/packages/babel-core/test/fixtures/plugins/targets/preset/options.json new file mode 100644 index 000000000000..2e86914c87e1 --- /dev/null +++ b/packages/babel-core/test/fixtures/plugins/targets/preset/options.json @@ -0,0 +1,4 @@ +{ + "targets": ["firefox 64", "node 8"], + "presets": ["./preset"] +} diff --git a/packages/babel-core/test/fixtures/plugins/targets/preset/output.js b/packages/babel-core/test/fixtures/plugins/targets/preset/output.js new file mode 100644 index 000000000000..570eb08d2ee3 --- /dev/null +++ b/packages/babel-core/test/fixtures/plugins/targets/preset/output.js @@ -0,0 +1,2 @@ +; +"preset: {\"firefox\":\"64.0.0\",\"node\":\"8.17.0\"}" diff --git a/packages/babel-core/test/fixtures/plugins/targets/preset/preset.js b/packages/babel-core/test/fixtures/plugins/targets/preset/preset.js new file mode 100644 index 000000000000..b35f4d5fa94e --- /dev/null +++ b/packages/babel-core/test/fixtures/plugins/targets/preset/preset.js @@ -0,0 +1,18 @@ +module.exports = function (api) { + const targets = api.targets(); + + return { + plugins: [plugin], + }; + + function plugin({ types: t }) { + return { + visitor: { + Program(path) { + const output = t.stringLiteral(`preset: ${JSON.stringify(targets)}`); + path.pushContainer("body", output); + }, + }, + }; + } +}; diff --git a/packages/babel-core/test/fixtures/targets/.browserslistrc b/packages/babel-core/test/fixtures/targets/.browserslistrc new file mode 100644 index 000000000000..6b3ad521fb07 --- /dev/null +++ b/packages/babel-core/test/fixtures/targets/.browserslistrc @@ -0,0 +1,4 @@ +chrome 80 + +[browserslist-loading-test] +chrome 70 diff --git a/packages/babel-core/test/fixtures/targets/.browserslistrc-firefox b/packages/babel-core/test/fixtures/targets/.browserslistrc-firefox new file mode 100644 index 000000000000..c2f0c40728a6 --- /dev/null +++ b/packages/babel-core/test/fixtures/targets/.browserslistrc-firefox @@ -0,0 +1 @@ +firefox 74 diff --git a/packages/babel-core/test/fixtures/targets/nested/.browserslistrc b/packages/babel-core/test/fixtures/targets/nested/.browserslistrc new file mode 100644 index 000000000000..124541b16eb8 --- /dev/null +++ b/packages/babel-core/test/fixtures/targets/nested/.browserslistrc @@ -0,0 +1 @@ +edge 14 diff --git a/packages/babel-core/test/helpers/esm.js b/packages/babel-core/test/helpers/esm.js new file mode 100644 index 000000000000..23f70eb097ca --- /dev/null +++ b/packages/babel-core/test/helpers/esm.js @@ -0,0 +1,74 @@ +import cp from "child_process"; +import util from "util"; +import path from "path"; +import * as babel from "../../lib"; + +// "minNodeVersion": "10.0.0" <-- For Ctrl+F when dropping node 10 +const nodeSupportsESM = parseInt(process.versions.node) >= 12; +const isWindows = process.platform === "win32"; + +export const supportsESM = nodeSupportsESM && !isWindows; + +export const isMJS = file => path.extname(file) === ".mjs"; + +export const itESM = supportsESM ? it : it.skip; + +export function skipUnsupportedESM(esm, name) { + if (esm && !nodeSupportsESM) { + console.warn( + `Skipping "${name}" because native ECMAScript modules are not supported.`, + ); + return true; + } + // This can be removed when loadOptionsAsyncInSpawedProcess is removed. + if (esm && isWindows) { + console.warn( + `Skipping "${name}" because the ESM runner cannot be spawned on Windows.`, + ); + return true; + } + return false; +} + +export function loadOptionsAsync({ filename, cwd = __dirname }, mjs) { + if (mjs) { + // import() crashes with jest + return spawn("load-options-async", filename, cwd); + } + + return babel.loadOptionsAsync({ filename, cwd }); +} + +export function spawnTransformAsync() { + // import() crashes with jest + return spawn("compile-async"); +} + +export function spawnTransformSync() { + // import() crashes with jest + return spawn("compile-sync"); +} + +// !!!! hack is coming !!!! +// Remove this function when https://github.com/nodejs/node/issues/35889 is resolved. +// Jest supports dynamic import(), but Node.js segfaults when using it in our tests. +async function spawn(runner, filename, cwd = process.cwd()) { + const { stdout, stderr } = await util.promisify(cp.execFile)( + require.resolve(`../fixtures/babel-${runner}.mjs`), + // pass `cwd` as params as `process.cwd()` will normalize `cwd` on macOS + [filename, cwd], + { cwd, env: process.env }, + ); + + const EXPERIMENTAL_WARNING = /\(node:\d+\) ExperimentalWarning: The ESM module loader is experimental\./; + + if (stderr.replace(EXPERIMENTAL_WARNING, "").trim()) { + throw new Error( + `error is thrown in babel-${runner}.mjs: stdout\n` + + stdout + + "\nstderr:\n" + + stderr, + ); + } + return JSON.parse(stdout); +} diff --git a/packages/babel-core/test/targets.js b/packages/babel-core/test/targets.js new file mode 100644 index 000000000000..00214c9b7f06 --- /dev/null +++ b/packages/babel-core/test/targets.js @@ -0,0 +1,150 @@ +import { loadOptions as loadOptionsOrig } from "../lib"; +import { join } from "path"; + +function loadOptions(opts) { + return loadOptionsOrig({ cwd: __dirname, ...opts }); +} + +function withTargets(targets) { + return loadOptions({ targets }); +} + +describe("targets", () => { + it("throws if invalid type", () => { + expect(() => withTargets(2)).toThrow( + ".targets must be a string, an array of strings or an object", + ); + + expect(() => withTargets([2])).toThrow( + ".targets must be a string, an array of strings or an object", + ); + + expect(() => withTargets([{}])).toThrow( + ".targets must be a string, an array of strings or an object", + ); + + expect(() => withTargets([])).not.toThrow(); + expect(() => withTargets({})).not.toThrow(); + }); + + it("throws if invalid target", () => { + expect(() => withTargets({ uglify: "2.3" })).toThrow( + /\.targets\["uglify"\] is not a valid target/, + ); + + expect(() => withTargets({ foo: "bar" })).toThrow( + /\.targets\["foo"\] is not a valid target/, + ); + + expect(() => withTargets({ firefox: 71 })).not.toThrow(); + }); + + it("throws if invalid version", () => { + expect(() => withTargets({ node: 10.1 /* or 10.10? */ })).toThrow( + `.targets["node"] must be a string or an integer number`, + ); + + expect(() => withTargets({ node: true })).toThrow( + `.targets["node"] must be a string or an integer number`, + ); + + expect(() => withTargets({ node: "10.1" })).not.toThrow(); + + expect(() => withTargets({ node: "current" })).not.toThrow(); + }); + + it("esmodules", () => { + expect(() => withTargets({ esmodules: "7" })).toThrow( + `.targets["esmodules"] must be a boolean, or undefined`, + ); + + expect(() => withTargets({ esmodules: false })).not.toThrow(); + expect(() => withTargets({ esmodules: true })).not.toThrow(); + }); + + it("browsers", () => { + expect(() => withTargets({ browsers: 2 })).toThrow( + `.targets["browsers"] must be undefined, a string or an array of strings`, + ); + + expect(() => withTargets({ browsers: [2] })).toThrow( + `.targets["browsers"] must be undefined, a string or an array of strings`, + ); + + expect(() => withTargets({ browsers: {} })).toThrow( + `.targets["browsers"] must be undefined, a string or an array of strings`, + ); + + expect(() => withTargets({ browsers: [] })).not.toThrow(); + }); +}); + +describe("browserslist", () => { + it("loads .browserslistrc by default", () => { + expect( + loadOptions({ + cwd: join(__dirname, "fixtures", "targets"), + }).targets, + ).toEqual({ chrome: "80.0.0" }); + }); + + it("loads .browserslistrc relative to the input file", () => { + expect( + loadOptions({ + cwd: join(__dirname, "fixtures", "targets"), + filename: "./nested/test.js", + }).targets, + ).toEqual({ edge: "14.0.0" }); + }); + + describe("browserslistConfigFile", () => { + it("can disable config loading", () => { + expect( + loadOptions({ + cwd: join(__dirname, "fixtures", "targets"), + browserslistConfigFile: false, + }).targets, + ).toEqual({}); + }); + + it("can specify a custom file", () => { + expect( + loadOptions({ + cwd: join(__dirname, "fixtures", "targets"), + browserslistConfigFile: "./.browserslistrc-firefox", + }).targets, + ).toEqual({ firefox: "74.0.0" }); + }); + + it("is relative to the project root", () => { + expect( + loadOptions({ + cwd: join(__dirname, "fixtures", "targets"), + root: "..", + filename: "./nested/test.js", + browserslistConfigFile: "./targets/.browserslistrc-firefox", + }).targets, + ).toEqual({ firefox: "74.0.0" }); + }); + }); + + describe("browserslistEnv", () => { + it("is forwarded to browserslist", () => { + expect( + loadOptions({ + cwd: join(__dirname, "fixtures", "targets"), + browserslistEnv: "browserslist-loading-test", + }).targets, + ).toEqual({ chrome: "70.0.0" }); + }); + }); + + it("esmodules and browsers are intersected", () => { + expect( + withTargets({ + esmodules: true, + browsers: "chrome >= 80, firefox >= 30", + }).targets, + ).toEqual({ chrome: "80.0.0", firefox: "60.0.0" }); + }); +}); diff --git a/packages/babel-helper-compilation-targets/src/index.js b/packages/babel-helper-compilation-targets/src/index.js index e488ea3eec4e..b6ce5284ecb4 100644 --- a/packages/babel-helper-compilation-targets/src/index.js +++ b/packages/babel-helper-compilation-targets/src/index.js @@ -9,6 +9,7 @@ import { semverMin, isUnreleasedVersion, getLowestUnreleased, + getHighestUnreleased, } from "./utils"; import { OptionValidator } from "@babel/helper-validator-option"; import { browserNameMap } from "./targets"; @@ -21,9 +22,11 @@ export { prettifyTargets } from "./pretty"; export { getInclusionReasons } from "./debug"; export { default as filterItems, isRequired } from "./filter-items"; export { unreleasedLabels } from "./targets"; +export { TargetNames }; + +const ESM_SUPPORT = browserModulesData["es6.module"]; const v = new OptionValidator(PACKAGE_JSON.name); -const browserslistDefaults = browserslist.defaults; function validateTargetNames(targets: Targets): TargetsTuple { const validTargets = Object.keys(TargetNames); @@ -39,8 +42,11 @@ function validateTargetNames(targets: Targets): TargetsTuple { return (targets: any); } -export function isBrowsersQueryValid(browsers: Browsers | Targets): boolean { - return typeof browsers === "string" || Array.isArray(browsers); +export function isBrowsersQueryValid(browsers: mixed): boolean %checks { + return ( + typeof browsers === "string" || + (Array.isArray(browsers) && browsers.every(b => typeof b === "string")) + ); } function validateBrowsers(browsers: Browsers | void) { @@ -149,55 +155,83 @@ function generateTargets(inputTargets: InputTargets): Targets { return ((input: any): Targets); } +function resolveTargets(queries: Browsers): Targets { + const resolved = browserslist(queries, { mobileToDesktop: true }); + return getLowestVersions(resolved); +} + +type GetTargetsOption = { + // This is not the path of the config file, but the path where start searching it from + configPath?: string, + + // The path of the config file + configFile?: string, + + // The env to pass to browserslist + browserslistEnv?: string, + + // true to disable config loading + ignoreBrowserslistConfig?: boolean, +}; + export default function getTargets( inputTargets: InputTargets = {}, - options: Object = {}, + options: GetTargetsOption = {}, ): Targets { - let { browsers } = inputTargets; - - // `esmodules` as a target indicates the specific set of browsers supporting ES Modules. - // These values OVERRIDE the `browsers` field. - if (inputTargets.esmodules) { - const supportsESModules = browserModulesData["es6.module"]; - browsers = Object.keys(supportsESModules) - .map(browser => `${browser} ${supportsESModules[browser]}`) - .join(", "); - } + let { browsers, esmodules } = inputTargets; - // Parse browsers target via browserslist - const browsersquery = validateBrowsers(browsers); + validateBrowsers(browsers); const input = generateTargets(inputTargets); let targets: TargetsTuple = validateTargetNames(input); - const shouldParseBrowsers = !!browsersquery; + const shouldParseBrowsers = !!browsers; const hasTargets = shouldParseBrowsers || Object.keys(targets).length > 0; const shouldSearchForConfig = !options.ignoreBrowserslistConfig && !hasTargets; - if (shouldParseBrowsers || shouldSearchForConfig) { - // If no targets are passed, we need to overwrite browserslist's defaults - // so that we enable all transforms (acting like the now deprecated - // preset-latest). - // - // Note, if browserslist resolves the config (ex. package.json), then usage - // of `defaults` in queries will be different since we don't want to break - // the behavior of "no targets is the same as preset-latest". - if (!hasTargets) { - browserslist.defaults = []; - } + if (!browsers && shouldSearchForConfig) { + browsers = + browserslist.loadConfig({ + config: options.configFile, + path: options.configPath, + env: options.browserslistEnv, + }) ?? + // If no targets are passed, we need to overwrite browserslist's defaults + // so that we enable all transforms (acting like the now deprecated + // preset-latest). + []; + } + + // `esmodules` as a target indicates the specific set of browsers supporting ES Modules. + // These values OVERRIDE the `browsers` field. + if (esmodules && (esmodules !== "intersect" || !browsers)) { + browsers = Object.keys(ESM_SUPPORT) + .map(browser => `${browser} >= ${ESM_SUPPORT[browser]}`) + .join(", "); + esmodules = false; + } - const browsers = browserslist(browsersquery, { - path: options.configPath, - mobileToDesktop: true, - env: options.browserslistEnv, - }); + if (browsers) { + const queryBrowsers = resolveTargets(browsers); + + if (esmodules === "intersect") { + for (const browser of Object.keys(queryBrowsers)) { + const version = queryBrowsers[browser]; + + if (ESM_SUPPORT[browser]) { + queryBrowsers[browser] = getHighestUnreleased( + version, + semverify(ESM_SUPPORT[browser]), + browser, + ); + } else { + delete queryBrowsers[browser]; + } + } + } - const queryBrowsers = getLowestVersions(browsers); targets = Object.assign(queryBrowsers, targets); - - // Reset browserslist defaults - browserslist.defaults = browserslistDefaults; } // Parse remaining targets diff --git a/packages/babel-helper-compilation-targets/src/types.js b/packages/babel-helper-compilation-targets/src/types.js index 9e0bc3a06f5e..16dd02dd140d 100644 --- a/packages/babel-helper-compilation-targets/src/types.js +++ b/packages/babel-helper-compilation-targets/src/types.js @@ -22,11 +22,17 @@ export type TargetsTuple = {| [target: Target]: string, |}; -export type Browsers = string | Array; +export type Browsers = string | $ReadOnlyArray; export type InputTargets = { ...Targets, browsers?: Browsers, - esmodules?: boolean, + + // When `true`, this completely replaces the `browsers` option. + // When `intersect`, this is intersected with the `browsers` + // option (giving the higher browsers as the result). + // TODO(Babel 8): Make `true` behave like `intersect` and + // remove `intersect`. + esmodules?: boolean | "intersect", }; diff --git a/packages/babel-helper-compilation-targets/src/utils.js b/packages/babel-helper-compilation-targets/src/utils.js index 80fda8315f13..5feb9c9e38c4 100644 --- a/packages/babel-helper-compilation-targets/src/utils.js +++ b/packages/babel-helper-compilation-targets/src/utils.js @@ -51,6 +51,14 @@ export function getLowestUnreleased(a: string, b: string, env: string): string { return semverMin(a, b); } +export function getHighestUnreleased( + a: string, + b: string, + env: string, +): string { + return getLowestUnreleased(a, b, env) === a ? b : a; +} + export function getLowestImplementedVersion( plugin: Targets, environment: Target, diff --git a/packages/babel-helper-compilation-targets/test/__snapshots__/targets-parser.spec.js.snap b/packages/babel-helper-compilation-targets/test/__snapshots__/targets-parser.spec.js.snap index 9b49cb2af4b6..e6ea5cbace26 100644 --- a/packages/babel-helper-compilation-targets/test/__snapshots__/targets-parser.spec.js.snap +++ b/packages/babel-helper-compilation-targets/test/__snapshots__/targets-parser.spec.js.snap @@ -1,5 +1,26 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`getTargets esmodules can be intersected with a .browserslistrc file 1`] = ` +Object { + "chrome": "70.0.0", + "firefox": "60.0.0", +} +`; + +exports[`getTargets esmodules can be intersected with the browsers option 1`] = ` +Object { + "chrome": "70.0.0", + "firefox": "60.0.0", +} +`; + +exports[`getTargets esmodules explicit browser versions have the precedence over 'esmodules' 1`] = ` +Object { + "chrome": "20.0.0", + "firefox": "70.0.0", +} +`; + exports[`getTargets esmodules returns browser supporting modules and keyed browser overrides 1`] = ` Object { "android": "61.0.0", diff --git a/packages/babel-helper-compilation-targets/test/fixtures/.browserslistrc b/packages/babel-helper-compilation-targets/test/fixtures/.browserslistrc new file mode 100644 index 000000000000..595f09dab553 --- /dev/null +++ b/packages/babel-helper-compilation-targets/test/fixtures/.browserslistrc @@ -0,0 +1,2 @@ +chrome >= 70 +firefox >= 30 diff --git a/packages/babel-helper-compilation-targets/test/targets-parser.spec.js b/packages/babel-helper-compilation-targets/test/targets-parser.spec.js index 562ee2fc3b87..2119db119928 100644 --- a/packages/babel-helper-compilation-targets/test/targets-parser.spec.js +++ b/packages/babel-helper-compilation-targets/test/targets-parser.spec.js @@ -1,4 +1,5 @@ import browserslist from "browserslist"; +import { join } from "path"; import getTargets from ".."; describe("getTargets", () => { @@ -233,6 +234,48 @@ describe("getTargets", () => { }), ).toMatchSnapshot(); }); + + it("can be intersected with the browsers option", () => { + expect( + getTargets({ + esmodules: "intersect", + browsers: ["chrome >= 70", "firefox >= 30"], + }), + ).toMatchSnapshot(); + }); + + it("can be intersected with a .browserslistrc file", () => { + expect( + getTargets( + { + esmodules: "intersect", + }, + { configPath: join(__dirname, "fixtures", "foo.js") }, + ), + ).toMatchSnapshot(); + }); + + it("explicit browser versions have the precedence over 'esmodules'", () => { + expect( + getTargets({ + browsers: "chrome 5, firefox 5", + esmodules: "intersect", + chrome: 20, + firefox: 70, + }), + ).toMatchSnapshot(); + }); + + it("'intersect' behaves like 'true' if no browsers are specified", () => { + expect( + getTargets( + { esmodules: "intersect" }, + { ignoreBrowserslistConfig: true }, + ), + ).toEqual( + getTargets({ esmodules: true }, { ignoreBrowserslistConfig: true }), + ); + }); }); describe("node", () => { diff --git a/packages/babel-helper-create-class-features-plugin/src/fields.js b/packages/babel-helper-create-class-features-plugin/src/fields.js index 438335e5b9e5..bfe6fc5da1a3 100644 --- a/packages/babel-helper-create-class-features-plugin/src/fields.js +++ b/packages/babel-helper-create-class-features-plugin/src/fields.js @@ -35,11 +35,16 @@ export function buildPrivateNamesMap(props) { return privateNamesMap; } -export function buildPrivateNamesNodes(privateNamesMap, loose, state) { +export function buildPrivateNamesNodes( + privateNamesMap, + privateFieldsAsProperties, + state, +) { const initNodes = []; for (const [name, value] of privateNamesMap) { - // In loose mode, both static and instance fields are transpiled using a + // When the privateFieldsAsProperties assumption is enabled, + // both static and instance fields are transpiled using a // secret non-enumerable property. Hence, we also need to generate that // key (using the classPrivateFieldLooseKey helper). // In spec mode, only instance fields need a "private name" initializer @@ -48,7 +53,7 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) { const { static: isStatic, method: isMethod, getId, setId } = value; const isAccessor = getId || setId; const id = t.cloneNode(value.id); - if (loose) { + if (privateFieldsAsProperties) { initNodes.push( template.statement.ast` var ${id} = ${state.addHelper("classPrivateFieldLooseKey")}("${name}") @@ -125,7 +130,7 @@ function privateNameVisitorFactory(visitor) { } const privateNameVisitor = privateNameVisitorFactory({ - PrivateName(path) { + PrivateName(path, { noDocumentAll }) { const { privateNamesMap, redeclared } = this; const { node, parentPath } = path; @@ -139,7 +144,7 @@ const privateNameVisitor = privateNameVisitorFactory({ if (!privateNamesMap.has(name)) return; if (redeclared && redeclared.includes(name)) return; - this.handle(parentPath); + this.handle(parentPath, noDocumentAll); }, }); @@ -149,13 +154,13 @@ const privateInVisitor = privateNameVisitorFactory({ if (operator !== "in") return; if (!path.get("left").isPrivateName()) return; - const { loose, privateNamesMap, redeclared } = this; + const { privateFieldsAsProperties, privateNamesMap, redeclared } = this; const { name } = left.id; if (!privateNamesMap.has(name)) return; if (redeclared && redeclared.includes(name)) return; - if (loose) { + if (privateFieldsAsProperties) { const { id } = privateNamesMap.get(name); path.replaceWith(template.expression.ast` Object.prototype.hasOwnProperty.call(${right}, ${t.cloneNode(id)}) @@ -373,25 +378,28 @@ export function transformPrivateNamesUsage( ref, path, privateNamesMap, - loose, + { privateFieldsAsProperties, noDocumentAll }, state, ) { if (!privateNamesMap.size) return; const body = path.get("body"); - const handler = loose ? privateNameHandlerLoose : privateNameHandlerSpec; + const handler = privateFieldsAsProperties + ? privateNameHandlerLoose + : privateNameHandlerSpec; memberExpressionToFunctions(body, privateNameVisitor, { privateNamesMap, classRef: ref, file: state, ...handler, + noDocumentAll, }); body.traverse(privateInVisitor, { privateNamesMap, classRef: ref, file: state, - loose, + privateFieldsAsProperties, }); } @@ -573,7 +581,11 @@ function buildPrivateStaticMethodInitLoose(ref, prop, state, privateNamesMap) { `; } -function buildPrivateMethodDeclaration(prop, privateNamesMap, loose = false) { +function buildPrivateMethodDeclaration( + prop, + privateNamesMap, + privateFieldsAsProperties = false, +) { const privateName = privateNamesMap.get(prop.node.key.id.name); const { id, @@ -613,7 +625,7 @@ function buildPrivateMethodDeclaration(prop, privateNamesMap, loose = false) { t.variableDeclarator(setId, methodValue), ]); } - if (isStatic && !loose) { + if (isStatic && !privateFieldsAsProperties) { return t.variableDeclaration("var", [ t.variableDeclarator( t.cloneNode(id), @@ -637,12 +649,12 @@ const thisContextVisitor = traverse.visitors.merge([ environmentVisitor, ]); -function replaceThisContext(path, ref, superRef, file, loose) { +function replaceThisContext(path, ref, superRef, file, constantSuper) { const state = { classRef: ref, needsClassRef: false }; const replacer = new ReplaceSupers({ methodPath: path, - isLoose: loose, + constantSuper, superRef, file, refToPreserve: ref, @@ -666,7 +678,9 @@ export function buildFieldsInitNodes( props, privateNamesMap, state, - loose, + setPublicClassFields, + privateFieldsAsProperties, + constantSuper, ) { const staticNodes = []; const instanceNodes = []; @@ -683,39 +697,45 @@ export function buildFieldsInitNodes( const isMethod = !isField; if (isStatic || (isMethod && isPrivate)) { - const replaced = replaceThisContext(prop, ref, superRef, state, loose); + const replaced = replaceThisContext( + prop, + ref, + superRef, + state, + constantSuper, + ); needsClassRef = needsClassRef || replaced; } switch (true) { - case isStatic && isPrivate && isField && loose: + case isStatic && isPrivate && isField && privateFieldsAsProperties: needsClassRef = true; staticNodes.push( buildPrivateFieldInitLoose(t.cloneNode(ref), prop, privateNamesMap), ); break; - case isStatic && isPrivate && isField && !loose: + case isStatic && isPrivate && isField && !privateFieldsAsProperties: needsClassRef = true; staticNodes.push( buildPrivateStaticFieldInitSpec(prop, privateNamesMap), ); break; - case isStatic && isPublic && isField && loose: + case isStatic && isPublic && isField && setPublicClassFields: needsClassRef = true; staticNodes.push(buildPublicFieldInitLoose(t.cloneNode(ref), prop)); break; - case isStatic && isPublic && isField && !loose: + case isStatic && isPublic && isField && !setPublicClassFields: needsClassRef = true; staticNodes.push( buildPublicFieldInitSpec(t.cloneNode(ref), prop, state), ); break; - case isInstance && isPrivate && isField && loose: + case isInstance && isPrivate && isField && privateFieldsAsProperties: instanceNodes.push( buildPrivateFieldInitLoose(t.thisExpression(), prop, privateNamesMap), ); break; - case isInstance && isPrivate && isField && !loose: + case isInstance && isPrivate && isField && !privateFieldsAsProperties: instanceNodes.push( buildPrivateInstanceFieldInitSpec( t.thisExpression(), @@ -724,7 +744,7 @@ export function buildFieldsInitNodes( ), ); break; - case isInstance && isPrivate && isMethod && loose: + case isInstance && isPrivate && isMethod && privateFieldsAsProperties: instanceNodes.unshift( buildPrivateMethodInitLoose( t.thisExpression(), @@ -733,10 +753,14 @@ export function buildFieldsInitNodes( ), ); staticNodes.push( - buildPrivateMethodDeclaration(prop, privateNamesMap, loose), + buildPrivateMethodDeclaration( + prop, + privateNamesMap, + privateFieldsAsProperties, + ), ); break; - case isInstance && isPrivate && isMethod && !loose: + case isInstance && isPrivate && isMethod && !privateFieldsAsProperties: instanceNodes.unshift( buildPrivateInstanceMethodInitSpec( t.thisExpression(), @@ -745,19 +769,27 @@ export function buildFieldsInitNodes( ), ); staticNodes.push( - buildPrivateMethodDeclaration(prop, privateNamesMap, loose), + buildPrivateMethodDeclaration( + prop, + privateNamesMap, + privateFieldsAsProperties, + ), ); break; - case isStatic && isPrivate && isMethod && !loose: + case isStatic && isPrivate && isMethod && !privateFieldsAsProperties: needsClassRef = true; staticNodes.push( buildPrivateStaticFieldInitSpec(prop, privateNamesMap), ); staticNodes.unshift( - buildPrivateMethodDeclaration(prop, privateNamesMap, loose), + buildPrivateMethodDeclaration( + prop, + privateNamesMap, + privateFieldsAsProperties, + ), ); break; - case isStatic && isPrivate && isMethod && loose: + case isStatic && isPrivate && isMethod && privateFieldsAsProperties: needsClassRef = true; staticNodes.push( buildPrivateStaticMethodInitLoose( @@ -768,13 +800,17 @@ export function buildFieldsInitNodes( ), ); staticNodes.unshift( - buildPrivateMethodDeclaration(prop, privateNamesMap, loose), + buildPrivateMethodDeclaration( + prop, + privateNamesMap, + privateFieldsAsProperties, + ), ); break; - case isInstance && isPublic && isField && loose: + case isInstance && isPublic && isField && setPublicClassFields: instanceNodes.push(buildPublicFieldInitLoose(t.thisExpression(), prop)); break; - case isInstance && isPublic && isField && !loose: + case isInstance && isPublic && isField && !setPublicClassFields: instanceNodes.push( buildPublicFieldInitSpec(t.thisExpression(), prop, state), ); diff --git a/packages/babel-helper-create-class-features-plugin/src/index.js b/packages/babel-helper-create-class-features-plugin/src/index.js index 66cfb83fb082..7c2c097c485e 100644 --- a/packages/babel-helper-create-class-features-plugin/src/index.js +++ b/packages/babel-helper-create-class-features-plugin/src/index.js @@ -36,7 +36,39 @@ export function createClassFeaturePlugin({ feature, loose, manipulateOptions, + // TODO(Babel 8): Remove the default falue + api = { assumption: () => {} }, }) { + const setPublicClassFields = api.assumption("setPublicClassFields"); + const privateFieldsAsProperties = api.assumption("privateFieldsAsProperties"); + const constantSuper = api.assumption("constantSuper"); + const noDocumentAll = api.assumption("noDocumentAll"); + + if (loose) { + const explicit = []; + + if (setPublicClassFields !== undefined) { + explicit.push(`"setPublicClassFields"`); + } + if (privateFieldsAsProperties !== undefined) { + explicit.push(`"privateFieldsAsProperties"`); + } + if (explicit.length !== 0) { + console.warn( + `[${name}]: You are using the "loose: true" option and you are` + + ` explicitly setting a value for the ${explicit.join(" and ")}` + + ` assumption${explicit.length > 1 ? "s" : ""}. The "loose" option` + + ` can cause incompatibilities with the other class features` + + ` plugins, so it's recommended that you replace it with the` + + ` following top-level option:\n` + + `\t"assumptions": {\n` + + `\t\t"setPublicClassFields": true,\n` + + `\t\t"privateFieldsAsProperties": true\n` + + `\t}`, + ); + } + } + return { name, manipulateOptions, @@ -151,11 +183,20 @@ export function createClassFeaturePlugin({ const privateNamesMap = buildPrivateNamesMap(props); const privateNamesNodes = buildPrivateNamesNodes( privateNamesMap, - loose, + privateFieldsAsProperties ?? loose, state, ); - transformPrivateNamesUsage(ref, path, privateNamesMap, loose, state); + transformPrivateNamesUsage( + ref, + path, + privateNamesMap, + { + privateFieldsAsProperties: privateFieldsAsProperties ?? loose, + noDocumentAll, + }, + state, + ); let keysNodes, staticNodes, instanceNodes, wrapClass; @@ -175,7 +216,9 @@ export function createClassFeaturePlugin({ props, privateNamesMap, state, - loose, + setPublicClassFields ?? loose, + privateFieldsAsProperties ?? loose, + constantSuper ?? loose, )); } diff --git a/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/input.js b/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/input.js new file mode 100644 index 000000000000..eb0eb350654f --- /dev/null +++ b/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/input.js @@ -0,0 +1,3 @@ +class A { + foo; +} diff --git a/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/options.json b/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/options.json new file mode 100644 index 000000000000..3fae40ed0d43 --- /dev/null +++ b/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/options.json @@ -0,0 +1,9 @@ +{ + "validateLogs": true, + "plugins": [ + ["proposal-class-properties", { "loose": true }] + ], + "assumptions": { + "setPublicClassFields": true + } +} diff --git a/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/output.js b/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/output.js new file mode 100644 index 000000000000..063a057f52c0 --- /dev/null +++ b/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/output.js @@ -0,0 +1,6 @@ +class A { + constructor() { + this.foo = void 0; + } + +} diff --git a/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/stderr.txt b/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/stderr.txt new file mode 100644 index 000000000000..2d6c3d02acff --- /dev/null +++ b/packages/babel-helper-create-class-features-plugin/test/fixtures/plugin-proposal-class-properties/warn-loose-and-assumptions/stderr.txt @@ -0,0 +1,5 @@ +[proposal-class-properties]: You are using the "loose: true" option and you are explicitly setting a value for the "setPublicClassFields" assumption. The "loose" option can cause incompatibilities with the other class features plugins, so it's recommended that you replace it with the following top-level option: + "assumptions": { + "setPublicClassFields": true, + "privateFieldsAsProperties": true + } diff --git a/packages/babel-helper-member-expression-to-functions/src/index.js b/packages/babel-helper-member-expression-to-functions/src/index.js index f9f3ba723d0f..52a28e8de3cc 100644 --- a/packages/babel-helper-member-expression-to-functions/src/index.js +++ b/packages/babel-helper-member-expression-to-functions/src/index.js @@ -84,7 +84,7 @@ const handle = { // noop. }, - handle(member) { + handle(member: t.NodePath, noDocumentAll: boolean) { const { node, parent, parentPath, scope } = member; if (member.isOptionalMemberExpression()) { @@ -241,50 +241,56 @@ const handle = { regular = endParentPath.node; } + const baseMemoised = baseNeedsMemoised + ? t.assignmentExpression( + "=", + t.cloneNode(baseRef), + t.cloneNode(startingNode), + ) + : t.cloneNode(baseRef); + if (willEndPathCastToBoolean) { - const nonNullishCheck = t.logicalExpression( - "&&", - t.binaryExpression( - "!==", - baseNeedsMemoised - ? t.assignmentExpression( - "=", - t.cloneNode(baseRef), - t.cloneNode(startingNode), - ) - : t.cloneNode(baseRef), + let nonNullishCheck; + if (noDocumentAll) { + nonNullishCheck = t.binaryExpression( + "!=", + baseMemoised, t.nullLiteral(), - ), - t.binaryExpression( - "!==", - t.cloneNode(baseRef), - scope.buildUndefinedNode(), - ), - ); + ); + } else { + nonNullishCheck = t.logicalExpression( + "&&", + t.binaryExpression("!==", baseMemoised, t.nullLiteral()), + t.binaryExpression( + "!==", + t.cloneNode(baseRef), + scope.buildUndefinedNode(), + ), + ); + } replacementPath.replaceWith( t.logicalExpression("&&", nonNullishCheck, regular), ); } else { - // todo: respect assumptions.noDocumentAll when assumptions are implemented - const nullishCheck = t.logicalExpression( - "||", - t.binaryExpression( - "===", - baseNeedsMemoised - ? t.assignmentExpression( - "=", - t.cloneNode(baseRef), - t.cloneNode(startingNode), - ) - : t.cloneNode(baseRef), + let nullishCheck; + if (noDocumentAll) { + nullishCheck = t.binaryExpression( + "==", + baseMemoised, t.nullLiteral(), - ), - t.binaryExpression( - "===", - t.cloneNode(baseRef), - scope.buildUndefinedNode(), - ), - ); + ); + } else { + nullishCheck = t.logicalExpression( + "||", + t.binaryExpression("===", baseMemoised, t.nullLiteral()), + t.binaryExpression( + "===", + t.cloneNode(baseRef), + scope.buildUndefinedNode(), + ), + ); + } + replacementPath.replaceWith( t.conditionalExpression( nullishCheck, diff --git a/packages/babel-helper-module-transforms/src/index.js b/packages/babel-helper-module-transforms/src/index.js index 164462ee0450..5e244e2ab2f1 100644 --- a/packages/babel-helper-module-transforms/src/index.js +++ b/packages/babel-helper-module-transforms/src/index.js @@ -27,14 +27,19 @@ export { hasExports, isSideEffectImport, isModule, rewriteThis }; export function rewriteModuleStatementsAndPrepareHeader( path: NodePath, { + // TODO(Babel 8): Remove this + loose, + exportName, strict, allowTopLevelThis, strictMode, - loose, noInterop, lazy, esNamespaceOnly, + + constantReexports = loose, + enumerableModuleMeta = loose, }, ) { assert(isModule(path), "Cannot process module statements in a script"); @@ -42,7 +47,7 @@ export function rewriteModuleStatementsAndPrepareHeader( const meta = normalizeAndLoadModuleMetadata(path, exportName, { noInterop, - loose, + initializeReexports: constantReexports, lazy, esNamespaceOnly, }); @@ -67,7 +72,7 @@ export function rewriteModuleStatementsAndPrepareHeader( const headers = []; if (hasExports(meta) && !strict) { - headers.push(buildESModuleHeader(meta, loose /* enumerable */)); + headers.push(buildESModuleHeader(meta, enumerableModuleMeta)); } const nameList = buildExportNameListDeclaration(path, meta); @@ -78,7 +83,9 @@ export function rewriteModuleStatementsAndPrepareHeader( } // Create all of the statically known named exports. - headers.push(...buildExportInitializationStatements(path, meta, loose)); + headers.push( + ...buildExportInitializationStatements(path, meta, constantReexports), + ); return { meta, headers }; } @@ -128,7 +135,7 @@ export function wrapInterop( export function buildNamespaceInitStatements( metadata: ModuleMetadata, sourceMetadata: SourceModuleMetadata, - loose: boolean = false, + constantReexports: boolean = false, ) { const statements = []; @@ -146,8 +153,8 @@ export function buildNamespaceInitStatements( }), ); } - if (loose) { - statements.push(...buildReexportsFromMeta(metadata, sourceMetadata, loose)); + if (constantReexports) { + statements.push(...buildReexportsFromMeta(metadata, sourceMetadata, true)); } for (const exportName of sourceMetadata.reexportNamespace) { // Assign export to namespace object. @@ -172,7 +179,7 @@ export function buildNamespaceInitStatements( const statement = buildNamespaceReexport( metadata, t.cloneNode(srcNamespace), - loose, + constantReexports, ); statement.loc = sourceMetadata.reexportAll.loc; @@ -183,8 +190,8 @@ export function buildNamespaceInitStatements( } const ReexportTemplate = { - loose: template.statement`EXPORTS.EXPORT_NAME = NAMESPACE_IMPORT;`, - looseComputed: template.statement`EXPORTS["EXPORT_NAME"] = NAMESPACE_IMPORT;`, + constant: template.statement`EXPORTS.EXPORT_NAME = NAMESPACE_IMPORT;`, + constantComputed: template.statement`EXPORTS["EXPORT_NAME"] = NAMESPACE_IMPORT;`, spec: template` Object.defineProperty(EXPORTS, "EXPORT_NAME", { enumerable: true, @@ -198,7 +205,7 @@ const ReexportTemplate = { const buildReexportsFromMeta = ( meta: ModuleMetadata, metadata: SourceModuleMetadata, - loose, + constantReexports: boolean, ) => { const namespace = metadata.lazy ? t.callExpression(t.identifier(metadata.name), []) @@ -224,11 +231,11 @@ const buildReexportsFromMeta = ( EXPORT_NAME: exportName, NAMESPACE_IMPORT, }; - if (loose) { + if (constantReexports) { if (stringSpecifiers.has(exportName)) { - return ReexportTemplate.looseComputed(astNodes); + return ReexportTemplate.constantComputed(astNodes); } else { - return ReexportTemplate.loose(astNodes); + return ReexportTemplate.constant(astNodes); } } else { return ReexportTemplate.spec(astNodes); @@ -241,9 +248,9 @@ const buildReexportsFromMeta = ( */ function buildESModuleHeader( metadata: ModuleMetadata, - enumerable: boolean = false, + enumerableModuleMeta: boolean = false, ) { - return (enumerable + return (enumerableModuleMeta ? template.statement` EXPORTS.__esModule = true; ` @@ -257,8 +264,8 @@ function buildESModuleHeader( /** * Create a re-export initialization loop for a specific imported namespace. */ -function buildNamespaceReexport(metadata, namespace, loose) { - return (loose +function buildNamespaceReexport(metadata, namespace, constantReexports) { + return (constantReexports ? template.statement` Object.keys(NAMESPACE).forEach(function(key) { if (key === "default" || key === "__esModule") return; @@ -347,7 +354,7 @@ function buildExportNameListDeclaration( function buildExportInitializationStatements( programPath: NodePath, metadata: ModuleMetadata, - loose: boolean = false, + constantReexports: boolean = false, ) { const initStatements = []; @@ -365,8 +372,8 @@ function buildExportInitializationStatements( } for (const data of metadata.source.values()) { - if (!loose) { - initStatements.push(...buildReexportsFromMeta(metadata, data, loose)); + if (!constantReexports) { + initStatements.push(...buildReexportsFromMeta(metadata, data, false)); } for (const exportName of data.reexportNamespace) { exportNames.push(exportName); diff --git a/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.js b/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.js index c95e0b188cb2..84bac99f3ce0 100644 --- a/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.js +++ b/packages/babel-helper-module-transforms/src/normalize-and-load-metadata.js @@ -86,7 +86,7 @@ export default function normalizeModuleAndLoadMetadata( exportName?: string, { noInterop = false, - loose = false, + initializeReexports = false, lazy = false, esNamespaceOnly = false, } = {}, @@ -100,10 +100,7 @@ export default function normalizeModuleAndLoadMetadata( const { local, source, hasExports } = getModuleMetadata( programPath, - { - loose, - lazy, - }, + { initializeReexports, lazy }, stringSpecifiers, ); @@ -170,12 +167,15 @@ function getExportSpecifierName( */ function getModuleMetadata( programPath: NodePath, - { loose, lazy }: { loose: boolean, lazy: boolean }, + { + lazy, + initializeReexports, + }: { lazy: boolean, initializeReexports: boolean }, stringSpecifiers: Set, ) { const localData = getLocalExportMetadata( programPath, - loose, + initializeReexports, stringSpecifiers, ); @@ -361,7 +361,7 @@ function getModuleMetadata( */ function getLocalExportMetadata( programPath: NodePath, - loose: boolean, + initializeReexports: boolean, stringSpecifiers: Set, ): Map { const bindingKindLookup = new Map(); @@ -376,7 +376,7 @@ function getLocalExportMetadata( if (child.node.declaration) { child = child.get("declaration"); } else if ( - loose && + initializeReexports && child.node.source && child.get("source").isStringLiteral() ) { @@ -429,7 +429,10 @@ function getLocalExportMetadata( }; programPath.get("body").forEach(child => { - if (child.isExportNamedDeclaration() && (loose || !child.node.source)) { + if ( + child.isExportNamedDeclaration() && + (initializeReexports || !child.node.source) + ) { if (child.node.declaration) { const declaration = child.get("declaration"); const ids = declaration.getOuterBindingIdentifierPaths(); diff --git a/packages/babel-helper-plugin-utils/src/index.js b/packages/babel-helper-plugin-utils/src/index.js index f0ecb83a22e2..5347c2470fa7 100644 --- a/packages/babel-helper-plugin-utils/src/index.js +++ b/packages/babel-helper-plugin-utils/src/index.js @@ -1,19 +1,36 @@ export function declare(builder) { return (api, options, dirname) => { - if (!api.assertVersion) { - // Inject a custom version of 'assertVersion' for Babel 6 and early - // versions of Babel 7's beta that didn't have it. - api = Object.assign(copyApiObject(api), { - assertVersion(range) { - throwVersionError(range, api.version); - }, - }); + let clonedApi; + + for (const name of Object.keys(apiPolyfills)) { + if (api[name]) continue; + + // TODO: Use ??= when flow lets us to do so + clonedApi = clonedApi ?? copyApiObject(api); + clonedApi[name] = apiPolyfills[name](clonedApi); } - return builder(api, options || {}, dirname); + return builder(clonedApi ?? api, options || {}, dirname); }; } +const apiPolyfills = { + // Not supported by Babel 7 and early versions of Babel 7 beta. + // It's important that this is polyfilled for older Babel versions + // since it's needed to report the version mismatch. + assertVersion: api => range => { + throwVersionError(range, api.version); + }, + // This is supported starting from Babel 7.13 + // TODO(Babel 8): Remove this polyfill + targets: () => () => { + return {}; + }, + // This is supported starting from Babel 7.13 + // TODO(Babel 8): Remove this polyfill + assumption: () => () => {}, +}; + function copyApiObject(api) { // Babel >= 7 <= beta.41 passed the API as a new object that had // babel/core as the prototype. While slightly faster, it also diff --git a/packages/babel-helper-remap-async-to-generator/src/index.js b/packages/babel-helper-remap-async-to-generator/src/index.js index ac96c9311218..282d32124b34 100644 --- a/packages/babel-helper-remap-async-to-generator/src/index.js +++ b/packages/babel-helper-remap-async-to-generator/src/index.js @@ -31,6 +31,7 @@ const awaitVisitor = { export default function ( path: NodePath, helpers: { wrapAsync: Object, wrapAwait: Object }, + noNewArrows?: boolean, ) { path.traverse(awaitVisitor, { wrapAwait: helpers.wrapAwait, @@ -41,7 +42,7 @@ export default function ( path.node.async = false; path.node.generator = true; - wrapFunction(path, t.cloneNode(helpers.wrapAsync)); + wrapFunction(path, t.cloneNode(helpers.wrapAsync), noNewArrows); const isProperty = path.isObjectMethod() || diff --git a/packages/babel-helper-replace-supers/src/index.js b/packages/babel-helper-replace-supers/src/index.js index 248d44f9637e..7ae8b2799333 100644 --- a/packages/babel-helper-replace-supers/src/index.js +++ b/packages/babel-helper-replace-supers/src/index.js @@ -255,7 +255,7 @@ const looseHandlers = { type ReplaceSupersOptionsBase = {| methodPath: NodePath, superRef: Object, - isLoose: boolean, + constantSuper: boolean, file: any, // objectRef might have been shadowed in child scopes, // in that case, we need to rename related variables. @@ -284,13 +284,16 @@ export default class ReplaceSupers { this.file = opts.file; this.superRef = opts.superRef; - this.isLoose = opts.isLoose; + this.constantSuper = process.env.BABEL_8_BREAKING + ? opts.constantSuper + : // Fallback to isLoose for backward compatibility + opts.constantSuper ?? (opts: any).isLoose; this.opts = opts; } declare file: HubInterface; declare isDerivedConstructor: boolean; - declare isLoose: boolean; + declare constantSuper: boolean; declare isPrivateMethod: boolean; declare isStatic: boolean; declare methodPath: NodePath; @@ -309,7 +312,7 @@ export default class ReplaceSupers { }); } - const handler = this.isLoose ? looseHandlers : specHandlers; + const handler = this.constantSuper ? looseHandlers : specHandlers; memberExpressionToFunctions(this.methodPath, visitor, { file: this.file, diff --git a/packages/babel-helper-wrap-function/src/index.js b/packages/babel-helper-wrap-function/src/index.js index e1ff0d37ac81..59f47780a972 100644 --- a/packages/babel-helper-wrap-function/src/index.js +++ b/packages/babel-helper-wrap-function/src/index.js @@ -57,7 +57,7 @@ function classOrObjectMethod(path: NodePath, callId: Object) { .unwrapFunctionEnvironment(); } -function plainFunction(path: NodePath, callId: Object) { +function plainFunction(path: NodePath, callId: Object, noNewArrows: boolean) { const node = path.node; const isDeclaration = path.isFunctionDeclaration(); const functionId = node.id; @@ -68,7 +68,7 @@ function plainFunction(path: NodePath, callId: Object) { : buildAnonymousExpressionWrapper; if (path.isArrowFunctionExpression()) { - path.arrowFunctionToExpression(); + path.arrowFunctionToExpression({ noNewArrows }); } node.id = null; @@ -123,10 +123,15 @@ function plainFunction(path: NodePath, callId: Object) { } } -export default function wrapFunction(path: NodePath, callId: Object) { +export default function wrapFunction( + path: NodePath, + callId: Object, + // TODO(Babel 8): Consider defaulting to false for spec compliancy + noNewArrows: boolean = true, +) { if (path.isMethod()) { classOrObjectMethod(path, callId); } else { - plainFunction(path, callId); + plainFunction(path, callId, noNewArrows); } } diff --git a/packages/babel-plugin-proposal-async-generator-functions/src/index.js b/packages/babel-plugin-proposal-async-generator-functions/src/index.js index 82bfa1d32a86..5460a792149e 100644 --- a/packages/babel-plugin-proposal-async-generator-functions/src/index.js +++ b/packages/babel-plugin-proposal-async-generator-functions/src/index.js @@ -70,6 +70,8 @@ export default declare(api => { path.traverse(yieldStarVisitor, state); + // We don't need to pass the noNewArrows assumption, since + // async generators are never arrow functions. remapAsyncToGenerator(path, { wrapAsync: state.addHelper("wrapAsyncGenerator"), wrapAwait: state.addHelper("awaitAsyncGenerator"), diff --git a/packages/babel-plugin-proposal-class-properties/src/index.js b/packages/babel-plugin-proposal-class-properties/src/index.js index 89c016dbca54..f8a6058a181f 100644 --- a/packages/babel-plugin-proposal-class-properties/src/index.js +++ b/packages/babel-plugin-proposal-class-properties/src/index.js @@ -12,6 +12,7 @@ export default declare((api, options) => { return createClassFeaturePlugin({ name: "proposal-class-properties", + api, feature: FEATURES.fields, loose: options.loose, diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/exec.js new file mode 100644 index 000000000000..13cc95662d95 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/exec.js @@ -0,0 +1,122 @@ +class Foo { + static #x = 1; + static #m = function() { return this.#x; }; + static #self = Foo; + static self = Foo; + static getSelf() { return this } + + static test() { + const o = { Foo: Foo }; + const deep = { very: { o } }; + function fn() { + return o; + } + function fnDeep() { + return deep; + } + + expect(o?.Foo.#m()).toEqual(1); + expect(o?.Foo.#m().toString).toEqual(1..toString); + expect(o?.Foo.#m().toString()).toEqual('1'); + + expect(deep?.very.o?.Foo.#m()).toEqual(1); + expect(deep?.very.o?.Foo.#m().toString).toEqual(1..toString); + expect(deep?.very.o?.Foo.#m().toString()).toEqual('1'); + + expect(o?.Foo.#self.#m()).toEqual(1); + expect(o?.Foo.#self.self.#m()).toEqual(1); + expect(o?.Foo.#self?.self.#m()).toEqual(1); + expect(o?.Foo.#self.self?.self.#m()).toEqual(1); + expect(o?.Foo.#self?.self?.self.#m()).toEqual(1); + + expect(o?.Foo.#self.getSelf().#m()).toEqual(1); + expect(o?.Foo.#self.getSelf?.().#m()).toEqual(1); + expect(o?.Foo.#self?.getSelf().#m()).toEqual(1); + expect(o?.Foo.#self?.getSelf?.().#m()).toEqual(1); + expect(o?.Foo.#self.getSelf()?.self.#m()).toEqual(1); + expect(o?.Foo.#self.getSelf?.()?.self.#m()).toEqual(1); + expect(o?.Foo.#self?.getSelf()?.self.#m()).toEqual(1); + expect(o?.Foo.#self?.getSelf?.()?.self.#m()).toEqual(1); + + expect(fn?.().Foo.#m()).toEqual(1); + expect(fn?.().Foo.#m().toString).toEqual(1..toString); + expect(fn?.().Foo.#m().toString()).toEqual('1'); + + expect(fnDeep?.().very.o?.Foo.#m()).toEqual(1); + expect(fnDeep?.().very.o?.Foo.#m().toString).toEqual(1..toString); + expect(fnDeep?.().very.o?.Foo.#m().toString()).toEqual('1'); + + expect(fn?.().Foo.#self.#m()).toEqual(1); + expect(fn?.().Foo.#self.self.#m()).toEqual(1); + expect(fn?.().Foo.#self?.self.#m()).toEqual(1); + expect(fn?.().Foo.#self.self?.self.#m()).toEqual(1); + expect(fn?.().Foo.#self?.self?.self.#m()).toEqual(1); + + expect(fn?.().Foo.#self.getSelf().#m()).toEqual(1); + expect(fn?.().Foo.#self.getSelf?.().#m()).toEqual(1); + expect(fn?.().Foo.#self?.getSelf().#m()).toEqual(1); + expect(fn?.().Foo.#self?.getSelf?.().#m()).toEqual(1); + expect(fn?.().Foo.#self.getSelf()?.self.#m()).toEqual(1); + expect(fn?.().Foo.#self.getSelf?.()?.self.#m()).toEqual(1); + expect(fn?.().Foo.#self?.getSelf()?.self.#m()).toEqual(1); + expect(fn?.().Foo.#self?.getSelf?.()?.self.#m()).toEqual(1); + } + + static testNull() { + const o = null;; + const deep = { very: { o } }; + const fn = null; + function fnDeep() { + return deep; + } + + expect(o?.Foo.#m()).toEqual(undefined); + expect(o?.Foo.#m().toString).toEqual(undefined); + expect(o?.Foo.#m().toString()).toEqual(undefined); + + expect(deep?.very.o?.Foo.#m()).toEqual(undefined); + expect(deep?.very.o?.Foo.#m().toString).toEqual(undefined); + expect(deep?.very.o?.Foo.#m().toString()).toEqual(undefined); + + expect(o?.Foo.#self.#m()).toEqual(undefined); + expect(o?.Foo.#self.self.#m()).toEqual(undefined); + expect(o?.Foo.#self?.self.#m()).toEqual(undefined); + expect(o?.Foo.#self.self?.self.#m()).toEqual(undefined); + expect(o?.Foo.#self?.self?.self.#m()).toEqual(undefined); + + expect(o?.Foo.#self.getSelf().#m()).toEqual(undefined); + expect(o?.Foo.#self.getSelf?.().#m()).toEqual(undefined); + expect(o?.Foo.#self?.getSelf().#m()).toEqual(undefined); + expect(o?.Foo.#self?.getSelf?.().#m()).toEqual(undefined); + expect(o?.Foo.#self.getSelf()?.self.#m()).toEqual(undefined); + expect(o?.Foo.#self.getSelf?.()?.self.#m()).toEqual(undefined); + expect(o?.Foo.#self?.getSelf()?.self.#m()).toEqual(undefined); + expect(o?.Foo.#self?.getSelf?.()?.self.#m()).toEqual(undefined); + + expect(fn?.().Foo.#m()).toEqual(undefined); + expect(fn?.().Foo.#m().toString).toEqual(undefined); + expect(fn?.().Foo.#m().toString()).toEqual(undefined); + + expect(fnDeep?.().very.o?.Foo.#m()).toEqual(undefined); + expect(fnDeep?.().very.o?.Foo.#m().toString).toEqual(undefined); + expect(fnDeep?.().very.o?.Foo.#m().toString()).toEqual(undefined); + + expect(fn?.().Foo.#self.#m()).toEqual(undefined); + expect(fn?.().Foo.#self.self.#m()).toEqual(undefined); + expect(fn?.().Foo.#self?.self.#m()).toEqual(undefined); + expect(fn?.().Foo.#self.self?.self.#m()).toEqual(undefined); + expect(fn?.().Foo.#self?.self?.self.#m()).toEqual(undefined); + + expect(fn?.().Foo.#self.getSelf().#m()).toEqual(undefined); + expect(fn?.().Foo.#self.getSelf?.().#m()).toEqual(undefined); + expect(fn?.().Foo.#self?.getSelf().#m()).toEqual(undefined); + expect(fn?.().Foo.#self?.getSelf?.().#m()).toEqual(undefined); + expect(fn?.().Foo.#self.getSelf()?.self.#m()).toEqual(undefined); + expect(fn?.().Foo.#self.getSelf?.()?.self.#m()).toEqual(undefined); + expect(fn?.().Foo.#self?.getSelf()?.self.#m()).toEqual(undefined); + expect(fn?.().Foo.#self?.getSelf?.()?.self.#m()).toEqual(undefined); + } +} + +Foo.test(); +Foo.testNull(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/input.js new file mode 100644 index 000000000000..d29585b51d60 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/input.js @@ -0,0 +1,66 @@ +class Foo { + static #x = 1; + static #m = function() { return this.#x; }; + static #self = Foo; + static self = Foo; + static getSelf() { return this } + + static test() { + const o = { Foo: Foo }; + const deep = { very: { o } }; + function fn() { + return o; + } + function fnDeep() { + return deep; + } + + o?.Foo.#m(); + o?.Foo.#m().toString; + o?.Foo.#m().toString(); + + deep?.very.o?.Foo.#m(); + deep?.very.o?.Foo.#m().toString; + deep?.very.o?.Foo.#m().toString(); + + o?.Foo.#self.#m(); + o?.Foo.#self.self.#m(); + o?.Foo.#self?.self.#m(); + o?.Foo.#self.self?.self.#m(); + o?.Foo.#self?.self?.self.#m(); + + o?.Foo.#self.getSelf().#m(); + o?.Foo.#self.getSelf?.().#m(); + o?.Foo.#self?.getSelf().#m(); + o?.Foo.#self?.getSelf?.().#m(); + o?.Foo.#self.getSelf()?.self.#m(); + o?.Foo.#self.getSelf?.()?.self.#m(); + o?.Foo.#self?.getSelf()?.self.#m(); + o?.Foo.#self?.getSelf?.()?.self.#m(); + + fn?.().Foo.#m(); + fn?.().Foo.#m().toString; + fn?.().Foo.#m().toString(); + + fnDeep?.().very.o?.Foo.#m(); + fnDeep?.().very.o?.Foo.#m().toString; + fnDeep?.().very.o?.Foo.#m().toString(); + + fn?.().Foo.#self.#m(); + fn?.().Foo.#self.self.#m(); + fn?.().Foo.#self?.self.#m(); + fn?.().Foo.#self.self?.self.#m(); + fn?.().Foo.#self?.self?.self.#m(); + + fn?.().Foo.#self.getSelf().#m(); + fn?.().Foo.#self.getSelf?.().#m(); + fn?.().Foo.#self?.getSelf().#m(); + fn?.().Foo.#self?.getSelf?.().#m(); + fn?.().Foo.#self.getSelf()?.self.#m(); + fn?.().Foo.#self.getSelf?.()?.self.#m(); + fn?.().Foo.#self?.getSelf()?.self.#m(); + fn?.().Foo.#self?.getSelf?.()?.self.#m(); + } +} + +Foo.test(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/options.json new file mode 100644 index 000000000000..3b59e1bbfcc8 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/options.json @@ -0,0 +1,4 @@ +{ + "plugins": ["proposal-class-properties"], + "minNodeVersion": "14.0.0" +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/output.js new file mode 100644 index 000000000000..71a4277d0032 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-before-member-call/output.js @@ -0,0 +1,89 @@ +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +function _classStaticPrivateFieldSpecGet(receiver, classConstructor, descriptor) { if (receiver !== classConstructor) { throw new TypeError("Private static access of wrong provenance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; } + +class Foo { + static getSelf() { + return this; + } + + static test() { + var _o$Foo, _o$Foo2, _o$Foo3, _deep$very$o, _deep$very$o$Foo, _deep$very$o2, _deep$very$o2$Foo, _deep$very$o3, _deep$very$o3$Foo, _classStaticPrivateFi, _classStaticPrivateFi2, _ref, _ref$self, _ref2, _ref2$self, _self2, _self2$self, _classStaticPrivateFi3, _classStaticPrivateFi4, _ref3, _ref3$call, _ref4, _ref4$getSelf, _getSelf, _ref5, _getSelf$call, _ref6, _ref6$self, _classStaticPrivateFi5, _call, _call$self, _getSelf2, _getSelf2$self, _getSelf3, _getSelf3$self, _fn$Foo, _fn$Foo2, _fn$Foo3, _fnDeep$very$o, _fnDeep$very$o$Foo, _fnDeep$very$o2, _fnDeep$very$o2$Foo, _fnDeep$very$o3, _fnDeep$very$o3$Foo, _classStaticPrivateFi6, _classStaticPrivateFi7, _ref7, _ref7$self, _ref8, _ref8$self, _self3, _self3$self, _classStaticPrivateFi8, _classStaticPrivateFi9, _ref9, _ref9$call, _ref10, _ref10$getSelf, _getSelf4, _ref11, _getSelf4$call, _ref12, _ref12$self, _classStaticPrivateFi10, _call2, _call2$self, _getSelf5, _getSelf5$self, _getSelf6, _getSelf6$self; + + const o = { + Foo: Foo + }; + const deep = { + very: { + o + } + }; + + function fn() { + return o; + } + + function fnDeep() { + return deep; + } + + o == null ? void 0 : _classStaticPrivateFieldSpecGet(_o$Foo = o.Foo, Foo, _m).call(_o$Foo); + o == null ? void 0 : _classStaticPrivateFieldSpecGet(_o$Foo2 = o.Foo, Foo, _m).call(_o$Foo2).toString; + o == null ? void 0 : _classStaticPrivateFieldSpecGet(_o$Foo3 = o.Foo, Foo, _m).call(_o$Foo3).toString(); + (_deep$very$o = deep?.very.o) == null ? void 0 : _classStaticPrivateFieldSpecGet(_deep$very$o$Foo = _deep$very$o.Foo, Foo, _m).call(_deep$very$o$Foo); + (_deep$very$o2 = deep?.very.o) == null ? void 0 : _classStaticPrivateFieldSpecGet(_deep$very$o2$Foo = _deep$very$o2.Foo, Foo, _m).call(_deep$very$o2$Foo).toString; + (_deep$very$o3 = deep?.very.o) == null ? void 0 : _classStaticPrivateFieldSpecGet(_deep$very$o3$Foo = _deep$very$o3.Foo, Foo, _m).call(_deep$very$o3$Foo).toString(); + o == null ? void 0 : _classStaticPrivateFieldSpecGet(_classStaticPrivateFi = _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self), Foo, _m).call(_classStaticPrivateFi); + o == null ? void 0 : _classStaticPrivateFieldSpecGet(_classStaticPrivateFi2 = _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self).self, Foo, _m).call(_classStaticPrivateFi2); + (_ref = o == null ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self)) == null ? void 0 : _classStaticPrivateFieldSpecGet(_ref$self = _ref.self, Foo, _m).call(_ref$self); + (_ref2 = o == null ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self).self) == null ? void 0 : _classStaticPrivateFieldSpecGet(_ref2$self = _ref2.self, Foo, _m).call(_ref2$self); + (_self2 = (o == null ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self))?.self) == null ? void 0 : _classStaticPrivateFieldSpecGet(_self2$self = _self2.self, Foo, _m).call(_self2$self); + o == null ? void 0 : _classStaticPrivateFieldSpecGet(_classStaticPrivateFi3 = _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self).getSelf(), Foo, _m).call(_classStaticPrivateFi3); + (_ref3 = o == null ? void 0 : (_classStaticPrivateFi4 = _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self)).getSelf) == null ? void 0 : _classStaticPrivateFieldSpecGet(_ref3$call = _ref3.call(_classStaticPrivateFi4), Foo, _m).call(_ref3$call); + (_ref4 = o == null ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self)) == null ? void 0 : _classStaticPrivateFieldSpecGet(_ref4$getSelf = _ref4.getSelf(), Foo, _m).call(_ref4$getSelf); + (_getSelf = (_ref5 = o == null ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self))?.getSelf) == null ? void 0 : _classStaticPrivateFieldSpecGet(_getSelf$call = _getSelf.call(_ref5), Foo, _m).call(_getSelf$call); + (_ref6 = o == null ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self).getSelf()) == null ? void 0 : _classStaticPrivateFieldSpecGet(_ref6$self = _ref6.self, Foo, _m).call(_ref6$self); + (_call = (o == null ? void 0 : (_classStaticPrivateFi5 = _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self)).getSelf)?.call(_classStaticPrivateFi5)) == null ? void 0 : _classStaticPrivateFieldSpecGet(_call$self = _call.self, Foo, _m).call(_call$self); + (_getSelf2 = (o == null ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self))?.getSelf()) == null ? void 0 : _classStaticPrivateFieldSpecGet(_getSelf2$self = _getSelf2.self, Foo, _m).call(_getSelf2$self); + (_getSelf3 = (o == null ? void 0 : _classStaticPrivateFieldSpecGet(o.Foo, Foo, _self))?.getSelf?.()) == null ? void 0 : _classStaticPrivateFieldSpecGet(_getSelf3$self = _getSelf3.self, Foo, _m).call(_getSelf3$self); + fn == null ? void 0 : _classStaticPrivateFieldSpecGet(_fn$Foo = fn().Foo, Foo, _m).call(_fn$Foo); + fn == null ? void 0 : _classStaticPrivateFieldSpecGet(_fn$Foo2 = fn().Foo, Foo, _m).call(_fn$Foo2).toString; + fn == null ? void 0 : _classStaticPrivateFieldSpecGet(_fn$Foo3 = fn().Foo, Foo, _m).call(_fn$Foo3).toString(); + (_fnDeep$very$o = fnDeep?.().very.o) == null ? void 0 : _classStaticPrivateFieldSpecGet(_fnDeep$very$o$Foo = _fnDeep$very$o.Foo, Foo, _m).call(_fnDeep$very$o$Foo); + (_fnDeep$very$o2 = fnDeep?.().very.o) == null ? void 0 : _classStaticPrivateFieldSpecGet(_fnDeep$very$o2$Foo = _fnDeep$very$o2.Foo, Foo, _m).call(_fnDeep$very$o2$Foo).toString; + (_fnDeep$very$o3 = fnDeep?.().very.o) == null ? void 0 : _classStaticPrivateFieldSpecGet(_fnDeep$very$o3$Foo = _fnDeep$very$o3.Foo, Foo, _m).call(_fnDeep$very$o3$Foo).toString(); + fn == null ? void 0 : _classStaticPrivateFieldSpecGet(_classStaticPrivateFi6 = _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self), Foo, _m).call(_classStaticPrivateFi6); + fn == null ? void 0 : _classStaticPrivateFieldSpecGet(_classStaticPrivateFi7 = _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self).self, Foo, _m).call(_classStaticPrivateFi7); + (_ref7 = fn == null ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self)) == null ? void 0 : _classStaticPrivateFieldSpecGet(_ref7$self = _ref7.self, Foo, _m).call(_ref7$self); + (_ref8 = fn == null ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self).self) == null ? void 0 : _classStaticPrivateFieldSpecGet(_ref8$self = _ref8.self, Foo, _m).call(_ref8$self); + (_self3 = (fn == null ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self))?.self) == null ? void 0 : _classStaticPrivateFieldSpecGet(_self3$self = _self3.self, Foo, _m).call(_self3$self); + fn == null ? void 0 : _classStaticPrivateFieldSpecGet(_classStaticPrivateFi8 = _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self).getSelf(), Foo, _m).call(_classStaticPrivateFi8); + (_ref9 = fn == null ? void 0 : (_classStaticPrivateFi9 = _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self)).getSelf) == null ? void 0 : _classStaticPrivateFieldSpecGet(_ref9$call = _ref9.call(_classStaticPrivateFi9), Foo, _m).call(_ref9$call); + (_ref10 = fn == null ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self)) == null ? void 0 : _classStaticPrivateFieldSpecGet(_ref10$getSelf = _ref10.getSelf(), Foo, _m).call(_ref10$getSelf); + (_getSelf4 = (_ref11 = fn == null ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self))?.getSelf) == null ? void 0 : _classStaticPrivateFieldSpecGet(_getSelf4$call = _getSelf4.call(_ref11), Foo, _m).call(_getSelf4$call); + (_ref12 = fn == null ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self).getSelf()) == null ? void 0 : _classStaticPrivateFieldSpecGet(_ref12$self = _ref12.self, Foo, _m).call(_ref12$self); + (_call2 = (fn == null ? void 0 : (_classStaticPrivateFi10 = _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self)).getSelf)?.call(_classStaticPrivateFi10)) == null ? void 0 : _classStaticPrivateFieldSpecGet(_call2$self = _call2.self, Foo, _m).call(_call2$self); + (_getSelf5 = (fn == null ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self))?.getSelf()) == null ? void 0 : _classStaticPrivateFieldSpecGet(_getSelf5$self = _getSelf5.self, Foo, _m).call(_getSelf5$self); + (_getSelf6 = (fn == null ? void 0 : _classStaticPrivateFieldSpecGet(fn().Foo, Foo, _self))?.getSelf?.()) == null ? void 0 : _classStaticPrivateFieldSpecGet(_getSelf6$self = _getSelf6.self, Foo, _m).call(_getSelf6$self); + } + +} + +var _x = { + writable: true, + value: 1 +}; +var _m = { + writable: true, + value: function () { + return _classStaticPrivateFieldSpecGet(this, Foo, _x); + } +}; +var _self = { + writable: true, + value: Foo +}; + +_defineProperty(Foo, "self", Foo); + +Foo.test(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/exec.js new file mode 100644 index 000000000000..c035e0eb1ddd --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/exec.js @@ -0,0 +1,119 @@ +class C { + static #a = { + b: { + c: { + d: 2, + }, + }, + }; + static testIf(o) { + if (o?.#a.b.c.d) { + return true; + } + return false; + } + static testConditional(o) { + return o?.#a.b?.c.d ? true : false; + } + static testLoop(o) { + while (o?.#a.b.c.d) { + for (; o?.#a.b.c?.d; ) { + let i = 0; + do { + i++; + if (i === 2) { + return true; + } + } while (o?.#a.b?.c.d); + } + } + return false; + } + static testNegate(o) { + return !!o?.#a.b?.c.d; + } + static testIfDeep(o) { + if (o.obj?.#a.b?.c.d) { + return true; + } + return false; + } + static testConditionalDeep(o) { + return o.obj?.#a.b?.c.d ? true : false; + } + static testLoopDeep(o) { + while (o.obj?.#a.b.c.d) { + for (; o.obj?.#a.b.c?.d; ) { + let i = 0; + do { + i++; + if (i === 2) { + return true; + } + } while (o.obj?.#a.b?.c.d); + } + } + return false; + } + static testNegateDeep(o) { + return !!o.obj?.#a.b?.c.d; + } + + static testLogicalInIf(o) { + if (o?.#a.b?.c.d && o?.#a?.b.c.d) { + return true; + } + return false; + } + + static testLogicalInReturn(o) { + return o?.#a.b?.c.d && o?.#a?.b.c.d; + } + + static testNullishCoalescing(o) { + if (o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d) { + return o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d; + } + return o?.#a.b?.c.non_existent ?? o; + } + + static test() { + const c = C; + expect(C.testIf(c)).toBe(true); + expect(C.testConditional(c)).toBe(true); + expect(C.testLoop(c)).toBe(true); + expect(C.testNegate(c)).toBe(true); + + expect(C.testIfDeep({ obj: c })).toBe(true); + expect(C.testConditionalDeep({ obj: c })).toBe(true); + expect(C.testLoopDeep({ obj: c })).toBe(true); + expect(C.testNegateDeep({ obj: c })).toBe(true); + + expect(C.testLogicalInIf(c)).toBe(true); + expect(C.testLogicalInReturn(c)).toBe(2); + + expect(C.testNullishCoalescing(c)).toBe(2); + } + + static testNullish() { + for (const n of [null, undefined]) { + expect(C.testIf(n)).toBe(false); + expect(C.testConditional(n)).toBe(false); + expect(C.testLoop(n)).toBe(false); + expect(C.testNegate(n)).toBe(false); + + expect(C.testIfDeep({ obj: n })).toBe(false); + expect(C.testConditionalDeep({ obj: n })).toBe(false); + expect(C.testLoopDeep({ obj: n })).toBe(false); + expect(C.testNegateDeep({ obj: n })).toBe(false); + + expect(C.testLogicalInIf(n)).toBe(false); + expect(C.testLogicalInReturn(n)).toBe(undefined); + + expect(C.testNullishCoalescing(n)).toBe(n); + } + } +} + +C.test(); +C.testNullish(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/input.js new file mode 100644 index 000000000000..f80f89dd7a89 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/input.js @@ -0,0 +1,82 @@ +class C { + static #a = { + b: { + c: { + d: 2, + }, + }, + }; + static testIf(o) { + if (o?.#a.b.c.d) { + return true; + } + return false; + } + static testConditional(o) { + return o?.#a.b?.c.d ? true : false; + } + static testLoop(o) { + while (o?.#a.b.c.d) { + for (; o?.#a.b.c?.d; ) { + let i = 0; + do { + i++; + if (i === 2) { + return true; + } + } while (o?.#a.b?.c.d); + } + } + return false; + } + static testNegate(o) { + return !!o?.#a.b?.c.d; + } + static testIfDeep(o) { + if (o.obj?.#a.b?.c.d) { + return true; + } + return false; + } + static testConditionalDeep(o) { + return o.obj?.#a.b?.c.d ? true : false; + } + static testLoopDeep(o) { + while (o.obj?.#a.b.c.d) { + for (; o.obj?.#a.b.c?.d; ) { + let i = 0; + do { + i++; + if (i === 2) { + return true; + } + } while (o.obj?.#a.b?.c.d); + } + } + return false; + } + static testNegateDeep(o) { + return !!o.obj?.#a.b?.c.d; + } + + static testLogicalInIf(o) { + if (o?.#a.b?.c.d && o?.#a?.b.c.d) { + return true; + } + return false; + } + + static testLogicalInReturn(o) { + return o?.#a.b?.c.d && o?.#a?.b.c.d; + } + + static testNullishCoalescing(o) { + if (o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d) { + return o?.#a.b?.c.non_existent ?? o?.#a.b?.c.d; + } + return o?.#a.b?.c.non_existent ?? o; + } +} + +C.test(); +C.testNullish(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/options.json new file mode 100644 index 000000000000..e7e7eecfe816 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/options.json @@ -0,0 +1,4 @@ +{ + "plugins": [["external-helpers", { "helperVersion": "7.100.0" }], "proposal-class-properties"], + "minNodeVersion": "14.0.0" +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/output.js new file mode 100644 index 000000000000..b0c0e6bc3061 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/optional-chain-cast-to-boolean/output.js @@ -0,0 +1,115 @@ +class C { + static testIf(o) { + if (o != null && babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b.c.d) { + return true; + } + + return false; + } + + static testConditional(o) { + return (o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d ? true : false; + } + + static testLoop(o) { + while (o != null && babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b.c.d) { + for (; (o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b.c)?.d;) { + let i = 0; + + do { + i++; + + if (i === 2) { + return true; + } + } while ((o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d); + } + } + + return false; + } + + static testNegate(o) { + return !!(o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d; + } + + static testIfDeep(o) { + var _o$obj; + + if (((_o$obj = o.obj) == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(_o$obj, C, _a).b)?.c.d) { + return true; + } + + return false; + } + + static testConditionalDeep(o) { + var _o$obj2; + + return ((_o$obj2 = o.obj) == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(_o$obj2, C, _a).b)?.c.d ? true : false; + } + + static testLoopDeep(o) { + while ((_o$obj3 = o.obj) != null && babelHelpers.classStaticPrivateFieldSpecGet(_o$obj3, C, _a).b.c.d) { + var _o$obj3; + + for (; ((_o$obj4 = o.obj) == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(_o$obj4, C, _a).b.c)?.d;) { + var _o$obj4; + + let i = 0; + + do { + var _o$obj5; + + i++; + + if (i === 2) { + return true; + } + } while (((_o$obj5 = o.obj) == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(_o$obj5, C, _a).b)?.c.d); + } + } + + return false; + } + + static testNegateDeep(o) { + var _o$obj6; + + return !!((_o$obj6 = o.obj) == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(_o$obj6, C, _a).b)?.c.d; + } + + static testLogicalInIf(o) { + if ((o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d && (o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a))?.b.c.d) { + return true; + } + + return false; + } + + static testLogicalInReturn(o) { + return (o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d && (o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a))?.b.c.d; + } + + static testNullishCoalescing(o) { + if ((o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.non_existent ?? (o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d) { + return (o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.non_existent ?? (o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.d; + } + + return (o == null ? void 0 : babelHelpers.classStaticPrivateFieldSpecGet(o, C, _a).b)?.c.non_existent ?? o; + } + +} + +var _a = { + writable: true, + value: { + b: { + c: { + d: 2 + } + } + } +}; +C.test(); +C.testNullish(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/options.json new file mode 100644 index 000000000000..070c7fc1cc25 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-noDocumentAll/options.json @@ -0,0 +1,5 @@ +{ + "assumptions": { + "noDocumentAll": true + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/computed-initialization-order/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/computed-initialization-order/exec.js new file mode 100644 index 000000000000..339de138c781 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/computed-initialization-order/exec.js @@ -0,0 +1,38 @@ +const actualOrder = []; + +const track = i => { + actualOrder.push(i); + return i; +}; + +class MyClass { + static [track(1)] = track(10); + [track(2)] = track(13); + get [track(3)]() { + return "foo"; + } + set [track(4)](value) { + this.bar = value; + } + [track(5)] = track(14); + static [track(6)] = track(11); + static [track(7)] = track(12); + [track(8)]() {} + [track(9)] = track(15); +} + +const inst = new MyClass(); + +const expectedOrder = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; +expect(actualOrder).toEqual(expectedOrder); + +expect(MyClass[1]).toBe(10); +expect(inst[2]).toBe(13); +expect(inst[3]).toBe("foo"); +inst[4] = "baz"; +expect(inst.bar).toBe("baz"); +expect(inst[5]).toBe(14); +expect(MyClass[6]).toBe(11); +expect(MyClass[7]).toBe(12); +expect(typeof inst[8]).toBe("function"); +expect(inst[9]).toBe(15); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/computed/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/computed/input.js new file mode 100644 index 000000000000..0e777063a283 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/computed/input.js @@ -0,0 +1,25 @@ +const foo = "foo"; +const bar = () => {}; +const four = 4; + +class MyClass { + static [one()] = "test"; + static [2 * 4 + 7] = "247"; + static [2 * four + 7] = "247"; + static [2 * four + seven] = "247"; + [null] = "null"; + [undefined] = "undefined"; + [void 0] = "void 0"; + get ["whatever"]() {} + set ["whatever"](value) {} + get [computed()]() {} + set [computed()](value) {} + ["test" + one]() {} + static [10]() {} + [/regex/] = "regex"; + [foo] = "foo"; + [bar] = "bar"; + [baz] = "baz"; + [`template`] = "template"; + [`template${expression}`] = "template-with-expression"; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/computed/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/computed/output.js new file mode 100644 index 000000000000..a13d0420c8a7 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/computed/output.js @@ -0,0 +1,48 @@ +let _one, _ref, _undefined, _computed, _computed2, _ref2, _ref3, _baz, _ref4; + +const foo = "foo"; + +const bar = () => {}; + +const four = 4; +_one = one(); +_ref = 2 * four + seven; +_undefined = undefined; +_computed = computed(); +_computed2 = computed(); +_ref2 = "test" + one; +_ref3 = /regex/; +_baz = baz; +_ref4 = `template${expression}`; + +class MyClass { + constructor() { + this[null] = "null"; + this[_undefined] = "undefined"; + this[void 0] = "void 0"; + this[_ref3] = "regex"; + this[foo] = "foo"; + this[bar] = "bar"; + this[_baz] = "baz"; + this[`template`] = "template"; + this[_ref4] = "template-with-expression"; + } + + get ["whatever"]() {} + + set ["whatever"](value) {} + + get [_computed]() {} + + set [_computed2](value) {} + + [_ref2]() {} + + static [10]() {} + +} + +MyClass[_one] = "test"; +MyClass[2 * 4 + 7] = "247"; +MyClass[2 * four + 7] = "247"; +MyClass[_ref] = "247"; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/constructor-collision/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/constructor-collision/input.js new file mode 100644 index 000000000000..3071b5edb87b --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/constructor-collision/input.js @@ -0,0 +1,11 @@ +var foo = "bar"; + +class Foo { + bar = foo; + static bar = baz; + + constructor() { + var foo = "foo"; + var baz = "baz"; + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/constructor-collision/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/constructor-collision/output.js new file mode 100644 index 000000000000..58b6d55bfdb6 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/constructor-collision/output.js @@ -0,0 +1,12 @@ +var foo = "bar"; + +class Foo { + constructor() { + this.bar = foo; + var _foo = "foo"; + var baz = "baz"; + } + +} + +Foo.bar = baz; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/derived/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/derived/input.js new file mode 100644 index 000000000000..cd8e3fdd8031 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/derived/input.js @@ -0,0 +1,3 @@ +class Foo extends Bar { + bar = "foo"; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/derived/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/derived/output.js new file mode 100644 index 000000000000..5399e29d2d87 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/derived/output.js @@ -0,0 +1,7 @@ +class Foo extends Bar { + constructor(...args) { + super(...args); + this.bar = "foo"; + } + +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/foobar/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/foobar/input.js new file mode 100644 index 000000000000..60a1c5e823cd --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/foobar/input.js @@ -0,0 +1,9 @@ +class Child extends Parent { + constructor() { + super(); + } + + scopedFunctionWithThis = () => { + this.name = {}; + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/foobar/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/foobar/options.json new file mode 100644 index 000000000000..a56954a5e7ea --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/foobar/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "proposal-class-properties" + ], + "presets": ["env"], + "assumptions": { + "setPublicClassFields": true + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/foobar/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/foobar/output.js new file mode 100644 index 000000000000..86a6067497dc --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/foobar/output.js @@ -0,0 +1,22 @@ +var Child = /*#__PURE__*/function (_Parent) { + "use strict"; + + babelHelpers.inherits(Child, _Parent); + + var _super = babelHelpers.createSuper(Child); + + function Child() { + var _this; + + babelHelpers.classCallCheck(this, Child); + _this = _super.call(this); + + _this.scopedFunctionWithThis = function () { + _this.name = {}; + }; + + return _this; + } + + return Child; +}(Parent); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-computed/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-computed/exec.js new file mode 100644 index 000000000000..3f619174beb4 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-computed/exec.js @@ -0,0 +1,13 @@ +function test(x) { + class F { + [x] = 1; + constructor() {} + } + + x = 'deadbeef'; + expect(new F().foo).toBe(1); + x = 'wrong'; + expect(new F().foo).toBe(1); +} + +test('foo'); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-computed/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-computed/input.js new file mode 100644 index 000000000000..3f619174beb4 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-computed/input.js @@ -0,0 +1,13 @@ +function test(x) { + class F { + [x] = 1; + constructor() {} + } + + x = 'deadbeef'; + expect(new F().foo).toBe(1); + x = 'wrong'; + expect(new F().foo).toBe(1); +} + +test('foo'); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-computed/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-computed/output.js new file mode 100644 index 000000000000..4216994effe0 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-computed/output.js @@ -0,0 +1,19 @@ +function test(x) { + let _x; + + _x = x; + + class F { + constructor() { + this[_x] = 1; + } + + } + + x = 'deadbeef'; + expect(new F().foo).toBe(1); + x = 'wrong'; + expect(new F().foo).toBe(1); +} + +test('foo'); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-undefined/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-undefined/input.js new file mode 100644 index 000000000000..a36cdd975c82 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-undefined/input.js @@ -0,0 +1,3 @@ +class Foo { + bar; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-undefined/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-undefined/output.js new file mode 100644 index 000000000000..8cd3e63f7fcf --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance-undefined/output.js @@ -0,0 +1,6 @@ +class Foo { + constructor() { + this.bar = void 0; + } + +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance/input.js new file mode 100644 index 000000000000..9cecfe8a3013 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance/input.js @@ -0,0 +1,3 @@ +class Foo { + bar = "foo"; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance/output.js new file mode 100644 index 000000000000..f2bdaefe6a7c --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/instance/output.js @@ -0,0 +1,6 @@ +class Foo { + constructor() { + this.bar = "foo"; + } + +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/non-block-arrow-func/input.mjs b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/non-block-arrow-func/input.mjs new file mode 100644 index 000000000000..4b67e0e158f6 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/non-block-arrow-func/input.mjs @@ -0,0 +1,11 @@ +export default param => + class App { + static props = { + prop1: 'prop1', + prop2: 'prop2' + } + + getParam() { + return param; + } + } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/non-block-arrow-func/output.mjs b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/non-block-arrow-func/output.mjs new file mode 100644 index 000000000000..4bacda92aa9c --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/non-block-arrow-func/output.mjs @@ -0,0 +1,13 @@ +export default (param => { + var _class, _temp; + + return _temp = _class = class App { + getParam() { + return param; + } + + }, _class.props = { + prop1: 'prop1', + prop2: 'prop2' + }, _temp; +}); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/options.json new file mode 100644 index 000000000000..018ebbb8d5a8 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "proposal-class-properties", + "syntax-class-properties" + ], + "assumptions": { + "setPublicClassFields": true + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T2983/input.mjs b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T2983/input.mjs new file mode 100644 index 000000000000..2961c9a40366 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T2983/input.mjs @@ -0,0 +1,7 @@ +call(class { + static test = true +}); + +export default class { + static test = true +}; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T2983/output.mjs b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T2983/output.mjs new file mode 100644 index 000000000000..b962b2bfb723 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T2983/output.mjs @@ -0,0 +1,6 @@ +var _class, _temp; + +call((_temp = _class = class {}, _class.test = true, _temp)); +export default class _class2 {} +_class2.test = true; +; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T6719/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T6719/input.js new file mode 100644 index 000000000000..38b9e80baecc --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T6719/input.js @@ -0,0 +1,14 @@ +function withContext(ComposedComponent) { + return class WithContext extends Component { + + static propTypes = { + context: PropTypes.shape( + { + addCss: PropTypes.func, + setTitle: PropTypes.func, + setMeta: PropTypes.func, + } + ), + }; + }; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T6719/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T6719/output.js new file mode 100644 index 000000000000..7e9c64e86abe --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T6719/output.js @@ -0,0 +1,11 @@ +function withContext(ComposedComponent) { + var _class, _temp; + + return _temp = _class = class WithContext extends Component {}, _class.propTypes = { + context: PropTypes.shape({ + addCss: PropTypes.func, + setTitle: PropTypes.func, + setMeta: PropTypes.func + }) + }, _temp; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T7364/input.mjs b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T7364/input.mjs new file mode 100644 index 000000000000..1ddb4a1e7887 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T7364/input.mjs @@ -0,0 +1,17 @@ +class MyClass { + myAsyncMethod = async () => { + console.log(this); + } +} + +(class MyClass2 { + myAsyncMethod = async () => { + console.log(this); + } +}) + +export default class MyClass3 { + myAsyncMethod = async () => { + console.log(this); + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T7364/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T7364/options.json new file mode 100644 index 000000000000..7e57d1f03f2b --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T7364/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + "external-helpers", + "transform-async-to-generator", + "proposal-class-properties" + ], + "assumptions": { + "setPublicClassFields": true + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T7364/output.mjs b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T7364/output.mjs new file mode 100644 index 000000000000..24c39cad22bd --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/regression-T7364/output.mjs @@ -0,0 +1,32 @@ +class MyClass { + constructor() { + var _this = this; + + this.myAsyncMethod = /*#__PURE__*/babelHelpers.asyncToGenerator(function* () { + console.log(_this); + }); + } + +} + +(class MyClass2 { + constructor() { + var _this2 = this; + + this.myAsyncMethod = /*#__PURE__*/babelHelpers.asyncToGenerator(function* () { + console.log(_this2); + }); + } + +}); + +export default class MyClass3 { + constructor() { + var _this3 = this; + + this.myAsyncMethod = /*#__PURE__*/babelHelpers.asyncToGenerator(function* () { + console.log(_this3); + }); + } + +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-export/input.mjs b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-export/input.mjs new file mode 100644 index 000000000000..729475cc52ff --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-export/input.mjs @@ -0,0 +1,7 @@ +export class MyClass { + static property = value; +} + +export default class MyClass2 { + static property = value; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-export/output.mjs b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-export/output.mjs new file mode 100644 index 000000000000..0664f082e29c --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-export/output.mjs @@ -0,0 +1,4 @@ +export class MyClass {} +MyClass.property = value; +export default class MyClass2 {} +MyClass2.property = value; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-infer-name/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-infer-name/exec.js new file mode 100644 index 000000000000..bc62d48d907f --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-infer-name/exec.js @@ -0,0 +1,7 @@ +var Foo = class { + static num = 0; +} + +expect(Foo.num).toBe(0); +expect(Foo.num = 1).toBe(1); +expect(Foo.name).toBe("Foo"); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-infer-name/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-infer-name/input.js new file mode 100644 index 000000000000..96f03df576a0 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-infer-name/input.js @@ -0,0 +1,3 @@ +var Foo = class { + static num = 0; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-infer-name/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-infer-name/output.js new file mode 100644 index 000000000000..812b9613442d --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-infer-name/output.js @@ -0,0 +1,3 @@ +var _class, _temp; + +var Foo = (_temp = _class = class Foo {}, _class.num = 0, _temp); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/input.js new file mode 100644 index 000000000000..9f649ab392bc --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/input.js @@ -0,0 +1,9 @@ +class A { + static prop = 1; +} + +class B extends A { + static prop = 2; + static propA = super.prop; + static getPropA = () => super.prop; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/options.json b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/options.json new file mode 100644 index 000000000000..755819446903 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/options.json @@ -0,0 +1,11 @@ +{ + "validateLogs": true, + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + ["proposal-class-properties", { "loose": true }], + "syntax-class-properties" + ], + "assumptions": { + "setPublicClassFields": true + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/output.js new file mode 100644 index 000000000000..269e97147e8a --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/output.js @@ -0,0 +1,10 @@ +class A {} + +A.prop = 1; + +class B extends A {} + +B.prop = 2; +B.propA = A.prop; + +B.getPropA = () => A.prop; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/stderr.txt b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/stderr.txt new file mode 100644 index 000000000000..2d6c3d02acff --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super-loose/stderr.txt @@ -0,0 +1,5 @@ +[proposal-class-properties]: You are using the "loose: true" option and you are explicitly setting a value for the "setPublicClassFields" assumption. The "loose" option can cause incompatibilities with the other class features plugins, so it's recommended that you replace it with the following top-level option: + "assumptions": { + "setPublicClassFields": true, + "privateFieldsAsProperties": true + } diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super/exec.js new file mode 100644 index 000000000000..4b4e3fcf1a36 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super/exec.js @@ -0,0 +1,15 @@ +class A { + static prop = 1; +} + +class B extends A { + static prop = 2; + static propA = super.prop; + static getPropA = () => super.prop; +} + +const { prop, propA, getPropA } = B; + +expect(prop).toBe(2); +expect(propA).toBe(1); +expect(getPropA()).toBe(1); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super/input.js new file mode 100644 index 000000000000..9f649ab392bc --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super/input.js @@ -0,0 +1,9 @@ +class A { + static prop = 1; +} + +class B extends A { + static prop = 2; + static propA = super.prop; + static getPropA = () => super.prop; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super/output.js new file mode 100644 index 000000000000..2d4da1550419 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-super/output.js @@ -0,0 +1,10 @@ +class A {} + +A.prop = 1; + +class B extends A {} + +B.prop = 2; +B.propA = babelHelpers.get(babelHelpers.getPrototypeOf(B), "prop", B); + +B.getPropA = () => babelHelpers.get(babelHelpers.getPrototypeOf(B), "prop", B); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-this/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-this/exec.js new file mode 100644 index 000000000000..0dbdf7491878 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-this/exec.js @@ -0,0 +1,9 @@ +class A { + static self = this; + static getA = () => this; +} + +const { self, getA } = A; + +expect(self).toBe(A); +expect(getA()).toBe(A); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-this/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-this/input.js new file mode 100644 index 000000000000..59f5c38c2c3e --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-this/input.js @@ -0,0 +1,4 @@ +class A { + static self = this; + static getA = () => this; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-this/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-this/output.js new file mode 100644 index 000000000000..b51f4e90407e --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-this/output.js @@ -0,0 +1,5 @@ +class A {} + +A.self = A; + +A.getA = () => A; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-undefined/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-undefined/exec.js new file mode 100644 index 000000000000..fa1152511452 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-undefined/exec.js @@ -0,0 +1,6 @@ +class Foo { + static num; +} + +expect("num" in Foo).toBe(true); +expect(Foo.num).toBeUndefined(); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-undefined/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-undefined/input.js new file mode 100644 index 000000000000..4ee31b9c3541 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-undefined/input.js @@ -0,0 +1,3 @@ +class Foo { + static bar; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-undefined/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-undefined/output.js new file mode 100644 index 000000000000..d31c6a0733da --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static-undefined/output.js @@ -0,0 +1,3 @@ +class Foo {} + +Foo.bar = void 0; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static/exec.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static/exec.js new file mode 100644 index 000000000000..c7d613dd53d9 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static/exec.js @@ -0,0 +1,9 @@ +class Foo { + static num = 0; + static str = "foo"; +} + +expect(Foo.num).toBe(0); +expect(Foo.num = 1).toBe(1); +expect(Foo.str).toBe("foo"); +expect(Foo.str = "bar").toBe("bar"); diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static/input.js new file mode 100644 index 000000000000..ddc637ec2391 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static/input.js @@ -0,0 +1,3 @@ +class Foo { + static bar = "foo"; +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static/output.js new file mode 100644 index 000000000000..d48d8c76676d --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/static/output.js @@ -0,0 +1,3 @@ +class Foo {} + +Foo.bar = "foo"; diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-call/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-call/input.js new file mode 100644 index 000000000000..175fc704e7e0 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-call/input.js @@ -0,0 +1,9 @@ +class A { + foo() { + return "bar"; + } +} + +class B extends A { + foo = super.foo(); +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-call/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-call/output.js new file mode 100644 index 000000000000..7d557cdf90e3 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-call/output.js @@ -0,0 +1,14 @@ +class A { + foo() { + return "bar"; + } + +} + +class B extends A { + constructor(...args) { + super(...args); + this.foo = super.foo(); + } + +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-expression/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-expression/input.js new file mode 100644 index 000000000000..222dec81a60c --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-expression/input.js @@ -0,0 +1,7 @@ +class Foo extends Bar { + bar = "foo"; + + constructor() { + foo(super()); + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-expression/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-expression/output.js new file mode 100644 index 000000000000..6896211d2e9d --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-expression/output.js @@ -0,0 +1,8 @@ +class Foo extends Bar { + constructor() { + var _temp; + + foo((_temp = super(), this.bar = "foo", _temp)); + } + +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-statement/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-statement/input.js new file mode 100644 index 000000000000..0af8843375d4 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-statement/input.js @@ -0,0 +1,7 @@ +class Foo extends Bar { + bar = "foo"; + + constructor() { + super(); + } +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-statement/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-statement/output.js new file mode 100644 index 000000000000..73e8f7eb4971 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-statement/output.js @@ -0,0 +1,7 @@ +class Foo extends Bar { + constructor() { + super(); + this.bar = "foo"; + } + +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-with-collision/input.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-with-collision/input.js new file mode 100644 index 000000000000..a9552f3068e1 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-with-collision/input.js @@ -0,0 +1,6 @@ +class A { + force = force; + foo = super.method(); + + constructor(force) {} +} diff --git a/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-with-collision/output.js b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-with-collision/output.js new file mode 100644 index 000000000000..19d410990a03 --- /dev/null +++ b/packages/babel-plugin-proposal-class-properties/test/fixtures/assumption-setPublicClassFields/super-with-collision/output.js @@ -0,0 +1,7 @@ +class A { + constructor(_force) { + this.force = force; + this.foo = super.method(); + } + +} diff --git a/packages/babel-plugin-proposal-decorators/src/index.js b/packages/babel-plugin-proposal-decorators/src/index.js index 879de5f04703..a7e142769038 100644 --- a/packages/babel-plugin-proposal-decorators/src/index.js +++ b/packages/babel-plugin-proposal-decorators/src/index.js @@ -50,6 +50,7 @@ export default declare((api, options) => { return createClassFeaturePlugin({ name: "proposal-decorators", + api, feature: FEATURES.decorators, // loose: options.loose, Not supported diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/src/index.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/src/index.js index 12ddbc7cba97..ae948bad9a12 100644 --- a/packages/babel-plugin-proposal-nullish-coalescing-operator/src/index.js +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/src/index.js @@ -4,6 +4,7 @@ import { types as t, template } from "@babel/core"; export default declare((api, { loose = false }) => { api.assertVersion(7); + const noDocumentAll = api.assumption("noDocumentAll") ?? loose; return { name: "proposal-nullish-coalescing-operator", @@ -38,7 +39,7 @@ export default declare((api, { loose = false }) => { t.conditionalExpression( // We cannot use `!= null` in spec mode because // `document.all == null` and `document.all` is not "nullish". - loose + noDocumentAll ? t.binaryExpression("!=", assignment, t.nullLiteral()) : t.logicalExpression( "&&", diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/options.json b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/options.json new file mode 100644 index 000000000000..d0c9dda0ccc3 --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/options.json @@ -0,0 +1,6 @@ +{ + "plugins": ["proposal-nullish-coalescing-operator"], + "assumptions": { + "noDocumentAll": true + } +} diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/runtime-semantics/exec.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/runtime-semantics/exec.js new file mode 100644 index 000000000000..b2b21ccec9ff --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/runtime-semantics/exec.js @@ -0,0 +1,19 @@ +expect(null ?? undefined).toBeUndefined(undefined); +expect(undefined ?? null).toBeNull(); +expect(false ?? true).toBe(false); +expect(0 ?? 1).toBe(0); +expect("" ?? "foo").toBe(""); + +var obj = { exists: true }; +expect(obj.exists ?? false).toBe(true); +expect(obj.doesNotExist ?? "foo").toBe("foo"); + +var counter = 0; +function sideEffect() { return counter++; } +expect(sideEffect() ?? -1).toBe(0); + +var counter2 = 0; +var obj2 = { + get foo() { return counter2++; } +}; +expect(obj2.foo ?? -1).toBe(0); diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-destructuring/input.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-destructuring/input.js new file mode 100644 index 000000000000..876e05c1a625 --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-destructuring/input.js @@ -0,0 +1 @@ +var { qux = foo.bar ?? "qux" } = {}; diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-destructuring/output.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-destructuring/output.js new file mode 100644 index 000000000000..18d9e6f39130 --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-destructuring/output.js @@ -0,0 +1,5 @@ +var _foo$bar; + +var { + qux = (_foo$bar = foo.bar) != null ? _foo$bar : "qux" +} = {}; diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-param/input.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-param/input.js new file mode 100644 index 000000000000..65b7719722bc --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-param/input.js @@ -0,0 +1,3 @@ +function foo(foo, qux = foo.bar ?? "qux") {} + +function bar(bar, qux = bar ?? "qux") {} diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-param/output.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-param/output.js new file mode 100644 index 000000000000..97f53f5aedd3 --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-default-param/output.js @@ -0,0 +1,7 @@ +function foo(foo, qux = (() => { + var _foo$bar; + + return (_foo$bar = foo.bar) != null ? _foo$bar : "qux"; +})()) {} + +function bar(bar, qux = bar != null ? bar : "qux") {} diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-function/input.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-function/input.js new file mode 100644 index 000000000000..63b28b6c23cb --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-function/input.js @@ -0,0 +1,3 @@ +function foo(opts) { + var foo = opts.foo ?? "default"; +} diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-function/output.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-function/output.js new file mode 100644 index 000000000000..ee76d1c950a9 --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-in-function/output.js @@ -0,0 +1,5 @@ +function foo(opts) { + var _opts$foo; + + var foo = (_opts$foo = opts.foo) != null ? _opts$foo : "default"; +} diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-default/input.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-default/input.js new file mode 100644 index 000000000000..7c7dcae88cf4 --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-default/input.js @@ -0,0 +1 @@ +function foo(foo, bar = foo ?? "bar") {} diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-default/output.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-default/output.js new file mode 100644 index 000000000000..d725908ed2a8 --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-default/output.js @@ -0,0 +1 @@ +function foo(foo, bar = foo != null ? foo : "bar") {} diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-function/input.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-function/input.js new file mode 100644 index 000000000000..8e488a306361 --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-function/input.js @@ -0,0 +1,3 @@ +function foo() { + var foo = this ?? {}; +} diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-function/output.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-function/output.js new file mode 100644 index 000000000000..cbf17bc50297 --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform-static-refs-in-function/output.js @@ -0,0 +1,3 @@ +function foo() { + var foo = this != null ? this : {}; +} diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform/input.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform/input.js new file mode 100644 index 000000000000..63b28b6c23cb --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform/input.js @@ -0,0 +1,3 @@ +function foo(opts) { + var foo = opts.foo ?? "default"; +} diff --git a/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform/output.js b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform/output.js new file mode 100644 index 000000000000..ee76d1c950a9 --- /dev/null +++ b/packages/babel-plugin-proposal-nullish-coalescing-operator/test/fixtures/assumption-noDocumentAll/transform/output.js @@ -0,0 +1,5 @@ +function foo(opts) { + var _opts$foo; + + var foo = (_opts$foo = opts.foo) != null ? _opts$foo : "default"; +} diff --git a/packages/babel-plugin-proposal-object-rest-spread/src/index.js b/packages/babel-plugin-proposal-object-rest-spread/src/index.js index e1f9b7d51016..7179c20899ba 100644 --- a/packages/babel-plugin-proposal-object-rest-spread/src/index.js +++ b/packages/babel-plugin-proposal-object-rest-spread/src/index.js @@ -23,6 +23,11 @@ export default declare((api, opts) => { throw new Error(".loose must be a boolean, or undefined"); } + const ignoreFunctionLength = api.assumption("ignoreFunctionLength") ?? loose; + const objectRestNoSymbols = api.assumption("objectRestNoSymbols") ?? loose; + const pureGetters = api.assumption("pureGetters") ?? loose; + const setSpreadProperties = api.assumption("setSpreadProperties") ?? loose; + function getExtendsHelper(file) { return useBuiltIns ? t.memberExpression(t.identifier("Object"), t.identifier("assign")) @@ -133,7 +138,7 @@ export default declare((api, opts) => { } //expects path to an object pattern - function createObjectSpread(path, file, objRef) { + function createObjectRest(path, file, objRef) { const props = path.get("properties"); const last = props[props.length - 1]; t.assertRestElement(last.node); @@ -172,7 +177,9 @@ export default declare((api, opts) => { impureComputedPropertyDeclarators, restElement.argument, t.callExpression( - file.addHelper(`objectWithoutProperties${loose ? "Loose" : ""}`), + file.addHelper( + `objectWithoutProperties${objectRestNoSymbols ? "Loose" : ""}`, + ), [t.cloneNode(objRef), keyExpression], ), ]; @@ -275,7 +282,7 @@ export default declare((api, opts) => { idx >= i - 1 || paramsWithRestElement.has(idx); convertFunctionParams( path, - loose, + ignoreFunctionLength, shouldTransformParam, replaceRestElement, ); @@ -361,9 +368,9 @@ export default declare((api, opts) => { impureComputedPropertyDeclarators, argument, callExpression, - ] = createObjectSpread(objectPatternPath, file, ref); + ] = createObjectRest(objectPatternPath, file, ref); - if (loose) { + if (pureGetters) { removeUnusedExcludedKeys(objectPatternPath); } @@ -444,7 +451,7 @@ export default declare((api, opts) => { impureComputedPropertyDeclarators, argument, callExpression, - ] = createObjectSpread(leftPath, file, t.identifier(refName)); + ] = createObjectRest(leftPath, file, t.identifier(refName)); if (impureComputedPropertyDeclarators.length > 0) { nodes.push( @@ -553,7 +560,7 @@ export default declare((api, opts) => { if (!hasSpread(path.node)) return; let helper; - if (loose) { + if (setSpreadProperties) { helper = getExtendsHelper(file); } else { try { @@ -583,10 +590,9 @@ export default declare((api, opts) => { return; } - // In loose mode, we don't want to make multiple calls. We're assuming - // that the spread objects either don't use getters, or that the - // getters are pure and don't depend on the order of evaluation. - if (loose) { + // When we can assume that getters are pure and don't depend on + // the order of evaluation, we can avoid making multiple calls. + if (pureGetters) { if (hadProps) { exp.arguments.push(obj); } diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-ignoreFunctionLength/options.json b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-ignoreFunctionLength/options.json new file mode 100644 index 000000000000..ec966b0b43ba --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-ignoreFunctionLength/options.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + "proposal-object-rest-spread" + ], + "assumptions": { + "ignoreFunctionLength": true + } +} diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-ignoreFunctionLength/parameters-object-rest-used-in-default/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-ignoreFunctionLength/parameters-object-rest-used-in-default/input.js new file mode 100644 index 000000000000..000e99bcf250 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-ignoreFunctionLength/parameters-object-rest-used-in-default/input.js @@ -0,0 +1,3 @@ +({...R}, a = R) => {} +({...R}, e, c = 2, a = R, f = q) => { let q; } +({...R}, a = f(R)) => {} diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-ignoreFunctionLength/parameters-object-rest-used-in-default/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-ignoreFunctionLength/parameters-object-rest-used-in-default/output.js new file mode 100644 index 000000000000..84e28e863e5b --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-ignoreFunctionLength/parameters-object-rest-used-in-default/output.js @@ -0,0 +1,33 @@ +function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } + +(_ref, a) => { + let R = _extends({}, _ref); + + if (a === void 0) { + a = R; + } +}; + +(_ref2, e, c = 2, a, f) => { + let R = _extends({}, _ref2); + + if (a === void 0) { + a = R; + } + + if (f === void 0) { + f = q; + } + + return function () { + let q; + }(); +}; + +(_ref3, a) => { + let R = _extends({}, _ref3); + + if (a === void 0) { + a = f(R); + } +}; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/options.json b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/options.json new file mode 100644 index 000000000000..0640a8088af0 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0"}], + "proposal-object-rest-spread" + ], + "assumptions": { + "objectRestNoSymbols": true + } +} diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/input.js new file mode 100644 index 000000000000..f03be37640bc --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/input.js @@ -0,0 +1 @@ +({ a, b, ...c } = obj); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/output.js new file mode 100644 index 000000000000..a1b0485e897b --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/output.js @@ -0,0 +1,7 @@ +var _obj = obj; +({ + a, + b +} = _obj); +c = babelHelpers.objectWithoutPropertiesLoose(_obj, ["a", "b"]); +_obj; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-computed/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-computed/input.js new file mode 100644 index 000000000000..8ddf55177eac --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-computed/input.js @@ -0,0 +1 @@ +let { [a]: b, ...c } = obj; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-computed/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-computed/output.js new file mode 100644 index 000000000000..ffc31792901e --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-computed/output.js @@ -0,0 +1,5 @@ +let _a = a, + { + [_a]: b +} = obj, + c = babelHelpers.objectWithoutPropertiesLoose(obj, [_a].map(babelHelpers.toPropertyKey)); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-ignore-symbols/exec.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-ignore-symbols/exec.js new file mode 100644 index 000000000000..2c85a4c5711e --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-ignore-symbols/exec.js @@ -0,0 +1,7 @@ +let sym = Symbol(); + +let { a, ...r } = { a: 1, b: 2, [sym]: 3 }; + +expect(a).toBe(1); +expect(r.b).toBe(2); +expect(sym in r).toBe(false); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-nested/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-nested/input.js new file mode 100644 index 000000000000..e1025ccc4cb9 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-nested/input.js @@ -0,0 +1 @@ +let { a, nested: { b, c, ...d }, e } = obj; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-nested/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-nested/output.js new file mode 100644 index 000000000000..8a0d9f86b1b7 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-nested/output.js @@ -0,0 +1,9 @@ +let { + a, + nested: { + b, + c + }, + e +} = obj, + d = babelHelpers.objectWithoutPropertiesLoose(obj.nested, ["b", "c"]); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/input.js new file mode 100644 index 000000000000..099aa76e4907 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/input.js @@ -0,0 +1 @@ +var { a, b, ...c } = obj; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/output.js new file mode 100644 index 000000000000..dbacd1a572a3 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/output.js @@ -0,0 +1,5 @@ +var { + a, + b +} = obj, + c = babelHelpers.objectWithoutPropertiesLoose(obj, ["a", "b"]); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/options.json b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/options.json new file mode 100644 index 000000000000..63724ae13025 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0"}], + "proposal-object-rest-spread" + ], + "assumptions": { + "pureGetters": true + } +} diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/rest-remove-unused-excluded-keys/exec.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/rest-remove-unused-excluded-keys/exec.js new file mode 100644 index 000000000000..d3ad45c50d79 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/rest-remove-unused-excluded-keys/exec.js @@ -0,0 +1,11 @@ +let called = false; +let obj = { + get foo() { called = true } +}; + +let { foo, ...rest } = obj; + +expect("foo" in rest).toBe(false); + +// Without assuming that getters are pure (in this case it isn't), this should be true +expect(called).toBe(false); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/rest-remove-unused-excluded-keys/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/rest-remove-unused-excluded-keys/input.js new file mode 100644 index 000000000000..848847b6d5af --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/rest-remove-unused-excluded-keys/input.js @@ -0,0 +1,20 @@ +// should not remove when destructuring into existing bindings +({ a2, ...b2 } = c2); + +function render() { + const { + excluded, + excluded2: excludedRenamed, + used, + used2: usedRenamed, + ...props + } = this.props; + + console.log(used, usedRenamed); + + return React.createElement("input", props); +} + +function smth({ unused, ...rest }) { + call(rest); +} diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/rest-remove-unused-excluded-keys/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/rest-remove-unused-excluded-keys/output.js new file mode 100644 index 000000000000..cf80c637a3ef --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/rest-remove-unused-excluded-keys/output.js @@ -0,0 +1,23 @@ +// should not remove when destructuring into existing bindings +var _c = c2; +({ + a2 +} = _c); +b2 = babelHelpers.objectWithoutProperties(_c, ["a2"]); +_c; + +function render() { + const _this$props = this.props, + { + used, + used2: usedRenamed + } = _this$props, + props = babelHelpers.objectWithoutProperties(_this$props, ["excluded", "excluded2", "used", "used2"]); + console.log(used, usedRenamed); + return React.createElement("input", props); +} + +function smth(_ref) { + let rest = babelHelpers.objectWithoutProperties(_ref, ["unused"]); + call(rest); +} diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/spread-single-call/exec.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/spread-single-call/exec.js new file mode 100644 index 000000000000..16e821917d0e --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/spread-single-call/exec.js @@ -0,0 +1,10 @@ +let count = 0; + +let withFoo = { get foo() { return count++; } }; +let withBar = { get bar() { return count++; } }; + +let res = { ...withFoo, middle: count, ...withBar }; + +// Without assuming that getters are pure (in this case it isn't), +// the result should be { foo: 0, middle: 1, bar: 1 } +expect(res).toEqual({ foo: 0, middle: 0, bar: 1 }); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/spread-single-call/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/spread-single-call/input.js new file mode 100644 index 000000000000..bfc9f72440df --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/spread-single-call/input.js @@ -0,0 +1 @@ +let obj = { a, ...b, c, ...d, e }; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/spread-single-call/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/spread-single-call/output.js new file mode 100644 index 000000000000..6aae4df0db26 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-pureGetters/spread-single-call/output.js @@ -0,0 +1,7 @@ +let obj = babelHelpers.objectSpread2({ + a +}, b, { + c +}, d, { + e +}); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/assignment/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/assignment/input.js new file mode 100644 index 000000000000..093a8e9f9351 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/assignment/input.js @@ -0,0 +1,7 @@ +var x; +var y; +var z; + +z = { x, ...y }; + +z = { x, w: { ...y } }; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/assignment/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/assignment/output.js new file mode 100644 index 000000000000..8e9602898ed6 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/assignment/output.js @@ -0,0 +1,10 @@ +var x; +var y; +var z; +z = Object.assign({ + x +}, y); +z = { + x, + w: Object.assign({}, y) +}; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/expression/exec.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/expression/exec.js new file mode 100644 index 000000000000..b57d8d3222b9 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/expression/exec.js @@ -0,0 +1,9 @@ +var log = []; + +var a = { + ...{ get foo() { log.push(1); } }, + get bar() { log.push(2); } +}; + +// Loose mode uses regular Get, not GetOwnProperty. +expect(log).toEqual([1, 2]); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/expression/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/expression/input.js new file mode 100644 index 000000000000..da4e7b689505 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/expression/input.js @@ -0,0 +1,16 @@ +var a; +var b; +var c; +var d; +var x; +var y; + +({ x, ...y, a, ...b, c }); + +({ ...Object.prototype }); + +({ ...{ foo: 'bar' } }); + +({ ...{ foo: 'bar' }, ...{ bar: 'baz' } }); + +({ ...{ get foo () { return 'foo' } } }); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/expression/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/expression/output.js new file mode 100644 index 000000000000..cfd3f3b62882 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/expression/output.js @@ -0,0 +1,28 @@ +var a; +var b; +var c; +var d; +var x; +var y; +Object.assign(Object.assign(Object.assign({ + x +}, y), {}, { + a +}, b), {}, { + c +}); +Object.assign({}, Object.prototype); +Object.assign({}, { + foo: 'bar' +}); +Object.assign(Object.assign({}, { + foo: 'bar' +}), { + bar: 'baz' +}); +Object.assign({}, { + get foo() { + return 'foo'; + } + +}); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/no-getOwnPropertyDescriptors/exec.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/no-getOwnPropertyDescriptors/exec.js new file mode 100644 index 000000000000..e4674d812a50 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/no-getOwnPropertyDescriptors/exec.js @@ -0,0 +1,9 @@ +const oldGOPDs = Object.getOwnPropertyDescriptors; +Object.getOwnPropertyDescriptors = null; + +try { + ({ ...{ a: 1 }, b: 1, ...{} }); +} finally { + Object.getOwnPropertyDescriptors = oldGOPDs; +} + diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/no-object-assign-exec/exec.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/no-object-assign-exec/exec.js new file mode 100644 index 000000000000..4d937710e367 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/no-object-assign-exec/exec.js @@ -0,0 +1,43 @@ +"use strict"; +Object.defineProperty(Object.prototype, 'NOSET', { + get(value) { + // noop + }, +}); + +Object.defineProperty(Object.prototype, 'NOWRITE', { + writable: false, + value: 'abc', +}); + +const obj = { 'NOSET': 123 }; +// this won't work as expected if transformed as Object.assign (or equivalent) +// because those trigger object setters (spread don't) +expect(() => { + const objSpread = { ...obj }; +}).toThrow(); + +const obj2 = { 'NOWRITE': 456 }; +// this throws `TypeError: Cannot assign to read only property 'NOWRITE'` +// if transformed as Object.assign (or equivalent) because those use *assignment* for creating properties +// (spread defines them) +expect(() => { + const obj2Spread = { ...obj2 }; +}).toThrow(); + +const KEY = Symbol('key'); +const obj3Spread = { ...{ get foo () { return 'bar' } }, [KEY]: 'symbol' }; +expect(Object.getOwnPropertyDescriptor(obj3Spread, 'foo').value).toBe('bar'); +expect(Object.getOwnPropertyDescriptor(obj3Spread, KEY).value).toBe('symbol'); + +const obj4Spread = { ...Object.prototype }; +expect(Object.getOwnPropertyDescriptor(obj4Spread, 'hasOwnProperty')).toBeUndefined(); + +expect(() => ({ ...null, ...undefined })).not.toThrow(); + +const o = Object.create(null); +o.a = 'foo'; +o.__proto__ = []; +const o2 = { ...o }; +// Loose will do o2.__proto__ = [] +expect(Array.isArray(Object.getPrototypeOf(o2))).toBe(true); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/options.json b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/options.json new file mode 100644 index 000000000000..d9e80e039563 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties-with-useBuiltIns/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0"}], + ["proposal-object-rest-spread", { "useBuiltIns": true }] + ], + "assumptions": { + "setSpreadProperties": true + } +} diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/assignment/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/assignment/input.js new file mode 100644 index 000000000000..093a8e9f9351 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/assignment/input.js @@ -0,0 +1,7 @@ +var x; +var y; +var z; + +z = { x, ...y }; + +z = { x, w: { ...y } }; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/assignment/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/assignment/output.js new file mode 100644 index 000000000000..3e34747bd999 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/assignment/output.js @@ -0,0 +1,10 @@ +var x; +var y; +var z; +z = babelHelpers.extends({ + x +}, y); +z = { + x, + w: babelHelpers.extends({}, y) +}; diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/expression/exec.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/expression/exec.js new file mode 100644 index 000000000000..b57d8d3222b9 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/expression/exec.js @@ -0,0 +1,9 @@ +var log = []; + +var a = { + ...{ get foo() { log.push(1); } }, + get bar() { log.push(2); } +}; + +// Loose mode uses regular Get, not GetOwnProperty. +expect(log).toEqual([1, 2]); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/expression/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/expression/input.js new file mode 100644 index 000000000000..da4e7b689505 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/expression/input.js @@ -0,0 +1,16 @@ +var a; +var b; +var c; +var d; +var x; +var y; + +({ x, ...y, a, ...b, c }); + +({ ...Object.prototype }); + +({ ...{ foo: 'bar' } }); + +({ ...{ foo: 'bar' }, ...{ bar: 'baz' } }); + +({ ...{ get foo () { return 'foo' } } }); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/expression/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/expression/output.js new file mode 100644 index 000000000000..a21536eeb3aa --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/expression/output.js @@ -0,0 +1,28 @@ +var a; +var b; +var c; +var d; +var x; +var y; +babelHelpers.extends(babelHelpers.extends(babelHelpers.extends({ + x +}, y), {}, { + a +}, b), {}, { + c +}); +babelHelpers.extends({}, Object.prototype); +babelHelpers.extends({}, { + foo: 'bar' +}); +babelHelpers.extends(babelHelpers.extends({}, { + foo: 'bar' +}), { + bar: 'baz' +}); +babelHelpers.extends({}, { + get foo() { + return 'foo'; + } + +}); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/no-getOwnPropertyDescriptors/exec.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/no-getOwnPropertyDescriptors/exec.js new file mode 100644 index 000000000000..e4674d812a50 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/no-getOwnPropertyDescriptors/exec.js @@ -0,0 +1,9 @@ +const oldGOPDs = Object.getOwnPropertyDescriptors; +Object.getOwnPropertyDescriptors = null; + +try { + ({ ...{ a: 1 }, b: 1, ...{} }); +} finally { + Object.getOwnPropertyDescriptors = oldGOPDs; +} + diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/no-object-assign-exec/exec.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/no-object-assign-exec/exec.js new file mode 100644 index 000000000000..4d937710e367 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/no-object-assign-exec/exec.js @@ -0,0 +1,43 @@ +"use strict"; +Object.defineProperty(Object.prototype, 'NOSET', { + get(value) { + // noop + }, +}); + +Object.defineProperty(Object.prototype, 'NOWRITE', { + writable: false, + value: 'abc', +}); + +const obj = { 'NOSET': 123 }; +// this won't work as expected if transformed as Object.assign (or equivalent) +// because those trigger object setters (spread don't) +expect(() => { + const objSpread = { ...obj }; +}).toThrow(); + +const obj2 = { 'NOWRITE': 456 }; +// this throws `TypeError: Cannot assign to read only property 'NOWRITE'` +// if transformed as Object.assign (or equivalent) because those use *assignment* for creating properties +// (spread defines them) +expect(() => { + const obj2Spread = { ...obj2 }; +}).toThrow(); + +const KEY = Symbol('key'); +const obj3Spread = { ...{ get foo () { return 'bar' } }, [KEY]: 'symbol' }; +expect(Object.getOwnPropertyDescriptor(obj3Spread, 'foo').value).toBe('bar'); +expect(Object.getOwnPropertyDescriptor(obj3Spread, KEY).value).toBe('symbol'); + +const obj4Spread = { ...Object.prototype }; +expect(Object.getOwnPropertyDescriptor(obj4Spread, 'hasOwnProperty')).toBeUndefined(); + +expect(() => ({ ...null, ...undefined })).not.toThrow(); + +const o = Object.create(null); +o.a = 'foo'; +o.__proto__ = []; +const o2 = { ...o }; +// Loose will do o2.__proto__ = [] +expect(Array.isArray(Object.getPrototypeOf(o2))).toBe(true); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/options.json b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/options.json new file mode 100644 index 000000000000..2ac8b8a6e836 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/assumption-setSpreadProperties/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0"}], + "proposal-object-rest-spread" + ], + "assumptions": { + "setSpreadProperties": true + } +} diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-extra/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-object-rest-used-in-default/input.js similarity index 100% rename from packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-extra/input.js rename to packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-object-rest-used-in-default/input.js diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-extra/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-object-rest-used-in-default/output.js similarity index 100% rename from packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-extra/output.js rename to packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/parameters-object-rest-used-in-default/output.js diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-spread-loose/parameters-object-rest-used-in-default/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-spread-loose/parameters-object-rest-used-in-default/input.js new file mode 100644 index 000000000000..000e99bcf250 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-spread-loose/parameters-object-rest-used-in-default/input.js @@ -0,0 +1,3 @@ +({...R}, a = R) => {} +({...R}, e, c = 2, a = R, f = q) => { let q; } +({...R}, a = f(R)) => {} diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-spread-loose/parameters-object-rest-used-in-default/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-spread-loose/parameters-object-rest-used-in-default/output.js new file mode 100644 index 000000000000..84e28e863e5b --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-spread-loose/parameters-object-rest-used-in-default/output.js @@ -0,0 +1,33 @@ +function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } + +(_ref, a) => { + let R = _extends({}, _ref); + + if (a === void 0) { + a = R; + } +}; + +(_ref2, e, c = 2, a, f) => { + let R = _extends({}, _ref2); + + if (a === void 0) { + a = R; + } + + if (f === void 0) { + f = q; + } + + return function () { + let q; + }(); +}; + +(_ref3, a) => { + let R = _extends({}, _ref3); + + if (a === void 0) { + a = f(R); + } +}; diff --git a/packages/babel-plugin-proposal-optional-chaining/src/index.js b/packages/babel-plugin-proposal-optional-chaining/src/index.js index 052c71b6f048..d6e72baa0f98 100644 --- a/packages/babel-plugin-proposal-optional-chaining/src/index.js +++ b/packages/babel-plugin-proposal-optional-chaining/src/index.js @@ -13,6 +13,8 @@ export default declare((api, options) => { api.assertVersion(7); const { loose = false } = options; + const noDocumentAll = api.assumption("noDocumentAll") ?? loose; + const pureGetters = api.assumption("pureGetters") ?? loose; function isSimpleMemberExpression(expression) { expression = skipTransparentExprWrappers(expression); @@ -127,8 +129,8 @@ export default declare((api, options) => { check = ref = chain; // `eval?.()` is an indirect eval call transformed to `(0,eval)()` node[replaceKey] = t.sequenceExpression([t.numericLiteral(0), ref]); - } else if (loose && isCall && isSimpleMemberExpression(chain)) { - // If we are using a loose transform (avoiding a Function#call) and we are at the call, + } else if (pureGetters && isCall && isSimpleMemberExpression(chain)) { + // If we assume getters are pure (avoiding a Function#call) and we are at the call, // we can avoid a needless memoize. We only do this if the callee is a simple member // expression, to avoid multiple calls to nested call expressions. check = ref = chainWithTypes; @@ -153,7 +155,7 @@ export default declare((api, options) => { // Ensure call expressions have the proper `this` // `foo.bar()` has context `foo`. if (isCall && t.isMemberExpression(chain)) { - if (loose && isSimpleMemberExpression(chain)) { + if (pureGetters && isSimpleMemberExpression(chain)) { // To avoid a Function#call, we can instead re-grab the property from the context object. // `a.?b.?()` translates roughly to `_a.b != null && _a.b()` node.callee = chainWithTypes; @@ -188,8 +190,9 @@ export default declare((api, options) => { replacementPath.get("object"), ).node; let baseRef; - if (!loose || !isSimpleMemberExpression(object)) { - // memoize the context object in non-loose mode + if (!pureGetters || !isSimpleMemberExpression(object)) { + // memoize the context object when getters are not always pure + // or the object is not a simple member expression // `(a?.b.c)()` to `(a == null ? undefined : (_a$b = a.b).c.bind(_a$b))()` baseRef = scope.maybeGenerateMemoised(object); if (baseRef) { @@ -210,7 +213,7 @@ export default declare((api, options) => { // `if (a?.b) {}` transformed to `if (a != null && a.b) {}` // we don't need to return `void 0` because the returned value will // eveutally cast to boolean. - const nonNullishCheck = loose + const nonNullishCheck = noDocumentAll ? ast`${t.cloneNode(check)} != null` : ast` ${t.cloneNode(check)} !== null && ${t.cloneNode(ref)} !== void 0`; @@ -221,7 +224,7 @@ export default declare((api, options) => { replacementPath.get("right"), ); } else { - const nullishCheck = loose + const nullishCheck = noDocumentAll ? ast`${t.cloneNode(check)} == null` : ast` ${t.cloneNode(check)} === null || ${t.cloneNode(ref)} === void 0`; diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/assignment/exec.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/assignment/exec.js new file mode 100644 index 000000000000..48bcd49d016e --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/assignment/exec.js @@ -0,0 +1,28 @@ +"use strict"; + +const obj = { + a: { + b: { + c: { + d: 2, + }, + }, + }, +}; + +const a = obj?.a; +expect(a).toBe(obj.a); + +const b = obj?.a?.b; +expect(b).toBe(obj.a.b); + +const bad = obj?.b?.b; +expect(bad).toBeUndefined(); + +let val; +val = obj?.a?.b; +expect(val).toBe(obj.a.b); + +expect(() => { + const bad = obj?.b.b; +}).toThrow(); diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/assignment/input.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/assignment/input.js new file mode 100644 index 000000000000..86e2d6e46d22 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/assignment/input.js @@ -0,0 +1,20 @@ +"use strict"; + +const obj = { + a: { + b: { + c: { + d: 2, + }, + }, + }, +}; + +const a = obj?.a; + +const b = obj?.a?.b; + +const bad = obj?.b?.b; + +let val; +val = obj?.a?.b; diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/assignment/output.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/assignment/output.js new file mode 100644 index 000000000000..778b9a11d450 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/assignment/output.js @@ -0,0 +1,18 @@ +"use strict"; + +var _obj$a, _obj$b, _obj$a2; + +const obj = { + a: { + b: { + c: { + d: 2 + } + } + } +}; +const a = obj == null ? void 0 : obj.a; +const b = obj == null ? void 0 : (_obj$a = obj.a) == null ? void 0 : _obj$a.b; +const bad = obj == null ? void 0 : (_obj$b = obj.b) == null ? void 0 : _obj$b.b; +let val; +val = obj == null ? void 0 : (_obj$a2 = obj.a) == null ? void 0 : _obj$a2.b; diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/call/exec.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/call/exec.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/exec.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/exec.js new file mode 100644 index 000000000000..77ae4c0a0706 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/exec.js @@ -0,0 +1,120 @@ +class C { + static testIf(o) { + if (o?.a.b.c.d) { + return true; + } + return false; + } + static testConditional(o) { + return o?.a.b?.c.d ? true : false; + } + static testLoop(o) { + while (o?.a.b.c.d) { + for (; o?.a.b.c?.d; ) { + let i = 0; + do { + i++; + if (i === 2) { + return true; + } + } while (o?.a.b?.c.d); + } + } + return false; + } + static testNegate(o) { + return !!o?.a.b?.c.d; + } + static testIfDeep(o) { + if (o.obj?.a.b?.c.d) { + return true; + } + return false; + } + static testConditionalDeep(o) { + return o.obj?.a.b?.c.d ? true : false; + } + static testLoopDeep(o) { + while (o.obj?.a.b.c.d) { + for (; o.obj?.a.b.c?.d; ) { + let i = 0; + do { + i++; + if (i === 2) { + return true; + } + } while (o.obj?.a.b?.c.d); + } + } + return false; + } + static testNegateDeep(o) { + return !!o.obj?.a.b?.c.d; + } + + static testLogicalInIf(o) { + if (o?.a.b?.c.d && o?.a?.b.c.d) { + return true; + } + return false; + } + + static testLogicalInReturn(o) { + return o?.a.b?.c.d && o?.a?.b.c.d; + } + + static testNullishCoalescing(o) { + if (o?.a.b?.c.non_existent ?? o?.a.b?.c.d) { + return o?.a.b?.c.non_existent ?? o?.a.b?.c.d; + } + return o?.a.b?.c.non_existent ?? o; + } + + static test() { + const c = { + a: { + b: { + c: { + d: 2, + }, + }, + }, + }; + expect(C.testIf(c)).toBe(true); + expect(C.testConditional(c)).toBe(true); + expect(C.testLoop(c)).toBe(true); + expect(C.testNegate(c)).toBe(true); + + expect(C.testIfDeep({ obj: c })).toBe(true); + expect(C.testConditionalDeep({ obj: c })).toBe(true); + expect(C.testLoopDeep({ obj: c })).toBe(true); + expect(C.testNegateDeep({ obj: c })).toBe(true); + + expect(C.testLogicalInIf(c)).toBe(true); + expect(C.testLogicalInReturn(c)).toBe(2); + + expect(C.testNullishCoalescing(c)).toBe(2); + } + + static testNullish() { + for (const n of [null, undefined]) { + expect(C.testIf(n)).toBe(false); + expect(C.testConditional(n)).toBe(false); + expect(C.testLoop(n)).toBe(false); + expect(C.testNegate(n)).toBe(false); + + expect(C.testIfDeep({ obj: n })).toBe(false); + expect(C.testConditionalDeep({ obj: n })).toBe(false); + expect(C.testLoopDeep({ obj: n })).toBe(false); + expect(C.testNegateDeep({ obj: n })).toBe(false); + + expect(C.testLogicalInIf(n)).toBe(false); + expect(C.testLogicalInReturn(n)).toBe(undefined); + + expect(C.testNullishCoalescing(n)).toBe(n); + } + } +} + +C.test(); +C.testNullish(); diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/input.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/input.js new file mode 100644 index 000000000000..a9aab8bee395 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/input.js @@ -0,0 +1,75 @@ +class C { + static testIf(o) { + if (o?.a.b.c.d) { + return true; + } + return false; + } + static testConditional(o) { + return o?.a.b?.c.d ? true : false; + } + static testLoop(o) { + while (o?.a.b.c.d) { + for (; o?.a.b.c?.d; ) { + let i = 0; + do { + i++; + if (i === 2) { + return true; + } + } while (o?.a.b?.c.d); + } + } + return false; + } + static testNegate(o) { + return !!o?.a.b?.c.d; + } + static testIfDeep(o) { + if (o.obj?.a.b?.c.d) { + return true; + } + return false; + } + static testConditionalDeep(o) { + return o.obj?.a.b?.c.d ? true : false; + } + static testLoopDeep(o) { + while (o.obj?.a.b.c.d) { + for (; o.obj?.a.b.c?.d; ) { + let i = 0; + do { + i++; + if (i === 2) { + return true; + } + } while (o.obj?.a.b?.c.d); + } + } + return false; + } + static testNegateDeep(o) { + return !!o.obj?.a.b?.c.d; + } + + static testLogicalInIf(o) { + if (o?.a.b?.c.d && o?.a?.b.c.d) { + return true; + } + return false; + } + + static testLogicalInReturn(o) { + return o?.a.b?.c.d && o?.a?.b.c.d; + } + + static testNullishCoalescing(o) { + if (o?.a.b?.c.non_existent ?? o?.a.b?.c.d) { + return o?.a.b?.c.non_existent ?? o?.a.b?.c.d; + } + return o?.a.b?.c.non_existent ?? o; + } +} + +C.test(); +C.testNullish(); diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/options.json b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/options.json new file mode 100644 index 000000000000..f55bb7215867 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/options.json @@ -0,0 +1,3 @@ +{ + "plugins": ["proposal-optional-chaining", "proposal-nullish-coalescing-operator"] +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/output.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/output.js new file mode 100644 index 000000000000..4b41cfb287c7 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/cast-to-boolean/output.js @@ -0,0 +1,121 @@ +class C { + static testIf(o) { + if (o != null && o.a.b.c.d) { + return true; + } + + return false; + } + + static testConditional(o) { + var _o$a$b; + + return o != null && (_o$a$b = o.a.b) != null && _o$a$b.c.d ? true : false; + } + + static testLoop(o) { + while (o != null && o.a.b.c.d) { + for (; o != null && (_o$a$b$c = o.a.b.c) != null && _o$a$b$c.d;) { + var _o$a$b$c; + + let i = 0; + + do { + var _o$a$b2; + + i++; + + if (i === 2) { + return true; + } + } while (o != null && (_o$a$b2 = o.a.b) != null && _o$a$b2.c.d); + } + } + + return false; + } + + static testNegate(o) { + var _o$a$b3; + + return !!(o != null && (_o$a$b3 = o.a.b) != null && _o$a$b3.c.d); + } + + static testIfDeep(o) { + var _o$obj, _o$obj$a$b; + + if ((_o$obj = o.obj) != null && (_o$obj$a$b = _o$obj.a.b) != null && _o$obj$a$b.c.d) { + return true; + } + + return false; + } + + static testConditionalDeep(o) { + var _o$obj2, _o$obj2$a$b; + + return (_o$obj2 = o.obj) != null && (_o$obj2$a$b = _o$obj2.a.b) != null && _o$obj2$a$b.c.d ? true : false; + } + + static testLoopDeep(o) { + while ((_o$obj3 = o.obj) != null && _o$obj3.a.b.c.d) { + var _o$obj3; + + for (; (_o$obj4 = o.obj) != null && (_o$obj4$a$b$c = _o$obj4.a.b.c) != null && _o$obj4$a$b$c.d;) { + var _o$obj4, _o$obj4$a$b$c; + + let i = 0; + + do { + var _o$obj5, _o$obj5$a$b; + + i++; + + if (i === 2) { + return true; + } + } while ((_o$obj5 = o.obj) != null && (_o$obj5$a$b = _o$obj5.a.b) != null && _o$obj5$a$b.c.d); + } + } + + return false; + } + + static testNegateDeep(o) { + var _o$obj6, _o$obj6$a$b; + + return !!((_o$obj6 = o.obj) != null && (_o$obj6$a$b = _o$obj6.a.b) != null && _o$obj6$a$b.c.d); + } + + static testLogicalInIf(o) { + var _o$a$b4, _o$a; + + if (o != null && (_o$a$b4 = o.a.b) != null && _o$a$b4.c.d && o != null && (_o$a = o.a) != null && _o$a.b.c.d) { + return true; + } + + return false; + } + + static testLogicalInReturn(o) { + var _o$a$b5, _o$a2; + + return (o == null ? void 0 : (_o$a$b5 = o.a.b) == null ? void 0 : _o$a$b5.c.d) && (o == null ? void 0 : (_o$a2 = o.a) == null ? void 0 : _o$a2.b.c.d); + } + + static testNullishCoalescing(o) { + var _o$a$b$c$non_existent, _o$a$b6, _o$a$b7, _o$a$b$c$non_existent3, _o$a$b10; + + if ((_o$a$b$c$non_existent = o == null ? void 0 : (_o$a$b6 = o.a.b) == null ? void 0 : _o$a$b6.c.non_existent) != null ? _o$a$b$c$non_existent : o == null ? void 0 : (_o$a$b7 = o.a.b) == null ? void 0 : _o$a$b7.c.d) { + var _o$a$b$c$non_existent2, _o$a$b8, _o$a$b9; + + return (_o$a$b$c$non_existent2 = o == null ? void 0 : (_o$a$b8 = o.a.b) == null ? void 0 : _o$a$b8.c.non_existent) != null ? _o$a$b$c$non_existent2 : o == null ? void 0 : (_o$a$b9 = o.a.b) == null ? void 0 : _o$a$b9.c.d; + } + + return (_o$a$b$c$non_existent3 = o == null ? void 0 : (_o$a$b10 = o.a.b) == null ? void 0 : _o$a$b10.c.non_existent) != null ? _o$a$b$c$non_existent3 : o; + } + +} + +C.test(); +C.testNullish(); diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/in-function-params/input.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/in-function-params/input.js new file mode 100644 index 000000000000..882511b447f8 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/in-function-params/input.js @@ -0,0 +1,9 @@ +function f(a = x?.y) {} + +function g({ a, b = a?.c }) {} + +function h(a, { b = a.b?.c?.d.e }) {} + +function i(a, { b = (a.b?.c?.d).e }) {} + +function j(a, { b = a?.b?.c().d.e }) {} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/in-function-params/output.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/in-function-params/output.js new file mode 100644 index 000000000000..f5cda260cbfe --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/in-function-params/output.js @@ -0,0 +1,34 @@ +function f(a = (() => { + var _x; + + return (_x = x) == null ? void 0 : _x.y; +})()) {} + +function g({ + a, + b = a == null ? void 0 : a.c +}) {} + +function h(a, { + b = (() => { + var _a$b, _a$b$c; + + return (_a$b = a.b) == null ? void 0 : (_a$b$c = _a$b.c) == null ? void 0 : _a$b$c.d.e; + })() +}) {} + +function i(a, { + b = (() => { + var _a$b2, _a$b2$c; + + return (_a$b2 = a.b) == null ? void 0 : (_a$b2$c = _a$b2.c) == null ? void 0 : _a$b2$c.d; + })().e +}) {} + +function j(a, { + b = (() => { + var _a$b3; + + return a == null ? void 0 : (_a$b3 = a.b) == null ? void 0 : _a$b3.c().d.e; + })() +}) {} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/memoize/input.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/memoize/input.js new file mode 100644 index 000000000000..bbb26771f34e --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/memoize/input.js @@ -0,0 +1,29 @@ +function test(foo) { + foo?.bar; + + foo?.bar?.baz; + + foo?.(foo); + + foo?.bar() + + foo.get(bar)?.() + + foo.bar()?.() + foo[bar]()?.() + + foo.bar().baz?.() + foo[bar]().baz?.() + + foo.bar?.(foo.bar, false) + + foo?.bar?.(foo.bar, true) + + foo.bar?.baz(foo.bar, false) + + foo?.bar?.baz(foo.bar, true) + + foo.bar?.baz?.(foo.bar, false) + + foo?.bar?.baz?.(foo.bar, true) +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/memoize/output.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/memoize/output.js new file mode 100644 index 000000000000..3d48a529d4cf --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/memoize/output.js @@ -0,0 +1,19 @@ +function test(foo) { + var _foo$bar, _foo$get, _foo$bar2, _foo$bar3, _foo$bar$baz, _foo$bar4, _foo$bar$baz2, _foo$bar5, _foo$bar6, _foo$bar7, _foo$bar8, _foo$bar9, _foo$bar10, _foo$bar10$baz, _foo$bar11, _foo$bar11$baz; + + foo == null ? void 0 : foo.bar; + foo == null ? void 0 : (_foo$bar = foo.bar) == null ? void 0 : _foo$bar.baz; + foo == null ? void 0 : foo(foo); + foo == null ? void 0 : foo.bar(); + (_foo$get = foo.get(bar)) == null ? void 0 : _foo$get(); + (_foo$bar2 = foo.bar()) == null ? void 0 : _foo$bar2(); + (_foo$bar3 = foo[bar]()) == null ? void 0 : _foo$bar3(); + (_foo$bar$baz = (_foo$bar4 = foo.bar()).baz) == null ? void 0 : _foo$bar$baz.call(_foo$bar4); + (_foo$bar$baz2 = (_foo$bar5 = foo[bar]()).baz) == null ? void 0 : _foo$bar$baz2.call(_foo$bar5); + (_foo$bar6 = foo.bar) == null ? void 0 : _foo$bar6.call(foo, foo.bar, false); + foo == null ? void 0 : (_foo$bar7 = foo.bar) == null ? void 0 : _foo$bar7.call(foo, foo.bar, true); + (_foo$bar8 = foo.bar) == null ? void 0 : _foo$bar8.baz(foo.bar, false); + foo == null ? void 0 : (_foo$bar9 = foo.bar) == null ? void 0 : _foo$bar9.baz(foo.bar, true); + (_foo$bar10 = foo.bar) == null ? void 0 : (_foo$bar10$baz = _foo$bar10.baz) == null ? void 0 : _foo$bar10$baz.call(_foo$bar10, foo.bar, false); + foo == null ? void 0 : (_foo$bar11 = foo.bar) == null ? void 0 : (_foo$bar11$baz = _foo$bar11.baz) == null ? void 0 : _foo$bar11$baz.call(_foo$bar11, foo.bar, true); +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/optional-eval-call/input.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/optional-eval-call/input.js new file mode 100644 index 000000000000..731610528ac4 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/optional-eval-call/input.js @@ -0,0 +1,22 @@ +var foo; + +/* indirect eval calls */ +eval?.(foo); + +(eval)?.(foo); + +eval?.()(); + +eval?.().foo; + +/* direct eval calls */ + +eval()?.(); + +eval()?.foo; + +/* plain function calls */ + +foo.eval?.(foo); + +eval.foo?.(foo); diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/optional-eval-call/output.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/optional-eval-call/output.js new file mode 100644 index 000000000000..a6fd734cae72 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/optional-eval-call/output.js @@ -0,0 +1,17 @@ +var _eval, _eval2, _foo$eval, _eval$foo; + +var foo; +/* indirect eval calls */ + +eval == null ? void 0 : (0, eval)(foo); +eval == null ? void 0 : (0, eval)(foo); +eval == null ? void 0 : (0, eval)()(); +eval == null ? void 0 : (0, eval)().foo; +/* direct eval calls */ + +(_eval = eval()) == null ? void 0 : _eval(); +(_eval2 = eval()) == null ? void 0 : _eval2.foo; +/* plain function calls */ + +(_foo$eval = foo.eval) == null ? void 0 : _foo$eval.call(foo, foo); +(_eval$foo = eval.foo) == null ? void 0 : _eval$foo.call(eval, foo); diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/options.json b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/options.json new file mode 100644 index 000000000000..6f85efc683b3 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/options.json @@ -0,0 +1,6 @@ +{ + "plugins": ["proposal-optional-chaining"], + "assumptions": { + "noDocumentAll": true + } +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/parenthesized-expression-member-call/exec.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/parenthesized-expression-member-call/exec.js new file mode 100644 index 000000000000..2af236e11a8b --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/parenthesized-expression-member-call/exec.js @@ -0,0 +1,51 @@ +class Foo { + constructor() { + this.x = 1; + this.self = this; + } + m() { return this.x; }; + getSelf() { return this } + + test() { + const Foo = this; + const o = { Foo: Foo }; + const fn = function () { + return o; + }; + + expect((Foo?.["m"])()).toEqual(1); + expect((Foo?.["m"])().toString).toEqual(1..toString); + expect((Foo?.["m"])().toString()).toEqual('1'); + + expect(((Foo?.["m"]))()).toEqual(1); + expect(((Foo?.["m"]))().toString).toEqual(1..toString); + expect(((Foo?.["m"]))().toString()).toEqual('1'); + + expect((o?.Foo.m)()).toEqual(1); + expect((o?.Foo.m)().toString).toEqual(1..toString); + expect((o?.Foo.m)().toString()).toEqual('1'); + + expect((((o.Foo?.self.getSelf)())?.m)()).toEqual(1); + expect((((o.Foo.self?.getSelf)())?.m)()).toEqual(1); + + expect((((fn()?.Foo?.self.getSelf)())?.m)()).toEqual(1); + expect((((fn?.().Foo.self?.getSelf)())?.m)()).toEqual(1); + } + + testNull() { + const o = null; + + expect(() => { (o?.Foo.m)() }).toThrow(); + expect(() => { (o?.Foo.m)().toString }).toThrow(); + expect(() => { (o?.Foo.m)().toString() }).toThrow(); + + expect(() => { (((o.Foo?.self.getSelf)())?.m)() }).toThrow(); + expect(() => { (((o.Foo.self?.getSelf)())?.m)() }).toThrow(); + + expect(() => (((fn()?.Foo?.self.getSelf)())?.m)()).toThrow(); + expect(() => (((fn?.().Foo.self?.getSelf)())?.m)()).toThrow(); + } +} + +(new Foo).test(); +(new Foo).testNull(); diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/parenthesized-expression-member-call/options.json b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/parenthesized-expression-member-call/options.json new file mode 100644 index 000000000000..2931a52b5b3f --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/parenthesized-expression-member-call/options.json @@ -0,0 +1,5 @@ +{ + "parserOpts": { + "createParenthesizedExpressions": true + } +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/super-method-call/input.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/super-method-call/input.js new file mode 100644 index 000000000000..445c06ab259e --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/super-method-call/input.js @@ -0,0 +1,12 @@ +"use strict"; +class Base { + method() { + return 'Hello!'; + } +} + +class Derived extends Base { + method() { + return super.method?.() + } +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/super-method-call/output.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/super-method-call/output.js new file mode 100644 index 000000000000..a274b60b9e65 --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-noDocumentAll/super-method-call/output.js @@ -0,0 +1,17 @@ +"use strict"; + +class Base { + method() { + return 'Hello!'; + } + +} + +class Derived extends Base { + method() { + var _super$method; + + return (_super$method = super.method) == null ? void 0 : _super$method.call(this); + } + +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/function-call/input.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/function-call/input.js new file mode 100644 index 000000000000..51882eacf65d --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/function-call/input.js @@ -0,0 +1,19 @@ +foo?.(foo); + +foo?.bar() + +foo.bar?.(foo.bar, false) + +foo?.bar?.(foo.bar, true) + +foo?.().bar + +foo?.()?.bar + +foo.bar?.().baz + +foo.bar?.()?.baz + +foo?.bar?.().baz + +foo?.bar?.()?.baz diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/function-call/output.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/function-call/output.js new file mode 100644 index 000000000000..5b41f4a9fd6e --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/function-call/output.js @@ -0,0 +1,12 @@ +var _foo, _foo2, _foo3, _foo$bar, _foo4, _foo5, _foo5$bar; + +foo === null || foo === void 0 ? void 0 : foo(foo); +(_foo = foo) === null || _foo === void 0 ? void 0 : _foo.bar(); +foo.bar === null || foo.bar === void 0 ? void 0 : foo.bar(foo.bar, false); +(_foo2 = foo) === null || _foo2 === void 0 ? void 0 : _foo2.bar === null || _foo2.bar === void 0 ? void 0 : _foo2.bar(foo.bar, true); +foo === null || foo === void 0 ? void 0 : foo().bar; +foo === null || foo === void 0 ? void 0 : (_foo3 = foo()) === null || _foo3 === void 0 ? void 0 : _foo3.bar; +foo.bar === null || foo.bar === void 0 ? void 0 : foo.bar().baz; +foo.bar === null || foo.bar === void 0 ? void 0 : (_foo$bar = foo.bar()) === null || _foo$bar === void 0 ? void 0 : _foo$bar.baz; +(_foo4 = foo) === null || _foo4 === void 0 ? void 0 : _foo4.bar === null || _foo4.bar === void 0 ? void 0 : _foo4.bar().baz; +(_foo5 = foo) === null || _foo5 === void 0 ? void 0 : _foo5.bar === null || _foo5.bar === void 0 ? void 0 : (_foo5$bar = _foo5.bar()) === null || _foo5$bar === void 0 ? void 0 : _foo5$bar.baz; diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/memoize/input.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/memoize/input.js new file mode 100644 index 000000000000..bbb26771f34e --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/memoize/input.js @@ -0,0 +1,29 @@ +function test(foo) { + foo?.bar; + + foo?.bar?.baz; + + foo?.(foo); + + foo?.bar() + + foo.get(bar)?.() + + foo.bar()?.() + foo[bar]()?.() + + foo.bar().baz?.() + foo[bar]().baz?.() + + foo.bar?.(foo.bar, false) + + foo?.bar?.(foo.bar, true) + + foo.bar?.baz(foo.bar, false) + + foo?.bar?.baz(foo.bar, true) + + foo.bar?.baz?.(foo.bar, false) + + foo?.bar?.baz?.(foo.bar, true) +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/memoize/output.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/memoize/output.js new file mode 100644 index 000000000000..4ac4eb12be8c --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/memoize/output.js @@ -0,0 +1,19 @@ +function test(foo) { + var _foo$bar, _foo$get, _foo$bar2, _foo$bar3, _foo$bar$baz, _foo$bar4, _foo$bar$baz2, _foo$bar5, _foo$bar6, _foo$bar7, _foo$bar8, _foo$bar9; + + foo === null || foo === void 0 ? void 0 : foo.bar; + foo === null || foo === void 0 ? void 0 : (_foo$bar = foo.bar) === null || _foo$bar === void 0 ? void 0 : _foo$bar.baz; + foo === null || foo === void 0 ? void 0 : foo(foo); + foo === null || foo === void 0 ? void 0 : foo.bar(); + (_foo$get = foo.get(bar)) === null || _foo$get === void 0 ? void 0 : _foo$get(); + (_foo$bar2 = foo.bar()) === null || _foo$bar2 === void 0 ? void 0 : _foo$bar2(); + (_foo$bar3 = foo[bar]()) === null || _foo$bar3 === void 0 ? void 0 : _foo$bar3(); + (_foo$bar$baz = (_foo$bar4 = foo.bar()).baz) === null || _foo$bar$baz === void 0 ? void 0 : _foo$bar$baz.call(_foo$bar4); + (_foo$bar$baz2 = (_foo$bar5 = foo[bar]()).baz) === null || _foo$bar$baz2 === void 0 ? void 0 : _foo$bar$baz2.call(_foo$bar5); + foo.bar === null || foo.bar === void 0 ? void 0 : foo.bar(foo.bar, false); + foo === null || foo === void 0 ? void 0 : foo.bar === null || foo.bar === void 0 ? void 0 : foo.bar(foo.bar, true); + (_foo$bar6 = foo.bar) === null || _foo$bar6 === void 0 ? void 0 : _foo$bar6.baz(foo.bar, false); + foo === null || foo === void 0 ? void 0 : (_foo$bar7 = foo.bar) === null || _foo$bar7 === void 0 ? void 0 : _foo$bar7.baz(foo.bar, true); + (_foo$bar8 = foo.bar) === null || _foo$bar8 === void 0 ? void 0 : _foo$bar8.baz === null || _foo$bar8.baz === void 0 ? void 0 : _foo$bar8.baz(foo.bar, false); + foo === null || foo === void 0 ? void 0 : (_foo$bar9 = foo.bar) === null || _foo$bar9 === void 0 ? void 0 : _foo$bar9.baz === null || _foo$bar9.baz === void 0 ? void 0 : _foo$bar9.baz(foo.bar, true); +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/options.json b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/options.json new file mode 100644 index 000000000000..05b80d0efb8f --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/options.json @@ -0,0 +1,6 @@ +{ + "plugins": ["proposal-optional-chaining"], + "assumptions": { + "pureGetters": true + } +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/super-method-call/input.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/super-method-call/input.js new file mode 100644 index 000000000000..445c06ab259e --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/super-method-call/input.js @@ -0,0 +1,12 @@ +"use strict"; +class Base { + method() { + return 'Hello!'; + } +} + +class Derived extends Base { + method() { + return super.method?.() + } +} diff --git a/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/super-method-call/output.js b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/super-method-call/output.js new file mode 100644 index 000000000000..e51be18dde9a --- /dev/null +++ b/packages/babel-plugin-proposal-optional-chaining/test/fixtures/assumption-pureGetters/super-method-call/output.js @@ -0,0 +1,15 @@ +"use strict"; + +class Base { + method() { + return 'Hello!'; + } + +} + +class Derived extends Base { + method() { + return super.method === null || super.method === void 0 ? void 0 : super.method(); + } + +} diff --git a/packages/babel-plugin-proposal-private-methods/src/index.js b/packages/babel-plugin-proposal-private-methods/src/index.js index 0efbf93682a6..31652dfcfacb 100644 --- a/packages/babel-plugin-proposal-private-methods/src/index.js +++ b/packages/babel-plugin-proposal-private-methods/src/index.js @@ -12,6 +12,7 @@ export default declare((api, options) => { return createClassFeaturePlugin({ name: "proposal-private-methods", + api, feature: FEATURES.privateMethods, loose: options.loose, diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/basic/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/basic/exec.js new file mode 100644 index 000000000000..3cdb24863398 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/basic/exec.js @@ -0,0 +1,31 @@ +class Cl { + #privateField = "top secret string"; + + constructor() { + this.publicField = "not secret string"; + } + + get #privateFieldValue() { + return this.#privateField; + } + + set #privateFieldValue(newValue) { + this.#privateField = newValue; + } + + publicGetPrivateField() { + return this.#privateFieldValue; + } + + publicSetPrivateField(newValue) { + this.#privateFieldValue = newValue; + } +} + +const cl = new Cl(); + +expect(cl.publicGetPrivateField()).toEqual("top secret string"); + +cl.publicSetPrivateField("new secret string"); +expect(cl.publicGetPrivateField()).toEqual("new secret string"); + diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/basic/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/basic/input.js new file mode 100644 index 000000000000..53e77128c0bd --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/basic/input.js @@ -0,0 +1,23 @@ +class Cl { + #privateField = "top secret string"; + + constructor() { + this.publicField = "not secret string"; + } + + get #privateFieldValue() { + return this.#privateField; + } + + set #privateFieldValue(newValue) { + this.#privateField = newValue; + } + + publicGetPrivateField() { + return this.#privateFieldValue; + } + + publicSetPrivateField(newValue) { + this.#privateFieldValue = newValue; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/basic/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/basic/output.js new file mode 100644 index 000000000000..e450d62cb5e8 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/basic/output.js @@ -0,0 +1,34 @@ +var _privateField = babelHelpers.classPrivateFieldLooseKey("privateField"); + +var _privateFieldValue = babelHelpers.classPrivateFieldLooseKey("privateFieldValue"); + +class Cl { + constructor() { + Object.defineProperty(this, _privateFieldValue, { + get: _get_privateFieldValue, + set: _set_privateFieldValue + }); + Object.defineProperty(this, _privateField, { + writable: true, + value: "top secret string" + }); + this.publicField = "not secret string"; + } + + publicGetPrivateField() { + return babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]; + } + + publicSetPrivateField(newValue) { + babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = newValue; + } + +} + +var _get_privateFieldValue = function () { + return babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField]; +}; + +var _set_privateFieldValue = function (newValue) { + babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField] = newValue; +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/get-only-setter/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/get-only-setter/exec.js new file mode 100644 index 000000000000..92e8197700c0 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/get-only-setter/exec.js @@ -0,0 +1,13 @@ +class Cl { + #privateField = 0; + + set #privateFieldValue(newValue) { + this.#privateField = newValue; + } + + constructor() { + expect(this.#privateFieldValue).toBeUndefined(); + } +} + +const cl = new Cl(); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/get-only-setter/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/get-only-setter/input.js new file mode 100644 index 000000000000..d676919b85eb --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/get-only-setter/input.js @@ -0,0 +1,11 @@ +class Cl { + #privateField = 0; + + set #privateFieldValue(newValue) { + this.#privateField = newValue; + } + + constructor() { + this.publicField = this.#privateFieldValue; + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/get-only-setter/output.js new file mode 100644 index 000000000000..b68476be9665 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/get-only-setter/output.js @@ -0,0 +1,22 @@ +var _privateField = babelHelpers.classPrivateFieldLooseKey("privateField"); + +var _privateFieldValue = babelHelpers.classPrivateFieldLooseKey("privateFieldValue"); + +class Cl { + constructor() { + Object.defineProperty(this, _privateFieldValue, { + get: void 0, + set: _set_privateFieldValue + }); + Object.defineProperty(this, _privateField, { + writable: true, + value: 0 + }); + this.publicField = babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]; + } + +} + +var _set_privateFieldValue = function (newValue) { + babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField] = newValue; +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/helper/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/helper/exec.js new file mode 100644 index 000000000000..59d4b47896ae --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/helper/exec.js @@ -0,0 +1,11 @@ +let foo; +class Cl { + set #foo(v) { return 1 } + test() { + foo = this.#foo = 2; + } +} + +new Cl().test(); + +expect(foo).toBe(2); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/options.json b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/options.json new file mode 100644 index 000000000000..8db8526496b9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + ["external-helpers",{ "helperVersion": "7.1000.0" }], + "proposal-private-methods", + "proposal-class-properties" + ], + "assumptions": { + "privateFieldsAsProperties": true + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/set-only-getter/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/set-only-getter/exec.js new file mode 100644 index 000000000000..64dd9738fd4f --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/set-only-getter/exec.js @@ -0,0 +1,13 @@ +class Cl { + #privateField = 0; + + get #privateFieldValue() { + return this.#privateField; + } + + constructor() { + expect(() => this.#privateFieldValue = 1).toThrow(TypeError); + } +} + +const cl = new Cl(); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/set-only-getter/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/set-only-getter/input.js new file mode 100644 index 000000000000..a3385ef16034 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/set-only-getter/input.js @@ -0,0 +1,11 @@ +class Cl { + #privateField = 0; + + get #privateFieldValue() { + return this.#privateField; + } + + constructor() { + this.#privateFieldValue = 1; + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/set-only-getter/output.js new file mode 100644 index 000000000000..3ae50780168c --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/set-only-getter/output.js @@ -0,0 +1,22 @@ +var _privateField = babelHelpers.classPrivateFieldLooseKey("privateField"); + +var _privateFieldValue = babelHelpers.classPrivateFieldLooseKey("privateFieldValue"); + +class Cl { + constructor() { + Object.defineProperty(this, _privateFieldValue, { + get: _get_privateFieldValue, + set: void 0 + }); + Object.defineProperty(this, _privateField, { + writable: true, + value: 0 + }); + babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = 1; + } + +} + +var _get_privateFieldValue = function () { + return babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField]; +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/updates/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/updates/exec.js new file mode 100644 index 000000000000..2e0c58ef2785 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/updates/exec.js @@ -0,0 +1,50 @@ +class Cl { + #privateField = "top secret string"; + + constructor() { + this.publicField = "not secret string"; + } + + get #privateFieldValue() { + return this.#privateField; + } + + set #privateFieldValue(newValue) { + this.#privateField = newValue; + } + + publicGetPrivateField() { + return this.#privateFieldValue; + } + + publicSetPrivateField(newValue) { + this.#privateFieldValue = newValue; + } + + get publicFieldValue() { + return this.publicField; + } + + set publicFieldValue(newValue) { + this.publicField = newValue; + } + + testUpdates() { + this.#privateField = 0; + this.publicField = 0; + this.#privateFieldValue = this.#privateFieldValue++; + this.publicFieldValue = this.publicFieldValue++; + expect(this.#privateField).toEqual(this.publicField); + + ++this.#privateFieldValue; + ++this.publicFieldValue; + expect(this.#privateField).toEqual(this.publicField); + + this.#privateFieldValue += 1; + this.publicFieldValue += 1; + expect(this.#privateField).toEqual(this.publicField); + } +} + +const cl = new Cl(); +cl.testUpdates(); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/updates/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/updates/input.js new file mode 100644 index 000000000000..587f09e0aa93 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/updates/input.js @@ -0,0 +1,47 @@ +class Cl { + #privateField = "top secret string"; + + constructor() { + this.publicField = "not secret string"; + } + + get #privateFieldValue() { + return this.#privateField; + } + + set #privateFieldValue(newValue) { + this.#privateField = newValue; + } + + publicGetPrivateField() { + return this.#privateFieldValue; + } + + publicSetPrivateField(newValue) { + this.#privateFieldValue = newValue; + } + + get publicFieldValue() { + return this.publicField; + } + + set publicFieldValue(newValue) { + this.publicField = newValue; + } + + testUpdates() { + this.#privateField = 0; + this.publicField = 0; + this.#privateFieldValue = this.#privateFieldValue++; + this.publicFieldValue = this.publicFieldValue++; + + ++this.#privateFieldValue; + ++this.publicFieldValue; + + this.#privateFieldValue += 1; + this.publicFieldValue += 1; + + this.#privateFieldValue = -(this.#privateFieldValue ** this.#privateFieldValue); + this.publicFieldValue = -(this.publicFieldValue ** this.publicFieldValue); + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/updates/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/updates/output.js new file mode 100644 index 000000000000..b9fb372f9ba5 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/accessors-privateFieldsAsProperties/updates/output.js @@ -0,0 +1,55 @@ +var _privateField = babelHelpers.classPrivateFieldLooseKey("privateField"); + +var _privateFieldValue = babelHelpers.classPrivateFieldLooseKey("privateFieldValue"); + +class Cl { + constructor() { + Object.defineProperty(this, _privateFieldValue, { + get: _get_privateFieldValue, + set: _set_privateFieldValue + }); + Object.defineProperty(this, _privateField, { + writable: true, + value: "top secret string" + }); + this.publicField = "not secret string"; + } + + publicGetPrivateField() { + return babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]; + } + + publicSetPrivateField(newValue) { + babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = newValue; + } + + get publicFieldValue() { + return this.publicField; + } + + set publicFieldValue(newValue) { + this.publicField = newValue; + } + + testUpdates() { + babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField] = 0; + this.publicField = 0; + babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]++; + this.publicFieldValue = this.publicFieldValue++; + ++babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]; + ++this.publicFieldValue; + babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] += 1; + this.publicFieldValue += 1; + babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] = -(babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue] ** babelHelpers.classPrivateFieldLooseBase(this, _privateFieldValue)[_privateFieldValue]); + this.publicFieldValue = -(this.publicFieldValue ** this.publicFieldValue); + } + +} + +var _get_privateFieldValue = function () { + return babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField]; +}; + +var _set_privateFieldValue = function (newValue) { + babelHelpers.classPrivateFieldLooseBase(this, _privateField)[_privateField] = newValue; +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/options.json b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/options.json new file mode 100644 index 000000000000..4ada272a1b6b --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/options.json @@ -0,0 +1,17 @@ +{ + "plugins": [ + [ + "external-helpers", + { + "helperVersion": "7.1000.0" + } + ], + "proposal-private-methods", + "proposal-class-properties", + "transform-block-scoping", + "syntax-class-properties" + ], + "assumptions": { + "constantSuper": true + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/input.js new file mode 100644 index 000000000000..d85e01133ac1 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/input.js @@ -0,0 +1,19 @@ +class Base { + superMethod() { + return 'good'; + } +} + +class Sub extends Base { + superMethod() { + return 'bad'; + } + + #privateMethod() { + return super.superMethod(); + } + + publicMethod() { + return this.#privateMethod(); + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/output.js new file mode 100644 index 000000000000..6c26d54af7c3 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/assumption-constantSuper/private-method-super/output.js @@ -0,0 +1,29 @@ +class Base { + superMethod() { + return 'good'; + } + +} + +var _privateMethod = new WeakSet(); + +class Sub extends Base { + constructor(...args) { + super(...args); + + _privateMethod.add(this); + } + + superMethod() { + return 'bad'; + } + + publicMethod() { + return babelHelpers.classPrivateMethodGet(this, _privateMethod, _privateMethod2).call(this); + } + +} + +var _privateMethod2 = function _privateMethod2() { + return Base.prototype.superMethod.call(this); +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/assignment/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/assignment/exec.js new file mode 100644 index 000000000000..4c1324aeeb62 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/assignment/exec.js @@ -0,0 +1,11 @@ +class Foo { + constructor() { + this.publicField = this.#privateMethod(); + } + + #privateMethod() { + return 42; + } + } + + expect((new Foo).publicField).toEqual(42); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/assignment/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/assignment/input.js new file mode 100644 index 000000000000..e55a8afdd3ad --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/assignment/input.js @@ -0,0 +1,9 @@ +class Foo { + constructor() { + this.publicField = this.#privateMethod(); + } + + #privateMethod() { + return 42; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/assignment/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/assignment/output.js new file mode 100644 index 000000000000..e85cf49ca0e1 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/assignment/output.js @@ -0,0 +1,15 @@ +var _privateMethod = babelHelpers.classPrivateFieldLooseKey("privateMethod"); + +class Foo { + constructor() { + Object.defineProperty(this, _privateMethod, { + value: _privateMethod2 + }); + this.publicField = babelHelpers.classPrivateFieldLooseBase(this, _privateMethod)[_privateMethod](); + } + +} + +var _privateMethod2 = function _privateMethod2() { + return 42; +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/exec.js new file mode 100644 index 000000000000..168eb945dd14 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/exec.js @@ -0,0 +1,13 @@ +class Cl { + async #foo() { + return 2; + } + + test() { + return this.#foo(); + } +} + +return new Cl().test().then(val => { + expect(val).toBe(2); +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/input.js new file mode 100644 index 000000000000..aed36e25613f --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/input.js @@ -0,0 +1,9 @@ +class Cl { + async #foo() { + return 2; + } + + test() { + return this.#foo(); + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/options.json b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/options.json new file mode 100644 index 000000000000..95ab365853e8 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/options.json @@ -0,0 +1,14 @@ +{ + "minNodeVersion": "8.0.0", + "plugins": [ + ["external-helpers",{ "helperVersion": "7.1000.0" }], + "proposal-private-methods", + "proposal-class-properties" + ], + "assumptions": { + "privateFieldsAsProperties": true + }, + "parserOpts": { + "allowReturnOutsideFunction": true + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/output.js new file mode 100644 index 000000000000..2b437a303f1a --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/async/output.js @@ -0,0 +1,18 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Cl { + constructor() { + Object.defineProperty(this, _foo, { + value: _foo2 + }); + } + + test() { + return babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo](); + } + +} + +var _foo2 = async function _foo2() { + return 2; +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/before-fields/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/before-fields/exec.js new file mode 100644 index 000000000000..26caf2d02c1f --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/before-fields/exec.js @@ -0,0 +1,16 @@ +class Cl { + prop = this.#method(1); + + #priv = this.#method(2); + + #method(x) { + return x; + } + + getPriv() { + return this.#priv; + } +} + +expect(new Cl().prop).toBe(1); +expect(new Cl().getPriv()).toBe(2); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/before-fields/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/before-fields/input.js new file mode 100644 index 000000000000..2fcb7857468f --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/before-fields/input.js @@ -0,0 +1,13 @@ +class Cl { + prop = this.#method(1); + + #priv = this.#method(2); + + #method(x) { + return x; + } + + getPriv() { + return this.#priv; + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/before-fields/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/before-fields/output.js new file mode 100644 index 000000000000..2618032e6669 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/before-fields/output.js @@ -0,0 +1,25 @@ +var _priv = babelHelpers.classPrivateFieldLooseKey("priv"); + +var _method = babelHelpers.classPrivateFieldLooseKey("method"); + +class Cl { + constructor() { + Object.defineProperty(this, _method, { + value: _method2 + }); + babelHelpers.defineProperty(this, "prop", babelHelpers.classPrivateFieldLooseBase(this, _method)[_method](1)); + Object.defineProperty(this, _priv, { + writable: true, + value: babelHelpers.classPrivateFieldLooseBase(this, _method)[_method](2) + }); + } + + getPriv() { + return babelHelpers.classPrivateFieldLooseBase(this, _priv)[_priv]; + } + +} + +var _method2 = function _method2(x) { + return x; +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/context/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/context/exec.js new file mode 100644 index 000000000000..6c18bf53c193 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/context/exec.js @@ -0,0 +1,41 @@ +class Foo { + constructor(status) { + this.status = status; + expect(() => this.#getStatus = null).toThrow(TypeError); + } + + #getStatus() { + return this.status; + } + + getCurrentStatus() { + return this.#getStatus(); + } + + setCurrentStatus(newStatus) { + this.status = newStatus; + } + + getFakeStatus(fakeStatus) { + const getStatus = this.#getStatus; + return function () { + return getStatus.call({ status: fakeStatus }); + }; + } + + getFakeStatusFunc() { + return { + status: 'fake-status', + getFakeStatus: this.#getStatus, + }; + } + } + + const f = new Foo('inactive'); + expect(f.getCurrentStatus()).toBe('inactive'); + + f.setCurrentStatus('new-status'); + expect(f.getCurrentStatus()).toBe('new-status'); + + expect(f.getFakeStatus('fake')()).toBe('fake'); + expect(f.getFakeStatusFunc().getFakeStatus()).toBe('fake-status'); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/context/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/context/input.js new file mode 100644 index 000000000000..67a8ab68a682 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/context/input.js @@ -0,0 +1,31 @@ +class Foo { + constructor(status) { + this.status = status; + } + + #getStatus() { + return this.status; + } + + getCurrentStatus() { + return this.#getStatus(); + } + + setCurrentStatus(newStatus) { + this.status = newStatus; + } + + getFakeStatus(fakeStatus) { + const fakeGetStatus = this.#getStatus; + return function() { + return fakeGetStatus.call({ status: fakeStatus }); + }; + } + + getFakeStatusFunc() { + return { + status: 'fake-status', + getFakeStatus: this.#getStatus, + }; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/context/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/context/output.js new file mode 100644 index 000000000000..b1c396755f7e --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/context/output.js @@ -0,0 +1,40 @@ +var _getStatus = babelHelpers.classPrivateFieldLooseKey("getStatus"); + +class Foo { + constructor(status) { + Object.defineProperty(this, _getStatus, { + value: _getStatus2 + }); + this.status = status; + } + + getCurrentStatus() { + return babelHelpers.classPrivateFieldLooseBase(this, _getStatus)[_getStatus](); + } + + setCurrentStatus(newStatus) { + this.status = newStatus; + } + + getFakeStatus(fakeStatus) { + const fakeGetStatus = babelHelpers.classPrivateFieldLooseBase(this, _getStatus)[_getStatus]; + + return function () { + return fakeGetStatus.call({ + status: fakeStatus + }); + }; + } + + getFakeStatusFunc() { + return { + status: 'fake-status', + getFakeStatus: babelHelpers.classPrivateFieldLooseBase(this, _getStatus)[_getStatus] + }; + } + +} + +var _getStatus2 = function _getStatus2() { + return this.status; +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/exfiltrated/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/exfiltrated/exec.js new file mode 100644 index 000000000000..659a3e891085 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/exfiltrated/exec.js @@ -0,0 +1,15 @@ +let exfiltrated; +class Foo { + #privateMethod() {} + + constructor() { + if (exfiltrated === undefined) { + exfiltrated = this.#privateMethod; + } + expect(exfiltrated).toStrictEqual(this.#privateMethod); + } +} + +new Foo(); +// check for private method function object equality +new Foo(); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/exfiltrated/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/exfiltrated/input.js new file mode 100644 index 000000000000..91bf8510d814 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/exfiltrated/input.js @@ -0,0 +1,10 @@ +let exfiltrated; +class Foo { + #privateMethod() {} + + constructor() { + if (exfiltrated === undefined) { + exfiltrated = this.#privateMethod; + } + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/exfiltrated/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/exfiltrated/output.js new file mode 100644 index 000000000000..100562baf534 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/exfiltrated/output.js @@ -0,0 +1,18 @@ +let exfiltrated; + +var _privateMethod = babelHelpers.classPrivateFieldLooseKey("privateMethod"); + +class Foo { + constructor() { + Object.defineProperty(this, _privateMethod, { + value: _privateMethod2 + }); + + if (exfiltrated === undefined) { + exfiltrated = babelHelpers.classPrivateFieldLooseBase(this, _privateMethod)[_privateMethod]; + } + } + +} + +var _privateMethod2 = function _privateMethod2() {}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/generator/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/generator/exec.js new file mode 100644 index 000000000000..472eadeabff6 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/generator/exec.js @@ -0,0 +1,14 @@ +class Cl { + *#foo() { + yield 2; + return 3; + } + + test() { + return this.#foo(); + } +} + +const val = new Cl().test(); +expect(val.next()).toEqual({ value: 2, done: false }); +expect(val.next()).toEqual({ value: 3, done: true }); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/generator/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/generator/input.js new file mode 100644 index 000000000000..39aace6dc402 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/generator/input.js @@ -0,0 +1,10 @@ +class Cl { + *#foo() { + yield 2; + return 3; + } + + test() { + return this.#foo(); + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/generator/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/generator/output.js new file mode 100644 index 000000000000..ead1fffcb593 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/generator/output.js @@ -0,0 +1,19 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Cl { + constructor() { + Object.defineProperty(this, _foo, { + value: _foo2 + }); + } + + test() { + return babelHelpers.classPrivateFieldLooseBase(this, _foo)[_foo](); + } + +} + +var _foo2 = function* _foo2() { + yield 2; + return 3; +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/options.json b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/options.json new file mode 100644 index 000000000000..8db8526496b9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + ["external-helpers",{ "helperVersion": "7.1000.0" }], + "proposal-private-methods", + "proposal-class-properties" + ], + "assumptions": { + "privateFieldsAsProperties": true + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/super/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/super/exec.js new file mode 100644 index 000000000000..63d8fe8cdfe3 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/super/exec.js @@ -0,0 +1,21 @@ +class Base { + superMethod() { + return 'good'; + } +} + +class Sub extends Base { + superMethod() { + return 'bad'; + } + + #privateMethod() { + return super.superMethod(); + } + + publicMethod() { + return this.#privateMethod(); + } +} + +expect((new Sub()).publicMethod()).toEqual('good'); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/super/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/super/input.js new file mode 100644 index 000000000000..d85e01133ac1 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/super/input.js @@ -0,0 +1,19 @@ +class Base { + superMethod() { + return 'good'; + } +} + +class Sub extends Base { + superMethod() { + return 'bad'; + } + + #privateMethod() { + return super.superMethod(); + } + + publicMethod() { + return this.#privateMethod(); + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/super/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/super/output.js new file mode 100644 index 000000000000..1a0d87d98e0c --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-method-privateFieldsAsProperties/super/output.js @@ -0,0 +1,30 @@ +class Base { + superMethod() { + return 'good'; + } + +} + +var _privateMethod = babelHelpers.classPrivateFieldLooseKey("privateMethod"); + +class Sub extends Base { + constructor(...args) { + super(...args); + Object.defineProperty(this, _privateMethod, { + value: _privateMethod2 + }); + } + + superMethod() { + return 'bad'; + } + + publicMethod() { + return babelHelpers.classPrivateFieldLooseBase(this, _privateMethod)[_privateMethod](); + } + +} + +var _privateMethod2 = function _privateMethod2() { + return babelHelpers.get(babelHelpers.getPrototypeOf(Sub.prototype), "superMethod", this).call(this); +}; diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/async/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/async/input.js new file mode 100644 index 000000000000..99125b6f24c4 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/async/input.js @@ -0,0 +1,13 @@ +class Cl { + static async #privateStaticMethod() { + return 2; + } + + test() { + return Cl.#privateStaticMethod(); + } +} + +return new Cl().test().then(val => { + expect(val).toBe(2); +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/async/options.json b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/async/options.json new file mode 100644 index 000000000000..95ab365853e8 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/async/options.json @@ -0,0 +1,14 @@ +{ + "minNodeVersion": "8.0.0", + "plugins": [ + ["external-helpers",{ "helperVersion": "7.1000.0" }], + "proposal-private-methods", + "proposal-class-properties" + ], + "assumptions": { + "privateFieldsAsProperties": true + }, + "parserOpts": { + "allowReturnOutsideFunction": true + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/async/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/async/output.js new file mode 100644 index 000000000000..9d5595eaafa9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/async/output.js @@ -0,0 +1,19 @@ +var _privateStaticMethod = babelHelpers.classPrivateFieldLooseKey("privateStaticMethod"); + +class Cl { + test() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod](); + } + +} + +var _privateStaticMethod2 = async function _privateStaticMethod2() { + return 2; +}; + +Object.defineProperty(Cl, _privateStaticMethod, { + value: _privateStaticMethod2 +}); +return new Cl().test().then(val => { + expect(val).toBe(2); +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/basic/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/basic/exec.js new file mode 100644 index 000000000000..d5577057caa9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/basic/exec.js @@ -0,0 +1,33 @@ +const privateStaticValue = 1017; + +class Cl { + static staticMethod2() { + return Cl.#privateStaticMethod(); + } + + static #privateStaticMethod() { + return privateStaticValue; + } + + static staticMethod() { + return Cl.#privateStaticMethod(); + } + + static privateStaticMethod() { + return Cl.#privateStaticMethod(); + } + + publicMethod() { + return Cl.#privateStaticMethod(); + } + + constructor() { + this.instanceField = Cl.#privateStaticMethod(); + } +} + +expect((new Cl).publicMethod()).toEqual(privateStaticValue); +// expect((new Cl).instanceField).toEqual(privateStaticValue); +// expect(Cl.privateStaticMethod()).toEqual(privateStaticValue); +// expect(Cl.staticMethod()).toEqual(privateStaticValue); +// expect(Cl.staticMethod2()).toEqual(privateStaticValue); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/basic/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/basic/input.js new file mode 100644 index 000000000000..ad0ee3d44814 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/basic/input.js @@ -0,0 +1,25 @@ +class Cl { + static staticMethod2() { + return Cl.#privateStaticMethod(); + } + + static #privateStaticMethod() { + return 1017; + } + + static staticMethod() { + return Cl.#privateStaticMethod(); + } + + static privateStaticMethod() { + return Cl.#privateStaticMethod(); + } + + publicMethod() { + return Cl.#privateStaticMethod(); + } + + constructor() { + this.instanceField = Cl.#privateStaticMethod(); + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/basic/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/basic/output.js new file mode 100644 index 000000000000..c62177365e9a --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/basic/output.js @@ -0,0 +1,32 @@ +var _privateStaticMethod = babelHelpers.classPrivateFieldLooseKey("privateStaticMethod"); + +class Cl { + static staticMethod2() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod](); + } + + static staticMethod() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod](); + } + + static privateStaticMethod() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod](); + } + + publicMethod() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod](); + } + + constructor() { + this.instanceField = babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod](); + } + +} + +var _privateStaticMethod2 = function _privateStaticMethod2() { + return 1017; +}; + +Object.defineProperty(Cl, _privateStaticMethod, { + value: _privateStaticMethod2 +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/class-check/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/class-check/exec.js new file mode 100644 index 000000000000..940b62801e26 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/class-check/exec.js @@ -0,0 +1,12 @@ +class Cl { + static #privateStaticMethod() { + return 1017; + } + + publicMethod(checked) { + return checked.#privateStaticMethod(); + } +} + +const cl = new Cl(); +expect(cl.publicMethod(Cl)).toBe(1017); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/class-check/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/class-check/input.js new file mode 100644 index 000000000000..fd8c6c331e4e --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/class-check/input.js @@ -0,0 +1,7 @@ +class Cl { + static #privateStaticMethod() { } + + publicMethod(checked) { + return checked.#privateStaticMethod(); + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/class-check/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/class-check/output.js new file mode 100644 index 000000000000..353da8ad4fac --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/class-check/output.js @@ -0,0 +1,14 @@ +var _privateStaticMethod = babelHelpers.classPrivateFieldLooseKey("privateStaticMethod"); + +class Cl { + publicMethod(checked) { + return babelHelpers.classPrivateFieldLooseBase(checked, _privateStaticMethod)[_privateStaticMethod](); + } + +} + +var _privateStaticMethod2 = function _privateStaticMethod2() {}; + +Object.defineProperty(Cl, _privateStaticMethod, { + value: _privateStaticMethod2 +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/exfiltrated/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/exfiltrated/exec.js new file mode 100644 index 000000000000..14a7b5edd830 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/exfiltrated/exec.js @@ -0,0 +1,20 @@ +let exfiltrated; + +class Cl { + static #privateStaticMethod() { + return 1017; + } + + constructor() { + if (exfiltrated === undefined) { + exfiltrated = Cl.#privateStaticMethod; + } + expect(exfiltrated).toStrictEqual(Cl.#privateStaticMethod); + } +} + +new Cl(); +// check for private method function object equality +new Cl(); + +expect(exfiltrated()).toEqual(1017); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/exfiltrated/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/exfiltrated/input.js new file mode 100644 index 000000000000..fdc78e57981a --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/exfiltrated/input.js @@ -0,0 +1,13 @@ +let exfiltrated; + +class Cl { + static #privateStaticMethod() { + return 1017; + } + + constructor() { + if (exfiltrated === undefined) { + exfiltrated = Cl.#privateStaticMethod; + } + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/exfiltrated/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/exfiltrated/output.js new file mode 100644 index 000000000000..c6a5a2dc8000 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/exfiltrated/output.js @@ -0,0 +1,20 @@ +let exfiltrated; + +var _privateStaticMethod = babelHelpers.classPrivateFieldLooseKey("privateStaticMethod"); + +class Cl { + constructor() { + if (exfiltrated === undefined) { + exfiltrated = babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod]; + } + } + +} + +var _privateStaticMethod2 = function _privateStaticMethod2() { + return 1017; +}; + +Object.defineProperty(Cl, _privateStaticMethod, { + value: _privateStaticMethod2 +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/generator/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/generator/exec.js new file mode 100644 index 000000000000..97a6a708fc63 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/generator/exec.js @@ -0,0 +1,14 @@ +class Cl { + static *#foo() { + yield 2; + return 3; + } + + test() { + return Cl.#foo(); + } +} + +const val = new Cl().test(); +expect(val.next()).toEqual({ value: 2, done: false }); +expect(val.next()).toEqual({ value: 3, done: true }); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/generator/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/generator/input.js new file mode 100644 index 000000000000..2b8727d64cfa --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/generator/input.js @@ -0,0 +1,10 @@ +class Cl { + static *#foo() { + yield 2; + return 3; + } + + test() { + return Cl.#foo(); + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/generator/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/generator/output.js new file mode 100644 index 000000000000..464971ea7944 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/generator/output.js @@ -0,0 +1,17 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Cl { + test() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _foo)[_foo](); + } + +} + +var _foo2 = function* _foo2() { + yield 2; + return 3; +}; + +Object.defineProperty(Cl, _foo, { + value: _foo2 +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/options.json b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/options.json new file mode 100644 index 000000000000..8db8526496b9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + ["external-helpers",{ "helperVersion": "7.1000.0" }], + "proposal-private-methods", + "proposal-class-properties" + ], + "assumptions": { + "privateFieldsAsProperties": true + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/reassignment/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/reassignment/exec.js new file mode 100644 index 000000000000..d55af8ba71d7 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/reassignment/exec.js @@ -0,0 +1,9 @@ +class Cl { + static #privateStaticMethod() { } + + constructor() { + expect(() => Cl.#privateStaticMethod = null).toThrow(TypeError); + } +} + +new Cl(); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/reassignment/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/reassignment/input.js new file mode 100644 index 000000000000..865ddea4ccf1 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/reassignment/input.js @@ -0,0 +1,9 @@ +class Cl { + static #privateStaticMethod() { } + + constructor() { + Cl.#privateStaticMethod = null; + } +} + +new Cl(); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/reassignment/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/reassignment/output.js new file mode 100644 index 000000000000..5b3fae07d026 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/reassignment/output.js @@ -0,0 +1,15 @@ +var _privateStaticMethod = babelHelpers.classPrivateFieldLooseKey("privateStaticMethod"); + +class Cl { + constructor() { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticMethod)[_privateStaticMethod] = null; + } + +} + +var _privateStaticMethod2 = function _privateStaticMethod2() {}; + +Object.defineProperty(Cl, _privateStaticMethod, { + value: _privateStaticMethod2 +}); +new Cl(); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/scopable/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/scopable/exec.js new file mode 100644 index 000000000000..f94e5c495f9a --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/scopable/exec.js @@ -0,0 +1,17 @@ +class Cl { + static #privateMethodA() { + const i = 40; + return i; + } + + static #privateMethodB() { + const i = 2; + return i; + } + + publicMethod() { + return Cl.#privateMethodA() + Cl.#privateMethodB(); + } +} + +expect((new Cl).publicMethod()).toEqual(42); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/super/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/super/exec.js new file mode 100644 index 000000000000..1d6f0c63559a --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/super/exec.js @@ -0,0 +1,21 @@ +class Base { + static basePublicStaticMethod() { + return 'good'; + } +} + +class Sub extends Base { + static basePublicStaticMethod() { + return 'bad'; + } + + static #subStaticPrivateMethod() { + return super.basePublicStaticMethod(); + } + + static check() { + return Sub.#subStaticPrivateMethod(); + } +} + +expect(Sub.check()).toEqual('good'); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/super/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/super/input.js new file mode 100644 index 000000000000..e5fb0ecd5eec --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/super/input.js @@ -0,0 +1,19 @@ +class Base { + static basePublicStaticMethod() { + return 'good'; + } +} + +class Sub extends Base { + static basePublicStaticMethod() { + return 'bad'; + } + + static #subStaticPrivateMethod() { + return super.basePublicStaticMethod(); + } + + static check() { + Sub.#subStaticPrivateMethod(); + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/super/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/super/output.js new file mode 100644 index 000000000000..ae589469caf6 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/super/output.js @@ -0,0 +1,27 @@ +class Base { + static basePublicStaticMethod() { + return 'good'; + } + +} + +var _subStaticPrivateMethod = babelHelpers.classPrivateFieldLooseKey("subStaticPrivateMethod"); + +class Sub extends Base { + static basePublicStaticMethod() { + return 'bad'; + } + + static check() { + babelHelpers.classPrivateFieldLooseBase(Sub, _subStaticPrivateMethod)[_subStaticPrivateMethod](); + } + +} + +var _subStaticPrivateMethod2 = function _subStaticPrivateMethod2() { + return babelHelpers.get(babelHelpers.getPrototypeOf(Sub), "basePublicStaticMethod", this).call(this); +}; + +Object.defineProperty(Sub, _subStaticPrivateMethod, { + value: _subStaticPrivateMethod2 +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/this/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/this/exec.js new file mode 100644 index 000000000000..3262c36845be --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/this/exec.js @@ -0,0 +1,18 @@ +class A { + static get a() { return 1 } +} + +class B extends A { + static get b() { return 2 } + + static #getA() { return super.a } + static #getB() { return this.b } + + static extract() { + return [this.#getA, this.#getB]; + } +} + +const [getA, getB] = B.extract(); +expect(getA.call({ a: 3 })).toBe(1); +expect(getB.call({ b: 4 })).toBe(4); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/this/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/this/input.js new file mode 100644 index 000000000000..3c8639776d62 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/this/input.js @@ -0,0 +1,16 @@ +class A { + static get a() { return 1 } +} + +class B extends A { + static get b() { return 2 } + + static #getA() { return super.a } + static #getB() { return this.b } + + static extract() { + return [this.#getA, this.#getB]; + } +} + +const [getA, getB] = B.extract(); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/this/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/this/output.js new file mode 100644 index 000000000000..0d39c5bf1282 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/private-static-method-privateFieldsAsProperties/this/output.js @@ -0,0 +1,37 @@ +class A { + static get a() { + return 1; + } + +} + +var _getA = babelHelpers.classPrivateFieldLooseKey("getA"); + +var _getB = babelHelpers.classPrivateFieldLooseKey("getB"); + +class B extends A { + static get b() { + return 2; + } + + static extract() { + return [babelHelpers.classPrivateFieldLooseBase(this, _getA)[_getA], babelHelpers.classPrivateFieldLooseBase(this, _getB)[_getB]]; + } + +} + +var _getB2 = function _getB2() { + return this.b; +}; + +var _getA2 = function _getA2() { + return babelHelpers.get(babelHelpers.getPrototypeOf(B), "a", this); +}; + +Object.defineProperty(B, _getA, { + value: _getA2 +}); +Object.defineProperty(B, _getB, { + value: _getB2 +}); +const [getA, getB] = B.extract(); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/basic/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/basic/exec.js new file mode 100644 index 000000000000..791a59034af9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/basic/exec.js @@ -0,0 +1,23 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = "top secret string"; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = `Updated: ${newValue}`; + } + + static getValue() { + return Cl.#privateStaticFieldValue; + } + + static setValue() { + Cl.#privateStaticFieldValue = "dank"; + } +} + +expect(Cl.getValue()).toEqual("top secret string"); +Cl.setValue(); +expect(Cl.getValue()).toEqual("Updated: dank"); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/basic/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/basic/input.js new file mode 100644 index 000000000000..c79cdbe5ff0e --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/basic/input.js @@ -0,0 +1,19 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = "top secret string"; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = `Updated: ${newValue}`; + } + + static getValue() { + return Cl.#privateStaticFieldValue; + } + + static setValue() { + Cl.#privateStaticFieldValue = "dank"; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/basic/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/basic/output.js new file mode 100644 index 000000000000..f9b15a52fad0 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/basic/output.js @@ -0,0 +1,31 @@ +var _PRIVATE_STATIC_FIELD = babelHelpers.classPrivateFieldLooseKey("PRIVATE_STATIC_FIELD"); + +var _privateStaticFieldValue = babelHelpers.classPrivateFieldLooseKey("privateStaticFieldValue"); + +class Cl { + static getValue() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticFieldValue)[_privateStaticFieldValue]; + } + + static setValue() { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticFieldValue)[_privateStaticFieldValue] = "dank"; + } + +} + +var _set_privateStaticFieldValue = function (newValue) { + babelHelpers.classPrivateFieldLooseBase(Cl, _PRIVATE_STATIC_FIELD)[_PRIVATE_STATIC_FIELD] = `Updated: ${newValue}`; +}; + +var _get_privateStaticFieldValue = function () { + return babelHelpers.classPrivateFieldLooseBase(Cl, _PRIVATE_STATIC_FIELD)[_PRIVATE_STATIC_FIELD]; +}; + +Object.defineProperty(Cl, _PRIVATE_STATIC_FIELD, { + writable: true, + value: "top secret string" +}); +Object.defineProperty(Cl, _privateStaticFieldValue, { + get: _get_privateStaticFieldValue, + set: _set_privateStaticFieldValue +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/get-only-setter/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/get-only-setter/exec.js new file mode 100644 index 000000000000..0c14f25c0938 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/get-only-setter/exec.js @@ -0,0 +1,13 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = newValue; + } + + static getPrivateStaticFieldValue() { + return Cl.#privateStaticFieldValue; + } +} + +expect(Cl.getPrivateStaticFieldValue()).toBeUndefined(); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/get-only-setter/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/get-only-setter/input.js new file mode 100644 index 000000000000..ab8771074ec7 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/get-only-setter/input.js @@ -0,0 +1,11 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static set #privateStaticFieldValue(newValue) { + Cl.#PRIVATE_STATIC_FIELD = newValue; + } + + static getPrivateStaticFieldValue() { + return Cl.#privateStaticFieldValue; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/get-only-setter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/get-only-setter/output.js new file mode 100644 index 000000000000..9fc34593fd65 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/get-only-setter/output.js @@ -0,0 +1,23 @@ +var _PRIVATE_STATIC_FIELD = babelHelpers.classPrivateFieldLooseKey("PRIVATE_STATIC_FIELD"); + +var _privateStaticFieldValue = babelHelpers.classPrivateFieldLooseKey("privateStaticFieldValue"); + +class Cl { + static getPrivateStaticFieldValue() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticFieldValue)[_privateStaticFieldValue]; + } + +} + +var _set_privateStaticFieldValue = function (newValue) { + babelHelpers.classPrivateFieldLooseBase(Cl, _PRIVATE_STATIC_FIELD)[_PRIVATE_STATIC_FIELD] = newValue; +}; + +Object.defineProperty(Cl, _PRIVATE_STATIC_FIELD, { + writable: true, + value: 0 +}); +Object.defineProperty(Cl, _privateStaticFieldValue, { + get: void 0, + set: _set_privateStaticFieldValue +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/options.json b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/options.json new file mode 100644 index 000000000000..8db8526496b9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + ["external-helpers",{ "helperVersion": "7.1000.0" }], + "proposal-private-methods", + "proposal-class-properties" + ], + "assumptions": { + "privateFieldsAsProperties": true + } +} diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/set-only-getter/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/set-only-getter/exec.js new file mode 100644 index 000000000000..7069abfadc9d --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/set-only-getter/exec.js @@ -0,0 +1,13 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static setPrivateStaticFieldValue() { + Cl.#privateStaticFieldValue = 1; + } +} + +expect(() => Cl.setPrivateStaticFieldValue()).toThrow(TypeError); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/set-only-getter/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/set-only-getter/input.js new file mode 100644 index 000000000000..d54ce4e2c2d0 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/set-only-getter/input.js @@ -0,0 +1,11 @@ +class Cl { + static #PRIVATE_STATIC_FIELD = 0; + + static get #privateStaticFieldValue() { + return Cl.#PRIVATE_STATIC_FIELD; + } + + static setPrivateStaticFieldValue() { + Cl.#privateStaticFieldValue = 1; + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/set-only-getter/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/set-only-getter/output.js new file mode 100644 index 000000000000..2dfa44c30302 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/set-only-getter/output.js @@ -0,0 +1,23 @@ +var _PRIVATE_STATIC_FIELD = babelHelpers.classPrivateFieldLooseKey("PRIVATE_STATIC_FIELD"); + +var _privateStaticFieldValue = babelHelpers.classPrivateFieldLooseKey("privateStaticFieldValue"); + +class Cl { + static setPrivateStaticFieldValue() { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateStaticFieldValue)[_privateStaticFieldValue] = 1; + } + +} + +var _get_privateStaticFieldValue = function () { + return babelHelpers.classPrivateFieldLooseBase(Cl, _PRIVATE_STATIC_FIELD)[_PRIVATE_STATIC_FIELD]; +}; + +Object.defineProperty(Cl, _PRIVATE_STATIC_FIELD, { + writable: true, + value: 0 +}); +Object.defineProperty(Cl, _privateStaticFieldValue, { + get: _get_privateStaticFieldValue, + set: void 0 +}); diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/updates/exec.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/updates/exec.js new file mode 100644 index 000000000000..05f70aecceec --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/updates/exec.js @@ -0,0 +1,46 @@ +class Cl { + static #privateField = "top secret string"; + static publicField = "not secret string"; + + static get #privateFieldValue() { + return Cl.#privateField; + } + + static set #privateFieldValue(newValue) { + Cl.#privateField = newValue; + } + + static publicGetPrivateField() { + return Cl.#privateFieldValue; + } + + static publicSetPrivateField(newValue) { + Cl.#privateFieldValue = newValue; + } + + static get publicFieldValue() { + return Cl.publicField; + } + + static set publicFieldValue(newValue) { + Cl.publicField = newValue; + } + + static testUpdates() { + Cl.#privateField = 0; + Cl.publicField = 0; + Cl.#privateFieldValue = Cl.#privateFieldValue++; + Cl.publicFieldValue = Cl.publicFieldValue++; + expect(Cl.#privateField).toEqual(Cl.publicField); + + ++Cl.#privateFieldValue; + ++Cl.publicFieldValue; + expect(Cl.#privateField).toEqual(Cl.publicField); + + Cl.#privateFieldValue += 1; + Cl.publicFieldValue += 1; + expect(Cl.#privateField).toEqual(Cl.publicField); + } +} + +Cl.testUpdates(); \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/updates/input.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/updates/input.js new file mode 100644 index 000000000000..33c7b39d9cb4 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/updates/input.js @@ -0,0 +1,44 @@ +class Cl { + static #privateField = "top secret string"; + static publicField = "not secret string"; + + static get #privateFieldValue() { + return Cl.#privateField; + } + + static set #privateFieldValue(newValue) { + Cl.#privateField = newValue; + } + + static publicGetPrivateField() { + return Cl.#privateFieldValue; + } + + static publicSetPrivateField(newValue) { + Cl.#privateFieldValue = newValue; + } + + static get publicFieldValue() { + return Cl.publicField; + } + + static set publicFieldValue(newValue) { + Cl.publicField = newValue; + } + + static testUpdates() { + Cl.#privateField = 0; + Cl.publicField = 0; + Cl.#privateFieldValue = Cl.#privateFieldValue++; + Cl.publicFieldValue = Cl.publicFieldValue++; + + ++Cl.#privateFieldValue; + ++Cl.publicFieldValue; + + Cl.#privateFieldValue += 1; + Cl.publicFieldValue += 1; + + Cl.#privateFieldValue = -(Cl.#privateFieldValue ** Cl.#privateFieldValue); + Cl.publicFieldValue = -(Cl.publicFieldValue ** Cl.publicFieldValue); + } +} \ No newline at end of file diff --git a/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/updates/output.js b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/updates/output.js new file mode 100644 index 000000000000..d9d601bd2297 --- /dev/null +++ b/packages/babel-plugin-proposal-private-methods/test/fixtures/static-accessors-privateFieldsAsProperties/updates/output.js @@ -0,0 +1,53 @@ +var _privateField = babelHelpers.classPrivateFieldLooseKey("privateField"); + +var _privateFieldValue = babelHelpers.classPrivateFieldLooseKey("privateFieldValue"); + +class Cl { + static publicGetPrivateField() { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue]; + } + + static publicSetPrivateField(newValue) { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue] = newValue; + } + + static get publicFieldValue() { + return Cl.publicField; + } + + static set publicFieldValue(newValue) { + Cl.publicField = newValue; + } + + static testUpdates() { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateField)[_privateField] = 0; + Cl.publicField = 0; + babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue] = babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue]++; + Cl.publicFieldValue = Cl.publicFieldValue++; + ++babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue]; + ++Cl.publicFieldValue; + babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue] += 1; + Cl.publicFieldValue += 1; + babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue] = -(babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue] ** babelHelpers.classPrivateFieldLooseBase(Cl, _privateFieldValue)[_privateFieldValue]); + Cl.publicFieldValue = -(Cl.publicFieldValue ** Cl.publicFieldValue); + } + +} + +var _set_privateFieldValue = function (newValue) { + babelHelpers.classPrivateFieldLooseBase(Cl, _privateField)[_privateField] = newValue; +}; + +var _get_privateFieldValue = function () { + return babelHelpers.classPrivateFieldLooseBase(Cl, _privateField)[_privateField]; +}; + +Object.defineProperty(Cl, _privateField, { + writable: true, + value: "top secret string" +}); +babelHelpers.defineProperty(Cl, "publicField", "not secret string"); +Object.defineProperty(Cl, _privateFieldValue, { + get: _get_privateFieldValue, + set: _set_privateFieldValue +}); diff --git a/packages/babel-plugin-proposal-private-property-in-object/src/index.js b/packages/babel-plugin-proposal-private-property-in-object/src/index.js index 70dbf3e4c737..c8c5c7bddcc0 100644 --- a/packages/babel-plugin-proposal-private-property-in-object/src/index.js +++ b/packages/babel-plugin-proposal-private-property-in-object/src/index.js @@ -12,6 +12,7 @@ export default declare((api, options) => { return createClassFeaturePlugin({ name: "proposal-class-properties", + api, feature: FEATURES.privateIn, loose: options.loose, diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/accessor/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/accessor/input.js new file mode 100644 index 000000000000..c0e9000615fd --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/accessor/input.js @@ -0,0 +1,7 @@ +class Foo { + get #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/accessor/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/accessor/output.js new file mode 100644 index 000000000000..9d2a42925dfe --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/accessor/output.js @@ -0,0 +1,17 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Foo { + constructor() { + Object.defineProperty(this, _foo, { + get: _get_foo, + set: void 0 + }); + } + + test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + +} + +var _get_foo = function () {}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/compiled-classes/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/compiled-classes/input.js new file mode 100644 index 000000000000..23c266018025 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/compiled-classes/input.js @@ -0,0 +1,12 @@ +class Foo { + static #foo = "foo"; + #bar = "bar"; + + static test() { + return #foo in Foo; + } + + test() { + return #bar in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/compiled-classes/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/compiled-classes/options.json new file mode 100644 index 000000000000..9d27af601e04 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/compiled-classes/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "proposal-private-property-in-object", + "proposal-class-properties", + "proposal-private-methods", + "transform-classes" + ] +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/compiled-classes/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/compiled-classes/output.js new file mode 100644 index 000000000000..1889def268b8 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/compiled-classes/output.js @@ -0,0 +1,33 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +var _bar = babelHelpers.classPrivateFieldLooseKey("bar"); + +let Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + Object.defineProperty(this, _bar, { + writable: true, + value: "bar" + }); + } + + babelHelpers.createClass(Foo, [{ + key: "test", + value: function test() { + return Object.prototype.hasOwnProperty.call(this, _bar); + } + }], [{ + key: "test", + value: function test() { + return Object.prototype.hasOwnProperty.call(Foo, _foo); + } + }]); + return Foo; +}(); + +Object.defineProperty(Foo, _foo, { + writable: true, + value: "foo" +}); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/field/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/field/input.js new file mode 100644 index 000000000000..a682a1a15c5b --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/field/input.js @@ -0,0 +1,7 @@ +class Foo { + #foo = 1; + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/field/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/field/output.js new file mode 100644 index 000000000000..df6a89c95c78 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/field/output.js @@ -0,0 +1,15 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Foo { + constructor() { + Object.defineProperty(this, _foo, { + writable: true, + value: 1 + }); + } + + test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/method/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/method/input.js new file mode 100644 index 000000000000..365843c59708 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/method/input.js @@ -0,0 +1,7 @@ +class Foo { + #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/method/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/method/output.js new file mode 100644 index 000000000000..aebc5e5ffad0 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/method/output.js @@ -0,0 +1,16 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Foo { + constructor() { + Object.defineProperty(this, _foo, { + value: _foo2 + }); + } + + test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + +} + +var _foo2 = function _foo2() {}; diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-other-redeclared/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-other-redeclared/input.js new file mode 100644 index 000000000000..a084dd06afd6 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-other-redeclared/input.js @@ -0,0 +1,18 @@ +class Foo { + #foo = 1; + #bar = 1; + + test() { + class Nested { + #bar = 2; + + test() { + #foo in this; + #bar in this; + } + } + + #foo in this; + #bar in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-other-redeclared/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-other-redeclared/output.js new file mode 100644 index 000000000000..42541d45123f --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-other-redeclared/output.js @@ -0,0 +1,39 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +var _bar = babelHelpers.classPrivateFieldLooseKey("bar"); + +class Foo { + constructor() { + Object.defineProperty(this, _foo, { + writable: true, + value: 1 + }); + Object.defineProperty(this, _bar, { + writable: true, + value: 1 + }); + } + + test() { + var _bar2 = babelHelpers.classPrivateFieldLooseKey("bar"); + + class Nested { + constructor() { + Object.defineProperty(this, _bar2, { + writable: true, + value: 2 + }); + } + + test() { + Object.prototype.hasOwnProperty.call(this, _foo); + Object.prototype.hasOwnProperty.call(this, _bar2); + } + + } + + Object.prototype.hasOwnProperty.call(this, _foo); + Object.prototype.hasOwnProperty.call(this, _bar); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-redeclared/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-redeclared/input.js new file mode 100644 index 000000000000..2258be35c5fd --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-redeclared/input.js @@ -0,0 +1,15 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + #foo = 2; + + test() { + #foo in this; + } + } + + #foo in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-redeclared/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-redeclared/output.js new file mode 100644 index 000000000000..e20e475ad96f --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class-redeclared/output.js @@ -0,0 +1,31 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Foo { + constructor() { + Object.defineProperty(this, _foo, { + writable: true, + value: 1 + }); + } + + test() { + var _foo2 = babelHelpers.classPrivateFieldLooseKey("foo"); + + class Nested { + constructor() { + Object.defineProperty(this, _foo2, { + writable: true, + value: 2 + }); + } + + test() { + Object.prototype.hasOwnProperty.call(this, _foo2); + } + + } + + Object.prototype.hasOwnProperty.call(this, _foo); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class/input.js new file mode 100644 index 000000000000..e17e438b314d --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class/input.js @@ -0,0 +1,13 @@ +class Foo { + #foo = 1; + + test() { + class Nested { + test() { + #foo in this; + } + } + + #foo in this; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class/output.js new file mode 100644 index 000000000000..b87aa8205365 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/nested-class/output.js @@ -0,0 +1,22 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Foo { + constructor() { + Object.defineProperty(this, _foo, { + writable: true, + value: 1 + }); + } + + test() { + class Nested { + test() { + Object.prototype.hasOwnProperty.call(this, _foo); + } + + } + + Object.prototype.hasOwnProperty.call(this, _foo); + } + +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/options.json b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/options.json new file mode 100644 index 000000000000..27edc061ba5a --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/options.json @@ -0,0 +1,11 @@ +{ + "plugins": [ + ["external-helpers",{ "helperVersion": "7.1000.0" }], + "proposal-private-property-in-object", + "proposal-private-methods", + "proposal-class-properties" + ], + "assumptions": { + "privateFieldsAsProperties": true + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-accessor/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-accessor/input.js new file mode 100644 index 000000000000..e74333f2055f --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-accessor/input.js @@ -0,0 +1,7 @@ +class Foo { + static get #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-accessor/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-accessor/output.js new file mode 100644 index 000000000000..3f5bbb4c847f --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-accessor/output.js @@ -0,0 +1,15 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Foo { + test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + +} + +var _get_foo = function () {}; + +Object.defineProperty(Foo, _foo, { + get: _get_foo, + set: void 0 +}); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-field/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-field/input.js new file mode 100644 index 000000000000..a4f771844fe9 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-field/input.js @@ -0,0 +1,7 @@ +class Foo { + static #foo = 1; + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-field/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-field/output.js new file mode 100644 index 000000000000..b69ce320b78f --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-field/output.js @@ -0,0 +1,13 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Foo { + test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + +} + +Object.defineProperty(Foo, _foo, { + writable: true, + value: 1 +}); diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-method/input.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-method/input.js new file mode 100644 index 000000000000..9fffe7a01622 --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-method/input.js @@ -0,0 +1,7 @@ +class Foo { + static #foo() {} + + test(other) { + return #foo in other; + } +} diff --git a/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-method/output.js b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-method/output.js new file mode 100644 index 000000000000..e6af49be3aff --- /dev/null +++ b/packages/babel-plugin-proposal-private-property-in-object/test/fixtures/assumption-privateFieldsAsProperties/static-method/output.js @@ -0,0 +1,14 @@ +var _foo = babelHelpers.classPrivateFieldLooseKey("foo"); + +class Foo { + test(other) { + return Object.prototype.hasOwnProperty.call(other, _foo); + } + +} + +var _foo2 = function _foo2() {}; + +Object.defineProperty(Foo, _foo, { + value: _foo2 +}); diff --git a/packages/babel-plugin-transform-arrow-functions/src/index.js b/packages/babel-plugin-transform-arrow-functions/src/index.js index 3e323707a887..98ac9f4d626e 100644 --- a/packages/babel-plugin-transform-arrow-functions/src/index.js +++ b/packages/babel-plugin-transform-arrow-functions/src/index.js @@ -4,7 +4,8 @@ import type NodePath from "@babel/traverse"; export default declare((api, options) => { api.assertVersion(7); - const { spec } = options; + const noNewArrows = api.assumption("noNewArrows") ?? !options.spec; + return { name: "transform-arrow-functions", @@ -20,7 +21,10 @@ export default declare((api, options) => { // While other utils may be fine inserting other arrows to make more transforms possible, // the arrow transform itself absolutely cannot insert new arrow functions. allowInsertArrow: false, - specCompliant: !!spec, + noNewArrows, + + // TODO(Babel 8): This is only needed for backward compat with @babel/traverse <7.13.0 + specCompliant: !noNewArrows, }); }, }, diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-self-referential/options.json b/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-self-referential/options.json deleted file mode 100644 index edcdc8224cda..000000000000 --- a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-self-referential/options.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "plugins": [ - "external-helpers", - ["transform-arrow-functions", { "spec": true }], - "transform-function-name" - ] -} diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/basic/input.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/basic/input.js new file mode 100644 index 000000000000..f84ea4ed3876 --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/basic/input.js @@ -0,0 +1,10 @@ +function foo() { + arr.map(x => x * x); + var f = (x, y) => x * y; + (function () { + return () => this; + })(); + return { + g: () => this + } +} diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/basic/output.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/basic/output.js new file mode 100644 index 000000000000..6b0103c02f66 --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/basic/output.js @@ -0,0 +1,29 @@ +function foo() { + var _this = this; + + arr.map(function (x) { + babelHelpers.newArrowCheck(this, _this); + return x * x; + }.bind(this)); + + var f = function f(x, y) { + babelHelpers.newArrowCheck(this, _this); + return x * y; + }.bind(this); + + (function () { + var _this2 = this; + + return function () { + babelHelpers.newArrowCheck(this, _this2); + return this; + }.bind(this); + })(); + + return { + g: function g() { + babelHelpers.newArrowCheck(this, _this); + return this; + }.bind(this) + }; +} diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-naming/input.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/naming/input.js similarity index 100% rename from packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-naming/input.js rename to packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/naming/input.js diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-naming/output.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/naming/output.js similarity index 100% rename from packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-naming/output.js rename to packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/naming/output.js diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/options.json b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/options.json new file mode 100644 index 000000000000..0f1579e8b4f4 --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/options.json @@ -0,0 +1,6 @@ +{ + "plugins": ["external-helpers", "transform-arrow-functions"], + "assumptions": { + "noNewArrows": false + } +} diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-self-referential/exec.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/self-referential/exec.js similarity index 100% rename from packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-self-referential/exec.js rename to packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/self-referential/exec.js diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-self-referential/input.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/self-referential/input.js similarity index 100% rename from packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-self-referential/input.js rename to packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/self-referential/input.js diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-self-referential/output.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/self-referential/output.js similarity index 100% rename from packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-self-referential/output.js rename to packages/babel-plugin-transform-arrow-functions/test/fixtures/assumption-newableArrowFunctions-false/self-referential/output.js diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-default/input.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-default/input.js new file mode 100644 index 000000000000..0f3dac36a7ce --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-default/input.js @@ -0,0 +1 @@ +let a = () => 1; diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-naming/options.json b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-default/options.json similarity index 100% rename from packages/babel-plugin-transform-arrow-functions/test/fixtures/arrow-functions/spec-naming/options.json rename to packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-default/options.json diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-default/output.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-default/output.js new file mode 100644 index 000000000000..cee824c23a0b --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-default/output.js @@ -0,0 +1,6 @@ +var _this = this; + +let a = function a() { + babelHelpers.newArrowCheck(this, _this); + return 1; +}.bind(this); diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-false/input.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-false/input.js new file mode 100644 index 000000000000..0f3dac36a7ce --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-false/input.js @@ -0,0 +1 @@ +let a = () => 1; diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-false/options.json b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-false/options.json new file mode 100644 index 000000000000..54a09372627d --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-false/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "external-helpers", + ["transform-arrow-functions", { "spec": false }] + ], + "assumptions": { + "noNewArrows": false + } +} diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-false/output.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-false/output.js new file mode 100644 index 000000000000..cee824c23a0b --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-false/output.js @@ -0,0 +1,6 @@ +var _this = this; + +let a = function a() { + babelHelpers.newArrowCheck(this, _this); + return 1; +}.bind(this); diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-true/input.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-true/input.js new file mode 100644 index 000000000000..0f3dac36a7ce --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-true/input.js @@ -0,0 +1 @@ +let a = () => 1; diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-true/options.json b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-true/options.json new file mode 100644 index 000000000000..fe79242117b9 --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-true/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "external-helpers", + ["transform-arrow-functions", { "spec": true }] + ], + "assumptions": { + "noNewArrows": true + } +} diff --git a/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-true/output.js b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-true/output.js new file mode 100644 index 000000000000..ccc9512d820a --- /dev/null +++ b/packages/babel-plugin-transform-arrow-functions/test/fixtures/spec/newableArrowFunction-vs-spec-true/output.js @@ -0,0 +1,3 @@ +let a = function () { + return 1; +}; diff --git a/packages/babel-plugin-transform-async-to-generator/src/index.js b/packages/babel-plugin-transform-async-to-generator/src/index.js index 55669063f13b..da21acedbf12 100644 --- a/packages/babel-plugin-transform-async-to-generator/src/index.js +++ b/packages/babel-plugin-transform-async-to-generator/src/index.js @@ -7,6 +7,7 @@ export default declare((api, options) => { api.assertVersion(7); const { method, module } = options; + const noNewArrows = api.assumption("noNewArrows"); if (method && module) { return { @@ -23,7 +24,7 @@ export default declare((api, options) => { wrapAsync = state.methodWrapper = addNamed(path, method, module); } - remapAsyncToGenerator(path, { wrapAsync }); + remapAsyncToGenerator(path, { wrapAsync }, noNewArrows); }, }, }; @@ -36,9 +37,11 @@ export default declare((api, options) => { Function(path, state) { if (!path.node.async || path.node.generator) return; - remapAsyncToGenerator(path, { - wrapAsync: state.addHelper("asyncToGenerator"), - }); + remapAsyncToGenerator( + path, + { wrapAsync: state.addHelper("asyncToGenerator") }, + noNewArrows, + ); }, }, }; diff --git a/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/exec.js b/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/exec.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/input.js b/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/input.js new file mode 100644 index 000000000000..eb65515a95bd --- /dev/null +++ b/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/input.js @@ -0,0 +1 @@ +async () => 2; diff --git a/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/options.json b/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/options.json new file mode 100644 index 000000000000..0aed78e05b38 --- /dev/null +++ b/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/options.json @@ -0,0 +1,6 @@ +{ + "plugins": ["external-helpers", "transform-async-to-generator"], + "assumptions": { + "noNewArrows": false + } +} diff --git a/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/output.js b/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/output.js new file mode 100644 index 000000000000..c0d2e6069da5 --- /dev/null +++ b/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/basic/output.js @@ -0,0 +1,7 @@ +var _this = this; + +/*#__PURE__*/ +babelHelpers.asyncToGenerator(function* () { + babelHelpers.newArrowCheck(this, _this); + return 2; +}); diff --git a/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/bluebird/input.js b/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/bluebird/input.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/bluebird/options.json b/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/bluebird/options.json new file mode 100644 index 000000000000..bcd09c73c443 --- /dev/null +++ b/packages/babel-plugin-transform-async-to-generator/test/fixtures/assumption-newableArrowFunctions-false/bluebird/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + "external-helpers", + [ + "transform-async-to-generator", + { "module": "bluebird", "method": "coroutine" } + ] + ], + "assumptions": { + "noNewArrows": true + } +} diff --git a/packages/babel-plugin-transform-classes/src/index.js b/packages/babel-plugin-transform-classes/src/index.js index 8f0ecfc202ca..cceccf155e49 100644 --- a/packages/babel-plugin-transform-classes/src/index.js +++ b/packages/babel-plugin-transform-classes/src/index.js @@ -21,6 +21,12 @@ export default declare((api, options) => { const { loose } = options; + const setClassMethods = api.assumption("setClassMethods") ?? options.loose; + const constantSuper = api.assumption("constantSuper") ?? options.loose; + const superIsCallableConstructor = + api.assumption("superIsCallableConstructor") ?? options.loose; + const noClassCalls = api.assumption("noClassCalls") ?? options.loose; + // todo: investigate traversal requeueing const VISITED = Symbol(); @@ -58,12 +64,18 @@ export default declare((api, options) => { node[VISITED] = true; path.replaceWith( - transformClass(path, state.file, builtinClasses, loose), + transformClass(path, state.file, builtinClasses, loose, { + setClassMethods, + constantSuper, + superIsCallableConstructor, + noClassCalls, + }), ); if (path.isCallExpression()) { annotateAsPure(path); if (path.get("callee").isArrowFunctionExpression()) { + // This is an IIFE, so we don't need to worry about the noNewArrows assumption path.get("callee").arrowFunctionToExpression(); } } diff --git a/packages/babel-plugin-transform-classes/src/transformClass.js b/packages/babel-plugin-transform-classes/src/transformClass.js index 0d3fa37600d8..5244e6b64022 100644 --- a/packages/babel-plugin-transform-classes/src/transformClass.js +++ b/packages/babel-plugin-transform-classes/src/transformClass.js @@ -11,6 +11,13 @@ import addCreateSuperHelper from "./inline-createSuper-helpers"; type ReadonlySet = Set | { has(val: T): boolean }; +type ClassAssumptions = { + setClassMethods: boolean, + constantSuper: boolean, + superIsCallableConstructor: boolean, + noClassCalls: boolean, +}; + function buildConstructor(classRef, constructorBody, node) { const func = t.functionDeclaration( t.cloneNode(classRef), @@ -26,6 +33,7 @@ export default function transformClass( file: any, builtinClasses: ReadonlySet, isLoose: boolean, + assumptions: ClassAssumptions, ) { const classState = { parent: undefined, @@ -161,7 +169,7 @@ export default function transformClass( methodPath: path, objectRef: classState.classRef, superRef: classState.superName, - isLoose: classState.isLoose, + constantSuper: assumptions.constantSuper, file: classState.file, refToPreserve: classState.classRef, }); @@ -246,7 +254,7 @@ export default function transformClass( const bareSuperNode = bareSuper.node; let call; - if (classState.isLoose) { + if (assumptions.superIsCallableConstructor) { bareSuperNode.arguments.unshift(t.thisExpression()); if ( bareSuperNode.arguments.length === 2 && @@ -452,7 +460,7 @@ export default function transformClass( } function processMethod(node, scope) { - if (classState.isLoose && !node.decorators) { + if (assumptions.setClassMethods && !node.decorators) { // use assignments instead of define properties for loose classes let { classRef } = classState; if (!node.static) { @@ -563,7 +571,7 @@ export default function transformClass( // Unshift to ensure that the constructor inheritance is set up before // any properties can be assigned to the prototype. - if (!classState.isLoose) { + if (!assumptions.superIsCallableConstructor) { classState.body.unshift( t.variableDeclaration("var", [ t.variableDeclarator( @@ -663,7 +671,7 @@ export default function transformClass( buildBody(); // make sure this class isn't directly called (with A() instead new A()) - if (!classState.isLoose) { + if (!assumptions.noClassCalls) { constructorBody.body.unshift( t.expressionStatement( t.callExpression(classState.file.addHelper("classCallCheck"), [ diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/input.js new file mode 100644 index 000000000000..83f054a6e911 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/input.js @@ -0,0 +1,13 @@ +class Test extends Foo { + constructor() { + woops.super.test(); + super(); + super.test(); + + super(...arguments); + super("test", ...arguments); + + super.test(...arguments); + super.test("test", ...arguments); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/output.js new file mode 100644 index 000000000000..929c2c08fe95 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-class/output.js @@ -0,0 +1,30 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inherits(Test, _Foo); + + var _super = babelHelpers.createSuper(Test); + + function Test() { + var _Foo$prototype$test; + + var _this; + + babelHelpers.classCallCheck(this, Test); + woops.super.test(); + _this = _super.call(this); + + _Foo.prototype.test.call(babelHelpers.assertThisInitialized(_this)); + + _this = _super.apply(this, arguments); + _this = _super.call.apply(_super, [this, "test"].concat(Array.prototype.slice.call(arguments))); + + _Foo.prototype.test.apply(babelHelpers.assertThisInitialized(_this), arguments); + + (_Foo$prototype$test = _Foo.prototype.test).call.apply(_Foo$prototype$test, [babelHelpers.assertThisInitialized(_this), "test"].concat(Array.prototype.slice.call(arguments))); + + return _this; + } + + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/input.js new file mode 100644 index 000000000000..fad2b31584ef --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/input.js @@ -0,0 +1,7 @@ +class Test extends Foo { + constructor() { + super(); + super.test; + super.test.whatever; + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/output.js new file mode 100644 index 000000000000..57ce4e416d44 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-properties/output.js @@ -0,0 +1,19 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inherits(Test, _Foo); + + var _super = babelHelpers.createSuper(Test); + + function Test() { + var _this; + + babelHelpers.classCallCheck(this, Test); + _this = _super.call(this); + _Foo.prototype.test; + _Foo.prototype.test.whatever; + return _this; + } + + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/input.js new file mode 100644 index 000000000000..e0788b60b37f --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/input.js @@ -0,0 +1,6 @@ +class Test extends Foo { + constructor() { + super.foo?.bar; + super.foo?.(); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/options.json new file mode 100644 index 000000000000..d969db5fb34d --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + ["proposal-optional-chaining", { "loose": true }], + "transform-function-name", + ["transform-classes", { "loose": true }], + ["transform-spread", { "loose": true }], + "transform-block-scoping" + ] +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/output.js new file mode 100644 index 000000000000..d076ccfc9cce --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/accessing-super-property-optional-chain/output.js @@ -0,0 +1,17 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inheritsLoose(Test, _Foo); + + function Test() { + var _Foo$prototype$foo, _Foo$prototype$foo2; + + var _this; + + (_Foo$prototype$foo = _Foo.prototype.foo) == null ? void 0 : _Foo$prototype$foo.bar; + (_Foo$prototype$foo2 = _Foo.prototype.foo) == null ? void 0 : _Foo$prototype$foo2.call(babelHelpers.assertThisInitialized(_this)); + return babelHelpers.assertThisInitialized(_this); + } + + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/input.js new file mode 100644 index 000000000000..0b392d3eb252 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/input.js @@ -0,0 +1,11 @@ +class Test extends Foo { + constructor() { + super(); + super.test.whatever(); + super.test(); + } + + static test() { + return super.wow(); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/output.js new file mode 100644 index 000000000000..d071019228d2 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/calling-super-properties/output.js @@ -0,0 +1,28 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inherits(Test, _Foo); + + var _super = babelHelpers.createSuper(Test); + + function Test() { + var _this; + + babelHelpers.classCallCheck(this, Test); + _this = _super.call(this); + + _Foo.prototype.test.whatever(); + + _Foo.prototype.test.call(babelHelpers.assertThisInitialized(_this)); + + return _this; + } + + babelHelpers.createClass(Test, null, [{ + key: "test", + value: function test() { + return _Foo.wow.call(this); + } + }]); + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/input.js new file mode 100644 index 000000000000..eaba10ab2bbd --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/input.js @@ -0,0 +1,17 @@ +class Test { + constructor() { + return super.constructor; + } + + static test() { + return super.constructor; + } +} + +// Instances +expect(Object.getPrototypeOf(Test.prototype)).toBe(Object.prototype); +expect(new Test()).toBe(Object); + +// Static +expect(Object.getPrototypeOf(Test)).toBe(Function.prototype); +expect(Test.test()).toBe(Function); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/output.js new file mode 100644 index 000000000000..56f85c05785c --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/default-super/output.js @@ -0,0 +1,23 @@ +var Test = /*#__PURE__*/function () { + "use strict"; + + function Test() { + babelHelpers.classCallCheck(this, Test); + return Object.prototype.constructor; + } + + babelHelpers.createClass(Test, null, [{ + key: "test", + value: function test() { + return Function.prototype.constructor; + } + }]); + return Test; +}(); // Instances + + +expect(Object.getPrototypeOf(Test.prototype)).toBe(Object.prototype); +expect(new Test()).toBe(Object); // Static + +expect(Object.getPrototypeOf(Test)).toBe(Function.prototype); +expect(Test.test()).toBe(Function); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/options.json new file mode 100644 index 000000000000..39e1d1bab810 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-function-name", + "transform-classes", + ["transform-spread", { "loose": true }], + "transform-block-scoping" + ], + "assumptions": { + "constantSuper": true + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/input.js new file mode 100644 index 000000000000..18ebeb8f3085 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/input.js @@ -0,0 +1,5 @@ +class Test { + constructor() { + super.hasOwnProperty("test"); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/output.js new file mode 100644 index 000000000000..f57c0d549409 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-constantSuper/super-function-fallback/output.js @@ -0,0 +1,6 @@ +var Test = function Test() { + "use strict"; + + babelHelpers.classCallCheck(this, Test); + Object.prototype.hasOwnProperty.call(this, "test"); +}; diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/input.js new file mode 100644 index 000000000000..a869c2849526 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/input.js @@ -0,0 +1 @@ +class A {} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/output.js new file mode 100644 index 000000000000..60718092a600 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/class/output.js @@ -0,0 +1,3 @@ +var A = function A() { + "use strict"; +}; diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json new file mode 100644 index 000000000000..fe4fa1e68bec --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-function-name", + "transform-classes", + ["transform-spread", { "loose": true }], + "transform-block-scoping" + ], + "assumptions": { + "noClassCalls": true + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/input.js new file mode 100644 index 000000000000..9da66478b288 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/input.js @@ -0,0 +1,11 @@ +class A { + constructor() { + console.log('a'); + } +} + +class B { + b() { + console.log('b'); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/output.js new file mode 100644 index 000000000000..a9666614fef8 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-constructor/output.js @@ -0,0 +1,19 @@ +var A = function A() { + "use strict"; + + console.log('a'); +}; + +var B = /*#__PURE__*/function () { + "use strict"; + + function B() {} + + babelHelpers.createClass(B, [{ + key: "b", + value: function b() { + console.log('b'); + } + }]); + return B; +}(); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/input.js new file mode 100644 index 000000000000..76bb1ebddfbf --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/input.js @@ -0,0 +1,8 @@ +class B {} + +class A extends B { + constructor(track) { + if (track !== undefined) super(track); + else super(); + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/output.js new file mode 100644 index 000000000000..1d09fd08d8e6 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-noCallClass/with-superClass/output.js @@ -0,0 +1,20 @@ +var B = function B() { + "use strict"; +}; + +var A = /*#__PURE__*/function (_B) { + "use strict"; + + babelHelpers.inherits(A, _B); + + var _super = babelHelpers.createSuper(A); + + function A(track) { + var _this; + + if (track !== undefined) _this = _super.call(this, track);else _this = _super.call(this); + return babelHelpers.possibleConstructorReturn(_this); + } + + return A; +}(B); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/input.js new file mode 100644 index 000000000000..e3ad20145b86 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/input.js @@ -0,0 +1,5 @@ +class Foo { + "bar"() { + + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/output.js new file mode 100644 index 000000000000..610fbb5a157e --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/literal-key/output.js @@ -0,0 +1,13 @@ +var Foo = /*#__PURE__*/function () { + "use strict"; + + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + var _proto = Foo.prototype; + + _proto["bar"] = function bar() {}; + + return Foo; +}(); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/input.js new file mode 100644 index 000000000000..918e7469b6c7 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/input.js @@ -0,0 +1,6 @@ +// @flow +class C { + m(x: number): string { + return 'a'; + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/options.json new file mode 100644 index 000000000000..1f9617ec390b --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/options.json @@ -0,0 +1,10 @@ +{ + "plugins": [ + "external-helpers", + "transform-function-name", + ["transform-classes", { "loose": true }], + "transform-spread", + "transform-block-scoping", + "syntax-flow" + ] +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/output.js new file mode 100644 index 000000000000..45403829143d --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-return-type-annotation/output.js @@ -0,0 +1,14 @@ +// @flow +var C = /*#__PURE__*/function () { + "use strict"; + + function C() {} + + var _proto = C.prototype; + + _proto.m = function m(x: number): string { + return 'a'; + }; + + return C; +}(); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/input.js new file mode 100644 index 000000000000..1c08a3644980 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/input.js @@ -0,0 +1,5 @@ +class Test { + a() {} + static b() {} + c() {} +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/output.js new file mode 100644 index 000000000000..844b0d7655e7 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/method-reuse-prototype/output.js @@ -0,0 +1,17 @@ +var Test = /*#__PURE__*/function () { + "use strict"; + + function Test() { + babelHelpers.classCallCheck(this, Test); + } + + var _proto = Test.prototype; + + _proto.a = function a() {}; + + Test.b = function b() {}; + + _proto.c = function c() {}; + + return Test; +}(); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/options.json new file mode 100644 index 000000000000..62562eb645d7 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-function-name", + "transform-classes", + ["transform-spread", { "loose": true }], + "transform-block-scoping" + ], + "assumptions": { + "setClassMethods": true + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/input.js new file mode 100644 index 000000000000..4bbf0638b3be --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/input.js @@ -0,0 +1,7 @@ +"use strict"; + +class Foo { + method() { + + } +} \ No newline at end of file diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/output.js new file mode 100644 index 000000000000..96acb356c59a --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-setClassMethods/program-with-use-strict-directive/output.js @@ -0,0 +1,13 @@ +"use strict"; + +var Foo = /*#__PURE__*/function () { + function Foo() { + babelHelpers.classCallCheck(this, Foo); + } + + var _proto = Foo.prototype; + + _proto.method = function method() {}; + + return Foo; +}(); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/options.json b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/options.json new file mode 100644 index 000000000000..7002b66f731e --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/options.json @@ -0,0 +1,12 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-function-name", + "transform-classes", + ["transform-spread", { "loose": true }], + "transform-block-scoping" + ], + "assumptions": { + "superIsCallableConstructor": true + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/input.js new file mode 100644 index 000000000000..e245d3a69baa --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/input.js @@ -0,0 +1,7 @@ +class BaseController extends Chaplin.Controller { + +} + +class BaseController2 extends Chaplin.Controller.Another { + +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/output.js new file mode 100644 index 000000000000..1b4b3a994b0d --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-id-member-expression/output.js @@ -0,0 +1,25 @@ +var BaseController = /*#__PURE__*/function (_Chaplin$Controller) { + "use strict"; + + babelHelpers.inherits(BaseController, _Chaplin$Controller); + + function BaseController() { + babelHelpers.classCallCheck(this, BaseController); + return _Chaplin$Controller.apply(this, arguments) || this; + } + + return BaseController; +}(Chaplin.Controller); + +var BaseController2 = /*#__PURE__*/function (_Chaplin$Controller$A) { + "use strict"; + + babelHelpers.inherits(BaseController2, _Chaplin$Controller$A); + + function BaseController2() { + babelHelpers.classCallCheck(this, BaseController2); + return _Chaplin$Controller$A.apply(this, arguments) || this; + } + + return BaseController2; +}(Chaplin.Controller.Another); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/input.js new file mode 100644 index 000000000000..f27cd5b8b449 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/input.js @@ -0,0 +1,9 @@ +class Test extends Foo { + constructor() { + super(); + + this; + + this.prop = 1; + } +} diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/output.js new file mode 100644 index 000000000000..f516eaf62a1f --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class-this-usage/output.js @@ -0,0 +1,17 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inherits(Test, _Foo); + + function Test() { + var _this; + + babelHelpers.classCallCheck(this, Test); + _this = _Foo.call(this) || this; + babelHelpers.assertThisInitialized(_this); + _this.prop = 1; + return _this; + } + + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/input.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/input.js new file mode 100644 index 000000000000..13a98b37be8b --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/input.js @@ -0,0 +1 @@ +class Test extends Foo { } diff --git a/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/output.js b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/output.js new file mode 100644 index 000000000000..01c3014c0112 --- /dev/null +++ b/packages/babel-plugin-transform-classes/test/fixtures/assumption-superIsCallableConstructor/super-class/output.js @@ -0,0 +1,12 @@ +var Test = /*#__PURE__*/function (_Foo) { + "use strict"; + + babelHelpers.inherits(Test, _Foo); + + function Test() { + babelHelpers.classCallCheck(this, Test); + return _Foo.apply(this, arguments) || this; + } + + return Test; +}(Foo); diff --git a/packages/babel-plugin-transform-computed-properties/src/index.js b/packages/babel-plugin-transform-computed-properties/src/index.js index eabb277b3e42..9fa5c5c96482 100644 --- a/packages/babel-plugin-transform-computed-properties/src/index.js +++ b/packages/babel-plugin-transform-computed-properties/src/index.js @@ -4,8 +4,10 @@ import { template, types as t } from "@babel/core"; export default declare((api, options) => { api.assertVersion(7); - const { loose } = options; - const pushComputedProps = loose + const setComputedProperties = + api.assumption("setComputedProperties") ?? options.loose; + + const pushComputedProps = setComputedProperties ? pushComputedPropsLoose : pushComputedPropsSpec; diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/accessors/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/accessors/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/accessors/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/accessors/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/accessors/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/accessors/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/accessors/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/accessors/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/argument/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/argument/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/argument/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/argument/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/argument/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/argument/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/argument/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/argument/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/assignment/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/assignment/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/assignment/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/assignment/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/assignment/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/assignment/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/assignment/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/assignment/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/coerce/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/coerce/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/coerce/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/coerce/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/coerce/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/coerce/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/coerce/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/coerce/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/method/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/method/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/method/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/method/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/method/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/method/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/method/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/method/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/mixed/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/mixed/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/mixed/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/mixed/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/mixed/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/mixed/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/mixed/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/mixed/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/multiple/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/multiple/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/multiple/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/multiple/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/multiple/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/multiple/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/multiple/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/multiple/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/options.json b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/options.json new file mode 100644 index 000000000000..2a2f114c2a9e --- /dev/null +++ b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + "external-helpers", + "transform-computed-properties" + ], + "assumptions": { + "setComputedProperties": true + } +} diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/single/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/single/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/single/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/single/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/single/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/single/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/single/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/single/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/symbol/exec.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/symbol/exec.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/symbol/exec.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/symbol/exec.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/symbol/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/symbol/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/symbol/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/symbol/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/symbol/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/symbol/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/symbol/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/symbol/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/this/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/this/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/this/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/this/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/this/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/this/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/this/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/this/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/two/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/two/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/two/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/two/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/two/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/two/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/two/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/two/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/variable/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/variable/input.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/variable/input.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/variable/input.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/variable/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/variable/output.js similarity index 100% rename from packages/babel-plugin-transform-computed-properties/test/fixtures/loose/variable/output.js rename to packages/babel-plugin-transform-computed-properties/test/fixtures/assumption-setComputedProperties/variable/output.js diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/setComputedProperties/input.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/setComputedProperties/input.js new file mode 100644 index 000000000000..02d4195fa78d --- /dev/null +++ b/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/setComputedProperties/input.js @@ -0,0 +1,4 @@ +var obj = { + ["x" + foo]: "heh", + ["y" + bar]: "noo" +}; diff --git a/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/setComputedProperties/output.js b/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/setComputedProperties/output.js new file mode 100644 index 000000000000..13145e4a26f8 --- /dev/null +++ b/packages/babel-plugin-transform-computed-properties/test/fixtures/loose/setComputedProperties/output.js @@ -0,0 +1,3 @@ +var _obj; + +var obj = (_obj = {}, _obj["x" + foo] = "heh", _obj["y" + bar] = "noo", _obj); diff --git a/packages/babel-plugin-transform-destructuring/src/index.js b/packages/babel-plugin-transform-destructuring/src/index.js index cca55d21be77..d42c2bfc7a5d 100644 --- a/packages/babel-plugin-transform-destructuring/src/index.js +++ b/packages/babel-plugin-transform-destructuring/src/index.js @@ -4,17 +4,13 @@ import { types as t } from "@babel/core"; export default declare((api, options) => { api.assertVersion(7); - const { - loose = false, - useBuiltIns = false, - allowArrayLike = false, - } = options; - - if (typeof loose !== "boolean") { - throw new Error(`.loose must be a boolean or undefined`); - } + const { useBuiltIns = false } = options; - const arrayOnlySpread = loose; + const iterableIsArray = api.assumption("iterableIsArray") ?? options.loose; + const arrayLikeIsIterable = + options.allowArrayLike ?? api.assumption("arrayLikeIsIterable"); + const objectRestNoSymbols = + api.assumption("objectRestNoSymbols") ?? options.loose; function getExtendsHelper(file) { return useBuiltIns @@ -88,8 +84,8 @@ export default declare((api, options) => { this.nodes = opts.nodes || []; this.scope = opts.scope; this.kind = opts.kind; - this.arrayOnlySpread = opts.arrayOnlySpread; - this.allowArrayLike = opts.allowArrayLike; + this.iterableIsArray = opts.iterableIsArray; + this.arrayLikeIsIterable = opts.arrayLikeIsIterable; this.addHelper = opts.addHelper; } @@ -141,12 +137,12 @@ export default declare((api, options) => { toArray(node, count) { if ( - this.arrayOnlySpread || + this.iterableIsArray || (t.isIdentifier(node) && this.arrays[node.name]) ) { return node; } else { - return this.scope.toArray(node, count, this.allowArrayLike); + return this.scope.toArray(node, count, this.arrayLikeIsIterable); } } @@ -235,7 +231,9 @@ export default declare((api, options) => { } value = t.callExpression( - this.addHelper(`objectWithoutProperties${loose ? "Loose" : ""}`), + this.addHelper( + `objectWithoutProperties${objectRestNoSymbols ? "Loose" : ""}`, + ), [t.cloneNode(objRef), keyExpression], ); } @@ -527,8 +525,8 @@ export default declare((api, options) => { kind: left.kind, scope: scope, nodes: nodes, - arrayOnlySpread, - allowArrayLike, + iterableIsArray, + arrayLikeIsIterable, addHelper: name => this.addHelper(name), }); @@ -553,8 +551,8 @@ export default declare((api, options) => { kind: "let", scope: scope, nodes: nodes, - arrayOnlySpread, - allowArrayLike, + iterableIsArray, + arrayLikeIsIterable, addHelper: name => this.addHelper(name), }); destructuring.init(pattern, ref); @@ -572,8 +570,8 @@ export default declare((api, options) => { operator: node.operator, scope: scope, nodes: nodes, - arrayOnlySpread, - allowArrayLike, + iterableIsArray, + arrayLikeIsIterable, addHelper: name => this.addHelper(name), }); @@ -631,8 +629,8 @@ export default declare((api, options) => { nodes: nodes, scope: scope, kind: node.kind, - arrayOnlySpread, - allowArrayLike, + iterableIsArray, + arrayLikeIsIterable, addHelper: name => this.addHelper(name), }); diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/holes/exec.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/holes/exec.js new file mode 100644 index 000000000000..108b033a0cc7 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/holes/exec.js @@ -0,0 +1,6 @@ +var o = { 0: "a", 2: "c", length: 3 }; + +var [...rest] = o; + +expect(rest).toEqual(["a", undefined, "c"]); +expect(1 in rest).toBe(true); // Not holey diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/length-cropped/exec.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/length-cropped/exec.js new file mode 100644 index 000000000000..ec1b3fc7dfc3 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/length-cropped/exec.js @@ -0,0 +1,6 @@ +var o = { 0: "a", 1: "b", 2: "c", length: 2 }; + +var [first, ...rest] = o; + +expect(first).toBe("a"); +expect(rest).toEqual(["b"]); diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/options.json b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/options.json new file mode 100644 index 000000000000..c2eb7c339ded --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-destructuring" + ], + "assumptions": { + "arrayLikeIsIterable": true + } +} diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/simple/exec.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/simple/exec.js new file mode 100644 index 000000000000..8e71b1e45cfa --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/simple/exec.js @@ -0,0 +1,6 @@ +var o = { 0: "a", 1: "b", 2: "c", length: 3 }; + +var [first, ...rest] = o; + +expect(first).toBe("a"); +expect(rest).toEqual(["b", "c"]); diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/simple/input.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/simple/input.js new file mode 100644 index 000000000000..7d37e9622d78 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/simple/input.js @@ -0,0 +1 @@ +var [first, ...rest] = o; diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/simple/output.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/simple/output.js new file mode 100644 index 000000000000..50615d4e3e13 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-arrayLikeIsIterable/simple/output.js @@ -0,0 +1,4 @@ +var _o = o, + _o2 = babelHelpers.maybeArrayLike(babelHelpers.toArray, _o), + first = _o2[0], + rest = _o2.slice(1); diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/basic/input.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/basic/input.js new file mode 100644 index 000000000000..bc86d03f6d6b --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/basic/input.js @@ -0,0 +1 @@ +let [foo, bar] = baz; diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/basic/output.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/basic/output.js new file mode 100644 index 000000000000..c5b4279cf5fc --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/basic/output.js @@ -0,0 +1,3 @@ +let _baz = baz, + foo = _baz[0], + bar = _baz[1]; diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/for-in/input.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/for-in/input.js new file mode 100644 index 000000000000..f7a87fe3f876 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/for-in/input.js @@ -0,0 +1,7 @@ +for (var [name, value] in obj) { + print("Name: " + name + ", Value: " + value); +} + +for ([name, value] in obj) { + print("Name: " + name + ", Value: " + value); +} diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/for-in/output.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/for-in/output.js new file mode 100644 index 000000000000..de8d1198b549 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/for-in/output.js @@ -0,0 +1,11 @@ +for (var _ref in obj) { + var name = _ref[0]; + var value = _ref[1]; + print("Name: " + name + ", Value: " + value); +} + +for (var _ref2 in obj) { + name = _ref2[0]; + value = _ref2[1]; + print("Name: " + name + ", Value: " + value); +} diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/options.json b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/options.json new file mode 100644 index 000000000000..e08ab5b1c8f4 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-iterableIsArray/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-destructuring" + ], + "assumptions": { + "iterableIsArray": true + } +} diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/options.json b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/options.json new file mode 100644 index 000000000000..d48381a6db92 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0"}], + "transform-destructuring" + ], + "assumptions": { + "objectRestNoSymbols": true + } +} diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/input.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/input.js new file mode 100644 index 000000000000..f03be37640bc --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/input.js @@ -0,0 +1 @@ +({ a, b, ...c } = obj); diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/output.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/output.js new file mode 100644 index 000000000000..462fb0f56a31 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-assignment-expression/output.js @@ -0,0 +1,5 @@ +var _obj = obj; +a = _obj.a; +b = _obj.b; +c = babelHelpers.objectWithoutPropertiesLoose(_obj, ["a", "b"]); +_obj; diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-computed/input.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-computed/input.js new file mode 100644 index 000000000000..8ddf55177eac --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-computed/input.js @@ -0,0 +1 @@ +let { [a]: b, ...c } = obj; diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-computed/output.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-computed/output.js new file mode 100644 index 000000000000..3e00dda0fa08 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-computed/output.js @@ -0,0 +1,4 @@ +let _obj = obj, + _a = a, + b = _obj[_a], + c = babelHelpers.objectWithoutPropertiesLoose(_obj, [_a].map(babelHelpers.toPropertyKey)); diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-ignore-symbols/exec.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-ignore-symbols/exec.js new file mode 100644 index 000000000000..2c85a4c5711e --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-ignore-symbols/exec.js @@ -0,0 +1,7 @@ +let sym = Symbol(); + +let { a, ...r } = { a: 1, b: 2, [sym]: 3 }; + +expect(a).toBe(1); +expect(r.b).toBe(2); +expect(sym in r).toBe(false); diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-nested/input.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-nested/input.js new file mode 100644 index 000000000000..e1025ccc4cb9 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-nested/input.js @@ -0,0 +1 @@ +let { a, nested: { b, c, ...d }, e } = obj; diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-nested/output.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-nested/output.js new file mode 100644 index 000000000000..db6b37a3420f --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-nested/output.js @@ -0,0 +1,7 @@ +let _obj = obj, + a = _obj.a, + _obj$nested = _obj.nested, + b = _obj$nested.b, + c = _obj$nested.c, + d = babelHelpers.objectWithoutPropertiesLoose(_obj$nested, ["b", "c"]), + e = _obj.e; diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/input.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/input.js new file mode 100644 index 000000000000..099aa76e4907 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/input.js @@ -0,0 +1 @@ +var { a, b, ...c } = obj; diff --git a/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/output.js b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/output.js new file mode 100644 index 000000000000..96c7228e6297 --- /dev/null +++ b/packages/babel-plugin-transform-destructuring/test/fixtures/assumption-objectRestNoSymbols/rest-var-declaration/output.js @@ -0,0 +1,4 @@ +var _obj = obj, + a = _obj.a, + b = _obj.b, + c = babelHelpers.objectWithoutPropertiesLoose(_obj, ["a", "b"]); diff --git a/packages/babel-plugin-transform-for-of/src/index.js b/packages/babel-plugin-transform-for-of/src/index.js index 42b238aef076..882ff9b82baa 100644 --- a/packages/babel-plugin-transform-for-of/src/index.js +++ b/packages/babel-plugin-transform-for-of/src/index.js @@ -6,28 +6,48 @@ import transformWithoutHelper from "./no-helper-implementation"; export default declare((api, options) => { api.assertVersion(7); - const { loose, assumeArray, allowArrayLike } = options; + { + const { assumeArray, allowArrayLike, loose } = options; - if (loose === true && assumeArray === true) { - throw new Error( - `The loose and assumeArray options cannot be used together in @babel/plugin-transform-for-of`, - ); - } + if (loose === true && assumeArray === true) { + throw new Error( + `The loose and assumeArray options cannot be used together in @babel/plugin-transform-for-of`, + ); + } - if (assumeArray === true && allowArrayLike === true) { - throw new Error( - `The assumeArray and allowArrayLike options cannot be used together in @babel/plugin-transform-for-of`, - ); + if (assumeArray === true && allowArrayLike === true) { + throw new Error( + `The assumeArray and allowArrayLike options cannot be used together in @babel/plugin-transform-for-of`, + ); + } + + // TODO: Remove in Babel 8 + if (allowArrayLike && /^7\.\d\./.test(api.version)) { + throw new Error( + `The allowArrayLike is only supported when using @babel/core@^7.10.0`, + ); + } } - // TODO: Remove in Babel 8 - if (allowArrayLike && /^7\.\d\./.test(api.version)) { + const iterableIsArray = + options.assumeArray ?? + // Loose mode is not compatible with 'assumeArray', so we shouldn't read + // 'iterableIsArray' if 'loose' is true. + (!options.loose && api.assumption("iterableIsArray")); + + const arrayLikeIsIterable = + options.allowArrayLike ?? api.assumption("arrayLikeIsIterable"); + + const skipteratorClosing = + api.assumption("skipForOfIteratorClosing") ?? options.loose; + + if (iterableIsArray && arrayLikeIsIterable) { throw new Error( - `The allowArrayLike is only supported when using @babel/core@^7.10.0`, + `The "iterableIsArray" and "arrayLikeIsIterable" assumptions are not compatible.`, ); } - if (assumeArray) { + if (iterableIsArray) { return { name: "transform-for-of", @@ -94,17 +114,17 @@ export default declare((api, options) => { }; } - const buildForOfArray = template(` + const buildForOfArray = template` for (var KEY = 0, NAME = ARR; KEY < NAME.length; KEY++) BODY; - `); + `; - const buildForOfLoose = template.statements(` - for (var ITERATOR_HELPER = CREATE_ITERATOR_HELPER(OBJECT, ALLOW_ARRAY_LIKE), STEP_KEY; + const buildForOfNoIteratorClosing = template.statements` + for (var ITERATOR_HELPER = CREATE_ITERATOR_HELPER(OBJECT, ARRAY_LIKE_IS_ITERABLE), STEP_KEY; !(STEP_KEY = ITERATOR_HELPER()).done;) BODY; - `); + `; - const buildForOf = template.statements(` - var ITERATOR_HELPER = CREATE_ITERATOR_HELPER(OBJECT, ALLOW_ARRAY_LIKE), STEP_KEY; + const buildForOf = template.statements` + var ITERATOR_HELPER = CREATE_ITERATOR_HELPER(OBJECT, ARRAY_LIKE_IS_ITERABLE), STEP_KEY; try { for (ITERATOR_HELPER.s(); !(STEP_KEY = ITERATOR_HELPER.n()).done;) BODY; } catch (err) { @@ -112,11 +132,11 @@ export default declare((api, options) => { } finally { ITERATOR_HELPER.f(); } - `); + `; - const builder = loose + const builder = skipteratorClosing ? { - build: buildForOfLoose, + build: buildForOfNoIteratorClosing, helper: "createForOfIteratorHelperLoose", getContainer: nodes => nodes, } @@ -179,7 +199,7 @@ export default declare((api, options) => { if (!state.availableHelper(builder.helper)) { // Babel <7.9.0 doesn't support this helper - transformWithoutHelper(loose, path, state); + transformWithoutHelper(skipteratorClosing, path, state); return; } @@ -213,7 +233,9 @@ export default declare((api, options) => { const nodes = builder.build({ CREATE_ITERATOR_HELPER: state.addHelper(builder.helper), ITERATOR_HELPER: scope.generateUidIdentifier("iterator"), - ALLOW_ARRAY_LIKE: allowArrayLike ? t.booleanLiteral(true) : null, + ARRAY_LIKE_IS_ITERABLE: arrayLikeIsIterable + ? t.booleanLiteral(true) + : null, STEP_KEY: t.identifier(stepKey), OBJECT: node.right, BODY: node.body, diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/holes/exec.js b/packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/holes/exec.js similarity index 100% rename from packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/holes/exec.js rename to packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/holes/exec.js diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/holes/options.json b/packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/holes/options.json similarity index 100% rename from packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/holes/options.json rename to packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/holes/options.json diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/length-cropped/exec.js b/packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/length-cropped/exec.js similarity index 100% rename from packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/length-cropped/exec.js rename to packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/length-cropped/exec.js diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/length-cropped/options.json b/packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/length-cropped/options.json similarity index 100% rename from packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/length-cropped/options.json rename to packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/length-cropped/options.json diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/simple/exec.js b/packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/simple/exec.js similarity index 100% rename from packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/simple/exec.js rename to packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/simple/exec.js diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/simple/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/simple/input.js similarity index 100% rename from packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/simple/input.js rename to packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/simple/input.js diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/simple/options.json b/packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/simple/options.json similarity index 100% rename from packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/simple/options.json rename to packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/simple/options.json diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/simple/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/simple/output.js similarity index 100% rename from packages/babel-plugin-transform-for-of/test/fixtures/spec-allowArrayLike/simple/output.js rename to packages/babel-plugin-transform-for-of/test/fixtures/allowArrayLike/simple/output.js diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/holes/exec.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/holes/exec.js new file mode 100644 index 000000000000..4bd0a5df0097 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/holes/exec.js @@ -0,0 +1,7 @@ +var p2 = { 0: "a", 2: "c", length: 3 }; + +var arr = []; +for (var x of p2) arr.push(x); + +expect(arr).toEqual(["a", undefined, "c"]); +expect(1 in arr).toBe(true); // Not holey diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/length-cropped/exec.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/length-cropped/exec.js new file mode 100644 index 000000000000..16d81476a95e --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/length-cropped/exec.js @@ -0,0 +1,6 @@ +var p2 = { 0: "b", 1: "c", 2: "d", length: 2 }; + +var arr = []; +for (var x of p2) arr.push(x); + +expect(arr).toEqual(["b", "c"]); diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/options.json b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/options.json new file mode 100644 index 000000000000..34fc8ef005b1 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-for-of" + ], + "assumptions": { + "arrayLikeIsIterable": true + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/simple/exec.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/simple/exec.js new file mode 100644 index 000000000000..d016662a6048 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/simple/exec.js @@ -0,0 +1,6 @@ +var p2 = { 0: "b", 1: "c", 2: "d", length: 3 }; + +var arr = []; +for (var x of p2) arr.push(x); + +expect(arr).toEqual(["b", "c", "d"]); diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/simple/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/simple/input.js new file mode 100644 index 000000000000..9bcb06d816be --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/simple/input.js @@ -0,0 +1 @@ +for (var x of p2) arr.push(x); diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/simple/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/simple/output.js new file mode 100644 index 000000000000..9dbae0e22992 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-arrayLikeIsIterable/simple/output.js @@ -0,0 +1,13 @@ +var _iterator = babelHelpers.createForOfIteratorHelper(p2, true), + _step; + +try { + for (_iterator.s(); !(_step = _iterator.n()).done;) { + var x = _step.value; + arr.push(x); + } +} catch (err) { + _iterator.e(err); +} finally { + _iterator.f(); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-await-of/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-await-of/input.js new file mode 100644 index 000000000000..623d204b34cb --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-await-of/input.js @@ -0,0 +1 @@ +async () => { for await (let foo of []); }; diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-await-of/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-await-of/output.js new file mode 100644 index 000000000000..03379d55586f --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-await-of/output.js @@ -0,0 +1,3 @@ +async () => { + for await (let foo of []); +}; diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-array-pattern/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-array-pattern/input.js new file mode 100644 index 000000000000..8ffcd7ff809f --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-array-pattern/input.js @@ -0,0 +1,4 @@ +let elm; +for ([elm] of array) { + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-array-pattern/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-array-pattern/output.js new file mode 100644 index 000000000000..f405987d23e2 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-array-pattern/output.js @@ -0,0 +1,6 @@ +let elm; + +for (let _i = 0, _array = array; _i < _array.length; _i++) { + [elm] = _array[_i]; + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration-array-pattern/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration-array-pattern/input.js new file mode 100644 index 000000000000..2de13b3e47dd --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration-array-pattern/input.js @@ -0,0 +1,3 @@ +for (const [elm] of array) { + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration-array-pattern/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration-array-pattern/output.js new file mode 100644 index 000000000000..97fa884dc981 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration-array-pattern/output.js @@ -0,0 +1,4 @@ +for (let _i = 0, _array = array; _i < _array.length; _i++) { + const [elm] = _array[_i]; + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration/input.js new file mode 100644 index 000000000000..9f773dd63361 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration/input.js @@ -0,0 +1,3 @@ +for (const elm of array) { + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration/output.js new file mode 100644 index 000000000000..3794b43c998e --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-declaration/output.js @@ -0,0 +1,4 @@ +for (let _i = 0, _array = array; _i < _array.length; _i++) { + const elm = _array[_i]; + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression-declaration/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression-declaration/input.js new file mode 100644 index 000000000000..f47de4cad51b --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression-declaration/input.js @@ -0,0 +1 @@ +for (const i of items) i; diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression-declaration/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression-declaration/output.js new file mode 100644 index 000000000000..935f3004f555 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression-declaration/output.js @@ -0,0 +1,4 @@ +for (let _i = 0, _items = items; _i < _items.length; _i++) { + const i = _items[_i]; + i; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression/input.js new file mode 100644 index 000000000000..794f63b28034 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression/input.js @@ -0,0 +1,2 @@ +let i; +for (i of items) i; diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression/output.js new file mode 100644 index 000000000000..eef987e35c90 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-expression/output.js @@ -0,0 +1,6 @@ +let i; + +for (let _i = 0, _items = items; _i < _items.length; _i++) { + i = _items[_i]; + i; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-amd/input.mjs b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-amd/input.mjs new file mode 100644 index 000000000000..bd895e71c71f --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-amd/input.mjs @@ -0,0 +1,5 @@ +import { array } from "foo"; + +for (const elm of array) { + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-amd/options.json b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-amd/options.json new file mode 100644 index 000000000000..89a0601dc948 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-amd/options.json @@ -0,0 +1,11 @@ +{ + "plugins": [ + [ + "transform-for-of", + { + "assumeArray": true + } + ], + ["transform-modules-amd"] + ] +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-amd/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-amd/output.js new file mode 100644 index 000000000000..0e9d9e0152cb --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-amd/output.js @@ -0,0 +1,8 @@ +define(["foo"], function (_foo) { + "use strict"; + + for (let _i = 0; _i < _foo.array.length; _i++) { + const elm = _foo.array[_i]; + console.log(elm); + } +}); diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-commonjs/input.mjs b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-commonjs/input.mjs new file mode 100644 index 000000000000..bd895e71c71f --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-commonjs/input.mjs @@ -0,0 +1,5 @@ +import { array } from "foo"; + +for (const elm of array) { + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-commonjs/options.json b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-commonjs/options.json new file mode 100644 index 000000000000..855454080e78 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-commonjs/options.json @@ -0,0 +1,11 @@ +{ + "plugins": [ + [ + "transform-for-of", + { + "assumeArray": true + } + ], + ["transform-modules-commonjs"] + ] +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-commonjs/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-commonjs/output.js new file mode 100644 index 000000000000..9cf9ad09b782 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-commonjs/output.js @@ -0,0 +1,8 @@ +"use strict"; + +var _foo = require("foo"); + +for (let _i = 0; _i < _foo.array.length; _i++) { + const elm = _foo.array[_i]; + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-es2015/input.mjs b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-es2015/input.mjs new file mode 100644 index 000000000000..bd895e71c71f --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-es2015/input.mjs @@ -0,0 +1,5 @@ +import { array } from "foo"; + +for (const elm of array) { + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-es2015/output.mjs b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-es2015/output.mjs new file mode 100644 index 000000000000..62a2980913e6 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-import-es2015/output.mjs @@ -0,0 +1,6 @@ +import { array } from "foo"; + +for (let _i = 0; _i < array.length; _i++) { + const elm = array[_i]; + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-array-pattern/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-array-pattern/input.js new file mode 100644 index 000000000000..9c42dd07cf92 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-array-pattern/input.js @@ -0,0 +1,5 @@ +for (const [head, ...tail] of array) { + const head = 1; + console.log(tail); + console.log(head); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-array-pattern/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-array-pattern/output.js new file mode 100644 index 000000000000..d10f3cea1988 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-array-pattern/output.js @@ -0,0 +1,8 @@ +for (let _i = 0, _array = array; _i < _array.length; _i++) { + const [head, ...tail] = _array[_i]; + { + const head = 1; + console.log(tail); + console.log(head); + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-object-pattern/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-object-pattern/input.js new file mode 100644 index 000000000000..5d9d07cdff54 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-object-pattern/input.js @@ -0,0 +1,5 @@ +for (const [type, ...rest] of array) { + const type = 1; + console.log(rest); + console.log(type); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-object-pattern/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-object-pattern/output.js new file mode 100644 index 000000000000..bca1a961708b --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-partial-redeclaration-in-body-object-pattern/output.js @@ -0,0 +1,8 @@ +for (let _i = 0, _array = array; _i < _array.length; _i++) { + const [type, ...rest] = _array[_i]; + { + const type = 1; + console.log(rest); + console.log(type); + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-array-pattern/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-array-pattern/input.js new file mode 100644 index 000000000000..150e02bcd775 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-array-pattern/input.js @@ -0,0 +1,6 @@ +for (const [head, ...tail] of array) { + const head = 1; + let tail; + console.log(tail); + console.log(head); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-array-pattern/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-array-pattern/output.js new file mode 100644 index 000000000000..bb103233d714 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-array-pattern/output.js @@ -0,0 +1,9 @@ +for (let _i = 0, _array = array; _i < _array.length; _i++) { + const [head, ...tail] = _array[_i]; + { + const head = 1; + let tail; + console.log(tail); + console.log(head); + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-object-pattern/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-object-pattern/input.js new file mode 100644 index 000000000000..756ecda0da25 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-object-pattern/input.js @@ -0,0 +1,6 @@ +for (const {type, ...rest} of array) { + const type = 1; + let rest; + console.log(rest); + console.log(type); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-object-pattern/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-object-pattern/output.js new file mode 100644 index 000000000000..03a45647d69f --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body-object-pattern/output.js @@ -0,0 +1,12 @@ +for (let _i = 0, _array = array; _i < _array.length; _i++) { + const { + type, + ...rest + } = _array[_i]; + { + const type = 1; + let rest; + console.log(rest); + console.log(type); + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body/input.js new file mode 100644 index 000000000000..ded052290862 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body/input.js @@ -0,0 +1,3 @@ +for (const elm of array) { + const elm = 2; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body/output.js new file mode 100644 index 000000000000..f05d069d547d --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclaration-in-body/output.js @@ -0,0 +1,6 @@ +for (let _i = 0, _array = array; _i < _array.length; _i++) { + const elm = _array[_i]; + { + const elm = 2; + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclare-iterable/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclare-iterable/input.js new file mode 100644 index 000000000000..3abfab88f65b --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclare-iterable/input.js @@ -0,0 +1,3 @@ +for (let o of arr) { + const arr = o; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclare-iterable/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclare-iterable/output.js new file mode 100644 index 000000000000..81a8e0ef45fb --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-redeclare-iterable/output.js @@ -0,0 +1,4 @@ +for (let _i = 0, _arr = arr; _i < _arr.length; _i++) { + let o = _arr[_i]; + const arr = o; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static-declaration/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static-declaration/input.js new file mode 100644 index 000000000000..b84065c48dcf --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static-declaration/input.js @@ -0,0 +1,5 @@ +const array = []; + +for (const elm of array) { + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static-declaration/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static-declaration/output.js new file mode 100644 index 000000000000..072dd5498da1 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static-declaration/output.js @@ -0,0 +1,6 @@ +const array = []; + +for (let _i = 0; _i < array.length; _i++) { + const elm = array[_i]; + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static/input.js new file mode 100644 index 000000000000..d4de87d351dd --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static/input.js @@ -0,0 +1,6 @@ +const array = []; +let elm; + +for (elm of array) { + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static/output.js new file mode 100644 index 000000000000..fc47bc82edf3 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of-static/output.js @@ -0,0 +1,7 @@ +const array = []; +let elm; + +for (let _i = 0; _i < array.length; _i++) { + elm = array[_i]; + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of/input.js new file mode 100644 index 000000000000..4b77690e9e86 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of/input.js @@ -0,0 +1,5 @@ +let elm; + +for (elm of array) { + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of/output.js new file mode 100644 index 000000000000..1024f7a72773 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/for-of/output.js @@ -0,0 +1,6 @@ +let elm; + +for (let _i = 0, _array = array; _i < _array.length; _i++) { + elm = _array[_i]; + console.log(elm); +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/options.json b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/options.json new file mode 100644 index 000000000000..d1e759f09a9d --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-iterableIsArray/options.json @@ -0,0 +1,6 @@ +{ + "plugins": ["transform-for-of"], + "assumptions": { + "iterableIsArray": true + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/identifier/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/identifier/input.js new file mode 100644 index 000000000000..ddd15051ba40 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/identifier/input.js @@ -0,0 +1,3 @@ +for (i of arr) { + +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/identifier/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/identifier/output.js new file mode 100644 index 000000000000..09cfa4b62184 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/identifier/output.js @@ -0,0 +1,3 @@ +for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) { + i = _step.value; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/ignore-cases/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/ignore-cases/input.js new file mode 100644 index 000000000000..e79141052993 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/ignore-cases/input.js @@ -0,0 +1,6 @@ +for (var i of foo) { + switch (i) { + case 1: + break; + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/ignore-cases/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/ignore-cases/output.js new file mode 100644 index 000000000000..346e9bed2735 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/ignore-cases/output.js @@ -0,0 +1,8 @@ +for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(foo), _step; !(_step = _iterator()).done;) { + var i = _step.value; + + switch (i) { + case 1: + break; + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/let/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/let/input.js new file mode 100644 index 000000000000..f1e32392def1 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/let/input.js @@ -0,0 +1,3 @@ +for (let i of arr) { + +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/let/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/let/output.js new file mode 100644 index 000000000000..5181b1253590 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/let/output.js @@ -0,0 +1,3 @@ +for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) { + let i = _step.value; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/member-expression/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/member-expression/input.js new file mode 100644 index 000000000000..d67e03308150 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/member-expression/input.js @@ -0,0 +1,3 @@ +for (obj.prop of arr) { + +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/member-expression/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/member-expression/output.js new file mode 100644 index 000000000000..670a8f952d51 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/member-expression/output.js @@ -0,0 +1,3 @@ +for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) { + obj.prop = _step.value; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/multiple/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/multiple/input.js new file mode 100644 index 000000000000..d9c969b80951 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/multiple/input.js @@ -0,0 +1,7 @@ +for (var i of arr) { + +} + +for (var i of numbers) { + +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/multiple/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/multiple/output.js new file mode 100644 index 000000000000..adc55422e337 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/multiple/output.js @@ -0,0 +1,7 @@ +for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) { + var i = _step.value; +} + +for (var _iterator2 = babelHelpers.createForOfIteratorHelperLoose(numbers), _step2; !(_step2 = _iterator2()).done;) { + var i = _step2.value; +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/nested-label-for-of/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/nested-label-for-of/input.js new file mode 100644 index 000000000000..73c8203449d4 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/nested-label-for-of/input.js @@ -0,0 +1,5 @@ +b: for (let c of d()) { + for (let e of f()) { + continue b; + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/nested-label-for-of/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/nested-label-for-of/output.js new file mode 100644 index 000000000000..87e1ddec80f7 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/nested-label-for-of/output.js @@ -0,0 +1,8 @@ +b: for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(d()), _step; !(_step = _iterator()).done;) { + let c = _step.value; + + for (var _iterator2 = babelHelpers.createForOfIteratorHelperLoose(f()), _step2; !(_step2 = _iterator2()).done;) { + let e = _step2.value; + continue b; + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/options.json b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/options.json new file mode 100644 index 000000000000..77ffac99ff48 --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-for-of" + ], + "assumptions": { + "skipForOfIteratorClosing": true + } +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/var/input.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/var/input.js new file mode 100644 index 000000000000..48e5f59b2c6b --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/var/input.js @@ -0,0 +1,3 @@ +for (var i of arr) { + +} diff --git a/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/var/output.js b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/var/output.js new file mode 100644 index 000000000000..c9f297e237ab --- /dev/null +++ b/packages/babel-plugin-transform-for-of/test/fixtures/assumption-skipForOfIteratorClosing/var/output.js @@ -0,0 +1,3 @@ +for (var _iterator = babelHelpers.createForOfIteratorHelperLoose(arr), _step; !(_step = _iterator()).done;) { + var i = _step.value; +} diff --git a/packages/babel-plugin-transform-modules-amd/src/index.js b/packages/babel-plugin-transform-modules-amd/src/index.js index 7ea2b150f04b..9d916292d8df 100644 --- a/packages/babel-plugin-transform-modules-amd/src/index.js +++ b/packages/babel-plugin-transform-modules-amd/src/index.js @@ -38,7 +38,13 @@ function injectWrapper(path, wrapper) { export default declare((api, options) => { api.assertVersion(7); - const { loose, allowTopLevelThis, strict, strictMode, noInterop } = options; + const { allowTopLevelThis, strict, strictMode, noInterop } = options; + + const constantReexports = + api.assumption("constantReexports") ?? options.loose; + const enumerableModuleMeta = + api.assumption("enumerableModuleMeta") ?? options.loose; + return { name: "transform-modules-amd", @@ -103,7 +109,8 @@ export default declare((api, options) => { const { meta, headers } = rewriteModuleStatementsAndPrepareHeader( path, { - loose, + enumerableModuleMeta, + constantReexports, strict, strictMode, allowTopLevelThis, @@ -141,7 +148,11 @@ export default declare((api, options) => { } headers.push( - ...buildNamespaceInitStatements(meta, metadata, loose), + ...buildNamespaceInitStatements( + meta, + metadata, + constantReexports, + ), ); } diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-2/input.mjs b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-2/input.mjs new file mode 100644 index 000000000000..5be9a685aabd --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-2/input.mjs @@ -0,0 +1 @@ +export {foo as default} from "foo"; diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-2/output.js b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-2/output.js new file mode 100644 index 000000000000..c4d089259801 --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-2/output.js @@ -0,0 +1,9 @@ +define(["exports", "foo"], function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.default = void 0; + _exports.default = _foo.foo; +}); diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-3/input.mjs b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-3/input.mjs new file mode 100644 index 000000000000..4461d79e3bf3 --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-3/input.mjs @@ -0,0 +1 @@ +export {foo as default, bar} from "foo"; diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-3/output.js b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-3/output.js new file mode 100644 index 000000000000..0497fcd36acb --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-3/output.js @@ -0,0 +1,10 @@ +define(["exports", "foo"], function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.bar = _exports.default = void 0; + _exports.default = _foo.foo; + _exports.bar = _foo.bar; +}); diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-4/input.mjs b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-4/input.mjs new file mode 100644 index 000000000000..9fff903bd969 --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-4/input.mjs @@ -0,0 +1 @@ +export {foo as bar} from "foo"; diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-4/output.js b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-4/output.js new file mode 100644 index 000000000000..ee86c9ebeb3a --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-4/output.js @@ -0,0 +1,9 @@ +define(["exports", "foo"], function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.bar = void 0; + _exports.bar = _foo.foo; +}); diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-5/input.mjs b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-5/input.mjs new file mode 100644 index 000000000000..35c2762a2954 --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-5/input.mjs @@ -0,0 +1 @@ +export {foo, bar} from "foo"; diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-5/output.js b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-5/output.js new file mode 100644 index 000000000000..64d68cdbf862 --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-5/output.js @@ -0,0 +1,10 @@ +define(["exports", "foo"], function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.bar = _exports.foo = void 0; + _exports.foo = _foo.foo; + _exports.bar = _foo.bar; +}); diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-6/input.mjs b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-6/input.mjs new file mode 100644 index 000000000000..9ec8f63ab2fd --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-6/input.mjs @@ -0,0 +1 @@ +export * from "foo"; diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-6/output.js b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-6/output.js new file mode 100644 index 000000000000..e7988a807f00 --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from-6/output.js @@ -0,0 +1,12 @@ +define(["exports", "foo"], function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + Object.keys(_foo).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in _exports && _exports[key] === _foo[key]) return; + _exports[key] = _foo[key]; + }); +}); diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from/input.mjs b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from/input.mjs new file mode 100644 index 000000000000..83b7b67c51ce --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from/input.mjs @@ -0,0 +1 @@ +export {foo} from "foo"; diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from/output.js b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from/output.js new file mode 100644 index 000000000000..6fb67b7327a9 --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/export-from/output.js @@ -0,0 +1,9 @@ +define(["exports", "foo"], function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.foo = void 0; + _exports.foo = _foo.foo; +}); diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/import-export/input.mjs b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/import-export/input.mjs new file mode 100644 index 000000000000..b9e4c92265a4 --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/import-export/input.mjs @@ -0,0 +1,3 @@ +import { foo } from "./foo"; + +export { foo }; diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/import-export/output.js b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/import-export/output.js new file mode 100644 index 000000000000..4b3c1b13a220 --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/import-export/output.js @@ -0,0 +1,8 @@ +define(["exports", "./foo"], function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.foo = _foo.foo; +}); diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/options.json b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/options.json new file mode 100644 index 000000000000..6687fc23f80a --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-constantReexports/options.json @@ -0,0 +1,6 @@ +{ + "assumptions": { + "constantReexports": true + }, + "plugins": ["external-helpers", "transform-modules-amd"] +} diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-enumerableModuleMeta/export/input.mjs b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-enumerableModuleMeta/export/input.mjs new file mode 100644 index 000000000000..2263b5a27c28 --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-enumerableModuleMeta/export/input.mjs @@ -0,0 +1 @@ +export var foo = 2; diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-enumerableModuleMeta/export/output.js b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-enumerableModuleMeta/export/output.js new file mode 100644 index 000000000000..06ac96c4985d --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-enumerableModuleMeta/export/output.js @@ -0,0 +1,8 @@ +define(["exports"], function (_exports) { + "use strict"; + + _exports.__esModule = true; + _exports.foo = void 0; + var foo = 2; + _exports.foo = foo; +}); diff --git a/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-enumerableModuleMeta/options.json b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-enumerableModuleMeta/options.json new file mode 100644 index 000000000000..7f92d5a3c9ea --- /dev/null +++ b/packages/babel-plugin-transform-modules-amd/test/fixtures/assumption-enumerableModuleMeta/options.json @@ -0,0 +1,6 @@ +{ + "assumptions": { + "enumerableModuleMeta": true + }, + "plugins": ["external-helpers", "transform-modules-amd"] +} diff --git a/packages/babel-plugin-transform-modules-commonjs/src/index.js b/packages/babel-plugin-transform-modules-commonjs/src/index.js index de9274d890f7..0004c3c773bc 100644 --- a/packages/babel-plugin-transform-modules-commonjs/src/index.js +++ b/packages/babel-plugin-transform-modules-commonjs/src/index.js @@ -19,8 +19,6 @@ export default declare((api, options) => { const transformImportCall = createDynamicImportTransform(api); const { - loose, - // 'true' for non-mjs files to strictly have .default, instead of having // destructuring-like behavior for their properties. strictNamespace = false, @@ -37,6 +35,11 @@ export default declare((api, options) => { allowCommonJSExports = true, } = options; + const constantReexports = + api.assumption("constantReexports") ?? options.loose; + const enumerableModuleMeta = + api.assumption("enumerableModuleMeta") ?? options.loose; + if ( typeof lazy !== "boolean" && typeof lazy !== "function" && @@ -169,7 +172,8 @@ export default declare((api, options) => { path, { exportName: "exports", - loose, + constantReexports, + enumerableModuleMeta, strict, strictMode, allowTopLevelThis, @@ -215,7 +219,11 @@ export default declare((api, options) => { headers.push(header); headers.push( - ...buildNamespaceInitStatements(meta, metadata, loose), + ...buildNamespaceInitStatements( + meta, + metadata, + constantReexports, + ), ); } diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-2/input.mjs b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-2/input.mjs new file mode 100644 index 000000000000..5be9a685aabd --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-2/input.mjs @@ -0,0 +1 @@ +export {foo as default} from "foo"; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-2/output.js b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-2/output.js new file mode 100644 index 000000000000..efa99139e82e --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-2/output.js @@ -0,0 +1,10 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = void 0; + +var _foo = require("foo"); + +exports.default = _foo.foo; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-3/input.mjs b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-3/input.mjs new file mode 100644 index 000000000000..4461d79e3bf3 --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-3/input.mjs @@ -0,0 +1 @@ +export {foo as default, bar} from "foo"; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-3/output.js b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-3/output.js new file mode 100644 index 000000000000..aef9e075e34e --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-3/output.js @@ -0,0 +1,11 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.bar = exports.default = void 0; + +var _foo = require("foo"); + +exports.default = _foo.foo; +exports.bar = _foo.bar; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-4/input.mjs b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-4/input.mjs new file mode 100644 index 000000000000..9fff903bd969 --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-4/input.mjs @@ -0,0 +1 @@ +export {foo as bar} from "foo"; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-4/output.js b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-4/output.js new file mode 100644 index 000000000000..7c4b8590b769 --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-4/output.js @@ -0,0 +1,10 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.bar = void 0; + +var _foo = require("foo"); + +exports.bar = _foo.foo; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-5/input.mjs b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-5/input.mjs new file mode 100644 index 000000000000..35c2762a2954 --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-5/input.mjs @@ -0,0 +1 @@ +export {foo, bar} from "foo"; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-5/output.js b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-5/output.js new file mode 100644 index 000000000000..f9446e04700f --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-5/output.js @@ -0,0 +1,11 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.bar = exports.foo = void 0; + +var _foo = require("foo"); + +exports.foo = _foo.foo; +exports.bar = _foo.bar; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-6/input.mjs b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-6/input.mjs new file mode 100644 index 000000000000..9ec8f63ab2fd --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-6/input.mjs @@ -0,0 +1 @@ +export * from "foo"; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-6/output.js b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-6/output.js new file mode 100644 index 000000000000..8eba9a5ceeca --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from-6/output.js @@ -0,0 +1,13 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _foo = require("foo"); + +Object.keys(_foo).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in exports && exports[key] === _foo[key]) return; + exports[key] = _foo[key]; +}); diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from/input.mjs b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from/input.mjs new file mode 100644 index 000000000000..83b7b67c51ce --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from/input.mjs @@ -0,0 +1 @@ +export {foo} from "foo"; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from/output.js b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from/output.js new file mode 100644 index 000000000000..9902d90fc95f --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/export-from/output.js @@ -0,0 +1,10 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.foo = void 0; + +var _foo = require("foo"); + +exports.foo = _foo.foo; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/import-export/input.mjs b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/import-export/input.mjs new file mode 100644 index 000000000000..b9e4c92265a4 --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/import-export/input.mjs @@ -0,0 +1,3 @@ +import { foo } from "./foo"; + +export { foo }; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/import-export/output.js b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/import-export/output.js new file mode 100644 index 000000000000..8e12703582dc --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/import-export/output.js @@ -0,0 +1,9 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _foo = require("./foo"); + +exports.foo = _foo.foo; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/options.json b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/options.json new file mode 100644 index 000000000000..d795b6de6c28 --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-constantReexports/options.json @@ -0,0 +1,6 @@ +{ + "assumptions": { + "constantReexports": true + }, + "plugins": ["external-helpers", "transform-modules-commonjs"] +} diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-enumerableModuleMeta/export/input.mjs b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-enumerableModuleMeta/export/input.mjs new file mode 100644 index 000000000000..2263b5a27c28 --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-enumerableModuleMeta/export/input.mjs @@ -0,0 +1 @@ +export var foo = 2; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-enumerableModuleMeta/export/output.js b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-enumerableModuleMeta/export/output.js new file mode 100644 index 000000000000..5429b31f4ce8 --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-enumerableModuleMeta/export/output.js @@ -0,0 +1,6 @@ +"use strict"; + +exports.__esModule = true; +exports.foo = void 0; +var foo = 2; +exports.foo = foo; diff --git a/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-enumerableModuleMeta/options.json b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-enumerableModuleMeta/options.json new file mode 100644 index 000000000000..7b20177727bd --- /dev/null +++ b/packages/babel-plugin-transform-modules-commonjs/test/fixtures/assumption-enumerableModuleMeta/options.json @@ -0,0 +1,6 @@ +{ + "assumptions": { + "enumerableModuleMeta": true + }, + "plugins": ["external-helpers", "transform-modules-commonjs"] +} diff --git a/packages/babel-plugin-transform-modules-umd/src/index.js b/packages/babel-plugin-transform-modules-umd/src/index.js index 0f85d5f9a324..4b1d69b63bdd 100644 --- a/packages/babel-plugin-transform-modules-umd/src/index.js +++ b/packages/babel-plugin-transform-modules-umd/src/index.js @@ -44,13 +44,17 @@ export default declare((api, options) => { const { globals, exactGlobals, - loose, allowTopLevelThis, strict, strictMode, noInterop, } = options; + const constantReexports = + api.assumption("constantReexports") ?? options.loose; + const enumerableModuleMeta = + api.assumption("enumerableModuleMeta") ?? options.loose; + /** * Build the assignment statements that initialize the UMD global. */ @@ -147,7 +151,8 @@ export default declare((api, options) => { const { meta, headers } = rewriteModuleStatementsAndPrepareHeader( path, { - loose, + constantReexports, + enumerableModuleMeta, strict, strictMode, allowTopLevelThis, @@ -201,7 +206,11 @@ export default declare((api, options) => { } headers.push( - ...buildNamespaceInitStatements(meta, metadata, loose), + ...buildNamespaceInitStatements( + meta, + metadata, + constantReexports, + ), ); } diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-2/input.mjs b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-2/input.mjs new file mode 100644 index 000000000000..5be9a685aabd --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-2/input.mjs @@ -0,0 +1 @@ +export {foo as default} from "foo"; diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-2/output.js b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-2/output.js new file mode 100644 index 000000000000..88d339f99e7c --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-2/output.js @@ -0,0 +1,21 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["exports", "foo"], factory); + } else if (typeof exports !== "undefined") { + factory(exports, require("foo")); + } else { + var mod = { + exports: {} + }; + factory(mod.exports, global.foo); + global.input = mod.exports; + } +})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.default = void 0; + _exports.default = _foo.foo; +}); diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-3/input.mjs b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-3/input.mjs new file mode 100644 index 000000000000..4461d79e3bf3 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-3/input.mjs @@ -0,0 +1 @@ +export {foo as default, bar} from "foo"; diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-3/output.js b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-3/output.js new file mode 100644 index 000000000000..6a46f9585f99 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-3/output.js @@ -0,0 +1,22 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["exports", "foo"], factory); + } else if (typeof exports !== "undefined") { + factory(exports, require("foo")); + } else { + var mod = { + exports: {} + }; + factory(mod.exports, global.foo); + global.input = mod.exports; + } +})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.bar = _exports.default = void 0; + _exports.default = _foo.foo; + _exports.bar = _foo.bar; +}); diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-4/input.mjs b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-4/input.mjs new file mode 100644 index 000000000000..9fff903bd969 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-4/input.mjs @@ -0,0 +1 @@ +export {foo as bar} from "foo"; diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-4/output.js b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-4/output.js new file mode 100644 index 000000000000..de25f98ea8a6 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-4/output.js @@ -0,0 +1,21 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["exports", "foo"], factory); + } else if (typeof exports !== "undefined") { + factory(exports, require("foo")); + } else { + var mod = { + exports: {} + }; + factory(mod.exports, global.foo); + global.input = mod.exports; + } +})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.bar = void 0; + _exports.bar = _foo.foo; +}); diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-5/input.mjs b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-5/input.mjs new file mode 100644 index 000000000000..35c2762a2954 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-5/input.mjs @@ -0,0 +1 @@ +export {foo, bar} from "foo"; diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-5/output.js b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-5/output.js new file mode 100644 index 000000000000..ebcd9bd3ef61 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-5/output.js @@ -0,0 +1,22 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["exports", "foo"], factory); + } else if (typeof exports !== "undefined") { + factory(exports, require("foo")); + } else { + var mod = { + exports: {} + }; + factory(mod.exports, global.foo); + global.input = mod.exports; + } +})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.bar = _exports.foo = void 0; + _exports.foo = _foo.foo; + _exports.bar = _foo.bar; +}); diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-6/input.mjs b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-6/input.mjs new file mode 100644 index 000000000000..9ec8f63ab2fd --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-6/input.mjs @@ -0,0 +1 @@ +export * from "foo"; diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-6/output.js b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-6/output.js new file mode 100644 index 000000000000..2ce869023290 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from-6/output.js @@ -0,0 +1,24 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["exports", "foo"], factory); + } else if (typeof exports !== "undefined") { + factory(exports, require("foo")); + } else { + var mod = { + exports: {} + }; + factory(mod.exports, global.foo); + global.input = mod.exports; + } +})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + Object.keys(_foo).forEach(function (key) { + if (key === "default" || key === "__esModule") return; + if (key in _exports && _exports[key] === _foo[key]) return; + _exports[key] = _foo[key]; + }); +}); diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from/input.mjs b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from/input.mjs new file mode 100644 index 000000000000..83b7b67c51ce --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from/input.mjs @@ -0,0 +1 @@ +export {foo} from "foo"; diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from/output.js b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from/output.js new file mode 100644 index 000000000000..4e921805b159 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/export-from/output.js @@ -0,0 +1,21 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["exports", "foo"], factory); + } else if (typeof exports !== "undefined") { + factory(exports, require("foo")); + } else { + var mod = { + exports: {} + }; + factory(mod.exports, global.foo); + global.input = mod.exports; + } +})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.foo = void 0; + _exports.foo = _foo.foo; +}); diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/import-export/input.mjs b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/import-export/input.mjs new file mode 100644 index 000000000000..b9e4c92265a4 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/import-export/input.mjs @@ -0,0 +1,3 @@ +import { foo } from "./foo"; + +export { foo }; diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/import-export/output.js b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/import-export/output.js new file mode 100644 index 000000000000..b1b0636d9e00 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/import-export/output.js @@ -0,0 +1,20 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["exports", "./foo"], factory); + } else if (typeof exports !== "undefined") { + factory(exports, require("./foo")); + } else { + var mod = { + exports: {} + }; + factory(mod.exports, global.foo); + global.input = mod.exports; + } +})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports, _foo) { + "use strict"; + + Object.defineProperty(_exports, "__esModule", { + value: true + }); + _exports.foo = _foo.foo; +}); diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/options.json b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/options.json new file mode 100644 index 000000000000..1a3f6d1a0d60 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-constantReexports/options.json @@ -0,0 +1,6 @@ +{ + "assumptions": { + "constantReexports": true + }, + "plugins": ["external-helpers", "transform-modules-umd"] +} diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-enumerableModuleMeta/export/input.mjs b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-enumerableModuleMeta/export/input.mjs new file mode 100644 index 000000000000..2263b5a27c28 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-enumerableModuleMeta/export/input.mjs @@ -0,0 +1 @@ +export var foo = 2; diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-enumerableModuleMeta/export/output.js b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-enumerableModuleMeta/export/output.js new file mode 100644 index 000000000000..e80e1fe59ee3 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-enumerableModuleMeta/export/output.js @@ -0,0 +1,20 @@ +(function (global, factory) { + if (typeof define === "function" && define.amd) { + define(["exports"], factory); + } else if (typeof exports !== "undefined") { + factory(exports); + } else { + var mod = { + exports: {} + }; + factory(mod.exports); + global.input = mod.exports; + } +})(typeof globalThis !== "undefined" ? globalThis : typeof self !== "undefined" ? self : this, function (_exports) { + "use strict"; + + _exports.__esModule = true; + _exports.foo = void 0; + var foo = 2; + _exports.foo = foo; +}); diff --git a/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-enumerableModuleMeta/options.json b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-enumerableModuleMeta/options.json new file mode 100644 index 000000000000..56bfa8f269a6 --- /dev/null +++ b/packages/babel-plugin-transform-modules-umd/test/fixtures/assumption-enumerableModuleMeta/options.json @@ -0,0 +1,6 @@ +{ + "assumptions": { + "enumerableModuleMeta": true + }, + "plugins": ["external-helpers", "transform-modules-umd"] +} diff --git a/packages/babel-plugin-transform-parameters/src/index.js b/packages/babel-plugin-transform-parameters/src/index.js index 1f5cb7184b04..69d2ce512f15 100644 --- a/packages/babel-plugin-transform-parameters/src/index.js +++ b/packages/babel-plugin-transform-parameters/src/index.js @@ -6,7 +6,10 @@ export { convertFunctionParams }; export default declare((api, options) => { api.assertVersion(7); - const { loose } = options; + const ignoreFunctionLength = + api.assumption("ignoreFunctionLength") ?? options.loose; + const noNewArrows = api.assumption("noNewArrows"); + return { name: "transform-parameters", @@ -19,11 +22,14 @@ export default declare((api, options) => { .some(param => param.isRestElement() || param.isAssignmentPattern()) ) { // default/rest visitors require access to `arguments`, so it cannot be an arrow - path.arrowFunctionToExpression(); + path.arrowFunctionToExpression({ noNewArrows }); } const convertedRest = convertFunctionRest(path); - const convertedParams = convertFunctionParams(path, loose); + const convertedParams = convertFunctionParams( + path, + ignoreFunctionLength, + ); if (convertedRest || convertedParams) { // Manually reprocess this scope to ensure that the moved params are updated. diff --git a/packages/babel-plugin-transform-parameters/src/params.js b/packages/babel-plugin-transform-parameters/src/params.js index 4608a225af45..335a8e884241 100644 --- a/packages/babel-plugin-transform-parameters/src/params.js +++ b/packages/babel-plugin-transform-parameters/src/params.js @@ -44,7 +44,7 @@ const iifeVisitor = { // last 2 parameters are optional -- they are used by proposal-object-rest-spread/src/index.js export default function convertFunctionParams( path, - loose, + ignoreFunctionLength, shouldTransformParam, replaceRestElement, ) { @@ -123,7 +123,10 @@ export default function convertFunctionParams( } const paramIsAssignmentPattern = param.isAssignmentPattern(); - if (paramIsAssignmentPattern && (loose || node.kind === "set")) { + if ( + paramIsAssignmentPattern && + (ignoreFunctionLength || node.kind === "set") + ) { const left = param.get("left"); const right = param.get("right"); @@ -203,6 +206,8 @@ export default function convertFunctionParams( // sure that we correctly handle this and arguments. const bodyPath = path.get("body.body"); const arrowPath = bodyPath[bodyPath.length - 1].get("argument.callee"); + + // This is an IIFE, so we don't need to worry about the noNewArrows assumption arrowPath.arrowFunctionToExpression(); arrowPath.node.generator = path.node.generator; diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/complex-assignment/input.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/complex-assignment/input.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/complex-assignment/input.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/complex-assignment/input.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/complex-assignment/output.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/complex-assignment/output.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/complex-assignment/output.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/complex-assignment/output.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-array-destructuring/exec.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-array-destructuring/exec.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-array-destructuring/exec.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-array-destructuring/exec.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-array-destructuring/input.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-array-destructuring/input.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-array-destructuring/input.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-array-destructuring/input.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-array-destructuring/output.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-array-destructuring/output.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-array-destructuring/output.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-array-destructuring/output.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-assignment-with-types/input.mjs b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-assignment-with-types/input.mjs similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-assignment-with-types/input.mjs rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-assignment-with-types/input.mjs diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-assignment-with-types/options.json b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-assignment-with-types/options.json similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-assignment-with-types/options.json rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-assignment-with-types/options.json diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-assignment-with-types/output.mjs b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-assignment-with-types/output.mjs similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-assignment-with-types/output.mjs rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-assignment-with-types/output.mjs diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-earlier-params/exec.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-earlier-params/exec.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-earlier-params/exec.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-earlier-params/exec.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-iife-1128/exec.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-iife-1128/exec.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-iife-1128/exec.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-iife-1128/exec.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-iife-4253/exec.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-iife-4253/exec.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-iife-4253/exec.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-iife-4253/exec.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-iife-self/exec.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-iife-self/exec.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-iife-self/exec.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-iife-self/exec.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-multiple/input.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-multiple/input.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-multiple/input.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-multiple/input.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-multiple/output.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-multiple/output.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-multiple/output.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-multiple/output.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-object-destructuring/exec.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-object-destructuring/exec.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-object-destructuring/exec.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-object-destructuring/exec.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-rest-mix/input.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-rest-mix/input.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-rest-mix/input.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-rest-mix/input.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-rest-mix/output.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-rest-mix/output.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-rest-mix/output.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-rest-mix/output.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-rest/exec.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-rest/exec.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-rest/exec.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-rest/exec.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-single/input.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-single/input.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-single/input.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-single/input.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-single/output.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-single/output.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/default-single/output.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/default-single/output.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/destructuring-rest/input.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/destructuring-rest/input.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/destructuring-rest/input.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/destructuring-rest/input.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/destructuring-rest/output.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/destructuring-rest/output.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/destructuring-rest/output.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/destructuring-rest/output.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/options.json b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/options.json similarity index 62% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/options.json rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/options.json index aa8f6cf317dd..f8c2c7a9fafe 100644 --- a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/options.json +++ b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/options.json @@ -3,12 +3,14 @@ "proposal-class-properties", "external-helpers", "syntax-flow", - ["transform-parameters", { "loose": true }], + "transform-parameters", "transform-block-scoping", "transform-spread", "transform-classes", "transform-destructuring", - "transform-arrow-functions", - "transform-for-of" - ] + "transform-arrow-functions" + ], + "assumptions": { + "ignoreFunctionLength": true + } } diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/overwrite-undefined/exec.js b/packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/overwrite-undefined/exec.js similarity index 100% rename from packages/babel-plugin-transform-parameters/test/fixtures/use-loose-option/overwrite-undefined/exec.js rename to packages/babel-plugin-transform-parameters/test/fixtures/assumption-ignoreFunctionLength/overwrite-undefined/exec.js diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/loose/ignoreFunctionLength/input.js b/packages/babel-plugin-transform-parameters/test/fixtures/loose/ignoreFunctionLength/input.js new file mode 100644 index 000000000000..b91cfb244914 --- /dev/null +++ b/packages/babel-plugin-transform-parameters/test/fixtures/loose/ignoreFunctionLength/input.js @@ -0,0 +1,3 @@ +function fn(a, b = c()) { + return b; +} diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/loose/ignoreFunctionLength/output.js b/packages/babel-plugin-transform-parameters/test/fixtures/loose/ignoreFunctionLength/output.js new file mode 100644 index 000000000000..6c1471d59a4f --- /dev/null +++ b/packages/babel-plugin-transform-parameters/test/fixtures/loose/ignoreFunctionLength/output.js @@ -0,0 +1,7 @@ +function fn(a, b) { + if (b === void 0) { + b = c(); + } + + return b; +} diff --git a/packages/babel-plugin-transform-parameters/test/fixtures/loose/options.json b/packages/babel-plugin-transform-parameters/test/fixtures/loose/options.json new file mode 100644 index 000000000000..0d49296cfac0 --- /dev/null +++ b/packages/babel-plugin-transform-parameters/test/fixtures/loose/options.json @@ -0,0 +1,5 @@ +{ + "plugins": [ + ["transform-parameters", { "loose": true }] + ] +} diff --git a/packages/babel-plugin-transform-spread/src/index.js b/packages/babel-plugin-transform-spread/src/index.js index 3bacc1f677fc..f6559cfccd8c 100644 --- a/packages/babel-plugin-transform-spread/src/index.js +++ b/packages/babel-plugin-transform-spread/src/index.js @@ -5,13 +5,18 @@ import { types as t } from "@babel/core"; export default declare((api, options) => { api.assertVersion(7); - const { loose, allowArrayLike } = options; + const iterableIsArray = api.assumption("iterableIsArray") ?? options.loose; + const arrayLikeIsIterable = + options.allowArrayLike ?? api.assumption("arrayLikeIsIterable"); function getSpreadLiteral(spread, scope) { - if (loose && !t.isIdentifier(spread.argument, { name: "arguments" })) { + if ( + iterableIsArray && + !t.isIdentifier(spread.argument, { name: "arguments" }) + ) { return spread.argument; } else { - return scope.toArray(spread.argument, true, allowArrayLike); + return scope.toArray(spread.argument, true, arrayLikeIsIterable); } } diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/holes/exec.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/holes/exec.js new file mode 100644 index 000000000000..c5f809fae86f --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/holes/exec.js @@ -0,0 +1,6 @@ +var p2 = { 0: "a", 2: "c", length: 3 }; + +var arr = [...p2, "d"]; + +expect(arr).toEqual(["a", undefined, "c", "d"]); +expect(1 in arr).toBe(true); // Not holey diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/length-cropped/exec.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/length-cropped/exec.js new file mode 100644 index 000000000000..dbb1602da453 --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/length-cropped/exec.js @@ -0,0 +1,5 @@ +var p2 = { 0: "b", 1: "c", 2: "d", length: 2 }; + +var arr = ["a", ...p2, "e"]; + +expect(arr).toEqual(["a", "b", "c", "e"]); diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/options.json b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/options.json new file mode 100644 index 000000000000..966d179d1685 --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/options.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + ["external-helpers", { "helperVersion": "7.100.0" }], + "transform-spread" + ], + "assumptions": { + "arrayLikeIsIterable": true + } +} diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/simple/exec.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/simple/exec.js new file mode 100644 index 000000000000..786324084b00 --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/simple/exec.js @@ -0,0 +1,5 @@ +var p2 = { 0: "b", 1: "c", 2: "d", length: 3 }; + +var arr = ["a", ...p2, "e"]; + +expect(arr).toEqual(["a", "b", "c", "d", "e"]); diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/simple/input.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/simple/input.js new file mode 100644 index 000000000000..266012c540ec --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/simple/input.js @@ -0,0 +1 @@ +var arr = ["a", ...p2, "e"]; diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/simple/output.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/simple/output.js new file mode 100644 index 000000000000..caa46f72da3c --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-arrayLikeIsIterable/simple/output.js @@ -0,0 +1 @@ +var arr = ["a"].concat(babelHelpers.maybeArrayLike(babelHelpers.toConsumableArray, p2), ["e"]); diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/arguments/input.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/arguments/input.js new file mode 100644 index 000000000000..55bba0661b94 --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/arguments/input.js @@ -0,0 +1,5 @@ +function foo() { + // We know for sure that 'arguments' is _not_ an array, so we + // can ignore the assumption in this case. + return [...arguments]; +} diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/arguments/output.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/arguments/output.js new file mode 100644 index 000000000000..8261a6054ace --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/arguments/output.js @@ -0,0 +1,5 @@ +function foo() { + // We know for sure that 'arguments' is _not_ an array, so we + // can ignore the assumption in this case. + return Array.prototype.slice.call(arguments); +} diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/array-literals/input.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/array-literals/input.js new file mode 100644 index 000000000000..5ebb80da6607 --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/array-literals/input.js @@ -0,0 +1 @@ +var lyrics = ["head", "and", "toes", ...parts]; diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/array-literals/output.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/array-literals/output.js new file mode 100644 index 000000000000..ff599f4229aa --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/array-literals/output.js @@ -0,0 +1 @@ +var lyrics = ["head", "and", "toes"].concat(parts); diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/function-call/input.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/function-call/input.js new file mode 100644 index 000000000000..01f9b028cc5e --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/function-call/input.js @@ -0,0 +1 @@ +lyrics(["head", "and", "toes", ...parts]); diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/function-call/output.js b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/function-call/output.js new file mode 100644 index 000000000000..f069f8d6db57 --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/function-call/output.js @@ -0,0 +1 @@ +lyrics(["head", "and", "toes"].concat(parts)); diff --git a/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/options.json b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/options.json new file mode 100644 index 000000000000..992778aa569d --- /dev/null +++ b/packages/babel-plugin-transform-spread/test/fixtures/assumption-iterableIsArray/options.json @@ -0,0 +1,6 @@ +{ + "plugins": ["external-helpers", "transform-spread"], + "assumptions": { + "iterableIsArray": true + } +} diff --git a/packages/babel-plugin-transform-template-literals/src/index.js b/packages/babel-plugin-transform-template-literals/src/index.js index d1f1689103df..5b588900d33e 100644 --- a/packages/babel-plugin-transform-template-literals/src/index.js +++ b/packages/babel-plugin-transform-template-literals/src/index.js @@ -3,10 +3,14 @@ import { template, types as t } from "@babel/core"; export default declare((api, options) => { api.assertVersion(7); - const { loose } = options; + + const ignoreToPrimitiveHint = + api.assumption("ignoreToPrimitiveHint") ?? options.loose; + const mutableTemplateObject = + api.assumption("mutableTemplateObject") ?? options.loose; let helperName = "taggedTemplateLiteral"; - if (loose) helperName += "Loose"; + if (mutableTemplateObject) helperName += "Loose"; /** * This function groups the objects into multiple calls to `.concat()` in @@ -115,13 +119,15 @@ export default declare((api, options) => { // since `+` is left-to-right associative // ensure the first node is a string if first/second isn't - const considerSecondNode = !loose || !t.isStringLiteral(nodes[1]); - if (!t.isStringLiteral(nodes[0]) && considerSecondNode) { + if ( + !t.isStringLiteral(nodes[0]) && + !(ignoreToPrimitiveHint && t.isStringLiteral(nodes[1])) + ) { nodes.unshift(t.stringLiteral("")); } let root = nodes[0]; - if (loose) { + if (ignoreToPrimitiveHint) { for (let i = 1; i < nodes.length; i++) { root = t.binaryExpression("+", root, nodes[i]); } diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/escape-quotes/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/escape-quotes/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/escape-quotes/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/escape-quotes/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/escape-quotes/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/escape-quotes/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/escape-quotes/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/escape-quotes/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/expression-first/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/expression-first/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/expression-first/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/expression-first/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/expression-first/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/expression-first/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/expression-first/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/expression-first/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/functions/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/functions/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/functions/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/functions/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/functions/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/functions/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/functions/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/functions/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/literals/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/literals/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/literals/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/literals/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/literals/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/literals/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/literals/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/literals/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/multiline/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/multiline/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/multiline/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/multiline/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/multiline/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/multiline/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/multiline/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/multiline/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/multiple/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/multiple/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/multiple/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/multiple/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/multiple/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/multiple/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/multiple/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/multiple/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/none/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/none/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/none/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/none/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/none/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/none/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/none/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/none/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/only/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/only/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/only/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/only/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/only/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/only/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/only/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/only/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/options.json b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/options.json new file mode 100644 index 000000000000..e9058d39d544 --- /dev/null +++ b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/options.json @@ -0,0 +1,6 @@ +{ + "plugins": ["transform-template-literals"], + "assumptions": { + "ignoreToPrimitiveHint": true + } +} diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/order/exec.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/order/exec.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/order/exec.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/order/exec.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/order/options.json b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/order/options.json similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/order/options.json rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/order/options.json diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/order2/exec.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/order2/exec.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/order2/exec.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/order2/exec.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/order2/options.json b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/order2/options.json similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/order2/options.json rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/order2/options.json diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/single/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/single/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/single/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/single/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/single/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/single/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/single/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/single/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/statement/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/statement/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/statement/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/statement/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/statement/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/statement/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/statement/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/statement/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/symbol/exec.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/symbol/exec.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/symbol/exec.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/symbol/exec.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/tag/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/tag/input.js new file mode 100644 index 000000000000..79f996661e4b --- /dev/null +++ b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/tag/input.js @@ -0,0 +1 @@ +tag`foo ${bar} baz`; diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/tag/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/tag/output.js new file mode 100644 index 000000000000..d2bd91618a71 --- /dev/null +++ b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-ignoreToPrimitiveHint/tag/output.js @@ -0,0 +1,5 @@ +var _templateObject; + +function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); } + +tag(_templateObject || (_templateObject = _taggedTemplateLiteral(["foo ", " baz"])), bar); diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/no-tag/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/no-tag/input.js new file mode 100644 index 000000000000..05ead3e65df5 --- /dev/null +++ b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/no-tag/input.js @@ -0,0 +1 @@ +`foo ${bar} baz`; diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/no-tag/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/no-tag/output.js new file mode 100644 index 000000000000..2328f9dfa655 --- /dev/null +++ b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/no-tag/output.js @@ -0,0 +1 @@ +"foo ".concat(bar, " baz"); diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/options.json b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/options.json new file mode 100644 index 000000000000..29cf2ac88867 --- /dev/null +++ b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/options.json @@ -0,0 +1,6 @@ +{ + "plugins": ["transform-template-literals"], + "assumptions": { + "mutableTemplateObject": true + } +} diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/tag/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/tag/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/tag/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/tag/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/tag/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/tag/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/tag/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/tag/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/template-revision/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/template-revision/input.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/template-revision/input.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/template-revision/input.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/template-revision/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/template-revision/output.js similarity index 100% rename from packages/babel-plugin-transform-template-literals/test/fixtures/loose/template-revision/output.js rename to packages/babel-plugin-transform-template-literals/test/fixtures/assumption-mutableTemplateObject/template-revision/output.js diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/ignoreToPrimitiveHint/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/loose/ignoreToPrimitiveHint/input.js new file mode 100644 index 000000000000..98413bcfcede --- /dev/null +++ b/packages/babel-plugin-transform-template-literals/test/fixtures/loose/ignoreToPrimitiveHint/input.js @@ -0,0 +1 @@ +var o = `foo ${bar} baz`; diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/ignoreToPrimitiveHint/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/loose/ignoreToPrimitiveHint/output.js new file mode 100644 index 000000000000..f0a7277e17f4 --- /dev/null +++ b/packages/babel-plugin-transform-template-literals/test/fixtures/loose/ignoreToPrimitiveHint/output.js @@ -0,0 +1 @@ +var o = "foo " + bar + " baz"; diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/mutableTemplateObject/input.js b/packages/babel-plugin-transform-template-literals/test/fixtures/loose/mutableTemplateObject/input.js new file mode 100644 index 000000000000..8b87c3fe9f4d --- /dev/null +++ b/packages/babel-plugin-transform-template-literals/test/fixtures/loose/mutableTemplateObject/input.js @@ -0,0 +1 @@ +var o = tag`foo ${bar} baz`; diff --git a/packages/babel-plugin-transform-template-literals/test/fixtures/loose/mutableTemplateObject/output.js b/packages/babel-plugin-transform-template-literals/test/fixtures/loose/mutableTemplateObject/output.js new file mode 100644 index 000000000000..195dbdc46430 --- /dev/null +++ b/packages/babel-plugin-transform-template-literals/test/fixtures/loose/mutableTemplateObject/output.js @@ -0,0 +1,5 @@ +var _templateObject; + +function _taggedTemplateLiteralLoose(strings, raw) { if (!raw) { raw = strings.slice(0); } strings.raw = raw; return strings; } + +var o = tag(_templateObject || (_templateObject = _taggedTemplateLiteralLoose(["foo ", " baz"])), bar); diff --git a/packages/babel-preset-env/src/index.js b/packages/babel-preset-env/src/index.js index 90384f6103a1..68b0428fe213 100644 --- a/packages/babel-preset-env/src/index.js +++ b/packages/babel-preset-env/src/index.js @@ -206,6 +206,26 @@ export const getPolyfillPlugins = ({ return polyfillPlugins; }; +function getLocalTargets( + optionsTargets, + ignoreBrowserslistConfig, + configPath, + browserslistEnv, +) { + if (optionsTargets?.esmodules && optionsTargets.browsers) { + console.warn(` +@babel/preset-env: esmodules and browsers targets have been specified together. +\`browsers\` target, \`${optionsTargets.browsers.toString()}\` will be ignored. +`); + } + + return getTargets( + // $FlowIgnore optionsTargets doesn't have an "uglify" property anymore + (optionsTargets: InputTargets), + { ignoreBrowserslistConfig, configPath, browserslistEnv }, + ); +} + function supportsStaticESM(caller) { return !!caller?.supportsStaticESM; } @@ -225,6 +245,8 @@ function supportsTopLevelAwait(caller) { export default declare((api, opts) => { api.assertVersion(7); + const babelTargets = api.targets(); + const { bugfixes, configPath, @@ -243,36 +265,39 @@ export default declare((api, opts) => { browserslistEnv, } = normalizeOptions(opts); - if (!process.env.BABEL_8_BREAKING) { - // eslint-disable-next-line no-var - var hasUglifyTarget = false; - - if (optionsTargets?.uglify) { - hasUglifyTarget = true; - delete optionsTargets.uglify; - - console.warn(` + let targets = babelTargets; + + if ( + // If any browserslist-related option is specified, fallback to the old + // behavior of not using the targets specified in the top-level options. + opts.targets || + opts.configPath || + opts.browserslistEnv || + opts.ignoreBrowserslistConfig + ) { + if (!process.env.BABEL_8_BREAKING) { + // eslint-disable-next-line no-var + var hasUglifyTarget = false; + + if (optionsTargets?.uglify) { + hasUglifyTarget = true; + delete optionsTargets.uglify; + + console.warn(` The uglify target has been deprecated. Set the top level option \`forceAllTransforms: true\` instead. `); + } } - } - if (optionsTargets?.esmodules && optionsTargets.browsers) { - console.warn(` -@babel/preset-env: esmodules and browsers targets have been specified together. -\`browsers\` target, \`${optionsTargets.browsers.toString()}\` will be ignored. -`); + targets = getLocalTargets( + optionsTargets, + ignoreBrowserslistConfig, + configPath, + browserslistEnv, + ); } - const targets = getTargets( - // $FlowIgnore optionsTargets doesn't have an "uglify" property anymore - (optionsTargets: InputTargets), - { ignoreBrowserslistConfig, configPath, browserslistEnv }, - ); - const include = transformIncludesAndExcludes(optionsInclude); - const exclude = transformIncludesAndExcludes(optionsExclude); - const transformTargets = ( process.env.BABEL_8_BREAKING ? forceAllTransforms @@ -281,6 +306,9 @@ option \`forceAllTransforms: true\` instead. ? {} : targets; + const include = transformIncludesAndExcludes(optionsInclude); + const exclude = transformIncludesAndExcludes(optionsExclude); + const compatData = getPluginList(shippedProposals, bugfixes); const shouldSkipExportNamespaceFrom = (modules === "auto" && api.caller?.(supportsExportNamespaceFrom)) || diff --git a/packages/babel-preset-env/src/normalize-options.js b/packages/babel-preset-env/src/normalize-options.js index 1f1086ab572b..332e38de5ee3 100644 --- a/packages/babel-preset-env/src/normalize-options.js +++ b/packages/babel-preset-env/src/normalize-options.js @@ -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, diff --git a/packages/babel-preset-env/test/fixtures/debug/top-level-targets-shadowed/input.mjs b/packages/babel-preset-env/test/fixtures/debug/top-level-targets-shadowed/input.mjs new file mode 100644 index 000000000000..fbb8052d71ab --- /dev/null +++ b/packages/babel-preset-env/test/fixtures/debug/top-level-targets-shadowed/input.mjs @@ -0,0 +1 @@ +foo?.bar; diff --git a/packages/babel-preset-env/test/fixtures/debug/top-level-targets-shadowed/options.json b/packages/babel-preset-env/test/fixtures/debug/top-level-targets-shadowed/options.json new file mode 100644 index 000000000000..bd767ffbae7b --- /dev/null +++ b/packages/babel-preset-env/test/fixtures/debug/top-level-targets-shadowed/options.json @@ -0,0 +1,8 @@ +{ + "validateLogs": true, + "ignoreOutput": true, + "targets": "chrome 80", + "presets": [ + ["env", { "debug": true, "targets": "chrome 60" }] + ] +} diff --git a/packages/babel-preset-env/test/fixtures/debug/top-level-targets-shadowed/stdout.txt b/packages/babel-preset-env/test/fixtures/debug/top-level-targets-shadowed/stdout.txt new file mode 100644 index 000000000000..2548b104e672 --- /dev/null +++ b/packages/babel-preset-env/test/fixtures/debug/top-level-targets-shadowed/stdout.txt @@ -0,0 +1,26 @@ +@babel/preset-env: `DEBUG` option + +Using targets: +{ + "chrome": "60" +} + +Using modules transform: auto + +Using plugins: + proposal-numeric-separator { "chrome":"60" } + proposal-logical-assignment-operators { "chrome":"60" } + proposal-nullish-coalescing-operator { "chrome":"60" } + proposal-optional-chaining { "chrome":"60" } + proposal-json-strings { "chrome":"60" } + proposal-optional-catch-binding { "chrome":"60" } + proposal-async-generator-functions { "chrome":"60" } + syntax-object-rest-spread { "chrome":"60" } + transform-dotall-regex { "chrome":"60" } + proposal-unicode-property-regex { "chrome":"60" } + transform-named-capturing-groups-regex { "chrome":"60" } + proposal-export-namespace-from { "chrome":"60" } + transform-modules-commonjs { "chrome":"60" } + proposal-dynamic-import { "chrome":"60" } + +Using polyfills: No polyfills were added, since the `useBuiltIns` option was not set. diff --git a/packages/babel-preset-env/test/fixtures/debug/top-level-targets/input.mjs b/packages/babel-preset-env/test/fixtures/debug/top-level-targets/input.mjs new file mode 100644 index 000000000000..fbb8052d71ab --- /dev/null +++ b/packages/babel-preset-env/test/fixtures/debug/top-level-targets/input.mjs @@ -0,0 +1 @@ +foo?.bar; diff --git a/packages/babel-preset-env/test/fixtures/debug/top-level-targets/options.json b/packages/babel-preset-env/test/fixtures/debug/top-level-targets/options.json new file mode 100644 index 000000000000..dbc78d327863 --- /dev/null +++ b/packages/babel-preset-env/test/fixtures/debug/top-level-targets/options.json @@ -0,0 +1,8 @@ +{ + "validateLogs": true, + "ignoreOutput": true, + "targets": "chrome 80", + "presets": [ + ["env", { "debug": true }] + ] +} diff --git a/packages/babel-preset-env/test/fixtures/debug/top-level-targets/stdout.txt b/packages/babel-preset-env/test/fixtures/debug/top-level-targets/stdout.txt new file mode 100644 index 000000000000..762aee9a191e --- /dev/null +++ b/packages/babel-preset-env/test/fixtures/debug/top-level-targets/stdout.txt @@ -0,0 +1,23 @@ +@babel/preset-env: `DEBUG` option + +Using targets: +{ + "chrome": "80" +} + +Using modules transform: auto + +Using plugins: + syntax-numeric-separator { "chrome":"80" } + proposal-logical-assignment-operators { "chrome":"80" } + syntax-nullish-coalescing-operator { "chrome":"80" } + syntax-optional-chaining { "chrome":"80" } + syntax-json-strings { "chrome":"80" } + syntax-optional-catch-binding { "chrome":"80" } + syntax-async-generators { "chrome":"80" } + syntax-object-rest-spread { "chrome":"80" } + transform-modules-commonjs { "chrome":"80" } + proposal-dynamic-import { "chrome":"80" } + proposal-export-namespace-from {} + +Using polyfills: No polyfills were added, since the `useBuiltIns` option was not set. diff --git a/packages/babel-traverse/src/path/conversion.ts b/packages/babel-traverse/src/path/conversion.ts index 028695961264..5e401415c14e 100644 --- a/packages/babel-traverse/src/path/conversion.ts +++ b/packages/babel-traverse/src/path/conversion.ts @@ -76,6 +76,7 @@ export function ensureBlock( /** * Keeping this for backward-compatibility. You should use arrowFunctionToExpression() for >=7.x. */ +// TODO(Babel 8): Remove this export function arrowFunctionToShadowed(this: NodePath) { if (!this.isArrowFunctionExpression()) return; @@ -107,7 +108,13 @@ export function unwrapFunctionEnvironment(this: NodePath) { */ export function arrowFunctionToExpression( this: NodePath, - { allowInsertArrow = true, specCompliant = false } = {}, + { + allowInsertArrow = true, + /** @deprecated Use `noNewArrows` instead */ + specCompliant = false, + // TODO(Babel 8): Consider defaulting to `false` for spec compliancy + noNewArrows = !specCompliant, + } = {}, ) { if (!this.isArrowFunctionExpression()) { throw this.buildCodeFrameError( @@ -117,14 +124,14 @@ export function arrowFunctionToExpression( const thisBinding = hoistFunctionEnvironment( this, - specCompliant, + noNewArrows, allowInsertArrow, ); this.ensureBlock(); // @ts-expect-error todo(flow->ts): avoid mutating nodes this.node.type = "FunctionExpression"; - if (specCompliant) { + if (!noNewArrows) { const checkBinding = thisBinding ? null : this.parentPath.scope.generateUidIdentifier("arrowCheckId"); @@ -165,7 +172,8 @@ export function arrowFunctionToExpression( */ function hoistFunctionEnvironment( fnPath, - specCompliant = false, + // TODO(Babel 8): Consider defaulting to `false` for spec compliancy + noNewArrows = true, allowInsertArrow = true, ) { const thisEnvFn = fnPath.findParent(p => { @@ -303,11 +311,11 @@ function hoistFunctionEnvironment( // Convert all "this" references in the arrow to point at the alias. let thisBinding; - if (thisPaths.length > 0 || specCompliant) { + if (thisPaths.length > 0 || !noNewArrows) { thisBinding = getThisBinding(thisEnvFn, inConstructor); if ( - !specCompliant || + noNewArrows || // In subclass constructors, still need to rewrite because "this" can't be bound in spec mode // because it might not have been initialized yet. (inConstructor && hasSuperClass(thisEnvFn)) @@ -321,7 +329,7 @@ function hoistFunctionEnvironment( thisChild.replaceWith(thisRef); }); - if (specCompliant) thisBinding = null; + if (!noNewArrows) thisBinding = null; } } diff --git a/packages/babel-traverse/src/path/replacement.ts b/packages/babel-traverse/src/path/replacement.ts index 3774fa53ffc3..e114740501e8 100644 --- a/packages/babel-traverse/src/path/replacement.ts +++ b/packages/babel-traverse/src/path/replacement.ts @@ -272,6 +272,8 @@ export function replaceExpressionWithStatements( } const callee = this.get("callee") as NodePath; + + // This is an IIFE, so we don't need to worry about the noNewArrows assumption callee.arrowFunctionToExpression(); // (() => await xxx)() -> await (async () => await xxx)(); diff --git a/packages/babel-traverse/src/scope/index.ts b/packages/babel-traverse/src/scope/index.ts index 169f8a585e98..6a9b8b80c5ed 100644 --- a/packages/babel-traverse/src/scope/index.ts +++ b/packages/babel-traverse/src/scope/index.ts @@ -578,7 +578,7 @@ export default class Scope { } // TODO: (Babel 8) Split i in two parameters, and use an object of flags - toArray(node: t.Node, i?: number | boolean, allowArrayLike?: boolean) { + toArray(node: t.Node, i?: number | boolean, arrayLikeIsIterable?: boolean) { if (t.isIdentifier(node)) { const binding = this.getBinding(node.name); if (binding?.constant && binding.path.isGenericType("Array")) { @@ -622,7 +622,7 @@ export default class Scope { helperName = "toArray"; } - if (allowArrayLike) { + if (arrayLikeIsIterable) { args.unshift(this.hub.addHelper(helperName)); helperName = "maybeArrayLike"; } diff --git a/yarn.lock b/yarn.lock index 04958e1a4608..ffc9d8de4b47 100644 --- a/yarn.lock +++ b/yarn.lock @@ -131,6 +131,7 @@ __metadata: dependencies: "@babel/code-frame": "workspace:^7.12.13" "@babel/generator": "workspace:^7.12.17" + "@babel/helper-compilation-targets": "workspace:^7.12.17" "@babel/helper-module-transforms": "workspace:^7.12.17" "@babel/helper-transform-fixture-test-runner": "workspace:*" "@babel/helpers": "workspace:^7.12.17" @@ -141,7 +142,7 @@ __metadata: convert-source-map: ^1.7.0 debug: ^4.1.0 escape-string-regexp: "condition:BABEL_8_BREAKING ? ^4.0.0 : " - gensync: ^1.0.0-beta.1 + gensync: ^1.0.0-beta.2 json5: ^2.1.2 lodash: ^4.17.19 semver: ^5.4.1 @@ -7375,10 +7376,10 @@ fsevents@^1.2.7: languageName: node linkType: hard -"gensync@npm:^1.0.0-beta.1": - version: 1.0.0-beta.1 - resolution: "gensync@npm:1.0.0-beta.1" - checksum: 3d14f7c34fc903dd52c36d0879de2c4afde8315edccd630e97919c365819b32c06d98770ef87f7ba45686ee5d2bd5818354920187659b42828319f7cc3352fdb +"gensync@npm:^1.0.0-beta.1, gensync@npm:^1.0.0-beta.2": + version: 1.0.0-beta.2 + resolution: "gensync@npm:1.0.0-beta.2" + checksum: d523437689c97b3aba9c5cdeca4677d5fff9a29d620db693fea40d852bad63563110f16979d0170248439dbcd2ecee0780fb2533d3f0519f019081aa10767c60 languageName: node linkType: hard