functionalscript 0.6.11 → 0.8.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/bnf/module.f.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { type Array2 } from '../types/array/module.f.ts';
2
2
  /**
3
- * A range of symbols (48 bits)
3
+ * A range of symbols. Two 24-bit numbers are stored in one JS number (48 bits).
4
+ *
4
5
  * For example: 0xBBBBBB_EEEEEE
5
- * - 0xBBBBBB is the first symbol
6
- * - 0xEEEEEE is the last symbol
6
+ * - 0xBBBBBB is the first symbol (24 bits)
7
+ * - 0xEEEEEE is the last symbol (24 bits)
7
8
  */
8
9
  export type TerminalRange = number;
9
10
  /** A sequence of rules. */
@@ -34,8 +35,8 @@ export declare const remove: (range: TerminalRange, removeSet: RangeVariant) =>
34
35
  export type None = readonly [];
35
36
  export declare const none: None;
36
37
  export type Option<S> = {
37
- none: None;
38
38
  some: S;
39
+ none: None;
39
40
  };
40
41
  export declare const option: <S extends Rule>(some: S) => Option<S>;
41
42
  export type Repeat0Plus<T> = () => Option<readonly [T, Repeat0Plus<T>]>;
package/bnf/module.f.js CHANGED
@@ -69,8 +69,8 @@ export const remove = (range, removeSet) => {
69
69
  };
70
70
  export const none = [];
71
71
  export const option = (some) => ({
72
- none,
73
72
  some,
73
+ none,
74
74
  });
75
75
  /**
76
76
  * Repeat zero or more times.
package/bnf/testlib.f.js CHANGED
@@ -130,8 +130,8 @@ export const deterministic = () => {
130
130
  close,
131
131
  ];
132
132
  const value = () => ({
133
- object: commaJoin0Plus('{}', [string, ws, ':', ws, value]),
134
133
  array: commaJoin0Plus('[]', value),
134
+ object: commaJoin0Plus('{}', [string, ws, ':', ws, value]),
135
135
  string,
136
136
  number,
137
137
  true: 'true',
package/dev/test.f.js CHANGED
@@ -18,7 +18,7 @@ export default {
18
18
  ctorUndefined: () => {
19
19
  /** @type {any} */
20
20
  const o = {
21
- constructor: void 0
21
+ constructor: undefined
22
22
  };
23
23
  const c = o['constructor'];
24
24
  //console.log(c)
@@ -0,0 +1,43 @@
1
+ import { io } from "../../io/module.js";
2
+ import { loadModuleMap } from "../module.f.js";
3
+ import { isTest, parseTestSet } from "./module.f.js";
4
+ import * as nodeTest from 'node:test';
5
+ const isBun = typeof Bun !== 'undefined';
6
+ const createFramework = (fw) => (prefix, f) => fw.test(prefix, t => f((name, v) => t.test(name, v)));
7
+ const createBunFramework = (fw) => (prefix, f) => f((name, v) => fw.test(`${prefix}: ${name}`, v));
8
+ const framework = isBun ? createBunFramework(nodeTest) : createFramework(nodeTest);
9
+ const parse = parseTestSet(io.tryCatch);
10
+ const scanModule = (x) => async (subTestRunner) => {
11
+ let subTests = [x];
12
+ while (true) {
13
+ const [first, ...rest] = subTests;
14
+ if (first === undefined) {
15
+ break;
16
+ }
17
+ subTests = rest;
18
+ //
19
+ const [name, value] = first;
20
+ const set = parse(value);
21
+ if (typeof set === 'function') {
22
+ await subTestRunner(name, () => {
23
+ const r = set();
24
+ subTests = [...subTests, [`${name}()`, r]];
25
+ });
26
+ }
27
+ else {
28
+ for (const [j, y] of set) {
29
+ const pr = `${name}/${j}`;
30
+ subTests = [...subTests, [pr, y]];
31
+ }
32
+ }
33
+ }
34
+ };
35
+ const run = async () => {
36
+ const x = await loadModuleMap(io);
37
+ for (const [i, v] of Object.entries(x)) {
38
+ if (isTest(i)) {
39
+ framework(i, scanModule(['', v.default]));
40
+ }
41
+ }
42
+ };
43
+ await run();
@@ -1,6 +1,6 @@
1
1
  import { type CsiConsole } from '../../text/sgr/module.f.ts';
