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
@@ -4,32 +4,11 @@
4
4
  * @module
5
5
  */
6
6
  import { msb, lsb, length, vec, empty } from "../types/bit_vec/module.f.js";
7
+ import { baseN } from "../base_n/module.f.js";
7
8
  // 0123456789abcdef
8
9
  const m = '0123456789abcdefghjkmnpqrstvwxyz';
9
- const { popFront, concat } = msb;
10
+ const { concat } = msb;
10
11
  const popBack1 = lsb.popFront(1n);
11
- const popFront5 = popFront(5n);
12
- export const vec5xToCBase32 = (v) => {
13
- let result = '';
14
- while (true) {
15
- const len = length(v);
16
- if (len === 0n) {
17
- break;
18
- }
19
- const [r, rest] = popFront5(v);
20
- result += m[Number(r)];
21
- v = rest;
22
- }
23
- return result;
24
- };
25
- export const vecToCBase32 = (v) => {
26
- const len = length(v);
27
- const extraLen = 5n - len % 5n;
28
- const last = 1n << (extraLen - 1n);
29
- const padded = concat(v)(vec(extraLen)(last));
30
- return vec5xToCBase32(padded);
31
- };
32
- const vec5 = vec(5n);
33
12
  const normalizeChar = (c) => {
34
13
  const lower = c.toLowerCase();
35
14
  switch (lower) {
@@ -47,30 +26,30 @@ const normalizeChar = (c) => {
47
26
  }
48
27
  }
49
28
  };
