@intentius/chant-lexicon-k8s 0.124.30 → 0.124.32

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 (270) hide show
  1. package/dist/actions/apps.js +18 -0
  2. package/dist/actions/batch.js +6 -0
  3. package/dist/actions/core.js +48 -0
  4. package/dist/actions/index.js +13 -0
  5. package/dist/actions/networking.js +11 -0
  6. package/dist/actions/rbac.js +8 -0
  7. package/dist/api/classify.js +123 -0
  8. package/dist/api/connect.js +62 -0
  9. package/dist/api/fake-cluster.js +175 -0
  10. package/dist/api/operation-surface.d.ts.map +1 -1
  11. package/dist/api/operation-surface.js +109 -0
  12. package/dist/api/owner-chain.js +100 -0
  13. package/dist/api/sweep-types.js +35 -0
  14. package/dist/behaviour-kinds.js +82 -0
  15. package/dist/codegen/docs-cli.js +2 -0
  16. package/dist/codegen/docs.js +146 -0
  17. package/dist/codegen/generate-cli.js +30 -0
  18. package/dist/codegen/generate-lexicon.js +74 -0
  19. package/dist/codegen/generate-list-map-keys.js +88 -0
  20. package/dist/codegen/generate-operations.js +53 -0
  21. package/dist/codegen/generate-typescript.js +124 -0
  22. package/dist/codegen/generate.js +173 -0
  23. package/dist/codegen/naming.js +174 -0
  24. package/dist/codegen/package.js +36 -0
  25. package/dist/codegen/patches.js +88 -0
  26. package/dist/codegen/typecheck.js +4 -0
  27. package/dist/codegen/versions.js +41 -0
  28. package/dist/components/argo-app.js +51 -0
  29. package/dist/components/builders.js +22 -0
  30. package/dist/components/capability-plugin.js +31 -0
  31. package/dist/components/flux-reconcile.js +61 -0
  32. package/dist/components/index.d.ts +1 -1
  33. package/dist/components/index.d.ts.map +1 -1
  34. package/dist/components/index.js +18 -0
  35. package/dist/components/kubectl-apply.d.ts +83 -1
  36. package/dist/components/kubectl-apply.d.ts.map +1 -1
  37. package/dist/components/kubectl-apply.js +274 -0
  38. package/dist/components/kustomize-apply.js +25 -0
  39. package/dist/composites/adot-collector.js +184 -0
  40. package/dist/composites/agic-ingress.js +85 -0
  41. package/dist/composites/aks-external-dns-agent.js +146 -0
  42. package/dist/composites/alb-ingress.js +86 -0
  43. package/dist/composites/argo-app.js +199 -0
  44. package/dist/composites/autoscaled-service.js +174 -0
  45. package/dist/composites/azure-disk-storage-class.js +47 -0
  46. package/dist/composites/azure-file-storage-class.js +48 -0
  47. package/dist/composites/azure-monitor-collector.js +176 -0
  48. package/dist/composites/batch-job.js +139 -0
  49. package/dist/composites/catalog.js +4110 -0
  50. package/dist/composites/cockroachdb-cluster.js +371 -0
  51. package/dist/composites/cockroachdb-region-stack.js +369 -0
  52. package/dist/composites/config-connector-context.js +40 -0
  53. package/dist/composites/configured-app.js +135 -0
  54. package/dist/composites/cron-schedule.js +38 -0
  55. package/dist/composites/cron-workload.js +109 -0
  56. package/dist/composites/ebs-storage-class.js +54 -0
  57. package/dist/composites/efs-storage-class.js +46 -0
  58. package/dist/composites/external-dns-agent.js +122 -0
  59. package/dist/composites/filestore-storage-class.js +49 -0
  60. package/dist/composites/fluent-bit-agent.js +157 -0
  61. package/dist/composites/flux-app.js +156 -0
  62. package/dist/composites/gce-ingress.js +83 -0
  63. package/dist/composites/gce-pd-storage-class.js +49 -0
  64. package/dist/composites/gke-external-dns-agent.js +129 -0
  65. package/dist/composites/gke-fluent-bit-agent.js +165 -0
  66. package/dist/composites/gke-gateway.js +91 -0
  67. package/dist/composites/gke-otel-collector.js +94 -0
  68. package/dist/composites/index.js +51 -0
  69. package/dist/composites/inference-service.js +76 -0
  70. package/dist/composites/irsa-service-account.js +77 -0
  71. package/dist/composites/member-defaults.js +14 -0
  72. package/dist/composites/metrics-server.js +181 -0
  73. package/dist/composites/model.js +92 -0
  74. package/dist/composites/monitored-service.js +152 -0
  75. package/dist/composites/namespace-env.js +114 -0
  76. package/dist/composites/network-isolated-app.js +124 -0
  77. package/dist/composites/node-agent.js +149 -0
  78. package/dist/composites/operator-stack.js +268 -0
  79. package/dist/composites/otel-collector-agent.js +142 -0
  80. package/dist/composites/otel-collector-gateway.js +216 -0
  81. package/dist/composites/otel-collector-node.js +176 -0
  82. package/dist/composites/otel-collector-rbac.js +115 -0
  83. package/dist/composites/otel-collector-shape.js +128 -0
  84. package/dist/composites/otel-collector.js +115 -0
  85. package/dist/composites/otel-operator-collector.js +123 -0
  86. package/dist/composites/ray-cluster.js +378 -0
  87. package/dist/composites/ray-job.js +136 -0
  88. package/dist/composites/ray-service.js +178 -0
  89. package/dist/composites/secure-ingress.js +100 -0
  90. package/dist/composites/security-context.js +1 -0
  91. package/dist/composites/sidecar-app.js +105 -0
  92. package/dist/composites/stateful-app.js +111 -0
  93. package/dist/composites/vllm-serving-runtime.js +114 -0
  94. package/dist/composites/web-app.js +157 -0
  95. package/dist/composites/worker-pool.js +167 -0
  96. package/dist/composites/workload-identity-sa.js +81 -0
  97. package/dist/composites/workload-identity-service-account.js +77 -0
  98. package/dist/config-schema.js +72 -0
  99. package/dist/config.js +59 -0
  100. package/dist/coverage.js +27 -0
  101. package/dist/crd/crd-sources.js +615 -0
  102. package/dist/crd/loader.js +181 -0
  103. package/dist/crd/oci-chart.js +144 -0
  104. package/dist/crd/parser.js +382 -0
  105. package/dist/crd/project-codegen.js +273 -0
  106. package/dist/crd/types.js +7 -0
  107. package/dist/deep-observe-hooks.js +306 -0
  108. package/dist/deep-observe.js +234 -0
  109. package/dist/default-labels.js +87 -0
  110. package/dist/describe-resources.js +699 -0
  111. package/dist/describe-stack-status.js +99 -0
  112. package/dist/detect.js +11 -0
  113. package/dist/effect-receipt-row.js +205 -0
  114. package/dist/export-resources.js +39 -0
  115. package/dist/generated/index.js +1092 -0
  116. package/dist/generated/runtime.js +4 -0
  117. package/dist/group-namespace.js +96 -0
  118. package/dist/import/embedded.js +197 -0
  119. package/dist/import/generator.js +288 -0
  120. package/dist/import/live-export.js +85 -0
  121. package/dist/import/parser.js +204 -0
  122. package/dist/import/testdata/embedded/fixtures.js +60 -0
  123. package/dist/include/entity.js +78 -0
  124. package/dist/include/resolve.js +170 -0
  125. package/dist/index.js +59 -0
  126. package/dist/integrity.json +3 -3
  127. package/dist/kube/apply.js +90 -0
  128. package/dist/kube/connect.js +46 -0
  129. package/dist/kube/delete.js +138 -0
  130. package/dist/kube/describe.js +169 -0
  131. package/dist/kube/events.js +132 -0
  132. package/dist/kube/flags.js +91 -0
  133. package/dist/kube/get.js +159 -0
  134. package/dist/kube/group.js +123 -0
  135. package/dist/kube/logs.js +82 -0
  136. package/dist/kube/project.js +94 -0
  137. package/dist/kube/render.js +227 -0
  138. package/dist/kube/source.js +122 -0
  139. package/dist/kube/target.js +63 -0
  140. package/dist/kube/testing.js +28 -0
  141. package/dist/kube/top.js +99 -0
  142. package/dist/kube/verdict.js +72 -0
  143. package/dist/kube/wait.js +129 -0
  144. package/dist/kustomize/render.js +73 -0
  145. package/dist/kustomize/rendered-entity.js +67 -0
  146. package/dist/kustomize/root.js +68 -0
  147. package/dist/lint/audit-catalog.js +61 -0
  148. package/dist/lint/audit-lineage.js +118 -0
  149. package/dist/lint/post-synth/argo-helpers.js +36 -0
  150. package/dist/lint/post-synth/argo002.js +31 -0
  151. package/dist/lint/post-synth/argo003.js +53 -0
  152. package/dist/lint/post-synth/argo005.js +54 -0
  153. package/dist/lint/post-synth/crd-schema-helpers.d.ts.map +1 -1
  154. package/dist/lint/post-synth/crd-schema-helpers.js +214 -0
  155. package/dist/lint/post-synth/flux002.js +56 -0
  156. package/dist/lint/post-synth/flux003.js +50 -0
  157. package/dist/lint/post-synth/index.js +104 -0
  158. package/dist/lint/post-synth/k8s-helpers.js +186 -0
  159. package/dist/lint/post-synth/monitoring-selection-helpers.js +163 -0
  160. package/dist/lint/post-synth/otel-placement-helpers.js +293 -0
  161. package/dist/lint/post-synth/sops-helpers.js +43 -0
  162. package/dist/lint/post-synth/wk8005.js +44 -0
  163. package/dist/lint/post-synth/wk8006.js +56 -0
  164. package/dist/lint/post-synth/wk8041.js +60 -0
  165. package/dist/lint/post-synth/wk8042.js +36 -0
  166. package/dist/lint/post-synth/wk8101.js +52 -0
  167. package/dist/lint/post-synth/wk8102.js +30 -0
  168. package/dist/lint/post-synth/wk8103.js +33 -0
  169. package/dist/lint/post-synth/wk8104.js +58 -0
  170. package/dist/lint/post-synth/wk8105.js +33 -0
  171. package/dist/lint/post-synth/wk8201.js +44 -0
  172. package/dist/lint/post-synth/wk8202.js +34 -0
  173. package/dist/lint/post-synth/wk8203.js +34 -0
  174. package/dist/lint/post-synth/wk8204.js +71 -0
  175. package/dist/lint/post-synth/wk8205.js +38 -0
  176. package/dist/lint/post-synth/wk8207.js +33 -0
  177. package/dist/lint/post-synth/wk8208.js +33 -0
  178. package/dist/lint/post-synth/wk8209.js +33 -0
  179. package/dist/lint/post-synth/wk8301.js +49 -0
  180. package/dist/lint/post-synth/wk8302.js +34 -0
  181. package/dist/lint/post-synth/wk8303.js +68 -0
  182. package/dist/lint/post-synth/wk8304.js +58 -0
  183. package/dist/lint/post-synth/wk8305.js +96 -0
  184. package/dist/lint/post-synth/wk8306.js +38 -0
  185. package/dist/lint/post-synth/wk8401.js +86 -0
  186. package/dist/lint/post-synth/wk8402.js +31 -0
  187. package/dist/lint/post-synth/wk8403.js +49 -0
  188. package/dist/lint/post-synth/wk8404.js +36 -0
  189. package/dist/lint/post-synth/wk8405.js +65 -0
  190. package/dist/lint/post-synth/wk8406.js +50 -0
  191. package/dist/lint/post-synth/wk8407.js +58 -0
  192. package/dist/lint/post-synth/wk8501.js +36 -0
  193. package/dist/lint/post-synth/wk8502.js +35 -0
  194. package/dist/lint/post-synth/wk8503.js +164 -0
  195. package/dist/lint/post-synth/wk8504.js +20 -0
  196. package/dist/lint/post-synth/wk8505.js +31 -0
  197. package/dist/lint/post-synth/wk8601.js +40 -0
  198. package/dist/lint/post-synth/wk8602.js +120 -0
  199. package/dist/lint/post-synth/wk8603.js +63 -0
  200. package/dist/lint/post-synth/wk8604.js +31 -0
  201. package/dist/lint/post-synth/wk8605.js +124 -0
  202. package/dist/lint/post-synth/wk8606.js +22 -0
  203. package/dist/lint/post-synth/wk8701.js +31 -0
  204. package/dist/lint/post-synth/wk8702.js +37 -0
  205. package/dist/lint/post-synth/wk8703.js +31 -0
  206. package/dist/lint/post-synth/wk8704.js +135 -0
  207. package/dist/lint/post-synth/wk8705.js +38 -0
  208. package/dist/lint/rules/argo-appset-single-project.js +56 -0
  209. package/dist/lint/rules/argo-ast.js +94 -0
  210. package/dist/lint/rules/argo-automated-prune.js +59 -0
  211. package/dist/lint/rules/flux-source-ref-pin.js +44 -0
  212. package/dist/lint/rules/hardcoded-namespace.js +57 -0
  213. package/dist/lint/rules/latest-image-tag.js +103 -0
  214. package/dist/lint/rules/missing-resource-limits.js +85 -0
  215. package/dist/lsp/completions.d.ts.map +1 -1
  216. package/dist/lsp/completions.js +18 -0
  217. package/dist/lsp/hover.d.ts.map +1 -1
  218. package/dist/lsp/hover.js +57 -0
  219. package/dist/manifest-entity.js +71 -0
  220. package/dist/manifest.json +1 -1
  221. package/dist/micro-time.js +49 -0
  222. package/dist/op/activities/apply-diff.d.ts +31 -0
  223. package/dist/op/activities/apply-diff.d.ts.map +1 -0
  224. package/dist/op/activities/apply-diff.js +79 -0
  225. package/dist/op/activities/argo.js +98 -0
  226. package/dist/op/activities/ensure-secret.js +38 -0
  227. package/dist/op/activities/index.js +51 -0
  228. package/dist/op/activities/kubectl.d.ts +64 -0
  229. package/dist/op/activities/kubectl.d.ts.map +1 -1
  230. package/dist/op/activities/kubectl.js +517 -0
  231. package/dist/op/activities/wait-for-ready.js +229 -0
  232. package/dist/op/builders.js +68 -0
  233. package/dist/package-cli.js +21 -0
  234. package/dist/patch/json-patch.js +187 -0
  235. package/dist/patch/rendered-patch.js +94 -0
  236. package/dist/plugin.js +741 -0
  237. package/dist/project-kinds.js +56 -0
  238. package/dist/receipt-store.js +216 -0
  239. package/dist/rules/crd-schema-helpers.ts +2 -1
  240. package/dist/secret-labels.js +33 -0
  241. package/dist/secret-store.js +116 -0
  242. package/dist/serializer.d.ts.map +1 -1
  243. package/dist/serializer.js +578 -0
  244. package/dist/sops/encrypted-secret-file.js +194 -0
  245. package/dist/sops/entity.js +32 -0
  246. package/dist/spec/fetch.js +58 -0
  247. package/dist/spec/parse.js +622 -0
  248. package/dist/subscribe-changes.js +168 -0
  249. package/dist/teardown.js +197 -0
  250. package/dist/telemetry-release.js +86 -0
  251. package/dist/validate-cli.js +17 -0
  252. package/dist/validate.js +47 -0
  253. package/dist/variables.js +34 -0
  254. package/dist/whoami.js +109 -0
  255. package/package.json +12 -12
  256. package/src/api/operation-surface.ts +2 -1
  257. package/src/codegen/package.ts +2 -2
  258. package/src/components/index.ts +3 -0
  259. package/src/components/kubectl-apply-plan.k3d.e2e.test.ts +127 -0
  260. package/src/components/kubectl-apply.test.ts +262 -0
  261. package/src/components/kubectl-apply.ts +341 -12
  262. package/src/deep-observe-hooks.ts +2 -2
  263. package/src/import/roundtrip-build.test.ts +46 -0
  264. package/src/lint/post-synth/crd-schema-helpers.ts +2 -1
  265. package/src/lsp/completions.ts +2 -1
  266. package/src/lsp/hover.ts +2 -1
  267. package/src/op/activities/apply-diff.ts +87 -0
  268. package/src/op/activities/kubectl-plan.test.ts +224 -0
  269. package/src/op/activities/kubectl.ts +204 -16
  270. package/src/serializer.ts +2 -1
