import { readFile, writeFile, mkdir } from "node:fs/promises"; import path from "node:path"; import { kingWenEntries, validateContentPackage } from "./content-contract.mjs"; import { repositoryRoot } from "./repository-files.mjs"; import { lingjiPlain } from "../content/plain/lingji-plain.mjs"; const names = [ "乾", "坤", "屯", "蒙", "需", "讼", "师", "比", "小畜", "履", "泰", "否", "同人", "大有", "谦", "豫", "随", "蛊", "临", "观", "噬嗑", "贲", "剥", "复", "无妄", "大畜", "颐", "大过", "坎", "离", "咸", "恒", "遁", "大壮", "晋", "明夷", "家人", "睽", "蹇", "解", "损", "益", "夬", "姤", "萃", "升", "困", "井", "革", "鼎", "震", "艮", "渐", "归妹", "丰", "旅", "巽", "兑", "涣", "节", "中孚", "小过", "既济", "未济", ]; if (lingjiPlain.length !== 64) { throw new Error(`lingji plain table must contain 64 hexagrams, got ${lingjiPlain.length}`); } const jingPath = path.join(repositoryRoot, "content", "raw", "zhouyi-wikisource-jing.json"); const jing = JSON.parse(await readFile(jingPath, "utf8")); if (!Array.isArray(jing) || jing.length !== 64) { throw new Error("Wikisource jing import must contain 64 hexagrams; run scripts/import-zhouyi-wikisource.mjs"); } const jingById = new Map(jing.map((item) => [item.kingWenNumber, item])); const entries = kingWenEntries(); const originalSource = "wikisource-zhouyi-jing-zh-Hans"; const plainSource = "lingji-plain-zh-Hans-2026.1"; const contentPackage = { schemaVersion: 1, contentVersion: "zh-Hans-2026.1", specialUsageTexts: { qian: true, kun: true }, sources: [ { id: originalSource, title: "维基文库《周易》易经", edition: "仅卦辞、爻辞与乾用九、坤用六,不含十翼;由 zh.wikisource.org 导入并经 Wikimedia zh-hans 转换", license: "公版(Wikimedia PD-old)", url: "https://zh.wikisource.org/wiki/周易", }, { id: plainSource, title: "灵机本地白话", edition: "2026.1 项目自撰草稿,待内容负责人审校后视为可再分发", license: "项目自撰;审校完成前仅用于本机构建,不以现代译注冒充公版", url: "https://creativecommons.org/licenses/by/4.0/deed.zh-Hans", }, ], hexagrams: entries.map((entry) => { const original = jingById.get(entry.kingWenNumber); if (!original) { throw new Error(`Missing jing text for King Wen ${entry.kingWenNumber}`); } const plain = lingjiPlain[entry.kingWenNumber - 1]; if (!Array.isArray(plain) || plain.length !== 7 || plain.some((text) => !String(text).trim())) { throw new Error(`Plain text for King Wen ${entry.kingWenNumber} must contain 7 non-blank strings`); } return { ...entry, name: names[entry.kingWenNumber - 1], symbol: String.fromCodePoint(0x4DC0 + entry.kingWenNumber - 1), judgmentOriginal: original.judgmentOriginal, judgmentPlain: plain[0], lineTextsBottomUp: original.lineTextsBottomUp, linePlainBottomUp: plain.slice(1), specialUsageText: original.specialUsageText ?? null, sourceRefs: [originalSource, plainSource], }; }), }; const errors = validateContentPackage(contentPackage); if (errors.length > 0) { throw new Error(`Built content package failed validation:\n${errors.join("\n")}`); } const outputDirectory = path.join(repositoryRoot, "content", "packages"); await mkdir(outputDirectory, { recursive: true }); const outputPath = path.join(outputDirectory, "hexagram-content.json"); await writeFile(outputPath, `${JSON.stringify(contentPackage, null, 2)}\n`); process.stdout.write(`wrote ${outputPath}\n`);