Skip to content

Commit

Permalink
fix: Fix sourceFile.getExportedDeclarations() returning import iden…
Browse files Browse the repository at this point in the history
…tifiers in some scenarios
  • Loading branch information
dsherret committed Oct 1, 2018
1 parent e2a8d2e commit 295ea4a
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 11 deletions.
38 changes: 29 additions & 9 deletions src/compiler/ast/base/ModuledNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,29 +343,49 @@ export function ModuledNode<T extends Constructor<ModuledNodeExtensionType>>(Bas

for (const symbol of exportSymbols)
for (const declaration of symbol.getDeclarations())
yield* getDeclarationHandlingExportSpecifiers(declaration);
yield* getDeclarationHandlingImportsAndExports(declaration);

function* getDeclarationHandlingExportSpecifiers(declaration: Node): IterableIterator<Node> {
function* getDeclarationHandlingImportsAndExports(declaration: Node): IterableIterator<Node> {
if (handledDeclarations.has(declaration))
return;
handledDeclarations.add(declaration);

if (declaration.getKind() === SyntaxKind.ExportSpecifier) {
for (const d of (declaration as ExportSpecifier).getLocalTargetDeclarations())
yield* getDeclarationHandlingExportSpecifiers(d);
if (TypeGuards.isExportSpecifier(declaration)) {
for (const d of declaration.getLocalTargetDeclarations())
yield* getDeclarationHandlingImportsAndExports(d);
}
else if (declaration.getKind() === SyntaxKind.ExportAssignment) {
const identifier = (declaration as ExportAssignment).getExpression();
else if (TypeGuards.isExportAssignment(declaration)) {
const identifier = declaration.getExpression();
if (identifier == null || identifier.getKind() !== SyntaxKind.Identifier)
return;
yield* getDeclarationsForSymbol(identifier.getSymbol());
}
else if (TypeGuards.isImportSpecifier(declaration)) {
const identifier = declaration.getNameNode();
const symbol = identifier.getSymbol();
if (symbol == null)
return;
for (const d of symbol.getDeclarations())
yield* getDeclarationHandlingExportSpecifiers(d);
yield* getDeclarationsForSymbol(symbol.getAliasedSymbol());
}
else if (declaration.getKind() === SyntaxKind.ImportClause) {
// default import
const identifier = (declaration as Node<ts.ImportClause>).getNodeProperty("name");
if (identifier == null)
return;
const symbol = identifier.getSymbol();
if (symbol == null)
return;
yield* getDeclarationsForSymbol(symbol.getAliasedSymbol());
}
else
yield declaration;

function* getDeclarationsForSymbol(symbol: Symbol | undefined): IterableIterator<Node> {
if (symbol == null)
return;
for (const d of symbol.getDeclarations())
yield* getDeclarationHandlingImportsAndExports(d);
}
}
}
}
Expand Down
38 changes: 36 additions & 2 deletions src/tests/compiler/base/moduledNodeTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -492,8 +492,42 @@ describe(nameof(ModuledNode), () => {
project.createSourceFile("subFile2.ts", `export class SubClass2 {}`);
project.createSourceFile("subFile3.ts", `class SubClass3 {}\nexport default SubClass3;`);

expect(mainSourceFile.getExportedDeclarations().map(d => (d as any).getName()).sort())
.to.deep.equal(["MainFileClass", "OtherClass", "Class", "MyClass", "SubClass", "SubClass2", "SubClass3"].sort());
expect(mainSourceFile.getExportedDeclarations().map(d => d.getText()).sort())
.to.deep.equal([
"export class MainFileClass {}",
"export class OtherClass {}",
"export class Class {}",
"export class MyClass {}",
"export class SubClass {}",
"export class SubClass2 {}",
"class SubClass3 {}"].sort());
});

it("should get the original declaration of one that's imported then exported", () => {
const project = new Project({ useVirtualFileSystem: true });
const mainSourceFile = project.createSourceFile("main.ts", `import { Test } from "./Test"; export { Test };`);
project.createSourceFile("Test.ts", `export class Test {}`);

expect(mainSourceFile.getExportedDeclarations().map(d => (d as any).getText()).sort())
.to.deep.equal(["export class Test {}"].sort());
});

it("should get the original declaration of one that's imported on a different name then exported", () => {
const project = new Project({ useVirtualFileSystem: true });
const mainSourceFile = project.createSourceFile("main.ts", `import { Test as NewTest } from "./Test"; export { NewTest };`);
project.createSourceFile("Test.ts", `export class Test {}`);

expect(mainSourceFile.getExportedDeclarations().map(d => (d as any).getText()).sort())
.to.deep.equal(["export class Test {}"].sort());
});

it("should get the original declaration of one that's imported on a default import then exported", () => {
const project = new Project({ useVirtualFileSystem: true });
const mainSourceFile = project.createSourceFile("main.ts", `import Test from "./Test"; export { Test };`);
project.createSourceFile("Test.ts", `export default class Test {}`);

expect(mainSourceFile.getExportedDeclarations().map(d => (d as any).getText()).sort())
.to.deep.equal(["export default class Test {}"].sort());
});

function doTest(text: string, expectedDeclarationNames: string[]) {
Expand Down

0 comments on commit 295ea4a

Please sign in to comment.