aontu 0.62.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 (356) hide show
  1. package/README.md +1 -1
  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 +1 -1
  8. package/dist/aontu.js +1 -79
  9. package/dist/aontu.js.map +1 -1
  10. package/dist/aontumodel.d.ts +4 -0
  11. package/dist/aontumodel.js +33 -0
  12. package/dist/aontumodel.js.map +1 -0
  13. package/dist/cli.js +101 -620
  14. package/dist/cli.js.map +1 -1
  15. package/dist/ctx.js +0 -48
  16. package/dist/ctx.js.map +1 -1
  17. package/dist/diff.js +0 -32
  18. package/dist/diff.js.map +1 -1
  19. package/dist/err.js +0 -40
  20. package/dist/err.js.map +1 -1
  21. package/dist/escape.js +0 -45
  22. package/dist/escape.js.map +1 -1
  23. package/dist/exactjson.d.ts +0 -35
  24. package/dist/exactjson.js +0 -131
  25. package/dist/exactjson.js.map +1 -1
  26. package/dist/format.js +13 -203
  27. package/dist/format.js.map +1 -1
  28. package/dist/grammar.d.ts +9 -0
  29. package/dist/grammar.js +54 -0
  30. package/dist/grammar.js.map +1 -0
  31. package/dist/graph.js +0 -26
  32. package/dist/graph.js.map +1 -1
  33. package/dist/hcanon.js +0 -82
  34. package/dist/hcanon.js.map +1 -1
  35. package/dist/helpdoc.js +1 -1
  36. package/dist/helpdoc.js.map +1 -1
  37. package/dist/hints.d.ts +0 -6
  38. package/dist/hints.js +54 -55
  39. package/dist/hints.js.map +1 -1
  40. package/dist/jsonschema.js +0 -114
  41. package/dist/jsonschema.js.map +1 -1
  42. package/dist/keyorder.d.ts +0 -7
  43. package/dist/keyorder.js +0 -41
  44. package/dist/keyorder.js.map +1 -1
  45. package/dist/lang.js +17 -915
  46. package/dist/lang.js.map +1 -1
  47. package/dist/lower.js +11 -61
  48. package/dist/lower.js.map +1 -1
  49. package/dist/lsp-server.js +0 -16
  50. package/dist/lsp-server.js.map +1 -1
  51. package/dist/lsp.d.ts +1 -1
  52. package/dist/lsp.js +12 -159
  53. package/dist/lsp.js.map +1 -1
  54. package/dist/mcp-server.js +0 -26
  55. package/dist/mcp-server.js.map +1 -1
  56. package/dist/mcp.js +0 -113
  57. package/dist/mcp.js.map +1 -1
  58. package/dist/mod-tool.js +0 -130
  59. package/dist/mod-tool.js.map +1 -1
  60. package/dist/mod.js +0 -162
  61. package/dist/mod.js.map +1 -1
  62. package/dist/patch.js +0 -217
  63. package/dist/patch.js.map +1 -1
  64. package/dist/provenance.js +0 -140
  65. package/dist/provenance.js.map +1 -1
  66. package/dist/query.js +0 -75
  67. package/dist/query.js.map +1 -1
  68. package/dist/reach.js +0 -43
  69. package/dist/reach.js.map +1 -1
  70. package/dist/relation.js +0 -61
  71. package/dist/relation.js.map +1 -1
  72. package/dist/render.js +20 -135
  73. package/dist/render.js.map +1 -1
  74. package/dist/report-sarif.d.ts +0 -11
  75. package/dist/report-sarif.js +0 -28
  76. package/dist/report-sarif.js.map +1 -1
  77. package/dist/sig.js +0 -35
  78. package/dist/sig.js.map +1 -1
  79. package/dist/sigdecl.js +1 -1
  80. package/dist/sigdecl.js.map +1 -1
  81. package/dist/siggate.js +0 -4
  82. package/dist/siggate.js.map +1 -1
  83. package/dist/site.js +3 -29
  84. package/dist/site.js.map +1 -1
  85. package/dist/subsume.d.ts +0 -10
  86. package/dist/subsume.js +0 -137
  87. package/dist/subsume.js.map +1 -1
  88. package/dist/template.d.ts +2 -1
  89. package/dist/template.js +58 -138
  90. package/dist/template.js.map +1 -1
  91. package/dist/trim.js +0 -41
  92. package/dist/trim.js.map +1 -1
  93. package/dist/tsconfig.tsbuildinfo +1 -1
  94. package/dist/type.js.map +1 -1
  95. package/dist/unify.js +12 -242
  96. package/dist/unify.js.map +1 -1
  97. package/dist/utility.js +0 -22
  98. package/dist/utility.js.map +1 -1
  99. package/dist/val/AbnfFuncVal.d.ts +18 -0
  100. package/dist/val/AbnfFuncVal.js +132 -0
  101. package/dist/val/AbnfFuncVal.js.map +1 -0
  102. package/dist/val/AbsentVal.d.ts +11 -0
  103. package/dist/val/AbsentVal.js +30 -0
  104. package/dist/val/AbsentVal.js.map +1 -0
  105. package/dist/val/AggFuncVal.d.ts +10 -1
  106. package/dist/val/AggFuncVal.js +104 -116
  107. package/dist/val/AggFuncVal.js.map +1 -1
  108. package/dist/val/ArithFuncVal.js +0 -12
  109. package/dist/val/ArithFuncVal.js.map +1 -1
  110. package/dist/val/BagVal.js +1 -78
  111. package/dist/val/BagVal.js.map +1 -1
  112. package/dist/val/BigDecimalVal.js +0 -16
  113. package/dist/val/BigDecimalVal.js.map +1 -1
  114. package/dist/val/BigIntegerVal.js +0 -16
  115. package/dist/val/BigIntegerVal.js.map +1 -1
  116. package/dist/val/CloseFuncVal.js +0 -9
  117. package/dist/val/CloseFuncVal.js.map +1 -1
  118. package/dist/val/CmpFuncVal.js +2 -59
  119. package/dist/val/CmpFuncVal.js.map +1 -1
  120. package/dist/val/ConjunctVal.js +0 -29
  121. package/dist/val/ConjunctVal.js.map +1 -1
  122. package/dist/val/ConstraintVal.js +0 -500
  123. package/dist/val/ConstraintVal.js.map +1 -1
  124. package/dist/val/ContainerKindVal.js +0 -2
  125. package/dist/val/ContainerKindVal.js.map +1 -1
  126. package/dist/val/CopyFuncVal.js +0 -3
  127. package/dist/val/CopyFuncVal.js.map +1 -1
  128. package/dist/val/Decimal.js +0 -179
  129. package/dist/val/Decimal.js.map +1 -1
  130. package/dist/val/DeprecateFuncVal.js.map +1 -1
  131. package/dist/val/DisjunctVal.js +0 -152
  132. package/dist/val/DisjunctVal.js.map +1 -1
  133. package/dist/val/EachFuncVal.js +0 -3
  134. package/dist/val/EachFuncVal.js.map +1 -1
  135. package/dist/val/EmitFuncVal.d.ts +1 -1
  136. package/dist/val/EmitFuncVal.js +6 -119
  137. package/dist/val/EmitFuncVal.js.map +1 -1
  138. package/dist/val/ExpectVal.js +0 -62
  139. package/dist/val/ExpectVal.js.map +1 -1
  140. package/dist/val/FilterFuncVal.js +0 -25
  141. package/dist/val/FilterFuncVal.js.map +1 -1
  142. package/dist/val/FuncBaseVal.d.ts +1 -0
  143. package/dist/val/FuncBaseVal.js +7 -127
  144. package/dist/val/FuncBaseVal.js.map +1 -1
  145. package/dist/val/GraphAtomVal.js +0 -15
  146. package/dist/val/GraphAtomVal.js.map +1 -1
  147. package/dist/val/HideFuncVal.js +0 -13
  148. package/dist/val/HideFuncVal.js.map +1 -1
  149. package/dist/val/IntegerVal.js +0 -61
  150. package/dist/val/IntegerVal.js.map +1 -1
  151. package/dist/val/JunctionVal.js +0 -20
  152. package/dist/val/JunctionVal.js.map +1 -1
  153. package/dist/val/KeyFuncVal.js +0 -46
  154. package/dist/val/KeyFuncVal.js.map +1 -1
  155. package/dist/val/ListVal.js +0 -57
  156. package/dist/val/ListVal.js.map +1 -1
  157. package/dist/val/LowerFuncVal.js +0 -11
  158. package/dist/val/LowerFuncVal.js.map +1 -1
  159. package/dist/val/MapVal.js +0 -151
  160. package/dist/val/MapVal.js.map +1 -1
  161. package/dist/val/MatchFuncVal.js +0 -27
  162. package/dist/val/MatchFuncVal.js.map +1 -1
  163. package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
  164. package/dist/val/MaybeFuncVal.js +50 -0
  165. package/dist/val/MaybeFuncVal.js.map +1 -0
  166. package/dist/val/MoveFuncVal.js +0 -18
  167. package/dist/val/MoveFuncVal.js.map +1 -1
  168. package/dist/val/NilVal.js +0 -60
  169. package/dist/val/NilVal.js.map +1 -1
  170. package/dist/val/NomFuncVal.js +8 -42
  171. package/dist/val/NomFuncVal.js.map +1 -1
  172. package/dist/val/NumberVal.js +0 -15
  173. package/dist/val/NumberVal.js.map +1 -1
  174. package/dist/val/OpBaseVal.d.ts +1 -0
  175. package/dist/val/OpBaseVal.js +3 -15
  176. package/dist/val/OpBaseVal.js.map +1 -1
  177. package/dist/val/PackFuncVal.js +0 -34
  178. package/dist/val/PackFuncVal.js.map +1 -1
  179. package/dist/val/PathFuncVal.js +0 -6
  180. package/dist/val/PathFuncVal.js.map +1 -1
  181. package/dist/val/PathVal.js +0 -41
  182. package/dist/val/PathVal.js.map +1 -1
  183. package/dist/val/PlaceVal.js +0 -25
  184. package/dist/val/PlaceVal.js.map +1 -1
  185. package/dist/val/PlusOpVal.d.ts +1 -7
  186. package/dist/val/PlusOpVal.js +13 -74
  187. package/dist/val/PlusOpVal.js.map +1 -1
  188. package/dist/val/PrefFuncVal.js +0 -1
  189. package/dist/val/PrefFuncVal.js.map +1 -1
  190. package/dist/val/PrefVal.js +0 -167
  191. package/dist/val/PrefVal.js.map +1 -1
  192. package/dist/val/RecurseVal.js +0 -55
  193. package/dist/val/RecurseVal.js.map +1 -1
  194. package/dist/val/RefVal.js +0 -282
  195. package/dist/val/RefVal.js.map +1 -1
  196. package/dist/val/ReferFuncVal.js +0 -232
  197. package/dist/val/ReferFuncVal.js.map +1 -1
  198. package/dist/val/ScalarKindVal.js +0 -49
  199. package/dist/val/ScalarKindVal.js.map +1 -1
  200. package/dist/val/ScalarVal.js +0 -11
  201. package/dist/val/ScalarVal.js.map +1 -1
  202. package/dist/val/StrFuncVal.js +0 -18
  203. package/dist/val/StrFuncVal.js.map +1 -1
  204. package/dist/val/SuperFuncVal.js +0 -32
  205. package/dist/val/SuperFuncVal.js.map +1 -1
  206. package/dist/val/TopVal.js +0 -1
  207. package/dist/val/TopVal.js.map +1 -1
  208. package/dist/val/TranslateFuncVal.js +1 -3
  209. package/dist/val/TranslateFuncVal.js.map +1 -1
  210. package/dist/val/UpperFuncVal.js +0 -11
  211. package/dist/val/UpperFuncVal.js.map +1 -1
  212. package/dist/val/Val.d.ts +1 -0
  213. package/dist/val/Val.js +2 -133
  214. package/dist/val/Val.js.map +1 -1
  215. package/dist/val/VarVal.js +0 -12
  216. package/dist/val/VarVal.js.map +1 -1
  217. package/dist/val/arith.js +0 -37
  218. package/dist/val/arith.js.map +1 -1
  219. package/dist/val/caserange.js +0 -61
  220. package/dist/val/caserange.js.map +1 -1
  221. package/dist/val/members.js +0 -6
  222. package/dist/val/members.js.map +1 -1
  223. package/dist/val/numcmp.js +0 -11
  224. package/dist/val/numcmp.js.map +1 -1
  225. package/dist/val/numkind.js +0 -145
  226. package/dist/val/numkind.js.map +1 -1
  227. package/dist/val/valutil.js +0 -16
  228. package/dist/val/valutil.js.map +1 -1
  229. package/dist/vet.js +0 -461
  230. package/dist/vet.js.map +1 -1
  231. package/dist/view.js +0 -414
  232. package/dist/view.js.map +1 -1
  233. package/dist/walk.js +0 -41
  234. package/dist/walk.js.map +1 -1
  235. package/grammar/aontu.abnf +8 -6
  236. package/grammar/aontu.gbnf +4 -4
  237. package/grammar/aontu.lark +4 -4
  238. package/grammar/aontu.tmLanguage.json +1 -1
  239. package/package.json +4 -2
  240. package/src/agentsmd.ts +0 -35
  241. package/src/alias.ts +0 -39
  242. package/src/allow.ts +1 -96
  243. package/src/aontu.ts +3 -110
  244. package/src/aontumodel.ts +32 -0
  245. package/src/cli.ts +113 -682
  246. package/src/ctx.ts +0 -103
  247. package/src/diff.ts +0 -40
  248. package/src/err.ts +0 -40
  249. package/src/escape.ts +0 -46
  250. package/src/exactjson.ts +0 -131
  251. package/src/format.ts +14 -257
  252. package/src/grammar.ts +72 -0
  253. package/src/graph.ts +0 -61
  254. package/src/hcanon.ts +0 -82
  255. package/src/helpdoc.ts +1 -1
  256. package/src/hints.ts +66 -57
  257. package/src/jsonschema.ts +0 -123
  258. package/src/keyorder.ts +0 -42
  259. package/src/lang.ts +19 -931
  260. package/src/lower.ts +12 -62
  261. package/src/lsp-server.ts +0 -16
  262. package/src/lsp.ts +12 -180
  263. package/src/mcp-server.ts +0 -31
  264. package/src/mcp.ts +0 -130
  265. package/src/mod-tool.ts +0 -158
  266. package/src/mod.ts +0 -178
  267. package/src/patch.ts +0 -232
  268. package/src/provenance.ts +0 -183
  269. package/src/query.ts +0 -84
  270. package/src/reach.ts +0 -53
  271. package/src/relation.ts +0 -84
  272. package/src/render.ts +20 -172
  273. package/src/report-sarif.ts +0 -48
  274. package/src/sig.ts +0 -35
  275. package/src/sigdecl.ts +1 -1
  276. package/src/siggate.ts +0 -30
  277. package/src/site.ts +3 -29
  278. package/src/subsume.ts +1 -161
  279. package/src/template.ts +69 -140
  280. package/src/trim.ts +0 -53
  281. package/src/type.ts +2 -45
  282. package/src/unify.ts +13 -251
  283. package/src/utility.ts +0 -31
  284. package/src/val/AbnfFuncVal.ts +181 -0
  285. package/src/val/AbsentVal.ts +54 -0
  286. package/src/val/AggFuncVal.ts +152 -188
  287. package/src/val/ArithFuncVal.ts +0 -20
  288. package/src/val/BagVal.ts +1 -78
  289. package/src/val/BigDecimalVal.ts +0 -16
  290. package/src/val/BigIntegerVal.ts +0 -16
  291. package/src/val/CloseFuncVal.ts +0 -9
  292. package/src/val/CmpFuncVal.ts +4 -166
  293. package/src/val/ConjunctVal.ts +0 -33
  294. package/src/val/ConstraintVal.ts +2 -537
  295. package/src/val/ContainerKindVal.ts +0 -18
  296. package/src/val/CopyFuncVal.ts +0 -5
  297. package/src/val/Decimal.ts +1 -185
  298. package/src/val/DeprecateFuncVal.ts +0 -10
  299. package/src/val/DisjunctVal.ts +0 -157
  300. package/src/val/EachFuncVal.ts +0 -40
  301. package/src/val/EmitFuncVal.ts +8 -208
  302. package/src/val/ExpectVal.ts +0 -62
  303. package/src/val/FilterFuncVal.ts +0 -55
  304. package/src/val/FuncBaseVal.ts +9 -130
  305. package/src/val/GraphAtomVal.ts +0 -42
  306. package/src/val/HideFuncVal.ts +0 -15
  307. package/src/val/IntegerVal.ts +0 -61
  308. package/src/val/JunctionVal.ts +0 -20
  309. package/src/val/KeyFuncVal.ts +0 -48
  310. package/src/val/ListVal.ts +0 -59
  311. package/src/val/LowerFuncVal.ts +0 -12
  312. package/src/val/MapVal.ts +0 -151
  313. package/src/val/MatchFuncVal.ts +0 -59
  314. package/src/val/MaybeFuncVal.ts +86 -0
  315. package/src/val/MoveFuncVal.ts +0 -20
  316. package/src/val/NilVal.ts +0 -60
  317. package/src/val/NomFuncVal.ts +8 -95
  318. package/src/val/NumberVal.ts +0 -16
  319. package/src/val/OpBaseVal.ts +4 -17
  320. package/src/val/PackFuncVal.ts +0 -63
  321. package/src/val/PathFuncVal.ts +0 -32
  322. package/src/val/PathVal.ts +0 -66
  323. package/src/val/PlaceVal.ts +0 -45
  324. package/src/val/PlusOpVal.ts +18 -75
  325. package/src/val/PrefFuncVal.ts +0 -1
  326. package/src/val/PrefVal.ts +0 -179
  327. package/src/val/RecurseVal.ts +0 -81
  328. package/src/val/RefVal.ts +1 -285
  329. package/src/val/ReferFuncVal.ts +0 -255
  330. package/src/val/ScalarKindVal.ts +0 -50
  331. package/src/val/ScalarVal.ts +0 -12
  332. package/src/val/StrFuncVal.ts +0 -44
  333. package/src/val/SuperFuncVal.ts +0 -42
  334. package/src/val/TopVal.ts +0 -1
  335. package/src/val/TranslateFuncVal.ts +1 -51
  336. package/src/val/UpperFuncVal.ts +0 -12
  337. package/src/val/Val.ts +3 -192
  338. package/src/val/VarVal.ts +0 -15
  339. package/src/val/arith.ts +0 -92
  340. package/src/val/caserange.ts +0 -62
  341. package/src/val/members.ts +0 -23
  342. package/src/val/numcmp.ts +1 -27
  343. package/src/val/numkind.ts +0 -149
  344. package/src/val/valutil.ts +0 -16
  345. package/src/vet.ts +1 -582
  346. package/src/view.ts +0 -507
  347. package/src/walk.ts +0 -41
  348. package/dist/std.d.ts +0 -3
  349. package/dist/std.js +0 -672
  350. package/dist/std.js.map +0 -1
  351. package/dist/val/FormFuncVal.js +0 -55
  352. package/dist/val/FormFuncVal.js.map +0 -1
  353. package/dist/val/NamerFuncVal.d.ts +0 -12
  354. package/dist/val/NamerFuncVal.js +0 -176
  355. package/dist/val/NamerFuncVal.js.map +0 -1
  356. package/src/std.ts +0 -683
