@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/shared.d.ts CHANGED
@@ -1,26 +1,18 @@
1
- import { ClassPropertyContexts } from '@komaci/common-shared';
2
- import { GetPrimingAdapter } from './types';
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 { PrimingDiagnostic, Range } from '.';
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 getter functions and collect any Priming Diagnostic info for invalid gettters.
42
- * @param srcCode the source code to analyze.
43
- * @param namespace the namespace of src file.
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 analyzeSrcForInvalidGetterFunctions(srcCode: string, namespace: string, properties: ClassPropertyContexts): PrimingDiagnostic[];
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.analyzeSrcForInvalidGetterFunctions = exports.LLSRange = exports.getPrimingAdapter = exports.isSupportedNamespace = exports.isSupportedWireAdapter = exports.ERROR_PREFIX = exports.WIRE_FUNCTION = void 0;
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 getter functions and collect any Priming Diagnostic info for invalid gettters.
139
- * @param srcCode the source code to analyze.
140
- * @param namespace the namespace of src file.
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(srcCode, namespace, properties) {
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 identifiers = new Set();
151
- const checkForPropertyReferences = {
152
- // visitor for each type
153
- MemberExpression(path) {
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 diagnostics;
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
- private processKomaciTemplateDoc;
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 iterators which iterate on unresolvable inputs, such as private properties
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 {Composition} image the composition containing the Image
72
- * @param {Adg[]} adgs an array of ADGs
73
- * @returns {PrimingDiagnostic} a PrimingDiagnostic if an image with unresolvable `src` attribute is found. void otherwise
74
- */
75
- private findUnresolvableImage;
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 compositionsToArray;
68
+ private findUnresolvableCompositionProperty;
81
69
  /**
82
70
  * find Import name information (resourceName, importName) given komaciDoc imports and reference
83
71
  */
@@ -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.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
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-platform/lwc-metadata-next"));
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
- 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 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 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);
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
- if (komaciDoc) {
121
- const properties = (0, common_shared_1.collectPropertyMetadataFromScriptDoc)(komaciDoc);
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 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);
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 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
- }
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, shared_1.isSupportedWireAdapter)(komaciImport.resourceName, imports[importIdx].names[nameIdx]))) {
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 iterators which iterate on unresolvable inputs, such as private properties
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
- findUnresolvableIterator(composition, adgs) {
548
- if (composition.type === 'Iteration') {
549
- const iteration = composition;
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 === propName &&
588
+ if (wire.propName === propertyName &&
553
589
  wire.isNonAnalyzable &&
554
590
  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'));
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[propName]) {
560
- const prop = adg.properties[propName];
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
- 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'));
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
- 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
- }
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
- 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
- }
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