aontu 0.61.0 → 0.63.0

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 (371) hide show
  1. package/README.md +4 -4
  2. package/dist/agentsmd.d.ts +1 -0
  3. package/dist/agentsmd.js +7 -28
  4. package/dist/agentsmd.js.map +1 -1
  5. package/dist/alias.js.map +1 -1
  6. package/dist/allow.d.ts +23 -0
  7. package/dist/allow.js +138 -0
  8. package/dist/allow.js.map +1 -0
  9. package/dist/aontu.d.ts +4 -2
  10. package/dist/aontu.js +4 -80
  11. package/dist/aontu.js.map +1 -1
  12. package/dist/aontumodel.d.ts +4 -0
  13. package/dist/aontumodel.js +33 -0
  14. package/dist/aontumodel.js.map +1 -0
  15. package/dist/cli.d.ts +10 -1
  16. package/dist/cli.js +877 -479
  17. package/dist/cli.js.map +1 -1
  18. package/dist/ctx.js +0 -48
  19. package/dist/ctx.js.map +1 -1
  20. package/dist/diff.js +0 -32
  21. package/dist/diff.js.map +1 -1
  22. package/dist/err.js +0 -40
  23. package/dist/err.js.map +1 -1
  24. package/dist/escape.js +0 -45
  25. package/dist/escape.js.map +1 -1
  26. package/dist/exactjson.d.ts +0 -35
  27. package/dist/exactjson.js +0 -131
  28. package/dist/exactjson.js.map +1 -1
  29. package/dist/format.js +55 -189
  30. package/dist/format.js.map +1 -1
  31. package/dist/grammar.d.ts +9 -0
  32. package/dist/grammar.js +54 -0
  33. package/dist/grammar.js.map +1 -0
  34. package/dist/graph.js +0 -26
  35. package/dist/graph.js.map +1 -1
  36. package/dist/hcanon.js +0 -82
  37. package/dist/hcanon.js.map +1 -1
  38. package/dist/helpdoc.d.ts +16 -0
  39. package/dist/helpdoc.js +59 -0
  40. package/dist/helpdoc.js.map +1 -0
  41. package/dist/hints.d.ts +0 -6
  42. package/dist/hints.js +59 -47
  43. package/dist/hints.js.map +1 -1
  44. package/dist/jsonschema.js +0 -114
  45. package/dist/jsonschema.js.map +1 -1
  46. package/dist/keyorder.d.ts +0 -7
  47. package/dist/keyorder.js +0 -41
  48. package/dist/keyorder.js.map +1 -1
  49. package/dist/lang.js +32 -877
  50. package/dist/lang.js.map +1 -1
  51. package/dist/lower.d.ts +3 -0
  52. package/dist/lower.js +14 -61
  53. package/dist/lower.js.map +1 -1
  54. package/dist/lsp-server.js +0 -16
  55. package/dist/lsp-server.js.map +1 -1
  56. package/dist/lsp.d.ts +1 -1
  57. package/dist/lsp.js +12 -159
  58. package/dist/lsp.js.map +1 -1
  59. package/dist/mcp-server.js +0 -26
  60. package/dist/mcp-server.js.map +1 -1
  61. package/dist/mcp.js +0 -113
  62. package/dist/mcp.js.map +1 -1
  63. package/dist/mod-tool.js +0 -130
  64. package/dist/mod-tool.js.map +1 -1
  65. package/dist/mod.js +0 -162
  66. package/dist/mod.js.map +1 -1
  67. package/dist/patch.js +0 -217
  68. package/dist/patch.js.map +1 -1
  69. package/dist/provenance.js +0 -140
  70. package/dist/provenance.js.map +1 -1
  71. package/dist/query.js +0 -75
  72. package/dist/query.js.map +1 -1
  73. package/dist/reach.js +0 -43
  74. package/dist/reach.js.map +1 -1
  75. package/dist/relation.d.ts +2 -0
  76. package/dist/relation.js +3 -58
  77. package/dist/relation.js.map +1 -1
  78. package/dist/render.js +33 -143
  79. package/dist/render.js.map +1 -1
  80. package/dist/report-sarif.d.ts +0 -11
  81. package/dist/report-sarif.js +0 -28
  82. package/dist/report-sarif.js.map +1 -1
  83. package/dist/sig.js +0 -35
  84. package/dist/sig.js.map +1 -1
  85. package/dist/sigdecl.js +1 -1
  86. package/dist/sigdecl.js.map +1 -1
  87. package/dist/siggate.js +0 -4
  88. package/dist/siggate.js.map +1 -1
  89. package/dist/site.js +3 -29
  90. package/dist/site.js.map +1 -1
  91. package/dist/subsume.d.ts +0 -10
  92. package/dist/subsume.js +0 -137
  93. package/dist/subsume.js.map +1 -1
  94. package/dist/template.d.ts +2 -1
  95. package/dist/template.js +58 -138
  96. package/dist/template.js.map +1 -1
  97. package/dist/trim.js +0 -41
  98. package/dist/trim.js.map +1 -1
  99. package/dist/tsconfig.tsbuildinfo +1 -1
  100. package/dist/type.js.map +1 -1
  101. package/dist/unify.js +12 -242
  102. package/dist/unify.js.map +1 -1
  103. package/dist/utility.js +0 -22
  104. package/dist/utility.js.map +1 -1
  105. package/dist/val/AbnfFuncVal.d.ts +18 -0
  106. package/dist/val/AbnfFuncVal.js +132 -0
  107. package/dist/val/AbnfFuncVal.js.map +1 -0
  108. package/dist/val/AbsentVal.d.ts +11 -0
  109. package/dist/val/AbsentVal.js +30 -0
  110. package/dist/val/AbsentVal.js.map +1 -0
  111. package/dist/val/AggFuncVal.d.ts +10 -1
  112. package/dist/val/AggFuncVal.js +104 -116
  113. package/dist/val/AggFuncVal.js.map +1 -1
  114. package/dist/val/ArithFuncVal.js +0 -12
  115. package/dist/val/ArithFuncVal.js.map +1 -1
  116. package/dist/val/BagVal.js +1 -78
  117. package/dist/val/BagVal.js.map +1 -1
  118. package/dist/val/BigDecimalVal.js +0 -16
  119. package/dist/val/BigDecimalVal.js.map +1 -1
  120. package/dist/val/BigIntegerVal.js +0 -16
  121. package/dist/val/BigIntegerVal.js.map +1 -1
  122. package/dist/val/CloseFuncVal.js +0 -9
  123. package/dist/val/CloseFuncVal.js.map +1 -1
  124. package/dist/val/CmpFuncVal.d.ts +20 -0
  125. package/dist/val/CmpFuncVal.js +188 -0
  126. package/dist/val/CmpFuncVal.js.map +1 -0
  127. package/dist/val/ConjunctVal.js +0 -29
  128. package/dist/val/ConjunctVal.js.map +1 -1
  129. package/dist/val/ConstraintVal.js +0 -500
  130. package/dist/val/ConstraintVal.js.map +1 -1
  131. package/dist/val/ContainerKindVal.js +0 -2
  132. package/dist/val/ContainerKindVal.js.map +1 -1
  133. package/dist/val/CopyFuncVal.js +0 -3
  134. package/dist/val/CopyFuncVal.js.map +1 -1
  135. package/dist/val/Decimal.js +0 -179
  136. package/dist/val/Decimal.js.map +1 -1
  137. package/dist/val/DeprecateFuncVal.js.map +1 -1
  138. package/dist/val/DisjunctVal.js +0 -152
  139. package/dist/val/DisjunctVal.js.map +1 -1
  140. package/dist/val/EachFuncVal.d.ts +1 -2
  141. package/dist/val/EachFuncVal.js +12 -29
  142. package/dist/val/EachFuncVal.js.map +1 -1
  143. package/dist/val/EmitFuncVal.d.ts +1 -1
  144. package/dist/val/EmitFuncVal.js +6 -119
  145. package/dist/val/EmitFuncVal.js.map +1 -1
  146. package/dist/val/ExpectVal.js +0 -62
  147. package/dist/val/ExpectVal.js.map +1 -1
  148. package/dist/val/FilterFuncVal.js +0 -25
  149. package/dist/val/FilterFuncVal.js.map +1 -1
  150. package/dist/val/FuncBaseVal.d.ts +1 -0
  151. package/dist/val/FuncBaseVal.js +7 -127
  152. package/dist/val/FuncBaseVal.js.map +1 -1
  153. package/dist/val/GraphAtomVal.js +0 -15
  154. package/dist/val/GraphAtomVal.js.map +1 -1
  155. package/dist/val/HideFuncVal.js +0 -13
  156. package/dist/val/HideFuncVal.js.map +1 -1
  157. package/dist/val/IntegerVal.js +0 -61
  158. package/dist/val/IntegerVal.js.map +1 -1
  159. package/dist/val/JunctionVal.js +0 -20
  160. package/dist/val/JunctionVal.js.map +1 -1
  161. package/dist/val/KeyFuncVal.js +0 -46
  162. package/dist/val/KeyFuncVal.js.map +1 -1
  163. package/dist/val/ListVal.js +0 -57
  164. package/dist/val/ListVal.js.map +1 -1
  165. package/dist/val/LowerFuncVal.js +11 -6
  166. package/dist/val/LowerFuncVal.js.map +1 -1
  167. package/dist/val/MapVal.js +0 -151
  168. package/dist/val/MapVal.js.map +1 -1
  169. package/dist/val/MatchFuncVal.js +0 -27
  170. package/dist/val/MatchFuncVal.js.map +1 -1
  171. package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
  172. package/dist/val/MaybeFuncVal.js +50 -0
  173. package/dist/val/MaybeFuncVal.js.map +1 -0
  174. package/dist/val/MoveFuncVal.js +0 -18
  175. package/dist/val/MoveFuncVal.js.map +1 -1
  176. package/dist/val/NilVal.js +2 -36
  177. package/dist/val/NilVal.js.map +1 -1
  178. package/dist/val/NomFuncVal.d.ts +12 -0
  179. package/dist/val/NomFuncVal.js +153 -0
  180. package/dist/val/NomFuncVal.js.map +1 -0
  181. package/dist/val/NumberVal.js +0 -15
  182. package/dist/val/NumberVal.js.map +1 -1
  183. package/dist/val/OpBaseVal.d.ts +1 -0
  184. package/dist/val/OpBaseVal.js +3 -15
  185. package/dist/val/OpBaseVal.js.map +1 -1
  186. package/dist/val/PackFuncVal.js +0 -34
  187. package/dist/val/PackFuncVal.js.map +1 -1
  188. package/dist/val/PathFuncVal.js +0 -6
  189. package/dist/val/PathFuncVal.js.map +1 -1
  190. package/dist/val/PathVal.js +0 -41
  191. package/dist/val/PathVal.js.map +1 -1
  192. package/dist/val/PlaceVal.js +0 -25
  193. package/dist/val/PlaceVal.js.map +1 -1
  194. package/dist/val/PlusOpVal.d.ts +1 -7
  195. package/dist/val/PlusOpVal.js +13 -74
  196. package/dist/val/PlusOpVal.js.map +1 -1
  197. package/dist/val/PrefFuncVal.js +0 -1
  198. package/dist/val/PrefFuncVal.js.map +1 -1
  199. package/dist/val/PrefVal.js +0 -167
  200. package/dist/val/PrefVal.js.map +1 -1
  201. package/dist/val/RecurseVal.js +0 -55
  202. package/dist/val/RecurseVal.js.map +1 -1
  203. package/dist/val/RefVal.js +0 -282
  204. package/dist/val/RefVal.js.map +1 -1
  205. package/dist/val/ReferFuncVal.js +0 -232
  206. package/dist/val/ReferFuncVal.js.map +1 -1
  207. package/dist/val/ScalarKindVal.js +0 -49
  208. package/dist/val/ScalarKindVal.js.map +1 -1
  209. package/dist/val/ScalarVal.js +0 -11
  210. package/dist/val/ScalarVal.js.map +1 -1
  211. package/dist/val/StrFuncVal.js +0 -18
  212. package/dist/val/StrFuncVal.js.map +1 -1
  213. package/dist/val/SuperFuncVal.js +0 -32
  214. package/dist/val/SuperFuncVal.js.map +1 -1
  215. package/dist/val/TopVal.js +0 -1
  216. package/dist/val/TopVal.js.map +1 -1
  217. package/dist/val/TranslateFuncVal.d.ts +12 -0
  218. package/dist/val/TranslateFuncVal.js +99 -0
  219. package/dist/val/TranslateFuncVal.js.map +1 -0
  220. package/dist/val/UpperFuncVal.js +11 -6
  221. package/dist/val/UpperFuncVal.js.map +1 -1
  222. package/dist/val/Val.d.ts +1 -0
  223. package/dist/val/Val.js +2 -133
  224. package/dist/val/Val.js.map +1 -1
  225. package/dist/val/VarVal.js +0 -12
  226. package/dist/val/VarVal.js.map +1 -1
  227. package/dist/val/arith.js +0 -37
  228. package/dist/val/arith.js.map +1 -1
  229. package/dist/val/caserange.d.ts +3 -0
  230. package/dist/val/caserange.js +49 -0
  231. package/dist/val/caserange.js.map +1 -0
  232. package/dist/val/members.js +0 -6
  233. package/dist/val/members.js.map +1 -1
  234. package/dist/val/numcmp.js +0 -11
  235. package/dist/val/numcmp.js.map +1 -1
  236. package/dist/val/numkind.js +0 -145
  237. package/dist/val/numkind.js.map +1 -1
  238. package/dist/val/valutil.js +0 -16
  239. package/dist/val/valutil.js.map +1 -1
  240. package/dist/vet.d.ts +12 -0
  241. package/dist/vet.js +159 -412
  242. package/dist/vet.js.map +1 -1
  243. package/dist/view.js +0 -414
  244. package/dist/view.js.map +1 -1
  245. package/dist/walk.js +0 -41
  246. package/dist/walk.js.map +1 -1
  247. package/grammar/aontu.abnf +9 -7
  248. package/grammar/aontu.gbnf +5 -5
  249. package/grammar/aontu.lark +5 -5
  250. package/grammar/aontu.tmLanguage.json +1 -1
  251. package/package.json +4 -2
  252. package/skill/SKILL.md +8 -0
  253. package/skill/init/check.sh +28 -0
  254. package/skill/init/data.aon +12 -0
  255. package/skill/init/model.aon +19 -0
  256. package/skill/tasks.md +151 -0
  257. package/src/agentsmd.ts +8 -32
  258. package/src/alias.ts +0 -39
  259. package/src/allow.ts +221 -0
  260. package/src/aontu.ts +10 -108
  261. package/src/aontumodel.ts +32 -0
  262. package/src/cli.ts +1009 -540
  263. package/src/ctx.ts +0 -103
  264. package/src/diff.ts +0 -40
  265. package/src/err.ts +0 -40
  266. package/src/escape.ts +0 -46
  267. package/src/exactjson.ts +0 -131
  268. package/src/format.ts +63 -234
  269. package/src/grammar.ts +72 -0
  270. package/src/graph.ts +0 -61
  271. package/src/hcanon.ts +0 -82
  272. package/src/helpdoc.ts +77 -0
  273. package/src/hints.ts +72 -49
  274. package/src/jsonschema.ts +0 -123
  275. package/src/keyorder.ts +0 -42
  276. package/src/lang.ts +39 -895
  277. package/src/lower.ts +15 -65
  278. package/src/lsp-server.ts +0 -16
  279. package/src/lsp.ts +12 -180
  280. package/src/mcp-server.ts +0 -31
  281. package/src/mcp.ts +0 -130
  282. package/src/mod-tool.ts +0 -158
  283. package/src/mod.ts +0 -178
  284. package/src/patch.ts +0 -232
  285. package/src/provenance.ts +0 -183
  286. package/src/query.ts +0 -84
  287. package/src/reach.ts +0 -53
  288. package/src/relation.ts +7 -71
  289. package/src/render.ts +33 -180
  290. package/src/report-sarif.ts +0 -48
  291. package/src/sig.ts +0 -35
  292. package/src/sigdecl.ts +1 -1
  293. package/src/siggate.ts +0 -30
  294. package/src/site.ts +3 -29
  295. package/src/subsume.ts +1 -161
  296. package/src/template.ts +69 -140
  297. package/src/trim.ts +0 -53
  298. package/src/type.ts +2 -45
  299. package/src/unify.ts +13 -251
  300. package/src/utility.ts +0 -31
  301. package/src/val/AbnfFuncVal.ts +181 -0
  302. package/src/val/AbsentVal.ts +54 -0
  303. package/src/val/AggFuncVal.ts +152 -188
  304. package/src/val/ArithFuncVal.ts +0 -20
  305. package/src/val/BagVal.ts +1 -78
  306. package/src/val/BigDecimalVal.ts +0 -16
  307. package/src/val/BigIntegerVal.ts +0 -16
  308. package/src/val/CloseFuncVal.ts +0 -9
  309. package/src/val/CmpFuncVal.ts +249 -0
  310. package/src/val/ConjunctVal.ts +0 -33
  311. package/src/val/ConstraintVal.ts +2 -537
  312. package/src/val/ContainerKindVal.ts +0 -18
  313. package/src/val/CopyFuncVal.ts +0 -5
  314. package/src/val/Decimal.ts +1 -185
  315. package/src/val/DeprecateFuncVal.ts +0 -10
  316. package/src/val/DisjunctVal.ts +0 -157
  317. package/src/val/EachFuncVal.ts +12 -53
  318. package/src/val/EmitFuncVal.ts +8 -208
  319. package/src/val/ExpectVal.ts +0 -62
  320. package/src/val/FilterFuncVal.ts +0 -55
  321. package/src/val/FuncBaseVal.ts +9 -130
  322. package/src/val/GraphAtomVal.ts +0 -42
  323. package/src/val/HideFuncVal.ts +0 -15
  324. package/src/val/IntegerVal.ts +0 -61
  325. package/src/val/JunctionVal.ts +0 -20
  326. package/src/val/KeyFuncVal.ts +0 -48
  327. package/src/val/ListVal.ts +0 -59
  328. package/src/val/LowerFuncVal.ts +12 -7
  329. package/src/val/MapVal.ts +0 -151
  330. package/src/val/MatchFuncVal.ts +0 -59
  331. package/src/val/MaybeFuncVal.ts +86 -0
  332. package/src/val/MoveFuncVal.ts +0 -20
  333. package/src/val/NilVal.ts +2 -36
  334. package/src/val/NomFuncVal.ts +200 -0
  335. package/src/val/NumberVal.ts +0 -16
  336. package/src/val/OpBaseVal.ts +4 -17
  337. package/src/val/PackFuncVal.ts +0 -63
  338. package/src/val/PathFuncVal.ts +0 -32
  339. package/src/val/PathVal.ts +0 -66
  340. package/src/val/PlaceVal.ts +0 -45
  341. package/src/val/PlusOpVal.ts +18 -75
  342. package/src/val/PrefFuncVal.ts +0 -1
  343. package/src/val/PrefVal.ts +0 -179
  344. package/src/val/RecurseVal.ts +0 -81
  345. package/src/val/RefVal.ts +1 -285
  346. package/src/val/ReferFuncVal.ts +0 -255
  347. package/src/val/ScalarKindVal.ts +0 -50
  348. package/src/val/ScalarVal.ts +0 -12
  349. package/src/val/StrFuncVal.ts +0 -44
  350. package/src/val/SuperFuncVal.ts +0 -42
  351. package/src/val/TopVal.ts +0 -1
  352. package/src/val/TranslateFuncVal.ts +132 -0
  353. package/src/val/UpperFuncVal.ts +12 -7
  354. package/src/val/Val.ts +3 -192
  355. package/src/val/VarVal.ts +0 -15
  356. package/src/val/arith.ts +0 -92
  357. package/src/val/caserange.ts +53 -0
  358. package/src/val/members.ts +0 -23
  359. package/src/val/numcmp.ts +1 -27
  360. package/src/val/numkind.ts +0 -149
  361. package/src/val/valutil.ts +0 -16
  362. package/src/vet.ts +209 -504
  363. package/src/view.ts +0 -507
  364. package/src/walk.ts +0 -41
  365. package/dist/std.d.ts +0 -3
  366. package/dist/std.js +0 -637
  367. package/dist/std.js.map +0 -1
  368. package/dist/val/FormFuncVal.js +0 -55
  369. package/dist/val/FormFuncVal.js.map +0 -1
  370. package/src/std.ts +0 -648
  371. package/src/val/FormFuncVal.ts +0 -119
