typekro 0.2.2 → 0.3.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 (213) hide show
  1. package/README.md +4 -3
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/core/composition/imperative.d.ts.map +1 -1
  4. package/dist/core/composition/imperative.js +15 -2
  5. package/dist/core/composition/imperative.js.map +1 -1
  6. package/dist/core/composition/typekro-runtime/typekro-runtime.d.ts.map +1 -1
  7. package/dist/core/composition/typekro-runtime/typekro-runtime.js +24 -25
  8. package/dist/core/composition/typekro-runtime/typekro-runtime.js.map +1 -1
  9. package/dist/core/dependencies/type-guards.d.ts.map +1 -1
  10. package/dist/core/dependencies/type-guards.js +7 -2
  11. package/dist/core/dependencies/type-guards.js.map +1 -1
  12. package/dist/core/deployment/engine.d.ts +13 -1
  13. package/dist/core/deployment/engine.d.ts.map +1 -1
  14. package/dist/core/deployment/engine.js +48 -3
  15. package/dist/core/deployment/engine.js.map +1 -1
  16. package/dist/core/errors.d.ts +85 -0
  17. package/dist/core/errors.d.ts.map +1 -1
  18. package/dist/core/errors.js +135 -0
  19. package/dist/core/errors.js.map +1 -1
  20. package/dist/core/evaluation/cel-optimizer.d.ts.map +1 -1
  21. package/dist/core/evaluation/cel-optimizer.js +7 -13
  22. package/dist/core/evaluation/cel-optimizer.js.map +1 -1
  23. package/dist/core/expressions/analyzer.d.ts +584 -0
  24. package/dist/core/expressions/analyzer.d.ts.map +1 -0
  25. package/dist/core/expressions/analyzer.js +2956 -0
  26. package/dist/core/expressions/analyzer.js.map +1 -0
  27. package/dist/core/expressions/cache.d.ts +136 -0
  28. package/dist/core/expressions/cache.d.ts.map +1 -0
  29. package/dist/core/expressions/cache.js +347 -0
  30. package/dist/core/expressions/cache.js.map +1 -0
  31. package/dist/core/expressions/cel-conversion-engine.d.ts +126 -0
  32. package/dist/core/expressions/cel-conversion-engine.d.ts.map +1 -0
  33. package/dist/core/expressions/cel-conversion-engine.js +293 -0
  34. package/dist/core/expressions/cel-conversion-engine.js.map +1 -0
  35. package/dist/core/expressions/compile-time-validation.d.ts +270 -0
  36. package/dist/core/expressions/compile-time-validation.d.ts.map +1 -0
  37. package/dist/core/expressions/compile-time-validation.js +506 -0
  38. package/dist/core/expressions/compile-time-validation.js.map +1 -0
  39. package/dist/core/expressions/composition-integration.d.ts +315 -0
  40. package/dist/core/expressions/composition-integration.d.ts.map +1 -0
  41. package/dist/core/expressions/composition-integration.js +936 -0
  42. package/dist/core/expressions/composition-integration.js.map +1 -0
  43. package/dist/core/expressions/conditional-expression-processor.d.ts +154 -0
  44. package/dist/core/expressions/conditional-expression-processor.d.ts.map +1 -0
  45. package/dist/core/expressions/conditional-expression-processor.js +479 -0
  46. package/dist/core/expressions/conditional-expression-processor.js.map +1 -0
  47. package/dist/core/expressions/conditional-integration.d.ts +133 -0
  48. package/dist/core/expressions/conditional-integration.d.ts.map +1 -0
  49. package/dist/core/expressions/conditional-integration.js +293 -0
  50. package/dist/core/expressions/conditional-integration.js.map +1 -0
  51. package/dist/core/expressions/conditional-validation.d.ts +181 -0
  52. package/dist/core/expressions/conditional-validation.d.ts.map +1 -0
  53. package/dist/core/expressions/conditional-validation.js +460 -0
  54. package/dist/core/expressions/conditional-validation.js.map +1 -0
  55. package/dist/core/expressions/context-aware-generator.d.ts +127 -0
  56. package/dist/core/expressions/context-aware-generator.d.ts.map +1 -0
  57. package/dist/core/expressions/context-aware-generator.js +500 -0
  58. package/dist/core/expressions/context-aware-generator.js.map +1 -0
  59. package/dist/core/expressions/context-detector.d.ts +148 -0
  60. package/dist/core/expressions/context-detector.d.ts.map +1 -0
  61. package/dist/core/expressions/context-detector.js +546 -0
  62. package/dist/core/expressions/context-detector.js.map +1 -0
  63. package/dist/core/expressions/context-switcher.d.ts +185 -0
  64. package/dist/core/expressions/context-switcher.d.ts.map +1 -0
  65. package/dist/core/expressions/context-switcher.js +515 -0
  66. package/dist/core/expressions/context-switcher.js.map +1 -0
  67. package/dist/core/expressions/context-validator.d.ts +176 -0
  68. package/dist/core/expressions/context-validator.d.ts.map +1 -0
  69. package/dist/core/expressions/context-validator.js +452 -0
  70. package/dist/core/expressions/context-validator.js.map +1 -0
  71. package/dist/core/expressions/custom-context-manager.d.ts +194 -0
  72. package/dist/core/expressions/custom-context-manager.d.ts.map +1 -0
  73. package/dist/core/expressions/custom-context-manager.js +390 -0
  74. package/dist/core/expressions/custom-context-manager.js.map +1 -0
  75. package/dist/core/expressions/expression-proxy.d.ts +80 -0
  76. package/dist/core/expressions/expression-proxy.d.ts.map +1 -0
  77. package/dist/core/expressions/expression-proxy.js +227 -0
  78. package/dist/core/expressions/expression-proxy.js.map +1 -0
  79. package/dist/core/expressions/factory-integration.d.ts +132 -0
  80. package/dist/core/expressions/factory-integration.d.ts.map +1 -0
  81. package/dist/core/expressions/factory-integration.js +327 -0
  82. package/dist/core/expressions/factory-integration.js.map +1 -0
  83. package/dist/core/expressions/factory-pattern-handler.d.ts +88 -0
  84. package/dist/core/expressions/factory-pattern-handler.d.ts.map +1 -0
  85. package/dist/core/expressions/factory-pattern-handler.js +336 -0
  86. package/dist/core/expressions/factory-pattern-handler.js.map +1 -0
  87. package/dist/core/expressions/field-hydration-processor.d.ts +188 -0
  88. package/dist/core/expressions/field-hydration-processor.d.ts.map +1 -0
  89. package/dist/core/expressions/field-hydration-processor.js +562 -0
  90. package/dist/core/expressions/field-hydration-processor.js.map +1 -0
  91. package/dist/core/expressions/imperative-analyzer.d.ts +21 -0
  92. package/dist/core/expressions/imperative-analyzer.d.ts.map +1 -0
  93. package/dist/core/expressions/imperative-analyzer.js +457 -0
  94. package/dist/core/expressions/imperative-analyzer.js.map +1 -0
  95. package/dist/core/expressions/index.d.ts +54 -0
  96. package/dist/core/expressions/index.d.ts.map +1 -0
  97. package/dist/core/expressions/index.js +50 -0
  98. package/dist/core/expressions/index.js.map +1 -0
  99. package/dist/core/expressions/lazy-analysis.d.ts +1128 -0
  100. package/dist/core/expressions/lazy-analysis.d.ts.map +1 -0
  101. package/dist/core/expressions/lazy-analysis.js +2443 -0
  102. package/dist/core/expressions/lazy-analysis.js.map +1 -0
  103. package/dist/core/expressions/magic-assignable-analyzer.d.ts +123 -0
  104. package/dist/core/expressions/magic-assignable-analyzer.d.ts.map +1 -0
  105. package/dist/core/expressions/magic-assignable-analyzer.js +352 -0
  106. package/dist/core/expressions/magic-assignable-analyzer.js.map +1 -0
  107. package/dist/core/expressions/magic-proxy-analyzer.d.ts +206 -0
  108. package/dist/core/expressions/magic-proxy-analyzer.d.ts.map +1 -0
  109. package/dist/core/expressions/magic-proxy-analyzer.js +639 -0
  110. package/dist/core/expressions/magic-proxy-analyzer.js.map +1 -0
  111. package/dist/core/expressions/magic-proxy-detector.d.ts +154 -0
  112. package/dist/core/expressions/magic-proxy-detector.d.ts.map +1 -0
  113. package/dist/core/expressions/magic-proxy-detector.js +242 -0
  114. package/dist/core/expressions/magic-proxy-detector.js.map +1 -0
  115. package/dist/core/expressions/migration-helpers.d.ts +133 -0
  116. package/dist/core/expressions/migration-helpers.d.ts.map +1 -0
  117. package/dist/core/expressions/migration-helpers.js +443 -0
  118. package/dist/core/expressions/migration-helpers.js.map +1 -0
  119. package/dist/core/expressions/optionality-handler.d.ts +503 -0
  120. package/dist/core/expressions/optionality-handler.d.ts.map +1 -0
  121. package/dist/core/expressions/optionality-handler.js +1306 -0
  122. package/dist/core/expressions/optionality-handler.js.map +1 -0
  123. package/dist/core/expressions/readiness-integration.d.ts +119 -0
  124. package/dist/core/expressions/readiness-integration.d.ts.map +1 -0
  125. package/dist/core/expressions/readiness-integration.js +386 -0
  126. package/dist/core/expressions/readiness-integration.js.map +1 -0
  127. package/dist/core/expressions/resource-analyzer.d.ts +486 -0
  128. package/dist/core/expressions/resource-analyzer.d.ts.map +1 -0
  129. package/dist/core/expressions/resource-analyzer.js +1086 -0
  130. package/dist/core/expressions/resource-analyzer.js.map +1 -0
  131. package/dist/core/expressions/resource-validation.d.ts +187 -0
  132. package/dist/core/expressions/resource-validation.d.ts.map +1 -0
  133. package/dist/core/expressions/resource-validation.js +552 -0
  134. package/dist/core/expressions/resource-validation.js.map +1 -0
  135. package/dist/core/expressions/runtime-error-mapper.d.ts +138 -0
  136. package/dist/core/expressions/runtime-error-mapper.d.ts.map +1 -0
  137. package/dist/core/expressions/runtime-error-mapper.js +412 -0
  138. package/dist/core/expressions/runtime-error-mapper.js.map +1 -0
  139. package/dist/core/expressions/source-map.d.ts +168 -0
  140. package/dist/core/expressions/source-map.d.ts.map +1 -0
  141. package/dist/core/expressions/source-map.js +350 -0
  142. package/dist/core/expressions/source-map.js.map +1 -0
  143. package/dist/core/expressions/status-builder-analyzer.d.ts +353 -0
  144. package/dist/core/expressions/status-builder-analyzer.d.ts.map +1 -0
  145. package/dist/core/expressions/status-builder-analyzer.js +1311 -0
  146. package/dist/core/expressions/status-builder-analyzer.js.map +1 -0
  147. package/dist/core/expressions/type-inference.d.ts +184 -0
  148. package/dist/core/expressions/type-inference.d.ts.map +1 -0
  149. package/dist/core/expressions/type-inference.js +838 -0
  150. package/dist/core/expressions/type-inference.js.map +1 -0
  151. package/dist/core/expressions/type-safety.d.ts +203 -0
  152. package/dist/core/expressions/type-safety.d.ts.map +1 -0
  153. package/dist/core/expressions/type-safety.js +442 -0
  154. package/dist/core/expressions/type-safety.js.map +1 -0
  155. package/dist/core/expressions/types.d.ts +282 -0
  156. package/dist/core/expressions/types.d.ts.map +1 -0
  157. package/dist/core/expressions/types.js +8 -0
  158. package/dist/core/expressions/types.js.map +1 -0
  159. package/dist/core/kubernetes/client-provider.js +2 -2
  160. package/dist/core/kubernetes/client-provider.js.map +1 -1
  161. package/dist/core/references/cel.d.ts +13 -1
  162. package/dist/core/references/cel.d.ts.map +1 -1
  163. package/dist/core/references/cel.js +50 -0
  164. package/dist/core/references/cel.js.map +1 -1
  165. package/dist/core/references/schema-proxy.d.ts.map +1 -1
  166. package/dist/core/references/schema-proxy.js +13 -8
  167. package/dist/core/references/schema-proxy.js.map +1 -1
  168. package/dist/core/serialization/core.d.ts.map +1 -1
  169. package/dist/core/serialization/core.js +573 -9
  170. package/dist/core/serialization/core.js.map +1 -1
  171. package/dist/core/types/deployment.d.ts +7 -0
  172. package/dist/core/types/deployment.d.ts.map +1 -1
  173. package/dist/core/types/deployment.js +7 -0
  174. package/dist/core/types/deployment.js.map +1 -1
  175. package/dist/core/types/index.d.ts +1 -0
  176. package/dist/core/types/index.d.ts.map +1 -1
  177. package/dist/core/types/index.js.map +1 -1
  178. package/dist/core/validation/cel-validator.d.ts.map +1 -1
  179. package/dist/core/validation/cel-validator.js +4 -8
  180. package/dist/core/validation/cel-validator.js.map +1 -1
  181. package/dist/core.d.ts +1 -1
  182. package/dist/core.d.ts.map +1 -1
  183. package/dist/core.js +1 -1
  184. package/dist/core.js.map +1 -1
  185. package/dist/factories/helm/helm-release.d.ts.map +1 -1
  186. package/dist/factories/helm/helm-release.js +0 -5
  187. package/dist/factories/helm/helm-release.js.map +1 -1
  188. package/dist/factories/helm/types.d.ts +1 -1
  189. package/dist/factories/helm/types.d.ts.map +1 -1
  190. package/dist/factories/index.js +1 -0
  191. package/dist/factories/index.js.map +1 -1
  192. package/dist/factories/shared.d.ts.map +1 -1
  193. package/dist/factories/shared.js +21 -1
  194. package/dist/factories/shared.js.map +1 -1
  195. package/dist/factories/simple/index.d.ts +2 -2
  196. package/dist/factories/simple/index.d.ts.map +1 -1
  197. package/dist/factories/simple/workloads/deployment.d.ts +3 -3
  198. package/dist/factories/simple/workloads/deployment.d.ts.map +1 -1
  199. package/dist/factories/simple/workloads/deployment.js +37 -11
  200. package/dist/factories/simple/workloads/deployment.js.map +1 -1
  201. package/dist/index.d.ts +1 -1
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +1 -1
  204. package/dist/index.js.map +1 -1
  205. package/dist/utils/index.d.ts +1 -1
  206. package/dist/utils/index.d.ts.map +1 -1
  207. package/dist/utils/index.js +1 -1
  208. package/dist/utils/index.js.map +1 -1
  209. package/dist/utils/type-guards.d.ts +6 -0
  210. package/dist/utils/type-guards.d.ts.map +1 -1
  211. package/dist/utils/type-guards.js +25 -2
  212. package/dist/utils/type-guards.js.map +1 -1
  213. package/package.json +6 -1
