aontu 0.62.0 → 0.63.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 +1 -1
- 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 +1 -1
- package/dist/aontu.js +1 -79
- package/dist/aontu.js.map +1 -1
- package/dist/aontumodel.d.ts +4 -0
- package/dist/aontumodel.js +33 -0
- package/dist/aontumodel.js.map +1 -0
- package/dist/cli.js +101 -620
- 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 +1 -1
- package/dist/helpdoc.js.map +1 -1
- package/dist/hints.d.ts +0 -6
- package/dist/hints.js +54 -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/lower.js +11 -61
- package/dist/lower.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 -113
- package/dist/mcp.js.map +1 -1
- package/dist/mod-tool.js +0 -130
- 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/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/render.js +20 -135
- package/dist/render.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/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 +12 -242
- 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.js +2 -59
- 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 +8 -42
- 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 +0 -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/src/agentsmd.ts +0 -35
- package/src/alias.ts +0 -39
- package/src/allow.ts +1 -96
- package/src/aontu.ts +3 -110
- package/src/aontumodel.ts +32 -0
- package/src/cli.ts +113 -682
- 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 +1 -1
- package/src/hints.ts +66 -57
- package/src/jsonschema.ts +0 -123
- package/src/keyorder.ts +0 -42
- package/src/lang.ts +19 -931
- package/src/lower.ts +12 -62
- 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 -130
- package/src/mod-tool.ts +0 -158
- package/src/mod.ts +0 -178
- package/src/patch.ts +0 -232
- 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/render.ts +20 -172
- 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/trim.ts +0 -53
- package/src/type.ts +2 -45
- package/src/unify.ts +13 -251
- 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 +4 -166
- 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 +8 -95
- 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 +0 -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/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/std.ts +0 -683
package/src/graph.ts
CHANGED
|
@@ -1,22 +1,5 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
2
|
|
|
3
|
-
// THE DERIVED STRUCTURE (G4 phase 3,
|
|
4
|
-
// docs/capability-review/g4-identity-relations.md): an evaluated
|
|
5
|
-
// document has, besides its value, a GRAPH — the set of checked links,
|
|
6
|
-
// each from one tree position to another.
|
|
7
|
-
//
|
|
8
|
-
// The graph is PATH-NATIVE (ADR-014). There is no second namespace to
|
|
9
|
-
// index: a node's address is its path, so the entity index the first
|
|
10
|
-
// design carried is exactly the set of paths already in the edges, and
|
|
11
|
-
// the node a link starts at is derived from where the link sits rather
|
|
12
|
-
// than declared by a mark.
|
|
13
|
-
//
|
|
14
|
-
// G4's deliverable is that this exists and is DETERMINISTIC. What is
|
|
15
|
-
// built on it — impact analysis ("what reaches $.services.auth?"),
|
|
16
|
-
// reachability, context-window-sized slices — is a traversal, and its
|
|
17
|
-
// exposure as verbs and projections belongs to G7. Relation properties
|
|
18
|
-
// (acyclicity, inverse consistency) are G4 phase 5's, and consume
|
|
19
|
-
// exactly this edge set.
|
|
20
3
|
|
|
21
4
|
import type { Val } from './type'
|
|
22
5
|
|
|
@@ -24,35 +7,17 @@ import { cmpCodePoint } from './keyorder'
|
|
|
24
7
|
|
|
25
8
|
|
|
26
9
|
export type Edge = {
|
|
27
|
-
// The node the link starts at, as a `$.dotted.path`: the link's own
|
|
28
|
-
// position with the relation key and any list indices stripped. `$`
|
|
29
|
-
// when the link sits at the top of the document.
|
|
30
10
|
from: string
|
|
31
|
-
// The RELATION: the key the link hangs under, so a link inside a
|
|
32
|
-
// list (`dependsOn: [refer() & "$.a"]`) is an edge under `dependsOn`
|
|
33
|
-
// rather than under `0`. A rel()-minted link carries its predicate
|
|
34
|
-
// declared rather than inferred.
|
|
35
11
|
key: string
|
|
36
|
-
// The address, as the link spells it.
|
|
37
12
|
to: string
|
|
38
13
|
// Where the link is, as a `$.dotted.path`, so a report can point at
|
|
39
14
|
// it.
|
|
40
15
|
at: string
|
|
41
|
-
// Set when the link sits inside a `hide()`-marked subtree. The link
|
|
42
|
-
// is still checked and still an edge, but a figure that draws it
|
|
43
|
-
// DISCLOSES what the document hides, so the view extractors skip it
|
|
44
|
-
// and report it as `hidden_contribution`.
|
|
45
16
|
hidden?: true
|
|
46
17
|
}
|
|
47
18
|
|
|
48
19
|
export type Graph = {
|
|
49
20
|
edges: Edge[]
|
|
50
|
-
// The positions of links written under an UNRESOLVED DISJUNCTION.
|
|
51
|
-
// ADR-007: an unresolved disjunction is not a value, so a link
|
|
52
|
-
// beneath one of its arms is not a fact and is not an edge -- but it
|
|
53
|
-
// is not nothing either, and a figure that silently dropped it would
|
|
54
|
-
// be the failure the views exist to avoid. Absent when there are
|
|
55
|
-
// none, so a graph of a decided document is the shape it always was.
|
|
56
21
|
disjunct?: string[]
|
|
57
22
|
}
|
|
58
23
|
|
|
@@ -66,14 +31,6 @@ const formatPath = (path: string[]): string =>
|
|
|
66
31
|
const isIndex = (seg: string): boolean => /^[0-9]+$/.test(seg)
|
|
67
32
|
|
|
68
33
|
|
|
69
|
-
// The node a link starts at and the relation it hangs under, derived
|
|
70
|
-
// from the link's own position.
|
|
71
|
-
//
|
|
72
|
-
// A DECLARED predicate (rel()-minted) is authoritative: the link is cut
|
|
73
|
-
// at the key the rel() sat on, wherever that is on the way down, which
|
|
74
|
-
// is what makes a MAP-valued relation report the relation rather than
|
|
75
|
-
// the inner label. Without one the relation is INFERRED: strip the list
|
|
76
|
-
// indices, and the first real key above the link is it.
|
|
77
34
|
const cut = (
|
|
78
35
|
at: string[], relkey: string | undefined
|
|
79
36
|
): { from: string, key: string } => {
|
|
@@ -92,11 +49,6 @@ const cut = (
|
|
|
92
49
|
}
|
|
93
50
|
|
|
94
51
|
|
|
95
|
-
// The graph of an evaluated tree. Walks POSITIONS, not values: a
|
|
96
|
-
// reference or a spread can put one value object at several positions,
|
|
97
|
-
// and a walk guarded by object identity would find the first and miss
|
|
98
|
-
// every other place it is reached. The guard is therefore the ancestor
|
|
99
|
-
// chain — which is what a cycle actually is.
|
|
100
52
|
export function graphOf(root: Val): Graph {
|
|
101
53
|
const edges: Edge[] = []
|
|
102
54
|
const disjunct: string[] = []
|
|
@@ -136,11 +88,6 @@ export function graphOf(root: Val): Graph {
|
|
|
136
88
|
visit(node.held, path, ancestors, hidden, undecided)
|
|
137
89
|
}
|
|
138
90
|
|
|
139
|
-
// An unresolved conjunction (a link waiting on a peer that never
|
|
140
|
-
// came, a constraint still open) holds its terms at the SAME
|
|
141
|
-
// position; every link among them is written there, and is an
|
|
142
|
-
// edge. This is what a match-selected branch or a deferred refer()
|
|
143
|
-
// looks like after evaluation.
|
|
144
91
|
if (true === node.isConjunct && Array.isArray(node.peg)) {
|
|
145
92
|
ancestors.add(node)
|
|
146
93
|
for (const term of node.peg) {
|
|
@@ -149,10 +96,6 @@ export function graphOf(root: Val): Graph {
|
|
|
149
96
|
ancestors.delete(node)
|
|
150
97
|
}
|
|
151
98
|
|
|
152
|
-
// AN UNRESOLVED DISJUNCTION IS NOT A VALUE (ADR-007), so a link
|
|
153
|
-
// under one of its arms is not an edge. Its POSITION is collected
|
|
154
|
-
// instead, so a figure can report what the document leaves
|
|
155
|
-
// undecided rather than drawing it or dropping it in silence.
|
|
156
99
|
if (true === node.isDisjunct && Array.isArray(node.peg)) {
|
|
157
100
|
ancestors.add(node)
|
|
158
101
|
for (const arm of node.peg) {
|
|
@@ -172,10 +115,6 @@ export function graphOf(root: Val): Graph {
|
|
|
172
115
|
|
|
173
116
|
visit(root, [], new Set(), false, false)
|
|
174
117
|
|
|
175
|
-
// DETERMINISTIC by construction, not by luck: edges by the position
|
|
176
|
-
// they are written at, which is unique — one link, one place. That
|
|
177
|
-
// holds through a conjunction too: its terms share the position, and
|
|
178
|
-
// two links there would have had to unify into one.
|
|
179
118
|
edges.sort((a, b) => cmpCodePoint(a.at, b.at))
|
|
180
119
|
|
|
181
120
|
if (0 < disjunct.length) {
|
package/src/hcanon.ts
CHANGED
|
@@ -1,44 +1,5 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
2
|
|
|
3
|
-
// The HASH FORM (G6 phase 0, docs/capability-review/g6-distribution.md):
|
|
4
|
-
// exactly the unify-level canon with the additions that close its
|
|
5
|
-
// semantic gaps, so that two documents with the same hash form have the
|
|
6
|
-
// same meaning:
|
|
7
|
-
//
|
|
8
|
-
// - a CLOSED map or list renders wrapped: close({...}), close([...])
|
|
9
|
-
// (canon drops closedness);
|
|
10
|
-
// - the type/hide MARKS render as their builtin wrappers: type(x),
|
|
11
|
-
// hide(x) (canon drops marks).
|
|
12
|
-
//
|
|
13
|
-
// Both additions reuse existing parseable syntax, so the hash form
|
|
14
|
-
// remains valid Aontu source and round-trips:
|
|
15
|
-
// hcanon(unify(parse(hcanon(v)))) == hcanon(v) is a spec-suite property
|
|
16
|
-
// (test/spec/hcanon.tsv). User-facing canon is UNCHANGED — hcanon is a
|
|
17
|
-
// separate rendering.
|
|
18
|
-
//
|
|
19
|
-
// An ALIAS REFERENCE left standing in a spread template renders its
|
|
20
|
-
// EXPANSION through this same walk rather than through the reference's
|
|
21
|
-
// own canon, so a close() or a mark on the aliased value survives into
|
|
22
|
-
// the hash. Without that the wrappers above are absent exactly where
|
|
23
|
-
// the alias filter has already erased the declaration that carried
|
|
24
|
-
// them (BUGS.md §60).
|
|
25
|
-
//
|
|
26
|
-
// The marks PROPAGATE to every descendant at unification (walkMark), so
|
|
27
|
-
// a wrapper is emitted only where a mark STARTS: the walk carries the
|
|
28
|
-
// inherited marks down and a child whose mark the parent already
|
|
29
|
-
// carries renders bare. Without that, hide({a:1}) would render every
|
|
30
|
-
// leaf re-wrapped — still correct, never minimal, and not what the
|
|
31
|
-
// source said.
|
|
32
|
-
//
|
|
33
|
-
// canonHash (G6 phase 1) is the pin built on it:
|
|
34
|
-
// "aon1-" + base64url( SHA-256( UTF-8( hcanon(v) ) ) )
|
|
35
|
-
// (unpadded base64url, RFC 4648 section 5). The "aon1-" scheme id
|
|
36
|
-
// exists so a future semantically-stronger normal form is an upgrade,
|
|
37
|
-
// not a breakage. This is a CANONICAL-TEXT hash, not a semantic
|
|
38
|
-
// equivalence class: the failure direction is the safe one — a false
|
|
39
|
-
// "changed" forces a needless re-review; a false "unchanged" would need
|
|
40
|
-
// two hash forms with the same bytes and different meanings, which is
|
|
41
|
-
// exactly the gap the close/mark wrappers exist to shut.
|
|
42
3
|
|
|
43
4
|
import { createHash } from 'node:crypto'
|
|
44
5
|
|
|
@@ -53,15 +14,6 @@ type HMarks = {
|
|
|
53
14
|
}
|
|
54
15
|
|
|
55
16
|
|
|
56
|
-
// One node's rendering, carrying the marks the ANCESTORS already
|
|
57
|
-
// wrapped. Bags and junctions recurse structurally (their canon getters
|
|
58
|
-
// render children through plain canon, which would drop a nested
|
|
59
|
-
// close), and so does an expanded alias reference, for the reason its
|
|
60
|
-
// own arm gives. Everything else — scalars, kinds, funcs, constraints,
|
|
61
|
-
// and a reference with nothing to expand — delegates to its own canon,
|
|
62
|
-
// whose text is already in cross-port parity. The non-Val arm mirrors
|
|
63
|
-
// MapVal.canon's raw-peg fallback and is unreachable through an
|
|
64
|
-
// evaluated tree (direct-tested, ADR-002).
|
|
65
17
|
function render(v: any, inh: HMarks): string {
|
|
66
18
|
if (true !== v?.isVal) {
|
|
67
19
|
return String(v)
|
|
@@ -76,12 +28,6 @@ function render(v: any, inh: HMarks): string {
|
|
|
76
28
|
|
|
77
29
|
let s: string
|
|
78
30
|
if (true === v.isMap) {
|
|
79
|
-
// Alias declarations are dropped here for the same reason
|
|
80
|
-
// MapVal.canon drops them, and this is the surface where it counts:
|
|
81
|
-
// `aon1-` pins MEANING, so a document written with aliases and the
|
|
82
|
-
// same document written longhand must hash to one string. Two
|
|
83
|
-
// renderers, one rule -- hcanon is not canon and does not inherit
|
|
84
|
-
// the filter (docs/design/ALIASES.0.md §4).
|
|
85
31
|
const keys = Object.keys(v.peg)
|
|
86
32
|
.filter((k) => !v.aliasKeys.includes(k))
|
|
87
33
|
.sort(cmpCodePoint)
|
|
@@ -115,22 +61,6 @@ function render(v: any, inh: HMarks): string {
|
|
|
115
61
|
else if (true === v.isConjunct || true === v.isDisjunct) {
|
|
116
62
|
s = junctionText(v, true === v.isConjunct ? '&' : '|', inner)
|
|
117
63
|
}
|
|
118
|
-
// AN EXPANDED ALIAS REFERENCE IS RENDERED, NOT DELEGATED (BUGS.md
|
|
119
|
-
// §60). A reference standing after unification is one inside a
|
|
120
|
-
// spread template, and `RefVal.canon` answers with the EXPANSION's
|
|
121
|
-
// plain canon -- which drops exactly what this renderer exists to
|
|
122
|
-
// keep. The declaration carrying `close()` or a mark is erased by
|
|
123
|
-
// the alias filter above, so a `close()` lost here is lost from the
|
|
124
|
-
// hash entirely: `%A = close({n:string})` and `%A = {n:string}`,
|
|
125
|
-
// used as `box: [&: %A]`, hashed to ONE STRING while refusing and
|
|
126
|
-
// admitting `{n:"x",z:1}` respectively -- a change of meaning the
|
|
127
|
-
// pin reported as no change, in the unsafe direction. Recursing
|
|
128
|
-
// through `inner` is what makes the alias form and its longhand
|
|
129
|
-
// twin agree again, which is ALIASES.0.md §4's own requirement.
|
|
130
|
-
//
|
|
131
|
-
// A reference with NO expansion still spells its name: a plain
|
|
132
|
-
// `$.A` names a key the hash form still carries in full, and the
|
|
133
|
-
// knot of a recursive alias inside its own template never gets one.
|
|
134
64
|
else if (true === v.isRef && undefined !== v.expansion) {
|
|
135
65
|
s = render(v.expansion, inner)
|
|
136
66
|
}
|
|
@@ -160,14 +90,6 @@ function render(v: any, inh: HMarks): string {
|
|
|
160
90
|
}
|
|
161
91
|
|
|
162
92
|
|
|
163
|
-
// The JunctionVal.canon parenthesisation rule, kept: a member that is
|
|
164
|
-
// itself a junction with more than one term keeps its parens so the
|
|
165
|
-
// text reparses with the same structure (`(1|2)&3`, not the
|
|
166
|
-
// differently-parsing `1|2&3`). Post-unification junctions are
|
|
167
|
-
// flattened by norm, so no SOURCE reaches the wrapping arm -- it is
|
|
168
|
-
// pinned by direct tests over constructed Vals in both ports, because
|
|
169
|
-
// a hash form that could render ambiguously would be a pin that
|
|
170
|
-
// silently agrees with a document it should not.
|
|
171
93
|
function junctionText(v: any, sym: string, inner: HMarks): string {
|
|
172
94
|
return v.peg.map((m: any) =>
|
|
173
95
|
true === m?.isJunction && 1 < m.peg.length
|
|
@@ -185,10 +107,6 @@ export function hcanon(v: Val): string {
|
|
|
185
107
|
}
|
|
186
108
|
|
|
187
109
|
|
|
188
|
-
// The canon-hash pin. Scoped to the module evaluated STANDALONE: its
|
|
189
|
-
// own include closure resolved and unified at its own root, before any
|
|
190
|
-
// consumer context — which is what makes the pin transitive (an edit
|
|
191
|
-
// two includes deep changes the unified root, hence the hash).
|
|
192
110
|
export function canonHash(v: Val): string {
|
|
193
111
|
return 'aon1-' +
|
|
194
112
|
createHash('sha256').update(hcanon(v), 'utf8').digest('base64url')
|
package/src/helpdoc.ts
CHANGED
|
@@ -41,7 +41,7 @@ const HELPDOC: HelpTopic[] = [
|
|
|
41
41
|
"topic": "grammar",
|
|
42
42
|
"summary": "the published ABNF, for a parser or a constrained decoder",
|
|
43
43
|
"source": "grammar/aontu.abnf",
|
|
44
|
-
"text": "; Aontu --- published grammar (ABNF, RFC 5234 + RFC 7405).\n;\n; The same language as grammar/aontu.gbnf, rule for rule and name for\n; name, in the notation an RFC reader expects. The GBNF form is for a\n; constrained decoder; THIS form is for a person, and for the railroad\n; diagram in the language reference, which is generated from this file\n; (ts/scripts/figures.cjs).\n;\n; It covers the DOCUMENTED EMISSION SURFACE: what a model should be\n; allowed to write, which is a superset of JSON plus the operators,\n; constraints and marks the language's own canonical form emits. It is\n; CONSERVATIVE BY CONSTRUCTION --- it may accept less than the parser\n; does, never more. The same two deliberate exclusions the GBNF has:\n;\n; - `@\"...\"` includes. A generated document should describe values,\n; not reach for files.\n; - Unquoted keys and the other spellings the parser tolerates.\n; Canon quotes every key, and one spelling is what a grammar is\n; for.\n;\n; TWO NOTATION CHOICES worth stating, because both are load-bearing.\n;\n; EVERY LITERAL IS CASE-SENSITIVE, spelled `%s\"...\"` (RFC 7405). A\n; plain `\"...\"` is case-INSENSITIVE in RFC 5234, and Aontu is not:\n; `TRUE` is a bare word and `true` is a boolean. The reader in\n; ts/scripts/abnf.cjs refuses a bare quoted string rather than guess\n; which was meant.\n;\n; ALTERNATION IS ORDERED. RFC 5234's `/` is formally unordered, and\n; the consumers of this file (a PEG-style matcher here, a railroad\n; renderer) take the first branch that matches. Where one spelling is\n; a prefix of another the longer comes first --- `exact` before\n; `number`, `refer` before `rem` before `re`, `biginteger` before\n; `boolean` --- so the ordered reading and the unordered one accept\n; the same language. ts/test/grammar.test.ts holds this file to the\n; whole canon corpus of test/spec/*.tsv, which is what proves it.\n\nroot = ws value ws\n\n; No pipe. `|>` was parse-time sugar; it was removed, `x |> f(a)`\n; being written `f(x, a)`.\nvalue = disjunct\n\ndisjunct = conjunct *( ws %s\"|\" ws conjunct )\n\nconjunct = prefixed *( ws %s\"&\" ws prefixed )\n\n; A preference marks the alternative a generation picks.\nprefixed = %s\"*\" ws prefixed / sum\n\nsum = atom *( ws %s\"+\" ws atom )\n\natom = map\n / list\n / func\n / ref\n / kind\n / place\n / scalar\n / %s\"(\" ws value ws %s\")\"\n\nmap = %s\"{\" ws [ entry *( ws %s\",\" ws entry ) ws ] %s\"}\"\n\nentry = spread / pair\n\n; The template every key of the bag must also satisfy.\nspread = %s\"&\" ws %s\":\" ws value\n\npair = string ws [ %s\"?\" ] ws %s\":\" ws value\n\n; A list ELEMENT is a value, not a pair --- only the template is keyed.\nlist = %s\"[\" ws [ element *( ws %s\",\" ws element ) ws ] %s\"]\"\n\nelement = spread / value\n\n; The builtins, applied. The name set is closed on purpose: an unknown\n; function is a parse-time error in the engine, so a grammar that\n; allowed any name would over-approximate.\nfunc = name %s\"(\" ws [ value *( ws %s\",\" ws value ) ws ] %s\")\"\n\n; ORDER MATTERS where one name is a prefix of another: `refer` is\n; listed before `re`, and `rem` before `re` as well.\nname = %s\"above\" / %s\"acyclic\" / %s\"add\" / %s\"below\" / %s\"close\"\n / %s\"copy\" / %s\"deprecate\" / %s\"div\"\n / %s\"each\" / %s\"emit\" / %s\"esc\" / %s\"filter\" / %s\"greatest\"\n / %s\"hide\"\n / %s\"inverse\" / %s\"join\" / %s\"key\" / %s\"least\"\n / %s\"length\" / %s\"list\" / %s\"lower\" / %s\"map\" / %s\"match\"\n / %s\"max\" / %s\"min\" / %s\"mod\" / %s\"move\"\n / %s\"mul\" / %s\"must\"\n / %s\"neq\"\n / %s\"open\" / %s\"pack\" / %s\"path\" / %s\"pick\" / %s\"pref\"\n / %s\"refer\" / %s\"rel\" / %s\"rem\" / %s\"rep\" / %s\"re\" / %s\"split\"\n / %s\"super\"\n / %s\"sub\" / %s\"sum\"\n / %s\"type\"\n / %s\"unique\" / %s\"upper\" / %s\"usc\"\n\n; A path reference, absolute from the document root. At least one\n; segment: a bare `$` is an incomplete expression, not a reference.\n; A RELATIVE reference has no `$`: `.n` names a sibling, resolved\n; against the enclosing map rather than the document root. Canon emits\n; one wherever a spread template survives unresolved, so a grammar\n; without it cannot parse this engine's own output. No conflict with\n; `number`: a numeric literal always starts with a digit or `-`.\nref = %s\"$\" 1*( %s\".\" segment ) / 1*( %s\".\" segment )\n\n; No `-`: it is not a bare-text character (test/spec/op-chars.tsv pins\n; `a:6-2` as a parse error), so admitting it would over-approximate.\nsegment = 1*( ALPHA / DIGIT / %s\"_\" )\n\n; The placeholder: a hole a call is filled through. BARE only --- `\"_\"`\n; is an ordinary string, and a longer bare word containing it is\n; ordinary text.\nplace = %s\"_\"\n\n; `biginteger` before `bigdecimal` is not required (they differ at the\n; fourth character), but `biginteger` before `boolean` is: see the\n; ordered-alternation note above.\nkind = %s\"biginteger\" / %s\"bigdecimal\" / %s\"boolean\" / %s\"float\"\n / %s\"integer\" / %s\"number\" / %s\"string\" / %s\"top\" / %s\"nil\"\n\n; `exact` before `number`, or `0d5` would match `number` as the single\n; digit `0` and leave `d5` unconsumed.\nscalar = string / exact / number / %s\"true\" / %s\"false\" / %s\"null\"\n\nstring = DQUOTE *char DQUOTE\n\nchar = unescaped / %x5C escape\n\n; Every code point but the quote and the backslash, which is what the\n; GBNF's `[^\"\\\\]` says. Control characters included: canon writes them\n; escaped, and a grammar that refused them would refuse less than the\n; parser accepts in the one direction this file may not.\nunescaped = %x00-21 / %x23-5B / %x5D-10FFFF\n\nescape = DQUOTE / %x5C / %s\"/\" / %s\"b\" / %s\"f\" / %s\"n\" / %s\"r\"\n / %s\"t\" / %s\"u\" hex hex hex hex\n\nhex = DIGIT / %x41-46 / %x61-66\n\n; The exact leaves: arbitrary precision, spelled with the 0d marker.\nexact = [ %s\"-\" ] %s\"0d\" digits [ %s\".\" digits ] [ exponent ]\n\nnumber = [ %s\"-\" ] digits [ %s\".\" digits ] [ exponent ]\n\nexponent = ( %s\"e\" / %s\"E\" ) [ %s\"-\" / %s\"+\" ] digits\n\ndigits = 1*DIGIT\n\nws = *( %x20 / %x09 / %x0A / %x0D )\n\n; RFC 5234's core rules, written out so this file stands alone.\nALPHA = %x41-5A / %x61-7A\nDIGIT = %x30-39\nDQUOTE = %x22\n"
|
|
44
|
+
"text": "; Aontu --- published grammar (ABNF, RFC 5234 + RFC 7405).\n;\n; The same language as grammar/aontu.gbnf, rule for rule and name for\n; name, in the notation an RFC reader expects. The GBNF form is for a\n; constrained decoder; THIS form is for a person, and for the railroad\n; diagram in the language reference, which is generated from this file\n; (ts/scripts/figures.cjs).\n;\n; It covers the DOCUMENTED EMISSION SURFACE: what a model should be\n; allowed to write, which is a superset of JSON plus the operators,\n; constraints and marks the language's own canonical form emits. It is\n; CONSERVATIVE BY CONSTRUCTION --- it may accept less than the parser\n; does, never more. The same two deliberate exclusions the GBNF has:\n;\n; - `@\"...\"` includes. A generated document should describe values,\n; not reach for files.\n; - Unquoted keys and the other spellings the parser tolerates.\n; Canon quotes every key, and one spelling is what a grammar is\n; for.\n;\n; TWO NOTATION CHOICES worth stating, because both are load-bearing.\n;\n; EVERY LITERAL IS CASE-SENSITIVE, spelled `%s\"...\"` (RFC 7405). A\n; plain `\"...\"` is case-INSENSITIVE in RFC 5234, and Aontu is not:\n; `TRUE` is a bare word and `true` is a boolean. The reader in\n; ts/scripts/abnf.cjs refuses a bare quoted string rather than guess\n; which was meant.\n;\n; ALTERNATION IS ORDERED. RFC 5234's `/` is formally unordered, and\n; the consumers of this file (a PEG-style matcher here, a railroad\n; renderer) take the first branch that matches. Where one spelling is\n; a prefix of another the longer comes first --- `exact` before\n; `number`, `refer` before `rem` before `re`, `biginteger` before\n; `boolean` --- so the ordered reading and the unordered one accept\n; the same language. ts/test/grammar.test.ts holds this file to the\n; whole canon corpus of test/spec/*.tsv, which is what proves it.\n\nroot = ws value ws\n\n; No pipe. `|>` was parse-time sugar; it was removed, `x |> f(a)`\n; being written `f(x, a)`.\nvalue = disjunct\n\ndisjunct = conjunct *( ws %s\"|\" ws conjunct )\n\nconjunct = prefixed *( ws %s\"&\" ws prefixed )\n\n; A preference marks the alternative a generation picks.\nprefixed = %s\"*\" ws prefixed / sum\n\nsum = atom *( ws %s\"+\" ws atom )\n\natom = map\n / list\n / func\n / ref\n / kind\n / place\n / scalar\n / %s\"(\" ws value ws %s\")\"\n\nmap = %s\"{\" ws [ entry *( ws %s\",\" ws entry ) ws ] %s\"}\"\n\nentry = spread / pair\n\n; The template every key of the bag must also satisfy.\nspread = %s\"&\" ws %s\":\" ws value\n\npair = string ws [ %s\"?\" ] ws %s\":\" ws value\n\n; A list ELEMENT is a value, not a pair --- only the template is keyed.\nlist = %s\"[\" ws [ element *( ws %s\",\" ws element ) ws ] %s\"]\"\n\nelement = spread / value\n\n; The builtins, applied. The name set is closed on purpose: an unknown\n; function is a parse-time error in the engine, so a grammar that\n; allowed any name would over-approximate.\nfunc = name %s\"(\" ws [ value *( ws %s\",\" ws value ) ws ] %s\")\"\n\n; ORDER MATTERS where one name is a prefix of another: `refer` is\n; listed before `re`, and `rem` before `re` as well.\nname = %s\"abnf\" / %s\"above\" / %s\"acyclic\" / %s\"add\" / %s\"below\" / %s\"close\"\n / %s\"copyfiles\" / %s\"copy\" / %s\"deprecate\" / %s\"div\"\n / %s\"each\" / %s\"emit\" / %s\"esc\" / %s\"filter\" / %s\"greatest\"\n / %s\"hide\"\n / %s\"inverse\" / %s\"join\" / %s\"key\" / %s\"least\"\n / %s\"length\" / %s\"listitems\" / %s\"list\" / %s\"lower\" / %s\"map\" / %s\"match\"\n / %s\"maybe\" / %s\"max\" / %s\"min\" / %s\"mod\" / %s\"move\"\n / %s\"mul\" / %s\"must\"\n / %s\"neq\"\n / %s\"open\" / %s\"pack\" / %s\"parse\" / %s\"path\" / %s\"pick\" / %s\"pref\"\n / %s\"refer\" / %s\"rel\" / %s\"rem\" / %s\"rep\" / %s\"re\" / %s\"sort\" / %s\"split\"\n / %s\"super\"\n / %s\"content\" / %s\"file\" / %s\"folder\" / %s\"fragment\" / %s\"inject\"\n / %s\"line\" / %s\"nom\" / %s\"project\" / %s\"slot\" / %s\"translate\"\n / %s\"sub\" / %s\"sum\"\n / %s\"type\"\n / %s\"unique\" / %s\"upper\" / %s\"usc\"\n\n; A path reference, absolute from the document root. At least one\n; segment: a bare `$` is an incomplete expression, not a reference.\n; A RELATIVE reference has no `$`: `.n` names a sibling, resolved\n; against the enclosing map rather than the document root. Canon emits\n; one wherever a spread template survives unresolved, so a grammar\n; without it cannot parse this engine's own output. No conflict with\n; `number`: a numeric literal always starts with a digit or `-`.\nref = %s\"$\" 1*( %s\".\" segment ) / 1*( %s\".\" segment )\n\n; No `-`: it is not a bare-text character (test/spec/op-chars.tsv pins\n; `a:6-2` as a parse error), so admitting it would over-approximate.\nsegment = 1*( ALPHA / DIGIT / %s\"_\" )\n\n; The placeholder: a hole a call is filled through. BARE only --- `\"_\"`\n; is an ordinary string, and a longer bare word containing it is\n; ordinary text.\nplace = %s\"_\"\n\n; `biginteger` before `bigdecimal` is not required (they differ at the\n; fourth character), but `biginteger` before `boolean` is: see the\n; ordered-alternation note above.\nkind = %s\"biginteger\" / %s\"bigdecimal\" / %s\"boolean\" / %s\"float\"\n / %s\"integer\" / %s\"number\" / %s\"string\" / %s\"top\" / %s\"nil\"\n\n; `exact` before `number`, or `0d5` would match `number` as the single\n; digit `0` and leave `d5` unconsumed.\nscalar = string / exact / number / %s\"true\" / %s\"false\" / %s\"null\"\n\nstring = DQUOTE *char DQUOTE\n\nchar = unescaped / %x5C escape\n\n; Every code point but the quote and the backslash, which is what the\n; GBNF's `[^\"\\\\]` says. Control characters included: canon writes them\n; escaped, and a grammar that refused them would refuse less than the\n; parser accepts in the one direction this file may not.\nunescaped = %x00-21 / %x23-5B / %x5D-10FFFF\n\nescape = DQUOTE / %x5C / %s\"/\" / %s\"b\" / %s\"f\" / %s\"n\" / %s\"r\"\n / %s\"t\" / %s\"u\" hex hex hex hex\n\nhex = DIGIT / %x41-46 / %x61-66\n\n; The exact leaves: arbitrary precision, spelled with the 0d marker.\nexact = [ %s\"-\" ] %s\"0d\" digits [ %s\".\" digits ] [ exponent ]\n\nnumber = [ %s\"-\" ] digits [ %s\".\" digits ] [ exponent ]\n\nexponent = ( %s\"e\" / %s\"E\" ) [ %s\"-\" / %s\"+\" ] digits\n\ndigits = 1*DIGIT\n\nws = *( %x20 / %x09 / %x0A / %x0D )\n\n; RFC 5234's core rules, written out so this file stands alone.\nALPHA = %x41-5A / %x61-7A\nDIGIT = %x30-39\nDQUOTE = %x22\n"
|
|
45
45
|
}
|
|
46
46
|
]
|
|
47
47
|
|
package/src/hints.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Error code hints for Aontu unification errors.
|
|
5
|
-
*
|
|
6
|
-
* Each key is an error code that can be passed to makeNilErr.
|
|
7
|
-
* Each value is a human-readable explanation of what the error means.
|
|
8
|
-
*/
|
|
9
3
|
|
|
10
4
|
const hints: Record<string, string> = {
|
|
11
5
|
|
|
@@ -40,7 +34,6 @@ const hints: Record<string, string> = {
|
|
|
40
34
|
'when nothing else does.',
|
|
41
35
|
|
|
42
36
|
|
|
43
|
-
// TODO: extend errors to have details so we can name the key
|
|
44
37
|
mapval_required: 'This map value is required.',
|
|
45
38
|
|
|
46
39
|
mapval_no_gen:
|
|
@@ -108,6 +101,31 @@ const hints: Record<string, string> = {
|
|
|
108
101
|
' # with "tier";\n' +
|
|
109
102
|
' min(0) & must(integer,"whole") & 3 -> 3 # Bands compose.',
|
|
110
103
|
|
|
104
|
+
abnf_grammar:
|
|
105
|
+
'This ABNF grammar could not be compiled:\n' +
|
|
106
|
+
'{reason}\n' +
|
|
107
|
+
' \n' +
|
|
108
|
+
'abnf() takes RFC 5234 ABNF -- `=` and `/`, not `::=`. The\n' +
|
|
109
|
+
'compiler reports the first thing it could not read; a rule\n' +
|
|
110
|
+
'referenced but never defined is the usual cause, after a\n' +
|
|
111
|
+
'quantifier written the EBNF way.',
|
|
112
|
+
|
|
113
|
+
parse_arg:
|
|
114
|
+
'parse(grammar, text) takes two strings: a grammar, normally the\n' +
|
|
115
|
+
'answer of an abnf() call, and the text to parse.\n' +
|
|
116
|
+
' \n' +
|
|
117
|
+
'Examples:\n' +
|
|
118
|
+
' G: abnf("v = 1*DIGIT")\n' +
|
|
119
|
+
' a: parse($.G, "12") # the AST\n' +
|
|
120
|
+
' b: parse($.G, 12) # parse_arg: the text is not a string',
|
|
121
|
+
|
|
122
|
+
parse_failed:
|
|
123
|
+
'The text does not parse under this grammar:\n' +
|
|
124
|
+
'{reason}\n' +
|
|
125
|
+
' \n' +
|
|
126
|
+
'A failure to parse is a failure to unify, so the field is\n' +
|
|
127
|
+
'refused rather than set to a value meaning "no".',
|
|
128
|
+
|
|
111
129
|
constraint_pattern:
|
|
112
130
|
'This re() pattern is outside the supported subset. It uses\n' +
|
|
113
131
|
'{reason}.\n' +
|
|
@@ -176,8 +194,6 @@ const hints: Record<string, string> = {
|
|
|
176
194
|
bare_punct: 'A bare string holds letters, digits, `-` and `_`, and nothing else.\nThis one holds `{char}`, in `{text}`. Every other punctuation\ncharacter is either syntax or an error, never silently part of a\nstring: a value that needs one is written quoted, and a `>` or `<`\nthat was meant as a bound is written as min(x), max(x), above(x) or\nbelow(x).\n \nExamples:\n a: team-payments -> "team-payments" # `-` and `_` are text;\n a: 2026-09-05 -> "2026-09-05" # ... digits included;\n a: x=y -> nil # `=` is not;\n a: "x=y" -> "x=y" # ... so quote it;\n a: >10 -> nil # Not an operator: write above(10).',
|
|
177
195
|
|
|
178
196
|
|
|
179
|
-
|
|
180
|
-
|
|
181
197
|
recursion_unexpanded: 'A schema refers to itself here, and no data reached this position\nto expand it against. Guard the recursion -- an optional key\n(next?:) drops when nothing arrives, and a preferred alternative\n(*null | $.Node) generates -- or supply the data.\n \nExamples:\n Node: {v: integer, next?: $.Node}\n t: $.Node & {v: 1} -> {..} # next? drops;\n Node: {v: integer, next: $.Node}\n t: $.Node & {v: 1} -> nil # ... required refuses.',
|
|
182
198
|
recursion_budget: 'A recursive schema expanded past the evaluation depth budget\nwithout meeting concrete data. Expansion is driven by the data --\nfinite data always terminates -- so a chain this deep means two\ndefinitions feeding each other, or data deeper than the budget\n(docs/trust.md raises it deliberately).',
|
|
183
199
|
list_length: 'A literal list alternative in a disjunction admits only a list of\nits own length -- a spread (&:) makes it variadic. Outside a\ndisjunction two statements of one list still merge elementwise.\n \nExamples:\n x: [] | [&: integer]\n x: [1, 2] -> [1,2] # The variadic arm;\n x: [] -> [] # ... or exactly empty;\n y: [a] | [b]\n y: [a, extra] -> nil # ... a literal arm is its length.',
|
|
@@ -204,15 +220,6 @@ const hints: Record<string, string> = {
|
|
|
204
220
|
|
|
205
221
|
format_check: 'The formatted text is not the same document, so nothing was written.\nThis is a formatter defect: please report it, with the source.',
|
|
206
222
|
|
|
207
|
-
// THIS PORT NEVER RAISES decimal_syntax -- Go's construct.go does,
|
|
208
|
-
// and go/hints.go's header records that the CODE is Go-only. The
|
|
209
|
-
// TEXT is here anyway, verbatim, because since G11 phase 3 this
|
|
210
|
-
// table is a LOOKUP surface as well as a message source: the code is
|
|
211
|
-
// in the shared registry (test/spec/errcodes.tsv), so
|
|
212
|
-
// `aontu explain decimal_syntax` must answer the same in both ports
|
|
213
|
-
// or the agent that met the error under one binary learns nothing
|
|
214
|
-
// from the other. An entry for a code this port cannot raise is
|
|
215
|
-
// never read on an error path, only on that lookup.
|
|
216
223
|
decimal_syntax: 'This 0d literal is not a valid exact number.',
|
|
217
224
|
view_style_profile: 'Each profile has ONE way to carry the meaning of a figure\'s marks:\nSGR escapes for text, CSS classes for svg. Asking for the other one is\na usage error rather than a silent no-op. `none` works everywhere.',
|
|
218
225
|
view_style_unknown: 'The styles are none, ansi and css, plus `auto` at the command line,\nwhich the command resolves before the library runs: whether the\ndestination is a terminal is not something a library can see.',
|
|
@@ -345,6 +352,41 @@ const hints: Record<string, string> = {
|
|
|
345
352
|
' pick([{a:1},{b:2}], a) -> nil # ... the second does not;\n' +
|
|
346
353
|
' pick([[9],[8]], 0) -> [9,8] # A list child takes an index.',
|
|
347
354
|
|
|
355
|
+
sort_key:
|
|
356
|
+
'A child of this bag has no key `{key}` to order by. Ordering\n' +
|
|
357
|
+
'refuses rather than skipping, for the reason `pick` does: a\n' +
|
|
358
|
+
'shorter list orders a DIFFERENT set of records than the one the\n' +
|
|
359
|
+
'author named. Give every child the key, or filter the bag first.\n' +
|
|
360
|
+
' \n' +
|
|
361
|
+
'Examples:\n' +
|
|
362
|
+
' sort([{a:2},{a:1}], a) -> [{a:1},{a:2}] # Every child has it;\n' +
|
|
363
|
+
' sort([{a:1},{b:2}], a) -> nil # ... the second does not;\n' +
|
|
364
|
+
' sort([[9],[8]], 0) -> [[8],[9]] # A list child takes an index.',
|
|
365
|
+
|
|
366
|
+
sort_domain:
|
|
367
|
+
'This bag cannot be ordered: `{member}`. There are two orders and no\n' +
|
|
368
|
+
'third -- text by code point, numbers by the exact comparator -- so a\n' +
|
|
369
|
+
'bag that mixes them, or holds a boolean, a null or a container, has\n' +
|
|
370
|
+
'no order to be put in. Project a field that is all one kind, or\n' +
|
|
371
|
+
'filter the bag first.\n' +
|
|
372
|
+
' \n' +
|
|
373
|
+
'Examples:\n' +
|
|
374
|
+
' sort([3,1,2]) -> [1,2,3] # All numbers;\n' +
|
|
375
|
+
' sort([b,a]) -> ["a","b"] # ... or all text;\n' +
|
|
376
|
+
' sort([1,a]) -> nil # ... never both.',
|
|
377
|
+
|
|
378
|
+
sort_dir:
|
|
379
|
+
'A sort direction names no direction: `{dir}`. The third argument is\n' +
|
|
380
|
+
'`asc` or `desc`, and omitting it is `asc`. The second argument is\n' +
|
|
381
|
+
'the field to order by, so a keyless descending sort writes the\n' +
|
|
382
|
+
'empty projector: the member itself.\n' +
|
|
383
|
+
' \n' +
|
|
384
|
+
'Examples:\n' +
|
|
385
|
+
' sort($.rows, n) # Ascending by field `n`;\n' +
|
|
386
|
+
' sort($.rows, n, desc) # ... descending;\n' +
|
|
387
|
+
' sort($.tags) # The members themselves, ascending;\n' +
|
|
388
|
+
' sort($.tags, "", desc) # ... descending.',
|
|
389
|
+
|
|
348
390
|
join_member:
|
|
349
391
|
'A member of this bag is not text and never will be: `{member}`.\n' +
|
|
350
392
|
'`join` folds with `+` seeded with the empty string, and `+` with a\n' +
|
|
@@ -479,8 +521,6 @@ const hints: Record<string, string> = {
|
|
|
479
521
|
'empty': 'Empty disjunction. The disjunction has no valid alternatives.',
|
|
480
522
|
'empty-dist': 'Empty disjunction distribution. All alternatives in the disjunction are invalid.',
|
|
481
523
|
|
|
482
|
-
// ADR-011 R2: two DEFAULTS of equal rank that cannot agree. The
|
|
483
|
-
// fix is a rank, so the hint names it.
|
|
484
524
|
'pref_rank_clash': 'Two defaults of the same rank disagree.' +
|
|
485
525
|
' Rank one of them (`**x`) to say which is the weaker layer,' +
|
|
486
526
|
' or give them the same value.',
|
|
@@ -508,15 +548,6 @@ const hints: Record<string, string> = {
|
|
|
508
548
|
}
|
|
509
549
|
|
|
510
550
|
|
|
511
|
-
// codeClasses assigns every error code a CLASS: conflict | incomplete |
|
|
512
|
-
// reference | parse | budget | internal. The contract lives in
|
|
513
|
-
// test/spec/errcodes.tsv (mode `errcode`): the spec suite executes one
|
|
514
|
-
// row per code against this table and asserts SET EQUALITY between the
|
|
515
|
-
// file and these keys, in both implementations (go/hints.go mirrors
|
|
516
|
-
// this map exactly). Codes are append-only and never renamed; a class
|
|
517
|
-
// change is a breaking change. Class rulings (why decimal_budget and
|
|
518
|
-
// lossy_integer_literal are conflict, not budget; why unknown_function
|
|
519
|
-
// is reference) are documented in the tsv header.
|
|
520
551
|
const codeClasses: Record<string, string> = {
|
|
521
552
|
// parse -- the source text is malformed or unusable
|
|
522
553
|
parse: 'parse',
|
|
@@ -551,10 +582,6 @@ const codeClasses: Record<string, string> = {
|
|
|
551
582
|
patch_ambiguous: 'reference',
|
|
552
583
|
patch_span_mismatch: 'internal',
|
|
553
584
|
|
|
554
|
-
// G4 phase 2 -- the checked link: a string that is not a tree
|
|
555
|
-
// address (class `parse`, the text is wrong), and an address that
|
|
556
|
-
// names nothing in this evaluation (class `reference`, the same
|
|
557
|
-
// class as `no_path`, because it is the same kind of miss).
|
|
558
585
|
refer_address: 'parse',
|
|
559
586
|
rel_address: 'parse',
|
|
560
587
|
refer_unresolved: 'reference',
|
|
@@ -595,10 +622,6 @@ const codeClasses: Record<string, string> = {
|
|
|
595
622
|
// class as refer_address, because it is the same mistake.
|
|
596
623
|
path_address: 'parse',
|
|
597
624
|
|
|
598
|
-
// G8 phase 1 -- the generation combinators. All three are class
|
|
599
|
-
// `parse`: what is wrong is the CALL as written (data that is not a
|
|
600
|
-
// bag, a list element that is not a name), not any pair of values a
|
|
601
|
-
// meet brought together.
|
|
602
625
|
pack_data: 'parse',
|
|
603
626
|
pack_key: 'parse',
|
|
604
627
|
each_data: 'parse',
|
|
@@ -611,24 +634,12 @@ const codeClasses: Record<string, string> = {
|
|
|
611
634
|
filter_data: 'parse',
|
|
612
635
|
match_none: 'conflict',
|
|
613
636
|
|
|
614
|
-
// G9 phase 6 -- the string builtins. All five are class `parse`:
|
|
615
|
-
// what is wrong is the CALL as written -- a variant that names no
|
|
616
|
-
// convention, a pattern outside the subset, a substitution naming a
|
|
617
|
-
// group that does not exist, a separator that is neither string nor
|
|
618
|
-
// pattern. `usc_malformed` is the odd one and still `parse`: the
|
|
619
|
-
// TEXT the call was given has no inverse, which is a fact about the
|
|
620
|
-
// argument rather than about any meet.
|
|
621
637
|
esc_variant: 'parse',
|
|
622
638
|
usc_malformed: 'parse',
|
|
623
639
|
rep_pattern: 'parse',
|
|
624
640
|
rep_sub: 'parse',
|
|
625
641
|
split_sep: 'parse',
|
|
626
642
|
|
|
627
|
-
// G9 phase 6 -- apply-templates. The four shape codes are class
|
|
628
|
-
// `parse`: what is wrong is the CALL as written -- a selection with
|
|
629
|
-
// no children, a table that is not one, a rule missing a half.
|
|
630
|
-
// `emit_none` is class `conflict` for `match_none`'s reason: the
|
|
631
|
-
// node and every pattern written for it disagreed.
|
|
632
643
|
emit_data: 'parse',
|
|
633
644
|
emit_table: 'parse',
|
|
634
645
|
emit_template: 'parse',
|
|
@@ -636,19 +647,11 @@ const codeClasses: Record<string, string> = {
|
|
|
636
647
|
emit_none: 'conflict',
|
|
637
648
|
emit_ref: 'conflict',
|
|
638
649
|
|
|
639
|
-
// RENDER P6 -- `replace` on a template, and `form`. The two
|
|
640
|
-
// template checks are class `parse`: what is wrong is the TEMPLATE
|
|
641
|
-
// as written, before any node. `replace_value` is class `conflict`:
|
|
642
|
-
// the node's value and the body that wanted text disagreed.
|
|
643
|
-
// `form_data` is `each_data`'s retired twin (ADR-027).
|
|
644
650
|
replace_overlap: 'parse',
|
|
645
651
|
replace_unused: 'parse',
|
|
646
652
|
replace_value: 'conflict',
|
|
647
653
|
form_data: 'parse',
|
|
648
654
|
|
|
649
|
-
// G8 phase 3 -- the placeholder. Class `conflict`: two values met
|
|
650
|
-
// and neither could answer for the other, which is what every
|
|
651
|
-
// conflict is.
|
|
652
655
|
place_pair: 'conflict',
|
|
653
656
|
|
|
654
657
|
// G6 phase 2 -- modules. Both are class `parse`: a module import is
|
|
@@ -689,6 +692,9 @@ const codeClasses: Record<string, string> = {
|
|
|
689
692
|
constraint: 'conflict',
|
|
690
693
|
must: 'conflict',
|
|
691
694
|
constraint_pattern: 'conflict',
|
|
695
|
+
abnf_grammar: 'parse',
|
|
696
|
+
parse_arg: 'parse',
|
|
697
|
+
parse_failed: 'conflict',
|
|
692
698
|
scalar_value: 'conflict',
|
|
693
699
|
scalar_kind: 'conflict',
|
|
694
700
|
no_scalar_unify: 'conflict',
|
|
@@ -706,6 +712,9 @@ const codeClasses: Record<string, string> = {
|
|
|
706
712
|
exact_float_mix: 'conflict',
|
|
707
713
|
inexact_integer_sum: 'conflict',
|
|
708
714
|
pick_key: 'conflict',
|
|
715
|
+
sort_key: 'conflict',
|
|
716
|
+
sort_domain: 'conflict',
|
|
717
|
+
sort_dir: 'parse',
|
|
709
718
|
aggregate_data: 'conflict',
|
|
710
719
|
aggregate_empty: 'conflict',
|
|
711
720
|
join_member: 'conflict',
|