aontu 0.61.0 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/README.md +4 -4
  2. package/dist/agentsmd.d.ts +1 -0
  3. package/dist/agentsmd.js +7 -28
  4. package/dist/agentsmd.js.map +1 -1
  5. package/dist/alias.js.map +1 -1
  6. package/dist/allow.d.ts +23 -0
  7. package/dist/allow.js +138 -0
  8. package/dist/allow.js.map +1 -0
  9. package/dist/aontu.d.ts +4 -2
  10. package/dist/aontu.js +4 -80
  11. package/dist/aontu.js.map +1 -1
  12. package/dist/aontumodel.d.ts +4 -0
  13. package/dist/aontumodel.js +33 -0
  14. package/dist/aontumodel.js.map +1 -0
  15. package/dist/cli.d.ts +10 -1
  16. package/dist/cli.js +877 -479
  17. package/dist/cli.js.map +1 -1
  18. package/dist/ctx.js +0 -48
  19. package/dist/ctx.js.map +1 -1
  20. package/dist/diff.js +0 -32
  21. package/dist/diff.js.map +1 -1
  22. package/dist/err.js +0 -40
  23. package/dist/err.js.map +1 -1
  24. package/dist/escape.js +0 -45
  25. package/dist/escape.js.map +1 -1
  26. package/dist/exactjson.d.ts +0 -35
  27. package/dist/exactjson.js +0 -131
  28. package/dist/exactjson.js.map +1 -1
  29. package/dist/format.js +55 -189
  30. package/dist/format.js.map +1 -1
  31. package/dist/grammar.d.ts +9 -0
  32. package/dist/grammar.js +54 -0
  33. package/dist/grammar.js.map +1 -0
  34. package/dist/graph.js +0 -26
  35. package/dist/graph.js.map +1 -1
  36. package/dist/hcanon.js +0 -82
  37. package/dist/hcanon.js.map +1 -1
  38. package/dist/helpdoc.d.ts +16 -0
  39. package/dist/helpdoc.js +59 -0
  40. package/dist/helpdoc.js.map +1 -0
  41. package/dist/hints.d.ts +0 -6
  42. package/dist/hints.js +59 -47
  43. package/dist/hints.js.map +1 -1
  44. package/dist/jsonschema.js +0 -114
  45. package/dist/jsonschema.js.map +1 -1
  46. package/dist/keyorder.d.ts +0 -7
  47. package/dist/keyorder.js +0 -41
  48. package/dist/keyorder.js.map +1 -1
  49. package/dist/lang.js +32 -877
  50. package/dist/lang.js.map +1 -1
  51. package/dist/lower.d.ts +3 -0
  52. package/dist/lower.js +14 -61
  53. package/dist/lower.js.map +1 -1
  54. package/dist/lsp-server.js +0 -16
  55. package/dist/lsp-server.js.map +1 -1
  56. package/dist/lsp.d.ts +1 -1
  57. package/dist/lsp.js +12 -159
  58. package/dist/lsp.js.map +1 -1
  59. package/dist/mcp-server.js +0 -26
  60. package/dist/mcp-server.js.map +1 -1
  61. package/dist/mcp.js +0 -113
  62. package/dist/mcp.js.map +1 -1
  63. package/dist/mod-tool.js +0 -130
  64. package/dist/mod-tool.js.map +1 -1
  65. package/dist/mod.js +0 -162
  66. package/dist/mod.js.map +1 -1
  67. package/dist/patch.js +0 -217
  68. package/dist/patch.js.map +1 -1
  69. package/dist/provenance.js +0 -140
  70. package/dist/provenance.js.map +1 -1
  71. package/dist/query.js +0 -75
  72. package/dist/query.js.map +1 -1
  73. package/dist/reach.js +0 -43
  74. package/dist/reach.js.map +1 -1
  75. package/dist/relation.d.ts +2 -0
  76. package/dist/relation.js +3 -58
  77. package/dist/relation.js.map +1 -1
  78. package/dist/render.js +33 -143
  79. package/dist/render.js.map +1 -1
  80. package/dist/report-sarif.d.ts +0 -11
  81. package/dist/report-sarif.js +0 -28
  82. package/dist/report-sarif.js.map +1 -1
  83. package/dist/sig.js +0 -35
  84. package/dist/sig.js.map +1 -1
  85. package/dist/sigdecl.js +1 -1
  86. package/dist/sigdecl.js.map +1 -1
  87. package/dist/siggate.js +0 -4
  88. package/dist/siggate.js.map +1 -1
  89. package/dist/site.js +3 -29
  90. package/dist/site.js.map +1 -1
  91. package/dist/subsume.d.ts +0 -10
  92. package/dist/subsume.js +0 -137
  93. package/dist/subsume.js.map +1 -1
  94. package/dist/template.d.ts +2 -1
  95. package/dist/template.js +58 -138
  96. package/dist/template.js.map +1 -1
  97. package/dist/trim.js +0 -41
  98. package/dist/trim.js.map +1 -1
  99. package/dist/tsconfig.tsbuildinfo +1 -1
  100. package/dist/type.js.map +1 -1
  101. package/dist/unify.js +12 -242
  102. package/dist/unify.js.map +1 -1
  103. package/dist/utility.js +0 -22
  104. package/dist/utility.js.map +1 -1
  105. package/dist/val/AbnfFuncVal.d.ts +18 -0
  106. package/dist/val/AbnfFuncVal.js +132 -0
  107. package/dist/val/AbnfFuncVal.js.map +1 -0
  108. package/dist/val/AbsentVal.d.ts +11 -0
  109. package/dist/val/AbsentVal.js +30 -0
  110. package/dist/val/AbsentVal.js.map +1 -0
  111. package/dist/val/AggFuncVal.d.ts +10 -1
  112. package/dist/val/AggFuncVal.js +104 -116
  113. package/dist/val/AggFuncVal.js.map +1 -1
  114. package/dist/val/ArithFuncVal.js +0 -12
  115. package/dist/val/ArithFuncVal.js.map +1 -1
  116. package/dist/val/BagVal.js +1 -78
  117. package/dist/val/BagVal.js.map +1 -1
  118. package/dist/val/BigDecimalVal.js +0 -16
  119. package/dist/val/BigDecimalVal.js.map +1 -1
  120. package/dist/val/BigIntegerVal.js +0 -16
  121. package/dist/val/BigIntegerVal.js.map +1 -1
  122. package/dist/val/CloseFuncVal.js +0 -9
  123. package/dist/val/CloseFuncVal.js.map +1 -1
  124. package/dist/val/CmpFuncVal.d.ts +20 -0
  125. package/dist/val/CmpFuncVal.js +188 -0
  126. package/dist/val/CmpFuncVal.js.map +1 -0
  127. package/dist/val/ConjunctVal.js +0 -29
  128. package/dist/val/ConjunctVal.js.map +1 -1
  129. package/dist/val/ConstraintVal.js +0 -500
  130. package/dist/val/ConstraintVal.js.map +1 -1
  131. package/dist/val/ContainerKindVal.js +0 -2
  132. package/dist/val/ContainerKindVal.js.map +1 -1
  133. package/dist/val/CopyFuncVal.js +0 -3
  134. package/dist/val/CopyFuncVal.js.map +1 -1
  135. package/dist/val/Decimal.js +0 -179
  136. package/dist/val/Decimal.js.map +1 -1
  137. package/dist/val/DeprecateFuncVal.js.map +1 -1
  138. package/dist/val/DisjunctVal.js +0 -152
  139. package/dist/val/DisjunctVal.js.map +1 -1
  140. package/dist/val/EachFuncVal.d.ts +1 -2
  141. package/dist/val/EachFuncVal.js +12 -29
  142. package/dist/val/EachFuncVal.js.map +1 -1
  143. package/dist/val/EmitFuncVal.d.ts +1 -1
  144. package/dist/val/EmitFuncVal.js +6 -119
  145. package/dist/val/EmitFuncVal.js.map +1 -1
  146. package/dist/val/ExpectVal.js +0 -62
  147. package/dist/val/ExpectVal.js.map +1 -1
  148. package/dist/val/FilterFuncVal.js +0 -25
  149. package/dist/val/FilterFuncVal.js.map +1 -1
  150. package/dist/val/FuncBaseVal.d.ts +1 -0
  151. package/dist/val/FuncBaseVal.js +7 -127
  152. package/dist/val/FuncBaseVal.js.map +1 -1
  153. package/dist/val/GraphAtomVal.js +0 -15
  154. package/dist/val/GraphAtomVal.js.map +1 -1
  155. package/dist/val/HideFuncVal.js +0 -13
  156. package/dist/val/HideFuncVal.js.map +1 -1
  157. package/dist/val/IntegerVal.js +0 -61
  158. package/dist/val/IntegerVal.js.map +1 -1
  159. package/dist/val/JunctionVal.js +0 -20
  160. package/dist/val/JunctionVal.js.map +1 -1
  161. package/dist/val/KeyFuncVal.js +0 -46
  162. package/dist/val/KeyFuncVal.js.map +1 -1
  163. package/dist/val/ListVal.js +0 -57
  164. package/dist/val/ListVal.js.map +1 -1
  165. package/dist/val/LowerFuncVal.js +11 -6
  166. package/dist/val/LowerFuncVal.js.map +1 -1
  167. package/dist/val/MapVal.js +0 -151
  168. package/dist/val/MapVal.js.map +1 -1
  169. package/dist/val/MatchFuncVal.js +0 -27
  170. package/dist/val/MatchFuncVal.js.map +1 -1
  171. package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
  172. package/dist/val/MaybeFuncVal.js +50 -0
  173. package/dist/val/MaybeFuncVal.js.map +1 -0
  174. package/dist/val/MoveFuncVal.js +0 -18
  175. package/dist/val/MoveFuncVal.js.map +1 -1
  176. package/dist/val/NilVal.js +2 -36
  177. package/dist/val/NilVal.js.map +1 -1
  178. package/dist/val/NomFuncVal.d.ts +12 -0
  179. package/dist/val/NomFuncVal.js +153 -0
  180. package/dist/val/NomFuncVal.js.map +1 -0
  181. package/dist/val/NumberVal.js +0 -15
  182. package/dist/val/NumberVal.js.map +1 -1
  183. package/dist/val/OpBaseVal.d.ts +1 -0
  184. package/dist/val/OpBaseVal.js +3 -15
  185. package/dist/val/OpBaseVal.js.map +1 -1
  186. package/dist/val/PackFuncVal.js +0 -34
  187. package/dist/val/PackFuncVal.js.map +1 -1
  188. package/dist/val/PathFuncVal.js +0 -6
  189. package/dist/val/PathFuncVal.js.map +1 -1
  190. package/dist/val/PathVal.js +0 -41
  191. package/dist/val/PathVal.js.map +1 -1
  192. package/dist/val/PlaceVal.js +0 -25
  193. package/dist/val/PlaceVal.js.map +1 -1
  194. package/dist/val/PlusOpVal.d.ts +1 -7
  195. package/dist/val/PlusOpVal.js +13 -74
  196. package/dist/val/PlusOpVal.js.map +1 -1
  197. package/dist/val/PrefFuncVal.js +0 -1
  198. package/dist/val/PrefFuncVal.js.map +1 -1
  199. package/dist/val/PrefVal.js +0 -167
  200. package/dist/val/PrefVal.js.map +1 -1
  201. package/dist/val/RecurseVal.js +0 -55
  202. package/dist/val/RecurseVal.js.map +1 -1
  203. package/dist/val/RefVal.js +0 -282
  204. package/dist/val/RefVal.js.map +1 -1
  205. package/dist/val/ReferFuncVal.js +0 -232
  206. package/dist/val/ReferFuncVal.js.map +1 -1
  207. package/dist/val/ScalarKindVal.js +0 -49
  208. package/dist/val/ScalarKindVal.js.map +1 -1
  209. package/dist/val/ScalarVal.js +0 -11
  210. package/dist/val/ScalarVal.js.map +1 -1
  211. package/dist/val/StrFuncVal.js +0 -18
  212. package/dist/val/StrFuncVal.js.map +1 -1
  213. package/dist/val/SuperFuncVal.js +0 -32
  214. package/dist/val/SuperFuncVal.js.map +1 -1
  215. package/dist/val/TopVal.js +0 -1
  216. package/dist/val/TopVal.js.map +1 -1
  217. package/dist/val/TranslateFuncVal.d.ts +12 -0
  218. package/dist/val/TranslateFuncVal.js +99 -0
  219. package/dist/val/TranslateFuncVal.js.map +1 -0
  220. package/dist/val/UpperFuncVal.js +11 -6
  221. package/dist/val/UpperFuncVal.js.map +1 -1
  222. package/dist/val/Val.d.ts +1 -0
  223. package/dist/val/Val.js +2 -133
  224. package/dist/val/Val.js.map +1 -1
  225. package/dist/val/VarVal.js +0 -12
  226. package/dist/val/VarVal.js.map +1 -1
  227. package/dist/val/arith.js +0 -37
  228. package/dist/val/arith.js.map +1 -1
  229. package/dist/val/caserange.d.ts +3 -0
  230. package/dist/val/caserange.js +49 -0
  231. package/dist/val/caserange.js.map +1 -0
  232. package/dist/val/members.js +0 -6
  233. package/dist/val/members.js.map +1 -1
  234. package/dist/val/numcmp.js +0 -11
  235. package/dist/val/numcmp.js.map +1 -1
  236. package/dist/val/numkind.js +0 -145
  237. package/dist/val/numkind.js.map +1 -1
  238. package/dist/val/valutil.js +0 -16
  239. package/dist/val/valutil.js.map +1 -1
  240. package/dist/vet.d.ts +12 -0
  241. package/dist/vet.js +159 -412
  242. package/dist/vet.js.map +1 -1
  243. package/dist/view.js +0 -414
  244. package/dist/view.js.map +1 -1
  245. package/dist/walk.js +0 -41
  246. package/dist/walk.js.map +1 -1
  247. package/grammar/aontu.abnf +9 -7
  248. package/grammar/aontu.gbnf +5 -5
  249. package/grammar/aontu.lark +5 -5
  250. package/grammar/aontu.tmLanguage.json +1 -1
  251. package/package.json +4 -2
  252. package/skill/SKILL.md +8 -0
  253. package/skill/init/check.sh +28 -0
  254. package/skill/init/data.aon +12 -0
  255. package/skill/init/model.aon +19 -0
  256. package/skill/tasks.md +151 -0
  257. package/src/agentsmd.ts +8 -32
  258. package/src/alias.ts +0 -39
  259. package/src/allow.ts +221 -0
  260. package/src/aontu.ts +10 -108
  261. package/src/aontumodel.ts +32 -0
  262. package/src/cli.ts +1009 -540
  263. package/src/ctx.ts +0 -103
  264. package/src/diff.ts +0 -40
  265. package/src/err.ts +0 -40
  266. package/src/escape.ts +0 -46
  267. package/src/exactjson.ts +0 -131
  268. package/src/format.ts +63 -234
  269. package/src/grammar.ts +72 -0
  270. package/src/graph.ts +0 -61
  271. package/src/hcanon.ts +0 -82
  272. package/src/helpdoc.ts +77 -0
  273. package/src/hints.ts +72 -49
  274. package/src/jsonschema.ts +0 -123
  275. package/src/keyorder.ts +0 -42
  276. package/src/lang.ts +39 -895
  277. package/src/lower.ts +15 -65
  278. package/src/lsp-server.ts +0 -16
  279. package/src/lsp.ts +12 -180
  280. package/src/mcp-server.ts +0 -31
  281. package/src/mcp.ts +0 -130
  282. package/src/mod-tool.ts +0 -158
  283. package/src/mod.ts +0 -178
  284. package/src/patch.ts +0 -232
  285. package/src/provenance.ts +0 -183
  286. package/src/query.ts +0 -84
  287. package/src/reach.ts +0 -53
  288. package/src/relation.ts +7 -71
  289. package/src/render.ts +33 -180
  290. package/src/report-sarif.ts +0 -48
  291. package/src/sig.ts +0 -35
  292. package/src/sigdecl.ts +1 -1
  293. package/src/siggate.ts +0 -30
  294. package/src/site.ts +3 -29
  295. package/src/subsume.ts +1 -161
  296. package/src/template.ts +69 -140
  297. package/src/trim.ts +0 -53
  298. package/src/type.ts +2 -45
  299. package/src/unify.ts +13 -251
  300. package/src/utility.ts +0 -31
  301. package/src/val/AbnfFuncVal.ts +181 -0
  302. package/src/val/AbsentVal.ts +54 -0
  303. package/src/val/AggFuncVal.ts +152 -188
  304. package/src/val/ArithFuncVal.ts +0 -20
  305. package/src/val/BagVal.ts +1 -78
  306. package/src/val/BigDecimalVal.ts +0 -16
  307. package/src/val/BigIntegerVal.ts +0 -16
  308. package/src/val/CloseFuncVal.ts +0 -9
  309. package/src/val/CmpFuncVal.ts +249 -0
  310. package/src/val/ConjunctVal.ts +0 -33
  311. package/src/val/ConstraintVal.ts +2 -537
  312. package/src/val/ContainerKindVal.ts +0 -18
  313. package/src/val/CopyFuncVal.ts +0 -5
  314. package/src/val/Decimal.ts +1 -185
  315. package/src/val/DeprecateFuncVal.ts +0 -10
  316. package/src/val/DisjunctVal.ts +0 -157
  317. package/src/val/EachFuncVal.ts +12 -53
  318. package/src/val/EmitFuncVal.ts +8 -208
  319. package/src/val/ExpectVal.ts +0 -62
  320. package/src/val/FilterFuncVal.ts +0 -55
  321. package/src/val/FuncBaseVal.ts +9 -130
  322. package/src/val/GraphAtomVal.ts +0 -42
  323. package/src/val/HideFuncVal.ts +0 -15
  324. package/src/val/IntegerVal.ts +0 -61
  325. package/src/val/JunctionVal.ts +0 -20
  326. package/src/val/KeyFuncVal.ts +0 -48
  327. package/src/val/ListVal.ts +0 -59
  328. package/src/val/LowerFuncVal.ts +12 -7
  329. package/src/val/MapVal.ts +0 -151
  330. package/src/val/MatchFuncVal.ts +0 -59
  331. package/src/val/MaybeFuncVal.ts +86 -0
  332. package/src/val/MoveFuncVal.ts +0 -20
  333. package/src/val/NilVal.ts +2 -36
  334. package/src/val/NomFuncVal.ts +200 -0
  335. package/src/val/NumberVal.ts +0 -16
  336. package/src/val/OpBaseVal.ts +4 -17
  337. package/src/val/PackFuncVal.ts +0 -63
  338. package/src/val/PathFuncVal.ts +0 -32
  339. package/src/val/PathVal.ts +0 -66
  340. package/src/val/PlaceVal.ts +0 -45
  341. package/src/val/PlusOpVal.ts +18 -75
  342. package/src/val/PrefFuncVal.ts +0 -1
  343. package/src/val/PrefVal.ts +0 -179
  344. package/src/val/RecurseVal.ts +0 -81
  345. package/src/val/RefVal.ts +1 -285
  346. package/src/val/ReferFuncVal.ts +0 -255
  347. package/src/val/ScalarKindVal.ts +0 -50
  348. package/src/val/ScalarVal.ts +0 -12
  349. package/src/val/StrFuncVal.ts +0 -44
  350. package/src/val/SuperFuncVal.ts +0 -42
  351. package/src/val/TopVal.ts +0 -1
  352. package/src/val/TranslateFuncVal.ts +132 -0
  353. package/src/val/UpperFuncVal.ts +12 -7
  354. package/src/val/Val.ts +3 -192
  355. package/src/val/VarVal.ts +0 -15
  356. package/src/val/arith.ts +0 -92
  357. package/src/val/caserange.ts +53 -0
  358. package/src/val/members.ts +0 -23
  359. package/src/val/numcmp.ts +1 -27
  360. package/src/val/numkind.ts +0 -149
  361. package/src/val/valutil.ts +0 -16
  362. package/src/vet.ts +209 -504
  363. package/src/view.ts +0 -507
  364. package/src/walk.ts +0 -41
  365. package/dist/std.d.ts +0 -3
  366. package/dist/std.js +0 -637
  367. package/dist/std.js.map +0 -1
  368. package/dist/val/FormFuncVal.js +0 -55
  369. package/dist/val/FormFuncVal.js.map +0 -1
  370. package/src/std.ts +0 -648
  371. package/src/val/FormFuncVal.ts +0 -119
