functionalscript 0.38.0 → 0.40.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/README.md +1 -1
- package/fjs/bnf/descent/module.f.d.ts +43 -2
- package/fjs/bnf/descent/module.f.js +37 -12
- package/fjs/bnf/descent/proof.f.d.ts +1 -0
- package/fjs/bnf/descent/proof.f.js +73 -32
- package/fjs/bnf/ll1/module.f.js +2 -2
- package/fjs/bnf/token_symbol/module.f.d.ts +38 -0
- package/fjs/bnf/token_symbol/module.f.js +48 -0
- package/fjs/bnf/token_symbol/proof.f.d.ts +10 -0
- package/fjs/bnf/token_symbol/proof.f.js +37 -0
- package/fjs/cas/cli/module.f.js +6 -9
- package/fjs/cas/evo/module.f.d.ts +77 -13
- package/fjs/cas/evo/module.f.js +130 -18
- package/fjs/cas/evo/proof.f.d.ts +7 -0
- package/fjs/cas/evo/proof.f.js +120 -1
- package/fjs/cas/module.f.js +64 -37
- package/fjs/cas/proof.f.d.ts +3 -9
- package/fjs/cas/proof.f.js +94 -74
- package/fjs/ci/bun/module.f.js +3 -3
- package/fjs/ci/common/module.f.d.ts +1 -2
- package/fjs/ci/common/module.f.js +1 -5
- package/fjs/ci/config/module.f.d.ts +11 -8
- package/fjs/ci/config/module.f.js +24 -9
- package/fjs/ci/deno/module.f.js +3 -3
- package/fjs/ci/module.f.js +13 -7
- package/fjs/ci/nix/module.f.d.ts +61 -0
- package/fjs/ci/nix/module.f.js +92 -0
- package/fjs/ci/nix/proof.f.d.ts +23 -0
- package/fjs/ci/nix/proof.f.js +109 -0
- package/fjs/ci/node/module.f.d.ts +23 -1
- package/fjs/ci/node/module.f.js +58 -12
- package/fjs/ci/proof.f.d.ts +2 -0
- package/fjs/ci/proof.f.js +49 -9
- package/fjs/cli/module.f.js +2 -2
- package/fjs/common/monoid/module.f.d.ts +46 -2
- package/fjs/common/monoid/module.f.js +44 -0
- package/fjs/common/monoid/proof.f.d.ts +5 -0
- package/fjs/common/monoid/proof.f.js +27 -1
- package/fjs/dev/module.f.d.ts +1 -0
- package/fjs/dev/module.f.js +38 -27
- package/fjs/dev/update/module.f.d.ts +11 -0
- package/fjs/dev/update/module.f.js +20 -0
- package/fjs/dev/update/proof.f.d.ts +7 -0
- package/fjs/dev/update/proof.f.js +35 -0
- package/fjs/djs/ast/module.f.d.ts +47 -0
- package/fjs/djs/ast/module.f.js +9 -0
- package/fjs/djs/module.f.js +5 -8
- package/fjs/djs/parser/module.f.d.ts +3 -0
- package/fjs/djs/parser/module.f.js +17 -0
- package/fjs/djs/tokenizer/module.f.js +2 -2
- package/fjs/djs/tokenizer/proof.f.d.ts +1 -0
- package/fjs/djs/tokenizer/proof.f.js +70 -16
- package/fjs/djs/transpiler/module.f.js +6 -6
- package/fjs/effects/eff/module.f.d.ts +72 -0
- package/fjs/effects/eff/module.f.js +46 -0
- package/fjs/effects/eff/proof.f.d.ts +11 -0
- package/fjs/effects/eff/proof.f.js +58 -0
- package/fjs/effects/list/module.f.d.ts +11 -5
- package/fjs/effects/list/module.f.js +2 -1
- package/fjs/effects/memory/proof.f.js +7 -8
- package/fjs/effects/module.f.d.ts +334 -52
- package/fjs/effects/module.f.js +253 -45
- package/fjs/effects/node/memory/proof.js +3 -2
- package/fjs/effects/node/module.d.ts +3 -3
- package/fjs/effects/node/module.f.d.ts +18 -8
- package/fjs/effects/node/module.f.js +31 -11
- package/fjs/effects/node/module.js +12 -12
- package/fjs/effects/node/proof.f.d.ts +1 -0
- package/fjs/effects/node/proof.f.js +32 -11
- package/fjs/effects/node/virtual/module.f.js +1 -1
- package/fjs/effects/proof.f.d.ts +32 -6
- package/fjs/effects/proof.f.js +131 -39
- package/fjs/emergent_testing/all.test.js +2 -1
- package/fjs/emergent_testing/module.f.d.ts +3 -3
- package/fjs/emergent_testing/module.f.js +63 -49
- package/fjs/emergent_testing/proof.f.d.ts +4 -0
- package/fjs/emergent_testing/proof.f.js +54 -21
- package/fjs/emergent_testing/scenarios/thenable.pass.js +1 -1
- package/fjs/fsc/module.f.js +4 -4
- package/fjs/fsm/module.f.js +1 -1
- package/fjs/js/tokenizer/module.f.d.ts +1 -0
- package/fjs/js/tokenizer/module.f.js +13 -6
- package/fjs/{cas/mcp → mcp/cas}/module.f.d.ts +3 -25
- package/fjs/{cas/mcp → mcp/cas}/module.f.js +26 -64
- package/fjs/mcp/evo/module.f.d.ts +27 -0
- package/fjs/mcp/evo/module.f.js +94 -0
- package/fjs/{cas/evo/mcp → mcp/evo}/proof.f.d.ts +2 -0
- package/fjs/{cas/evo/mcp → mcp/evo}/proof.f.js +40 -9
- package/fjs/mcp/module.f.d.ts +54 -237
- package/fjs/mcp/module.f.js +55 -258
- package/fjs/mcp/proof.f.d.ts +43 -32
- package/fjs/mcp/proof.f.js +509 -200
- package/fjs/media/nix/module.f.d.ts +30 -0
- package/fjs/media/nix/module.f.js +166 -0
- package/fjs/media/nix/proof.f.d.ts +32 -0
- package/fjs/media/nix/proof.f.js +127 -0
- package/fjs/media/type/module.f.js +2 -2
- package/fjs/media/type/proof.f.js +7 -10
- package/fjs/module.f.js +5 -9
- package/fjs/protocol/json_rpc/module.f.d.ts +114 -0
- package/fjs/{media/json/rpc → protocol/json_rpc}/module.f.js +3 -3
- package/fjs/{media/json/rpc → protocol/json_rpc}/proof.f.js +3 -3
- package/fjs/protocol/mcp/module.f.d.ts +239 -0
- package/fjs/protocol/mcp/module.f.js +272 -0
- package/fjs/protocol/mcp/proof.f.d.ts +34 -0
- package/fjs/protocol/mcp/proof.f.js +208 -0
- package/fjs/{mcp → protocol/mcp}/stdio/module.f.d.ts +7 -7
- package/fjs/{mcp → protocol/mcp}/stdio/module.f.js +22 -22
- package/fjs/{mcp → protocol/mcp}/stdio/proof.f.js +9 -9
- package/fjs/types/bigint/module.f.js +4 -3
- package/fjs/types/bit_vec/module.f.js +5 -15
- package/fjs/types/btree/remove/module.f.d.ts +5 -0
- package/fjs/types/btree/remove/module.f.js +12 -0
- package/fjs/types/list/module.f.d.ts +21 -0
- package/fjs/types/list/module.f.js +17 -0
- package/fjs/types/list/proof.f.d.ts +1 -0
- package/fjs/types/list/proof.f.js +24 -1
- package/fjs/types/number/module.f.js +2 -1
- package/fjs/types/range_map/module.f.d.ts +14 -13
- package/fjs/types/range_map/module.f.js +18 -13
- package/fjs/types/range_map/proof.f.js +26 -39
- package/fjs/types/range_set/module.f.d.ts +5 -0
- package/fjs/types/range_set/module.f.js +16 -0
- package/fjs/types/range_set/proof.f.d.ts +1 -0
- package/fjs/types/range_set/proof.f.js +19 -0
- package/fjs/types/string/module.f.js +10 -2
- package/fjs/website/module.f.js +2 -3
- package/package.json +5 -5
- package/fjs/cas/evo/mcp/module.f.d.ts +0 -19
- package/fjs/cas/evo/mcp/module.f.js +0 -56
- package/fjs/cas/mcp/proof.f.d.ts +0 -45
- package/fjs/cas/mcp/proof.f.js +0 -545
- package/fjs/ci/playwright/module.f.d.ts +0 -2
- package/fjs/ci/playwright/module.f.js +0 -25
- package/fjs/media/json/rpc/module.f.d.ts +0 -114
- /package/fjs/{media/json/rpc → protocol/json_rpc}/proof.f.d.ts +0 -0
- /package/fjs/{mcp → protocol/mcp}/stdio/proof.f.d.ts +0 -0
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Monoids: the `Monoid<T>` algebraic structure (identity plus associative
|
|
3
|
-
* binary operation)
|
|
4
|
-
* exponentiation by squaring
|
|
3
|
+
* binary operation), `repeat`, which applies the operation `n` times using
|
|
4
|
+
* exponentiation by squaring, and `fold`, which applies it across every element
|
|
5
|
+
* of a list.
|
|
5
6
|
*
|
|
6
7
|
* @module
|
|
7
8
|
*/
|
|
8
9
|
import type { Fold, Reduce } from '../../types/function/operator/module.f.ts';
|
|
10
|
+
import { type List } from '../../types/list/module.f.ts';
|
|
9
11
|
/**
|
|
10
12
|
* Represents a monoid, an algebraic structure with a binary operation
|
|
11
13
|
* and an identity (neutral) element.
|
|
@@ -80,3 +82,45 @@ export type Monoid<T> = {
|
|
|
80
82
|
* ```
|
|
81
83
|
*/
|
|
82
84
|
export declare const repeat: <T>({ identity, operation }: Monoid<T>) => Fold<bigint, T>;
|
|
85
|
+
/**
|
|
86
|
+
* Reduces a `List<T>` with the monoid's associative `operation`, seeded at its
|
|
87
|
+
* `identity`. An empty list folds to `identity`.
|
|
88
|
+
*
|
|
89
|
+
* `fold` is the reduction companion of {@link repeat}: where `repeat` applies
|
|
90
|
+
* the operation a fixed number of times to a single element, `fold` applies it
|
|
91
|
+
* across every element of a list. Together they let list reductions such as
|
|
92
|
+
* `sum`, `product`, and string `concat` be expressed directly as monoid folds,
|
|
93
|
+
* so the identity paired with each operation is stated once at the call site
|
|
94
|
+
* instead of hand-seeding a raw `reduce`.
|
|
95
|
+
*
|
|
96
|
+
* Like `repeat`, `fold` applies the operation **accumulator-first**:
|
|
97
|
+
* `operation(accumulator)(element)`, seeded at `identity`, so
|
|
98
|
+
* `[a, b, c]` folds to `((identity op a) op b) op c`. Left-to-right order is
|
|
99
|
+
* therefore preserved and `fold` is correct for non-commutative monoids (e.g.
|
|
100
|
+
* string concatenation as `a => b => a + b`). `list.reduce` calls its reducer
|
|
101
|
+
* element-first, so the operation is `flip`ped before it is handed over.
|
|
102
|
+
*
|
|
103
|
+
* @template T The type of the elements in the monoid.
|
|
104
|
+
* @param monoid The monoid structure, including the identity and binary operation.
|
|
105
|
+
* @returns A function that reduces a `List<T>` to a single `T`.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
*
|
|
109
|
+
* ```ts
|
|
110
|
+
* const add: Monoid<number> = {
|
|
111
|
+
* identity: 0,
|
|
112
|
+
* operation: a => b => a + b,
|
|
113
|
+
* };
|
|
114
|
+
*
|
|
115
|
+
* fold(add)([1, 2, 3, 4]) // 10
|
|
116
|
+
* fold(add)([]) // 0
|
|
117
|
+
*
|
|
118
|
+
* const concat: Monoid<string> = {
|
|
119
|
+
* identity: '',
|
|
120
|
+
* operation: a => b => a + b,
|
|
121
|
+
* };
|
|
122
|
+
*
|
|
123
|
+
* fold(concat)(['a', 'b', 'c']) // 'abc' — order preserved
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
export declare const fold: <T>({ identity, operation }: Monoid<T>) => (list: List<T>) => T;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { reduce } from '../../types/list/module.f.js';
|
|
2
|
+
import { flip } from '../../types/function/module.f.js';
|
|
1
3
|
/**
|
|
2
4
|
* Repeats a monoid operation `n` times on the given element `a`.
|
|
3
5
|
* This function efficiently performs the operation using exponentiation by squaring.
|
|
@@ -42,3 +44,45 @@ export const repeat = ({ identity, operation }) => n => a => {
|
|
|
42
44
|
ai = operation(ai)(ai);
|
|
43
45
|
}
|
|
44
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* Reduces a `List<T>` with the monoid's associative `operation`, seeded at its
|
|
49
|
+
* `identity`. An empty list folds to `identity`.
|
|
50
|
+
*
|
|
51
|
+
* `fold` is the reduction companion of {@link repeat}: where `repeat` applies
|
|
52
|
+
* the operation a fixed number of times to a single element, `fold` applies it
|
|
53
|
+
* across every element of a list. Together they let list reductions such as
|
|
54
|
+
* `sum`, `product`, and string `concat` be expressed directly as monoid folds,
|
|
55
|
+
* so the identity paired with each operation is stated once at the call site
|
|
56
|
+
* instead of hand-seeding a raw `reduce`.
|
|
57
|
+
*
|
|
58
|
+
* Like `repeat`, `fold` applies the operation **accumulator-first**:
|
|
59
|
+
* `operation(accumulator)(element)`, seeded at `identity`, so
|
|
60
|
+
* `[a, b, c]` folds to `((identity op a) op b) op c`. Left-to-right order is
|
|
61
|
+
* therefore preserved and `fold` is correct for non-commutative monoids (e.g.
|
|
62
|
+
* string concatenation as `a => b => a + b`). `list.reduce` calls its reducer
|
|
63
|
+
* element-first, so the operation is `flip`ped before it is handed over.
|
|
64
|
+
*
|
|
65
|
+
* @template T The type of the elements in the monoid.
|
|
66
|
+
* @param monoid The monoid structure, including the identity and binary operation.
|
|
67
|
+
* @returns A function that reduces a `List<T>` to a single `T`.
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
*
|
|
71
|
+
* ```ts
|
|
72
|
+
* const add: Monoid<number> = {
|
|
73
|
+
* identity: 0,
|
|
74
|
+
* operation: a => b => a + b,
|
|
75
|
+
* };
|
|
76
|
+
*
|
|
77
|
+
* fold(add)([1, 2, 3, 4]) // 10
|
|
78
|
+
* fold(add)([]) // 0
|
|
79
|
+
*
|
|
80
|
+
* const concat: Monoid<string> = {
|
|
81
|
+
* identity: '',
|
|
82
|
+
* operation: a => b => a + b,
|
|
83
|
+
* };
|
|
84
|
+
*
|
|
85
|
+
* fold(concat)(['a', 'b', 'c']) // 'abc' — order preserved
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export const fold = ({ identity, operation }) => reduce(flip(operation))(identity);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { repeat } from "./module.f.js";
|
|
1
|
+
import { repeat, fold } from "./module.f.js";
|
|
2
2
|
import { assertEq } from '../../asserts/module.f.js';
|
|
3
3
|
export const proof = {
|
|
4
4
|
numberAdd: () => {
|
|
@@ -18,5 +18,31 @@ export const proof = {
|
|
|
18
18
|
};
|
|
19
19
|
const resultConcat = repeat(concat)(3n)('ha'); // 'hahaha'
|
|
20
20
|
assertEq(resultConcat, 'hahaha');
|
|
21
|
+
},
|
|
22
|
+
fold: {
|
|
23
|
+
nonEmpty: () => {
|
|
24
|
+
const add = {
|
|
25
|
+
identity: 0,
|
|
26
|
+
operation: a => b => a + b,
|
|
27
|
+
};
|
|
28
|
+
assertEq(fold(add)([1, 2, 3, 4]), 10);
|
|
29
|
+
},
|
|
30
|
+
order: () => {
|
|
31
|
+
// a non-commutative monoid: `fold` must preserve left-to-right order
|
|
32
|
+
// (`((('' + 'a') + 'b') + 'c')`), not reverse it to `'cba'`.
|
|
33
|
+
const concat = {
|
|
34
|
+
identity: '',
|
|
35
|
+
operation: a => b => a + b,
|
|
36
|
+
};
|
|
37
|
+
assertEq(fold(concat)(['a', 'b', 'c']), 'abc');
|
|
38
|
+
},
|
|
39
|
+
empty: () => {
|
|
40
|
+
const concat = {
|
|
41
|
+
identity: '',
|
|
42
|
+
operation: a => b => a + b,
|
|
43
|
+
};
|
|
44
|
+
// an empty list folds to the identity
|
|
45
|
+
assertEq(fold(concat)([]), '');
|
|
46
|
+
},
|
|
21
47
|
}
|
|
22
48
|
};
|
package/fjs/dev/module.f.d.ts
CHANGED
|
@@ -42,4 +42,5 @@ export type LoadModuleOperations = Access | Import | All | Readdir;
|
|
|
42
42
|
export declare const loadModuleMap: (env: Env) => Effect<LoadModuleOperations, ModuleMap>;
|
|
43
43
|
export declare const proof: {
|
|
44
44
|
isSourceFile: () => void;
|
|
45
|
+
allFilesSkipsNodeModules: () => void;
|
|
45
46
|
};
|
package/fjs/dev/module.f.js
CHANGED
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
import { all, import_, readdir } from '../effects/node/module.f.js';
|
|
7
7
|
import { cmp as strCmp } from '../types/string/module.f.js';
|
|
8
8
|
import { unwrap } from '../types/result/module.f.js';
|
|
9
|
-
import { pure } from '../effects/module.f.js';
|
|
9
|
+
import { pure, step } from '../effects/module.f.js';
|
|
10
10
|
import { join, relativize, toPosix } from '../path/module.f.js';
|
|
11
|
-
import { assert } from '../asserts/module.f.js';
|
|
11
|
+
import { assert, assertEq } from '../asserts/module.f.js';
|
|
12
|
+
import { emptyState, virtual } from '../effects/node/virtual/module.f.js';
|
|
12
13
|
/**
|
|
13
14
|
* Returns `true` if the file should be loaded for proof discovery.
|
|
14
15
|
*
|
|
@@ -25,32 +26,33 @@ export const shouldLoad = (s) => s.endsWith('.f.ts') || s.endsWith('.f.js') ||
|
|
|
25
26
|
s.endsWith('proof.mts') || s.endsWith('proof.mjs');
|
|
26
27
|
const isSourceFile = (path) => path.endsWith('.js') || path.endsWith('.ts') || path.endsWith('.mts') || path.endsWith('.mjs');
|
|
27
28
|
const allFiles = (s, predicate) => {
|
|
28
|
-
const load = (p) =>
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
const file = join(p, name);
|
|
37
|
-
if (!i.isFile) {
|
|
38
|
-
if (name === 'node_modules') {
|
|
29
|
+
const load = (p) => {
|
|
30
|
+
const x0 = step(readdir(p, {}), d => {
|
|
31
|
+
let result = [];
|
|
32
|
+
for (const i of unwrap(d)) {
|
|
33
|
+
const { name } = i;
|
|
34
|
+
if (name.startsWith('.')) {
|
|
39
35
|
continue;
|
|
40
36
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
37
|
+
const file = join(p, name);
|
|
38
|
+
if (!i.isFile) {
|
|
39
|
+
if (name === 'node_modules') {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
result = [...result, load(file)];
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (predicate(file)) {
|
|
46
|
+
result = [...result, pure([file])];
|
|
47
|
+
}
|
|
46
48
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
return all(...result);
|
|
50
|
+
});
|
|
51
|
+
return step(x0, v => pure(v.flat()));
|
|
52
|
+
};
|
|
51
53
|
return load(s);
|
|
52
54
|
};
|
|
53
|
-
const loadFile = (f) => import_(f)
|
|
55
|
+
const loadFile = (f) => step(import_(f), r => pure([[f, unwrap(r)]]));
|
|
54
56
|
const { fromEntries } = Object;
|
|
55
57
|
/**
|
|
56
58
|
* Discovers all source files under `INIT_CWD` (or `.` if unset) that match
|
|
@@ -71,12 +73,11 @@ export const loadModuleMap = (env) => {
|
|
|
71
73
|
const s = initCwd === undefined ? '.' : toPosix(initCwd);
|
|
72
74
|
const prefix = s === '.' ? '' : s;
|
|
73
75
|
// TODO: there are multiple `all` effects here,
|
|
74
|
-
// we should consider
|
|
76
|
+
// we should consider optimizing them by ALIQ technique or something similar.
|
|
75
77
|
// For example, we should be able to write it like `allFiles(s).flatMap(loadFile)`,
|
|
76
78
|
// then an effect runner can batch all file loading operations together.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
.step(entries => pure(fromEntries(entries
|
|
79
|
+
const x0 = step(allFiles(s, shouldLoad), files => all(...files.map(loadFile)));
|
|
80
|
+
return step(x0, entries => pure(fromEntries(entries
|
|
80
81
|
.flat()
|
|
81
82
|
.map(([k, v]) => [relativize(prefix, k), v])
|
|
82
83
|
.toSorted(([a], [b]) => strCmp(a)(b)))));
|
|
@@ -90,4 +91,14 @@ export const proof = {
|
|
|
90
91
|
assert(!isSourceFile('readme.md'));
|
|
91
92
|
assert(!isSourceFile('module.json'));
|
|
92
93
|
},
|
|
94
|
+
allFilesSkipsNodeModules: () => {
|
|
95
|
+
// `node_modules` is skipped without descending into it, even though
|
|
96
|
+
// it contains a file that would otherwise match the predicate.
|
|
97
|
+
const root = {
|
|
98
|
+
'node_modules': { 'pkg.f.ts': [] },
|
|
99
|
+
'a.f.ts': [],
|
|
100
|
+
};
|
|
101
|
+
const [, result] = virtual({ ...emptyState, root })(allFiles('.', shouldLoad));
|
|
102
|
+
assertEq(result.join(','), './a.f.ts');
|
|
103
|
+
},
|
|
93
104
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronizes local development configuration generated from canonical repository files.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { type Effect } from '../../effects/module.f.ts';
|
|
7
|
+
import { type Mkdir, type NodeProgram, type ReadFile, type WriteFile } from '../../effects/node/module.f.ts';
|
|
8
|
+
/** Regenerates VS Code's local MCP configuration from the canonical Copilot configuration. */
|
|
9
|
+
export declare const syncMcp: () => Effect<Mkdir | ReadFile | WriteFile, void>;
|
|
10
|
+
/** Runs all local development configuration generators. */
|
|
11
|
+
export declare const main: NodeProgram;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronizes local development configuration generated from canonical repository files.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { history, historyStep, mapStep, step } from '../../effects/module.f.js';
|
|
7
|
+
import { mkdir, readUtf8File, writeUtf8File } from '../../effects/node/module.f.js';
|
|
8
|
+
import { unwrap } from '../../types/result/module.f.js';
|
|
9
|
+
const source = '.copilot/mcp.json';
|
|
10
|
+
const targetDirectory = '.vscode';
|
|
11
|
+
const target = '.vscode/mcp.json';
|
|
12
|
+
/** Regenerates VS Code's local MCP configuration from the canonical Copilot configuration. */
|
|
13
|
+
export const syncMcp = () => {
|
|
14
|
+
const sourceText = history(mapStep(readUtf8File(source), unwrap));
|
|
15
|
+
const targetDirectoryReady = historyStep(sourceText, () => mapStep(mkdir(targetDirectory, { recursive: true }), unwrap));
|
|
16
|
+
const targetWritten = step(targetDirectoryReady, ([, text]) => writeUtf8File(target, text));
|
|
17
|
+
return mapStep(targetWritten, unwrap);
|
|
18
|
+
};
|
|
19
|
+
/** Runs all local development configuration generators. */
|
|
20
|
+
export const main = () => mapStep(syncMcp(), () => 0);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proofs for local development configuration generation.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { assert, assertEq } from '../../asserts/module.f.js';
|
|
7
|
+
import { utf8 } from '../../text/module.f.js';
|
|
8
|
+
import { readUtf8File } from '../../effects/node/module.f.js';
|
|
9
|
+
import { defaultNodeProgramOptions, emptyState, virtual } from '../../effects/node/virtual/module.f.js';
|
|
10
|
+
import { main, syncMcp } from './module.f.js';
|
|
11
|
+
import { step } from '../../effects/module.f.js';
|
|
12
|
+
const mcp = '{"servers":{}}';
|
|
13
|
+
const initial = {
|
|
14
|
+
...emptyState,
|
|
15
|
+
root: {
|
|
16
|
+
'.copilot': {
|
|
17
|
+
'mcp.json': [utf8(mcp)],
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
export const proof = {
|
|
22
|
+
syncMcp: () => {
|
|
23
|
+
const generatedMcp = step(syncMcp(), () => readUtf8File('.vscode/mcp.json'));
|
|
24
|
+
const [, [tag, result]] = virtual(initial)(generatedMcp);
|
|
25
|
+
assert(tag === 'ok', result);
|
|
26
|
+
assertEq(result, mcp);
|
|
27
|
+
},
|
|
28
|
+
main: () => {
|
|
29
|
+
const [, result] = virtual(initial)(main(defaultNodeProgramOptions));
|
|
30
|
+
assertEq(result, 0);
|
|
31
|
+
},
|
|
32
|
+
throw: {
|
|
33
|
+
missingSource: () => virtual(emptyState)(syncMcp()),
|
|
34
|
+
},
|
|
35
|
+
};
|
|
@@ -4,12 +4,59 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import type { Primitive, Array, Unknown } from '../module.f.ts';
|
|
7
|
+
/**
|
|
8
|
+
* A parsed DJS module: its imported module specifiers, in source order, and
|
|
9
|
+
* its body.
|
|
10
|
+
*
|
|
11
|
+
* The specifier list indexes `['aref', i]`.
|
|
12
|
+
*/
|
|
7
13
|
export type AstModule = [readonly string[], AstBody];
|
|
14
|
+
/** A value in a module body: a primitive, a reference, an array, or an object. */
|
|
8
15
|
export type AstConst = Primitive | AstModuleRef | AstArray | AstObject;
|
|
16
|
+
/**
|
|
17
|
+
* A reference to a value defined outside this `AstConst`.
|
|
18
|
+
*
|
|
19
|
+
* - `['aref', i]` — the `i`-th argument of the body, i.e. the `i`-th imported
|
|
20
|
+
* module of the enclosing `AstModule`.
|
|
21
|
+
* - `['cref', i]` — the `i`-th entry of the enclosing `AstBody`.
|
|
22
|
+
*
|
|
23
|
+
* Both indices are absolute and zero-based, **not** offsets from the
|
|
24
|
+
* referencing entry: in the body `[a, b, ['cref', 0]]` the reference resolves
|
|
25
|
+
* to `a`, not to the nearest preceding entry `b`.
|
|
26
|
+
*
|
|
27
|
+
* A `cref` index must be smaller than the index of the entry holding it —
|
|
28
|
+
* `run` evaluates a body left to right, so a reference to the current or a
|
|
29
|
+
* later entry is unsatisfiable. It is not rejected: it resolves to the most
|
|
30
|
+
* recently evaluated entry instead.
|
|
31
|
+
*/
|
|
9
32
|
export type AstModuleRef = ['aref' | 'cref', number];
|
|
33
|
+
/** An array value; its elements are evaluated in order. */
|
|
10
34
|
export type AstArray = ['array', readonly AstConst[]];
|
|
35
|
+
/** An object value, keyed by property name. */
|
|
11
36
|
export type AstObject = {
|
|
12
37
|
readonly [k in string]?: AstConst;
|
|
13
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* The constants of a module body, in declaration order. The **last** entry is
|
|
41
|
+
* the value the module yields; the preceding entries exist to be named by
|
|
42
|
+
* `['cref', i]`.
|
|
43
|
+
*
|
|
44
|
+
* A body describes the function
|
|
45
|
+
*
|
|
46
|
+
* ```js
|
|
47
|
+
* (...args) => { const c0 = ...; const c1 = ...; return <last> }
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* where `args` are the imported modules.
|
|
51
|
+
*/
|
|
14
52
|
export type AstBody = readonly AstConst[];
|
|
53
|
+
/**
|
|
54
|
+
* Evaluates a module body against its imported modules and returns the value
|
|
55
|
+
* the module yields — the last entry of the body.
|
|
56
|
+
*
|
|
57
|
+
* Entries are evaluated left to right, so a `cref` resolves to an already
|
|
58
|
+
* evaluated entry. A reference is shared, not copied: two properties holding
|
|
59
|
+
* the same `['cref', i]` deserialize to the same object, which is what lets a
|
|
60
|
+
* DJS module denote a graph rather than a tree.
|
|
61
|
+
*/
|
|
15
62
|
export declare const run: (body: AstBody) => (args: Array) => Unknown;
|
package/fjs/djs/ast/module.f.js
CHANGED
|
@@ -42,6 +42,15 @@ const toDjs = state => ast => {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* Evaluates a module body against its imported modules and returns the value
|
|
47
|
+
* the module yields — the last entry of the body.
|
|
48
|
+
*
|
|
49
|
+
* Entries are evaluated left to right, so a `cref` resolves to an already
|
|
50
|
+
* evaluated entry. A reference is shared, not copied: two properties holding
|
|
51
|
+
* the same `['cref', i]` deserialize to the same object, which is what lets a
|
|
52
|
+
* DJS module denote a graph rather than a tree.
|
|
53
|
+
*/
|
|
45
54
|
export const run = body => args => {
|
|
46
55
|
const state = fold(foldOp)({ body, args, consts: null })(body);
|
|
47
56
|
return last(null)(state.consts);
|
package/fjs/djs/module.f.js
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
import { transpile } from './transpiler/module.f.js';
|
|
2
2
|
import { stringify, stringifyAsTree } from './serializer/module.f.js';
|
|
3
3
|
import { sort } from '../types/object/module.f.js';
|
|
4
|
-
import { pure } from '../effects/module.f.js';
|
|
4
|
+
import { pure, step } from '../effects/module.f.js';
|
|
5
5
|
import { writeUtf8File, error, } from '../effects/node/module.f.js';
|
|
6
6
|
export const compile = args => {
|
|
7
7
|
if (args.length < 2) {
|
|
8
|
-
return error('Error: Requires 2 or more arguments')
|
|
9
|
-
.step(() => pure(1));
|
|
8
|
+
return step(error('Error: Requires 2 or more arguments'), () => pure(1));
|
|
10
9
|
}
|
|
11
10
|
const inputFileName = args[0];
|
|
12
11
|
const outputFileName = args[1];
|
|
13
|
-
return transpile(inputFileName)
|
|
12
|
+
return step(transpile(inputFileName), (result) => {
|
|
14
13
|
if (result[0] === 'error') {
|
|
15
14
|
const metadata = result[1].metadata;
|
|
16
|
-
return error(`${metadata?.path}:${metadata?.line}:${metadata?.column} - error: ${result[1].message}`)
|
|
17
|
-
.step(() => pure(0));
|
|
15
|
+
return step(error(`${metadata?.path}:${metadata?.line}:${metadata?.column} - error: ${result[1].message}`), () => pure(0));
|
|
18
16
|
}
|
|
19
17
|
const content = outputFileName.endsWith('.json')
|
|
20
18
|
? stringifyAsTree(sort)(result[1])
|
|
21
19
|
: stringify(sort)(result[1]);
|
|
22
|
-
return writeUtf8File(outputFileName, content)
|
|
23
|
-
.step(() => pure(0));
|
|
20
|
+
return step(writeUtf8File(outputFileName, content), () => pure(0));
|
|
24
21
|
});
|
|
25
22
|
};
|
|
@@ -380,4 +380,21 @@ export const proof = {
|
|
|
380
380
|
assertEq(result.state, 'error');
|
|
381
381
|
},
|
|
382
382
|
},
|
|
383
|
+
endArray: {
|
|
384
|
+
// `endArray` is only ever invoked while `state.top` is an array (the
|
|
385
|
+
// `'['`/`'[v'`/`'[,'` value-states guarantee it), so its non-array
|
|
386
|
+
// guard is a defensive branch unreachable through `parseFromTokens`.
|
|
387
|
+
// Call it directly to cover that branch.
|
|
388
|
+
nonArrayTop: () => {
|
|
389
|
+
const state = {
|
|
390
|
+
state: 'exportValue',
|
|
391
|
+
module: { refs: null, modules: null, consts: null },
|
|
392
|
+
valueState: '[,',
|
|
393
|
+
top: null,
|
|
394
|
+
stack: null,
|
|
395
|
+
};
|
|
396
|
+
const result = endArray(state);
|
|
397
|
+
assertEq(result.state, 'result');
|
|
398
|
+
},
|
|
399
|
+
},
|
|
383
400
|
};
|
|
@@ -364,7 +364,7 @@ export const tokenizeString = s => {
|
|
|
364
364
|
}
|
|
365
365
|
const m = descentParser(jsGrammar());
|
|
366
366
|
const cpm = codePointsWithMetadata('')(cp);
|
|
367
|
-
const
|
|
367
|
+
const { ast, success: ok, idx: len } = m('', cpm);
|
|
368
368
|
if (!ok || len !== cp.length)
|
|
369
369
|
return 'error';
|
|
370
370
|
const flatTokens = toArray(getTokensFromAstRule(ast));
|
|
@@ -394,7 +394,7 @@ export const tokenizeJs = input => path => {
|
|
|
394
394
|
return [{ token: { kind: 'eof' }, metadata: initial }];
|
|
395
395
|
const m = descentParser(jsGrammar());
|
|
396
396
|
const cpm = codePointsWithMetadata(path)(cp);
|
|
397
|
-
const
|
|
397
|
+
const { ast, success: ok, idx: len } = m('', cpm);
|
|
398
398
|
const finalMetadata = fold(advanceMetadata)(initial)(cp);
|
|
399
399
|
if (!ok || len !== cp.length) {
|
|
400
400
|
const errorMetadata = len < cpm.length ? cpm[len][1] : finalMetadata;
|