1 | "use strict";
|
2 |
|
3 |
|
4 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
5 | if (k2 === undefined) k2 = k;
|
6 | var desc = Object.getOwnPropertyDescriptor(m, k);
|
7 | if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
8 | desc = { enumerable: true, get: function() { return m[k]; } };
|
9 | }
|
10 | Object.defineProperty(o, k2, desc);
|
11 | }) : (function(o, m, k, k2) {
|
12 | if (k2 === undefined) k2 = k;
|
13 | o[k2] = m[k];
|
14 | }));
|
15 | var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
16 | Object.defineProperty(o, "default", { enumerable: true, value: v });
|
17 | }) : function(o, v) {
|
18 | o["default"] = v;
|
19 | });
|
20 | var __importStar = (this && this.__importStar) || function (mod) {
|
21 | if (mod && mod.__esModule) return mod;
|
22 | var result = {};
|
23 | if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
24 | __setModuleDefault(result, mod);
|
25 | return result;
|
26 | };
|
27 | Object.defineProperty(exports, "__esModule", { value: true });
|
28 | exports.AstSymbolTable = void 0;
|
29 |
|
30 | const ts = __importStar(require("typescript"));
|
31 | const node_core_library_1 = require("@rushstack/node-core-library");
|
32 | const AstDeclaration_1 = require("./AstDeclaration");
|
33 | const TypeScriptHelpers_1 = require("./TypeScriptHelpers");
|
34 | const AstSymbol_1 = require("./AstSymbol");
|
35 | const PackageMetadataManager_1 = require("./PackageMetadataManager");
|
36 | const ExportAnalyzer_1 = require("./ExportAnalyzer");
|
37 | const AstNamespaceImport_1 = require("./AstNamespaceImport");
|
38 | const TypeScriptInternals_1 = require("./TypeScriptInternals");
|
39 | const SyntaxHelpers_1 = require("./SyntaxHelpers");
|
40 | const SourceFileLocationFormatter_1 = require("./SourceFileLocationFormatter");
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 | class AstSymbolTable {
|
52 | constructor(program, typeChecker, packageJsonLookup, bundledPackageNames, messageRouter) {
|
53 | |
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 | this._astSymbolsBySymbol = new Map();
|
61 | |
62 |
|
63 |
|
64 | this._astDeclarationsByDeclaration = new Map();
|
65 |
|
66 |
|
67 | this._entitiesByNode = new Map();
|
68 | this._program = program;
|
69 | this._typeChecker = typeChecker;
|
70 | this._messageRouter = messageRouter;
|
71 | this._globalVariableAnalyzer = TypeScriptInternals_1.TypeScriptInternals.getGlobalVariableAnalyzer(program);
|
72 | this._packageMetadataManager = new PackageMetadataManager_1.PackageMetadataManager(packageJsonLookup, messageRouter);
|
73 | this._exportAnalyzer = new ExportAnalyzer_1.ExportAnalyzer(this._program, this._typeChecker, bundledPackageNames, {
|
74 | analyze: this.analyze.bind(this),
|
75 | fetchAstSymbol: this._fetchAstSymbol.bind(this)
|
76 | });
|
77 | this._alreadyWarnedGlobalNames = new Set();
|
78 | }
|
79 | |
80 |
|
81 |
|
82 | fetchAstModuleFromWorkingPackage(sourceFile) {
|
83 | return this._exportAnalyzer.fetchAstModuleFromSourceFile(sourceFile, undefined, false);
|
84 | }
|
85 | |
86 |
|
87 |
|
88 | fetchAstModuleExportInfo(astModule) {
|
89 | return this._exportAnalyzer.fetchAstModuleExportInfo(astModule);
|
90 | }
|
91 | |
92 |
|
93 |
|
94 |
|
95 | tryGetExportOfAstModule(exportName, astModule) {
|
96 | return this._exportAnalyzer.tryGetExportOfAstModule(exportName, astModule);
|
97 | }
|
98 | |
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 | analyze(astEntity) {
|
112 | if (astEntity instanceof AstSymbol_1.AstSymbol) {
|
113 | return this._analyzeAstSymbol(astEntity);
|
114 | }
|
115 | if (astEntity instanceof AstNamespaceImport_1.AstNamespaceImport) {
|
116 | return this._analyzeAstNamespaceImport(astEntity);
|
117 | }
|
118 | }
|
119 | |
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 | getChildAstDeclarationByNode(node, parentAstDeclaration) {
|
126 | if (!parentAstDeclaration.astSymbol.analyzed) {
|
127 | throw new Error('getChildDeclarationByNode() cannot be used for an AstSymbol that was not analyzed');
|
128 | }
|
129 | const childAstDeclaration = this._astDeclarationsByDeclaration.get(node);
|
130 | if (!childAstDeclaration) {
|
131 | throw new Error('Child declaration not found for the specified node');
|
132 | }
|
133 | if (childAstDeclaration.parent !== parentAstDeclaration) {
|
134 | throw new node_core_library_1.InternalError('The found child is not attached to the parent AstDeclaration');
|
135 | }
|
136 | return childAstDeclaration;
|
137 | }
|
138 | |
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 | tryGetEntityForNode(identifier) {
|
145 | if (!this._entitiesByNode.has(identifier)) {
|
146 | throw new node_core_library_1.InternalError('tryGetEntityForIdentifier() called for an identifier that was not analyzed');
|
147 | }
|
148 | return this._entitiesByNode.get(identifier);
|
149 | }
|
150 | |
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 | static getLocalNameForSymbol(symbol) {
|
166 |
|
167 |
|
168 | const wellKnownSymbolName = TypeScriptHelpers_1.TypeScriptHelpers.tryDecodeWellKnownSymbolName(symbol.escapedName);
|
169 | if (wellKnownSymbolName) {
|
170 | return wellKnownSymbolName;
|
171 | }
|
172 | const isUniqueSymbol = TypeScriptHelpers_1.TypeScriptHelpers.isUniqueSymbolName(symbol.escapedName);
|
173 |
|
174 | let unquotedName = symbol.name;
|
175 | for (const declaration of symbol.declarations || []) {
|
176 |
|
177 |
|
178 | const localSymbol = TypeScriptInternals_1.TypeScriptInternals.tryGetLocalSymbol(declaration);
|
179 | if (localSymbol) {
|
180 | unquotedName = localSymbol.name;
|
181 | }
|
182 |
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 | if (isUniqueSymbol) {
|
195 | const declarationName = ts.getNameOfDeclaration(declaration);
|
196 | if (declarationName && ts.isComputedPropertyName(declarationName)) {
|
197 | const lateBoundName = TypeScriptHelpers_1.TypeScriptHelpers.tryGetLateBoundName(declarationName);
|
198 | if (lateBoundName) {
|
199 |
|
200 |
|
201 |
|
202 | return lateBoundName;
|
203 | }
|
204 | }
|
205 | }
|
206 | }
|
207 |
|
208 |
|
209 |
|
210 | if (!SyntaxHelpers_1.SyntaxHelpers.isSafeUnquotedMemberIdentifier(unquotedName)) {
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 | return JSON.stringify(unquotedName);
|
220 | }
|
221 | return unquotedName;
|
222 | }
|
223 | _analyzeAstNamespaceImport(astNamespaceImport) {
|
224 | if (astNamespaceImport.analyzed) {
|
225 | return;
|
226 | }
|
227 |
|
228 | astNamespaceImport.analyzed = true;
|
229 | const exportedLocalEntities = this.fetchAstModuleExportInfo(astNamespaceImport.astModule).exportedLocalEntities;
|
230 | for (const exportedEntity of exportedLocalEntities.values()) {
|
231 | this.analyze(exportedEntity);
|
232 | }
|
233 | }
|
234 | _analyzeAstSymbol(astSymbol) {
|
235 | if (astSymbol.analyzed) {
|
236 | return;
|
237 | }
|
238 | if (astSymbol.nominalAnalysis) {
|
239 |
|
240 | astSymbol._notifyAnalyzed();
|
241 | return;
|
242 | }
|
243 |
|
244 | const rootAstSymbol = astSymbol.rootAstSymbol;
|
245 |
|
246 | for (const astDeclaration of rootAstSymbol.astDeclarations) {
|
247 | this._analyzeChildTree(astDeclaration.declaration, astDeclaration);
|
248 | }
|
249 | rootAstSymbol._notifyAnalyzed();
|
250 | if (!astSymbol.isExternal) {
|
251 |
|
252 |
|
253 |
|
254 | rootAstSymbol.forEachDeclarationRecursive((astDeclaration) => {
|
255 | for (const referencedAstEntity of astDeclaration.referencedAstEntities) {
|
256 |
|
257 | if (referencedAstEntity instanceof AstSymbol_1.AstSymbol) {
|
258 | if (!referencedAstEntity.isExternal) {
|
259 | this._analyzeAstSymbol(referencedAstEntity);
|
260 | }
|
261 | }
|
262 | if (referencedAstEntity instanceof AstNamespaceImport_1.AstNamespaceImport) {
|
263 | if (!referencedAstEntity.astModule.isExternal) {
|
264 | this._analyzeAstNamespaceImport(referencedAstEntity);
|
265 | }
|
266 | }
|
267 | }
|
268 | });
|
269 | }
|
270 | }
|
271 | |
272 |
|
273 |
|
274 | _analyzeChildTree(node, governingAstDeclaration) {
|
275 | switch (node.kind) {
|
276 | case ts.SyntaxKind.JSDocComment:
|
277 | return;
|
278 |
|
279 | case ts.SyntaxKind.TypeReference:
|
280 | case ts.SyntaxKind.ExpressionWithTypeArguments:
|
281 | case ts.SyntaxKind.ComputedPropertyName:
|
282 | case ts.SyntaxKind.TypeQuery:
|
283 | {
|
284 |
|
285 |
|
286 |
|
287 | const identifierNode = TypeScriptHelpers_1.TypeScriptHelpers.findFirstChildNode(node, ts.SyntaxKind.Identifier);
|
288 | if (identifierNode) {
|
289 | let referencedAstEntity = this._entitiesByNode.get(identifierNode);
|
290 | if (!referencedAstEntity) {
|
291 | const symbol = this._typeChecker.getSymbolAtLocation(identifierNode);
|
292 | if (!symbol) {
|
293 | throw new Error('Symbol not found for identifier: ' + identifierNode.getText());
|
294 | }
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 | let displacedSymbol = true;
|
303 | for (const declaration of symbol.declarations || []) {
|
304 | if (declaration.getSourceFile() === identifierNode.getSourceFile()) {
|
305 | displacedSymbol = false;
|
306 | break;
|
307 | }
|
308 | }
|
309 | if (displacedSymbol) {
|
310 | if (this._globalVariableAnalyzer.hasGlobalName(identifierNode.text)) {
|
311 |
|
312 |
|
313 |
|
314 |
|
315 |
|
316 | if (this._messageRouter.showDiagnostics) {
|
317 | if (!this._alreadyWarnedGlobalNames.has(identifierNode.text)) {
|
318 | this._alreadyWarnedGlobalNames.add(identifierNode.text);
|
319 | this._messageRouter.logDiagnostic(`Ignoring reference to global variable "${identifierNode.text}"` +
|
320 | ` in ` +
|
321 | SourceFileLocationFormatter_1.SourceFileLocationFormatter.formatDeclaration(identifierNode));
|
322 | }
|
323 | }
|
324 | }
|
325 | else {
|
326 |
|
327 |
|
328 | throw new node_core_library_1.InternalError(`Unable to follow symbol for "${identifierNode.text}"`);
|
329 | }
|
330 | }
|
331 | else {
|
332 | referencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntity(symbol, governingAstDeclaration.astSymbol.isExternal);
|
333 | this._entitiesByNode.set(identifierNode, referencedAstEntity);
|
334 | }
|
335 | }
|
336 | if (referencedAstEntity) {
|
337 | governingAstDeclaration._notifyReferencedAstEntity(referencedAstEntity);
|
338 | }
|
339 | }
|
340 | }
|
341 | break;
|
342 |
|
343 | case ts.SyntaxKind.Identifier:
|
344 | {
|
345 | const identifierNode = node;
|
346 | if (!this._entitiesByNode.has(identifierNode)) {
|
347 | const symbol = this._typeChecker.getSymbolAtLocation(identifierNode);
|
348 | let referencedAstEntity = undefined;
|
349 | if (symbol === governingAstDeclaration.astSymbol.followedSymbol) {
|
350 | referencedAstEntity = this._fetchEntityForNode(identifierNode, governingAstDeclaration);
|
351 | }
|
352 | this._entitiesByNode.set(identifierNode, referencedAstEntity);
|
353 | }
|
354 | }
|
355 | break;
|
356 | case ts.SyntaxKind.ImportType:
|
357 | {
|
358 | const importTypeNode = node;
|
359 | let referencedAstEntity = this._entitiesByNode.get(importTypeNode);
|
360 | if (!this._entitiesByNode.has(importTypeNode)) {
|
361 | referencedAstEntity = this._fetchEntityForNode(importTypeNode, governingAstDeclaration);
|
362 | if (!referencedAstEntity) {
|
363 |
|
364 | throw new Error('Failed to fetch entity for import() type node: ' + importTypeNode.getText());
|
365 | }
|
366 | this._entitiesByNode.set(importTypeNode, referencedAstEntity);
|
367 | }
|
368 | if (referencedAstEntity) {
|
369 | governingAstDeclaration._notifyReferencedAstEntity(referencedAstEntity);
|
370 | }
|
371 | }
|
372 | break;
|
373 | }
|
374 |
|
375 | const newGoverningAstDeclaration = this._fetchAstDeclaration(node, governingAstDeclaration.astSymbol.isExternal);
|
376 | for (const childNode of node.getChildren()) {
|
377 | this._analyzeChildTree(childNode, newGoverningAstDeclaration || governingAstDeclaration);
|
378 | }
|
379 | }
|
380 | _fetchEntityForNode(node, governingAstDeclaration) {
|
381 | let referencedAstEntity = this._entitiesByNode.get(node);
|
382 | if (!referencedAstEntity) {
|
383 | if (node.kind === ts.SyntaxKind.ImportType) {
|
384 | referencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntityFromImportTypeNode(node, governingAstDeclaration.astSymbol.isExternal);
|
385 | }
|
386 | else {
|
387 | const symbol = this._typeChecker.getSymbolAtLocation(node);
|
388 | if (!symbol) {
|
389 | throw new Error('Symbol not found for identifier: ' + node.getText());
|
390 | }
|
391 | referencedAstEntity = this._exportAnalyzer.fetchReferencedAstEntity(symbol, governingAstDeclaration.astSymbol.isExternal);
|
392 | }
|
393 | this._entitiesByNode.set(node, referencedAstEntity);
|
394 | }
|
395 | return referencedAstEntity;
|
396 | }
|
397 | _fetchAstDeclaration(node, isExternal) {
|
398 | if (!AstDeclaration_1.AstDeclaration.isSupportedSyntaxKind(node.kind)) {
|
399 | return undefined;
|
400 | }
|
401 | const symbol = TypeScriptHelpers_1.TypeScriptHelpers.getSymbolForDeclaration(node, this._typeChecker);
|
402 | if (!symbol) {
|
403 | throw new node_core_library_1.InternalError('Unable to find symbol for node');
|
404 | }
|
405 | const astSymbol = this._fetchAstSymbol({
|
406 | followedSymbol: symbol,
|
407 | isExternal: isExternal,
|
408 | includeNominalAnalysis: true,
|
409 | addIfMissing: true
|
410 | });
|
411 | if (!astSymbol) {
|
412 | return undefined;
|
413 | }
|
414 | const astDeclaration = this._astDeclarationsByDeclaration.get(node);
|
415 | if (!astDeclaration) {
|
416 | throw new node_core_library_1.InternalError('Unable to find constructed AstDeclaration');
|
417 | }
|
418 | return astDeclaration;
|
419 | }
|
420 | _fetchAstSymbol(options) {
|
421 | const followedSymbol = options.followedSymbol;
|
422 |
|
423 | const arbitraryDeclaration = TypeScriptHelpers_1.TypeScriptHelpers.tryGetADeclaration(followedSymbol);
|
424 | if (!arbitraryDeclaration) {
|
425 | return undefined;
|
426 | }
|
427 | if (followedSymbol.flags &
|
428 | (ts.SymbolFlags.TypeParameter | ts.SymbolFlags.TypeLiteral | ts.SymbolFlags.Transient)) {
|
429 | if (!TypeScriptInternals_1.TypeScriptInternals.isLateBoundSymbol(followedSymbol)) {
|
430 | return undefined;
|
431 | }
|
432 | }
|
433 |
|
434 | if (TypeScriptHelpers_1.TypeScriptHelpers.isAmbient(followedSymbol, this._typeChecker)) {
|
435 |
|
436 |
|
437 | if (!this._exportAnalyzer.isImportableAmbientSourceFile(arbitraryDeclaration.getSourceFile())) {
|
438 | return undefined;
|
439 | }
|
440 | }
|
441 |
|
442 | if (TypeScriptHelpers_1.TypeScriptHelpers.isFollowableAlias(followedSymbol, this._typeChecker)) {
|
443 |
|
444 | throw new node_core_library_1.InternalError('AstSymbolTable._fetchAstSymbol() cannot be called with a symbol alias');
|
445 | }
|
446 | let astSymbol = this._astSymbolsBySymbol.get(followedSymbol);
|
447 | if (!astSymbol) {
|
448 |
|
449 | let nominalAnalysis = false;
|
450 | if (options.isExternal) {
|
451 |
|
452 |
|
453 |
|
454 | const followedSymbolSourceFileName = arbitraryDeclaration.getSourceFile().fileName;
|
455 | if (!this._packageMetadataManager.isAedocSupportedFor(followedSymbolSourceFileName)) {
|
456 | nominalAnalysis = true;
|
457 | if (!options.includeNominalAnalysis) {
|
458 | return undefined;
|
459 | }
|
460 | }
|
461 | }
|
462 | let parentAstSymbol = undefined;
|
463 | if (!nominalAnalysis) {
|
464 | for (const declaration of followedSymbol.declarations || []) {
|
465 | if (!AstDeclaration_1.AstDeclaration.isSupportedSyntaxKind(declaration.kind)) {
|
466 | throw new node_core_library_1.InternalError(`The "${followedSymbol.name}" symbol has a` +
|
467 | ` ts.SyntaxKind.${ts.SyntaxKind[declaration.kind]} declaration which is not (yet?)` +
|
468 | ` supported by API Extractor`);
|
469 | }
|
470 | }
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 | const arbitraryDeclaration = TypeScriptHelpers_1.TypeScriptHelpers.tryGetADeclaration(followedSymbol);
|
482 | if (arbitraryDeclaration) {
|
483 | const arbitraryParentDeclaration = this._tryFindFirstAstDeclarationParent(arbitraryDeclaration);
|
484 | if (arbitraryParentDeclaration) {
|
485 | const parentSymbol = TypeScriptHelpers_1.TypeScriptHelpers.getSymbolForDeclaration(arbitraryParentDeclaration, this._typeChecker);
|
486 | parentAstSymbol = this._fetchAstSymbol({
|
487 | followedSymbol: parentSymbol,
|
488 | isExternal: options.isExternal,
|
489 | includeNominalAnalysis: false,
|
490 | addIfMissing: true
|
491 | });
|
492 | if (!parentAstSymbol) {
|
493 | throw new node_core_library_1.InternalError('Unable to construct a parent AstSymbol for ' + followedSymbol.name);
|
494 | }
|
495 | }
|
496 | }
|
497 | }
|
498 | const localName = options.localName || AstSymbolTable.getLocalNameForSymbol(followedSymbol);
|
499 | astSymbol = new AstSymbol_1.AstSymbol({
|
500 | followedSymbol: followedSymbol,
|
501 | localName: localName,
|
502 | isExternal: options.isExternal,
|
503 | nominalAnalysis: nominalAnalysis,
|
504 | parentAstSymbol: parentAstSymbol,
|
505 | rootAstSymbol: parentAstSymbol ? parentAstSymbol.rootAstSymbol : undefined
|
506 | });
|
507 | this._astSymbolsBySymbol.set(followedSymbol, astSymbol);
|
508 |
|
509 |
|
510 | for (const declaration of followedSymbol.declarations || []) {
|
511 | let parentAstDeclaration = undefined;
|
512 | if (parentAstSymbol) {
|
513 | const parentDeclaration = this._tryFindFirstAstDeclarationParent(declaration);
|
514 | if (!parentDeclaration) {
|
515 | throw new node_core_library_1.InternalError('Missing parent declaration');
|
516 | }
|
517 | parentAstDeclaration = this._astDeclarationsByDeclaration.get(parentDeclaration);
|
518 | if (!parentAstDeclaration) {
|
519 | throw new node_core_library_1.InternalError('Missing parent AstDeclaration');
|
520 | }
|
521 | }
|
522 | const astDeclaration = new AstDeclaration_1.AstDeclaration({
|
523 | declaration,
|
524 | astSymbol,
|
525 | parent: parentAstDeclaration
|
526 | });
|
527 | this._astDeclarationsByDeclaration.set(declaration, astDeclaration);
|
528 | }
|
529 | }
|
530 | if (options.isExternal !== astSymbol.isExternal) {
|
531 | throw new node_core_library_1.InternalError(`Cannot assign isExternal=${options.isExternal} for` +
|
532 | ` the symbol ${astSymbol.localName} because it was previously registered` +
|
533 | ` with isExternal=${astSymbol.isExternal}`);
|
534 | }
|
535 | return astSymbol;
|
536 | }
|
537 | |
538 |
|
539 |
|
540 | _tryFindFirstAstDeclarationParent(node) {
|
541 | let currentNode = node.parent;
|
542 | while (currentNode) {
|
543 | if (AstDeclaration_1.AstDeclaration.isSupportedSyntaxKind(currentNode.kind)) {
|
544 | return currentNode;
|
545 | }
|
546 | currentNode = currentNode.parent;
|
547 | }
|
548 | return undefined;
|
549 | }
|
550 | }
|
551 | exports.AstSymbolTable = AstSymbolTable;
|
552 |
|
\ | No newline at end of file |