package/dist/exactjson.js CHANGED
@@ -2,72 +2,12 @@
2
2
  /* Copyright (c) 2025 Richard Rodger, MIT License */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.exactJSON = exactJSON;
5
- /*
6
- * D9 -- THE EXACT JSON EMITTER.
7
- *
8
- * `generate()` returns NATIVE values, and once a document opts into the
9
- * exact leaves two of them are not things `JSON.stringify` can write: a
10
- * biginteger generates as a native `bigint`, and a bigdecimal generates
11
- * as a `Decimal`. `JSON.stringify` THROWS on a bigint ("Do not know how
12
- * to serialize a BigInt") and a `replacer` cannot rescue it, because a
13
- * replacer may only return another *value* -- everything it returns that
14
- * is not already a JSON primitive gets quoted, so the exact digits could
15
- * only come back as a JSON *string*, which is a different document.
16
- *
17
- * JSON itself was never the obstacle. A JSON number is arbitrary-
18
- * precision decimal TEXT: `{"x":9007199254740993}` is a perfectly legal
19
- * document that every conforming parser reads, and Go's `encoding/json`
20
- * already emits exactly that for a `*big.Int`. Only JavaScript's
21
- * serialiser stands in the way, so aontu ships its own.
22
- *
23
- * WHY THIS IS PUBLIC API and not a CLI internal: D9 promises that an
24
- * exact value reaches JSON as exact digits. A library consumer whose
25
- * document contains `0d9007199254740993` has no other supported way to
26
- * keep that promise -- hiding the only implementation behind the command
27
- * line would leave the contract unfulfillable from the library. The
28
- * `aontu` CLI consumes this same export (with `indent`), and so does the
29
- * shared suite's byte-exact `gens` mode, so there is exactly one set of
30
- * bytes to keep in step with the Go port.
31
- *
32
- * PARITY WITH GO. The output must match Go's
33
- * `json.Encoder` + `SetEscapeHTML(false)` (see specGens in
34
- * go/spec_test.go) byte for byte:
35
- *
36
- * - Key order is the order `generate()` produced. Both ports already
37
- * sort map keys (see the entries sort in BagVal.gen; Go's encoder
38
- * sorts map keys), so neither has to sort again here.
39
- * - Strings keep JavaScript's escaping, which is what the `gens` mode
40
- * settled on when it turned Go's HTML escaping OFF so that `<`, `>`
41
- * and `&` stay literal in both ports. U+2028/U+2029 are the one
42
- * place JS and Go disagree by default -- Go escapes them, JS does
43
- * not -- so they are escaped here too, which is both legal JSON and
44
- * the safer output (it can be embedded in a JavaScript source).
45
- * - Numbers keep JavaScript's `Number.prototype.toString` form, which
46
- * is already what Go's encoder produces: fixed notation inside
47
- * [1e-6, 1e21) and an unpadded, always-signed exponent outside it
48
- * (`1e+21`, `1e-7`).
49
- * - A bigint writes its digits; a Decimal writes its plain digit form
50
- * (`1000.0`, `0.1`, `-1.5`) -- no `0d` marker, since that belongs to
51
- * canon and is not JSON, but an integral bigdecimal keeps its `.0`
52
- * so the JSON still shows a decimal. Go's `*Decimal.MarshalJSON`
53
- * mirrors this.
54
- *
55
- * NOTE that byte-exact output CANNOT check the other half of D9: an
56
- * integral bigdecimal and a biginteger can serialise to different text,
57
- * but a biginteger and an ordinary integer serialise to the SAME text
58
- * while `generate()` returned the wrong runtime type. Canon pins the AST
59
- * kind, `gens` pins these bytes, and only the per-port API tests
60
- * (ts/test/exactjson.test.ts here) pin the returned object.
61
- */
62
5
  const Decimal_1 = require("./val/Decimal");
