functionalscript 0.16.0 → 0.17.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 (53) hide show
  1. package/fs/asn.1/module.f.js +6 -0
  2. package/fs/ci/bun/module.f.js +6 -0
  3. package/fs/ci/common/module.f.d.ts +7 -0
  4. package/fs/ci/common/module.f.js +7 -0
  5. package/fs/ci/config/module.f.d.ts +7 -0
  6. package/fs/ci/config/module.f.js +7 -0
  7. package/fs/ci/deno/module.f.js +6 -0
  8. package/fs/ci/node/module.f.js +6 -0
  9. package/fs/ci/playwright/module.f.js +7 -2
  10. package/fs/ci/rust/module.f.js +7 -0
  11. package/fs/crypto/secp/module.f.d.ts +7 -0
  12. package/fs/dev/index/module.f.d.ts +6 -0
  13. package/fs/dev/index/module.f.js +6 -0
  14. package/fs/dev/module.f.d.ts +2 -1
  15. package/fs/dev/module.f.js +3 -4
  16. package/fs/dev/tf/module.f.d.ts +3 -19
  17. package/fs/dev/tf/module.f.js +25 -36
  18. package/fs/dev/tf/module.js +4 -3
  19. package/fs/djs/module.f.d.ts +5 -2
  20. package/fs/djs/module.f.js +13 -21
  21. package/fs/djs/test.f.d.ts +11 -0
  22. package/fs/djs/test.f.js +75 -0
  23. package/fs/djs/transpiler/module.f.d.ts +3 -3
  24. package/fs/djs/transpiler/module.f.js +34 -29
  25. package/fs/djs/transpiler/test.f.js +20 -26
  26. package/fs/fjs/module.f.js +10 -4
  27. package/fs/html/module.f.d.ts +6 -0
  28. package/fs/html/module.f.js +6 -0
  29. package/fs/io/module.f.d.ts +5 -2
  30. package/fs/io/module.f.js +14 -3
  31. package/fs/io/module.js +19 -1
  32. package/fs/js/tokenizer/module.f.js +7 -0
  33. package/fs/json/module.f.d.ts +7 -0
  34. package/fs/json/module.f.js +7 -0
  35. package/fs/text/module.f.d.ts +7 -0
  36. package/fs/text/module.f.js +7 -0
  37. package/fs/text/utf16/module.f.d.ts +7 -0
  38. package/fs/text/utf16/module.f.js +7 -0
  39. package/fs/types/effects/node/module.f.d.ts +46 -2
  40. package/fs/types/effects/node/module.f.js +20 -0
  41. package/fs/types/effects/node/test.f.d.ts +5 -0
  42. package/fs/types/effects/node/test.f.js +31 -1
  43. package/fs/types/effects/node/virtual/module.f.d.ts +1 -0
  44. package/fs/types/effects/node/virtual/module.f.js +12 -0
  45. package/fs/types/monoid/module.f.d.ts +7 -0
  46. package/fs/types/number/module.f.d.ts +6 -0
  47. package/fs/types/number/module.f.js +6 -0
  48. package/fs/types/object/module.f.js +7 -0
  49. package/fs/types/prime_field/module.f.d.ts +8 -0
  50. package/fs/types/ts/module.f.d.ts +7 -0
  51. package/package.json +3 -2
  52. package/fs/io/virtual/module.f.d.ts +0 -8
  53. package/fs/io/virtual/module.f.js +0 -43
@@ -1,17 +1,16 @@
1
1
  import { sort } from "../../types/object/module.f.js";
2
- import { setReplace } from "../../types/ordered_map/module.f.js";
3
2
  import { transpile } from "./module.f.js";
4
3
  import { stringifyAsTree } from "../serializer/module.f.js";
