typekro 0.2.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) 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 +0 -1
  13. package/dist/core/deployment/engine.d.ts.map +1 -1
  14. package/dist/core/deployment/engine.js +0 -1
  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/expressions/analyzer.d.ts +584 -0
  21. package/dist/core/expressions/analyzer.d.ts.map +1 -0
  22. package/dist/core/expressions/analyzer.js +2956 -0
  23. package/dist/core/expressions/analyzer.js.map +1 -0
  24. package/dist/core/expressions/cache.d.ts +136 -0
  25. package/dist/core/expressions/cache.d.ts.map +1 -0
  26. package/dist/core/expressions/cache.js +347 -0
  27. package/dist/core/expressions/cache.js.map +1 -0
  28. package/dist/core/expressions/cel-conversion-engine.d.ts +126 -0
  29. package/dist/core/expressions/cel-conversion-engine.d.ts.map +1 -0
  30. package/dist/core/expressions/cel-conversion-engine.js +293 -0
  31. package/dist/core/expressions/cel-conversion-engine.js.map +1 -0
  32. package/dist/core/expressions/compile-time-validation.d.ts +270 -0
  33. package/dist/core/expressions/compile-time-validation.d.ts.map +1 -0
  34. package/dist/core/expressions/compile-time-validation.js +506 -0
  35. package/dist/core/expressions/compile-time-validation.js.map +1 -0
  36. package/dist/core/expressions/composition-integration.d.ts +315 -0
  37. package/dist/core/expressions/composition-integration.d.ts.map +1 -0
  38. package/dist/core/expressions/composition-integration.js +936 -0
  39. package/dist/core/expressions/composition-integration.js.map +1 -0
  40. package/dist/core/expressions/conditional-expression-processor.d.ts +154 -0
  41. package/dist/core/expressions/conditional-expression-processor.d.ts.map +1 -0
  42. package/dist/core/expressions/conditional-expression-processor.js +479 -0
  43. package/dist/core/expressions/conditional-expression-processor.js.map +1 -0
  44. package/dist/core/expressions/conditional-integration.d.ts +133 -0
  45. package/dist/core/expressions/conditional-integration.d.ts.map +1 -0
  46. package/dist/core/expressions/conditional-integration.js +293 -0
  47. package/dist/core/expressions/conditional-integration.js.map +1 -0
  48. package/dist/core/expressions/conditional-validation.d.ts +181 -0
  49. package/dist/core/expressions/conditional-validation.d.ts.map +1 -0
  50. package/dist/core/expressions/conditional-validation.js +460 -0
  51. package/dist/core/expressions/conditional-validation.js.map +1 -0
  52. package/dist/core/expressions/context-aware-generator.d.ts +127 -0
  53. package/dist/core/expressions/context-aware-generator.d.ts.map +1 -0
  54. package/dist/core/expressions/context-aware-generator.js +500 -0
  55. package/dist/core/expressions/context-aware-generator.js.map +1 -0
  56. package/dist/core/expressions/context-detector.d.ts +148 -0
  57. package/dist/core/expressions/context-detector.d.ts.map +1 -0
  58. package/dist/core/expressions/context-detector.js +546 -0
  59. package/dist/core/expressions/context-detector.js.map +1 -0
  60. package/dist/core/expressions/context-switcher.d.ts +185 -0
  61. package/dist/core/expressions/context-switcher.d.ts.map +1 -0
  62. package/dist/core/expressions/context-switcher.js +515 -0
  63. package/dist/core/expressions/context-switcher.js.map +1 -0
  64. package/dist/core/expressions/context-validator.d.ts +176 -0
  65. package/dist/core/expressions/context-validator.d.ts.map +1 -0
  66. package/dist/core/expressions/context-validator.js +452 -0
  67. package/dist/core/expressions/context-validator.js.map +1 -0
  68. package/dist/core/expressions/custom-context-manager.d.ts +194 -0
  69. package/dist/core/expressions/custom-context-manager.d.ts.map +1 -0
  70. package/dist/core/expressions/custom-context-manager.js +390 -0
  71. package/dist/core/expressions/custom-context-manager.js.map +1 -0
  72. package/dist/core/expressions/expression-proxy.d.ts +80 -0
  73. package/dist/core/expressions/expression-proxy.d.ts.map +1 -0
  74. package/dist/core/expressions/expression-proxy.js +227 -0
  75. package/dist/core/expressions/expression-proxy.js.map +1 -0
  76. package/dist/core/expressions/factory-integration.d.ts +132 -0
  77. package/dist/core/expressions/factory-integration.d.ts.map +1 -0
  78. package/dist/core/expressions/factory-integration.js +327 -0
  79. package/dist/core/expressions/factory-integration.js.map +1 -0
  80. package/dist/core/expressions/factory-pattern-handler.d.ts +88 -0
  81. package/dist/core/expressions/factory-pattern-handler.d.ts.map +1 -0
  82. package/dist/core/expressions/factory-pattern-handler.js +336 -0
  83. package/dist/core/expressions/factory-pattern-handler.js.map +1 -0
  84. package/dist/core/expressions/field-hydration-processor.d.ts +188 -0
  85. package/dist/core/expressions/field-hydration-processor.d.ts.map +1 -0
  86. package/dist/core/expressions/field-hydration-processor.js +562 -0
  87. package/dist/core/expressions/field-hydration-processor.js.map +1 -0
  88. package/dist/core/expressions/imperative-analyzer.d.ts +21 -0
  89. package/dist/core/expressions/imperative-analyzer.d.ts.map +1 -0
  90. package/dist/core/expressions/imperative-analyzer.js +343 -0
  91. package/dist/core/expressions/imperative-analyzer.js.map +1 -0
  92. package/dist/core/expressions/index.d.ts +54 -0
  93. package/dist/core/expressions/index.d.ts.map +1 -0
  94. package/dist/core/expressions/index.js +50 -0
  95. package/dist/core/expressions/index.js.map +1 -0
  96. package/dist/core/expressions/lazy-analysis.d.ts +1128 -0
  97. package/dist/core/expressions/lazy-analysis.d.ts.map +1 -0
  98. package/dist/core/expressions/lazy-analysis.js +2443 -0
  99. package/dist/core/expressions/lazy-analysis.js.map +1 -0
  100. package/dist/core/expressions/magic-assignable-analyzer.d.ts +123 -0
  101. package/dist/core/expressions/magic-assignable-analyzer.d.ts.map +1 -0
  102. package/dist/core/expressions/magic-assignable-analyzer.js +352 -0
  103. package/dist/core/expressions/magic-assignable-analyzer.js.map +1 -0
  104. package/dist/core/expressions/magic-proxy-analyzer.d.ts +206 -0
  105. package/dist/core/expressions/magic-proxy-analyzer.d.ts.map +1 -0
  106. package/dist/core/expressions/magic-proxy-analyzer.js +639 -0
  107. package/dist/core/expressions/magic-proxy-analyzer.js.map +1 -0
  108. package/dist/core/expressions/magic-proxy-detector.d.ts +154 -0
  109. package/dist/core/expressions/magic-proxy-detector.d.ts.map +1 -0
  110. package/dist/core/expressions/magic-proxy-detector.js +242 -0
  111. package/dist/core/expressions/magic-proxy-detector.js.map +1 -0
  112. package/dist/core/expressions/migration-helpers.d.ts +133 -0
  113. package/dist/core/expressions/migration-helpers.d.ts.map +1 -0
  114. package/dist/core/expressions/migration-helpers.js +443 -0
  115. package/dist/core/expressions/migration-helpers.js.map +1 -0
  116. package/dist/core/expressions/optionality-handler.d.ts +503 -0
  117. package/dist/core/expressions/optionality-handler.d.ts.map +1 -0
  118. package/dist/core/expressions/optionality-handler.js +1306 -0
  119. package/dist/core/expressions/optionality-handler.js.map +1 -0
  120. package/dist/core/expressions/readiness-integration.d.ts +119 -0
  121. package/dist/core/expressions/readiness-integration.d.ts.map +1 -0
  122. package/dist/core/expressions/readiness-integration.js +386 -0
  123. package/dist/core/expressions/readiness-integration.js.map +1 -0
  124. package/dist/core/expressions/resource-analyzer.d.ts +486 -0
  125. package/dist/core/expressions/resource-analyzer.d.ts.map +1 -0
  126. package/dist/core/expressions/resource-analyzer.js +1086 -0
  127. package/dist/core/expressions/resource-analyzer.js.map +1 -0
  128. package/dist/core/expressions/resource-validation.d.ts +187 -0
  129. package/dist/core/expressions/resource-validation.d.ts.map +1 -0
  130. package/dist/core/expressions/resource-validation.js +552 -0
  131. package/dist/core/expressions/resource-validation.js.map +1 -0
  132. package/dist/core/expressions/runtime-error-mapper.d.ts +138 -0
  133. package/dist/core/expressions/runtime-error-mapper.d.ts.map +1 -0
  134. package/dist/core/expressions/runtime-error-mapper.js +412 -0
  135. package/dist/core/expressions/runtime-error-mapper.js.map +1 -0
  136. package/dist/core/expressions/source-map.d.ts +168 -0
  137. package/dist/core/expressions/source-map.d.ts.map +1 -0
  138. package/dist/core/expressions/source-map.js +350 -0
  139. package/dist/core/expressions/source-map.js.map +1 -0
  140. package/dist/core/expressions/status-builder-analyzer.d.ts +353 -0
  141. package/dist/core/expressions/status-builder-analyzer.d.ts.map +1 -0
  142. package/dist/core/expressions/status-builder-analyzer.js +1301 -0
  143. package/dist/core/expressions/status-builder-analyzer.js.map +1 -0
  144. package/dist/core/expressions/type-inference.d.ts +184 -0
  145. package/dist/core/expressions/type-inference.d.ts.map +1 -0
  146. package/dist/core/expressions/type-inference.js +838 -0
  147. package/dist/core/expressions/type-inference.js.map +1 -0
  148. package/dist/core/expressions/type-safety.d.ts +203 -0
  149. package/dist/core/expressions/type-safety.d.ts.map +1 -0
  150. package/dist/core/expressions/type-safety.js +442 -0
  151. package/dist/core/expressions/type-safety.js.map +1 -0
  152. package/dist/core/expressions/types.d.ts +282 -0
  153. package/dist/core/expressions/types.d.ts.map +1 -0
  154. package/dist/core/expressions/types.js +8 -0
  155. package/dist/core/expressions/types.js.map +1 -0
  156. package/dist/core/kubernetes/client-provider.js +2 -2
  157. package/dist/core/kubernetes/client-provider.js.map +1 -1
  158. package/dist/core/serialization/core.d.ts.map +1 -1
  159. package/dist/core/serialization/core.js +573 -9
  160. package/dist/core/serialization/core.js.map +1 -1
  161. package/dist/core/types/deployment.d.ts +4 -0
  162. package/dist/core/types/deployment.d.ts.map +1 -1
  163. package/dist/core/types/deployment.js.map +1 -1
  164. package/dist/core/types/index.d.ts +1 -0
  165. package/dist/core/types/index.d.ts.map +1 -1
  166. package/dist/core/types/index.js.map +1 -1
  167. package/dist/core.d.ts +1 -1
  168. package/dist/core.d.ts.map +1 -1
  169. package/dist/core.js +1 -1
  170. package/dist/core.js.map +1 -1
  171. package/dist/factories/helm/helm-release.d.ts.map +1 -1
  172. package/dist/factories/helm/helm-release.js +0 -5
  173. package/dist/factories/helm/helm-release.js.map +1 -1
  174. package/dist/factories/helm/types.d.ts +1 -1
  175. package/dist/factories/helm/types.d.ts.map +1 -1
  176. package/dist/factories/shared.d.ts.map +1 -1
  177. package/dist/factories/shared.js +21 -1
  178. package/dist/factories/shared.js.map +1 -1
  179. package/dist/factories/simple/index.d.ts +2 -2
  180. package/dist/factories/simple/index.d.ts.map +1 -1
  181. package/dist/factories/simple/workloads/deployment.d.ts +3 -3
  182. package/dist/factories/simple/workloads/deployment.d.ts.map +1 -1
  183. package/dist/factories/simple/workloads/deployment.js +37 -11
  184. package/dist/factories/simple/workloads/deployment.js.map +1 -1
  185. package/dist/index.d.ts +1 -1
  186. package/dist/index.d.ts.map +1 -1
  187. package/dist/index.js +1 -1
  188. package/dist/index.js.map +1 -1
  189. package/dist/utils/index.d.ts +1 -1
  190. package/dist/utils/index.d.ts.map +1 -1
  191. package/dist/utils/index.js +1 -1
  192. package/dist/utils/index.js.map +1 -1
  193. package/dist/utils/type-guards.d.ts +6 -0
  194. package/dist/utils/type-guards.d.ts.map +1 -1
  195. package/dist/utils/type-guards.js +25 -2
  196. package/dist/utils/type-guards.js.map +1 -1
  197. package/package.json +6 -1
