Files
jp-editor/scripts/generate-requirements.mjs
2026-09-22 16:33:35 +08:00

44 lines
5.1 KiB
JavaScript

import { mkdir, writeFile } from "node:fs/promises";
const range = (prefix, start, end) => Array.from({ length: end - start + 1 }, (_, index) => `${prefix}-${String(start + index).padStart(3, "0")}`);
const rows = [];
const add = ({ ids, priority, stages, accRefs, source, scope = "R1", notes }) => {
for (const id of ids) rows.push({ id, source, priority, scope, stages, accRefs, status: "baseline-not-started", notes });
};
add({ ids: range("F", 1, 7), source: "PRD-F-001..007", priority: "P0", stages: ["M1", "M2", "M4", "M5"], accRefs: ["ACC-F-001..020", "ACC-X-001..012"], notes: "核心文件、导入、编辑、工程和导出闭环;在实现阶段拆解为逐条断言。" });
add({ ids: ["F-008"], source: "PRD-F-008", priority: "P1", stages: ["M2", "M4", "M6", "M7"], accRefs: ["ACC-F-021..022", "ACC-L-009..011", "ACC-L-019", "ACC-X-013"], notes: "扩展编辑能力,未知内容必须保留并诊断。" });
add({ ids: range("E", 1, 4), source: "PRD-E-001..004", priority: "P0", stages: ["M2", "M4", "M6"], accRefs: ["ACC-E-001..004", "ACC-E-007", "ACC-F-009"], notes: "核心节拍、音符、休止和时值语义。" });
add({ ids: range("E", 5, 8), source: "PRD-E-005..008", priority: "P1", stages: ["M6", "M8"], accRefs: ["ACC-E-005..012", "ACC-O-001..006", "ACC-A-009", "ACC-A-017", "ACC-A-021..023"], notes: "复杂装饰、和弦/伴奏及扩展语义。" });
add({ ids: range("T", 1, 6), source: "PRD-T-001..006", priority: "P0/P1", stages: ["M4", "M6"], accRefs: ["ACC-T-001..007", "ACC-L-006", "ACC-L-012"], notes: "歌词、分词、对齐和未知歌词内容保留。" });
add({ ids: range("V", 1, 6), source: "PRD-V-001..006", priority: "P1", stages: ["M7"], accRefs: ["ACC-V-001..006", "ACC-O-003..006", "ACC-L-020"], notes: "多声部、声部组和临时声部。" });
add({ ids: ["V-007"], source: "PRD-V-007", priority: "P1", stages: ["M5", "M7"], accRefs: ["ACC-V-007", "ACC-A-015"], notes: "声部级播放/静音与导出边界。" });
add({ ids: range("L", 1, 6), source: "PRD-L-001..006", priority: "P0/P1", stages: ["M3", "M6"], accRefs: ["ACC-L-001..008", "ACC-L-013..018", "ACC-L-020", "ACC-G-001..004", "ACC-X-009"], notes: "A4 固定布局、分页、字体测量和 SVG 正式谱面。" });
add({ ids: range("L", 7, 8), source: "PRD-L-007..008", priority: "P1", stages: ["M7"], accRefs: ["ACC-L-009..011", "ACC-L-019"], notes: "手动布局状态必须进入工程保存。" });
add({ ids: ["L-009"], source: "PRD-L-009", priority: "P1", stages: ["M3", "M6"], accRefs: ["ACC-L-005", "ACC-L-015", "ACC-G-001..004"], notes: "复杂布局附件和占位行为。" });
add({ ids: ["L-010"], source: "PRD-L-010", priority: "P1", stages: ["M3"], accRefs: ["ACC-L-018", "ACC-Q-002"], notes: "输出确定性和溢出诊断。" });
add({ ids: [...range("A", 1, 3), ...range("A", 6, 7)], source: "PRD-A-001..003,006..007", priority: "P0", stages: ["M5"], accRefs: ["ACC-A-001..008", "ACC-A-012..016"], notes: "基础播放、控制、时间线和声部控制。" });
add({ ids: range("A", 4, 5), source: "PRD-A-004..005", priority: "P1", stages: ["M8"], accRefs: ["ACC-A-009..011", "ACC-A-017..023"], notes: "反复、谱内控制状态和扩展播放降级。" });
add({ ids: ["A-008"], source: "PRD-A-008", priority: "P2", scope: "out-of-scope", stages: [], accRefs: ["ACC-A-023"], notes: "外部音色/扩展音频能力明确不纳入本目标。" });
add({ ids: ["A-009"], source: "PRD-A-009", priority: "P1", stages: ["M8"], accRefs: ["ACC-A-006", "ACC-A-018", "ACC-A-022", "ACC-E-007", "ACC-T-007"], notes: "W1 播放金样和控制语义。" });
add({ ids: range("U", 1, 4), source: "PRD-U-001..004", priority: "P0", stages: ["M4", "M5", "M9"], accRefs: ["ACC-Q-004..006", "ACC-L-013", "ACC-X-003", "ACC-X-006"], notes: "可用性、键盘、无障碍和错误提示。" });
add({ ids: range("Q", 1, 9), source: "验收标准-质量门槛", priority: "P0/P1", stages: ["M0", "M5", "M9"], accRefs: ["ACC-Q-001..009", "ACC-X-001..014"], notes: "性能、安全、回退、证据完整性和发布门槛;逐项结果在验收证据包中记录。" });
await mkdir("config", { recursive: true });
const baseline = {
version: 1,
generatedBy: "scripts/generate-requirements.mjs",
sources: [
{ path: "docs/JPW7在线简谱编辑器-产品需求文档.md", version: "current project baseline" },
{ path: "docs/JPW7在线简谱编辑器-功能规格与技术方案.md", version: "current project baseline" },
{ path: "docs/JPW7在线简谱编辑器-开发步骤计划.md", version: "v1.1" },
{ path: "docs/JPW7在线简谱编辑器-验收标准.md", version: "v1.2" },
{ path: "docs/JPW7在线简谱编辑器-兼容性矩阵.md", version: "current project baseline" }
],
capabilityDimensions: ["file-codec", "parser", "lossless-retention", "semantic-model", "stable-anchor", "commands", "project-save", "layout", "svg", "playback", "compatibility-export", "e2e", "performance", "security", "accessibility", "licensing", "evidence"],
entryCount: rows.length,
entries: rows
};
await writeFile("config/requirements.json", `${JSON.stringify(baseline, null, 2)}\n`, "utf8");
console.log(`Wrote config/requirements.json with ${rows.length} traceability entries`);