63
6
  const err_1 = require("./err");
64
7
  const keyorder_1 = require("./keyorder");
65
8
  // JS leaves U+2028 (LINE SEPARATOR) and U+2029 (PARAGRAPH SEPARATOR)
66
9
  // literal in a JSON string; Go's encoder escapes them. Byte parity wins.
67
10
  const LSPS_RE = new RegExp('[\u2028\u2029]', 'g');
68
- // JSON.stringify's `space` argument, normalised the way the spec does:
69
- // a number is clamped to 0..10 spaces, a string is truncated to 10
70
- // characters, anything else means "compact".
71
11
  function indentUnit(indent) {
72
12
  if ('number' === typeof indent) {
73
13
  const n = Math.min(10, Math.floor(indent));
@@ -84,16 +24,9 @@ function quote(s) {
84
24
  // inside an escape), so a straight replace is safe.
85
25
  return out.replace(LSPS_RE, (c) => '\u2028' === c ? '\\u2028' : '\\u2029');
86
26
  }
87
- // True for a value JSON.stringify omits from an object and writes as
88
- // `null` inside an array. generate() never produces one, but a consumer
89
- // splicing its own data into the result might.
90
27
  function skipped(v) {
91
28
  return undefined === v || 'function' === typeof v || 'symbol' === typeof v;
92
29
  }
93
- // `seen` tracks the containers on the CURRENT path only (added on entry,
94
- // removed on exit), so a shared subtree -- which unification can easily
95
- // produce -- serialises fine and only a true cycle is refused, exactly
96
- // as JSON.stringify does it.
97
30
  function emit(v, unit, pad, seen) {
98
31
  if (null === v) {
99
32
  return 'null';
@@ -145,35 +78,6 @@ function emit(v, unit, pad, seen) {
145
78
  else {
146
79
  const colon = '' === unit ? ':' : ': ';
147
80
  const parts = [];
148
- // OWN enumerable keys, SORTED. A `for ... in` here would additionally
149
- // walk the prototype chain.
150
- //
151
- // WHY THE SORT IS HERE AND NOT IN gen(). BagVal.gen already sorts map
152
- // entries lexicographically -- and then writes them into a plain JS
153
- // object, where ECMAScript throws that sort away. OrdinaryOwnPropertyKeys
154
- // lists canonical ARRAY-INDEX keys first, in ascending NUMERIC order,
155
- // and only then the remaining string keys in insertion order. So
156
- // `{9:1,10:2}` came back out as 9 before 10, and `{"!":1,9:2}` put the
157
- // digit key ahead of the punctuation one.
158
- //
159
- // This is not a V8 quirk and not a JSON.stringify quirk; it is the
160
- // object's own key order, and it CANNOT be fixed upstream, because no
161
- // JavaScript object can hold "10" before "9". The emitter is the last
162
- // point that still has the freedom to choose, so it chooses here.
163
- //
164
- // The giveaway that it was never a design rule: only indices up to
165
- // 2^32-2 are hoisted, so `{4294967295:1,4294967296:2,5:3}` emitted as
166
- // 5, 4294967295, 4294967296 -- and TypeScript's own CANON, which builds
167
- // text from a sorted list rather than from an object, was lexicographic
168
- // all along. The port contradicted itself.
169
- //
170
- // Lexicographic by UTF-16 code unit, which is what `<` on JS strings
171
- // does and what MapVal.canon/BagVal.gen already sort by. Go sorts map
172
- // keys by UTF-8 byte, and the two orders agree on every key that stays
173
- // inside the BMP; astral-plane keys are a separate, tracked divergence.
174
- // CODE POINT order (cmpCodePoint), which is what Go's UTF-8 byte sort
175
- // produces. A bare .sort() is UTF-16 code-unit order, which puts an
176
- // astral key ahead of everything in U+E000-U+FFFF.
177
81
  for (const k of Object.keys(v).sort(keyorder_1.cmpCodePoint)) {
178
82
  const cv = v[k];
179
83
  if (skipped(cv)) {
@@ -187,41 +91,6 @@ function emit(v, unit, pad, seen) {
187
91
  seen.delete(v);
188
92
  return out;
189
93
  }
190
- /**
191
- * Serialise a value produced by `Aontu.generate()` as JSON text,
192
- * preserving EXACT numbers.
193
- *
194
- * Use this instead of `JSON.stringify` on generated output. A document
195
- * that uses the `0d` exact leaves generates native `bigint` and
196
- * `Decimal` values; `JSON.stringify` throws on the first and mangles the
197
- * second, while this emitter writes both as raw JSON numbers with their
198
- * exact digits -- which is what the D9 generate contract promises, and
199
- * what the Go port's marshallers produce for the same document.
200
- *
201
- * ```ts
202
- * import { Aontu, exactJSON } from 'aontu'
203
- *
204
- * const out = new Aontu().generate('x:0d9007199254740993')
205
- * typeof out.x // 'bigint'
206
- * exactJSON(out) // '{"x":9007199254740993}'
207
- * exactJSON(out, 2) // '{\n "x": 9007199254740993\n}'
208
- * JSON.stringify(out) // TypeError: Do not know how to serialize a BigInt
209
- * ```
210
- *
211
- * @param value The value to serialise -- normally `generate()` output:
212
- * `null`, booleans, numbers, strings, `bigint`,
213
- * `Decimal`, arrays and plain objects. An object with a
214
- * `toJSON` method is asked for its replacement first
215
- * (`Decimal` is handled as a number before that check).
216
- * @param indent Optional indentation, with `JSON.stringify`'s `space`
217
- * semantics: a number of spaces (clamped to 0..10) or a
218
- * literal string. Omitted or `0` gives COMPACT output
219
- * (no spaces, no newlines) -- the form the shared spec
220
- * suite's `gens` mode compares byte for byte.
221
- * @returns The JSON text. Unlike `JSON.stringify` this always
222
- * returns a string: a top-level `undefined` is `null`.
223
- * @throws {AontuError} if the value contains a reference cycle.
224
- */
225
94
  function exactJSON(value, indent) {
226
95
  return emit(value, indentUnit(indent), '', new Set());
227
96
  } /* node:coverage ignore next 6 */
@@ -1 +1 @@
1
- {"version":3,"file":"exactjson.js","sourceRoot":"","sources":["../src/exactjson.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"exactjson.js","sourceRoot":"","sources":["../src/exactjson.ts"],"names":[],"mappings":"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"}
package/dist/format.js CHANGED
@@ -3,51 +3,14 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.format = format;
5
5
  exports.unifiedDiff = unifiedDiff;
6
- // THE SOURCE FORMATTER (docs/design/FMT.0.md): `aontu fmt`, in the
7
- // tradition of gofmt. One agreed form for Aontu source, so that layout
8
- // is never argued about and a diff shows only what changed.
9
- //
10
- // It reads the token stream the parser reads -- the lex subscriber the
11
- // parser stack exposes -- so it sees what the value tree throws away:
12
- // comments, blank lines, the quote a string used, the spelling of a
13
- // number. From that stream it builds a layout tree, decides the shape
14
- // of every container by the rules of the note's §3, and emits. Before
15
- // returning it re-parses what it wrote and compares the two parse
16
- // trees: a formatter that cannot prove its output is the same document
17
- // refuses rather than return it.
18
- //
19
- // Two tiers. The syntactic (P1): whitespace, commas, quotes, bare
20
- // keys, chains and pair elements, none of which changes the parse
21
- // tree. The lawful (P2), over it: repeat the prefix, and merge what
22
- // repeats -- rewrites that rest on the meet, each checked by the meet
23
- // in isolation and kept only where the engine agrees.
24
- //
25
- // The Go twin is go/format.go, function for function; the shared
26
- // behaviour is test/spec/fmt.tsv, executed by both spec runners.
27
6
  const aontu_1 = require("./aontu");
28
7
  const vet_1 = require("./vet");
29
8
  const template_1 = require("./template");
30
- // The packing budget (§3.1). It decides which of two legal spellings
31
- // to use, one line or several, and nothing else: the formatter never
32
- // breaks a line, so a value wider than this stays as wide as it is.
33
9
  const BUDGET = 80;
34
- // THE DEPTH BUDGET. The layout is recursive, as the tree it reads is,
35
- // and the canonical port's stack is finite: past the evaluation budget
36
- // of 1000 levels -- the depth at which unification itself refuses --
37
- // the formatter stops reading and refuses, so a pathological document
38
- // is a finding rather than a crash.
39
10
  const MAX_DEPTH = 1000;
40
- // EVERY INCLUDE RESOLVES TO NOTHING. The formatter reads the file it is
41
- // given and no other (§3.13), so `@"..."` is answered from memory with
42
- // an empty source: the directive parses, the include is a token like
43
- // any other, and no capability is needed because no file is read.
44
11
  const stubResolver = ((spec) => ({
45
12
  ...spec, kind: 'aon', full: '__fmt__.aon', src: '', found: true, search: [],
46
13
  }));
47
- // ONE ENGINE, ONE SUBSCRIBER. The parser's subscriber list is
48
- // append-only, so the subscription is made once and writes to
49
- // whichever sink the current parse installed; the sink is cleared
50
- // before the parse returns, so the check's re-parse collects nothing.
51
14
  let ENGINE;
52
15
  let SINK;
53
16
  function engine() {
@@ -55,10 +18,6 @@ function engine() {
55
18
  ENGINE = new aontu_1.Aontu({ resolver: stubResolver });
56
19
  ENGINE.lang.jsonic.sub({
57
20
  lex: (tkn) => {
58
- // Spaces carry nothing the layout needs, and the end token
59
- // arrives once per nested parse -- the stub's empty includes
60
- // among them -- so both are dropped here rather than skipped
61
- // everywhere below.
62
21
  if (undefined !== SINK && '#SP' !== tkn.name && '#ZZ' !== tkn.name) {
63
22
  SINK.push({ name: tkn.name, src: tkn.src, val: tkn.val, sI: tkn.sI });
64
23
  }
@@ -148,10 +107,6 @@ class Reader {
148
107
  return KEYISH[this.name(0)] && ('#CL' === this.name(1) ||
149
108
  ('#QM' === this.name(1) && '#CL' === this.name(2)));
150
109
  }
151
- // The entries of a container up to its closer, or of the document up
152
- // to its end. Comments attach by the rules of §3.7: on the line of
153
- // the entry that precedes them, or of the opener, they trail it;
154
- // alone on a line they stand as entries and precede what follows.
155
110
  body(close, opened) {
156
111
  const body = [];
157
112
  let open;
@@ -448,11 +403,6 @@ function unwrap(root) {
448
403
  }
449
404
  // ---------------------------------------------------------------------
450
405
  // The layout
451
- // D1: a one-pair map in value position is written as a chain, and a
452
- // one-pair map as a list element as a pair element. A map whose only
453
- // entry is a spread keeps its braces (X-7), and one holding a comment
454
- // keeps them too, because the comment needs the lines. A trailing
455
- // comment on the map's line joins the pair's own.
456
406
  function chain(node) {
457
407
  if ('map' !== node.t || undefined !== node.open || 1 !== node.body.length ||
458
408
  'pair' !== node.body[0].t) {
@@ -467,18 +417,16 @@ function chain(node) {
467
417
  function width(s) {
468
418
  return Array.from(s).length;
469
419
  }
470
- function pairHead(node, tight) {
420
+ function pairHead(node, tight, value) {
471
421
  // An alias declaration is `%name = value` at every width: the `=` is
472
422
  // an operator, and operators are spaced (§3.2).
473
423
  if (node.alias) {
474
424
  return node.key + ' = ';
475
425
  }
476
- return node.key + (node.opt ? '?' : '') + (tight ? ':' : ': ');
426
+ const pad = !tight ||
427
+ (undefined !== value && '' !== value && OPENS.includes(value[0]));
428
+ return node.key + (node.opt ? '?' : '') + (pad ? ': ' : ':');
477
429
  }
478
- // The one-line spelling of a node, or undefined where it has none: a
479
- // comment, a blank line, a break the author kept, a string that spans
480
- // lines. `tight` is the inline form of a pair, `a:1`, used inside a
481
- // container; a statement's pair is `a: 1`.
482
430
  function inline(node, tight) {
483
431
  if (undefined !== node.trail || node.held) {
484
432
  return undefined;
@@ -489,7 +437,7 @@ function inline(node, tight) {
489
437
  return node.text.includes('\n') ? undefined : node.text;
490
438
  case 'pair': {
491
439
  const v = inline(chain(node.value), tight);
492
- return undefined === v ? undefined : pairHead(node, tight) + v;
440
+ return undefined === v ? undefined : pairHead(node, tight, v) + v;
493
441
  }
494
442
  case 'spread': {
495
443
  // `{ &: integer }`, padded inside braces too: the marker reads as
@@ -544,11 +492,15 @@ function inlineSeq(items) {
544
492
  }
545
493
  return out;
546
494
  }
495
+ // A value that OPENS keeps the space after the colon (§3.2); `|` is
496
+ // tight within a line and spaced where it leads one (§3.11, §7.7).
497
+ const OPENS = '*{[(';
498
+ const TIGHT_OP = '|';
547
499
  function sepOf(node) {
548
500
  return node.sep ? ', ' : ' ';
549
501
  }
550
- // Binary operators spaced, prefixes tight (§3.11). An operand is
551
- // never directly after an operand: the reader ends a value there.
502
+ // Binary operators spaced, prefixes and `|` tight (§3.11). An operand
503
+ // is never directly after an operand: the reader ends a value there.
552
504
  function inlineExpr(items) {
553
505
  let out = '';
554
506
  for (const it of items) {
@@ -556,7 +508,7 @@ function inlineExpr(items) {
556
508
  return undefined;
557
509
  }
558
510
  if ('op' === it.t) {
559
- out += ' ' + it.text + ' ';
511
+ out += TIGHT_OP === it.text ? it.text : ' ' + it.text + ' ';
560
512
  continue;
561
513
  }
562
514
  if ('prefix' === it.t) {
@@ -606,9 +558,6 @@ class Writer {
606
558
  since(mark) {
607
559
  return this.lines.slice(mark).concat([this.line]).map(rtrim).join('\n') + '\n';
608
560
  }
609
- // A blank line above the line at an index: the gap of §3.8, opened
610
- // once the statement below it turns out to be a tree. Never at the
611
- // top of the page, and never a second time.
612
561
  gap(at) {
613
562
  if (0 < at && '' !== this.lines[at - 1]) {
614
563
  this.lines.splice(at, 0, '');
@@ -636,19 +585,9 @@ class Writer {
636
585
  function rtrim(s) {
637
586
  return s.replace(/ +$/, '');
638
587
  }
639
- // The entries of a body, one per line at the indentation, with the
640
- // blank lines the author kept between them (§3.8) -- never at the
641
- // start or the end. In STATEMENT position (`stmt`: the root, and the
642
- // body of a plain map that is itself the value of a statement) a pair
643
- // is laid out by §3.4, which may repeat its key; anywhere else -- a
644
- // list, an operand, an argument -- by §3.5 alone.
645
588
  function emitBody(w, body, indent, stmt, root) {
646
589
  let pending = false;
647
590
  let count = 0;
648
- // Where the run being written begins: a statement, with the comments
649
- // standing directly above it, so that the gap below opens ABOVE the
650
- // comments rather than between them and what they describe. A blank
651
- // line ends a run -- comments across a gap belong to what is above.
652
591
  let head = 0;
653
592
  let noted = false;
654
593
  for (const node of body) {
@@ -680,14 +619,6 @@ function emitBody(w, body, indent, stmt, root) {
680
619
  w.text(' ' + e.trail);
681
620
  }
682
621
  }
683
- // A TOP-LEVEL STATEMENT WRITTEN AS A TREE STANDS APART (§3.8). A
684
- // document states several things -- a service, then its entities,
685
- // then its errors -- and where one of them is a tree rather than a
686
- // line, the eye finds it by the space around it. What counts as a
687
- // tree is measured rather than guessed: the statement took more
688
- // than one line to write. So `a: 1` beside `b: 2` is left alone,
689
- // and this rule cannot fire below the root, where a blank line is
690
- // the author's (§3.8) and nothing else.
691
622
  if (root && from < w.mark()) {
692
623
  w.gap(head);
693
624
  pending = true;
@@ -734,18 +665,6 @@ function emitValue(w, node, indent) {
734
665
  w.text(node.text);
735
666
  }
736
667
  }
737
- // A call, or a parenthesis, that has no one-line form or is too wide
738
- // for the budget. Three shapes. Arguments that are all FLAT -- none
739
- // holds a container -- stay on the one line however wide it is: a
740
- // scalar is no narrower on a line of its own, and the formatter never
741
- // breaks a line. The last argument HUGS the parentheses, `hide({` ...
742
- // `})`, `close($.E & {` ... `})`, when it is a container, or an
743
- // expression the author did not break that ends in one, and the
744
- // arguments before it fit on the opener's line: the container decides
745
- // its own lines. Otherwise the parenthesis opens a block: one argument
746
- // per line one level in, the closer alone at the opener's level. A
747
- // call whose last argument hugs is hugged in turn, `type(close({` ...
748
- // `}))`: the schema idiom.
749
668
  function emitCall(w, node, indent) {
750
669
  const items = 'call' === node.t ? node.args : node.inner;
751
670
  const open = ('call' === node.t ? node.name : '') + '(';
@@ -841,21 +760,8 @@ function emitBlock(w, open, close, node, indent, stmt) {
841
760
  w.open(indent, false);
842
761
  w.text(close);
843
762
  }
844
- // An expression that has no one-line form, or one too wide for the
845
- // budget: the author's breaks are kept, each at its operator, which
846
- // leads its continuation line (§3.11). The continuation is one level
847
- // in when the expression follows a key on its line, and level with
848
- // the first operand when the expression has the line to itself -- an
849
- // argument of a block call, say -- so a disjunction of alternatives
850
- // reads as the list it is. A container operand that does not fit from
851
- // where it stands is a block whose closer lines up with the line that
852
- // opened it.
853
763
  function emitExpr(w, items, indent) {
854
764
  const cont = w.fresh() ? indent : indent + 2;
855
- // Whether the last item was an operand: a comment after one is a
856
- // space away, and after an operator or the colon it is not. An
857
- // operand is never directly after an operand (the reader ends a
858
- // value there), so operands need no such check.
859
765
  let operand = false;
860
766
  let cur = indent;
861
767
  for (const it of items) {
@@ -868,7 +774,7 @@ function emitExpr(w, items, indent) {
868
774
  w.text(it.text + ' ');
869
775
  }
870
776
  else {
871
- w.text(' ' + it.text + ' ');
777
+ w.text(TIGHT_OP === it.text ? it.text : ' ' + it.text + ' ');
872
778
  }
873
779
  operand = false;
874
780
  continue;
@@ -892,10 +798,6 @@ function emitExpr(w, items, indent) {
892
798
  operand = true;
893
799
  }
894
800
  }
895
- // The entries of a plain map value: a braced map, or a chain, which is
896
- // a one-entry map. A map with a comment on its opener keeps its braces
897
- // (§3.7), so it is not plain here; nor is a map holding an include,
898
- // which the local check cannot follow.
899
801
  function plainEntries(v) {
900
802
  if ('pair' === v.t) {
901
803
  return [v];
@@ -921,17 +823,6 @@ function members(p) {
921
823
  const trail = undefined === last.trail ? p.trail : last.trail + ' ' + p.trail;
922
824
  return entries.slice(0, -1).concat([{ ...last, trail }]);
923
825
  }
924
- // Adjacent statements naming one key, whose values are plain maps, are
925
- // one map: their entries in order, with the comments and blank lines
926
- // between the statements travelling with the statement they preceded.
927
- // Only ADJACENT statements merge -- a `server:` line, something else,
928
- // then another `server:` line stays as it is, because merging them
929
- // would move a statement, and the formatter never reorders (§3.13).
930
- // Nor do two statements merge into a map with two spreads: the engine
931
- // keeps those as a conjunction, which is not the meet of the two maps.
932
- // The tree is not changed: a merged statement is a new node that keeps
933
- // the statements it replaces as its `orig`, its spelling before, and a
934
- // statement merged somewhere below is copied the same way.
935
826
  function mergeRuns(body) {
936
827
  const out = [];
937
828
  let i = 0;
@@ -993,15 +884,6 @@ function mergeDeep(p) {
993
884
  }
994
885
  return { ...p, value: 'pair' === v.t ? body[0] : { ...v, body }, orig: [p] };
995
886
  }
996
- // Whether a value is a RECORD: a braced map of several entries, every
997
- // one of them a VALUE rather than another map. A field, an error, a
998
- // rule row -- something whose keys are what it IS, as against a level
999
- // of the tree, whose keys are a way through to something else.
1000
- //
1001
- // A CHAIN IS NOT ONE, whatever it holds: a one-entry map is D1's, and
1002
- // D1 writes it as a chain at every width. Nor is a map holding a
1003
- // spread, which says something about the map's MEMBERS and which D1's
1004
- // exception already gives a spelling of its own inside a repeat.
1005
887
  function record(v, entries) {
1006
888
  if ('map' !== v.t) {
1007
889
  return false;
@@ -1061,12 +943,6 @@ function repeatLines(entries, prefix, indent) {
1061
943
  if (undefined === lines) {
1062
944
  return undefined;
1063
945
  }
1064
- // THE DESCENT COULD GO ON, AND WHAT IT REACHES IS A RECORD: it
1065
- // stops, and the record is a block under the prefix instead. The
1066
- // deeper repeat is asked for first and thrown away deliberately --
1067
- // the block REPLACES a descent that would have worked, and never
1068
- // rescues one that would not, so a map this rule cannot reach two
1069
- // ways round is laid out exactly as it was before the amendment.
1070
946
  if (record(e.value, sub)) {
1071
947
  out.push({ t: 'block', text: head, node: e.value, trail });
1072
948
  continue;
@@ -1090,18 +966,6 @@ function repeatLines(entries, prefix, indent) {
1090
966
  function fits(indent, text) {
1091
967
  return indent + width(text) <= BUDGET;
1092
968
  }
1093
- // A pair in statement position, by §3.4. `prefix` is what stands
1094
- // before it on its line: the heads of the chain it hangs from, not yet
1095
- // written. Its value is laid out by §3.5 unless it is a plain map, and
1096
- // then in this order: a chain, when the map holds exactly one pair
1097
- // (D1); one line, when that fits the budget; the key repeated over the
1098
- // entries, when every entry can be one line that way; a braced block
1099
- // otherwise, whose entries are statements in turn. Whether the
1100
- // statement was rewritten by this tier -- merged, or repeated -- is
1101
- // returned, and the outermost such statement is checked: its spelling
1102
- // on the page against what the syntactic tier writes for the
1103
- // statements it came from, at the same indentation, which is what
1104
- // stays on the page when the check fails.
1105
969
  function emitStatement(w, p, indent, stmt, prefix) {
1106
970
  const mark = w.mark();
1107
971
  let rewritten = undefined !== p.orig;
@@ -1177,11 +1041,6 @@ function emit(root, meet) {
1177
1041
  emitBody(w, undefined === meet ? root : mergeRuns(root), 0, undefined === meet ? undefined : { meet, covered: false }, true);
1178
1042
  return w.finish();
1179
1043
  }
1180
- // ---------------------------------------------------------------------
1181
- // The lint (§4): what the formatter points at and never touches. Two
1182
- // rules, both advice: the formatter never renames a key (§4.1) and
1183
- // never introduces an alias (§4.2), and a rule with a mechanical fix
1184
- // that keeps the document would belong to §3 instead (§4.3).
1185
1044
  // The shape width at which a repeat is worth an alias (§4.2): below
1186
1045
  // it, `{ a:1 }` twice is the shorter spelling. Measured over the use
1187
1046
  // cases when the lint landed (§7.10).
@@ -1228,11 +1087,6 @@ function lineCol(text, at) {
1228
1087
  const before = text.slice(0, at);
1229
1088
  return { line: before.split('\n').length, col: at - before.lastIndexOf('\n') };
1230
1089
  }
1231
- // D4 (§4.1): keys are lower-case words, or CamelCase when a key is
1232
- // several. A bare key holding `_`, or beginning with two capitals, is
1233
- // reported with the spelling that would follow the form; a quoted key
1234
- // is a deliberate spelling and a key of underscores alone names
1235
- // nothing the rule can respell.
1236
1090
  function keyCase(node, text, out) {
1237
1091
  if ('pair' === node.t && BARE.test(node.key) && /[A-Za-z]/.test(node.key)) {
1238
1092
  const why = node.key.includes('_') ? 'holds an underscore'
@@ -1248,9 +1102,6 @@ function keyCase(node, text, out) {
1248
1102
  keyCase(child, text, out);
1249
1103
  }
1250
1104
  }
1251
- // The key as lower-case words or CamelCase: `credit_cents` is
1252
- // `creditCents`, `HTTP_PORT` is `httpPort`, `HTTPServer` is
1253
- // `httpServer`, `ID` is `id`.
1254
1105
  function camel(key) {
1255
1106
  const words = key.split('_').filter((w) => '' !== w)
1256
1107
  .map((w) => /^[A-Z]+$/.test(w) ? w.toLowerCase() : w);
@@ -1258,12 +1109,6 @@ function camel(key) {
1258
1109
  return head.charAt(0).toLowerCase() + head.slice(1) +
1259
1110
  words.slice(1).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join('');
1260
1111
  }
1261
- // D3 (§4.2): a shape written twice can drift, and an alias names it
1262
- // once. Every map or list whose shape recurs in the file, and whose
1263
- // shape is REPEAT_MIN_WIDTH or wider, is reported once, at its first
1264
- // site, with the count and the other sites; the naming is the
1265
- // author's. A repeat inside a repeat is the outer one's: the walk does
1266
- // not descend into a shape it reports.
1267
1112
  function repeats(nodes, text, out) {
1268
1113
  const counts = new Map();
1269
1114
  const tally = (node) => {
@@ -1298,9 +1143,6 @@ function repeats(nodes, text, out) {
1298
1143
  }
1299
1144
  }
1300
1145
  }
1301
- // A node's shape: its spelling with the layout, the comments and, for
1302
- // a map, the order of its entries taken out, so that two spellings of
1303
- // one value are one shape, as they are one canon.
1304
1146
  function shape(node) {
1305
1147
  switch (node.t) {
1306
1148
  case 'map':
@@ -1336,15 +1178,6 @@ function sameDocument(root, after) {
1336
1178
  const p = parseDoc(after, undefined, undefined);
1337
1179
  return undefined === p.errors && root.canon === p.root.canon;
1338
1180
  }
1339
- // The check of a lawful rewrite: the spelling before and the spelling
1340
- // after, evaluated in isolation, come to the same canon, the same
1341
- // kinds of failure, and the same outcome of generation (§7.3). Local,
1342
- // so it needs no include and no capability, and it applies whether or
1343
- // not the document as a whole evaluates. The kinds, not the count: how
1344
- // often one unresolved reference is reported depends on the order the
1345
- // meet took. Generation too, because the engine generates from more
1346
- // than the canon: a meet of maps with a nil member has refused a key
1347
- // the same map written once generates.
1348
1181
  function sameByMeet(before, after) {
1349
1182
  return meetOf(before) === meetOf(after);
1350
1183
  }
@@ -1386,12 +1219,6 @@ function checkFinding(path, expected, actual) {
1386
1219
  actual,
1387
1220
  };
1388
1221
  }
1389
- // THE TARGET'S OWN LINES ARE HELD ON LINES OF THEIR OWN (§3.14). The
1390
- // desugaring is line for line, so a line of output is known by the
1391
- // offset it begins at, and the node beginning there -- the quoted
1392
- // string the desugaring wrote -- is marked. From there on it has no
1393
- // one-line form, so every container holding it opens, and no two lines
1394
- // of the generated file are ever packed onto one.
1395
1222
  function holdOutput(nodes, at) {
1396
1223
  for (const node of nodes) {
1397
1224
  if (undefined !== node.at && at.has(node.at)) {
@@ -1419,11 +1246,6 @@ function outputAt(doc, flags) {
1419
1246
  }
1420
1247
  return at;
1421
1248
  }
1422
- // A finding's column in the TEMPLATE rather than in the document it
1423
- // carries (§3.14): the marker and its one space stand before the aontu
1424
- // on every line the resugaring writes. Every finding is on such a
1425
- // line -- the two rules point at a key or at a container, and a line of
1426
- // output is a bare string, which is neither.
1427
1249
  function shiftFindings(findings, mark) {
1428
1250
  return undefined === mark ? findings :
1429
1251
  findings.map((f) => ({ ...f, col: f.col + mark.length + 1 }));
@@ -1433,9 +1255,6 @@ function shiftFindings(findings, mark) {
1433
1255
  // what `--check` and `--list` report.
1434
1256
  function format(src, opts, hooks) {
1435
1257
  const text = lf(src);
1436
- // A GENERATOR IS FORMATTED AS THE DOCUMENT IT CARRIES (§3.14): the
1437
- // template surface's two transforms stand either side of the
1438
- // formatter, and between them is what happens to any other document.
1439
1258
  const mark = opts?.template;
1440
1259
  const doc = undefined === mark ? text : (0, template_1.desugarTemplate)(text, mark);
1441
1260
  const toks = [];
@@ -1468,11 +1287,6 @@ function format(src, opts, hooks) {
1468
1287
  findings: opts?.lint ? shiftFindings(lintOf(root, doc), mark) : [],
1469
1288
  };
1470
1289
  }
1471
- // The lines of a text, with a marker on the last when the text does
1472
- // not end in a newline: such a line never equals its
1473
- // newline-terminated twin, which is how the diff reports the
1474
- // difference, and the marker is rendered as diff renders it. NUL,
1475
- // which no source line ends in.
1476
1290
  const NO_NEWLINE = String.fromCharCode(0);
1477
1291
  function textLines(text) {
1478
1292
  if ('' === text) {
@@ -1569,8 +1383,6 @@ function patience(a, x0, x1, b, y0, y1, out) {
1569
1383
  out.push({ op: ' ', text: a[x1 + k] });
1570
1384
  }
1571
1385
  }
1572
- // The diff in unified format, three lines of context, the file named
1573
- // on both sides. Empty when the texts are the same.
1574
1386
  function unifiedDiff(name, before, after) {
1575
1387
  const a = textLines(before);
1576
1388
  const b = textLines(after);
@@ -1600,8 +1412,6 @@ function unifiedDiff(name, before, after) {
1600
1412
  for (const [s, e] of hunks) {
1601
1413
  const from = Math.max(s - 3, 0);
1602
1414
  const to = Math.min(e + 4, edits.length);
1603
- // Everything between two hunks is context -- a change would have
1604
- // opened a hunk -- so both sides advance together.
1605
1415
  for (; next < from; next++) {
1606
1416
  ai++;
1607
1417
  bi++;