aontu 0.62.0 → 0.64.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 (373) hide show
  1. package/README.md +7 -7
  2. package/dist/agentsmd.js +0 -27
  3. package/dist/agentsmd.js.map +1 -1
  4. package/dist/alias.js.map +1 -1
  5. package/dist/allow.js +0 -92
  6. package/dist/allow.js.map +1 -1
  7. package/dist/aontu.d.ts +3 -3
  8. package/dist/aontu.js +4 -84
  9. package/dist/aontu.js.map +1 -1
  10. package/dist/aontumodel.d.ts +4 -0
  11. package/dist/aontumodel.js +27 -0
  12. package/dist/aontumodel.js.map +1 -0
  13. package/dist/casing.d.ts +5 -0
  14. package/dist/casing.js +90 -0
  15. package/dist/casing.js.map +1 -0
  16. package/dist/cli.d.ts +2 -2
  17. package/dist/cli.js +228 -935
  18. package/dist/cli.js.map +1 -1
  19. package/dist/ctx.js +0 -48
  20. package/dist/ctx.js.map +1 -1
  21. package/dist/diff.js +0 -32
  22. package/dist/diff.js.map +1 -1
  23. package/dist/err.js +0 -40
  24. package/dist/err.js.map +1 -1
  25. package/dist/escape.js +0 -45
  26. package/dist/escape.js.map +1 -1
  27. package/dist/exactjson.d.ts +0 -35
  28. package/dist/exactjson.js +0 -131
  29. package/dist/exactjson.js.map +1 -1
  30. package/dist/format.js +13 -203
  31. package/dist/format.js.map +1 -1
  32. package/dist/grammar.d.ts +9 -0
  33. package/dist/grammar.js +54 -0
  34. package/dist/grammar.js.map +1 -0
  35. package/dist/graph.js +0 -26
  36. package/dist/graph.js.map +1 -1
  37. package/dist/hcanon.js +0 -82
  38. package/dist/hcanon.js.map +1 -1
  39. package/dist/helpdoc.js +2 -2
  40. package/dist/helpdoc.js.map +1 -1
  41. package/dist/hints.d.ts +0 -6
  42. package/dist/hints.js +57 -55
  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 +17 -915
  50. package/dist/lang.js.map +1 -1
  51. package/dist/lsp-server.js +0 -16
  52. package/dist/lsp-server.js.map +1 -1
  53. package/dist/lsp.d.ts +1 -1
  54. package/dist/lsp.js +12 -159
  55. package/dist/lsp.js.map +1 -1
  56. package/dist/mcp-server.js +0 -26
  57. package/dist/mcp-server.js.map +1 -1
  58. package/dist/mcp.js +0 -149
  59. package/dist/mcp.js.map +1 -1
  60. package/dist/mod-tool.js +16 -131
  61. package/dist/mod-tool.js.map +1 -1
  62. package/dist/mod.js +0 -162
  63. package/dist/mod.js.map +1 -1
  64. package/dist/patch.js +0 -217
  65. package/dist/patch.js.map +1 -1
  66. package/dist/profile.d.ts +9 -0
  67. package/dist/profile.js +28 -0
  68. package/dist/profile.js.map +1 -0
  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.js +0 -61
  76. package/dist/relation.js.map +1 -1
  77. package/dist/report-sarif.d.ts +0 -11
  78. package/dist/report-sarif.js +0 -28
  79. package/dist/report-sarif.js.map +1 -1
  80. package/dist/sig.js +0 -35
  81. package/dist/sig.js.map +1 -1
  82. package/dist/sigdecl.js +1 -1
  83. package/dist/sigdecl.js.map +1 -1
  84. package/dist/siggate.js +0 -4
  85. package/dist/siggate.js.map +1 -1
  86. package/dist/site.js +3 -29
  87. package/dist/site.js.map +1 -1
  88. package/dist/subsume.d.ts +0 -10
  89. package/dist/subsume.js +0 -137
  90. package/dist/subsume.js.map +1 -1
  91. package/dist/template.d.ts +2 -1
  92. package/dist/template.js +58 -138
  93. package/dist/template.js.map +1 -1
  94. package/dist/trace.d.ts +21 -0
  95. package/dist/trace.js +107 -0
  96. package/dist/trace.js.map +1 -0
  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 +13 -248
  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 +2 -0
  125. package/dist/val/CmpFuncVal.js +49 -72
  126. package/dist/val/CmpFuncVal.js.map +1 -1
  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.js +0 -3
  141. package/dist/val/EachFuncVal.js.map +1 -1
  142. package/dist/val/EmitFuncVal.d.ts +1 -1
  143. package/dist/val/EmitFuncVal.js +6 -119
  144. package/dist/val/EmitFuncVal.js.map +1 -1
  145. package/dist/val/ExpectVal.js +0 -62
  146. package/dist/val/ExpectVal.js.map +1 -1
  147. package/dist/val/FilterFuncVal.js +0 -25
  148. package/dist/val/FilterFuncVal.js.map +1 -1
  149. package/dist/val/FuncBaseVal.d.ts +1 -0
  150. package/dist/val/FuncBaseVal.js +7 -127
  151. package/dist/val/FuncBaseVal.js.map +1 -1
  152. package/dist/val/GraphAtomVal.js +0 -15
  153. package/dist/val/GraphAtomVal.js.map +1 -1
  154. package/dist/val/HideFuncVal.js +0 -13
  155. package/dist/val/HideFuncVal.js.map +1 -1
  156. package/dist/val/IntegerVal.js +0 -61
  157. package/dist/val/IntegerVal.js.map +1 -1
  158. package/dist/val/JunctionVal.js +0 -20
  159. package/dist/val/JunctionVal.js.map +1 -1
  160. package/dist/val/KeyFuncVal.js +0 -46
  161. package/dist/val/KeyFuncVal.js.map +1 -1
  162. package/dist/val/ListVal.js +0 -57
  163. package/dist/val/ListVal.js.map +1 -1
  164. package/dist/val/LowerFuncVal.js +0 -11
  165. package/dist/val/LowerFuncVal.js.map +1 -1
  166. package/dist/val/MapVal.js +0 -151
  167. package/dist/val/MapVal.js.map +1 -1
  168. package/dist/val/MatchFuncVal.js +0 -27
  169. package/dist/val/MatchFuncVal.js.map +1 -1
  170. package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
  171. package/dist/val/MaybeFuncVal.js +50 -0
  172. package/dist/val/MaybeFuncVal.js.map +1 -0
  173. package/dist/val/MoveFuncVal.js +0 -18
  174. package/dist/val/MoveFuncVal.js.map +1 -1
  175. package/dist/val/NilVal.js +0 -60
  176. package/dist/val/NilVal.js.map +1 -1
  177. package/dist/val/NomFuncVal.js +18 -54
  178. package/dist/val/NomFuncVal.js.map +1 -1
  179. package/dist/val/NumberVal.js +0 -15
  180. package/dist/val/NumberVal.js.map +1 -1
  181. package/dist/val/OpBaseVal.d.ts +1 -0
  182. package/dist/val/OpBaseVal.js +3 -15
  183. package/dist/val/OpBaseVal.js.map +1 -1
  184. package/dist/val/PackFuncVal.js +0 -34
  185. package/dist/val/PackFuncVal.js.map +1 -1
  186. package/dist/val/PathFuncVal.js +0 -6
  187. package/dist/val/PathFuncVal.js.map +1 -1
  188. package/dist/val/PathVal.js +0 -41
  189. package/dist/val/PathVal.js.map +1 -1
  190. package/dist/val/PlaceVal.js +0 -25
  191. package/dist/val/PlaceVal.js.map +1 -1
  192. package/dist/val/PlusOpVal.d.ts +1 -7
  193. package/dist/val/PlusOpVal.js +13 -74
  194. package/dist/val/PlusOpVal.js.map +1 -1
  195. package/dist/val/PrefFuncVal.js +0 -1
  196. package/dist/val/PrefFuncVal.js.map +1 -1
  197. package/dist/val/PrefVal.js +0 -167
  198. package/dist/val/PrefVal.js.map +1 -1
  199. package/dist/val/RecurseVal.js +0 -55
  200. package/dist/val/RecurseVal.js.map +1 -1
  201. package/dist/val/RefVal.js +0 -282
  202. package/dist/val/RefVal.js.map +1 -1
  203. package/dist/val/ReferFuncVal.js +3 -232
  204. package/dist/val/ReferFuncVal.js.map +1 -1
  205. package/dist/val/ScalarKindVal.js +0 -49
  206. package/dist/val/ScalarKindVal.js.map +1 -1
  207. package/dist/val/ScalarVal.js +0 -11
  208. package/dist/val/ScalarVal.js.map +1 -1
  209. package/dist/val/StrFuncVal.js +0 -18
  210. package/dist/val/StrFuncVal.js.map +1 -1
  211. package/dist/val/SuperFuncVal.js +0 -32
  212. package/dist/val/SuperFuncVal.js.map +1 -1
  213. package/dist/val/TopVal.js +0 -1
  214. package/dist/val/TopVal.js.map +1 -1
  215. package/dist/val/TranslateFuncVal.js +1 -3
  216. package/dist/val/TranslateFuncVal.js.map +1 -1
  217. package/dist/val/UpperFuncVal.js +0 -11
  218. package/dist/val/UpperFuncVal.js.map +1 -1
  219. package/dist/val/Val.d.ts +1 -0
  220. package/dist/val/Val.js +2 -133
  221. package/dist/val/Val.js.map +1 -1
  222. package/dist/val/VarVal.js +0 -12
  223. package/dist/val/VarVal.js.map +1 -1
  224. package/dist/val/arith.js +0 -37
  225. package/dist/val/arith.js.map +1 -1
  226. package/dist/val/caserange.js +0 -61
  227. package/dist/val/caserange.js.map +1 -1
  228. package/dist/val/members.js +0 -6
  229. package/dist/val/members.js.map +1 -1
  230. package/dist/val/numcmp.js +0 -11
  231. package/dist/val/numcmp.js.map +1 -1
  232. package/dist/val/numkind.js +0 -145
  233. package/dist/val/numkind.js.map +1 -1
  234. package/dist/val/valutil.js +0 -16
  235. package/dist/val/valutil.js.map +1 -1
  236. package/dist/vet.js +0 -461
  237. package/dist/vet.js.map +1 -1
  238. package/dist/view.js +0 -414
  239. package/dist/view.js.map +1 -1
  240. package/dist/walk.js +0 -41
  241. package/dist/walk.js.map +1 -1
  242. package/grammar/aontu.abnf +8 -6
  243. package/grammar/aontu.gbnf +4 -4
  244. package/grammar/aontu.lark +4 -4
  245. package/grammar/aontu.tmLanguage.json +1 -1
  246. package/package.json +4 -2
  247. package/skill/tasks.md +9 -7
  248. package/src/agentsmd.ts +0 -35
  249. package/src/alias.ts +0 -39
  250. package/src/allow.ts +1 -96
  251. package/src/aontu.ts +4 -116
  252. package/src/aontumodel.ts +26 -0
  253. package/src/casing.ts +95 -0
  254. package/src/cli.ts +258 -1024
  255. package/src/ctx.ts +0 -103
  256. package/src/diff.ts +0 -40
  257. package/src/err.ts +0 -40
  258. package/src/escape.ts +0 -46
  259. package/src/exactjson.ts +0 -131
  260. package/src/format.ts +14 -257
  261. package/src/grammar.ts +72 -0
  262. package/src/graph.ts +0 -61
  263. package/src/hcanon.ts +0 -82
  264. package/src/helpdoc.ts +2 -2
  265. package/src/hints.ts +69 -57
  266. package/src/jsonschema.ts +0 -123
  267. package/src/keyorder.ts +0 -42
  268. package/src/lang.ts +19 -931
  269. package/src/lsp-server.ts +0 -16
  270. package/src/lsp.ts +12 -180
  271. package/src/mcp-server.ts +0 -31
  272. package/src/mcp.ts +0 -169
  273. package/src/mod-tool.ts +18 -159
  274. package/src/mod.ts +0 -178
  275. package/src/patch.ts +0 -232
  276. package/src/profile.ts +42 -0
  277. package/src/provenance.ts +0 -183
  278. package/src/query.ts +0 -84
  279. package/src/reach.ts +0 -53
  280. package/src/relation.ts +0 -84
  281. package/src/report-sarif.ts +0 -48
  282. package/src/sig.ts +0 -35
  283. package/src/sigdecl.ts +1 -1
  284. package/src/siggate.ts +0 -30
  285. package/src/site.ts +3 -29
  286. package/src/subsume.ts +1 -161
  287. package/src/template.ts +69 -140
  288. package/src/trace.ts +157 -0
  289. package/src/trim.ts +0 -53
  290. package/src/type.ts +2 -45
  291. package/src/unify.ts +14 -257
  292. package/src/utility.ts +0 -31
  293. package/src/val/AbnfFuncVal.ts +181 -0
  294. package/src/val/AbsentVal.ts +54 -0
  295. package/src/val/AggFuncVal.ts +152 -188
  296. package/src/val/ArithFuncVal.ts +0 -20
  297. package/src/val/BagVal.ts +1 -78
  298. package/src/val/BigDecimalVal.ts +0 -16
  299. package/src/val/BigIntegerVal.ts +0 -16
  300. package/src/val/CloseFuncVal.ts +0 -9
  301. package/src/val/CmpFuncVal.ts +68 -184
  302. package/src/val/ConjunctVal.ts +0 -33
  303. package/src/val/ConstraintVal.ts +2 -537
  304. package/src/val/ContainerKindVal.ts +0 -18
  305. package/src/val/CopyFuncVal.ts +0 -5
  306. package/src/val/Decimal.ts +1 -185
  307. package/src/val/DeprecateFuncVal.ts +0 -10
  308. package/src/val/DisjunctVal.ts +0 -157
  309. package/src/val/EachFuncVal.ts +0 -40
  310. package/src/val/EmitFuncVal.ts +8 -208
  311. package/src/val/ExpectVal.ts +0 -62
  312. package/src/val/FilterFuncVal.ts +0 -55
  313. package/src/val/FuncBaseVal.ts +9 -130
  314. package/src/val/GraphAtomVal.ts +0 -42
  315. package/src/val/HideFuncVal.ts +0 -15
  316. package/src/val/IntegerVal.ts +0 -61
  317. package/src/val/JunctionVal.ts +0 -20
  318. package/src/val/KeyFuncVal.ts +0 -48
  319. package/src/val/ListVal.ts +0 -59
  320. package/src/val/LowerFuncVal.ts +0 -12
  321. package/src/val/MapVal.ts +0 -151
  322. package/src/val/MatchFuncVal.ts +0 -59
  323. package/src/val/MaybeFuncVal.ts +86 -0
  324. package/src/val/MoveFuncVal.ts +0 -20
  325. package/src/val/NilVal.ts +0 -60
  326. package/src/val/NomFuncVal.ts +10 -99
  327. package/src/val/NumberVal.ts +0 -16
  328. package/src/val/OpBaseVal.ts +4 -17
  329. package/src/val/PackFuncVal.ts +0 -63
  330. package/src/val/PathFuncVal.ts +0 -32
  331. package/src/val/PathVal.ts +0 -66
  332. package/src/val/PlaceVal.ts +0 -45
  333. package/src/val/PlusOpVal.ts +18 -75
  334. package/src/val/PrefFuncVal.ts +0 -1
  335. package/src/val/PrefVal.ts +0 -179
  336. package/src/val/RecurseVal.ts +0 -81
  337. package/src/val/RefVal.ts +1 -285
  338. package/src/val/ReferFuncVal.ts +4 -255
  339. package/src/val/ScalarKindVal.ts +0 -50
  340. package/src/val/ScalarVal.ts +0 -12
  341. package/src/val/StrFuncVal.ts +0 -44
  342. package/src/val/SuperFuncVal.ts +0 -42
  343. package/src/val/TopVal.ts +0 -1
  344. package/src/val/TranslateFuncVal.ts +1 -51
  345. package/src/val/UpperFuncVal.ts +0 -12
  346. package/src/val/Val.ts +3 -192
  347. package/src/val/VarVal.ts +0 -15
  348. package/src/val/arith.ts +0 -92
  349. package/src/val/caserange.ts +0 -62
  350. package/src/val/members.ts +0 -23
  351. package/src/val/numcmp.ts +1 -27
  352. package/src/val/numkind.ts +0 -149
  353. package/src/val/valutil.ts +0 -16
  354. package/src/vet.ts +1 -582
  355. package/src/view.ts +0 -507
  356. package/src/walk.ts +0 -41
  357. package/dist/lower.d.ts +0 -23
  358. package/dist/lower.js +0 -578
  359. package/dist/lower.js.map +0 -1
  360. package/dist/render.d.ts +0 -53
  361. package/dist/render.js +0 -547
  362. package/dist/render.js.map +0 -1
  363. package/dist/std.d.ts +0 -3
  364. package/dist/std.js +0 -672
  365. package/dist/std.js.map +0 -1
  366. package/dist/val/FormFuncVal.js +0 -55
  367. package/dist/val/FormFuncVal.js.map +0 -1
  368. package/dist/val/NamerFuncVal.d.ts +0 -12
  369. package/dist/val/NamerFuncVal.js +0 -176
  370. package/dist/val/NamerFuncVal.js.map +0 -1
  371. package/src/lower.ts +0 -636
  372. package/src/render.ts +0 -732
  373. package/src/std.ts +0 -683
