functionalscript 0.30.0 → 0.31.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/fs/asn.1/module.f.js +18 -22
  2. package/fs/asn.1/proof.f.d.ts +5 -0
  3. package/fs/asn.1/proof.f.js +38 -2
  4. package/fs/base64/module.f.d.ts +9 -0
  5. package/fs/base64/module.f.js +60 -0
  6. package/fs/base64/proof.f.d.ts +11 -0
  7. package/fs/base64/proof.f.js +117 -0
  8. package/fs/base_n/module.f.d.ts +44 -0
  9. package/fs/base_n/module.f.js +54 -0
  10. package/fs/base_n/proof.f.d.ts +10 -0
  11. package/fs/base_n/proof.f.js +86 -0
  12. package/fs/bnf/data/module.f.d.ts +4 -9
  13. package/fs/bnf/data/module.f.js +4 -3
  14. package/fs/bnf/module.f.d.ts +3 -4
  15. package/fs/bnf/module.f.js +3 -2
  16. package/fs/bnf/proof.f.d.ts +9 -0
  17. package/fs/bnf/proof.f.js +98 -1
  18. package/fs/cas/mcp/module.f.d.ts +40 -0
  19. package/fs/cas/mcp/module.f.js +223 -0
  20. package/fs/cas/mcp/proof.f.d.ts +30 -0
  21. package/fs/cas/mcp/proof.f.js +310 -0
  22. package/fs/cas/module.f.d.ts +9 -3
  23. package/fs/cas/module.f.js +104 -69
  24. package/fs/cas/proof.f.d.ts +2 -0
  25. package/fs/cas/proof.f.js +30 -1
  26. package/fs/cbase32/module.f.d.ts +1 -1
  27. package/fs/cbase32/module.f.js +19 -40
  28. package/fs/cbase32/proof.f.d.ts +1 -0
  29. package/fs/cbase32/proof.f.js +15 -0
  30. package/fs/ci/config/module.f.d.ts +6 -6
  31. package/fs/ci/config/module.f.js +6 -6
  32. package/fs/ci/deno/module.f.js +2 -2
  33. package/fs/ci/module.f.d.ts +5 -0
  34. package/fs/ci/module.f.js +2 -3
  35. package/fs/ci/proof.f.d.ts +1 -0
  36. package/fs/ci/proof.f.js +9 -3
  37. package/fs/cli/module.f.d.ts +3 -1
  38. package/fs/cli/module.f.js +22 -12
  39. package/fs/cli/proof.f.d.ts +5 -0
  40. package/fs/cli/proof.f.js +76 -0
  41. package/fs/crypto/hmac/proof.f.d.ts +1 -0
  42. package/fs/crypto/hmac/proof.f.js +8 -0
  43. package/fs/crypto/secp/proof.f.d.ts +1 -0
  44. package/fs/crypto/secp/proof.f.js +10 -0
  45. package/fs/crypto/sign/module.f.js +1 -4
  46. package/fs/dev/module.f.d.ts +5 -3
  47. package/fs/dev/module.f.js +13 -2
  48. package/fs/dev/package_json/proof.f.d.ts +1 -0
  49. package/fs/dev/package_json/proof.f.js +5 -0
  50. package/fs/dev/proof.f.d.ts +1 -0
  51. package/fs/dev/proof.f.js +12 -1
  52. package/fs/djs/ast/module.f.d.ts +1 -1
  53. package/fs/djs/ast/proof.f.d.ts +5 -0
  54. package/fs/djs/ast/proof.f.js +17 -0
  55. package/fs/djs/module.f.d.ts +1 -1
  56. package/fs/djs/module.f.js +2 -3
  57. package/fs/djs/serializer/module.f.js +24 -11
  58. package/fs/djs/transpiler/module.f.js +3 -4
  59. package/fs/effects/memory/module.f.d.ts +37 -0
  60. package/fs/effects/memory/module.f.js +24 -0
  61. package/fs/effects/memory/proof.f.d.ts +6 -0
  62. package/fs/effects/memory/proof.f.js +64 -0
  63. package/fs/effects/mock/module.f.d.ts +7 -2
  64. package/fs/effects/mock/module.f.js +12 -8
  65. package/fs/effects/module.d.ts +1 -1
  66. package/fs/effects/module.f.d.ts +41 -0
  67. package/fs/effects/module.f.js +25 -0
  68. package/fs/effects/module.js +6 -7
  69. package/fs/effects/node/memory/module.d.ts +20 -0
  70. package/fs/effects/node/memory/module.js +44 -0
  71. package/fs/effects/node/memory/proof.d.ts +10 -0
  72. package/fs/effects/node/memory/proof.js +35 -0
  73. package/fs/effects/node/module.d.ts +1 -1
  74. package/fs/effects/node/module.f.d.ts +54 -8
  75. package/fs/effects/node/module.f.js +55 -4
  76. package/fs/effects/node/module.js +167 -137
  77. package/fs/effects/node/proof.f.d.ts +10 -0
  78. package/fs/effects/node/proof.f.js +88 -21
  79. package/fs/effects/node/virtual/module.f.d.ts +6 -0
  80. package/fs/effects/node/virtual/module.f.js +48 -16
  81. package/fs/effects/node/virtual/proof.f.d.ts +17 -0
  82. package/fs/effects/node/virtual/proof.f.js +79 -0
  83. package/fs/effects/proof.f.d.ts +5 -0
  84. package/fs/effects/proof.f.js +54 -34
  85. package/fs/emergent_testing/module.f.d.ts +6 -1
  86. package/fs/emergent_testing/module.f.js +8 -3
  87. package/fs/emergent_testing/proof.f.d.ts +11 -0
  88. package/fs/emergent_testing/proof.f.js +52 -16
  89. package/fs/fjs/module.f.js +2 -2
  90. package/fs/fjs/proof.f.d.ts +8 -0
  91. package/fs/fjs/proof.f.js +39 -0
  92. package/fs/fsc/module.f.d.ts +5 -0
  93. package/fs/fsc/module.f.js +17 -27
  94. package/fs/fsc/proof.f.d.ts +8 -0
  95. package/fs/fsc/proof.f.js +48 -2
  96. package/fs/fsm/module.f.d.ts +2 -3
  97. package/fs/fsm/module.f.js +1 -1
  98. package/fs/html/module.f.d.ts +2 -3
  99. package/fs/html/module.f.js +7 -6
  100. package/fs/html/proof.f.d.ts +1 -0
  101. package/fs/html/proof.f.js +7 -0
  102. package/fs/js/tokenizer/module.f.js +1 -1
  103. package/fs/js/tokenizer/proof.f.js +7 -0
  104. package/fs/json/module.f.d.ts +9 -2
  105. package/fs/json/module.f.js +9 -7
  106. package/fs/json/parser/module.f.js +4 -6
  107. package/fs/json/parser/proof.f.js +19 -10
  108. package/fs/json/proof.f.d.ts +2 -1
  109. package/fs/json/proof.f.js +33 -6
  110. package/fs/json/rpc/module.f.d.ts +5 -0
  111. package/fs/json/rpc/module.f.js +16 -11
  112. package/fs/json/schema/module.f.d.ts +15 -14
  113. package/fs/json/schema/proof.f.d.ts +3 -0
  114. package/fs/json/schema/proof.f.js +16 -1
  115. package/fs/mcp/module.f.d.ts +103 -5
  116. package/fs/mcp/module.f.js +139 -2
  117. package/fs/mcp/proof.f.d.ts +34 -0
  118. package/fs/mcp/proof.f.js +207 -0
  119. package/fs/mcp/stdio/module.f.d.ts +39 -0
  120. package/fs/mcp/stdio/module.f.js +54 -0
  121. package/fs/mcp/stdio/proof.f.d.ts +10 -0
  122. package/fs/mcp/stdio/proof.f.js +92 -0
  123. package/fs/mime/module.f.d.ts +39 -0
  124. package/fs/mime/module.f.js +78 -0
  125. package/fs/mime/proof.f.d.ts +15 -0
  126. package/fs/mime/proof.f.js +30 -0
  127. package/fs/path/module.f.d.ts +8 -0
  128. package/fs/path/module.f.js +10 -3
  129. package/fs/path/proof.f.d.ts +1 -0
  130. package/fs/path/proof.f.js +40 -2
  131. package/fs/text/sgr/proof.f.js +30 -2
  132. package/fs/text/utf8/module.f.d.ts +7 -0
  133. package/fs/text/utf8/module.f.js +85 -31
  134. package/fs/text/utf8/proof.f.d.ts +1 -0
  135. package/fs/text/utf8/proof.f.js +60 -1
  136. package/fs/types/bigfloat/module.f.d.ts +3 -0
  137. package/fs/types/bigfloat/module.f.js +30 -31
  138. package/fs/types/bigint/module.f.d.ts +24 -2
  139. package/fs/types/bigint/module.f.js +30 -2
  140. package/fs/types/bigint/proof.f.d.ts +7 -0
  141. package/fs/types/bigint/proof.f.js +47 -16
  142. package/fs/types/bit_vec/module.f.d.ts +18 -0
  143. package/fs/types/bit_vec/module.f.js +18 -0
  144. package/fs/types/bit_vec/proof.f.d.ts +1 -0
  145. package/fs/types/bit_vec/proof.f.js +13 -1
  146. package/fs/types/function/operator/proof.f.d.ts +2 -0
  147. package/fs/types/function/operator/proof.f.js +20 -2
  148. package/fs/types/list/module.f.js +1 -4
  149. package/fs/types/list/proof.f.d.ts +1 -1
  150. package/fs/types/list/proof.f.js +14 -6
  151. package/fs/types/map/proof.f.d.ts +1 -0
  152. package/fs/types/map/proof.f.js +10 -1
  153. package/fs/types/nibble_set/module.f.d.ts +13 -0
  154. package/fs/types/nibble_set/module.f.js +16 -0
  155. package/fs/types/object/module.f.d.ts +12 -8
  156. package/fs/types/object/module.f.js +9 -2
  157. package/fs/types/object/proof.f.d.ts +14 -0
  158. package/fs/types/object/proof.f.js +4 -0
  159. package/fs/types/ordered_map/proof.f.d.ts +1 -0
  160. package/fs/types/ordered_map/proof.f.js +39 -79
  161. package/fs/types/phantom/module.f.d.ts +22 -0
  162. package/fs/types/phantom/module.f.js +11 -0
  163. package/fs/types/prime_field/proof.f.d.ts +7 -0
  164. package/fs/types/prime_field/proof.f.js +63 -122
  165. package/fs/types/rtti/common/module.f.d.ts +4 -4
  166. package/fs/types/rtti/common/module.f.js +1 -1
  167. package/fs/types/rtti/module.f.d.ts +2 -3
  168. package/fs/types/rtti/parse/module.f.js +0 -1
  169. package/fs/types/rtti/ts/module.f.d.ts +26 -32
  170. package/fs/types/rtti/ts/module.f.js +2 -2
  171. package/fs/types/rtti/ts/proof.f.js +3 -3
  172. package/fs/types/rtti/validate/module.f.js +0 -1
  173. package/fs/types/sorted_list/module.f.d.ts +6 -0
  174. package/fs/types/sorted_list/module.f.js +11 -0
  175. package/fs/types/sorted_set/module.f.js +2 -8
  176. package/fs/types/ts/module.f.d.ts +1 -1
  177. package/fs/types/ts/module.f.js +3 -1
  178. package/fs/types/ts/proof.f.js +3 -2
  179. package/fs/website/proof.f.d.ts +1 -0
  180. package/fs/website/proof.f.js +8 -1
  181. package/package.json +3 -3
