aontu 0.52.1 → 0.54.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 +88 -0
- package/bin/aontu-mcp.js +4 -0
- package/dist/agentsmd.d.ts +16 -0
- package/dist/agentsmd.js +107 -0
- package/dist/agentsmd.js.map +1 -0
- package/dist/aontu.d.ts +15 -3
- package/dist/aontu.js +126 -5
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +45 -1
- package/dist/cli.js +2845 -69
- package/dist/cli.js.map +1 -1
- package/dist/ctx.d.ts +18 -0
- package/dist/ctx.js +44 -0
- package/dist/ctx.js.map +1 -1
- package/dist/diff.d.ts +22 -0
- package/dist/diff.js +141 -0
- package/dist/diff.js.map +1 -0
- package/dist/err.d.ts +3 -1
- package/dist/err.js +45 -8
- package/dist/err.js.map +1 -1
- package/dist/graph.d.ts +13 -0
- package/dist/graph.js +110 -0
- package/dist/graph.js.map +1 -0
- package/dist/hcanon.d.ts +3 -0
- package/dist/hcanon.js +145 -0
- package/dist/hcanon.js.map +1 -0
- package/dist/hints.js +235 -8
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.d.ts +20 -0
- package/dist/jsonschema.js +425 -0
- package/dist/jsonschema.js.map +1 -0
- package/dist/lang.js +955 -110
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +9 -2
- package/dist/lsp.js +343 -48
- package/dist/lsp.js.map +1 -1
- package/dist/mcp-server.d.ts +20 -0
- package/dist/mcp-server.js +147 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mcp.d.ts +42 -0
- package/dist/mcp.js +941 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mod-tool.d.ts +58 -0
- package/dist/mod-tool.js +532 -0
- package/dist/mod-tool.js.map +1 -0
- package/dist/mod.d.ts +35 -0
- package/dist/mod.js +345 -0
- package/dist/mod.js.map +1 -0
- package/dist/patch.d.ts +49 -0
- package/dist/patch.js +506 -0
- package/dist/patch.js.map +1 -0
- package/dist/provenance.d.ts +41 -0
- package/dist/provenance.js +336 -0
- package/dist/provenance.js.map +1 -0
- package/dist/query.d.ts +27 -0
- package/dist/query.js +294 -0
- package/dist/query.js.map +1 -0
- package/dist/reach.d.ts +15 -0
- package/dist/reach.js +168 -0
- package/dist/reach.js.map +1 -0
- package/dist/relation.d.ts +23 -0
- package/dist/relation.js +230 -0
- package/dist/relation.js.map +1 -0
- package/dist/report-sarif.d.ts +14 -0
- package/dist/report-sarif.js +102 -0
- package/dist/report-sarif.js.map +1 -0
- package/dist/sig.d.ts +25 -0
- package/dist/sig.js +277 -0
- package/dist/sig.js.map +1 -0
- package/dist/sigdecl.d.ts +2 -0
- package/dist/sigdecl.js +11 -0
- package/dist/sigdecl.js.map +1 -0
- package/dist/siggate.d.ts +4 -0
- package/dist/siggate.js +90 -0
- package/dist/siggate.js.map +1 -0
- package/dist/site.d.ts +4 -0
- package/dist/site.js +31 -0
- package/dist/site.js.map +1 -1
- package/dist/std.d.ts +1 -0
- package/dist/std.js +129 -0
- package/dist/std.js.map +1 -0
- package/dist/subsume.d.ts +39 -0
- package/dist/subsume.js +573 -0
- package/dist/subsume.js.map +1 -0
- package/dist/trim.d.ts +19 -0
- package/dist/trim.js +155 -0
- package/dist/trim.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.d.ts +17 -1
- package/dist/type.js.map +1 -1
- package/dist/unify.d.ts +2 -1
- package/dist/unify.js +234 -38
- package/dist/unify.js.map +1 -1
- package/dist/utility.d.ts +8 -1
- package/dist/utility.js +68 -1
- package/dist/utility.js.map +1 -1
- package/dist/val/AggFuncVal.d.ts +44 -0
- package/dist/val/AggFuncVal.js +364 -0
- package/dist/val/AggFuncVal.js.map +1 -0
- package/dist/val/ArithFuncVal.d.ts +31 -0
- package/dist/val/ArithFuncVal.js +62 -0
- package/dist/val/ArithFuncVal.js.map +1 -0
- package/dist/val/BagVal.d.ts +7 -0
- package/dist/val/BagVal.js +150 -11
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/CloseFuncVal.js +9 -1
- package/dist/val/CloseFuncVal.js.map +1 -1
- package/dist/val/ConjunctVal.d.ts +1 -1
- package/dist/val/ConjunctVal.js +19 -0
- package/dist/val/ConjunctVal.js.map +1 -1
- package/dist/val/ConstraintVal.d.ts +7 -1
- package/dist/val/ConstraintVal.js +523 -45
- package/dist/val/ConstraintVal.js.map +1 -1
- package/dist/val/ContainerKindVal.d.ts +35 -0
- package/dist/val/ContainerKindVal.js +99 -0
- package/dist/val/ContainerKindVal.js.map +1 -0
- package/dist/val/CopyFuncVal.d.ts +1 -2
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/Decimal.d.ts +1 -0
- package/dist/val/Decimal.js +13 -0
- package/dist/val/Decimal.js.map +1 -1
- package/dist/val/DeprecateFuncVal.d.ts +11 -0
- package/dist/val/DeprecateFuncVal.js +47 -0
- package/dist/val/DeprecateFuncVal.js.map +1 -0
- package/dist/val/DisjunctVal.d.ts +1 -2
- package/dist/val/DisjunctVal.js +269 -53
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/EachFuncVal.d.ts +15 -0
- package/dist/val/EachFuncVal.js +75 -0
- package/dist/val/EachFuncVal.js.map +1 -0
- package/dist/val/ExpectVal.js +62 -4
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FeatureVal.js +1 -1
- package/dist/val/FeatureVal.js.map +1 -1
- package/dist/val/FilterFuncVal.d.ts +15 -0
- package/dist/val/FilterFuncVal.js +91 -0
- package/dist/val/FilterFuncVal.js.map +1 -0
- package/dist/val/FuncBaseVal.d.ts +7 -1
- package/dist/val/FuncBaseVal.js +183 -2
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/GraphAtomVal.d.ts +39 -0
- package/dist/val/GraphAtomVal.js +184 -0
- package/dist/val/GraphAtomVal.js.map +1 -0
- package/dist/val/HideFuncVal.js.map +1 -1
- package/dist/val/JunctionVal.js +24 -1
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/KeyFuncVal.d.ts +1 -1
- package/dist/val/KeyFuncVal.js +38 -30
- package/dist/val/KeyFuncVal.js.map +1 -1
- package/dist/val/ListVal.js +94 -14
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.d.ts +1 -0
- package/dist/val/MapVal.js +146 -14
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MatchFuncVal.d.ts +15 -0
- package/dist/val/MatchFuncVal.js +107 -0
- package/dist/val/MatchFuncVal.js.map +1 -0
- package/dist/val/MoveFuncVal.js.map +1 -1
- package/dist/val/NilVal.js +24 -0
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/OpBaseVal.d.ts +1 -1
- package/dist/val/OpBaseVal.js +19 -1
- package/dist/val/OpBaseVal.js.map +1 -1
- package/dist/val/OpenFuncVal.js +4 -1
- package/dist/val/OpenFuncVal.js.map +1 -1
- package/dist/val/PackFuncVal.d.ts +15 -0
- package/dist/val/PackFuncVal.js +108 -0
- package/dist/val/PackFuncVal.js.map +1 -0
- package/dist/val/PathFuncVal.d.ts +2 -2
- package/dist/val/PathFuncVal.js +75 -16
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PathVal.d.ts +25 -0
- package/dist/val/PathVal.js +150 -0
- package/dist/val/PathVal.js.map +1 -0
- package/dist/val/PlaceVal.d.ts +13 -0
- package/dist/val/PlaceVal.js +131 -0
- package/dist/val/PlaceVal.js.map +1 -0
- package/dist/val/PlusOpVal.d.ts +2 -1
- package/dist/val/PlusOpVal.js +61 -37
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefFuncVal.js.map +1 -1
- package/dist/val/PrefVal.d.ts +4 -2
- package/dist/val/PrefVal.js +223 -41
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RecurseVal.d.ts +19 -0
- package/dist/val/RecurseVal.js +217 -0
- package/dist/val/RecurseVal.js.map +1 -0
- package/dist/val/RefVal.d.ts +3 -2
- package/dist/val/RefVal.js +181 -66
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.d.ts +59 -0
- package/dist/val/ReferFuncVal.js +604 -0
- package/dist/val/ReferFuncVal.js.map +1 -0
- package/dist/val/ScalarKindVal.d.ts +4 -3
- package/dist/val/ScalarKindVal.js +12 -12
- package/dist/val/ScalarKindVal.js.map +1 -1
- package/dist/val/SuperFuncVal.d.ts +4 -2
- package/dist/val/SuperFuncVal.js +118 -14
- package/dist/val/SuperFuncVal.js.map +1 -1
- package/dist/val/TopVal.d.ts +1 -1
- package/dist/val/TopVal.js.map +1 -1
- package/dist/val/TypeFuncVal.js.map +1 -1
- package/dist/val/UpperFuncVal.js.map +1 -1
- package/dist/val/Val.d.ts +7 -1
- package/dist/val/Val.js +170 -2
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js.map +1 -1
- package/dist/val/arith.d.ts +6 -0
- package/dist/val/arith.js +173 -0
- package/dist/val/arith.js.map +1 -0
- package/dist/vet.d.ts +45 -0
- package/dist/vet.js +802 -0
- package/dist/vet.js.map +1 -0
- package/dist/view.d.ts +85 -0
- package/dist/view.js +1948 -0
- package/dist/view.js.map +1 -0
- package/dist/walk.d.ts +2 -0
- package/dist/walk.js +91 -0
- package/dist/walk.js.map +1 -0
- package/grammar/aontu.gbnf +138 -0
- package/grammar/aontu.lark +118 -0
- package/grammar/aontu.tmLanguage.json +184 -0
- package/package.json +30 -8
- package/skill/SKILL.md +37 -0
- package/skill/error-codes.md +62 -0
- package/skill/examples.md +99 -0
- package/skill/grammar-card.md +56 -0
- package/src/agentsmd.ts +135 -0
- package/src/aontu.ts +166 -5
- package/src/cli.ts +3324 -72
- package/src/ctx.ts +93 -1
- package/src/diff.ts +198 -0
- package/src/err.ts +50 -8
- package/src/graph.ts +185 -0
- package/src/hcanon.ts +167 -0
- package/src/hints.ts +291 -8
- package/src/jsonschema.ts +552 -0
- package/src/lang.ts +1049 -110
- package/src/lsp.ts +351 -49
- package/src/mcp-server.ts +187 -0
- package/src/mcp.ts +1130 -0
- package/src/mod-tool.ts +718 -0
- package/src/mod.ts +453 -0
- package/src/patch.ts +628 -0
- package/src/provenance.ts +437 -0
- package/src/query.ts +381 -0
- package/src/reach.ts +213 -0
- package/src/relation.ts +298 -0
- package/src/report-sarif.ts +137 -0
- package/src/sig.ts +345 -0
- package/src/sigdecl.ts +11 -0
- package/src/siggate.ts +144 -0
- package/src/site.ts +36 -1
- package/src/std.ts +131 -0
- package/src/subsume.ts +739 -0
- package/src/trim.ts +195 -0
- package/src/tsconfig.json +10 -4
- package/src/type.ts +51 -2
- package/src/unify.ts +253 -38
- package/src/utility.ts +79 -1
- package/src/val/AggFuncVal.ts +546 -0
- package/src/val/ArithFuncVal.ts +108 -0
- package/src/val/BagVal.ts +158 -12
- package/src/val/CloseFuncVal.ts +9 -1
- package/src/val/ConjunctVal.ts +20 -0
- package/src/val/ConstraintVal.ts +576 -48
- package/src/val/ContainerKindVal.ts +158 -0
- package/src/val/CopyFuncVal.ts +0 -1
- package/src/val/Decimal.ts +15 -0
- package/src/val/DeprecateFuncVal.ts +84 -0
- package/src/val/DisjunctVal.ts +282 -59
- package/src/val/EachFuncVal.ts +133 -0
- package/src/val/ExpectVal.ts +65 -8
- package/src/val/FeatureVal.ts +1 -1
- package/src/val/FilterFuncVal.ts +154 -0
- package/src/val/FuncBaseVal.ts +206 -2
- package/src/val/GraphAtomVal.ts +264 -0
- package/src/val/HideFuncVal.ts +0 -2
- package/src/val/JunctionVal.ts +24 -1
- package/src/val/KeyFuncVal.ts +39 -35
- package/src/val/ListVal.ts +101 -15
- package/src/val/LowerFuncVal.ts +0 -1
- package/src/val/MapVal.ts +153 -14
- package/src/val/MatchFuncVal.ts +176 -0
- package/src/val/MoveFuncVal.ts +0 -2
- package/src/val/NilVal.ts +25 -0
- package/src/val/OpBaseVal.ts +20 -1
- package/src/val/OpenFuncVal.ts +4 -2
- package/src/val/PackFuncVal.ts +175 -0
- package/src/val/PathFuncVal.ts +107 -20
- package/src/val/PathVal.ts +221 -0
- package/src/val/PlaceVal.ts +193 -0
- package/src/val/PlusOpVal.ts +67 -39
- package/src/val/PrefFuncVal.ts +0 -1
- package/src/val/PrefVal.ts +251 -60
- package/src/val/RecurseVal.ts +285 -0
- package/src/val/RefVal.ts +183 -78
- package/src/val/ReferFuncVal.ts +732 -0
- package/src/val/ScalarKindVal.ts +12 -13
- package/src/val/SuperFuncVal.ts +137 -13
- package/src/val/TopVal.ts +1 -2
- package/src/val/TypeFuncVal.ts +0 -2
- package/src/val/UpperFuncVal.ts +0 -1
- package/src/val/Val.ts +216 -4
- package/src/val/VarVal.ts +0 -1
- package/src/val/arith.ts +319 -0
- package/src/vet.ts +1025 -0
- package/src/view.ts +2563 -0
- package/src/walk.ts +99 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
// THE RECURSIVE RESIDUAL (docs/design/RECURSION.0.md): where RefVal's
|
|
4
|
+
// prefix test used to answer `path_cycle` for a self-reference --
|
|
5
|
+
// `$.Node` written anywhere inside `Node` -- it now answers this
|
|
6
|
+
// value: a deferred reference carrying the target path, exactly as a
|
|
7
|
+
// constraint atom carries its bound. No new syntax: the reference the
|
|
8
|
+
// author wrote simply MEANS the fixpoint.
|
|
9
|
+
//
|
|
10
|
+
// The three moments of every residual:
|
|
11
|
+
//
|
|
12
|
+
// - At unification, EXPAND ONE LEVEL PER MEET WITH STRUCTURE: met by
|
|
13
|
+
// a map, list, or scalar, the residual clones the schema body one
|
|
14
|
+
// level -- per destination, under ADR-005's clone discipline -- and
|
|
15
|
+
// unifies the clone with the peer. The clone's own self-reference
|
|
16
|
+
// is again this residual, so each expansion consumes one level of
|
|
17
|
+
// concrete data; data is finite, so expansion terminates
|
|
18
|
+
// (structural descent), with the depth budget as the backstop
|
|
19
|
+
// (recursion_budget).
|
|
20
|
+
// - In canon and the aon1- hash, SYMBOLIC: the residual prints as the
|
|
21
|
+
// reference the author wrote, so a recursive schema's canon is
|
|
22
|
+
// finite and round-trips, and the hash pins the mu-form rather than
|
|
23
|
+
// any unrolling.
|
|
24
|
+
// - At generation, an unexpanded residual REFUSES with
|
|
25
|
+
// recursion_unexpanded. Guardedness is therefore EMERGENT: under
|
|
26
|
+
// `next?:` the refusal is isolated and the optional key drops;
|
|
27
|
+
// under `*null | $.Node` the preference generates; a REQUIRED
|
|
28
|
+
// recursive field with no data refuses at the instance.
|
|
29
|
+
|
|
30
|
+
import type {
|
|
31
|
+
Val,
|
|
32
|
+
ValSpec,
|
|
33
|
+
} from '../type'
|
|
34
|
+
|
|
35
|
+
import {
|
|
36
|
+
DONE,
|
|
37
|
+
} from '../type'
|
|
38
|
+
|
|
39
|
+
import {
|
|
40
|
+
AontuContext,
|
|
41
|
+
} from '../ctx'
|
|
42
|
+
|
|
43
|
+
import { makeNilErr } from '../err'
|
|
44
|
+
|
|
45
|
+
import { FeatureVal } from './FeatureVal'
|
|
46
|
+
import { ConjunctVal } from './ConjunctVal'
|
|
47
|
+
import { unite } from '../unify'
|
|
48
|
+
import { propagateMarks, walk } from '../utility'
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class RecurseVal extends FeatureVal {
|
|
52
|
+
isRecurse = true
|
|
53
|
+
isGenable = true
|
|
54
|
+
// LAST in a conjunct fold, after even the graph atoms: the residual
|
|
55
|
+
// wants to see the assembled concrete structure it expands against.
|
|
56
|
+
cjo = 47000
|
|
57
|
+
|
|
58
|
+
// The target path, absolute from the root, as the reference spelled
|
|
59
|
+
// it.
|
|
60
|
+
target: string[]
|
|
61
|
+
// Expansion depth so far along this chain, charged against the
|
|
62
|
+
// depth budget (the T-1 backstop).
|
|
63
|
+
xc: number
|
|
64
|
+
|
|
65
|
+
constructor(spec: ValSpec, ctx?: AontuContext) {
|
|
66
|
+
super(spec, ctx)
|
|
67
|
+
this.target = (spec as any).target ?? []
|
|
68
|
+
this.xc = (spec as any).xc ?? 0
|
|
69
|
+
// A settled residual: a type() body carrying one must settle, and
|
|
70
|
+
// an unmet recursion is its own value until data arrives.
|
|
71
|
+
this.dc = DONE
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
75
|
+
const out: any = super.clone(ctx, spec)
|
|
76
|
+
out.target = this.target
|
|
77
|
+
out.xc = this.xc
|
|
78
|
+
return out
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// The schema body the target names, from the ROOT: the fixpoint is
|
|
82
|
+
// over the finished definition, and the definition's own residual
|
|
83
|
+
// keeps it finite. When the root does not contain the target -- the
|
|
84
|
+
// residual was LIFTED out of its defining tree, as vet's anchored
|
|
85
|
+
// meet does -- fall back to ctx._fixroot, the settled tree the
|
|
86
|
+
// lifter kept for exactly this walk.
|
|
87
|
+
private body(ctx: AontuContext): Val | undefined {
|
|
88
|
+
return walkTarget(ctx.root, this.target)
|
|
89
|
+
?? walkTarget((ctx as any)._fixroot, this.target)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
unify(peer: Val, ctx: AontuContext): Val {
|
|
93
|
+
const p: any = peer
|
|
94
|
+
|
|
95
|
+
// The self-drive: nothing to advance -- the residual waits for
|
|
96
|
+
// structure. (A null/nil peer never arrives; unite's ladder
|
|
97
|
+
// absorbs both.)
|
|
98
|
+
if (null == peer || true === p.isTop) {
|
|
99
|
+
return this
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// The same fixpoint twice is one fixpoint.
|
|
103
|
+
if (true === p.isRecurse) {
|
|
104
|
+
if (this.target.length === p.target.length
|
|
105
|
+
&& this.target.every((s, i) => s === p.target[i])) {
|
|
106
|
+
return this
|
|
107
|
+
}
|
|
108
|
+
// Different targets -- mutual recursion meeting -- are BOTH
|
|
109
|
+
// held: each expands as data arrives, through the fold that
|
|
110
|
+
// keeps a conjunct's members separate.
|
|
111
|
+
const out = new ConjunctVal({ peg: [this, peer] }, ctx)
|
|
112
|
+
propagateMarks(this, out)
|
|
113
|
+
out.path = this.path
|
|
114
|
+
return out
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// CONCRETE STRUCTURE: expand one level against it.
|
|
118
|
+
if (true === p.isMap || true === p.isList || true === p.isScalar) {
|
|
119
|
+
if (ctx.budget.depth <= this.xc) {
|
|
120
|
+
return makeNilErr(ctx, 'recursion_budget', this, peer, 'recurse',
|
|
121
|
+
{ target: '$.' + this.target.join('.') })
|
|
122
|
+
}
|
|
123
|
+
const body = this.body(ctx)
|
|
124
|
+
if (undefined === body) {
|
|
125
|
+
// The definition has not assembled yet (an early pass): hold
|
|
126
|
+
// the peer beside the residual and try again when it has.
|
|
127
|
+
const out = new ConjunctVal({ peg: [this, peer] }, ctx)
|
|
128
|
+
propagateMarks(this, out)
|
|
129
|
+
out.path = this.path
|
|
130
|
+
return out
|
|
131
|
+
}
|
|
132
|
+
// ADR-005's clone discipline: the expansion is a per-destination
|
|
133
|
+
// instantiation, so the definition itself is never written
|
|
134
|
+
// into. The clone's type/hide marks are CLEARED at every depth,
|
|
135
|
+
// exactly as a plain reference copy clears them (concreteFlow's
|
|
136
|
+
// rule): the schema is hidden, the instances it expands into
|
|
137
|
+
// are the output.
|
|
138
|
+
// The clone is REBASED to the DRIVE path explicitly (spec.path;
|
|
139
|
+
// the Go twin passes cp(r.path), whose stored paths its clone
|
|
140
|
+
// arms keep clean): the default rebase slices the definition's
|
|
141
|
+
// path by the destination's length, which leaks definition
|
|
142
|
+
// segments into instance paths whenever the destination is
|
|
143
|
+
// shallower -- a residual carried inside a copied definition
|
|
144
|
+
// body (`chain: $.spec.Step` inside Policy, copied to a slot
|
|
145
|
+
// shallower than the definition) reported
|
|
146
|
+
// `$.payments_policy.Policy.chain.then.approver` for the
|
|
147
|
+
// finding Go placed at `$.payments_policy.chain.then.approver`.
|
|
148
|
+
// The drive path is also right under vet's anchored meet, which
|
|
149
|
+
// drives AT the anchor's own path (see vet.ts), so anchored
|
|
150
|
+
// findings land in the schema's namespace in both ports.
|
|
151
|
+
const level: any = body.clone(ctx, {
|
|
152
|
+
dup: true, path: [...ctx.path],
|
|
153
|
+
} as any)
|
|
154
|
+
walk(level, (_key: string | number | undefined, v: Val) => {
|
|
155
|
+
v.mark.type = false
|
|
156
|
+
v.mark.hide = false
|
|
157
|
+
return v
|
|
158
|
+
})
|
|
159
|
+
bumpRecurse(level, this.xc + 1)
|
|
160
|
+
return unite(ctx, level, peer, 'recurse-expand')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Anything else -- a func still resolving, a reference, a
|
|
164
|
+
// constraint -- waits beside the residual.
|
|
165
|
+
const out = new ConjunctVal({ peg: [this, peer] }, ctx)
|
|
166
|
+
propagateMarks(this, out)
|
|
167
|
+
out.path = this.path
|
|
168
|
+
return out
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
get canon(): string {
|
|
172
|
+
return '$.' + this.target.join('.')
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
gen(ctx: AontuContext) {
|
|
176
|
+
// An unexpanded residual in a demanded position refuses;
|
|
177
|
+
// guardedness is emergent -- under an optional key the bag's
|
|
178
|
+
// isolated context swallows this and drops the key.
|
|
179
|
+
makeNilErr(ctx, 'recursion_unexpanded', this, undefined, 'recurse',
|
|
180
|
+
{ target: '$.' + this.target.join('.') })
|
|
181
|
+
return undefined
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
// walkTarget descends a tree by the residual's absolute target path,
|
|
187
|
+
// answering the definition node or undefined.
|
|
188
|
+
function walkTarget(root: any, target: string[]): Val | undefined {
|
|
189
|
+
let node: any = root
|
|
190
|
+
for (const seg of target) {
|
|
191
|
+
node = node?.peg?.[seg]
|
|
192
|
+
}
|
|
193
|
+
return null != node && true === node.isVal ? node : undefined
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
// bumpRecurse stamps the expansion depth onto every residual inside a
|
|
198
|
+
// freshly cloned level, so descent is charged along the chain.
|
|
199
|
+
function bumpRecurse(v: any, xc: number): void {
|
|
200
|
+
if (null == v || true !== v.isVal) {
|
|
201
|
+
return
|
|
202
|
+
}
|
|
203
|
+
if (true === v.isRecurse) {
|
|
204
|
+
v.xc = Math.max(v.xc, xc)
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
const peg: any = v.peg
|
|
208
|
+
if (true === v.isMap && null != peg) {
|
|
209
|
+
for (const k of Object.keys(peg)) {
|
|
210
|
+
bumpRecurse(peg[k], xc)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
else if (true === v.isList && Array.isArray(peg)) {
|
|
214
|
+
for (const e of peg) {
|
|
215
|
+
bumpRecurse(e, xc)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else if (true === v.isConjunct && Array.isArray(peg)) {
|
|
219
|
+
for (const e of peg) {
|
|
220
|
+
bumpRecurse(e, xc)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (null != v.spread?.cj) {
|
|
224
|
+
bumpRecurse(v.spread.cj, xc)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
// containsRecurseOf answers whether a definition holds a residual of
|
|
230
|
+
// the given target -- i.e. the definition is (transitively) the
|
|
231
|
+
// fixpoint that target names. A reference RESOLVING to such a
|
|
232
|
+
// definition must itself answer the residual: cloned instead, every
|
|
233
|
+
// reparse of a canon unrolled the schema one more level and canon
|
|
234
|
+
// never converged.
|
|
235
|
+
function containsRecurseOf(v: any, target: string[], depth?: number): boolean {
|
|
236
|
+
const d = depth ?? 0
|
|
237
|
+
if (null == v || true !== v.isVal || 8 < d) {
|
|
238
|
+
return false
|
|
239
|
+
}
|
|
240
|
+
if (true === v.isRecurse) {
|
|
241
|
+
return v.target.length === target.length
|
|
242
|
+
&& v.target.every((s: string, i: number) => s === target[i])
|
|
243
|
+
}
|
|
244
|
+
// A RAW REFERENCE to the target IS the recursion, minted or not:
|
|
245
|
+
// the answer must not depend on whether the definition's own
|
|
246
|
+
// prefix position has been visited yet. Without this arm the
|
|
247
|
+
// answer was ORDER-DEPENDENT -- reparsing a generated canon puts
|
|
248
|
+
// the instance before the definition, its trailing `$.spec.Step`
|
|
249
|
+
// leaves resolved before `Step.then` had minted, and each resolve
|
|
250
|
+
// cloned one more unrolled level until the unify depth guard
|
|
251
|
+
// (unify_cycle) killed the document.
|
|
252
|
+
if (true === v.isRef && Array.isArray(v.peg)) {
|
|
253
|
+
if (v.peg.length === target.length
|
|
254
|
+
&& v.peg.every((s: any, i: number) => s === target[i])) {
|
|
255
|
+
return true
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const peg: any = v.peg
|
|
259
|
+
if (true === v.isMap && null != peg) {
|
|
260
|
+
for (const k of Object.keys(peg)) {
|
|
261
|
+
if (containsRecurseOf(peg[k], target, d + 1)) {
|
|
262
|
+
return true
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
else if ((true === v.isList || true === v.isConjunct || true === v.isDisjunct)
|
|
267
|
+
&& Array.isArray(peg)) {
|
|
268
|
+
for (const e of peg) {
|
|
269
|
+
if (containsRecurseOf(e, target, d + 1)) {
|
|
270
|
+
return true
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (null != v.spread?.cj && containsRecurseOf(v.spread.cj, target, d + 1)) {
|
|
275
|
+
return true
|
|
276
|
+
}
|
|
277
|
+
return false
|
|
278
|
+
} /* node:coverage ignore next 7 */
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
export {
|
|
282
|
+
RecurseVal,
|
|
283
|
+
bumpRecurse,
|
|
284
|
+
containsRecurseOf,
|
|
285
|
+
}
|
package/src/val/RefVal.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/* Copyright (c) 2021-2025 Richard Rodger, MIT License */
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
import Util from 'node:util'
|
|
5
4
|
|
|
6
5
|
import {
|
|
7
6
|
walk,
|
|
@@ -23,6 +22,7 @@ import {
|
|
|
23
22
|
import { AontuContext } from '../ctx'
|
|
24
23
|
|
|
25
24
|
import { makeNilErr } from '../err'
|
|
25
|
+
import { RecurseVal, containsRecurseOf } from './RecurseVal'
|
|
26
26
|
import { unite } from '../unify'
|
|
27
27
|
|
|
28
28
|
|
|
@@ -49,6 +49,30 @@ import { BigDecimalVal } from './BigDecimalVal'
|
|
|
49
49
|
const UNSPELLABLE_SEGMENT = '\u0000unspellable'
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
// Is this value an unresolved type()/hide() call — or a conjunct still
|
|
53
|
+
// carrying one? A reference that lands on one must defer rather than
|
|
54
|
+
// clone it (see the call site in `find`): the marks such a call will
|
|
55
|
+
// stamp belong to the field it was WRITTEN at, and a clone resolving
|
|
56
|
+
// at the reference's site re-applies them after the reference's
|
|
57
|
+
// mark-clearing walk has already run. Only the two mark wrappers
|
|
58
|
+
// qualify — every other pending call resolves to an unmarked value,
|
|
59
|
+
// and the existing early-clone behaviour for those is pinned
|
|
60
|
+
// (move()/copy() ghost rows, hole-filling conjuncts).
|
|
61
|
+
function pendingMarkWrapper(v: any): boolean {
|
|
62
|
+
if (true === v.isTypeFunc || true === v.isHideFunc) {
|
|
63
|
+
return !v.done
|
|
64
|
+
}
|
|
65
|
+
if (true === v.isConjunct && Array.isArray(v.peg)) {
|
|
66
|
+
for (const t of v.peg) {
|
|
67
|
+
if (pendingMarkWrapper(t)) {
|
|
68
|
+
return true
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return false
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
52
76
|
class RefVal extends FeatureVal {
|
|
53
77
|
isRef = true
|
|
54
78
|
isGenable = true
|
|
@@ -175,7 +199,6 @@ class RefVal extends FeatureVal {
|
|
|
175
199
|
|
|
176
200
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Ref', this, peer)
|
|
177
201
|
let out: Val = this
|
|
178
|
-
let why = 'id'
|
|
179
202
|
|
|
180
203
|
if (this.id !== peer.id) {
|
|
181
204
|
|
|
@@ -191,29 +214,24 @@ class RefVal extends FeatureVal {
|
|
|
191
214
|
if (resolved instanceof RefVal) {
|
|
192
215
|
if (peer.isTop) {
|
|
193
216
|
out = this
|
|
194
|
-
why = 'pt'
|
|
195
217
|
}
|
|
196
218
|
else if (peer.isNil) {
|
|
197
219
|
out = makeNilErr(ctx, 'ref[' + this.peg + ']', this, peer)
|
|
198
|
-
why = 'pn'
|
|
199
220
|
}
|
|
200
221
|
|
|
201
222
|
// same path
|
|
202
223
|
else if (this.canon === peer.canon) {
|
|
203
224
|
out = this
|
|
204
|
-
why = 'pp'
|
|
205
225
|
}
|
|
206
226
|
|
|
207
227
|
else {
|
|
208
228
|
// Ensure RefVal done is incremented
|
|
209
229
|
this.dc = DONE === this.dc ? DONE : this.dc + 1
|
|
210
230
|
out = new ConjunctVal({ peg: [this, peer] }, ctx)
|
|
211
|
-
why = 'cj'
|
|
212
231
|
}
|
|
213
232
|
}
|
|
214
233
|
else {
|
|
215
234
|
out = unite(te ? ctx.clone({ explain: ec(te, 'RES') }) : ctx, resolved, peer, 'ref')
|
|
216
|
-
why = 'u'
|
|
217
235
|
}
|
|
218
236
|
|
|
219
237
|
out.dc = DONE === out.dc ? DONE : this.dc + 1
|
|
@@ -226,7 +244,15 @@ class RefVal extends FeatureVal {
|
|
|
226
244
|
}
|
|
227
245
|
|
|
228
246
|
|
|
229
|
-
|
|
247
|
+
// `snap` is set by snapshotRefSpread (MapVal): a SPREAD snapshot
|
|
248
|
+
// wants the target's pre-resolution STRUCTURE — key()/path() still
|
|
249
|
+
// unresolved, to be re-resolved per destination — so the
|
|
250
|
+
// pending-mark-wrapper defer below must not apply to it. Deferring
|
|
251
|
+
// there made the snapshot wait until the target's own key() had
|
|
252
|
+
// resolved at the target, and the literal leaked into every
|
|
253
|
+
// destination (the exact failure the snapshot exists to prevent —
|
|
254
|
+
// test/spec/spread-type.tsv, spread-type-key-ref).
|
|
255
|
+
find(ctx: AontuContext, snap?: boolean) {
|
|
230
256
|
let out: Val | undefined = undefined
|
|
231
257
|
|
|
232
258
|
// Check if self.path starts with peg (cycle detection).
|
|
@@ -254,50 +280,56 @@ class RefVal extends FeatureVal {
|
|
|
254
280
|
// let descent = ''
|
|
255
281
|
|
|
256
282
|
if (isprefixpath) {
|
|
257
|
-
//
|
|
258
|
-
|
|
283
|
+
// THE DETECTOR'S ANSWER IS A RESIDUAL (RECURSION.0.md): a
|
|
284
|
+
// self-reference under a guarded shape is the fixpoint the
|
|
285
|
+
// author wrote, so the prefix hit mints the recursive residual
|
|
286
|
+
// instead of refusing -- except the degenerate all-empty
|
|
287
|
+
// spelling (path("")), which names nothing and keeps its
|
|
288
|
+
// path_cycle. Only all-string paths recurse; anything else
|
|
289
|
+
// keeps the conservative refusal.
|
|
290
|
+
let degenerate = 0 === this.path.length
|
|
291
|
+
let target: string[] = []
|
|
292
|
+
for (let i = 0; i < this.peg.length && !degenerate; i++) {
|
|
293
|
+
if ('string' !== typeof this.peg[i] || '' === this.peg[i]) {
|
|
294
|
+
degenerate = true
|
|
295
|
+
break
|
|
296
|
+
}
|
|
297
|
+
target.push(this.peg[i] as string)
|
|
298
|
+
}
|
|
299
|
+
if (degenerate) {
|
|
300
|
+
out = makeNilErr(ctx, 'path_cycle', this)
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
const rec: any = new RecurseVal({ target } as any, ctx)
|
|
304
|
+
rec.site = this.site
|
|
305
|
+
rec.path = [...this.path]
|
|
306
|
+
out = rec
|
|
307
|
+
}
|
|
259
308
|
}
|
|
260
309
|
else {
|
|
261
310
|
|
|
262
311
|
let parts: string[] = []
|
|
263
312
|
|
|
264
|
-
let modes: string[] = []
|
|
265
|
-
|
|
266
313
|
for (let pI = 0; pI < this.peg.length; pI++) {
|
|
267
314
|
let part = this.peg[pI]
|
|
315
|
+
// An unspellable segment MISSES BEFORE ANY LOOKUP. The marker
|
|
316
|
+
// is NUL-prefixed because no spelling produces one, but a
|
|
317
|
+
// document can still hold a key spelled with an escaped NUL
|
|
318
|
+
// (`a:{"unspellable":7}`), and matching it would turn the
|
|
319
|
+
// silent path-shortening this marker exists to prevent into a
|
|
320
|
+
// different silent wrong value. The marker is a marker, never a
|
|
321
|
+
// lookup key.
|
|
322
|
+
if (UNSPELLABLE_SEGMENT === part) {
|
|
323
|
+
return makeNilErr(ctx, 'no_path', this)
|
|
324
|
+
}
|
|
268
325
|
if (part instanceof VarVal) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
else {
|
|
277
|
-
// TODO: return a Nil explaining error
|
|
278
|
-
return
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
if ('SELF' === name) {
|
|
283
|
-
if (pI === 0) {
|
|
284
|
-
modes.push(name)
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
// TODO: return a Nil explaining error
|
|
288
|
-
return
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
else if ('PARENT' === name) {
|
|
292
|
-
if (pI === 0) {
|
|
293
|
-
modes.push(name)
|
|
294
|
-
}
|
|
295
|
-
else {
|
|
296
|
-
// TODO: return a Nil explaining error
|
|
297
|
-
return
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
else if (0 === modes.length) {
|
|
326
|
+
// EVERY `$name` IN A PATH IS AN ORDINARY VARIABLE. `$KEY`,
|
|
327
|
+
// `$SELF` and `$PARENT` used to be intercepted here by name;
|
|
328
|
+
// they are gone (ADR-009). `key()` is the replacement for
|
|
329
|
+
// `$KEY` and answers where a value LANDS rather than where it
|
|
330
|
+
// was written, `$SELF.x` was only ever `$.x`, and `$PARENT.x`
|
|
331
|
+
// was only ever `.x`.
|
|
332
|
+
{
|
|
301
333
|
part = (part as VarVal).unify(top(), ctx)
|
|
302
334
|
if (part.isNil) {
|
|
303
335
|
// TODO: var not found, so can't find path
|
|
@@ -332,15 +364,9 @@ class RefVal extends FeatureVal {
|
|
|
332
364
|
refpath = parts
|
|
333
365
|
}
|
|
334
366
|
else {
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
(
|
|
339
|
-
modes.includes('SELF') ? 0 :
|
|
340
|
-
modes.includes('PARENT') ? -1 :
|
|
341
|
-
-1 // siblings
|
|
342
|
-
)
|
|
343
|
-
).concat(parts)
|
|
367
|
+
// A relative reference reads from the SIBLING scope: drop this
|
|
368
|
+
// node's own key and append the written segments.
|
|
369
|
+
refpath = this.path.slice(0, -1).concat(parts)
|
|
344
370
|
}
|
|
345
371
|
|
|
346
372
|
let sep = '.'
|
|
@@ -348,29 +374,6 @@ class RefVal extends FeatureVal {
|
|
|
348
374
|
.reduce(((a: string[], p: string) =>
|
|
349
375
|
(p === sep ? a.length = a.length - 1 : a.push(p), a)), [])
|
|
350
376
|
|
|
351
|
-
if (modes.includes('KEY')) {
|
|
352
|
-
// STRINGIFY. A LIST index arrives here as a JS NUMBER (jsonic puts
|
|
353
|
-
// it in the path as one, and lang.ts copies the path wholesale),
|
|
354
|
-
// so `.$KEY` inside a list built a StringVal whose peg was the
|
|
355
|
-
// number 0 -- an ill-formed value, not a design choice: it canoned
|
|
356
|
-
// as a bare 0, generated a JSON number, satisfied `number` and
|
|
357
|
-
// failed `string`. Go stringifies, and key() already agreed with
|
|
358
|
-
// Go, so this port disagreed with itself.
|
|
359
|
-
//
|
|
360
|
-
// Coerced HERE, at the consumption site, rather than by
|
|
361
|
-
// normalising Val.path: the numeric segment originates in jsonic's
|
|
362
|
-
// own r.k.path and every other path consumer (find's descent,
|
|
363
|
-
// key(), the clone/spread machinery) already handles it.
|
|
364
|
-
let key = this.path[this.path.length - 2]
|
|
365
|
-
let sv = new StringVal({ peg: null == key ? '' : '' + key }, ctx)
|
|
366
|
-
|
|
367
|
-
// TODO: other props?
|
|
368
|
-
sv.dc = DONE
|
|
369
|
-
sv.path = this.path
|
|
370
|
-
|
|
371
|
-
return sv
|
|
372
|
-
}
|
|
373
|
-
|
|
374
377
|
let node = ctx.root as Val
|
|
375
378
|
|
|
376
379
|
let nopath = false
|
|
@@ -388,6 +391,21 @@ class RefVal extends FeatureVal {
|
|
|
388
391
|
else if (node.isList) {
|
|
389
392
|
node = node.peg[part]
|
|
390
393
|
}
|
|
394
|
+
// A PENDING MARK WRAPPER IS TRANSPARENT TO THE WALK: hide()
|
|
395
|
+
// and type() only mark, and their argument is the structure
|
|
396
|
+
// the path names. Without this, two sibling schemas in one
|
|
397
|
+
// hide() bag deadlock -- the wrapper waits for its argument,
|
|
398
|
+
// the argument's members wait for references that walk into
|
|
399
|
+
// the unresolved wrapper (BUGS.md §53's family; the
|
|
400
|
+
// recursive Policy/Step pair found it again). The found node
|
|
401
|
+
// is cloned and mark-cleared exactly as any reference target
|
|
402
|
+
// is, and the wrapper still marks its own field.
|
|
403
|
+
else if (true === (node as any).isFunc
|
|
404
|
+
&& ((node as any).isHideFunc || (node as any).isTypeFunc)
|
|
405
|
+
&& (true === (node as any).peg?.[0]?.isMap
|
|
406
|
+
|| true === (node as any).peg?.[0]?.isList)) {
|
|
407
|
+
node = (node as any).peg[0].peg[part]
|
|
408
|
+
}
|
|
391
409
|
else if (node.done) {
|
|
392
410
|
nopath = true
|
|
393
411
|
break;
|
|
@@ -404,8 +422,41 @@ class RefVal extends FeatureVal {
|
|
|
404
422
|
}
|
|
405
423
|
}
|
|
406
424
|
|
|
407
|
-
//
|
|
408
|
-
|
|
425
|
+
// THE ANCHORED-MEET FALLBACK (vet --at): an absolute reference
|
|
426
|
+
// inside a lifted subtree names the SCHEMA's namespace, and the
|
|
427
|
+
// meet's root does not contain it. The settled schema root the
|
|
428
|
+
// lifter kept (AontuContext._fixroot; see RecurseVal.body) is
|
|
429
|
+
// the tree such a reference means. Without this, a recursion
|
|
430
|
+
// re-entering through a list spread died as no_path at the
|
|
431
|
+
// first element under vet --at, while the map-tail form (whose
|
|
432
|
+
// residual was minted during schema settling) worked; the Go
|
|
433
|
+
// port answers the anchored meet from settled structures and
|
|
434
|
+
// never sees the gap.
|
|
435
|
+
const fixroot: any = (ctx as any)._fixroot
|
|
436
|
+
if (this.absolute && null != fixroot
|
|
437
|
+
&& (nopath || pI !== refpath.length)) {
|
|
438
|
+
nopath = false
|
|
439
|
+
pI = 0
|
|
440
|
+
let fnode: any = fixroot
|
|
441
|
+
for (; pI < refpath.length; pI++) {
|
|
442
|
+
const part = refpath[pI]
|
|
443
|
+
if (true === fnode.isMap || true === fnode.isList) {
|
|
444
|
+
fnode = fnode.peg[part]
|
|
445
|
+
}
|
|
446
|
+
else {
|
|
447
|
+
break
|
|
448
|
+
}
|
|
449
|
+
if (null == fnode) {
|
|
450
|
+
break
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
if (null != fnode && pI === refpath.length) {
|
|
454
|
+
node = fnode
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
nopath = true
|
|
458
|
+
}
|
|
459
|
+
}
|
|
409
460
|
|
|
410
461
|
if (nopath) {
|
|
411
462
|
out = makeNilErr(ctx, 'no_path', this)
|
|
@@ -424,6 +475,53 @@ class RefVal extends FeatureVal {
|
|
|
424
475
|
this.detectRefCycle(ctx)) {
|
|
425
476
|
out = makeNilErr(ctx, 'path_cycle', this)
|
|
426
477
|
}
|
|
478
|
+
// A PENDING MARK WRAPPER IS NOT YET A VALUE TO COPY (ADR-005).
|
|
479
|
+
// A type()/hide() call still waiting for its argument — an
|
|
480
|
+
// alias reference inside a type() body, a generator inside a
|
|
481
|
+
// hide() — would be cloned here as the CALL, and the clone
|
|
482
|
+
// then resolves at the REFERENCE's site, stamping marks that
|
|
483
|
+
// the mark-clearing walk below has already run too early to
|
|
484
|
+
// clear. That is how a type-marked alias silently suppressed
|
|
485
|
+
// the referring field's emission (use-cases/BUGS.md §12), how
|
|
486
|
+
// `hide(pack(...))` leaked its mark onto downstream packs
|
|
487
|
+
// (§11), and how hide() around a computed field swallowed the
|
|
488
|
+
// value into a silent [] (§35b). Defer instead: the reference
|
|
489
|
+
// residuates until the wrapper has resolved at its OWN field,
|
|
490
|
+
// and the ordinary marked-value path below then clears the
|
|
491
|
+
// marks on the clone as documented. The move() reference
|
|
492
|
+
// (`_hide_found`) is exempt: a move TRANSPLANTS the pending
|
|
493
|
+
// call, and the ghost rows (test/spec/func.tsv) pin that its
|
|
494
|
+
// innards resolve at the destination.
|
|
495
|
+
else if (null != out && !snap && !this.mark._hide_found &&
|
|
496
|
+
pendingMarkWrapper(out)) {
|
|
497
|
+
out = undefined
|
|
498
|
+
}
|
|
499
|
+
// A STAGED ARGUMENT SNAPSHOTS A SETTLED SOURCE (the argsnap
|
|
500
|
+
// flag, set by driveStagedArgs). A generator's data argument is
|
|
501
|
+
// a copy OUTSIDE the tree, so anything in the target that still
|
|
502
|
+
// resolves against its own tree location — a spread-injected
|
|
503
|
+
// relative reference, a pending template — must finish there
|
|
504
|
+
// BEFORE the copy is taken: cloned earlier, the copy's rebased
|
|
505
|
+
// relative refs dangle under the generator and the model dies
|
|
506
|
+
// as *_no_gen with the generator never firing. Deferring here
|
|
507
|
+
// is exactly the documented staging rule: the generator waits
|
|
508
|
+
// for the source, then snapshots it whole.
|
|
509
|
+
else if (null != out && !snap && true === (ctx as any).argsnap &&
|
|
510
|
+
!out.done) {
|
|
511
|
+
out = undefined
|
|
512
|
+
}
|
|
513
|
+
// A REFERENCE TO A RECURSIVE DEFINITION IS THE FIXPOINT
|
|
514
|
+
// REFERENCE (RECURSION.0.md): resolving it to a clone
|
|
515
|
+
// unrolled the schema one level, and every reparse of a
|
|
516
|
+
// canon then unrolled one more -- canon never converged. The
|
|
517
|
+
// residual is the resolved form, exactly as at the prefix
|
|
518
|
+
// positions inside the definition.
|
|
519
|
+
else if (null != out && !snap && containsRecurseOf(out, this.peg as any)) {
|
|
520
|
+
const rec: any = new RecurseVal({ target: [...this.peg] } as any, ctx)
|
|
521
|
+
rec.site = this.site
|
|
522
|
+
rec.path = [...this.path]
|
|
523
|
+
out = rec
|
|
524
|
+
}
|
|
427
525
|
// Types and hidden values are cloned and made concrete
|
|
428
526
|
else if (null != out) { // && (out.mark.type || out.mark.hide)) {
|
|
429
527
|
|
|
@@ -452,6 +550,12 @@ class RefVal extends FeatureVal {
|
|
|
452
550
|
walk(out, (_key: string | number | undefined, val: Val) => {
|
|
453
551
|
val.mark.type = false
|
|
454
552
|
val.mark.hide = false
|
|
553
|
+
// THE LINK IS NOT CLEARED (G4 phase 3): a link says what a
|
|
554
|
+
// value POINTS AT, and a copy of a link points at the same
|
|
555
|
+
// thing. An ABSOLUTE address still names the same node from
|
|
556
|
+
// the copy; a RELATIVE one is read from the copy's own
|
|
557
|
+
// position, which is what makes a referenced model resolve
|
|
558
|
+
// its internal links inside the copy (ADR-014).
|
|
455
559
|
return val
|
|
456
560
|
})
|
|
457
561
|
//}
|
|
@@ -636,5 +740,6 @@ class RefVal extends FeatureVal {
|
|
|
636
740
|
|
|
637
741
|
|
|
638
742
|
export {
|
|
743
|
+
pendingMarkWrapper,
|
|
639
744
|
RefVal,
|
|
640
745
|
}
|