@@ -15,17 +15,6 @@ import { arith } from './arith'
15
15
  import type { ArithOp } from './arith'
16
16
 
17
17
 
18
- // ONE CLASS FOR SIX FUNCTIONS, because every rule they obey is a rule
19
- // about arithmetic rather than about any one operation (see arith.ts).
20
- // Six near-identical classes would be six places for the exact ladder,
21
- // the zero divisor and the storage contract to drift apart, and the
22
- // number tower's whole point is that they cannot.
23
- //
24
- // The op is carried on the instance and answered by `funcname()`, which
25
- // is what canon renders and what an error names. The six one-line
26
- // subclasses below exist only because the parser's registry constructs
27
- // with `new funcval({peg: args})` and has nowhere to put a name; every
28
- // line of behaviour is here.
29
18
  class ArithFuncVal extends FuncBaseVal {
30
19
  isArithFunc = true
31
20
 
@@ -60,18 +49,9 @@ class ArithFuncVal extends FuncBaseVal {
60
49
  }
61
50
 
62
51
 
63
- // NO superior() OVERRIDE, deliberately. An arithmetic call could only
64
- // advertise a kind once both its operands were concrete scalars -- and
65
- // at that point it has RESOLVED, so what `super()` sees is the result,
66
- // whose own superior is already the right answer:
67
- // `super(mul(2,3))` is `integer` and `super(mul(2,1.5))` is `float`,
68
- // through the value rather than through a promise about it. The
69
- // override was written and then removed as unreachable; the same is
70
- // true of FuncVal.superior in the Go port.
71
52
  }