package/dist/vet.js CHANGED
@@ -6,6 +6,7 @@ exports.displayFile = displayFile;
6
6
  exports.failureFinding = failureFinding;
7
7
  exports.anchorAt = anchorAt;
8
8
  exports.throughResidue = throughResidue;
9
+ exports.vetCoverage = vetCoverage;
9
10
  exports.vet = vet;
10
11
  const aontu_1 = require("./aontu");
11
12
  const node_path_1 = require("node:path");
@@ -15,49 +16,18 @@ const walk_1 = require("./walk");
15
16
  const BagVal_1 = require("./val/BagVal");
16
17
  const utility_1 = require("./utility");
17
18
  const subsume_1 = require("./subsume");
18
- // The `--at` refusal is the SAME refusal `get` and `why` give for a
19
- // path that names nothing, down to the "did you mean" -- so it is that
20
- // one, not a second spelling of it. A cycle in the module graph
21
- // (query imports anchorAt from here), and a benign one: both sides
22
- // use the other only from inside a function body, never at load time.
23
19
  const query_1 = require("./query");
20
+ const keyorder_1 = require("./keyorder");
24
21
  // The default cap, exported because the CLI applies it to the WHOLE
25
22
  // report across several data files and must not carry a second copy of
26
23
  // the number (ts/src/cli.ts).
