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.ValidationEnhancer = void 0;
|
29 | const path = __importStar(require("path"));
|
30 | const ts = __importStar(require("typescript"));
|
31 | const AstSymbol_1 = require("../analyzer/AstSymbol");
|
32 | const api_extractor_model_1 = require("@microsoft/api-extractor-model");
|
33 | const AstNamespaceImport_1 = require("../analyzer/AstNamespaceImport");
|
34 | class ValidationEnhancer {
|
35 | static analyze(collector) {
|
36 | const alreadyWarnedEntities = new Set();
|
37 | for (const entity of collector.entities) {
|
38 | if (!entity.consumable) {
|
39 | continue;
|
40 | }
|
41 | if (entity.astEntity instanceof AstSymbol_1.AstSymbol) {
|
42 |
|
43 | const astSymbol = entity.astEntity;
|
44 | astSymbol.forEachDeclarationRecursive((astDeclaration) => {
|
45 | ValidationEnhancer._checkReferences(collector, astDeclaration, alreadyWarnedEntities);
|
46 | });
|
47 | const symbolMetadata = collector.fetchSymbolMetadata(astSymbol);
|
48 | ValidationEnhancer._checkForInternalUnderscore(collector, entity, astSymbol, symbolMetadata);
|
49 | ValidationEnhancer._checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata);
|
50 | }
|
51 | else if (entity.astEntity instanceof AstNamespaceImport_1.AstNamespaceImport) {
|
52 |
|
53 | const astNamespaceImport = entity.astEntity;
|
54 | const astModuleExportInfo = astNamespaceImport.fetchAstModuleExportInfo(collector);
|
55 | for (const namespaceMemberAstEntity of astModuleExportInfo.exportedLocalEntities.values()) {
|
56 | if (namespaceMemberAstEntity instanceof AstSymbol_1.AstSymbol) {
|
57 | const astSymbol = namespaceMemberAstEntity;
|
58 | astSymbol.forEachDeclarationRecursive((astDeclaration) => {
|
59 | ValidationEnhancer._checkReferences(collector, astDeclaration, alreadyWarnedEntities);
|
60 | });
|
61 | const symbolMetadata = collector.fetchSymbolMetadata(astSymbol);
|
62 |
|
63 | ValidationEnhancer._checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata);
|
64 | }
|
65 | }
|
66 | }
|
67 | }
|
68 | }
|
69 | static _checkForInternalUnderscore(collector, collectorEntity, astSymbol, symbolMetadata) {
|
70 | let needsUnderscore = false;
|
71 | if (symbolMetadata.maxEffectiveReleaseTag === api_extractor_model_1.ReleaseTag.Internal) {
|
72 | if (!astSymbol.parentAstSymbol) {
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | needsUnderscore = true;
|
84 | }
|
85 | else {
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 | const parentSymbolMetadata = collector.fetchSymbolMetadata(astSymbol);
|
101 | if (parentSymbolMetadata.maxEffectiveReleaseTag > api_extractor_model_1.ReleaseTag.Internal) {
|
102 | needsUnderscore = true;
|
103 | }
|
104 | }
|
105 | }
|
106 | if (needsUnderscore) {
|
107 | for (const exportName of collectorEntity.exportNames) {
|
108 | if (exportName[0] !== '_') {
|
109 | collector.messageRouter.addAnalyzerIssue("ae-internal-missing-underscore" , `The name "${exportName}" should be prefixed with an underscore` +
|
110 | ` because the declaration is marked as @internal`, astSymbol, { exportName });
|
111 | }
|
112 | }
|
113 | }
|
114 | }
|
115 | static _checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata) {
|
116 | if (astSymbol.isExternal) {
|
117 |
|
118 |
|
119 | return;
|
120 | }
|
121 |
|
122 |
|
123 | const expectedEffectiveReleaseTag = symbolMetadata.maxEffectiveReleaseTag;
|
124 |
|
125 | let mixedReleaseTags = false;
|
126 |
|
127 | let onlyFunctionOverloads = true;
|
128 |
|
129 | let anyInternalReleaseTags = false;
|
130 | for (const astDeclaration of astSymbol.astDeclarations) {
|
131 | const apiItemMetadata = collector.fetchApiItemMetadata(astDeclaration);
|
132 | const effectiveReleaseTag = apiItemMetadata.effectiveReleaseTag;
|
133 | switch (astDeclaration.declaration.kind) {
|
134 | case ts.SyntaxKind.FunctionDeclaration:
|
135 | case ts.SyntaxKind.MethodDeclaration:
|
136 | break;
|
137 | default:
|
138 | onlyFunctionOverloads = false;
|
139 | }
|
140 | if (effectiveReleaseTag !== expectedEffectiveReleaseTag) {
|
141 | mixedReleaseTags = true;
|
142 | }
|
143 | if (effectiveReleaseTag === api_extractor_model_1.ReleaseTag.Internal) {
|
144 | anyInternalReleaseTags = true;
|
145 | }
|
146 | }
|
147 | if (mixedReleaseTags) {
|
148 | if (!onlyFunctionOverloads) {
|
149 | collector.messageRouter.addAnalyzerIssue("ae-different-release-tags" , 'This symbol has another declaration with a different release tag', astSymbol);
|
150 | }
|
151 | if (anyInternalReleaseTags) {
|
152 | collector.messageRouter.addAnalyzerIssue("ae-internal-mixed-release-tag" , `Mixed release tags are not allowed for "${astSymbol.localName}" because one of its declarations` +
|
153 | ` is marked as @internal`, astSymbol);
|
154 | }
|
155 | }
|
156 | }
|
157 | static _checkReferences(collector, astDeclaration, alreadyWarnedEntities) {
|
158 | const apiItemMetadata = collector.fetchApiItemMetadata(astDeclaration);
|
159 | const declarationReleaseTag = apiItemMetadata.effectiveReleaseTag;
|
160 | for (const referencedEntity of astDeclaration.referencedAstEntities) {
|
161 | let collectorEntity;
|
162 | let referencedReleaseTag;
|
163 | let localName;
|
164 | if (referencedEntity instanceof AstSymbol_1.AstSymbol) {
|
165 |
|
166 |
|
167 |
|
168 |
|
169 | const rootSymbol = referencedEntity.rootAstSymbol;
|
170 | if (rootSymbol.isExternal) {
|
171 | continue;
|
172 | }
|
173 | localName = rootSymbol.localName;
|
174 | collectorEntity = collector.tryGetCollectorEntity(rootSymbol);
|
175 | const referencedMetadata = collector.fetchSymbolMetadata(referencedEntity);
|
176 | referencedReleaseTag = referencedMetadata.maxEffectiveReleaseTag;
|
177 | }
|
178 | else if (referencedEntity instanceof AstNamespaceImport_1.AstNamespaceImport) {
|
179 | collectorEntity = collector.tryGetCollectorEntity(referencedEntity);
|
180 |
|
181 | referencedReleaseTag = api_extractor_model_1.ReleaseTag.Public;
|
182 | localName = referencedEntity.localName;
|
183 | }
|
184 | else {
|
185 | continue;
|
186 | }
|
187 | if (collectorEntity && collectorEntity.consumable) {
|
188 | if (api_extractor_model_1.ReleaseTag.compare(declarationReleaseTag, referencedReleaseTag) > 0) {
|
189 | collector.messageRouter.addAnalyzerIssue("ae-incompatible-release-tags" , `The symbol "${astDeclaration.astSymbol.localName}"` +
|
190 | ` is marked as ${api_extractor_model_1.ReleaseTag.getTagName(declarationReleaseTag)},` +
|
191 | ` but its signature references "${referencedEntity.localName}"` +
|
192 | ` which is marked as ${api_extractor_model_1.ReleaseTag.getTagName(referencedReleaseTag)}`, astDeclaration);
|
193 | }
|
194 | }
|
195 | else {
|
196 | const entryPointFilename = path.basename(collector.workingPackage.entryPointSourceFile.fileName);
|
197 | if (!alreadyWarnedEntities.has(referencedEntity)) {
|
198 | alreadyWarnedEntities.add(referencedEntity);
|
199 | if (referencedEntity instanceof AstSymbol_1.AstSymbol &&
|
200 | ValidationEnhancer._isEcmaScriptSymbol(referencedEntity)) {
|
201 |
|
202 |
|
203 | }
|
204 | else {
|
205 | collector.messageRouter.addAnalyzerIssue("ae-forgotten-export" , `The symbol "${localName}" needs to be exported by the entry point ${entryPointFilename}`, astDeclaration);
|
206 | }
|
207 | }
|
208 | }
|
209 | }
|
210 | }
|
211 |
|
212 |
|
213 |
|
214 | static _isEcmaScriptSymbol(astSymbol) {
|
215 | if (astSymbol.astDeclarations.length !== 1) {
|
216 | return false;
|
217 | }
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 | const astDeclaration = astSymbol.astDeclarations[0];
|
227 | if (ts.isVariableDeclaration(astDeclaration.declaration)) {
|
228 | const variableTypeNode = astDeclaration.declaration.type;
|
229 | if (variableTypeNode) {
|
230 | for (const token of variableTypeNode.getChildren()) {
|
231 | if (token.kind === ts.SyntaxKind.SymbolKeyword) {
|
232 | return true;
|
233 | }
|
234 | }
|
235 | }
|
236 | }
|
237 | return false;
|
238 | }
|
239 | }
|
240 | exports.ValidationEnhancer = ValidationEnhancer;
|
241 |
|
\ | No newline at end of file |