package/dist/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,12 +51,16 @@ 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");
59
+ const CmpFuncVal_1 = require("./val/CmpFuncVal");
60
+ const MaybeFuncVal_1 = require("./val/MaybeFuncVal");
61
+ const NomFuncVal_1 = require("./val/NomFuncVal");
62
+ const TranslateFuncVal_1 = require("./val/TranslateFuncVal");
74
63
  const EachFuncVal_1 = require("./val/EachFuncVal");
75
- const FormFuncVal_1 = require("./val/FormFuncVal");
76
64
  const FilterFuncVal_1 = require("./val/FilterFuncVal");
77
65
  const MatchFuncVal_1 = require("./val/MatchFuncVal");
78
66
  const EmitFuncVal_1 = require("./val/EmitFuncVal");
@@ -89,32 +77,11 @@ const OpenFuncVal_1 = require("./val/OpenFuncVal");
89
77
  const SuperFuncVal_1 = require("./val/SuperFuncVal");
90
78
  const ConstraintVal_1 = require("./val/ConstraintVal");
91
79
  const asPlugin = (p) => p;
92
- // Build the Val for a matched `0d` literal (see the `0d` value matcher
93
- // below). Leaf by source: digits only is a biginteger, a `.` or an
94
- // exponent makes it a bigdecimal.
95
- //
96
- // A literal over the D6 exactness budget becomes a LOCATED ERROR here
97
- // and not a rounded or expanded value: `0d1e1000000000` has a one-digit
98
- // coefficient, so only the scale bound catches it, and it is caught at
99
- // parse -- before plain-form rendering would try to materialise a
100
- // gigabyte of zeros.
101
- // The source text of a negated exact literal. `-` is a prefix OPERATOR,
102
- // not part of the literal, so the text has to be rebuilt here to keep
103
- // `src` meaning "how this value is spelled" (see bigVal).
104
80
  function negsrc(src) {
105
- // src is never empty here: it is a BIG_LITERAL_RE match (at minimum
106
- // the two chars `0d`) or an already-negated spelling. Computed exact
107
- // values do carry src '', but they are built at unify time, long
108
- // after this parse-time opmap.
109
81
  return src.startsWith('-') ? src.slice(1) : '-' + src;
110
82
  }