5
- import { createVirtualIo } from "../../io/virtual/module.f.js";
6
- import { encodeUtf8 } from "../../types/uint8array/module.f.js";
7
- const virtualFs = map => {
8
- return createVirtualIo(map).fs;
4
+ import { virtual, emptyState } from "../../types/effects/node/virtual/module.f.js";
5
+ import { encodeUtf8, toVec } from "../../types/uint8array/module.f.js";
6
+ const fileVec = (s) => toVec(encodeUtf8(s));
7
+ const run = (root) => (path) => {
8
+ const [_, result] = virtual({ ...emptyState, root })(transpile(path));
9
+ return result;
9
10
  };
10
11
  export default {
11
12
  parse: () => {
12
- const map = setReplace('a')(encodeUtf8('export default 1'))(null);
13
- const fs = virtualFs(map);
14
- const result = transpile(fs)('a');
13
+ const result = run({ a: fileVec('export default 1') })('a');
15
14
  if (result[0] === 'error') {
16
15
  throw result[1];
17
16
  }
@@ -21,10 +20,7 @@ export default {
21
20
  }
22
21
  },
23
22
  parseWithSubModule: () => {
24
- const map = setReplace('a/b')(encodeUtf8('import c from "c"\nexport default c'))(null);
25
- const map2 = setReplace('a/c')(encodeUtf8('export default 2'))(map);
26
- const fs = virtualFs(map2);
27
- const result = transpile(fs)('a/b');
23
+ const result = run({ a: { b: fileVec('import c from "c"\nexport default c'), c: fileVec('export default 2') } })('a/b');
28
24
  if (result[0] === 'error') {
29
25
  throw result[1];
30
26
  }
@@ -34,12 +30,12 @@ export default {
34
30
  }
35
31
  },
36
32
  parseWithSubModules: () => {
37
- const map = setReplace('a')(encodeUtf8('import b from "b"\nimport c from "c"\nexport default [b,c,b]'))(null);
38
- const map2 = setReplace('b')(encodeUtf8('import d from "d"\nexport default [0,d]'))(map);
39
- const map3 = setReplace('c')(encodeUtf8('import d from "d"\nexport default [1,d]'))(map2);
40
- const map4 = setReplace('d')(encodeUtf8('export default 2'))(map3);
41
- const fs = virtualFs(map4);
42
- const result = transpile(fs)('a');
33
+ const result = run({
34
+ a: fileVec('import b from "b"\nimport c from "c"\nexport default [b,c,b]'),
35
+ b: fileVec('import d from "d"\nexport default [0,d]'),
36
+ c: fileVec('import d from "d"\nexport default [1,d]'),
37
+ d: fileVec('export default 2'),
38
+ })('a');
43
39
  if (result[0] === 'error') {
44
40
  throw result[1];
45
41
  }
@@ -49,9 +45,7 @@ export default {
49
45
  }
50
46
  },
51
47
  parseWithFileNotFoundError: () => {
52
- const map = setReplace('a')(encodeUtf8('import b from "b"\nexport default b'))(null);
53
- const fs = virtualFs(map);
54
- const result = transpile(fs)('a');
48
+ const result = run({ a: fileVec('import b from "b"\nexport default b') })('a');
55
49
  if (result[0] !== 'error') {
56
50
  throw result;
57
51
  }
@@ -60,11 +54,11 @@ export default {
60
54
  }
61
55
  },
62
56
  parseWithCycleError: () => {
63
- const map = setReplace('a')(encodeUtf8('import b from "b"\nimport c from "c"\nexport default [b,c,b]'))(null);
64
- const map2 = setReplace('b')(encodeUtf8('import c from "c"\nexport default c'))(map);
65
- const map3 = setReplace('c')(encodeUtf8('import b from "b"\nexport default b'))(map2);
66
- const fs = virtualFs(map3);
67
- const result = transpile(fs)('a');
57
+ const result = run({
58
+ a: fileVec('import b from "b"\nimport c from "c"\nexport default [b,c,b]'),
59
+ b: fileVec('import c from "c"\nexport default c'),
60
+ c: fileVec('import b from "b"\nexport default b'),
61
+ })('a');
68
62
  if (result[0] !== 'error') {
69
63
  throw result;
70
64
  }
@@ -7,9 +7,10 @@ import { fromIo } from "../io/module.f.js";
7
7
  import { compile } from "../djs/module.f.js";
8
8
  import { main as testMain } from "../dev/tf/module.f.js";
9
9
  import { main as casMain } from "../cas/module.f.js";
10
+ import { import_ } from "../types/effects/node/module.f.js";
10
11
  export const main = async (io) => {
11
12
  const { error } = io.console;
12
- const { process, asyncImport } = io;
13
+ const { process } = io;
13
14
  const { env } = process;
14
15
  const [command, ...rest] = process.argv.slice(2);
15
16
  const eRun = fromIo(io);
@@ -19,15 +20,20 @@ export const main = async (io) => {
19
20
  return testMain(io);
20
21
  case 'compile':
21
22
  case 'c':
22
- return compile(io)(rest);
23
+ return eRun(compile(rest));
23
24
  case 'cas':
24
25
  case 's':
25
26
  return eRun(casMain(rest));
26
27
  case 'run':
27
28
  case 'r':
28
29
  const [file, ...args] = rest;
29
- const m = await asyncImport(file);
30
- return eRun(m.default(args, env));
30
+ return eRun(import_(file).step(result => {
31
+ if (result[0] === 'error') {
32
+ throw result[1];
33
+ }
34
+ const options = { args, env };
35
+ return result[1].default(options);
36
+ }));
31
37
  case undefined:
32
38
  error('Error: command is required');
33
39
  return Promise.resolve(1);
@@ -1,3 +1,9 @@
1
+ /**
2
+ * HTML serialization helpers: `Element`/`Attributes` builders, void-tag
3
+ * handling, attribute/text escaping, and a UTF-8 emitter for full documents.
4
+ *
5
+ * @module
6
+ */
1
7
  import { type List } from '../types/list/module.f.ts';
2
8
  import { type Vec } from '../types/bit_vec/module.f.ts';
3
9
  type Tag = string;
@@ -1,3 +1,9 @@
1
+ /**
2
+ * HTML serialization helpers: `Element`/`Attributes` builders, void-tag
3
+ * handling, attribute/text escaping, and a UTF-8 emitter for full documents.
4
+ *
5
+ * @module
6
+ */
1
7
  import { map, flatMap, flat, concat as listConcat } from "../types/list/module.f.js";
2
8
  import { concat, concat as stringConcat } from "../types/string/module.f.js";
3
9
  import { compose } from "../types/function/module.f.js";
@@ -1,5 +1,5 @@
1
1
  import { type Effect } from '../types/effects/module.f.ts';
2
- import type { Headers, Module, NodeOp, Env } from '../types/effects/node/module.f.ts';
2
+ import type { Headers, Module, NodeOp, Env, SandboxResult } from '../types/effects/node/module.f.ts';
3
3
  import { type Result } from '../types/result/module.f.ts';
4
4
  /**
5
5
  * Represents a directory entry (file or directory) in the filesystem
@@ -73,6 +73,7 @@ export type Process = {
73
73
  readonly stderr: Writable;
74
74
  };
75
75
  export type TryCatch = <T>(f: () => T) => Result<T, unknown>;
76
+ export type Sandbox = <T>(f: () => T) => SandboxResult<T>;
76
77
  export type Server = {
77
78
  readonly listen: (port: number) => void;
78
79
  };
@@ -111,6 +112,8 @@ export type Io = {
111
112
  readonly asyncTryCatch: <T>(f: () => Promise<T>) => Promise<Result<T, unknown>>;
112
113
  readonly http: Http;
113
114
  readonly childProcess: ChildProcess;
115
+ readonly now: () => number;
116
+ readonly sandbox: Sandbox;
114
117
  };
115
118
  export type App = (io: Io) => Promise<number>;
116
119
  export type Run = (f: App) => Promise<never>;
@@ -120,4 +123,4 @@ export type Run = (f: App) => Promise<never>;
120
123
  */
121
124
  export declare const run: (io: Io) => Run;
122
125
  export type EffectToPromise = <T>(effect: Effect<NodeOp, T>) => Promise<T>;
123
- export declare const fromIo: ({ console: { error, log }, fs: { promises: { mkdir, readFile, readdir, writeFile, rm, access } }, fetch, http: { createServer }, childProcess, asyncImport, }: Io) => EffectToPromise;
126
+ export declare const fromIo: ({ console: { error: logError, log }, fs: { promises: { mkdir, readFile, readdir, writeFile, rm, access } }, fetch, http: { createServer }, childProcess, asyncImport, now: ioNow, sandbox: ioSandbox, }: Io) => EffectToPromise;
package/fs/io/module.f.js CHANGED
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Legacy `Io` interface and adapter (`fromIo`) bridging the old IO API to the
3
+ * effect runner.
4
+ *
5
+ * @deprecated Use `fs/types/effects/node` (see issue
6
+ * [i139](../../issues/README.md)).
7
+ *
8
+ * @module
9
+ */
1
10
  import { normalize } from "../path/module.f.js";
2
11
  import {} from "../types/effects/module.f.js";
3
12
  import { asyncRun } from "../types/effects/module.js";
@@ -35,10 +44,10 @@ const collect = async (v) => {
35
44
  }
36
45
  return result;
37
46
  };
38
- export const fromIo = ({ console: { error, log }, fs: { promises: { mkdir, readFile, readdir, writeFile, rm, access } }, fetch, http: { createServer }, childProcess, asyncImport, }) => {
47
+ export const fromIo = ({ console: { error: logError, log }, fs: { promises: { mkdir, readFile, readdir, writeFile, rm, access } }, fetch, http: { createServer }, childProcess, asyncImport, now: ioNow, sandbox: ioSandbox, }) => {
39
48
  const result = asyncRun({
40
49
  all: async (...effects) => await Promise.all(effects.map(result)),
41
- error: async (message) => error(message),
50
+ error: async (message) => logError(message),
42
51
  log: async (message) => log(message),
43
52
  fetch: async (url) => tc(async () => {
44
53
  const response = await fetch(url);
@@ -85,7 +94,9 @@ export const fromIo = ({ console: { error, log }, fs: { promises: { mkdir, readF
85
94
  const s = asBase(server);
86
95
  s.listen(port);
87
96
  },
88
- forever: () => new Promise(() => { })
97
+ forever: () => new Promise(() => { }),
98
+ now: async () => ioNow(),
99
+ sandbox: async (f) => ioSandbox(f),
89
100
  });
90
101
  return result;
91
102
  };
package/fs/io/module.js CHANGED
@@ -14,6 +14,7 @@ import { fromIo, run } from "./module.f.js";
14
14
  import { concat } from "../path/module.f.js";
15
15
  import { error, ok } from "../types/result/module.f.js";
16
16
  const prefix = 'file:///';
17
+ const { now } = Date;
17
18
  export const asyncImport = (v) => import(__rewriteRelativeImportExtension(v));
18
19
  export const io = {
19
20
  console,
@@ -44,12 +45,29 @@ export const io = {
44
45
  },
45
46
  http,
46
47
  childProcess,
48
+ now,
49
+ sandbox: (f) => {
50
+ let result;
51
+ let after;
52
+ const before = performance.now();
53
+ try {
54
+ const value = f();
55
+ after = performance.now();
56
+ result = ok(value);
57
+ }
58
+ catch (e) {
59
+ after = performance.now();
60
+ result = error(e);
61
+ }
62
+ return { result, duration: after - before };
63
+ },
47
64
  };
48
65
  export const legacyRun = run(io);
49
66
  export const ioRun = (io) => {
50
67
  const r = fromIo(io);
51
68
  const { argv, env } = io.process;
52
- return p => r(p(argv, env));
69
+ const options = { args: argv.slice(2), env };
70
+ return p => r(p(options));
53
71
  };
54
72
  const effectRun = ioRun(io);
55
73
  export default effectRun;
@@ -1,3 +1,10 @@
1
+ /**
2
+ * JavaScript tokenizer built as a range-map state machine over code points,
3
+ * producing tokens for keywords, identifiers, punctuators, comments, strings,
4
+ * and numeric literals (including `BigFloat`).
5
+ *
6
+ * @module
7
+ */
1
8
  import { strictEqual } from "../../types/function/operator/module.f.js";
2
9
  import { merge, fromRange, get } from "../../types/range_map/module.f.js";
3
10
  import { empty, stateScan, flat, toArray, reduce as listReduce, scan, map as listMap } from "../../types/list/module.f.js";
@@ -1,3 +1,10 @@
1
+ /**
2
+ * JSON tree types and utilities: `Primitive`/`Unknown` value shapes,
3
+ * `setProperty` for immutable nested updates, and a `stringify` built from the
4
+ * serializer wraps.
5
+ *
6
+ * @module
7
+ */
1
8
  import { type List } from '../types/list/module.f.ts';
2
9
  import { type Entry as ObjectEntry } from '../types/object/module.f.ts';
3
10
  type Object = {
@@ -1,3 +1,10 @@
1
+ /**
2
+ * JSON tree types and utilities: `Primitive`/`Unknown` value shapes,
3
+ * `setProperty` for immutable nested updates, and a `stringify` built from the
4
+ * serializer wraps.
5
+ *
6
+ * @module
7
+ */
1
8
  import { next, flat, map } from "../types/list/module.f.js";
2
9
  import { concat } from "../types/string/module.f.js";
3
10
  import { at } from "../types/object/module.f.js";
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Indented text `Block` rendering and UTF-8 helpers: `flat` flattens a nested
3
+ * block into prefixed lines, while `utf8`/`utf8ToString` convert between
4
+ * strings and MSB-first UTF-8 bit vectors.
5
+ *
6
+ * @module
7
+ */
1
8
  import { type Vec } from '../types/bit_vec/module.f.ts';
2
9
  import { type List } from '../types/list/module.f.ts';
3
10
  export type Block = ItemThunk | ItemArray;
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Indented text `Block` rendering and UTF-8 helpers: `flat` flattens a nested
3
+ * block into prefixed lines, while `utf8`/`utf8ToString` convert between
4
+ * strings and MSB-first UTF-8 bit vectors.
5
+ *
6
+ * @module
7
+ */
1
8
  import { msb, u8List, u8ListToVec } from "../types/bit_vec/module.f.js";
2
9
  import { flatMap } from "../types/list/module.f.js";
3
10
  import { fromCodePointList, toCodePointList } from "./utf8/module.f.js";
@@ -1,3 +1,10 @@
1
+ /**
2
+ * UTF-16 utilities: convert between strings, UTF-16 code units, and Unicode
3
+ * code points, including surrogate-pair encoding/decoding via streaming
4
+ * `stateScan` operations.
5
+ *
6
+ * @module
7
+ */
1
8
  import { type List, type Thunk } from '../../types/list/module.f.ts';
2
9
  /**
3
10
  * Represent an unsigned UTF16, used to store one word UTF-16 (code unit).
@@ -1,3 +1,10 @@
1
+ /**
2
+ * UTF-16 utilities: convert between strings, UTF-16 code units, and Unicode
3
+ * code points, including surrogate-pair encoding/decoding via streaming
4
+ * `stateScan` operations.
5
+ *
6
+ * @module
7
+ */
1
8
  import { map, flat, stateScan, reduce, flatMap, empty, } from "../../types/list/module.f.js";
2
9
  import { concat } from "../../types/function/operator/module.f.js";
3
10
  import { contains } from "../../types/range/module.f.js";
@@ -1,3 +1,12 @@
1
+ /**
2
+ * Node.js effect operations: filesystem (`mkdir`, `readFile`, `readdir`,
3
+ * `writeFile`, `rm`, `access`), networking (`fetch`, `createServer`, `listen`),
4
+ * subprocess `exec`, console (`log`, `error`), `import_`, `now`, `sandbox`, `forever`,
5
+ * and `all`/`both` parallelism; defines the `NodeOp`/`NodeProgram` types used
6
+ * by the Node runner.
7
+ *
8
+ * @module
9
+ */
1
10
  import type { Vec } from '../../bit_vec/module.f.ts';
2
11
  import type { Nominal } from '../../nominal/module.f.ts';
3
12
  import type { Result } from '../../result/module.f.ts';
@@ -82,7 +91,38 @@ export type Module = {
82
91
  };
83
92
  export type Import = ['import', (path: string) => IoResult<Module>];
84
93
  export declare const import_: Func<Import>;
85
- export type NodeOp = All | Fetch | Console | Fs | Http | Forever | Import;
94
+ export type Now = readonly ['now', () => number];
95
+ export declare const now: Func<Now>;
96
+ export type SandboxResult<T> = {
97
+ readonly result: Result<T, unknown>;
98
+ /**
99
+ * Measured milliseconds but it's not limited to that.
100
+ * Instead, they represent times as floating-point numbers
101
+ * with up to microsecond precision.
102
+ */
103
+ readonly duration: number;
104
+ };
105
+ export type Sandbox = readonly ['sandbox', <T>(f: () => T) => SandboxResult<T>];
106
+ /**
107
+ * Runs a plain synchronous function in an isolated, measured environment.
108
+ *
109
+ * Combines try/catch and high-resolution timing into a single atomic operation.
110
+ * Only plain synchronous functions are accepted — no effects, no promises.
111
+ *
112
+ * Using a single operation rather than separate `TryCatch` + `Perf` effects is
113
+ * necessary for correctness: effects execute as async tasks, so the scheduler
114
+ * can insert arbitrary work between two separate timing calls, making the
115
+ * measured delta inaccurate. Here the clock reads happen synchronously around
116
+ * the function call with nothing in between.
117
+ *
118
+ * Future parameters (time limit, memory limit) can be added to the payload
119
+ * without breaking the API. Worker-based implementations can enforce hard
120
+ * limits via worker termination.
121
+ *
122
+ * @see {@link SandboxResult}
123
+ */
124
+ export declare const sandbox: Func<Sandbox>;
125
+ export type NodeOp = All | Fetch | Console | Fs | Http | Forever | Import | Now | Sandbox;
86
126
  export type NodeEffect<T> = Effect<NodeOp, T>;
87
127
  export type NodeOperationMap = ToAsyncOperationMap<NodeOp>;
88
128
  /**
@@ -91,4 +131,8 @@ export type NodeOperationMap = ToAsyncOperationMap<NodeOp>;
91
131
  export type Env = {
92
132
  readonly [k: string]: string | undefined;
93
133
  };
94
- export type NodeProgram = (argv: readonly string[], env: Env) => Effect<NodeOp, number>;
134
+ export type NodeProgramOptions = {
135
+ readonly args: readonly string[];
136
+ readonly env: Env;
137
+ };
138
+ export type NodeProgram = (options: NodeProgramOptions) => Effect<NodeOp, number>;
@@ -23,3 +23,23 @@ export const createServer = do_('createServer');
23
23
  export const listen = do_('listen');
24
24
  export const forever = do_('forever');
25
25
  export const import_ = do_('import');
26
+ export const now = do_('now');
27
+ /**
28
+ * Runs a plain synchronous function in an isolated, measured environment.
29
+ *
30
+ * Combines try/catch and high-resolution timing into a single atomic operation.
31
+ * Only plain synchronous functions are accepted — no effects, no promises.
32
+ *
33
+ * Using a single operation rather than separate `TryCatch` + `Perf` effects is
34
+ * necessary for correctness: effects execute as async tasks, so the scheduler
35
+ * can insert arbitrary work between two separate timing calls, making the
36
+ * measured delta inaccurate. Here the clock reads happen synchronously around
37
+ * the function call with nothing in between.
38
+ *
39
+ * Future parameters (time limit, memory limit) can be added to the payload
40
+ * without breaking the API. Worker-based implementations can enforce hard
41
+ * limits via worker termination.
42
+ *
43
+ * @see {@link SandboxResult}
44
+ */
45
+ export const sandbox = do_('sandbox');
@@ -30,5 +30,10 @@ declare const _default: {
30
30
  noSuchFile: () => void;
31
31
  isDirectory: () => void;
32
32
  };
33
+ now: () => void;
34
+ sandbox: {
35
+ ok: () => void;
36
+ error: () => void;
37
+ };
33
38
  };
34
39
  export default _default;
@@ -1,6 +1,6 @@
1
1
  import { empty, isVec, uint, vec8 } from "../../bit_vec/module.f.js";
2
2
  import { pure } from "../module.f.js";
3
- import { fetch, mkdir, readdir, readFile, rm, writeFile } from "./module.f.js";
3
+ import { fetch, mkdir, now, readdir, readFile, rm, sandbox, writeFile } from "./module.f.js";
4
4
  import { emptyState, virtual } from "./virtual/module.f.js";
5
5
  export default {
6
6
  map: () => {
@@ -326,4 +326,34 @@ export default {
326
326
  }
327
327
  },
328
328
  },
329
+ now: () => {
330
+ const [_, result] = virtual({ ...emptyState, epochNs: 1_000_000 })(now());
331
+ if (result !== 1_000_000) {
332
+ throw result;
333
+ }
334
+ },
335
+ sandbox: {
336
+ ok: () => {
337
+ const [_, { result, duration }] = virtual(emptyState)(sandbox(() => 42));
338
+ if (result[0] !== 'ok') {
339
+ throw result;
340
+ }
341
+ if (result[1] !== 42) {
342
+ throw result[1];
343
+ }
344
+ if (duration !== 0) {
345
+ throw duration;
346
+ }
347
+ },
348
+ error: () => {
349
+ const err = new Error('fail');
350
+ const [_, { result }] = virtual(emptyState)(sandbox(() => { throw err; }));
351
+ if (result[0] !== 'error') {
352
+ throw result;
353
+ }
354
+ if (result[1] !== err) {
355
+ throw result[1];
356
+ }
357
+ },
358
+ },
329
359
  };
@@ -11,6 +11,7 @@ export type State = {
11
11
  internet: {
12
12
  readonly [url: string]: Vec;
13
13
  };
14
+ epochNs: number;
14
15
  };
15
16
  export declare const emptyState: State;
16
17
  export declare const virtual: RunInstance<NodeOp, State>;
@@ -13,6 +13,7 @@ export const emptyState = {
13
13
  stderr: '',
14
14
  root: {},
15
15
  internet: {},
16
+ epochNs: 0,
16
17
  };
17
18
  const operation = (op) => {
18
19
  const f = (dir, path) => {
@@ -146,5 +147,16 @@ const map = {
146
147
  createServer: todo,
147
148
  listen: todo,
148
149
  forever: todo,
150
+ now: (state) => [state, state.epochNs],
151
+ sandbox: (state, f) => {
152
+ let result;
153
+ try {
154
+ result = ok(f());
155
+ }
156
+ catch (e) {
157
+ result = error(e);
158
+ }
159
+ return [state, { result, duration: 0 }];
160
+ },
149
161
  };
150
162
  export const virtual = run(map);
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Monoids: the `Monoid<T>` algebraic structure (identity plus associative
3
+ * binary operation) and `repeat`, which applies the operation `n` times using
4
+ * exponentiation by squaring.
5
+ *
6
+ * @module
7
+ */
1
8
  import type { Fold, Reduce } from '../function/operator/module.f.ts';
2
9
  /**
3
10
  * Represents a monoid, an algebraic structure with a binary operation
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Numeric list reductions (`sum`, `min`, `max`), comparison via `cmp`, and
3
+ * `countOnes` for 32-bit population count using SWAR.
4
+ *
5
+ * @module
6
+ */
1
7
  import { type List } from '../list/module.f.ts';
2
8
  import { type Sign } from '../function/compare/module.f.ts';
3
9
  export declare const sum: (input: List<number>) => number;
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Numeric list reductions (`sum`, `min`, `max`), comparison via `cmp`, and
3
+ * `countOnes` for 32-bit population count using SWAR.
4
+ *
5
+ * @module
6
+ */
1
7
  import { reduce } from "../list/module.f.js";
2
8
  import { addition, min as minOp, max as maxOp } from "../function/operator/module.f.js";
3
9
  import { cmp as uCmp } from "../function/compare/module.f.js";
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Plain-object helpers and types: `Map<T>`/`Entry<T>` shapes, safe property
3
+ * lookup via `at`, conversions between entries and `OrderedMap`, and the
4
+ * `OneKey`/`SingleProperty`/`NotUnion` utility types.
5
+ *
6
+ * @module
7
+ */
1
8
  import { isArray } from "../array/module.f.js";
2
9
  import { iterable } from "../list/module.f.js";
3
10
  import { entries as mapEntries, fromEntries as mapFromEntries } from "../ordered_map/module.f.js";
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Prime field arithmetic over `bigint`: `prime_field(p)` builds a `PrimeField`
3
+ * with negation, addition, subtraction, multiplication, division via modular
4
+ * inverse, and exponentiation; `sqrt` returns a square-root function when
5
+ * `p % 4 === 3`.
6
+ *
7
+ * @module
8
+ */
1
9
  import type { Unary, Reduce } from '../bigint/module.f.ts';
2
10
  /**
3
11
  * A type representing a prime field and its associated operations.
@@ -1,3 +1,10 @@
1
+ /**
2
+ * TypeScript source-emitter helpers: the `Equal`/`Assert` compile-time
3
+ * predicates and a `Printer` that renders tuples, structs, arrays, records,
4
+ * primitive literals, and unions as TypeScript type expressions.
5
+ *
6
+ * @module
7
+ */
1
8
  export type Equal<A, B> = (<T>() => T extends A ? 1 : 2) extends (<T>() => T extends B ? 1 : 2) ? true : false;
2
9
  export type Assert<T extends true> = T;
3
10
  /** Functions for emitting TypeScript type expression strings. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "**/*.js",
@@ -15,7 +15,8 @@
15
15
  "start": "node ./fs/fjs/module.ts",
16
16
  "ci-update": "node ./fs/fjs/module.ts r ./fs/ci/module.f.ts",
17
17
  "update": "npm install && npm run index && npm run ci-update",
18
- "website": "node --experimental-strip-types ./fs/fjs/module.ts r ./fs/website/module.f.ts"
18
+ "index-html": "node --experimental-strip-types ./fs/fjs/module.ts r ./fs/website/module.f.ts",
19
+ "website": "npm run prepack &&npm run index-html"
19
20
  },
20
21
  "engines": {
21
22
  "node": ">=22"
@@ -1,8 +0,0 @@
1
- /**
2
- * Virtual I/O adapter implementations for deterministic testing.
3
- *
4
- * @module
5
- */
6
- import type { Io } from '../module.f.ts';
7
- import { type OrderedMap } from '../../types/ordered_map/module.f.ts';
8
- export declare const createVirtualIo: (files: OrderedMap<Uint8Array>) => Io;
@@ -1,43 +0,0 @@
1
- import { at } from "../../types/ordered_map/module.f.js";
2
- import { todo } from "../../dev/module.f.js";
3
- export const createVirtualIo = (files) => ({
4
- console: {
5
- log: (..._d) => { },
6
- error: (..._d) => { }
7
- },
8
- fs: {
9
- writeSync: (_fd, _s) => { },
10
- writeFileSync: (_file, _data) => { },
11
- readFileSync: (path) => { return at(path)(files); },
12
- promises: {
13
- readdir: (_path) => Promise.resolve([]),
14
- readFile: (_path) => Promise.resolve(new Uint8Array()),
15
- writeFile: (_path, _data) => Promise.resolve(),
16
- rm: (_path, _options) => Promise.resolve(),
17
- mkdir: (_path, _options) => Promise.resolve(undefined),
18
- copyFile: (_src, _dest) => Promise.resolve(),
19
- access: (_path) => Promise.resolve(),
20
- }
21
- },
22
- process: {
23
- argv: [],
24
- env: {},
25
- exit: n => { throw n; },
26
- cwd: () => '',
27
- stdout: { fd: 1, isTTY: false },
28
- stderr: { fd: 2, isTTY: false },
29
- },
30
- asyncImport: () => Promise.reject(),
31
- performance: {
32
- now: () => 0,
33
- },
34
- fetch: () => Promise.reject(),
35
- tryCatch: f => ['ok', f()],
36
- asyncTryCatch: async (f) => ['ok', await f()],
37
- http: {
38
- createServer: todo
39
- },
40
- childProcess: {
41
- exec: todo,
42
- },
43
- });