@komaci/static-analyzer 240.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/build/WireGraph.d.ts +34 -0
  2. package/build/WireGraph.js +82 -0
  3. package/build/__mocks__/@babel/parser.d.ts +2 -0
  4. package/build/__mocks__/@babel/parser.js +6 -0
  5. package/build/adaptersMapping.d.ts +3 -0
  6. package/build/adaptersMapping.js +25 -0
  7. package/build/allowlistAdapters.d.ts +6 -0
  8. package/build/allowlistAdapters.js +10 -0
  9. package/build/index.d.ts +7 -0
  10. package/build/index.js +35 -0
  11. package/build/invariantFunctions/assignmentExpressionInvariantFunctions.d.ts +16 -0
  12. package/build/invariantFunctions/assignmentExpressionInvariantFunctions.js +34 -0
  13. package/build/invariantFunctions/callExpressionInvariantFunctions.d.ts +33 -0
  14. package/build/invariantFunctions/callExpressionInvariantFunctions.js +87 -0
  15. package/build/invariantFunctions/functionExpressionInvariantFunctions.d.ts +31 -0
  16. package/build/invariantFunctions/functionExpressionInvariantFunctions.js +69 -0
  17. package/build/invariantFunctions/identifierInvariantFunctions.d.ts +28 -0
  18. package/build/invariantFunctions/identifierInvariantFunctions.js +56 -0
  19. package/build/invariantFunctions/memberExpressionInvariantFunctions.d.ts +50 -0
  20. package/build/invariantFunctions/memberExpressionInvariantFunctions.js +146 -0
  21. package/build/invariantFunctions/returnStatementInvariantFunctions.d.ts +12 -0
  22. package/build/invariantFunctions/returnStatementInvariantFunctions.js +23 -0
  23. package/build/invariantFunctions/taggedTemplateExpressionInvariantFunctions.d.ts +12 -0
  24. package/build/invariantFunctions/taggedTemplateExpressionInvariantFunctions.js +25 -0
  25. package/build/komaci-mapping.json +288 -0
  26. package/build/rules.d.ts +22 -0
  27. package/build/rules.js +310 -0
  28. package/build/shared.d.ts +52 -0
  29. package/build/shared.js +184 -0
  30. package/build/staticAnalyzer.d.ts +100 -0
  31. package/build/staticAnalyzer.js +822 -0
  32. package/build/types.d.ts +102 -0
  33. package/build/types.js +3 -0
  34. package/build/validateGetter.d.ts +46 -0
  35. package/build/validateGetter.js +154 -0
  36. package/package.json +39 -0
