aontu 0.53.0 → 0.55.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 (197) hide show
  1. package/dist/aontu.d.ts +3 -2
  2. package/dist/aontu.js +36 -7
  3. package/dist/aontu.js.map +1 -1
  4. package/dist/cli.d.ts +2 -1
  5. package/dist/cli.js +500 -8
  6. package/dist/cli.js.map +1 -1
  7. package/dist/ctx.d.ts +5 -0
  8. package/dist/ctx.js +1 -0
  9. package/dist/ctx.js.map +1 -1
  10. package/dist/diff.js.map +1 -1
  11. package/dist/err.js +7 -1
  12. package/dist/err.js.map +1 -1
  13. package/dist/graph.d.ts +2 -5
  14. package/dist/graph.js +83 -46
  15. package/dist/graph.js.map +1 -1
  16. package/dist/hcanon.js +9 -10
  17. package/dist/hcanon.js.map +1 -1
  18. package/dist/hints.js +94 -26
  19. package/dist/hints.js.map +1 -1
  20. package/dist/jsonschema.js +34 -0
  21. package/dist/jsonschema.js.map +1 -1
  22. package/dist/lang.js +593 -191
  23. package/dist/lang.js.map +1 -1
  24. package/dist/lsp.d.ts +1 -1
  25. package/dist/lsp.js +86 -6
  26. package/dist/lsp.js.map +1 -1
  27. package/dist/mcp.js +153 -6
  28. package/dist/mcp.js.map +1 -1
  29. package/dist/mod-tool.js +42 -8
  30. package/dist/mod-tool.js.map +1 -1
  31. package/dist/mod.d.ts +4 -0
  32. package/dist/mod.js +97 -2
  33. package/dist/mod.js.map +1 -1
  34. package/dist/patch.d.ts +5 -0
  35. package/dist/patch.js +25 -25
  36. package/dist/patch.js.map +1 -1
  37. package/dist/provenance.d.ts +1 -0
  38. package/dist/provenance.js +2 -1
  39. package/dist/provenance.js.map +1 -1
  40. package/dist/query.js.map +1 -1
  41. package/dist/reach.d.ts +1 -0
  42. package/dist/reach.js +49 -21
  43. package/dist/reach.js.map +1 -1
  44. package/dist/relation.d.ts +4 -0
  45. package/dist/relation.js +125 -200
  46. package/dist/relation.js.map +1 -1
  47. package/dist/sig.d.ts +25 -0
  48. package/dist/sig.js +277 -0
  49. package/dist/sig.js.map +1 -0
  50. package/dist/sigdecl.d.ts +2 -0
  51. package/dist/sigdecl.js +11 -0
  52. package/dist/sigdecl.js.map +1 -0
  53. package/dist/siggate.d.ts +4 -0
  54. package/dist/siggate.js +90 -0
  55. package/dist/siggate.js.map +1 -0
  56. package/dist/std.js +75 -16
  57. package/dist/std.js.map +1 -1
  58. package/dist/subsume.js +57 -10
  59. package/dist/subsume.js.map +1 -1
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/dist/unify.d.ts +2 -2
  62. package/dist/unify.js +93 -114
  63. package/dist/unify.js.map +1 -1
  64. package/dist/utility.d.ts +1 -2
  65. package/dist/utility.js +7 -61
  66. package/dist/utility.js.map +1 -1
  67. package/dist/val/AggFuncVal.d.ts +12 -1
  68. package/dist/val/AggFuncVal.js +165 -3
  69. package/dist/val/AggFuncVal.js.map +1 -1
  70. package/dist/val/BagVal.d.ts +2 -0
  71. package/dist/val/BagVal.js +56 -8
  72. package/dist/val/BagVal.js.map +1 -1
  73. package/dist/val/ConstraintVal.js +33 -5
  74. package/dist/val/ConstraintVal.js.map +1 -1
  75. package/dist/val/ContainerKindVal.d.ts +35 -0
  76. package/dist/val/ContainerKindVal.js +99 -0
  77. package/dist/val/ContainerKindVal.js.map +1 -0
  78. package/dist/val/CopyFuncVal.js +0 -7
  79. package/dist/val/CopyFuncVal.js.map +1 -1
  80. package/dist/val/DisjunctVal.d.ts +1 -2
  81. package/dist/val/DisjunctVal.js +146 -39
  82. package/dist/val/DisjunctVal.js.map +1 -1
  83. package/dist/val/ExpectVal.js +37 -2
  84. package/dist/val/ExpectVal.js.map +1 -1
  85. package/dist/val/FuncBaseVal.d.ts +1 -0
  86. package/dist/val/FuncBaseVal.js +19 -8
  87. package/dist/val/FuncBaseVal.js.map +1 -1
  88. package/dist/val/GraphAtomVal.d.ts +39 -0
  89. package/dist/val/GraphAtomVal.js +184 -0
  90. package/dist/val/GraphAtomVal.js.map +1 -0
  91. package/dist/val/JunctionVal.js +22 -5
  92. package/dist/val/JunctionVal.js.map +1 -1
  93. package/dist/val/ListVal.js +27 -34
  94. package/dist/val/ListVal.js.map +1 -1
  95. package/dist/val/MapVal.d.ts +1 -0
  96. package/dist/val/MapVal.js +82 -35
  97. package/dist/val/MapVal.js.map +1 -1
  98. package/dist/val/PathFuncVal.d.ts +2 -2
  99. package/dist/val/PathFuncVal.js +75 -16
  100. package/dist/val/PathFuncVal.js.map +1 -1
  101. package/dist/val/PathVal.d.ts +25 -0
  102. package/dist/val/PathVal.js +150 -0
  103. package/dist/val/PathVal.js.map +1 -0
  104. package/dist/val/PlusOpVal.d.ts +2 -1
  105. package/dist/val/PlusOpVal.js +50 -35
  106. package/dist/val/PlusOpVal.js.map +1 -1
  107. package/dist/val/PrefVal.d.ts +2 -0
  108. package/dist/val/PrefVal.js +159 -32
  109. package/dist/val/PrefVal.js.map +1 -1
  110. package/dist/val/RecurseVal.d.ts +19 -0
  111. package/dist/val/RecurseVal.js +217 -0
  112. package/dist/val/RecurseVal.js.map +1 -0
  113. package/dist/val/RefVal.d.ts +2 -1
  114. package/dist/val/RefVal.js +105 -72
  115. package/dist/val/RefVal.js.map +1 -1
  116. package/dist/val/ReferFuncVal.d.ts +30 -7
  117. package/dist/val/ReferFuncVal.js +395 -94
  118. package/dist/val/ReferFuncVal.js.map +1 -1
  119. package/dist/val/ScalarKindVal.d.ts +4 -2
  120. package/dist/val/ScalarKindVal.js +12 -1
  121. package/dist/val/ScalarKindVal.js.map +1 -1
  122. package/dist/val/SuperFuncVal.d.ts +4 -2
  123. package/dist/val/SuperFuncVal.js +118 -14
  124. package/dist/val/SuperFuncVal.js.map +1 -1
  125. package/dist/val/TopVal.d.ts +1 -1
  126. package/dist/val/Val.d.ts +2 -3
  127. package/dist/val/Val.js +39 -20
  128. package/dist/val/Val.js.map +1 -1
  129. package/dist/val/arith.js +4 -1
  130. package/dist/val/arith.js.map +1 -1
  131. package/dist/vet.d.ts +1 -0
  132. package/dist/vet.js +32 -1
  133. package/dist/vet.js.map +1 -1
  134. package/dist/view.d.ts +90 -0
  135. package/dist/view.js +2168 -0
  136. package/dist/view.js.map +1 -0
  137. package/grammar/aontu.gbnf +18 -10
  138. package/grammar/aontu.lark +15 -10
  139. package/grammar/aontu.tmLanguage.json +184 -0
  140. package/package.json +10 -3
  141. package/skill/grammar-card.md +1 -2
  142. package/src/aontu.ts +37 -7
  143. package/src/cli.ts +553 -8
  144. package/src/ctx.ts +20 -0
  145. package/src/diff.ts +4 -2
  146. package/src/err.ts +8 -1
  147. package/src/graph.ts +125 -75
  148. package/src/hcanon.ts +9 -11
  149. package/src/hints.ts +112 -29
  150. package/src/jsonschema.ts +41 -0
  151. package/src/lang.ts +642 -203
  152. package/src/lsp.ts +75 -6
  153. package/src/mcp.ts +164 -6
  154. package/src/mod-tool.ts +48 -9
  155. package/src/mod.ts +110 -1
  156. package/src/patch.ts +31 -27
  157. package/src/provenance.ts +8 -1
  158. package/src/query.ts +4 -2
  159. package/src/reach.ts +52 -23
  160. package/src/relation.ts +139 -236
  161. package/src/sig.ts +345 -0
  162. package/src/sigdecl.ts +11 -0
  163. package/src/siggate.ts +144 -0
  164. package/src/std.ts +77 -16
  165. package/src/subsume.ts +59 -10
  166. package/src/unify.ts +102 -125
  167. package/src/utility.ts +7 -67
  168. package/src/val/AggFuncVal.ts +231 -4
  169. package/src/val/BagVal.ts +58 -9
  170. package/src/val/ConstraintVal.ts +34 -5
  171. package/src/val/ContainerKindVal.ts +158 -0
  172. package/src/val/CopyFuncVal.ts +0 -7
  173. package/src/val/DisjunctVal.ts +152 -40
  174. package/src/val/ExpectVal.ts +39 -4
  175. package/src/val/FuncBaseVal.ts +21 -8
  176. package/src/val/GraphAtomVal.ts +264 -0
  177. package/src/val/JunctionVal.ts +23 -6
  178. package/src/val/ListVal.ts +30 -37
  179. package/src/val/MapVal.ts +87 -39
  180. package/src/val/PathFuncVal.ts +107 -19
  181. package/src/val/PathVal.ts +221 -0
  182. package/src/val/PlusOpVal.ts +56 -37
  183. package/src/val/PrefVal.ts +186 -38
  184. package/src/val/RecurseVal.ts +285 -0
  185. package/src/val/RefVal.ts +105 -83
  186. package/src/val/ReferFuncVal.ts +445 -100
  187. package/src/val/ScalarKindVal.ts +12 -0
  188. package/src/val/SuperFuncVal.ts +137 -13
  189. package/src/val/TopVal.ts +1 -1
  190. package/src/val/Val.ts +44 -35
  191. package/src/val/arith.ts +4 -1
  192. package/src/vet.ts +41 -4
  193. package/src/view.ts +2882 -0
  194. package/dist/val/IdFuncVal.d.ts +0 -13
  195. package/dist/val/IdFuncVal.js +0 -54
  196. package/dist/val/IdFuncVal.js.map +0 -1
  197. package/src/val/IdFuncVal.ts +0 -91
