aontu 0.67.0 → 0.69.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/dist/alias.d.ts +12 -1
- package/dist/alias.js +176 -6
- package/dist/alias.js.map +1 -1
- package/dist/aliasname.d.ts +19 -0
- package/dist/aliasname.js +65 -0
- package/dist/aliasname.js.map +1 -0
- package/dist/aontu.d.ts +1 -1
- package/dist/aontu.js +21 -8
- package/dist/aontu.js.map +1 -1
- package/dist/aontumodel.js +1 -1
- package/dist/aontumodel.js.map +1 -1
- package/dist/cli.d.ts +4 -1
- package/dist/cli.js +29 -13
- package/dist/cli.js.map +1 -1
- package/dist/ctx.d.ts +1 -0
- package/dist/ctx.js +1 -0
- package/dist/ctx.js.map +1 -1
- package/dist/err.js +18 -1
- package/dist/err.js.map +1 -1
- package/dist/format.js +14 -0
- package/dist/format.js.map +1 -1
- package/dist/helpdoc.js +1 -1
- package/dist/helpdoc.js.map +1 -1
- package/dist/hints.js +171 -0
- package/dist/hints.js.map +1 -1
- package/dist/lang.js +325 -38
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +10 -4
- package/dist/lsp.js +116 -7
- package/dist/lsp.js.map +1 -1
- package/dist/site.d.ts +9 -0
- package/dist/site.js +2 -1
- package/dist/site.js.map +1 -1
- package/dist/subsume.js +6 -1
- package/dist/subsume.js.map +1 -1
- package/dist/val/BagVal.d.ts +1 -0
- package/dist/val/BagVal.js +3 -0
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/EmitFuncVal.js +2 -1
- package/dist/val/EmitFuncVal.js.map +1 -1
- package/dist/val/FilterFuncVal.js +1 -1
- package/dist/val/FilterFuncVal.js.map +1 -1
- package/dist/val/FuncBaseVal.d.ts +2 -1
- package/dist/val/FuncBaseVal.js +25 -1
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/MapVal.js +10 -4
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MatchFuncVal.js +2 -1
- package/dist/val/MatchFuncVal.js.map +1 -1
- package/dist/val/NilVal.js +3 -0
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/RecurseVal.d.ts +1 -0
- package/dist/val/RecurseVal.js +7 -3
- package/dist/val/RecurseVal.js.map +1 -1
- package/dist/val/RefVal.d.ts +1 -0
- package/dist/val/RefVal.js +47 -18
- package/dist/val/RefVal.js.map +1 -1
- package/dist/vet.d.ts +2 -1
- package/dist/vet.js +51 -6
- package/dist/vet.js.map +1 -1
- package/package.json +1 -1
- package/skill/error-codes.md +25 -1
- package/src/alias.ts +214 -6
- package/src/aliasname.ts +95 -0
- package/src/aontu.ts +23 -9
- package/src/aontumodel.ts +1 -1
- package/src/cli.ts +35 -13
- package/src/ctx.ts +4 -1
- package/src/err.ts +19 -1
- package/src/format.ts +14 -0
- package/src/helpdoc.ts +1 -1
- package/src/hints.ts +228 -0
- package/src/lang.ts +370 -33
- package/src/lsp.ts +136 -6
- package/src/site.ts +15 -1
- package/src/subsume.ts +9 -2
- package/src/val/BagVal.ts +4 -0
- package/src/val/EmitFuncVal.ts +3 -2
- package/src/val/FilterFuncVal.ts +2 -2
- package/src/val/FuncBaseVal.ts +30 -1
- package/src/val/MapVal.ts +10 -4
- package/src/val/MatchFuncVal.ts +3 -2
- package/src/val/NilVal.ts +3 -0
- package/src/val/RecurseVal.ts +8 -3
- package/src/val/RefVal.ts +49 -19
- package/src/vet.ts +55 -6
package/src/cli.ts
CHANGED
|
@@ -5039,6 +5039,17 @@ function runHelp(argv: string[]): number {
|
|
|
5039
5039
|
// and carries that prefix's hint.
|
|
5040
5040
|
const EXPLAIN_PREFIXES = ['func:', 'op:', 'op[', 'var[', 'ref[']
|
|
5041
5041
|
|
|
5042
|
+
// A report prints the namespaced spelling in its brackets, which is the
|
|
5043
|
+
// span a reader copies. The answer names the registered one.
|
|
5044
|
+
const EXPLAIN_NAMESPACE = 'aontu/'
|
|
5045
|
+
|
|
5046
|
+
|
|
5047
|
+
function canonExplainCode(code: string): string {
|
|
5048
|
+
return code.startsWith(EXPLAIN_NAMESPACE)
|
|
5049
|
+
? code.slice(EXPLAIN_NAMESPACE.length)
|
|
5050
|
+
: code
|
|
5051
|
+
}
|
|
5052
|
+
|
|
5042
5053
|
|
|
5043
5054
|
function explainCode(
|
|
5044
5055
|
code: string): { cls: string, hint: string, registered: boolean } {
|
|
@@ -5078,9 +5089,10 @@ function explainListText(format: SubsumeFormat): string {
|
|
|
5078
5089
|
codes: codes.map((code) => ({
|
|
5079
5090
|
code,
|
|
5080
5091
|
class: codeClass(code),
|
|
5081
|
-
// Whether this port carries explanation text for the code.
|
|
5082
|
-
//
|
|
5083
|
-
//
|
|
5092
|
+
// Whether this port carries explanation text for the code. A
|
|
5093
|
+
// gate holds every registered code explained, so this reads
|
|
5094
|
+
// true throughout; it stays because the registry is
|
|
5095
|
+
// append-only and a consumer should filter rather than guess.
|
|
5084
5096
|
explained: '' !== explainCode(code).hint,
|
|
5085
5097
|
})),
|
|
5086
5098
|
}, 2)
|
|
@@ -5088,7 +5100,21 @@ function explainListText(format: SubsumeFormat): string {
|
|
|
5088
5100
|
const width = codes.reduce((w, c) => Math.max(w, c.length), 0)
|
|
5089
5101
|
return codes.map((c) =>
|
|
5090
5102
|
c.padEnd(width) + ' ' + codeClass(c) +
|
|
5091
|
-
(
|
|
5103
|
+
noTextMark(explainCode(c).hint)).join('\n')
|
|
5104
|
+
}
|
|
5105
|
+
|
|
5106
|
+
|
|
5107
|
+
// The registry is append-only, so a code can be registered before its
|
|
5108
|
+
// text is written; saying so beats printing an empty block.
|
|
5109
|
+
function explainBody(hint: string): string {
|
|
5110
|
+
return '' === hint
|
|
5111
|
+
? '(no explanation text is registered for this code)'
|
|
5112
|
+
: hint
|
|
5113
|
+
}
|
|
5114
|
+
|
|
5115
|
+
|
|
5116
|
+
function noTextMark(hint: string): string {
|
|
5117
|
+
return '' === hint ? ' (no text)' : ''
|
|
5092
5118
|
}
|
|
5093
5119
|
|
|
5094
5120
|
|
|
@@ -5138,7 +5164,7 @@ function runExplain(argv: string[]): number {
|
|
|
5138
5164
|
return 2
|
|
5139
5165
|
}
|
|
5140
5166
|
|
|
5141
|
-
const code = codes[0]
|
|
5167
|
+
const code = canonExplainCode(codes[0])
|
|
5142
5168
|
const { cls, hint, registered } = explainCode(code)
|
|
5143
5169
|
if (!registered) {
|
|
5144
5170
|
// AN UNKNOWN CODE IS A USAGE ERROR AND NAMES NEAR MATCHES. A
|
|
@@ -5164,13 +5190,8 @@ function runExplain(argv: string[]): number {
|
|
|
5164
5190
|
}, 2) + '\n')
|
|
5165
5191
|
return 0
|
|
5166
5192
|
}
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
// be blank.
|
|
5170
|
-
const body = '' === hint
|
|
5171
|
-
? '(no explanation text is registered for this code)'
|
|
5172
|
-
: hint
|
|
5173
|
-
process.stdout.write(`code: ${code}\nclass: ${cls}\n\n${body}\n`)
|
|
5193
|
+
process.stdout.write(
|
|
5194
|
+
`code: ${code}\nclass: ${cls}\n\n${explainBody(hint)}\n`)
|
|
5174
5195
|
return 0
|
|
5175
5196
|
}
|
|
5176
5197
|
|
|
@@ -5487,7 +5508,7 @@ function main(argv: string[], servers: Servers = SERVERS): void {
|
|
|
5487
5508
|
else {
|
|
5488
5509
|
runStdin(mode, format, trust).then((code) => finish(code))
|
|
5489
5510
|
}
|
|
5490
|
-
} /* node:coverage ignore next
|
|
5511
|
+
} /* node:coverage ignore next 22 */
|
|
5491
5512
|
|
|
5492
5513
|
|
|
5493
5514
|
// No require.main guard here: bin/aontu.js is the executable entry and
|
|
@@ -5504,6 +5525,7 @@ export {
|
|
|
5504
5525
|
runRender, renderSkipped,
|
|
5505
5526
|
runPkg, runModel, runPackageVerb, pkgToolOptions, serveUntilInterrupted,
|
|
5506
5527
|
runHash, runGet, runHelp, runExplain, runInit, nearestVerb,
|
|
5528
|
+
explainBody, noTextMark, canonExplainCode,
|
|
5507
5529
|
looksLikeVerb,
|
|
5508
5530
|
KNOWN_VERBS,
|
|
5509
5531
|
runWhy, renderWhyText, runSet, runAllow, runAgentsMd, runFmt,
|
package/src/ctx.ts
CHANGED
|
@@ -93,7 +93,9 @@ class AontuContext {
|
|
|
93
93
|
|
|
94
94
|
_fixroot: any
|
|
95
95
|
|
|
96
|
-
budget: {
|
|
96
|
+
budget: {
|
|
97
|
+
passes: number, revisits: number, depth: number, alias: number
|
|
98
|
+
}
|
|
97
99
|
|
|
98
100
|
// The include manifest sink (G5, docs/trust.md): every include the
|
|
99
101
|
// resolver reads is recorded here as { path, capability }, and
|
|
@@ -153,6 +155,7 @@ class AontuContext {
|
|
|
153
155
|
passes: budget.passes ?? 9,
|
|
154
156
|
revisits: 999,
|
|
155
157
|
depth: budget.depth ?? 1000,
|
|
158
|
+
alias: budget.alias ?? 1000000,
|
|
156
159
|
}
|
|
157
160
|
}
|
|
158
161
|
|
package/src/err.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* Copyright (c) 2021-2025 Richard Rodger, MIT License */
|
|
2
2
|
|
|
3
3
|
|
|
4
|
+
import { aliasPathSegment } from './aliasname'
|
|
4
5
|
import { sep } from 'node:path'
|
|
5
6
|
|
|
6
7
|
import { util } from '@tabnas/jsonic'
|
|
@@ -71,7 +72,10 @@ function descErr<NILS extends NilVal | NilVal[]>(
|
|
|
71
72
|
let v1src = resolveSrc(v1, errctx)
|
|
72
73
|
let v2src = resolveSrc(v2, errctx)
|
|
73
74
|
|
|
74
|
-
|
|
75
|
+
// A list index is a number here, and only a key can be an alias.
|
|
76
|
+
let path = ['$', ...err.path.map((p: any) =>
|
|
77
|
+
'string' === typeof p ? aliasPathSegment(p) : p)]
|
|
78
|
+
.filter((p: any) => null != p && '' !== p)
|
|
75
79
|
|
|
76
80
|
// '$' is neither null nor '', so the filter always leaves it.
|
|
77
81
|
let valpath = path.join('.')
|
|
@@ -125,6 +129,20 @@ function descErr<NILS extends NilVal | NilVal[]>(
|
|
|
125
129
|
col: v2.site.col,
|
|
126
130
|
})),
|
|
127
131
|
|
|
132
|
+
// A NAME IS WHERE THE VALUE ENTERED THIS PATH, which is not
|
|
133
|
+
// where it is written (ALIASES.0.md A-1).
|
|
134
|
+
...[v1, v2].map((v: any) => null != v?.site?.via && errmsg({
|
|
135
|
+
color: { active: colorActive(), line: '\x1b[34m' },
|
|
136
|
+
txts: {
|
|
137
|
+
msg: 'Value arrived through ' + v.site.via.name,
|
|
138
|
+
site: ''
|
|
139
|
+
},
|
|
140
|
+
smsg: 'used ' + v.site.via.name + ' here',
|
|
141
|
+
file: resolveFile(v.site.via.url),
|
|
142
|
+
src: resolveSrc({ site: v.site.via } as any, errctx),
|
|
143
|
+
row: v.site.via.row,
|
|
144
|
+
col: v.site.via.col,
|
|
145
|
+
})),
|
|
128
146
|
|
|
129
147
|
]
|
|
130
148
|
.filter((n: any) => null != n && false !== n)
|
package/src/format.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { failureFinding } from './vet'
|
|
|
6
6
|
import type { VetFinding } from './vet'
|
|
7
7
|
import type { Resolver } from './type'
|
|
8
8
|
import { desugarTemplate, resugarTemplate, templateOutputs } from './template'
|
|
9
|
+
import { ALIAS_RE, EXPORT_DECL_NAME, isExportHoldKey } from './aliasname'
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
const BUDGET = 80
|
|
@@ -303,6 +304,19 @@ class Reader {
|
|
|
303
304
|
this.i += 2
|
|
304
305
|
return { t: 'spread', value: this.value(), at }
|
|
305
306
|
}
|
|
307
|
+
// `export({ %a })` is ONE declaration lexed as a pair.
|
|
308
|
+
if (isExportHoldKey(this.T[this.i].val) &&
|
|
309
|
+
EXPORT_DECL_NAME === this.T[this.i].src && this.atKey()) {
|
|
310
|
+
const text = EXPORT_DECL_NAME + '(' + this.T[this.i + 2].src + ')'
|
|
311
|
+
this.i += 3
|
|
312
|
+
return { t: 'atom', text, at }
|
|
313
|
+
}
|
|
314
|
+
if (this.atKey() && ALIAS_RE.test('' + this.T[this.i].src) &&
|
|
315
|
+
this.T[this.i].src === this.T[this.i + 2]?.src) {
|
|
316
|
+
const text = '' + this.T[this.i].src
|
|
317
|
+
this.i += 3
|
|
318
|
+
return { t: 'atom', text, at }
|
|
319
|
+
}
|
|
306
320
|
if (this.atKey()) {
|
|
307
321
|
const tok = this.T[this.i]
|
|
308
322
|
const opt = '#QM' === this.name(1)
|
package/src/helpdoc.ts
CHANGED
|
@@ -35,7 +35,7 @@ const HELPDOC: HelpTopic[] = [
|
|
|
35
35
|
"topic": "codes",
|
|
36
36
|
"summary": "what a refusal means, and what to do about it",
|
|
37
37
|
"source": "docs/skill/error-codes.md",
|
|
38
|
-
"text": "# What a refusal means\n\nEvery aontu error carries a **code**, and every code has a **class**.\nThe class says what kind of thing went wrong, which is what decides\nyour next move. The full registry — every code, its class, and the\nversion it appeared in — is\n[`test/spec/errcodes.tsv`](../../test/spec/errcodes.tsv), which the\ntest suite holds to the engine in both implementations.\n\n| Class | Meaning | What to do |\n|-------|---------|------------|\n| `parse` | the text is not a document | fix the syntax at the site the frame points at |\n| `conflict` | two values cannot both hold | one of them is wrong: `aontu model why <path>` names both and where they were written |\n| `incomplete` | nothing contradicts, but the value is not concrete | supply what is missing, or accept it with `--partial` |\n| `reference` | a path names nothing | check the spelling; `aontu model get $ --keys` lists what is there |\n| `compat` | a change breaks an earlier version | that is `aontu subsume` / `aontu breaking` talking: widen the change or version it |\n| `budget` | evaluation hit a deterministic limit | usually a cycle; simplify, or raise the budget deliberately |\n| `internal` | the engine surprised itself | a bug worth reporting |\n\n## The repair loop\n\n```\naontu vet schema.aon mine.aon --format json\n```\n\nThe exit code branches for you: `0` valid, `1` invalid (fix the\ndata), `3` incomplete (supply more), `4` the schema itself is\nunusable (fix the truth, not the data). Every finding carries\n`path`, `code`, and the sites on both sides — the data site first,\nbecause that is the one to edit. A site names **the file whose text\nit excerpts**, so its row and column are safe to edit at even when\nthe document loads others.\n\nRead `hint` before guessing. `message` is the one-line headline;\n`hint` is the engine's own explanation of the failure class with the\noffending values filled in, and for several codes it names the fix\noutright — `lossy_integer_literal` tells you to write the literal as\n`0d…`.
|
|
38
|
+
"text": "# What a refusal means\n\nEvery aontu error carries a **code**, and every code has a **class**.\nThe class says what kind of thing went wrong, which is what decides\nyour next move. The full registry — every code, its class, and the\nversion it appeared in — is\n[`test/spec/errcodes.tsv`](../../test/spec/errcodes.tsv), which the\ntest suite holds to the engine in both implementations.\n\n| Class | Meaning | What to do |\n|-------|---------|------------|\n| `parse` | the text is not a document | fix the syntax at the site the frame points at |\n| `conflict` | two values cannot both hold | one of them is wrong: `aontu model why <path>` names both and where they were written |\n| `incomplete` | nothing contradicts, but the value is not concrete | supply what is missing, or accept it with `--partial` |\n| `reference` | a path names nothing | check the spelling; `aontu model get $ --keys` lists what is there |\n| `compat` | a change breaks an earlier version | that is `aontu subsume` / `aontu breaking` talking: widen the change or version it |\n| `budget` | evaluation hit a deterministic limit | usually a cycle; simplify, or raise the budget deliberately |\n| `internal` | the engine surprised itself | a bug worth reporting |\n\n## Looking a code up\n\n```\naontu explain constraint # what one code means, and its class\naontu explain --list # every registered code, with its class\n```\n\nA report prints two bracketed spans, and only one of them is a code:\n\n```\n$.note.n1.id: constraint [conflict]\n [aontu/constraint]: Cannot unify values at path $.note.n1.id\n```\n\n`[conflict]` is the **class**. `[aontu/constraint]` is the **code**,\ncarrying the `aontu/` prefix. `explain` takes either spelling —\n`constraint` or `aontu/constraint` — and answers under the registered\none. The headline carries the bare code as well, and so does the `code`\nfield of a `--format json` report.\n\n## The repair loop\n\n```\naontu vet schema.aon mine.aon --format json\n```\n\nThe exit code branches for you: `0` valid, `1` invalid (fix the\ndata), `3` incomplete (supply more), `4` the schema itself is\nunusable (fix the truth, not the data). Every finding carries\n`path`, `code`, and the sites on both sides — the data site first,\nbecause that is the one to edit. A site names **the file whose text\nit excerpts**, so its row and column are safe to edit at even when\nthe document loads others.\n\nRead `hint` before guessing. `message` is the one-line headline;\n`hint` is the engine's own explanation of the failure class with the\noffending values filled in, and for several codes it names the fix\noutright — `lossy_integer_literal` tells you to write the literal as\n`0d…`. Every code in the registry has hint text, which is what\n`aontu explain` prints. A finding carries it inline for an exact\nregistry code; a **dynamic** code (`func:upper`, `op[+]`) is registered\nthrough its prefix, and only `explain` falls back to the prefix's text,\nso such a finding carries no `hint`.\n\nFor a conflict, `aontu model why <path> mine.aon` lists every contribution\nto that path with its role and source line, which turns \"these\ndisagree\" into \"these two lines disagree\".\n\nThen fix it:\n\n```\naontu model set '$.replicas=5' --entry schema.aon --overlay mine.aon --in-place\n```\n\n`--in-place` rewrites the pinned literal **where it was written**, so\ncomments and layout survive. Without it, `set` APPENDS — which is the\nright thing when the document left a hole, and cannot work when it\npinned the wrong value, because unification only narrows.\n\nThe edit is verified before a byte is written: a site carries the\nsource text it covers, and the text at the span must match it. Where\nthat cannot be established — the value comes from a `&:` template or a\n`$ref`, two statements pin the path, the site names the opening token\nof a compound like `min(1)`, or the overlay `@\"includes\"` another\ndocument — the assignment is appended as usual and a **warning** says\nwhich case it hit. A warning never changes the verdict, so asking for\n`--in-place` cannot make a run fail that would have succeeded.\n"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"topic": "grammar",
|
package/src/hints.ts
CHANGED
|
@@ -189,6 +189,8 @@ const hints: Record<string, string> = {
|
|
|
189
189
|
|
|
190
190
|
elided_value: 'A key or element was written with no value after the colon. An\nelided value is a mistake in the source rather than a null: write\n`null` if that is what was meant, or supply the value.\n \nExamples:\n a:null -> null # An explicit null, which is a value;\n a: -> nil # ... but nothing at all is not;\n a: b:1 -> {..} # A colon chain is not an elision;\n [1,] -> [1] # ... nor is a trailing comma.',
|
|
191
191
|
|
|
192
|
+
alias_budget: 'Alias expansion is bounded but not small: a name that names names\nexpands to the product of what they hold, so twenty shallow\ndeclarations reach a million nodes. The expanded size is counted\nbefore evaluation and refused over the budget ({budget} nodes), so\nthe document is turned away rather than run until memory is gone.\n \nExpansion terminates whatever the budget: an alias takes no\nparameters, a cycle is refused, and a file declares finitely many\nnames. The budget is about SIZE, not about termination.\n \nRaise it with trust.budget.alias where the document is trusted and\nthe machine can hold the result.',
|
|
193
|
+
reserved_key: 'The \\u0000aontu_ key prefix belongs to the engine. A document\'s key\norder, its spreads and its alias declarations are held under keys in\nthat namespace, so a source key written there would land on one of\nthem. It is refused where it stands rather than silently replacing\nwhat the parser put there. No ordinary key needs the prefix: it\nbegins with a NUL, which only an escape can spell.\n \nExamples:\n "\\u0000aontu_order": 1 -> nil # The namespace is the engine\'s;\n "aontu_order": 1 -> {..} # ... without the NUL it is a key;\n "___merge": 1 -> {..} # ... and so is this.',
|
|
192
194
|
alias_colon: 'An alias is declared with `=`: write `%name = value`. Until 0.57.0\nthe declaration was spelled with a colon, `%name: value`, and that\nform is refused rather than read as an ordinary key -- a document\nwritten for the old spelling fails here, at the declaration, instead\nof gaining a key named `%name` and a use that resolves to nothing.\n \nExamples:\n %u8 = integer & min(0) -> {..} # Declares %u8, which a: %u8 uses;\n %u8: integer -> nil # The form before 0.58.0, refused;\n "%u8": 1 -> {..} # A quoted key is an ordinary key.',
|
|
193
195
|
|
|
194
196
|
bare_punct: 'A bare string holds letters, digits, `-` and `_`, and nothing else.\nThis one holds `{char}`, in `{text}`. Every other punctuation\ncharacter is either syntax or an error, never silently part of a\nstring: a value that needs one is written quoted, and a `>` or `<`\nthat was meant as a bound is written as min(x), max(x), above(x) or\nbelow(x).\n \nExamples:\n a: team-payments -> "team-payments" # `-` and `_` are text;\n a: 2026-09-05 -> "2026-09-05" # ... digits included;\n a: x=y -> nil # `=` is not;\n a: "x=y" -> "x=y" # ... so quote it;\n a: >10 -> nil # Not an operator: write above(10).',
|
|
@@ -542,6 +544,228 @@ const hints: Record<string, string> = {
|
|
|
542
544
|
// Close operation
|
|
543
545
|
'close': 'Failed to close structure. The structure could not be closed.',
|
|
544
546
|
|
|
547
|
+
// Parse: the source text is malformed or unusable
|
|
548
|
+
'parse': 'The document could not be turned into a value. This wraps the\n' +
|
|
549
|
+
'failure that stopped it -- a syntax error, or a source the include\n' +
|
|
550
|
+
'machinery refused -- and that inner code and its frame say which,\n' +
|
|
551
|
+
'so a report names the inner code rather than this one.\n' +
|
|
552
|
+
' \nNote that `parse` is also the name of a CLASS, and the class is\n' +
|
|
553
|
+
'what a refusal shows in the second bracket: `syntax [parse]` is\n' +
|
|
554
|
+
'the code `syntax` in the class `parse`.',
|
|
555
|
+
|
|
556
|
+
'syntax': 'The text is not valid Aontu syntax. The frame points at the\n' +
|
|
557
|
+
'character the parser stopped on; the fault is usually just before\n' +
|
|
558
|
+
'it, and commenting out the suspect lines with # isolates which.',
|
|
559
|
+
|
|
560
|
+
'parse_unknown':
|
|
561
|
+
'A parsed value arrived in a kind the language has no value for.\n' +
|
|
562
|
+
'Aontu builds from maps, lists, strings, numbers, booleans and nil,\n' +
|
|
563
|
+
'so a value outside that set is a defect in whatever produced it\n' +
|
|
564
|
+
'rather than something a document can write.',
|
|
565
|
+
|
|
566
|
+
'negative': 'Only a number can be negated. A `-` in front of a\n' +
|
|
567
|
+
'non-numeric value is an error rather than a missing value.\n' +
|
|
568
|
+
' \nA `-` is a PREFIX here and never an operator between two values,\n' +
|
|
569
|
+
'so subtraction is sub(a, b).' +
|
|
570
|
+
'\n \nExamples:\n' +
|
|
571
|
+
' a: -1 -> -1 # A number negates;\n' +
|
|
572
|
+
' a: -x -> nil # ... a bare word does not;\n' +
|
|
573
|
+
' a: k-x -> "k-x" # ... and this is one word, not a minus;\n' +
|
|
574
|
+
' a: sub(5,3) -> 2 # Subtraction is a function.',
|
|
575
|
+
|
|
576
|
+
'not_number': 'This numeric literal is not a finite number. A literal\n' +
|
|
577
|
+
'past the range a double can hold (1e999) overflows to infinity\n' +
|
|
578
|
+
'while lexing, which is an error value and not a number. Write it\n' +
|
|
579
|
+
'within range, or as a decimal literal with the 0d escape.',
|
|
580
|
+
|
|
581
|
+
'incomplete_expression':
|
|
582
|
+
'The expression has no terms. An operator or a pair of parentheses\n' +
|
|
583
|
+
'was written with nothing for it to work on -- `a:()` is the bare\n' +
|
|
584
|
+
'case. Supply the operand, or delete the construct.',
|
|
585
|
+
|
|
586
|
+
'alias_in_path':
|
|
587
|
+
'An alias is not a path segment. The alias namespace and the path\n' +
|
|
588
|
+
'namespace are disjoint, so `$.%foo` is refused at any depth: an\n' +
|
|
589
|
+
'alias is reached by writing `%foo` and only that.' +
|
|
590
|
+
'\n \nExamples:\n' +
|
|
591
|
+
' %port = min(1) -> declared;\n' +
|
|
592
|
+
' listen: %port -> the alias, reached by its own name;\n' +
|
|
593
|
+
' listen: $.%port -> nil # Not a path segment.',
|
|
594
|
+
|
|
595
|
+
'alias_not_toplevel':
|
|
596
|
+
'An alias declaration written as a KEY sits at the root of the\n' +
|
|
597
|
+
'document. A nested `x: { %a = 1 }` is refused because `%a` resolves\n' +
|
|
598
|
+
'from the root: the declaration would be erased from the output,\n' +
|
|
599
|
+
'being a declaration, and still unreachable by any reference, not\n' +
|
|
600
|
+
'being at the root. Where the declaration LANDS decides this, not\n' +
|
|
601
|
+
'where it was written, so an include spliced at the root may declare\n' +
|
|
602
|
+
'one and an include taken as a value may not.\n' +
|
|
603
|
+
'To name a shape where it is used, write the declaration as a VALUE\n' +
|
|
604
|
+
'prefix instead: `x: %a = 1` is accepted at any depth, leaves the\n' +
|
|
605
|
+
'value alone, and declares `%a` for the document.',
|
|
606
|
+
|
|
607
|
+
'export_arg':
|
|
608
|
+
'`export` takes a SET OF ALIAS NAMES and nothing else: write\n' +
|
|
609
|
+
'`export({ %a, %b })`. A key already crosses a file boundary as a\n' +
|
|
610
|
+
'value, so a bare word names nothing `export` could publish, and a\n' +
|
|
611
|
+
'single name still stands in a set. The `{%}` wildcard is the\n' +
|
|
612
|
+
'importing side\'s: the publishing file chooses what it publishes.\n' +
|
|
613
|
+
' \nExamples:\n' +
|
|
614
|
+
' %u8 = integer\n' +
|
|
615
|
+
' export({ %u8 }) -> published;\n' +
|
|
616
|
+
' export({ u8 }) -> nil # A key, not an alias;\n' +
|
|
617
|
+
' export(%u8) -> nil # A set, even of one;\n' +
|
|
618
|
+
' export({%}) -> nil # The wildcard is the importer\'s.',
|
|
619
|
+
|
|
620
|
+
'import_not_exported':
|
|
621
|
+
'The file this name was asked of does not publish `{name}`. A name\n' +
|
|
622
|
+
'belongs to the file that declares it and crosses only where that\n' +
|
|
623
|
+
'file says so, which is what `export` is for: add the name to the\n' +
|
|
624
|
+
'other file\'s `export({ ... })`, or write the value in this one.\n' +
|
|
625
|
+
'The include still placed the file\'s values -- it is the NAME that\n' +
|
|
626
|
+
'did not cross.\n' +
|
|
627
|
+
' \nExamples:\n' +
|
|
628
|
+
' { %u8 } = @"types.aon" -> bound, if types.aon exports %u8;\n' +
|
|
629
|
+
' { %secret } = @"types.aon" -> nil # ... and refused if not.',
|
|
630
|
+
|
|
631
|
+
'patch_assignment':
|
|
632
|
+
'This is not a <path>=<value> assignment. The path is what stands\n' +
|
|
633
|
+
'before the first `=` and the value is what follows it, so an\n' +
|
|
634
|
+
'argument carrying only one of them cannot be applied.',
|
|
635
|
+
|
|
636
|
+
// Reference: a name or path resolves to nothing editable
|
|
637
|
+
'multisource_not_found':
|
|
638
|
+
'The source named here was not found. For a file include, check the\n' +
|
|
639
|
+
'path as written, which is resolved against the document that writes\n' +
|
|
640
|
+
'it; for an `aontu:` name the message lists the models the language\n' +
|
|
641
|
+
'supplies, and a name outside that set is never looked for on disk.',
|
|
642
|
+
|
|
643
|
+
'patch_ambiguous':
|
|
644
|
+
'More than one statement pins this path, so there is no single\n' +
|
|
645
|
+
'literal to rewrite in place. The sites on the finding are all of\n' +
|
|
646
|
+
'them: edit the one that should change, or narrow the overlay so\n' +
|
|
647
|
+
'that only one pins the path.',
|
|
648
|
+
|
|
649
|
+
'patch_not_editable':
|
|
650
|
+
'There is no literal at this path to rewrite in place. The value is\n' +
|
|
651
|
+
'reached through a reference, arrives only once the overlay loads\n' +
|
|
652
|
+
'another document, or is produced rather than written -- the finding\n' +
|
|
653
|
+
'names which, and the sites say where it does come from. Edit there,\n' +
|
|
654
|
+
'or let set append instead of asking for --in-place.',
|
|
655
|
+
|
|
656
|
+
'var': 'This variable has no value, and an unresolved variable cannot\n' +
|
|
657
|
+
'be generated. A `$name` variable is supplied by the CALLER, never\n' +
|
|
658
|
+
'by the document: bind it through `ctx.vars` in TypeScript or pass\n' +
|
|
659
|
+
'it to `UnifyVars` in Go. If the value was meant to come from the\n' +
|
|
660
|
+
'document, a path reference ($.a.b) or an alias (%name) is what\n' +
|
|
661
|
+
'reads one.',
|
|
662
|
+
|
|
663
|
+
// Internal: the engine surprised itself
|
|
664
|
+
'patch_span_mismatch':
|
|
665
|
+
'The overlay does not hold the text the site says is there, so the\n' +
|
|
666
|
+
'span cannot be verified and the edit is refused rather than\n' +
|
|
667
|
+
'written: splicing without verifying the span corrupts the file.\n' +
|
|
668
|
+
'The span is checked against the very text it was derived from, so\n' +
|
|
669
|
+
'a document changing underneath cannot produce this. It is an\n' +
|
|
670
|
+
'engine provenance defect -- the one refusal classed internal for\n' +
|
|
671
|
+
'that reason -- and worth reporting.',
|
|
672
|
+
|
|
673
|
+
'unify_failed':
|
|
674
|
+
'The document does not evaluate, and the failure carried no more\n' +
|
|
675
|
+
'specific code. This stands in where a nil reaches the report\n' +
|
|
676
|
+
'without one, so the other findings in the same run are what say\n' +
|
|
677
|
+
'what actually went wrong.',
|
|
678
|
+
|
|
679
|
+
'unknown_op':
|
|
680
|
+
'The parser produced an operator form the value builder does not\n' +
|
|
681
|
+
'recognise. Reaching this is an engine defect rather than a fault\n' +
|
|
682
|
+
'in the document.',
|
|
683
|
+
|
|
684
|
+
// Compat: the subsumption and outcome vocabulary
|
|
685
|
+
'compat_narrowed':
|
|
686
|
+
'The general value does not admit the specific one: the specific\n' +
|
|
687
|
+
'side allows something the general side refuses -- a wider kind, a\n' +
|
|
688
|
+
'wider residual, or a value the general residual excludes. A\n' +
|
|
689
|
+
'document the specific side accepts can therefore fail against the\n' +
|
|
690
|
+
'general one. Which document is on which side is the comparison\'s:\n' +
|
|
691
|
+
'subsume takes them in the order given, and breaking decides by its\n' +
|
|
692
|
+
'mode.',
|
|
693
|
+
|
|
694
|
+
'compat_required_added':
|
|
695
|
+
'The general value requires this key and the specific value does\n' +
|
|
696
|
+
'not, either because the key is absent there or because it is\n' +
|
|
697
|
+
'optional there. Instances without the key are admitted where the\n' +
|
|
698
|
+
'general side refuses them.',
|
|
699
|
+
|
|
700
|
+
'compat_default_changed':
|
|
701
|
+
'The general and specific values have different effective defaults,\n' +
|
|
702
|
+
'so a document resolving to one of them against one side resolves\n' +
|
|
703
|
+
'to the other -- or stops resolving -- against the other, with\n' +
|
|
704
|
+
'nothing in the document itself changing. Which document is on\n' +
|
|
705
|
+
'which side is the comparison\'s own.',
|
|
706
|
+
|
|
707
|
+
'compat_marks_changed':
|
|
708
|
+
'The marks on this value differ between the general and specific\n' +
|
|
709
|
+
'sides: one carries type() or hide() where the other does not. A\n' +
|
|
710
|
+
'mark changes what the value contributes to a generated document,\n' +
|
|
711
|
+
'so the two are not the same declaration even where what they admit\n' +
|
|
712
|
+
'agrees. Reported under the gen profile, which is the one that\n' +
|
|
713
|
+
'compares them.',
|
|
714
|
+
|
|
715
|
+
'compat_outcome_changed':
|
|
716
|
+
'This path resolved to one value before and resolves to a different\n' +
|
|
717
|
+
'one now. Nothing refuses, so the change is silent: a consumer\n' +
|
|
718
|
+
'reading this path gets a new answer with no error to say so.',
|
|
719
|
+
|
|
720
|
+
'compat_undetermined':
|
|
721
|
+
'This path resolved to a value before and nothing resolves it now.\n' +
|
|
722
|
+
'The declaration became incomplete rather than wrong, so a consumer\n' +
|
|
723
|
+
'that read a value here reads nothing.',
|
|
724
|
+
|
|
725
|
+
'deprecated':
|
|
726
|
+
'This value is marked deprecated. The record carries the author\'s\n' +
|
|
727
|
+
'message, and where they supplied them, what to use instead and the\n' +
|
|
728
|
+
'version it was deprecated in. Nothing refuses: a deprecation is a\n' +
|
|
729
|
+
'warning and never changes a verdict.',
|
|
730
|
+
|
|
731
|
+
'pref_not_instance':
|
|
732
|
+
'The preferred value is not repeated among the remaining\n' +
|
|
733
|
+
'alternatives of its disjunction. Nothing is refused and the\n' +
|
|
734
|
+
'preference still holds -- the default stays admitted, and\n' +
|
|
735
|
+
'generation selects it -- so this is ADVISORY. It catches the typo\n' +
|
|
736
|
+
'where a default was meant to name one of the alternatives beside\n' +
|
|
737
|
+
'it and names something else instead.',
|
|
738
|
+
|
|
739
|
+
'sub_unresolved':
|
|
740
|
+
'An unresolved value has no admitted set to compare. Either a\n' +
|
|
741
|
+
'residue is still standing here, or the two sides are value formers\n' +
|
|
742
|
+
'no comparison rule covers, so the answer is undecided rather than\n' +
|
|
743
|
+
'yes or no.',
|
|
744
|
+
|
|
745
|
+
'sub_evaluate_only':
|
|
746
|
+
'An evaluate-only check makes the admitted set opaque. must() is\n' +
|
|
747
|
+
'checked by running it and never by reasoning about what it admits,\n' +
|
|
748
|
+
'so a value carrying one cannot be compared and the answer is\n' +
|
|
749
|
+
'undecided rather than yes or no.',
|
|
750
|
+
|
|
751
|
+
'sub_disjunct_distribution':
|
|
752
|
+
'An alternative is not admitted member by member, and no concrete\n' +
|
|
753
|
+
'value settles it either way. Comparing a disjunction member-wise\n' +
|
|
754
|
+
'is sound when it answers yes; a no needs a counterexample, and\n' +
|
|
755
|
+
'there is none here, so the answer is undecided.',
|
|
756
|
+
|
|
757
|
+
'sub_default_indeterminate':
|
|
758
|
+
'The effective default is not a single value, because preferences\n' +
|
|
759
|
+
'of equal rank disagree. Nothing can be decided about the default\n' +
|
|
760
|
+
'until one of them is ranked (`**x`) or they are made to agree, so\n' +
|
|
761
|
+
'the answer is undecided rather than yes or no.',
|
|
762
|
+
|
|
763
|
+
'sub_path_dependent_spread':
|
|
764
|
+
'A spread template that depends on where it lands cannot be\n' +
|
|
765
|
+
'compared structurally. What it produces is known only once it is\n' +
|
|
766
|
+
'applied to a path, so the general and specific sides cannot be\n' +
|
|
767
|
+
'held against each other and the answer is undecided.',
|
|
768
|
+
|
|
545
769
|
// Dynamic patterns (these serve as prefixes)
|
|
546
770
|
'func:': 'Function error: ',
|
|
547
771
|
'op:': 'Operator error: ',
|
|
@@ -687,7 +911,11 @@ const codeClasses: Record<string, string> = {
|
|
|
687
911
|
pref_implicit_bag: 'parse',
|
|
688
912
|
alias_not_toplevel: 'parse',
|
|
689
913
|
alias_in_path: 'parse',
|
|
914
|
+
alias_budget: 'budget',
|
|
915
|
+
reserved_key: 'parse',
|
|
690
916
|
alias_colon: 'parse',
|
|
917
|
+
export_arg: 'parse',
|
|
918
|
+
import_not_exported: 'reference',
|
|
691
919
|
bare_punct: 'parse',
|
|
692
920
|
not_number: 'parse',
|
|
693
921
|
negative: 'parse',
|