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/subsume.ts
CHANGED
|
@@ -1,27 +1,6 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
2
|
import { includeOpts } from './utility'
|
|
3
3
|
|
|
4
|
-
// Subsumption as a first-class query (G3 phases 1-2,
|
|
5
|
-
// docs/capability-review/g3-subsumption-evolution.md): does the GENERAL
|
|
6
|
-
// value admit every instance the SPECIFIC value admits?
|
|
7
|
-
//
|
|
8
|
-
// The recursion is a dedicated structural walk over EVALUATED values —
|
|
9
|
-
// design option B. It never mutates its inputs (it runs after
|
|
10
|
-
// evaluation, on finished trees), carries no fixpoint, and returns a
|
|
11
|
-
// THREE-VALUED verdict: `subsumes`, `does_not_subsume` (with the
|
|
12
|
-
// failing path and both sides' canons as the witness), or `undecided`
|
|
13
|
-
// (with a reason code, never silently). Where a rule cannot decide the
|
|
14
|
-
// answer folds toward "not subsumed" or "undecided" — the safe
|
|
15
|
-
// directions: a compatibility gate that wrongly reports "breaking"
|
|
16
|
-
// costs a second look, one that wrongly reports "compatible" ships the
|
|
17
|
-
// break (docs/reference-language.md, "Subsumption").
|
|
18
|
-
//
|
|
19
|
-
// Findings reuse G2's report vocabulary (the vet finding object), with
|
|
20
|
-
// the G3 codes appended to the shared registry: `compat_narrowed`,
|
|
21
|
-
// `compat_required_added`, `compat_default_changed`,
|
|
22
|
-
// `compat_marks_changed`, and the `sub_*` undecided reasons — all
|
|
23
|
-
// class `compat`.
|
|
24
|
-
|
|
25
4
|
|
|
26
5
|
import type { TrustOptions } from './type'
|
|
27
6
|
import { Aontu } from './aontu'
|
|
@@ -45,7 +24,7 @@ export type SubsumeProfile = 'values' | 'defaults' | 'gen'
|
|
|
45
24
|
export type SubsumeOptions = {
|
|
46
25
|
profile?: SubsumeProfile
|
|
47
26
|
at?: string
|
|
48
|
-
generalUrl?: string
|
|
27
|
+
generalUrl?: string
|
|
49
28
|
specificUrl?: string // provenance label for specific sites
|
|
50
29
|
// Where each document CAME FROM, so a relative `@"file"` load inside
|
|
51
30
|
// it resolves from its own directory — vet's schemaPath/dataPath
|
|
@@ -73,8 +52,6 @@ const DEFAULT_GENERAL_URL = 'general'
|
|
|
73
52
|
const DEFAULT_SPECIFIC_URL = 'specific'
|
|
74
53
|
|
|
75
54
|
|
|
76
|
-
// One comparison's running state: the finding list, the two provenance
|
|
77
|
-
// labels, and the profile.
|
|
78
55
|
type SubState = {
|
|
79
56
|
profile: SubsumeProfile
|
|
80
57
|
// Set inside a distribution trial: see trialSubsume.
|
|
@@ -94,10 +71,6 @@ function pathText(path: string[]): string {
|
|
|
94
71
|
}
|
|
95
72
|
|
|
96
73
|
|
|
97
|
-
// Every recorded operand is a real evaluated Val or the sited topLike
|
|
98
|
-
// stand-in, so no null guards: a Val's site is always an object, and a
|
|
99
|
-
// value parsed without a usable frame (a disjunct, say) already carries
|
|
100
|
-
// the -1 coordinates in it.
|
|
101
74
|
function siteOf(v: any, role: string, url: string): VetSite {
|
|
102
75
|
return {
|
|
103
76
|
file: url,
|
|
@@ -133,50 +106,17 @@ function record(
|
|
|
133
106
|
}
|
|
134
107
|
|
|
135
108
|
|
|
136
|
-
// The admission view of a value under a profile: a BARE preference
|
|
137
|
-
// admits what its superior admits (the engine's own PrefVal.superpeg
|
|
138
|
-
// semantics, and the docs' "a bare preference is gated by kind"); the
|
|
139
|
-
// default itself is compared separately, by the `defaults` and `gen`
|
|
140
|
-
// profiles.
|
|
141
109
|
function admission(v: any): any {
|
|
142
110
|
return true === v?.isPref ? v.superpeg : v
|
|
143
111
|
}
|
|
144
112
|
|
|
145
113
|
|
|
146
|
-
// A PREFERRED BRANCH CONTRIBUTES EXACTLY ITS OWN VALUE (ADR-004). The
|
|
147
|
-
// admission gate made that the engine's rule -- `*'auto'|'literal'|'data'`
|
|
148
|
-
// admits those three strings and nothing else -- and the subsumption
|
|
149
|
-
// walk kept comparing a pref MEMBER by its kind superior, the
|
|
150
|
-
// pre-ADR-004 reading. So a disjunction with a default did not subsume
|
|
151
|
-
// ITSELF: every member of the specific side widened to `string`, which
|
|
152
|
-
// no general member admits, and the walk answered the distribution
|
|
153
|
-
// case. `aontu_policy: hide({compat: *backward|forward|full|none})` --
|
|
154
|
-
// the verbatim idiom from reference-api.md -- failed self-subsumption
|
|
155
|
-
// under --profile gen (use-cases/BUGS.md §29).
|
|
156
|
-
//
|
|
157
|
-
// Only for a member of a disjunction: a bare `*x` standing alone is
|
|
158
|
-
// still gated by kind, which is the rule above and the documented one.
|
|
159
114
|
function memberAdmission(v: any): any {
|
|
160
115
|
return true === v?.isPref ? prefInnerPeg(v) : v
|
|
161
116
|
}
|
|
162
117
|
|
|
163
118
|
|
|
164
|
-
// The effective default of a value, or undefined when it has none, or
|
|
165
|
-
// 'indeterminate' when equal-rank preferences disagree (which the
|
|
166
|
-
// engine itself refuses only at generation).
|
|
167
|
-
// Exported (with subsumeNode) for the default-validity lint in
|
|
168
|
-
// ts/src/vet.ts (G3 phase 5): the lint asks exactly this walk's two
|
|
169
|
-
// questions — what is the effective default, and does a member admit
|
|
170
|
-
// it.
|
|
171
119
|
export function effectiveDefault(v: any): any {
|
|
172
|
-
// EVERY pref layer is unwrapped (prefInnerPeg), not just one: a
|
|
173
|
-
// ranked default's effective value is the innermost peg — `**member`
|
|
174
|
-
// generates "member" exactly as `*member` does (the rank-uniform
|
|
175
|
-
// meet, ADR-004). The one-layer unwrap left a rank-2 default wearing
|
|
176
|
-
// a `*`-wrapper no plain alternative subsumes, which is the
|
|
177
|
-
// pref_not_instance lint's ranked false positive of
|
|
178
|
-
// use-cases/BUGS.md §4 (`**member|member|admin|owner` warned while
|
|
179
|
-
// generating a value its own branch admits).
|
|
180
120
|
if (true === v?.isPref) {
|
|
181
121
|
return prefInnerPeg(v)
|
|
182
122
|
}
|
|
@@ -225,10 +165,6 @@ function unresolved(v: any): boolean {
|
|
|
225
165
|
}
|
|
226
166
|
|
|
227
167
|
|
|
228
|
-
// Exported for the defensive-arm unit test (ADR-002,
|
|
229
|
-
// ts/test/coverage3.test.ts): the no-rule fold at the walk's tail is
|
|
230
|
-
// unreachable through subsume() today — the ladder is total for every
|
|
231
|
-
// evaluated former — and the walk is otherwise private.
|
|
232
168
|
export function subsumeNode(
|
|
233
169
|
state: SubState, path: string[], g0: any, s0: any): Tri {
|
|
234
170
|
|
|
@@ -247,32 +183,11 @@ export function subsumeNode(
|
|
|
247
183
|
return 'no'
|
|
248
184
|
}
|
|
249
185
|
|
|
250
|
-
// TOP admits everything. There is no nil rule: an error-free
|
|
251
|
-
// evaluated document carries no nil (failing disjunct members are
|
|
252
|
-
// discarded, every other nil collects an error, and subsume() answers
|
|
253
|
-
// `error` for a source that does not stand alone), so a nil handed to
|
|
254
|
-
// the walk by a future caller falls to the no-rule fold below —
|
|
255
|
-
// `undecided`, the safe direction.
|
|
256
186
|
if (true === g?.isTop) {
|
|
257
187
|
return 'yes'
|
|
258
188
|
}
|
|
259
189
|
|
|
260
190
|
if (unresolved(g) || unresolved(s)) {
|
|
261
|
-
// REFLEXIVITY IS A LAW, not a rule the ladder gets to skip. Every
|
|
262
|
-
// value admits itself, residue included: the set admitted by
|
|
263
|
-
// `integer & min(0)` is exactly the set admitted by
|
|
264
|
-
// `integer & min(0)`. Without this, a constraint inside a spread
|
|
265
|
-
// template made a contract non-SELF-subsumable -- expected and
|
|
266
|
-
// actual byte-identical, verdict `undecided` -- so `breaking` on
|
|
267
|
-
// the documented close-per-entry idiom hard-failed reflexivity and
|
|
268
|
-
// had to run --allow-undecided, which then masks the genuine
|
|
269
|
-
// undecideds it exists to surface (use-cases/BUGS.md §28).
|
|
270
|
-
//
|
|
271
|
-
// Identity is the HASH FORM, not the canon: canon drops closedness
|
|
272
|
-
// and the marks, so `close({a:1})` and `{a:1}` share a canon while
|
|
273
|
-
// admitting different sets. Computed only on this branch, where
|
|
274
|
-
// the answer would otherwise be undecided, so the hot path is
|
|
275
|
-
// untouched.
|
|
276
191
|
if (hcanon(g) === hcanon(s)) {
|
|
277
192
|
return 'yes'
|
|
278
193
|
}
|
|
@@ -281,10 +196,6 @@ export function subsumeNode(
|
|
|
281
196
|
return 'undecided'
|
|
282
197
|
}
|
|
283
198
|
|
|
284
|
-
// Disjunctions. General side first: a specific member must be
|
|
285
|
-
// subsumed by SOME general member; member-wise failure is not proof
|
|
286
|
-
// (the distribution case), so a concrete failing member becomes the
|
|
287
|
-
// witness and anything else is honestly undecided.
|
|
288
199
|
if (true === s?.isDisjunct) {
|
|
289
200
|
let out: Tri = 'yes'
|
|
290
201
|
for (const raw of s.peg as any[]) {
|
|
@@ -343,11 +254,6 @@ export function subsumeNode(
|
|
|
343
254
|
return 'no'
|
|
344
255
|
}
|
|
345
256
|
if (true === s?.isConstraint) {
|
|
346
|
-
// A kind covers a residual of its own domain: `number` admits any
|
|
347
|
-
// numeric residual (the supertype admits every leaf a bound can
|
|
348
|
-
// pin), a numeric LEAF kind admits only a residual pinned to that
|
|
349
|
-
// leaf, and `string` admits any pattern residual. A residual with
|
|
350
|
-
// no domain (sizing-only) admits containers no kind covers.
|
|
351
257
|
const dom = (s as any).domain
|
|
352
258
|
const skind = (s as any).kind
|
|
353
259
|
if ('number' === dom &&
|
|
@@ -383,7 +289,6 @@ export function subsumeNode(
|
|
|
383
289
|
return 'no'
|
|
384
290
|
}
|
|
385
291
|
|
|
386
|
-
// Constraint residuals.
|
|
387
292
|
if (true === g?.isConstraint) {
|
|
388
293
|
if (true === s?.isConstraint) {
|
|
389
294
|
const r = constraintSubsumesConstraint(g, s)
|
|
@@ -460,26 +365,6 @@ export function subsumeNode(
|
|
|
460
365
|
(v: any, k: string) => v.peg[Number(k)])
|
|
461
366
|
}
|
|
462
367
|
|
|
463
|
-
// THE LADDER IS NOT TOTAL, and the formers that fall past it are the
|
|
464
|
-
// ones the evaluator MEANS to leave standing: a recursion, a
|
|
465
|
-
// relation and its graph atom, a `refer()` target constraint. None
|
|
466
|
-
// of them describes a set of values a structural walk can compare,
|
|
467
|
-
// so `undecided` is the honest answer for two DIFFERENT ones.
|
|
468
|
-
//
|
|
469
|
-
// For two IDENTICAL ones it is not. REFLEXIVITY IS A LAW -- every
|
|
470
|
-
// value admits itself -- and identity is the HASH FORM, the same
|
|
471
|
-
// rule the unresolved branch above applies and for the same reason:
|
|
472
|
-
// it costs nothing, because it runs only where the answer would
|
|
473
|
-
// otherwise be `undecided`. Without it a document that declares a
|
|
474
|
-
// relation, shares a template by reference or alias, or recurses did
|
|
475
|
-
// not subsume ITSELF, so `breaking` on the idiom the language exists
|
|
476
|
-
// for hard-failed and had to run --allow-undecided, which masks the
|
|
477
|
-
// genuine undecideds it exists to surface (use-cases/BUGS.md 64,
|
|
478
|
-
// and 28 before it).
|
|
479
|
-
//
|
|
480
|
-
// A NIL is the exception, and the reason the law is spelled here
|
|
481
|
-
// rather than in `unresolved`: a nil is not a value, so it admits
|
|
482
|
-
// nothing, itself included.
|
|
483
368
|
if (true !== g?.isNil && true !== s?.isNil && hcanon(g) === hcanon(s)) {
|
|
484
369
|
return 'yes'
|
|
485
370
|
}
|
|
@@ -554,16 +439,6 @@ function subsumeBag(
|
|
|
554
439
|
}
|
|
555
440
|
}
|
|
556
441
|
|
|
557
|
-
// Spread templates: a path-dependent template's meaning depends on
|
|
558
|
-
// where it lands, which no structural comparison can decide -- UNLESS
|
|
559
|
-
// the two templates are the same template. REFLEXIVITY IS A LAW and
|
|
560
|
-
// identity is the HASH FORM (the same rule the unresolved branch of
|
|
561
|
-
// subsumeNode applies): two byte-identical templates admit the same
|
|
562
|
-
// set wherever they land, so a document with a reference- or
|
|
563
|
-
// alias-valued template subsumes itself, and the comparison either
|
|
564
|
-
// side of the template is decided on its own merits rather than
|
|
565
|
-
// dragged to `undecided` (use-cases/BUGS.md 64). Where they are NOT
|
|
566
|
-
// identical, nothing structural can decide them and the fold stands.
|
|
567
442
|
const gcj = g.spread?.cj
|
|
568
443
|
const scj = s.spread?.cj
|
|
569
444
|
if (null != gcj || null != scj) {
|
|
@@ -596,12 +471,6 @@ function subsumeBag(
|
|
|
596
471
|
let topVal: any
|
|
597
472
|
function topLike(): any {
|
|
598
473
|
if (null == topVal) {
|
|
599
|
-
// A full site, not a partial one: `len` and `src` are as much part
|
|
600
|
-
// of the shape as row and col, and leaving them undefined dropped
|
|
601
|
-
// both keys from the emitted report — so this stand-in was the one
|
|
602
|
-
// site in either port with no `len` at all, and the Go twin (which
|
|
603
|
-
// has no undefined) disagreed. It occupies no source, so the values
|
|
604
|
-
// are the "unknown" ones.
|
|
605
474
|
topVal = {
|
|
606
475
|
isTop: true, canon: 'top',
|
|
607
476
|
site: { row: -1, col: -1, len: -1, src: '' },
|
|
@@ -611,20 +480,6 @@ function topLike(): any {
|
|
|
611
480
|
}
|
|
612
481
|
|
|
613
482
|
|
|
614
|
-
// A trial comparison whose findings are DISCARDED: disjunct
|
|
615
|
-
// member-matching asks many "would this member do?" questions, and only
|
|
616
|
-
// the aggregated outcome is a finding.
|
|
617
|
-
// A DISTRIBUTION TRIAL IS NOT A NODE CORRESPONDENCE. It asks whether
|
|
618
|
-
// one ALTERNATIVE of one side admits one alternative of the other,
|
|
619
|
-
// which is a question about admitted sets; the two values it compares
|
|
620
|
-
// are not the same node of the two documents. The `gen` profile's mark
|
|
621
|
-
// rule is a correspondence question -- did a field that used to be
|
|
622
|
-
// generated become hidden -- and firing it here compared a whole
|
|
623
|
-
// disjunction (carrying its enclosing bag's mark) against a member
|
|
624
|
-
// extracted out of one (which does not), so `hide({c: *a|b})` stopped
|
|
625
|
-
// subsuming ITSELF under --profile gen (use-cases/BUGS.md §29). The
|
|
626
|
-
// enclosing node's marks are compared where they correspond: at that
|
|
627
|
-
// node, by the ordinary walk.
|
|
628
483
|
function trialSubsume(
|
|
629
484
|
state: SubState, path: string[], g: any, s: any): Tri {
|
|
630
485
|
const trial: SubState = { ...state, findings: [], distributing: true }
|
|
@@ -632,11 +487,6 @@ function trialSubsume(
|
|
|
632
487
|
}
|
|
633
488
|
|
|
634
489
|
|
|
635
|
-
// The defaults comparison (the `defaults` and `gen` profiles): the
|
|
636
|
-
// specific side's effective default must survive into the general side
|
|
637
|
-
// unchanged. Adding a default where none existed is compatible;
|
|
638
|
-
// changing or removing one is not (removal turns previously generable
|
|
639
|
-
// documents incomplete).
|
|
640
490
|
function subsumeDefaults(
|
|
641
491
|
state: SubState, path: string[], g: any, s: any): Tri {
|
|
642
492
|
const sd = effectiveDefault(s)
|
|
@@ -682,16 +532,6 @@ function subsumeDefaultsWalk(
|
|
|
682
532
|
}
|
|
683
533
|
|
|
684
534
|
|
|
685
|
-
/**
|
|
686
|
-
* Does `generalSrc` subsume `specificSrc` — is every instance the
|
|
687
|
-
* specific admits admitted by the general too?
|
|
688
|
-
*
|
|
689
|
-
* Both sources are evaluated fresh (single-use trees make this
|
|
690
|
-
* mandatory), and the recursion runs on the finished values. The
|
|
691
|
-
* verdict is three-valued plus `error` (a source that does not stand up
|
|
692
|
-
* on its own, mirroring vet's schema-error verdict); findings reuse
|
|
693
|
-
* G2's object with class `compat`.
|
|
694
|
-
*/
|
|
695
535
|
export function subsume(
|
|
696
536
|
generalSrc: string, specificSrc: string, opts?: SubsumeOptions,
|
|
697
537
|
): SubsumeReport {
|
package/src/template.ts
CHANGED
|
@@ -1,70 +1,6 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
// THE TEMPLATE SURFACE (docs/design/TEMPLATE.0.md; RENDER.0.md P8).
|
|
5
|
-
// A generator written in the TARGET's own syntax: a marked line is
|
|
6
|
-
// aontu source, and every other line is a line of output.
|
|
7
|
-
//
|
|
8
|
-
// //- code: units: [{ path: "hi.ts", lang: "typescript", decls: [{
|
|
9
|
-
// //- k: "frag", of: emit($.svc, { match: { n: string }, body: [
|
|
10
|
-
// export const NAME = "world"
|
|
11
|
-
// //- ]}) }] }]
|
|
12
|
-
//
|
|
13
|
-
// That is the whole desugaring, and it is LINE-ORIENTED: nothing here
|
|
14
|
-
// parses aontu, and nothing here reads the target's syntax beyond its
|
|
15
|
-
// comment token. A marker line contributes its text to the document; an
|
|
16
|
-
// unmarked line contributes one quoted string, which is a body element
|
|
17
|
-
// where the marker lines left a list open.
|
|
18
|
-
//
|
|
19
|
-
// WHY A COMMENT TOKEN PLUS A DASH (D2). The generator file must stay
|
|
20
|
-
// valid in its own language -- so an editor highlights it, a compiler
|
|
21
|
-
// parses it, and a reviewer reads it -- and the one thing every
|
|
22
|
-
// language has that the target's own tools already ignore is a
|
|
23
|
-
// comment. Adding a dash distinguishes a marker from an ordinary
|
|
24
|
-
// comment, and derives for a language this table has never seen: the
|
|
25
|
-
// caller passes the token.
|
|
26
|
-
//
|
|
27
|
-
// A MARKER IS RECOGNISED AFTER LEADING WHITESPACE, AND THE INDENTATION
|
|
28
|
-
// THE RESUGARING WRITES IS THE AONTU'S (D2, amended 2026-09-07). An
|
|
29
|
-
// output line is verbatim -- a line indented two spaces in the template
|
|
30
|
-
// is indented two spaces in the generated file (D7) -- and that is the
|
|
31
|
-
// half a reader of the TARGET needs. The other half is the document:
|
|
32
|
-
// the marker lines carry a tree, and a tree nobody can see the shape of
|
|
33
|
-
// is the one thing this surface took away. So the marker stands at the
|
|
34
|
-
// left margin and the aontu is indented AFTER it, which `aontu fmt`
|
|
35
|
-
// (FMT.0.md M-BM-'3.14) is what writes.
|
|
36
|
-
//
|
|
37
|
-
// Reading is unchanged and stays generous: a marker after leading
|
|
38
|
-
// whitespace is a marker, and its own indentation still counts toward
|
|
39
|
-
// the aontu it carries, so a template written the other way desugars to
|
|
40
|
-
// the same document. What changes is the spelling the round trip
|
|
41
|
-
// answers, and `template --check` names the difference as the drift it
|
|
42
|
-
// is.
|
|
43
|
-
//
|
|
44
|
-
// THE SUGAR IS THE FIXPOINT OF THE TWO TRANSFORMS (D6), and that is
|
|
45
|
-
// the whole of the resugaring's safety. A canonical line that looks
|
|
46
|
-
// like a body element is rebuilt as a target line, the rebuild is
|
|
47
|
-
// desugared, and the rebuild is taken ONLY if that reproduces the
|
|
48
|
-
// canonical line. A line no target line can carry -- one that would
|
|
49
|
-
// itself read as a marker -- fails that test and stays where it is, so
|
|
50
|
-
// there is no table of escapes to get wrong and no line the round trip
|
|
51
|
-
// can lose.
|
|
52
|
-
//
|
|
53
|
-
// WHITESPACE CONTROL IS ABSENT AND UNNEEDED (D8): a marker line is not
|
|
54
|
-
// an output line at all, so no construct can leak a newline into the
|
|
55
|
-
// output. What IS significant is the template's own trailing
|
|
56
|
-
// whitespace -- a line of two spaces is two spaces of output -- which
|
|
57
|
-
// is why the canonical form quotes every body line explicitly. Note
|
|
58
|
-
// what `template --check` does and does not catch: it holds the FILE
|
|
59
|
-
// to the spelling these two transforms answer, so a marker written
|
|
60
|
-
// without its space or with its aontu indented after it is named; a
|
|
61
|
-
// body line an editor trimmed is still a valid template, and what
|
|
62
|
-
// names that is `render --check` against the committed output.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// A marker is a comment token plus a dash. These are the tokens the
|
|
66
|
-
// verb derives from a file's extension; any other language passes its
|
|
67
|
-
// own, which is why the surface needs no table of languages.
|
|
68
4
|
const MARKERS: Record<string, string> = {
|
|
69
5
|
c: '//-',
|
|
70
6
|
cc: '//-',
|
|
@@ -79,6 +15,8 @@ const MARKERS: Record<string, string> = {
|
|
|
79
15
|
jsx: '//-',
|
|
80
16
|
kt: '//-',
|
|
81
17
|
lua: '---',
|
|
18
|
+
markdown: '<!---',
|
|
19
|
+
md: '<!---',
|
|
82
20
|
php: '//-',
|
|
83
21
|
pl: '#-',
|
|
84
22
|
py: '#-',
|
|
@@ -99,36 +37,70 @@ const MARKERS: Record<string, string> = {
|
|
|
99
37
|
// C-family line comment, which is the one the note is written in.
|
|
100
38
|
const DEFAULT_MARKER = '//-'
|
|
101
39
|
|
|
102
|
-
// A
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
40
|
+
// A marker outside this table names its closer itself.
|
|
41
|
+
const IMPLIED_CLOSE: [string, string][] = [
|
|
42
|
+
['<!--', '-->'],
|
|
43
|
+
['/*', '*/'],
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
function extensionOf(path: string): string {
|
|
48
|
+
const dot = path.lastIndexOf('.')
|
|
49
|
+
const slash = Math.max(path.lastIndexOf('/'), path.lastIndexOf('\\'))
|
|
50
|
+
return dot > slash ? path.slice(dot + 1).toLowerCase() : ''
|
|
51
|
+
}
|
|
107
52
|
|
|
108
53
|
|
|
109
54
|
// The marker for a file, by its extension, or the C-family default.
|
|
110
55
|
// The extension decides, exactly as it decides what an include is
|
|
111
56
|
// (ADR-012) -- one rule, and no flag to remember for the common case.
|
|
112
57
|
function markerFor(path: string): string {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
58
|
+
return MARKERS[extensionOf(path)] ?? DEFAULT_MARKER
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
// What reaches a language the table has no entry for by FILENAME
|
|
63
|
+
// rather than by a flag on every call.
|
|
64
|
+
function markerFromProfiles(
|
|
65
|
+
profiles: any[], path: string
|
|
66
|
+
): string | undefined {
|
|
67
|
+
const ext = extensionOf(path)
|
|
68
|
+
if ('' === ext) {
|
|
69
|
+
return undefined
|
|
70
|
+
}
|
|
71
|
+
for (const profile of profiles) {
|
|
72
|
+
const tmpl = profile?.template
|
|
73
|
+
if (null == tmpl || !Array.isArray(tmpl.ext) || !tmpl.ext.includes(ext)) {
|
|
74
|
+
continue
|
|
75
|
+
}
|
|
76
|
+
return null == tmpl.close ? tmpl.marker : tmpl.marker + ' ' + tmpl.close
|
|
77
|
+
}
|
|
78
|
+
return undefined
|
|
117
79
|
}
|
|
118
80
|
|
|
119
81
|
|
|
120
|
-
//
|
|
121
|
-
|
|
122
|
-
|
|
82
|
+
// A marker may carry its own closer after a space, which no comment
|
|
83
|
+
// opener holds. An empty closer is the line form.
|
|
84
|
+
type MarkerForm = { open: string, close: string }
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
function markerForm(marker: string): MarkerForm {
|
|
88
|
+
const cut = marker.indexOf(' ')
|
|
89
|
+
if (-1 < cut) {
|
|
90
|
+
return {
|
|
91
|
+
open: marker.slice(0, cut),
|
|
92
|
+
close: trimLine(marker.slice(cut + 1)),
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
for (const [open, close] of IMPLIED_CLOSE) {
|
|
96
|
+
if (marker.startsWith(open)) {
|
|
97
|
+
return { open: marker, close }
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { open: marker, close: '' }
|
|
123
101
|
}
|
|
124
102
|
|
|
125
103
|
|
|
126
|
-
// INDENTATION IS SPACES AND TABS, and nothing else. A host trim is not
|
|
127
|
-
// the same set in the two ports -- JavaScript's trims every Unicode
|
|
128
|
-
// space, Go's `TrimSpace` trims a different list -- and a line of a
|
|
129
|
-
// template file that began with one of the characters they disagree
|
|
130
|
-
// about would be a marker line in one engine and a line of output in
|
|
131
|
-
// the other. Twin of templateIndent in go/template.go.
|
|
132
104
|
function indentOf(line: string): number {
|
|
133
105
|
let i = 0
|
|
134
106
|
while (i < line.length && (' ' === line[i] || '\t' === line[i])) {
|
|
@@ -164,31 +136,21 @@ type Line = {
|
|
|
164
136
|
}
|
|
165
137
|
|
|
166
138
|
|
|
167
|
-
function readLine(line: string,
|
|
139
|
+
function readLine(line: string, form: MarkerForm): Line {
|
|
168
140
|
const cut = indentOf(line)
|
|
169
141
|
const indent = line.slice(0, cut)
|
|
170
142
|
const rest = line.slice(cut)
|
|
171
|
-
if (!rest.startsWith(
|
|
143
|
+
if (!rest.startsWith(form.open)) {
|
|
172
144
|
return { marker: false, indent: '', text: line }
|
|
173
145
|
}
|
|
174
|
-
let body = rest.slice(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
// language's own parser would not read it as a comment either.
|
|
178
|
-
// Only the TRAILING space goes: what stands between the opener and
|
|
179
|
-
// the aontu is the aontu's indentation, exactly as it is for a line
|
|
180
|
-
// marker, and the one-space rule below takes the marker's own.
|
|
181
|
-
if (isBlock(marker)) {
|
|
182
|
-
const end = body.lastIndexOf(BLOCK_CLOSE)
|
|
146
|
+
let body = rest.slice(form.open.length)
|
|
147
|
+
if ('' !== form.close) {
|
|
148
|
+
const end = body.lastIndexOf(form.close)
|
|
183
149
|
if (end < 0) {
|
|
184
150
|
return { marker: false, indent: '', text: line }
|
|
185
151
|
}
|
|
186
152
|
body = trimEnd(body.slice(0, end))
|
|
187
153
|
}
|
|
188
|
-
// ONE SPACE AFTER THE MARKER IS THE MARKER'S, so `//- x: 1` carries
|
|
189
|
-
// `x: 1` and the resugaring writes the space back. A marker written
|
|
190
|
-
// without it carries the same aontu and is normalised on the round
|
|
191
|
-
// trip, which `--check` reports as the drift it is.
|
|
192
154
|
if (body.startsWith(' ')) {
|
|
193
155
|
body = body.slice(1)
|
|
194
156
|
}
|
|
@@ -196,16 +158,6 @@ function readLine(line: string, marker: string): Line {
|
|
|
196
158
|
}
|
|
197
159
|
|
|
198
160
|
|
|
199
|
-
// THE CANONICAL QUOTE IS CHOSEN PER LINE (D6). A backtick string
|
|
200
|
-
// carries `"` and `'` unescaped, which is most of what target code
|
|
201
|
-
// holds, so a line takes one unless it holds a backtick itself.
|
|
202
|
-
//
|
|
203
|
-
// A BACKSLASH IS ESCAPED IN EITHER QUOTE, and that is not what the
|
|
204
|
-
// design note assumed: this engine reads the escapes of a backtick
|
|
205
|
-
// string exactly as it reads a quoted one, and an unknown escape drops
|
|
206
|
-
// its backslash (`\p` is `p`), so a target line holding `\n` inside a
|
|
207
|
-
// string of its own would arrive in the output as a newline. Only the
|
|
208
|
-
// delimiter differs between the two forms.
|
|
209
161
|
function quoteLine(text: string): string {
|
|
210
162
|
const escaped = text.replace(/\\/g, '\\\\')
|
|
211
163
|
return text.includes('`') ?
|
|
@@ -214,10 +166,6 @@ function quoteLine(text: string): string {
|
|
|
214
166
|
}
|
|
215
167
|
|
|
216
168
|
|
|
217
|
-
// The line a quoted body element carries, or undefined when the line
|
|
218
|
-
// is not one: anything but a lone string literal, and any escape the
|
|
219
|
-
// quoting above does not write. The fixpoint test below is what makes
|
|
220
|
-
// being conservative here safe -- a line this refuses stays aontu.
|
|
221
169
|
function unquoteLine(text: string): string | undefined {
|
|
222
170
|
const t = trimLine(text)
|
|
223
171
|
if (2 > t.length) {
|
|
@@ -249,12 +197,8 @@ function unquoteLine(text: string): string | undefined {
|
|
|
249
197
|
}
|
|
250
198
|
|
|
251
199
|
|
|
252
|
-
// DESUGAR: a template file becomes the canonical aontu document.
|
|
253
|
-
// A marker line is its own text, at its own indentation; every other
|
|
254
|
-
// line is one quoted string, which lands wherever the marker lines
|
|
255
|
-
// left a list open.
|
|
256
200
|
function desugarTemplate(src: string, marker?: string): string {
|
|
257
|
-
const
|
|
201
|
+
const form = markerForm(marker ?? DEFAULT_MARKER)
|
|
258
202
|
const lines = src.split('\n')
|
|
259
203
|
// A trailing newline is the file's, not a line of output: a text
|
|
260
204
|
// file ends with one, and the round trip must not grow an empty
|
|
@@ -264,30 +208,22 @@ function desugarTemplate(src: string, marker?: string): string {
|
|
|
264
208
|
lines.pop()
|
|
265
209
|
}
|
|
266
210
|
const out = lines.map((line) => {
|
|
267
|
-
const read = readLine(line,
|
|
211
|
+
const read = readLine(line, form)
|
|
268
212
|
return read.marker ? read.indent + read.text : quoteLine(read.text)
|
|
269
213
|
})
|
|
270
214
|
return out.join('\n') + (tail ? '\n' : '')
|
|
271
215
|
}
|
|
272
216
|
|
|
273
217
|
|
|
274
|
-
// RESUGAR: the canonical document becomes a template file. Every line
|
|
275
|
-
// is a marker line unless it is a body element that survives the
|
|
276
|
-
// fixpoint -- rebuild the target line, desugar the rebuild, and take
|
|
277
|
-
// it only if that answers the canonical line back.
|
|
278
218
|
function resugarTemplate(src: string, marker?: string): string {
|
|
279
219
|
const mark = marker ?? DEFAULT_MARKER
|
|
220
|
+
const form = markerForm(mark)
|
|
280
221
|
const lines = src.split('\n')
|
|
281
222
|
const tail = 1 < lines.length && '' === lines[lines.length - 1]
|
|
282
223
|
if (tail) {
|
|
283
224
|
lines.pop()
|
|
284
225
|
}
|
|
285
226
|
const out = lines.map((line) => {
|
|
286
|
-
// THE ELEMENT'S OWN INDENTATION IS NOT PART OF IT: the target line
|
|
287
|
-
// is the string's content, and where the canonical form puts the
|
|
288
|
-
// element on the page is the formatter's business. Comparing the
|
|
289
|
-
// whole line instead would refuse every body element of a document
|
|
290
|
-
// `aontu fmt` had indented, which is every document it has seen.
|
|
291
227
|
const target = unquoteLine(line)
|
|
292
228
|
if (undefined !== target && desugarTemplate(target, mark) === trimLine(line)) {
|
|
293
229
|
return target
|
|
@@ -296,30 +232,22 @@ function resugarTemplate(src: string, marker?: string): string {
|
|
|
296
232
|
// is written after it, so the aontu's own shape is on the page.
|
|
297
233
|
// The one space is the marker's, which the reading takes back.
|
|
298
234
|
const text = trimEnd(line)
|
|
299
|
-
const close =
|
|
300
|
-
return '' === text ?
|
|
235
|
+
const close = '' === form.close ? '' : ' ' + form.close
|
|
236
|
+
return '' === text ? form.open + close :
|
|
237
|
+
form.open + ' ' + text + close
|
|
301
238
|
})
|
|
302
239
|
return out.join('\n') + (tail ? '\n' : '')
|
|
303
240
|
}
|
|
304
241
|
|
|
305
242
|
|
|
306
|
-
// WHICH LINES OF THE DESUGARED DOCUMENT ARE THE TARGET'S. The
|
|
307
|
-
// desugaring is line for line, so this is one flag per line of what
|
|
308
|
-
// `desugarTemplate` returns: true where the template's line was not a
|
|
309
|
-
// marker, and so where the document's line is one quoted line of the
|
|
310
|
-
// generated file.
|
|
311
|
-
//
|
|
312
|
-
// `aontu fmt` reads it (FMT.0.md M-BM-'3.14) to hold those lines on lines of
|
|
313
|
-
// their own. A body element is a string like any other, and the packing
|
|
314
|
-
// budget would put three of them on one line -- which is aontu where
|
|
315
|
-
// three lines of output were, and a generator that writes them as one.
|
|
316
243
|
function templateOutputs(src: string, marker: string): boolean[] {
|
|
244
|
+
const form = markerForm(marker)
|
|
317
245
|
const lines = src.split('\n')
|
|
318
246
|
if (1 < lines.length && '' === lines[lines.length - 1]) {
|
|
319
247
|
lines.pop()
|
|
320
248
|
}
|
|
321
|
-
return lines.map((line) => !readLine(line,
|
|
322
|
-
} /* node:coverage ignore next
|
|
249
|
+
return lines.map((line) => !readLine(line, form).marker)
|
|
250
|
+
} /* node:coverage ignore next 10 */
|
|
323
251
|
|
|
324
252
|
|
|
325
253
|
export {
|
|
@@ -327,5 +255,6 @@ export {
|
|
|
327
255
|
resugarTemplate,
|
|
328
256
|
templateOutputs,
|
|
329
257
|
markerFor,
|
|
258
|
+
markerFromProfiles,
|
|
330
259
|
DEFAULT_MARKER,
|
|
331
260
|
}
|