aontu 0.62.0 → 0.64.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 (373) hide show
  1. package/README.md +7 -7
  2. package/dist/agentsmd.js +0 -27
  3. package/dist/agentsmd.js.map +1 -1
  4. package/dist/alias.js.map +1 -1
  5. package/dist/allow.js +0 -92
  6. package/dist/allow.js.map +1 -1
  7. package/dist/aontu.d.ts +3 -3
  8. package/dist/aontu.js +4 -84
  9. package/dist/aontu.js.map +1 -1
  10. package/dist/aontumodel.d.ts +4 -0
  11. package/dist/aontumodel.js +27 -0
  12. package/dist/aontumodel.js.map +1 -0
  13. package/dist/casing.d.ts +5 -0
  14. package/dist/casing.js +90 -0
  15. package/dist/casing.js.map +1 -0
  16. package/dist/cli.d.ts +2 -2
  17. package/dist/cli.js +228 -935
  18. package/dist/cli.js.map +1 -1
  19. package/dist/ctx.js +0 -48
  20. package/dist/ctx.js.map +1 -1
  21. package/dist/diff.js +0 -32
  22. package/dist/diff.js.map +1 -1
  23. package/dist/err.js +0 -40
  24. package/dist/err.js.map +1 -1
  25. package/dist/escape.js +0 -45
  26. package/dist/escape.js.map +1 -1
  27. package/dist/exactjson.d.ts +0 -35
  28. package/dist/exactjson.js +0 -131
  29. package/dist/exactjson.js.map +1 -1
  30. package/dist/format.js +13 -203
  31. package/dist/format.js.map +1 -1
  32. package/dist/grammar.d.ts +9 -0
  33. package/dist/grammar.js +54 -0
  34. package/dist/grammar.js.map +1 -0
  35. package/dist/graph.js +0 -26
  36. package/dist/graph.js.map +1 -1
  37. package/dist/hcanon.js +0 -82
  38. package/dist/hcanon.js.map +1 -1
  39. package/dist/helpdoc.js +2 -2
  40. package/dist/helpdoc.js.map +1 -1
  41. package/dist/hints.d.ts +0 -6
  42. package/dist/hints.js +57 -55
  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 +17 -915
  50. package/dist/lang.js.map +1 -1
  51. package/dist/lsp-server.js +0 -16
  52. package/dist/lsp-server.js.map +1 -1
  53. package/dist/lsp.d.ts +1 -1
  54. package/dist/lsp.js +12 -159
  55. package/dist/lsp.js.map +1 -1
  56. package/dist/mcp-server.js +0 -26
  57. package/dist/mcp-server.js.map +1 -1
  58. package/dist/mcp.js +0 -149
  59. package/dist/mcp.js.map +1 -1
  60. package/dist/mod-tool.js +16 -131
  61. package/dist/mod-tool.js.map +1 -1
  62. package/dist/mod.js +0 -162
  63. package/dist/mod.js.map +1 -1
  64. package/dist/patch.js +0 -217
  65. package/dist/patch.js.map +1 -1
  66. package/dist/profile.d.ts +9 -0
  67. package/dist/profile.js +28 -0
  68. package/dist/profile.js.map +1 -0
  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.js +0 -61
  76. package/dist/relation.js.map +1 -1
  77. package/dist/report-sarif.d.ts +0 -11
  78. package/dist/report-sarif.js +0 -28
  79. package/dist/report-sarif.js.map +1 -1
  80. package/dist/sig.js +0 -35
  81. package/dist/sig.js.map +1 -1
  82. package/dist/sigdecl.js +1 -1
  83. package/dist/sigdecl.js.map +1 -1
  84. package/dist/siggate.js +0 -4
  85. package/dist/siggate.js.map +1 -1
  86. package/dist/site.js +3 -29
  87. package/dist/site.js.map +1 -1
  88. package/dist/subsume.d.ts +0 -10
  89. package/dist/subsume.js +0 -137
  90. package/dist/subsume.js.map +1 -1
  91. package/dist/template.d.ts +2 -1
  92. package/dist/template.js +58 -138
  93. package/dist/template.js.map +1 -1
  94. package/dist/trace.d.ts +21 -0
  95. package/dist/trace.js +107 -0
  96. package/dist/trace.js.map +1 -0
  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 +13 -248
  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 +2 -0
  125. package/dist/val/CmpFuncVal.js +49 -72
  126. package/dist/val/CmpFuncVal.js.map +1 -1
  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.js +0 -3
  141. package/dist/val/EachFuncVal.js.map +1 -1
  142. package/dist/val/EmitFuncVal.d.ts +1 -1
  143. package/dist/val/EmitFuncVal.js +6 -119
  144. package/dist/val/EmitFuncVal.js.map +1 -1
  145. package/dist/val/ExpectVal.js +0 -62
  146. package/dist/val/ExpectVal.js.map +1 -1
  147. package/dist/val/FilterFuncVal.js +0 -25
  148. package/dist/val/FilterFuncVal.js.map +1 -1
  149. package/dist/val/FuncBaseVal.d.ts +1 -0
  150. package/dist/val/FuncBaseVal.js +7 -127
  151. package/dist/val/FuncBaseVal.js.map +1 -1
  152. package/dist/val/GraphAtomVal.js +0 -15
  153. package/dist/val/GraphAtomVal.js.map +1 -1
  154. package/dist/val/HideFuncVal.js +0 -13
  155. package/dist/val/HideFuncVal.js.map +1 -1
  156. package/dist/val/IntegerVal.js +0 -61
  157. package/dist/val/IntegerVal.js.map +1 -1
  158. package/dist/val/JunctionVal.js +0 -20
  159. package/dist/val/JunctionVal.js.map +1 -1
  160. package/dist/val/KeyFuncVal.js +0 -46
  161. package/dist/val/KeyFuncVal.js.map +1 -1
  162. package/dist/val/ListVal.js +0 -57
  163. package/dist/val/ListVal.js.map +1 -1
  164. package/dist/val/LowerFuncVal.js +0 -11
  165. package/dist/val/LowerFuncVal.js.map +1 -1
  166. package/dist/val/MapVal.js +0 -151
  167. package/dist/val/MapVal.js.map +1 -1
  168. package/dist/val/MatchFuncVal.js +0 -27
  169. package/dist/val/MatchFuncVal.js.map +1 -1
  170. package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
  171. package/dist/val/MaybeFuncVal.js +50 -0
  172. package/dist/val/MaybeFuncVal.js.map +1 -0
  173. package/dist/val/MoveFuncVal.js +0 -18
  174. package/dist/val/MoveFuncVal.js.map +1 -1
  175. package/dist/val/NilVal.js +0 -60
  176. package/dist/val/NilVal.js.map +1 -1
  177. package/dist/val/NomFuncVal.js +18 -54
  178. package/dist/val/NomFuncVal.js.map +1 -1
  179. package/dist/val/NumberVal.js +0 -15
  180. package/dist/val/NumberVal.js.map +1 -1
  181. package/dist/val/OpBaseVal.d.ts +1 -0
  182. package/dist/val/OpBaseVal.js +3 -15
  183. package/dist/val/OpBaseVal.js.map +1 -1
  184. package/dist/val/PackFuncVal.js +0 -34
  185. package/dist/val/PackFuncVal.js.map +1 -1
  186. package/dist/val/PathFuncVal.js +0 -6
  187. package/dist/val/PathFuncVal.js.map +1 -1
  188. package/dist/val/PathVal.js +0 -41
  189. package/dist/val/PathVal.js.map +1 -1
  190. package/dist/val/PlaceVal.js +0 -25
  191. package/dist/val/PlaceVal.js.map +1 -1
  192. package/dist/val/PlusOpVal.d.ts +1 -7
  193. package/dist/val/PlusOpVal.js +13 -74
  194. package/dist/val/PlusOpVal.js.map +1 -1
  195. package/dist/val/PrefFuncVal.js +0 -1
  196. package/dist/val/PrefFuncVal.js.map +1 -1
  197. package/dist/val/PrefVal.js +0 -167
  198. package/dist/val/PrefVal.js.map +1 -1
  199. package/dist/val/RecurseVal.js +0 -55
  200. package/dist/val/RecurseVal.js.map +1 -1
  201. package/dist/val/RefVal.js +0 -282
  202. package/dist/val/RefVal.js.map +1 -1
  203. package/dist/val/ReferFuncVal.js +3 -232
  204. package/dist/val/ReferFuncVal.js.map +1 -1
  205. package/dist/val/ScalarKindVal.js +0 -49
  206. package/dist/val/ScalarKindVal.js.map +1 -1
  207. package/dist/val/ScalarVal.js +0 -11
  208. package/dist/val/ScalarVal.js.map +1 -1
  209. package/dist/val/StrFuncVal.js +0 -18
  210. package/dist/val/StrFuncVal.js.map +1 -1
  211. package/dist/val/SuperFuncVal.js +0 -32
  212. package/dist/val/SuperFuncVal.js.map +1 -1
  213. package/dist/val/TopVal.js +0 -1
  214. package/dist/val/TopVal.js.map +1 -1
  215. package/dist/val/TranslateFuncVal.js +1 -3
  216. package/dist/val/TranslateFuncVal.js.map +1 -1
  217. package/dist/val/UpperFuncVal.js +0 -11
  218. package/dist/val/UpperFuncVal.js.map +1 -1
  219. package/dist/val/Val.d.ts +1 -0
  220. package/dist/val/Val.js +2 -133
  221. package/dist/val/Val.js.map +1 -1
  222. package/dist/val/VarVal.js +0 -12
  223. package/dist/val/VarVal.js.map +1 -1
  224. package/dist/val/arith.js +0 -37
  225. package/dist/val/arith.js.map +1 -1
  226. package/dist/val/caserange.js +0 -61
  227. package/dist/val/caserange.js.map +1 -1
  228. package/dist/val/members.js +0 -6
  229. package/dist/val/members.js.map +1 -1
  230. package/dist/val/numcmp.js +0 -11
  231. package/dist/val/numcmp.js.map +1 -1
  232. package/dist/val/numkind.js +0 -145
  233. package/dist/val/numkind.js.map +1 -1
  234. package/dist/val/valutil.js +0 -16
  235. package/dist/val/valutil.js.map +1 -1
  236. package/dist/vet.js +0 -461
  237. package/dist/vet.js.map +1 -1
  238. package/dist/view.js +0 -414
  239. package/dist/view.js.map +1 -1
  240. package/dist/walk.js +0 -41
  241. package/dist/walk.js.map +1 -1
  242. package/grammar/aontu.abnf +8 -6
  243. package/grammar/aontu.gbnf +4 -4
  244. package/grammar/aontu.lark +4 -4
  245. package/grammar/aontu.tmLanguage.json +1 -1
  246. package/package.json +4 -2
  247. package/skill/tasks.md +9 -7
  248. package/src/agentsmd.ts +0 -35
  249. package/src/alias.ts +0 -39
  250. package/src/allow.ts +1 -96
  251. package/src/aontu.ts +4 -116
  252. package/src/aontumodel.ts +26 -0
  253. package/src/casing.ts +95 -0
  254. package/src/cli.ts +258 -1024
  255. package/src/ctx.ts +0 -103
  256. package/src/diff.ts +0 -40
  257. package/src/err.ts +0 -40
  258. package/src/escape.ts +0 -46
  259. package/src/exactjson.ts +0 -131
  260. package/src/format.ts +14 -257
  261. package/src/grammar.ts +72 -0
  262. package/src/graph.ts +0 -61
  263. package/src/hcanon.ts +0 -82
  264. package/src/helpdoc.ts +2 -2
  265. package/src/hints.ts +69 -57
  266. package/src/jsonschema.ts +0 -123
  267. package/src/keyorder.ts +0 -42
  268. package/src/lang.ts +19 -931
  269. package/src/lsp-server.ts +0 -16
  270. package/src/lsp.ts +12 -180
  271. package/src/mcp-server.ts +0 -31
  272. package/src/mcp.ts +0 -169
  273. package/src/mod-tool.ts +18 -159
  274. package/src/mod.ts +0 -178
  275. package/src/patch.ts +0 -232
  276. package/src/profile.ts +42 -0
  277. package/src/provenance.ts +0 -183
  278. package/src/query.ts +0 -84
  279. package/src/reach.ts +0 -53
  280. package/src/relation.ts +0 -84
  281. package/src/report-sarif.ts +0 -48
  282. package/src/sig.ts +0 -35
  283. package/src/sigdecl.ts +1 -1
  284. package/src/siggate.ts +0 -30
  285. package/src/site.ts +3 -29
  286. package/src/subsume.ts +1 -161
  287. package/src/template.ts +69 -140
  288. package/src/trace.ts +157 -0
  289. package/src/trim.ts +0 -53
  290. package/src/type.ts +2 -45
  291. package/src/unify.ts +14 -257
  292. package/src/utility.ts +0 -31
  293. package/src/val/AbnfFuncVal.ts +181 -0
  294. package/src/val/AbsentVal.ts +54 -0
  295. package/src/val/AggFuncVal.ts +152 -188
  296. package/src/val/ArithFuncVal.ts +0 -20
  297. package/src/val/BagVal.ts +1 -78
  298. package/src/val/BigDecimalVal.ts +0 -16
  299. package/src/val/BigIntegerVal.ts +0 -16
  300. package/src/val/CloseFuncVal.ts +0 -9
  301. package/src/val/CmpFuncVal.ts +68 -184
  302. package/src/val/ConjunctVal.ts +0 -33
  303. package/src/val/ConstraintVal.ts +2 -537
  304. package/src/val/ContainerKindVal.ts +0 -18
  305. package/src/val/CopyFuncVal.ts +0 -5
  306. package/src/val/Decimal.ts +1 -185
  307. package/src/val/DeprecateFuncVal.ts +0 -10
  308. package/src/val/DisjunctVal.ts +0 -157
  309. package/src/val/EachFuncVal.ts +0 -40
  310. package/src/val/EmitFuncVal.ts +8 -208
  311. package/src/val/ExpectVal.ts +0 -62
  312. package/src/val/FilterFuncVal.ts +0 -55
  313. package/src/val/FuncBaseVal.ts +9 -130
  314. package/src/val/GraphAtomVal.ts +0 -42
  315. package/src/val/HideFuncVal.ts +0 -15
  316. package/src/val/IntegerVal.ts +0 -61
  317. package/src/val/JunctionVal.ts +0 -20
  318. package/src/val/KeyFuncVal.ts +0 -48
  319. package/src/val/ListVal.ts +0 -59
  320. package/src/val/LowerFuncVal.ts +0 -12
  321. package/src/val/MapVal.ts +0 -151
  322. package/src/val/MatchFuncVal.ts +0 -59
  323. package/src/val/MaybeFuncVal.ts +86 -0
  324. package/src/val/MoveFuncVal.ts +0 -20
  325. package/src/val/NilVal.ts +0 -60
  326. package/src/val/NomFuncVal.ts +10 -99
  327. package/src/val/NumberVal.ts +0 -16
  328. package/src/val/OpBaseVal.ts +4 -17
  329. package/src/val/PackFuncVal.ts +0 -63
  330. package/src/val/PathFuncVal.ts +0 -32
  331. package/src/val/PathVal.ts +0 -66
  332. package/src/val/PlaceVal.ts +0 -45
  333. package/src/val/PlusOpVal.ts +18 -75
  334. package/src/val/PrefFuncVal.ts +0 -1
  335. package/src/val/PrefVal.ts +0 -179
  336. package/src/val/RecurseVal.ts +0 -81
  337. package/src/val/RefVal.ts +1 -285
  338. package/src/val/ReferFuncVal.ts +4 -255
  339. package/src/val/ScalarKindVal.ts +0 -50
  340. package/src/val/ScalarVal.ts +0 -12
  341. package/src/val/StrFuncVal.ts +0 -44
  342. package/src/val/SuperFuncVal.ts +0 -42
  343. package/src/val/TopVal.ts +0 -1
  344. package/src/val/TranslateFuncVal.ts +1 -51
  345. package/src/val/UpperFuncVal.ts +0 -12
  346. package/src/val/Val.ts +3 -192
  347. package/src/val/VarVal.ts +0 -15
  348. package/src/val/arith.ts +0 -92
  349. package/src/val/caserange.ts +0 -62
  350. package/src/val/members.ts +0 -23
  351. package/src/val/numcmp.ts +1 -27
  352. package/src/val/numkind.ts +0 -149
  353. package/src/val/valutil.ts +0 -16
  354. package/src/vet.ts +1 -582
  355. package/src/view.ts +0 -507
  356. package/src/walk.ts +0 -41
  357. package/dist/lower.d.ts +0 -23
  358. package/dist/lower.js +0 -578
  359. package/dist/lower.js.map +0 -1
  360. package/dist/render.d.ts +0 -53
  361. package/dist/render.js +0 -547
  362. package/dist/render.js.map +0 -1
  363. package/dist/std.d.ts +0 -3
  364. package/dist/std.js +0 -672
  365. package/dist/std.js.map +0 -1
  366. package/dist/val/FormFuncVal.js +0 -55
  367. package/dist/val/FormFuncVal.js.map +0 -1
  368. package/dist/val/NamerFuncVal.d.ts +0 -12
  369. package/dist/val/NamerFuncVal.js +0 -176
  370. package/dist/val/NamerFuncVal.js.map +0 -1
  371. package/src/lower.ts +0 -636
  372. package/src/render.ts +0 -732
  373. package/src/std.ts +0 -683
