typekro 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/compositions/typekro-runtime/typekro-runtime.d.ts +1 -1
  3. package/dist/compositions/typekro-runtime/typekro-runtime.js +4 -4
  4. package/dist/core/aspects/apply.d.ts.map +1 -1
  5. package/dist/core/aspects/apply.js +42 -1
  6. package/dist/core/aspects/apply.js.map +1 -1
  7. package/dist/core/aspects/values-merge.d.ts +8 -0
  8. package/dist/core/aspects/values-merge.d.ts.map +1 -0
  9. package/dist/core/aspects/values-merge.js +21 -0
  10. package/dist/core/aspects/values-merge.js.map +1 -0
  11. package/dist/core/composition/imperative.d.ts.map +1 -1
  12. package/dist/core/composition/imperative.js +6 -2
  13. package/dist/core/composition/imperative.js.map +1 -1
  14. package/dist/core/deployment/direct-factory.d.ts +5 -1
  15. package/dist/core/deployment/direct-factory.d.ts.map +1 -1
  16. package/dist/core/deployment/direct-factory.js +21 -2
  17. package/dist/core/deployment/direct-factory.js.map +1 -1
  18. package/dist/core/deployment/engine.d.ts +1 -0
  19. package/dist/core/deployment/engine.d.ts.map +1 -1
  20. package/dist/core/deployment/engine.js +28 -7
  21. package/dist/core/deployment/engine.js.map +1 -1
  22. package/dist/core/deployment/kro-factory.d.ts.map +1 -1
  23. package/dist/core/deployment/kro-factory.js +22 -3
  24. package/dist/core/deployment/kro-factory.js.map +1 -1
  25. package/dist/core/deployment/strategies/base-strategy.d.ts +1 -0
  26. package/dist/core/deployment/strategies/base-strategy.d.ts.map +1 -1
  27. package/dist/core/deployment/strategies/base-strategy.js +35 -33
  28. package/dist/core/deployment/strategies/base-strategy.js.map +1 -1
  29. package/dist/core/deployment/strategies/direct-strategy.d.ts +4 -0
  30. package/dist/core/deployment/strategies/direct-strategy.d.ts.map +1 -1
  31. package/dist/core/deployment/strategies/direct-strategy.js +40 -29
  32. package/dist/core/deployment/strategies/direct-strategy.js.map +1 -1
  33. package/dist/core/references/cel.d.ts +13 -0
  34. package/dist/core/references/cel.d.ts.map +1 -1
  35. package/dist/core/references/cel.js +42 -3
  36. package/dist/core/references/cel.js.map +1 -1
  37. package/dist/core/references/external-refs.d.ts +13 -0
  38. package/dist/core/references/external-refs.d.ts.map +1 -1
  39. package/dist/core/references/external-refs.js +18 -0
  40. package/dist/core/references/external-refs.js.map +1 -1
  41. package/dist/core/references/index.d.ts +1 -1
  42. package/dist/core/references/index.d.ts.map +1 -1
  43. package/dist/core/references/index.js +1 -1
  44. package/dist/core/references/index.js.map +1 -1
  45. package/dist/core/references/schema-proxy.d.ts.map +1 -1
  46. package/dist/core/references/schema-proxy.js +7 -3
  47. package/dist/core/references/schema-proxy.js.map +1 -1
  48. package/dist/core/serialization/cel-references.d.ts +2 -7
  49. package/dist/core/serialization/cel-references.d.ts.map +1 -1
  50. package/dist/core/serialization/cel-references.js +451 -35
  51. package/dist/core/serialization/cel-references.js.map +1 -1
  52. package/dist/core/serialization/core.d.ts.map +1 -1
  53. package/dist/core/serialization/core.js +95 -62
  54. package/dist/core/serialization/core.js.map +1 -1
  55. package/dist/core/serialization/yaml.d.ts +2 -2
  56. package/dist/core/serialization/yaml.d.ts.map +1 -1
  57. package/dist/core/serialization/yaml.js +14 -4
  58. package/dist/core/serialization/yaml.js.map +1 -1
  59. package/dist/core/types/common.d.ts +41 -0
  60. package/dist/core/types/common.d.ts.map +1 -1
  61. package/dist/core/types/deployment.d.ts +2 -0
  62. package/dist/core/types/deployment.d.ts.map +1 -1
  63. package/dist/core/types/deployment.js +1 -1
  64. package/dist/core/types/deployment.js.map +1 -1
  65. package/dist/core/types/references.d.ts +1 -1
  66. package/dist/core/types/references.d.ts.map +1 -1
  67. package/dist/core/validation/cel-validator.d.ts.map +1 -1
  68. package/dist/core/validation/cel-validator.js +26 -8
  69. package/dist/core/validation/cel-validator.js.map +1 -1
  70. package/dist/factories/apisix/resources/helm.d.ts +3 -2
  71. package/dist/factories/apisix/resources/helm.d.ts.map +1 -1
  72. package/dist/factories/apisix/resources/helm.js +1 -1
  73. package/dist/factories/apisix/resources/helm.js.map +1 -1
  74. package/dist/factories/cert-manager/types.d.ts +2 -1
  75. package/dist/factories/cert-manager/types.d.ts.map +1 -1
  76. package/dist/factories/cert-manager/types.js.map +1 -1
  77. package/dist/factories/cilium/resources/helm.d.ts +1 -1
  78. package/dist/factories/cilium/resources/helm.d.ts.map +1 -1
  79. package/dist/factories/cilium/types.d.ts +2 -1
  80. package/dist/factories/cilium/types.d.ts.map +1 -1
  81. package/dist/factories/cilium/types.js.map +1 -1
  82. package/dist/factories/external-dns/resources/helm.d.ts +2 -1
  83. package/dist/factories/external-dns/resources/helm.d.ts.map +1 -1
  84. package/dist/factories/external-dns/resources/helm.js +6 -1
  85. package/dist/factories/external-dns/resources/helm.js.map +1 -1
  86. package/dist/factories/external-dns/types.d.ts +2 -2
  87. package/dist/factories/external-dns/types.d.ts.map +1 -1
  88. package/dist/factories/helm/helm-release.d.ts +9 -4
  89. package/dist/factories/helm/helm-release.d.ts.map +1 -1
  90. package/dist/factories/helm/helm-release.js.map +1 -1
  91. package/dist/factories/helm/types.d.ts +7 -2
  92. package/dist/factories/helm/types.d.ts.map +1 -1
  93. package/dist/factories/index.d.ts +1 -0
  94. package/dist/factories/index.d.ts.map +1 -1
  95. package/dist/factories/index.js +4 -0
  96. package/dist/factories/index.js.map +1 -1
  97. package/dist/factories/inngest/types.d.ts +5 -1
  98. package/dist/factories/inngest/types.d.ts.map +1 -1
  99. package/dist/factories/inngest/types.js.map +1 -1
  100. package/dist/factories/kro/resource-graph-definition.d.ts.map +1 -1
  101. package/dist/factories/kro/resource-graph-definition.js +27 -11
  102. package/dist/factories/kro/resource-graph-definition.js.map +1 -1
  103. package/dist/factories/ory/compositions/index.d.ts +3 -0
  104. package/dist/factories/ory/compositions/index.d.ts.map +1 -0
  105. package/dist/factories/ory/compositions/index.js +3 -0
  106. package/dist/factories/ory/compositions/index.js.map +1 -0
  107. package/dist/factories/ory/compositions/ory-identity-stack.d.ts +2073 -0
  108. package/dist/factories/ory/compositions/ory-identity-stack.d.ts.map +1 -0
  109. package/dist/factories/ory/compositions/ory-identity-stack.js +432 -0
  110. package/dist/factories/ory/compositions/ory-identity-stack.js.map +1 -0
  111. package/dist/factories/ory/compositions/ory-platform-stack.d.ts +185 -0
  112. package/dist/factories/ory/compositions/ory-platform-stack.d.ts.map +1 -0
  113. package/dist/factories/ory/compositions/ory-platform-stack.js +536 -0
  114. package/dist/factories/ory/compositions/ory-platform-stack.js.map +1 -0
  115. package/dist/factories/ory/index.d.ts +5 -0
  116. package/dist/factories/ory/index.d.ts.map +1 -0
  117. package/dist/factories/ory/index.js +5 -0
  118. package/dist/factories/ory/index.js.map +1 -0
  119. package/dist/factories/ory/resources/helm.d.ts +20 -0
  120. package/dist/factories/ory/resources/helm.d.ts.map +1 -0
  121. package/dist/factories/ory/resources/helm.js +52 -0
  122. package/dist/factories/ory/resources/helm.js.map +1 -0
  123. package/dist/factories/ory/resources/index.d.ts +4 -0
  124. package/dist/factories/ory/resources/index.d.ts.map +1 -0
  125. package/dist/factories/ory/resources/index.js +4 -0
  126. package/dist/factories/ory/resources/index.js.map +1 -0
  127. package/dist/factories/ory/resources/oathkeeper-rule.d.ts +4 -0
  128. package/dist/factories/ory/resources/oathkeeper-rule.d.ts.map +1 -0
  129. package/dist/factories/ory/resources/oathkeeper-rule.js +19 -0
  130. package/dist/factories/ory/resources/oathkeeper-rule.js.map +1 -0
  131. package/dist/factories/ory/resources/oauth2-client.d.ts +4 -0
  132. package/dist/factories/ory/resources/oauth2-client.d.ts.map +1 -0
  133. package/dist/factories/ory/resources/oauth2-client.js +20 -0
  134. package/dist/factories/ory/resources/oauth2-client.js.map +1 -0
  135. package/dist/factories/ory/schemas/chart-values.d.ts +253 -0
  136. package/dist/factories/ory/schemas/chart-values.d.ts.map +1 -0
  137. package/dist/factories/ory/schemas/chart-values.js +10 -0
  138. package/dist/factories/ory/schemas/chart-values.js.map +1 -0
  139. package/dist/factories/ory/schemas/hydra-maester.d.ts +152 -0
  140. package/dist/factories/ory/schemas/hydra-maester.d.ts.map +1 -0
  141. package/dist/factories/ory/schemas/hydra-maester.js +3 -0
  142. package/dist/factories/ory/schemas/hydra-maester.js.map +1 -0
  143. package/dist/factories/ory/schemas/hydra.d.ts +115 -0
  144. package/dist/factories/ory/schemas/hydra.d.ts.map +1 -0
  145. package/dist/factories/ory/schemas/hydra.js +3 -0
  146. package/dist/factories/ory/schemas/hydra.js.map +1 -0
  147. package/dist/factories/ory/schemas/index.d.ts +20 -0
  148. package/dist/factories/ory/schemas/index.d.ts.map +1 -0
  149. package/dist/factories/ory/schemas/index.js +2 -0
  150. package/dist/factories/ory/schemas/index.js.map +1 -0
  151. package/dist/factories/ory/schemas/keto.d.ts +86 -0
  152. package/dist/factories/ory/schemas/keto.d.ts.map +1 -0
  153. package/dist/factories/ory/schemas/keto.js +3 -0
  154. package/dist/factories/ory/schemas/keto.js.map +1 -0
  155. package/dist/factories/ory/schemas/kratos.d.ts +124 -0
  156. package/dist/factories/ory/schemas/kratos.d.ts.map +1 -0
  157. package/dist/factories/ory/schemas/kratos.js +3 -0
  158. package/dist/factories/ory/schemas/kratos.js.map +1 -0
  159. package/dist/factories/ory/schemas/maester-crds.d.ts +9 -0
  160. package/dist/factories/ory/schemas/maester-crds.d.ts.map +1 -0
  161. package/dist/factories/ory/schemas/maester-crds.js +8 -0
  162. package/dist/factories/ory/schemas/maester-crds.js.map +1 -0
  163. package/dist/factories/ory/schemas/oathkeeper-maester.d.ts +80 -0
  164. package/dist/factories/ory/schemas/oathkeeper-maester.d.ts.map +1 -0
  165. package/dist/factories/ory/schemas/oathkeeper-maester.js +3 -0
  166. package/dist/factories/ory/schemas/oathkeeper-maester.js.map +1 -0
  167. package/dist/factories/ory/schemas/oathkeeper.d.ts +105 -0
  168. package/dist/factories/ory/schemas/oathkeeper.d.ts.map +1 -0
  169. package/dist/factories/ory/schemas/oathkeeper.js +3 -0
  170. package/dist/factories/ory/schemas/oathkeeper.js.map +1 -0
  171. package/dist/factories/ory/types.d.ts +4948 -0
  172. package/dist/factories/ory/types.d.ts.map +1 -0
  173. package/dist/factories/ory/types.js +581 -0
  174. package/dist/factories/ory/types.js.map +1 -0
  175. package/dist/factories/ory/utils/helm-values-mapper.d.ts +7 -0
  176. package/dist/factories/ory/utils/helm-values-mapper.d.ts.map +1 -0
  177. package/dist/factories/ory/utils/helm-values-mapper.js +534 -0
  178. package/dist/factories/ory/utils/helm-values-mapper.js.map +1 -0
  179. package/dist/factories/ory/utils/index.d.ts +2 -0
  180. package/dist/factories/ory/utils/index.d.ts.map +1 -0
  181. package/dist/factories/ory/utils/index.js +2 -0
  182. package/dist/factories/ory/utils/index.js.map +1 -0
  183. package/dist/factories/pebble/resources/helm.d.ts +2 -2
  184. package/dist/factories/pebble/resources/helm.d.ts.map +1 -1
  185. package/dist/factories/pebble/resources/helm.js.map +1 -1
  186. package/dist/factories/pebble/types.d.ts +2 -1
  187. package/dist/factories/pebble/types.d.ts.map +1 -1
  188. package/dist/factories/pebble/types.js.map +1 -1
  189. package/dist/factories/searxng/compositions/searxng-bootstrap.d.ts.map +1 -1
  190. package/dist/factories/searxng/compositions/searxng-bootstrap.js +152 -42
  191. package/dist/factories/searxng/compositions/searxng-bootstrap.js.map +1 -1
  192. package/dist/factories/searxng/types.d.ts.map +1 -1
  193. package/dist/factories/searxng/types.js +9 -1
  194. package/dist/factories/searxng/types.js.map +1 -1
  195. package/dist/factories/simple/helm/index.d.ts +2 -1
  196. package/dist/factories/simple/helm/index.d.ts.map +1 -1
  197. package/dist/factories/simple/helm/index.js.map +1 -1
  198. package/dist/factories/valkey/types.d.ts +5 -1
  199. package/dist/factories/valkey/types.d.ts.map +1 -1
  200. package/dist/factories/valkey/types.js.map +1 -1
  201. package/dist/index.d.ts +1 -1
  202. package/dist/index.d.ts.map +1 -1
  203. package/dist/index.js +1 -1
  204. package/dist/index.js.map +1 -1
  205. package/dist/shared/brands.d.ts +7 -5
  206. package/dist/shared/brands.d.ts.map +1 -1
  207. package/dist/shared/brands.js +5 -3
  208. package/dist/shared/brands.js.map +1 -1
  209. package/package.json +5 -1
