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
package/src/render.ts DELETED
@@ -1,732 +0,0 @@
1
- /* Copyright (c) 2025 Richard Rodger, MIT License */
2
-
3
-
4
- // THE RENDERER (docs/design/RENDER.0.md; docs/capability-review/
5
- // g9-transformation.md §3). `render` evaluates a document, takes the
6
- // value at `--at` (the root by default), vets it against the bundled
7
- // `aontu:code` vocabulary, and folds `code.units` into bytes;
8
- // `renderValue` is the fold alone, over `generate()` output. The fold
9
- // is pure and total: it never touches the Val tree, never reads or
10
- // writes a file, never sorts and never iterates a map, and every piece
11
- // of a fragment carries its own depth (`at`), so the renderer owns
12
- // every prefix and no piece nests another (the second amendment's
13
- // fragment algebra, RENDER.0.md D2 and D6).
14
- //
15
- // WHAT THIS PHASE RENDERS (RENDER.0.md P3): fragments -- a line, a
16
- // blank run, a raw block, a bare string piece, a reference inline --
17
- // and the `text` escape, under a profile that knows its language. The
18
- // one bundled profile is `aontu:lang/text`, which every fragment-only
19
- // unit falls back to; a declaration (`record`, `enum`, ...) needs a
20
- // LOWERING, which P5 brings with the TypeScript and Go profiles, and
21
- // until then is `render_profile`.
22
-
23
- import { Aontu } from './aontu'
24
- import { vet, failureFinding, anchorAt } from './vet'
25
- import type { VetFinding } from './vet'
26
- import { hcanon } from './hcanon'
27
- import { makeNilErr } from './err'
28
- import { cmpCodePoint } from './keyorder'
29
- import { includeOpts } from './utility'
30
- import type { IncludeOptions } from './utility'
31
- import { lowerDecl, lowerHeader, ident } from './lower'
32
- import type { LowerCtx } from './lower'
33
-
34
-
35
- export type RenderVerdict = 'ok' | 'lossy' | 'error'
36
-
37
- // One rendered unit: the path the instance gave it, its language, and
38
- // its bytes, as one string.
39
- export type RenderUnit = {
40
- path: string
41
- lang: string
42
- text: string
43
- }
44
-
45
- // THE THREE LOSS TIERS (RENDER.0.md D7). Tier 1 is a check the target's
46
- // type system cannot enforce (the declaration lowering's, P5); tier 2
47
- // a fragment -- structured, re-indentable, terminator-checked, saying
48
- // nothing about target syntax; tier 3 an opaque escape, a `text`
49
- // declaration or a `raw` piece. `strict` refuses tier 3 and only
50
- // tier 3.
51
- export type RenderLoss = {
52
- unit: string
53
- path: string
54
- tier: 1 | 2 | 3
55
- construct: string
56
- reason: string
57
- }
58
-
59
- // ONE PIECE'S PROVENANCE (RENDER.0.md D9, D11; P7). A dispatch stamps
60
- // every piece it emits with the node it matched and the rule it took,
61
- // and the fold reads the stamps back off the instance: `piece` is the
62
- // piece's own path there, `unit` the unit it landed in, `node` the
63
- // model address the rule matched, and `rule` the rule's address --
64
- // its table's, then `#`, then its index in that table.
65
- export type RenderTrace = {
66
- unit: string
67
- piece: string
68
- node: string
69
- rule: string
70
- }
71
-
72
- // THE COVERAGE REPORT (P7; G9 §6, "coverage cuts both ways"). Two
73
- // lists, and both are set computations over what the run recorded.
74
- export type RenderCoverage = {
75
- // Every model path a reference resolved to, in walk order: what the
76
- // render READ.
77
- read: string[]
78
- // Dead model: the SHALLOWEST model paths no read reached. A path
79
- // whose subtree holds a read is not named; its unread children are.
80
- dead: string[]
81
- // A silent hole: a rendered declaration no rule produced. In a
82
- // document with no rule table that is every declaration, which is
83
- // the true statement about it -- the rule layer governs none of this
84
- // output.
85
- unruled: { unit: string, path: string }[]
86
- }
87
-
88
- export type RenderReport = {
89
- verdict: RenderVerdict
90
- // In `units[]` order. Empty on `error`.
91
- units: RenderUnit[]
92
- // Per unit and path. Empty on `error`.
93
- lossy: RenderLoss[]
94
- // On `error` only, in vet's finding shape: the document did not
95
- // stand up, the instance is not `aontu:code`, or a unit could not be
96
- // rendered (`render_*`).
97
- errors?: VetFinding[]
98
- // The dispatch trace, under `trace` or `coverage` (P7), in document
99
- // order. Absent when it is empty, on `error`, and from
100
- // `renderValue`, which folds an instance the recorder never watched
101
- // being built.
102
- trace?: RenderTrace[]
103
- // The coverage report, under `coverage` (P7).
104
- coverage?: RenderCoverage
105
- }
106
-
107
- export type RenderOptions = IncludeOptions & {
108
- // The value to render, a path into the document. Absent means the
109
- // root.
110
- at?: string
111
- // Where the document CAME FROM, so a relative `@"file"` load inside
112
- // it resolves from its own directory.
113
- path?: string
114
- // Profiles supplied by the caller, each an evaluated profile map
115
- // (`{lang, indent, ...}`), matched to a unit by `lang` before the
116
- // bundled set is asked (RENDER.0.md D5, step 1).
117
- profiles?: any[]
118
- // Render only the unit at this path.
119
- unit?: string
120
- // Refuse tier-3 loss: the opaque escapes.
121
- strict?: boolean
122
- // RECORD THE DISPATCH TRACE (P7). Off by default: an instrumented
123
- // run stamps every value a reference resolves and every piece a rule
124
- // emits, and an ordinary one pays one property load per meet.
125
- trace?: boolean
126
- // Compute the coverage report, which needs the trace and turns it on.
127
- coverage?: boolean
128
- // Measure coverage under this path only, instead of the document
129
- // root (RENDER.0.md X-3). The narrower measure a document with its
130
- // model under one key wants.
131
- coverageAt?: string
132
- }
133
-
134
-
135
- const VOCABULARY = '@"aontu:code"'
136
- // The bundled profiles, by lang: aontu:lang/<lang>.
137
- const BUNDLED_LANGS = ['go', 'text', 'typescript']
138
- const PROFILE_VOCABULARY = '@"aontu:profile"'
139
-
140
-
141
- function finding(
142
- code: string, cls: string, path: string, message: string
143
- ): VetFinding {
144
- return { code, class: cls as any, severity: 'error', path, message, sites: [] }
145
- }
146
-
147
-
148
- function errorReport(errors: VetFinding[]): RenderReport {
149
- return { verdict: 'error', units: [], lossy: [], errors }
150
- }
151
-
152
-
153
- // The verb's evaluation, before the fold (RENDER.0.md D1): evaluate,
154
- // anchor, vet the anchored value against the vocabulary as `aontu vet`
155
- // would, and generate the MEET of the two -- so the vocabulary's
156
- // defaults (`at: 0`, `n: 1`, `reindent: true`) are in the instance the
157
- // fold reads, whether or not the document included the vocabulary
158
- // itself. THE VET AND THE MEET READ THE SETTLED VALUE, re-sourced
159
- // through its hash form (valid source that evaluates to the same
160
- // value), not the document's text: a fragment's lines are what a
161
- // transform COMPUTED -- an `emit`, a `join` -- and the vocabulary's
162
- // alternatives are tried against values, not against calls that are
163
- // still waiting to fire. A finding from that vet therefore addresses
164
- // the instance by path, which is the addressing every render finding
165
- // uses (G9 §3); a document that does not stand up at all is reported
166
- // with its own sites, before any of this.
167
- export function render(src: string, options?: RenderOptions): RenderReport {
168
- const opts = options ?? {}
169
- const aontu = new Aontu(includeOpts(opts))
170
-
171
- // THE RECORDER (P7), on for a run that was asked for a trace or a
172
- // coverage report and off for every other. Its presence is the one
173
- // switch: the read set fills as references resolve, and the two
174
- // riders that carry a read address and a dispatch stamp are written
175
- // only while it is there.
176
- const rec = true === opts.trace || true === opts.coverage
177
- const reads = rec ? new Set<string>() : undefined
178
-
179
- // COLLECT MODE, so a syntax error arrives on the context rather than
180
- // as a throw (the jsonschema and vet precedent; no try/catch, for
181
- // the reason those verbs have none).
182
- const actx = aontu.ctx({ collect: true, reads })
183
- const root: any = aontu.unify(src, { path: opts.path, collect: true }, actx)
184
- if (0 < actx.err.length || true === root?.isNil) {
185
- return errorReport([failureFinding(actx, opts.path, root)])
186
- }
187
-
188
- let node: any = root
189
- if (null != opts.at && '' !== opts.at) {
190
- const found: any = anchorAt(root, opts.at)
191
- if (null == found) {
192
- // The anchor names nothing: a `no_path` nil through the finding
193
- // shape every other refusal here uses.
194
- const nil: any = makeNilErr(actx, 'no_path', root, undefined, 'at')
195
- actx.err.push(nil)
196
- return errorReport([failureFinding(actx, opts.path, root)])
197
- }
198
- node = found
199
- }
200
-
201
- // UNDER NO CALLER CAPABILITY, here and in the meet below: the
202
- // vocabulary is the engine's own and the instance is a canon, which
203
- // includes nothing, so the caller's include capability -- which
204
- // governs the DOCUMENT -- has nothing to govern here, and `none`
205
- // must not deny the renderer its own schema.
206
- const value = hcanon(node)
207
- const report = vet(VOCABULARY, value)
208
- if ('valid' !== report.verdict) {
209
- return errorReport(report.findings)
210
- }
211
-
212
- // The meet, keyed: the vocabulary's root holds `aontu.Code`, and so
213
- // does the instance's (a value the vet admitted is a map), and a
214
- // document with no `code` at all is the vocabulary's own empty
215
- // instance. The key is namespaced (ADR-029), so the reach is two deep.
216
- const codeVal: any = node.peg.aontu?.peg?.Code
217
- const instance = new Aontu().generate(
218
- VOCABULARY + (undefined === codeVal ? '' : '\naontu: Code: ' + hcanon(codeVal)))
219
- const folded = renderValue(instance, opts)
220
-
221
- // THE TWO REPORTS ARE JOINED TO THE FOLD BY PATH (P7), which is what
222
- // lets the fold stay the pure total function D6 asks for: the
223
- // dispatch stamps ride the VALUE, the instance the fold reads is
224
- // that value re-sourced through its hash form, and a piece is at the
225
- // same path in both. Nothing to report on `error`: there are no
226
- // units to attribute pieces to.
227
- if (rec && 'error' !== folded.verdict) {
228
- const marks = emitted(node)
229
- const trace = traceOf(marks, instance, folded.units)
230
- // AN EMPTY TRACE IS NO TRACE, in both ports: Go omits an empty
231
- // slice, and a report shape that differed by port would be the one
232
- // thing the shared rows exist to refuse. A run that emitted no
233
- // piece has nothing to attribute, and the coverage report says so
234
- // in its own words.
235
- if (0 < trace.length) {
236
- folded.trace = trace
237
- }
238
- if (true === opts.coverage) {
239
- const cov = coverOf(root, node, reads as Set<string>, opts, marks,
240
- instance, folded.units)
241
- if (undefined === cov) {
242
- const nil: any = makeNilErr(actx, 'no_path', root, undefined,
243
- 'coverageAt')
244
- actx.err.push(nil)
245
- return errorReport([failureFinding(actx, opts.path, root)])
246
- }
247
- folded.coverage = cov
248
- }
249
- }
250
- return folded
251
- }
252
-
253
-
254
- // ---------------------------------------------------------------------
255
- // THE TRACE AND THE COVERAGE REPORT (RENDER.0.md D11, P7).
256
-
257
- // The one walk order both ports walk in: a list by index, a map by key
258
- // in code-point order. `fn` answers whether to descend.
259
- function walkVals(root: any, fn: (v: any, path: string[]) => boolean): void {
260
- const walk = (v: any, path: string[]): void => {
261
- if (null == v || true !== v.isVal || !fn(v, path)) {
262
- return
263
- }
264
- if (true === v.isList && null != v.peg) {
265
- for (let i = 0; i < v.peg.length; i++) {
266
- walk(v.peg[i], [...path, String(i)])
267
- }
268
- }
269
- else if (true === v.isMap && null != v.peg) {
270
- for (const k of Object.keys(v.peg).sort(cmpCodePoint)) {
271
- // AN ALIAS DECLARATION IS NOT A MEMBER, here for the reason
272
- // every fold has it (./val/members.ts): `%wire = …` holds a
273
- // value the document never generates, so it is neither a piece
274
- // to trace nor model that could be called dead.
275
- if (!v.aliasKeys.includes(k)) {
276
- walk(v.peg[k], [...path, k])
277
- }
278
- }
279
- }
280
- }
281
- walk(root, [])
282
- }
283
-
284
-
285
- // A path as an address: `$`, then a dot before every segment.
286
- function addr(path: string[]): string {
287
- return '$' + path.map((seg) => '.' + seg).join('')
288
- }
289
-
290
-
291
- // Every piece a dispatch stamped, under the anchored value, in
292
- // document order. The path is relative to the anchor, which is where
293
- // the instance the fold reads is rooted too.
294
- function emitted(node: any): { path: string, mark: any }[] {
295
- const out: { path: string, mark: any }[] = []
296
- walkVals(node, (v: any, path: string[]) => {
297
- if (null != v.emitted) {
298
- out.push({ path: addr(path), mark: v.emitted })
299
- }
300
- return true
301
- })
302
- return out
303
- }
304
-
305
-
306
- // The trace: one entry per stamped piece that a RENDERED unit holds. A
307
- // piece is IN the unit whose path prefixes its own, which is the whole
308
- // of the question -- no path is parsed, and a stamp that lies under no
309
- // unit at all (a rule set held under a key of its own, and referred to
310
- // from a unit) simply matches nothing. A unit the run did not render
311
- // (`--unit` names one) has no bytes for a piece of it to be in, so it
312
- // is not among the prefixes either.
313
- function traceOf(marks: { path: string, mark: any }[], instance: any,
314
- units: RenderUnit[]): RenderTrace[] {
315
- const pre: { at: string, path: string }[] = []
316
- unitList(instance).forEach((u: any, i: number) => {
317
- if (units.some((r) => r.path === u.path)) {
318
- pre.push({ at: '$.aontu.Code.units.' + i, path: u.path })
319
- }
320
- })
321
- const out: RenderTrace[] = []
322
- for (const m of marks) {
323
- const hit = pre.find((p) => m.path === p.at || m.path.startsWith(p.at + '.'))
324
- if (undefined === hit) {
325
- continue
326
- }
327
- out.push({ unit: hit.path, piece: m.path, node: m.mark.node, rule: m.mark.rule })
328
- }
329
- return out
330
- }
331
-
332
-
333
- // Every proper ancestor of an address, `$` included.
334
- function ancestors(a: string): string[] {
335
- const parts = a.split('.')
336
- const out: string[] = []
337
- for (let i = 1; i < parts.length; i++) {
338
- out.push(parts.slice(0, i).join('.'))
339
- }
340
- return out
341
- }
342
-
343
-
344
- // Is the value at `a` covered by the set -- the address itself in it,
345
- // or an address above it? An address ABOVE it covers the whole subtree:
346
- // a reference that read `$.schema` read everything under it, and a rule
347
- // that emitted a unit emitted every declaration in it.
348
- function covered(set: Set<string>, a: string): boolean {
349
- if (set.has(a)) {
350
- return true
351
- }
352
- for (const up of ancestors(a)) {
353
- if (set.has(up)) {
354
- return true
355
- }
356
- }
357
- return false
358
- }
359
-
360
-
361
- // THE COVERAGE REPORT (P7). Dead model is measured over the DOCUMENT
362
- // ROOT, or under `coverageAt` when a document keeps its model under one
363
- // key (X-3, decided here): the read set is absolute, so a narrower
364
- // measure is a narrower walk, not a different origin. The render's own
365
- // output -- the `aontu` namespace under the anchor -- is not model and
366
- // is never walked into: nothing reads it, so every document would
367
- // otherwise report it dead. The whole NAMESPACE is excluded, not just
368
- // `aontu.Code` (ADR-029): everything under it is language-supplied, so
369
- // an included vocabulary is not dead model either.
370
- function coverOf(root: any, node: any, reads: Set<string>,
371
- opts: RenderOptions, marks: { path: string, mark: any }[], instance: any,
372
- units: RenderUnit[]): RenderCoverage | undefined {
373
- // THE ANCHOR IS THE ONE render() ALREADY FOUND, so the namespace
374
- // under it is named without asking a second time: `--at` is resolved
375
- // before the vet, and an anchor that named nothing never reached here.
376
- const codeAddr = addr(node.path.concat('aontu'))
377
-
378
- let from: any = root
379
- let base: string[] = []
380
- if (null != opts.coverageAt && '' !== opts.coverageAt) {
381
- const found: any = anchorAt(root, opts.coverageAt)
382
- if (null == found) {
383
- return undefined
384
- }
385
- from = found
386
- base = found.path
387
- }
388
-
389
- // The two questions asked of the read set, as sets: is this address
390
- // read (or under one that is), and does a read lie BELOW it?
391
- const above = new Set<string>(reads)
392
- const below = new Set<string>()
393
- for (const r of reads) {
394
- for (const up of ancestors(r)) {
395
- below.add(up)
396
- }
397
- }
398
-
399
- const dead: string[] = []
400
- walkVals(from, (_v: any, path: string[]) => {
401
- const a = addr(base.concat(path))
402
- if (a === codeAddr || covered(above, a)) {
403
- return false
404
- }
405
- // THE ROOT OF THE MEASURE IS NEVER ITSELF DEAD MODEL, and is
406
- // descended into whatever the read set holds. A document that is
407
- // only a transform reads nothing above its own model, and naming
408
- // the root there would report the whole document dead while its
409
- // one live subtree sat inside it.
410
- if (below.has(a) || 0 === path.length) {
411
- return true
412
- }
413
- dead.push(a)
414
- return false
415
- })
416
-
417
- // A SILENT HOLE: a declaration of a rendered unit that no stamp
418
- // touches -- neither its own, nor one on the unit above it, nor one
419
- // on a piece inside it.
420
- const stamped = new Set<string>(marks.map((m) => m.path))
421
- const inside = new Set<string>()
422
- for (const m of marks) {
423
- for (const up of ancestors(m.path)) {
424
- inside.add(up)
425
- }
426
- }
427
- const unruled: { unit: string, path: string }[] = []
428
- unitList(instance).forEach((unit: any, i: number) => {
429
- if (!units.some((u) => u.path === unit.path)) {
430
- return
431
- }
432
- const decls: any[] = unit.decls
433
- decls.forEach((_d: any, j: number) => {
434
- const a = '$.aontu.Code.units.' + i + '.decls.' + j
435
- if (!covered(stamped, a) && !inside.has(a)) {
436
- unruled.push({ unit: unit.path, path: a })
437
- }
438
- })
439
- })
440
-
441
- return { read: [...reads].sort(cmpCodePoint), dead, unruled }
442
- }
443
-
444
-
445
- // The bundled text profile, evaluated once: the profile of a unit
446
- // whose declarations are fragments and text escapes only.
447
- const bundled: Record<string, any> = {}
448
-
449
- // A bundled profile, evaluated once: the meet of aontu:lang/<lang>
450
- // with the vocabulary, so its defaults are in it.
451
- function bundledProfile(lang: string): any {
452
- if (!BUNDLED_LANGS.includes(lang)) {
453
- return undefined
454
- }
455
- if (undefined === bundled[lang]) {
456
- bundled[lang] = new Aontu().generate('@"aontu:lang/' + lang + '"').aontu.Profile
457
- }
458
- return bundled[lang]
459
- }
460
-
461
-
462
- // PROFILE SELECTION, per unit (RENDER.0.md D5): a caller-supplied
463
- // profile whose `lang` is the unit's; else the bundled profile of that
464
- // `lang`; else `aontu:lang/text`, if and only if every declaration in
465
- // the unit is a fragment or a text escape; else nothing, which the
466
- // caller reports as `render_profile`. The unit's inline `profile` is
467
- // merged over whichever base was found.
468
- function profileFor(lang: string, given: any[] | undefined, fragOnly: boolean): any {
469
- const supplied = (given ?? []).find((p: any) => p?.lang === lang)
470
- if (undefined !== supplied) {
471
- return supplied
472
- }
473
- const own = bundledProfile(lang)
474
- if (undefined !== own) {
475
- return own
476
- }
477
- return fragOnly ? bundledProfile('text') : undefined
478
- }
479
-
480
-
481
- function isMap(v: any): boolean {
482
- return null != v && 'object' === typeof v && !Array.isArray(v)
483
- }
484
-
485
-
486
- // An inline profile merged over its base, map by map, the inline
487
- // value winning at a leaf; keys in code-point order, so the merge is
488
- // the same in both ports.
489
- function mergeProfile(base: any, over: any): any {
490
- const out: any = { ...base }
491
- for (const k of Object.keys(over).sort(cmpCodePoint)) {
492
- out[k] = isMap(base[k]) && isMap(over[k]) ?
493
- mergeProfile(base[k], over[k]) : over[k]
494
- }
495
- return out
496
- }
497
-
498
-
499
- // THE FOLD (RENDER.0.md D6). `pad(at)` is `indent.unit` repeated
500
- // `indent.width × at` times; a line is `pad + text + LF`, and an empty
501
- // text emits no pad; a blank is its terminators alone; a raw block's
502
- // lines each get the pad unless `reindent: false`, which emits them
503
- // at column 0 verbatim -- and common leading indentation is never
504
- // stripped. A reference inline is its name, verbatim (a
505
- // declaration-capable profile puts it through its identifier rules,
506
- // P5). Nothing is trimmed (D3): the text is the transform's.
507
- // A profile with no indent -- a caller-supplied map the vocabulary
508
- // never filled -- takes the vocabulary's own default, two spaces.
509
- function pad(profile: any, at: number): string {
510
- const indent = profile.indent ?? { unit: ' ', width: 2 }
511
- return (indent.unit ?? ' ').repeat((indent.width ?? 2) * at)
512
- }
513
-
514
- function line(profile: any, at: number, text: string): string {
515
- return ('' === text ? '' : pad(profile, at)) + text + '\n'
516
- }
517
-
518
- // A reference inline is its name: through the profile's identifier
519
- // rules under a lowering, verbatim under text.
520
- function inline(piece: any, ctx: LowerCtx | undefined): string {
521
- if ('string' === typeof piece) {
522
- return piece
523
- }
524
- return undefined === ctx ? piece.name : ident(piece.name, 'record', ctx, '', false)
525
- }
526
-
527
- function foldPiece(
528
- piece: any, profile: any, unit: string, path: string, lossy: RenderLoss[],
529
- ctx?: LowerCtx
530
- ): string {
531
- if ('string' === typeof piece) {
532
- return line(profile, 0, piece)
533
- }
534
- if ('line' === piece.k) {
535
- return line(profile, piece.at ?? 0, piece.of.map((p: any) => inline(p, ctx)).join(''))
536
- }
537
- if ('blank' === piece.k) {
538
- return '\n'.repeat(piece.n ?? 1)
539
- }
540
- lossy.push({
541
- unit, path, tier: 3, construct: 'raw',
542
- reason: 'verbatim text: the renderer re-indents it and checks nothing else',
543
- })
544
- const at: number = piece.at ?? 0
545
- const reindent: boolean = piece.reindent ?? true
546
- const lines: string[] = piece.text.split('\n')
547
- if ('' === lines[lines.length - 1]) {
548
- lines.pop()
549
- }
550
- return lines.map((l: string) => reindent ? line(profile, at, l) : l + '\n').join('')
551
- }
552
-
553
-
554
- // A PROFILE DOCUMENT (RENDER.0.md D5), evaluated the way `render`
555
- // evaluates its own: under the caller's include options, then vetted
556
- // against aontu:profile as a settled value and met with that vocabulary
557
- // so its defaults (`indent.width: 2`, ...) are in it. The answer is the
558
- // `profile` map the fold reads -- what `--profile <file>` hands to
559
- // RenderOptions.profiles -- or the findings that refused the document:
560
- // one that does not stand up, or one the vocabulary rejects.
561
- export function renderProfile(src: string, options?: RenderOptions):
562
- { profile?: any, errors?: VetFinding[] } {
563
- const opts = options ?? {}
564
- const aontu = new Aontu(includeOpts(opts))
565
- const actx = aontu.ctx({ collect: true })
566
- const root: any = aontu.unify(src, { path: opts.path, collect: true }, actx)
567
- if (0 < actx.err.length || true === root?.isNil) {
568
- return { errors: [failureFinding(actx, opts.path, root)] }
569
- }
570
- const report = vet(PROFILE_VOCABULARY, hcanon(root))
571
- if ('valid' !== report.verdict) {
572
- return { errors: report.findings }
573
- }
574
- // The meet, keyed as render's is: the vocabulary requires `profile`,
575
- // so a value the vet admitted has one.
576
- const instance = new Aontu().generate(
577
- PROFILE_VOCABULARY + '\naontu: Profile: ' +
578
- hcanon(root.peg.aontu.peg.Profile))
579
- return { profile: instance.aontu.Profile }
580
- }
581
-
582
-
583
- // The instance's unit list, or none: `code` is the vocabulary's own
584
- // key and is always there, `units` is not. One reader, so the fold,
585
- // the trace and the coverage report all see the same list.
586
- function unitList(instance: any): any[] {
587
- return Array.isArray(instance?.aontu?.Code?.units) ?
588
- instance.aontu.Code.units : []
589
- }
590
-
591
-
592
- // The fold alone, over `generate()` output: the instance is
593
- // `{code: {units: [...]}}` as the vocabulary shapes it, with its
594
- // defaults filled -- which is what `render` hands over, and what a
595
- // caller of this function is responsible for.
596
- export function renderValue(instance: any, options?: RenderOptions): RenderReport {
597
- const opts = options ?? {}
598
- const errors: VetFinding[] = []
599
- const lossy: RenderLoss[] = []
600
- const units: RenderUnit[] = []
601
- const list: any[] = unitList(instance)
602
-
603
- const seen: string[] = []
604
- let selected = 0
605
- list.forEach((unit: any, i: number) => {
606
- const upath = '$.aontu.Code.units.' + i
607
- const path: string = unit.path
608
- const lang: string = unit.lang
609
-
610
- // A UNIT PATH IS RELATIVE, DESCENDS, AND IS ITS OWN (RENDER.0.md
611
- // D8): an absolute path, a `..` segment or a repeat of another
612
- // unit's path is refused before anything is written.
613
- if (path.startsWith('/')) {
614
- errors.push(finding('render_path', 'parse', upath + '.path',
615
- 'the unit path ' + path + ' is absolute.'))
616
- return
617
- }
618
- if (path.split('/').includes('..')) {
619
- errors.push(finding('render_path', 'parse', upath + '.path',
620
- 'the unit path ' + path + ' climbs out of the output directory.'))
621
- return
622
- }
623
- if (seen.includes(path)) {
624
- errors.push(finding('render_path', 'parse', upath + '.path',
625
- 'the unit path ' + path + ' repeats another unit\'s.'))
626
- return
627
- }
628
- seen.push(path)
629
-
630
- if (undefined !== opts.unit && opts.unit !== path) {
631
- return
632
- }
633
- selected++
634
-
635
- const decls: any[] = unit.decls
636
- const fragOnly = decls.every((d: any) => 'frag' === d.k || 'text' === d.k)
637
- const base = profileFor(lang, opts.profiles, fragOnly)
638
- if (undefined === base) {
639
- errors.push(finding('render_profile', 'parse', upath + '.lang',
640
- 'no profile renders ' + lang + ': a declaration needs a lowering, and ' +
641
- 'only fragments and text escapes render under aontu:lang/text.'))
642
- return
643
- }
644
- const profile = null == unit.profile ? base : mergeProfile(base, unit.profile)
645
-
646
- // THE LOWERING (D5, P5), when the profile names one: the unit's
647
- // header -- banner, package clause, imports -- and each declaration
648
- // as pieces the fold takes, a blank line between two lowered
649
- // declarations. A fragment or a text escape owns its own blanks.
650
- const family: string | undefined = profile.lowering
651
- const ctx: LowerCtx | undefined = undefined === family ? undefined
652
- : { profile, family, unit: path, lossy }
653
-
654
- let text = ''
655
- if (undefined !== ctx) {
656
- const header = lowerHeader(unit, instance?.aontu?.Code?.source, ctx)
657
- for (const piece of header) {
658
- text += foldPiece(piece, profile, path, upath, lossy, ctx)
659
- }
660
- if (0 < header.length && 0 < decls.length) {
661
- text += '\n'
662
- }
663
- }
664
- let lowered = false
665
- decls.forEach((decl: any, j: number) => {
666
- const dpath = upath + '.decls.' + j
667
- if ('frag' === decl.k) {
668
- lowered = false
669
- lossy.push({
670
- unit: path, path: dpath, tier: 2, construct: 'frag',
671
- reason: 'a fragment says nothing about ' + lang + ' syntax',
672
- })
673
- decl.of.forEach((piece: any, n: number) => {
674
- text += foldPiece(piece, profile, path, dpath + '.of.' + n, lossy, ctx)
675
- })
676
- }
677
- else if ('text' === decl.k) {
678
- lowered = false
679
- if (decl.lang !== lang) {
680
- errors.push(finding('render_lang', 'conflict', dpath + '.lang',
681
- 'the text escape is ' + decl.lang + ' in a ' + lang + ' unit.'))
682
- return
683
- }
684
- lossy.push({
685
- unit: path, path: dpath, tier: 3, construct: 'text',
686
- reason: 'verbatim ' + lang + ': the renderer checks nothing in it',
687
- })
688
- text += decl.text
689
- }
690
- else if (undefined !== ctx) {
691
- if (lowered) {
692
- text += '\n'
693
- }
694
- for (const piece of lowerDecl(decl, dpath, ctx)) {
695
- text += foldPiece(piece, profile, path, dpath, lossy, ctx)
696
- }
697
- lowered = true
698
- }
699
- else {
700
- errors.push(finding('render_profile', 'parse', dpath + '.k',
701
- 'a ' + decl.k + ' declaration has no lowering under the ' +
702
- profile.lang + ' profile.'))
703
- }
704
- })
705
-
706
- units.push({ path, lang, text })
707
- })
708
-
709
- if (undefined !== opts.unit && 0 === selected) {
710
- errors.push(finding('render_unit', 'reference', '$.aontu.Code.units',
711
- 'no unit has the path ' + opts.unit + '.'))
712
- }
713
-
714
- if (true === opts.strict) {
715
- for (const loss of lossy) {
716
- if (3 === loss.tier) {
717
- errors.push(finding('render_strict', 'conflict', loss.path,
718
- 'the ' + loss.construct + ' in ' + loss.unit +
719
- ' is an opaque escape, refused under strict.'))
720
- }
721
- }
722
- }
723
-
724
- if (0 < errors.length) {
725
- return errorReport(errors)
726
- }
727
- return {
728
- verdict: 0 < lossy.length ? 'lossy' : 'ok',
729
- units,
730
- lossy,
731
- }
732
- }