@@ -44,36 +44,26 @@ const create = (a) => {
44
44
  };
45
45
  export const terminal = -1;
46
46
  const toInit = () => () => [[], init];
47
+ const single = (c) => range(c)(() => () => [[c], unexpectedSymbol]);
48
+ const punctuation = "!\"%&'()*+,-./:;<=>?[]^`{|}~";
47
49
  export const init = create([
48
50
  codePointRange(one(terminal))(toInit),
49
51
  rangeSet(['\t', ' ', '\n', '\r'])(toInit),
50
- range('!')(() => () => [['!'], unexpectedSymbol]),
51
- range('"')(() => () => [['"'], unexpectedSymbol]),
52
52
  rangeSet(['$', '_', 'AZ', 'az'])(() => c => [[fromCharCode(c)], unexpectedSymbol]),
53
- range('%')(() => () => [['%'], unexpectedSymbol]),
54
- range('&')(() => () => [['&'], unexpectedSymbol]),
55
- range("'")(() => () => [["'"], unexpectedSymbol]),
56
- range('(')(() => () => [['('], unexpectedSymbol]),
57
- range(')')(() => () => [[')'], unexpectedSymbol]),
58
- range('*')(() => () => [['*'], unexpectedSymbol]),
59
- range('+')(() => () => [['+'], unexpectedSymbol]),
60
- range(',')(() => () => [[','], unexpectedSymbol]),
61
- range('-')(() => () => [['-'], unexpectedSymbol]),
62
- range('.')(() => () => [['.'], unexpectedSymbol]),
63
- range('/')(() => () => [['/'], unexpectedSymbol]),
64
53
  range('09')(() => a => [[fromCharCode(a)], unexpectedSymbol]),
65
- range(':')(() => () => [[':'], unexpectedSymbol]),
66
- range(';')(() => () => [[';'], unexpectedSymbol]),
67
- range('<')(() => () => [['<'], unexpectedSymbol]),
68
- range('=')(() => () => [['='], unexpectedSymbol]),
69
- range('>')(() => () => [['>'], unexpectedSymbol]),
70
- range('?')(() => () => [['?'], unexpectedSymbol]),
71
- range('[')(() => () => [['['], unexpectedSymbol]),
72
- range(']')(() => () => [[']'], unexpectedSymbol]),
73
- range('^')(() => () => [['^'], unexpectedSymbol]),
74
- range('`')(() => () => [['`'], unexpectedSymbol]),
75
- range('{')(() => () => [['{'], unexpectedSymbol]),
76
- range('|')(() => () => [['|'], unexpectedSymbol]),
77
- range('}')(() => () => [['}'], unexpectedSymbol]),
78
- range('~')(() => () => [['~'], unexpectedSymbol]),
54
+ ...[...punctuation].map(single),
79
55
  ])(undefined);