@@ -0,0 +1,822 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.StaticAnalyzer = void 0;
23
+ const collector = __importStar(require("@lwc-platform/lwc-metadata-next"));
24
+ const rules_1 = require("./rules");
25
+ const common_shared_1 = require("@komaci/common-shared");
26
+ const shared_1 = require("./shared");
27
+ const WireGraph_1 = require("./WireGraph");
28
+ class StaticAnalyzer {
29
+ constructor() {
30
+ // TODO: Remove this sample Range when it is no longer needed as a placeholder
31
+ this.startPos = { line: 0, character: 0 };
32
+ this.endPos = { line: 0, character: 0 };
33
+ this.emptyRange = {
34
+ start: this.startPos,
35
+ end: this.endPos,
36
+ };
37
+ this.orderedWireInfos = [];
38
+ this.wireInfoMap = new Map();
39
+ this.fileNamesMap = new Map();
40
+ }
41
+ /**
42
+ * Given a bundle of files of different types (html, js), this method will perform static analysis of the input source files,
43
+ * and will output the result of the analysis as an array of PrimingDiagnostic objects that are compliant with the lightning language server specifications.
44
+ * @param input AnalyzerInput object containing the source files, their types, and namespace information required for analysis.
45
+ * @returns array of PrimingDiagnostic, with each element containing the analysis message and location information for IDE syntax underlining.
46
+ */
47
+ analyzeBundle(input) {
48
+ const diagnostics = [];
49
+ if (input.type === 'bundle') {
50
+ // generate komaciDoc from source file from collector in lwc-metadata-next package
51
+ const metadataObj = this.getMetadata(input);
52
+ if (metadataObj) {
53
+ let templateKomaciDoc;
54
+ let scriptKomaciDoc;
55
+ let sourceFileName;
56
+ let templateLimitReached = false;
57
+ for (const file of metadataObj.files) {
58
+ if (file.komaciDoc) {
59
+ if (file.fileName.split('.')[0] != input.name) {
60
+ continue; // ignore files whose name do not match module name
61
+ }
62
+ if (file.fileType === 'js') {
63
+ const fileName = file.fileName;
64
+ this.fileNamesMap.set('js', fileName);
65
+ sourceFileName = fileName;
66
+ scriptKomaciDoc = file.komaciDoc;
67
+ }
68
+ else if (file.fileType === 'html') {
69
+ if (templateLimitReached === true) {
70
+ // a template file has been processed already
71
+ diagnostics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_MULTIPLE_TEMPLATE_FILES, this.emptyRange, []), this.fileNamesMap.get('html')));
72
+ }
73
+ else {
74
+ templateKomaciDoc = file.komaciDoc;
75
+ templateLimitReached = true;
76
+ this.fileNamesMap.set('html', file.fileName);
77
+ }
78
+ }
79
+ }
80
+ }
81
+ if (sourceFileName && scriptKomaciDoc) {
82
+ const properties = (0, common_shared_1.collectPropertyMetadataFromScriptDoc)(scriptKomaciDoc);
83
+ if (templateKomaciDoc) {
84
+ (0, common_shared_1.updatePropertyMetadataFromTemplateDoc)(templateKomaciDoc, properties);
85
+ }
86
+ const srcCode = input.files[sourceFileName];
87
+ const getterFunctionDiagnostics = (0, shared_1.analyzeSrcForInvalidGetterFunctions)(srcCode, input.namespace, properties);
88
+ if (getterFunctionDiagnostics.length > 0) {
89
+ getterFunctionDiagnostics.map((diagnostic) => (0, rules_1.updatePrimingDiagnosticWithFileInfo)(diagnostic, sourceFileName));
90
+ diagnostics.push(...getterFunctionDiagnostics);
91
+ }
92
+ }
93
+ this.processKomaciScriptDoc(scriptKomaciDoc, diagnostics);
94
+ this.processKomaciTemplateDoc(templateKomaciDoc, scriptKomaciDoc, diagnostics);
95
+ }
96
+ return diagnostics;
97
+ }
98
+ else {
99
+ throw new Error(shared_1.ERROR_PREFIX +
100
+ 'this method was invoked with unexpected input type: ' +
101
+ input.type);
102
+ }
103
+ }
104
+ /**
105
+ * Given a script (JS) file, this method will perform static analysis of the input source JS files,
106
+ * and will output the result of the analysis as an array of PrimingDiagnostic objects that are compliant with the lightning language server specifications.
107
+ * @param input AnalyzerInput object containing the source JS files, namespace and other information required for analysis.
108
+ * @returns array of PrimingDiagnostic, with each element containing the analysis message and location information for IDE syntax underlining.
109
+ */
110
+ analyzeScript(input) {
111
+ const diagnostics = [];
112
+ if (input.type === 'file') {
113
+ // generate komaciDoc from source file from collector in lwc-metadata-next package
114
+ const metadataObj = this.getMetadata(input);
115
+ // since this is analyze script, this array only has one element for analyzeScript case.
116
+ const komaciDoc = metadataObj?.files[0].komaciDoc;
117
+ // get the file name and store for VSCode analysis display purposes
118
+ const fileName = metadataObj?.files[0].fileName;
119
+ this.fileNamesMap.set('js', fileName);
120
+ if (komaciDoc) {
121
+ const properties = (0, common_shared_1.collectPropertyMetadataFromScriptDoc)(komaciDoc);
122
+ const srcCode = input.sourceFile;
123
+ const getterFunctionDiagnostics = (0, shared_1.analyzeSrcForInvalidGetterFunctions)(srcCode, input.namespace, properties);
124
+ if (getterFunctionDiagnostics.length > 0) {
125
+ getterFunctionDiagnostics.map((diagnostic) => (0, rules_1.updatePrimingDiagnosticWithFileInfo)(diagnostic, this.fileNamesMap.get('js')));
126
+ diagnostics.push(...getterFunctionDiagnostics);
127
+ }
128
+ }
129
+ return this.processKomaciScriptDoc(komaciDoc, diagnostics);
130
+ }
131
+ else {
132
+ throw new Error(shared_1.ERROR_PREFIX +
133
+ 'this method was invoked with unexpected input type: ' +
134
+ input.type);
135
+ }
136
+ }
137
+ processKomaciScriptDoc(komaciDoc, diagnostics) {
138
+ if (komaciDoc && komaciDoc.adgs) {
139
+ for (const adg of komaciDoc.adgs) {
140
+ if (adg.functions) {
141
+ this.orderedWireInfos = this.reorderFunctionsByWireDependency(adg, adg.functions);
142
+ // loop on ordered WireInfos, fetch the FunctionType (function node) from there.
143
+ for (const wireInfo of this.orderedWireInfos) {
144
+ const func = wireInfo.wireFunction;
145
+ let problem;
146
+ // unit-tested by: artifact-script-files/wireImportUnresolved, artifact-script-files/invalidWireAdapter
147
+ problem = this.findUnresolvableWireAdaptersFromImports(func, komaciDoc.imports);
148
+ if (problem) {
149
+ wireInfo.isNonAnalyzable = true;
150
+ diagnostics.push(problem);
151
+ }
152
+ // unit-tested by: artifact-script-files/privatePropWireConfig
153
+ // using spread operator (...) to append more than one item (potentially) at the same time
154
+ problem = this.findWireConfigsThatUsePrivateProperty(adg, func);
155
+ if (problem && problem.length > 0) {
156
+ wireInfo.isNonAnalyzable = true;
157
+ diagnostics.push(...problem);
158
+ }
159
+ // unit-tested by: artifact-script-files/wireCfgGetterReturnsNonLiteral
160
+ problem = this.findWireConfigGetterReturningNonLiteral(adg, func);
161
+ if (problem && problem.length > 0) {
162
+ wireInfo.isNonAnalyzable = true;
163
+ diagnostics.push(...problem);
164
+ }
165
+ // unit-tested by: artifact-script-files/wireCfgGetterReturnsInaccessibleImports
166
+ problem =
167
+ this.findWireConfigForGetterReturningInaccessibleImports(adg, func, komaciDoc.imports);
168
+ if (problem && problem.length > 0) {
169
+ wireInfo.isNonAnalyzable = true;
170
+ diagnostics.push(...problem);
171
+ }
172
+ // unit-tested by: artifact-script-files/wireImportUnsupportedNamespace
173
+ problem = this.findWiresWithReactivePropNameFromUnsupportedNS(func, komaciDoc.imports);
174
+ if (problem && problem.length > 0) {
175
+ wireInfo.isNonAnalyzable = true;
176
+ diagnostics.push(...problem);
177
+ }
178
+ // unit-tested by: artifact-script-files/nonExistPropWireConfig
179
+ problem = this.findWireConfigReferenceNonExistProperty(adg, func);
180
+ if (problem && problem.length > 0) {
181
+ wireInfo.isNonAnalyzable = true;
182
+ diagnostics.push(...problem);
183
+ }
184
+ // unit-tested by: artifact-script-files/
185
+ problem = this.findPropagatedUnresolvedWireAdaptersFromConfigProp(wireInfo, this.orderedWireInfos);
186
+ if (problem && problem.length > 0) {
187
+ wireInfo.isNonAnalyzable = true;
188
+ diagnostics.push(...problem);
189
+ }
190
+ }
191
+ }
192
+ // unit-tested by: artifact-script-files/unresolvedParentClass
193
+ let diagnostic = this.findUnresolvedParentClass(adg);
194
+ if (diagnostic) {
195
+ diagnostics.push(diagnostic);
196
+ }
197
+ // unit-tested by: artifact-script-files/unresolvedRelativeImport
198
+ const diagnosticPc = this.findParentClassFromUnsupportedNS(adg, komaciDoc.imports);
199
+ if (diagnosticPc) {
200
+ diagnostics.push(diagnosticPc);
201
+ }
202
+ // unit-tested by: artifact-script-files/wireCircular(RefSimple|RefMedium|RefComplex)
203
+ diagnostic = this.findWireConfigReferenceCircularDependency();
204
+ if (diagnostic) {
205
+ diagnostics.push(diagnostic);
206
+ }
207
+ }
208
+ }
209
+ return diagnostics;
210
+ }
211
+ /**
212
+ * Given bundle komaciDocs, produce diagnostics for conditionals and iterators which are unanalyzable
213
+ * @param templateKomaciDoc KomaciDoc which provides composition information
214
+ * @param scriptKomaciDoc KomaciDoc which provides relevant adg information
215
+ * @returns array of PrimingDiagnostic, with each element containing the analysis message and location information for IDE syntax underlining.
216
+ */
217
+ processKomaciTemplateDoc(templateKomaciDoc, scriptKomaciDoc, diagnostics) {
218
+ if (templateKomaciDoc?.compositions &&
219
+ scriptKomaciDoc?.adgs &&
220
+ scriptKomaciDoc?.exports) {
221
+ const adgs = [];
222
+ const defaultExport = scriptKomaciDoc.exports['default'];
223
+ if (defaultExport && defaultExport.type === 'AdgReference') {
224
+ const defaultAdg = scriptKomaciDoc.adgs[defaultExport.value];
225
+ adgs.push(defaultAdg);
226
+ let parentClass = defaultAdg.parentClass;
227
+ while (parentClass?.type === 'AdgReference') {
228
+ const parentAdg = scriptKomaciDoc.adgs[parentClass.value];
229
+ adgs.push(parentAdg);
230
+ parentClass = parentAdg.parentClass;
231
+ }
232
+ }
233
+ const compositionArray = this.compositionsToArray(templateKomaciDoc.compositions);
234
+ for (const composition of compositionArray) {
235
+ // tested by: artifact-combined-files/unresolvableIterator
236
+ let diagnostic = this.findUnresolvableIterator(composition, adgs);
237
+ if (diagnostic) {
238
+ diagnostics.push(diagnostic);
239
+ }
240
+ // tested by: artifact-combined-files/unresolvableConditional
241
+ diagnostic = this.findUnresolvableConditional(composition, adgs);
242
+ if (diagnostic) {
243
+ diagnostics.push(diagnostic);
244
+ }
245
+ // test by: artifact-combined-files/unresolvedImageBinding
246
+ diagnostic = this.findUnresolvableImage(composition, adgs);
247
+ if (diagnostic) {
248
+ diagnostics.push(diagnostic);
249
+ }
250
+ }
251
+ }
252
+ return diagnostics;
253
+ }
254
+ findWireConfigsThatUsePrivateProperty(adg, func) {
255
+ const diagnostics = [];
256
+ if (adg.properties) {
257
+ if (func.type === shared_1.WIRE_FUNCTION && func.input && func.location) {
258
+ for (const inputProp of func.input) {
259
+ if (inputProp.type === 'ObjectValue') {
260
+ // inputProp.value = { recordId: {type: "", value: ""}}
261
+ for (const propName in inputProp.value) {
262
+ const prop = inputProp.value[propName];
263
+ // Looking for a PropertyReference type here. That's the only one we are interested in here
264
+ if (prop.type === 'PropertyReference') {
265
+ // We attempt a split in case we have a nested property name (ex: record.data.name)
266
+ // We only care about the first part (first element)
267
+ const adgPropName = prop.value.split('/')[0];
268
+ if (adg.properties[adgPropName] &&
269
+ !adg.properties[adgPropName].isPublic &&
270
+ !adg.properties[adgPropName].input) {
271
+ const parsedProps = adgPropName.split(',');
272
+ const range = shared_1.LLSRange.fromLWCSourceLocation(func.location);
273
+ const srcFileName = this.fileNamesMap.get('js');
274
+ if (parsedProps.length < 2) {
275
+ diagnostics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_PRIVATE_WIRE_CONFIG_PROPERTY, range, [parsedProps[0]]), srcFileName));
276
+ }
277
+ else {
278
+ diagnostics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_UNDEFINED_WIRE_CONFIG_PROPERTY, range, [parsedProps[0]]), srcFileName));
279
+ }
280
+ }
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ }
287
+ return diagnostics;
288
+ }
289
+ /**
290
+ * Traverses direct dependencies of the input wire (represented by a WireInfo) to see if any
291
+ * are non-analyzable. If any are, the input wire is also marked as non-analyzable, and a PrimingDiagnostic
292
+ * is generated for each dependency that is non-analyzable.
293
+ * @param wireInfo the current WireInfo to evaluate
294
+ * @param orderedWireInfos an array of dependency-sorted WireInfo against which to check the
295
+ * state of dependencies of wireInfo
296
+ * @returns array of PrimingDiagnostic containing a diagnostic for all non-analyzable wires found.
297
+ */
298
+ findPropagatedUnresolvedWireAdaptersFromConfigProp(wireInfo, orderedWireInfos) {
299
+ const diagnostics = [];
300
+ const funcObj = wireInfo.wireFunction;
301
+ for (const depWireInfo of wireInfo.dependentWires) {
302
+ const depFunc = depWireInfo.wireFunction;
303
+ const updatedWireInfo = orderedWireInfos.find((wire) => wire.funcIndex === depWireInfo.funcIndex);
304
+ if (updatedWireInfo?.isNonAnalyzable &&
305
+ depFunc &&
306
+ depFunc.type === 'WireFunction' &&
307
+ funcObj?.location) {
308
+ diagnostics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_WIRE_CONFIGURATION_PROPERTY_USING_OUTPUT_OF_NON_PRIMEABLE_WIRE, shared_1.LLSRange.fromLWCSourceLocation(funcObj.location), [updatedWireInfo.propName ? updatedWireInfo.propName : '']), this.fileNamesMap.get('js')));
309
+ }
310
+ }
311
+ return diagnostics;
312
+ }
313
+ findUnresolvableWireAdaptersFromImports(funcObj, imports) {
314
+ let unresolvableImport;
315
+ let importRef;
316
+ if (imports &&
317
+ funcObj.type === shared_1.WIRE_FUNCTION &&
318
+ funcObj.reference.type === 'ImportReference' &&
319
+ funcObj.location) {
320
+ // funcObj.location.
321
+ importRef = funcObj.reference.value; // ex: "2/names/0"
322
+ const importIndexArray = importRef.split('/');
323
+ // + operator converts string to number
324
+ const importIdx = +importIndexArray[0];
325
+ const nameIdx = +importIndexArray[2];
326
+ const komaciImport = imports[importIdx];
327
+ const importName = komaciImport.names[nameIdx];
328
+ if (!((0, shared_1.isSupportedNamespace)(komaciImport.resourceName) &&
329
+ (0, shared_1.isSupportedWireAdapter)(komaciImport.resourceName, imports[importIdx].names[nameIdx]))) {
330
+ unresolvableImport = {
331
+ name: importName,
332
+ namespace: imports[importIdx].resourceName,
333
+ location: funcObj.location,
334
+ };
335
+ }
336
+ }
337
+ else if (funcObj.type === shared_1.WIRE_FUNCTION &&
338
+ funcObj.reference.type === 'Unresolved' &&
339
+ funcObj.location) {
340
+ // this handles the corner case where an import wasn't declared, such that wire adapter's function reference type is "Unresolved"
341
+ unresolvableImport = {
342
+ name: 'unresolved',
343
+ namespace: 'unresolved',
344
+ location: funcObj.location,
345
+ };
346
+ }
347
+ let diagnostic;
348
+ if (unresolvableImport) {
349
+ const range = shared_1.LLSRange.fromLWCSourceLocation(unresolvableImport.location);
350
+ if (unresolvableImport.name !== 'unresolved' &&
351
+ unresolvableImport.namespace !== 'unresolved') {
352
+ diagnostic = (0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_WIRE_ADAPTER_OF_RESOURCE_CANNOT_BE_PRIMED, range, [unresolvableImport.name, unresolvableImport.namespace]);
353
+ (0, rules_1.updatePrimingDiagnosticWithFileInfo)(diagnostic, this.fileNamesMap.get('js'));
354
+ }
355
+ else {
356
+ diagnostic = (0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_MISSING_RESOURCE_CANNOT_PRIME_WIRE_ADAPTER, range, []);
357
+ (0, rules_1.updatePrimingDiagnosticWithFileInfo)(diagnostic, this.fileNamesMap.get('js'));
358
+ }
359
+ }
360
+ return diagnostic;
361
+ }
362
+ findWireConfigGetterReturningNonLiteral(adg, func) {
363
+ const diagnostics = [];
364
+ if (adg.properties) {
365
+ if (func.type === shared_1.WIRE_FUNCTION && func.input && func.location) {
366
+ for (const inputProp of func.input) {
367
+ if (inputProp.type === 'ObjectValue') {
368
+ // inputProp.value = { recordId: {type: "", value: ""}}
369
+ for (const wireCfgPropKey in inputProp.value) {
370
+ const prop = inputProp.value[wireCfgPropKey];
371
+ if (prop.type === 'PropertyReference') {
372
+ const adgPropName = prop.value.split('/')[0];
373
+ if (adg.properties[adgPropName]?.input?.type ===
374
+ 'Unresolved') {
375
+ diagnostics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_WIRE_CONFIG_PROPERTY_USES_GETTER_FUNCTION_RETURNING_NON_LITERAL, shared_1.LLSRange.fromLWCSourceLocation(func.location), [adgPropName]), this.fileNamesMap.get('js')));
376
+ }
377
+ }
378
+ }
379
+ }
380
+ }
381
+ }
382
+ }
383
+ return diagnostics;
384
+ }
385
+ findWireConfigForGetterReturningInaccessibleImports(adg, func, imports) {
386
+ const diagnostics = [];
387
+ if (adg.properties &&
388
+ func.type === shared_1.WIRE_FUNCTION &&
389
+ imports &&
390
+ func.input &&
391
+ func.location) {
392
+ for (const inputProp of func.input) {
393
+ if (inputProp.type === 'ObjectValue') {
394
+ // inputProp.value = { recordId: {type: "", value: ""}}
395
+ for (const propName in inputProp.value) {
396
+ const prop = inputProp.value[propName];
397
+ if (prop.type === 'PropertyReference') {
398
+ const adgPropName = prop.value.split('/')[0];
399
+ const property = adg.properties[adgPropName];
400
+ if (property?.input?.type === 'ImportReference') {
401
+ const importsArrIdx = +property.input?.value.split('/')[0];
402
+ const resourceName = imports[importsArrIdx].resourceName;
403
+ if (!(0, shared_1.isSupportedNamespace)(resourceName)) {
404
+ diagnostics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_WIRE_CONFIG_PROPERTY_USES_GETTER_FUNCTION_RETURNING_INACCESSIBLE_IMPORT, shared_1.LLSRange.fromLWCSourceLocation(func.location), [adgPropName]), this.fileNamesMap.get('js')));
405
+ }
406
+ }
407
+ }
408
+ }
409
+ }
410
+ }
411
+ }
412
+ return diagnostics;
413
+ }
414
+ findUnresolvedParentClass(adg) {
415
+ let diagnostic;
416
+ if (adg?.parentClass?.type === 'Unresolved') {
417
+ const range = shared_1.LLSRange.fromLWCSourceLocation(adg?.parentClass?.location);
418
+ diagnostic = (0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_UNRESOLVED_PARENT_CLASS_REFERENCE, range, []);
419
+ }
420
+ if (diagnostic) {
421
+ (0, rules_1.updatePrimingDiagnosticWithFileInfo)(diagnostic, this.fileNamesMap.get('js'));
422
+ }
423
+ return diagnostic;
424
+ }
425
+ findParentClassFromUnsupportedNS(adg, imports) {
426
+ let diagnostic;
427
+ let importRef;
428
+ if (adg?.parentClass?.type === 'ImportReference' && imports) {
429
+ importRef = adg?.parentClass?.value;
430
+ const importIndexArray = importRef.split('/');
431
+ const importIdx = +importIndexArray[0]; // + operator converts string to number
432
+ const myImport = imports[importIdx];
433
+ if (!(0, shared_1.isSupportedNamespace)(myImport.resourceName)) {
434
+ const range = shared_1.LLSRange.fromLWCSourceLocation(adg?.parentClass?.location);
435
+ diagnostic = (0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_CLASS_REFERS_TO_PARENT_CLASS_FROM_UNSUPPORTED_NAMESPACE, range, []);
436
+ (0, rules_1.updatePrimingDiagnosticWithFileInfo)(diagnostic, this.fileNamesMap.get('js'));
437
+ }
438
+ }
439
+ return diagnostic;
440
+ }
441
+ findWiresWithReactivePropNameFromUnsupportedNS(func, imports) {
442
+ const diagnostics = [];
443
+ if (func.type === shared_1.WIRE_FUNCTION && func.input && func.location && imports) {
444
+ for (const inputObj of func.input) {
445
+ if (inputObj.type === 'ObjectValue' && inputObj.value) {
446
+ for (const inputProp in inputObj.value) {
447
+ if (inputProp) {
448
+ if (inputObj.value[inputProp].type === 'ImportReference') {
449
+ const importNames = this.findImport(imports, inputObj.value[inputProp]);
450
+ if (!(0, shared_1.isSupportedNamespace)(importNames[1])) {
451
+ diagnostics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_WIRE_CONFIG_PROPERTY_USES_IMPORTED_ARTIFACT_FROM_UNSUPPORTED_NAMESPACE, shared_1.LLSRange.fromLWCSourceLocation(func.location), [importNames[0], importNames[1]]), this.fileNamesMap.get('js')));
452
+ }
453
+ }
454
+ else if (inputObj.value[inputProp].type === 'ArrayValue') {
455
+ const input = inputObj.value[inputProp];
456
+ // if nested within array, recurse to identify any unsupported ns
457
+ diagnostics.push(...this.findNestedUnsupportedNSArray(input, imports, func.location));
458
+ }
459
+ else if (inputObj.value[inputProp].type === 'ObjectValue') {
460
+ const input = inputObj.value[inputProp];
461
+ // if nested within object, recurse to identify any unsupported ns
462
+ diagnostics.push(...this.findNestedUnsupportedNSObject(input, imports, func.location));
463
+ }
464
+ }
465
+ }
466
+ }
467
+ }
468
+ }
469
+ return diagnostics;
470
+ }
471
+ /**
472
+ * identify unsupported namespaces usage nested within wireConfig array property
473
+ */
474
+ findNestedUnsupportedNSArray(input, imports, loc) {
475
+ const diagnostics = [];
476
+ const array = input.value;
477
+ for (const property of array) {
478
+ if (property.type === 'ArrayValue') {
479
+ // if nested further, continue recursion
480
+ const newInput = property;
481
+ diagnostics.push(...this.findNestedUnsupportedNSArray(newInput, imports, loc));
482
+ }
483
+ else if (property.type === 'ObjectValue') {
484
+ // if nested further, continue recursion
485
+ const newInput = property;
486
+ diagnostics.push(...this.findNestedUnsupportedNSObject(newInput, imports, loc));
487
+ }
488
+ else if (property.type === 'ImportReference') {
489
+ const importNames = this.findImport(imports, property);
490
+ if (!(0, shared_1.isSupportedNamespace)(importNames[1])) {
491
+ diagnostics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_WIRE_CONFIG_PROPERTY_USES_IMPORTED_ARTIFACT_FROM_UNSUPPORTED_NAMESPACE, shared_1.LLSRange.fromLWCSourceLocation(loc), [importNames[0], importNames[1]]), this.fileNamesMap.get('js')));
492
+ }
493
+ }
494
+ }
495
+ return diagnostics;
496
+ }
497
+ /**
498
+ * identify unsupported namespaces usage nested within wireConfig object property
499
+ */
500
+ findNestedUnsupportedNSObject(input, imports, loc) {
501
+ const diagnostics = [];
502
+ const object = input.value;
503
+ Object.keys(object).forEach((key) => {
504
+ if (object[key].type === 'ImportReference') {
505
+ const importNames = this.findImport(imports, object[key]);
506
+ if (!(0, shared_1.isSupportedNamespace)(importNames[1])) {
507
+ diagnostics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_WIRE_CONFIG_PROPERTY_USES_IMPORTED_ARTIFACT_FROM_UNSUPPORTED_NAMESPACE, shared_1.LLSRange.fromLWCSourceLocation(loc), [importNames[0], importNames[1]]), this.fileNamesMap.get('js')));
508
+ }
509
+ }
510
+ else if (object[key].type === 'ArrayValue') {
511
+ // if nested further, continue recursion
512
+ const newInput = object[key];
513
+ diagnostics.push(...this.findNestedUnsupportedNSArray(newInput, imports, loc));
514
+ }
515
+ else if (object[key].type === 'ObjectValue') {
516
+ // if nested further, continue recursion
517
+ const newInput = object[key];
518
+ diagnostics.push(...this.findNestedUnsupportedNSObject(newInput, imports, loc));
519
+ }
520
+ });
521
+ return diagnostics;
522
+ }
523
+ findWireConfigReferenceNonExistProperty(adg, func) {
524
+ const diagnostics = [];
525
+ if (func.type === shared_1.WIRE_FUNCTION && func.input && func.location) {
526
+ for (const inputObj of func.input) {
527
+ if (inputObj.type === 'ObjectValue' && inputObj.value) {
528
+ for (const propName in inputObj.value) {
529
+ const prop = inputObj.value[propName];
530
+ if (prop.type === 'PropertyReference') {
531
+ const propName = prop.value.split('/')[0];
532
+ if (!adg.properties ||
533
+ adg.properties[propName] === undefined) {
534
+ diagnostics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_WIRE_CONFIG_REFERENCES_NON_LOCAL_PROPERTY_REACTIVE_VALUE, shared_1.LLSRange.fromLWCSourceLocation(func.location), [propName]), this.fileNamesMap.get('js')));
535
+ }
536
+ }
537
+ }
538
+ }
539
+ }
540
+ }
541
+ return diagnostics;
542
+ }
543
+ /**
544
+ * Produce diagnostics for iterators which iterate on unresolvable inputs, such as private properties
545
+ * or wired properties which associated to unresolvable wires
546
+ */
547
+ findUnresolvableIterator(composition, adgs) {
548
+ if (composition.type === 'Iteration') {
549
+ const iteration = composition;
550
+ const propName = iteration.input.value.split('/')[0];
551
+ for (const wire of this.orderedWireInfos) {
552
+ if (wire.propName === propName &&
553
+ wire.isNonAnalyzable &&
554
+ adgs.includes(wire.adg)) {
555
+ return (0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_ITERATE_ON_UNANALYZABLE_PROPERTY_FROM_UNRESOLVABLE_WIRE, shared_1.LLSRange.fromLWCSourceLocation(composition.location), [propName]), this.fileNamesMap.get('html'));
556
+ }
557
+ }
558
+ for (const adg of adgs) {
559
+ if (adg.properties && adg.properties[propName]) {
560
+ const prop = adg.properties[propName];
561
+ if (prop.input) {
562
+ if (prop.input.type === 'Unresolved') {
563
+ return (0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_ITERATE_ON_UNANALYZABLE_GETTER_PROPERTY, shared_1.LLSRange.fromLWCSourceLocation(composition.location), [propName]), this.fileNamesMap.get('html'));
564
+ }
565
+ }
566
+ else {
567
+ if (!prop.isPublic) {
568
+ return (0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_CONDITIONAL_USING_UNANALYZABLE_NON_PUBLIC_PROPERTY, shared_1.LLSRange.fromLWCSourceLocation(composition.location), [propName]), this.fileNamesMap.get('html'));
569
+ }
570
+ }
571
+ }
572
+ }
573
+ }
574
+ return;
575
+ }
576
+ /**
577
+ * Produce diagnostics for conditionals which act upon unresolvable inputs, such as private properties
578
+ * or wired properties which associated to unresolvable wires
579
+ */
580
+ findUnresolvableConditional(composition, adgs) {
581
+ if (composition.type === 'Container') {
582
+ if (composition.isActive) {
583
+ const propName = composition.isActive.input.value.split('/')[0];
584
+ for (const wire of this.orderedWireInfos) {
585
+ if (wire.propName === propName &&
586
+ wire.isNonAnalyzable &&
587
+ adgs.includes(wire.adg)) {
588
+ const fileNameHTML = this.fileNamesMap.get('html');
589
+ return (0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_CONDITIONAL_USING_PROPERTY_FROM_UNRESOLVABLE_WIRE, shared_1.LLSRange.fromLWCSourceLocation(composition.location), [propName]), fileNameHTML);
590
+ }
591
+ }
592
+ for (const adg of adgs) {
593
+ if (adg.properties && adg.properties[propName]) {
594
+ const prop = adg.properties[propName];
595
+ if (prop.input) {
596
+ if (prop.input.type === 'Unresolved') {
597
+ return (0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_CONDITIONAL_ON_UNANALYZABLE_GETTER_PROPERTY, shared_1.LLSRange.fromLWCSourceLocation(composition.location), [propName]), this.fileNamesMap.get('html'));
598
+ }
599
+ }
600
+ else {
601
+ if (!prop.isPublic) {
602
+ return (0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_CONDITIONAL_USING_UNANALYZABLE_NON_PUBLIC_PROPERTY, shared_1.LLSRange.fromLWCSourceLocation(composition.location), [propName]), this.fileNamesMap.get('html'));
603
+ }
604
+ }
605
+ }
606
+ }
607
+ }
608
+ }
609
+ return;
610
+ }
611
+ /**
612
+ * Produces diagnostic for images which refer to unresolvable `src` attributes within the `<img>` tag.
613
+ * Note that Images are a type of Composition
614
+ *
615
+ * @param {Composition} image the composition containing the Image
616
+ * @param {Adg[]} adgs an array of ADGs
617
+ * @returns {PrimingDiagnostic} a PrimingDiagnostic if an image with unresolvable `src` attribute is found. void otherwise
618
+ */
619
+ findUnresolvableImage(image, adgs) {
620
+ if ((0, shared_1.isImageComposition)(image)) {
621
+ if (image.src.type === 'Binding') {
622
+ const propName = image.src.value;
623
+ for (const adg of adgs) {
624
+ if (adg.properties?.[propName]) {
625
+ const prop = adg.properties[propName];
626
+ if (prop.initial?.type === 'Unresolved') {
627
+ return (0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_IMAGE_REFERENCE_UNANALYZABLE_SOURCE_PROPERTY,
628
+ // TODO: currently is an emptyRange location. May need to add support
629
+ // for location of image tags. Created work item W-11309043 for this
630
+ shared_1.LLSRange.fromLWCSourceLocation(image.location), [propName]), this.fileNamesMap.get('html'));
631
+ }
632
+ }
633
+ else {
634
+ // property in image src attribute is not found in the script file, so return a dianostic
635
+ // for this situation too.
636
+ return (0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_IMAGE_REFERENCE_MISSING_SOURCE_PROPERTY,
637
+ // TODO: currently is an emptyRange location. May need to add support
638
+ // for location of image tags. Created work item W-11309043 for this
639
+ shared_1.LLSRange.fromLWCSourceLocation(image.location), [propName]), this.fileNamesMap.get('html'));
640
+ }
641
+ }
642
+ }
643
+ }
644
+ return;
645
+ }
646
+ /**
647
+ * Convert array of Compositions into flattened array of Compositions,
648
+ * visiting top-level and nested children compositions
649
+ */
650
+ compositionsToArray(compositions) {
651
+ const compositionArray = [];
652
+ compositions.forEach((node) => {
653
+ compositionArray.push(node);
654
+ if (node.compositions) {
655
+ compositionArray.push(...this.compositionsToArray(node.compositions));
656
+ }
657
+ });
658
+ return compositionArray;
659
+ }
660
+ /**
661
+ * find Import name information (resourceName, importName) given komaciDoc imports and reference
662
+ */
663
+ findImport(imports, property) {
664
+ const importRef = property.value; // casting as expecting string type
665
+ const importIndexArray = importRef.split('/');
666
+ const importIdx = +importIndexArray[0]; // + operator converts string to number
667
+ const nameIdx = +importIndexArray[2];
668
+ const myImport = imports[importIdx];
669
+ const importName = myImport.names[nameIdx];
670
+ return [importName, myImport.resourceName];
671
+ }
672
+ getMetadata(input) {
673
+ let bundleMetadata;
674
+ // using a type guard to distinguish between interface types
675
+ if (input.type === 'file') {
676
+ bundleMetadata = collector.collectBundleMetadata({
677
+ namespace: input.namespace,
678
+ name: input.name,
679
+ type: 'platform',
680
+ namespaceMapping: {},
681
+ files: [{ fileName: input.fileName, source: input.sourceFile }],
682
+ enableKomaci: true,
683
+ });
684
+ }
685
+ else if (input.type === 'bundle') {
686
+ const fileEntries = [];
687
+ for (const filename in input.files) {
688
+ fileEntries.push({
689
+ fileName: filename,
690
+ source: input.files[filename],
691
+ });
692
+ }
693
+ bundleMetadata = collector.collectBundleMetadata({
694
+ namespace: input.namespace,
695
+ name: input.name,
696
+ type: 'platform',
697
+ namespaceMapping: {},
698
+ files: fileEntries,
699
+ enableKomaci: true,
700
+ });
701
+ }
702
+ else {
703
+ throw new Error(shared_1.ERROR_PREFIX + 'invalid input type. Cannot retrieve metadata from input.');
704
+ }
705
+ return bundleMetadata;
706
+ }
707
+ findWireConfigReferenceCircularDependency() {
708
+ const linkedWireInfos = [];
709
+ this.wireInfoMap.forEach((wireInfo) => {
710
+ linkedWireInfos.push(wireInfo);
711
+ });
712
+ const dependencyGraph = new WireGraph_1.WireGraph(linkedWireInfos);
713
+ if (dependencyGraph.hasCycle()) {
714
+ const wire = dependencyGraph.getWireThatCycles();
715
+ if (wire && wire.wireFunction && wire.wireFunction.location) {
716
+ return (0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_WIRE_CONFIG_PROPERTY_CIRCULAR_WIRE_DEPENDENCY, shared_1.LLSRange.fromLWCSourceLocation(wire.wireFunction.location), [
717
+ dependencyGraph.getWireCycleProperty(),
718
+ dependencyGraph.getWireCycleString(),
719
+ ]), this.fileNamesMap.get('js'));
720
+ }
721
+ }
722
+ return undefined;
723
+ }
724
+ /**
725
+ * Given an input array of FunctionType function nodes, this method creates an array of WireInfo that is
726
+ * ordered in such a way that independent WireFunction nodes are placed towards the beginning of the array, and the
727
+ * most dependent ones are placed towards the end of the array, so that iterating the array from beginning to end
728
+ * while evaluating wire conditions without running into unencountered dependencies is actually possible
729
+ * @param adg Adg, containing needed properties for this method
730
+ * @param funcs Array of FunctionType, which correspond to WireInfos that this method creates
731
+ * @returns and array of WireInfo, which contain references to FunctionType nodes for Wires, and other important state
732
+ */
733
+ reorderFunctionsByWireDependency(adg, funcs) {
734
+ const srcOrderedWireInfos = [];
735
+ for (const funcIdx in funcs) {
736
+ // build up the wireInfos and buid dependency list
737
+ if (funcs[funcIdx].type === 'WireFunction' && adg.properties) {
738
+ // find or create WireInfo associated with function
739
+ const wireInfo = this.findWireInfo(+funcIdx, adg, funcs);
740
+ srcOrderedWireInfos.push(wireInfo);
741
+ // find dependencies of the WireInfo, and create those and add to the original wireInfo
742
+ const funcInputArray = funcs[funcIdx].input;
743
+ if (funcInputArray &&
744
+ funcInputArray[0] &&
745
+ funcInputArray[0].type === 'ObjectValue' &&
746
+ funcInputArray[0].value) {
747
+ // per Komaci spec: "The input of the function is an array with a single element of type object"
748
+ // so we can assume a single input in the input array passed to this method
749
+ for (const configObj of Object.values(funcInputArray[0].value)) {
750
+ if (configObj.type === 'PropertyReference') {
751
+ const propToEval = configObj.value;
752
+ const propToEvalParsed = propToEval.split('/');
753
+ for (const [propName, propValue] of Object.entries(adg.properties)) {
754
+ // does the wire config property refer to another wire?
755
+ if (propName === propToEvalParsed[0] && // we only care about top level property. ex: wireOutput1 from wireOutput1/data
756
+ propValue.input?.type === 'FunctionReference') {
757
+ // add the depWireInfo that the wireInfo depends on
758
+ const funcIdx = propValue.input.value;
759
+ wireInfo.dependentWires.push(this.findWireInfo(+funcIdx, adg, funcs));
760
+ }
761
+ }
762
+ }
763
+ }
764
+ }
765
+ }
766
+ }
767
+ return srcOrderedWireInfos.sort((wire1, wire2) => {
768
+ if (this.dependsOn(wire1, wire2) && this.dependsOn(wire2, wire1)) {
769
+ return 0;
770
+ }
771
+ else if (this.dependsOn(wire1, wire2)) {
772
+ return 1;
773
+ }
774
+ else if (this.dependsOn(wire2, wire1)) {
775
+ return -1;
776
+ }
777
+ return 0;
778
+ });
779
+ }
780
+ // comparator function compatible with Array.sort() method
781
+ // Determines if wire1 depends on wire2
782
+ dependsOn(wire1, wire2) {
783
+ for (const index in wire1.dependentWires) {
784
+ const depWire = wire1.dependentWires[index];
785
+ if (wire2.funcIndex === depWire.funcIndex) {
786
+ return true;
787
+ }
788
+ }
789
+ return false;
790
+ }
791
+ // acquire wired property name and use to create WireInfo, if not already created
792
+ findWireInfo(index, adg, funcs) {
793
+ let wireInfo = this.wireInfoMap.get(index);
794
+ if (!wireInfo) {
795
+ // find property name
796
+ let propertyName = undefined;
797
+ for (const propName in adg.properties) {
798
+ if (adg.properties[propName].input?.type === 'FunctionReference' &&
799
+ adg.properties[propName].input?.value === index) {
800
+ propertyName = propName;
801
+ break;
802
+ }
803
+ }
804
+ // create new WireInfo
805
+ wireInfo = {
806
+ funcIndex: index,
807
+ isNonAnalyzable: false,
808
+ dependentWires: [],
809
+ location: undefined,
810
+ wireFunction: funcs[index],
811
+ propName: propertyName,
812
+ adg: adg,
813
+ beingVisited: false,
814
+ visited: false,
815
+ };
816
+ this.wireInfoMap.set(index, wireInfo);
817
+ }
818
+ return wireInfo;
819
+ }
820
+ }
821
+ exports.StaticAnalyzer = StaticAnalyzer;
822
+ //# sourceMappingURL=staticAnalyzer.js.map