aontu 0.50.1 → 0.52.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.
Files changed (197) hide show
  1. package/bin/aontu-lsp.js +6 -0
  2. package/bin/aontu.js +7 -0
  3. package/dist/aontu.d.ts +4 -2
  4. package/dist/aontu.js +21 -8
  5. package/dist/aontu.js.map +1 -1
  6. package/dist/cli.d.ts +0 -1
  7. package/dist/cli.js +43 -53
  8. package/dist/cli.js.map +1 -1
  9. package/dist/ctx.js +1 -1
  10. package/dist/ctx.js.map +1 -1
  11. package/dist/err.js +3 -2
  12. package/dist/err.js.map +1 -1
  13. package/dist/exactjson.d.ts +37 -0
  14. package/dist/exactjson.js +228 -0
  15. package/dist/exactjson.js.map +1 -0
  16. package/dist/hints.d.ts +3 -1
  17. package/dist/hints.js +187 -5
  18. package/dist/hints.js.map +1 -1
  19. package/dist/keyorder.d.ts +9 -0
  20. package/dist/keyorder.js +65 -0
  21. package/dist/keyorder.js.map +1 -0
  22. package/dist/lang.js +263 -30
  23. package/dist/lang.js.map +1 -1
  24. package/dist/lsp-server.d.ts +2 -2
  25. package/dist/lsp-server.js +10 -10
  26. package/dist/lsp-server.js.map +1 -1
  27. package/dist/lsp.js +39 -21
  28. package/dist/lsp.js.map +1 -1
  29. package/dist/site.js +1 -1
  30. package/dist/site.js.map +1 -1
  31. package/dist/tsconfig.tsbuildinfo +1 -1
  32. package/dist/unify.js +48 -1
  33. package/dist/unify.js.map +1 -1
  34. package/dist/utility.js +3 -8
  35. package/dist/utility.js.map +1 -1
  36. package/dist/val/BagVal.js +9 -6
  37. package/dist/val/BagVal.js.map +1 -1
  38. package/dist/val/BigDecimalVal.d.ts +13 -0
  39. package/dist/val/BigDecimalVal.js +80 -0
  40. package/dist/val/BigDecimalVal.js.map +1 -0
  41. package/dist/val/BigIntegerVal.d.ts +11 -0
  42. package/dist/val/BigIntegerVal.js +75 -0
  43. package/dist/val/BigIntegerVal.js.map +1 -0
  44. package/dist/val/BooleanVal.js +1 -1
  45. package/dist/val/BooleanVal.js.map +1 -1
  46. package/dist/val/CloseFuncVal.js +1 -1
  47. package/dist/val/CloseFuncVal.js.map +1 -1
  48. package/dist/val/ConjunctVal.js +1 -1
  49. package/dist/val/ConjunctVal.js.map +1 -1
  50. package/dist/val/ConstraintVal.d.ts +56 -0
  51. package/dist/val/ConstraintVal.js +407 -0
  52. package/dist/val/ConstraintVal.js.map +1 -0
  53. package/dist/val/CopyFuncVal.js +1 -1
  54. package/dist/val/CopyFuncVal.js.map +1 -1
  55. package/dist/val/Decimal.d.ts +32 -0
  56. package/dist/val/Decimal.js +318 -0
  57. package/dist/val/Decimal.js.map +1 -0
  58. package/dist/val/DisjunctVal.js +1 -29
  59. package/dist/val/DisjunctVal.js.map +1 -1
  60. package/dist/val/ExpectVal.js +1 -1
  61. package/dist/val/ExpectVal.js.map +1 -1
  62. package/dist/val/FeatureVal.js +1 -1
  63. package/dist/val/FeatureVal.js.map +1 -1
  64. package/dist/val/FuncBaseVal.js +1 -1
  65. package/dist/val/FuncBaseVal.js.map +1 -1
  66. package/dist/val/HideFuncVal.js +1 -1
  67. package/dist/val/HideFuncVal.js.map +1 -1
  68. package/dist/val/IntegerVal.d.ts +2 -0
  69. package/dist/val/IntegerVal.js +77 -5
  70. package/dist/val/IntegerVal.js.map +1 -1
  71. package/dist/val/JunctionVal.js +1 -1
  72. package/dist/val/JunctionVal.js.map +1 -1
  73. package/dist/val/KeyFuncVal.d.ts +1 -1
  74. package/dist/val/KeyFuncVal.js +34 -4
  75. package/dist/val/KeyFuncVal.js.map +1 -1
  76. package/dist/val/ListVal.js +7 -7
  77. package/dist/val/ListVal.js.map +1 -1
  78. package/dist/val/LowerFuncVal.js +21 -4
  79. package/dist/val/LowerFuncVal.js.map +1 -1
  80. package/dist/val/MapVal.js +17 -13
  81. package/dist/val/MapVal.js.map +1 -1
  82. package/dist/val/MoveFuncVal.js +26 -9
  83. package/dist/val/MoveFuncVal.js.map +1 -1
  84. package/dist/val/NilVal.d.ts +1 -0
  85. package/dist/val/NilVal.js +10 -3
  86. package/dist/val/NilVal.js.map +1 -1
  87. package/dist/val/NullVal.js +1 -1
  88. package/dist/val/NullVal.js.map +1 -1
  89. package/dist/val/NumberVal.d.ts +1 -0
  90. package/dist/val/NumberVal.js +25 -4
  91. package/dist/val/NumberVal.js.map +1 -1
  92. package/dist/val/OpBaseVal.js +10 -8
  93. package/dist/val/OpBaseVal.js.map +1 -1
  94. package/dist/val/OpenFuncVal.js +1 -1
  95. package/dist/val/OpenFuncVal.js.map +1 -1
  96. package/dist/val/PathFuncVal.js +10 -2
  97. package/dist/val/PathFuncVal.js.map +1 -1
  98. package/dist/val/PlusOpVal.d.ts +3 -1
  99. package/dist/val/PlusOpVal.js +140 -29
  100. package/dist/val/PlusOpVal.js.map +1 -1
  101. package/dist/val/PrefFuncVal.js +1 -1
  102. package/dist/val/PrefFuncVal.js.map +1 -1
  103. package/dist/val/PrefVal.d.ts +2 -0
  104. package/dist/val/PrefVal.js +44 -7
  105. package/dist/val/PrefVal.js.map +1 -1
  106. package/dist/val/RefVal.d.ts +2 -0
  107. package/dist/val/RefVal.js +135 -11
  108. package/dist/val/RefVal.js.map +1 -1
  109. package/dist/val/ScalarKindVal.d.ts +12 -2
  110. package/dist/val/ScalarKindVal.js +108 -13
  111. package/dist/val/ScalarKindVal.js.map +1 -1
  112. package/dist/val/ScalarVal.d.ts +1 -0
  113. package/dist/val/ScalarVal.js +18 -3
  114. package/dist/val/ScalarVal.js.map +1 -1
  115. package/dist/val/StringVal.js +1 -1
  116. package/dist/val/StringVal.js.map +1 -1
  117. package/dist/val/SuperFuncVal.d.ts +1 -1
  118. package/dist/val/SuperFuncVal.js +15 -2
  119. package/dist/val/SuperFuncVal.js.map +1 -1
  120. package/dist/val/TopVal.js +1 -1
  121. package/dist/val/TopVal.js.map +1 -1
  122. package/dist/val/TypeFuncVal.js +1 -1
  123. package/dist/val/TypeFuncVal.js.map +1 -1
  124. package/dist/val/UpperFuncVal.js +21 -4
  125. package/dist/val/UpperFuncVal.js.map +1 -1
  126. package/dist/val/Val.d.ts +1 -1
  127. package/dist/val/Val.js +11 -21
  128. package/dist/val/Val.js.map +1 -1
  129. package/dist/val/VarVal.js +8 -2
  130. package/dist/val/VarVal.js.map +1 -1
  131. package/dist/val/numcmp.d.ts +14 -0
  132. package/dist/val/numcmp.js +134 -0
  133. package/dist/val/numcmp.js.map +1 -0
  134. package/dist/val/numkind.d.ts +6 -0
  135. package/dist/val/numkind.js +224 -0
  136. package/dist/val/numkind.js.map +1 -0
  137. package/dist/val/valutil.d.ts +1 -0
  138. package/dist/val/valutil.js +35 -0
  139. package/dist/val/valutil.js.map +1 -1
  140. package/package.json +7 -5
  141. package/src/aontu.ts +26 -9
  142. package/src/cli.ts +48 -21
  143. package/src/ctx.ts +1 -1
  144. package/src/err.ts +3 -2
  145. package/src/exactjson.ts +254 -0
  146. package/src/hints.ts +213 -4
  147. package/src/keyorder.ts +73 -0
  148. package/src/lang.ts +303 -31
  149. package/src/lsp-server.ts +17 -15
  150. package/src/lsp.ts +37 -14
  151. package/src/site.ts +1 -1
  152. package/src/type.ts +1 -1
  153. package/src/unify.ts +52 -1
  154. package/src/utility.ts +3 -9
  155. package/src/val/BagVal.ts +9 -6
  156. package/src/val/BigDecimalVal.ts +117 -0
  157. package/src/val/BigIntegerVal.ts +110 -0
  158. package/src/val/BooleanVal.ts +1 -1
  159. package/src/val/CloseFuncVal.ts +1 -1
  160. package/src/val/ConjunctVal.ts +1 -1
  161. package/src/val/ConstraintVal.ts +561 -0
  162. package/src/val/CopyFuncVal.ts +1 -1
  163. package/src/val/Decimal.ts +385 -0
  164. package/src/val/DisjunctVal.ts +1 -37
  165. package/src/val/ExpectVal.ts +1 -1
  166. package/src/val/FeatureVal.ts +1 -1
  167. package/src/val/FuncBaseVal.ts +1 -1
  168. package/src/val/HideFuncVal.ts +1 -1
  169. package/src/val/IntegerVal.ts +81 -5
  170. package/src/val/JunctionVal.ts +1 -1
  171. package/src/val/KeyFuncVal.ts +36 -4
  172. package/src/val/ListVal.ts +3 -5
  173. package/src/val/LowerFuncVal.ts +22 -5
  174. package/src/val/MapVal.ts +13 -9
  175. package/src/val/MoveFuncVal.ts +27 -10
  176. package/src/val/NilVal.ts +13 -3
  177. package/src/val/NullVal.ts +1 -1
  178. package/src/val/NumberVal.ts +27 -4
  179. package/src/val/OpBaseVal.ts +10 -10
  180. package/src/val/OpenFuncVal.ts +1 -1
  181. package/src/val/PathFuncVal.ts +10 -2
  182. package/src/val/PlusOpVal.ts +168 -32
  183. package/src/val/PrefFuncVal.ts +1 -1
  184. package/src/val/PrefVal.ts +70 -8
  185. package/src/val/RefVal.ts +143 -11
  186. package/src/val/ScalarKindVal.ts +123 -12
  187. package/src/val/ScalarVal.ts +20 -3
  188. package/src/val/StringVal.ts +1 -1
  189. package/src/val/SuperFuncVal.ts +15 -2
  190. package/src/val/TopVal.ts +1 -1
  191. package/src/val/TypeFuncVal.ts +1 -1
  192. package/src/val/UpperFuncVal.ts +22 -5
  193. package/src/val/Val.ts +13 -8
  194. package/src/val/VarVal.ts +8 -2
  195. package/src/val/numcmp.ts +189 -0
  196. package/src/val/numkind.ts +256 -0
  197. package/src/val/valutil.ts +36 -0
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ /* Copyright (c) 2025 Richard Rodger, MIT License */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.exactJSON = exactJSON;
5
+ /*
6
+ * D9 -- THE EXACT JSON EMITTER.
7
+ *
8
+ * `generate()` returns NATIVE values, and once a document opts into the
9
+ * exact leaves two of them are not things `JSON.stringify` can write: a
10
+ * biginteger generates as a native `bigint`, and a bigdecimal generates
11
+ * as a `Decimal`. `JSON.stringify` THROWS on a bigint ("Do not know how
12
+ * to serialize a BigInt") and a `replacer` cannot rescue it, because a
13
+ * replacer may only return another *value* -- everything it returns that
14
+ * is not already a JSON primitive gets quoted, so the exact digits could
15
+ * only come back as a JSON *string*, which is a different document.
16
+ *
17
+ * JSON itself was never the obstacle. A JSON number is arbitrary-
18
+ * precision decimal TEXT: `{"x":9007199254740993}` is a perfectly legal
19
+ * document that every conforming parser reads, and Go's `encoding/json`
20
+ * already emits exactly that for a `*big.Int`. Only JavaScript's
21
+ * serialiser stands in the way, so aontu ships its own.
22
+ *
23
+ * WHY THIS IS PUBLIC API and not a CLI internal: D9 promises that an
24
+ * exact value reaches JSON as exact digits. A library consumer whose
25
+ * document contains `0d9007199254740993` has no other supported way to
26
+ * keep that promise -- hiding the only implementation behind the command
27
+ * line would leave the contract unfulfillable from the library. The
28
+ * `aontu` CLI consumes this same export (with `indent`), and so does the
29
+ * shared suite's byte-exact `gens` mode, so there is exactly one set of
30
+ * bytes to keep in step with the Go port.
31
+ *
32
+ * PARITY WITH GO. The output must match Go's
33
+ * `json.Encoder` + `SetEscapeHTML(false)` (see specGens in
34
+ * go/spec_test.go) byte for byte:
35
+ *
36
+ * - Key order is the order `generate()` produced. Both ports already
37
+ * sort map keys (see the entries sort in BagVal.gen; Go's encoder
38
+ * sorts map keys), so neither has to sort again here.
39
+ * - Strings keep JavaScript's escaping, which is what the `gens` mode
40
+ * settled on when it turned Go's HTML escaping OFF so that `<`, `>`
41
+ * and `&` stay literal in both ports. U+2028/U+2029 are the one
42
+ * place JS and Go disagree by default -- Go escapes them, JS does
43
+ * not -- so they are escaped here too, which is both legal JSON and
44
+ * the safer output (it can be embedded in a JavaScript source).
45
+ * - Numbers keep JavaScript's `Number.prototype.toString` form, which
46
+ * is already what Go's encoder produces: fixed notation inside
47
+ * [1e-6, 1e21) and an unpadded, always-signed exponent outside it
48
+ * (`1e+21`, `1e-7`).
49
+ * - A bigint writes its digits; a Decimal writes its plain digit form
50
+ * (`1000.0`, `0.1`, `-1.5`) -- no `0d` marker, since that belongs to
51
+ * canon and is not JSON, but an integral bigdecimal keeps its `.0`
52
+ * so the JSON still shows a decimal. Go's `*Decimal.MarshalJSON`
53
+ * mirrors this.
54
+ *
55
+ * NOTE that byte-exact output CANNOT check the other half of D9: an
56
+ * integral bigdecimal and a biginteger can serialise to different text,
57
+ * but a biginteger and an ordinary integer serialise to the SAME text
58
+ * while `generate()` returned the wrong runtime type. Canon pins the AST
59
+ * kind, `gens` pins these bytes, and only the per-port API tests
60
+ * (ts/test/exactjson.test.ts here) pin the returned object.
61
+ */
62
+ const Decimal_1 = require("./val/Decimal");
63
+ const err_1 = require("./err");
64
+ const keyorder_1 = require("./keyorder");
65
+ // JS leaves U+2028 (LINE SEPARATOR) and U+2029 (PARAGRAPH SEPARATOR)
66
+ // literal in a JSON string; Go's encoder escapes them. Byte parity wins.
67
+ const LSPS_RE = new RegExp('[\u2028\u2029]', 'g');
68
+ // JSON.stringify's `space` argument, normalised the way the spec does:
69
+ // a number is clamped to 0..10 spaces, a string is truncated to 10
70
+ // characters, anything else means "compact".
71
+ function indentUnit(indent) {
72
+ if ('number' === typeof indent) {
73
+ const n = Math.min(10, Math.floor(indent));
74
+ return 0 < n ? ' '.repeat(n) : '';
75
+ }
76
+ if ('string' === typeof indent) {
77
+ return indent.slice(0, 10);
78
+ }
79
+ return '';
80
+ }
81
+ function quote(s) {
82
+ const out = JSON.stringify(s);
83
+ // A raw separator can only appear as itself in the output (never
84
+ // inside an escape), so a straight replace is safe.
85
+ return out.replace(LSPS_RE, (c) => '\u2028' === c ? '\\u2028' : '\\u2029');
86
+ }
87
+ // True for a value JSON.stringify omits from an object and writes as
88
+ // `null` inside an array. generate() never produces one, but a consumer
89
+ // splicing its own data into the result might.
90
+ function skipped(v) {
91
+ return undefined === v || 'function' === typeof v || 'symbol' === typeof v;
92
+ }
93
+ // `seen` tracks the containers on the CURRENT path only (added on entry,
94
+ // removed on exit), so a shared subtree -- which unification can easily
95
+ // produce -- serialises fine and only a true cycle is refused, exactly
96
+ // as JSON.stringify does it.
97
+ function emit(v, unit, pad, seen) {
98
+ if (null === v) {
99
+ return 'null';
100
+ }
101
+ const t = typeof v;
102
+ if ('string' === t) {
103
+ return quote(v);
104
+ }
105
+ if ('number' === t) {
106
+ // JSON has no NaN, no Infinity and no negative zero: JSON.stringify
107
+ // writes `null` for the first two and `0` for the last, and gen()
108
+ // has already normalised -0 away (R2).
109
+ return JSON.stringify(v);
110
+ }
111
+ if ('bigint' === t) {
112
+ // THE POINT OF THIS MODULE: exact digits, as a raw JSON number.
113
+ return v.toString();
114
+ }
115
+ if ('boolean' === t) {
116
+ return v ? 'true' : 'false';
117
+ }
118
+ if (skipped(v)) {
119
+ return 'null';
120
+ }
121
+ // Before any other object handling: a Decimal is a value, not a
122
+ // structure, and its plain digit form is the JSON number.
123
+ if (v instanceof Decimal_1.Decimal) {
124
+ return v.toString();
125
+ }
126
+ if ('object' === t && 'function' === typeof v.toJSON) {
127
+ return emit(v.toJSON(), unit, pad, seen);
128
+ }
129
+ if (seen.has(v)) {
130
+ throw new err_1.AontuError('aontu: cannot convert circular structure to JSON');
131
+ }
132
+ seen.add(v);
133
+ const inner = pad + unit;
134
+ const nl = '' === unit ? '' : '\n';
135
+ let out;
136
+ if (Array.isArray(v)) {
137
+ if (0 === v.length) {
138
+ out = '[]';
139
+ }
140
+ else {
141
+ const parts = v.map((e) => inner + emit(skipped(e) ? null : e, unit, inner, seen));
142
+ out = '[' + nl + parts.join(',' + nl) + nl + pad + ']';
143
+ }
144
+ }
145
+ else {
146
+ const colon = '' === unit ? ':' : ': ';
147
+ const parts = [];
148
+ // OWN enumerable keys, SORTED. A `for ... in` here would additionally
149
+ // walk the prototype chain.
150
+ //
151
+ // WHY THE SORT IS HERE AND NOT IN gen(). BagVal.gen already sorts map
152
+ // entries lexicographically -- and then writes them into a plain JS
153
+ // object, where ECMAScript throws that sort away. OrdinaryOwnPropertyKeys
154
+ // lists canonical ARRAY-INDEX keys first, in ascending NUMERIC order,
155
+ // and only then the remaining string keys in insertion order. So
156
+ // `{9:1,10:2}` came back out as 9 before 10, and `{"!":1,9:2}` put the
157
+ // digit key ahead of the punctuation one.
158
+ //
159
+ // This is not a V8 quirk and not a JSON.stringify quirk; it is the
160
+ // object's own key order, and it CANNOT be fixed upstream, because no
161
+ // JavaScript object can hold "10" before "9". The emitter is the last
162
+ // point that still has the freedom to choose, so it chooses here.
163
+ //
164
+ // The giveaway that it was never a design rule: only indices up to
165
+ // 2^32-2 are hoisted, so `{4294967295:1,4294967296:2,5:3}` emitted as
166
+ // 5, 4294967295, 4294967296 -- and TypeScript's own CANON, which builds
167
+ // text from a sorted list rather than from an object, was lexicographic
168
+ // all along. The port contradicted itself.
169
+ //
170
+ // Lexicographic by UTF-16 code unit, which is what `<` on JS strings
171
+ // does and what MapVal.canon/BagVal.gen already sort by. Go sorts map
172
+ // keys by UTF-8 byte, and the two orders agree on every key that stays
173
+ // inside the BMP; astral-plane keys are a separate, tracked divergence.
174
+ // CODE POINT order (cmpCodePoint), which is what Go's UTF-8 byte sort
175
+ // produces. A bare .sort() is UTF-16 code-unit order, which puts an
176
+ // astral key ahead of everything in U+E000-U+FFFF.
177
+ for (const k of Object.keys(v).sort(keyorder_1.cmpCodePoint)) {
178
+ const cv = v[k];
179
+ if (skipped(cv)) {
180
+ continue;
181
+ }
182
+ parts.push(inner + quote(k) + colon + emit(cv, unit, inner, seen));
183
+ }
184
+ out = 0 === parts.length ? '{}' :
185
+ '{' + nl + parts.join(',' + nl) + nl + pad + '}';
186
+ }
187
+ seen.delete(v);
188
+ return out;
189
+ }
190
+ /**
191
+ * Serialise a value produced by `Aontu.generate()` as JSON text,
192
+ * preserving EXACT numbers.
193
+ *
194
+ * Use this instead of `JSON.stringify` on generated output. A document
195
+ * that uses the `0d` exact leaves generates native `bigint` and
196
+ * `Decimal` values; `JSON.stringify` throws on the first and mangles the
197
+ * second, while this emitter writes both as raw JSON numbers with their
198
+ * exact digits -- which is what the D9 generate contract promises, and
199
+ * what the Go port's marshallers produce for the same document.
200
+ *
201
+ * ```ts
202
+ * import { Aontu, exactJSON } from 'aontu'
203
+ *
204
+ * const out = new Aontu().generate('x:0d9007199254740993')
205
+ * typeof out.x // 'bigint'
206
+ * exactJSON(out) // '{"x":9007199254740993}'
207
+ * exactJSON(out, 2) // '{\n "x": 9007199254740993\n}'
208
+ * JSON.stringify(out) // TypeError: Do not know how to serialize a BigInt
209
+ * ```
210
+ *
211
+ * @param value The value to serialise -- normally `generate()` output:
212
+ * `null`, booleans, numbers, strings, `bigint`,
213
+ * `Decimal`, arrays and plain objects. An object with a
214
+ * `toJSON` method is asked for its replacement first
215
+ * (`Decimal` is handled as a number before that check).
216
+ * @param indent Optional indentation, with `JSON.stringify`'s `space`
217
+ * semantics: a number of spaces (clamped to 0..10) or a
218
+ * literal string. Omitted or `0` gives COMPACT output
219
+ * (no spaces, no newlines) -- the form the shared spec
220
+ * suite's `gens` mode compares byte for byte.
221
+ * @returns The JSON text. Unlike `JSON.stringify` this always
222
+ * returns a string: a top-level `undefined` is `null`.
223
+ * @throws {AontuError} if the value contains a reference cycle.
224
+ */
225
+ function exactJSON(value, indent) {
226
+ return emit(value, indentUnit(indent), '', new Set());
227
+ } /* node:coverage ignore next 6 */
228
+ //# sourceMappingURL=exactjson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exactjson.js","sourceRoot":"","sources":["../src/exactjson.ts"],"names":[],"mappings":"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"}
package/dist/hints.d.ts CHANGED
@@ -5,4 +5,6 @@
5
5
  * Each value is a human-readable explanation of what the error means.
