@intentius/chant-lexicon-k8s 0.124.31 → 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.
- package/dist/actions/apps.js +18 -0
- package/dist/actions/batch.js +6 -0
- package/dist/actions/core.js +48 -0
- package/dist/actions/index.js +13 -0
- package/dist/actions/networking.js +11 -0
- package/dist/actions/rbac.js +8 -0
- package/dist/api/classify.js +123 -0
- package/dist/api/connect.js +62 -0
- package/dist/api/fake-cluster.js +175 -0
- package/dist/api/operation-surface.d.ts.map +1 -1
- package/dist/api/operation-surface.js +109 -0
- package/dist/api/owner-chain.js +100 -0
- package/dist/api/sweep-types.js +35 -0
- package/dist/behaviour-kinds.js +82 -0
- package/dist/codegen/docs-cli.js +2 -0
- package/dist/codegen/docs.js +146 -0
- package/dist/codegen/generate-cli.js +30 -0
- package/dist/codegen/generate-lexicon.js +74 -0
- package/dist/codegen/generate-list-map-keys.js +88 -0
- package/dist/codegen/generate-operations.js +53 -0
- package/dist/codegen/generate-typescript.js +124 -0
- package/dist/codegen/generate.js +173 -0
- package/dist/codegen/naming.js +174 -0
- package/dist/codegen/package.js +36 -0
- package/dist/codegen/patches.js +88 -0
- package/dist/codegen/typecheck.js +4 -0
- package/dist/codegen/versions.js +41 -0
- package/dist/components/argo-app.js +51 -0
- package/dist/components/builders.js +22 -0
- package/dist/components/capability-plugin.js +31 -0
- package/dist/components/flux-reconcile.js +61 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +18 -0
- package/dist/components/kubectl-apply.d.ts +83 -1
- package/dist/components/kubectl-apply.d.ts.map +1 -1
- package/dist/components/kubectl-apply.js +274 -0
- package/dist/components/kustomize-apply.js +25 -0
- package/dist/composites/adot-collector.js +184 -0
- package/dist/composites/agic-ingress.js +85 -0
- package/dist/composites/aks-external-dns-agent.js +146 -0
- package/dist/composites/alb-ingress.js +86 -0
- package/dist/composites/argo-app.js +199 -0
- package/dist/composites/autoscaled-service.js +174 -0
- package/dist/composites/azure-disk-storage-class.js +47 -0
- package/dist/composites/azure-file-storage-class.js +48 -0
- package/dist/composites/azure-monitor-collector.js +176 -0
- package/dist/composites/batch-job.js +139 -0
- package/dist/composites/catalog.js +4110 -0
- package/dist/composites/cockroachdb-cluster.js +371 -0
- package/dist/composites/cockroachdb-region-stack.js +369 -0
- package/dist/composites/config-connector-context.js +40 -0
- package/dist/composites/configured-app.js +135 -0
- package/dist/composites/cron-schedule.js +38 -0
- package/dist/composites/cron-workload.js +109 -0
- package/dist/composites/ebs-storage-class.js +54 -0
- package/dist/composites/efs-storage-class.js +46 -0
- package/dist/composites/external-dns-agent.js +122 -0
- package/dist/composites/filestore-storage-class.js +49 -0
- package/dist/composites/fluent-bit-agent.js +157 -0
- package/dist/composites/flux-app.js +156 -0
- package/dist/composites/gce-ingress.js +83 -0
- package/dist/composites/gce-pd-storage-class.js +49 -0
- package/dist/composites/gke-external-dns-agent.js +129 -0
- package/dist/composites/gke-fluent-bit-agent.js +165 -0
- package/dist/composites/gke-gateway.js +91 -0
- package/dist/composites/gke-otel-collector.js +94 -0
- package/dist/composites/index.js +51 -0
- package/dist/composites/inference-service.js +76 -0
- package/dist/composites/irsa-service-account.js +77 -0
- package/dist/composites/member-defaults.js +14 -0
- package/dist/composites/metrics-server.js +181 -0
- package/dist/composites/model.js +92 -0
- package/dist/composites/monitored-service.js +152 -0
- package/dist/composites/namespace-env.js +114 -0
- package/dist/composites/network-isolated-app.js +124 -0
- package/dist/composites/node-agent.js +149 -0
- package/dist/composites/operator-stack.js +268 -0
- package/dist/composites/otel-collector-agent.js +142 -0
- package/dist/composites/otel-collector-gateway.js +216 -0
- package/dist/composites/otel-collector-node.js +176 -0
- package/dist/composites/otel-collector-rbac.js +115 -0
- package/dist/composites/otel-collector-shape.js +128 -0
- package/dist/composites/otel-collector.js +115 -0
- package/dist/composites/otel-operator-collector.js +123 -0
- package/dist/composites/ray-cluster.js +378 -0
- package/dist/composites/ray-job.js +136 -0
- package/dist/composites/ray-service.js +178 -0
- package/dist/composites/secure-ingress.js +100 -0
- package/dist/composites/security-context.js +1 -0
- package/dist/composites/sidecar-app.js +105 -0
- package/dist/composites/stateful-app.js +111 -0
- package/dist/composites/vllm-serving-runtime.js +114 -0
- package/dist/composites/web-app.js +157 -0
- package/dist/composites/worker-pool.js +167 -0
- package/dist/composites/workload-identity-sa.js +81 -0
- package/dist/composites/workload-identity-service-account.js +77 -0
- package/dist/config-schema.js +72 -0
- package/dist/config.js +59 -0
- package/dist/coverage.js +27 -0
- package/dist/crd/crd-sources.js +615 -0
- package/dist/crd/loader.js +181 -0
- package/dist/crd/oci-chart.js +144 -0
- package/dist/crd/parser.js +382 -0
- package/dist/crd/project-codegen.js +273 -0
- package/dist/crd/types.js +7 -0
- package/dist/deep-observe-hooks.js +306 -0
- package/dist/deep-observe.js +234 -0
- package/dist/default-labels.js +87 -0
- package/dist/describe-resources.js +699 -0
- package/dist/describe-stack-status.js +99 -0
- package/dist/detect.js +11 -0
- package/dist/effect-receipt-row.js +205 -0
- package/dist/export-resources.js +39 -0
- package/dist/generated/index.js +1092 -0
- package/dist/generated/runtime.js +4 -0
- package/dist/group-namespace.js +96 -0
- package/dist/import/embedded.js +197 -0
- package/dist/import/generator.js +288 -0
- package/dist/import/live-export.js +85 -0
- package/dist/import/parser.js +204 -0
- package/dist/import/testdata/embedded/fixtures.js +60 -0
- package/dist/include/entity.js +78 -0
- package/dist/include/resolve.js +170 -0
- package/dist/index.js +59 -0
- package/dist/integrity.json +3 -3
- package/dist/kube/apply.js +90 -0
- package/dist/kube/connect.js +46 -0
- package/dist/kube/delete.js +138 -0
- package/dist/kube/describe.js +169 -0
- package/dist/kube/events.js +132 -0
- package/dist/kube/flags.js +91 -0
- package/dist/kube/get.js +159 -0
- package/dist/kube/group.js +123 -0
- package/dist/kube/logs.js +82 -0
- package/dist/kube/project.js +94 -0
- package/dist/kube/render.js +227 -0
- package/dist/kube/source.js +122 -0
- package/dist/kube/target.js +63 -0
- package/dist/kube/testing.js +28 -0
- package/dist/kube/top.js +99 -0
- package/dist/kube/verdict.js +72 -0
- package/dist/kube/wait.js +129 -0
- package/dist/kustomize/render.js +73 -0
- package/dist/kustomize/rendered-entity.js +67 -0
- package/dist/kustomize/root.js +68 -0
- package/dist/lint/audit-catalog.js +61 -0
- package/dist/lint/audit-lineage.js +118 -0
- package/dist/lint/post-synth/argo-helpers.js +36 -0
- package/dist/lint/post-synth/argo002.js +31 -0
- package/dist/lint/post-synth/argo003.js +53 -0
- package/dist/lint/post-synth/argo005.js +54 -0
- package/dist/lint/post-synth/crd-schema-helpers.d.ts.map +1 -1
- package/dist/lint/post-synth/crd-schema-helpers.js +214 -0
- package/dist/lint/post-synth/flux002.js +56 -0
- package/dist/lint/post-synth/flux003.js +50 -0
- package/dist/lint/post-synth/index.js +104 -0
- package/dist/lint/post-synth/k8s-helpers.js +186 -0
- package/dist/lint/post-synth/monitoring-selection-helpers.js +163 -0
- package/dist/lint/post-synth/otel-placement-helpers.js +293 -0
- package/dist/lint/post-synth/sops-helpers.js +43 -0
- package/dist/lint/post-synth/wk8005.js +44 -0
- package/dist/lint/post-synth/wk8006.js +56 -0
- package/dist/lint/post-synth/wk8041.js +60 -0
- package/dist/lint/post-synth/wk8042.js +36 -0
- package/dist/lint/post-synth/wk8101.js +52 -0
- package/dist/lint/post-synth/wk8102.js +30 -0
- package/dist/lint/post-synth/wk8103.js +33 -0
- package/dist/lint/post-synth/wk8104.js +58 -0
- package/dist/lint/post-synth/wk8105.js +33 -0
- package/dist/lint/post-synth/wk8201.js +44 -0
- package/dist/lint/post-synth/wk8202.js +34 -0
- package/dist/lint/post-synth/wk8203.js +34 -0
- package/dist/lint/post-synth/wk8204.js +71 -0
- package/dist/lint/post-synth/wk8205.js +38 -0
- package/dist/lint/post-synth/wk8207.js +33 -0
- package/dist/lint/post-synth/wk8208.js +33 -0
- package/dist/lint/post-synth/wk8209.js +33 -0
- package/dist/lint/post-synth/wk8301.js +49 -0
- package/dist/lint/post-synth/wk8302.js +34 -0
- package/dist/lint/post-synth/wk8303.js +68 -0
- package/dist/lint/post-synth/wk8304.js +58 -0
- package/dist/lint/post-synth/wk8305.js +96 -0
- package/dist/lint/post-synth/wk8306.js +38 -0
- package/dist/lint/post-synth/wk8401.js +86 -0
- package/dist/lint/post-synth/wk8402.js +31 -0
- package/dist/lint/post-synth/wk8403.js +49 -0
- package/dist/lint/post-synth/wk8404.js +36 -0
- package/dist/lint/post-synth/wk8405.js +65 -0
- package/dist/lint/post-synth/wk8406.js +50 -0
- package/dist/lint/post-synth/wk8407.js +58 -0
- package/dist/lint/post-synth/wk8501.js +36 -0
- package/dist/lint/post-synth/wk8502.js +35 -0
- package/dist/lint/post-synth/wk8503.js +164 -0
- package/dist/lint/post-synth/wk8504.js +20 -0
- package/dist/lint/post-synth/wk8505.js +31 -0
- package/dist/lint/post-synth/wk8601.js +40 -0
- package/dist/lint/post-synth/wk8602.js +120 -0
- package/dist/lint/post-synth/wk8603.js +63 -0
- package/dist/lint/post-synth/wk8604.js +31 -0
- package/dist/lint/post-synth/wk8605.js +124 -0
- package/dist/lint/post-synth/wk8606.js +22 -0
- package/dist/lint/post-synth/wk8701.js +31 -0
- package/dist/lint/post-synth/wk8702.js +37 -0
- package/dist/lint/post-synth/wk8703.js +31 -0
- package/dist/lint/post-synth/wk8704.js +135 -0
- package/dist/lint/post-synth/wk8705.js +38 -0
- package/dist/lint/rules/argo-appset-single-project.js +56 -0
- package/dist/lint/rules/argo-ast.js +94 -0
- package/dist/lint/rules/argo-automated-prune.js +59 -0
- package/dist/lint/rules/flux-source-ref-pin.js +44 -0
- package/dist/lint/rules/hardcoded-namespace.js +57 -0
- package/dist/lint/rules/latest-image-tag.js +103 -0
- package/dist/lint/rules/missing-resource-limits.js +85 -0
- package/dist/lsp/completions.d.ts.map +1 -1
- package/dist/lsp/completions.js +18 -0
- package/dist/lsp/hover.d.ts.map +1 -1
- package/dist/lsp/hover.js +57 -0
- package/dist/manifest-entity.js +71 -0
- package/dist/manifest.json +1 -1
- package/dist/micro-time.js +49 -0
- package/dist/op/activities/apply-diff.d.ts +31 -0
- package/dist/op/activities/apply-diff.d.ts.map +1 -0
- package/dist/op/activities/apply-diff.js +79 -0
- package/dist/op/activities/argo.js +98 -0
- package/dist/op/activities/ensure-secret.js +38 -0
- package/dist/op/activities/index.js +51 -0
- package/dist/op/activities/kubectl.d.ts +64 -0
- package/dist/op/activities/kubectl.d.ts.map +1 -1
- package/dist/op/activities/kubectl.js +517 -0
- package/dist/op/activities/wait-for-ready.js +229 -0
- package/dist/op/builders.js +68 -0
- package/dist/package-cli.js +21 -0
- package/dist/patch/json-patch.js +187 -0
- package/dist/patch/rendered-patch.js +94 -0
- package/dist/plugin.js +741 -0
- package/dist/project-kinds.js +56 -0
- package/dist/receipt-store.js +216 -0
- package/dist/rules/crd-schema-helpers.ts +2 -1
- package/dist/secret-labels.js +33 -0
- package/dist/secret-store.js +116 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/serializer.js +578 -0
- package/dist/sops/encrypted-secret-file.js +194 -0
- package/dist/sops/entity.js +32 -0
- package/dist/spec/fetch.js +58 -0
- package/dist/spec/parse.js +622 -0
- package/dist/subscribe-changes.js +168 -0
- package/dist/teardown.js +197 -0
- package/dist/telemetry-release.js +86 -0
- package/dist/validate-cli.js +17 -0
- package/dist/validate.js +47 -0
- package/dist/variables.js +34 -0
- package/dist/whoami.js +109 -0
- package/package.json +12 -12
- package/src/api/operation-surface.ts +2 -1
- package/src/codegen/package.ts +2 -2
- package/src/components/index.ts +3 -0
- package/src/components/kubectl-apply-plan.k3d.e2e.test.ts +127 -0
- package/src/components/kubectl-apply.test.ts +262 -0
- package/src/components/kubectl-apply.ts +341 -12
- package/src/deep-observe-hooks.ts +2 -2
- package/src/import/roundtrip-build.test.ts +46 -0
- package/src/lint/post-synth/crd-schema-helpers.ts +2 -1
- package/src/lsp/completions.ts +2 -1
- package/src/lsp/hover.ts +2 -1
- package/src/op/activities/apply-diff.ts +87 -0
- package/src/op/activities/kubectl-plan.test.ts +224 -0
- package/src/op/activities/kubectl.ts +204 -16
- package/src/serializer.ts +2 -1
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TypeScript declaration file generator — produces index.d.ts with all
|
|
3
|
+
* Kubernetes resource and property type classes.
|
|
4
|
+
*/
|
|
5
|
+
import { k8sShortName } from "../spec/parse.js";
|
|
6
|
+
import { propertyTypeName, extractDefName } from "./naming.js";
|
|
7
|
+
import { writeResourceClass, resolveConstructorType, } from "@intentius/chant/codegen/generate-typescript";
|
|
8
|
+
/**
|
|
9
|
+
* Generate the complete .d.ts file content.
|
|
10
|
+
*/
|
|
11
|
+
export function generateTypeScriptDeclarations(results, naming, definitionTypes = []) {
|
|
12
|
+
const lines = [];
|
|
13
|
+
lines.push("// Code generated by chant k8s generate. DO NOT EDIT.");
|
|
14
|
+
const resources = [];
|
|
15
|
+
for (const r of results) {
|
|
16
|
+
const typeName = r.resource.typeName;
|
|
17
|
+
const tsName = naming.resolve(typeName);
|
|
18
|
+
if (!tsName)
|
|
19
|
+
continue;
|
|
20
|
+
const shortName = k8sShortName(typeName);
|
|
21
|
+
const remap = new Map();
|
|
22
|
+
for (const pt of r.propertyTypes) {
|
|
23
|
+
const defName = extractDefName(pt.name, shortName);
|
|
24
|
+
remap.set(pt.name, propertyTypeName(tsName, defName));
|
|
25
|
+
}
|
|
26
|
+
for (const e of r.enums) {
|
|
27
|
+
const defName = extractDefName(e.name, shortName);
|
|
28
|
+
remap.set(e.name, propertyTypeName(tsName, defName));
|
|
29
|
+
}
|
|
30
|
+
const dtsProps = r.resource.properties.map((p) => ({
|
|
31
|
+
name: p.name,
|
|
32
|
+
type: p.tsType,
|
|
33
|
+
required: p.required,
|
|
34
|
+
description: p.description,
|
|
35
|
+
}));
|
|
36
|
+
const dtsAttrs = r.resource.attributes.map((a) => ({
|
|
37
|
+
name: a.name,
|
|
38
|
+
type: a.tsType,
|
|
39
|
+
}));
|
|
40
|
+
resources.push({ tsName, isProperty: !!r.isProperty, properties: dtsProps, attributes: dtsAttrs, remap });
|
|
41
|
+
for (const alias of naming.aliases(typeName)) {
|
|
42
|
+
resources.push({ tsName: alias, isProperty: !!r.isProperty, properties: dtsProps, attributes: dtsAttrs, remap });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// Sort alphabetically
|
|
46
|
+
resources.sort((a, b) => a.tsName.localeCompare(b.tsName));
|
|
47
|
+
// Resource classes
|
|
48
|
+
const resourceEntries = resources.filter((r) => !r.isProperty);
|
|
49
|
+
const propertyEntries = resources.filter((r) => r.isProperty);
|
|
50
|
+
if (resourceEntries.length > 0) {
|
|
51
|
+
lines.push("");
|
|
52
|
+
lines.push("// --- Kubernetes Resource classes ---");
|
|
53
|
+
for (const re of resourceEntries) {
|
|
54
|
+
writeResourceClass(lines, re.tsName, re.properties, re.attributes, re.remap);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (propertyEntries.length > 0) {
|
|
58
|
+
lines.push("");
|
|
59
|
+
lines.push("// --- Property type classes ---");
|
|
60
|
+
for (const pe of propertyEntries) {
|
|
61
|
+
writeMembersInterface(lines, pe.tsName, undefined, pe.properties, pe.remap);
|
|
62
|
+
lines.push(`export declare class ${pe.tsName} {`);
|
|
63
|
+
lines.push(` constructor(props: ${pe.tsName});`);
|
|
64
|
+
lines.push("}");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// chant #3093 — every other object definition a resource reaches. Declared
|
|
68
|
+
// as interfaces: nothing constructs them at runtime, an author writes them
|
|
69
|
+
// as object literals.
|
|
70
|
+
if (definitionTypes.length > 0) {
|
|
71
|
+
const classNames = new Set(resources.map((r) => r.tsName));
|
|
72
|
+
lines.push("");
|
|
73
|
+
lines.push("// --- Definition interfaces ---");
|
|
74
|
+
for (const dt of definitionTypes) {
|
|
75
|
+
if (classNames.has(dt.name)) {
|
|
76
|
+
throw new Error(`k8s codegen: definition ${dt.defKey} would be declared as ${dt.name}, which is already a class`);
|
|
77
|
+
}
|
|
78
|
+
const props = dt.properties.map((p) => ({
|
|
79
|
+
name: p.name,
|
|
80
|
+
type: p.tsType,
|
|
81
|
+
required: p.required,
|
|
82
|
+
description: p.description,
|
|
83
|
+
}));
|
|
84
|
+
writeMembersInterface(lines, dt.name, dt.description, props, undefined);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
lines.push("");
|
|
88
|
+
return lines.join("\n");
|
|
89
|
+
}
|
|
90
|
+
const IDENT = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
91
|
+
/**
|
|
92
|
+
* Write the members of a property type or definition as an interface. For a
|
|
93
|
+
* property type the interface merges with its class, so `new Container({...})`
|
|
94
|
+
* and a `{...}` literal both check against the same members, and so does a
|
|
95
|
+
* field typed `Container`. A class with only a constructor has no members, and
|
|
96
|
+
* an empty instance type accepts any object (chant #3093).
|
|
97
|
+
*/
|
|
98
|
+
function writeMembersInterface(lines, tsName, description, props, remap) {
|
|
99
|
+
lines.push("");
|
|
100
|
+
if (description)
|
|
101
|
+
lines.push(`/** ${jsdoc(description)} */`);
|
|
102
|
+
if (props.length === 0) {
|
|
103
|
+
lines.push(`export interface ${tsName} {}`);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// Required first, then optional, each alphabetical — the constructor order.
|
|
107
|
+
const sorted = [...props].sort((a, b) => {
|
|
108
|
+
if (a.required !== b.required)
|
|
109
|
+
return a.required ? -1 : 1;
|
|
110
|
+
return a.name.localeCompare(b.name);
|
|
111
|
+
});
|
|
112
|
+
lines.push(`export interface ${tsName} {`);
|
|
113
|
+
for (const p of sorted) {
|
|
114
|
+
if (p.description)
|
|
115
|
+
lines.push(` /** ${jsdoc(p.description)} */`);
|
|
116
|
+
const key = IDENT.test(p.name) ? p.name : JSON.stringify(p.name);
|
|
117
|
+
lines.push(` ${key}${p.required ? "" : "?"}: ${resolveConstructorType(p.type, remap)};`);
|
|
118
|
+
}
|
|
119
|
+
lines.push("}");
|
|
120
|
+
}
|
|
121
|
+
/** A description made safe for a one-line JSDoc comment. */
|
|
122
|
+
function jsdoc(text) {
|
|
123
|
+
return text.replace(/\*\//g, "*\\/");
|
|
124
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kubernetes generation pipeline — uses core generatePipeline
|
|
3
|
+
* with K8s-specific fetch, parse, naming, and generation callbacks.
|
|
4
|
+
*/
|
|
5
|
+
import { generatePipeline, writeGeneratedArtifacts, } from "@intentius/chant/codegen/generate";
|
|
6
|
+
import { fetchSchemas } from "../spec/fetch.js";
|
|
7
|
+
import { parseK8sSwaggerTypes, specListMapKeyPairs, k8sShortName, } from "../spec/parse.js";
|
|
8
|
+
import { loadMultipleCRDs } from "../crd/loader.js";
|
|
9
|
+
import { CRD_SOURCES } from "../crd/crd-sources.js";
|
|
10
|
+
import { NamingStrategy, propertyTypeName, extractDefName } from "./naming.js";
|
|
11
|
+
import { generateLexiconJSON } from "./generate-lexicon.js";
|
|
12
|
+
import { generateOperationsJSON } from "./generate-operations.js";
|
|
13
|
+
import { generateListMapKeysJSON } from "./generate-list-map-keys.js";
|
|
14
|
+
import { generateTypeScriptDeclarations } from "./generate-typescript.js";
|
|
15
|
+
import { generateRuntimeIndex as coreGenerateRuntimeIndex, } from "@intentius/chant/codegen/generate-runtime-index";
|
|
16
|
+
/** Where a CRD source comes from, as a log line or an error names it. */
|
|
17
|
+
function crdSourceLabel(source) {
|
|
18
|
+
return source.url ?? source.path ?? source.chart ?? "cluster";
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Load every CRD source. A source that fails to load fails generation and the
|
|
22
|
+
* error names it (#3310): skipping it shrinks the output silently, and the loss
|
|
23
|
+
* shows up only later as a surface-snapshot diff. Every source is tried first,
|
|
24
|
+
* so one run names all the failures. `allowFailures` turns them back into
|
|
25
|
+
* warnings for a deliberate partial run.
|
|
26
|
+
*/
|
|
27
|
+
export async function loadCrdSources(sources, log, opts = {}) {
|
|
28
|
+
const load = opts.load ?? loadMultipleCRDs;
|
|
29
|
+
const results = [];
|
|
30
|
+
const failures = [];
|
|
31
|
+
for (const source of sources) {
|
|
32
|
+
const label = crdSourceLabel(source);
|
|
33
|
+
try {
|
|
34
|
+
const parsed = await load([source]);
|
|
35
|
+
results.push(...parsed);
|
|
36
|
+
log(`Loaded ${parsed.length} CRD type(s) from ${label}`);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
40
|
+
failures.push({ file: label, error: msg });
|
|
41
|
+
log(`${opts.allowFailures ? "Warning: skipping" : "Error:"} CRD source ${label} failed to load: ${msg}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (failures.length > 0 && !opts.allowFailures) {
|
|
45
|
+
const lines = failures.map((f) => ` ${f.file}: ${f.error}`).join("\n");
|
|
46
|
+
throw new Error(`${failures.length} CRD source(s) failed to load, so generation would drop their kinds:\n${lines}\n` +
|
|
47
|
+
`Set CHANT_K8S_ALLOW_CRD_FAILURES=1 to generate without them deliberately.`);
|
|
48
|
+
}
|
|
49
|
+
log(`Total CRD types loaded: ${results.length}`);
|
|
50
|
+
return { results, warnings: failures };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Run the full Kubernetes generation pipeline.
|
|
54
|
+
*/
|
|
55
|
+
export async function generate(opts = {}) {
|
|
56
|
+
// Pipeline state captured in closure — no module-level mutation
|
|
57
|
+
let pendingResults = [];
|
|
58
|
+
// chant #1441 — read off the raw document in `parseSchema`, since the
|
|
59
|
+
// result set covers only the definitions chant emits types for.
|
|
60
|
+
let specPairs = [];
|
|
61
|
+
// chant #3093 — the declaration-only interfaces, which only the `.d.ts` emits.
|
|
62
|
+
let definitionTypes = [];
|
|
63
|
+
const config = {
|
|
64
|
+
fetchSchemas: async (fetchOpts) => {
|
|
65
|
+
return fetchSchemas(fetchOpts.force, opts.schemaVersion);
|
|
66
|
+
},
|
|
67
|
+
parseSchema: (_typeName, data) => {
|
|
68
|
+
// The K8s schema is a single document — parseK8sSwaggerTypes returns multiple results.
|
|
69
|
+
// The pipeline calls this once per schema entry. We return the first result
|
|
70
|
+
// and use augmentResults to inject the rest.
|
|
71
|
+
const { results, definitionTypes: defs } = parseK8sSwaggerTypes(data);
|
|
72
|
+
definitionTypes = defs;
|
|
73
|
+
specPairs = specListMapKeyPairs(data);
|
|
74
|
+
if (results.length === 0)
|
|
75
|
+
return null;
|
|
76
|
+
// Return the first result; stash the rest for augmentResults
|
|
77
|
+
pendingResults = results.slice(1);
|
|
78
|
+
return results[0];
|
|
79
|
+
},
|
|
80
|
+
createNaming: (results) => new NamingStrategy(results),
|
|
81
|
+
augmentSchemas: async (schemas, _opts, log) => {
|
|
82
|
+
// Load third-party CRDs and return as extraResults so they are
|
|
83
|
+
// included in the generated types alongside the core K8s resources.
|
|
84
|
+
const allowFailures = opts.allowCrdFailures ?? process.env.CHANT_K8S_ALLOW_CRD_FAILURES === "1";
|
|
85
|
+
const { results: crdResults, warnings } = await loadCrdSources(CRD_SOURCES, log, { allowFailures });
|
|
86
|
+
return { schemas, extraResults: crdResults, warnings };
|
|
87
|
+
},
|
|
88
|
+
augmentResults: (results, _opts, log) => {
|
|
89
|
+
// Add the remaining results from the single-schema parse
|
|
90
|
+
if (pendingResults.length > 0) {
|
|
91
|
+
results.push(...pendingResults);
|
|
92
|
+
log(`Added ${pendingResults.length} additional K8s resources from OpenAPI spec`);
|
|
93
|
+
pendingResults = [];
|
|
94
|
+
}
|
|
95
|
+
log(`Total: ${results.length} K8s resource/property schemas`);
|
|
96
|
+
return { results };
|
|
97
|
+
},
|
|
98
|
+
generateRegistry: (results, naming) => {
|
|
99
|
+
return generateLexiconJSON(results, naming);
|
|
100
|
+
},
|
|
101
|
+
generateTypes: (results, naming) => {
|
|
102
|
+
return generateTypeScriptDeclarations(results, naming, definitionTypes);
|
|
103
|
+
},
|
|
104
|
+
generateRuntimeIndex: (results, naming) => {
|
|
105
|
+
return generateRuntimeIndex(results, naming);
|
|
106
|
+
},
|
|
107
|
+
// chant #1074 — the operation surface, out of the same results the types
|
|
108
|
+
// and the registry come out of, so the live client cannot address a kind
|
|
109
|
+
// differently from how the declarable surface names it.
|
|
110
|
+
generateExtraArtifacts: (results) => ({
|
|
111
|
+
"operations.json": generateOperationsJSON(results),
|
|
112
|
+
// chant #1441 — the spec's own associative-list keys, so drift compares
|
|
113
|
+
// list elements by identity instead of by index.
|
|
114
|
+
"list-map-keys.json": generateListMapKeysJSON(specPairs, results),
|
|
115
|
+
}),
|
|
116
|
+
};
|
|
117
|
+
return generatePipeline(config, opts);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Write generated artifacts to disk.
|
|
121
|
+
*/
|
|
122
|
+
export function writeGeneratedFiles(result, baseDir) {
|
|
123
|
+
writeGeneratedArtifacts({
|
|
124
|
+
baseDir,
|
|
125
|
+
files: {
|
|
126
|
+
"lexicon-k8s.json": result.lexiconJSON,
|
|
127
|
+
"index.d.ts": result.typesDTS,
|
|
128
|
+
"index.ts": result.indexTS,
|
|
129
|
+
"runtime.ts": `/**\n * Runtime factory constructors — re-exported from core.\n */\nexport { createResource, createProperty } from "@intentius/chant/runtime";\n`,
|
|
130
|
+
...(result.extraArtifacts ?? {}),
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Generate the runtime index.ts with factory constructor exports.
|
|
136
|
+
*/
|
|
137
|
+
function generateRuntimeIndex(results, naming) {
|
|
138
|
+
const resourceEntries = [];
|
|
139
|
+
const propertyEntries = [];
|
|
140
|
+
for (const r of results) {
|
|
141
|
+
const typeName = r.resource.typeName;
|
|
142
|
+
const tsName = naming.resolve(typeName);
|
|
143
|
+
if (!tsName)
|
|
144
|
+
continue;
|
|
145
|
+
const attrs = {};
|
|
146
|
+
for (const attr of r.resource.attributes) {
|
|
147
|
+
attrs[attr.name] = attr.name;
|
|
148
|
+
}
|
|
149
|
+
if (r.isProperty) {
|
|
150
|
+
propertyEntries.push({ tsName, resourceType: typeName });
|
|
151
|
+
for (const alias of naming.aliases(typeName)) {
|
|
152
|
+
propertyEntries.push({ tsName: alias, resourceType: typeName });
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
resourceEntries.push({ tsName, resourceType: typeName, attrs });
|
|
157
|
+
for (const alias of naming.aliases(typeName)) {
|
|
158
|
+
resourceEntries.push({ tsName: alias, resourceType: typeName, attrs });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Nested property types
|
|
162
|
+
const shortName = k8sShortName(typeName);
|
|
163
|
+
for (const pt of r.propertyTypes) {
|
|
164
|
+
const defName = extractDefName(pt.name, shortName);
|
|
165
|
+
const ptName = propertyTypeName(tsName, defName);
|
|
166
|
+
const ptType = `${typeName}.${pt.defType}`;
|
|
167
|
+
propertyEntries.push({ tsName: ptName, resourceType: ptType });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return coreGenerateRuntimeIndex(resourceEntries, propertyEntries, {
|
|
171
|
+
lexiconName: "k8s",
|
|
172
|
+
});
|
|
173
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kubernetes naming strategy — maps K8s::{Group}::{Kind} type names
|
|
3
|
+
* to user-friendly TypeScript class names.
|
|
4
|
+
*/
|
|
5
|
+
import { NamingStrategy as CoreNamingStrategy, } from "@intentius/chant/codegen/naming";
|
|
6
|
+
import { k8sShortName, k8sServiceName } from "../spec/parse.js";
|
|
7
|
+
export { propertyTypeName, extractDefName } from "@intentius/chant/codegen/naming";
|
|
8
|
+
const k8sNamingConfig = {
|
|
9
|
+
priorityNames: {
|
|
10
|
+
// Core
|
|
11
|
+
"K8s::Core::Pod": "Pod",
|
|
12
|
+
"K8s::Core::Service": "Service",
|
|
13
|
+
"K8s::Core::ConfigMap": "ConfigMap",
|
|
14
|
+
"K8s::Core::Secret": "Secret",
|
|
15
|
+
"K8s::Core::Namespace": "Namespace",
|
|
16
|
+
"K8s::Core::ServiceAccount": "ServiceAccount",
|
|
17
|
+
"K8s::Core::PersistentVolume": "PersistentVolume",
|
|
18
|
+
"K8s::Core::PersistentVolumeClaim": "PersistentVolumeClaim",
|
|
19
|
+
"K8s::Core::Node": "Node",
|
|
20
|
+
"K8s::Core::Endpoints": "Endpoints",
|
|
21
|
+
"K8s::Core::ResourceQuota": "ResourceQuota",
|
|
22
|
+
"K8s::Core::LimitRange": "LimitRange",
|
|
23
|
+
"K8s::Core::ReplicationController": "ReplicationController",
|
|
24
|
+
// Apps
|
|
25
|
+
"K8s::Apps::Deployment": "Deployment",
|
|
26
|
+
"K8s::Apps::StatefulSet": "StatefulSet",
|
|
27
|
+
"K8s::Apps::DaemonSet": "DaemonSet",
|
|
28
|
+
"K8s::Apps::ReplicaSet": "ReplicaSet",
|
|
29
|
+
"K8s::Apps::ControllerRevision": "ControllerRevision",
|
|
30
|
+
// Batch
|
|
31
|
+
"K8s::Batch::Job": "Job",
|
|
32
|
+
"K8s::Batch::CronJob": "CronJob",
|
|
33
|
+
// Networking
|
|
34
|
+
"K8s::Networking::Ingress": "Ingress",
|
|
35
|
+
"K8s::Networking::IngressClass": "IngressClass",
|
|
36
|
+
"K8s::Networking::NetworkPolicy": "NetworkPolicy",
|
|
37
|
+
// RBAC
|
|
38
|
+
"K8s::Rbac::Role": "Role",
|
|
39
|
+
"K8s::Rbac::ClusterRole": "ClusterRole",
|
|
40
|
+
"K8s::Rbac::RoleBinding": "RoleBinding",
|
|
41
|
+
"K8s::Rbac::ClusterRoleBinding": "ClusterRoleBinding",
|
|
42
|
+
// Autoscaling
|
|
43
|
+
"K8s::Autoscaling::HorizontalPodAutoscaler": "HorizontalPodAutoscaler",
|
|
44
|
+
// Policy
|
|
45
|
+
"K8s::Policy::PodDisruptionBudget": "PodDisruptionBudget",
|
|
46
|
+
// Storage
|
|
47
|
+
"K8s::Storage::StorageClass": "StorageClass",
|
|
48
|
+
"K8s::Storage::CSIDriver": "CSIDriver",
|
|
49
|
+
// Scheduling
|
|
50
|
+
"K8s::Scheduling::PriorityClass": "PriorityClass",
|
|
51
|
+
// Coordination
|
|
52
|
+
"K8s::Coordination::Lease": "Lease",
|
|
53
|
+
// Discovery
|
|
54
|
+
"K8s::Discovery::EndpointSlice": "EndpointSlice",
|
|
55
|
+
// Certificates
|
|
56
|
+
"K8s::Certificates::CertificateSigningRequest": "CertificateSigningRequest",
|
|
57
|
+
// Admission
|
|
58
|
+
"K8s::Admissionregistration::ValidatingWebhookConfiguration": "ValidatingWebhookConfiguration",
|
|
59
|
+
"K8s::Admissionregistration::MutatingWebhookConfiguration": "MutatingWebhookConfiguration",
|
|
60
|
+
// Events (core vs events.k8s.io — the core version wins)
|
|
61
|
+
"K8s::Core::Event": "Event",
|
|
62
|
+
// Prometheus Operator's Probe CRD would collide with the core Probe property type
|
|
63
|
+
"K8s::Monitoring::Probe": "MonitoringProbe",
|
|
64
|
+
// Property types
|
|
65
|
+
"K8s::Core::Container": "Container",
|
|
66
|
+
"K8s::Core::ContainerPort": "ContainerPort",
|
|
67
|
+
"K8s::Core::EnvVar": "EnvVar",
|
|
68
|
+
"K8s::Core::EnvFromSource": "EnvFromSource",
|
|
69
|
+
"K8s::Core::Volume": "Volume",
|
|
70
|
+
"K8s::Core::VolumeMount": "VolumeMount",
|
|
71
|
+
"K8s::Core::PodSpec": "PodSpec",
|
|
72
|
+
"K8s::Core::PodTemplateSpec": "PodTemplateSpec",
|
|
73
|
+
"K8s::Core::ServicePort": "ServicePort",
|
|
74
|
+
"K8s::Core::Probe": "Probe",
|
|
75
|
+
"K8s::Core::ResourceRequirements": "ResourceRequirements",
|
|
76
|
+
"K8s::Core::SecurityContext": "SecurityContext",
|
|
77
|
+
"K8s::Core::PodSecurityContext": "PodSecurityContext",
|
|
78
|
+
"K8s::Core::Capabilities": "Capabilities",
|
|
79
|
+
"K8s::Core::ConfigMapKeySelector": "ConfigMapKeySelector",
|
|
80
|
+
"K8s::Core::SecretKeySelector": "SecretKeySelector",
|
|
81
|
+
"K8s::Core::EnvVarSource": "EnvVarSource",
|
|
82
|
+
"K8s::Core::ObjectReference": "ObjectReference",
|
|
83
|
+
"K8s::Core::LocalObjectReference": "LocalObjectReference",
|
|
84
|
+
"K8s::Core::Toleration": "Toleration",
|
|
85
|
+
"K8s::Core::Affinity": "Affinity",
|
|
86
|
+
"K8s::Core::TopologySpreadConstraint": "TopologySpreadConstraint",
|
|
87
|
+
"K8s::Core::PersistentVolumeClaimSpec": "PersistentVolumeClaimSpec",
|
|
88
|
+
"K8s::Core::HTTPGetAction": "HTTPGetAction",
|
|
89
|
+
"K8s::Core::TCPSocketAction": "TCPSocketAction",
|
|
90
|
+
"K8s::Core::ExecAction": "ExecAction",
|
|
91
|
+
"K8s::Core::HostAlias": "HostAlias",
|
|
92
|
+
"K8s::Core::EphemeralContainer": "EphemeralContainer",
|
|
93
|
+
"K8s::Core::KeyToPath": "KeyToPath",
|
|
94
|
+
"K8s::Apps::DeploymentStrategy": "DeploymentStrategy",
|
|
95
|
+
"K8s::Apps::RollingUpdateDeployment": "RollingUpdateDeployment",
|
|
96
|
+
"K8s::Networking::IngressRule": "IngressRule",
|
|
97
|
+
"K8s::Networking::IngressTLS": "IngressTLS",
|
|
98
|
+
"K8s::Networking::HTTPIngressPath": "HTTPIngressPath",
|
|
99
|
+
"K8s::Networking::IngressBackend": "IngressBackend",
|
|
100
|
+
"K8s::Networking::IngressServiceBackend": "IngressServiceBackend",
|
|
101
|
+
"K8s::Networking::ServiceBackendPort": "ServiceBackendPort",
|
|
102
|
+
"K8s::Networking::NetworkPolicyIngressRule": "NetworkPolicyIngressRule",
|
|
103
|
+
"K8s::Networking::NetworkPolicyEgressRule": "NetworkPolicyEgressRule",
|
|
104
|
+
"K8s::Networking::NetworkPolicyPeer": "NetworkPolicyPeer",
|
|
105
|
+
"K8s::Networking::NetworkPolicyPort": "NetworkPolicyPort",
|
|
106
|
+
"K8s::Rbac::PolicyRule": "PolicyRule",
|
|
107
|
+
"K8s::Rbac::RoleRef": "RoleRef",
|
|
108
|
+
"K8s::Rbac::Subject": "Subject",
|
|
109
|
+
"K8s::Autoscaling::MetricSpec": "MetricSpec",
|
|
110
|
+
"K8s::Autoscaling::HorizontalPodAutoscalerBehavior": "HorizontalPodAutoscalerBehavior",
|
|
111
|
+
"K8s::Policy::PodDisruptionBudgetSpec": "PodDisruptionBudgetSpec",
|
|
112
|
+
"K8s::Meta::ObjectMeta": "ObjectMeta",
|
|
113
|
+
"K8s::Meta::LabelSelector": "LabelSelector",
|
|
114
|
+
"K8s::Meta::LabelSelectorRequirement": "LabelSelectorRequirement",
|
|
115
|
+
},
|
|
116
|
+
priorityAliases: {
|
|
117
|
+
"K8s::Batch::Job": ["BatchJob"],
|
|
118
|
+
"K8s::Apps::Deployment": ["Deploy"],
|
|
119
|
+
"K8s::Core::ConfigMap": ["CM"],
|
|
120
|
+
"K8s::Core::ServiceAccount": ["SA"],
|
|
121
|
+
"K8s::Autoscaling::HorizontalPodAutoscaler": ["HPA"],
|
|
122
|
+
"K8s::Core::PersistentVolumeClaim": ["PVC"],
|
|
123
|
+
"K8s::Core::PersistentVolume": ["PV"],
|
|
124
|
+
"K8s::Policy::PodDisruptionBudget": ["PDB"],
|
|
125
|
+
"K8s::Core::Namespace": ["NS"],
|
|
126
|
+
"K8s::Apps::StatefulSet": ["STS"],
|
|
127
|
+
"K8s::Apps::DaemonSet": ["DS"],
|
|
128
|
+
"K8s::Core::Secret": ["Sec"],
|
|
129
|
+
"K8s::Networking::Ingress": ["Ing"],
|
|
130
|
+
"K8s::Networking::NetworkPolicy": ["NetPol"],
|
|
131
|
+
},
|
|
132
|
+
// Names published before the Prometheus Operator CRDs (v0.94.1) added colliding
|
|
133
|
+
// property types stay with their original owners; the new CRDs' types are prefixed.
|
|
134
|
+
priorityPropertyAliases: {
|
|
135
|
+
"K8s::Monitoring::ServiceMonitor": {
|
|
136
|
+
AttachMetadata: "AttachMetadata",
|
|
137
|
+
NamespaceSelector: "NamespaceSelector",
|
|
138
|
+
Selector: "Selector",
|
|
139
|
+
},
|
|
140
|
+
"K8s::Traefik::Middleware": { BasicAuth: "BasicAuth" },
|
|
141
|
+
"K8s::Addons::HelmChartProxy": { TlsConfig: "TlsConfig" },
|
|
142
|
+
"K8s::S3::Bucket": { Lifecycle: "Lifecycle" },
|
|
143
|
+
},
|
|
144
|
+
serviceAbbreviations: {
|
|
145
|
+
Core: "Core",
|
|
146
|
+
Apps: "Apps",
|
|
147
|
+
Batch: "Batch",
|
|
148
|
+
Networking: "Net",
|
|
149
|
+
Rbac: "Rbac",
|
|
150
|
+
Autoscaling: "AS",
|
|
151
|
+
Policy: "Pol",
|
|
152
|
+
Storage: "Stor",
|
|
153
|
+
Scheduling: "Sched",
|
|
154
|
+
Coordination: "Coord",
|
|
155
|
+
Discovery: "Disc",
|
|
156
|
+
Certificates: "Cert",
|
|
157
|
+
Admissionregistration: "Adm",
|
|
158
|
+
},
|
|
159
|
+
shortName: k8sShortName,
|
|
160
|
+
serviceName: k8sServiceName,
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Kubernetes-specific naming strategy.
|
|
164
|
+
* Extends core NamingStrategy with K8s naming config.
|
|
165
|
+
*/
|
|
166
|
+
export class NamingStrategy extends CoreNamingStrategy {
|
|
167
|
+
constructor(results) {
|
|
168
|
+
const inputs = results.map((r) => ({
|
|
169
|
+
typeName: r.resource.typeName,
|
|
170
|
+
propertyTypes: r.propertyTypes,
|
|
171
|
+
}));
|
|
172
|
+
super(inputs, k8sNamingConfig);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Kubernetes lexicon packaging — delegates to core packagePipeline
|
|
3
|
+
* with K8s-specific manifest building and skill collection.
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync } from "fs";
|
|
6
|
+
import { k8sPlugin } from "../plugin.js";
|
|
7
|
+
import { join, dirname } from "path";
|
|
8
|
+
import { moduleSourceDir } from "@intentius/chant/module-source";
|
|
9
|
+
import { packagePipeline, collectSkills, } from "@intentius/chant/codegen/package";
|
|
10
|
+
import { generate } from "./generate.js";
|
|
11
|
+
const pkgDir = dirname(moduleSourceDir(import.meta.url));
|
|
12
|
+
/**
|
|
13
|
+
* Package the Kubernetes lexicon into a distributable BundleSpec.
|
|
14
|
+
*/
|
|
15
|
+
export async function packageLexicon(opts = {}) {
|
|
16
|
+
const pkgJson = JSON.parse(readFileSync(join(pkgDir, "..", "package.json"), "utf-8"));
|
|
17
|
+
return packagePipeline({
|
|
18
|
+
generate: (genOpts) => generate({ verbose: genOpts.verbose, force: genOpts.force }),
|
|
19
|
+
buildManifest: (_genResult) => {
|
|
20
|
+
return {
|
|
21
|
+
name: "k8s",
|
|
22
|
+
version: pkgJson.version ?? "0.0.0",
|
|
23
|
+
chantVersion: ">=0.1.0",
|
|
24
|
+
namespace: "K8s",
|
|
25
|
+
intrinsics: [],
|
|
26
|
+
pseudoParameters: {},
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
srcDir: pkgDir,
|
|
30
|
+
collectSkills: () => {
|
|
31
|
+
const skillDefs = k8sPlugin.skills?.() ?? [];
|
|
32
|
+
return collectSkills(skillDefs);
|
|
33
|
+
},
|
|
34
|
+
version: pkgJson.version ?? "0.0.0",
|
|
35
|
+
}, opts);
|
|
36
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema augmentation patches for the Kubernetes OpenAPI spec.
|
|
3
|
+
*
|
|
4
|
+
* The official K8s OpenAPI spec has known issues: recursive definitions
|
|
5
|
+
* in JSONSchemaProps, ambiguous IntOrString typing, and Quantity being
|
|
6
|
+
* opaque. Patches are applied after fetch but before parse.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Registry of known schema patches.
|
|
10
|
+
*/
|
|
11
|
+
export const schemaPatches = [
|
|
12
|
+
{
|
|
13
|
+
description: "Break infinite recursion in JSONSchemaProps by capping nested $ref depth",
|
|
14
|
+
path: "definitions.io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps",
|
|
15
|
+
apply(def) {
|
|
16
|
+
var _a;
|
|
17
|
+
// JSONSchemaProps references itself in properties, items, additionalProperties, etc.
|
|
18
|
+
// We mark it as a plain object to prevent infinite recursion in the codegen walker.
|
|
19
|
+
const props = def.properties;
|
|
20
|
+
if (!props)
|
|
21
|
+
return;
|
|
22
|
+
// Replace self-referencing fields with opaque Record<string, any>
|
|
23
|
+
for (const key of [
|
|
24
|
+
"properties",
|
|
25
|
+
"additionalProperties",
|
|
26
|
+
"not",
|
|
27
|
+
"allOf",
|
|
28
|
+
"oneOf",
|
|
29
|
+
"anyOf",
|
|
30
|
+
]) {
|
|
31
|
+
if (props[key]) {
|
|
32
|
+
(_a = props[key]).description ?? (_a.description = "JSON Schema definition (recursive, treated as opaque)");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
description: "Patch IntOrString to be explicitly typed as string | number",
|
|
39
|
+
path: "definitions.io.k8s.apimachinery.pkg.util.intstr.IntOrString",
|
|
40
|
+
apply(def) {
|
|
41
|
+
// The spec marks this as just "string" with a format, but it's actually
|
|
42
|
+
// a union type used for ports, resource quantities, etc.
|
|
43
|
+
if (!def["x-kubernetes-int-or-string"]) {
|
|
44
|
+
def["x-kubernetes-int-or-string"] = true;
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
description: "Patch Quantity to be typed as string",
|
|
50
|
+
path: "definitions.io.k8s.apimachinery.pkg.api.resource.Quantity",
|
|
51
|
+
apply(def) {
|
|
52
|
+
// Quantity is serialized as a string (e.g., "500m", "1Gi") but the
|
|
53
|
+
// spec sometimes marks it as having no type. Force string.
|
|
54
|
+
if (!def.type) {
|
|
55
|
+
def.type = "string";
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
];
|
|
60
|
+
/**
|
|
61
|
+
* Apply all registered patches to a parsed schema.
|
|
62
|
+
* Modifies the schema in place.
|
|
63
|
+
*/
|
|
64
|
+
export function applyPatches(schema) {
|
|
65
|
+
const applied = [];
|
|
66
|
+
const skipped = [];
|
|
67
|
+
for (const patch of schemaPatches) {
|
|
68
|
+
const segments = patch.path.split(".");
|
|
69
|
+
let target = schema;
|
|
70
|
+
for (const segment of segments) {
|
|
71
|
+
if (target && typeof target === "object" && segment in target) {
|
|
72
|
+
target = target[segment];
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
target = undefined;
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (target) {
|
|
80
|
+
patch.apply(target);
|
|
81
|
+
applied.push(patch.description);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
skipped.push(`${patch.description} (path "${patch.path}" not found)`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return { applied, skipped };
|
|
88
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pinned dependency versions for the Kubernetes lexicon.
|
|
3
|
+
*
|
|
4
|
+
* Centralises the schema version used by fetch.ts and provides
|
|
5
|
+
* a helper to check for newer Kubernetes releases.
|
|
6
|
+
*/
|
|
7
|
+
import { fetchWithRetry } from "@intentius/chant/codegen/fetch";
|
|
8
|
+
import { K8S_SCHEMA_VERSION } from "../spec/fetch.js";
|
|
9
|
+
/**
|
|
10
|
+
* Pinned versions of external dependencies. The Kubernetes entry mirrors
|
|
11
|
+
* K8S_SCHEMA_VERSION in spec/fetch.ts, which is the version codegen downloads.
|
|
12
|
+
*/
|
|
13
|
+
export const PINNED_VERSIONS = {
|
|
14
|
+
k8sOpenAPI: K8S_SCHEMA_VERSION,
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Build the raw GitHub URL for the K8s swagger.json for a given version.
|
|
18
|
+
*/
|
|
19
|
+
export function k8sSwaggerUrl(version) {
|
|
20
|
+
const v = version ?? PINNED_VERSIONS.k8sOpenAPI;
|
|
21
|
+
return `https://raw.githubusercontent.com/kubernetes/kubernetes/${v}/api/openapi-spec/swagger.json`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Check for a newer stable Kubernetes release on GitHub.
|
|
25
|
+
* Returns the latest tag if newer than pinned, or null if up-to-date.
|
|
26
|
+
*/
|
|
27
|
+
export async function checkForUpdates() {
|
|
28
|
+
try {
|
|
29
|
+
const res = await fetchWithRetry("https://api.github.com/repos/kubernetes/kubernetes/releases/latest", undefined, undefined, { headers: { Accept: "application/vnd.github+json" } });
|
|
30
|
+
const data = (await res.json());
|
|
31
|
+
const latest = data.tag_name;
|
|
32
|
+
if (!latest)
|
|
33
|
+
return null;
|
|
34
|
+
return latest !== PINNED_VERSIONS.k8sOpenAPI ? latest : null;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Transient failures are retried inside fetchWithRetry; permanent
|
|
38
|
+
// failures (or exhausted retries) land here — treat as up-to-date.
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|