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/lang.js CHANGED
@@ -2,18 +2,9 @@
2
2
  /* Copyright (c) 2021-2025 Richard Rodger, MIT License */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.Site = exports.Lang = void 0;
5
- // import { performance } from 'node:perf_hooks'
6
- // Named imports, not `import * as`: the namespace form makes tsc emit
7
- // the __importStar downlevel helper, whose branches no supported Node
8
- // takes (the same rule cli.ts records). Aliased because `Path` is
9
- // already the @tabnas/path plugin below.
10
5
  const node_fs_1 = require("node:fs");
11
6
  const node_path_1 = require("node:path");
12
7
  const jsonic_1 = require("@tabnas/jsonic");
13
- // THE CONFIG-FORMAT READERS (ADR-012). Each is a jsonic plugin for one
14
- // format, so an included `.toml` or `.yaml` is parsed by a real parser
15
- // for that format rather than guessed at by this one. `@tabnas/json` is
16
- // the strict RFC 8259 reader, used for `.json` and `.jsonld`.
17
8
  const sig_1 = require("./sig");
18
9
  const json_1 = require("@tabnas/json");
19
10
  const toml_1 = require("@tabnas/toml");
@@ -23,18 +14,11 @@ const yaml_1 = require("@tabnas/yaml");
23
14
  const ini_1 = require("@tabnas/ini");
24
15
  const debug_1 = require("@tabnas/debug");
25
16
  const multisource_1 = require("@tabnas/multisource");
26
- // TODO: @tabnas/multisource should support virtual fs
27
17
  const file_1 = require("@tabnas/multisource/resolver/file");
28
18
  const pkg_1 = require("@tabnas/multisource/resolver/pkg");
29
19
  const mem_1 = require("@tabnas/multisource/resolver/mem");
30
- // The Aontu-source processor, TAKEN RATHER THAN ALIASED. The obvious
31
- // spelling is the alias `aon: 'jsonic'`, which multisource resolves
32
- // through its own processor map -- but `jsonic` is a FORMAT NAME in
33
- // the include table now, so that alias resolved to the plain-jsonic
34
- // DATA reader and every `.aon` include was suddenly parsed without the
35
- // language in it. Naming the function leaves nothing to collide with.
36
20
  const jsonic_2 = require("@tabnas/multisource/processor/jsonic");
37
- const std_1 = require("./std");
21
+ const aontumodel_1 = require("./aontumodel");
38
22
  const mod_1 = require("./mod");
39
23
  const expr_1 = require("@tabnas/expr");
40
24
  const path_1 = require("@tabnas/path");
@@ -67,11 +51,13 @@ const CopyFuncVal_1 = require("./val/CopyFuncVal");
67
51
  const KeyFuncVal_1 = require("./val/KeyFuncVal");
68
52
  const TypeFuncVal_1 = require("./val/TypeFuncVal");
69
53
  const HideFuncVal_1 = require("./val/HideFuncVal");
54
+ const AbnfFuncVal_1 = require("./val/AbnfFuncVal");
70
55
  const DeprecateFuncVal_1 = require("./val/DeprecateFuncVal");
71
56
  const ReferFuncVal_1 = require("./val/ReferFuncVal");
72
57
  const GraphAtomVal_1 = require("./val/GraphAtomVal");
73
58
  const PackFuncVal_1 = require("./val/PackFuncVal");
74
59
  const CmpFuncVal_1 = require("./val/CmpFuncVal");
60
+ const MaybeFuncVal_1 = require("./val/MaybeFuncVal");
75
61
  const NomFuncVal_1 = require("./val/NomFuncVal");
76
62
  const TranslateFuncVal_1 = require("./val/TranslateFuncVal");
77
63
  const EachFuncVal_1 = require("./val/EachFuncVal");
@@ -91,32 +77,11 @@ const OpenFuncVal_1 = require("./val/OpenFuncVal");
91
77
  const SuperFuncVal_1 = require("./val/SuperFuncVal");
92
78
  const ConstraintVal_1 = require("./val/ConstraintVal");
93
79
  const asPlugin = (p) => p;
94
- // Build the Val for a matched `0d` literal (see the `0d` value matcher
95
- // below). Leaf by source: digits only is a biginteger, a `.` or an
96
- // exponent makes it a bigdecimal.
97
- //
98
- // A literal over the D6 exactness budget becomes a LOCATED ERROR here
99
- // and not a rounded or expanded value: `0d1e1000000000` has a one-digit
100
- // coefficient, so only the scale bound catches it, and it is caught at
101
- // parse -- before plain-form rendering would try to materialise a
102
- // gigabyte of zeros.
103
- // The source text of a negated exact literal. `-` is a prefix OPERATOR,
104
- // not part of the literal, so the text has to be rebuilt here to keep
105
- // `src` meaning "how this value is spelled" (see bigVal).
106
80
  function negsrc(src) {
107
- // src is never empty here: it is a BIG_LITERAL_RE match (at minimum
108
- // the two chars `0d`) or an already-negated spelling. Computed exact
109
- // values do carry src '', but they are built at unify time, long
110
- // after this parse-time opmap.
111
81
  return src.startsWith('-') ? src.slice(1) : '-' + src;
112
82
  }
