(section: string, key: string, value: string | number | boolean)
| 112 | * 采用简单的 TOML 序列化:仅支持一级 section + 字符串/数字值。 |
| 113 | */ |
| 114 | export function writeConfigField(section: string, key: string, value: string | number | boolean): void { |
| 115 | if (!fs.existsSync(CONFIG_DIR)) { |
| 116 | fs.mkdirSync(CONFIG_DIR, { recursive: true }) |
| 117 | } |
| 118 | |
| 119 | let existing: Record<string, Record<string, unknown>> = {} |
| 120 | if (fs.existsSync(CONFIG_TOML)) { |
| 121 | try { |
| 122 | const content = fs.readFileSync(CONFIG_TOML, 'utf-8') |
| 123 | existing = parseToml(content) as Record<string, Record<string, unknown>> |
| 124 | } catch { |
| 125 | // 解析失败时从空开始,旧文件会被覆盖 |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | if (!existing[section] || typeof existing[section] !== 'object') { |
| 130 | existing[section] = {} |
| 131 | } |
| 132 | existing[section][key] = value |
| 133 | |
| 134 | const lines: string[] = [] |
| 135 | for (const [sec, entries] of Object.entries(existing)) { |
| 136 | if (typeof entries !== 'object' || entries === null) continue |
| 137 | lines.push(`[${sec}]`) |
| 138 | for (const [k, v] of Object.entries(entries as Record<string, unknown>)) { |
| 139 | if (typeof v === 'string') { |
| 140 | lines.push(`${k} = ${JSON.stringify(v)}`) |
| 141 | } else if (typeof v === 'number' || typeof v === 'boolean') { |
| 142 | lines.push(`${k} = ${v}`) |
| 143 | } |
| 144 | } |
| 145 | lines.push('') |
| 146 | } |
| 147 | |
| 148 | fs.writeFileSync(CONFIG_TOML, lines.join('\n'), 'utf-8') |
| 149 | } |
| 150 | |
| 151 | function deepMerge(base: Record<string, unknown>, override: Record<string, unknown>): Record<string, unknown> { |
| 152 | const result = { ...base } |
no outgoing calls
no test coverage detected