2
2
  import type * as Result from '../../types/result/module.f.ts';
3
- import type { Io, Performance } from '../../io/module.f.ts';
3
+ import type { Io, Performance, TryCatch } from '../../io/module.f.ts';
4
4
  import { type ModuleMap } from '../module.f.ts';
5
5
  type Log<T> = CsiConsole;
6
6
  type Measure<T> = <R>(f: () => R) => (state: T) => readonly [R, number, T];
@@ -14,6 +14,9 @@ type Input<T> = {
14
14
  readonly env: (n: string) => string | undefined;
15
15
  };
16
16
  export declare const isTest: (s: string) => boolean;
17
+ export type Test = () => unknown;
18
+ export type TestSet = Test | readonly (readonly [string, unknown])[];
19
+ export declare const parseTestSet: (t: TryCatch) => (x: unknown) => TestSet;
17
20
  export declare const test: <T>(input: Input<T>) => readonly [number, T];
18
21
  export declare const anyLog: (f: (s: string) => void) => (s: string) => <T>(state: T) => T;
19
22
  export declare const measure: (p: Performance) => <R>(f: () => R) => <T>(state: T) => readonly [R, number, T];
@@ -13,49 +13,71 @@ const timeFormat = (a) => {
13
13
  const e = x.substring(s);
14
14
  return `${b}.${e} ms`;
15
15
  };
