Skip to content

Commit f7f0ad3

Browse files
author
tanmaishi
committed
fix: ensure YAML 1.1 compatibility by migrating parser to yaml library
1 parent b43ea8b commit f7f0ad3

File tree

5 files changed

+77
-15
lines changed

5 files changed

+77
-15
lines changed

package-lock.json

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,15 +62,15 @@
6262
"form-data": "^4.0.0",
6363
"hpagent": "^1.2.0",
6464
"isomorphic-ws": "^5.0.0",
65-
"js-yaml": "^4.1.0",
6665
"jsonpath-plus": "^10.3.0",
6766
"node-fetch": "^2.7.0",
6867
"openid-client": "^6.1.3",
6968
"rfc4648": "^1.3.0",
7069
"socks-proxy-agent": "^8.0.4",
7170
"stream-buffers": "^3.0.2",
7271
"tar-fs": "^3.0.9",
73-
"ws": "^8.18.2"
72+
"ws": "^8.18.2",
73+
"yaml": "^2.8.1"
7474
},
7575
"devDependencies": {
7676
"@eslint/js": "^9.18.0",

src/types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { V1ListMeta, V1ObjectMeta } from './api.js';
2+
import { Schema } from 'yaml';
23

34
export interface KubernetesObject {
45
apiVersion?: string;
@@ -13,6 +14,15 @@ export interface KubernetesListObject<T extends KubernetesObject> {
1314
items: T[];
1415
}
1516

17+
export type YamlParseOptions = {
18+
version?: '1.1' | '1.2';
19+
maxAliasCount?: number;
20+
prettyErrors?: boolean;
21+
keepCstNodes?: boolean;
22+
keepNodeTypes?: boolean;
23+
logLevel?: 'silent' | 'error' | 'warn';
24+
};
25+
1626
export type IntOrString = number | string;
1727

1828
export class V1MicroTime extends Date {

src/yaml.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import yaml from 'js-yaml';
1+
import yaml from 'yaml';
22
import { getSerializationType } from './util.js';
3-
import { KubernetesObject } from './types.js';
3+
import { KubernetesObject, YamlParseOptions } from './types.js';
44
import { ObjectSerializer } from './serializer.js';
55

66
/**
@@ -9,8 +9,8 @@ import { ObjectSerializer } from './serializer.js';
99
* @param opts - Optional YAML load options.
1010
* @returns The deserialized Kubernetes object.
1111
*/
12-
export function loadYaml<T>(data: string, opts?: yaml.LoadOptions): T {
13-
const yml = yaml.load(data, opts) as any as KubernetesObject;
12+
export function loadYaml<T>(data: string, opts?: YamlParseOptions): T {
13+
const yml = yaml.parse(data, { version: '1.1', ...opts }) as any as KubernetesObject;
1414
if (!yml) {
1515
throw new Error('Failed to load YAML');
1616
}
@@ -25,12 +25,12 @@ export function loadYaml<T>(data: string, opts?: yaml.LoadOptions): T {
2525
* @param opts - Optional YAML load options.
2626
* @returns An array of deserialized Kubernetes objects.
2727
*/
28-
export function loadAllYaml(data: string, opts?: yaml.LoadOptions): any[] {
29-
const ymls = yaml.loadAll(data, undefined, opts);
28+
export function loadAllYaml(data: string, opts?: YamlParseOptions): any[] {
29+
const ymls = yaml.parseAllDocuments(data, { version: '1.1', ...opts });
3030
return ymls.map((yml) => {
31-
const obj = yml as KubernetesObject;
31+
const obj = yml.toJS() as KubernetesObject;
3232
const type = getSerializationType(obj.apiVersion, obj.kind);
33-
return ObjectSerializer.deserialize(yml, type);
33+
return ObjectSerializer.deserialize(obj, type);
3434
});
3535
}
3636

@@ -40,9 +40,9 @@ export function loadAllYaml(data: string, opts?: yaml.LoadOptions): any[] {
4040
* @param opts - Optional YAML dump options.
4141
* @returns The YAML string representation of the serialized Kubernetes object.
4242
*/
43-
export function dumpYaml(object: any, opts?: yaml.DumpOptions): string {
43+
export function dumpYaml(object: any, opts?: YamlParseOptions): string {
4444
const kubeObject = object as KubernetesObject;
4545
const type = getSerializationType(kubeObject.apiVersion, kubeObject.kind);
4646
const serialized = ObjectSerializer.serialize(kubeObject, type);
47-
return yaml.dump(serialized, opts);
47+
return yaml.stringify(serialized, { version: '1.1', ...opts });
4848
}

src/yaml_test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,55 @@ spec:
154154
// not using strict equality as types are not matching
155155
deepEqual(actual, expected);
156156
});
157+
158+
it('should parse octal values correctly using default YAML 1.1', () => {
159+
const yamlStr = `
160+
apiVersion: v1
161+
kind: ConfigMap
162+
metadata:
163+
name: test
164+
data:
165+
mode: 0644
166+
`;
167+
const obj = loadYaml<{
168+
data: { mode: number };
169+
metadata: { name: string };
170+
apiVersion: string;
171+
kind: string;
172+
}>(yamlStr);
173+
strictEqual(obj.data.mode, 420);
174+
});
175+
176+
it('should treat octal as string if version 1.2 is provided', () => {
177+
const yamlStr = `
178+
apiVersion: v1
179+
kind: ConfigMap
180+
metadata:
181+
name: test
182+
data:
183+
mode: '0644'
184+
`;
185+
186+
const objs = loadAllYaml(yamlStr, { version: '1.2', maxAliasCount: 100, prettyErrors: true });
187+
188+
strictEqual(objs[0].data.mode, '0644');
189+
});
190+
191+
it('should load multiple documents with default YAML 1.1', () => {
192+
const yamlStr = `
193+
apiVersion: v1
194+
kind: ConfigMap
195+
metadata:
196+
name: cm1
197+
---
198+
apiVersion: v1
199+
kind: ConfigMap
200+
metadata:
201+
name: cm2
202+
`;
203+
const objs = loadAllYaml(yamlStr) as Array<{ metadata: { name: string } }>;
204+
strictEqual(objs.length, 2);
205+
strictEqual(objs[0].metadata.name, 'cm1');
206+
strictEqual(objs[1].metadata.name, 'cm2');
207+
});
157208
});

0 commit comments

Comments
 (0)