50
- const toCrockfordIndex = (c) => m.indexOf(normalizeChar(c));
51
- export const cBase32ToVec5x = (s) => {
52
- let result = empty;
53
- for (const c of s) {
54
- const index = toCrockfordIndex(c);
55
- if (index < 0) {
56
- return null;
57
- }
58
- const v = vec5(BigInt(index));
59
- result = concat(result)(v);
60
- }
61
- return result;
29
+ const codec = baseN(5n, m, normalizeChar);
30
+ export const vec5xToCBase32 = codec.vecToString;
31
+ export const cBase32ToVec5x = codec.stringToVec;
32
+ export const vecToCBase32 = (v) => {
33
+ const len = length(v);
34
+ const extraLen = 5n - len % 5n;
35
+ const last = 1n << (extraLen - 1n);
36
+ const padded = concat(v)(vec(extraLen)(last));
37
+ return vec5xToCBase32(padded);
62
38
  };
63
39
  export const cBase32ToVec = (s) => {
64
40
  let v = cBase32ToVec5x(s);
65
- if (v === null || v === empty) {
41
+ if (v === null) {
66
42
  return null;
67
43
  }
68
- // TODO: replace with a function that computes trailing zeros.
69
- while (true) {
70
- const [last, v0] = popBack1(v);
71
- v = v0;
44
+ // Strip the padding: trailing zeros up to and including the sentinel `1` bit.
45
+ // A string with no sentinel — only zero symbols (`0`/`o`), or empty — exhausts
46
+ // to `empty` and is rejected as `null` rather than looping forever.
47
+ while (v !== empty) {
48
+ const [last, rest] = popBack1(v);
49
+ v = rest;
72
50
  if (last === 1n) {
73
51
  return v;
74
52
  }
75
53
  }
54
+ return null;
76
55
  };
@@ -3,4 +3,5 @@ export declare const proof: {
3
3
  roundtrip: () => void;
4
4
  unalignedBits: () => void;
5
5
  caseInsensitive: () => void;
6
+ unterminated: () => void;
6
7
  };
@@ -70,5 +70,20 @@ export const proof = {
70
70
  if (cBase32ToVec5x("u") !== null) {
71
71
  throw 'should error on invalid character';
72
72
  }
73
+ },
74
+ unterminated: () => {
75
+ // No sentinel `1` bit → invalid; must return null, not loop forever.
76
+ if (cBase32ToVec("") !== null) {
77
+ throw 'empty must be null';
78
+ }
79
+ if (cBase32ToVec("0") !== null) {
80
+ throw 'single zero symbol must be null';
81
+ }
82
+ if (cBase32ToVec("00") !== null) {
83
+ throw 'all-zero symbols must be null';
84
+ }
85
+ if (cBase32ToVec("o") !== null) {
86
+ throw 'o (maps to 0) must be null';
87
+ }
73
88
  }
74
89
  };
@@ -19,18 +19,18 @@ export declare const images: {
19
19
  readonly arm: "windows-11-arm";
20
20
  };
21
21
  };
22
- export declare const functionalscript: "0.29.1";
22
+ export declare const functionalscript: "0.30.0";
23
23
  export declare const bun = "1.3.14";
24
- export declare const deno = "2.8.2";
25
- export declare const playwright = "1.60.0";
24
+ export declare const deno = "2.8.3";
25
+ export declare const playwright = "1.61.0";
26
26
  export declare const node: {
27
27
  readonly default: "26.3.0";
28
- readonly node22: "22.22.2";
28
+ readonly node22: "22.22.3";
29
29
  readonly node24: "24.16.0";
30
30
  };
31
- export declare const wasmtime = "45.0.0";
31
+ export declare const wasmtime = "45.0.2";
32
32
  export declare const wasmer = "7.1.0";
33
- export declare const tsgo = "7.0.0-dev.20260606.1";
33
+ export declare const tsgo = "7.0.0-dev.20260615.1";
34
34
  export declare const actions: {
35
35
  readonly 'actions/checkout': "v6";
36
36
  readonly 'actions/setup-node': "v6";
@@ -24,25 +24,25 @@ export const images = {
24
24
  // published FunctionalScript release; do not tie it to package.json's current
25
25
  // in-repo version. A separate maintenance job advances this pin.
26
26
  // https://www.npmjs.com/package/functionalscript
27
- export const functionalscript = '0.29.1';
27
+ export const functionalscript = '0.30.0';
28
28
  // https://bun.sh/
29
29
  export const bun = '1.3.14';
30
30
  // https://deno.com/
31
- export const deno = '2.8.2';
31
+ export const deno = '2.8.3';
32
32
  // https://www.npmjs.com/package/playwright
33
- export const playwright = '1.60.0';
33
+ export const playwright = '1.61.0';
34
34
  // https://nodejs.org/en/download
35
35
  export const node = {
36
36
  default: '26.3.0',
37
- node22: '22.22.2',
37
+ node22: '22.22.3',
38
38
  node24: '24.16.0',
39
39
  };
40
40
  // https://github.com/bytecodealliance/wasmtime/releases
41
- export const wasmtime = '45.0.0';
41
+ export const wasmtime = '45.0.2';
42
42
  // https://github.com/wasmerio/wasmer/releases
43
43
  export const wasmer = '7.1.0';
44
44
  // https://www.npmjs.com/package/@typescript/native-preview?activeTab=versions
45
- export const tsgo = '7.0.0-dev.20260606.1';
45
+ export const tsgo = '7.0.0-dev.20260615.1';
46
46
  // GitHub Action versions used by CI step builders. The key is the action
47
47
  // `owner/name`; call sites compose the full ref as
48
48
  // `` `${name}@${actions[name]}` ``.
@@ -6,11 +6,11 @@
6
6
  */
7
7
  import { deno } from "../config/module.f.js";
8
8
  import { clean, install, test, uses } from "../common/module.f.js";
9
- const denoTest = 'deno test --allow-read --allow-env';
9
+ const denoTest = 'deno test --allow-read --allow-env --allow-sys';
10
10
  export const denoSteps = (version) => clean([
11
11
  install(uses('denoland/setup-deno', { 'deno-version': deno })),
12
12
  install({ run: `deno install -g -A npm:functionalscript@${version}` }),
13
- test({ run: 'deno install --frozen' }),
14
13
  test({ run: `deno run -A npm:functionalscript@${version} t` }),
14
+ test({ run: 'deno install --frozen' }),
15
15
  test({ run: `${denoTest} --coverage && deno coverage --include='.*module\\.f\\.ts'` }),
16
16
  ]);
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Continuous integration helper commands for repository automation tasks.
3
+ *
4
+ * @module
5
+ */
1
6
  import { type Effect } from '../effects/module.f.ts';
2
7
  import { type NodeOp } from '../effects/node/module.f.ts';
3
8
  import { type MetaStep, type Os } from './common/module.f.ts';
package/fs/ci/module.f.js CHANGED
@@ -3,9 +3,8 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import { utf8 } from "../text/module.f.js";
7
6
  import { pure } from "../effects/module.f.js";
8
- import { access, writeFile } from "../effects/node/module.f.js";
7
+ import { access, writeUtf8File } from "../effects/node/module.f.js";
9
8
  import { functionalscript, images } from "./config/module.f.js";
10
9
  import { architecture, os, toSteps, ubuntuArm } from "./common/module.f.js";
11
10
  import { rustPlatformSteps, rustWasmSteps } from "./rust/module.f.js";
@@ -47,7 +46,7 @@ export const ci = ({ nodeExtra }) => access('Cargo.toml').step(result => {
47
46
  },
48
47
  jobs,
49
48
  };
50
- return writeFile('.github/workflows/ci.yml', utf8(JSON.stringify(gha, null, ' ')))
49
+ return writeUtf8File('.github/workflows/ci.yml', JSON.stringify(gha, null, ' '))
51
50
  .step(() => pure(0));
52
51
  });
53
52
  export const main = () => ci({ nodeExtra: () => [] });
@@ -12,4 +12,5 @@ export declare const proof: {
12
12
  configuredPackageVersion: () => void;
13
13
  missingPackageJson: () => void;
14
14
  };
15
+ ubuntu: () => void;
15
16
  };