56
+ export const proof = {
57
+ // union throws when two distinct non-def handlers are merged for the same range;
58
+ // this path is unreachable through the public API (init has no overlapping ranges),
59
+ // so we exercise it here where the private union function is in scope.
60
+ throw: {
61
+ unionConflict: () => {
62
+ const a = _s => unexpectedSymbol;
63
+ const b = _s => unexpectedSymbol;
64
+ a(undefined);
65
+ b(undefined);
66
+ union(a)(b);
67
+ }
68
+ }
69
+ };
@@ -1,8 +1,16 @@
1
1
  export declare const proof: {
2
2
  a: () => void;
3
+ b: () => void;
4
+ c: () => void;
3
5
  fn: () => void;
4
6
  f1: () => void;
5
7
  f2: () => void;
6
8
  f3: () => void;
7
9
  f4: () => void;
10
+ chars: {
11
+ whitespace: () => void;
12
+ punctuation: () => void;
13
+ identifier_start: () => void;
14
+ digits: () => void;
15
+ };
8
16
  };
package/fs/fsc/proof.f.js CHANGED
@@ -1,6 +1,7 @@
1
- import { init } from "./module.f.js";
1
+ import { init, terminal } from "./module.f.js";
2
2
  import { one } from "../text/ascii/module.f.js";
