@@ -10,38 +10,26 @@ import {
1010 Navigation ,
1111 Meaning
1212} from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference' ;
13- import { PackageJsonLookup , INodePackageJson , InternalError } from '@rushstack/node-core-library' ;
13+ import { INodePackageJson , InternalError } from '@rushstack/node-core-library' ;
1414import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers' ;
1515import { TypeScriptInternals } from '../analyzer/TypeScriptInternals' ;
16+ import { Collector } from '../collector/Collector' ;
17+ import { CollectorEntity } from '../collector/CollectorEntity' ;
1618
1719export class DeclarationReferenceGenerator {
1820 public static readonly unknownReference : string = '?' ;
1921
20- private _packageJsonLookup : PackageJsonLookup ;
21- private _workingPackageName : string ;
22- private _program : ts . Program ;
23- private _typeChecker : ts . TypeChecker ;
24- private _bundledPackageNames : ReadonlySet < string > ;
25-
26- public constructor (
27- packageJsonLookup : PackageJsonLookup ,
28- workingPackageName : string ,
29- program : ts . Program ,
30- typeChecker : ts . TypeChecker ,
31- bundledPackageNames : ReadonlySet < string >
32- ) {
33- this . _packageJsonLookup = packageJsonLookup ;
34- this . _workingPackageName = workingPackageName ;
35- this . _program = program ;
36- this . _typeChecker = typeChecker ;
37- this . _bundledPackageNames = bundledPackageNames ;
22+ private _collector : Collector ;
23+
24+ public constructor ( collector : Collector ) {
25+ this . _collector = collector ;
3826 }
3927
4028 /**
4129 * Gets the UID for a TypeScript Identifier that references a type.
4230 */
4331 public getDeclarationReferenceForIdentifier ( node : ts . Identifier ) : DeclarationReference | undefined {
44- const symbol : ts . Symbol | undefined = this . _typeChecker . getSymbolAtLocation ( node ) ;
32+ const symbol : ts . Symbol | undefined = this . _collector . typeChecker . getSymbolAtLocation ( node ) ;
4533 if ( symbol !== undefined ) {
4634 const isExpression : boolean = DeclarationReferenceGenerator . _isInExpressionContext ( node ) ;
4735 return (
@@ -99,68 +87,48 @@ export class DeclarationReferenceGenerator {
9987 ) ;
10088 }
10189
102- private static _getNavigationToSymbol ( symbol : ts . Symbol ) : Navigation | 'global' {
90+ private _getNavigationToSymbol ( symbol : ts . Symbol ) : Navigation {
91+ const declaration : ts . Declaration | undefined = TypeScriptHelpers . tryGetADeclaration ( symbol ) ;
92+ const sourceFile : ts . SourceFile | undefined = declaration ?. getSourceFile ( ) ;
10393 const parent : ts . Symbol | undefined = TypeScriptInternals . getSymbolParent ( symbol ) ;
104- // First, try to determine navigation to symbol via its parent.
105- if ( parent ) {
106- if (
107- parent . exports &&
108- DeclarationReferenceGenerator . _isSameSymbol ( parent . exports . get ( symbol . escapedName ) , symbol )
109- ) {
110- return Navigation . Exports ;
111- }
112- if (
113- parent . members &&
114- DeclarationReferenceGenerator . _isSameSymbol ( parent . members . get ( symbol . escapedName ) , symbol )
115- ) {
116- return Navigation . Members ;
117- }
118- if (
119- parent . globalExports &&
120- DeclarationReferenceGenerator . _isSameSymbol ( parent . globalExports . get ( symbol . escapedName ) , symbol )
121- ) {
122- return 'global' ;
123- }
94+
95+ // If it's a global, then use an Exports navigation.
96+ if ( sourceFile && ! ts . isExternalModule ( sourceFile ) ) {
97+ return Navigation . Exports ;
12498 }
12599
126- // Next, try determining navigation to symbol by its node
127- if ( symbol . valueDeclaration ) {
128- const declaration : ts . Declaration = ts . isBindingElement ( symbol . valueDeclaration )
129- ? ts . walkUpBindingElementsAndPatterns ( symbol . valueDeclaration )
130- : symbol . valueDeclaration ;
131- if ( ts . isClassElement ( declaration ) && ts . isClassLike ( declaration . parent ) ) {
132- // class members are an "export" if they have the static modifier.
133- return ts . getCombinedModifierFlags ( declaration ) & ts . ModifierFlags . Static
134- ? Navigation . Exports
135- : Navigation . Members ;
136- }
137- if ( ts . isTypeElement ( declaration ) || ts . isObjectLiteralElement ( declaration ) ) {
138- // type and object literal element members are just members
139- return Navigation . Members ;
140- }
141- if ( ts . isEnumMember ( declaration ) ) {
142- // enum members are exports
143- return Navigation . Exports ;
144- }
145- if (
146- ts . isExportSpecifier ( declaration ) ||
147- ts . isExportAssignment ( declaration ) ||
148- ts . isExportSpecifier ( declaration ) ||
149- ts . isExportDeclaration ( declaration ) ||
150- ts . isNamedExports ( declaration )
151- ) {
152- return Navigation . Exports ;
100+ // If it's from an external library, then use an Exports navigation.
101+ if ( sourceFile && this . _collector . program . isSourceFileFromExternalLibrary ( sourceFile ) ) {
102+ return Navigation . Exports ;
103+ }
104+
105+ // Otherwise, this symbol is from the current package.
106+ if ( parent ) {
107+ // If we've found an exported CollectorEntity, then it's exported from the package entry point, so
108+ // use an Exports navigation.
109+ const namedDeclaration : ts . DeclarationName | undefined = (
110+ declaration as ts . NamedDeclaration | undefined
111+ ) ?. name ;
112+ if ( namedDeclaration && ts . isIdentifier ( namedDeclaration ) ) {
113+ const collectorEntity : CollectorEntity | undefined =
114+ this . _collector . tryGetEntityForNode ( namedDeclaration ) ;
115+ if ( collectorEntity && collectorEntity . exported ) {
116+ return Navigation . Exports ;
117+ }
153118 }
154- // declarations are exports if they have an `export` modifier.
155- if ( ts . getCombinedModifierFlags ( declaration ) & ts . ModifierFlags . Export ) {
119+
120+ // If its parent symbol is not a source file, then use an Exports navigation. If the parent symbol is
121+ // a source file, but it wasn't exported from the package entry point (in the check above), then the symbol
122+ // is a local, so fall through below.
123+ if ( ! DeclarationReferenceGenerator . _isExternalModuleSymbol ( parent ) ) {
156124 return Navigation . Exports ;
157125 }
158- if ( ts . isSourceFile ( declaration . parent ) && ! ts . isExternalModule ( declaration . parent ) ) {
159- // declarations in a source file are global if the source file is not a module.
160- return 'global' ;
161- }
162126 }
163- // all other declarations are locals
127+
128+ // Otherwise, we have a local symbol, so use a Locals navigation. These are either:
129+ //
130+ // 1. Symbols that are exported from a file module but not the package entry point.
131+ // 2. Symbols that are not exported from their parent module.
164132 return Navigation . Locals ;
165133 }
166134
@@ -218,20 +186,21 @@ export class DeclarationReferenceGenerator {
218186 meaning : ts . SymbolFlags ,
219187 includeModuleSymbols : boolean
220188 ) : DeclarationReference | undefined {
189+ const declaration : ts . Node | undefined = TypeScriptHelpers . tryGetADeclaration ( symbol ) ;
190+ const sourceFile : ts . SourceFile | undefined = declaration ?. getSourceFile ( ) ;
191+
221192 let followedSymbol : ts . Symbol = symbol ;
222193 if ( followedSymbol . flags & ts . SymbolFlags . ExportValue ) {
223- followedSymbol = this . _typeChecker . getExportSymbolOfSymbol ( followedSymbol ) ;
194+ followedSymbol = this . _collector . typeChecker . getExportSymbolOfSymbol ( followedSymbol ) ;
224195 }
225196 if ( followedSymbol . flags & ts . SymbolFlags . Alias ) {
226- followedSymbol = this . _typeChecker . getAliasedSymbol ( followedSymbol ) ;
197+ followedSymbol = this . _collector . typeChecker . getAliasedSymbol ( followedSymbol ) ;
227198 }
228199
229200 if ( DeclarationReferenceGenerator . _isExternalModuleSymbol ( followedSymbol ) ) {
230201 if ( ! includeModuleSymbols ) {
231202 return undefined ;
232203 }
233- const declaration : ts . Node | undefined = TypeScriptHelpers . tryGetADeclaration ( symbol ) ;
234- const sourceFile : ts . SourceFile | undefined = declaration ?. getSourceFile ( ) ;
235204 return new DeclarationReference ( this . _sourceFileToModuleSource ( sourceFile ) ) ;
236205 }
237206
@@ -270,13 +239,11 @@ export class DeclarationReferenceGenerator {
270239 }
271240 }
272241
273- let navigation : Navigation | 'global' =
274- DeclarationReferenceGenerator . _getNavigationToSymbol ( followedSymbol ) ;
275- if ( navigation === 'global' ) {
276- if ( parentRef . source !== GlobalSource . instance ) {
277- parentRef = new DeclarationReference ( GlobalSource . instance ) ;
278- }
279- navigation = Navigation . Exports ;
242+ const navigation : Navigation = this . _getNavigationToSymbol ( followedSymbol ) ;
243+
244+ // If the symbol is a global, ensure the source is global.
245+ if ( sourceFile && ! ts . isExternalModule ( sourceFile ) && parentRef . source !== GlobalSource . instance ) {
246+ parentRef = new DeclarationReference ( GlobalSource . instance ) ;
280247 }
281248
282249 return parentRef
@@ -313,7 +280,7 @@ export class DeclarationReferenceGenerator {
313280 if ( grandParent && ts . isModuleDeclaration ( grandParent ) ) {
314281 const grandParentSymbol : ts . Symbol | undefined = TypeScriptInternals . tryGetSymbolForDeclaration (
315282 grandParent ,
316- this . _typeChecker
283+ this . _collector . typeChecker
317284 ) ;
318285 if ( grandParentSymbol ) {
319286 return this . _symbolToDeclarationReference (
@@ -334,28 +301,27 @@ export class DeclarationReferenceGenerator {
334301 }
335302
336303 private _getPackageName ( sourceFile : ts . SourceFile ) : string {
337- if ( this . _program . isSourceFileFromExternalLibrary ( sourceFile ) ) {
338- const packageJson : INodePackageJson | undefined = this . _packageJsonLookup . tryLoadNodePackageJsonFor (
339- sourceFile . fileName
340- ) ;
304+ if ( this . _collector . program . isSourceFileFromExternalLibrary ( sourceFile ) ) {
305+ const packageJson : INodePackageJson | undefined =
306+ this . _collector . packageJsonLookup . tryLoadNodePackageJsonFor ( sourceFile . fileName ) ;
341307
342308 if ( packageJson && packageJson . name ) {
343309 return packageJson . name ;
344310 }
345311 return DeclarationReferenceGenerator . unknownReference ;
346312 }
347- return this . _workingPackageName ;
313+ return this . _collector . workingPackage . name ;
348314 }
349315
350316 private _sourceFileToModuleSource ( sourceFile : ts . SourceFile | undefined ) : GlobalSource | ModuleSource {
351317 if ( sourceFile && ts . isExternalModule ( sourceFile ) ) {
352318 const packageName : string = this . _getPackageName ( sourceFile ) ;
353319
354- if ( this . _bundledPackageNames . has ( packageName ) ) {
320+ if ( this . _collector . bundledPackageNames . has ( packageName ) ) {
355321 // The api-extractor.json config file has a "bundledPackages" setting, which causes imports from
356322 // certain NPM packages to be treated as part of the working project. In this case, we need to
357323 // substitute the working package name.
358- return new ModuleSource ( this . _workingPackageName ) ;
324+ return new ModuleSource ( this . _collector . workingPackage . name ) ;
359325 } else {
360326 return new ModuleSource ( packageName ) ;
361327 }
0 commit comments