diff --git a/packages/babel-core/src/config/full.ts b/packages/babel-core/src/config/full.ts index fb016f79734e..de947b5d4e53 100644 --- a/packages/babel-core/src/config/full.ts +++ b/packages/babel-core/src/config/full.ts @@ -37,7 +37,7 @@ type LoadedDescriptor = { options: {}; dirname: string; alias: string; - externalDependencies: DeepArray; + externalDependencies: ReadonlyDeepArray; }; export type { InputOptions } from "./validation/options"; @@ -319,7 +319,13 @@ const makeDescriptorLoader = ( throw new Error(error); } - return { value: item, options, dirname, alias, externalDependencies }; + return { + value: item, + options, + dirname, + alias, + externalDependencies: freezeDeepArray(externalDependencies), + }; }); const pluginDescriptorLoader = makeDescriptorLoader< @@ -397,7 +403,16 @@ const instantiatePlugin = makeWeakCache(function* ( plugin.visitor || {}, ]); - externalDependencies.push(inherits.externalDependencies); + if (inherits.externalDependencies.length > 0) { + if (externalDependencies.length === 0) { + externalDependencies = inherits.externalDependencies; + } else { + externalDependencies = freezeDeepArray([ + externalDependencies, + inherits.externalDependencies, + ]); + } + } } return new Plugin(plugin, options, alias, externalDependencies); @@ -470,7 +485,7 @@ const instantiatePreset = makeWeakCacheSync( options: validate("preset", value), alias, dirname, - externalDependencies: freezeDeepArray(externalDependencies), + externalDependencies, }; }, ); diff --git a/packages/babel-core/src/config/plugin.ts b/packages/babel-core/src/config/plugin.ts index bb3151e0c018..ea10bb8c7eaa 100644 --- a/packages/babel-core/src/config/plugin.ts +++ b/packages/babel-core/src/config/plugin.ts @@ -1,5 +1,5 @@ import { finalize } from "./helpers/deep-array"; -import type { DeepArray, ReadonlyDeepArray } from "./helpers/deep-array"; +import type { ReadonlyDeepArray } from "./helpers/deep-array"; import type { PluginObject } from "./validation/plugins"; export default class Plugin { @@ -20,7 +20,7 @@ export default class Plugin { plugin: PluginObject, options: {}, key?: string, - externalDependencies: DeepArray = [], + externalDependencies: ReadonlyDeepArray = finalize([]), ) { this.key = plugin.name || key; @@ -32,7 +32,6 @@ export default class Plugin { this.generatorOverride = plugin.generatorOverride; this.options = options; - - this.externalDependencies = finalize(externalDependencies); + this.externalDependencies = externalDependencies; } } diff --git a/packages/babel-core/test/external-dependencies.js b/packages/babel-core/test/external-dependencies.js index fe041e054484..e37c26785e37 100644 --- a/packages/babel-core/test/external-dependencies.js +++ b/packages/babel-core/test/external-dependencies.js @@ -230,4 +230,55 @@ describe("externalDependencies", () => { ).not.toThrow(); }); }); + + describe("regressions", () => { + describe("#14233", () => { + it("no external dependencies", () => { + const code = `let a = 1`; + + function pluginA(api) { + api.cache.never(); + return { name: "plugin-a" }; + } + function pluginB() { + return { name: "plugin-b", inherits: pluginA }; + } + + expect(() => { + transform(code, { plugins: [pluginB] }); + + transform(code, { plugins: [pluginB] }); + }).not.toThrow(); + }); + + it("with external dependencies", () => { + const code = `let a = 1`; + + let pluginAdep = "./a-foo"; + + function pluginA(api) { + api.cache.never(); + api.addExternalDependency(pluginAdep); + return { name: "plugin-a" }; + } + const pluginB = jest.fn(function pluginB(api) { + api.cache.using(() => 0); + api.addExternalDependency("./b-foo"); + return { name: "plugin-b", inherits: pluginA }; + }); + + const result1 = transform(code, { plugins: [pluginB] }); + pluginAdep = "./a-bar"; + const result2 = transform(code, { plugins: [pluginB] }); + + expect(pluginB).toHaveBeenCalledTimes(1); + expect(new Set(result1.externalDependencies)).toEqual( + new Set(["./a-foo", "./b-foo"]), + ); + expect(new Set(result2.externalDependencies)).toEqual( + new Set(["./a-bar", "./b-foo"]), + ); + }); + }); + }); });