aontu 0.61.0 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/README.md +4 -4
  2. package/dist/agentsmd.d.ts +1 -0
  3. package/dist/agentsmd.js +7 -28
  4. package/dist/agentsmd.js.map +1 -1
  5. package/dist/alias.js.map +1 -1
  6. package/dist/allow.d.ts +23 -0
  7. package/dist/allow.js +138 -0
  8. package/dist/allow.js.map +1 -0
  9. package/dist/aontu.d.ts +4 -2
  10. package/dist/aontu.js +4 -80
  11. package/dist/aontu.js.map +1 -1
  12. package/dist/aontumodel.d.ts +4 -0
  13. package/dist/aontumodel.js +33 -0
  14. package/dist/aontumodel.js.map +1 -0
  15. package/dist/cli.d.ts +10 -1
  16. package/dist/cli.js +877 -479
  17. package/dist/cli.js.map +1 -1
  18. package/dist/ctx.js +0 -48
  19. package/dist/ctx.js.map +1 -1
  20. package/dist/diff.js +0 -32
  21. package/dist/diff.js.map +1 -1
  22. package/dist/err.js +0 -40
  23. package/dist/err.js.map +1 -1
  24. package/dist/escape.js +0 -45
  25. package/dist/escape.js.map +1 -1
  26. package/dist/exactjson.d.ts +0 -35
  27. package/dist/exactjson.js +0 -131
  28. package/dist/exactjson.js.map +1 -1
  29. package/dist/format.js +55 -189
  30. package/dist/format.js.map +1 -1
  31. package/dist/grammar.d.ts +9 -0
  32. package/dist/grammar.js +54 -0
  33. package/dist/grammar.js.map +1 -0
  34. package/dist/graph.js +0 -26
  35. package/dist/graph.js.map +1 -1
  36. package/dist/hcanon.js +0 -82
  37. package/dist/hcanon.js.map +1 -1
  38. package/dist/helpdoc.d.ts +16 -0
  39. package/dist/helpdoc.js +59 -0
  40. package/dist/helpdoc.js.map +1 -0
  41. package/dist/hints.d.ts +0 -6
  42. package/dist/hints.js +59 -47
  43. package/dist/hints.js.map +1 -1
  44. package/dist/jsonschema.js +0 -114
  45. package/dist/jsonschema.js.map +1 -1
  46. package/dist/keyorder.d.ts +0 -7
  47. package/dist/keyorder.js +0 -41
  48. package/dist/keyorder.js.map +1 -1
  49. package/dist/lang.js +32 -877
  50. package/dist/lang.js.map +1 -1
  51. package/dist/lower.d.ts +3 -0
  52. package/dist/lower.js +14 -61
  53. package/dist/lower.js.map +1 -1
  54. package/dist/lsp-server.js +0 -16
  55. package/dist/lsp-server.js.map +1 -1
  56. package/dist/lsp.d.ts +1 -1
  57. package/dist/lsp.js +12 -159
  58. package/dist/lsp.js.map +1 -1
  59. package/dist/mcp-server.js +0 -26
  60. package/dist/mcp-server.js.map +1 -1
  61. package/dist/mcp.js +0 -113
  62. package/dist/mcp.js.map +1 -1
  63. package/dist/mod-tool.js +0 -130
  64. package/dist/mod-tool.js.map +1 -1
  65. package/dist/mod.js +0 -162
  66. package/dist/mod.js.map +1 -1
  67. package/dist/patch.js +0 -217
  68. package/dist/patch.js.map +1 -1
  69. package/dist/provenance.js +0 -140
  70. package/dist/provenance.js.map +1 -1
  71. package/dist/query.js +0 -75
  72. package/dist/query.js.map +1 -1
  73. package/dist/reach.js +0 -43
  74. package/dist/reach.js.map +1 -1
  75. package/dist/relation.d.ts +2 -0
  76. package/dist/relation.js +3 -58
  77. package/dist/relation.js.map +1 -1
  78. package/dist/render.js +33 -143
  79. package/dist/render.js.map +1 -1
  80. package/dist/report-sarif.d.ts +0 -11
  81. package/dist/report-sarif.js +0 -28
  82. package/dist/report-sarif.js.map +1 -1
  83. package/dist/sig.js +0 -35
  84. package/dist/sig.js.map +1 -1
  85. package/dist/sigdecl.js +1 -1
  86. package/dist/sigdecl.js.map +1 -1
  87. package/dist/siggate.js +0 -4
  88. package/dist/siggate.js.map +1 -1
  89. package/dist/site.js +3 -29
  90. package/dist/site.js.map +1 -1
  91. package/dist/subsume.d.ts +0 -10
  92. package/dist/subsume.js +0 -137
  93. package/dist/subsume.js.map +1 -1
  94. package/dist/template.d.ts +2 -1
  95. package/dist/template.js +58 -138
  96. package/dist/template.js.map +1 -1
  97. package/dist/trim.js +0 -41
  98. package/dist/trim.js.map +1 -1
  99. package/dist/tsconfig.tsbuildinfo +1 -1
  100. package/dist/type.js.map +1 -1
  101. package/dist/unify.js +12 -242
  102. package/dist/unify.js.map +1 -1
  103. package/dist/utility.js +0 -22
  104. package/dist/utility.js.map +1 -1
  105. package/dist/val/AbnfFuncVal.d.ts +18 -0
  106. package/dist/val/AbnfFuncVal.js +132 -0
  107. package/dist/val/AbnfFuncVal.js.map +1 -0
  108. package/dist/val/AbsentVal.d.ts +11 -0
  109. package/dist/val/AbsentVal.js +30 -0
  110. package/dist/val/AbsentVal.js.map +1 -0
  111. package/dist/val/AggFuncVal.d.ts +10 -1
  112. package/dist/val/AggFuncVal.js +104 -116
  113. package/dist/val/AggFuncVal.js.map +1 -1
  114. package/dist/val/ArithFuncVal.js +0 -12
  115. package/dist/val/ArithFuncVal.js.map +1 -1
  116. package/dist/val/BagVal.js +1 -78
  117. package/dist/val/BagVal.js.map +1 -1
  118. package/dist/val/BigDecimalVal.js +0 -16
  119. package/dist/val/BigDecimalVal.js.map +1 -1
  120. package/dist/val/BigIntegerVal.js +0 -16
  121. package/dist/val/BigIntegerVal.js.map +1 -1
  122. package/dist/val/CloseFuncVal.js +0 -9
  123. package/dist/val/CloseFuncVal.js.map +1 -1
  124. package/dist/val/CmpFuncVal.d.ts +20 -0
  125. package/dist/val/CmpFuncVal.js +188 -0
  126. package/dist/val/CmpFuncVal.js.map +1 -0
  127. package/dist/val/ConjunctVal.js +0 -29
  128. package/dist/val/ConjunctVal.js.map +1 -1
  129. package/dist/val/ConstraintVal.js +0 -500
  130. package/dist/val/ConstraintVal.js.map +1 -1
  131. package/dist/val/ContainerKindVal.js +0 -2
  132. package/dist/val/ContainerKindVal.js.map +1 -1
  133. package/dist/val/CopyFuncVal.js +0 -3
  134. package/dist/val/CopyFuncVal.js.map +1 -1
  135. package/dist/val/Decimal.js +0 -179
  136. package/dist/val/Decimal.js.map +1 -1
  137. package/dist/val/DeprecateFuncVal.js.map +1 -1
  138. package/dist/val/DisjunctVal.js +0 -152
  139. package/dist/val/DisjunctVal.js.map +1 -1
  140. package/dist/val/EachFuncVal.d.ts +1 -2
  141. package/dist/val/EachFuncVal.js +12 -29
  142. package/dist/val/EachFuncVal.js.map +1 -1
  143. package/dist/val/EmitFuncVal.d.ts +1 -1
  144. package/dist/val/EmitFuncVal.js +6 -119
  145. package/dist/val/EmitFuncVal.js.map +1 -1
  146. package/dist/val/ExpectVal.js +0 -62
  147. package/dist/val/ExpectVal.js.map +1 -1
  148. package/dist/val/FilterFuncVal.js +0 -25
  149. package/dist/val/FilterFuncVal.js.map +1 -1
  150. package/dist/val/FuncBaseVal.d.ts +1 -0
  151. package/dist/val/FuncBaseVal.js +7 -127
  152. package/dist/val/FuncBaseVal.js.map +1 -1
  153. package/dist/val/GraphAtomVal.js +0 -15
  154. package/dist/val/GraphAtomVal.js.map +1 -1
  155. package/dist/val/HideFuncVal.js +0 -13
  156. package/dist/val/HideFuncVal.js.map +1 -1
  157. package/dist/val/IntegerVal.js +0 -61
  158. package/dist/val/IntegerVal.js.map +1 -1
  159. package/dist/val/JunctionVal.js +0 -20
  160. package/dist/val/JunctionVal.js.map +1 -1
  161. package/dist/val/KeyFuncVal.js +0 -46
  162. package/dist/val/KeyFuncVal.js.map +1 -1
  163. package/dist/val/ListVal.js +0 -57
  164. package/dist/val/ListVal.js.map +1 -1
  165. package/dist/val/LowerFuncVal.js +11 -6
  166. package/dist/val/LowerFuncVal.js.map +1 -1
  167. package/dist/val/MapVal.js +0 -151
  168. package/dist/val/MapVal.js.map +1 -1
  169. package/dist/val/MatchFuncVal.js +0 -27
  170. package/dist/val/MatchFuncVal.js.map +1 -1
  171. package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
  172. package/dist/val/MaybeFuncVal.js +50 -0
  173. package/dist/val/MaybeFuncVal.js.map +1 -0
  174. package/dist/val/MoveFuncVal.js +0 -18
  175. package/dist/val/MoveFuncVal.js.map +1 -1
  176. package/dist/val/NilVal.js +2 -36
  177. package/dist/val/NilVal.js.map +1 -1
  178. package/dist/val/NomFuncVal.d.ts +12 -0
  179. package/dist/val/NomFuncVal.js +153 -0
  180. package/dist/val/NomFuncVal.js.map +1 -0
  181. package/dist/val/NumberVal.js +0 -15
  182. package/dist/val/NumberVal.js.map +1 -1
  183. package/dist/val/OpBaseVal.d.ts +1 -0
  184. package/dist/val/OpBaseVal.js +3 -15
  185. package/dist/val/OpBaseVal.js.map +1 -1
  186. package/dist/val/PackFuncVal.js +0 -34
  187. package/dist/val/PackFuncVal.js.map +1 -1
  188. package/dist/val/PathFuncVal.js +0 -6
  189. package/dist/val/PathFuncVal.js.map +1 -1
  190. package/dist/val/PathVal.js +0 -41
  191. package/dist/val/PathVal.js.map +1 -1
  192. package/dist/val/PlaceVal.js +0 -25
  193. package/dist/val/PlaceVal.js.map +1 -1
  194. package/dist/val/PlusOpVal.d.ts +1 -7
  195. package/dist/val/PlusOpVal.js +13 -74
  196. package/dist/val/PlusOpVal.js.map +1 -1
  197. package/dist/val/PrefFuncVal.js +0 -1
  198. package/dist/val/PrefFuncVal.js.map +1 -1
  199. package/dist/val/PrefVal.js +0 -167
  200. package/dist/val/PrefVal.js.map +1 -1
  201. package/dist/val/RecurseVal.js +0 -55
  202. package/dist/val/RecurseVal.js.map +1 -1
  203. package/dist/val/RefVal.js +0 -282
  204. package/dist/val/RefVal.js.map +1 -1
  205. package/dist/val/ReferFuncVal.js +0 -232
  206. package/dist/val/ReferFuncVal.js.map +1 -1
  207. package/dist/val/ScalarKindVal.js +0 -49
  208. package/dist/val/ScalarKindVal.js.map +1 -1
  209. package/dist/val/ScalarVal.js +0 -11
  210. package/dist/val/ScalarVal.js.map +1 -1
  211. package/dist/val/StrFuncVal.js +0 -18
  212. package/dist/val/StrFuncVal.js.map +1 -1
  213. package/dist/val/SuperFuncVal.js +0 -32
  214. package/dist/val/SuperFuncVal.js.map +1 -1
  215. package/dist/val/TopVal.js +0 -1
  216. package/dist/val/TopVal.js.map +1 -1
  217. package/dist/val/TranslateFuncVal.d.ts +12 -0
  218. package/dist/val/TranslateFuncVal.js +99 -0
  219. package/dist/val/TranslateFuncVal.js.map +1 -0
  220. package/dist/val/UpperFuncVal.js +11 -6
  221. package/dist/val/UpperFuncVal.js.map +1 -1
  222. package/dist/val/Val.d.ts +1 -0
  223. package/dist/val/Val.js +2 -133
  224. package/dist/val/Val.js.map +1 -1
  225. package/dist/val/VarVal.js +0 -12
  226. package/dist/val/VarVal.js.map +1 -1
  227. package/dist/val/arith.js +0 -37
  228. package/dist/val/arith.js.map +1 -1
  229. package/dist/val/caserange.d.ts +3 -0
  230. package/dist/val/caserange.js +49 -0
  231. package/dist/val/caserange.js.map +1 -0
  232. package/dist/val/members.js +0 -6
  233. package/dist/val/members.js.map +1 -1
  234. package/dist/val/numcmp.js +0 -11
  235. package/dist/val/numcmp.js.map +1 -1
  236. package/dist/val/numkind.js +0 -145
  237. package/dist/val/numkind.js.map +1 -1
  238. package/dist/val/valutil.js +0 -16
  239. package/dist/val/valutil.js.map +1 -1
  240. package/dist/vet.d.ts +12 -0
  241. package/dist/vet.js +159 -412
  242. package/dist/vet.js.map +1 -1
  243. package/dist/view.js +0 -414
  244. package/dist/view.js.map +1 -1
  245. package/dist/walk.js +0 -41
  246. package/dist/walk.js.map +1 -1
  247. package/grammar/aontu.abnf +9 -7
  248. package/grammar/aontu.gbnf +5 -5
  249. package/grammar/aontu.lark +5 -5
  250. package/grammar/aontu.tmLanguage.json +1 -1
  251. package/package.json +4 -2
  252. package/skill/SKILL.md +8 -0
  253. package/skill/init/check.sh +28 -0
  254. package/skill/init/data.aon +12 -0
  255. package/skill/init/model.aon +19 -0
  256. package/skill/tasks.md +151 -0
  257. package/src/agentsmd.ts +8 -32
  258. package/src/alias.ts +0 -39
  259. package/src/allow.ts +221 -0
  260. package/src/aontu.ts +10 -108
  261. package/src/aontumodel.ts +32 -0
  262. package/src/cli.ts +1009 -540
  263. package/src/ctx.ts +0 -103
  264. package/src/diff.ts +0 -40
  265. package/src/err.ts +0 -40
  266. package/src/escape.ts +0 -46
  267. package/src/exactjson.ts +0 -131
  268. package/src/format.ts +63 -234
  269. package/src/grammar.ts +72 -0
  270. package/src/graph.ts +0 -61
  271. package/src/hcanon.ts +0 -82
  272. package/src/helpdoc.ts +77 -0
  273. package/src/hints.ts +72 -49
  274. package/src/jsonschema.ts +0 -123
  275. package/src/keyorder.ts +0 -42
  276. package/src/lang.ts +39 -895
  277. package/src/lower.ts +15 -65
  278. package/src/lsp-server.ts +0 -16
  279. package/src/lsp.ts +12 -180
  280. package/src/mcp-server.ts +0 -31
  281. package/src/mcp.ts +0 -130
  282. package/src/mod-tool.ts +0 -158
  283. package/src/mod.ts +0 -178
  284. package/src/patch.ts +0 -232
  285. package/src/provenance.ts +0 -183
  286. package/src/query.ts +0 -84
  287. package/src/reach.ts +0 -53
  288. package/src/relation.ts +7 -71
  289. package/src/render.ts +33 -180
  290. package/src/report-sarif.ts +0 -48
  291. package/src/sig.ts +0 -35
  292. package/src/sigdecl.ts +1 -1
  293. package/src/siggate.ts +0 -30
  294. package/src/site.ts +3 -29
  295. package/src/subsume.ts +1 -161
  296. package/src/template.ts +69 -140
  297. package/src/trim.ts +0 -53
  298. package/src/type.ts +2 -45
  299. package/src/unify.ts +13 -251
  300. package/src/utility.ts +0 -31
  301. package/src/val/AbnfFuncVal.ts +181 -0
  302. package/src/val/AbsentVal.ts +54 -0
  303. package/src/val/AggFuncVal.ts +152 -188
  304. package/src/val/ArithFuncVal.ts +0 -20
  305. package/src/val/BagVal.ts +1 -78
  306. package/src/val/BigDecimalVal.ts +0 -16
  307. package/src/val/BigIntegerVal.ts +0 -16
  308. package/src/val/CloseFuncVal.ts +0 -9
  309. package/src/val/CmpFuncVal.ts +249 -0
  310. package/src/val/ConjunctVal.ts +0 -33
  311. package/src/val/ConstraintVal.ts +2 -537
  312. package/src/val/ContainerKindVal.ts +0 -18
  313. package/src/val/CopyFuncVal.ts +0 -5
  314. package/src/val/Decimal.ts +1 -185
  315. package/src/val/DeprecateFuncVal.ts +0 -10
  316. package/src/val/DisjunctVal.ts +0 -157
  317. package/src/val/EachFuncVal.ts +12 -53
  318. package/src/val/EmitFuncVal.ts +8 -208
  319. package/src/val/ExpectVal.ts +0 -62
  320. package/src/val/FilterFuncVal.ts +0 -55
  321. package/src/val/FuncBaseVal.ts +9 -130
  322. package/src/val/GraphAtomVal.ts +0 -42
  323. package/src/val/HideFuncVal.ts +0 -15
  324. package/src/val/IntegerVal.ts +0 -61
  325. package/src/val/JunctionVal.ts +0 -20
  326. package/src/val/KeyFuncVal.ts +0 -48
  327. package/src/val/ListVal.ts +0 -59
  328. package/src/val/LowerFuncVal.ts +12 -7
  329. package/src/val/MapVal.ts +0 -151
  330. package/src/val/MatchFuncVal.ts +0 -59
  331. package/src/val/MaybeFuncVal.ts +86 -0
  332. package/src/val/MoveFuncVal.ts +0 -20
  333. package/src/val/NilVal.ts +2 -36
  334. package/src/val/NomFuncVal.ts +200 -0
  335. package/src/val/NumberVal.ts +0 -16
  336. package/src/val/OpBaseVal.ts +4 -17
  337. package/src/val/PackFuncVal.ts +0 -63
  338. package/src/val/PathFuncVal.ts +0 -32
  339. package/src/val/PathVal.ts +0 -66
  340. package/src/val/PlaceVal.ts +0 -45
  341. package/src/val/PlusOpVal.ts +18 -75
  342. package/src/val/PrefFuncVal.ts +0 -1
  343. package/src/val/PrefVal.ts +0 -179
  344. package/src/val/RecurseVal.ts +0 -81
  345. package/src/val/RefVal.ts +1 -285
  346. package/src/val/ReferFuncVal.ts +0 -255
  347. package/src/val/ScalarKindVal.ts +0 -50
  348. package/src/val/ScalarVal.ts +0 -12
  349. package/src/val/StrFuncVal.ts +0 -44
  350. package/src/val/SuperFuncVal.ts +0 -42
  351. package/src/val/TopVal.ts +0 -1
  352. package/src/val/TranslateFuncVal.ts +132 -0
  353. package/src/val/UpperFuncVal.ts +12 -7
  354. package/src/val/Val.ts +3 -192
  355. package/src/val/VarVal.ts +0 -15
  356. package/src/val/arith.ts +0 -92
  357. package/src/val/caserange.ts +53 -0
  358. package/src/val/members.ts +0 -23
  359. package/src/val/numcmp.ts +1 -27
  360. package/src/val/numkind.ts +0 -149
  361. package/src/val/valutil.ts +0 -16
  362. package/src/vet.ts +209 -504
  363. package/src/view.ts +0 -507
  364. package/src/walk.ts +0 -41
  365. package/dist/std.d.ts +0 -3
  366. package/dist/std.js +0 -637
  367. package/dist/std.js.map +0 -1
  368. package/dist/val/FormFuncVal.js +0 -55
  369. package/dist/val/FormFuncVal.js.map +0 -1
  370. package/src/std.ts +0 -648
  371. package/src/val/FormFuncVal.ts +0 -119
