@komaci/static-analyzer 240.1.3 → 242.1.0
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/helpers.d.ts +10 -0
- package/build/helpers.js +87 -0
- package/build/index.d.ts +2 -2
- package/build/index.js +6 -4
- package/build/invariantFunctions/assignmentExpressionInvariantFunctions.js +2 -2
- package/build/invariantFunctions/callExpressionInvariantFunctions.d.ts +2 -2
- package/build/invariantFunctions/callExpressionInvariantFunctions.js +9 -9
- package/build/invariantFunctions/functionExpressionInvariantFunctions.js +4 -4
- package/build/invariantFunctions/identifierInvariantFunctions.d.ts +2 -2
- package/build/invariantFunctions/identifierInvariantFunctions.js +5 -3
- package/build/invariantFunctions/memberExpressionInvariantFunctions.d.ts +5 -5
- package/build/invariantFunctions/memberExpressionInvariantFunctions.js +21 -38
- package/build/invariantFunctions/taggedTemplateExpressionInvariantFunctions.d.ts +2 -2
- package/build/invariantFunctions/taggedTemplateExpressionInvariantFunctions.js +5 -5
- package/build/rules.js +8 -44
- package/build/shared.d.ts +21 -17
- package/build/shared.js +92 -81
- package/build/staticAnalyzer.d.ts +10 -22
- package/build/staticAnalyzer.js +92 -132
- package/build/types.d.ts +17 -0
- package/build/validateGetter.d.ts +4 -4
- package/build/validateGetter.js +65 -61
- package/package.json +6 -8
- package/build/adaptersMapping.d.ts +0 -3
- package/build/adaptersMapping.js +0 -25
- package/build/allowlistAdapters.d.ts +0 -6
- package/build/allowlistAdapters.js +0 -10
- package/build/komaci-mapping.json +0 -288
package/build/shared.d.ts
CHANGED
|
@@ -1,26 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import * as t from '@babel/types';
|
|
2
|
+
import { ModuleContext } from '@komaci/common-shared';
|
|
3
|
+
import { GetterDiagnosticsContext, TemplateDiagnosticsContext } from './types';
|
|
3
4
|
import { SourceLocation } from '@babel/types';
|
|
4
|
-
import {
|
|
5
|
+
import { Range } from '.';
|
|
5
6
|
import { Composition, Image, SourceLocation as KomaciSourceLocation } from '@komaci/types';
|
|
7
|
+
import { ModuleMetadata } from '@komaci/common-shared';
|
|
6
8
|
export declare const WIRE_FUNCTION = "WireFunction";
|
|
7
9
|
export declare const ERROR_PREFIX = "[komaci static-analyzer] ";
|
|
8
|
-
/**
|
|
9
|
-
* Determine whether the wire adapter is supported
|
|
10
|
-
* @param resourceName the resource name of the Import, as a string
|
|
11
|
-
* @param adapterName the wire adapter variable name (import specifier export name) from a single
|
|
12
|
-
* Import statement (which can have more than one of these export names)
|
|
13
|
-
* @returns boolean true if the adapterName represents is a supported wire adapter (note that some
|
|
14
|
-
* resourceNames allow any adapterName as valid wire adapters)
|
|
15
|
-
*/
|
|
16
|
-
export declare function isSupportedWireAdapter(resourceName: string | undefined, adapterName: string | undefined): boolean;
|
|
17
10
|
/**
|
|
18
11
|
* Determine whether the resource name is in a supported namespace
|
|
19
12
|
* @param resourceName the resource name of the Import, as a string
|
|
20
13
|
* @returns boolean true if the resource name is in a supported namespace
|
|
21
14
|
*/
|
|
22
15
|
export declare function isSupportedNamespace(resourceName: string | undefined): boolean;
|
|
23
|
-
export declare const getPrimingAdapter: GetPrimingAdapter;
|
|
24
16
|
export declare const LLSRange: {
|
|
25
17
|
/**
|
|
26
18
|
* Converts an lwc-metadata SourceLocation (1-indexed for both line and column) into a Lightning Language
|
|
@@ -38,11 +30,23 @@ export declare const LLSRange: {
|
|
|
38
30
|
fromBabelSourceLocation({ start, end }: SourceLocation): Range;
|
|
39
31
|
};
|
|
40
32
|
/**
|
|
41
|
-
* Function to analyze
|
|
42
|
-
* @param
|
|
43
|
-
* @param
|
|
33
|
+
* Function to analyze src code and returns any diagnostics found and valid getter contexts in a GetterDiagnosticContext
|
|
34
|
+
* @param adgIndex index of the current adg to process
|
|
35
|
+
* @param rootAst the Abstract Syntax Tree for the component
|
|
36
|
+
* @param moduleMetadata metadata about the given component
|
|
37
|
+
* @param moduleContext contextual details about the component, like module level variables, etc
|
|
38
|
+
* @returns diagnostics for the getters
|
|
39
|
+
*/
|
|
40
|
+
export declare function analyzeSrcForInvalidGetterFunctions(adgIndex: number, rootAst: t.File, moduleMetadata: ModuleMetadata, moduleContext: ModuleContext): GetterDiagnosticsContext;
|
|
41
|
+
/**
|
|
42
|
+
* Function to analyze tempplate strings and collect any Priming Diagnostic info for them along with returning valid templates contexts
|
|
43
|
+
* @param adgIndex index of the current adg to process
|
|
44
|
+
* @param rootAst the Abstract Syntax Tree for the component
|
|
45
|
+
* @param moduleMetadata metadata about the given component
|
|
46
|
+
* @param moduleContext contextual details about the component, like module level variables, etc
|
|
47
|
+
* @returns diagnostics for the template strings
|
|
44
48
|
*/
|
|
45
|
-
export declare function
|
|
49
|
+
export declare function analyzeSrcForTemplateStringDiagnostics(adgIndex: number, rootAst: t.File, moduleMetadata: ModuleMetadata, moduleContext: ModuleContext): TemplateDiagnosticsContext;
|
|
46
50
|
/**
|
|
47
51
|
* Type guard for the komaci Image type
|
|
48
52
|
* @param {Composition} composition the komaci Composition object
|
package/build/shared.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isImageComposition = exports.
|
|
4
|
-
const adaptersMapping_1 = require("./adaptersMapping");
|
|
5
|
-
const allowlistAdapters_1 = require("./allowlistAdapters");
|
|
3
|
+
exports.isImageComposition = exports.analyzeSrcForTemplateStringDiagnostics = exports.analyzeSrcForInvalidGetterFunctions = exports.LLSRange = exports.isSupportedNamespace = exports.ERROR_PREFIX = exports.WIRE_FUNCTION = void 0;
|
|
6
4
|
const common_shared_1 = require("@komaci/common-shared");
|
|
5
|
+
const _1 = require(".");
|
|
7
6
|
const validateGetter_1 = require("./validateGetter");
|
|
8
7
|
// TODO: eventually refactor list consts into their own file
|
|
9
8
|
exports.WIRE_FUNCTION = 'WireFunction';
|
|
@@ -12,44 +11,6 @@ const emptyRange = {
|
|
|
12
11
|
start: { line: 0, character: 0 },
|
|
13
12
|
end: { line: 0, character: 0 },
|
|
14
13
|
};
|
|
15
|
-
/**
|
|
16
|
-
* Determine whether the wire adapter is supported
|
|
17
|
-
* @param resourceName the resource name of the Import, as a string
|
|
18
|
-
* @param adapterName the wire adapter variable name (import specifier export name) from a single
|
|
19
|
-
* Import statement (which can have more than one of these export names)
|
|
20
|
-
* @returns boolean true if the adapterName represents is a supported wire adapter (note that some
|
|
21
|
-
* resourceNames allow any adapterName as valid wire adapters)
|
|
22
|
-
*/
|
|
23
|
-
function isSupportedWireAdapter(resourceName, adapterName) {
|
|
24
|
-
if (!resourceName || !adapterName) {
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
27
|
-
// check if the resourceName is one of the types that can have any wire adapter name. If so, return true.
|
|
28
|
-
// allow list of ResourceName that can be a "starsWith" match
|
|
29
|
-
for (const allowedResourceNamePrefix of allowlistAdapters_1.allowlistResourceNamesStartsWith) {
|
|
30
|
-
if (resourceName.startsWith(allowedResourceNamePrefix)) {
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
// allow list of ResourceNames that need to be an exact match
|
|
35
|
-
for (const allowedResourceName of allowlistAdapters_1.allowlistResourceNamesExact) {
|
|
36
|
-
if (resourceName === allowedResourceName) {
|
|
37
|
-
return true;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
// check the allowlist of wire adapters for certain various resourceNames that all start with "lightning".
|
|
41
|
-
for (const [resourceNameKey, adapterList] of Object.entries(allowlistAdapters_1.allowlistAdapters)) {
|
|
42
|
-
if (resourceNameKey === resourceName && adapterList.includes(adapterName)) {
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
// check if there's an associated LDS priming adapter.
|
|
47
|
-
if ((0, exports.getPrimingAdapter)(resourceName, adapterName)) {
|
|
48
|
-
return true;
|
|
49
|
-
}
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
exports.isSupportedWireAdapter = isSupportedWireAdapter;
|
|
53
14
|
/**
|
|
54
15
|
* Determine whether the resource name is in a supported namespace
|
|
55
16
|
* @param resourceName the resource name of the Import, as a string
|
|
@@ -70,18 +31,6 @@ function isSupportedNamespace(resourceName) {
|
|
|
70
31
|
(0, common_shared_1.isLibraryValid)(resourceName));
|
|
71
32
|
}
|
|
72
33
|
exports.isSupportedNamespace = isSupportedNamespace;
|
|
73
|
-
const getPrimingAdapter = (importPath, identifier) => {
|
|
74
|
-
const adapterMap = adaptersMapping_1.wireAdaptersMap[importPath];
|
|
75
|
-
if (adapterMap === undefined) {
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
const primingAdapter = adapterMap[identifier];
|
|
79
|
-
if (primingAdapter === undefined) {
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
return primingAdapter;
|
|
83
|
-
};
|
|
84
|
-
exports.getPrimingAdapter = getPrimingAdapter;
|
|
85
34
|
/* Related utilty functions to convert Locations of various types into a Range format and indexing scheme supported by
|
|
86
35
|
the Lightning Language Server
|
|
87
36
|
(0-index based for lines and columns, and a specific format where `column` is called `character`) */
|
|
@@ -135,43 +84,70 @@ exports.LLSRange = {
|
|
|
135
84
|
},
|
|
136
85
|
};
|
|
137
86
|
/**
|
|
138
|
-
* Function to analyze
|
|
139
|
-
* @param
|
|
140
|
-
* @param
|
|
87
|
+
* Function to analyze src code and returns any diagnostics found and valid getter contexts in a GetterDiagnosticContext
|
|
88
|
+
* @param adgIndex index of the current adg to process
|
|
89
|
+
* @param rootAst the Abstract Syntax Tree for the component
|
|
90
|
+
* @param moduleMetadata metadata about the given component
|
|
91
|
+
* @param moduleContext contextual details about the component, like module level variables, etc
|
|
92
|
+
* @returns diagnostics for the getters
|
|
141
93
|
*/
|
|
142
|
-
function analyzeSrcForInvalidGetterFunctions(
|
|
143
|
-
const rootAst = (0, common_shared_1.generateAstFromSrcCode)(srcCode);
|
|
144
|
-
const moduleContext = {
|
|
145
|
-
astContext: (0, common_shared_1.getAstContextObject)(rootAst),
|
|
146
|
-
isExternal: (0, common_shared_1.isExternalModule)(namespace),
|
|
147
|
-
};
|
|
94
|
+
function analyzeSrcForInvalidGetterFunctions(adgIndex, rootAst, moduleMetadata, moduleContext) {
|
|
148
95
|
const diagnostics = [];
|
|
96
|
+
const validGetters = [];
|
|
149
97
|
const { getters } = (0, common_shared_1.getPropertyMetadataFromAst)(rootAst);
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
(0, common_shared_1.getMemberVarsFromGetter)(path, identifiers);
|
|
155
|
-
},
|
|
156
|
-
};
|
|
157
|
-
if (getters.length > 0) {
|
|
158
|
-
getters
|
|
159
|
-
.map((getter) => {
|
|
160
|
-
identifiers.clear();
|
|
161
|
-
getter.traverse(checkForPropertyReferences);
|
|
162
|
-
const name = (0, common_shared_1.getClassMethodName)(getter);
|
|
163
|
-
(0, common_shared_1.updatePropertyUsage)(name, Array.from(identifiers), properties, common_shared_1.PropertyTypes.GETTER);
|
|
164
|
-
return getter;
|
|
165
|
-
})
|
|
166
|
-
.forEach((func) => {
|
|
167
|
-
const res = (0, validateGetter_1.validateGetter)(func, moduleContext, true);
|
|
98
|
+
const adg = moduleMetadata.adgs.get(adgIndex);
|
|
99
|
+
if (getters.length > 0 && adg) {
|
|
100
|
+
getters.forEach((getterFunc, index) => {
|
|
101
|
+
const res = (0, validateGetter_1.validateGetter)(getterFunc, adgIndex, moduleMetadata, moduleContext, true);
|
|
168
102
|
const getterDiagnostics = res;
|
|
103
|
+
//Same thing as passing false into validate getter and getting a boolean back. If there are no diagnostics its valid.
|
|
104
|
+
if (getterDiagnostics.length == 0) {
|
|
105
|
+
const validGetter = generateValidGetterContext(getterFunc, adgIndex, moduleMetadata, index);
|
|
106
|
+
validGetters.push(validGetter);
|
|
107
|
+
const name = (0, common_shared_1.getClassMethodName)(getterFunc);
|
|
108
|
+
(0, common_shared_1.updatePropertyUsage)(name, validGetter.memberUsage, adg.properties, common_shared_1.PropertyTypes.GETTER);
|
|
109
|
+
}
|
|
169
110
|
diagnostics.push(...getterDiagnostics);
|
|
170
111
|
});
|
|
171
112
|
}
|
|
172
|
-
return
|
|
113
|
+
return {
|
|
114
|
+
getterFunctionDiagnostics: diagnostics,
|
|
115
|
+
validGetters: validGetters,
|
|
116
|
+
};
|
|
173
117
|
}
|
|
174
118
|
exports.analyzeSrcForInvalidGetterFunctions = analyzeSrcForInvalidGetterFunctions;
|
|
119
|
+
/**
|
|
120
|
+
* Function to analyze tempplate strings and collect any Priming Diagnostic info for them along with returning valid templates contexts
|
|
121
|
+
* @param adgIndex index of the current adg to process
|
|
122
|
+
* @param rootAst the Abstract Syntax Tree for the component
|
|
123
|
+
* @param moduleMetadata metadata about the given component
|
|
124
|
+
* @param moduleContext contextual details about the component, like module level variables, etc
|
|
125
|
+
* @returns diagnostics for the template strings
|
|
126
|
+
*/
|
|
127
|
+
function analyzeSrcForTemplateStringDiagnostics(adgIndex, rootAst, moduleMetadata, moduleContext) {
|
|
128
|
+
const diagnostics = [];
|
|
129
|
+
const validTemplates = [];
|
|
130
|
+
const { templateStrings } = (0, common_shared_1.getPropertyMetadataFromAst)(rootAst);
|
|
131
|
+
const adg = moduleMetadata.adgs.get(adgIndex);
|
|
132
|
+
if (templateStrings.length > 0 && adg) {
|
|
133
|
+
templateStrings.forEach((templateString, index) => {
|
|
134
|
+
const res = (0, _1.validateTemplateString)(templateString, adgIndex, moduleMetadata, moduleContext, true);
|
|
135
|
+
const templateDiagnostics = res;
|
|
136
|
+
//Same thing as passing false into validate getter and getting a boolean back. If there are no diagnostics its valid.
|
|
137
|
+
if (templateDiagnostics.length == 0) {
|
|
138
|
+
const validTemplate = generateValidTemplateContext(templateString, adgIndex, moduleMetadata, index);
|
|
139
|
+
validTemplates.push(validTemplate);
|
|
140
|
+
(0, common_shared_1.updatePropertyUsage)((0, common_shared_1.getFromIdentifierOrStringLiteral)(templateString.node.key), validTemplate.memberUsage, adg.properties, common_shared_1.PropertyTypes.TEMPLATE_STRING);
|
|
141
|
+
}
|
|
142
|
+
diagnostics.push(...templateDiagnostics);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
return {
|
|
146
|
+
templateDiagnostics: diagnostics,
|
|
147
|
+
validTemplates: validTemplates,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
exports.analyzeSrcForTemplateStringDiagnostics = analyzeSrcForTemplateStringDiagnostics;
|
|
175
151
|
/**
|
|
176
152
|
* Type guard for the komaci Image type
|
|
177
153
|
* @param {Composition} composition the komaci Composition object
|
|
@@ -181,4 +157,39 @@ function isImageComposition(composition) {
|
|
|
181
157
|
return composition.type === 'Image';
|
|
182
158
|
}
|
|
183
159
|
exports.isImageComposition = isImageComposition;
|
|
160
|
+
/**
|
|
161
|
+
* Helper function to generate a validGetterContext
|
|
162
|
+
* @param getterFunc the valid getter function
|
|
163
|
+
* @param moduleContext the module context
|
|
164
|
+
* @param moduleLevelConsumption a moduleLevelConsumption object
|
|
165
|
+
* @param properties properties array
|
|
166
|
+
* @param index index of the getter function
|
|
167
|
+
* @returns a valid getter context
|
|
168
|
+
*/
|
|
169
|
+
function generateValidGetterContext(getterFunc, adgIndex, moduleMetadata, index) {
|
|
170
|
+
const { identifiers } = (0, common_shared_1.implicitConsumptionMetadata)(getterFunc, adgIndex, moduleMetadata);
|
|
171
|
+
const validGetter = {
|
|
172
|
+
getter: getterFunc,
|
|
173
|
+
generatedName: `g${index}`,
|
|
174
|
+
memberUsage: identifiers,
|
|
175
|
+
};
|
|
176
|
+
return validGetter;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Helper function to generate a validTemplateContext
|
|
180
|
+
* @param template the valid template string
|
|
181
|
+
* @param moduleContext the module context
|
|
182
|
+
* @param moduleLevelConsumption a moduleLevelConsumption object
|
|
183
|
+
* @param properties properties array
|
|
184
|
+
* @param index index of the template string
|
|
185
|
+
* @returns a valid template context
|
|
186
|
+
*/
|
|
187
|
+
function generateValidTemplateContext(template, adgIndex, moduleMetadata, index) {
|
|
188
|
+
const { identifiers } = (0, common_shared_1.implicitConsumptionMetadata)(template, adgIndex, moduleMetadata);
|
|
189
|
+
return {
|
|
190
|
+
template,
|
|
191
|
+
generatedName: `t${index}`,
|
|
192
|
+
memberUsage: identifiers,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
184
195
|
//# sourceMappingURL=shared.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { KomaciDocument } from '@komaci/types';
|
|
1
2
|
import { AnalyzerInput, PrimingDiagnostic, Range, Position, WireInfo } from './types';
|
|
2
3
|
export declare class StaticAnalyzer {
|
|
3
4
|
startPos: Position;
|
|
@@ -27,7 +28,7 @@ export declare class StaticAnalyzer {
|
|
|
27
28
|
* @param scriptKomaciDoc KomaciDoc which provides relevant adg information
|
|
28
29
|
* @returns array of PrimingDiagnostic, with each element containing the analysis message and location information for IDE syntax underlining.
|
|
29
30
|
*/
|
|
30
|
-
|
|
31
|
+
processKomaciTemplateDoc(templateKomaciDoc: KomaciDocument | undefined, scriptKomaciDoc: KomaciDocument | undefined, diagnostics: PrimingDiagnostic[]): PrimingDiagnostic[];
|
|
31
32
|
private findWireConfigsThatUsePrivateProperty;
|
|
32
33
|
/**
|
|
33
34
|
* Traverses direct dependencies of the input wire (represented by a WireInfo) to see if any
|
|
@@ -55,29 +56,16 @@ export declare class StaticAnalyzer {
|
|
|
55
56
|
private findNestedUnsupportedNSObject;
|
|
56
57
|
private findWireConfigReferenceNonExistProperty;
|
|
57
58
|
/**
|
|
58
|
-
* Produce diagnostics for
|
|
59
|
-
* or wired properties which associated to unresolvable wires
|
|
60
|
-
*/
|
|
61
|
-
private findUnresolvableIterator;
|
|
62
|
-
/**
|
|
63
|
-
* Produce diagnostics for conditionals which act upon unresolvable inputs, such as private properties
|
|
64
|
-
* or wired properties which associated to unresolvable wires
|
|
65
|
-
*/
|
|
66
|
-
private findUnresolvableConditional;
|
|
67
|
-
/**
|
|
68
|
-
* Produces diagnostic for images which refer to unresolvable `src` attributes within the `<img>` tag.
|
|
69
|
-
* Note that Images are a type of Composition
|
|
59
|
+
* Produce diagnostics for compositions which use unresolvable inputs, such as private properties
|
|
60
|
+
* or wired properties which associated to unresolvable wires.
|
|
70
61
|
*
|
|
71
|
-
* @param
|
|
72
|
-
* @param
|
|
73
|
-
* @
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Convert array of Compositions into flattened array of Compositions,
|
|
78
|
-
* visiting top-level and nested children compositions
|
|
62
|
+
* @param properties the properties array
|
|
63
|
+
* @param adgs the adgs associated with the template
|
|
64
|
+
* @param diagnosics the diagnosics array
|
|
65
|
+
* @param defaultHasParent if the default expored ADG inherent a parent class
|
|
66
|
+
* @returns void
|
|
79
67
|
*/
|
|
80
|
-
private
|
|
68
|
+
private findUnresolvableCompositionProperty;
|
|
81
69
|
/**
|
|
82
70
|
* find Import name information (resourceName, importName) given komaciDoc imports and reference
|
|
83
71
|
*/
|
package/build/staticAnalyzer.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -20,11 +24,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
20
24
|
};
|
|
21
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
26
|
exports.StaticAnalyzer = void 0;
|
|
23
|
-
const collector = __importStar(require("@lwc
|
|
27
|
+
const collector = __importStar(require("@lwc/metadata"));
|
|
24
28
|
const rules_1 = require("./rules");
|
|
25
29
|
const common_shared_1 = require("@komaci/common-shared");
|
|
26
30
|
const shared_1 = require("./shared");
|
|
27
31
|
const WireGraph_1 = require("./WireGraph");
|
|
32
|
+
const helpers_1 = require("./helpers");
|
|
28
33
|
class StaticAnalyzer {
|
|
29
34
|
constructor() {
|
|
30
35
|
// TODO: Remove this sample Range when it is no longer needed as a placeholder
|
|
@@ -78,17 +83,38 @@ class StaticAnalyzer {
|
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
85
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
const adgIndex = scriptKomaciDoc?.exports?.default?.value;
|
|
87
|
+
const defaultAdg = scriptKomaciDoc?.adgs?.[adgIndex || 0];
|
|
88
|
+
if (sourceFileName &&
|
|
89
|
+
scriptKomaciDoc &&
|
|
90
|
+
adgIndex !== undefined &&
|
|
91
|
+
defaultAdg) {
|
|
92
|
+
const moduleMetadata = (0, common_shared_1.initModuleMetadataObject)();
|
|
93
|
+
(0, common_shared_1.initializeImportMetdataFromKomaciDocument)(scriptKomaciDoc, moduleMetadata);
|
|
94
|
+
const adg = (0, common_shared_1.initAdgMetadataObject)('adg0');
|
|
95
|
+
moduleMetadata.adgs.set(adgIndex, adg);
|
|
96
|
+
(0, common_shared_1.initializePropertiesMap)(defaultAdg.properties, defaultAdg.functions, adgIndex, scriptKomaciDoc, moduleMetadata);
|
|
86
97
|
const srcCode = input.files[sourceFileName];
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
const rootAst = (0, common_shared_1.generateAstFromSrcCode)(srcCode);
|
|
99
|
+
(0, common_shared_1.collectImportMetadataFromAst)(rootAst, moduleMetadata);
|
|
100
|
+
const moduleContext = {
|
|
101
|
+
astContext: (0, common_shared_1.getAstContextObject)(rootAst),
|
|
102
|
+
isExternal: (0, common_shared_1.isExternalModule)(input.namespace),
|
|
103
|
+
};
|
|
104
|
+
const { getterFunctionDiagnostics, validGetters } = (0, shared_1.analyzeSrcForInvalidGetterFunctions)(adgIndex, rootAst, moduleMetadata, moduleContext);
|
|
105
|
+
const { templateDiagnostics, validTemplates } = (0, shared_1.analyzeSrcForTemplateStringDiagnostics)(adgIndex, rootAst, moduleMetadata, moduleContext);
|
|
106
|
+
const getterAndTemplateDiagnostics = [
|
|
107
|
+
...getterFunctionDiagnostics,
|
|
108
|
+
...templateDiagnostics,
|
|
109
|
+
];
|
|
110
|
+
if (getterAndTemplateDiagnostics.length > 0) {
|
|
111
|
+
getterAndTemplateDiagnostics.forEach((diagnostic) => {
|
|
112
|
+
(0, rules_1.updatePrimingDiagnosticWithFileInfo)(diagnostic, sourceFileName);
|
|
113
|
+
diagnostics.push(diagnostic);
|
|
114
|
+
});
|
|
91
115
|
}
|
|
116
|
+
(0, common_shared_1.updateKomaciDocumentWithValidGetters)(scriptKomaciDoc, validGetters);
|
|
117
|
+
(0, common_shared_1.updateKomaciDocumentWithValidTemplatedStrings)(scriptKomaciDoc, validTemplates);
|
|
92
118
|
}
|
|
93
119
|
this.processKomaciScriptDoc(scriptKomaciDoc, diagnostics);
|
|
94
120
|
this.processKomaciTemplateDoc(templateKomaciDoc, scriptKomaciDoc, diagnostics);
|
|
@@ -117,13 +143,32 @@ class StaticAnalyzer {
|
|
|
117
143
|
// get the file name and store for VSCode analysis display purposes
|
|
118
144
|
const fileName = metadataObj?.files[0].fileName;
|
|
119
145
|
this.fileNamesMap.set('js', fileName);
|
|
120
|
-
|
|
121
|
-
|
|
146
|
+
const adgIndex = komaciDoc?.exports?.default?.value;
|
|
147
|
+
const defaultAdg = komaciDoc?.adgs?.[adgIndex || 0];
|
|
148
|
+
if (komaciDoc && adgIndex !== undefined && defaultAdg) {
|
|
149
|
+
const moduleMetadata = (0, common_shared_1.initModuleMetadataObject)();
|
|
150
|
+
(0, common_shared_1.initializeImportMetdataFromKomaciDocument)(komaciDoc, moduleMetadata);
|
|
151
|
+
const adg = (0, common_shared_1.initAdgMetadataObject)('adg0');
|
|
152
|
+
moduleMetadata.adgs.set(adgIndex, adg);
|
|
153
|
+
(0, common_shared_1.initializePropertiesMap)(defaultAdg.properties, defaultAdg.functions, adgIndex, komaciDoc, moduleMetadata);
|
|
122
154
|
const srcCode = input.sourceFile;
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
155
|
+
const rootAst = (0, common_shared_1.generateAstFromSrcCode)(srcCode);
|
|
156
|
+
(0, common_shared_1.collectImportMetadataFromAst)(rootAst, moduleMetadata);
|
|
157
|
+
const moduleContext = {
|
|
158
|
+
astContext: (0, common_shared_1.getAstContextObject)(rootAst),
|
|
159
|
+
isExternal: (0, common_shared_1.isExternalModule)(input.namespace),
|
|
160
|
+
};
|
|
161
|
+
const { getterFunctionDiagnostics } = (0, shared_1.analyzeSrcForInvalidGetterFunctions)(adgIndex, rootAst, moduleMetadata, moduleContext);
|
|
162
|
+
const { templateDiagnostics } = (0, shared_1.analyzeSrcForTemplateStringDiagnostics)(adgIndex, rootAst, moduleMetadata, moduleContext);
|
|
163
|
+
const getterAndTemplateDiagnostics = [
|
|
164
|
+
...getterFunctionDiagnostics,
|
|
165
|
+
...templateDiagnostics,
|
|
166
|
+
];
|
|
167
|
+
if (getterAndTemplateDiagnostics.length > 0) {
|
|
168
|
+
getterAndTemplateDiagnostics.forEach((diagnostic) => {
|
|
169
|
+
(0, rules_1.updatePrimingDiagnosticWithFileInfo)(diagnostic, this.fileNamesMap.get('js'));
|
|
170
|
+
diagnostics.push(diagnostic);
|
|
171
|
+
});
|
|
127
172
|
}
|
|
128
173
|
}
|
|
129
174
|
return this.processKomaciScriptDoc(komaciDoc, diagnostics);
|
|
@@ -220,34 +265,20 @@ class StaticAnalyzer {
|
|
|
220
265
|
scriptKomaciDoc?.exports) {
|
|
221
266
|
const adgs = [];
|
|
222
267
|
const defaultExport = scriptKomaciDoc.exports['default'];
|
|
268
|
+
let defaultHasParent = false;
|
|
223
269
|
if (defaultExport && defaultExport.type === 'AdgReference') {
|
|
224
270
|
const defaultAdg = scriptKomaciDoc.adgs[defaultExport.value];
|
|
225
271
|
adgs.push(defaultAdg);
|
|
226
272
|
let parentClass = defaultAdg.parentClass;
|
|
227
273
|
while (parentClass?.type === 'AdgReference') {
|
|
274
|
+
defaultHasParent = true;
|
|
228
275
|
const parentAdg = scriptKomaciDoc.adgs[parentClass.value];
|
|
229
276
|
adgs.push(parentAdg);
|
|
230
277
|
parentClass = parentAdg.parentClass;
|
|
231
278
|
}
|
|
232
279
|
}
|
|
233
|
-
const
|
|
234
|
-
|
|
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
|
-
}
|
|
280
|
+
const properties = (0, helpers_1.findPropertiesUsedInCompositions)(templateKomaciDoc.compositions);
|
|
281
|
+
this.findUnresolvableCompositionProperty(properties, adgs, diagnostics, defaultHasParent);
|
|
251
282
|
}
|
|
252
283
|
return diagnostics;
|
|
253
284
|
}
|
|
@@ -326,7 +357,7 @@ class StaticAnalyzer {
|
|
|
326
357
|
const komaciImport = imports[importIdx];
|
|
327
358
|
const importName = komaciImport.names[nameIdx];
|
|
328
359
|
if (!((0, shared_1.isSupportedNamespace)(komaciImport.resourceName) &&
|
|
329
|
-
(0,
|
|
360
|
+
(0, common_shared_1.isSupportedWireAdapter)(komaciImport.resourceName, imports[importIdx].names[nameIdx]))) {
|
|
330
361
|
unresolvableImport = {
|
|
331
362
|
name: importName,
|
|
332
363
|
namespace: imports[importIdx].resourceName,
|
|
@@ -541,121 +572,50 @@ class StaticAnalyzer {
|
|
|
541
572
|
return diagnostics;
|
|
542
573
|
}
|
|
543
574
|
/**
|
|
544
|
-
* Produce diagnostics for
|
|
545
|
-
* or wired properties which associated to unresolvable wires
|
|
575
|
+
* Produce diagnostics for compositions which use unresolvable inputs, such as private properties
|
|
576
|
+
* or wired properties which associated to unresolvable wires.
|
|
577
|
+
*
|
|
578
|
+
* @param properties the properties array
|
|
579
|
+
* @param adgs the adgs associated with the template
|
|
580
|
+
* @param diagnosics the diagnosics array
|
|
581
|
+
* @param defaultHasParent if the default expored ADG inherent a parent class
|
|
582
|
+
* @returns void
|
|
546
583
|
*/
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
const
|
|
550
|
-
const propName = iteration.input.value.split('/')[0];
|
|
584
|
+
findUnresolvableCompositionProperty(properties, adgs, diagnosics, defaultHasParent) {
|
|
585
|
+
for (const compositionProperty of properties) {
|
|
586
|
+
const { propertyName, diagnosticMessageAct, location } = compositionProperty;
|
|
551
587
|
for (const wire of this.orderedWireInfos) {
|
|
552
|
-
if (wire.propName ===
|
|
588
|
+
if (wire.propName === propertyName &&
|
|
553
589
|
wire.isNonAnalyzable &&
|
|
554
590
|
adgs.includes(wire.adg)) {
|
|
555
|
-
|
|
591
|
+
// property on unresolvable wire
|
|
592
|
+
diagnosics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_COMPOSITION_ON_UNANALYZABLE_PROPERTY_FROM_UNRESOLVABLE_WIRE, shared_1.LLSRange.fromLWCSourceLocation(location), [diagnosticMessageAct, propertyName]), this.fileNamesMap.get('html')));
|
|
556
593
|
}
|
|
557
594
|
}
|
|
595
|
+
let propertyFound = false;
|
|
558
596
|
for (const adg of adgs) {
|
|
559
|
-
if (adg.properties && adg.properties[
|
|
560
|
-
|
|
597
|
+
if (adg.properties && adg.properties[propertyName]) {
|
|
598
|
+
propertyFound = true;
|
|
599
|
+
const prop = adg.properties[propertyName];
|
|
561
600
|
if (prop.input) {
|
|
601
|
+
// getter
|
|
562
602
|
if (prop.input.type === 'Unresolved') {
|
|
563
|
-
|
|
603
|
+
diagnosics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_COMPOSITION_ON_UNANALYZABLE_GETTER_PROPERTY, shared_1.LLSRange.fromLWCSourceLocation(location), [diagnosticMessageAct, propertyName]), this.fileNamesMap.get('html')));
|
|
564
604
|
}
|
|
565
605
|
}
|
|
566
606
|
else {
|
|
567
607
|
if (!prop.isPublic) {
|
|
568
|
-
|
|
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
|
-
}
|
|
608
|
+
// private property
|
|
609
|
+
diagnosics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_COMPOSITION_ON_UNANALYZABLE_PROPERTY_NON_PUBLIC, shared_1.LLSRange.fromLWCSourceLocation(location), [diagnosticMessageAct, propertyName]), this.fileNamesMap.get('html')));
|
|
604
610
|
}
|
|
605
611
|
}
|
|
606
612
|
}
|
|
607
613
|
}
|
|
608
|
-
|
|
609
|
-
|
|
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
|
-
}
|
|
614
|
+
if (!propertyFound && !defaultHasParent) {
|
|
615
|
+
// property not exist
|
|
616
|
+
diagnosics.push((0, rules_1.updatePrimingDiagnosticWithFileInfo)((0, rules_1.getPrimingDiagnostic)(rules_1.diagnosticMessages.NO_COMPOSITION_ON_UNANALYZABLE_PROPERTY_MISSING, shared_1.LLSRange.fromLWCSourceLocation(location), [diagnosticMessageAct, propertyName]), this.fileNamesMap.get('html')));
|
|
642
617
|
}
|
|
643
618
|
}
|
|
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
619
|
}
|
|
660
620
|
/**
|
|
661
621
|
* find Import name information (resourceName, importName) given komaciDoc imports and reference
|