@omne-harness/repo-toolchain 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +26 -2
  2. package/README_ZH.md +48 -2
  3. package/dist/core/toolchain-config.d.ts +1 -1
  4. package/dist/core/toolchain-config.d.ts.map +1 -1
  5. package/dist/core/toolchain-config.js +7 -2
  6. package/dist/core/toolchain-config.js.map +1 -1
  7. package/dist/declarations/api-classify.d.ts +94 -0
  8. package/dist/declarations/api-classify.d.ts.map +1 -0
  9. package/dist/declarations/api-classify.js +208 -0
  10. package/dist/declarations/api-classify.js.map +1 -0
  11. package/dist/declarations/api-cli.d.ts +3 -0
  12. package/dist/declarations/api-cli.d.ts.map +1 -0
  13. package/dist/declarations/api-cli.js +92 -0
  14. package/dist/declarations/api-cli.js.map +1 -0
  15. package/dist/declarations/api-compare.d.ts +86 -0
  16. package/dist/declarations/api-compare.d.ts.map +1 -0
  17. package/dist/declarations/api-compare.js +616 -0
  18. package/dist/declarations/api-compare.js.map +1 -0
  19. package/dist/declarations/api-format.d.ts +47 -0
  20. package/dist/declarations/api-format.d.ts.map +1 -0
  21. package/dist/declarations/api-format.js +154 -0
  22. package/dist/declarations/api-format.js.map +1 -0
  23. package/dist/declarations/api-normalize.d.ts +20 -0
  24. package/dist/declarations/api-normalize.d.ts.map +1 -0
  25. package/dist/declarations/api-normalize.js +76 -0
  26. package/dist/declarations/api-normalize.js.map +1 -0
  27. package/dist/declarations/api-snapshot.d.ts +49 -0
  28. package/dist/declarations/api-snapshot.d.ts.map +1 -0
  29. package/dist/declarations/api-snapshot.js +282 -0
  30. package/dist/declarations/api-snapshot.js.map +1 -0
  31. package/dist/declarations/api-whitelist.d.ts +25 -0
  32. package/dist/declarations/api-whitelist.d.ts.map +1 -0
  33. package/dist/declarations/api-whitelist.js +415 -0
  34. package/dist/declarations/api-whitelist.js.map +1 -0
  35. package/dist/declarations/compat.d.ts +11 -0
  36. package/dist/declarations/compat.d.ts.map +1 -1
  37. package/dist/declarations/compat.js +9 -4
  38. package/dist/declarations/compat.js.map +1 -1
  39. package/dist/declarations/contract-api.d.ts +128 -0
  40. package/dist/declarations/contract-api.d.ts.map +1 -0
  41. package/dist/declarations/contract-api.js +420 -0
  42. package/dist/declarations/contract-api.js.map +1 -0
  43. package/package.json +3 -2
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [中文说明](README_ZH.md)
4
4
 
5
- `@omne-harness/repo-toolchain` is this repository's checker package. It is published on npm. It provides the rule engine, commit attribution, the dependency graph, declaration compatibility, structure metrics, actual architecture extraction, the review page and the clean loop. The repository pins its exact version in the catalog of `pnpm-workspace.yaml`. The root checks and the three tool members run that version from npm, not the sources in this directory. After a change here, publish a new version first, then open a PR that changes the pin. See the [development guide](../../docs/development.md#仓库工具链的版本).
5
+ `@omne-harness/repo-toolchain` is this repository's checker package. It is published on npm. It provides the rule engine, commit attribution, the dependency graph, declaration compatibility, contract API snapshots, structure metrics, actual architecture extraction, the review page and the clean loop. The repository pins its exact version in the catalog of `pnpm-workspace.yaml`. The root checks and the three tool members run that version from npm, not the sources in this directory. After a change here, publish a new version first, then open a PR that changes the pin. See the [development guide](../../docs/development.md#仓库工具链的版本).
6
6
 
7
7
  Three unpublished tool members import this package through its subpaths. This package does not import them:
8
8
 
@@ -14,7 +14,7 @@ Three unpublished tool members import this package through its subpaths. This pa
14
14
 
15
15
  - The checked repository is `OMNE_SUBJECT_ROOT`. When it is not set, it is the Git root of the current directory.
16
16
  - The runner repository is `OMNE_RUNNER_ROOT`. When it is not set, it is the checked repository. Dependency rules (`.dependency-cruiser.cjs`, `tsconfig.base.json`) and configuration come only from the runner repository, so a checked tree cannot change them.
17
- - Configuration is in [`repo-toolchain.config.json`](../../repo-toolchain.config.json) at the repository root, in the sections `loop`, `metrics` and `acceptanceLock`. A missing file, a missing section or an unknown section is an error. No defaults apply.
17
+ - Configuration is in [`repo-toolchain.config.json`](../../repo-toolchain.config.json) at the repository root, in the sections `loop`, `metrics`, `acceptanceLock` and `contractApi`. Each command reads only its own section. A missing file, a missing section that a command reads, or an unknown section is an error. No defaults apply. Version 0.0.10 is the first version that accepts the `contractApi` section. Earlier versions reject it.
18
18
  - dependency-cruiser needs TypeScript to parse `.ts` files. With pnpm, add `typescript` to dependency-cruiser under `packageExtensions` in `pnpm-workspace.yaml`. If TypeScript is not found, the dependency check exits with an error. It does not pass with the `.ts` files left out.
19
19
 
20
20
  ## Default baseline
@@ -41,6 +41,7 @@ The commands (`bin`) point at `dist`. Run them from the installed package:
41
41
  | --- | --- | --- |
42
42
  | `omne-deps` | `src/deps/cli.ts` | Dependency rules, and cycles between members and groups |
43
43
  | `omne-declarations` | `src/declarations/cli.ts` | Reads member `dist` declarations with TypeScript 6 |
