In JS declaration emit, move imports painted in nested contexts to the root private context (#39818)

* In JS declaration emit, move imports painted in nested contexts to the root private context

* Add test for nathan
This commit is contained in:
Wesley Wigham
2020-07-31 18:25:37 -07:00
committed by GitHub
parent 1b97d03b8a
commit 94989789df
10 changed files with 665 additions and 7 deletions

View File

@@ -5899,7 +5899,7 @@ namespace ts {
const enclosingDeclaration = context.enclosingDeclaration!;
let results: Statement[] = [];
const visitedSymbols = new Set<number>();
let deferredPrivates: ESMap<SymbolId, Symbol> | undefined;
const deferredPrivatesStack: ESMap<SymbolId, Symbol>[] = [];
const oldcontext = context;
context = {
...oldcontext,
@@ -6110,9 +6110,8 @@ namespace ts {
}
function visitSymbolTable(symbolTable: SymbolTable, suppressNewPrivateContext?: boolean, propertyAsAlias?: boolean) {
const oldDeferredPrivates = deferredPrivates;
if (!suppressNewPrivateContext) {
deferredPrivates = new Map();
deferredPrivatesStack.push(new Map());
}
symbolTable.forEach((symbol: Symbol) => {
serializeSymbol(symbol, /*isPrivate*/ false, !!propertyAsAlias);
@@ -6121,11 +6120,11 @@ namespace ts {
// deferredPrivates will be filled up by visiting the symbol table
// And will continue to iterate as elements are added while visited `deferredPrivates`
// (As that's how a map iterator is defined to work)
deferredPrivates!.forEach((symbol: Symbol) => {
deferredPrivatesStack[deferredPrivatesStack.length - 1].forEach((symbol: Symbol) => {
serializeSymbol(symbol, /*isPrivate*/ true, !!propertyAsAlias);
});
deferredPrivatesStack.pop();
}
deferredPrivates = oldDeferredPrivates;
}
function serializeSymbol(symbol: Symbol, isPrivate: boolean, propertyAsAlias: boolean) {
@@ -6309,9 +6308,19 @@ namespace ts {
function includePrivateSymbol(symbol: Symbol) {
if (some(symbol.declarations, isParameterDeclaration)) return;
Debug.assertIsDefined(deferredPrivates);
Debug.assertIsDefined(deferredPrivatesStack[deferredPrivatesStack.length - 1]);
getUnusedName(unescapeLeadingUnderscores(symbol.escapedName), symbol); // Call to cache unique name for symbol
deferredPrivates.set(getSymbolId(symbol), symbol);
// Blanket moving (import) aliases into the root private context should work, since imports are not valid within namespaces
// (so they must have been in the root to begin with if they were real imports) cjs `require` aliases (an upcoming feature)
// will throw a wrench in this, since those may have been nested, but we'll need to synthesize them in the outer scope
// anyway, as that's the only place the import they translate to is valid. In such a case, we might need to use a unique name
// for the moved import; which hopefully the above `getUnusedName` call should produce.
const isExternalImportAlias = !!(symbol.flags & SymbolFlags.Alias) && !some(symbol.declarations, d =>
!!findAncestor(d, isExportDeclaration) ||
isNamespaceExport(d) ||
(isImportEqualsDeclaration(d) && !isExternalModuleReference(d.moduleReference))
);
deferredPrivatesStack[isExternalImportAlias ? 0 : (deferredPrivatesStack.length - 1)].set(getSymbolId(symbol), symbol);
}
function isExportingScope(enclosingDeclaration: Node) {