functionalscript 0.24.0 → 0.26.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.
Files changed (62) hide show
  1. package/fs/asserts/proof.f.d.ts +8 -0
  2. package/fs/asserts/proof.f.js +51 -0
  3. package/fs/bnf/data/proof.f.js +7 -17
  4. package/fs/bnf/module.f.d.ts +10 -0
  5. package/fs/bnf/module.f.js +10 -0
  6. package/fs/bnf/testlib.f.js +4 -9
  7. package/fs/cas/module.f.d.ts +2 -10
  8. package/fs/cas/module.f.js +48 -52
  9. package/fs/cas/proof.f.js +21 -12
  10. package/fs/ci/common/module.f.d.ts +2 -0
  11. package/fs/ci/common/module.f.js +4 -1
  12. package/fs/ci/config/module.f.d.ts +2 -2
  13. package/fs/ci/config/module.f.js +2 -2
  14. package/fs/ci/module.f.d.ts +2 -4
  15. package/fs/ci/module.f.js +11 -9
  16. package/fs/ci/node/module.f.js +4 -2
  17. package/fs/ci/proof.f.js +8 -5
  18. package/fs/cli/module.f.d.ts +9 -0
  19. package/fs/cli/module.f.js +24 -0
  20. package/fs/cli/proof.f.d.ts +9 -0
  21. package/fs/cli/proof.f.js +86 -0
  22. package/fs/crypto/sha2/module.f.js +32 -36
  23. package/fs/crypto/vdf/module.f.d.ts +21 -0
  24. package/fs/crypto/vdf/module.f.js +57 -0
  25. package/fs/crypto/vdf/proof.f.d.ts +32 -0
  26. package/fs/crypto/vdf/proof.f.js +135 -0
  27. package/fs/dev/index/module.f.d.ts +1 -8
  28. package/fs/dev/index/module.f.js +1 -1
  29. package/fs/effects/node/module.f.d.ts +1 -1
  30. package/fs/emergent_testing/module.f.d.ts +1 -1
  31. package/fs/emergent_testing/module.f.js +2 -2
  32. package/fs/emergent_testing/proof.f.js +1 -1
  33. package/fs/fjs/module.f.js +34 -24
  34. package/fs/json/module.f.d.ts +25 -9
  35. package/fs/json/module.f.js +25 -3
  36. package/fs/json/rpc/module.f.d.ts +109 -0
  37. package/fs/json/rpc/module.f.js +84 -0
  38. package/fs/json/rpc/proof.f.d.ts +35 -0
  39. package/fs/json/rpc/proof.f.js +68 -0
  40. package/fs/json/schema/module.f.d.ts +76 -0
  41. package/fs/json/schema/module.f.js +112 -0
  42. package/fs/json/schema/proof.f.d.ts +33 -0
  43. package/fs/json/schema/proof.f.js +71 -0
  44. package/fs/mcp/module.f.d.ts +88 -0
  45. package/fs/mcp/module.f.js +69 -0
  46. package/fs/sul/level/literal/proof.f.d.ts +1 -0
  47. package/fs/sul/level/literal/proof.f.js +6 -0
  48. package/fs/types/array/module.f.d.ts +7 -0
  49. package/fs/types/array/module.f.js +7 -0
  50. package/fs/types/prime_field/module.f.d.ts +8 -0
  51. package/fs/types/prime_field/module.f.js +37 -5
  52. package/fs/types/prime_field/proof.f.d.ts +3 -0
  53. package/fs/types/prime_field/proof.f.js +27 -2
  54. package/fs/types/rtti/parse/module.f.d.ts +28 -0
  55. package/fs/types/rtti/parse/module.f.js +35 -5
  56. package/fs/types/rtti/ts/module.f.d.ts +46 -3
  57. package/fs/types/rtti/validate/module.f.js +5 -0
  58. package/fs/website/module.f.d.ts +1 -2
  59. package/fs/website/module.f.js +1 -1
  60. package/fs/website/proof.f.d.ts +1 -1
  61. package/fs/website/proof.f.js +3 -3
  62. package/package.json +4 -4