package/src/view.ts CHANGED
@@ -1,45 +1,5 @@
1
1
  /* Copyright (c) 2026 Richard Rodger, MIT License */
2
2
 
3
- // THE VIEWS (docs/design/VIEWS.0.md and VIEWS-ORDER.0.md): figures of
4
- // an evaluated document, drawn as deterministic text a golden diff can
5
- // check. Nine kinds:
6
- //
7
- // doc the shape of the document itself
8
- // lattice the language's value lattice, with the document's own
9
- // values placed on it
10
- // tree the dependency tree of one relation
11
- // matrix the dependency matrix over one relation, in canon or
12
- // partition order, with closure and the unmirrored mark
13
- // graph the node-link drawing, as Mermaid, DOT or an ER diagram
14
- // layer the architecture layers: stacked bands, one per value of
15
- // a field, with the relation's upward edges called out
16
- // sets the set-intersection panel over a named set family
17
- // layers which document contributed which path (provenance)
18
- // ladder the meet ladder at one path (the `why` record, drawn)
19
- // poset the subsumption order over a set of documents
20
- //
21
- // A view consumes a REPORT, never the Val tree: the edge set `graphOf`
22
- // derives (ts/src/graph.ts), the relation declarations, the generated
23
- // value, the provenance record, the subsumption verdict. That is what
24
- // keeps the two ports at parity -- Go's exported Val interface is five
25
- // methods, and a Val-walking view would be TypeScript-only on the day
26
- // it landed.
27
- //
28
- // Everything here is deterministic: nodes and edges are sorted by code
29
- // point before emission, nothing iterates a map in insertion order, no
30
- // coordinate is computed and no number is formatted beyond its decimal
31
- // digits. The Go twin is go/view.go; what the two ports must agree on
32
- // -- the rendered text, the loss report and the refusals -- is
33
- // test/spec/view.tsv.
34
- //
35
- // EVERY RUN CARRIES A LOSS REPORT: what the figure could not draw, or
36
- // drew differently from the model, aggregated by code with a count.
37
- // Three codes are informational -- `edges_deduped` (several written
38
- // positions, one fact), `inverse_suppressed` (a declared mirror,
39
- // implied by the edge drawn) and `crossings` (a property of the
40
- // emitted order, not of the model) -- and leave the verdict `rendered`. Every
41
- // other code makes it `lossy`, which `--strict` refuses: a figure that
42
- // quietly omits things is the failure this capability exists to avoid.
43
3
 
