@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.
- package/build/WireGraph.d.ts +34 -0
- package/build/WireGraph.js +82 -0
- package/build/__mocks__/@babel/parser.d.ts +2 -0
- package/build/__mocks__/@babel/parser.js +6 -0
- package/build/adaptersMapping.d.ts +3 -0
- package/build/adaptersMapping.js +25 -0
- package/build/allowlistAdapters.d.ts +6 -0
- package/build/allowlistAdapters.js +10 -0
- package/build/index.d.ts +7 -0
- package/build/index.js +35 -0
- package/build/invariantFunctions/assignmentExpressionInvariantFunctions.d.ts +16 -0
- package/build/invariantFunctions/assignmentExpressionInvariantFunctions.js +34 -0
- package/build/invariantFunctions/callExpressionInvariantFunctions.d.ts +33 -0
- package/build/invariantFunctions/callExpressionInvariantFunctions.js +87 -0
- package/build/invariantFunctions/functionExpressionInvariantFunctions.d.ts +31 -0
- package/build/invariantFunctions/functionExpressionInvariantFunctions.js +69 -0
- package/build/invariantFunctions/identifierInvariantFunctions.d.ts +28 -0
- package/build/invariantFunctions/identifierInvariantFunctions.js +56 -0
- package/build/invariantFunctions/memberExpressionInvariantFunctions.d.ts +50 -0
- package/build/invariantFunctions/memberExpressionInvariantFunctions.js +146 -0
- package/build/invariantFunctions/returnStatementInvariantFunctions.d.ts +12 -0
- package/build/invariantFunctions/returnStatementInvariantFunctions.js +23 -0
- package/build/invariantFunctions/taggedTemplateExpressionInvariantFunctions.d.ts +12 -0
- package/build/invariantFunctions/taggedTemplateExpressionInvariantFunctions.js +25 -0
- package/build/komaci-mapping.json +288 -0
- package/build/rules.d.ts +22 -0
- package/build/rules.js +310 -0
- package/build/shared.d.ts +52 -0
- package/build/shared.js +184 -0
- package/build/staticAnalyzer.d.ts +100 -0
- package/build/staticAnalyzer.js +822 -0
- package/build/types.d.ts +102 -0
- package/build/types.js +3 -0
- package/build/validateGetter.d.ts +46 -0
- package/build/validateGetter.js +154 -0
- 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
|