6
6
  */
7
7
  declare const hints: Record<string, string>;
8
- export { hints, };
8
+ declare const codeClasses: Record<string, string>;
9
+ declare function codeClass(code: string): string;
10
+ export { hints, codeClasses, codeClass, };
package/dist/hints.js CHANGED
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  /* Copyright (c) 2025 Richard Rodger, MIT License */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.hints = void 0;
4
+ exports.codeClasses = exports.hints = void 0;
5
+ exports.codeClass = codeClass;
5
6
  /**
6
7
  * Error code hints for Aontu unification errors.
7
8
  *
@@ -15,12 +16,12 @@ const hints = {
15
16
  ' 1 & 1 -> 1 # Does unify (equal Integers);\n' +
16
17
  ' a & a -> a # Does unify (equal Strings);\n' +
17
18
  ' 1 & 2 -> nil # Does not unify (unequal Integers);\n' +
18
- ' 1 & 1.0 -> nil # Does not unify (kinds: Integer & Number).',
19
+ ' 1 & 1.0 -> nil # Does not unify (kinds: Integer & Float).',
19
20
  scalar_kind: 'Literal scalar values of different kinds cannot unify.' +
20
21
  '\n \nExamples:\n' +
21
22
  ' 1 & 1 -> 1 # Does unify (equal Integers);\n' +
22
23
  ' 1 & a -> nil # Does not unify (Kinds: Integer & String);\n' +
23
- ' 1 & 1.0 -> nil # Does not unify (kinds: Integer & Number).',
24
+ ' 1 & 1.0 -> nil # Does not unify (kinds: Integer & Float).',
24
25
  nil_gen: 'The nil value was present after unification, and nil cannot be\n' +
25
26
  'generated because nil is not a literal value.',
26
27
  no_gen: 'This value was present after unification, and cannot be generated\n' +
@@ -37,6 +38,22 @@ const hints = {
37
38
  unknown_function: 'This function name is not recognized.',
38
39
  literal_nil: 'A literal nil cannot unify with any other value.',
39
40
  unify_cycle: 'Circular reference detected during unification.',
41
+ constraint: 'This value does not satisfy the constraint. A constraint is the\n' +
42
+ 'meet of bound atoms (min, max, above, below) and exclusions (neq)\n' +
43
+ 'over one domain; the expected form shown is the normalised\n' +
44
+ 'residual the value must satisfy.' +
45
+ '\n \nExamples:\n' +
46
+ ' min(0) & 3 -> 3 # Admitted (3 >= 0);\n' +
47
+ ' min(0) & 0d5 -> 0d5 # Bounds are leaf-agnostic;\n' +
48
+ ' max(65535) & 99999 -> nil # Above the bound;\n' +
49
+ ' min(5) & max(3) -> nil # Empty at composition time;\n' +
50
+ ' integer & above(1) & below(2) -> nil # No integer in the gap;\n' +
51
+ ' neq(1) & 1.0 -> 1.0 # neq excludes leaf AND value.',
52
+ budget_passes: 'The evaluation budget of {limit} fixpoint passes was spent before\n' +
53
+ 'the model converged; still refining: {paths}.\n' +
54
+ 'This is the evaluator giving up, not a contradiction in the model:\n' +
55
+ 'raising the budget helps only a model that is still converging --\n' +
56
+ 'a genuine cycle never converges at any budget.',
40
57
  conjunct: 'This conjunction (& operator) could not be completed as some terms\n' +
41
58
  'could not be resolved.',
42
59
  no_path: 'The path reference could not be found.' +
@@ -51,14 +68,71 @@ const hints = {
51
68
  'unite': 'Failed to unite two values. The values are incompatible and cannot be unified.',
52
69
  'internal': 'Internal error during unification. This indicates an unexpected error in the unification process.',
53
70
  // Type mismatch errors
54
- 'scalar-type': 'Scalar type mismatch. The scalar types are incompatible.',
55
- 'no_scalar_unify': 'Cannot unify scalar values. The scalar values have incompatible types.',
71
+ decimal_budget: 'This exact decimal exceeds the exactness budget: at most 4096\n' +
72
+ 'coefficient digits and an absolute scale of at most 4096. The\n' +
73
+ 'budget applies to computed results as well as to literals.\n' +
74
+ 'Aontu never rounds, so a value beyond the budget is refused\n' +
75
+ 'rather than approximated.' +
76
+ '\n \nExamples:\n' +
77
+ ' 0d1e1000000000 -> nil # Scale far beyond the budget;\n' +
78
+ ' 0d1e4000+0d1e-4000 -> nil # An exact sum too wide to hold;\n' +
79
+ ' 0d1e-1 -> 0d0.1 # Well within it.',
80
+ lossy_integer_literal: 'This integer literal, {src}, is not exactly representable in\n' +
81
+ 'binary64, so storing it would silently round it to a DIFFERENT\n' +
82
+ 'number. Aontu refuses rather than corrupts: write it as a `0d`\n' +
83
+ 'literal to get the exact integer.\n' +
84
+ 'The rule is exactness, not magnitude -- a literal far outside the\n' +
85
+ 'int64 window is still a value when it lands exactly on a binary64.' +
86
+ '\n \nExamples:\n' +
87
+ ' 9007199254740992 -> 9007199254740992 # 2^53, exact;\n' +
88
+ ' 9007199254740993 -> nil # 2^53+1 is not;\n' +
89
+ ' 0d9007199254740993 -> 0d9007199254740993 # ... the exact escape;\n' +
90
+ ' 0x7fffffffffffffff -> nil # 2^63-1 rounds up to 2^63;\n' +
91
+ ' 100000000000000000000 -> 1e20 # 10^20 is huge and exact.',
92
+ exact_float_mix: 'Aontu cannot mix an exact number with a binary float.\n' +
93
+ 'Here the operands are {left} and {right}, in that order.\n' +
94
+ 'A big type never silently becomes a binary float, in either\n' +
95
+ 'operand order -- binary64 cannot hold every exact value, so the\n' +
96
+ 'promotion would throw away the exactness the `0d` leaves exist to\n' +
97
+ 'guarantee. Write both operands in the same family (`0d1.0` for the\n' +
98
+ 'float, or a plain integer for the big).' +
99
+ '\n \nExamples:\n' +
100
+ ' 0d2 + 0d0.5 -> 0d2.5 # Exact with exact (widest leaf wins);\n' +
101
+ ' 1 + 0d0.5 -> 0d1.5 # integer is on the exact ladder;\n' +
102
+ ' 1 + 2.0 -> 3.0 # ... and float still mixes with integer;\n' +
103
+ ' 1.0 + 0d2 -> nil # float with biginteger;\n' +
104
+ ' 0d0.5 + 1.0 -> nil # ... and the same the other way round.',
105
+ inexact_integer_sum: 'The `integer` leaf holds a value only when it is integral, within\n' +
106
+ 'the int64 range, and exactly representable in binary64. This sum\n' +
107
+ 'is not: {sum}.\n' +
108
+ 'Aontu adds integers exactly and refuses to store a rounded answer\n' +
109
+ '-- write `0d<digits>` for an exact integer beyond that window.' +
110
+ '\n \nExamples:\n' +
111
+ ' 4503599627370496 + 4503599627370496 -> 9007199254740992 # Exact;\n' +
112
+ ' 4503599627370496 + 4503599627370497 -> nil # 2^53+1 is not;\n' +
113
+ ' 0d4503599627370496 + 0d4503599627370497 -> 0d9007199254740993.',
114
+ 'scalar-type': 'Scalar kinds only unify when one contains the other. `number` is\n' +
115
+ 'the supertype of the numeric leaves (integer, float, biginteger,\n' +
116
+ 'bigdecimal), so meeting it with a leaf gives that leaf; two distinct\n' +
117
+ 'leaves describe disjoint sets of values and so have no common lower\n' +
118
+ 'bound.' +
119
+ '\n \nExamples:\n' +
120
+ ' number & integer -> integer # Does unify (integer is a number);\n' +
121
+ ' number & number -> number # Does unify (same kind);\n' +
122
+ ' float & integer -> nil # Does not unify (disjoint leaves).',
123
+ 'no_scalar_unify': 'Cannot unify scalar values. The scalar values have incompatible types.' +
124
+ '\n \nExamples:\n' +
125
+ ' number & 1 -> 1 # Does unify (1 is a number);\n' +
126
+ ' integer & 1 -> 1 # Does unify (1 is an integer);\n' +
127
+ ' float & 1 -> nil # Does not unify (1 is an integer, not a float);\n' +
128
+ ' integer & 1.5 -> nil # Does not unify (1.5 is a float, not an integer).',
56
129
  'not-scalar-type': 'Expected a scalar type but got a non-scalar type.',
57
130
  'map': 'Type mismatch: expected a map value but got a different type.',
58
131
  'list': 'Type mismatch: expected a list value but got a different type.',
59
132
  // Argument errors
60
133
  'arg': 'Missing required argument. A function requires an argument but none was provided.',
61
134
  'invalid-arg': 'Invalid argument provided. The argument does not match the expected type or format.',
135
+ 'key_level': 'The argument to key() is a LEVEL: how many steps up the path to look, where 0 is the key of the value itself and the default 1 is its parent. It must therefore be an integer -- `key(2)`, or `key(0d2)` for the exact leaf. A float, a decimal, a string, a boolean, a map or a list is not a level. A level beyond the top of the path is not an error; it yields the empty string.',
62
136
  'no_first_arg': 'Missing first argument. The function requires a first argument but none was provided.',
63
137
  // Variable errors
64
138
  'unknown_var': 'Unknown variable reference. The variable has not been defined.',
@@ -90,4 +164,112 @@ const hints = {
90
164
  'op[': 'Operator value error: ',
91
165
  };
92
166
  exports.hints = hints;
167
+ // codeClasses assigns every error code a CLASS: conflict | incomplete |
168
+ // reference | parse | budget | internal. The contract lives in
169
+ // test/spec/errcodes.tsv (mode `errcode`): the spec suite executes one
170
+ // row per code against this table and asserts SET EQUALITY between the
171
+ // file and these keys, in both implementations (go/hints.go mirrors
172
+ // this map exactly). Codes are append-only and never renamed; a class
173
+ // change is a breaking change. Class rulings (why decimal_budget and
174
+ // lossy_integer_literal are conflict, not budget; why unknown_function
175
+ // is reference) are documented in the tsv header.
176
+ const codeClasses = {
177
+ // parse -- the source text is malformed or unusable
178
+ parse: 'parse',
179
+ syntax: 'parse',
180
+ parse_unknown: 'parse',
181
+ parse_bad_src: 'parse',
182
+ unify_no_src: 'parse',
183
+ incomplete_expression: 'parse',
184
+ not_number: 'parse',
185
+ negative: 'parse',
186
+ decimal_syntax: 'parse',
187
+ // conflict -- no common lower bound, or a value refused by a rule
188
+ // (constraint covers the whole algebra family: membership failure,
189
+ // empty meets at composition time, and domain/kind mixing.)
190
+ constraint: 'conflict',
191
+ scalar_value: 'conflict',
192
+ scalar_kind: 'conflict',
193
+ no_scalar_unify: 'conflict',
194
+ 'scalar-type': 'conflict',
195
+ 'not-scalar-type': 'conflict',
196
+ map: 'conflict',
197
+ list: 'conflict',
198
+ closed: 'conflict',
199
+ literal_nil: 'conflict',
200
+ nil_gen: 'conflict',
201
+ unite: 'conflict',
202
+ '|:empty': 'conflict',
203
+ '|:empty-dist': 'conflict',
204
+ exact_float_mix: 'conflict',
205
+ inexact_integer_sum: 'conflict',
206
+ decimal_budget: 'conflict',
207
+ lossy_integer_literal: 'conflict',
208
+ arg: 'conflict',
209
+ 'invalid-arg': 'conflict',
210
+ no_first_arg: 'conflict',
211
+ key_level: 'conflict',
212
+ func: 'conflict',
213
+ 'func:': 'conflict',
214
+ op: 'conflict',
215
+ 'op:': 'conflict',
216
+ 'op[': 'conflict',
217
+ make: 'conflict',
218
+ resolve: 'conflict',
219
+ operate: 'conflict',
220
+ close: 'conflict',
221
+ // incomplete -- residue: the truth requires more than was supplied
222
+ no_gen: 'incomplete',
223
+ conjunct: 'incomplete',
224
+ mapval_no_gen: 'incomplete',
225
+ mapval_required: 'incomplete',
226
+ mapval_spread_required: 'incomplete',
227
+ listval_no_gen: 'incomplete',
228
+ listval_required: 'incomplete',
229
+ listval_spread_required: 'incomplete',
230
+ required_listelem: 'incomplete',
231
+ // reference -- a name or path that does not resolve
232
+ no_path: 'reference',
233
+ // A PROVEN structural cycle is a defect of the model, not a spent
234
+ // evaluation bound: raising a budget never fixes it (G5's ruling --
235
+ // class budget means "retry with more may help", path_cycle means
236
+ // "fix the model").
237
+ path_cycle: 'reference',
238
+ ref: 'reference',
239
+ 'ref[': 'reference',
240
+ var: 'reference',
241
+ 'var[': 'reference',
242
+ unknown_var: 'reference',
243
+ invalid_var_kind: 'reference',
244
+ unknown_function: 'reference',
245
+ multisource_not_found: 'reference',
246
+ // budget -- an evaluation bound was exceeded
247
+ unify_cycle: 'budget',
248
+ max_depth: 'budget',
249
+ budget_passes: 'budget',
250
+ // internal -- the engine reached a state it should not reach
251
+ internal: 'internal',
252
+ unify_no_res: 'internal',
253
+ unknown_op: 'internal',
254
+ };
255
+ exports.codeClasses = codeClasses;
256
+ // Dynamic-prefix families: the engine appends a name or value to these
257
+ // (e.g. `func:upper`, `op:+`, `var[string]`, `ref[$.x]`, `op[+]`), so
258
+ // class lookup falls back to the registered prefix.
259
+ const CODE_PREFIXES = ['func:', 'op:', 'op[', 'var[', 'ref['];
260
+ // The class of an error code: an exact registry entry, else the
261
+ // registered dynamic prefix it extends, else `internal` -- an
262
+ // unregistered code is an engine defect, not a user error.
263
+ function codeClass(code) {
264
+ const cls = codeClasses[code];
265
+ if (null != cls) {
266
+ return cls;
267
+ }
268
+ for (const prefix of CODE_PREFIXES) {
269
+ if (code.startsWith(prefix)) {
270
+ return codeClasses[prefix];
271
+ }
272
+ }
273
+ return 'internal';
274
+ } /* node:coverage ignore next 8 */
93
275
  //# sourceMappingURL=hints.js.map