16
+ export const parseTestSet = (t) => (x) => {
17
+ switch (typeof x) {
18
+ case 'function': {
19
+ if (x.length === 0) {
20
+ const xt = x;
21
+ if (xt.name !== 'throw') {
22
+ return xt;
23
+ }
24
+ // Usual tests throw on error, but if the function name is 'throw',
25
+ // then the test passes if it throws.
26
+ return () => {
27
+ const [tag, value] = t(xt);
28
+ if (tag === 'ok') {
29
+ throw value;
30
+ }
31
+ return value;
32
+ };
33
+ }
34
+ break;
35
+ }
36
+ case 'object': {
37
+ if (x !== null) {
38
+ return Object.entries(x);
39
+ }
40
+ break;
41
+ }
42
+ }
43
+ return [];
44
+ };
16
45
  export const test = (input) => {
17
46
  let { moduleMap, log, error, measure, tryCatch, env, state } = input;
18
47
  const isGitHub = env('GITHUB_ACTION') !== undefined;
48
+ const parse = parseTestSet(tryCatch);
19
49
  const f = ([k, v]) => {
20
50
  const test = i => v => ([ts, state]) => {
21
51
  const next = test(`${i}| `);
22
- switch (typeof v) {
23
- case 'function': {
24
- if (v.length === 0) {
25
- const [[s, r], delta, state0] = measure(() => tryCatch(v))(state);
26
- state = state0;
27
- // Usual tests throw on error, but if the function name is 'throw', then the test passes if it throws.
28
- if ((s === 'error') === (v.name !== 'throw')) {
29
- ts = addFail(delta)(ts);
30
- if (isGitHub) {
31
- // https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions
32
- // https://github.com/OndraM/ci-detector/blob/main/src/Ci/GitHubActions.php
33
- error(`::error file=${k},line=1,title=[3]['a']()::${r}`);
34
- }
35
- else {
36
- error(`${i}() ${fgRed}error${reset}, ${timeFormat(delta)}`);
37
- error(`${fgRed}${r}${reset}`);
38
- }
39
- }
40
- else {
41
- ts = addPass(delta)(ts);
42
- log(`${i}() ${fgGreen}ok${reset}, ${timeFormat(delta)}`);
43
- }
44
- [ts, state] = next(r)([ts, state]);
52
+ const set = parse(v);
53
+ if (typeof set === 'function') {
54
+ const [[s, r], delta, state0] = measure(() => tryCatch(set))(state);
55
+ state = state0;
56
+ if (s !== 'ok') {
57
+ ts = addFail(delta)(ts);
58
+ if (isGitHub) {
59
+ // https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions
60
+ // https://github.com/OndraM/ci-detector/blob/main/src/Ci/GitHubActions.php
61
+ error(`::error file=${k},line=1,title=[3]['a']()::${r}`);
45
62
  }
46
- break;
47
- }
48
- case 'object': {
49
- if (v !== null) {
50
- const f = ([k, v]) => ([time, state]) => {
51
- log(`${i}${k}:`);
52
- [time, state] = next(v)([time, state]);
53
- return [time, state];
54
- };
55
- [ts, state] = fold(f)([ts, state])(v instanceof Array ? entries(v) : Object.entries(v));
63
+ else {
64
+ error(`${i}() ${fgRed}error${reset}, ${timeFormat(delta)}`);
65
+ error(`${fgRed}${r}${reset}`);
56
66
  }
57
- break;
58
67
  }
68
+ else {
69
+ ts = addPass(delta)(ts);
70
+ log(`${i}() ${fgGreen}ok${reset}, ${timeFormat(delta)}`);
71
+ [ts, state] = next(r)([ts, state]);
72
+ }
73
+ }
74
+ else {
75
+ const f = ([k, v]) => ([time, state]) => {
76
+ log(`${i}${k}:`);
77
+ [time, state] = next(v)([time, state]);
78
+ return [time, state];
79
+ };
80
+ [ts, state] = fold(f)([ts, state])(set);
59
81
  }
60
82
  return [ts, state];
61
83
  };
@@ -0,0 +1,4 @@
1
+ declare const _default: {
2
+ throw: () => never;
3
+ };
4
+ export default _default;
@@ -0,0 +1,5 @@
1
+ export default {
2
+ throw: () => {
3
+ throw [() => { }, () => { }];
4
+ }
5
+ };
package/fsc/test.f.d.ts CHANGED
@@ -1,4 +1,9 @@
1
1
  declare const _default: {
2
2
  a: () => void;
3
+ fn: () => void;
4
+ f1: () => void;
5
+ f2: () => void;
6
+ f3: () => void;
7
+ f4: () => void;
3
8
  };
4
9
  export default _default;
package/fsc/test.f.js CHANGED
@@ -8,11 +8,75 @@ const f = v => {
8
8
  const n = one(v);
9
9
  return s(_.init(n)[0]);
10
10
  };
11
+ // this doesn't change a name of the function
12
+ const fn = (f, name) => ({ [name]: f }[name]);
13
+ const withName = (name) =>
14
+ // translated into one command: define a `function [name]() { return undefined }`
15
+ Object.getOwnPropertyDescriptor({ [name]: () => undefined }, name).value;
11
16
  export default {
12
17
  a: () => {
13
18
  const x = f('1');
14
- if (x != '["1"]') {
19
+ if (x !== '["1"]') {
15
20
  throw x;
16
21
  }
22
+ },
23
+ fn: () => {
24
+ const o = {
25
+ ["hello world!"]: () => undefined
26
+ };
27
+ const f = o["hello world!"];
28
+ const { name } = f;
29
+ if (name !== "hello world!") {
30
+ throw name;
31
+ }
32
+ //
33
+ const f1 = { ["boring"]: () => undefined }["boring"];
34
+ if (f1.name !== "boring") {
35
+ throw f1.name;
36
+ }
37
+ //
38
+ const x = fn(() => undefined, "hello").name;
39
+ if (x !== "") {
40
+ throw x;
41
+ }
42
+ //
43
+ const m = withName("boring2").name;
44
+ if (m !== "boring2") {
45
+ throw m;
46
+ }
47
+ //
48
+ const a = function x() { return undefined; };
49
+ if (a.name !== "x") {
50
+ throw a.name;
51
+ }
52
+ },
53
+ //
54
+ f1: () => {
55
+ const m1 = () => undefined;
56
+ if (m1.name !== "m1") {
57
+ throw m1.name;
58
+ }
59
+ },
60
+ //
61
+ f2: () => {
62
+ const m11 = (() => undefined);
63
+ if (m11.name !== "m11") {
64
+ throw m11.name;
65
+ }
66
+ },
67
+ //
68
+ f3: () => {
69
+ const m2 = true ? () => undefined : () => undefined;
70
+ // for `bun` it is `m2`:
71
+ // if (m2.name !== "") { throw m2.name }
72
+ // see also https://github.com/oven-sh/bun/issues/20398
73
+ },
74
+ f4: () => {
75
+ const id = (i) => i;
76
+ const f = id(() => undefined);
77
+ // for `bun` it is `m2`:
78
+ if (f.name !== "") {
79
+ throw f.name;
80
+ }
17
81
  }
18
82
  };
package/io/module.f.d.ts CHANGED
@@ -77,6 +77,7 @@ export type Process = {
77
77
  readonly stdout: Writable;
78
78
  readonly stderr: Writable;
79
79
  };
80
+ export type TryCatch = <T>(f: () => T) => Result<T, unknown>;
80
81
  /**
81
82
  * Core IO operations interface providing access to system resources
82
83
  */
@@ -87,7 +88,7 @@ export type Io = {
87
88
  readonly asyncImport: (s: string) => Promise<Module>;
88
89
  readonly performance: Performance;
89
90
  readonly fetch: (url: string) => Promise<Response>;
90
- readonly tryCatch: <T>(f: () => T) => Result<T, unknown>;
91
+ readonly tryCatch: TryCatch;
91
92
  readonly asyncTryCatch: <T>(f: () => Promise<T>) => Promise<Result<T, unknown>>;
92
93
  };
93
94
  /**
@@ -1,7 +1,12 @@
1
1
  declare const _default: {
2
2
  literal: () => void;
3
3
  ownProperty: {
4
- nullish: () => void;
4
+ null: {
5
+ throw: () => PropertyDescriptor | undefined;
6
+ };
7
+ undefined: {
8
+ throw: () => PropertyDescriptor | undefined;
9
+ };
5
10
  bool: () => void;
6
11
  array: () => void;
7
12
  object: {
package/issues/test.f.js CHANGED
@@ -6,19 +6,11 @@ export default {
6
6
  const m = '<html>Hello</html>';
7
7
  },
8
8
  ownProperty: {
9
- nullish: () => {
10
- /* // panic
11
- const v = Object.getOwnPropertyDescriptor(null, 0)
12
- if (v !== undefined) {
13
- throw v
14
- }
15
- */
16
- /* // panic
17
- const v = Object.getOwnPropertyDescriptor(undefined, 0)
18
- if (v !== undefined) {
19
- throw v
20
- }
21
- */
9
+ null: {
10
+ throw: () => Object.getOwnPropertyDescriptor(null, 0),
11
+ },
12
+ undefined: {
13
+ throw: () => Object.getOwnPropertyDescriptor(undefined, 0),
22
14
  },
23
15
  bool: () => {
24
16
  const v = at(true)('x');
@@ -0,0 +1,25 @@
1
+ declare const _default: {
2
+ stringCoercion: {
3
+ number: () => void;
4
+ bool: () => void;
5
+ null: () => void;
6
+ undefined: () => void;
7
+ bigint: () => void;
8
+ array: () => void;
9
+ func: () => void;
10
+ object: {
11
+ norm: () => void;
12
+ toString: () => void;
13
+ toStringThrow: {
14
+ throw: () => void;
15
+ };
16
+ toStringNotFunc: {
17
+ throw: () => void;
18
+ };
19
+ toStringNonPrimitive: {
20
+ throw: () => void;
21
+ };
22
+ };
23
+ };
24
+ };
25
+ export default _default;
@@ -0,0 +1,105 @@
1
+ const stringCoercion = (a) => a + '';
2
+ export default {
3
+ stringCoercion: {
4
+ number: () => {
5
+ if (stringCoercion(123) !== '123') {
6
+ throw [123, 'toString', '123'];
7
+ }
8
+ if (stringCoercion(-456) !== '-456') {
9
+ throw [-456, 'toString', '-456'];
10
+ }
11
+ if (stringCoercion(0) !== '0') {
12
+ throw [0, 'toString', '0'];
13
+ }
14
+ if (stringCoercion(-0) !== '0') {
15
+ throw [0, 'toString', '0'];
16
+ }
17
+ if (stringCoercion(1 / (-0)) !== '-Infinity') {
18
+ throw [0, 'toString', '-Infinity'];
19
+ }
20
+ if (stringCoercion(Infinity) !== 'Infinity') {
21
+ throw [Infinity, 'toString', 'Infinity'];
22
+ }
23
+ if (stringCoercion(-Infinity) !== '-Infinity') {
24
+ throw [-Infinity, 'toString', '-Infinity'];
25
+ }
26
+ if (stringCoercion(1 / -Infinity) !== '0') {
27
+ throw [-Infinity, 'toString', '0'];
28
+ }
29
+ if (stringCoercion(NaN) !== 'NaN') {
30
+ throw [NaN, 'toString', 'NaN'];
31
+ }
32
+ },
33
+ bool: () => {
34
+ if (stringCoercion(true) !== 'true') {
35
+ throw [true, 'toString', 'true'];
36
+ }
37
+ if (stringCoercion(false) !== 'false') {
38
+ throw [false, 'toString', 'false'];
39
+ }
40
+ },
41
+ null: () => {
42
+ if (stringCoercion(null) !== 'null') {
43
+ throw [null, 'toString', 'null'];
44
+ }
45
+ },
46
+ undefined: () => {
47
+ if (stringCoercion(undefined) !== 'undefined') {
48
+ throw [undefined, 'toString', 'undefined'];
49
+ }
50
+ },
51
+ bigint: () => {
52
+ if (stringCoercion(123n) !== '123') {
53
+ throw [123n, 'toString', '123'];
54
+ }
55
+ if (stringCoercion(-456n) !== '-456') {
56
+ throw [-456n, 'toString', '-456'];
57
+ }
58
+ },
59
+ array: () => {
60
+ const arr = [1, 2, 3];
61
+ if (stringCoercion(arr) !== '1,2,3') {
62
+ throw [arr, 'toString', '1,2,3'];
63
+ }
64
+ },
65
+ func: () => {
66
+ const func = () => 5;
67
+ if (typeof stringCoercion(func) !== 'string') {
68
+ throw [func, 'toString'];
69
+ }
70
+ // if (stringCoercion(func) !== '() => 5') { throw [func, 'toString', 'function result'] }
71
+ },
72
+ object: {
73
+ norm: () => {
74
+ const obj = { a: 1, b: 2 };
75
+ if (stringCoercion(obj) !== '[object Object]') {
76
+ throw [obj, 'toString', '[object Object]'];
77
+ }
78
+ },
79
+ toString: () => {
80
+ const x = { toString: () => 'custom string' };
81
+ if (stringCoercion(x) !== 'custom string') {
82
+ throw [x, 'toString', 'custom string'];
83
+ }
84
+ },
85
+ toStringThrow: {
86
+ throw: () => {
87
+ const x = { toString: () => { throw new Error('Custom error'); } };
88
+ stringCoercion(x);
89
+ }
90
+ },
91
+ toStringNotFunc: {
92
+ throw: () => {
93
+ const x = { toString: 'hello' };
94
+ stringCoercion(x);
95
+ }
96
+ },
97
+ toStringNonPrimitive: {
98
+ throw: () => {
99
+ const x = { toString: () => [] };
100
+ stringCoercion(x);
101
+ }
102
+ }
103
+ }
104
+ }
105
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.6.11",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "**/*.js",
@@ -10,11 +10,12 @@
10
10
  "scripts": {
11
11
  "prepack": "tsc --NoEmit false",
12
12
  "git-clean": "git clean -xf",
13
- "test20": "npm run prepack && node ./dev/test/module.js",
14
- "test22": "tsc && node --experimental-strip-types ./dev/test/module.ts",
15
- "test": "tsc && node ./dev/test/module.ts",
13
+ "test20": "npm run prepack && node --test",
14
+ "test22": "tsc && node --test --experimental-strip-types",
15
+ "test": "tsc && node --test --experimental-test-coverage --test-coverage-include=**/module.f.ts",
16
16
  "index": "node ./dev/index/module.ts",
17
17
  "fsc": "node ./fsc/module.ts",
18
+ "fst": "node ./dev/tf/module.ts",
18
19
  "update": "npm run index && npm install"
19
20
  },
20
21
  "engines": {
@@ -22,14 +23,14 @@
22
23
  },
23
24
  "bin": {
24
25
  "fsc": "fsc/module.js",
25
- "fst": "dev/test/module.js"
26
+ "fst": "dev/tf/module.js"
26
27
  },
27
28
  "repository": {
28
29
  "type": "git",
29
30
  "url": "git+https://github.com/functionalscript/functionalscript.git"
30
31
  },
31
32
  "author": "Sergey Shandar",
32
- "license": "AGPL-3.0-only",
33
+ "license": "MIT",
33
34
  "keywords": [
34
35
  "lambda",
35
36
  "functional-programming",
@@ -44,8 +45,8 @@
44
45
  },
45
46
  "homepage": "https://github.com/functionalscript/functionalscript#readme",
46
47
  "devDependencies": {
47
- "@types/node": "^24.0.15",
48
- "@typescript/native-preview": "^7.0.0-dev.20250719.1",
49
- "typescript": "^5.8.3"
48
+ "@types/node": "*",
49
+ "@typescript/native-preview": "*",
50
+ "typescript": "*"
50
51
  }
51
52
  }
@@ -5,7 +5,6 @@ type ItemArray = readonly Item[];
5
5
  type ItemThunk = () => List<Item>;
6
6
  export type Item = string | ItemArray | ItemThunk;
7
7
  export declare const flat: (indent: string) => (text: Block) => List<string>;
8
- export declare const curly: (type: string) => (name: string) => (body: Block) => Block;
9
8
  /**
10
9
  * Converts a string to an UTF-8, represented as an MSB first bit vector.
11
10
  *
package/text/module.f.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { msb, u8List, u8ListToVec } from "../types/bit_vec/module.f.js";
2
2
  import { flatMap } from "../types/list/module.f.js";
3
- import * as utf8 from "./utf8/module.f.js";
3
+ import { fromCodePointList, toCodePointList } from "./utf8/module.f.js";
4
4
  import { stringToCodePointList, codePointListToString } from "./utf16/module.f.js";
5
5
  export const flat = (indent) => {
6
6
  const f = (prefix) => {
@@ -9,18 +9,18 @@ export const flat = (indent) => {
9
9
  };
10
10
  return f('');
11
11
  };
12
- export const curly = (type) => (name) => (body) => [`${type} ${name}`, '{', body, '}'];
12
+ const u8ListToVecMsb = u8ListToVec(msb);
13
13
  /**
14
14
  * Converts a string to an UTF-8, represented as an MSB first bit vector.
15
15
  *
16
16
  * @param s The input string to be converted.
17
17
  * @returns The resulting UTF-8 bit vector, MSB first.
18
18
  */
19
- export const msbUtf8 = (s) => u8ListToVec(msb)(utf8.fromCodePointList(stringToCodePointList(s)));
19
+ export const msbUtf8 = (s) => u8ListToVecMsb(fromCodePointList(stringToCodePointList(s)));
20
20
  /**
21
21
  * Converts a UTF-8 bit vector with MSB first encoding to a string.
22
22
  *
23
23
  * @param msbV - The UTF-8 bit vector with MSB first encoding.
24
24
  * @returns The resulting string.
25
25
  */
26
- export const msbUtf8ToString = (msbV) => codePointListToString(utf8.toCodePointList(u8List(msb)(msbV)));
26
+ export const msbUtf8ToString = (msbV) => codePointListToString(toCodePointList(u8List(msb)(msbV)));