typekro 0.8.0 → 0.10.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/dist/.tsbuildinfo +1 -1
- package/dist/alchemy/deployers.d.ts +16 -1
- package/dist/alchemy/deployers.d.ts.map +1 -1
- package/dist/alchemy/deployers.js +131 -18
- package/dist/alchemy/deployers.js.map +1 -1
- package/dist/alchemy/deployment.d.ts +1 -1
- package/dist/alchemy/deployment.d.ts.map +1 -1
- package/dist/alchemy/deployment.js +1 -1
- package/dist/alchemy/deployment.js.map +1 -1
- package/dist/alchemy/kro-delete.d.ts +66 -0
- package/dist/alchemy/kro-delete.d.ts.map +1 -0
- package/dist/alchemy/kro-delete.js +183 -0
- package/dist/alchemy/kro-delete.js.map +1 -0
- package/dist/alchemy/resource-registration.d.ts +16 -0
- package/dist/alchemy/resource-registration.d.ts.map +1 -1
- package/dist/alchemy/resource-registration.js +138 -24
- package/dist/alchemy/resource-registration.js.map +1 -1
- package/dist/alchemy/types.d.ts +8 -4
- package/dist/alchemy/types.d.ts.map +1 -1
- package/dist/aspects.d.ts +3 -0
- package/dist/aspects.d.ts.map +1 -0
- package/dist/aspects.js +2 -0
- package/dist/aspects.js.map +1 -0
- package/dist/compositions/typekro-runtime/typekro-runtime.d.ts +1 -1
- package/dist/compositions/typekro-runtime/typekro-runtime.d.ts.map +1 -1
- package/dist/compositions/typekro-runtime/typekro-runtime.js +27 -9
- package/dist/compositions/typekro-runtime/typekro-runtime.js.map +1 -1
- package/dist/core/aspects/apply.d.ts +30 -0
- package/dist/core/aspects/apply.d.ts.map +1 -0
- package/dist/core/aspects/apply.js +369 -0
- package/dist/core/aspects/apply.js.map +1 -0
- package/dist/core/aspects/dev-aspects.d.ts +14 -0
- package/dist/core/aspects/dev-aspects.d.ts.map +1 -0
- package/dist/core/aspects/dev-aspects.js +70 -0
- package/dist/core/aspects/dev-aspects.js.map +1 -0
- package/dist/core/aspects/index.d.ts +31 -0
- package/dist/core/aspects/index.d.ts.map +1 -0
- package/dist/core/aspects/index.js +30 -0
- package/dist/core/aspects/index.js.map +1 -0
- package/dist/core/aspects/metadata-aspects.d.ts +12 -0
- package/dist/core/aspects/metadata-aspects.d.ts.map +1 -0
- package/dist/core/aspects/metadata-aspects.js +24 -0
- package/dist/core/aspects/metadata-aspects.js.map +1 -0
- package/dist/core/aspects/metadata.d.ts +16 -0
- package/dist/core/aspects/metadata.d.ts.map +1 -0
- package/dist/core/aspects/metadata.js +24 -0
- package/dist/core/aspects/metadata.js.map +1 -0
- package/dist/core/aspects/primitives.d.ts +23 -0
- package/dist/core/aspects/primitives.d.ts.map +1 -0
- package/dist/core/aspects/primitives.js +258 -0
- package/dist/core/aspects/primitives.js.map +1 -0
- package/dist/core/aspects/targets.d.ts +9 -0
- package/dist/core/aspects/targets.d.ts.map +1 -0
- package/dist/core/aspects/targets.js +23 -0
- package/dist/core/aspects/targets.js.map +1 -0
- package/dist/core/aspects/types.d.ts +361 -0
- package/dist/core/aspects/types.d.ts.map +1 -0
- package/dist/core/aspects/types.js +16 -0
- package/dist/core/aspects/types.js.map +1 -0
- package/dist/core/aspects/workload-aspects.d.ts +17 -0
- package/dist/core/aspects/workload-aspects.d.ts.map +1 -0
- package/dist/core/aspects/workload-aspects.js +40 -0
- package/dist/core/aspects/workload-aspects.js.map +1 -0
- package/dist/core/composition/context.d.ts +58 -2
- package/dist/core/composition/context.d.ts.map +1 -1
- package/dist/core/composition/context.js +4 -0
- package/dist/core/composition/context.js.map +1 -1
- package/dist/core/composition/imperative.d.ts +9 -0
- package/dist/core/composition/imperative.d.ts.map +1 -1
- package/dist/core/composition/imperative.js +538 -54
- package/dist/core/composition/imperative.js.map +1 -1
- package/dist/core/composition/nested-status-cel.d.ts +34 -1
- package/dist/core/composition/nested-status-cel.d.ts.map +1 -1
- package/dist/core/composition/nested-status-cel.js +379 -41
- package/dist/core/composition/nested-status-cel.js.map +1 -1
- package/dist/core/composition-debugger.d.ts +1 -1
- package/dist/core/composition-debugger.d.ts.map +1 -1
- package/dist/core/composition-debugger.js.map +1 -1
- package/dist/core/constants/brands.d.ts +1 -1
- package/dist/core/constants/brands.d.ts.map +1 -1
- package/dist/core/constants/brands.js +1 -1
- package/dist/core/constants/brands.js.map +1 -1
- package/dist/core/containers/build.d.ts.map +1 -1
- package/dist/core/containers/build.js +40 -12
- package/dist/core/containers/build.js.map +1 -1
- package/dist/core/dependencies/resolver.d.ts +19 -0
- package/dist/core/dependencies/resolver.d.ts.map +1 -1
- package/dist/core/dependencies/resolver.js +261 -1
- package/dist/core/dependencies/resolver.js.map +1 -1
- package/dist/core/deployment/client-provider-manager.d.ts +9 -3
- package/dist/core/deployment/client-provider-manager.d.ts.map +1 -1
- package/dist/core/deployment/client-provider-manager.js +12 -0
- package/dist/core/deployment/client-provider-manager.js.map +1 -1
- package/dist/core/deployment/crd-manager.d.ts +24 -0
- package/dist/core/deployment/crd-manager.d.ts.map +1 -1
- package/dist/core/deployment/crd-manager.js +79 -1
- package/dist/core/deployment/crd-manager.js.map +1 -1
- package/dist/core/deployment/deployment-state-discovery.d.ts +116 -0
- package/dist/core/deployment/deployment-state-discovery.d.ts.map +1 -0
- package/dist/core/deployment/deployment-state-discovery.js +400 -0
- package/dist/core/deployment/deployment-state-discovery.js.map +1 -0
- package/dist/core/deployment/direct-factory.d.ts +65 -6
- package/dist/core/deployment/direct-factory.d.ts.map +1 -1
- package/dist/core/deployment/direct-factory.js +584 -62
- package/dist/core/deployment/direct-factory.js.map +1 -1
- package/dist/core/deployment/engine.d.ts +64 -3
- package/dist/core/deployment/engine.d.ts.map +1 -1
- package/dist/core/deployment/engine.js +194 -27
- package/dist/core/deployment/engine.js.map +1 -1
- package/dist/core/deployment/event-filter.js +1 -1
- package/dist/core/deployment/event-filter.js.map +1 -1
- package/dist/core/deployment/event-monitor.d.ts +11 -0
- package/dist/core/deployment/event-monitor.d.ts.map +1 -1
- package/dist/core/deployment/event-monitor.js +14 -0
- package/dist/core/deployment/event-monitor.js.map +1 -1
- package/dist/core/deployment/handle-tracing.d.ts +14 -0
- package/dist/core/deployment/handle-tracing.d.ts.map +1 -0
- package/dist/core/deployment/handle-tracing.js +38 -0
- package/dist/core/deployment/handle-tracing.js.map +1 -0
- package/dist/core/deployment/kro-factory.d.ts +115 -3
- package/dist/core/deployment/kro-factory.d.ts.map +1 -1
- package/dist/core/deployment/kro-factory.js +922 -278
- package/dist/core/deployment/kro-factory.js.map +1 -1
- package/dist/core/deployment/kro-readiness.d.ts.map +1 -1
- package/dist/core/deployment/kro-readiness.js +21 -12
- package/dist/core/deployment/kro-readiness.js.map +1 -1
- package/dist/core/deployment/nested-composition-status.d.ts +1 -1
- package/dist/core/deployment/nested-composition-status.d.ts.map +1 -1
- package/dist/core/deployment/nested-composition-status.js +96 -53
- package/dist/core/deployment/nested-composition-status.js.map +1 -1
- package/dist/core/deployment/resource-applier.d.ts +15 -2
- package/dist/core/deployment/resource-applier.d.ts.map +1 -1
- package/dist/core/deployment/resource-applier.js +75 -25
- package/dist/core/deployment/resource-applier.js.map +1 -1
- package/dist/core/deployment/resource-tagging.d.ts +220 -0
- package/dist/core/deployment/resource-tagging.d.ts.map +1 -0
- package/dist/core/deployment/resource-tagging.js +292 -0
- package/dist/core/deployment/resource-tagging.js.map +1 -0
- package/dist/core/deployment/rollback-manager.d.ts +25 -4
- package/dist/core/deployment/rollback-manager.d.ts.map +1 -1
- package/dist/core/deployment/rollback-manager.js +70 -57
- package/dist/core/deployment/rollback-manager.js.map +1 -1
- package/dist/core/deployment/shared-utilities.d.ts +6 -0
- package/dist/core/deployment/shared-utilities.d.ts.map +1 -1
- package/dist/core/deployment/shared-utilities.js +32 -2
- package/dist/core/deployment/shared-utilities.js.map +1 -1
- package/dist/core/deployment/singleton-owner-drift.d.ts +16 -0
- package/dist/core/deployment/singleton-owner-drift.d.ts.map +1 -0
- package/dist/core/deployment/singleton-owner-drift.js +54 -0
- package/dist/core/deployment/singleton-owner-drift.js.map +1 -0
- package/dist/core/deployment/strategies/alchemy-strategy.d.ts +3 -1
- package/dist/core/deployment/strategies/alchemy-strategy.d.ts.map +1 -1
- package/dist/core/deployment/strategies/alchemy-strategy.js +121 -18
- package/dist/core/deployment/strategies/alchemy-strategy.js.map +1 -1
- package/dist/core/deployment/strategies/base-strategy.d.ts +9 -3
- package/dist/core/deployment/strategies/base-strategy.d.ts.map +1 -1
- package/dist/core/deployment/strategies/base-strategy.js +32 -4
- package/dist/core/deployment/strategies/base-strategy.js.map +1 -1
- package/dist/core/deployment/strategies/direct-strategy.d.ts +12 -4
- package/dist/core/deployment/strategies/direct-strategy.d.ts.map +1 -1
- package/dist/core/deployment/strategies/direct-strategy.js +112 -8
- package/dist/core/deployment/strategies/direct-strategy.js.map +1 -1
- package/dist/core/errors.d.ts +2 -2
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js.map +1 -1
- package/dist/core/expressions/analysis/cache.d.ts +2 -2
- package/dist/core/expressions/analysis/cache.d.ts.map +1 -1
- package/dist/core/expressions/analysis/cache.js +4 -0
- package/dist/core/expressions/analysis/cache.js.map +1 -1
- package/dist/core/expressions/analysis/fn-toString-self-test.d.ts.map +1 -1
- package/dist/core/expressions/analysis/fn-toString-self-test.js +0 -1
- package/dist/core/expressions/analysis/fn-toString-self-test.js.map +1 -1
- package/dist/core/expressions/analysis/shared-types.d.ts +2 -2
- package/dist/core/expressions/analysis/shared-types.d.ts.map +1 -1
- package/dist/core/expressions/analysis/source-map.d.ts.map +1 -1
- package/dist/core/expressions/analysis/source-map.js +1 -0
- package/dist/core/expressions/analysis/source-map.js.map +1 -1
- package/dist/core/expressions/analysis/types.d.ts +7 -7
- package/dist/core/expressions/analysis/types.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-helpers.d.ts +29 -1
- package/dist/core/expressions/composition/composition-analyzer-helpers.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-helpers.js +348 -17
- package/dist/core/expressions/composition/composition-analyzer-helpers.js.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-ternary.d.ts +2 -2
- package/dist/core/expressions/composition/composition-analyzer-ternary.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-ternary.js +221 -10
- package/dist/core/expressions/composition/composition-analyzer-ternary.js.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-traversal.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-traversal.js +67 -2
- package/dist/core/expressions/composition/composition-analyzer-traversal.js.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer-types.d.ts +52 -0
- package/dist/core/expressions/composition/composition-analyzer-types.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/composition/composition-analyzer.js +150 -6
- package/dist/core/expressions/composition/composition-analyzer.js.map +1 -1
- package/dist/core/expressions/composition/expression-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/composition/expression-analyzer.js +21 -4
- package/dist/core/expressions/composition/expression-analyzer.js.map +1 -1
- package/dist/core/expressions/composition/imperative-analyzer.d.ts +1 -1
- package/dist/core/expressions/composition/imperative-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/composition/imperative-analyzer.js +31 -7
- package/dist/core/expressions/composition/imperative-analyzer.js.map +1 -1
- package/dist/core/expressions/composition/scope-manager.d.ts +2 -2
- package/dist/core/expressions/composition/scope-manager.d.ts.map +1 -1
- package/dist/core/expressions/composition/scope-manager.js.map +1 -1
- package/dist/core/expressions/conditional/conditional-expression-processor.d.ts +3 -3
- package/dist/core/expressions/conditional/conditional-expression-processor.d.ts.map +1 -1
- package/dist/core/expressions/conditional/conditional-expression-processor.js.map +1 -1
- package/dist/core/expressions/conditional/conditional-integration.d.ts.map +1 -1
- package/dist/core/expressions/conditional/conditional-integration.js.map +1 -1
- package/dist/core/expressions/context/context-aware-generator.d.ts +5 -5
- package/dist/core/expressions/context/context-aware-generator.d.ts.map +1 -1
- package/dist/core/expressions/context/context-aware-generator.js.map +1 -1
- package/dist/core/expressions/context/context-detector.d.ts +3 -3
- package/dist/core/expressions/context/context-detector.d.ts.map +1 -1
- package/dist/core/expressions/context/context-detector.js.map +1 -1
- package/dist/core/expressions/context/context-validator.d.ts +6 -6
- package/dist/core/expressions/context/context-validator.d.ts.map +1 -1
- package/dist/core/expressions/context/context-validator.js +2 -2
- package/dist/core/expressions/context/context-validator.js.map +1 -1
- package/dist/core/expressions/factory/cel-conversion-engine.d.ts +4 -4
- package/dist/core/expressions/factory/cel-conversion-engine.d.ts.map +1 -1
- package/dist/core/expressions/factory/cel-conversion-engine.js.map +1 -1
- package/dist/core/expressions/factory/dependency-tracker.d.ts +2 -2
- package/dist/core/expressions/factory/dependency-tracker.d.ts.map +1 -1
- package/dist/core/expressions/factory/dependency-tracker.js +21 -5
- package/dist/core/expressions/factory/dependency-tracker.js.map +1 -1
- package/dist/core/expressions/factory/factory-integration.d.ts +2 -4
- package/dist/core/expressions/factory/factory-integration.d.ts.map +1 -1
- package/dist/core/expressions/factory/factory-integration.js +0 -6
- package/dist/core/expressions/factory/factory-integration.js.map +1 -1
- package/dist/core/expressions/factory/factory-pattern-handler.d.ts +3 -3
- package/dist/core/expressions/factory/factory-pattern-handler.d.ts.map +1 -1
- package/dist/core/expressions/factory/factory-pattern-handler.js +1 -0
- package/dist/core/expressions/factory/factory-pattern-handler.js.map +1 -1
- package/dist/core/expressions/factory/migration-helpers.js.map +1 -1
- package/dist/core/expressions/factory/resource-analyzer.d.ts +4 -4
- package/dist/core/expressions/factory/resource-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/factory/resource-analyzer.js.map +1 -1
- package/dist/core/expressions/factory/resource-type-validator.d.ts +5 -5
- package/dist/core/expressions/factory/resource-type-validator.d.ts.map +1 -1
- package/dist/core/expressions/factory/resource-type-validator.js.map +1 -1
- package/dist/core/expressions/factory/status-builder-analyzer.d.ts +6 -7
- package/dist/core/expressions/factory/status-builder-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/factory/status-builder-analyzer.js +0 -3
- package/dist/core/expressions/factory/status-builder-analyzer.js.map +1 -1
- package/dist/core/expressions/factory/status-builder-types.d.ts +1 -1
- package/dist/core/expressions/factory/status-builder-types.d.ts.map +1 -1
- package/dist/core/expressions/factory/status-cel-generation.d.ts +1 -1
- package/dist/core/expressions/factory/status-cel-generation.d.ts.map +1 -1
- package/dist/core/expressions/factory/status-cel-generation.js +1 -1
- package/dist/core/expressions/factory/status-cel-generation.js.map +1 -1
- package/dist/core/expressions/factory/status-field-analysis.d.ts +3 -3
- package/dist/core/expressions/factory/status-field-analysis.d.ts.map +1 -1
- package/dist/core/expressions/factory/status-field-analysis.js.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.d.ts +5 -5
- package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.js +1 -1
- package/dist/core/expressions/magic-proxy/magic-assignable-analyzer.js.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.d.ts +10 -10
- package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.js +5 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-analyzer.js.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-ast.d.ts +2 -2
- package/dist/core/expressions/magic-proxy/magic-proxy-ast.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-ast.js.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-detector.d.ts +5 -5
- package/dist/core/expressions/magic-proxy/magic-proxy-detector.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-detector.js.map +1 -1
- package/dist/core/expressions/magic-proxy/magic-proxy-types.d.ts +2 -2
- package/dist/core/expressions/magic-proxy/magic-proxy-types.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/optionality-handler.d.ts +1 -2
- package/dist/core/expressions/magic-proxy/optionality-handler.d.ts.map +1 -1
- package/dist/core/expressions/magic-proxy/optionality-handler.js +2 -15
- package/dist/core/expressions/magic-proxy/optionality-handler.js.map +1 -1
- package/dist/core/expressions/validation/compile-time-checker.d.ts +1 -1
- package/dist/core/expressions/validation/compile-time-checker.d.ts.map +1 -1
- package/dist/core/expressions/validation/compile-time-checker.js.map +1 -1
- package/dist/core/expressions/validation/compile-time-types.d.ts +2 -2
- package/dist/core/expressions/validation/compile-time-types.d.ts.map +1 -1
- package/dist/core/expressions/validation/kubernetes-field-types.d.ts +4 -4
- package/dist/core/expressions/validation/kubernetes-field-types.d.ts.map +1 -1
- package/dist/core/expressions/validation/kubernetes-field-types.js.map +1 -1
- package/dist/core/expressions/validation/resource-field-utils.d.ts +10 -10
- package/dist/core/expressions/validation/resource-field-utils.d.ts.map +1 -1
- package/dist/core/expressions/validation/resource-field-utils.js.map +1 -1
- package/dist/core/expressions/validation/resource-validation.d.ts +3 -3
- package/dist/core/expressions/validation/resource-validation.d.ts.map +1 -1
- package/dist/core/expressions/validation/resource-validation.js.map +1 -1
- package/dist/core/expressions/validation/type-inference-types.d.ts +2 -2
- package/dist/core/expressions/validation/type-inference-types.d.ts.map +1 -1
- package/dist/core/expressions/validation/type-safety.d.ts +2 -2
- package/dist/core/expressions/validation/type-safety.d.ts.map +1 -1
- package/dist/core/expressions/validation/type-safety.js +1 -0
- package/dist/core/expressions/validation/type-safety.js.map +1 -1
- package/dist/core/kubernetes/bun-api-client.js.map +1 -1
- package/dist/core/kubernetes/bun-http-library.d.ts.map +1 -1
- package/dist/core/kubernetes/bun-http-library.js +29 -3
- package/dist/core/kubernetes/bun-http-library.js.map +1 -1
- package/dist/core/kubernetes/client-provider.d.ts +12 -0
- package/dist/core/kubernetes/client-provider.d.ts.map +1 -1
- package/dist/core/kubernetes/client-provider.js +35 -0
- package/dist/core/kubernetes/client-provider.js.map +1 -1
- package/dist/core/metadata/resource-metadata.d.ts +49 -1
- package/dist/core/metadata/resource-metadata.d.ts.map +1 -1
- package/dist/core/metadata/resource-metadata.js.map +1 -1
- package/dist/core/proxy/create-resource.d.ts +15 -0
- package/dist/core/proxy/create-resource.d.ts.map +1 -1
- package/dist/core/proxy/create-resource.js +79 -2
- package/dist/core/proxy/create-resource.js.map +1 -1
- package/dist/core/readiness/registry.js +2 -2
- package/dist/core/readiness/registry.js.map +1 -1
- package/dist/core/references/cel-evaluator.d.ts +1 -4
- package/dist/core/references/cel-evaluator.d.ts.map +1 -1
- package/dist/core/references/cel-evaluator.js +3 -7
- package/dist/core/references/cel-evaluator.js.map +1 -1
- package/dist/core/references/cel.d.ts +22 -0
- package/dist/core/references/cel.d.ts.map +1 -1
- package/dist/core/references/cel.js +106 -8
- package/dist/core/references/cel.js.map +1 -1
- package/dist/core/references/external-refs.d.ts.map +1 -1
- package/dist/core/references/external-refs.js +3 -0
- package/dist/core/references/external-refs.js.map +1 -1
- package/dist/core/references/resolver.d.ts.map +1 -1
- package/dist/core/references/resolver.js +28 -17
- package/dist/core/references/resolver.js.map +1 -1
- package/dist/core/references/schema-proxy.d.ts +18 -10
- package/dist/core/references/schema-proxy.d.ts.map +1 -1
- package/dist/core/references/schema-proxy.js +174 -23
- package/dist/core/references/schema-proxy.js.map +1 -1
- package/dist/core/runtime-patches/crd-schema-fix.d.ts.map +1 -1
- package/dist/core/runtime-patches/crd-schema-fix.js +4 -1
- package/dist/core/runtime-patches/crd-schema-fix.js.map +1 -1
- package/dist/core/serialization/cel-optimizer.d.ts.map +1 -1
- package/dist/core/serialization/cel-optimizer.js +2 -0
- package/dist/core/serialization/cel-optimizer.js.map +1 -1
- package/dist/core/serialization/cel-references.d.ts +75 -1
- package/dist/core/serialization/cel-references.d.ts.map +1 -1
- package/dist/core/serialization/cel-references.js +692 -156
- package/dist/core/serialization/cel-references.js.map +1 -1
- package/dist/core/serialization/core.d.ts +8 -8
- package/dist/core/serialization/core.d.ts.map +1 -1
- package/dist/core/serialization/core.js +672 -90
- package/dist/core/serialization/core.js.map +1 -1
- package/dist/core/serialization/kro-post-processing.d.ts +1 -1
- package/dist/core/serialization/kro-post-processing.d.ts.map +1 -1
- package/dist/core/serialization/kro-post-processing.js +69 -22
- package/dist/core/serialization/kro-post-processing.js.map +1 -1
- package/dist/core/serialization/schema.d.ts +1 -0
- package/dist/core/serialization/schema.d.ts.map +1 -1
- package/dist/core/serialization/schema.js +378 -50
- package/dist/core/serialization/schema.js.map +1 -1
- package/dist/core/serialization/status-analysis-pipeline.d.ts +1 -1
- package/dist/core/serialization/status-analysis-pipeline.d.ts.map +1 -1
- package/dist/core/serialization/status-analysis-pipeline.js.map +1 -1
- package/dist/core/serialization/yaml.d.ts +3 -2
- package/dist/core/serialization/yaml.d.ts.map +1 -1
- package/dist/core/serialization/yaml.js +385 -55
- package/dist/core/serialization/yaml.js.map +1 -1
- package/dist/core/singleton/singleton.d.ts +16 -0
- package/dist/core/singleton/singleton.d.ts.map +1 -0
- package/dist/core/singleton/singleton.js +135 -0
- package/dist/core/singleton/singleton.js.map +1 -0
- package/dist/core/types/common.d.ts +2 -2
- package/dist/core/types/common.d.ts.map +1 -1
- package/dist/core/types/composable.d.ts +1 -1
- package/dist/core/types/composable.d.ts.map +1 -1
- package/dist/core/types/deployment.d.ts +129 -9
- package/dist/core/types/deployment.d.ts.map +1 -1
- package/dist/core/types/deployment.js +1 -1
- package/dist/core/types/deployment.js.map +1 -1
- package/dist/core/types/kubernetes.d.ts +25 -17
- package/dist/core/types/kubernetes.d.ts.map +1 -1
- package/dist/core/types/references.d.ts +1 -1
- package/dist/core/types/references.d.ts.map +1 -1
- package/dist/core/types/references.js.map +1 -1
- package/dist/core/types/resource-graph.d.ts +2 -1
- package/dist/core/types/resource-graph.d.ts.map +1 -1
- package/dist/core/types/schema.d.ts +1 -1
- package/dist/core/types/schema.d.ts.map +1 -1
- package/dist/core/types/serialization.d.ts +24 -6
- package/dist/core/types/serialization.d.ts.map +1 -1
- package/dist/core/validation/cel-validator.d.ts +15 -2
- package/dist/core/validation/cel-validator.d.ts.map +1 -1
- package/dist/core/validation/cel-validator.js +144 -63
- package/dist/core/validation/cel-validator.js.map +1 -1
- package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts +2 -41
- package/dist/factories/apisix/compositions/apisix-bootstrap.d.ts.map +1 -1
- package/dist/factories/apisix/compositions/apisix-bootstrap.js +262 -217
- package/dist/factories/apisix/compositions/apisix-bootstrap.js.map +1 -1
- package/dist/factories/apisix/index.d.ts +2 -2
- package/dist/factories/apisix/index.js +2 -2
- package/dist/factories/apisix/resources/helm.d.ts +2 -2
- package/dist/factories/apisix/resources/helm.d.ts.map +1 -1
- package/dist/factories/apisix/resources/helm.js.map +1 -1
- package/dist/factories/apisix/types.d.ts +21 -11
- package/dist/factories/apisix/types.d.ts.map +1 -1
- package/dist/factories/apisix/types.js +106 -4
- package/dist/factories/apisix/types.js.map +1 -1
- package/dist/factories/apisix/utils/admin-credentials.d.ts +5 -3
- package/dist/factories/apisix/utils/admin-credentials.d.ts.map +1 -1
- package/dist/factories/apisix/utils/admin-credentials.js +14 -10
- package/dist/factories/apisix/utils/admin-credentials.js.map +1 -1
- package/dist/factories/apisix/utils/helm-values-mapper.d.ts.map +1 -1
- package/dist/factories/apisix/utils/helm-values-mapper.js +4 -2
- package/dist/factories/apisix/utils/helm-values-mapper.js.map +1 -1
- package/dist/factories/cert-manager/resources/challenges.js.map +1 -1
- package/dist/factories/cert-manager/types.d.ts +3 -3
- package/dist/factories/cert-manager/types.d.ts.map +1 -1
- package/dist/factories/cilium/compositions/cilium-bootstrap.d.ts +4 -4
- package/dist/factories/cilium/types.d.ts +3 -3
- package/dist/factories/cilium/types.d.ts.map +1 -1
- package/dist/factories/cnpg/compositions/cnpg-bootstrap.d.ts +1 -0
- package/dist/factories/cnpg/compositions/cnpg-bootstrap.d.ts.map +1 -1
- package/dist/factories/cnpg/compositions/cnpg-bootstrap.js +48 -0
- package/dist/factories/cnpg/compositions/cnpg-bootstrap.js.map +1 -1
- package/dist/factories/cnpg/resources/cluster.js +1 -1
- package/dist/factories/cnpg/resources/cluster.js.map +1 -1
- package/dist/factories/cnpg/resources/helm.d.ts.map +1 -1
- package/dist/factories/cnpg/resources/helm.js +1 -0
- package/dist/factories/cnpg/resources/helm.js.map +1 -1
- package/dist/factories/cnpg/resources/pooler.js +1 -1
- package/dist/factories/cnpg/resources/pooler.js.map +1 -1
- package/dist/factories/cnpg/types.d.ts +9 -8
- package/dist/factories/cnpg/types.d.ts.map +1 -1
- package/dist/factories/cnpg/types.js +11 -0
- package/dist/factories/cnpg/types.js.map +1 -1
- package/dist/factories/external-dns/compositions/external-dns-bootstrap.d.ts.map +1 -1
- package/dist/factories/external-dns/compositions/external-dns-bootstrap.js +153 -41
- package/dist/factories/external-dns/compositions/external-dns-bootstrap.js.map +1 -1
- package/dist/factories/external-dns/resources/dns-endpoint.js +1 -1
- package/dist/factories/external-dns/resources/dns-endpoint.js.map +1 -1
- package/dist/factories/external-dns/resources/helm.d.ts +1 -1
- package/dist/factories/external-dns/resources/helm.d.ts.map +1 -1
- package/dist/factories/external-dns/resources/helm.js +17 -10
- package/dist/factories/external-dns/resources/helm.js.map +1 -1
- package/dist/factories/external-dns/types.d.ts +5 -2
- package/dist/factories/external-dns/types.d.ts.map +1 -1
- package/dist/factories/external-dns/types.js.map +1 -1
- package/dist/factories/flux/git-repository.d.ts.map +1 -1
- package/dist/factories/flux/git-repository.js +1 -1
- package/dist/factories/flux/git-repository.js.map +1 -1
- package/dist/factories/flux/kustomize/kustomization.d.ts +2 -2
- package/dist/factories/flux/kustomize/kustomization.d.ts.map +1 -1
- package/dist/factories/flux/kustomize/readiness-evaluators.d.ts +1 -1
- package/dist/factories/flux/kustomize/readiness-evaluators.d.ts.map +1 -1
- package/dist/factories/flux/kustomize/readiness-evaluators.js +1 -1
- package/dist/factories/flux/kustomize/readiness-evaluators.js.map +1 -1
- package/dist/factories/helm/helm-release.d.ts +3 -2
- package/dist/factories/helm/helm-release.d.ts.map +1 -1
- package/dist/factories/helm/helm-release.js +1 -0
- package/dist/factories/helm/helm-release.js.map +1 -1
- package/dist/factories/helm/helm-repository.d.ts +1 -1
- package/dist/factories/helm/helm-repository.d.ts.map +1 -1
- package/dist/factories/helm/helm-repository.js +6 -4
- package/dist/factories/helm/helm-repository.js.map +1 -1
- package/dist/factories/helm/readiness-evaluators.d.ts +6 -6
- package/dist/factories/helm/readiness-evaluators.d.ts.map +1 -1
- package/dist/factories/helm/readiness-evaluators.js +15 -9
- package/dist/factories/helm/readiness-evaluators.js.map +1 -1
- package/dist/factories/helm/types.d.ts +5 -1
- package/dist/factories/helm/types.d.ts.map +1 -1
- package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts +1 -0
- package/dist/factories/inngest/compositions/inngest-bootstrap.d.ts.map +1 -1
- package/dist/factories/inngest/compositions/inngest-bootstrap.js +4 -3
- package/dist/factories/inngest/compositions/inngest-bootstrap.js.map +1 -1
- package/dist/factories/inngest/resources/helm.js +1 -1
- package/dist/factories/inngest/resources/helm.js.map +1 -1
- package/dist/factories/inngest/types.d.ts +5 -4
- package/dist/factories/inngest/types.d.ts.map +1 -1
- package/dist/factories/inngest/types.js +2 -0
- package/dist/factories/inngest/types.js.map +1 -1
- package/dist/factories/kro/kro-custom-resource.js +1 -1
- package/dist/factories/kro/kro-custom-resource.js.map +1 -1
- package/dist/factories/kubernetes/config/config-map.d.ts +2 -2
- package/dist/factories/kubernetes/config/config-map.d.ts.map +1 -1
- package/dist/factories/kubernetes/config/secret.d.ts +2 -2
- package/dist/factories/kubernetes/config/secret.d.ts.map +1 -1
- package/dist/factories/kubernetes/networking/service.js +1 -1
- package/dist/factories/kubernetes/networking/service.js.map +1 -1
- package/dist/factories/kubernetes/yaml/yaml-directory.d.ts.map +1 -1
- package/dist/factories/kubernetes/yaml/yaml-directory.js +9 -0
- package/dist/factories/kubernetes/yaml/yaml-directory.js.map +1 -1
- package/dist/factories/kubernetes/yaml/yaml-file.d.ts.map +1 -1
- package/dist/factories/kubernetes/yaml/yaml-file.js +9 -0
- package/dist/factories/kubernetes/yaml/yaml-file.js.map +1 -1
- package/dist/factories/pebble/resources/helm.js.map +1 -1
- package/dist/factories/pebble/types.d.ts +2 -2
- package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts +3 -2
- package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts.map +1 -1
- package/dist/factories/searxng/compositions/searxng-bootstrap.js +205 -167
- package/dist/factories/searxng/compositions/searxng-bootstrap.js.map +1 -1
- package/dist/factories/searxng/resources/searxng.d.ts +1 -1
- package/dist/factories/searxng/resources/searxng.js +1 -1
- package/dist/factories/searxng/types.d.ts +5 -4
- package/dist/factories/searxng/types.d.ts.map +1 -1
- package/dist/factories/searxng/types.js +8 -7
- package/dist/factories/searxng/types.js.map +1 -1
- package/dist/factories/searxng/utils/settings-builder.d.ts +4 -3
- package/dist/factories/searxng/utils/settings-builder.d.ts.map +1 -1
- package/dist/factories/searxng/utils/settings-builder.js +4 -3
- package/dist/factories/searxng/utils/settings-builder.js.map +1 -1
- package/dist/factories/simple/config/config-map.d.ts +2 -2
- package/dist/factories/simple/config/config-map.d.ts.map +1 -1
- package/dist/factories/simple/config/secret.d.ts +2 -2
- package/dist/factories/simple/config/secret.d.ts.map +1 -1
- package/dist/factories/simple/helm/index.d.ts +1 -1
- package/dist/factories/simple/helm/index.d.ts.map +1 -1
- package/dist/factories/simple/helm/index.js.map +1 -1
- package/dist/factories/simple/index.d.ts +3 -3
- package/dist/factories/simple/index.d.ts.map +1 -1
- package/dist/factories/simple/storage/persistent-volume.js.map +1 -1
- package/dist/factories/simple/types.d.ts +11 -1
- package/dist/factories/simple/types.d.ts.map +1 -1
- package/dist/factories/simple/workloads/deployment.d.ts +4 -1
- package/dist/factories/simple/workloads/deployment.d.ts.map +1 -1
- package/dist/factories/simple/workloads/deployment.js +9 -2
- package/dist/factories/simple/workloads/deployment.js.map +1 -1
- package/dist/factories/simple/workloads/stateful-set.d.ts +4 -1
- package/dist/factories/simple/workloads/stateful-set.d.ts.map +1 -1
- package/dist/factories/simple/workloads/stateful-set.js +6 -2
- package/dist/factories/simple/workloads/stateful-set.js.map +1 -1
- package/dist/factories/valkey/compositions/valkey-bootstrap.d.ts +1 -0
- package/dist/factories/valkey/compositions/valkey-bootstrap.d.ts.map +1 -1
- package/dist/factories/valkey/compositions/valkey-bootstrap.js +116 -0
- package/dist/factories/valkey/compositions/valkey-bootstrap.js.map +1 -1
- package/dist/factories/valkey/resources/valkey.js +1 -1
- package/dist/factories/valkey/resources/valkey.js.map +1 -1
- package/dist/factories/valkey/types.d.ts +6 -5
- package/dist/factories/valkey/types.d.ts.map +1 -1
- package/dist/factories/valkey/types.js +10 -0
- package/dist/factories/valkey/types.js.map +1 -1
- package/dist/factories/webapp/compositions/web-app-with-processing.d.ts +90 -6
- package/dist/factories/webapp/compositions/web-app-with-processing.d.ts.map +1 -1
- package/dist/factories/webapp/compositions/web-app-with-processing.js +180 -20
- package/dist/factories/webapp/compositions/web-app-with-processing.js.map +1 -1
- package/dist/factories/webapp/index.d.ts +3 -4
- package/dist/factories/webapp/index.d.ts.map +1 -1
- package/dist/factories/webapp/index.js +3 -4
- package/dist/factories/webapp/index.js.map +1 -1
- package/dist/factories/webapp/types.d.ts +60 -2
- package/dist/factories/webapp/types.d.ts.map +1 -1
- package/dist/factories/webapp/types.js +80 -3
- package/dist/factories/webapp/types.js.map +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/shared/brands.d.ts +18 -8
- package/dist/shared/brands.d.ts.map +1 -1
- package/dist/shared/brands.js +19 -9
- package/dist/shared/brands.js.map +1 -1
- package/dist/utils/cel-escape.d.ts +12 -0
- package/dist/utils/cel-escape.d.ts.map +1 -0
- package/dist/utils/cel-escape.js +19 -0
- package/dist/utils/cel-escape.js.map +1 -0
- package/package.json +7 -2
|
@@ -4,22 +4,40 @@
|
|
|
4
4
|
* This module provides the main serialization functions to convert
|
|
5
5
|
* TypeScript resource definitions to Kro ResourceGraphDefinition YAML manifests.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import { CEL_EXPRESSION_BRAND, KUBERNETES_REF_MARKER_SOURCE } from '../../shared/brands.js';
|
|
8
|
+
import { createCompositionContext, getCurrentCompositionContext, runInStatusBuilderContext, runWithCompositionContext, } from '../composition/context.js';
|
|
8
9
|
import { createDirectResourceFactory } from '../deployment/direct-factory.js';
|
|
9
10
|
import { createKroResourceFactory } from '../deployment/kro-factory.js';
|
|
10
11
|
import { ensureError, ValidationError } from '../errors.js';
|
|
11
12
|
import { analyzeCompositionBody, applyAnalysisToResources, } from '../expressions/composition/composition-analyzer.js';
|
|
13
|
+
import { remapResourceStatusReferences } from '../expressions/composition/composition-analyzer-helpers.js';
|
|
12
14
|
import { StatusBuilderAnalyzer } from '../expressions/factory/status-builder-analyzer.js';
|
|
13
15
|
import { getComponentLogger } from '../logging/index.js';
|
|
14
|
-
import { setResourceId } from '../metadata/index.js';
|
|
16
|
+
import { getMetadataField, setResourceId } from '../metadata/index.js';
|
|
15
17
|
import { createExternalRefWithoutRegistration, createSchemaProxy } from '../references/index.js';
|
|
16
18
|
import { getKindInfo, getSemanticCandidateKinds } from '../resources/factory-registry.js';
|
|
17
19
|
import { validateResourceGraphDefinition } from '../validation/cel-validator.js';
|
|
18
20
|
import { optimizeStatusMappings } from './cel-optimizer.js';
|
|
21
|
+
import { finalizeCelForKro } from './cel-references.js';
|
|
19
22
|
import { applyTernaryConditionalsToResources } from './kro-post-processing.js';
|
|
20
23
|
import { generateKroSchemaFromArktype } from './schema.js';
|
|
21
24
|
import { runStatusAnalysisPipeline } from './status-analysis-pipeline.js';
|
|
22
25
|
import { serializeResourceGraphToYaml } from './yaml.js';
|
|
26
|
+
function isToYamlOptions(value) {
|
|
27
|
+
if (typeof value !== 'object' || value === null || !Object.hasOwn(value, 'aspects')) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const aspects = value.aspects;
|
|
31
|
+
if (!Array.isArray(aspects))
|
|
32
|
+
return false;
|
|
33
|
+
// Empty arrays remain render options for the established `toYaml({ aspects: [] })`
|
|
34
|
+
// API only when `aspects` is the whole object. Non-empty arrays must contain
|
|
35
|
+
// aspect descriptors so CRD specs with unrelated `aspects` arrays are not
|
|
36
|
+
// accidentally interpreted as render options.
|
|
37
|
+
if (aspects.length === 0)
|
|
38
|
+
return Object.keys(value).length === 1;
|
|
39
|
+
return aspects.every((entry) => typeof entry === 'object' && entry !== null && entry.kind === 'aspect');
|
|
40
|
+
}
|
|
23
41
|
/**
|
|
24
42
|
* Separate Enhanced<> resources from deployment closures in the builder result
|
|
25
43
|
*/
|
|
@@ -247,9 +265,9 @@ function processCompositionBodyAnalysis(statusMappings, resourcesWithKeys, analy
|
|
|
247
265
|
try {
|
|
248
266
|
const resourceIds = new Set(Object.keys(resourcesWithKeys));
|
|
249
267
|
const specJson = schemaDefinition?.spec?.json;
|
|
250
|
-
const optionalFieldNames = specJson
|
|
251
|
-
|
|
252
|
-
|
|
268
|
+
const optionalFieldNames = specJson ? collectOptionalSpecPaths(specJson) : undefined;
|
|
269
|
+
const nestedStatusDescriptor = Object.getOwnPropertyDescriptor(statusMappings, '__nestedStatusCel');
|
|
270
|
+
const nestedStatusCel = nestedStatusDescriptor?.value;
|
|
253
271
|
compositionAnalysis = analyzeCompositionBody(originalCompositionFnForAnalysis, resourceIds, optionalFieldNames);
|
|
254
272
|
// Differential execution to capture untaken-branch resources.
|
|
255
273
|
//
|
|
@@ -270,10 +288,78 @@ function processCompositionBodyAnalysis(statusMappings, resourcesWithKeys, analy
|
|
|
270
288
|
// (so we set them to a sentinel that prevents the composition from
|
|
271
289
|
// dereferencing undefined). Both runs use the same composition
|
|
272
290
|
// function, so resource IDs and factory calls are deterministic.
|
|
273
|
-
|
|
291
|
+
//
|
|
292
|
+
// SKIP when this composition is being executed as a nested call
|
|
293
|
+
// (`context.isNestedCall === true`). The inner composition's own
|
|
294
|
+
// definition-time pass already captured its hybrid-branch analysis
|
|
295
|
+
// with the INNER schema proxy. Re-running that hybrid capture here —
|
|
296
|
+
// against the fresh inner schema proxy that `captureHybridRunResources`
|
|
297
|
+
// creates — would emit differential CEL conditionals that reference
|
|
298
|
+
// inner-schema fields (e.g., `has(schema.spec.secretKeyRef)`) which
|
|
299
|
+
// don't exist in the outer RGD. The outer composition is the
|
|
300
|
+
// authority on branch conditions for its own calls; the inner's
|
|
301
|
+
// branch shape is driven by what the outer passed in.
|
|
302
|
+
// ── Resource-status ternary compilation (Phases 3+4) ────────────
|
|
303
|
+
//
|
|
304
|
+
// When the AST detects ternaries conditioned on resource status
|
|
305
|
+
// fields (e.g., `cache.status.ready ? 'redis' : 'memory'`), proxy
|
|
306
|
+
// JS evaluation does not necessarily match CEL truth evaluation.
|
|
307
|
+
// To emit the CEL conditional, re-execute explicit true and false
|
|
308
|
+
// branches using `liveStatusMap`, then diff those branch outputs.
|
|
309
|
+
//
|
|
310
|
+
// To avoid false positives (other fields changing due to the status
|
|
311
|
+
// flip), direct factory calls diff only `callSiteResourceId`; nested
|
|
312
|
+
// composition call arguments diff only resources registered under known
|
|
313
|
+
// nested composition base IDs.
|
|
314
|
+
const resourceStatusTernaries = compositionAnalysis.resourceStatusTernaries;
|
|
315
|
+
// Deduplicate by call site and condition. Conditionalization is scoped to
|
|
316
|
+
// one callSiteResourceId, so two resources using the same status condition
|
|
317
|
+
// must both be processed.
|
|
318
|
+
const seenConditions = new Set();
|
|
319
|
+
const uniqueTernaries = resourceStatusTernaries.filter((t) => {
|
|
320
|
+
const key = `${t.callSiteResourceId}:${t.variableName}:${t.conditionExpression ?? t.statusField}`;
|
|
321
|
+
if (seenConditions.has(key))
|
|
322
|
+
return false;
|
|
323
|
+
seenConditions.add(key);
|
|
324
|
+
return true;
|
|
325
|
+
});
|
|
326
|
+
// Process EACH resource-status ternary independently to avoid
|
|
327
|
+
// cross-contamination: flip ONE condition → run → diff → apply.
|
|
328
|
+
// Multiple ternaries on the same resource get independent conditionals.
|
|
329
|
+
for (const ternary of uniqueTernaries) {
|
|
330
|
+
const resId = compositionAnalysis.variableToResourceId.get(ternary.variableName) ??
|
|
331
|
+
ternary.variableName;
|
|
332
|
+
if (!resourceIds.has(resId))
|
|
333
|
+
continue;
|
|
334
|
+
const conditionCel = ternary.conditionExpression
|
|
335
|
+
? remapResourceStatusReferences(ternary.conditionExpression, new Map(compositionAnalysis.variableToResourceId).set(ternary.variableName, resId))
|
|
336
|
+
: `${resId}.status.${ternary.statusField}`;
|
|
337
|
+
const trueCtx = runResourceStatusBranch(originalCompositionFnForAnalysis, schemaDefinition, compositionAnalysis, ternary, true);
|
|
338
|
+
const falseCtx = runResourceStatusBranch(originalCompositionFnForAnalysis, schemaDefinition, compositionAnalysis, ternary, false);
|
|
339
|
+
// Diff ONLY the targeted resource(s)
|
|
340
|
+
const targetIds = ternary.callSiteResourceId && ternary.callSiteResourceId !== '__non_factory_call__'
|
|
341
|
+
? [ternary.callSiteResourceId]
|
|
342
|
+
: getNestedResourceStatusTargetIds(trueCtx.resources, trueCtx.nestedCompositionIds);
|
|
343
|
+
for (const id of targetIds) {
|
|
344
|
+
const targetRes = resourcesWithKeys[id];
|
|
345
|
+
const trueRes = trueCtx.resources[id];
|
|
346
|
+
const falseRes = falseCtx.resources[id];
|
|
347
|
+
if (targetRes && trueRes && falseRes) {
|
|
348
|
+
applyResourceStatusBranchDiff(targetRes, trueRes, falseRes, conditionCel, nestedStatusCel, resourceIds);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
serializationLogger.debug('Resource-status branch runs applied', {
|
|
352
|
+
conditionCel,
|
|
353
|
+
targetIds,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
const currentCtx = getCurrentCompositionContext();
|
|
357
|
+
const skipHybridCapture = currentCtx?.isNestedCall === true;
|
|
358
|
+
if (!skipHybridCapture &&
|
|
359
|
+
schemaDefinition &&
|
|
274
360
|
(compositionAnalysis.unregisteredFactories.length > 0 ||
|
|
275
361
|
collectOverridableOptionalFields(schemaDefinition, compositionAnalysis).size > 0)) {
|
|
276
|
-
const { captured, overriddenFields } = captureHybridRunResources(originalCompositionFnForAnalysis, schemaDefinition, compositionAnalysis);
|
|
362
|
+
const { captured, overriddenFields, overrideConditions } = captureHybridRunResources(originalCompositionFnForAnalysis, schemaDefinition, compositionAnalysis);
|
|
277
363
|
// (a) Merge resources that exist ONLY in the hybrid run — these
|
|
278
364
|
// come from branches the proxy run didn't take (e.g., `if (!spec.x)`).
|
|
279
365
|
// The AST analyzer has already attached the appropriate includeWhen.
|
|
@@ -306,11 +392,27 @@ function processCompositionBodyAnalysis(statusMappings, resourcesWithKeys, analy
|
|
|
306
392
|
// so multiple `toYaml()` calls on the resulting TypedResourceGraph
|
|
307
393
|
// all see a consistent final state.
|
|
308
394
|
if (overriddenFields.size > 0) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
395
|
+
const baselineResources = Object.fromEntries(Object.entries(resourcesWithKeys).map(([id, resource]) => [
|
|
396
|
+
id,
|
|
397
|
+
cloneResourceTree(resource),
|
|
398
|
+
]));
|
|
399
|
+
const differentialFields = collectDifferentialOptionalFields(compositionAnalysis);
|
|
400
|
+
const fieldsToDiff = Array.from(differentialFields).filter((field) => overriddenFields.has(field));
|
|
401
|
+
for (const field of fieldsToDiff) {
|
|
402
|
+
const singleFieldSet = new Set([field]);
|
|
403
|
+
const { captured: fieldCaptured } = captureHybridRunResources(originalCompositionFnForAnalysis, schemaDefinition, compositionAnalysis, singleFieldSet);
|
|
404
|
+
const fieldConditions = new Map();
|
|
405
|
+
const explicitCondition = overrideConditions.get(field);
|
|
406
|
+
if (explicitCondition) {
|
|
407
|
+
fieldConditions.set(field, explicitCondition);
|
|
408
|
+
}
|
|
409
|
+
for (const id of Object.keys(resourcesWithKeys)) {
|
|
410
|
+
const proxyRes = resourcesWithKeys[id];
|
|
411
|
+
const baselineRes = baselineResources[id];
|
|
412
|
+
const hybridRes = fieldCaptured[id];
|
|
413
|
+
if (proxyRes && baselineRes && hybridRes) {
|
|
414
|
+
applyDifferentialFieldConditionals(proxyRes, baselineRes, hybridRes, singleFieldSet, fieldConditions, nestedStatusCel, resourceIds);
|
|
415
|
+
}
|
|
314
416
|
}
|
|
315
417
|
}
|
|
316
418
|
}
|
|
@@ -369,23 +471,65 @@ function collectOverridableOptionalFields(schemaDefinition, analysis) {
|
|
|
369
471
|
const specJson = schemaDefinition.spec.json;
|
|
370
472
|
if (!specJson)
|
|
371
473
|
return new Set();
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
474
|
+
const differentialFields = collectDifferentialOptionalFields(analysis);
|
|
475
|
+
return new Set(Array.from(collectOptionalSpecPaths(specJson)).filter((field) => differentialFields.has(field)));
|
|
476
|
+
}
|
|
477
|
+
function collectOptionalSpecPaths(schemaJson, prefix = '') {
|
|
478
|
+
const paths = new Set();
|
|
479
|
+
if (!schemaJson || typeof schemaJson !== 'object')
|
|
480
|
+
return paths;
|
|
481
|
+
const node = schemaJson;
|
|
482
|
+
for (const entry of node.optional ?? []) {
|
|
483
|
+
if (!entry.key)
|
|
484
|
+
continue;
|
|
485
|
+
const path = prefix ? `${prefix}.${entry.key}` : entry.key;
|
|
486
|
+
paths.add(path);
|
|
487
|
+
for (const childPath of collectOptionalSpecPaths(entry.value, path)) {
|
|
488
|
+
paths.add(childPath);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
for (const entry of node.required ?? []) {
|
|
492
|
+
if (!entry.key)
|
|
493
|
+
continue;
|
|
494
|
+
const path = prefix ? `${prefix}.${entry.key}` : entry.key;
|
|
495
|
+
for (const childPath of collectOptionalSpecPaths(entry.value, path)) {
|
|
496
|
+
paths.add(childPath);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return paths;
|
|
500
|
+
}
|
|
501
|
+
function collectDifferentialOptionalFields(analysis) {
|
|
502
|
+
const fields = new Set(analysis.hybridOverrideConditions.keys());
|
|
503
|
+
for (const field of analysis.differentialConditionFields) {
|
|
504
|
+
fields.add(field);
|
|
505
|
+
}
|
|
506
|
+
for (const controlFlow of analysis.resources.values()) {
|
|
507
|
+
for (const condition of controlFlow.includeWhen) {
|
|
508
|
+
const expression = condition.expression;
|
|
509
|
+
const matches = expression.matchAll(/schema\.spec\.([a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+)*)/g);
|
|
510
|
+
for (const match of matches) {
|
|
511
|
+
const field = match[1];
|
|
512
|
+
if (field) {
|
|
513
|
+
fields.add(field);
|
|
384
514
|
}
|
|
385
515
|
}
|
|
386
516
|
}
|
|
387
517
|
}
|
|
388
|
-
return
|
|
518
|
+
return fields;
|
|
519
|
+
}
|
|
520
|
+
function collectHybridOverrideValues(analysis) {
|
|
521
|
+
const overrideValues = new Map();
|
|
522
|
+
for (const [field, expression] of analysis.hybridOverrideConditions.entries()) {
|
|
523
|
+
const match = expression.match(/^schema\.spec\.([a-zA-Z0-9_.]+)\s*!=\s*false$/);
|
|
524
|
+
const path = match?.[1];
|
|
525
|
+
if (!path || path !== field || overrideValues.has(field))
|
|
526
|
+
continue;
|
|
527
|
+
overrideValues.set(field, false);
|
|
528
|
+
}
|
|
529
|
+
return overrideValues;
|
|
530
|
+
}
|
|
531
|
+
function collectHybridOverrideConditions(analysis) {
|
|
532
|
+
return new Map(analysis.hybridOverrideConditions);
|
|
389
533
|
}
|
|
390
534
|
/**
|
|
391
535
|
* Re-execute the composition function in an isolated composition context
|
|
@@ -412,11 +556,17 @@ function collectOverridableOptionalFields(schemaDefinition, analysis) {
|
|
|
412
556
|
* effects a second time during this re-execution — see integration-skill
|
|
413
557
|
* rule #30 for the full contract.
|
|
414
558
|
*/
|
|
415
|
-
function captureHybridRunResources(compositionFn, schemaDefinition, analysis) {
|
|
559
|
+
function captureHybridRunResources(compositionFn, schemaDefinition, analysis, fieldsToOverride) {
|
|
416
560
|
try {
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
561
|
+
const allOverriddenFields = collectOverridableOptionalFields(schemaDefinition, analysis);
|
|
562
|
+
const overriddenFields = fieldsToOverride
|
|
563
|
+
? new Set(Array.from(allOverriddenFields).filter((field) => fieldsToOverride.has(field)))
|
|
564
|
+
: allOverriddenFields;
|
|
565
|
+
if (overriddenFields.size === 0) {
|
|
566
|
+
return { captured: {}, overriddenFields, overrideConditions: new Map() };
|
|
567
|
+
}
|
|
568
|
+
const overrideValues = new Map(Array.from(collectHybridOverrideValues(analysis)).filter(([field]) => overriddenFields.has(field)));
|
|
569
|
+
const overrideConditions = new Map(Array.from(collectHybridOverrideConditions(analysis)).filter(([field]) => overriddenFields.has(field)));
|
|
420
570
|
// Build the hybrid spec: the real schema proxy (so all other field
|
|
421
571
|
// accesses produce KubernetesRef values) wrapped in a Proxy that
|
|
422
572
|
// intercepts the overridden keys and returns `undefined`. Accessing
|
|
@@ -424,21 +574,8 @@ function captureHybridRunResources(compositionFn, schemaDefinition, analysis) {
|
|
|
424
574
|
// will throw — but that's exactly the code path the override is
|
|
425
575
|
// meant to skip, so the thrown access lives inside the `else`
|
|
426
576
|
// branch that this run intentionally does not execute.
|
|
427
|
-
const realSchema = createSchemaProxy();
|
|
428
|
-
const hybridSpec =
|
|
429
|
-
get(target, prop, receiver) {
|
|
430
|
-
if (typeof prop === 'string' && overriddenFields.has(prop)) {
|
|
431
|
-
return undefined;
|
|
432
|
-
}
|
|
433
|
-
return Reflect.get(target, prop, receiver);
|
|
434
|
-
},
|
|
435
|
-
has(target, prop) {
|
|
436
|
-
if (typeof prop === 'string' && overriddenFields.has(prop)) {
|
|
437
|
-
return false;
|
|
438
|
-
}
|
|
439
|
-
return Reflect.has(target, prop);
|
|
440
|
-
},
|
|
441
|
-
});
|
|
577
|
+
const realSchema = createSchemaProxy(schemaDefinition.spec?.json, schemaDefinition.status?.json);
|
|
578
|
+
const hybridSpec = createHybridSpecProxy(realSchema.spec, overriddenFields, overrideValues);
|
|
442
579
|
const tempCtx = createCompositionContext('hybrid-capture');
|
|
443
580
|
runWithCompositionContext(tempCtx, () => {
|
|
444
581
|
compositionFn(hybridSpec);
|
|
@@ -446,15 +583,74 @@ function captureHybridRunResources(compositionFn, schemaDefinition, analysis) {
|
|
|
446
583
|
return {
|
|
447
584
|
captured: tempCtx.resources,
|
|
448
585
|
overriddenFields,
|
|
586
|
+
overrideConditions,
|
|
449
587
|
};
|
|
450
588
|
}
|
|
451
589
|
catch {
|
|
452
590
|
// Best-effort: compositions that throw when running with a hybrid spec
|
|
453
591
|
// degrade gracefully — stub resources still cover the missing factories
|
|
454
592
|
// and the proxy-run resources are used as-is.
|
|
455
|
-
return { captured: {}, overriddenFields: new Set() };
|
|
593
|
+
return { captured: {}, overriddenFields: new Set(), overrideConditions: new Map() };
|
|
456
594
|
}
|
|
457
595
|
}
|
|
596
|
+
function createHybridSpecProxy(target, overriddenFields, overrideValues, pathPrefix = '') {
|
|
597
|
+
return new Proxy(target, {
|
|
598
|
+
get(proxyTarget, prop, receiver) {
|
|
599
|
+
if (typeof prop !== 'string') {
|
|
600
|
+
return Reflect.get(proxyTarget, prop, receiver);
|
|
601
|
+
}
|
|
602
|
+
const path = pathPrefix ? `${pathPrefix}.${prop}` : prop;
|
|
603
|
+
if (overriddenFields.has(path)) {
|
|
604
|
+
return overrideValues.has(path) ? overrideValues.get(path) : undefined;
|
|
605
|
+
}
|
|
606
|
+
const hasNestedOverride = Array.from(overriddenFields).some((field) => field.startsWith(`${path}.`));
|
|
607
|
+
const value = Reflect.get(proxyTarget, prop, receiver);
|
|
608
|
+
if (hasNestedOverride &&
|
|
609
|
+
value &&
|
|
610
|
+
(typeof value === 'object' || typeof value === 'function')) {
|
|
611
|
+
return createHybridSpecProxy(value, overriddenFields, overrideValues, path);
|
|
612
|
+
}
|
|
613
|
+
return value;
|
|
614
|
+
},
|
|
615
|
+
has(proxyTarget, prop) {
|
|
616
|
+
if (typeof prop !== 'string') {
|
|
617
|
+
return Reflect.has(proxyTarget, prop);
|
|
618
|
+
}
|
|
619
|
+
const path = pathPrefix ? `${pathPrefix}.${prop}` : prop;
|
|
620
|
+
if (overriddenFields.has(path)) {
|
|
621
|
+
return overrideValues.has(path);
|
|
622
|
+
}
|
|
623
|
+
return Reflect.has(proxyTarget, prop);
|
|
624
|
+
},
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
function cloneResourceTree(value) {
|
|
628
|
+
if (Array.isArray(value)) {
|
|
629
|
+
return value.map((item) => cloneResourceTree(item));
|
|
630
|
+
}
|
|
631
|
+
if (isPlainObject(value)) {
|
|
632
|
+
return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [key, cloneResourceTree(entryValue)]));
|
|
633
|
+
}
|
|
634
|
+
return value;
|
|
635
|
+
}
|
|
636
|
+
function structuralEquals(a, b) {
|
|
637
|
+
if (isLeafValue(a) || isLeafValue(b)) {
|
|
638
|
+
return leafEquals(a, b);
|
|
639
|
+
}
|
|
640
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
641
|
+
return a.length === b.length && a.every((item, index) => structuralEquals(item, b[index]));
|
|
642
|
+
}
|
|
643
|
+
if (isWalkableRecord(a) && isWalkableRecord(b)) {
|
|
644
|
+
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
645
|
+
for (const key of keys) {
|
|
646
|
+
if (!structuralEquals(a[key], b[key])) {
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
return true;
|
|
651
|
+
}
|
|
652
|
+
return a === b;
|
|
653
|
+
}
|
|
458
654
|
/**
|
|
459
655
|
* Walk `proxyRes` and `hybridRes` in parallel and replace any leaf value
|
|
460
656
|
* in `proxyRes` that differs from the corresponding leaf in `hybridRes`
|
|
@@ -482,59 +678,76 @@ function captureHybridRunResources(compositionFn, schemaDefinition, analysis) {
|
|
|
482
678
|
* are converted to their dollar-wrapped forms before embedding in
|
|
483
679
|
* the conditional.
|
|
484
680
|
*/
|
|
485
|
-
function applyDifferentialFieldConditionals(
|
|
486
|
-
walkAndConditionalize(
|
|
681
|
+
function applyDifferentialFieldConditionals(currentRes, baselineRes, hybridRes, overriddenFields, overrideConditions, nestedStatusCel, resourceIds) {
|
|
682
|
+
walkAndConditionalize(currentRes, baselineRes, hybridRes, overriddenFields, overrideConditions, nestedStatusCel, resourceIds);
|
|
487
683
|
}
|
|
488
|
-
function walkAndConditionalize(
|
|
489
|
-
if (Array.isArray(
|
|
490
|
-
|
|
684
|
+
function walkAndConditionalize(current, baseline, hybrid, overriddenFields, overrideConditions, nestedStatusCel, resourceIds) {
|
|
685
|
+
if (Array.isArray(current) && Array.isArray(baseline) && Array.isArray(hybrid)) {
|
|
686
|
+
if (baseline.length !== hybrid.length) {
|
|
687
|
+
return structuralEquals(current, baseline)
|
|
688
|
+
? buildCelConditional(baseline, hybrid, overriddenFields, overrideConditions, nestedStatusCel, resourceIds)
|
|
689
|
+
: current;
|
|
690
|
+
}
|
|
691
|
+
const maxLen = Math.max(current.length, hybrid.length);
|
|
491
692
|
for (let i = 0; i < maxLen; i++) {
|
|
492
|
-
const
|
|
693
|
+
const c = current[i];
|
|
694
|
+
const b = baseline[i];
|
|
493
695
|
const h = hybrid[i];
|
|
494
|
-
if (i >=
|
|
696
|
+
if (i >= current.length) {
|
|
495
697
|
// New element added by hybrid run — copy it over.
|
|
496
|
-
|
|
698
|
+
current.push(h);
|
|
497
699
|
continue;
|
|
498
700
|
}
|
|
499
701
|
if (i >= hybrid.length) {
|
|
500
702
|
// Element removed in hybrid — leave the proxy value as-is.
|
|
501
703
|
continue;
|
|
502
704
|
}
|
|
503
|
-
if (isLeafValue(
|
|
504
|
-
if (!leafEquals(
|
|
505
|
-
|
|
705
|
+
if (isLeafValue(b) && isLeafValue(h)) {
|
|
706
|
+
if (!leafEquals(b, h) && leafEquals(c, b)) {
|
|
707
|
+
current[i] = buildCelConditional(b, h, overriddenFields, overrideConditions, nestedStatusCel, resourceIds);
|
|
506
708
|
}
|
|
507
709
|
}
|
|
508
710
|
else {
|
|
509
|
-
walkAndConditionalize(
|
|
711
|
+
const conditionalized = walkAndConditionalize(c, b, h, overriddenFields, overrideConditions, nestedStatusCel, resourceIds);
|
|
712
|
+
if (conditionalized !== c) {
|
|
713
|
+
current[i] = conditionalized;
|
|
714
|
+
}
|
|
510
715
|
}
|
|
511
716
|
}
|
|
512
|
-
return
|
|
717
|
+
return current;
|
|
513
718
|
}
|
|
514
|
-
if (
|
|
515
|
-
const keys = new Set([
|
|
719
|
+
if (isWalkableRecord(current) && isWalkableRecord(baseline) && isWalkableRecord(hybrid)) {
|
|
720
|
+
const keys = new Set([
|
|
721
|
+
...Object.keys(current),
|
|
722
|
+
...Object.keys(baseline),
|
|
723
|
+
...Object.keys(hybrid),
|
|
724
|
+
]);
|
|
516
725
|
for (const key of keys) {
|
|
517
|
-
const
|
|
726
|
+
const c = current[key];
|
|
727
|
+
const b = baseline[key];
|
|
518
728
|
const h = hybrid[key];
|
|
519
729
|
if (!(key in hybrid)) {
|
|
520
|
-
continue;
|
|
730
|
+
continue;
|
|
521
731
|
}
|
|
522
|
-
if (!(key in
|
|
523
|
-
|
|
732
|
+
if (!(key in current)) {
|
|
733
|
+
current[key] = h;
|
|
524
734
|
continue;
|
|
525
735
|
}
|
|
526
|
-
if (isLeafValue(
|
|
527
|
-
if (!leafEquals(
|
|
528
|
-
|
|
736
|
+
if (isLeafValue(b) && isLeafValue(h)) {
|
|
737
|
+
if (!leafEquals(b, h) && leafEquals(c, b)) {
|
|
738
|
+
current[key] = buildCelConditional(b, h, overriddenFields, overrideConditions, nestedStatusCel, resourceIds);
|
|
529
739
|
}
|
|
530
740
|
}
|
|
531
741
|
else {
|
|
532
|
-
walkAndConditionalize(
|
|
742
|
+
const conditionalized = walkAndConditionalize(c, b, h, overriddenFields, overrideConditions, nestedStatusCel, resourceIds);
|
|
743
|
+
if (conditionalized !== c) {
|
|
744
|
+
current[key] = conditionalized;
|
|
745
|
+
}
|
|
533
746
|
}
|
|
534
747
|
}
|
|
535
|
-
return
|
|
748
|
+
return current;
|
|
536
749
|
}
|
|
537
|
-
return
|
|
750
|
+
return current;
|
|
538
751
|
}
|
|
539
752
|
function isLeafValue(v) {
|
|
540
753
|
return (v === null ||
|
|
@@ -542,9 +755,218 @@ function isLeafValue(v) {
|
|
|
542
755
|
typeof v === 'string' ||
|
|
543
756
|
typeof v === 'number' ||
|
|
544
757
|
typeof v === 'boolean' ||
|
|
758
|
+
isCelExpressionLike(v) ||
|
|
545
759
|
// KubernetesRef proxies register as functions (typeof fn is 'function')
|
|
546
760
|
typeof v === 'function');
|
|
547
761
|
}
|
|
762
|
+
function runResourceStatusBranch(compositionFn, schemaDefinition, analysis, ternary, desiredConditionValue) {
|
|
763
|
+
const branchCtx = createCompositionContext('resource-status-branch', {
|
|
764
|
+
isReExecution: true,
|
|
765
|
+
});
|
|
766
|
+
branchCtx.liveStatusMap = createResourceStatusBranchMap(analysis, ternary, desiredConditionValue);
|
|
767
|
+
const branchSchema = createSchemaProxy(schemaDefinition?.spec?.json, schemaDefinition?.status?.json);
|
|
768
|
+
const specOverrides = createSpecConditionOverrideMap(ternary.conditionExpression, desiredConditionValue);
|
|
769
|
+
const branchSpec = specOverrides.size > 0
|
|
770
|
+
? createSpecOverrideProxy(branchSchema.spec, specOverrides)
|
|
771
|
+
: branchSchema.spec;
|
|
772
|
+
runWithCompositionContext(branchCtx, () => {
|
|
773
|
+
runInStatusBuilderContext(() => {
|
|
774
|
+
compositionFn(branchSpec);
|
|
775
|
+
});
|
|
776
|
+
});
|
|
777
|
+
return branchCtx;
|
|
778
|
+
}
|
|
779
|
+
function createResourceStatusBranchMap(analysis, ternary, desiredConditionValue) {
|
|
780
|
+
const conditionExpression = ternary.conditionExpression ?? `${ternary.variableName}.status.${ternary.statusField}`;
|
|
781
|
+
const statusRefs = collectStatusRefs(conditionExpression);
|
|
782
|
+
if (statusRefs.length === 0) {
|
|
783
|
+
statusRefs.push({ variableName: ternary.variableName, statusField: ternary.statusField });
|
|
784
|
+
}
|
|
785
|
+
const statusMap = new Map();
|
|
786
|
+
for (const statusRef of statusRefs) {
|
|
787
|
+
const resourceId = analysis.variableToResourceId.get(statusRef.variableName) ?? statusRef.variableName;
|
|
788
|
+
const existing = statusMap.get(resourceId) ?? {};
|
|
789
|
+
setNestedBranchStatusValue(existing, statusRef.statusField, getBranchStatusValue(conditionExpression, `${statusRef.variableName}.status.${statusRef.statusField}`, desiredConditionValue));
|
|
790
|
+
statusMap.set(resourceId, existing);
|
|
791
|
+
}
|
|
792
|
+
return statusMap;
|
|
793
|
+
}
|
|
794
|
+
function setNestedBranchStatusValue(target, statusField, value) {
|
|
795
|
+
const parts = statusField.split('.').filter(Boolean);
|
|
796
|
+
if (parts.length === 0)
|
|
797
|
+
return;
|
|
798
|
+
let cursor = target;
|
|
799
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
800
|
+
const part = parts[i];
|
|
801
|
+
if (!part)
|
|
802
|
+
continue;
|
|
803
|
+
const next = cursor[part];
|
|
804
|
+
if (!isPlainObject(next)) {
|
|
805
|
+
cursor[part] = {};
|
|
806
|
+
}
|
|
807
|
+
cursor = cursor[part];
|
|
808
|
+
}
|
|
809
|
+
const leaf = parts[parts.length - 1];
|
|
810
|
+
if (leaf) {
|
|
811
|
+
cursor[leaf] = value;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
function collectStatusRefs(conditionExpression) {
|
|
815
|
+
const refs = [];
|
|
816
|
+
const seen = new Set();
|
|
817
|
+
const statusRefPattern = /\b([A-Za-z_$][\w$]*)\.status\.([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g;
|
|
818
|
+
for (const match of conditionExpression.matchAll(statusRefPattern)) {
|
|
819
|
+
const variableName = match[1];
|
|
820
|
+
const statusField = match[2];
|
|
821
|
+
if (!variableName || !statusField)
|
|
822
|
+
continue;
|
|
823
|
+
const key = `${variableName}:${statusField}`;
|
|
824
|
+
if (seen.has(key))
|
|
825
|
+
continue;
|
|
826
|
+
seen.add(key);
|
|
827
|
+
refs.push({ variableName, statusField });
|
|
828
|
+
}
|
|
829
|
+
return refs;
|
|
830
|
+
}
|
|
831
|
+
function createSpecConditionOverrideMap(conditionExpression, desiredConditionValue) {
|
|
832
|
+
const overrides = new Map();
|
|
833
|
+
if (!conditionExpression)
|
|
834
|
+
return overrides;
|
|
835
|
+
const specRefPattern = /\b(?:schema\.)?spec\.([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)/g;
|
|
836
|
+
for (const match of conditionExpression.matchAll(specRefPattern)) {
|
|
837
|
+
const specPath = match[1];
|
|
838
|
+
const fullRef = match[0];
|
|
839
|
+
if (!specPath || !fullRef || overrides.has(specPath))
|
|
840
|
+
continue;
|
|
841
|
+
overrides.set(specPath, getBranchStatusValue(conditionExpression, fullRef, desiredConditionValue));
|
|
842
|
+
}
|
|
843
|
+
return overrides;
|
|
844
|
+
}
|
|
845
|
+
function createSpecOverrideProxy(target, overrides, path = []) {
|
|
846
|
+
return new Proxy(target, {
|
|
847
|
+
get(obj, prop, receiver) {
|
|
848
|
+
if (typeof prop !== 'string')
|
|
849
|
+
return Reflect.get(obj, prop, receiver);
|
|
850
|
+
const fullPath = [...path, prop].join('.');
|
|
851
|
+
if (overrides.has(fullPath))
|
|
852
|
+
return overrides.get(fullPath);
|
|
853
|
+
const hasNestedOverride = [...overrides.keys()].some((key) => key.startsWith(`${fullPath}.`));
|
|
854
|
+
const value = Reflect.get(obj, prop, receiver);
|
|
855
|
+
if (hasNestedOverride &&
|
|
856
|
+
value &&
|
|
857
|
+
(typeof value === 'object' || typeof value === 'function')) {
|
|
858
|
+
return createSpecOverrideProxy(value, overrides, [
|
|
859
|
+
...path,
|
|
860
|
+
prop,
|
|
861
|
+
]);
|
|
862
|
+
}
|
|
863
|
+
return value;
|
|
864
|
+
},
|
|
865
|
+
ownKeys: (obj) => Reflect.ownKeys(obj),
|
|
866
|
+
getOwnPropertyDescriptor: (obj, prop) => Reflect.getOwnPropertyDescriptor(obj, prop),
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
function getBranchStatusValue(conditionExpression, statusRefExpression, desiredConditionValue) {
|
|
870
|
+
const escapedRef = statusRefExpression.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
871
|
+
const comparison = conditionExpression.match(new RegExp(`${escapedRef}\\s*(>=|>|<=|<|==|!=)\\s*(-?\\d+(?:\\.\\d+)?)`));
|
|
872
|
+
if (comparison?.[1] && comparison[2] !== undefined) {
|
|
873
|
+
const operator = comparison[1];
|
|
874
|
+
const numberValue = Number(comparison[2]);
|
|
875
|
+
if (operator === '>=')
|
|
876
|
+
return desiredConditionValue ? numberValue : numberValue - 1;
|
|
877
|
+
if (operator === '>')
|
|
878
|
+
return desiredConditionValue ? numberValue + 1 : numberValue;
|
|
879
|
+
if (operator === '<=')
|
|
880
|
+
return desiredConditionValue ? numberValue : numberValue + 1;
|
|
881
|
+
if (operator === '<')
|
|
882
|
+
return desiredConditionValue ? numberValue - 1 : numberValue;
|
|
883
|
+
if (operator === '==')
|
|
884
|
+
return desiredConditionValue ? numberValue : numberValue + 1;
|
|
885
|
+
if (operator === '!=')
|
|
886
|
+
return desiredConditionValue ? numberValue + 1 : numberValue;
|
|
887
|
+
}
|
|
888
|
+
const stringComparison = conditionExpression.match(new RegExp(`${escapedRef}\\s*(==|!=)\\s*(['"])(.*?)\\2`));
|
|
889
|
+
if (stringComparison?.[1] && stringComparison[3] !== undefined) {
|
|
890
|
+
const operator = stringComparison[1];
|
|
891
|
+
const stringValue = stringComparison[3];
|
|
892
|
+
if (operator === '==')
|
|
893
|
+
return desiredConditionValue ? stringValue : `__typekro_not_${stringValue}`;
|
|
894
|
+
if (operator === '!=')
|
|
895
|
+
return desiredConditionValue ? `__typekro_not_${stringValue}` : stringValue;
|
|
896
|
+
}
|
|
897
|
+
const booleanComparison = conditionExpression.match(new RegExp(`${escapedRef}\\s*(==|!=)\\s*(true|false)`));
|
|
898
|
+
if (booleanComparison?.[1] && booleanComparison[2] !== undefined) {
|
|
899
|
+
const operator = booleanComparison[1];
|
|
900
|
+
const booleanValue = booleanComparison[2] === 'true';
|
|
901
|
+
if (operator === '==')
|
|
902
|
+
return desiredConditionValue ? booleanValue : !booleanValue;
|
|
903
|
+
if (operator === '!=')
|
|
904
|
+
return desiredConditionValue ? !booleanValue : booleanValue;
|
|
905
|
+
}
|
|
906
|
+
const negatedRef = new RegExp(`!\\s*${escapedRef}(?![A-Za-z0-9_$.])`).test(conditionExpression);
|
|
907
|
+
return negatedRef ? !desiredConditionValue : desiredConditionValue;
|
|
908
|
+
}
|
|
909
|
+
function applyResourceStatusBranchDiff(targetRes, trueRes, falseRes, conditionCel, nestedStatusCel, resourceIds) {
|
|
910
|
+
for (const key of new Set([...Object.keys(trueRes), ...Object.keys(falseRes)])) {
|
|
911
|
+
if (key === '__resourceId' || key === 'id' || key.startsWith('__'))
|
|
912
|
+
continue;
|
|
913
|
+
const tv = trueRes[key];
|
|
914
|
+
const fv = falseRes[key];
|
|
915
|
+
if (tv === undefined && fv !== undefined) {
|
|
916
|
+
const falseRepr = celValueRepr(fv, nestedStatusCel, resourceIds);
|
|
917
|
+
targetRes[key] = `\${${conditionCel} ? omit() : ${falseRepr}}`;
|
|
918
|
+
continue;
|
|
919
|
+
}
|
|
920
|
+
if (fv === undefined && tv !== undefined) {
|
|
921
|
+
const trueRepr = celValueRepr(tv, nestedStatusCel, resourceIds);
|
|
922
|
+
targetRes[key] = `\${${conditionCel} ? ${trueRepr} : omit()}`;
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
if (tv === undefined || fv === undefined)
|
|
926
|
+
continue;
|
|
927
|
+
if (isCelExpressionLike(tv) || isCelExpressionLike(fv)) {
|
|
928
|
+
if (!leafEquals(tv, fv)) {
|
|
929
|
+
const trueRepr = celValueRepr(tv, nestedStatusCel, resourceIds);
|
|
930
|
+
const falseRepr = celValueRepr(fv, nestedStatusCel, resourceIds);
|
|
931
|
+
targetRes[key] = `\${${conditionCel} ? ${trueRepr} : ${falseRepr}}`;
|
|
932
|
+
}
|
|
933
|
+
continue;
|
|
934
|
+
}
|
|
935
|
+
const targetValue = targetRes[key];
|
|
936
|
+
if (isPlainObject(tv) && isPlainObject(fv)) {
|
|
937
|
+
if (!isPlainObject(targetValue))
|
|
938
|
+
targetRes[key] = {};
|
|
939
|
+
applyResourceStatusBranchDiff(targetRes[key], tv, fv, conditionCel, nestedStatusCel, resourceIds);
|
|
940
|
+
}
|
|
941
|
+
else if (Array.isArray(tv) && Array.isArray(fv) && tv.length === fv.length) {
|
|
942
|
+
if (!Array.isArray(targetValue))
|
|
943
|
+
targetRes[key] = [...tv];
|
|
944
|
+
const targetArray = targetRes[key];
|
|
945
|
+
for (let i = 0; i < tv.length; i++) {
|
|
946
|
+
if (isPlainObject(tv[i]) && isPlainObject(fv[i])) {
|
|
947
|
+
if (!isPlainObject(targetArray[i]))
|
|
948
|
+
targetArray[i] = {};
|
|
949
|
+
applyResourceStatusBranchDiff(targetArray[i], tv[i], fv[i], conditionCel, nestedStatusCel, resourceIds);
|
|
950
|
+
}
|
|
951
|
+
else if (!leafEquals(tv[i], fv[i])) {
|
|
952
|
+
const trueRepr = celValueRepr(tv[i], nestedStatusCel, resourceIds);
|
|
953
|
+
const falseRepr = celValueRepr(fv[i], nestedStatusCel, resourceIds);
|
|
954
|
+
targetArray[i] = `\${${conditionCel} ? ${trueRepr} : ${falseRepr}}`;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
else if (Array.isArray(tv) && Array.isArray(fv) && tv.length !== fv.length) {
|
|
959
|
+
const trueRepr = celValueRepr(tv, nestedStatusCel, resourceIds);
|
|
960
|
+
const falseRepr = celValueRepr(fv, nestedStatusCel, resourceIds);
|
|
961
|
+
targetRes[key] = `\${${conditionCel} ? ${trueRepr} : ${falseRepr}}`;
|
|
962
|
+
}
|
|
963
|
+
else if (!leafEquals(tv, fv)) {
|
|
964
|
+
const trueRepr = celValueRepr(tv, nestedStatusCel, resourceIds);
|
|
965
|
+
const falseRepr = celValueRepr(fv, nestedStatusCel, resourceIds);
|
|
966
|
+
targetRes[key] = `\${${conditionCel} ? ${trueRepr} : ${falseRepr}}`;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
}
|
|
548
970
|
function leafEquals(a, b) {
|
|
549
971
|
// For KubernetesRef proxies, compare their string coercions (marker tokens).
|
|
550
972
|
if (typeof a === 'function' || typeof b === 'function') {
|
|
@@ -552,8 +974,50 @@ function leafEquals(a, b) {
|
|
|
552
974
|
}
|
|
553
975
|
return a === b;
|
|
554
976
|
}
|
|
977
|
+
function getNestedResourceStatusTargetIds(resources, nestedCompositionIds) {
|
|
978
|
+
if (!nestedCompositionIds || nestedCompositionIds.size === 0)
|
|
979
|
+
return [];
|
|
980
|
+
return Object.entries(resources)
|
|
981
|
+
.filter(([resourceId, resource]) => [...nestedCompositionIds].some((nestedId) => isNestedCompositionChild(resourceId, resource, nestedId)))
|
|
982
|
+
.map(([resourceId]) => resourceId);
|
|
983
|
+
}
|
|
984
|
+
function isNestedCompositionChild(resourceId, resource, nestedId) {
|
|
985
|
+
if (resourceId === nestedId)
|
|
986
|
+
return true;
|
|
987
|
+
const boundaryChar = resourceId[nestedId.length];
|
|
988
|
+
if (resourceId.startsWith(nestedId) &&
|
|
989
|
+
boundaryChar !== undefined &&
|
|
990
|
+
/[A-Z_-]/.test(boundaryChar)) {
|
|
991
|
+
return true;
|
|
992
|
+
}
|
|
993
|
+
const aliases = getMetadataField(resource, 'resourceAliases');
|
|
994
|
+
return (aliases?.some((alias) => {
|
|
995
|
+
if (alias === nestedId)
|
|
996
|
+
return true;
|
|
997
|
+
const aliasBoundaryChar = alias[nestedId.length];
|
|
998
|
+
return (alias.startsWith(nestedId) &&
|
|
999
|
+
aliasBoundaryChar !== undefined &&
|
|
1000
|
+
/[A-Z_-]/.test(aliasBoundaryChar));
|
|
1001
|
+
}) ?? false);
|
|
1002
|
+
}
|
|
555
1003
|
function isPlainObject(v) {
|
|
556
|
-
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
1004
|
+
return typeof v === 'object' && v !== null && !Array.isArray(v) && !isCelExpressionLike(v);
|
|
1005
|
+
}
|
|
1006
|
+
function isWalkableRecord(v) {
|
|
1007
|
+
if (isPlainObject(v)) {
|
|
1008
|
+
return true;
|
|
1009
|
+
}
|
|
1010
|
+
return typeof v === 'function' && Object.keys(v).length > 0;
|
|
1011
|
+
}
|
|
1012
|
+
/** Duck-type check for CelExpression objects — avoids importing from cel.ts (cycle risk). */
|
|
1013
|
+
function isCelExpressionLike(v) {
|
|
1014
|
+
if (typeof v !== 'object' || v === null)
|
|
1015
|
+
return false;
|
|
1016
|
+
// Plain Cel.expr() objects carry the symbol brand; template expressions also
|
|
1017
|
+
// carry `__isTemplate`. Support both shapes without importing cel.ts.
|
|
1018
|
+
return ('expression' in v &&
|
|
1019
|
+
typeof v.expression === 'string' &&
|
|
1020
|
+
(v[CEL_EXPRESSION_BRAND] === true || '__isTemplate' in v));
|
|
557
1021
|
}
|
|
558
1022
|
/**
|
|
559
1023
|
* Build a CEL conditional string from two diverging leaf values.
|
|
@@ -564,11 +1028,44 @@ function isPlainObject(v) {
|
|
|
564
1028
|
* `${has(schema.spec.X) ? <proxy repr> : <hybrid repr>}` that later
|
|
565
1029
|
* serialization phases treat as a final CEL expression.
|
|
566
1030
|
*/
|
|
567
|
-
function buildCelConditional(proxyValue, hybridValue, overriddenFields) {
|
|
1031
|
+
function buildCelConditional(proxyValue, hybridValue, overriddenFields, overrideConditions, nestedStatusCel, resourceIds) {
|
|
568
1032
|
const field = pickConditionField(proxyValue, hybridValue, overriddenFields);
|
|
569
|
-
const proxyRepr = celValueRepr(proxyValue);
|
|
570
|
-
const hybridRepr = celValueRepr(hybridValue);
|
|
571
|
-
|
|
1033
|
+
const proxyRepr = celValueRepr(proxyValue, nestedStatusCel, resourceIds);
|
|
1034
|
+
const hybridRepr = celValueRepr(hybridValue, nestedStatusCel, resourceIds);
|
|
1035
|
+
const explicitCondition = overrideConditions.get(field);
|
|
1036
|
+
if (explicitCondition) {
|
|
1037
|
+
return `\${${explicitCondition} ? ${proxyRepr} : ${hybridRepr}}`;
|
|
1038
|
+
}
|
|
1039
|
+
// Chain has() guards when the proxy value references a sub-field deeper
|
|
1040
|
+
// than the controlling optional field. A single has(schema.spec.X) is
|
|
1041
|
+
// insufficient when the value accesses X.Y — the user may provide X: {}
|
|
1042
|
+
// without Y, and KRO would fail with "no such key: Y".
|
|
1043
|
+
const guardField = `schema.spec.${field}`;
|
|
1044
|
+
let guard = `has(${guardField})`;
|
|
1045
|
+
// Extract the full schema path from the proxy repr to check depth.
|
|
1046
|
+
// proxyRepr may be a bare path like `schema.spec.cnpgOperator.version`
|
|
1047
|
+
// or wrapped in string() like `string(schema.spec.cnpgOperator.version)`.
|
|
1048
|
+
// Chain has() guards for ALL intermediate levels between the controlling
|
|
1049
|
+
// field and the leaf. For `cnpgOperator.monitoring.enabled`, we need:
|
|
1050
|
+
// has(cnpgOperator) && has(cnpgOperator.monitoring) && has(cnpgOperator.monitoring.enabled)
|
|
1051
|
+
const schemaPathMatch = proxyRepr.match(/schema\.spec\.([a-zA-Z0-9_.]+)/);
|
|
1052
|
+
if (schemaPathMatch) {
|
|
1053
|
+
const fullRefPath = schemaPathMatch[1]?.replace(/\.+$/, '');
|
|
1054
|
+
if (!fullRefPath)
|
|
1055
|
+
return `\${has(${guardField}) ? ${proxyRepr} : ${hybridRepr}}`;
|
|
1056
|
+
const fullPath = `schema.spec.${fullRefPath}`;
|
|
1057
|
+
if (fullPath !== guardField && fullPath.startsWith(`${guardField}.`)) {
|
|
1058
|
+
const guardSegments = field.split('.').length;
|
|
1059
|
+
const leafSegments = fullRefPath.split('.');
|
|
1060
|
+
const guards = [`has(${guardField})`];
|
|
1061
|
+
for (let j = guardSegments + 1; j <= leafSegments.length; j++) {
|
|
1062
|
+
const intermediatePath = `schema.spec.${leafSegments.slice(0, j).join('.')}`;
|
|
1063
|
+
guards.push(`has(${intermediatePath})`);
|
|
1064
|
+
}
|
|
1065
|
+
guard = guards.join(' && ');
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
return `\${${guard} ? ${proxyRepr} : ${hybridRepr}}`;
|
|
572
1069
|
}
|
|
573
1070
|
/**
|
|
574
1071
|
* Pick the "controlling" optional field for a diverging leaf. If exactly
|
|
@@ -612,11 +1109,18 @@ function pickConditionField(proxyValue, hybridValue, overriddenFields) {
|
|
|
612
1109
|
* result is valid CEL, not just a raw string)
|
|
613
1110
|
* - Numbers and booleans are emitted verbatim
|
|
614
1111
|
*/
|
|
615
|
-
|
|
1112
|
+
// Re-export from shared utility for local use. This was previously an
|
|
1113
|
+
// inline copy; the canonical implementation lives in utils/cel-escape.ts.
|
|
1114
|
+
import { escapeCelString as escapeCelLiteral } from '../../utils/cel-escape.js';
|
|
1115
|
+
function celValueRepr(value, nestedStatusCel, resourceIds) {
|
|
616
1116
|
if (value === null || value === undefined)
|
|
617
1117
|
return '""';
|
|
618
1118
|
if (typeof value === 'number' || typeof value === 'boolean')
|
|
619
1119
|
return String(value);
|
|
1120
|
+
// CelExpression object — use the expression string directly.
|
|
1121
|
+
if (isCelExpressionLike(value)) {
|
|
1122
|
+
return unwrapKroExpression(finalizeCelForKro(value.expression, nestedStatusCel, createBranchCelContext(nestedStatusCel, resourceIds)));
|
|
1123
|
+
}
|
|
620
1124
|
if (typeof value === 'function') {
|
|
621
1125
|
// KubernetesRef proxy — toString yields the marker token which we
|
|
622
1126
|
// convert to a bare CEL path via the marker → CEL rules.
|
|
@@ -627,16 +1131,40 @@ function celValueRepr(value) {
|
|
|
627
1131
|
return markerStringToCelExpr(value);
|
|
628
1132
|
}
|
|
629
1133
|
// Plain string literal — escape for CEL embedding
|
|
630
|
-
return `"${value
|
|
1134
|
+
return `"${escapeCelLiteral(value)}"`;
|
|
1135
|
+
}
|
|
1136
|
+
if (Array.isArray(value)) {
|
|
1137
|
+
return `[${value.map((item) => celValueRepr(item, nestedStatusCel, resourceIds)).join(', ')}]`;
|
|
1138
|
+
}
|
|
1139
|
+
if (isPlainObject(value)) {
|
|
1140
|
+
return `{${Object.entries(value)
|
|
1141
|
+
.map(([key, entryValue]) => `"${escapeCelLiteral(key)}": ${celValueRepr(entryValue, nestedStatusCel, resourceIds)}`)
|
|
1142
|
+
.join(', ')}}`;
|
|
631
1143
|
}
|
|
632
1144
|
return '""';
|
|
633
1145
|
}
|
|
1146
|
+
function createBranchCelContext(nestedStatusCel, resourceIds) {
|
|
1147
|
+
if (!nestedStatusCel && !resourceIds)
|
|
1148
|
+
return undefined;
|
|
1149
|
+
return {
|
|
1150
|
+
celPrefix: '',
|
|
1151
|
+
resourceIdStrategy: 'deterministic',
|
|
1152
|
+
...(nestedStatusCel ? { nestedStatusCel } : {}),
|
|
1153
|
+
...(resourceIds ? { resourceIds } : {}),
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
function unwrapKroExpression(value) {
|
|
1157
|
+
if (value.startsWith('${') && value.endsWith('}') && value.indexOf('${', 2) === -1) {
|
|
1158
|
+
return value.slice(2, -1);
|
|
1159
|
+
}
|
|
1160
|
+
return value;
|
|
1161
|
+
}
|
|
634
1162
|
/**
|
|
635
1163
|
* Convert a single-marker string (the whole string is one marker) to
|
|
636
1164
|
* its bare CEL path form: `schema.spec.X` or `resources.X.field`.
|
|
637
1165
|
*/
|
|
638
1166
|
function markerStringToCelBare(str) {
|
|
639
|
-
const m = str.match(
|
|
1167
|
+
const m = str.match(new RegExp(`^${KUBERNETES_REF_MARKER_SOURCE}$`));
|
|
640
1168
|
if (!m)
|
|
641
1169
|
return markerStringToCelExpr(str);
|
|
642
1170
|
const [, resourceId, fieldPath] = m;
|
|
@@ -648,8 +1176,9 @@ function markerStringToCelBare(str) {
|
|
|
648
1176
|
* embedding inside a CEL ternary.
|
|
649
1177
|
*/
|
|
650
1178
|
function markerStringToCelExpr(str) {
|
|
1179
|
+
const markerSource = KUBERNETES_REF_MARKER_SOURCE;
|
|
651
1180
|
// Fast path: whole string is a single marker
|
|
652
|
-
const singleMatch = str.match(
|
|
1181
|
+
const singleMatch = str.match(new RegExp(`^${markerSource}$`));
|
|
653
1182
|
if (singleMatch) {
|
|
654
1183
|
const [, resourceId, fieldPath] = singleMatch;
|
|
655
1184
|
return resourceId === '__schema__' ? `schema.${fieldPath}` : `${resourceId}.${fieldPath}`;
|
|
@@ -657,15 +1186,19 @@ function markerStringToCelExpr(str) {
|
|
|
657
1186
|
// Slow path: interleave literal text and markers via CEL string concatenation
|
|
658
1187
|
const parts = [];
|
|
659
1188
|
let lastIndex = 0;
|
|
660
|
-
const pattern =
|
|
1189
|
+
const pattern = new RegExp(markerSource, 'g');
|
|
661
1190
|
let m = pattern.exec(str);
|
|
662
1191
|
while (m !== null) {
|
|
663
1192
|
if (m.index > lastIndex) {
|
|
664
1193
|
const literal = str.slice(lastIndex, m.index);
|
|
665
|
-
parts.push(`"${literal
|
|
1194
|
+
parts.push(`"${escapeCelLiteral(literal)}"`);
|
|
666
1195
|
}
|
|
667
1196
|
const resourceId = m[1];
|
|
668
1197
|
const fieldPath = m[2];
|
|
1198
|
+
if (!resourceId || !fieldPath) {
|
|
1199
|
+
m = pattern.exec(str);
|
|
1200
|
+
continue;
|
|
1201
|
+
}
|
|
669
1202
|
const celPath = resourceId === '__schema__' ? `schema.${fieldPath}` : `${resourceId}.${fieldPath}`;
|
|
670
1203
|
parts.push(`string(${celPath})`);
|
|
671
1204
|
lastIndex = m.index + m[0].length;
|
|
@@ -673,9 +1206,10 @@ function markerStringToCelExpr(str) {
|
|
|
673
1206
|
}
|
|
674
1207
|
if (lastIndex < str.length) {
|
|
675
1208
|
const literal = str.slice(lastIndex);
|
|
676
|
-
parts.push(`"${literal
|
|
1209
|
+
parts.push(`"${escapeCelLiteral(literal)}"`);
|
|
677
1210
|
}
|
|
678
|
-
|
|
1211
|
+
const [firstPart] = parts;
|
|
1212
|
+
return parts.length === 1 && firstPart !== undefined ? firstPart : parts.join(' + ');
|
|
679
1213
|
}
|
|
680
1214
|
// =============================================================================
|
|
681
1215
|
// Extracted helper: Direct factory status re-analysis
|
|
@@ -828,10 +1362,14 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
|
|
|
828
1362
|
const schemaDefinition = {
|
|
829
1363
|
apiVersion: definition.apiVersion || 'v1alpha1',
|
|
830
1364
|
kind: definition.kind,
|
|
1365
|
+
...(definition.group && { group: definition.group }),
|
|
831
1366
|
spec: definition.spec,
|
|
832
1367
|
status: definition.status,
|
|
833
1368
|
};
|
|
834
|
-
|
|
1369
|
+
// Pass the Arktype JSON so the proxy is shape-aware — spread
|
|
1370
|
+
// (`{ ...spec.X }`) and `Object.keys(spec.X)` enumerate declared
|
|
1371
|
+
// fields instead of returning an opaque empty object.
|
|
1372
|
+
const schema = createSchemaProxy(definition.spec?.json, definition.status?.json);
|
|
835
1373
|
const builderResult = resourceBuilder(schema);
|
|
836
1374
|
const { resources: resourcesWithKeys, closures } = separateResourcesAndClosures(builderResult);
|
|
837
1375
|
// 3. Analyze status builder and convert JS expressions to CEL
|
|
@@ -856,6 +1394,18 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
|
|
|
856
1394
|
// Evaluate and optimize CEL expressions
|
|
857
1395
|
const evaluationContext = { resources: resourcesWithKeys, schema };
|
|
858
1396
|
const { mappings: optimizedStatusMappings, optimizations } = optimizeStatusMappings(analyzedStatusMappings, evaluationContext);
|
|
1397
|
+
for (const metadataKey of [
|
|
1398
|
+
'__originalCompositionFn',
|
|
1399
|
+
'__nestedCompositionFns',
|
|
1400
|
+
'__nestedCompositionDefinitions',
|
|
1401
|
+
'__nestedCompositionResources',
|
|
1402
|
+
'__nestedCompositionSpecMappings',
|
|
1403
|
+
]) {
|
|
1404
|
+
const descriptor = Object.getOwnPropertyDescriptor(statusMappings, metadataKey);
|
|
1405
|
+
if (descriptor) {
|
|
1406
|
+
Object.defineProperty(optimizedStatusMappings, metadataKey, descriptor);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
859
1409
|
if (optimizations.length > 0) {
|
|
860
1410
|
serializationLogger.info('CEL expression optimizations applied', { optimizations });
|
|
861
1411
|
}
|
|
@@ -890,6 +1440,11 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
|
|
|
890
1440
|
statusMappings: directStatusMappings,
|
|
891
1441
|
compositionFn: declarativeCompositionFn,
|
|
892
1442
|
compositionDefinition: definition,
|
|
1443
|
+
...(this._singletonDefinitions
|
|
1444
|
+
? {
|
|
1445
|
+
singletonDefinitions: this._singletonDefinitions,
|
|
1446
|
+
}
|
|
1447
|
+
: {}),
|
|
893
1448
|
});
|
|
894
1449
|
}
|
|
895
1450
|
else if (mode === 'kro') {
|
|
@@ -898,13 +1453,26 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
|
|
|
898
1453
|
closures,
|
|
899
1454
|
factoryType: 'kro',
|
|
900
1455
|
compositionFn: declarativeCompositionFn,
|
|
1456
|
+
compositionAnalysis,
|
|
1457
|
+
...(this._singletonDefinitions
|
|
1458
|
+
? {
|
|
1459
|
+
singletonDefinitions: this._singletonDefinitions,
|
|
1460
|
+
}
|
|
1461
|
+
: {}),
|
|
901
1462
|
});
|
|
902
1463
|
}
|
|
903
1464
|
else {
|
|
904
1465
|
throw new ValidationError(`Unsupported factory mode: ${mode}`, 'ResourceGraphDefinition', definition.name, 'mode', ['Use "kro" or "direct" as the factory mode']);
|
|
905
1466
|
}
|
|
906
1467
|
},
|
|
907
|
-
toYaml() {
|
|
1468
|
+
toYaml(specOrOptions) {
|
|
1469
|
+
if (specOrOptions !== undefined) {
|
|
1470
|
+
if (isToYamlOptions(specOrOptions)) {
|
|
1471
|
+
const factory = this.factory('kro', specOrOptions);
|
|
1472
|
+
return factory.toYaml();
|
|
1473
|
+
}
|
|
1474
|
+
return this.factory('kro').toYaml(specOrOptions);
|
|
1475
|
+
}
|
|
908
1476
|
// Apply composition body analysis results (guard: only once)
|
|
909
1477
|
if (compositionAnalysis && !analysisState.appliedToResources) {
|
|
910
1478
|
analysisState.appliedToResources = true;
|
|
@@ -921,10 +1489,13 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
|
|
|
921
1489
|
// Collect nested composition status CEL mappings from the composition context.
|
|
922
1490
|
// These enable inlining the inner composition's real CEL expressions instead
|
|
923
1491
|
// of referencing virtual nested composition IDs.
|
|
924
|
-
// Extract nested composition status CEL mappings attached by
|
|
925
|
-
//
|
|
926
|
-
//
|
|
927
|
-
|
|
1492
|
+
// Extract nested composition status CEL mappings attached by
|
|
1493
|
+
// executeCompositionCore via Reflect.set. Must use
|
|
1494
|
+
// Object.getOwnPropertyDescriptor to bypass the Enhanced proxy's
|
|
1495
|
+
// get handler which would return a KubernetesRef instead of the
|
|
1496
|
+
// actual Record<string, string>.
|
|
1497
|
+
const nestedStatusDescriptor = Object.getOwnPropertyDescriptor(statusMappings, '__nestedStatusCel');
|
|
1498
|
+
const nestedStatusCel = nestedStatusDescriptor?.value ?? {};
|
|
928
1499
|
serializationLogger.debug('Nested status CEL extraction', {
|
|
929
1500
|
hasNestedStatusCel: Object.keys(nestedStatusCel).length > 0,
|
|
930
1501
|
keys: Object.keys(nestedStatusCel),
|
|
@@ -934,6 +1505,17 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
|
|
|
934
1505
|
if (definition.group) {
|
|
935
1506
|
kroSchema.group = definition.group;
|
|
936
1507
|
}
|
|
1508
|
+
// Attach nested status CEL mappings to the schema as a non-enumerable
|
|
1509
|
+
// property (same pattern as __ternaryConditionals, __omitFields).
|
|
1510
|
+
// Non-enumerable so it doesn't appear in the YAML output, but
|
|
1511
|
+
// accessible via KroSimpleSchemaWithMetadata for the YAML serializer
|
|
1512
|
+
// to resolve virtual composition IDs in resource templates.
|
|
1513
|
+
if (Object.keys(nestedStatusCel).length > 0) {
|
|
1514
|
+
Object.defineProperty(kroSchema, '__nestedStatusCel', {
|
|
1515
|
+
value: nestedStatusCel,
|
|
1516
|
+
enumerable: false,
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
937
1519
|
// Inject status overrides into schema status section.
|
|
938
1520
|
// Convert "..." to '...' in CEL string literals for YAML compatibility.
|
|
939
1521
|
const statusOverrides = compositionAnalysis?.statusOverrides ?? [];
|
|
@@ -955,7 +1537,7 @@ function createTypedResourceGraph(definition, resourceBuilder, statusBuilder, op
|
|
|
955
1537
|
if (!analysisState.ternaryAndOmitApplied) {
|
|
956
1538
|
analysisState.ternaryAndOmitApplied = true;
|
|
957
1539
|
if (kroSchema.__ternaryConditionals?.length) {
|
|
958
|
-
applyTernaryConditionalsToResources(resourcesWithKeys, kroSchema.__ternaryConditionals);
|
|
1540
|
+
applyTernaryConditionalsToResources(resourcesWithKeys, kroSchema.__ternaryConditionals, kroSchema.__nestedStatusCel);
|
|
959
1541
|
}
|
|
960
1542
|
}
|
|
961
1543
|
return serializeResourceGraphToYaml(definition.name, resourcesWithKeys, options, kroSchema);
|