27
24
  exports.VET_MAX_ERRORS = 20;
28
25
  const DEFAULT_SCHEMA_URL = 'schema';
29
26
  const DEFAULT_DATA_URL = 'data';
30
- // Every site in a freshly parsed tree carries the same url, and for a
31
- // bare parse that url is the empty string: `site.url` is only populated
32
- // by the multisource loader (ts/src/lang.ts). Vet takes two documents
33
- // from its CALLER, not from the filesystem, so it stamps provenance
34
- // itself — which is what lets the report assign site ROLES by
35
- // provenance rather than by NilVal's source-order heuristic, exactly as
36
- // the design requires.
37
- // EVERY SITE NAMES THE FILE WHOSE TEXT IT EXCERPTS (the review's
38
- // finding F, use-cases/BUGS.md §25). The parser already names the file
39
- // each value was read from -- a value loaded through `@"lib/types.aon"`
40
- // carries that path, with that file's row and column -- and this walk
41
- // used to OVERWRITE every url with the entry document's name. The
42
- // coordinates stayed the included file's, so a finding cited
43
- // `entry.aon:3:7` for text that lives three files away, at a line the
44
- // entry may not even have. A repair agent that follows the site edits
45
- // the wrong file.
46
- //
47
- // Only the values that carry no name of their own are stamped: those
48
- // are the ones the engine minted rather than read, and the entry is
49
- // the honest name for them. The urls actually seen are collected, so
50
- // the report can still tell WHICH DOCUMENT a site belongs to without
51
- // pretending they all came from one file -- see roleOf.
52
27
  function stampUrl(v, url, seen) {
53
28
  const urls = seen ?? new Set();
54
29
  urls.add(url);
55
30
  (0, walk_1.walkVals)(v, (n) => {
56
- // UNDEFINED counts as unstamped, not just empty: the parser leaves
57
- // the url undefined on one of its two paths (ts/src/lang.ts), and
58
- // treating that as a name would put `undefined` in the url set --
59
- // where the OTHER document's unstamped values would then match it,
60
- // and every site would read `data`.
61
31
  if (null == n.site.url || '' === n.site.url) {
62
32
  n.site.url = url;
63
33
  }
@@ -66,20 +36,6 @@ function stampUrl(v, url, seen) {
66
36
  }, new Set());
67
37
  return urls;
68
38
  }
69
- // A FILE THE READER CAN OPEN. The parser resolves an include to an
70
- // absolute path, which is the right identity (two files loading the
71
- // same library by different relative spellings must be one file) and
72
- // the wrong NAME: a report whose entry reads `contract.aon` and whose
73
- // included site reads `/home/someone/checkout/types.aon` is a report
74
- // that cannot be uploaded as SARIF, diffed between machines, or read
75
- // beside the command that produced it.
76
- //
77
- // So an included file is named as the ENTRY'S OWN NAME reaches it:
78
- // relative to the entry's directory, then re-anchored on however the
79
- // caller spelled the entry. `vet contract.aon` names `types.aon`;
80
- // `vet a/b/contract.aon` names `a/b/types.aon`; an absolute entry
81
- // keeps absolute includes. A caller who passed no path at all has no
82
- // base to relativise against and gets the url unchanged.
83
39
  function displayFile(url, label, path) {
84
40
  if (url === label || null == path || '' === url || !(0, node_path_1.isAbsolute)(url)) {
85
41
  return url;
@@ -88,57 +44,22 @@ function displayFile(url, label, path) {
88
44
  const dir = (0, node_path_1.dirname)(label);
89
45
  return '.' === dir ? rel : (0, node_path_1.join)(dir, rel);
90
46
  }
91
- // The name for one site, taken from the document the site BELONGS to
92
- // -- which is the role, already decided by url-set membership. Doing
93
- // it here rather than from a map built at stamping time is not a
94
- // shortcut: a nil's operands are off the tree by the time the report
95
- // is built, so a value first seen during the MEET (the commonest
96
- // schema site there is) would be missing from any such map.
97
47
  function displayOf(file, role, prov) {
98
48
  return 'data' === role
99
49
  ? displayFile(file, prov.dataUrl ?? file, prov.dataPath)
100
50
  : displayFile(file, prov.schemaUrl ?? file, prov.schemaPath);
101
51
  }
102
- // The ROLE of a site: which of the two documents it belongs to. Not a
103
- // name comparison -- a data document may itself include another file,
104
- // and that file's values are still data. Membership of the url set the
105
- // stamping walk collected is the question, and the answer is `schema`
106
- // for anything the data walk never reached (an engine-minted value
107
- // stamped with the schema entry, say).
108
52
  function roleOf(file, prov) {
109
53
  return prov.data.has(file) ? 'data' : 'schema';
110
54
  }
111
- // `$.a.b`, and `$` for the root. Deliberately NOT delimiter-escaped: a
112
- // map key may contain any character, including every separator a
113
- // compact summary might pick, so the path is carried as a JSON string
114
- // and never parsed back out of a larger token.
115
55
  function pathText(path) {
116
56
  return '$' + (null != path && 0 < path.length ? '.' + path.join('.') : '');
117
57
  }
118
- // `secondary` is the only operand that can be absent — a `closed` or an
119
- // incomplete finding has one side, a two-site conflict has both — so
120
- // this is the one nullable input, and every Val that does arrive
121
- // carries a site and a canon.
122
58
  function siteOf(v, prov) {
123
59
  if (null == v) {
124
60
  return undefined;
125
61
  }
126
- // The report's `file` is whatever the site carries, and by the time a
127
- // site reaches a report that is always a stamped name: vet walks both
128
- // documents before they meet, and the walk reaches the off-peg values
129
- // a finding can name (ts/src/walk.ts). A consumer therefore reads
130
- // `file` without a presence check, and the Go port -- whose field is
131
- // a plain string -- writes the same key.
132
- //
133
- // NOT coalesced. The parser leaves the url undefined on one of its
134
- // two paths (ts/src/lang.ts), and a `?? ''` here would be dead code
135
- // that hides it: if a value ever reaches a report unstamped, the two
136
- // ports should disagree loudly rather than quietly agree on an empty
137
- // name that neither of them meant.
138
62
  const file = v.site.url;
139
- // NAMED for the reader, ROLED by the raw url: the two questions are
140
- // different, and only the first is about how the file is spelled
141
- // (see displayFile).
142
63
  const role = roleOf(file, prov);
143
64
  return {
144
65
  file: displayOf(file, role, prov),
@@ -154,32 +75,16 @@ function siteOf(v, prov) {
154
75
  // The underlying NilVal fields are untouched: this is a report-layer
155
76
  // projection, so the existing error.tsv assertions do not move.
156
77
  function sitesOf(nil, prov) {
157
- // `?? nil`: a failure raised about a CONSTRUCT rather than about a
158
- // failed meet -- a lossy integer literal, say -- carries no operands
159
- // at all, and reporting it about ITSELF is what ctx.adderr already
160
- // does for the same reason. Without the fallback the report built a
161
- // site out of `undefined` and threw while partitioning it, which is
162
- // the one thing vet promises not to do: a bad value in the data is
163
- // DATA, and the caller gets a report.
164
78
  const sites = [siteOf(nil.primary ?? nil, prov)];
165
79
  const secondary = siteOf(nil.secondary, prov);
166
80
  if (null != secondary) {
167
81
  sites.push(secondary);
168
82
  }
169
- // Partitioned rather than sorted: which of the two NilVal operands is
170
- // `primary` follows source order within one document, which says
171
- // nothing useful when one side is a schema and the other is data.
172
83
  return [
173
84
  ...sites.filter((s) => 'data' === s.role),
174
85
  ...sites.filter((s) => 'schema' === s.role),
175
86
  ];
176
87
  }
177
- // The message text is MATERIALISED on demand, exactly as handleErrors
178
- // materialises one before a caller sees it: makeNilErr defers it
179
- // because most NilVals are transient and never rendered, and only the
180
- // throwing path asks for it. Without this a finding could carry an
181
- // empty `message` -- which is what the incomplete half of every report
182
- // did, and what any nil built during the PARSE of a document did.
183
88
  function materialise(nil, ctx) {
184
89
  if (null == nil.msg || '' === nil.msg) {
185
90
  (0, err_1.descErr)(nil, ctx);
@@ -199,30 +104,13 @@ function findingOf(nil, prov) {
199
104
  class: nil.class,
200
105
  severity: 'error',
201
106
  path: pathText(nil.path),
202
- // The HEADLINE only, WITHOUT ANSI: the frames below it are for a
203
- // human reading a terminal, and the first line is the part the two
204
- // ports hold to byte parity. Materialised before this runs, so it
205
- // is always there (see materialise above). The escapes matter for
206
- // one family only -- a parse failure's text comes from the parser,
207
- // which colours its marker -- and a machine-readable report is no
208
- // place for terminal control codes.
209
107
  message: stripAnsi(nil.msg.split('\n')[0]),
210
108
  sites: sitesOf(nil, prov),
211
109
  };
212
- // The hint, whole, with its detail placeholders filled in exactly as
213
- // the terminal frame fills them. Trailing whitespace is dropped
214
- // because it is spacing for the frame that used to follow it, not
215
- // part of the text; the deliberate blank lines INSIDE a hint are
216
- // `\n \n` and survive.
217
110
  const hint = (0, err_1.getHint)(nil.why, nil.details);
218
111
  if (null != hint && '' !== hint) {
219
112
  finding.hint = stripAnsi(hint).replace(/\s+$/, '');
220
113
  }
221
- // `expected`/`actual` are the admissible-alternatives contract, and
222
- // the constraint algebra already produces them: G1's atoms attach the
223
- // normalised residual and the offending value, and `must` attaches
224
- // the author's message. Read them where they are rather than
225
- // re-deriving them here.
226
114
  if ('string' === typeof details.expected) {
227
115
  finding.expected = details.expected;
228
116
  }
@@ -234,29 +122,10 @@ function findingOf(nil, prov) {
234
122
  }
235
123
  return finding;
236
124
  }
237
- // Findings are sorted BY VET, not by the walk. The underlying walk
238
- // iterates raw object keys and the two hosts disagree about their order
239
- // — `10:… 9:…` yields ["9","10"] in JavaScript, which hoists
240
- // integer-like keys, against Go's insertion order (ts/src/keyorder.ts
241
- // exists for exactly this) — so an unsorted report could never be in
242
- // cross-port parity.
243
- //
244
- // The order is by data site (file, row, column), then code, then path.
245
- // It is carried in ONE key string rather than a cascade of comparisons:
246
- // the row and column are zero-padded so lexicographic order is numeric
247
- // order, and NUL joins the fields because no field can contain one.
248
- // A cascade would need a test per tie-breaker to stay honest; a key
249
- // needs none, and cannot disagree with itself.
250
125
  const ORDER_PAD = 9;
251
126
  function pad(n) {
252
127
  return String(n).padStart(ORDER_PAD, '0');
253
128
  }
254
- // The walk index is the LAST field, which makes every key unique and
255
- // the sort below total: two findings can otherwise share everything the
256
- // key carries — same data site, same code, same path — and a comparator
257
- // that has to answer "equal" is one more thing to get right in two
258
- // languages. With the index appended, ties simply keep walk order, in
259
- // both ports, by construction rather than by the sort's promises.
260
129
  function orderKey(f, index) {
261
130
  const site = f.sites[0];
262
131
  return [
@@ -268,42 +137,9 @@ function orderKey(f, index) {
268
137
  pad(index),
269
138
  ].join('\u0000');
270
139
  }
271
- // A DOCUMENT THAT DOES NOT STAND UP, in the finding shape (the
272
- // review's finding F). `trim` and `relations` answered an unusable
273
- // document with `verdict: error` and an EMPTY list: the caller learned
274
- // that something was wrong and nothing about what, which is the one
275
- // thing a repair loop cannot work with. Both verbs take ONE document,
276
- // so there is no role to decide -- the document is the thing being
277
- // checked and the thing to edit, which is what `data` means here.
278
- //
279
- // The engine's own first error IS the finding: these verbs add nothing
280
- // to a diagnosis the evaluator already made, and the FIRST is enough
281
- // because everything after it is a consequence.
282
- //
283
- // The Go twin is failureFinding in go/vet.go.
284
140
  function failureFinding(ctx, url, failed) {
285
- // ctx.err IS SOMETIMES EMPTY, and the comment that used to stand here
286
- // said otherwise (use-cases/BUGS.md §43). `&: id(root)` fails with a
287
- // NIL ROOT and NO COLLECTED ERROR -- the id-spread refusal is the
288
- // root itself -- and every verb that reports "this document does not
289
- // stand up" then read `ctx.err[0]` as undefined and died: a TypeError
290
- // out of `relations`, `reaches` and `jsonschema` in TypeScript, a
291
- // panic in Go. The one shape where finding F's own invariant, that a
292
- // document which does not stand up SAYS SO in the finding shape, was
293
- // answered with a stack trace.
294
- //
295
- // `failed` is the caller's own root -- every caller has it, and its
296
- // condition is `0 < ctx.err.length || root.isNil`, so when the first
297
- // half is false the second holds and the root IS the reason.
298
141
  const nil = ctx.err[0] ?? failed;
299
142
  materialise(nil, ctx);
300
- // STAMPED, as vet stamps both documents before they meet: siteOf does
301
- // not coalesce a missing name (deliberately -- see there), so a site
302
- // that reached the report unstamped would carry `file: undefined`.
303
- // The three Vals a finding can name are the nil and its two operands,
304
- // and the url set collects whatever name each already had, so a value
305
- // read from an included file keeps that file's name and still counts
306
- // as part of the one document being checked.
307
143
  const at = url ?? '';
308
144
  const urls = new Set([at]);
309
145
  for (const v of [nil, nil.primary, nil.secondary]) {
@@ -325,27 +161,7 @@ function anchorAt(root, at) {
325
161
  const parts = trimmed.split('.').filter((p) => '' !== p);
326
162
  let node = root;
327
163
  for (const part of parts) {
328
- // A SIZING RESIDUE IS ITS CONTAINER, plus a note about what the
329
- // container must still satisfy (use-cases/BUGS.md §16). The path
330
- // steps through it: `$.a.ports.0.port` names the same node whether
331
- // or not `ports` still carries a `unique()`, and an anchor that
332
- // stopped here would report `no_path` for a key the document
333
- // plainly has.
334
164
  node = throughResidue(node);
335
- // TYPE-DIRECTED, not a property lookup on whatever `peg` happens to
336
- // be. An anchor is a STRUCTURAL path into the schema — the same
337
- // thing a reference means by `$.a.b` — so it walks map keys and
338
- // list indices, and stops at anything else.
339
- //
340
- // Indexing the peg generically walked much further than that: into
341
- // a junction's branches (`a:1|2` with `--at $.a.0` validated
342
- // against ONE branch), into a constraint's atom arguments (so
343
- // `min(2)` with `--at $.a.0` reported the bound's own argument as
344
- // the truth), into a pref's wrapped value through the literal key
345
- // `peg`, and into an array's `length` — that last one handing back
346
- // a JavaScript NUMBER as the anchor, after which every document
347
- // whatsoever came back valid. The Go port has always been
348
- // type-directed here; this is the canonical side moving to it.
349
165
  if (true === node?.isMap) {
350
166
  const peg = node.peg;
351
167
  if (null == peg || !Object.prototype.hasOwnProperty.call(peg, part)) {
@@ -369,38 +185,158 @@ function anchorAt(root, at) {
369
185
  return undefined;
370
186
  }
371
187
  }
372
- // THE ANCHOR KEEPS ITS ATOM. Stepping THROUGH a residue is right --
373
- // `$.x.a` names a key of the container whatever the container still
374
- // has to satisfy -- but ARRIVING at one and handing back the bare
375
- // container drops a constraint the author wrote, so `--at $.x` vetted
376
- // clean against a `length` the evaluator enforces. The residue is the
377
- // honest schema for the node: the meet drives it, and generation
378
- // settles it, exactly as it does without an anchor.
379
188
  return node;
380
189
  }
381
- // The container inside a settled sizing residue, or the value itself.
382
- // EXPORTED for the `doc` figure, which walks the same shape the anchor
383
- // does: a list still carrying a `unique()` is a list, and a drawing
384
- // that stopped at the residue would omit keys the document plainly
385
- // has.
386
190
  function throughResidue(v) {
387
191
  return (0, BagVal_1.sizingResidue)(v)?.bag ?? v;
388
192
  }
389
- // Validate `dataSrc` against `schemaSrc`.
390
- //
391
- // Never throws for findings: a contradiction in the data is DATA, and
392
- // the caller gets a report. It throws only when the caller's own inputs
393
- // are unusable — which is why an unusable schema is a verdict (`error`)
394
- // rather than an exception too: "the schema is broken" is a fact the
395
- // agent loop needs to branch on, not an exceptional condition.
193
+ const COVER_TEMPLATE = '&';
194
+ // Is this value a bag with children to walk?
195
+ function coverKids(v) {
196
+ const out = [];
197
+ if (true === v.isMap && null != v.peg) {
198
+ for (const k of Object.keys(v.peg).sort(keyorder_1.cmpCodePoint)) {
199
+ out.push({ key: k, val: v.peg[k] });
200
+ }
201
+ }
202
+ else if (true === v.isList && Array.isArray(v.peg)) {
203
+ v.peg.forEach((m, i) => out.push({ key: String(i), val: m }));
204
+ }
205
+ return out;
206
+ }
207
+ function coverTemplate(v) {
208
+ const cj = v?.spread?.cj;
209
+ return null != cj && true === cj.isVal && true !== cj.isTop ? cj : undefined;
210
+ }
211
+ function coverDeclare(v, path, out) {
212
+ const tpl = coverTemplate(v);
213
+ if (null != tpl) {
214
+ const at = [...path, COVER_TEMPLATE];
215
+ out.set(pathText(at), tpl);
216
+ coverDeclare(tpl, at, out);
217
+ }
218
+ for (const { key, val } of coverKids(v)) {
219
+ const at = [...path, key];
220
+ out.set(pathText(at), val);
221
+ coverDeclare(val, at, out);
222
+ }
223
+ }
224
+ // Every path in the data, and whether it is a LEAF -- a node with no
225
+ // children, which is where a value lives.
226
+ function coverDataPaths(v, path, out) {
227
+ const kids = coverKids(v);
228
+ if (0 < path.length) {
229
+ out.push({ path: pathText(path), leaf: 0 === kids.length });
230
+ }
231
+ for (const { key, val } of kids) {
232
+ coverDataPaths(val, [...path, key], out);
233
+ }
234
+ }
235
+ // Walk one data path down the schema, naming the declaration that
236
+ // constrains it -- the exact key where the schema has one, else the
237
+ // covering template. Undefined when the schema declares nothing there.
238
+ function coverMatch(anchor, segs) {
239
+ let at = anchor;
240
+ let decl = '';
241
+ for (const seg of segs) {
242
+ const named = true === at.isMap && null != at.peg ? at.peg[seg]
243
+ : true === at.isList && Array.isArray(at.peg) ? at.peg[Number(seg)]
244
+ : undefined;
245
+ if (null != named && true === named.isVal) {
246
+ decl = '' === decl ? seg : decl + '.' + seg;
247
+ at = named;
248
+ continue;
249
+ }
250
+ const tpl = coverTemplate(at);
251
+ if (null == tpl) {
252
+ return undefined;
253
+ }
254
+ decl = '' === decl ? COVER_TEMPLATE : decl + '.' + COVER_TEMPLATE;
255
+ at = tpl;
256
+ }
257
+ return '$.' + decl;
258
+ }
259
+ // The SHALLOWEST members of a set of paths: one whose parent is also in
260
+ // the set is covered by naming the parent, and naming both is noise.
261
+ // `render --coverage`'s `dead` is built on the same rule.
262
+ function coverShallowest(paths) {
263
+ const held = new Set(paths);
264
+ return paths.filter((p) => {
265
+ for (let at = p; -1 !== at.lastIndexOf('.');) {
266
+ at = at.slice(0, at.lastIndexOf('.'));
267
+ if (held.has(at)) {
268
+ return false;
269
+ }
270
+ }
271
+ return true;
272
+ }).sort(keyorder_1.cmpCodePoint);
273
+ }
274
+ // The accounting itself: what the schema declared, what the data holds,
275
+ // and which of each the other met.
276
+ function vetCoverage(anchor, dataVal, coverageAt) {
277
+ const declarations = new Map();
278
+ coverDeclare(anchor, [], declarations);
279
+ const dataPaths = [];
280
+ coverDataPaths(dataVal, [], dataPaths);
281
+ // `--coverage-at` narrows the DATA side, which is the side a caller
282
+ // gating one subtree is asking about. The schema side follows from
283
+ // it: a declaration is unused only among the data actually measured.
284
+ const under = null == coverageAt ? undefined
285
+ : coverageAt.replace(/^\$\.?/, '');
286
+ const inScope = (p) => {
287
+ if (null == under || '' === under) {
288
+ return true;
289
+ }
290
+ const want = '$.' + under;
291
+ return p === want || p.startsWith(want + '.');
292
+ };
293
+ const used = new Set();
294
+ const unchecked = [];
295
+ let checked = 0;
296
+ let leaves = 0;
297
+ for (const { path, leaf } of dataPaths) {
298
+ if (!inScope(path)) {
299
+ continue;
300
+ }
301
+ const segs = path.replace(/^\$\.?/, '').split('.').filter((x) => '' !== x);
302
+ const decl = coverMatch(anchor, segs);
303
+ if (leaf) {
304
+ leaves++;
305
+ }
306
+ if (null == decl) {
307
+ unchecked.push(path);
308
+ continue;
309
+ }
310
+ used.add(decl);
311
+ if (leaf) {
312
+ checked++;
313
+ }
314
+ }
315
+ // A declaration is met when it constrained a data path, or when a
316
+ // declaration BENEATH it was: `$.a` is used by `$.a.b` meeting
317
+ // `$.a.b`, and reporting the parent as unused would be false.
318
+ const unused = [];
319
+ for (const decl of declarations.keys()) {
320
+ const covered = used.has(decl) ||
321
+ [...used].some((u) => u.startsWith(decl + '.'));
322
+ if (!covered) {
323
+ unused.push(decl);
324
+ }
325
+ }
326
+ return {
327
+ checked,
328
+ declared: declarations.size,
329
+ leaves,
330
+ unchecked: coverShallowest(unchecked),
331
+ unused: coverShallowest(unused),
332
+ vacuous: 0 === checked && 0 < leaves,
333
+ };
334
+ }
396
335
  function vet(schemaSrc, dataSrc, opts) {
397
336
  const options = opts ?? {};
398
337
  const schemaUrl = options.schemaUrl ?? DEFAULT_SCHEMA_URL;
399
338
  const dataUrl = options.dataUrl ?? DEFAULT_DATA_URL;
400
339
  const maxErrors = options.maxErrors ?? exports.VET_MAX_ERRORS;
401
- // ONE instance, two bases: the path rides on each CALL rather than on
402
- // the constructor, because the schema and the data may live in
403
- // different directories (Lang.parse takes `opts.path` per parse).
404
340
  const aontu = new aontu_1.Aontu((0, utility_1.includeOpts)(options));
405
341
  const schemaOpts = null == options.schemaPath ?
406
342
  undefined : { path: options.schemaPath };
@@ -411,33 +347,7 @@ function vet(schemaSrc, dataSrc, opts) {
411
347
  const schemaCtx = aontu.ctx({ collect: true });
412
348
  const schemaVal = aontu.unify(schemaSrc, schemaOpts, schemaCtx);
413
349
  if (0 < schemaCtx.err.length || true === schemaVal?.isNil) {
414
- // A broken schema REPORTS, exactly as broken data does. It used to
415
- // answer `findings: []` with exit 4 and nothing else, in both
416
- // ports: the engine had collected the fault and vet threw it away,
417
- // so an agent -- or a person -- was told the schema was broken and
418
- // not what or where. The verdict stays `error` (the fault is in
419
- // the truth, not in the data, and that distinction is the whole
420
- // point of the class), but the finding travels with it.
421
- //
422
- // The FIRST error only, and the data path's reasoning applies
423
- // unchanged: later errors in a document that does not stand up are
424
- // consequences of the first rather than separate things to fix.
425
- //
426
- // ONE OF THE TWO IS ALWAYS THERE, and both are nils: the branch
427
- // condition admits a collected error or a nil root, and every
428
- // value on `schemaCtx.err` is a NilVal. There is no third case, so
429
- // there is no guard here -- a guard that cannot fire is dead code,
430
- // and dead code is what ADR-002 exists to keep out. (One stood
431
- // here and the TypeScript line report called it covered; the Go
432
- // gate, which measures blocks, refused the twin.)
433
350
  const failure = 0 < schemaCtx.err.length ? schemaCtx.err[0] : schemaVal;
434
- // The normal path stamps both documents before they meet
435
- // (stampUrl(anchor...) below), and this early return never reaches
436
- // it, so it stamps what it is about to report: the unified root,
437
- // and the failure itself -- a COLLECTED error is minted during
438
- // unification and hangs off no tree, so nothing else would name
439
- // it. The walk reaches a failure's operands (ts/src/walk.ts),
440
- // which is what makes the sites say which file.
441
351
  stampUrl(schemaVal, schemaUrl);
442
352
  stampUrl(failure, schemaUrl);
443
353
  materialise(failure, schemaCtx);
@@ -454,11 +364,6 @@ function vet(schemaSrc, dataSrc, opts) {
454
364
  if (null != options.at) {
455
365
  anchor = anchorAt(schemaVal, options.at);
456
366
  if (null == anchor) {
457
- // AND IT SAYS WHICH SEGMENT. `--at` naming nothing is an error
458
- // verdict for the same reason a broken schema is -- the run
459
- // could not be set up from the truth's side -- and it reports
460
- // for the same reason too: a caller handed exit 4 and an empty
461
- // list has nothing to act on.
462
367
  return {
463
368
  verdict: 'error',
464
369
  truncated: false,
@@ -471,22 +376,6 @@ function vet(schemaSrc, dataSrc, opts) {
471
376
  const dataCtx = aontu.ctx({ collect: true });
472
377
  const dataVal = aontu.parse(dataSrc, dataOpts, dataCtx);
473
378
  if (0 < dataCtx.err.length || null == dataVal) {
474
- // A DATA DOCUMENT THAT WILL NOT PARSE IS THE DATA'S FAULT, and the
475
- // report says so: verdict `invalid`, with a finding carrying the
476
- // parser's own code and a site in the data. `error` is left to mean
477
- // what the exit table says it means -- the run could not be set up
478
- // from the SCHEMA side.
479
- //
480
- // The engine already answered it this way one character earlier: a
481
- // refused CONSTRUCT (`a: 9007199254740993`) reaches the tree as an
482
- // ordinary nil and is reported as an invalid data finding. A stray
483
- // `]` took the throwing path instead and came back as a broken
484
- // SCHEMA -- the same fault, classified two opposite ways by which
485
- // branch the parser happened to take.
486
- //
487
- // The FIRST error only: the parser stops at the first syntax error,
488
- // so a second entry would be a consequence of the first rather than
489
- // a separate thing to fix.
490
379
  const failure = dataCtx.err[0];
491
380
  if (null == failure) {
492
381
  return { verdict: 'error', truncated: false, findings: [] };
@@ -499,17 +388,6 @@ function vet(schemaSrc, dataSrc, opts) {
499
388
  findings: [findingOf(failure, { data: new Set([dataUrl]) })],
500
389
  };
501
390
  }
502
- // STAMP THE WHOLE SETTLED SCHEMA, not just the lifted anchor.
503
- // Without `--at` these are the same tree. With it, the anchor is a
504
- // subtree and the rest of the schema is still REACHABLE from inside
505
- // it -- a `%alias` declaration (`[&: %U]`, target `$.%U`) or a
506
- // recursive residual's `$.spec.Step`, both of which the meet
507
- // resolves through _fixroot (RefVal.find, RecurseVal.body). A node
508
- // reached that way but never stamped carries no url, so its site
509
- // named no file while excerpting the schema's text -- against the
510
- // invariant that every site names the file whose text it shows
511
- // (finding F, §25). stampUrl only fills a url that is EMPTY, so
512
- // stamping the superset never renames a value read from an include.
513
391
  stampUrl(schemaVal, schemaUrl);
514
392
  const dataUrls = stampUrl(dataVal, dataUrl);
515
393
  // The projection every site in this report goes through: roles by
@@ -519,31 +397,17 @@ function vet(schemaSrc, dataSrc, opts) {
519
397
  schemaUrl, schemaPath: options.schemaPath,
520
398
  dataUrl, dataPath: options.dataPath,
521
399
  };
522
- // Default-validity lint (G3 phase 5, re-examined under ADR-004): for
523
- // every disjunction in the SCHEMA carrying a preference, warn when
524
- // the effective default is not an instance of any REMAINING
525
- // alternative (code `pref_not_instance`, class compat, severity
526
- // warning).
527
- //
528
- // What the finding MEANS changed with the admission gate (ADR-004).
529
- // Before the gate it flagged a soundness hole: the preference held
530
- // the disjunction open, so `a:*5|string` both generated a value the
531
- // alternatives refuse AND admitted any same-kind override. The gate
532
- // closed that hole — a preferred branch now contributes exactly its
533
- // own value to the admitted set, so a default can no longer be
534
- // "invalid against its own disjunct" and the enum-with-default idiom
535
- // (`*'auto'|'literal'|'data'`) is sound as written. The lint is KEPT,
536
- // as an advisory: a default admitted only because it is the default
537
- // is also the exact shape of a typo'd default
538
- // (`level:*wran|info|warn|debug` — the intended `*warn` would be
539
- // silent), and nothing at meet time can catch that. The
540
- // repeated-branch spelling (`*warn|warn|...`) states "the default is
541
- // a first-class member", silences the lint, and — unlike before the
542
- // gate — enforces exactly the same admitted set. The message names
543
- // the REMAINING alternatives because that is what was scanned: the
544
- // preferred branch itself always admits its own default, so the old
545
- // wording ("any alternative of *5|string") read as false on its face
546
- // (use-cases/BUGS.md §4).
400
+ let coverage;
401
+ if (true === options.coverage) {
402
+ const coverCtx = aontu.ctx({ collect: true });
403
+ const settledData = aontu.unify(dataSrc, dataOpts, coverCtx);
404
+ // A data document that does not stand alone is already reported by
405
+ // the meet below; here it falls back to what was parsed, which is
406
+ // the same paths minus whatever an include would have added.
407
+ const measured = 0 === coverCtx.err.length && true !== settledData?.isNil
408
+ ? settledData : dataVal;
409
+ coverage = vetCoverage(anchor, measured, options.coverageAt);
410
+ }
547
411
  const lintFindings = [];
548
412
  (0, utility_1.walkBagVals)(anchor, (v, path) => {
549
413
  if (true === v.isDisjunct && Array.isArray(v.peg)) {
@@ -578,44 +442,9 @@ function vet(schemaSrc, dataSrc, opts) {
578
442
  }
579
443
  }
580
444
  });
581
- // `--closed` sets the flag `close()` itself sets, rather than wrapping
582
- // the anchor in a CloseFuncVal: the anchor is an already-evaluated
583
- // tree, and a func value would have to resolve again to have any
584
- // effect. A scalar anchor has no keys to close, so the flag is only
585
- // meaningful on a bag.
586
445
  if (true === options.closed && (true === anchor.isMap || true === anchor.isList)) {
587
446
  anchor.closed = true;
588
447
  }
589
- // THE MEET IS FROM A FRESH PARSE, NOT THE SETTLED SCHEMA (the
590
- // review's finding C, use-cases/BUGS.md §15).
591
- //
592
- // Step 1 evaluated the schema ALONE, to decide whether it stands up
593
- // before any data is blamed for it. That answer is a diagnosis, and
594
- // it was also being used as the left side of the meet -- so every
595
- // reference in the schema had already RESOLVED against the schema's
596
- // own values and been replaced by them. `a:integer b:$.a` settled to
597
- // `a:integer b:integer`, and data `{a:3,b:4}` then vetted VALID,
598
- // while the same four lines as one document refuse with
599
- // scalar_value. A reference is a statement about the FINAL model, and
600
- // vet is asking about a model the data is part of.
601
- //
602
- // Parsing again is what makes `vet(S,D)` and `eval(S ∪ D)` the same
603
- // question: the meet runs the fixpoint once, over both documents, so
604
- // references, spreads and generators all see the data. Parsed trees
605
- // are single-use, hence a second parse rather than a reuse of step
606
- // 1's. The lint above still reads the SETTLED tree, where
607
- // disjunctions are ranked and normalised.
608
- //
609
- // ONLY WHEN THERE IS NO `--at`. An anchor is a SUBTREE lifted out of
610
- // the schema, and an absolute reference inside it (`$.OrderPlaced`,
611
- // the discriminated-union idiom) names a sibling of the document
612
- // root -- which the lifted subtree no longer has. The settled tree is
613
- // where those references have already been resolved and substituted,
614
- // so an anchored run keeps meeting that, exactly as it always has.
615
- // Making the rule explicit rather than leaving it to whether
616
- // anchorAt happens to find the path in an unresolved tree: the two
617
- // ports answered that differently, which is an ADR-001 divergence
618
- // waiting to happen.
619
448
  const ctx = aontu.ctx({ collect: true });
620
449
  let meetAnchor = anchor;
621
450
  if (null == options.at) {
@@ -631,15 +460,6 @@ function vet(schemaSrc, dataSrc, opts) {
631
460
  }
632
461
  }
633
462
  else {
634
- // A RECURSIVE residual inside the lifted anchor still names its
635
- // definition by absolute path (`then?: $.spec.Step` -- the
636
- // fixpoint, RECURSION.0.md), and the meet's root is the anchored
637
- // subtree, which does not contain `$.spec`. Without a tree to
638
- // walk, the residual held its peer forever and everything under a
639
- // recursive field vetted VALID unchecked. The settled schema root
640
- // is kept on the meet context for exactly that walk
641
- // (AontuContext._fixroot; RecurseVal.body and RefVal.find fall
642
- // back to it).
643
463
  ;
644
464
  ctx._fixroot = schemaVal;
645
465
  ctx.path = options.at.replace(/^\$\.?/, '')
@@ -647,17 +467,6 @@ function vet(schemaSrc, dataSrc, opts) {
647
467
  }
648
468
  const pair = new ConjunctVal_1.ConjunctVal({ peg: [meetAnchor, dataVal] }, ctx);
649
469
  const unified = aontu.unify(pair, undefined, ctx);
650
- // 4. Contradictions: every NilVal standing in the result, PLUS the
651
- // ones that never made it into the tree.
652
- //
653
- // The second half is not belt-and-braces. When a parent collapses to
654
- // a nil the whole subtree goes with it, so `service: close({...})`
655
- // meeting a typo AND a kind conflict leaves ONE nil in the tree and
656
- // reports the other only on the context — the vet verb's own
657
- // motivating example, reporting half of what it found. The language
658
- // server already walks both for this reason; vet dedups by identity
659
- // the same way, and skips the transient disjunct-trial sentinel,
660
- // which is bookkeeping rather than a finding.
661
470
  const seen = new Set();
662
471
  const nils = (0, walk_1.collectNils)(unified, seen);
663
472
  for (const err of ctx.err) {
@@ -670,44 +479,16 @@ function vet(schemaSrc, dataSrc, opts) {
670
479
  materialise(n, ctx);
671
480
  return findingOf(n, prov);
672
481
  });
673
- // 5. Incompleteness: what is left standing that cannot generate. The
674
- // generate check runs in its own collect context so nothing it
675
- // raises reaches the caller's error list, and so a schema that is
676
- // merely unsatisfied does not look like one that is contradicted.
677
- // No try/catch: in collect mode `gen` records its reasons on the
678
- // context instead of throwing, which is the whole point of the mode.
679
482
  const genCtx = aontu.ctx({ collect: true });
680
483
  genCtx.root = unified;
681
- // Under `--at` the probe descends through the OUTPUT marks: the
682
- // caller named this node as the truth to validate against, so a
683
- // `type()` or `hide()` on it (or propagated into it) is not a reason
684
- // to check nothing. See AontuContext.probe.
685
484
  genCtx.probe = null != options.at;
686
485
  unified.gen(genCtx);
687
486
  for (const err of genCtx.err) {
688
- // A CONFLICT RAISED AT GENERATION COUNTS TOO (the review's finding
689
- // C, use-cases/BUGS.md §16). The filter used to keep the
690
- // `incomplete` class alone, on the reading that step 4 had already
691
- // found every contradiction -- true while every conflict was
692
- // decided during the meet, and untrue since a sizing atom or a
693
- // container `must` may hold a PROVISIONAL reading until generation,
694
- // which is where no more members can arrive. Dropping those left
695
- // `vet` answering `valid` for data the evaluator refuses, which is
696
- // the one disagreement the vet-equals-eval harness exists to catch
697
- // -- and did.
698
- //
699
- // Deduped against step 4 by the same cause key the loop below uses,
700
- // so a contradiction seen twice is still reported once.
701
487
  if ('incomplete' === err.class || 'conflict' === err.class) {
702
488
  materialise(err, genCtx);
703
489
  findings.push(findingOf(err, prov));
704
490
  }
705
491
  }
706
- // 5b. Deprecation warnings (G3 phase 4): a value that carries the
707
- // deprecate() record after the meet was USED — the data met a
708
- // deprecated schema value, or the schema's own default will
709
- // generate one. Severity `warning` (the slot G2 reserved for
710
- // exactly this mark), and warnings never touch the verdict below.
711
492
  findings.push(...lintFindings);
712
493
  for (const { val, path } of (0, utility_1.collectDeprecations)(unified)) {
713
494
  const v = val;
@@ -735,27 +516,6 @@ function vet(schemaSrc, dataSrc, opts) {
735
516
  const keyed = findings.map((f, i) => ({ key: orderKey(f, i), finding: f }));
736
517
  keyed.sort((a, b) => a.key < b.key ? -1 : 1);
737
518
  let ordered = keyed.map((k) => k.finding);
738
- // ONE CAUSE, ONE FINDING. A reference resolves by CLONING its target,
739
- // so a target that later fails can fail once per referrer — same
740
- // code, same two source sites, a different path each time. Multi-pass
741
- // collection (G2 phase 6) made this reachable: the pass loop now
742
- // continues past the erroring pass, so the clones' own folds run too.
743
- // The dedup key is the CODE plus the SITES (file, row, col, value,
744
- // role): two findings that name the same meet of the same two source
745
- // positions are one contradiction observed from two paths. The key is
746
- // NOT (code, path) — the design's sketch — because the paths are
747
- // exactly what differ. Sorted order makes the kept finding the first
748
- // by data site then path, deterministically in both ports.
749
- //
750
- // THE KEPT PATH IS THE DEEPEST one (use-cases/BUGS.md §41). A meet
751
- // that fails inside a REFERENCED map is recorded twice: once at the
752
- // key that actually conflicts, and once at the enclosing map, which
753
- // collapsed as a consequence and carries the child's two sites. Both
754
- // are the same cause; only the deeper one names the field an author
755
- // or an agent has to edit, and `$.q` for a conflict in `$.q.a` sent a
756
- // repair loop to rewrite the whole record -- twice over, identically,
757
- // when two of its fields conflicted. Depth first, then the sort order
758
- // above, so the choice stays deterministic in both ports.
759
519
  const causeKey = (f) => f.code + '\u0000' + f.sites.map((s) => [s.file, s.row, s.col, s.role, s.value].join('\u0000')).join('\u0000');
760
520
  const depth = (f) => f.path.split('.').length;
761
521
  const deepest = new Map();
@@ -777,22 +537,6 @@ function vet(schemaSrc, dataSrc, opts) {
777
537
  });
778
538
  const truncated = maxErrors < ordered.length;
779
539
  const kept = truncated ? ordered.slice(0, maxErrors) : ordered;
780
- // 6. The verdict derives from finding CLASSES, never from codes, so a
781
- // new code can never change exit behaviour.
782
- //
783
- // BY CLASS, NOT BY STAGE. The split used to be positional -- whatever
784
- // step 4 found counted as contradiction and whatever step 5 added
785
- // counted as incompleteness -- which stopped being true when a sizing
786
- // atom or a container `must` began holding a provisional reading
787
- // until generation (the review's finding C, use-cases/BUGS.md §16). A
788
- // CONTRADICTION found at generation is still a contradiction: reading
789
- // it as mere incompleteness answered `incomplete` where the evaluator
790
- // refuses, and `vet` and `eval` have to agree.
791
- //
792
- // So: an error-severity finding that is not INCOMPLETENESS makes the
793
- // document invalid, wherever it was found -- a contradiction, a parse
794
- // refusal, an unresolvable reference alike. Warnings (the `compat`
795
- // class: lint and deprecation) never touch the verdict.
796
540
  let verdict = 'valid';
797
541
  const errors = ordered.filter((f) => 'error' === f.severity);
798
542
  const unmet = errors.filter((f) => 'incomplete' === f.class).length;
@@ -802,6 +546,9 @@ function vet(schemaSrc, dataSrc, opts) {
802
546
  else if (0 < unmet && true !== options.partial) {
803
547
  verdict = 'incomplete';
804
548
  }
805
- return { verdict, truncated, findings: kept };
549
+ return {
550
+ verdict, truncated, findings: kept,
551
+ ...(null == coverage ? {} : { coverage }),
552
+ };
806
553
  }
807
554
  //# sourceMappingURL=vet.js.map