aontu 0.60.0 → 0.62.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 +3 -3
- package/dist/agentsmd.d.ts +1 -0
- package/dist/agentsmd.js +7 -1
- package/dist/agentsmd.js.map +1 -1
- package/dist/allow.d.ts +23 -0
- package/dist/allow.js +230 -0
- package/dist/allow.js.map +1 -0
- package/dist/aontu.d.ts +4 -2
- package/dist/aontu.js +4 -2
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +10 -1
- package/dist/cli.js +1000 -47
- package/dist/cli.js.map +1 -1
- package/dist/format.d.ts +1 -0
- package/dist/format.js +154 -12
- package/dist/format.js.map +1 -1
- package/dist/helpdoc.d.ts +16 -0
- package/dist/helpdoc.js +59 -0
- package/dist/helpdoc.js.map +1 -0
- package/dist/hints.js +15 -2
- package/dist/hints.js.map +1 -1
- package/dist/lang.js +93 -40
- package/dist/lang.js.map +1 -1
- package/dist/lower.d.ts +3 -0
- package/dist/lower.js +3 -0
- package/dist/lower.js.map +1 -1
- package/dist/lsp.d.ts +1 -1
- package/dist/lsp.js +1 -1
- package/dist/lsp.js.map +1 -1
- package/dist/relation.d.ts +2 -0
- package/dist/relation.js +7 -1
- package/dist/relation.js.map +1 -1
- package/dist/render.js +26 -21
- package/dist/render.js.map +1 -1
- package/dist/sigdecl.js +1 -1
- package/dist/sigdecl.js.map +1 -1
- package/dist/std.js +112 -69
- package/dist/std.js.map +1 -1
- package/dist/template.d.ts +2 -1
- package/dist/template.js +51 -15
- package/dist/template.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/val/AggFuncVal.js +2 -2
- package/dist/val/AggFuncVal.js.map +1 -1
- package/dist/val/CmpFuncVal.d.ts +20 -0
- package/dist/val/CmpFuncVal.js +245 -0
- package/dist/val/CmpFuncVal.js.map +1 -0
- package/dist/val/EachFuncVal.d.ts +1 -2
- package/dist/val/EachFuncVal.js +15 -29
- package/dist/val/EachFuncVal.js.map +1 -1
- package/dist/val/FormFuncVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js +17 -1
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/NamerFuncVal.d.ts +12 -0
- package/dist/val/NamerFuncVal.js +176 -0
- package/dist/val/NamerFuncVal.js.map +1 -0
- package/dist/val/NilVal.js +29 -3
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/NomFuncVal.d.ts +12 -0
- package/dist/val/NomFuncVal.js +187 -0
- package/dist/val/NomFuncVal.js.map +1 -0
- package/dist/val/PackFuncVal.js +3 -3
- package/dist/val/PackFuncVal.js.map +1 -1
- package/dist/val/RefVal.js +1 -1
- package/dist/val/TranslateFuncVal.d.ts +12 -0
- package/dist/val/TranslateFuncVal.js +101 -0
- package/dist/val/TranslateFuncVal.js.map +1 -0
- package/dist/val/UpperFuncVal.js +17 -1
- package/dist/val/UpperFuncVal.js.map +1 -1
- package/dist/val/caserange.d.ts +3 -0
- package/dist/val/caserange.js +110 -0
- package/dist/val/caserange.js.map +1 -0
- package/dist/vet.d.ts +12 -0
- package/dist/vet.js +209 -1
- package/dist/vet.js.map +1 -1
- package/grammar/aontu.abnf +1 -1
- package/grammar/aontu.gbnf +1 -1
- package/grammar/aontu.lark +1 -1
- package/grammar/aontu.tmLanguage.json +1 -1
- package/package.json +1 -1
- package/skill/SKILL.md +8 -0
- package/skill/init/check.sh +28 -0
- package/skill/init/data.aon +12 -0
- package/skill/init/model.aon +19 -0
- package/skill/tasks.md +151 -0
- package/src/agentsmd.ts +13 -2
- package/src/allow.ts +316 -0
- package/src/aontu.ts +10 -1
- package/src/cli.ts +1131 -53
- package/src/format.ts +191 -14
- package/src/helpdoc.ts +77 -0
- package/src/hints.ts +16 -2
- package/src/lang.ts +98 -42
- package/src/lower.ts +3 -3
- package/src/lsp.ts +1 -1
- package/src/relation.ts +21 -1
- package/src/render.ts +26 -21
- package/src/sigdecl.ts +1 -1
- package/src/std.ts +112 -69
- package/src/template.ts +55 -15
- package/src/val/AggFuncVal.ts +2 -2
- package/src/val/CmpFuncVal.ts +411 -0
- package/src/val/EachFuncVal.ts +49 -50
- package/src/val/LowerFuncVal.ts +18 -1
- package/src/val/NilVal.ts +29 -3
- package/src/val/NomFuncVal.ts +287 -0
- package/src/val/PackFuncVal.ts +3 -3
- package/src/val/RefVal.ts +1 -1
- package/src/val/TranslateFuncVal.ts +182 -0
- package/src/val/UpperFuncVal.ts +18 -1
- package/src/val/caserange.ts +115 -0
- package/src/vet.ts +287 -1
- package/src/val/FormFuncVal.ts +0 -119
package/src/vet.ts
CHANGED
|
@@ -46,6 +46,7 @@ import { subsumeNode, effectiveDefault } from './subsume'
|
|
|
46
46
|
// (query imports anchorAt from here), and a benign one: both sides
|
|
47
47
|
// use the other only from inside a function body, never at load time.
|
|
48
48
|
import { noPathFinding } from './query'
|
|
49
|
+
import { cmpCodePoint } from './keyorder'
|
|
49
50
|
|
|
50
51
|
|
|
51
52
|
export type VetVerdict = 'valid' | 'invalid' | 'incomplete' | 'error'
|
|
@@ -118,10 +119,52 @@ export type VetFinding = {
|
|
|
118
119
|
note?: string
|
|
119
120
|
}
|
|
120
121
|
|
|
122
|
+
// WHAT THE CHECK ACTUALLY EXAMINED (G11 phase 5,
|
|
123
|
+
// docs/capability-review/g11-agent-onramp.md).
|
|
124
|
+
//
|
|
125
|
+
// The defect this exists for: a schema written with the wildcard every
|
|
126
|
+
// neighbouring tool uses -- `{"*": {...}}`, which in aontu is a key
|
|
127
|
+
// NAMED `*` and not a template -- constrains nothing, and vet answers
|
|
128
|
+
// `valid` over data that violates it. aontu is not wrong there; it was
|
|
129
|
+
// asked about a document declaring an entity called `*`. The defect is
|
|
130
|
+
// that a check that examined NOTHING and a check that PASSED are the
|
|
131
|
+
// same bytes and the same exit code, so an unattended caller reports
|
|
132
|
+
// success.
|
|
133
|
+
//
|
|
134
|
+
// Absent unless asked for (`VetOptions.coverage`), so no existing
|
|
135
|
+
// report changes shape and the accounting costs nothing by default --
|
|
136
|
+
// `render --coverage` sets both precedents.
|
|
137
|
+
export type VetCoverage = {
|
|
138
|
+
// Data LEAVES a schema declaration constrained. Leaves, not paths:
|
|
139
|
+
// a leaf is where a value lives, and matching a CONTAINER constrains
|
|
140
|
+
// no value. A schema that says only "there is a key called entity"
|
|
141
|
+
// has checked nothing, and this is the number that says so.
|
|
142
|
+
checked: number
|
|
143
|
+
// Declarations the schema makes under the anchor. A declaration is a
|
|
144
|
+
// map key, a list index, or a template (spelled `&` in the path),
|
|
145
|
+
// at every depth.
|
|
146
|
+
declared: number
|
|
147
|
+
// Data leaves in all, under `coverageAt` when it is given. `checked`
|
|
148
|
+
// over this is the ratio a reader wants.
|
|
149
|
+
leaves: number
|
|
150
|
+
// The SHALLOWEST data paths no declaration constrained. Shallowest,
|
|
151
|
+
// as `render --coverage`'s `dead` is: a path whose subtree is wholly
|
|
152
|
+
// unconstrained is named once instead of every leaf beneath it.
|
|
153
|
+
unchecked: string[]
|
|
154
|
+
// The SHALLOWEST declarations no data path met.
|
|
155
|
+
unused: string[]
|
|
156
|
+
// NO data leaf was constrained, over a document that has leaves.
|
|
157
|
+
// The exact condition of the `"*"` failure, and what
|
|
158
|
+
// `--strict-coverage` exits 1 on.
|
|
159
|
+
vacuous: boolean
|
|
160
|
+
}
|
|
161
|
+
|
|
121
162
|
export type VetReport = {
|
|
122
163
|
verdict: VetVerdict
|
|
123
164
|
truncated: boolean
|
|
124
165
|
findings: VetFinding[]
|
|
166
|
+
// Absent unless the run asked for it.
|
|
167
|
+
coverage?: VetCoverage
|
|
125
168
|
}
|
|
126
169
|
|
|
127
170
|
export type VetOptions = {
|
|
@@ -129,6 +172,16 @@ export type VetOptions = {
|
|
|
129
172
|
closed?: boolean // close() the anchor for this run
|
|
130
173
|
partial?: boolean // residue is not a failure
|
|
131
174
|
maxErrors?: number // cap the finding list (default 20)
|
|
175
|
+
|
|
176
|
+
// Account for what the check examined (G11 phase 5). Off by default:
|
|
177
|
+
// the report gains a `coverage` object only when this is set, so no
|
|
178
|
+
// existing caller's report changes shape.
|
|
179
|
+
coverage?: boolean
|
|
180
|
+
// Measure under this path of the DATA only, instead of the whole
|
|
181
|
+
// document -- `render --coverage`'s `--coverage-at`, for the same
|
|
182
|
+
// reason: a caller gating one subtree should not be answered about
|
|
183
|
+
// the rest. Ignored unless `coverage` is set.
|
|
184
|
+
coverageAt?: string
|
|
132
185
|
schemaUrl?: string // provenance label for schema sites
|
|
133
186
|
dataUrl?: string // provenance label for data sites
|
|
134
187
|
|
|
@@ -596,6 +649,215 @@ export function throughResidue(v: any): any {
|
|
|
596
649
|
// are unusable — which is why an unusable schema is a verdict (`error`)
|
|
597
650
|
// rather than an exception too: "the schema is broken" is a fact the
|
|
598
651
|
// agent loop needs to branch on, not an exceptional condition.
|
|
652
|
+
// THE COVERAGE ACCOUNTING (G11 phase 5). Structural, over the two
|
|
653
|
+
// trees vet already holds, and deliberately NOT provenance-based: the
|
|
654
|
+
// question is what the SCHEMA DECLARES about the data, which is a
|
|
655
|
+
// property of the two documents rather than of the meet that ran. A
|
|
656
|
+
// meet-based reading would also count a value the data supplied to
|
|
657
|
+
// itself as "covered", which is the opposite of the thing being asked.
|
|
658
|
+
//
|
|
659
|
+
// A map's template lives on `spread.cj` rather than in `peg`, so a
|
|
660
|
+
// declaration path spells it `&` -- the same character the language
|
|
661
|
+
// spells it with, and one no map key can collide with, since a bare
|
|
662
|
+
// `&` cannot be a key.
|
|
663
|
+
const COVER_TEMPLATE = '&'
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
// Is this value a bag with children to walk?
|
|
667
|
+
function coverKids(v: any): { key: string, val: any }[] {
|
|
668
|
+
// NO KIND GUARD: the two tests below already reject anything that is
|
|
669
|
+
// not a bag, exactly as the Go twin's type switch does, so a guard
|
|
670
|
+
// above them is dead code (ADR-002).
|
|
671
|
+
const out: { key: string, val: any }[] = []
|
|
672
|
+
if (true === v.isMap && null != v.peg) {
|
|
673
|
+
for (const k of Object.keys(v.peg).sort(cmpCodePoint)) {
|
|
674
|
+
out.push({ key: k, val: v.peg[k] })
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
else if (true === v.isList && Array.isArray(v.peg)) {
|
|
678
|
+
v.peg.forEach((m: any, i: number) => out.push({ key: String(i), val: m }))
|
|
679
|
+
}
|
|
680
|
+
return out
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
// The template a bag applies to every child, when it has one. A spread
|
|
685
|
+
// with no conjunct is not a declaration: `{"*":{...}}` carries the
|
|
686
|
+
// empty spread every map carries, and reading that as a template is
|
|
687
|
+
// precisely the confusion this phase exists to end.
|
|
688
|
+
function coverTemplate(v: any): any {
|
|
689
|
+
const cj = v?.spread?.cj
|
|
690
|
+
return null != cj && true === cj.isVal && true !== cj.isTop ? cj : undefined
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
// Every declaration the schema makes, as a path, with the node at it.
|
|
695
|
+
// Named keys and templates alike, at every depth.
|
|
696
|
+
//
|
|
697
|
+
// NO IDENTITY GUARD, and that is a decision rather than an omission.
|
|
698
|
+
// `walkVals` (ts/src/walk.ts) carries one because it walks values the
|
|
699
|
+
// unification MINTED -- findings, conjunct operands, disjunct trials --
|
|
700
|
+
// where a node really is reached twice. These two walks descend a
|
|
701
|
+
// SETTLED bag through `peg` and `spread` alone, and such a tree is a
|
|
702
|
+
// tree: a reference resolves by cloning its target, and an alias, a
|
|
703
|
+
// repeated spread and a recursive residual were each probed and share
|
|
704
|
+
// nothing. The property is already relied on repository-wide, because
|
|
705
|
+
// `canon` walks the same edges with no guard and is computed on every
|
|
706
|
+
// one of these values. A guard here would be a branch nothing can
|
|
707
|
+
// take, which ADR-002 exists to keep out.
|
|
708
|
+
function coverDeclare(
|
|
709
|
+
v: any, path: string[], out: Map<string, any>): void {
|
|
710
|
+
const tpl = coverTemplate(v)
|
|
711
|
+
if (null != tpl) {
|
|
712
|
+
const at = [...path, COVER_TEMPLATE]
|
|
713
|
+
out.set(pathText(at), tpl)
|
|
714
|
+
coverDeclare(tpl, at, out)
|
|
715
|
+
}
|
|
716
|
+
for (const { key, val } of coverKids(v)) {
|
|
717
|
+
const at = [...path, key]
|
|
718
|
+
out.set(pathText(at), val)
|
|
719
|
+
coverDeclare(val, at, out)
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
// Every path in the data, and whether it is a LEAF -- a node with no
|
|
725
|
+
// children, which is where a value lives.
|
|
726
|
+
function coverDataPaths(
|
|
727
|
+
v: any, path: string[],
|
|
728
|
+
out: { path: string, leaf: boolean }[]): void {
|
|
729
|
+
const kids = coverKids(v)
|
|
730
|
+
if (0 < path.length) {
|
|
731
|
+
out.push({ path: pathText(path), leaf: 0 === kids.length })
|
|
732
|
+
}
|
|
733
|
+
for (const { key, val } of kids) {
|
|
734
|
+
coverDataPaths(val, [...path, key], out)
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
// Walk one data path down the schema, naming the declaration that
|
|
740
|
+
// constrains it -- the exact key where the schema has one, else the
|
|
741
|
+
// covering template. Undefined when the schema declares nothing there.
|
|
742
|
+
function coverMatch(
|
|
743
|
+
anchor: any, segs: string[]): string | undefined {
|
|
744
|
+
// NO NIL GUARD ON `at`, and none on an empty `segs`: `at` starts as
|
|
745
|
+
// the anchor and is only ever reassigned to a non-nil child or
|
|
746
|
+
// template, and coverDataPaths never emits the root path, so a call
|
|
747
|
+
// with no segments cannot happen. A guard that cannot fire is dead
|
|
748
|
+
// code, and dead code is what ADR-002 exists to keep out.
|
|
749
|
+
let at: any = anchor
|
|
750
|
+
let decl = ''
|
|
751
|
+
for (const seg of segs) {
|
|
752
|
+
const named = true === at.isMap && null != at.peg ? at.peg[seg]
|
|
753
|
+
: true === at.isList && Array.isArray(at.peg) ? at.peg[Number(seg)]
|
|
754
|
+
: undefined
|
|
755
|
+
if (null != named && true === named.isVal) {
|
|
756
|
+
decl = '' === decl ? seg : decl + '.' + seg
|
|
757
|
+
at = named
|
|
758
|
+
continue
|
|
759
|
+
}
|
|
760
|
+
const tpl = coverTemplate(at)
|
|
761
|
+
if (null == tpl) {
|
|
762
|
+
return undefined
|
|
763
|
+
}
|
|
764
|
+
decl = '' === decl ? COVER_TEMPLATE : decl + '.' + COVER_TEMPLATE
|
|
765
|
+
at = tpl
|
|
766
|
+
}
|
|
767
|
+
return '$.' + decl
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
// The SHALLOWEST members of a set of paths: one whose parent is also in
|
|
772
|
+
// the set is covered by naming the parent, and naming both is noise.
|
|
773
|
+
// `render --coverage`'s `dead` is built on the same rule.
|
|
774
|
+
function coverShallowest(paths: string[]): string[] {
|
|
775
|
+
const held = new Set(paths)
|
|
776
|
+
return paths.filter((p) => {
|
|
777
|
+
for (let at = p; -1 !== at.lastIndexOf('.');) {
|
|
778
|
+
at = at.slice(0, at.lastIndexOf('.'))
|
|
779
|
+
if (held.has(at)) {
|
|
780
|
+
return false
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return true
|
|
784
|
+
}).sort(cmpCodePoint)
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
|
|
788
|
+
// The accounting itself: what the schema declared, what the data holds,
|
|
789
|
+
// and which of each the other met.
|
|
790
|
+
export function vetCoverage(
|
|
791
|
+
anchor: any, dataVal: any, coverageAt?: string): VetCoverage {
|
|
792
|
+
const declarations = new Map<string, any>()
|
|
793
|
+
coverDeclare(anchor, [], declarations)
|
|
794
|
+
|
|
795
|
+
const dataPaths: { path: string, leaf: boolean }[] = []
|
|
796
|
+
coverDataPaths(dataVal, [], dataPaths)
|
|
797
|
+
|
|
798
|
+
// `--coverage-at` narrows the DATA side, which is the side a caller
|
|
799
|
+
// gating one subtree is asking about. The schema side follows from
|
|
800
|
+
// it: a declaration is unused only among the data actually measured.
|
|
801
|
+
const under = null == coverageAt ? undefined
|
|
802
|
+
: coverageAt.replace(/^\$\.?/, '')
|
|
803
|
+
const inScope = (p: string): boolean => {
|
|
804
|
+
if (null == under || '' === under) {
|
|
805
|
+
return true
|
|
806
|
+
}
|
|
807
|
+
const want = '$.' + under
|
|
808
|
+
return p === want || p.startsWith(want + '.')
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
const used = new Set<string>()
|
|
812
|
+
const unchecked: string[] = []
|
|
813
|
+
let checked = 0
|
|
814
|
+
let leaves = 0
|
|
815
|
+
for (const { path, leaf } of dataPaths) {
|
|
816
|
+
if (!inScope(path)) {
|
|
817
|
+
continue
|
|
818
|
+
}
|
|
819
|
+
const segs = path.replace(/^\$\.?/, '').split('.').filter((x) => '' !== x)
|
|
820
|
+
const decl = coverMatch(anchor, segs)
|
|
821
|
+
if (leaf) {
|
|
822
|
+
leaves++
|
|
823
|
+
}
|
|
824
|
+
if (null == decl) {
|
|
825
|
+
unchecked.push(path)
|
|
826
|
+
continue
|
|
827
|
+
}
|
|
828
|
+
used.add(decl)
|
|
829
|
+
if (leaf) {
|
|
830
|
+
checked++
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
// A declaration is met when it constrained a data path, or when a
|
|
835
|
+
// declaration BENEATH it was: `$.a` is used by `$.a.b` meeting
|
|
836
|
+
// `$.a.b`, and reporting the parent as unused would be false.
|
|
837
|
+
const unused: string[] = []
|
|
838
|
+
for (const decl of declarations.keys()) {
|
|
839
|
+
const covered = used.has(decl) ||
|
|
840
|
+
[...used].some((u) => u.startsWith(decl + '.'))
|
|
841
|
+
if (!covered) {
|
|
842
|
+
unused.push(decl)
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
return {
|
|
847
|
+
checked,
|
|
848
|
+
declared: declarations.size,
|
|
849
|
+
leaves,
|
|
850
|
+
unchecked: coverShallowest(unchecked),
|
|
851
|
+
unused: coverShallowest(unused),
|
|
852
|
+
// VACUOUS IS ABOUT LEAVES, and a document with none cannot be
|
|
853
|
+
// vacuously checked: `{}` against any schema examined nothing
|
|
854
|
+
// because there was nothing to examine, which is not the failure
|
|
855
|
+
// this reports.
|
|
856
|
+
vacuous: 0 === checked && 0 < leaves,
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
|
|
599
861
|
export function vet(
|
|
600
862
|
schemaSrc: string, dataSrc: string, opts?: VetOptions): VetReport {
|
|
601
863
|
const options = opts ?? {}
|
|
@@ -729,6 +991,27 @@ export function vet(
|
|
|
729
991
|
dataUrl, dataPath: options.dataPath,
|
|
730
992
|
}
|
|
731
993
|
|
|
994
|
+
// COVERAGE IS MEASURED BEFORE THE MEET (G11 phase 5), because the
|
|
995
|
+
// meet CONSUMES its operands: parsed trees are single-use, and under
|
|
996
|
+
// `--at` the anchor itself is the left operand. Measuring after would
|
|
997
|
+
// read a tree the fixpoint had already rewritten.
|
|
998
|
+
//
|
|
999
|
+
// The data side is its own evaluation rather than the parse above,
|
|
1000
|
+
// so a document that reaches its values through `@"..."` or a
|
|
1001
|
+
// reference is measured on the paths it actually has. It is one more
|
|
1002
|
+
// evaluation of one document, and it happens only when asked for.
|
|
1003
|
+
let coverage: VetCoverage | undefined
|
|
1004
|
+
if (true === options.coverage) {
|
|
1005
|
+
const coverCtx = aontu.ctx({ collect: true })
|
|
1006
|
+
const settledData: any = aontu.unify(dataSrc, dataOpts, coverCtx)
|
|
1007
|
+
// A data document that does not stand alone is already reported by
|
|
1008
|
+
// the meet below; here it falls back to what was parsed, which is
|
|
1009
|
+
// the same paths minus whatever an include would have added.
|
|
1010
|
+
const measured = 0 === coverCtx.err.length && true !== settledData?.isNil
|
|
1011
|
+
? settledData : dataVal
|
|
1012
|
+
coverage = vetCoverage(anchor, measured, options.coverageAt)
|
|
1013
|
+
}
|
|
1014
|
+
|
|
732
1015
|
// Default-validity lint (G3 phase 5, re-examined under ADR-004): for
|
|
733
1016
|
// every disjunction in the SCHEMA carrying a preference, warn when
|
|
734
1017
|
// the effective default is not an instance of any REMAINING
|
|
@@ -1031,5 +1314,8 @@ export function vet(
|
|
|
1031
1314
|
verdict = 'incomplete'
|
|
1032
1315
|
}
|
|
1033
1316
|
|
|
1034
|
-
return {
|
|
1317
|
+
return {
|
|
1318
|
+
verdict, truncated, findings: kept,
|
|
1319
|
+
...(null == coverage ? {} : { coverage }),
|
|
1320
|
+
}
|
|
1035
1321
|
}
|
package/src/val/FormFuncVal.ts
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
-
|
|
3
|
-
// TRANSFORMATION: `form(data, tmpl)` (G9 §4; docs/design/RENDER.0.md
|
|
4
|
-
// D11 and P6). One element of the result list per child of `data`,
|
|
5
|
-
// being `tmpl` instantiated at that position with `_` bound to the
|
|
6
|
-
// source child. It REPLACES; it does not meet.
|
|
7
|
-
//
|
|
8
|
-
// names: [web, auth]
|
|
9
|
-
// units: form($.names, {path: _ + ".ts"}) -> [{path: "web.ts"}, {path: "auth.ts"}]
|
|
10
|
-
//
|
|
11
|
-
// WHY BESIDE `each`. `each($.ports, integer)` is a schema statement
|
|
12
|
-
// and is monotone -- more information about the template narrows the
|
|
13
|
-
// children -- so it is a lattice citizen, and a constructor is not.
|
|
14
|
-
// The language draws this line twice already: `min`/`max` (bounds)
|
|
15
|
-
// against `least`/`greatest` (aggregates), and `filter` (select by
|
|
16
|
-
// unifiability) against `match` (choose a result). `each` is the
|
|
17
|
-
// bound; `form` is the construction. `each` also carries the source
|
|
18
|
-
// child's identity (its clone keeps the entity), where `form`'s
|
|
19
|
-
// element IS the template.
|
|
20
|
-
//
|
|
21
|
-
// WHY IT EXISTS AT ALL: ORDER. `pick(pack(d, {f: t}), f)` maps too,
|
|
22
|
-
// but it goes through a map and re-sorts to code-point order, and it
|
|
23
|
-
// refuses a list of records outright (pack_key). A struct's fields, a
|
|
24
|
-
// DDL's columns and a file's imports are lists whose order is the
|
|
25
|
-
// model's, and silently alphabetising them is wrong output. `form`
|
|
26
|
-
// reads its members through the one ordering helper `each` uses
|
|
27
|
-
// (members.ts), so the two can never disagree about order -- source
|
|
28
|
-
// order for a list, sorted-key order for a map -- and skips what
|
|
29
|
-
// generation would not emit: a hidden child, an unfilled optional.
|
|
30
|
-
//
|
|
31
|
-
// It joins `boundArgStart` (PlaceVal.ts): a `_` inside its template
|
|
32
|
-
// is ITS hole to bind, never an outer generator's. Forgetting that is
|
|
33
|
-
// BUGS.md §34's silent failure -- every existing test passes and the
|
|
34
|
-
// new combinator captures an outer generator's hole -- which is why
|
|
35
|
-
// the shared spec's nesting rows exist.
|
|
36
|
-
|
|
37
|
-
import type {
|
|
38
|
-
Val,
|
|
39
|
-
ValSpec,
|
|
40
|
-
} from '../type'
|
|
41
|
-
|
|
42
|
-
import {
|
|
43
|
-
AontuContext,
|
|
44
|
-
} from '../ctx'
|
|
45
|
-
|
|
46
|
-
import { makeNilErr } from '../err'
|
|
47
|
-
import { ListVal } from './ListVal'
|
|
48
|
-
import { FuncBaseVal } from './FuncBaseVal'
|
|
49
|
-
import { repathInstance } from './Val'
|
|
50
|
-
import { fillPlace } from './PlaceVal'
|
|
51
|
-
import { memberVals } from './members'
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class FormFuncVal extends FuncBaseVal {
|
|
55
|
-
isFormFunc = true
|
|
56
|
-
|
|
57
|
-
// THE STAGING RULE, for the reason given in PackFuncVal: the data
|
|
58
|
-
// is not settled merely by being `done` once.
|
|
59
|
-
staged = true
|
|
60
|
-
|
|
61
|
-
constructor(
|
|
62
|
-
spec: ValSpec,
|
|
63
|
-
ctx?: AontuContext
|
|
64
|
-
) {
|
|
65
|
-
super(spec, ctx)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
funcname() {
|
|
70
|
-
return 'form'
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// The template is not an argument to drive (see PackFuncVal.prepare).
|
|
75
|
-
prepare(_ctx: AontuContext, _args: Val[]) {
|
|
76
|
-
return null
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
unify(peer: Val, ctx: AontuContext): Val {
|
|
81
|
-
// ONE argument is driven: the data. The template is not (see
|
|
82
|
-
// prepare above).
|
|
83
|
-
if (!this.stagedReady(peer, ctx, 1)) {
|
|
84
|
-
return this.residuate(peer, ctx)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return super.unify(peer, ctx)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
resolve(ctx: AontuContext, args: Val[]) {
|
|
92
|
-
const vals = memberVals(args?.[0], ctx)
|
|
93
|
-
if (undefined === vals) {
|
|
94
|
-
return makeNilErr(ctx, 'form_data', this)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Arity is checked at parse (funcArity), so the template is here.
|
|
98
|
-
const tmpl: Val = args[1]
|
|
99
|
-
const peg: Val[] = []
|
|
100
|
-
|
|
101
|
-
for (let i = 0; i < vals.length; i++) {
|
|
102
|
-
const elctx = ctx.descend(String(i))
|
|
103
|
-
// A FULL INSTANCE per element, to the leaves (`dup`, ADR-005),
|
|
104
|
-
// at the element's own position -- see PackFuncVal.resolve --
|
|
105
|
-
// with `_` bound to the source child and NOTHING met into it.
|
|
106
|
-
const inst = tmpl.clone(elctx, { dup: true })
|
|
107
|
-
repathInstance(inst, inst.path)
|
|
108
|
-
peg.push(fillPlace(inst, vals[i], elctx))
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return new ListVal({ peg }, ctx)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
} /* node:coverage ignore next 6 */
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
export {
|
|
118
|
-
FormFuncVal,
|
|
119
|
-
}
|