@@ -0,0 +1,8 @@
1
+ export declare const proof: {
2
+ assertPassesOnTrue: () => void;
3
+ assertThrowsDefaultMsg: () => void;
4
+ assertThrowsCustomMsg: () => void;
5
+ assertEqPassesOnEqual: () => void;
6
+ assertEqThrowsOnUnequal: () => void;
7
+ todoThrows: () => void;
8
+ };
@@ -0,0 +1,51 @@
1
+ import { assert, assertEq, todo } from "./module.f.js";
2
+ const throws = (f, expected) => {
3
+ let caught = false;
4
+ try {
5
+ f();
6
+ }
7
+ catch (e) {
8
+ caught = true;
9
+ if (e !== expected) {
10
+ throw ['unexpected throw value', e];
11
+ }
12
+ }
13
+ if (!caught) {
14
+ throw 'expected function to throw but it did not';
15
+ }
16
+ };
17
+ export const proof = {
18
+ assertPassesOnTrue: () => {
19
+ assert(true);
20
+ assert(true, 'with message');
21
+ },
22
+ assertThrowsDefaultMsg: () => {
23
+ throws(() => assert(false), 'assertion failed');
24
+ },
25
+ assertThrowsCustomMsg: () => {
26
+ throws(() => assert(false, 'oops'), 'oops');
27
+ },
28
+ assertEqPassesOnEqual: () => {
29
+ assertEq(1, 1);
30
+ assertEq('x', 'x');
31
+ },
32
+ assertEqThrowsOnUnequal: () => {
33
+ let caught = false;
34
+ try {
35
+ assertEq(1, 2);
36
+ }
37
+ catch (e) {
38
+ caught = true;
39
+ const arr = e;
40
+ if (arr[0] !== 1 || arr[1] !== 2) {
41
+ throw ['wrong throw value', e];
42
+ }
43
+ }
44
+ if (!caught) {
45
+ throw 'expected assertEq to throw';
46
+ }
47
+ },
48
+ todoThrows: () => {
49
+ throws(() => todo(), 'not implemented');
50
+ },
51
+ };
@@ -3,7 +3,7 @@ import { stringToCodePointList } from "../../text/utf16/module.f.js";
3
3
  import { identity } from "../../types/function/module.f.js";
4
4
  import { map, toArray } from "../../types/list/module.f.js";
5
5
  import { sort } from "../../types/object/module.f.js";
6
- import { join0Plus, oneEncode, option, range, rangeDecode, repeat0Plus, set } from "../module.f.js";
6
+ import { commaJoin0Plus, oneEncode, option, range, rangeDecode, repeat0Plus, set } from "../module.f.js";
7
7
  import { classic, deterministic } from "../testlib.f.js";
8
8
  import { dispatchMap, parser, parserRuleSet, toData, createEmptyTagMap, descentParser } from "./module.f.js";
9
9
  const mapCodePoint = (cp) => [cp, undefined];
@@ -437,15 +437,10 @@ export const proof = {
437
437
  },