package/dist/cli.js CHANGED
@@ -11,6 +11,7 @@ exports.runBreaking = runBreaking;
11
11
  exports.runTrim = runTrim;
12
12
  exports.runRelations = runRelations;
13
13
  exports.runReaches = runReaches;
14
+ exports.runView = runView;
14
15
  exports.runJsonSchema = runJsonSchema;
15
16
  exports.runMod = runMod;
16
17
  exports.runHash = runHash;
@@ -43,6 +44,7 @@ const mod_tool_1 = require("./mod-tool");
43
44
  const mod_1 = require("./mod");
44
45
  const vet_1 = require("./vet");
45
46
  const reach_1 = require("./reach");
47
+ const view_1 = require("./view");
46
48
  const agentsmd_1 = require("./agentsmd");
47
49
  const HELP = `Usage: aontu [options] [file]
48
50
  aontu vet [options] <schema> <data> [more-data...]
@@ -51,6 +53,8 @@ const HELP = `Usage: aontu [options] [file]
51
53
  aontu trim --check [options] <file>
52
54
  aontu relations [options] <file>
53
55
  aontu reaches <from> <to> [--relation <name>] [options] <file>
56
+ aontu view <kind> [options] <file>...
57
+ aontu view --views <path> [--check] [options] <file>
54
58
  aontu jsonschema [--at <path>] [--strict] [options] <file>