package/dist/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,6 +884,25 @@ function mergeDeep(p) {
993
884
  }
994
885
  return { ...p, value: 'pair' === v.t ? body[0] : { ...v, body }, orig: [p] };
995
886
  }
887
+ function record(v, entries) {
888
+ if ('map' !== v.t) {
889
+ return false;
890
+ }
891
+ let pairs = 0;
892
+ for (const e of entries) {
893
+ if ('spread' === e.t) {
894
+ return false;
895
+ }
896
+ if ('pair' !== e.t) {
897
+ continue;
898
+ }
899
+ if (undefined !== plainEntries(e.value)) {
900
+ return false;
901
+ }
902
+ pairs++;
903
+ }
904
+ return 1 < pairs;
905
+ }
996
906
  function repeatLines(entries, prefix, indent) {
997
907
  if (0 === entries.length || 'comment' === entries[entries.length - 1].t ||
998
908
  1 < entries.filter((e) => 'spread' === e.t).length) {
@@ -1033,8 +943,21 @@ function repeatLines(entries, prefix, indent) {
1033
943
  if (undefined === lines) {
1034
944
  return undefined;
1035
945
  }
946
+ if (record(e.value, sub)) {
947
+ out.push({ t: 'block', text: head, node: e.value, trail });
948
+ continue;
949
+ }
1036
950
  if ('' !== trail) {
1037
- lines[lines.length - 1].text += trail;
951
+ // Onto the last line written for this entry -- and after the
952
+ // CLOSER where that line is a block, which is where the trailing
953
+ // comment of the entry the block came from also stands.
954
+ const last = lines[lines.length - 1];
955
+ if ('block' === last.t) {
956
+ last.trail = (last.trail ?? '') + trail;
957
+ }
958
+ else {
959
+ last.text += trail;
960
+ }
1038
961
  }
1039
962
  out.push(...lines);
1040
963
  }
@@ -1043,18 +966,6 @@ function repeatLines(entries, prefix, indent) {
1043
966
  function fits(indent, text) {
1044
967
  return indent + width(text) <= BUDGET;
1045
968
  }
1046
- // A pair in statement position, by §3.4. `prefix` is what stands
1047
- // before it on its line: the heads of the chain it hangs from, not yet
1048
- // written. Its value is laid out by §3.5 unless it is a plain map, and
1049
- // then in this order: a chain, when the map holds exactly one pair
1050
- // (D1); one line, when that fits the budget; the key repeated over the
1051
- // entries, when every entry can be one line that way; a braced block
1052
- // otherwise, whose entries are statements in turn. Whether the
1053
- // statement was rewritten by this tier -- merged, or repeated -- is
1054
- // returned, and the outermost such statement is checked: its spelling
1055
- // on the page against what the syntactic tier writes for the
1056
- // statements it came from, at the same indentation, which is what
1057
- // stays on the page when the check fails.
1058
969
  function emitStatement(w, p, indent, stmt, prefix) {
1059
970
  const mark = w.mark();
1060
971
  let rewritten = undefined !== p.orig;
@@ -1088,6 +999,15 @@ function emitStatement(w, p, indent, stmt, prefix) {
1088
999
  pending = false;
1089
1000
  count++;
1090
1001
  w.text(line.text);
1002
+ if ('block' === line.t) {
1003
+ // The record the descent stopped at: its entries are
1004
+ // statements in turn, and the whole statement this repeat
1005
+ // belongs to is what carries the check, so they are covered.
1006
+ emitBlock(w, '{', '}', line.node, indent, { meet: stmt.meet, covered: true });
1007
+ if (undefined !== line.trail) {
1008
+ w.text(line.trail);
1009
+ }
1010
+ }
1091
1011
  }
1092
1012
  rewritten = true;
1093
1013
  }
@@ -1121,11 +1041,6 @@ function emit(root, meet) {
1121
1041
  emitBody(w, undefined === meet ? root : mergeRuns(root), 0, undefined === meet ? undefined : { meet, covered: false }, true);
1122
1042
  return w.finish();
1123
1043
  }
1124
- // ---------------------------------------------------------------------
1125
- // The lint (§4): what the formatter points at and never touches. Two
1126
- // rules, both advice: the formatter never renames a key (§4.1) and
1127
- // never introduces an alias (§4.2), and a rule with a mechanical fix
1128
- // that keeps the document would belong to §3 instead (§4.3).
1129
1044
  // The shape width at which a repeat is worth an alias (§4.2): below
1130
1045
  // it, `{ a:1 }` twice is the shorter spelling. Measured over the use
1131
1046
  // cases when the lint landed (§7.10).
@@ -1172,11 +1087,6 @@ function lineCol(text, at) {
1172
1087
  const before = text.slice(0, at);
1173
1088
  return { line: before.split('\n').length, col: at - before.lastIndexOf('\n') };
1174
1089
  }
1175
- // D4 (§4.1): keys are lower-case words, or CamelCase when a key is
1176
- // several. A bare key holding `_`, or beginning with two capitals, is
1177
- // reported with the spelling that would follow the form; a quoted key
1178
- // is a deliberate spelling and a key of underscores alone names
1179
- // nothing the rule can respell.
1180
1090
  function keyCase(node, text, out) {
1181
1091
  if ('pair' === node.t && BARE.test(node.key) && /[A-Za-z]/.test(node.key)) {
1182
1092
  const why = node.key.includes('_') ? 'holds an underscore'
@@ -1192,9 +1102,6 @@ function keyCase(node, text, out) {
1192
1102
  keyCase(child, text, out);
1193
1103
  }
1194
1104
  }
1195
- // The key as lower-case words or CamelCase: `credit_cents` is
1196
- // `creditCents`, `HTTP_PORT` is `httpPort`, `HTTPServer` is
1197
- // `httpServer`, `ID` is `id`.
1198
1105
  function camel(key) {
1199
1106
  const words = key.split('_').filter((w) => '' !== w)
1200
1107
  .map((w) => /^[A-Z]+$/.test(w) ? w.toLowerCase() : w);
@@ -1202,12 +1109,6 @@ function camel(key) {
1202
1109
  return head.charAt(0).toLowerCase() + head.slice(1) +
1203
1110
  words.slice(1).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join('');
1204
1111
  }
1205
- // D3 (§4.2): a shape written twice can drift, and an alias names it
1206
- // once. Every map or list whose shape recurs in the file, and whose
1207
- // shape is REPEAT_MIN_WIDTH or wider, is reported once, at its first
1208
- // site, with the count and the other sites; the naming is the
1209
- // author's. A repeat inside a repeat is the outer one's: the walk does
1210
- // not descend into a shape it reports.
1211
1112
  function repeats(nodes, text, out) {
1212
1113
  const counts = new Map();
1213
1114
  const tally = (node) => {
@@ -1242,9 +1143,6 @@ function repeats(nodes, text, out) {
1242
1143
  }
1243
1144
  }
1244
1145
  }
1245
- // A node's shape: its spelling with the layout, the comments and, for
1246
- // a map, the order of its entries taken out, so that two spellings of
1247
- // one value are one shape, as they are one canon.
1248
1146
  function shape(node) {
1249
1147
  switch (node.t) {
1250
1148
  case 'map':
@@ -1280,15 +1178,6 @@ function sameDocument(root, after) {
1280
1178
  const p = parseDoc(after, undefined, undefined);
1281
1179
  return undefined === p.errors && root.canon === p.root.canon;
1282
1180
  }
1283
- // The check of a lawful rewrite: the spelling before and the spelling
1284
- // after, evaluated in isolation, come to the same canon, the same
1285
- // kinds of failure, and the same outcome of generation (§7.3). Local,
1286
- // so it needs no include and no capability, and it applies whether or
1287
- // not the document as a whole evaluates. The kinds, not the count: how
1288
- // often one unresolved reference is reported depends on the order the
1289
- // meet took. Generation too, because the engine generates from more
1290
- // than the canon: a meet of maps with a nil member has refused a key
1291
- // the same map written once generates.
1292
1181
  function sameByMeet(before, after) {
1293
1182
  return meetOf(before) === meetOf(after);
1294
1183
  }
@@ -1330,12 +1219,6 @@ function checkFinding(path, expected, actual) {
1330
1219
  actual,
1331
1220
  };
1332
1221
  }
1333
- // THE TARGET'S OWN LINES ARE HELD ON LINES OF THEIR OWN (§3.14). The
1334
- // desugaring is line for line, so a line of output is known by the
1335
- // offset it begins at, and the node beginning there -- the quoted
1336
- // string the desugaring wrote -- is marked. From there on it has no
1337
- // one-line form, so every container holding it opens, and no two lines
1338
- // of the generated file are ever packed onto one.
1339
1222
  function holdOutput(nodes, at) {
1340
1223
  for (const node of nodes) {
1341
1224
  if (undefined !== node.at && at.has(node.at)) {
@@ -1363,11 +1246,6 @@ function outputAt(doc, flags) {
1363
1246
  }
1364
1247
  return at;
1365
1248
  }
1366
- // A finding's column in the TEMPLATE rather than in the document it
1367
- // carries (§3.14): the marker and its one space stand before the aontu
1368
- // on every line the resugaring writes. Every finding is on such a
1369
- // line -- the two rules point at a key or at a container, and a line of
1370
- // output is a bare string, which is neither.
1371
1249
  function shiftFindings(findings, mark) {
1372
1250
  return undefined === mark ? findings :
1373
1251
  findings.map((f) => ({ ...f, col: f.col + mark.length + 1 }));
@@ -1377,9 +1255,6 @@ function shiftFindings(findings, mark) {
1377
1255
  // what `--check` and `--list` report.
1378
1256
  function format(src, opts, hooks) {
1379
1257
  const text = lf(src);
1380
- // A GENERATOR IS FORMATTED AS THE DOCUMENT IT CARRIES (§3.14): the
1381
- // template surface's two transforms stand either side of the
1382
- // formatter, and between them is what happens to any other document.
1383
1258
  const mark = opts?.template;
1384
1259
  const doc = undefined === mark ? text : (0, template_1.desugarTemplate)(text, mark);
1385
1260
  const toks = [];
@@ -1412,11 +1287,6 @@ function format(src, opts, hooks) {
1412
1287
  findings: opts?.lint ? shiftFindings(lintOf(root, doc), mark) : [],
1413
1288
  };
1414
1289
  }
1415
- // The lines of a text, with a marker on the last when the text does
1416
- // not end in a newline: such a line never equals its
1417
- // newline-terminated twin, which is how the diff reports the
1418
- // difference, and the marker is rendered as diff renders it. NUL,
1419
- // which no source line ends in.
1420
1290
  const NO_NEWLINE = String.fromCharCode(0);
1421
1291
  function textLines(text) {
1422
1292
  if ('' === text) {
@@ -1513,8 +1383,6 @@ function patience(a, x0, x1, b, y0, y1, out) {
1513
1383
  out.push({ op: ' ', text: a[x1 + k] });
1514
1384
  }
1515
1385
  }
1516
- // The diff in unified format, three lines of context, the file named
1517
- // on both sides. Empty when the texts are the same.
1518
1386
  function unifiedDiff(name, before, after) {
1519
1387
  const a = textLines(before);
1520
1388
  const b = textLines(after);
@@ -1544,8 +1412,6 @@ function unifiedDiff(name, before, after) {
1544
1412
  for (const [s, e] of hunks) {
1545
1413
  const from = Math.max(s - 3, 0);
1546
1414
  const to = Math.min(e + 4, edits.length);
1547
- // Everything between two hunks is context -- a change would have
1548
- // opened a hunk -- so both sides advance together.
1549
1415
  for (; next < from; next++) {
1550
1416
  ai++;
1551
1417
  bi++;