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