aontu 0.52.1 → 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 +96 -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 +13 -0
- package/dist/ctx.js +43 -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 +38 -7
- 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 +167 -4
- 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 +512 -69
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +9 -2
- package/dist/lsp.js +262 -47
- 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 +2 -1
- package/dist/unify.js +253 -36
- 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 +7 -1
- package/dist/val/ConstraintVal.js +490 -40
- 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.js +27 -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 +171 -1
- 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 +101 -14
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.js +93 -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 +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.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 +89 -7
- 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 +8 -1
- package/dist/val/Val.js +150 -1
- 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 +21 -6
- 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 +135 -4
- package/src/cli.ts +2858 -71
- package/src/ctx.ts +73 -1
- package/src/diff.ts +196 -0
- package/src/err.ts +42 -7
- package/src/graph.ts +135 -0
- package/src/hcanon.ts +169 -0
- package/src/hints.ts +208 -4
- package/src/jsonschema.ts +511 -0
- package/src/lang.ts +570 -70
- package/src/lsp.ts +281 -48
- 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 +274 -36
- 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 +542 -43
- 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 +28 -6
- package/src/val/FeatureVal.ts +1 -1
- package/src/val/FilterFuncVal.ts +154 -0
- package/src/val/FuncBaseVal.ts +192 -1
- 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 +108 -15
- package/src/val/LowerFuncVal.ts +0 -1
- package/src/val/MapVal.ts +99 -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 +20 -1
- 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 +91 -8
- 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 +205 -2
- 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/lang.ts
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
|
|
4
4
|
// import { performance } from 'node:perf_hooks'
|
|
5
5
|
|
|
6
|
+
// Named imports, not `import * as`: the namespace form makes tsc emit
|
|
7
|
+
// the __importStar downlevel helper, whose branches no supported Node
|
|
8
|
+
// takes (the same rule cli.ts records). Aliased because `Path` is
|
|
9
|
+
// already the @tabnas/path plugin below.
|
|
10
|
+
import { existsSync, readFileSync, realpathSync } from 'node:fs'
|
|
11
|
+
import {
|
|
12
|
+
basename as pathBasename,
|
|
13
|
+
dirname as pathDirname,
|
|
14
|
+
join as pathJoin,
|
|
15
|
+
resolve as pathResolve,
|
|
16
|
+
sep as pathSep,
|
|
17
|
+
} from 'node:path'
|
|
18
|
+
|
|
6
19
|
import {
|
|
7
20
|
Jsonic,
|
|
8
21
|
Tabnas,
|
|
@@ -34,6 +47,9 @@ import {
|
|
|
34
47
|
makeMemResolver
|
|
35
48
|
} from '@tabnas/multisource/resolver/mem'
|
|
36
49
|
|
|
50
|
+
import { STD_SOURCES } from './std'
|
|
51
|
+
import { parseModuleRef, resolveModule, modCacheDir } from './mod'
|
|
52
|
+
|
|
37
53
|
import {
|
|
38
54
|
Expr,
|
|
39
55
|
Op,
|
|
@@ -96,6 +112,20 @@ import { CopyFuncVal } from './val/CopyFuncVal'
|
|
|
96
112
|
import { KeyFuncVal } from './val/KeyFuncVal'
|
|
97
113
|
import { TypeFuncVal } from './val/TypeFuncVal'
|
|
98
114
|
import { HideFuncVal } from './val/HideFuncVal'
|
|
115
|
+
import { DeprecateFuncVal } from './val/DeprecateFuncVal'
|
|
116
|
+
import { IdFuncVal } from './val/IdFuncVal'
|
|
117
|
+
import { ReferFuncVal } from './val/ReferFuncVal'
|
|
118
|
+
import { PackFuncVal } from './val/PackFuncVal'
|
|
119
|
+
import { EachFuncVal } from './val/EachFuncVal'
|
|
120
|
+
import { FilterFuncVal } from './val/FilterFuncVal'
|
|
121
|
+
import { MatchFuncVal } from './val/MatchFuncVal'
|
|
122
|
+
import {
|
|
123
|
+
AddFuncVal, SubFuncVal, MulFuncVal, DivFuncVal, ModFuncVal, RemFuncVal,
|
|
124
|
+
} from './val/ArithFuncVal'
|
|
125
|
+
import {
|
|
126
|
+
SumFuncVal, LeastFuncVal, GreatestFuncVal, PickFuncVal,
|
|
127
|
+
} from './val/AggFuncVal'
|
|
128
|
+
import { PlaceVal } from './val/PlaceVal'
|
|
99
129
|
import { MoveFuncVal } from './val/MoveFuncVal'
|
|
100
130
|
import { PathFuncVal } from './val/PathFuncVal'
|
|
101
131
|
import { PrefFuncVal } from './val/PrefFuncVal'
|
|
@@ -287,6 +317,16 @@ let AontuJsonic: Plugin = function AontuLang(jsonic: Jsonic) {
|
|
|
287
317
|
v.site.row = null == r.o0 ? -1 : r.o0.rI
|
|
288
318
|
v.site.col = null == r.o0 ? -1 : r.o0.cI
|
|
289
319
|
v.site.url = ctx.meta.multisource ? ctx.meta.multisource.path : ''
|
|
320
|
+
// The source text, from the SAME token the row and column above
|
|
321
|
+
// come from. jsonic has carried it all along; not reading it is
|
|
322
|
+
// what left a site uneditable (ts/src/site.ts).
|
|
323
|
+
//
|
|
324
|
+
// A TOKEN WITH NO TEXT IS NO SPAN, in both ports, and the extent is
|
|
325
|
+
// DERIVED from the text rather than read from the token's own `len`
|
|
326
|
+
// — so the Go twin, whose token has no len field, computes the
|
|
327
|
+
// identical number with utf16Len and nothing has to be kept in step.
|
|
328
|
+
v.site.src = null == r.o0 ? '' : r.o0.src
|
|
329
|
+
v.site.len = '' === v.site.src ? -1 : v.site.src.length
|
|
290
330
|
// A keyed rule always carries a path array; a keyless one has none.
|
|
291
331
|
v.path = r.k ? [...r.k.path] : []
|
|
292
332
|
|
|
@@ -365,6 +405,14 @@ help isolate the syntax error.`,
|
|
|
365
405
|
|
|
366
406
|
// TODO: FIX: need a TOP instance to hold path
|
|
367
407
|
'top': { val: () => top() },
|
|
408
|
+
|
|
409
|
+
// G8 phase 3: the placeholder. A BARE `_` is the hole; `"_"`
|
|
410
|
+
// quoted, and any longer bare word containing it, stay text.
|
|
411
|
+
// Reserving it is a breaking change, pinned by place.tsv.
|
|
412
|
+
'_': {
|
|
413
|
+
val: (r: Rule, ctx: JsonicContext) =>
|
|
414
|
+
addsite(new PlaceVal({}), r, ctx)
|
|
415
|
+
},
|
|
368
416
|
}
|
|
369
417
|
},
|
|
370
418
|
|
|
@@ -441,6 +489,65 @@ help isolate the syntax error.`,
|
|
|
441
489
|
// reported with the author's own message, never simplified and
|
|
442
490
|
// never consulted for emptiness or subsumption.
|
|
443
491
|
must: MustConstraintVal,
|
|
492
|
+
|
|
493
|
+
// G3 phase 4: the deprecation mark. Unification-transparent; the
|
|
494
|
+
// record rides the result (Val.deprecation) and canon renders the
|
|
495
|
+
// call back (canonRiders).
|
|
496
|
+
deprecate: DeprecateFuncVal,
|
|
497
|
+
|
|
498
|
+
// G4 phase 1: the identity mark. Written as a conjunct
|
|
499
|
+
// (`id(svc/auth) & {…}`), it resolves to the unit carrying the
|
|
500
|
+
// name, and every node in one evaluation with that name is
|
|
501
|
+
// unified with every other.
|
|
502
|
+
id: IdFuncVal,
|
|
503
|
+
|
|
504
|
+
// G4 phase 2: the checked, typed, LINK-shaped reference. A
|
|
505
|
+
// constraint on a string field: the string must be an entity
|
|
506
|
+
// address, the address must resolve, and the optional argument
|
|
507
|
+
// flows INTO the target. The field keeps the string.
|
|
508
|
+
refer: ReferFuncVal,
|
|
509
|
+
|
|
510
|
+
// G8 phase 1: the generation combinators. `pack` makes one keyed
|
|
511
|
+
// child per child of its data, `each` one list element; both clone
|
|
512
|
+
// their template per destination exactly as a spread does, and both
|
|
513
|
+
// wait for the model to settle before they fire (the staging rule,
|
|
514
|
+
// G8 phase 0).
|
|
515
|
+
pack: PackFuncVal,
|
|
516
|
+
each: EachFuncVal,
|
|
517
|
+
|
|
518
|
+
// G8 phase 2: selection. `filter` keeps the children of a bag that
|
|
519
|
+
// unify with a condition; `match` picks the first arm whose
|
|
520
|
+
// pattern the scrutinee unifies with. Both select by
|
|
521
|
+
// UNIFIABILITY, tried in trial mode, so neither adds a predicate
|
|
522
|
+
// language to the one the lattice already is.
|
|
523
|
+
filter: FilterFuncVal,
|
|
524
|
+
match: MatchFuncVal,
|
|
525
|
+
|
|
526
|
+
// The arithmetic family (the review's finding I). Maths beyond `+`
|
|
527
|
+
// arrives as FUNCTIONS — `-` `*` `/` `%` stay reserved — and the
|
|
528
|
+
// family is numeric where the operator is polymorphic, which is
|
|
529
|
+
// what makes `add` more than a second spelling of `+`: it refuses
|
|
530
|
+
// the string concatenation that silently answers `"500m" + "500m"`.
|
|
531
|
+
// Every rule they obey is in ts/src/val/arith.ts.
|
|
532
|
+
add: AddFuncVal,
|
|
533
|
+
sub: SubFuncVal,
|
|
534
|
+
mul: MulFuncVal,
|
|
535
|
+
div: DivFuncVal,
|
|
536
|
+
mod: ModFuncVal,
|
|
537
|
+
rem: RemFuncVal,
|
|
538
|
+
|
|
539
|
+
// Aggregation over a finite, settled bag (the review's finding I).
|
|
540
|
+
// `least` and `greatest` rather than min and max, which are already
|
|
541
|
+
// the atoms for a lower and an upper BOUND -- an aggregate over a
|
|
542
|
+
// set and a bound on a value must not share a spelling.
|
|
543
|
+
sum: SumFuncVal,
|
|
544
|
+
least: LeastFuncVal,
|
|
545
|
+
greatest: GreatestFuncVal,
|
|
546
|
+
|
|
547
|
+
// Projection, which is what lets the aggregates reach a bag of
|
|
548
|
+
// RECORDS: `sum(pick($.lines, amountCents))`. Not a clever `each`
|
|
549
|
+
// template -- `each` MEETS each child, and a meet cannot select.
|
|
550
|
+
pick: PickFuncVal,
|
|
444
551
|
}
|
|
445
552
|
|
|
446
553
|
|
|
@@ -454,6 +561,117 @@ help isolate the syntax error.`,
|
|
|
454
561
|
const incompleteNil = (r: Rule, ctx: JsonicContext) =>
|
|
455
562
|
addsite(new NilVal({ why: 'incomplete_expression' }), r, ctx)
|
|
456
563
|
|
|
564
|
+
// Build a call from a NAME and the argument terms as the author
|
|
565
|
+
// wrote them. Shared by the `func(...)` handler and by the pipe,
|
|
566
|
+
// which is the same call with one more argument on the front — so
|
|
567
|
+
// the arity check, the comma-group rule and the raw-value conversion
|
|
568
|
+
// are stated once and both spellings get all three.
|
|
569
|
+
const buildCall = (r: Rule, ctx: JsonicContext,
|
|
570
|
+
fname: string, argterms: any[]): any => {
|
|
571
|
+
const funcval = funcMap[fname]
|
|
572
|
+
|
|
573
|
+
// Arity is known for every built-in, so a surplus or missing
|
|
574
|
+
// argument is a mistake in the SOURCE, refused here where the
|
|
575
|
+
// author can see it (issue #51). It was previously left to each
|
|
576
|
+
// function to notice or not: the two ports disagreed on `upper()`
|
|
577
|
+
// and on `close()`, and `min(1,2)` noticed nothing at all -- it
|
|
578
|
+
// built a constraint that merely refused to generate later, with a
|
|
579
|
+
// message about the map rather than about the call.
|
|
580
|
+
//
|
|
581
|
+
// Counted BEFORE the rawToVal pass below, which is what makes the
|
|
582
|
+
// count possible: a comma group arrives as a RAW array and a
|
|
583
|
+
// written list literal as a ListVal, and rawToVal turns the first
|
|
584
|
+
// into the second.
|
|
585
|
+
const arity = funcArity[fname]
|
|
586
|
+
if (null != arity) {
|
|
587
|
+
const got = writtenArgCount(argterms)
|
|
588
|
+
if (got < arity[0] || (-1 !== arity[1] && got > arity[1])) {
|
|
589
|
+
// details is assigned AFTER construction: the NilVal
|
|
590
|
+
// constructor does not read it from its spec (only NilVal.make
|
|
591
|
+
// does), so passing it in the spec left the hint's
|
|
592
|
+
// {func}/{want}/{got} placeholders un-injected and printed
|
|
593
|
+
// literally.
|
|
594
|
+
const nil: any = new NilVal({ why: 'func_arity' })
|
|
595
|
+
nil.details = {
|
|
596
|
+
func: fname,
|
|
597
|
+
want: arityText(arity[0], arity[1]),
|
|
598
|
+
got: '' + got,
|
|
599
|
+
}
|
|
600
|
+
// The CALL AS WRITTEN rides the refusal (G8 phase 4): a pipe
|
|
601
|
+
// rebuilds `x |> upper()` as `upper(x)`, and the arity it fails
|
|
602
|
+
// on here is the arity of a call one argument short of the one
|
|
603
|
+
// the author actually wrote.
|
|
604
|
+
nil._callname = fname
|
|
605
|
+
nil._callterms = argterms
|
|
606
|
+
return addsite(nil, r, ctx)
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// rawToVal EVERY argument. A degenerate expression can hand this
|
|
611
|
+
// handler raw parse values rather than Vals -- `pref(1-3)` arrives
|
|
612
|
+
// as the plain numbers 1 and -3 -- and a func's peg is unified
|
|
613
|
+
// element by element, so a raw one reached `arg.unify(...)` and
|
|
614
|
+
// threw. The unifier's catch-all turned that into an `internal`
|
|
615
|
+
// verdict: a crash reported as a unification result (issue #49).
|
|
616
|
+
// The Go port has always converted here (asVal in evaluate).
|
|
617
|
+
// A comma group is ONE raw-array term (see writtenArgCount).
|
|
618
|
+
// For a function whose arguments are distinct POSITIONS —
|
|
619
|
+
// deprecate's value and record, pack's and each's data and template
|
|
620
|
+
// — the group is expanded back into them here, while a written list
|
|
621
|
+
// literal, already a ListVal, stays one argument. The constraint
|
|
622
|
+
// atoms make the same move in their own constructor (atomArgs,
|
|
623
|
+
// ConstraintVal.ts), which is why they are not in this set:
|
|
624
|
+
// `neq(1,2)` is one argument LIST, not two positions, and expanding
|
|
625
|
+
// it here would take the list away from the code that reads it.
|
|
626
|
+
let terms = argterms
|
|
627
|
+
if (true === POSITIONAL_ARG_FUNCS[fname] && 1 === terms.length &&
|
|
628
|
+
Array.isArray(terms[0])) {
|
|
629
|
+
terms = terms[0]
|
|
630
|
+
}
|
|
631
|
+
const args = terms.map(rawToVal)
|
|
632
|
+
const val: any = null == funcval ?
|
|
633
|
+
new NilVal({ why: 'unknown_function' }) :
|
|
634
|
+
new funcval({ peg: args })
|
|
635
|
+
|
|
636
|
+
// The call as written, for the pipe to rebuild from. Parse-time
|
|
637
|
+
// only: nothing downstream reads it, and a clone does not carry it.
|
|
638
|
+
//
|
|
639
|
+
// NOT on a constraint atom that BUILT: an atom with its argument
|
|
640
|
+
// list complete is a residual, not a call waiting for a subject,
|
|
641
|
+
// and `1 |> neq(2,3)` is asking for `1 & neq(2,3)` -- which is
|
|
642
|
+
// what `&` is for. (An atom the arity check REFUSED still carries
|
|
643
|
+
// it, on the nil above: `1 |> min()` is `min(1)`, and that is a
|
|
644
|
+
// call waiting for a subject.) The Go port cannot rebuild a built
|
|
645
|
+
// atom at all -- its residual keeps no atom name -- so this is
|
|
646
|
+
// also what keeps the two ports answering the same thing.
|
|
647
|
+
if (true !== val.isConstraint) {
|
|
648
|
+
val._callname = fname
|
|
649
|
+
val._callterms = argterms
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
return val
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
// The argument terms `f(...)` would have been written with, had the
|
|
657
|
+
// piped value been written into it. A comma group is one raw-array
|
|
658
|
+
// term: for a POSITIONAL function the group is separate arguments,
|
|
659
|
+
// so the piped value joins them; for a constraint atom the group IS
|
|
660
|
+
// the argument list, so the piped value joins the list instead.
|
|
661
|
+
const pipeTerms = (call: any, val: any): any[] => {
|
|
662
|
+
const written: any[] = call._callterms
|
|
663
|
+
const group = 1 === written.length && Array.isArray(written[0]) ?
|
|
664
|
+
written[0] : written
|
|
665
|
+
|
|
666
|
+
if (0 === group.length) {
|
|
667
|
+
return [val]
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
return true === POSITIONAL_ARG_FUNCS[call._callname] ?
|
|
671
|
+
[val, ...group] : [[val, ...group]]
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
|
|
457
675
|
let opmap: any = {
|
|
458
676
|
'conjunct-infix': (r: Rule, ctx: JsonicContext, _op: Op, terms: any) =>
|
|
459
677
|
addsite(new ConjunctVal({ peg: dropUnfilled(terms) }), r, ctx),
|
|
@@ -533,55 +751,47 @@ help isolate the syntax error.`,
|
|
|
533
751
|
return addsite(val, r, ctx)
|
|
534
752
|
},
|
|
535
753
|
|
|
754
|
+
// THE PIPE `|>` (G8 phase 4): parse-time sugar and nothing else.
|
|
755
|
+
// `x |> f(a)` IS `f(x, a)` -- the piped value goes in as the FIRST
|
|
756
|
+
// argument, Elixir-style, because every Aontu call is data-first
|
|
757
|
+
// already (`close(x)`, `pack(data, tmpl)`) and a pipe must read the
|
|
758
|
+
// way the calls it replaces read. It never reaches a Val: by the
|
|
759
|
+
// time the tree exists the call is an ordinary call, which is why
|
|
760
|
+
// canon can never emit the token and the two ports' canon stay
|
|
761
|
+
// byte-identical without either knowing about it.
|
|
762
|
+
'pipe-infix': (r: Rule, ctx: JsonicContext, _op: Op, terms: any) => {
|
|
763
|
+
const val = terms[0]
|
|
764
|
+
const call: any = terms[1]
|
|
765
|
+
|
|
766
|
+
if (null == val || null == call) return incompleteNil(r, ctx)
|
|
767
|
+
|
|
768
|
+
// The right-hand side is a CALL: either one the func handler
|
|
769
|
+
// already built, or one it refused for an arity the pipe is about
|
|
770
|
+
// to satisfy. Both carry what they were written as.
|
|
771
|
+
if (null != call._callname) {
|
|
772
|
+
return buildCall(r, ctx, call._callname, pipeTerms(call, val))
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// ... or a bare NAME, which is the whole point of the short
|
|
776
|
+
// spelling: `x |> upper` is `upper(x)`. A bare word has already
|
|
777
|
+
// become a string VALUE by the time an infix operator sees it, so
|
|
778
|
+
// this is where a string becomes a call.
|
|
779
|
+
if (true === call?.isScalar && 'string' === typeof call.peg &&
|
|
780
|
+
null != funcMap[call.peg]) {
|
|
781
|
+
return buildCall(r, ctx, call.peg, [val])
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// Anything else is not a call, and a pipe into a non-call is a
|
|
785
|
+
// mistake in the source rather than a value.
|
|
786
|
+
return addsite(new NilVal({ why: 'pipe_target' }), r, ctx)
|
|
787
|
+
},
|
|
788
|
+
|
|
536
789
|
'func-paren': (r: Rule, ctx: JsonicContext, _op: Op, terms: any) => {
|
|
537
790
|
let val = terms[1]
|
|
538
791
|
const fname = terms[0]
|
|
539
792
|
|
|
540
793
|
if ('' !== fname) {
|
|
541
|
-
|
|
542
|
-
// Arity is known for every built-in, so a surplus or missing
|
|
543
|
-
// argument is a mistake in the SOURCE, refused here where the
|
|
544
|
-
// author can see it (issue #51). It was previously left to each
|
|
545
|
-
// function to notice or not: the two ports disagreed on `upper()`
|
|
546
|
-
// and on `close()`, and `min(1,2)` noticed nothing at all -- it
|
|
547
|
-
// built a constraint that merely refused to generate later, with
|
|
548
|
-
// a message about the map rather than about the call.
|
|
549
|
-
//
|
|
550
|
-
// Counted BEFORE the rawToVal pass below, which is what makes the
|
|
551
|
-
// count possible: a comma group arrives as a RAW array and a
|
|
552
|
-
// written list literal as a ListVal, and rawToVal turns the first
|
|
553
|
-
// into the second.
|
|
554
|
-
const arity = funcArity[fname]
|
|
555
|
-
if (null != arity) {
|
|
556
|
-
const got = writtenArgCount(terms.slice(1))
|
|
557
|
-
if (got < arity[0] || (-1 !== arity[1] && got > arity[1])) {
|
|
558
|
-
// details is assigned AFTER construction: the NilVal
|
|
559
|
-
// constructor does not read it from its spec (only
|
|
560
|
-
// NilVal.make does), so passing it in the spec left the
|
|
561
|
-
// hint's {func}/{want}/{got} placeholders un-injected and
|
|
562
|
-
// printed literally.
|
|
563
|
-
const nil: any = new NilVal({ why: 'func_arity' })
|
|
564
|
-
nil.details = {
|
|
565
|
-
func: fname,
|
|
566
|
-
want: arityText(arity[0], arity[1]),
|
|
567
|
-
got: '' + got,
|
|
568
|
-
}
|
|
569
|
-
return addsite(nil, r, ctx)
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
// rawToVal EVERY argument. A degenerate expression can hand this
|
|
573
|
-
// handler raw parse values rather than Vals -- `pref(1-3)` arrives
|
|
574
|
-
// as the plain numbers 1 and -3 -- and a func's peg is unified
|
|
575
|
-
// element by element, so a raw one reached `arg.unify(...)` and
|
|
576
|
-
// threw. The unifier's catch-all turned that into an `internal`
|
|
577
|
-
// verdict: a crash reported as a unification result (issue #49).
|
|
578
|
-
// The Go port has always converted here (asVal in evaluate).
|
|
579
|
-
const args = terms.slice(1).map(rawToVal)
|
|
580
|
-
val = null == funcval ?
|
|
581
|
-
new NilVal({ why: 'unknown_function' }) :
|
|
582
|
-
new funcval({
|
|
583
|
-
peg: args
|
|
584
|
-
})
|
|
794
|
+
val = buildCall(r, ctx, fname, terms.slice(1))
|
|
585
795
|
}
|
|
586
796
|
// `a:()` — grouping parens with nothing inside.
|
|
587
797
|
if (null == val) return incompleteNil(r, ctx)
|
|
@@ -607,6 +817,14 @@ help isolate the syntax error.`,
|
|
|
607
817
|
infix: true, src: '|', left: 14_000_000, right: 15_000_000
|
|
608
818
|
},
|
|
609
819
|
|
|
820
|
+
// G8 phase 4: the pipe. LOOSEST of all the infix operators, so
|
|
821
|
+
// `a & b |> f` pipes the whole meet and not just `b` -- a pipe
|
|
822
|
+
// reads as "and then", which is a statement about everything to
|
|
823
|
+
// its left. Kept in lock-step with the op table in go/lang.go.
|
|
824
|
+
'pipe-infix': {
|
|
825
|
+
infix: true, src: '|>', left: 12_000_000, right: 13_000_000
|
|
826
|
+
},
|
|
827
|
+
|
|
610
828
|
'plus-infix': {
|
|
611
829
|
src: '+',
|
|
612
830
|
infix: true,
|
|
@@ -818,6 +1036,13 @@ help isolate the syntax error.`,
|
|
|
818
1036
|
valnode.site.row = st.rI
|
|
819
1037
|
valnode.site.col = st.cI
|
|
820
1038
|
valnode.site.url = ctx.meta.multisource && ctx.meta.multisource.path
|
|
1039
|
+
// No `?? ''` and no empty-text arm here: this branch runs only
|
|
1040
|
+
// for a rule that HAS an open token, and a token that opens a
|
|
1041
|
+
// value always carries text — the coverage gate refuses both
|
|
1042
|
+
// guards as dead. The unset case is the one above, where r.o0
|
|
1043
|
+
// itself can be absent.
|
|
1044
|
+
valnode.site.src = st.src
|
|
1045
|
+
valnode.site.len = st.src.length
|
|
821
1046
|
}
|
|
822
1047
|
// else { ERROR? }
|
|
823
1048
|
|
|
@@ -1166,19 +1391,41 @@ help isolate the syntax error.`,
|
|
|
1166
1391
|
|
|
1167
1392
|
|
|
1168
1393
|
|
|
1169
|
-
// SECURITY: the
|
|
1170
|
-
// reach — @"path"
|
|
1171
|
-
//
|
|
1172
|
-
//
|
|
1173
|
-
//
|
|
1174
|
-
//
|
|
1175
|
-
//
|
|
1394
|
+
// SECURITY: under the DEFAULT ('system') include capability this
|
|
1395
|
+
// resolver reads any file/package the process can reach — @"path"
|
|
1396
|
+
// follows relative paths (`@"../../etc/passwd"`) and symlinks, and
|
|
1397
|
+
// @"pkg" can require() arbitrary installed modules — so treat opening
|
|
1398
|
+
// an untrusted source as running it. The trust profile (G5,
|
|
1399
|
+
// docs/trust.md) is the confinement surface: `trust.include` of
|
|
1400
|
+
// 'none', `{ mem }` or `{ root }` restricts what `@"..."` may resolve,
|
|
1401
|
+
// and a denied resolution is a deterministic parse-stage
|
|
1402
|
+
// `include_denied` error.
|
|
1176
1403
|
function makeModelResolver(options: any) {
|
|
1177
1404
|
const useRequire = options.require || require
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1405
|
+
const capability = options.trust?.include ?? 'system'
|
|
1406
|
+
|
|
1407
|
+
const memCapability =
|
|
1408
|
+
'object' === typeof capability && null != (capability as any).mem
|
|
1409
|
+
const rootDir: string | undefined =
|
|
1410
|
+
'object' === typeof capability &&
|
|
1411
|
+
'string' === typeof (capability as any).root
|
|
1412
|
+
? pathResolve((capability as any).root) : undefined
|
|
1413
|
+
|
|
1414
|
+
// Under the mem capability the CAPABILITY's file set is the whole
|
|
1415
|
+
// world; otherwise the host-injected `options.resolver.mem` entries
|
|
1416
|
+
// remain available under every capability but 'none' — they are
|
|
1417
|
+
// host-provided, not document-requested, so confining them would
|
|
1418
|
+
// confine the host against itself.
|
|
1419
|
+
// THE BUNDLED VOCABULARY (G4 phase 4, ts/src/std.ts) rides the
|
|
1420
|
+
// memory leg: served from the engine itself, so it needs neither the
|
|
1421
|
+
// filesystem nor package resolution and is available under every
|
|
1422
|
+
// capability but `none` — which denies every include outright, that
|
|
1423
|
+
// being what `none` means. Host entries and the capability's own set
|
|
1424
|
+
// WIN over it: a caller that supplies its own `std/system` gets the
|
|
1425
|
+
// one it supplied.
|
|
1426
|
+
let memResolver = makeMemResolver(memCapability
|
|
1427
|
+
? { ...(capability as any).mem }
|
|
1428
|
+
: { ...(options.resolver?.mem || {}) })
|
|
1182
1429
|
|
|
1183
1430
|
// TODO: make this consistent with other resolvers
|
|
1184
1431
|
let fileResolver = makeFileResolver((spec: any) => {
|
|
@@ -1190,6 +1437,100 @@ function makeModelResolver(options: any) {
|
|
|
1190
1437
|
...(options.resolver?.pkg || {})
|
|
1191
1438
|
})
|
|
1192
1439
|
|
|
1440
|
+
// Confinement is realpath-then-prefix-check (docs/trust.md): the
|
|
1441
|
+
// RESOLVED file's real path must sit below the root's real path, so a
|
|
1442
|
+
// symlink inside the root pointing outside it is an escape, not a
|
|
1443
|
+
// loophole. A path realpath cannot resolve falls back to the lexical
|
|
1444
|
+
// form — the comparison is then against what the resolver actually
|
|
1445
|
+
// read.
|
|
1446
|
+
// Real fs, deliberately: `options.fs` is not a sandbox (it feeds
|
|
1447
|
+
// parse text; the file leg reads through its own channel), so the
|
|
1448
|
+
// containment check must see the same filesystem that leg read from.
|
|
1449
|
+
// A path that does not (fully) exist cannot be realpath'd whole, and
|
|
1450
|
+
// falling back to the LEXICAL form compares apples to oranges when
|
|
1451
|
+
// the root itself sits behind a symlink -- on macOS a root under
|
|
1452
|
+
// /var realpaths to /private/var, so a merely-missing file inside it
|
|
1453
|
+
// reads as an escape. Realpath the deepest EXISTING ancestor and
|
|
1454
|
+
// re-attach the rest, so both sides of the check are in real
|
|
1455
|
+
// coordinates. (The MCP server's own confinement carries the twin of
|
|
1456
|
+
// this rule; its CI failure is what found the shape.)
|
|
1457
|
+
const realpath = (p: string): string => {
|
|
1458
|
+
try {
|
|
1459
|
+
return realpathSync(p)
|
|
1460
|
+
}
|
|
1461
|
+
catch {
|
|
1462
|
+
const parent = pathDirname(p)
|
|
1463
|
+
if (parent === p) {
|
|
1464
|
+
return p
|
|
1465
|
+
}
|
|
1466
|
+
return pathJoin(realpath(parent), pathBasename(p))
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
const outsideRoot = (root: string, full: string): boolean => {
|
|
1471
|
+
const rootReal = realpath(root)
|
|
1472
|
+
const fullReal = realpath(full)
|
|
1473
|
+
return fullReal !== rootReal && !fullReal.startsWith(rootReal + pathSep)
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
// A denial THROWS with the code; Lang.parse converts it to the
|
|
1477
|
+
// parse-stage `include_denied` nil (the same shape a syntax failure
|
|
1478
|
+
// takes). Raising beats injecting a nil value: a bare-member include
|
|
1479
|
+
// (`@"denied.aon"` at the top of a file) MERGES into the enclosing
|
|
1480
|
+
// map, and a nil contributes no keys, so an injected denial would
|
|
1481
|
+
// vanish and leave a plausible, silently-partial document.
|
|
1482
|
+
const deny = (path: string): never => {
|
|
1483
|
+
// Only 'none' and 'root' can deny: the mem capability's misses are
|
|
1484
|
+
// not-found (its set is the whole world), so there is no third arm.
|
|
1485
|
+
const capname = 'none' === capability ? 'none' : 'root:' + rootDir
|
|
1486
|
+
const err: any = new Error(
|
|
1487
|
+
'include denied: ' + path + ' (capability: ' + capname + ')')
|
|
1488
|
+
err.code = 'include_denied'
|
|
1489
|
+
throw err
|
|
1490
|
+
}
|
|
1491
|
+
|
|
1492
|
+
// The user cache: whatever the host named, else the platform rule
|
|
1493
|
+
// (`modCacheDir`, ts/src/mod.ts) the tooling writes by.
|
|
1494
|
+
const modCache = (opts: any): string | undefined => {
|
|
1495
|
+
const named = opts.mod?.cache
|
|
1496
|
+
return 'string' === typeof named ? named : modCacheDir()
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1499
|
+
// The directory an include is being resolved FROM: the source that
|
|
1500
|
+
// holds it, or the entry path when the source is a string. Same base
|
|
1501
|
+
// the file leg computes (resolvePathSpec in @tabnas/multisource).
|
|
1502
|
+
const dirOf = (p: string | undefined): string =>
|
|
1503
|
+
null == p || '' === p ? pathResolve('.') : pathDirname(pathResolve(p))
|
|
1504
|
+
|
|
1505
|
+
// The module store reader: the host's filesystem when one was
|
|
1506
|
+
// injected, so a sandboxed evaluation stays in the filesystem the
|
|
1507
|
+
// host gave it.
|
|
1508
|
+
const modFs = (ctx: any): any => {
|
|
1509
|
+
const hostfs = ctx?.meta?.fs
|
|
1510
|
+
return null == hostfs ? { existsSync, readFileSync } : {
|
|
1511
|
+
existsSync: (p: string) => {
|
|
1512
|
+
try {
|
|
1513
|
+
hostfs.statSync(p)
|
|
1514
|
+
return true
|
|
1515
|
+
}
|
|
1516
|
+
catch {
|
|
1517
|
+
return false
|
|
1518
|
+
}
|
|
1519
|
+
},
|
|
1520
|
+
readFileSync: (p: string, enc: string) => hostfs.readFileSync(p, enc),
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
// The manifest sink rides the parse meta (Lang.parse seeds it, the
|
|
1525
|
+
// multisource plugin's child-meta spread carries it to every nested
|
|
1526
|
+
// include), so the recorded closure covers the whole include tree.
|
|
1527
|
+
const record = (ctx: any, path: string, cap: string) => {
|
|
1528
|
+
const manifest = ctx?.meta?.aontu?.manifest
|
|
1529
|
+
if (Array.isArray(manifest)) {
|
|
1530
|
+
manifest.push({ path, capability: cap })
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1193
1534
|
return function ModelResolver(
|
|
1194
1535
|
spec: any,
|
|
1195
1536
|
popts: any,
|
|
@@ -1209,10 +1550,64 @@ function makeModelResolver(options: any) {
|
|
|
1209
1550
|
return { found: false, path: '' + (path ?? ''), search: [] }
|
|
1210
1551
|
}
|
|
1211
1552
|
|
|
1553
|
+
if ('none' === capability) {
|
|
1554
|
+
deny(path)
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
// THE BUNDLED VOCABULARY (G4 phase 4, ts/src/std.ts): served from
|
|
1558
|
+
// the engine itself, so it needs neither the filesystem nor package
|
|
1559
|
+
// resolution and is available under every capability but `none` —
|
|
1560
|
+
// checked just above, that being what `none` means. Matched against
|
|
1561
|
+
// the name the author WROTE, before the memory leg, so the kind is
|
|
1562
|
+
// stated rather than guessed from an extension the bare name does
|
|
1563
|
+
// not have.
|
|
1564
|
+
const std = STD_SOURCES[path]
|
|
1565
|
+
if (null != std) {
|
|
1566
|
+
record(ctx, path, 'std')
|
|
1567
|
+
return { found: true, path, full: path, kind: 'aon', src: std, search: [] }
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1212
1570
|
let search: any = []
|
|
1213
1571
|
let res = memResolver(path, popts, rule, ctx, jsonic)
|
|
1214
1572
|
res.path = path
|
|
1215
1573
|
if (res.found) {
|
|
1574
|
+
record(ctx, res.full ?? path, 'mem')
|
|
1575
|
+
return res
|
|
1576
|
+
}
|
|
1577
|
+
|
|
1578
|
+
// THE MODULE LEG (G6 phase 2, ts/src/mod.ts): memory -> MODULE ->
|
|
1579
|
+
// filesystem -> package. Memory stays FIRST so a sandbox and the
|
|
1580
|
+
// spec suite can stub a module path without touching disk; a path
|
|
1581
|
+
// that is not module-shaped falls straight through, so no existing
|
|
1582
|
+
// include can be routed somewhere new by this.
|
|
1583
|
+
const modref = memCapability ? undefined : parseModuleRef(path)
|
|
1584
|
+
if (null != modref) {
|
|
1585
|
+
const msmeta = (ctx as any)?.meta?.multisource
|
|
1586
|
+
const from = dirOf(null != msmeta?.path ? msmeta.path : popts?.path)
|
|
1587
|
+
const found = resolveModule(modref, from, modFs(ctx), {
|
|
1588
|
+
// The user cache lives outside any confinement root, so it is
|
|
1589
|
+
// consulted only when nothing confines this evaluation. A
|
|
1590
|
+
// rooted profile sees the project's own `aon_vendor/` and
|
|
1591
|
+
// nothing else, which is what `root` means.
|
|
1592
|
+
...(null == rootDir ? { cache: modCache(options) } : {}),
|
|
1593
|
+
eval: options.mod?.eval,
|
|
1594
|
+
depth: options.mod?.depth,
|
|
1595
|
+
})
|
|
1596
|
+
if (null != rootDir && outsideRoot(rootDir, found.full)) {
|
|
1597
|
+
deny(path)
|
|
1598
|
+
}
|
|
1599
|
+
record(ctx, found.full, 'mod')
|
|
1600
|
+
return {
|
|
1601
|
+
found: true, path, full: found.full,
|
|
1602
|
+
kind: 'aon', src: found.src, search: [],
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1606
|
+
if (memCapability) {
|
|
1607
|
+
// A miss in the declared virtual set is NOT-FOUND, not denial:
|
|
1608
|
+
// the allowed mechanism ran and missed. Denial is reserved for a
|
|
1609
|
+
// capability refusing a mechanism outright.
|
|
1610
|
+
res.search = search.concat(res.search)
|
|
1216
1611
|
return res
|
|
1217
1612
|
}
|
|
1218
1613
|
|
|
@@ -1221,14 +1616,42 @@ function makeModelResolver(options: any) {
|
|
|
1221
1616
|
res = fileResolver(path, popts, rule, ctx, jsonic)
|
|
1222
1617
|
res.path = path
|
|
1223
1618
|
if (res.found) {
|
|
1619
|
+
// `res.full` asserted non-null: a FOUND file resolution always
|
|
1620
|
+
// carries the absolute path it read (and the pkg leg below is the
|
|
1621
|
+
// same), so a runtime fallback arm would be dead code.
|
|
1622
|
+
const full = res.full as string
|
|
1623
|
+
if (null != rootDir && outsideRoot(rootDir, full)) {
|
|
1624
|
+
deny(path)
|
|
1625
|
+
}
|
|
1626
|
+
// The warning window for the staged default flip (G5 phase 6):
|
|
1627
|
+
// under 'system', the CLI supplies trustWarn and the entry root,
|
|
1628
|
+
// and every resolution escaping that root names the flag a future
|
|
1629
|
+
// default will require.
|
|
1630
|
+
if (null == rootDir && null != options.trustWarn &&
|
|
1631
|
+
null != options.trustWarnRoot &&
|
|
1632
|
+
outsideRoot(options.trustWarnRoot, full)) {
|
|
1633
|
+
options.trustWarn('escape', full)
|
|
1634
|
+
}
|
|
1635
|
+
record(ctx, full, 'file')
|
|
1224
1636
|
return res
|
|
1225
1637
|
}
|
|
1226
1638
|
|
|
1227
1639
|
search = search.concat(res.search)
|
|
1228
1640
|
|
|
1641
|
+
if (null != rootDir) {
|
|
1642
|
+
// Package resolution is not part of the root capability; the
|
|
1643
|
+
// miss stands as not-found with the searched paths listed.
|
|
1644
|
+
res.search = search
|
|
1645
|
+
return res
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1229
1648
|
res = pkgResolver(path, popts, rule, ctx, jsonic)
|
|
1230
1649
|
res.path = path
|
|
1231
1650
|
if (res.found) {
|
|
1651
|
+
if (null != options.trustWarn) {
|
|
1652
|
+
options.trustWarn('pkg', res.full as string)
|
|
1653
|
+
}
|
|
1654
|
+
record(ctx, res.full as string, 'pkg')
|
|
1232
1655
|
return res
|
|
1233
1656
|
}
|
|
1234
1657
|
|
|
@@ -1239,16 +1662,31 @@ function makeModelResolver(options: any) {
|
|
|
1239
1662
|
|
|
1240
1663
|
|
|
1241
1664
|
// funcArity is the permitted WRITTEN argument count of each built-in, as
|
|
1665
|
+
// The functions whose comma-separated arguments are distinct POSITIONS
|
|
1666
|
+
// rather than one argument list. See the func-paren handler above: this
|
|
1667
|
+
// is the set whose comma group is expanded back into separate `peg`
|
|
1668
|
+
// entries.
|
|
1669
|
+
const POSITIONAL_ARG_FUNCS: Record<string, boolean> = {
|
|
1670
|
+
deprecate: true, pack: true, each: true, filter: true, match: true,
|
|
1671
|
+
// Arithmetic takes two OPERANDS, and an operand is a position: `sub`
|
|
1672
|
+
// is not commutative, so `sub(a, b)` reaching the engine as one
|
|
1673
|
+
// two-element list would lose which is which.
|
|
1674
|
+
add: true, sub: true, mul: true, div: true, mod: true, rem: true,
|
|
1675
|
+
// The bag and the key are distinct positions.
|
|
1676
|
+
pick: true,
|
|
1677
|
+
}
|
|
1678
|
+
|
|
1679
|
+
|
|
1242
1680
|
// [min, max]; a max of -1 is unbounded. Every name in funcMap has an
|
|
1243
1681
|
// entry, and the arity is a property of the language rather than of
|
|
1244
1682
|
// either port -- go/func.go carries the same table.
|
|
1245
1683
|
//
|
|
1246
|
-
// Nearly everything takes exactly one. The
|
|
1247
|
-
//
|
|
1248
|
-
//
|
|
1249
|
-
//
|
|
1250
|
-
//
|
|
1251
|
-
//
|
|
1684
|
+
// Nearly everything takes exactly one. The exceptions earn their place:
|
|
1685
|
+
// key() names how many levels UP the path to read, defaulting to the
|
|
1686
|
+
// parent when omitted, neq takes a whole set of exclusions, unique()
|
|
1687
|
+
// takes none (a property of the container) or a PROJECTOR key, must()
|
|
1688
|
+
// takes a check AND the author's message for when it fails, and the
|
|
1689
|
+
// arithmetic family takes two operands.
|
|
1252
1690
|
const funcArity: Record<string, [number, number]> = {
|
|
1253
1691
|
upper: [1, 1], lower: [1, 1], copy: [1, 1], pref: [1, 1],
|
|
1254
1692
|
super: [1, 1], type: [1, 1], hide: [1, 1], close: [1, 1],
|
|
@@ -1256,9 +1694,30 @@ const funcArity: Record<string, [number, number]> = {
|
|
|
1256
1694
|
min: [1, 1], max: [1, 1], above: [1, 1], below: [1, 1], re: [1, 1],
|
|
1257
1695
|
length: [1, 1],
|
|
1258
1696
|
key: [0, 1],
|
|
1259
|
-
|
|
1697
|
+
// THE ONE ARGUMENT IS A PROJECTOR: `unique(port)` says no two
|
|
1698
|
+
// members share a `port`. The arity was reserved for it (finding I).
|
|
1699
|
+
unique: [0, 1],
|
|
1260
1700
|
neq: [1, -1],
|
|
1261
1701
|
must: [2, 2],
|
|
1702
|
+
deprecate: [1, 2],
|
|
1703
|
+
id: [1, 1],
|
|
1704
|
+
refer: [0, 1],
|
|
1705
|
+
pack: [2, 2],
|
|
1706
|
+
each: [1, 2],
|
|
1707
|
+
filter: [2, 2],
|
|
1708
|
+
// The scrutinee, then pattern/result pairs, then an optional
|
|
1709
|
+
// default: three arguments at least, and any number above that.
|
|
1710
|
+
match: [3, -1],
|
|
1711
|
+
// Two operands, always. Arithmetic has no variadic reading that is
|
|
1712
|
+
// not a fold, and a fold is the recursion this language refuses.
|
|
1713
|
+
add: [2, 2], sub: [2, 2], mul: [2, 2],
|
|
1714
|
+
div: [2, 2], mod: [2, 2], rem: [2, 2],
|
|
1715
|
+
// One bag. The operation is fixed, so there is nothing else to pass:
|
|
1716
|
+
// a fold's second argument is a FUNCTION, and this language has none
|
|
1717
|
+
// to give it.
|
|
1718
|
+
sum: [1, 1], least: [1, 1], greatest: [1, 1],
|
|
1719
|
+
// The bag, and the key to take from each of its children.
|
|
1720
|
+
pick: [2, 2],
|
|
1262
1721
|
}
|
|
1263
1722
|
|
|
1264
1723
|
|
|
@@ -1293,11 +1752,13 @@ function arityText(lo: number, hi: number): string {
|
|
|
1293
1752
|
return 'one or more arguments'
|
|
1294
1753
|
}
|
|
1295
1754
|
if (lo !== hi) {
|
|
1296
|
-
return 'no arguments or one'
|
|
1297
|
-
}
|
|
1298
|
-
if (0 === hi) {
|
|
1299
|
-
return 'no arguments'
|
|
1755
|
+
return 0 === lo ? 'no arguments or one' : 'one argument or two'
|
|
1300
1756
|
}
|
|
1757
|
+
// NO {0,0} ARM. `unique` was the only built-in taking none, and its
|
|
1758
|
+
// one argument is now the projector the arity was reserved for
|
|
1759
|
+
// (finding I), so a phrasing for a count no entry carries would be
|
|
1760
|
+
// untested prose pretending to be tested -- the rule this function's
|
|
1761
|
+
// header states. The arm returns with the table, if one ever does.
|
|
1301
1762
|
if (2 === hi) {
|
|
1302
1763
|
return 'exactly two arguments'
|
|
1303
1764
|
}
|
|
@@ -1421,7 +1882,13 @@ class Lang {
|
|
|
1421
1882
|
multisource: {
|
|
1422
1883
|
path: opts?.path ?? this.opts.path,
|
|
1423
1884
|
deps: (opts && opts.deps) || undefined
|
|
1424
|
-
}
|
|
1885
|
+
},
|
|
1886
|
+
// The include-manifest sink (G5, docs/trust.md): the resolver
|
|
1887
|
+
// records every resolved include here, and the plugin's
|
|
1888
|
+
// child-meta spread carries the same array to nested includes.
|
|
1889
|
+
aontu: {
|
|
1890
|
+
manifest: (opts as any)?.manifest,
|
|
1891
|
+
},
|
|
1425
1892
|
}
|
|
1426
1893
|
|
|
1427
1894
|
if (null != opts?.idcount) {
|
|
@@ -1449,16 +1916,49 @@ class Lang {
|
|
|
1449
1916
|
}
|
|
1450
1917
|
}
|
|
1451
1918
|
catch (e: any) {
|
|
1452
|
-
if (
|
|
1919
|
+
if ('include_denied' === e?.code ||
|
|
1920
|
+
'module_missing' === e?.code || 'module_integrity' === e?.code ||
|
|
1921
|
+
'module_depth' === e?.code) {
|
|
1922
|
+
// A denied include (trust profile, G5): the resolver throws so
|
|
1923
|
+
// a bare-member include cannot vanish in the merge, and the
|
|
1924
|
+
// code survives here as the parse-stage nil the registry
|
|
1925
|
+
// pins (errcodes.tsv: include_denied, class parse).
|
|
1926
|
+
// A denied include (G5) and a module that is missing or fails
|
|
1927
|
+
// its pin (G6 phase 2) are refused the same way, for the same
|
|
1928
|
+
// reason: the resolver THROWS so a bare-member include cannot
|
|
1929
|
+
// vanish in the merge, and the code survives here as the
|
|
1930
|
+
// parse-stage nil the registry pins (errcodes.tsv).
|
|
1453
1931
|
val = new NilVal({
|
|
1454
1932
|
why: 'parse',
|
|
1455
1933
|
err: new NilVal({
|
|
1456
|
-
why:
|
|
1457
|
-
msg: e.message
|
|
1934
|
+
why: e.code,
|
|
1935
|
+
msg: e.message,
|
|
1458
1936
|
err: e,
|
|
1459
1937
|
})
|
|
1460
1938
|
})
|
|
1461
1939
|
}
|
|
1940
|
+
else if (e instanceof JsonicError || 'JsonicError' === e.constructor.name) {
|
|
1941
|
+
const syntax: any = new NilVal({
|
|
1942
|
+
why: 'syntax',
|
|
1943
|
+
msg: e.message + opCharHint(src),
|
|
1944
|
+
err: e,
|
|
1945
|
+
})
|
|
1946
|
+
// THE POSITION TRAVELS WITH IT. The parser knows exactly where
|
|
1947
|
+
// it stopped -- it draws a caret there -- and the rendered
|
|
1948
|
+
// message carried the only copy, so `vet --format json`
|
|
1949
|
+
// reported row -1, col -1 for a document whose fault the human
|
|
1950
|
+
// renderer located to the character. A machine-readable report
|
|
1951
|
+
// that says "somewhere in this file" is the one a repair loop
|
|
1952
|
+
// can do nothing with. Both numbers are already 1-based here,
|
|
1953
|
+
// which is the base a site uses (go/lang.go does the same).
|
|
1954
|
+
if ('number' === typeof e.lineNumber) {
|
|
1955
|
+
syntax.site.row = e.lineNumber
|
|
1956
|
+
}
|
|
1957
|
+
if ('number' === typeof e.columnNumber) {
|
|
1958
|
+
syntax.site.col = e.columnNumber
|
|
1959
|
+
}
|
|
1960
|
+
val = new NilVal({ why: 'parse', err: syntax })
|
|
1961
|
+
}
|
|
1462
1962
|
else {
|
|
1463
1963
|
throw e
|
|
1464
1964
|
}
|