diff --git a/docs/maintainer/diagram-artifact-export-cli.md b/docs/maintainer/diagram-artifact-export-cli.md index 52e24e45..33d95e83 100644 --- a/docs/maintainer/diagram-artifact-export-cli.md +++ b/docs/maintainer/diagram-artifact-export-cli.md @@ -9,7 +9,7 @@ topic: diagram-artifact-export-cli `scripts/export-diagram-artifact.js` is the offline CLI boundary for the diagram figure work that came from the Cloudy-style technical-diagram reference and the Drawnix reference spike. -It accepts a checked `DiagramSpec` JSON file and writes one artifact without requiring Obsidian, `obsidian-cli`, diagrams.net Desktop, Drawnix, Plait, or a browser runtime. +It accepts a checked `DiagramSpec` JSON file and writes one artifact without requiring Obsidian, `obsidian-cli`, diagrams.net Desktop, Drawnix, Plait, or a browser runtime. The input may be UTF-8 with or without a BOM, which keeps files produced by Windows PowerShell usable without a separate normalization step. ```bash npm run diagram:export-artifact -- --input spec.json --target editable-html-svg --output figure.html diff --git a/docs/maintainer/diagram-artifact-export-cli.zh-CN.md b/docs/maintainer/diagram-artifact-export-cli.zh-CN.md index e1b9c49a..e50f8e68 100644 --- a/docs/maintainer/diagram-artifact-export-cli.zh-CN.md +++ b/docs/maintainer/diagram-artifact-export-cli.zh-CN.md @@ -9,7 +9,7 @@ topic: diagram-artifact-export-cli `scripts/export-diagram-artifact.js` 是图形扩展工作的离线 CLI 边界,覆盖 Cloudy 风格技术图参考与 Drawnix 参考 spike 产生的 artifact 导出需求。 -它读取已验证结构的 `DiagramSpec` JSON 文件,并写出一个 artifact;不需要 Obsidian、`obsidian-cli`、diagrams.net Desktop、Drawnix、Plait 或浏览器运行时。 +它读取已验证结构的 `DiagramSpec` JSON 文件,并写出一个 artifact;不需要 Obsidian、`obsidian-cli`、diagrams.net Desktop、Drawnix、Plait 或浏览器运行时。输入文件可以是带 BOM 或不带 BOM 的 UTF-8,这样 Windows PowerShell 生成的 JSON 不需要额外归一化也能直接使用。 ```bash npm run diagram:export-artifact -- --input spec.json --target editable-html-svg --output figure.html diff --git a/scripts/export-diagram-artifact.js b/scripts/export-diagram-artifact.js index 6be84d97..bdb5c5f2 100644 --- a/scripts/export-diagram-artifact.js +++ b/scripts/export-diagram-artifact.js @@ -79,7 +79,8 @@ function assertSupportedTarget(target) { } function loadDiagramSpec(inputPath) { - return JSON.parse(fs.readFileSync(inputPath, 'utf8')); + const source = fs.readFileSync(inputPath, 'utf8').replace(/^\uFEFF/, ''); + return JSON.parse(source); } function ensureOutputDirectory(outputPath) { diff --git a/src/tests/diagramArtifactExportCli.test.ts b/src/tests/diagramArtifactExportCli.test.ts index ca7e27db..a71f833a 100644 --- a/src/tests/diagramArtifactExportCli.test.ts +++ b/src/tests/diagramArtifactExportCli.test.ts @@ -50,6 +50,8 @@ describe('diagram artifact export CLI', () => { expect(runbook).toContain('DiagramSpec'); expect(runbook).toContain('SemanticFigureModel'); expect(runbook).toContain('no Obsidian runtime'); + expect(runbook).toContain('UTF-8'); + expect(runbook).toContain('BOM'); } }); @@ -125,6 +127,40 @@ describe('diagram artifact export CLI', () => { } }, 30000); + test('accepts UTF-8 BOM DiagramSpec files produced by Windows PowerShell', () => { + const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'notemd-diagram-artifact-cli-bom-')); + const specPath = path.join(tempRoot, 'spec.json'); + const outputPath = path.join(tempRoot, 'figure.drawio'); + fs.writeFileSync(specPath, `\uFEFF${JSON.stringify(createSpec(), null, 2)}`, 'utf8'); + + try { + const stdout = execFileSync( + process.execPath, + [ + scriptPath, + '--input', specPath, + '--target', 'drawio', + '--output', outputPath + ], + { + cwd: repoRoot, + encoding: 'utf8' + } + ); + + const result = JSON.parse(stdout); + expect(result).toEqual(expect.objectContaining({ + target: 'drawio', + outputPath, + nodeCount: 3, + edgeCount: 2 + })); + expect(fs.readFileSync(outputPath, 'utf8')).toContain(' { const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'notemd-diagram-artifact-cli-bad-target-')); const specPath = path.join(tempRoot, 'spec.json');