diff --git a/package-lock.json b/package-lock.json index 2747dfa6e9..aa2c17d5d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,14 +9,12 @@ "version": "1.3.0", "license": "Apache-2.0", "dependencies": { - "@types/js-yaml": "^4.0.1", "@types/node": "^24.0.0", "@types/node-fetch": "^2.6.9", "@types/stream-buffers": "^3.0.3", "form-data": "^4.0.0", "hpagent": "^1.2.0", "isomorphic-ws": "^5.0.0", - "js-yaml": "^4.1.0", "jsonpath-plus": "^10.3.0", "node-fetch": "^2.6.9", "openid-client": "^6.1.3", @@ -24,7 +22,8 @@ "socks-proxy-agent": "^8.0.4", "stream-buffers": "^3.0.2", "tar-fs": "^3.0.9", - "ws": "^8.18.2" + "ws": "^8.18.2", + "yaml": "^2.8.0" }, "devDependencies": { "@eslint/js": "^9.18.0", @@ -1349,6 +1348,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, "license": "Python-2.0" }, "node_modules/asynckit": { @@ -2659,6 +2659,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -4022,7 +4023,7 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", - "dev": true, + "license": "ISC", "bin": { "yaml": "bin.mjs" }, diff --git a/package.json b/package.json index 173117514f..cd5a51ff52 100644 --- a/package.json +++ b/package.json @@ -55,14 +55,12 @@ "author": "Kubernetes Authors", "license": "Apache-2.0", "dependencies": { - "@types/js-yaml": "^4.0.1", "@types/node": "^24.0.0", "@types/node-fetch": "^2.6.9", "@types/stream-buffers": "^3.0.3", "form-data": "^4.0.0", "hpagent": "^1.2.0", "isomorphic-ws": "^5.0.0", - "js-yaml": "^4.1.0", "jsonpath-plus": "^10.3.0", "node-fetch": "^2.6.9", "openid-client": "^6.1.3", @@ -70,7 +68,8 @@ "socks-proxy-agent": "^8.0.4", "stream-buffers": "^3.0.2", "tar-fs": "^3.0.9", - "ws": "^8.18.2" + "ws": "^8.18.2", + "yaml": "^2.8.0" }, "devDependencies": { "@eslint/js": "^9.18.0", diff --git a/src/yaml.ts b/src/yaml.ts index 09468a3e5d..2218fd47d3 100644 --- a/src/yaml.ts +++ b/src/yaml.ts @@ -1,48 +1,50 @@ -import yaml from 'js-yaml'; +import yaml from 'yaml'; import { getSerializationType } from './util.js'; import { KubernetesObject } from './types.js'; import { ObjectSerializer } from './serializer.js'; /** - * Load a Kubernetes object from YAML. + * Load a single Kubernetes object from YAML. * @param data - The YAML string to load. - * @param opts - Optional YAML load options. + * @param opts - Optional YAML parse options. * @returns The deserialized Kubernetes object. */ -export function loadYaml(data: string, opts?: yaml.LoadOptions): T { - const yml = yaml.load(data, opts) as any as KubernetesObject; +export function loadYaml(data: string, opts?: yaml.ParseOptions & yaml.DocumentOptions): T { + const yml = yaml.parse(data, { version: '1.1', ...opts }) as any as KubernetesObject; if (!yml) { - throw new Error('Failed to load YAML'); + throw new Error('Failed to load yaml'); } const type = getSerializationType(yml.apiVersion, yml.kind); - return ObjectSerializer.deserialize(yml, type) as T; } /** - * Load all Kubernetes objects from YAML. + * Load all Kubernetes objects from a multi-document YAML string. * @param data - The YAML string to load. - * @param opts - Optional YAML load options. + * @param opts - Optional YAML parse options. * @returns An array of deserialized Kubernetes objects. */ -export function loadAllYaml(data: string, opts?: yaml.LoadOptions): any[] { - const ymls = yaml.loadAll(data, undefined, opts); - return ymls.map((yml) => { - const obj = yml as KubernetesObject; +export function loadAllYaml( + data: string, + opts?: yaml.ParseOptions & yaml.DocumentOptions & yaml.SchemaOptions, +): any[] { + const ymls = yaml.parseAllDocuments(data, { version: '1.1', ...opts }); + return ymls.map((doc) => { + const obj = doc.toJSON() as KubernetesObject; const type = getSerializationType(obj.apiVersion, obj.kind); - return ObjectSerializer.deserialize(yml, type); + return ObjectSerializer.deserialize(obj, type); }); } /** - * Dump a Kubernetes object to YAML. + * Dump a Kubernetes object to a YAML string. * @param object - The Kubernetes object to dump. - * @param opts - Optional YAML dump options. - * @returns The YAML string representation of the serialized Kubernetes object. + * @param opts - Optional YAML stringify options. + * @returns The YAML string representation of the serialized object. */ -export function dumpYaml(object: any, opts?: yaml.DumpOptions): string { +export function dumpYaml(object: any, opts?: yaml.ToStringOptions): string { const kubeObject = object as KubernetesObject; const type = getSerializationType(kubeObject.apiVersion, kubeObject.kind); const serialized = ObjectSerializer.serialize(kubeObject, type); - return yaml.dump(serialized, opts); + return yaml.stringify(serialized, opts); } diff --git a/src/yaml_test.ts b/src/yaml_test.ts index 958f7ba45b..d99c08b869 100644 --- a/src/yaml_test.ts +++ b/src/yaml_test.ts @@ -154,4 +154,39 @@ spec: // not using strict equality as types are not matching deepEqual(actual, expected); }); + + it('should parse octal-like strings as numbers (YAML 1.1 style)', () => { + const yaml = ` + defaultMode: 0644 + fileMode: 0755 + `; + const result = loadYaml<{ + defaultMode: number; + fileMode: number; + }>(yaml); + + // 0644 (octal) = 420 decimal, 0755 = 493 + strictEqual(result.defaultMode, 420); + strictEqual(result.fileMode, 493); + }); + + it('should parse boolean-like strings as booleans (YAML 1.1 style)', () => { + const yaml = ` + enableFeature: yes + debugMode: ON + maintenance: no + safeMode: off + `; + const result = loadYaml<{ + enableFeature: boolean; + debugMode: boolean; + maintenance: boolean; + safeMode: boolean; + }>(yaml); + + strictEqual(result.enableFeature, true); + strictEqual(result.debugMode, true); + strictEqual(result.maintenance, false); + strictEqual(result.safeMode, false); + }); });