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/src/ctx.ts CHANGED
@@ -16,7 +16,6 @@ import {
16
16
  } from './err'
17
17
 
18
18
 
19
-
20
19
  type AontuContextConfig = {
21
20
  cc?: number
22
21
  err?: any[] // Omit<NilVal[], "push">
@@ -27,12 +26,6 @@ type AontuContextConfig = {
27
26
  // error list is, so one run has one record.
28
27
  prov?: any
29
28
 
30
- // THE READ SET (RENDER.0.md P7), or absent for an uninstrumented
31
- // run: every tree path a reference resolved to, in one shared set.
32
- // It is what `render --coverage` measures the model against -- a
33
- // path no read reached is model the transform never consumed -- and
34
- // its presence is also what switches the two render riders on
35
- // (Val.origin, Val.emitted), so one flag turns the whole record on.
36
29
  reads?: Set<string>
37
30
  fs?: any
38
31
  errfs?: any
@@ -56,24 +49,6 @@ class AontuContext {
56
49
  vc: number // Val counter to create unique val ids.
57
50
  cc: number = -1
58
51
 
59
- // THE STAGING RULE (G8 phase 0,
60
- // docs/capability-review/g8-generation.md). A value whose answer
61
- // depends on WHERE IT IS -- `key()` today, the generation
62
- // combinators next -- must not answer while anything is still
63
- // moving it: resolved early it reports the position it was WRITTEN
64
- // at rather than the one it ends up at. Such a value RESIDUATES
65
- // while this is false, and fires exactly once on the pass where it
66
- // is true.
67
- //
68
- // The pass loop (ts/src/unify.ts) sets it on the first pass whose
69
- // input tree is IDENTICAL to the previous pass's: everything that
70
- // was going to move has moved, and what is left is the staged
71
- // values themselves, which is precisely the moment they may answer.
72
- // It replaces a `ctx.cc < 3` pass count in KeyFuncVal -- a magic
73
- // number, right for the documents it was tuned on and silently
74
- // wrong for anything that took a fourth pass to place a value. The
75
- // comment it replaces said as much: "this delay makes keys in
76
- // spreads and refs work, but it is a hack - find a better way".
77
52
  settle: boolean = false
78
53
  vars: Record<string, Val> = {}
79
54
  src?: string
@@ -86,18 +61,6 @@ class AontuContext {
86
61
 
87
62
  collect: boolean
88
63
 
89
- // THE COMPLETENESS PROBE (the review's finding C). vet detects
90
- // residue by GENERATING the anchored meet and keeping the
91
- // incomplete-class failures. Generation honours the OUTPUT marks --
92
- // `type()` and `hide()` say "do not emit this" -- so a `--at` anchor
93
- // sitting under a mark generated nothing at all, reported nothing,
94
- // and vetted VALID for data missing a required field, while the same
95
- // anchor without the mark answered incomplete (use-cases/BUGS.md
96
- // §14). A mark is a decision about OUTPUT; it is not a statement
97
- // about what the data must satisfy, and `--at` names the truth to
98
- // validate against explicitly. Under this flag the generation walk
99
- // descends through marked values; nothing else changes, and no
100
- // output is produced from a probe run -- only its findings are read.
101
64
  probe: boolean = false
102
65
 
103
66
  // The provenance recorder (G7 phase 3), or undefined for an
@@ -113,7 +76,6 @@ class AontuContext {
113
76
  err: any[]
114
77
  explain: any[] | null
115
78
 
116
- // TODO: separate options and context!!!
117
79
  srcpath?: string
118
80
 
119
81
  deps: Record<string, any>
@@ -122,49 +84,15 @@ class AontuContext {
122
84
  _pathstr: string | undefined
123
85
  _pathidx: number | undefined
124
86
  _pathmap: Map<string, number>
125
- // Trie keyed by (parentIdx, key) -> { idx, path }. Serves two
126
- // jobs: (1) assign O(1) pathidx without rebuilding
127
- // `path.join('\x00')` for cycle-detection; (2) cache the
128
- // materialised path array so the same (parent, key) visited
129
- // across fixpoint passes reuses one array instead of re-concat.
130
87
  _pathTrie: Map<number, Map<string, { idx: number, path: string[] }>>
131
88
  _pathidxNext: { n: number }
132
89
 
133
- // Current `unite` recursion depth, checked against the depth budget
134
- // (ts/src/unify.ts). Held in a shared mutable box, like _pathidxNext,
135
- // because clone() uses Object.create: the box is inherited by
136
- // reference, so a nested clone's increments are visible to the frame
137
- // that will decrement them. The Go port keeps the same counter
138
- // directly on its Ctx pointer (go/unify.go, maxUniteDepth).
139
90
  _depth: { n: number }
140
91
 
141
- // The relation declarations this evaluation accumulates (RELATIONS
142
- // P2): predicate -> what its graph atoms said. One Map per
143
- // evaluation, created here and inherited by reference through
144
- // clone()'s prototype chain, exactly as _depth's box is -- a clone
145
- // made before the first registration must still share the registry.
146
92
  _reldecls: Map<string, { acyclic?: boolean, inverses: Set<string> }>
147
93
 
148
- // The tree a recursive residual's target resolves against when the
149
- // meet's own root does not contain it (RECURSION.0.md). Normally
150
- // undefined: a residual expands by walking ctx.root, and the root
151
- // holds the definition. An ANCHORED vet run meets a subtree LIFTED
152
- // out of the settled schema, so `$.spec.Step` names nothing in the
153
- // meet's root -- the residual held its peer forever and the data
154
- // under it vetted VALID unchecked. Vet sets this to the settled
155
- // schema root for anchored runs; RecurseVal.body falls back to it
156
- // only when the root walk finds nothing. Inherited by clone()
157
- // through the prototype chain.
158
94
  _fixroot: any
159
95
 
160
- // The evaluation budgets (G5 trust profile, docs/trust.md): integer
161
- // counts of engine events, never wall-clock. Always present, defaults
162
- // from the shared spec-visible constants (test/spec/budget.tsv), so
163
- // the hot-path reads in unify.ts are plain property loads. Inherited
164
- // by clone() through the prototype chain. `revisits` is NOT profile
165
- // surface (the Go port has no revisit counter to configure — see
166
- // TrustBudget in type.ts); it is carried here so unify.ts reads one
167
- // budget object, at its fixed spec constant.
168
96
  budget: { passes: number, revisits: number, depth: number }
169
97
 
170
98
  // The include manifest sink (G5, docs/trust.md): every include the
@@ -172,20 +100,8 @@ class AontuContext {
172
100
  // Aontu.parse() sorts and dedups it onto the result's `deps`.
173
101
  manifest: { path: string, capability: string }[]
174
102
 
175
- // Trial mode: set by DisjunctVal.unify while each member is tried
176
- // against the peer. When true, makeNilErr returns the shared
177
- // TRIAL_NIL sentinel instead of allocating a fresh NilVal, and
178
- // pushes TRIAL_NIL to ctx.err only once per trial (the caller's
179
- // `trialErr.length > 0` check still signals failure). See err.ts.
180
103
  _trialMode?: boolean
181
104
 
182
- // Per-parent descend cache: (key) -> already-descended child ctx.
183
- // ~48% of descends in foo-sdk repeat the same (parent, key) pair
184
- // (e.g. a MapVal.unify visits the same peer keys across fixpoint
185
- // passes). The child's prototype chain, path, and pathidx are
186
- // identical every time, and no code writes to a descended ctx
187
- // between visits — nothing mutates per-child state — so the
188
- // cached child is safe to reuse.
189
105
  _childCache?: Map<string, AontuContext>
190
106
 
191
107
 
@@ -258,9 +174,6 @@ class AontuContext {
258
174
  ctx.explain = Array.isArray(cfg.explain) ? cfg.explain : ctx.explain
259
175
 
260
176
  ctx._pathstr = undefined
261
- // Path didn't move unless cfg.path was supplied, so pathidx stays
262
- // valid in the common case. For cfg.path-override (4 calls per
263
- // run, fixpoint advances) fall back to the join-based lookup.
264
177
  if (cfg.path !== undefined) {
265
178
  ctx._pathidx = undefined
266
179
  }
@@ -269,14 +182,6 @@ class AontuContext {
269
182
  }
270
183
 
271
184
  descend(key: string): AontuContext {
272
- // C3: reuse the child ctx from a previous descend with the same
273
- // (parent, key). Saves one Object.create + several property
274
- // writes per hit; ~48% hit rate on foo-sdk.
275
- //
276
- // NB: must use hasOwnProperty here — plain `this._childCache`
277
- // would walk the prototype chain and read the *parent's* cache
278
- // (ctxs are created via Object.create(parent)), so keys would
279
- // cross-contaminate between sibling branches.
280
185
  let childCache: Map<string, AontuContext> | undefined
281
186
  if (Object.prototype.hasOwnProperty.call(this, '_childCache')) {
282
187
  childCache = this._childCache
@@ -291,11 +196,6 @@ class AontuContext {
291
196
  const ctx = Object.create(this)
292
197
  ctx._pathstr = undefined
293
198
 
294
- // Trie doubles as both pathidx assignment and path-array cache.
295
- // (parent_pathidx, key) uniquely identifies a descended path,
296
- // and is visited many times across fixpoint passes. Caching the
297
- // materialised array lets descend share references instead of
298
- // allocating a fresh concat every time.
299
199
  const parentIdx = this._pathidx!
300
200
  let childMap = this._pathTrie.get(parentIdx)
301
201
  if (childMap === undefined) {
@@ -329,7 +229,6 @@ class AontuContext {
329
229
 
330
230
  this.src = ('string' === typeof this.opts.src ? this.opts.src : undefined) ?? this.src
331
231
 
332
- // TODO: rename srcpath to file
333
232
  this.srcpath = this.opts.path ?? this.srcpath
334
233
  }
335
234
 
@@ -351,7 +250,6 @@ class AontuContext {
351
250
 
352
251
 
353
252
  errmsg() {
354
- // return this.errlist
355
253
  return this.err
356
254
  .map((err: any) => (err && (null == err.msg || '' === err.msg)
357
255
  ? (descErr(err, this), err.msg)
@@ -407,7 +305,6 @@ class AontuContext {
407
305
  } /* node:coverage ignore next 8 */
408
306
 
409
307
 
410
-
411
308
  export {
412
309
  AontuContext,
413
310
  AontuContextConfig
package/src/diff.ts CHANGED
@@ -1,25 +1,6 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
  import { includeOpts } from './utility'
3
3
 
4
- // PATH-ADDRESSED DIFF (G7 phase 6,
5
- // docs/capability-review/g7-machine-access.md): what changed, at which
6
- // paths, between two documents — the dyff-style answer, which
7
- // deterministic canon makes possible without phantom noise. Two
8
- // documents that mean the same thing canon the same way, so a diff of
9
- // canons reports semantic change and not reformatting.
10
- //
11
- // The text compared is the HASH FORM (G6's `hcanon`), not the plain
12
- // canon, for the reason G6 gives: canon drops closedness and the
13
- // type/hide marks, so a canon diff calls `close({a:1})` and `{a:1}`
14
- // identical. A false "changed" costs a needless read; a false
15
- // "unchanged" is a change nobody reviewed, which is the one direction
16
- // that must not happen.
17
- //
18
- // WHETHER a change is BREAKING is a different question, and it belongs
19
- // to G3: `subsume` and `breaking` answer it with the lattice's own
20
- // rules. This verb answers "what moved", which is what a reviewer
21
- // reads first and what an agent needs before it can ask the other
22
- // question at all.
23
4
 
24
5
  import { Aontu } from './aontu'
25
6
  import type { TrustOptions } from './type'
@@ -44,7 +25,6 @@ export type DiffReport = {
44
25
  changes: DiffChange[]
45
26
  findings: VetFinding[]
46
27
  ok: boolean
47
- // True when nothing moved: the two documents mean the same thing.
48
28
  same: boolean
49
29
  }
50
30
 
@@ -54,13 +34,6 @@ export type DiffOptions = {
54
34
  // Compare at this path of both documents, rather than at the root.
55
35
  at?: string
56
36
 
57
- // The trust profile this run evaluates under (G5, docs/trust.md).
58
- // The source arrives from a caller, so the caller must be able to
59
- // say what it may reach: without this the include chain is the
60
- // default one, and `@"../../etc/passwd.aon"` reads whatever the
61
- // process can. (`@"x.js"` no longer executes -- ADR-012 refuses the
62
- // extension -- but reading is enough.) A server passes
63
- // `{include:'none'}`.
64
37
  trust?: TrustOptions
65
38
 
66
39
  // Extensions additionally read as text (the CLI's `--text-ext`).
@@ -75,11 +48,6 @@ function pathText(parts: string[]): string {
75
48
  }
76
49
 
77
50
 
78
- // Both sides of one node — never both absent: keys come from the
79
- // union of the two bags, and list indices run to the longer side, so
80
- // every walk has at least one value. Bags of the SAME kind recurse,
81
- // which is what makes the report path-addressed rather than one line
82
- // saying the whole document changed; everything else compares text.
83
51
  function walk(
84
52
  left: any, right: any, parts: string[], out: DiffChange[]): void {
85
53
  if (null == left) {
@@ -94,11 +62,6 @@ function walk(
94
62
  const bothMaps = true === left.isMap && true === right.isMap
95
63
  const bothLists = true === left.isList && true === right.isList
96
64
  if (bothMaps || bothLists) {
97
- // The bag's OWN attributes, at pseudo-keys under it: a recursing
98
- // bag never compares its own text, so what the children do not
99
- // carry has to be compared here. The spread is part of what a bag
100
- // MEANS; so are closedness and the marks, which is exactly why the
101
- // hash form spells them (G6).
102
65
  const lc = null == left.spread.cj ? undefined : hcanon(left.spread.cj)
103
66
  const rc = null == right.spread.cj ? undefined : hcanon(right.spread.cj)
104
67
  if (lc !== rc) {
@@ -182,9 +145,6 @@ function evalSide(
182
145
  }
183
146
 
184
147
 
185
- // Diff two documents. Each is evaluated on its own — a document that
186
- // does not stand up has no meaning to compare, and the report says so
187
- // rather than diffing a wreck.
188
148
  export function diff(
189
149
  leftSrc: string, rightSrc: string, opts?: DiffOptions): DiffReport {
190
150
  const options = opts ?? {}
package/src/err.ts CHANGED
@@ -17,17 +17,6 @@ import { hints } from './hints'
17
17
  const { errmsg, strinject } = util
18
18
 
19
19
 
20
- // COLOUR IS A DECISION ABOUT THE DESTINATION, not about the message.
21
- // Every error frame hardcoded the ANSI escapes, so a piped report and
22
- // a `--jsonl` answer carried terminal control codes into whatever read
23
- // them -- a log file, a CI annotation, an agent's parser (the review's
24
- // finding F).
25
- //
26
- // NO_COLOR (no-color.org: set, to anything, means no colour) turns them
27
- // off everywhere, library callers included. The CLI additionally turns
28
- // them off when its stderr is not a terminal, through setColor: a
29
- // library cannot see the destination, and a caller who has one is the
30
- // only one who can say.
31
20
  let COLOR: boolean | undefined
32
21
 
33
22
  function setColor(on: boolean | undefined): void {
@@ -38,13 +27,6 @@ function colorActive(): boolean {
38
27
  if (null != COLOR) {
39
28
  return COLOR
40
29
  }
41
- // `globalThis` always exists; `process` need not (this library runs
42
- // in a browser too), so the optional chain starts at the part that
43
- // can actually be missing -- and stays a CHAIN rather than becoming
44
- // an `if`, because the browser arm is unreachable from any test this
45
- // suite can run and ADR-002 does not accept an arm nothing takes.
46
- // Set-but-EMPTY is the documented exception and does not disable
47
- // colour (no-color.org).
48
30
  const no = (globalThis as any).process?.env?.NO_COLOR
49
31
  return null == no || '' === no
50
32
  }
@@ -68,15 +50,6 @@ function makeNilErr(
68
50
  attempt?: string,
69
51
  details?: Record<string, any>
70
52
  ): NilVal {
71
- // C1-inner: when a DisjunctVal trial is in progress, failures are
72
- // transient markers — none of the NilVal fields (site, path,
73
- // primary, secondary, details) ever surface to the user because
74
- // DisjunctVal replaces the oval entry with TRIAL_NIL and filters
75
- // by isNil. Allocating a fresh NilVal per failure (~60k per
76
- // foo-sdk run from IntegerVal/BooleanVal/ScalarVal.unify et al.)
77
- // is pure waste. Short-circuit to the shared sentinel; push once
78
- // to ctx.err so the caller's `trialErr.length > 0` check still
79
- // signals failure.
80
53
  if (ctx !== undefined && ctx._trialMode === true) {
81
54
  if (ctx.err.length === 0) ctx.err.push(TRIAL_NIL)
82
55
  return TRIAL_NIL
@@ -86,7 +59,6 @@ function makeNilErr(
86
59
  }
87
60
 
88
61
 
89
- // TODO: move to utility?
90
62
  function descErr<NILS extends NilVal | NilVal[]>(
91
63
  err: NILS | any,
92
64
  errctx?: ErrContext,
@@ -99,15 +71,6 @@ function descErr<NILS extends NilVal | NilVal[]>(
99
71
  let v1src = resolveSrc(v1, errctx)
100
72
  let v2src = resolveSrc(v2, errctx)
101
73
 
102
- // STRICT `!==` against the empty string. The loose `!=` here dropped
103
- // the list index 0, because `'' != 0` is FALSE in JavaScript ('' and
104
- // 0 are both coerced to 0): `a:[1]&[2]` reported its conflict at
105
- // `$.a` while `a:[1,5]&[1,6]` reported `$.a.1`, so the one index a
106
- // reader is most likely to meet was the one silently erased, and a
107
- // nested `a:[[1]]&[[2]]` lost both segments (issue #37). Numeric
108
- // segments arrive here as numbers, so only `===`/`!==` compares them
109
- // for what they are. `null != p` stays loose on purpose -- it is the
110
- // idiomatic null-and-undefined test.
111
74
  let path = ['$', ...err.path].filter((p: any) => null != p && '' !== p)
112
75
 
113
76
  // '$' is neither null nor '', so the filter always leaves it.
@@ -133,7 +96,6 @@ function descErr<NILS extends NilVal | NilVal[]>(
133
96
  '\n',
134
97
 
135
98
  (null != v1 && errmsg({
136
- // TODO: color should come from jsonic config
137
99
  color: { active: colorActive(), line: '\x1b[34m' },
138
100
  txts: {
139
101
  msg: 'Cannot ' + attempt + ' value: ' + v1.canon +
@@ -149,7 +111,6 @@ function descErr<NILS extends NilVal | NilVal[]>(
149
111
  })),
150
112
 
151
113
  (null != v2 && errmsg({
152
- // TODO: color should come from jsonic config
153
114
  color: { active: colorActive(), line: '\x1b[34m' },
154
115
  txts: {
155
116
  msg: 'Cannot ' + attempt + ' value: ' + v2.canon +
@@ -169,7 +130,6 @@ function descErr<NILS extends NilVal | NilVal[]>(
169
130
  .filter((n: any) => null != n && false !== n)
170
131
  .join('\n')
171
132
 
172
- // TODO: update jsonic errmsg to avoid multiple empty lines
173
133
  .replace(/\n\n/g, '\n')
174
134
 
175
135
  }
package/src/escape.ts CHANGED
@@ -1,36 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- // THE ESCAPE CONVENTIONS (G9 phase 6, docs/design/TEMPLATE.0.md D4).
4
- // `esc(s, variant?)` makes a string safe to place inside a literal of
5
- // the named convention, and `usc` reads it back out.
6
- //
7
- // A VARIANT NAMES A CONVENTION, NOT A LANGUAGE, and that is the whole
8
- // reason it is a variant rather than something a renderer knows:
9
- // several languages share one convention, and one language has
10
- // several -- a C-family literal escapes differently in each quote, and
11
- // SQL spells a literal one way and an identifier another.
12
- //
13
- // With no variant it is the C escape, JSON canonical, which covers
14
- // TypeScript, JavaScript, Java, C, C++, C#, Go, Rust, Swift, Kotlin,
15
- // Scala and JSON itself. That is why it is the default rather than a
16
- // lookup.
17
- //
18
- // EVERY CONVENTION IS SPELLED OUT HERE rather than borrowed from a
19
- // host function, and the reason is parity: `JSON.stringify` escapes
20
- // what Go's `encoding/json` does not (and the reverse), and
21
- // `encodeURIComponent` leaves `!'()*` alone where RFC 3986 does not.
22
- // A generated file must be byte-identical whichever engine wrote it,
23
- // so both ports carry this table and go/escape.go is its twin.
24
- //
25
- // `usc` IS THE LEFT INVERSE, AND IT IS PARTIAL. `usc(esc(s))` is `s`
26
- // for every `s`; `esc(usc(t))` is `t` only for canonically escaped
27
- // `t`, because several spellings escape to one value. Input with no
28
- // inverse -- a truncated `\u12`, an undefined `\q`, a lone `'` where
29
- // the convention doubles it -- is REFUSED (`usc_malformed`), never
30
- // passed through: a generator that reads a value back out of an
31
- // artifact and silently gets a different one is the failure this
32
- // whole pair exists to close.
33
-
34
3
 
35
4
  // The variant names, in the order the reference lists them. `none` is
36
5
  // not here: it is the absent argument, and the absent argument is the
@@ -38,15 +7,9 @@
38
7
  const ESC_VARIANTS = ['sq', 'sql', 'shell', 'xml', 'uri', 'regex']
39
8
 
40
9
 
41
- // The regex metacharacters, which are exactly the ones the pattern
42
- // subset admits as escaped-to-mean-themselves (RE_ESCAPE_PUNCT in
43
- // ConstraintVal). So `esc(s, regex)` always answers a pattern the
44
- // subset accepts, which is the point of having the variant at all.
45
10
  const ESC_REGEX_PUNCT = '\\.+*?()[]{}|^$/'
46
11
 
47
12
 
48
- // The five XML entities, in the order they must be APPLIED: `&` first,
49
- // or the ampersands of the other four are escaped a second time.
50
13
  const ESC_XML: [string, string][] = [
51
14
  ['&', '&amp;'],
52
15
  ['<', '&lt;'],
@@ -56,10 +19,6 @@ const ESC_XML: [string, string][] = [
56
19
  ]
57
20
 
58
21
 
59
- // The characters RFC 3986 calls unreserved. Everything else is
60
- // percent-encoded, byte by byte of its UTF-8, with UPPERCASE hex --
61
- // the case the RFC prefers, pinned here because the two ports must
62
- // agree on it.
63
22
  const ESC_URI_UNRESERVED =
64
23
  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'
65
24
 
@@ -143,7 +102,6 @@ function unescC(src: string, quote: string): [string, boolean] {
143
102
  }
144
103
 
145
104
 
146
- // Four hex digits at `at`, or -1 when they are not four hex digits.
147
105
  function hex4(src: string, at: number): number {
148
106
  if (src.length < at + 4) { return -1 }
149
107
  let v = 0
@@ -286,10 +244,6 @@ function unescRegex(src: string): [string, boolean] {
286
244
  }
287
245
 
288
246
 
289
- // UTF-8 by hand, both ways, because the percent convention is defined
290
- // over BYTES and the two ports must produce the same ones. TextEncoder
291
- // would do for the forward direction; the reverse needs the error
292
- // behaviour spelled out, so both are here.
293
247
  function utf8Bytes(ch: string): number[] {
294
248
  const c = ch.codePointAt(0) as number
295
249
  if (0x80 > c) { return [c] }
package/src/exactjson.ts CHANGED
@@ -1,62 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- /*
4
- * D9 -- THE EXACT JSON EMITTER.
5
- *
6
- * `generate()` returns NATIVE values, and once a document opts into the
7
- * exact leaves two of them are not things `JSON.stringify` can write: a
8
- * biginteger generates as a native `bigint`, and a bigdecimal generates
9
- * as a `Decimal`. `JSON.stringify` THROWS on a bigint ("Do not know how
10
- * to serialize a BigInt") and a `replacer` cannot rescue it, because a
11
- * replacer may only return another *value* -- everything it returns that
12
- * is not already a JSON primitive gets quoted, so the exact digits could
13
- * only come back as a JSON *string*, which is a different document.
14
- *
15
- * JSON itself was never the obstacle. A JSON number is arbitrary-
16
- * precision decimal TEXT: `{"x":9007199254740993}` is a perfectly legal
17
- * document that every conforming parser reads, and Go's `encoding/json`
18
- * already emits exactly that for a `*big.Int`. Only JavaScript's
19
- * serialiser stands in the way, so aontu ships its own.
20
- *
21
- * WHY THIS IS PUBLIC API and not a CLI internal: D9 promises that an
22
- * exact value reaches JSON as exact digits. A library consumer whose
23
- * document contains `0d9007199254740993` has no other supported way to
24
- * keep that promise -- hiding the only implementation behind the command
25
- * line would leave the contract unfulfillable from the library. The
26
- * `aontu` CLI consumes this same export (with `indent`), and so does the
27
- * shared suite's byte-exact `gens` mode, so there is exactly one set of
28
- * bytes to keep in step with the Go port.
29
- *
30
- * PARITY WITH GO. The output must match Go's
31
- * `json.Encoder` + `SetEscapeHTML(false)` (see specGens in
32
- * go/spec_test.go) byte for byte:
33
- *
34
- * - Key order is the order `generate()` produced. Both ports already
35
- * sort map keys (see the entries sort in BagVal.gen; Go's encoder
36
- * sorts map keys), so neither has to sort again here.
37
- * - Strings keep JavaScript's escaping, which is what the `gens` mode
38
- * settled on when it turned Go's HTML escaping OFF so that `<`, `>`
39
- * and `&` stay literal in both ports. U+2028/U+2029 are the one
40
- * place JS and Go disagree by default -- Go escapes them, JS does
41
- * not -- so they are escaped here too, which is both legal JSON and
42
- * the safer output (it can be embedded in a JavaScript source).
43
- * - Numbers keep JavaScript's `Number.prototype.toString` form, which
44
- * is already what Go's encoder produces: fixed notation inside
45
- * [1e-6, 1e21) and an unpadded, always-signed exponent outside it
46
- * (`1e+21`, `1e-7`).
47
- * - A bigint writes its digits; a Decimal writes its plain digit form
48
- * (`1000.0`, `0.1`, `-1.5`) -- no `0d` marker, since that belongs to
49
- * canon and is not JSON, but an integral bigdecimal keeps its `.0`
50
- * so the JSON still shows a decimal. Go's `*Decimal.MarshalJSON`
51
- * mirrors this.
52
- *
53
- * NOTE that byte-exact output CANNOT check the other half of D9: an
54
- * integral bigdecimal and a biginteger can serialise to different text,
55
- * but a biginteger and an ordinary integer serialise to the SAME text
56
- * while `generate()` returned the wrong runtime type. Canon pins the AST
57
- * kind, `gens` pins these bytes, and only the per-port API tests
58
- * (ts/test/exactjson.test.ts here) pin the returned object.
59
- */
60
3
 
61
4
  import { Decimal } from './val/Decimal'
62
5
  import { AontuError } from './err'
@@ -68,9 +11,6 @@ import { cmpCodePoint } from './keyorder'
68
11
  const LSPS_RE = new RegExp('[\u2028\u2029]', 'g')
69
12
 
70
13
 
71
- // JSON.stringify's `space` argument, normalised the way the spec does:
72
- // a number is clamped to 0..10 spaces, a string is truncated to 10
73
- // characters, anything else means "compact".
74
14
  function indentUnit(indent: number | string | undefined): string {
75
15
  if ('number' === typeof indent) {
76
16
  const n = Math.min(10, Math.floor(indent))
@@ -92,18 +32,11 @@ function quote(s: string): string {
92
32
  }
93
33
 
94
34
 
95
- // True for a value JSON.stringify omits from an object and writes as
96
- // `null` inside an array. generate() never produces one, but a consumer
97
- // splicing its own data into the result might.
98
35
  function skipped(v: any): boolean {
99
36
  return undefined === v || 'function' === typeof v || 'symbol' === typeof v
100
37
  }
101
38
 
102
39
 
103
- // `seen` tracks the containers on the CURRENT path only (added on entry,
104
- // removed on exit), so a shared subtree -- which unification can easily
105
- // produce -- serialises fine and only a true cycle is refused, exactly
106
- // as JSON.stringify does it.
107
40
  function emit(v: any, unit: string, pad: string, seen: Set<any>): string {
108
41
  if (null === v) {
109
42
  return 'null'
@@ -163,35 +96,6 @@ function emit(v: any, unit: string, pad: string, seen: Set<any>): string {
163
96
  else {
164
97
  const colon = '' === unit ? ':' : ': '
165
98
  const parts: string[] = []
166
- // OWN enumerable keys, SORTED. A `for ... in` here would additionally
167
- // walk the prototype chain.
168
- //
169
- // WHY THE SORT IS HERE AND NOT IN gen(). BagVal.gen already sorts map
170
- // entries lexicographically -- and then writes them into a plain JS
171
- // object, where ECMAScript throws that sort away. OrdinaryOwnPropertyKeys
172
- // lists canonical ARRAY-INDEX keys first, in ascending NUMERIC order,
173
- // and only then the remaining string keys in insertion order. So
174
- // `{9:1,10:2}` came back out as 9 before 10, and `{"!":1,9:2}` put the
175
- // digit key ahead of the punctuation one.
176
- //
177
- // This is not a V8 quirk and not a JSON.stringify quirk; it is the
178
- // object's own key order, and it CANNOT be fixed upstream, because no
179
- // JavaScript object can hold "10" before "9". The emitter is the last
180
- // point that still has the freedom to choose, so it chooses here.
181
- //
182
- // The giveaway that it was never a design rule: only indices up to
183
- // 2^32-2 are hoisted, so `{4294967295:1,4294967296:2,5:3}` emitted as
184
- // 5, 4294967295, 4294967296 -- and TypeScript's own CANON, which builds
185
- // text from a sorted list rather than from an object, was lexicographic
186
- // all along. The port contradicted itself.
187
- //
188
- // Lexicographic by UTF-16 code unit, which is what `<` on JS strings
189
- // does and what MapVal.canon/BagVal.gen already sort by. Go sorts map
190
- // keys by UTF-8 byte, and the two orders agree on every key that stays
191
- // inside the BMP; astral-plane keys are a separate, tracked divergence.
192
- // CODE POINT order (cmpCodePoint), which is what Go's UTF-8 byte sort
193
- // produces. A bare .sort() is UTF-16 code-unit order, which puts an
194
- // astral key ahead of everything in U+E000-U+FFFF.
195
99
  for (const k of Object.keys(v).sort(cmpCodePoint)) {
196
100
  const cv = v[k]
197
101
  if (skipped(cv)) {
@@ -209,41 +113,6 @@ function emit(v: any, unit: string, pad: string, seen: Set<any>): string {
209
113
  }
210
114
 
211
115
 
212
- /**
213
- * Serialise a value produced by `Aontu.generate()` as JSON text,
214
- * preserving EXACT numbers.
215
- *
216
- * Use this instead of `JSON.stringify` on generated output. A document
217
- * that uses the `0d` exact leaves generates native `bigint` and
218
- * `Decimal` values; `JSON.stringify` throws on the first and mangles the
219
- * second, while this emitter writes both as raw JSON numbers with their
220
- * exact digits -- which is what the D9 generate contract promises, and
221
- * what the Go port's marshallers produce for the same document.
222
- *
223
- * ```ts
224
- * import { Aontu, exactJSON } from 'aontu'
225
- *
226
- * const out = new Aontu().generate('x:0d9007199254740993')
227
- * typeof out.x // 'bigint'
228
- * exactJSON(out) // '{"x":9007199254740993}'
229
- * exactJSON(out, 2) // '{\n "x": 9007199254740993\n}'
230
- * JSON.stringify(out) // TypeError: Do not know how to serialize a BigInt
231
- * ```
232
- *
233
- * @param value The value to serialise -- normally `generate()` output:
234
- * `null`, booleans, numbers, strings, `bigint`,
235
- * `Decimal`, arrays and plain objects. An object with a
236
- * `toJSON` method is asked for its replacement first
237
- * (`Decimal` is handled as a number before that check).
238
- * @param indent Optional indentation, with `JSON.stringify`'s `space`
239
- * semantics: a number of spaces (clamped to 0..10) or a
240
- * literal string. Omitted or `0` gives COMPACT output
241
- * (no spaces, no newlines) -- the form the shared spec
242
- * suite's `gens` mode compares byte for byte.
243
- * @returns The JSON text. Unlike `JSON.stringify` this always
244
- * returns a string: a top-level `undefined` is `null`.
245
- * @throws {AontuError} if the value contains a reference cycle.
246
- */
247
116
  function exactJSON(value: any, indent?: number | string): string {
248
117
  return emit(value, indentUnit(indent), '', new Set())
249
118
  } /* node:coverage ignore next 6 */