@@ -10,6 +10,7 @@
10
10
  */
11
11
  import type { KubernetesRef } from '../types/common.js';
12
12
  import type { SerializationContext } from '../types/serialization.js';
13
+ export declare function normalizeCelArrayIndexPaths(expr: string): string;
13
14
  /**
14
15
  * Compute the inner CEL path for a {@link KubernetesRef}.
15
16
  *
@@ -94,13 +95,7 @@ export declare function inlineNestedStatusRefs(expr: string, nestedStatusCel: Re
94
95
  * `${…}` so KRO recognizes it as an expression to evaluate.
95
96
  */
96
97
  export declare function finalizeCelForKro(expr: string, nestedStatusCel: Record<string, string> | undefined, context?: SerializationContext): string;
97
- /**
98
- * Recursively replace all {@link KubernetesRef} objects with CEL expressions
99
- * for Kro YAML output.
100
- *
101
- * This is the **only** function that should perform this transformation.
102
- */
103
- export declare function processResourceReferences(obj: unknown, context?: SerializationContext): unknown;
98
+ export declare function processResourceReferences(obj: unknown, context?: SerializationContext, path?: string): unknown;
104
99
  /**
105
100
  * Serialize user-defined status mappings to CEL expressions for Kro schema.
106
101
  *
@@ -1 +1 @@
1
- {"version":3,"file":"cel-references.d.ts","sourceRoot":"","sources":["../../../src/core/serialization/cel-references.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAQH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAYtE;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,MAAM,CAGnE;AA0LD,qFAAqF;AACrF,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAajG;AA6DD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAClD,OAAO,CAIT;AAmBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,kBAAkB,GAAE,OAAc,GACjC,MAAM,GAAG,SAAS,CA2EpB;AAmDD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACnD,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAChC,MAAM,CAER;AA2HD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACnD,OAAO,CAAC,EAAE,oBAAoB,GAC7B,MAAM,CAUR;AA0ED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAgE/F;AAMD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACxC,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EACzB,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,CAAC,CAkL9D"}
1
+ {"version":3,"file":"cel-references.d.ts","sourceRoot":"","sources":["../../../src/core/serialization/cel-references.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AASH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAQtE,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAmDhE;AAMD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,MAAM,CAGnE;AAwMD,qFAAqF;AACrF,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAajG;AA6DD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,GAClD,OAAO,CAIT;AAmBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACvC,kBAAkB,GAAE,OAAc,GACjC,MAAM,GAAG,SAAS,CAyEpB;AAmDD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACnD,WAAW,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAChC,MAAM,CAER;AA4HD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EACnD,OAAO,CAAC,EAAE,oBAAoB,GAC7B,MAAM,CAYR;AA+mBD,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,EACZ,OAAO,CAAC,EAAE,oBAAoB,EAC9B,IAAI,SAAK,GACR,OAAO,CAgHT;AAMD;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACvC,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACxC,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EACzB,eAAe,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAC5C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,CAAC,CA4K9D"}
@@ -8,9 +8,10 @@
8
8
  * This module is the **single authority** for KubernetesRef → CEL string
9
9
  * conversion. No other module should duplicate this logic.
10
10
  */
