Files
brainwave/scripts/build-hexagram-package.mjs
QiuSWandCursor 534c88993e feat: add local hexagram content for offline reading
Load a versioned Wikisource jing plus project-authored plain drafts so results can show labeled original and vernacular texts without unauthorized modern translations.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-19 11:48:16 +08:00

86 lines
3.6 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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`);