package/fs/ci/proof.f.js CHANGED
@@ -2,12 +2,13 @@ import { ci, main } from "./module.f.js";
2
2
  import { functionalscript } from "./config/module.f.js";
3
3
  import { utf8, utf8ToString } from "../text/module.f.js";
4
4
  import { empty as emptyVec, isVec } from "../types/bit_vec/module.f.js";
5
- import { test, parseGitHubAction } from "./common/module.f.js";
5
+ import { test, ubuntu, parseGitHubAction } from "./common/module.f.js";
6
6
  import { assert } from "../asserts/module.f.js";
7
7
  import { emptyState, virtual } from "../effects/node/virtual/module.f.js";
8
8
  import { parse as jsonParse } from "../json/module.f.js";
9
9
  import { unwrap } from "../types/result/module.f.js";
10
- const hasRun = (cmd) => (gha) => Object.values(gha.jobs).some(job => job.steps.some(step => step.run?.includes(cmd)));
10
+ import { definedValues } from "../types/object/module.f.js";
11
+ const hasRun = (cmd) => (gha) => definedValues(gha.jobs).some(job => job.steps.some(step => step.run?.includes(cmd)));
11
12
  const hasRunInJob = (jobId, cmd) => (gha) => gha.jobs[jobId]?.steps.some(step => step.run?.includes(cmd)) ?? false;