113
83
  function bigVal(res) {
114
84
  const lit = (0, Decimal_1.readBigLiteral)(res);
115
- // `src` is the literal's own text, and it is not decoration: a path
116
- // segment is spelled text, so `$.a.0d1` must address the key `0d1` --
117
- // the same key `a:{0d1:7}` creates -- rather than the number 1. See
118
- // RefVal.append. Without it the segment was empty and the reference
119
- // silently resolved to its own container.
120
85
  const src = res[0];
121
86
  return 'biginteger' === lit.leaf ? new BigIntegerVal_1.BigIntegerVal({ peg: lit.int, src }) :
122
87
  'bigdecimal' === lit.leaf ? new BigDecimalVal_1.BigDecimalVal({ peg: lit.dec, src }) :
@@ -126,43 +91,11 @@ function bigVal(res) {
126
91
  const CC_0 = 48;
127
92
  const CC_d = 100;
128
93
  const CC_D = 68;
129
- // THE ALIAS SIGIL. `%` is part of an alias's name, so the name is one
130
- // lexeme wherever it appears and its meaning is decided by position:
131
- // a BINDING in key position (`%uint8 = …` declares), a USE in value
132
- // position (`listen: %uint8` refers). docs/design/ALIASES.0.md §4.
133
94
  const CC_PCT = 37;
134
95
  const ALIAS_RE = /^%[A-Za-z_][A-Za-z0-9_]*/;
135
- // THE DECLARATION OPERATOR. `%name = value` declares; the `=` is the
136
- // pair's separator, lexed as the colon token so the declaration then
137
- // parses as a pair whose key is the alias name (ALIASES.0.md X-1, as
138
- // settled 2026-09-05). `=` is syntax ONLY there: anywhere else it is
139
- // punctuation outside its syntax, and the bare-text scan below refuses
140
- // it (`foo = 1`, `a: x=y`).
141
96
  const CC_EQ = 61;
142
97
  const CC_SP = 32;
143
98
  const CC_TAB = 9;
144
- // THE BARE-TEXT RULE. A bare string holds letters, digits, `-` and `_`,
145
- // and nothing else. Every other punctuation character is either SYNTAX,
146
- // where the grammar gives it a meaning, or an ERROR where it does not
147
- // -- never silently part of a string. `x=y`, `6/2`, `50%` and `>10`
148
- // were all bare strings once, each a well-formed wrong document, and
149
- // each is refused now, naming the character (bare_punct).
150
- //
151
- // scanBareRun classifies each character of a run three ways, in this
152
- // order: TEXT continues the run; an ENDER stops it; anything else is
153
- // BAD. The ender set is the lexer's own -- space, line, fixed tokens,
154
- // comment starters -- read from the config its text matcher was built
155
- // from, so it cannot drift from the grammar. A bad run is still scanned
156
- // to its ender, so the refusal claims the whole spelling and the lexer
157
- // never reads the tail of it as syntax.
158
- //
159
- // `-` is text wherever the scan sees it. A run never STARTS on one:
160
- // `-` is the sign of a number and the negation prefix, a fixed token
161
- // the fixed matcher claims before either scanning stage can run, so
162
- // `a:-1` is the negation of 1 and `a:6-2` the string. The `+` of an
163
- // exponent (`1e+2`) is admitted only by the NUMBER stage's scan, the
164
- // one stage that can make a number of it. Mirrors scanBareRun in
165
- // go/lang.go, decision for decision.
166
99
  const CC_9 = 57;
167
100
  const CC_A = 65;
168
101
  const CC_Z = 90;
@@ -233,34 +166,10 @@ const NUMBER_RUN_RE = /^[-+]?(?:0(?:[xX][0-9a-fA-F_]+|[oO][0-7_]+|[bB][01_]+)|[0
233
166
  const NOT_A_NUMBER = { done: true, token: undefined };
234
167
  let AontuJsonic = function AontuLang(jsonic) {
235
168
  jsonic.use(asPlugin(path_1.Path));
236
- // Only # line comments are valid Aontu syntax (see
237
- // docs/reference-language.md; go/lang.go sets the same). Clear the
238
- // underlying jsonic comment markers entirely, then define # directly,
239
- // so the comment set is hash-only regardless of those defaults.
240
169
  let dotRef = (r, ctx, terms, prefix) => {
241
170
  terms = dropUnfilled(terms);
242
171
  if (0 === terms.length)
243
172
  return incompleteNil(r, ctx);
244
- // AN ALIAS IS NOT A PATH SEGMENT. `$.%foo` is refused: the alias
245
- // namespace and the path namespace are disjoint, and an alias is
246
- // reached by writing `%foo` and only that.
247
- //
248
- // The engine spells an alias reference AS a root reference to the
249
- // declaration -- which is what gives it order independence and a
250
- // cycle check shared with paths -- but that is an implementation of
251
- // the name, not a second way to write it. Left writable, the two
252
- // spellings would drift apart the moment aliases stop being
253
- // file-shaped, and `$.%b` inside an included file would reach the
254
- // INCLUDER's `%b` rather than its own, which is exactly the
255
- // cross-file capture the sigil exists to prevent.
256
- // `%foo` lexes to the reference itself, so in `$.%foo` it arrives
257
- // as a TERM rather than as a string segment -- both shapes are
258
- // checked, since a quoted `$."%foo"` would arrive as the string.
259
- // Terms here are always Vals -- dropUnfilled has removed the
260
- // nulls, and the dot rules never hand over a raw string -- so the
261
- // shapes are exactly three: a RefVal (peg is the segment array), a
262
- // StringVal (peg is the segment), and anything else (a numeric or
263
- // exact segment, which cannot be an alias name).
264
173
  for (const t of terms) {
265
174
  const segs = Array.isArray(t.peg) ? t.peg :
266
175
  ('string' === typeof t.peg ? [t.peg] : []);
@@ -281,48 +190,12 @@ let AontuJsonic = function AontuLang(jsonic) {
281
190
  },
282
191
  },
283
192
  });
284
- // Digit separators are legal only as a SINGLE separator BETWEEN
285
- // digits (the rule test/spec/engine-parity.tsv records as the engine's
286
- // adjudication; pinned by the sep-* rows in
287
- // test/spec/number-model.tsv). The engine's number matcher
288
- // enforces most of that already — `1_`, `_1`, `1_.5`, `1._5`, `1e_2`,
289
- // `1e2_` all fall through to text — but two gaps remain: a REPEATED
290
- // separator (`1__0` lexed as 10) and a separator at the edge of a
291
- // base-prefixed digit run (`0x_ff`, `0xff_` lexed as 255). Both
292
- // silently accept a typo as a different number, so aontu declines the
293
- // whole run instead and it lexes as text ("1__0"), exactly as `1_`
294
- // already does.
295
- //
296
- // `number.exclude` is tested against the matched number source and,
297
- // when it matches, makes the matcher decline the entire span. Kept in
298
- // lock-step with sepInvalid in go/lang.go, which is wired to the
299
- // equivalent `Number.Exclude` hook (and to the Check hook, which
300
- // constructs big base-prefixed tokens itself and so bypasses Exclude).
301
193
  jsonic.options({
302
194
  number: {
303
- // `__` repeated separator; `0x_`/`0o_`/`0b_` separator opening a
304
- // base-prefixed run; `_` closing any run. The prefix letter is
305
- // matched case-insensitively so the rule does not depend on which
306
- // prefix spellings the engine accepts.
307
195
  exclude: /__|^[-+]?0[xXoObB]_|_$/,
308
- // THE NUMBER STAGE OF THE BARE-TEXT RULE. The matcher runs before
309
- // the text matcher and reads a number up to the next ender -- and
310
- // `-` is an ender, being the negation prefix's fixed token, so it
311
- // would take the `2026` of `2026-09-05` and leave `-09-05` to the
312
- // grammar. The hook scans the whole run first and declines for
313
- // the matcher wherever the run is not its to lex: a run with a
314
- // bad character (the text stage refuses it), a run that is not a
315
- // number at all (`2026-09-05`, `6-2` are text). Twin of tsNumCheck
316
- // in go/lang.go.
317
196
  check: (lex) => {
318
197
  const pnt = lex.pnt;
319
198
  const src = lex.src;
320
- // The hook makes the matcher a candidate at every position, so
321
- // the common case -- a run no number can open -- declines for it
322
- // in one char read. A DIGIT opens a number here and nothing
323
- // else: the sign and the dot open the matcher's own grammar, but
324
- // they are fixed tokens (the prefix operators and member
325
- // access), claimed before this hook can run.
326
199
  const c = src.charCodeAt(pnt.sI);
327
200
  if (!(CC_0 <= c && c <= CC_9)) {
328
201
  return NOT_A_NUMBER;
@@ -335,67 +208,15 @@ let AontuJsonic = function AontuLang(jsonic) {
335
208
  },
336
209
  },
337
210
  });
338
- // D3 -- the `0d` literal, the only route to the exact leaves
339
- // (biginteger and bigdecimal). See BIG_LITERAL_RE for the grammar and
340
- // the leaf-by-source rule.
341
- //
342
- // The literal is claimed by the TEXT MATCHER'S CHECK HOOK (the sibling
343
- // of the `Number.Check` hook the Go port already uses for big
344
- // base-prefixed literals), not by a `value.def` entry, because a `0d`
345
- // run may contain a `.` and the two claim source differently:
346
- //
347
- // - A value def -- even a consuming one, matched against the full
348
- // forward source -- is applied INSIDE the text matcher, AFTER its
349
- // ender regexp has already carved the run at the `.`. The def
350
- // claims `0d1.5` whole, but the matcher then still emits the
351
- // ender's `.` as a fixed token, so `x:0d1.5` lexed as the
352
- // bigdecimal FOLLOWED BY a dangling member-access dot (a path
353
- // cycle). Verified, not theorised.
354
- // - The check hook runs BEFORE that ender regexp and returns the
355
- // token outright, so the run is claimed whole and nothing else is
356
- // emitted.
357
- //
358
- // A `match.value` matcher (which runs ahead of every other matcher)
359
- // also claims it correctly, but it is a candidate at EVERY lex
360
- // position and materializes the forward source there: ~8% on a
361
- // text-heavy document, for a syntax almost none of them use. The check
362
- // hook only runs where the text matcher already runs, and measures at
363
- // parity with not having it.
364
- //
365
- // The number matcher never sees these runs at all: it declines `0d…`
366
- // outright, since `d` is not an ender.
367
211
  jsonic.options({
368
212
  text: {
369
213
  check: (lex) => {
370
- // Guard first, on char codes: this hook runs at every text
371
- // position, and the common case (any run that cannot be a `0d`
372
- // literal or an alias) must cost two char reads and no
373
- // allocation.
374
214
  const pnt = lex.pnt;
375
215
  const src = lex.src;
376
- // AN ALIAS NAME IS CLAIMED WHOLE, for the same reason the `0d`
377
- // run below is: the text matcher's ender regexp would otherwise
378
- // carve `%uint8` at the `%` and emit the sigil as its own token,
379
- // leaving a bare `uint8` behind -- which is exactly the capture
380
- // the sigil exists to prevent. Claiming it here, before that
381
- // ender runs, keeps the name one lexeme.
382
- //
383
- // The token's SOURCE is the whole `%name`, which is what makes
384
- // the same lexeme work in both positions: jsonic keys a pair by
385
- // the token's source text (`0d1: 5` yields the key `0d1`), so a
386
- // declaration reads as the key `%uint8`, while a value position
387
- // calls the function below and gets the reference.
388
- // A `%` that opens no name (`%`, `%1`, `50%`) falls through to
389
- // the bare-text scan below, which refuses it.
390
216
  const ares = CC_PCT === src.charCodeAt(pnt.sI) ?
391
217
  ALIAS_RE.exec(lex.refwd()) : null;
392
218
  if (null != ares) {
393
219
  const asrc = ares[0];
394
- // A lone `=` after the name, across horizontal space only, is
395
- // the declaration operator. Decided HERE, where the name is
396
- // claimed, and only its position is kept: the very next text
397
- // position is that `=`, since nothing but space sits between,
398
- // so the mark cannot outlive its one use. `==` is not it.
399
220
  let j = pnt.sI + asrc.length;
400
221
  while (j < src.length &&
401
222
  (CC_SP === src.charCodeAt(j) || CC_TAB === src.charCodeAt(j))) {
@@ -404,24 +225,11 @@ let AontuJsonic = function AontuLang(jsonic) {
404
225
  if (CC_EQ === src.charCodeAt(j) && CC_EQ !== src.charCodeAt(j + 1)) {
405
226
  lex.aontu_eq_at = j;
406
227
  }
407
- const atkn = lex.token('#VL',
408
- // AN ALIAS REFERENCE IS A PATH REFERENCE. `%uint8` is
409
- // `$.%uint8`: root-absolute, one segment, spelled with the
410
- // sigil the declaration is spelled with. Everything the
411
- // design asks of it -- order independence, alias-of-alias,
412
- // redeclaration unifying, cycle refusal spanning both
413
- // namespaces -- is then the reference machinery already in
414
- // the language, not a second resolver beside it.
415
- (r, ctx) => addsite(new RefVal_1.RefVal({ peg: [asrc], absolute: true }), r, ctx), asrc, pnt);
228
+ const atkn = lex.token('#VL', (r, ctx) => addsite(new RefVal_1.RefVal({ peg: [asrc], absolute: true }), r, ctx), asrc, pnt);
416
229
  pnt.sI += asrc.length;
417
230
  pnt.cI += asrc.length;
418
231
  return { done: true, token: atkn };
419
232
  }
420
- // The `=` the alias arm above marked: the separator of a
421
- // declaration, as a colon token whose source is `=`. The pair rule
422
- // is then the pair rule, and the formatter writes the spelling it
423
- // read. Marked in `use` so the pair rule can tell it from a colon,
424
- // which no longer declares.
425
233
  if (CC_EQ === src.charCodeAt(pnt.sI) && lex.aontu_eq_at === pnt.sI) {
426
234
  delete lex.aontu_eq_at;
427
235
  const eqtkn = lex.token('#CL', undefined, '=', pnt, { aontu_eq: true });
@@ -432,18 +240,9 @@ let AontuJsonic = function AontuLang(jsonic) {
432
240
  if (CC_0 === src.charCodeAt(pnt.sI)) {
433
241
  const c1 = src.charCodeAt(pnt.sI + 1);
434
242
  if (CC_d === c1 || CC_D === c1) {
435
- // BIG_LITERAL_RE is `^`-anchored and read against the
436
- // forward source (memoized per position by refwd), which is
437
- // what lets it claim the `.` of `0d1.5`. A `0d` run it does
438
- // not match falls through to the bare-text scan below.
439
243
  const res = Decimal_1.BIG_LITERAL_RE.exec(lex.refwd());
440
244
  if (null != res) {
441
245
  const msrc = res[0];
442
- // The token value is a FUNCTION so Val construction
443
- // happens at parse time, where the rule and context needed
444
- // for the site exist (jsonic calls a #VL token's function
445
- // value with them). A `0d` literal never spans a line, so
446
- // only the source and column positions advance.
447
246
  const tkn = lex.token('#VL', (r, ctx) => addsite(bigVal(res), r, ctx), msrc, pnt);
448
247
  pnt.sI += msrc.length;
449
248
  pnt.cI += msrc.length;
@@ -451,21 +250,9 @@ let AontuJsonic = function AontuLang(jsonic) {
451
250
  }
452
251
  }
453
252
  }
454
- // THE BARE-TEXT RULE (scanBareRun). Last, so that a name, a
455
- // declaration operator and an exact literal are read before a
456
- // run is judged as text.
457
- // The run is never empty: every ender is a token an earlier
458
- // matcher claims, so the text stage only opens on a character
459
- // the scan classifies as text or as bad.
460
253
  const run = scanBareRun(lex.cfg, src, pnt.sI, false);
461
254
  const msrc = src.slice(pnt.sI, run.end);
462
255
  if (-1 !== run.bad) {
463
- // BAD: the run is refused whole, sited at the character (the
464
- // mark in `use` is what tokenSite reads). As a VALUE the
465
- // token's function builds the refusal at the parse, where the
466
- // rule carries the position. As a KEY the token is read for
467
- // its source alone, so the mark is what the pair and elem
468
- // rules read to write the refusal where the map is built.
469
256
  const ch = run.ch;
470
257
  const tkn = lex.token('#VL', (r, ctx) => {
471
258
  const nv = addsite(new NilVal_1.NilVal({ why: 'bare_punct' }), r, ctx);
@@ -476,11 +263,6 @@ let AontuJsonic = function AontuLang(jsonic) {
476
263
  pnt.cI += msrc.length;
477
264
  return { done: true, token: tkn };
478
265
  }
479
- // CLEAN, with a `-` past its start (`team-payments`,
480
- // `2026-09-05`): claimed here as one text token, because the
481
- // default matcher's ender set would carve the run at the `-`.
482
- // Any other clean run is the default matcher's, which also reads
483
- // the value keywords and the `_` hole.
484
266
  if (-1 !== msrc.indexOf('-')) {
485
267
  const tkn = lex.token('#TX', msrc, msrc, pnt);
486
268
  pnt.sI += msrc.length;
@@ -518,14 +300,6 @@ let AontuJsonic = function AontuLang(jsonic) {
518
300
  v.path = r.k ? [...r.k.path] : [];
519
301
  return v;
520
302
  };
521
- // THE KEY REFUSALS a pair may carry, decided from its key TOKEN --
522
- // never from the key text alone, since a quoted `"%a"` or `"x=y"` is
523
- // an ordinary key: a declaration spelled with a colon (alias_colon),
524
- // and a key the bare-text rule refuses (bare_punct). Undefined for an
525
- // ordinary key, and for a declaration (`%a = 1`), which is a binding
526
- // (isAliasDecl), not a refusal. Asked FIRST by the pair rule and by
527
- // the elem rule, before the declaration is, so a pair in list
528
- // position is held to the map's rules.
529
303
  const isAliasDecl = (ktkn, sep) => null != ktkn && VL === ktkn.tin && ALIAS_RE.test('' + ktkn.src) &&
530
304
  true === sep?.use?.aontu_eq;
531
305
  const keyRefusalOf = (ktkn, sep) => {
@@ -564,10 +338,6 @@ help isolate the syntax error.`,
564
338
  },
565
339
  value: {
566
340
  def: {
567
- // NOTE: specify with functions as jsonic/deep will
568
- // remove class prototype as options are assumed plain
569
- // (except for functions).
570
- // TODO: jsonic should be able to pass context into these
571
341
  'string': {
572
342
  val: (r, ctx) => addsite(new ScalarKindVal_1.ScalarKindVal({ peg: String }), r, ctx)
573
343
  },
@@ -583,8 +353,6 @@ help isolate the syntax error.`,
583
353
  'float': {
584
354
  val: (r, ctx) => addsite(new ScalarKindVal_1.ScalarKindVal({ peg: ScalarKindVal_1.Float }), r, ctx)
585
355
  },
586
- // The two exact leaves. Their keywords are the marker class
587
- // names lowercased, which is also how ScalarKindVal canons them.
588
356
  'biginteger': {
589
357
  val: (r, ctx) => addsite(new ScalarKindVal_1.ScalarKindVal({ peg: ScalarKindVal_1.BigInteger }), r, ctx)
590
358
  },
@@ -597,7 +365,6 @@ help isolate the syntax error.`,
597
365
  'nil': {
598
366
  val: (r, ctx) => addsite(new NilVal_1.NilVal({ why: 'literal_nil' }), r, ctx)
599
367
  },
600
- // TODO: FIX: need a TOP instance to hold path
601
368
  'top': { val: () => (0, top_1.top)() },
602
369
  // G8 phase 3: the placeholder. A BARE `_` is the hole; `"_"`
603
370
  // quoted, and any longer bare word containing it, stay text.
@@ -612,7 +379,6 @@ help isolate the syntax error.`,
612
379
  let pval = prev;
613
380
  let cval = curr;
614
381
  if (pval?.isVal && cval?.isVal) {
615
- // TODO: test multi element conjuncts work
616
382
  if (pval.isConjunct && cval.isConjunct) {
617
383
  pval.append(cval);
618
384
  return pval;
@@ -628,14 +394,6 @@ help isolate the syntax error.`,
628
394
  // Handle defered conjuncts, where MapVal does not yet
629
395
  // exist, by creating ConjunctVal later.
630
396
  else {
631
- // AN INCLUDE UNIFIES IN PLACE. multisource calls this hook at
632
- // the `@`'s own source position, so `prev` holds exactly the
633
- // pairs written BEFORE it. Folding the loaded map's keys in
634
- // here -- host-so-far first, arriving value second -- is what
635
- // inlining the loaded bytes at the `@` does, and mirrors
636
- // go/lang.go's Map.Merge, which multisource-go drives one key
637
- // at a time. A non-map load has no keys to fold and stays a
638
- // deferred conjunct arm.
639
397
  if (true === cval?.isMap) {
640
398
  const lm = cval;
641
399
  for (const k of Object.keys(lm.peg)) {
@@ -645,10 +403,6 @@ help isolate the syntax error.`,
645
403
  ? new ConjunctVal_1.ConjunctVal({ peg: [own, lm.peg[k]] })
646
404
  : lm.peg[k]);
647
405
  }
648
- // The loaded map's spread joins THIS map's spread list at
649
- // the `@`'s position: the parse pushes each `&:` onto the
650
- // node as it is read, so `prev[SPREAD].v` already holds the
651
- // spreads written before the `@` and nothing after it.
652
406
  if (null != lm.spread?.cj) {
653
407
  ;
654
408
  prev[type_1.SPREAD] =
@@ -682,20 +436,11 @@ help isolate the syntax error.`,
682
436
  move: MoveFuncVal_1.MoveFuncVal,
683
437
  path: PathFuncVal_1.PathFuncVal,
684
438
  pref: PrefFuncVal_1.PrefFuncVal,
685
- // First-class paths and the container kinds
686
- // (docs/design/PATHS.0.md). `path(p)` CAPTURES a path as a value;
687
- // `path()`, `map()` and `list()` are kinds -- the vacuous
688
- // constructor call admits its values and defaults to nothing,
689
- // where the container LITERALS `{}`/`[]` default to empty.
690
439
  map: ContainerKindVal_1.MapFuncVal,
691
440
  list: ContainerKindVal_1.ListFuncVal,
692
441
  close: CloseFuncVal_1.CloseFuncVal,
693
442
  open: OpenFuncVal_1.OpenFuncVal,
694
443
  super: SuperFuncVal_1.SuperFuncVal,
695
- // The constraint algebra's Band A atoms (G1 phase 1;
696
- // docs/reference-language.md, "The constraint algebra"): bounds
697
- // and exclusion enter through the function registry — the
698
- // established extension point — with zero grammar change.
699
444
  min: ConstraintVal_1.MinConstraintVal,
700
445
  max: ConstraintVal_1.MaxConstraintVal,
701
446
  above: ConstraintVal_1.AboveConstraintVal,
@@ -704,25 +449,15 @@ help isolate the syntax error.`,
704
449
  // G1 phase 2: pattern membership, over the portable subset both
705
450
  // host regex engines agree on (nonPortableRe in ConstraintVal.ts).
706
451
  re: ConstraintVal_1.ReConstraintVal,
707
- // G1 phase 3: the sizing atoms. Both are properties of a CONTAINER
708
- // (or, for length, of a string) rather than comparisons against a
709
- // value, which is why `unique` is the one built-in taking no
710
- // argument at all.
711
452
  length: ConstraintVal_1.LengthConstraintVal,
712
453
  unique: ConstraintVal_1.UniqueConstraintVal,
713
- // G1 phase 5: Band B. `must` is the one atom the algebra does not
714
- // reason about -- it is checked against the finished value and
715
- // reported with the author's own message, never simplified and
716
- // never consulted for emptiness or subsumption.
717
454
  must: ConstraintVal_1.MustConstraintVal,
455
+ abnf: AbnfFuncVal_1.AbnfFuncVal,
456
+ parse: AbnfFuncVal_1.ParseFuncVal,
718
457
  // G3 phase 4: the deprecation mark. Unification-transparent; the
719
458
  // record rides the result (Val.deprecation) and canon renders the
720
459
  // call back (canonRiders).
721
460
  deprecate: DeprecateFuncVal_1.DeprecateFuncVal,
722
- // G4 phase 2: the checked, typed, LINK-shaped reference. A
723
- // constraint on a string field: the string must be a TREE ADDRESS
724
- // (`$.a.b` or `.b`), the address must resolve, and the optional
725
- // argument flows INTO the target. The field keeps the string.
726
461
  refer: ReferFuncVal_1.ReferFuncVal,
727
462
  rel: ReferFuncVal_1.RelFuncVal,
728
463
  // RELATIONS P2 (docs/design/RELATIONS.0.md §3.3): the graph
@@ -730,112 +465,32 @@ help isolate the syntax error.`,
730
465
  // govern. Lattice-inert; the verdict lands at generation.
731
466
  acyclic: GraphAtomVal_1.AcyclicFuncVal,
732
467
  inverse: GraphAtomVal_1.InverseFuncVal,
733
- // G8 phase 1: generation to KEYED CHILDREN. `pack` makes one keyed
734
- // child per child of its data, cloning its template per
735
- // destination exactly as a spread does, and waits for the model to
736
- // settle before it fires (the staging rule, G8 phase 0).
737
468
  pack: PackFuncVal_1.PackFuncVal,
738
- // RENDER P6: the order-preserving map, and generation to a LIST.
739
- // `each` makes one list element per child of its data, being the
740
- // template with `_` bound to the source child. It exists because
741
- // `pick(pack(...))` re-sorts to code-point order, and a struct's
742
- // fields or a file's imports are the model's order or they are
743
- // wrong.
744
- //
745
- // Mentioning the hole makes it a BOUND instead: `each(d, _ & t)`
746
- // meets each child with `t`, and `each(d, _)` is a bag's members
747
- // as a list. That is what the retired meet-only `each` spelled
748
- // (ADR-026), and why this one could take the name (ADR-027).
749
469
  each: EachFuncVal_1.EachFuncVal,
750
- // G8 phase 2: selection. `filter` keeps the children of a bag that
751
- // unify with a condition; `match` picks the first arm whose
752
- // pattern the scrutinee unifies with. Both select by
753
- // UNIFIABILITY, tried in trial mode, so neither adds a predicate
754
- // language to the one the lattice already is.
755
470
  filter: FilterFuncVal_1.FilterFuncVal,
756
471
  match: MatchFuncVal_1.MatchFuncVal,
757
- // The arithmetic family (the review's finding I). Maths beyond `+`
758
- // arrives as FUNCTIONS — `-` `*` `/` `%` stay reserved — and the
759
- // family is numeric where the operator is polymorphic, which is
760
- // what makes `add` more than a second spelling of `+`: it refuses
761
- // the string concatenation that silently answers `"500m" + "500m"`.
762
- // Every rule they obey is in ts/src/val/arith.ts.
763
472
  add: ArithFuncVal_1.AddFuncVal,
764
473
  sub: ArithFuncVal_1.SubFuncVal,
765
474
  mul: ArithFuncVal_1.MulFuncVal,
766
475
  div: ArithFuncVal_1.DivFuncVal,
767
476
  mod: ArithFuncVal_1.ModFuncVal,
768
477
  rem: ArithFuncVal_1.RemFuncVal,
769
- // Aggregation over a finite, settled bag (the review's finding I).
770
- // `least` and `greatest` rather than min and max, which are already
771
- // the atoms for a lower and an upper BOUND -- an aggregate over a
772
- // set and a bound on a value must not share a spelling.
773
478
  sum: AggFuncVal_1.SumFuncVal,
774
479
  least: AggFuncVal_1.LeastFuncVal,
775
480
  greatest: AggFuncVal_1.GreatestFuncVal,
776
- // Projection, which is what lets the aggregates reach a bag of
777
- // RECORDS: `sum(pick($.lines, amountCents))`. Not a clever `each`
778
- // template -- `each(d, _ & t)` MEETS each child, and a meet cannot
779
- // select.
481
+ maybe: MaybeFuncVal_1.MaybeFuncVal,
780
482
  pick: AggFuncVal_1.PickFuncVal,
781
- // G9 phase 2: the fold to a STRING. `sum` folds with `add`; this
782
- // folds with `+`, so it inherits the one number-to-text rule and
783
- // the language does not grow a second. It is the primitive that
784
- // turns a bag of computed lines into a file.
483
+ sort: AggFuncVal_1.SortFuncVal,
785
484
  join: AggFuncVal_1.JoinFuncVal,
786
- // G9 phase 6: apply-templates. One flat list of pieces from a
787
- // selection and a RULE TABLE -- for each node, the first template
788
- // whose `match` it unifies with, its `body` instantiated at that
789
- // node. The dispatch is the engine's because a body referenced by
790
- // path resolves its references at the definition site, and the
791
- // relative resolution that does exist is a dot count that does not
792
- // survive a second dispatch (docs/design/EMIT.0.md).
793
485
  emit: EmitFuncVal_1.EmitFuncVal,
794
- // G9 phase 6: the string builtins the rule layer needs. `esc`
795
- // makes a value safe inside a literal and `usc` reads it back;
796
- // `rep` and `split` derive names from model data. All four are
797
- // ordinary string functions -- they know nothing about generation,
798
- // which is why they can land before the renderer does.
799
486
  esc: StrFuncVal_1.EscFuncVal,
800
487
  usc: StrFuncVal_1.UscFuncVal,
801
488
  rep: StrFuncVal_1.RepFuncVal,
802
489
  split: StrFuncVal_1.SplitFuncVal,
803
- // THE COMPONENT PRIMITIVES -- SPIKE (ts/src/val/CmpFuncVal.ts,
804
- // docs/design/JOSTRACA.0.md). jostraca's component set, spelled
805
- // as functions -- LOWER CASE, like every other builtin in this
806
- // language, while the node each one builds names the jostraca
807
- // component it drives (`file(...)` is aontu, `"File"` is
808
- // jostraca's). A document then says what FILES it produces
809
- // instead of filling in the `aontu:code` vocabulary as data.
810
- // Eight of jostraca's ten: `copy` and `list` are already builtins
811
- // here with unrelated meanings, so those two have no lower-case
812
- // spelling to take (see ts/src/val/CmpFuncVal.ts).
813
- //
814
- // TypeScript only, and so deliberately NOT in
815
- // test/spec/signature.tsv, BUILTIN_FUNCS (ts/src/lsp.ts) or the
816
- // grammar/ files -- each is asserted in cross-port parity and a
817
- // TS-only entry turns the Go suite red. Arity and argument shape
818
- // are refused in CmpFuncVal.resolve for the same reason.
819
490
  ...CmpFuncVal_1.CMP_FUNCS,
820
- // NAME TRANSFORMATION -- SPIKE (ts/src/val/NamerFuncVal.ts).
821
- // Generated code is mostly names, and no two targets spell them
822
- // the same way. Splits a name into words whatever format it is
823
- // written in, then renders it in the target's. TypeScript only,
824
- // and out of the parity-pinned registries for the reason the
825
- // component primitives are.
826
491
  nom: NomFuncVal_1.NomFuncVal,
827
- // PER-CHARACTER SUBSTITUTION AND DELETION -- SPIKE
828
- // (ts/src/val/TranslateFuncVal.ts), after `tr`. Reads the source
829
- // once and consults a table, which is what `rep` cannot do: a
830
- // per-character map spelled as N `rep` calls composes wrongly,
831
- // since each pass sees the previous one's output.
832
492
  translate: TranslateFuncVal_1.TranslateFuncVal,
833
493
  };
834
- // A dangling operator (`a:1|`, `a:$`, `a:*` at end of input) leaves
835
- // null/undefined unfilled terms. Junction ops drop them (so `a:1&`
836
- // and `a:1|` are just 1); ops missing a required operand become an
837
- // incomplete_expression nil, surfaced by generate() as a "Cannot
838
- // resolve value" error (the Go port mirrors this in lang.go).
839
494
  const dropUnfilled = (terms) => terms.filter((t) => null != t);
840
495
  const incompleteNil = (r, ctx) => addsite(new NilVal_1.NilVal({ why: 'incomplete_expression' }), r, ctx);
841
496
  // Build a call from a NAME and the argument terms as the author
@@ -843,27 +498,10 @@ help isolate the syntax error.`,
843
498
  // raw-value conversion, stated once.
844
499
  const buildCall = (r, ctx, fname, argterms) => {
845
500
  const funcval = funcMap[fname];
846
- // Arity is known for every built-in, so a surplus or missing
847
- // argument is a mistake in the SOURCE, refused here where the
848
- // author can see it (issue #51). It was previously left to each
849
- // function to notice or not: the two ports disagreed on `upper()`
850
- // and on `close()`, and `min(1,2)` noticed nothing at all -- it
851
- // built a constraint that merely refused to generate later, with a
852
- // message about the map rather than about the call.
853
- //
854
- // Counted BEFORE the rawToVal pass below, which is what makes the
855
- // count possible: a comma group arrives as a RAW array and a
856
- // written list literal as a ListVal, and rawToVal turns the first
857
- // into the second.
858
501
  const arity = funcArity[fname];
859
502
  if (null != arity) {
860
503
  const got = writtenArgCount(argterms);
861
504
  if (got < arity[0] || (-1 !== arity[1] && got > arity[1])) {
862
- // details is assigned AFTER construction: the NilVal
863
- // constructor does not read it from its spec (only NilVal.make
864
- // does), so passing it in the spec left the hint's
865
- // {func}/{want}/{got} placeholders un-injected and printed
866
- // literally.
867
505
  const nil = new NilVal_1.NilVal({ why: 'func_arity' });
868
506
  nil.details = {
869
507
  func: fname,
@@ -873,22 +511,6 @@ help isolate the syntax error.`,
873
511
  return addsite(nil, r, ctx);
874
512
  }
875
513
  }
876
- // rawToVal EVERY argument. A degenerate expression can hand this
877
- // handler raw parse values rather than Vals -- `pref(1-3)` arrives
878
- // as the plain numbers 1 and -3 -- and a func's peg is unified
879
- // element by element, so a raw one reached `arg.unify(...)` and
880
- // threw. The unifier's catch-all turned that into an `internal`
881
- // verdict: a crash reported as a unification result (issue #49).
882
- // The Go port has always converted here (asVal in evaluate).
883
- // A comma group is ONE raw-array term (see writtenArgCount).
884
- // For a function whose arguments are distinct POSITIONS —
885
- // deprecate's value and record, pack's and each's data and template
886
- // — the group is expanded back into them here, while a written list
887
- // literal, already a ListVal, stays one argument. The constraint
888
- // atoms make the same move in their own constructor (atomArgs,
889
- // ConstraintVal.ts), which is why they are not in this set:
890
- // `neq(1,2)` is one argument LIST, not two positions, and expanding
891
- // it here would take the list away from the code that reads it.
892
514
  let terms = argterms;
893
515
  if (true === POSITIONAL_ARG_FUNCS[fname] && 1 === terms.length &&
894
516
  Array.isArray(terms[0])) {
@@ -911,24 +533,6 @@ help isolate the syntax error.`,
911
533
  'star-prefix': (r, ctx, _op, terms) => {
912
534
  if (null == terms[0])
913
535
  return incompleteNil(r, ctx);
914
- // A PREFERENCE MARKS A VALUE, AND A BARE KEY IS NOT ONE.
915
- // `*a: 1` has no braces, so the prefix took the whole IMPLICIT
916
- // map as its operand and the document silently became
917
- // `*{"a":1}` -- `*a: 1, b: 2` became a one-element LIST, losing
918
- // `b` outright. Neither is anything the author wrote.
919
- //
920
- // The accident is confined to the first position of the implicit
921
- // top-level map, which is the only place no brace has yet
922
- // committed the rule to a map: `{*a: 1}` and `a: 1, *b: 2` are
923
- // ALREADY parse errors. This makes the third spelling agree with
924
- // them rather than inventing a meaning for it.
925
- //
926
- // A BRACED operand is untouched, and that is the whole of the
927
- // distinction: `*{x:1}` and `*[1]` are the real spelling, they
928
- // are what `*{x:1} | *{y:2}` needs, and the shared spec pins them
929
- // (11 rows). The open token's own source text is what separates
930
- // the two -- `{` or `[` for a braced bag, the first key or
931
- // element for an implicit one.
932
536
  const bag = terms[0];
933
537
  if ((bag.isMap && '{' !== bag.site.src) ||
934
538
  (bag.isList && '[' !== bag.site.src)) {
@@ -952,7 +556,6 @@ help isolate the syntax error.`,
952
556
  terms[0].peg.some((seg) => 'string' === typeof seg && ALIAS_RE.test(seg))) {
953
557
  return addsite(new NilVal_1.NilVal({ why: 'alias_in_path' }), r, ctx);
954
558
  }
955
- // $.a.b absolute path
956
559
  if (terms[0] instanceof RefVal_1.RefVal) {
957
560
  terms[0].absolute = true;
958
561
  return terms[0];
@@ -968,10 +571,6 @@ help isolate the syntax error.`,
968
571
  let val = terms[0];
969
572
  if (null == val)
970
573
  return incompleteNil(r, ctx);
971
- // The exact leaves negate exactly and never change kind. R2/D5
972
- // holds here too: bigint has a single zero, and Decimal's
973
- // normalising constructor sends every zero to the same form, so
974
- // `-0d0` is `0d0` and `-0d0.0` is `0d0.0`.
975
574
  if (val instanceof BigIntegerVal_1.BigIntegerVal) {
976
575
  return addsite(new BigIntegerVal_1.BigIntegerVal({ peg: -val.peg, src: negsrc(val.src) }), r, ctx);
977
576
  }
@@ -983,18 +582,10 @@ help isolate the syntax error.`,
983
582
  if (!(val instanceof IntegerVal_1.IntegerVal) && !(val instanceof NumberVal_1.NumberVal)) {
984
583
  return addsite(new NilVal_1.NilVal({ why: 'negative' }), r, ctx);
985
584
  }
986
- // Build a fresh Val rather than mutating in place: the expr plugin
987
- // can evaluate the same node twice (e.g. inside `*-1` or a
988
- // disjunct member), and an in-place `peg = -peg` applied twice
989
- // silently un-negates the number.
990
585
  let peg = -1 * val.peg;
991
586
  // Normalize -0 to 0 (keeps the AST and canon free of negative zero).
992
587
  if (0 === peg)
993
588
  peg = 0;
994
- // Negation never narrows the kind: a number stays a number. An
995
- // integer stays an integer unless the negation leaves the int64
996
- // range (only -(-2^63), which no literal can express), in which
997
- // case it widens to a number rather than failing.
998
589
  const out = val instanceof IntegerVal_1.IntegerVal && (0, numkind_1.isIntegerKind)(peg)
999
590
  ? new IntegerVal_1.IntegerVal({ peg })
1000
591
  : new NumberVal_1.NumberVal({ peg });
@@ -1026,7 +617,6 @@ help isolate the syntax error.`,
1026
617
  jsonic
1027
618
  .use(asPlugin(expr_1.Expr), {
1028
619
  op: {
1029
- // disjunct < conjunct: c & b | a -> (c & b) | a
1030
620
  'conjunct': {
1031
621
  infix: true, src: '&', left: 16_000_000, right: 17_000_000
1032
622
  },
@@ -1039,16 +629,6 @@ help isolate the syntax error.`,
1039
629
  left: 20_000_000,
1040
630
  right: 21_000_000,
1041
631
  },
1042
- // Re-base the unary prefixes for the same reason. Every aontu
1043
- // operator sits far above the @tabnas/expr defaults, so the
1044
- // default prefix binding power of 4_000_000 left unary `-`/`+`
1045
- // LOOSER than every infix operator: `-1 & integer` parsed as
1046
- // `-(1 & integer)`, and negative-prefix (below) then rejected
1047
- // the composite operand as a `negative` error nil (likewise
1048
- // `-2+3`, `-1|2`). Unary minus must bind tighter than `+`, `&`
1049
- // and `|` — but still looser than `.` (dot-infix left is
1050
- // 25_000_000), so `-0xFF.5` stays `-(0xFF.5)` and `$`.
1051
- // Kept in lock-step with the op table in go/lang.go.
1052
632
  'negative': {
1053
633
  src: '-',
1054
634
  prefix: true,
@@ -1097,15 +677,11 @@ help isolate the syntax error.`,
1097
677
  remainder: null,
1098
678
  },
1099
679
  evaluate: (r, ctx, op, terms) => {
1100
- // // console.log('EVAL-START', r.u)
1101
680
  if ('func-paren' === op.name
1102
- // && !r.parent.prev?.u?.paren_preval
1103
681
  && !r.u?.paren_preval) {
1104
- // terms = [new StringVal({ peg: '' }), ...terms]
1105
682
  terms = ['', ...terms];
1106
683
  }
1107
684
  let val = opmap[op.name](r, ctx, op, terms);
1108
- // // console.log('EVAL', terms, '->', val)
1109
685
  return val;
1110
686
  }
1111
687
  });
@@ -1119,16 +695,6 @@ help isolate the syntax error.`,
1119
695
  const OPTKEY = [TX, ST, NR];
1120
696
  jsonic.rule('expr', (rs) => {
1121
697
  rs.close([
1122
- // A `&` followed by `:` after an expression value belongs to the
1123
- // enclosing map as a spread, not to the expression as a conjunct
1124
- // — backtrack both tokens so the expression completes (and
1125
- // evaluates to a Val) and the map's spread alts take over. This
1126
- // is what makes `k1:$flag &:boolean` parse: without it the expr
1127
- // plugin consumes the `&` as an infix conjunct, chokes on the
1128
- // `:`, and leaves the raw unevaluated expr node in the map
1129
- // (mirrors the expr-rule PrependClose in go/lang.go). The
1130
- // `n: { expr: 0 }` reset matches the plugin's own expr-end alts —
1131
- // the evaluation after-close only fires when the counter is 0.
1132
698
  { s: [CJ, CL], b: 2, n: { expr: 0 }, g: 'expr,expr-end,spread' },
1133
699
  ]);
1134
700
  return rs;
@@ -1175,18 +741,6 @@ help isolate the syntax error.`,
1175
741
  if (!Number.isFinite(r.node)) {
1176
742
  valnode = addsite(new NilVal_1.NilVal({ why: 'not_number' }), r, ctx);
1177
743
  }
1178
- // D7 -- A LOSSY INTEGER LITERAL IS REFUSED, NOT ROUNDED. The
1179
- // token above is already a double, so a literal the double
1180
- // cannot hold exactly (2^53+1, 0x7fffffffffffffff,
1181
- // 0xffffffffffffffff) has ALREADY become a different number by
1182
- // the time it gets here. Storing it would mean the document
1183
- // silently means something other than what it says, so the
1184
- // literal becomes a located error whose hint names the escape:
1185
- // write it `0d…` and get the exact value.
1186
- //
1187
- // The rule is EXACTNESS, not magnitude -- 10^20 and 2^124 are
1188
- // both far outside the int64 window and both land exactly on a
1189
- // binary64, so both stay values (see isLossyIntegerLiteral).
1190
744
  else if ((0, numkind_1.isLossyIntegerLiteral)(r.node, r.o0.src)) {
1191
745
  const nil = new NilVal_1.NilVal({ why: 'lossy_integer_literal' });
1192
746
  nil.details = { src: r.o0.src };
@@ -1230,15 +784,6 @@ help isolate the syntax error.`,
1230
784
  const optionalKeys = r.u.aontu_optional_keys ?? [];
1231
785
  const aliasKeys = r.u.aontu_alias_keys ?? [];
1232
786
  let mo = r.node;
1233
- // An elided value (`a:`) leaves a raw null/undefined that never
1234
- // passed through the val rule. It is REFUSED rather than made a
1235
- // null (issue #48): a key with nothing after the colon is a
1236
- // mistake in the source, and turning it into a value made that
1237
- // mistake indistinguishable from a deliberate `a:null`.
1238
- //
1239
- // A colon chain (`a: b:1`) is not an elision -- the value is the
1240
- // nested pair, which the val rule does produce -- and neither is
1241
- // a trailing comma.
1242
787
  for (const k in mo) {
1243
788
  if (null == mo[k] && '___merge' !== k &&
1244
789
  '___optional' !== k && '___alias' !== k) {
@@ -1249,45 +794,22 @@ help isolate the syntax error.`,
1249
794
  const en = addsite(new NilVal_1.NilVal({ why: 'elided_value' }), r, ctx);
1250
795
  en.path = [...(r.k?.path ?? []), k];
1251
796
  mo[k] = en;
1252
- // An elided value under an OPTIONAL key stops being optional.
1253
- // Optionality is about a value that may be absent at
1254
- // GENERATE; it does not excuse a source that stops after the
1255
- // colon. Left optional, the refusal was dropped with the key
1256
- // and `a?:` generated `{}` -- a silent nothing, which is
1257
- // worse than either the old null or the error.
1258
797
  const oi = optionalKeys.indexOf(k);
1259
798
  if (-1 !== oi) {
1260
799
  optionalKeys.splice(oi, 1);
1261
800
  }
1262
801
  }
1263
802
  }
1264
- // ... and the OPTIONAL spelling, `a?:`, which does not leave a
1265
- // null behind to be found: its value never reaches the node at
1266
- // all, so the key is simply absent and the map generated without
1267
- // it. A key recorded as optional but missing from the node was
1268
- // written with nothing after its colon.
1269
803
  for (const k of optionalKeys) {
1270
804
  if (!(k in mo)) {
1271
805
  mo[k] = addsite(new NilVal_1.NilVal({ why: 'elided_value' }), r, ctx);
1272
806
  }
1273
807
  }
1274
- // An elided SPREAD (`x:$obj&:` with nothing after the colon)
1275
- // refuses the whole map, not a key (issue #48). A spread is not a
1276
- // child, so a refusal stored in its place has nothing to attach
1277
- // to: `x:&:` has no children for the spread to apply to, and the
1278
- // map would generate as `{}` with the mistake silently gone.
1279
- // Refusing the container is what makes it visible at all.
1280
808
  const sp = mo[type_1.SPREAD];
1281
809
  if (sp && sp.v.some((sv) => null == sv)) {
1282
810
  r.node = addsite(new NilVal_1.NilVal({ why: 'elided_value' }), r, ctx);
1283
811
  return undefined;
1284
812
  }
1285
- // A KEY REFUSAL (the pair rule records them: a declaration
1286
- // spelled with a colon, a key the bare-text rule refuses) becomes
1287
- // the refusal, in place of whatever followed the colon and sited
1288
- // at the KEY rather than at the map -- at the offending character
1289
- // of it, where there is one -- so the frame points at the
1290
- // spelling to change.
1291
813
  for (const { key, tkn, why, details } of (r.u.aontu_key_refusals ?? [])) {
1292
814
  const en = siteAt(addsite(new NilVal_1.NilVal({ why }), r, ctx), tokenSite(tkn));
1293
815
  if (null != details) {
@@ -1316,7 +838,6 @@ help isolate the syntax error.`,
1316
838
  if (mo.___merge) {
1317
839
  let mop = { ...mo };
1318
840
  delete mop.___merge;
1319
- // TODO: needs addpath?
1320
841
  let mopv = new MapVal_1.MapVal({ peg: mop });
1321
842
  mopv.optionalKeys = optionalKeys;
1322
843
  mopv.aliasKeys = aliasKeys;
@@ -1335,13 +856,9 @@ help isolate the syntax error.`,
1335
856
  });
1336
857
  jsonic.rule('list', (rs) => {
1337
858
  rs
1338
- // .open([{ s: [CJ, CL], p: 'pair', b: 2, g: 'spread' }])
1339
859
  .bc((r, ctx) => {
1340
860
  const optionalKeys = r.u.aontu_optional_keys ?? [];
1341
861
  let ao = r.node;
1342
- // An elided ELEMENT (`[,]`, `[1,,2]`) is refused for the same
1343
- // reason as an elided map value (issue #48). A trailing comma
1344
- // (`[1,]`) is not an elision and never reaches here.
1345
862
  for (let i = 0; i < ao.length; i++) {
1346
863
  if (null == ao[i]) {
1347
864
  // Pathed at the INDEX, for the same reason as the map case.
@@ -1359,36 +876,16 @@ help isolate the syntax error.`,
1359
876
  }
1360
877
  return undefined;
1361
878
  });
1362
- // .close([{ s: [CJ, CL], b: 2, g: 'spread,json,more' }])
1363
879
  return rs;
1364
880
  });
1365
- // TODO: copied from jsonic grammar
1366
- // jsonic should provide a way to export this
1367
881
  const pairkey = (r) => {
1368
882
  // Get key string value from first matching token of `Open` state.
1369
883
  const key_token = r.o0;
1370
884
  const key = ST === key_token.tin || TX === key_token.tin
1371
- ? key_token.val // Was text
885
+ ? key_token.val
1372
886
  : key_token.src; // Was number, use original text
1373
887
  r.u.key = key;
1374
888
  };
1375
- // A pair in LIST position writes its value at `node[key]` like any
1376
- // other pair, and the enclosing list's node is an ARRAY -- so a numeric
1377
- // key lands on an index and becomes an element, and may land on an
1378
- // index a real element already holds (`[5,0:1]`). Since the pair must
1379
- // contribute nothing (issue #40), the slot is photographed before the
1380
- // value is parsed and put back afterwards. Restoring beats deleting for
1381
- // exactly the overwrite case: deleting `[5,0:1]`'s index 0 would take
1382
- // the 5 with it, where restoring gives back the list the pair was
1383
- // never part of.
1384
- //
1385
- // `length` is saved too: writing past the end grows an array, and
1386
- // `[5,1?:9]` must be [5] again and not [5, <hole>].
1387
- // Typed as a string bag deliberately: the slot may be named by a
1388
- // non-numeric key (`[x:1]`), which the array type would refuse. Both
1389
- // helpers run only from the elem rule, whose node is the enclosing
1390
- // list, so neither guards against a non-array node — a guard there
1391
- // proved unreachable and dead code is worse than none.
1392
889
  const asSlots = (r) => r.node;
1393
890
  const snapshotPairSlot = (r, key) => {
1394
891
  const node = asSlots(r);
@@ -1448,40 +945,14 @@ help isolate the syntax error.`,
1448
945
  })
1449
946
  .bc((rule) => {
1450
947
  // TRAVERSE PARENTS TO GET PATH
1451
- // A DECLARATION IS A PAIR WHOSE KEY IS AN ALIAS NAME. The lexer
1452
- // claims `%name` whole and hands it over as a #VL token whose
1453
- // SOURCE is the name, so the key TEXT alone cannot be the test:
1454
- // a quoted `"%a": 1` is an ordinary key that merely starts with
1455
- // the sigil, and erasing that would be wrong. The token is what
1456
- // separates them.
1457
- //
1458
- // Recorded on the enclosing map, never on the value, and that is
1459
- // the point: a reference COPIES the value it resolves to, so a
1460
- // mark riding the value would erase the referring field too.
1461
- // Being a property of the map is also what carries it through a
1462
- // meet, the way optional keys are carried.
1463
948
  const ktkn = rule.o0;
1464
949
  const holder = rule.parent;
1465
950
  const kr = keyRefusalOf(ktkn, rule.o1);
1466
951
  if (null != kr) {
1467
- // A KEY REFUSAL (keyRefusalOf) is written where the map is
1468
- // built, in the value's place and sited at the key, so the
1469
- // frame points at the spelling to change. A declaration
1470
- // spelled with a colon is refused rather than read as the
1471
- // ordinary key `%foo` the text would otherwise become -- a
1472
- // document written for the old form would then generate a
1473
- // "%foo" field and every `%foo` use would resolve to nothing,
1474
- // and neither says why.
1475
952
  holder.u.aontu_key_refusals = (holder.u.aontu_key_refusals || []);
1476
953
  holder.u.aontu_key_refusals.push({ key: '' + ktkn.src, tkn: ktkn, ...kr });
1477
954
  }
1478
955
  else if (isAliasDecl(ktkn, rule.o1)) {
1479
- // Always recorded here; whether the map is ALLOWED to carry
1480
- // declarations is decided on the VALUE (MapVal.unify), not at
1481
- // the parse. The parse cannot see it: an INCLUDED file's
1482
- // declarations are at the root of their own text, and only
1483
- // once the loaded map is placed does it become apparent that
1484
- // root is not the document's.
1485
956
  holder.u.aontu_alias_keys = (holder.u.aontu_alias_keys || []);
1486
957
  holder.u.aontu_alias_keys.push('' + ktkn.src);
1487
958
  }
@@ -1493,11 +964,6 @@ help isolate the syntax error.`,
1493
964
  return undefined;
1494
965
  })
1495
966
  .close([
1496
- // A following `&:` starts a sibling spread pair in the current
1497
- // map: directly inside a braced map (pk<=0) at any depth, or in
1498
- // the implicit top-level map (dmap<=1). Inside an implicit
1499
- // colon-chain map (pk>0) it bubbles up instead (second alt), so
1500
- // `a:b:1 &:2` attaches the spread to a's map, not b's.
1501
967
  { s: [CJ, CL], c: (r) => r.lte('pk', 0) || r.lte('dmap', 1), r: 'pair', b: 2, g: 'spread,json,pair' },
1502
968
  { s: [CJ, CL], b: 2, g: 'spread,json,more' }
1503
969
  ]);
@@ -1532,17 +998,6 @@ help isolate the syntax error.`,
1532
998
  },
1533
999
  g: 'aontu-optional-elem'
1534
1000
  },
1535
- // A PLAIN pair in list position IS A SINGLE-KEY MAP ELEMENT:
1536
- // `[a:1, b:2]` is `[{a:1}, {b:2}]` (the rule @tabnas/jsonic
1537
- // spells as `list.pair`). This REVERSES issue #40's "a pair is
1538
- // not an element": that rule was chosen because jsonic wrote
1539
- // the pair at `node[key]` -- an array PROPERTY that never
1540
- // showed up for a text key and an INDEX for a numeric one --
1541
- // and inert beat that incoherence. But inert was itself a
1542
- // silent drop: `x: [a:1, b:2]` evaluated to `x: []`, the
1543
- // author's data gone at exit 0. The element is built in the
1544
- // bc below, where the value is already a Val; the snapshot
1545
- // still neutralises jsonic's raw slot write first.
1546
1001
  {
1547
1002
  s: [OPTKEY, CL], p: 'val',
1548
1003
  u: { spread: true, done: true, list: true, pair: true },
@@ -1553,36 +1008,7 @@ help isolate the syntax error.`,
1553
1008
  g: 'aontu-plain-pair-elem'
1554
1009
  }
1555
1010
  ])
1556
- // NOTE: manually adjust path - the twin of the `pair` rule's hook
1557
- // above, and for the same reason, one layer down.
1558
- //
1559
- // Every alt above contributes NO element: a `&:` spread is a
1560
- // constraint on the elements, and a `k:v` pair in list position is
1561
- // simply not one (the `aontu-plain-pair-elem` note above). The array
1562
- // slot they briefly occupy is already given back by
1563
- // restorePairSlot. The PATH index was not: @tabnas/path's
1564
- // `@elem-ao` increments `r.k.index` for every elem rule it sees, so
1565
- // each of these stole an index and every later element's path was
1566
- // one too high — `[&: integer, 10, 20, "bad"]` reported the bad
1567
- // value at `$.l.3` while `aontu get $.l.2` returned it, and on a
1568
- // one-element list the path pointed off the end. Generation was
1569
- // never wrong, which is why nothing caught it: the array is right
1570
- // and only the labels on it were shifted (BUGS.md 44).
1571
- //
1572
- // Rewinding here rather than in the plugin keeps the plugin's rule
1573
- // ("in an array, the path property is the element index") true —
1574
- // these alts are the aontu-specific exceptions to what counts as an
1575
- // element, so the correction belongs with the grammar that
1576
- // introduces them. The child is re-pathed because the plugin has
1577
- // already stamped it with the index being given back: a spread
1578
- // takes the `'&'` segment its map twin takes, and a pair takes its
1579
- // key, as a map entry would.
1580
1011
  .ao((r) => {
1581
- // A pair IS an element now, so it keeps the index @tabnas/path
1582
- // gave it, and its VALUE is pathed through both the index and
1583
- // the key (`[a: $.nope]` fails at $.l.0.a). Only the `&:`
1584
- // spread still contributes no element and gives its index back
1585
- // (BUGS.md 44).
1586
1012
  if (0 < r.d && r.u.spread && !r.u.pair) {
1587
1013
  r.k.index = r.k.index - 1;
1588
1014
  const seg = '&';
@@ -1590,11 +1016,6 @@ help isolate the syntax error.`,
1590
1016
  r.child.k.key = seg;
1591
1017
  }
1592
1018
  else if (0 < r.d && r.u.pair) {
1593
- // The element's index is the array length: everything before
1594
- // it is already pushed, and the pair's own map is pushed at
1595
- // close. `r.k.index` is not usable here -- the path plugin
1596
- // counts only the elements it pushes itself, and this one is
1597
- // aontu's.
1598
1019
  const seg = '' + r.u.key;
1599
1020
  r.child.k.path =
1600
1021
  [...r.k.path, '' + (r.node?.length ?? 0), seg];
@@ -1603,39 +1024,14 @@ help isolate the syntax error.`,
1603
1024
  })
1604
1025
  .bc((rule, ctx) => {
1605
1026
  // TRAVERSE PARENTS TO GET PATH
1606
- // Only the `&:` alternative is a SPREAD. All four alts above set
1607
- // `spread: true` -- it is what marks them as contributing no
1608
- // element -- so this guard needs the narrower test, and `pair`
1609
- // is what distinguishes a `k:v` in list position from a spread.
1610
- //
1611
- // Without it a pair BUILT the spread record, with `o` taken from
1612
- // its own key rather than '&': `[x:1, &:integer, "bad"]` left
1613
- // `{o:'x', v:[1, integer]}`, and ListVal's `'&' === spread.o`
1614
- // then discarded the real constraint -- so the element spread
1615
- // was silently dropped and the bad value generated (BUGS.md 46).
1616
- // A pair alone did it too: `[x:1, 10]` produced a spread record
1617
- // out of nothing.
1618
1027
  if (rule.u.spread && !rule.u.pair) {
1619
1028
  rule.node[type_1.SPREAD] =
1620
1029
  (rule.node[type_1.SPREAD] || { o: rule.o0.src, v: [] });
1621
1030
  rule.node[type_1.SPREAD].v.push(rule.child.node);
1622
1031
  }
1623
- // The slot is given back BEFORE the element is added: the
1624
- // restore undoes jsonic's raw write (a property for a text
1625
- // key, an INDEX for a numeric one -- restoring length is what
1626
- // keeps `[1:2]` from padding with a null), and the push then
1627
- // appends cleanly after it.
1628
1032
  restorePairSlot(rule);
1629
- // THE SINGLE-KEY MAP ELEMENT, for both pair spellings. The
1630
- // value is a Val already (`p: 'val'`), so the map is built
1631
- // exactly as the map rule builds one -- and an elided value
1632
- // (`[a:]`) is refused exactly as the map rule refuses one
1633
- // (issue #48): a key with nothing after the colon is a
1634
- // mistake, not an empty value.
1635
1033
  if (true === rule.u.pair) {
1636
1034
  const key = '' + rule.u.key;
1637
- // The key TOKEN: the optional spelling's sits on the elem rule
1638
- // before this one (`[x?: 1]` is two elem rules).
1639
1035
  const ktkn = true === rule.u.aontu_optional_elem ?
1640
1036
  rule.prev.o0 : rule.o0;
1641
1037
  let v = rule.child.node;
@@ -1663,9 +1059,6 @@ help isolate the syntax error.`,
1663
1059
  // "is this the top level" test reads the path, so an element
1664
1060
  // of a top-level list must not read as the root.
1665
1061
  mv.path = [...(rule.k?.path ?? []), '' + rule.node.length];
1666
- // `[a?: 1]` is `[{a?: 1}]`: the key is optional IN the
1667
- // element, so the two spellings stay one rule apart rather
1668
- // than two behaviours apart.
1669
1062
  if (true === rule.u.aontu_optional_elem) {
1670
1063
  mv.optionalKeys = [key];
1671
1064
  }
@@ -1683,43 +1076,10 @@ help isolate the syntax error.`,
1683
1076
  return rs;
1684
1077
  });
1685
1078
  };
1686
- // INCLUDE_KINDS IS THE RULE FOR WHAT AN INCLUDE MEANS (ADR-012,
1687
- // use-cases/BUGS.md §49). An extension is on this list or it is not
1688
- // read at all, and its entry says WHICH OF TWO THINGS the file is.
1689
- //
1690
- // `source` — Aontu, with everything the language has: types, defaults,
1691
- // references, constraints, its own includes. Two extensions, and they
1692
- // are the ones this project owns.
1693
- //
1694
- // `text` — the file's BYTES, as one string scalar. No parser is
1695
- // chosen, so there is nothing for two ports to disagree about and
1696
- // nothing in the file that can mean anything: `notes: @"notes.txt"`
1697
- // is a document loading prose into a string. `.txt` is the only
1698
- // extension here by default; `AontuOptions.textExt` (the CLI's
1699
- // `--text-ext`) adds others, because which name a project keeps its
1700
- // templates under is the project's business, not this table's.
1701
- //
1702
- // A FORMAT NAME — configuration DATA, parsed by that format's own
1703
- // parser into the JSON value it denotes, which then becomes Aontu
1704
- // values like any other data. Every one of these formats maps onto
1705
- // JSON, which is why one word covers them: a `.toml` file is a map of
1706
- // scalars, lists and maps, and so is the `.aon` file that unifies with
1707
- // it. What the format does NOT get is the language — a `&` in a YAML
1708
- // file is a YAML anchor, not a spread key, because the YAML parser
1709
- // reads it, not this one.
1710
- //
1711
- // The parsers are @tabnas's, one per format, and the Go port uses the
1712
- // same ones (ADR-001): the two implementations agree because they are
1713
- // running the same grammar, not because two hand-written readers were
1714
- // kept in step.
1715
- //
1716
- // This table and go/source.go's includeKinds are the same table.
1717
1079
  const INCLUDE_KINDS = {
1718
1080
  aon: 'source',
1719
1081
  aontu: 'source',
1720
1082
  json: 'json',
1721
- // JSON-LD is JSON: a `@context` is a key like any other here, and
1722
- // what it MEANS is the vocabulary's business, not the reader's.
1723
1083
  jsonld: 'json',
1724
1084
  jsonc: 'jsonc',
1725
1085
  json5: 'json5',
@@ -1731,25 +1091,11 @@ const INCLUDE_KINDS = {
1731
1091
  ini: 'ini',
1732
1092
  txt: 'text',
1733
1093
  };
1734
- // WHAT AN EXTENSION MEANS, for this parse. The table is the fixed
1735
- // part; `textExt` is the per-parse widening, and it wins over nothing
1736
- // -- a host cannot re-read `.toml` as text, because an extension the
1737
- // table already names has a meaning documents rely on. Undefined is
1738
- // the refusal, and it is the ONE place that decides it: the resolver's
1739
- // gate and the processor map both ask here, so a widening cannot reach
1740
- // one and not the other.
1741
1094
  function includeFormat(ext, textExt) {
1742
1095
  const known = INCLUDE_KINDS[ext];
1743
1096
  if (undefined !== known) {
1744
1097
  return known;
1745
1098
  }
1746
- // NOT EVEN AS TEXT. `.js` is the extension ADR-012 singles out
1747
- // because multisource's own default EXECUTES it, and an extension
1748
- // this project refuses on purpose stays refused however a flag is
1749
- // spelled -- reading it is harmless, but a widening that can reach
1750
- // the one name the rule names is a widening whose limit nobody can
1751
- // state. Go's includeFormat holds the same list, and the two CLIs
1752
- // are diffed on `--text-ext js` because they once disagreed here.
1753
1099
  if (REFUSED_EXT.has(ext)) {
1754
1100
  return undefined;
1755
1101
  }
@@ -1759,17 +1105,6 @@ function includeFormat(ext, textExt) {
1759
1105
  // default processor; `''` is the no-extension fallback, which names no
1760
1106
  // file type at all.
1761
1107
  const REFUSED_EXT = new Set(['js', '']);
1762
- // `.csv` IS DELIBERATELY ABSENT, and the reason is ADR-001 rather than
1763
- // taste. The two ports' CSV parsers disagree about what a CSV file IS:
1764
- // one answers header-keyed records with string fields, the other raw
1765
- // rows including the header, with numbers parsed. Admitting it would
1766
- // admit a divergence into the one thing this project refuses to have
1767
- // one in. Recorded in ADR-012 and pinned by file.tsv's load-ext-csv.
1768
- // The multisource kind of a path: the LAST segment's extension, without
1769
- // its dot, lowercased -- `''` for a name that has none. The rule is
1770
- // @tabnas/multisource's own extKind (and Go's filepath.Ext), copied
1771
- // rather than imported because it decides what a source IS: a dot in a
1772
- // parent folder (`/my.app/conf`) must not read as an extension.
1773
1108
  function extKindOf(full) {
1774
1109
  const seg = full.match(/[^\\/]*$/)[0];
1775
1110
  return (seg.match(/\.([^.]*)$/) || ['', ''])[1].toLowerCase();
@@ -1782,15 +1117,6 @@ function extensionMsg(path, ext) {
1782
1117
  const which = '' === ext ? 'no extension' : 'extension: .' + ext;
1783
1118
  return 'include not readable: ' + path + ' (' + which + ')';
1784
1119
  }
1785
- // THE RULE ALSO HOLDS FOR A RESOLVER THIS ENGINE DID NOT WRITE.
1786
- // gateExtension refuses an unlisted extension inside makeModelResolver,
1787
- // which is the default; a HOST may supply its own through
1788
- // `AontuOptions.resolver`, and that one has never heard of
1789
- // INCLUDE_KINDS. Without this the host's resolution would fall to
1790
- // multisource's own default for an unnamed kind, which hands the file
1791
- // back as TEXT — or, for `.js`, EXECUTES it. So the two roads end in
1792
- // one place: whatever chose the source, an extension off the list is
1793
- // refused with the same code and the same message.
1794
1120
  const refuseProcessor = (res) => {
1795
1121
  // `full` is the one part a host resolution may leave out -- it is the
1796
1122
  // path the resolver CHOSE, and a resolver that answers from something
@@ -1826,22 +1152,6 @@ const DATA_READERS = (() => {
1826
1152
  ini: viaPlugin(ini_1.Ini),
1827
1153
  };
1828
1154
  })();
1829
- /**
1830
- * A TOML document with its dates as the TEXT they were written as.
1831
- *
1832
- * TOML HAS DATES AND JSON DOES NOT, so the reader cannot hand one over
1833
- * as itself: it answers with a marker object carrying the kind and the
1834
- * source text. The value that reaches a document is that TEXT, which is
1835
- * what a JSON document carries for a date anyway — and it is what the
1836
- * Go port produces too, from a `*TomlTime` holding those same two
1837
- * fields (`dataToValDepth`, go/source.go). Without this the same file
1838
- * is a nested map in one port and a string in the other, which is the
1839
- * class of divergence ADR-012 exists to stop.
1840
- *
1841
- * The guard is exact — one key, `__toml__`, holding a `kind` and a
1842
- * `src` string — so a document whose own data happens to use the name
1843
- * passes through untouched.
1844
- */
1845
1155
  function tomlDates(node) {
1846
1156
  if (Array.isArray(node)) {
1847
1157
  return node.map(tomlDates);
@@ -1861,31 +1171,12 @@ function tomlDates(node) {
1861
1171
  }
1862
1172
  return out;
1863
1173
  }
1864
- /**
1865
- * Read one included file as DATA in the named format.
1866
- *
1867
- * The parser hands back the JSON value the file denotes — plain maps,
1868
- * lists and scalars — and rawToVal turns that into Vals. THE
1869
- * CONVERSION HAPPENS HERE, not at the top level, because an include is
1870
- * usually not at the top level: `a: @"conf.toml"` puts the value under
1871
- * a key, where a raw JavaScript object is something the tree cannot
1872
- * unify with (the crash that was BUGS §49b).
1873
- */
1874
1174
  const dataProcessor = (format) => (res) => {
1875
1175
  res.val = rawToVal(DATA_READERS[format](res.src, res.path));
1876
1176
  };
1877
- // TEXT IS NOT PARSED. The bytes multisource read are the value, so
1878
- // this is the one processor with no reader behind it -- which is why
1879
- // a `.txt` include cannot fail on content, only on being unreadable.
1880
1177
  const textProcessor = (res) => {
1881
1178
  res.val = new StringVal_1.StringVal({ peg: res.src });
1882
1179
  };
1883
- /**
1884
- * The multisource processor map, built FROM the include table so the
1885
- * two cannot drift: every extension the table names gets the reader
1886
- * the table names for it, and the two kinds that are not in the table
1887
- * refuse.
1888
- */
1889
1180
  function includeProcessors(textExt) {
1890
1181
  const map = {
1891
1182
  // multisource's fallback for an extension no entry names, so it is
@@ -1906,10 +1197,6 @@ function includeProcessors(textExt) {
1906
1197
  for (const kind of Object.keys(INCLUDE_KINDS)) {
1907
1198
  map[kind] = forKind(kind);
1908
1199
  }
1909
- // A WIDENING NEVER OVERWRITES. `js` and the empty fallback refuse
1910
- // above and stay refusing: `--text-ext js` would otherwise turn the
1911
- // one extension ADR-012 singles out into a readable one, by a flag
1912
- // whose whole promise is that it chooses no parser.
1913
1200
  for (const ext of textExt ?? []) {
1914
1201
  if (undefined === map[ext]) {
1915
1202
  map[ext] = textProcessor;
@@ -1917,17 +1204,8 @@ function includeProcessors(textExt) {
1917
1204
  }
1918
1205
  return map;
1919
1206
  }
1920
- // SECURITY: under the DEFAULT ('system') include capability this
1921
- // resolver reads any file the process can reach — @"path" follows
1922
- // relative paths (`@"../../etc/passwd.aon"`) and symlinks — so treat
1923
- // opening an untrusted source as reading your disk. It no longer RUNS
1924
- // one: @"pkg" could require() an arbitrary installed module until
1925
- // ADR-012, which refuses a `.js` entry point by the same rule that
1926
- // refuses `.txt`. The trust profile (G5, docs/trust.md) is the
1927
- // confinement surface: `trust.include` of
1928
- // 'none', `{ mem }` or `{ root }` restricts what `@"..."` may resolve,
1929
- // and a denied resolution is a deterministic parse-stage
1930
- // `include_denied` error.
1207
+ // What a resolved include may reach, and how it is confined:
1208
+ // docs/trust.md.
1931
1209
  function makeModelResolver(options) {
1932
1210
  const useRequire = options.require || require;
1933
1211
  const capability = options.trust?.include ?? 'system';
@@ -1935,22 +1213,9 @@ function makeModelResolver(options) {
1935
1213
  const rootDir = 'object' === typeof capability &&
1936
1214
  'string' === typeof capability.root
1937
1215
  ? (0, node_path_1.resolve)(capability.root) : undefined;
1938
- // Under the mem capability the CAPABILITY's file set is the whole
1939
- // world; otherwise the host-injected `options.resolver.mem` entries
1940
- // remain available under every capability but 'none' — they are
1941
- // host-provided, not document-requested, so confining them would
1942
- // confine the host against itself.
1943
- // A LANGUAGE-SUPPLIED MODEL DOES NOT RIDE THIS LEG (ADR-028). Every
1944
- // bundled schema is named under `aontu:` and answered by the scheme
1945
- // leg above, which returns before the memory resolver is built, so
1946
- // neither a host entry nor a capability's own file set can stand in
1947
- // front of one: `aontu:system` is the engine's, always. That is what
1948
- // the prefix buys, and it is why the bare-name leg that once let a
1949
- // caller shadow `std/system` is gone.
1950
1216
  let memResolver = (0, mem_1.makeMemResolver)(memCapability
1951
1217
  ? { ...capability.mem }
1952
1218
  : { ...(options.resolver?.mem || {}) });
1953
- // TODO: make this consistent with other resolvers
1954
1219
  let fileResolver = (0, file_1.makeFileResolver)((spec) => {
1955
1220
  return 'string' === typeof spec ? spec : spec?.peg;
1956
1221
  });
@@ -1958,23 +1223,6 @@ function makeModelResolver(options) {
1958
1223
  require: useRequire,
1959
1224
  ...(options.resolver?.pkg || {})
1960
1225
  });
1961
- // Confinement is realpath-then-prefix-check (docs/trust.md): the
1962
- // RESOLVED file's real path must sit below the root's real path, so a
1963
- // symlink inside the root pointing outside it is an escape, not a
1964
- // loophole. A path realpath cannot resolve falls back to the lexical
1965
- // form — the comparison is then against what the resolver actually
1966
- // read.
1967
- // Real fs, deliberately: `options.fs` is not a sandbox (it feeds
1968
- // parse text; the file leg reads through its own channel), so the
1969
- // containment check must see the same filesystem that leg read from.
1970
- // A path that does not (fully) exist cannot be realpath'd whole, and
1971
- // falling back to the LEXICAL form compares apples to oranges when
1972
- // the root itself sits behind a symlink -- on macOS a root under
1973
- // /var realpaths to /private/var, so a merely-missing file inside it
1974
- // reads as an escape. Realpath the deepest EXISTING ancestor and
1975
- // re-attach the rest, so both sides of the check are in real
1976
- // coordinates. (The MCP server's own confinement carries the twin of
1977
- // this rule; its CI failure is what found the shape.)
1978
1226
  const realpath = (p) => {
1979
1227
  try {
1980
1228
  return (0, node_fs_1.realpathSync)(p);
@@ -1992,12 +1240,6 @@ function makeModelResolver(options) {
1992
1240
  const fullReal = realpath(full);
1993
1241
  return fullReal !== rootReal && !fullReal.startsWith(rootReal + node_path_1.sep);
1994
1242
  };
1995
- // A denial THROWS with the code; Lang.parse converts it to the
1996
- // parse-stage `include_denied` nil (the same shape a syntax failure
1997
- // takes). Raising beats injecting a nil value: a bare-member include
1998
- // (`@"denied.aon"` at the top of a file) MERGES into the enclosing
1999
- // map, and a nil contributes no keys, so an injected denial would
2000
- // vanish and leave a plausible, silently-partial document.
2001
1243
  const deny = (path) => {
2002
1244
  // Only 'none' and 'root' can deny: the mem capability's misses are
2003
1245
  // not-found (its set is the whole world), so there is no third arm.
@@ -2006,12 +1248,6 @@ function makeModelResolver(options) {
2006
1248
  err.code = 'include_denied';
2007
1249
  throw err;
2008
1250
  };
2009
- // AN UNREADABLE EXTENSION THROWS, exactly as a denial does, and for
2010
- // the same reason: a bare-member include (`@"notes.txt"` at the top
2011
- // of a file) MERGES into the enclosing map, and a nil contributes no
2012
- // keys, so an injected refusal would vanish and leave a plausible,
2013
- // silently-partial document. Lang.parse turns the throw into the
2014
- // parse-stage `include_extension` nil.
2015
1251
  const refuseExtension = (path, full) => {
2016
1252
  const err = new Error(extensionMsg(path, extKindOf(full)));
2017
1253
  err.code = 'include_extension';
@@ -2023,12 +1259,12 @@ function makeModelResolver(options) {
2023
1259
  // set: a typo in an `aontu:` name must not go looking on disk.
2024
1260
  const modelNotFound = (path) => {
2025
1261
  const err = new Error('source not found: ' + path +
2026
- ' (the language-supplied models are ' + std_1.AONTU_MODELS.join(', ') + ')');
1262
+ ' (the language-supplied models are ' + aontumodel_1.AONTU_MODELS.join(', ') + ')');
2027
1263
  err.code = 'multisource_not_found';
2028
1264
  throw err;
2029
1265
  };
2030
- // The gate every leg that RESOLVES A NAME passes through. The std and
2031
- // module legs do not: both state `kind: 'aon'` because what they
1266
+ // The gate every leg that RESOLVES A NAME passes through. The aontu:
1267
+ // and module legs do not: both state `kind: 'aon'` because what they
2032
1268
  // serve is Aontu source by construction, not by its spelling.
2033
1269
  const gateExtension = (path, full) => {
2034
1270
  if (undefined === includeFormat(extKindOf(full), options.textExt)) {
@@ -2085,25 +1321,12 @@ function makeModelResolver(options) {
2085
1321
  if ('none' === capability) {
2086
1322
  deny(path);
2087
1323
  }
2088
- // THE LANGUAGE-SUPPLIED MODELS (docs/design/MODELS.0.md D1): an
2089
- // `aontu:` name resolves from the engine's own table and nowhere
2090
- // else -- the memory, module, file and package legs are never
2091
- // asked, so nothing on disk can shadow one and a typo is refused
2092
- // here, naming the set, rather than searched for. Available under
2093
- // every capability but `none`, checked just above. A path that is
2094
- // not a string (`a: @1`) is not a name at all: it falls through to
2095
- // the legs below and is not found there, as it always was.
2096
- //
2097
- // This is the ONLY leg that serves a bundled model (ADR-028). The
2098
- // vocabularies once had bare names (`std/system`) and a second leg
2099
- // below to match them; the prefix is now the whole spelling, so one
2100
- // leg answers for every language-supplied schema.
2101
- if ('string' === typeof path && path.startsWith(std_1.AONTU_SCHEME)) {
2102
- const model = std_1.STD_SOURCES[path];
1324
+ if ('string' === typeof path && path.startsWith(aontumodel_1.AONTU_SCHEME)) {
1325
+ const model = aontumodel_1.AONTU_SOURCES[path];
2103
1326
  if (null == model) {
2104
1327
  modelNotFound(path);
2105
1328
  }
2106
- record(ctx, path, 'std');
1329
+ record(ctx, path, 'aontu');
2107
1330
  return { found: true, path, full: path, kind: 'aon', src: model, search: [] };
2108
1331
  }
2109
1332
  let search = [];
@@ -2118,11 +1341,6 @@ function makeModelResolver(options) {
2118
1341
  record(ctx, res.full ?? path, 'mem');
2119
1342
  return res;
2120
1343
  }
2121
- // THE MODULE LEG (G6 phase 2, ts/src/mod.ts): memory -> MODULE ->
2122
- // filesystem -> package. Memory stays FIRST so a sandbox and the
2123
- // spec suite can stub a module path without touching disk; a path
2124
- // that is not module-shaped falls straight through, so no existing
2125
- // include can be routed somewhere new by this.
2126
1344
  const modref = memCapability ? undefined : (0, mod_1.parseModuleRef)(path);
2127
1345
  if (null != modref) {
2128
1346
  const msmeta = ctx?.meta?.multisource;
@@ -2200,53 +1418,17 @@ function makeModelResolver(options) {
2200
1418
  return res;
2201
1419
  };
2202
1420
  }
2203
- // THE SIGNATURE REGISTRY (docs/design/SIGNATURES.0.md). The call
2204
- // surface is DECLARED in test/spec/signature.tsv and parsed by the
2205
- // signature grammar (ts/src/sig.ts) from the build-time-inlined copy;
2206
- // the arity table and the positional set below are DERIVED from the
2207
- // parsed registry (funcSig, ts/src/sig.ts), so the declaration is the
2208
- // one source. go/func.go derives the same two tables from the same
2209
- // text.
2210
- // The functions whose comma-separated arguments are distinct POSITIONS
2211
- // rather than one argument list. See the func-paren handler above: this
2212
- // is the set whose comma group is expanded back into separate `peg`
2213
- // entries. Derived: two or more declared argument slots, excluding the
2214
- // residual producers (`constraint` results) -- the constraint atoms
2215
- // make the same expansion in their own constructor (`atomArgs`,
2216
- // ConstraintVal.ts, deliberately before the settled check), which is
2217
- // why they are not in this set; `must` is the load-bearing example.
2218
- // Arithmetic is here because `sub` is not commutative: `sub(a, b)`
2219
- // reaching the engine as one two-element list would lose which is
2220
- // which.
2221
1421
  const POSITIONAL_ARG_FUNCS = {};
2222
1422
  for (const name in sig_1.funcSig) {
2223
1423
  if (2 <= sig_1.funcSig[name].args.length && 'constraint' !== sig_1.funcSig[name].out) {
2224
1424
  POSITIONAL_ARG_FUNCS[name] = true;
2225
1425
  }
2226
1426
  }
2227
- // THE COMPONENT PRIMITIVES, listed by hand (the spike, see funcMap
2228
- // above and ts/src/val/CmpFuncVal.ts). They carry no signature
2229
- // declaration, so the derivation above cannot see them -- and
2230
- // `file("main.ts", [...])` without an entry arrives as ONE raw array
2231
- // term, which the call then reads as its spec. The leaves are here
2232
- // too, so that a written second argument is COUNTED and refused as
2233
- // the arity mistake it is rather than arriving as a one-element list
2234
- // that is merely the wrong shape.
2235
1427
  for (const name of Object.keys(CmpFuncVal_1.CMP_FUNCS)) {
2236
1428
  POSITIONAL_ARG_FUNCS[name] = true;
2237
1429
  }
2238
1430
  POSITIONAL_ARG_FUNCS['nom'] = true;
2239
1431
  POSITIONAL_ARG_FUNCS['translate'] = true;
2240
- // [min, max]; a max of -1 is unbounded. Every DECLARED name has an
2241
- // entry, and the arity is a property of the language rather than of
2242
- // either port -- go/func.go derives the same table. The spike's
2243
- // component primitives are the one exception: they carry no
2244
- // declaration, so they have no entry here and refuse a bad count in
2245
- // their own resolve (ts/src/val/CmpFuncVal.ts). A required slot
2246
- // counts toward the minimum; a rest slot makes the maximum unbounded
2247
- // and counts its group size (one, for a plain rest type) toward the
2248
- // minimum, which is what gives `match` its floor of three and `neq`
2249
- // its floor of one.
2250
1432
  function sigArity(sig) {
2251
1433
  let min = 0;
2252
1434
  let max = 0;
@@ -2270,14 +1452,6 @@ const funcArity = {};
2270
1452
  for (const name in sig_1.funcSig) {
2271
1453
  funcArity[name] = sigArity(sig_1.funcSig[name]);
2272
1454
  }
2273
- // writtenArgCount counts the arguments as the AUTHOR wrote them.
2274
- //
2275
- // It cannot simply be terms.length: a comma group reaches the func-paren
2276
- // handler as ONE term holding a raw array, so `upper("a","b")` and
2277
- // `upper(["a","b"])` both arrive as a single argument. They are still
2278
- // distinguishable, and that is what makes an arity check possible at
2279
- // all -- the comma group is a RAW array, while a written list literal
2280
- // has already been built into a ListVal by the list rule.
2281
1455
  function writtenArgCount(terms) {
2282
1456
  if (1 === terms.length) {
2283
1457
  // `terms[0]` is re-read rather than reusing a narrowed local:
@@ -2302,12 +1476,6 @@ function arityText(lo, hi) {
2302
1476
  if (0 === lo) {
2303
1477
  return 'no arguments or one';
2304
1478
  }
2305
- // The case range gave `upper` and `lower` a span rather than a
2306
- // pair, and a two-arm phrasing cannot say it: [1,3] read as "one
2307
- // argument or two", which is a wrong count rather than an
2308
- // imprecise one. Each arm here is a shape the table actually
2309
- // carries, and each is pinned by a row -- a phrasing for a count no
2310
- // entry has would be untested prose pretending to be tested.
2311
1479
  return 3 === hi ? 'one to three arguments' : 'one argument or two';
2312
1480
  }
2313
1481
  // The {0,0} arm returned with the container kinds and acyclic()
@@ -2320,17 +1488,6 @@ function arityText(lo, hi) {
2320
1488
  }
2321
1489
  return 'exactly one argument';
2322
1490
  }
2323
- // rawToVal converts a raw parse node (or raw elements inside one) into
2324
- // the matching Val. Used for implicit top-level lists, whose nodes skip
2325
- // the aontu val rule conversions (mirrors asVal in go/lang.go; like
2326
- // there, source text is unavailable, so an integral number is an
2327
- // integer).
2328
- // The targeted parse hint for CUE-trained authors and models: `>` and
2329
- // `<` are not Aontu operators (the op-chars reservation stands), and an
2330
- // agent that emits `number > 0` should be redirected to the bound
2331
- // atoms, not left with a bare "unexpected character". Appended to a
2332
- // parse error's message when the source carries an unquoted `<` or
2333
- // `>`; the Go twin is opCharHint in go/lang.go, byte-identical text.
2334
1491
  function opCharHint(src) {
2335
1492
  let q = '';
2336
1493
  for (let i = 0; i < src.length; i++) {
@@ -2358,12 +1515,6 @@ function rawToVal(n) {
2358
1515
  if (Array.isArray(n)) {
2359
1516
  return new ListVal_1.ListVal({ peg: n.map(rawToVal) });
2360
1517
  }
2361
- // THE SCALAR ARMS ARE WHERE A CONFIG FILE BECOMES VALUES. Every
2362
- // format on the include table is read by its own parser into plain
2363
- // JavaScript -- a string, a number, a map -- and this is the walk
2364
- // that turns that into Vals (dataProcessor, ADR-012). The two arms
2365
- // above are the other caller: a raw expression TERM, which the
2366
- // expression grammar hands over already built.
2367
1518
  if (null == n) {
2368
1519
  return new NullVal_1.NullVal({ peg: null });
2369
1520
  }
@@ -2372,24 +1523,12 @@ function rawToVal(n) {
2372
1523
  return new StringVal_1.StringVal({ peg: n });
2373
1524
  }
2374
1525
  if ('number' === t) {
2375
- // No source text here, so the "no '.'" condition is vacuous and the
2376
- // integral + int64-range conditions decide (same helper as the val
2377
- // rule, so the two paths cannot drift).
2378
1526
  return (0, numkind_1.isIntegerKind)(n) ?
2379
1527
  new IntegerVal_1.IntegerVal({ peg: n }) : new NumberVal_1.NumberVal({ peg: n });
2380
1528
  }
2381
1529
  if ('boolean' === t) {
2382
1530
  return new BooleanVal_1.BooleanVal({ peg: n });
2383
1531
  }
2384
- // AND EVERYTHING ELSE IS A MAP, with no arm after it because there is
2385
- // nothing after it. Every reader on the include table answers with
2386
- // the JSON kinds and no others -- probed, including the two that
2387
- // could plausibly escape them: a big integer comes back a `number`,
2388
- // and a TOML date is normalised to its text before it gets here. The
2389
- // one include that could hand over a function was `.js`, which
2390
- // ADR-012 refuses. `parse_unknown` lived here for that case and has
2391
- // no producer left in this port; the Go twin keeps its own, where the
2392
- // type switch really can be handed something unaccounted for.
2393
1532
  const peg = {};
2394
1533
  for (const k in n) {
2395
1534
  peg[k] = rawToVal(n[k]);
@@ -2398,7 +1537,6 @@ function rawToVal(n) {
2398
1537
  }
2399
1538
  class Lang {
2400
1539
  constructor(options) {
2401
- // const start = performance.now()
2402
1540
  this.opts = Object.assign((0, type_1.DEFAULT_OPTS)(), options);
2403
1541
  const modelResolver = makeModelResolver(this.opts);
2404
1542
  this.jsonic = jsonic_1.Jsonic.make();
@@ -2410,31 +1548,12 @@ class Lang {
2410
1548
  this.jsonic
2411
1549
  .use(asPlugin(multisource_1.MultiSource), {
2412
1550
  resolver: options?.resolver || modelResolver,
2413
- // `.aon` is the preferred Aontu source extension; `.aontu` also
2414
- // works. `.jsonic` is retired (no longer auto-resolved); the
2415
- // default `['jsonic','jsc','json','js']` is overridden here.
2416
- // (Upstream option name is the misspelled `implictExt`.)
2417
- //
2418
- // Only these two are SEARCHED for a bare `@"name"`; `.json` and
2419
- // `.jsonld` are read when NAMED, which is how a vendored
2420
- // vocabulary is always written.
2421
1551
  implictExt: ['aon', 'aontu'],
2422
- // ONE ENTRY PER EXTENSION THE TABLE NAMES, built from it (see
2423
- // includeProcessors) so the rule and its wiring cannot drift.
2424
- //
2425
- // The upstream defaults are REPLACED, not extended. Its `json`
2426
- // entry is what made that extension the one that crashed: it
2427
- // hands back a raw JS object where the aontu grammar produces
2428
- // Vals, and the tree then met a value it could not convert
2429
- // (BUGS §49b). Its `js` entry EXECUTES the file, which is not
2430
- // something an extension should be able to ask for. And its
2431
- // fallback hands any other file back as TEXT.
2432
1552
  processor: includeProcessors(this.opts.textExt)
2433
1553
  })
2434
1554
  .use(AontuJsonic);
2435
1555
  }
2436
1556
  parse(src, opts) {
2437
- // const start = performance.now()
2438
1557
  // JSONIC-UPDATE - check meta
2439
1558
  let jm = {
2440
1559
  fs: opts?.fs,
@@ -2457,7 +1576,6 @@ class Lang {
2457
1576
  if (opts && null != opts.log && Number.isInteger(opts.log)) {
2458
1577
  jm.log = opts.log;
2459
1578
  }
2460
- // jm.log = -1
2461
1579
  let val;
2462
1580
  try {
2463
1581
  val = this.jsonic(src, jm);
@@ -2472,14 +1590,6 @@ class Lang {
2472
1590
  catch (e) {
2473
1591
  if ('include_denied' === e?.code || 'include_extension' === e?.code ||
2474
1592
  'multisource_not_found' === e?.code || mod_1.MODULE_REFUSAL_CODES.has(e?.code)) {
2475
- // A denied include (G5), an include whose extension is not read
2476
- // as Aontu source (ADR-012, INCLUDE_KINDS), an `aontu:` name the
2477
- // engine does not serve (MODELS.0.md D1), and a module that is
2478
- // missing, fails its pin, or names a path that escapes its store
2479
- // (G6 phase 2) are refused the same way, for the same reason: the
2480
- // resolver THROWS so a bare-member include cannot vanish in the
2481
- // merge, and the code survives here as the parse-stage nil the
2482
- // registry pins (errcodes.tsv).
2483
1593
  val = new NilVal_1.NilVal({
2484
1594
  why: 'parse',
2485
1595
  err: new NilVal_1.NilVal({
@@ -2495,14 +1605,6 @@ class Lang {
2495
1605
  msg: e.message + opCharHint(src),
2496
1606
  err: e,
2497
1607
  });
2498
- // THE POSITION TRAVELS WITH IT. The parser knows exactly where
2499
- // it stopped -- it draws a caret there -- and the rendered
2500
- // message carried the only copy, so `vet --format json`
2501
- // reported row -1, col -1 for a document whose fault the human
2502
- // renderer located to the character. A machine-readable report
2503
- // that says "somewhere in this file" is the one a repair loop
2504
- // can do nothing with. Both numbers are already 1-based here,
2505
- // which is the base a site uses (go/lang.go does the same).
2506
1608
  if ('number' === typeof e.lineNumber) {
2507
1609
  syntax.site.row = e.lineNumber;
2508
1610
  }