functionalscript 0.10.1 → 0.10.3
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/bnf/module.f.d.ts +73 -0
- package/bnf/module.f.js +58 -0
- package/cas/module.f.d.ts +2 -2
- package/cas/module.f.js +53 -26
- package/ci/module.f.d.ts +2 -2
- package/ci/module.f.js +6 -3
- package/dev/module.f.js +8 -5
- package/dev/tf/all.test.js +1 -0
- package/dev/version/module.f.d.ts +1 -1
- package/dev/version/module.f.js +12 -9
- package/dev/version/test.f.js +4 -4
- package/io/module.d.ts +1 -1
- package/io/module.f.d.ts +1 -1
- package/io/module.f.js +1 -1
- package/package.json +1 -1
- package/types/{effect → effects}/mock/module.f.js +3 -3
- package/types/{effect → effects}/module.f.d.ts +12 -13
- package/types/effects/module.f.js +20 -0
- package/types/{effect → effects}/module.js +3 -3
- package/types/{effect → effects}/node/test.f.js +5 -4
- package/website/module.f.d.ts +1 -2
- package/website/module.f.js +6 -3
- package/types/effect/module.f.js +0 -14
- /package/types/{effect → effects}/mock/module.f.d.ts +0 -0
- /package/types/{effect → effects}/module.d.ts +0 -0
- /package/types/{effect → effects}/node/module.f.d.ts +0 -0
- /package/types/{effect → effects}/node/module.f.js +0 -0
- /package/types/{effect → effects}/node/test.f.d.ts +0 -0
- /package/types/{effect → effects}/node/virtual/module.f.d.ts +0 -0
- /package/types/{effect → effects}/node/virtual/module.f.js +0 -0
package/bnf/module.f.d.ts
CHANGED
|
@@ -7,9 +7,21 @@ import { type Array2 } from '../types/array/module.f.ts';
|
|
|
7
7
|
* - 0xEEEEEE is the last symbol (24 bits)
|
|
8
8
|
*/
|
|
9
9
|
export type TerminalRange = number;
|
|
10
|
+
/**
|
|
11
|
+
* Full 24-bit symbol range packed into a single {@link TerminalRange}.
|
|
12
|
+
*/
|
|
10
13
|
export declare const fullRange: TerminalRange;
|
|
14
|
+
/**
|
|
15
|
+
* Unicode scalar value range packed into a single {@link TerminalRange}.
|
|
16
|
+
*/
|
|
11
17
|
export declare const unicodeRange: TerminalRange;
|
|
18
|
+
/**
|
|
19
|
+
* Maximal non-Unicode symbol encoded as a string value.
|
|
20
|
+
*/
|
|
12
21
|
export declare const max: string;
|
|
22
|
+
/**
|
|
23
|
+
* Maximal Unicode code point encoded as a string value.
|
|
24
|
+
*/
|
|
13
25
|
export declare const unicodeMax: string;
|
|
14
26
|
/** A sequence of rules. */
|
|
15
27
|
export type Sequence = readonly Rule[];
|
|
@@ -17,16 +29,47 @@ export type Sequence = readonly Rule[];
|
|
|
17
29
|
export type Variant = {
|
|
18
30
|
readonly [k in string]: Rule;
|
|
19
31
|
};
|
|
32
|
+
/**
|
|
33
|
+
* Data-only grammar rule.
|
|
34
|
+
*/
|
|
20
35
|
export type DataRule = Variant | Sequence | TerminalRange | string;
|
|
36
|
+
/**
|
|
37
|
+
* Lazily evaluated grammar rule.
|
|
38
|
+
*/
|
|
21
39
|
export type LazyRule = () => DataRule;
|
|
40
|
+
/**
|
|
41
|
+
* Grammar rule, either immediate data or lazy rule factory.
|
|
42
|
+
*/
|
|
22
43
|
export type Rule = DataRule | LazyRule;
|
|
23
44
|
export declare const rangeEncode: (a: number, b: number) => TerminalRange;
|
|
45
|
+
/**
|
|
46
|
+
* Encodes a single symbol as a {@link TerminalRange}.
|
|
47
|
+
*/
|
|
24
48
|
export declare const oneEncode: (a: number) => TerminalRange;
|
|
49
|
+
/**
|
|
50
|
+
* End-of-file marker represented as one code point beyond Unicode range.
|
|
51
|
+
*/
|
|
25
52
|
export declare const eof: TerminalRange;
|
|
53
|
+
/**
|
|
54
|
+
* Decodes a packed range into `[start, end]` symbols.
|
|
55
|
+
*/
|
|
26
56
|
export declare const rangeDecode: (r: number) => Array2<number>;
|
|
27
57
|
export declare const toSequence: (s: string) => readonly TerminalRange[];
|
|
58
|
+
/**
|
|
59
|
+
* Converts the whole string into one rule:
|
|
60
|
+
* - a single {@link TerminalRange} when the string has one symbol,
|
|
61
|
+
* - a sequence of {@link TerminalRange} values when the string has multiple symbols.
|
|
62
|
+
*/
|
|
28
63
|
export declare const str: (s: string) => readonly TerminalRange[] | TerminalRange;
|
|
64
|
+
/**
|
|
65
|
+
* Converts a string into a variant that maps each character to its symbol range.
|
|
66
|
+
*/
|
|
29
67
|
export declare const set: (s: string) => RangeVariant;
|
|
68
|
+
/**
|
|
69
|
+
* Encodes a two-symbol string into a terminal range.
|
|
70
|
+
*
|
|
71
|
+
* @throws If `ab` does not contain exactly two unicode code points.
|
|
72
|
+
*/
|
|
30
73
|
export declare const range: (ab: string) => TerminalRange;
|
|
31
74
|
/**
|
|
32
75
|
* A set of terminal ranges compatible with the `Variant` rule.
|
|
@@ -35,14 +78,32 @@ export type RangeVariant = {
|
|
|
35
78
|
readonly [k in string]: TerminalRange;
|
|
36
79
|
};
|
|
37
80
|
export declare const remove: (range: TerminalRange, v: RangeVariant) => RangeVariant;
|
|
81
|
+
/**
|
|
82
|
+
* Returns the complement set of the provided ranges over {@link fullRange}.
|
|
83
|
+
*/
|
|
38
84
|
export declare const not: (v: RangeVariant) => RangeVariant;
|
|
85
|
+
/**
|
|
86
|
+
* Returns the complement set of a character set over {@link fullRange}.
|
|
87
|
+
*/
|
|
39
88
|
export declare const notSet: (s: string) => RangeVariant;
|
|
89
|
+
/**
|
|
90
|
+
* Empty sequence type for optional grammar branches.
|
|
91
|
+
*/
|
|
40
92
|
export type None = readonly [];
|
|
93
|
+
/**
|
|
94
|
+
* Shared empty sequence literal.
|
|
95
|
+
*/
|
|
41
96
|
export declare const none: None;
|
|
97
|
+
/**
|
|
98
|
+
* Optional grammar branch.
|
|
99
|
+
*/
|
|
42
100
|
export type Option<S> = {
|
|
43
101
|
some: S;
|
|
44
102
|
none: None;
|
|
45
103
|
};
|
|
104
|
+
/**
|
|
105
|
+
* Creates an option value from a required branch.
|
|
106
|
+
*/
|
|
46
107
|
export declare const option: <S extends Rule>(some: S) => Option<S>;
|
|
47
108
|
export type Repeat0Plus<T> = () => Option<readonly [T, Repeat0Plus<T>]>;
|
|
48
109
|
/**
|
|
@@ -61,9 +122,21 @@ export type Repeat1Plus<T> = readonly [T, Repeat0Plus<T>];
|
|
|
61
122
|
*/
|
|
62
123
|
export declare const repeat1Plus: <T extends Rule>(some: T) => Repeat1Plus<T>;
|
|
63
124
|
export type Join1Plus<T, S> = readonly [T, Repeat0Plus<readonly [S, T]>];
|
|
125
|
+
/**
|
|
126
|
+
* Repeats `some` one or more times separated by `separator`.
|
|
127
|
+
*/
|
|
64
128
|
export declare const join1Plus: <T extends Rule, S extends Rule>(some: T, separator: S) => Join1Plus<T, S>;
|
|
65
129
|
export type Join0Plus<T, S> = Option<readonly [T, Repeat0Plus<readonly [S, T]>]>;
|
|
130
|
+
/**
|
|
131
|
+
* Repeats `some` zero or more times separated by `separator`.
|
|
132
|
+
*/
|
|
66
133
|
export declare const join0Plus: <T extends Rule, S extends Rule>(some: T, separator: S) => Rule;
|
|
67
134
|
export type Repeat<T> = readonly T[];
|
|
135
|
+
/**
|
|
136
|
+
* Repeats a rule a fixed number of times.
|
|
137
|
+
*/
|
|
68
138
|
export declare const repeat: (n: number) => <T extends Rule>(some: T) => Repeat<T>;
|
|
139
|
+
/**
|
|
140
|
+
* Determines whether the rule is an empty rule.
|
|
141
|
+
*/
|
|
69
142
|
export declare const isEmpty: (rule: Rule) => boolean;
|
package/bnf/module.f.js
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import { codePointListToString, stringToCodePointList } from "../text/utf16/module.f.js";
|
|
2
2
|
import { isArray2 } from "../types/array/module.f.js";
|
|
3
3
|
import { map, toArray, repeat as listRepeat } from "../types/list/module.f.js";
|
|
4
|
+
/**
|
|
5
|
+
* Full 24-bit symbol range packed into a single {@link TerminalRange}.
|
|
6
|
+
*/
|
|
4
7
|
export const fullRange = 0x000000_FFFFFF;
|
|
8
|
+
/**
|
|
9
|
+
* Unicode scalar value range packed into a single {@link TerminalRange}.
|
|
10
|
+
*/
|
|
5
11
|
export const unicodeRange = 0x000000_10FFFF;
|
|
12
|
+
/**
|
|
13
|
+
* Maximal non-Unicode symbol encoded as a string value.
|
|
14
|
+
*/
|
|
6
15
|
export const max = codePointListToString([0xFFFFFF]);
|
|
16
|
+
/**
|
|
17
|
+
* Maximal Unicode code point encoded as a string value.
|
|
18
|
+
*/
|
|
7
19
|
export const unicodeMax = codePointListToString([0x10FFFF]);
|
|
8
20
|
// Internals:
|
|
9
21
|
const { fromEntries, values } = Object;
|
|
@@ -20,17 +32,39 @@ export const rangeEncode = (a, b) => {
|
|
|
20
32
|
}
|
|
21
33
|
return Number((BigInt(a) << BigInt(offset)) | BigInt(b));
|
|
22
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Encodes a single symbol as a {@link TerminalRange}.
|
|
37
|
+
*/
|
|
23
38
|
export const oneEncode = (a) => rangeEncode(a, a);
|
|
39
|
+
/**
|
|
40
|
+
* End-of-file marker represented as one code point beyond Unicode range.
|
|
41
|
+
*/
|
|
24
42
|
export const eof = oneEncode(0x110000);
|
|
43
|
+
/**
|
|
44
|
+
* Decodes a packed range into `[start, end]` symbols.
|
|
45
|
+
*/
|
|
25
46
|
export const rangeDecode = (r) => [Number(BigInt(r) >> BigInt(offset)), Number(BigInt(r) & BigInt(mask))];
|
|
26
47
|
const mapOneEncode = map(oneEncode);
|
|
27
48
|
export const toSequence = (s) => toArray(mapOneEncode(stringToCodePointList(s)));
|
|
49
|
+
/**
|
|
50
|
+
* Converts the whole string into one rule:
|
|
51
|
+
* - a single {@link TerminalRange} when the string has one symbol,
|
|
52
|
+
* - a sequence of {@link TerminalRange} values when the string has multiple symbols.
|
|
53
|
+
*/
|
|
28
54
|
export const str = (s) => {
|
|
29
55
|
const x = toSequence(s);
|
|
30
56
|
return x.length === 1 ? x[0] : x;
|
|
31
57
|
};
|
|
32
58
|
const mapEntry = map((v) => [fromCodePoint(v), oneEncode(v)]);
|
|
59
|
+
/**
|
|
60
|
+
* Converts a string into a variant that maps each character to its symbol range.
|
|
61
|
+
*/
|
|
33
62
|
export const set = (s) => fromEntries(toArray(mapEntry(stringToCodePointList(s))));
|
|
63
|
+
/**
|
|
64
|
+
* Encodes a two-symbol string into a terminal range.
|
|
65
|
+
*
|
|
66
|
+
* @throws If `ab` does not contain exactly two unicode code points.
|
|
67
|
+
*/
|
|
34
68
|
export const range = (ab) => {
|
|
35
69
|
const a = toArray(stringToCodePointList(ab));
|
|
36
70
|
if (!isArray2(a)) {
|
|
@@ -65,9 +99,21 @@ export const remove = (range, v) => {
|
|
|
65
99
|
}
|
|
66
100
|
return toVariantRangeSet(result);
|
|
67
101
|
};
|
|
102
|
+
/**
|
|
103
|
+
* Returns the complement set of the provided ranges over {@link fullRange}.
|
|
104
|
+
*/
|
|
68
105
|
export const not = (v) => remove(fullRange, v);
|
|
106
|
+
/**
|
|
107
|
+
* Returns the complement set of a character set over {@link fullRange}.
|
|
108
|
+
*/
|
|
69
109
|
export const notSet = (s) => not(set(s));
|
|
110
|
+
/**
|
|
111
|
+
* Shared empty sequence literal.
|
|
112
|
+
*/
|
|
70
113
|
export const none = [];
|
|
114
|
+
/**
|
|
115
|
+
* Creates an option value from a required branch.
|
|
116
|
+
*/
|
|
71
117
|
export const option = (some) => ({
|
|
72
118
|
some,
|
|
73
119
|
none,
|
|
@@ -89,9 +135,21 @@ export const repeat0Plus = (some) => {
|
|
|
89
135
|
* Repeat one or more times.
|
|
90
136
|
*/
|
|
91
137
|
export const repeat1Plus = (some) => [some, repeat0Plus(some)];
|
|
138
|
+
/**
|
|
139
|
+
* Repeats `some` one or more times separated by `separator`.
|
|
140
|
+
*/
|
|
92
141
|
export const join1Plus = (some, separator) => [some, repeat0Plus([separator, some])];
|
|
142
|
+
/**
|
|
143
|
+
* Repeats `some` zero or more times separated by `separator`.
|
|
144
|
+
*/
|
|
93
145
|
export const join0Plus = (some, separator) => option(join1Plus(some, separator));
|
|
146
|
+
/**
|
|
147
|
+
* Repeats a rule a fixed number of times.
|
|
148
|
+
*/
|
|
94
149
|
export const repeat = (n) => (some) => toArray(listRepeat(some)(n));
|
|
150
|
+
/**
|
|
151
|
+
* Determines whether the rule is an empty rule.
|
|
152
|
+
*/
|
|
95
153
|
export const isEmpty = (rule) => {
|
|
96
154
|
const d = typeof rule === 'function' ? rule() : rule;
|
|
97
155
|
return d === '' || (d instanceof Array && d.length === 0);
|
package/cas/module.f.d.ts
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { type Sha2 } from "../crypto/sha2/module.f.ts";
|
|
7
7
|
import type { Vec } from "../types/bit_vec/module.f.ts";
|
|
8
|
-
import { type Effect, type Operations } from "../types/
|
|
9
|
-
import { type Fs, type NodeOperations } from "../types/
|
|
8
|
+
import { type Effect, type Operations } from "../types/effects/module.f.ts";
|
|
9
|
+
import { type Fs, type NodeOperations } from "../types/effects/node/module.f.ts";
|
|
10
10
|
export type KvStore<O extends Operations> = {
|
|
11
11
|
readonly read: (key: Vec) => Effect<O, Vec | undefined>;
|
|
12
12
|
readonly write: (key: Vec, value: Vec) => Effect<O, void>;
|
package/cas/module.f.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
import { computeSync, sha256 } from "../crypto/sha2/module.f.js";
|
|
7
7
|
import { parse } from "../path/module.f.js";
|
|
8
8
|
import { cBase32ToVec, vecToCBase32 } from "../types/cbase32/module.f.js";
|
|
9
|
-
import { pure } from "../types/
|
|
10
|
-
import { error, log, mkdir, readdir, readFile, writeFile } from "../types/
|
|
9
|
+
import { fluent, pure } from "../types/effects/module.f.js";
|
|
10
|
+
import { error, log, mkdir, readdir, readFile, writeFile } from "../types/effects/node/module.f.js";
|
|
11
11
|
import { toOption } from "../types/nullable/module.f.js";
|
|
12
12
|
import { unwrap } from "../types/result/module.f.js";
|
|
13
13
|
const o = { withFileTypes: true };
|
|
@@ -20,20 +20,29 @@ const toPath = (key) => {
|
|
|
20
20
|
return `${prefix}/${a}/${b}/${c}`;
|
|
21
21
|
};
|
|
22
22
|
export const fileKvStore = (path) => ({
|
|
23
|
-
read: (key) =>
|
|
24
|
-
.
|
|
23
|
+
read: (key) => fluent
|
|
24
|
+
.step(() => readFile(toPath(key)))
|
|
25
|
+
.step(([status, data]) => pure(status === 'error' ? undefined : data))
|
|
26
|
+
.effect,
|
|
25
27
|
write: (key, value) => {
|
|
26
28
|
const p = toPath(key);
|
|
27
29
|
const parts = parse(p);
|
|
28
30
|
const dir = `${path}/${parts.slice(0, -1).join('/')}`;
|
|
29
31
|
// TODO: error handling
|
|
30
|
-
return
|
|
31
|
-
.
|
|
32
|
-
.
|
|
32
|
+
return fluent
|
|
33
|
+
.step(() => mkdir(dir, { recursive: true }))
|
|
34
|
+
.step(() => writeFile(`${path}/${p}`, value))
|
|
35
|
+
.step(() => pure(undefined))
|
|
36
|
+
.effect;
|
|
33
37
|
},
|
|
34
|
-
list: () =>
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
list: () =>
|
|
39
|
+
// TODO: remove unwrap
|
|
40
|
+
fluent
|
|
41
|
+
.step(() => readdir('.cas', { recursive: true }))
|
|
42
|
+
.step(r => pure(unwrap(r).flatMap(({ name, parentPath, isFile }) => toOption(isFile
|
|
43
|
+
? cBase32ToVec(parentPath.substring(prefix.length).replaceAll('/', '') + name)
|
|
44
|
+
: null))))
|
|
45
|
+
.effect,
|
|
37
46
|
});
|
|
38
47
|
export const cas = (sha2) => {
|
|
39
48
|
const compute = computeSync(sha2);
|
|
@@ -41,13 +50,18 @@ export const cas = (sha2) => {
|
|
|
41
50
|
read,
|
|
42
51
|
write: (value) => {
|
|
43
52
|
const hash = compute([value]);
|
|
44
|
-
return
|
|
45
|
-
.
|
|
53
|
+
return fluent
|
|
54
|
+
.step(() => write(hash, value))
|
|
55
|
+
.step(() => pure(hash))
|
|
56
|
+
.effect;
|
|
46
57
|
},
|
|
47
58
|
list,
|
|
48
59
|
});
|
|
49
60
|
};
|
|
50
|
-
const e = (s) =>
|
|
61
|
+
const e = (s) => fluent
|
|
62
|
+
.step(() => error(s))
|
|
63
|
+
.step(() => pure(1))
|
|
64
|
+
.effect;
|
|
51
65
|
export const main = (args) => {
|
|
52
66
|
const c = cas(sha256)(fileKvStore('.'));
|
|
53
67
|
const [cmd, ...options] = args;
|
|
@@ -57,10 +71,12 @@ export const main = (args) => {
|
|
|
57
71
|
return e("'cas add' expects one parameter");
|
|
58
72
|
}
|
|
59
73
|
const [path] = options;
|
|
60
|
-
return
|
|
61
|
-
.
|
|
62
|
-
.
|
|
63
|
-
.
|
|
74
|
+
return fluent
|
|
75
|
+
.step(() => readFile(path))
|
|
76
|
+
.step(v => c.write(unwrap(v)))
|
|
77
|
+
.step(hash => log(vecToCBase32(hash)))
|
|
78
|
+
.step(() => pure(0))
|
|
79
|
+
.effect;
|
|
64
80
|
}
|
|
65
81
|
case 'get': {
|
|
66
82
|
if (options.length !== 2) {
|
|
@@ -71,25 +87,36 @@ export const main = (args) => {
|
|
|
71
87
|
if (hash === null) {
|
|
72
88
|
return e(`invalid hash format: ${hashCBase32}`);
|
|
73
89
|
}
|
|
74
|
-
return
|
|
75
|
-
.
|
|
90
|
+
return fluent
|
|
91
|
+
.step(() => c.read(hash))
|
|
92
|
+
.step(v => {
|
|
76
93
|
const result = v === undefined
|
|
77
94
|
? e(`no such hash: ${hashCBase32}`)
|
|
78
|
-
:
|
|
95
|
+
: fluent
|
|
96
|
+
.step(() => writeFile(path, v))
|
|
97
|
+
.step(() => pure(0))
|
|
98
|
+
.effect;
|
|
79
99
|
return result;
|
|
80
|
-
})
|
|
100
|
+
})
|
|
101
|
+
.effect;
|
|
81
102
|
}
|
|
82
103
|
case 'list': {
|
|
83
|
-
return
|
|
84
|
-
.
|
|
104
|
+
return fluent
|
|
105
|
+
.step(() => c.list())
|
|
106
|
+
.step(v => {
|
|
85
107
|
// TODO: make it lazy.
|
|
86
|
-
let i =
|
|
108
|
+
let i = fluent.effect;
|
|
87
109
|
for (const j of v) {
|
|
88
|
-
|
|
110
|
+
const prev = i;
|
|
111
|
+
i = fluent
|
|
112
|
+
.step(() => prev)
|
|
113
|
+
.step(() => log(vecToCBase32(j)))
|
|
114
|
+
.effect;
|
|
89
115
|
}
|
|
90
116
|
return i;
|
|
91
117
|
})
|
|
92
|
-
.
|
|
118
|
+
.step(() => pure(0))
|
|
119
|
+
.effect;
|
|
93
120
|
}
|
|
94
121
|
case undefined: {
|
|
95
122
|
return e('Error: CAS command requires subcommand');
|
package/ci/module.f.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type NodeEffect } from '../types/
|
|
1
|
+
import { type NodeEffect } from '../types/effects/node/module.f.ts';
|
|
2
2
|
export declare const effect: NodeEffect<number>;
|
|
3
|
-
declare const _default: () =>
|
|
3
|
+
declare const _default: () => import("../types/effects/module.f.ts").Pure<number>;
|
|
4
4
|
export default _default;
|
package/ci/module.f.js
CHANGED
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import { utf8 } from "../text/module.f.js";
|
|
7
|
-
import {
|
|
7
|
+
import { fluent, pure } from "../types/effects/module.f.js";
|
|
8
|
+
import { writeFile } from "../types/effects/node/module.f.js";
|
|
8
9
|
const os = ['ubuntu', 'macos', 'windows'];
|
|
9
10
|
const architecture = ['intel', 'arm'];
|
|
10
11
|
// https://docs.github.com/en/actions/reference/runners/github-hosted-runners#standard-github-hosted-runners-for-public-repositories
|
|
@@ -176,6 +177,8 @@ const gha = {
|
|
|
176
177
|
on: { pull_request: {} },
|
|
177
178
|
jobs,
|
|
178
179
|
};
|
|
179
|
-
export const effect =
|
|
180
|
-
.
|
|
180
|
+
export const effect = fluent
|
|
181
|
+
.step(() => writeFile('.github/workflows/ci.yml', utf8(JSON.stringify(gha, null, ' '))))
|
|
182
|
+
.step(() => pure(0))
|
|
183
|
+
.effect;
|
|
181
184
|
export default () => effect;
|
package/dev/module.f.js
CHANGED
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { fromIo } from "../io/module.f.js";
|
|
7
7
|
import { updateVersion } from "./version/module.f.js";
|
|
8
|
-
import {
|
|
9
|
-
import { readFile } from "../types/
|
|
8
|
+
import { encodeUtf8 } from "../types/uint8array/module.f.js";
|
|
9
|
+
import { readFile } from "../types/effects/node/module.f.js";
|
|
10
10
|
import { utf8ToString } from "../text/module.f.js";
|
|
11
11
|
import { unwrap } from "../types/result/module.f.js";
|
|
12
|
+
import { fluent, pure } from "../types/effects/module.f.js";
|
|
12
13
|
export const todo = () => { throw 'not implemented'; };
|
|
13
14
|
const cmp = ([a], [b]) => a < b ? -1 : a > b ? 1 : 0;
|
|
14
15
|
export const env = ({ process: { env } }) => a => {
|
|
@@ -57,9 +58,11 @@ export const loadModuleMap = async (io) => {
|
|
|
57
58
|
return Object.fromEntries(map.toSorted(cmp));
|
|
58
59
|
};
|
|
59
60
|
const denoJson = './deno.json';
|
|
60
|
-
const index2 =
|
|
61
|
-
.
|
|
62
|
-
.
|
|
61
|
+
const index2 = fluent
|
|
62
|
+
.step(() => updateVersion)
|
|
63
|
+
.step(() => readFile(denoJson))
|
|
64
|
+
.step(v => pure(JSON.parse(utf8ToString(unwrap(v)))))
|
|
65
|
+
.effect;
|
|
63
66
|
export const index = async (io) => {
|
|
64
67
|
const runner = fromIo(io);
|
|
65
68
|
const jsr_json = await runner(index2);
|
package/dev/tf/all.test.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { type NodeEffect } from "../../types/
|
|
1
|
+
import { type NodeEffect } from "../../types/effects/node/module.f.ts";
|
|
2
2
|
export declare const updateVersion: NodeEffect<number>;
|
package/dev/version/module.f.js
CHANGED
|
@@ -4,21 +4,24 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import { utf8, utf8ToString } from "../../text/module.f.js";
|
|
7
|
-
import { all } from "../../types/
|
|
8
|
-
import { readFile, writeFile } from "../../types/
|
|
7
|
+
import { all, fluent, pure, step } from "../../types/effects/module.f.js";
|
|
8
|
+
import { readFile, writeFile } from "../../types/effects/node/module.f.js";
|
|
9
9
|
import { unwrap } from "../../types/result/module.f.js";
|
|
10
10
|
const { stringify, parse } = JSON;
|
|
11
11
|
const jsonFile = (jsonFile) => `${jsonFile}.json`;
|
|
12
|
-
const readJson = (name) =>
|
|
13
|
-
.
|
|
14
|
-
|
|
15
|
-
.
|
|
12
|
+
const readJson = (name) => fluent
|
|
13
|
+
.step(() => readFile(jsonFile(name)))
|
|
14
|
+
.step(v => pure(parse(utf8ToString(unwrap(v)))))
|
|
15
|
+
.effect;
|
|
16
|
+
const writeVersion = (version) => (name) => step(readJson(name))(json => writeFile(jsonFile(name), utf8(stringify({
|
|
16
17
|
...json,
|
|
17
18
|
version,
|
|
18
19
|
}, null, 2))));
|
|
19
|
-
export const updateVersion =
|
|
20
|
-
.
|
|
20
|
+
export const updateVersion = fluent
|
|
21
|
+
.step(() => readJson('package'))
|
|
22
|
+
.step(p => {
|
|
21
23
|
const w = writeVersion(p.version);
|
|
22
24
|
return all([w('package'), w('deno')]);
|
|
23
25
|
})
|
|
24
|
-
.
|
|
26
|
+
.step(() => pure(0))
|
|
27
|
+
.effect;
|
package/dev/version/test.f.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { utf8, utf8ToString } from "../../text/module.f.js";
|
|
2
2
|
import { isVec } from "../../types/bit_vec/module.f.js";
|
|
3
|
-
import { run } from "../../types/
|
|
4
|
-
import { all } from "../../types/
|
|
5
|
-
import { writeFile } from "../../types/
|
|
6
|
-
import { emptyState, virtual } from "../../types/
|
|
3
|
+
import { run } from "../../types/effects/mock/module.f.js";
|
|
4
|
+
import { all } from "../../types/effects/module.f.js";
|
|
5
|
+
import { writeFile } from "../../types/effects/node/module.f.js";
|
|
6
|
+
import { emptyState, virtual } from "../../types/effects/node/virtual/module.f.js";
|
|
7
7
|
import { updateVersion } from "./module.f.js";
|
|
8
8
|
const version = '0.3.0';
|
|
9
9
|
const x = {
|
package/io/module.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Io, type Run } from './module.f.ts';
|
|
2
|
-
import type { NodeProgram } from '../types/
|
|
2
|
+
import type { NodeProgram } from '../types/effects/node/module.f.ts';
|
|
3
3
|
export declare const io: Io;
|
|
4
4
|
export declare const legacyRun: Run;
|
|
5
5
|
export type NodeRun = (p: NodeProgram) => Promise<number>;
|
package/io/module.f.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NodeEffect } from '../types/
|
|
1
|
+
import type { NodeEffect } from '../types/effects/node/module.f.ts';
|
|
2
2
|
import { type Result } from '../types/result/module.f.ts';
|
|
3
3
|
/**
|
|
4
4
|
* Represents a directory entry (file or directory) in the filesystem
|
package/io/module.f.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { normalize } from "../path/module.f.js";
|
|
2
|
-
import { asyncRun } from "../types/
|
|
2
|
+
import { asyncRun } from "../types/effects/module.js";
|
|
3
3
|
import { error, ok } from "../types/result/module.f.js";
|
|
4
4
|
import { fromVec, toVec } from "../types/uint8array/module.f.js";
|
|
5
5
|
/**
|
package/package.json
CHANGED
|
@@ -2,10 +2,10 @@ export const run = (o) => (state) => (effect) => {
|
|
|
2
2
|
let s = state;
|
|
3
3
|
let e = effect;
|
|
4
4
|
while (true) {
|
|
5
|
-
if (
|
|
6
|
-
return [s, e
|
|
5
|
+
if (e.length === 1) {
|
|
6
|
+
return [s, e[0]];
|
|
7
7
|
}
|
|
8
|
-
const [cmd, payload, cont] = e
|
|
8
|
+
const [cmd, payload, cont] = e;
|
|
9
9
|
const operation = o[cmd];
|
|
10
10
|
const [ns, m] = operation(s, payload);
|
|
11
11
|
s = ns;
|
|
@@ -6,23 +6,22 @@
|
|
|
6
6
|
export type Operations = {
|
|
7
7
|
readonly [command in string]: readonly [input: unknown, output: unknown];
|
|
8
8
|
};
|
|
9
|
-
export type Effect<O extends Operations, T> = Pure<
|
|
10
|
-
export type
|
|
11
|
-
readonly pipe: <O1 extends Operations, R>(f: (_: T) => Effect<O1, R>) => Effect<O | O1, R>;
|
|
12
|
-
readonly map: <O1 extends Operations, R>(f: (_: T) => R) => Effect<O | O1, R>;
|
|
13
|
-
};
|
|
14
|
-
export type Pure<O extends Operations, T> = {
|
|
15
|
-
readonly pure: T;
|
|
16
|
-
} & Map<O, T>;
|
|
17
|
-
export declare const pure: <O extends Operations, T>(value: T) => Pure<O, T>;
|
|
9
|
+
export type Effect<O extends Operations, T> = Pure<T> | Do<O, T>;
|
|
10
|
+
export type Pure<T> = readonly [T];
|
|
18
11
|
export type One<O extends Operations, T, K extends keyof O & string> = readonly [K, O[K][0], (input: O[K][1]) => Effect<O, T>];
|
|
19
12
|
export type Do<O extends Operations, T> = {
|
|
20
|
-
readonly
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
} & Map<O, T>;
|
|
13
|
+
readonly [K in keyof O & string]: One<O, T, K>;
|
|
14
|
+
}[keyof O & string];
|
|
15
|
+
export declare const pure: <T>(value: T) => Pure<T>;
|
|
24
16
|
export declare const do_: <O extends Operations, K extends keyof O & string>(cmd: K, payload: O[K][0]) => Do<O, O[K][1]>;
|
|
25
17
|
export type ToAsyncOperationMap<O extends Operations> = {
|
|
26
18
|
readonly [K in keyof O]: (payload: O[K][0]) => Promise<O[K][1]>;
|
|
27
19
|
};
|
|
20
|
+
export declare const step: <O extends Operations, T>(e: Effect<O, T>) => <O1 extends Operations, R>(f: (_: T) => Effect<O1, R>) => Effect<O | O1, R>;
|
|
21
|
+
export declare const map: <O extends Operations, T>(e: Effect<O, T>) => <R>(f: (_: T) => R) => Effect<O, R>;
|
|
22
|
+
export type Fluent<O extends Operations, T> = {
|
|
23
|
+
readonly effect: Effect<O, T>;
|
|
24
|
+
readonly step: <O1 extends Operations, R>(f: (_: T) => Effect<O1, R>) => Fluent<O | O1, R>;
|
|
25
|
+
};
|
|
26
|
+
export declare const fluent: Fluent<{}, void>;
|
|
28
27
|
export declare const all: <O extends Operations, T>(set: readonly Effect<O, T>[]) => Effect<O, readonly T[]>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const pure = (value) => [value];
|
|
2
|
+
const doFull = (cmd, payload, cont) => [cmd, payload, cont];
|
|
3
|
+
export const do_ = (cmd, payload) => doFull(cmd, payload, pure);
|
|
4
|
+
export const step = (e) => (f) => {
|
|
5
|
+
if (e.length === 1) {
|
|
6
|
+
const [value] = e;
|
|
7
|
+
return f(value);
|
|
8
|
+
}
|
|
9
|
+
const [cmd, payload, cont] = e;
|
|
10
|
+
return doFull(cmd, payload, x => step(cont(x))(f));
|
|
11
|
+
};
|
|
12
|
+
export const map = (e) => (f) => step(e)(x => pure(f(x)));
|
|
13
|
+
const wrap = (effect) => ({
|
|
14
|
+
effect,
|
|
15
|
+
step: x => wrap(step(effect)(x)),
|
|
16
|
+
});
|
|
17
|
+
export const fluent = wrap(pure(undefined));
|
|
18
|
+
const empty = pure([]);
|
|
19
|
+
// TODO: replace with either a `Do` operation or as an addition to `Pure` and `Do`.
|
|
20
|
+
export const all = (set) => set.reduce((previous, current) => step(previous)(previousResult => map(current)(currentResult => [...previousResult, currentResult])), empty);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export const asyncRun = (map) => async (effect) => {
|
|
2
2
|
while (true) {
|
|
3
|
-
if (
|
|
4
|
-
return effect
|
|
3
|
+
if (effect.length === 1) {
|
|
4
|
+
return effect[0];
|
|
5
5
|
}
|
|
6
|
-
const [command, payload, continuation] = effect
|
|
6
|
+
const [command, payload, continuation] = effect;
|
|
7
7
|
const operation = map[command];
|
|
8
8
|
const result = await operation(payload);
|
|
9
9
|
effect = continuation(result);
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { empty, isVec, uint, vec8 } from "../../bit_vec/module.f.js";
|
|
2
|
+
import { map } from "../module.f.js";
|
|
2
3
|
import { run } from "../mock/module.f.js";
|
|
3
4
|
import { fetch, mkdir, readdir, readFile, writeFile } from "./module.f.js";
|
|
4
5
|
import { emptyState, virtual } from "./virtual/module.f.js";
|
|
5
6
|
export default {
|
|
6
7
|
map: () => {
|
|
7
|
-
let e = readFile('hello')
|
|
8
|
+
let e = map(readFile('hello'))(([k, v]) => {
|
|
8
9
|
if (k === 'error') {
|
|
9
10
|
throw v;
|
|
10
11
|
}
|
|
@@ -12,14 +13,14 @@ export default {
|
|
|
12
13
|
});
|
|
13
14
|
//
|
|
14
15
|
while (true) {
|
|
15
|
-
if (
|
|
16
|
-
const result = e
|
|
16
|
+
if (e.length === 1) {
|
|
17
|
+
const result = e[0];
|
|
17
18
|
if (result !== 0x2an) {
|
|
18
19
|
throw result;
|
|
19
20
|
}
|
|
20
21
|
return;
|
|
21
22
|
}
|
|
22
|
-
const [cmd, p, cont] = e
|
|
23
|
+
const [cmd, p, cont] = e;
|
|
23
24
|
if (cmd !== 'readFile') {
|
|
24
25
|
throw cmd;
|
|
25
26
|
}
|
package/website/module.f.d.ts
CHANGED
package/website/module.f.js
CHANGED
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
import { htmlToString } from "../html/module.f.js";
|
|
7
|
-
import { writeFile } from "../types/
|
|
7
|
+
import { writeFile } from "../types/effects/node/module.f.js";
|
|
8
8
|
import { utf8 } from "../text/module.f.js";
|
|
9
|
+
import { fluent, pure } from "../types/effects/module.f.js";
|
|
9
10
|
const html = ['body',
|
|
10
11
|
['a', { href: 'https://github.com/functionalscript/functionalscript' }, 'GitHub Repository']
|
|
11
12
|
];
|
|
12
|
-
const program =
|
|
13
|
-
.
|
|
13
|
+
const program = fluent
|
|
14
|
+
.step(() => writeFile('index.html', utf8(htmlToString(html))))
|
|
15
|
+
.step(() => pure(0))
|
|
16
|
+
.effect;
|
|
14
17
|
export default () => program;
|
package/types/effect/module.f.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export const pure = (value) => ({
|
|
2
|
-
pure: value,
|
|
3
|
-
pipe: e => e(value),
|
|
4
|
-
map: f => pure(f(value))
|
|
5
|
-
});
|
|
6
|
-
const doFull = (cmd, payload, cont) => ({
|
|
7
|
-
do: [cmd, payload, cont],
|
|
8
|
-
pipe: e => doFull(cmd, payload, x => cont(x).pipe(e)),
|
|
9
|
-
map: f => doFull(cmd, payload, x => cont(x).map(f))
|
|
10
|
-
});
|
|
11
|
-
export const do_ = (cmd, payload) => doFull(cmd, payload, pure);
|
|
12
|
-
const empty = pure([]);
|
|
13
|
-
// TODO: replace with either a `Do` operation or as an addition to `Pure` and `Do`.
|
|
14
|
-
export const all = (set) => set.reduce((previous, current) => previous.pipe(previousResult => current.map(currentResult => [...previousResult, currentResult])), empty);
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|