55
59
  aontu hash [options] <file>
56
60
  aontu mod tidy|verify|vendor|manifest [options] [dir]
@@ -171,6 +175,72 @@ Why options:
171
175
  Why exit codes mirror get's: 0 explained, 1 the path names nothing,
172
176
  2 usage, 4 the document does not stand up on its own.
173
177
 
178
+ View kinds: tree, matrix, graph, layer, sets, layers, ladder, poset
179
+ (the poset takes several files). The figure goes to stdout, the loss
180
+ report to stderr. With --views it draws every figure a document
181
+ declares as data, from one evaluation: each declaration names its own
182
+ kind and out file, nothing is written unless every figure rendered,
183
+ and --check gates the committed set.
184
+
185
+ View options:
186
+ --as <profile> text | mermaid | dot | er | svg, per kind: doc,
187
+ tree, matrix, sets and layers draw text (default)
188
+ or svg; graph draws mermaid (default), dot or er;
189
+ layer draws text (default), mermaid or svg; ladder
190
+ and poset draw mermaid (default) or dot
191
+ --at <path> Restrict the figure to nodes under this path; the
192
+ subtree doc draws; the path the ladder draws;
193
+ where the poset compares
194
+ --views <path> Draw every figure the document declares at this
195
+ path, one evaluation, all or nothing; each
196
+ declaration names its own kind and out file
197
+ -o, --out <file> Write the figure here instead of stdout
198
+ --check Exit 1 if --out differs from what would be drawn;
199
+ nothing is written
200
+ --strict Exit 1 when the loss report holds anything beyond
201
+ edges_deduped, inverse_suppressed and crossings
202
+ --depth <n> doc: how many levels of key to draw (default 3)
203
+ --max-rows <n> Refuse a figure above this many rows (default 60)
204
+ --style <s> auto (default), none, ansi or css. A figure's
205
+ marks carry their meaning -- a direct cell, a
206
+ closure cell, an upward edge -- and each profile
207
+ has one way to show it: SGR escapes for text, CSS
208
+ classes for svg. auto picks that mechanism where
209
+ the destination can carry it: escapes only on a
210
+ terminal (NO_COLOR is honoured), and an svg keeps
211
+ the stylesheet that makes it standalone. none
212
+ drops both; on svg the classes stay and only the
213
+ stylesheet goes, for a host page that has already
214
+ bound --av-ink and its kin. Escapes are never
215
+ written to a file
216
+ --format <f> text (default) or json, the whole report
217
+ --relation <n> tree, matrix, layer: draw over this relation only;
218
+ graph: keep this predicate (repeatable)
219
+ --root <path> tree: draw only the subtree under this node;
220
+ repeatable
221
+ --order <o> matrix: canon (default) or partition
222
+ --closure matrix: mark transitively reachable cells +
223
+ --group-by <k> graph: one subgraph per distinct value of field k;
224
+ layer: one band per value (required)
225
+ --layers <a,b> layer: the bands in this order, top first; without
226
+ it the order is derived from the relation
227
+ --edges <e> layer: which of the relation's edges to draw over
228
+ the bands -- upward (the violations, the default
229
+ for text and svg), all (mermaid's default) or none
230
+ --label <k> graph: label each node with field k
231
+ --sets <path> sets: the map whose keys are the sets
232
+ --member <k> sets: the field holding each set's members
233
+ --universe <p> sets: the full element domain, so the empty
234
+ column exists
235
+ --min-degree <n> sets: drop intersections below this degree
236
+ --min-size <n> layers: drop intersections below this many paths
237
+ --max-cols <n> sets, layers: elide columns beyond this many
238
+ --profile <p> poset: values | defaults (default) | gen
239
+
240
+ View exit codes: 0 rendered, 1 --check mismatch or lossy under
241
+ --strict, 2 usage or --max-rows exceeded, 4 the document does not stand
242
+ up on its own, or a relation, root or path that names nothing.
243
+
174
244
  Set options:
175
245
  --entry <file> The document the change is checked against
176
246
  --overlay <file> The file the change is appended to (created if
@@ -1419,6 +1489,57 @@ const REACHES_EXIT = {
1419
1489
  unreachable: 1,
1420
1490
  error: 4,
1421
1491
  };
1492
+ const VIEW_HELP = 'aontu view <kind> [options] <file>... (try --help)';
1493
+ const VIEW_KINDS = ['doc', 'tree', 'matrix', 'graph', 'layer', 'sets', 'layers', 'ladder',
1494
+ 'poset'];
1495
+ const VIEW_PROFILES = ['text', 'mermaid', 'dot', 'er', 'svg'];
1496
+ const VIEW_EDGES = ['upward', 'all', 'none'];
1497
+ // The styles the CLI accepts (VIEWS.0.md, "7. Styling"). `auto` is
1498
+ // here and NOT in ViewStyle: resolving it means knowing whether stdout
1499
+ // is a terminal, which is the CLI's to know and the library's never --
1500
+ // the same division err.ts already draws for the error frames.
1501
+ const VIEW_STYLES = ['auto', 'none', 'ansi', 'css'];
1502
+ // `--style auto` resolved, which only the CLI can do. The mechanism is
1503
+ // the PROFILE's and the library knows it -- an SVG carries its
1504
+ // stylesheet unless told not to, which is what makes a figure stand
1505
+ // alone. What the library cannot know is whether the DESTINATION is a
1506
+ // terminal, so that is the only thing decided here: escapes on the
1507
+ // text profile when stdout is a terminal and NO_COLOR is unset, the
1508
+ // same two conditions the error frames use. `undefined` leaves the
1509
+ // profile's own default in place.
1510
+ function viewStyleOf(asked, as) {
1511
+ if (undefined !== asked && 'auto' !== asked) {
1512
+ return asked;
1513
+ }
1514
+ // STDOUT'S OWN TERMINAL-NESS, and NO_COLOR read here rather than
1515
+ // through colorActive(). The figure goes to STDOUT and the error
1516
+ // frames go to STDERR, and they are not the same destination: main()
1517
+ // has already called setColor for stderr, so asking colorActive()
1518
+ // would answer the wrong question twice --- no escapes for
1519
+ // `aontu view tree m.aon 2>/dev/null` at a terminal, and escapes
1520
+ // into the pipe for `aontu view tree m.aon | less`. The NO_COLOR
1521
+ // rule is the one no-color.org states and err.ts implements:
1522
+ // set, to anything but empty, means no colour.
1523
+ const no = process.env.NO_COLOR;
1524
+ return 'text' === as && true === process.stdout.isTTY
1525
+ && (null == no || '' === no) ? 'ansi' : undefined;
1526
+ }
1527
+ // The figure was drawn (0, `lossy` included: the loss report says
1528
+ // what it could not draw, and --strict is the gate on that), or the
1529
+ // document could not be drawn (4). An EMPTY figure is a drawing, not
1530
+ // a failure: a model with no links has nothing to draw, honestly.
1531
+ const VIEW_EXIT = {
1532
+ rendered: 0,
1533
+ lossy: 0,
1534
+ error: 4,
1535
+ };
1536
+ // The refusals that are USAGE, not the document's fault: exit 2, as
1537
+ // every other verb's usage errors do.
1538
+ const VIEW_USAGE_CODES = [
1539
+ 'view_kind_unknown', 'view_profile_unknown', 'view_rows_exceeded',
1540
+ 'view_at_required', 'view_sets_required', 'view_group_required',
1541
+ 'view_document_shape', 'view_style_profile', 'view_style_unknown',
1542
+ ];
1422
1543
  const MOD_HELP = 'aontu mod tidy|verify|vendor|manifest [dir] (try --help)';
1423
1544
  // The module tooling (G6 phase 3, ts/src/mod-tool.ts). All LOCAL:
1424
1545
  // `tidy` resolves the closure from what is in the stores and rewrites
@@ -1476,7 +1597,8 @@ function runMod(argv) {
1476
1597
  const dir = rest[1] ?? '.';
1477
1598
  if ('get' === sub || 'publish' === sub) {
1478
1599
  process.stderr.write('aontu: mod ' + sub + ' needs a registry client, which this build ' +
1479
- 'does not ship (docs/capability-review/g6-distribution.md)\n');
1600
+ 'does not ship; vendor the module by hand and run ' +
1601
+ "'aontu mod tidy'\n");
1480
1602
  return 2;
1481
1603
  }
1482
1604
  if (!MOD_SUBS.includes(sub) || 2 < rest.length) {
@@ -1690,7 +1812,7 @@ function runReaches(argv) {
1690
1812
  }
1691
1813
  }
1692
1814
  if (3 !== rest.length) {
1693
- process.stderr.write(`aontu: reaches needs two entities and one file\n${REACHES_HELP}\n`);
1815
+ process.stderr.write(`aontu: reaches needs two node paths and one file\n${REACHES_HELP}\n`);
1694
1816
  return 2;
1695
1817
  }
1696
1818
  let src;
@@ -1732,6 +1854,376 @@ function renderReachesJson(report) {
1732
1854
  ...(null == report.errors ? {} : { errors: report.errors }),
1733
1855
  }, 2);
1734
1856
  }
