Skip to content

Repository files navigation

najia

六爻纳甲排盘的 TypeScript 实现。

移植自 Python 库 najia(MIT,作者 bopo),并保留其版权声明。

状态:移植完成,并在全部 4⁶ = 4096 种起卦组合上与 Python 实现验证一致。

用法

import { cast } from "@taoracle/najia";

// 六爻,初爻在前:1 单(阳静) 2 拆(阴静) 3 重(阳动) 4 交(阴动)
const reading = cast([2, 2, 1, 2, 4, 2], { date: new Date(2026, 6, 26, 14), guaci: true });

reading.gua.name;   // 卦名
reading.gua.gong;   // 卦宫
reading.gua.qin6;   // 六亲(每爻)
reading.gua.qinx;   // 干支五行(每爻)
reading.shiy;       // { shi, ying } 世应爻
reading.god6;       // 六神,按日干起
reading.dong;       // 动爻位置(0 起)
reading.bian;       // 变卦,无动爻时为 null
reading.hide;       // 伏神,六亲齐全时为 null
reading.ganzhi;     // { year, month, day, hour, xkong }

模块

模块 内容
src/const.ts 纳甲表、六十四卦、六神、六亲、五行、旬空、卦宫
src/utils.ts 纳甲配干支、世应爻、卦宫、游魂归魂、六冲六合、卦型、六亲、六神、旬空、干支五行
src/calendar.ts 年月日时干支与旬空,基于 tyme4ts
src/najia.ts 起卦主流程、变卦、伏神、卦辞
src/data/guaci.json 六十四卦卦辞,转录自中文维基文库(见下)

验证

全部 4⁶ = 4096 种起卦组合 × 5 个日期,99,776 个字段与 Python 实现零差异。

test/fixtures/parity.json 固化了这个结果:全空间取一个 SHA-256 聚合哈希,另有 48 个精选详例覆盖八个卦宫与变卦/伏神/动爻的各个分支。CI 不需要 Python 解释器即可验证一致性。

日期干支层单独验证:336 个时点(含立春、节气、子时、闰年、跨年边界)× 5 个字段,与 lunar_python 零差异。

重新生成 fixture 需要参考实现,见 tools/make-parity-fixture.ts

与原版的有意差异

移植过程中发现的原版缺陷,这里做了修正。每一处都会改变输出或 API,所以逐条列出:

1. 移除 set_shi_yao 的第三个返回值 index 上游 compile() 从不使用它,始终把世爻传给 palace()。而对 8 个游魂卦,两者给出不同的卦宫(火地晋用世爻得乾宫,用 index 得离宫)。留着它就是留一个静默出错的入口。

2. seat(伏神位置)改为升序确定输出。 上游用 set 差集迭代产生顺序,Python 的字符串哈希按进程随机化,同样的输入在不同次运行会得到不同顺序

3. 字符串入参不再静默失效。 上游 _transform 写的是 if 3 in params,当 params 是字符串时该判断恒为假——传字符串会静默地不产生变卦、不识别动爻。现在入参统一归一化并校验。

4. 拒绝非法日期。 lunar_python 接受 1900-2-29 这类不存在的日期(1900 非闰年)并给出结果,tyme4ts 会报错。测试中 24 个这类时点在本实现下抛异常。

5. 晚子时流派显式可选。 23:00–24:00 的日柱归属有两种成法,两个上游库的默认值恰好相反。本实现默认 day-stays(与 Python 一致,保证迁移不改变任何人的卦),可通过 lateZi: "day-advances" 切换。时柱不受影响——两个库都用次日干起。

6. 卦辞整体换源。 不沿用上游那份采集文本,改为从中文维基文库转录,见「卦辞数据的来源」。上游 64 卦里有 4 卦为错或为空,乾卦缺全部逐爻小象,正文夹着站点水印。

7. 不移植渲染层与 CLI。 上游的 jinja2 模板与 click 命令行不在范围内,结构化输出交给调用方格式化。因此本库零运行时依赖(除 tyme4ts)。

卦辞数据的来源

src/data/guaci.jsontools/build-guaci.py中文维基文库的《周易》转录而来:

  • 原文:https://zh.wikisource.org/wiki/周易
  • 《周易》本身属公有领域;维基文库的转录内容以 CC BY-SA 4.0 授权,本仓库据此注明来源
  • 全 64 卦,每卦包含卦辞、彖传、大象、六(七)爻爻辞与逐爻小象
  • 繁体转简体,并逐卦校验爻辞与小象一一对应

为什么不用上游 Python 库自带的那份

它是从命理网站 sm.aa963.com 采集的,判定依据是该站防盗水印直接留在正文里。除此之外还有:

问题 影响
txt→pickle 切分错位 泽山咸 粘着整条雷风恒,震为雷 粘着整条艮为山;4 卦卦辞为错或为空
乾卦缺全部逐爻小象 8 条缺失
站点水印 3 处、BBCode 残留 1 处 会被当作经文读给用户
转写错字 如乾卦九二作「见龙田」