@@ -0,0 +1,622 @@
1
+ /**
2
+ * Kubernetes OpenAPI Swagger 2.0 parser.
3
+ *
4
+ * Parses the single swagger.json into multiple K8sParseResult entries —
5
+ * one per resource identified by `x-kubernetes-group-version-kind`.
6
+ * Property types (Container, PodSpec, Volume, etc.) are extracted as
7
+ * nested property types within their parent resources.
8
+ */
9
+ import { extractConstraints as coreExtractConstraints, primaryType, } from "@intentius/chant/codegen/json-schema";
10
+ import { namespaceSegmentForGroup } from "../group-namespace.js";
11
+ // ── Well-known property type definitions ───────────────────────────
12
+ /**
13
+ * Definitions that should be extracted as standalone property types
14
+ * even though they don't have GVK. Mapped to friendly names.
15
+ */
16
+ const PROPERTY_TYPE_DEFS = {
17
+ "io.k8s.api.core.v1.Container": { typeName: "K8s::Core::Container", description: "A container definition for a pod" },
18
+ "io.k8s.api.core.v1.ContainerPort": { typeName: "K8s::Core::ContainerPort", description: "A port to expose from a container" },
19
+ "io.k8s.api.core.v1.EnvVar": { typeName: "K8s::Core::EnvVar", description: "An environment variable for a container" },
20
+ "io.k8s.api.core.v1.EnvFromSource": { typeName: "K8s::Core::EnvFromSource", description: "Source for environment variables" },
21
+ "io.k8s.api.core.v1.Volume": { typeName: "K8s::Core::Volume", description: "A volume that can be mounted by containers" },
22
+ "io.k8s.api.core.v1.VolumeMount": { typeName: "K8s::Core::VolumeMount", description: "A volume mount in a container" },
23
+ "io.k8s.api.core.v1.PodSpec": { typeName: "K8s::Core::PodSpec", description: "Specification of a pod" },
24
+ "io.k8s.api.core.v1.PodTemplateSpec": { typeName: "K8s::Core::PodTemplateSpec", description: "Pod template specification" },
25
+ "io.k8s.api.core.v1.ServicePort": { typeName: "K8s::Core::ServicePort", description: "A port exposed by a service" },
26
+ "io.k8s.api.core.v1.Probe": { typeName: "K8s::Core::Probe", description: "A health check probe" },
27
+ "io.k8s.api.core.v1.ResourceRequirements": { typeName: "K8s::Core::ResourceRequirements", description: "CPU and memory resource requirements" },
28
+ "io.k8s.api.core.v1.SecurityContext": { typeName: "K8s::Core::SecurityContext", description: "Security options for a container" },
29
+ "io.k8s.api.core.v1.PodSecurityContext": { typeName: "K8s::Core::PodSecurityContext", description: "Security options for a pod" },
30
+ "io.k8s.api.core.v1.Capabilities": { typeName: "K8s::Core::Capabilities", description: "Linux capabilities to add or drop" },
31
+ "io.k8s.api.core.v1.ConfigMapKeySelector": { typeName: "K8s::Core::ConfigMapKeySelector", description: "Reference to a key in a ConfigMap" },
32
+ "io.k8s.api.core.v1.SecretKeySelector": { typeName: "K8s::Core::SecretKeySelector", description: "Reference to a key in a Secret" },
33
+ "io.k8s.api.core.v1.EnvVarSource": { typeName: "K8s::Core::EnvVarSource", description: "Source for an environment variable value" },
34
+ "io.k8s.api.core.v1.ObjectReference": { typeName: "K8s::Core::ObjectReference", description: "Reference to another Kubernetes object" },
35
+ "io.k8s.api.core.v1.LocalObjectReference": { typeName: "K8s::Core::LocalObjectReference", description: "Reference to a local object" },
36
+ "io.k8s.api.core.v1.Toleration": { typeName: "K8s::Core::Toleration", description: "A toleration for pod scheduling" },
37
+ "io.k8s.api.core.v1.Affinity": { typeName: "K8s::Core::Affinity", description: "Scheduling affinity rules" },
38
+ "io.k8s.api.core.v1.TopologySpreadConstraint": { typeName: "K8s::Core::TopologySpreadConstraint", description: "Pod topology spread constraint" },
39
+ "io.k8s.api.core.v1.PersistentVolumeClaimSpec": { typeName: "K8s::Core::PersistentVolumeClaimSpec", description: "PVC spec for StatefulSet volume templates" },
40
+ "io.k8s.api.core.v1.HTTPGetAction": { typeName: "K8s::Core::HTTPGetAction", description: "HTTP GET probe action" },
41
+ "io.k8s.api.core.v1.TCPSocketAction": { typeName: "K8s::Core::TCPSocketAction", description: "TCP socket probe action" },
42
+ "io.k8s.api.core.v1.ExecAction": { typeName: "K8s::Core::ExecAction", description: "Exec probe action" },
43
+ "io.k8s.api.core.v1.HostAlias": { typeName: "K8s::Core::HostAlias", description: "Host alias entry for /etc/hosts" },
44
+ "io.k8s.api.core.v1.EphemeralContainer": { typeName: "K8s::Core::EphemeralContainer", description: "An ephemeral container for debugging" },
45
+ "io.k8s.api.core.v1.KeyToPath": { typeName: "K8s::Core::KeyToPath", description: "Maps a key to a file path" },
46
+ "io.k8s.api.apps.v1.DeploymentStrategy": { typeName: "K8s::Apps::DeploymentStrategy", description: "Deployment rolling update strategy" },
47
+ "io.k8s.api.apps.v1.RollingUpdateDeployment": { typeName: "K8s::Apps::RollingUpdateDeployment", description: "Rolling update parameters" },
48
+ "io.k8s.api.networking.v1.IngressRule": { typeName: "K8s::Networking::IngressRule", description: "Ingress routing rule" },
49
+ "io.k8s.api.networking.v1.IngressTLS": { typeName: "K8s::Networking::IngressTLS", description: "Ingress TLS configuration" },
50
+ "io.k8s.api.networking.v1.HTTPIngressPath": { typeName: "K8s::Networking::HTTPIngressPath", description: "HTTP Ingress path" },
51
+ "io.k8s.api.networking.v1.IngressBackend": { typeName: "K8s::Networking::IngressBackend", description: "Ingress backend reference" },
52
+ "io.k8s.api.networking.v1.IngressServiceBackend": { typeName: "K8s::Networking::IngressServiceBackend", description: "Ingress service backend" },
53
+ "io.k8s.api.networking.v1.ServiceBackendPort": { typeName: "K8s::Networking::ServiceBackendPort", description: "Service port reference" },
54
+ "io.k8s.api.networking.v1.NetworkPolicyIngressRule": { typeName: "K8s::Networking::NetworkPolicyIngressRule", description: "NetworkPolicy ingress rule" },
55
+ "io.k8s.api.networking.v1.NetworkPolicyEgressRule": { typeName: "K8s::Networking::NetworkPolicyEgressRule", description: "NetworkPolicy egress rule" },
56
+ "io.k8s.api.networking.v1.NetworkPolicyPeer": { typeName: "K8s::Networking::NetworkPolicyPeer", description: "NetworkPolicy peer selector" },
57
+ "io.k8s.api.networking.v1.NetworkPolicyPort": { typeName: "K8s::Networking::NetworkPolicyPort", description: "NetworkPolicy port" },
58
+ "io.k8s.api.rbac.v1.PolicyRule": { typeName: "K8s::Rbac::PolicyRule", description: "RBAC policy rule" },
59
+ "io.k8s.api.rbac.v1.RoleRef": { typeName: "K8s::Rbac::RoleRef", description: "RBAC role reference" },
60
+ "io.k8s.api.rbac.v1.Subject": { typeName: "K8s::Rbac::Subject", description: "RBAC subject" },
61
+ "io.k8s.api.autoscaling.v2.MetricSpec": { typeName: "K8s::Autoscaling::MetricSpec", description: "HPA metric specification" },
62
+ "io.k8s.api.autoscaling.v2.HorizontalPodAutoscalerBehavior": { typeName: "K8s::Autoscaling::HorizontalPodAutoscalerBehavior", description: "HPA scaling behavior" },
63
+ "io.k8s.api.policy.v1.PodDisruptionBudgetSpec": { typeName: "K8s::Policy::PodDisruptionBudgetSpec", description: "PDB specification" },
64
+ "io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta": { typeName: "K8s::Meta::ObjectMeta", description: "Standard object metadata" },
65
+ "io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelector": { typeName: "K8s::Meta::LabelSelector", description: "Label selector" },
66
+ "io.k8s.apimachinery.pkg.apis.meta.v1.LabelSelectorRequirement": { typeName: "K8s::Meta::LabelSelectorRequirement", description: "Label selector requirement" },
67
+ };
68
+ // ── Parser ─────────────────────────────────────────────────────────
69
+ /**
70
+ * Parse the Kubernetes OpenAPI swagger.json into multiple resource results.
71
+ * Returns one result per top-level resource identified by x-kubernetes-group-version-kind.
72
+ */
73
+ export function parseK8sSwagger(data) {
74
+ return parseK8sSwaggerTypes(data).results;
75
+ }
76
+ /**
77
+ * Parse the swagger document into resource and property-type results, and the
78
+ * declaration-only interfaces for every other object definition a resource
79
+ * reaches (chant #3093).
80
+ */
81
+ export function parseK8sSwaggerTypes(data) {
82
+ const spec = JSON.parse(typeof data === "string" ? data : data.toString("utf-8"));
83
+ const definitions = spec.definitions ?? {};
84
+ const results = [];
85
+ const operations = parseOperations(spec.paths);
86
+ // Which definitions become resources: those with a GVK, preferred version only.
87
+ const resourceDefs = [];
88
+ for (const [defKey, def] of Object.entries(definitions)) {
89
+ const gvks = def["x-kubernetes-group-version-kind"];
90
+ if (!gvks || gvks.length === 0)
91
+ continue;
92
+ // Take the first GVK (most definitions have exactly one)
93
+ const gvk = gvks[0];
94
+ // Skip internal/legacy API versions — only take the preferred version
95
+ if (!isPreferredVersion(defKey, gvk, definitions))
96
+ continue;
97
+ resourceDefs.push({ defKey, def, gvk });
98
+ }
99
+ // Name every object definition a resource reaches before any property is
100
+ // typed, so a `$ref` resolves to its interface instead of a Record.
101
+ const reachable = reachableDefinitions(resourceDefs.map((r) => r.def), definitions);
102
+ const ctx = {
103
+ definitions,
104
+ names: nameDefinitions(reachable, definitions),
105
+ resources: new Set(resourceDefs.map((r) => r.defKey)),
106
+ };
107
+ // Phase 1: Extract top-level resources (definitions with GVK)
108
+ for (const { defKey, def, gvk } of resourceDefs) {
109
+ const typeName = gvkToTypeName(gvk);
110
+ const result = extractResource(defKey, def, typeName, gvk, ctx);
111
+ if (result) {
112
+ const operation = operations.get(gvkKey(gvk));
113
+ if (operation)
114
+ result.operation = operation;
115
+ results.push(result);
116
+ }
117
+ }
118
+ // Phase 2: Extract well-known property types
119
+ for (const [defKey, config] of Object.entries(PROPERTY_TYPE_DEFS)) {
120
+ const def = definitions[defKey];
121
+ if (!def)
122
+ continue;
123
+ const result = extractPropertyType(defKey, def, config.typeName, config.description, ctx);
124
+ if (result)
125
+ results.push(result);
126
+ }
127
+ // Phase 3: Every other reachable object definition, as an interface.
128
+ const definitionTypes = [];
129
+ for (const defKey of reachable) {
130
+ if (PROPERTY_TYPE_DEFS[defKey])
131
+ continue;
132
+ const def = definitions[defKey];
133
+ definitionTypes.push({
134
+ name: ctx.names.get(defKey),
135
+ defKey,
136
+ description: def.description,
137
+ properties: parseProperties(def.properties ?? {}, new Set(def.required ?? []), ctx),
138
+ });
139
+ }
140
+ definitionTypes.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
141
+ return { results, definitionTypes };
142
+ }
143
+ // ── Definition interfaces (chant #3093) ────────────────────────────
144
+ /**
145
+ * Definitions that stay open however they are reached: `RawExtension` holds an
146
+ * arbitrary embedded object, and the rest are scalars on the wire. A Quantity
147
+ * is a string in the schema, but the API server also decodes a number
148
+ * (`cpu: 1`), and manifests write it both ways.
149
+ */
150
+ const OPEN_OR_SCALAR_DEFS = {
151
+ "io.k8s.apimachinery.pkg.util.intstr.IntOrString": "string | number",
152
+ "io.k8s.apimachinery.pkg.api.resource.Quantity": "string | number",
153
+ "io.k8s.apimachinery.pkg.apis.meta.v1.Time": "string",
154
+ "io.k8s.apimachinery.pkg.apis.meta.v1.MicroTime": "string",
155
+ "io.k8s.apimachinery.pkg.runtime.RawExtension": "Record<string, any>",
156
+ };
157
+ /**
158
+ * A resource embedded in another object (`StatefulSetSpec.volumeClaimTemplates`
159
+ * holds PersistentVolumeClaims, a List holds its items) is typed inline with
160
+ * the props its class takes. A name would have to avoid the class's own.
161
+ */
162
+ function inlineResourceType(defKey, ctx) {
163
+ const inlining = ctx.inlining ?? new Set();
164
+ if (inlining.has(defKey))
165
+ return "Record<string, any>";
166
+ const def = ctx.definitions[defKey];
167
+ const inner = { ...ctx, inlining: new Set([...inlining, defKey]) };
168
+ const required = new Set(def.required ?? []);
169
+ const members = Object.entries(def.properties ?? {})
170
+ .filter(([name]) => name !== "apiVersion" && name !== "kind" && name !== "status")
171
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
172
+ .map(([name, prop]) => `${name}${required.has(name) ? "" : "?"}: ${resolvePropertyType(prop, inner)}`);
173
+ return members.length === 0 ? "Record<string, any>" : `{ ${members.join("; ")} }`;
174
+ }
175
+ /**
176
+ * Whether a definition becomes a named type: an object with properties that
177
+ * is not itself a resource. A `$ref` to a resource is typed inline instead
178
+ * ({@link inlineResourceType}).
179
+ */
180
+ function isNamedObjectDef(defKey, def) {
181
+ if (!def?.properties || defKey in OPEN_OR_SCALAR_DEFS)
182
+ return false;
183
+ return !def["x-kubernetes-group-version-kind"]?.length;
184
+ }
185
+ /**
186
+ * The object definitions reachable from the resources' authored properties
187
+ * (everything but `apiVersion`, `kind` and `status`), plus the well-known
188
+ * property types. Sorted by key. A recursive definition such as
189
+ * `JSONSchemaProps` is visited once and refers to itself by name, so no depth
190
+ * bound is needed.
191
+ */
192
+ function reachableDefinitions(resources, definitions) {
193
+ const seen = new Set();
194
+ const queue = [];
195
+ const visitRef = (defKey) => {
196
+ if (seen.has(defKey) || !isNamedObjectDef(defKey, definitions[defKey]))
197
+ return;
198
+ seen.add(defKey);
199
+ queue.push(defKey);
200
+ };
201
+ const walk = (prop) => {
202
+ if (!prop)
203
+ return;
204
+ if (prop.$ref) {
205
+ if (prop.$ref.startsWith("#/definitions/"))
206
+ visitRef(prop.$ref.slice("#/definitions/".length));
207
+ return;
208
+ }
209
+ walk(prop.items);
210
+ if (prop.additionalProperties && typeof prop.additionalProperties === "object")
211
+ walk(prop.additionalProperties);
212
+ };
213
+ for (const def of resources) {
214
+ for (const [name, prop] of Object.entries(def.properties ?? {})) {
215
+ if (name !== "apiVersion" && name !== "kind" && name !== "status")
216
+ walk(prop);
217
+ }
218
+ }
219
+ for (const defKey of Object.keys(PROPERTY_TYPE_DEFS))
220
+ visitRef(defKey);
221
+ while (queue.length > 0) {
222
+ const def = definitions[queue.shift()];
223
+ for (const prop of Object.values(def.properties ?? {}))
224
+ walk(prop);
225
+ }
226
+ return [...seen].sort();
227
+ }
228
+ const VERSION_SEGMENT = /^v\d+((alpha|beta)\d+)?$/;
229
+ /** `io.k8s.api.flowcontrol.v1.Subject` → `{ group: "Flowcontrol", version: "V1", kind: "Subject" }`. */
230
+ function definitionKeyParts(defKey) {
231
+ const parts = defKey.split(".");
232
+ const kind = parts[parts.length - 1];
233
+ const vIdx = parts.length - 2;
234
+ const version = VERSION_SEGMENT.test(parts[vIdx] ?? "") ? parts[vIdx] : "";
235
+ const group = (version ? parts[vIdx - 1] : parts[vIdx]) ?? "";
236
+ const pascal = (s) => s.split(/[^A-Za-z0-9]+/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join("");
237
+ return { group: pascal(group), version: pascal(version), kind };
238
+ }
239
+ /**
240
+ * Give every reachable definition a TypeScript name.
241
+ *
242
+ * The well-known property types keep their friendly names. Every other
243
+ * definition takes the last segment of its key (`DeploymentSpec`) when no
244
+ * other reachable definition shares that segment and no resource kind or
245
+ * friendly name already uses it. Otherwise each contender is qualified by its
246
+ * API group (`FlowcontrolSubject`, `CoreResourceClaim`), and by group and
247
+ * version when one group has several (`ResourceV1beta2Device`). The rule
248
+ * reads only the set of keys, so the result does not depend on the order of
249
+ * the document.
250
+ */
251
+ function nameDefinitions(reachable, definitions) {
252
+ const names = new Map();
253
+ const taken = new Set();
254
+ for (const def of Object.values(definitions)) {
255
+ for (const gvk of def["x-kubernetes-group-version-kind"] ?? [])
256
+ taken.add(gvk.kind);
257
+ }
258
+ for (const [defKey, config] of Object.entries(PROPERTY_TYPE_DEFS)) {
259
+ const name = k8sShortName(config.typeName);
260
+ names.set(defKey, name);
261
+ taken.add(name);
262
+ }
263
+ const byKind = new Map();
264
+ for (const defKey of reachable) {
265
+ if (names.has(defKey))
266
+ continue;
267
+ const { kind } = definitionKeyParts(defKey);
268
+ byKind.set(kind, [...(byKind.get(kind) ?? []), defKey]);
269
+ }
270
+ for (const [kind, keys] of byKind) {
271
+ if (keys.length === 1 && !taken.has(kind)) {
272
+ names.set(keys[0], kind);
273
+ continue;
274
+ }
275
+ const groupCount = new Map();
276
+ for (const k of keys) {
277
+ const { group } = definitionKeyParts(k);
278
+ groupCount.set(group, (groupCount.get(group) ?? 0) + 1);
279
+ }
280
+ for (const k of keys) {
281
+ const { group, version } = definitionKeyParts(k);
282
+ names.set(k, groupCount.get(group) > 1 ? `${group}${version}${kind}` : `${group}${kind}`);
283
+ }
284
+ }
285
+ const owner = new Map();
286
+ for (const [defKey, name] of names) {
287
+ const prev = owner.get(name);
288
+ if (prev)
289
+ throw new Error(`k8s codegen: definitions ${prev} and ${defKey} both map to the type name ${name}`);
290
+ owner.set(name, defKey);
291
+ }
292
+ return names;
293
+ }
294
+ /** Stable key for a GVK, used to join the `paths` pass onto the `definitions` pass. */
295
+ /**
296
+ * Every `(property name, list-map keys)` pair the spec declares, across ALL
297
+ * definitions (chant #1441).
298
+ *
299
+ * Deliberately independent of {@link parseK8sSwagger}'s resource/property-type
300
+ * extraction. That extraction keeps 257 resources and 320 property types out
301
+ * of roughly a thousand definitions, so collecting merge keys from its output
302
+ * alone finds 18 of the 32 properties the spec annotates — and misses
303
+ * `ServicePort.port`, whose absence would silently demote every Service port
304
+ * list to the hand-written fallback. A definition is worth reading for its
305
+ * merge semantics whether or not chant emits a type for it.
306
+ */
307
+ export function specListMapKeyPairs(data) {
308
+ const spec = JSON.parse(typeof data === "string" ? data : data.toString("utf-8"));
309
+ const pairs = [];
310
+ for (const def of Object.values(spec.definitions ?? {})) {
311
+ for (const [name, prop] of Object.entries(def.properties ?? {})) {
312
+ if (prop["x-kubernetes-list-type"] !== "map")
313
+ continue;
314
+ const keys = prop["x-kubernetes-list-map-keys"];
315
+ if (keys?.length)
316
+ pairs.push([name, [...keys]]);
317
+ }
318
+ }
319
+ return pairs;
320
+ }
321
+ export function gvkKey(gvk) {
322
+ return `${gvk.group}|${gvk.version}|${gvk.kind}`;
323
+ }
324
+ /**
325
+ * Derive the operation surface from the OpenAPI `paths` — chant #1074.
326
+ *
327
+ * Every Kubernetes operation carries `x-kubernetes-group-version-kind` and
328
+ * `x-kubernetes-action`, and the path itself carries the two facts a REST call
329
+ * needs and a definition does not have: the plural segment, and whether the
330
+ * resource is namespaced (`/namespaces/{namespace}/` appears in its path).
331
+ *
332
+ * Only paths addressing a single named object (`.../{plural}/{name}`) are read,
333
+ * so subresource paths (`.../{name}/status`, `.../{name}/scale`) and collection
334
+ * paths do not supply the plural — but their verbs are collected, because
335
+ * "this kind can be listed" is worth knowing.
336
+ */
337
+ export function parseOperations(paths) {
338
+ const out = new Map();
339
+ if (!paths)
340
+ return out;
341
+ for (const [path, item] of Object.entries(paths)) {
342
+ for (const operation of Object.values(item ?? {})) {
343
+ if (!operation || typeof operation !== "object")
344
+ continue;
345
+ const op = operation;
346
+ const gvk = op["x-kubernetes-group-version-kind"];
347
+ const action = op["x-kubernetes-action"];
348
+ if (!gvk || !action)
349
+ continue;
350
+ const segments = path.split("/").filter(Boolean);
351
+ const last = segments[segments.length - 1];
352
+ // `.../{plural}/{name}` — the only shape that names the plural
353
+ // unambiguously. `/api/v1/namespaces/{name}` is such a shape too, and
354
+ // correctly yields plural `namespaces`, cluster-scoped.
355
+ if (last !== "{name}")
356
+ continue;
357
+ const plural = segments[segments.length - 2];
358
+ if (!plural || plural.startsWith("{"))
359
+ continue;
360
+ const key = gvkKey(gvk);
361
+ const existing = out.get(key);
362
+ if (existing) {
363
+ if (!existing.verbs.includes(action))
364
+ existing.verbs.push(action);
365
+ continue;
366
+ }
367
+ out.set(key, {
368
+ plural,
369
+ scope: path.includes("/namespaces/{namespace}/") ? "Namespaced" : "Cluster",
370
+ verbs: [action],
371
+ });
372
+ }
373
+ }
374
+ for (const operation of out.values())
375
+ operation.verbs.sort();
376
+ return out;
377
+ }
378
+ /**
379
+ * Convert GVK to our type name convention: K8s::{Group}::{Kind}
380
+ */
381
+ export function gvkToTypeName(gvk) {
382
+ const group = normalizeGroup(gvk.group);
383
+ return `K8s::${group}::${gvk.kind}`;
384
+ }
385
+ /**
386
+ * Convert GVK to apiVersion string for serialization.
387
+ */
388
+ export function gvkToApiVersion(gvk) {
389
+ if (!gvk.group || gvk.group === "") {
390
+ return gvk.version; // core group: "v1"
391
+ }
392
+ return `${gvk.group}/${gvk.version}`; // e.g. "apps/v1"
393
+ }
394
+ /**
395
+ * Normalize API group to a PascalCase segment — the shared rule, so the
396
+ * swagger-generated surface, kustomize-rendered entities and live discovery
397
+ * (all three reach here through `gvkToTypeName`) spell a kind exactly as CRD
398
+ * codegen and `chant import` do. See `../group-namespace`.
399
+ */
400
+ function normalizeGroup(group) {
401
+ return namespaceSegmentForGroup(group);
402
+ }
403
+ /**
404
+ * Check if this definition key represents the preferred API version.
405
+ * Prefer stable (v1) over beta/alpha, and prefer the highest stable version.
406
+ */
407
+ function isPreferredVersion(defKey, gvk, definitions) {
408
+ // Skip alpha versions
409
+ if (gvk.version.includes("alpha"))
410
+ return false;
411
+ // Find all definitions with the same GVK kind+group
412
+ const sameName = [];
413
+ for (const [key, def] of Object.entries(definitions)) {
414
+ const gvks = def["x-kubernetes-group-version-kind"];
415
+ if (!gvks)
416
+ continue;
417
+ for (const g of gvks) {
418
+ if (g.kind === gvk.kind && g.group === gvk.group) {
419
+ sameName.push({ key, version: g.version });
420
+ }
421
+ }
422
+ }
423
+ if (sameName.length <= 1)
424
+ return true;
425
+ // Prefer stable (v1, v2) over beta
426
+ const stable = sameName.filter((s) => !s.version.includes("beta") && !s.version.includes("alpha"));
427
+ if (stable.length > 0) {
428
+ // Among stable, pick the highest version
429
+ stable.sort((a, b) => b.version.localeCompare(a.version));
430
+ return defKey === stable[0].key;
431
+ }
432
+ // All beta — pick highest
433
+ sameName.sort((a, b) => b.version.localeCompare(a.version));
434
+ return defKey === sameName[0].key;
435
+ }
436
+ /**
437
+ * Extract a top-level resource from a swagger definition.
438
+ */
439
+ function extractResource(defKey, def, typeName, gvk, ctx) {
440
+ if (!def.properties)
441
+ return null;
442
+ const requiredSet = new Set(def.required ?? []);
443
+ // K8s resources have standard fields (apiVersion, kind, metadata, spec, status)
444
+ // We only expose user-configurable properties — skip apiVersion, kind, status
445
+ const skipProps = new Set(["apiVersion", "kind", "status"]);
446
+ const filteredProps = {};
447
+ for (const [name, prop] of Object.entries(def.properties)) {
448
+ if (!skipProps.has(name)) {
449
+ filteredProps[name] = prop;
450
+ }
451
+ }
452
+ const properties = parseProperties(filteredProps, requiredSet, ctx);
453
+ return {
454
+ resource: {
455
+ typeName,
456
+ description: def.description,
457
+ properties,
458
+ attributes: [
459
+ { name: "name", tsType: "string" },
460
+ { name: "namespace", tsType: "string" },
461
+ { name: "uid", tsType: "string" },
462
+ ],
463
+ deprecatedProperties: [],
464
+ },
465
+ propertyTypes: [],
466
+ enums: [],
467
+ gvk,
468
+ };
469
+ }
470
+ /**
471
+ * Extract a property type definition (not a top-level resource).
472
+ */
473
+ function extractPropertyType(defKey, def, typeName, description, ctx) {
474
+ if (!def.properties)
475
+ return null;
476
+ const requiredSet = new Set(def.required ?? []);
477
+ const properties = parseProperties(def.properties, requiredSet, ctx);
478
+ const gvkParts = typeName.split("::");
479
+ return {
480
+ resource: {
481
+ typeName,
482
+ description,
483
+ properties,
484
+ attributes: [],
485
+ deprecatedProperties: [],
486
+ },
487
+ propertyTypes: [],
488
+ enums: [],
489
+ gvk: { group: gvkParts[1]?.toLowerCase() ?? "", version: "v1", kind: gvkParts[2] ?? "" },
490
+ isProperty: true,
491
+ };
492
+ }
493
+ /**
494
+ * Parse properties from a swagger definition into ParsedProperty[].
495
+ */
496
+ function parseProperties(properties, requiredSet, ctx) {
497
+ const result = [];
498
+ for (const [name, prop] of Object.entries(properties)) {
499
+ const tsType = resolvePropertyType(prop, ctx);
500
+ const parsed = {
501
+ name,
502
+ tsType,
503
+ required: requiredSet.has(name),
504
+ description: prop.description,
505
+ enum: prop.enum,
506
+ constraints: coreExtractConstraints(prop),
507
+ };
508
+ // chant #1441 — the merge semantics the API server itself uses. Kept only
509
+ // when present; a spec that says nothing leaves both fields absent rather
510
+ // than asserting a default the schema did not state.
511
+ const listType = prop["x-kubernetes-list-type"];
512
+ if (listType)
513
+ parsed.listType = listType;
514
+ const listMapKeys = prop["x-kubernetes-list-map-keys"];
515
+ if (listMapKeys?.length)
516
+ parsed.listMapKeys = [...listMapKeys];
517
+ result.push(parsed);
518
+ }
519
+ return result;
520
+ }
521
+ /**
522
+ * Resolve a swagger property to its TypeScript type string.
523
+ */
524
+ function resolvePropertyType(prop, ctx) {
525
+ if (!prop)
526
+ return "any";
527
+ // Handle $ref
528
+ if (prop.$ref) {
529
+ return resolveRefType(prop.$ref, ctx);
530
+ }
531
+ // x-kubernetes-int-or-string
532
+ if (prop["x-kubernetes-int-or-string"]) {
533
+ return "string | number";
534
+ }
535
+ // Inline enum
536
+ if (prop.enum && prop.enum.length > 0) {
537
+ return prop.enum.map((v) => JSON.stringify(v)).join(" | ");
538
+ }
539
+ const pt = primaryType(prop.type);
540
+ switch (pt) {
541
+ case "string":
542
+ return "string";
543
+ case "integer":
544
+ case "number":
545
+ return "number";
546
+ case "boolean":
547
+ return "boolean";
548
+ case "array":
549
+ if (prop.items) {
550
+ const itemType = resolvePropertyType(prop.items, ctx);
551
+ if (itemType.includes(" | "))
552
+ return `(${itemType})[]`;
553
+ return `${itemType}[]`;
554
+ }
555
+ return "any[]";
556
+ case "object":
557
+ if (prop.additionalProperties && typeof prop.additionalProperties === "object") {
558
+ const valueType = resolvePropertyType(prop.additionalProperties, ctx);
559
+ return `Record<string, ${valueType}>`;
560
+ }
561
+ return "Record<string, any>";
562
+ default:
563
+ return "any";
564
+ }
565
+ }
566
+ /**
567
+ * Resolve a $ref to a TypeScript type.
568
+ */
569
+ function resolveRefType(ref, ctx) {
570
+ const prefix = "#/definitions/";
571
+ if (!ref.startsWith(prefix))
572
+ return "any";
573
+ const defKey = ref.slice(prefix.length);
574
+ // Well-known scalars, and RawExtension, which stays open.
575
+ const fixed = OPEN_OR_SCALAR_DEFS[defKey];
576
+ if (fixed)
577
+ return fixed;
578
+ // A property class or a definition interface (chant #3093).
579
+ const named = ctx.names.get(defKey);
580
+ if (named)
581
+ return named;
582
+ if (ctx.resources.has(defKey))
583
+ return inlineResourceType(defKey, ctx);
584
+ // Resolve the definition
585
+ const def = ctx.definitions[defKey];
586
+ if (!def)
587
+ return "any";
588
+ // Enum
589
+ if (def.enum && def.enum.length > 0 && !def.properties) {
590
+ return def.enum.map((v) => JSON.stringify(v)).join(" | ");
591
+ }
592
+ // Primitive type
593
+ if (def.type && !def.properties) {
594
+ const pt = primaryType(def.type);
595
+ switch (pt) {
596
+ case "string": return "string";
597
+ case "integer":
598
+ case "number": return "number";
599
+ case "boolean": return "boolean";
600
+ default: return "any";
601
+ }
602
+ }
603
+ // An object this pass does not name: a resource of a non-preferred
604
+ // version, or a definition with no properties (`JSON`, `FieldsV1`).
605
+ if (def.properties)
606
+ return "Record<string, any>";
607
+ return "any";
608
+ }
609
+ /**
610
+ * Extract short name: "K8s::Apps::Deployment" → "Deployment"
611
+ */
612
+ export function k8sShortName(typeName) {
613
+ const parts = typeName.split("::");
614
+ return parts[parts.length - 1];
615
+ }
616
+ /**
617
+ * Extract service/group name: "K8s::Apps::Deployment" → "Apps"
618
+ */
619
+ export function k8sServiceName(typeName) {
620
+ const parts = typeName.split("::");
621
+ return parts.length >= 2 ? parts[1] : "Core";
622
+ }