functionalscript 0.17.0 → 0.18.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/ci/common/module.f.d.ts +4 -5
- package/fs/ci/common/module.f.js +4 -4
- package/fs/ci/config/module.f.d.ts +4 -4
- package/fs/ci/config/module.f.js +4 -4
- package/fs/ci/test.f.js +2 -4
- package/fs/dev/module.f.d.ts +3 -3
- package/fs/dev/module.f.js +12 -9
- package/fs/dev/tf/module.d.ts +1 -0
- package/fs/dev/tf/module.f.d.ts +70 -6
- package/fs/dev/tf/module.f.js +135 -87
- package/fs/dev/tf/module.js +66 -17
- package/fs/dev/tf/test.f.d.ts +21 -20
- package/fs/dev/tf/test.f.js +249 -31
- package/fs/djs/module.f.d.ts +2 -2
- package/fs/djs/module.f.js +8 -5
- package/fs/djs/test.f.js +5 -6
- package/fs/djs/tokenizer-new/test.f.js +126 -78
- package/fs/djs/transpiler/module.f.js +2 -2
- package/fs/djs/transpiler/test.f.js +11 -12
- package/fs/fjs/module.f.d.ts +2 -7
- package/fs/fjs/module.f.js +16 -22
- package/fs/fjs/module.js +2 -2
- package/fs/io/module.d.ts +3 -3
- package/fs/io/module.f.d.ts +5 -2
- package/fs/io/module.f.js +14 -3
- package/fs/io/module.js +38 -17
- package/fs/path/module.f.d.ts +6 -0
- package/fs/path/module.f.js +6 -0
- package/fs/path/test.f.d.ts +3 -5
- package/fs/path/test.f.js +67 -49
- package/fs/text/sgr/module.f.d.ts +9 -1
- package/fs/text/sgr/module.f.js +16 -5
- package/fs/types/effects/node/module.f.d.ts +17 -17
- package/fs/types/effects/node/module.f.js +20 -2
- package/fs/types/effects/node/test.f.js +8 -5
- package/fs/types/effects/node/virtual/module.f.d.ts +11 -2
- package/fs/types/effects/node/virtual/module.f.js +30 -17
- package/fs/types/function/compare/module.f.d.ts +12 -0
- package/fs/types/function/compare/module.f.js +33 -0
- package/fs/types/function/operator/test.f.d.ts +10 -0
- package/fs/types/function/operator/test.f.js +81 -0
- package/fs/types/range_map/module.f.js +3 -18
- package/fs/types/result/module.f.d.ts +4 -0
- package/fs/types/result/module.f.js +4 -0
- package/fs/types/result/test.f.d.ts +2 -4
- package/fs/types/result/test.f.js +24 -16
- package/fs/types/rtti/common/module.f.d.ts +10 -1
- package/fs/types/rtti/common/module.f.js +7 -2
- package/fs/types/rtti/parse/module.f.js +35 -46
- package/fs/types/rtti/validate/module.f.js +9 -12
- package/fs/types/sorted_list/module.f.d.ts +1 -2
- package/fs/types/sorted_list/module.f.js +8 -21
- package/fs/types/sorted_set/module.f.d.ts +1 -3
- package/fs/types/ts/test.f.d.ts +18 -0
- package/fs/types/ts/test.f.js +111 -0
- package/fs/types/uint8array/module.f.js +7 -1
- package/fs/types/uint8array/test.f.d.ts +1 -0
- package/fs/types/uint8array/test.f.js +5 -1
- package/package.json +1 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { join, concat, logicalNot, strictEqual, addition, min, max, increment, foldToScan, reduceToScan, } from "./module.f.js";
|
|
2
|
+
export const joinTest = () => {
|
|
3
|
+
const result = join(', ')('world')('hello');
|
|
4
|
+
if (result !== 'hello, world') {
|
|
5
|
+
throw result;
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
export const concatTest = () => {
|
|
9
|
+
const result = concat('world')('hello');
|
|
10
|
+
if (result !== 'helloworld') {
|
|
11
|
+
throw result;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
export const logicalNotTest = () => {
|
|
15
|
+
if (logicalNot(true) !== false) {
|
|
16
|
+
throw 'expected false';
|
|
17
|
+
}
|
|
18
|
+
if (logicalNot(false) !== true) {
|
|
19
|
+
throw 'expected true';
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export const strictEqualTest = () => {
|
|
23
|
+
if (!strictEqual(1)(1)) {
|
|
24
|
+
throw 'expected true';
|
|
25
|
+
}
|
|
26
|
+
if (strictEqual(1)(2)) {
|
|
27
|
+
throw 'expected false';
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
export const additionTest = () => {
|
|
31
|
+
const result = addition(3)(4);
|
|
32
|
+
if (result !== 7) {
|
|
33
|
+
throw result;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
export const minTest = () => {
|
|
37
|
+
if (min(3)(5) !== 3) {
|
|
38
|
+
throw 'min(3)(5)';
|
|
39
|
+
}
|
|
40
|
+
if (min(7)(2) !== 2) {
|
|
41
|
+
throw 'min(7)(2)';
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
export const maxTest = () => {
|
|
45
|
+
if (max(3)(5) !== 5) {
|
|
46
|
+
throw 'max(3)(5)';
|
|
47
|
+
}
|
|
48
|
+
if (max(7)(2) !== 7) {
|
|
49
|
+
throw 'max(7)(2)';
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
export const incrementTest = () => {
|
|
53
|
+
if (increment(4) !== 5) {
|
|
54
|
+
throw 'increment(4)';
|
|
55
|
+
}
|
|
56
|
+
if (increment(0) !== 1) {
|
|
57
|
+
throw 'increment(0)';
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export const foldToScanTest = () => {
|
|
61
|
+
const scan = foldToScan(addition)(0);
|
|
62
|
+
const [v1, scan2] = scan(3);
|
|
63
|
+
if (v1 !== 3) {
|
|
64
|
+
throw v1;
|
|
65
|
+
}
|
|
66
|
+
const [v2] = scan2(4);
|
|
67
|
+
if (v2 !== 7) {
|
|
68
|
+
throw v2;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
export const reduceToScanTest = () => {
|
|
72
|
+
const scan = reduceToScan(addition);
|
|
73
|
+
const [v0, scan2] = scan(10);
|
|
74
|
+
if (v0 !== 10) {
|
|
75
|
+
throw v0;
|
|
76
|
+
}
|
|
77
|
+
const [v1] = scan2(5);
|
|
78
|
+
if (v1 !== 15) {
|
|
79
|
+
throw v1;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
import { genericMerge } from "../sorted_list/module.f.js";
|
|
38
38
|
import { next } from "../list/module.f.js";
|
|
39
39
|
import { cmp } from "../number/module.f.js";
|
|
40
|
+
import { bsearch } from "../function/compare/module.f.js";
|
|
40
41
|
const reduceOp = ({ union, equal }) => state => ([aItem, aMax]) => ([bItem, bMax]) => {
|
|
41
42
|
const sign = cmp(aMax)(bMax);
|
|
42
43
|
const min = sign === 1 ? bMax : aMax;
|
|
@@ -59,24 +60,8 @@ const tailReduce = equal => state => tail => {
|
|
|
59
60
|
};
|
|
60
61
|
export const merge = op => genericMerge({ reduceOp: reduceOp(op), tailReduce: tailReduce(op.equal) })(null);
|
|
61
62
|
export const get = def => value => rm => {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
let e = len - 1;
|
|
65
|
-
while (true) {
|
|
66
|
-
if (b >= len) {
|
|
67
|
-
return def;
|
|
68
|
-
}
|
|
69
|
-
if (e - b < 0) {
|
|
70
|
-
return rm[b][0];
|
|
71
|
-
}
|
|
72
|
-
const mid = b + (e - b >> 1);
|
|
73
|
-
if (value <= rm[mid][1]) {
|
|
74
|
-
e = mid - 1;
|
|
75
|
-
}
|
|
76
|
-
else {
|
|
77
|
-
b = mid + 1;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
63
|
+
const pos = bsearch(rm.length)(mid => value <= rm[mid][1] ? -1 : 1);
|
|
64
|
+
return pos < rm.length ? rm[pos][0] : def;
|
|
80
65
|
};
|
|
81
66
|
export const fromRange = def => ([a, b]) => v => [[def, a - 1], [v, b]];
|
|
82
67
|
/**
|
|
@@ -51,3 +51,7 @@ export declare const error: <E>(e: E) => Error<E>;
|
|
|
51
51
|
* @returns The value if the result is successful. Otherwise, throws the error.
|
|
52
52
|
*/
|
|
53
53
|
export declare const unwrap: <T, E>([kind, v]: Result<T, E>) => T;
|
|
54
|
+
/**
|
|
55
|
+
* Swaps the `ok` and `error` cases of a result.
|
|
56
|
+
*/
|
|
57
|
+
export declare const invert: <T, E>([k, v]: Result<T, E>) => Result<E, T>;
|
|
@@ -1,18 +1,26 @@
|
|
|
1
|
-
import { error, ok, unwrap } from "./module.f.js";
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
1
|
+
import { error, ok, unwrap, invert } from "./module.f.js";
|
|
2
|
+
export const example = () => {
|
|
3
|
+
const success = ok(42);
|
|
4
|
+
const failure = error('Something went wrong');
|
|
5
|
+
if (unwrap(success) !== 42) {
|
|
6
|
+
throw 'error';
|
|
7
|
+
}
|
|
8
|
+
const [kind, v] = failure;
|
|
9
|
+
if (kind !== 'error') {
|
|
10
|
+
throw 'error';
|
|
11
|
+
}
|
|
12
|
+
// `v` is inferred as `string` here
|
|
13
|
+
if (v !== 'Something went wrong') {
|
|
14
|
+
throw 'error';
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
export const invertTest = () => {
|
|
18
|
+
const [k0, v0] = invert(ok(42));
|
|
19
|
+
if (k0 !== 'error' || v0 !== 42) {
|
|
20
|
+
throw [k0, v0];
|
|
21
|
+
}
|
|
22
|
+
const [k1, v1] = invert(error('oops'));
|
|
23
|
+
if (k1 !== 'ok' || v1 !== 'oops') {
|
|
24
|
+
throw [k1, v1];
|
|
17
25
|
}
|
|
18
26
|
};
|
|
@@ -23,9 +23,10 @@
|
|
|
23
23
|
* @module
|
|
24
24
|
*/
|
|
25
25
|
import type { Primitive, Unknown } from '../../../djs/module.f.ts';
|
|
26
|
-
import { type Info0, type Primitive0, type Struct, type Tuple, type Type } from '../module.f.ts';
|
|
26
|
+
import { type Info0, type Primitive0, type Struct, type Tag1, type Tuple, type Type } from '../module.f.ts';
|
|
27
27
|
import { type Error, type Result as CommonResult } from '../../result/module.f.ts';
|
|
28
28
|
import type { Ts } from '../ts/module.f.ts';
|
|
29
|
+
import { type ReadonlyRecord } from '../../object/module.f.ts';
|
|
29
30
|
/** A path to a sub-value within the validated structure. Each step is an object key or stringified array index. */
|
|
30
31
|
export type Path = readonly string[];
|
|
31
32
|
/** Detailed validation failure: the offending `path` plus a short `message`. */
|
|
@@ -65,6 +66,14 @@ export type Visitor<R> = {
|
|
|
65
66
|
readonly primitive0: (tag: Primitive0) => R;
|
|
66
67
|
readonly unknown: () => R;
|
|
67
68
|
};
|
|
69
|
+
/** Type guard narrowing `Unknown` to a specific container type `C`. */
|
|
70
|
+
export type IsContainer<C extends Unknown> = (value: Unknown) => value is C;
|
|
71
|
+
/** Maps a `Tag1` to its runtime container type. */
|
|
72
|
+
export type Container<K extends Tag1> = K extends 'array' ? ReadonlyArray<Unknown> : ReadonlyRecord<string, Unknown>;
|
|
73
|
+
/** `IsContainer` guard for arrays, shared by `validate` and `parse`. */
|
|
74
|
+
export declare const isArray: IsContainer<ReadonlyArray<Unknown>>;
|
|
75
|
+
/** `IsContainer` guard for records/structs, shared by `validate` and `parse`. */
|
|
76
|
+
export declare const isObject: IsContainer<ReadonlyRecord<string, Unknown>>;
|
|
68
77
|
/**
|
|
69
78
|
* Visits a schema `Type` by dispatching to the matching handler in `v`.
|
|
70
79
|
*
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {} from "../module.f.js";
|
|
2
2
|
import { error, ok } from "../../result/module.f.js";
|
|
3
|
-
import { isArray } from "../../array/module.f.js";
|
|
3
|
+
import { isArray as commonIsArray } from "../../array/module.f.js";
|
|
4
|
+
import { isObject as commonIsObject } from "../../object/module.f.js";
|
|
4
5
|
/** Builds an error result with empty path and the given message. */
|
|
5
6
|
export const verror = (message) => error({ path: [], message });
|
|
6
7
|
/** Prepends `key` to the error's path, used to build the path bottom-up. */
|
|
@@ -18,8 +19,12 @@ export const constPrimitiveValidate = (rtti) => value => Object.is(rtti, value)
|
|
|
18
19
|
? ok(value)
|
|
19
20
|
: verror('unexpected value');
|
|
20
21
|
const visitConst = (v) => (c) => typeof c === 'object' && c !== null
|
|
21
|
-
? (
|
|
22
|
+
? (commonIsArray(c) ? v.tuple(c) : v.struct(c))
|
|
22
23
|
: v.constPrimitive(c);
|
|
24
|
+
/** `IsContainer` guard for arrays, shared by `validate` and `parse`. */
|
|
25
|
+
export const isArray = value => commonIsArray(value);
|
|
26
|
+
/** `IsContainer` guard for records/structs, shared by `validate` and `parse`. */
|
|
27
|
+
export const isObject = value => commonIsObject(value);
|
|
23
28
|
/**
|
|
24
29
|
* Visits a schema `Type` by dispatching to the matching handler in `v`.
|
|
25
30
|
*
|
|
@@ -1,71 +1,60 @@
|
|
|
1
1
|
import {} from "../module.f.js";
|
|
2
2
|
import { ok } from "../../result/module.f.js";
|
|
3
|
-
import {
|
|
4
|
-
import { isObject as commonIsObject } from "../../object/module.f.js";
|
|
3
|
+
import {} from "../../object/module.f.js";
|
|
5
4
|
import { find, map as listMap } from "../../list/module.f.js";
|
|
6
|
-
import { constPrimitiveValidate, prependPath, primitive0Validate, verror, visit, } from "../common/module.f.js";
|
|
5
|
+
import { constPrimitiveValidate, isArray, isObject, prependPath, primitive0Validate, verror, visit, } from "../common/module.f.js";
|
|
7
6
|
export {} from "../common/module.f.js";
|
|
8
|
-
const
|
|
9
|
-
// TODO: findIndex breaks type inference,
|
|
10
|
-
// we should replace it with something else.
|
|
11
|
-
const i = results.findIndex(r => r[0] === 'error');
|
|
12
|
-
return i < 0 ? null : [i, results[i]];
|
|
13
|
-
};
|
|
7
|
+
const { entries } = Object;
|
|
14
8
|
const keyedFirstError = (results) => {
|
|
15
9
|
const e = results.find(([, r]) => r[0] === 'error');
|
|
16
10
|
return e === undefined ? null : [e[0], e[1]];
|
|
17
11
|
};
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
? ok(results.map(r => r[1]))
|
|
32
|
-
: prependPath(String(err[0]), err[1]));
|
|
33
|
-
};
|
|
34
|
-
const recordParse = (item) => value => {
|
|
35
|
-
if (!commonIsObject(value)) {
|
|
12
|
+
const arrayRebuild = entries => entries.map(([, v]) => v);
|
|
13
|
+
const recordRebuild = entries => Object.fromEntries(entries);
|
|
14
|
+
/** Drops the `'ok'` tag from each result, yielding the rebuild's `[key, value]` entries. */
|
|
15
|
+
const okEntries = (results) => results.map(([k, r]) => [k, r[1]]);
|
|
16
|
+
/**
|
|
17
|
+
* Builds a parser for `array` or `record` schemas. Mirrors `validate`'s
|
|
18
|
+
* `containerValidate`, but rebuilds a fresh container from each item's parsed
|
|
19
|
+
* result instead of returning the value unchanged. The inner item parser is
|
|
20
|
+
* instantiated lazily (only when the container is non-empty) so recursive
|
|
21
|
+
* schemas don't recurse forever on empty containers.
|
|
22
|
+
*/
|
|
23
|
+
const containerParse = (isContainer, rebuild) => (item) => value => {
|
|
24
|
+
if (!isContainer(value)) {
|
|
36
25
|
return verror('unexpected value');
|
|
37
26
|
}
|
|
38
|
-
const
|
|
39
|
-
if (
|
|
40
|
-
return ok(
|
|
27
|
+
const e = entries(value);
|
|
28
|
+
if (e.length === 0) {
|
|
29
|
+
return ok(rebuild([]));
|
|
41
30
|
}
|
|
42
31
|
const itemParse = parse(item);
|
|
43
|
-
const results =
|
|
32
|
+
const results = e.map(([k, v]) => [k, itemParse(v)]);
|
|
44
33
|
const err = keyedFirstError(results);
|
|
45
34
|
return (err === null
|
|
46
|
-
? ok(
|
|
35
|
+
? ok(rebuild(okEntries(results)))
|
|
47
36
|
: prependPath(err[0], err[1]));
|
|
48
37
|
};
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const structParse = (rtti) => value => {
|
|
60
|
-
if (!commonIsObject(value)) {
|
|
38
|
+
const arrayParse = containerParse(isArray, arrayRebuild);
|
|
39
|
+
const recordParse = containerParse(isObject, recordRebuild);
|
|
40
|
+
/**
|
|
41
|
+
* Builds a parser for `Tuple` or `Struct` const schemas. Mirrors `validate`'s
|
|
42
|
+
* `constContainerValidate`: it iterates the schema's entries (so extra tuple
|
|
43
|
+
* elements and undeclared struct keys are dropped) and rebuilds the result
|
|
44
|
+
* from each parsed item.
|
|
45
|
+
*/
|
|
46
|
+
const constContainerParse = (isContainer, getItem, rebuild) => (rtti) => value => {
|
|
47
|
+
if (!isContainer(value)) {
|
|
61
48
|
return verror('unexpected value');
|
|
62
49
|
}
|
|
63
|
-
const results =
|
|
50
|
+
const results = entries(rtti).map(([k, t]) => [k, parse(t)(getItem(value, k))]);
|
|
64
51
|
const err = keyedFirstError(results);
|
|
65
52
|
return (err === null
|
|
66
|
-
? ok(
|
|
53
|
+
? ok(rebuild(okEntries(results)))
|
|
67
54
|
: prependPath(err[0], err[1]));
|
|
68
55
|
};
|
|
56
|
+
const tupleParse = constContainerParse(isArray, (value, k) => value[Number(k)], arrayRebuild);
|
|
57
|
+
const structParse = constContainerParse(isObject, (value, k) => value[k], recordRebuild);
|
|
69
58
|
const findFirst = find(verror('no match'))((k) => k[0] === 'ok');
|
|
70
59
|
const orParse = (rtti) => value => findFirst(listMap(t => parse(t)(value))(rtti));
|
|
71
60
|
/**
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import {} from "../module.f.js";
|
|
2
2
|
import { ok } from "../../result/module.f.js";
|
|
3
|
-
import {
|
|
4
|
-
import { isObject
|
|
5
|
-
import { constPrimitiveValidate, prependPath, primitive0Validate, verror, visit, } from "../common/module.f.js";
|
|
3
|
+
import {} from "../../object/module.f.js";
|
|
4
|
+
import { constPrimitiveValidate, isArray, isObject, prependPath, primitive0Validate, verror, visit, } from "../common/module.f.js";
|
|
6
5
|
export { constPrimitiveValidate, prependPath, primitive0Validate, verror, } from "../common/module.f.js";
|
|
6
|
+
const { entries } = Object;
|
|
7
7
|
/**
|
|
8
8
|
* Builds a validator for `array` or `record` schemas.
|
|
9
9
|
* The inner item validator is instantiated lazily (only when the container is
|
|
10
10
|
* non-empty) to avoid infinite recursion with recursive schemas.
|
|
11
11
|
*/
|
|
12
|
-
const containerValidate = (isContainer
|
|
12
|
+
const containerValidate = (isContainer) => (item) => value => {
|
|
13
13
|
if (!isContainer(value)) {
|
|
14
14
|
return verror('unexpected value');
|
|
15
15
|
}
|
|
16
|
-
const
|
|
17
|
-
if (
|
|
16
|
+
const e = entries(value);
|
|
17
|
+
if (e.length === 0) {
|
|
18
18
|
return ok(value);
|
|
19
19
|
}
|
|
20
20
|
// Note: we shouldn't instantiate `itemValidate` until we make sure `entries` is not empty.
|
|
21
21
|
// Otherwise, we can get infinite recursion on empty arrays and objects
|
|
22
22
|
const itemValidate = validate(item);
|
|
23
|
-
for (const [k, v] of
|
|
23
|
+
for (const [k, v] of e) {
|
|
24
24
|
const r = itemValidate(v);
|
|
25
25
|
if (r[0] === 'error') {
|
|
26
26
|
return prependPath(k, r);
|
|
@@ -28,11 +28,8 @@ const containerValidate = (isContainer, getEntries) => (item) => value => {
|
|
|
28
28
|
}
|
|
29
29
|
return ok(value);
|
|
30
30
|
};
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
const arrayValidate = containerValidate(isArray, arrayEntries);
|
|
34
|
-
const isObject = value => commonIsObject(value);
|
|
35
|
-
const recordValidate = containerValidate(isObject, Object.entries);
|
|
31
|
+
const arrayValidate = containerValidate(isArray);
|
|
32
|
+
const recordValidate = containerValidate(isObject);
|
|
36
33
|
/**
|
|
37
34
|
* Builds a validator for `Tuple` or `Struct` const schemas.
|
|
38
35
|
* Iterates over the schema's entries and validates each corresponding
|
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import type
|
|
6
|
+
import { type Sign, type Cmp } from '../function/compare/module.f.ts';
|
|
7
7
|
import { type List } from '../list/module.f.ts';
|
|
8
8
|
import type { Nullable } from '../nullable/module.f.ts';
|
|
9
9
|
export type SortedList<T> = List<T>;
|
|
10
10
|
type SortedArray<T> = readonly T[];
|
|
11
|
-
type Cmp<T> = (a: T) => (b: T) => Sign;
|
|
12
11
|
export type ReduceOp<T, S> = (state: S) => (a: T) => (b: T) => readonly [Nullable<T>, Sign, S];
|
|
13
12
|
export type TailReduce<T, S> = (state: S) => (tail: List<T>) => List<T>;
|
|
14
13
|
type MergeReduce<T, S> = {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sorted immutable list helpers and merge operations.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { bsearch } from "../function/compare/module.f.js";
|
|
1
7
|
import { next } from "../list/module.f.js";
|
|
2
8
|
import { identity } from "../function/module.f.js";
|
|
3
9
|
export const genericMerge = ({ reduceOp, tailReduce }) => {
|
|
@@ -29,25 +35,6 @@ const cmpReduce = (cmp) => () => a => b => {
|
|
|
29
35
|
const mergeTail = () => identity;
|
|
30
36
|
export const find = (cmp) => (value) => (array) => {
|
|
31
37
|
const cmpValue = cmp(value);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
while (true) {
|
|
35
|
-
const d = e - b;
|
|
36
|
-
if (d < 0)
|
|
37
|
-
return null;
|
|
38
|
-
const mid = b + (d >> 1);
|
|
39
|
-
switch (cmpValue(array[mid])) {
|
|
40
|
-
case -1: {
|
|
41
|
-
e = mid - 1;
|
|
42
|
-
break;
|
|
43
|
-
}
|
|
44
|
-
case 0: {
|
|
45
|
-
return value;
|
|
46
|
-
}
|
|
47
|
-
case 1: {
|
|
48
|
-
b = mid + 1;
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
38
|
+
const pos = bsearch(array.length)(mid => cmpValue(array[mid]));
|
|
39
|
+
return pos < array.length && cmpValue(array[pos]) === 0 ? value : null;
|
|
53
40
|
};
|
|
@@ -26,10 +26,8 @@
|
|
|
26
26
|
* has(cmp)(2)(setA) // false
|
|
27
27
|
* ```
|
|
28
28
|
*/
|
|
29
|
-
import type {
|
|
29
|
+
import type { Cmp } from '../function/compare/module.f.ts';
|
|
30
30
|
export type SortedSet<T> = readonly T[];
|
|
31
|
-
type Cmp<T> = (a: T) => (b: T) => Sign;
|
|
32
31
|
export declare const union: <T>(cmp: Cmp<T>) => (a: SortedSet<T>) => (b: SortedSet<T>) => SortedSet<T>;
|
|
33
32
|
export declare const intersect: <T>(cmp: Cmp<T>) => (a: SortedSet<T>) => (b: SortedSet<T>) => SortedSet<T>;
|
|
34
33
|
export declare const has: <T>(cmp: Cmp<T>) => (value: T) => (set: SortedSet<T>) => boolean;
|
|
35
|
-
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const primitiveNull: () => void;
|
|
2
|
+
export declare const primitiveBigint: () => void;
|
|
3
|
+
export declare const primitiveString: () => void;
|
|
4
|
+
export declare const primitiveNumberFinite: () => void;
|
|
5
|
+
export declare const primitiveNumberInfinite: () => void;
|
|
6
|
+
export declare const primitiveUndefined: () => void;
|
|
7
|
+
export declare const primitiveBoolean: () => void;
|
|
8
|
+
export declare const unionEmpty: () => void;
|
|
9
|
+
export declare const unionSingle: () => void;
|
|
10
|
+
export declare const unionMulti: () => void;
|
|
11
|
+
export declare const printerReadonlyTuple: () => void;
|
|
12
|
+
export declare const printerReadonlyStruct: () => void;
|
|
13
|
+
export declare const printerReadonlyArray: () => void;
|
|
14
|
+
export declare const printerReadonlyRecord: () => void;
|
|
15
|
+
export declare const printerMutableTuple: () => void;
|
|
16
|
+
export declare const printerMutableStruct: () => void;
|
|
17
|
+
export declare const printerMutableArray: () => void;
|
|
18
|
+
export declare const printerMutableRecord: () => void;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { printer, primitive, union } from "./module.f.js";
|
|
2
|
+
const ro = printer();
|
|
3
|
+
const mut = printer(true);
|
|
4
|
+
export const primitiveNull = () => {
|
|
5
|
+
const r = primitive(null);
|
|
6
|
+
if (r !== 'null') {
|
|
7
|
+
throw r;
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
export const primitiveBigint = () => {
|
|
11
|
+
const r = primitive(42n);
|
|
12
|
+
if (r !== '42n') {
|
|
13
|
+
throw r;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
export const primitiveString = () => {
|
|
17
|
+
const r = primitive('hello');
|
|
18
|
+
if (r !== '"hello"') {
|
|
19
|
+
throw r;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
export const primitiveNumberFinite = () => {
|
|
23
|
+
const r = primitive(3.14);
|
|
24
|
+
if (r !== '3.14') {
|
|
25
|
+
throw r;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
export const primitiveNumberInfinite = () => {
|
|
29
|
+
const r = primitive(Infinity);
|
|
30
|
+
if (r !== 'number') {
|
|
31
|
+
throw r;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
export const primitiveUndefined = () => {
|
|
35
|
+
const r = primitive(undefined);
|
|
36
|
+
if (r !== 'undefined') {
|
|
37
|
+
throw r;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
export const primitiveBoolean = () => {
|
|
41
|
+
const r = primitive(true);
|
|
42
|
+
if (r !== 'true') {
|
|
43
|
+
throw r;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
export const unionEmpty = () => {
|
|
47
|
+
const r = union([]);
|
|
48
|
+
if (r !== 'never') {
|
|
49
|
+
throw r;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
export const unionSingle = () => {
|
|
53
|
+
const r = union(['string']);
|
|
54
|
+
if (r !== 'string') {
|
|
55
|
+
throw r;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
export const unionMulti = () => {
|
|
59
|
+
const r = union(['string', 'number']);
|
|
60
|
+
if (r !== 'string|number') {
|
|
61
|
+
throw r;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
export const printerReadonlyTuple = () => {
|
|
65
|
+
const r = ro.tuple(['string', 'number']);
|
|
66
|
+
if (r !== 'readonly[string,number]') {
|
|
67
|
+
throw r;
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
export const printerReadonlyStruct = () => {
|
|
71
|
+
const r = ro.struct([['x', 'number'], ['y', 'string']]);
|
|
72
|
+
if (r !== '{readonly"x":number,readonly"y":string}') {
|
|
73
|
+
throw r;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
export const printerReadonlyArray = () => {
|
|
77
|
+
const r = ro.array('string');
|
|
78
|
+
if (r !== 'readonly(string)[]') {
|
|
79
|
+
throw r;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
export const printerReadonlyRecord = () => {
|
|
83
|
+
const r = ro.record('number');
|
|
84
|
+
if (r !== '{readonly[k:string]:number}') {
|
|
85
|
+
throw r;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
export const printerMutableTuple = () => {
|
|
89
|
+
const r = mut.tuple(['string', 'number']);
|
|
90
|
+
if (r !== '[string,number]') {
|
|
91
|
+
throw r;
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
export const printerMutableStruct = () => {
|
|
95
|
+
const r = mut.struct([['x', 'number']]);
|
|
96
|
+
if (r !== '{"x":number}') {
|
|
97
|
+
throw r;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
export const printerMutableArray = () => {
|
|
101
|
+
const r = mut.array('string');
|
|
102
|
+
if (r !== '(string)[]') {
|
|
103
|
+
throw r;
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
export const printerMutableRecord = () => {
|
|
107
|
+
const r = mut.record('number');
|
|
108
|
+
if (r !== '{[k:string]:number}') {
|
|
109
|
+
throw r;
|
|
110
|
+
}
|
|
111
|
+
};
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Conversions between Uint8Array values and bit vectors.
|
|
2
|
+
* Conversions between `Uint8Array` values and bit vectors.
|
|
3
|
+
*
|
|
4
|
+
* @deprecated FunctionalScript represents byte data as `bigint`-based bit
|
|
5
|
+
* vectors (`Vec` from `fs/types/bit_vec`). Use `utf8`/`utf8ToString` from
|
|
6
|
+
* `fs/text` for string encoding, and the `bit_vec` module directly for raw
|
|
7
|
+
* byte manipulation. `Uint8Array` interop belongs at Node.js boundaries only
|
|
8
|
+
* (e.g. `fromVec`/`toVec` when reading or writing files).
|
|
3
9
|
*
|
|
4
10
|
* @module
|
|
5
11
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { vec } from "../bit_vec/module.f.js";
|
|
2
|
-
import { toVec, fromVec, decodeUtf8, encodeUtf8 } from "./module.f.js";
|
|
2
|
+
import { toVec, fromVec, listToVec, decodeUtf8, encodeUtf8 } from "./module.f.js";
|
|
3
3
|
import { strictEqual } from "../function/operator/module.f.js";
|
|
4
4
|
import { equal, fromArrayLike } from "../list/module.f.js";
|
|
5
5
|
const assertEq = (a, b) => {
|
|
@@ -54,5 +54,9 @@ export default {
|
|
|
54
54
|
const input = 'FunctionalScript 🐝';
|
|
55
55
|
const output = decodeUtf8(encodeUtf8(input));
|
|
56
56
|
assertEq(output, input);
|
|
57
|
+
},
|
|
58
|
+
listToVec: () => {
|
|
59
|
+
const result = listToVec([Uint8Array.from([1, 2]), Uint8Array.from([3])]);
|
|
60
|
+
assertArrayEq(fromVec(result), Uint8Array.from([1, 2, 3]));
|
|
57
61
|
}
|
|
58
62
|
};
|