11
- import { isCelExpression, isKubernetesRef } from '../../utils/type-guards.js';
12
- import { escapeCelString } from '../../utils/cel-escape.js';
13
11
  import { KUBERNETES_REF_MARKER_SOURCE } from '../../shared/brands.js';
12
+ import { escapeCelString } from '../../utils/cel-escape.js';
13
+ import { isCelExpression, isKubernetesRef } from '../../utils/type-guards.js';
14
+ import { isValuesMergeExpression } from '../aspects/values-merge.js';
14
15
  import { remapVariableNames } from '../composition/nested-status-cel.js';
15
16
  import { getComponentLogger } from '../logging/index.js';
16
17
  import { copyResourceMetadata } from '../metadata/index.js';
@@ -18,6 +19,52 @@ const logger = getComponentLogger('cel-references');
18
19
  function escapeRegExpLiteral(value) {
19
20
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
20
21
  }
22
+ export function normalizeCelArrayIndexPaths(expr) {
23
+ let result = '';
24
+ let quote = null;
25
+ let escaped = false;
26
+ for (let i = 0; i < expr.length; i++) {
27
+ const char = expr[i];
28
+ if (!char)
29
+ continue;
30
+ if (quote) {
31
+ result += char;
32
+ if (escaped) {
33
+ escaped = false;
34
+ }
35
+ else if (char === '\\') {
36
+ escaped = true;
37
+ }
38
+ else if (char === quote) {
39
+ quote = null;
40
+ }
41
+ continue;
42
+ }
43
+ if (char === '"' || char === "'") {
44
+ quote = char;
45
+ result += char;
46
+ continue;
47
+ }
48
+ if (char === '.') {
49
+ const digitStart = i + 1;
50
+ let digitEnd = digitStart;
51
+ while (digitEnd < expr.length && /\d/.test(expr[digitEnd] ?? '')) {
52
+ digitEnd++;
53
+ }
54
+ const previous = expr[i - 1] ?? '';
55
+ const next = expr[digitEnd] ?? '';
56
+ if (digitEnd > digitStart &&
57
+ /[A-Za-z_$\]]/.test(previous) &&
58
+ (next === '' || /[.\])}\s?:,+\-*/<>=!&|]/.test(next))) {
59
+ result += `[${expr.slice(digitStart, digitEnd)}]`;
60
+ i = digitEnd - 1;
61
+ continue;
62
+ }
63
+ }
64
+ result += char;
65
+ }
66
+ return result;
67
+ }
21
68
  // ---------------------------------------------------------------------------
