aontu 0.55.0 → 0.57.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 +10 -3
- package/dist/agentsmd.js.map +1 -1
- package/dist/aontu.d.ts +4 -2
- package/dist/aontu.js +5 -2
- package/dist/aontu.js.map +1 -1
- package/dist/cli.d.ts +10 -3
- package/dist/cli.js +311 -53
- package/dist/cli.js.map +1 -1
- package/dist/diff.d.ts +1 -0
- package/dist/diff.js +3 -2
- package/dist/diff.js.map +1 -1
- package/dist/escape.d.ts +5 -0
- package/dist/escape.js +455 -0
- package/dist/escape.js.map +1 -0
- package/dist/format.d.ts +26 -0
- package/dist/format.js +1489 -0
- package/dist/format.js.map +1 -0
- package/dist/hints.js +39 -1
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.d.ts +1 -0
- package/dist/jsonschema.js +3 -2
- package/dist/jsonschema.js.map +1 -1
- package/dist/lang.js +84 -6
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +2 -1
- package/dist/lsp.js +4 -4
- package/dist/lsp.js.map +1 -1
- package/dist/mcp-server.js +2 -2
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp.js +6 -4
- package/dist/mcp.js.map +1 -1
- package/dist/mod-tool.js +8 -7
- package/dist/mod-tool.js.map +1 -1
- package/dist/mod.js +6 -6
- package/dist/mod.js.map +1 -1
- package/dist/patch.d.ts +1 -0
- package/dist/patch.js +1 -0
- package/dist/patch.js.map +1 -1
- package/dist/query.d.ts +1 -0
- package/dist/query.js +4 -3
- package/dist/query.js.map +1 -1
- package/dist/reach.d.ts +1 -0
- package/dist/reach.js +3 -2
- package/dist/reach.js.map +1 -1
- package/dist/relation.d.ts +1 -0
- package/dist/relation.js +3 -2
- package/dist/relation.js.map +1 -1
- package/dist/sigdecl.js +1 -1
- package/dist/sigdecl.js.map +1 -1
- package/dist/std.js +2 -1
- package/dist/std.js.map +1 -1
- package/dist/subsume.d.ts +1 -0
- package/dist/subsume.js +3 -2
- package/dist/subsume.js.map +1 -1
- package/dist/trim.d.ts +1 -0
- package/dist/trim.js +3 -2
- package/dist/trim.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.d.ts +1 -0
- package/dist/type.js.map +1 -1
- package/dist/utility.d.ts +8 -2
- package/dist/utility.js +9 -1
- package/dist/utility.js.map +1 -1
- package/dist/val/EachFuncVal.js +1 -2
- package/dist/val/EachFuncVal.js.map +1 -1
- package/dist/val/EmitFuncVal.d.ts +23 -0
- package/dist/val/EmitFuncVal.js +261 -0
- package/dist/val/EmitFuncVal.js.map +1 -0
- package/dist/val/FilterFuncVal.js +1 -2
- package/dist/val/FilterFuncVal.js.map +1 -1
- package/dist/val/FuncBaseVal.d.ts +1 -0
- package/dist/val/FuncBaseVal.js +16 -0
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/PackFuncVal.js +1 -2
- package/dist/val/PackFuncVal.js.map +1 -1
- package/dist/val/PlaceVal.d.ts +3 -1
- package/dist/val/PlaceVal.js +8 -6
- package/dist/val/PlaceVal.js.map +1 -1
- package/dist/val/StrFuncVal.d.ts +32 -0
- package/dist/val/StrFuncVal.js +292 -0
- package/dist/val/StrFuncVal.js.map +1 -0
- package/dist/vet.d.ts +1 -0
- package/dist/vet.js +1 -1
- package/dist/vet.js.map +1 -1
- package/dist/view.d.ts +2 -1
- package/dist/view.js +379 -8
- package/dist/view.js.map +1 -1
- package/grammar/aontu.abnf +156 -0
- package/grammar/aontu.gbnf +4 -3
- package/grammar/aontu.lark +4 -3
- package/grammar/aontu.tmLanguage.json +1 -1
- package/package.json +2 -1
- package/skill/grammar-card.md +5 -2
- package/src/agentsmd.ts +15 -3
- package/src/aontu.ts +8 -1
- package/src/cli.ts +365 -58
- package/src/diff.ts +7 -2
- package/src/escape.ts +371 -0
- package/src/format.ts +1728 -0
- package/src/hints.ts +53 -1
- package/src/jsonschema.ts +7 -1
- package/src/lang.ts +93 -6
- package/src/lsp.ts +8 -6
- package/src/mcp-server.ts +3 -2
- package/src/mcp.ts +6 -4
- package/src/mod-tool.ts +9 -8
- package/src/mod.ts +6 -6
- package/src/patch.ts +7 -0
- package/src/query.ts +8 -4
- package/src/reach.ts +7 -2
- package/src/relation.ts +7 -2
- package/src/sigdecl.ts +1 -1
- package/src/std.ts +2 -1
- package/src/subsume.ts +7 -2
- package/src/trim.ts +7 -2
- package/src/type.ts +8 -0
- package/src/utility.ts +27 -2
- package/src/val/EachFuncVal.ts +1 -3
- package/src/val/EmitFuncVal.ts +401 -0
- package/src/val/FilterFuncVal.ts +1 -3
- package/src/val/FuncBaseVal.ts +18 -0
- package/src/val/PackFuncVal.ts +1 -3
- package/src/val/PlaceVal.ts +8 -6
- package/src/val/StrFuncVal.ts +334 -0
- package/src/vet.ts +9 -3
- package/src/view.ts +442 -9
package/src/hints.ts
CHANGED
|
@@ -192,6 +192,8 @@ const hints: Record<string, string> = {
|
|
|
192
192
|
view_kind_unknown: 'The figure kind is not one the verb draws. The kinds are tree, matrix,\ngraph, layer, sets, layers, ladder and poset; the note lists them.',
|
|
193
193
|
|
|
194
194
|
view_profile_unknown: 'The figure kind does not render into the profile asked for: there is no\ntext form of a node-link drawing and no Mermaid form of a matrix. The\nnote lists the profiles the kind declares; the first is its default.',
|
|
195
|
+
|
|
196
|
+
format_check: 'The formatted text is not the same document, so nothing was written.\nThis is a formatter defect: please report it, with the source.',
|
|
195
197
|
view_style_profile: 'Each profile has ONE way to carry the meaning of a figure\'s marks:\nSGR escapes for text, CSS classes for svg. Asking for the other one is\na usage error rather than a silent no-op. `none` works everywhere.',
|
|
196
198
|
view_style_unknown: 'The styles are none, ansi and css, plus `auto` at the command line,\nwhich the command resolves before the library runs: whether the\ndestination is a terminal is not something a library can see.',
|
|
197
199
|
|
|
@@ -220,11 +222,33 @@ const hints: Record<string, string> = {
|
|
|
220
222
|
|
|
221
223
|
match_none: 'No pattern matched, and there is no default. `match` tries each\npattern in the order written and takes the first the value unifies\nwith; the value {value} unified with none of {tried}. Add a trailing\ndefault — the argument after the last pair — if the rest was meant\nto be allowed.\n \nExamples:\n match(1, integer, ok) -> "ok" # The first pattern matches;\n match(x, integer, ok, other) -> "other" # ... or the default does;\n match(x, integer, ok) -> nil # ... but nothing here does.',
|
|
222
224
|
|
|
225
|
+
emit_data: 'The first argument to emit() is not a bag. `emit` visits the\nchildren of its SELECTION, so the selection has to have children: a\nlist of nodes, or a map whose values are the nodes.\n \nExamples:\n emit([{k:1}], {match:{k:1},body:[a]}) -> [..] # A list of nodes;\n emit({x:{k:1}}, {match:{k:1},body:[a]}) -> [..] # ... or a map of them;\n emit(1, {match:{k:1},body:[a]}) -> nil # ... but not a scalar.',
|
|
226
|
+
|
|
227
|
+
emit_table: 'The second argument to emit() is not a rule table. A table is a\nLIST of templates, tried in order; a single template may be written\nas the map itself, which is that list of one.\n \nExamples:\n emit($.n, [{match:integer,body:[a]}]) -> [..] # A table of rules;\n emit($.n, {match:integer,body:[a]}) -> [..] # ... or one rule alone;\n emit($.n, integer) -> nil # ... but not a value.',
|
|
228
|
+
|
|
229
|
+
emit_template: 'A template in an emit() table is not a rule. Every rule is a map\nnaming both a `match` — the pattern the node is tried against — and a\n`body`, the pieces to emit. A rule with no pattern would claim every\nnode by accident; one with no body would claim a node and emit\nnothing.\n \nExamples:\n {match: {kind: sqs}, body: [a]} # A rule;\n {match: {kind: sqs}} # ... but a pattern is not one;\n {body: [a]} # ... nor is a body alone.',
|
|
230
|
+
|
|
231
|
+
emit_body: 'A template body in an emit() table is not a list. A body is the\nSEQUENCE of pieces the matched node emits, so it is written as a\nlist even when it holds one piece — which is what lets bodies\ncompose, since a body element that is itself a list splices.\n \nExamples:\n {match: integer, body: [a]} -> [..] # One piece;\n {match: integer, body: [a,b]} -> [..] # ... or several;\n {match: integer, body: a} -> nil # ... but not a bare value.',
|
|
232
|
+
|
|
233
|
+
emit_ref: 'A template body names {ref}, and the node it matched cannot\nanswer it. Inside a body a relative reference is a field of the\nMATCHED NODE — `.pin` is that node\'s `pin` — so the node has to have\nthe field; the node was {value}. An absolute reference (`$.x`) reads\nthe document root instead, and is untouched.\n \nExamples:\n {match:{pin:string}, body:[.pin]} -> [..] # A field of the node;\n {match:{pin:string}, body:[$.z]} -> [..] # ... or the root;\n {match:{pin:string}, body:[.port]} -> nil # ... but not a field it\n # has not got.',
|
|
234
|
+
|
|
235
|
+
emit_none: 'No template matched a node, and there is no catch-all. `emit`\ntries each template in the order written and takes the first the\nnode unifies with; the node {value} unified with none of {tried}.\nAdd a template whose `match` is `any` — last, since the first match\nwins — if the rest of the selection was meant to be allowed.\n \nExamples:\n emit([1], [{match:integer,body:[a]}]) -> [..] # A pattern matches;\n emit([x], [{match:any,body:[a]}]) -> [..] # ... or a catch-all;\n emit([x], [{match:integer,body:[a]}]) -> nil # ... but nothing here.',
|
|
236
|
+
|
|
237
|
+
esc_variant: 'esc() and usc() were given a variant that names no convention.\nA variant names a CONVENTION rather than a language, because several\nlanguages share one and one language has several. The names are `sq`,\n`sql`, `shell`, `xml`, `uri` and `regex`; written with no variant at\nall it is the C escape, JSON canonical, which covers the double-quoted\nliteral of every C-family language.\n \nExamples:\n esc(text) -> ... # C / JSON, the default;\n esc(text, sq) -> ... # ... single-quoted C-family;\n esc(text, pascal) -> nil # ... but that is not a convention.',
|
|
238
|
+
|
|
239
|
+
usc_malformed: 'usc() was given text the convention could not have produced,\nso there is nothing to read back out: a truncated code-point escape, an\nescape the convention does not define, or an escape character standing\nalone where the convention doubles it. `usc` is the LEFT inverse of\n`esc` and it is partial — every escaped value has an original, but not\nevery string is an escaped value.\n \nExamples:\n usc(esc(text)) -> ... # Whatever esc() wrote;\n usc(text, sql) -> ... # ... in the same convention;\n usc(text, shell) -> nil # ... but not in another one.',
|
|
240
|
+
|
|
241
|
+
rep_pattern: 'The pattern given to rep() is outside the portable subset. It is\nthe same subset re() takes — RE2-compatible, no backreferences, no\nlookaround — so one document has one regexp language rather than two,\nand so a generator running a pattern over model data cannot take\nexponential time doing it.\n \nExamples:\n rep(s, "[:,]", " ") -> ... # A class;\n rep(s, "(a)(b)", "$2$1") -> ... # ... a group;\n rep(s, "(?=a)", "x") -> nil # ... but not a lookahead.',
|
|
242
|
+
|
|
243
|
+
rep_sub: 'The substitution given to rep() names something the pattern has\nnot got. `$1` to `$9` are the numbered groups, `$&` is the whole match\nand `$$` is a literal `$`; a `$` naming anything else, or a group\nnumber the pattern does not have, is refused rather than expanded to\nnothing — a generator that writes a file with a hole in it and says\nnothing is the failure this refusal exists to close.\n \nExamples:\n rep(s, "(a)", "[$1]") -> ... # A group the pattern has;\n rep(s, "a", "$$") -> ... # ... a literal dollar;\n rep(s, "a", "$1") -> nil # ... but not a group it has not.',
|
|
244
|
+
|
|
245
|
+
split_sep: 'The separator given to split() is neither a string nor a pattern.\nA plain string is a LITERAL and an `re(…)` argument is a pattern — the\nasymmetry with rep() is deliberate, since splitting is usually on a\nliteral, and it removes the trap where `split(v, ".")` silently cuts\nbetween every character.\n \nExamples:\n split("a,b", ",") -> [..] # A literal separator;\n split("a1b", re("[0-9]")) -> [..] # ... or a pattern;\n split("a,b", 1) -> nil # ... but not a number.',
|
|
246
|
+
|
|
223
247
|
place_pair: 'Two placeholders met, and neither has a value to fill the other.\n`_` is a HOLE: it is filled by whatever the call is unified with, so\na call holding one needs a peer that does not. Give one side a\nvalue.\n \nExamples:\n upper(_) & hello -> "HELLO" # The peer fills the hole;\n _ + 2 & 1 -> 3 # ... whatever the call is;\n upper(_) & lower(_) -> nil # ... but two holes fill nothing.',
|
|
224
248
|
|
|
225
249
|
|
|
226
250
|
module_path: 'A module import is domain-shaped and carries a major, but its\npath cannot be a directory on every platform the toolchain runs on --\nso it is refused before anything is built from it. An element may not\nbe empty, may not begin or end with `.` (which is what forbids `..`),\nand may not be a reserved device name. These are Go\'s module-path\nrules, for Go\'s reason: a module path becomes a real directory.\n \nExamples:\n @"corp.example/s@1" -> {..} # An ordinary path is fine;\n @"corp.example/../s@1" -> nil # ... `..` would escape the store;\n @"corp.example/nul@1" -> nil # ... and Windows has no such file.',
|
|
227
|
-
module_missing: 'A module import names a module that is not in this project. A\nmodule is resolved from LOCAL stores only -- `
|
|
251
|
+
module_missing: 'A module import names a module that is not in this project. A\nmodule is resolved from LOCAL stores only -- `aontu_meta/vendor/` beside the\nproject\'s mod.aon, then the user cache -- because evaluation never\ntouches the network. Fetching is a separate step, and the message\nnames it.\n \nExamples:\n @"corp.example/s@1" -> nil # Not fetched: run aontu mod get;\n @"./local.aon" -> {..} # ... a local path is not a module;\n @"corp.example/s@1#aon1-…" -> {..} # ... and a pin does not fetch it either.',
|
|
228
252
|
|
|
229
253
|
module_integrity: 'A module resolved locally does not have the MEANING it was pinned\nto. The pin is a canon-hash -- the hash of the module unified\nstandalone -- so it survives comments, formatting and refactoring and\nbreaks on any semantic change in the module\'s transitive closure.\nVerification is always local: the registry\'s annotation is advisory.\n \nExamples:\n @"corp.example/s@1" -> {..} # No pin, no check;\n @"corp.example/s@1#aon1-x" -> nil # ... a pin that disagrees refuses;\n aontu hash <file> # ... and this is what it should be.',
|
|
230
254
|
|
|
@@ -513,6 +537,9 @@ const codeClasses: Record<string, string> = {
|
|
|
513
537
|
view_profile_unknown: 'reference',
|
|
514
538
|
view_style_profile: 'reference',
|
|
515
539
|
view_style_unknown: 'reference',
|
|
540
|
+
// The formatter's self-check (docs/design/FMT.0.md): a report-layer
|
|
541
|
+
// code, class internal -- the formatter, not the document, is wrong.
|
|
542
|
+
format_check: 'internal',
|
|
516
543
|
view_rows_exceeded: 'budget',
|
|
517
544
|
view_line_break: 'parse',
|
|
518
545
|
view_relation_ambiguous: 'reference',
|
|
@@ -544,6 +571,31 @@ const codeClasses: Record<string, string> = {
|
|
|
544
571
|
filter_data: 'parse',
|
|
545
572
|
match_none: 'conflict',
|
|
546
573
|
|
|
574
|
+
// G9 phase 6 -- the string builtins. All five are class `parse`:
|
|
575
|
+
// what is wrong is the CALL as written -- a variant that names no
|
|
576
|
+
// convention, a pattern outside the subset, a substitution naming a
|
|
577
|
+
// group that does not exist, a separator that is neither string nor
|
|
578
|
+
// pattern. `usc_malformed` is the odd one and still `parse`: the
|
|
579
|
+
// TEXT the call was given has no inverse, which is a fact about the
|
|
580
|
+
// argument rather than about any meet.
|
|
581
|
+
esc_variant: 'parse',
|
|
582
|
+
usc_malformed: 'parse',
|
|
583
|
+
rep_pattern: 'parse',
|
|
584
|
+
rep_sub: 'parse',
|
|
585
|
+
split_sep: 'parse',
|
|
586
|
+
|
|
587
|
+
// G9 phase 6 -- apply-templates. The four shape codes are class
|
|
588
|
+
// `parse`: what is wrong is the CALL as written -- a selection with
|
|
589
|
+
// no children, a table that is not one, a rule missing a half.
|
|
590
|
+
// `emit_none` is class `conflict` for `match_none`'s reason: the
|
|
591
|
+
// node and every pattern written for it disagreed.
|
|
592
|
+
emit_data: 'parse',
|
|
593
|
+
emit_table: 'parse',
|
|
594
|
+
emit_template: 'parse',
|
|
595
|
+
emit_body: 'parse',
|
|
596
|
+
emit_none: 'conflict',
|
|
597
|
+
emit_ref: 'conflict',
|
|
598
|
+
|
|
547
599
|
// G8 phase 3 -- the placeholder. Class `conflict`: two values met
|
|
548
600
|
// and neither could answer for the other, which is what every
|
|
549
601
|
// conflict is.
|
package/src/jsonschema.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
import { includeOpts } from './utility'
|
|
2
3
|
|
|
3
4
|
// JSON SCHEMA EXPORT (the review's finding I / SUPPORT.md act 2).
|
|
4
5
|
//
|
|
@@ -75,6 +76,11 @@ export type SchemaOptions = {
|
|
|
75
76
|
// its own directory.
|
|
76
77
|
path?: string
|
|
77
78
|
trust?: TrustOptions
|
|
79
|
+
|
|
80
|
+
// Extensions additionally read as text (the CLI's `--text-ext`).
|
|
81
|
+
// Rides beside `trust` because it is the other half of what an
|
|
82
|
+
// include may read.
|
|
83
|
+
textExt?: string[]
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
|
|
@@ -501,7 +507,7 @@ function fromList(ctx: Ctx, path: string[], v: any): any {
|
|
|
501
507
|
// The verb. Evaluate, anchor, walk, report.
|
|
502
508
|
export function jsonSchema(src: string, options?: SchemaOptions): SchemaReport {
|
|
503
509
|
const opts = options ?? {}
|
|
504
|
-
const aontu = new Aontu(
|
|
510
|
+
const aontu = new Aontu(includeOpts(opts))
|
|
505
511
|
|
|
506
512
|
// COLLECT MODE, so a syntax error arrives on the context rather than
|
|
507
513
|
// as a throw -- the same failure Go's `parseEntry` hands back as an
|
package/src/lang.ts
CHANGED
|
@@ -145,6 +145,10 @@ import { PackFuncVal } from './val/PackFuncVal'
|
|
|
145
145
|
import { EachFuncVal } from './val/EachFuncVal'
|
|
146
146
|
import { FilterFuncVal } from './val/FilterFuncVal'
|
|
147
147
|
import { MatchFuncVal } from './val/MatchFuncVal'
|
|
148
|
+
import { EmitFuncVal } from './val/EmitFuncVal'
|
|
149
|
+
import {
|
|
150
|
+
EscFuncVal, UscFuncVal, RepFuncVal, SplitFuncVal,
|
|
151
|
+
} from './val/StrFuncVal'
|
|
148
152
|
import {
|
|
149
153
|
AddFuncVal, SubFuncVal, MulFuncVal, DivFuncVal, ModFuncVal, RemFuncVal,
|
|
150
154
|
} from './val/ArithFuncVal'
|
|
@@ -667,6 +671,25 @@ help isolate the syntax error.`,
|
|
|
667
671
|
// the language does not grow a second. It is the primitive that
|
|
668
672
|
// turns a bag of computed lines into a file.
|
|
669
673
|
join: JoinFuncVal,
|
|
674
|
+
|
|
675
|
+
// G9 phase 6: apply-templates. One flat list of pieces from a
|
|
676
|
+
// selection and a RULE TABLE -- for each node, the first template
|
|
677
|
+
// whose `match` it unifies with, its `body` instantiated at that
|
|
678
|
+
// node. The dispatch is the engine's because a body referenced by
|
|
679
|
+
// path resolves its references at the definition site, and the
|
|
680
|
+
// relative resolution that does exist is a dot count that does not
|
|
681
|
+
// survive a second dispatch (docs/design/EMIT.0.md).
|
|
682
|
+
emit: EmitFuncVal,
|
|
683
|
+
|
|
684
|
+
// G9 phase 6: the string builtins the rule layer needs. `esc`
|
|
685
|
+
// makes a value safe inside a literal and `usc` reads it back;
|
|
686
|
+
// `rep` and `split` derive names from model data. All four are
|
|
687
|
+
// ordinary string functions -- they know nothing about generation,
|
|
688
|
+
// which is why they can land before the renderer does.
|
|
689
|
+
esc: EscFuncVal,
|
|
690
|
+
usc: UscFuncVal,
|
|
691
|
+
rep: RepFuncVal,
|
|
692
|
+
split: SplitFuncVal,
|
|
670
693
|
}
|
|
671
694
|
|
|
672
695
|
|
|
@@ -1597,6 +1620,14 @@ help isolate the syntax error.`,
|
|
|
1597
1620
|
// references, constraints, its own includes. Two extensions, and they
|
|
1598
1621
|
// are the ones this project owns.
|
|
1599
1622
|
//
|
|
1623
|
+
// `text` — the file's BYTES, as one string scalar. No parser is
|
|
1624
|
+
// chosen, so there is nothing for two ports to disagree about and
|
|
1625
|
+
// nothing in the file that can mean anything: `notes: @"notes.txt"`
|
|
1626
|
+
// is a document loading prose into a string. `.txt` is the only
|
|
1627
|
+
// extension here by default; `AontuOptions.textExt` (the CLI's
|
|
1628
|
+
// `--text-ext`) adds others, because which name a project keeps its
|
|
1629
|
+
// templates under is the project's business, not this table's.
|
|
1630
|
+
//
|
|
1600
1631
|
// A FORMAT NAME — configuration DATA, parsed by that format's own
|
|
1601
1632
|
// parser into the JSON value it denotes, which then becomes Aontu
|
|
1602
1633
|
// values like any other data. Every one of these formats maps onto
|
|
@@ -1628,8 +1659,43 @@ const INCLUDE_KINDS: { [kind: string]: string } = {
|
|
|
1628
1659
|
yaml: 'yaml',
|
|
1629
1660
|
yml: 'yaml',
|
|
1630
1661
|
ini: 'ini',
|
|
1662
|
+
|
|
1663
|
+
txt: 'text',
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
|
|
1667
|
+
// WHAT AN EXTENSION MEANS, for this parse. The table is the fixed
|
|
1668
|
+
// part; `textExt` is the per-parse widening, and it wins over nothing
|
|
1669
|
+
// -- a host cannot re-read `.toml` as text, because an extension the
|
|
1670
|
+
// table already names has a meaning documents rely on. Undefined is
|
|
1671
|
+
// the refusal, and it is the ONE place that decides it: the resolver's
|
|
1672
|
+
// gate and the processor map both ask here, so a widening cannot reach
|
|
1673
|
+
// one and not the other.
|
|
1674
|
+
function includeFormat(
|
|
1675
|
+
ext: string, textExt?: string[]): string | undefined {
|
|
1676
|
+
const known = INCLUDE_KINDS[ext]
|
|
1677
|
+
if (undefined !== known) {
|
|
1678
|
+
return known
|
|
1679
|
+
}
|
|
1680
|
+
// NOT EVEN AS TEXT. `.js` is the extension ADR-012 singles out
|
|
1681
|
+
// because multisource's own default EXECUTES it, and an extension
|
|
1682
|
+
// this project refuses on purpose stays refused however a flag is
|
|
1683
|
+
// spelled -- reading it is harmless, but a widening that can reach
|
|
1684
|
+
// the one name the rule names is a widening whose limit nobody can
|
|
1685
|
+
// state. Go's includeFormat holds the same list, and the two CLIs
|
|
1686
|
+
// are diffed on `--text-ext js` because they once disagreed here.
|
|
1687
|
+
if (REFUSED_EXT.has(ext)) {
|
|
1688
|
+
return undefined
|
|
1689
|
+
}
|
|
1690
|
+
return textExt?.includes(ext) ? 'text' : undefined
|
|
1631
1691
|
}
|
|
1632
1692
|
|
|
1693
|
+
|
|
1694
|
+
// Extensions no widening may reach. `js` executes under multisource's
|
|
1695
|
+
// default processor; `''` is the no-extension fallback, which names no
|
|
1696
|
+
// file type at all.
|
|
1697
|
+
const REFUSED_EXT = new Set(['js', ''])
|
|
1698
|
+
|
|
1633
1699
|
// `.csv` IS DELIBERATELY ABSENT, and the reason is ADR-001 rather than
|
|
1634
1700
|
// taste. The two ports' CSV parsers disagree about what a CSV file IS:
|
|
1635
1701
|
// one answers header-keyed records with string fields, the other raw
|
|
@@ -1754,13 +1820,20 @@ const dataProcessor = (format: string) => (res: any) => {
|
|
|
1754
1820
|
res.val = rawToVal(DATA_READERS[format](res.src, res.path))
|
|
1755
1821
|
}
|
|
1756
1822
|
|
|
1823
|
+
// TEXT IS NOT PARSED. The bytes multisource read are the value, so
|
|
1824
|
+
// this is the one processor with no reader behind it -- which is why
|
|
1825
|
+
// a `.txt` include cannot fail on content, only on being unreadable.
|
|
1826
|
+
const textProcessor = (res: any) => {
|
|
1827
|
+
res.val = new StringVal({ peg: res.src })
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1757
1830
|
/**
|
|
1758
1831
|
* The multisource processor map, built FROM the include table so the
|
|
1759
1832
|
* two cannot drift: every extension the table names gets the reader
|
|
1760
1833
|
* the table names for it, and the two kinds that are not in the table
|
|
1761
1834
|
* refuse.
|
|
1762
1835
|
*/
|
|
1763
|
-
function includeProcessors(): { [kind: string]: any } {
|
|
1836
|
+
function includeProcessors(textExt?: string[]): { [kind: string]: any } {
|
|
1764
1837
|
const map: { [kind: string]: any } = {
|
|
1765
1838
|
// multisource's fallback for an extension no entry names, so it is
|
|
1766
1839
|
// the one that catches whatever the resolver's gate did not.
|
|
@@ -1769,9 +1842,23 @@ function includeProcessors(): { [kind: string]: any } {
|
|
|
1769
1842
|
js: refuseProcessor,
|
|
1770
1843
|
}
|
|
1771
1844
|
const source = makeJsonicProcessor()
|
|
1845
|
+
const forKind = (kind: string) => {
|
|
1846
|
+
const format = includeFormat(kind, textExt)
|
|
1847
|
+
if ('source' === format) return source
|
|
1848
|
+
if ('text' === format) return textProcessor
|
|
1849
|
+
return dataProcessor(format as string)
|
|
1850
|
+
}
|
|
1772
1851
|
for (const kind of Object.keys(INCLUDE_KINDS)) {
|
|
1773
|
-
|
|
1774
|
-
|
|
1852
|
+
map[kind] = forKind(kind)
|
|
1853
|
+
}
|
|
1854
|
+
// A WIDENING NEVER OVERWRITES. `js` and the empty fallback refuse
|
|
1855
|
+
// above and stay refusing: `--text-ext js` would otherwise turn the
|
|
1856
|
+
// one extension ADR-012 singles out into a readable one, by a flag
|
|
1857
|
+
// whose whole promise is that it chooses no parser.
|
|
1858
|
+
for (const ext of textExt ?? []) {
|
|
1859
|
+
if (undefined === map[ext]) {
|
|
1860
|
+
map[ext] = textProcessor
|
|
1861
|
+
}
|
|
1775
1862
|
}
|
|
1776
1863
|
return map
|
|
1777
1864
|
}
|
|
@@ -1893,7 +1980,7 @@ function makeModelResolver(options: any) {
|
|
|
1893
1980
|
// module legs do not: both state `kind: 'aon'` because what they
|
|
1894
1981
|
// serve is Aontu source by construction, not by its spelling.
|
|
1895
1982
|
const gateExtension = (path: string, full: string): void => {
|
|
1896
|
-
if (undefined ===
|
|
1983
|
+
if (undefined === includeFormat(extKindOf(full), options.textExt)) {
|
|
1897
1984
|
refuseExtension(path, full)
|
|
1898
1985
|
}
|
|
1899
1986
|
}
|
|
@@ -2001,7 +2088,7 @@ function makeModelResolver(options: any) {
|
|
|
2001
2088
|
const found = resolveModule(modref, from, modFs(ctx), {
|
|
2002
2089
|
// The user cache lives outside any confinement root, so it is
|
|
2003
2090
|
// consulted only when nothing confines this evaluation. A
|
|
2004
|
-
// rooted profile sees the project's own `
|
|
2091
|
+
// rooted profile sees the project's own `aontu_meta/vendor/` and
|
|
2005
2092
|
// nothing else, which is what `root` means.
|
|
2006
2093
|
...(null == rootDir ? { cache: modCache(options) } : {}),
|
|
2007
2094
|
eval: options.mod?.eval,
|
|
@@ -2308,7 +2395,7 @@ class Lang {
|
|
|
2308
2395
|
// (BUGS §49b). Its `js` entry EXECUTES the file, which is not
|
|
2309
2396
|
// something an extension should be able to ask for. And its
|
|
2310
2397
|
// fallback hands any other file back as TEXT.
|
|
2311
|
-
processor: includeProcessors()
|
|
2398
|
+
processor: includeProcessors(this.opts.textExt)
|
|
2312
2399
|
})
|
|
2313
2400
|
.use(AontuJsonic)
|
|
2314
2401
|
}
|
package/src/lsp.ts
CHANGED
|
@@ -21,7 +21,9 @@ import type { Val } from './type'
|
|
|
21
21
|
import { Aontu, VERSION } from './aontu'
|
|
22
22
|
import { getHint } from './err'
|
|
23
23
|
import { collectNils } from './walk'
|
|
24
|
-
import { collectDeprecations, deprecationMessage
|
|
24
|
+
import { collectDeprecations, deprecationMessage,
|
|
25
|
+
includeOpts,
|
|
26
|
+
} from './utility'
|
|
25
27
|
import { why } from './query'
|
|
26
28
|
import type { WhyConjunct } from './provenance'
|
|
27
29
|
|
|
@@ -84,13 +86,13 @@ type OutMessage = {
|
|
|
84
86
|
// functions, syntax errors) produce diagnostics.
|
|
85
87
|
function computeDiagnostics(
|
|
86
88
|
src: string,
|
|
87
|
-
opts?: { vars?: Record<string, Val>, trust?: any }
|
|
89
|
+
opts?: { vars?: Record<string, Val>, trust?: any, textExt?: string[] }
|
|
88
90
|
): Diagnostic[] {
|
|
89
91
|
// The trust profile (G5, docs/trust.md): the LSP is the
|
|
90
92
|
// highest-exposure surface — merely OPENING a hostile .aon file in an
|
|
91
93
|
// editor performs its reads — so the handler confines evaluation to
|
|
92
94
|
// the workspace root and threads the profile through here.
|
|
93
|
-
const aontu = new Aontu(
|
|
95
|
+
const aontu = new Aontu(includeOpts(opts ?? {}))
|
|
94
96
|
|
|
95
97
|
let root: any
|
|
96
98
|
let ac: any
|
|
@@ -525,13 +527,13 @@ const COMPLETION_KEYWORD = 14
|
|
|
525
527
|
// between G4 phases 1/2 and G8 phase 1.
|
|
526
528
|
const BUILTIN_FUNCS = [
|
|
527
529
|
'above', 'acyclic', 'add', 'below', 'close', 'copy', 'deprecate', 'div',
|
|
528
|
-
'each',
|
|
530
|
+
'each', 'emit', 'esc',
|
|
529
531
|
'filter', 'greatest',
|
|
530
532
|
'hide', 'inverse', 'join', 'key', 'least', 'length', 'list', 'lower',
|
|
531
533
|
'map', 'match', 'max', 'min', 'mod', 'move', 'mul', 'must', 'neq', 'open',
|
|
532
534
|
'pack', 'path', 'pick',
|
|
533
|
-
'pref', 're', 'refer', 'rel', 'rem', '
|
|
534
|
-
'upper',
|
|
535
|
+
'pref', 're', 'refer', 'rel', 'rem', 'rep', 'split', 'sub', 'sum',
|
|
536
|
+
'super', 'type', 'unique', 'upper', 'usc',
|
|
535
537
|
]
|
|
536
538
|
|
|
537
539
|
// Scalar-kind and literal keywords.
|
package/src/mcp-server.ts
CHANGED
|
@@ -30,9 +30,9 @@ import type { McpRequest, McpResponse } from './mcp'
|
|
|
30
30
|
import { VERSION } from './aontu'
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
const USAGE = 'aontu
|
|
33
|
+
const USAGE = 'aontu mcp - Aontu MCP server (stdio, NDJSON JSON-RPC)\n' +
|
|
34
34
|
'\n' +
|
|
35
|
-
' aontu
|
|
35
|
+
' aontu mcp [--root <dir>]\n' +
|
|
36
36
|
'\n' +
|
|
37
37
|
' --root <dir> Serve <name>Path file arguments and resolve\n' +
|
|
38
38
|
' @"..." includes, confined below <dir>\n' +
|
|
@@ -41,6 +41,7 @@ const USAGE = 'aontu-mcp - Aontu MCP server (stdio, NDJSON JSON-RPC)\n' +
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
// The startup arguments. Parsed here rather than in bin/aontu-mcp.js
|
|
44
|
+
// or the CLI's mcp verb
|
|
44
45
|
// so the parsing is import-testable; unknown options REFUSE rather
|
|
45
46
|
// than warn, because a server whose operator typo'd --root must not
|
|
46
47
|
// come up quietly unconfined.
|
package/src/mcp.ts
CHANGED
|
@@ -459,6 +459,8 @@ const TOOLS: ToolDef[] = [
|
|
|
459
459
|
name: 'view',
|
|
460
460
|
description:
|
|
461
461
|
'Draw a figure of the document as deterministic text. Kinds: ' +
|
|
462
|
+
'doc (the shape of the document itself), lattice (the value ' +
|
|
463
|
+
'lattice, with the document\'s own values placed on it), ' +
|
|
462
464
|
'tree (the dependency tree of a relation), matrix (the ' +
|
|
463
465
|
'dependency matrix, canon or partition order, --closure), graph ' +
|
|
464
466
|
'(node-link, as mermaid, dot or er), layer (the architecture ' +
|
|
@@ -474,8 +476,8 @@ const TOOLS: ToolDef[] = [
|
|
|
474
476
|
kind: {
|
|
475
477
|
type: 'string',
|
|
476
478
|
description:
|
|
477
|
-
'The figure to draw: tree (the default),
|
|
478
|
-
'sets, layers or ladder',
|
|
479
|
+
'The figure to draw: tree (the default), doc, lattice, matrix, ' +
|
|
480
|
+
'graph, layer, sets, layers or ladder',
|
|
479
481
|
},
|
|
480
482
|
as: {
|
|
481
483
|
type: 'string',
|
|
@@ -565,8 +567,8 @@ const TOOLS: ToolDef[] = [
|
|
|
565
567
|
required: ['source'],
|
|
566
568
|
docs: ['source'],
|
|
567
569
|
check: (a) => {
|
|
568
|
-
const kinds = ['doc', 'tree', 'matrix', 'graph', 'layer',
|
|
569
|
-
'layers', 'ladder']
|
|
570
|
+
const kinds = ['doc', 'lattice', 'tree', 'matrix', 'graph', 'layer',
|
|
571
|
+
'sets', 'layers', 'ladder']
|
|
570
572
|
if (null != a.kind && !kinds.includes(a.kind)) {
|
|
571
573
|
return `kind must be one of ${kinds.join(', ')}, not ${JSON.stringify(a.kind)}`
|
|
572
574
|
}
|
package/src/mod-tool.ts
CHANGED
|
@@ -78,7 +78,7 @@ export type ModVerifyReport = {
|
|
|
78
78
|
|
|
79
79
|
export type ModVendorReport = {
|
|
80
80
|
verdict: 'ok' | 'missing'
|
|
81
|
-
// The modules materialised into `
|
|
81
|
+
// The modules materialised into `aontu_meta/vendor/`, sorted.
|
|
82
82
|
vendored: string[]
|
|
83
83
|
// Locked modules present in no store, sorted.
|
|
84
84
|
missing: string[]
|
|
@@ -193,7 +193,7 @@ function usableRef(mod: string): ModuleRef | undefined {
|
|
|
193
193
|
function storeDir(
|
|
194
194
|
root: string, ref: ModuleRef, hash: string, options: ModToolOptions,
|
|
195
195
|
): string | undefined {
|
|
196
|
-
const stores = [moduleDir(pathJoin(root, '
|
|
196
|
+
const stores = [moduleDir(pathJoin(root, 'aontu_meta', 'vendor'), ref)]
|
|
197
197
|
if (null != options.cache && '' !== hash) {
|
|
198
198
|
stores.push(pathJoin(options.cache, hash))
|
|
199
199
|
}
|
|
@@ -203,7 +203,7 @@ function storeDir(
|
|
|
203
203
|
|
|
204
204
|
// The lockfile's entries, as written.
|
|
205
205
|
function readLock(root: string): Record<string, ModLock> {
|
|
206
|
-
const file = pathJoin(root, 'mod-lock.aon')
|
|
206
|
+
const file = pathJoin(root, 'aontu_meta', 'mod-lock.aon')
|
|
207
207
|
if (!existsSync(file)) {
|
|
208
208
|
return {}
|
|
209
209
|
}
|
|
@@ -335,7 +335,8 @@ export function modTidy(root: string, options: ModToolOptions): ModTidyReport {
|
|
|
335
335
|
const uniqueUnevaluable = [...new Set(unevaluable)].sort()
|
|
336
336
|
const held = 0 === uniqueMissing.length && 0 === uniqueUnevaluable.length
|
|
337
337
|
if (held) {
|
|
338
|
-
|
|
338
|
+
mkdirSync(pathJoin(root, 'aontu_meta'), { recursive: true })
|
|
339
|
+
writeFileSync(pathJoin(root, 'aontu_meta', 'mod-lock.aon'),
|
|
339
340
|
LOCK_HEADER + lockText(lock, options) + '\n')
|
|
340
341
|
}
|
|
341
342
|
|
|
@@ -441,14 +442,14 @@ export function modVerify(root: string, options: ModToolOptions):
|
|
|
441
442
|
}
|
|
442
443
|
|
|
443
444
|
|
|
444
|
-
// `aontu mod vendor`: materialise the locked closure into `
|
|
445
|
+
// `aontu mod vendor`: materialise the locked closure into `aontu_meta/vendor/`.
|
|
445
446
|
export function modVendor(root: string, options: ModToolOptions):
|
|
446
447
|
ModVendorReport {
|
|
447
448
|
const locked = readLock(root)
|
|
448
449
|
const vendored: string[] = []
|
|
449
450
|
const missing: string[] = []
|
|
450
451
|
|
|
451
|
-
const vendorRoot = pathJoin(root, '
|
|
452
|
+
const vendorRoot = pathJoin(root, 'aontu_meta', 'vendor')
|
|
452
453
|
|
|
453
454
|
for (const mod of Object.keys(locked).sort()) {
|
|
454
455
|
const ref = usableRef(mod)
|
|
@@ -593,13 +594,13 @@ function majorOf(version: string): string {
|
|
|
593
594
|
|
|
594
595
|
|
|
595
596
|
// Every file of a module's source tree, relative and forward-slashed.
|
|
596
|
-
// `
|
|
597
|
+
// `aontu_meta/vendor/` is excluded: a published module carries its own
|
|
597
598
|
// sources, not a copy of everyone else's -- a consumer resolves the
|
|
598
599
|
// closure itself, and a nested vendor tree would publish the world.
|
|
599
600
|
function layerFiles(dir: string, prefix = ''): string[] {
|
|
600
601
|
const out: string[] = []
|
|
601
602
|
for (const name of readdirSync(dir).sort()) {
|
|
602
|
-
if ('
|
|
603
|
+
if ('aontu_meta' === name) {
|
|
603
604
|
continue
|
|
604
605
|
}
|
|
605
606
|
const full = pathJoin(dir, name)
|
package/src/mod.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// local: @"./fragment.aon" <- unchanged, not a module
|
|
13
13
|
//
|
|
14
14
|
// EVALUATION NEVER TOUCHES THE NETWORK. Resolution reads local stores
|
|
15
|
-
// only: `
|
|
15
|
+
// only: `aontu_meta/vendor/` beside the project's `mod.aon`, then a
|
|
16
16
|
// content-addressed user cache keyed by canon-hash. Fetching is a
|
|
17
17
|
// separate, explicit tool step, and a module that is in neither store
|
|
18
18
|
// is an evaluation error that says so.
|
|
@@ -81,7 +81,7 @@ export function parseModuleRef(spec: string): ModuleRef | undefined {
|
|
|
81
81
|
// `[A-Za-z0-9._-]` admits `..`, and `moduleDir` joins elements with
|
|
82
82
|
// pathJoin, which CLEANS `..` rather than refusing it:
|
|
83
83
|
//
|
|
84
|
-
// moduleDir('/store/
|
|
84
|
+
// moduleDir('/store/aontu_meta/vendor', 'corp.example/../../etc/passwd@1')
|
|
85
85
|
// -> /store/etc/passwd@1
|
|
86
86
|
//
|
|
87
87
|
// `mod vendor` then copied a tree THERE, outside the project entirely,
|
|
@@ -168,9 +168,9 @@ export function moduleDir(store: string, ref: ModuleRef): string {
|
|
|
168
168
|
// root being a directory holding a `mod.aon`. This used to answer with
|
|
169
169
|
// the NEAREST one alone, and the plural is the fix, because a
|
|
170
170
|
// VENDORED MODULE IS A PROJECT INSIDE A PROJECT. A module in
|
|
171
|
-
// `
|
|
171
|
+
// `aontu_meta/vendor/` carries its own `mod.aon`, which stopped the upward
|
|
172
172
|
// walk there, so a nested import resolved against the vendored
|
|
173
|
-
// module's own directory: a tree with no `
|
|
173
|
+
// module's own directory: a tree with no `aontu_meta/vendor/` of its own, and
|
|
174
174
|
// therefore a `module not fetched` for a dependency sitting flat
|
|
175
175
|
// beside it in the CONSUMER's vendor tree — the only layout `mod
|
|
176
176
|
// vendor` produces (use-cases/BUGS.md §31).
|
|
@@ -272,7 +272,7 @@ export function modCacheDirFor(
|
|
|
272
272
|
|
|
273
273
|
export function lockHash(root: string, ref: ModuleRef, fs: ModuleFs):
|
|
274
274
|
string | undefined {
|
|
275
|
-
const file = pathJoin(root, 'mod-lock.aon')
|
|
275
|
+
const file = pathJoin(root, 'aontu_meta', 'mod-lock.aon')
|
|
276
276
|
if (!fs.existsSync(file)) {
|
|
277
277
|
return undefined
|
|
278
278
|
}
|
|
@@ -392,7 +392,7 @@ export function resolveModule(
|
|
|
392
392
|
roots.map((r) => lockHash(r, ref, fs)).find((h) => null != h)
|
|
393
393
|
|
|
394
394
|
const stores: string[] =
|
|
395
|
-
roots.map((r) => moduleDir(pathJoin(r, '
|
|
395
|
+
roots.map((r) => moduleDir(pathJoin(r, 'aontu_meta', 'vendor'), ref))
|
|
396
396
|
if (null != options.cache && null != expect) {
|
|
397
397
|
// Content-addressed: the cache is keyed by the hash, so a cache hit
|
|
398
398
|
// is already the right MEANING before anything is read from it.
|
package/src/patch.ts
CHANGED
|
@@ -75,6 +75,12 @@ export type PatchOptions = {
|
|
|
75
75
|
// The include capability this document evaluates under
|
|
76
76
|
// (G5, docs/trust.md); vet's precedent.
|
|
77
77
|
trust?: TrustOptions
|
|
78
|
+
// The extensions an include additionally reads as text (the CLI's
|
|
79
|
+
// --text-ext). It rides WITH the capability, never beside it: this
|
|
80
|
+
// verb threaded the capability and not the extension, so `set`
|
|
81
|
+
// refused an include -- and wrote nothing -- under a flag the bare
|
|
82
|
+
// command honoured.
|
|
83
|
+
textExt?: string[]
|
|
78
84
|
}
|
|
79
85
|
|
|
80
86
|
|
|
@@ -578,6 +584,7 @@ export function patch(
|
|
|
578
584
|
// the caller, "which file" is the whole question.
|
|
579
585
|
const report: VetReport = vet(entrySrc, overlay, {
|
|
580
586
|
trust: options.trust,
|
|
587
|
+
textExt: options.textExt,
|
|
581
588
|
schemaPath: options.entryPath,
|
|
582
589
|
dataPath: options.overlayPath,
|
|
583
590
|
schemaUrl: options.entryPath,
|
package/src/query.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
import { includeOpts } from './utility'
|
|
2
3
|
|
|
3
4
|
// THE QUERY SURFACE (G7 phase 1,
|
|
4
5
|
// docs/capability-review/g7-machine-access.md): select one node of an
|
|
@@ -56,6 +57,11 @@ export type QueryOptions = {
|
|
|
56
57
|
// extension -- but reading is enough.) A server passes
|
|
57
58
|
// `{include:'none'}`.
|
|
58
59
|
trust?: TrustOptions
|
|
60
|
+
|
|
61
|
+
// Extensions additionally read as text (the CLI's `--text-ext`).
|
|
62
|
+
// Rides beside `trust` because it is the other half of what an
|
|
63
|
+
// include may read.
|
|
64
|
+
textExt?: string[]
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
export type QueryReport = {
|
|
@@ -271,8 +277,7 @@ export function get(
|
|
|
271
277
|
const options = opts ?? {}
|
|
272
278
|
const view: QueryView = options.view ?? 'json'
|
|
273
279
|
|
|
274
|
-
const aontu = new Aontu(
|
|
275
|
-
null == options.trust ? undefined : { trust: options.trust })
|
|
280
|
+
const aontu = new Aontu(includeOpts(options))
|
|
276
281
|
const ctx = aontu.ctx({ collect: true })
|
|
277
282
|
const parseOpts = null == options.path ? undefined : { path: options.path }
|
|
278
283
|
const root: any = aontu.unify(src, parseOpts, ctx)
|
|
@@ -336,8 +341,7 @@ export type WhyReport = {
|
|
|
336
341
|
export function why(
|
|
337
342
|
src: string, path: string, opts?: QueryOptions): WhyReport {
|
|
338
343
|
const options = opts ?? {}
|
|
339
|
-
const aontu = new Aontu(
|
|
340
|
-
null == options.trust ? undefined : { trust: options.trust })
|
|
344
|
+
const aontu = new Aontu(includeOpts(options))
|
|
341
345
|
const prov = new Provenance()
|
|
342
346
|
const ctx = aontu.ctx({ collect: true, prov })
|
|
343
347
|
const parseOpts = null == options.path ? undefined : { path: options.path }
|
package/src/reach.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
import { includeOpts } from './utility'
|
|
2
3
|
|
|
3
4
|
// REACHABILITY OVER THE LINK GRAPH (the review's finding J,
|
|
4
5
|
// use-cases/REVIEW.md): "ship a transitive `reaches(a, b)` check verb".
|
|
@@ -60,6 +61,11 @@ export type ReachOptions = {
|
|
|
60
61
|
// The include capability this document evaluates under (G5,
|
|
61
62
|
// docs/trust.md).
|
|
62
63
|
trust?: TrustOptions
|
|
64
|
+
|
|
65
|
+
// Extensions additionally read as text (the CLI's `--text-ext`).
|
|
66
|
+
// Rides beside `trust` because it is the other half of what an
|
|
67
|
+
// include may read.
|
|
68
|
+
textExt?: string[]
|
|
63
69
|
// Follow only edges under this relation. Absent means follow every
|
|
64
70
|
// edge, which is the whole graph and the commoner question.
|
|
65
71
|
relation?: string
|
|
@@ -124,8 +130,7 @@ export function reachCheck(
|
|
|
124
130
|
src: string, from: string, to: string, opts?: ReachOptions
|
|
125
131
|
): ReachReport {
|
|
126
132
|
const options = opts ?? {}
|
|
127
|
-
const aontu = new Aontu(
|
|
128
|
-
null == options.trust ? undefined : { trust: options.trust })
|
|
133
|
+
const aontu = new Aontu(includeOpts(options))
|
|
129
134
|
const ctx = aontu.ctx({ collect: true })
|
|
130
135
|
const parseOpts = null == options.path ? undefined : { path: options.path }
|
|
131
136
|
const root: any = aontu.unify(src, parseOpts, ctx)
|
package/src/relation.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
2
|
+
import { includeOpts } from './utility'
|
|
2
3
|
|
|
3
4
|
// RELATION GRAPH VERDICTS (RELATIONS.0.md §3.3, replacing the G4
|
|
4
5
|
// phase 5 magic-key pass): acyclicity and inverse consistency over
|
|
@@ -70,6 +71,11 @@ export type RelationOptions = {
|
|
|
70
71
|
// docs/trust.md). vet's precedent: the verb passes the profile the
|
|
71
72
|
// caller asked for, and an absent option means today's default.
|
|
72
73
|
trust?: TrustOptions
|
|
74
|
+
|
|
75
|
+
// Extensions additionally read as text (the CLI's `--text-ext`).
|
|
76
|
+
// Rides beside `trust` because it is the other half of what an
|
|
77
|
+
// include may read.
|
|
78
|
+
textExt?: string[]
|
|
73
79
|
}
|
|
74
80
|
|
|
75
81
|
|
|
@@ -248,8 +254,7 @@ export function relationErrors(ctx: any, root: any): void {
|
|
|
248
254
|
export function relationCheck(
|
|
249
255
|
src: string, opts?: RelationOptions): RelationReport {
|
|
250
256
|
const options = opts ?? {}
|
|
251
|
-
const aontu = new Aontu(
|
|
252
|
-
null == options.trust ? undefined : { trust: options.trust })
|
|
257
|
+
const aontu = new Aontu(includeOpts(options))
|
|
253
258
|
const ctx = aontu.ctx({ collect: true })
|
|
254
259
|
const parseOpts = null == options.path ? undefined : { path: options.path }
|
|
255
260
|
const root: any = aontu.unify(src, parseOpts, ctx)
|
package/src/sigdecl.ts
CHANGED
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
// this copy is identical with the shared file.
|
|
7
7
|
|
|
8
8
|
const SIGDECL: string =
|
|
9
|
-
"# The call surface: one declaration line per built-in function\n# (docs/design/SIGNATURES.0.md). THIS FILE IS THE SOURCE — both ports\n# carry a build-time-inlined copy (ts/src/sigdecl.ts, go/sigdecl.txt;\n# `make sig` regenerates both, and each port's suite asserts its copy\n# is byte-identical with this file) and parse it at initialisation\n# with the signature grammar, a tabnas grammar (ts/src/sig.ts,\n# go/sig.go). The suites also round-trip every line:\n# render(parse(line)) must be the line exactly, in both ports.\n#\n# The syntax (rendered TypeScript-ish, honest about argument MODES):\n# line = name '(' [ arg {',' arg} ] ')' ':' type\n# arg = [mode] name ['?'] ':' type\n# | '...' name ':' '(' [mode] type {',' [mode] type} ')'\n# type = word {'|' word}\n# mode = 'capture' | 'template' | 'trial' | 'projector' | 'text'\n# `value` mode is unmarked. `constraint` is the result word for\n# residuals whose meet depends on the peer; `any` is the honest type\n# where a function is a wrapper.\nupper(s: string|number) : string\nlower(s: string|number) : string\ncopy(v: any) : any\npref(v: any) : any\nsuper(t: any) : any\ntype(t: any) : any\nhide(v: any) : any\nclose(m: any) : any\nopen(m: any) : any\nmove(v: any) : any\npath(capture p?: path) : path\nmap() : map\nlist() : list\nmin(n: number|string) : constraint\nmax(n: number|string) : constraint\nabove(n: number|string) : constraint\nbelow(n: number|string) : constraint\nre(text p: string) : constraint\nlength(n: number|constraint) : constraint\nkey(up?: integer|biginteger) : string\nunique(projector k?: string) : constraint\nneq(...vals: number|string) : constraint\nmust(trial c: any, text msg: string) : constraint\ndeprecate(v: any, r?: map) : any\nacyclic() : constraint\ninverse(projector k: string) : constraint\nrefer(template t?: any) : constraint\nrel(template t?: any) : constraint\npack(d: map|list, template t: any) : map\neach(d: map|list, template t?: any) : list\nfilter(d: map|list, trial c: any) : map|list\nmatch(s: any, ...pr: (trial any, any), dflt?: any) : any\nadd(a: number, b: number) : number\nsub(a: number, b: number) : number\nmul(a: number, b: number) : number\ndiv(a: number, b: number) : number\nmod(a: number, b: number) : number\nrem(a: number, b: number) : number\nsum(d: map|list) : number\nleast(d: map|list) : number\ngreatest(d: map|list) : number\npick(d: map|list, projector k: string|integer) : any\njoin(d: map|list, sep?: string) : string\n"
|
|
9
|
+
"# The call surface: one declaration line per built-in function\n# (docs/design/SIGNATURES.0.md). THIS FILE IS THE SOURCE — both ports\n# carry a build-time-inlined copy (ts/src/sigdecl.ts, go/sigdecl.txt;\n# `make sig` regenerates both, and each port's suite asserts its copy\n# is byte-identical with this file) and parse it at initialisation\n# with the signature grammar, a tabnas grammar (ts/src/sig.ts,\n# go/sig.go). The suites also round-trip every line:\n# render(parse(line)) must be the line exactly, in both ports.\n#\n# The syntax (rendered TypeScript-ish, honest about argument MODES):\n# line = name '(' [ arg {',' arg} ] ')' ':' type\n# arg = [mode] name ['?'] ':' type\n# | '...' name ':' '(' [mode] type {',' [mode] type} ')'\n# type = word {'|' word}\n# mode = 'capture' | 'template' | 'trial' | 'projector' | 'text'\n# `value` mode is unmarked. `constraint` is the result word for\n# residuals whose meet depends on the peer; `any` is the honest type\n# where a function is a wrapper.\nupper(s: string|number) : string\nlower(s: string|number) : string\ncopy(v: any) : any\npref(v: any) : any\nsuper(t: any) : any\ntype(t: any) : any\nhide(v: any) : any\nclose(m: any) : any\nopen(m: any) : any\nmove(v: any) : any\npath(capture p?: path) : path\nmap() : map\nlist() : list\nmin(n: number|string) : constraint\nmax(n: number|string) : constraint\nabove(n: number|string) : constraint\nbelow(n: number|string) : constraint\nre(text p: string) : constraint\nlength(n: number|constraint) : constraint\nkey(up?: integer|biginteger) : string\nunique(projector k?: string) : constraint\nneq(...vals: number|string) : constraint\nmust(trial c: any, text msg: string) : constraint\ndeprecate(v: any, r?: map) : any\nacyclic() : constraint\ninverse(projector k: string) : constraint\nrefer(template t?: any) : constraint\nrel(template t?: any) : constraint\npack(d: map|list, template t: any) : map\neach(d: map|list, template t?: any) : list\nfilter(d: map|list, trial c: any) : map|list\nmatch(s: any, ...pr: (trial any, any), dflt?: any) : any\nadd(a: number, b: number) : number\nsub(a: number, b: number) : number\nmul(a: number, b: number) : number\ndiv(a: number, b: number) : number\nmod(a: number, b: number) : number\nrem(a: number, b: number) : number\nsum(d: map|list) : number\nleast(d: map|list) : number\ngreatest(d: map|list) : number\npick(d: map|list, projector k: string|integer) : any\njoin(d: map|list, sep?: string) : string\nesc(s: string, variant?: string) : string\nusc(s: string, variant?: string) : string\nrep(s: string, text p: string, text sub: string) : string\nsplit(s: string, sep: string|constraint) : list\nemit(s: map|list, template t: map|list) : list\n"
|
|
10
10
|
|
|
11
11
|
export { SIGDECL }
|