@cyclonedx/cdxgen 12.3.3 → 12.4.1

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 (175) hide show
  1. package/README.md +69 -25
  2. package/bin/audit.js +21 -7
  3. package/bin/cdxgen.js +270 -127
  4. package/bin/convert.js +34 -15
  5. package/bin/hbom.js +495 -0
  6. package/bin/repl.js +592 -37
  7. package/bin/validate.js +31 -4
  8. package/bin/verify.js +18 -5
  9. package/data/README.md +298 -25
  10. package/data/component-tags.json +6 -0
  11. package/data/crypto-oid.json +16 -0
  12. package/data/cyclonedx-2.0-bundled.schema.json +7182 -0
  13. package/data/predictive-audit-allowlist.json +11 -0
  14. package/data/queries-darwin.json +12 -1
  15. package/data/queries-win.json +7 -1
  16. package/data/queries.json +39 -2
  17. package/data/rules/ai-agent-governance.yaml +16 -0
  18. package/data/rules/asar-archives.yaml +150 -0
  19. package/data/rules/chrome-extensions.yaml +8 -0
  20. package/data/rules/ci-permissions.yaml +42 -18
  21. package/data/rules/container-risk.yaml +14 -7
  22. package/data/rules/dependency-sources.yaml +11 -0
  23. package/data/rules/hbom-compliance.yaml +325 -0
  24. package/data/rules/hbom-performance.yaml +307 -0
  25. package/data/rules/hbom-security.yaml +248 -0
  26. package/data/rules/host-topology.yaml +165 -0
  27. package/data/rules/mcp-servers.yaml +18 -3
  28. package/data/rules/obom-runtime.yaml +907 -22
  29. package/data/rules/package-integrity.yaml +14 -0
  30. package/data/rules/rootfs-hardening.yaml +179 -0
  31. package/data/rules/vscode-extensions.yaml +9 -0
  32. package/lib/audit/index.js +210 -8
  33. package/lib/audit/index.poku.js +332 -0
  34. package/lib/audit/reporters.js +222 -0
  35. package/lib/audit/targets.js +146 -1
  36. package/lib/audit/targets.poku.js +186 -0
  37. package/lib/cli/asar.poku.js +328 -0
  38. package/lib/cli/index.js +527 -99
  39. package/lib/cli/index.poku.js +1469 -212
  40. package/lib/evinser/evinser.js +14 -9
  41. package/lib/helpers/analyzer.js +1406 -29
  42. package/lib/helpers/analyzer.poku.js +342 -0
  43. package/lib/helpers/analyzerScope.js +712 -0
  44. package/lib/helpers/asarutils.js +1556 -0
  45. package/lib/helpers/asarutils.poku.js +443 -0
  46. package/lib/helpers/auditCategories.js +12 -0
  47. package/lib/helpers/auditCategories.poku.js +32 -0
  48. package/lib/helpers/bomUtils.js +155 -1
  49. package/lib/helpers/bomUtils.poku.js +79 -1
  50. package/lib/helpers/cbomutils.js +271 -1
  51. package/lib/helpers/cbomutils.poku.js +248 -5
  52. package/lib/helpers/display.js +291 -1
  53. package/lib/helpers/display.poku.js +149 -0
  54. package/lib/helpers/evidenceUtils.js +58 -0
  55. package/lib/helpers/evidenceUtils.poku.js +54 -0
  56. package/lib/helpers/exportUtils.js +9 -0
  57. package/lib/helpers/gtfobins.js +142 -8
  58. package/lib/helpers/gtfobins.poku.js +24 -1
  59. package/lib/helpers/hbom.js +710 -0
  60. package/lib/helpers/hbom.poku.js +496 -0
  61. package/lib/helpers/hbomAnalysis.js +268 -0
  62. package/lib/helpers/hbomAnalysis.poku.js +249 -0
  63. package/lib/helpers/hbomLoader.js +35 -0
  64. package/lib/helpers/hostTopology.js +803 -0
  65. package/lib/helpers/hostTopology.poku.js +363 -0
  66. package/lib/helpers/inventoryStats.js +69 -0
  67. package/lib/helpers/inventoryStats.poku.js +86 -0
  68. package/lib/helpers/lolbas.js +19 -1
  69. package/lib/helpers/lolbas.poku.js +23 -0
  70. package/lib/helpers/osqueryTransform.js +47 -0
  71. package/lib/helpers/osqueryTransform.poku.js +47 -0
  72. package/lib/helpers/plugins.js +350 -0
  73. package/lib/helpers/plugins.poku.js +57 -0
  74. package/lib/helpers/protobom.js +209 -45
  75. package/lib/helpers/protobom.poku.js +183 -5
  76. package/lib/helpers/protobomLoader.js +43 -0
  77. package/lib/helpers/protobomLoader.poku.js +31 -0
  78. package/lib/helpers/remote/dependency-track.js +36 -3
  79. package/lib/helpers/remote/dependency-track.poku.js +44 -0
  80. package/lib/helpers/source.js +24 -0
  81. package/lib/helpers/source.poku.js +32 -0
  82. package/lib/helpers/utils.js +1438 -93
  83. package/lib/helpers/utils.poku.js +846 -4
  84. package/lib/managers/binary.e2e.poku.js +367 -0
  85. package/lib/managers/binary.js +2293 -353
  86. package/lib/managers/binary.poku.js +1699 -1
  87. package/lib/managers/docker.js +201 -79
  88. package/lib/managers/docker.poku.js +337 -12
  89. package/lib/server/server.js +4 -28
  90. package/lib/stages/postgen/annotator.js +38 -0
  91. package/lib/stages/postgen/annotator.poku.js +107 -1
  92. package/lib/stages/postgen/auditBom.js +121 -18
  93. package/lib/stages/postgen/auditBom.poku.js +1366 -31
  94. package/lib/stages/postgen/hostTopologyAudit.poku.js +186 -0
  95. package/lib/stages/postgen/postgen.js +406 -8
  96. package/lib/stages/postgen/postgen.poku.js +484 -0
  97. package/lib/stages/postgen/ruleEngine.js +116 -0
  98. package/lib/stages/pregen/envAudit.js +14 -3
  99. package/lib/validator/bomValidator.js +90 -38
  100. package/lib/validator/bomValidator.poku.js +90 -0
  101. package/lib/validator/complianceRules.js +4 -2
  102. package/lib/validator/index.poku.js +14 -0
  103. package/package.json +23 -21
  104. package/types/bin/hbom.d.ts +3 -0
  105. package/types/bin/hbom.d.ts.map +1 -0
  106. package/types/bin/repl.d.ts +1 -1
  107. package/types/bin/repl.d.ts.map +1 -1
  108. package/types/lib/audit/index.d.ts +44 -0
  109. package/types/lib/audit/index.d.ts.map +1 -1
  110. package/types/lib/audit/reporters.d.ts +16 -0
  111. package/types/lib/audit/reporters.d.ts.map +1 -1
  112. package/types/lib/audit/targets.d.ts.map +1 -1
  113. package/types/lib/cli/index.d.ts +16 -0
  114. package/types/lib/cli/index.d.ts.map +1 -1
  115. package/types/lib/evinser/evinser.d.ts +4 -0
  116. package/types/lib/evinser/evinser.d.ts.map +1 -1
  117. package/types/lib/helpers/analyzer.d.ts +33 -0
  118. package/types/lib/helpers/analyzer.d.ts.map +1 -1
  119. package/types/lib/helpers/analyzerScope.d.ts +11 -0
  120. package/types/lib/helpers/analyzerScope.d.ts.map +1 -0
  121. package/types/lib/helpers/asarutils.d.ts +34 -0
  122. package/types/lib/helpers/asarutils.d.ts.map +1 -0
  123. package/types/lib/helpers/auditCategories.d.ts +5 -0
  124. package/types/lib/helpers/auditCategories.d.ts.map +1 -1
  125. package/types/lib/helpers/bomUtils.d.ts +10 -0
  126. package/types/lib/helpers/bomUtils.d.ts.map +1 -1
  127. package/types/lib/helpers/cbomutils.d.ts +3 -2
  128. package/types/lib/helpers/cbomutils.d.ts.map +1 -1
  129. package/types/lib/helpers/display.d.ts.map +1 -1
  130. package/types/lib/helpers/evidenceUtils.d.ts +8 -0
  131. package/types/lib/helpers/evidenceUtils.d.ts.map +1 -0
  132. package/types/lib/helpers/exportUtils.d.ts.map +1 -1
  133. package/types/lib/helpers/gtfobins.d.ts +8 -0
  134. package/types/lib/helpers/gtfobins.d.ts.map +1 -1
  135. package/types/lib/helpers/hbom.d.ts +49 -0
  136. package/types/lib/helpers/hbom.d.ts.map +1 -0
  137. package/types/lib/helpers/hbomAnalysis.d.ts +76 -0
  138. package/types/lib/helpers/hbomAnalysis.d.ts.map +1 -0
  139. package/types/lib/helpers/hbomLoader.d.ts +7 -0
  140. package/types/lib/helpers/hbomLoader.d.ts.map +1 -0
  141. package/types/lib/helpers/hostTopology.d.ts +12 -0
  142. package/types/lib/helpers/hostTopology.d.ts.map +1 -0
  143. package/types/lib/helpers/inventoryStats.d.ts +11 -0
  144. package/types/lib/helpers/inventoryStats.d.ts.map +1 -0
  145. package/types/lib/helpers/lolbas.d.ts.map +1 -1
  146. package/types/lib/helpers/osqueryTransform.d.ts +3 -0
  147. package/types/lib/helpers/osqueryTransform.d.ts.map +1 -1
  148. package/types/lib/helpers/plugins.d.ts +58 -0
  149. package/types/lib/helpers/plugins.d.ts.map +1 -0
  150. package/types/lib/helpers/protobom.d.ts +5 -4
  151. package/types/lib/helpers/protobom.d.ts.map +1 -1
  152. package/types/lib/helpers/protobomLoader.d.ts +17 -0
  153. package/types/lib/helpers/protobomLoader.d.ts.map +1 -0
  154. package/types/lib/helpers/remote/dependency-track.d.ts +10 -3
  155. package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -1
  156. package/types/lib/helpers/source.d.ts.map +1 -1
  157. package/types/lib/helpers/utils.d.ts +45 -8
  158. package/types/lib/helpers/utils.d.ts.map +1 -1
  159. package/types/lib/managers/binary.d.ts +5 -0
  160. package/types/lib/managers/binary.d.ts.map +1 -1
  161. package/types/lib/managers/docker.d.ts.map +1 -1
  162. package/types/lib/server/server.d.ts +2 -1
  163. package/types/lib/server/server.d.ts.map +1 -1
  164. package/types/lib/stages/postgen/annotator.d.ts.map +1 -1
  165. package/types/lib/stages/postgen/auditBom.d.ts +26 -1
  166. package/types/lib/stages/postgen/auditBom.d.ts.map +1 -1
  167. package/types/lib/stages/postgen/postgen.d.ts +2 -1
  168. package/types/lib/stages/postgen/postgen.d.ts.map +1 -1
  169. package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -1
  170. package/types/lib/stages/pregen/envAudit.d.ts.map +1 -1
  171. package/types/lib/third-party/arborist/lib/node.d.ts +23 -0
  172. package/types/lib/third-party/arborist/lib/node.d.ts.map +1 -1
  173. package/types/lib/validator/bomValidator.d.ts.map +1 -1
  174. package/types/lib/validator/complianceRules.d.ts.map +1 -1
  175. package/data/spdx-model-v3.0.1.jsonld +0 -15999
