aontu 0.62.0 → 0.63.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 +1 -1
- package/dist/agentsmd.js +0 -27
- package/dist/agentsmd.js.map +1 -1
- package/dist/alias.js.map +1 -1
- package/dist/allow.js +0 -92
- package/dist/allow.js.map +1 -1
- package/dist/aontu.d.ts +1 -1
- package/dist/aontu.js +1 -79
- package/dist/aontu.js.map +1 -1
- package/dist/aontumodel.d.ts +4 -0
- package/dist/aontumodel.js +33 -0
- package/dist/aontumodel.js.map +1 -0
- package/dist/cli.js +101 -620
- package/dist/cli.js.map +1 -1
- package/dist/ctx.js +0 -48
- package/dist/ctx.js.map +1 -1
- package/dist/diff.js +0 -32
- package/dist/diff.js.map +1 -1
- package/dist/err.js +0 -40
- package/dist/err.js.map +1 -1
- package/dist/escape.js +0 -45
- package/dist/escape.js.map +1 -1
- package/dist/exactjson.d.ts +0 -35
- package/dist/exactjson.js +0 -131
- package/dist/exactjson.js.map +1 -1
- package/dist/format.js +13 -203
- package/dist/format.js.map +1 -1
- package/dist/grammar.d.ts +9 -0
- package/dist/grammar.js +54 -0
- package/dist/grammar.js.map +1 -0
- package/dist/graph.js +0 -26
- package/dist/graph.js.map +1 -1
- package/dist/hcanon.js +0 -82
- package/dist/hcanon.js.map +1 -1
- package/dist/helpdoc.js +1 -1
- package/dist/helpdoc.js.map +1 -1
- package/dist/hints.d.ts +0 -6
- package/dist/hints.js +54 -55
- package/dist/hints.js.map +1 -1
- package/dist/jsonschema.js +0 -114
- package/dist/jsonschema.js.map +1 -1
- package/dist/keyorder.d.ts +0 -7
- package/dist/keyorder.js +0 -41
- package/dist/keyorder.js.map +1 -1
- package/dist/lang.js +17 -915
- package/dist/lang.js.map +1 -1
- package/dist/lower.js +11 -61
- package/dist/lower.js.map +1 -1
- package/dist/lsp-server.js +0 -16
- package/dist/lsp-server.js.map +1 -1
- package/dist/lsp.d.ts +1 -1
- package/dist/lsp.js +12 -159
- package/dist/lsp.js.map +1 -1
- package/dist/mcp-server.js +0 -26
- package/dist/mcp-server.js.map +1 -1
- package/dist/mcp.js +0 -113
- package/dist/mcp.js.map +1 -1
- package/dist/mod-tool.js +0 -130
- package/dist/mod-tool.js.map +1 -1
- package/dist/mod.js +0 -162
- package/dist/mod.js.map +1 -1
- package/dist/patch.js +0 -217
- package/dist/patch.js.map +1 -1
- package/dist/provenance.js +0 -140
- package/dist/provenance.js.map +1 -1
- package/dist/query.js +0 -75
- package/dist/query.js.map +1 -1
- package/dist/reach.js +0 -43
- package/dist/reach.js.map +1 -1
- package/dist/relation.js +0 -61
- package/dist/relation.js.map +1 -1
- package/dist/render.js +20 -135
- package/dist/render.js.map +1 -1
- package/dist/report-sarif.d.ts +0 -11
- package/dist/report-sarif.js +0 -28
- package/dist/report-sarif.js.map +1 -1
- package/dist/sig.js +0 -35
- package/dist/sig.js.map +1 -1
- package/dist/sigdecl.js +1 -1
- package/dist/sigdecl.js.map +1 -1
- package/dist/siggate.js +0 -4
- package/dist/siggate.js.map +1 -1
- package/dist/site.js +3 -29
- package/dist/site.js.map +1 -1
- package/dist/subsume.d.ts +0 -10
- package/dist/subsume.js +0 -137
- package/dist/subsume.js.map +1 -1
- package/dist/template.d.ts +2 -1
- package/dist/template.js +58 -138
- package/dist/template.js.map +1 -1
- package/dist/trim.js +0 -41
- package/dist/trim.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/type.js.map +1 -1
- package/dist/unify.js +12 -242
- package/dist/unify.js.map +1 -1
- package/dist/utility.js +0 -22
- package/dist/utility.js.map +1 -1
- package/dist/val/AbnfFuncVal.d.ts +18 -0
- package/dist/val/AbnfFuncVal.js +132 -0
- package/dist/val/AbnfFuncVal.js.map +1 -0
- package/dist/val/AbsentVal.d.ts +11 -0
- package/dist/val/AbsentVal.js +30 -0
- package/dist/val/AbsentVal.js.map +1 -0
- package/dist/val/AggFuncVal.d.ts +10 -1
- package/dist/val/AggFuncVal.js +104 -116
- package/dist/val/AggFuncVal.js.map +1 -1
- package/dist/val/ArithFuncVal.js +0 -12
- package/dist/val/ArithFuncVal.js.map +1 -1
- package/dist/val/BagVal.js +1 -78
- package/dist/val/BagVal.js.map +1 -1
- package/dist/val/BigDecimalVal.js +0 -16
- package/dist/val/BigDecimalVal.js.map +1 -1
- package/dist/val/BigIntegerVal.js +0 -16
- package/dist/val/BigIntegerVal.js.map +1 -1
- package/dist/val/CloseFuncVal.js +0 -9
- package/dist/val/CloseFuncVal.js.map +1 -1
- package/dist/val/CmpFuncVal.js +2 -59
- package/dist/val/CmpFuncVal.js.map +1 -1
- package/dist/val/ConjunctVal.js +0 -29
- package/dist/val/ConjunctVal.js.map +1 -1
- package/dist/val/ConstraintVal.js +0 -500
- package/dist/val/ConstraintVal.js.map +1 -1
- package/dist/val/ContainerKindVal.js +0 -2
- package/dist/val/ContainerKindVal.js.map +1 -1
- package/dist/val/CopyFuncVal.js +0 -3
- package/dist/val/CopyFuncVal.js.map +1 -1
- package/dist/val/Decimal.js +0 -179
- package/dist/val/Decimal.js.map +1 -1
- package/dist/val/DeprecateFuncVal.js.map +1 -1
- package/dist/val/DisjunctVal.js +0 -152
- package/dist/val/DisjunctVal.js.map +1 -1
- package/dist/val/EachFuncVal.js +0 -3
- package/dist/val/EachFuncVal.js.map +1 -1
- package/dist/val/EmitFuncVal.d.ts +1 -1
- package/dist/val/EmitFuncVal.js +6 -119
- package/dist/val/EmitFuncVal.js.map +1 -1
- package/dist/val/ExpectVal.js +0 -62
- package/dist/val/ExpectVal.js.map +1 -1
- package/dist/val/FilterFuncVal.js +0 -25
- package/dist/val/FilterFuncVal.js.map +1 -1
- package/dist/val/FuncBaseVal.d.ts +1 -0
- package/dist/val/FuncBaseVal.js +7 -127
- package/dist/val/FuncBaseVal.js.map +1 -1
- package/dist/val/GraphAtomVal.js +0 -15
- package/dist/val/GraphAtomVal.js.map +1 -1
- package/dist/val/HideFuncVal.js +0 -13
- package/dist/val/HideFuncVal.js.map +1 -1
- package/dist/val/IntegerVal.js +0 -61
- package/dist/val/IntegerVal.js.map +1 -1
- package/dist/val/JunctionVal.js +0 -20
- package/dist/val/JunctionVal.js.map +1 -1
- package/dist/val/KeyFuncVal.js +0 -46
- package/dist/val/KeyFuncVal.js.map +1 -1
- package/dist/val/ListVal.js +0 -57
- package/dist/val/ListVal.js.map +1 -1
- package/dist/val/LowerFuncVal.js +0 -11
- package/dist/val/LowerFuncVal.js.map +1 -1
- package/dist/val/MapVal.js +0 -151
- package/dist/val/MapVal.js.map +1 -1
- package/dist/val/MatchFuncVal.js +0 -27
- package/dist/val/MatchFuncVal.js.map +1 -1
- package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
- package/dist/val/MaybeFuncVal.js +50 -0
- package/dist/val/MaybeFuncVal.js.map +1 -0
- package/dist/val/MoveFuncVal.js +0 -18
- package/dist/val/MoveFuncVal.js.map +1 -1
- package/dist/val/NilVal.js +0 -60
- package/dist/val/NilVal.js.map +1 -1
- package/dist/val/NomFuncVal.js +8 -42
- package/dist/val/NomFuncVal.js.map +1 -1
- package/dist/val/NumberVal.js +0 -15
- package/dist/val/NumberVal.js.map +1 -1
- package/dist/val/OpBaseVal.d.ts +1 -0
- package/dist/val/OpBaseVal.js +3 -15
- package/dist/val/OpBaseVal.js.map +1 -1
- package/dist/val/PackFuncVal.js +0 -34
- package/dist/val/PackFuncVal.js.map +1 -1
- package/dist/val/PathFuncVal.js +0 -6
- package/dist/val/PathFuncVal.js.map +1 -1
- package/dist/val/PathVal.js +0 -41
- package/dist/val/PathVal.js.map +1 -1
- package/dist/val/PlaceVal.js +0 -25
- package/dist/val/PlaceVal.js.map +1 -1
- package/dist/val/PlusOpVal.d.ts +1 -7
- package/dist/val/PlusOpVal.js +13 -74
- package/dist/val/PlusOpVal.js.map +1 -1
- package/dist/val/PrefFuncVal.js +0 -1
- package/dist/val/PrefFuncVal.js.map +1 -1
- package/dist/val/PrefVal.js +0 -167
- package/dist/val/PrefVal.js.map +1 -1
- package/dist/val/RecurseVal.js +0 -55
- package/dist/val/RecurseVal.js.map +1 -1
- package/dist/val/RefVal.js +0 -282
- package/dist/val/RefVal.js.map +1 -1
- package/dist/val/ReferFuncVal.js +0 -232
- package/dist/val/ReferFuncVal.js.map +1 -1
- package/dist/val/ScalarKindVal.js +0 -49
- package/dist/val/ScalarKindVal.js.map +1 -1
- package/dist/val/ScalarVal.js +0 -11
- package/dist/val/ScalarVal.js.map +1 -1
- package/dist/val/StrFuncVal.js +0 -18
- package/dist/val/StrFuncVal.js.map +1 -1
- package/dist/val/SuperFuncVal.js +0 -32
- package/dist/val/SuperFuncVal.js.map +1 -1
- package/dist/val/TopVal.js +0 -1
- package/dist/val/TopVal.js.map +1 -1
- package/dist/val/TranslateFuncVal.js +1 -3
- package/dist/val/TranslateFuncVal.js.map +1 -1
- package/dist/val/UpperFuncVal.js +0 -11
- package/dist/val/UpperFuncVal.js.map +1 -1
- package/dist/val/Val.d.ts +1 -0
- package/dist/val/Val.js +2 -133
- package/dist/val/Val.js.map +1 -1
- package/dist/val/VarVal.js +0 -12
- package/dist/val/VarVal.js.map +1 -1
- package/dist/val/arith.js +0 -37
- package/dist/val/arith.js.map +1 -1
- package/dist/val/caserange.js +0 -61
- package/dist/val/caserange.js.map +1 -1
- package/dist/val/members.js +0 -6
- package/dist/val/members.js.map +1 -1
- package/dist/val/numcmp.js +0 -11
- package/dist/val/numcmp.js.map +1 -1
- package/dist/val/numkind.js +0 -145
- package/dist/val/numkind.js.map +1 -1
- package/dist/val/valutil.js +0 -16
- package/dist/val/valutil.js.map +1 -1
- package/dist/vet.js +0 -461
- package/dist/vet.js.map +1 -1
- package/dist/view.js +0 -414
- package/dist/view.js.map +1 -1
- package/dist/walk.js +0 -41
- package/dist/walk.js.map +1 -1
- package/grammar/aontu.abnf +8 -6
- package/grammar/aontu.gbnf +4 -4
- package/grammar/aontu.lark +4 -4
- package/grammar/aontu.tmLanguage.json +1 -1
- package/package.json +4 -2
- package/src/agentsmd.ts +0 -35
- package/src/alias.ts +0 -39
- package/src/allow.ts +1 -96
- package/src/aontu.ts +3 -110
- package/src/aontumodel.ts +32 -0
- package/src/cli.ts +113 -682
- package/src/ctx.ts +0 -103
- package/src/diff.ts +0 -40
- package/src/err.ts +0 -40
- package/src/escape.ts +0 -46
- package/src/exactjson.ts +0 -131
- package/src/format.ts +14 -257
- package/src/grammar.ts +72 -0
- package/src/graph.ts +0 -61
- package/src/hcanon.ts +0 -82
- package/src/helpdoc.ts +1 -1
- package/src/hints.ts +66 -57
- package/src/jsonschema.ts +0 -123
- package/src/keyorder.ts +0 -42
- package/src/lang.ts +19 -931
- package/src/lower.ts +12 -62
- package/src/lsp-server.ts +0 -16
- package/src/lsp.ts +12 -180
- package/src/mcp-server.ts +0 -31
- package/src/mcp.ts +0 -130
- package/src/mod-tool.ts +0 -158
- package/src/mod.ts +0 -178
- package/src/patch.ts +0 -232
- package/src/provenance.ts +0 -183
- package/src/query.ts +0 -84
- package/src/reach.ts +0 -53
- package/src/relation.ts +0 -84
- package/src/render.ts +20 -172
- package/src/report-sarif.ts +0 -48
- package/src/sig.ts +0 -35
- package/src/sigdecl.ts +1 -1
- package/src/siggate.ts +0 -30
- package/src/site.ts +3 -29
- package/src/subsume.ts +1 -161
- package/src/template.ts +69 -140
- package/src/trim.ts +0 -53
- package/src/type.ts +2 -45
- package/src/unify.ts +13 -251
- package/src/utility.ts +0 -31
- package/src/val/AbnfFuncVal.ts +181 -0
- package/src/val/AbsentVal.ts +54 -0
- package/src/val/AggFuncVal.ts +152 -188
- package/src/val/ArithFuncVal.ts +0 -20
- package/src/val/BagVal.ts +1 -78
- package/src/val/BigDecimalVal.ts +0 -16
- package/src/val/BigIntegerVal.ts +0 -16
- package/src/val/CloseFuncVal.ts +0 -9
- package/src/val/CmpFuncVal.ts +4 -166
- package/src/val/ConjunctVal.ts +0 -33
- package/src/val/ConstraintVal.ts +2 -537
- package/src/val/ContainerKindVal.ts +0 -18
- package/src/val/CopyFuncVal.ts +0 -5
- package/src/val/Decimal.ts +1 -185
- package/src/val/DeprecateFuncVal.ts +0 -10
- package/src/val/DisjunctVal.ts +0 -157
- package/src/val/EachFuncVal.ts +0 -40
- package/src/val/EmitFuncVal.ts +8 -208
- package/src/val/ExpectVal.ts +0 -62
- package/src/val/FilterFuncVal.ts +0 -55
- package/src/val/FuncBaseVal.ts +9 -130
- package/src/val/GraphAtomVal.ts +0 -42
- package/src/val/HideFuncVal.ts +0 -15
- package/src/val/IntegerVal.ts +0 -61
- package/src/val/JunctionVal.ts +0 -20
- package/src/val/KeyFuncVal.ts +0 -48
- package/src/val/ListVal.ts +0 -59
- package/src/val/LowerFuncVal.ts +0 -12
- package/src/val/MapVal.ts +0 -151
- package/src/val/MatchFuncVal.ts +0 -59
- package/src/val/MaybeFuncVal.ts +86 -0
- package/src/val/MoveFuncVal.ts +0 -20
- package/src/val/NilVal.ts +0 -60
- package/src/val/NomFuncVal.ts +8 -95
- package/src/val/NumberVal.ts +0 -16
- package/src/val/OpBaseVal.ts +4 -17
- package/src/val/PackFuncVal.ts +0 -63
- package/src/val/PathFuncVal.ts +0 -32
- package/src/val/PathVal.ts +0 -66
- package/src/val/PlaceVal.ts +0 -45
- package/src/val/PlusOpVal.ts +18 -75
- package/src/val/PrefFuncVal.ts +0 -1
- package/src/val/PrefVal.ts +0 -179
- package/src/val/RecurseVal.ts +0 -81
- package/src/val/RefVal.ts +1 -285
- package/src/val/ReferFuncVal.ts +0 -255
- package/src/val/ScalarKindVal.ts +0 -50
- package/src/val/ScalarVal.ts +0 -12
- package/src/val/StrFuncVal.ts +0 -44
- package/src/val/SuperFuncVal.ts +0 -42
- package/src/val/TopVal.ts +0 -1
- package/src/val/TranslateFuncVal.ts +1 -51
- package/src/val/UpperFuncVal.ts +0 -12
- package/src/val/Val.ts +3 -192
- package/src/val/VarVal.ts +0 -15
- package/src/val/arith.ts +0 -92
- package/src/val/caserange.ts +0 -62
- package/src/val/members.ts +0 -23
- package/src/val/numcmp.ts +1 -27
- package/src/val/numkind.ts +0 -149
- package/src/val/valutil.ts +0 -16
- package/src/vet.ts +1 -582
- package/src/view.ts +0 -507
- package/src/walk.ts +0 -41
- package/dist/std.d.ts +0 -3
- package/dist/std.js +0 -672
- package/dist/std.js.map +0 -1
- package/dist/val/FormFuncVal.js +0 -55
- package/dist/val/FormFuncVal.js.map +0 -1
- package/dist/val/NamerFuncVal.d.ts +0 -12
- package/dist/val/NamerFuncVal.js +0 -176
- package/dist/val/NamerFuncVal.js.map +0 -1
- package/src/std.ts +0 -683
package/dist/exactjson.js
CHANGED
|
@@ -2,72 +2,12 @@
|
|
|
2
2
|
/* Copyright (c) 2025 Richard Rodger, MIT License */
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
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
5
|
const Decimal_1 = require("./val/Decimal");
|
|
63
6
|
const err_1 = require("./err");
|
|
64
7
|
const keyorder_1 = require("./keyorder");
|
|
65
8
|
// JS leaves U+2028 (LINE SEPARATOR) and U+2029 (PARAGRAPH SEPARATOR)
|
|
66
9
|
// literal in a JSON string; Go's encoder escapes them. Byte parity wins.
|
|
67
10
|
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
11
|
function indentUnit(indent) {
|
|
72
12
|
if ('number' === typeof indent) {
|
|
73
13
|
const n = Math.min(10, Math.floor(indent));
|
|
@@ -84,16 +24,9 @@ function quote(s) {
|
|
|
84
24
|
// inside an escape), so a straight replace is safe.
|
|
85
25
|
return out.replace(LSPS_RE, (c) => '\u2028' === c ? '\\u2028' : '\\u2029');
|
|
86
26
|
}
|
|
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
27
|
function skipped(v) {
|
|
91
28
|
return undefined === v || 'function' === typeof v || 'symbol' === typeof v;
|
|
92
29
|
}
|
|
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
30
|
function emit(v, unit, pad, seen) {
|
|
98
31
|
if (null === v) {
|
|
99
32
|
return 'null';
|
|
@@ -145,35 +78,6 @@ function emit(v, unit, pad, seen) {
|
|
|
145
78
|
else {
|
|
146
79
|
const colon = '' === unit ? ':' : ': ';
|
|
147
80
|
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
81
|
for (const k of Object.keys(v).sort(keyorder_1.cmpCodePoint)) {
|
|
178
82
|
const cv = v[k];
|
|
179
83
|
if (skipped(cv)) {
|
|
@@ -187,41 +91,6 @@ function emit(v, unit, pad, seen) {
|
|
|
187
91
|
seen.delete(v);
|
|
188
92
|
return out;
|
|
189
93
|
}
|
|
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
94
|
function exactJSON(value, indent) {
|
|
226
95
|
return emit(value, indentUnit(indent), '', new Set());
|
|
227
96
|
} /* node:coverage ignore next 6 */
|
package/dist/exactjson.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exactjson.js","sourceRoot":"","sources":["../src/exactjson.ts"],"names":[],"mappings":";AAAA,oDAAoD;;
|
|
1
|
+
{"version":3,"file":"exactjson.js","sourceRoot":"","sources":["../src/exactjson.ts"],"names":[],"mappings":"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"}
|
package/dist/format.js
CHANGED
|
@@ -3,51 +3,14 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.format = format;
|
|
5
5
|
exports.unifiedDiff = unifiedDiff;
|
|
6
|
-
// THE SOURCE FORMATTER (docs/design/FMT.0.md): `aontu fmt`, in the
|
|
7
|
-
// tradition of gofmt. One agreed form for Aontu source, so that layout
|
|
8
|
-
// is never argued about and a diff shows only what changed.
|
|
9
|
-
//
|
|
10
|
-
// It reads the token stream the parser reads -- the lex subscriber the
|
|
11
|
-
// parser stack exposes -- so it sees what the value tree throws away:
|
|
12
|
-
// comments, blank lines, the quote a string used, the spelling of a
|
|
13
|
-
// number. From that stream it builds a layout tree, decides the shape
|
|
14
|
-
// of every container by the rules of the note's §3, and emits. Before
|
|
15
|
-
// returning it re-parses what it wrote and compares the two parse
|
|
16
|
-
// trees: a formatter that cannot prove its output is the same document
|
|
17
|
-
// refuses rather than return it.
|
|
18
|
-
//
|
|
19
|
-
// Two tiers. The syntactic (P1): whitespace, commas, quotes, bare
|
|
20
|
-
// keys, chains and pair elements, none of which changes the parse
|
|
21
|
-
// tree. The lawful (P2), over it: repeat the prefix, and merge what
|
|
22
|
-
// repeats -- rewrites that rest on the meet, each checked by the meet
|
|
23
|
-
// in isolation and kept only where the engine agrees.
|
|
24
|
-
//
|
|
25
|
-
// The Go twin is go/format.go, function for function; the shared
|
|
26
|
-
// behaviour is test/spec/fmt.tsv, executed by both spec runners.
|
|
27
6
|
const aontu_1 = require("./aontu");
|
|
28
7
|
const vet_1 = require("./vet");
|
|
29
8
|
const template_1 = require("./template");
|
|
30
|
-
// The packing budget (§3.1). It decides which of two legal spellings
|
|
31
|
-
// to use, one line or several, and nothing else: the formatter never
|
|
32
|
-
// breaks a line, so a value wider than this stays as wide as it is.
|
|
33
9
|
const BUDGET = 80;
|
|
34
|
-
// THE DEPTH BUDGET. The layout is recursive, as the tree it reads is,
|
|
35
|
-
// and the canonical port's stack is finite: past the evaluation budget
|
|
36
|
-
// of 1000 levels -- the depth at which unification itself refuses --
|
|
37
|
-
// the formatter stops reading and refuses, so a pathological document
|
|
38
|
-
// is a finding rather than a crash.
|
|
39
10
|
const MAX_DEPTH = 1000;
|
|
40
|
-
// EVERY INCLUDE RESOLVES TO NOTHING. The formatter reads the file it is
|
|
41
|
-
// given and no other (§3.13), so `@"..."` is answered from memory with
|
|
42
|
-
// an empty source: the directive parses, the include is a token like
|
|
43
|
-
// any other, and no capability is needed because no file is read.
|
|
44
11
|
const stubResolver = ((spec) => ({
|
|
45
12
|
...spec, kind: 'aon', full: '__fmt__.aon', src: '', found: true, search: [],
|
|
46
13
|
}));
|
|
47
|
-
// ONE ENGINE, ONE SUBSCRIBER. The parser's subscriber list is
|
|
48
|
-
// append-only, so the subscription is made once and writes to
|
|
49
|
-
// whichever sink the current parse installed; the sink is cleared
|
|
50
|
-
// before the parse returns, so the check's re-parse collects nothing.
|
|
51
14
|
let ENGINE;
|
|
52
15
|
let SINK;
|
|
53
16
|
function engine() {
|
|
@@ -55,10 +18,6 @@ function engine() {
|
|
|
55
18
|
ENGINE = new aontu_1.Aontu({ resolver: stubResolver });
|
|
56
19
|
ENGINE.lang.jsonic.sub({
|
|
57
20
|
lex: (tkn) => {
|
|
58
|
-
// Spaces carry nothing the layout needs, and the end token
|
|
59
|
-
// arrives once per nested parse -- the stub's empty includes
|
|
60
|
-
// among them -- so both are dropped here rather than skipped
|
|
61
|
-
// everywhere below.
|
|
62
21
|
if (undefined !== SINK && '#SP' !== tkn.name && '#ZZ' !== tkn.name) {
|
|
63
22
|
SINK.push({ name: tkn.name, src: tkn.src, val: tkn.val, sI: tkn.sI });
|
|
64
23
|
}
|
|
@@ -148,10 +107,6 @@ class Reader {
|
|
|
148
107
|
return KEYISH[this.name(0)] && ('#CL' === this.name(1) ||
|
|
149
108
|
('#QM' === this.name(1) && '#CL' === this.name(2)));
|
|
150
109
|
}
|
|
151
|
-
// The entries of a container up to its closer, or of the document up
|
|
152
|
-
// to its end. Comments attach by the rules of §3.7: on the line of
|
|
153
|
-
// the entry that precedes them, or of the opener, they trail it;
|
|
154
|
-
// alone on a line they stand as entries and precede what follows.
|
|
155
110
|
body(close, opened) {
|
|
156
111
|
const body = [];
|
|
157
112
|
let open;
|
|
@@ -448,11 +403,6 @@ function unwrap(root) {
|
|
|
448
403
|
}
|
|
449
404
|
// ---------------------------------------------------------------------
|
|
450
405
|
// The layout
|
|
451
|
-
// D1: a one-pair map in value position is written as a chain, and a
|
|
452
|
-
// one-pair map as a list element as a pair element. A map whose only
|
|
453
|
-
// entry is a spread keeps its braces (X-7), and one holding a comment
|
|
454
|
-
// keeps them too, because the comment needs the lines. A trailing
|
|
455
|
-
// comment on the map's line joins the pair's own.
|
|
456
406
|
function chain(node) {
|
|
457
407
|
if ('map' !== node.t || undefined !== node.open || 1 !== node.body.length ||
|
|
458
408
|
'pair' !== node.body[0].t) {
|
|
@@ -467,18 +417,16 @@ function chain(node) {
|
|
|
467
417
|
function width(s) {
|
|
468
418
|
return Array.from(s).length;
|
|
469
419
|
}
|
|
470
|
-
function pairHead(node, tight) {
|
|
420
|
+
function pairHead(node, tight, value) {
|
|
471
421
|
// An alias declaration is `%name = value` at every width: the `=` is
|
|
472
422
|
// an operator, and operators are spaced (§3.2).
|
|
473
423
|
if (node.alias) {
|
|
474
424
|
return node.key + ' = ';
|
|
475
425
|
}
|
|
476
|
-
|
|
426
|
+
const pad = !tight ||
|
|
427
|
+
(undefined !== value && '' !== value && OPENS.includes(value[0]));
|
|
428
|
+
return node.key + (node.opt ? '?' : '') + (pad ? ': ' : ':');
|
|
477
429
|
}
|
|
478
|
-
// The one-line spelling of a node, or undefined where it has none: a
|
|
479
|
-
// comment, a blank line, a break the author kept, a string that spans
|
|
480
|
-
// lines. `tight` is the inline form of a pair, `a:1`, used inside a
|
|
481
|
-
// container; a statement's pair is `a: 1`.
|
|
482
430
|
function inline(node, tight) {
|
|
483
431
|
if (undefined !== node.trail || node.held) {
|
|
484
432
|
return undefined;
|
|
@@ -489,7 +437,7 @@ function inline(node, tight) {
|
|
|
489
437
|
return node.text.includes('\n') ? undefined : node.text;
|
|
490
438
|
case 'pair': {
|
|
491
439
|
const v = inline(chain(node.value), tight);
|
|
492
|
-
return undefined === v ? undefined : pairHead(node, tight) + v;
|
|
440
|
+
return undefined === v ? undefined : pairHead(node, tight, v) + v;
|
|
493
441
|
}
|
|
494
442
|
case 'spread': {
|
|
495
443
|
// `{ &: integer }`, padded inside braces too: the marker reads as
|
|
@@ -544,11 +492,15 @@ function inlineSeq(items) {
|
|
|
544
492
|
}
|
|
545
493
|
return out;
|
|
546
494
|
}
|
|
495
|
+
// A value that OPENS keeps the space after the colon (§3.2); `|` is
|
|
496
|
+
// tight within a line and spaced where it leads one (§3.11, §7.7).
|
|
497
|
+
const OPENS = '*{[(';
|
|
498
|
+
const TIGHT_OP = '|';
|
|
547
499
|
function sepOf(node) {
|
|
548
500
|
return node.sep ? ', ' : ' ';
|
|
549
501
|
}
|
|
550
|
-
// Binary operators spaced, prefixes tight (§3.11). An operand
|
|
551
|
-
// never directly after an operand: the reader ends a value there.
|
|
502
|
+
// Binary operators spaced, prefixes and `|` tight (§3.11). An operand
|
|
503
|
+
// is never directly after an operand: the reader ends a value there.
|
|
552
504
|
function inlineExpr(items) {
|
|
553
505
|
let out = '';
|
|
554
506
|
for (const it of items) {
|
|
@@ -556,7 +508,7 @@ function inlineExpr(items) {
|
|
|
556
508
|
return undefined;
|
|
557
509
|
}
|
|
558
510
|
if ('op' === it.t) {
|
|
559
|
-
out += ' ' + it.text + ' ';
|
|
511
|
+
out += TIGHT_OP === it.text ? it.text : ' ' + it.text + ' ';
|
|
560
512
|
continue;
|
|
561
513
|
}
|
|
562
514
|
if ('prefix' === it.t) {
|
|
@@ -606,9 +558,6 @@ class Writer {
|
|
|
606
558
|
since(mark) {
|
|
607
559
|
return this.lines.slice(mark).concat([this.line]).map(rtrim).join('\n') + '\n';
|
|
608
560
|
}
|
|
609
|
-
// A blank line above the line at an index: the gap of §3.8, opened
|
|
610
|
-
// once the statement below it turns out to be a tree. Never at the
|
|
611
|
-
// top of the page, and never a second time.
|
|
612
561
|
gap(at) {
|
|
613
562
|
if (0 < at && '' !== this.lines[at - 1]) {
|
|
614
563
|
this.lines.splice(at, 0, '');
|
|
@@ -636,19 +585,9 @@ class Writer {
|
|
|
636
585
|
function rtrim(s) {
|
|
637
586
|
return s.replace(/ +$/, '');
|
|
638
587
|
}
|
|
639
|
-
// The entries of a body, one per line at the indentation, with the
|
|
640
|
-
// blank lines the author kept between them (§3.8) -- never at the
|
|
641
|
-
// start or the end. In STATEMENT position (`stmt`: the root, and the
|
|
642
|
-
// body of a plain map that is itself the value of a statement) a pair
|
|
643
|
-
// is laid out by §3.4, which may repeat its key; anywhere else -- a
|
|
644
|
-
// list, an operand, an argument -- by §3.5 alone.
|
|
645
588
|
function emitBody(w, body, indent, stmt, root) {
|
|
646
589
|
let pending = false;
|
|
647
590
|
let count = 0;
|
|
648
|
-
// Where the run being written begins: a statement, with the comments
|
|
649
|
-
// standing directly above it, so that the gap below opens ABOVE the
|
|
650
|
-
// comments rather than between them and what they describe. A blank
|
|
651
|
-
// line ends a run -- comments across a gap belong to what is above.
|
|
652
591
|
let head = 0;
|
|
653
592
|
let noted = false;
|
|
654
593
|
for (const node of body) {
|
|
@@ -680,14 +619,6 @@ function emitBody(w, body, indent, stmt, root) {
|
|
|
680
619
|
w.text(' ' + e.trail);
|
|
681
620
|
}
|
|
682
621
|
}
|
|
683
|
-
// A TOP-LEVEL STATEMENT WRITTEN AS A TREE STANDS APART (§3.8). A
|
|
684
|
-
// document states several things -- a service, then its entities,
|
|
685
|
-
// then its errors -- and where one of them is a tree rather than a
|
|
686
|
-
// line, the eye finds it by the space around it. What counts as a
|
|
687
|
-
// tree is measured rather than guessed: the statement took more
|
|
688
|
-
// than one line to write. So `a: 1` beside `b: 2` is left alone,
|
|
689
|
-
// and this rule cannot fire below the root, where a blank line is
|
|
690
|
-
// the author's (§3.8) and nothing else.
|
|
691
622
|
if (root && from < w.mark()) {
|
|
692
623
|
w.gap(head);
|
|
693
624
|
pending = true;
|
|
@@ -734,18 +665,6 @@ function emitValue(w, node, indent) {
|
|
|
734
665
|
w.text(node.text);
|
|
735
666
|
}
|
|
736
667
|
}
|
|
737
|
-
// A call, or a parenthesis, that has no one-line form or is too wide
|
|
738
|
-
// for the budget. Three shapes. Arguments that are all FLAT -- none
|
|
739
|
-
// holds a container -- stay on the one line however wide it is: a
|
|
740
|
-
// scalar is no narrower on a line of its own, and the formatter never
|
|
741
|
-
// breaks a line. The last argument HUGS the parentheses, `hide({` ...
|
|
742
|
-
// `})`, `close($.E & {` ... `})`, when it is a container, or an
|
|
743
|
-
// expression the author did not break that ends in one, and the
|
|
744
|
-
// arguments before it fit on the opener's line: the container decides
|
|
745
|
-
// its own lines. Otherwise the parenthesis opens a block: one argument
|
|
746
|
-
// per line one level in, the closer alone at the opener's level. A
|
|
747
|
-
// call whose last argument hugs is hugged in turn, `type(close({` ...
|
|
748
|
-
// `}))`: the schema idiom.
|
|
749
668
|
function emitCall(w, node, indent) {
|
|
750
669
|
const items = 'call' === node.t ? node.args : node.inner;
|
|
751
670
|
const open = ('call' === node.t ? node.name : '') + '(';
|
|
@@ -841,21 +760,8 @@ function emitBlock(w, open, close, node, indent, stmt) {
|
|
|
841
760
|
w.open(indent, false);
|
|
842
761
|
w.text(close);
|
|
843
762
|
}
|
|
844
|
-
// An expression that has no one-line form, or one too wide for the
|
|
845
|
-
// budget: the author's breaks are kept, each at its operator, which
|
|
846
|
-
// leads its continuation line (§3.11). The continuation is one level
|
|
847
|
-
// in when the expression follows a key on its line, and level with
|
|
848
|
-
// the first operand when the expression has the line to itself -- an
|
|
849
|
-
// argument of a block call, say -- so a disjunction of alternatives
|
|
850
|
-
// reads as the list it is. A container operand that does not fit from
|
|
851
|
-
// where it stands is a block whose closer lines up with the line that
|
|
852
|
-
// opened it.
|
|
853
763
|
function emitExpr(w, items, indent) {
|
|
854
764
|
const cont = w.fresh() ? indent : indent + 2;
|
|
855
|
-
// Whether the last item was an operand: a comment after one is a
|
|
856
|
-
// space away, and after an operator or the colon it is not. An
|
|
857
|
-
// operand is never directly after an operand (the reader ends a
|
|
858
|
-
// value there), so operands need no such check.
|
|
859
765
|
let operand = false;
|
|
860
766
|
let cur = indent;
|
|
861
767
|
for (const it of items) {
|
|
@@ -868,7 +774,7 @@ function emitExpr(w, items, indent) {
|
|
|
868
774
|
w.text(it.text + ' ');
|
|
869
775
|
}
|
|
870
776
|
else {
|
|
871
|
-
w.text(' ' + it.text + ' ');
|
|
777
|
+
w.text(TIGHT_OP === it.text ? it.text : ' ' + it.text + ' ');
|
|
872
778
|
}
|
|
873
779
|
operand = false;
|
|
874
780
|
continue;
|
|
@@ -892,10 +798,6 @@ function emitExpr(w, items, indent) {
|
|
|
892
798
|
operand = true;
|
|
893
799
|
}
|
|
894
800
|
}
|
|
895
|
-
// The entries of a plain map value: a braced map, or a chain, which is
|
|
896
|
-
// a one-entry map. A map with a comment on its opener keeps its braces
|
|
897
|
-
// (§3.7), so it is not plain here; nor is a map holding an include,
|
|
898
|
-
// which the local check cannot follow.
|
|
899
801
|
function plainEntries(v) {
|
|
900
802
|
if ('pair' === v.t) {
|
|
901
803
|
return [v];
|
|
@@ -921,17 +823,6 @@ function members(p) {
|
|
|
921
823
|
const trail = undefined === last.trail ? p.trail : last.trail + ' ' + p.trail;
|
|
922
824
|
return entries.slice(0, -1).concat([{ ...last, trail }]);
|
|
923
825
|
}
|
|
924
|
-
// Adjacent statements naming one key, whose values are plain maps, are
|
|
925
|
-
// one map: their entries in order, with the comments and blank lines
|
|
926
|
-
// between the statements travelling with the statement they preceded.
|
|
927
|
-
// Only ADJACENT statements merge -- a `server:` line, something else,
|
|
928
|
-
// then another `server:` line stays as it is, because merging them
|
|
929
|
-
// would move a statement, and the formatter never reorders (§3.13).
|
|
930
|
-
// Nor do two statements merge into a map with two spreads: the engine
|
|
931
|
-
// keeps those as a conjunction, which is not the meet of the two maps.
|
|
932
|
-
// The tree is not changed: a merged statement is a new node that keeps
|
|
933
|
-
// the statements it replaces as its `orig`, its spelling before, and a
|
|
934
|
-
// statement merged somewhere below is copied the same way.
|
|
935
826
|
function mergeRuns(body) {
|
|
936
827
|
const out = [];
|
|
937
828
|
let i = 0;
|
|
@@ -993,15 +884,6 @@ function mergeDeep(p) {
|
|
|
993
884
|
}
|
|
994
885
|
return { ...p, value: 'pair' === v.t ? body[0] : { ...v, body }, orig: [p] };
|
|
995
886
|
}
|
|
996
|
-
// Whether a value is a RECORD: a braced map of several entries, every
|
|
997
|
-
// one of them a VALUE rather than another map. A field, an error, a
|
|
998
|
-
// rule row -- something whose keys are what it IS, as against a level
|
|
999
|
-
// of the tree, whose keys are a way through to something else.
|
|
1000
|
-
//
|
|
1001
|
-
// A CHAIN IS NOT ONE, whatever it holds: a one-entry map is D1's, and
|
|
1002
|
-
// D1 writes it as a chain at every width. Nor is a map holding a
|
|
1003
|
-
// spread, which says something about the map's MEMBERS and which D1's
|
|
1004
|
-
// exception already gives a spelling of its own inside a repeat.
|
|
1005
887
|
function record(v, entries) {
|
|
1006
888
|
if ('map' !== v.t) {
|
|
1007
889
|
return false;
|
|
@@ -1061,12 +943,6 @@ function repeatLines(entries, prefix, indent) {
|
|
|
1061
943
|
if (undefined === lines) {
|
|
1062
944
|
return undefined;
|
|
1063
945
|
}
|
|
1064
|
-
// THE DESCENT COULD GO ON, AND WHAT IT REACHES IS A RECORD: it
|
|
1065
|
-
// stops, and the record is a block under the prefix instead. The
|
|
1066
|
-
// deeper repeat is asked for first and thrown away deliberately --
|
|
1067
|
-
// the block REPLACES a descent that would have worked, and never
|
|
1068
|
-
// rescues one that would not, so a map this rule cannot reach two
|
|
1069
|
-
// ways round is laid out exactly as it was before the amendment.
|
|
1070
946
|
if (record(e.value, sub)) {
|
|
1071
947
|
out.push({ t: 'block', text: head, node: e.value, trail });
|
|
1072
948
|
continue;
|
|
@@ -1090,18 +966,6 @@ function repeatLines(entries, prefix, indent) {
|
|
|
1090
966
|
function fits(indent, text) {
|
|
1091
967
|
return indent + width(text) <= BUDGET;
|
|
1092
968
|
}
|
|
1093
|
-
// A pair in statement position, by §3.4. `prefix` is what stands
|
|
1094
|
-
// before it on its line: the heads of the chain it hangs from, not yet
|
|
1095
|
-
// written. Its value is laid out by §3.5 unless it is a plain map, and
|
|
1096
|
-
// then in this order: a chain, when the map holds exactly one pair
|
|
1097
|
-
// (D1); one line, when that fits the budget; the key repeated over the
|
|
1098
|
-
// entries, when every entry can be one line that way; a braced block
|
|
1099
|
-
// otherwise, whose entries are statements in turn. Whether the
|
|
1100
|
-
// statement was rewritten by this tier -- merged, or repeated -- is
|
|
1101
|
-
// returned, and the outermost such statement is checked: its spelling
|
|
1102
|
-
// on the page against what the syntactic tier writes for the
|
|
1103
|
-
// statements it came from, at the same indentation, which is what
|
|
1104
|
-
// stays on the page when the check fails.
|
|
1105
969
|
function emitStatement(w, p, indent, stmt, prefix) {
|
|
1106
970
|
const mark = w.mark();
|
|
1107
971
|
let rewritten = undefined !== p.orig;
|
|
@@ -1177,11 +1041,6 @@ function emit(root, meet) {
|
|
|
1177
1041
|
emitBody(w, undefined === meet ? root : mergeRuns(root), 0, undefined === meet ? undefined : { meet, covered: false }, true);
|
|
1178
1042
|
return w.finish();
|
|
1179
1043
|
}
|
|
1180
|
-
// ---------------------------------------------------------------------
|
|
1181
|
-
// The lint (§4): what the formatter points at and never touches. Two
|
|
1182
|
-
// rules, both advice: the formatter never renames a key (§4.1) and
|
|
1183
|
-
// never introduces an alias (§4.2), and a rule with a mechanical fix
|
|
1184
|
-
// that keeps the document would belong to §3 instead (§4.3).
|
|
1185
1044
|
// The shape width at which a repeat is worth an alias (§4.2): below
|
|
1186
1045
|
// it, `{ a:1 }` twice is the shorter spelling. Measured over the use
|
|
1187
1046
|
// cases when the lint landed (§7.10).
|
|
@@ -1228,11 +1087,6 @@ function lineCol(text, at) {
|
|
|
1228
1087
|
const before = text.slice(0, at);
|
|
1229
1088
|
return { line: before.split('\n').length, col: at - before.lastIndexOf('\n') };
|
|
1230
1089
|
}
|
|
1231
|
-
// D4 (§4.1): keys are lower-case words, or CamelCase when a key is
|
|
1232
|
-
// several. A bare key holding `_`, or beginning with two capitals, is
|
|
1233
|
-
// reported with the spelling that would follow the form; a quoted key
|
|
1234
|
-
// is a deliberate spelling and a key of underscores alone names
|
|
1235
|
-
// nothing the rule can respell.
|
|
1236
1090
|
function keyCase(node, text, out) {
|
|
1237
1091
|
if ('pair' === node.t && BARE.test(node.key) && /[A-Za-z]/.test(node.key)) {
|
|
1238
1092
|
const why = node.key.includes('_') ? 'holds an underscore'
|
|
@@ -1248,9 +1102,6 @@ function keyCase(node, text, out) {
|
|
|
1248
1102
|
keyCase(child, text, out);
|
|
1249
1103
|
}
|
|
1250
1104
|
}
|
|
1251
|
-
// The key as lower-case words or CamelCase: `credit_cents` is
|
|
1252
|
-
// `creditCents`, `HTTP_PORT` is `httpPort`, `HTTPServer` is
|
|
1253
|
-
// `httpServer`, `ID` is `id`.
|
|
1254
1105
|
function camel(key) {
|
|
1255
1106
|
const words = key.split('_').filter((w) => '' !== w)
|
|
1256
1107
|
.map((w) => /^[A-Z]+$/.test(w) ? w.toLowerCase() : w);
|
|
@@ -1258,12 +1109,6 @@ function camel(key) {
|
|
|
1258
1109
|
return head.charAt(0).toLowerCase() + head.slice(1) +
|
|
1259
1110
|
words.slice(1).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join('');
|
|
1260
1111
|
}
|
|
1261
|
-
// D3 (§4.2): a shape written twice can drift, and an alias names it
|
|
1262
|
-
// once. Every map or list whose shape recurs in the file, and whose
|
|
1263
|
-
// shape is REPEAT_MIN_WIDTH or wider, is reported once, at its first
|
|
1264
|
-
// site, with the count and the other sites; the naming is the
|
|
1265
|
-
// author's. A repeat inside a repeat is the outer one's: the walk does
|
|
1266
|
-
// not descend into a shape it reports.
|
|
1267
1112
|
function repeats(nodes, text, out) {
|
|
1268
1113
|
const counts = new Map();
|
|
1269
1114
|
const tally = (node) => {
|
|
@@ -1298,9 +1143,6 @@ function repeats(nodes, text, out) {
|
|
|
1298
1143
|
}
|
|
1299
1144
|
}
|
|
1300
1145
|
}
|
|
1301
|
-
// A node's shape: its spelling with the layout, the comments and, for
|
|
1302
|
-
// a map, the order of its entries taken out, so that two spellings of
|
|
1303
|
-
// one value are one shape, as they are one canon.
|
|
1304
1146
|
function shape(node) {
|
|
1305
1147
|
switch (node.t) {
|
|
1306
1148
|
case 'map':
|
|
@@ -1336,15 +1178,6 @@ function sameDocument(root, after) {
|
|
|
1336
1178
|
const p = parseDoc(after, undefined, undefined);
|
|
1337
1179
|
return undefined === p.errors && root.canon === p.root.canon;
|
|
1338
1180
|
}
|
|
1339
|
-
// The check of a lawful rewrite: the spelling before and the spelling
|
|
1340
|
-
// after, evaluated in isolation, come to the same canon, the same
|
|
1341
|
-
// kinds of failure, and the same outcome of generation (§7.3). Local,
|
|
1342
|
-
// so it needs no include and no capability, and it applies whether or
|
|
1343
|
-
// not the document as a whole evaluates. The kinds, not the count: how
|
|
1344
|
-
// often one unresolved reference is reported depends on the order the
|
|
1345
|
-
// meet took. Generation too, because the engine generates from more
|
|
1346
|
-
// than the canon: a meet of maps with a nil member has refused a key
|
|
1347
|
-
// the same map written once generates.
|
|
1348
1181
|
function sameByMeet(before, after) {
|
|
1349
1182
|
return meetOf(before) === meetOf(after);
|
|
1350
1183
|
}
|
|
@@ -1386,12 +1219,6 @@ function checkFinding(path, expected, actual) {
|
|
|
1386
1219
|
actual,
|
|
1387
1220
|
};
|
|
1388
1221
|
}
|
|
1389
|
-
// THE TARGET'S OWN LINES ARE HELD ON LINES OF THEIR OWN (§3.14). The
|
|
1390
|
-
// desugaring is line for line, so a line of output is known by the
|
|
1391
|
-
// offset it begins at, and the node beginning there -- the quoted
|
|
1392
|
-
// string the desugaring wrote -- is marked. From there on it has no
|
|
1393
|
-
// one-line form, so every container holding it opens, and no two lines
|
|
1394
|
-
// of the generated file are ever packed onto one.
|
|
1395
1222
|
function holdOutput(nodes, at) {
|
|
1396
1223
|
for (const node of nodes) {
|
|
1397
1224
|
if (undefined !== node.at && at.has(node.at)) {
|
|
@@ -1419,11 +1246,6 @@ function outputAt(doc, flags) {
|
|
|
1419
1246
|
}
|
|
1420
1247
|
return at;
|
|
1421
1248
|
}
|
|
1422
|
-
// A finding's column in the TEMPLATE rather than in the document it
|
|
1423
|
-
// carries (§3.14): the marker and its one space stand before the aontu
|
|
1424
|
-
// on every line the resugaring writes. Every finding is on such a
|
|
1425
|
-
// line -- the two rules point at a key or at a container, and a line of
|
|
1426
|
-
// output is a bare string, which is neither.
|
|
1427
1249
|
function shiftFindings(findings, mark) {
|
|
1428
1250
|
return undefined === mark ? findings :
|
|
1429
1251
|
findings.map((f) => ({ ...f, col: f.col + mark.length + 1 }));
|
|
@@ -1433,9 +1255,6 @@ function shiftFindings(findings, mark) {
|
|
|
1433
1255
|
// what `--check` and `--list` report.
|
|
1434
1256
|
function format(src, opts, hooks) {
|
|
1435
1257
|
const text = lf(src);
|
|
1436
|
-
// A GENERATOR IS FORMATTED AS THE DOCUMENT IT CARRIES (§3.14): the
|
|
1437
|
-
// template surface's two transforms stand either side of the
|
|
1438
|
-
// formatter, and between them is what happens to any other document.
|
|
1439
1258
|
const mark = opts?.template;
|
|
1440
1259
|
const doc = undefined === mark ? text : (0, template_1.desugarTemplate)(text, mark);
|
|
1441
1260
|
const toks = [];
|
|
@@ -1468,11 +1287,6 @@ function format(src, opts, hooks) {
|
|
|
1468
1287
|
findings: opts?.lint ? shiftFindings(lintOf(root, doc), mark) : [],
|
|
1469
1288
|
};
|
|
1470
1289
|
}
|
|
1471
|
-
// The lines of a text, with a marker on the last when the text does
|
|
1472
|
-
// not end in a newline: such a line never equals its
|
|
1473
|
-
// newline-terminated twin, which is how the diff reports the
|
|
1474
|
-
// difference, and the marker is rendered as diff renders it. NUL,
|
|
1475
|
-
// which no source line ends in.
|
|
1476
1290
|
const NO_NEWLINE = String.fromCharCode(0);
|
|
1477
1291
|
function textLines(text) {
|
|
1478
1292
|
if ('' === text) {
|
|
@@ -1569,8 +1383,6 @@ function patience(a, x0, x1, b, y0, y1, out) {
|
|
|
1569
1383
|
out.push({ op: ' ', text: a[x1 + k] });
|
|
1570
1384
|
}
|
|
1571
1385
|
}
|
|
1572
|
-
// The diff in unified format, three lines of context, the file named
|
|
1573
|
-
// on both sides. Empty when the texts are the same.
|
|
1574
1386
|
function unifiedDiff(name, before, after) {
|
|
1575
1387
|
const a = textLines(before);
|
|
1576
1388
|
const b = textLines(after);
|
|
@@ -1600,8 +1412,6 @@ function unifiedDiff(name, before, after) {
|
|
|
1600
1412
|
for (const [s, e] of hunks) {
|
|
1601
1413
|
const from = Math.max(s - 3, 0);
|
|
1602
1414
|
const to = Math.min(e + 4, edits.length);
|
|
1603
|
-
// Everything between two hunks is context -- a change would have
|
|
1604
|
-
// opened a hunk -- so both sides advance together.
|
|
1605
1415
|
for (; next < from; next++) {
|
|
1606
1416
|
ai++;
|
|
1607
1417
|
bi++;
|