@komaci/static-analyzer 240.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/build/WireGraph.d.ts +34 -0
  2. package/build/WireGraph.js +82 -0
  3. package/build/__mocks__/@babel/parser.d.ts +2 -0
  4. package/build/__mocks__/@babel/parser.js +6 -0
  5. package/build/adaptersMapping.d.ts +3 -0
  6. package/build/adaptersMapping.js +25 -0
  7. package/build/allowlistAdapters.d.ts +6 -0
  8. package/build/allowlistAdapters.js +10 -0
  9. package/build/index.d.ts +7 -0
  10. package/build/index.js +35 -0
  11. package/build/invariantFunctions/assignmentExpressionInvariantFunctions.d.ts +16 -0
  12. package/build/invariantFunctions/assignmentExpressionInvariantFunctions.js +34 -0
  13. package/build/invariantFunctions/callExpressionInvariantFunctions.d.ts +33 -0
  14. package/build/invariantFunctions/callExpressionInvariantFunctions.js +87 -0
  15. package/build/invariantFunctions/functionExpressionInvariantFunctions.d.ts +31 -0
  16. package/build/invariantFunctions/functionExpressionInvariantFunctions.js +69 -0
  17. package/build/invariantFunctions/identifierInvariantFunctions.d.ts +28 -0
  18. package/build/invariantFunctions/identifierInvariantFunctions.js +56 -0
  19. package/build/invariantFunctions/memberExpressionInvariantFunctions.d.ts +50 -0
  20. package/build/invariantFunctions/memberExpressionInvariantFunctions.js +146 -0
  21. package/build/invariantFunctions/returnStatementInvariantFunctions.d.ts +12 -0
  22. package/build/invariantFunctions/returnStatementInvariantFunctions.js +23 -0
  23. package/build/invariantFunctions/taggedTemplateExpressionInvariantFunctions.d.ts +12 -0
  24. package/build/invariantFunctions/taggedTemplateExpressionInvariantFunctions.js +25 -0
  25. package/build/komaci-mapping.json +288 -0
  26. package/build/rules.d.ts +22 -0
  27. package/build/rules.js +310 -0
  28. package/build/shared.d.ts +52 -0
  29. package/build/shared.js +184 -0
  30. package/build/staticAnalyzer.d.ts +100 -0
  31. package/build/staticAnalyzer.js +822 -0
  32. package/build/types.d.ts +102 -0
  33. package/build/types.js +3 -0
  34. package/build/validateGetter.d.ts +46 -0
  35. package/build/validateGetter.js +154 -0
  36. package/package.json +39 -0
@@ -0,0 +1,102 @@
1
+ import { Adg, FunctionType, SourceLocation } from '@komaci/types';
2
+ /** Representation of a source code file being analyzed, in format neeed by the VSCode language server */
3
+ export declare type Uri = {
4
+ path: string;
5
+ scheme: string;
6
+ fragment: '';
7
+ query: '';
8
+ authority: '';
9
+ };
10
+ /**
11
+ * When a diagnostic message occurs in a specific file within a bundle, this type contains the information
12
+ * needed by the VSCode language server, in the format it requires it.
13
+ */
14
+ export declare type Code = {
15
+ target: Uri;
16
+ value: string | number;
17
+ };
18
+ /**
19
+ * This is consumed by the VSCode language server to enable it to report diagnosics
20
+ * within the IDE, including the location (Range) of any error, warning, informational occurence.
21
+ */
22
+ export declare type PrimingDiagnostic = DiagnosticMessage & {
23
+ range: Range;
24
+ };
25
+ /**
26
+ * Contains information about a Diagnostic occurence while doing static analysis
27
+ * in a format compatible with VSCode language server
28
+ */
29
+ export declare type DiagnosticMessage = {
30
+ code?: string | number | Code;
31
+ severity: 'info' | 'warning' | 'error';
32
+ message: string;
33
+ source: 'offline code analyzer';
34
+ };
35
+ export declare type Range = {
36
+ start: Position;
37
+ end: Position;
38
+ };
39
+ export declare type Position = {
40
+ line: number;
41
+ character: number;
42
+ };
43
+ export declare type AnalyzerInput = DiagnosticFileInfo | DiagnosticBundleInfo;
44
+ export declare type StaticAnalyzerImportInfo = {
45
+ name: string;
46
+ namespace: string;
47
+ location: SourceLocation;
48
+ };
49
+ export declare type WireInfo = {
50
+ funcIndex: number;
51
+ propName?: string;
52
+ isNonAnalyzable: boolean;
53
+ dependentWires: WireInfo[];
54
+ location?: SourceLocation;
55
+ wireFunction: FunctionType;
56
+ adg: Adg;
57
+ beingVisited: boolean;
58
+ visited: boolean;
59
+ };
60
+ export declare type DiagnosticInfo = {
61
+ type: string;
62
+ name: string;
63
+ namespace: string;
64
+ };
65
+ export declare type DiagnosticFileInfo = DiagnosticInfo & {
66
+ type: 'file';
67
+ fileName: string;
68
+ sourceFile: string;
69
+ };
70
+ export declare type DiagnosticBundleInfo = DiagnosticInfo & {
71
+ type: 'bundle';
72
+ files: {
73
+ [fileName: string]: string;
74
+ };
75
+ };
76
+ export declare type ImportBinding = {
77
+ importPath: string;
78
+ identifier: string;
79
+ };
80
+ export declare type PrimingAdapterDefinition = {
81
+ prime: ImportBinding;
82
+ batch?: {
83
+ prime: ImportBinding;
84
+ reducer: ImportBinding;
85
+ };
86
+ };
87
+ export declare type GetPrimingAdapter = {
88
+ (importPath: string, identifier: string): PrimingAdapterDefinition | null;
89
+ };
90
+ export declare type WireAdaptersMapping = {
91
+ [importPath: string]: {
92
+ [identifier: string]: PrimingAdapterDefinition;
93
+ };
94
+ };
95
+ /**
96
+ * Contextual info about the given contextual code block
97
+ */
98
+ export declare type FunctionalContext = {
99
+ declaredVariables: string[];
100
+ thisAliases: Set<string>;
101
+ };
102
+ //# sourceMappingURL=types.d.ts.map
package/build/types.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,46 @@
1
+ import * as t from '@babel/types';
2
+ import { NodePath } from '@babel/traverse';
3
+ import { FunctionalContext, PrimingDiagnostic } from './types';
4
+ import { ModuleContext } from '@komaci/common-shared';
5
+ /**
6
+ * Run a series of checks against a functional node (currently class method or some form of template string) for "purity"
7
+ *
8
+ * See the individual invariants for details about each check
9
+ *
10
+ * @param path The babel nodepath we are looking at
11
+ * @param moduleContext Contextual information about the module
12
+ * @param functionalContext Contextual information about this functional code block
13
+ * @returns An array of the problems identified
14
+ */
15
+ export declare function checkFunctionalPurity(path: NodePath<t.ClassMethod | t.ClassProperty>, moduleContext: ModuleContext, functionalContext: FunctionalContext): Array<PrimingDiagnostic>;
16
+ /**
17
+ * Given a ClassMethod representing a getter method, it will run several invariant checks against its NodePath representation,
18
+ * in order to determine if it adheres all designated invariants.
19
+ * @param getterMethodPath NodePath<ClassMethod> path that represents class member-level getter method
20
+ * e.g. "get myId() { return '187291110cd3a'; }"
21
+ * @param returnSourceLocation if true, we will return an Array<InvariantDetail> for any
22
+ * detected invariants (or empty array if none were found)
23
+ * @param moduleContext all needful context about items in the class or encapsulating module
24
+ *
25
+ * @returns boolean or Array<InvariantDetail> representing whether the validated getter failed one of the
26
+ * invariant checks.
27
+ *
28
+ * boolean:
29
+ * If returnSourceLocation is false AND none fails the check, true is returned because
30
+ * the getter is valid. False is returned otherwise.
31
+ * Array<InvariantDetail>:
32
+ * Or, if returnSourceLocation is true AND a non-empty Array<InvariantDetail> is returned, that means at
33
+ * least one invariant check failed. If no invariant checks failed, an empty Array<InvariantDetail> is returned.
34
+ */
35
+ export declare function validateGetter(getterMethodPath: NodePath<t.ClassMethod>, moduleContext: ModuleContext, returnSourceLocation?: boolean): boolean | Array<PrimingDiagnostic>;
36
+ /**
37
+ * Validate template strings for purity. Variable declarations are not valid inside of a template expression so we do not have to support that use case here.
38
+ * Template string processing is essentially a subset of what we do for getter functions. The only diff is that we don't have to do the extra "only a return statement"
39
+ * check that we do for getters.
40
+ * @param node Node Path to check
41
+ * @param moduleContext contextual details about the module
42
+ * @param returnSourceLocation if we have to return the priming diagnostics or not
43
+ * @returns Priming diagnostics or just a true/false if it's valid
44
+ */
45
+ export declare function validateTemplateString(node: NodePath<t.ClassProperty>, moduleContext: ModuleContext, returnSourceLocation?: boolean): boolean | Array<PrimingDiagnostic>;
46
+ //# sourceMappingURL=validateGetter.d.ts.map
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateTemplateString = exports.validateGetter = exports.checkFunctionalPurity = void 0;
4
+ const memberExpressionInvariantFunctions_1 = require("./invariantFunctions/memberExpressionInvariantFunctions");
5
+ const callExpressionInvariantFunctions_1 = require("./invariantFunctions/callExpressionInvariantFunctions");
6
+ const assignmentExpressionInvariantFunctions_1 = require("./invariantFunctions/assignmentExpressionInvariantFunctions");
7
+ const returnStatementInvariantFunctions_1 = require("./invariantFunctions/returnStatementInvariantFunctions");
8
+ const functionExpressionInvariantFunctions_1 = require("./invariantFunctions/functionExpressionInvariantFunctions");
9
+ const identifierInvariantFunctions_1 = require("./invariantFunctions/identifierInvariantFunctions");
10
+ const common_shared_1 = require("@komaci/common-shared");
11
+ const taggedTemplateExpressionInvariantFunctions_1 = require("./invariantFunctions/taggedTemplateExpressionInvariantFunctions");
12
+ /**
13
+ * Run a series of checks against a functional node (currently class method or some form of template string) for "purity"
14
+ *
15
+ * See the individual invariants for details about each check
16
+ *
17
+ * @param path The babel nodepath we are looking at
18
+ * @param moduleContext Contextual information about the module
19
+ * @param functionalContext Contextual information about this functional code block
20
+ * @returns An array of the problems identified
21
+ */
22
+ function checkFunctionalPurity(path, moduleContext, functionalContext) {
23
+ let primingDiagnostics = [];
24
+ const Visitors = {
25
+ // visitor for each type
26
+ MemberExpression(path) {
27
+ primingDiagnostics = processLocationInfo(primingDiagnostics, [
28
+ (0, memberExpressionInvariantFunctions_1.checkNoUsageOfDocumentOrWindow)(path),
29
+ (0, memberExpressionInvariantFunctions_1.checkForNonSupportedMemberRefs)(path, moduleContext.astContext.classProperties),
30
+ (0, memberExpressionInvariantFunctions_1.checkForNonExistentMemberRefs)(path, moduleContext.astContext.classProperties, functionalContext.thisAliases),
31
+ (0, memberExpressionInvariantFunctions_1.checkMemberExpressionForNonSupportedNamespaceRefs)(path, moduleContext.astContext.importDeclarations),
32
+ (0, memberExpressionInvariantFunctions_1.checkForNoUseOfSuper)(path),
33
+ (0, memberExpressionInvariantFunctions_1.checkForUnsupportedGlobalRef)(path, moduleContext.astContext, functionalContext.declaredVariables),
34
+ ]);
35
+ },
36
+ CallExpression(path) {
37
+ primingDiagnostics = processLocationInfo(primingDiagnostics, [
38
+ (0, callExpressionInvariantFunctions_1.checkNoUsageOfEval)(path),
39
+ (0, callExpressionInvariantFunctions_1.checkCallExpressionForNonSupportedNamespaceRefs)(path, moduleContext.astContext.importDeclarations),
40
+ (0, callExpressionInvariantFunctions_1.checkForNoReferenceToClassFunctions)(path, moduleContext.astContext.classFunctions),
41
+ (0, callExpressionInvariantFunctions_1.checkForNoReferenceToModuleFunctions)(path, moduleContext.astContext.moduleFunctions),
42
+ ]);
43
+ },
44
+ AssignmentExpression(path) {
45
+ const functionCallArr = [(0, assignmentExpressionInvariantFunctions_1.checkForNoMemberVariableAssignments)(path)];
46
+ if (moduleContext.isExternal) {
47
+ functionCallArr.push((0, assignmentExpressionInvariantFunctions_1.checkExternalComponentForAssignmentExpr)(path));
48
+ }
49
+ primingDiagnostics = processLocationInfo(primingDiagnostics, functionCallArr);
50
+ },
51
+ FunctionExpression(path) {
52
+ primingDiagnostics = processLocationInfo(primingDiagnostics, [
53
+ (0, functionExpressionInvariantFunctions_1.checkForFunctionExpressionIfExternalComponent)(moduleContext, path),
54
+ ]);
55
+ },
56
+ ArrowFunctionExpression(path) {
57
+ primingDiagnostics = processLocationInfo(primingDiagnostics, [
58
+ (0, functionExpressionInvariantFunctions_1.checkForFunctionExpressionIfExternalComponent)(moduleContext, path),
59
+ ]);
60
+ },
61
+ ObjectMethod(path) {
62
+ primingDiagnostics = processLocationInfo(primingDiagnostics, [
63
+ (0, functionExpressionInvariantFunctions_1.checkForObjectMethodFunctionDeclarations)(moduleContext, path),
64
+ ]);
65
+ },
66
+ Identifier(path) {
67
+ primingDiagnostics = processLocationInfo(primingDiagnostics, [
68
+ (0, identifierInvariantFunctions_1.checkForNoReferenceToModuleVariables)(path, moduleContext.astContext.moduleVariables, functionalContext.declaredVariables),
69
+ (0, identifierInvariantFunctions_1.checkIdentifierForNonSupportedNamespaceRefs)(path, moduleContext.astContext.importDeclarations, functionalContext.declaredVariables),
70
+ ]);
71
+ },
72
+ TaggedTemplateExpression(path) {
73
+ primingDiagnostics = processLocationInfo(primingDiagnostics, [
74
+ (0, taggedTemplateExpressionInvariantFunctions_1.checkTaggedTemplateExprForNonSupportedNamespaceRefs)(path, moduleContext.astContext.importDeclarations),
75
+ ]);
76
+ },
77
+ };
78
+ // traverse the getter method NodePath, checking the logic in the visitors for each corresponding type of node to check
79
+ path.traverse(Visitors);
80
+ return primingDiagnostics;
81
+ }
82
+ exports.checkFunctionalPurity = checkFunctionalPurity;
83
+ /**
84
+ * Given a ClassMethod representing a getter method, it will run several invariant checks against its NodePath representation,
85
+ * in order to determine if it adheres all designated invariants.
86
+ * @param getterMethodPath NodePath<ClassMethod> path that represents class member-level getter method
87
+ * e.g. "get myId() { return '187291110cd3a'; }"
88
+ * @param returnSourceLocation if true, we will return an Array<InvariantDetail> for any
89
+ * detected invariants (or empty array if none were found)
90
+ * @param moduleContext all needful context about items in the class or encapsulating module
91
+ *
92
+ * @returns boolean or Array<InvariantDetail> representing whether the validated getter failed one of the
93
+ * invariant checks.
94
+ *
95
+ * boolean:
96
+ * If returnSourceLocation is false AND none fails the check, true is returned because
97
+ * the getter is valid. False is returned otherwise.
98
+ * Array<InvariantDetail>:
99
+ * Or, if returnSourceLocation is true AND a non-empty Array<InvariantDetail> is returned, that means at
100
+ * least one invariant check failed. If no invariant checks failed, an empty Array<InvariantDetail> is returned.
101
+ */
102
+ function validateGetter(getterMethodPath, moduleContext, returnSourceLocation = false) {
103
+ const getterDeclaredVars = (0, common_shared_1.getVariablesDeclaredInGetter)(getterMethodPath);
104
+ const thisAliases = (0, common_shared_1.getThisAliasDeclaredInGetter)(getterMethodPath);
105
+ let primingDiagnostics = checkFunctionalPurity(getterMethodPath, moduleContext, {
106
+ thisAliases,
107
+ declaredVariables: getterDeclaredVars,
108
+ });
109
+ // if getter was defined in an external module
110
+ if (moduleContext.isExternal) {
111
+ const blockStatement = getterMethodPath.get('body');
112
+ const statements = blockStatement.get('body');
113
+ // the getter doesn't only have a return method as expected. Skip traversal, then return from this method here
114
+ primingDiagnostics = processLocationInfo(primingDiagnostics, [
115
+ (0, returnStatementInvariantFunctions_1.checkExternalModuleGetterReturnStatement)(blockStatement, statements),
116
+ ]);
117
+ // If checkExternalModuleGetterReturnStatement() fails we should just return. There's no use in
118
+ // validating a function that is already foundationally invalid
119
+ if (primingDiagnostics.length > 0) {
120
+ return returnSourceLocation ? primingDiagnostics : false;
121
+ }
122
+ }
123
+ return returnSourceLocation ? primingDiagnostics : primingDiagnostics.length === 0;
124
+ }
125
+ exports.validateGetter = validateGetter;
126
+ /**
127
+ * Given a set of results from invariant checks. we want to filter out any no-op values and put meaningful
128
+ * results into the list of allInvalidLocations
129
+ * @param allInvalidLocations PrimingDiagnostic[] containing all invariants that occurred so far
130
+ * @param results the Array<PrimingDiagnostic | undefined> containing what is return by calling invariant checker method.
131
+ * @returns array of PrimingDiagnostic filtered of no-op values/non-meaningful results.
132
+ */
133
+ function processLocationInfo(allInvalidLocations, results) {
134
+ // concat method returns a new array from the original array + the arrays to concatenate
135
+ return allInvalidLocations.concat(results.filter((result) => result !== undefined));
136
+ }
137
+ /**
138
+ * Validate template strings for purity. Variable declarations are not valid inside of a template expression so we do not have to support that use case here.
139
+ * Template string processing is essentially a subset of what we do for getter functions. The only diff is that we don't have to do the extra "only a return statement"
140
+ * check that we do for getters.
141
+ * @param node Node Path to check
142
+ * @param moduleContext contextual details about the module
143
+ * @param returnSourceLocation if we have to return the priming diagnostics or not
144
+ * @returns Priming diagnostics or just a true/false if it's valid
145
+ */
146
+ function validateTemplateString(node, moduleContext, returnSourceLocation = false) {
147
+ const diagnostics = checkFunctionalPurity(node, moduleContext, {
148
+ declaredVariables: [],
149
+ thisAliases: new Set(),
150
+ });
151
+ return returnSourceLocation ? diagnostics : diagnostics.length === 0;
152
+ }
153
+ exports.validateTemplateString = validateTemplateString;
154
+ //# sourceMappingURL=validateGetter.js.map
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@komaci/static-analyzer",
3
+ "version": "240.1.3",
4
+ "description": "Komaci Diagnostics API",
5
+ "homepage": "https://komaci.dev/",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/salesforce/komaci.git",
9
+ "directory": "packages/@komaci/static-analyzer"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/salesforce/komaci/issues"
13
+ },
14
+ "license": "MIT",
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "type": "commonjs",
19
+ "types": "build/index.d.ts",
20
+ "main": "build/index.js",
21
+ "scripts": {
22
+ "build": "tsc -b"
23
+ },
24
+ "files": [
25
+ "build/**/*.js",
26
+ "build/**/*.d.ts",
27
+ "build/komaci-mapping.json"
28
+ ],
29
+ "peerDependencies": {
30
+ "@lwc-platform/lwc-metadata-next": "^2.18.0-240.2"
31
+ },
32
+ "dependencies": {
33
+ "@komaci/common-shared": "240.1.3"
34
+ },
35
+ "devDependencies": {
36
+ "@babel/types": "^7.9.0",
37
+ "@komaci/types": "240.1.3"
38
+ }
39
+ }