@@ -10,38 +10,26 @@ import {
10
10
Navigation ,
11
11
Meaning
12
12
} 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' ;
14
14
import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers' ;
15
15
import { TypeScriptInternals } from '../analyzer/TypeScriptInternals' ;
16
+ import { Collector } from '../collector/Collector' ;
17
+ import { CollectorEntity } from '../collector/CollectorEntity' ;
16
18
17
19
export class DeclarationReferenceGenerator {
18
20
public static readonly unknownReference : string = '?' ;
19
21
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 ;
38
26
}
39
27
40
28
/**
41
29
* Gets the UID for a TypeScript Identifier that references a type.
42
30
*/
43
31
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 ) ;
45
33
if ( symbol !== undefined ) {
46
34
const isExpression : boolean = DeclarationReferenceGenerator . _isInExpressionContext ( node ) ;
47
35
return (
@@ -99,68 +87,62 @@ export class DeclarationReferenceGenerator {
99
87
) ;
100
88
}
101
89
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 ( ) ;
103
93
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
- }
94
+
95
+ // If it's global or from an external library, then use either Members or Exports. It's not possible for
96
+ // global symbols or external library symbols to be Locals.
97
+ const isGlobal : boolean = ! ! sourceFile && ! ts . isExternalModule ( sourceFile ) ;
98
+ const isFromExternalLibrary : boolean =
99
+ ! ! sourceFile && this . _collector . program . isSourceFileFromExternalLibrary ( sourceFile ) ;
100
+ if ( isGlobal || isFromExternalLibrary ) {
112
101
if (
102
+ parent &&
113
103
parent . members &&
114
104
DeclarationReferenceGenerator . _isSameSymbol ( parent . members . get ( symbol . escapedName ) , symbol )
115
105
) {
116
106
return Navigation . Members ;
117
107
}
118
- if (
119
- parent . globalExports &&
120
- DeclarationReferenceGenerator . _isSameSymbol ( parent . globalExports . get ( symbol . escapedName ) , symbol )
121
- ) {
122
- return 'global' ;
123
- }
108
+
109
+ return Navigation . Exports ;
124
110
}
125
111
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 ;
112
+ // Otherwise, this symbol is from the current package.
113
+ if ( parent ) {
114
+ // If we've found an exported CollectorEntity, then it's exported from the package entry point, so
115
+ // use Exports.
116
+ const namedDeclaration : ts . DeclarationName | undefined = (
117
+ declaration as ts . NamedDeclaration | undefined
118
+ ) ?. name ;
119
+ if ( namedDeclaration && ts . isIdentifier ( namedDeclaration ) ) {
120
+ const collectorEntity : CollectorEntity | undefined =
121
+ this . _collector . tryGetEntityForNode ( namedDeclaration ) ;
122
+ if ( collectorEntity && collectorEntity . exported ) {
123
+ return Navigation . Exports ;
124
+ }
153
125
}
154
- // declarations are exports if they have an `export` modifier.
155
- if ( ts . getCombinedModifierFlags ( declaration ) & ts . ModifierFlags . Export ) {
126
+
127
+ // If its parent symbol is not a source file, then use either Exports or Members. If the parent symbol
128
+ // is a source file, but it wasn't exported from the package entry point (in the check above), then the
129
+ // symbol is a local, so fall through below.
130
+ if ( ! DeclarationReferenceGenerator . _isExternalModuleSymbol ( parent ) ) {
131
+ if (
132
+ parent . members &&
133
+ DeclarationReferenceGenerator . _isSameSymbol ( parent . members . get ( symbol . escapedName ) , symbol )
134
+ ) {
135
+ return Navigation . Members ;
136
+ }
137
+
156
138
return Navigation . Exports ;
157
139
}
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
- }
162
140
}
163
- // all other declarations are locals
141
+
142
+ // Otherwise, we have a local symbol, so use a Locals navigation. These are either:
143
+ //
144
+ // 1. Symbols that are exported from a file module but not the package entry point.
145
+ // 2. Symbols that are not exported from their parent module.
164
146
return Navigation . Locals ;
165
147
}
166
148
@@ -218,20 +200,21 @@ export class DeclarationReferenceGenerator {
218
200
meaning : ts . SymbolFlags ,
219
201
includeModuleSymbols : boolean
220
202
) : DeclarationReference | undefined {
203
+ const declaration : ts . Node | undefined = TypeScriptHelpers . tryGetADeclaration ( symbol ) ;
204
+ const sourceFile : ts . SourceFile | undefined = declaration ?. getSourceFile ( ) ;
205
+
221
206
let followedSymbol : ts . Symbol = symbol ;
222
207
if ( followedSymbol . flags & ts . SymbolFlags . ExportValue ) {
223
- followedSymbol = this . _typeChecker . getExportSymbolOfSymbol ( followedSymbol ) ;
208
+ followedSymbol = this . _collector . typeChecker . getExportSymbolOfSymbol ( followedSymbol ) ;
224
209
}
225
210
if ( followedSymbol . flags & ts . SymbolFlags . Alias ) {
226
- followedSymbol = this . _typeChecker . getAliasedSymbol ( followedSymbol ) ;
211
+ followedSymbol = this . _collector . typeChecker . getAliasedSymbol ( followedSymbol ) ;
227
212
}
228
213
229
214
if ( DeclarationReferenceGenerator . _isExternalModuleSymbol ( followedSymbol ) ) {
230
215
if ( ! includeModuleSymbols ) {
231
216
return undefined ;
232
217
}
233
- const declaration : ts . Node | undefined = TypeScriptHelpers . tryGetADeclaration ( symbol ) ;
234
- const sourceFile : ts . SourceFile | undefined = declaration ?. getSourceFile ( ) ;
235
218
return new DeclarationReference ( this . _sourceFileToModuleSource ( sourceFile ) ) ;
236
219
}
237
220
@@ -270,13 +253,11 @@ export class DeclarationReferenceGenerator {
270
253
}
271
254
}
272
255
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 ;
256
+ const navigation : Navigation = this . _getNavigationToSymbol ( followedSymbol ) ;
257
+
258
+ // If the symbol is a global, ensure the source is global.
259
+ if ( sourceFile && ! ts . isExternalModule ( sourceFile ) && parentRef . source !== GlobalSource . instance ) {
260
+ parentRef = new DeclarationReference ( GlobalSource . instance ) ;
280
261
}
281
262
282
263
return parentRef
@@ -313,7 +294,7 @@ export class DeclarationReferenceGenerator {
313
294
if ( grandParent && ts . isModuleDeclaration ( grandParent ) ) {
314
295
const grandParentSymbol : ts . Symbol | undefined = TypeScriptInternals . tryGetSymbolForDeclaration (
315
296
grandParent ,
316
- this . _typeChecker
297
+ this . _collector . typeChecker
317
298
) ;
318
299
if ( grandParentSymbol ) {
319
300
return this . _symbolToDeclarationReference (
@@ -334,28 +315,27 @@ export class DeclarationReferenceGenerator {
334
315
}
335
316
336
317
private _getPackageName ( sourceFile : ts . SourceFile ) : string {
337
- if ( this . _program . isSourceFileFromExternalLibrary ( sourceFile ) ) {
338
- const packageJson : INodePackageJson | undefined = this . _packageJsonLookup . tryLoadNodePackageJsonFor (
339
- sourceFile . fileName
340
- ) ;
318
+ if ( this . _collector . program . isSourceFileFromExternalLibrary ( sourceFile ) ) {
319
+ const packageJson : INodePackageJson | undefined =
320
+ this . _collector . packageJsonLookup . tryLoadNodePackageJsonFor ( sourceFile . fileName ) ;
341
321
342
322
if ( packageJson && packageJson . name ) {
343
323
return packageJson . name ;
344
324
}
345
325
return DeclarationReferenceGenerator . unknownReference ;
346
326
}
347
- return this . _workingPackageName ;
327
+ return this . _collector . workingPackage . name ;
348
328
}
349
329
350
330
private _sourceFileToModuleSource ( sourceFile : ts . SourceFile | undefined ) : GlobalSource | ModuleSource {
351
331
if ( sourceFile && ts . isExternalModule ( sourceFile ) ) {
352
332
const packageName : string = this . _getPackageName ( sourceFile ) ;
353
333
354
- if ( this . _bundledPackageNames . has ( packageName ) ) {
334
+ if ( this . _collector . bundledPackageNames . has ( packageName ) ) {
355
335
// The api-extractor.json config file has a "bundledPackages" setting, which causes imports from
356
336
// certain NPM packages to be treated as part of the working project. In this case, we need to
357
337
// substitute the working package name.
358
- return new ModuleSource ( this . _workingPackageName ) ;
338
+ return new ModuleSource ( this . _collector . workingPackage . name ) ;
359
339
} else {
360
340
return new ModuleSource ( packageName ) ;
361
341
}
0 commit comments