Skip to content

Commit

Permalink
feat: ExportSpecifier - getLocalTargetSymbol() and getLocalTargetDecl…
Browse files Browse the repository at this point in the history
…arations()

This can be used to get the export specifier's declarations.
  • Loading branch information
dsherret committed Jan 20, 2018
1 parent a42d6a1 commit 30eff42
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 3 deletions.
8 changes: 8 additions & 0 deletions docs/details/exports.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,14 @@ namedExport.setAlias("NewAliasName");

_Note:_ Setting the alias will rename any uses of the alias or identifier to the new value.

##### Local Target Declarations

The local target declarations are the declarations that the export specifier is referencing:

```ts
const declarations = namedExport.getLocalTargetDeclarations(); // returns: Node[]
```

##### Parent export declaration

```typescript
Expand Down
27 changes: 25 additions & 2 deletions src/compiler/file/ExportSpecifier.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import * as ts from "typescript";
import * as errors from "./../../errors";
import {insertIntoParent, replaceNodeText, removeCommaSeparatedChild} from "./../../manipulation";
import {TypeGuards} from "./../../utils";
import {Node, Identifier} from "./../common";
import {TypeGuards, Logger} from "./../../utils";
import {Node, Identifier, Symbol} from "./../common";
import {ExportDeclaration} from "./ExportDeclaration";

export class ExportSpecifier extends Node<ts.ExportSpecifier> {
Expand Down Expand Up @@ -76,6 +77,28 @@ export class ExportSpecifier extends Node<ts.ExportSpecifier> {
return this.getFirstAncestorByKindOrThrow(ts.SyntaxKind.ExportDeclaration) as ExportDeclaration;
}

/**
* Gets the local target symbol of the export specifier or throws if it doesn't exist.
*/
getLocalTargetSymbolOrThrow() {
return errors.throwIfNullOrUndefined(this.getLocalTargetSymbol(), `The export specifier's local target symbol was expected.`);
}

/**
* Gets the local target symbol of the export specifier or undefined if it doesn't exist.
*/
getLocalTargetSymbol(): Symbol | undefined {
return this.global.typeChecker.getExportSpecifierLocalTargetSymbol(this);
}

/**
* Gets all the declarations referenced by the export specifier.
*/
getLocalTargetDeclarations(): Node[] {
const symbol = this.getLocalTargetSymbol();
return symbol == null ? [] : symbol.getDeclarations();
}

/**
* Removes the export specifier.
*/
Expand Down
19 changes: 19 additions & 0 deletions src/compiler/tools/TypeChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {GlobalContainer} from "./../../GlobalContainer";
import {EnumMember} from "./../enum";
import {Expression} from "./../expression";
import {Node, Symbol, Signature} from "./../common";
import {ExportSpecifier} from "./../file";
import {Type} from "./../type";

/**
Expand Down Expand Up @@ -152,6 +153,24 @@ export class TypeChecker {
return signature == null ? undefined : this.global.compilerFactory.getSignature(signature);
}

/**
* Gets the exports of a module.
* @param moduleSymbol - Module symbol.
*/
getExportsOfModule(moduleSymbol: Symbol) {
const symbols = this.compilerObject.getExportsOfModule(moduleSymbol.compilerSymbol);
return (symbols || []).map(s => this.global.compilerFactory.getSymbol(s));
}

/**
* Gets the local target symbol of the provided export specifier.
* @param exportSpecifier - Export specifier.
*/
getExportSpecifierLocalTargetSymbol(exportSpecifier: ExportSpecifier) {
const symbol = this.compilerObject.getExportSpecifierLocalTargetSymbol(exportSpecifier.compilerNode);
return symbol == null ? undefined : this.global.compilerFactory.getSymbol(symbol);
}

private getDefaultTypeFormatFlags(enclosingNode?: Node) {
let formatFlags = (ts.TypeFormatFlags.UseTypeOfFunction | ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.UseFullyQualifiedType |
ts.TypeFormatFlags.WriteTypeArgumentsOfSignature) as ts.TypeFormatFlags;
Expand Down
46 changes: 45 additions & 1 deletion src/tests/compiler/file/exportSpecifierTests.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {expect} from "chai";
import * as ts from "typescript";
import {expect} from "chai";
import TsSimpleAst from "./../../../main";
import {ExportDeclaration, ExportSpecifier} from "./../../../compiler";
import {ArrayUtils} from "./../../../utils";
Expand Down Expand Up @@ -131,6 +132,49 @@ describe(nameof(ExportSpecifier), () => {
});
});

function setupLocalTargetSymbolTest() {
const ast = getAst();
const mainFile = ast.createSourceFile("main.ts", `export {MyClass, OtherClass} from "./MyClass";`);
const myClassFile = ast.createSourceFile("MyClass.ts", `export class MyClass {}`);
return mainFile.getExportDeclarations()[0].getNamedExports();
}

describe(nameof<ExportSpecifier>(n => n.getLocalTargetSymbol), () => {
it("should get the local target symbol when it exists", () => {
const myClassExportSpecifier = setupLocalTargetSymbolTest()[0];
expect(myClassExportSpecifier.getLocalTargetSymbol()!.getDeclarations()[0].getKind()).to.equal(ts.SyntaxKind.ClassDeclaration);
});

it("should returned undefined when it doesn't exist", () => {
const otherClassExportSpecifier = setupLocalTargetSymbolTest()[1];
expect(otherClassExportSpecifier.getLocalTargetSymbol()).to.be.undefined;
});
});

describe(nameof<ExportSpecifier>(n => n.getLocalTargetSymbolOrThrow), () => {
it("should get the local target symbol when it exists", () => {
const myClassExportSpecifier = setupLocalTargetSymbolTest()[0];
expect(myClassExportSpecifier.getLocalTargetSymbolOrThrow().getDeclarations()[0].getKind()).to.equal(ts.SyntaxKind.ClassDeclaration);
});

it("should throw when it doesn't exist", () => {
const otherClassExportSpecifier = setupLocalTargetSymbolTest()[1];
expect(() => otherClassExportSpecifier.getLocalTargetSymbolOrThrow()).to.throw();
});
});

describe(nameof<ExportSpecifier>(n => n.getLocalTargetDeclarations), () => {
it("should get the local target declarations when they exist", () => {
const myClassExportSpecifier = setupLocalTargetSymbolTest()[0];
expect(myClassExportSpecifier.getLocalTargetDeclarations().map(d => d.getKind())).to.deep.equal([ts.SyntaxKind.ClassDeclaration]);
});

it("should returned an empty array when they don't exist", () => {
const otherClassExportSpecifier = setupLocalTargetSymbolTest()[1];
expect(otherClassExportSpecifier.getLocalTargetDeclarations()).to.deep.equal([]);
});
});

describe(nameof<ExportSpecifier>(n => n.getExportDeclaration), () => {
it("should get the parent export declaration", () => {
const {firstChild} = getInfoFromText<ExportDeclaration>(`export {name} from "./test";`);
Expand Down

0 comments on commit 30eff42

Please sign in to comment.