1857
+ // ---------------------------------------------------------------------
1858
+ // The tree view (docs/design/VIEWS.0.md, ts/src/view.ts): the drawn
1859
+ // edge set, as text a golden diff can check.
1860
+ function runView(argv) {
1861
+ const trusted = takeTrust(argv);
1862
+ if (null == trusted) {
1863
+ return 2;
1864
+ }
1865
+ argv = trusted.argv;
1866
+ const trust = trusted.trust;
1867
+ const rest = [];
1868
+ let format = 'text';
1869
+ let out = undefined;
1870
+ let check = false;
1871
+ let strict = false;
1872
+ const relations = [];
1873
+ const roots = [];
1874
+ const opts = {};
1875
+ // The style ASKED FOR, which may be `auto` -- a word ViewStyle does
1876
+ // not have, because resolving it is the CLI's job.
1877
+ let style = undefined;
1878
+ // A flag that takes a value, read into `opts` by name.
1879
+ const valued = {
1880
+ '--as': 'as', '--at': 'at', '--order': 'order', '--group-by': 'groupBy',
1881
+ '--label': 'label', '--sets': 'sets', '--member': 'member',
1882
+ '--universe': 'universe', '--profile': 'profile', '--views': 'views',
1883
+ '--edges': 'edges',
1884
+ };
1885
+ const counted = {
1886
+ '--max-rows': 'maxRows', '--max-cols': 'maxCols',
1887
+ '--min-degree': 'minDegree', '--min-size': 'minSize',
1888
+ '--depth': 'depth',
1889
+ };
1890
+ for (let i = 0; i < argv.length; i++) {
1891
+ const arg = argv[i];
1892
+ if ('-h' === arg || '--help' === arg) {
1893
+ process.stdout.write(HELP);
1894
+ return 0;
1895
+ }
1896
+ if ('--format' === arg) {
1897
+ const f = argv[++i];
1898
+ if ('text' !== f && 'json' !== f) {
1899
+ process.stderr.write('aontu: --format needs text or json\n');
1900
+ return 2;
1901
+ }
1902
+ format = f;
1903
+ }
1904
+ else if ('--relation' === arg) {
1905
+ const relation = argv[++i];
1906
+ if (null == relation || '' === relation) {
1907
+ process.stderr.write('aontu: --relation needs a name\n');
1908
+ return 2;
1909
+ }
1910
+ relations.push(relation);
1911
+ }
1912
+ else if ('--root' === arg) {
1913
+ const root = argv[++i];
1914
+ if (null == root) {
1915
+ process.stderr.write('aontu: --root needs a node path\n');
1916
+ return 2;
1917
+ }
1918
+ roots.push(root);
1919
+ }
1920
+ else if ('-o' === arg || '--out' === arg) {
1921
+ out = argv[++i];
1922
+ if (null == out) {
1923
+ process.stderr.write('aontu: --out needs a file\n');
1924
+ return 2;
1925
+ }
1926
+ }
1927
+ else if ('--style' === arg) {
1928
+ style = argv[++i];
1929
+ if (null == style || !VIEW_STYLES.includes(style)) {
1930
+ process.stderr.write(`aontu: --style needs one of ${VIEW_STYLES.join(', ')}\n`);
1931
+ return 2;
1932
+ }
1933
+ }
1934
+ else if ('--check' === arg) {
1935
+ check = true;
1936
+ }
1937
+ else if ('--strict' === arg) {
1938
+ strict = true;
1939
+ }
1940
+ else if ('--closure' === arg) {
1941
+ opts.closure = true;
1942
+ }
1943
+ else if ('--layers' === arg) {
1944
+ const v = argv[++i];
1945
+ if (null == v || '' === v) {
1946
+ process.stderr.write('aontu: --layers needs a comma-separated list\n');
1947
+ return 2;
1948
+ }
1949
+ opts.layers = v.split(',');
1950
+ }
1951
+ else if (undefined !== valued[arg]) {
1952
+ const v = argv[++i];
1953
+ if (null == v || '' === v) {
1954
+ process.stderr.write(`aontu: ${arg} needs a value\n`);
1955
+ return 2;
1956
+ }
1957
+ opts[valued[arg]] = v;
1958
+ }
1959
+ else if (undefined !== counted[arg]) {
1960
+ const v = argv[++i];
1961
+ if (null == v || !/^[0-9]+$/.test(v)) {
1962
+ process.stderr.write(`aontu: ${arg} needs a count\n`);
1963
+ return 2;
1964
+ }
1965
+ opts[counted[arg]] = parseInt(v, 10);
1966
+ }
1967
+ else if (arg.startsWith('-')) {
1968
+ process.stderr.write(`aontu: unknown view option ${arg} (try --help)\n`);
1969
+ return 2;
1970
+ }
1971
+ else {
1972
+ rest.push(arg);
1973
+ }
1974
+ }
1975
+ // ESCAPES NEVER GO INTO A FILE. A pinned golden holding terminal
1976
+ // control codes is not a golden anybody can read, and a byte
1977
+ // comparison against one would fail on the reader's terminal
1978
+ // settings. `auto` resolves to `none` there on its own; asking for
1979
+ // `ansi` explicitly is a usage error rather than a silent downgrade,
1980
+ // so a script that wanted colour is told where it went.
1981
+ if ('ansi' === style && (undefined !== out || undefined !== opts.views)) {
1982
+ process.stderr.write('aontu: --style ansi writes to a terminal, not to a file\n');
1983
+ return 2;
1984
+ }
1985
+ // THE VIEW DOCUMENT draws every figure a document declares, so it
1986
+ // names no kind: the declarations do, one each.
1987
+ if (undefined !== opts.views) {
1988
+ // A declaration names its own profile, so the style is left to
1989
+ // each figure's own default; `--style none` still reaches every
1990
+ // one of them, which is how a host page that binds the CSS
1991
+ // variables asks for eight figures without eight stylesheets.
1992
+ opts.style = viewStyleOf(style, undefined);
1993
+ return runViewSet(rest, opts, trust, { format, check, strict, out });
1994
+ }
1995
+ if (2 > rest.length) {
1996
+ process.stderr.write(`aontu: view needs a kind and a file\n${VIEW_HELP}\n`);
1997
+ return 2;
1998
+ }
1999
+ const kind = rest[0];
2000
+ if (!VIEW_KINDS.includes(kind)) {
2001
+ process.stderr.write(`aontu: unknown view kind ${kind} (the kinds are: ${VIEW_KINDS.join(', ')})\n`);
2002
+ return 2;
2003
+ }
2004
+ if (undefined !== opts.as && !VIEW_PROFILES.includes(opts.as)) {
2005
+ process.stderr.write(`aontu: --as needs one of ${VIEW_PROFILES.join(', ')}\n`);
2006
+ return 2;
2007
+ }
2008
+ if (undefined !== opts.order && 'canon' !== opts.order && 'partition' !== opts.order) {
2009
+ process.stderr.write('aontu: --order needs canon or partition\n');
2010
+ return 2;
2011
+ }
2012
+ if (undefined !== opts.edges && !VIEW_EDGES.includes(opts.edges)) {
2013
+ process.stderr.write(`aontu: --edges needs one of ${VIEW_EDGES.join(', ')}\n`);
2014
+ return 2;
2015
+ }
2016
+ if (undefined !== opts.profile && !['values', 'defaults', 'gen'].includes(opts.profile)) {
2017
+ process.stderr.write('aontu: --profile needs values, defaults or gen\n');
2018
+ return 2;
2019
+ }
2020
+ if ('poset' !== kind && 2 !== rest.length) {
2021
+ process.stderr.write(`aontu: view ${kind} takes one file\n`);
2022
+ return 2;
2023
+ }
2024
+ if ('graph' === kind) {
2025
+ opts.relations = relations;
2026
+ }
2027
+ else if (1 < relations.length) {
2028
+ process.stderr.write(`aontu: view ${kind} takes one --relation\n`);
2029
+ return 2;
2030
+ }
2031
+ else {
2032
+ opts.relation = relations[0];
2033
+ }
2034
+ if (check && undefined === out) {
2035
+ process.stderr.write('aontu: --check needs --out\n');
2036
+ return 2;
2037
+ }
2038
+ const files = rest.slice(1);
2039
+ const srcs = [];
2040
+ for (const file of files) {
2041
+ try {
2042
+ srcs.push((0, node_fs_1.readFileSync)(file, 'utf8'));
2043
+ }
2044
+ catch (err) {
2045
+ process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
2046
+ return 2;
2047
+ }
2048
+ }
2049
+ const report = (0, view_1.view)(srcs[0], {
2050
+ ...opts,
2051
+ style: viewStyleOf(style, opts.as ?? (0, view_1.viewDefaultProfile)(kind)),
2052
+ kind,
2053
+ path: files[0],
2054
+ roots,
2055
+ trust: verbTrust(trust, entryRootOf(files[0])),
2056
+ docs: files.slice(1).map((path, i) => ({ src: srcs[i + 1], path })),
2057
+ });
2058
+ if ('json' === format) {
2059
+ process.stdout.write(renderViewJson(report) + '\n');
2060
+ }
2061
+ else if ('error' === report.verdict) {
2062
+ process.stderr.write(report.errors.map(renderFinding).join('\n') + '\n');
2063
+ }
2064
+ else {
2065
+ // THE FIGURE AND NOTHING ELSE on stdout (or in the file): stdout is
2066
+ // what a golden diff reads, and a verdict line would be part of
2067
+ // every drawing. The loss report goes to stderr, so a figure
2068
+ // written to a file still tells the reader what it could not draw.
2069
+ const text = report.text + '\n';
2070
+ if (undefined === out) {
2071
+ process.stdout.write(text);
2072
+ }
2073
+ else if (check) {
2074
+ let have = undefined;
2075
+ try {
2076
+ have = (0, node_fs_1.readFileSync)(out, 'utf8');
2077
+ }
2078
+ catch (_err) {
2079
+ // Absent is a mismatch.
2080
+ }
2081
+ if (have !== text) {
2082
+ process.stderr.write(`aontu: ${out} differs from the ${kind} figure\n`);
2083
+ return 1;
2084
+ }
2085
+ }
2086
+ else {
2087
+ (0, node_fs_1.writeFileSync)(out, text, 'utf8');
2088
+ }
2089
+ if (0 < report.loss.length) {
2090
+ process.stderr.write(renderViewLoss(report.loss) + '\n');
2091
+ }
2092
+ }
2093
+ if ('error' === report.verdict) {
2094
+ const code = report.errors[0]?.code;
2095
+ return VIEW_USAGE_CODES.includes(code) ? 2 : VIEW_EXIT.error;
2096
+ }
2097
+ return strict && 'lossy' === report.verdict ? 1 : VIEW_EXIT[report.verdict];
2098
+ }
2099
+ // `aontu view --views <path> <file>`: every figure the document
2100
+ // declares, from one evaluation, all or nothing.
2101
+ //
2102
+ // A declared `out` is resolved against the DOCUMENT's own directory,
2103
+ // not the caller's: a view document is committed beside the figures it
2104
+ // gates, and a gate that only passes from one working directory is not
2105
+ // a gate.
2106
+ function runViewSet(rest, opts, trust, how) {
2107
+ if (1 !== rest.length) {
2108
+ process.stderr.write('aontu: view --views takes one file\n');
2109
+ return 2;
2110
+ }
2111
+ if (undefined !== how.out) {
2112
+ process.stderr.write('aontu: --out is per figure in a view document; each declares its own\n');
2113
+ return 2;
2114
+ }
2115
+ const file = rest[0];
2116
+ let src;
2117
+ try {
2118
+ src = (0, node_fs_1.readFileSync)(file, 'utf8');
2119
+ }
2120
+ catch (err) {
2121
+ process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
2122
+ return 2;
2123
+ }
2124
+ const report = (0, view_1.viewSet)(src, {
2125
+ ...opts, path: file, trust: verbTrust(trust, entryRootOf(file)),
2126
+ });
2127
+ if ('json' === how.format) {
2128
+ process.stdout.write(renderViewSetJson(report) + '\n');
2129
+ }
2130
+ else if (undefined !== report.errors) {
2131
+ process.stderr.write(report.errors.map(renderFinding).join('\n') + '\n');
2132
+ }
2133
+ else {
2134
+ for (const fig of report.views) {
2135
+ if (undefined !== fig.errors) {
2136
+ process.stderr.write(`${fig.name} (${fig.kind}):\n` +
2137
+ fig.errors.map(renderFinding).join('\n') + '\n');
2138
+ }
2139
+ else if (0 < fig.loss.length) {
2140
+ process.stderr.write(renderViewLoss(fig.loss)
2141
+ .split('\n').map((l) => `${fig.name} ${l}`).join('\n') + '\n');
2142
+ }
2143
+ }
2144
+ }
2145
+ if ('error' === report.verdict) {
2146
+ return setExit(report);
2147
+ }
2148
+ // EVERY FIGURE RENDERED, so the whole set is written -- or, under
2149
+ // --check, the whole set is compared and every difference named.
2150
+ const dir = (0, node_path_1.dirname)((0, node_path_1.resolve)(file));
2151
+ let differ = 0;
2152
+ for (const fig of report.views) {
2153
+ const path = (0, node_path_1.resolve)(dir, fig.out);
2154
+ const text = fig.text + '\n';
2155
+ if (how.check) {
2156
+ let have = undefined;
2157
+ try {
2158
+ have = (0, node_fs_1.readFileSync)(path, 'utf8');
2159
+ }
2160
+ catch (_err) {
2161
+ // Absent is a mismatch.
2162
+ }
2163
+ if (have !== text) {
2164
+ differ++;
2165
+ process.stderr.write(`aontu: ${fig.out} differs from the ${fig.name} figure\n`);
2166
+ }
2167
+ }
2168
+ else {
2169
+ try {
2170
+ (0, node_fs_1.writeFileSync)(path, text, 'utf8');
2171
+ }
2172
+ catch (err) {
2173
+ process.stderr.write(`aontu: cannot write ${err.path}: ${err.message}\n`);
2174
+ return 2;
2175
+ }
2176
+ if ('json' !== how.format) {
2177
+ process.stderr.write(`wrote ${fig.out} ${fig.name} (${fig.kind})\n`);
2178
+ }
2179
+ }
2180
+ }
2181
+ if (0 < differ) {
2182
+ return 1;
2183
+ }
2184
+ return how.strict && 'lossy' === report.verdict ? 1 : VIEW_EXIT[report.verdict];
2185
+ }
2186
+ // A set's exit code is the worst of its figures': a usage refusal
2187
+ // anywhere is usage, and any other refusal is the document's fault.
2188
+ function setExit(report) {
2189
+ const codes = [
2190
+ ...(report.errors ?? []),
2191
+ ...report.views.flatMap((v) => v.errors ?? []),
2192
+ ].map((e) => e.code);
2193
+ return codes.some((c) => VIEW_USAGE_CODES.includes(c))
2194
+ ? 2 : VIEW_EXIT.error;
2195
+ }
2196
+ function renderViewSetJson(report) {
2197
+ return (0, aontu_1.exactJSON)({
2198
+ aontu: { version: version(), verb: 'view' },
2199
+ verdict: report.verdict,
2200
+ views: report.views.map((v) => ({
2201
+ name: v.name,
2202
+ kind: v.kind,
2203
+ out: v.out,
2204
+ verdict: v.verdict,
2205
+ ...(null == v.text ? {} : { text: v.text }),
2206
+ loss: v.loss,
2207
+ ...(null == v.errors ? {} : { errors: v.errors }),
2208
+ })),
2209
+ ...(null == report.errors ? {} : { errors: report.errors }),
2210
+ }, 2);
2211
+ }
2212
+ // One line per code: the code, the count, and the detail if any.
2213
+ function renderViewLoss(loss) {
2214
+ return loss.map((l) => `${l.code} ${l.count}` +
2215
+ (undefined === l.detail ? '' : ' ' + l.detail.join(' '))).join('\n');
2216
+ }
2217
+ function renderViewJson(report) {
2218
+ return (0, aontu_1.exactJSON)({
2219
+ aontu: { version: version(), verb: 'view' },
2220
+ kind: report.kind,
2221
+ verdict: report.verdict,
2222
+ ...(null == report.text ? {} : { text: report.text }),
2223
+ loss: report.loss,
2224
+ ...(null == report.errors ? {} : { errors: report.errors }),
2225
+ }, 2);
2226
+ }
1735
2227
  function renderRelationsText(report) {
1736
2228
  const head = `verdict: ${report.verdict}`;
1737
2229
  // WHY, when the document could not be evaluated at all: rendered as
@@ -1745,11 +2237,8 @@ function renderRelationsText(report) {
1745
2237
  }
1746
2238
  const lines = report.findings.map((f) => 'relation_cycle' === f.code
1747
2239
  ? `${f.at} ${f.relation}: cycle ${f.detail.join(' -> ')}`
1748
- : 'relation_target_unmet' === f.code
1749
- ? `${f.at} ${f.relation}: ${f.detail[1]} is not what ` +
1750
- `${f.relation} targets (${f.detail[2]})`
1751
- : `${f.at} ${f.relation}: ${f.detail[1]} does not list ` +
1752
- `${f.detail[0]} under ${f.detail[2]}`);
2240
+ : `${f.at} ${f.relation}: ${f.detail[1]} does not list ` +
2241
+ `${f.detail[0]} under ${f.detail[2]}`);
1753
2242
  return [head, ''].concat(lines).join('\n');
1754
2243
  }
1755
2244
  function renderRelationsJson(report) {
@@ -2468,6 +2957,9 @@ function main(argv) {
2468
2957
  if ('reaches' === argv[2]) {
2469
2958
  return finish(runReaches(argv.slice(3)));
2470
2959
  }
2960
+ if ('view' === argv[2]) {
2961
+ return finish(runView(argv.slice(3)));
2962
+ }
2471
2963
  if ('trim' === argv[2]) {
2472
2964
  return finish(runTrim(argv.slice(3)));
2473
2965
  }
@@ -2546,5 +3038,5 @@ function main(argv) {
2546
3038
  else {
2547
3039
  runStdin(mode, trust).then((code) => finish(code));
2548
3040
  }
2549
- } /* node:coverage ignore next 15 */
3041
+ } /* node:coverage ignore next 16 */
2550
3042
  //# sourceMappingURL=cli.js.map