fix(schemas): k8s toYaml 修复 ports/volumes/envFrom 等数组-对象字段被错渲为 dict
toYaml(obj, indent=0) 旧版递归缩进计算错位,导致:
ports:
ports: <- 多余的父 key 行
- name: http
containerPort: 5099
被 pyyaml 反解为 {0:{...}} 而不是 list, kubectl apply 报:
cannot unmarshal object into Go struct field
Container.spec.template.spec.containers.ports of type []v1.ContainerPort
修复:
- 重写为 baseIndent 字符串缩进版, 数组-对象分支递归渲染后第一行加 '- '
- 新增 yamlScalar(v) 处理 number/boolean/特殊字符安全引号
- 新增 isEmptyMapping(o) 把 emptyDir:{} 等空对象渲染为 {}
- 20 个 k8s-*.js schema 全部统一替换
验证:
- npm run build 通过
- PyYAML 反序列化 ports/volumes/envFrom/tolerations 等 9 个数组-对象字段全部为 list
- 全部 20 个 schema E2E OK
This commit is contained in:
+46
-17
@@ -136,36 +136,65 @@ export const k8sIngressSchema = {
|
||||
],
|
||||
}
|
||||
|
||||
function toYaml(obj, indent = 0) {
|
||||
const lines = []
|
||||
const prefix = ' '.repeat(indent)
|
||||
|
||||
|
||||
|
||||
function yamlScalar(v) {
|
||||
if (v === null || v === undefined) return ''
|
||||
if (typeof v === 'number' || typeof v === 'boolean') return String(v)
|
||||
const s = String(v)
|
||||
if (/[:#\n"'`]|^[\s\-]|[\s]$/.test(s) || /^(true|false|null|yes|no|on|off|~)$/i.test(s)) {
|
||||
return JSON.stringify(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
function isEmptyMapping(o) {
|
||||
if (!o || typeof o !== 'object' || Array.isArray(o)) return false
|
||||
return Object.values(o).every(v => v === null || v === undefined || v === '' || (typeof v === 'object' && isEmptyMapping(v)))
|
||||
}
|
||||
|
||||
function toYaml(obj, baseIndent = '') {
|
||||
const lines = []
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
if (value === null || value === undefined || value === '') continue
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
lines.push(`${prefix}${key}:`)
|
||||
for (const item of value) {
|
||||
if (typeof item === 'object' && item !== null) {
|
||||
const items = value.filter(v => v !== null && v !== undefined && v !== '')
|
||||
if (!items.length) continue
|
||||
lines.push(`${baseIndent}${key}:`)
|
||||
for (const item of items) {
|
||||
if (item && typeof item === 'object' && !Array.isArray(item)) {
|
||||
if (isEmptyMapping(item)) continue
|
||||
const entries = Object.entries(item).filter(([, v]) => v !== null && v !== undefined && v !== '')
|
||||
if (entries.length === 0) continue
|
||||
const first = entries[0]
|
||||
lines.push(`${prefix} - ${first[0]}: ${first[1]}`)
|
||||
for (let i = 1; i < entries.length; i++) {
|
||||
lines.push(`${prefix} ${entries[i][0]}: ${entries[i][1]}`)
|
||||
if (!entries.length) continue
|
||||
const childIndent = baseIndent + ' '
|
||||
const subAllIndent = childIndent + ' '
|
||||
const subObj = {}
|
||||
for (const [k, v] of entries) subObj[k] = v
|
||||
const subRendered = toYaml(subObj, subAllIndent)
|
||||
const subLines = subRendered.split('\n')
|
||||
if (subLines[0].startsWith(subAllIndent)) {
|
||||
subLines[0] = childIndent + '- ' + subLines[0].slice(subAllIndent.length)
|
||||
} else {
|
||||
subLines[0] = childIndent + '- ' + subLines[0].trimStart()
|
||||
}
|
||||
lines.push(...subLines)
|
||||
} else {
|
||||
lines.push(`${prefix} - ${item}`)
|
||||
lines.push(`${baseIndent} - ${yamlScalar(item)}`)
|
||||
}
|
||||
}
|
||||
} else if (typeof value === 'object') {
|
||||
lines.push(`${prefix}${key}:`)
|
||||
lines.push(toYaml(value, indent + 1))
|
||||
if (isEmptyMapping(value)) {
|
||||
lines.push(`${baseIndent}${key}: {}`)
|
||||
continue
|
||||
}
|
||||
lines.push(`${baseIndent}${key}:`)
|
||||
const childIndent = baseIndent + ' '
|
||||
lines.push(toYaml(value, childIndent))
|
||||
} else {
|
||||
lines.push(`${prefix}${key}: ${value}`)
|
||||
lines.push(`${baseIndent}${key}: ${yamlScalar(value)}`)
|
||||
}
|
||||
}
|
||||
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user