@@ -0,0 +1,712 @@
1
+ const getStaticNumberValue = (astNode) => {
2
+ if (!astNode) {
3
+ return undefined;
4
+ }
5
+ if (astNode.type === "NumericLiteral") {
6
+ return astNode.value;
7
+ }
8
+ if (astNode.type === "UnaryExpression" && astNode.operator === "-") {
9
+ const argumentValue = getStaticNumberValue(astNode.argument);
10
+ return typeof argumentValue === "number" ? -argumentValue : undefined;
11
+ }
12
+ return undefined;
13
+ };
14
+
15
+ const getStaticPrimitiveValue = (astNode, getLiteralStringValue) => {
16
+ if (!astNode) {
17
+ return undefined;
18
+ }
19
+ const stringValue = getLiteralStringValue(astNode);
20
+ if (stringValue !== undefined) {
21
+ return stringValue;
22
+ }
23
+ const numberValue = getStaticNumberValue(astNode);
24
+ if (numberValue !== undefined) {
25
+ return numberValue;
26
+ }
27
+ if (astNode.type === "BooleanLiteral") {
28
+ return astNode.value;
29
+ }
30
+ if (astNode.type === "NullLiteral") {
31
+ return null;
32
+ }
33
+ return undefined;
34
+ };
35
+
36
+ export const toResolvedValueArray = (value) => {
37
+ if (value === undefined) {
38
+ return [];
39
+ }
40
+ if (!Array.isArray(value)) {
41
+ return [value];
42
+ }
43
+ return value.flatMap((entry) => toResolvedValueArray(entry));
44
+ };
45
+
46
+ export const resolvedValueKey = (value) => {
47
+ if (value && typeof value === "object") {
48
+ return `object:${JSON.stringify(value)}`;
49
+ }
50
+ return `${typeof value}:${String(value)}`;
51
+ };
52
+
53
+ export const mergeResolvedValues = (...values) => {
54
+ const mergedValues = [];
55
+ const seen = new Set();
56
+ for (const value of values) {
57
+ for (const candidate of toResolvedValueArray(value)) {
58
+ const key = resolvedValueKey(candidate);
59
+ if (seen.has(key)) {
60
+ continue;
61
+ }
62
+ seen.add(key);
63
+ mergedValues.push(candidate);
64
+ }
65
+ }
66
+ if (!mergedValues.length) {
67
+ return undefined;
68
+ }
69
+ return mergedValues.length === 1 ? mergedValues[0] : mergedValues;
70
+ };
71
+
72
+ export const filterResolvedValues = (value, predicate) => {
73
+ return mergeResolvedValues(
74
+ ...toResolvedValueArray(value).filter((candidate) => predicate(candidate)),
75
+ );
76
+ };
77
+
78
+ export const hasOnlyResolvedValues = (value, predicate) => {
79
+ const resolvedValues = toResolvedValueArray(value);
80
+ return resolvedValues.length > 0 && resolvedValues.every(predicate);
81
+ };
82
+
83
+ const applyStringTransformToResolvedValue = (value, transform) => {
84
+ const transformedValues = [];
85
+ for (const candidate of toResolvedValueArray(value)) {
86
+ if (typeof candidate !== "string") {
87
+ continue;
88
+ }
89
+ transformedValues.push(transform(candidate));
90
+ }
91
+ return mergeResolvedValues(...transformedValues);
92
+ };
93
+
94
+ export const getStaticObjectProperty = (objectValue, propertyName) => {
95
+ if (Array.isArray(objectValue)) {
96
+ return mergeResolvedValues(
97
+ ...objectValue.map((entry) =>
98
+ getStaticObjectProperty(entry, propertyName),
99
+ ),
100
+ );
101
+ }
102
+ if (!objectValue || typeof objectValue !== "object") {
103
+ return undefined;
104
+ }
105
+ return objectValue[propertyName];
106
+ };
107
+
108
+ const intersectResolvedValues = (leftValue, rightValue) => {
109
+ const rightValueKeys = new Set(
110
+ toResolvedValueArray(rightValue).map((value) => resolvedValueKey(value)),
111
+ );
112
+ return mergeResolvedValues(
113
+ ...toResolvedValueArray(leftValue).filter((value) =>
114
+ rightValueKeys.has(resolvedValueKey(value)),
115
+ ),
116
+ );
117
+ };
118
+
119
+ const createStaticNarrowingMap = (identifierName, value) => {
120
+ if (!identifierName || value === undefined) {
121
+ return undefined;
122
+ }
123
+ return new Map([[identifierName, value]]);
124
+ };
125
+
126
+ const mergeStaticNarrowingMapsForAnd = (leftMap, rightMap) => {
127
+ if (!leftMap || !rightMap) {
128
+ return undefined;
129
+ }
130
+ const mergedMap = new Map(leftMap);
131
+ for (const [identifierName, value] of rightMap) {
132
+ if (!mergedMap.has(identifierName)) {
133
+ mergedMap.set(identifierName, value);
134
+ continue;
135
+ }
136
+ const intersectedValue = intersectResolvedValues(
137
+ mergedMap.get(identifierName),
138
+ value,
139
+ );
140
+ if (intersectedValue === undefined) {
141
+ return undefined;
142
+ }
143
+ mergedMap.set(identifierName, intersectedValue);
144
+ }
145
+ return mergedMap;
146
+ };
147
+
148
+ const mergeStaticNarrowingMapsForOr = (leftMap, rightMap) => {
149
+ if (!leftMap || !rightMap || leftMap.size !== rightMap.size) {
150
+ return undefined;
151
+ }
152
+ const mergedMap = new Map();
153
+ for (const [identifierName, value] of leftMap) {
154
+ if (!rightMap.has(identifierName)) {
155
+ return undefined;
156
+ }
157
+ mergedMap.set(
158
+ identifierName,
159
+ mergeResolvedValues(value, rightMap.get(identifierName)),
160
+ );
161
+ }
162
+ return mergedMap;
163
+ };
164
+
165
+ const getConditionComparisonIdentifier = (astNode) => {
166
+ return astNode?.type === "Identifier" ? astNode.name : undefined;
167
+ };
168
+
169
+ const getConditionComparisonValue = (astNode, getLiteralStringValue) => {
170
+ return getStaticPrimitiveValue(astNode, getLiteralStringValue);
171
+ };
172
+
173
+ export const deriveStaticNarrowingsFromCondition = (
174
+ astNode,
175
+ branchTaken,
176
+ getLiteralStringValue,
177
+ ) => {
178
+ if (!astNode) {
179
+ return undefined;
180
+ }
181
+ if (
182
+ [
183
+ "ParenthesizedExpression",
184
+ "TSAsExpression",
185
+ "TSNonNullExpression",
186
+ "TSSatisfiesExpression",
187
+ "TypeCastExpression",
188
+ ].includes(astNode.type)
189
+ ) {
190
+ return deriveStaticNarrowingsFromCondition(
191
+ astNode.expression,
192
+ branchTaken,
193
+ getLiteralStringValue,
194
+ );
195
+ }
196
+ if (astNode.type === "UnaryExpression" && astNode.operator === "!") {
197
+ return deriveStaticNarrowingsFromCondition(
198
+ astNode.argument,
199
+ !branchTaken,
200
+ getLiteralStringValue,
201
+ );
202
+ }
203
+ if (astNode.type === "LogicalExpression") {
204
+ if (branchTaken && astNode.operator === "&&") {
205
+ return mergeStaticNarrowingMapsForAnd(
206
+ deriveStaticNarrowingsFromCondition(
207
+ astNode.left,
208
+ true,
209
+ getLiteralStringValue,
210
+ ),
211
+ deriveStaticNarrowingsFromCondition(
212
+ astNode.right,
213
+ true,
214
+ getLiteralStringValue,
215
+ ),
216
+ );
217
+ }
218
+ if (branchTaken && astNode.operator === "||") {
219
+ return mergeStaticNarrowingMapsForOr(
220
+ deriveStaticNarrowingsFromCondition(
221
+ astNode.left,
222
+ true,
223
+ getLiteralStringValue,
224
+ ),
225
+ deriveStaticNarrowingsFromCondition(
226
+ astNode.right,
227
+ true,
228
+ getLiteralStringValue,
229
+ ),
230
+ );
231
+ }
232
+ return undefined;
233
+ }
234
+ if (astNode.type !== "BinaryExpression") {
235
+ return undefined;
236
+ }
237
+ const leftIdentifier = getConditionComparisonIdentifier(astNode.left);
238
+ const rightIdentifier = getConditionComparisonIdentifier(astNode.right);
239
+ const leftValue = getConditionComparisonValue(
240
+ astNode.left,
241
+ getLiteralStringValue,
242
+ );
243
+ const rightValue = getConditionComparisonValue(
244
+ astNode.right,
245
+ getLiteralStringValue,
246
+ );
247
+ const identifierName = leftIdentifier || rightIdentifier;
248
+ const comparisonValue = leftIdentifier ? rightValue : leftValue;
249
+ if (!identifierName || comparisonValue === undefined) {
250
+ return undefined;
251
+ }
252
+ if (["===", "=="].includes(astNode.operator) && branchTaken) {
253
+ return createStaticNarrowingMap(identifierName, comparisonValue);
254
+ }
255
+ if (["!==", "!="].includes(astNode.operator) && !branchTaken) {
256
+ return createStaticNarrowingMap(identifierName, comparisonValue);
257
+ }
258
+ return undefined;
259
+ };
260
+
261
+ export const resolveStaticValue = (
262
+ astNode,
263
+ staticValueByName,
264
+ getLiteralStringValue,
265
+ getMemberExpressionPropertyName,
266
+ depth = 0,
267
+ ) => {
268
+ if (!astNode || depth > 6) {
269
+ return undefined;
270
+ }
271
+ const primitiveValue = getStaticPrimitiveValue(
272
+ astNode,
273
+ getLiteralStringValue,
274
+ );
275
+ if (primitiveValue !== undefined) {
276
+ return primitiveValue;
277
+ }
278
+ if (astNode.type === "Identifier") {
279
+ if (staticValueByName.has(astNode.name)) {
280
+ return staticValueByName.get(astNode.name);
281
+ }
282
+ return undefined;
283
+ }
284
+ if (
285
+ [
286
+ "ParenthesizedExpression",
287
+ "TSAsExpression",
288
+ "TSNonNullExpression",
289
+ "TSSatisfiesExpression",
290
+ "TypeCastExpression",
291
+ ].includes(astNode.type)
292
+ ) {
293
+ return resolveStaticValue(
294
+ astNode.expression,
295
+ staticValueByName,
296
+ getLiteralStringValue,
297
+ getMemberExpressionPropertyName,
298
+ depth + 1,
299
+ );
300
+ }
301
+ if (astNode.type === "ConditionalExpression") {
302
+ const testValue = resolveStaticValue(
303
+ astNode.test,
304
+ staticValueByName,
305
+ getLiteralStringValue,
306
+ getMemberExpressionPropertyName,
307
+ depth + 1,
308
+ );
309
+ const consequentValue = resolveStaticValue(
310
+ astNode.consequent,
311
+ staticValueByName,
312
+ getLiteralStringValue,
313
+ getMemberExpressionPropertyName,
314
+ depth + 1,
315
+ );
316
+ const alternateValue = resolveStaticValue(
317
+ astNode.alternate,
318
+ staticValueByName,
319
+ getLiteralStringValue,
320
+ getMemberExpressionPropertyName,
321
+ depth + 1,
322
+ );
323
+ if (typeof testValue === "boolean") {
324
+ return testValue ? consequentValue : alternateValue;
325
+ }
326
+ return mergeResolvedValues(consequentValue, alternateValue);
327
+ }
328
+ if (astNode.type === "LogicalExpression") {
329
+ const leftValue = resolveStaticValue(
330
+ astNode.left,
331
+ staticValueByName,
332
+ getLiteralStringValue,
333
+ getMemberExpressionPropertyName,
334
+ depth + 1,
335
+ );
336
+ const rightValue = resolveStaticValue(
337
+ astNode.right,
338
+ staticValueByName,
339
+ getLiteralStringValue,
340
+ getMemberExpressionPropertyName,
341
+ depth + 1,
342
+ );
343
+ if (astNode.operator === "||") {
344
+ if (leftValue === undefined) {
345
+ return rightValue;
346
+ }
347
+ if (hasOnlyResolvedValues(leftValue, (candidate) => Boolean(candidate))) {
348
+ return leftValue;
349
+ }
350
+ if (hasOnlyResolvedValues(leftValue, (candidate) => !candidate)) {
351
+ return rightValue;
352
+ }
353
+ return mergeResolvedValues(
354
+ filterResolvedValues(leftValue, (candidate) => Boolean(candidate)),
355
+ rightValue,
356
+ );
357
+ }
358
+ if (astNode.operator === "??") {
359
+ if (leftValue === undefined) {
360
+ return rightValue;
361
+ }
362
+ if (
363
+ hasOnlyResolvedValues(
364
+ leftValue,
365
+ (candidate) => candidate !== null && candidate !== undefined,
366
+ )
367
+ ) {
368
+ return leftValue;
369
+ }
370
+ if (
371
+ hasOnlyResolvedValues(
372
+ leftValue,
373
+ (candidate) => candidate === null || candidate === undefined,
374
+ )
375
+ ) {
376
+ return rightValue;
377
+ }
378
+ return mergeResolvedValues(
379
+ filterResolvedValues(
380
+ leftValue,
381
+ (candidate) => candidate !== null && candidate !== undefined,
382
+ ),
383
+ rightValue,
384
+ );
385
+ }
386
+ if (astNode.operator === "&&") {
387
+ if (leftValue === undefined) {
388
+ return undefined;
389
+ }
390
+ if (hasOnlyResolvedValues(leftValue, (candidate) => !candidate)) {
391
+ return leftValue;
392
+ }
393
+ if (hasOnlyResolvedValues(leftValue, (candidate) => Boolean(candidate))) {
394
+ return rightValue;
395
+ }
396
+ return mergeResolvedValues(
397
+ filterResolvedValues(leftValue, (candidate) => !candidate),
398
+ rightValue,
399
+ );
400
+ }
401
+ }
402
+ if (astNode.type === "ObjectExpression") {
403
+ const objectValue = {};
404
+ for (const property of astNode.properties || []) {
405
+ if (property.type !== "ObjectProperty") {
406
+ continue;
407
+ }
408
+ const keyName = getMemberExpressionPropertyName(property.key);
409
+ if (!keyName) {
410
+ continue;
411
+ }
412
+ const resolvedValue = resolveStaticValue(
413
+ property.value,
414
+ staticValueByName,
415
+ getLiteralStringValue,
416
+ getMemberExpressionPropertyName,
417
+ depth + 1,
418
+ );
419
+ if (resolvedValue !== undefined) {
420
+ objectValue[keyName] = resolvedValue;
421
+ }
422
+ }
423
+ return Object.keys(objectValue).length ? objectValue : undefined;
424
+ }
425
+ if (
426
+ astNode.type === "MemberExpression" ||
427
+ astNode.type === "OptionalMemberExpression"
428
+ ) {
429
+ const objectValue = resolveStaticValue(
430
+ astNode.object,
431
+ staticValueByName,
432
+ getLiteralStringValue,
433
+ getMemberExpressionPropertyName,
434
+ depth + 1,
435
+ );
436
+ const propertyName = getMemberExpressionPropertyName(astNode.property);
437
+ if (!propertyName) {
438
+ return undefined;
439
+ }
440
+ return getStaticObjectProperty(objectValue, propertyName);
441
+ }
442
+ if (astNode.type === "CallExpression") {
443
+ const callee = astNode.callee;
444
+ if (
445
+ callee?.type !== "MemberExpression" &&
446
+ callee?.type !== "OptionalMemberExpression"
447
+ ) {
448
+ return undefined;
449
+ }
450
+ const methodName = getMemberExpressionPropertyName(callee.property);
451
+ if (!methodName) {
452
+ return undefined;
453
+ }
454
+ const targetValue = resolveStaticValue(
455
+ callee.object,
456
+ staticValueByName,
457
+ getLiteralStringValue,
458
+ getMemberExpressionPropertyName,
459
+ depth + 1,
460
+ );
461
+ if (["toLowerCase", "toUpperCase", "trim"].includes(methodName)) {
462
+ if ((astNode.arguments || []).length) {
463
+ return undefined;
464
+ }
465
+ const transform =
466
+ methodName === "toLowerCase"
467
+ ? (value) => value.toLowerCase()
468
+ : methodName === "toUpperCase"
469
+ ? (value) => value.toUpperCase()
470
+ : (value) => value.trim();
471
+ return applyStringTransformToResolvedValue(targetValue, transform);
472
+ }
473
+ if (["replace", "replaceAll"].includes(methodName)) {
474
+ const searchValue = resolveStaticValue(
475
+ astNode.arguments?.[0],
476
+ staticValueByName,
477
+ getLiteralStringValue,
478
+ getMemberExpressionPropertyName,
479
+ depth + 1,
480
+ );
481
+ const replacementValue = resolveStaticValue(
482
+ astNode.arguments?.[1],
483
+ staticValueByName,
484
+ getLiteralStringValue,
485
+ getMemberExpressionPropertyName,
486
+ depth + 1,
487
+ );
488
+ if (
489
+ typeof searchValue !== "string" ||
490
+ typeof replacementValue !== "string"
491
+ ) {
492
+ return undefined;
493
+ }
494
+ return applyStringTransformToResolvedValue(targetValue, (value) =>
495
+ methodName === "replaceAll"
496
+ ? value.replaceAll(searchValue, replacementValue)
497
+ : value.replace(searchValue, replacementValue),
498
+ );
499
+ }
500
+ }
501
+ return undefined;
502
+ };
503
+
504
+ const statementDefinitelyAbrupt = (astNode) => {
505
+ if (!astNode) {
506
+ return false;
507
+ }
508
+ if (
509
+ [
510
+ "BreakStatement",
511
+ "ContinueStatement",
512
+ "ReturnStatement",
513
+ "ThrowStatement",
514
+ ].includes(astNode.type)
515
+ ) {
516
+ return true;
517
+ }
518
+ if (astNode.type === "BlockStatement") {
519
+ return statementListFallsThrough(astNode.body || []) === false;
520
+ }
521
+ if (astNode.type === "IfStatement") {
522
+ return (
523
+ statementDefinitelyAbrupt(astNode.consequent) &&
524
+ statementDefinitelyAbrupt(astNode.alternate)
525
+ );
526
+ }
527
+ return false;
528
+ };
529
+
530
+ const statementListFallsThrough = (statements) => {
531
+ const safeStatements = Array.isArray(statements) ? statements : [];
532
+ if (!safeStatements.length) {
533
+ return true;
534
+ }
535
+ return !statementDefinitelyAbrupt(safeStatements[safeStatements.length - 1]);
536
+ };
537
+
538
+ const getSwitchDiscriminantIdentifier = (astNode) => {
539
+ if (!astNode) {
540
+ return undefined;
541
+ }
542
+ if (
543
+ [
544
+ "ParenthesizedExpression",
545
+ "TSAsExpression",
546
+ "TSNonNullExpression",
547
+ "TSSatisfiesExpression",
548
+ "TypeCastExpression",
549
+ ].includes(astNode.type)
550
+ ) {
551
+ return getSwitchDiscriminantIdentifier(astNode.expression);
552
+ }
553
+ return astNode.type === "Identifier" ? astNode.name : undefined;
554
+ };
555
+
556
+ const isStaticPrimitiveResolvedValue = (value) => {
557
+ return (
558
+ ["boolean", "number", "string"].includes(typeof value) || value === null
559
+ );
560
+ };
561
+
562
+ const hasOnlyStaticPrimitiveResolvedValues = (value) => {
563
+ return hasOnlyResolvedValues(value, isStaticPrimitiveResolvedValue);
564
+ };
565
+
566
+ export const deriveStaticNarrowingsFromSwitchCase = (
567
+ switchCaseNode,
568
+ switchStatementNode,
569
+ staticValueByName,
570
+ getLiteralStringValue,
571
+ getMemberExpressionPropertyName,
572
+ ) => {
573
+ if (!switchCaseNode || !switchStatementNode) {
574
+ return undefined;
575
+ }
576
+ const identifierName = getSwitchDiscriminantIdentifier(
577
+ switchStatementNode.discriminant,
578
+ );
579
+ if (!identifierName) {
580
+ return undefined;
581
+ }
582
+ const switchCases = switchStatementNode.cases || [];
583
+ const currentCaseIndex = switchCases.indexOf(switchCaseNode);
584
+ if (currentCaseIndex === -1) {
585
+ return undefined;
586
+ }
587
+ if (switchCaseNode.test === null) {
588
+ const knownDiscriminantValue = staticValueByName.get(identifierName);
589
+ if (!hasOnlyStaticPrimitiveResolvedValues(knownDiscriminantValue)) {
590
+ return undefined;
591
+ }
592
+ const explicitCaseValues = [];
593
+ for (const caseNode of switchCases) {
594
+ if (caseNode.test === null) {
595
+ continue;
596
+ }
597
+ const caseValue = resolveStaticValue(
598
+ caseNode.test,
599
+ staticValueByName,
600
+ getLiteralStringValue,
601
+ getMemberExpressionPropertyName,
602
+ );
603
+ if (!hasOnlyStaticPrimitiveResolvedValues(caseValue)) {
604
+ return undefined;
605
+ }
606
+ explicitCaseValues.push(...toResolvedValueArray(caseValue));
607
+ }
608
+ const explicitCaseKeys = new Set(
609
+ explicitCaseValues.map((value) => resolvedValueKey(value)),
610
+ );
611
+ const remainingValues = toResolvedValueArray(knownDiscriminantValue).filter(
612
+ (value) => !explicitCaseKeys.has(resolvedValueKey(value)),
613
+ );
614
+ const narrowedValue = mergeResolvedValues(...remainingValues);
615
+ return createStaticNarrowingMap(identifierName, narrowedValue);
616
+ }
617
+ let chainStartIndex = currentCaseIndex;
618
+ for (
619
+ let caseIndex = currentCaseIndex - 1;
620
+ caseIndex >= 0 &&
621
+ statementListFallsThrough(switchCases[caseIndex].consequent);
622
+ caseIndex -= 1
623
+ ) {
624
+ chainStartIndex = caseIndex;
625
+ }
626
+ const caseValues = [];
627
+ for (
628
+ let caseIndex = chainStartIndex;
629
+ caseIndex <= currentCaseIndex;
630
+ caseIndex += 1
631
+ ) {
632
+ const caseNode = switchCases[caseIndex];
633
+ if (caseNode.test === null) {
634
+ return undefined;
635
+ }
636
+ const caseValue = resolveStaticValue(
637
+ caseNode.test,
638
+ staticValueByName,
639
+ getLiteralStringValue,
640
+ getMemberExpressionPropertyName,
641
+ );
642
+ if (!hasOnlyStaticPrimitiveResolvedValues(caseValue)) {
643
+ return undefined;
644
+ }
645
+ caseValues.push(caseValue);
646
+ }
647
+ const narrowedValue = mergeResolvedValues(...caseValues);
648
+ return createStaticNarrowingMap(identifierName, narrowedValue);
649
+ };
650
+
651
+ export const getScopedStaticValueByName = (
652
+ path,
653
+ staticValueByName,
654
+ getLiteralStringValue,
655
+ getMemberExpressionPropertyName,
656
+ ) => {
657
+ const scopedStaticValueByName = new Map(staticValueByName);
658
+ const ancestorNarrowingContexts = [];
659
+ let currentPath = path;
660
+ while (currentPath?.parentPath) {
661
+ const parentPath = currentPath.parentPath;
662
+ if (parentPath.node?.type === "IfStatement") {
663
+ const branchTaken =
664
+ currentPath.key === "consequent"
665
+ ? true
666
+ : currentPath.key === "alternate"
667
+ ? false
668
+ : undefined;
669
+ if (branchTaken !== undefined) {
670
+ ancestorNarrowingContexts.push({
671
+ branchTaken,
672
+ test: parentPath.node.test,
673
+ type: "if",
674
+ });
675
+ }
676
+ }
677
+ if (
678
+ parentPath.node?.type === "SwitchCase" &&
679
+ parentPath.parentPath?.node?.type === "SwitchStatement"
680
+ ) {
681
+ ancestorNarrowingContexts.push({
682
+ switchCaseNode: parentPath.node,
683
+ switchStatementNode: parentPath.parentPath.node,
684
+ type: "switch-case",
685
+ });
686
+ }
687
+ currentPath = parentPath;
688
+ }
689
+ ancestorNarrowingContexts.reverse().forEach((context) => {
690
+ const narrowedValues =
691
+ context.type === "if"
692
+ ? deriveStaticNarrowingsFromCondition(
693
+ context.test,
694
+ context.branchTaken,
695
+ getLiteralStringValue,
696
+ )
697
+ : deriveStaticNarrowingsFromSwitchCase(
698
+ context.switchCaseNode,
699
+ context.switchStatementNode,
700
+ scopedStaticValueByName,
701
+ getLiteralStringValue,
702
+ getMemberExpressionPropertyName,
703
+ );
704
+ if (!narrowedValues?.size) {
705
+ return;
706
+ }
707
+ narrowedValues.forEach((value, identifierName) => {
708
+ scopedStaticValueByName.set(identifierName, value);
709
+ });
710
+ });
711
+ return scopedStaticValueByName;
712
+ };