Skip to content

Commit fcf0bc4

Browse files
committed
Big rewrite to completely eliminate Entry/EntryTable, replacing with the new AstSymbolTable system
1 parent ef183e9 commit fcf0bc4

7 files changed

Lines changed: 283 additions & 598 deletions

File tree

apps/api-extractor/src/generators/packageTypings/AstDeclaration.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { Span } from '../../utils/Span';
88
export interface IAstDeclarationParameters {
99
readonly declaration: ts.Declaration;
1010
readonly astSymbol: AstSymbol;
11-
readonly typeDirectiveReferences: ReadonlyArray<string>;
1211
readonly parentAstDeclaration: AstDeclaration | undefined;
1312
}
1413

@@ -17,13 +16,6 @@ export class AstDeclaration {
1716

1817
public readonly astSymbol: AstSymbol;
1918

20-
/**
21-
* A list of names (e.g. "example-library") that should appear in a reference like this:
22-
*
23-
* /// <reference types="example-library" />
24-
*/
25-
public readonly typeDirectiveReferences: ReadonlyArray<string>;
26-
2719
/**
2820
* The parent, if this object is nested inside another AstDeclaration.
2921
*/
@@ -34,7 +26,6 @@ export class AstDeclaration {
3426
public constructor(parameters: IAstDeclarationParameters) {
3527
this.declaration = parameters.declaration;
3628
this.astSymbol = parameters.astSymbol;
37-
this.typeDirectiveReferences = parameters.typeDirectiveReferences;
3829
this.parent = parameters.parentAstDeclaration;
3930

4031
this.astSymbol.notifyDeclarationAttach(this);

apps/api-extractor/src/generators/packageTypings/AstEntryPoint.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@
33

44
import { AstSymbol } from './AstSymbol';
55

6-
export interface IAstNamedExport {
6+
export interface IExportedMember {
77
readonly name: string;
88
readonly astSymbol: AstSymbol;
99
}
1010

1111
export interface IAstEntryPointParameters {
12-
readonly exports: ReadonlyArray<IAstNamedExport>;
12+
readonly exportedMembers: ReadonlyArray<IExportedMember>;
1313
}
1414

1515
export class AstEntryPoint {
16-
public readonly exports: ReadonlyArray<IAstNamedExport>;
16+
public readonly exportedMembers: ReadonlyArray<IExportedMember>;
1717

1818
public constructor(parameters: IAstEntryPointParameters) {
19-
this.exports = parameters.exports;
19+
this.exportedMembers = parameters.exportedMembers;
2020
}
2121
}

apps/api-extractor/src/generators/packageTypings/AstSymbolTable.ts

Lines changed: 17 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { SymbolAnalyzer, IFollowAliasesResult } from './SymbolAnalyzer';
1010
import { TypeScriptHelpers } from '../../utils/TypeScriptHelpers';
1111
import { AstSymbol } from './AstSymbol';
1212
import { AstImport } from './AstImport';
13-
import { AstEntryPoint, IAstNamedExport } from './AstEntryPoint';
13+
import { AstEntryPoint, IExportedMember } from './AstEntryPoint';
1414

1515
export class AstSymbolTable {
1616
private _typeChecker: ts.TypeChecker;
@@ -40,15 +40,6 @@ export class AstSymbolTable {
4040
private readonly _astEntryPointsBySourceFile: Map<ts.SourceFile, AstEntryPoint>
4141
= new Map<ts.SourceFile, AstEntryPoint>();
4242

43-
/**
44-
* A mapping from a source filename to a list of type declaration references.
45-
*
46-
* For example, the file path "/project1/lib/example.d.ts" might map to an array
47-
* such as [ "node", "es6-promise" ].
48-
*/
49-
private readonly _typeDirectiveReferencesByFilePath: Map<string, ReadonlyArray<string>>
50-
= new Map<string, ReadonlyArray<string>>();
51-
5243
public constructor(typeChecker: ts.TypeChecker) {
5344
this._typeChecker = typeChecker;
5445
}
@@ -64,10 +55,10 @@ export class AstSymbolTable {
6455

6556
const exportSymbols: ts.Symbol[] = this._typeChecker.getExportsOfModule(rootFileSymbol) || [];
6657

67-
const exports: IAstNamedExport[] = [];
58+
const exportedMembers: IExportedMember[] = [];
6859

6960
for (const exportSymbol of exportSymbols) {
70-
const astSymbol: AstSymbol | undefined = this._fetchAstSymbol(exportSymbol);
61+
const astSymbol: AstSymbol | undefined = this._fetchAstSymbol(exportSymbol, true);
7162

7263
if (!astSymbol) {
7364
throw new Error('Unsupported export: ' + exportSymbol.name);
@@ -80,10 +71,10 @@ export class AstSymbolTable {
8071
console.log(d.getDump());
8172
}
8273

83-
exports.push({ name: exportSymbol.name, astSymbol: astSymbol });
74+
exportedMembers.push({ name: exportSymbol.name, astSymbol: astSymbol });
8475
}
8576

86-
astEntryPoint = new AstEntryPoint({ exports });
77+
astEntryPoint = new AstEntryPoint({ exportedMembers });
8778
this._astEntryPointsBySourceFile.set(sourceFile, astEntryPoint);
8879
}
8980
return astEntryPoint;
@@ -120,6 +111,7 @@ export class AstSymbolTable {
120111
case ts.SyntaxKind.ClassDeclaration:
121112
case ts.SyntaxKind.MethodDeclaration:
122113
case ts.SyntaxKind.PropertySignature:
114+
case ts.SyntaxKind.PropertyDeclaration:
123115
case ts.SyntaxKind.InterfaceDeclaration:
124116
case ts.SyntaxKind.FunctionDeclaration:
125117
case ts.SyntaxKind.ModuleDeclaration:
@@ -128,10 +120,14 @@ export class AstSymbolTable {
128120
return false;
129121
}
130122

131-
public tryGetSymbolForAstDeclaration(node: ts.Node): ts.Symbol | undefined {
123+
public tryGetSymbolForNode(node: ts.Node): ts.Symbol | undefined {
132124
return TypeScriptHelpers.getSymbolForDeclaration(node as ts.Declaration);
133125
}
134126

127+
public tryGetAstSymbol(symbol: ts.Symbol): AstSymbol | undefined {
128+
return this._fetchAstSymbol(symbol, false);
129+
}
130+
135131
/**
136132
* Used by analyze to recursively analyze the entire child tree.
137133
*/
@@ -168,15 +164,15 @@ export class AstSymbolTable {
168164
return undefined;
169165
}
170166

171-
const symbol: ts.Symbol | undefined = this.tryGetSymbolForAstDeclaration(node);
167+
const symbol: ts.Symbol | undefined = this.tryGetSymbolForNode(node);
172168
if (!symbol) {
173169
throw new Error('Program Bug: Unable to find symbol for node');
174170
}
175171

176-
return this._fetchAstSymbol(symbol);
172+
return this._fetchAstSymbol(symbol, true);
177173
}
178174

179-
private _fetchAstSymbol(symbol: ts.Symbol): AstSymbol | undefined {
175+
private _fetchAstSymbol(symbol: ts.Symbol, addIfMissing: boolean): AstSymbol | undefined {
180176
const followAliasesResult: IFollowAliasesResult = SymbolAnalyzer.followAliases(symbol, this._typeChecker);
181177

182178
const followedSymbol: ts.Symbol = followAliasesResult.followedSymbol;
@@ -240,21 +236,18 @@ export class AstSymbolTable {
240236
let parentAstSymbol: AstSymbol | undefined = undefined;
241237

242238
if (arbitaryParent) {
243-
const parentSymbol: ts.Symbol | undefined = this.tryGetSymbolForAstDeclaration(arbitaryParent);
239+
const parentSymbol: ts.Symbol | undefined = this.tryGetSymbolForNode(arbitaryParent);
244240
if (!parentSymbol) {
245241
throw new Error('Program bug: missing parent symbol for declaration');
246242
}
247243

248-
parentAstSymbol = this._fetchAstSymbol(parentSymbol);
244+
parentAstSymbol = this._fetchAstSymbol(parentSymbol, addIfMissing);
249245
}
250246

251247
// Okay, now while creating the declarations we will wire them up to the
252248
// their corresopnding parent declarations
253249
for (const declaration of followedSymbol.declarations || []) {
254250

255-
const typeDirectiveReferences: ReadonlyArray<string>
256-
= this._getTypeDirectiveReferences(declaration);
257-
258251
let parentAstDeclaration: AstDeclaration | undefined = undefined;
259252
if (parentAstSymbol) {
260253
const parentDeclaration: ts.Node | undefined
@@ -271,7 +264,7 @@ export class AstSymbolTable {
271264
}
272265

273266
const astDeclaration: AstDeclaration = new AstDeclaration({
274-
declaration, astSymbol, typeDirectiveReferences, parentAstDeclaration});
267+
declaration, astSymbol, parentAstDeclaration});
275268

276269
this._astDeclarationsByDeclaration.set(declaration, astDeclaration);
277270
}
@@ -294,30 +287,4 @@ export class AstSymbolTable {
294287
}
295288
return undefined;
296289
}
297-
298-
private _getTypeDirectiveReferences(node: ts.Node): ReadonlyArray<string> {
299-
const sourceFile: ts.SourceFile = node.getSourceFile();
300-
if (!sourceFile || !sourceFile.fileName) {
301-
return [];
302-
}
303-
304-
const cachedList: ReadonlyArray<string> | undefined
305-
= this._typeDirectiveReferencesByFilePath.get(sourceFile.fileName);
306-
if (cachedList) {
307-
return cachedList;
308-
}
309-
310-
const list: string[] = [];
311-
312-
for (const typeReferenceDirective of sourceFile.typeReferenceDirectives) {
313-
const name: string = sourceFile.text.substring(typeReferenceDirective.pos, typeReferenceDirective.end);
314-
if (list.indexOf(name) < 0) {
315-
list.push(name);
316-
}
317-
}
318-
319-
this._typeDirectiveReferencesByFilePath.set(sourceFile.fileName, list);
320-
return list;
321-
}
322-
323290
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
import { AstSymbol } from './AstSymbol';
5+
import { ReleaseTag } from '../../aedoc/ReleaseTag';
6+
7+
export interface IDtsEntryParameters {
8+
readonly astSymbol: AstSymbol;
9+
readonly originalName: string;
10+
readonly exported: boolean;
11+
readonly releaseTag: ReleaseTag;
12+
}
13+
14+
export class DtsEntry {
15+
public readonly astSymbol: AstSymbol;
16+
public readonly originalName: string;
17+
public readonly exported: boolean;
18+
public readonly releaseTag: ReleaseTag;
19+
20+
private _nameForEmit: string | undefined = undefined;
21+
22+
private _sortKey: string|undefined = undefined;
23+
24+
public constructor(parameters: IDtsEntryParameters) {
25+
this.astSymbol = parameters.astSymbol;
26+
this.originalName = parameters.originalName;
27+
this.exported = parameters.exported;
28+
this.releaseTag = parameters.releaseTag;
29+
}
30+
31+
/**
32+
* The originalName, possibly renamed to ensure that all the top-level exports have unique names.
33+
*/
34+
public get nameForEmit(): string | undefined {
35+
return this._nameForEmit;
36+
}
37+
38+
public set nameForEmit(value: string | undefined) {
39+
this._nameForEmit = value;
40+
this._sortKey = undefined; // invalidate the cached value
41+
}
42+
43+
public getSortKey(): string {
44+
if (!this._sortKey) {
45+
const name: string = this.nameForEmit || this.originalName;
46+
if (name.substr(0, 1) === '_') {
47+
// Removes the leading underscore, for example: "_example" --> "example*"
48+
// This causes internal definitions to sort alphabetically with regular definitions.
49+
// The star is appended to preserve uniqueness, since "*" is not a legal identifier character.
50+
this._sortKey = name.substr(1) + '*';
51+
} else {
52+
this._sortKey = name;
53+
}
54+
}
55+
return this._sortKey;
56+
}
57+
}

0 commit comments

Comments
 (0)