@intentius/chant-lexicon-k8s 0.109.0 → 0.110.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/import/parser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAc,YAAY,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/import/parser.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAc,YAAY,EAAE,MAAM,gCAAgC,CAAC;AA2I3G;;;;;GAKG;AACH,qBAAa,SAAU,YAAW,cAAc;IAC9C;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,GAAG,UAAU,CAkCzD;IAED,OAAO,CAAC,aAAa;CAiCtB"}
|
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "646a27dcdca60bc489585d973cea113d61fa84619559f52eb93c8ea280851913",
|
|
5
5
|
"meta.json": "c1831ac15083f5e0e45b29698d7b77f1c01646240fe6de5d6320753188594f69",
|
|
6
6
|
"types/index.d.ts": "5c5340046d090ae9db5553039d923cf92a8b2eb57aa4dc941273ed5bcfb5bc9d",
|
|
7
7
|
"rules/argo-appset-single-project.ts": "afa9f310753aa2d475f35012b13135b2dfaebed2a35d44edbe185ebc07673674",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"skills/chant-k8s-argo.md": "24c9a85b78a2fc5c6657424baac9cc6d6caff6f47605b8146b2c0082133181cf",
|
|
79
79
|
"skills/chant-k8s-flux.md": "9670efc2e9854bd14686b5adeb707396b9030a4dcaee6529b30abf56efe2c50c"
|
|
80
80
|
},
|
|
81
|
-
"composite": "
|
|
81
|
+
"composite": "bf22f83f07f28ae92b4bcf607a90c4988292f0f01b206817041a104e196bb927"
|
|
82
82
|
}
|
package/dist/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-k8s",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.110.0",
|
|
4
4
|
"description": "Kubernetes lexicon for chant — declarative IaC in TypeScript",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://intentius.io/chant",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"@types/js-yaml": "^4.0.9"
|
|
79
79
|
},
|
|
80
80
|
"optionalDependencies": {
|
|
81
|
-
"@intentius/chant-k8s-client": "^0.
|
|
81
|
+
"@intentius/chant-k8s-client": "^0.110.0"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@intentius/chant": "*",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
},
|
|
87
87
|
"peerDependencies": {
|
|
88
88
|
"zod": "^4.3.6",
|
|
89
|
-
"@intentius/chant": "^0.
|
|
89
|
+
"@intentius/chant": "^0.110.0",
|
|
90
90
|
"typescript": "^5.9.3"
|
|
91
91
|
}
|
|
92
92
|
}
|
package/src/import/parser.ts
CHANGED
|
@@ -77,6 +77,22 @@ const GVK_TYPE_MAP: Record<string, string> = {
|
|
|
77
77
|
* Resolve apiVersion + kind to a K8s type name.
|
|
78
78
|
* Falls back to constructing from the apiVersion group.
|
|
79
79
|
*/
|
|
80
|
+
/**
|
|
81
|
+
* `<apiVersion>/<kind>` keys that map to a type another key maps to first.
|
|
82
|
+
* The build writes the first key's apiVersion for that type, so a document
|
|
83
|
+
* written against a later key (`autoscaling/v1` HorizontalPodAutoscaler)
|
|
84
|
+
* keeps its own apiVersion as a property.
|
|
85
|
+
*/
|
|
86
|
+
const ALIASED_GVKS: ReadonlySet<string> = (() => {
|
|
87
|
+
const firstForType = new Set<string>();
|
|
88
|
+
const aliased = new Set<string>();
|
|
89
|
+
for (const [key, type] of Object.entries(GVK_TYPE_MAP)) {
|
|
90
|
+
if (firstForType.has(type)) aliased.add(key);
|
|
91
|
+
else firstForType.add(type);
|
|
92
|
+
}
|
|
93
|
+
return aliased;
|
|
94
|
+
})();
|
|
95
|
+
|
|
80
96
|
function resolveTypeName(apiVersion: string, kind: string): string {
|
|
81
97
|
// Try exact match
|
|
82
98
|
const key = `${apiVersion}/${kind}`;
|
|
@@ -192,7 +208,8 @@ export class K8sParser implements TemplateParser {
|
|
|
192
208
|
// Extract the user-configurable properties (skip apiVersion, kind)
|
|
193
209
|
const properties: Record<string, unknown> = {};
|
|
194
210
|
for (const [key, value] of Object.entries(doc)) {
|
|
195
|
-
if (key === "
|
|
211
|
+
if (key === "kind") continue;
|
|
212
|
+
if (key === "apiVersion" && !ALIASED_GVKS.has(`${apiVersion}/${kind}`)) continue;
|
|
196
213
|
properties[key] = value;
|
|
197
214
|
}
|
|
198
215
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import a manifest, build the generated source, and compare the documents.
|
|
3
|
+
* Each case is a manifest from the Kubernetes documentation examples that did
|
|
4
|
+
* not come back.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, expect, test } from "vitest";
|
|
7
|
+
import { loadAll } from "js-yaml";
|
|
8
|
+
import { build } from "@intentius/chant/build";
|
|
9
|
+
import type { SerializerResult } from "@intentius/chant/serializer";
|
|
10
|
+
import { k8sSerializer } from "../serializer";
|
|
11
|
+
import { importManifest, removeDir } from "./testdata/embedded/fixtures";
|
|
12
|
+
|
|
13
|
+
function primary(out: string | SerializerResult | undefined): string {
|
|
14
|
+
if (out === undefined) return "";
|
|
15
|
+
return typeof out === "string" ? out : out.primary;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function roundTrip(yaml: string): Promise<unknown[]> {
|
|
19
|
+
const imported = await importManifest(yaml);
|
|
20
|
+
try {
|
|
21
|
+
expect(imported.result.error).toBeUndefined();
|
|
22
|
+
const result = await build(imported.srcDir, [k8sSerializer]);
|
|
23
|
+
expect(result.errors).toEqual([]);
|
|
24
|
+
return (loadAll(primary(result.outputs.get("k8s"))) as unknown[]).filter((d) => d);
|
|
25
|
+
} finally {
|
|
26
|
+
removeDir(imported.dir);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe("k8s import round trip", () => {
|
|
31
|
+
test("a NetworkPolicy's egress: [{}] comes back as one empty rule", async () => {
|
|
32
|
+
const yaml = [
|
|
33
|
+
"apiVersion: networking.k8s.io/v1",
|
|
34
|
+
"kind: NetworkPolicy",
|
|
35
|
+
"metadata:",
|
|
36
|
+
" name: allow-all-egress",
|
|
37
|
+
"spec:",
|
|
38
|
+
" podSelector: {}",
|
|
39
|
+
" egress:",
|
|
40
|
+
" - {}",
|
|
41
|
+
" policyTypes:",
|
|
42
|
+
" - Egress",
|
|
43
|
+
].join("\n");
|
|
44
|
+
expect(await roundTrip(yaml)).toEqual(loadAll(yaml));
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("an autoscaling/v1 HorizontalPodAutoscaler keeps its apiVersion", async () => {
|
|
48
|
+
const yaml = [
|
|
49
|
+
"apiVersion: autoscaling/v1",
|
|
50
|
+
"kind: HorizontalPodAutoscaler",
|
|
51
|
+
"metadata:",
|
|
52
|
+
" name: frontend-scaler",
|
|
53
|
+
"spec:",
|
|
54
|
+
" scaleTargetRef:",
|
|
55
|
+
" kind: ReplicaSet",
|
|
56
|
+
" name: frontend",
|
|
57
|
+
" minReplicas: 3",
|
|
58
|
+
" maxReplicas: 10",
|
|
59
|
+
" targetCPUUtilizationPercentage: 50",
|
|
60
|
+
].join("\n");
|
|
61
|
+
expect(await roundTrip(yaml)).toEqual(loadAll(yaml));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("an autoscaling/v2 HorizontalPodAutoscaler is generated without an apiVersion property", async () => {
|
|
65
|
+
const yaml = [
|
|
66
|
+
"apiVersion: autoscaling/v2",
|
|
67
|
+
"kind: HorizontalPodAutoscaler",
|
|
68
|
+
"metadata:",
|
|
69
|
+
" name: web",
|
|
70
|
+
"spec:",
|
|
71
|
+
" scaleTargetRef:",
|
|
72
|
+
" apiVersion: apps/v1",
|
|
73
|
+
" kind: Deployment",
|
|
74
|
+
" name: web",
|
|
75
|
+
" minReplicas: 1",
|
|
76
|
+
" maxReplicas: 3",
|
|
77
|
+
].join("\n");
|
|
78
|
+
const imported = await importManifest(yaml);
|
|
79
|
+
try {
|
|
80
|
+
const source = Object.values(imported.files).join("\n");
|
|
81
|
+
expect(source).not.toContain('apiVersion: "autoscaling/v2"');
|
|
82
|
+
} finally {
|
|
83
|
+
removeDir(imported.dir);
|
|
84
|
+
}
|
|
85
|
+
expect(await roundTrip(yaml)).toEqual(loadAll(yaml));
|
|
86
|
+
});
|
|
87
|
+
});
|