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
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* @import { OrderedMap } from '../../types/ordered_map/types.ts'
|
|
11
11
|
* @import { AstArray, AstConst, AstModule, AstModuleRef } from '../ast/types.ts'
|
|
12
12
|
* @import { TokenMetadata } from '../../js/tokenizer/types.ts'
|
|
13
|
-
* @import { ParseError } from './types.ts'
|
|
13
|
+
* @import { ParseError, _ValueToken } from './types.ts'
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { error, ok } from '../../types/result/module.f.mjs'
|
|
@@ -60,10 +60,22 @@ import { assertEq } from '../../asserts/module.f.mjs'
|
|
|
60
60
|
* readonly module: _ModuleState
|
|
61
61
|
* }} _ExportState */
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Where the value parser stands inside the value it is reading.
|
|
65
|
+
*
|
|
66
|
+
* The object states spell a property out left to right: `'{'` expects a key,
|
|
67
|
+
* `'{k'` the `:` after one, `'{:'` the value, `'{v'` the `,` or `}` after it,
|
|
68
|
+
* and `'{,'` the next key. A computed key `["a"]` takes the two extra steps
|
|
69
|
+
* `'{['` (the string inside the brackets) and `'{[k'` (the closing `]`), then
|
|
70
|
+
* rejoins the plain path at `'{k'`.
|
|
71
|
+
*
|
|
72
|
+
* @typedef {'' | '[' | '[v' | '[,' | '{' | '{[' | '{[k' | '{k' | '{:' | '{v' | '{,'} _ValueState
|
|
73
|
+
*/
|
|
74
|
+
|
|
63
75
|
/** @typedef {{
|
|
64
76
|
* readonly state: 'constValue' | 'exportValue'
|
|
65
77
|
* readonly module: _ModuleState
|
|
66
|
-
* readonly valueState:
|
|
78
|
+
* readonly valueState: _ValueState
|
|
67
79
|
* readonly top: _DjsStackElement | null
|
|
68
80
|
* readonly stack: _DjsStack
|
|
69
81
|
* }} _ParseValueState */
|
|
@@ -78,7 +90,21 @@ import { assertEq } from '../../asserts/module.f.mjs'
|
|
|
78
90
|
* readonly error: ParseError
|
|
79
91
|
* }} _ErrorState */
|
|
80
92
|
|
|
81
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* A statement begins with `import`, `const`, or `export` and with nothing
|
|
95
|
+
* else. The three are a whitelist that grows as the language does, not a
|
|
96
|
+
* closed set; what a statement may never begin with is a **value**. A text
|
|
97
|
+
* that does — `42`, `[1,2]`, `{"a":1}` — is a JSON document, and reading it
|
|
98
|
+
* as a module would give it a value no JavaScript engine gives it: as
|
|
99
|
+
* JavaScript `{"a":1}` does not parse at all, and `[1,2]` is an expression
|
|
100
|
+
* statement exporting nothing.
|
|
101
|
+
*
|
|
102
|
+
* The statements are also ordered: every `import` precedes every `const`, and
|
|
103
|
+
* `export default` ends the module. `eof` here is a module with no
|
|
104
|
+
* `export default`, which is what "unexpected end" reports.
|
|
105
|
+
*
|
|
106
|
+
* @type {(token: DjsTokenWithMetadata) => (state: _InitialState) => _ParserState}
|
|
107
|
+
*/
|
|
82
108
|
const parseInitialOp = ({ token, metadata }) => state => {
|
|
83
109
|
switch (token.kind)
|
|
84
110
|
{
|
|
@@ -88,13 +114,17 @@ const parseInitialOp = ({ token, metadata }) => state => {
|
|
|
88
114
|
case '/*': return state
|
|
89
115
|
case 'id': {
|
|
90
116
|
switch (token.value) {
|
|
91
|
-
case 'import': return
|
|
117
|
+
case 'import': return length(state.module.consts) === 0
|
|
118
|
+
? { ...state, state: 'import' }
|
|
119
|
+
: { state: 'error', error: { message: 'import must come before const', metadata } }
|
|
92
120
|
case 'const': return { ...state, state: 'const' }
|
|
93
121
|
case 'export': return { ...state, state: 'export' }
|
|
94
122
|
}
|
|
123
|
+
break
|
|
95
124
|
}
|
|
125
|
+
case 'eof': return { state: 'error', error: { message: 'unexpected end', metadata } }
|
|
96
126
|
}
|
|
97
|
-
return
|
|
127
|
+
return { state: 'error', error: { message: 'unexpected token', metadata } }
|
|
98
128
|
}
|
|
99
129
|
|
|
100
130
|
/** @type {(token: DjsTokenWithMetadata) => (state: _NewLineRequiredState) => _ParserState} */
|
|
@@ -230,12 +260,34 @@ const addValueToObject = obj => value => (['object', setReplace(obj[2])(value)(o
|
|
|
230
260
|
/** @type {(array: _DjsStackArray) => (value: AstConst) => _DjsStackArray} */
|
|
231
261
|
const addToArray = array => value => (['array', concat(array[1])([value])])
|
|
232
262
|
|
|
233
|
-
/**
|
|
234
|
-
|
|
235
|
-
|
|
263
|
+
/**
|
|
264
|
+
* The key of `{ __proto__: v }` and `{ "__proto__": v }`. JavaScript reads
|
|
265
|
+
* both as an instruction to replace the object's prototype instead of as a
|
|
266
|
+
* property, so FunctionalScript rejects them and accepts only the computed
|
|
267
|
+
* spelling `{ ["__proto__"]: v }`, which denotes an ordinary property.
|
|
268
|
+
* See [spec: the `__proto__` key](../../../spec/README.md#the-__proto__-key).
|
|
269
|
+
*/
|
|
270
|
+
const protoKey = '__proto__'
|
|
271
|
+
|
|
272
|
+
/** @type {(valueState: _ValueState) => (state: _ParseValueState) => (key: string) => (metadata: TokenMetadata) => _ParserState} */
|
|
273
|
+
const pushKey = valueState => state => key => metadata => {
|
|
274
|
+
if (state.top?.[0] === 'object') { return { ...state, valueState, top: addKeyToObject(state.top)(key), stack: state.stack } }
|
|
236
275
|
return { state: 'error', error: { message: 'error', metadata } }
|
|
237
276
|
}
|
|
238
277
|
|
|
278
|
+
/**
|
|
279
|
+
* A key written as an identifier or a string literal, which is every key but
|
|
280
|
+
* the computed one — so this is where `__proto__` is refused. A JSON document
|
|
281
|
+
* spells that key the same way and means an ordinary property by it, but a
|
|
282
|
+
* JSON document is not a module and this parser does not read one
|
|
283
|
+
* ([spec: the `__proto__` key](../../../spec/README.md#the-__proto__-key)).
|
|
284
|
+
*
|
|
285
|
+
* @type {(state: _ParseValueState) => (key: string) => (metadata: TokenMetadata) => _ParserState}
|
|
286
|
+
*/
|
|
287
|
+
const pushPlainKey = state => key => metadata => key === protoKey
|
|
288
|
+
? { state: 'error', error: { message: '__proto__ requires the computed key form', metadata } }
|
|
289
|
+
: pushKey('{k')(state)(key)(metadata)
|
|
290
|
+
|
|
239
291
|
/** @type {(state: _ParseValueState) => (value: AstConst) => _ParserState} */
|
|
240
292
|
const pushValue = state => value => {
|
|
241
293
|
if (state.top === null) {
|
|
@@ -302,7 +354,12 @@ const endObject = state => {
|
|
|
302
354
|
return pushValue(newState)(obj)
|
|
303
355
|
}
|
|
304
356
|
|
|
305
|
-
/**
|
|
357
|
+
/**
|
|
358
|
+
* Only ever called on a token `isValueToken` has already confirmed carries a
|
|
359
|
+
* value, so the switch covers every `_ValueToken` case with no fallback arm.
|
|
360
|
+
*
|
|
361
|
+
* @type {(token: _ValueToken) => AstConst}
|
|
362
|
+
*/
|
|
306
363
|
const tokenToValue = token => {
|
|
307
364
|
switch (token.kind) {
|
|
308
365
|
case 'null': return null
|
|
@@ -312,11 +369,13 @@ const tokenToValue = token => {
|
|
|
312
369
|
case 'string': return token.value
|
|
313
370
|
case 'bigint': return token.value
|
|
314
371
|
case 'undefined': return undefined
|
|
315
|
-
default: return null
|
|
316
372
|
}
|
|
317
373
|
}
|
|
318
374
|
|
|
319
|
-
/**
|
|
375
|
+
/**
|
|
376
|
+
* @param {DjsToken} token
|
|
377
|
+
* @returns {token is _ValueToken}
|
|
378
|
+
*/
|
|
320
379
|
const isValueToken = token => {
|
|
321
380
|
switch (token.kind) {
|
|
322
381
|
case 'null':
|
|
@@ -391,7 +450,8 @@ const parseObjectStartOp = ({ token, metadata }) => state => {
|
|
|
391
450
|
{
|
|
392
451
|
case 'string':
|
|
393
452
|
case 'id':
|
|
394
|
-
return
|
|
453
|
+
return pushPlainKey(state)(token.value)(metadata)
|
|
454
|
+
case '[': return { ...state, valueState: '{[' }
|
|
395
455
|
case '}': return endObject(state)
|
|
396
456
|
case 'ws':
|
|
397
457
|
case 'nl':
|
|
@@ -402,6 +462,35 @@ const parseObjectStartOp = ({ token, metadata }) => state => {
|
|
|
402
462
|
}
|
|
403
463
|
}
|
|
404
464
|
|
|
465
|
+
// computed property keys with a constant string key (#2470)
|
|
466
|
+
/** @type {(token: DjsTokenWithMetadata) => (state: _ParseValueState) => _ParserState} */
|
|
467
|
+
const parseObjectComputedKeyOp = ({ token, metadata }) => state => {
|
|
468
|
+
switch (token.kind)
|
|
469
|
+
{
|
|
470
|
+
case 'string': return pushKey('{[k')(state)(token.value)(metadata)
|
|
471
|
+
case 'ws':
|
|
472
|
+
case 'nl':
|
|
473
|
+
case '//':
|
|
474
|
+
case '/*': return state
|
|
475
|
+
case 'eof': return { state: 'error', error: { message: 'unexpected end', metadata } }
|
|
476
|
+
default: return { state: 'error', error: { message: 'unexpected token', metadata } }
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/** @type {(token: DjsTokenWithMetadata) => (state: _ParseValueState) => _ParserState} */
|
|
481
|
+
const parseObjectComputedKeyEndOp = ({ token, metadata }) => state => {
|
|
482
|
+
switch (token.kind)
|
|
483
|
+
{
|
|
484
|
+
case ']': return { ...state, valueState: '{k' }
|
|
485
|
+
case 'ws':
|
|
486
|
+
case 'nl':
|
|
487
|
+
case '//':
|
|
488
|
+
case '/*': return state
|
|
489
|
+
case 'eof': return { state: 'error', error: { message: 'unexpected end', metadata } }
|
|
490
|
+
default: return { state: 'error', error: { message: 'unexpected token', metadata } }
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
405
494
|
/** @type {(token: DjsTokenWithMetadata) => (state: _ParseValueState) => _ParserState} */
|
|
406
495
|
const parseObjectKeyOp = ({ token, metadata }) => state => {
|
|
407
496
|
switch (token.kind)
|
|
@@ -455,7 +544,8 @@ const parseObjectCommaOp = ({ token, metadata }) => state => {
|
|
|
455
544
|
case '}': return endObject(state)
|
|
456
545
|
case 'string':
|
|
457
546
|
case 'id':
|
|
458
|
-
return
|
|
547
|
+
return pushPlainKey(state)(token.value)(metadata)
|
|
548
|
+
case '[': return { ...state, valueState: '{[' }
|
|
459
549
|
case 'ws':
|
|
460
550
|
case 'nl':
|
|
461
551
|
case '//':
|
|
@@ -488,6 +578,8 @@ const foldOp = token => state => {
|
|
|
488
578
|
case '[v': return parseArrayValueOp(token)(state)
|
|
489
579
|
case '[,': return parseValueOp(token)(state)
|
|
490
580
|
case '{': return parseObjectStartOp(token)(state)
|
|
581
|
+
case '{[': return parseObjectComputedKeyOp(token)(state)
|
|
582
|
+
case '{[k': return parseObjectComputedKeyEndOp(token)(state)
|
|
491
583
|
case '{k': return parseObjectKeyOp(token)(state)
|
|
492
584
|
case '{:': return parseObjectColonOp(token)(state)
|
|
493
585
|
case '{v': return parseObjectNextOp(token)(state)
|
|
@@ -497,11 +589,20 @@ const foldOp = token => state => {
|
|
|
497
589
|
}
|
|
498
590
|
}
|
|
499
591
|
|
|
500
|
-
/**
|
|
592
|
+
/**
|
|
593
|
+
* Reads the token list as a FunctionalScript module: `import` statements, then
|
|
594
|
+
* `const` statements, then one `export default`.
|
|
595
|
+
*
|
|
596
|
+
* This is the only language the parser reads. A JSON document is data, not a
|
|
597
|
+
* module, and `fjs/media/json` is its reader
|
|
598
|
+
* ([spec: JSON input](../../../spec/README.md#json-input)).
|
|
599
|
+
*
|
|
600
|
+
* @type {(tokenList: List<DjsTokenWithMetadata>) => Result<AstModule, ParseError>}
|
|
601
|
+
*/
|
|
501
602
|
export const parseFromTokens = tokenList => {
|
|
502
603
|
const state = fold(foldOp)({ state: '', module: { refs: null, modules: null, consts: null } })(tokenList)
|
|
503
604
|
switch (state.state) {
|
|
504
|
-
case 'result': return ok(/** @
|
|
605
|
+
case 'result': return ok(/** @satisfies {AstModule} */ ([toArray(state.module.modules), toArray(state.module.consts)]))
|
|
505
606
|
case 'error': return error(state.error)
|
|
506
607
|
default: return error({ message: 'unexpected end', metadata: null })
|
|
507
608
|
}
|
|
@@ -522,7 +623,7 @@ export const proof = {
|
|
|
522
623
|
top: null,
|
|
523
624
|
stack: null,
|
|
524
625
|
}
|
|
525
|
-
const result = pushKey(state)('key')({ path: 'test', line: 0, column: 0 })
|
|
626
|
+
const result = pushKey('{k')(state)('key')({ path: 'test', line: 0, column: 0 })
|
|
526
627
|
assertEq(result.state, 'error')
|
|
527
628
|
},
|
|
528
629
|
},
|
|
@@ -3,10 +3,14 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export declare const proof: {
|
|
5
5
|
valid: (() => void)[];
|
|
6
|
+
computedKey: (() => void)[];
|
|
7
|
+
invalidComputedKey: (() => void)[];
|
|
8
|
+
protoKey: (() => void)[];
|
|
6
9
|
invalid: (() => void)[];
|
|
7
10
|
errorMetadata: (() => void)[];
|
|
8
11
|
validWhiteSpaces: (() => void)[];
|
|
9
|
-
|
|
12
|
+
jsonDocumentIsNotAModule: (() => void)[];
|
|
13
|
+
statementOrder: (() => void)[];
|
|
10
14
|
invalidModule: (() => void)[];
|
|
11
15
|
validWithConst: (() => void)[];
|
|
12
16
|
invalidWithConst: (() => void)[];
|
|
@@ -159,6 +159,108 @@ export const proof = {
|
|
|
159
159
|
if (result !== '[[],[{"a":1}]]') { throw result }
|
|
160
160
|
}
|
|
161
161
|
],
|
|
162
|
+
// A computed key `["a"]` is a third spelling of an ordinary key, next to
|
|
163
|
+
// the identifier and the string literal (#2470).
|
|
164
|
+
computedKey: [
|
|
165
|
+
() => {
|
|
166
|
+
const tokenList = tokenizeString('export default {["a"]:1}')
|
|
167
|
+
const obj = parseFromTokens(tokenList)
|
|
168
|
+
assert(obj[0] === 'ok', obj)
|
|
169
|
+
const result = stringifyDjsModule(obj[1])
|
|
170
|
+
assertEq(result, '[[],[{"a":1}]]')
|
|
171
|
+
},
|
|
172
|
+
() => {
|
|
173
|
+
// all three spellings in one object, plus a trailing comma
|
|
174
|
+
const tokenList = tokenizeString('export default {a:1,"b":2,["c"]:3,}')
|
|
175
|
+
const obj = parseFromTokens(tokenList)
|
|
176
|
+
assert(obj[0] === 'ok', obj)
|
|
177
|
+
const result = stringifyDjsModule(obj[1])
|
|
178
|
+
assertEq(result, '[[],[{"a":1,"b":2,"c":3}]]')
|
|
179
|
+
},
|
|
180
|
+
() => {
|
|
181
|
+
// trivia is trivia inside the brackets too
|
|
182
|
+
const tokenList = tokenizeString('export default { [ /* c */ \n // c \n "a" /* c */ \n // c \n ] : 1 }')
|
|
183
|
+
const obj = parseFromTokens(tokenList)
|
|
184
|
+
assert(obj[0] === 'ok', obj)
|
|
185
|
+
const result = stringifyDjsModule(obj[1])
|
|
186
|
+
assertEq(result, '[[],[{"a":1}]]')
|
|
187
|
+
},
|
|
188
|
+
() => {
|
|
189
|
+
// the key that has no other spelling
|
|
190
|
+
const tokenList = tokenizeString('export default {["__proto__"]:{"a":42}}')
|
|
191
|
+
const obj = parseFromTokens(tokenList)
|
|
192
|
+
assert(obj[0] === 'ok', obj)
|
|
193
|
+
const result = stringifyDjsModule(obj[1])
|
|
194
|
+
assertEq(result, '[[],[{"__proto__":{"a":42}}]]')
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
invalidComputedKey: [
|
|
198
|
+
() => {
|
|
199
|
+
// the brackets hold a string literal, not a number
|
|
200
|
+
const tokenList = tokenizeString('export default {[1]:2}')
|
|
201
|
+
const obj = parseFromTokens(tokenList)
|
|
202
|
+
assert(obj[0] === 'error', obj)
|
|
203
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
204
|
+
},
|
|
205
|
+
() => {
|
|
206
|
+
// eof inside the brackets, before the key
|
|
207
|
+
const tokenList = tokenizeString('export default {[')
|
|
208
|
+
const obj = parseFromTokens(tokenList)
|
|
209
|
+
assert(obj[0] === 'error', obj)
|
|
210
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
211
|
+
},
|
|
212
|
+
() => {
|
|
213
|
+
// the brackets are not closed
|
|
214
|
+
const tokenList = tokenizeString('export default {["a"}')
|
|
215
|
+
const obj = parseFromTokens(tokenList)
|
|
216
|
+
assert(obj[0] === 'error', obj)
|
|
217
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
218
|
+
},
|
|
219
|
+
() => {
|
|
220
|
+
// eof after the key, before ']'
|
|
221
|
+
const tokenList = tokenizeString('export default {["a"')
|
|
222
|
+
const obj = parseFromTokens(tokenList)
|
|
223
|
+
assert(obj[0] === 'error', obj)
|
|
224
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
225
|
+
},
|
|
226
|
+
() => {
|
|
227
|
+
// a computed key still needs its ':'
|
|
228
|
+
const tokenList = tokenizeString('export default {["a"]}')
|
|
229
|
+
const obj = parseFromTokens(tokenList)
|
|
230
|
+
assert(obj[0] === 'error', obj)
|
|
231
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
// `{__proto__: v}` and `{"__proto__": v}` assign a prototype in JavaScript
|
|
235
|
+
// instead of adding a property, so FunctionalScript rejects both spellings
|
|
236
|
+
// and accepts only the computed one (#2480).
|
|
237
|
+
protoKey: [
|
|
238
|
+
() => {
|
|
239
|
+
const tokenList = tokenizeString('export default {__proto__:1}')
|
|
240
|
+
const obj = parseFromTokens(tokenList)
|
|
241
|
+
assert(obj[0] === 'error', obj)
|
|
242
|
+
assertEq(obj[1].message, '__proto__ requires the computed key form')
|
|
243
|
+
},
|
|
244
|
+
() => {
|
|
245
|
+
const tokenList = tokenizeString('export default {"__proto__":1}')
|
|
246
|
+
const obj = parseFromTokens(tokenList)
|
|
247
|
+
assert(obj[0] === 'error', obj)
|
|
248
|
+
assertEq(obj[1].message, '__proto__ requires the computed key form')
|
|
249
|
+
},
|
|
250
|
+
() => {
|
|
251
|
+
// the same two spellings after a ',', the parser's other key state
|
|
252
|
+
const tokenList = tokenizeString('export default {"a":1,__proto__:2}')
|
|
253
|
+
const obj = parseFromTokens(tokenList)
|
|
254
|
+
assert(obj[0] === 'error', obj)
|
|
255
|
+
assertEq(obj[1].message, '__proto__ requires the computed key form')
|
|
256
|
+
},
|
|
257
|
+
() => {
|
|
258
|
+
const tokenList = tokenizeString('export default {"a":1,"__proto__":2}')
|
|
259
|
+
const obj = parseFromTokens(tokenList)
|
|
260
|
+
assert(obj[0] === 'error', obj)
|
|
261
|
+
assertEq(obj[1].message, '__proto__ requires the computed key form')
|
|
262
|
+
},
|
|
263
|
+
],
|
|
162
264
|
invalid: [
|
|
163
265
|
() => {
|
|
164
266
|
const tokenList = tokenizeString('export default')
|
|
@@ -300,6 +402,115 @@ export const proof = {
|
|
|
300
402
|
assert(obj[0] === 'error', obj)
|
|
301
403
|
assertEq(obj[1].message, 'unexpected token')
|
|
302
404
|
},
|
|
405
|
+
() => {
|
|
406
|
+
// 'export' with no 'default' before eof.
|
|
407
|
+
const tokenList = tokenizeString('export')
|
|
408
|
+
const obj = parseFromTokens(tokenList)
|
|
409
|
+
assert(obj[0] === 'error', obj)
|
|
410
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
411
|
+
},
|
|
412
|
+
() => {
|
|
413
|
+
// 'const' with no name before eof.
|
|
414
|
+
const tokenList = tokenizeString('const')
|
|
415
|
+
const obj = parseFromTokens(tokenList)
|
|
416
|
+
assert(obj[0] === 'error', obj)
|
|
417
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
418
|
+
},
|
|
419
|
+
() => {
|
|
420
|
+
// 'const <name>' with no '=' before eof.
|
|
421
|
+
const tokenList = tokenizeString('const x')
|
|
422
|
+
const obj = parseFromTokens(tokenList)
|
|
423
|
+
assert(obj[0] === 'error', obj)
|
|
424
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
425
|
+
},
|
|
426
|
+
() => {
|
|
427
|
+
// 'const <name>' followed by a token that isn't '='.
|
|
428
|
+
const tokenList = tokenizeString('const x 5')
|
|
429
|
+
const obj = parseFromTokens(tokenList)
|
|
430
|
+
assert(obj[0] === 'error', obj)
|
|
431
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
432
|
+
},
|
|
433
|
+
() => {
|
|
434
|
+
// 'import' with no name before eof.
|
|
435
|
+
const tokenList = tokenizeString('import')
|
|
436
|
+
const obj = parseFromTokens(tokenList)
|
|
437
|
+
assert(obj[0] === 'error', obj)
|
|
438
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
439
|
+
},
|
|
440
|
+
() => {
|
|
441
|
+
// 'import' followed by a token that isn't an id.
|
|
442
|
+
const tokenList = tokenizeString('import 5')
|
|
443
|
+
const obj = parseFromTokens(tokenList)
|
|
444
|
+
assert(obj[0] === 'error', obj)
|
|
445
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
446
|
+
},
|
|
447
|
+
() => {
|
|
448
|
+
// 'import <name>' with no 'from' before eof.
|
|
449
|
+
const tokenList = tokenizeString('import a')
|
|
450
|
+
const obj = parseFromTokens(tokenList)
|
|
451
|
+
assert(obj[0] === 'error', obj)
|
|
452
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
453
|
+
},
|
|
454
|
+
() => {
|
|
455
|
+
// 'import <name> from' with no module string before eof.
|
|
456
|
+
const tokenList = tokenizeString('import a from')
|
|
457
|
+
const obj = parseFromTokens(tokenList)
|
|
458
|
+
assert(obj[0] === 'error', obj)
|
|
459
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
460
|
+
},
|
|
461
|
+
() => {
|
|
462
|
+
// Array opened but eof arrives before any value/']'.
|
|
463
|
+
const tokenList = tokenizeString('export default [')
|
|
464
|
+
const obj = parseFromTokens(tokenList)
|
|
465
|
+
assert(obj[0] === 'error', obj)
|
|
466
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
467
|
+
},
|
|
468
|
+
() => {
|
|
469
|
+
// Object opened but eof arrives before any key/'}'.
|
|
470
|
+
const tokenList = tokenizeString('export default {')
|
|
471
|
+
const obj = parseFromTokens(tokenList)
|
|
472
|
+
assert(obj[0] === 'error', obj)
|
|
473
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
474
|
+
},
|
|
475
|
+
() => {
|
|
476
|
+
// Object key given but eof arrives before ':'.
|
|
477
|
+
const tokenList = tokenizeString('export default {"a"')
|
|
478
|
+
const obj = parseFromTokens(tokenList)
|
|
479
|
+
assert(obj[0] === 'error', obj)
|
|
480
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
481
|
+
},
|
|
482
|
+
() => {
|
|
483
|
+
// Object ':' given but eof arrives before the value.
|
|
484
|
+
const tokenList = tokenizeString('export default {"a":')
|
|
485
|
+
const obj = parseFromTokens(tokenList)
|
|
486
|
+
assert(obj[0] === 'error', obj)
|
|
487
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
488
|
+
},
|
|
489
|
+
() => {
|
|
490
|
+
// Object value given, followed by a token that's neither ',' nor '}'.
|
|
491
|
+
const tokenList = tokenizeString('export default {"a":1 2}')
|
|
492
|
+
const obj = parseFromTokens(tokenList)
|
|
493
|
+
assert(obj[0] === 'error', obj)
|
|
494
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
495
|
+
},
|
|
496
|
+
() => {
|
|
497
|
+
// Object ',' given but eof arrives before the next key/'}'.
|
|
498
|
+
const tokenList = tokenizeString('export default {"a":1,')
|
|
499
|
+
const obj = parseFromTokens(tokenList)
|
|
500
|
+
assert(obj[0] === 'error', obj)
|
|
501
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
502
|
+
},
|
|
503
|
+
() => {
|
|
504
|
+
// `parseFromTokens` itself, called with no tokens at all (the
|
|
505
|
+
// tokenizer never produces this — it always emits at least an
|
|
506
|
+
// `eof` token — but the exported function's own contract must
|
|
507
|
+
// still handle it: the initial state is neither 'result' nor
|
|
508
|
+
// 'error', so it falls through to the same "unexpected end".
|
|
509
|
+
const obj = parseFromTokens(null)
|
|
510
|
+
assert(obj[0] === 'error', obj)
|
|
511
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
512
|
+
assertEq(obj[1].metadata, null)
|
|
513
|
+
},
|
|
303
514
|
],
|
|
304
515
|
errorMetadata: [
|
|
305
516
|
() => {
|
|
@@ -343,41 +554,92 @@ export const proof = {
|
|
|
343
554
|
if (result !== '[[],[{"a":0,"b":1}]]') { throw result }
|
|
344
555
|
},
|
|
345
556
|
],
|
|
346
|
-
|
|
557
|
+
// A JSON document is not a module: a statement begins with `import`,
|
|
558
|
+
// `const`, or `export` and never with a value. `fjs/media/json` is the
|
|
559
|
+
// reader for these texts.
|
|
560
|
+
jsonDocumentIsNotAModule: [
|
|
347
561
|
() => {
|
|
348
562
|
const tokenList = tokenizeString('null')
|
|
349
563
|
const obj = parseFromTokens(tokenList)
|
|
350
|
-
assert(obj[0] === '
|
|
351
|
-
|
|
352
|
-
assertEq(result, '[[],[null]]')
|
|
564
|
+
assert(obj[0] === 'error', obj)
|
|
565
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
353
566
|
},
|
|
354
567
|
() => {
|
|
355
568
|
const tokenList = tokenizeString('1')
|
|
356
569
|
const obj = parseFromTokens(tokenList)
|
|
357
|
-
assert(obj[0] === '
|
|
358
|
-
|
|
359
|
-
assertEq(result, '[[],[1]]')
|
|
570
|
+
assert(obj[0] === 'error', obj)
|
|
571
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
360
572
|
},
|
|
361
573
|
() => {
|
|
362
574
|
const tokenList = tokenizeString('[]')
|
|
363
575
|
const obj = parseFromTokens(tokenList)
|
|
364
|
-
assert(obj[0] === '
|
|
365
|
-
|
|
366
|
-
assertEq(result, '[[],[["array",[]]]]')
|
|
576
|
+
assert(obj[0] === 'error', obj)
|
|
577
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
367
578
|
},
|
|
368
579
|
() => {
|
|
369
580
|
const tokenList = tokenizeString('{"valid":"json"}')
|
|
370
581
|
const obj = parseFromTokens(tokenList)
|
|
582
|
+
assert(obj[0] === 'error', obj)
|
|
583
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
584
|
+
},
|
|
585
|
+
() => {
|
|
586
|
+
// an identifier that is not a statement keyword is no better
|
|
587
|
+
const tokenList = tokenizeString('a')
|
|
588
|
+
const obj = parseFromTokens(tokenList)
|
|
589
|
+
assert(obj[0] === 'error', obj)
|
|
590
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
591
|
+
},
|
|
592
|
+
() => {
|
|
593
|
+
// an empty module has no `export default`
|
|
594
|
+
const tokenList = tokenizeString('')
|
|
595
|
+
const obj = parseFromTokens(tokenList)
|
|
596
|
+
assert(obj[0] === 'error', obj)
|
|
597
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
598
|
+
},
|
|
599
|
+
() => {
|
|
600
|
+
// …and neither has one that only declares constants
|
|
601
|
+
const tokenList = tokenizeString('const a = 1\n')
|
|
602
|
+
const obj = parseFromTokens(tokenList)
|
|
603
|
+
assert(obj[0] === 'error', obj)
|
|
604
|
+
assertEq(obj[1].message, 'unexpected end')
|
|
605
|
+
},
|
|
606
|
+
],
|
|
607
|
+
// Statements are ordered: imports, then constants, then `export default`.
|
|
608
|
+
statementOrder: [
|
|
609
|
+
() => {
|
|
610
|
+
const tokenList = tokenizeString('import a from "a.f.js" \n const b = 1 \n export default [a,b]')
|
|
611
|
+
const obj = parseFromTokens(tokenList)
|
|
371
612
|
assert(obj[0] === 'ok', obj)
|
|
372
613
|
const result = stringifyDjsModule(obj[1])
|
|
373
|
-
|
|
374
|
-
}
|
|
614
|
+
assertEq(result, '[["a.f.js"],[1,["array",[["aref",0],["cref",0]]]]]')
|
|
615
|
+
},
|
|
616
|
+
() => {
|
|
617
|
+
const tokenList = tokenizeString('const b = 1 \n import a from "a.f.js" \n export default [a,b]')
|
|
618
|
+
const obj = parseFromTokens(tokenList)
|
|
619
|
+
assert(obj[0] === 'error', obj)
|
|
620
|
+
assertEq(obj[1].message, 'import must come before const')
|
|
621
|
+
},
|
|
622
|
+
() => {
|
|
623
|
+
// nothing follows `export default` but trivia
|
|
624
|
+
const tokenList = tokenizeString('export default 1 \n const a = 2')
|
|
625
|
+
const obj = parseFromTokens(tokenList)
|
|
626
|
+
assert(obj[0] === 'error', obj)
|
|
627
|
+
assertEq(obj[1].message, 'unexpected token')
|
|
628
|
+
},
|
|
375
629
|
],
|
|
376
630
|
invalidModule:[
|
|
377
631
|
() => {
|
|
632
|
+
// `module` is not one of the statement keywords
|
|
378
633
|
const tokenList = tokenizeString('module=null')
|
|
379
634
|
const obj = parseFromTokens(tokenList)
|
|
380
635
|
assert(obj[0] === 'error', obj)
|
|
636
|
+
assertEq(obj[1].message, 'unexpected token', obj)
|
|
637
|
+
},
|
|
638
|
+
() => {
|
|
639
|
+
// a reference the module never declared, in a value position
|
|
640
|
+
const tokenList = tokenizeString('export default a')
|
|
641
|
+
const obj = parseFromTokens(tokenList)
|
|
642
|
+
assert(obj[0] === 'error', obj)
|
|
381
643
|
assertEq(obj[1].message, 'const not found', obj)
|
|
382
644
|
},
|
|
383
645
|
() => {
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Type-level API for `fjs/djs/parser/module.f.mjs`: the `ParseError` shape
|
|
3
|
-
* `parseFromTokens` reports
|
|
3
|
+
* `parseFromTokens` reports, and the `_ValueToken` subset `tokenToValue`
|
|
4
|
+
* accepts.
|
|
4
5
|
*
|
|
5
6
|
* @module
|
|
6
7
|
*/
|
|
7
8
|
import type { TokenMetadata } from '../../js/tokenizer/types.ts';
|
|
9
|
+
import type { DjsToken } from '../tokenizer/types.ts';
|
|
8
10
|
export type ParseError = {
|
|
9
11
|
readonly message: string;
|
|
10
12
|
readonly metadata: TokenMetadata | null;
|
|
11
13
|
};
|
|
14
|
+
/** DJS tokens that carry a directly-usable value. */
|
|
15
|
+
export type _ValueToken = Extract<DjsToken, {
|
|
16
|
+
readonly kind: 'null' | 'false' | 'true' | 'undefined' | 'string' | 'number' | 'bigint';
|
|
17
|
+
}>;
|
package/fjs/djs/proof.f.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @import {
|
|
2
|
+
* @import { Unknown } from './types.ts'
|
|
3
3
|
*/
|
|
4
4
|
export declare const proof: {
|
|
5
5
|
tooFewArgs: {
|
|
@@ -8,6 +8,22 @@ export declare const proof: {
|
|
|
8
8
|
};
|
|
9
9
|
success: () => void;
|
|
10
10
|
jsonOutput: () => void;
|
|
11
|
-
fileNotFound:
|
|
11
|
+
fileNotFound: {
|
|
12
|
+
module: () => void;
|
|
13
|
+
json: () => void;
|
|
14
|
+
};
|
|
12
15
|
parseError: () => void;
|
|
16
|
+
roundTrip: (() => void)[];
|
|
17
|
+
protoKey: {
|
|
18
|
+
moduleRoundTrip: () => void;
|
|
19
|
+
jsonOutput: () => void;
|
|
20
|
+
jsonInput: () => void;
|
|
21
|
+
jsonInputRoundTrip: () => void;
|
|
22
|
+
jsonImportRejected: () => void;
|
|
23
|
+
jsonInputIdKeyRejected: () => void;
|
|
24
|
+
jsonInputRejectsDjsExtensions: () => void;
|
|
25
|
+
value: () => void;
|
|
26
|
+
idKeyRejected: () => void;
|
|
27
|
+
stringKeyRejected: () => void;
|
|
28
|
+
};
|
|
13
29
|
};
|