3
3
  import { stringify } from "../json/module.f.js";
4
+ import { assertEq } from "../asserts/module.f.js";
4
5
  const s = stringify(i => i);
5
6
  const f = v => {
6
7
  const n = one(v);
@@ -18,6 +19,21 @@ export const proof = {
18
19
  throw x;
19
20
  }
20
21
  },
22
+ b: () => {
23
+ // exercises toInit: terminal returns empty output and loops back to init
24
+ const result = init(terminal);
25
+ if (result[0].length !== 0) {
26
+ throw result[0];
27
+ }
28
+ },
29
+ c: () => {
30
+ // exercises unexpectedSymbol: next state after a token returns an error message
31
+ const next = init(one('1'))[1];
32
+ const result = next(42);
33
+ if (result[0][0] !== 'unexpected symbol 42') {
34
+ throw result[0][0];
35
+ }
36
+ },
21
37
  fn: () => {
22
38
  const o = {
23
39
  ["hello world!"]: () => undefined
@@ -76,5 +92,35 @@ export const proof = {
76
92
  if (f.name !== "") {
77
93
  throw f.name;
78
94
  }
79
- }
95
+ },
96
+ chars: {
97
+ whitespace: () => {
98
+ for (const ch of ['\t', ' ', '\n', '\r']) {
99
+ const [tokens, next] = init(one(ch));
100
+ assertEq(tokens.length, 0);
101
+ assertEq(next, init);
102
+ }
103
+ },
104
+ punctuation: () => {
105
+ for (const ch of ['!', '"', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '^', '`', '{', '|', '}', '~']) {
106
+ const [tokens] = init(one(ch));
107
+ assertEq(tokens.length, 1);
108
+ assertEq(tokens[0], ch);
109
+ }
110
+ },
111
+ identifier_start: () => {
112
+ for (const ch of ['$', '_', 'A', 'Z', 'a', 'z']) {
113
+ const [tokens] = init(one(ch));
114
+ assertEq(tokens.length, 1);
115
+ assertEq(tokens[0], ch);
116
+ }
117
+ },
118
+ digits: () => {
119
+ for (const ch of ['0', '5', '9']) {
120
+ const [tokens] = init(one(ch));
121
+ assertEq(tokens.length, 1);
122
+ assertEq(tokens[0], ch);
123
+ }
124
+ },
125
+ },
80
126
  };
@@ -4,13 +4,12 @@
4
4
  * @module
5
5
  */
6
6
  import { type List } from '../types/list/module.f.ts';
7
+ import type { StringMap } from '../types/object/module.f.ts';
7
8
  import { type ByteSet } from '../types/byte_set/module.f.ts';
8
9
  import { type RangeMapArray } from '../types/range_map/module.f.ts';
9
10
  type Rule = readonly [string, ByteSet, string];
10
11
  export type Grammar = List<Rule>;
11
- type Dfa = {
12
- readonly [state in string]: RangeMapArray<string>;
13
- };
12
+ type Dfa = StringMap<string, RangeMapArray<string>>;
14
13
  export declare const toRange: (s: string) => ByteSet;
15
14
  export declare const toUnion: (s: string) => ByteSet;
16
15
  export declare const dfa: (grammar: Grammar) => Dfa;
@@ -51,5 +51,5 @@ const initialState = [''];
51
51
  const initialStateStringify = stringifyIdentity(initialState);
52
52
  export const dfa = grammar => addEntry(grammar)(initialState)({});
53
53
  const get = rangeMapGet(emptyStateStringify);
54
- const runOp = dfa => input => s => get(input)(dfa[s]);
54
+ const runOp = dfa => input => s => get(input)(dfa[s] ?? []);
55
55
  export const run = (dfa) => (input) => foldScan(runOp(dfa))(initialStateStringify)(input);
@@ -5,6 +5,7 @@
5
5
  * @module
6
6
  */
7
7
  import { type List } from '../types/list/module.f.ts';
