aontu 0.65.0 → 0.66.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.
package/dist/aontu.d.ts CHANGED
@@ -23,7 +23,7 @@ import { loadProfile } from './profile';
23
23
  import { desugarTemplate, resugarTemplate, markerFor } from './template';
24
24
  import { format, unifiedDiff } from './format';
25
25
  export type { LintFinding, FormatReport, FormatOptions } from './format';
26
- declare const VERSION = "0.65.0";
26
+ declare const VERSION = "0.66.0";
27
27
  declare class Aontu {
28
28
  opts: AontuOptions;
29
29
  lang: Lang;
package/dist/aontu.js CHANGED
@@ -58,7 +58,7 @@ Object.defineProperty(exports, "markerFor", { enumerable: true, get: function ()
58
58
  const format_1 = require("./format");
59
59
  Object.defineProperty(exports, "format", { enumerable: true, get: function () { return format_1.format; } });
60
60
  Object.defineProperty(exports, "unifiedDiff", { enumerable: true, get: function () { return format_1.unifiedDiff; } });
61
- const VERSION = '0.65.0';
61
+ const VERSION = '0.66.0';
62
62
  exports.VERSION = VERSION;
63
63
  function genQuiet(val, aontu) {
64
64
  return val.gen(aontu.ctx({ collect: true }));
package/dist/cli.d.ts CHANGED
@@ -49,6 +49,7 @@ declare function runPackageVerb(verb: string, argv: string[], servers: Servers):
49
49
  declare function runModel(argv: string[]): number;
50
50
  declare function runRelations(argv: string[]): number;
51
51
  declare function runTrace(argv: string[]): number;
52
+ declare function runRender(argv: string[]): Promise<number>;
52
53
  declare function runReaches(argv: string[]): number;
53
54
  declare function runView(argv: string[]): number;
54
55
  declare function runJsonSchema(argv: string[]): number;
@@ -80,4 +81,4 @@ declare const KNOWN_VERBS: string[];
80
81
  declare function looksLikeVerb(arg: string): boolean;
81
82
  declare function nearestVerb(word: string, verbs: string[]): string;
82
83
  declare function main(argv: string[], servers?: Servers): void;
83
- export { evalSource, main, runVet, runSubsume, runBreaking, runTrim, runRelations, runReaches, runView, runJsonSchema, runTemplate, runTrace, runPkg, runModel, runPackageVerb, pkgToolOptions, serveUntilInterrupted, runHash, runGet, runHelp, runExplain, runInit, nearestVerb, looksLikeVerb, KNOWN_VERBS, runWhy, renderWhyText, runSet, runAllow, runAgentsMd, runFmt, watchChange, watchSignature, vetWaiter, deprecatedAt, };
84
+ export { evalSource, main, runVet, runSubsume, runBreaking, runTrim, runRelations, runReaches, runView, runJsonSchema, runTemplate, runTrace, runRender, runPkg, runModel, runPackageVerb, pkgToolOptions, serveUntilInterrupted, runHash, runGet, runHelp, runExplain, runInit, nearestVerb, looksLikeVerb, KNOWN_VERBS, runWhy, renderWhyText, runSet, runAllow, runAgentsMd, runFmt, watchChange, watchSignature, vetWaiter, deprecatedAt, };
package/dist/cli.js CHANGED
@@ -15,6 +15,7 @@ exports.runView = runView;
15
15
  exports.runJsonSchema = runJsonSchema;
16
16
  exports.runTemplate = runTemplate;
17
17
  exports.runTrace = runTrace;
18
+ exports.runRender = runRender;
18
19
  exports.runPkg = runPkg;
19
20
  exports.runModel = runModel;
20
21
  exports.runPackageVerb = runPackageVerb;
@@ -76,6 +77,9 @@ const HELP = `Usage: aontu [options] [file]
76
77
  [--profile <file>] <file>
77
78
  aontu trace [--at <path>] [--format json] [--marker <token>]
78
79
  [--profile <file>] <file>
80
+ aontu render [--check] [--at <path>] [--format json]
81
+ [--marker <token>] [--profile <file>]
82
+ <file|folder> <path>
79
83
  aontu hash [options] <file>
80
84
  aontu sync [--frozen] [options] [dir]
81
85
  aontu add <pkg>[@<version>] [options] [dir]
@@ -390,6 +394,31 @@ every other line is a line of output.
390
394
 
391
395
  Template exit codes: 0 written, 1 --check drift, 2 usage or I/O.
392
396
 
397
+ Render options:
398
+ --check Compare what the generator writes with what <path>
399
+ holds, write nothing, and exit 1 on drift
400
+ --at <path> Where the component tree lives in the document
401
+ (default $.out)
402
+ --format json Print the files written, or the drift, as JSON
403
+ --marker <t> The file is a generator, and this is its marker
404
+ (default //-, and #- --- /*- <!--- by extension)
405
+ --profile <f> A profile file, whose template.ext names the
406
+ extensions it marks and template.marker the marker
407
+
408
+ The render verb writes the component tree a generator answers. The
409
+ tree is handed to jostraca, the generator runtime, which writes the
410
+ files: a tree that is one file is written to <path> itself, unless
411
+ <path> is a directory, and any other tree is written below <path>.
412
+ With --check nothing is written and <path> is compared with what the
413
+ generator writes, one "kind: file" line per difference.
414
+ A folder as the generator is a set: every regular file directly in
415
+ it, dotfiles aside, in name order, and their trees are written below
416
+ <path> as one run, so a path two of them claim is refused. A file with
417
+ no marker line in it is refused by name.
418
+
419
+ Render exit codes: 0 written or clean, 1 --check drift, 2 usage or
420
+ I/O, 4 the document does not stand up, or --at names nothing.
421
+
393
422
  Model set options:
394
423
  --entry <file> The document the change is checked against
395
424
  --overlay <file> The file the change is appended to (created if
@@ -2446,6 +2475,192 @@ function runTrace(argv) {
2446
2475
  }
2447
2476
  return 0;
2448
2477
  }
2478
+ // ---------------------------------------------------------------------
2479
+ // The writer (ADR-040). A generator answers a component tree; this verb
2480
+ // hands it to jostraca, which writes the files below a path or holds
2481
+ // them to it.
2482
+ const RENDER_HELP = 'aontu render [--check] [--at <path>] [--format json] ' +
2483
+ '[--marker <token>] [--profile <file>] <file|folder> <path> (try --help)';
2484
+ // Loaded at the call, so every other verb starts without it.
2485
+ function generatorRuntime() {
2486
+ return require('jostraca');
2487
+ }
2488
+ function isDirectory(path) {
2489
+ return true === (0, node_fs_1.statSync)(path, { throwIfNoEntry: false })?.isDirectory();
2490
+ }
2491
+ async function runRender(argv) {
2492
+ const trusted = takeTrust(argv);
2493
+ if (null == trusted) {
2494
+ return 2;
2495
+ }
2496
+ argv = trusted.argv;
2497
+ const trust = trusted.trust;
2498
+ const rest = [];
2499
+ const profileFiles = [];
2500
+ let format = 'text';
2501
+ let at = undefined;
2502
+ let marker = undefined;
2503
+ let check = false;
2504
+ for (let i = 0; i < argv.length; i++) {
2505
+ const arg = argv[i];
2506
+ if ('-h' === arg || '--help' === arg) {
2507
+ process.stdout.write(HELP);
2508
+ return 0;
2509
+ }
2510
+ if ('--check' === arg) {
2511
+ check = true;
2512
+ }
2513
+ else if ('--format' === arg) {
2514
+ const f = argv[++i];
2515
+ if ('text' !== f && 'json' !== f) {
2516
+ process.stderr.write('aontu: --format needs text or json\n');
2517
+ return 2;
2518
+ }
2519
+ format = f;
2520
+ }
2521
+ else if ('--at' === arg) {
2522
+ at = argv[++i];
2523
+ if (null == at || '' === at) {
2524
+ process.stderr.write('aontu: --at needs a path\n');
2525
+ return 2;
2526
+ }
2527
+ }
2528
+ else if ('--marker' === arg) {
2529
+ marker = argv[++i];
2530
+ if (null == marker || '' === marker) {
2531
+ process.stderr.write('aontu: --marker needs a token\n');
2532
+ return 2;
2533
+ }
2534
+ }
2535
+ else if ('--profile' === arg) {
2536
+ const pf = argv[++i];
2537
+ if (null == pf || '' === pf) {
2538
+ process.stderr.write('aontu: --profile needs a file\n');
2539
+ return 2;
2540
+ }
2541
+ profileFiles.push(pf);
2542
+ }
2543
+ else if (arg.startsWith('-')) {
2544
+ process.stderr.write(`aontu: unknown render option ${arg} (try --help)\n`);
2545
+ return 2;
2546
+ }
2547
+ else {
2548
+ rest.push(arg);
2549
+ }
2550
+ }
2551
+ if (2 !== rest.length) {
2552
+ process.stderr.write(`aontu: render needs a file and a path\n${RENDER_HELP}\n`);
2553
+ return 2;
2554
+ }
2555
+ const [file, dest] = rest;
2556
+ const declared = loadProfiles(profileFiles, trust);
2557
+ if ('number' === typeof declared) {
2558
+ return declared;
2559
+ }
2560
+ // A FOLDER IS A SET OF GENERATORS: every regular file directly in it,
2561
+ // dotfiles aside, in code-point order, written as one tree.
2562
+ let entries;
2563
+ try {
2564
+ entries = (0, node_fs_1.readdirSync)(file, { withFileTypes: true });
2565
+ }
2566
+ catch (err) {
2567
+ entries = undefined;
2568
+ }
2569
+ const set = undefined !== entries;
2570
+ const files = undefined === entries ? [file] :
2571
+ entries.filter((e) => e.isFile() && !e.name.startsWith('.'))
2572
+ .map((e) => e.name).sort(keyorder_1.cmpCodePoint).map((n) => (0, node_path_1.join)(file, n));
2573
+ if (0 === files.length) {
2574
+ process.stderr.write(`aontu: ${file} holds no generator\n`);
2575
+ return 2;
2576
+ }
2577
+ const trees = [];
2578
+ for (const f of files) {
2579
+ let src;
2580
+ try {
2581
+ src = (0, node_fs_1.readFileSync)(f, 'utf8');
2582
+ }
2583
+ catch (err) {
2584
+ process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
2585
+ return 2;
2586
+ }
2587
+ if (!/[.](aon|aontu)$/.test(f)) {
2588
+ const mark = marker ?? (0, template_1.markerFromProfiles)(declared, f) ?? (0, template_1.markerFor)(f);
2589
+ if (!(0, template_1.templateOutputs)(src, mark).some((out) => !out)) {
2590
+ process.stderr.write(`aontu: ${f} carries no ${mark} marker line, ` +
2591
+ 'so there is no aontu in it to render\n');
2592
+ return 2;
2593
+ }
2594
+ src = (0, template_1.desugarTemplate)(src, mark);
2595
+ }
2596
+ const report = (0, aontu_1.get)(src, at ?? '$.out', {
2597
+ view: 'json', path: f, ...verbOpts(trust, entryRootOf(f)),
2598
+ });
2599
+ if (!report.ok) {
2600
+ process.stderr.write(report.findings.map(renderFinding).join('\n') + '\n');
2601
+ return 4;
2602
+ }
2603
+ const tree = JSON.parse(report.out);
2604
+ // A `File` without a name is refused: the runtime ports disagree
2605
+ // about it.
2606
+ if ('File' === tree?.cmp && 'string' !== typeof tree.props?.name) {
2607
+ process.stderr.write(`aontu: ${f}: the file at ${at ?? '$.out'} has no name\n`);
2608
+ return 4;
2609
+ }
2610
+ trees.push(tree);
2611
+ }
2612
+ // ONE FILE GOES TO THE PATH ITSELF, unless the path is a directory; a
2613
+ // set is written below the path whatever its trees are.
2614
+ let folder = dest;
2615
+ const tree = set ? trees.flatMap((t) => Array.isArray(t) ? t : [t]) : trees[0];
2616
+ if (!set && 'File' === tree?.cmp && !isDirectory(dest)) {
2617
+ tree.props.name = (0, node_path_1.basename)(dest);
2618
+ folder = (0, node_path_1.dirname)(dest);
2619
+ }
2620
+ const { cmpTree, Jostraca } = generatorRuntime();
2621
+ let root;
2622
+ try {
2623
+ root = cmpTree(tree, { raw: true });
2624
+ }
2625
+ catch (err) {
2626
+ process.stderr.write(`aontu: ${file}: ${err.message}\n`);
2627
+ return 4;
2628
+ }
2629
+ const runtime = Jostraca();
2630
+ try {
2631
+ if (check) {
2632
+ const res = await runtime.check({ folder }, root);
2633
+ const drift = res.drift.map((d) => ({ kind: d.kind, path: d.path }));
2634
+ if ('json' === format) {
2635
+ process.stdout.write((0, aontu_1.exactJSON)({
2636
+ aontu: { version: version(), verb: 'render' },
2637
+ verdict: 0 === drift.length ? 'ok' : 'drift',
2638
+ checked: res.checked,
2639
+ drift,
2640
+ }, 2) + '\n');
2641
+ }
2642
+ else {
2643
+ for (const d of drift) {
2644
+ process.stdout.write(`${d.kind}: ${d.path}\n`);
2645
+ }
2646
+ }
2647
+ return 0 === drift.length ? 0 : 1;
2648
+ }
2649
+ const res = await runtime.generate({ folder }, root);
2650
+ if ('json' === format) {
2651
+ process.stdout.write((0, aontu_1.exactJSON)({
2652
+ aontu: { version: version(), verb: 'render' },
2653
+ verdict: 'ok',
2654
+ files: res.files,
2655
+ }, 2) + '\n');
2656
+ }
2657
+ return 0;
2658
+ }
2659
+ catch (err) {
2660
+ process.stderr.write(`aontu: ${err.message}\n`);
2661
+ return 2;
2662
+ }
2663
+ }
2449
2664
  function runReaches(argv) {
2450
2665
  const trusted = takeTrust(argv);
2451
2666
  if (null == trusted) {
@@ -4191,8 +4406,8 @@ function runInit(argv) {
4191
4406
  const KNOWN_VERBS = [
4192
4407
  'add', 'agentsmd', 'allow', 'breaking', 'explain', 'fmt', 'get', 'hash',
4193
4408
  'help', 'init', 'jsonschema', 'lsp', 'mcp', 'model', 'pkg', 'publish',
4194
- 'reaches', 'relations', 'remove', 'subsume', 'sync', 'template', 'trace',
4195
- 'trim', 'vet', 'view', 'why',
4409
+ 'reaches', 'relations', 'remove', 'render', 'subsume', 'sync', 'template',
4410
+ 'trace', 'trim', 'vet', 'view', 'why',
4196
4411
  ];
4197
4412
  exports.KNOWN_VERBS = KNOWN_VERBS;
4198
4413
  // looksLikeVerb reports whether an unreadable argument was meant as a
@@ -4316,6 +4531,9 @@ function main(argv, servers = SERVERS) {
4316
4531
  if ('trace' === argv[2]) {
4317
4532
  return finish(runTrace(argv.slice(3)));
4318
4533
  }
4534
+ if ('render' === argv[2]) {
4535
+ return void runRender(argv.slice(3)).then(finish);
4536
+ }
4319
4537
  if ('reaches' === argv[2]) {
4320
4538
  return finish(runReaches(argv.slice(3)));
4321
4539
  }