@@ -0,0 +1,1301 @@
1
+ /**
2
+ * Status Builder Analyzer for JavaScript to CEL Expression Conversion
3
+ *
4
+ * This module provides specialized analysis for status builder functions used in
5
+ * toResourceGraph. It detects KubernetesRef objects from the magic proxy system
6
+ * and converts JavaScript expressions to appropriate CEL expressions for status
7
+ * field population.
8
+ *
9
+ * Key Features:
10
+ * - Analyzes status builder functions for KubernetesRef detection
11
+ * - Converts return object expressions to CEL for status field mapping
12
+ * - Integrates with magic proxy system (SchemaProxy and ResourcesProxy)
13
+ * - Provides status context-specific CEL generation
14
+ * - Supports both direct and Kro factory patterns
15
+ */
16
+ import * as acorn from 'acorn';
17
+ import * as estraverse from 'estraverse';
18
+ import { ConversionError } from '../errors.js';
19
+ import { getComponentLogger } from '../logging/index.js';
20
+ import { containsKubernetesRefs } from '../../utils/type-guards.js';
21
+ import { JavaScriptToCelAnalyzer } from './analyzer.js';
22
+ import { MagicProxyAnalyzer, } from './magic-proxy-analyzer.js';
23
+ import { SourceMapBuilder } from './source-map.js';
24
+ import { EnhancedTypeOptionalityHandler } from './optionality-handler.js';
25
+ import { CEL_EXPRESSION_BRAND } from '../constants/brands.js';
26
+ /**
27
+ * Default analysis options
28
+ */
29
+ const DEFAULT_ANALYSIS_OPTIONS = {
30
+ deepAnalysis: true,
31
+ includeSourceMapping: true,
32
+ validateReferences: true,
33
+ performOptionalityAnalysis: true,
34
+ factoryType: 'kro',
35
+ maxDepth: 10,
36
+ hydrationStates: new Map(),
37
+ conservativeNullSafety: true
38
+ };
39
+ /**
40
+ * Status Builder Analyzer
41
+ *
42
+ * Analyzes status builder functions to extract KubernetesRef dependencies
43
+ * and convert JavaScript expressions to CEL for status field population.
44
+ */
45
+ export class StatusBuilderAnalyzer {
46
+ expressionAnalyzer;
47
+ magicProxyAnalyzer;
48
+ optionalityHandler;
49
+ options;
50
+ logger = getComponentLogger('status-builder-analyzer');
51
+ constructor(expressionAnalyzer, options) {
52
+ this.expressionAnalyzer = expressionAnalyzer || new JavaScriptToCelAnalyzer();
53
+ this.magicProxyAnalyzer = new MagicProxyAnalyzer();
54
+ this.optionalityHandler = new EnhancedTypeOptionalityHandler();
55
+ this.options = { ...DEFAULT_ANALYSIS_OPTIONS, ...options };
56
+ }
57
+ /**
58
+ * Analyze status builder function for toResourceGraph integration
59
+ *
60
+ * This is the main method that analyzes a status builder function and extracts
61
+ * KubernetesRef dependencies for conversion to CEL expressions.
62
+ */
63
+ analyzeStatusBuilder(statusBuilder, resources, schemaProxy) {
64
+ try {
65
+ this.logger.debug('Analyzing status builder function', {
66
+ resourceCount: Object.keys(resources).length,
67
+ hasSchemaProxy: !!schemaProxy,
68
+ factoryType: this.options.factoryType
69
+ });
70
+ const originalSource = statusBuilder.toString();
71
+ // Parse the status builder function
72
+ const ast = this.parseStatusBuilderFunction(originalSource);
73
+ // Analyze the return statement
74
+ const returnStatement = this.analyzeReturnStatement(ast, originalSource);
75
+ if (!returnStatement || !returnStatement.returnsObject) {
76
+ throw new ConversionError('Status builder must return an object literal', originalSource, 'function-call');
77
+ }
78
+ // Analyze each property in the returned object
79
+ const fieldAnalysis = new Map();
80
+ const statusMappings = {};
81
+ const allDependencies = [];
82
+ const allSourceMap = [];
83
+ const allErrors = [];
84
+ let overallValid = true;
85
+ for (const property of returnStatement.properties) {
86
+ try {
87
+ const fieldResult = this.analyzeStatusField(property, resources, originalSource, schemaProxy);
88
+ fieldAnalysis.set(property.name, fieldResult);
89
+ if (fieldResult.valid) {
90
+ if (fieldResult.celExpression) {
91
+ // For dynamic expressions, use the CEL expression directly
92
+ statusMappings[property.name] = fieldResult.celExpression;
93
+ }
94
+ else if (fieldResult.staticValue !== undefined) {
95
+ // For static objects, keep as plain JavaScript objects for performance
96
+ statusMappings[property.name] = fieldResult.staticValue;
97
+ }
98
+ else if (property.valueNode.type === 'Literal') {
99
+ // For static literals, keep as plain JavaScript values for performance
100
+ statusMappings[property.name] = property.valueNode.value;
101
+ }
102
+ else if (property.valueNode.type === 'Identifier' && property.valueNode.name === 'undefined') {
103
+ // For undefined identifier, preserve as undefined (will be filtered out during serialization)
104
+ statusMappings[property.name] = undefined;
105
+ }
106
+ else if (property.valueNode.type === 'UnaryExpression' &&
107
+ property.valueNode.operator === '!' &&
108
+ property.valueNode.argument?.type === 'Literal' &&
109
+ typeof property.valueNode.argument.value === 'number') {
110
+ // For boolean literals represented as !0 or !1
111
+ const booleanValue = property.valueNode.argument.value === 0; // !0 = true, !1 = false
112
+ statusMappings[property.name] = booleanValue;
113
+ }
114
+ }
115
+ allDependencies.push(...fieldResult.dependencies);
116
+ allSourceMap.push(...fieldResult.sourceMap);
117
+ allErrors.push(...fieldResult.errors);
118
+ if (!fieldResult.valid) {
119
+ overallValid = false;
120
+ }
121
+ }
122
+ catch (error) {
123
+ const fieldError = new ConversionError(`Failed to analyze status field '${property.name}': ${error instanceof Error ? error.message : String(error)}`, property.valueSource, 'unknown');
124
+ allErrors.push(fieldError);
125
+ overallValid = false;
126
+ this.logger.error('Failed to analyze status field', error, {
127
+ fieldName: property.name
128
+ });
129
+ }
130
+ }
131
+ // Categorize dependencies
132
+ const { resourceReferences, schemaReferences } = this.categorizeDependencies(allDependencies);
133
+ this.logger.debug('Status builder analysis complete', {
134
+ fieldCount: returnStatement.properties.length,
135
+ validFields: Object.keys(statusMappings).length,
136
+ totalDependencies: allDependencies.length,
137
+ resourceReferences: resourceReferences.length,
138
+ schemaReferences: schemaReferences.length,
139
+ overallValid
140
+ });
141
+ return {
142
+ fieldAnalysis,
143
+ statusMappings,
144
+ allDependencies,
145
+ resourceReferences,
146
+ schemaReferences,
147
+ sourceMap: allSourceMap,
148
+ errors: allErrors,
149
+ valid: overallValid,
150
+ originalSource,
151
+ ast,
152
+ returnStatement
153
+ };
154
+ }
155
+ catch (error) {
156
+ const analysisError = new ConversionError(`Failed to analyze status builder: ${error instanceof Error ? error.message : String(error)}`, statusBuilder.toString(), 'function-call');
157
+ this.logger.error('Status builder analysis failed', error);
158
+ return {
159
+ fieldAnalysis: new Map(),
160
+ statusMappings: {},
161
+ allDependencies: [],
162
+ resourceReferences: [],
163
+ schemaReferences: [],
164
+ sourceMap: [],
165
+ errors: [analysisError],
166
+ valid: false,
167
+ originalSource: statusBuilder.toString()
168
+ };
169
+ }
170
+ }
171
+ /**
172
+ * Analyze return object expressions with magic proxy support
173
+ *
174
+ * This method analyzes the object returned by the status builder function
175
+ * and detects KubernetesRef objects from the magic proxy system.
176
+ */
177
+ analyzeReturnObjectWithMagicProxy(returnObject, resources, schemaProxy) {
178
+ const statusMappings = {};
179
+ const dependencies = [];
180
+ const errors = [];
181
+ if (!returnObject || typeof returnObject !== 'object') {
182
+ errors.push(new ConversionError('Return object must be a valid object', String(returnObject), 'unknown'));
183
+ return { statusMappings, dependencies, errors };
184
+ }
185
+ for (const [fieldName, fieldValue] of Object.entries(returnObject)) {
186
+ try {
187
+ const fieldResult = this.analyzeReturnObjectField(fieldName, fieldValue, resources, schemaProxy);
188
+ if (fieldResult.celExpression) {
189
+ statusMappings[fieldName] = fieldResult.celExpression;
190
+ }
191
+ dependencies.push(...fieldResult.dependencies);
192
+ errors.push(...fieldResult.errors);
193
+ }
194
+ catch (error) {
195
+ errors.push(new ConversionError(`Failed to analyze field '${fieldName}': ${error instanceof Error ? error.message : String(error)}`, String(fieldValue), 'unknown'));
196
+ }
197
+ }
198
+ return { statusMappings, dependencies, errors };
199
+ }
200
+ /**
201
+ * Analyze a single field in the return object with comprehensive magic proxy support
202
+ */
203
+ analyzeReturnObjectField(fieldName, fieldValue, resources, schemaProxy) {
204
+ try {
205
+ // Create comprehensive analysis context
206
+ const context = {
207
+ type: 'status',
208
+ availableReferences: resources,
209
+ ...(schemaProxy && { schemaProxy }),
210
+ factoryType: this.options.factoryType,
211
+ hydrationStates: this.options.hydrationStates,
212
+ conservativeNullSafety: this.options.conservativeNullSafety,
213
+ useKroConditionals: true,
214
+ generateHasChecks: true,
215
+ maxOptionalityDepth: this.options.maxDepth,
216
+ dependencies: []
217
+ };
218
+ // Step 1: Detect if the field value contains KubernetesRef objects
219
+ const containsRefs = containsKubernetesRefs(fieldValue);
220
+ if (!containsRefs) {
221
+ // No KubernetesRef objects - return as static value
222
+ return {
223
+ celExpression: this.convertStaticValueToCel(fieldValue),
224
+ dependencies: [],
225
+ errors: [],
226
+ requiresConversion: false
227
+ };
228
+ }
229
+ // Step 2: Analyze KubernetesRef objects for optionality requirements
230
+ const optionalityResults = this.optionalityHandler.analyzeOptionalityRequirements(fieldValue, context);
231
+ // Step 3: Generate CEL expression with appropriate null-safety
232
+ const celResult = this.optionalityHandler.generateNullSafeCelExpression(fieldValue, optionalityResults, context);
233
+ // Step 4: Extract dependencies from the analysis
234
+ const dependencies = optionalityResults.map(result => result.kubernetesRef);
235
+ return {
236
+ celExpression: celResult.celExpression,
237
+ dependencies,
238
+ errors: celResult.errors,
239
+ requiresConversion: true
240
+ };
241
+ }
242
+ catch (error) {
243
+ const fieldError = new ConversionError(`Failed to analyze return object field '${fieldName}': ${error instanceof Error ? error.message : String(error)}`, String(fieldValue), 'unknown');
244
+ return {
245
+ celExpression: null,
246
+ dependencies: [],
247
+ errors: [fieldError],
248
+ requiresConversion: false
249
+ };
250
+ }
251
+ }
252
+ /**
253
+ * Convert static values (no KubernetesRef objects) to CEL expressions
254
+ */
255
+ convertStaticValueToCel(value) {
256
+ let celExpression;
257
+ let type;
258
+ if (typeof value === 'string') {
259
+ celExpression = `"${value.replace(/"/g, '\\"')}"`;
260
+ type = 'string';
261
+ }
262
+ else if (typeof value === 'number') {
263
+ celExpression = String(value);
264
+ type = 'number';
265
+ }
266
+ else if (typeof value === 'boolean') {
267
+ celExpression = String(value);
268
+ type = 'boolean';
269
+ }
270
+ else if (value === null) {
271
+ celExpression = 'null';
272
+ type = 'null';
273
+ }
274
+ else if (value === undefined) {
275
+ celExpression = 'null';
276
+ type = 'null';
277
+ }
278
+ else if (Array.isArray(value)) {
279
+ const elements = value.map(item => this.convertStaticValueToCel(item).expression);
280
+ celExpression = `[${elements.join(', ')}]`;
281
+ type = 'array';
282
+ }
283
+ else if (typeof value === 'object') {
284
+ const properties = Object.entries(value).map(([key, val]) => {
285
+ const convertedVal = this.convertStaticValueToCel(val);
286
+ return `"${key}": ${convertedVal.expression}`;
287
+ });
288
+ celExpression = `{${properties.join(', ')}}`;
289
+ type = 'object';
290
+ }
291
+ else {
292
+ celExpression = String(value);
293
+ type = 'unknown';
294
+ }
295
+ return {
296
+ [CEL_EXPRESSION_BRAND]: true,
297
+ expression: celExpression,
298
+ type
299
+ };
300
+ }
301
+ /**
302
+ * Perform deep analysis of nested return object structures
303
+ */
304
+ analyzeNestedReturnObjectStructure(returnObject, resources, schemaProxy, depth = 0) {
305
+ const flattenedMappings = {};
306
+ const nestedDependencies = new Map();
307
+ const structureErrors = [];
308
+ if (depth > this.options.maxDepth) {
309
+ structureErrors.push(new ConversionError(`Maximum analysis depth (${this.options.maxDepth}) exceeded`, String(returnObject), 'unknown'));
310
+ return { flattenedMappings, nestedDependencies, structureErrors };
311
+ }
312
+ try {
313
+ this.analyzeObjectStructureRecursively(returnObject, '', flattenedMappings, nestedDependencies, structureErrors, resources, schemaProxy, depth);
314
+ }
315
+ catch (error) {
316
+ structureErrors.push(new ConversionError(`Failed to analyze nested structure: ${error instanceof Error ? error.message : String(error)}`, String(returnObject), 'unknown'));
317
+ }
318
+ return { flattenedMappings, nestedDependencies, structureErrors };
319
+ }
320
+ /**
321
+ * Recursively analyze object structure for KubernetesRef objects
322
+ */
323
+ analyzeObjectStructureRecursively(obj, pathPrefix, flattenedMappings, nestedDependencies, errors, resources, schemaProxy, depth = 0) {
324
+ if (!obj || typeof obj !== 'object' || Array.isArray(obj)) {
325
+ return;
326
+ }
327
+ for (const [key, value] of Object.entries(obj)) {
328
+ const fullPath = pathPrefix ? `${pathPrefix}.${key}` : key;
329
+ try {
330
+ if (containsKubernetesRefs(value)) {
331
+ // Analyze this field for KubernetesRef objects
332
+ const fieldResult = this.analyzeReturnObjectField(fullPath, value, resources, schemaProxy);
333
+ if (fieldResult.celExpression) {
334
+ flattenedMappings[fullPath] = fieldResult.celExpression;
335
+ }
336
+ if (fieldResult.dependencies.length > 0) {
337
+ nestedDependencies.set(fullPath, fieldResult.dependencies);
338
+ }
339
+ errors.push(...fieldResult.errors);
340
+ }
341
+ else if (value && typeof value === 'object' && !Array.isArray(value)) {
342
+ // Recursively analyze nested objects
343
+ this.analyzeObjectStructureRecursively(value, fullPath, flattenedMappings, nestedDependencies, errors, resources, schemaProxy, depth + 1);
344
+ }
345
+ else {
346
+ // Static value - convert directly
347
+ flattenedMappings[fullPath] = this.convertStaticValueToCel(value);
348
+ }
349
+ }
350
+ catch (error) {
351
+ errors.push(new ConversionError(`Failed to analyze nested field '${fullPath}': ${error instanceof Error ? error.message : String(error)}`, String(value), 'unknown'));
352
+ }
353
+ }
354
+ }
355
+ /**
356
+ * Generate status context-specific CEL from KubernetesRef objects
357
+ *
358
+ * This method generates CEL expressions specifically for status context,
359
+ * taking into account the magic proxy system and field hydration timing.
360
+ */
361
+ generateStatusContextCel(kubernetesRef, context) {
362
+ try {
363
+ return this.generateStatusContextCelWithAdvancedFeatures(kubernetesRef, context);
364
+ }
365
+ catch (error) {
366
+ this.logger.error('Failed to generate status context CEL', error, {
367
+ resourceId: kubernetesRef.resourceId,
368
+ fieldPath: kubernetesRef.fieldPath
369
+ });
370
+ // Return a safe fallback
371
+ return this.generateFallbackStatusCel(kubernetesRef);
372
+ }
373
+ }
374
+ /**
375
+ * Generate advanced status context CEL with full feature support
376
+ */
377
+ generateStatusContextCelWithAdvancedFeatures(kubernetesRef, context) {
378
+ const isSchemaRef = kubernetesRef.resourceId === '__schema__';
379
+ const fieldPath = kubernetesRef.fieldPath || '';
380
+ // Build base CEL expression
381
+ let baseCelExpression;
382
+ if (isSchemaRef) {
383
+ baseCelExpression = `schema.${fieldPath}`;
384
+ }
385
+ else {
386
+ baseCelExpression = `resources.${kubernetesRef.resourceId}.${fieldPath}`;
387
+ }
388
+ // Determine status-specific handling requirements
389
+ const statusHandlingInfo = this.analyzeStatusFieldHandlingRequirements(kubernetesRef, context);
390
+ // Apply status-specific transformations
391
+ const finalExpression = this.applyStatusContextTransformations(baseCelExpression, statusHandlingInfo, context);
392
+ // Infer the result type based on the field path and context
393
+ const resultType = this.inferStatusFieldType(kubernetesRef, context);
394
+ return {
395
+ [CEL_EXPRESSION_BRAND]: true,
396
+ expression: finalExpression,
397
+ type: resultType,
398
+ metadata: {
399
+ isStatusContext: true,
400
+ requiresHydration: statusHandlingInfo.requiresHydration,
401
+ isOptional: statusHandlingInfo.isOptional,
402
+ handlingStrategy: statusHandlingInfo.strategy
403
+ }
404
+ };
405
+ }
406
+ /**
407
+ * Analyze status field handling requirements
408
+ */
409
+ analyzeStatusFieldHandlingRequirements(kubernetesRef, context) {
410
+ const fieldPath = kubernetesRef.fieldPath || '';
411
+ const isSchemaRef = kubernetesRef.resourceId === '__schema__';
412
+ const isStatusField = fieldPath.startsWith('status.');
413
+ // Determine if this field requires hydration
414
+ const requiresHydration = !isSchemaRef && isStatusField;
415
+ // Determine if this field is optional in status context
416
+ const isOptional = this.isFieldOptionalInStatusContext(kubernetesRef, context);
417
+ // Determine handling strategy
418
+ let strategy;
419
+ if (requiresHydration && isOptional) {
420
+ strategy = 'hydration-with-null-safety';
421
+ }
422
+ else if (requiresHydration) {
423
+ strategy = 'hydration-required';
424
+ }
425
+ else if (isOptional) {
426
+ strategy = 'null-safety-only';
427
+ }
428
+ else {
429
+ strategy = 'direct-access';
430
+ }
431
+ // Determine priority for status field evaluation
432
+ const priority = this.calculateStatusFieldPriority(kubernetesRef, context);
433
+ return {
434
+ kubernetesRef,
435
+ requiresHydration,
436
+ isOptional,
437
+ strategy,
438
+ priority,
439
+ fieldCategory: this.categorizeStatusField(fieldPath),
440
+ expectedAvailability: this.estimateFieldAvailability(kubernetesRef, context)
441
+ };
442
+ }
443
+ /**
444
+ * Apply status context-specific transformations to CEL expression
445
+ */
446
+ applyStatusContextTransformations(baseCelExpression, handlingInfo, context) {
447
+ let transformedExpression = baseCelExpression;
448
+ switch (handlingInfo.strategy) {
449
+ case 'hydration-with-null-safety':
450
+ transformedExpression = this.applyHydrationWithNullSafety(baseCelExpression, handlingInfo, context);
451
+ break;
452
+ case 'hydration-required':
453
+ transformedExpression = this.applyHydrationRequired(baseCelExpression, handlingInfo, context);
454
+ break;
455
+ case 'null-safety-only':
456
+ transformedExpression = this.applyNullSafetyOnly(baseCelExpression, handlingInfo, context);
457
+ break;
458
+ case 'direct-access':
459
+ // No transformation needed
460
+ break;
461
+ }
462
+ return transformedExpression;
463
+ }
464
+ /**
465
+ * Apply hydration with null-safety transformation
466
+ */
467
+ applyHydrationWithNullSafety(baseCelExpression, _handlingInfo, context) {
468
+ if (context.useKroConditionals) {
469
+ // Use Kro's conditional operators
470
+ return baseCelExpression.replace(/\./g, '?.');
471
+ }
472
+ else if (context.generateHasChecks) {
473
+ // Use has() checks
474
+ const pathParts = baseCelExpression.split('.');
475
+ const hasChecks = [];
476
+ for (let i = 0; i < pathParts.length; i++) {
477
+ const partialPath = pathParts.slice(0, i + 1).join('.');
478
+ hasChecks.push(`has(${partialPath})`);
479
+ }
480
+ return `${hasChecks.join(' && ')} && ${baseCelExpression}`;
481
+ }
482
+ return baseCelExpression;
483
+ }
484
+ /**
485
+ * Apply hydration required transformation
486
+ */
487
+ applyHydrationRequired(baseCelExpression, handlingInfo, _context) {
488
+ // For hydration required fields, we might want to add readiness checks
489
+ if (handlingInfo.fieldCategory === 'readiness-indicator') {
490
+ return `${baseCelExpression} != null && ${baseCelExpression}`;
491
+ }
492
+ return baseCelExpression;
493
+ }
494
+ /**
495
+ * Apply null-safety only transformation
496
+ */
497
+ applyNullSafetyOnly(baseCelExpression, _handlingInfo, context) {
498
+ if (context.generateHasChecks) {
499
+ return `has(${baseCelExpression}) && ${baseCelExpression}`;
500
+ }
501
+ return baseCelExpression;
502
+ }
503
+ /**
504
+ * Check if a field is optional in status context
505
+ */
506
+ isFieldOptionalInStatusContext(kubernetesRef, _context) {
507
+ const fieldPath = kubernetesRef.fieldPath || '';
508
+ // Status fields are generally optional during hydration
509
+ if (fieldPath.startsWith('status.')) {
510
+ return true;
511
+ }
512
+ // Some spec fields might be optional
513
+ const optionalSpecFields = [
514
+ 'spec.replicas',
515
+ 'spec.resources',
516
+ 'spec.nodeSelector',
517
+ 'spec.tolerations'
518
+ ];
519
+ if (optionalSpecFields.some(field => fieldPath.startsWith(field))) {
520
+ return true;
521
+ }
522
+ // Metadata fields like labels and annotations are optional
523
+ const optionalMetadataFields = [
524
+ 'metadata.labels',
525
+ 'metadata.annotations',
526
+ 'metadata.namespace'
527
+ ];
528
+ if (optionalMetadataFields.some(field => fieldPath.startsWith(field))) {
529
+ return true;
530
+ }
531
+ return false;
532
+ }
533
+ /**
534
+ * Calculate priority for status field evaluation
535
+ */
536
+ calculateStatusFieldPriority(kubernetesRef, _context) {
537
+ const fieldPath = kubernetesRef.fieldPath || '';
538
+ // Higher priority (lower number) for critical status fields
539
+ if (fieldPath.includes('ready') || fieldPath.includes('available')) {
540
+ return 1;
541
+ }
542
+ if (fieldPath.startsWith('status.conditions')) {
543
+ return 2;
544
+ }
545
+ if (fieldPath.startsWith('status.')) {
546
+ return 3;
547
+ }
548
+ if (fieldPath.startsWith('spec.')) {
549
+ return 4;
550
+ }
551
+ if (fieldPath.startsWith('metadata.')) {
552
+ return 5;
553
+ }
554
+ return 10; // Default priority
555
+ }
556
+ /**
557
+ * Categorize status field type
558
+ */
559
+ categorizeStatusField(fieldPath) {
560
+ if (fieldPath.includes('ready') || fieldPath.includes('available')) {
561
+ return 'readiness-indicator';
562
+ }
563
+ if (fieldPath.includes('conditions')) {
564
+ return 'condition-status';
565
+ }
566
+ if (fieldPath.includes('replicas')) {
567
+ return 'replica-status';
568
+ }
569
+ if (fieldPath.includes('loadBalancer') || fieldPath.includes('ingress')) {
570
+ return 'network-status';
571
+ }
572
+ if (fieldPath.includes('phase') || fieldPath.includes('state')) {
573
+ return 'lifecycle-status';
574
+ }
575
+ return 'general-status';
576
+ }
577
+ /**
578
+ * Estimate field availability timing
579
+ */
580
+ estimateFieldAvailability(kubernetesRef, _context) {
581
+ const fieldPath = kubernetesRef.fieldPath || '';
582
+ if (kubernetesRef.resourceId === '__schema__') {
583
+ return 'immediate';
584
+ }
585
+ if (fieldPath.startsWith('metadata.')) {
586
+ return 'immediate';
587
+ }
588
+ if (fieldPath.startsWith('spec.')) {
589
+ return 'immediate';
590
+ }
591
+ if (fieldPath.includes('ready') || fieldPath.includes('available')) {
592
+ return 'delayed';
593
+ }
594
+ if (fieldPath.includes('loadBalancer') || fieldPath.includes('ingress')) {
595
+ return 'very-delayed';
596
+ }
597
+ return 'delayed';
598
+ }
599
+ /**
600
+ * Infer the type of a status field
601
+ */
602
+ inferStatusFieldType(kubernetesRef, _context) {
603
+ const fieldPath = kubernetesRef.fieldPath || '';
604
+ if (fieldPath.includes('replicas') || fieldPath.includes('count')) {
605
+ return 'number';
606
+ }
607
+ if (fieldPath.includes('ready') || fieldPath.includes('available')) {
608
+ return 'boolean';
609
+ }
610
+ if (fieldPath.includes('conditions')) {
611
+ return 'array';
612
+ }
613
+ if (fieldPath.includes('phase') || fieldPath.includes('state')) {
614
+ return 'string';
615
+ }
616
+ if (fieldPath.includes('ip') || fieldPath.includes('IP')) {
617
+ return 'string';
618
+ }
619
+ return 'unknown';
620
+ }
621
+ /**
622
+ * Analyze a mixed object expression (contains both static and dynamic values)
623
+ */
624
+ analyzeMixedObjectExpression(objectNode, resources, originalSource, schemaProxy) {
625
+ if (objectNode.type !== 'ObjectExpression') {
626
+ return { valid: false, processedObject: null, dependencies: [], requiresConversion: false };
627
+ }
628
+ const result = {};
629
+ const allDependencies = [];
630
+ let requiresConversion = false;
631
+ for (const prop of objectNode.properties) {
632
+ if (prop.type === 'Property' && prop.key.type === 'Identifier') {
633
+ const key = prop.key.name;
634
+ // Handle different value types
635
+ if (prop.value.type === 'Literal') {
636
+ // Static literal value
637
+ result[key] = prop.value.value;
638
+ }
639
+ else if (prop.value.type === 'ObjectExpression') {
640
+ // Nested object - recursively analyze
641
+ const nestedResult = this.analyzeMixedObjectExpression(prop.value, resources, originalSource, schemaProxy);
642
+ if (nestedResult.valid) {
643
+ result[key] = nestedResult.processedObject;
644
+ allDependencies.push(...nestedResult.dependencies);
645
+ if (nestedResult.requiresConversion) {
646
+ requiresConversion = true;
647
+ }
648
+ }
649
+ else {
650
+ return { valid: false, processedObject: null, dependencies: [], requiresConversion: false };
651
+ }
652
+ }
653
+ else {
654
+ // Dynamic expression - analyze with expression analyzer
655
+ let valueSource;
656
+ try {
657
+ valueSource = this.getNodeSource(prop.value, originalSource);
658
+ }
659
+ catch (_error) {
660
+ return { valid: false, processedObject: null, dependencies: [], requiresConversion: false };
661
+ }
662
+ // Create analysis context
663
+ const context = {
664
+ type: 'status',
665
+ availableReferences: resources,
666
+ ...(schemaProxy && { schemaProxy }),
667
+ factoryType: this.options.factoryType,
668
+ dependencies: []
669
+ };
670
+ try {
671
+ // Analyze the expression using the main analyzer
672
+ const analysisResult = this.expressionAnalyzer.analyzeExpression(valueSource, context);
673
+ if (analysisResult.valid && analysisResult.celExpression) {
674
+ // Dynamic expression - wrap in CEL
675
+ const celString = analysisResult.celExpression.expression;
676
+ result[key] = celString.includes('${') ? celString : `\${${celString}}`;
677
+ allDependencies.push(...analysisResult.dependencies);
678
+ requiresConversion = true;
679
+ }
680
+ else {
681
+ // Try to evaluate as static value
682
+ const staticValue = this.evaluateStaticValue(prop.value);
683
+ if (staticValue !== null) {
684
+ result[key] = staticValue;
685
+ }
686
+ else {
687
+ return { valid: false, processedObject: null, dependencies: [], requiresConversion: false };
688
+ }
689
+ }
690
+ }
691
+ catch (error) {
692
+ // If expression analysis fails, try static evaluation
693
+ const staticValue = this.evaluateStaticValue(prop.value);
694
+ if (staticValue !== null) {
695
+ result[key] = staticValue;
696
+ }
697
+ else {
698
+ console.log(`Failed to analyze property '${key}' of type '${prop.value.type}':`, error);
699
+ return { valid: false, processedObject: null, dependencies: [], requiresConversion: false };
700
+ }
701
+ }
702
+ }
703
+ }
704
+ else {
705
+ // Non-standard property structure
706
+ return { valid: false, processedObject: null, dependencies: [], requiresConversion: false };
707
+ }
708
+ }
709
+ return {
710
+ valid: true,
711
+ processedObject: result,
712
+ dependencies: allDependencies,
713
+ requiresConversion
714
+ };
715
+ }
716
+ /**
717
+ * Evaluate a static object expression to a JavaScript object
718
+ */
719
+ evaluateStaticObjectExpression(objectNode) {
720
+ if (objectNode.type !== 'ObjectExpression') {
721
+ return null;
722
+ }
723
+ const result = {};
724
+ for (const prop of objectNode.properties) {
725
+ if (prop.type === 'Property' && prop.key.type === 'Identifier') {
726
+ const key = prop.key.name;
727
+ const value = this.evaluateStaticValue(prop.value);
728
+ if (value === null && prop.value.type !== 'Literal') {
729
+ // If we can't evaluate a property statically, this isn't a static object
730
+ return null;
731
+ }
732
+ result[key] = value;
733
+ }
734
+ else {
735
+ // Non-static property structure
736
+ return null;
737
+ }
738
+ }
739
+ return result;
740
+ }
741
+ /**
742
+ * Evaluate a static value from an AST node
743
+ */
744
+ evaluateStaticValue(node) {
745
+ switch (node.type) {
746
+ case 'Literal':
747
+ return node.value;
748
+ case 'UnaryExpression':
749
+ if (node.operator === '!' && node.argument?.type === 'Literal') {
750
+ return !node.argument.value;
751
+ }
752
+ if (node.operator === '-' && node.argument?.type === 'Literal' && typeof node.argument.value === 'number') {
753
+ return -node.argument.value;
754
+ }
755
+ return null;
756
+ case 'ObjectExpression':
757
+ return this.evaluateStaticObjectExpression(node);
758
+ case 'ArrayExpression': {
759
+ const arrayResult = [];
760
+ for (const element of node.elements) {
761
+ if (element === null) {
762
+ arrayResult.push(null);
763
+ }
764
+ else {
765
+ const elementValue = this.evaluateStaticValue(element);
766
+ if (elementValue === null && element.type !== 'Literal') {
767
+ return null; // Non-static array
768
+ }
769
+ arrayResult.push(elementValue);
770
+ }
771
+ }
772
+ return arrayResult;
773
+ }
774
+ default:
775
+ return null; // Non-static value
776
+ }
777
+ }
778
+ /**
779
+ * Create a CelExpression for a static value
780
+ */
781
+ createStaticCelExpression(value) {
782
+ return {
783
+ [CEL_EXPRESSION_BRAND]: true,
784
+ expression: value
785
+ };
786
+ }
787
+ /**
788
+ * Extract source code for an AST node using range information
789
+ */
790
+ getNodeSource(node, originalSource) {
791
+ if (!node || !node.type) {
792
+ return '';
793
+ }
794
+ // Try to use range information to extract the actual source
795
+ let start;
796
+ let end;
797
+ // Check for start/end properties (acorn format)
798
+ if (typeof node.start === 'number' && typeof node.end === 'number') {
799
+ start = node.start;
800
+ end = node.end;
801
+ }
802
+ // Check for range array (alternative format)
803
+ else if (Array.isArray(node.range) && node.range.length === 2) {
804
+ start = node.range[0];
805
+ end = node.range[1];
806
+ }
807
+ // If we have valid range information, extract the source
808
+ if (typeof start === 'number' && typeof end === 'number' &&
809
+ start >= 0 && end <= originalSource.length && start <= end) {
810
+ const extracted = originalSource.slice(start, end).trim();
811
+ if (extracted.length > 0) {
812
+ return extracted;
813
+ }
814
+ }
815
+ // Fallback to manual reconstruction for specific node types
816
+ switch (node.type) {
817
+ case 'Literal':
818
+ return typeof node.value === 'string' ? `"${node.value}"` : String(node.value);
819
+ case 'Identifier':
820
+ return node.name;
821
+ case 'BinaryExpression': {
822
+ const left = this.getNodeSource(node.left, originalSource);
823
+ const right = this.getNodeSource(node.right, originalSource);
824
+ return `${left} ${node.operator} ${right}`;
825
+ }
826
+ case 'MemberExpression': {
827
+ const object = this.getNodeSource(node.object, originalSource);
828
+ if (node.computed) {
829
+ return `${object}[${this.getNodeSource(node.property, originalSource)}]`;
830
+ }
831
+ else {
832
+ const propertyName = node.property.name || this.getNodeSource(node.property, originalSource);
833
+ return `${object}.${propertyName}`;
834
+ }
835
+ }
836
+ case 'ConditionalExpression':
837
+ return `${this.getNodeSource(node.test, originalSource)} ? ${this.getNodeSource(node.consequent, originalSource)} : ${this.getNodeSource(node.alternate, originalSource)}`;
838
+ case 'LogicalExpression':
839
+ return `${this.getNodeSource(node.left, originalSource)} ${node.operator} ${this.getNodeSource(node.right, originalSource)}`;
840
+ case 'CallExpression': {
841
+ const callee = this.getNodeSource(node.callee, originalSource);
842
+ const args = node.arguments.map((arg) => this.getNodeSource(arg, originalSource)).join(', ');
843
+ return `${callee}(${args})`;
844
+ }
845
+ case 'ArrowFunctionExpression': {
846
+ const params = node.params.map((param) => param.name).join(', ');
847
+ const body = this.getNodeSource(node.body, originalSource);
848
+ return `(${params}) => ${body}`;
849
+ }
850
+ case 'TemplateLiteral': {
851
+ // Simplified template literal reconstruction
852
+ let result = '`';
853
+ for (let i = 0; i < node.quasis.length; i++) {
854
+ const quasi = node.quasis[i];
855
+ result += quasi?.value?.raw || quasi?.value?.cooked || '';
856
+ if (i < node.expressions.length) {
857
+ result += `\${${this.getNodeSource(node.expressions[i], originalSource)}}`;
858
+ }
859
+ }
860
+ result += '`';
861
+ return result;
862
+ }
863
+ default:
864
+ // Fallback - return a placeholder
865
+ return `<${node.type}>`;
866
+ }
867
+ }
868
+ /**
869
+ * Generate fallback status CEL expression
870
+ */
871
+ generateFallbackStatusCel(kubernetesRef) {
872
+ const isSchemaRef = kubernetesRef.resourceId === '__schema__';
873
+ const basePath = isSchemaRef
874
+ ? `schema.${kubernetesRef.fieldPath}`
875
+ : `resources.${kubernetesRef.resourceId}.${kubernetesRef.fieldPath}`;
876
+ return {
877
+ [CEL_EXPRESSION_BRAND]: true,
878
+ expression: basePath,
879
+ type: 'unknown'
880
+ };
881
+ }
882
+ /**
883
+ * Parse status builder function to AST
884
+ */
885
+ parseStatusBuilderFunction(source) {
886
+ try {
887
+ // Parse the function source with modern JavaScript support using acorn
888
+ const ast = acorn.parse(source, {
889
+ ecmaVersion: 2022, // Support modern JavaScript features including optional chaining
890
+ sourceType: 'script',
891
+ locations: true,
892
+ ranges: true
893
+ });
894
+ return ast;
895
+ }
896
+ catch (error) {
897
+ throw new ConversionError(`Failed to parse status builder function: ${error instanceof Error ? error.message : String(error)}`, source, 'javascript');
898
+ }
899
+ }
900
+ /**
901
+ * Analyze the return statement of the status builder
902
+ */
903
+ analyzeReturnStatement(ast, originalSource) {
904
+ let foundReturnStatement = null;
905
+ let foundArrowFunction = null;
906
+ // Find the return statement or arrow function with implicit return
907
+ estraverse.traverse(ast, {
908
+ enter: (node) => {
909
+ if (node.type === 'ReturnStatement') {
910
+ foundReturnStatement = node;
911
+ return estraverse.VisitorOption.Break;
912
+ }
913
+ if (node.type === 'ArrowFunctionExpression' && node.body?.type === 'ObjectExpression') {
914
+ foundArrowFunction = node;
915
+ return estraverse.VisitorOption.Break;
916
+ }
917
+ return undefined;
918
+ }
919
+ });
920
+ // Handle explicit return statement
921
+ if (foundReturnStatement) {
922
+ const returnStatement = foundReturnStatement;
923
+ // Check if it returns an object expression
924
+ const returnsObject = returnStatement.argument?.type === 'ObjectExpression';
925
+ if (!returnsObject) {
926
+ return {
927
+ node: returnStatement,
928
+ returnsObject: false,
929
+ properties: [],
930
+ sourceLocation: {
931
+ line: returnStatement.loc?.start.line || 0,
932
+ column: returnStatement.loc?.start.column || 0,
933
+ length: 0
934
+ }
935
+ };
936
+ }
937
+ // Analyze properties in the object expression
938
+ const objectExpression = returnStatement.argument;
939
+ const properties = this.analyzeObjectProperties(objectExpression, originalSource);
940
+ return {
941
+ node: returnStatement,
942
+ returnsObject: true,
943
+ properties,
944
+ sourceLocation: {
945
+ line: returnStatement.loc?.start.line || 0,
946
+ column: returnStatement.loc?.start.column || 0,
947
+ length: returnStatement.range ? returnStatement.range[1] - returnStatement.range[0] : 0
948
+ }
949
+ };
950
+ }
951
+ // Handle arrow function with implicit return
952
+ if (foundArrowFunction && foundArrowFunction.body?.type === 'ObjectExpression') {
953
+ const objectExpression = foundArrowFunction.body;
954
+ const properties = this.analyzeObjectProperties(objectExpression, originalSource);
955
+ return {
956
+ node: foundArrowFunction,
957
+ returnsObject: true,
958
+ properties,
959
+ sourceLocation: {
960
+ line: objectExpression.loc?.start.line || 0,
961
+ column: objectExpression.loc?.start.column || 0,
962
+ length: objectExpression.range ? objectExpression.range[1] - objectExpression.range[0] : 0
963
+ }
964
+ };
965
+ }
966
+ return null;
967
+ }
968
+ /**
969
+ * Analyze properties in an object expression
970
+ */
971
+ analyzeObjectProperties(objectExpression, originalSource) {
972
+ const properties = [];
973
+ for (const prop of objectExpression.properties) {
974
+ if (prop.type === 'Property' && prop.key.type === 'Identifier') {
975
+ const propertyAnalysis = {
976
+ name: prop.key.name,
977
+ valueNode: prop.value,
978
+ valueSource: this.getNodeSource(prop.value, originalSource),
979
+ containsKubernetesRefs: false, // Will be determined during field analysis
980
+ sourceLocation: {
981
+ line: prop.loc?.start.line || 0,
982
+ column: prop.loc?.start.column || 0,
983
+ length: prop.range ? prop.range[1] - prop.range[0] : 0
984
+ }
985
+ };
986
+ properties.push(propertyAnalysis);
987
+ }
988
+ }
989
+ return properties;
990
+ }
991
+ /**
992
+ * Analyze a single status field
993
+ */
994
+ analyzeStatusField(property, resources, originalSource, schemaProxy) {
995
+ const fieldName = property.name;
996
+ const originalExpression = property.valueSource;
997
+ try {
998
+ // Check if this is a static literal value
999
+ if (property.valueNode.type === 'Literal') {
1000
+ // Static literal - return as-is without CEL conversion
1001
+ return {
1002
+ fieldName,
1003
+ originalExpression,
1004
+ celExpression: null,
1005
+ dependencies: [],
1006
+ requiresConversion: false,
1007
+ valid: true,
1008
+ errors: [],
1009
+ sourceMap: [],
1010
+ optionalityAnalysis: [],
1011
+ inferredType: typeof property.valueNode.value,
1012
+ confidence: 1.0
1013
+ };
1014
+ }
1015
+ // Check if this is the 'undefined' identifier (special case)
1016
+ if (property.valueNode.type === 'Identifier' && property.valueNode.name === 'undefined') {
1017
+ // undefined identifier - return as-is without CEL conversion
1018
+ return {
1019
+ fieldName,
1020
+ originalExpression,
1021
+ celExpression: null,
1022
+ dependencies: [],
1023
+ requiresConversion: false,
1024
+ valid: true,
1025
+ errors: [],
1026
+ sourceMap: [],
1027
+ optionalityAnalysis: [],
1028
+ inferredType: 'undefined',
1029
+ confidence: 1.0
1030
+ };
1031
+ }
1032
+ // Check if this is a boolean literal represented as UnaryExpression (!0 for true, !1 for false)
1033
+ if (property.valueNode.type === 'UnaryExpression' &&
1034
+ property.valueNode.operator === '!' &&
1035
+ property.valueNode.argument?.type === 'Literal' &&
1036
+ typeof property.valueNode.argument.value === 'number') {
1037
+ const _booleanValue = property.valueNode.argument.value === 0; // !0 = true, !1 = false
1038
+ return {
1039
+ fieldName,
1040
+ originalExpression,
1041
+ celExpression: null,
1042
+ dependencies: [],
1043
+ requiresConversion: false,
1044
+ valid: true,
1045
+ errors: [],
1046
+ sourceMap: [],
1047
+ optionalityAnalysis: [],
1048
+ inferredType: 'boolean',
1049
+ confidence: 1.0
1050
+ };
1051
+ }
1052
+ // Check if this is a static object expression
1053
+ if (property.valueNode.type === 'ObjectExpression') {
1054
+ // Try to evaluate the object as a static value
1055
+ const staticValue = this.evaluateStaticObjectExpression(property.valueNode);
1056
+ if (staticValue !== null) {
1057
+ return {
1058
+ fieldName,
1059
+ originalExpression,
1060
+ celExpression: null,
1061
+ dependencies: [],
1062
+ requiresConversion: false,
1063
+ valid: true,
1064
+ errors: [],
1065
+ sourceMap: [],
1066
+ optionalityAnalysis: [],
1067
+ inferredType: 'object',
1068
+ confidence: 1.0,
1069
+ staticValue // Store the evaluated static value
1070
+ };
1071
+ }
1072
+ else {
1073
+ // This is a mixed object (contains both static and dynamic values)
1074
+ // Recursively analyze each property
1075
+ const mixedObjectResult = this.analyzeMixedObjectExpression(property.valueNode, resources, originalSource, schemaProxy);
1076
+ if (mixedObjectResult.valid) {
1077
+ return {
1078
+ fieldName,
1079
+ originalExpression,
1080
+ celExpression: null,
1081
+ dependencies: mixedObjectResult.dependencies,
1082
+ requiresConversion: mixedObjectResult.requiresConversion,
1083
+ valid: true,
1084
+ errors: [],
1085
+ sourceMap: [],
1086
+ optionalityAnalysis: [],
1087
+ inferredType: 'object',
1088
+ confidence: 1.0,
1089
+ staticValue: mixedObjectResult.processedObject
1090
+ };
1091
+ }
1092
+ else {
1093
+ // Mixed object analysis failed, return error
1094
+ return {
1095
+ fieldName,
1096
+ originalExpression,
1097
+ celExpression: null,
1098
+ dependencies: [],
1099
+ requiresConversion: false,
1100
+ valid: false,
1101
+ errors: [new ConversionError(`Failed to analyze mixed object expression for field '${fieldName}'`, originalExpression, 'unknown')],
1102
+ sourceMap: [],
1103
+ optionalityAnalysis: [],
1104
+ inferredType: 'object',
1105
+ confidence: 0.0
1106
+ };
1107
+ }
1108
+ }
1109
+ }
1110
+ // Create analysis context
1111
+ const context = {
1112
+ type: 'status',
1113
+ availableReferences: resources,
1114
+ ...(schemaProxy && { schemaProxy }),
1115
+ factoryType: this.options.factoryType,
1116
+ ...(this.options.includeSourceMapping && { sourceMap: new SourceMapBuilder() }),
1117
+ dependencies: []
1118
+ };
1119
+ // Analyze the expression using the main analyzer
1120
+ const analysisResult = this.expressionAnalyzer.analyzeExpression(originalExpression, context);
1121
+ // Perform optionality analysis if enabled
1122
+ let optionalityAnalysis = [];
1123
+ if (this.options.performOptionalityAnalysis) {
1124
+ const optionalityContext = {
1125
+ ...context,
1126
+ hydrationStates: this.options.hydrationStates,
1127
+ conservativeNullSafety: this.options.conservativeNullSafety,
1128
+ useKroConditionals: true,
1129
+ generateHasChecks: true
1130
+ };
1131
+ optionalityAnalysis = this.optionalityHandler.analyzeOptionalityRequirements(originalExpression, optionalityContext);
1132
+ }
1133
+ return {
1134
+ fieldName,
1135
+ originalExpression,
1136
+ celExpression: analysisResult.celExpression,
1137
+ dependencies: analysisResult.dependencies,
1138
+ requiresConversion: analysisResult.requiresConversion,
1139
+ valid: analysisResult.valid,
1140
+ errors: analysisResult.errors,
1141
+ sourceMap: analysisResult.sourceMap,
1142
+ optionalityAnalysis,
1143
+ inferredType: analysisResult.inferredType ? String(analysisResult.inferredType) : undefined,
1144
+ confidence: this.calculateFieldConfidence(analysisResult, optionalityAnalysis)
1145
+ };
1146
+ }
1147
+ catch (error) {
1148
+ const fieldError = new ConversionError(`Failed to analyze field '${fieldName}': ${error instanceof Error ? error.message : String(error)}`, originalExpression, 'unknown');
1149
+ return {
1150
+ fieldName,
1151
+ originalExpression,
1152
+ celExpression: null,
1153
+ dependencies: [],
1154
+ requiresConversion: false,
1155
+ valid: false,
1156
+ errors: [fieldError],
1157
+ sourceMap: [],
1158
+ optionalityAnalysis: [],
1159
+ inferredType: undefined,
1160
+ confidence: 0
1161
+ };
1162
+ }
1163
+ }
1164
+ /**
1165
+ * Calculate confidence level for field analysis
1166
+ */
1167
+ calculateFieldConfidence(analysisResult, optionalityAnalysis) {
1168
+ let confidence = 0.8; // Base confidence
1169
+ if (analysisResult.valid) {
1170
+ confidence += 0.1;
1171
+ }
1172
+ if (analysisResult.errors.length === 0) {
1173
+ confidence += 0.1;
1174
+ }
1175
+ // Factor in optionality analysis confidence
1176
+ if (optionalityAnalysis.length > 0) {
1177
+ const avgOptionalityConfidence = optionalityAnalysis.reduce((sum, result) => sum + result.confidence, 0) / optionalityAnalysis.length;
1178
+ confidence = (confidence + avgOptionalityConfidence) / 2;
1179
+ }
1180
+ return Math.max(0, Math.min(1, confidence));
1181
+ }
1182
+ /**
1183
+ * Categorize dependencies into resource and schema references
1184
+ */
1185
+ categorizeDependencies(dependencies) {
1186
+ const resourceReferences = [];
1187
+ const schemaReferences = [];
1188
+ for (const dep of dependencies) {
1189
+ if (dep.resourceId === '__schema__') {
1190
+ schemaReferences.push(dep);
1191
+ }
1192
+ else {
1193
+ resourceReferences.push(dep);
1194
+ }
1195
+ }
1196
+ return { resourceReferences, schemaReferences };
1197
+ }
1198
+ }
1199
+ /**
1200
+ * Analyze status builder function for toResourceGraph integration with KubernetesRef detection
1201
+ *
1202
+ * This is the main integration point for toResourceGraph to analyze status builder functions
1203
+ * and detect KubernetesRef objects from the magic proxy system.
1204
+ */
1205
+ export function analyzeStatusBuilderForToResourceGraph(statusBuilder, resources, schemaProxy, factoryType = 'kro') {
1206
+ const options = {
1207
+ deepAnalysis: true,
1208
+ includeSourceMapping: true,
1209
+ validateReferences: true,
1210
+ performOptionalityAnalysis: true,
1211
+ factoryType,
1212
+ conservativeNullSafety: true
1213
+ };
1214
+ const analyzer = new StatusBuilderAnalyzer(undefined, options);
1215
+ const result = analyzer.analyzeStatusBuilder(statusBuilder, resources, schemaProxy);
1216
+ // Calculate hydration order based on dependencies
1217
+ const hydrationOrder = calculateStatusFieldHydrationOrder(result.fieldAnalysis);
1218
+ // Determine if any conversion is required
1219
+ const requiresConversion = Array.from(result.fieldAnalysis.values()).some(field => field.requiresConversion);
1220
+ return {
1221
+ statusMappings: result.statusMappings,
1222
+ dependencies: result.allDependencies,
1223
+ hydrationOrder,
1224
+ errors: result.errors,
1225
+ valid: result.valid,
1226
+ requiresConversion
1227
+ };
1228
+ }
1229
+ /**
1230
+ * Calculate hydration order for status fields based on their dependencies
1231
+ */
1232
+ function calculateStatusFieldHydrationOrder(fieldAnalysis) {
1233
+ const fieldDependencies = new Map();
1234
+ const allFields = Array.from(fieldAnalysis.keys());
1235
+ // Build field-to-field dependencies
1236
+ for (const [fieldName, analysis] of fieldAnalysis) {
1237
+ const fieldDeps = new Set();
1238
+ // For each KubernetesRef dependency, find other fields that might provide that data
1239
+ for (const dep of analysis.dependencies) {
1240
+ if (dep.resourceId !== '__schema__') {
1241
+ // Find fields that reference the same resource
1242
+ for (const [otherField, otherAnalysis] of fieldAnalysis) {
1243
+ if (otherField !== fieldName) {
1244
+ const hasMatchingResource = otherAnalysis.dependencies.some(otherDep => otherDep.resourceId === dep.resourceId);
1245
+ if (hasMatchingResource) {
1246
+ fieldDeps.add(otherField);
1247
+ }
1248
+ }
1249
+ }
1250
+ }
1251
+ }
1252
+ fieldDependencies.set(fieldName, fieldDeps);
1253
+ }
1254
+ // Perform topological sort
1255
+ const visited = new Set();
1256
+ const visiting = new Set();
1257
+ const result = [];
1258
+ const visit = (field) => {
1259
+ if (visiting.has(field)) {
1260
+ // Circular dependency - add to result anyway
1261
+ return;
1262
+ }
1263
+ if (visited.has(field)) {
1264
+ return;
1265
+ }
1266
+ visiting.add(field);
1267
+ const deps = fieldDependencies.get(field) || new Set();
1268
+ for (const dep of deps) {
1269
+ visit(dep);
1270
+ }
1271
+ visiting.delete(field);
1272
+ visited.add(field);
1273
+ result.push(field);
1274
+ };
1275
+ for (const field of allFields) {
1276
+ visit(field);
1277
+ }
1278
+ return result;
1279
+ }
1280
+ /**
1281
+ * Convenience function to analyze status builder functions
1282
+ */
1283
+ export function analyzeStatusBuilder(statusBuilder, resources, schemaProxy, options) {
1284
+ const analyzer = new StatusBuilderAnalyzer(undefined, options);
1285
+ return analyzer.analyzeStatusBuilder(statusBuilder, resources, schemaProxy);
1286
+ }
1287
+ /**
1288
+ * Convenience function to analyze return objects with magic proxy support
1289
+ */
1290
+ export function analyzeReturnObjectWithMagicProxy(returnObject, resources, schemaProxy, options) {
1291
+ const analyzer = new StatusBuilderAnalyzer(undefined, options);
1292
+ return analyzer.analyzeReturnObjectWithMagicProxy(returnObject, resources, schemaProxy);
1293
+ }
1294
+ /**
1295
+ * Convenience function to generate status context-specific CEL
1296
+ */
1297
+ export function generateStatusContextCel(kubernetesRef, context, options) {
1298
+ const analyzer = new StatusBuilderAnalyzer(undefined, options);
1299
+ return analyzer.generateStatusContextCel(kubernetesRef, context);
1300
+ }
1301
+ //# sourceMappingURL=status-builder-analyzer.js.map