12
13
  const makeState = (rust, packageJson) => ({
13
14
  ...emptyState,
@@ -115,7 +116,7 @@ export const proof = {
115
116
  assert(hasRun(`deno install -g -A npm:functionalscript@${functionalscript}`)(gha), 'expected configured-version deno install cache');
116
117
  assert(hasRun('deno install --frozen')(gha), 'expected deno lock install');
117
118
  assert(hasRun(`deno run -A npm:functionalscript@${functionalscript} t`)(gha), 'expected configured-version deno install');
118
- assert(hasRun("deno test --allow-read --allow-env --coverage && deno coverage --include='.*module\\.f\\.ts'")(gha), 'expected limited-permission deno coverage');
119
+ assert(hasRun("deno test --allow-read --allow-env --allow-sys --coverage && deno coverage --include='.*module\\.f\\.ts'")(gha), 'expected limited-permission deno coverage');
119
120
  assert(hasRun(`bun install -g functionalscript@${functionalscript}`)(gha), 'expected configured-version bun cache');
120
121
  assert(hasRun('bun install --frozen-lockfile')(gha), 'expected bun lock install');
121
122
  assert(hasRun(`bunx functionalscript@${functionalscript} t`)(gha), 'expected configured-version bun install');
@@ -125,4 +126,9 @@ export const proof = {
125
126
  assert(hasRun(`npm install -g functionalscript@${functionalscript}`)(gha), 'expected configured-version install');
126
127
  },
127
128
  },
129
+ ubuntu: () => {
130
+ const job = ubuntu([test({ run: 'echo hi' })]);
131
+ assert(job['runs-on'] !== undefined, 'expected runs-on');
132
+ assert(job.steps.length > 0, 'expected steps');
133
+ },
128
134
  };
@@ -1,9 +1,11 @@
1
1
  import { type NodeOp, type NodeProgramOptions, type Write } from '../effects/node/module.f.ts';
2
2
  import { type Effect } from '../effects/module.f.ts';
3
+ type Handler<O extends NodeOp> = (options: NodeProgramOptions) => Effect<O, number>;
3
4
  export type Command<O extends NodeOp> = {
4
5
  readonly names: readonly string[];
5
6
  readonly description: string;
6
- readonly handler: (options: NodeProgramOptions) => Effect<O, number>;
7
+ readonly handler: Handler<O> | Commands<O>;
7
8
  };
8
9
  export type Commands<O extends NodeOp> = readonly Command<O>[];
9
10
  export declare const dispatch: <O extends NodeOp>(commands: Commands<O>) => (options: NodeProgramOptions) => Effect<O | Write, number>;
11
+ export {};
@@ -1,24 +1,34 @@
1
1
  import { errorExit, log } from "../effects/node/module.f.js";
2
2
  import { pure } from "../effects/module.f.js";
3
+ import { at, fromEntries } from "../types/object/module.f.js";
3
4
  const helpMeta = { names: ['help', 'h', '?'], description: 'Print this help message' };
4
5
  export const dispatch = (commands) => (options) => {
5
6
  const [cmd, ...rest] = options.args;
6
7
  const rows = [...commands, helpMeta];
7
- const nameCol = rows.map(c => c.names.join(', '));
8
- const width = Math.max(...nameCol.map(s => s.length));
9
- const helpText = ['Available commands:', ...rows.map((c, i) => ` ${nameCol[i].padEnd(width)} ${c.description}`)].join('\n');
10
- const helpCommand = {
11
- ...helpMeta,
12
- handler: () => log(helpText).step(() => pure(0)),
13
- };
14
- const allCommands = [...commands, helpCommand];
15
- const map = Object.fromEntries(allCommands.flatMap(c => c.names.map(n => [n, c])));
8
+ const nameCol = rows.map(({ names }) => names.join(', '));
9
+ const width = Math.max(...nameCol.map(({ length }) => length));
10
+ const helpText = [
11
+ 'Available commands:',
12
+ ...rows.map(({ description }, i) => ` ${nameCol[i].padEnd(width)} ${description}`)
13
+ ].join('\n');
14
+ const map = fromEntries(commands.flatMap(c => c.names.map(n => [n, c])));
16
15
  if (cmd === undefined) {
17
16
  return errorExit(`Error: command is required.\n${helpText}`);
18
17
  }
19
- const found = map[cmd];
20
- if (found === undefined) {
18
+ if (helpMeta.names.includes(cmd)) {
19
+ const [target] = rest;
20
+ if (target !== undefined) {
21
+ const targetCmd = at(target)(map);
22
+ if (targetCmd !== null && typeof targetCmd.handler !== 'function') {
23
+ return dispatch(targetCmd.handler)({ ...options, args: ['help'] });
24
+ }
25
+ }
26
+ return log(helpText).step(() => pure(0));
27
+ }
28
+ const found = at(cmd)(map);
29
+ if (found === null) {
21
30
  return errorExit(`Error: unknown command "${cmd}".\n${helpText}`);
22
31
  }
23
- return found.handler({ ...options, args: rest });
32
+ const { handler } = found;
33
+ return (typeof handler === 'function' ? handler : dispatch(handler))({ ...options, args: rest });
24
34
  };
@@ -6,4 +6,9 @@ export declare const proof: {
6
6
  help: () => void;
7
7
  errorIncludesAvailable: () => void;
8
8
  handlerReceivesRemainingArgs: () => void;
9
+ nestedCommands: () => void;
10
+ nestedHelp: () => void;
11
+ prototypeNameIsUnknownCommand: () => void;
12
+ helpPrototypeSafe: () => void;
13
+ helpWithTarget: () => void;
9
14
  };
package/fs/cli/proof.f.js CHANGED
@@ -5,6 +5,7 @@ import { dispatch } from "./module.f.js";
5
5
  const makeOptions = (args) => ({
6
6
  args,
7
7
  env: {},
8
+ home: '.',
8
9
  std: { stdout: { isTTY: false }, stderr: { isTTY: false } },
9
10
  testContext: { test: async () => { } },
10
11
  bunTestContext: { test: async () => { } },
@@ -83,4 +84,79 @@ export const proof = {
83
84
  throw ['unexpected args', captured];
84
85
  }
85
86
  },
87
+ nestedCommands: () => {
88
+ const inner = [{
89
+ names: ['ping'],
90
+ description: 'Inner ping',
91
+ handler: () => pure(42),
92
+ }];
93
+ const outer = [{
94
+ names: ['sub'],
95
+ description: 'Subcommand group',
96
+ handler: inner,
97
+ }];
98
+ const [, code] = run(outer)(['sub', 'ping']);
99
+ if (code !== 42) {
100
+ throw ['expected 42', code];
101
+ }
102
+ },
103
+ nestedHelp: () => {
104
+ const inner = [{
105
+ names: ['ping'],
106
+ description: 'Inner ping',
107
+ handler: () => pure(0),
108
+ }];
109
+ const outer = [{
110
+ names: ['sub'],
111
+ description: 'Subcommand group',
112
+ handler: inner,
113
+ }];
114
+ const [state, code] = run(outer)(['sub', 'help']);
115
+ if (code !== 0) {
116
+ throw ['expected exit 0', code];
117
+ }
118
+ if (!state.stdout.includes('ping')) {
119
+ throw 'expected inner command in help';
120
+ }
121
+ },
122
+ prototypeNameIsUnknownCommand: () => {
123
+ const [state, code] = run(echoCommands)(['toString']);
124
+ if (code !== 1) {
125
+ throw ['expected exit 1 for prototype-name command', code];
126
+ }
127
+ if (!state.stderr.includes('unknown command')) {
128
+ throw 'expected unknown-command error in stderr';
129
+ }
130
+ },
131
+ helpPrototypeSafe: () => {
132
+ const [state, code] = run(echoCommands)(['help', 'toString']);
133
+ if (code !== 0) {
134
+ throw ['expected exit 0, not a throw', code];
135
+ }
136
+ if (!state.stdout.includes('echo')) {
137
+ throw 'expected top-level help for unknown target';
138
+ }
139
+ },
140
+ helpWithTarget: () => {
141
+ const inner = [{
142
+ names: ['ping'],
143
+ description: 'Inner ping',
144
+ handler: () => pure(0),
145
+ }];
146
+ const outer = [{
147
+ names: ['sub'],
148
+ description: 'Subcommand group',
149
+ handler: inner,
150
+ }];
151
+ const [state, code] = run(outer)(['help', 'sub']);
152
+ if (code !== 0) {
153
+ throw ['expected exit 0', code];
154
+ }
155
+ if (!state.stdout.includes('ping')) {
156
+ throw 'expected inner command in help';
157
+ }
158
+ if (state.stdout.includes('Subcommand group')) {
159
+ throw 'expected inner help, not outer';
160
+ }
161
+ },
86
162
  };
@@ -3,4 +3,5 @@ export declare const proof: {
3
3
  sha256: () => void;
4
4
  sha384: () => void;
5
5
  sha512: () => void;
6
+ longKey: () => void;
6
7
  };
@@ -1,3 +1,4 @@
1
+ import { assertEq } from "../../asserts/module.f.js";
1
2
  import { utf8 } from "../../text/module.f.js";
2
3
  import { uint, vec } from "../../types/bit_vec/module.f.js";
3
4
  import { sha256, sha384, sha512 } from "../sha2/module.f.js";
@@ -28,5 +29,12 @@ export const proof = {
28
29
  if (r !== vec(512n)(0xb42af09057bac1e2d41708e48a902e09b5ff7f12ab428a4fe86653c73dd248fb82f948a549f7b791a5b41915ee4d1ec3935357e4e2317250d0372afa2ebeeb3an)) {
29
30
  throw r;
30
31
  }
32
+ },
33
+ // RFC 4231 Test Case 6: key (131 bytes of 0xaa = 1048 bits) exceeds SHA-256 block size (512 bits),
34
+ // so the key is first compressed via the hash function before use.
35
+ longKey: () => {
36
+ const key = vec(1048n)(BigInt('0x' + 'aa'.repeat(131)));
37
+ const r = hmac(sha256)(key)(utf8('Test Using Larger Than Block-Size Key - Hash Key First'));
38
+ assertEq(uint(r), 0x60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54n);
31
39
  }
32
40
  };
@@ -4,4 +4,5 @@ export declare const proof: {
4
4
  poker: () => {
5
5
  [k: string]: () => void;
6
6
  };
7
+ nullPointOps: () => void;
7
8
  };
@@ -1,3 +1,4 @@
1
+ import { assert } from "../../asserts/module.f.js";
1
2
  import { prime_field } from "../../types/prime_field/module.f.js";
2
3
  import { curve, secp256k1, secp192r1, secp256r1, eq, secp384r1, secp521r1 } from "./module.f.js";
3
4
  const poker = (param) => () => {
@@ -131,5 +132,14 @@ export const proof = {
131
132
  //secp256r1,
132
133
  };
133
134
  return Object.fromEntries(Object.entries(c).map(([k, v]) => [k, poker(v)]));
135
+ },
136
+ // Cover null (point at infinity) branches in neg, add, and eq.
137
+ nullPointOps: () => {
138
+ const c = secp256k1;
139
+ assert(c.neg(null) === null);
140
+ assert(eq(null)(null));
141
+ assert(!eq(null)(c.g));
142
+ assert(!eq(c.g)(null));
143
+ assert(eq(c.add(c.g)(null))(c.g));
134
144
  }
135
145
  };
