functionalscript 0.19.0 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fs/asn.1/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/asn.1/{test.f.js → proof.f.js} +1 -1
- package/fs/asserts/module.f.d.ts +4 -0
- package/fs/asserts/module.f.js +6 -0
- package/fs/base128/proof.f.d.ts +1 -0
- package/fs/base128/{test.f.js → proof.f.js} +1 -1
- package/fs/bnf/data/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/bnf/data/{test.f.js → proof.f.js} +1 -1
- package/fs/bnf/proof.f.d.ts +3 -0
- package/fs/bnf/{test.f.js → proof.f.js} +1 -1
- package/fs/cas/module.f.js +9 -23
- package/fs/cas/proof.f.d.ts +4 -0
- package/fs/cas/proof.f.js +37 -0
- package/fs/cbase32/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/cbase32/{test.f.js → proof.f.js} +1 -1
- package/fs/ci/bun/module.f.js +2 -7
- package/fs/ci/common/module.f.d.ts +2 -1
- package/fs/ci/common/module.f.js +7 -9
- package/fs/ci/config/module.f.d.ts +12 -3
- package/fs/ci/config/module.f.js +24 -4
- package/fs/ci/deno/module.f.js +2 -5
- package/fs/ci/node/module.f.js +14 -9
- package/fs/ci/playwright/module.f.js +5 -8
- package/fs/ci/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/ci/{test.f.js → proof.f.js} +2 -2
- package/fs/ci/rust/module.f.js +3 -9
- package/fs/crypto/hmac/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/crypto/hmac/{test.f.js → proof.f.js} +1 -1
- package/fs/crypto/secp/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/crypto/secp/{test.f.js → proof.f.js} +1 -1
- package/fs/crypto/sha2/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/crypto/sha2/{test.f.js → proof.f.js} +1 -1
- package/fs/crypto/sign/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/crypto/sign/{test.f.js → proof.f.js} +1 -1
- package/fs/dev/module.f.d.ts +28 -5
- package/fs/dev/module.f.js +38 -28
- package/fs/dev/{test.f.d.ts → proof.f.d.ts} +5 -2
- package/fs/dev/{test.f.js → proof.f.js} +26 -2
- package/fs/dev/version/proof.f.d.ts +3 -0
- package/fs/dev/version/{test.f.js → proof.f.js} +1 -1
- package/fs/djs/ast/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/djs/ast/{test.f.js → proof.f.js} +1 -1
- package/fs/djs/parser/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/djs/parser/{test.f.js → proof.f.js} +1 -1
- package/fs/djs/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/djs/{test.f.js → proof.f.js} +1 -1
- package/fs/djs/serializer/module.f.d.ts +2 -2
- package/fs/djs/serializer/module.f.js +47 -79
- package/fs/djs/serializer/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/djs/serializer/{test.f.js → proof.f.js} +8 -8
- package/fs/djs/tokenizer/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/djs/tokenizer/{test.f.js → proof.f.js} +1 -1
- package/fs/djs/tokenizer-new/module.f.js +1 -1
- package/fs/djs/tokenizer-new/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/djs/tokenizer-new/{test.f.js → proof.f.js} +1 -1
- package/fs/djs/transpiler/module.f.d.ts +15 -0
- package/fs/djs/transpiler/module.f.js +10 -2
- package/fs/djs/transpiler/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/djs/transpiler/{test.f.js → proof.f.js} +1 -1
- package/fs/{dev/tf → emergent-testing}/module.f.d.ts +66 -8
- package/fs/{dev/tf → emergent-testing}/module.f.js +101 -34
- package/fs/{dev/tf → emergent-testing}/module.js +2 -2
- package/fs/{dev/tf/test.f.d.ts → emergent-testing/proof.f.d.ts} +28 -0
- package/fs/{dev/tf/test.f.js → emergent-testing/proof.f.js} +119 -40
- package/fs/emergent-testing/scenarios/async-subtests.fail.d.ts +6 -0
- package/fs/emergent-testing/scenarios/async-subtests.fail.js +9 -0
- package/fs/emergent-testing/scenarios/async-subtests.pass.d.ts +6 -0
- package/fs/emergent-testing/scenarios/async-subtests.pass.js +9 -0
- package/fs/emergent-testing/scenarios/async.fail.d.ts +3 -0
- package/fs/emergent-testing/scenarios/async.fail.js +6 -0
- package/fs/emergent-testing/scenarios/async.pass.d.ts +3 -0
- package/fs/emergent-testing/scenarios/async.pass.js +5 -0
- package/fs/emergent-testing/scenarios/fail.fail.d.ts +3 -0
- package/fs/emergent-testing/scenarios/fail.fail.js +3 -0
- package/fs/emergent-testing/scenarios/return-value.pass.d.ts +3 -0
- package/fs/emergent-testing/scenarios/return-value.pass.js +4 -0
- package/fs/emergent-testing/scenarios/thenable.pass.d.ts +5 -0
- package/fs/emergent-testing/scenarios/thenable.pass.js +11 -0
- package/fs/emergent-testing/scenarios/thenable2.pass.d.ts +5 -0
- package/fs/emergent-testing/scenarios/thenable2.pass.js +3 -0
- package/fs/emergent-testing/scenarios/throw.pass.d.ts +5 -0
- package/fs/{dev/tf/scenarios/throw.pass.f.js → emergent-testing/scenarios/throw.pass.js} +1 -1
- package/fs/fjs/module.f.js +4 -5
- package/fs/fsc/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/fsc/{test.f.js → proof.f.js} +1 -1
- package/fs/fsm/proof.f.d.ts +4 -0
- package/fs/fsm/{test.f.js → proof.f.js} +1 -1
- package/fs/html/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/html/{test.f.js → proof.f.js} +1 -1
- package/fs/io/module.d.ts +1 -1
- package/fs/io/module.f.d.ts +3 -2
- package/fs/io/module.f.js +4 -3
- package/fs/io/module.js +19 -11
- package/fs/js/tokenizer/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/js/tokenizer/{test.f.js → proof.f.js} +1 -1
- package/fs/json/parser/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/json/parser/{test.f.js → proof.f.js} +1 -1
- package/fs/json/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/json/{test.f.js → proof.f.js} +1 -1
- package/fs/json/serializer/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/json/serializer/{test.f.js → proof.f.js} +1 -1
- package/fs/json/tokenizer/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/json/tokenizer/{test.f.js → proof.f.js} +1 -1
- package/fs/path/proof.f.d.ts +5 -0
- package/fs/path/{test.f.js → proof.f.js} +4 -3
- package/fs/sul/id/module.f.js +1 -1
- package/fs/sul/id/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/sul/id/{test.f.js → proof.f.js} +2 -2
- package/fs/sul/level/hash/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/sul/level/hash/{test.f.js → proof.f.js} +2 -2
- package/fs/sul/level/literal/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/sul/level/literal/{test.f.js → proof.f.js} +1 -1
- package/fs/sul/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/sul/{test.f.js → proof.f.js} +2 -2
- package/fs/text/ascii/proof.f.d.ts +3 -0
- package/fs/text/ascii/{test.f.js → proof.f.js} +1 -1
- package/fs/text/code_point/module.f.d.ts +28 -0
- package/fs/text/code_point/module.f.js +31 -0
- package/fs/text/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/text/{test.f.js → proof.f.js} +1 -1
- package/fs/text/sgr/proof.f.d.ts +1 -0
- package/fs/text/sgr/{test.f.js → proof.f.js} +1 -1
- package/fs/text/utf16/module.f.js +3 -53
- package/fs/text/utf16/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/text/utf16/{test.f.js → proof.f.js} +1 -1
- package/fs/text/utf8/module.f.js +3 -25
- package/fs/text/utf8/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/text/utf8/{test.f.js → proof.f.js} +1 -1
- package/fs/types/array/module.f.js +2 -5
- package/fs/types/array/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/array/{test.f.js → proof.f.js} +1 -1
- package/fs/types/bigfloat/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/bigfloat/{test.f.js → proof.f.js} +1 -1
- package/fs/types/bigint/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/bigint/{test.f.js → proof.f.js} +1 -1
- package/fs/types/bit_vec/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/bit_vec/{test.f.js → proof.f.js} +1 -1
- package/fs/types/btree/find/proof.f.d.ts +1 -0
- package/fs/types/btree/find/{test.f.js → proof.f.js} +1 -1
- package/fs/types/btree/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/btree/{test.f.js → proof.f.js} +1 -1
- package/fs/types/btree/remove/proof.f.d.ts +4 -0
- package/fs/types/btree/remove/{test.f.js → proof.f.js} +1 -1
- package/fs/types/btree/set/proof.f.d.ts +1 -0
- package/fs/types/btree/set/{test.f.js → proof.f.js} +1 -1
- package/fs/types/btree/types/module.f.d.ts +8 -0
- package/fs/types/btree/types/module.f.js +8 -0
- package/fs/types/byte_set/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/byte_set/{test.f.js → proof.f.js} +1 -1
- package/fs/types/effects/module.f.d.ts +17 -0
- package/fs/types/effects/module.f.js +17 -0
- package/fs/types/effects/node/module.f.d.ts +60 -5
- package/fs/types/effects/node/module.f.js +12 -1
- package/fs/types/effects/node/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/effects/node/{test.f.js → proof.f.js} +1 -1
- package/fs/types/effects/node/virtual/module.f.js +2 -1
- package/fs/types/effects/proof.f.d.ts +11 -0
- package/fs/types/effects/proof.f.js +57 -0
- package/fs/types/function/compare/proof.f.d.ts +1 -0
- package/fs/types/function/compare/{test.f.js → proof.f.js} +1 -1
- package/fs/types/function/operator/proof.f.d.ts +12 -0
- package/fs/types/function/operator/{test.f.js → proof.f.js} +11 -10
- package/fs/types/function/proof.f.d.ts +1 -0
- package/fs/types/function/{test.f.js → proof.f.js} +1 -1
- package/fs/types/list/{test.f.d.ts → proof.f.d.ts} +2 -2
- package/fs/types/list/{test.f.js → proof.f.js} +15 -1
- package/fs/types/map/proof.f.d.ts +4 -0
- package/fs/types/map/{test.f.js → proof.f.js} +1 -1
- package/fs/types/monoid/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/monoid/{test.f.js → proof.f.js} +1 -1
- package/fs/types/nibble_set/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/nibble_set/{test.f.js → proof.f.js} +1 -1
- package/fs/types/nominal/proof.f.d.ts +4 -0
- package/fs/types/nominal/{test.f.js → proof.f.js} +1 -1
- package/fs/types/nullable/module.f.d.ts +7 -0
- package/fs/types/nullable/module.f.js +7 -0
- package/fs/types/nullable/proof.f.d.ts +1 -0
- package/fs/types/nullable/{test.f.js → proof.f.js} +20 -3
- package/fs/types/number/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/number/{test.f.js → proof.f.js} +1 -1
- package/fs/types/object/module.f.js +2 -4
- package/fs/types/object/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/object/{test.f.js → proof.f.js} +1 -1
- package/fs/types/ordered_map/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/ordered_map/{test.f.js → proof.f.js} +1 -1
- package/fs/types/patricia_trie/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/patricia_trie/{test.f.js → proof.f.js} +2 -2
- package/fs/types/prime_field/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/prime_field/{test.f.js → proof.f.js} +1 -1
- package/fs/types/range/proof.f.d.ts +1 -0
- package/fs/types/range/{test.f.js → proof.f.js} +1 -1
- package/fs/types/range_map/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/range_map/{test.f.js → proof.f.js} +1 -1
- package/fs/types/result/proof.f.d.ts +5 -0
- package/fs/types/result/{test.f.js → proof.f.js} +18 -2
- package/fs/types/rtti/parse/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/rtti/parse/{test.f.js → proof.f.js} +1 -1
- package/fs/types/rtti/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/rtti/{test.f.js → proof.f.js} +1 -1
- package/fs/types/rtti/ts/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/rtti/ts/{test.f.js → proof.f.js} +1 -1
- package/fs/types/rtti/validate/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/rtti/validate/{test.f.js → proof.f.js} +1 -1
- package/fs/types/sorted_list/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/sorted_list/{test.f.js → proof.f.js} +1 -1
- package/fs/types/sorted_set/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/sorted_set/{test.f.js → proof.f.js} +1 -1
- package/fs/types/string/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/string/{test.f.js → proof.f.js} +1 -1
- package/fs/types/string_set/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/string_set/{test.f.js → proof.f.js} +1 -1
- package/fs/types/ts/module.f.d.ts +0 -1
- package/fs/types/ts/{test.f.d.ts → proof.f.d.ts} +20 -0
- package/fs/types/ts/{test.f.js → proof.f.js} +1 -0
- package/fs/types/uint8array/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/fs/types/uint8array/{test.f.js → proof.f.js} +1 -1
- package/fs/website/proof.f.d.ts +3 -0
- package/fs/website/proof.f.js +9 -0
- package/issues/demo/sample/{test.f.js → proof.f.js} +1 -1
- package/issues/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/issues/{test.f.js → proof.f.js} +1 -1
- package/nanvm-lib/tests/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/nanvm-lib/tests/{test.f.js → proof.f.js} +1 -1
- package/nanvm-lib/tests/vm/{test.f.d.ts → proof.f.d.ts} +1 -2
- package/nanvm-lib/tests/vm/{test.f.js → proof.f.js} +1 -1
- package/package.json +2 -2
- package/fs/base128/test.f.d.ts +0 -2
- package/fs/bnf/test.f.d.ts +0 -4
- package/fs/cas/test.f.d.ts +0 -2
- package/fs/cas/test.f.js +0 -1
- package/fs/dev/tf/scenarios/fail.fail.f.d.ts +0 -1
- package/fs/dev/tf/scenarios/fail.fail.f.js +0 -1
- package/fs/dev/tf/scenarios/return-value.pass.f.d.ts +0 -1
- package/fs/dev/tf/scenarios/return-value.pass.f.js +0 -2
- package/fs/dev/tf/scenarios/throw.pass.f.d.ts +0 -6
- package/fs/dev/version/test.f.d.ts +0 -4
- package/fs/fsm/test.f.d.ts +0 -5
- package/fs/path/test.f.d.ts +0 -3
- package/fs/text/ascii/test.f.d.ts +0 -4
- package/fs/text/sgr/test.f.d.ts +0 -2
- package/fs/types/btree/find/test.f.d.ts +0 -2
- package/fs/types/btree/remove/test.f.d.ts +0 -5
- package/fs/types/btree/set/test.f.d.ts +0 -2
- package/fs/types/function/compare/test.f.d.ts +0 -2
- package/fs/types/function/operator/test.f.d.ts +0 -10
- package/fs/types/function/test.f.d.ts +0 -2
- package/fs/types/map/test.f.d.ts +0 -5
- package/fs/types/nominal/test.f.d.ts +0 -5
- package/fs/types/nullable/test.f.d.ts +0 -2
- package/fs/types/range/test.f.d.ts +0 -2
- package/fs/types/result/test.f.d.ts +0 -2
- /package/fs/{dev/tf → emergent-testing}/all.test.d.ts +0 -0
- /package/fs/{dev/tf → emergent-testing}/all.test.js +0 -0
- /package/fs/{dev/tf → emergent-testing}/module.d.ts +0 -0
- /package/fs/{dev/tf → emergent-testing}/scenarios/all.d.ts +0 -0
- /package/fs/{dev/tf → emergent-testing}/scenarios/all.js +0 -0
|
@@ -1,13 +1,33 @@
|
|
|
1
|
-
import { type All, type NodeProgram, type NodeProgramOptions, type Program, type Sandbox, type SandboxResult, type Test, type TestContext, type Write } from '
|
|
2
|
-
import { type Effect, type Operation } from '
|
|
3
|
-
import { type LoadModuleOperations, type ModuleMap } from '../module.f.ts';
|
|
4
|
-
|
|
1
|
+
import { type All, type Await, type NodeProgram, type NodeProgramOptions, type Program, type Sandbox, type SandboxResult, type Test, type TestContext, type Write } from '../types/effects/node/module.f.ts';
|
|
2
|
+
import { type Effect, type Operation } from '../types/effects/module.f.ts';
|
|
3
|
+
import { type LoadModuleOperations, type ModuleMap } from '../dev/module.f.ts';
|
|
4
|
+
/** A zero-argument test function whose return value may contain sub-tests. */
|
|
5
5
|
export type TestFn = () => unknown;
|
|
6
|
+
/**
|
|
7
|
+
* A leaf test bundled with its throw expectation.
|
|
8
|
+
*
|
|
9
|
+
* `throws: true` means the test is expected to throw; the runner inverts the
|
|
10
|
+
* `sandbox` result so a caught error becomes a pass and a clean return becomes
|
|
11
|
+
* a failure. Using a record instead of a wrapper function avoids a double
|
|
12
|
+
* `sandbox` call and gives accurate per-test timing.
|
|
13
|
+
*/
|
|
6
14
|
export type TestEntry = {
|
|
7
15
|
readonly fn: TestFn;
|
|
8
16
|
readonly throws: boolean;
|
|
9
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Either a leaf `TestEntry` (function + throw flag) or a named sub-tree of
|
|
20
|
+
* `[key, value]` pairs to recurse into. Discriminate with `Array.isArray`.
|
|
21
|
+
*/
|
|
10
22
|
export type TestSet = TestEntry | readonly (readonly [string, unknown])[];
|
|
23
|
+
/**
|
|
24
|
+
* Converts an arbitrary JS value into a `TestSet`.
|
|
25
|
+
*
|
|
26
|
+
* - Zero-argument functions become a `TestEntry`; the `throws` flag is set if
|
|
27
|
+
* `throws` is already `true` or the function's `.name === 'throw'`.
|
|
28
|
+
* - Non-null objects become an array of `[key, value]` pairs to recurse into.
|
|
29
|
+
* - All other values (including functions with parameters) produce an empty array.
|
|
30
|
+
*/
|
|
11
31
|
export declare const parseTestSet: (throws: boolean, x: unknown) => TestSet;
|
|
12
32
|
type TestAndPath = readonly [Path, TestEntry];
|
|
13
33
|
/**
|
|
@@ -26,16 +46,42 @@ export declare const collectTests: (path: Path, throws: boolean, v: unknown) =>
|
|
|
26
46
|
* contained `inner`.
|
|
27
47
|
*/
|
|
28
48
|
export type Reporter<O extends Operation> = {
|
|
29
|
-
readonly result: (file: string, path: Path, r: SandboxResult<unknown
|
|
49
|
+
readonly result: (file: string, path: Path, r: SandboxResult<unknown>, throws: boolean) => Effect<O, void>;
|
|
30
50
|
readonly summary: (pass: number, fail: number, time: number) => Effect<O, void>;
|
|
31
51
|
readonly test: (file: string, path: Path, set: TestEntry) => Effect<O, SandboxResult<unknown>>;
|
|
32
52
|
};
|
|
33
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Registers all tests reachable from module export `v` (keyed by `k`) with
|
|
55
|
+
* the given `TestContext`.
|
|
56
|
+
*
|
|
57
|
+
* Unlike `runModule`, which sandboxes only the leaf function, `registerModule`
|
|
58
|
+
* lets the external framework own scheduling: each registered test callback
|
|
59
|
+
* calls `fn`, then recursively registers any sub-trees returned by the function.
|
|
60
|
+
* This is the correct model for Node `--test`, Bun, and Playwright, where tests
|
|
61
|
+
* must be declared upfront and the framework drives execution.
|
|
62
|
+
*/
|
|
63
|
+
export declare const registerModule: (ctx: TestContext, k: string, v: unknown, star: string) => Effect<Test | All | Await, void>;
|
|
64
|
+
/**
|
|
65
|
+
* Runs all test modules in `moduleMap` whose names pass `isTest`, accumulates
|
|
66
|
+
* pass/fail/time via `reporter`, and returns an exit code (0 = all passed,
|
|
67
|
+
* 1 = at least one failure).
|
|
68
|
+
*/
|
|
34
69
|
export declare const runModuleMap: <O extends Operation>(reporter: Reporter<O>) => (moduleMap: ModuleMap) => Effect<O | All, number>;
|
|
70
|
+
/**
|
|
71
|
+
* Discovers all test modules via `loadModuleMap`, then runs them through
|
|
72
|
+
* `runModuleMap`. The composed effect is a `NodeProgram` entry point for the
|
|
73
|
+
* `fjs t` test runner.
|
|
74
|
+
*/
|
|
35
75
|
export declare const testAll: <O extends Operation>(reporter: Reporter<O>) => Program<O | All | LoadModuleOperations>;
|
|
36
|
-
|
|
76
|
+
/**
|
|
77
|
+
* A chain of property-access keys leading to a test location. String entries
|
|
78
|
+
* are object/array keys; `null` marks a function-call boundary (the return
|
|
79
|
+
* value was walked as a sub-tree).
|
|
80
|
+
*/
|
|
37
81
|
export type Path = readonly (string | null)[];
|
|
82
|
+
/** Returns `true` if `s` is a non-negative decimal integer without a leading zero. */
|
|
38
83
|
export declare const isInteger: (s: string) => boolean;
|
|
84
|
+
/** Returns `true` if `s` is a valid JS identifier (ASCII subset: `[A-Za-z_$][A-Za-z0-9_$]*`). */
|
|
39
85
|
export declare const isIdentifier: (s: string) => boolean;
|
|
40
86
|
/**
|
|
41
87
|
* Renders a key chain as a JS property-access expression: identifier keys use
|
|
@@ -46,7 +92,7 @@ export declare const isIdentifier: (s: string) => boolean;
|
|
|
46
92
|
export declare const fmtPath: (path: Path) => string;
|
|
47
93
|
/**
|
|
48
94
|
* Formats a fully-qualified test identifier as a JS-like expression, e.g.
|
|
49
|
-
* `import("./math.
|
|
95
|
+
* `import("./math.proof.f.ts").add()` or `import("./a.proof.f.ts").users[3].name()`.
|
|
50
96
|
* Self-contained per line — suitable for parallel output and as a CLI filter argument.
|
|
51
97
|
*/
|
|
52
98
|
export declare const fmtImport: (file: string, path: Path) => string;
|
|
@@ -63,6 +109,10 @@ export declare const fmtTerm: (path: Path) => string;
|
|
|
63
109
|
* https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions
|
|
64
110
|
*/
|
|
65
111
|
export declare const ghEscape: (s: string) => string;
|
|
112
|
+
/**
|
|
113
|
+
* Default `Reporter.test` implementation: sandboxes `fn` once and inverts the
|
|
114
|
+
* result when `throws` is `true` (caught error → pass, clean return → fail).
|
|
115
|
+
*/
|
|
66
116
|
export declare const defaultTest: (file: string, path: Path, { fn, throws }: TestEntry) => Effect<Sandbox, SandboxResult<unknown>>;
|
|
67
117
|
/**
|
|
68
118
|
* The terminal/GitHub reporter used by `fjs t`. Output goes through
|
|
@@ -72,6 +122,14 @@ export declare const defaultTest: (file: string, path: Path, { fn, throws }: Tes
|
|
|
72
122
|
* GitHub format path can be exercised directly from tests.
|
|
73
123
|
*/
|
|
74
124
|
export declare const defaultReporter: (options: NodeProgramOptions) => Reporter<Write | Sandbox>;
|
|
125
|
+
/** The `fjs t` entry point: runs all tests using `defaultReporter`. */
|
|
75
126
|
export declare const main: NodeProgram;
|
|
127
|
+
/**
|
|
128
|
+
* Entry point for external test frameworks (Node `--test`, Bun, Playwright).
|
|
129
|
+
*
|
|
130
|
+
* Discovers test modules via `loadModuleMap`, then registers each with the
|
|
131
|
+
* framework-appropriate `TestContext` selected from `NodeProgramOptions`
|
|
132
|
+
* based on the detected `engine`.
|
|
133
|
+
*/
|
|
76
134
|
export declare const register: NodeProgram;
|
|
77
135
|
export {};
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Test-framework helpers for running and reporting FunctionalScript tests.
|
|
3
3
|
*
|
|
4
|
+
* Two parallel execution paths:
|
|
5
|
+
* - `runModule` / `Reporter<O>` — self-hosted Effects runner used by `fjs t`;
|
|
6
|
+
* sandboxes each leaf call individually and accumulates `TestState`.
|
|
7
|
+
* - `registerModule` / `TestContext` — registers tests with an external
|
|
8
|
+
* framework (Node `--test`, Bun, Playwright) at import time; the framework
|
|
9
|
+
* owns scheduling and pass/fail counting.
|
|
10
|
+
*
|
|
4
11
|
* @module
|
|
5
12
|
*/
|
|
6
|
-
import { reset, fgGreen, fgRed, bold, csiWrite } from "
|
|
7
|
-
import { all, sandbox, test } from "
|
|
8
|
-
import { pure
|
|
9
|
-
import { loadModuleMap } from "../module.f.js";
|
|
10
|
-
import { invert } from "
|
|
11
|
-
export const isTest = (s) => s.endsWith('test.f.js') || s.endsWith('test.f.ts');
|
|
13
|
+
import { reset, fgGreen, fgRed, bold, csiWrite } from "../text/sgr/module.f.js";
|
|
14
|
+
import { all, awaitIfPromise, sandbox, test } from "../types/effects/node/module.f.js";
|
|
15
|
+
import { pure } from "../types/effects/module.f.js";
|
|
16
|
+
import { loadModuleMap, shouldLoad } from "../dev/module.f.js";
|
|
17
|
+
import { invert } from "../types/result/module.f.js";
|
|
12
18
|
const addPass = (delta) => (ts) => ({ ...ts, time: ts.time + delta, pass: ts.pass + 1 });
|
|
13
19
|
const addFail = (delta) => (ts) => ({ ...ts, time: ts.time + delta, fail: ts.fail + 1 });
|
|
14
20
|
const timeFormat = (a) => {
|
|
@@ -20,6 +26,14 @@ const timeFormat = (a) => {
|
|
|
20
26
|
const e = x.substring(s);
|
|
21
27
|
return `${b}.${e} ms`;
|
|
22
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* Converts an arbitrary JS value into a `TestSet`.
|
|
31
|
+
*
|
|
32
|
+
* - Zero-argument functions become a `TestEntry`; the `throws` flag is set if
|
|
33
|
+
* `throws` is already `true` or the function's `.name === 'throw'`.
|
|
34
|
+
* - Non-null objects become an array of `[key, value]` pairs to recurse into.
|
|
35
|
+
* - All other values (including functions with parameters) produce an empty array.
|
|
36
|
+
*/
|
|
23
37
|
export const parseTestSet = (throws, x) => {
|
|
24
38
|
switch (typeof x) {
|
|
25
39
|
case 'function': {
|
|
@@ -51,19 +65,36 @@ export const collectTests = (path, throws, v) => {
|
|
|
51
65
|
}
|
|
52
66
|
return [[path, set]];
|
|
53
67
|
};
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Registers all tests reachable from module export `v` (keyed by `k`) with
|
|
70
|
+
* the given `TestContext`.
|
|
71
|
+
*
|
|
72
|
+
* Unlike `runModule`, which sandboxes only the leaf function, `registerModule`
|
|
73
|
+
* lets the external framework own scheduling: each registered test callback
|
|
74
|
+
* calls `fn`, then recursively registers any sub-trees returned by the function.
|
|
75
|
+
* This is the correct model for Node `--test`, Bun, and Playwright, where tests
|
|
76
|
+
* must be declared upfront and the framework drives execution.
|
|
77
|
+
*/
|
|
78
|
+
export const registerModule = (ctx, k, v, star) => {
|
|
79
|
+
const registerOne = (ctx, [path, { fn, throws }]) => {
|
|
80
|
+
// ' *' (non-empty only for Bun/Playwright) signals that all sub-tests run
|
|
81
|
+
// inline inside this single registration. Not appended to throw-tests since
|
|
82
|
+
// those never produce sub-tests. The path already contains '.throw' when a
|
|
83
|
+
// test is expected to throw, so no extra suffix is needed.
|
|
84
|
+
const base = fmtImport(k, path);
|
|
85
|
+
const name = throws ? base : `${base}${star}`;
|
|
86
|
+
return test(ctx, name, throws, (t) => awaitIfPromise(fn())
|
|
87
|
+
.step(resolved => {
|
|
88
|
+
if (throws) {
|
|
89
|
+
return pure(undefined);
|
|
90
|
+
}
|
|
91
|
+
const sub = collectTests([...path, null], false, resolved);
|
|
92
|
+
if (sub.length === 0) {
|
|
93
|
+
return pure(undefined);
|
|
94
|
+
}
|
|
95
|
+
return all(...sub.map(e => registerOne(t, e))).step(() => pure(undefined));
|
|
96
|
+
}));
|
|
97
|
+
};
|
|
67
98
|
const tests = collectTests([], false, v);
|
|
68
99
|
if (tests.length === 0) {
|
|
69
100
|
return pure(undefined);
|
|
@@ -76,7 +107,7 @@ const runModule = ({ result, test }) => (k, v) => (ts) => {
|
|
|
76
107
|
const one = ([testPath, set]) => test(k, testPath, set)
|
|
77
108
|
.step(sr => {
|
|
78
109
|
const { result: [s, r], duration } = sr;
|
|
79
|
-
return result(k, testPath, sr)
|
|
110
|
+
return result(k, testPath, sr, set.throws)
|
|
80
111
|
.step(() => {
|
|
81
112
|
if (s === 'ok') {
|
|
82
113
|
if (set.throws) {
|
|
@@ -99,24 +130,43 @@ const runModule = ({ result, test }) => (k, v) => (ts) => {
|
|
|
99
130
|
.step(delta => pure(mergeState(ts, delta)));
|
|
100
131
|
};
|
|
101
132
|
const { entries } = Object;
|
|
133
|
+
/**
|
|
134
|
+
* Runs all test modules in `moduleMap` whose names pass `isTest`, accumulates
|
|
135
|
+
* pass/fail/time via `reporter`, and returns an exit code (0 = all passed,
|
|
136
|
+
* 1 = at least one failure).
|
|
137
|
+
*/
|
|
102
138
|
export const runModuleMap = (reporter) => (moduleMap) => {
|
|
103
139
|
const { summary } = reporter;
|
|
104
|
-
const modules = entries(moduleMap)
|
|
105
|
-
|
|
140
|
+
const modules = entries(moduleMap)
|
|
141
|
+
.flatMap(([k, v]) => v.proof !== undefined ? [[k, v.proof]] : []);
|
|
142
|
+
return all(...modules.map(([k, v]) => runModule(reporter)(k, v)(zero)))
|
|
143
|
+
.step(m => pure(m.reduce(mergeState, zero)))
|
|
106
144
|
.step(ts => summary(ts.pass, ts.fail, ts.time)
|
|
107
145
|
.step(() => pure(ts.fail !== 0 ? 1 : 0)));
|
|
108
146
|
};
|
|
147
|
+
/**
|
|
148
|
+
* Discovers all test modules via `loadModuleMap`, then runs them through
|
|
149
|
+
* `runModuleMap`. The composed effect is a `NodeProgram` entry point for the
|
|
150
|
+
* `fjs t` test runner.
|
|
151
|
+
*/
|
|
109
152
|
export const testAll = (reporter) => options => loadModuleMap(options.env).step(runModuleMap(reporter));
|
|
110
|
-
|
|
111
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Registers all modules in `moduleMap` that export a `proof` property with
|
|
155
|
+
* `ctx`. Delegates to `registerModule` for each matching entry.
|
|
156
|
+
*/
|
|
157
|
+
const registerModuleMap = (ctx, star) => (moduleMap) => {
|
|
158
|
+
const modules = entries(moduleMap)
|
|
159
|
+
.flatMap(([k, v]) => v.proof !== undefined ? [[k, v.proof]] : []);
|
|
112
160
|
if (modules.length === 0) {
|
|
113
161
|
return pure(undefined);
|
|
114
162
|
}
|
|
115
|
-
return all(...modules.map(([k, v]) => registerModule(ctx, k, v))).step(() => pure(undefined));
|
|
163
|
+
return all(...modules.map(([k, v]) => registerModule(ctx, k, v, star))).step(() => pure(undefined));
|
|
116
164
|
};
|
|
117
165
|
const isAlpha = (c) => (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c === '_' || c === '$';
|
|
118
166
|
const isDigit = (c) => c >= '0' && c <= '9';
|
|
167
|
+
/** Returns `true` if `s` is a non-negative decimal integer without a leading zero. */
|
|
119
168
|
export const isInteger = (s) => s.length > 0 && [...s].every(isDigit) && (s === '0' || s[0] !== '0');
|
|
169
|
+
/** Returns `true` if `s` is a valid JS identifier (ASCII subset: `[A-Za-z_$][A-Za-z0-9_$]*`). */
|
|
120
170
|
export const isIdentifier = (s) => s.length > 0 && isAlpha(s[0]) && [...s.slice(1)].every(c => isAlpha(c) || isDigit(c));
|
|
121
171
|
const fmtKey = (k) => k === null ? '()'
|
|
122
172
|
: isInteger(k) ? `[${k}]`
|
|
@@ -131,10 +181,10 @@ const fmtKey = (k) => k === null ? '()'
|
|
|
131
181
|
export const fmtPath = (path) => path.reduce((acc, k) => acc + fmtKey(k), '');
|
|
132
182
|
/**
|
|
133
183
|
* Formats a fully-qualified test identifier as a JS-like expression, e.g.
|
|
134
|
-
* `import("./math.
|
|
184
|
+
* `import("./math.proof.f.ts").add()` or `import("./a.proof.f.ts").users[3].name()`.
|
|
135
185
|
* Self-contained per line — suitable for parallel output and as a CLI filter argument.
|
|
136
186
|
*/
|
|
137
|
-
export const fmtImport = (file, path) => `import(${JSON.stringify(file)})${fmtPath(path)}()`;
|
|
187
|
+
export const fmtImport = (file, path) => `import(${JSON.stringify(file)}).proof${fmtPath(path)}()`;
|
|
138
188
|
/**
|
|
139
189
|
* Renders a key chain for terminal output: `| ` per level of depth, followed
|
|
140
190
|
* by the last segment formatted as a bare integer, a bare identifier, or a
|
|
@@ -160,6 +210,10 @@ export const ghEscape = (s) => s.replaceAll('%', '%25')
|
|
|
160
210
|
.replaceAll(',', '%2C')
|
|
161
211
|
.replaceAll('\r', '%0D')
|
|
162
212
|
.replaceAll('\n', '%0A');
|
|
213
|
+
/**
|
|
214
|
+
* Default `Reporter.test` implementation: sandboxes `fn` once and inverts the
|
|
215
|
+
* result when `throws` is `true` (caught error → pass, clean return → fail).
|
|
216
|
+
*/
|
|
163
217
|
export const defaultTest = (file, path, { fn, throws }) => sandbox(fn)
|
|
164
218
|
.step(r => pure(throws ? { ...r, result: invert(r.result) } : r));
|
|
165
219
|
const fmtResultLine = (file, path, color, label, duration) => `${fmtImport(file, path)}: ${color}${label}${reset}, ${timeFormat(duration)}`;
|
|
@@ -181,8 +235,8 @@ export const defaultReporter = (options) => {
|
|
|
181
235
|
const isGitHub = options.env['GITHUB_ACTION'] !== undefined;
|
|
182
236
|
return {
|
|
183
237
|
// https://github.com/OndraM/ci-detector/blob/main/src/Ci/GitHubActions.php
|
|
184
|
-
result: (file, path, { result: [s, v], duration }) => s === 'ok'
|
|
185
|
-
? csiLog(fmtResultLine(file, path, fgGreen, 'ok', duration))
|
|
238
|
+
result: (file, path, { result: [s, v], duration }, throws) => s === 'ok'
|
|
239
|
+
? csiLog(fmtResultLine(file, path, fgGreen, 'ok', duration) + (throws ? ' # EXPECTED TO THROW' : ''))
|
|
186
240
|
: isGitHub
|
|
187
241
|
? csiError(`::error file=${file},line=1,title=${ghEscape(fmtImport(file, path))}::${ghEscape(String(v))}`)
|
|
188
242
|
: csiError(fmtResultLine(file, path, fgRed, 'error', duration))
|
|
@@ -195,9 +249,22 @@ export const defaultReporter = (options) => {
|
|
|
195
249
|
test: defaultTest,
|
|
196
250
|
};
|
|
197
251
|
};
|
|
252
|
+
/** The `fjs t` entry point: runs all tests using `defaultReporter`. */
|
|
198
253
|
export const main = options => testAll(defaultReporter(options))(options);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
254
|
+
/**
|
|
255
|
+
* Entry point for external test frameworks (Node `--test`, Bun, Playwright).
|
|
256
|
+
*
|
|
257
|
+
* Discovers test modules via `loadModuleMap`, then registers each with the
|
|
258
|
+
* framework-appropriate `TestContext` selected from `NodeProgramOptions`
|
|
259
|
+
* based on the detected `engine`.
|
|
260
|
+
*/
|
|
261
|
+
export const register = o => {
|
|
262
|
+
const star = o.engine === 'bun' || o.engine === 'playwright' ? ' ...' : '';
|
|
263
|
+
const ctx = o.engine === 'bun' ? o.bunTestContext :
|
|
264
|
+
o.engine === 'playwright' ? o.playwrightTestContext :
|
|
265
|
+
o.testContext;
|
|
266
|
+
const r = registerModuleMap(ctx, star);
|
|
267
|
+
return loadModuleMap(o.env)
|
|
268
|
+
.step(r)
|
|
269
|
+
.step(() => pure(0));
|
|
270
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { io } from "
|
|
1
|
+
import { io } from "../io/module.js";
|
|
2
2
|
import { register } from "./module.f.js";
|
|
3
|
-
import { runProgram } from "
|
|
3
|
+
import { runProgram } from "../io/module.f.js";
|
|
4
4
|
export const run = () => runProgram(io)([])(register);
|
|
@@ -12,11 +12,39 @@ export declare const namedExports: () => void;
|
|
|
12
12
|
export declare const defaultReporterOutput: () => void;
|
|
13
13
|
export declare const defaultReporterFailOutput: () => void;
|
|
14
14
|
export declare const githubReporterOutput: () => void;
|
|
15
|
+
export declare const registerSuffixes: () => void;
|
|
15
16
|
export declare const helpers: {
|
|
16
17
|
isInteger: () => void;
|
|
17
18
|
isIdentifier: () => void;
|
|
19
|
+
shouldLoad: () => void;
|
|
18
20
|
fmtImport: () => void;
|
|
19
21
|
fmtPath: () => void;
|
|
20
22
|
fmtTerm: () => void;
|
|
21
23
|
ghEscape: () => void;
|
|
22
24
|
};
|
|
25
|
+
export declare const proof: {
|
|
26
|
+
flat: () => void;
|
|
27
|
+
nested: () => void;
|
|
28
|
+
throwKey: () => void;
|
|
29
|
+
throwKeyFail: () => void;
|
|
30
|
+
mixedPassFail: () => void;
|
|
31
|
+
returnValueSubTree: () => void;
|
|
32
|
+
arrayKeys: () => void;
|
|
33
|
+
nonTestFilesSkipped: () => void;
|
|
34
|
+
multipleFiles: () => void;
|
|
35
|
+
throwByFunctionName: () => void;
|
|
36
|
+
namedExports: () => void;
|
|
37
|
+
defaultReporterOutput: () => void;
|
|
38
|
+
defaultReporterFailOutput: () => void;
|
|
39
|
+
githubReporterOutput: () => void;
|
|
40
|
+
registerSuffixes: () => void;
|
|
41
|
+
helpers: {
|
|
42
|
+
isInteger: () => void;
|
|
43
|
+
isIdentifier: () => void;
|
|
44
|
+
shouldLoad: () => void;
|
|
45
|
+
fmtImport: () => void;
|
|
46
|
+
fmtPath: () => void;
|
|
47
|
+
fmtTerm: () => void;
|
|
48
|
+
ghEscape: () => void;
|
|
49
|
+
};
|
|
50
|
+
};
|