package/dist/hints.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hints.js","sourceRoot":"","sources":["../src/hints.ts"],"names":[],"mappings":";AAAA,oDAAoD;;;AAEpD;;;;;GAKG;AAEH,MAAM,KAAK,GAA2B;IAEpC,YAAY,EACV,qEAAqE;QACrE,gBAAgB;QAChB,kBAAkB;QAClB,oDAAoD;QACpD,mDAAmD;QACnD,0DAA0D;QAC1D,+DAA+D;IAEjE,WAAW,EACT,wDAAwD;QACxD,kBAAkB;QAClB,oDAAoD;QACpD,iEAAiE;QACjE,+DAA+D;IAEjE,OAAO,EACL,kEAAkE;QAClE,+CAA+C;IAEjD,MAAM,EACJ,qEAAqE;QACrE,oCAAoC;IAGtC,6DAA6D;IAC7D,eAAe,EAAE,6BAA6B;IAE9C,aAAa,EACX,qEAAqE;QACrE,oCAAoC;IAEtC,sBAAsB,EACpB,0DAA0D;IAE5D,gBAAgB,EAAE,gCAAgC;IAElD,cAAc,EACZ,4EAA4E;QAC5E,oCAAoC;IAEtC,uBAAuB,EACrB,0DAA0D;IAE5D,gBAAgB,EACd,uCAAuC;IAEzC,WAAW,EACT,kDAAkD;IAEpD,WAAW,EAAE,iDAAiD;IAE9D,QAAQ,EACN,sEAAsE;QACtE,wBAAwB;IAE1B,OAAO,EAAE,wCAAwC;QAC/C,kBAAkB;QAClB,uFAAuF;QACvF,kGAAkG;IAEpG,iBAAiB;IACjB,eAAe,EAAE,6EAA6E;IAE9F,qBAAqB;IACrB,cAAc,EAAE,yEAAyE;IACzF,cAAc,EAAE,kEAAkE;IAClF,OAAO,EAAE,gFAAgF;IAEzF,UAAU,EAAE,mGAAmG;IAE/G,uBAAuB;IAEvB,aAAa,EAAE,0DAA0D;IACzE,iBAAiB,EAAE,wEAAwE;IAC3F,iBAAiB,EAAE,mDAAmD;IACtE,KAAK,EAAE,+DAA+D;IACtE,MAAM,EAAE,gEAAgE;IAExE,kBAAkB;IAClB,KAAK,EAAE,mFAAmF;IAC1F,aAAa,EAAE,qFAAqF;IACpG,cAAc,EAAE,uFAAuF;IAEvG,kBAAkB;IAClB,aAAa,EAAE,gEAAgE;IAC/E,kBAAkB,EAAE,4EAA4E;IAEhG,4BAA4B;IAC5B,UAAU,EAAE,8DAA8D;IAC1E,KAAK,EAAE,0EAA0E;IAEjF,2BAA2B;IAC3B,QAAQ,EAAE,kGAAkG;IAC5G,mBAAmB,EAAE,6EAA6E;IAElG,2CAA2C;IAC3C,SAAS,EAAE,+DAA+D;IAC1E,cAAc,EAAE,kFAAkF;IAElG,WAAW,EAAE,8CAA8C;IAE3D,qCAAqC;IACrC,MAAM,EAAE,wEAAwE;IAChF,MAAM,EAAE,iFAAiF;IACzF,SAAS,EAAE,wFAAwF;IACnG,SAAS,EAAE,6EAA6E;IAExF,qCAAqC;IACrC,IAAI,EAAE,wEAAwE;IAE9E,kBAAkB;IAClB,OAAO,EAAE,+DAA+D;IAExE,6CAA6C;IAC7C,OAAO,EAAE,kBAAkB;IAC3B,KAAK,EAAE,kBAAkB;IACzB,MAAM,EAAE,uBAAuB;IAC/B,MAAM,EAAE,mBAAmB;IAC3B,KAAK,EAAE,wBAAwB;CAChC,CAAA;QAIC,KAAK"}
1
+ {"version":3,"file":"hints.js","sourceRoot":"","sources":["../src/hints.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Compare two map keys by Unicode CODE POINT.
3
+ *
4
+ * `String.prototype[Symbol.iterator]` yields whole code points, pairing
5
+ * surrogates, so this is a plain lexicographic compare of code point
6
+ * sequences -- the order Go's UTF-8 byte sort produces.
7
+ */
8
+ declare function cmpCodePoint(a: string, b: string): number;
9
+ export { cmpCodePoint, };
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ /* Copyright (c) 2025 Richard Rodger, MIT License */
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.cmpCodePoint = cmpCodePoint;
5
+ /*
6
+ * THE ONE MAP-KEY ORDER, shared by every site that emits keys.
7
+ *
8
+ * Map key order is not meaningful in unification, so both ports sort to
9
+ * make output independent of insertion and unification order. The order
10
+ * they sort into has to be the SAME order, and it was not.
11
+ *
12
+ * JavaScript compares strings by UTF-16 CODE UNIT. An astral character is
13
+ * stored as a surrogate pair beginning D800-DBFF, so `<` puts it BEFORE
14
+ * every character in U+E000-U+FFFF -- ahead of the private use area, of
15
+ * U+FFFD, of U+FFFF. Go sorts map keys as UTF-8 bytes, which is code
16
+ * POINT order, so it puts the astral character last. The two agree on
17
+ * everything below U+D800 and disagree above U+DFFF, which is why this
18
+ * survived: the shared suite had no key above the BMP at all, and three
19
+ * separate comments in the tree asserted the ports already agreed.
20
+ *
21
+ * CODE POINT ORDER WINS, and not merely because Go had it. Go's
22
+ * `generate()` returns a native map, so a consumer's own `json.Marshal`
23
+ * sorts byte-wise no matter what this engine chooses -- picking UTF-16
24
+ * order would leave the TypeScript output disagreeing with what a Go
25
+ * consumer produces from the same document.
26
+ *
27
+ * NOT Buffer.compare, which would be the obvious shortcut. A lone
28
+ * surrogate has no valid UTF-8 encoding, so Buffer.from replaces it with
29
+ * U+FFFD and two DISTINCT keys compare equal -- reintroducing exactly the
30
+ * insertion-order dependence the sort exists to remove. Iterating code
31
+ * points keeps distinct keys distinct.
32
+ */
33
+ /**
34
+ * Compare two map keys by Unicode CODE POINT.
35
+ *
36
+ * `String.prototype[Symbol.iterator]` yields whole code points, pairing
37
+ * surrogates, so this is a plain lexicographic compare of code point
38
+ * sequences -- the order Go's UTF-8 byte sort produces.
39
+ */
40
+ function cmpCodePoint(a, b) {
41
+ // Fast path: identical strings, and the common all-BMP case where the
42
+ // two orders coincide, still walk the iterator -- but the loop exits at
43
+ // the first differing code point, so it is one pass over the shared
44
+ // prefix rather than any conversion or allocation.
45
+ const ai = a[Symbol.iterator]();
46
+ const bi = b[Symbol.iterator]();
47
+ for (;;) {
48
+ const x = ai.next();
49
+ const y = bi.next();
50
+ // A prefix sorts before the string it is a prefix of, and two equal
51
+ // strings compare 0 -- the same rule a byte compare gives.
52
+ if (x.done) {
53
+ return y.done ? 0 : -1;
54
+ }
55
+ if (y.done) {
56
+ return 1;
57
+ }
58
+ const xc = x.value.codePointAt(0);
59
+ const yc = y.value.codePointAt(0);
60
+ if (xc !== yc) {
61
+ return xc < yc ? -1 : 1;
62
+ }
63
+ }
64
+ } /* node:coverage ignore next 6 */
65
+ //# sourceMappingURL=keyorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyorder.js","sourceRoot":"","sources":["../src/keyorder.ts"],"names":[],"mappings":";AAAA,oDAAoD;;QAuElD,YAAY;AArEd;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,CAAS,EAAE,CAAS;IACxC,sEAAsE;IACtE,wEAAwE;IACxE,oEAAoE;IACpE,mDAAmD;IACnD,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAA;IAC/B,MAAM,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAA;IAE/B,SAAU,CAAC;QACT,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAA;QACnB,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAA;QAEnB,oEAAoE;QACpE,2DAA2D;QAC3D,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACX,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACxB,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YACX,OAAO,CAAC,CAAA;QACV,CAAC;QAED,MAAM,EAAE,GAAI,CAAC,CAAC,KAAgB,CAAC,WAAW,CAAC,CAAC,CAAW,CAAA;QACvD,MAAM,EAAE,GAAI,CAAC,CAAC,KAAgB,CAAC,WAAW,CAAC,CAAC,CAAW,CAAA;QAEvD,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACd,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACzB,CAAC;IACH,CAAC;AACH,CAAC,CAAC,iCAAiC"}