8
+ import { type StringMap } from '../types/object/module.f.ts';
8
9
  import { type Vec } from '../types/bit_vec/module.f.ts';
9
10
  type Tag = string;
10
11
  type Element1 = readonly [Tag, ...Node[]];
@@ -16,9 +17,7 @@ type Element2 = readonly [Tag, Attributes, ...Node[]];
16
17
  * - `[tag, attributes, ...children]` for elements with attributes.
17
18
  */
18
19
  export type Element = Element1 | Element2;
19
- type Attributes = {
20
- readonly [k in string]: string;
21
- };
20
+ type Attributes = StringMap<string, string>;
22
21
  export type Node = Element | string;
23
22
  /**
24
23
  * Converts a FunctionalScript element into a list of HTML string chunks.
@@ -6,13 +6,14 @@
6
6
  */
7
7
  import { map, flatMap, flat, concat as listConcat } from "../types/list/module.f.js";
8
8
  import { concat, concat as stringConcat } from "../types/string/module.f.js";
9
+ import { definedEntries } from "../types/object/module.f.js";
9
10
  import { compose } from "../types/function/module.f.js";
10
11
  import { stringToList } from "../text/utf16/module.f.js";
11
12
  import { includes } from "../types/array/module.f.js";
12
13
  import {} from "../types/bit_vec/module.f.js";
13
14
  import { utf8 } from "../text/module.f.js";
15
+ import { quotationMark, ampersand, lessThanSign, greaterThanSign } from "../text/ascii/module.f.js";
14
16
  const { fromCharCode } = String;
15
- const { entries } = Object;
16
17
  /**
17
18
  * Void Elements
18
19
  *
@@ -47,10 +48,10 @@ const rawText = [
47
48
  */
48
49
  const escapeCharCode = (code) => {
49
50
  switch (code) {
50
- case 0x22: return '&quot;';
51
- case 0x26: return '&amp;';
52
- case 0x3C: return '&lt;';
53
- case 0x3E: return '&gt;';
51
+ case quotationMark: return '&quot;';
52
+ case ampersand: return '&amp;';
53
+ case lessThanSign: return '&lt;';
54
+ case greaterThanSign: return '&gt;';
54
55
  default: return fromCharCode(code);
55
56
  }
56
57
  };
@@ -62,7 +63,7 @@ const mr = map(raw);
62
63
  // Escape closing tags in raw text elements
63
64
  const rawMap = (n) => concat(mr(n)).replaceAll('</', '<\\/');
64
65
  const attribute = ([name, value]) => flat([[' ', name, '="'], escape(value), ['"']]);
65
- const attributes = compose(entries)(flatMap(attribute));
66
+ const attributes = (a) => flatMap(attribute)(definedEntries(a));
66
67
  const parseElement = (e) => {
67
68
  const [tag, item1, ...list] = e;
68
69
  return item1 === undefined ?
@@ -11,5 +11,6 @@ export declare const proof: {
11
11
  style: () => void;
12
12
  styleEsc: () => void;
13
13
  noRaw: () => void;
14
+ elemChild: () => void;
14
15
  };
15
16
  };
@@ -75,5 +75,12 @@ export const proof = {
75
75
  throw s;
76
76
  }
77
77
  },
78
+ elemChild: () => {
79
+ const x = ['script', ['span', 'ignored'], 'visible'];
80
+ const s = htmlToString(x);
81
+ if (s !== '<!DOCTYPE html><script>visible</script>') {
82
+ throw s;
83
+ }
84
+ },
78
85
  }
79
86
  };
@@ -517,5 +517,5 @@ const tokenizeWithPositionOp = (input, { state, metadata }) => {
517
517
  const scanTokenize = stateScan(tokenizeWithPositionOp);
518
518
  export const tokenize = input => path => {
519
519
  const scan = scanTokenize({ state: { kind: 'initial' }, metadata: { path, line: 1, column: 1 } });
520
- return flat(scan(flat([input, [null]])));
520
+ return flat(scan(flat([input /*satisfies List<CharCodeOrEof>*/, [null]])));
521
521
  };
@@ -177,6 +177,13 @@ export const proof = {
177
177
  throw result;
178
178
  }
179
179
  },
180
+ () => {
181
+ // terminal char after invalidNumber state (covers invalidNumberStateOp terminal branch)
182
+ const result = stringify(tokenizeString('00,'));
183
+ if (result !== '[{"kind":"error","message":"invalid number"},{"kind":","},{"kind":"eof"}]') {
184
+ throw result;
185
+ }
186
+ },
180
187
  () => {
181
188
  const result = stringify(tokenizeString('0abc,'));
182
189
  if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"id","value":"abc"},{"kind":","},{"kind":"eof"}]') {
@@ -23,12 +23,18 @@ export declare const primitive: import("../types/rtti/module.f.ts").Or<[null, im
23
23
  * core's `unknown`, the JSON `unknown` excludes `undefined`.
24
24
  */
25
25
  export declare const unknown: () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>, import("../types/rtti/module.f.ts").Type1<"array", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>];