@@ -0,0 +1,2443 @@
1
+ /**
2
+ * Lazy Analysis Support for JavaScript to CEL Expression Conversion
3
+ *
4
+ * This module provides lazy evaluation capabilities for expressions containing
5
+ * KubernetesRef objects, optimizing performance by deferring analysis until
6
+ * the results are actually needed.
7
+ */
8
+ import { JavaScriptToCelAnalyzer } from './analyzer.js';
9
+ import { containsKubernetesRefs, extractResourceReferences } from '../../utils/type-guards.js';
10
+ import { ConversionError } from '../errors.js';
11
+ import { KUBERNETES_REF_BRAND } from '../constants/brands.js';
12
+ /**
13
+ * Lazy wrapper for expressions that may contain KubernetesRef objects
14
+ * Defers analysis until the CEL expression is actually needed
15
+ */
16
+ export class LazyAnalyzedExpression {
17
+ _expression;
18
+ _context;
19
+ _analyzed = false;
20
+ _result = null;
21
+ _error = null;
22
+ _analyzer;
23
+ constructor(_expression, _context, analyzer) {
24
+ this._expression = _expression;
25
+ this._context = _context;
26
+ this._analyzer = analyzer || new JavaScriptToCelAnalyzer();
27
+ }
28
+ /**
29
+ * Get the original expression without triggering analysis
30
+ */
31
+ get originalExpression() {
32
+ return this._expression;
33
+ }
34
+ /**
35
+ * Get the analysis context
36
+ */
37
+ get context() {
38
+ return this._context;
39
+ }
40
+ /**
41
+ * Check if the expression has been analyzed yet
42
+ */
43
+ get isAnalyzed() {
44
+ return this._analyzed;
45
+ }
46
+ /**
47
+ * Check if the expression requires conversion (contains KubernetesRef objects)
48
+ * This is a fast check that doesn't trigger full analysis
49
+ */
50
+ get requiresConversion() {
51
+ return containsKubernetesRefs(this._expression);
52
+ }
53
+ /**
54
+ * Check if the expression is static (no KubernetesRef objects)
55
+ * This is a fast check that doesn't trigger analysis
56
+ */
57
+ get isStatic() {
58
+ return !this.requiresConversion;
59
+ }
60
+ /**
61
+ * Get the analysis result, triggering analysis if not already done
62
+ */
63
+ get result() {
64
+ if (!this._analyzed) {
65
+ this._performAnalysis();
66
+ }
67
+ if (this._error) {
68
+ throw this._error;
69
+ }
70
+ return this._result;
71
+ }
72
+ /**
73
+ * Get the CEL expression, triggering analysis if needed
74
+ */
75
+ get celExpression() {
76
+ return this.result.celExpression;
77
+ }
78
+ /**
79
+ * Get the dependencies, triggering analysis if needed
80
+ */
81
+ get dependencies() {
82
+ return this.result.dependencies;
83
+ }
84
+ /**
85
+ * Get conversion errors, triggering analysis if needed
86
+ */
87
+ get errors() {
88
+ return this.result.errors;
89
+ }
90
+ /**
91
+ * Check if the analysis was successful, triggering analysis if needed
92
+ */
93
+ get isValid() {
94
+ return this.result.valid;
95
+ }
96
+ /**
97
+ * Force analysis to occur immediately
98
+ */
99
+ analyze() {
100
+ if (!this._analyzed) {
101
+ this._performAnalysis();
102
+ }
103
+ if (this._error) {
104
+ throw this._error;
105
+ }
106
+ return this._result;
107
+ }
108
+ /**
109
+ * Try to get the result without throwing errors
110
+ */
111
+ tryGetResult() {
112
+ try {
113
+ const result = this.result;
114
+ return { success: true, result };
115
+ }
116
+ catch (error) {
117
+ return {
118
+ success: false,
119
+ error: error instanceof Error ? error : new Error(String(error))
120
+ };
121
+ }
122
+ }
123
+ /**
124
+ * Create a new lazy expression with a different context
125
+ */
126
+ withContext(newContext) {
127
+ return new LazyAnalyzedExpression(this._expression, newContext, this._analyzer);
128
+ }
129
+ /**
130
+ * Create a new lazy expression with a different analyzer
131
+ */
132
+ withAnalyzer(analyzer) {
133
+ return new LazyAnalyzedExpression(this._expression, this._context, analyzer);
134
+ }
135
+ /**
136
+ * Perform the actual analysis
137
+ */
138
+ _performAnalysis() {
139
+ try {
140
+ this._result = this._analyzer.analyzeExpressionWithRefs(this._expression, this._context);
141
+ this._analyzed = true;
142
+ }
143
+ catch (error) {
144
+ this._error = error instanceof Error ? error : new Error(String(error));
145
+ this._analyzed = true;
146
+ }
147
+ }
148
+ /**
149
+ * Reset the analysis state (for testing or re-analysis)
150
+ */
151
+ reset() {
152
+ this._analyzed = false;
153
+ this._result = null;
154
+ this._error = null;
155
+ }
156
+ /**
157
+ * Get a string representation for debugging
158
+ */
159
+ toString() {
160
+ const exprStr = typeof this._expression === 'string'
161
+ ? this._expression
162
+ : JSON.stringify(this._expression);
163
+ if (this._analyzed) {
164
+ if (this._error) {
165
+ return `LazyAnalyzedExpression(${exprStr}) [ERROR: ${this._error.message}]`;
166
+ }
167
+ return `LazyAnalyzedExpression(${exprStr}) [ANALYZED: ${this._result?.valid ? 'VALID' : 'INVALID'}]`;
168
+ }
169
+ return `LazyAnalyzedExpression(${exprStr}) [NOT ANALYZED]`;
170
+ }
171
+ }
172
+ /**
173
+ * Collection of lazy analyzed expressions for batch processing
174
+ */
175
+ export class LazyExpressionCollection {
176
+ _expressions = new Map();
177
+ _analyzer;
178
+ constructor(analyzer) {
179
+ this._analyzer = analyzer || new JavaScriptToCelAnalyzer();
180
+ }
181
+ /**
182
+ * Add an expression to the collection
183
+ */
184
+ add(key, expression, context) {
185
+ const lazy = new LazyAnalyzedExpression(expression, context, this._analyzer);
186
+ this._expressions.set(key, lazy);
187
+ return lazy;
188
+ }
189
+ /**
190
+ * Get a lazy expression by key
191
+ */
192
+ get(key) {
193
+ return this._expressions.get(key);
194
+ }
195
+ /**
196
+ * Check if an expression exists
197
+ */
198
+ has(key) {
199
+ return this._expressions.has(key);
200
+ }
201
+ /**
202
+ * Remove an expression
203
+ */
204
+ remove(key) {
205
+ return this._expressions.delete(key);
206
+ }
207
+ /**
208
+ * Get all expression keys
209
+ */
210
+ keys() {
211
+ return Array.from(this._expressions.keys());
212
+ }
213
+ /**
214
+ * Get all lazy expressions
215
+ */
216
+ values() {
217
+ return Array.from(this._expressions.values());
218
+ }
219
+ /**
220
+ * Get all entries
221
+ */
222
+ entries() {
223
+ return Array.from(this._expressions.entries());
224
+ }
225
+ /**
226
+ * Get the number of expressions
227
+ */
228
+ get size() {
229
+ return this._expressions.size;
230
+ }
231
+ /**
232
+ * Check how many expressions require conversion
233
+ */
234
+ get requiresConversionCount() {
235
+ return this.values().filter(expr => expr.requiresConversion).length;
236
+ }
237
+ /**
238
+ * Check how many expressions are static
239
+ */
240
+ get staticCount() {
241
+ return this.values().filter(expr => expr.isStatic).length;
242
+ }
243
+ /**
244
+ * Check how many expressions have been analyzed
245
+ */
246
+ get analyzedCount() {
247
+ return this.values().filter(expr => expr.isAnalyzed).length;
248
+ }
249
+ /**
250
+ * Analyze all expressions that require conversion
251
+ */
252
+ analyzeAll() {
253
+ const results = new Map();
254
+ for (const [key, expr] of this._expressions) {
255
+ if (expr.requiresConversion) {
256
+ try {
257
+ results.set(key, expr.analyze());
258
+ }
259
+ catch (error) {
260
+ // Create error result
261
+ results.set(key, {
262
+ valid: false,
263
+ celExpression: null,
264
+ dependencies: [],
265
+ sourceMap: [],
266
+ errors: [new ConversionError(error instanceof Error ? error.message : String(error), String(expr.originalExpression), 'unknown')],
267
+ warnings: [],
268
+ requiresConversion: true
269
+ });
270
+ }
271
+ }
272
+ }
273
+ return results;
274
+ }
275
+ /**
276
+ * Analyze expressions in parallel (for independent expressions)
277
+ */
278
+ async analyzeAllParallel() {
279
+ const promises = Array.from(this._expressions.entries())
280
+ .filter(([, expr]) => expr.requiresConversion)
281
+ .map(async ([key, expr]) => {
282
+ try {
283
+ const result = expr.analyze();
284
+ return [key, result];
285
+ }
286
+ catch (error) {
287
+ const errorResult = {
288
+ valid: false,
289
+ celExpression: null,
290
+ dependencies: [],
291
+ sourceMap: [],
292
+ errors: [new ConversionError(error instanceof Error ? error.message : String(error), String(expr.originalExpression), 'unknown')],
293
+ warnings: [],
294
+ requiresConversion: true
295
+ };
296
+ return [key, errorResult];
297
+ }
298
+ });
299
+ const results = await Promise.all(promises);
300
+ return new Map(results);
301
+ }
302
+ /**
303
+ * Get statistics about the collection
304
+ */
305
+ getStats() {
306
+ const total = this.size;
307
+ const requiresConversion = this.requiresConversionCount;
308
+ const static_ = this.staticCount;
309
+ const analyzed = this.analyzedCount;
310
+ return {
311
+ total,
312
+ requiresConversion,
313
+ static: static_,
314
+ analyzed,
315
+ pending: requiresConversion - analyzed,
316
+ conversionRatio: total > 0 ? requiresConversion / total : 0,
317
+ analysisProgress: requiresConversion > 0 ? analyzed / requiresConversion : 1
318
+ };
319
+ }
320
+ /**
321
+ * Clear all expressions
322
+ */
323
+ clear() {
324
+ this._expressions.clear();
325
+ }
326
+ /**
327
+ * Reset analysis state for all expressions
328
+ */
329
+ resetAll() {
330
+ for (const expr of this._expressions.values()) {
331
+ expr.reset();
332
+ }
333
+ }
334
+ }
335
+ /**
336
+ * Factory function to create lazy analyzed expressions
337
+ */
338
+ export function createLazyExpression(expression, context, analyzer) {
339
+ return new LazyAnalyzedExpression(expression, context, analyzer);
340
+ }
341
+ /**
342
+ * Factory function to create lazy expression collections
343
+ */
344
+ export function createLazyCollection(analyzer) {
345
+ return new LazyExpressionCollection(analyzer);
346
+ }
347
+ /**
348
+ * On-demand expression analyzer that performs KubernetesRef detection and analysis
349
+ * only when results are actually needed
350
+ */
351
+ export class OnDemandExpressionAnalyzer {
352
+ _analyzer;
353
+ _cache = new Map();
354
+ _cacheHits = 0;
355
+ _cacheMisses = 0;
356
+ constructor(analyzer) {
357
+ this._analyzer = analyzer || new JavaScriptToCelAnalyzer();
358
+ }
359
+ /**
360
+ * Create a lazy expression that will be analyzed on-demand
361
+ */
362
+ createLazyExpression(expression, context, cacheKey) {
363
+ // Generate cache key if not provided
364
+ const key = cacheKey || this._generateCacheKey(expression, context);
365
+ // Check cache first
366
+ const cached = this._cache.get(key);
367
+ if (cached) {
368
+ this._cacheHits++;
369
+ return cached;
370
+ }
371
+ // Create new lazy expression
372
+ this._cacheMisses++;
373
+ const lazy = new LazyAnalyzedExpression(expression, context, this._analyzer);
374
+ // Cache it for future use
375
+ this._cache.set(key, lazy);
376
+ return lazy;
377
+ }
378
+ /**
379
+ * Analyze an expression immediately if it contains KubernetesRef objects,
380
+ * otherwise return it as-is
381
+ */
382
+ analyzeIfNeeded(expression, context) {
383
+ // Fast check for KubernetesRef objects
384
+ if (!containsKubernetesRefs(expression)) {
385
+ return {
386
+ needsConversion: false,
387
+ result: expression
388
+ };
389
+ }
390
+ // Create lazy expression for on-demand analysis
391
+ const lazy = this.createLazyExpression(expression, context);
392
+ return {
393
+ needsConversion: true,
394
+ result: lazy,
395
+ lazy
396
+ };
397
+ }
398
+ /**
399
+ * Batch analyze multiple expressions, only processing those that need conversion
400
+ */
401
+ batchAnalyze(expressions) {
402
+ const results = new Map();
403
+ for (const { key, expression, context } of expressions) {
404
+ const result = this.analyzeIfNeeded(expression, context);
405
+ results.set(key, result);
406
+ }
407
+ return results;
408
+ }
409
+ /**
410
+ * Get cache statistics
411
+ */
412
+ getCacheStats() {
413
+ const total = this._cacheHits + this._cacheMisses;
414
+ return {
415
+ hits: this._cacheHits,
416
+ misses: this._cacheMisses,
417
+ size: this._cache.size,
418
+ hitRatio: total > 0 ? this._cacheHits / total : 0
419
+ };
420
+ }
421
+ /**
422
+ * Clear the cache
423
+ */
424
+ clearCache() {
425
+ this._cache.clear();
426
+ this._cacheHits = 0;
427
+ this._cacheMisses = 0;
428
+ }
429
+ /**
430
+ * Generate a cache key for an expression and context
431
+ */
432
+ _generateCacheKey(expression, context) {
433
+ const exprStr = typeof expression === 'string'
434
+ ? expression
435
+ : JSON.stringify(expression);
436
+ const contextStr = JSON.stringify({
437
+ type: context.type,
438
+ factoryType: context.factoryType,
439
+ availableRefs: Object.keys(context.availableReferences || {}),
440
+ strictTypeChecking: context.strictTypeChecking,
441
+ validateResourceReferences: context.validateResourceReferences
442
+ });
443
+ return `${exprStr}:${contextStr}`;
444
+ }
445
+ }
446
+ /**
447
+ * Expression tree analyzer for complex nested expressions with KubernetesRef objects
448
+ */
449
+ export class ExpressionTreeAnalyzer {
450
+ _onDemandAnalyzer;
451
+ constructor(analyzer) {
452
+ this._onDemandAnalyzer = new OnDemandExpressionAnalyzer(analyzer);
453
+ }
454
+ /**
455
+ * Analyze a complex expression tree, creating lazy expressions for branches
456
+ * that contain KubernetesRef objects
457
+ */
458
+ analyzeTree(expressionTree, context, path = []) {
459
+ const result = {
460
+ path,
461
+ needsConversion: false,
462
+ staticValue: null,
463
+ lazyExpression: null,
464
+ children: new Map()
465
+ };
466
+ // Handle primitive values
467
+ if (this._isPrimitive(expressionTree)) {
468
+ if (containsKubernetesRefs(expressionTree)) {
469
+ result.needsConversion = true;
470
+ result.lazyExpression = this._onDemandAnalyzer.createLazyExpression(expressionTree, context, path.join('.'));
471
+ }
472
+ else {
473
+ result.staticValue = expressionTree;
474
+ }
475
+ return result;
476
+ }
477
+ // Handle arrays
478
+ if (Array.isArray(expressionTree)) {
479
+ let hasKubernetesRefs = false;
480
+ for (let i = 0; i < expressionTree.length; i++) {
481
+ const childPath = [...path, i.toString()];
482
+ const childResult = this.analyzeTree(expressionTree[i], context, childPath);
483
+ result.children.set(i.toString(), childResult);
484
+ if (childResult.needsConversion) {
485
+ hasKubernetesRefs = true;
486
+ }
487
+ }
488
+ if (hasKubernetesRefs) {
489
+ result.needsConversion = true;
490
+ result.lazyExpression = this._onDemandAnalyzer.createLazyExpression(expressionTree, context, path.join('.'));
491
+ }
492
+ else {
493
+ result.staticValue = expressionTree;
494
+ }
495
+ return result;
496
+ }
497
+ // Handle objects
498
+ if (expressionTree && typeof expressionTree === 'object') {
499
+ // First check if the object itself contains KubernetesRef objects
500
+ const objectHasRefs = containsKubernetesRefs(expressionTree);
501
+ let hasKubernetesRefs = objectHasRefs;
502
+ for (const [key, value] of Object.entries(expressionTree)) {
503
+ const childPath = [...path, key];
504
+ const childResult = this.analyzeTree(value, context, childPath);
505
+ result.children.set(key, childResult);
506
+ if (childResult.needsConversion) {
507
+ hasKubernetesRefs = true;
508
+ }
509
+ }
510
+ if (hasKubernetesRefs) {
511
+ result.needsConversion = true;
512
+ result.lazyExpression = this._onDemandAnalyzer.createLazyExpression(expressionTree, context, path.join('.'));
513
+ }
514
+ else {
515
+ result.staticValue = expressionTree;
516
+ }
517
+ return result;
518
+ }
519
+ // Fallback for unknown types
520
+ result.staticValue = expressionTree;
521
+ return result;
522
+ }
523
+ /**
524
+ * Get all lazy expressions from a tree result
525
+ */
526
+ getAllLazyExpressions(treeResult) {
527
+ const expressions = [];
528
+ if (treeResult.lazyExpression) {
529
+ expressions.push(treeResult.lazyExpression);
530
+ }
531
+ for (const child of treeResult.children.values()) {
532
+ expressions.push(...this.getAllLazyExpressions(child));
533
+ }
534
+ return expressions;
535
+ }
536
+ /**
537
+ * Get statistics about the expression tree
538
+ */
539
+ getTreeStats(treeResult) {
540
+ let totalNodes = 1;
541
+ let lazyNodes = treeResult.lazyExpression ? 1 : 0;
542
+ let staticNodes = treeResult.staticValue !== null ? 1 : 0;
543
+ let maxDepth = 0;
544
+ for (const child of treeResult.children.values()) {
545
+ const childStats = this.getTreeStats(child);
546
+ totalNodes += childStats.totalNodes;
547
+ lazyNodes += childStats.lazyNodes;
548
+ staticNodes += childStats.staticNodes;
549
+ maxDepth = Math.max(maxDepth, childStats.maxDepth + 1);
550
+ }
551
+ return {
552
+ totalNodes,
553
+ lazyNodes,
554
+ staticNodes,
555
+ maxDepth,
556
+ lazyRatio: totalNodes > 0 ? lazyNodes / totalNodes : 0
557
+ };
558
+ }
559
+ /**
560
+ * Check if a value is a primitive type
561
+ */
562
+ _isPrimitive(value) {
563
+ return value === null ||
564
+ value === undefined ||
565
+ typeof value === 'string' ||
566
+ typeof value === 'number' ||
567
+ typeof value === 'boolean' ||
568
+ typeof value === 'function';
569
+ }
570
+ }
571
+ /**
572
+ * Global on-demand analyzer instance
573
+ */
574
+ export const globalOnDemandAnalyzer = new OnDemandExpressionAnalyzer();
575
+ /**
576
+ * Lazy loading manager for complex expression trees with magic proxy integration
577
+ */
578
+ export class LazyExpressionTreeLoader {
579
+ _treeAnalyzer;
580
+ _loadedTrees = new Map();
581
+ _loadingPromises = new Map();
582
+ _loadCount = 0;
583
+ constructor(analyzer) {
584
+ this._treeAnalyzer = new ExpressionTreeAnalyzer(analyzer);
585
+ }
586
+ /**
587
+ * Load an expression tree lazily, returning immediately with a promise
588
+ */
589
+ async loadTree(expressionTree, context, treeId) {
590
+ const id = treeId || this._generateTreeId(expressionTree);
591
+ // Check if already loaded
592
+ const cached = this._loadedTrees.get(id);
593
+ if (cached) {
594
+ return cached;
595
+ }
596
+ // Check if currently loading
597
+ const loading = this._loadingPromises.get(id);
598
+ if (loading) {
599
+ return loading;
600
+ }
601
+ // Start loading
602
+ const loadPromise = this._performTreeLoad(expressionTree, context, id);
603
+ this._loadingPromises.set(id, loadPromise);
604
+ try {
605
+ const result = await loadPromise;
606
+ this._loadedTrees.set(id, result);
607
+ return result;
608
+ }
609
+ finally {
610
+ this._loadingPromises.delete(id);
611
+ }
612
+ }
613
+ /**
614
+ * Load multiple trees in parallel
615
+ */
616
+ async loadTrees(trees) {
617
+ const loadPromises = trees.map(async ({ tree, context, id }) => {
618
+ const treeId = id || this._generateTreeId(tree);
619
+ const result = await this.loadTree(tree, context, treeId);
620
+ return [treeId, result];
621
+ });
622
+ const results = await Promise.all(loadPromises);
623
+ return new Map(results);
624
+ }
625
+ /**
626
+ * Get a tree if it's already loaded, otherwise return null
627
+ */
628
+ getLoadedTree(treeId) {
629
+ return this._loadedTrees.get(treeId) || null;
630
+ }
631
+ /**
632
+ * Check if a tree is currently being loaded
633
+ */
634
+ isLoading(treeId) {
635
+ return this._loadingPromises.has(treeId);
636
+ }
637
+ /**
638
+ * Check if a tree is loaded
639
+ */
640
+ isLoaded(treeId) {
641
+ return this._loadedTrees.has(treeId);
642
+ }
643
+ /**
644
+ * Preload trees that are likely to be needed soon
645
+ */
646
+ async preloadTrees(trees) {
647
+ // Sort by priority (higher priority first)
648
+ const sortedTrees = trees.sort((a, b) => (b.priority || 0) - (a.priority || 0));
649
+ // Load high priority trees first
650
+ const highPriorityTrees = sortedTrees.filter(t => (t.priority || 0) > 5);
651
+ if (highPriorityTrees.length > 0) {
652
+ await this.loadTrees(highPriorityTrees);
653
+ }
654
+ // Load remaining trees in background
655
+ const remainingTrees = sortedTrees.filter(t => (t.priority || 0) <= 5);
656
+ if (remainingTrees.length > 0) {
657
+ // Don't await - load in background
658
+ this.loadTrees(remainingTrees).catch(error => {
659
+ console.warn('Background tree preloading failed:', error);
660
+ });
661
+ }
662
+ }
663
+ /**
664
+ * Get loading statistics
665
+ */
666
+ getStats() {
667
+ return {
668
+ loadedTrees: this._loadedTrees.size,
669
+ loadingTrees: this._loadingPromises.size,
670
+ totalLoads: this._loadCount,
671
+ memoryUsage: this._estimateMemoryUsage()
672
+ };
673
+ }
674
+ /**
675
+ * Clear loaded trees to free memory
676
+ */
677
+ clearCache() {
678
+ this._loadedTrees.clear();
679
+ this._loadCount = 0;
680
+ }
681
+ /**
682
+ * Perform the actual tree loading
683
+ */
684
+ async _performTreeLoad(expressionTree, context, treeId) {
685
+ this._loadCount++;
686
+ // Use setTimeout to yield control and allow other operations
687
+ await new Promise(resolve => setTimeout(resolve, 0));
688
+ // Analyze the tree
689
+ const result = this._treeAnalyzer.analyzeTree(expressionTree, context, [treeId]);
690
+ return result;
691
+ }
692
+ /**
693
+ * Generate a unique ID for a tree
694
+ */
695
+ _generateTreeId(tree) {
696
+ const treeStr = JSON.stringify(tree);
697
+ // Simple hash function for tree ID
698
+ let hash = 0;
699
+ for (let i = 0; i < treeStr.length; i++) {
700
+ const char = treeStr.charCodeAt(i);
701
+ hash = ((hash << 5) - hash) + char;
702
+ hash = hash & hash; // Convert to 32-bit integer
703
+ }
704
+ return `tree_${Math.abs(hash)}`;
705
+ }
706
+ /**
707
+ * Estimate memory usage of loaded trees
708
+ */
709
+ _estimateMemoryUsage() {
710
+ let totalSize = 0;
711
+ for (const tree of this._loadedTrees.values()) {
712
+ totalSize += this._estimateTreeSize(tree);
713
+ }
714
+ return totalSize;
715
+ }
716
+ /**
717
+ * Estimate the size of a tree result
718
+ */
719
+ _estimateTreeSize(tree) {
720
+ let size = 100; // Base size
721
+ if (tree.staticValue) {
722
+ size += JSON.stringify(tree.staticValue).length;
723
+ }
724
+ if (tree.lazyExpression) {
725
+ size += 200; // Estimated size of lazy expression
726
+ }
727
+ for (const child of tree.children.values()) {
728
+ size += this._estimateTreeSize(child);
729
+ }
730
+ return size;
731
+ }
732
+ }
733
+ /**
734
+ * Magic proxy integration for lazy expression loading
735
+ */
736
+ export class MagicProxyLazyIntegration {
737
+ _treeLoader;
738
+ _proxyCache = new Map();
739
+ constructor(analyzer) {
740
+ this._treeLoader = new LazyExpressionTreeLoader(analyzer);
741
+ }
742
+ /**
743
+ * Create a lazy proxy for a complex object that may contain KubernetesRef objects
744
+ */
745
+ createLazyProxy(target, context, options = {}) {
746
+ const proxyId = options.id || this._generateProxyId(target);
747
+ // Check cache first
748
+ const cached = this._proxyCache.get(proxyId);
749
+ if (cached) {
750
+ return cached;
751
+ }
752
+ const proxy = new Proxy(target, {
753
+ get: (obj, prop) => {
754
+ const value = obj[prop];
755
+ // If the value contains KubernetesRef objects, wrap it in lazy analysis
756
+ if (containsKubernetesRefs(value)) {
757
+ return this._createLazyValue(value, context, `${proxyId}.${String(prop)}`);
758
+ }
759
+ // For complex objects, create nested lazy proxies
760
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
761
+ return this.createLazyProxy(value, context, {
762
+ ...options,
763
+ id: `${proxyId}.${String(prop)}`
764
+ });
765
+ }
766
+ return value;
767
+ },
768
+ set: (obj, prop, value) => {
769
+ // Invalidate cache when properties are set
770
+ this._invalidateCache(proxyId);
771
+ obj[prop] = value;
772
+ return true;
773
+ }
774
+ });
775
+ // Cache the proxy
776
+ this._proxyCache.set(proxyId, proxy);
777
+ return proxy;
778
+ }
779
+ /**
780
+ * Load expression trees for all KubernetesRef-containing values in an object
781
+ */
782
+ async preloadObjectTrees(obj, context, maxDepth = 5) {
783
+ const trees = [];
784
+ this._collectTreesFromObject(obj, context, trees, [], maxDepth);
785
+ if (trees.length > 0) {
786
+ await this._treeLoader.preloadTrees(trees);
787
+ }
788
+ }
789
+ /**
790
+ * Get statistics about the magic proxy integration
791
+ */
792
+ getStats() {
793
+ return {
794
+ cachedProxies: this._proxyCache.size,
795
+ treeLoaderStats: this._treeLoader.getStats()
796
+ };
797
+ }
798
+ /**
799
+ * Clear all caches
800
+ */
801
+ clearCaches() {
802
+ this._proxyCache.clear();
803
+ this._treeLoader.clearCache();
804
+ }
805
+ /**
806
+ * Create a lazy value wrapper
807
+ */
808
+ _createLazyValue(value, context, valueId) {
809
+ // For simple values, create a lazy expression
810
+ if (this._isSimpleValue(value)) {
811
+ const lazy = globalOnDemandAnalyzer.createLazyExpression(value, context, valueId);
812
+ // Return a proxy that triggers analysis when accessed
813
+ return new Proxy({}, {
814
+ get: (_, prop) => {
815
+ if (prop === 'valueOf' || prop === 'toString') {
816
+ return () => lazy.result.celExpression?.expression || String(value);
817
+ }
818
+ if (prop === Symbol.toPrimitive) {
819
+ return () => lazy.result.celExpression?.expression || value;
820
+ }
821
+ // Trigger analysis and return the result
822
+ const result = lazy.result;
823
+ if (result.valid && result.celExpression) {
824
+ return result.celExpression.expression;
825
+ }
826
+ return value;
827
+ }
828
+ });
829
+ }
830
+ // For complex values, load the tree lazily
831
+ this._treeLoader.loadTree(value, context, valueId).catch(error => {
832
+ console.warn(`Failed to load tree for ${valueId}:`, error);
833
+ });
834
+ return value;
835
+ }
836
+ /**
837
+ * Check if a value is simple (not an object or array)
838
+ */
839
+ _isSimpleValue(value) {
840
+ return value === null ||
841
+ value === undefined ||
842
+ typeof value === 'string' ||
843
+ typeof value === 'number' ||
844
+ typeof value === 'boolean' ||
845
+ typeof value === 'function';
846
+ }
847
+ /**
848
+ * Generate a unique ID for a proxy
849
+ */
850
+ _generateProxyId(target) {
851
+ const targetStr = JSON.stringify(target);
852
+ let hash = 0;
853
+ for (let i = 0; i < targetStr.length; i++) {
854
+ const char = targetStr.charCodeAt(i);
855
+ hash = ((hash << 5) - hash) + char;
856
+ hash = hash & hash;
857
+ }
858
+ return `proxy_${Math.abs(hash)}`;
859
+ }
860
+ /**
861
+ * Invalidate cache entries related to a proxy
862
+ */
863
+ _invalidateCache(proxyId) {
864
+ // Remove the proxy from cache
865
+ this._proxyCache.delete(proxyId);
866
+ // Remove related entries (those that start with the proxy ID)
867
+ for (const key of this._proxyCache.keys()) {
868
+ if (key.startsWith(`${proxyId}.`)) {
869
+ this._proxyCache.delete(key);
870
+ }
871
+ }
872
+ }
873
+ /**
874
+ * Collect trees from an object recursively
875
+ */
876
+ _collectTreesFromObject(obj, context, trees, path, maxDepth) {
877
+ if (maxDepth <= 0 || !obj || typeof obj !== 'object') {
878
+ return;
879
+ }
880
+ if (containsKubernetesRefs(obj)) {
881
+ trees.push({
882
+ tree: obj,
883
+ context,
884
+ id: path.join('.'),
885
+ priority: maxDepth // Higher depth = higher priority
886
+ });
887
+ }
888
+ // Recurse into object properties
889
+ for (const [key, value] of Object.entries(obj)) {
890
+ this._collectTreesFromObject(value, context, trees, [...path, key], maxDepth - 1);
891
+ }
892
+ }
893
+ }
894
+ /**
895
+ * Global lazy tree loader instance
896
+ */
897
+ export const globalLazyTreeLoader = new LazyExpressionTreeLoader();
898
+ /**
899
+ * Memory-optimized expression manager for large sets of KubernetesRef-containing expressions
900
+ */
901
+ export class MemoryOptimizedExpressionManager {
902
+ _expressions = new Map();
903
+ _expressionSizes = new Map();
904
+ _accessTimes = new Map();
905
+ _analyzer;
906
+ _totalMemoryUsage = 0;
907
+ _maxMemoryUsage;
908
+ _cleanupThreshold;
909
+ _lastCleanup = Date.now();
910
+ constructor(analyzer, options = {}) {
911
+ this._analyzer = analyzer || new JavaScriptToCelAnalyzer();
912
+ this._maxMemoryUsage = options.maxMemoryUsage || 50 * 1024 * 1024; // 50MB default
913
+ this._cleanupThreshold = options.cleanupThreshold || 0.8; // Cleanup at 80% capacity
914
+ }
915
+ /**
916
+ * Create or retrieve a lazy expression with memory management
917
+ */
918
+ getOrCreateExpression(key, expression, context) {
919
+ // Check if expression exists and is still alive
920
+ const existingRef = this._expressions.get(key);
921
+ if (existingRef) {
922
+ const existing = existingRef.deref();
923
+ if (existing) {
924
+ this._accessTimes.set(key, Date.now());
925
+ return existing;
926
+ }
927
+ else {
928
+ // Expression was garbage collected, clean up references
929
+ this._cleanupExpression(key);
930
+ }
931
+ }
932
+ // Check if we need to cleanup before creating new expression
933
+ if (this._shouldCleanup()) {
934
+ this._performCleanup();
935
+ }
936
+ // Create new lazy expression
937
+ const lazy = new LazyAnalyzedExpression(expression, context, this._analyzer);
938
+ const estimatedSize = this._estimateExpressionSize(expression);
939
+ // Store with weak reference
940
+ this._expressions.set(key, new WeakRef(lazy));
941
+ this._expressionSizes.set(key, estimatedSize);
942
+ this._accessTimes.set(key, Date.now());
943
+ this._totalMemoryUsage += estimatedSize;
944
+ return lazy;
945
+ }
946
+ /**
947
+ * Batch create expressions with memory optimization
948
+ */
949
+ batchCreateExpressions(expressions) {
950
+ const results = new Map();
951
+ // Sort by estimated size (smallest first) to optimize memory allocation
952
+ const sortedExpressions = expressions
953
+ .map(expr => ({
954
+ ...expr,
955
+ estimatedSize: this._estimateExpressionSize(expr.expression)
956
+ }))
957
+ .sort((a, b) => a.estimatedSize - b.estimatedSize);
958
+ for (const { key, expression, context } of sortedExpressions) {
959
+ const lazy = this.getOrCreateExpression(key, expression, context);
960
+ results.set(key, lazy);
961
+ }
962
+ return results;
963
+ }
964
+ /**
965
+ * Get memory usage statistics
966
+ */
967
+ getMemoryStats() {
968
+ // Clean up dead references first
969
+ this._cleanupDeadReferences();
970
+ return {
971
+ totalExpressions: this._expressions.size,
972
+ totalMemoryUsage: this._totalMemoryUsage,
973
+ maxMemoryUsage: this._maxMemoryUsage,
974
+ memoryUtilization: this._totalMemoryUsage / this._maxMemoryUsage,
975
+ averageExpressionSize: this._expressions.size > 0
976
+ ? this._totalMemoryUsage / this._expressions.size
977
+ : 0,
978
+ lastCleanup: this._lastCleanup,
979
+ needsCleanup: this._shouldCleanup()
980
+ };
981
+ }
982
+ /**
983
+ * Force cleanup of unused expressions
984
+ */
985
+ forceCleanup() {
986
+ return this._performCleanup();
987
+ }
988
+ /**
989
+ * Set memory limits
990
+ */
991
+ setMemoryLimits(maxMemoryUsage, cleanupThreshold) {
992
+ this._maxMemoryUsage = maxMemoryUsage;
993
+ this._cleanupThreshold = cleanupThreshold;
994
+ // Trigger cleanup if we're now over the limit
995
+ if (this._shouldCleanup()) {
996
+ this._performCleanup();
997
+ }
998
+ }
999
+ /**
1000
+ * Clear all expressions
1001
+ */
1002
+ clear() {
1003
+ this._expressions.clear();
1004
+ this._expressionSizes.clear();
1005
+ this._accessTimes.clear();
1006
+ this._totalMemoryUsage = 0;
1007
+ this._lastCleanup = Date.now();
1008
+ }
1009
+ /**
1010
+ * Get expressions that are likely to be garbage collected soon
1011
+ */
1012
+ getExpiringExpressions() {
1013
+ const now = Date.now();
1014
+ const expiring = [];
1015
+ for (const [key, ref] of this._expressions) {
1016
+ const expr = ref.deref();
1017
+ if (!expr) {
1018
+ expiring.push(key);
1019
+ }
1020
+ else {
1021
+ const lastAccess = this._accessTimes.get(key) || 0;
1022
+ const age = now - lastAccess;
1023
+ // Consider expressions older than 5 minutes as expiring
1024
+ if (age > 5 * 60 * 1000) {
1025
+ expiring.push(key);
1026
+ }
1027
+ }
1028
+ }
1029
+ return expiring;
1030
+ }
1031
+ /**
1032
+ * Estimate the memory size of an expression
1033
+ */
1034
+ _estimateExpressionSize(expression) {
1035
+ if (typeof expression === 'string') {
1036
+ return expression.length * 2; // UTF-16 encoding
1037
+ }
1038
+ if (typeof expression === 'function') {
1039
+ return expression.toString().length * 2 + 1000; // Function overhead
1040
+ }
1041
+ if (Array.isArray(expression)) {
1042
+ return expression.reduce((size, item) => size + this._estimateExpressionSize(item), 100);
1043
+ }
1044
+ if (expression && typeof expression === 'object') {
1045
+ let size = 100; // Object overhead
1046
+ for (const [key, value] of Object.entries(expression)) {
1047
+ size += key.length * 2; // Key size
1048
+ size += this._estimateExpressionSize(value); // Value size
1049
+ }
1050
+ return size;
1051
+ }
1052
+ return 50; // Default size for primitives
1053
+ }
1054
+ /**
1055
+ * Check if cleanup is needed
1056
+ */
1057
+ _shouldCleanup() {
1058
+ return this._totalMemoryUsage > (this._maxMemoryUsage * this._cleanupThreshold);
1059
+ }
1060
+ /**
1061
+ * Perform memory cleanup
1062
+ */
1063
+ _performCleanup() {
1064
+ const startTime = Date.now();
1065
+ const initialMemory = this._totalMemoryUsage;
1066
+ const initialCount = this._expressions.size;
1067
+ // First, clean up dead references
1068
+ const deadRefs = this._cleanupDeadReferences();
1069
+ // If still over threshold, remove least recently used expressions
1070
+ if (this._shouldCleanup()) {
1071
+ const lruCleanup = this._cleanupLRU();
1072
+ deadRefs.cleaned += lruCleanup.cleaned;
1073
+ deadRefs.freedMemory += lruCleanup.freedMemory;
1074
+ }
1075
+ this._lastCleanup = Date.now();
1076
+ return {
1077
+ duration: Date.now() - startTime,
1078
+ initialMemoryUsage: initialMemory,
1079
+ finalMemoryUsage: this._totalMemoryUsage,
1080
+ freedMemory: initialMemory - this._totalMemoryUsage,
1081
+ initialExpressionCount: initialCount,
1082
+ finalExpressionCount: this._expressions.size,
1083
+ cleanedExpressions: initialCount - this._expressions.size
1084
+ };
1085
+ }
1086
+ /**
1087
+ * Clean up dead weak references
1088
+ */
1089
+ _cleanupDeadReferences() {
1090
+ let cleaned = 0;
1091
+ let freedMemory = 0;
1092
+ for (const [key, ref] of this._expressions) {
1093
+ if (!ref.deref()) {
1094
+ const size = this._expressionSizes.get(key) || 0;
1095
+ this._cleanupExpression(key);
1096
+ cleaned++;
1097
+ freedMemory += size;
1098
+ }
1099
+ }
1100
+ return { cleaned, freedMemory };
1101
+ }
1102
+ /**
1103
+ * Clean up least recently used expressions
1104
+ */
1105
+ _cleanupLRU() {
1106
+ const _now = Date.now();
1107
+ const entries = Array.from(this._accessTimes.entries())
1108
+ .sort((a, b) => a[1] - b[1]); // Sort by access time (oldest first)
1109
+ let cleaned = 0;
1110
+ let freedMemory = 0;
1111
+ const targetMemory = this._maxMemoryUsage * (this._cleanupThreshold - 0.1); // Clean to 10% below threshold
1112
+ for (const [key] of entries) {
1113
+ if (this._totalMemoryUsage <= targetMemory) {
1114
+ break;
1115
+ }
1116
+ const size = this._expressionSizes.get(key) || 0;
1117
+ this._cleanupExpression(key);
1118
+ cleaned++;
1119
+ freedMemory += size;
1120
+ }
1121
+ return { cleaned, freedMemory };
1122
+ }
1123
+ /**
1124
+ * Clean up a single expression
1125
+ */
1126
+ _cleanupExpression(key) {
1127
+ const size = this._expressionSizes.get(key) || 0;
1128
+ this._expressions.delete(key);
1129
+ this._expressionSizes.delete(key);
1130
+ this._accessTimes.delete(key);
1131
+ this._totalMemoryUsage -= size;
1132
+ }
1133
+ }
1134
+ /**
1135
+ * Advanced parallel expression analyzer for independent expressions with KubernetesRef objects
1136
+ */
1137
+ export class ParallelExpressionAnalyzer {
1138
+ _analyzer;
1139
+ _maxConcurrency;
1140
+ _detector;
1141
+ _activeAnalyses = 0;
1142
+ _totalAnalyses = 0;
1143
+ _completedAnalyses = 0;
1144
+ _failedAnalyses = 0;
1145
+ constructor(analyzer, maxConcurrency = 4, detector) {
1146
+ this._analyzer = analyzer || new JavaScriptToCelAnalyzer();
1147
+ this._maxConcurrency = maxConcurrency;
1148
+ this._detector = detector || new OptimizedKubernetesRefDetector();
1149
+ }
1150
+ /**
1151
+ * Analyze multiple expressions in parallel with advanced scheduling
1152
+ */
1153
+ async analyzeParallel(expressions) {
1154
+ const results = new Map();
1155
+ // Pre-filter expressions that need conversion
1156
+ const filteredExpressions = expressions.filter(({ expression }) => this._detector.containsKubernetesRefs(expression));
1157
+ // Add static expressions directly to results
1158
+ for (const { key, expression } of expressions) {
1159
+ if (!this._detector.containsKubernetesRefs(expression)) {
1160
+ results.set(key, {
1161
+ valid: true,
1162
+ celExpression: null,
1163
+ dependencies: [],
1164
+ sourceMap: [],
1165
+ errors: [],
1166
+ warnings: [],
1167
+ requiresConversion: false
1168
+ });
1169
+ }
1170
+ }
1171
+ if (filteredExpressions.length === 0) {
1172
+ return results;
1173
+ }
1174
+ this._totalAnalyses = filteredExpressions.length;
1175
+ this._completedAnalyses = 0;
1176
+ this._failedAnalyses = 0;
1177
+ // Create work queue with dependency analysis
1178
+ const workQueue = await this._createWorkQueue(filteredExpressions);
1179
+ // Process work queue in parallel
1180
+ const parallelResults = await this._processWorkQueue(workQueue);
1181
+ // Merge results
1182
+ for (const [key, result] of parallelResults) {
1183
+ results.set(key, result);
1184
+ }
1185
+ return results;
1186
+ }
1187
+ /**
1188
+ * Analyze expressions with priority-based scheduling and dependency resolution
1189
+ */
1190
+ async analyzePrioritized(expressions) {
1191
+ // Build dependency graph
1192
+ const dependencyGraph = this._buildDependencyGraph(expressions);
1193
+ // Topological sort to respect dependencies
1194
+ const sortedExpressions = this._topologicalSort(expressions, dependencyGraph);
1195
+ // Group by priority within dependency levels
1196
+ const priorityGroups = this._groupByPriority(sortedExpressions);
1197
+ const results = new Map();
1198
+ // Process each priority group
1199
+ for (const group of priorityGroups) {
1200
+ const groupResults = await this.analyzeParallel(group);
1201
+ for (const [key, result] of groupResults) {
1202
+ results.set(key, result);
1203
+ }
1204
+ }
1205
+ return results;
1206
+ }
1207
+ /**
1208
+ * Analyze expressions with adaptive concurrency based on system load
1209
+ */
1210
+ async analyzeAdaptive(expressions, options = {}) {
1211
+ const { initialConcurrency = this._maxConcurrency, maxConcurrency = this._maxConcurrency * 2, minConcurrency = 1, performanceThreshold = 100 // ms
1212
+ } = options;
1213
+ let currentConcurrency = initialConcurrency;
1214
+ const results = new Map();
1215
+ const remaining = [...expressions];
1216
+ while (remaining.length > 0) {
1217
+ // Take batch based on current concurrency
1218
+ const batch = remaining.splice(0, currentConcurrency);
1219
+ // Measure performance
1220
+ const startTime = performance.now();
1221
+ const batchResults = await this._processBatch(batch);
1222
+ const endTime = performance.now();
1223
+ const avgTime = (endTime - startTime) / batch.length;
1224
+ // Adapt concurrency based on performance
1225
+ if (avgTime > performanceThreshold && currentConcurrency > minConcurrency) {
1226
+ currentConcurrency = Math.max(minConcurrency, currentConcurrency - 1);
1227
+ }
1228
+ else if (avgTime < performanceThreshold / 2 && currentConcurrency < maxConcurrency) {
1229
+ currentConcurrency = Math.min(maxConcurrency, currentConcurrency + 1);
1230
+ }
1231
+ // Merge results
1232
+ for (const [key, result] of batchResults) {
1233
+ results.set(key, result);
1234
+ }
1235
+ }
1236
+ return results;
1237
+ }
1238
+ /**
1239
+ * Stream analysis results as they complete
1240
+ */
1241
+ async *analyzeStream(expressions) {
1242
+ const total = expressions.length;
1243
+ let completed = 0;
1244
+ // Filter expressions that need conversion
1245
+ const needConversion = expressions.filter(({ expression }) => this._detector.containsKubernetesRefs(expression));
1246
+ // Yield static results immediately
1247
+ for (const { key, expression } of expressions) {
1248
+ if (!this._detector.containsKubernetesRefs(expression)) {
1249
+ completed++;
1250
+ yield {
1251
+ key,
1252
+ result: {
1253
+ valid: true,
1254
+ celExpression: null,
1255
+ dependencies: [],
1256
+ sourceMap: [],
1257
+ errors: [],
1258
+ warnings: [],
1259
+ requiresConversion: false
1260
+ },
1261
+ progress: completed / total
1262
+ };
1263
+ }
1264
+ }
1265
+ // Process expressions that need conversion
1266
+ const batches = this._createBatches(needConversion, this._maxConcurrency);
1267
+ for (const batch of batches) {
1268
+ const promises = batch.map(async ({ key, expression, context }) => {
1269
+ this._activeAnalyses++;
1270
+ try {
1271
+ const result = this._analyzer.analyzeExpressionWithRefs(expression, context);
1272
+ this._completedAnalyses++;
1273
+ return { key, result };
1274
+ }
1275
+ catch (error) {
1276
+ this._failedAnalyses++;
1277
+ const errorResult = {
1278
+ valid: false,
1279
+ celExpression: null,
1280
+ dependencies: [],
1281
+ sourceMap: [],
1282
+ errors: [new ConversionError(error instanceof Error ? error.message : String(error), String(expression), 'unknown')],
1283
+ warnings: [],
1284
+ requiresConversion: true
1285
+ };
1286
+ return { key, result: errorResult };
1287
+ }
1288
+ finally {
1289
+ this._activeAnalyses--;
1290
+ }
1291
+ });
1292
+ // Yield results as they complete
1293
+ for (const promise of promises) {
1294
+ const { key, result } = await promise;
1295
+ completed++;
1296
+ yield {
1297
+ key,
1298
+ result,
1299
+ progress: completed / total
1300
+ };
1301
+ }
1302
+ }
1303
+ }
1304
+ /**
1305
+ * Get comprehensive analysis statistics
1306
+ */
1307
+ getStats() {
1308
+ return {
1309
+ maxConcurrency: this._maxConcurrency,
1310
+ activeAnalyses: this._activeAnalyses,
1311
+ utilizationRatio: this._activeAnalyses / this._maxConcurrency,
1312
+ totalAnalyses: this._totalAnalyses,
1313
+ completedAnalyses: this._completedAnalyses,
1314
+ failedAnalyses: this._failedAnalyses,
1315
+ successRate: this._totalAnalyses > 0 ? this._completedAnalyses / this._totalAnalyses : 0,
1316
+ detectorStats: this._detector.getCacheStats()
1317
+ };
1318
+ }
1319
+ /**
1320
+ * Create work queue with complexity analysis
1321
+ */
1322
+ async _createWorkQueue(expressions) {
1323
+ const workItems = [];
1324
+ for (const { key, expression, context } of expressions) {
1325
+ const complexity = this._calculateComplexity(expression);
1326
+ const refCount = this._detector.extractKubernetesRefs(expression).length;
1327
+ workItems.push({
1328
+ key,
1329
+ expression,
1330
+ context,
1331
+ complexity,
1332
+ refCount,
1333
+ estimatedTime: complexity * 10 + refCount * 5 // Simple estimation
1334
+ });
1335
+ }
1336
+ // Sort by estimated time (shortest first for better parallelization)
1337
+ return workItems.sort((a, b) => a.estimatedTime - b.estimatedTime);
1338
+ }
1339
+ /**
1340
+ * Process work queue in parallel
1341
+ */
1342
+ async _processWorkQueue(workQueue) {
1343
+ const results = new Map();
1344
+ const batches = this._createBatches(workQueue, this._maxConcurrency);
1345
+ for (const batch of batches) {
1346
+ const batchResults = await this._processBatch(batch);
1347
+ for (const [key, result] of batchResults) {
1348
+ results.set(key, result);
1349
+ }
1350
+ }
1351
+ return results;
1352
+ }
1353
+ /**
1354
+ * Process a batch of work items
1355
+ */
1356
+ async _processBatch(batch) {
1357
+ const promises = batch.map(async ({ key, expression, context }) => {
1358
+ this._activeAnalyses++;
1359
+ try {
1360
+ const result = this._analyzer.analyzeExpressionWithRefs(expression, context);
1361
+ this._completedAnalyses++;
1362
+ return [key, result];
1363
+ }
1364
+ catch (error) {
1365
+ this._failedAnalyses++;
1366
+ const errorResult = {
1367
+ valid: false,
1368
+ celExpression: null,
1369
+ dependencies: [],
1370
+ sourceMap: [],
1371
+ errors: [new ConversionError(error instanceof Error ? error.message : String(error), String(expression), 'unknown')],
1372
+ warnings: [],
1373
+ requiresConversion: true
1374
+ };
1375
+ return [key, errorResult];
1376
+ }
1377
+ finally {
1378
+ this._activeAnalyses--;
1379
+ }
1380
+ });
1381
+ const results = await Promise.all(promises);
1382
+ return new Map(results);
1383
+ }
1384
+ /**
1385
+ * Build dependency graph for expressions
1386
+ */
1387
+ _buildDependencyGraph(expressions) {
1388
+ const graph = new Map();
1389
+ for (const { key, dependencies = [] } of expressions) {
1390
+ graph.set(key, dependencies);
1391
+ }
1392
+ return graph;
1393
+ }
1394
+ /**
1395
+ * Topological sort for dependency resolution
1396
+ */
1397
+ _topologicalSort(expressions, dependencyGraph) {
1398
+ const visited = new Set();
1399
+ const visiting = new Set();
1400
+ const result = [];
1401
+ const expressionMap = new Map(expressions.map(expr => [expr.key, expr]));
1402
+ const visit = (key) => {
1403
+ if (visited.has(key))
1404
+ return;
1405
+ if (visiting.has(key)) {
1406
+ throw new Error(`Circular dependency detected involving ${key}`);
1407
+ }
1408
+ visiting.add(key);
1409
+ const dependencies = dependencyGraph.get(key) || [];
1410
+ for (const dep of dependencies) {
1411
+ visit(dep);
1412
+ }
1413
+ visiting.delete(key);
1414
+ visited.add(key);
1415
+ const expression = expressionMap.get(key);
1416
+ if (expression) {
1417
+ result.push(expression);
1418
+ }
1419
+ };
1420
+ for (const { key } of expressions) {
1421
+ visit(key);
1422
+ }
1423
+ return result;
1424
+ }
1425
+ /**
1426
+ * Group expressions by priority
1427
+ */
1428
+ _groupByPriority(expressions) {
1429
+ const groups = new Map();
1430
+ for (const expr of expressions) {
1431
+ const priority = expr.priority;
1432
+ if (!groups.has(priority)) {
1433
+ groups.set(priority, []);
1434
+ }
1435
+ groups.get(priority)?.push(expr);
1436
+ }
1437
+ // Sort by priority (highest first)
1438
+ const sortedPriorities = Array.from(groups.keys()).sort((a, b) => b - a);
1439
+ return sortedPriorities.map(priority => groups.get(priority));
1440
+ }
1441
+ /**
1442
+ * Calculate expression complexity
1443
+ */
1444
+ _calculateComplexity(expression) {
1445
+ if (typeof expression === 'string') {
1446
+ let complexity = Math.min(expression.length / 20, 10);
1447
+ if (expression.includes('?.'))
1448
+ complexity += 2;
1449
+ if (expression.includes('??'))
1450
+ complexity += 2;
1451
+ if (expression.includes('${'))
1452
+ complexity += 3;
1453
+ return complexity;
1454
+ }
1455
+ if (Array.isArray(expression)) {
1456
+ return expression.reduce((sum, item) => sum + this._calculateComplexity(item), 1);
1457
+ }
1458
+ if (expression && typeof expression === 'object') {
1459
+ let complexity = 1;
1460
+ for (const value of Object.values(expression)) {
1461
+ complexity += this._calculateComplexity(value);
1462
+ }
1463
+ return Math.min(complexity, 50); // Cap complexity
1464
+ }
1465
+ return 1;
1466
+ }
1467
+ /**
1468
+ * Create batches for parallel processing
1469
+ */
1470
+ _createBatches(items, batchSize) {
1471
+ const batches = [];
1472
+ for (let i = 0; i < items.length; i += batchSize) {
1473
+ batches.push(items.slice(i, i + batchSize));
1474
+ }
1475
+ return batches;
1476
+ }
1477
+ }
1478
+ /**
1479
+ * Global memory-optimized expression manager
1480
+ */
1481
+ export const globalMemoryOptimizedManager = new MemoryOptimizedExpressionManager();
1482
+ /**
1483
+ * Performance profiler for expression analysis with KubernetesRef detection
1484
+ */
1485
+ export class ExpressionAnalysisProfiler {
1486
+ _profiles = new Map();
1487
+ _analyzer;
1488
+ _enabled = true;
1489
+ constructor(analyzer) {
1490
+ this._analyzer = analyzer || new JavaScriptToCelAnalyzer();
1491
+ }
1492
+ /**
1493
+ * Enable or disable profiling
1494
+ */
1495
+ setEnabled(enabled) {
1496
+ this._enabled = enabled;
1497
+ }
1498
+ /**
1499
+ * Profile expression analysis performance
1500
+ */
1501
+ profileExpression(expression, context, profileId) {
1502
+ const id = profileId || this._generateProfileId(expression);
1503
+ if (!this._enabled) {
1504
+ const result = this._analyzer.analyzeExpressionWithRefs(expression, context);
1505
+ return {
1506
+ result,
1507
+ profile: {
1508
+ id,
1509
+ expression: String(expression),
1510
+ startTime: Date.now(),
1511
+ endTime: Date.now(),
1512
+ duration: 0,
1513
+ kubernetesRefDetectionTime: 0,
1514
+ astParsingTime: 0,
1515
+ celGenerationTime: 0,
1516
+ memoryUsage: 0,
1517
+ kubernetesRefCount: 0,
1518
+ expressionComplexity: 0,
1519
+ cacheHit: false
1520
+ }
1521
+ };
1522
+ }
1523
+ const profile = {
1524
+ id,
1525
+ expression: String(expression),
1526
+ startTime: performance.now(),
1527
+ endTime: 0,
1528
+ duration: 0,
1529
+ kubernetesRefDetectionTime: 0,
1530
+ astParsingTime: 0,
1531
+ celGenerationTime: 0,
1532
+ memoryUsage: 0,
1533
+ kubernetesRefCount: 0,
1534
+ expressionComplexity: this._calculateComplexity(expression),
1535
+ cacheHit: false
1536
+ };
1537
+ // Profile KubernetesRef detection
1538
+ const refDetectionStart = performance.now();
1539
+ const hasRefs = containsKubernetesRefs(expression);
1540
+ const refDetectionEnd = performance.now();
1541
+ profile.kubernetesRefDetectionTime = refDetectionEnd - refDetectionStart;
1542
+ if (hasRefs) {
1543
+ const refs = extractResourceReferences(expression);
1544
+ profile.kubernetesRefCount = refs.length;
1545
+ }
1546
+ // Profile the actual analysis
1547
+ const analysisStart = performance.now();
1548
+ const result = this._analyzer.analyzeExpressionWithRefs(expression, context);
1549
+ const analysisEnd = performance.now();
1550
+ profile.endTime = performance.now();
1551
+ profile.duration = profile.endTime - profile.startTime;
1552
+ profile.celGenerationTime = analysisEnd - analysisStart - profile.kubernetesRefDetectionTime;
1553
+ profile.memoryUsage = this._estimateMemoryUsage(expression, result);
1554
+ // Store the profile
1555
+ this._profiles.set(id, profile);
1556
+ return { result, profile };
1557
+ }
1558
+ /**
1559
+ * Profile multiple expressions in batch
1560
+ */
1561
+ profileBatch(expressions) {
1562
+ const results = new Map();
1563
+ for (const { expression, context, id } of expressions) {
1564
+ const profileResult = this.profileExpression(expression, context, id);
1565
+ const profileId = id || this._generateProfileId(expression);
1566
+ results.set(profileId, profileResult);
1567
+ }
1568
+ return results;
1569
+ }
1570
+ /**
1571
+ * Get performance statistics
1572
+ */
1573
+ getStats() {
1574
+ const profiles = Array.from(this._profiles.values());
1575
+ if (profiles.length === 0) {
1576
+ return {
1577
+ totalProfiles: 0,
1578
+ averageDuration: 0,
1579
+ averageKubernetesRefDetectionTime: 0,
1580
+ averageCelGenerationTime: 0,
1581
+ averageMemoryUsage: 0,
1582
+ averageKubernetesRefCount: 0,
1583
+ averageComplexity: 0,
1584
+ slowestExpression: null,
1585
+ fastestExpression: null,
1586
+ mostComplexExpression: null,
1587
+ cacheHitRatio: 0
1588
+ };
1589
+ }
1590
+ const totalDuration = profiles.reduce((sum, p) => sum + p.duration, 0);
1591
+ const totalRefDetection = profiles.reduce((sum, p) => sum + p.kubernetesRefDetectionTime, 0);
1592
+ const totalCelGeneration = profiles.reduce((sum, p) => sum + p.celGenerationTime, 0);
1593
+ const totalMemory = profiles.reduce((sum, p) => sum + p.memoryUsage, 0);
1594
+ const totalRefCount = profiles.reduce((sum, p) => sum + p.kubernetesRefCount, 0);
1595
+ const totalComplexity = profiles.reduce((sum, p) => sum + p.expressionComplexity, 0);
1596
+ const cacheHits = profiles.filter(p => p.cacheHit).length;
1597
+ const sortedByDuration = [...profiles].sort((a, b) => b.duration - a.duration);
1598
+ const sortedByComplexity = [...profiles].sort((a, b) => b.expressionComplexity - a.expressionComplexity);
1599
+ return {
1600
+ totalProfiles: profiles.length,
1601
+ averageDuration: totalDuration / profiles.length,
1602
+ averageKubernetesRefDetectionTime: totalRefDetection / profiles.length,
1603
+ averageCelGenerationTime: totalCelGeneration / profiles.length,
1604
+ averageMemoryUsage: totalMemory / profiles.length,
1605
+ averageKubernetesRefCount: totalRefCount / profiles.length,
1606
+ averageComplexity: totalComplexity / profiles.length,
1607
+ slowestExpression: sortedByDuration[0] || null,
1608
+ fastestExpression: sortedByDuration[sortedByDuration.length - 1] || null,
1609
+ mostComplexExpression: sortedByComplexity[0] || null,
1610
+ cacheHitRatio: profiles.length > 0 ? cacheHits / profiles.length : 0
1611
+ };
1612
+ }
1613
+ /**
1614
+ * Get profiles that exceed performance thresholds
1615
+ */
1616
+ getSlowProfiles(durationThreshold = 10) {
1617
+ return Array.from(this._profiles.values())
1618
+ .filter(profile => profile.duration > durationThreshold)
1619
+ .sort((a, b) => b.duration - a.duration);
1620
+ }
1621
+ /**
1622
+ * Get profiles with high KubernetesRef detection overhead
1623
+ */
1624
+ getHighOverheadProfiles(overheadThreshold = 0.5) {
1625
+ return Array.from(this._profiles.values())
1626
+ .filter(profile => {
1627
+ const overhead = profile.duration > 0
1628
+ ? profile.kubernetesRefDetectionTime / profile.duration
1629
+ : 0;
1630
+ return overhead > overheadThreshold;
1631
+ })
1632
+ .sort((a, b) => {
1633
+ const aOverhead = a.duration > 0 ? a.kubernetesRefDetectionTime / a.duration : 0;
1634
+ const bOverhead = b.duration > 0 ? b.kubernetesRefDetectionTime / b.duration : 0;
1635
+ return bOverhead - aOverhead;
1636
+ });
1637
+ }
1638
+ /**
1639
+ * Clear all profiles
1640
+ */
1641
+ clearProfiles() {
1642
+ this._profiles.clear();
1643
+ }
1644
+ /**
1645
+ * Export profiles for analysis
1646
+ */
1647
+ exportProfiles() {
1648
+ return Array.from(this._profiles.values());
1649
+ }
1650
+ /**
1651
+ * Generate a profile ID
1652
+ */
1653
+ _generateProfileId(expression) {
1654
+ const exprStr = String(expression);
1655
+ const timestamp = Date.now();
1656
+ return `profile_${timestamp}_${exprStr.slice(0, 20).replace(/\W/g, '_')}`;
1657
+ }
1658
+ /**
1659
+ * Calculate expression complexity score
1660
+ */
1661
+ _calculateComplexity(expression) {
1662
+ if (typeof expression === 'string') {
1663
+ // String complexity based on length and special characters
1664
+ let complexity = Math.min(expression.length / 10, 10); // Max 10 for length
1665
+ // Add complexity for special patterns
1666
+ if (expression.includes('?.'))
1667
+ complexity += 2; // Optional chaining
1668
+ if (expression.includes('??'))
1669
+ complexity += 2; // Nullish coalescing
1670
+ if (expression.includes('${'))
1671
+ complexity += 3; // Template literals
1672
+ if (expression.match(/\w+\.\w+/))
1673
+ complexity += 1; // Property access
1674
+ return complexity;
1675
+ }
1676
+ if (Array.isArray(expression)) {
1677
+ return expression.reduce((sum, item) => sum + this._calculateComplexity(item), 1);
1678
+ }
1679
+ if (expression && typeof expression === 'object') {
1680
+ let complexity = 1;
1681
+ for (const value of Object.values(expression)) {
1682
+ complexity += this._calculateComplexity(value);
1683
+ }
1684
+ return complexity;
1685
+ }
1686
+ return 1; // Base complexity for primitives
1687
+ }
1688
+ /**
1689
+ * Estimate memory usage
1690
+ */
1691
+ _estimateMemoryUsage(expression, result) {
1692
+ let size = 0;
1693
+ // Expression size
1694
+ if (typeof expression === 'string') {
1695
+ size += expression.length * 2; // UTF-16
1696
+ }
1697
+ else {
1698
+ size += JSON.stringify(expression).length * 2;
1699
+ }
1700
+ // Result size
1701
+ if (result.celExpression) {
1702
+ size += result.celExpression.expression.length * 2;
1703
+ }
1704
+ // Dependencies size
1705
+ size += result.dependencies.length * 100; // Estimated size per dependency
1706
+ // Source map size
1707
+ size += result.sourceMap.length * 200; // Estimated size per source map entry
1708
+ return size;
1709
+ }
1710
+ }
1711
+ /**
1712
+ * Optimized KubernetesRef detector with caching and fast paths
1713
+ */
1714
+ export class OptimizedKubernetesRefDetector {
1715
+ _cache = new Map();
1716
+ _refCache = new Map();
1717
+ _cacheHits = 0;
1718
+ _cacheMisses = 0;
1719
+ _maxCacheSize = 1000;
1720
+ /**
1721
+ * Fast detection of KubernetesRef objects with caching
1722
+ */
1723
+ containsKubernetesRefs(value, useCache = true) {
1724
+ if (!useCache) {
1725
+ return this._containsKubernetesRefsUncached(value);
1726
+ }
1727
+ const cacheKey = this._generateCacheKey(value);
1728
+ // Check cache first
1729
+ const cached = this._cache.get(cacheKey);
1730
+ if (cached !== undefined) {
1731
+ this._cacheHits++;
1732
+ return cached;
1733
+ }
1734
+ // Compute result
1735
+ this._cacheMisses++;
1736
+ const result = this._containsKubernetesRefsUncached(value);
1737
+ // Cache result if cache isn't full
1738
+ if (this._cache.size < this._maxCacheSize) {
1739
+ this._cache.set(cacheKey, result);
1740
+ }
1741
+ return result;
1742
+ }
1743
+ /**
1744
+ * Extract KubernetesRef objects with optimized traversal
1745
+ */
1746
+ extractKubernetesRefs(value, useCache = true) {
1747
+ if (!useCache) {
1748
+ return this._extractKubernetesRefsUncached(value);
1749
+ }
1750
+ const cacheKey = this._generateCacheKey(value);
1751
+ // Check cache first
1752
+ const cached = this._refCache.get(cacheKey);
1753
+ if (cached !== undefined) {
1754
+ this._cacheHits++;
1755
+ return [...cached]; // Return copy to prevent mutation
1756
+ }
1757
+ // Compute result
1758
+ this._cacheMisses++;
1759
+ const result = this._extractKubernetesRefsUncached(value);
1760
+ // Cache result if cache isn't full
1761
+ if (this._refCache.size < this._maxCacheSize) {
1762
+ this._refCache.set(cacheKey, [...result]); // Store copy
1763
+ }
1764
+ return result;
1765
+ }
1766
+ /**
1767
+ * Optimized traversal that stops early when possible
1768
+ */
1769
+ traverseOptimized(value, callback, path = [], maxDepth = 10) {
1770
+ if (maxDepth <= 0) {
1771
+ return false;
1772
+ }
1773
+ // Call callback - if it returns true, stop traversal
1774
+ const shouldStop = callback(value, path);
1775
+ if (shouldStop === true) {
1776
+ return true;
1777
+ }
1778
+ // Fast path for primitives
1779
+ if (this._isPrimitive(value)) {
1780
+ return false;
1781
+ }
1782
+ // Handle arrays with early termination
1783
+ if (Array.isArray(value)) {
1784
+ for (let i = 0; i < value.length; i++) {
1785
+ const stopped = this.traverseOptimized(value[i], callback, [...path, i.toString()], maxDepth - 1);
1786
+ if (stopped) {
1787
+ return true;
1788
+ }
1789
+ }
1790
+ return false;
1791
+ }
1792
+ // Handle objects with early termination
1793
+ if (value && typeof value === 'object') {
1794
+ for (const [key, val] of Object.entries(value)) {
1795
+ const stopped = this.traverseOptimized(val, callback, [...path, key], maxDepth - 1);
1796
+ if (stopped) {
1797
+ return true;
1798
+ }
1799
+ }
1800
+ return false;
1801
+ }
1802
+ return false;
1803
+ }
1804
+ /**
1805
+ * Get cache statistics
1806
+ */
1807
+ getCacheStats() {
1808
+ const total = this._cacheHits + this._cacheMisses;
1809
+ return {
1810
+ hits: this._cacheHits,
1811
+ misses: this._cacheMisses,
1812
+ hitRatio: total > 0 ? this._cacheHits / total : 0,
1813
+ size: this._cache.size + this._refCache.size
1814
+ };
1815
+ }
1816
+ /**
1817
+ * Clear caches
1818
+ */
1819
+ clearCache() {
1820
+ this._cache.clear();
1821
+ this._refCache.clear();
1822
+ this._cacheHits = 0;
1823
+ this._cacheMisses = 0;
1824
+ }
1825
+ /**
1826
+ * Set maximum cache size
1827
+ */
1828
+ setMaxCacheSize(size) {
1829
+ this._maxCacheSize = size;
1830
+ // Trim caches if they're too large
1831
+ if (this._cache.size > size) {
1832
+ const entries = Array.from(this._cache.entries());
1833
+ this._cache.clear();
1834
+ // Keep the most recent entries
1835
+ for (const [key, value] of entries.slice(-size)) {
1836
+ this._cache.set(key, value);
1837
+ }
1838
+ }
1839
+ if (this._refCache.size > size) {
1840
+ const entries = Array.from(this._refCache.entries());
1841
+ this._refCache.clear();
1842
+ // Keep the most recent entries
1843
+ for (const [key, value] of entries.slice(-size)) {
1844
+ this._refCache.set(key, value);
1845
+ }
1846
+ }
1847
+ }
1848
+ /**
1849
+ * Uncached KubernetesRef detection with optimizations
1850
+ */
1851
+ _containsKubernetesRefsUncached(value) {
1852
+ // Fast path for primitives
1853
+ if (this._isPrimitive(value)) {
1854
+ return false;
1855
+ }
1856
+ // Check if this is a KubernetesRef
1857
+ if (this.isKubernetesRef(value)) {
1858
+ return true;
1859
+ }
1860
+ // Use optimized traversal with early termination
1861
+ return this.traverseOptimized(value, (val) => {
1862
+ if (this.isKubernetesRef(val)) {
1863
+ return true; // Stop traversal, we found one
1864
+ }
1865
+ return false; // Continue traversal
1866
+ });
1867
+ }
1868
+ /**
1869
+ * Uncached KubernetesRef extraction with optimizations
1870
+ */
1871
+ _extractKubernetesRefsUncached(value) {
1872
+ const refs = [];
1873
+ this.traverseOptimized(value, (val) => {
1874
+ if (this.isKubernetesRef(val)) {
1875
+ refs.push(val);
1876
+ }
1877
+ return false; // Continue traversal to find all refs
1878
+ });
1879
+ return refs;
1880
+ }
1881
+ /**
1882
+ * Generate cache key for a value
1883
+ */
1884
+ _generateCacheKey(value) {
1885
+ if (typeof value === 'string') {
1886
+ return `str:${value.length}:${value.slice(0, 50)}`;
1887
+ }
1888
+ if (typeof value === 'number' || typeof value === 'boolean') {
1889
+ return `prim:${String(value)}`;
1890
+ }
1891
+ if (value === null || value === undefined) {
1892
+ return `null:${String(value)}`;
1893
+ }
1894
+ if (typeof value === 'function') {
1895
+ return `func:${value.name || 'anonymous'}:${value.toString().slice(0, 50)}`;
1896
+ }
1897
+ // For objects and arrays, use a hash of the JSON representation
1898
+ try {
1899
+ const json = JSON.stringify(value);
1900
+ return `obj:${json.length}:${this._simpleHash(json)}`;
1901
+ }
1902
+ catch {
1903
+ return `obj:unstringifiable:${Date.now()}`;
1904
+ }
1905
+ }
1906
+ /**
1907
+ * Simple hash function for cache keys
1908
+ */
1909
+ _simpleHash(str) {
1910
+ let hash = 0;
1911
+ for (let i = 0; i < str.length; i++) {
1912
+ const char = str.charCodeAt(i);
1913
+ hash = ((hash << 5) - hash) + char;
1914
+ hash = hash & hash; // Convert to 32-bit integer
1915
+ }
1916
+ return Math.abs(hash).toString(36);
1917
+ }
1918
+ /**
1919
+ * Fast primitive check
1920
+ */
1921
+ _isPrimitive(value) {
1922
+ return value === null ||
1923
+ value === undefined ||
1924
+ typeof value === 'string' ||
1925
+ typeof value === 'number' ||
1926
+ typeof value === 'boolean' ||
1927
+ typeof value === 'function';
1928
+ }
1929
+ /**
1930
+ * Fast KubernetesRef check
1931
+ */
1932
+ isKubernetesRef(value) {
1933
+ return ((typeof value === 'object' || typeof value === 'function') &&
1934
+ value !== null &&
1935
+ KUBERNETES_REF_BRAND in value);
1936
+ }
1937
+ }
1938
+ /**
1939
+ * Optimized expression traverser for complex nested structures
1940
+ */
1941
+ export class OptimizedExpressionTraverser {
1942
+ _detector;
1943
+ _visitedObjects = new WeakSet();
1944
+ constructor(detector) {
1945
+ this._detector = detector || new OptimizedKubernetesRefDetector();
1946
+ }
1947
+ /**
1948
+ * Traverse expression tree with cycle detection and optimization
1949
+ */
1950
+ traverse(expression, visitor, options = {}) {
1951
+ const { maxDepth = 20, detectCycles = true, earlyTermination = true } = options;
1952
+ const result = {
1953
+ visited: 0,
1954
+ skipped: 0,
1955
+ kubernetesRefs: [],
1956
+ maxDepthReached: false,
1957
+ cyclesDetected: 0,
1958
+ duplicatesSkipped: 0
1959
+ };
1960
+ // WeakSet doesn't have a clear method, create a new instance
1961
+ this._visitedObjects = new WeakSet();
1962
+ const traverse = (value, path, depth) => {
1963
+ // Check depth limit
1964
+ if (depth > maxDepth) {
1965
+ result.maxDepthReached = true;
1966
+ return false;
1967
+ }
1968
+ // Cycle detection
1969
+ if (detectCycles && value && typeof value === 'object') {
1970
+ if (this._visitedObjects.has(value)) {
1971
+ result.cyclesDetected++;
1972
+ result.skipped++;
1973
+ return false;
1974
+ }
1975
+ this._visitedObjects.add(value);
1976
+ }
1977
+ result.visited++;
1978
+ // Check if this is a KubernetesRef
1979
+ if (this._detector.isKubernetesRef(value)) {
1980
+ result.kubernetesRefs.push(value);
1981
+ }
1982
+ // Call visitor
1983
+ const context = {
1984
+ depth,
1985
+ isKubernetesRef: this._detector.isKubernetesRef(value),
1986
+ hasKubernetesRefs: this._detector.containsKubernetesRefs(value, false),
1987
+ path: [...path]
1988
+ };
1989
+ const action = visitor(value, path, context);
1990
+ // Handle visitor actions
1991
+ switch (action) {
1992
+ case TraversalAction.STOP:
1993
+ return true; // Stop entire traversal
1994
+ case TraversalAction.SKIP:
1995
+ result.skipped++;
1996
+ return false; // Skip this subtree
1997
+ default:
1998
+ break; // Continue normal traversal
1999
+ }
2000
+ // Traverse children
2001
+ if (Array.isArray(value)) {
2002
+ for (let i = 0; i < value.length; i++) {
2003
+ const stopped = traverse(value[i], [...path, i.toString()], depth + 1);
2004
+ if (stopped && earlyTermination) {
2005
+ return true;
2006
+ }
2007
+ }
2008
+ }
2009
+ else if (value && typeof value === 'object') {
2010
+ for (const [key, val] of Object.entries(value)) {
2011
+ const stopped = traverse(val, [...path, key], depth + 1);
2012
+ if (stopped && earlyTermination) {
2013
+ return true;
2014
+ }
2015
+ }
2016
+ }
2017
+ return false;
2018
+ };
2019
+ traverse(expression, [], 0);
2020
+ return result;
2021
+ }
2022
+ /**
2023
+ * Find all KubernetesRef objects efficiently
2024
+ */
2025
+ findAllKubernetesRefs(expression, maxDepth = 20) {
2026
+ const refs = [];
2027
+ this.traverse(expression, (value, _path, context) => {
2028
+ if (context.isKubernetesRef) {
2029
+ refs.push(value);
2030
+ }
2031
+ return TraversalAction.CONTINUE;
2032
+ }, { maxDepth, detectCycles: true, earlyTermination: false });
2033
+ return refs;
2034
+ }
2035
+ /**
2036
+ * Check if expression contains KubernetesRefs efficiently
2037
+ */
2038
+ hasKubernetesRefs(expression, maxDepth = 20) {
2039
+ let found = false;
2040
+ this.traverse(expression, (_value, _path, context) => {
2041
+ if (context.isKubernetesRef) {
2042
+ found = true;
2043
+ return TraversalAction.STOP; // Early termination
2044
+ }
2045
+ return TraversalAction.CONTINUE;
2046
+ }, { maxDepth, detectCycles: true, earlyTermination: true });
2047
+ return found;
2048
+ }
2049
+ }
2050
+ /**
2051
+ * Traversal action returned by visitor functions
2052
+ */
2053
+ export var TraversalAction;
2054
+ (function (TraversalAction) {
2055
+ /** Continue normal traversal */
2056
+ TraversalAction["CONTINUE"] = "continue";
2057
+ /** Skip this subtree */
2058
+ TraversalAction["SKIP"] = "skip";
2059
+ /** Stop entire traversal */
2060
+ TraversalAction["STOP"] = "stop";
2061
+ })(TraversalAction || (TraversalAction = {}));
2062
+ /**
2063
+ * Global optimized KubernetesRef detector
2064
+ */
2065
+ export const globalOptimizedDetector = new OptimizedKubernetesRefDetector();
2066
+ /**
2067
+ * Expression complexity analyzer with warnings for magic proxy usage
2068
+ */
2069
+ export class ExpressionComplexityAnalyzer {
2070
+ _detector;
2071
+ _traverser;
2072
+ _thresholds;
2073
+ constructor(detector, traverser, thresholds) {
2074
+ this._detector = detector || new OptimizedKubernetesRefDetector();
2075
+ this._traverser = traverser || new OptimizedExpressionTraverser();
2076
+ this._thresholds = {
2077
+ low: 5,
2078
+ medium: 15,
2079
+ high: 30,
2080
+ extreme: 50,
2081
+ ...thresholds
2082
+ };
2083
+ }
2084
+ /**
2085
+ * Analyze expression complexity and generate warnings
2086
+ */
2087
+ analyzeComplexity(expression) {
2088
+ const startTime = performance.now();
2089
+ // Calculate various complexity metrics
2090
+ const syntacticComplexity = this._calculateSyntacticComplexity(expression);
2091
+ const structuralComplexity = this._calculateStructuralComplexity(expression);
2092
+ const magicProxyComplexity = this._calculateMagicProxyComplexity(expression);
2093
+ const cyclomaticComplexity = this._calculateCyclomaticComplexity(expression);
2094
+ // Overall complexity score
2095
+ const overallComplexity = Math.max(syntacticComplexity, structuralComplexity, magicProxyComplexity, cyclomaticComplexity);
2096
+ // Determine complexity level
2097
+ const level = this._determineComplexityLevel(overallComplexity);
2098
+ // Generate warnings
2099
+ const warnings = this._generateWarnings(expression, {
2100
+ syntacticComplexity,
2101
+ structuralComplexity,
2102
+ magicProxyComplexity,
2103
+ cyclomaticComplexity,
2104
+ overallComplexity,
2105
+ level
2106
+ });
2107
+ // Generate recommendations
2108
+ const recommendations = this._generateRecommendations(expression, {
2109
+ syntacticComplexity,
2110
+ structuralComplexity,
2111
+ magicProxyComplexity,
2112
+ cyclomaticComplexity,
2113
+ overallComplexity,
2114
+ level
2115
+ });
2116
+ const endTime = performance.now();
2117
+ return {
2118
+ expression: String(expression),
2119
+ syntacticComplexity,
2120
+ structuralComplexity,
2121
+ magicProxyComplexity,
2122
+ cyclomaticComplexity,
2123
+ overallComplexity,
2124
+ level,
2125
+ warnings,
2126
+ recommendations,
2127
+ analysisTime: endTime - startTime,
2128
+ kubernetesRefCount: this._detector.extractKubernetesRefs(expression).length,
2129
+ estimatedConversionTime: this._estimateConversionTime(overallComplexity),
2130
+ memoryImpact: this._estimateMemoryImpact(expression)
2131
+ };
2132
+ }
2133
+ /**
2134
+ * Batch analyze multiple expressions
2135
+ */
2136
+ batchAnalyzeComplexity(expressions) {
2137
+ const results = new Map();
2138
+ for (const { key, expression } of expressions) {
2139
+ results.set(key, this.analyzeComplexity(expression));
2140
+ }
2141
+ return results;
2142
+ }
2143
+ /**
2144
+ * Get complexity statistics for a set of expressions
2145
+ */
2146
+ getComplexityStats(expressions) {
2147
+ const results = this.batchAnalyzeComplexity(expressions);
2148
+ const analyses = Array.from(results.values());
2149
+ if (analyses.length === 0) {
2150
+ return {
2151
+ totalExpressions: 0,
2152
+ averageComplexity: 0,
2153
+ maxComplexity: 0,
2154
+ minComplexity: 0,
2155
+ complexityDistribution: { low: 0, medium: 0, high: 0, extreme: 0 },
2156
+ totalWarnings: 0,
2157
+ averageWarnings: 0,
2158
+ mostComplexExpression: null,
2159
+ totalKubernetesRefs: 0,
2160
+ averageKubernetesRefs: 0
2161
+ };
2162
+ }
2163
+ const complexities = analyses.map(a => a.overallComplexity);
2164
+ const totalComplexity = complexities.reduce((sum, c) => sum + c, 0);
2165
+ const totalWarnings = analyses.reduce((sum, a) => sum + a.warnings.length, 0);
2166
+ const totalKubernetesRefs = analyses.reduce((sum, a) => sum + a.kubernetesRefCount, 0);
2167
+ const distribution = { low: 0, medium: 0, high: 0, extreme: 0 };
2168
+ for (const analysis of analyses) {
2169
+ distribution[analysis.level]++;
2170
+ }
2171
+ const mostComplex = analyses.reduce((max, current) => current.overallComplexity > max.overallComplexity ? current : max);
2172
+ return {
2173
+ totalExpressions: analyses.length,
2174
+ averageComplexity: totalComplexity / analyses.length,
2175
+ maxComplexity: Math.max(...complexities),
2176
+ minComplexity: Math.min(...complexities),
2177
+ complexityDistribution: distribution,
2178
+ totalWarnings,
2179
+ averageWarnings: totalWarnings / analyses.length,
2180
+ mostComplexExpression: mostComplex,
2181
+ totalKubernetesRefs,
2182
+ averageKubernetesRefs: totalKubernetesRefs / analyses.length
2183
+ };
2184
+ }
2185
+ /**
2186
+ * Calculate syntactic complexity (based on syntax patterns)
2187
+ */
2188
+ _calculateSyntacticComplexity(expression) {
2189
+ if (typeof expression !== 'string') {
2190
+ return 1;
2191
+ }
2192
+ let complexity = Math.min(expression.length / 50, 10); // Base complexity from length
2193
+ // Add complexity for various syntax patterns
2194
+ const patterns = [
2195
+ { pattern: /\?\./g, weight: 2, name: 'optional chaining' },
2196
+ { pattern: /\?\?/g, weight: 2, name: 'nullish coalescing' },
2197
+ { pattern: /\$\{[^}]+\}/g, weight: 3, name: 'template literals' },
2198
+ { pattern: /\w+\.\w+/g, weight: 1, name: 'property access' },
2199
+ { pattern: /\[[^\]]+\]/g, weight: 1.5, name: 'array access' },
2200
+ { pattern: /\?\s*:/g, weight: 2, name: 'ternary operator' },
2201
+ { pattern: /&&|\|\|/g, weight: 1.5, name: 'logical operators' },
2202
+ { pattern: /===|!==|==|!=/g, weight: 1, name: 'comparison operators' },
2203
+ { pattern: /\w+\([^)]*\)/g, weight: 2.5, name: 'function calls' },
2204
+ { pattern: /\bfind\b|\bfilter\b|\bmap\b|\breduce\b/g, weight: 3, name: 'array methods' }
2205
+ ];
2206
+ for (const { pattern, weight } of patterns) {
2207
+ const matches = expression.match(pattern);
2208
+ if (matches) {
2209
+ complexity += matches.length * weight;
2210
+ }
2211
+ }
2212
+ return Math.min(complexity, 50); // Cap at 50
2213
+ }
2214
+ /**
2215
+ * Calculate structural complexity (based on nesting and object structure)
2216
+ */
2217
+ _calculateStructuralComplexity(expression) {
2218
+ let complexity = 1;
2219
+ let maxDepth = 0;
2220
+ let nodeCount = 0;
2221
+ const traversalResult = this._traverser.traverse(expression, (value, _path, context) => {
2222
+ nodeCount++;
2223
+ maxDepth = Math.max(maxDepth, context.depth);
2224
+ // Add complexity for different node types
2225
+ if (Array.isArray(value)) {
2226
+ complexity += value.length * 0.5;
2227
+ }
2228
+ else if (value && typeof value === 'object') {
2229
+ complexity += Object.keys(value).length * 0.3;
2230
+ }
2231
+ return TraversalAction.CONTINUE;
2232
+ }, { maxDepth: 20 });
2233
+ // Factor in depth and node count
2234
+ complexity += maxDepth * 2;
2235
+ complexity += nodeCount * 0.1;
2236
+ // Penalize cycles
2237
+ complexity += traversalResult.cyclesDetected * 5;
2238
+ return Math.min(complexity, 50);
2239
+ }
2240
+ /**
2241
+ * Calculate magic proxy complexity (based on KubernetesRef usage)
2242
+ */
2243
+ _calculateMagicProxyComplexity(expression) {
2244
+ const refs = this._detector.extractKubernetesRefs(expression);
2245
+ let complexity = refs.length * 2; // Base complexity per ref
2246
+ // Analyze ref patterns
2247
+ const resourceIds = new Set(refs.map(ref => ref.resourceId));
2248
+ const fieldPaths = refs.map(ref => ref.fieldPath);
2249
+ // Add complexity for multiple resources
2250
+ complexity += resourceIds.size * 1.5;
2251
+ // Add complexity for deep field paths
2252
+ for (const fieldPath of fieldPaths) {
2253
+ const depth = fieldPath.split('.').length;
2254
+ complexity += Math.max(0, depth - 2) * 0.5; // Penalize deep paths
2255
+ }
2256
+ // Add complexity for optional chaining in field paths
2257
+ const optionalPaths = fieldPaths.filter(path => path.includes('?'));
2258
+ complexity += optionalPaths.length * 1.5;
2259
+ return Math.min(complexity, 50);
2260
+ }
2261
+ /**
2262
+ * Calculate cyclomatic complexity (based on control flow)
2263
+ */
2264
+ _calculateCyclomaticComplexity(expression) {
2265
+ if (typeof expression !== 'string') {
2266
+ return 1;
2267
+ }
2268
+ let complexity = 1; // Base complexity
2269
+ // Count decision points
2270
+ const decisionPatterns = [
2271
+ /\?\s*:/g, // Ternary operators
2272
+ /&&/g, // Logical AND
2273
+ /\|\|/g, // Logical OR
2274
+ /\bif\b/g, // If statements (in case of function expressions)
2275
+ /\belse\b/g, // Else statements
2276
+ /\bswitch\b/g, // Switch statements
2277
+ /\bcase\b/g, // Case statements
2278
+ /\bwhile\b/g, // While loops
2279
+ /\bfor\b/g, // For loops
2280
+ /\btry\b/g, // Try blocks
2281
+ /\bcatch\b/g // Catch blocks
2282
+ ];
2283
+ for (const pattern of decisionPatterns) {
2284
+ const matches = expression.match(pattern);
2285
+ if (matches) {
2286
+ complexity += matches.length;
2287
+ }
2288
+ }
2289
+ return Math.min(complexity, 20);
2290
+ }
2291
+ /**
2292
+ * Determine complexity level
2293
+ */
2294
+ _determineComplexityLevel(complexity) {
2295
+ if (complexity <= this._thresholds.low)
2296
+ return 'low';
2297
+ if (complexity <= this._thresholds.medium)
2298
+ return 'medium';
2299
+ if (complexity <= this._thresholds.high)
2300
+ return 'high';
2301
+ return 'extreme';
2302
+ }
2303
+ /**
2304
+ * Generate warnings based on complexity analysis
2305
+ */
2306
+ _generateWarnings(_expression, metrics) {
2307
+ const warnings = [];
2308
+ // Overall complexity warnings
2309
+ if (metrics.overallComplexity > this._thresholds.high) {
2310
+ warnings.push({
2311
+ type: 'high-complexity',
2312
+ severity: metrics.overallComplexity > this._thresholds.extreme ? 'error' : 'warning',
2313
+ message: `Expression has very high complexity (${metrics.overallComplexity.toFixed(1)}). Consider breaking it down into smaller parts.`,
2314
+ metric: 'overallComplexity',
2315
+ value: metrics.overallComplexity,
2316
+ threshold: this._thresholds.high
2317
+ });
2318
+ }
2319
+ // Magic proxy specific warnings
2320
+ if (metrics.magicProxyComplexity > 10) {
2321
+ warnings.push({
2322
+ type: 'magic-proxy-complexity',
2323
+ severity: 'warning',
2324
+ message: `High magic proxy usage complexity (${metrics.magicProxyComplexity.toFixed(1)}). Consider reducing KubernetesRef dependencies.`,
2325
+ metric: 'magicProxyComplexity',
2326
+ value: metrics.magicProxyComplexity,
2327
+ threshold: 10
2328
+ });
2329
+ }
2330
+ // Syntactic complexity warnings
2331
+ if (metrics.syntacticComplexity > 20) {
2332
+ warnings.push({
2333
+ type: 'syntactic-complexity',
2334
+ severity: 'info',
2335
+ message: `Complex syntax patterns detected (${metrics.syntacticComplexity.toFixed(1)}). Consider simplifying the expression.`,
2336
+ metric: 'syntacticComplexity',
2337
+ value: metrics.syntacticComplexity,
2338
+ threshold: 20
2339
+ });
2340
+ }
2341
+ // Structural complexity warnings
2342
+ if (metrics.structuralComplexity > 15) {
2343
+ warnings.push({
2344
+ type: 'structural-complexity',
2345
+ severity: 'info',
2346
+ message: `Deep or complex object structure (${metrics.structuralComplexity.toFixed(1)}). Consider flattening the structure.`,
2347
+ metric: 'structuralComplexity',
2348
+ value: metrics.structuralComplexity,
2349
+ threshold: 15
2350
+ });
2351
+ }
2352
+ return warnings;
2353
+ }
2354
+ /**
2355
+ * Generate recommendations for reducing complexity
2356
+ */
2357
+ _generateRecommendations(_expression, metrics) {
2358
+ const recommendations = [];
2359
+ if (metrics.overallComplexity > this._thresholds.high) {
2360
+ recommendations.push('Break down the expression into smaller, more manageable parts');
2361
+ recommendations.push('Consider extracting complex logic into separate functions');
2362
+ }
2363
+ if (metrics.magicProxyComplexity > 10) {
2364
+ recommendations.push('Reduce the number of KubernetesRef dependencies');
2365
+ recommendations.push('Consider caching frequently accessed resource fields');
2366
+ recommendations.push('Use direct references instead of deep field path access where possible');
2367
+ }
2368
+ if (metrics.syntacticComplexity > 20) {
2369
+ recommendations.push('Simplify complex syntax patterns like nested ternary operators');
2370
+ recommendations.push('Replace complex template literals with string concatenation');
2371
+ recommendations.push('Use intermediate variables for complex property access chains');
2372
+ }
2373
+ if (metrics.cyclomaticComplexity > 10) {
2374
+ recommendations.push('Reduce the number of conditional branches');
2375
+ recommendations.push('Consider using lookup tables instead of complex conditional logic');
2376
+ recommendations.push('Extract decision logic into separate functions');
2377
+ }
2378
+ return recommendations;
2379
+ }
2380
+ /**
2381
+ * Estimate conversion time based on complexity
2382
+ */
2383
+ _estimateConversionTime(complexity) {
2384
+ // Base time + complexity factor
2385
+ return 1 + (complexity * 0.5);
2386
+ }
2387
+ /**
2388
+ * Estimate memory impact
2389
+ */
2390
+ _estimateMemoryImpact(expression) {
2391
+ const size = JSON.stringify(expression).length;
2392
+ const refs = this._detector.extractKubernetesRefs(expression);
2393
+ const estimatedSize = size * 2 + refs.length * 100; // Rough estimation
2394
+ if (estimatedSize < 1000)
2395
+ return 'low';
2396
+ if (estimatedSize < 5000)
2397
+ return 'medium';
2398
+ if (estimatedSize < 20000)
2399
+ return 'high';
2400
+ return 'extreme';
2401
+ }
2402
+ }
2403
+ /**
2404
+ * Global expression complexity analyzer
2405
+ */
2406
+ export const globalComplexityAnalyzer = new ExpressionComplexityAnalyzer();
2407
+ /**
2408
+ * Global optimized expression traverser
2409
+ */
2410
+ export const globalOptimizedTraverser = new OptimizedExpressionTraverser();
2411
+ /**
2412
+ * Global expression analysis profiler
2413
+ */
2414
+ export const globalExpressionProfiler = new ExpressionAnalysisProfiler();
2415
+ /**
2416
+ * Global parallel expression analyzer
2417
+ */
2418
+ export const globalParallelAnalyzer = new ParallelExpressionAnalyzer();
2419
+ /**
2420
+ * Global magic proxy integration instance
2421
+ */
2422
+ export const globalMagicProxyIntegration = new MagicProxyLazyIntegration();
2423
+ /**
2424
+ * Global expression tree analyzer instance
2425
+ */
2426
+ export const globalTreeAnalyzer = new ExpressionTreeAnalyzer();
2427
+ /**
2428
+ * Utility to check if a value should be wrapped in a lazy expression
2429
+ */
2430
+ export function shouldUseLazyAnalysis(expression) {
2431
+ // Use lazy analysis for complex expressions or those that might contain KubernetesRef objects
2432
+ if (typeof expression === 'function') {
2433
+ return true; // Functions always need analysis
2434
+ }
2435
+ if (typeof expression === 'string' && expression.length > 50) {
2436
+ return true; // Long strings might be complex expressions
2437
+ }
2438
+ if (Array.isArray(expression) || (expression && typeof expression === 'object')) {
2439
+ return true; // Complex structures might contain KubernetesRef objects
2440
+ }
2441
+ return containsKubernetesRefs(expression);
2442
+ }
2443
+ //# sourceMappingURL=lazy-analysis.js.map