From aace364df38db741efe964e068f72d4e4b0bdef3 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 21 Feb 2020 11:15:20 +0100 Subject: [PATCH] avoid crashing when exports info contains a circular reference e. g. when using import * as self from "./self"; export { self } --- lib/ModuleInfoHeaderPlugin.js | 62 ++++++++++++++++--- ...armonyExportImportedSpecifierDependency.js | 14 ++++- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/lib/ModuleInfoHeaderPlugin.js b/lib/ModuleInfoHeaderPlugin.js index 1cef3d88a..e799e61a2 100644 --- a/lib/ModuleInfoHeaderPlugin.js +++ b/lib/ModuleInfoHeaderPlugin.js @@ -28,9 +28,36 @@ const joinIterableWithComma = iterable => { return str; }; -const printExportsInfoToSource = (source, indent, exportsInfo) => { - let hasExports = false; +const printExportsInfoToSource = ( + source, + indent, + exportsInfo, + alreadyPrinted = new Set() +) => { + const otherExportsInfo = exportsInfo.otherExportsInfo; + + let alreadyPrintedExports = 0; + + // determine exports to print + const printedExports = []; for (const exportInfo of exportsInfo.orderedExports) { + if (!alreadyPrinted.has(exportInfo)) { + alreadyPrinted.add(exportInfo); + printedExports.push(exportInfo); + } else { + alreadyPrintedExports++; + } + } + let showOtherExports = false; + if (!alreadyPrinted.has(otherExportsInfo)) { + alreadyPrinted.add(otherExportsInfo); + showOtherExports = true; + } else { + alreadyPrintedExports++; + } + + // print the exports + for (const exportInfo of printedExports) { source.add( Template.toComment( `${indent}export ${JSON.stringify(exportInfo.name).slice( @@ -40,20 +67,39 @@ const printExportsInfoToSource = (source, indent, exportsInfo) => { ) + "\n" ); if (exportInfo.exportsInfo) { - printExportsInfoToSource(source, indent + " ", exportInfo.exportsInfo); + printExportsInfoToSource( + source, + indent + " ", + exportInfo.exportsInfo, + alreadyPrinted + ); } - hasExports = true; } - const otherExportsInfo = exportsInfo.otherExportsInfo; - if (otherExportsInfo.provided !== false || otherExportsInfo.used !== false) { - const title = hasExports ? "other exports" : "exports"; + if (alreadyPrintedExports) { source.add( Template.toComment( - `${indent}${title} [${otherExportsInfo.getProvidedInfo()}] [${otherExportsInfo.getUsedInfo()}]` + `${indent}... (${alreadyPrintedExports} already listed exports)` ) + "\n" ); } + + if (showOtherExports) { + if ( + otherExportsInfo.provided !== false || + otherExportsInfo.used !== false + ) { + const title = + printedExports.length > 0 || alreadyPrintedExports > 0 + ? "other exports" + : "exports"; + source.add( + Template.toComment( + `${indent}${title} [${otherExportsInfo.getProvidedInfo()}] [${otherExportsInfo.getUsedInfo()}]` + ) + "\n" + ); + } + } }; class ModuleInfoHeaderPlugin { diff --git a/lib/dependencies/HarmonyExportImportedSpecifierDependency.js b/lib/dependencies/HarmonyExportImportedSpecifierDependency.js index 31dc373b3..130809661 100644 --- a/lib/dependencies/HarmonyExportImportedSpecifierDependency.js +++ b/lib/dependencies/HarmonyExportImportedSpecifierDependency.js @@ -40,16 +40,23 @@ const EMPTY_MAP = new Map(); const EMPTY_SET = new Set(); /** - * * @param {string[][]} referencedExports list of referenced exports, will be added to * @param {string[]} prefix export prefix * @param {ExportInfo} exportInfo the export info + * @param {Set} alreadyVisited already visited export info (to handle circular reexports) */ -const processExportInfo = (referencedExports, prefix, exportInfo) => { +const processExportInfo = ( + referencedExports, + prefix, + exportInfo, + alreadyVisited = new Set() +) => { if (!exportInfo) { referencedExports.push(prefix); return; } + if (alreadyVisited.has(exportInfo)) return; + alreadyVisited.add(exportInfo); if (exportInfo.used === UsageState.Unused) return; if ( exportInfo.used !== UsageState.OnlyPropertiesUsed || @@ -64,7 +71,8 @@ const processExportInfo = (referencedExports, prefix, exportInfo) => { processExportInfo( referencedExports, prefix.concat(exportInfo.name), - exportInfo + exportInfo, + alreadyVisited ); } };