Handle exported functions in ExportDeclarations for CJS/AMD/UMD emit (#58489)

This commit is contained in:
Jake Bailey
2024-05-28 17:22:27 -07:00
committed by GitHub
parent 8f408cc120
commit fa58c615a4
24 changed files with 77 additions and 62 deletions

View File

@@ -283,10 +283,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile
);
}
}
if (some(currentModuleInfo.exportedFunctions)) {
for (const f of currentModuleInfo.exportedFunctions) {
appendExportsOfHoistedDeclaration(statements, f);
}
for (const f of currentModuleInfo.exportedFunctions) {
appendExportsOfHoistedDeclaration(statements, f);
}
append(statements, visitNode(currentModuleInfo.externalHelpersImportDeclaration, topLevelVisitor, isStatement));
@@ -613,10 +611,8 @@ export function transformModule(context: TransformationContext): (x: SourceFile
if (some(currentModuleInfo.exportedNames)) {
append(statements, factory.createExpressionStatement(reduceLeft(currentModuleInfo.exportedNames, (prev, nextId) => factory.createAssignment(factory.createPropertyAccessExpression(factory.createIdentifier("exports"), factory.createIdentifier(idText(nextId))), prev), factory.createVoidZero() as Expression)));
}
if (some(currentModuleInfo.exportedFunctions)) {
for (const f of currentModuleInfo.exportedFunctions) {
appendExportsOfHoistedDeclaration(statements, f);
}
for (const f of currentModuleInfo.exportedFunctions) {
appendExportsOfHoistedDeclaration(statements, f);
}
// Visit each statement of the module body.

View File

@@ -433,7 +433,7 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc
// this set is used to filter names brought by star expors.
// local names set should only be added if we have anything exported
if (!some(moduleInfo.exportedNames) && !some(moduleInfo.exportedFunctions) && moduleInfo.exportSpecifiers.size === 0) {
if (!some(moduleInfo.exportedNames) && moduleInfo.exportedFunctions.size === 0 && moduleInfo.exportSpecifiers.size === 0) {
// no exported declarations (export var ...) or export specifiers (export {x})
// check if we have any non star export declarations.
let hasExportDeclarationWithExportClause = false;
@@ -469,21 +469,19 @@ export function transformSystemModule(context: TransformationContext): (x: Sourc
}
}
if (moduleInfo.exportedFunctions) {
for (const f of moduleInfo.exportedFunctions) {
if (hasSyntacticModifier(f, ModifierFlags.Default)) {
continue;
}
Debug.assert(!!f.name);
// write name of exported declaration, i.e 'export var x...'
exportedNames.push(
factory.createPropertyAssignment(
factory.createStringLiteralFromNode(f.name),
factory.createTrue(),
),
);
for (const f of moduleInfo.exportedFunctions) {
if (hasSyntacticModifier(f, ModifierFlags.Default)) {
continue;
}
Debug.assert(!!f.name);
// write name of exported declaration, i.e 'export var x...'
exportedNames.push(
factory.createPropertyAssignment(
factory.createStringLiteralFromNode(f.name),
factory.createTrue(),
),
);
}
const exportedNamesStorageRef = factory.createUniqueName("exportedNames");

View File

@@ -105,7 +105,7 @@ export interface ExternalModuleInfo {
exportSpecifiers: IdentifierNameMap<ExportSpecifier[]>; // file-local export specifiers by name (no reexports)
exportedBindings: Identifier[][]; // exported names of local declarations
exportedNames: Identifier[] | undefined; // all exported names in the module, both local and reexported, excluding the names of locally exported function declarations
exportedFunctions: FunctionDeclaration[] | undefined; // all of the top-level exported function declarations
exportedFunctions: Set<FunctionDeclaration>; // all of the top-level exported function declarations
exportEquals: ExportAssignment | undefined; // an export= declaration if one was present
hasExportStarsToExportValues: boolean; // whether this module contains export*
}
@@ -174,8 +174,8 @@ export function collectExternalModuleInfo(context: TransformationContext, source
const exportSpecifiers = new IdentifierNameMultiMap<ExportSpecifier>();
const exportedBindings: Identifier[][] = [];
const uniqueExports = new Map<string, boolean>();
const exportedFunctions = new Set<FunctionDeclaration>();
let exportedNames: Identifier[] | undefined;
let exportedFunctions: FunctionDeclaration[] | undefined;
let hasExportDefault = false;
let exportEquals: ExportAssignment | undefined;
let hasExportStarsToExportValues = false;
@@ -256,22 +256,7 @@ export function collectExternalModuleInfo(context: TransformationContext, source
case SyntaxKind.FunctionDeclaration:
if (hasSyntacticModifier(node, ModifierFlags.Export)) {
exportedFunctions = append(exportedFunctions, node as FunctionDeclaration);
if (hasSyntacticModifier(node, ModifierFlags.Default)) {
// export default function() { }
if (!hasExportDefault) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), context.factory.getDeclarationName(node as FunctionDeclaration));
hasExportDefault = true;
}
}
else {
// export function x() { }
const name = (node as FunctionDeclaration).name!;
if (!uniqueExports.get(idText(name))) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(idText(name), true);
}
}
addExportedFunctionDeclaration(node as FunctionDeclaration, /*name*/ undefined, hasSyntacticModifier(node, ModifierFlags.Default));
}
break;
@@ -317,6 +302,11 @@ export function collectExternalModuleInfo(context: TransformationContext, source
|| resolver.getReferencedValueDeclaration(name);
if (decl) {
if (decl.kind === SyntaxKind.FunctionDeclaration) {
addExportedFunctionDeclaration(decl as FunctionDeclaration, specifier.name, specifier.name.escapedText === InternalSymbolName.Default);
continue;
}
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(decl), specifier.name);
}
@@ -325,6 +315,27 @@ export function collectExternalModuleInfo(context: TransformationContext, source
}
}
}
function addExportedFunctionDeclaration(node: FunctionDeclaration, name: Identifier | undefined, isDefault: boolean) {
exportedFunctions.add(node);
if (isDefault) {
// export default function() { }
// function x() { } + export { x as default };
if (!hasExportDefault) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name ?? context.factory.getDeclarationName(node));
hasExportDefault = true;
}
}
else {
// export function x() { }
// function x() { } + export { x }
name ??= node.name!;
if (!uniqueExports.get(idText(name))) {
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
uniqueExports.set(idText(name), true);
}
}
}
}
function collectExportedVariableInfo(decl: VariableDeclaration | BindingElement, uniqueExports: Map<string, boolean>, exportedNames: Identifier[] | undefined, exportedBindings: Identifier[][]) {