44
4
  import { basename, dirname, isAbsolute, relative, resolve } from 'node:path'
45
5
 
@@ -71,52 +31,14 @@ export type ViewProfile = 'text' | 'mermaid' | 'dot' | 'er' | 'svg'
71
31
 
72
32
  export type ViewOrder = 'canon' | 'partition'
73
33
 
74
- // Which of the relation's edges the layer figure DRAWS. The bands
75
- // already say which way every edge goes, so the default shows the ones
76
- // that break the rule: `upward`. `all` draws the relation over the
77
- // bands -- what a reader tracing one module's dependencies wants --
78
- // and `none` leaves the bands alone. The default is `all` for a
79
- // profile that lays edges out itself (mermaid) and `upward` for the
80
- // fixed grids (text, svg), which is what each drew before the option
81
- // existed.
82
34
  export type ViewEdges = 'upward' | 'all' | 'none'
83
35
 
84
- // STYLING (VIEWS.0.md, "7. Styling"), which amends that note's colour
85
- // boundary. Every mark a figure makes already has a reason the
86
- // extractor established -- a cell is `direct` because the edge is
87
- // declared, an arrow is `upward` because it runs against the bands --
88
- // and the SVG profile has published those reasons as classes since it
89
- // landed, because an SVG cannot be drawn without saying what each
90
- // shape is. This declares the same vocabulary for the text profile and
91
- // adds the one thing missing: a way to turn it on at the call.
92
- //
93
- // NEITHER MECHANISM STATES A COLOUR, which is what keeps the boundary
94
- // intact. SGR 31 does not mean red; it means the colour the reader's
95
- // terminal calls red, which the reader chose. A CSS class states
96
- // nothing at all, and the stylesheet reads `var(--av-closure, ...)` so
97
- // a host page's palette wins. A hex triple is the thing that cannot
98
- // follow a theme, and it stays refused -- no truecolour escape, no
99
- // 256-colour escape, no `classDef`.
100
36
  export type ViewRole =
101
37
  'label' | 'muted' | 'rule' | 'direct' | 'closure' | 'unmirrored'
102
38
  | 'upward' | 'repeat' | 'bar' | 'hole'
103
39
 
104
- // `none` is plain characters, and an SVG carrying its classes but not
105
- // the embedded stylesheet -- what a host page wants once it has bound
106
- // the variables and is embedding eight figures. `ansi` is the text
107
- // profile's mechanism and `css` the SVG's; asking for either on the
108
- // wrong profile is a usage error.
109
- //
110
- // `auto` IS NOT HERE ON PURPOSE. Resolving it means knowing whether
111
- // the destination is a terminal, which err.ts already settles for the
112
- // error frames: a library cannot see its destination and a caller who
113
- // can is the only one who may decide. The CLI maps `auto`; `viewOf`
114
- // takes a resolved value, so every shared-spec row is deterministic.
115
40
  export type ViewStyle = 'none' | 'ansi' | 'css'
116
41
 