26
- /** rtti schema matching a JSON object: `{ readonly [k: string]: Unknown }`. */
26
+ /**
27
+ * rtti schema matching a JSON object: `{ readonly [k: string]?: Unknown }`.
28
+ */
27
29
  export declare const object: import("../types/rtti/module.f.ts").Type1<"record", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>;
28
30
  /** rtti schema matching a JSON array: `readonly Unknown[]`. */
29
31
  export declare const array: import("../types/rtti/module.f.ts").Type1<"array", () => readonly ["or", import("../types/rtti/module.f.ts").Or<[null, import("../types/rtti/module.f.ts").Boolean, import("../types/rtti/module.f.ts").Number, import("../types/rtti/module.f.ts").String]>, import("../types/rtti/module.f.ts").Type1<"record", /*elided*/ any>, import("../types/rtti/module.f.ts").Type1<"array", /*elided*/ any>]>;
30
32
  export type Primitive = Ts<typeof primitive>;
31
- export type Unknown = Ts<typeof unknown>;
33
+ export type Unknown = Object | Array | Primitive;
34
+ export type Object = {
35
+ readonly [k in string]?: Unknown;
36
+ };
37
+ export type Array = readonly Unknown[];
32
38
  export declare const setProperty: (value: Unknown) => (path: List<string>) => (src: Unknown) => Unknown;
33
39
  export type Entry = ObjectEntry<Unknown>;
34
40
  type Entries = List<Entry>;
@@ -37,6 +43,7 @@ export declare const serialize: (mapEntries: MapEntries) => (value: Unknown) =>
37
43
  /**
38
44
  * The standard `JSON.stringify` rules determined by
39
45
  * https://262.ecma-international.org/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys
46
+ * https://tc39.es/ecma262/#sec-serializejsonproperty
40
47
  */
41
48
  export declare const stringify: (mapEntries: MapEntries) => (value: Unknown) => string;
42
49
  export declare const parse: (value: string) => Unknown;
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import { next, flat, map } from "../types/list/module.f.js";
12
12
  import { concat } from "../types/string/module.f.js";
13
- import { at } from "../types/object/module.f.js";
13
+ import { at, definedEntries } from "../types/object/module.f.js";
14
14
  import { compose, fn } from "../types/function/module.f.js";
15
15
  import { objectWrap, arrayWrap, stringSerialize, numberSerialize, nullSerialize, boolSerialize } from "./serializer/module.f.js";
16
16
  import { boolean as rttiBoolean, number as rttiNumber, string as rttiString, or, record, array as rttiArray } from "../types/rtti/module.f.js";
@@ -27,14 +27,15 @@ export const primitive = or(null, rttiBoolean, rttiNumber, rttiString);
27
27
  * core's `unknown`, the JSON `unknown` excludes `undefined`.
28
28
  */
29
29
  export const unknown = () => ['or', primitive, object, array];
30
- /** rtti schema matching a JSON object: `{ readonly [k: string]: Unknown }`. */
30
+ /**
31
+ * rtti schema matching a JSON object: `{ readonly [k: string]?: Unknown }`.
32
+ */
31
33
  export const object = record(unknown);
32
34
  /** rtti schema matching a JSON array: `readonly Unknown[]`. */
33
35
  export const array = rttiArray(unknown);
34
36
  // ── JSON utilities ────────────────────────────────────────────────────────────
