functionalscript 0.45.0 → 0.46.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 +5 -3
- package/fjs/asn.1/module.f.mjs +8 -1
- package/fjs/asn.1/proof.f.d.mts +10 -0
- package/fjs/asn.1/proof.f.mjs +16 -0
- package/fjs/basen/base128/module.f.mjs +22 -5
- package/fjs/bnf/data/module.f.d.mts +32 -6
- package/fjs/bnf/data/module.f.mjs +112 -7
- package/fjs/bnf/data/proof.f.d.mts +2 -0
- package/fjs/bnf/data/proof.f.mjs +74 -3
- package/fjs/bnf/data/types.d.ts +20 -2
- package/fjs/bnf/descent/module.f.d.mts +28 -14
- package/fjs/bnf/descent/module.f.mjs +122 -77
- package/fjs/bnf/descent/proof.f.d.mts +2 -0
- package/fjs/bnf/descent/proof.f.mjs +117 -31
- package/fjs/bnf/descent/types.d.ts +12 -14
- package/fjs/bnf/ll1/module.f.d.mts +64 -22
- package/fjs/bnf/ll1/module.f.mjs +214 -154
- package/fjs/bnf/ll1/proof.f.d.mts +15 -2
- package/fjs/bnf/ll1/proof.f.mjs +323 -149
- package/fjs/bnf/ll1/types.d.ts +16 -24
- package/fjs/bnf/matcher/module.f.d.mts +66 -0
- package/fjs/bnf/matcher/module.f.mjs +81 -0
- package/fjs/bnf/matcher/proof.f.d.mts +10 -0
- package/fjs/bnf/matcher/proof.f.mjs +79 -0
- package/fjs/bnf/matcher/types.d.ts +54 -0
- package/fjs/bnf/testlib.f.d.mts +31 -0
- package/fjs/bnf/testlib.f.mjs +80 -0
- package/fjs/cas/cli/module.f.d.mts +1 -1
- package/fjs/cas/cli/module.f.mjs +14 -20
- package/fjs/cas/cli/proof.f.d.mts +1 -3
- package/fjs/cas/cli/proof.f.mjs +44 -33
- package/fjs/cas/evo/module.f.d.mts +64 -18
- package/fjs/cas/evo/module.f.mjs +148 -70
- package/fjs/cas/evo/proof.f.d.mts +10 -1
- package/fjs/cas/evo/proof.f.mjs +305 -223
- package/fjs/cas/evo/types.d.ts +45 -9
- package/fjs/cas/module.f.d.mts +18 -32
- package/fjs/cas/module.f.mjs +129 -128
- package/fjs/cas/proof.f.d.mts +11 -8
- package/fjs/cas/proof.f.mjs +259 -147
- package/fjs/cas/types.d.ts +24 -10
- package/fjs/ci/config/module.f.d.mts +2 -2
- package/fjs/ci/config/module.f.mjs +2 -2
- package/fjs/ci/module.f.d.mts +5 -5
- package/fjs/ci/module.f.mjs +8 -7
- package/fjs/ci/nix/module.f.d.mts +7 -5
- package/fjs/ci/nix/module.f.mjs +13 -12
- package/fjs/ci/nix/proof.f.mjs +2 -2
- package/fjs/ci/proof.f.mjs +9 -5
- package/fjs/cli/module.f.d.mts +4 -6
- package/fjs/cli/module.f.mjs +4 -8
- package/fjs/cli/proof.f.mjs +17 -16
- package/fjs/cli/types.d.ts +2 -3
- package/fjs/common/monoid/types.d.ts +1 -1
- package/fjs/crypto/hmac/module.f.mjs +2 -2
- package/fjs/crypto/sha2/module.f.mjs +3 -1
- package/fjs/crypto/sha2/proof.f.d.mts +1 -0
- package/fjs/crypto/sha2/proof.f.mjs +24 -0
- package/fjs/crypto/sha2/types.d.ts +11 -0
- package/fjs/crypto/sign/module.f.mjs +2 -2
- package/fjs/dev/module.f.d.mts +13 -4
- package/fjs/dev/module.f.mjs +56 -27
- package/fjs/dev/update/module.f.d.mts +9 -4
- package/fjs/dev/update/module.f.mjs +14 -10
- package/fjs/dev/update/proof.f.d.mts +1 -3
- package/fjs/dev/update/proof.f.mjs +10 -5
- package/fjs/djs/module.f.d.mts +13 -5
- package/fjs/djs/module.f.mjs +31 -16
- package/fjs/djs/parser/module.f.d.mts +13 -3
- package/fjs/djs/parser/module.f.mjs +117 -16
- package/fjs/djs/parser/proof.f.d.mts +5 -1
- package/fjs/djs/parser/proof.f.mjs +274 -12
- package/fjs/djs/parser/types.d.ts +7 -1
- package/fjs/djs/proof.f.d.mts +18 -2
- package/fjs/djs/proof.f.mjs +187 -12
- package/fjs/djs/serializer/module.f.d.mts +25 -8
- package/fjs/djs/serializer/module.f.mjs +61 -15
- package/fjs/djs/serializer/proof.f.d.mts +5 -0
- package/fjs/djs/serializer/proof.f.mjs +23 -1
- package/fjs/djs/tokenizer/module.f.d.mts +17 -5
- package/fjs/djs/tokenizer/module.f.mjs +99 -60
- package/fjs/djs/tokenizer/proof.f.d.mts +1 -1
- package/fjs/djs/tokenizer/proof.f.mjs +74 -67
- package/fjs/djs/transpiler/module.f.d.mts +12 -7
- package/fjs/djs/transpiler/module.f.mjs +82 -56
- package/fjs/djs/transpiler/types.d.ts +7 -3
- package/fjs/djs/types.d.ts +7 -1
- package/fjs/effects/list/module.f.d.mts +14 -11
- package/fjs/effects/list/module.f.mjs +13 -11
- package/fjs/effects/list/types.d.ts +27 -7
- package/fjs/effects/memory/module.f.d.mts +2 -1
- package/fjs/effects/memory/module.f.mjs +3 -4
- package/fjs/effects/memory/proof.f.mjs +13 -7
- package/fjs/effects/memory/types.d.ts +4 -3
- package/fjs/effects/mock/module.f.d.mts +20 -4
- package/fjs/effects/mock/module.f.mjs +37 -5
- package/fjs/effects/mock/types.d.ts +10 -1
- package/fjs/effects/module.d.mts +4 -2
- package/fjs/effects/module.f.d.mts +466 -280
- package/fjs/effects/module.f.mjs +537 -299
- package/fjs/effects/module.mjs +2 -1
- package/fjs/effects/node/memory/module.d.mts +4 -2
- package/fjs/effects/node/memory/module.mjs +6 -3
- package/fjs/effects/node/memory/proof.mjs +10 -4
- package/fjs/effects/node/module.d.mts +4 -3
- package/fjs/effects/node/module.f.d.mts +168 -33
- package/fjs/effects/node/module.f.mjs +256 -52
- package/fjs/effects/node/module.mjs +57 -34
- package/fjs/effects/node/proof.f.d.mts +28 -2
- package/fjs/effects/node/proof.f.mjs +161 -42
- package/fjs/effects/node/types.d.ts +106 -18
- package/fjs/effects/node/virtual/module.f.d.mts +18 -4
- package/fjs/effects/node/virtual/module.f.mjs +110 -68
- package/fjs/effects/node/virtual/proof.f.d.mts +28 -2
- package/fjs/effects/node/virtual/proof.f.mjs +190 -9
- package/fjs/effects/proof.f.d.mts +69 -37
- package/fjs/effects/proof.f.mjs +410 -130
- package/fjs/effects/types.d.ts +161 -33
- package/fjs/emergent_testing/module.f.d.mts +19 -12
- package/fjs/emergent_testing/module.f.mjs +93 -33
- package/fjs/emergent_testing/proof.f.d.mts +21 -7
- package/fjs/emergent_testing/proof.f.mjs +166 -32
- package/fjs/emergent_testing/types.d.ts +22 -4
- package/fjs/fsm/module.f.d.mts +14 -4
- package/fjs/fsm/module.f.mjs +54 -37
- package/fjs/fsm/proof.f.d.mts +2 -0
- package/fjs/fsm/proof.f.mjs +83 -114
- package/fjs/js/keywords/module.f.d.mts +52 -0
- package/fjs/js/keywords/module.f.mjs +72 -0
- package/fjs/js/keywords/proof.f.d.mts +3 -0
- package/fjs/js/keywords/proof.f.mjs +13 -0
- package/fjs/js/tokenizer/module.f.d.mts +26 -6
- package/fjs/js/tokenizer/module.f.mjs +145 -159
- package/fjs/js/tokenizer/proof.f.d.mts +1 -0
- package/fjs/js/tokenizer/proof.f.mjs +54 -24
- package/fjs/js/tokenizer/types.d.ts +33 -24
- package/fjs/mcp/cas/module.f.d.mts +1 -6
- package/fjs/mcp/cas/module.f.mjs +55 -51
- package/fjs/mcp/cas/proof.f.d.mts +15 -0
- package/fjs/mcp/cas/proof.f.mjs +174 -0
- package/fjs/mcp/evo/module.f.d.mts +19 -10
- package/fjs/mcp/evo/module.f.mjs +48 -27
- package/fjs/mcp/evo/proof.f.d.mts +6 -1
- package/fjs/mcp/evo/proof.f.mjs +115 -31
- package/fjs/mcp/module.f.d.mts +4 -4
- package/fjs/mcp/module.f.mjs +6 -6
- package/fjs/mcp/proof.f.d.mts +5 -3
- package/fjs/mcp/proof.f.mjs +112 -46
- package/fjs/media/html/module.f.mjs +1 -1
- package/fjs/media/json/extended/module.f.d.mts +82 -0
- package/fjs/media/json/extended/module.f.mjs +153 -0
- package/fjs/media/json/extended/proof.f.d.mts +42 -0
- package/fjs/media/json/extended/proof.f.mjs +127 -0
- package/fjs/media/json/extended/types.d.ts +23 -0
- package/fjs/media/json/module.f.d.mts +8 -2
- package/fjs/media/json/module.f.mjs +43 -41
- package/fjs/media/json/number/module.f.d.mts +59 -0
- package/fjs/media/json/number/module.f.mjs +136 -0
- package/fjs/media/json/number/proof.f.d.mts +24 -0
- package/fjs/media/json/number/proof.f.mjs +86 -0
- package/fjs/media/json/number/types.d.ts +28 -0
- package/fjs/media/json/parser/module.f.d.mts +25 -13
- package/fjs/media/json/parser/module.f.mjs +114 -70
- package/fjs/media/json/parser/proof.f.d.mts +5 -0
- package/fjs/media/json/parser/proof.f.mjs +31 -1
- package/fjs/media/json/parser/types.d.ts +33 -14
- package/fjs/media/json/rtti/module.f.d.mts +1 -1
- package/fjs/media/json/rtti/module.f.mjs +1 -1
- package/fjs/media/json/rtti/proof.f.mjs +9 -9
- package/fjs/media/json/schema/module.f.mjs +3 -13
- package/fjs/media/json/schema/proof.f.d.mts +0 -1
- package/fjs/media/json/schema/proof.f.mjs +1 -2
- package/fjs/media/json/serializer/module.f.d.mts +32 -1
- package/fjs/media/json/serializer/module.f.mjs +64 -2
- package/fjs/media/json/tokenizer/module.f.mjs +7 -3
- package/fjs/media/json/tokenizer/proof.f.d.mts +6 -0
- package/fjs/media/json/tokenizer/proof.f.mjs +62 -21
- package/fjs/media/json/types.d.ts +36 -10
- package/fjs/media/lock/module.f.d.mts +100 -0
- package/fjs/media/lock/module.f.mjs +125 -0
- package/fjs/media/lock/proof.f.d.mts +33 -0
- package/fjs/media/lock/proof.f.mjs +196 -0
- package/fjs/media/lock/types.d.ts +15 -0
- package/fjs/media/module.f.d.mts +6 -5
- package/fjs/media/module.f.mjs +8 -7
- package/fjs/media/note/module.f.d.mts +121 -0
- package/fjs/media/note/module.f.mjs +131 -0
- package/fjs/media/note/proof.f.d.mts +29 -0
- package/fjs/media/note/proof.f.mjs +150 -0
- package/fjs/media/note/types.d.ts +10 -0
- package/fjs/media/proof.f.d.mts +4 -1
- package/fjs/media/proof.f.mjs +40 -21
- package/fjs/media/revision/module.f.d.mts +78 -7
- package/fjs/media/revision/module.f.mjs +119 -12
- package/fjs/media/revision/proof.f.d.mts +10 -0
- package/fjs/media/revision/proof.f.mjs +88 -0
- package/fjs/media/revision/types.d.ts +34 -5
- package/fjs/media/type/module.f.d.mts +33 -15
- package/fjs/media/type/module.f.mjs +35 -29
- package/fjs/media/type/proof.f.d.mts +2 -1
- package/fjs/media/type/proof.f.mjs +30 -10
- package/fjs/module.f.mjs +29 -8
- package/fjs/nanvm/proof.f.mjs +3 -3
- package/fjs/nanvm/rust/module.f.mjs +1 -1
- package/fjs/nanvm/update/module.f.d.mts +4 -4
- package/fjs/nanvm/update/module.f.mjs +8 -9
- package/fjs/nanvm/update/proof.f.mjs +4 -3
- package/fjs/proof.f.d.mts +3 -3
- package/fjs/proof.f.mjs +36 -10
- package/fjs/protocol/json_rpc/module.f.d.mts +2 -2
- package/fjs/protocol/json_rpc/module.f.mjs +3 -3
- package/fjs/protocol/json_rpc/proof.f.mjs +4 -4
- package/fjs/protocol/mcp/module.f.d.mts +10 -13
- package/fjs/protocol/mcp/module.f.mjs +74 -58
- package/fjs/protocol/mcp/proof.f.d.mts +13 -4
- package/fjs/protocol/mcp/proof.f.mjs +193 -61
- package/fjs/protocol/mcp/stdio/module.f.d.mts +15 -7
- package/fjs/protocol/mcp/stdio/module.f.mjs +38 -25
- package/fjs/protocol/mcp/stdio/proof.f.d.mts +4 -2
- package/fjs/protocol/mcp/stdio/proof.f.mjs +45 -12
- package/fjs/protocol/mcp/stdio/types.d.ts +1 -1
- package/fjs/protocol/mcp/types.d.ts +17 -6
- package/fjs/sul/id/module.f.d.mts +0 -1
- package/fjs/sul/id/module.f.mjs +2 -3
- package/fjs/sul/level/hash/module.f.mjs +2 -1
- package/fjs/sul/level/hash/proof.f.mjs +2 -2
- package/fjs/sul/module.f.mjs +18 -13
- package/fjs/text/code_point/module.f.d.mts +8 -0
- package/fjs/text/code_point/module.f.mjs +8 -1
- package/fjs/text/code_point/proof.f.d.mts +1 -0
- package/fjs/text/code_point/proof.f.mjs +11 -0
- package/fjs/text/sgr/module.f.d.mts +4 -6
- package/fjs/text/sgr/module.f.mjs +6 -7
- package/fjs/text/utf16/module.f.mjs +7 -2
- package/fjs/text/utf16/proof.f.mjs +3 -3
- package/fjs/text/utf8/module.f.mjs +4 -2
- package/fjs/types/array/module.f.mjs +14 -2
- package/fjs/types/bit_vec/module.f.d.mts +0 -2
- package/fjs/types/bit_vec/module.f.mjs +46 -32
- package/fjs/types/bit_vec/proof.f.mjs +2 -2
- package/fjs/types/btree/remove/module.f.mjs +1 -1
- package/fjs/types/btree/set/module.f.mjs +9 -11
- package/fjs/types/btree/set/proof.f.mjs +12 -0
- package/fjs/types/byte_set/module.f.d.mts +11 -4
- package/fjs/types/byte_set/module.f.mjs +14 -6
- package/fjs/types/byte_set/proof.f.mjs +7 -7
- package/fjs/types/function/compare/module.f.mjs +10 -3
- package/fjs/types/list/module.f.d.mts +1 -1
- package/fjs/types/list/module.f.mjs +1 -1
- package/fjs/types/nullable/module.f.d.mts +18 -4
- package/fjs/types/nullable/module.f.mjs +21 -4
- package/fjs/types/nullable/proof.f.d.mts +4 -0
- package/fjs/types/nullable/proof.f.mjs +15 -0
- package/fjs/types/object/module.f.d.mts +12 -2
- package/fjs/types/object/module.f.mjs +11 -1
- package/fjs/types/patricia_trie/module.f.mjs +26 -11
- package/fjs/types/result/module.f.d.mts +3 -3
- package/fjs/types/result/module.f.mjs +3 -3
- package/fjs/types/rtti/common/module.f.d.mts +25 -28
- package/fjs/types/rtti/common/module.f.mjs +36 -32
- package/fjs/types/rtti/common/proof.f.mjs +5 -5
- package/fjs/types/rtti/data/module.f.d.mts +14 -0
- package/fjs/types/rtti/data/module.f.mjs +25 -2
- package/fjs/types/rtti/data/proof.f.d.mts +1 -0
- package/fjs/types/rtti/data/proof.f.mjs +25 -2
- package/fjs/types/rtti/parse/module.f.d.mts +24 -14
- package/fjs/types/rtti/parse/module.f.mjs +37 -28
- package/fjs/types/rtti/parse/proof.f.d.mts +3 -2
- package/fjs/types/rtti/parse/proof.f.mjs +33 -14
- package/fjs/types/rtti/proof.f.mjs +3 -1
- package/fjs/types/rtti/ts/module.f.mjs +13 -17
- package/fjs/types/rtti/ts/types.d.ts +14 -1
- package/fjs/types/sorted_set/module.f.d.mts +18 -0
- package/fjs/types/sorted_set/module.f.mjs +22 -0
- package/fjs/types/sorted_set/proof.f.d.mts +1 -0
- package/fjs/types/sorted_set/proof.f.mjs +16 -1
- package/fjs/types/uint8array/module.f.d.mts +1 -1
- package/fjs/types/uint8array/module.f.mjs +1 -1
- package/fjs/website/module.f.d.mts +3 -3
- package/fjs/website/module.f.mjs +4 -7
- package/fjs/website/proof.f.mjs +2 -1
- package/package.json +2 -2
- package/fjs/dev/package_json/module.f.d.mts +0 -39
- package/fjs/dev/package_json/module.f.mjs +0 -40
- package/fjs/dev/package_json/proof.f.d.mts +0 -6
- package/fjs/dev/package_json/proof.f.mjs +0 -32
- package/fjs/effects/eff/module.f.d.mts +0 -20
- package/fjs/effects/eff/module.f.mjs +0 -70
- package/fjs/effects/eff/proof.f.d.mts +0 -15
- package/fjs/effects/eff/proof.f.mjs +0 -69
- package/fjs/effects/eff/types.d.ts +0 -71
- package/fjs/types/rtti/validate/module.f.d.mts +0 -41
- package/fjs/types/rtti/validate/module.f.mjs +0 -171
- package/fjs/types/rtti/validate/proof.f.d.mts +0 -125
- package/fjs/types/rtti/validate/proof.f.mjs +0 -437
- package/fjs/types/rtti/validate/types.d.ts +0 -6
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @import { JsonToken } from '../tokenizer/types.ts'
|
|
3
|
+
* @import { NumberPolicy } from './types.ts'
|
|
3
4
|
*/
|
|
4
5
|
export declare const proof: {
|
|
5
6
|
valid: (() => void)[];
|
|
6
7
|
invalid: (() => void)[];
|
|
7
8
|
siblingContainers: (() => void)[];
|
|
9
|
+
policy: {
|
|
10
|
+
exactLexeme: () => void;
|
|
11
|
+
rejected: () => void;
|
|
12
|
+
};
|
|
8
13
|
};
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @import { JsonToken } from '../tokenizer/types.ts'
|
|
3
|
+
* @import { NumberPolicy } from './types.ts'
|
|
3
4
|
*/
|
|
4
5
|
|
|
5
|
-
import { parse } from './module.f.mjs'
|
|
6
|
+
import { parse as parseWithPolicy } from './module.f.mjs'
|
|
6
7
|
import { tokenize } from '../tokenizer/module.f.mjs'
|
|
7
8
|
import { toArray } from '../../../types/list/module.f.mjs'
|
|
8
9
|
import { stringify as jsonStringify } from '../module.f.mjs'
|
|
9
10
|
import { sort } from '../../../types/object/module.f.mjs'
|
|
10
11
|
import { stringToList } from '../../../text/utf16/module.f.mjs'
|
|
12
|
+
import { error, ok } from '../../../types/result/module.f.mjs'
|
|
11
13
|
import { assertEq } from '../../../asserts/module.f.mjs'
|
|
12
14
|
|
|
13
15
|
/** @type {(s: string) => readonly JsonToken[]} */
|
|
14
16
|
const tokenizeString = s => toArray(tokenize(stringToList(s)))
|
|
15
17
|
|
|
18
|
+
/** The structural machine is proved through the ordinary `number` policy. */
|
|
19
|
+
/** @type {NumberPolicy<number>} */
|
|
20
|
+
const numberPolicy = token => ok(parseFloat(token.value))
|
|
21
|
+
|
|
22
|
+
const parse = parseWithPolicy(numberPolicy)
|
|
23
|
+
|
|
16
24
|
const stringify = jsonStringify(sort)
|
|
17
25
|
|
|
18
26
|
export const proof = {
|
|
@@ -311,4 +319,26 @@ export const proof = {
|
|
|
311
319
|
assertEq(Array.isArray(value) ? value.length : -1, 12000)
|
|
312
320
|
},
|
|
313
321
|
],
|
|
322
|
+
// The numeric policy is the parser's only opinion about numbers: it is
|
|
323
|
+
// handed the token, so it reads the exact lexeme, and it may reject one.
|
|
324
|
+
policy: {
|
|
325
|
+
// the lexeme reaches the policy unrounded — `1.0`, `1e0` and `1` are
|
|
326
|
+
// one `number` but three tokens
|
|
327
|
+
exactLexeme: () => {
|
|
328
|
+
/** @type {NumberPolicy<string>} */
|
|
329
|
+
const lexemePolicy = token => ok(token.value)
|
|
330
|
+
const [tag, value] = parseWithPolicy(lexemePolicy)(tokenizeString('[1.0,1e0,1,-0]'))
|
|
331
|
+
assertEq(tag, 'ok')
|
|
332
|
+
assertEq(stringify(value), '["1.0","1e0","1","-0"]')
|
|
333
|
+
},
|
|
334
|
+
// a policy that cannot represent the number fails the parse as an
|
|
335
|
+
// ordinary `Result`, with its own message
|
|
336
|
+
rejected: () => {
|
|
337
|
+
/** @type {NumberPolicy<never>} */
|
|
338
|
+
const rejectPolicy = () => error('no numbers here')
|
|
339
|
+
const [tag, message] = parseWithPolicy(rejectPolicy)(tokenizeString('{"a":[1]}'))
|
|
340
|
+
assertEq(tag, 'error')
|
|
341
|
+
assertEq(message, 'no numbers here')
|
|
342
|
+
},
|
|
343
|
+
},
|
|
314
344
|
}
|
|
@@ -1,39 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Types for the shared structural JSON parser: its numeric policy, the tree
|
|
3
|
+
* that policy produces, and the parser's internal state.
|
|
3
4
|
*
|
|
4
5
|
* @module
|
|
5
6
|
*/
|
|
6
|
-
import type {
|
|
7
|
+
import type { Tree } from '../types.ts';
|
|
7
8
|
import type { OrderedMap } from '../../../types/ordered_map/types.ts';
|
|
8
9
|
import type { List } from '../../../types/list/types.ts';
|
|
10
|
+
import type { Result } from '../../../types/result/types.ts';
|
|
9
11
|
import type { JsonToken } from '../tokenizer/types.ts';
|
|
12
|
+
import type { NumberToken } from '../../../js/tokenizer/types.ts';
|
|
10
13
|
/** JSON tokens that carry a directly-usable value. */
|
|
11
14
|
export type _ValueToken = Extract<JsonToken, {
|
|
12
15
|
readonly kind: 'null' | 'false' | 'true' | 'string' | 'number';
|
|
13
16
|
}>;
|
|
14
|
-
|
|
17
|
+
/**
|
|
18
|
+
* A numeric policy: how one codec materializes a JSON number token into its
|
|
19
|
+
* own numeric domain `P`.
|
|
20
|
+
*
|
|
21
|
+
* The policy is handed the token itself, so it decides from the exact lexeme —
|
|
22
|
+
* before any narrowing the parser might otherwise have imposed. It may fail:
|
|
23
|
+
* a valid JSON number can be outside the domain the codec offers (the extended
|
|
24
|
+
* codec has no non-finite `number`), and that has to be an ordinary parse
|
|
25
|
+
* error rather than an escaping runtime exception.
|
|
26
|
+
*/
|
|
27
|
+
export type NumberPolicy<P> = (token: NumberToken) => Result<P, string>;
|
|
28
|
+
/**
|
|
29
|
+
* The tree a numeric policy `P` parses into: JSON's containers over `P` plus
|
|
30
|
+
* the primitives every policy shares.
|
|
31
|
+
*/
|
|
32
|
+
export type ParseUnknown<P> = Tree<P | null | boolean | string>;
|
|
33
|
+
export type _JsonObject<P> = {
|
|
15
34
|
readonly kind: 'object';
|
|
16
|
-
readonly values: OrderedMap<
|
|
35
|
+
readonly values: OrderedMap<ParseUnknown<P>>;
|
|
17
36
|
readonly key: string;
|
|
18
37
|
};
|
|
19
|
-
export type _JsonArray = {
|
|
38
|
+
export type _JsonArray<P> = {
|
|
20
39
|
readonly kind: 'array';
|
|
21
|
-
readonly values: List<
|
|
40
|
+
readonly values: List<ParseUnknown<P>>;
|
|
22
41
|
};
|
|
23
|
-
type _JsonStackElement = _JsonObject | _JsonArray
|
|
24
|
-
export type _JsonStack = List<_JsonStackElement
|
|
25
|
-
export type _StateParse = {
|
|
42
|
+
type _JsonStackElement<P> = _JsonObject<P> | _JsonArray<P>;
|
|
43
|
+
export type _JsonStack<P> = List<_JsonStackElement<P>>;
|
|
44
|
+
export type _StateParse<P> = {
|
|
26
45
|
readonly status: '' | '[' | '[v' | '[,' | '{' | '{k' | '{:' | '{v' | '{,';
|
|
27
|
-
readonly top: _JsonStackElement | null;
|
|
28
|
-
readonly stack: _JsonStack
|
|
46
|
+
readonly top: _JsonStackElement<P> | null;
|
|
47
|
+
readonly stack: _JsonStack<P>;
|
|
29
48
|
};
|
|
30
|
-
type _StateResult = {
|
|
49
|
+
type _StateResult<P> = {
|
|
31
50
|
readonly status: 'result';
|
|
32
|
-
readonly value:
|
|
51
|
+
readonly value: ParseUnknown<P>;
|
|
33
52
|
};
|
|
34
53
|
type _StateError = {
|
|
35
54
|
readonly status: 'error';
|
|
36
55
|
readonly message: string;
|
|
37
56
|
};
|
|
38
|
-
export type _JsonState = _StateParse | _StateResult | _StateError;
|
|
57
|
+
export type _JsonState<P> = _StateParse<P> | _StateResult<P> | _StateError;
|
|
39
58
|
export {};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* `typeof`. That spelling is deliberate: `@type {const}` also type-checks here,
|
|
9
9
|
* but leaves declaration emit no name for the recursive positions, so it
|
|
10
10
|
* inlines the structure, gives up at depth, and degrades the emitted `.d.mts`
|
|
11
|
-
* to `any`. See AGENTS.md §
|
|
11
|
+
* to `any`. See `fjs/AGENTS.md` §3.2.
|
|
12
12
|
*
|
|
13
13
|
* The TypeScript counterparts live in the sibling
|
|
14
14
|
* [`../types.ts`](../types.ts), which pins them against these schemas with
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* `typeof`. That spelling is deliberate: `@type {const}` also type-checks here,
|
|
9
9
|
* but leaves declaration emit no name for the recursive positions, so it
|
|
10
10
|
* inlines the structure, gives up at depth, and degrades the emitted `.d.mts`
|
|
11
|
-
* to `any`. See AGENTS.md §
|
|
11
|
+
* to `any`. See `fjs/AGENTS.md` §3.2.
|
|
12
12
|
*
|
|
13
13
|
* The TypeScript counterparts live in the sibling
|
|
14
14
|
* [`../types.ts`](../types.ts), which pins them against these schemas with
|
|
@@ -8,20 +8,20 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { assertEq } from '../../../asserts/module.f.mjs'
|
|
11
|
-
import {
|
|
11
|
+
import { parse } from '../../../types/rtti/parse/module.f.mjs'
|
|
12
12
|
import { primitive, unknown, object, array } from './module.f.mjs'
|
|
13
13
|
|
|
14
|
-
// Reduces a
|
|
15
|
-
// accepted, not about the payload
|
|
16
|
-
//
|
|
17
|
-
//
|
|
14
|
+
// Reduces a parse to its `ok`/`error` tag: these schemas are about what is
|
|
15
|
+
// accepted, not about the payload `parse` rebuilds. The erased `ValidateE`
|
|
16
|
+
// keeps the shared helper from re-instantiating each schema's deep recursive
|
|
17
|
+
// result type (TS2589).
|
|
18
18
|
/** @type {(v: ValidateE) => (value: Unknown) => string} */
|
|
19
19
|
const tag = v => value => v(value)[0]
|
|
20
20
|
|
|
21
|
-
const primitiveAccepts = tag(
|
|
22
|
-
const unknownAccepts = tag(
|
|
23
|
-
const objectAccepts = tag(
|
|
24
|
-
const arrayAccepts = tag(
|
|
21
|
+
const primitiveAccepts = tag(parse(primitive))
|
|
22
|
+
const unknownAccepts = tag(parse(unknown))
|
|
23
|
+
const objectAccepts = tag(parse(object))
|
|
24
|
+
const arrayAccepts = tag(parse(array))
|
|
25
25
|
|
|
26
26
|
export const proof = {
|
|
27
27
|
primitive: {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
import { assert, assertNotNullish } from '../../../asserts/module.f.mjs'
|
|
27
27
|
import { at, definedEntries } from '../../../types/object/module.f.mjs'
|
|
28
28
|
import { array, number, option, or, record, string } from '../../../types/rtti/module.f.mjs'
|
|
29
|
-
import { cmp, toData, unitBit, unknown as top } from '../../../types/rtti/data/module.f.mjs'
|
|
29
|
+
import { cmp, toData, unitBit, unknown as top, withoutUnits } from '../../../types/rtti/data/module.f.mjs'
|
|
30
30
|
import { unknown as jsonUnknown } from '../rtti/module.f.mjs'
|
|
31
31
|
|
|
32
32
|
/** @type {() => readonly ['const', typeof unknownConst]} */
|
|
@@ -199,18 +199,8 @@ const admitsUndefined = rules => n => {
|
|
|
199
199
|
*
|
|
200
200
|
* @type {(n: Node) => Node}
|
|
201
201
|
*/
|
|
202
|
-
const stripUndefined = n =>
|
|
203
|
-
|
|
204
|
-
const unit = (n.unit ?? 0) & ~undefinedBit
|
|
205
|
-
return {
|
|
206
|
-
...(unit === 0 ? {} : { unit }),
|
|
207
|
-
...(n.number === undefined ? {} : { number: n.number }),
|
|
208
|
-
...(n.string === undefined ? {} : { string: n.string }),
|
|
209
|
-
...(n.bigint === undefined ? {} : { bigint: n.bigint }),
|
|
210
|
-
...(n.array === undefined ? {} : { array: n.array }),
|
|
211
|
-
...(n.object === undefined ? {} : { object: n.object }),
|
|
212
|
-
}
|
|
213
|
-
}
|
|
202
|
+
const stripUndefined = n =>
|
|
203
|
+
typeof n === 'string' ? n : withoutUnits(undefinedBit)(n)
|
|
214
204
|
|
|
215
205
|
/**
|
|
216
206
|
* A set of objects: `properties` for the declared keys — a key admitting
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @import { Unknown as JsonValue } from '../types.ts'
|
|
3
2
|
* @import { Unknown } from './module.f.mjs'
|
|
4
3
|
* @import { Data } from '../../../types/rtti/data/types.ts'
|
|
5
4
|
*/
|
|
@@ -11,7 +10,7 @@ import { unitBit } from '../../../types/rtti/data/module.f.mjs'
|
|
|
11
10
|
import { assert, assertEq } from '../../../asserts/module.f.mjs'
|
|
12
11
|
|
|
13
12
|
/** @type {(v: Unknown) => string} */
|
|
14
|
-
const serialize = v => stringify(e => e)(
|
|
13
|
+
const serialize = v => stringify(e => e)(v)
|
|
15
14
|
|
|
16
15
|
/** @type {(rtti: Parameters<typeof toJsonSchema>[0], expected: Unknown) => () => void} */
|
|
17
16
|
const eq = (rtti, expected) => () => {
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* JSON serializer for deterministic string output
|
|
2
|
+
* JSON serializer for deterministic string output: the atoms every JSON leaf
|
|
3
|
+
* is spelled with, and the one recursive walk over JSON's containers.
|
|
4
|
+
*
|
|
5
|
+
* `treeSerialize` is that walk. It knows objects and arrays and nothing about
|
|
6
|
+
* leaves, so a codec supplies its own leaf spelling — standard JSON and
|
|
7
|
+
* extended JSON differ only there, not in a second object/array walker.
|
|
3
8
|
*
|
|
4
9
|
* `stringSerialize` is FunctionalScript, not the host's `JSON.stringify`: it
|
|
5
10
|
* escapes over this repository's own UTF-16 decoder and reproduces the
|
|
@@ -10,8 +15,10 @@
|
|
|
10
15
|
* @import { List } from '../../../types/list/types.ts'
|
|
11
16
|
* @import { Reduce } from '../../../types/function/operator/types.ts'
|
|
12
17
|
* @import { CodePoint } from '../../../text/utf16/types.ts'
|
|
18
|
+
* @import { Tree, TreeObject, TreeArray, TreeEntry, TreeEntries, TreeMapEntries } from '../types.ts'
|
|
13
19
|
*/
|
|
14
20
|
import type { List } from '../../../types/list/types.ts';
|
|
21
|
+
import type { Tree, TreeMapEntries } from '../types.ts';
|
|
15
22
|
/**
|
|
16
23
|
* Serializes a string as a JSON string literal.
|
|
17
24
|
*
|
|
@@ -38,3 +45,27 @@ export declare const objectWrap: (input: List<List<string>>) => List<string>;
|
|
|
38
45
|
* @type {(input: List<List<string>>) => List<string>}
|
|
39
46
|
*/
|
|
40
47
|
export declare const arrayWrap: (input: List<List<string>>) => List<string>;
|
|
48
|
+
/**
|
|
49
|
+
* The separator between a serialized property key and its value. Shared with
|
|
50
|
+
* the DJS serializer, which builds the same `key : value` fragment.
|
|
51
|
+
*
|
|
52
|
+
* @type {List<string>}
|
|
53
|
+
*/
|
|
54
|
+
export declare const colon: List<string>;
|
|
55
|
+
/**
|
|
56
|
+
* The recursive walk over a JSON-shaped tree: objects, arrays, and a leaf
|
|
57
|
+
* spelling supplied by the codec.
|
|
58
|
+
*
|
|
59
|
+
* Every leaf of `Tree<P>` reaches `leafSerialize` — containers are the only
|
|
60
|
+
* thing this function recognizes — so a codec that adds a leaf type (extended
|
|
61
|
+
* JSON's `bigint`) or respells one (extended JSON's `3.0` for a whole-valued
|
|
62
|
+
* `number`) changes `leafSerialize` alone.
|
|
63
|
+
*
|
|
64
|
+
* Object entries whose value is `undefined` are dropped: `undefined` is a
|
|
65
|
+
* missing property, not a leaf of any of these trees.
|
|
66
|
+
*
|
|
67
|
+
* @template P
|
|
68
|
+
* @param {(value: P) => List<string>} leafSerialize
|
|
69
|
+
* @returns {(sort: TreeMapEntries<P>) => (value: Tree<P>) => List<string>}
|
|
70
|
+
*/
|
|
71
|
+
export declare const treeSerialize: <P>(leafSerialize: (value: P) => List<string>) => (sort: TreeMapEntries<P>) => (value: Tree<P>) => List<string>;
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* JSON serializer for deterministic string output
|
|
2
|
+
* JSON serializer for deterministic string output: the atoms every JSON leaf
|
|
3
|
+
* is spelled with, and the one recursive walk over JSON's containers.
|
|
4
|
+
*
|
|
5
|
+
* `treeSerialize` is that walk. It knows objects and arrays and nothing about
|
|
6
|
+
* leaves, so a codec supplies its own leaf spelling — standard JSON and
|
|
7
|
+
* extended JSON differ only there, not in a second object/array walker.
|
|
3
8
|
*
|
|
4
9
|
* `stringSerialize` is FunctionalScript, not the host's `JSON.stringify`: it
|
|
5
10
|
* escapes over this repository's own UTF-16 decoder and reproduces the
|
|
@@ -10,12 +15,15 @@
|
|
|
10
15
|
* @import { List } from '../../../types/list/types.ts'
|
|
11
16
|
* @import { Reduce } from '../../../types/function/operator/types.ts'
|
|
12
17
|
* @import { CodePoint } from '../../../text/utf16/types.ts'
|
|
18
|
+
* @import { Tree, TreeObject, TreeArray, TreeEntry, TreeEntries, TreeMapEntries } from '../types.ts'
|
|
13
19
|
*/
|
|
14
20
|
|
|
15
21
|
import { flat, map, reduce, empty } from '../../../types/list/module.f.mjs'
|
|
16
22
|
import { concat } from '../../../types/string/module.f.mjs'
|
|
17
23
|
import { codePointToString, stringToCodePointList } from '../../../text/utf16/module.f.mjs'
|
|
18
24
|
import { errorMask } from '../../../text/code_point/module.f.mjs'
|
|
25
|
+
import { definedEntries, isObject } from '../../../types/object/module.f.mjs'
|
|
26
|
+
import { compose, fn } from '../../../types/function/module.f.mjs'
|
|
19
27
|
import {
|
|
20
28
|
backspace,
|
|
21
29
|
cr,
|
|
@@ -68,7 +76,7 @@ const unicodeEscape = unit =>
|
|
|
68
76
|
const escapeCodePoint = codePoint =>
|
|
69
77
|
(codePoint & errorMask) !== 0
|
|
70
78
|
? unicodeEscape(codePoint & 0xffff)
|
|
71
|
-
: escapeTable[
|
|
79
|
+
: escapeTable[codePoint]
|
|
72
80
|
?? (codePoint < space ? unicodeEscape(codePoint) : codePointToString(codePoint))
|
|
73
81
|
|
|
74
82
|
/**
|
|
@@ -129,3 +137,57 @@ export const objectWrap
|
|
|
129
137
|
*/
|
|
130
138
|
export const arrayWrap
|
|
131
139
|
= wrap('[')(']')
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* The separator between a serialized property key and its value. Shared with
|
|
143
|
+
* the DJS serializer, which builds the same `key : value` fragment.
|
|
144
|
+
*
|
|
145
|
+
* @type {List<string>}
|
|
146
|
+
*/
|
|
147
|
+
export const colon = [':']
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The recursive walk over a JSON-shaped tree: objects, arrays, and a leaf
|
|
151
|
+
* spelling supplied by the codec.
|
|
152
|
+
*
|
|
153
|
+
* Every leaf of `Tree<P>` reaches `leafSerialize` — containers are the only
|
|
154
|
+
* thing this function recognizes — so a codec that adds a leaf type (extended
|
|
155
|
+
* JSON's `bigint`) or respells one (extended JSON's `3.0` for a whole-valued
|
|
156
|
+
* `number`) changes `leafSerialize` alone.
|
|
157
|
+
*
|
|
158
|
+
* Object entries whose value is `undefined` are dropped: `undefined` is a
|
|
159
|
+
* missing property, not a leaf of any of these trees.
|
|
160
|
+
*
|
|
161
|
+
* @template P
|
|
162
|
+
* @param {(value: P) => List<string>} leafSerialize
|
|
163
|
+
* @returns {(sort: TreeMapEntries<P>) => (value: Tree<P>) => List<string>}
|
|
164
|
+
*/
|
|
165
|
+
export const treeSerialize = leafSerialize => sort => {
|
|
166
|
+
// `definedEntries` is generic; naming it at `P` here is what keeps the leaf
|
|
167
|
+
// type through the `fn(...)` composition below, which would otherwise
|
|
168
|
+
// instantiate it at `unknown`.
|
|
169
|
+
/** @type {(object: TreeObject<P>) => TreeEntries<P>} */
|
|
170
|
+
const objectEntries = definedEntries
|
|
171
|
+
/** @type {(kv: TreeEntry<P>) => List<string>} */
|
|
172
|
+
const propertySerialize = ([k, v]) => flat([
|
|
173
|
+
stringSerialize(k),
|
|
174
|
+
colon,
|
|
175
|
+
f(v)
|
|
176
|
+
])
|
|
177
|
+
const mapPropertySerialize = map(propertySerialize)
|
|
178
|
+
/** @type {(object: TreeObject<P>) => List<string>} */
|
|
179
|
+
const objectSerialize = fn(objectEntries)
|
|
180
|
+
.map(sort)
|
|
181
|
+
.map(mapPropertySerialize)
|
|
182
|
+
.map(objectWrap)
|
|
183
|
+
.result
|
|
184
|
+
/** @type {(value: Tree<P>) => List<string>} */
|
|
185
|
+
const f = value => {
|
|
186
|
+
if (value instanceof Array) { return arraySerialize(value) }
|
|
187
|
+
if (isObject(value)) { return objectSerialize(value) }
|
|
188
|
+
return leafSerialize(value)
|
|
189
|
+
}
|
|
190
|
+
/** @type {(value: TreeArray<P>) => List<string>} */
|
|
191
|
+
const arraySerialize = compose(map(f))(arrayWrap)
|
|
192
|
+
return f
|
|
193
|
+
}
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { concat, empty, flat, stateScan, toArray } from '../../../types/list/module.f.mjs'
|
|
13
|
-
import { multiply } from '../../../types/bigfloat/module.f.mjs'
|
|
14
13
|
import { tokenize as jsTokenize } from '../../../js/tokenizer/module.f.mjs'
|
|
15
14
|
import { assertEq } from '../../../asserts/module.f.mjs'
|
|
16
15
|
|
|
@@ -49,8 +48,13 @@ const parseDefaultState = input => {
|
|
|
49
48
|
const parseMinusState = input => {
|
|
50
49
|
if (input === null) return [[{ kind: 'error', message: 'invalid token' }], { kind: 'def' }]
|
|
51
50
|
switch (input.token.kind) {
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
// negation is lexical: the minus sign joins the lexeme, so the token
|
|
52
|
+
// stays the exact source text of the JSON number.
|
|
53
|
+
case 'number': return [[{ kind: 'number', value: `-${input.token.value}` }], { kind: 'def' }]
|
|
54
|
+
// No `'-'` case: the underlying JS tokenizer always merges adjacent
|
|
55
|
+
// `-` characters into a single `'--'` token (see `js/tokenizer`), so
|
|
56
|
+
// this state never sees a second `'-'` — a run of `-` past the first
|
|
57
|
+
// always falls through to the `default` arm below instead.
|
|
54
58
|
default: return [{ first: { kind: 'error', message: 'invalid token' }, tail: mapToken(input.token) }, { kind: 'def' }]
|
|
55
59
|
}
|
|
56
60
|
}
|
|
@@ -5,4 +5,10 @@ export declare const proof: {
|
|
|
5
5
|
json: (() => void)[];
|
|
6
6
|
id: (() => void)[];
|
|
7
7
|
keywords: (() => void)[];
|
|
8
|
+
lossless: {
|
|
9
|
+
oversizedCoefficient: () => void;
|
|
10
|
+
unboundedExponent: () => void;
|
|
11
|
+
negativeUnboundedExponent: () => void;
|
|
12
|
+
negativeOversized: () => void;
|
|
13
|
+
};
|
|
8
14
|
};
|
|
@@ -7,6 +7,7 @@ import { toArray } from '../../../types/list/module.f.mjs'
|
|
|
7
7
|
import { stringifyAsTree } from '../../../djs/serializer/module.f.mjs'
|
|
8
8
|
import { sort } from '../../../types/object/module.f.mjs'
|
|
9
9
|
import { stringToList } from '../../../text/utf16/module.f.mjs'
|
|
10
|
+
import { assertStructurallySame } from '../../../asserts/module.f.mjs'
|
|
10
11
|
|
|
11
12
|
/** @type {(s: string) => readonly JsonToken[]} */
|
|
12
13
|
const tokenizeString = s => toArray(tokenize(stringToList(s)))
|
|
@@ -109,11 +110,11 @@ export const proof = {
|
|
|
109
110
|
},
|
|
110
111
|
() => {
|
|
111
112
|
const result = stringify(tokenizeString('0'))
|
|
112
|
-
if (result !== '[{"
|
|
113
|
+
if (result !== '[{"kind":"number","value":"0"},{"kind":"eof"}]') { throw result }
|
|
113
114
|
},
|
|
114
115
|
() => {
|
|
115
116
|
const result = stringify(tokenizeString('[0]'))
|
|
116
|
-
if (result !== '[{"kind":"["},{"
|
|
117
|
+
if (result !== '[{"kind":"["},{"kind":"number","value":"0"},{"kind":"]"},{"kind":"eof"}]') { throw result }
|
|
117
118
|
},
|
|
118
119
|
() => {
|
|
119
120
|
const result = stringify(tokenizeString('00'))
|
|
@@ -125,23 +126,23 @@ export const proof = {
|
|
|
125
126
|
},
|
|
126
127
|
() => {
|
|
127
128
|
const result = stringify(tokenizeString('123456789012345678901234567890'))
|
|
128
|
-
if (result !== '[{"
|
|
129
|
+
if (result !== '[{"kind":"number","value":"123456789012345678901234567890"},{"kind":"eof"}]') { throw result }
|
|
129
130
|
},
|
|
130
131
|
() => {
|
|
131
132
|
const result = stringify(tokenizeString('{90}'))
|
|
132
|
-
if (result !== '[{"kind":"{"},{"
|
|
133
|
+
if (result !== '[{"kind":"{"},{"kind":"number","value":"90"},{"kind":"}"},{"kind":"eof"}]') { throw result }
|
|
133
134
|
},
|
|
134
135
|
() => {
|
|
135
136
|
const result = stringify(tokenizeString('1 2'))
|
|
136
|
-
if (result !== '[{"
|
|
137
|
+
if (result !== '[{"kind":"number","value":"1"},{"kind":"number","value":"2"},{"kind":"eof"}]') { throw result }
|
|
137
138
|
},
|
|
138
139
|
() => {
|
|
139
140
|
const result = stringify(tokenizeString('0. 2'))
|
|
140
|
-
if (result !== '[{"kind":"error","message":"invalid number"},{"
|
|
141
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"number","value":"2"},{"kind":"eof"}]') { throw result }
|
|
141
142
|
},
|
|
142
143
|
() => {
|
|
143
144
|
const result = stringify(tokenizeString('10-0'))
|
|
144
|
-
if (result !== '[{"
|
|
145
|
+
if (result !== '[{"kind":"number","value":"10"},{"kind":"number","value":"-0"},{"kind":"eof"}]') { throw result }
|
|
145
146
|
},
|
|
146
147
|
() => {
|
|
147
148
|
const result = stringify(tokenizeString('9a:'))
|
|
@@ -149,7 +150,7 @@ export const proof = {
|
|
|
149
150
|
},
|
|
150
151
|
() => {
|
|
151
152
|
const result = stringify(tokenizeString('-10'))
|
|
152
|
-
if (result !== '[{"
|
|
153
|
+
if (result !== '[{"kind":"number","value":"-10"},{"kind":"eof"}]') { throw result }
|
|
153
154
|
},
|
|
154
155
|
() => {
|
|
155
156
|
const result = stringify(tokenizeString('-'))
|
|
@@ -165,7 +166,7 @@ export const proof = {
|
|
|
165
166
|
},
|
|
166
167
|
() => {
|
|
167
168
|
const result = stringify(tokenizeString('-0'))
|
|
168
|
-
if (result !== '[{"
|
|
169
|
+
if (result !== '[{"kind":"number","value":"-0"},{"kind":"eof"}]') { throw result }
|
|
169
170
|
},
|
|
170
171
|
() => {
|
|
171
172
|
const result = stringify(tokenizeString('-00'))
|
|
@@ -173,15 +174,15 @@ export const proof = {
|
|
|
173
174
|
},
|
|
174
175
|
() => {
|
|
175
176
|
const result = stringify(tokenizeString('-.123'))
|
|
176
|
-
if (result !== '[{"kind":"error","message":"invalid token"},{"kind":"error","message":"invalid token"},{"
|
|
177
|
+
if (result !== '[{"kind":"error","message":"invalid token"},{"kind":"error","message":"invalid token"},{"kind":"number","value":"123"},{"kind":"eof"}]') { throw result }
|
|
177
178
|
},
|
|
178
179
|
() => {
|
|
179
180
|
const result = stringify(tokenizeString('0.01'))
|
|
180
|
-
if (result !== '[{"
|
|
181
|
+
if (result !== '[{"kind":"number","value":"0.01"},{"kind":"eof"}]') { throw result }
|
|
181
182
|
},
|
|
182
183
|
() => {
|
|
183
184
|
const result = stringify(tokenizeString('-0.9'))
|
|
184
|
-
if (result !== '[{"
|
|
185
|
+
if (result !== '[{"kind":"number","value":"-0.9"},{"kind":"eof"}]') { throw result }
|
|
185
186
|
},
|
|
186
187
|
() => {
|
|
187
188
|
const result = stringify(tokenizeString('-0.'))
|
|
@@ -193,11 +194,11 @@ export const proof = {
|
|
|
193
194
|
},
|
|
194
195
|
() => {
|
|
195
196
|
const result = stringify(tokenizeString('12.34'))
|
|
196
|
-
if (result !== '[{"
|
|
197
|
+
if (result !== '[{"kind":"number","value":"12.34"},{"kind":"eof"}]') { throw result }
|
|
197
198
|
},
|
|
198
199
|
() => {
|
|
199
200
|
const result = stringify(tokenizeString('-12.00'))
|
|
200
|
-
if (result !== '[{"
|
|
201
|
+
if (result !== '[{"kind":"number","value":"-12.00"},{"kind":"eof"}]') { throw result }
|
|
201
202
|
},
|
|
202
203
|
() => {
|
|
203
204
|
const result = stringify(tokenizeString('-12.'))
|
|
@@ -209,27 +210,27 @@ export const proof = {
|
|
|
209
210
|
},
|
|
210
211
|
() => {
|
|
211
212
|
const result = stringify(tokenizeString('0e1'))
|
|
212
|
-
if (result !== '[{"
|
|
213
|
+
if (result !== '[{"kind":"number","value":"0e1"},{"kind":"eof"}]') { throw result }
|
|
213
214
|
},
|
|
214
215
|
() => {
|
|
215
216
|
const result = stringify(tokenizeString('0e+2'))
|
|
216
|
-
if (result !== '[{"
|
|
217
|
+
if (result !== '[{"kind":"number","value":"0e+2"},{"kind":"eof"}]') { throw result }
|
|
217
218
|
},
|
|
218
219
|
() => {
|
|
219
220
|
const result = stringify(tokenizeString('0e-0'))
|
|
220
|
-
if (result !== '[{"
|
|
221
|
+
if (result !== '[{"kind":"number","value":"0e-0"},{"kind":"eof"}]') { throw result }
|
|
221
222
|
},
|
|
222
223
|
() => {
|
|
223
224
|
const result = stringify(tokenizeString('12e0000'))
|
|
224
|
-
if (result !== '[{"
|
|
225
|
+
if (result !== '[{"kind":"number","value":"12e0000"},{"kind":"eof"}]') { throw result }
|
|
225
226
|
},
|
|
226
227
|
() => {
|
|
227
228
|
const result = stringify(tokenizeString('-12e-0001'))
|
|
228
|
-
if (result !== '[{"
|
|
229
|
+
if (result !== '[{"kind":"number","value":"-12e-0001"},{"kind":"eof"}]') { throw result }
|
|
229
230
|
},
|
|
230
231
|
() => {
|
|
231
232
|
const result = stringify(tokenizeString('-12.34e1234'))
|
|
232
|
-
if (result !== '[{"
|
|
233
|
+
if (result !== '[{"kind":"number","value":"-12.34e1234"},{"kind":"eof"}]') { throw result }
|
|
233
234
|
},
|
|
234
235
|
() => {
|
|
235
236
|
const result = stringify(tokenizeString('0e'))
|
|
@@ -287,5 +288,45 @@ export const proof = {
|
|
|
287
288
|
const result = stringify(tokenizeString('[null]'))
|
|
288
289
|
if (result !== '[{"kind":"["},{"kind":"null"},{"kind":"]"},{"kind":"eof"}]') { throw result }
|
|
289
290
|
},
|
|
290
|
-
]
|
|
291
|
+
],
|
|
292
|
+
// Losslessness starts at the tokenizer boundary: a syntactically valid
|
|
293
|
+
// JSON number reaches `NumberToken.value` as its exact lexeme. Nothing
|
|
294
|
+
// derived from it — a coefficient bigint, an exponent number — is built
|
|
295
|
+
// while scanning, so no valid input can fail to tokenize because such a
|
|
296
|
+
// derived value would exceed a runtime numeric limit.
|
|
297
|
+
//
|
|
298
|
+
// The runtime's own bigint limit (V8 rejects magnitudes above 2^30 bits,
|
|
299
|
+
// roughly 3.2e8 decimal digits) is not exercised here: the smallest input
|
|
300
|
+
// that reaches it is a JSON document of some hundreds of megabytes. These
|
|
301
|
+
// cases stay far below that while still being far above what `number` and
|
|
302
|
+
// `Number.MAX_SAFE_INTEGER` can hold.
|
|
303
|
+
lossless: {
|
|
304
|
+
// a coefficient with more digits than any JavaScript number can carry
|
|
305
|
+
oversizedCoefficient: () => {
|
|
306
|
+
const value = `1${'0'.repeat(100000)}1`
|
|
307
|
+
assertStructurallySame(
|
|
308
|
+
tokenizeString(value),
|
|
309
|
+
[{ kind: 'number', value }, { kind: 'eof' }])
|
|
310
|
+
},
|
|
311
|
+
// exponent text far beyond JavaScript-number precision: `Number` of it
|
|
312
|
+
// is `Infinity`, yet every digit still has to reach the token
|
|
313
|
+
unboundedExponent: () => {
|
|
314
|
+
const value = '1e999999999999999999999'
|
|
315
|
+
assertStructurallySame(
|
|
316
|
+
tokenizeString(value),
|
|
317
|
+
[{ kind: 'number', value }, { kind: 'eof' }])
|
|
318
|
+
},
|
|
319
|
+
negativeUnboundedExponent: () => {
|
|
320
|
+
const value = '-1.5e-999999999999999999999'
|
|
321
|
+
assertStructurallySame(
|
|
322
|
+
tokenizeString(value),
|
|
323
|
+
[{ kind: 'number', value }, { kind: 'eof' }])
|
|
324
|
+
},
|
|
325
|
+
negativeOversized: () => {
|
|
326
|
+
const value = `-1${'0'.repeat(100000)}1`
|
|
327
|
+
assertStructurallySame(
|
|
328
|
+
tokenizeString(value),
|
|
329
|
+
[{ kind: 'number', value }, { kind: 'eof' }])
|
|
330
|
+
},
|
|
331
|
+
},
|
|
291
332
|
}
|