72
53
 
73
54
 
74
- // The six the registry names. Each is its operation and nothing else.
75
55
  class AddFuncVal extends ArithFuncVal {
76
56
  constructor(spec: ValSpec, ctx?: AontuContext) { super(spec, ctx, 'add') }
77
57
  }
package/src/val/BagVal.ts CHANGED
@@ -30,15 +30,6 @@ abstract class BagVal extends FeatureVal {
30
30
  closed: boolean = false
31
31
  optionalKeys: string[] = []
32
32
 
33
- // ALIAS DECLARATIONS, by key. `%uint8 = …` binds a name for this file
34
- // and is not a field of the document: it does not generate and does
35
- // not appear in canon, so a document using aliases and its expanded
36
- // twin are the SAME document and hash identically
37
- // (docs/design/ALIASES.0.md §4).
38
- //
39
- // Keyed on the map rather than marked on the value, because a
40
- // reference copies the value it resolves to -- a mark riding the
41
- // value would erase the referring field along with the declaration.
42
33
  aliasKeys: string[] = []
43
34
 
44
35
  spread = {
@@ -60,30 +51,9 @@ abstract class BagVal extends FeatureVal {
60
51
 
61
52
 
62
53
  handleExpectedVal(key: string, val: Val, parent: Val, ctx: AontuContext): Val {
63
- // A MARKED value is carried, never expected (ADR-005 era, BUGS.md
64
- // §12's include form): a type()/hide()-marked child legitimately
65
- // participates in unification without ever generating — that is
66
- // the marks contract — so wrapping one as an expectation turned a
67
- // schema field arriving through an include's map meet into a
68
- // bogus `mapval_spread_required` naming a spread that exists in
69
- // neither file. The bag's gen already skips marked children.
70
- //
71
- // An OPERATOR is carried too (BUGS.md §36): an expression is a
72
- // computation that resolves by itself once its operands do — the
73
- // bag's own-key loop drives it every pass — so `m:{y:.x+1}`
74
- // arriving as a peer key must keep computing exactly as it does
75
- // written inline. Wrapping it froze the op (an expectation only
76
- // advances when a peer arrives) and the residue then reported the
77
- // phantom `mapval_spread_required` naming a spread that exists
78
- // nowhere. An op that truly never resolves is honest *_no_gen
79
- // residue naming the expression itself.
80
54
  if (val.isGenable || val.isOp || val.mark.type || val.mark.hide) {
81
55
  return val
82
56
  }
83
- // An expectation baked into a combined spread template (the
84
- // 'map-self' meet of two unequal templates) is re-wrapped FRESH, so
85
- // key/parent name THIS bag and the template's own node is never
86
- // stored at a destination.
87
57
  const expectVal = new ExpectVal({ peg: val.isExpect ? val.peg : val }, ctx)
88
58
  expectVal.key = key
89
59
  expectVal.parent = parent
@@ -91,20 +61,6 @@ abstract class BagVal extends FeatureVal {
91
61
  }
92
62
 
93
63
 
94
- // TWO BAGS ARE THE SAME VALUE WHEN THEY HAVE THE SAME SHAPE. Val.same
95
- // falls back to object IDENTITY, which no two separately built maps
96
- // share -- so `x:*{a:1}|{a:number}` met by `x:{a:2}` left
97
- // `{"a":2}|{"a":2}`, a disjunction of one value spelled twice, past
98
- // the DisjunctVal dedup. Generation's old member FOLD hid that
99
- // (folding a value with itself is that value); ADR-007 does not, and
100
- // a disjunction whose alternatives are all the SAME value is
101
- // resolved, not ambiguous. Canon prints the collapse too, which is
102
- // the more honest text.
103
- //
104
- // Structural, and deliberately strict: container kind, closedness,
105
- // the marks, the optional keys and the key set must all agree before
106
- // the children are compared pairwise. Recursion terminates because a
107
- // reference is not a bag -- RefVal keeps the identity comparison.
108
64
  same(peer: any): boolean {
109
65
  if (this === peer) {
110
66
  return true
@@ -118,11 +74,6 @@ abstract class BagVal extends FeatureVal {
118
74
  this.mark.hide !== peer.mark.hide) {
119
75
  return false
120
76
  }
121
- // The SPREAD is part of the shape (BUGS.md §52 regime 4): `[]`
122
- // and `[&: T]` share an empty key set, and calling them the same
123
- // value collapsed the disjunction to its first arm before any
124
- // data could pick -- the vacuous-schema hole. Two spreads are the
125
- // same when their canons are.
126
77
  const scj: any = (this as any).spread?.cj
127
78
  const pcj: any = peer.spread?.cj
128
79
  if ((null == scj) !== (null == pcj) ||
@@ -158,12 +109,6 @@ abstract class BagVal extends FeatureVal {
158
109
  return undefined
159
110
  }
160
111
 
161
- // Maps emit their keys in CODE POINT order so the generated output
162
- // is independent of insertion/unification order and matches the Go
163
- // port. Lists keep their numeric index order.
164
- //
165
- // The keys are String()-coerced because a list entry carries a
166
- // numeric index here; the coercion is a no-op for every map key.
167
112
  let entries = items(this.peg)
168
113
  if (this.isMap) {
169
114
  entries = entries
@@ -214,22 +159,7 @@ abstract class BagVal extends FeatureVal {
214
159
  put(cval)
215
160
  }
216
161
 
217
- // A CONJUNCT IS GENERABLE WHEN IT IS A SETTLED SIZING RESIDUE
218
- // (the review's finding C, use-cases/BUGS.md §16). `length` and
219
- // `unique` over a container keep the readings more members could
220
- // still change, so `a: length(3) a:[1,2,3]` is a conjunct of the
221
- // atom and the list right up to generation -- which is where the
222
- // atom decides, in ConjunctVal.gen. Any OTHER conjunct is
223
- // unresolved and falls through to the residue error below,
224
- // exactly as before.
225
162
  else if (bagGenable(child)) {
226
- // An optional child is generated in an isolated collect context so an
227
- // unresolved inner value (a bare type that survived unification, e.g.
228
- // an absent optional sub-map's `field: string`) is dropped rather than
229
- // raised: the optional subtree is simply omitted. Without isolation
230
- // such inner errors pollute the shared ctx.err and make generate()
231
- // throw even though the key is skipped below. Mirrors the
232
- // optional-disjunct path above.
233
163
  const cctx = optional ? ctx.clone({ err: [], collect: true }) : ctx
234
164
 
235
165
  let cval = child.gen(cctx)
@@ -273,7 +203,6 @@ abstract class BagVal extends FeatureVal {
273
203
  break
274
204
  }
275
205
 
276
- // else optional so we can ignore it
277
206
  }
278
207
 
279
208
  return out
@@ -304,13 +233,6 @@ export function sizingResidue(v: any): { con: any, bag: any } | undefined {
304
233
  { con, bag } : undefined
305
234
  }
306
235
 
307
- // bagGenable is the bag's generability whitelist. A graph atom
308
- // (RELATIONS P2) is exactly as generable as the value it carries: the
309
- // atom is transparent at generation, so wrapping a field's value in
310
- // acyclic() must not change whether the bag accepts it -- an unmet
311
- // rel() refuses required generation with or without the atom, and a
312
- // BARE atom generates nothing and is dropped, exactly as an unmet
313
- // rel() under an optional key is.
314
236
  export function bagGenable(child: any): boolean {
315
237
  if (true === child.isGraphAtom) {
316
238
  return undefined === child.held || bagGenable(child.held)
@@ -322,6 +244,7 @@ export function bagGenable(child: any): boolean {
322
244
  return true
323
245
  }
324
246
  return true === child.isScalar
247
+ || true === child.isAbsent
325
248
  || true === child.isMap
326
249
  || true === child.isList
327
250
  || true === child.isPref
@@ -22,15 +22,6 @@ import {
22
22
  } from '../utility'
23
23
 
24
24
 
25
- // The exact base-10 decimal leaf of the number tower, reached only by a
26
- // `0d` literal carrying a `.` or an exponent (`0d1.5`, `0d1e3`) or by
27
- // direct construction.
28
- //
29
- // Its peg is a Decimal -- an OBJECT, so unlike every other scalar leaf
30
- // its identity cannot be `===` on the peg. Two bigdecimals are the same
31
- // value when their NUMBERS are equal (D2), which normalisation at
32
- // construction reduces to a two-field comparison; `samePeg` and `unify`
33
- // below are the two places that must not forget it.
34
25
  class BigDecimalVal extends ScalarVal {
35
26
  isBigDecimal = true
36
27
 
@@ -40,10 +31,6 @@ class BigDecimalVal extends ScalarVal {
40
31
  spec: ValSpec,
41
32
  ctx?: AontuContext
42
33
  ) {
43
- // Exact-input construction (D8): a Decimal, or a decimal literal as
44
- // text (`'1.5'`, `'0d1e3'`). A JS `number` is deliberately NOT
45
- // accepted -- binary64 has already rounded it, so `0.1` could never
46
- // arrive exact.
47
34
  let peg = spec.peg
48
35
  if ('string' === typeof peg) {
49
36
  try {
@@ -78,9 +65,6 @@ class BigDecimalVal extends ScalarVal {
78
65
  peer.kind === this.kind &&
79
66
  this.peg.equals(peer.peg)
80
67
  ) {
81
- // Same kind and equal NUMBER. Never `peer.peg === this.peg`:
82
- // that is object identity, and `0d0.10 & 0d0.1` (two Decimals
83
- // holding one value) has to succeed.
84
68
  out = this
85
69
  }
86
70
  else if (peer.isTop) {
@@ -21,18 +21,6 @@ import {
21
21
  } from '../utility'
22
22
 
23
23
 
24
- // The unbounded exact integer leaf of the number tower, reached only by
25
- // a `0d` literal with no fraction and no exponent (`0d5`, `-0d5`,
26
- // `0d123456789012345678901234567890`) or by direct construction.
27
- //
28
- // Its peg is a native bigint: exact at any magnitude, immutable, and
29
- // compared by VALUE with `===` (D2 -- two separately built bigints
30
- // holding the same number are `===`, which is exactly the property the
31
- // Go port has to reproduce by hand for `*big.Int`).
32
- //
33
- // `biginteger` is DISJOINT from `integer`: `5 & 0d5` is an error, since
34
- // a successful meet would have to pick one of the two kinds and either
35
- // choice makes `&` asymmetric in kind.
36
24
  class BigIntegerVal extends ScalarVal {
37
25
  isBigInteger = true
38
26
 
@@ -42,10 +30,6 @@ class BigIntegerVal extends ScalarVal {
42
30
  spec: ValSpec,
43
31
  ctx?: AontuContext
44
32
  ) {
45
- // Exact-input construction (D8): a bigint, or the digits as text. A
46
- // JS `number` is deliberately NOT accepted -- it has already been
47
- // rounded before this library could inspect it, so an exact value
48
- // above 2^53 could never arrive that way intact.
49
33
  let peg = spec.peg
50
34
  if ('string' === typeof peg) {
51
35
  if (!/^[-+]?[0-9]+$/.test(peg)) {
@@ -46,16 +46,7 @@ class CloseFuncVal extends FuncBaseVal {
46
46
  }
47
47
 
48
48
  if (argval.isMap || argval.isList) {
49
- // The in-place write is safe BECAUSE of the per-destination
50
- // instantiation rule (ADR-005): everywhere a close() call is
51
- // multiplied — a pack/each template, a spread constraint — the
52
- // clone now owns its argument (`dup`), so `closed` lands on that
53
- // instance alone. Cloning the bag here instead was tried and
54
- // rejected: the re-path it implies corrupts the source
55
- // attribution of children inside nested spread templates (the
56
- // 06-k8s use case's env findings named the wrong path).
57
49
  (argval as BagVal).closed = true
58
- // console.log('CLOSED', argval.canon)
59
50
  }
60
51
 
61
52
  return argval
@@ -1,97 +1,5 @@
1
1
  /* Copyright (c) 2026 Richard Rodger, MIT License */
2
2
 
3
- // THE COMPONENT PRIMITIVES -- SPIKE (docs/design/JOSTRACA.0.md).
4
- //
5
- // `Folder`, `File` and `Content` are the first three of jostraca's
6
- // component set, spelled as aontu functions and keeping jostraca's
7
- // own capitalisation. They are the authoring surface an aontu
8
- // document uses to say what FILES it produces:
9
- //
10
- // out: folder("src", [
11
- // file("main.ts", [
12
- // content("export const x = 1")
13
- // ])
14
- // ])
15
- //
16
- // WHAT THIS REPLACES. `aontu:code` (ts/src/std.ts, test/spec/
17
- // aontu-code.tsv) is a hand-written vocabulary an author fills in as
18
- // DATA -- `aontu: Code: units: [{path, lang, decls}]` -- and `aontu
19
- // render` folds that instance into bytes. The instance is checked by
20
- // unification against the vocabulary, which is the good half; the bad
21
- // half is that an author writes a schema instance rather than a
22
- // generator, the vocabulary owns every construct the renderer will
23
- // ever emit, and nothing in it corresponds to a component someone can
24
- // already write in jostraca. These primitives take the other road:
25
- // the CALL is the construct, the call's own resolve is where the
26
- // shape is refused, and the value it lands is a jostraca component
27
- // tree that jostraca's build phase already knows how to walk.
28
- //
29
- // THE VALUE IS AN ORDINARY MAP, which is the whole reason this can be
30
- // a spike at all. A component call resolves to
31
- //
32
- // {cmp: "Folder", props: {name: "src"}, children: [...]}
33
- //
34
- // so nothing downstream needs new machinery: `generate()` emits the
35
- // tree as JSON, `canon` renders the calls back, references and
36
- // spreads reach into a tree as they reach into any map, and `each()`
37
- // over model data drops straight into a `children` list -- which is
38
- // the point, and is why the second argument must BE a list rather
39
- // than accepting a bare node as a convenience. `each($.fields,
40
- // content(...))` is already the list; a one-child special case would
41
- // make `file(n, each(...))` and `file(n, [each(...)])` both legal and
42
- // different.
43
- //
44
- // CHILDREN FLATTEN, for the same reason. A generator's output lands
45
- // in the MIDDLE of a written list --
46
- //
47
- // file("planet.ts", [
48
- // content("export interface Planet {"),
49
- // each($.fields, content(" " + _ + ": string")),
50
- // content("}")
51
- // ])
52
- //
53
- // -- and that list therefore holds two nodes and a LIST OF NODES. A
54
- // list is not a node and could only be an error otherwise, so
55
- // splicing is the total rule and nesting is not: children are
56
- // flattened to any depth before the containment grammar is checked.
57
- // This is the finding the spike's worked example produced; every
58
- // component system that takes children arrives at it.
59
- //
60
- // THE NODE MAP IS CLOSED and its `props` map is not. The three keys
61
- // are the vocabulary and a fourth is a mistake, so a typo in
62
- // `folder(...) & {childrn: []}` is refused where every other mistake
63
- // in an aontu document is refused. Props are the COMPONENT's business
64
- // -- jostraca's File already reads `mode` and `exclude`, and a
65
- // component the spike does not implement will read its own -- so they
66
- // pass through, and only the one prop each primitive cannot work
67
- // without is checked here.
68
- //
69
- // THE CONTAINMENT GRAMMAR IS CHECKED AT THE CALL. A Folder holds
70
- // folders and files, a File holds content, and Content holds nothing.
71
- // Unification cannot state that on its own -- a node is a map, and
72
- // every node map unifies with every other -- so the constructor
73
- // states it, at the site the author wrote, which is the argument for
74
- // making these functions rather than another vocabulary.
75
- //
76
- // NOT STAGED, deliberately. A component call answers from its
77
- // arguments alone: it has no dependence on WHERE it sits (unlike
78
- // `key()`) and it reads no bag that a sibling may still merge into
79
- // (unlike `pack`/`each`). A children list BUILT by one of
80
- // those combinators still waits, because the combinator residuates
81
- // and the enclosing call is not `pegdone` until it fires -- so the
82
- // ordinary args-done gate is the correct one and the staging rule
83
- // costs nothing here.
84
- //
85
- // SPIKE SCOPE. TypeScript only; no Go port yet, and so:
86
- // deliberately absent from `test/spec/signature.tsv`, from
87
- // `BUILTIN_FUNCS` (ts/src/lsp.ts) and from the `grammar/` files, all
88
- // three of which are pinned in cross-port parity and would go red on
89
- // a TS-only change. Argument arity and shape are therefore refused
90
- // HERE rather than by the parse-time arity table or the signature
91
- // gate, both of which read the declaration this spike does not have.
92
- // Failures are `invalid-arg` for the same reason -- a new code needs
93
- // a row in test/spec/errcodes.tsv and an entry in BOTH ports' code
94
- // tables (AGENTS.md, "The shared test suite").
95
3
 
96
4
  import type {
97
5
  Val,
@@ -110,110 +18,88 @@ import { StringVal } from './StringVal'
110
18
  import { FuncBaseVal } from './FuncBaseVal'
111
19
 
112
20
 
113
- // The component names this spike serves, each with the children it
114
- // admits and the one prop it cannot work without. Adding a fourth
115
- // primitive is an entry here plus the two-line subclass below.
116
21
  type CmpDef = {
117
- // The jostraca component this call builds. CAPITALISED, because it
118
- // names a component in the other project's exported set and the
119
- // bridge looks it up by that name -- while the aontu FUNCTION is
120
- // lower case, like every other builtin in this language. The two
121
- // spellings say what they are: `file(...)` is aontu, `"File"` is
122
- // jostraca's.
123
22
  cmp: string
124
23
  // The children this component admits, by aontu function name. Empty
125
24
  // means a leaf: any child at all is a mistake.
126
25
  children: string[]
127
- // The prop a bare string argument fills. ABSENT means the component
128
- // has no one-string spelling and its spec must be a map: `listitems`
129
- // is driven by a LIST, and there is no sensible string to promote.
130
26
  text?: string
131
27
  // Whether that prop is required. `project`'s folder is the one that
132
- // is not: jostraca defaults it to `.`, and the data path must not be
133
- // stricter than the component it drives.
28
+ // is not: Jostraca defaults it to `.`.
134
29
  req: boolean
30
+ // Whether that prop is a SPAN of target text rather than a name. A
31
+ // blank line is a span; a folder called "" is a mistake.
32
+ span?: boolean
135
33
  // A prop that must be present and must be a list.
136
34
  bag?: string
35
+ // Hand-kept: no jostraca dependency to derive it from.
36
+ props: string[]
137
37
  }
138
38
 
139
- // EIGHT OF JOSTRACA'S TEN COMPONENTS. `Copy` and `List` are missing and
140
- // cannot be added under these rules: `copy` and `list` are already
141
- // aontu builtins with settled, unrelated meanings -- `copy(v)` copies a
142
- // VALUE and `list()` is the list container kind, both declared in
143
- // test/spec/signature.tsv and implemented in both ports. Lower-casing
144
- // jostraca's names onto them would either shadow landed language
145
- // surface or make one name mean two things by arity, and neither is a
146
- // trade a spike gets to make. See docs/design/JOSTRACA.0.md.
39
+
40
+ const SPAN_PROPS =
41
+ ['arg', 'src', 'name', 'indent', 'extra', 'replace', 'raw']
42
+
147
43
  const CMP_DEF: Record<string, CmpDef> = {
148
44
  // The output root. Its `folder` is refused an absolute path or a
149
- // `..` segment on the jostraca side, where the tree is data.
45
+ // `..` segment on the Jostraca side, where the tree is data.
150
46
  project: {
151
47
  cmp: 'Project', text: 'folder', req: false,
152
48
  children: ['project', 'folder', 'file', 'copyfiles'],
49
+ props: ['name', 'folder'],
153
50
  },
154
51
  folder: {
155
52
  cmp: 'Folder', text: 'name', req: true,
156
53
  children: ['folder', 'file', 'copyfiles'],
54
+ props: ['name'],
157
55
  },
158
56
  file: {
159
57
  cmp: 'File', text: 'name', req: true,
160
58
  children: ['content', 'line', 'fragment', 'inject', 'listitems', 'copyfiles'],
59
+ props: ['name', 'exclude', 'mode'],
161
60
  },
162
- // A span of text, exactly as written. `FileOp` joins a file's spans
163
- // with the empty string, so a `content` carries its own terminator.
164
61
  content: {
165
- cmp: 'Content', text: 'src', req: true,
62
+ cmp: 'Content', text: 'src', req: true, span: true,
166
63
  children: [],
64
+ props: SPAN_PROPS,
167
65
  },
168
66
  // A span with a newline added, which is the whole difference.
169
67
  line: {
170
- cmp: 'Line', text: 'src', req: true,
68
+ cmp: 'Line', text: 'src', req: true, span: true,
171
69
  children: [],
70
+ props: SPAN_PROPS,
172
71
  },
173
72
  // A file read from disk with its `<[SLOT]>` markers filled.
174
73
  fragment: {
175
74
  cmp: 'Fragment', text: 'from', req: true,
176
75
  children: ['slot', 'content', 'line', 'listitems'],
76
+ props: ['from', 'indent', 'replace', 'eject'],
177
77
  },
178
78
  slot: {
179
79
  cmp: 'Slot', text: 'name', req: true,
180
80
  children: ['content', 'line', 'fragment', 'listitems'],
81
+ props: ['name'],
181
82
  },
182
83
  // A body written between markers in a file that already exists.
183
84
  inject: {
184
85
  cmp: 'Inject', text: 'name', req: true,
185
86
  children: ['content', 'line', 'listitems'],
87
+ props: ['name', 'markers', 'exclude'],
186
88
  },
187
89
  // `Copy` under a name aontu has free: `copy` is taken by the builtin
188
90
  // that copies a VALUE, and a file copy is a different verb.
189
91
  copyfiles: {
190
92
  cmp: 'CopyFiles', text: 'from', req: true,
191
93
  children: [],
94
+ props: ['from', 'to', 'replace', 'exclude'],
192
95
  },
193
- // `List` under a name that says what it does: it renders its children
194
- // ONCE PER ELEMENT of `item`, binding jostraca's `{item}` and
195
- // `{item.path}` macros, and adds a trailing blank line unless
196
- // `line: false`.
197
- //
198
- // IT IS THE ONE COMPONENT THE AONTU SIDE ALREADY SUBSUMES, and a
199
- // generator should reach for `each()` first. `each($.rows, content(...))`
200
- // repeats in the MODEL, so the repetition is finished before the tree
201
- // exists and every produced node is data a document can reference,
202
- // vet and diff. `listitems` defers it into jostraca's define phase behind
203
- // a string macro aontu cannot see into -- which is the layer this
204
- // spike exists to remove. It is here so the component set is
205
- // complete, not because it is the better spelling.
206
96
  listitems: {
207
97
  cmp: 'ListItems', req: true, bag: 'item',
208
98
  children: ['content', 'line', 'fragment'],
99
+ props: ['item', 'line', 'indent'],
209
100
  },
210
101
  }
211
102
 
212
- // The component name a value carries, when the value is a node this
213
- // vocabulary built. Read structurally rather than by class, because a
214
- // node reaches a children list as a MAP -- through a reference, a
215
- // `each()` instance, a spread -- long after the call that made it has
216
- // resolved away.
217
103
  const BY_CMP: Record<string, string> = {}
218
104
  for (const fname of Object.keys(CMP_DEF)) {
219
105
  BY_CMP[CMP_DEF[fname].cmp] = fname
@@ -232,7 +118,29 @@ function nodeCmp(v: any): string | undefined {
232
118
  }
233
119
 
234
120
 
235
- // A prop's text, when the prop is a concrete string.
121
+ function cmpNode(cmp: string, props: Val, children: Val,
122
+ ctx: AontuContext): MapVal {
123
+ const node = new MapVal({ peg: { cmp: new StringVal({ peg: cmp }, ctx), props, children } }, ctx)
124
+ node.closed = true
125
+ return node
126
+ }
127
+
128
+
129
+ // A bare string child is a LINE: `Content` writes no newline, and the
130
+ // emit mark rides across or `aontu trace` loses the line's rule.
131
+ function lineNode(from: any, src: string, ctx: AontuContext): MapVal {
132
+ const node = cmpNode(
133
+ CMP_DEF.line.cmp,
134
+ new MapVal({ peg: { src: new StringVal({ peg: src }, ctx) } }, ctx),
135
+ new ListVal({ peg: [] }, ctx),
136
+ ctx)
137
+ if (null != from?.emitted) {
138
+ ; (node as any).emitted = from.emitted
139
+ }
140
+ return node
141
+ }
142
+
143
+
236
144
  function propText(props: any, key: string): string | undefined {
237
145
  const v: any = props?.peg?.[key]
238
146
  return (true === v?.isScalar && 'string' === typeof v.peg) ? v.peg : undefined
@@ -242,9 +150,7 @@ function propText(props: any, key: string): string | undefined {
242
150
  class CmpFuncVal extends FuncBaseVal {
243
151
  isCmpFunc = true
244
152
 
245
- // The component this call builds: the function's own name, which is
246
- // also the `cmp` key of the node and the jostraca component the
247
- // bridge looks up.
153
+ // The function's own name, which is also the node's `cmp` key.
248
154
  cmp: string
249
155
 
250
156
  constructor(
@@ -264,24 +170,8 @@ class CmpFuncVal extends FuncBaseVal {
264
170
 
265
171
  resolve(ctx: AontuContext, args: Val[]): Val {
266
172
  const def: CmpDef = CMP_DEF[this.cmp]
267
- const leaf = 0 === def.children.length
268
-
269
- // ARITY, refused here (see the spike-scope note above): a leaf
270
- // takes its spec alone, a container takes a spec and an optional
271
- // children list.
272
- // A component whose text prop is OPTIONAL may be called with
273
- // nothing at all: `project()` is the defaulted root, as
274
- // `project({})` is on the other side. Everything else needs its
275
- // spec.
276
- if (args.length < (def.req ? 1 : 0) || args.length > (leaf ? 1 : 2)) {
277
- return makeNilErr(ctx, 'invalid-arg', this, undefined, 'arity')
278
- }
279
173
 
280
- // THE SPEC IS A STRING OR A PROPS MAP. The string spelling fills
281
- // the one prop the component cannot work without, so the common
282
- // case reads as the component does -- `file("main.ts", ...)` --
283
- // and the map spelling is there the moment a second prop is
284
- // wanted: `file({name: "run.sh", mode: 0o755}, ...)`.
174
+ // Arity is checked at parse (funcArity); args[0] can be undefined.
285
175
  const spec: any = args[0]
286
176
  let props: Val
287
177
  if (undefined === spec) {
@@ -300,15 +190,21 @@ class CmpFuncVal extends FuncBaseVal {
300
190
  return makeNilErr(ctx, 'invalid-arg', this, spec, 'spec')
301
191
  }
302
192
 
303
- // The one prop that is not the component's own business: without
304
- // it there is no file to write and no content to write into one.
193
+ // An unknown prop is a silently dropped `indent` or `mode`.
194
+ for (const key of Object.keys((props as any).peg)) {
195
+ if (!def.props.includes(key)) {
196
+ return makeNilErr(ctx, 'invalid-arg', this, props, key)
197
+ }
198
+ }
199
+
305
200
  if (undefined !== def.text) {
306
201
  const text = propText(props, def.text)
307
- if (def.req && (undefined === text || '' === text)) {
202
+ if (def.req &&
203
+ (undefined === text || ('' === text && true !== def.span))) {
308
204
  return makeNilErr(ctx, 'invalid-arg', this, props, def.text)
309
205
  }
310
206
  if (!def.req && undefined !== (props as any).peg?.[def.text] &&
311
- undefined === text) {
207
+ (undefined === text || ('' === text && true !== def.span))) {
312
208
  return makeNilErr(ctx, 'invalid-arg', this, props, def.text)
313
209
  }
314
210
  }
@@ -323,10 +219,6 @@ class CmpFuncVal extends FuncBaseVal {
323
219
  }
324
220
  }
325
221
 
326
- // THE CHILDREN, flattened, then the containment grammar. Absent
327
- // is empty -- an empty folder and a file with no content are both
328
- // things a model may legitimately say -- and every node that
329
- // survives the flattening must be one this component admits.
330
222
  const kids: any = args[1]
331
223
  let children: Val
332
224
  if (undefined === kids) {
@@ -343,6 +235,15 @@ class CmpFuncVal extends FuncBaseVal {
343
235
  }
344
236
  continue
345
237
  }
238
+ const text = (true === (kid as any)?.isScalar &&
239
+ 'string' === typeof (kid as any).peg) ? (kid as any).peg : undefined
240
+ if (undefined !== text) {
241
+ if (!def.children.includes('line')) {
242
+ return kid
243
+ }
244
+ flat.push(lineNode(kid, text, ctx))
245
+ continue
246
+ }
346
247
  const kcmp = nodeCmp(kid)
347
248
  if (undefined === kcmp || !def.children.includes(kcmp)) {
348
249
  return kid
@@ -361,29 +262,12 @@ class CmpFuncVal extends FuncBaseVal {
361
262
  return makeNilErr(ctx, 'invalid-arg', this, kids, 'children')
362
263
  }
363
264
 
364
- const node = new MapVal({
365
- peg: {
366
- cmp: new StringVal({ peg: def.cmp }, ctx),
367
- props,
368
- children,
369
- }
370
- }, ctx)
371
-
372
- // Closed: the three keys ARE the node vocabulary (see the note
373
- // above). `props` is left open on purpose.
374
- node.closed = true
375
-
376
- return this.place(node)
265
+ return this.place(cmpNode(def.cmp, props, children, ctx))
377
266
  }
378
267
 
379
268
  } /* node:coverage ignore next 3 */
380
269
 
381
270
 
382
- // ONE CLASS PER COMPONENT, generated from the table, because the
383
- // registry constructs by `new funcval({peg: args})` and so needs a
384
- // constructor per name. Written as a factory rather than eight
385
- // near-identical subclasses: the table is the single statement of what
386
- // exists, and a ninth component is a row in it and nothing else.
387
271
  function cmpFuncClass(fname: string): any {
388
272
  class Cmp extends CmpFuncVal {
389
273
  constructor(spec: ValSpec, ctx?: AontuContext) {