35
- const { entries } = Object;
36
- export const setProperty = value => {
37
- const f = path => src => {
37
+ export const setProperty = (value) => {
38
+ const f = (path) => (src) => {
38
39
  const result = next(path);
39
40
  if (result === null) {
40
41
  return value;
@@ -53,12 +54,12 @@ export const serialize = sort => {
53
54
  f(v)
54
55
  ]);
55
56
  const mapPropertySerialize = map(propertySerialize);
56
- const objectSerialize = fn(entries)
57
+ const objectSerialize = fn((definedEntries))
57
58
  .map(sort)
58
59
  .map(mapPropertySerialize)
59
60
  .map(objectWrap)
60
61
  .result;
61
- const f = value => {
62
+ const f = (value) => {
62
63
  switch (typeof value) {
63
64
  case 'boolean': {
64
65
  return boolSerialize(value);
@@ -86,6 +87,7 @@ export const serialize = sort => {
86
87
  /**
87
88
  * The standard `JSON.stringify` rules determined by
88
89
  * https://262.ecma-international.org/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys
90
+ * https://tc39.es/ecma262/#sec-serializejsonproperty
89
91
  */
90
92
  export const stringify = sort => compose(serialize(sort))(concat);
91
93
  export const parse = JSON.parse;
@@ -68,10 +68,9 @@ const isValueToken = token => {
68
68
  };
69
69
  const parseValueOp = token => state => {
70
70
  switch (token.kind) {
71
+ // A value is required here (top level, after `[`+`,`, or after `:`),
72
+ // so `]` is never valid — strict JSON has no trailing commas.
71
73
  case ']':
72
- if (state.status === '[,') {
73
- return endArray(state);
74
- }
75
74
  return { status: 'error', message: 'unexpected token' };
76
75
  case '[': return startArray(state);
77
76
  case '{': return startObject(state);
@@ -131,9 +130,8 @@ const parseObjectNextOp = token => state => {
131
130
  return { status: 'error', message: 'unexpected token' };
132
131
  };
133
132
  const parseObjectCommaOp = token => state => {
134
- if (token.kind === '}') {
135
- return endObject(state);
136
- }
133
+ // After a `,` a member (string key) is required — `}` here would be a
134
+ // trailing comma, which strict JSON rejects.
137
135
  if (token.kind === 'string') {
138
136
  return pushKey(state)(token.value);
139
137
  }
@@ -119,30 +119,31 @@ export const proof = {
119
119
  if (result !== '["ok",{"a":{"b":{"c":["d"]}}}]') {
120
120
  throw result;
121
121
  }
122
- },
122
+ }
123
+ ],
124
+ invalid: [
123
125
  () => {
124
- const tokenList = tokenizeString('[1,]');
126
+ const tokenList = tokenizeString('');
125
127
  const obj = parse(tokenList);
126
128
  const result = stringify(obj);
127
- if (result !== '["ok",[1]]') {
129
+ if (result !== '["error","unexpected end"]') {
128
130
  throw result;
129
131
  }
130
132
  },
133
+ // Trailing commas are not valid JSON — strict parser rejects them.
131
134
  () => {
132
- const tokenList = tokenizeString('{"a":1,}');
135
+ const tokenList = tokenizeString('[1,]');
133
136
  const obj = parse(tokenList);
134
137
  const result = stringify(obj);
135
- if (result !== '["ok",{"a":1}]') {
138
+ if (result !== '["error","unexpected token"]') {
136
139
  throw result;
137
140
  }
138
- }
139
- ],
140
- invalid: [
141
+ },
141
142
  () => {
142
- const tokenList = tokenizeString('');
143
+ const tokenList = tokenizeString('{"a":1,}');
143
144
  const obj = parse(tokenList);
144
145
  const result = stringify(obj);
145
- if (result !== '["error","unexpected end"]') {
146
+ if (result !== '["error","unexpected token"]') {
146
147
  throw result;
147
148
  }
148
149
  },
@@ -290,6 +291,14 @@ export const proof = {
290
291
  throw result;
291
292
  }
292
293
  },
294
+ () => {
295
+ const tokenList = tokenizeString('{"a":1 "b":2}');
296
+ const obj = parse(tokenList);
297
+ const result = stringify(obj);
298
+ if (result !== '["error","unexpected token"]') {
299
+ throw result;
300
+ }
301
+ },
293
302
  () => {
294
303
  const tokenList = tokenizeString('[{]}');
295
304
  const obj = parse(tokenList);
@@ -1,7 +1,8 @@
1
1
  export declare const proof: {
2
- setProperty: () => void;
2
+ setProperty: (() => void)[];
3
3
  stringify: {
4
4
  sort: () => void;
5
5
  identity: () => void;
6
6
  }[];
7
+ undefined: () => void;
7
8
  };
@@ -1,12 +1,36 @@
1
1
  import { setProperty, stringify } from "./module.f.js";
2
2
  import { sort } from "../types/object/module.f.js";
3
3
  import { identity } from "../types/function/module.f.js";
4
+ import { assertEq } from "../asserts/module.f.js";
4
5
  export const proof = {
5
- setProperty: () => {
6
- if (setProperty("Hello")([])({}) !== "Hello") {
7
- throw 'error';
8
- }
9
- },
6
+ setProperty: [
7
+ () => {
8
+ if (setProperty("Hello")([])({}) !== "Hello") {
9
+ throw 'error';
10
+ }
11
+ },
12
+ () => {
13
+ // src === null: should treat as empty object
14
+ const x = stringify(sort)(setProperty("Hello")(['a'])(null));
15
+ if (x !== '{"a":"Hello"}') {
16
+ throw x;
17
+ }
18
+ },
19
+ () => {
20
+ // typeof src !== 'object': primitive src treated as empty object
21
+ const x = stringify(sort)(setProperty("Hello")(['a'])(42));
22
+ if (x !== '{"a":"Hello"}') {
23
+ throw x;
24
+ }
25
+ },
26
+ () => {
27
+ // src instanceof Array: array src treated as empty object
28
+ const x = stringify(sort)(setProperty("Hello")(['a'])([1, 2]));
29
+ if (x !== '{"a":"Hello"}') {
30
+ throw x;
31
+ }
32
+ },
33
+ ],
10
34
  stringify: [
11
35
  {
12
36
  sort: () => {
@@ -55,5 +79,8 @@ export const proof = {
55
79
  }
56
80
  }
57
81
  }
58
- ]
82
+ ],
83
+ undefined: () => {
84
+ assertEq(stringify(sort)({ x: undefined }), '{}');
85
+ }
59
86
  };
@@ -1,11 +1,14 @@
1
1
  import type { Ts } from '../../types/rtti/ts/module.f.ts';
2
2
  import type { Result } from '../../types/result/module.f.ts';
3
3
  import { type Unknown } from '../module.f.ts';
4
+ export declare const jsonrpc: "2.0";
4
5
  /** Request/response identifier: a string, a number, or `null`. */
5
6
  declare const id: import("../../types/rtti/module.f.ts").Or<[import("../../types/rtti/module.f.ts").String, import("../../types/rtti/module.f.ts").Number, null]>;
6
7
  /**
7
8
  * A request or notification envelope. `id` present → request (a response is
8
9
  * expected); `id` absent → notification (no response). `params` is optional.
10
+ *
11
+ * https://www.jsonrpc.org/specification#request_object
9
12
  */
10
13
  export declare const request: {
11
14
  readonly jsonrpc: "2.0";
@@ -42,6 +45,8 @@ export declare const errorResponse: {
42
45
  * runtime decoder and the static type, with no drift. rtti structs are open
43
46
  * (extra keys allowed), so "result XOR error" is not enforced at runtime; in
44
47
  * practice the dispatcher only ever constructs one or the other.
48
+ *
49
+ * https://www.jsonrpc.org/specification#response_object
45
50
  */
46
51
  export declare const response: import("../../types/rtti/module.f.ts").Or<[{
47
52
  readonly jsonrpc: "2.0";
@@ -10,17 +10,21 @@
10
10
  * `fs/effects/node`, and concrete method sets such as MCP (i665-mcp), which layer
11
11
  * on top of `dispatch`.
12
12
  *
13
+ * https://www.jsonrpc.org/specification
14
+ *
13
15
  * @module
14
16
  */
15
17
  import { number, string, or, option } from "../../types/rtti/module.f.js";
16
18
  import { validate } from "../../types/rtti/validate/module.f.js";
17
19
  import { unknown } from "../module.f.js";
18
- const jsonrpc = '2.0';
20
+ export const jsonrpc = '2.0';
19
21
  /** Request/response identifier: a string, a number, or `null`. */
20
22
  const id = or(string, number, null);
21
23
  /**
22
24
  * A request or notification envelope. `id` present → request (a response is
23
25
  * expected); `id` absent → notification (no response). `params` is optional.
26
+ *
27
+ * https://www.jsonrpc.org/specification#request_object
24
28
  */
25
29
  export const request = {
26
30
  jsonrpc,
@@ -42,6 +46,8 @@ export const errorResponse = { jsonrpc, error, id };
42
46
  * runtime decoder and the static type, with no drift. rtti structs are open
43
47
  * (extra keys allowed), so "result XOR error" is not enforced at runtime; in
44
48
  * practice the dispatcher only ever constructs one or the other.
49
+ *
50
+ * https://www.jsonrpc.org/specification#response_object
45
51
  */
46
52
  export const response = or(successResponse, errorResponse);
47
53
  /** Decodes an untrusted value as a JSON-RPC request / notification. */
@@ -54,7 +60,7 @@ export const invalidRequest = rpcError(-32600)('Invalid Request');
54
60
  export const methodNotFound = rpcError(-32601)('Method not found');
55
61
  export const invalidParams = rpcError(-32602)('Invalid params');
56
62
  export const internalError = rpcError(-32603)('Internal error');
57
- const errorResponseOf = (id) => (e) => ({ jsonrpc, error: e, id });
63
+ const errorResponseOf = (id) => (error) => ({ jsonrpc, error, id });
58
64
  /**
59
65
  * Dispatches an already-parsed JSON-RPC value against `handlers`.
60
66
  *
@@ -64,21 +70,20 @@ const errorResponseOf = (id) => (e) => ({ jsonrpc, error: e, id });
64
70
  * - otherwise the handler's `ok` / `error` result becomes a success / error response
65
71
  */
66
72
  export const dispatch = (handlers) => (value) => {
67
- const decoded = decodeRequest(value);
68
- if (decoded[0] === 'error') {
73
+ const [t, message] = decodeRequest(value);
74
+ if (t === 'error') {
69
75
  return errorResponseOf(null)(invalidRequest);
70
76
  }
71
- const message = decoded[1];
72
- const id = message.id;
77
+ const { id, method, params } = message;
73
78
  if (id === undefined) {
74
79
  return null;
75
80
  }
76
- const handler = handlers[message.method];
81
+ const handler = handlers[method];
77
82
  if (handler === undefined) {
78
83
  return errorResponseOf(id)(methodNotFound);
79
84
  }
80
- const result = handler(message.params);
81
- return result[0] === 'ok'
82
- ? { jsonrpc, result: result[1], id }
83
- : errorResponseOf(id)(result[1]);
85
+ const [t2, result] = handler(params);
86
+ return t2 === 'ok'
87
+ ? { jsonrpc, result, id }
88
+ : errorResponseOf(id)(result);
84
89
  };