438
438
  () => {
439
439
  const ws = repeat0Plus(set(' \n\r\t'));
440
- const commaJoin0Plus = ([open, close], a) => [
441
- open,
442
- ws,
443
- join0Plus([a, ws], [',', ws]),
444
- close,
445
- ];
440
+ const cj = commaJoin0Plus(ws);
446
441
  const value = () => ({
447
- object: commaJoin0Plus('{}', 'a'),
448
- array: commaJoin0Plus('[]', 'a')
442
+ object: cj('{}', 'a'),
443
+ array: cj('[]', 'a')
449
444
  });
450
445
  value.name; //bun will fail if no usage of name found
451
446
  const m = parser(value);
@@ -642,15 +637,10 @@ export const proof = {
642
637
  },
643
638
  () => {
644
639
  const ws = repeat0Plus(set(' \n\r\t'));
645
- const commaJoin0Plus = ([open, close], a) => [
646
- open,
647
- ws,
648
- join0Plus([a, ws], [',', ws]),
649
- close,
650
- ];
640
+ const cj = commaJoin0Plus(ws);
651
641
  const value = () => ({
652
- object: commaJoin0Plus('{}', 'a'),
653
- array: commaJoin0Plus('[]', 'a')
642
+ object: cj('{}', 'a'),
643
+ array: cj('[]', 'a')
654
644
  });
655
645
  value.name; //bun will fail if no usage of name found
656
646
  const m = descentParser(value);
@@ -131,6 +131,16 @@ export type Join0Plus<T, S> = Option<readonly [T, Repeat0Plus<readonly [S, T]>]>
131
131
  * Repeats `some` zero or more times separated by `separator`.
132
132
  */
133
133
  export declare const join0Plus: <T extends Rule, S extends Rule>(some: T, separator: S) => Rule;
134
+ /**
135
+ * A delimited, comma-separated list with whitespace between tokens:
136
+ * `open ws (item ws (',' ws item ws)*)? close`.
137
+ *
138
+ * `ws` is the per-grammar whitespace rule and is curried so callers can
139
+ * partially apply it once (`const cj = commaJoin0Plus(ws)`) before reusing
140
+ * the same combinator at multiple bracket pairs. The two-character string
141
+ * supplies the bracket pair via destructuring (e.g. `'[]'`, `'{}'`).
142
+ */
143
+ export declare const commaJoin0Plus: (ws: Rule) => ([open, close]: string, item: Rule) => Sequence;
134
144
  export type Repeat<T> = readonly T[];
135
145
  /**
136
146
  * Repeats a rule a fixed number of times.
@@ -151,6 +151,16 @@ export const join1Plus = (some, separator) => [some, repeat0Plus([separator, som
151
151
  * Repeats `some` zero or more times separated by `separator`.
152
152
  */
153
153
  export const join0Plus = (some, separator) => option(join1Plus(some, separator));
154
+ /**
155
+ * A delimited, comma-separated list with whitespace between tokens:
156
+ * `open ws (item ws (',' ws item ws)*)? close`.
157
+ *
158
+ * `ws` is the per-grammar whitespace rule and is curried so callers can
159
+ * partially apply it once (`const cj = commaJoin0Plus(ws)`) before reusing
160
+ * the same combinator at multiple bracket pairs. The two-character string
161
+ * supplies the bracket pair via destructuring (e.g. `'[]'`, `'{}'`).
162
+ */
163
+ export const commaJoin0Plus = (ws) => ([open, close], item) => [open, ws, join0Plus([item, ws], [',', ws]), close];
154
164
  /**
155
165
  * Repeats a rule a fixed number of times.
156
166
  */
@@ -1,4 +1,4 @@
1
- import { join0Plus, max, none, option, range, remove, repeat, repeat0Plus, set } from "./module.f.js";
1
+ import { commaJoin0Plus, max, none, option, range, remove, repeat, repeat0Plus, set } from "./module.f.js";
2
2
  export const classic = () => {
3
3
  // https://www.json.org/json-en.html
4
4
  const json = () => [element];
@@ -123,15 +123,10 @@ export const deterministic = () => {
123
123
  option([set('Ee'), option(set('+-')), digits])
124
124
  ];
125
125
  const ws = repeat0Plus(set(' \n\r\t'));
126
- const commaJoin0Plus = ([open, close], a) => [
127
- open,
128
- ws,
129
- join0Plus([a, ws], [',', ws]),
130
- close,
131
- ];
126
+ const cj = commaJoin0Plus(ws);
132
127
  const value = () => ({
133
- array: commaJoin0Plus('[]', value),
134
- object: commaJoin0Plus('{}', [string, ws, ':', ws, value]),
128
+ array: cj('[]', value),
129
+ object: cj('{}', [string, ws, ':', ws, value]),
135
130
  string,
136
131
  number,
137
132
  true: 'true',
@@ -6,7 +6,7 @@
6
6
  import { type Sha2 } from '../crypto/sha2/module.f.ts';
7
7
  import type { Vec } from '../types/bit_vec/module.f.ts';
8
8
  import { type Effect, type Operation } from '../effects/module.f.ts';
9
- import { type Fs, type NodeOp } from '../effects/node/module.f.ts';
9
+ import { type Fs, type NodeOp, type NodeProgramOptions } from '../effects/node/module.f.ts';
10
10
  export type KvStore<O extends Operation> = {
11
11
  /** Reads a value by key; returns `undefined` when the key does not exist. */
12
12
  readonly read: (key: Vec) => Effect<O, Vec | undefined>;
@@ -33,12 +33,4 @@ export type Cas<O extends Operation> = {
33
33
  * Builds a content-addressable storage facade from a SHA-2 implementation.
34
34
  */
35
35
  export declare const cas: (sha2: Sha2) => <O extends Operation>(_: KvStore<O>) => Cas<O>;
36
- /**
37
- * Runs the CAS CLI.
38
- *
39
- * Supported subcommands:
40
- * - `add <path>`: stores file content and prints the hash.
41
- * - `get <hash> <path>`: restores content by hash into a file.
42
- * - `list`: prints all known hashes.
43
- */
44
- export declare const main: (args: readonly string[]) => Effect<NodeOp, number>;
36
+ export declare const main: (options: NodeProgramOptions) => Effect<NodeOp, number>;
@@ -8,6 +8,7 @@ import { parse } from "../path/module.f.js";
8
8
  import { cBase32ToVec, vecToCBase32 } from "../cbase32/module.f.js";
9
9
  import { begin, forEachStep, pure } from "../effects/module.f.js";
10
10
  import { errorExit, log, mkdir, readdir, readFile, writeFile } from "../effects/node/module.f.js";
11
+ import { dispatch } from "../cli/module.f.js";
11
12
  import { toOption } from "../types/nullable/module.f.js";
12
13
  import { unwrap } from "../types/result/module.f.js";
13
14
  const o = { withFileTypes: true };
@@ -61,59 +62,54 @@ export const cas = (sha2) => {
61
62
  list,
62
63
  });
63
64
  };
64
- /**
65
- * Runs the CAS CLI.
66
- *
67
- * Supported subcommands:
68
- * - `add <path>`: stores file content and prints the hash.
69
- * - `get <hash> <path>`: restores content by hash into a file.
70
- * - `list`: prints all known hashes.
71
- */
72
- export const main = (args) => {
65
+ export const main = (options) => {
73
66
  const c = cas(sha256)(fileKvStore('.'));
74
- const [cmd, ...options] = args;
75
- switch (cmd) {
76
- case 'add': {
77
- if (options.length !== 1) {
78
- return errorExit("'cas add' expects one parameter");
79
- }
80
- const [path] = options;
81
- return begin
82
- .step(() => readFile(path))
83
- .step(v => c.write(unwrap(v)))
84
- .step(hash => log(vecToCBase32(hash)))
85
- .step(() => pure(0));
86
- }
87
- case 'get': {
88
- if (options.length !== 2) {
89
- return errorExit("'cas get' expects two parameters");
90
- }
91
- const [hashCBase32, path] = options;
92
- const hash = cBase32ToVec(hashCBase32);
93
- if (hash === null) {
94
- return errorExit(`invalid hash format: ${hashCBase32}`);
95
- }
96
- return begin
97
- .step(() => c.read(hash))
98
- .step(v => {
99
- const result = v === undefined
100
- ? errorExit(`no such hash: ${hashCBase32}`)
101
- : begin
102
- .step(() => writeFile(path, v))
103
- .step(() => pure(0));
104
- return result;
105
- });
106
- }
107
- case 'list': {
108
- return begin
67
+ const commands = [
68
+ {
69
+ names: ['add'],
70
+ description: 'Store file content and print its hash',
71
+ handler: ({ args: [path, ...rest] }) => {
72
+ if (path === undefined || rest.length !== 0) {
73
+ return errorExit("'cas add' expects one parameter");
74
+ }
75
+ return begin
76
+ .step(() => readFile(path))
77
+ .step(v => c.write(unwrap(v)))
78
+ .step(hash => log(vecToCBase32(hash)))
79
+ .step(() => pure(0));
80
+ },
81
+ },
82
+ {
83
+ names: ['get'],
84
+ description: 'Restore content by hash into a file',
85
+ handler: ({ args: [hashCBase32, path, ...rest] }) => {
86
+ if (hashCBase32 === undefined || path === undefined || rest.length !== 0) {
87
+ return errorExit("'cas get' expects two parameters");
88
+ }
89
+ const hash = cBase32ToVec(hashCBase32);
90
+ if (hash === null) {
91
+ return errorExit(`invalid hash format: ${hashCBase32}`);
92
+ }
93
+ return begin
94
+ .step(() => c.read(hash))
95
+ .step(v => {
96
+ const result = v === undefined
97
+ ? errorExit(`no such hash: ${hashCBase32}`)
98
+ : begin
99
+ .step(() => writeFile(path, v))
100
+ .step(() => pure(0));
101
+ return result;
102
+ });
103
+ },
104
+ },
105
+ {
106
+ names: ['list'],
107
+ description: 'List all stored content hashes',
108
+ handler: () => begin
109
109
  .step(() => c.list())
110
110
  .step(forEachStep(j => log(vecToCBase32(j))))
111
- .step(() => pure(0));
112
- }
113
- case undefined: {
114
- return errorExit('Error: CAS command requires subcommand');
115
- }
116
- default:
117
- return errorExit(`Error: Unknown CAS subcommand "${args[0]}"`);
118
- }
111
+ .step(() => pure(0)),
112
+ },
113
+ ];
114
+ return dispatch(commands)(options);
119
115
  };
package/fs/cas/proof.f.js CHANGED
@@ -4,11 +4,20 @@ import { empty, length, vec8 } from "../types/bit_vec/module.f.js";
4
4
  import { pure } from "../effects/module.f.js";
5
5
  import { run } from "../effects/mock/module.f.js";
6
6
  import { emptyState, virtual } from "../effects/node/virtual/module.f.js";
7
+ const makeOptions = (args) => ({
8
+ args,
9
+ env: {},
10
+ std: { stdout: { isTTY: false }, stderr: { isTTY: false } },
11
+ testContext: { test: async () => { } },
12
+ bunTestContext: { test: async () => { } },
13
+ playwrightTestContext: { test: async () => { } },
14
+ engine: 'node',
15
+ });
7
16
  export const proof = {
8
17
  mainAdd: () => {
9
18
  const content = vec8(0x2an);
10
19
  const state = { ...emptyState, root: { myfile: content } };
11
- const [finalState, exitCode] = virtual(state)(main(['add', 'myfile']));
20
+ const [finalState, exitCode] = virtual(state)(main(makeOptions(['add', 'myfile'])));
12
21
  if (exitCode !== 0) {
13
22
  throw ['expected exit 0', exitCode];
14
23
  }
@@ -17,7 +26,7 @@ export const proof = {
17
26
  }
18
27
  },
19
28
  mainAddWrongArgs: () => {
20
- const [finalState, exitCode] = virtual(emptyState)(main(['add']));
29
+ const [finalState, exitCode] = virtual(emptyState)(main(makeOptions(['add'])));
21
30
  if (exitCode !== 1) {
22
31
  throw ['expected exit 1', exitCode];
23
32
  }
@@ -28,12 +37,12 @@ export const proof = {
28
37
  mainGetFound: () => {
29
38
  const content = vec8(0x2an);
30
39
  const state = { ...emptyState, root: { myfile: content } };
31
- const [state1, exitCode1] = virtual(state)(main(['add', 'myfile']));
40
+ const [state1, exitCode1] = virtual(state)(main(makeOptions(['add', 'myfile'])));
32
41
  if (exitCode1 !== 0) {
33
42
  throw ['expected add exit 0', exitCode1];
34
43
  }
35
44
  const hashStr = state1.stdout.trim();
36
- const [, exitCode2] = virtual(state1)(main(['get', hashStr, 'output']));
45
+ const [, exitCode2] = virtual(state1)(main(makeOptions(['get', hashStr, 'output'])));
37
46
  if (exitCode2 !== 0) {
38
47
  throw ['expected get exit 0', exitCode2];
39
48
  }
@@ -42,10 +51,10 @@ export const proof = {
42
51
  // valid cBase32 hash that has not been stored
43
52
  const content = vec8(0x2an);
44
53
  const state = { ...emptyState, root: { myfile: content } };
45
- const [state1] = virtual(state)(main(['add', 'myfile']));
54
+ const [state1] = virtual(state)(main(makeOptions(['add', 'myfile'])));
46
55
  const hashStr = state1.stdout.trim();
47
56
  // use an empty store so the hash is not found
48
- const [finalState, exitCode] = virtual(emptyState)(main(['get', hashStr, 'output']));
57
+ const [finalState, exitCode] = virtual(emptyState)(main(makeOptions(['get', hashStr, 'output'])));
49
58
  if (exitCode !== 1) {
50
59
  throw ['expected exit 1', exitCode];
51
60
  }
@@ -54,7 +63,7 @@ export const proof = {
54
63
  }
55
64
  },
56
65
  mainGetWrongArgs: () => {
57
- const [finalState, exitCode] = virtual(emptyState)(main(['get']));
66
+ const [finalState, exitCode] = virtual(emptyState)(main(makeOptions(['get'])));
58
67
  if (exitCode !== 1) {
59
68
  throw ['expected exit 1', exitCode];
60
69
  }
@@ -63,7 +72,7 @@ export const proof = {
63
72
  }
64
73
  },
65
74
  mainGetInvalidHash: () => {
66
- const [finalState, exitCode] = virtual(emptyState)(main(['get', 'not-a-valid-hash', 'output']));
75
+ const [finalState, exitCode] = virtual(emptyState)(main(makeOptions(['get', 'not-a-valid-hash', 'output'])));
67
76
  if (exitCode !== 1) {
68
77
  throw ['expected exit 1', exitCode];
69
78
  }
@@ -74,14 +83,14 @@ export const proof = {
74
83
  mainList: () => {
75
84
  const content = vec8(0x2an);
76
85
  const state = { ...emptyState, root: { myfile: content } };
77
- const [state1] = virtual(state)(main(['add', 'myfile']));
78
- const [, exitCode] = virtual(state1)(main(['list']));
86
+ const [state1] = virtual(state)(main(makeOptions(['add', 'myfile'])));
87
+ const [, exitCode] = virtual(state1)(main(makeOptions(['list'])));
79
88
  if (exitCode !== 0) {
80
89
  throw ['expected exit 0', exitCode];
81
90
  }
82
91
  },
83
92
  mainNoCmd: () => {
84
- const [finalState, exitCode] = virtual(emptyState)(main([]));
93
+ const [finalState, exitCode] = virtual(emptyState)(main(makeOptions([])));
85
94
  if (exitCode !== 1) {
86
95
  throw ['expected exit 1', exitCode];
87
96
  }
@@ -90,7 +99,7 @@ export const proof = {
90
99
  }
91
100
  },
92
101
  mainUnknownCmd: () => {
93
- const [finalState, exitCode] = virtual(emptyState)(main(['bogus']));
102
+ const [finalState, exitCode] = virtual(emptyState)(main(makeOptions(['bogus'])));
94
103
  if (exitCode !== 1) {
95
104
  throw ['expected exit 1', exitCode];
96
105
  }
@@ -37,6 +37,7 @@ export declare const gitHubActionSchema: {
37
37
  readonly name: import("../../types/rtti/module.f.ts").String;
38
38
  readonly on: {
39
39
  readonly pull_request: import("../../types/rtti/module.f.ts").Or<readonly [{}, undefined]>;
40
+ readonly merge_group: import("../../types/rtti/module.f.ts").Or<readonly [{}, undefined]>;
40
41
  };
41
42
  readonly jobs: import("../../types/rtti/module.f.ts").Type1<"record", {
42
43
  readonly 'runs-on': import("../../types/rtti/module.f.ts").String;
@@ -55,6 +56,7 @@ export declare const parseGitHubAction: import("../../types/rtti/parse/module.f.
55
56
  readonly name: import("../../types/rtti/module.f.ts").String;
56
57
  readonly on: {
57
58
  readonly pull_request: import("../../types/rtti/module.f.ts").Or<readonly [{}, undefined]>;
59
+ readonly merge_group: import("../../types/rtti/module.f.ts").Or<readonly [{}, undefined]>;
58
60
  };
59
61
  readonly jobs: import("../../types/rtti/module.f.ts").Type1<"record", {
60
62
  readonly 'runs-on': import("../../types/rtti/module.f.ts").String;
@@ -23,7 +23,10 @@ export const jobSchema = {
23
23
  export const jobsSchema = record(jobSchema);
24
24
  export const gitHubActionSchema = {
25
25
  name: string,
26
- on: { pull_request: option({}) },
26
+ on: {
27
+ pull_request: option({}),
28
+ merge_group: option({})
29
+ },
27
30
  jobs: jobsSchema
28
31
  };
29
32
  export const parseGitHubAction = rttiParse(gitHubActionSchema);
@@ -28,7 +28,7 @@ export declare const node: {
28
28
  };
29
29
  export declare const wasmtime = "45.0.0";
30
30
  export declare const wasmer = "7.1.0";
31
- export declare const tsgo = "7.0.0-dev.20260604.1";
31
+ export declare const tsgo = "7.0.0-dev.20260605.1";
32
32
  export declare const actions: {
33
33
  readonly 'actions/checkout': "v6";
34
34
  readonly 'actions/setup-node': "v6";
@@ -37,5 +37,5 @@ export declare const actions: {
37
37
  readonly 'oven-sh/setup-bun': "v2";
38
38
  readonly 'bytecodealliance/actions/wasmtime/setup': "v1";
39
39
  readonly 'wasmerio/setup-wasmer': "v3.1";
40
- readonly 'dtolnay/rust-toolchain': "1.95.0";
40
+ readonly 'dtolnay/rust-toolchain': "1.96.0";
41
41
  };
@@ -36,7 +36,7 @@ export const wasmtime = '45.0.0';
36
36
  // https://github.com/wasmerio/wasmer/releases
37
37
  export const wasmer = '7.1.0';
38
38
  // https://www.npmjs.com/package/@typescript/native-preview?activeTab=versions
39
- export const tsgo = '7.0.0-dev.20260604.1';
39
+ export const tsgo = '7.0.0-dev.20260605.1';
40
40
  // GitHub Action versions used by CI step builders. The key is the action
41
41
  // `owner/name`; call sites compose the full ref as
42
42
  // `` `${name}@${actions[name]}` ``.
@@ -57,5 +57,5 @@ export const actions = {
57
57
  // https://github.com/wasmerio/setup-wasmer
58
58
  'wasmerio/setup-wasmer': 'v3.1',
59
59
  // https://rust-lang.org/ - value is Rust version, not action version
60
- 'dtolnay/rust-toolchain': '1.95.0',
60
+ 'dtolnay/rust-toolchain': '1.96.0',
61
61
  };
@@ -2,11 +2,9 @@ import { type Effect } from '../effects/module.f.ts';
2
2
  import { type NodeOp } from '../effects/node/module.f.ts';
3
3
  import { type MetaStep, type Os } from './common/module.f.ts';
4
4
  export type Setup = {
5
- readonly rust: boolean;
6
5
  readonly nodeExtra: (os: Os) => readonly MetaStep[];
7
6
  readonly denoExtra: readonly MetaStep[];
8
7
  readonly bunExtra: readonly MetaStep[];
9
8
  };
10
- export declare const ci: ({ rust, nodeExtra, denoExtra, bunExtra }: Setup) => Effect<NodeOp, number>;
11
- declare const _default: () => Effect<NodeOp, number>;
12
- export default _default;
9
+ export declare const ci: ({ nodeExtra, denoExtra, bunExtra }: Setup) => Effect<NodeOp, number>;
10
+ export declare const main: () => Effect<NodeOp, number>;
package/fs/ci/module.f.js CHANGED
@@ -4,8 +4,8 @@
4
4
  * @module
5
5
  */
6
6
  import { utf8 } from "../text/module.f.js";
7
- import { begin, pure } from "../effects/module.f.js";
8
- import { writeFile } from "../effects/node/module.f.js";
7
+ import { pure } from "../effects/module.f.js";
8
+ import { access, writeFile } from "../effects/node/module.f.js";
9
9
  import { images } from "./config/module.f.js";
10
10
  import { architecture, findTgz, os, test, toSteps } from "./common/module.f.js";
11
11
  import { rustSteps } from "./rust/module.f.js";
@@ -24,7 +24,8 @@ const job = (rust, nodeExtra, denoExtra, bunExtra) => (o) => (a) => {
24
24
  ];
25
25
  return [id, { 'runs-on': image, steps: toSteps(result) }];
26
26
  };
27
- export const ci = ({ rust, nodeExtra, denoExtra, bunExtra }) => {
27
+ export const ci = ({ nodeExtra, denoExtra, bunExtra }) => access('Cargo.toml').step(result => {
28
+ const rust = result[0] === 'ok';
28
29
  const jobs = {
29
30
  ...Object.fromEntries(os.flatMap(o => architecture.map(job(rust, nodeExtra(o), denoExtra, bunExtra)(o)))),
30
31
  ...nodeVersions,
@@ -32,15 +33,16 @@ export const ci = ({ rust, nodeExtra, denoExtra, bunExtra }) => {
32
33
  };
33
34
  const gha = {
34
35
  name: 'CI',
35
- on: { pull_request: {} },
36
+ on: {
37
+ pull_request: {},
38
+ merge_group: {},
39
+ },
36
40
  jobs,
37
41
  };
38
- return begin
39
- .step(() => writeFile('.github/workflows/ci.yml', utf8(JSON.stringify(gha, null, ' '))))
42
+ return writeFile('.github/workflows/ci.yml', utf8(JSON.stringify(gha, null, ' ')))
40
43
  .step(() => pure(0));
41
- };
44
+ });
42
45
  const defaultEffect = ci({
43
- rust: true,
44
46
  nodeExtra: o => [
45
47
  test({ run: 'npm pack' }),
46
48
  test({ run: `npm install -g ${findTgz(o)}` }),
@@ -57,4 +59,4 @@ const defaultEffect = ci({
57
59
  test({ run: 'bun ./fs/fjs/module.ts t' }),
58
60
  ]
59
61
  });
60
- export default () => defaultEffect;
62
+ export const main = () => defaultEffect;
@@ -17,8 +17,10 @@ export const basicNode = (version) => (extra) => clean([
17
17
  ...extra,
18
18
  ]);
19
19
  const basicTests = [
20
- test({ run: 'npm t' }),
21
- test({ run: 'npm run fst' }),
20
+ test({ run: 'npx tsc' }),
21
+ test({ run: 'npm test' }),
22
+ test({ run: 'node --test' }),
23
+ test({ run: 'npm run cov' }),
22
24
  ];
23
25
  export const nodeTests = (version) => (extra) => basicNode(version)([
24
26
  ...basicTests,
package/fs/ci/proof.f.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ci } from "./module.f.js";
2
2
  import { utf8ToString } from "../text/module.f.js";
3
- import { isVec } from "../types/bit_vec/module.f.js";
3
+ import { empty as emptyVec, isVec } from "../types/bit_vec/module.f.js";
4
4
  import { test, parseGitHubAction } from "./common/module.f.js";
5
5
  import { assert } from "../asserts/module.f.js";
6
6
  import { emptyState, virtual } from "../effects/node/virtual/module.f.js";
@@ -8,12 +8,15 @@ import { parse as jsonParse } from "../json/module.f.js";
8
8
  import { unwrap } from "../types/result/module.f.js";
9
9
  const hasRun = (cmd) => (gha) => Object.values(gha.jobs).some(job => job.steps.some(step => step.run?.includes(cmd)));
10
10
  const hasRunInJob = (jobId, cmd) => (gha) => gha.jobs[jobId]?.steps.some(step => step.run?.includes(cmd)) ?? false;
11
- const githubState = {
11
+ const makeState = (rust) => ({
12
12
  ...emptyState,
13
- root: { '.github': { workflows: {} } },
14
- };
13
+ root: {
14
+ '.github': { workflows: {} },
15
+ ...(rust ? { 'Cargo.toml': emptyVec } : {}),
16
+ },
17
+ });
15
18
  const run = (rust, nodeExtra = () => []) => {
16
- const [state, result] = virtual(githubState)(ci({ rust, nodeExtra, denoExtra: [], bunExtra: [] }));
19
+ const [state, result] = virtual(makeState(rust))(ci({ nodeExtra, denoExtra: [], bunExtra: [] }));
17
20
  assert(result === 0, result);
18
21
  const dotGithub = state.root['.github'];
19
22
  assert(typeof dotGithub === 'object', dotGithub);
@@ -0,0 +1,9 @@
1
+ import { type NodeOp, type NodeProgramOptions, type Write } from '../effects/node/module.f.ts';
2
+ import { type Effect } from '../effects/module.f.ts';
3
+ export type Command<O extends NodeOp> = {
4
+ readonly names: readonly string[];
5
+ readonly description: string;
6
+ readonly handler: (options: NodeProgramOptions) => Effect<O, number>;
7
+ };
8
+ export type Commands<O extends NodeOp> = readonly Command<O>[];
9
+ export declare const dispatch: <O extends NodeOp>(commands: Commands<O>) => (options: NodeProgramOptions) => Effect<O | Write, number>;
@@ -0,0 +1,24 @@
1
+ import { errorExit, log } from "../effects/node/module.f.js";
2
+ import { pure } from "../effects/module.f.js";
3
+ const helpMeta = { names: ['help', 'h', '?'], description: 'Print this help message' };
4
+ export const dispatch = (commands) => (options) => {
5
+ const [cmd, ...rest] = options.args;
6
+ 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])));
16
+ if (cmd === undefined) {
17
+ return errorExit(`Error: command is required.\n${helpText}`);
18
+ }
19
+ const found = map[cmd];
20
+ if (found === undefined) {
21
+ return errorExit(`Error: unknown command "${cmd}".\n${helpText}`);
22
+ }
23
+ return found.handler({ ...options, args: rest });
24
+ };
@@ -0,0 +1,9 @@
1
+ export declare const proof: {
2
+ knownCommand: () => void;
3
+ alias: () => void;
4
+ noArgs: () => void;
5
+ unknownCommand: () => void;
6
+ help: () => void;
7
+ errorIncludesAvailable: () => void;
8
+ handlerReceivesRemainingArgs: () => void;
9
+ };