Skip to content

Commit 4e50cae

Browse files
committed
feat(generator/engine): 新增 NormalizeYAML 函数,写入前通过 unmarshal→marshal 标准化 YAML 格式
解决 LLM 生成的 YAML 存在缩进不一致、多余空格、换行错乱等格式问题,同时应用于 generator 和 updater 的所有写入路径
1 parent 3bf8f5f commit 4e50cae

2 files changed

Lines changed: 42 additions & 17 deletions

File tree

internal/generator/engine.go

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -278,17 +278,32 @@ func generateAndWrite(client llm.Client, summary, conversation string) error {
278278
return nil
279279
}
280280

281-
// writeYAMLFile 校验 YAML 合法性并写入文件
281+
// writeYAMLFile 校验 YAML 合法性,通过 unmarshal → marshal 标准化格式后写入文件
282282
func writeYAMLFile(path, content string) error {
283-
if err := ValidateYAML(content); err != nil {
283+
normalized, err := NormalizeYAML(content)
284+
if err != nil {
284285
return fmt.Errorf("生成的 %s 不合法: %w", filepath.Base(path), err)
285286
}
286-
if err := fileutil.WriteFile(path, []byte(content)); err != nil {
287+
if err := fileutil.WriteFile(path, []byte(normalized)); err != nil {
287288
return fmt.Errorf("写入 %s 失败: %w", path, err)
288289
}
289290
return nil
290291
}
291292

293+
// NormalizeYAML 通过 unmarshal → marshal 标准化 YAML 格式。
294+
// 解决 LLM 生成的 YAML 存在的缩进不一致、多余空格、换行错乱等问题。
295+
func NormalizeYAML(content string) (string, error) {
296+
var data interface{}
297+
if err := yaml.Unmarshal([]byte(content), &data); err != nil {
298+
return "", err
299+
}
300+
out, err := yaml.Marshal(data)
301+
if err != nil {
302+
return "", err
303+
}
304+
return string(out), nil
305+
}
306+
292307
// extractModulesFromArchitecture 从 ARCHITECTURE_MAP YAML 中提取模块名列表。
293308
// 使用完整相对路径(/ 替换为 _)作为模块标识符,避免不同父目录下同名包冲突。
294309
// 例如 "internal/config" → "internal_config", "cmd" → "cmd"。
@@ -317,24 +332,30 @@ func extractModulesFromArchitecture(archYAML string) []string {
317332
return modules
318333
}
319334

320-
// WriteGeneratedYAML 校验 GeneratedYAML 并写入 .kontext/ 目录。
335+
// WriteGeneratedYAML 校验 GeneratedYAML,标准化格式并写入 .kontext/ 目录。
321336
func WriteGeneratedYAML(generated *GeneratedYAML) error {
322-
// 校验 YAML 合法性
323-
if err := ValidateYAML(generated.ProjectManifest); err != nil {
337+
// 标准化 YAML 格式
338+
normalizedManifest, err := NormalizeYAML(generated.ProjectManifest)
339+
if err != nil {
324340
return fmt.Errorf("生成的 PROJECT_MANIFEST.yaml 不合法: %w", err)
325341
}
326-
if err := ValidateYAML(generated.ArchitectureMap); err != nil {
342+
normalizedArch, err := NormalizeYAML(generated.ArchitectureMap)
343+
if err != nil {
327344
return fmt.Errorf("生成的 ARCHITECTURE_MAP.yaml 不合法: %w", err)
328345
}
329-
if err := ValidateYAML(generated.Conventions); err != nil {
346+
normalizedConv, err := NormalizeYAML(generated.Conventions)
347+
if err != nil {
330348
return fmt.Errorf("生成的 CONVENTIONS.yaml 不合法: %w", err)
331349
}
332350

333-
// 校验模块契约
351+
// 标准化模块契约
352+
normalizedContracts := make(map[string]string, len(generated.ModuleContracts))
334353
for name, content := range generated.ModuleContracts {
335-
if err := ValidateYAML(content); err != nil {
354+
normalized, err := NormalizeYAML(content)
355+
if err != nil {
336356
return fmt.Errorf("生成的 %s_CONTRACT.yaml 不合法: %w", name, err)
337357
}
358+
normalizedContracts[name] = normalized
338359
}
339360

340361
// 写入文件
@@ -352,9 +373,9 @@ func WriteGeneratedYAML(generated *GeneratedYAML) error {
352373

353374
// 写入核心配置文件
354375
files := map[string]string{
355-
filepath.Join(kontextDir, "PROJECT_MANIFEST.yaml"): generated.ProjectManifest,
356-
filepath.Join(kontextDir, "ARCHITECTURE_MAP.yaml"): generated.ArchitectureMap,
357-
filepath.Join(kontextDir, "CONVENTIONS.yaml"): generated.Conventions,
376+
filepath.Join(kontextDir, "PROJECT_MANIFEST.yaml"): normalizedManifest,
377+
filepath.Join(kontextDir, "ARCHITECTURE_MAP.yaml"): normalizedArch,
378+
filepath.Join(kontextDir, "CONVENTIONS.yaml"): normalizedConv,
358379
}
359380

360381
for path, content := range files {
@@ -365,10 +386,10 @@ func WriteGeneratedYAML(generated *GeneratedYAML) error {
365386
}
366387

367388
// 写入模块契约文件
368-
if len(generated.ModuleContracts) > 0 {
389+
if len(normalizedContracts) > 0 {
369390
fmt.Println()
370-
fmt.Printf(" 模块契约 (%d 个):\n", len(generated.ModuleContracts))
371-
for name, content := range generated.ModuleContracts {
391+
fmt.Printf(" 模块契约 (%d 个):\n", len(normalizedContracts))
392+
for name, content := range normalizedContracts {
372393
filename := fmt.Sprintf("%s_CONTRACT.yaml", name)
373394
path := filepath.Join(kontextDir, "module_contracts", filename)
374395
if err := fileutil.WriteFile(path, []byte(content)); err != nil {

internal/updater/executor.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -531,7 +531,11 @@ func (e *Executor) applyAction(targetPath string, action UpdateAction, content s
531531
return nil
532532
}
533533

534-
return fileutil.WriteFile(targetPath, []byte(content))
534+
normalized, err := generator.NormalizeYAML(content)
535+
if err != nil {
536+
return fmt.Errorf("生成的 YAML 格式不合法: %w", err)
537+
}
538+
return fileutil.WriteFile(targetPath, []byte(normalized))
535539
}
536540

537541
// backupIfExists 如果目标文件存在则备份到 backup/ 目录。

0 commit comments

Comments
 (0)