functionalscript 0.25.0 → 0.27.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/cas/module.f.d.ts +2 -10
- package/fs/cas/module.f.js +48 -52
- package/fs/cas/proof.f.js +21 -12
- package/fs/ci/config/module.f.d.ts +1 -1
- package/fs/ci/config/module.f.js +1 -1
- package/fs/ci/module.f.d.ts +1 -2
- package/fs/ci/module.f.js +39 -16
- package/fs/ci/proof.f.d.ts +9 -0
- package/fs/ci/proof.f.js +58 -6
- package/fs/cli/module.f.d.ts +9 -0
- package/fs/cli/module.f.js +24 -0
- package/fs/cli/proof.f.d.ts +9 -0
- package/fs/cli/proof.f.js +86 -0
- package/fs/dev/index/module.f.d.ts +1 -8
- package/fs/dev/index/module.f.js +1 -1
- package/fs/dev/package_json/module.f.d.ts +16 -0
- package/fs/dev/package_json/module.f.js +21 -0
- package/fs/dev/package_json/proof.f.d.ts +5 -0
- package/fs/dev/package_json/proof.f.js +23 -0
- package/fs/dev/version/module.f.js +10 -4
- package/fs/effects/node/module.f.d.ts +1 -1
- package/fs/emergent_testing/module.f.d.ts +1 -1
- package/fs/emergent_testing/module.f.js +2 -2
- package/fs/emergent_testing/proof.f.js +1 -1
- package/fs/fjs/module.f.js +34 -24
- package/fs/website/module.f.d.ts +1 -2
- package/fs/website/module.f.js +1 -1
- package/fs/website/proof.f.d.ts +1 -1
- package/fs/website/proof.f.js +3 -3
- package/package.json +2 -2
package/fs/cas/module.f.d.ts
CHANGED
|
@@ -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>;
|
package/fs/cas/module.f.js
CHANGED
|
@@ -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
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
114
|
-
|
|
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
|
}
|
|
@@ -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.
|
|
31
|
+
export declare const tsgo = "7.0.0-dev.20260606.1";
|
|
32
32
|
export declare const actions: {
|
|
33
33
|
readonly 'actions/checkout': "v6";
|
|
34
34
|
readonly 'actions/setup-node': "v6";
|
package/fs/ci/config/module.f.js
CHANGED
|
@@ -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.
|
|
39
|
+
export const tsgo = '7.0.0-dev.20260606.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]}` ``.
|
package/fs/ci/module.f.d.ts
CHANGED
|
@@ -7,5 +7,4 @@ export type Setup = {
|
|
|
7
7
|
readonly bunExtra: readonly MetaStep[];
|
|
8
8
|
};
|
|
9
9
|
export declare const ci: ({ nodeExtra, denoExtra, bunExtra }: Setup) => Effect<NodeOp, number>;
|
|
10
|
-
declare const
|
|
11
|
-
export default _default;
|
|
10
|
+
export declare const main: () => Effect<NodeOp, number>;
|
package/fs/ci/module.f.js
CHANGED
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import { utf8 } from "../text/module.f.js";
|
|
6
|
+
import { utf8, utf8ToString } from "../text/module.f.js";
|
|
7
|
+
import { validatePackageJsonText } from "../dev/package_json/module.f.js";
|
|
7
8
|
import { pure } from "../effects/module.f.js";
|
|
8
|
-
import { access, writeFile } from "../effects/node/module.f.js";
|
|
9
|
+
import { access, readFile, writeFile } from "../effects/node/module.f.js";
|
|
9
10
|
import { images } from "./config/module.f.js";
|
|
10
11
|
import { architecture, findTgz, os, test, toSteps } from "./common/module.f.js";
|
|
11
12
|
import { rustSteps } from "./rust/module.f.js";
|
|
@@ -24,6 +25,20 @@ const job = (rust, nodeExtra, denoExtra, bunExtra) => (o) => (a) => {
|
|
|
24
25
|
];
|
|
25
26
|
return [id, { 'runs-on': image, steps: toSteps(result) }];
|
|
26
27
|
};
|
|
28
|
+
const functionalscriptPackageName = 'functionalscript';
|
|
29
|
+
const fallbackPackageInfo = {
|
|
30
|
+
name: functionalscriptPackageName,
|
|
31
|
+
functionalscript: false,
|
|
32
|
+
};
|
|
33
|
+
const packageInfoFromPackageJson = ({ name }) => name !== undefined
|
|
34
|
+
? { name, functionalscript: name === functionalscriptPackageName }
|
|
35
|
+
: fallbackPackageInfo;
|
|
36
|
+
const packageInfoFromText = (text) => {
|
|
37
|
+
const result = validatePackageJsonText(text);
|
|
38
|
+
return result[0] === 'ok' ? packageInfoFromPackageJson(result[1]) : fallbackPackageInfo;
|
|
39
|
+
};
|
|
40
|
+
const readPackageInfo = readFile('package.json')
|
|
41
|
+
.step(result => pure(result[0] === 'ok' ? packageInfoFromText(utf8ToString(result[1])) : fallbackPackageInfo));
|
|
27
42
|
export const ci = ({ nodeExtra, denoExtra, bunExtra }) => access('Cargo.toml').step(result => {
|
|
28
43
|
const rust = result[0] === 'ok';
|
|
29
44
|
const jobs = {
|
|
@@ -42,21 +57,29 @@ export const ci = ({ nodeExtra, denoExtra, bunExtra }) => access('Cargo.toml').s
|
|
|
42
57
|
return writeFile('.github/workflows/ci.yml', utf8(JSON.stringify(gha, null, ' ')))
|
|
43
58
|
.step(() => pure(0));
|
|
44
59
|
});
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
60
|
+
const demoCompile = [
|
|
61
|
+
test({ run: 'fjs compile issues/demo/data/tree.json _tree.f.js' }),
|
|
62
|
+
test({ run: 'fjs t' }),
|
|
63
|
+
];
|
|
64
|
+
const denoDemoCompile = [
|
|
65
|
+
test({ run: 'deno task fjs compile issues/demo/data/tree.json _tree.f.js' }),
|
|
66
|
+
test({ run: 'deno task fjs t' }),
|
|
67
|
+
];
|
|
68
|
+
const bunDemoCompile = [
|
|
69
|
+
test({ run: 'bun ./fs/fjs/module.ts t' }),
|
|
70
|
+
];
|
|
71
|
+
const defaultNodeExtra = ({ name, functionalscript }) => (o) => [
|
|
72
|
+
test({ run: 'npm pack' }),
|
|
73
|
+
test({ run: `npm install -g ${findTgz(o)}` }),
|
|
74
|
+
...(functionalscript ? demoCompile : []),
|
|
75
|
+
test({ run: `npm uninstall ${name} -g` }),
|
|
76
|
+
];
|
|
77
|
+
const defaultEffect = (info) => ci({
|
|
78
|
+
nodeExtra: defaultNodeExtra(info),
|
|
53
79
|
denoExtra: [
|
|
54
|
-
|
|
55
|
-
test({ run: 'deno task fjs t' }),
|
|
80
|
+
...(info.functionalscript ? denoDemoCompile : []),
|
|
56
81
|
test({ run: 'deno publish --dry-run --allow-slow-types' }),
|
|
57
82
|
],
|
|
58
|
-
bunExtra: [
|
|
59
|
-
test({ run: 'bun ./fs/fjs/module.ts t' }),
|
|
60
|
-
]
|
|
83
|
+
bunExtra: info.functionalscript ? bunDemoCompile : [],
|
|
61
84
|
});
|
|
62
|
-
export
|
|
85
|
+
export const main = () => readPackageInfo.step(defaultEffect);
|
package/fs/ci/proof.f.d.ts
CHANGED
|
@@ -5,4 +5,13 @@ export declare const proof: {
|
|
|
5
5
|
allOs: () => void;
|
|
6
6
|
osSpecific: () => void;
|
|
7
7
|
};
|
|
8
|
+
defaultSetup: {
|
|
9
|
+
functionalscriptDemo: () => void;
|
|
10
|
+
otherPackageNoDemo: () => void;
|
|
11
|
+
uninstallPackageName: () => void;
|
|
12
|
+
malformedPackageJsonFallback: () => void;
|
|
13
|
+
missingPackageJsonFallback: () => void;
|
|
14
|
+
missingNameFallback: () => void;
|
|
15
|
+
nonObjectFallback: () => void;
|
|
16
|
+
};
|
|
8
17
|
};
|
package/fs/ci/proof.f.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ci } from "./module.f.js";
|
|
2
|
-
import { utf8ToString } from "../text/module.f.js";
|
|
1
|
+
import { ci, main } from "./module.f.js";
|
|
2
|
+
import { utf8, utf8ToString } from "../text/module.f.js";
|
|
3
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";
|
|
@@ -8,16 +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 makeState = (rust) => ({
|
|
11
|
+
const makeState = (rust, packageJson) => ({
|
|
12
12
|
...emptyState,
|
|
13
13
|
root: {
|
|
14
14
|
'.github': { workflows: {} },
|
|
15
|
+
...(packageJson !== undefined ? { 'package.json': utf8(packageJson) } : {}),
|
|
15
16
|
...(rust ? { 'Cargo.toml': emptyVec } : {}),
|
|
16
17
|
},
|
|
17
18
|
});
|
|
18
|
-
const
|
|
19
|
-
const [state, result] = virtual(makeState(rust))(ci({ nodeExtra, denoExtra: [], bunExtra: [] }));
|
|
20
|
-
assert(result === 0, result);
|
|
19
|
+
const workflow = (state) => {
|
|
21
20
|
const dotGithub = state.root['.github'];
|
|
22
21
|
assert(typeof dotGithub === 'object', dotGithub);
|
|
23
22
|
const workflows = dotGithub['workflows'];
|
|
@@ -26,6 +25,16 @@ const run = (rust, nodeExtra = () => []) => {
|
|
|
26
25
|
assert(isVec(file), file);
|
|
27
26
|
return unwrap(parseGitHubAction(jsonParse(utf8ToString(file))));
|
|
28
27
|
};
|
|
28
|
+
const run = (rust, nodeExtra = () => []) => {
|
|
29
|
+
const [state, result] = virtual(makeState(rust))(ci({ nodeExtra, denoExtra: [], bunExtra: [] }));
|
|
30
|
+
assert(result === 0, result);
|
|
31
|
+
return workflow(state);
|
|
32
|
+
};
|
|
33
|
+
const runDefault = (packageJson) => {
|
|
34
|
+
const [state, result] = virtual(makeState(false, packageJson))(main());
|
|
35
|
+
assert(result === 0, result);
|
|
36
|
+
return workflow(state);
|
|
37
|
+
};
|
|
29
38
|
export const proof = {
|
|
30
39
|
rust: () => {
|
|
31
40
|
assert(hasRun('cargo')(run(true)), 'expected Rust steps');
|
|
@@ -52,4 +61,47 @@ export const proof = {
|
|
|
52
61
|
}
|
|
53
62
|
},
|
|
54
63
|
},
|
|
64
|
+
defaultSetup: {
|
|
65
|
+
functionalscriptDemo: () => {
|
|
66
|
+
const gha = runDefault('{"name":"functionalscript"}');
|
|
67
|
+
assert(hasRun('fjs compile issues/demo/data/tree.json _tree.f.js')(gha), 'expected fjs demo compile');
|
|
68
|
+
assert(hasRun('fjs t')(gha), 'expected fjs self-test');
|
|
69
|
+
assert(hasRun('deno task fjs compile issues/demo/data/tree.json _tree.f.js')(gha), 'expected deno demo compile');
|
|
70
|
+
assert(hasRun('deno task fjs t')(gha), 'expected deno self-test');
|
|
71
|
+
assert(hasRun('bun ./fs/fjs/module.ts t')(gha), 'expected bun self-test');
|
|
72
|
+
},
|
|
73
|
+
otherPackageNoDemo: () => {
|
|
74
|
+
const gha = runDefault('{"name":"other-package"}');
|
|
75
|
+
assert(!hasRun('fjs compile issues/demo/data/tree.json _tree.f.js')(gha), 'unexpected fjs demo compile');
|
|
76
|
+
assert(!hasRun('fjs t')(gha), 'unexpected fjs self-test');
|
|
77
|
+
assert(!hasRun('deno task fjs compile issues/demo/data/tree.json _tree.f.js')(gha), 'unexpected deno demo compile');
|
|
78
|
+
assert(!hasRun('deno task fjs t')(gha), 'unexpected deno self-test');
|
|
79
|
+
assert(!hasRun('bun ./fs/fjs/module.ts t')(gha), 'unexpected bun self-test');
|
|
80
|
+
},
|
|
81
|
+
uninstallPackageName: () => {
|
|
82
|
+
const gha = runDefault('{"name":"other-package"}');
|
|
83
|
+
assert(hasRun('npm uninstall other-package -g')(gha), 'expected package-specific uninstall');
|
|
84
|
+
assert(!hasRun('npm uninstall functionalscript -g')(gha), 'unexpected functionalscript uninstall');
|
|
85
|
+
},
|
|
86
|
+
malformedPackageJsonFallback: () => {
|
|
87
|
+
const gha = runDefault('{');
|
|
88
|
+
assert(!hasRun('fjs compile issues/demo/data/tree.json _tree.f.js')(gha), 'unexpected fjs demo compile');
|
|
89
|
+
assert(hasRun('npm uninstall functionalscript -g')(gha), 'expected fallback uninstall');
|
|
90
|
+
},
|
|
91
|
+
missingPackageJsonFallback: () => {
|
|
92
|
+
const gha = runDefault();
|
|
93
|
+
assert(!hasRun('fjs compile issues/demo/data/tree.json _tree.f.js')(gha), 'unexpected fjs demo compile');
|
|
94
|
+
assert(hasRun('npm uninstall functionalscript -g')(gha), 'expected fallback uninstall');
|
|
95
|
+
},
|
|
96
|
+
missingNameFallback: () => {
|
|
97
|
+
const gha = runDefault('{"version":"1.0.0"}');
|
|
98
|
+
assert(!hasRun('fjs compile issues/demo/data/tree.json _tree.f.js')(gha), 'unexpected fjs demo compile');
|
|
99
|
+
assert(hasRun('npm uninstall functionalscript -g')(gha), 'expected fallback uninstall');
|
|
100
|
+
},
|
|
101
|
+
nonObjectFallback: () => {
|
|
102
|
+
const gha = runDefault('[]');
|
|
103
|
+
assert(!hasRun('fjs compile issues/demo/data/tree.json _tree.f.js')(gha), 'unexpected fjs demo compile');
|
|
104
|
+
assert(hasRun('npm uninstall functionalscript -g')(gha), 'expected fallback uninstall');
|
|
105
|
+
},
|
|
106
|
+
},
|
|
55
107
|
};
|
|
@@ -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,86 @@
|
|
|
1
|
+
import { pure } from "../effects/module.f.js";
|
|
2
|
+
import {} from "../effects/node/module.f.js";
|
|
3
|
+
import { emptyState, virtual } from "../effects/node/virtual/module.f.js";
|
|
4
|
+
import { dispatch } from "./module.f.js";
|
|
5
|
+
const makeOptions = (args) => ({
|
|
6
|
+
args,
|
|
7
|
+
env: {},
|
|
8
|
+
std: { stdout: { isTTY: false }, stderr: { isTTY: false } },
|
|
9
|
+
testContext: { test: async () => { } },
|
|
10
|
+
bunTestContext: { test: async () => { } },
|
|
11
|
+
playwrightTestContext: { test: async () => { } },
|
|
12
|
+
engine: 'node',
|
|
13
|
+
});
|
|
14
|
+
const echoCommands = [
|
|
15
|
+
{
|
|
16
|
+
names: ['echo', 'e'],
|
|
17
|
+
description: 'Print the first argument',
|
|
18
|
+
handler: ({ args: [arg = ''] }) => pure(arg.length),
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
const run = (commands) => (args) => virtual(emptyState)(dispatch(commands)(makeOptions(args)));
|
|
22
|
+
export const proof = {
|
|
23
|
+
knownCommand: () => {
|
|
24
|
+
const [, code] = run(echoCommands)(['echo', 'hello']);
|
|
25
|
+
if (code !== 5) {
|
|
26
|
+
throw ['expected length 5', code];
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
alias: () => {
|
|
30
|
+
const [, code] = run(echoCommands)(['e', 'hi']);
|
|
31
|
+
if (code !== 2) {
|
|
32
|
+
throw ['expected length 2', code];
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
noArgs: () => {
|
|
36
|
+
const [state, code] = run(echoCommands)([]);
|
|
37
|
+
if (code !== 1) {
|
|
38
|
+
throw ['expected exit 1', code];
|
|
39
|
+
}
|
|
40
|
+
if (state.stderr.length === 0) {
|
|
41
|
+
throw 'expected error in stderr';
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
unknownCommand: () => {
|
|
45
|
+
const [state, code] = run(echoCommands)(['bogus']);
|
|
46
|
+
if (code !== 1) {
|
|
47
|
+
throw ['expected exit 1', code];
|
|
48
|
+
}
|
|
49
|
+
if (state.stderr.length === 0) {
|
|
50
|
+
throw 'expected error in stderr';
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
help: () => {
|
|
54
|
+
const [state, code] = run(echoCommands)(['help']);
|
|
55
|
+
if (code !== 0) {
|
|
56
|
+
throw ['expected exit 0', code];
|
|
57
|
+
}
|
|
58
|
+
if (!state.stdout.includes('echo')) {
|
|
59
|
+
throw 'expected command name in stdout';
|
|
60
|
+
}
|
|
61
|
+
if (!state.stdout.includes('help')) {
|
|
62
|
+
throw 'expected help entry in stdout';
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
errorIncludesAvailable: () => {
|
|
66
|
+
const [state] = run(echoCommands)(['bogus']);
|
|
67
|
+
if (!state.stderr.includes('echo')) {
|
|
68
|
+
throw 'expected available commands in error';
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
handlerReceivesRemainingArgs: () => {
|
|
72
|
+
const captured = [];
|
|
73
|
+
const commands = [{
|
|
74
|
+
names: ['grab'],
|
|
75
|
+
description: 'Capture args',
|
|
76
|
+
handler: ({ args }) => {
|
|
77
|
+
captured.push(...args);
|
|
78
|
+
return pure(0);
|
|
79
|
+
},
|
|
80
|
+
}];
|
|
81
|
+
run(commands)(['grab', 'a', 'b', 'c']);
|
|
82
|
+
if (captured.join(',') !== 'a,b,c') {
|
|
83
|
+
throw ['unexpected args', captured];
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
};
|
|
@@ -1,8 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Entry point for the `index` developer program: re-exports `index4` from the
|
|
3
|
-
* parent `dev` module as the default `NodeProgram`.
|
|
4
|
-
*
|
|
5
|
-
* @module
|
|
6
|
-
*/
|
|
7
|
-
import { index4 } from '../module.f.ts';
|
|
8
|
-
export default index4;
|
|
1
|
+
export declare const main: import("../../effects/node/module.f.ts").NodeProgram;
|
package/fs/dev/index/module.f.js
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ValidationError } from '../../types/rtti/validate/module.f.ts';
|
|
2
|
+
import type { Ts } from '../../types/rtti/ts/module.f.ts';
|
|
3
|
+
import { type Result } from '../../types/result/module.f.ts';
|
|
4
|
+
export declare const packageJsonSchema: {
|
|
5
|
+
readonly name: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").String, undefined]>;
|
|
6
|
+
readonly version: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").String, undefined]>;
|
|
7
|
+
readonly scripts: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Type1<"record", import("../../types/rtti/module.f.ts").String>, undefined]>;
|
|
8
|
+
};
|
|
9
|
+
export type PackageJson = Ts<typeof packageJsonSchema>;
|
|
10
|
+
export type JsonTextError = string | ValidationError;
|
|
11
|
+
export declare const validatePackageJson: import("../../types/rtti/common/module.f.ts").Validate<{
|
|
12
|
+
readonly name: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").String, undefined]>;
|
|
13
|
+
readonly version: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").String, undefined]>;
|
|
14
|
+
readonly scripts: import("../../types/rtti/module.f.ts").Or<readonly [import("../../types/rtti/module.f.ts").Type1<"record", import("../../types/rtti/module.f.ts").String>, undefined]>;
|
|
15
|
+
}>;
|
|
16
|
+
export declare const validatePackageJsonText: (text: string) => Result<PackageJson, JsonTextError>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { parse as jsonParse } from "../../json/parser/module.f.js";
|
|
2
|
+
import { tokenize as jsonTokenize } from "../../json/tokenizer/module.f.js";
|
|
3
|
+
import { stringToList } from "../../text/utf16/module.f.js";
|
|
4
|
+
import { option, record, string } from "../../types/rtti/module.f.js";
|
|
5
|
+
import { validate as rttiValidate } from "../../types/rtti/validate/module.f.js";
|
|
6
|
+
import { error, ok } from "../../types/result/module.f.js";
|
|
7
|
+
export const packageJsonSchema = {
|
|
8
|
+
name: option(string),
|
|
9
|
+
version: option(string),
|
|
10
|
+
scripts: option(record(string)),
|
|
11
|
+
};
|
|
12
|
+
export const validatePackageJson = rttiValidate(packageJsonSchema);
|
|
13
|
+
const parseJsonText = (text) => jsonParse(jsonTokenize(stringToList(text)));
|
|
14
|
+
export const validatePackageJsonText = (text) => {
|
|
15
|
+
const [t, v] = parseJsonText(text);
|
|
16
|
+
if (t === 'error') {
|
|
17
|
+
return error(v);
|
|
18
|
+
}
|
|
19
|
+
const [t2, v2] = validatePackageJson(v);
|
|
20
|
+
return t2 === 'ok' ? ok(v2) : error(v2);
|
|
21
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { assert } from "../../asserts/module.f.js";
|
|
2
|
+
import { unwrap } from "../../types/result/module.f.js";
|
|
3
|
+
import { validatePackageJson, validatePackageJsonText, } from "./module.f.js";
|
|
4
|
+
export const proof = {
|
|
5
|
+
parseMetadata: () => {
|
|
6
|
+
const result = unwrap(validatePackageJsonText('{"name":"x","version":"1.0.0","scripts":{"test":"node test.js"}}'));
|
|
7
|
+
assert(result.name === 'x', result);
|
|
8
|
+
assert(result.version === '1.0.0', result);
|
|
9
|
+
assert(result.scripts?.test === 'node test.js', result);
|
|
10
|
+
},
|
|
11
|
+
malformedJson: () => {
|
|
12
|
+
const result = validatePackageJsonText('{');
|
|
13
|
+
assert(result[0] === 'error', result);
|
|
14
|
+
},
|
|
15
|
+
validatePreservesOriginalObject: () => {
|
|
16
|
+
const object = { name: 'x', version: '1.0.0', private: true };
|
|
17
|
+
const metadata = unwrap(validatePackageJson(object));
|
|
18
|
+
assert(metadata.name === 'x', metadata);
|
|
19
|
+
assert(metadata.version === '1.0.0', metadata);
|
|
20
|
+
assert(Object.is(metadata, object), metadata);
|
|
21
|
+
assert(object.private === true, object);
|
|
22
|
+
},
|
|
23
|
+
};
|
|
@@ -7,21 +7,27 @@ import { utf8, utf8ToString } from "../../text/module.f.js";
|
|
|
7
7
|
import { begin, pure } from "../../effects/module.f.js";
|
|
8
8
|
import { all, readFile, writeFile } from "../../effects/node/module.f.js";
|
|
9
9
|
import { unwrap } from "../../types/result/module.f.js";
|
|
10
|
-
|
|
10
|
+
import { validatePackageJson } from "../package_json/module.f.js";
|
|
11
|
+
import { assert } from "../../asserts/module.f.js";
|
|
12
|
+
const { parse, stringify } = JSON;
|
|
11
13
|
const jsonFile = (jsonFile) => `${jsonFile}.json`;
|
|
12
14
|
const readJson = (name) => begin
|
|
13
15
|
.step(() => readFile(jsonFile(name)))
|
|
14
|
-
.step(v => pure(parse(utf8ToString(unwrap(v)))));
|
|
16
|
+
.step(v => pure(unwrap(validatePackageJson(parse(utf8ToString(unwrap(v)))))));
|
|
15
17
|
const writeVersion = (version) => (name) => begin
|
|
16
18
|
.step(() => readJson(name))
|
|
17
|
-
.step(json => writeFile(jsonFile(name), utf8(stringify({
|
|
19
|
+
.step((json) => writeFile(jsonFile(name), utf8(stringify({
|
|
18
20
|
...json,
|
|
19
21
|
version,
|
|
20
22
|
}, null, 2))));
|
|
23
|
+
const version = (p) => {
|
|
24
|
+
assert(p.version !== undefined, 'package.json version is missing');
|
|
25
|
+
return p.version;
|
|
26
|
+
};
|
|
21
27
|
export const updateVersion = begin
|
|
22
28
|
.step(() => readJson('package'))
|
|
23
29
|
.step(p => {
|
|
24
|
-
const w = writeVersion(p
|
|
30
|
+
const w = writeVersion(version(p));
|
|
25
31
|
return all(w('package'), w('deno'));
|
|
26
32
|
})
|
|
27
33
|
.step(() => pure(0));
|
|
@@ -166,7 +166,7 @@ export type NodeEffect<T> = Effect<NodeOp, T>;
|
|
|
166
166
|
* "fail with a message" program for a `NodeProgram`. For non-`1` exit codes,
|
|
167
167
|
* compose `error(s).step(() => pure(n))` directly.
|
|
168
168
|
*/
|
|
169
|
-
export declare const errorExit: (s: string) => Effect<
|
|
169
|
+
export declare const errorExit: (s: string) => Effect<Write, number>;
|
|
170
170
|
export type NodeOperationMap = ToAsyncOperationMap<NodeOp>;
|
|
171
171
|
/**
|
|
172
172
|
* The environment variables.
|
|
@@ -117,7 +117,7 @@ export declare const defaultTest: (file: string, path: Path, { fn, throws }: Tes
|
|
|
117
117
|
/**
|
|
118
118
|
* The terminal/GitHub reporter used by `fjs t`. Output goes through
|
|
119
119
|
* `csiWrite`, so ANSI styles are stripped on non-TTY streams. When
|
|
120
|
-
* `
|
|
120
|
+
* `GITHUB_ACTIONS` is set, failures are emitted as `::error` workflow
|
|
121
121
|
* annotations instead of colored lines. Exported as a factory so the
|
|
122
122
|
* GitHub format path can be exercised directly from tests.
|
|
123
123
|
*/
|
|
@@ -220,7 +220,7 @@ const fmtResultLine = (file, path, color, label, duration) => `${fmtImport(file,
|
|
|
220
220
|
/**
|
|
221
221
|
* The terminal/GitHub reporter used by `fjs t`. Output goes through
|
|
222
222
|
* `csiWrite`, so ANSI styles are stripped on non-TTY streams. When
|
|
223
|
-
* `
|
|
223
|
+
* `GITHUB_ACTIONS` is set, failures are emitted as `::error` workflow
|
|
224
224
|
* annotations instead of colored lines. Exported as a factory so the
|
|
225
225
|
* GitHub format path can be exercised directly from tests.
|
|
226
226
|
*/
|
|
@@ -232,7 +232,7 @@ export const defaultReporter = (options) => {
|
|
|
232
232
|
};
|
|
233
233
|
const csiLog = line('stdout');
|
|
234
234
|
const csiError = line('stderr');
|
|
235
|
-
const isGitHub = options.env['
|
|
235
|
+
const isGitHub = options.env['GITHUB_ACTIONS'] !== undefined;
|
|
236
236
|
return {
|
|
237
237
|
// https://github.com/OndraM/ci-detector/blob/main/src/Ci/GitHubActions.php
|
|
238
238
|
result: (file, path, { result: [s, v], duration }, throws) => s === 'ok'
|
|
@@ -17,7 +17,7 @@ const makeReporter = () => {
|
|
|
17
17
|
const noopTestContext = { test: todo };
|
|
18
18
|
const options = (initCwd, github = false) => ({
|
|
19
19
|
args: [],
|
|
20
|
-
env: { INIT_CWD: initCwd, ...(github ? {
|
|
20
|
+
env: { INIT_CWD: initCwd, ...(github ? { GITHUB_ACTIONS: 'true' } : {}) },
|
|
21
21
|
std: { stdout: { isTTY: false }, stderr: { isTTY: false } },
|
|
22
22
|
testContext: noopTestContext,
|
|
23
23
|
bunTestContext: noopTestContext,
|
package/fs/fjs/module.f.js
CHANGED
|
@@ -6,32 +6,42 @@
|
|
|
6
6
|
import { compile } from "../djs/module.f.js";
|
|
7
7
|
import { main as testMain } from "../emergent_testing/module.f.js";
|
|
8
8
|
import { main as casMain } from "../cas/module.f.js";
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
9
|
+
import { main as ciMain } from "../ci/module.f.js";
|
|
10
|
+
import { import_ } from "../effects/node/module.f.js";
|
|
11
|
+
import { dispatch } from "../cli/module.f.js";
|
|
12
|
+
const commands = [
|
|
13
|
+
{
|
|
14
|
+
names: ['test', 't'],
|
|
15
|
+
description: 'Run the FunctionalScript test suite',
|
|
16
|
+
handler: testMain,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
names: ['compile', 'c'],
|
|
20
|
+
description: 'Compile a FunctionalScript module to JavaScript',
|
|
21
|
+
handler: ({ args }) => compile(args),
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
names: ['cas', 's'],
|
|
25
|
+
description: 'Content-addressable storage operations',
|
|
26
|
+
handler: casMain,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
names: ['ci', 'i'],
|
|
30
|
+
description: 'Generate the GitHub Actions CI workflow',
|
|
31
|
+
handler: ciMain,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
names: ['run', 'r'],
|
|
35
|
+
description: 'Run a FunctionalScript module as a NodeProgram',
|
|
36
|
+
handler: options => {
|
|
37
|
+
const [file, ...args] = options.args;
|
|
25
38
|
return import_(file).step(([s, v]) => {
|
|
26
39
|
if (s === 'error') {
|
|
27
40
|
throw v;
|
|
28
41
|
}
|
|
29
|
-
return v.
|
|
42
|
+
return v.main({ ...options, args });
|
|
30
43
|
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return errorExit(`Error: Unknown command "${command}"`);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
export const main = dispatch(commands);
|
package/fs/website/module.f.d.ts
CHANGED
package/fs/website/module.f.js
CHANGED
package/fs/website/proof.f.d.ts
CHANGED
package/fs/website/proof.f.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { main } from "./module.f.js";
|
|
2
2
|
export const proof = {
|
|
3
|
-
|
|
4
|
-
const program =
|
|
3
|
+
main: () => {
|
|
4
|
+
const program = main();
|
|
5
5
|
if (program === undefined) {
|
|
6
6
|
throw 'expected a program effect';
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "functionalscript",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"**/*.js",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"cov": "node --test --experimental-test-coverage --test-coverage-include=**/module.f.ts",
|
|
14
14
|
"index": "node ./fs/fjs/module.ts r ./fs/dev/index/module.f.ts",
|
|
15
15
|
"start": "node ./fs/fjs/module.ts",
|
|
16
|
-
"ci-update": "node ./fs/fjs/module.ts
|
|
16
|
+
"ci-update": "node ./fs/fjs/module.ts ci",
|
|
17
17
|
"update": "npm install && npm run index && npm run ci-update",
|
|
18
18
|
"index-html": "node ./fs/fjs/module.ts r ./fs/website/module.f.ts",
|
|
19
19
|
"website": "npm run prepack &&npm run index-html"
|