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.
- package/fs/asn.1/module.f.js +6 -0
- package/fs/ci/bun/module.f.js +6 -0
- package/fs/ci/common/module.f.d.ts +7 -0
- package/fs/ci/common/module.f.js +7 -0
- package/fs/ci/config/module.f.d.ts +7 -0
- package/fs/ci/config/module.f.js +7 -0
- package/fs/ci/deno/module.f.js +6 -0
- package/fs/ci/node/module.f.js +6 -0
- package/fs/ci/playwright/module.f.js +7 -2
- package/fs/ci/rust/module.f.js +7 -0
- package/fs/crypto/secp/module.f.d.ts +7 -0
- package/fs/dev/index/module.f.d.ts +6 -0
- package/fs/dev/index/module.f.js +6 -0
- package/fs/dev/module.f.d.ts +2 -1
- package/fs/dev/module.f.js +3 -4
- package/fs/dev/tf/module.f.d.ts +3 -19
- package/fs/dev/tf/module.f.js +25 -36
- package/fs/dev/tf/module.js +4 -3
- package/fs/djs/module.f.d.ts +5 -2
- package/fs/djs/module.f.js +13 -21
- package/fs/djs/test.f.d.ts +11 -0
- package/fs/djs/test.f.js +75 -0
- package/fs/djs/transpiler/module.f.d.ts +3 -3
- package/fs/djs/transpiler/module.f.js +34 -29
- package/fs/djs/transpiler/test.f.js +20 -26
- package/fs/fjs/module.f.js +10 -4
- package/fs/html/module.f.d.ts +6 -0
- package/fs/html/module.f.js +6 -0
- package/fs/io/module.f.d.ts +5 -2
- package/fs/io/module.f.js +14 -3
- package/fs/io/module.js +19 -1
- package/fs/js/tokenizer/module.f.js +7 -0
- package/fs/json/module.f.d.ts +7 -0
- package/fs/json/module.f.js +7 -0
- package/fs/text/module.f.d.ts +7 -0
- package/fs/text/module.f.js +7 -0
- package/fs/text/utf16/module.f.d.ts +7 -0
- package/fs/text/utf16/module.f.js +7 -0
- package/fs/types/effects/node/module.f.d.ts +46 -2
- package/fs/types/effects/node/module.f.js +20 -0
- package/fs/types/effects/node/test.f.d.ts +5 -0
- package/fs/types/effects/node/test.f.js +31 -1
- package/fs/types/effects/node/virtual/module.f.d.ts +1 -0
- package/fs/types/effects/node/virtual/module.f.js +12 -0
- package/fs/types/monoid/module.f.d.ts +7 -0
- package/fs/types/number/module.f.d.ts +6 -0
- package/fs/types/number/module.f.js +6 -0
- package/fs/types/object/module.f.js +7 -0
- package/fs/types/prime_field/module.f.d.ts +8 -0
- package/fs/types/ts/module.f.d.ts +7 -0
- package/package.json +3 -2
- package/fs/io/virtual/module.f.d.ts +0 -8
- 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 {
|
|
6
|
-
import { encodeUtf8 } from "../../types/uint8array/module.f.js";
|
|
7
|
-
const
|
|
8
|
-
|
|
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
|
|
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
|
|
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
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
|
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
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
}
|
package/fs/fjs/module.f.js
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
-
|
|
30
|
-
|
|
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);
|
package/fs/html/module.f.d.ts
CHANGED
|
@@ -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;
|
package/fs/html/module.f.js
CHANGED
|
@@ -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";
|
package/fs/io/module.f.d.ts
CHANGED
|
@@ -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) =>
|
|
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
|
-
|
|
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";
|
package/fs/json/module.f.d.ts
CHANGED
|
@@ -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 = {
|
package/fs/json/module.f.js
CHANGED
|
@@ -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";
|
package/fs/text/module.f.d.ts
CHANGED
|
@@ -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;
|
package/fs/text/module.f.js
CHANGED
|
@@ -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
|
|
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
|
|
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');
|
|
@@ -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
|
};
|
|
@@ -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.
|
|
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
|
-
"
|
|
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
|
-
});
|