44
+ | `omne-contract-api` | `src/declarations/api-cli.ts` | Contract API snapshots: write, check, and a coarse class of the change against a base |
44
45
  | `omne-metrics` | `src/metrics/cli.ts` | Structure metrics and the review page |
45
46
  | `omne-loop-status` | `src/loop/cli.ts` | Clean loop status |
46
47
  | `omne-loop-health` | `src/loop/health-cli.ts` | Process health page |
@@ -51,6 +52,29 @@ The actual architecture extraction reads only the files of one revision. A packa
51
52
 
52
53
  `pnpm run check:design` checks current design sources, domain objects, and generated inputs. `pnpm run loop:health` reports trends, test timings, and Git history.
53
54
 
55
+ ## Contract API snapshots
56
+
57
+ `omne-contract-api` keeps one API snapshot file for each contract member. The contract members are the `contracts` entries of `docs/engineering/delivery-lines.json`. The behavior contract is in the [SPEC](src/declarations/SPEC.md).
58
+
59
+ - `--write` writes the snapshots from `dist`. It does not write a member that has no `dist`, incomplete declarations or compile diagnostics.
60
+ - `--check` compares each snapshot file with a snapshot that it makes from `dist` now, and reports each difference. With `--json`, it gives the SHA-256 of each snapshot file. The snapshot digest is this SHA-256 of the file bytes.
61
+ - `--diff <base>` compares the snapshot files at a base commit with the snapshot files in the working tree. It gives `none`, `additive` or `review` for each member and reports which side a change breaks. It reads only the snapshot files, not `dist`, so run `--check` first. The member list is the union of the contract lists at the base and now. A member without a snapshot at the base counts as `additive`. To decide whether a change is additive, give the milestone baseline commit.
62
+ - `--check` and `--diff` only report and exit 0. `--write` exits 1 when it cannot write a member. Errors exit 2.
63
+
64
+ A snapshot has two parts: the names that each entry exports, and every declaration file of the member's `dist`, normalized by the TypeScript printer. The declaration files keep their imports, exports and module augmentations, so a snapshot can be restored to declarations that compile.
65
+
66
+ The class is a whitelist gate. Differences fall into two buckets. Any difference in global scope makes the whole member `review` without running the checker: a `declare global` block or a `declare module` block for an external module that is added, removed or changed; a script file (a `.d.ts` without imports or exports) that is added, removed, changed or switched to a module; any triple-slash directive difference; an added or removed import or `export … from` edge (bound, type-only, empty and side-effect imports all count); an added, removed or renamed `export as namespace`. A consumer's program has one global scope, so the checker cannot prove that such a change leaves existing exports untouched. In module scope a change is `additive` only with two pieces of positive evidence. First, every difference is in the whitelist. The whitelist has two kinds of change: a new export that introduces a name the old side does not know (a declaration that merges with an existing one, such as a new overload, does not count; nor does a name that an entry already exports or that resolves to an existing symbol in the file's scope, such as a local `Error` shadowing the lib's), and a new optional property (property syntax) in a module-scope interface or type literal (a change inside an augmentation of the member's own module does not count). Second, the TypeScript checker proves assignability in two directions for each export that the change touches. New to old shows that existing readers still accept the new value. Old to new shows that existing writers (providers, doubles and implementers) still produce an accepted value. Everything else is `review`, and the report names the rule: a global-scope change, a change outside the whitelist, no comparison covers the export, a direction fails, the checker did not finish, too many instance combinations, or compile diagnostics. The tool uses `@typescript/typescript6`, which repo-toolchain already depends on. It adds no new dependency.
67
+
68
+ The tool does not use API Extractor, because API Extractor does not analyze ambient declarations. It drops every `declare module` and `declare global` augmentation, and the public surface of 8 of the 27 contract members contains such augmentations.
69
+
70
+ The `contractApi` configuration section has two keys. `members` is the path of the line table. `snapshot` is the snapshot path template. It ends with `.md` and contains `{member}` or `{package}`. Any other key, a missing key or a bad value is an error.
71
+
72
+ `review` means that a person must decide. It includes changes that break the writer, the reader or both. It also includes changes that the additive-change table allows but that are outside the whitelist. Examples are a new member of a union that the contract declares open, and a new default for a type parameter. `review` is not a level for the "契约变化" section of a PR. A person decides that level (none, additive or breaking) from the additive-change table in `docs/engineering/integration.md`.
73
+
74
+ The tool reads only the shape of the declarations. It does not read behavior, documentation or runtime validation. It reports which side breaks, but it does not decide whether that break is acceptable. The gate fails closed: when the evidence is not complete, the result is `review`. So `review` results are more frequent than with the checker alone. This is a deliberate trade-off for the report-only stage. A snapshot that matches `dist` shows only that the snapshot is current. It does not show that a change is additive. See the SPEC for the known limits, including the recursion heuristic that puts additive changes to types like `ToolBindings` into `review`.
75
+
76
+ A card that changes the public surface of a contract member runs `--write` in the same PR. When the snapshot format version changes, all snapshots must be made again. See the Chinese README section "契约 API 快照" for the operating rules.
77
+
54
78
  ## Stop-hook revision reads
55
79
 
56
80
  The Stop hook recalculates its baseline on each invocation. With a task context it uses `taskBase`. Without one it uses the nearest merge base among `primaryBranch` and the active tracks in `integration-policy.json`. See the Chinese README section "收工钩子" for the exact rules.
package/README_ZH.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](README.md)
4
4
 