111
83
  function bigVal(res) {
112
84
  const lit = (0, Decimal_1.readBigLiteral)(res);
113
- // `src` is the literal's own text, and it is not decoration: a path
114
- // segment is spelled text, so `$.a.0d1` must address the key `0d1` --
115
- // the same key `a:{0d1:7}` creates -- rather than the number 1. See
116
- // RefVal.append. Without it the segment was empty and the reference
117
- // silently resolved to its own container.
118
85
  const src = res[0];
119
86
  return 'biginteger' === lit.leaf ? new BigIntegerVal_1.BigIntegerVal({ peg: lit.int, src }) :
120
87
  'bigdecimal' === lit.leaf ? new BigDecimalVal_1.BigDecimalVal({ peg: lit.dec, src }) :
@@ -124,43 +91,11 @@ function bigVal(res) {
124
91
  const CC_0 = 48;
125
92
  const CC_d = 100;
126
93
  const CC_D = 68;
127
- // THE ALIAS SIGIL. `%` is part of an alias's name, so the name is one
128
- // lexeme wherever it appears and its meaning is decided by position:
129
- // a BINDING in key position (`%uint8 = …` declares), a USE in value
130
- // position (`listen: %uint8` refers). docs/design/ALIASES.0.md §4.
131
94
  const CC_PCT = 37;
132
95
  const ALIAS_RE = /^%[A-Za-z_][A-Za-z0-9_]*/;
133
- // THE DECLARATION OPERATOR. `%name = value` declares; the `=` is the
134
- // pair's separator, lexed as the colon token so the declaration then
135
- // parses as a pair whose key is the alias name (ALIASES.0.md X-1, as
136
- // settled 2026-09-05). `=` is syntax ONLY there: anywhere else it is
137
- // punctuation outside its syntax, and the bare-text scan below refuses
138
- // it (`foo = 1`, `a: x=y`).
139
96
  const CC_EQ = 61;
140
97
  const CC_SP = 32;
141
98
  const CC_TAB = 9;
142
- // THE BARE-TEXT RULE. A bare string holds letters, digits, `-` and `_`,
143
- // and nothing else. Every other punctuation character is either SYNTAX,
144
- // where the grammar gives it a meaning, or an ERROR where it does not
145
- // -- never silently part of a string. `x=y`, `6/2`, `50%` and `>10`
146
- // were all bare strings once, each a well-formed wrong document, and
147
- // each is refused now, naming the character (bare_punct).
148
- //
149
- // scanBareRun classifies each character of a run three ways, in this
150
- // order: TEXT continues the run; an ENDER stops it; anything else is
151
- // BAD. The ender set is the lexer's own -- space, line, fixed tokens,
152
- // comment starters -- read from the config its text matcher was built
153
- // from, so it cannot drift from the grammar. A bad run is still scanned
154
- // to its ender, so the refusal claims the whole spelling and the lexer
155
- // never reads the tail of it as syntax.
156
- //
157
- // `-` is text wherever the scan sees it. A run never STARTS on one:
158
- // `-` is the sign of a number and the negation prefix, a fixed token
159
- // the fixed matcher claims before either scanning stage can run, so
160
- // `a:-1` is the negation of 1 and `a:6-2` the string. The `+` of an
161
- // exponent (`1e+2`) is admitted only by the NUMBER stage's scan, the
162
- // one stage that can make a number of it. Mirrors scanBareRun in
163
- // go/lang.go, decision for decision.
164
99
  const CC_9 = 57;
165
100
  const CC_A = 65;
166
101
  const CC_Z = 90;
@@ -231,34 +166,10 @@ const NUMBER_RUN_RE = /^[-+]?(?:0(?:[xX][0-9a-fA-F_]+|[oO][0-7_]+|[bB][01_]+)|[0
231
166
  const NOT_A_NUMBER = { done: true, token: undefined };
232
167
  let AontuJsonic = function AontuLang(jsonic) {
233
168
  jsonic.use(asPlugin(path_1.Path));
234
- // Only # line comments are valid Aontu syntax (see
235
- // docs/reference-language.md; go/lang.go sets the same). Clear the
236
- // underlying jsonic comment markers entirely, then define # directly,
237
- // so the comment set is hash-only regardless of those defaults.
238
169
  let dotRef = (r, ctx, terms, prefix) => {
239
170
  terms = dropUnfilled(terms);
240
171
  if (0 === terms.length)
241
172
  return incompleteNil(r, ctx);
242
- // AN ALIAS IS NOT A PATH SEGMENT. `$.%foo` is refused: the alias
243
- // namespace and the path namespace are disjoint, and an alias is
244
- // reached by writing `%foo` and only that.
245
- //
246
- // The engine spells an alias reference AS a root reference to the
247
- // declaration -- which is what gives it order independence and a
248
- // cycle check shared with paths -- but that is an implementation of
249
- // the name, not a second way to write it. Left writable, the two
250
- // spellings would drift apart the moment aliases stop being
251
- // file-shaped, and `$.%b` inside an included file would reach the
252
- // INCLUDER's `%b` rather than its own, which is exactly the
253
- // cross-file capture the sigil exists to prevent.
254
- // `%foo` lexes to the reference itself, so in `$.%foo` it arrives
255
- // as a TERM rather than as a string segment -- both shapes are
256
- // checked, since a quoted `$."%foo"` would arrive as the string.
257
- // Terms here are always Vals -- dropUnfilled has removed the
258
- // nulls, and the dot rules never hand over a raw string -- so the
259
- // shapes are exactly three: a RefVal (peg is the segment array), a
260
- // StringVal (peg is the segment), and anything else (a numeric or
261
- // exact segment, which cannot be an alias name).
262
173
  for (const t of terms) {
263
174
  const segs = Array.isArray(t.peg) ? t.peg :
264
175
  ('string' === typeof t.peg ? [t.peg] : []);
@@ -279,48 +190,12 @@ let AontuJsonic = function AontuLang(jsonic) {
279
190
  },
280
191
  },
281
192
  });
282
- // Digit separators are legal only as a SINGLE separator BETWEEN
283
- // digits (the rule test/spec/engine-parity.tsv records as the engine's
284
- // adjudication; pinned by the sep-* rows in
285
- // test/spec/number-model.tsv). The engine's number matcher
286
- // enforces most of that already — `1_`, `_1`, `1_.5`, `1._5`, `1e_2`,
287
- // `1e2_` all fall through to text — but two gaps remain: a REPEATED
288
- // separator (`1__0` lexed as 10) and a separator at the edge of a
289
- // base-prefixed digit run (`0x_ff`, `0xff_` lexed as 255). Both
290
- // silently accept a typo as a different number, so aontu declines the
291
- // whole run instead and it lexes as text ("1__0"), exactly as `1_`
292
- // already does.
293
- //
294
- // `number.exclude` is tested against the matched number source and,
295
- // when it matches, makes the matcher decline the entire span. Kept in
296
- // lock-step with sepInvalid in go/lang.go, which is wired to the
297
- // equivalent `Number.Exclude` hook (and to the Check hook, which
298
- // constructs big base-prefixed tokens itself and so bypasses Exclude).
299
193
  jsonic.options({
300
194
  number: {
301
- // `__` repeated separator; `0x_`/`0o_`/`0b_` separator opening a
302
- // base-prefixed run; `_` closing any run. The prefix letter is
303
- // matched case-insensitively so the rule does not depend on which
304
- // prefix spellings the engine accepts.
305
195
  exclude: /__|^[-+]?0[xXoObB]_|_$/,
306
- // THE NUMBER STAGE OF THE BARE-TEXT RULE. The matcher runs before
307
- // the text matcher and reads a number up to the next ender -- and
308
- // `-` is an ender, being the negation prefix's fixed token, so it
309
- // would take the `2026` of `2026-09-05` and leave `-09-05` to the
310
- // grammar. The hook scans the whole run first and declines for
311
- // the matcher wherever the run is not its to lex: a run with a
312
- // bad character (the text stage refuses it), a run that is not a
313
- // number at all (`2026-09-05`, `6-2` are text). Twin of tsNumCheck
314
- // in go/lang.go.
315
196
  check: (lex) => {
316
197
  const pnt = lex.pnt;
317
198
  const src = lex.src;
318
- // The hook makes the matcher a candidate at every position, so
319
- // the common case -- a run no number can open -- declines for it
320
- // in one char read. A DIGIT opens a number here and nothing
321
- // else: the sign and the dot open the matcher's own grammar, but
322
- // they are fixed tokens (the prefix operators and member
323
- // access), claimed before this hook can run.
324
199
  const c = src.charCodeAt(pnt.sI);
325
200
  if (!(CC_0 <= c && c <= CC_9)) {
326
201
  return NOT_A_NUMBER;
@@ -333,67 +208,15 @@ let AontuJsonic = function AontuLang(jsonic) {
333
208
  },
334
209
  },
335
210
  });
336
- // D3 -- the `0d` literal, the only route to the exact leaves
337
- // (biginteger and bigdecimal). See BIG_LITERAL_RE for the grammar and
338
- // the leaf-by-source rule.
339
- //
340
- // The literal is claimed by the TEXT MATCHER'S CHECK HOOK (the sibling
341
- // of the `Number.Check` hook the Go port already uses for big
342
- // base-prefixed literals), not by a `value.def` entry, because a `0d`
343
- // run may contain a `.` and the two claim source differently:
344
- //
345
- // - A value def -- even a consuming one, matched against the full
346
- // forward source -- is applied INSIDE the text matcher, AFTER its
347
- // ender regexp has already carved the run at the `.`. The def
348
- // claims `0d1.5` whole, but the matcher then still emits the
349
- // ender's `.` as a fixed token, so `x:0d1.5` lexed as the
350
- // bigdecimal FOLLOWED BY a dangling member-access dot (a path
351
- // cycle). Verified, not theorised.
352
- // - The check hook runs BEFORE that ender regexp and returns the
353
- // token outright, so the run is claimed whole and nothing else is
354
- // emitted.
355
- //
356
- // A `match.value` matcher (which runs ahead of every other matcher)
357
- // also claims it correctly, but it is a candidate at EVERY lex
358
- // position and materializes the forward source there: ~8% on a
359
- // text-heavy document, for a syntax almost none of them use. The check
360
- // hook only runs where the text matcher already runs, and measures at
361
- // parity with not having it.
362
- //
363
- // The number matcher never sees these runs at all: it declines `0d…`
364
- // outright, since `d` is not an ender.
365
211
  jsonic.options({
366
212
  text: {
367
213
  check: (lex) => {
368
- // Guard first, on char codes: this hook runs at every text
369
- // position, and the common case (any run that cannot be a `0d`
370
- // literal or an alias) must cost two char reads and no
371
- // allocation.
372
214
  const pnt = lex.pnt;
373
215
  const src = lex.src;
374
- // AN ALIAS NAME IS CLAIMED WHOLE, for the same reason the `0d`
375
- // run below is: the text matcher's ender regexp would otherwise
376
- // carve `%uint8` at the `%` and emit the sigil as its own token,
377
- // leaving a bare `uint8` behind -- which is exactly the capture
378
- // the sigil exists to prevent. Claiming it here, before that
379
- // ender runs, keeps the name one lexeme.
380
- //
381
- // The token's SOURCE is the whole `%name`, which is what makes
382
- // the same lexeme work in both positions: jsonic keys a pair by
383
- // the token's source text (`0d1: 5` yields the key `0d1`), so a
384
- // declaration reads as the key `%uint8`, while a value position
385
- // calls the function below and gets the reference.
386
- // A `%` that opens no name (`%`, `%1`, `50%`) falls through to
387
- // the bare-text scan below, which refuses it.
388
216
  const ares = CC_PCT === src.charCodeAt(pnt.sI) ?
389
217
  ALIAS_RE.exec(lex.refwd()) : null;
390
218
  if (null != ares) {
391
219
  const asrc = ares[0];
392
- // A lone `=` after the name, across horizontal space only, is
393
- // the declaration operator. Decided HERE, where the name is
394
- // claimed, and only its position is kept: the very next text
395
- // position is that `=`, since nothing but space sits between,
396
- // so the mark cannot outlive its one use. `==` is not it.
397
220
  let j = pnt.sI + asrc.length;
398
221
  while (j < src.length &&
399
222
  (CC_SP === src.charCodeAt(j) || CC_TAB === src.charCodeAt(j))) {
@@ -402,24 +225,11 @@ let AontuJsonic = function AontuLang(jsonic) {
402
225
  if (CC_EQ === src.charCodeAt(j) && CC_EQ !== src.charCodeAt(j + 1)) {
403
226
  lex.aontu_eq_at = j;
404
227
  }
405
- const atkn = lex.token('#VL',
406
- // AN ALIAS REFERENCE IS A PATH REFERENCE. `%uint8` is
407
- // `$.%uint8`: root-absolute, one segment, spelled with the
408
- // sigil the declaration is spelled with. Everything the
409
- // design asks of it -- order independence, alias-of-alias,
410
- // redeclaration unifying, cycle refusal spanning both
411
- // namespaces -- is then the reference machinery already in
412
- // the language, not a second resolver beside it.
413
- (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);
414
229
  pnt.sI += asrc.length;
415
230
  pnt.cI += asrc.length;
416
231
  return { done: true, token: atkn };
417
232
  }
418
- // The `=` the alias arm above marked: the separator of a
419
- // declaration, as a colon token whose source is `=`. The pair rule
420
- // is then the pair rule, and the formatter writes the spelling it
421
- // read. Marked in `use` so the pair rule can tell it from a colon,
422
- // which no longer declares.
423
233
  if (CC_EQ === src.charCodeAt(pnt.sI) && lex.aontu_eq_at === pnt.sI) {
424
234
  delete lex.aontu_eq_at;
425
235
  const eqtkn = lex.token('#CL', undefined, '=', pnt, { aontu_eq: true });
@@ -430,18 +240,9 @@ let AontuJsonic = function AontuLang(jsonic) {
430
240
  if (CC_0 === src.charCodeAt(pnt.sI)) {
431
241
  const c1 = src.charCodeAt(pnt.sI + 1);
432
242
  if (CC_d === c1 || CC_D === c1) {
433
- // BIG_LITERAL_RE is `^`-anchored and read against the
434
- // forward source (memoized per position by refwd), which is
435
- // what lets it claim the `.` of `0d1.5`. A `0d` run it does
436
- // not match falls through to the bare-text scan below.
437
243
  const res = Decimal_1.BIG_LITERAL_RE.exec(lex.refwd());
438
244
  if (null != res) {
439
245
  const msrc = res[0];
440
- // The token value is a FUNCTION so Val construction
441
- // happens at parse time, where the rule and context needed
442
- // for the site exist (jsonic calls a #VL token's function
443
- // value with them). A `0d` literal never spans a line, so
444
- // only the source and column positions advance.
445
246
  const tkn = lex.token('#VL', (r, ctx) => addsite(bigVal(res), r, ctx), msrc, pnt);
446
247
  pnt.sI += msrc.length;
447
248
  pnt.cI += msrc.length;
@@ -449,21 +250,9 @@ let AontuJsonic = function AontuLang(jsonic) {
449
250
  }
450
251
  }
451
252
  }
452
- // THE BARE-TEXT RULE (scanBareRun). Last, so that a name, a
453
- // declaration operator and an exact literal are read before a
454
- // run is judged as text.
455
- // The run is never empty: every ender is a token an earlier
456
- // matcher claims, so the text stage only opens on a character
457
- // the scan classifies as text or as bad.
458
253
  const run = scanBareRun(lex.cfg, src, pnt.sI, false);
459
254
  const msrc = src.slice(pnt.sI, run.end);
460
255
  if (-1 !== run.bad) {
461
- // BAD: the run is refused whole, sited at the character (the
462
- // mark in `use` is what tokenSite reads). As a VALUE the
463
- // token's function builds the refusal at the parse, where the
464
- // rule carries the position. As a KEY the token is read for
465
- // its source alone, so the mark is what the pair and elem
466
- // rules read to write the refusal where the map is built.
467
256
  const ch = run.ch;
468
257
  const tkn = lex.token('#VL', (r, ctx) => {
469
258
  const nv = addsite(new NilVal_1.NilVal({ why: 'bare_punct' }), r, ctx);
@@ -474,11 +263,6 @@ let AontuJsonic = function AontuLang(jsonic) {
474
263
  pnt.cI += msrc.length;
475
264
  return { done: true, token: tkn };
476
265
  }
477
- // CLEAN, with a `-` past its start (`team-payments`,
478
- // `2026-09-05`): claimed here as one text token, because the
479
- // default matcher's ender set would carve the run at the `-`.
480
- // Any other clean run is the default matcher's, which also reads
481
- // the value keywords and the `_` hole.
482
266
  if (-1 !== msrc.indexOf('-')) {
483
267
  const tkn = lex.token('#TX', msrc, msrc, pnt);
484
268
  pnt.sI += msrc.length;
@@ -516,14 +300,6 @@ let AontuJsonic = function AontuLang(jsonic) {
516
300
  v.path = r.k ? [...r.k.path] : [];
517
301
  return v;
518
302
  };
519
- // THE KEY REFUSALS a pair may carry, decided from its key TOKEN --
520
- // never from the key text alone, since a quoted `"%a"` or `"x=y"` is
521
- // an ordinary key: a declaration spelled with a colon (alias_colon),
522
- // and a key the bare-text rule refuses (bare_punct). Undefined for an
523
- // ordinary key, and for a declaration (`%a = 1`), which is a binding
524
- // (isAliasDecl), not a refusal. Asked FIRST by the pair rule and by
525
- // the elem rule, before the declaration is, so a pair in list
526
- // position is held to the map's rules.
527
303
  const isAliasDecl = (ktkn, sep) => null != ktkn && VL === ktkn.tin && ALIAS_RE.test('' + ktkn.src) &&
528
304
  true === sep?.use?.aontu_eq;
529
305
  const keyRefusalOf = (ktkn, sep) => {
@@ -562,10 +338,6 @@ help isolate the syntax error.`,
562
338
  },
563
339
  value: {
564
340
  def: {
565
- // NOTE: specify with functions as jsonic/deep will
566
- // remove class prototype as options are assumed plain
567
- // (except for functions).
568
- // TODO: jsonic should be able to pass context into these
569
341
  'string': {
570
342
  val: (r, ctx) => addsite(new ScalarKindVal_1.ScalarKindVal({ peg: String }), r, ctx)
571
343
  },
@@ -581,8 +353,6 @@ help isolate the syntax error.`,
581
353
  'float': {
582
354
  val: (r, ctx) => addsite(new ScalarKindVal_1.ScalarKindVal({ peg: ScalarKindVal_1.Float }), r, ctx)
583
355
  },
584
- // The two exact leaves. Their keywords are the marker class
585
- // names lowercased, which is also how ScalarKindVal canons them.
586
356
  'biginteger': {
587
357
  val: (r, ctx) => addsite(new ScalarKindVal_1.ScalarKindVal({ peg: ScalarKindVal_1.BigInteger }), r, ctx)
588
358
  },
@@ -595,7 +365,6 @@ help isolate the syntax error.`,
595
365
  'nil': {
596
366
  val: (r, ctx) => addsite(new NilVal_1.NilVal({ why: 'literal_nil' }), r, ctx)
597
367
  },
598
- // TODO: FIX: need a TOP instance to hold path
599
368
  'top': { val: () => (0, top_1.top)() },
600
369
  // G8 phase 3: the placeholder. A BARE `_` is the hole; `"_"`
601
370
  // quoted, and any longer bare word containing it, stay text.
@@ -610,7 +379,6 @@ help isolate the syntax error.`,
610
379
  let pval = prev;
611
380
  let cval = curr;
612
381
  if (pval?.isVal && cval?.isVal) {
613
- // TODO: test multi element conjuncts work
614
382
  if (pval.isConjunct && cval.isConjunct) {
615
383
  pval.append(cval);
616
384
  return pval;
@@ -626,14 +394,6 @@ help isolate the syntax error.`,
626
394
  // Handle defered conjuncts, where MapVal does not yet
627
395
  // exist, by creating ConjunctVal later.
628
396
  else {
629
- // AN INCLUDE UNIFIES IN PLACE. multisource calls this hook at
630
- // the `@`'s own source position, so `prev` holds exactly the
631
- // pairs written BEFORE it. Folding the loaded map's keys in
632
- // here -- host-so-far first, arriving value second -- is what
633
- // inlining the loaded bytes at the `@` does, and mirrors
634
- // go/lang.go's Map.Merge, which multisource-go drives one key
635
- // at a time. A non-map load has no keys to fold and stays a
636
- // deferred conjunct arm.
637
397
  if (true === cval?.isMap) {
638
398
  const lm = cval;
639
399
  for (const k of Object.keys(lm.peg)) {
@@ -643,10 +403,6 @@ help isolate the syntax error.`,
643
403
  ? new ConjunctVal_1.ConjunctVal({ peg: [own, lm.peg[k]] })
644
404
  : lm.peg[k]);
645
405
  }
646
- // The loaded map's spread joins THIS map's spread list at
647
- // the `@`'s position: the parse pushes each `&:` onto the
648
- // node as it is read, so `prev[SPREAD].v` already holds the
649
- // spreads written before the `@` and nothing after it.
650
406
  if (null != lm.spread?.cj) {
651
407
  ;
652
408
  prev[type_1.SPREAD] =
@@ -680,20 +436,11 @@ help isolate the syntax error.`,
680
436
  move: MoveFuncVal_1.MoveFuncVal,
681
437
  path: PathFuncVal_1.PathFuncVal,
682
438
  pref: PrefFuncVal_1.PrefFuncVal,
683
- // First-class paths and the container kinds
684
- // (docs/design/PATHS.0.md). `path(p)` CAPTURES a path as a value;
685
- // `path()`, `map()` and `list()` are kinds -- the vacuous
686
- // constructor call admits its values and defaults to nothing,
687
- // where the container LITERALS `{}`/`[]` default to empty.
688
439
  map: ContainerKindVal_1.MapFuncVal,
689
440
  list: ContainerKindVal_1.ListFuncVal,
690
441
  close: CloseFuncVal_1.CloseFuncVal,
691
442
  open: OpenFuncVal_1.OpenFuncVal,
692
443
  super: SuperFuncVal_1.SuperFuncVal,
693
- // The constraint algebra's Band A atoms (G1 phase 1;
694
- // docs/reference-language.md, "The constraint algebra"): bounds
695
- // and exclusion enter through the function registry — the
696
- // established extension point — with zero grammar change.
697
444
  min: ConstraintVal_1.MinConstraintVal,
698
445
  max: ConstraintVal_1.MaxConstraintVal,
699
446
  above: ConstraintVal_1.AboveConstraintVal,
@@ -702,25 +449,15 @@ help isolate the syntax error.`,
702
449
  // G1 phase 2: pattern membership, over the portable subset both
703
450
  // host regex engines agree on (nonPortableRe in ConstraintVal.ts).
704
451
  re: ConstraintVal_1.ReConstraintVal,
705
- // G1 phase 3: the sizing atoms. Both are properties of a CONTAINER
706
- // (or, for length, of a string) rather than comparisons against a
707
- // value, which is why `unique` is the one built-in taking no
708
- // argument at all.
709
452
  length: ConstraintVal_1.LengthConstraintVal,
710
453
  unique: ConstraintVal_1.UniqueConstraintVal,
711
- // G1 phase 5: Band B. `must` is the one atom the algebra does not
712
- // reason about -- it is checked against the finished value and
713
- // reported with the author's own message, never simplified and
714
- // never consulted for emptiness or subsumption.
715
454
  must: ConstraintVal_1.MustConstraintVal,
455
+ abnf: AbnfFuncVal_1.AbnfFuncVal,
456
+ parse: AbnfFuncVal_1.ParseFuncVal,
716
457
  // G3 phase 4: the deprecation mark. Unification-transparent; the
717
458
  // record rides the result (Val.deprecation) and canon renders the
718
459
  // call back (canonRiders).
719
460
  deprecate: DeprecateFuncVal_1.DeprecateFuncVal,
720
- // G4 phase 2: the checked, typed, LINK-shaped reference. A
721
- // constraint on a string field: the string must be a TREE ADDRESS
722
- // (`$.a.b` or `.b`), the address must resolve, and the optional
723
- // argument flows INTO the target. The field keeps the string.
724
461
  refer: ReferFuncVal_1.ReferFuncVal,
725
462
  rel: ReferFuncVal_1.RelFuncVal,
726
463
  // RELATIONS P2 (docs/design/RELATIONS.0.md §3.3): the graph
@@ -728,78 +465,32 @@ help isolate the syntax error.`,
728
465
  // govern. Lattice-inert; the verdict lands at generation.
729
466
  acyclic: GraphAtomVal_1.AcyclicFuncVal,
730
467
  inverse: GraphAtomVal_1.InverseFuncVal,
731
- // G8 phase 1: the generation combinators. `pack` makes one keyed
732
- // child per child of its data, `each` one list element; both clone
733
- // their template per destination exactly as a spread does, and both
734
- // wait for the model to settle before they fire (the staging rule,
735
- // G8 phase 0).
736
468
  pack: PackFuncVal_1.PackFuncVal,
737
469
  each: EachFuncVal_1.EachFuncVal,
738
- // RENDER P6: the order-preserving map. `form` makes one list
739
- // element per child of its data, being the template with `_`
740
- // bound to the source child -- a construction, where `each` is a
741
- // bound (G9 §4). It exists because `pick(pack(...))` re-sorts to
742
- // code-point order, and a struct's fields or a file's imports
743
- // are the model's order or they are wrong.
744
- form: FormFuncVal_1.FormFuncVal,
745
- // G8 phase 2: selection. `filter` keeps the children of a bag that
746
- // unify with a condition; `match` picks the first arm whose
747
- // pattern the scrutinee unifies with. Both select by
748
- // UNIFIABILITY, tried in trial mode, so neither adds a predicate
749
- // language to the one the lattice already is.
750
470
  filter: FilterFuncVal_1.FilterFuncVal,
751
471
  match: MatchFuncVal_1.MatchFuncVal,
752
- // The arithmetic family (the review's finding I). Maths beyond `+`
753
- // arrives as FUNCTIONS — `-` `*` `/` `%` stay reserved — and the
754
- // family is numeric where the operator is polymorphic, which is
755
- // what makes `add` more than a second spelling of `+`: it refuses
756
- // the string concatenation that silently answers `"500m" + "500m"`.
757
- // Every rule they obey is in ts/src/val/arith.ts.
758
472
  add: ArithFuncVal_1.AddFuncVal,
759
473
  sub: ArithFuncVal_1.SubFuncVal,
760
474
  mul: ArithFuncVal_1.MulFuncVal,
761
475
  div: ArithFuncVal_1.DivFuncVal,
762
476
  mod: ArithFuncVal_1.ModFuncVal,
763
477
  rem: ArithFuncVal_1.RemFuncVal,
764
- // Aggregation over a finite, settled bag (the review's finding I).
765
- // `least` and `greatest` rather than min and max, which are already
766
- // the atoms for a lower and an upper BOUND -- an aggregate over a
767
- // set and a bound on a value must not share a spelling.
768
478
  sum: AggFuncVal_1.SumFuncVal,
769
479
  least: AggFuncVal_1.LeastFuncVal,
770
480
  greatest: AggFuncVal_1.GreatestFuncVal,
771
- // Projection, which is what lets the aggregates reach a bag of
772
- // RECORDS: `sum(pick($.lines, amountCents))`. Not a clever `each`
773
- // template -- `each` MEETS each child, and a meet cannot select.
481
+ maybe: MaybeFuncVal_1.MaybeFuncVal,
774
482
  pick: AggFuncVal_1.PickFuncVal,
775
- // G9 phase 2: the fold to a STRING. `sum` folds with `add`; this
776
- // folds with `+`, so it inherits the one number-to-text rule and
777
- // the language does not grow a second. It is the primitive that
778
- // turns a bag of computed lines into a file.
483
+ sort: AggFuncVal_1.SortFuncVal,
779
484
  join: AggFuncVal_1.JoinFuncVal,
780
- // G9 phase 6: apply-templates. One flat list of pieces from a
781
- // selection and a RULE TABLE -- for each node, the first template
782
- // whose `match` it unifies with, its `body` instantiated at that
783
- // node. The dispatch is the engine's because a body referenced by
784
- // path resolves its references at the definition site, and the
785
- // relative resolution that does exist is a dot count that does not
786
- // survive a second dispatch (docs/design/EMIT.0.md).
787
485
  emit: EmitFuncVal_1.EmitFuncVal,
788
- // G9 phase 6: the string builtins the rule layer needs. `esc`
789
- // makes a value safe inside a literal and `usc` reads it back;
790
- // `rep` and `split` derive names from model data. All four are
791
- // ordinary string functions -- they know nothing about generation,
792
- // which is why they can land before the renderer does.
793
486
  esc: StrFuncVal_1.EscFuncVal,
794
487
  usc: StrFuncVal_1.UscFuncVal,
795
488
  rep: StrFuncVal_1.RepFuncVal,
796
489
  split: StrFuncVal_1.SplitFuncVal,
490
+ ...CmpFuncVal_1.CMP_FUNCS,
491
+ nom: NomFuncVal_1.NomFuncVal,
492
+ translate: TranslateFuncVal_1.TranslateFuncVal,
797
493
  };
798
- // A dangling operator (`a:1|`, `a:$`, `a:*` at end of input) leaves
799
- // null/undefined unfilled terms. Junction ops drop them (so `a:1&`
800
- // and `a:1|` are just 1); ops missing a required operand become an
801
- // incomplete_expression nil, surfaced by generate() as a "Cannot
802
- // resolve value" error (the Go port mirrors this in lang.go).
803
494
  const dropUnfilled = (terms) => terms.filter((t) => null != t);
804
495
  const incompleteNil = (r, ctx) => addsite(new NilVal_1.NilVal({ why: 'incomplete_expression' }), r, ctx);
805
496
  // Build a call from a NAME and the argument terms as the author
@@ -807,27 +498,10 @@ help isolate the syntax error.`,
807
498
  // raw-value conversion, stated once.
808
499
  const buildCall = (r, ctx, fname, argterms) => {
809
500
  const funcval = funcMap[fname];
810
- // Arity is known for every built-in, so a surplus or missing
811
- // argument is a mistake in the SOURCE, refused here where the
812
- // author can see it (issue #51). It was previously left to each
813
- // function to notice or not: the two ports disagreed on `upper()`
814
- // and on `close()`, and `min(1,2)` noticed nothing at all -- it
815
- // built a constraint that merely refused to generate later, with a
816
- // message about the map rather than about the call.
817
- //
818
- // Counted BEFORE the rawToVal pass below, which is what makes the
819
- // count possible: a comma group arrives as a RAW array and a
820
- // written list literal as a ListVal, and rawToVal turns the first
821
- // into the second.
822
501
  const arity = funcArity[fname];
823
502
  if (null != arity) {
824
503
  const got = writtenArgCount(argterms);
825
504
  if (got < arity[0] || (-1 !== arity[1] && got > arity[1])) {
826
- // details is assigned AFTER construction: the NilVal
827
- // constructor does not read it from its spec (only NilVal.make
828
- // does), so passing it in the spec left the hint's
829
- // {func}/{want}/{got} placeholders un-injected and printed
830
- // literally.
831
505
  const nil = new NilVal_1.NilVal({ why: 'func_arity' });
832
506
  nil.details = {
833
507
  func: fname,
@@ -837,22 +511,6 @@ help isolate the syntax error.`,
837
511
  return addsite(nil, r, ctx);
838
512
  }
839
513
  }
840
- // rawToVal EVERY argument. A degenerate expression can hand this
841
- // handler raw parse values rather than Vals -- `pref(1-3)` arrives
842
- // as the plain numbers 1 and -3 -- and a func's peg is unified
843
- // element by element, so a raw one reached `arg.unify(...)` and
844
- // threw. The unifier's catch-all turned that into an `internal`
845
- // verdict: a crash reported as a unification result (issue #49).
846
- // The Go port has always converted here (asVal in evaluate).
847
- // A comma group is ONE raw-array term (see writtenArgCount).
848
- // For a function whose arguments are distinct POSITIONS —
849
- // deprecate's value and record, pack's and each's data and template
850
- // — the group is expanded back into them here, while a written list
851
- // literal, already a ListVal, stays one argument. The constraint
852
- // atoms make the same move in their own constructor (atomArgs,
853
- // ConstraintVal.ts), which is why they are not in this set:
854
- // `neq(1,2)` is one argument LIST, not two positions, and expanding
855
- // it here would take the list away from the code that reads it.
856
514
  let terms = argterms;
857
515
  if (true === POSITIONAL_ARG_FUNCS[fname] && 1 === terms.length &&
858
516
  Array.isArray(terms[0])) {
@@ -875,24 +533,6 @@ help isolate the syntax error.`,
875
533
  'star-prefix': (r, ctx, _op, terms) => {
876
534
  if (null == terms[0])
877
535
  return incompleteNil(r, ctx);
878
- // A PREFERENCE MARKS A VALUE, AND A BARE KEY IS NOT ONE.
879
- // `*a: 1` has no braces, so the prefix took the whole IMPLICIT
880
- // map as its operand and the document silently became
881
- // `*{"a":1}` -- `*a: 1, b: 2` became a one-element LIST, losing
882
- // `b` outright. Neither is anything the author wrote.
883
- //
884
- // The accident is confined to the first position of the implicit
885
- // top-level map, which is the only place no brace has yet
886
- // committed the rule to a map: `{*a: 1}` and `a: 1, *b: 2` are
887
- // ALREADY parse errors. This makes the third spelling agree with
888
- // them rather than inventing a meaning for it.
889
- //
890
- // A BRACED operand is untouched, and that is the whole of the
891
- // distinction: `*{x:1}` and `*[1]` are the real spelling, they
892
- // are what `*{x:1} | *{y:2}` needs, and the shared spec pins them
893
- // (11 rows). The open token's own source text is what separates
894
- // the two -- `{` or `[` for a braced bag, the first key or
895
- // element for an implicit one.
896
536
  const bag = terms[0];
897
537
  if ((bag.isMap && '{' !== bag.site.src) ||
898
538
  (bag.isList && '[' !== bag.site.src)) {
@@ -916,7 +556,6 @@ help isolate the syntax error.`,
916
556
  terms[0].peg.some((seg) => 'string' === typeof seg && ALIAS_RE.test(seg))) {
917
557
  return addsite(new NilVal_1.NilVal({ why: 'alias_in_path' }), r, ctx);
918
558
  }
919
- // $.a.b absolute path
920
559
  if (terms[0] instanceof RefVal_1.RefVal) {
921
560
  terms[0].absolute = true;
922
561
  return terms[0];
@@ -932,10 +571,6 @@ help isolate the syntax error.`,
932
571
  let val = terms[0];
933
572
  if (null == val)
934
573
  return incompleteNil(r, ctx);
935
- // The exact leaves negate exactly and never change kind. R2/D5
936
- // holds here too: bigint has a single zero, and Decimal's
937
- // normalising constructor sends every zero to the same form, so
938
- // `-0d0` is `0d0` and `-0d0.0` is `0d0.0`.
939
574
  if (val instanceof BigIntegerVal_1.BigIntegerVal) {
940
575
  return addsite(new BigIntegerVal_1.BigIntegerVal({ peg: -val.peg, src: negsrc(val.src) }), r, ctx);
941
576
  }
@@ -947,18 +582,10 @@ help isolate the syntax error.`,
947
582
  if (!(val instanceof IntegerVal_1.IntegerVal) && !(val instanceof NumberVal_1.NumberVal)) {
948
583
  return addsite(new NilVal_1.NilVal({ why: 'negative' }), r, ctx);
949
584
  }
950
- // Build a fresh Val rather than mutating in place: the expr plugin
951
- // can evaluate the same node twice (e.g. inside `*-1` or a
952
- // disjunct member), and an in-place `peg = -peg` applied twice
953
- // silently un-negates the number.
954
585
  let peg = -1 * val.peg;
955
586
  // Normalize -0 to 0 (keeps the AST and canon free of negative zero).
956
587
  if (0 === peg)
957
588
  peg = 0;
958
- // Negation never narrows the kind: a number stays a number. An
959
- // integer stays an integer unless the negation leaves the int64
960
- // range (only -(-2^63), which no literal can express), in which
961
- // case it widens to a number rather than failing.
962
589
  const out = val instanceof IntegerVal_1.IntegerVal && (0, numkind_1.isIntegerKind)(peg)
963
590
  ? new IntegerVal_1.IntegerVal({ peg })
964
591
  : new NumberVal_1.NumberVal({ peg });
@@ -990,7 +617,6 @@ help isolate the syntax error.`,
990
617
  jsonic
991
618
  .use(asPlugin(expr_1.Expr), {
992
619
  op: {
993
- // disjunct < conjunct: c & b | a -> (c & b) | a
994
620
  'conjunct': {
995
621
  infix: true, src: '&', left: 16_000_000, right: 17_000_000
996
622
  },
@@ -1003,16 +629,6 @@ help isolate the syntax error.`,
1003
629
  left: 20_000_000,
1004
630
  right: 21_000_000,
1005
631
  },
1006
- // Re-base the unary prefixes for the same reason. Every aontu
1007
- // operator sits far above the @tabnas/expr defaults, so the
1008
- // default prefix binding power of 4_000_000 left unary `-`/`+`
1009
- // LOOSER than every infix operator: `-1 & integer` parsed as
1010
- // `-(1 & integer)`, and negative-prefix (below) then rejected
1011
- // the composite operand as a `negative` error nil (likewise
1012
- // `-2+3`, `-1|2`). Unary minus must bind tighter than `+`, `&`
1013
- // and `|` — but still looser than `.` (dot-infix left is
1014
- // 25_000_000), so `-0xFF.5` stays `-(0xFF.5)` and `$`.
1015
- // Kept in lock-step with the op table in go/lang.go.
1016
632
  'negative': {
1017
633
  src: '-',
1018
634
  prefix: true,
@@ -1061,15 +677,11 @@ help isolate the syntax error.`,
1061
677
  remainder: null,
1062
678
  },
1063
679
  evaluate: (r, ctx, op, terms) => {
1064
- // // console.log('EVAL-START', r.u)
1065
680
  if ('func-paren' === op.name
1066
- // && !r.parent.prev?.u?.paren_preval
1067
681
  && !r.u?.paren_preval) {
1068
- // terms = [new StringVal({ peg: '' }), ...terms]
1069
682
  terms = ['', ...terms];
1070
683
  }
1071
684
  let val = opmap[op.name](r, ctx, op, terms);
1072
- // // console.log('EVAL', terms, '->', val)
1073
685
  return val;
1074
686
  }
1075
687
  });
@@ -1083,16 +695,6 @@ help isolate the syntax error.`,
1083
695
  const OPTKEY = [TX, ST, NR];
1084
696
  jsonic.rule('expr', (rs) => {
1085
697
  rs.close([
1086
- // A `&` followed by `:` after an expression value belongs to the
1087
- // enclosing map as a spread, not to the expression as a conjunct
1088
- // — backtrack both tokens so the expression completes (and
1089
- // evaluates to a Val) and the map's spread alts take over. This
1090
- // is what makes `k1:$flag &:boolean` parse: without it the expr
1091
- // plugin consumes the `&` as an infix conjunct, chokes on the
1092
- // `:`, and leaves the raw unevaluated expr node in the map
1093
- // (mirrors the expr-rule PrependClose in go/lang.go). The
1094
- // `n: { expr: 0 }` reset matches the plugin's own expr-end alts —
1095
- // the evaluation after-close only fires when the counter is 0.
1096
698
  { s: [CJ, CL], b: 2, n: { expr: 0 }, g: 'expr,expr-end,spread' },
1097
699
  ]);
1098
700
  return rs;
@@ -1139,18 +741,6 @@ help isolate the syntax error.`,
1139
741
  if (!Number.isFinite(r.node)) {
1140
742
  valnode = addsite(new NilVal_1.NilVal({ why: 'not_number' }), r, ctx);
1141
743
  }
1142
- // D7 -- A LOSSY INTEGER LITERAL IS REFUSED, NOT ROUNDED. The
1143
- // token above is already a double, so a literal the double
1144
- // cannot hold exactly (2^53+1, 0x7fffffffffffffff,
1145
- // 0xffffffffffffffff) has ALREADY become a different number by
1146
- // the time it gets here. Storing it would mean the document
1147
- // silently means something other than what it says, so the
1148
- // literal becomes a located error whose hint names the escape:
1149
- // write it `0d…` and get the exact value.
1150
- //
1151
- // The rule is EXACTNESS, not magnitude -- 10^20 and 2^124 are
1152
- // both far outside the int64 window and both land exactly on a
1153
- // binary64, so both stay values (see isLossyIntegerLiteral).
1154
744
  else if ((0, numkind_1.isLossyIntegerLiteral)(r.node, r.o0.src)) {
1155
745
  const nil = new NilVal_1.NilVal({ why: 'lossy_integer_literal' });
1156
746
  nil.details = { src: r.o0.src };
@@ -1194,15 +784,6 @@ help isolate the syntax error.`,
1194
784
  const optionalKeys = r.u.aontu_optional_keys ?? [];
1195
785
  const aliasKeys = r.u.aontu_alias_keys ?? [];
1196
786
  let mo = r.node;
1197
- // An elided value (`a:`) leaves a raw null/undefined that never
1198
- // passed through the val rule. It is REFUSED rather than made a
1199
- // null (issue #48): a key with nothing after the colon is a
1200
- // mistake in the source, and turning it into a value made that
1201
- // mistake indistinguishable from a deliberate `a:null`.
1202
- //
1203
- // A colon chain (`a: b:1`) is not an elision -- the value is the
1204
- // nested pair, which the val rule does produce -- and neither is
1205
- // a trailing comma.
1206
787
  for (const k in mo) {
1207
788
  if (null == mo[k] && '___merge' !== k &&
1208
789
  '___optional' !== k && '___alias' !== k) {
@@ -1213,45 +794,22 @@ help isolate the syntax error.`,
1213
794
  const en = addsite(new NilVal_1.NilVal({ why: 'elided_value' }), r, ctx);
1214
795
  en.path = [...(r.k?.path ?? []), k];
1215
796
  mo[k] = en;
1216
- // An elided value under an OPTIONAL key stops being optional.
1217
- // Optionality is about a value that may be absent at
1218
- // GENERATE; it does not excuse a source that stops after the
1219
- // colon. Left optional, the refusal was dropped with the key
1220
- // and `a?:` generated `{}` -- a silent nothing, which is
1221
- // worse than either the old null or the error.
1222
797
  const oi = optionalKeys.indexOf(k);
1223
798
  if (-1 !== oi) {
1224
799
  optionalKeys.splice(oi, 1);
1225
800
  }
1226
801
  }
1227
802
  }
1228
- // ... and the OPTIONAL spelling, `a?:`, which does not leave a
1229
- // null behind to be found: its value never reaches the node at
1230
- // all, so the key is simply absent and the map generated without
1231
- // it. A key recorded as optional but missing from the node was
1232
- // written with nothing after its colon.
1233
803
  for (const k of optionalKeys) {
1234
804
  if (!(k in mo)) {
1235
805
  mo[k] = addsite(new NilVal_1.NilVal({ why: 'elided_value' }), r, ctx);
1236
806
  }
1237
807
  }
1238
- // An elided SPREAD (`x:$obj&:` with nothing after the colon)
1239
- // refuses the whole map, not a key (issue #48). A spread is not a
1240
- // child, so a refusal stored in its place has nothing to attach
1241
- // to: `x:&:` has no children for the spread to apply to, and the
1242
- // map would generate as `{}` with the mistake silently gone.
1243
- // Refusing the container is what makes it visible at all.
1244
808
  const sp = mo[type_1.SPREAD];
1245
809
  if (sp && sp.v.some((sv) => null == sv)) {
1246
810
  r.node = addsite(new NilVal_1.NilVal({ why: 'elided_value' }), r, ctx);
1247
811
  return undefined;
1248
812
  }
1249
- // A KEY REFUSAL (the pair rule records them: a declaration
1250
- // spelled with a colon, a key the bare-text rule refuses) becomes
1251
- // the refusal, in place of whatever followed the colon and sited
1252
- // at the KEY rather than at the map -- at the offending character
1253
- // of it, where there is one -- so the frame points at the
1254
- // spelling to change.
1255
813
  for (const { key, tkn, why, details } of (r.u.aontu_key_refusals ?? [])) {
1256
814
  const en = siteAt(addsite(new NilVal_1.NilVal({ why }), r, ctx), tokenSite(tkn));
1257
815
  if (null != details) {
@@ -1280,7 +838,6 @@ help isolate the syntax error.`,
1280
838
  if (mo.___merge) {
1281
839
  let mop = { ...mo };
1282
840
  delete mop.___merge;
1283
- // TODO: needs addpath?
1284
841
  let mopv = new MapVal_1.MapVal({ peg: mop });
1285
842
  mopv.optionalKeys = optionalKeys;
1286
843
  mopv.aliasKeys = aliasKeys;
@@ -1299,13 +856,9 @@ help isolate the syntax error.`,
1299
856
  });
1300
857
  jsonic.rule('list', (rs) => {
1301
858
  rs
1302
- // .open([{ s: [CJ, CL], p: 'pair', b: 2, g: 'spread' }])
1303
859
  .bc((r, ctx) => {
1304
860
  const optionalKeys = r.u.aontu_optional_keys ?? [];
1305
861
  let ao = r.node;
1306
- // An elided ELEMENT (`[,]`, `[1,,2]`) is refused for the same
1307
- // reason as an elided map value (issue #48). A trailing comma
1308
- // (`[1,]`) is not an elision and never reaches here.
1309
862
  for (let i = 0; i < ao.length; i++) {
1310
863
  if (null == ao[i]) {
1311
864
  // Pathed at the INDEX, for the same reason as the map case.
@@ -1323,36 +876,16 @@ help isolate the syntax error.`,
1323
876
  }
1324
877
  return undefined;
1325
878
  });
1326
- // .close([{ s: [CJ, CL], b: 2, g: 'spread,json,more' }])
1327
879
  return rs;
1328
880
  });
1329
- // TODO: copied from jsonic grammar
1330
- // jsonic should provide a way to export this
1331
881
  const pairkey = (r) => {
1332
882
  // Get key string value from first matching token of `Open` state.
1333
883
  const key_token = r.o0;
1334
884
  const key = ST === key_token.tin || TX === key_token.tin
1335
- ? key_token.val // Was text
885
+ ? key_token.val
1336
886
  : key_token.src; // Was number, use original text
1337
887
  r.u.key = key;
1338
888
  };
1339
- // A pair in LIST position writes its value at `node[key]` like any
1340
- // other pair, and the enclosing list's node is an ARRAY -- so a numeric
1341
- // key lands on an index and becomes an element, and may land on an
1342
- // index a real element already holds (`[5,0:1]`). Since the pair must
1343
- // contribute nothing (issue #40), the slot is photographed before the
1344
- // value is parsed and put back afterwards. Restoring beats deleting for
1345
- // exactly the overwrite case: deleting `[5,0:1]`'s index 0 would take
1346
- // the 5 with it, where restoring gives back the list the pair was
1347
- // never part of.
1348
- //
1349
- // `length` is saved too: writing past the end grows an array, and
1350
- // `[5,1?:9]` must be [5] again and not [5, <hole>].
1351
- // Typed as a string bag deliberately: the slot may be named by a
1352
- // non-numeric key (`[x:1]`), which the array type would refuse. Both
1353
- // helpers run only from the elem rule, whose node is the enclosing
1354
- // list, so neither guards against a non-array node — a guard there
1355
- // proved unreachable and dead code is worse than none.
1356
889
  const asSlots = (r) => r.node;
1357
890
  const snapshotPairSlot = (r, key) => {
1358
891
  const node = asSlots(r);
@@ -1412,40 +945,14 @@ help isolate the syntax error.`,
1412
945
  })
1413
946
  .bc((rule) => {
1414
947
  // TRAVERSE PARENTS TO GET PATH
1415
- // A DECLARATION IS A PAIR WHOSE KEY IS AN ALIAS NAME. The lexer
1416
- // claims `%name` whole and hands it over as a #VL token whose
1417
- // SOURCE is the name, so the key TEXT alone cannot be the test:
1418
- // a quoted `"%a": 1` is an ordinary key that merely starts with
1419
- // the sigil, and erasing that would be wrong. The token is what
1420
- // separates them.
1421
- //
1422
- // Recorded on the enclosing map, never on the value, and that is
1423
- // the point: a reference COPIES the value it resolves to, so a
1424
- // mark riding the value would erase the referring field too.
1425
- // Being a property of the map is also what carries it through a
1426
- // meet, the way optional keys are carried.
1427
948
  const ktkn = rule.o0;
1428
949
  const holder = rule.parent;
1429
950
  const kr = keyRefusalOf(ktkn, rule.o1);
1430
951
  if (null != kr) {
1431
- // A KEY REFUSAL (keyRefusalOf) is written where the map is
1432
- // built, in the value's place and sited at the key, so the
1433
- // frame points at the spelling to change. A declaration
1434
- // spelled with a colon is refused rather than read as the
1435
- // ordinary key `%foo` the text would otherwise become -- a
1436
- // document written for the old form would then generate a
1437
- // "%foo" field and every `%foo` use would resolve to nothing,
1438
- // and neither says why.
1439
952
  holder.u.aontu_key_refusals = (holder.u.aontu_key_refusals || []);
1440
953
  holder.u.aontu_key_refusals.push({ key: '' + ktkn.src, tkn: ktkn, ...kr });
1441
954
  }
1442
955
  else if (isAliasDecl(ktkn, rule.o1)) {
1443
- // Always recorded here; whether the map is ALLOWED to carry
1444
- // declarations is decided on the VALUE (MapVal.unify), not at
1445
- // the parse. The parse cannot see it: an INCLUDED file's
1446
- // declarations are at the root of their own text, and only
1447
- // once the loaded map is placed does it become apparent that
1448
- // root is not the document's.
1449
956
  holder.u.aontu_alias_keys = (holder.u.aontu_alias_keys || []);
1450
957
  holder.u.aontu_alias_keys.push('' + ktkn.src);
1451
958
  }
@@ -1457,11 +964,6 @@ help isolate the syntax error.`,
1457
964
  return undefined;
1458
965
  })
1459
966
  .close([
1460
- // A following `&:` starts a sibling spread pair in the current
1461
- // map: directly inside a braced map (pk<=0) at any depth, or in
1462
- // the implicit top-level map (dmap<=1). Inside an implicit
1463
- // colon-chain map (pk>0) it bubbles up instead (second alt), so
1464
- // `a:b:1 &:2` attaches the spread to a's map, not b's.
1465
967
  { s: [CJ, CL], c: (r) => r.lte('pk', 0) || r.lte('dmap', 1), r: 'pair', b: 2, g: 'spread,json,pair' },
1466
968
  { s: [CJ, CL], b: 2, g: 'spread,json,more' }
1467
969
  ]);
@@ -1496,17 +998,6 @@ help isolate the syntax error.`,
1496
998
  },
1497
999
  g: 'aontu-optional-elem'
1498
1000
  },
1499
- // A PLAIN pair in list position IS A SINGLE-KEY MAP ELEMENT:
1500
- // `[a:1, b:2]` is `[{a:1}, {b:2}]` (the rule @tabnas/jsonic
1501
- // spells as `list.pair`). This REVERSES issue #40's "a pair is
1502
- // not an element": that rule was chosen because jsonic wrote
1503
- // the pair at `node[key]` -- an array PROPERTY that never
1504
- // showed up for a text key and an INDEX for a numeric one --
1505
- // and inert beat that incoherence. But inert was itself a
1506
- // silent drop: `x: [a:1, b:2]` evaluated to `x: []`, the
1507
- // author's data gone at exit 0. The element is built in the
1508
- // bc below, where the value is already a Val; the snapshot
1509
- // still neutralises jsonic's raw slot write first.
1510
1001
  {
1511
1002
  s: [OPTKEY, CL], p: 'val',
1512
1003
  u: { spread: true, done: true, list: true, pair: true },
@@ -1517,36 +1008,7 @@ help isolate the syntax error.`,
1517
1008
  g: 'aontu-plain-pair-elem'
1518
1009
  }
1519
1010
  ])
1520
- // NOTE: manually adjust path - the twin of the `pair` rule's hook
1521
- // above, and for the same reason, one layer down.
1522
- //
1523
- // Every alt above contributes NO element: a `&:` spread is a
1524
- // constraint on the elements, and a `k:v` pair in list position is
1525
- // simply not one (the `aontu-plain-pair-elem` note above). The array
1526
- // slot they briefly occupy is already given back by
1527
- // restorePairSlot. The PATH index was not: @tabnas/path's
1528
- // `@elem-ao` increments `r.k.index` for every elem rule it sees, so
1529
- // each of these stole an index and every later element's path was
1530
- // one too high — `[&: integer, 10, 20, "bad"]` reported the bad
1531
- // value at `$.l.3` while `aontu get $.l.2` returned it, and on a
1532
- // one-element list the path pointed off the end. Generation was
1533
- // never wrong, which is why nothing caught it: the array is right
1534
- // and only the labels on it were shifted (BUGS.md 44).
1535
- //
1536
- // Rewinding here rather than in the plugin keeps the plugin's rule
1537
- // ("in an array, the path property is the element index") true —
1538
- // these alts are the aontu-specific exceptions to what counts as an
1539
- // element, so the correction belongs with the grammar that
1540
- // introduces them. The child is re-pathed because the plugin has
1541
- // already stamped it with the index being given back: a spread
1542
- // takes the `'&'` segment its map twin takes, and a pair takes its
1543
- // key, as a map entry would.
1544
1011
  .ao((r) => {
1545
- // A pair IS an element now, so it keeps the index @tabnas/path
1546
- // gave it, and its VALUE is pathed through both the index and
1547
- // the key (`[a: $.nope]` fails at $.l.0.a). Only the `&:`
1548
- // spread still contributes no element and gives its index back
1549
- // (BUGS.md 44).
1550
1012
  if (0 < r.d && r.u.spread && !r.u.pair) {
1551
1013
  r.k.index = r.k.index - 1;
1552
1014
  const seg = '&';
@@ -1554,11 +1016,6 @@ help isolate the syntax error.`,
1554
1016
  r.child.k.key = seg;
1555
1017
  }
1556
1018
  else if (0 < r.d && r.u.pair) {
1557
- // The element's index is the array length: everything before
1558
- // it is already pushed, and the pair's own map is pushed at
1559
- // close. `r.k.index` is not usable here -- the path plugin
1560
- // counts only the elements it pushes itself, and this one is
1561
- // aontu's.
1562
1019
  const seg = '' + r.u.key;
1563
1020
  r.child.k.path =
1564
1021
  [...r.k.path, '' + (r.node?.length ?? 0), seg];
@@ -1567,39 +1024,14 @@ help isolate the syntax error.`,
1567
1024
  })
1568
1025
  .bc((rule, ctx) => {
1569
1026
  // TRAVERSE PARENTS TO GET PATH
1570
- // Only the `&:` alternative is a SPREAD. All four alts above set
1571
- // `spread: true` -- it is what marks them as contributing no
1572
- // element -- so this guard needs the narrower test, and `pair`
1573
- // is what distinguishes a `k:v` in list position from a spread.
1574
- //
1575
- // Without it a pair BUILT the spread record, with `o` taken from
1576
- // its own key rather than '&': `[x:1, &:integer, "bad"]` left
1577
- // `{o:'x', v:[1, integer]}`, and ListVal's `'&' === spread.o`
1578
- // then discarded the real constraint -- so the element spread
1579
- // was silently dropped and the bad value generated (BUGS.md 46).
1580
- // A pair alone did it too: `[x:1, 10]` produced a spread record
1581
- // out of nothing.
1582
1027
  if (rule.u.spread && !rule.u.pair) {
1583
1028
  rule.node[type_1.SPREAD] =
1584
1029
  (rule.node[type_1.SPREAD] || { o: rule.o0.src, v: [] });
1585
1030
  rule.node[type_1.SPREAD].v.push(rule.child.node);
1586
1031
  }
1587
- // The slot is given back BEFORE the element is added: the
1588
- // restore undoes jsonic's raw write (a property for a text
1589
- // key, an INDEX for a numeric one -- restoring length is what
1590
- // keeps `[1:2]` from padding with a null), and the push then
1591
- // appends cleanly after it.
1592
1032
  restorePairSlot(rule);
1593
- // THE SINGLE-KEY MAP ELEMENT, for both pair spellings. The
1594
- // value is a Val already (`p: 'val'`), so the map is built
1595
- // exactly as the map rule builds one -- and an elided value
1596
- // (`[a:]`) is refused exactly as the map rule refuses one
1597
- // (issue #48): a key with nothing after the colon is a
1598
- // mistake, not an empty value.
1599
1033
  if (true === rule.u.pair) {
1600
1034
  const key = '' + rule.u.key;
1601
- // The key TOKEN: the optional spelling's sits on the elem rule
1602
- // before this one (`[x?: 1]` is two elem rules).
1603
1035
  const ktkn = true === rule.u.aontu_optional_elem ?
1604
1036
  rule.prev.o0 : rule.o0;
1605
1037
  let v = rule.child.node;
@@ -1627,9 +1059,6 @@ help isolate the syntax error.`,
1627
1059
  // "is this the top level" test reads the path, so an element
1628
1060
  // of a top-level list must not read as the root.
1629
1061
  mv.path = [...(rule.k?.path ?? []), '' + rule.node.length];
1630
- // `[a?: 1]` is `[{a?: 1}]`: the key is optional IN the
1631
- // element, so the two spellings stay one rule apart rather
1632
- // than two behaviours apart.
1633
1062
  if (true === rule.u.aontu_optional_elem) {
1634
1063
  mv.optionalKeys = [key];
1635
1064
  }
@@ -1647,43 +1076,10 @@ help isolate the syntax error.`,
1647
1076
  return rs;
1648
1077
  });
1649
1078
  };
1650
- // INCLUDE_KINDS IS THE RULE FOR WHAT AN INCLUDE MEANS (ADR-012,
1651
- // use-cases/BUGS.md §49). An extension is on this list or it is not
1652
- // read at all, and its entry says WHICH OF TWO THINGS the file is.
1653
- //
1654
- // `source` — Aontu, with everything the language has: types, defaults,
1655
- // references, constraints, its own includes. Two extensions, and they
1656
- // are the ones this project owns.
1657
- //
1658
- // `text` — the file's BYTES, as one string scalar. No parser is
1659
- // chosen, so there is nothing for two ports to disagree about and
1660
- // nothing in the file that can mean anything: `notes: @"notes.txt"`
1661
- // is a document loading prose into a string. `.txt` is the only
1662
- // extension here by default; `AontuOptions.textExt` (the CLI's
1663
- // `--text-ext`) adds others, because which name a project keeps its
1664
- // templates under is the project's business, not this table's.
1665
- //
1666
- // A FORMAT NAME — configuration DATA, parsed by that format's own
1667
- // parser into the JSON value it denotes, which then becomes Aontu
1668
- // values like any other data. Every one of these formats maps onto
1669
- // JSON, which is why one word covers them: a `.toml` file is a map of
1670
- // scalars, lists and maps, and so is the `.aon` file that unifies with
1671
- // it. What the format does NOT get is the language — a `&` in a YAML
1672
- // file is a YAML anchor, not a spread key, because the YAML parser
1673
- // reads it, not this one.
1674
- //
1675
- // The parsers are @tabnas's, one per format, and the Go port uses the
1676
- // same ones (ADR-001): the two implementations agree because they are
1677
- // running the same grammar, not because two hand-written readers were
1678
- // kept in step.
1679
- //
1680
- // This table and go/source.go's includeKinds are the same table.
1681
1079
  const INCLUDE_KINDS = {
1682
1080
  aon: 'source',
1683
1081
  aontu: 'source',
1684
1082
  json: 'json',
1685
- // JSON-LD is JSON: a `@context` is a key like any other here, and
1686
- // what it MEANS is the vocabulary's business, not the reader's.
1687
1083
  jsonld: 'json',
1688
1084
  jsonc: 'jsonc',
1689
1085
  json5: 'json5',
@@ -1695,25 +1091,11 @@ const INCLUDE_KINDS = {
1695
1091
  ini: 'ini',
1696
1092
  txt: 'text',
1697
1093
  };
1698
- // WHAT AN EXTENSION MEANS, for this parse. The table is the fixed
1699
- // part; `textExt` is the per-parse widening, and it wins over nothing
1700
- // -- a host cannot re-read `.toml` as text, because an extension the
1701
- // table already names has a meaning documents rely on. Undefined is
1702
- // the refusal, and it is the ONE place that decides it: the resolver's
1703
- // gate and the processor map both ask here, so a widening cannot reach
1704
- // one and not the other.
1705
1094
  function includeFormat(ext, textExt) {
1706
1095
  const known = INCLUDE_KINDS[ext];
1707
1096
  if (undefined !== known) {
1708
1097
  return known;
1709
1098
  }
1710
- // NOT EVEN AS TEXT. `.js` is the extension ADR-012 singles out
1711
- // because multisource's own default EXECUTES it, and an extension
1712
- // this project refuses on purpose stays refused however a flag is
1713
- // spelled -- reading it is harmless, but a widening that can reach
1714
- // the one name the rule names is a widening whose limit nobody can
1715
- // state. Go's includeFormat holds the same list, and the two CLIs
1716
- // are diffed on `--text-ext js` because they once disagreed here.
1717
1099
  if (REFUSED_EXT.has(ext)) {
1718
1100
  return undefined;
1719
1101
  }
@@ -1723,17 +1105,6 @@ function includeFormat(ext, textExt) {
1723
1105
  // default processor; `''` is the no-extension fallback, which names no
1724
1106
  // file type at all.
1725
1107
  const REFUSED_EXT = new Set(['js', '']);
1726
- // `.csv` IS DELIBERATELY ABSENT, and the reason is ADR-001 rather than
1727
- // taste. The two ports' CSV parsers disagree about what a CSV file IS:
1728
- // one answers header-keyed records with string fields, the other raw
1729
- // rows including the header, with numbers parsed. Admitting it would
1730
- // admit a divergence into the one thing this project refuses to have
1731
- // one in. Recorded in ADR-012 and pinned by file.tsv's load-ext-csv.
1732
- // The multisource kind of a path: the LAST segment's extension, without
1733
- // its dot, lowercased -- `''` for a name that has none. The rule is
1734
- // @tabnas/multisource's own extKind (and Go's filepath.Ext), copied
1735
- // rather than imported because it decides what a source IS: a dot in a
1736
- // parent folder (`/my.app/conf`) must not read as an extension.
1737
1108
  function extKindOf(full) {
1738
1109
  const seg = full.match(/[^\\/]*$/)[0];
1739
1110
  return (seg.match(/\.([^.]*)$/) || ['', ''])[1].toLowerCase();
@@ -1746,15 +1117,6 @@ function extensionMsg(path, ext) {
1746
1117
  const which = '' === ext ? 'no extension' : 'extension: .' + ext;
1747
1118
  return 'include not readable: ' + path + ' (' + which + ')';
1748
1119
  }
1749
- // THE RULE ALSO HOLDS FOR A RESOLVER THIS ENGINE DID NOT WRITE.
1750
- // gateExtension refuses an unlisted extension inside makeModelResolver,
1751
- // which is the default; a HOST may supply its own through
1752
- // `AontuOptions.resolver`, and that one has never heard of
1753
- // INCLUDE_KINDS. Without this the host's resolution would fall to
1754
- // multisource's own default for an unnamed kind, which hands the file
1755
- // back as TEXT — or, for `.js`, EXECUTES it. So the two roads end in
1756
- // one place: whatever chose the source, an extension off the list is
1757
- // refused with the same code and the same message.
1758
1120
  const refuseProcessor = (res) => {
1759
1121
  // `full` is the one part a host resolution may leave out -- it is the
1760
1122
  // path the resolver CHOSE, and a resolver that answers from something
@@ -1790,22 +1152,6 @@ const DATA_READERS = (() => {
1790
1152
  ini: viaPlugin(ini_1.Ini),
1791
1153
  };
1792
1154
  })();
1793
- /**
1794
- * A TOML document with its dates as the TEXT they were written as.
1795
- *
1796
- * TOML HAS DATES AND JSON DOES NOT, so the reader cannot hand one over
1797
- * as itself: it answers with a marker object carrying the kind and the
1798
- * source text. The value that reaches a document is that TEXT, which is
1799
- * what a JSON document carries for a date anyway — and it is what the
1800
- * Go port produces too, from a `*TomlTime` holding those same two
1801
- * fields (`dataToValDepth`, go/source.go). Without this the same file
1802
- * is a nested map in one port and a string in the other, which is the
1803
- * class of divergence ADR-012 exists to stop.
1804
- *
1805
- * The guard is exact — one key, `__toml__`, holding a `kind` and a
1806
- * `src` string — so a document whose own data happens to use the name
1807
- * passes through untouched.
1808
- */
1809
1155
  function tomlDates(node) {
1810
1156
  if (Array.isArray(node)) {
1811
1157
  return node.map(tomlDates);
@@ -1825,31 +1171,12 @@ function tomlDates(node) {
1825
1171
  }
1826
1172
  return out;
1827
1173
  }
1828
- /**
1829
- * Read one included file as DATA in the named format.
1830
- *
1831
- * The parser hands back the JSON value the file denotes — plain maps,
1832
- * lists and scalars — and rawToVal turns that into Vals. THE
1833
- * CONVERSION HAPPENS HERE, not at the top level, because an include is
1834
- * usually not at the top level: `a: @"conf.toml"` puts the value under
1835
- * a key, where a raw JavaScript object is something the tree cannot
1836
- * unify with (the crash that was BUGS §49b).
1837
- */
1838
1174
  const dataProcessor = (format) => (res) => {
1839
1175
  res.val = rawToVal(DATA_READERS[format](res.src, res.path));
1840
1176
  };
1841
- // TEXT IS NOT PARSED. The bytes multisource read are the value, so
1842
- // this is the one processor with no reader behind it -- which is why
1843
- // a `.txt` include cannot fail on content, only on being unreadable.
1844
1177
  const textProcessor = (res) => {
1845
1178
  res.val = new StringVal_1.StringVal({ peg: res.src });
1846
1179
  };
1847
- /**
1848
- * The multisource processor map, built FROM the include table so the
1849
- * two cannot drift: every extension the table names gets the reader
1850
- * the table names for it, and the two kinds that are not in the table
1851
- * refuse.
1852
- */
1853
1180
  function includeProcessors(textExt) {
1854
1181
  const map = {
1855
1182
  // multisource's fallback for an extension no entry names, so it is
@@ -1870,10 +1197,6 @@ function includeProcessors(textExt) {
1870
1197
  for (const kind of Object.keys(INCLUDE_KINDS)) {
1871
1198
  map[kind] = forKind(kind);
1872
1199
  }
1873
- // A WIDENING NEVER OVERWRITES. `js` and the empty fallback refuse
1874
- // above and stay refusing: `--text-ext js` would otherwise turn the
1875
- // one extension ADR-012 singles out into a readable one, by a flag
1876
- // whose whole promise is that it chooses no parser.
1877
1200
  for (const ext of textExt ?? []) {
1878
1201
  if (undefined === map[ext]) {
1879
1202
  map[ext] = textProcessor;
@@ -1881,17 +1204,8 @@ function includeProcessors(textExt) {
1881
1204
  }
1882
1205
  return map;
1883
1206
  }
1884
- // SECURITY: under the DEFAULT ('system') include capability this
1885
- // resolver reads any file the process can reach — @"path" follows
1886
- // relative paths (`@"../../etc/passwd.aon"`) and symlinks — so treat
1887
- // opening an untrusted source as reading your disk. It no longer RUNS
1888
- // one: @"pkg" could require() an arbitrary installed module until
1889
- // ADR-012, which refuses a `.js` entry point by the same rule that
1890
- // refuses `.txt`. The trust profile (G5, docs/trust.md) is the
1891
- // confinement surface: `trust.include` of
1892
- // 'none', `{ mem }` or `{ root }` restricts what `@"..."` may resolve,
1893
- // and a denied resolution is a deterministic parse-stage
1894
- // `include_denied` error.
1207
+ // What a resolved include may reach, and how it is confined:
1208
+ // docs/trust.md.
1895
1209
  function makeModelResolver(options) {
1896
1210
  const useRequire = options.require || require;
1897
1211
  const capability = options.trust?.include ?? 'system';
@@ -1899,22 +1213,9 @@ function makeModelResolver(options) {
1899
1213
  const rootDir = 'object' === typeof capability &&
1900
1214
  'string' === typeof capability.root
1901
1215
  ? (0, node_path_1.resolve)(capability.root) : undefined;
1902
- // Under the mem capability the CAPABILITY's file set is the whole
1903
- // world; otherwise the host-injected `options.resolver.mem` entries
1904
- // remain available under every capability but 'none' — they are
1905
- // host-provided, not document-requested, so confining them would
1906
- // confine the host against itself.
1907
- // THE BUNDLED VOCABULARY (G4 phase 4, ts/src/std.ts) rides the
1908
- // memory leg: served from the engine itself, so it needs neither the
1909
- // filesystem nor package resolution and is available under every
1910
- // capability but `none` — which denies every include outright, that
1911
- // being what `none` means. Host entries and the capability's own set
1912
- // WIN over it: a caller that supplies its own `std/system` gets the
1913
- // one it supplied.
1914
1216
  let memResolver = (0, mem_1.makeMemResolver)(memCapability
1915
1217
  ? { ...capability.mem }
1916
1218
  : { ...(options.resolver?.mem || {}) });
1917
- // TODO: make this consistent with other resolvers
1918
1219
  let fileResolver = (0, file_1.makeFileResolver)((spec) => {
1919
1220
  return 'string' === typeof spec ? spec : spec?.peg;
1920
1221
  });
@@ -1922,23 +1223,6 @@ function makeModelResolver(options) {
1922
1223
  require: useRequire,
1923
1224
  ...(options.resolver?.pkg || {})
1924
1225
  });
1925
- // Confinement is realpath-then-prefix-check (docs/trust.md): the
1926
- // RESOLVED file's real path must sit below the root's real path, so a
1927
- // symlink inside the root pointing outside it is an escape, not a
1928
- // loophole. A path realpath cannot resolve falls back to the lexical
1929
- // form — the comparison is then against what the resolver actually
1930
- // read.
1931
- // Real fs, deliberately: `options.fs` is not a sandbox (it feeds
1932
- // parse text; the file leg reads through its own channel), so the
1933
- // containment check must see the same filesystem that leg read from.
1934
- // A path that does not (fully) exist cannot be realpath'd whole, and
1935
- // falling back to the LEXICAL form compares apples to oranges when
1936
- // the root itself sits behind a symlink -- on macOS a root under
1937
- // /var realpaths to /private/var, so a merely-missing file inside it
1938
- // reads as an escape. Realpath the deepest EXISTING ancestor and
1939
- // re-attach the rest, so both sides of the check are in real
1940
- // coordinates. (The MCP server's own confinement carries the twin of
1941
- // this rule; its CI failure is what found the shape.)
1942
1226
  const realpath = (p) => {
1943
1227
  try {
1944
1228
  return (0, node_fs_1.realpathSync)(p);
@@ -1956,12 +1240,6 @@ function makeModelResolver(options) {
1956
1240
  const fullReal = realpath(full);
1957
1241
  return fullReal !== rootReal && !fullReal.startsWith(rootReal + node_path_1.sep);
1958
1242
  };
1959
- // A denial THROWS with the code; Lang.parse converts it to the
1960
- // parse-stage `include_denied` nil (the same shape a syntax failure
1961
- // takes). Raising beats injecting a nil value: a bare-member include
1962
- // (`@"denied.aon"` at the top of a file) MERGES into the enclosing
1963
- // map, and a nil contributes no keys, so an injected denial would
1964
- // vanish and leave a plausible, silently-partial document.
1965
1243
  const deny = (path) => {
1966
1244
  // Only 'none' and 'root' can deny: the mem capability's misses are
1967
1245
  // not-found (its set is the whole world), so there is no third arm.
@@ -1970,12 +1248,6 @@ function makeModelResolver(options) {
1970
1248
  err.code = 'include_denied';
1971
1249
  throw err;
1972
1250
  };
1973
- // AN UNREADABLE EXTENSION THROWS, exactly as a denial does, and for
1974
- // the same reason: a bare-member include (`@"notes.txt"` at the top
1975
- // of a file) MERGES into the enclosing map, and a nil contributes no
1976
- // keys, so an injected refusal would vanish and leave a plausible,
1977
- // silently-partial document. Lang.parse turns the throw into the
1978
- // parse-stage `include_extension` nil.
1979
1251
  const refuseExtension = (path, full) => {
1980
1252
  const err = new Error(extensionMsg(path, extKindOf(full)));
1981
1253
  err.code = 'include_extension';
@@ -1987,12 +1259,12 @@ function makeModelResolver(options) {
1987
1259
  // set: a typo in an `aontu:` name must not go looking on disk.
1988
1260
  const modelNotFound = (path) => {
1989
1261
  const err = new Error('source not found: ' + path +
1990
- ' (the language-supplied models are ' + std_1.AONTU_MODELS.join(', ') + ')');
1262
+ ' (the language-supplied models are ' + aontumodel_1.AONTU_MODELS.join(', ') + ')');
1991
1263
  err.code = 'multisource_not_found';
1992
1264
  throw err;
1993
1265
  };
1994
- // The gate every leg that RESOLVES A NAME passes through. The std and
1995
- // 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
1996
1268
  // serve is Aontu source by construction, not by its spelling.
1997
1269
  const gateExtension = (path, full) => {
1998
1270
  if (undefined === includeFormat(extKindOf(full), options.textExt)) {
@@ -2049,35 +1321,14 @@ function makeModelResolver(options) {
2049
1321
  if ('none' === capability) {
2050
1322
  deny(path);
2051
1323
  }
2052
- // THE LANGUAGE-SUPPLIED MODELS (docs/design/MODELS.0.md D1): an
2053
- // `aontu:` name resolves from the engine's own table and nowhere
2054
- // else -- the memory, module, file and package legs are never
2055
- // asked, so nothing on disk can shadow one and a typo is refused
2056
- // here, naming the set, rather than searched for. Available under
2057
- // every capability but `none`, checked just above, like the std
2058
- // names below. A path that is not a string (`a: @1`) is not a name
2059
- // at all: it falls through to the legs below and is not found there,
2060
- // as it always was.
2061
- if ('string' === typeof path && path.startsWith(std_1.AONTU_SCHEME)) {
2062
- 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];
2063
1326
  if (null == model) {
2064
1327
  modelNotFound(path);
2065
1328
  }
2066
- record(ctx, path, 'std');
1329
+ record(ctx, path, 'aontu');
2067
1330
  return { found: true, path, full: path, kind: 'aon', src: model, search: [] };
2068
1331
  }
2069
- // THE BUNDLED VOCABULARY (G4 phase 4, ts/src/std.ts): served from
2070
- // the engine itself, so it needs neither the filesystem nor package
2071
- // resolution and is available under every capability but `none` —
2072
- // checked just above, that being what `none` means. Matched against
2073
- // the name the author WROTE, before the memory leg, so the kind is
2074
- // stated rather than guessed from an extension the bare name does
2075
- // not have.
2076
- const std = std_1.STD_SOURCES[path];
2077
- if (null != std) {
2078
- record(ctx, path, 'std');
2079
- return { found: true, path, full: path, kind: 'aon', src: std, search: [] };
2080
- }
2081
1332
  let search = [];
2082
1333
  let res = memResolver(path, popts, rule, ctx, jsonic);
2083
1334
  res.path = path;
@@ -2090,11 +1341,6 @@ function makeModelResolver(options) {
2090
1341
  record(ctx, res.full ?? path, 'mem');
2091
1342
  return res;
2092
1343
  }
2093
- // THE MODULE LEG (G6 phase 2, ts/src/mod.ts): memory -> MODULE ->
2094
- // filesystem -> package. Memory stays FIRST so a sandbox and the
2095
- // spec suite can stub a module path without touching disk; a path
2096
- // that is not module-shaped falls straight through, so no existing
2097
- // include can be routed somewhere new by this.
2098
1344
  const modref = memCapability ? undefined : (0, mod_1.parseModuleRef)(path);
2099
1345
  if (null != modref) {
2100
1346
  const msmeta = ctx?.meta?.multisource;
@@ -2172,37 +1418,17 @@ function makeModelResolver(options) {
2172
1418
  return res;
2173
1419
  };
2174
1420
  }
2175
- // THE SIGNATURE REGISTRY (docs/design/SIGNATURES.0.md). The call
2176
- // surface is DECLARED in test/spec/signature.tsv and parsed by the
2177
- // signature grammar (ts/src/sig.ts) from the build-time-inlined copy;
2178
- // the arity table and the positional set below are DERIVED from the
2179
- // parsed registry (funcSig, ts/src/sig.ts), so the declaration is the
2180
- // one source. go/func.go derives the same two tables from the same
2181
- // text.
2182
- // The functions whose comma-separated arguments are distinct POSITIONS
2183
- // rather than one argument list. See the func-paren handler above: this
2184
- // is the set whose comma group is expanded back into separate `peg`
2185
- // entries. Derived: two or more declared argument slots, excluding the
2186
- // residual producers (`constraint` results) -- the constraint atoms
2187
- // make the same expansion in their own constructor (`atomArgs`,
2188
- // ConstraintVal.ts, deliberately before the settled check), which is
2189
- // why they are not in this set; `must` is the load-bearing example.
2190
- // Arithmetic is here because `sub` is not commutative: `sub(a, b)`
2191
- // reaching the engine as one two-element list would lose which is
2192
- // which.
2193
1421
  const POSITIONAL_ARG_FUNCS = {};
2194
1422
  for (const name in sig_1.funcSig) {
2195
1423
  if (2 <= sig_1.funcSig[name].args.length && 'constraint' !== sig_1.funcSig[name].out) {
2196
1424
  POSITIONAL_ARG_FUNCS[name] = true;
2197
1425
  }
2198
1426
  }
2199
- // [min, max]; a max of -1 is unbounded. Every name in funcMap has an
2200
- // entry, and the arity is a property of the language rather than of
2201
- // either port -- go/func.go derives the same table. A required slot
2202
- // counts toward the minimum; a rest slot makes the maximum unbounded
2203
- // and counts its group size (one, for a plain rest type) toward the
2204
- // minimum, which is what gives `match` its floor of three and `neq`
2205
- // its floor of one.
1427
+ for (const name of Object.keys(CmpFuncVal_1.CMP_FUNCS)) {
1428
+ POSITIONAL_ARG_FUNCS[name] = true;
1429
+ }
1430
+ POSITIONAL_ARG_FUNCS['nom'] = true;
1431
+ POSITIONAL_ARG_FUNCS['translate'] = true;
2206
1432
  function sigArity(sig) {
2207
1433
  let min = 0;
2208
1434
  let max = 0;
@@ -2226,14 +1452,6 @@ const funcArity = {};
2226
1452
  for (const name in sig_1.funcSig) {
2227
1453
  funcArity[name] = sigArity(sig_1.funcSig[name]);
2228
1454
  }
2229
- // writtenArgCount counts the arguments as the AUTHOR wrote them.
2230
- //
2231
- // It cannot simply be terms.length: a comma group reaches the func-paren
2232
- // handler as ONE term holding a raw array, so `upper("a","b")` and
2233
- // `upper(["a","b"])` both arrive as a single argument. They are still
2234
- // distinguishable, and that is what makes an arity check possible at
2235
- // all -- the comma group is a RAW array, while a written list literal
2236
- // has already been built into a ListVal by the list rule.
2237
1455
  function writtenArgCount(terms) {
2238
1456
  if (1 === terms.length) {
2239
1457
  // `terms[0]` is re-read rather than reusing a narrowed local:
@@ -2255,7 +1473,10 @@ function arityText(lo, hi) {
2255
1473
  return 'one or more arguments';
2256
1474
  }
2257
1475
  if (lo !== hi) {
2258
- return 0 === lo ? 'no arguments or one' : 'one argument or two';
1476
+ if (0 === lo) {
1477
+ return 'no arguments or one';
1478
+ }
1479
+ return 3 === hi ? 'one to three arguments' : 'one argument or two';
2259
1480
  }
2260
1481
  // The {0,0} arm returned with the container kinds and acyclic()
2261
1482
  // (ADR-015): `map(1)` must not claim map takes exactly one.
@@ -2267,17 +1488,6 @@ function arityText(lo, hi) {
2267
1488
  }
2268
1489
  return 'exactly one argument';
2269
1490
  }
2270
- // rawToVal converts a raw parse node (or raw elements inside one) into
2271
- // the matching Val. Used for implicit top-level lists, whose nodes skip
2272
- // the aontu val rule conversions (mirrors asVal in go/lang.go; like
2273
- // there, source text is unavailable, so an integral number is an
2274
- // integer).
2275
- // The targeted parse hint for CUE-trained authors and models: `>` and
2276
- // `<` are not Aontu operators (the op-chars reservation stands), and an
2277
- // agent that emits `number > 0` should be redirected to the bound
2278
- // atoms, not left with a bare "unexpected character". Appended to a
2279
- // parse error's message when the source carries an unquoted `<` or
2280
- // `>`; the Go twin is opCharHint in go/lang.go, byte-identical text.
2281
1491
  function opCharHint(src) {
2282
1492
  let q = '';
2283
1493
  for (let i = 0; i < src.length; i++) {
@@ -2305,12 +1515,6 @@ function rawToVal(n) {
2305
1515
  if (Array.isArray(n)) {
2306
1516
  return new ListVal_1.ListVal({ peg: n.map(rawToVal) });
2307
1517
  }
2308
- // THE SCALAR ARMS ARE WHERE A CONFIG FILE BECOMES VALUES. Every
2309
- // format on the include table is read by its own parser into plain
2310
- // JavaScript -- a string, a number, a map -- and this is the walk
2311
- // that turns that into Vals (dataProcessor, ADR-012). The two arms
2312
- // above are the other caller: a raw expression TERM, which the
2313
- // expression grammar hands over already built.
2314
1518
  if (null == n) {
2315
1519
  return new NullVal_1.NullVal({ peg: null });
2316
1520
  }
@@ -2319,24 +1523,12 @@ function rawToVal(n) {
2319
1523
  return new StringVal_1.StringVal({ peg: n });
2320
1524
  }
2321
1525
  if ('number' === t) {
2322
- // No source text here, so the "no '.'" condition is vacuous and the
2323
- // integral + int64-range conditions decide (same helper as the val
2324
- // rule, so the two paths cannot drift).
2325
1526
  return (0, numkind_1.isIntegerKind)(n) ?
2326
1527
  new IntegerVal_1.IntegerVal({ peg: n }) : new NumberVal_1.NumberVal({ peg: n });
2327
1528
  }
2328
1529
  if ('boolean' === t) {
2329
1530
  return new BooleanVal_1.BooleanVal({ peg: n });
2330
1531
  }
2331
- // AND EVERYTHING ELSE IS A MAP, with no arm after it because there is
2332
- // nothing after it. Every reader on the include table answers with
2333
- // the JSON kinds and no others -- probed, including the two that
2334
- // could plausibly escape them: a big integer comes back a `number`,
2335
- // and a TOML date is normalised to its text before it gets here. The
2336
- // one include that could hand over a function was `.js`, which
2337
- // ADR-012 refuses. `parse_unknown` lived here for that case and has
2338
- // no producer left in this port; the Go twin keeps its own, where the
2339
- // type switch really can be handed something unaccounted for.
2340
1532
  const peg = {};
2341
1533
  for (const k in n) {
2342
1534
  peg[k] = rawToVal(n[k]);
@@ -2345,7 +1537,6 @@ function rawToVal(n) {
2345
1537
  }
2346
1538
  class Lang {
2347
1539
  constructor(options) {
2348
- // const start = performance.now()
2349
1540
  this.opts = Object.assign((0, type_1.DEFAULT_OPTS)(), options);
2350
1541
  const modelResolver = makeModelResolver(this.opts);
2351
1542
  this.jsonic = jsonic_1.Jsonic.make();
@@ -2357,31 +1548,12 @@ class Lang {
2357
1548
  this.jsonic
2358
1549
  .use(asPlugin(multisource_1.MultiSource), {
2359
1550
  resolver: options?.resolver || modelResolver,
2360
- // `.aon` is the preferred Aontu source extension; `.aontu` also
2361
- // works. `.jsonic` is retired (no longer auto-resolved); the
2362
- // default `['jsonic','jsc','json','js']` is overridden here.
2363
- // (Upstream option name is the misspelled `implictExt`.)
2364
- //
2365
- // Only these two are SEARCHED for a bare `@"name"`; `.json` and
2366
- // `.jsonld` are read when NAMED, which is how a vendored
2367
- // vocabulary is always written.
2368
1551
  implictExt: ['aon', 'aontu'],
2369
- // ONE ENTRY PER EXTENSION THE TABLE NAMES, built from it (see
2370
- // includeProcessors) so the rule and its wiring cannot drift.
2371
- //
2372
- // The upstream defaults are REPLACED, not extended. Its `json`
2373
- // entry is what made that extension the one that crashed: it
2374
- // hands back a raw JS object where the aontu grammar produces
2375
- // Vals, and the tree then met a value it could not convert
2376
- // (BUGS §49b). Its `js` entry EXECUTES the file, which is not
2377
- // something an extension should be able to ask for. And its
2378
- // fallback hands any other file back as TEXT.
2379
1552
  processor: includeProcessors(this.opts.textExt)
2380
1553
  })
2381
1554
  .use(AontuJsonic);
2382
1555
  }
2383
1556
  parse(src, opts) {
2384
- // const start = performance.now()
2385
1557
  // JSONIC-UPDATE - check meta
2386
1558
  let jm = {
2387
1559
  fs: opts?.fs,
@@ -2404,7 +1576,6 @@ class Lang {
2404
1576
  if (opts && null != opts.log && Number.isInteger(opts.log)) {
2405
1577
  jm.log = opts.log;
2406
1578
  }
2407
- // jm.log = -1
2408
1579
  let val;
2409
1580
  try {
2410
1581
  val = this.jsonic(src, jm);
@@ -2419,14 +1590,6 @@ class Lang {
2419
1590
  catch (e) {
2420
1591
  if ('include_denied' === e?.code || 'include_extension' === e?.code ||
2421
1592
  'multisource_not_found' === e?.code || mod_1.MODULE_REFUSAL_CODES.has(e?.code)) {
2422
- // A denied include (G5), an include whose extension is not read
2423
- // as Aontu source (ADR-012, INCLUDE_KINDS), an `aontu:` name the
2424
- // engine does not serve (MODELS.0.md D1), and a module that is
2425
- // missing, fails its pin, or names a path that escapes its store
2426
- // (G6 phase 2) are refused the same way, for the same reason: the
2427
- // resolver THROWS so a bare-member include cannot vanish in the
2428
- // merge, and the code survives here as the parse-stage nil the
2429
- // registry pins (errcodes.tsv).
2430
1593
  val = new NilVal_1.NilVal({
2431
1594
  why: 'parse',
2432
1595
  err: new NilVal_1.NilVal({
@@ -2442,14 +1605,6 @@ class Lang {
2442
1605
  msg: e.message + opCharHint(src),
2443
1606
  err: e,
2444
1607
  });
2445
- // THE POSITION TRAVELS WITH IT. The parser knows exactly where
2446
- // it stopped -- it draws a caret there -- and the rendered
2447
- // message carried the only copy, so `vet --format json`
2448
- // reported row -1, col -1 for a document whose fault the human
2449
- // renderer located to the character. A machine-readable report
2450
- // that says "somewhere in this file" is the one a repair loop
2451
- // can do nothing with. Both numbers are already 1-based here,
2452
- // which is the base a site uses (go/lang.go does the same).
2453
1608
  if ('number' === typeof e.lineNumber) {
2454
1609
  syntax.site.row = e.lineNumber;
2455
1610
  }