typekro 0.2.1 → 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.
- package/README.md +4 -3
- package/dist/.tsbuildinfo +1 -1
- package/dist/core/composition/imperative.d.ts.map +1 -1
- package/dist/core/composition/imperative.js +15 -2
- package/dist/core/composition/imperative.js.map +1 -1
- package/dist/core/composition/typekro-runtime/typekro-runtime.d.ts.map +1 -1
- package/dist/core/composition/typekro-runtime/typekro-runtime.js +24 -25
- package/dist/core/composition/typekro-runtime/typekro-runtime.js.map +1 -1
- package/dist/core/dependencies/type-guards.d.ts.map +1 -1
- package/dist/core/dependencies/type-guards.js +7 -2
- package/dist/core/dependencies/type-guards.js.map +1 -1
- package/dist/core/deployment/engine.d.ts +0 -1
- package/dist/core/deployment/engine.d.ts.map +1 -1
- package/dist/core/deployment/engine.js +0 -1
- package/dist/core/deployment/engine.js.map +1 -1
- package/dist/core/errors.d.ts +85 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +135 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/expressions/analyzer.d.ts +584 -0
- package/dist/core/expressions/analyzer.d.ts.map +1 -0
- package/dist/core/expressions/analyzer.js +2956 -0
- package/dist/core/expressions/analyzer.js.map +1 -0
- package/dist/core/expressions/cache.d.ts +136 -0
- package/dist/core/expressions/cache.d.ts.map +1 -0
- package/dist/core/expressions/cache.js +347 -0
- package/dist/core/expressions/cache.js.map +1 -0
- package/dist/core/expressions/cel-conversion-engine.d.ts +126 -0
- package/dist/core/expressions/cel-conversion-engine.d.ts.map +1 -0
- package/dist/core/expressions/cel-conversion-engine.js +293 -0
- package/dist/core/expressions/cel-conversion-engine.js.map +1 -0
- package/dist/core/expressions/compile-time-validation.d.ts +270 -0
- package/dist/core/expressions/compile-time-validation.d.ts.map +1 -0
- package/dist/core/expressions/compile-time-validation.js +506 -0
- package/dist/core/expressions/compile-time-validation.js.map +1 -0
- package/dist/core/expressions/composition-integration.d.ts +315 -0
- package/dist/core/expressions/composition-integration.d.ts.map +1 -0
- package/dist/core/expressions/composition-integration.js +936 -0
- package/dist/core/expressions/composition-integration.js.map +1 -0
- package/dist/core/expressions/conditional-expression-processor.d.ts +154 -0
- package/dist/core/expressions/conditional-expression-processor.d.ts.map +1 -0
- package/dist/core/expressions/conditional-expression-processor.js +479 -0
- package/dist/core/expressions/conditional-expression-processor.js.map +1 -0
- package/dist/core/expressions/conditional-integration.d.ts +133 -0
- package/dist/core/expressions/conditional-integration.d.ts.map +1 -0
- package/dist/core/expressions/conditional-integration.js +293 -0
- package/dist/core/expressions/conditional-integration.js.map +1 -0
- package/dist/core/expressions/conditional-validation.d.ts +181 -0
- package/dist/core/expressions/conditional-validation.d.ts.map +1 -0
- package/dist/core/expressions/conditional-validation.js +460 -0
- package/dist/core/expressions/conditional-validation.js.map +1 -0
- package/dist/core/expressions/context-aware-generator.d.ts +127 -0
- package/dist/core/expressions/context-aware-generator.d.ts.map +1 -0
- package/dist/core/expressions/context-aware-generator.js +500 -0
- package/dist/core/expressions/context-aware-generator.js.map +1 -0
- package/dist/core/expressions/context-detector.d.ts +148 -0
- package/dist/core/expressions/context-detector.d.ts.map +1 -0
- package/dist/core/expressions/context-detector.js +546 -0
- package/dist/core/expressions/context-detector.js.map +1 -0
- package/dist/core/expressions/context-switcher.d.ts +185 -0
- package/dist/core/expressions/context-switcher.d.ts.map +1 -0
- package/dist/core/expressions/context-switcher.js +515 -0
- package/dist/core/expressions/context-switcher.js.map +1 -0
- package/dist/core/expressions/context-validator.d.ts +176 -0
- package/dist/core/expressions/context-validator.d.ts.map +1 -0
- package/dist/core/expressions/context-validator.js +452 -0
- package/dist/core/expressions/context-validator.js.map +1 -0
- package/dist/core/expressions/custom-context-manager.d.ts +194 -0
- package/dist/core/expressions/custom-context-manager.d.ts.map +1 -0
- package/dist/core/expressions/custom-context-manager.js +390 -0
- package/dist/core/expressions/custom-context-manager.js.map +1 -0
- package/dist/core/expressions/expression-proxy.d.ts +80 -0
- package/dist/core/expressions/expression-proxy.d.ts.map +1 -0
- package/dist/core/expressions/expression-proxy.js +227 -0
- package/dist/core/expressions/expression-proxy.js.map +1 -0
- package/dist/core/expressions/factory-integration.d.ts +132 -0
- package/dist/core/expressions/factory-integration.d.ts.map +1 -0
- package/dist/core/expressions/factory-integration.js +327 -0
- package/dist/core/expressions/factory-integration.js.map +1 -0
- package/dist/core/expressions/factory-pattern-handler.d.ts +88 -0
- package/dist/core/expressions/factory-pattern-handler.d.ts.map +1 -0
- package/dist/core/expressions/factory-pattern-handler.js +336 -0
- package/dist/core/expressions/factory-pattern-handler.js.map +1 -0
- package/dist/core/expressions/field-hydration-processor.d.ts +188 -0
- package/dist/core/expressions/field-hydration-processor.d.ts.map +1 -0
- package/dist/core/expressions/field-hydration-processor.js +562 -0
- package/dist/core/expressions/field-hydration-processor.js.map +1 -0
- package/dist/core/expressions/imperative-analyzer.d.ts +21 -0
- package/dist/core/expressions/imperative-analyzer.d.ts.map +1 -0
- package/dist/core/expressions/imperative-analyzer.js +343 -0
- package/dist/core/expressions/imperative-analyzer.js.map +1 -0
- package/dist/core/expressions/index.d.ts +54 -0
- package/dist/core/expressions/index.d.ts.map +1 -0
- package/dist/core/expressions/index.js +50 -0
- package/dist/core/expressions/index.js.map +1 -0
- package/dist/core/expressions/lazy-analysis.d.ts +1128 -0
- package/dist/core/expressions/lazy-analysis.d.ts.map +1 -0
- package/dist/core/expressions/lazy-analysis.js +2443 -0
- package/dist/core/expressions/lazy-analysis.js.map +1 -0
- package/dist/core/expressions/magic-assignable-analyzer.d.ts +123 -0
- package/dist/core/expressions/magic-assignable-analyzer.d.ts.map +1 -0
- package/dist/core/expressions/magic-assignable-analyzer.js +352 -0
- package/dist/core/expressions/magic-assignable-analyzer.js.map +1 -0
- package/dist/core/expressions/magic-proxy-analyzer.d.ts +206 -0
- package/dist/core/expressions/magic-proxy-analyzer.d.ts.map +1 -0
- package/dist/core/expressions/magic-proxy-analyzer.js +639 -0
- package/dist/core/expressions/magic-proxy-analyzer.js.map +1 -0
- package/dist/core/expressions/magic-proxy-detector.d.ts +154 -0
- package/dist/core/expressions/magic-proxy-detector.d.ts.map +1 -0
- package/dist/core/expressions/magic-proxy-detector.js +242 -0
- package/dist/core/expressions/magic-proxy-detector.js.map +1 -0
- package/dist/core/expressions/migration-helpers.d.ts +133 -0
- package/dist/core/expressions/migration-helpers.d.ts.map +1 -0
- package/dist/core/expressions/migration-helpers.js +443 -0
- package/dist/core/expressions/migration-helpers.js.map +1 -0
- package/dist/core/expressions/optionality-handler.d.ts +503 -0
- package/dist/core/expressions/optionality-handler.d.ts.map +1 -0
- package/dist/core/expressions/optionality-handler.js +1306 -0
- package/dist/core/expressions/optionality-handler.js.map +1 -0
- package/dist/core/expressions/readiness-integration.d.ts +119 -0
- package/dist/core/expressions/readiness-integration.d.ts.map +1 -0
- package/dist/core/expressions/readiness-integration.js +386 -0
- package/dist/core/expressions/readiness-integration.js.map +1 -0
- package/dist/core/expressions/resource-analyzer.d.ts +486 -0
- package/dist/core/expressions/resource-analyzer.d.ts.map +1 -0
- package/dist/core/expressions/resource-analyzer.js +1086 -0
- package/dist/core/expressions/resource-analyzer.js.map +1 -0
- package/dist/core/expressions/resource-validation.d.ts +187 -0
- package/dist/core/expressions/resource-validation.d.ts.map +1 -0
- package/dist/core/expressions/resource-validation.js +552 -0
- package/dist/core/expressions/resource-validation.js.map +1 -0
- package/dist/core/expressions/runtime-error-mapper.d.ts +138 -0
- package/dist/core/expressions/runtime-error-mapper.d.ts.map +1 -0
- package/dist/core/expressions/runtime-error-mapper.js +412 -0
- package/dist/core/expressions/runtime-error-mapper.js.map +1 -0
- package/dist/core/expressions/source-map.d.ts +168 -0
- package/dist/core/expressions/source-map.d.ts.map +1 -0
- package/dist/core/expressions/source-map.js +350 -0
- package/dist/core/expressions/source-map.js.map +1 -0
- package/dist/core/expressions/status-builder-analyzer.d.ts +353 -0
- package/dist/core/expressions/status-builder-analyzer.d.ts.map +1 -0
- package/dist/core/expressions/status-builder-analyzer.js +1301 -0
- package/dist/core/expressions/status-builder-analyzer.js.map +1 -0
- package/dist/core/expressions/type-inference.d.ts +184 -0
- package/dist/core/expressions/type-inference.d.ts.map +1 -0
- package/dist/core/expressions/type-inference.js +838 -0
- package/dist/core/expressions/type-inference.js.map +1 -0
- package/dist/core/expressions/type-safety.d.ts +203 -0
- package/dist/core/expressions/type-safety.d.ts.map +1 -0
- package/dist/core/expressions/type-safety.js +442 -0
- package/dist/core/expressions/type-safety.js.map +1 -0
- package/dist/core/expressions/types.d.ts +282 -0
- package/dist/core/expressions/types.d.ts.map +1 -0
- package/dist/core/expressions/types.js +8 -0
- package/dist/core/expressions/types.js.map +1 -0
- package/dist/core/kubernetes/client-provider.js +2 -2
- package/dist/core/kubernetes/client-provider.js.map +1 -1
- package/dist/core/serialization/core.d.ts.map +1 -1
- package/dist/core/serialization/core.js +573 -9
- package/dist/core/serialization/core.js.map +1 -1
- package/dist/core/types/deployment.d.ts +4 -0
- package/dist/core/types/deployment.d.ts.map +1 -1
- package/dist/core/types/deployment.js.map +1 -1
- package/dist/core/types/index.d.ts +1 -0
- package/dist/core/types/index.d.ts.map +1 -1
- package/dist/core/types/index.js.map +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +1 -1
- package/dist/core.js.map +1 -1
- package/dist/factories/helm/helm-release.d.ts.map +1 -1
- package/dist/factories/helm/helm-release.js +0 -5
- package/dist/factories/helm/helm-release.js.map +1 -1
- package/dist/factories/helm/types.d.ts +1 -1
- package/dist/factories/helm/types.d.ts.map +1 -1
- package/dist/factories/shared.d.ts.map +1 -1
- package/dist/factories/shared.js +21 -1
- package/dist/factories/shared.js.map +1 -1
- package/dist/factories/simple/index.d.ts +2 -2
- package/dist/factories/simple/index.d.ts.map +1 -1
- package/dist/factories/simple/workloads/deployment.d.ts +3 -3
- package/dist/factories/simple/workloads/deployment.d.ts.map +1 -1
- package/dist/factories/simple/workloads/deployment.js +37 -11
- package/dist/factories/simple/workloads/deployment.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/type-guards.d.ts +6 -0
- package/dist/utils/type-guards.d.ts.map +1 -1
- package/dist/utils/type-guards.js +25 -2
- package/dist/utils/type-guards.js.map +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,838 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type Inference for CEL Expressions
|
|
3
|
+
*
|
|
4
|
+
* This module provides type inference capabilities for CEL expressions
|
|
5
|
+
* generated from JavaScript expressions. It analyzes CEL expressions
|
|
6
|
+
* to determine their result types and validates type compatibility.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Type inference error
|
|
10
|
+
*/
|
|
11
|
+
export class TypeInferenceError extends Error {
|
|
12
|
+
celExpression;
|
|
13
|
+
location;
|
|
14
|
+
constructor(message, celExpression, location) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.celExpression = celExpression;
|
|
17
|
+
this.location = location;
|
|
18
|
+
this.name = 'TypeInferenceError';
|
|
19
|
+
}
|
|
20
|
+
static forUnknownFunction(celExpression, functionName, location) {
|
|
21
|
+
return new TypeInferenceError(`Unknown CEL function: ${functionName}`, celExpression, location);
|
|
22
|
+
}
|
|
23
|
+
static forIncompatibleOperands(celExpression, operator, leftType, rightType, location) {
|
|
24
|
+
return new TypeInferenceError(`Incompatible operands for operator '${operator}': ${leftType.typeName} and ${rightType.typeName}`, celExpression, location);
|
|
25
|
+
}
|
|
26
|
+
static forUnresolvableReference(celExpression, reference, location) {
|
|
27
|
+
return new TypeInferenceError(`Cannot resolve reference: ${reference}`, celExpression, location);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Type inference warning
|
|
32
|
+
*/
|
|
33
|
+
export class TypeInferenceWarning {
|
|
34
|
+
message;
|
|
35
|
+
celExpression;
|
|
36
|
+
location;
|
|
37
|
+
constructor(message, celExpression, location) {
|
|
38
|
+
this.message = message;
|
|
39
|
+
this.celExpression = celExpression;
|
|
40
|
+
this.location = location;
|
|
41
|
+
}
|
|
42
|
+
static forPotentialNullDereference(celExpression, reference, location) {
|
|
43
|
+
return new TypeInferenceWarning(`Potential null dereference: ${reference}`, celExpression, location);
|
|
44
|
+
}
|
|
45
|
+
static forImplicitTypeConversion(celExpression, fromType, toType, location) {
|
|
46
|
+
return new TypeInferenceWarning(`Implicit type conversion from ${fromType} to ${toType}`, celExpression, location);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* CEL type inference engine
|
|
51
|
+
*/
|
|
52
|
+
export class CelTypeInferenceEngine {
|
|
53
|
+
functionTypes = new Map();
|
|
54
|
+
operatorTypes = new Map();
|
|
55
|
+
constructor() {
|
|
56
|
+
this.initializeBuiltinTypes();
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Infer the type of a CEL expression
|
|
60
|
+
*/
|
|
61
|
+
inferType(celExpression, context) {
|
|
62
|
+
try {
|
|
63
|
+
const expression = celExpression.expression;
|
|
64
|
+
const result = this.analyzeExpression(expression, context);
|
|
65
|
+
return {
|
|
66
|
+
resultType: result.type,
|
|
67
|
+
success: true,
|
|
68
|
+
errors: result.errors,
|
|
69
|
+
warnings: result.warnings,
|
|
70
|
+
confidence: result.confidence,
|
|
71
|
+
metadata: result.metadata
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
resultType: { typeName: 'unknown', optional: false, nullable: false },
|
|
77
|
+
success: false,
|
|
78
|
+
errors: [new TypeInferenceError(`Type inference failed: ${error instanceof Error ? error.message : String(error)}`, celExpression.expression)],
|
|
79
|
+
warnings: [],
|
|
80
|
+
confidence: 0,
|
|
81
|
+
metadata: this.createEmptyMetadata()
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Infer types for multiple CEL expressions
|
|
87
|
+
*/
|
|
88
|
+
inferTypes(celExpressions, context) {
|
|
89
|
+
return celExpressions.map(expr => this.inferType(expr, context));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Validate type compatibility between expressions
|
|
93
|
+
*/
|
|
94
|
+
validateTypeCompatibility(sourceType, targetType) {
|
|
95
|
+
const errors = [];
|
|
96
|
+
const warnings = [];
|
|
97
|
+
// Check exact type match
|
|
98
|
+
if (sourceType.typeName === targetType.typeName) {
|
|
99
|
+
return {
|
|
100
|
+
valid: true,
|
|
101
|
+
resultType: targetType,
|
|
102
|
+
errors: [],
|
|
103
|
+
warnings: [],
|
|
104
|
+
suggestions: []
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
// Check assignability
|
|
108
|
+
if (this.isAssignable(sourceType, targetType)) {
|
|
109
|
+
if (this.requiresImplicitConversion(sourceType, targetType)) {
|
|
110
|
+
warnings.push(TypeInferenceWarning.forImplicitTypeConversion('', sourceType.typeName, targetType.typeName));
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
valid: true,
|
|
114
|
+
resultType: targetType,
|
|
115
|
+
errors: [],
|
|
116
|
+
warnings: warnings.map(w => ({ message: w.message, expression: w.celExpression })),
|
|
117
|
+
suggestions: []
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// Type mismatch
|
|
121
|
+
errors.push(TypeInferenceError.forIncompatibleOperands('', '=', sourceType, targetType));
|
|
122
|
+
return {
|
|
123
|
+
valid: false,
|
|
124
|
+
resultType: targetType,
|
|
125
|
+
errors: errors.map(e => ({
|
|
126
|
+
message: e.message,
|
|
127
|
+
expression: e.celExpression,
|
|
128
|
+
expectedType: targetType,
|
|
129
|
+
actualType: sourceType,
|
|
130
|
+
name: 'TypeValidationError'
|
|
131
|
+
})),
|
|
132
|
+
warnings: [],
|
|
133
|
+
suggestions: [`Convert ${sourceType.typeName} to ${targetType.typeName}`]
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Analyze a CEL expression and infer its type
|
|
138
|
+
*/
|
|
139
|
+
analyzeExpression(expression, context) {
|
|
140
|
+
const errors = [];
|
|
141
|
+
const warnings = [];
|
|
142
|
+
const metadata = this.createEmptyMetadata();
|
|
143
|
+
// First, extract all resource references from the expression
|
|
144
|
+
this.extractResourceReferences(expression, metadata);
|
|
145
|
+
// Parse the expression into tokens
|
|
146
|
+
const tokens = this.tokenizeExpression(expression);
|
|
147
|
+
// Analyze different expression patterns
|
|
148
|
+
if (this.isBinaryOperation(tokens)) {
|
|
149
|
+
return this.analyzeBinaryOperation(tokens, context, metadata);
|
|
150
|
+
}
|
|
151
|
+
if (this.isFunctionCall(tokens)) {
|
|
152
|
+
return this.analyzeFunctionCall(tokens, context, metadata);
|
|
153
|
+
}
|
|
154
|
+
if (this.isResourceReference(tokens)) {
|
|
155
|
+
return this.analyzeResourceReference(tokens, context, metadata);
|
|
156
|
+
}
|
|
157
|
+
if (this.isSchemaReference(tokens)) {
|
|
158
|
+
return this.analyzeSchemaReference(tokens, context, metadata);
|
|
159
|
+
}
|
|
160
|
+
if (this.isLiteral(tokens)) {
|
|
161
|
+
return this.analyzeLiteral(tokens, context, metadata);
|
|
162
|
+
}
|
|
163
|
+
if (this.isConditionalExpression(tokens)) {
|
|
164
|
+
return this.analyzeConditionalExpression(tokens, context, metadata);
|
|
165
|
+
}
|
|
166
|
+
// Default to unknown type
|
|
167
|
+
return {
|
|
168
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
169
|
+
errors,
|
|
170
|
+
warnings,
|
|
171
|
+
confidence: 0.1,
|
|
172
|
+
metadata
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Analyze binary operations (>, <, ==, !=, &&, ||, +, -, *, /)
|
|
177
|
+
*/
|
|
178
|
+
analyzeBinaryOperation(tokens, context, metadata) {
|
|
179
|
+
const errors = [];
|
|
180
|
+
const warnings = [];
|
|
181
|
+
// Find the operator
|
|
182
|
+
const operatorIndex = this.findMainOperator(tokens);
|
|
183
|
+
if (operatorIndex === -1) {
|
|
184
|
+
errors.push(TypeInferenceError.forUnknownFunction('', 'binary operator'));
|
|
185
|
+
return {
|
|
186
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
187
|
+
errors,
|
|
188
|
+
warnings,
|
|
189
|
+
confidence: 0,
|
|
190
|
+
metadata
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
const operator = tokens[operatorIndex];
|
|
194
|
+
if (!operator) {
|
|
195
|
+
errors.push(TypeInferenceError.forUnknownFunction('', 'unknown_operator'));
|
|
196
|
+
return {
|
|
197
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
198
|
+
errors,
|
|
199
|
+
warnings,
|
|
200
|
+
confidence: 0,
|
|
201
|
+
metadata
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
const leftTokens = tokens.slice(0, operatorIndex);
|
|
205
|
+
const rightTokens = tokens.slice(operatorIndex + 1);
|
|
206
|
+
// Analyze operands
|
|
207
|
+
const leftResult = this.analyzeExpression(leftTokens.join(' '), context);
|
|
208
|
+
const rightResult = this.analyzeExpression(rightTokens.join(' '), context);
|
|
209
|
+
// Determine result type based on operator
|
|
210
|
+
const operatorSignature = this.operatorTypes.get(operator);
|
|
211
|
+
if (!operatorSignature) {
|
|
212
|
+
errors.push(TypeInferenceError.forUnknownFunction('', operator));
|
|
213
|
+
return {
|
|
214
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
215
|
+
errors,
|
|
216
|
+
warnings,
|
|
217
|
+
confidence: 0,
|
|
218
|
+
metadata
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
// Validate operand types
|
|
222
|
+
const resultType = this.getOperatorResultType(operator, leftResult.type, rightResult.type);
|
|
223
|
+
if (!resultType) {
|
|
224
|
+
errors.push(TypeInferenceError.forIncompatibleOperands('', operator, leftResult.type, rightResult.type));
|
|
225
|
+
return {
|
|
226
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
227
|
+
errors,
|
|
228
|
+
warnings,
|
|
229
|
+
confidence: 0,
|
|
230
|
+
metadata
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
// Combine metadata
|
|
234
|
+
metadata.complexityScore += 1;
|
|
235
|
+
metadata.canReturnNull = leftResult.type.nullable || rightResult.type.nullable;
|
|
236
|
+
return {
|
|
237
|
+
type: resultType,
|
|
238
|
+
errors: [...errors, ...leftResult.errors, ...rightResult.errors],
|
|
239
|
+
warnings: [...warnings, ...leftResult.warnings, ...rightResult.warnings],
|
|
240
|
+
confidence: Math.min(leftResult.confidence, rightResult.confidence) * 0.9,
|
|
241
|
+
metadata
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Analyze function calls
|
|
246
|
+
*/
|
|
247
|
+
analyzeFunctionCall(tokens, _context, metadata) {
|
|
248
|
+
const errors = [];
|
|
249
|
+
const warnings = [];
|
|
250
|
+
// Extract function name - look for function call pattern
|
|
251
|
+
const expression = tokens.join(' ');
|
|
252
|
+
const functionMatch = expression.match(/(\w+)\s*\(/);
|
|
253
|
+
if (!functionMatch) {
|
|
254
|
+
errors.push(TypeInferenceError.forUnknownFunction('', 'unknown'));
|
|
255
|
+
return {
|
|
256
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
257
|
+
errors,
|
|
258
|
+
warnings,
|
|
259
|
+
confidence: 0,
|
|
260
|
+
metadata
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
const functionName = functionMatch[1];
|
|
264
|
+
if (!functionName) {
|
|
265
|
+
errors.push(TypeInferenceError.forUnknownFunction('', 'unknown_function'));
|
|
266
|
+
return {
|
|
267
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
268
|
+
errors,
|
|
269
|
+
warnings,
|
|
270
|
+
confidence: 0,
|
|
271
|
+
metadata
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const functionSignature = this.functionTypes.get(functionName);
|
|
275
|
+
if (!functionSignature) {
|
|
276
|
+
errors.push(TypeInferenceError.forUnknownFunction('', functionName));
|
|
277
|
+
return {
|
|
278
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
279
|
+
errors,
|
|
280
|
+
warnings,
|
|
281
|
+
confidence: 0,
|
|
282
|
+
metadata
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
metadata.functionsUsed.push(functionName);
|
|
286
|
+
metadata.complexityScore += 2;
|
|
287
|
+
return {
|
|
288
|
+
type: functionSignature.returnType,
|
|
289
|
+
errors,
|
|
290
|
+
warnings,
|
|
291
|
+
confidence: 0.8,
|
|
292
|
+
metadata
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Analyze resource references (resources.name.field)
|
|
297
|
+
*/
|
|
298
|
+
analyzeResourceReference(tokens, context, metadata) {
|
|
299
|
+
const errors = [];
|
|
300
|
+
const warnings = [];
|
|
301
|
+
const reference = tokens.join('').replace(/\s+/g, '');
|
|
302
|
+
metadata.resourceReferences.push(reference);
|
|
303
|
+
// Extract resource ID and field path
|
|
304
|
+
const match = reference.match(/^resources\.([^.]+)\.(.+)$/);
|
|
305
|
+
if (!match) {
|
|
306
|
+
errors.push(TypeInferenceError.forUnresolvableReference('', reference));
|
|
307
|
+
return {
|
|
308
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
309
|
+
errors,
|
|
310
|
+
warnings,
|
|
311
|
+
confidence: 0,
|
|
312
|
+
metadata
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const [, resourceId, fieldPath] = match;
|
|
316
|
+
if (!resourceId || !fieldPath) {
|
|
317
|
+
errors.push(TypeInferenceError.forUnresolvableReference('', reference));
|
|
318
|
+
return {
|
|
319
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
320
|
+
errors,
|
|
321
|
+
warnings,
|
|
322
|
+
confidence: 0,
|
|
323
|
+
metadata
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
// Look up resource type
|
|
327
|
+
const resource = context.availableResources[resourceId];
|
|
328
|
+
if (!resource) {
|
|
329
|
+
errors.push(TypeInferenceError.forUnresolvableReference('', reference));
|
|
330
|
+
return {
|
|
331
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
332
|
+
errors,
|
|
333
|
+
warnings,
|
|
334
|
+
confidence: 0,
|
|
335
|
+
metadata
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
// Infer field type
|
|
339
|
+
const fieldType = this.inferResourceFieldType(resource, fieldPath);
|
|
340
|
+
// Check for optional chaining
|
|
341
|
+
if (reference.includes('?')) {
|
|
342
|
+
metadata.usesOptionalChaining = true;
|
|
343
|
+
metadata.canReturnNull = true;
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
type: fieldType,
|
|
347
|
+
errors,
|
|
348
|
+
warnings,
|
|
349
|
+
confidence: 0.9,
|
|
350
|
+
metadata
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Analyze schema references (schema.spec.field)
|
|
355
|
+
*/
|
|
356
|
+
analyzeSchemaReference(tokens, context, metadata) {
|
|
357
|
+
const errors = [];
|
|
358
|
+
const warnings = [];
|
|
359
|
+
const reference = tokens.join('');
|
|
360
|
+
metadata.schemaReferences.push(reference);
|
|
361
|
+
// Extract field path
|
|
362
|
+
const match = reference.match(/^schema\.(.+)$/);
|
|
363
|
+
if (!match) {
|
|
364
|
+
errors.push(TypeInferenceError.forUnresolvableReference('', reference));
|
|
365
|
+
return {
|
|
366
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
367
|
+
errors,
|
|
368
|
+
warnings,
|
|
369
|
+
confidence: 0,
|
|
370
|
+
metadata
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
const [, fieldPath] = match;
|
|
374
|
+
if (!fieldPath) {
|
|
375
|
+
errors.push(TypeInferenceError.forUnresolvableReference('', reference));
|
|
376
|
+
return {
|
|
377
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
378
|
+
errors,
|
|
379
|
+
warnings,
|
|
380
|
+
confidence: 0,
|
|
381
|
+
metadata
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
// Infer schema field type
|
|
385
|
+
const fieldType = this.inferSchemaFieldType(context.schemaProxy, fieldPath);
|
|
386
|
+
return {
|
|
387
|
+
type: fieldType,
|
|
388
|
+
errors,
|
|
389
|
+
warnings,
|
|
390
|
+
confidence: 0.9,
|
|
391
|
+
metadata
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* Analyze literal values
|
|
396
|
+
*/
|
|
397
|
+
analyzeLiteral(tokens, _context, metadata) {
|
|
398
|
+
const literal = tokens.join(' ');
|
|
399
|
+
// String literals
|
|
400
|
+
if (literal.match(/^["'].*["']$/)) {
|
|
401
|
+
return {
|
|
402
|
+
type: { typeName: 'string', optional: false, nullable: false },
|
|
403
|
+
errors: [],
|
|
404
|
+
warnings: [],
|
|
405
|
+
confidence: 1.0,
|
|
406
|
+
metadata
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
// Number literals
|
|
410
|
+
if (literal.match(/^\d+(\.\d+)?$/)) {
|
|
411
|
+
return {
|
|
412
|
+
type: { typeName: 'number', optional: false, nullable: false },
|
|
413
|
+
errors: [],
|
|
414
|
+
warnings: [],
|
|
415
|
+
confidence: 1.0,
|
|
416
|
+
metadata
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
// Boolean literals
|
|
420
|
+
if (literal === 'true' || literal === 'false') {
|
|
421
|
+
return {
|
|
422
|
+
type: { typeName: 'boolean', optional: false, nullable: false },
|
|
423
|
+
errors: [],
|
|
424
|
+
warnings: [],
|
|
425
|
+
confidence: 1.0,
|
|
426
|
+
metadata
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
// Null literal
|
|
430
|
+
if (literal === 'null') {
|
|
431
|
+
return {
|
|
432
|
+
type: { typeName: 'null', optional: false, nullable: true },
|
|
433
|
+
errors: [],
|
|
434
|
+
warnings: [],
|
|
435
|
+
confidence: 1.0,
|
|
436
|
+
metadata
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
// Unknown literal
|
|
440
|
+
return {
|
|
441
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
442
|
+
errors: [],
|
|
443
|
+
warnings: [],
|
|
444
|
+
confidence: 0.5,
|
|
445
|
+
metadata
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Analyze conditional expressions (condition ? true : false)
|
|
450
|
+
*/
|
|
451
|
+
analyzeConditionalExpression(tokens, context, metadata) {
|
|
452
|
+
const errors = [];
|
|
453
|
+
const warnings = [];
|
|
454
|
+
// Find ? and : operators
|
|
455
|
+
const questionIndex = tokens.indexOf('?');
|
|
456
|
+
const colonIndex = tokens.indexOf(':');
|
|
457
|
+
if (questionIndex === -1 || colonIndex === -1) {
|
|
458
|
+
errors.push(TypeInferenceError.forUnknownFunction('', 'conditional'));
|
|
459
|
+
return {
|
|
460
|
+
type: { typeName: 'unknown', optional: false, nullable: false },
|
|
461
|
+
errors,
|
|
462
|
+
warnings,
|
|
463
|
+
confidence: 0,
|
|
464
|
+
metadata
|
|
465
|
+
};
|
|
466
|
+
}
|
|
467
|
+
const conditionTokens = tokens.slice(0, questionIndex);
|
|
468
|
+
const trueTokens = tokens.slice(questionIndex + 1, colonIndex);
|
|
469
|
+
const falseTokens = tokens.slice(colonIndex + 1);
|
|
470
|
+
// Analyze each part
|
|
471
|
+
const conditionResult = this.analyzeExpression(conditionTokens.join(' '), context);
|
|
472
|
+
const trueResult = this.analyzeExpression(trueTokens.join(' '), context);
|
|
473
|
+
const falseResult = this.analyzeExpression(falseTokens.join(' '), context);
|
|
474
|
+
// Result type is the union of true and false branches
|
|
475
|
+
const resultType = this.unifyTypes(trueResult.type, falseResult.type);
|
|
476
|
+
metadata.complexityScore += 2;
|
|
477
|
+
metadata.canReturnNull = trueResult.type.nullable || falseResult.type.nullable;
|
|
478
|
+
return {
|
|
479
|
+
type: resultType,
|
|
480
|
+
errors: [...errors, ...conditionResult.errors, ...trueResult.errors, ...falseResult.errors],
|
|
481
|
+
warnings: [...warnings, ...conditionResult.warnings, ...trueResult.warnings, ...falseResult.warnings],
|
|
482
|
+
confidence: Math.min(conditionResult.confidence, trueResult.confidence, falseResult.confidence) * 0.9,
|
|
483
|
+
metadata
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Initialize builtin CEL function and operator types
|
|
488
|
+
*/
|
|
489
|
+
initializeBuiltinTypes() {
|
|
490
|
+
// Comparison operators
|
|
491
|
+
this.operatorTypes.set('>', {
|
|
492
|
+
leftType: { typeName: 'number', optional: false, nullable: false },
|
|
493
|
+
rightType: { typeName: 'number', optional: false, nullable: false },
|
|
494
|
+
returnType: { typeName: 'boolean', optional: false, nullable: false }
|
|
495
|
+
});
|
|
496
|
+
this.operatorTypes.set('<', {
|
|
497
|
+
leftType: { typeName: 'number', optional: false, nullable: false },
|
|
498
|
+
rightType: { typeName: 'number', optional: false, nullable: false },
|
|
499
|
+
returnType: { typeName: 'boolean', optional: false, nullable: false }
|
|
500
|
+
});
|
|
501
|
+
this.operatorTypes.set('==', {
|
|
502
|
+
leftType: { typeName: 'any', optional: false, nullable: false },
|
|
503
|
+
rightType: { typeName: 'any', optional: false, nullable: false },
|
|
504
|
+
returnType: { typeName: 'boolean', optional: false, nullable: false }
|
|
505
|
+
});
|
|
506
|
+
this.operatorTypes.set('!=', {
|
|
507
|
+
leftType: { typeName: 'any', optional: false, nullable: false },
|
|
508
|
+
rightType: { typeName: 'any', optional: false, nullable: false },
|
|
509
|
+
returnType: { typeName: 'boolean', optional: false, nullable: false }
|
|
510
|
+
});
|
|
511
|
+
// Logical operators
|
|
512
|
+
this.operatorTypes.set('&&', {
|
|
513
|
+
leftType: { typeName: 'boolean', optional: false, nullable: false },
|
|
514
|
+
rightType: { typeName: 'boolean', optional: false, nullable: false },
|
|
515
|
+
returnType: { typeName: 'boolean', optional: false, nullable: false }
|
|
516
|
+
});
|
|
517
|
+
this.operatorTypes.set('||', {
|
|
518
|
+
leftType: { typeName: 'boolean', optional: false, nullable: false },
|
|
519
|
+
rightType: { typeName: 'boolean', optional: false, nullable: false },
|
|
520
|
+
returnType: { typeName: 'boolean', optional: false, nullable: false }
|
|
521
|
+
});
|
|
522
|
+
// Arithmetic operators
|
|
523
|
+
this.operatorTypes.set('+', {
|
|
524
|
+
leftType: { typeName: 'number', optional: false, nullable: false },
|
|
525
|
+
rightType: { typeName: 'number', optional: false, nullable: false },
|
|
526
|
+
returnType: { typeName: 'number', optional: false, nullable: false }
|
|
527
|
+
});
|
|
528
|
+
// CEL functions
|
|
529
|
+
this.functionTypes.set('has', {
|
|
530
|
+
parameters: [{ typeName: 'string', optional: false, nullable: false }],
|
|
531
|
+
returnType: { typeName: 'boolean', optional: false, nullable: false }
|
|
532
|
+
});
|
|
533
|
+
this.functionTypes.set('size', {
|
|
534
|
+
parameters: [{ typeName: 'any', optional: false, nullable: false }],
|
|
535
|
+
returnType: { typeName: 'number', optional: false, nullable: false }
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Utility methods
|
|
540
|
+
*/
|
|
541
|
+
tokenizeExpression(expression) {
|
|
542
|
+
// Simple tokenization - would need more sophisticated parsing for production
|
|
543
|
+
return expression.split(/\s+/).filter(token => token.length > 0);
|
|
544
|
+
}
|
|
545
|
+
isBinaryOperation(tokens) {
|
|
546
|
+
return tokens.some(token => ['>', '<', '>=', '<=', '==', '!=', '&&', '||', '+', '-', '*', '/'].includes(token));
|
|
547
|
+
}
|
|
548
|
+
isFunctionCall(tokens) {
|
|
549
|
+
const expression = tokens.join(' ');
|
|
550
|
+
return expression.includes('(') && expression.includes(')');
|
|
551
|
+
}
|
|
552
|
+
isResourceReference(tokens) {
|
|
553
|
+
const expression = tokens.join('').replace(/\s+/g, '');
|
|
554
|
+
return expression.startsWith('resources.');
|
|
555
|
+
}
|
|
556
|
+
isSchemaReference(tokens) {
|
|
557
|
+
return tokens.join('').startsWith('schema.');
|
|
558
|
+
}
|
|
559
|
+
isLiteral(tokens) {
|
|
560
|
+
const joined = tokens.join(' ');
|
|
561
|
+
return joined.match(/^(["'].*["']|\d+(\.\d+)?|true|false|null)$/) !== null;
|
|
562
|
+
}
|
|
563
|
+
isConditionalExpression(tokens) {
|
|
564
|
+
return tokens.includes('?') && tokens.includes(':');
|
|
565
|
+
}
|
|
566
|
+
findMainOperator(tokens) {
|
|
567
|
+
// Find the main operator (simplified - would need proper precedence parsing)
|
|
568
|
+
const operators = ['||', '&&', '==', '!=', '>', '<', '>=', '<=', '+', '-', '*', '/'];
|
|
569
|
+
for (const op of operators) {
|
|
570
|
+
const index = tokens.indexOf(op);
|
|
571
|
+
if (index !== -1)
|
|
572
|
+
return index;
|
|
573
|
+
}
|
|
574
|
+
return -1;
|
|
575
|
+
}
|
|
576
|
+
getOperatorResultType(operator, _leftType, _rightType) {
|
|
577
|
+
const signature = this.operatorTypes.get(operator);
|
|
578
|
+
if (!signature)
|
|
579
|
+
return null;
|
|
580
|
+
// Simplified type checking
|
|
581
|
+
return signature.returnType;
|
|
582
|
+
}
|
|
583
|
+
isAssignable(sourceType, targetType) {
|
|
584
|
+
if (sourceType.typeName === targetType.typeName)
|
|
585
|
+
return true;
|
|
586
|
+
if (targetType.typeName === 'any')
|
|
587
|
+
return true;
|
|
588
|
+
if (sourceType.typeName === 'null' && targetType.nullable)
|
|
589
|
+
return true;
|
|
590
|
+
if (sourceType.typeName === 'undefined' && targetType.optional)
|
|
591
|
+
return true;
|
|
592
|
+
return false;
|
|
593
|
+
}
|
|
594
|
+
requiresImplicitConversion(sourceType, targetType) {
|
|
595
|
+
return sourceType.typeName !== targetType.typeName &&
|
|
596
|
+
targetType.typeName !== 'any';
|
|
597
|
+
}
|
|
598
|
+
inferResourceFieldType(resource, fieldPath) {
|
|
599
|
+
try {
|
|
600
|
+
const parts = fieldPath.split('.');
|
|
601
|
+
// Handle common Kubernetes resource field patterns
|
|
602
|
+
if (parts[0] === 'metadata') {
|
|
603
|
+
return this.getMetadataFieldType(parts.slice(1));
|
|
604
|
+
}
|
|
605
|
+
if (parts[0] === 'spec') {
|
|
606
|
+
return this.getSpecFieldType(resource, parts.slice(1));
|
|
607
|
+
}
|
|
608
|
+
if (parts[0] === 'status') {
|
|
609
|
+
return this.getStatusFieldType(resource, parts.slice(1));
|
|
610
|
+
}
|
|
611
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
612
|
+
}
|
|
613
|
+
catch (_error) {
|
|
614
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
getMetadataFieldType(fieldParts) {
|
|
618
|
+
const fieldName = fieldParts[0];
|
|
619
|
+
if (!fieldName) {
|
|
620
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
621
|
+
}
|
|
622
|
+
// Common metadata fields
|
|
623
|
+
const metadataTypes = {
|
|
624
|
+
'name': { typeName: 'string', optional: false, nullable: false },
|
|
625
|
+
'namespace': { typeName: 'string', optional: true, nullable: false },
|
|
626
|
+
'labels': { typeName: 'Record<string, string>', optional: true, nullable: false },
|
|
627
|
+
'annotations': { typeName: 'Record<string, string>', optional: true, nullable: false },
|
|
628
|
+
'uid': { typeName: 'string', optional: true, nullable: false },
|
|
629
|
+
'resourceVersion': { typeName: 'string', optional: true, nullable: false },
|
|
630
|
+
'generation': { typeName: 'number', optional: true, nullable: false },
|
|
631
|
+
'creationTimestamp': { typeName: 'string', optional: true, nullable: false }
|
|
632
|
+
};
|
|
633
|
+
if (fieldName in metadataTypes) {
|
|
634
|
+
const baseType = metadataTypes[fieldName];
|
|
635
|
+
if (!baseType) {
|
|
636
|
+
return { typeName: 'string', optional: true, nullable: false };
|
|
637
|
+
}
|
|
638
|
+
// Handle nested access (e.g., labels.app)
|
|
639
|
+
if (fieldParts.length > 1) {
|
|
640
|
+
if (baseType.typeName.startsWith('Record<')) {
|
|
641
|
+
return { typeName: 'string', optional: true, nullable: false };
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
return baseType;
|
|
645
|
+
}
|
|
646
|
+
return { typeName: 'string', optional: true, nullable: false };
|
|
647
|
+
}
|
|
648
|
+
getSpecFieldType(resource, fieldParts) {
|
|
649
|
+
const resourceKind = resource.constructor.name;
|
|
650
|
+
const fieldName = fieldParts[0];
|
|
651
|
+
if (!fieldName) {
|
|
652
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
653
|
+
}
|
|
654
|
+
// Common spec fields by resource type
|
|
655
|
+
const specFieldTypes = {
|
|
656
|
+
'Deployment': {
|
|
657
|
+
'replicas': { typeName: 'number', optional: true, nullable: false },
|
|
658
|
+
'selector': { typeName: 'object', optional: false, nullable: false },
|
|
659
|
+
'template': { typeName: 'object', optional: false, nullable: false },
|
|
660
|
+
'strategy': { typeName: 'object', optional: true, nullable: false }
|
|
661
|
+
},
|
|
662
|
+
'Service': {
|
|
663
|
+
'type': { typeName: 'string', optional: true, nullable: false },
|
|
664
|
+
'ports': { typeName: 'array', optional: false, nullable: false },
|
|
665
|
+
'selector': { typeName: 'Record<string, string>', optional: true, nullable: false },
|
|
666
|
+
'clusterIP': { typeName: 'string', optional: true, nullable: false }
|
|
667
|
+
},
|
|
668
|
+
'ConfigMap': {
|
|
669
|
+
'data': { typeName: 'Record<string, string>', optional: true, nullable: false },
|
|
670
|
+
'binaryData': { typeName: 'Record<string, string>', optional: true, nullable: false }
|
|
671
|
+
}
|
|
672
|
+
};
|
|
673
|
+
const resourceFields = specFieldTypes[resourceKind];
|
|
674
|
+
if (resourceFields && fieldName in resourceFields) {
|
|
675
|
+
const baseType = resourceFields[fieldName];
|
|
676
|
+
// Handle nested access
|
|
677
|
+
if (fieldParts.length > 1 && baseType) {
|
|
678
|
+
if (baseType.typeName.startsWith('Record<')) {
|
|
679
|
+
return { typeName: 'string', optional: true, nullable: false };
|
|
680
|
+
}
|
|
681
|
+
if (baseType.typeName === 'array') {
|
|
682
|
+
return { typeName: 'object', optional: true, nullable: false };
|
|
683
|
+
}
|
|
684
|
+
if (baseType.typeName === 'object') {
|
|
685
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
return baseType || { typeName: 'unknown', optional: true, nullable: false };
|
|
689
|
+
}
|
|
690
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
691
|
+
}
|
|
692
|
+
getStatusFieldType(resource, fieldParts) {
|
|
693
|
+
const resourceKind = resource.constructor.name;
|
|
694
|
+
const fieldName = fieldParts[0];
|
|
695
|
+
if (!fieldName) {
|
|
696
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
697
|
+
}
|
|
698
|
+
// Common status fields by resource type
|
|
699
|
+
const statusFieldTypes = {
|
|
700
|
+
'Deployment': {
|
|
701
|
+
'replicas': { typeName: 'number', optional: true, nullable: false },
|
|
702
|
+
'readyReplicas': { typeName: 'number', optional: true, nullable: false },
|
|
703
|
+
'availableReplicas': { typeName: 'number', optional: true, nullable: false },
|
|
704
|
+
'unavailableReplicas': { typeName: 'number', optional: true, nullable: false },
|
|
705
|
+
'updatedReplicas': { typeName: 'number', optional: true, nullable: false },
|
|
706
|
+
'conditions': { typeName: 'array', optional: true, nullable: false },
|
|
707
|
+
'observedGeneration': { typeName: 'number', optional: true, nullable: false }
|
|
708
|
+
},
|
|
709
|
+
'Service': {
|
|
710
|
+
'loadBalancer': { typeName: 'object', optional: true, nullable: false },
|
|
711
|
+
'conditions': { typeName: 'array', optional: true, nullable: false }
|
|
712
|
+
},
|
|
713
|
+
'Pod': {
|
|
714
|
+
'phase': { typeName: 'string', optional: true, nullable: false },
|
|
715
|
+
'conditions': { typeName: 'array', optional: true, nullable: false },
|
|
716
|
+
'hostIP': { typeName: 'string', optional: true, nullable: false },
|
|
717
|
+
'podIP': { typeName: 'string', optional: true, nullable: false },
|
|
718
|
+
'startTime': { typeName: 'string', optional: true, nullable: false },
|
|
719
|
+
'containerStatuses': { typeName: 'array', optional: true, nullable: false }
|
|
720
|
+
}
|
|
721
|
+
};
|
|
722
|
+
const resourceFields = statusFieldTypes[resourceKind];
|
|
723
|
+
if (resourceFields && fieldName in resourceFields) {
|
|
724
|
+
const baseType = resourceFields[fieldName];
|
|
725
|
+
// Handle nested access
|
|
726
|
+
if (fieldParts.length > 1 && baseType) {
|
|
727
|
+
if (baseType.typeName === 'object') {
|
|
728
|
+
// Handle specific nested objects
|
|
729
|
+
if (fieldName === 'loadBalancer' && fieldParts[1] === 'ingress') {
|
|
730
|
+
return { typeName: 'array', optional: true, nullable: false };
|
|
731
|
+
}
|
|
732
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
733
|
+
}
|
|
734
|
+
if (baseType.typeName === 'array') {
|
|
735
|
+
// Array access like conditions[0] or length
|
|
736
|
+
if (fieldParts[1] === 'length') {
|
|
737
|
+
return { typeName: 'number', optional: false, nullable: false };
|
|
738
|
+
}
|
|
739
|
+
return { typeName: 'object', optional: true, nullable: false };
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
return baseType || { typeName: 'unknown', optional: true, nullable: true };
|
|
743
|
+
}
|
|
744
|
+
// Status fields are generally optional and may be null during resource creation
|
|
745
|
+
return { typeName: 'unknown', optional: true, nullable: true };
|
|
746
|
+
}
|
|
747
|
+
inferSchemaFieldType(schemaProxy, fieldPath) {
|
|
748
|
+
if (!schemaProxy) {
|
|
749
|
+
return { typeName: 'unknown', optional: false, nullable: false };
|
|
750
|
+
}
|
|
751
|
+
try {
|
|
752
|
+
// Extract the field from the schema proxy
|
|
753
|
+
const parts = fieldPath.split('.');
|
|
754
|
+
let current = schemaProxy;
|
|
755
|
+
for (const part of parts) {
|
|
756
|
+
if (current && typeof current === 'object' && part in current) {
|
|
757
|
+
current = current[part];
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
// Infer type from the schema field
|
|
764
|
+
if (current !== undefined) {
|
|
765
|
+
return this.inferTypeFromValue(current);
|
|
766
|
+
}
|
|
767
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
768
|
+
}
|
|
769
|
+
catch (_error) {
|
|
770
|
+
return { typeName: 'unknown', optional: true, nullable: false };
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
inferTypeFromValue(value) {
|
|
774
|
+
if (value === null) {
|
|
775
|
+
return { typeName: 'null', optional: false, nullable: true };
|
|
776
|
+
}
|
|
777
|
+
if (value === undefined) {
|
|
778
|
+
return { typeName: 'undefined', optional: true, nullable: false };
|
|
779
|
+
}
|
|
780
|
+
const type = typeof value;
|
|
781
|
+
switch (type) {
|
|
782
|
+
case 'string':
|
|
783
|
+
return { typeName: 'string', optional: false, nullable: false };
|
|
784
|
+
case 'number':
|
|
785
|
+
return { typeName: 'number', optional: false, nullable: false };
|
|
786
|
+
case 'boolean':
|
|
787
|
+
return { typeName: 'boolean', optional: false, nullable: false };
|
|
788
|
+
case 'object':
|
|
789
|
+
if (Array.isArray(value)) {
|
|
790
|
+
return { typeName: 'array', optional: false, nullable: false };
|
|
791
|
+
}
|
|
792
|
+
return { typeName: 'object', optional: false, nullable: false };
|
|
793
|
+
default:
|
|
794
|
+
return { typeName: 'unknown', optional: false, nullable: false };
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
unifyTypes(type1, type2) {
|
|
798
|
+
if (type1.typeName === type2.typeName)
|
|
799
|
+
return type1;
|
|
800
|
+
// Create union type
|
|
801
|
+
return {
|
|
802
|
+
typeName: `${type1.typeName} | ${type2.typeName}`,
|
|
803
|
+
optional: type1.optional || type2.optional,
|
|
804
|
+
nullable: type1.nullable || type2.nullable,
|
|
805
|
+
unionTypes: [type1, type2]
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
createEmptyMetadata() {
|
|
809
|
+
return {
|
|
810
|
+
functionsUsed: [],
|
|
811
|
+
resourceReferences: [],
|
|
812
|
+
schemaReferences: [],
|
|
813
|
+
usesOptionalChaining: false,
|
|
814
|
+
canReturnNull: false,
|
|
815
|
+
complexityScore: 0
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
/**
|
|
819
|
+
* Extract resource references from the expression
|
|
820
|
+
*/
|
|
821
|
+
extractResourceReferences(expression, metadata) {
|
|
822
|
+
// Find all resource references (resources.name.field)
|
|
823
|
+
const resourceMatches = expression.match(/resources\.\w+\.[a-zA-Z0-9_.]+/g);
|
|
824
|
+
if (resourceMatches) {
|
|
825
|
+
metadata.resourceReferences.push(...resourceMatches);
|
|
826
|
+
}
|
|
827
|
+
// Find all schema references (schema.field)
|
|
828
|
+
const schemaMatches = expression.match(/schema\.[a-zA-Z0-9_.]+/g);
|
|
829
|
+
if (schemaMatches) {
|
|
830
|
+
metadata.schemaReferences.push(...schemaMatches);
|
|
831
|
+
}
|
|
832
|
+
// Check for optional chaining
|
|
833
|
+
if (expression.includes('?.')) {
|
|
834
|
+
metadata.usesOptionalChaining = true;
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
//# sourceMappingURL=type-inference.js.map
|