@@ -1,10 +1,7 @@
1
- import { bitLength, divUp, roundUp } from "../../types/bigint/module.f.js";
1
+ import { bitLength, divUp8, roundUp8 } from "../../types/bigint/module.f.js";
2
2
  import { empty, length, msb, repeat, unpack, vec, vec8 } from "../../types/bit_vec/module.f.js";
3
3
  import { hmac } from "../hmac/module.f.js";
4
4
  import { computeSync } from "../sha2/module.f.js";
5
- // qlen to rlen
6
- const roundUp8 = roundUp(8n);
7
- const divUp8 = divUp(8n);
8
5
  /**
9
6
  * Builds RFC6979 helper conversions for a subgroup order.
10
7
  *
@@ -4,14 +4,13 @@
4
4
  * @module
5
5
  */
6
6
  import { type Access, type All, type Env, type Import, type Readdir } from '../effects/node/module.f.ts';
7
+ import type { StringMap } from '../types/object/module.f.ts';
7
8
  import { type Effect } from '../effects/module.f.ts';
8
9
  export type Module = {
9
10
  readonly proof?: unknown;
10
11
  readonly [k: string]: unknown;
11
12
  };
12
- export type ModuleMap = {
13
- readonly [k in string]: Module;
14
- };
13
+ export type ModuleMap = StringMap<string, Module>;
15
14
  /**
16
15
  * Returns `true` if the file should be loaded for proof discovery.
17
16
  *
@@ -41,3 +40,6 @@ export type LoadModuleOperations = Access | Import | All | Readdir;
41
40
  * deterministic regardless of filesystem traversal order.
42
41
  */
