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.
- package/README.md +7 -7
- package/dist/agentsmd.js +0 -27
- package/dist/agentsmd.js.map +1 -1
- package/dist/alias.js.map +1 -1
- package/dist/allow.js +0 -92
- package/dist/allow.js.map +1 -1
- package/dist/aontu.d.ts +3 -3
- package/dist/aontu.js +4 -84
- package/dist/aontu.js.map +1 -1
- package/dist/aontumodel.d.ts +4 -0
- package/dist/aontumodel.js +27 -0
- package/dist/aontumodel.js.map +1 -0
- package/dist/casing.d.ts +5 -0
- package/dist/casing.js +90 -0
- package/dist/casing.js.map +1 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +228 -935
- package/dist/cli.js.map +1 -1
- package/dist/ctx.js +0 -48
- package/dist/ctx.js.map +1 -1
- package/dist/diff.js +0 -32
- package/dist/diff.js.map +1 -1
- package/dist/err.js +0 -40
- package/dist/err.js.map +1 -1
- package/dist/escape.js +0 -45
- package/dist/escape.js.map +1 -1
- package/dist/exactjson.d.ts +0 -35
- package/dist/exactjson.js +0 -131
- package/dist/exactjson.js.map +1 -1
- package/dist/format.js +13 -203
- package/dist/format.js.map +1 -1
- package/dist/grammar.d.ts +9 -0
- package/dist/grammar.js +54 -0
- package/dist/grammar.js.map +1 -0
- package/dist/graph.js +0 -26
- package/dist/graph.js.map +1 -1
- package/dist/hcanon.js +0 -82
- package/dist/hcanon.js.map +1 -1
- package/dist/helpdoc.js +2 -2
- package/dist/helpdoc.js.map +1 -1
- package/dist/hints.d.ts +0 -6
- package/dist/hints.js +57 -55
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.js +0 -114
- package/dist/jsonschema.js.map +1 -1
- package/dist/keyorder.d.ts +0 -7
- package/dist/keyorder.js +0 -41
- package/dist/keyorder.js.map +1 -1
- package/dist/lang.js +17 -915
- package/dist/lang.js.map +1 -1
- package/dist/lsp-server.js +0 -16
- package/dist/lsp-server.js.map +1 -1
- package/dist/lsp.d.ts +1 -1
- package/dist/lsp.js +12 -159
- package/dist/lsp.js.map +1 -1
- package/dist/mcp-server.js +0 -26
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp.js +0 -149
- package/dist/mcp.js.map +1 -1
- package/dist/mod-tool.js +16 -131
- package/dist/mod-tool.js.map +1 -1
- package/dist/mod.js +0 -162
- package/dist/mod.js.map +1 -1
- package/dist/patch.js +0 -217
- package/dist/patch.js.map +1 -1
- package/dist/profile.d.ts +9 -0
- package/dist/profile.js +28 -0
- package/dist/profile.js.map +1 -0
- package/dist/provenance.js +0 -140
- package/dist/provenance.js.map +1 -1
- package/dist/query.js +0 -75
- package/dist/query.js.map +1 -1
- package/dist/reach.js +0 -43
- package/dist/reach.js.map +1 -1
- package/dist/relation.js +0 -61
- package/dist/relation.js.map +1 -1
- package/dist/report-sarif.d.ts +0 -11
- package/dist/report-sarif.js +0 -28
- package/dist/report-sarif.js.map +1 -1
- package/dist/sig.js +0 -35
- package/dist/sig.js.map +1 -1
- package/dist/sigdecl.js +1 -1
- package/dist/sigdecl.js.map +1 -1
- package/dist/siggate.js +0 -4
- package/dist/siggate.js.map +1 -1
- package/dist/site.js +3 -29
- package/dist/site.js.map +1 -1
- package/dist/subsume.d.ts +0 -10
- package/dist/subsume.js +0 -137
- package/dist/subsume.js.map +1 -1
- package/dist/template.d.ts +2 -1
- package/dist/template.js +58 -138
- package/dist/template.js.map +1 -1
- package/dist/trace.d.ts +21 -0
- package/dist/trace.js +107 -0
- package/dist/trace.js.map +1 -0
- package/dist/trim.js +0 -41
- package/dist/trim.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.js.map +1 -1
- package/dist/unify.js +13 -248
- package/dist/unify.js.map +1 -1
- package/dist/utility.js +0 -22
- package/dist/utility.js.map +1 -1
- package/dist/val/AbnfFuncVal.d.ts +18 -0
- package/dist/val/AbnfFuncVal.js +132 -0
- package/dist/val/AbnfFuncVal.js.map +1 -0
- package/dist/val/AbsentVal.d.ts +11 -0
- package/dist/val/AbsentVal.js +30 -0
- package/dist/val/AbsentVal.js.map +1 -0
- package/dist/val/AggFuncVal.d.ts +10 -1
- package/dist/val/AggFuncVal.js +104 -116
- package/dist/val/AggFuncVal.js.map +1 -1
- package/dist/val/ArithFuncVal.js +0 -12
- package/dist/val/ArithFuncVal.js.map +1 -1
- package/dist/val/BagVal.js +1 -78
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/BigDecimalVal.js +0 -16
- package/dist/val/BigDecimalVal.js.map +1 -1
- package/dist/val/BigIntegerVal.js +0 -16
- package/dist/val/BigIntegerVal.js.map +1 -1
- package/dist/val/CloseFuncVal.js +0 -9
- package/dist/val/CloseFuncVal.js.map +1 -1
- package/dist/val/CmpFuncVal.d.ts +2 -0
- package/dist/val/CmpFuncVal.js +49 -72
- package/dist/val/CmpFuncVal.js.map +1 -1
- package/dist/val/ConjunctVal.js +0 -29
- package/dist/val/ConjunctVal.js.map +1 -1
- package/dist/val/ConstraintVal.js +0 -500
- package/dist/val/ConstraintVal.js.map +1 -1
- package/dist/val/ContainerKindVal.js +0 -2
- package/dist/val/ContainerKindVal.js.map +1 -1
- package/dist/val/CopyFuncVal.js +0 -3
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/Decimal.js +0 -179
- package/dist/val/Decimal.js.map +1 -1
- package/dist/val/DeprecateFuncVal.js.map +1 -1
- package/dist/val/DisjunctVal.js +0 -152
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/EachFuncVal.js +0 -3
- package/dist/val/EachFuncVal.js.map +1 -1
- package/dist/val/EmitFuncVal.d.ts +1 -1
- package/dist/val/EmitFuncVal.js +6 -119
- package/dist/val/EmitFuncVal.js.map +1 -1
- package/dist/val/ExpectVal.js +0 -62
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FilterFuncVal.js +0 -25
- package/dist/val/FilterFuncVal.js.map +1 -1
- package/dist/val/FuncBaseVal.d.ts +1 -0
- package/dist/val/FuncBaseVal.js +7 -127
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/GraphAtomVal.js +0 -15
- package/dist/val/GraphAtomVal.js.map +1 -1
- package/dist/val/HideFuncVal.js +0 -13
- package/dist/val/HideFuncVal.js.map +1 -1
- package/dist/val/IntegerVal.js +0 -61
- package/dist/val/IntegerVal.js.map +1 -1
- package/dist/val/JunctionVal.js +0 -20
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/KeyFuncVal.js +0 -46
- package/dist/val/KeyFuncVal.js.map +1 -1
- package/dist/val/ListVal.js +0 -57
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js +0 -11
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.js +0 -151
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MatchFuncVal.js +0 -27
- package/dist/val/MatchFuncVal.js.map +1 -1
- package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
- package/dist/val/MaybeFuncVal.js +50 -0
- package/dist/val/MaybeFuncVal.js.map +1 -0
- package/dist/val/MoveFuncVal.js +0 -18
- package/dist/val/MoveFuncVal.js.map +1 -1
- package/dist/val/NilVal.js +0 -60
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/NomFuncVal.js +18 -54
- package/dist/val/NomFuncVal.js.map +1 -1
- package/dist/val/NumberVal.js +0 -15
- package/dist/val/NumberVal.js.map +1 -1
- package/dist/val/OpBaseVal.d.ts +1 -0
- package/dist/val/OpBaseVal.js +3 -15
- package/dist/val/OpBaseVal.js.map +1 -1
- package/dist/val/PackFuncVal.js +0 -34
- package/dist/val/PackFuncVal.js.map +1 -1
- package/dist/val/PathFuncVal.js +0 -6
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PathVal.js +0 -41
- package/dist/val/PathVal.js.map +1 -1
- package/dist/val/PlaceVal.js +0 -25
- package/dist/val/PlaceVal.js.map +1 -1
- package/dist/val/PlusOpVal.d.ts +1 -7
- package/dist/val/PlusOpVal.js +13 -74
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefFuncVal.js +0 -1
- package/dist/val/PrefFuncVal.js.map +1 -1
- package/dist/val/PrefVal.js +0 -167
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RecurseVal.js +0 -55
- package/dist/val/RecurseVal.js.map +1 -1
- package/dist/val/RefVal.js +0 -282
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.js +3 -232
- package/dist/val/ReferFuncVal.js.map +1 -1
- package/dist/val/ScalarKindVal.js +0 -49
- package/dist/val/ScalarKindVal.js.map +1 -1
- package/dist/val/ScalarVal.js +0 -11
- package/dist/val/ScalarVal.js.map +1 -1
- package/dist/val/StrFuncVal.js +0 -18
- package/dist/val/StrFuncVal.js.map +1 -1
- package/dist/val/SuperFuncVal.js +0 -32
- package/dist/val/SuperFuncVal.js.map +1 -1
- package/dist/val/TopVal.js +0 -1
- package/dist/val/TopVal.js.map +1 -1
- package/dist/val/TranslateFuncVal.js +1 -3
- package/dist/val/TranslateFuncVal.js.map +1 -1
- package/dist/val/UpperFuncVal.js +0 -11
- package/dist/val/UpperFuncVal.js.map +1 -1
- package/dist/val/Val.d.ts +1 -0
- package/dist/val/Val.js +2 -133
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js +0 -12
- package/dist/val/VarVal.js.map +1 -1
- package/dist/val/arith.js +0 -37
- package/dist/val/arith.js.map +1 -1
- package/dist/val/caserange.js +0 -61
- package/dist/val/caserange.js.map +1 -1
- package/dist/val/members.js +0 -6
- package/dist/val/members.js.map +1 -1
- package/dist/val/numcmp.js +0 -11
- package/dist/val/numcmp.js.map +1 -1
- package/dist/val/numkind.js +0 -145
- package/dist/val/numkind.js.map +1 -1
- package/dist/val/valutil.js +0 -16
- package/dist/val/valutil.js.map +1 -1
- package/dist/vet.js +0 -461
- package/dist/vet.js.map +1 -1
- package/dist/view.js +0 -414
- package/dist/view.js.map +1 -1
- package/dist/walk.js +0 -41
- package/dist/walk.js.map +1 -1
- package/grammar/aontu.abnf +8 -6
- package/grammar/aontu.gbnf +4 -4
- package/grammar/aontu.lark +4 -4
- package/grammar/aontu.tmLanguage.json +1 -1
- package/package.json +4 -2
- package/skill/tasks.md +9 -7
- package/src/agentsmd.ts +0 -35
- package/src/alias.ts +0 -39
- package/src/allow.ts +1 -96
- package/src/aontu.ts +4 -116
- package/src/aontumodel.ts +26 -0
- package/src/casing.ts +95 -0
- package/src/cli.ts +258 -1024
- package/src/ctx.ts +0 -103
- package/src/diff.ts +0 -40
- package/src/err.ts +0 -40
- package/src/escape.ts +0 -46
- package/src/exactjson.ts +0 -131
- package/src/format.ts +14 -257
- package/src/grammar.ts +72 -0
- package/src/graph.ts +0 -61
- package/src/hcanon.ts +0 -82
- package/src/helpdoc.ts +2 -2
- package/src/hints.ts +69 -57
- package/src/jsonschema.ts +0 -123
- package/src/keyorder.ts +0 -42
- package/src/lang.ts +19 -931
- package/src/lsp-server.ts +0 -16
- package/src/lsp.ts +12 -180
- package/src/mcp-server.ts +0 -31
- package/src/mcp.ts +0 -169
- package/src/mod-tool.ts +18 -159
- package/src/mod.ts +0 -178
- package/src/patch.ts +0 -232
- package/src/profile.ts +42 -0
- package/src/provenance.ts +0 -183
- package/src/query.ts +0 -84
- package/src/reach.ts +0 -53
- package/src/relation.ts +0 -84
- package/src/report-sarif.ts +0 -48
- package/src/sig.ts +0 -35
- package/src/sigdecl.ts +1 -1
- package/src/siggate.ts +0 -30
- package/src/site.ts +3 -29
- package/src/subsume.ts +1 -161
- package/src/template.ts +69 -140
- package/src/trace.ts +157 -0
- package/src/trim.ts +0 -53
- package/src/type.ts +2 -45
- package/src/unify.ts +14 -257
- package/src/utility.ts +0 -31
- package/src/val/AbnfFuncVal.ts +181 -0
- package/src/val/AbsentVal.ts +54 -0
- package/src/val/AggFuncVal.ts +152 -188
- package/src/val/ArithFuncVal.ts +0 -20
- package/src/val/BagVal.ts +1 -78
- package/src/val/BigDecimalVal.ts +0 -16
- package/src/val/BigIntegerVal.ts +0 -16
- package/src/val/CloseFuncVal.ts +0 -9
- package/src/val/CmpFuncVal.ts +68 -184
- package/src/val/ConjunctVal.ts +0 -33
- package/src/val/ConstraintVal.ts +2 -537
- package/src/val/ContainerKindVal.ts +0 -18
- package/src/val/CopyFuncVal.ts +0 -5
- package/src/val/Decimal.ts +1 -185
- package/src/val/DeprecateFuncVal.ts +0 -10
- package/src/val/DisjunctVal.ts +0 -157
- package/src/val/EachFuncVal.ts +0 -40
- package/src/val/EmitFuncVal.ts +8 -208
- package/src/val/ExpectVal.ts +0 -62
- package/src/val/FilterFuncVal.ts +0 -55
- package/src/val/FuncBaseVal.ts +9 -130
- package/src/val/GraphAtomVal.ts +0 -42
- package/src/val/HideFuncVal.ts +0 -15
- package/src/val/IntegerVal.ts +0 -61
- package/src/val/JunctionVal.ts +0 -20
- package/src/val/KeyFuncVal.ts +0 -48
- package/src/val/ListVal.ts +0 -59
- package/src/val/LowerFuncVal.ts +0 -12
- package/src/val/MapVal.ts +0 -151
- package/src/val/MatchFuncVal.ts +0 -59
- package/src/val/MaybeFuncVal.ts +86 -0
- package/src/val/MoveFuncVal.ts +0 -20
- package/src/val/NilVal.ts +0 -60
- package/src/val/NomFuncVal.ts +10 -99
- package/src/val/NumberVal.ts +0 -16
- package/src/val/OpBaseVal.ts +4 -17
- package/src/val/PackFuncVal.ts +0 -63
- package/src/val/PathFuncVal.ts +0 -32
- package/src/val/PathVal.ts +0 -66
- package/src/val/PlaceVal.ts +0 -45
- package/src/val/PlusOpVal.ts +18 -75
- package/src/val/PrefFuncVal.ts +0 -1
- package/src/val/PrefVal.ts +0 -179
- package/src/val/RecurseVal.ts +0 -81
- package/src/val/RefVal.ts +1 -285
- package/src/val/ReferFuncVal.ts +4 -255
- package/src/val/ScalarKindVal.ts +0 -50
- package/src/val/ScalarVal.ts +0 -12
- package/src/val/StrFuncVal.ts +0 -44
- package/src/val/SuperFuncVal.ts +0 -42
- package/src/val/TopVal.ts +0 -1
- package/src/val/TranslateFuncVal.ts +1 -51
- package/src/val/UpperFuncVal.ts +0 -12
- package/src/val/Val.ts +3 -192
- package/src/val/VarVal.ts +0 -15
- package/src/val/arith.ts +0 -92
- package/src/val/caserange.ts +0 -62
- package/src/val/members.ts +0 -23
- package/src/val/numcmp.ts +1 -27
- package/src/val/numkind.ts +0 -149
- package/src/val/valutil.ts +0 -16
- package/src/vet.ts +1 -582
- package/src/view.ts +0 -507
- package/src/walk.ts +0 -41
- package/dist/lower.d.ts +0 -23
- package/dist/lower.js +0 -578
- package/dist/lower.js.map +0 -1
- package/dist/render.d.ts +0 -53
- package/dist/render.js +0 -547
- package/dist/render.js.map +0 -1
- package/dist/std.d.ts +0 -3
- package/dist/std.js +0 -672
- package/dist/std.js.map +0 -1
- package/dist/val/FormFuncVal.js +0 -55
- package/dist/val/FormFuncVal.js.map +0 -1
- package/dist/val/NamerFuncVal.d.ts +0 -12
- package/dist/val/NamerFuncVal.js +0 -176
- package/dist/val/NamerFuncVal.js.map +0 -1
- package/src/lower.ts +0 -636
- package/src/render.ts +0 -732
- package/src/std.ts +0 -683
package/dist/cli.js
CHANGED
|
@@ -13,8 +13,8 @@ exports.runRelations = runRelations;
|
|
|
13
13
|
exports.runReaches = runReaches;
|
|
14
14
|
exports.runView = runView;
|
|
15
15
|
exports.runJsonSchema = runJsonSchema;
|
|
16
|
-
exports.runRender = runRender;
|
|
17
16
|
exports.runTemplate = runTemplate;
|
|
17
|
+
exports.runTrace = runTrace;
|
|
18
18
|
exports.runMod = runMod;
|
|
19
19
|
exports.runHash = runHash;
|
|
20
20
|
exports.runGet = runGet;
|
|
@@ -32,13 +32,6 @@ exports.runFmt = runFmt;
|
|
|
32
32
|
exports.watchChange = watchChange;
|
|
33
33
|
exports.watchSignature = watchSignature;
|
|
34
34
|
exports.deprecatedAt = deprecatedAt;
|
|
35
|
-
// Command-line interface for Aontu.
|
|
36
|
-
//
|
|
37
|
-
// aontu [options] [file]
|
|
38
|
-
//
|
|
39
|
-
// With a file argument, the file is evaluated and the result printed.
|
|
40
|
-
// With no file on an interactive terminal, a REPL is started. With no
|
|
41
|
-
// file and piped input, the source is read from stdin. See HELP below.
|
|
42
35
|
// Named imports, not `import * as`: the namespace form makes tsc emit the
|
|
43
36
|
const query_1 = require("./query");
|
|
44
37
|
// __importStar downlevel helper, whose branches no supported Node takes.
|
|
@@ -47,8 +40,8 @@ const node_path_1 = require("node:path");
|
|
|
47
40
|
const node_os_1 = require("node:os");
|
|
48
41
|
const node_readline_1 = require("node:readline");
|
|
49
42
|
const aontu_1 = require("./aontu");
|
|
43
|
+
const trace_1 = require("./trace");
|
|
50
44
|
const template_1 = require("./template");
|
|
51
|
-
const mcp_1 = require("./mcp");
|
|
52
45
|
const report_sarif_1 = require("./report-sarif");
|
|
53
46
|
const lsp_server_1 = require("./lsp-server");
|
|
54
47
|
const mcp_server_1 = require("./mcp-server");
|
|
@@ -74,10 +67,10 @@ const HELP = `Usage: aontu [options] [file]
|
|
|
74
67
|
aontu view <kind> [options] <file>...
|
|
75
68
|
aontu view --views <path> [--check] [options] <file>
|
|
76
69
|
aontu jsonschema [--at <path>] [--strict] [options] <file>
|
|
77
|
-
aontu
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
70
|
+
aontu template [--resugar] [--check] [--marker <token>]
|
|
71
|
+
[--profile <file>] <file>
|
|
72
|
+
aontu trace [--at <path>] [--format json] [--marker <token>]
|
|
73
|
+
[--profile <file>] <file>
|
|
81
74
|
aontu hash [options] <file>
|
|
82
75
|
aontu mod tidy|verify|vendor|manifest [options] [dir]
|
|
83
76
|
aontu get <path> [options] <file>
|
|
@@ -85,7 +78,8 @@ const HELP = `Usage: aontu [options] [file]
|
|
|
85
78
|
aontu set <path>=<value>... --entry <file> --overlay <file>
|
|
86
79
|
aontu allow --role <role> [--at <path>] <roles-file> <path>...
|
|
87
80
|
aontu agentsmd [--write <AGENTS.md>] [--depth <n>] <file>
|
|
88
|
-
aontu fmt [-w|-l|--check|-d|--lint] [--marker <token>]
|
|
81
|
+
aontu fmt [-w|-l|--check|-d|--lint] [--marker <token>]
|
|
82
|
+
[--profile <file>] <file>...
|
|
89
83
|
aontu help [topic] [--format text|json]
|
|
90
84
|
aontu explain <code> | --list [--format text|json]
|
|
91
85
|
aontu init [dir]
|
|
@@ -322,36 +316,11 @@ View exit codes: 0 rendered, 1 --check mismatch or lossy under
|
|
|
322
316
|
--strict, 2 usage or --max-rows exceeded, 4 the document does not stand
|
|
323
317
|
up on its own, or a relation, root or path that names nothing.
|
|
324
318
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
--unit <path> Render only the unit with this path
|
|
331
|
-
--stdout One unit's bytes and nothing else (with --unit when
|
|
332
|
-
the instance has several)
|
|
333
|
-
--out <dir> Write every unit below dir, or nothing; never deletes
|
|
334
|
-
--check <dir> Compare every unit with dir/<path>; drift is listed
|
|
335
|
-
--coverage Report what the render read and what it did not:
|
|
336
|
-
model paths no output consumed, and rendered
|
|
337
|
-
declarations no rule produced. Writes nothing
|
|
338
|
-
--coverage-at <p> Measure coverage under this path only, instead of
|
|
339
|
-
the document root
|
|
340
|
-
--strict Refuse the opaque escapes (a text declaration, a raw
|
|
341
|
-
block)
|
|
342
|
-
--format <f> text (default) or json, the whole report; json
|
|
343
|
-
carries the dispatch trace, one entry per emitted
|
|
344
|
-
piece
|
|
345
|
-
|
|
346
|
-
Render exit codes: 0 rendered, 1 lossy under --strict or drift under
|
|
347
|
-
--check, 2 usage or I/O (a refused unit path included), 4 the document
|
|
348
|
-
does not stand up or the instance is not aontu:code.
|
|
349
|
-
|
|
350
|
-
A render entry file whose extension is not .aon is a TEMPLATE: a
|
|
351
|
-
generator in the target's own syntax, whose marker lines carry aontu
|
|
352
|
-
and whose other lines are output. It is desugared before it is
|
|
353
|
-
evaluated, and --marker names the marker for a language the table does
|
|
354
|
-
not know.
|
|
319
|
+
A template entry file whose extension is not .aon is a GENERATOR: a
|
|
320
|
+
document in the target's own syntax, whose marker lines carry aontu and
|
|
321
|
+
whose other lines are output. It is desugared before it is evaluated,
|
|
322
|
+
and a language the table does not know names its marker with --marker,
|
|
323
|
+
or declares it once in a profile file that --profile reads.
|
|
355
324
|
|
|
356
325
|
Template options:
|
|
357
326
|
--resugar The file is the canonical aontu; print the template
|
|
@@ -359,7 +328,9 @@ Template options:
|
|
|
359
328
|
--check Desugar and resugar, and exit 1 if the file is not
|
|
360
329
|
what the round trip answers
|
|
361
330
|
--marker <t> The marker, when the extension does not name it
|
|
362
|
-
(default //-, and #- --- /*- by extension)
|
|
331
|
+
(default //-, and #- --- /*- <!--- by extension)
|
|
332
|
+
--profile <f> A profile file, whose template.ext names the
|
|
333
|
+
extensions it marks and template.marker the marker
|
|
363
334
|
|
|
364
335
|
The template verb prints the canonical aontu form of a generator
|
|
365
336
|
written in the target's own syntax: a marked line is aontu source, and
|
|
@@ -452,16 +423,18 @@ Fmt options:
|
|
|
452
423
|
shapes, on standard error, and print nothing else
|
|
453
424
|
--strict With --lint, and exit 1 when there is a finding
|
|
454
425
|
--marker <t> The file is a generator, and this is its marker
|
|
455
|
-
(default //-, and #- --- /*- by extension)
|
|
426
|
+
(default //-, and #- --- /*- <!--- by extension)
|
|
427
|
+
--profile <f> A profile file, whose template.ext names the
|
|
428
|
+
extensions it marks and template.marker the marker
|
|
456
429
|
|
|
457
430
|
The fmt verb prints one document in the agreed form; with no file it
|
|
458
431
|
reads standard input. Several files need one of the options above.
|
|
459
432
|
|
|
460
|
-
A file whose extension is not .aon is a GENERATOR, as it is for
|
|
461
|
-
the aontu its marker lines carry is formatted, the marker
|
|
462
|
-
left margin with the aontu indented after it, and every
|
|
463
|
-
is held on a line of its own. A file with no marker line
|
|
464
|
-
another language's, and is refused.
|
|
433
|
+
A file whose extension is not .aon is a GENERATOR, as it is for
|
|
434
|
+
template: the aontu its marker lines carry is formatted, the marker
|
|
435
|
+
stands at the left margin with the aontu indented after it, and every
|
|
436
|
+
line of output is held on a line of its own. A file with no marker line
|
|
437
|
+
in it is another language's, and is refused.
|
|
465
438
|
|
|
466
439
|
Fmt exit codes: 0 formatted or clean, 1 a --check file would change or
|
|
467
440
|
a --strict finding, 2 usage, 4 a document does not parse.
|
|
@@ -495,30 +468,7 @@ function version() {
|
|
|
495
468
|
return '0.0.0';
|
|
496
469
|
}
|
|
497
470
|
}
|
|
498
|
-
// The terminal colour escapes the parser puts in its message text. A
|
|
499
|
-
// machine-readable report is no place for them, which is the rule
|
|
500
|
-
// findingOf states in ts/src/vet.ts; the twin here rather than an
|
|
501
|
-
// import because go/cmd/aontu carries its own for the same reason (the
|
|
502
|
-
// engine's is not exported to its command).
|
|
503
471
|
const EVAL_ANSI = new RegExp('\u001b\\[[0-9;]*m', 'g');
|
|
504
|
-
// THE ENGINE'S DIAGNOSIS AS A FINDING (G11 phase 7). The bare command
|
|
505
|
-
// was the one verb whose failure had no machine-readable form, so the
|
|
506
|
-
// default entry point was the one an agent had to parse with a regular
|
|
507
|
-
// expression.
|
|
508
|
-
//
|
|
509
|
-
// THE HEADLINE ONLY, and no `hint`. Both are parity decisions rather
|
|
510
|
-
// than economies: the frames under the headline are drawn for a person
|
|
511
|
-
// reading a terminal and only the first line is held to byte parity
|
|
512
|
-
// between the ports (the rule findingOf states), and the hint TABLES
|
|
513
|
-
// are deliberately not in parity while the code registry is -- so a
|
|
514
|
-
// hint here would make the two ports answer differently for a code
|
|
515
|
-
// only one of them explains. `aontu explain <code>` is where the hint
|
|
516
|
-
// lives, which is what phase 3 built it for.
|
|
517
|
-
//
|
|
518
|
-
// The CLASS comes from the registry rather than from the nil, because
|
|
519
|
-
// the registry is what both ports hold set-equal
|
|
520
|
-
// (test/spec/errcodes.tsv). Mirrors evalFinding in
|
|
521
|
-
// go/cmd/aontu/main.go.
|
|
522
472
|
function evalFinding(code, text) {
|
|
523
473
|
return {
|
|
524
474
|
class: (0, hints_1.codeClass)(code),
|
|
@@ -526,10 +476,6 @@ function evalFinding(code, text) {
|
|
|
526
476
|
message: text.split('\n')[0].replace(EVAL_ANSI, ''),
|
|
527
477
|
path: '$',
|
|
528
478
|
severity: 'error',
|
|
529
|
-
// NO SITE. The bare command's failure is the whole document not
|
|
530
|
-
// standing up, and the two sites a conflict names are in the
|
|
531
|
-
// frames the text form prints; naming one of them here would be a
|
|
532
|
-
// choice the engine has not made.
|
|
533
479
|
sites: [],
|
|
534
480
|
};
|
|
535
481
|
}
|
|
@@ -537,12 +483,6 @@ function evalFinding(code, text) {
|
|
|
537
483
|
// message, and the failure in the finding shape. Never throws.
|
|
538
484
|
function evalSource(aontu, src, mode) {
|
|
539
485
|
try {
|
|
540
|
-
// exactJSON, not JSON.stringify: a document using the `0d` exact
|
|
541
|
-
// leaves generates bigints and Decimals, which JSON.stringify cannot
|
|
542
|
-
// write (D9). The CLI prints INDENTED JSON and the shared suite's
|
|
543
|
-
// `gens` mode prints COMPACT JSON, but both go through this one
|
|
544
|
-
// emitter -- an indent argument rather than a second implementation,
|
|
545
|
-
// so the two cannot drift from each other or from the Go port.
|
|
546
486
|
const text = 'canon' === mode
|
|
547
487
|
? aontu.unify(src).canon
|
|
548
488
|
: (0, aontu_1.exactJSON)(aontu.generate(src), 2);
|
|
@@ -552,13 +492,6 @@ function evalSource(aontu, src, mode) {
|
|
|
552
492
|
const msg = (err instanceof aontu_1.AontuError || true === err?.aontu)
|
|
553
493
|
? err.message
|
|
554
494
|
: String(err?.message ?? err);
|
|
555
|
-
// WHAT THE ENGINE COLLECTED, when it collected anything: an
|
|
556
|
-
// AontuError carries the NilVals the run failed on, already
|
|
557
|
-
// materialised (handleErrors in ts/src/aontu.ts), and their first
|
|
558
|
-
// is the diagnosis every other verb reports. An error raised
|
|
559
|
-
// outside the engine's own collection -- exactJSON's circular
|
|
560
|
-
// refusal, a foreign object claiming to be one -- carries none,
|
|
561
|
-
// and answers with the text alone rather than an invented code.
|
|
562
495
|
const errs = 'function' === typeof err?.errs ? err.errs() : [];
|
|
563
496
|
const first = errs[0];
|
|
564
497
|
return {
|
|
@@ -623,16 +556,6 @@ function trustOpts(trust, entryRoot) {
|
|
|
623
556
|
return { ...text, trustWarn: makeTrustWarn(), trustWarnRoot: entryRoot };
|
|
624
557
|
}
|
|
625
558
|
}
|
|
626
|
-
// EVERY VERB honours the include capability, not just the bare
|
|
627
|
-
// command. G5 wired `--trust`/`--include-root` to `aontu <file>` alone,
|
|
628
|
-
// so `aontu vet schema.aon data.json` -- the surface an agent actually
|
|
629
|
-
// scripts -- ran the full system resolver with no flag to confine it
|
|
630
|
-
// and no warning (use-cases/REVIEW.md finding G). The flags are
|
|
631
|
-
// stripped here, before each verb parses its own tail, so a verb only
|
|
632
|
-
// has to pass the profile on to its engine.
|
|
633
|
-
//
|
|
634
|
-
// Returns undefined when the spelling is wrong, with the message
|
|
635
|
-
// already printed: the caller answers the usage class.
|
|
636
559
|
function takeTrust(argv) {
|
|
637
560
|
const rest = [];
|
|
638
561
|
let trust = { kind: 'system-warn', textExt: [] };
|
|
@@ -727,17 +650,6 @@ function runFile(file, mode, format, trust) {
|
|
|
727
650
|
src = (0, node_fs_1.readFileSync)(file, 'utf8');
|
|
728
651
|
}
|
|
729
652
|
catch (err) {
|
|
730
|
-
// A MISTYPED VERB READS AS A FILE NAME, and until G11 phase 2 that
|
|
731
|
-
// was only said when there were TWO of them. The one-argument case
|
|
732
|
-
// is the one an agent actually produces -- `aontu help`, `aontu
|
|
733
|
-
// init`, `aontu ontology` -- and it answered `cannot read help:
|
|
734
|
-
// ...`, which describes the symptom and hides the cause.
|
|
735
|
-
//
|
|
736
|
-
// The test is SHAPE, not existence: a bare word (no separator, no
|
|
737
|
-
// extension) that cannot be read was meant as a verb, while
|
|
738
|
-
// `./help`, `help.aon` and `/tmp/help` were meant as paths and keep
|
|
739
|
-
// the file diagnosis and its exit 1. That is the same escape hatch
|
|
740
|
-
// the subcommand dispatch documents. Mirrors go/cmd/aontu/main.go.
|
|
741
653
|
if (looksLikeVerb(file)) {
|
|
742
654
|
process.stderr.write(`aontu: \`${file}\` is not a file, and not a verb this port knows\n`);
|
|
743
655
|
const near = nearestVerb(file, KNOWN_VERBS);
|
|
@@ -751,12 +663,6 @@ function runFile(file, mode, format, trust) {
|
|
|
751
663
|
return 1;
|
|
752
664
|
}
|
|
753
665
|
const path = (0, node_path_1.resolve)(file);
|
|
754
|
-
// `fs` IS WHAT MAKES A FRAME EXCERPT THE FILE IT NAMES. Without it,
|
|
755
|
-
// err.ts's resolveSrc falls back to the ENTRY text, so a frame whose
|
|
756
|
-
// arrow says `lib/types.aon:2:6` printed the entry's line 2 under it
|
|
757
|
-
// -- a real file name over another file's line, which
|
|
758
|
-
// docs/reference-api.md forbids in the same words it uses to require
|
|
759
|
-
// the name.
|
|
760
666
|
const aontu = new aontu_1.Aontu({
|
|
761
667
|
path,
|
|
762
668
|
errfs: { existsSync: node_fs_1.existsSync, readFileSync: node_fs_1.readFileSync },
|
|
@@ -892,14 +798,6 @@ function runRepl(initialMode, jsonl, trust) {
|
|
|
892
798
|
rl.prompt();
|
|
893
799
|
});
|
|
894
800
|
rl.on('close', () => {
|
|
895
|
-
// The closing newline is for a HUMAN, so it is written only for
|
|
896
|
-
// one: it moves the terminal off the prompt line that `rl` left
|
|
897
|
-
// hanging. In `--jsonl` there is no prompt, every answer already
|
|
898
|
-
// ends in its own newline, and this one appended a bare empty line
|
|
899
|
-
// to the stream -- a record that is not JSON, at the end of a
|
|
900
|
-
// protocol whose whole contract is one JSON object per line. A
|
|
901
|
-
// harness parsing every line it receives failed on it, after the
|
|
902
|
-
// commands had all succeeded. Mirrors go/cmd/aontu/repl.go.
|
|
903
801
|
if (!jsonl) {
|
|
904
802
|
process.stdout.write('\n');
|
|
905
803
|
}
|
|
@@ -909,15 +807,6 @@ function runRepl(initialMode, jsonl, trust) {
|
|
|
909
807
|
process.exitCode = 0;
|
|
910
808
|
});
|
|
911
809
|
}
|
|
912
|
-
// THE VET VERB (G2 phase 3).
|
|
913
|
-
//
|
|
914
|
-
// Exit codes are VERDICT CLASSES, not a pass/fail bit: an agent loop
|
|
915
|
-
// branches on "the data contradicts the truth" (1) differently from
|
|
916
|
-
// "the data has not supplied everything the truth requires" (3), and
|
|
917
|
-
// differently again from "the schema itself is broken" (4), which is
|
|
918
|
-
// never the data's fault. 2 stays what it already was for this CLI --
|
|
919
|
-
// the caller got the invocation wrong -- which is why an unreadable
|
|
920
|
-
// file is a 2 rather than a 4.
|
|
921
810
|
const VET_EXIT = {
|
|
922
811
|
valid: 0,
|
|
923
812
|
invalid: 1,
|
|
@@ -961,14 +850,6 @@ function parseVetArgs(argv) {
|
|
|
961
850
|
format = f;
|
|
962
851
|
}
|
|
963
852
|
else if ('--max-errors' === arg) {
|
|
964
|
-
// ONE GRAMMAR, spelled the same way in both ports: decimal
|
|
965
|
-
// digits, one to nine of them, at least 1. `Number()` alone
|
|
966
|
-
// accepted `1.0`, `1e2`, `0x10` and ` 3`, which Go's parser
|
|
967
|
-
// refuses -- so the same documented invocation meant different
|
|
968
|
-
// things in the two shipped commands. The nine-digit ceiling is
|
|
969
|
-
// where the ports would part company again: beyond it Go's
|
|
970
|
-
// integer conversion saturates, and a cap nobody can reach is
|
|
971
|
-
// not worth a divergence.
|
|
972
853
|
const raw = argv[++i];
|
|
973
854
|
if (!/^[0-9]{1,9}$/.test(raw ?? '') || 1 > Number(raw)) {
|
|
974
855
|
return { err: 'aontu: --max-errors needs a positive whole number' };
|
|
@@ -1046,10 +927,6 @@ function renderFinding(f) {
|
|
|
1046
927
|
out.push(` actual: ${f.actual}`);
|
|
1047
928
|
}
|
|
1048
929
|
for (const s of f.sites) {
|
|
1049
|
-
// Every site carries the canon of the value it stands for: that is
|
|
1050
|
-
// what makes the two sides of a conflict readable side by side. A
|
|
1051
|
-
// site's file is always a string -- empty when the value belongs to
|
|
1052
|
-
// neither document -- so there is nothing to coalesce here.
|
|
1053
930
|
out.push(` ${s.role}: ${s.file}:${s.row}:${s.col} (${s.value})`);
|
|
1054
931
|
}
|
|
1055
932
|
return out.join('\n');
|
|
@@ -1141,18 +1018,9 @@ function vetOnce(args, trust) {
|
|
|
1141
1018
|
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
|
|
1142
1019
|
return 2;
|
|
1143
1020
|
}
|
|
1144
|
-
// Each data file is vetted on its own, because a parsed tree is
|
|
1145
|
-
// single-use (docs/reference-api.md) -- and because two data files
|
|
1146
|
-
// are two candidates for the same truth, not one merged candidate.
|
|
1147
1021
|
let verdict = 'valid';
|
|
1148
1022
|
let truncated = false;
|
|
1149
1023
|
const findings = [];
|
|
1150
|
-
// COVERAGE ACROSS SEVERAL DATA FILES (G11 phase 5). Two data files
|
|
1151
|
-
// are two candidates for one truth, so the schema side is the SAME
|
|
1152
|
-
// for each: `declared` is taken once, and a declaration is unused
|
|
1153
|
-
// only when NO file met it -- the intersection, because a
|
|
1154
|
-
// declaration one file exercised is exercised. The data side adds
|
|
1155
|
-
// up: leaves and checked leaves sum, and `unchecked` is the union.
|
|
1156
1024
|
let cov;
|
|
1157
1025
|
// Initialised rather than left undefined: it is filled in the same
|
|
1158
1026
|
// block that sets `cov`, so a fallback at the read below would be an
|
|
@@ -1170,12 +1038,6 @@ function vetOnce(args, trust) {
|
|
|
1170
1038
|
maxErrors: args.maxErrors,
|
|
1171
1039
|
schemaUrl: args.schema,
|
|
1172
1040
|
dataUrl: source.file,
|
|
1173
|
-
// The paths as well as the labels: a relative `@"file"` load
|
|
1174
|
-
// inside either document resolves from ITS OWN directory, the
|
|
1175
|
-
// way `aontu <file>` already resolves one (runFile above). The
|
|
1176
|
-
// path is passed AS TYPED, not resolved: it doubles as the
|
|
1177
|
-
// label above, and a report that mixed the typed path with an
|
|
1178
|
-
// absolute one would name the same file two ways.
|
|
1179
1041
|
schemaPath: args.schema,
|
|
1180
1042
|
dataPath: source.file,
|
|
1181
1043
|
coverage: args.coverage,
|
|
@@ -1204,26 +1066,10 @@ function vetOnce(args, trust) {
|
|
|
1204
1066
|
? new Set([...unusedEvery].filter((u) => mine.has(u))) : mine;
|
|
1205
1067
|
unusedSeen = true;
|
|
1206
1068
|
}
|
|
1207
|
-
// A SCHEMA-SIDE FAULT IS THE SAME FAULT FOR EVERY DATA FILE, so it
|
|
1208
|
-
// is reported ONCE. `error` means exactly that -- the run could not
|
|
1209
|
-
// be set up from the truth's side, never the data's (the exit table
|
|
1210
|
-
// in docs/reference-api.md) -- so the report the first file
|
|
1211
|
-
// produced is the report every later file would produce, character
|
|
1212
|
-
// for character. Concatenating them repeated one broken schema N
|
|
1213
|
-
// times and, past the cap, marked the report `truncated` over a
|
|
1214
|
-
// single underlying fault. It only became visible once the `error`
|
|
1215
|
-
// verdict started carrying findings at all: while the list was
|
|
1216
|
-
// empty there was nothing to duplicate.
|
|
1217
1069
|
if ('error' === report.verdict) {
|
|
1218
1070
|
break;
|
|
1219
1071
|
}
|
|
1220
1072
|
}
|
|
1221
|
-
// The cap is on the REPORT, not on each file. Capping every file's
|
|
1222
|
-
// list and then concatenating them let `--max-errors 1` emit one
|
|
1223
|
-
// finding PER FILE -- and leave `truncated` false while doing it,
|
|
1224
|
-
// because no single file had been cut. The engine still caps each
|
|
1225
|
-
// run, so a pathological file cannot flood the aggregate before it
|
|
1226
|
-
// gets here; this is the second, honest cut.
|
|
1227
1073
|
const cap = args.maxErrors ?? vet_1.VET_MAX_ERRORS;
|
|
1228
1074
|
const kept = cap < findings.length ? findings.slice(0, cap) : findings;
|
|
1229
1075
|
if (null != cov) {
|
|
@@ -1241,12 +1087,6 @@ function vetOnce(args, trust) {
|
|
|
1241
1087
|
'sarif' === args.format ? renderVetSarif(report) :
|
|
1242
1088
|
renderVetText(report);
|
|
1243
1089
|
process.stdout.write(text + '\n');
|
|
1244
|
-
// A VACUOUS CHECK IS A FAILED GATE UNDER `--strict-coverage`, and
|
|
1245
|
-
// only under it: the verdict WORD is unchanged, so nothing that
|
|
1246
|
-
// passes today starts failing, and a caller who wants the stronger
|
|
1247
|
-
// gate asks for it. The reason goes to stderr, because stdout is a
|
|
1248
|
-
// report contract -- a JSON consumer reads `coverage.vacuous` and a
|
|
1249
|
-
// person reads this.
|
|
1250
1090
|
if (true === args.strictCoverage && true === report.coverage?.vacuous) {
|
|
1251
1091
|
process.stderr.write('aontu: no data leaf was constrained by the schema:' +
|
|
1252
1092
|
' this run checked nothing\n' +
|
|
@@ -1273,19 +1113,6 @@ function watchSignature(files) {
|
|
|
1273
1113
|
function sleep(ms) {
|
|
1274
1114
|
return new Promise((done) => setTimeout(done, ms));
|
|
1275
1115
|
}
|
|
1276
|
-
// Resolve true when any watched file's signature moves off `before`.
|
|
1277
|
-
// This is the real waiter: it never resolves false, so a real watch
|
|
1278
|
-
// runs until the process is interrupted; tests inject their own waiter
|
|
1279
|
-
// to bound the loop, and pass a short pollMs when they drive this one
|
|
1280
|
-
// directly. The interval is a required argument (the command passes
|
|
1281
|
-
// WATCH_POLL_MS) so there is no defaulting branch a test could never
|
|
1282
|
-
// take.
|
|
1283
|
-
//
|
|
1284
|
-
// The BASELINE is an argument, not a snapshot taken here: the loop
|
|
1285
|
-
// records it BEFORE each vet run, so a save landing between the run's
|
|
1286
|
-
// reads and the wait still compares as a change. A waiter that
|
|
1287
|
-
// snapshotted on entry would adopt that unvetted save as its baseline
|
|
1288
|
-
// and wait indefinitely on a stale report.
|
|
1289
1116
|
async function watchChange(files, before, pollMs) {
|
|
1290
1117
|
for (;;) {
|
|
1291
1118
|
await sleep(pollMs);
|
|
@@ -1314,9 +1141,6 @@ async function watchVet(args, wait, trust) {
|
|
|
1314
1141
|
}
|
|
1315
1142
|
return code;
|
|
1316
1143
|
}
|
|
1317
|
-
// The vet verb. Non-watch runs are synchronous and return the exit
|
|
1318
|
-
// class directly; `--watch` returns a promise that resolves only when
|
|
1319
|
-
// the waiter says stop (never, for the real one).
|
|
1320
1144
|
function runVet(argv, wait) {
|
|
1321
1145
|
const trusted = takeTrust(argv);
|
|
1322
1146
|
if (null == trusted) {
|
|
@@ -1527,30 +1351,7 @@ function parseBreakingArgs(argv) {
|
|
|
1527
1351
|
},
|
|
1528
1352
|
};
|
|
1529
1353
|
}
|
|
1530
|
-
// A source file the include resolver can actually load. `git#<rev>`
|
|
1531
|
-
// materialises these and nothing else: an include names an Aontu
|
|
1532
|
-
// document (`.aon`/`.aontu`, the two extensions `@"foo"` tries) or a
|
|
1533
|
-
// JSON one, so the rest of a revision's tree cannot be part of any
|
|
1534
|
-
// include closure and copying it would be pure cost.
|
|
1535
1354
|
const INCLUDABLE = /\.(aon|aontu|jsonic|json)$/;
|
|
1536
|
-
// Resolve one --against spelling to an old version.
|
|
1537
|
-
//
|
|
1538
|
-
// A `git#<rev>` spelling is the old version of the WHOLE TREE, not of
|
|
1539
|
-
// the entry file alone. It used to be `git show <rev>:./<file>`, whose
|
|
1540
|
-
// text was then evaluated with `generalPath`/`specificPath` pointing at
|
|
1541
|
-
// the WORKING file -- so every `@"..."` include in the old document
|
|
1542
|
-
// resolved against the working tree, and the "old" side was old entry
|
|
1543
|
-
// text meeting new includes. A breaking change inside an included file
|
|
1544
|
-
// therefore compared against itself and answered `compatible`: the
|
|
1545
|
-
// documented CI gate silently un-gated every non-entry file of the
|
|
1546
|
-
// multi-file layout real models use (use-cases/BUGS.md §26). The old
|
|
1547
|
-
// tree's includable sources are copied into a temporary directory and
|
|
1548
|
-
// the old document is evaluated from THERE.
|
|
1549
|
-
//
|
|
1550
|
-
// Sources outside the revision -- package includes under node_modules,
|
|
1551
|
-
// the bundled `std/system` -- still resolve as they do today: they are
|
|
1552
|
-
// not in the tree, and their versions travel with the lockfile rather
|
|
1553
|
-
// than with this comparison.
|
|
1554
1355
|
function oldVersion(spec, file) {
|
|
1555
1356
|
if (!spec.startsWith('git#')) {
|
|
1556
1357
|
try {
|
|
@@ -1578,23 +1379,9 @@ function oldVersion(spec, file) {
|
|
|
1578
1379
|
// that only some failures take.
|
|
1579
1380
|
const temp = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'aontu-against-'));
|
|
1580
1381
|
try {
|
|
1581
|
-
// THE REPO-RELATIVE PATH COMES FROM GIT, not from path arithmetic.
|
|
1582
|
-
// Relativising `rev-parse --show-toplevel` against `resolve(file)`
|
|
1583
|
-
// puts two DIFFERENT COORDINATE SYSTEMS on either side of the
|
|
1584
|
-
// subtraction: git prints the real path, while the caller's is
|
|
1585
|
-
// whatever they typed. On macOS a temp file under /var is
|
|
1586
|
-
// /private/var to git, and on Windows a TMP short name
|
|
1587
|
-
// (RUNNER~1) is the long form to git -- so the subtraction gave a
|
|
1588
|
-
// `../..` climb, the entry was "not in that revision", and the
|
|
1589
|
-
// documented CI spelling failed on both platforms while passing on
|
|
1590
|
-
// Linux (this PR's own CI). `--show-prefix` is the same question
|
|
1591
|
-
// asked in git's coordinates: the repo-relative directory of the
|
|
1592
|
-
// cwd, already slash-separated and already normalised.
|
|
1593
1382
|
const prefix = git(['rev-parse', '--show-prefix'], dir).trim();
|
|
1594
1383
|
const entryRel = prefix + (0, node_path_1.basename)(file);
|
|
1595
1384
|
const top = git(['rev-parse', '--show-toplevel'], dir).trim();
|
|
1596
|
-
// `-z` so a path with a newline or a quote cannot be mistaken for
|
|
1597
|
-
// two paths (git otherwise quotes such names).
|
|
1598
1385
|
const listed = git(['ls-tree', '-r', '-z', '--name-only', rev], top)
|
|
1599
1386
|
.split('\0').filter((p) => '' !== p);
|
|
1600
1387
|
if (!listed.includes(entryRel)) {
|
|
@@ -1624,13 +1411,6 @@ function oldVersion(spec, file) {
|
|
|
1624
1411
|
function policyCompat(newSrc, path, include) {
|
|
1625
1412
|
const aontu = new aontu_1.Aontu();
|
|
1626
1413
|
const ctx = aontu.ctx({ collect: true });
|
|
1627
|
-
// The declaration is read by EVALUATING the document, so this leg
|
|
1628
|
-
// runs the include resolver too and has to run it under BOTH of the
|
|
1629
|
-
// verb's include options -- a `breaking --trust none` that read its
|
|
1630
|
-
// own mode through an unconfined resolver would confine the
|
|
1631
|
-
// comparison and not the question (use-cases/REVIEW.md finding G),
|
|
1632
|
-
// and one that took the capability alone read no mode at all when
|
|
1633
|
-
// the declaration arrived through a `--text-ext` include.
|
|
1634
1414
|
const v = aontu.unify(newSrc, { path, ...(0, utility_1.includeOpts)(include) }, ctx);
|
|
1635
1415
|
if (0 < ctx.err.length || true === v?.isNil) {
|
|
1636
1416
|
return undefined;
|
|
@@ -1649,11 +1429,6 @@ function policyCompat(newSrc, path, include) {
|
|
|
1649
1429
|
return 'backward' === m || 'forward' === m || 'full' === m || 'none' === m
|
|
1650
1430
|
? m : undefined;
|
|
1651
1431
|
}
|
|
1652
|
-
// Is the evaluated old version's value at the finding path deprecated?
|
|
1653
|
-
// The --allow-deprecated-removal downgrade (G3 phase 4): removing (or
|
|
1654
|
-
// otherwise changing) a value the old version already deprecated warns
|
|
1655
|
-
// instead of breaking. The Go port exports the same reader as
|
|
1656
|
-
// aontu.DeprecatedAt.
|
|
1657
1432
|
function deprecatedAt(oldSrc, path, filePath) {
|
|
1658
1433
|
const aontu = new aontu_1.Aontu();
|
|
1659
1434
|
const ctx = aontu.ctx({ collect: true });
|
|
@@ -1720,9 +1495,6 @@ function runBreaking(argv) {
|
|
|
1720
1495
|
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
|
|
1721
1496
|
return 2;
|
|
1722
1497
|
}
|
|
1723
|
-
// The declared mode: --mode overrides the document's own policy;
|
|
1724
|
-
// neither means backward, the index's framing (v1-valid documents
|
|
1725
|
-
// stay valid).
|
|
1726
1498
|
const mode = args.mode ??
|
|
1727
1499
|
policyCompat(newSrc, args.file, verbOpts(trust, entryRootOf(args.file))) ??
|
|
1728
1500
|
'backward';
|
|
@@ -1755,8 +1527,6 @@ function runBreaking(argv) {
|
|
|
1755
1527
|
if (null != old.temp) {
|
|
1756
1528
|
temps.push(old.temp);
|
|
1757
1529
|
}
|
|
1758
|
-
// backward: the NEW document is the general side — every old
|
|
1759
|
-
// instance must still be admitted. forward: the old one is.
|
|
1760
1530
|
const checks = [];
|
|
1761
1531
|
if ('backward' === mode || 'full' === mode) {
|
|
1762
1532
|
checks.push({ general: [newSrc, args.file], specific: [oldSrc, spec] });
|
|
@@ -1771,17 +1541,9 @@ function runBreaking(argv) {
|
|
|
1771
1541
|
at: args.at,
|
|
1772
1542
|
generalUrl: check.general[1],
|
|
1773
1543
|
specificUrl: check.specific[1],
|
|
1774
|
-
// The old side's relative loads resolve from ITS own tree --
|
|
1775
|
-
// the materialised revision for a git spelling, the named
|
|
1776
|
-
// file's directory otherwise -- so an included file's change
|
|
1777
|
-
// is part of the comparison rather than invisible to it.
|
|
1778
1544
|
generalPath: check.general[1] === spec ? oldPath : args.file,
|
|
1779
1545
|
specificPath: check.specific[1] === spec ? oldPath : args.file,
|
|
1780
1546
|
});
|
|
1781
|
-
// The deprecated-removal downgrade: a finding about a value the
|
|
1782
|
-
// OLD version already deprecated becomes a warning, and warnings
|
|
1783
|
-
// do not move the verdict. Deprecate-then-remove is the
|
|
1784
|
-
// supported rename path (the design's own sequencing).
|
|
1785
1547
|
let verdict = report.verdict;
|
|
1786
1548
|
if (args.allowDeprecatedRemoval) {
|
|
1787
1549
|
let liveFindings = 0;
|
|
@@ -1832,12 +1594,6 @@ function renderBreakingJson(report, mode) {
|
|
|
1832
1594
|
findings: report.findings,
|
|
1833
1595
|
}, 2);
|
|
1834
1596
|
}
|
|
1835
|
-
// ---------------------------------------------------------------------
|
|
1836
|
-
// The trim reporter (G3 phase 6): report redundant entries as paths.
|
|
1837
|
-
// Report-only — REWRITING needs G7's format-preserving patch surface —
|
|
1838
|
-
// which is why --check is REQUIRED rather than defaulted: `aontu trim
|
|
1839
|
-
// f.aon` reads as "trim this file", and doing something else silently
|
|
1840
|
-
// is worse than saying so.
|
|
1841
1597
|
const TRIM_HELP = 'aontu trim --check <file> (try --help)';
|
|
1842
1598
|
const TRIM_EXIT = {
|
|
1843
1599
|
clean: 0,
|
|
@@ -1907,8 +1663,6 @@ function runTrim(argv) {
|
|
|
1907
1663
|
}
|
|
1908
1664
|
function renderTrimText(report) {
|
|
1909
1665
|
const head = `verdict: ${report.verdict}`;
|
|
1910
|
-
// WHY, when the document could not be evaluated at all: rendered as
|
|
1911
|
-
// vet renders a finding, because it IS one (the review's finding F).
|
|
1912
1666
|
const errors = report.errors ?? [];
|
|
1913
1667
|
if (0 < errors.length) {
|
|
1914
1668
|
return [head, ''].concat(errors.map(renderFinding)).join('\n');
|
|
@@ -1957,27 +1711,10 @@ const VIEW_EDGES = ['upward', 'all', 'none'];
|
|
|
1957
1711
|
// is a terminal, which is the CLI's to know and the library's never --
|
|
1958
1712
|
// the same division err.ts already draws for the error frames.
|
|
1959
1713
|
const VIEW_STYLES = ['auto', 'none', 'ansi', 'css'];
|
|
1960
|
-
// `--style auto` resolved, which only the CLI can do. The mechanism is
|
|
1961
|
-
// the PROFILE's and the library knows it -- an SVG carries its
|
|
1962
|
-
// stylesheet unless told not to, which is what makes a figure stand
|
|
1963
|
-
// alone. What the library cannot know is whether the DESTINATION is a
|
|
1964
|
-
// terminal, so that is the only thing decided here: escapes on the
|
|
1965
|
-
// text profile when stdout is a terminal and NO_COLOR is unset, the
|
|
1966
|
-
// same two conditions the error frames use. `undefined` leaves the
|
|
1967
|
-
// profile's own default in place.
|
|
1968
1714
|
function viewStyleOf(asked, as) {
|
|
1969
1715
|
if (undefined !== asked && 'auto' !== asked) {
|
|
1970
1716
|
return asked;
|
|
1971
1717
|
}
|
|
1972
|
-
// STDOUT'S OWN TERMINAL-NESS, and NO_COLOR read here rather than
|
|
1973
|
-
// through colorActive(). The figure goes to STDOUT and the error
|
|
1974
|
-
// frames go to STDERR, and they are not the same destination: main()
|
|
1975
|
-
// has already called setColor for stderr, so asking colorActive()
|
|
1976
|
-
// would answer the wrong question twice --- no escapes for
|
|
1977
|
-
// `aontu view tree m.aon 2>/dev/null` at a terminal, and escapes
|
|
1978
|
-
// into the pipe for `aontu view tree m.aon | less`. The NO_COLOR
|
|
1979
|
-
// rule is the one no-color.org states and err.ts implements:
|
|
1980
|
-
// set, to anything but empty, means no colour.
|
|
1981
1718
|
const no = process.env.NO_COLOR;
|
|
1982
1719
|
return 'text' === as && true === process.stdout.isTTY
|
|
1983
1720
|
&& (null == no || '' === no) ? 'ansi' : undefined;
|
|
@@ -1999,25 +1736,13 @@ const VIEW_USAGE_CODES = [
|
|
|
1999
1736
|
'view_document_shape', 'view_style_profile', 'view_style_unknown',
|
|
2000
1737
|
];
|
|
2001
1738
|
const MOD_HELP = 'aontu mod tidy|verify|vendor|manifest [dir] (try --help)';
|
|
2002
|
-
// The module tooling (G6 phase 3, ts/src/mod-tool.ts). All LOCAL:
|
|
2003
|
-
// `tidy` resolves the closure from what is in the stores and rewrites
|
|
2004
|
-
// the lockfile, `verify` asks whether the stores still mean what the
|
|
2005
|
-
// lockfile pins and changes nothing, `vendor` materialises the locked
|
|
2006
|
-
// closure into the project, `manifest` prints what a publish would
|
|
2007
|
-
// push.
|
|
2008
|
-
//
|
|
2009
|
-
// TIDY AND VERIFY ARE DIFFERENT QUESTIONS, and that is why both exist.
|
|
2010
|
-
// Tidy recomputes and rewrites by design -- a pin is what a module
|
|
2011
|
-
// means NOW -- so it makes the lockfile agree with whatever the store
|
|
2012
|
-
// holds, tampering included. Verify is the gate: a CI job runs it
|
|
2013
|
-
// BEFORE tidy, or instead of it.
|
|
2014
|
-
//
|
|
2015
|
-
// `get` and `publish` are the NETWORK half of the design and are not in
|
|
2016
|
-
// this build. They are named here rather than left to fall out as an
|
|
2017
|
-
// unknown subcommand, because a reader of the design will type them and
|
|
2018
|
-
// deserves to be told which half is missing rather than that the word
|
|
2019
|
-
// is wrong.
|
|
2020
1739
|
function runMod(argv) {
|
|
1740
|
+
const trusted = takeTrust(argv);
|
|
1741
|
+
if (null == trusted) {
|
|
1742
|
+
return 2;
|
|
1743
|
+
}
|
|
1744
|
+
argv = trusted.argv;
|
|
1745
|
+
const trust = trusted.trust;
|
|
2021
1746
|
const rest = [];
|
|
2022
1747
|
let format = 'text';
|
|
2023
1748
|
let against;
|
|
@@ -2063,10 +1788,6 @@ function runMod(argv) {
|
|
|
2063
1788
|
process.stderr.write(`aontu: mod needs tidy, verify, vendor or manifest\n${MOD_HELP}\n`);
|
|
2064
1789
|
return 2;
|
|
2065
1790
|
}
|
|
2066
|
-
// THE OLD LAYOUT IS NAMED, NOT READ. The lockfile and the vendored
|
|
2067
|
-
// closure moved under aontu_meta/; a project that still carries them
|
|
2068
|
-
// at its root would otherwise look untouched by any of these verbs,
|
|
2069
|
-
// which is the one silence worth breaking.
|
|
2070
1791
|
if ((0, node_fs_1.existsSync)((0, node_path_1.join)(dir, 'aon_vendor')) || (0, node_fs_1.existsSync)((0, node_path_1.join)(dir, 'mod-lock.aon'))) {
|
|
2071
1792
|
process.stderr.write('aontu: aon_vendor/ and mod-lock.aon now live under aontu_meta/: ' +
|
|
2072
1793
|
'move them, or run aontu mod tidy and aontu mod vendor\n');
|
|
@@ -2077,10 +1798,11 @@ function runMod(argv) {
|
|
|
2077
1798
|
process.stderr.write('aontu: --against is a manifest option\n');
|
|
2078
1799
|
return 2;
|
|
2079
1800
|
}
|
|
2080
|
-
const
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
1801
|
+
const modopts = modToolOptions(trust, (0, node_path_1.resolve)(dir));
|
|
1802
|
+
const report = 'tidy' === sub ? (0, mod_tool_1.modTidy)(dir, modopts) :
|
|
1803
|
+
'verify' === sub ? (0, mod_tool_1.modVerify)(dir, modopts) :
|
|
1804
|
+
'vendor' === sub ? (0, mod_tool_1.modVendor)(dir, modopts) :
|
|
1805
|
+
(0, mod_tool_1.modManifest)(dir, modopts, against);
|
|
2084
1806
|
process.stdout.write(('json' === format ?
|
|
2085
1807
|
(0, aontu_1.exactJSON)({ aontu: { version: version(), verb: 'mod ' + sub }, ...report }, 2) :
|
|
2086
1808
|
modText(sub, report)) + '\n');
|
|
@@ -2090,9 +1812,6 @@ const MOD_SUBS = ['tidy', 'verify', 'vendor', 'manifest'];
|
|
|
2090
1812
|
const MOD_EXIT = {
|
|
2091
1813
|
ok: 0,
|
|
2092
1814
|
missing: 1,
|
|
2093
|
-
// A REFUSED GATE, with `breaking`: a store that no longer means what
|
|
2094
|
-
// the lockfile pins is the integrity check saying no, and a CI job
|
|
2095
|
-
// reading exit codes should not have to learn a third class for it.
|
|
2096
1815
|
mismatch: 1,
|
|
2097
1816
|
// Likewise a lockfile that does not cover the project: the gate has
|
|
2098
1817
|
// nothing to check, which is a refusal and not a pass.
|
|
@@ -2104,11 +1823,16 @@ const MOD_EXIT = {
|
|
|
2104
1823
|
// The tooling's evaluator: the same standalone evaluation the module
|
|
2105
1824
|
// resolver verifies with (ts/src/mod.ts), and for the same reason —
|
|
2106
1825
|
// only the engine can say what a module MEANS.
|
|
2107
|
-
function modToolOptions() {
|
|
1826
|
+
function modToolOptions(trust, entryRoot) {
|
|
1827
|
+
const opts = verbOpts(trust, entryRoot);
|
|
1828
|
+
// The user cache lives outside any confinement root, so a confined
|
|
1829
|
+
// run reads the vendor tree only -- as the evaluator's own module
|
|
1830
|
+
// leg already does when a root is set.
|
|
1831
|
+
const rooted = null != opts.trust?.include?.root;
|
|
2108
1832
|
return {
|
|
2109
|
-
cache: (0, mod_1.modCacheDir)(),
|
|
1833
|
+
...(rooted ? {} : { cache: (0, mod_1.modCacheDir)() }),
|
|
2110
1834
|
eval: (src, path) => {
|
|
2111
|
-
const a0 = new aontu_1.Aontu();
|
|
1835
|
+
const a0 = new aontu_1.Aontu(opts);
|
|
2112
1836
|
const ctx = a0.ctx({ collect: true });
|
|
2113
1837
|
const val = a0.unify(src, { path }, ctx);
|
|
2114
1838
|
return {
|
|
@@ -2138,11 +1862,6 @@ function modText(sub, report) {
|
|
|
2138
1862
|
for (const f of report.findings) {
|
|
2139
1863
|
lines.push(f.path + ': ' + f.message);
|
|
2140
1864
|
}
|
|
2141
|
-
// What a manifest lacks is a declaration the module does not make
|
|
2142
|
-
// or an entry file that is not there, and neither is something a
|
|
2143
|
-
// fetch would supply -- so this is not the tail the other two
|
|
2144
|
-
// subcommands share. The name says which kind it is: `mod.version`
|
|
2145
|
-
// is a declaration, `service.aon` is a file.
|
|
2146
1865
|
for (const miss of report.missing) {
|
|
2147
1866
|
lines.push(miss + ': missing');
|
|
2148
1867
|
}
|
|
@@ -2152,8 +1871,6 @@ function modText(sub, report) {
|
|
|
2152
1871
|
for (const mod of report.verified) {
|
|
2153
1872
|
lines.push(mod + ': verified');
|
|
2154
1873
|
}
|
|
2155
|
-
// BOTH HASHES, because the useful question is which way it moved:
|
|
2156
|
-
// an empty `got` is a module that no longer stands up at all.
|
|
2157
1874
|
for (const m of report.mismatched) {
|
|
2158
1875
|
lines.push(m.mod + ': pinned ' + m.want + ' but the store means ' +
|
|
2159
1876
|
('' === m.got ? 'nothing (it does not evaluate)' : m.got));
|
|
@@ -2186,26 +1903,6 @@ function modText(sub, report) {
|
|
|
2186
1903
|
}
|
|
2187
1904
|
return lines.join('\n');
|
|
2188
1905
|
}
|
|
2189
|
-
// VACUITY SIGNALS (G11 phase 4,
|
|
2190
|
-
// docs/capability-review/g11-agent-onramp.md).
|
|
2191
|
-
//
|
|
2192
|
-
// The same principle phase 5 applied to `vet`: a verb that did NOTHING
|
|
2193
|
-
// and a verb that did its job answer the same. `aontu view tree` over a
|
|
2194
|
-
// document declaring no relations printed one newline and exited 0;
|
|
2195
|
-
// `aontu render` with no profile printed nothing and exited 0; `aontu
|
|
2196
|
-
// relations` over a document declaring none answered `verdict: pass`.
|
|
2197
|
-
// For a person at a terminal that is a shrug. For an unattended agent
|
|
2198
|
-
// it is a green check mark on an empty box.
|
|
2199
|
-
//
|
|
2200
|
-
// ON STDERR, ALWAYS. stdout is a report contract -- a `--format json`
|
|
2201
|
-
// consumer parses it -- and the exit code is a verdict class that
|
|
2202
|
-
// callers already branch on. Neither changes here: what changes is
|
|
2203
|
-
// that the caller is TOLD. A caller who wants it to be fatal has
|
|
2204
|
-
// `vet --strict-coverage`, and the same argument would give the other
|
|
2205
|
-
// verbs a flag of their own if one is ever asked for.
|
|
2206
|
-
//
|
|
2207
|
-
// The repository already ruled this for one verb, in G8 phase 6 on
|
|
2208
|
-
// `trim`: "doing something else silently is worse than refusing".
|
|
2209
1906
|
function vacuous(what, why) {
|
|
2210
1907
|
process.stderr.write(`aontu: ${what}: ${why}\n`);
|
|
2211
1908
|
}
|
|
@@ -2269,6 +1966,108 @@ function runRelations(argv) {
|
|
|
2269
1966
|
}
|
|
2270
1967
|
return RELATIONS_EXIT[report.verdict];
|
|
2271
1968
|
}
|
|
1969
|
+
const TRACE_HELP = 'aontu trace [--at <path>] [--format json] [--marker <token>] ' +
|
|
1970
|
+
'[--profile <file>] <file>';
|
|
1971
|
+
// WHAT WROTE THIS LINE. Every piece a rule stamped, under the
|
|
1972
|
+
// component tree, with the file it reached, the rule set that wrote it
|
|
1973
|
+
// and the model node the dispatch matched.
|
|
1974
|
+
function runTrace(argv) {
|
|
1975
|
+
const trusted = takeTrust(argv);
|
|
1976
|
+
if (null == trusted) {
|
|
1977
|
+
return 2;
|
|
1978
|
+
}
|
|
1979
|
+
argv = trusted.argv;
|
|
1980
|
+
const trust = trusted.trust;
|
|
1981
|
+
const rest = [];
|
|
1982
|
+
const profileFiles = [];
|
|
1983
|
+
let format = 'text';
|
|
1984
|
+
let at = undefined;
|
|
1985
|
+
let marker = undefined;
|
|
1986
|
+
for (let i = 0; i < argv.length; i++) {
|
|
1987
|
+
const arg = argv[i];
|
|
1988
|
+
if ('-h' === arg || '--help' === arg) {
|
|
1989
|
+
process.stdout.write(HELP);
|
|
1990
|
+
return 0;
|
|
1991
|
+
}
|
|
1992
|
+
if ('--format' === arg) {
|
|
1993
|
+
const f = argv[++i];
|
|
1994
|
+
if ('text' !== f && 'json' !== f) {
|
|
1995
|
+
process.stderr.write('aontu: --format needs text or json\n');
|
|
1996
|
+
return 2;
|
|
1997
|
+
}
|
|
1998
|
+
format = f;
|
|
1999
|
+
}
|
|
2000
|
+
else if ('--at' === arg) {
|
|
2001
|
+
at = argv[++i];
|
|
2002
|
+
if (null == at) {
|
|
2003
|
+
process.stderr.write('aontu: --at needs a path\n');
|
|
2004
|
+
return 2;
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
else if ('--marker' === arg) {
|
|
2008
|
+
marker = argv[++i];
|
|
2009
|
+
if (null == marker) {
|
|
2010
|
+
process.stderr.write('aontu: --marker needs a token\n');
|
|
2011
|
+
return 2;
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
else if ('--profile' === arg) {
|
|
2015
|
+
const pf = argv[++i];
|
|
2016
|
+
if (null == pf) {
|
|
2017
|
+
process.stderr.write('aontu: --profile needs a file\n');
|
|
2018
|
+
return 2;
|
|
2019
|
+
}
|
|
2020
|
+
profileFiles.push(pf);
|
|
2021
|
+
}
|
|
2022
|
+
else if (arg.startsWith('-')) {
|
|
2023
|
+
process.stderr.write(`aontu: unknown trace option ${arg} (try --help)\n`);
|
|
2024
|
+
return 2;
|
|
2025
|
+
}
|
|
2026
|
+
else {
|
|
2027
|
+
rest.push(arg);
|
|
2028
|
+
}
|
|
2029
|
+
}
|
|
2030
|
+
if (1 !== rest.length) {
|
|
2031
|
+
process.stderr.write(`aontu: trace needs one file\n${TRACE_HELP}\n`);
|
|
2032
|
+
return 2;
|
|
2033
|
+
}
|
|
2034
|
+
let src;
|
|
2035
|
+
try {
|
|
2036
|
+
src = (0, node_fs_1.readFileSync)(rest[0], 'utf8');
|
|
2037
|
+
}
|
|
2038
|
+
catch (err) {
|
|
2039
|
+
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
|
|
2040
|
+
return 2;
|
|
2041
|
+
}
|
|
2042
|
+
const declared = loadProfiles(profileFiles, trust);
|
|
2043
|
+
if ('number' === typeof declared) {
|
|
2044
|
+
return declared;
|
|
2045
|
+
}
|
|
2046
|
+
// A GENERATOR IS AN ENTRY, not a preprocessing step: the file whose
|
|
2047
|
+
// provenance is asked for is the one the author edits.
|
|
2048
|
+
if (!rest[0].endsWith('.aon')) {
|
|
2049
|
+
src = (0, template_1.desugarTemplate)(src, marker ??
|
|
2050
|
+
(0, template_1.markerFromProfiles)(declared, rest[0]) ?? (0, template_1.markerFor)(rest[0]));
|
|
2051
|
+
}
|
|
2052
|
+
const report = (0, trace_1.traceRun)(src, {
|
|
2053
|
+
path: rest[0], at,
|
|
2054
|
+
...verbOpts(trust, entryRootOf(rest[0])),
|
|
2055
|
+
});
|
|
2056
|
+
if ('error' === report.verdict) {
|
|
2057
|
+
// An error report always carries its findings.
|
|
2058
|
+
const errors = report.errors;
|
|
2059
|
+
process.stderr.write(errors.map(renderFinding).join('\n') + '\n');
|
|
2060
|
+
return 4;
|
|
2061
|
+
}
|
|
2062
|
+
if ('json' === format) {
|
|
2063
|
+
process.stdout.write(JSON.stringify({ trace: report.trace }) + '\n');
|
|
2064
|
+
return 0;
|
|
2065
|
+
}
|
|
2066
|
+
for (const e of report.trace) {
|
|
2067
|
+
process.stdout.write([e.file, e.at, e.node, e.rule].join('\t') + '\n');
|
|
2068
|
+
}
|
|
2069
|
+
return 0;
|
|
2070
|
+
}
|
|
2272
2071
|
function runReaches(argv) {
|
|
2273
2072
|
const trusted = takeTrust(argv);
|
|
2274
2073
|
if (null == trusted) {
|
|
@@ -2469,12 +2268,6 @@ function runView(argv) {
|
|
|
2469
2268
|
rest.push(arg);
|
|
2470
2269
|
}
|
|
2471
2270
|
}
|
|
2472
|
-
// ESCAPES NEVER GO INTO A FILE. A pinned golden holding terminal
|
|
2473
|
-
// control codes is not a golden anybody can read, and a byte
|
|
2474
|
-
// comparison against one would fail on the reader's terminal
|
|
2475
|
-
// settings. `auto` resolves to `none` there on its own; asking for
|
|
2476
|
-
// `ansi` explicitly is a usage error rather than a silent downgrade,
|
|
2477
|
-
// so a script that wanted colour is told where it went.
|
|
2478
2271
|
if ('ansi' === style && (undefined !== out || undefined !== opts.views)) {
|
|
2479
2272
|
process.stderr.write('aontu: --style ansi writes to a terminal, not to a file\n');
|
|
2480
2273
|
return 2;
|
|
@@ -2482,10 +2275,6 @@ function runView(argv) {
|
|
|
2482
2275
|
// THE VIEW DOCUMENT draws every figure a document declares, so it
|
|
2483
2276
|
// names no kind: the declarations do, one each.
|
|
2484
2277
|
if (undefined !== opts.views) {
|
|
2485
|
-
// A declaration names its own profile, so the style is left to
|
|
2486
|
-
// each figure's own default; `--style none` still reaches every
|
|
2487
|
-
// one of them, which is how a host page that binds the CSS
|
|
2488
|
-
// variables asks for eight figures without eight stylesheets.
|
|
2489
2278
|
opts.style = viewStyleOf(style, undefined);
|
|
2490
2279
|
return runViewSet(rest, opts, trust, { format, check, strict, out });
|
|
2491
2280
|
}
|
|
@@ -2553,17 +2342,6 @@ function runView(argv) {
|
|
|
2553
2342
|
docs: files.slice(1).map((path, i) => ({ src: srcs[i + 1], path })),
|
|
2554
2343
|
};
|
|
2555
2344
|
const report = (0, view_1.view)(srcs[0], viewOpts);
|
|
2556
|
-
// AN EMPTY FIGURE IS THE SAME BYTES AS A DRAWN ONE MINUS ITS
|
|
2557
|
-
// CONTENT, and every profile spells "empty" differently: text draws
|
|
2558
|
-
// nothing at all, mermaid still draws its `flowchart LR` header, the
|
|
2559
|
-
// matrix still prints its count line. Rather than teach this one
|
|
2560
|
-
// place each of those spellings -- a list that goes stale the first
|
|
2561
|
-
// time a profile gains a header -- ASK THE SAME KIND TO DRAW AN
|
|
2562
|
-
// EMPTY DOCUMENT and compare. Equal texts mean this document
|
|
2563
|
-
// contributed nothing to the figure, whatever the profile.
|
|
2564
|
-
//
|
|
2565
|
-
// It costs one drawing of `{}`, which is the cheapest document
|
|
2566
|
-
// there is, and only on a run that produced a figure at all.
|
|
2567
2345
|
if ('error' !== report.verdict && null != report.text) {
|
|
2568
2346
|
const bare = (0, view_1.view)('{}', viewOpts);
|
|
2569
2347
|
if ('error' !== bare.verdict && bare.text === report.text) {
|
|
@@ -2612,13 +2390,6 @@ function runView(argv) {
|
|
|
2612
2390
|
}
|
|
2613
2391
|
return strict && 'lossy' === report.verdict ? 1 : VIEW_EXIT[report.verdict];
|
|
2614
2392
|
}
|
|
2615
|
-
// `aontu view --views <path> <file>`: every figure the document
|
|
2616
|
-
// declares, from one evaluation, all or nothing.
|
|
2617
|
-
//
|
|
2618
|
-
// A declared `out` is resolved against the DOCUMENT's own directory,
|
|
2619
|
-
// not the caller's: a view document is committed beside the figures it
|
|
2620
|
-
// gates, and a gate that only passes from one working directory is not
|
|
2621
|
-
// a gate.
|
|
2622
2393
|
function runViewSet(rest, opts, trust, how) {
|
|
2623
2394
|
if (1 !== rest.length) {
|
|
2624
2395
|
process.stderr.write('aontu: view --views takes one file\n');
|
|
@@ -2742,8 +2513,6 @@ function renderViewJson(report) {
|
|
|
2742
2513
|
}
|
|
2743
2514
|
function renderRelationsText(report) {
|
|
2744
2515
|
const head = `verdict: ${report.verdict}`;
|
|
2745
|
-
// WHY, when the document could not be evaluated at all: rendered as
|
|
2746
|
-
// vet renders a finding, because it IS one (the review's finding F).
|
|
2747
2516
|
const errors = report.errors ?? [];
|
|
2748
2517
|
if (0 < errors.length) {
|
|
2749
2518
|
return [head, ''].concat(errors.map(renderFinding)).join('\n');
|
|
@@ -2765,19 +2534,6 @@ function renderRelationsJson(report) {
|
|
|
2765
2534
|
...(null == report.errors ? {} : { errors: report.errors }),
|
|
2766
2535
|
}, 2);
|
|
2767
2536
|
}
|
|
2768
|
-
// ---------------------------------------------------------------------
|
|
2769
|
-
// JSON SCHEMA EXPORT (SUPPORT.md act 2, the review's finding I): the
|
|
2770
|
-
// bridge to every structured-output API, which constrains generation to
|
|
2771
|
-
// JSON Schema and nothing else. Export the model, let the provider
|
|
2772
|
-
// generate under it, then `vet` the result against the model itself --
|
|
2773
|
-
// the hybrid an enterprise actually deploys, and impossible without
|
|
2774
|
-
// this verb.
|
|
2775
|
-
//
|
|
2776
|
-
// THE SCHEMA GOES TO STDOUT AND THE LOSSES TO STDERR, so `aontu
|
|
2777
|
-
// jsonschema x.aon > schema.json` writes a schema and still tells the
|
|
2778
|
-
// reader what it could not carry. `--strict` makes a loss a refusal,
|
|
2779
|
-
// for the CI job that would rather fail than ship a schema weaker than
|
|
2780
|
-
// its model.
|
|
2781
2537
|
const JSONSCHEMA_HELP = 'aontu jsonschema [--at <path>] [--strict] <file> (try --help)';
|
|
2782
2538
|
function runJsonSchema(argv) {
|
|
2783
2539
|
const trusted = takeTrust(argv);
|
|
@@ -2861,331 +2617,19 @@ function runJsonSchema(argv) {
|
|
|
2861
2617
|
return 'error' === report.verdict ? 4 :
|
|
2862
2618
|
strict && 'lossy' === report.verdict ? 1 : 0;
|
|
2863
2619
|
}
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
// vet the value at --at against aontu:code, fold code.units into bytes,
|
|
2867
|
-
// and put them where the flag says -- one unit on stdout, every unit
|
|
2868
|
-
// below --out (all or nothing), or compared against --check. Exit codes
|
|
2869
|
-
// mirror jsonschema's: 0 ok; 1 lossy under --strict or drift under
|
|
2870
|
-
// --check; 2 usage or I/O, a refused unit path included; 4 the
|
|
2871
|
-
// document does not stand up or the instance is not aontu:code.
|
|
2872
|
-
const RENDER_HELP = 'aontu render [--at <path>] [--profile <file>]... [--unit <path>] ' +
|
|
2873
|
-
'[--stdout | --out <dir> | --check <dir> | --coverage] ' +
|
|
2874
|
-
'[--coverage-at <path>] [--strict] [--marker <token>] <file> (try --help)';
|
|
2875
|
-
function runRender(argv) {
|
|
2620
|
+
const TEMPLATE_HELP = 'aontu template [--resugar] [--check] [--marker <token>] <file> (try --help)';
|
|
2621
|
+
function runTemplate(argv) {
|
|
2876
2622
|
const trusted = takeTrust(argv);
|
|
2877
2623
|
if (null == trusted) {
|
|
2878
2624
|
return 2;
|
|
2879
2625
|
}
|
|
2880
2626
|
argv = trusted.argv;
|
|
2881
2627
|
const trust = trusted.trust;
|
|
2882
|
-
const files = [];
|
|
2883
|
-
const profileFiles = [];
|
|
2884
|
-
let format = 'text';
|
|
2885
|
-
let at = undefined;
|
|
2886
|
-
let unit = undefined;
|
|
2887
|
-
let out = undefined;
|
|
2888
|
-
let check = undefined;
|
|
2889
|
-
let toStdout = false;
|
|
2890
|
-
let strict = false;
|
|
2891
|
-
let coverage = false;
|
|
2892
|
-
let coverageAt = undefined;
|
|
2893
|
-
let marker = undefined;
|
|
2894
|
-
for (let i = 0; i < argv.length; i++) {
|
|
2895
|
-
const arg = argv[i];
|
|
2896
|
-
if ('-h' === arg || '--help' === arg) {
|
|
2897
|
-
process.stdout.write(HELP);
|
|
2898
|
-
return 0;
|
|
2899
|
-
}
|
|
2900
|
-
if ('--format' === arg) {
|
|
2901
|
-
const f = argv[++i];
|
|
2902
|
-
if ('text' !== f && 'json' !== f) {
|
|
2903
|
-
process.stderr.write('aontu: --format needs text or json\n');
|
|
2904
|
-
return 2;
|
|
2905
|
-
}
|
|
2906
|
-
format = f;
|
|
2907
|
-
}
|
|
2908
|
-
else if ('--at' === arg) {
|
|
2909
|
-
at = argv[++i];
|
|
2910
|
-
if (null == at) {
|
|
2911
|
-
process.stderr.write('aontu: --at needs a path\n');
|
|
2912
|
-
return 2;
|
|
2913
|
-
}
|
|
2914
|
-
}
|
|
2915
|
-
else if ('--unit' === arg) {
|
|
2916
|
-
unit = argv[++i];
|
|
2917
|
-
if (null == unit) {
|
|
2918
|
-
process.stderr.write('aontu: --unit needs a unit path\n');
|
|
2919
|
-
return 2;
|
|
2920
|
-
}
|
|
2921
|
-
}
|
|
2922
|
-
else if ('--profile' === arg) {
|
|
2923
|
-
const pf = argv[++i];
|
|
2924
|
-
if (null == pf) {
|
|
2925
|
-
process.stderr.write('aontu: --profile needs a file\n');
|
|
2926
|
-
return 2;
|
|
2927
|
-
}
|
|
2928
|
-
profileFiles.push(pf);
|
|
2929
|
-
}
|
|
2930
|
-
else if ('--out' === arg) {
|
|
2931
|
-
out = argv[++i];
|
|
2932
|
-
if (null == out) {
|
|
2933
|
-
process.stderr.write('aontu: --out needs a directory\n');
|
|
2934
|
-
return 2;
|
|
2935
|
-
}
|
|
2936
|
-
}
|
|
2937
|
-
else if ('--check' === arg) {
|
|
2938
|
-
check = argv[++i];
|
|
2939
|
-
if (null == check) {
|
|
2940
|
-
process.stderr.write('aontu: --check needs a directory\n');
|
|
2941
|
-
return 2;
|
|
2942
|
-
}
|
|
2943
|
-
}
|
|
2944
|
-
else if ('--stdout' === arg) {
|
|
2945
|
-
toStdout = true;
|
|
2946
|
-
}
|
|
2947
|
-
else if ('--coverage' === arg) {
|
|
2948
|
-
coverage = true;
|
|
2949
|
-
}
|
|
2950
|
-
else if ('--marker' === arg) {
|
|
2951
|
-
marker = argv[++i];
|
|
2952
|
-
if (null == marker) {
|
|
2953
|
-
process.stderr.write('aontu: --marker needs a token\n');
|
|
2954
|
-
return 2;
|
|
2955
|
-
}
|
|
2956
|
-
}
|
|
2957
|
-
else if ('--coverage-at' === arg) {
|
|
2958
|
-
coverageAt = argv[++i];
|
|
2959
|
-
if (null == coverageAt) {
|
|
2960
|
-
process.stderr.write('aontu: --coverage-at needs a path\n');
|
|
2961
|
-
return 2;
|
|
2962
|
-
}
|
|
2963
|
-
}
|
|
2964
|
-
else if ('--strict' === arg) {
|
|
2965
|
-
strict = true;
|
|
2966
|
-
}
|
|
2967
|
-
else if (arg.startsWith('-')) {
|
|
2968
|
-
process.stderr.write(`aontu: unknown render option ${arg} (try --help)\n`);
|
|
2969
|
-
return 2;
|
|
2970
|
-
}
|
|
2971
|
-
else {
|
|
2972
|
-
files.push(arg);
|
|
2973
|
-
}
|
|
2974
|
-
}
|
|
2975
|
-
if (1 !== files.length) {
|
|
2976
|
-
process.stderr.write(`aontu: render needs one file\n${RENDER_HELP}\n`);
|
|
2977
|
-
return 2;
|
|
2978
|
-
}
|
|
2979
|
-
const modes = [toStdout, undefined !== out, undefined !== check, coverage]
|
|
2980
|
-
.filter((on) => on).length;
|
|
2981
|
-
if (1 < modes) {
|
|
2982
|
-
process.stderr.write('aontu: render takes one of --stdout, --out, --check or --coverage\n');
|
|
2983
|
-
return 2;
|
|
2984
|
-
}
|
|
2985
|
-
// A NARROWER MEASURE NEEDS SOMETHING TO NARROW. `--coverage-at`
|
|
2986
|
-
// without `--coverage` asks for a report the run does not compute,
|
|
2987
|
-
// and answering silently would be the wrong half of the request.
|
|
2988
|
-
if (undefined !== coverageAt && !coverage) {
|
|
2989
|
-
process.stderr.write('aontu: --coverage-at needs --coverage\n');
|
|
2990
|
-
return 2;
|
|
2991
|
-
}
|
|
2992
|
-
let src;
|
|
2993
|
-
try {
|
|
2994
|
-
src = (0, node_fs_1.readFileSync)(files[0], 'utf8');
|
|
2995
|
-
}
|
|
2996
|
-
catch (err) {
|
|
2997
|
-
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
|
|
2998
|
-
return 2;
|
|
2999
|
-
}
|
|
3000
|
-
// THE ENTRY MAY BE A TEMPLATE (TEMPLATE.0.md; P8), and its EXTENSION
|
|
3001
|
-
// decides, as an include's extension decides what the include is
|
|
3002
|
-
// (ADR-012): a generator is a file in the target's own syntax, so it
|
|
3003
|
-
// carries the target's extension and never `.aon`. Desugared here
|
|
3004
|
-
// rather than anywhere deeper, because a template is an entry
|
|
3005
|
-
// spelling and not a value: an include is still aontu.
|
|
3006
|
-
if (!files[0].endsWith('.aon')) {
|
|
3007
|
-
src = (0, template_1.desugarTemplate)(src, marker ?? (0, template_1.markerFor)(files[0]));
|
|
3008
|
-
}
|
|
3009
|
-
// THE PROFILES (D5): each --profile file is a document whose root is
|
|
3010
|
-
// `profile: {lang, ...}`, evaluated under the verb's trust and vetted
|
|
3011
|
-
// against aontu:profile as a settled value before the fold reads it
|
|
3012
|
-
// (renderProfile, which also fills the defaults). Two files claiming
|
|
3013
|
-
// one lang is a usage error: the fold could not choose.
|
|
3014
|
-
const profiles = [];
|
|
3015
|
-
const langs = new Map();
|
|
3016
|
-
for (const pf of profileFiles) {
|
|
3017
|
-
let text;
|
|
3018
|
-
try {
|
|
3019
|
-
text = (0, node_fs_1.readFileSync)(pf, 'utf8');
|
|
3020
|
-
}
|
|
3021
|
-
catch (err) {
|
|
3022
|
-
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
|
|
3023
|
-
return 2;
|
|
3024
|
-
}
|
|
3025
|
-
const loaded = (0, aontu_1.renderProfile)(text, { path: (0, node_path_1.resolve)(pf), ...verbOpts(trust, entryRootOf(pf)) });
|
|
3026
|
-
if (undefined !== loaded.errors) {
|
|
3027
|
-
process.stderr.write(loaded.errors.map(renderFinding).join('\n') + '\n');
|
|
3028
|
-
return 4;
|
|
3029
|
-
}
|
|
3030
|
-
const profile = loaded.profile;
|
|
3031
|
-
const prev = langs.get(profile.lang);
|
|
3032
|
-
if (undefined !== prev) {
|
|
3033
|
-
process.stderr.write(`aontu: two profiles claim ${profile.lang}: ${prev} and ${pf}\n`);
|
|
3034
|
-
return 2;
|
|
3035
|
-
}
|
|
3036
|
-
langs.set(profile.lang, pf);
|
|
3037
|
-
profiles.push(profile);
|
|
3038
|
-
}
|
|
3039
|
-
// A RENDER WITH NO PROFILE PRODUCES NO UNITS, and said so with zero
|
|
3040
|
-
// bytes and exit 0. The profile is what maps a model onto a
|
|
3041
|
-
// language, so without one there is nothing for the renderer to
|
|
3042
|
-
// write -- which is a usable answer only if the caller is told.
|
|
3043
|
-
const noProfiles = 0 === profiles.length;
|
|
3044
|
-
const report = (0, aontu_1.render)(src, {
|
|
3045
|
-
at, unit, strict, profiles, path: files[0],
|
|
3046
|
-
coverage, coverageAt,
|
|
3047
|
-
// THE JSON REPORT CARRIES THE TRACE (D9), which is what the shape
|
|
3048
|
-
// there has always said; a text run computes it only when the
|
|
3049
|
-
// coverage report needs it.
|
|
3050
|
-
trace: 'json' === format,
|
|
3051
|
-
...verbOpts(trust, entryRootOf(files[0])),
|
|
3052
|
-
});
|
|
3053
|
-
// Said once, whatever the format: stdout stays the report.
|
|
3054
|
-
if ('error' !== report.verdict && 0 === report.units.length) {
|
|
3055
|
-
vacuous('nothing was rendered', noProfiles
|
|
3056
|
-
? 'no profile was given, and the document declares none' +
|
|
3057
|
-
' (see aontu help tasks)'
|
|
3058
|
-
: 'the document produced no units under this profile');
|
|
3059
|
-
}
|
|
3060
|
-
if ('json' === format) {
|
|
3061
|
-
process.stdout.write((0, aontu_1.exactJSON)({
|
|
3062
|
-
aontu: { version: version(), verb: 'render' },
|
|
3063
|
-
verdict: report.verdict,
|
|
3064
|
-
units: report.units,
|
|
3065
|
-
lossy: report.lossy,
|
|
3066
|
-
...(null == report.errors ? {} : { errors: report.errors }),
|
|
3067
|
-
...(null == report.trace ? {} : { trace: report.trace }),
|
|
3068
|
-
...(null == report.coverage ? {} : { coverage: report.coverage }),
|
|
3069
|
-
}, 2) + '\n');
|
|
3070
|
-
return renderExit(report, 0);
|
|
3071
|
-
}
|
|
3072
|
-
if ('error' === report.verdict) {
|
|
3073
|
-
process.stderr.write(report.errors.map(renderFinding).join('\n') + '\n');
|
|
3074
|
-
return renderExit(report, 0);
|
|
3075
|
-
}
|
|
3076
|
-
let drift = 0;
|
|
3077
|
-
if (toStdout) {
|
|
3078
|
-
// ONE UNIT'S BYTES AND NOTHING ELSE, so the output can be piped
|
|
3079
|
-
// into a formatter or a file.
|
|
3080
|
-
if (1 !== report.units.length) {
|
|
3081
|
-
process.stderr.write('aontu: --stdout needs exactly one unit, and the instance has ' +
|
|
3082
|
-
`${report.units.length}; --unit names one\n`);
|
|
3083
|
-
return 2;
|
|
3084
|
-
}
|
|
3085
|
-
process.stdout.write(report.units[0].text);
|
|
3086
|
-
}
|
|
3087
|
-
else if (undefined !== out) {
|
|
3088
|
-
// EVERY UNIT BELOW <dir>, OR NOTHING: every unit rendered first
|
|
3089
|
-
// (the report above), and no file touched unless all did. The
|
|
3090
|
-
// directory is realpath-confined; a unit path is already a relative
|
|
3091
|
-
// descent (render_path refuses the rest), and the check here is
|
|
3092
|
-
// against the symlink inside it. render never deletes.
|
|
3093
|
-
for (const u of report.units) {
|
|
3094
|
-
if ((0, mcp_1.outsideRoot)(out, (0, node_path_1.resolve)(out, u.path))) {
|
|
3095
|
-
process.stderr.write(`aontu: ${u.path} escapes ${out}\n`);
|
|
3096
|
-
return 2;
|
|
3097
|
-
}
|
|
3098
|
-
}
|
|
3099
|
-
for (const u of report.units) {
|
|
3100
|
-
const full = (0, node_path_1.resolve)(out, u.path);
|
|
3101
|
-
try {
|
|
3102
|
-
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(full), { recursive: true });
|
|
3103
|
-
(0, node_fs_1.writeFileSync)(full, u.text, 'utf8');
|
|
3104
|
-
}
|
|
3105
|
-
catch (err) {
|
|
3106
|
-
process.stderr.write(`aontu: cannot write ${u.path}: ${err.message}\n`);
|
|
3107
|
-
return 2;
|
|
3108
|
-
}
|
|
3109
|
-
process.stderr.write(`wrote ${u.path}\n`);
|
|
3110
|
-
}
|
|
3111
|
-
}
|
|
3112
|
-
else if (undefined !== check) {
|
|
3113
|
-
// RENDER AND COMPARE: a unit whose bytes differ from the file at
|
|
3114
|
-
// <dir>/<path>, or whose file is absent, is drift, listed by path.
|
|
3115
|
-
// The CI form.
|
|
3116
|
-
for (const u of report.units) {
|
|
3117
|
-
let have = undefined;
|
|
3118
|
-
try {
|
|
3119
|
-
have = (0, node_fs_1.readFileSync)((0, node_path_1.resolve)(check, u.path), 'utf8');
|
|
3120
|
-
}
|
|
3121
|
-
catch {
|
|
3122
|
-
// Absent is drift, reported below.
|
|
3123
|
-
}
|
|
3124
|
-
if (undefined === have) {
|
|
3125
|
-
drift++;
|
|
3126
|
-
process.stderr.write(`aontu: ${u.path} is missing from ${check}\n`);
|
|
3127
|
-
}
|
|
3128
|
-
else if (have !== u.text) {
|
|
3129
|
-
drift++;
|
|
3130
|
-
process.stderr.write(`aontu: ${u.path} differs from the rendered unit\n`);
|
|
3131
|
-
}
|
|
3132
|
-
}
|
|
3133
|
-
}
|
|
3134
|
-
else if (coverage) {
|
|
3135
|
-
// THE COVERAGE REPORT (P7), one line per finding and a count at
|
|
3136
|
-
// the end: dead model first, then the declarations no rule
|
|
3137
|
-
// produced. A clean report is the count line alone.
|
|
3138
|
-
const cov = report.coverage;
|
|
3139
|
-
for (const d of cov.dead) {
|
|
3140
|
-
process.stdout.write(`dead: ${d}\n`);
|
|
3141
|
-
}
|
|
3142
|
-
for (const u of cov.unruled) {
|
|
3143
|
-
process.stdout.write(`unruled: ${u.unit} ${u.path}\n`);
|
|
3144
|
-
}
|
|
3145
|
-
process.stdout.write(`coverage: ${cov.read.length} path(s) read, ${cov.dead.length} ` +
|
|
3146
|
-
`no output consumed, ${cov.unruled.length} declaration(s) ` +
|
|
3147
|
-
'no rule produced\n');
|
|
3148
|
-
}
|
|
3149
|
-
else {
|
|
3150
|
-
// THE SUMMARY: one line per unit -- its path, its language and its
|
|
3151
|
-
// size -- since several units have no one text to print.
|
|
3152
|
-
for (const u of report.units) {
|
|
3153
|
-
process.stdout.write(`${u.path}\t${u.lang}\t${u.text.length} bytes\n`);
|
|
3154
|
-
}
|
|
3155
|
-
}
|
|
3156
|
-
for (const l of report.lossy) {
|
|
3157
|
-
process.stderr.write(`lossy: ${l.unit} ${l.path} tier ${l.tier} ${l.construct}: ${l.reason}\n`);
|
|
3158
|
-
}
|
|
3159
|
-
return renderExit(report, drift);
|
|
3160
|
-
}
|
|
3161
|
-
// D8's exit table over a report: a refused unit path is usage (2), a
|
|
3162
|
-
// strict refusal is lossy (1), any other error is the document's (4);
|
|
3163
|
-
// drift under --check is 1.
|
|
3164
|
-
function renderExit(report, drift) {
|
|
3165
|
-
if ('error' === report.verdict) {
|
|
3166
|
-
const errors = report.errors;
|
|
3167
|
-
if (errors.every((f) => 'render_path' === f.code)) {
|
|
3168
|
-
return 2;
|
|
3169
|
-
}
|
|
3170
|
-
if (errors.every((f) => 'render_strict' === f.code)) {
|
|
3171
|
-
return 1;
|
|
3172
|
-
}
|
|
3173
|
-
return 4;
|
|
3174
|
-
}
|
|
3175
|
-
return 0 < drift ? 1 : 0;
|
|
3176
|
-
}
|
|
3177
|
-
// ---------------------------------------------------------------------
|
|
3178
|
-
// THE TEMPLATE SURFACE (docs/design/TEMPLATE.0.md; RENDER.0.md P8): the
|
|
3179
|
-
// two transforms and the round trip between them. `render` reads a
|
|
3180
|
-
// template directly, by its extension; this verb is for seeing the
|
|
3181
|
-
// canonical form, for writing one by hand and sugaring it, and for the
|
|
3182
|
-
// check that keeps a committed template and its meaning in agreement.
|
|
3183
|
-
const TEMPLATE_HELP = 'aontu template [--resugar] [--check] [--marker <token>] <file> (try --help)';
|
|
3184
|
-
function runTemplate(argv) {
|
|
3185
2628
|
const files = [];
|
|
3186
2629
|
let resugar = false;
|
|
3187
2630
|
let check = false;
|
|
3188
2631
|
let marker = undefined;
|
|
2632
|
+
const profileFiles = [];
|
|
3189
2633
|
for (let i = 0; i < argv.length; i++) {
|
|
3190
2634
|
const arg = argv[i];
|
|
3191
2635
|
if ('-h' === arg || '--help' === arg) {
|
|
@@ -3205,6 +2649,14 @@ function runTemplate(argv) {
|
|
|
3205
2649
|
return 2;
|
|
3206
2650
|
}
|
|
3207
2651
|
}
|
|
2652
|
+
else if ('--profile' === arg) {
|
|
2653
|
+
const pf = argv[++i];
|
|
2654
|
+
if (null == pf) {
|
|
2655
|
+
process.stderr.write('aontu: --profile needs a file\n');
|
|
2656
|
+
return 2;
|
|
2657
|
+
}
|
|
2658
|
+
profileFiles.push(pf);
|
|
2659
|
+
}
|
|
3208
2660
|
else if (arg.startsWith('-')) {
|
|
3209
2661
|
process.stderr.write(`aontu: unknown template option ${arg} (try --help)\n`);
|
|
3210
2662
|
return 2;
|
|
@@ -3217,10 +2669,6 @@ function runTemplate(argv) {
|
|
|
3217
2669
|
process.stderr.write(`aontu: template needs one file\n${TEMPLATE_HELP}\n`);
|
|
3218
2670
|
return 2;
|
|
3219
2671
|
}
|
|
3220
|
-
// THE TWO ARE DIRECTIONS, NOT MODES THAT COMPOSE: `--check` reads a
|
|
3221
|
-
// template and asks whether the round trip answers it back, and
|
|
3222
|
-
// `--resugar` reads the canonical form instead. A run cannot be both
|
|
3223
|
-
// at once, because the file is one thing or the other.
|
|
3224
2672
|
if (resugar && check) {
|
|
3225
2673
|
process.stderr.write('aontu: template takes one of --resugar or --check\n');
|
|
3226
2674
|
return 2;
|
|
@@ -3233,18 +2681,13 @@ function runTemplate(argv) {
|
|
|
3233
2681
|
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
|
|
3234
2682
|
return 2;
|
|
3235
2683
|
}
|
|
3236
|
-
const
|
|
2684
|
+
const declared = loadProfiles(profileFiles, trust);
|
|
2685
|
+
if ('number' === typeof declared) {
|
|
2686
|
+
return declared;
|
|
2687
|
+
}
|
|
2688
|
+
const mark = marker ?? (0, template_1.markerFromProfiles)(declared, files[0]) ??
|
|
2689
|
+
(0, template_1.markerFor)(files[0]);
|
|
3237
2690
|
if (check) {
|
|
3238
|
-
// THE ROUND TRIP IS THE CHECK (D6): the file held to the spelling
|
|
3239
|
-
// the two transforms answer. What that names is a marker line the
|
|
3240
|
-
// transform would not have written -- one without its space, or one
|
|
3241
|
-
// whose aontu is indented after the marker rather than before it,
|
|
3242
|
-
// since the marker keeps its own indentation. It does NOT name a
|
|
3243
|
-
// changed body line: a template's whitespace is output, so a
|
|
3244
|
-
// trimmed trailing space is still a valid template and it is
|
|
3245
|
-
// `render --check` against the committed files that catches it.
|
|
3246
|
-
// The first line that differs is the report, since a whole diff of
|
|
3247
|
-
// a generator is the file again.
|
|
3248
2691
|
const back = (0, template_1.resugarTemplate)((0, template_1.desugarTemplate)(src, mark), mark);
|
|
3249
2692
|
if (back === src) {
|
|
3250
2693
|
return 0;
|
|
@@ -3255,12 +2698,6 @@ function runTemplate(argv) {
|
|
|
3255
2698
|
while (n < want.length && n < have.length && want[n] === have[n]) {
|
|
3256
2699
|
n++;
|
|
3257
2700
|
}
|
|
3258
|
-
// THE TWO ARE THE SAME LENGTH, always: each transform maps one
|
|
3259
|
-
// line to one line and applies the same trailing-newline rule, so
|
|
3260
|
-
// `back` has as many lines as `src`. The loop above therefore stops
|
|
3261
|
-
// at a real difference rather than by running out of either -- an
|
|
3262
|
-
// equal prefix all the way to the end IS `back === src`, which
|
|
3263
|
-
// returned above. So both indexes are in range here.
|
|
3264
2701
|
process.stderr.write(`aontu: ${files[0]}:${n + 1} is not what the round trip answers\n` +
|
|
3265
2702
|
` have: ${JSON.stringify(have[n])}\n` +
|
|
3266
2703
|
` want: ${JSON.stringify(want[n])}\n`);
|
|
@@ -3270,13 +2707,38 @@ function runTemplate(argv) {
|
|
|
3270
2707
|
(0, template_1.resugarTemplate)(src, mark) : (0, template_1.desugarTemplate)(src, mark));
|
|
3271
2708
|
return 0;
|
|
3272
2709
|
}
|
|
3273
|
-
//
|
|
3274
|
-
//
|
|
3275
|
-
//
|
|
3276
|
-
//
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
2710
|
+
// The profiles named by --profile, vetted, or the exit code that says
|
|
2711
|
+
// why not. A profile is a language declared as data: `template` and
|
|
2712
|
+
// `fmt` match one to a file by the extensions its `template.ext`
|
|
2713
|
+
// names.
|
|
2714
|
+
function loadProfiles(profileFiles, trust) {
|
|
2715
|
+
const profiles = [];
|
|
2716
|
+
const langs = new Map();
|
|
2717
|
+
for (const pf of profileFiles) {
|
|
2718
|
+
let text;
|
|
2719
|
+
try {
|
|
2720
|
+
text = (0, node_fs_1.readFileSync)(pf, 'utf8');
|
|
2721
|
+
}
|
|
2722
|
+
catch (err) {
|
|
2723
|
+
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
|
|
2724
|
+
return 2;
|
|
2725
|
+
}
|
|
2726
|
+
const loaded = (0, aontu_1.loadProfile)(text, { path: (0, node_path_1.resolve)(pf), ...verbOpts(trust, entryRootOf(pf)) });
|
|
2727
|
+
if (undefined !== loaded.errors) {
|
|
2728
|
+
process.stderr.write(loaded.errors.map(renderFinding).join('\n') + '\n');
|
|
2729
|
+
return 4;
|
|
2730
|
+
}
|
|
2731
|
+
const profile = loaded.profile;
|
|
2732
|
+
const prev = langs.get(profile.lang);
|
|
2733
|
+
if (undefined !== prev) {
|
|
2734
|
+
process.stderr.write(`aontu: two profiles claim ${profile.lang}: ${prev} and ${pf}\n`);
|
|
2735
|
+
return 2;
|
|
2736
|
+
}
|
|
2737
|
+
langs.set(profile.lang, pf);
|
|
2738
|
+
profiles.push(profile);
|
|
2739
|
+
}
|
|
2740
|
+
return profiles;
|
|
2741
|
+
}
|
|
3280
2742
|
const HASH_HELP = 'aontu hash <file> (try --help)';
|
|
3281
2743
|
function runHash(argv) {
|
|
3282
2744
|
const trusted = takeTrust(argv);
|
|
@@ -3331,14 +2793,6 @@ function runHash(argv) {
|
|
|
3331
2793
|
const ctx = aontu.ctx({ collect: true });
|
|
3332
2794
|
const v = aontu.unify(src, { path: files[0] }, ctx);
|
|
3333
2795
|
if (0 < ctx.err.length || true === v?.isNil) {
|
|
3334
|
-
// A document that does not stand up on its own has no meaning to
|
|
3335
|
-
// pin, and a hash of a broken evaluation would be a pin that
|
|
3336
|
-
// silently agrees with every other broken evaluation.
|
|
3337
|
-
// WHY it does not stand up, not just that it does not: the same
|
|
3338
|
-
// diagnosis `aontu <file>` prints (the review's finding F).
|
|
3339
|
-
// evalFailure unconditionally, as every other call site does: it
|
|
3340
|
-
// owns the "ctx.err is never empty here" contract, and a guard
|
|
3341
|
-
// that pretends otherwise is a dead arm asserting nothing.
|
|
3342
2796
|
process.stderr.write(`aontu: ${files[0]} does not evaluate on its own; nothing to hash\n` +
|
|
3343
2797
|
renderFinding((0, query_1.evalFailure)(ctx)) + '\n');
|
|
3344
2798
|
return 4;
|
|
@@ -3353,12 +2807,6 @@ function runHash(argv) {
|
|
|
3353
2807
|
process.stdout.write(text + '\n');
|
|
3354
2808
|
return 0;
|
|
3355
2809
|
}
|
|
3356
|
-
// ---------------------------------------------------------------------
|
|
3357
|
-
// The query surface (G7 phase 1): one node of an evaluated document,
|
|
3358
|
-
// selected by path and rendered. Evaluation is still GLOBAL -- what
|
|
3359
|
-
// `get` buys is the size of the ANSWER, not the cost of producing it --
|
|
3360
|
-
// and the projections are lattice abstractions, each a valid Aontu
|
|
3361
|
-
// document that subsumes the truth it summarises.
|
|
3362
2810
|
const GET_HELP = 'aontu get <path> <file> (try --help)';
|
|
3363
2811
|
function runGet(argv) {
|
|
3364
2812
|
const trusted = takeTrust(argv);
|
|
@@ -3527,11 +2975,6 @@ function runWhy(argv) {
|
|
|
3527
2975
|
}
|
|
3528
2976
|
return 'no_path' === report.findings[0]?.code ? 1 : 4;
|
|
3529
2977
|
}
|
|
3530
|
-
// One contribution per line, numbered in source order, each with what
|
|
3531
|
-
// was written, where, and how it got here. A siteless contribution
|
|
3532
|
-
// prints no location rather than a `-1:-1` that means nothing —
|
|
3533
|
-
// exported for the direct test, because the site SHAPE allows one
|
|
3534
|
-
// while no document has yet produced one (ADR-002).
|
|
3535
2978
|
function renderWhyText(record) {
|
|
3536
2979
|
const head = `${record.path} = ${record.value}`;
|
|
3537
2980
|
if (0 === record.conjuncts.length) {
|
|
@@ -3547,12 +2990,6 @@ function renderWhyText(record) {
|
|
|
3547
2990
|
('literal' === c.role ? '' : ` (${c.role})`);
|
|
3548
2991
|
})).join('\n');
|
|
3549
2992
|
}
|
|
3550
|
-
// ---------------------------------------------------------------------
|
|
3551
|
-
// The overlay patch verb (G7 phase 5): change a document by APPENDING
|
|
3552
|
-
// to an overlay, not by rewriting it. An overlay entry is just another
|
|
3553
|
-
// conjunct and unification is order-independent, so this needs no
|
|
3554
|
-
// rewriter — the format-preserving in-place edit is stage 2, and needs
|
|
3555
|
-
// a comment-preserving CST the parser stack does not have.
|
|
3556
2993
|
const SET_HELP = 'aontu set <path>=<value> --entry <file> --overlay <file> (try --help)';
|
|
3557
2994
|
function runSet(argv) {
|
|
3558
2995
|
const trusted = takeTrust(argv);
|
|
@@ -3659,27 +3096,10 @@ function runSet(argv) {
|
|
|
3659
3096
|
}, 2) + '\n');
|
|
3660
3097
|
}
|
|
3661
3098
|
else {
|
|
3662
|
-
// A replacement is REPORTED as the edit it is, not left for the
|
|
3663
|
-
// reader to infer from a changed file: `where: what -> what`, in
|
|
3664
|
-
// source spelling, because the spelling is what changed.
|
|
3665
|
-
//
|
|
3666
|
-
// PAST TENSE ONLY WHERE IT HAPPENED. A refused write leaves the
|
|
3667
|
-
// file exactly as it was, and one assignment can be replaceable
|
|
3668
|
-
// while another makes the whole run invalid — so `replaced:` there
|
|
3669
|
-
// tells an operator the pin was changed when it was not, and unlike
|
|
3670
|
-
// `--dry-run` there is nothing else on the line to say otherwise.
|
|
3671
3099
|
const verb = wrote ? 'replaced' : 'would replace';
|
|
3672
3100
|
const edits = report.replaced.map((r) => `${verb}: ${r.file}:${r.row}:${r.col} ${r.from} -> ${r.to}`);
|
|
3673
3101
|
const head = [`verdict: ${report.verdict}`].concat(edits).join('\n') +
|
|
3674
3102
|
(wrote ? `\nwrote: ${overlayFile}` : dryRun ? '\n(dry run)' : '');
|
|
3675
|
-
// A SUCCESSFUL COMMAND WRITES ITS STATUS TO STDOUT, findings or
|
|
3676
|
-
// not. Routing on `findings.length` was right while every finding
|
|
3677
|
-
// this verb could produce was an ERROR; `--in-place` made a WARNING
|
|
3678
|
-
// possible, and a run that held, wrote the file and exited 0 then
|
|
3679
|
-
// sent its whole report to stderr — leaving stdout empty, so
|
|
3680
|
-
// `$(aontu set ...)` captured nothing and only the JSON form
|
|
3681
|
-
// behaved like a success. The verdict decides the stream; warnings
|
|
3682
|
-
// are diagnostics and go to stderr beside it.
|
|
3683
3103
|
const failed = 'invalid' === report.verdict || 'error' === report.verdict;
|
|
3684
3104
|
const findingText = report.findings.map(renderFinding);
|
|
3685
3105
|
if (failed) {
|
|
@@ -3698,14 +3118,6 @@ function runSet(argv) {
|
|
|
3698
3118
|
}
|
|
3699
3119
|
return VET_EXIT[report.verdict];
|
|
3700
3120
|
}
|
|
3701
|
-
// ---------------------------------------------------------------------
|
|
3702
|
-
// The role gate (docs/design/ALLOW.0.md): may the role the caller is
|
|
3703
|
-
// operating under modify these subtrees? Asked before `set`, by an
|
|
3704
|
-
// agent whose skill names its role, and answered from a role model
|
|
3705
|
-
// that is itself an aontu document. The verdict is the exit code, as
|
|
3706
|
-
// it is for every gate here: 0 is yes, 1 is no, 4 is "the model that
|
|
3707
|
-
// was to decide does not stand up", and an agent branches on nothing
|
|
3708
|
-
// else.
|
|
3709
3121
|
const ALLOW_HELP = 'aontu allow --role <role> <roles-file> <path> [more-paths...] (try --help)';
|
|
3710
3122
|
const ALLOW_EXIT = {
|
|
3711
3123
|
allowed: 0,
|
|
@@ -3808,14 +3220,6 @@ function runAllow(argv) {
|
|
|
3808
3220
|
process.stderr.write('aontu: --role needs one key, without dots\n');
|
|
3809
3221
|
return 2;
|
|
3810
3222
|
}
|
|
3811
|
-
// A path may arrive in `set`'s spelling, `$.a.b=1`, so a skill can
|
|
3812
|
-
// hand the gate the very arguments the write will get. The text up
|
|
3813
|
-
// to the first `=` is the path, and it starts with `$`: an empty
|
|
3814
|
-
// argument, or a second file name, would otherwise read as a path
|
|
3815
|
-
// and be answered. The VALUE is checked to be one value. `set`
|
|
3816
|
-
// appends it as source after the flattened path, so a value carrying
|
|
3817
|
-
// a second pair -- `3 secrets: key: "x"` -- writes a sibling of the
|
|
3818
|
-
// overlay root, a subtree the gate was never asked about.
|
|
3819
3223
|
const paths = [];
|
|
3820
3224
|
for (const arg of asked) {
|
|
3821
3225
|
const eq = arg.indexOf('=');
|
|
@@ -3949,28 +3353,17 @@ function runAgentsMd(argv) {
|
|
|
3949
3353
|
process.stdout.write(`wrote: ${write}\n`);
|
|
3950
3354
|
return 0;
|
|
3951
3355
|
}
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
// process.exit() terminates immediately, discarding anything still
|
|
3955
|
-
// queued on stdout. A write to a PIPE is asynchronous once it exceeds
|
|
3956
|
-
// the pipe buffer, so `write(big); exit(0)` silently truncated output at
|
|
3957
|
-
// 65536 bytes — while a write to a TTY or a file, being synchronous,
|
|
3958
|
-
// looked fine. Setting exitCode instead lets the process end naturally,
|
|
3959
|
-
// after the queue drains.
|
|
3960
|
-
//
|
|
3961
|
-
// This predates the exact leaves but they make it trivially reachable
|
|
3962
|
-
// (one long biginteger canon exceeds the buffer), and it lands squarely
|
|
3963
|
-
// on the parity-probe discipline in AGENTS.md, which derives expected
|
|
3964
|
-
// spec values by piping BOTH CLIs and comparing. A truncated pipe there
|
|
3965
|
-
// reads as a port divergence.
|
|
3966
|
-
// ---------------------------------------------------------------------
|
|
3967
|
-
// The source formatter (docs/design/FMT.0.md): one agreed form, in the
|
|
3968
|
-
// tradition of gofmt. The verb prints, lists, checks, diffs or rewrites;
|
|
3969
|
-
// the form itself is the library's (ts/src/format.ts), and the two
|
|
3970
|
-
// ports agree on it row by row in test/spec/fmt.tsv.
|
|
3971
|
-
const FMT_HELP = 'aontu fmt [-w|-l|--check|-d|--lint] [--marker <token>] <file>... (try --help)';
|
|
3356
|
+
const FMT_HELP = 'aontu fmt [-w|-l|--check|-d|--lint] [--marker <token>] ' +
|
|
3357
|
+
'[--profile <file>] <file>... (try --help)';
|
|
3972
3358
|
function runFmt(argv) {
|
|
3359
|
+
const trusted = takeTrust(argv);
|
|
3360
|
+
if (null == trusted) {
|
|
3361
|
+
return 2;
|
|
3362
|
+
}
|
|
3363
|
+
argv = trusted.argv;
|
|
3364
|
+
const trust = trusted.trust;
|
|
3973
3365
|
const files = [];
|
|
3366
|
+
const profileFiles = [];
|
|
3974
3367
|
let marker = undefined;
|
|
3975
3368
|
const flags = {
|
|
3976
3369
|
write: false, list: false, check: false, diff: false, lint: false, strict: false,
|
|
@@ -4002,14 +3395,22 @@ function runFmt(argv) {
|
|
|
4002
3395
|
}
|
|
4003
3396
|
else if ('--marker' === arg) {
|
|
4004
3397
|
// THE MARKER SAYS THE FILE IS A GENERATOR, whatever its
|
|
4005
|
-
// extension: `
|
|
4006
|
-
//
|
|
3398
|
+
// extension: `fmt` and `template` take the same option for the
|
|
3399
|
+
// same reason, a language the table has never seen.
|
|
4007
3400
|
marker = argv[++i];
|
|
4008
3401
|
if (null == marker) {
|
|
4009
3402
|
process.stderr.write('aontu: --marker needs a token\n');
|
|
4010
3403
|
return 2;
|
|
4011
3404
|
}
|
|
4012
3405
|
}
|
|
3406
|
+
else if ('--profile' === arg) {
|
|
3407
|
+
const pf = argv[++i];
|
|
3408
|
+
if (null == pf) {
|
|
3409
|
+
process.stderr.write('aontu: --profile needs a file\n');
|
|
3410
|
+
return 2;
|
|
3411
|
+
}
|
|
3412
|
+
profileFiles.push(pf);
|
|
3413
|
+
}
|
|
4013
3414
|
else if (arg.startsWith('-')) {
|
|
4014
3415
|
process.stderr.write(`aontu: unknown fmt option ${arg} (try --help)\n`);
|
|
4015
3416
|
return 2;
|
|
@@ -4033,6 +3434,10 @@ function runFmt(argv) {
|
|
|
4033
3434
|
process.stdin.on('end', () => resolve(fmtOne('<stdin>', src, flags, marker)));
|
|
4034
3435
|
});
|
|
4035
3436
|
}
|
|
3437
|
+
const declared = loadProfiles(profileFiles, trust);
|
|
3438
|
+
if ('number' === typeof declared) {
|
|
3439
|
+
return declared;
|
|
3440
|
+
}
|
|
4036
3441
|
// Several files onto standard output would be one stream nobody can
|
|
4037
3442
|
// split again (the note's X-6): the verb refuses unless an option
|
|
4038
3443
|
// says what to do with each.
|
|
@@ -4051,32 +3456,18 @@ function runFmt(argv) {
|
|
|
4051
3456
|
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`);
|
|
4052
3457
|
return 2;
|
|
4053
3458
|
}
|
|
4054
|
-
const mark = fmtMarker(file, src, marker);
|
|
3459
|
+
const mark = fmtMarker(file, src, marker ?? (0, template_1.markerFromProfiles)(declared, file));
|
|
4055
3460
|
if (false === mark) {
|
|
4056
3461
|
process.stderr.write(`aontu: ${file} is not aontu source (.aon, .aontu) and carries no ` +
|
|
4057
3462
|
`${(0, template_1.markerFor)(file)} marker line, so there is no aontu in it to ` +
|
|
4058
|
-
'format; --marker names the marker for a language the table
|
|
4059
|
-
'not know\n');
|
|
3463
|
+
'format; --marker names the marker for a language the table ' +
|
|
3464
|
+
'does not know, and --profile reads one that declares it\n');
|
|
4060
3465
|
return 2;
|
|
4061
3466
|
}
|
|
4062
3467
|
worst = Math.max(worst, fmtOne(file, src, flags, mark));
|
|
4063
3468
|
}
|
|
4064
3469
|
return worst;
|
|
4065
3470
|
}
|
|
4066
|
-
// WHAT A FILE IS, BY ITS EXTENSION (ADR-012's rule, and the one
|
|
4067
|
-
// `render` reads an entry by): `.aon` and `.aontu` are aontu source,
|
|
4068
|
-
// and anything else is a GENERATOR written in the target's own syntax
|
|
4069
|
-
// (docs/design/TEMPLATE.0.md), whose marker lines carry the document
|
|
4070
|
-
// this formats and whose other lines are output. `undefined` is aontu,
|
|
4071
|
-
// a string is the generator's marker, and `false` is neither.
|
|
4072
|
-
//
|
|
4073
|
-
// A FILE WITH NO MARKER LINE IN IT IS NEITHER, and that is what keeps
|
|
4074
|
-
// FMT.0.md §9's boundary where it stood: a `.json`, `.yaml` or `.toml`
|
|
4075
|
-
// include is another language's file, and reading one as a generator
|
|
4076
|
-
// would answer it back unchanged having understood none of it. The
|
|
4077
|
-
// marker is the evidence that a file was written to carry aontu at
|
|
4078
|
-
// all. `--marker` says so outright, and then the file is a generator
|
|
4079
|
-
// whatever it is called.
|
|
4080
3471
|
function fmtMarker(file, src, marker) {
|
|
4081
3472
|
if (undefined !== marker) {
|
|
4082
3473
|
return marker;
|
|
@@ -4132,11 +3523,8 @@ function fmtOne(name, src, flags, marker) {
|
|
|
4132
3523
|
}
|
|
4133
3524
|
return flags.check ? 1 : strict;
|
|
4134
3525
|
}
|
|
4135
|
-
//
|
|
4136
|
-
//
|
|
4137
|
-
// cli.test.ts run each through a child process instead, so these two
|
|
4138
|
-
// lines are excluded from the in-process count, as the stdio wiring
|
|
4139
|
-
// of lsp-server.ts is.
|
|
3526
|
+
// Excluded: the real pair takes the process stdio, so ts/test/cli.test.ts
|
|
3527
|
+
// drives each server through a child process instead.
|
|
4140
3528
|
/* node:coverage ignore next 4 */
|
|
4141
3529
|
const SERVERS = {
|
|
4142
3530
|
lsp: () => void (0, lsp_server_1.main)(),
|
|
@@ -4176,19 +3564,6 @@ function parseTrustArg(value) {
|
|
|
4176
3564
|
}
|
|
4177
3565
|
return undefined;
|
|
4178
3566
|
}
|
|
4179
|
-
// THE TEACHING PACK, SERVED FROM THE COMMAND (G11 phase 1,
|
|
4180
|
-
// docs/capability-review/g11-agent-onramp.md; mirrors
|
|
4181
|
-
// go/cmd/aontu/help.go).
|
|
4182
|
-
//
|
|
4183
|
-
// HELP documents the TOOLCHAIN and says nothing about the LANGUAGE:
|
|
4184
|
-
// `&`, the map template and the one construct an ontology cannot be
|
|
4185
|
-
// written without, occurs zero times in it, while `template` occurs
|
|
4186
|
-
// fourteen times and names an unrelated verb every time. docs/skill/
|
|
4187
|
-
// was already the right content and already gated; the gap was
|
|
4188
|
-
// DELIVERY, since it reached an installation as
|
|
4189
|
-
// node_modules/aontu/skill/ where nothing looks. ts/src/helpdoc.ts is
|
|
4190
|
-
// generated from those sources by ts/scripts/helpdoc.cjs and asserted
|
|
4191
|
-
// byte-identical with them by ts/test/helpdoc.test.ts.
|
|
4192
3567
|
const HELP_VERB_HELP = 'aontu help [topic] (try `aontu help` for the topics)';
|
|
4193
3568
|
const EXPLAIN_HELP = 'aontu explain <code> (try `aontu explain --list`)';
|
|
4194
3569
|
function helpIndexText(index) {
|
|
@@ -4260,22 +3635,6 @@ function runHelp(argv) {
|
|
|
4260
3635
|
`aontu: topics are ${helpdoc_1.HELPDOC.map((t) => t.topic).join(', ')}\n`);
|
|
4261
3636
|
return 2;
|
|
4262
3637
|
}
|
|
4263
|
-
// `aontu explain <code>` (G11 phase 3; mirrors
|
|
4264
|
-
// go/cmd/aontu/explain.go).
|
|
4265
|
-
//
|
|
4266
|
-
// THE REGISTRY IS THE LIST, NOT THE HINT TABLE. test/spec/errcodes.tsv
|
|
4267
|
-
// registers 157 codes and the spec suite asserts set equality between
|
|
4268
|
-
// the file and codeClasses IN BOTH PORTS, so listing from codeClasses
|
|
4269
|
-
// is listing the shared contract. The hint tables are smaller and are
|
|
4270
|
-
// NOT in parity -- 130 entries here against 131 in Go, the extra being
|
|
4271
|
-
// decimal_syntax, which this port never raises -- so listing from them
|
|
4272
|
-
// would make `aontu explain --list` differ between ports over a
|
|
4273
|
-
// difference that is not about what either port can report.
|
|
4274
|
-
//
|
|
4275
|
-
// A REGISTERED CODE WITH NO HINT ANSWERS WITH ITS CLASS AND SAYS SO.
|
|
4276
|
-
// Twenty-seven registered codes carry no explanation text here; before
|
|
4277
|
-
// this verb their absence was invisible, because a hint is only ever
|
|
4278
|
-
// seen beside the error that raises it.
|
|
4279
3638
|
// The dynamic prefixes a generated code extends (`func:upper`,
|
|
4280
3639
|
// `op[+]`). Mirrors CODE_PREFIXES in ts/src/hints.ts, which is not
|
|
4281
3640
|
// exported; a code that extends one is registered through its prefix
|
|
@@ -4399,20 +3758,6 @@ function runExplain(argv) {
|
|
|
4399
3758
|
process.stdout.write(`code: ${code}\nclass: ${cls}\n\n${body}\n`);
|
|
4400
3759
|
return 0;
|
|
4401
3760
|
}
|
|
4402
|
-
// `aontu init` (G11 phase 6,
|
|
4403
|
-
// docs/capability-review/g11-agent-onramp.md).
|
|
4404
|
-
//
|
|
4405
|
-
// NOT SCAFFOLDING CONVENIENCE. The agent's most expensive failure is
|
|
4406
|
-
// writing a FIRST document at all: the measurement that opened G11
|
|
4407
|
-
// found one reaching for the wildcard its neighbours use and getting
|
|
4408
|
-
// `verdict: valid` over data that violates it. A known-good starting
|
|
4409
|
-
// document turns generation into editing, which is the operation a
|
|
4410
|
-
// model is reliably good at.
|
|
4411
|
-
//
|
|
4412
|
-
// The trio is real, runnable and tested where it lives
|
|
4413
|
-
// (docs/skill/init/, run by ts/test/helpdoc.test.ts), and staged into
|
|
4414
|
-
// both ports by the same generator that stages the teaching pack, so
|
|
4415
|
-
// the two write the same bytes.
|
|
4416
3761
|
const INIT_HELP = 'aontu init [dir] (try --help)';
|
|
4417
3762
|
function runInit(argv) {
|
|
4418
3763
|
const dirs = [];
|
|
@@ -4432,10 +3777,6 @@ function runInit(argv) {
|
|
|
4432
3777
|
return 2;
|
|
4433
3778
|
}
|
|
4434
3779
|
const dir = dirs[0] ?? '.';
|
|
4435
|
-
// REFUSES TO OVERWRITE, and checks every member BEFORE writing any of
|
|
4436
|
-
// them: a scaffold that wrote two files and then refused the third
|
|
4437
|
-
// would leave a directory in a state neither the caller nor a re-run
|
|
4438
|
-
// can reason about.
|
|
4439
3780
|
const standing = helpdoc_1.INITDOC.filter((f) => (0, node_fs_1.existsSync)((0, node_path_1.join)(dir, f.name)));
|
|
4440
3781
|
if (0 < standing.length) {
|
|
4441
3782
|
process.stderr.write(`aontu: ${dir} already holds ${standing.map((f) => f.name).join(', ')}\n` +
|
|
@@ -4459,17 +3800,11 @@ function runInit(argv) {
|
|
|
4459
3800
|
'Learn the language: aontu help language\n');
|
|
4460
3801
|
return 0;
|
|
4461
3802
|
}
|
|
4462
|
-
// EVERY VERB THIS PORT DISPATCHES, for the nearest-verb suggestion
|
|
4463
|
-
// G11 phase 2 prints. A separate list from the if-chain in main()
|
|
4464
|
-
// because the chain's arms have three different shapes and cannot be
|
|
4465
|
-
// a table; ts/test/cli-help.test.ts keeps the two from drifting by
|
|
4466
|
-
// running each name and requiring it not to fall through to the bare
|
|
4467
|
-
// command.
|
|
4468
3803
|
const KNOWN_VERBS = [
|
|
4469
3804
|
'agentsmd', 'allow', 'breaking', 'explain', 'fmt', 'get', 'hash',
|
|
4470
3805
|
'help', 'init', 'jsonschema', 'lsp', 'mcp', 'mod', 'reaches',
|
|
4471
|
-
'relations', '
|
|
4472
|
-
'view', 'why',
|
|
3806
|
+
'relations', 'set', 'subsume', 'template', 'trace', 'trim',
|
|
3807
|
+
'vet', 'view', 'why',
|
|
4473
3808
|
];
|
|
4474
3809
|
exports.KNOWN_VERBS = KNOWN_VERBS;
|
|
4475
3810
|
// looksLikeVerb reports whether an unreadable argument was meant as a
|
|
@@ -4481,13 +3816,6 @@ function looksLikeVerb(arg) {
|
|
|
4481
3816
|
!/[/\\.]/.test(arg) &&
|
|
4482
3817
|
!arg.startsWith('-');
|
|
4483
3818
|
}
|
|
4484
|
-
// NEAREST-VERB SUGGESTION (G11 phase 2). Restricted
|
|
4485
|
-
// Damerau-Levenshtein with a cap that grows with the word and stops at
|
|
4486
|
-
// three: one edit is a convincing suggestion on any length, three is
|
|
4487
|
-
// the most that can be believed on a long one, and an UNCAPPED
|
|
4488
|
-
// nearest match on a three-letter typo names something unrelated with
|
|
4489
|
-
// confidence. Mirrors go/cmd/aontu/help.go, including the sort, so
|
|
4490
|
-
// the two ports suggest the same verb on a tie.
|
|
4491
3819
|
function nearestVerb(word, verbs) {
|
|
4492
3820
|
let best = '';
|
|
4493
3821
|
let bestDist = Infinity;
|
|
@@ -4501,8 +3829,6 @@ function nearestVerb(word, verbs) {
|
|
|
4501
3829
|
}
|
|
4502
3830
|
return bestDist > limit ? '' : best;
|
|
4503
3831
|
}
|
|
4504
|
-
// Levenshtein with a transposition, iterative over two rows. Mirrors
|
|
4505
|
-
// editDistance in go/cmd/aontu/help.go exactly.
|
|
4506
3832
|
function editDistance(a, b) {
|
|
4507
3833
|
const ar = [...a];
|
|
4508
3834
|
const br = [...b];
|
|
@@ -4527,25 +3853,12 @@ function editDistance(a, b) {
|
|
|
4527
3853
|
return prev[br.length];
|
|
4528
3854
|
}
|
|
4529
3855
|
function main(argv, servers = SERVERS) {
|
|
4530
|
-
// COLOUR OFF WHEN THE DESTINATION IS NOT A TERMINAL. Error frames
|
|
4531
|
-
// hardcoded their ANSI escapes, so a piped report and a `--jsonl`
|
|
4532
|
-
// answer carried terminal control codes into whatever read them (the
|
|
4533
|
-
// review's finding F). `NO_COLOR` is honoured by the library itself;
|
|
4534
|
-
// only the CLI can see whether its stderr is a terminal, so only the
|
|
4535
|
-
// CLI can make this call. `undefined` means "leave it to NO_COLOR".
|
|
4536
3856
|
(0, aontu_1.setColor)(true === process.stderr.isTTY ? undefined : false);
|
|
4537
3857
|
let mode = 'json';
|
|
4538
3858
|
// THE REPORT FORM (G11 phase 7), default text: every existing caller
|
|
4539
3859
|
// reads exactly what it always read, and a caller that asks for json
|
|
4540
3860
|
// gets the failure in the finding shape every other verb reports.
|
|
4541
3861
|
let format = 'text';
|
|
4542
|
-
// A LIST, though the bare command evaluates exactly one document.
|
|
4543
|
-
// It used to be one variable and the last argument won, which made a
|
|
4544
|
-
// MISTYPED VERB a silent success: `aontu vet2 schema.aon good.json`
|
|
4545
|
-
// printed good.json and exited 0, because `vet2` matched no
|
|
4546
|
-
// subcommand, fell through to this loop as a file name, and was
|
|
4547
|
-
// overwritten twice. In a tool loop that reads as a passing
|
|
4548
|
-
// validation. Counting them is what lets the refusal below happen.
|
|
4549
3862
|
const files = [];
|
|
4550
3863
|
let trust = { kind: 'system-warn', textExt: [] };
|
|
4551
3864
|
let textExt = [];
|
|
@@ -4554,15 +3867,6 @@ function main(argv, servers = SERVERS) {
|
|
|
4554
3867
|
// than the design's --json, which would read as the `:json` output
|
|
4555
3868
|
// mode the REPL already has.
|
|
4556
3869
|
let jsonl = false;
|
|
4557
|
-
// Subcommand dispatch, and deliberately only for a FIRST argument:
|
|
4558
|
-
// `aontu vet` is the verb, while `aontu somefile vet` keeps meaning
|
|
4559
|
-
// what it always did. A file named `vet` is still reachable as
|
|
4560
|
-
// `aontu ./vet`.
|
|
4561
|
-
//
|
|
4562
|
-
// Promise.resolve either way: a non-watch run returns its exit class
|
|
4563
|
-
// synchronously (and has already written its report), while `--watch`
|
|
4564
|
-
// resolves only when the watch ends — so one await-shaped line serves
|
|
4565
|
-
// both without a branch to keep covered.
|
|
4566
3870
|
if ('vet' === argv[2]) {
|
|
4567
3871
|
return void Promise.resolve(runVet(argv.slice(3))).then(finish);
|
|
4568
3872
|
}
|
|
@@ -4620,12 +3924,12 @@ function main(argv, servers = SERVERS) {
|
|
|
4620
3924
|
if ('jsonschema' === argv[2]) {
|
|
4621
3925
|
return finish(runJsonSchema(argv.slice(3)));
|
|
4622
3926
|
}
|
|
4623
|
-
if ('render' === argv[2]) {
|
|
4624
|
-
return finish(runRender(argv.slice(3)));
|
|
4625
|
-
}
|
|
4626
3927
|
if ('template' === argv[2]) {
|
|
4627
3928
|
return finish(runTemplate(argv.slice(3)));
|
|
4628
3929
|
}
|
|
3930
|
+
if ('trace' === argv[2]) {
|
|
3931
|
+
return finish(runTrace(argv.slice(3)));
|
|
3932
|
+
}
|
|
4629
3933
|
if ('reaches' === argv[2]) {
|
|
4630
3934
|
return finish(runReaches(argv.slice(3)));
|
|
4631
3935
|
}
|
|
@@ -4699,23 +4003,12 @@ function main(argv, servers = SERVERS) {
|
|
|
4699
4003
|
files.push(arg);
|
|
4700
4004
|
}
|
|
4701
4005
|
}
|
|
4702
|
-
// ONE DOCUMENT. The bare form has always been `aontu [options]
|
|
4703
|
-
// [file]`, singular, and anything past the first was silently
|
|
4704
|
-
// discarded rather than refused -- so every way of getting the verb
|
|
4705
|
-
// wrong (a typo, a verb this port does not have, a verb spelled for
|
|
4706
|
-
// another tool) ended in a plausible answer about the wrong file.
|
|
4707
|
-
// Exit 2, the usage class, and the message names the cause rather
|
|
4708
|
-
// than the symptom: nothing here can tell a mistyped verb from a
|
|
4709
|
-
// second file, but the reader can.
|
|
4710
4006
|
if (1 < files.length) {
|
|
4711
4007
|
process.stderr.write(`aontu: the bare command evaluates one document, and ${files.length}` +
|
|
4712
4008
|
' were given\naontu: a mistyped verb reads as a file name' +
|
|
4713
4009
|
' (try --help)\n');
|
|
4714
4010
|
return finish(2);
|
|
4715
4011
|
}
|
|
4716
|
-
// The extensions ride with the capability from here on, so the three
|
|
4717
|
-
// entry shapes below (file, REPL, stdin) each get them by threading
|
|
4718
|
-
// the one value they already thread.
|
|
4719
4012
|
trust = { ...trust, textExt };
|
|
4720
4013
|
const file = files[0];
|
|
4721
4014
|
if (null != file) {
|
|
@@ -4731,5 +4024,5 @@ function main(argv, servers = SERVERS) {
|
|
|
4731
4024
|
else {
|
|
4732
4025
|
runStdin(mode, format, trust).then((code) => finish(code));
|
|
4733
4026
|
}
|
|
4734
|
-
} /* node:coverage ignore next
|
|
4027
|
+
} /* node:coverage ignore next 21 */
|
|
4735
4028
|
//# sourceMappingURL=cli.js.map
|