117
- // The text profile's mechanism: the eight named colours, `bold` and
118
- // `dim`, and nothing else. `label` is unstyled -- an entity's own name
119
- // is the figure's content, not a mark about it.
120
42
  const SGR: Record<ViewRole, string> = {
121
43
  label: '', muted: '2', rule: '2', direct: '1', closure: '36',
122
44
  unmirrored: '33', upward: '31', repeat: '2', bar: '36', hole: '2',
@@ -135,10 +57,6 @@ const ANSI: Paint = (role, text) =>
135
57
 
136
58
  const painter = (style: ViewStyle): Paint => 'ansi' === style ? ANSI : PLAIN
137
59
 
138
- // The style a figure gets when the caller named none. An SVG carries
139
- // its stylesheet, which is what makes it standalone and what every
140
- // pinned golden holds; everything else carries no mechanism, since a
141
- // library cannot see whether its output is a terminal.
142
60
  const styleOf = (
143
61
  style: ViewStyle | undefined, as: ViewProfile
144
62
  ): ViewStyle => style ?? ('svg' === as ? 'css' : 'none')
@@ -205,7 +123,6 @@ export type ViewSetReport = {
205
123
 
206
124
 
207
125
  export type ViewOptions = {
208
- // The figure to draw. Absent means `tree`.
209
126
  kind?: ViewKind
210
127
  // The target grammar. Absent means the kind's first profile.
211
128
  as?: ViewProfile
@@ -215,20 +132,11 @@ export type ViewOptions = {
215
132
  // The include capability this document evaluates under
216
133
  // (docs/trust.md).
217
134
  trust?: TrustOptions
218
- // The extensions an include additionally reads as text (the CLI's
219
- // --text-ext). It rides WITH the capability everywhere, never beside
220
- // it: both answer "what may an include read", and a verb that
221
- // threads one and not the other refuses under a flag the bare
222
- // command honours -- which is exactly what this verb did.
223
135
  textExt?: string[]
224
136
  // Restrict the figure to nodes (or paths) under this path. For the
225
137
  // ladder it is the path drawn, and required; for the poset it is
226
138
  // where the documents are compared.
227
139
  at?: string
228
- // Refuse a figure with more than this many rows (matrix rows, graph
229
- // and tree nodes, set rows, poset nodes, ladder rungs). Absent means
230
- // sixty. A REFUSAL, not a truncation: a view that quietly omits
231
- // things is the failure this capability exists to avoid.
232
140
  maxRows?: number
233
141
 
234
142
  // tree, matrix: draw OVER THIS RELATION. The tree draws every
@@ -268,7 +176,6 @@ export type ViewOptions = {
268
176
  // means three, which is the depth at which a model's shape is
269
177
  // legible and its data is not yet enumerated.
270
178
  depth?: number
271
- // sets: drop intersections below this degree.
272
179
  minDegree?: number
273
180
  // sets, layers: elide columns beyond this many, counted in the loss
274
181
  // report.
@@ -286,12 +193,6 @@ export type ViewOptions = {
286
193
  // document, only once every figure of the set rendered.
287
194
  out?: string
288
195
 
289
- // How the figure is styled (VIEWS.0.md, "7. Styling"). Absent means
290
- // `none`: plain characters, and an SVG carrying its classes without
291
- // the embedded stylesheet. THE CALLER RESOLVES `auto` -- see
292
- // ViewStyle. A figure written to a file is written plain whatever
293
- // this says, which the CLI enforces: a pinned golden with terminal
294
- // escapes in it is not a golden anybody can read.
295
196
  style?: ViewStyle
296
197
 
297
198
  // The VIEW DOCUMENT (VIEWS.0.md, "6. The view document"): the path of
@@ -352,11 +253,6 @@ function finding(
352
253
  }
353
254
 
354
255
 
355
- // A relation that draws nothing is a typo, and is refused for the same
356
- // reason a misspelled root is: an empty figure and a misspelled name
357
- // are the same file on disk, so the one that means nothing must not be
358
- // renderable. NOT `refer_unresolved`: a relation name is not an
359
- // address.
360
256
  function relationFinding(relation: string, have: string[]): VetFinding {
361
257
  return finding('view_relation_unknown', 'reference', '$',
362
258
  `${relation} names no relation with edges in this document.`,
@@ -364,10 +260,6 @@ function relationFinding(relation: string, have: string[]): VetFinding {
364
260
  }
365
261
 
366
262
 
367
- // A root is a node of the DRAWN graph, the rule the node set follows:
368
- // a path that exists in the document but takes no part in the relation
369
- // is not in the drawing, and a root naming it is refused rather than
370
- // drawn as an empty tree.
371
263
  function rootFinding(
372
264
  root: string, relation: string | undefined, nodes: string[]): VetFinding {
373
265
  return finding('refer_unresolved', 'reference', '$',
@@ -412,20 +304,6 @@ function under(path: string, at: string | undefined): boolean {
412
304
  }
413
305
 
414
306
 
415
- // The deduplicated edge set, with the hidden contributions and the
416
- // out-of-scope edges removed and the loss report told.
417
- //
418
- // `graphOf` emits one edge per WRITTEN POSITION by design, because each
419
- // `at` is an editable site, and an identity-merged model declares each
420
- // entity at two positions. Deduplication is part of the extraction
421
- // contract, not a renderer's private cleverness, and the count is
422
- // reported so nobody has to guess which number they are looking at.
423
- //
424
- // A HIDDEN edge -- one written inside a `hide()`-marked subtree -- is
425
- // not drawn. A figure is committed to a repository, so anything drawn
426
- // is disclosed, and the subtree's whole purpose is to say "not
427
- // output". It is reported with its path instead, and `--strict`
428
- // refuses the figure.
429
307
  function triplesOf(
430
308
  graph: Graph, at: string | undefined, loss: ViewLoss[]): Triple[] {
431
309
  const edges = graph.edges
@@ -450,10 +328,6 @@ function triplesOf(
450
328
  detail: hidden.sort(cmpCodePoint),
451
329
  })
452
330
  }
453
- // A link under an UNRESOLVED DISJUNCTION is not an edge (ADR-007),
454
- // and the figure says so rather than dropping it in silence: the
455
- // document has not decided, and a drawing that quietly picked an arm
456
- // would be inventing the decision.
457
331
  const undecided = (graph.disjunct ?? []).filter((p) => under(p, at))
458
332
  if (0 < undecided.length) {
459
333
  loss.push({
@@ -491,21 +365,6 @@ function nodesOf(triples: { from: string, to: string }[]): string[] {
491
365
  }
492
366
 
493
367
 
494
- // THE SHORTEST SUFFIX THAT IS STILL UNIQUE, as a node's visible label.
495
- //
496
- // A node's name IS its path (ADR-014), and the paths in a real model
497
- // are long: eight nodes labelled `$.catalog.domains.identity.services.auth`
498
- // and its siblings is a correct diagram nobody can read. The label is
499
- // therefore the fewest trailing segments that still tell this node from
500
- // every other in the same drawing -- `auth` where that is unambiguous,
501
- // `identity.auth` where it is not.
502
- //
503
- // The rule is a function of the node SET, so a drawing is deterministic
504
- // while two drawings of different slices may label the same node
505
- // differently -- which is correct, because uniqueness is a property of
506
- // the set being drawn. The search is unbounded on purpose: at the full
507
- // segment count the candidate is the whole path, which no other node
508
- // shares, so it always ends.
509
368
  function labelsOf(nodes: string[]): Map<string, string> {
510
369
  const segs = new Map<string, string[]>(
511
370
  nodes.map((n) => [n, n.replace(/^\$\.?/, '').split('.')]))
@@ -568,13 +427,6 @@ const widest = (ss: string[]): number =>
568
427
  // ---------------------------------------------------------------------
569
428
  // Identifiers and escapes (VIEWS.0.md, "The renderers and the profiles")
570
429
 
571
- // Injective by construction, with two disjoint prefixes and one
572
- // predicate: `n_` + the name when its first code point is an ASCII
573
- // letter and every code point is an ASCII letter, digit or `_`;
574
- // otherwise `nq_` + the name with every other code point replaced by
575
- // `_` and its lower-case hex. A code-point class test, not a regular
576
- // expression: pattern matching is the one subsystem with a stated
577
- // RE2-versus-RegExp divergence, and an encoder runs on every name.
578
430
  function ident(name: string): string {
579
431
  const letter = (c: number): boolean =>
580
432
  (65 <= c && c <= 90) || (97 <= c && c <= 122)
@@ -594,11 +446,6 @@ function ident(name: string): string {
594
446
  }
595
447
 
596
448
 
597
- // One pass, per code point, from a table keyed by DECIMAL CODE POINT.
598
- // Mermaid: numeric entities only, never HTML names, so there is no
599
- // name table to diverge; 124 is in it because `|` is the edge-label
600
- // delimiter. DOT: the two escapes that also make it impossible for user
601
- // text to forge DOT's own `\n` / `\l` / `\r` justification escapes.
602
449
  const MERMAID_ESC: Record<number, string> = {
603
450
  34: '#34;', 35: '#35;', 38: '#38;', 60: '#60;', 62: '#62;',
604
451
  123: '#123;', 124: '#124;', 125: '#125;',
@@ -614,24 +461,11 @@ function escape(text: string, table: Record<number, string>): string {
614
461
  return out
615
462
  }
616
463
 
617
- // U+000A, U+000D, U+2028 and U+2029: the four code points that end a
618
- // line somewhere.
619
464
  function hasLineBreak(text: string): boolean {
620
465
  return /[\n\r\u2028\u2029]/.test(text)
621
466
  }
622
467
 
623
468
 
624
- // ---------------------------------------------------------------------
625
- // SVG (VIEWS.0.md, "No SVG in v1" -- the phase after the text kinds)
626
- //
627
- // The cell-based kinds draw into SVG under the INTEGER RULE: every
628
- // coordinate is a whole number of a fixed cell -- 8 units per
629
- // character, 20 per line -- from the same counts that lay the text
630
- // figure out, so no font is measured and both ports emit the same
631
- // bytes. The reader's browser shapes the text; the geometry is ours.
632
- // A figure is standalone (its own style block, with default colours)
633
- // and themeable (every colour a CSS variable a host page can set).
634
-
635
469
  const CH = 8
636
470
  const LH = 20
637
471
  const PAD = 8
@@ -663,11 +497,6 @@ const svgEsc = (s: string): string => escape(s, SVG_ESC)
663
497
  function svgDoc(
664
498
  w: number, h: number, about: string, parts: string[], style: ViewStyle
665
499
  ): string {
666
- // The CLASSES are structure and are always written -- a rect that
667
- // does not say whether it is a direct cell or a closure cell is not
668
- // a figure. What `--style none` drops is the STYLESHEET, for a host
669
- // page that has already bound the variables and would otherwise
670
- // carry one copy of these rules per embedded figure.
671
500
  return [
672
501
  `<svg xmlns="http://www.w3.org/2000/svg" class="av" viewBox="0 0 ${w} ${h}" ` +
673
502
  `width="${w}" height="${h}" role="img" aria-label="${svgEsc(about)}">`,
@@ -700,25 +529,11 @@ function svgPath(d: string, cls: string): string {
700
529
  }
701
530
 
702
531
 
703
- // ---------------------------------------------------------------------
704
- // The tree
705
-
706
532
  // One edge as the tree draws it: a declared inverse pair collapsed to
707
533
  // one edge, and the label the branch carries.
708
534
  type Drawn = { from: string, to: string, label: string }
709
535
 
710
536
 
711
- // THE EDGE SET WITH DECLARED INVERSE PAIRS COLLAPSED to one logical
712
- // edge, the tree's way: a relation with a declared inverse arrives
713
- // twice -- once per direction -- and drawing it raw doubles every such
714
- // relation.
715
- //
716
- // WHAT IS NOT COLLAPSED IS A MUTUAL RELATION: `a dependsOn b` and `b
717
- // dependsOn a` are two facts under ONE key, and folding them into a
718
- // single undirected edge erases the shortest cycle a model can have.
719
- // The collapse is therefore per KEY PAIR rather than per node pair --
720
- // two keys facing each other are an inverse, one key facing itself is
721
- // a loop -- which is what makes `acyclic()`'s refusal drawable.
722
537
  function collapse(triples: Triple[], relation: string | undefined): Drawn[] {
723
538
  const pairs = new Map<string, Triple[]>()
724
539
  for (const e of triples) {
@@ -734,15 +549,6 @@ function collapse(triples: Triple[], relation: string | undefined): Drawn[] {
734
549
 
735
550
  const out: Drawn[] = []
736
551
  for (const group of pairs.values()) {
737
- // ONE KEY WINS THE PAIR, and every edge written under it stands.
738
- // The named relation wins; otherwise the code-point-least key,
739
- // which is arbitrary but stable. Keeping every edge under the
740
- // winner is what preserves a MUTUAL relation, while the losing keys
741
- // are the declared inverses, implied by the winner and not drawn
742
- // again. With a relation named, its inverse is implied and naming
743
- // both would double the label; without one, every key is shown,
744
- // because picking silently would hide that two predicates are in
745
- // play.
746
552
  const keys = keysOf(group)
747
553
  const named = undefined !== relation && keys.includes(relation)
748
554
  const winner = named ? (relation as string) : keys[0]
@@ -765,27 +571,6 @@ type Kid = { to: string, label: string }
765
571
  type Figure = { text?: string, errors?: VetFinding[] }
766
572
 
767
573
 
768
- // THE DEPENDENCY TREE: the drawn edges, walked from each root, indented.
769
- //
770
- // A dependency graph is a DAG and not a tree -- two modules may share a
771
- // dependency, and drawing that shared node once under each parent is
772
- // what makes `cargo tree` and `npm ls` readable rather than
773
- // exponential. So this is a SPANNING WALK with two honest marks: `(*)`
774
- // where a subtree is elided because the node was expanded earlier, and
775
- // `(cycle)` where an edge closes a loop. The first is routine in a
776
- // correct model -- a diamond is good engineering, not a fault. The
777
- // second cannot arise from a model whose relation declares
778
- // `acyclic()`, and is drawn rather than thrown because a renderer that
779
- // hangs on a hostile input is a renderer that cannot be pointed at one.
780
- //
781
- // Which nodes are roots is DERIVED, not asked for: a root is a node
782
- // nothing depends on. `roots` overrides that to draw named subtrees.
783
- // The order of everything -- roots, children, the choice of which
784
- // occurrence of a shared node is the expanded one -- follows the label
785
- // sort, so the drawing is a function of the model alone.
786
- // One drawn row of the tree, for the SVG: its depth, its text, the
787
- // mark after it, and the row of its parent (-1 for a root). A blank
788
- // separator between roots is `null`.
789
574
  type TreeRow = { depth: number, text: string, mark: string, parent: number }
790
575
 
791
576
 
@@ -794,11 +579,6 @@ function drawTree(
794
579
  as: ViewProfile, style: ViewStyle
795
580
  ): Figure {
796
581
  const paint = painter(style)
797
- // With a relation named, the tree is OVER THAT RELATION. A node-link
798
- // diagram can label each edge and so draw every relation at once; a
799
- // tree cannot without becoming unreadable, and walking two relations
800
- // as though they were one would draw a containment the model does
801
- // not state.
802
582
  const kept = undefined === relation
803
583
  ? all : all.filter((e) => e.label === relation)
804
584
 
@@ -827,10 +607,6 @@ function drawTree(
827
607
  list.sort((x, y) => cmpCodePoint(label(x.to), label(y.to)))
828
608
  }
829
609
 
830
- // The relation is named on the branch only where more than one is
831
- // drawn. Naming the single relation on every line of a tree that has
832
- // exactly one is noise; leaving it off where there are two would
833
- // hide which edge was walked.
834
610
  const many = 1 < new Set(kept.map((e) => e.label)).size
835
611
  const byLabel = (a: string, b: string): number =>
836
612
  cmpCodePoint(label(a), label(b))
@@ -844,10 +620,6 @@ function drawTree(
844
620
  named = [...new Set(roots)].sort(byLabel)
845
621
  }
846
622
  else {
847
- // A root is a node nothing depends on. A SELF-EDGE does not make a
848
- // node depended upon for this purpose: a module that names itself
849
- // would otherwise stop being a root and take its whole subtree out
850
- // of the drawing.
851
623
  const depended = new Set(
852
624
  kept.filter((e) => e.to !== e.from).map((e) => e.to))
853
625
  named = nodes.filter((n) => !depended.has(n)).sort(byLabel)
@@ -866,11 +638,6 @@ function drawTree(
866
638
  rows.push({ depth: 0, text: label(root), mark: '', parent: rows.length })
867
639
  expanded.add(root)
868
640
 
869
- // ITERATIVE, with the ancestor chain carried as a set that is added
870
- // to on the way down and removed from on the way up. A recursive
871
- // walk is O(depth) stack frames and a deep dependency chain is a
872
- // real shape, so the drawing of a model must not depend on how deep
873
- // the interpreter lets it go.
874
641
  const chain = new Set<string>([root])
875
642
  const stack: { node: string, prefix: string, at: number, row: number }[] =
876
643
  [{ node: root, prefix: '', at: 0, row: rows.length - 1 }]
@@ -910,13 +677,6 @@ function drawTree(
910
677
  draw(root)
911
678
  }
912
679
 
913
- // EVERY NODE IS DRAWN. A component whose nodes all depend on each
914
- // other has no node nothing depends on, so the derived roots miss it
915
- // entirely -- and a graph with roots elsewhere would drop it in
916
- // silence, which is the one thing a drawing must not do. The
917
- // least-labelled node left is taken as a root of its own, until
918
- // nothing is left. An explicitly named root is a request for one
919
- // subtree and is left alone.
920
680
  if (0 === roots.length) {
921
681
  for (const n of nodes) {
922
682
  if (!expanded.has(n)) {
@@ -933,10 +693,6 @@ function drawTree(
933
693
  }
934
694
 
935
695
 
936
- // The tree as SVG: one line per row, each node indented one unit per
937
- // depth, joined to its parent by a path that drops from the parent's
938
- // row and turns in to the child. The marks are muted text after the
939
- // label.
940
696
  function treeSvg(
941
697
  rows: (TreeRow | null)[], about: string, style: ViewStyle
942
698
  ): string {
@@ -966,42 +722,7 @@ function treeSvg(
966
722
  // ---------------------------------------------------------------------
967
723
  // The document tree
968
724
 
969
- // THE SHAPE OF THE MODEL ITSELF, which no other kind draws. Every
970
- // other figure here reads a REPORT -- the edge set, the provenance
971
- // record, the subsumption order -- and so can only draw a document
972
- // that has links, contributions or peers. A reader meeting a model for
973
- // the first time wants the plainer thing first: what is in it, and how
974
- // it is arranged.
975
- //
976
- // This is `get --keys --types` as a picture, and it reads the same
977
- // walk: map keys in code-point order, list indices in order, and a
978
- // leaf's KIND rather than its value -- the canon of a scalar's type,
979
- // not the scalar. Values are what the document is for; the shape is
980
- // what a reader needs before any of them mean anything.
981
- //
982
- // DEPTH IS A BOUND, NOT AN ELISION MARK. Below it the subtree is not
983
- // drawn and the row says how many keys were not drawn, because a tree
984
- // that stops without saying so is the one thing a structural drawing
985
- // must not be.
986
725
 
987
- // ---------------------------------------------------------------------
988
- // THE VALUE LATTICE, and where this document's values sit on it.
989
- //
990
- // THE SCAFFOLD IS THE LANGUAGE'S, NOT THE DOCUMENT'S: `top` at the
991
- // join, the four kind families under it, `path()` under `string`, the
992
- // four numeric leaves under `number`, and `nil` at the meet. Every
993
- // Aontu document is drawn against the SAME shape, which is what makes
994
- // two of these figures comparable -- and what makes this a view of the
995
- // language that a document annotates, rather than a picture assembled
996
- // out of whatever the document happened to contain.
997
- //
998
- // See docs/unification.md for what the ordering means.
999
-
1000
- // The scaffold: each kind and the one above it. The ENGINE decides
1001
- // which kind sits under which -- kindParent in ts/src/val/ScalarKindVal.ts,
1002
- // and its twin in go/scalar.go -- and a test in each port holds this
1003
- // table to it, so adding a kind to the engine makes the figure grow a
1004
- // node rather than quietly leave one out.
1005
726
  const LATTICE_PARENT: [string, string][] = [
1006
727
  ['string', 'top'],
1007
728
  ['path()', 'string'],
@@ -1014,12 +735,6 @@ const LATTICE_PARENT: [string, string][] = [
1014
735
  ['null', 'top'],
1015
736
  ]
1016
737
 
1017
- // The columns, left to right: the MINIMAL kinds, the ones with nothing
1018
- // under them. Everything else is drawn centred over the columns it
1019
- // covers, so this list alone fixes the figure's horizontal order -- and
1020
- // it puts the kinds that reach the bottom from higher up (`boolean`,
1021
- // `null`) on the outside, where their lines pass the numeric fan
1022
- // rather than crossing it.
1023
738
  const LATTICE_COLS =
1024
739
  ['path()', 'integer', 'float', 'biginteger', 'bigdecimal', 'boolean',
1025
740
  'null']
@@ -1050,10 +765,6 @@ function latticeAncestors(name: string): string[] {
1050
765
  return out
1051
766
  }
1052
767
 
1053
- // The columns one node covers: its own if it is minimal, otherwise
1054
- // every column beneath it. `nil` is beneath everything and above
1055
- // nothing, so the walk finds no column under it and the whole width is
1056
- // its span -- which is where it belongs.
1057
768
  function latticeSpan(name: string): number[] {
1058
769
  const own = LATTICE_COLS.indexOf(name)
1059
770
  if (-1 !== own) {
@@ -1065,10 +776,6 @@ function latticeSpan(name: string): number[] {
1065
776
  return 0 === under.length ? LATTICE_COLS.map((_, i) => i) : under
1066
777
  }
1067
778
 
1068
- // True when `parent` is immediately above `child`. NIL IS COVERED BY
1069
- // EVERY MINIMAL KIND: it is the meet of all of them, and the only node
1070
- // the parent table does not name, because nothing in the engine ever
1071
- // answers `nil` as a superior.
1072
779
  function latticeCovers(parent: string, child: string): boolean {
1073
780
  return 'nil' === child
1074
781
  ? -1 !== LATTICE_COLS.indexOf(parent)
@@ -1076,18 +783,6 @@ function latticeCovers(parent: string, child: string): boolean {
1076
783
  }
1077
784
 
1078
785
 
1079
- // WHERE ONE VALUE SITS, or undefined for a value that is not at a
1080
- // single point. The answers are the kinds of thing a document holds:
1081
- //
1082
- // a CONCRETE scalar sits at its kind -- `8080` is an `integer`, and
1083
- // `superior()` is the lattice's own answer to which;
1084
- // a KIND MARKER sits AT that kind -- `integer` written as a schema
1085
- // is the node itself, not a value under it;
1086
- // everything else -- a constraint, an unresolved disjunction, a
1087
- // reference -- is not one point. `integer & min(1)` is a REGION of
1088
- // the lattice and `*8080 | integer` is two places at once, so
1089
- // drawing either at a node would be a claim the figure cannot
1090
- // support. Both are counted into the loss report instead.
1091
786
  function latticePoint(v: any): string | undefined {
1092
787
  const node: any = throughDoc(v)
1093
788
  if (true === node?.isNil) {
@@ -1096,10 +791,6 @@ function latticePoint(v: any): string | undefined {
1096
791
  if (true === node?.isTop) {
1097
792
  return 'top'
1098
793
  }
1099
- // A kind marker names its own node; a concrete scalar names the node
1100
- // above it. Either way the name has to BE one of the figure's: a
1101
- // kind the scaffold does not draw has nowhere to go, and saying so
1102
- // through the loss report is the only honest answer.
1103
794
  const name: string = true === node?.isScalarKind ? String(node.canon)
1104
795
  : true === node?.isScalar ? String(node.superior?.().canon) : ''
1105
796
  return LATTICE_NODES.includes(name) ? name : undefined
@@ -1151,22 +842,11 @@ function latticeCensus(root: any, at: string):
1151
842
  }
1152
843
 
1153
844
 
1154
- // What one node is written as: its name, and the count of the
1155
- // document's values that landed on it. A node with nothing at it is
1156
- // still drawn -- the shape is the language's, and a figure that left
1157
- // the empty nodes out would be a different lattice for every document.
1158
845
  function latticeCell(counts: Map<string, string[]>, name: string): string {
1159
846
  const n = (counts.get(name) ?? []).length
1160
847
  return 0 === n ? name : `${name} (${n})`
1161
848
  }
1162
849
 
1163
- // The horizontal layout, in characters: one column per minimal kind,
1164
- // each as wide as the widest cell drawn over it plus a gutter, and the
1165
- // centre of each. The spanning nodes are narrower than the span they
1166
- // cover, so none of them needs a width of its own. The gutter is THREE
1167
- // because the SVG draws a box a character wider than its text: two of
1168
- // those characters are the box's own padding and the third is the gap
1169
- // between one box and the next.
1170
850
  const LATTICE_GUTTER = 3
1171
851
 
1172
852
  function latticeCols(counts: Map<string, string[]>):
@@ -1194,13 +874,6 @@ function latticeAt(name: string, cx: number[]): number {
1194
874
  }
1195
875
 
1196
876
 
1197
- // The box-drawing glyph for one column of a rule, from the four facts
1198
- // that meet there: whether the rule continues left and right, and
1199
- // whether a stem leaves upward and downward. Deciding it this way is
1200
- // what lets `number` -- which is BOTH one of the many under `top` and
1201
- // the one above the numeric leaves -- come out as the join it is,
1202
- // without a case written for it. The table is total, so no column has
1203
- // to be asked whether it has a glyph.
1204
877
  const LATTICE_GLYPH: Record<string, string> = {
1205
878
  '....': '─', '...d': '│', '..u.': '│', '..ud': '│',
1206
879
  '.r..': '─', '.r.d': '┌', '.ru.': '└', '.rud': '├',
@@ -1208,10 +881,6 @@ const LATTICE_GLYPH: Record<string, string> = {
1208
881
  'lr..': '─', 'lr.d': '┬', 'lru.': '┴', 'lrud': '┼',
1209
882
  }
1210
883
 
1211
- // The figure is PAINTED rather than assembled from padded strings: the
1212
- // nodes have to line up with the rules that join them, and a count
1213
- // changes a cell's width -- so the geometry is settled first, in
1214
- // columns, and every glyph is then written at a place already known.
1215
884
  function latticeText(counts: Map<string, string[]>, style: ViewStyle): string {
1216
885
  const paint = painter(style)
1217
886
  const { cx, width } = latticeCols(counts)
@@ -1227,9 +896,6 @@ function latticeText(counts: Map<string, string[]>, style: ViewStyle): string {
1227
896
  roles[y][x + i] = role
1228
897
  }
1229
898
  }
1230
- // A cell is its name and, where the document reached it, the count:
1231
- // two roles, so a terminal can mute the second without touching the
1232
- // first.
1233
899
  const cell = (y: number, name: string) => {
1234
900
  const text = latticeCell(counts, name)
1235
901
  const left = latticeAt(name, cx) - Math.floor(text.length / 2)
@@ -1256,9 +922,6 @@ function latticeText(counts: Map<string, string[]>, style: ViewStyle): string {
1256
922
  stems(y, by)
1257
923
  }
1258
924
 
1259
- // Four node rows and three joins. `open` is every node whose line
1260
- // downward has not been drawn yet, which is what carries `boolean`
1261
- // and `null` past the numeric row to the bottom rule.
1262
925
  let open: string[] = []
1263
926
  let y = 0
1264
927
  for (let r = 0; r < LATTICE_ROWS.length; r++) {
@@ -1296,14 +959,6 @@ function latticeText(counts: Map<string, string[]>, style: ViewStyle): string {
1296
959
  }
1297
960
 
1298
961
 
1299
- // The same figure as SVG, off the same column layout, so the two
1300
- // profiles are one drawing in two grammars rather than two drawings.
1301
- // A node the document REACHES is drawn with the ordinary rule stroke
1302
- // (`av-box`) and one it does not with the faint one (`av-cell`),
1303
- // because every node is drawn whether this document reaches it or not
1304
- // and a reader has to see which is which without counting. NO NEW
1305
- // CLASS: those two already mean a box and a faint box, so a host page
1306
- // that themed the other figures gets this one for nothing.
1307
962
  function latticeSvg(
1308
963
  counts: Map<string, string[]>, at: string, style: ViewStyle
1309
964
  ): string {
@@ -1317,11 +972,6 @@ function latticeSvg(
1317
972
  const y = (name: string): number =>
1318
973
  PAD + BOXH / 2 + (rowOf.get(name) as number) * ROWH
1319
974
 
1320
- // Edges first, so a box always sits over the lines that reach it.
1321
- // The horizontal jog is placed just above the CHILD rather than
1322
- // halfway down, which is what keeps `boolean` and `null` -- three
1323
- // rows from `top` to `nil` with nothing between -- clear of the
1324
- // numeric row they pass.
1325
975
  const edges: [string, string][] = [...LATTICE_PARENT,
1326
976
  ...LATTICE_COLS.map((col): [string, string] => ['nil', col])]
1327
977
  for (const [child, parent] of edges) {
@@ -1335,9 +985,6 @@ function latticeSvg(
1335
985
  const w = (text.length + 2) * CH
1336
986
  parts.push(svgRect(x(name) - w / 2, y(name) - BOXH / 2, w, BOXH,
1337
987
  name === text ? 'av-cell' : 'av-box'))
1338
- // The name and the count in ONE text element, as the tree does it:
1339
- // two runs on one baseline, so the count is muted without the
1340
- // figure having to place it.
1341
988
  parts.push(`<text x="${x(name)}" y="${y(name) + 5}" text-anchor="middle">` +
1342
989
  `<tspan class="av-t">${svgEsc(name)}</tspan>` +
1343
990
  `<tspan class="av-m">${svgEsc(text.slice(name.length))}</tspan></text>`)
@@ -1350,11 +997,6 @@ function latticeSvg(
1350
997
  }
1351
998
 
1352
999
 
1353
- // The figure. The row count is fixed -- the lattice is the language's,
1354
- // and no option makes it smaller -- so `--max-rows` below it is still a
1355
- // refusal, because a figure that quietly overran a stated bound is the
1356
- // thing every other kind here refuses to be; the message says raise
1357
- // rather than narrow.
1358
1000
  const LATTICE_LINES = 3 * LATTICE_ROWS.length - 2
1359
1001
 
1360
1002
  function drawLattice(
@@ -1406,13 +1048,6 @@ const DEFAULT_DOC_DEPTH = 3
1406
1048
  function docKids(v: any): string[] {
1407
1049
  const node: any = throughDoc(v)
1408
1050
  if (true === node?.isMap) {
1409
- // AN ALIAS DECLARATION IS NOT PART OF THE DOCUMENT
1410
- // (docs/reference-language.md, "Aliases"): it does not generate
1411
- // and it does not appear in canon. It IS a key of the root map in
1412
- // the value tree, which `get --keys` reports and this does not --
1413
- // a figure of the document's shape that showed `%Cents` beside
1414
- // `customers` would be drawing the declaration as data
1415
- // (use-cases/BUGS.md 74).
1416
1051
  return Object.keys(node.peg)
1417
1052
  .filter((k) => !k.startsWith('%')).sort(cmpCodePoint)
1418
1053
  }
@@ -1437,13 +1072,6 @@ function throughDoc(v: any): any {
1437
1072
  // is the constraint and for a scalar its value. Long canons are cut,
1438
1073
  // since the figure is the shape and not the data.
1439
1074
  function docLeaf(v: any): string {
1440
- // A CONTAINER WITH NOTHING IN IT IS NOT A LEAF, and calling it one
1441
- // by writing nothing after the key would make it read as a value the
1442
- // figure declined to describe. Its canon says what it is -- `{}`,
1443
- // `[]`, or a template a spread wrote and no member filled.
1444
- //
1445
- // `canon` is a string on every Val, so there is no other-type arm to
1446
- // take; the cut is the only decision here.
1447
1075
  const canon: string = throughDoc(v).canon
1448
1076
  return 32 < canon.length ? canon.slice(0, 29) + '...' : canon
1449
1077
  }
@@ -1492,11 +1120,6 @@ function drawDoc(
1492
1120
  const child = throughDoc(throughDoc(frame.node).peg[key])
1493
1121
  const kids = docKids(child)
1494
1122
  const under = stack.length < depth
1495
- // A container the depth bound stops at says how many keys are not
1496
- // drawn; a leaf says what it is.
1497
- // A leaf says what it is and a stopped container says how many
1498
- // keys it holds; both are written after the key with one space,
1499
- // and neither is ever empty (a canon has at least one character).
1500
1123
  const mark = 0 === kids.length ? ' ' + docLeaf(child)
1501
1124
  : under ? '' : ` (${kids.length})`
1502
1125
  if (0 < kids.length && !under) {
@@ -1533,15 +1156,6 @@ function drawDoc(
1533
1156
  // ---------------------------------------------------------------------
1534
1157
  // The matrix (Ghoniem et al. 2004; Sangal et al. 2005)
1535
1158
 
1536
- // THE PARTITION ORDER: leaves first. Repeatedly take every unplaced
1537
- // node whose every successor is placed, in label order, as the next
1538
- // layer. That is a topological sort with a canonical tiebreak, and on
1539
- // an acyclic relation it yields a perfect lower triangle -- which IS
1540
- // the acyclicity proof, in the picture's own shape. Where nothing can
1541
- // be placed the relation has a cycle: the least unplaced node is
1542
- // placed alone, the strongly connected component it sits in is
1543
- // reported as `cycle_block`, and the walk continues -- the cycle's
1544
- // above-diagonal cell is then the acyclicity violation, drawn.
1545
1159
  function partition(
1546
1160
  nodes: string[], succ: Map<string, string[]>,
1547
1161
  reach: Map<string, Set<string>>, label: (n: string) => string,
@@ -1576,9 +1190,6 @@ function partition(
1576
1190
  }
1577
1191
 
1578
1192
 
1579
- // The relation a matrix draws: the one named, else the only one with
1580
- // edges, else a refusal -- a matrix over two predicates at once would
1581
- // draw a containment the model does not state.
1582
1193
  function pickRelation(
1583
1194
  relation: string | undefined, keys: string[]
1584
1195
  ): { relation?: string, error?: VetFinding } {
@@ -1696,11 +1307,6 @@ const CELL_CLASS: Record<string, string> = {
1696
1307
  '.': 'av-cell', '\\': 'av-cell',
1697
1308
  }
1698
1309
 
1699
- // The same five states as ROLES, for the text profile. One table per
1700
- // mechanism rather than one shared one, because the two vocabularies
1701
- // are not in step: SVG needs a class for the empty cell (it draws a
1702
- // rect there) and the text profile has nothing to say about a `.`
1703
- // beyond that it is not a mark.
1704
1310
  const CELL_ROLE: Record<string, ViewRole> = {
1705
1311
  X: 'direct', '!': 'unmirrored', '+': 'closure',
1706
1312
  '.': 'muted', '\\': 'rule',
@@ -1863,9 +1469,6 @@ function drawGraph(
1863
1469
  || cmpCodePoint(node(a.to).label, node(b.to).label)
1864
1470
  || cmpCodePoint(a.key, b.key))
1865
1471
 
1866
- // Crossings in the emitted order: two edges cross when their spans
1867
- // interleave. A count, not a layout -- the consumer lays the picture
1868
- // out, and this says how tangled the order it is handed is.
1869
1472
  let crossings = 0
1870
1473
  const span = (e: GEdge): [number, number] => {
1871
1474
  const a = at.get(e.from) as number
@@ -1923,14 +1526,6 @@ function drawGraph(
1923
1526
  out.push('}')
1924
1527
  }
1925
1528
  else {
1926
- // Entity relationships, as Mermaid's own erDiagram. Cardinality is
1927
- // not something the model states, so every relationship is drawn
1928
- // many-to-many and the label carries the predicate: drawing a
1929
- // cardinality the model does not assert would be an invention. An
1930
- // erDiagram has no separate label -- the identifier IS what the
1931
- // reader sees -- so it is the encoded label, unique by the label
1932
- // rule. Every node is in some relationship, since the node set is
1933
- // what the edges connect.
1934
1529
  const esc = (s: string): string => escape(s, MERMAID_ESC)
1935
1530
  out.push('erDiagram')
1936
1531
  for (const e of drawn) {
@@ -1947,19 +1542,6 @@ function drawGraph(
1947
1542
  type Band = { name: string, nodes: GNode[] }
1948
1543
 
1949
1544
 
1950
- // THE LAYER DIAGRAM every architecture document has a hand-drawn
1951
- // version of: one band per layer, the layers stacked with the one
1952
- // nothing depends on at the top, each module in its band, and the
1953
- // rule -- dependencies point DOWN -- read off the bands. The band a
1954
- // node belongs to is the value of `--group-by`; the order of the
1955
- // bands is DERIVED from the relation, as the partition order over the
1956
- // layer-level graph (a layer depends on the layers its modules depend
1957
- // on), so it is a function of the model and not of a list somebody has
1958
- // to keep in step with it -- unless the model has an upward edge, when
1959
- // the layer graph is cyclic and no order is derivable, which is what
1960
- // `--layers` (top first) is for. A sideways edge (within one band) is
1961
- // ordinary engineering and counted; an UPWARD edge is the violation
1962
- // the drawing exists to show, and is named under the figure.
1963
1545
  function drawLayer(
1964
1546
  triples: Triple[], root: any,
1965
1547
  o: {
@@ -2082,9 +1664,6 @@ function drawLayer(
2082
1664
  }
2083
1665
  const out: string[] = []
2084
1666
  if ('svg' === o.as) {
2085
- // The description says WHAT WAS DRAWN, because two layer figures of
2086
- // one model on one page differ by exactly that, and a reader who
2087
- // cannot see them has only this to tell them apart.
2088
1667
  const drew = 'all' === edges
2089
1668
  ? `${shown.length} edges drawn, ${upward} of them upward`
2090
1669
  : 'none' === edges
@@ -2146,14 +1725,6 @@ function drawLayer(
2146
1725
  type Drawing = { edge: GEdge, way: 'downward' | 'sideways' | 'upward' }
2147
1726
 
2148
1727
 
2149
- // The layers as SVG: one band per row, its modules as boxes laid left
2150
- // to right, and every SHOWN edge drawn between them -- an upward one
2151
- // dashed and alert-coloured, because it is the violation the bands
2152
- // cannot show on their own; a downward one straight down from the
2153
- // bottom of its box to the top of the one it names; a sideways one
2154
- // dipped below the boxes, since two modules of one band sit on the
2155
- // same line and a straight edge between them would cross whatever
2156
- // stands between.
2157
1728
  function layerSvg(
2158
1729
  bands: Band[], shown: Drawing[], footer: string[], about: string,
2159
1730
  style: ViewStyle
@@ -2514,20 +2085,10 @@ function drawLayers(
2514
2085
  },
2515
2086
  max: number, loss: ViewLoss[]
2516
2087
  ): Figure {
2517
- // Every path something met at AND THE DOCUMENT HAS A VALUE AT,
2518
- // mapped to the documents that met there. A meet can happen at a
2519
- // position the finished document does not have -- a template's own
2520
- // child, folded into each key it is spread over -- and the panel is
2521
- // about the document, so only its paths are rows. A path is shown
2522
- // as `a.b.c`; the root as `$`.
2523
2088
  const members = new Map<string, Set<string>>()
2524
2089
  const paths: string[] = []
2525
2090
  const atParts = undefined === o.at ? [] : pathParts(o.at)
2526
2091
  for (const [key, rec] of prov.paths) {
2527
- // A record at a position the document does not have is the Go
2528
- // recorder's template ghost (use-cases/BUGS.md 70); this port's
2529
- // recorder does not write one, and the two ports must skip the
2530
- // same rows.
2531
2092
  if (0 === rec.conjuncts.length || null == anchorAt(root, '$.' + key)) {
2532
2093
  continue
2533
2094
  }
@@ -2578,13 +2139,6 @@ function drawLayers(
2578
2139
  // ---------------------------------------------------------------------
2579
2140
  // The meet ladder (VIEWS-ORDER.0.md)
2580
2141
 
2581
- // The descent from `top` through each contribution to the resolved
2582
- // value, one rung per conjunct. Where the contributions are ranked
2583
- // preferences the ladder IS the arbitration: fewer stars win, so the
2584
- // rungs read weakest-first and the winner is the last before the
2585
- // value. `why`'s record is in source order, which is not rank order,
2586
- // so the rungs are SORTED -- an emitter that trusted the record would
2587
- // draw an arbitration that did not happen.
2588
2142
  function drawLadder(
2589
2143
  src: string, options: ViewOptions, as: ViewProfile, max: number
2590
2144
  ): Figure {
@@ -2653,17 +2207,6 @@ type Doc = ViewPosetDoc
2653
2207
  type Cls = { members: number[], label: string }
2654
2208
 
2655
2209
 
2656
- // The order over a document set, in the design's five steps: the
2657
- // verdict matrix; the quotient by MUTUAL subsumption (two documents
2658
- // that subsume each other are one node -- mandatory, since without it
2659
- // the relation is not antisymmetric and the cover relation is
2660
- // undefined); the closure, then the cover relation over the closure;
2661
- // and a canonical order, so the result does not depend on the order the
2662
- // files were given.
2663
- // One pairwise comparison: does the general document admit everything
2664
- // the specific one does? `subsume`, with the poset's anchor and
2665
- // profile; a parameter so a test can hand the drawing a verdict matrix
2666
- // the checker cannot be made to produce.
2667
2210
  export type ViewCompare = (
2668
2211
  general: Doc, specific: Doc, options: ViewOptions
2669
2212
  ) => { verdict: string, code: string }
@@ -2749,11 +2292,6 @@ function drawPoset(
2749
2292
  if (!closure[lo][hi]) {
2750
2293
  continue
2751
2294
  }
2752
- // A pair the closure implies but the checker measured as
2753
- // `does_not_subsume` is reported rather than absorbed: the
2754
- // measured relation is a conservative under-approximation, and
2755
- // an under-approximation of a transitive relation need not be
2756
- // transitive.
2757
2295
  if ('does_not_subsume' === verdict[rep(hi)][rep(lo)]) {
2758
2296
  intransitive.push(`${classes[lo].label} < ${classes[hi].label}`)
2759
2297
  }
@@ -2931,12 +2469,6 @@ export function view(
2931
2469
  `profiles: ${profiles.join(', ')}`)],
2932
2470
  })
2933
2471
  }
2934
- // ONE MECHANISM PER PROFILE (VIEWS.0.md, "7. Styling"). `ansi` is
2935
- // the text profile's and `css` the SVG's; asking for one on a
2936
- // profile that has no way to carry it is a usage error rather than a
2937
- // silent no-op, so a script that asks for colour and gets none is
2938
- // told why. `none` is always available -- it is the absence of a
2939
- // mechanism.
2940
2472
  const style: ViewStyle = styleOf(options.style, as)
2941
2473
  const carrier: Record<string, ViewProfile> = { ansi: 'text', css: 'svg' }
2942
2474
  if (undefined !== carrier[style] && carrier[style] !== as) {
@@ -2980,13 +2512,6 @@ export function view(
2980
2512
  }
2981
2513
 
2982
2514
 
2983
- // THE KINDS THAT DRAW FROM A LOADED MODEL, so a view document can load
2984
- // once and draw N figures from the one evaluation. `gen` is the
2985
- // generated value where the caller already holds it -- a view document
2986
- // reads its own declarations out of one -- and undefined where the set
2987
- // panel must generate its own. It is a BOX rather than the value, so
2988
- // that a document generating `undefined` is still a value the panel
2989
- // has rather than one it must recompute.
2990
2515
  function drawLoaded(
2991
2516
  root: any, ctx: any, gen: { value: any } | undefined,
2992
2517
  prov: Provenance | undefined,
@@ -3066,20 +2591,6 @@ export function viewTree(src: string, opts?: ViewOptions): ViewReport {
3066
2591
  }
3067
2592
 
3068
2593
 
3069
- // ---------------------------------------------------------------------
3070
- // The view document (VIEWS.0.md, "6. The view document")
3071
- //
3072
- // A projection that runs in CI belongs in a file. A view document is an
3073
- // ORDINARY document that includes the model and declares its figures as
3074
- // data; `views` is the AUTHOR's key and nothing here knows the name
3075
- // (ADR-010), which is why `--views` names the path.
3076
- //
3077
- // The declaration keys ARE the library's option names, which are the
3078
- // CLI's flag names without the dashes: one vocabulary, three doors. A
3079
- // declaration must name its `kind` and its `out` -- a figure in a file
3080
- // that a review reads should say what it draws and where it goes,
3081
- // rather than inheriting a default from whoever ran the verb.
3082
-
3083
2594
  const DECL_TEXT = [
3084
2595
  'kind', 'as', 'out', 'at', 'relation', 'order', 'groupBy', 'label',
3085
2596
  'sets', 'member', 'universe', 'edges',
@@ -3105,9 +2616,6 @@ function documentFinding(path: string, message: string, note?: string): VetFindi
3105
2616
  }
3106
2617
 
3107
2618
 
3108
- // One validated declaration: everything the drawing needs, decided
3109
- // before any figure is drawn, so a document with three bad
3110
- // declarations reports three faults rather than the first.
3111
2619
  type Plan = {
3112
2620
  name: string
3113
2621
  kind: ViewKind
@@ -3183,9 +2691,6 @@ function planOf(name: string, decl: any, at: string): {
3183
2691
  'kinds: ' + Object.keys(PROFILES).join(', ')))
3184
2692
  }
3185
2693
  else if ('poset' === kind) {
3186
- // The poset is an order over SEVERAL documents, and a view document
3187
- // declares figures of the one it includes. `aontu view poset` draws
3188
- // it, naming the documents on the command line.
3189
2694
  errors.push(documentFinding(`${where}.kind`,
3190
2695
  'A view document draws figures of one document; ' +
3191
2696
  'the poset compares several.'))
@@ -3219,13 +2724,6 @@ function planOf(name: string, decl: any, at: string): {
3219
2724
  }
3220
2725
 
3221
2726
 
3222
- // N FIGURES OF ONE DOCUMENT. The document is evaluated ONCE, with the
3223
- // provenance recorder on, and every figure but the ladder draws from
3224
- // that one root; the ladder re-runs `why` by construction.
3225
- //
3226
- // The caller writes the files, and only when the whole set rendered:
3227
- // N figures of one model are only meaningful together, so a set whose
3228
- // third figure refuses must not leave the first two on disk.
3229
2727
  export function viewSet(
3230
2728
  src: string, opts?: ViewOptions, hooks?: ViewHooks
3231
2729
  ): ViewSetReport {
@@ -3238,11 +2736,6 @@ export function viewSet(
3238
2736
  'the map that declares the figures; name it with --views.')],
3239
2737
  }
3240
2738
  }
3241
- // ONE EVALUATION, and it is INSTRUMENTED: the layers panel reads the
3242
- // provenance record, which is written during unification, so a set
3243
- // that declares one would otherwise need a second run. Recording it
3244
- // always costs a little and makes the one-evaluation claim true for
3245
- // every kind but the ladder, which re-runs `why` by construction.
3246
2739
  const prov = (hooks?.provenance ?? (() => new Provenance()))()
3247
2740
  const loaded = load(src, options.path, options, prov)
3248
2741
  if (undefined !== loaded.errors) {