@@ -4962,7 +4962,7 @@ namespace ts {
49624962 const oldcontext = context;
49634963 context = {
49644964 ...oldcontext,
4965- usedSymbolNames: mapMap(symbolTable, (_symbol, name) => [unescapeLeadingUnderscores(name), true] ),
4965+ usedSymbolNames: createMap( ),
49664966 remappedSymbolNames: createMap(),
49674967 tracker: {
49684968 ...oldcontext.tracker,
@@ -4986,6 +4986,10 @@ namespace ts {
49864986 context.usedSymbolNames!.set(name, true);
49874987 });
49884988 }
4989+ forEachEntry(symbolTable, (symbol, name) => {
4990+ const baseName = unescapeLeadingUnderscores(name);
4991+ void getInternalSymbolName(symbol, baseName); // Called to cache values into `usedSymbolNames` and `remappedSymbolNames`
4992+ });
49894993 let addingDeclare = !bundled;
49904994 const exportEquals = symbolTable.get(InternalSymbolName.ExportEquals);
49914995 if (exportEquals && symbolTable.size > 1 && exportEquals.flags & SymbolFlags.Alias) {
@@ -5198,7 +5202,11 @@ namespace ts {
51985202 isPrivate = true;
51995203 }
52005204 const modifierFlags = (!isPrivate ? ModifierFlags.Export : 0) | (isDefault && !needsPostExportDefault ? ModifierFlags.Default : 0);
5201- if (symbol.flags & SymbolFlags.Function) {
5205+ const isConstMergedWithNS = symbol.flags & SymbolFlags.Module &&
5206+ symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property) &&
5207+ symbol.escapedName !== InternalSymbolName.ExportEquals;
5208+ const isConstMergedWithNSPrintableAsSignatureMerge = isConstMergedWithNS && isTypeRepresentableAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol);
5209+ if (symbol.flags & SymbolFlags.Function || isConstMergedWithNSPrintableAsSignatureMerge) {
52025210 serializeAsFunctionNamespaceMerge(getTypeOfSymbol(symbol), symbol, getInternalSymbolName(symbol, symbolName), modifierFlags);
52035211 }
52045212 if (symbol.flags & SymbolFlags.TypeAlias) {
@@ -5209,7 +5217,8 @@ namespace ts {
52095217 if (symbol.flags & (SymbolFlags.BlockScopedVariable | SymbolFlags.FunctionScopedVariable | SymbolFlags.Property)
52105218 && symbol.escapedName !== InternalSymbolName.ExportEquals
52115219 && !(symbol.flags & SymbolFlags.Prototype)
5212- && !(symbol.flags & SymbolFlags.Class)) {
5220+ && !(symbol.flags & SymbolFlags.Class)
5221+ && !isConstMergedWithNSPrintableAsSignatureMerge) {
52135222 serializeVariableOrProperty(symbol, symbolName, isPrivate, needsPostExportDefault, propertyAsAlias, modifierFlags);
52145223 }
52155224 if (symbol.flags & SymbolFlags.Enum) {
@@ -5226,7 +5235,7 @@ namespace ts {
52265235 serializeAsClass(symbol, getInternalSymbolName(symbol, symbolName), modifierFlags);
52275236 }
52285237 }
5229- if (symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule)) {
5238+ if (( symbol.flags & (SymbolFlags.ValueModule | SymbolFlags.NamespaceModule) && (!isConstMergedWithNS || isTypeOnlyNamespace(symbol))) || isConstMergedWithNSPrintableAsSignatureMerge ) {
52305239 serializeModule(symbol, symbolName, modifierFlags);
52315240 }
52325241 if (symbol.flags & SymbolFlags.Interface) {
@@ -5253,7 +5262,9 @@ namespace ts {
52535262 }
52545263
52555264 function includePrivateSymbol(symbol: Symbol) {
5265+ if (some(symbol.declarations, isParameterDeclaration)) return;
52565266 Debug.assertDefined(deferredPrivates);
5267+ getUnusedName(unescapeLeadingUnderscores(symbol.escapedName), symbol); // Call to cache unique name for symbol
52575268 deferredPrivates!.set("" + getSymbolId(symbol), symbol);
52585269 }
52595270
@@ -5327,8 +5338,16 @@ namespace ts {
53275338 ), modifierFlags);
53285339 }
53295340
5341+ function getNamespaceMembersForSerialization(symbol: Symbol) {
5342+ return !symbol.exports ? [] : filter(arrayFrom((symbol.exports).values()), p => !((p.flags & SymbolFlags.Prototype) || (p.escapedName === "prototype")));
5343+ }
5344+
5345+ function isTypeOnlyNamespace(symbol: Symbol) {
5346+ return every(getNamespaceMembersForSerialization(symbol), m => !(resolveSymbol(m).flags & SymbolFlags.Value));
5347+ }
5348+
53305349 function serializeModule(symbol: Symbol, symbolName: string, modifierFlags: ModifierFlags) {
5331- const members = !symbol.exports ? [] : filter(arrayFrom(( symbol.exports).values()), p => !((p.flags & SymbolFlags.Prototype) || (p.escapedName === "prototype")) );
5350+ const members = getNamespaceMembersForSerialization( symbol);
53325351 // Split NS members up by declaration - members whose parent symbol is the ns symbol vs those whose is not (but were added in later via merging)
53335352 const locationMap = arrayToMultiMap(members, m => m.parent && m.parent === symbol ? "real" : "merged");
53345353 const realMembers = locationMap.get("real") || emptyArray;
@@ -5338,18 +5357,21 @@ namespace ts {
53385357 // so we don't even have placeholders to fill in.
53395358 if (length(realMembers)) {
53405359 const localName = getInternalSymbolName(symbol, symbolName);
5341- serializeAsNamespaceDeclaration(realMembers, localName, modifierFlags, !!(symbol.flags & SymbolFlags.Function));
5360+ serializeAsNamespaceDeclaration(realMembers, localName, modifierFlags, !!(symbol.flags & ( SymbolFlags.Function | SymbolFlags.Assignment) ));
53425361 }
53435362 if (length(mergedMembers)) {
53445363 const localName = getInternalSymbolName(symbol, symbolName);
5345- forEach(mergedMembers, includePrivateSymbol);
53465364 const nsBody = createModuleBlock([createExportDeclaration(
53475365 /*decorators*/ undefined,
53485366 /*modifiers*/ undefined,
53495367 createNamedExports(map(filter(mergedMembers, n => n.escapedName !== InternalSymbolName.ExportEquals), s => {
53505368 const name = unescapeLeadingUnderscores(s.escapedName);
53515369 const localName = getInternalSymbolName(s, name);
5352- return createExportSpecifier(name === localName ? undefined : localName, name);
5370+ const aliasDecl = s.declarations && getDeclarationOfAliasSymbol(s);
5371+ const target = aliasDecl && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true);
5372+ includePrivateSymbol(target || s);
5373+ const targetName = target ? getInternalSymbolName(target, unescapeLeadingUnderscores(target.escapedName)) : localName;
5374+ return createExportSpecifier(name === targetName ? undefined : targetName, name);
53535375 }))
53545376 )]);
53555377 addResult(createModuleDeclaration(
@@ -5624,6 +5646,7 @@ namespace ts {
56245646 serializeMaybeAliasAssignment(symbol);
56255647 break;
56265648 case SyntaxKind.BinaryExpression:
5649+ case SyntaxKind.PropertyAccessExpression:
56275650 // Could be best encoded as though an export specifier or as though an export assignment
56285651 // If name is default or export=, do an export assignment
56295652 // Otherwise do an export specifier
@@ -5634,10 +5657,6 @@ namespace ts {
56345657 serializeExportSpecifier(localName, targetName);
56355658 }
56365659 break;
5637- case SyntaxKind.PropertyAccessExpression:
5638- // A PAE alias is _always_ going to exist as an append to a top-level export, where our top level
5639- // handling should always be sufficient to encode the export action itself
5640- break;
56415660 default:
56425661 return Debug.failBadSyntaxKind(node, "Unhandled alias declaration kind in symbol serializer!");
56435662 }
@@ -5666,7 +5685,8 @@ namespace ts {
56665685 const aliasDecl = symbol.declarations && getDeclarationOfAliasSymbol(symbol);
56675686 // serialize what the alias points to, preserve the declaration's initializer
56685687 const target = aliasDecl && getTargetOfAliasDeclaration(aliasDecl, /*dontRecursivelyResolve*/ true);
5669- if (target) {
5688+ // If the target resolves and resolves to a thing defined in this file, emit as an alias, otherwise emit as a const
5689+ if (target && length(target.declarations) && some(target.declarations, d => getSourceFileOfNode(d) === getSourceFileOfNode(enclosingDeclaration))) {
56705690 // In case `target` refers to a namespace member, look at the declaration and serialize the leftmost symbol in it
56715691 // eg, `namespace A { export class B {} }; exports = A.B;`
56725692 // Technically, this is all that's required in the case where the assignment is an entity name expression
@@ -5752,6 +5772,7 @@ namespace ts {
57525772 return getObjectFlags(typeToSerialize) & (ObjectFlags.Anonymous | ObjectFlags.Mapped) &&
57535773 !getIndexInfoOfType(typeToSerialize, IndexKind.String) &&
57545774 !getIndexInfoOfType(typeToSerialize, IndexKind.Number) &&
5775+ !!(length(getPropertiesOfType(typeToSerialize)) || length(getSignaturesOfType(typeToSerialize, SignatureKind.Call))) &&
57555776 !length(getSignaturesOfType(typeToSerialize, SignatureKind.Construct)) && // TODO: could probably serialize as function + ns + class, now that that's OK
57565777 !getDeclarationWithTypeAnnotation(hostSymbol) &&
57575778 !(typeToSerialize.symbol && some(typeToSerialize.symbol.declarations, d => getSourceFileOfNode(d) !== ctxSrc)) &&
@@ -6106,11 +6127,8 @@ namespace ts {
61066127 return context.remappedSymbolNames!.get("" + getSymbolId(symbol))!;
61076128 }
61086129 }
6109- if (input === InternalSymbolName.Default) {
6110- input = "_default";
6111- }
6112- else if (input === InternalSymbolName.ExportEquals) {
6113- input = "_exports";
6130+ if (symbol) {
6131+ input = getNameCandidateWorker(symbol, input);
61146132 }
61156133 let i = 0;
61166134 const original = input;
@@ -6125,17 +6143,29 @@ namespace ts {
61256143 return input;
61266144 }
61276145
6128- function getInternalSymbolName(symbol: Symbol, localName: string) {
6129- if (context.remappedSymbolNames!.has("" + getSymbolId(symbol))) {
6130- return context.remappedSymbolNames!.get("" + getSymbolId(symbol))!;
6131- }
6146+ function getNameCandidateWorker(symbol: Symbol, localName: string) {
61326147 if (localName === InternalSymbolName.Default || localName === InternalSymbolName.Class || localName === InternalSymbolName.Function) {
61336148 const flags = context.flags;
61346149 context.flags |= NodeBuilderFlags.InInitialEntityName;
61356150 const nameCandidate = getNameOfSymbolAsWritten(symbol, context);
61366151 context.flags = flags;
6137- localName = isIdentifierText(nameCandidate, languageVersion) && !isStringANonContextualKeyword(nameCandidate) ? nameCandidate : getUnusedName(`_default`, symbol);
6152+ localName = nameCandidate.length > 0 && isSingleOrDoubleQuote(nameCandidate.charCodeAt(0)) ? stripQuotes(nameCandidate) : nameCandidate;
6153+ }
6154+ if (localName === InternalSymbolName.Default) {
6155+ localName = "_default";
6156+ }
6157+ else if (localName === InternalSymbolName.ExportEquals) {
6158+ localName = "_exports";
6159+ }
6160+ localName = isIdentifierText(localName, languageVersion) && !isStringANonContextualKeyword(localName) ? localName : "_" + localName.replace(/[^a-zA-Z0-9]/g, "_");
6161+ return localName;
6162+ }
6163+
6164+ function getInternalSymbolName(symbol: Symbol, localName: string) {
6165+ if (context.remappedSymbolNames!.has("" + getSymbolId(symbol))) {
6166+ return context.remappedSymbolNames!.get("" + getSymbolId(symbol))!;
61386167 }
6168+ localName = getNameCandidateWorker(symbol, localName);
61396169 // The result of this is going to be used as the symbol's name - lock it in, so `getUnusedName` will also pick it up
61406170 context.remappedSymbolNames!.set("" + getSymbolId(symbol), localName);
61416171 return localName;
0 commit comments