43
42
  export declare const loadModuleMap: (env: Env) => Effect<LoadModuleOperations, ModuleMap>;
43
+ export declare const proof: {
44
+ isSourceFile: () => void;
45
+ };
@@ -7,7 +7,8 @@ import { all, import_, readdir } from "../effects/node/module.f.js";
7
7
  import { cmp as strCmp } from "../types/string/module.f.js";
8
8
  import { unwrap } from "../types/result/module.f.js";
9
9
  import { pure } from "../effects/module.f.js";
10
- import { relativize, toPosix } from "../path/module.f.js";
10
+ import { join, relativize, toPosix } from "../path/module.f.js";
11
+ import { assert } from "../asserts/module.f.js";
11
12
  /**
12
13
  * Returns `true` if the file should be loaded for proof discovery.
13
14
  *
@@ -32,7 +33,7 @@ const allFiles = (s, predicate) => {
32
33
  if (name.startsWith('.')) {
33
34
  continue;
34
35
  }
35
- const file = `${p}/${name}`;
36
+ const file = join(p, name);
36
37
  if (!i.isFile) {
37
38
  if (name === 'node_modules') {
38
39
  continue;
@@ -80,3 +81,13 @@ export const loadModuleMap = (env) => {
80
81
  .map(([k, v]) => [relativize(prefix, k), v])
81
82
  .toSorted(([a], [b]) => strCmp(a)(b)))));
82
83
  };
84
+ export const proof = {
85
+ isSourceFile: () => {
86
+ assert(isSourceFile('module.js'));
87
+ assert(isSourceFile('module.ts'));
88
+ assert(isSourceFile('module.mts'));
89
+ assert(isSourceFile('module.mjs'));
90
+ assert(!isSourceFile('readme.md'));
91
+ assert(!isSourceFile('module.json'));
92
+ },
93
+ };
@@ -1,5 +1,6 @@
1
1
  export declare const proof: {
2
2
  parseMetadata: () => void;
3
3
  malformedJson: () => void;
4
+ validationError: () => void;
4
5
  validatePreservesOriginalObject: () => void;
5
6
  };
@@ -12,6 +12,11 @@ export const proof = {
12
12
  const result = validatePackageJsonText('{');
13
13
  assert(result[0] === 'error', result);
14
14
  },
15
+ validationError: () => {
16
+ // valid JSON but `name` is a number, not a string — validation should fail
17
+ const result = validatePackageJsonText('{"name": 42}');
18
+ assert(result[0] === 'error', result);
19
+ },
15
20
  validatePreservesOriginalObject: () => {
16
21
  const object = { name: 'x', version: '1.0.0', private: true };
17
22
  const metadata = unwrap(validatePackageJson(object));
@@ -1,4 +1,5 @@
1
1
  export declare const proof: {
2
+ shouldLoad: () => void;
2
3
  shouldPass: () => {
3
4
  then: () => undefined;
4
5
  };
package/fs/dev/proof.f.js CHANGED
@@ -1,5 +1,16 @@
1
- import { todo } from "../asserts/module.f.js";
1
+ import { assert, todo } from "../asserts/module.f.js";
2
+ import { shouldLoad } from "./module.f.js";
2
3
  export const proof = {
4
+ shouldLoad: () => {
5
+ assert(shouldLoad('foo.f.ts'));
6
+ assert(shouldLoad('bar.f.js'));
7
+ assert(shouldLoad('proof.ts'));
8
+ assert(shouldLoad('proof.js'));
9
+ assert(shouldLoad('proof.mts'));
10
+ assert(shouldLoad('proof.mjs'));
11
+ assert(!shouldLoad('module.ts'));
12
+ assert(!shouldLoad('readme.md'));
13
+ },
3
14
  shouldPass: () => ({
4
15
  then: () => undefined
5
16
  }),
@@ -9,7 +9,7 @@ export type AstConst = Primitive | AstModuleRef | AstArray | AstObject;
9
9
  export type AstModuleRef = ['aref' | 'cref', number];
10
10
  export type AstArray = ['array', readonly AstConst[]];
11
11
  export type AstObject = {
12
- readonly [k in string]: AstConst;
12
+ readonly [k in string]?: AstConst;
13
13
  };
14
14
  export type AstBody = readonly AstConst[];
15
15
  export declare const run: (body: AstBody) => (args: Array) => Unknown;
@@ -4,4 +4,9 @@ export declare const proof: {
4
4
  testAref: () => void;
5
5
  testArray: () => void;
6
6
  testObj: () => void;
7
+ testBool: () => void;
8
+ testStr: () => void;
9
+ testNull: () => void;
10
+ testBigint: () => void;
11
+ testUndefined: () => void;
7
12
  };
@@ -1,6 +1,7 @@
1
1
  import { sort } from "../../types/object/module.f.js";
2
2
  import { run } from "./module.f.js";
3
3
  import { stringifyAsTree } from "../serializer/module.f.js";
4
+ import { assertEq } from "../../asserts/module.f.js";
4
5
  export const proof = {
5
6
  test: () => {
6
7
  const djs = run([1])([]);
@@ -37,4 +38,20 @@ export const proof = {
37
38
  throw result;
38
39
  }
39
40
  },
41
+ testBool: () => {
42
+ assertEq(stringifyAsTree(sort)(run([true])([])), 'true');
43
+ assertEq(stringifyAsTree(sort)(run([false])([])), 'false');
44
+ },
45
+ testStr: () => {
46
+ assertEq(stringifyAsTree(sort)(run(['hello'])([])), '"hello"');
47
+ },
48
+ testNull: () => {
49
+ assertEq(stringifyAsTree(sort)(run([null])([])), 'null');
50
+ },
51
+ testBigint: () => {
52
+ assertEq(stringifyAsTree(sort)(run([42n])([])), '42n');
53
+ },
54
+ testUndefined: () => {
55
+ assertEq(stringifyAsTree(sort)(run([undefined])([])), 'undefined');
56
+ },
40
57
  };
@@ -7,7 +7,7 @@ import type { Primitive as JsonPrimitive } from '../json/module.f.ts';
7
7
  import { type Effect } from '../effects/module.f.ts';
8
8
  import { type WriteFile, type ReadFile, type Write } from '../effects/node/module.f.ts';
9
9
  export type Object = {
10
- readonly [k in string]: Unknown;
10
+ readonly [k in string]?: Unknown;
11
11
  };
12
12
  export type Array = readonly Unknown[];
13
13
  export type Primitive = JsonPrimitive | bigint | undefined;