5
- `@omne-harness/repo-toolchain` 是本仓库的检查器包,发布在 npm。它提供规则引擎、提交署名、依赖图、声明兼容、结构度量、实际架构抽取、审讯页与 clean loop。仓库在 `pnpm-workspace.yaml` 的 catalog 里钉它的精确版本,根目录的检查与三个工具成员都运行 npm 上的那个版本,不运行本目录的源码。改了本目录,要先发新版本,再开改钉子的 PR,见[开发指南](../../docs/development.md#仓库工具链的版本)。
5
+ `@omne-harness/repo-toolchain` 是本仓库的检查器包,发布在 npm。它提供规则引擎、提交署名、依赖图、声明兼容、契约 API 快照、结构度量、实际架构抽取、审讯页与 clean loop。仓库在 `pnpm-workspace.yaml` 的 catalog 里钉它的精确版本,根目录的检查与三个工具成员都运行 npm 上的那个版本,不运行本目录的源码。改了本目录,要先发新版本,再开改钉子的 PR,见[开发指南](../../docs/development.md#仓库工具链的版本)。
6
6
 
7
7
  三个不发布的工具成员经本包的子路径导入它,本包不引用它们:
8
8
 
@@ -14,7 +14,7 @@
14
14
 
15
15
  - 被检查的仓库取 `OMNE_SUBJECT_ROOT`,未设置时取当前目录所在 Git 仓库的根。
16
16
  - 运行检查器的仓库取 `OMNE_RUNNER_ROOT`,未设置时与被检查的仓库相同。依赖规则(`.dependency-cruiser.cjs`、`tsconfig.base.json`)与配置只从这个仓库读,被检查的检出改不了它们。
17
- - 配置在仓库根的 [`repo-toolchain.config.json`](../../repo-toolchain.config.json),分 `loop`、`metrics`、`acceptanceLock` 三节。缺文件、缺节或有认不出的节时报错,不使用默认值。
17
+ - 配置在仓库根的 [`repo-toolchain.config.json`](../../repo-toolchain.config.json),可有 `loop`、`metrics`、`acceptanceLock`、`contractApi` 四节,每个命令只读自己的那一节。缺文件、缺所读的节或有认不出的节时报错,不使用默认值。`contractApi` 一节从 0.0.10 起认得,更早的版本见到它会报错。
18
18
  - dependency-cruiser 需要 TypeScript 才能解析 `.ts`。用 pnpm 安装时,在 `pnpm-workspace.yaml` 的 `packageExtensions` 里给 dependency-cruiser 加上 `typescript`。找不到 TypeScript 时,依赖图检查报错退出,不会在漏掉 `.ts` 的情况下通过。
19
19
 
20
20
  ## 包内分层
@@ -31,6 +31,7 @@
31
31
  | --- | --- | --- |
32
32
  | `omne-deps` | `src/deps/cli.ts` | 依赖规则与成员、组之间的环 |
33
33
  | `omne-declarations` | `src/declarations/cli.ts` | 用 TypeScript 6 读成员 dist 里的声明 |
34
+ | `omne-contract-api` | `src/declarations/api-cli.ts` | 契约成员的 API 快照:写、核对与相对基线的粗分类 |
34
35
  | `omne-metrics` | `src/metrics/cli.ts` | 结构度量与审讯页 |
35
36
  | `omne-loop-status` | `src/loop/cli.ts` | 回路状态 |
36
37
  | `omne-loop-health` | `src/loop/health-cli.ts` | 流程体检页 |
@@ -605,3 +606,48 @@ pnpm run loop:health # --out 可改产物目录
605
606
  `pnpm run check` 在构建一步之后常驻跑它。
606
607
 
607
608
  本工具调用 `createProgram`、`createSourceFile` 等旧编程接口的模块都从 `@typescript/typescript6` 导入,行为与 TypeScript 6 相同。
609
+
610
+ ## 契约 API 快照
611
+
612
+ 契约成员是[线归属表](../../docs/engineering/delivery-lines.json)各线 `contracts` 列出的成员。线内的卡对它们只做可加改动,规则见[可加改动](../../docs/engineering/integration.md#可加改动)。本命令给每个契约成员一份入库的 API 快照,并把两份快照之间的差异粗分为三类:`none` 表示没有变化;`additive` 表示改动对已有的读方与写方都不破坏;`review` 表示其余一切改动,需要人判断。它只报告,不拦截。行为契约(输入、快照内容、确定性、分类规则、已知限制、退出码与配置校验)见 [SPEC](src/declarations/SPEC.md)。
613
+
614
+ ```sh
615
+ omne-contract-api --write # 从 dist 重写快照(先构建)
616
+ omne-contract-api --check # 拿 dist 现场生成的快照与快照文件比
617
+ omne-contract-api --diff <基线提交或分支> # 基线提交上的快照对工作树的快照,逐成员粗分类
618
+ ```
619
+
620
+ 三个动作都可加 `--json`,把结果按 JSON 写到标准输出。`--root <检出目录>` 指定被检查的检出。
621
+
622
+ 配置在 `repo-toolchain.config.json` 的 `contractApi` 一节,有两个键:
623
+
624
+ - `members`:线归属表的路径。
625
+ - `snapshot`:快照路径模板,以 `.md` 结尾,至少含 `{member}`(成员目录)或 `{package}`(不带 scope 的包名)之一。
626
+
627
+ 这一节有别的键、缺键或值不合条件时,命令报错退出。两个成员算出同一个快照路径时,命令也报错退出。
628
+
629
+ 读法与[声明兼容](#声明兼容)用同一套 TypeScript 6 选项,另建一个程序,按消费者视角读 dist。成员 dist 有编译诊断时,不生成它的快照。
630
+
631
+ 快照分两部分:每个入口导出的名字(写明声明在哪个文件或哪个外部包),以及成员 dist 里经打印器规范化的全部声明文件。声明文件保留导入、导出与模块扩充,所以快照能还原成一组能编译的声明。
632
+
633
+ 分类是白名单门:只有正证据成立才是 `additive`。差异分两桶。全局作用域的任何差异整份 `review`,不跑检查器:`declare global` 与对外部模块的 `declare module` 块的增删改、脚本文件的增删改或与模块之间切换、三斜线指令的变化、导入或 `export … from` 的模块边增删(带绑定、仅类型、空导入、无绑定导入都算)、`export as namespace` 的增删改。消费者程序里全局作用域只有一份,检查器证明不了「这处改动没有影响已有导出」。模块作用域的正证据有两条。第一,每一处差异都在白名单里,白名单只有两类:新增一个旧侧不知道的名字的导出(与已有同名声明合并的不算,例如新增重载;与入口已有的导出名或该文件作用域里已有符号重名的也不算,例如遮住 `export *` 导出的名字或 lib 的 `Error`),以及在模块作用域的接口或类型字面量里新增可选属性(属性写法;对本成员模块的扩充块内的改动不算)。第二,TypeScript 检查器对涉及的每个导出证明两个方向都可赋值:新 → 旧成立表示读方不破坏,旧 → 新成立表示写方(提供者、替身、实现者)不破坏。其余一律 `review`,报告写明命中哪一条:全局作用域变了、白名单外改动、没有比较覆盖、方向不成立、检查器未完成、实例组合超限、编译诊断。它用的是 repo-toolchain 已有的 `@typescript/typescript6`,不加新依赖。规则、白名单与归一化见 [SPEC](src/declarations/SPEC.md#分类)。
634
+
635
+ 不用 API Extractor 的理由:它不分析 ambient 声明,`declare module` 与 `declare global` 的扩充在它的报告里全部缺失,而 27 个契约成员里有 8 个的公开面含这类扩充。探路与复核的结论记在卡 #645 的评论里。
636
+
637
+ 操作要求:
638
+
639
+ - 改了契约成员公开面的卡,在同一个 PR 里构建并运行 `--write`,把快照的变化一起提交。`--check` 报不一致时,先判断改动是否有意。
640
+ - 本工具改了快照格式(格式版本变了)时,全部快照要重新生成。
641
+ - 谁写首份快照、格式变化时谁重新生成,规则见[里程碑内的规则](../../docs/engineering/integration.md#里程碑内的规则)。
642
+
643
+ `--diff` 的前提:
644
+
645
+ - 它只比快照文件,不读 dist。先用 `--check` 确认工作树的快照与 dist 一致,或先运行 `--write`。
646
+ - 成员取基线与当前两份线归属表的并集,每侧的快照路径按那一侧的包名算。基线上没有快照的成员整份算 `additive`。
647
+ - 判断改动是否可加时,传里程碑登记的基线提交。
648
+
649
+ 快照摘要是快照文件字节的 SHA-256。`--check --json` 对每个有快照文件的成员给出 `sha256`。
650
+
651
+ `review` 不是 PR「契约变化」一节的级别。它包括两方都破坏的改动、只破坏一方的改动,也包括按「可加改动」表不破坏、但不在白名单里的改动(例如契约声明开放的联合加成员、给类型参数加默认值)。PR 的 none、additive 或 breaking 由人按「可加改动」表判定。
652
+
653
+ 它**不能声称**的:它报出读方与写方两个方向,但不判定哪个方向的破坏可以接受。白名单门失败关闭,拿不准时给 `review`,所以 `review` 会比只用检查器时多。这是 P1 只报告阶段的有意取舍。它只看声明的形状,不看行为、文档或运行时校验。转导出的别的包的声明变化归那个包的快照。快照与 dist 一致只说明快照是最新的,不说明改动可加。其余限制(例如 `ToolBindings` 一类的递归启发式误报)见 [SPEC](src/declarations/SPEC.md#已知限制)。
@@ -1,5 +1,5 @@
1
1
  export declare const TOOLCHAIN_CONFIG_FILE = "repo-toolchain.config.json";
2
- export declare const TOOLCHAIN_CONFIG_SECTIONS: readonly ['loop', 'metrics', 'acceptanceLock'];
2
+ export declare const TOOLCHAIN_CONFIG_SECTIONS: readonly ['loop', 'metrics', 'acceptanceLock', 'contractApi'];
3
3
  export type ToolchainConfigSection = (typeof TOOLCHAIN_CONFIG_SECTIONS)[number];
4
4
  export declare function toolchainConfigPath(root?: string): string;
5
5
  /** 读一节原样的 JSON;校验各节内容归各自的读取函数。 */
@@ -1 +1 @@
1
- {"version":3,"file":"toolchain-config.d.ts","sourceRoot":"","sources":["../../src/core/toolchain-config.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,qBAAqB,+BAA+B,CAAA;AACjE,eAAO,MAAM,yBAAyB,YAAI,MAAM,EAAE,SAAS,EAAE,gBAAgB,CAAU,CAAA;AACvF,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE/E,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,MAAqB,GAAG,MAAM,CAEvE;AAED,kCAAkC;AAClC,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,sBAAsB,EAC/B,IAAI,GAAE,MAA8B,GACnC,OAAO,CAUT"}
1
+ {"version":3,"file":"toolchain-config.d.ts","sourceRoot":"","sources":["../../src/core/toolchain-config.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,qBAAqB,+BAA+B,CAAA;AACjE,eAAO,MAAM,yBAAyB,YACpC,MAAM,EACN,SAAS,EACT,gBAAgB,EAChB,aAAa,CACL,CAAA;AACV,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE/E,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,MAAqB,GAAG,MAAM,CAEvE;AAED,kCAAkC;AAClC,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,sBAAsB,EAC/B,IAAI,GAAE,MAA8B,GACnC,OAAO,CAUT"}
@@ -1,10 +1,15 @@
1
- // 仓库专用的配置只在仓库根的 `repo-toolchain.config.json` 里定一次,按节分给回路、度量与验收锁。
1
+ // 仓库专用的配置只在仓库根的 `repo-toolchain.config.json` 里定一次,按节分给回路、度量、验收锁与契约 API 快照。
2
2
  // 文件从运行检查器的仓库读(见 subject.ts);缺文件、缺节或不是 JSON 对象都报错,不悄悄用默认。
3
3
  import { readFileSync } from 'node:fs';
4
4
  import { join } from 'node:path';
5
5
  import { runnerRoot } from './subject.js';
6
6
  export const TOOLCHAIN_CONFIG_FILE = 'repo-toolchain.config.json';
7
- export const TOOLCHAIN_CONFIG_SECTIONS = ['loop', 'metrics', 'acceptanceLock'];
7
+ export const TOOLCHAIN_CONFIG_SECTIONS = [
8
+ 'loop',
9
+ 'metrics',
10
+ 'acceptanceLock',
11
+ 'contractApi',
12
+ ];
8
13
  export function toolchainConfigPath(root = runnerRoot()) {
9
14
  return join(root, TOOLCHAIN_CONFIG_FILE);
10
15
  }
@@ -1 +1 @@
1
- {"version":3,"file":"toolchain-config.js","sourceRoot":"","sources":["../../src/core/toolchain-config.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,0DAA0D;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,MAAM,CAAC,MAAM,qBAAqB,GAAG,4BAA4B,CAAA;AACjE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,gBAAgB,CAAU,CAAA;AAGvF,MAAM,UAAU,mBAAmB,CAAC,IAAI,GAAW,UAAU,EAAE;IAC7D,OAAO,IAAI,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAA;AAC1C,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,oBAAoB,CAClC,OAA+B,EAC/B,IAAI,GAAW,mBAAmB,EAAE;IAEpC,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;IAC9D,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QACxE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,aAAa,CAAC,CAAA;IACvC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CACtC,GAAG,CAAC,EAAE,CAAC,CAAE,yBAA+C,CAAC,QAAQ,CAAC,GAAG,CAAC,CACvE,CAAA;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,YAAY,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC3E,IAAI,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,OAAO,OAAO,KAAK,CAAC,CAAA;IACrE,OAAQ,MAAkC,CAAC,OAAO,CAAC,CAAA;AACrD,CAAC"}
1
+ {"version":3,"file":"toolchain-config.js","sourceRoot":"","sources":["../../src/core/toolchain-config.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,0DAA0D;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC,MAAM,CAAC,MAAM,qBAAqB,GAAG,4BAA4B,CAAA;AACjE,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,MAAM;IACN,SAAS;IACT,gBAAgB;IAChB,aAAa;CACL,CAAA;AAGV,MAAM,UAAU,mBAAmB,CAAC,IAAI,GAAW,UAAU,EAAE;IAC7D,OAAO,IAAI,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAA;AAC1C,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,oBAAoB,CAClC,OAA+B,EAC/B,IAAI,GAAW,mBAAmB,EAAE;IAEpC,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;IAC9D,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QACxE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,aAAa,CAAC,CAAA;IACvC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,CACtC,GAAG,CAAC,EAAE,CAAC,CAAE,yBAA+C,CAAC,QAAQ,CAAC,GAAG,CAAC,CACvE,CAAA;IACD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,YAAY,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;IAC3E,IAAI,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,OAAO,OAAO,KAAK,CAAC,CAAA;IACrE,OAAQ,MAAkC,CAAC,OAAO,CAAC,CAAA;AACrD,CAAC"}
@@ -0,0 +1,94 @@
1
+ import { type CheckerComparison } from './api-compare.ts';
2
+ import { type ApiSnapshot } from './api-format.ts';
3
+ import { type WhitelistResult } from './api-whitelist.ts';
4
+ export type ApiChange = 'none' | 'additive' | 'review';
5
+ export declare function strongest(changes: readonly ApiChange[]): ApiChange;
6
+ /** 差异落在哪里:整份快照、一个入口、入口里的一个导出,或某个声明文件里的一条语句。 */
7
+ export type DifferenceTarget = {
8
+ readonly scope: 'snapshot';
9
+ } | {
10
+ readonly scope: 'entry';
11
+ readonly entry: string;
12
+ } | {
13
+ readonly scope: 'export';
14
+ readonly entry: string;
15
+ readonly name: string;
16
+ } | {
17
+ readonly scope: 'declaration';
18
+ readonly path: string;
19
+ readonly statement: string;
20
+ };
21
+ /**
22
+ * added/removed/changed:增删改;marked:导出标注变了(改名、仅类型、声明来源);
23
+ * renamed:包名变了;missing:两边都没有快照;unresolved:还原的声明有编译诊断,检查器的结论不可信。
24
+ */
25
+ export type DifferenceKind = 'added' | 'removed' | 'changed' | 'marked' | 'renamed' | 'missing' | 'unresolved';
26
+ /**
27
+ * review 的依据。global-scope-change:全局作用域有差异(扩充块、脚本文件、三斜线指令、导入导出的模块边),
28
+ * 整份 review 且不跑检查器;outside-whitelist:改动不在白名单里(含删除、标注变化、包名变化、两侧都没有快照);
29
+ * uncovered:涉及的导出没有任何可赋值比较;direction:某个方向不成立;incomplete:检查器没有给出结论;
30
+ * truncated:类型参数实例组合超过上限;diagnostics:还原的声明有编译诊断。
31
+ */
32
+ export type ReviewReason = {
33
+ readonly kind: 'global-scope-change';
34
+ readonly why: string;
35
+ } | {
36
+ readonly kind: 'outside-whitelist';
37
+ readonly why: string;
38
+ } | {
39
+ readonly kind: 'uncovered';
40
+ } | {
41
+ readonly kind: 'direction';
42
+ readonly readers: boolean;
43
+ readonly writers: boolean;
44
+ readonly details: readonly string[];
45
+ } | {
46
+ readonly kind: 'incomplete';
47
+ readonly details: readonly string[];
48
+ } | {
49
+ readonly kind: 'truncated';
50
+ readonly limit: number;
51
+ readonly total: number;
52
+ } | {
53
+ readonly kind: 'diagnostics';
54
+ readonly details: readonly string[];
55
+ };
56
+ export type Difference = {
57
+ readonly target: DifferenceTarget;
58
+ readonly kind: DifferenceKind;
59
+ readonly change: 'additive';
60
+ /** 检查器比较过并证明两个方向都成立时为 true。 */
61
+ readonly proved?: true;
62
+ } | {
63
+ readonly target: DifferenceTarget;
64
+ readonly kind: DifferenceKind;
65
+ readonly change: 'review';
66
+ readonly reasons: readonly [ReviewReason, ...ReviewReason[]];
67
+ };
68
+ export interface SnapshotDifference {
69
+ readonly change: ApiChange;
70
+ readonly differences: readonly Difference[];
71
+ }
72
+ /** 检查器还原声明要用的位置:外部包从检出根解析。 */
73
+ export interface ClassifyContext {
74
+ readonly root: string;
75
+ readonly directory: string;
76
+ }
77
+ /** 比较两份快照;`undefined` 表示那一侧没有快照。两侧都没有是 review:没有可比的东西,不能当作没变。 */
78
+ export declare function classifySnapshots(before: ApiSnapshot | undefined, after: ApiSnapshot | undefined, context: ClassifyContext): SnapshotDifference;
79
+ export interface JudgeInput {
80
+ /** 结构上的增删与标注变化,已经按规则分好类。 */
81
+ readonly structure: readonly Difference[];
82
+ readonly whitelist: WhitelistResult;
83
+ /** 检查器的结论;全局作用域有差异时没有跑,是 undefined。 */
84
+ readonly comparison: CheckerComparison | undefined;
85
+ /** 规范化后的声明文本有变化(参数改名、注释与布局之外)。 */
86
+ readonly textChanged: boolean;
87
+ }
88
+ /**
89
+ * 白名单门的判定(纯函数):结构差异照收;全局作用域的差异与白名单外的语句改动各记一项 review;
90
+ * 每个检查器结论按问题种类记 review,涉及却没有比较覆盖的也记 review;
91
+ * 两侧文本变了而没有任何差异落到导出上时,整份记一项 additive。整份取最强。
92
+ */
93
+ export declare function judge(input: JudgeInput): SnapshotDifference;
94
+ //# sourceMappingURL=api-classify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-classify.d.ts","sourceRoot":"","sources":["../../src/declarations/api-classify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,208 @@
1
+ // 契约 API 快照的差异粗分类:none、additive、review。白名单门:只有正证据成立才是 additive。
2
+ // none:两侧规范化文本相同。
3
+ // review(全局作用域):扩充块、脚本文件、三斜线指令、导入导出的模块边或 `export as namespace` 有任何差异,
4
+ // 整份 review,不跑检查器。消费者程序里全局作用域只有一份,检查器证明不了「这处改动没有影响已有导出」。
5
+ // additive:每一处差异都在模块作用域的白名单里(新增一个旧侧不知道的名字:不是入口已有的导出名,也不能在
6
+ // 该文件作用域里解析到已有符号;模块作用域的接口或类型字面量里新增可选属性),
7
+ // 并且检查器对涉及的每个导出用同一种写法证明两个方向都可赋值。
8
+ // review:其余一切。附注写明命中哪一条:全局作用域变了、白名单外改动、涉及的导出没有被比较覆盖、
9
+ // 方向不成立、检查器未完成、实例组合超限、编译诊断。
10
+ // 白名单的判断在 api-whitelist.ts(名字的作用域解析借旧侧程序),检查器证明在 api-compare.ts,
11
+ // 这里把两者合成结论(judge 是纯函数)。
12
+ // 这是粗分类:review 的意思是「需要人判断」,不是 PR「契约变化」的级别。拿不准一律 review。
13
+ import { compareSnapshots, oldSideScope, } from './api-compare.js';
14
+ import { byCodeUnit, renderSnapshot, } from './api-format.js';
15
+ import { normalizedFiles } from './api-normalize.js';
16
+ import { whitelistDifferences, } from './api-whitelist.js';
17
+ const RANK = { none: 0, additive: 1, review: 2 };
18
+ export function strongest(changes) {
19
+ return changes.reduce((a, b) => (RANK[b] > RANK[a] ? b : a), 'none');
20
+ }
21
+ function result(differences) {
22
+ return { change: strongest(differences.map(item => item.change)), differences };
23
+ }
24
+ const WHOLE = { scope: 'snapshot' };
25
+ const outside = (why) => ({ kind: 'outside-whitelist', why });
26
+ function review(target, kind, reasons) {
27
+ return { target, kind, change: 'review', reasons };
28
+ }
29
+ /** 比较两份快照;`undefined` 表示那一侧没有快照。两侧都没有是 review:没有可比的东西,不能当作没变。 */
30
+ export function classifySnapshots(before, after, context) {
31
+ if (before === undefined && after === undefined)
32
+ return result([review(WHOLE, 'missing', [outside('两侧都没有快照')])]);
33
+ if (before === undefined)
34
+ return result([{ target: WHOLE, kind: 'added', change: 'additive' }]);
35
+ if (after === undefined)
36
+ return result([review(WHOLE, 'removed', [outside('整份快照删除了')])]);
37
+ const renamed = before.packageName === after.packageName
38
+ ? []
39
+ : [review(WHOLE, 'renamed', [outside('包名变了')])];
40
+ if (renderSnapshot(before) === renderSnapshot({ ...after, packageName: before.packageName }))
41
+ return result(renamed);
42
+ const structure = compareEntries(before, after);
43
+ const whitelist = whitelistDifferences(before.files, after.files, {
44
+ exported: exportedNames(before),
45
+ resolve: oldSideScope({
46
+ root: context.root,
47
+ directory: context.directory,
48
+ files: before.files,
49
+ }),
50
+ });
51
+ const judging = {
52
+ structure: [...renamed, ...structure.differences],
53
+ whitelist,
54
+ textChanged: changedText(before, after),
55
+ };
56
+ // 全局作用域有差异:整份 review,检查器证明不了别的导出不受影响,不跑。
57
+ if (whitelist.global.length > 0)
58
+ return judge({ ...judging, comparison: undefined });
59
+ const comparison = compareSnapshots({
60
+ root: context.root,
61
+ directory: context.directory,
62
+ before,
63
+ after,
64
+ exports: structure.common,
65
+ });
66
+ return judge({ ...judging, comparison });
67
+ }
68
+ /**
69
+ * 白名单门的判定(纯函数):结构差异照收;全局作用域的差异与白名单外的语句改动各记一项 review;
70
+ * 每个检查器结论按问题种类记 review,涉及却没有比较覆盖的也记 review;
71
+ * 两侧文本变了而没有任何差异落到导出上时,整份记一项 additive。整份取最强。
72
+ */
73
+ export function judge(input) {
74
+ const differences = [...input.structure];
75
+ const declaration = (item) => ({ scope: 'declaration', path: item.path, statement: item.statement });
76
+ for (const item of input.whitelist.global)
77
+ differences.push(review(declaration(item), item.change, [{ kind: 'global-scope-change', why: item.why }]));
78
+ for (const item of input.whitelist.outside)
79
+ differences.push(review(declaration(item), item.change, [outside(item.why)]));
80
+ if (input.comparison !== undefined) {
81
+ for (const verdict of input.comparison.verdicts)
82
+ differences.push(...verdictDifference(verdict, input.whitelist.changed));
83
+ if (input.comparison.problems.length > 0)
84
+ differences.push(review(WHOLE, 'unresolved', [{ kind: 'diagnostics', details: input.comparison.problems }]));
85
+ }
86
+ if (strongest(differences.map(item => item.change)) === 'none' && input.textChanged)
87
+ differences.push({ target: WHOLE, kind: 'changed', change: 'additive' });
88
+ return result(differences);
89
+ }
90
+ /** 旧侧每个入口导出的名字(`export *` 与改名导出已经展开)到它所在的入口,给白名单 (a) 判断新名字。 */
91
+ function exportedNames(snapshot) {
92
+ const names = new Map();
93
+ for (const entry of snapshot.entries)
94
+ for (const item of entry.exports) {
95
+ const entries = names.get(item.name) ?? [];
96
+ entries.push(entry.subpath);
97
+ names.set(item.name, entries);
98
+ }
99
+ return names;
100
+ }
101
+ /** 参数改名、注释与布局之外的声明变化。 */
102
+ function changedText(before, after) {
103
+ const a = normalizedFiles(before.files);
104
+ const b = normalizedFiles(after.files);
105
+ return a.size !== b.size || [...a].some(([path, text]) => b.get(path) !== text);
106
+ }
107
+ function compareEntries(before, after) {
108
+ const structure = { differences: [], common: [] };
109
+ const old = new Map(before.entries.map(entry => [entry.subpath, entry]));
110
+ const next = new Map(after.entries.map(entry => [entry.subpath, entry]));
111
+ for (const subpath of [...new Set([...old.keys(), ...next.keys()])].sort(byCodeUnit)) {
112
+ const a = old.get(subpath);
113
+ const b = next.get(subpath);
114
+ const target = { scope: 'entry', entry: subpath };
115
+ if (a !== undefined && b !== undefined)
116
+ compareExports(structure, a, b);
117
+ else if (a !== undefined)
118
+ structure.differences.push(review(target, 'removed', [outside('入口删除了')]));
119
+ else
120
+ structure.differences.push({ target, kind: 'added', change: 'additive' });
121
+ }
122
+ return structure;
123
+ }
124
+ function compareExports(structure, before, after) {
125
+ const old = new Map(before.exports.map(item => [item.name, item]));
126
+ const next = new Map(after.exports.map(item => [item.name, item]));
127
+ for (const name of [...new Set([...old.keys(), ...next.keys()])].sort(byCodeUnit)) {
128
+ const a = old.get(name);
129
+ const b = next.get(name);
130
+ const target = { scope: 'export', entry: after.subpath, name };
131
+ if (a === undefined)
132
+ structure.differences.push({ target, kind: 'added', change: 'additive' });
133
+ else if (b === undefined)
134
+ structure.differences.push(review(target, 'removed', [outside('导出删除了')]));
135
+ else if (!sameMarks(a, b))
136
+ structure.differences.push(review(target, 'marked', [outside('导出的标注变了(改名、仅类型或声明来源)')]));
137
+ else if (b.origin.kind !== 'package')
138
+ structure.common.push({ entry: after.subpath, name });
139
+ }
140
+ }
141
+ /** 标注相同:改名、仅类型一致,来源同为本成员(文件可以挪动)或同一个外部包。 */
142
+ function sameMarks(a, b) {
143
+ if (a.typeOnly !== b.typeOnly || a.renamedFrom !== b.renamedFrom)
144
+ return false;
145
+ return sameOrigin(a.origin, b.origin);
146
+ }
147
+ function sameOrigin(a, b) {
148
+ if (a.kind === 'package' && b.kind === 'package')
149
+ return a.name === b.name;
150
+ return a.kind === b.kind;
151
+ }
152
+ /** 检查器的一条结论变成差异:有任何 review 依据就是 review,否则文本变了才记一项 additive。 */
153
+ function verdictDifference(verdict, changed) {
154
+ const reasons = reviewReasons(verdict, changed);
155
+ const target = {
156
+ scope: 'export',
157
+ entry: verdict.target.entry,
158
+ name: verdict.target.name,
159
+ };
160
+ const [first, ...rest] = reasons;
161
+ if (first !== undefined)
162
+ return [review(target, 'changed', [first, ...rest])];
163
+ return verdict.same ? [] : [{ target, kind: 'changed', change: 'additive', proved: true }];
164
+ }
165
+ function reviewReasons(verdict, changed) {
166
+ const reasons = [];
167
+ const grouped = groupProblems(verdict.problems);
168
+ if (grouped.direction.length > 0)
169
+ reasons.push({
170
+ kind: 'direction',
171
+ readers: verdict.readers,
172
+ writers: verdict.writers,
173
+ details: grouped.direction,
174
+ });
175
+ if (grouped.incomplete.length > 0)
176
+ reasons.push({ kind: 'incomplete', details: grouped.incomplete });
177
+ reasons.push(...grouped.truncated);
178
+ const involved = !verdict.same || verdict.reaches.some(id => changed.has(id));
179
+ if (involved && verdict.comparisons === 0 && reasons.length === 0)
180
+ reasons.push({ kind: 'uncovered' });
181
+ return reasons;
182
+ }
183
+ function groupProblems(problems) {
184
+ const grouped = {
185
+ direction: [],
186
+ incomplete: [],
187
+ truncated: [],
188
+ };
189
+ for (const problem of problems) {
190
+ switch (problem.kind) {
191
+ case 'direction':
192
+ grouped.direction.push(`${problem.label}:${problem.why}`);
193
+ break;
194
+ case 'incomplete':
195
+ grouped.incomplete.push(problem.why);
196
+ break;
197
+ case 'truncated':
198
+ grouped.truncated.push({ kind: 'truncated', limit: problem.limit, total: problem.total });
199
+ break;
200
+ default: {
201
+ const _exhaustive = problem;
202
+ return _exhaustive;
203
+ }
204
+ }
205
+ }
206
+ return grouped;
207
+ }
208
+ //# sourceMappingURL=api-classify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-classify.js","sourceRoot":"","sources":["../../src/declarations/api-classify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=api-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-cli.d.ts","sourceRoot":"","sources":["../../src/declarations/api-cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ // 契约 API 快照入口:`--write` 写快照,`--check` 核对快照与 dist,`--diff <基线>` 对比基线提交上的快照并粗分类。
3
+ // `--check` 与 `--diff` 只报告,有发现也退出 0;`--write` 有成员没写成时退出 1;用法、配置、基线或工具出错退出 2。
4
+ // 读 dist:先构建。`--json` 把结果按 JSON 写到标准输出。
5
+ import { resolve } from 'node:path';
6
+ import { subjectRoot } from '../core/subject.js';
7
+ import { checkSnapshots, diffSnapshots, readContractApiConfig, renderCheck, renderDiff, renderWrite, writeSnapshots, } from './contract-api.js';
8
+ const USAGE = '用法:--write | --check | --diff <基线提交或分支>,可加 [--json] [--root <检出目录>]';
9
+ function valueAfter(argv, index, flag) {
10
+ const value = argv[index + 1];
11
+ if (value === undefined || value === '' || value.startsWith('--'))
12
+ throw new Error(`${flag} 要一个值\n${USAGE}`);
13
+ return value;
14
+ }
15
+ function choose(parsed, action) {
16
+ if (parsed.action !== undefined)
17
+ throw new Error(`--write、--check、--diff 只能给一个\n${USAGE}`);
18
+ parsed.action = action;
19
+ }
20
+ /** 读一个参数,返回它占了几个位置。 */
21
+ function readFlag(argv, index, parsed) {
22
+ const flag = argv[index];
23
+ switch (flag) {
24
+ case '--write':
25
+ case '--check':
26
+ choose(parsed, { kind: flag === '--write' ? 'write' : 'check' });
27
+ return 1;
28
+ case '--json':
29
+ parsed.json = true;
30
+ return 1;
31
+ case '--diff':
32
+ choose(parsed, { kind: 'diff', base: valueAfter(argv, index, flag) });
33
+ return 2;
34
+ case '--root':
35
+ parsed.root = resolve(valueAfter(argv, index, flag));
36
+ return 2;
37
+ default:
38
+ throw new Error(`认不出的参数 ${flag ?? ''}\n${USAGE}`);
39
+ }
40
+ }
41
+ function parseArguments(argv) {
42
+ const parsed = { json: false, root: subjectRoot() };
43
+ for (let index = 0; index < argv.length;)
44
+ index += readFlag(argv, index, parsed);
45
+ if (parsed.action === undefined)
46
+ throw new Error(USAGE);
47
+ return { action: parsed.action, json: parsed.json, root: parsed.root };
48
+ }
49
+ function main(argv) {
50
+ const { action, json, root } = parseArguments(argv);
51
+ const config = readContractApiConfig();
52
+ const print = (value, lines) => {
53
+ if (json)
54
+ console.log(JSON.stringify(value, null, 2));
55
+ else
56
+ for (const line of lines)
57
+ console.log(line);
58
+ };
59
+ switch (action.kind) {
60
+ case 'write': {
61
+ const run = writeSnapshots(root, config);
62
+ print(run, renderWrite(run));
63
+ return run.members.some(item => item.status === 'unbuilt' || item.status === 'invalid')
64
+ ? 1
65
+ : 0;
66
+ }
67
+ case 'check': {
68
+ const run = checkSnapshots(root, config);
69
+ print(run, renderCheck(run));
70
+ return 0;
71
+ }
72
+ case 'diff': {
73
+ const run = diffSnapshots(root, config, action.base);
74
+ print(run, renderDiff(run));
75
+ return 0;
76
+ }
77
+ default: {
78
+ const _exhaustive = action;
79
+ return _exhaustive;
80
+ }
81
+ }
82
+ }
83
+ try {
84
+ process.exitCode = main(process.argv.slice(2));
85
+ }
86
+ catch (error) {
87
+ console.error(error instanceof Error ? error.message : String(error));
88
+ if (error instanceof Error && error.cause instanceof Error)
89
+ console.error(error.cause.message);
90
+ process.exitCode = 2;
91
+ }
92
+ //# sourceMappingURL=api-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-cli.js","sourceRoot":"","sources":["../../src/declarations/api-cli.ts"],"names":[],"mappings":"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"}