diff --git a/src/Module.ts b/src/Module.ts index f96737ce7cc..1ec309e7d8e 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -308,20 +308,28 @@ export default class Module { ); } - getReexports() { + getReexports(walkedModuleIds = new Set()) { const reexports = Object.create(null); for (const name in this.reexports) { reexports[name] = true; } + // avoid infinite recursion when using circular `export * from X` + if (walkedModuleIds.has(this.id)) { + return Object.keys(reexports); + } + walkedModuleIds.add(this.id); + this.exportAllModules.forEach(module => { if (module.isExternal) { reexports[`*${module.id}`] = true; return; } - for (const name of (module).getExports().concat((module).getReexports())) { + for (const name of (module) + .getExports() + .concat((module).getReexports(walkedModuleIds))) { if (name !== 'default') reexports[name] = true; } }); diff --git a/test/function/samples/cycles-export-star/_config.js b/test/function/samples/cycles-export-star/_config.js new file mode 100644 index 00000000000..73e20044778 --- /dev/null +++ b/test/function/samples/cycles-export-star/_config.js @@ -0,0 +1,18 @@ +const assert = require('assert'); + +module.exports = { + description: 'does not stack overflow on `export * from X` cycles', + code(code) { + assert.equal( + code, + `'use strict';\n\nfunction a() {\n\treturn 'a';\n}\n\nassert.equal(a(), 'a');\n` + ); + }, + warnings: [ + { + code: 'CIRCULAR_DEPENDENCY', + importer: 'a.js', + message: 'Circular dependency: a.js -> b.js -> a.js' + } + ] +}; diff --git a/test/function/samples/cycles-export-star/a.js b/test/function/samples/cycles-export-star/a.js new file mode 100644 index 00000000000..710a0d4c760 --- /dev/null +++ b/test/function/samples/cycles-export-star/a.js @@ -0,0 +1,5 @@ +export * from './b.js'; + +export function a() { + return 'a'; +} diff --git a/test/function/samples/cycles-export-star/b.js b/test/function/samples/cycles-export-star/b.js new file mode 100644 index 00000000000..f8cd8b45005 --- /dev/null +++ b/test/function/samples/cycles-export-star/b.js @@ -0,0 +1,5 @@ +export * from './a.js'; + +export function b() { + return 'b'; +} diff --git a/test/function/samples/cycles-export-star/main.js b/test/function/samples/cycles-export-star/main.js new file mode 100644 index 00000000000..ac1878f7f39 --- /dev/null +++ b/test/function/samples/cycles-export-star/main.js @@ -0,0 +1,3 @@ +import { a } from './a.js'; + +assert.equal(a(), 'a');