aontu 0.52.0 → 0.53.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 +14 -3
- package/dist/aontu.js +145 -4
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +44 -1
- package/dist/cli.js +2401 -44
- package/dist/cli.js.map +1 -1
- package/dist/ctx.d.ts +16 -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 +48 -8
- package/dist/err.js.map +1 -1
- package/dist/graph.d.ts +16 -0
- package/dist/graph.js +73 -0
- package/dist/graph.js.map +1 -0
- package/dist/hcanon.d.ts +3 -0
- package/dist/hcanon.js +146 -0
- package/dist/hcanon.js.map +1 -0
- package/dist/hints.js +223 -5
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.d.ts +20 -0
- package/dist/jsonschema.js +391 -0
- package/dist/jsonschema.js.map +1 -0
- package/dist/lang.js +698 -35
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +9 -2
- package/dist/lsp.js +262 -46
- 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 +814 -0
- package/dist/mcp.js.map +1 -0
- package/dist/mod-tool.d.ts +58 -0
- package/dist/mod-tool.js +498 -0
- package/dist/mod-tool.js.map +1 -0
- package/dist/mod.d.ts +31 -0
- package/dist/mod.js +250 -0
- package/dist/mod.js.map +1 -0
- package/dist/patch.d.ts +44 -0
- package/dist/patch.js +506 -0
- package/dist/patch.js.map +1 -0
- package/dist/provenance.d.ts +40 -0
- package/dist/provenance.js +335 -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 +14 -0
- package/dist/reach.js +140 -0
- package/dist/reach.js.map +1 -0
- package/dist/relation.d.ts +19 -0
- package/dist/relation.js +305 -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/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 +73 -0
- package/dist/std.js.map +1 -0
- package/dist/subsume.d.ts +39 -0
- package/dist/subsume.js +526 -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 +3 -1
- package/dist/unify.js +287 -18
- package/dist/unify.js.map +1 -1
- package/dist/utility.d.ts +9 -1
- package/dist/utility.js +122 -1
- package/dist/utility.js.map +1 -1
- package/dist/val/AggFuncVal.d.ts +33 -0
- package/dist/val/AggFuncVal.js +202 -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 +5 -0
- package/dist/val/BagVal.js +96 -5
- 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 +48 -1
- package/dist/val/ConstraintVal.js +1501 -110
- package/dist/val/ConstraintVal.js.map +1 -1
- package/dist/val/CopyFuncVal.d.ts +1 -2
- package/dist/val/CopyFuncVal.js +7 -0
- 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.js +130 -21
- 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.d.ts +1 -0
- package/dist/val/ExpectVal.js +41 -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 +6 -1
- package/dist/val/FuncBaseVal.js +178 -2
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/HideFuncVal.js.map +1 -1
- package/dist/val/IdFuncVal.d.ts +13 -0
- package/dist/val/IdFuncVal.js +54 -0
- package/dist/val/IdFuncVal.js.map +1 -0
- package/dist/val/JunctionVal.js +7 -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 +117 -17
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.js +102 -8
- 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 +24 -2
- 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.js.map +1 -1
- 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.js +11 -2
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefFuncVal.js.map +1 -1
- package/dist/val/PrefVal.d.ts +2 -2
- package/dist/val/PrefVal.js +78 -23
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RefVal.d.ts +1 -1
- package/dist/val/RefVal.js +158 -30
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.d.ts +36 -0
- package/dist/val/ReferFuncVal.js +303 -0
- package/dist/val/ReferFuncVal.js.map +1 -0
- package/dist/val/ScalarKindVal.d.ts +1 -2
- package/dist/val/ScalarKindVal.js +0 -11
- package/dist/val/ScalarKindVal.js.map +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 +9 -2
- package/dist/val/Val.js +150 -4
- 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 +170 -0
- package/dist/val/arith.js.map +1 -0
- package/dist/vet.d.ts +45 -0
- package/dist/vet.js +776 -0
- package/dist/vet.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 +130 -0
- package/grammar/aontu.lark +113 -0
- package/package.json +30 -15
- package/skill/SKILL.md +37 -0
- package/skill/error-codes.md +62 -0
- package/skill/examples.md +99 -0
- package/skill/grammar-card.md +57 -0
- package/src/agentsmd.ts +135 -0
- package/src/aontu.ts +192 -4
- package/src/cli.ts +2858 -71
- package/src/ctx.ts +81 -0
- package/src/diff.ts +196 -0
- package/src/err.ts +52 -8
- package/src/graph.ts +135 -0
- package/src/hcanon.ts +169 -0
- package/src/hints.ts +271 -5
- package/src/jsonschema.ts +511 -0
- package/src/lang.ts +779 -37
- package/src/lsp.ts +281 -47
- package/src/mcp-server.ts +187 -0
- package/src/mcp.ts +993 -0
- package/src/mod-tool.ts +679 -0
- package/src/mod.ts +344 -0
- package/src/patch.ts +624 -0
- package/src/provenance.ts +430 -0
- package/src/query.ts +379 -0
- package/src/reach.ts +184 -0
- package/src/relation.ts +395 -0
- package/src/report-sarif.ts +137 -0
- package/src/site.ts +36 -1
- package/src/std.ts +73 -0
- package/src/subsume.ts +690 -0
- package/src/trim.ts +195 -0
- package/src/tsconfig.json +10 -4
- package/src/type.ts +51 -2
- package/src/unify.ts +311 -16
- package/src/utility.ts +139 -1
- package/src/val/AggFuncVal.ts +319 -0
- package/src/val/ArithFuncVal.ts +108 -0
- package/src/val/BagVal.ts +101 -4
- package/src/val/CloseFuncVal.ts +9 -1
- package/src/val/ConjunctVal.ts +20 -0
- package/src/val/ConstraintVal.ts +1699 -116
- package/src/val/CopyFuncVal.ts +7 -1
- package/src/val/Decimal.ts +15 -0
- package/src/val/DeprecateFuncVal.ts +84 -0
- package/src/val/DisjunctVal.ts +139 -28
- package/src/val/EachFuncVal.ts +133 -0
- package/src/val/ExpectVal.ts +43 -6
- package/src/val/FeatureVal.ts +1 -1
- package/src/val/FilterFuncVal.ts +154 -0
- package/src/val/FuncBaseVal.ts +200 -3
- package/src/val/HideFuncVal.ts +0 -2
- package/src/val/IdFuncVal.ts +91 -0
- package/src/val/JunctionVal.ts +7 -1
- package/src/val/KeyFuncVal.ts +39 -35
- package/src/val/ListVal.ts +125 -18
- package/src/val/LowerFuncVal.ts +0 -1
- package/src/val/MapVal.ts +110 -8
- 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 +26 -3
- package/src/val/OpenFuncVal.ts +4 -2
- package/src/val/PackFuncVal.ts +175 -0
- package/src/val/PathFuncVal.ts +0 -1
- package/src/val/PlaceVal.ts +193 -0
- package/src/val/PlusOpVal.ts +11 -2
- package/src/val/PrefFuncVal.ts +0 -1
- package/src/val/PrefVal.ts +79 -36
- package/src/val/RefVal.ts +163 -30
- package/src/val/ReferFuncVal.ts +387 -0
- package/src/val/ScalarKindVal.ts +0 -13
- package/src/val/TopVal.ts +0 -1
- package/src/val/TypeFuncVal.ts +0 -2
- package/src/val/UpperFuncVal.ts +0 -1
- package/src/val/Val.ts +213 -3
- package/src/val/VarVal.ts +0 -1
- package/src/val/arith.ts +316 -0
- package/src/vet.ts +992 -0
- package/src/walk.ts +99 -0
package/src/val/OpBaseVal.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
} from '../err'
|
|
18
18
|
|
|
19
19
|
import { AontuContext } from '../ctx'
|
|
20
|
-
import { unite } from '../unify'
|
|
20
|
+
import { unite, withDepth } from '../unify'
|
|
21
21
|
|
|
22
22
|
import {
|
|
23
23
|
explainOpen,
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
|
|
32
32
|
import { ConjunctVal } from './ConjunctVal'
|
|
33
33
|
import { FeatureVal } from './FeatureVal'
|
|
34
|
+
import { hasPlace, fillPlace } from './PlaceVal'
|
|
34
35
|
|
|
35
36
|
|
|
36
37
|
|
|
@@ -66,6 +67,17 @@ class OpBaseVal extends FeatureVal {
|
|
|
66
67
|
|
|
67
68
|
|
|
68
69
|
unify(peer: Val, ctx: AontuContext): Val {
|
|
70
|
+
|
|
71
|
+
// THE PLACEHOLDER (G8 phase 3, see PlaceVal), on the operator side:
|
|
72
|
+
// `x: {&: {m: _ + 2}}` meeting `1` is `3`. Same rule as
|
|
73
|
+
// FuncBaseVal's -- the peer fills the hole and the operation is
|
|
74
|
+
// what answers.
|
|
75
|
+
if (!peer.isTop && !peer.isNil && this.id !== peer.id && hasPlace(this)) {
|
|
76
|
+
if (hasPlace(peer)) {
|
|
77
|
+
return makeNilErr(ctx, 'place_pair', this, peer)
|
|
78
|
+
}
|
|
79
|
+
return fillPlace(this, peer, ctx).unify(top(), ctx)
|
|
80
|
+
}
|
|
69
81
|
const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Op:' + this.opname(), this, peer)
|
|
70
82
|
// Declared without an initial value: every arm below assigns it, and
|
|
71
83
|
// seeding it with `this` made the two arms that stand the op read as
|
|
@@ -83,7 +95,11 @@ class OpBaseVal extends FeatureVal {
|
|
|
83
95
|
|
|
84
96
|
for (let arg of this.peg) {
|
|
85
97
|
if (!arg.done) {
|
|
86
|
-
|
|
98
|
+
// Charged to the depth budget: this recurses without going
|
|
99
|
+
// through `unite`, so the counter would otherwise stay flat
|
|
100
|
+
// while the stack grows (see withDepth in unify.ts).
|
|
101
|
+
const a = arg
|
|
102
|
+
arg = withDepth(ctx, a, top(), () => a.unify(top(), ctx, ec(te, 'ARG')))
|
|
87
103
|
}
|
|
88
104
|
pegdone &&= arg.done
|
|
89
105
|
newpeg.push(arg)
|
|
@@ -161,10 +177,17 @@ class OpBaseVal extends FeatureVal {
|
|
|
161
177
|
}
|
|
162
178
|
|
|
163
179
|
|
|
164
|
-
clone(ctx: AontuContext,
|
|
180
|
+
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
165
181
|
let out = (super.clone(ctx, {
|
|
166
182
|
peg: this.peg,
|
|
167
183
|
}) as OpBaseVal)
|
|
184
|
+
// THE PER-DESTINATION INSTANTIATION RULE (ADR-005): an operation
|
|
185
|
+
// inside a template clones its operands as instances — the
|
|
186
|
+
// default clone shares them (see FuncBaseVal.clone). Every
|
|
187
|
+
// operand is a Val by construction, as in the Go twin's []Val.
|
|
188
|
+
if (true === spec?.dup) {
|
|
189
|
+
out.peg = this.peg.map((a: Val) => a.clone(ctx, { dup: true }))
|
|
190
|
+
}
|
|
168
191
|
return out
|
|
169
192
|
}
|
|
170
193
|
|
package/src/val/OpenFuncVal.ts
CHANGED
|
@@ -14,7 +14,6 @@ import { makeNilErr } from '../err'
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
import { FuncBaseVal } from './FuncBaseVal'
|
|
17
|
-
import { NilVal } from '../val/NilVal'
|
|
18
17
|
import { BagVal } from '../val/BagVal'
|
|
19
18
|
|
|
20
19
|
|
|
@@ -39,13 +38,16 @@ class OpenFuncVal extends FuncBaseVal {
|
|
|
39
38
|
|
|
40
39
|
|
|
41
40
|
resolve(ctx: AontuContext | undefined, args: Val[]) {
|
|
42
|
-
|
|
41
|
+
let argval: any = args[0]
|
|
43
42
|
|
|
44
43
|
if (null == argval) {
|
|
45
44
|
return makeNilErr(ctx, 'no_first_arg', this, undefined, 'close')
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
if (argval.isMap || argval.isList) {
|
|
48
|
+
// In place, for the reason CloseFuncVal.resolve gives: the
|
|
49
|
+
// instantiation rule (ADR-005) makes the argument this call's
|
|
50
|
+
// own wherever the call is multiplied.
|
|
49
51
|
(argval as BagVal).closed = false
|
|
50
52
|
}
|
|
51
53
|
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
// GENERATION: `pack(data, tmpl)` (G8 phase 1,
|
|
4
|
+
// docs/capability-review/g8-generation.md). One child of the result map
|
|
5
|
+
// per child of `data`, each of them `tmpl` cloned at the destination.
|
|
6
|
+
//
|
|
7
|
+
// names: [web, auth, billing]
|
|
8
|
+
// deploy: pack($.names, {
|
|
9
|
+
// image: "acme/" + key() + ":1.4.2"
|
|
10
|
+
// replicas: *2 | integer
|
|
11
|
+
// })
|
|
12
|
+
//
|
|
13
|
+
// WHY A FUNCTION AND NOT SYNTAX. A comprehension would need keywords,
|
|
14
|
+
// a scoping rule, and string interpolation for the computed name; the
|
|
15
|
+
// language already has functions, spread templates, and `key()`, and
|
|
16
|
+
// `pack` is those three composed. A call is also DATA -- a named node
|
|
17
|
+
// in the tree -- so a document that generates stays as analysable as
|
|
18
|
+
// one that does not.
|
|
19
|
+
//
|
|
20
|
+
// KEYS ARE DATA, NOT POSITION. For a list, the strings themselves are
|
|
21
|
+
// the keys (a non-string element is refused: `pack_key`); for a map,
|
|
22
|
+
// its keys. Terraform's `count` keyed by index is the counter-example
|
|
23
|
+
// the review names: reordering the data churns every downstream child.
|
|
24
|
+
// Duplicate keys are not an error -- the colliding children unify,
|
|
25
|
+
// exactly as duplicate source keys already merge.
|
|
26
|
+
//
|
|
27
|
+
// TOTALITY. `pack` iterates a finite, settled bag and cannot call
|
|
28
|
+
// itself: the number of children it can produce is fixed by data that
|
|
29
|
+
// already exists. Nothing here can recurse, which is the guarantee the
|
|
30
|
+
// combinators exist to keep.
|
|
31
|
+
|
|
32
|
+
import type {
|
|
33
|
+
Val,
|
|
34
|
+
ValSpec,
|
|
35
|
+
} from '../type'
|
|
36
|
+
|
|
37
|
+
import {
|
|
38
|
+
AontuContext,
|
|
39
|
+
} from '../ctx'
|
|
40
|
+
|
|
41
|
+
import { unite } from '../unify'
|
|
42
|
+
import { makeNilErr } from '../err'
|
|
43
|
+
import { MapVal } from './MapVal'
|
|
44
|
+
import { FuncBaseVal } from './FuncBaseVal'
|
|
45
|
+
import { repathInstance } from './Val'
|
|
46
|
+
import { fillPlace } from './PlaceVal'
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// The keys a data bag names, in the order the result must carry them,
|
|
50
|
+
// or a code naming what is wrong with it. Shared with `each`, which
|
|
51
|
+
// asks the same question of the same argument and answers it with the
|
|
52
|
+
// values rather than the keys.
|
|
53
|
+
function dataKeys(data: Val | undefined): string[] | string {
|
|
54
|
+
const d: any = data
|
|
55
|
+
|
|
56
|
+
if (true === d?.isMap) {
|
|
57
|
+
return Object.keys(d.peg)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (true === d?.isList) {
|
|
61
|
+
const out: string[] = []
|
|
62
|
+
for (const el of d.peg as Val[]) {
|
|
63
|
+
const e: any = el
|
|
64
|
+
// A key is a NAME, and only a string is one. A number would
|
|
65
|
+
// key by position under another spelling, which is the failure
|
|
66
|
+
// mode the data-keyed rule exists to refuse.
|
|
67
|
+
if (true !== e?.isScalar || 'string' !== typeof e.peg) {
|
|
68
|
+
return 'pack_key'
|
|
69
|
+
}
|
|
70
|
+
out.push(e.peg)
|
|
71
|
+
}
|
|
72
|
+
return out
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return 'pack_data'
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class PackFuncVal extends FuncBaseVal {
|
|
80
|
+
isPackFunc = true
|
|
81
|
+
|
|
82
|
+
// THE STAGING RULE (G8 phase 0, see AontuContext.settle). A
|
|
83
|
+
// generator's data argument is not settled merely by being `done`
|
|
84
|
+
// once: a sibling conjunct, an include or a spread can still merge
|
|
85
|
+
// keys into it, and children generated from the half-merged bag
|
|
86
|
+
// would be missing. It fires on the settle pass and only then.
|
|
87
|
+
staged = true
|
|
88
|
+
|
|
89
|
+
constructor(
|
|
90
|
+
spec: ValSpec,
|
|
91
|
+
ctx?: AontuContext
|
|
92
|
+
) {
|
|
93
|
+
super(spec, ctx)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
funcname() {
|
|
99
|
+
return 'pack'
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
// The TEMPLATE IS NOT AN ARGUMENT TO DRIVE. Driving it would resolve
|
|
104
|
+
// its `key()` at the CALL SITE -- the one position the template is
|
|
105
|
+
// never used at -- and freeze whatever else in it is path-dependent
|
|
106
|
+
// there too. The data argument is driven by `unify` below instead,
|
|
107
|
+
// one argument by hand rather than all of them by the base.
|
|
108
|
+
prepare(_ctx: AontuContext, _args: Val[]) {
|
|
109
|
+
return null
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
unify(peer: Val, ctx: AontuContext): Val {
|
|
114
|
+
// ONE argument is driven: the data. The template is not (see
|
|
115
|
+
// prepare above), and driveStagedArgs answers whether the data has
|
|
116
|
+
// settled -- the other half of "ready to fire".
|
|
117
|
+
const ready = this.driveStagedArgs(ctx, 1)
|
|
118
|
+
|
|
119
|
+
if (!ready || !ctx.settle) {
|
|
120
|
+
return this.residuate(peer, ctx)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return super.unify(peer, ctx)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
resolve(ctx: AontuContext, args: Val[]) {
|
|
128
|
+
const keys = dataKeys(args?.[0])
|
|
129
|
+
if ('string' === typeof keys) {
|
|
130
|
+
return makeNilErr(ctx, keys, this)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Arity is checked at parse (funcArity), so both arguments are here.
|
|
134
|
+
const tmpl: Val = args[1]
|
|
135
|
+
const peg: Record<string, Val> = {}
|
|
136
|
+
|
|
137
|
+
const src: any = args[0]
|
|
138
|
+
|
|
139
|
+
for (const key of keys) {
|
|
140
|
+
const keyctx = ctx.descend(key)
|
|
141
|
+
// THE PLACEHOLDER BINDS THE SOURCE CHILD (G8 phase 3): inside a
|
|
142
|
+
// generator's template `_` is the datum this child is being made
|
|
143
|
+
// FROM. For a map that is the child's value; for a list of names
|
|
144
|
+
// it is the name, which is also the key -- so `_` and `key()`
|
|
145
|
+
// agree there, and differ the moment the data is a map.
|
|
146
|
+
const source: Val = true === src?.isMap ? src.peg[key] : src.peg[keys.indexOf(key)]
|
|
147
|
+
// CLONED, never shared. A spread may share a template that holds
|
|
148
|
+
// nothing path-dependent (MapVal.spreadClone), because a spread
|
|
149
|
+
// CONSTRAINS a child that exists; a generator's template IS the
|
|
150
|
+
// child, and a child is a position. Sharing left every generated
|
|
151
|
+
// child pointing at the template's own parse-time location, which
|
|
152
|
+
// is the position the template is never used at -- visible as the
|
|
153
|
+
// site an error inside a generated child reports.
|
|
154
|
+
//
|
|
155
|
+
// A FULL INSTANCE, to the leaves (`dup`, ADR-005): a bare clone
|
|
156
|
+
// shares the inner structure of any call, preference or
|
|
157
|
+
// operation in the template, so the first child's resolution of
|
|
158
|
+
// a shared key()/ref answered for every child (BUGS.md §8, §9).
|
|
159
|
+
const inst = tmpl.clone(keyctx, { dup: true })
|
|
160
|
+
repathInstance(inst, inst.path)
|
|
161
|
+
const child = fillPlace(inst, source, keyctx)
|
|
162
|
+
peg[key] = undefined === peg[key] ? child :
|
|
163
|
+
unite(keyctx, peg[key], child, 'pack')
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return new MapVal({ peg }, ctx)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
} /* node:coverage ignore next 7 */
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
export {
|
|
173
|
+
dataKeys,
|
|
174
|
+
PackFuncVal,
|
|
175
|
+
}
|
package/src/val/PathFuncVal.ts
CHANGED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
|
|
3
|
+
// THE PLACEHOLDER `_` (G8 phase 3,
|
|
4
|
+
// docs/capability-review/g8-generation.md): a HOLE in a call, filled
|
|
5
|
+
// by whatever the call is unified with.
|
|
6
|
+
//
|
|
7
|
+
// x: {&: {m: _ + 2}} x: a: m: 1 -> a: m: 3
|
|
8
|
+
// greeting: upper(_) & hello -> "HELLO"
|
|
9
|
+
//
|
|
10
|
+
// WHY A HOLE AND NOT A FUNCTION PARAMETER. Aontu has no user-defined
|
|
11
|
+
// functions and will not get them (G8's Boundary): a function value
|
|
12
|
+
// crossing into the data plane is the step that makes a configuration
|
|
13
|
+
// language a programming language. A hole is not a parameter -- it
|
|
14
|
+
// cannot be named, passed, or partially applied. It says only "the
|
|
15
|
+
// value that arrives here", which is what a template needs to compute
|
|
16
|
+
// from the value it lands on.
|
|
17
|
+
//
|
|
18
|
+
// ALONE, `_` IS TOP WITH A MARK: it admits everything and is filled by
|
|
19
|
+
// its peer, exactly as TOP is dropped by one. What makes it different
|
|
20
|
+
// is that a CALL can see it, and a call that holds one waits for a
|
|
21
|
+
// peer to fill it instead of resolving around it. Unfilled at
|
|
22
|
+
// generation it is an error, as TOP is -- a hole is not a value.
|
|
23
|
+
|
|
24
|
+
import type {
|
|
25
|
+
Val,
|
|
26
|
+
ValSpec,
|
|
27
|
+
} from '../type'
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
AontuContext,
|
|
31
|
+
} from '../ctx'
|
|
32
|
+
|
|
33
|
+
import { Val as ValBase } from './Val'
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class PlaceVal extends ValBase {
|
|
37
|
+
isPlace = true
|
|
38
|
+
|
|
39
|
+
constructor(
|
|
40
|
+
spec: ValSpec,
|
|
41
|
+
ctx?: AontuContext
|
|
42
|
+
) {
|
|
43
|
+
super(spec, ctx)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
unify(peer: Val, _ctx: AontuContext): Val {
|
|
48
|
+
// The peer FILLS the hole. Against TOP there is nothing to fill it
|
|
49
|
+
// with, so it waits -- and waiting is not done, or a call holding
|
|
50
|
+
// it would resolve around it.
|
|
51
|
+
if (peer.isTop) {
|
|
52
|
+
this.notdone()
|
|
53
|
+
return this
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return peer
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
get canon() {
|
|
61
|
+
return '_'
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
// A hole admits everything, so nothing sits above it -- the same
|
|
66
|
+
// answer TOP gives, for the same reason.
|
|
67
|
+
superior(): Val {
|
|
68
|
+
return this
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
// A HOLE BELONGS TO ITS NEAREST ENCLOSING GENERATOR. A `_` inside a
|
|
76
|
+
// generator's template (pack/each, arg 1) or condition (filter, arg 1)
|
|
77
|
+
// is that generator's to bind — "_ is the source child" — so neither
|
|
78
|
+
// the hole test nor the fill walk may cross into those arguments from
|
|
79
|
+
// outside. Before this boundary, `close(pack(d, _ & t))` reported a
|
|
80
|
+
// hole to the OUTER call, so an ordinary overlay statement was
|
|
81
|
+
// absorbed into the template instead of merging with the generated
|
|
82
|
+
// child (use-cases/BUGS.md §10), and an outer pack's fill pass
|
|
83
|
+
// captured a NESTED pack's hole lexically, binding it to the outer
|
|
84
|
+
// source (§34). The data argument (arg 0) is not a binding position,
|
|
85
|
+
// so it stays visible: a hole there is an outer hole as before.
|
|
86
|
+
function boundArgStart(v: any): number {
|
|
87
|
+
return true === v.isPackFunc || true === v.isEachFunc ||
|
|
88
|
+
true === v.isFilterFunc ? 1 : Infinity
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
// Does this value CONTAIN a hole? Asked of a call before it resolves:
|
|
93
|
+
// a call holding one must wait for a peer to fill it. Holes inside a
|
|
94
|
+
// generator's own binding arguments are NOT this value's holes — see
|
|
95
|
+
// boundArgStart above.
|
|
96
|
+
function hasPlace(v: Val): boolean {
|
|
97
|
+
if (true === (v as any).isPlace) {
|
|
98
|
+
return true
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const peg: any = (v as any).peg
|
|
102
|
+
const bound = boundArgStart(v)
|
|
103
|
+
|
|
104
|
+
if (Array.isArray(peg)) {
|
|
105
|
+
for (let cI = 0; cI < peg.length && cI < bound; cI++) {
|
|
106
|
+
const c = peg[cI]
|
|
107
|
+
if (true === c?.isVal && hasPlace(c)) {
|
|
108
|
+
return true
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else if (true === peg?.isVal) {
|
|
113
|
+
return hasPlace(peg)
|
|
114
|
+
}
|
|
115
|
+
else if (null != peg && 'object' === typeof peg) {
|
|
116
|
+
for (const k of Object.keys(peg)) {
|
|
117
|
+
if (true === peg[k]?.isVal && hasPlace(peg[k])) {
|
|
118
|
+
return true
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return false
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
// The same tree with every hole filled by `fill`. Answers the value
|
|
128
|
+
// UNCHANGED when it holds no hole, so a caller can test identity to
|
|
129
|
+
// know whether anything was filled -- and so a tree with no hole is
|
|
130
|
+
// never needlessly cloned. A nested generator's binding arguments are
|
|
131
|
+
// left untouched (boundArgStart): those holes are the inner
|
|
132
|
+
// generator's to fill with its OWN source children when it fires.
|
|
133
|
+
function fillPlace(v: Val, fill: Val, ctx: AontuContext): Val {
|
|
134
|
+
if (true === (v as any).isPlace) {
|
|
135
|
+
return fill
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const peg: any = (v as any).peg
|
|
139
|
+
const bound = boundArgStart(v)
|
|
140
|
+
|
|
141
|
+
if (Array.isArray(peg)) {
|
|
142
|
+
let changed = false
|
|
143
|
+
const out = peg.map((c: any, cI: number) => {
|
|
144
|
+
if (true !== c?.isVal || bound <= cI) {
|
|
145
|
+
return c
|
|
146
|
+
}
|
|
147
|
+
const f = fillPlace(c, fill, ctx)
|
|
148
|
+
changed = changed || f !== c
|
|
149
|
+
return f
|
|
150
|
+
})
|
|
151
|
+
return changed ? rebuild(v, out, ctx) : v
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (true === peg?.isVal) {
|
|
155
|
+
const f = fillPlace(peg, fill, ctx)
|
|
156
|
+
return f === peg ? v : rebuild(v, f, ctx)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (null != peg && 'object' === typeof peg) {
|
|
160
|
+
let changed = false
|
|
161
|
+
const out: Record<string, Val> = {}
|
|
162
|
+
for (const k of Object.keys(peg)) {
|
|
163
|
+
const c = peg[k]
|
|
164
|
+
// No isVal guard: a slot holding something that is not a Val
|
|
165
|
+
// answers itself, because fillPlace's own first tests -- is it a
|
|
166
|
+
// hole, has it a peg -- are both false for one.
|
|
167
|
+
const f = fillPlace(c, fill, ctx)
|
|
168
|
+
changed = changed || f !== c
|
|
169
|
+
out[k] = f
|
|
170
|
+
}
|
|
171
|
+
return changed ? rebuild(v, out, ctx) : v
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return v
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
// A clone carrying a new peg. `clone` shares the peg by reference (see
|
|
179
|
+
// Val.clone), which is exactly what must NOT happen here: the tree
|
|
180
|
+
// being filled is a template, and the fill is one destination's.
|
|
181
|
+
function rebuild(v: Val, peg: any, ctx: AontuContext): Val {
|
|
182
|
+
const out: any = v.clone(ctx)
|
|
183
|
+
out.peg = peg
|
|
184
|
+
out.dc = 0
|
|
185
|
+
return out
|
|
186
|
+
} /* node:coverage ignore next 8 */
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
export {
|
|
190
|
+
hasPlace,
|
|
191
|
+
fillPlace,
|
|
192
|
+
PlaceVal,
|
|
193
|
+
}
|
package/src/val/PlusOpVal.ts
CHANGED
|
@@ -157,9 +157,18 @@ class PlusOpVal extends OpBaseVal {
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
// Float with float or integer: unchanged R5 contagion, binary64
|
|
160
|
-
// addition, float result (`1 + 2.0` is `3.0`)
|
|
160
|
+
// addition, float result (`1 + 2.0` is `3.0`) -- but a sum that
|
|
161
|
+
// leaves binary64's finite range is NOT a value. Aontu is a JSON
|
|
162
|
+
// superset and there is no notation for an infinity, so one here
|
|
163
|
+
// used to escape as `[aontu/internal]` in TypeScript and as Go's
|
|
164
|
+
// raw `json: unsupported value: +Inf` with no code at all
|
|
165
|
+
// (use-cases/BUGS.md 39). The same check governs the arithmetic
|
|
166
|
+
// family (float_overflow, ts/src/val/arith.ts).
|
|
161
167
|
if ('float' === ak || 'float' === bk) {
|
|
162
|
-
|
|
168
|
+
const sum = av.peg + bv.peg
|
|
169
|
+
return Number.isFinite(sum) ?
|
|
170
|
+
new NumberVal({ peg: sum }) :
|
|
171
|
+
makeNilErr(ctx, 'float_overflow', this, undefined, 'add')
|
|
163
172
|
}
|
|
164
173
|
|
|
165
174
|
// Both operands are on the exact ladder: promote to the widest.
|
package/src/val/PrefFuncVal.ts
CHANGED
package/src/val/PrefVal.ts
CHANGED
|
@@ -23,7 +23,20 @@ import {
|
|
|
23
23
|
import { top } from './top'
|
|
24
24
|
|
|
25
25
|
import { FeatureVal } from './FeatureVal'
|
|
26
|
-
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
// The innermost preferred value under every pref layer: the value a
|
|
29
|
+
// preference of ANY rank ultimately defends, and the one generation
|
|
30
|
+
// emits for it. Shared by the disjunct admission gate (DisjunctVal),
|
|
31
|
+
// the defaulted-scrutinee rule (MatchFuncVal) and the effective-default
|
|
32
|
+
// walk (subsume.ts) so "the default's value" cannot mean three things.
|
|
33
|
+
function prefInnerPeg(v: Val): Val {
|
|
34
|
+
let out: any = v
|
|
35
|
+
while (true === out?.isPref) {
|
|
36
|
+
out = out.peg
|
|
37
|
+
}
|
|
38
|
+
return out
|
|
39
|
+
}
|
|
27
40
|
|
|
28
41
|
|
|
29
42
|
class PrefVal extends FeatureVal {
|
|
@@ -37,19 +50,28 @@ class PrefVal extends FeatureVal {
|
|
|
37
50
|
// Both are assigned by resuper(), called from the constructor.
|
|
38
51
|
superpeg!: Val
|
|
39
52
|
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
// FAMILY: `*lower(1.1) & a` is a conflict, not an override.
|
|
53
|
+
// THE GATE AN OVERRIDING PEER MUST PASS IS `superpeg` ITSELF — the
|
|
54
|
+
// preferred value's own KIND, not its family.
|
|
43
55
|
//
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
56
|
+
// A preference is a DEFAULT, so a concrete peer replaces it, but only
|
|
57
|
+
// where the peer is the same kind of thing: `*lower(1.1) & a` is a
|
|
58
|
+
// conflict, not an override. The number tower made `integer` and
|
|
59
|
+
// `float` disjoint siblings under `number`, and this gate used to
|
|
60
|
+
// widen to that family — so `*2.2 & 3` worked, and so did
|
|
61
|
+
// `*8080 & 3.5`. Those are ONE rule in two directions; no kind-based
|
|
62
|
+
// gate can keep the first and refuse the second.
|
|
63
|
+
//
|
|
64
|
+
// Refusing both is the choice, because the second is the documented
|
|
65
|
+
// default idiom: `port: *8080 | integer` accepted 3.5 in both ports,
|
|
66
|
+
// silently widening every key written that way from integer to
|
|
67
|
+
// number — the finding §6 of the 2026-08-21 status report calls the
|
|
68
|
+
// most consequential, precisely because docs/skill/examples.md
|
|
69
|
+
// teaches the idiom to agents.
|
|
70
|
+
//
|
|
71
|
+
// What the tightening costs is named rather than hidden: mixing the
|
|
72
|
+
// numeric leaves around a preference is now an error instead of a
|
|
73
|
+
// silent widening. `*1.5 & integer` used to answer `integer` and
|
|
74
|
+
// DISCARD a default that could never apply; it now says so.
|
|
53
75
|
|
|
54
76
|
rank: number = 0
|
|
55
77
|
|
|
@@ -74,7 +96,21 @@ class PrefVal extends FeatureVal {
|
|
|
74
96
|
// Recompute the type yardstick and the override gate from the current
|
|
75
97
|
// peg. Called again whenever the peg resolves (e.g. a ref).
|
|
76
98
|
private resuper() {
|
|
77
|
-
|
|
99
|
+
// THE RANK-UNIFORM MEET (ADR-004). The yardstick is the INNERMOST
|
|
100
|
+
// preferred value's kind, whatever the preference's rank: `**1.5`
|
|
101
|
+
// defends `float` exactly as `*1.5` does. The old rule read the
|
|
102
|
+
// immediate peg, and a rank>=2 peg is itself a PrefVal whose
|
|
103
|
+
// superior is top -- so ANY conjunct overrode a ranked default
|
|
104
|
+
// (`**1.5 & float` dropped the default and died as mapval_no_gen;
|
|
105
|
+
// `**2|integer` met by a bare `integer` lost the default the
|
|
106
|
+
// spelling exists to carry -- use-cases/BUGS.md §3), while the
|
|
107
|
+
// rank-1 spelling of the same document kept it. One rule, every
|
|
108
|
+
// rank. Pinned by test/spec/pref.tsv (pref-rank2-* rows, and the
|
|
109
|
+
// flipped pref-nested-concrete-wins).
|
|
110
|
+
let peg: any = this.peg
|
|
111
|
+
while (true === peg?.isPref) {
|
|
112
|
+
peg = peg.peg
|
|
113
|
+
}
|
|
78
114
|
|
|
79
115
|
// A preference whose peg is ITSELF a kind (`*integer`) constrains
|
|
80
116
|
// nothing: there is no type-of-a-type in this lattice, so any peer
|
|
@@ -83,28 +119,13 @@ class PrefVal extends FeatureVal {
|
|
|
83
119
|
// now that a leaf kind lifts to `number`, it has to be said.)
|
|
84
120
|
if (true === peg.isScalarKind) {
|
|
85
121
|
this.superpeg = top()
|
|
86
|
-
this.familypeg = this.superpeg
|
|
87
122
|
return
|
|
88
123
|
}
|
|
89
124
|
|
|
90
|
-
const sup: any = peg.superior()
|
|
91
|
-
this.superpeg = sup
|
|
92
|
-
|
|
93
125
|
// No optional chain: superior() is contractually non-null (every
|
|
94
126
|
// Val returns one, a NilVal returning itself), so guarding against
|
|
95
127
|
// nullish here would claim a possibility the type does not have.
|
|
96
|
-
|
|
97
|
-
const family = kindFamily(sup.peg)
|
|
98
|
-
// The gate stands in for the preferred value in any conflict it
|
|
99
|
-
// reports, so it must carry the same site and path as the type it
|
|
100
|
-
// widens -- otherwise NilVal.make picks a different primary and
|
|
101
|
-
// the error moves to the wrong path.
|
|
102
|
-
this.familypeg = family === sup.peg ?
|
|
103
|
-
sup : sup.place(new ScalarKindVal({ peg: family, path: sup.path }))
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
this.familypeg = sup
|
|
107
|
-
}
|
|
128
|
+
this.superpeg = peg.superior()
|
|
108
129
|
}
|
|
109
130
|
|
|
110
131
|
|
|
@@ -163,13 +184,21 @@ class PrefVal extends FeatureVal {
|
|
|
163
184
|
why += 'super-'
|
|
164
185
|
|
|
165
186
|
out = unite(te ? ctx.clone({ explain: ec(te, 'SUPER') }) : ctx,
|
|
166
|
-
this.
|
|
187
|
+
this.superpeg, peer, 'pref-super/' + this.id)
|
|
167
188
|
|
|
168
189
|
// The peer added nothing beyond a type the preferred value already
|
|
169
190
|
// satisfies (`*1 & integer`, `*1 & number`), so the preference
|
|
170
|
-
// stands
|
|
171
|
-
|
|
172
|
-
|
|
191
|
+
// stands — as ITSELF, rank intact (ADR-004). Returning the peg
|
|
192
|
+
// here (the old rule) demoted the preference to a concrete value
|
|
193
|
+
// at rank 0 and to a lower rank above it, which both destroyed
|
|
194
|
+
// overridability (`*1 & integer` then `2` was a conflict) and
|
|
195
|
+
// broke the layered-defaults ladder: a team's `**debug|string`
|
|
196
|
+
// meeting an env's `string` branch produced a rank-0 `*debug`
|
|
197
|
+
// that then fought the env's own rank-0 `*warn` as an equal.
|
|
198
|
+
// Anything else is a concrete override and wins (subject to the
|
|
199
|
+
// disjunct admission gate in DisjunctVal).
|
|
200
|
+
if (out.same(this.superpeg)) {
|
|
201
|
+
out = this
|
|
173
202
|
why += 'same'
|
|
174
203
|
}
|
|
175
204
|
|
|
@@ -205,7 +234,20 @@ class PrefVal extends FeatureVal {
|
|
|
205
234
|
|
|
206
235
|
clone(ctx: AontuContext, spec?: ValSpec): Val {
|
|
207
236
|
let out = (super.clone(ctx, spec) as PrefVal)
|
|
208
|
-
//
|
|
237
|
+
// THE PER-DESTINATION INSTANTIATION RULE (ADR-005). The default
|
|
238
|
+
// clone shares the preferred value (`peg: this.peg` in Val.clone)
|
|
239
|
+
// — a cloned pref spread template resolves its inner value at the
|
|
240
|
+
// template's own location, pinned behaviour. But a template
|
|
241
|
+
// INSTANCE must own it: with the peg shared, a rank-2 default
|
|
242
|
+
// (`**key(1) | string`) in a pack template resolved its one
|
|
243
|
+
// shared inner key() at the first destination and every child got
|
|
244
|
+
// the first child's key (use-cases/BUGS.md §9 — rank 1 escaped
|
|
245
|
+
// only because its unify builds a fresh PrefVal per meet). The
|
|
246
|
+
// superpeg yardstick from the shared peg still holds: the clone's
|
|
247
|
+
// innermost value is the same kind.
|
|
248
|
+
if (true === spec?.dup && true === (this.peg as any)?.isVal) {
|
|
249
|
+
out.peg = this.peg.clone(ctx, { dup: true })
|
|
250
|
+
}
|
|
209
251
|
return out
|
|
210
252
|
}
|
|
211
253
|
|
|
@@ -227,9 +269,10 @@ class PrefVal extends FeatureVal {
|
|
|
227
269
|
|
|
228
270
|
return val.gen(ctx)
|
|
229
271
|
}
|
|
230
|
-
} /* node:coverage ignore next
|
|
272
|
+
} /* node:coverage ignore next 7 */
|
|
231
273
|
|
|
232
274
|
|
|
233
275
|
export {
|
|
234
276
|
PrefVal,
|
|
277
|
+
prefInnerPeg,
|
|
235
278
|
}
|