22
69
  // Primitive helpers
23
70
  // ---------------------------------------------------------------------------
@@ -32,7 +79,7 @@ function escapeRegExpLiteral(value) {
32
79
  */
33
80
  export function getInnerCelPath(ref) {
34
81
  const resourceId = ref.resourceId === '__schema__' ? 'schema' : ref.resourceId;
35
- return `${resourceId}.${ref.fieldPath}`;
82
+ return normalizeCelArrayIndexPaths(`${resourceId}.${ref.fieldPath}`);
36
83
  }
37
84
  function resolveResourceIdAlias(resourceId, context) {
38
85
  if (resourceId === '__schema__') {
@@ -72,13 +119,17 @@ function resolveResourceIdAlias(resourceId, context) {
72
119
  */
73
120
  function maybeWrapWithOmit(celPath, stringWrap, omitFields) {
74
121
  const value = stringWrap ? `string(${celPath})` : celPath;
122
+ const guard = optionalSchemaSpecGuard(celPath, omitFields);
123
+ return guard ? `${guard} ? ${value} : omit()` : value;
124
+ }
125
+ function optionalSchemaSpecGuard(celPath, omitFields) {
75
126
  if (!omitFields || omitFields.size === 0)
76
- return value;
127
+ return undefined;
77
128
  // Only handle refs rooted at `schema.spec.`.
78
129
  const refMatch = /^schema\.spec\.([A-Za-z_$][\w$.]*)$/.exec(celPath);
79
130
  const refPath = refMatch?.[1];
80
131
  if (!refPath)
81
- return value;
132
+ return undefined;
82
133
  // Walk the full path and collect every optional prefix that applies.
83
134
  // We chain from the SHALLOWEST optional ancestor through the leaf.
84
135
  //
@@ -105,9 +156,9 @@ function maybeWrapWithOmit(celPath, stringWrap, omitFields) {
105
156
  const guardPath = `schema.spec.${segments.slice(0, i).join('.')}`;
106
157
  guards.push(`has(${guardPath})`);
107
158
  }
108
- return `${guards.join(' && ')} ? ${value} : omit()`;
159
+ return guards.join(' && ');
109
160
  }
110
- return value;
161
+ return undefined;
111
162
  }
112
163
  /**
113
164
  * Wrap a {@link KubernetesRef} in `${…}` for Kro YAML output.
@@ -133,7 +184,7 @@ function generateCelExpression(ref, context) {
133
184
  return finalizeCelForKro(innerExpr, context.nestedStatusCel, context);
134
185
  }
135
186
  }
136
- const expression = `${resolveResourceIdAlias(ref.resourceId, context)}.${ref.fieldPath}`;
187
+ const expression = normalizeCelArrayIndexPaths(`${resolveResourceIdAlias(ref.resourceId, context)}.${ref.fieldPath}`);
137
188
  const body = maybeWrapWithOmit(expression, false, context?.omitFields);
138
189
  return `\${${body}}`;
139
190
  }
@@ -174,7 +225,7 @@ const MARKER_PATTERN_FULL = new RegExp(`^${MARKER_PATTERN_SOURCE}$`);
174
225
  * emits `<resourceId>.<fieldPath>`.
175
226
  */
176
227
  function markerToCelPath(resourceId, fieldPath, context) {
177
- return `${resolveResourceIdAlias(resourceId, context)}.${fieldPath}`;
228
+ return normalizeCelArrayIndexPaths(`${resolveResourceIdAlias(resourceId, context)}.${fieldPath}`);
178
229
  }
179
230
  /**
180
231
  * Normalize any `__KUBERNETES_REF__` markers in `str` to their bare CEL paths
@@ -545,7 +596,7 @@ function innerExprToYamlSegment(innerExpr, nestedStatusCel, context) {
545
596
  }
546
597
  if (resolved.includes('${')) {
547
598
  // Already a KRO template (from Cel.template) — pass through.
548
- return resolved;
599
+ return normalizeCelArrayIndexPaths(resolved);
549
600
  }
550
601
  // Bare literal reached via a template-literal coercion — wrap with
551
602
  // `string(...)` so KRO evaluates it to a string value. This matches
@@ -575,16 +626,19 @@ function innerExprToYamlSegment(innerExpr, nestedStatusCel, context) {
575
626
  * `${…}` so KRO recognizes it as an expression to evaluate.
576
627
  */
577
628
  export function finalizeCelForKro(expr, nestedStatusCel, context) {
578
- const resolved = resolveNestedCompositionRefs(expr, nestedStatusCel, context?.resourceIds);
629
+ const resolved = normalizeCelArrayIndexPaths(resolveNestedCompositionRefs(expr, nestedStatusCel, context?.resourceIds));
579
630
  if (resolved.includes('__KUBERNETES_REF_')) {
580
631
  return convertKubernetesRefMarkersTocel(resolved, context);
581
632
  }
582
633
  if (resolved.includes('${')) {
583
634
  // Already contains KRO template placeholders — pass through.
584
- return resolved;
635
+ return normalizeCelArrayIndexPaths(resolved);
585
636
  }
586
637
  return `\${${resolved}}`;
587
638
  }
639
+ function normalizeSchemaSpecShorthand(expr) {
640
+ return expr.replace(/(^|[^A-Za-z0-9_$.])spec\./g, '$1schema.spec.');
641
+ }
588
642
  // ---------------------------------------------------------------------------
589
643
  // __KUBERNETES_REF__ marker → KRO CEL conversion
590
644
  // ---------------------------------------------------------------------------
@@ -656,13 +710,363 @@ function convertKubernetesRefMarkersTocel(str, context) {
656
710
  *
657
711
  * This is the **only** function that should perform this transformation.
658
712
  */
659
- export function processResourceReferences(obj, context) {
713
+ function valueTreePath(path) {
714
+ return path === 'spec.values' || path.includes('.values.') || path.endsWith('.values');
715
+ }
716
+ function childPath(parent, key) {
717
+ return parent ? `${parent}.${key}` : key;
718
+ }
719
+ function arrayChildPath(parent, index) {
720
+ return `${parent}[${index}]`;
721
+ }
722
+ function isPlainSerializableObject(value) {
723
+ const prototype = Object.getPrototypeOf(value);
724
+ return prototype === Object.prototype || prototype === null;
725
+ }
726
+ function valueTreeSerializationError(path, reason) {
727
+ return new Error(`Cannot serialize ${path} in graph mode. ${reason} Provide a serializable value or move this logic to a direct-only API.`);
728
+ }
729
+ function unwrapKroExpression(value) {
730
+ if (typeof value !== 'string')
731
+ return undefined;
732
+ if (!value.startsWith('${') || !value.endsWith('}'))
733
+ return undefined;
734
+ return value.slice(2, -1);
735
+ }
736
+ function celValueTreeBranch(expression) {
737
+ return expression.includes(' ? ') && expression.includes(' : ') ? `(${expression})` : expression;
738
+ }
739
+ function celStringTemplateExpression(template) {
740
+ const parts = [];
741
+ let lastIndex = 0;
742
+ for (const match of template.matchAll(/\$\{([^}]+)\}/g)) {
743
+ const index = match.index ?? 0;
744
+ if (index > lastIndex) {
745
+ parts.push(JSON.stringify(template.slice(lastIndex, index)));
746
+ }
747
+ const innerExpression = match[1]?.trim();
748
+ if (innerExpression) {
749
+ parts.push(innerExpression.startsWith('string(') ? innerExpression : `string(${innerExpression})`);
750
+ }
751
+ lastIndex = index + match[0].length;
752
+ }
753
+ if (lastIndex < template.length) {
754
+ parts.push(JSON.stringify(template.slice(lastIndex)));
755
+ }
756
+ return parts.length > 0 ? parts.join(' + ') : JSON.stringify(template);
757
+ }
758
+ function celMarkerStringLiteralForValueTree(value, context) {
759
+ const resolved = resolveNestedRefMarkers(value, context?.nestedStatusCel, context?.resourceIds, context);
760
+ if (!resolved.includes('__KUBERNETES_REF_')) {
761
+ return resolved.includes('${') ? celStringTemplateExpression(resolved) : JSON.stringify(resolved);
762
+ }
763
+ const parts = [];
764
+ let lastIndex = 0;
765
+ for (const match of resolved.matchAll(new RegExp(MARKER_PATTERN_SOURCE, 'g'))) {
766
+ const index = match.index ?? 0;
767
+ if (index > lastIndex) {
768
+ parts.push(JSON.stringify(resolved.slice(lastIndex, index)));
769
+ }
770
+ const [, resourceId, fieldPath] = match;
771
+ if (resourceId && fieldPath) {
772
+ parts.push(`string(${markerToCelPath(resourceId, fieldPath, context)})`);
773
+ }
774
+ else {
775
+ parts.push(JSON.stringify(match[0]));
776
+ }
777
+ lastIndex = index + match[0].length;
778
+ }
779
+ if (lastIndex < resolved.length) {
780
+ parts.push(JSON.stringify(resolved.slice(lastIndex)));
781
+ }
782
+ return parts.length > 0 ? parts.join(' + ') : JSON.stringify(resolved);
783
+ }
784
+ function finalizeValueTreeCelForKro(expr, context) {
785
+ const resolved = normalizeCelArrayIndexPaths(resolveNestedCompositionRefs(expr, context?.nestedStatusCel, context?.resourceIds));
786
+ return `\${${resolved}}`;
787
+ }
788
+ function celLiteralForValueTree(value, context, path) {
789
+ if (isValuesMergeExpression(value)) {
790
+ return celValuesMergeExpression(value.base, value.overlays, context, path);
791
+ }
792
+ if (isKubernetesRef(value) || isCelExpression(value)) {
793
+ const expression = unwrapKroExpression(processResourceReferences(value, context, path)) ?? 'null';
794
+ return celValueTreeBranch(expression);
795
+ }
796
+ if (typeof value === 'string') {
797
+ return value.includes('__KUBERNETES_REF_') || value.includes('${')
798
+ ? celMarkerStringLiteralForValueTree(value, context)
799
+ : JSON.stringify(value);
800
+ }
801
+ if (value === null || typeof value === 'number' || typeof value === 'boolean') {
802
+ return JSON.stringify(value);
803
+ }
804
+ if (value === undefined)
805
+ return 'null';
806
+ if (Array.isArray(value)) {
807
+ return `[${value
808
+ .filter((entry) => entry !== undefined)
809
+ .map((entry, index) => celLiteralForValueTree(entry, context, arrayChildPath(path, index)))
810
+ .join(', ')}]`;
811
+ }
812
+ if (typeof value === 'object' && isPlainSerializableObject(value)) {
813
+ const entries = Object.entries(value).flatMap(([key, child]) => {
814
+ if (child === undefined)
815
+ return [];
816
+ return [
817
+ `${JSON.stringify(key)}: ${celLiteralForValueTree(child, context, childPath(path, key))}`,
818
+ ];
819
+ });
820
+ return `{${entries.join(', ')}}`;
821
+ }
822
+ throw valueTreeSerializationError(path, 'Only plain data, refs, CEL expressions, and templates can be merged.');
823
+ }
824
+ function mergeValueTrees(base, overlay, path) {
825
+ if (overlay === undefined)
826
+ return base;
827
+ if (isValuesMergeExpression(overlay)) {
828
+ let mergedOverlay = overlay.base;
829
+ const normalizedOverlays = Array.isArray(overlay.overlays)
830
+ ? overlay.overlays
831
+ : [overlay.overlays];
832
+ normalizedOverlays.forEach((nestedOverlay, index) => {
833
+ mergedOverlay = mergeValueTrees(mergedOverlay, nestedOverlay, `${path}.overlay[${index}]`);
834
+ });
835
+ return mergeValueTrees(base, mergedOverlay, path);
836
+ }
837
+ if (Array.isArray(overlay))
838
+ return overlay;
839
+ if (isKubernetesRef(overlay) || isCelExpression(overlay)) {
840
+ if (path === 'spec.values') {
841
+ throw valueTreeSerializationError(path, 'Kro CEL map merge support is required for whole-object values refs or CEL maps.');
842
+ }
843
+ return overlay;
844
+ }
845
+ if (typeof base === 'object' &&
846
+ base !== null &&
847
+ isPlainSerializableObject(base) &&
848
+ typeof overlay === 'object' &&
849
+ overlay !== null &&
850
+ isPlainSerializableObject(overlay)) {
851
+ return Object.fromEntries(Array.from(new Set([...Object.keys(base), ...Object.keys(overlay)])).flatMap((key) => {
852
+ const merged = mergeValueTrees(base[key], overlay[key], childPath(path, key));
853
+ return merged === undefined ? [] : [[key, merged]];
854
+ }));
855
+ }
856
+ return overlay;
857
+ }
858
+ function needsRuntimeMapMerge(value) {
859
+ if (isKubernetesRef(value) || isCelExpression(value))
860
+ return true;
861
+ if (isValuesMergeExpression(value)) {
862
+ const normalizedOverlays = Array.isArray(value.overlays) ? value.overlays : [value.overlays];
863
+ return (needsRuntimeMapMerge(value.base) ||
864
+ normalizedOverlays.some((overlay) => needsRuntimeMapMerge(overlay)));
865
+ }
866
+ return false;
867
+ }
868
+ function isKnownMergeObject(value) {
869
+ return (!!value &&
870
+ typeof value === 'object' &&
871
+ !Array.isArray(value) &&
872
+ isPlainSerializableObject(value) &&
873
+ !isKubernetesRef(value) &&
874
+ !isCelExpression(value) &&
875
+ !isValuesMergeExpression(value));
876
+ }
877
+ function mapKeyAccess(mapExpression, key) {
878
+ return `(${mapExpression})[${JSON.stringify(key)}]`;
879
+ }
880
+ function mapHasKey(mapExpression, key) {
881
+ return `${JSON.stringify(key)} in (${mapExpression})`;
882
+ }
883
+ function celMapMergeOperand(value, context, path) {
884
+ if (isValuesMergeExpression(value)) {
885
+ return celValuesMergeExpression(value.base, value.overlays, context, path);
886
+ }
887
+ if (isKubernetesRef(value)) {
888
+ const celPath = getInnerCelPath(value);
889
+ const guard = optionalSchemaSpecGuard(celPath, context?.omitFields);
890
+ const operand = `json.unmarshal(json.marshal(${celPath}))`;
891
+ return guard ? `${guard} ? ${operand} : {}` : operand;
892
+ }
893
+ const expression = celLiteralForValueTree(value, context, path);
894
+ return `json.unmarshal(json.marshal(${expression}))`;
895
+ }
896
+ function celRuntimeMapMergeExpression(base, overlays, context, path) {
897
+ let expression;
898
+ let knownBase = base;
899
+ const normalizedOverlays = Array.isArray(overlays) ? overlays : [overlays];
900
+ normalizedOverlays.forEach((overlay, index) => {
901
+ if (overlay === undefined)
902
+ return;
903
+ const overlayPath = path || `spec.values.overlay[${index}]`;
904
+ if (expression === undefined) {
905
+ if (isKnownMergeObject(knownBase) && isKnownMergeObject(overlay)) {
906
+ knownBase = mergeValueTrees(knownBase, overlay, overlayPath);
907
+ return;
908
+ }
909
+ if (isKnownMergeObject(knownBase)) {
910
+ expression = isKnownMergeObject(overlay)
911
+ ? celDeepMergeKnownOverlay(celMapMergeOperand(knownBase, context, path), overlay, context, overlayPath)
912
+ : celDeepMergeRuntimeOverlay(knownBase, celMapMergeOperand(overlay, context, overlayPath), context, overlayPath);
913
+ return;
914
+ }
915
+ expression = isKnownMergeObject(overlay)
916
+ ? celDeepMergeKnownOverlay(celMapMergeOperand(knownBase, context, path), overlay, context, overlayPath)
917
+ : `(${celMapMergeOperand(knownBase, context, path)}).merge(${celMapMergeOperand(overlay, context, overlayPath)})`;
918
+ return;
919
+ }
920
+ expression = isKnownMergeObject(overlay)
921
+ ? celDeepMergeKnownOverlay(expression, overlay, context, overlayPath)
922
+ : `(${expression}).merge(${celMapMergeOperand(overlay, context, overlayPath)})`;
923
+ });
924
+ return expression ?? celLiteralForValueTree(knownBase, context, path);
925
+ }
926
+ function celDeepMergeRuntimeOverlay(base, overlayExpression, context, path) {
927
+ const entries = Object.entries(base).flatMap(([key, baseValue]) => {
928
+ if (baseValue === undefined)
929
+ return [];
930
+ const overlayValue = mapKeyAccess(overlayExpression, key);
931
+ const baseExpression = celLiteralForValueTree(baseValue, context, childPath(path, key));
932
+ const mergedValue = isKnownMergeObject(baseValue)
933
+ ? celDeepMergeRuntimeOverlay(baseValue, overlayValue, context, childPath(path, key))
934
+ : overlayValue;
935
+ return [
936
+ `${JSON.stringify(key)}: ${mapHasKey(overlayExpression, key)} ? ${mergedValue} : ${baseExpression}`,
937
+ ];
938
+ });
939
+ return `(${overlayExpression}).merge({${entries.join(', ')}})`;
940
+ }
941
+ function celDeepMergeKnownOverlay(baseExpression, overlay, context, path) {
942
+ const entries = Object.entries(overlay).flatMap(([key, overlayValue]) => {
943
+ if (overlayValue === undefined)
944
+ return [];
945
+ const overlayExpression = celLiteralForValueTree(overlayValue, context, childPath(path, key));
946
+ const baseValue = mapKeyAccess(baseExpression, key);
947
+ const mergedValue = isKnownMergeObject(overlayValue)
948
+ ? `${mapHasKey(baseExpression, key)} ? ${celDeepMergeKnownOverlay(baseValue, overlayValue, context, childPath(path, key))} : ${overlayExpression}`
949
+ : overlayExpression;
950
+ return [`${JSON.stringify(key)}: ${mergedValue}`];
951
+ });
952
+ return `(${baseExpression}).merge({${entries.join(', ')}})`;
953
+ }
954
+ function celValuesMergeExpression(base, overlays, context, path) {
955
+ const flattened = flattenValuesMergeExpression(base, overlays);
956
+ base = flattened.base;
957
+ const normalizedOverlays = flattened.overlays;
958
+ if (needsRuntimeMapMerge(base) ||
959
+ normalizedOverlays.some((overlay) => needsRuntimeMapMerge(overlay))) {
960
+ return celRuntimeMapMergeExpression(base, normalizedOverlays, context, path || 'spec.values');
961
+ }
962
+ let merged = base;
963
+ normalizedOverlays.forEach((overlay, index) => {
964
+ merged = mergeValueTrees(merged, overlay, path || `spec.values.overlay[${index}]`);
965
+ });
966
+ return celLiteralForValueTree(merged, context, path);
967
+ }
968
+ function valuesMergeNeedsRuntimeMapMerge(base, overlays) {
969
+ const flattened = flattenValuesMergeExpression(base, overlays);
970
+ return (needsRuntimeMapMerge(flattened.base) ||
971
+ flattened.overlays.some((overlay) => needsRuntimeMapMerge(overlay)));
972
+ }
973
+ function flattenValuesMergeExpression(base, overlays) {
974
+ let flattenedBase = base;
975
+ const flattenedOverlays = Array.isArray(overlays) ? [...overlays] : [overlays];
976
+ while (isValuesMergeExpression(flattenedBase)) {
977
+ const nestedOverlays = Array.isArray(flattenedBase.overlays)
978
+ ? flattenedBase.overlays
979
+ : [flattenedBase.overlays];
980
+ flattenedOverlays.unshift(...nestedOverlays);
981
+ flattenedBase = flattenedBase.base;
982
+ }
983
+ return { base: flattenedBase, overlays: flattenedOverlays };
984
+ }
985
+ function collectKnownMergeKeys(value, keys = new Set()) {
986
+ if (isValuesMergeExpression(value)) {
987
+ collectKnownMergeKeys(value.base, keys);
988
+ const normalizedOverlays = Array.isArray(value.overlays) ? value.overlays : [value.overlays];
989
+ normalizedOverlays.forEach((overlay) => collectKnownMergeKeys(overlay, keys));
990
+ return keys;
991
+ }
992
+ if (isKnownMergeObject(value)) {
993
+ Object.keys(value).forEach((key) => keys.add(key));
994
+ }
995
+ return keys;
996
+ }
997
+ function celValuesMergeTemplateObject(base, overlays, context, path) {
998
+ const flattened = flattenValuesMergeExpression(base, overlays);
999
+ base = flattened.base;
1000
+ const normalizedOverlays = flattened.overlays;
1001
+ const knownKeys = collectKnownMergeKeys(base);
1002
+ normalizedOverlays.forEach((overlay) => collectKnownMergeKeys(overlay, knownKeys));
1003
+ const orderedKeys = Array.from(knownKeys);
1004
+ if (orderedKeys.length === 0)
1005
+ return undefined;
1006
+ return Object.fromEntries(orderedKeys.map((key) => {
1007
+ const value = celValuesMergeTemplateValue(base, normalizedOverlays, key, context, path);
1008
+ return [key, value];
1009
+ }));
1010
+ }
1011
+ function celValuesMergeTemplateValue(base, overlays, key, context, path) {
1012
+ let knownValue = isKnownMergeObject(base) ? base[key] : undefined;
1013
+ for (const [index, overlay] of overlays.entries()) {
1014
+ if (overlay === undefined)
1015
+ continue;
1016
+ const overlayPath = path || `spec.values.overlay[${index}]`;
1017
+ if (isKnownMergeObject(overlay)) {
1018
+ if (!Object.hasOwn(overlay, key))
1019
+ continue;
1020
+ knownValue = mergeValueTrees(knownValue, overlay[key], childPath(overlayPath, key));
1021
+ continue;
1022
+ }
1023
+ return celValuesMergeRuntimeTemplateValue(knownValue, celMapMergeOperand(overlay, context, overlayPath), key, context, childPath(path, key));
1024
+ }
1025
+ return processResourceReferences(knownValue, context, childPath(path, key));
1026
+ }
1027
+ function celValuesMergeRuntimeTemplateValue(fallbackValue, overlayExpression, key, context, path) {
1028
+ if (isValuesMergeExpression(fallbackValue)) {
1029
+ const templateObject = celValuesMergeTemplateObject(fallbackValue.base, fallbackValue.overlays, context, path);
1030
+ if (templateObject) {
1031
+ return celValuesMergeRuntimeTemplateValue(templateObject, overlayExpression, key, context, path);
1032
+ }
1033
+ }
1034
+ if (isKnownMergeObject(fallbackValue)) {
1035
+ const childOverlay = `(${mapHasKey(overlayExpression, key)} ? ${mapKeyAccess(overlayExpression, key)} : {})`;
1036
+ return Object.fromEntries(Object.entries(fallbackValue).flatMap(([childKey, childValue]) => {
1037
+ if (childValue === undefined)
1038
+ return [];
1039
+ return [
1040
+ [
1041
+ childKey,
1042
+ celValuesMergeRuntimeTemplateValue(childValue, childOverlay, childKey, context, childPath(path, childKey)),
1043
+ ],
1044
+ ];
1045
+ }));
1046
+ }
1047
+ if (Array.isArray(fallbackValue)) {
1048
+ return processResourceReferences(fallbackValue, context, path);
1049
+ }
1050
+ const fallbackExpression = celLiteralForValueTree(fallbackValue, context, path);
1051
+ const expression = `${mapHasKey(overlayExpression, key)} ? ${mapKeyAccess(overlayExpression, key)} : (${fallbackExpression})`;
1052
+ return finalizeCelForKro(expression, context?.nestedStatusCel, context);
1053
+ }
1054
+ export function processResourceReferences(obj, context, path = '') {
1055
+ const inValueTree = valueTreePath(path);
1056
+ if (isValuesMergeExpression(obj)) {
1057
+ if (path === 'spec.values' && !valuesMergeNeedsRuntimeMapMerge(obj.base, obj.overlays)) {
1058
+ const templateObject = celValuesMergeTemplateObject(obj.base, obj.overlays, context, path);
1059
+ if (templateObject)
1060
+ return templateObject;
1061
+ }
1062
+ return finalizeValueTreeCelForKro(celValuesMergeExpression(obj.base, obj.overlays, context, path), context);
1063
+ }
660
1064
  if (isKubernetesRef(obj)) {
661
1065
  return generateCelExpression(obj, context);
662
1066
  }
663
1067
  if (isCelExpression(obj)) {
664
1068
  if (obj.__isTemplate) {
665
- return obj.expression.replace(/\$\{([^}]+)\}/g, (_match, innerExpr) => finalizeCelForKro(innerExpr, context?.nestedStatusCel, context));
1069
+ return obj.expression.replace(/\$\{([^}]+)\}/g, (_match, innerExpr) => finalizeCelForKro(normalizeSchemaSpecShorthand(innerExpr), context?.nestedStatusCel, context));
666
1070
  }
667
1071
  // Bare CelExpression — may be a single schema.spec.X reference (possibly
668
1072
  // wrapped in `string(...)`). Delegate any single schema ref to
@@ -679,6 +1083,12 @@ export function processResourceReferences(obj, context) {
679
1083
  }
680
1084
  return finalizeCelForKro(expr, context?.nestedStatusCel, context);
681
1085
  }
1086
+ if (inValueTree && typeof obj === 'function') {
1087
+ throw valueTreeSerializationError(path, 'Functions are direct-mode only.');
1088
+ }
1089
+ if (inValueTree && typeof obj === 'symbol') {
1090
+ throw valueTreeSerializationError(path, 'Symbols are runtime-only values.');
1091
+ }
682
1092
  // Strings containing __KUBERNETES_REF__ markers from template literals.
683
1093
  // First resolve any nested-composition references — markers produced by
684
1094
  // `createKubernetesRefProxy` use a virtual baseId as the resourceId,
@@ -695,15 +1105,24 @@ export function processResourceReferences(obj, context) {
695
1105
  return resolved;
696
1106
  }
697
1107
  if (Array.isArray(obj)) {
698
- return obj.map((item) => processResourceReferences(item, context));
1108
+ return obj.flatMap((item, index) => {
1109
+ if (inValueTree && item === undefined)
1110
+ return [];
1111
+ return [processResourceReferences(item, context, arrayChildPath(path, index))];
1112
+ });
699
1113
  }
700
1114
  if (obj && typeof obj === 'object') {
1115
+ if (inValueTree && !isPlainSerializableObject(obj)) {
1116
+ throw valueTreeSerializationError(path, `${obj.constructor?.name ?? 'This value'} is not a plain serializable object.`);
1117
+ }
701
1118
  const result = {};
702
1119
  for (const [key, value] of Object.entries(obj)) {
703
- // Exclude hidden resourceId property and id field from the final template
704
- if (key === '__resourceId' || key === 'id')
1120
+ // Exclude hidden resourceId metadata; nested `id` fields can be valid resource config.
1121
+ if (key === '__resourceId')
1122
+ continue;
1123
+ if (inValueTree && value === undefined)
705
1124
  continue;
706
- result[key] = processResourceReferences(value, context);
1125
+ result[key] = processResourceReferences(value, context, childPath(path, key));
707
1126
  }
708
1127
  // Preserve resource metadata (resourceId, readinessEvaluator, etc.) via WeakMap
709
1128
  // Also migrates legacy non-enumerable properties from source
@@ -755,20 +1174,16 @@ export function serializeStatusMappingsToCel(statusMappings, nestedStatusCel, re
755
1174
  : normalized;
756
1175
  }
757
1176
  /**
758
- * Rewrite `schema.spec.*` references inside a resolved CEL expression so
759
- * the result is valid KRO status CEL. KRO does not accept `schema.spec.*`
760
- * in status CEL, so we apply two rewrites:
761
- *
762
- * - `schema.spec.X.Y.orValue(Z)` → `Z` (substitute the default)
763
- * - `schema.spec.X.Y` → `X.spec.Y` iff `X` is a known resource ID
764
- * (routes the reference to the deployed resource's spec field)
1177
+ * Rewrite resolved schema refs for KRO status CEL.
765
1178
  *
766
- * Unknown schema references are left intact; the KRO factory's deploy-
767
- * time hydration handles them.
1179
+ * KRO validates CR spec references as `schema.spec.*` in status mappings.
1180
+ * The only schema-to-resource rewrite we keep is the explicit legacy shape
1181
+ * `schema.spec.<resourceId>.<field>`, where `<resourceId>` is a real graph
1182
+ * resource. Plain CR spec fields must remain `schema.spec.*`.
768
1183
  */
769
1184
  function rewriteSchemaRefsForKroStatus(expr) {
770
1185
  let out = expr.replace(/__schema__\.spec\.[a-zA-Z0-9_.]+\.orValue\(([^)]+)\)/g, '$1');
771
- out = out.replace(/__schema__\.spec\.([a-zA-Z0-9_.]+)/g, 'spec.$1');
1186
+ out = out.replace(/__schema__\.spec\.([a-zA-Z0-9_.]+)/g, 'schema.spec.$1');
772
1187
  out = out.replace(/schema\.spec\.[a-zA-Z0-9_.]+\.orValue\(([^)]+)\)/g, '$1');
773
1188
  out = out.replace(/schema\.spec\.([a-zA-Z0-9]+)\.([a-zA-Z0-9.]+)/g, (_match, firstSegment, rest) => {
774
1189
  if (resourceIds?.has(firstSegment)) {
@@ -776,7 +1191,6 @@ export function serializeStatusMappingsToCel(statusMappings, nestedStatusCel, re
776
1191
  }
777
1192
  return _match;
778
1193
  });
779
- out = out.replace(/schema\.spec\.([a-zA-Z_$][\w$]*)/g, 'spec.$1');
780
1194
  return out;
781
1195
  }
782
1196
  /**
@@ -785,18 +1199,20 @@ export function serializeStatusMappingsToCel(statusMappings, nestedStatusCel, re
785
1199
  * Centralized here so the two branches don't drift on what "produce
786
1200
  * KRO status CEL from a resolved expression" means.
787
1201
  */
788
- function statusFieldFromExpression(expr) {
789
- const resolved = normalizeLocalResourceExpr(resolveNestedCompositionRefs(normalizeLocalResourceExpr(expr), nestedStatusCel, resourceIds));
1202
+ function statusFieldFromExpression(expr, rewriteSchemaRefs = true) {
1203
+ const resolved = normalizeCelArrayIndexPaths(normalizeLocalResourceExpr(resolveNestedCompositionRefs(normalizeLocalResourceExpr(expr), nestedStatusCel, resourceIds)));
790
1204
  if (resolved.includes('__KUBERNETES_REF_')) {
791
1205
  // Marker-laden — use mixed-template form.
792
- return rewriteSchemaRefsForKroStatus(convertKubernetesRefMarkersTocel(resolved));
1206
+ const converted = convertKubernetesRefMarkersTocel(resolved);
1207
+ return rewriteSchemaRefs ? rewriteSchemaRefsForKroStatus(converted) : converted;
793
1208
  }
794
1209
  if (resolved.includes('${')) {
795
1210
  // Already a KRO mixed-template value. Do not wrap it again as
796
1211
  // `${http://${...}}`, which is invalid CEL/YAML for status fields.
797
- return rewriteSchemaRefsForKroStatus(resolved);
1212
+ return rewriteSchemaRefs ? rewriteSchemaRefsForKroStatus(resolved) : resolved;
798
1213
  }
799
- return `\${${rewriteSchemaRefsForKroStatus(resolved)}}`;
1214
+ const expression = rewriteSchemaRefs ? rewriteSchemaRefsForKroStatus(resolved) : resolved;
1215
+ return `\${${expression}}`;
800
1216
  }
801
1217
  function serializeValue(value) {
802
1218
  if (isKubernetesRef(value)) {
@@ -819,7 +1235,7 @@ export function serializeStatusMappingsToCel(statusMappings, nestedStatusCel, re
819
1235
  }
820
1236
  if (isCelExpression(value)) {
821
1237
  if (value.__isTemplate) {
822
- return value.expression.replace(/\$\{([^}]+)\}/g, (_match, innerExpr) => statusFieldFromExpression(innerExpr));
1238
+ return value.expression.replace(/\$\{([^}]+)\}/g, (_match, innerExpr) => statusFieldFromExpression(normalizeSchemaSpecShorthand(innerExpr), false));
823
1239
  }
824
1240
  return statusFieldFromExpression(value.expression);
825
1241
  }