这些缺陷在上游至今仍然存在(get_guaci('雷风恒') 返回 None),且其对卦辞的全部测试只有一行 assert get_guaci('乾为天')——在以上所有缺陷下都是绿的。

生成时的几个坑

  • opencct2s 会把「乾」转成「干」(乾燥/干燥),但《周易》的卦名与「乾乾」必须保留「乾」。已加白名单。
  • t2s 会把个别字转到 Unicode 扩展区:餗 → 𫗧 (U+2B5E7)、繻 → 𦈡 (U+26221),这些字在多数系统显示为缺字方块。转换改为逐字进行,并拒绝任何"把常用字推入扩展区"的转换。
  • 维基文库正文里夹有校勘注,如「保合大和〈一作太和〉」。这是校勘信息不是经文,已剥离。
  • 否卦的爻位用逗号而非冒号分隔,已统一为冒号。

以上四项都有测试或生成期断言守着。

对维基文库转录本身的修正

维基文库不是校勘本,转录本身亦有讹误。修正记在 tools/build-guaci.pyCORRECTIONS 表里,重新生成时自动复用,且待修正字符串一旦消失即报错,避免修正被静默丢弃。

每条修正都必须能从本数据内部证成,不依赖任何外部来源保持可访问:

改为 内部依据
地雷复 初九 复远 远复 紧随其后的象曰作「不远之复
地雷复 初九 袛为衣部,指内衣,此处无义

用什么代替外部互校

文本只有单一来源,所以校验放在仓库内部,不联网也能跑:

  • 爻位标签必须与卦码一致。 卦码说初爻为阳,标签就必须是「初九」而非「初六」——这把文本数据和计算逻辑互相钉死,错位或串行的爻辞会立刻暴露。上面复卦那处字序颠倒就是这么定位的。
  • 每条爻辞恰好配一条小象,另有一条大象
  • 每卦恰好一条彖曰
  • 首行卦名必须是本卦,正文不得夹带别卦标题
  • 不含校勘注、站点水印、Unicode 扩展区字符

test/guaci.test.ts

为什么要做这个

npm 上没有成熟的 TS 纳甲实现(现有几个包都还很稚嫩),而纯 TypeScript 的技术栈需要它。紫微斗数有 iztro 原生 TS 实现、农历有 tyme4ts,六爻纳甲是唯一没有上游可用的一环。

移植原则:先验证,后实现

一个算错的卦不会抛异常,也不会看起来有问题——它会输出一个自洽、完整、措辞确定的卦象,而它是错的。使用者无法察觉,作者也无法察觉。

所以这个移植不靠"仔细写"来保证正确,靠差分验证

  1. 以 Python najia 为基准(oracle)
  2. 穷举卦象输入空间(六爻的阴阳与动变,共 4^6 = 4096 种基本组合,再乘日期与性别维度)
  3. 逐字段比对,差异为零才算完成

六爻在这一点上比紫微有利:输入空间是有限且可穷举的,不像出生时间那样连续。理论上可以做到完全穷举,而不是抽样。

移植范围

Python 原库共 758 行,其中需要移植的是计算核心:

原文件 行数 是否移植 说明
najia.py 320 排盘主逻辑
utils.py 302 干支、纳甲、六亲等推导
const.py 96 常量表
__main__.py 35 CLI
data/standard.tpl 1.2K jinja2 文本模板,属表现层
data/guaci.pkl 57K 采集文本,已弃用;卦辞改从维基文库转录

安装

bun add @taoracle/najia      # 或 npm install @taoracle/najia

开发

bun install
bun run typecheck
bun test
bun run build      # tsc 输出 ESM + .d.ts 到 dist/

发布

版本号改好后打标签即可,.github/workflows/release.yml 会跑完整校验再发布:

# package.json 的 version 与标签必须一致,否则工作流会拒绝发布
git tag v0.1.0 && git push --tags

不需要任何 token。 该包在 npm 上配置了 trusted publishing:npm 直接校验 GitHub Actions 签发的 OIDC 令牌,只接受本仓库该工作流的发布请求,因此没有长期 凭据需要保管或轮换。发布会自动带上 provenance,在公共 registry 留下「此包由此 仓库此提交构建」的可验证记录。

本地发布仍然可行(需登录并输入 OTP),但拿不到 provenance:

npm login
npm publish        # prepublishOnly 会先跑 typecheck + test + build

许可

代码是 MIT,见 LICENSE,其中保留了原 Python 实现(bopo/najia)的版权声明。

卦辞数据的授权与代码不同:《周易》本文属公有领域,但维基文库的转录按站点条款为 CC BY-SA 4.0。若你需要闭源再分发这份数据,请先读 NOTICE.md——那里说明了争议点和 两条替换路径。

About

六爻纳甲排盘 — TypeScript implementation of Liu Yao / Na Jia hexagram divination

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages