@memberjunction/react-test-harness 2.121.0 → 2.122.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/dist/lib/component-linter.d.ts +5 -0
- package/dist/lib/component-linter.d.ts.map +1 -1
- package/dist/lib/component-linter.js +2441 -2270
- package/dist/lib/component-linter.js.map +1 -1
- package/dist/lib/control-flow-analyzer.d.ts +184 -0
- package/dist/lib/control-flow-analyzer.d.ts.map +1 -0
- package/dist/lib/control-flow-analyzer.js +825 -0
- package/dist/lib/control-flow-analyzer.js.map +1 -0
- package/dist/lib/type-context.d.ts +182 -0
- package/dist/lib/type-context.d.ts.map +1 -0
- package/dist/lib/type-context.js +394 -0
- package/dist/lib/type-context.js.map +1 -0
- package/dist/lib/type-inference-engine.d.ts +148 -0
- package/dist/lib/type-inference-engine.d.ts.map +1 -0
- package/dist/lib/type-inference-engine.js +826 -0
- package/dist/lib/type-inference-engine.js.map +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Control Flow Analyzer
|
|
3
|
+
*
|
|
4
|
+
* Tracks how types and values narrow through JavaScript code based on runtime checks.
|
|
5
|
+
* Similar to TypeScript's control flow analysis for type narrowing.
|
|
6
|
+
*
|
|
7
|
+
* This eliminates false positives in linting rules by understanding patterns like:
|
|
8
|
+
* - if (x != null) { x.method() } // x is non-null here
|
|
9
|
+
* - if (typeof x === 'number') { x + 1 } // x is number here
|
|
10
|
+
* - if (arr.length > 0) { arr[0] } // arr has elements here
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const cfa = new ControlFlowAnalyzer(ast, componentSpec);
|
|
14
|
+
* if (cfa.isDefinitelyNonNull(node, path)) {
|
|
15
|
+
* // Safe to access property - no violation
|
|
16
|
+
* }
|
|
17
|
+
*/
|
|
18
|
+
import * as t from '@babel/types';
|
|
19
|
+
import type { NodePath } from '@babel/traverse';
|
|
20
|
+
import type { ComponentSpec } from '@memberjunction/interactive-component-types';
|
|
21
|
+
export declare class ControlFlowAnalyzer {
|
|
22
|
+
private ast;
|
|
23
|
+
private componentSpec?;
|
|
24
|
+
private typeEngine;
|
|
25
|
+
constructor(ast: t.File, componentSpec?: ComponentSpec);
|
|
26
|
+
/**
|
|
27
|
+
* Check if a node is protected by a ternary/conditional guard
|
|
28
|
+
* Useful for checking expressions inside template literals within ternaries
|
|
29
|
+
*
|
|
30
|
+
* @param node - The node to check (e.g., member expression)
|
|
31
|
+
* @param path - Current path in the AST (should be close to the node's location)
|
|
32
|
+
* @returns true if protected by a ternary guard, false otherwise
|
|
33
|
+
*/
|
|
34
|
+
isProtectedByTernary(node: t.Node, path: NodePath): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Check if a variable/property is definitely non-null at this location
|
|
37
|
+
*
|
|
38
|
+
* Detects patterns like:
|
|
39
|
+
* - if (x != null) { x.method() } // x is non-null here
|
|
40
|
+
* - if (x !== undefined) { x.prop }
|
|
41
|
+
* - if (x) { x.prop } // truthiness check
|
|
42
|
+
* - x && x.prop // short-circuit &&
|
|
43
|
+
* - x ? x.prop : default // ternary check
|
|
44
|
+
*
|
|
45
|
+
* @param node - The node being accessed (identifier or member expression)
|
|
46
|
+
* @param path - Current path in the AST
|
|
47
|
+
* @returns true if guaranteed non-null, false otherwise
|
|
48
|
+
*/
|
|
49
|
+
isDefinitelyNonNull(node: t.Node, path: NodePath): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Check if a variable is narrowed to a specific type at this location
|
|
52
|
+
*
|
|
53
|
+
* Detects patterns like:
|
|
54
|
+
* - if (typeof x === 'number') { x + 1 } // x is number
|
|
55
|
+
* - if (x instanceof Date) { x.getTime() } // x is Date
|
|
56
|
+
* - if (Array.isArray(x)) { x.push() } // x is array
|
|
57
|
+
*
|
|
58
|
+
* @param node - The node being checked
|
|
59
|
+
* @param path - Current path in the AST
|
|
60
|
+
* @param expectedType - The type to check for ('number', 'string', 'Date', etc.)
|
|
61
|
+
* @returns true if narrowed to that type, false otherwise
|
|
62
|
+
*/
|
|
63
|
+
isNarrowedToType(node: t.Node, path: NodePath, expectedType: string): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Recursively check for typeof guards in nested && expressions
|
|
66
|
+
*/
|
|
67
|
+
private detectTypeofGuardRecursive;
|
|
68
|
+
/**
|
|
69
|
+
* Detect typeof guard pattern: typeof x === 'type'
|
|
70
|
+
*/
|
|
71
|
+
private detectTypeofGuard;
|
|
72
|
+
/**
|
|
73
|
+
* Detect null/undefined guard pattern: x != null, x !== null, x !== undefined
|
|
74
|
+
* Also detects short-circuit OR patterns: !x || x.prop (x.prop is safe due to short-circuit)
|
|
75
|
+
*/
|
|
76
|
+
private detectNullGuard;
|
|
77
|
+
/**
|
|
78
|
+
* Detect truthiness guard pattern: if (x), x && expr, x ? ... : ...
|
|
79
|
+
*
|
|
80
|
+
* Handles:
|
|
81
|
+
* - Simple identifier: if (x)
|
|
82
|
+
* - Member expression: if (obj.prop)
|
|
83
|
+
* - Full path matching: if (item.TotalCost) protects item.TotalCost.toFixed()
|
|
84
|
+
*/
|
|
85
|
+
private detectTruthinessGuard;
|
|
86
|
+
/**
|
|
87
|
+
* Check if expression contains a negated check (!x) for the variable
|
|
88
|
+
* Used for detecting guards within OR chains
|
|
89
|
+
*
|
|
90
|
+
* @param expr - Expression to check
|
|
91
|
+
* @param varName - Variable name to look for
|
|
92
|
+
* @returns true if !varName exists in the expression
|
|
93
|
+
*/
|
|
94
|
+
private detectNegatedCheck;
|
|
95
|
+
/**
|
|
96
|
+
* Detect negated null guard pattern for alternate branches
|
|
97
|
+
*
|
|
98
|
+
* In the alternate (else) branch of these patterns, the variable is proven truthy:
|
|
99
|
+
* - !x || ... ? ... : <here> (if !x is false, x is truthy)
|
|
100
|
+
* - !x.prop || ... ? ... : <here> (if !x.prop is false, x is truthy)
|
|
101
|
+
*
|
|
102
|
+
* @param test - The conditional test expression
|
|
103
|
+
* @param varName - Variable name or full member path to check
|
|
104
|
+
* @returns true if the pattern proves varName is truthy in the alternate branch
|
|
105
|
+
*/
|
|
106
|
+
private detectNegatedNullGuard;
|
|
107
|
+
/**
|
|
108
|
+
* Extract variable name or full member expression path from node
|
|
109
|
+
*
|
|
110
|
+
* Examples:
|
|
111
|
+
* - `arr` → "arr"
|
|
112
|
+
* - `obj.prop` → "obj.prop"
|
|
113
|
+
* - `result.Results` → "result.Results"
|
|
114
|
+
* - `accountsResult.Results` → "accountsResult.Results"
|
|
115
|
+
*
|
|
116
|
+
* This allows CFA to match guards on nested properties correctly.
|
|
117
|
+
* For example, guard `accountsResult.Results?.length > 0` protects `accountsResult.Results[0]`
|
|
118
|
+
*/
|
|
119
|
+
private extractVariableName;
|
|
120
|
+
/**
|
|
121
|
+
* Serialize a member expression to its full path string
|
|
122
|
+
* Handles both regular and optional member expressions
|
|
123
|
+
*
|
|
124
|
+
* Examples:
|
|
125
|
+
* - obj.prop → "obj.prop"
|
|
126
|
+
* - obj?.prop → "obj.prop" (normalized, ignores optional chaining syntax)
|
|
127
|
+
* - obj.prop.nested → "obj.prop.nested"
|
|
128
|
+
*/
|
|
129
|
+
private serializeMemberExpression;
|
|
130
|
+
/**
|
|
131
|
+
* Check if path is inside the consequent (then block) of an if/ternary
|
|
132
|
+
*/
|
|
133
|
+
private isInConsequent;
|
|
134
|
+
/**
|
|
135
|
+
* Check if path is in the alternate (else) branch of an if or ternary
|
|
136
|
+
*/
|
|
137
|
+
private isInAlternate;
|
|
138
|
+
/**
|
|
139
|
+
* Check if path is on the right side of a logical && expression
|
|
140
|
+
*/
|
|
141
|
+
private isInRightSide;
|
|
142
|
+
/**
|
|
143
|
+
* Check if an array access is safe due to bounds checking guards
|
|
144
|
+
*
|
|
145
|
+
* Detects patterns like:
|
|
146
|
+
* - if (arr.length > 0) { arr[0] } // index 0 is safe
|
|
147
|
+
* - if (arr.length > 2) { arr[2] } // index 2 is safe
|
|
148
|
+
* - if (arr.length === 0) return; arr[0] // early return pattern
|
|
149
|
+
* - arr.length > 0 && arr[0] // inline guard
|
|
150
|
+
* - arr ? arr[0] : default // ternary guard
|
|
151
|
+
*
|
|
152
|
+
* @param arrayNode - The array being accessed (identifier or member expression)
|
|
153
|
+
* @param accessIndex - The index being accessed (e.g., 0 for arr[0])
|
|
154
|
+
* @param path - Current path in the AST
|
|
155
|
+
* @returns true if access is guaranteed safe, false otherwise
|
|
156
|
+
*/
|
|
157
|
+
isArrayAccessSafe(arrayNode: t.Node, accessIndex: number, path: NodePath): boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Extract the maximum safe array index from a length check expression
|
|
160
|
+
*
|
|
161
|
+
* Examples:
|
|
162
|
+
* - arr.length > 0 → returns 0 (index 0 is safe)
|
|
163
|
+
* - arr?.length > 0 → returns 0 (optional chaining proves non-null)
|
|
164
|
+
* - arr.length > 2 → returns 2 (indices 0-2 are safe)
|
|
165
|
+
* - arr.length >= 3 → returns 2 (indices 0-2 are safe)
|
|
166
|
+
* - arr.length !== 0 → returns 0 (index 0 is safe)
|
|
167
|
+
*
|
|
168
|
+
* @param test - The test expression to analyze
|
|
169
|
+
* @param arrayName - The array variable name to look for
|
|
170
|
+
* @returns Maximum safe index, or -1 if no length check found
|
|
171
|
+
*/
|
|
172
|
+
private getMaxSafeIndexFromLengthCheck;
|
|
173
|
+
/**
|
|
174
|
+
* Check if an expression is accessing the length property of an array
|
|
175
|
+
* Handles both regular and optional chaining: arr.length and arr?.length
|
|
176
|
+
* Also handles nested paths: obj.arr.length and obj.arr?.length
|
|
177
|
+
*/
|
|
178
|
+
private isLengthAccess;
|
|
179
|
+
/**
|
|
180
|
+
* Check if a statement or block contains an early return
|
|
181
|
+
*/
|
|
182
|
+
private hasEarlyReturn;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=control-flow-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-flow-analyzer.d.ts","sourceRoot":"","sources":["../../src/lib/control-flow-analyzer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAGjF,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,UAAU,CAAsB;gBAE5B,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,aAAa,CAAC,EAAE,aAAa;IAMtD;;;;;;;OAOG;IACH,oBAAoB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO;IA0E3D;;;;;;;;;;;;;OAaG;IACH,mBAAmB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO;IA4F1D;;;;;;;;;;;;OAYG;IACH,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO;IAwD7E;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAelC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA0BzB;;;OAGG;IACH,OAAO,CAAC,eAAe;IA6DvB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAgC7B;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB;IAuB1B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,sBAAsB;IA2B9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,mBAAmB;IAc3B;;;;;;;;OAQG;IACH,OAAO,CAAC,yBAAyB;IA2BjC;;OAEG;IACH,OAAO,CAAC,cAAc;IA4BtB;;OAEG;IACH,OAAO,CAAC,aAAa;IA4BrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAmBrB;;;;;;;;;;;;;;OAcG;IACH,iBAAiB,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO;IAkHlF;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,8BAA8B;IA8DtC;;;;OAIG;IACH,OAAO,CAAC,cAAc;IA2BtB;;OAEG;IACH,OAAO,CAAC,cAAc;CAevB"}
|