functionalscript 0.6.10 → 0.6.11

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.
@@ -1,4 +1,4 @@
1
- import type { Rule as FRule } from '../module.f.ts';
1
+ import { type Rule as FRule } from '../module.f.ts';
2
2
  export type TerminalRange = number;
3
3
  export type Sequence = readonly string[];
4
4
  /** A variant of rule names. */
@@ -1,5 +1,6 @@
1
1
  import { stringToCodePointList } from "../../text/utf16/module.f.js";
2
- import { toArray } from "../../types/list/module.f.js";
2
+ import { map, toArray } from "../../types/list/module.f.js";
3
+ import { oneEncode, } from "../module.f.js";
3
4
  const { entries } = Object;
4
5
  const find = (map) => (fr) => {
5
6
  for (const [k, v] of entries(map)) {
@@ -40,10 +41,11 @@ const variant = (fr) => map => {
40
41
  }
41
42
  return [map, set, rule];
42
43
  };
44
+ const mapOneEncode = map(oneEncode);
43
45
  const data = (dr) => {
44
46
  switch (typeof dr) {
45
47
  case 'string': {
46
- return sequence(toArray(stringToCodePointList(dr)));
48
+ return sequence(toArray(mapOneEncode(stringToCodePointList(dr))));
47
49
  }
48
50
  case 'number':
49
51
  return m => [m, {}, dr];
@@ -1,5 +1,6 @@
1
1
  declare const _default: {
2
- toData: () => void;
2
+ toData: (() => void)[];
3
+ variantTest: () => void;
3
4
  example: () => void;
4
5
  };
5
6
  export default _default;
@@ -1,9 +1,66 @@
1
+ import { stringify } from "../../json/module.f.js";
2
+ import { sort } from "../../types/object/module.f.js";
3
+ import { range } from "../module.f.js";
1
4
  import { classic, deterministic } from "../testlib.f.js";
2
5
  import { toData } from "./module.f.js";
3
6
  export default {
4
- toData: () => {
5
- const c = toData(classic());
6
- const d = toData(deterministic());
7
+ toData: [
8
+ () => {
9
+ const c = toData(classic());
10
+ const d = toData(deterministic());
11
+ },
12
+ () => {
13
+ const stringRule = 'true';
14
+ const result = stringify(sort)(toData(stringRule));
15
+ if (result != '[{"":["0","1","2","3"],"0":1946157172,"1":1912602738,"2":1962934389,"3":1694498917},""]') {
16
+ throw result;
17
+ }
18
+ },
19
+ () => {
20
+ const terminalRangeRule = range('AF');
21
+ const result = stringify(sort)(toData(terminalRangeRule));
22
+ if (result != '[{"":1090519110},""]') {
23
+ throw result;
24
+ } //1090519110 = 65 * 2^24 + 70
25
+ },
26
+ () => {
27
+ const sequenceRangeRule = [range('AF'), range('af')];
28
+ const result = stringify(sort)(toData(sequenceRangeRule));
29
+ if (result != '[{"":["0","1"],"0":1090519110,"1":1627390054},""]') {
30
+ throw result;
31
+ }
32
+ },
33
+ () => {
34
+ const lazyRule = () => 'true';
35
+ const result = stringify(sort)(toData(lazyRule));
36
+ if (result != '[{"":1946157172,"0":1912602738,"1":1962934389,"2":1694498917,"lazyRule":["","0","1","2"]},"lazyRule"]') {
37
+ throw result;
38
+ }
39
+ },
40
+ () => {
41
+ const varintRule = { true: 'true', false: 'false' };
42
+ const result = stringify(sort)(toData(varintRule));
43
+ const expected = '[{"":{"false":"5","true":"0"},"0":["1","2","3","4"],"1":1946157172,"2":1912602738,"3":1962934389,"4":1694498917,"5":["6","7","8","9","4"],"6":1711276134,"7":1627390049,"8":1811939436,"9":1929379955},""]';
44
+ if (result != expected) {
45
+ throw [result, expected];
46
+ }
47
+ },
48
+ () => {
49
+ const lazyRule = () => 'true';
50
+ const lazyRule0 = () => 'false';
51
+ const result = stringify(sort)(toData([lazyRule, lazyRule0]));
52
+ const expected = '[{"":["lazyRule","lazyRule0"],"0":1946157172,"1":1912602738,"2":1962934389,"3":1694498917,"4":1711276134,"5":1627390049,"6":1811939436,"7":1929379955,"lazyRule":["0","1","2","3"],"lazyRule0":["4","5","6","7","3"]},""]';
53
+ if (result != expected) {
54
+ throw [result, expected];
55
+ }
56
+ },
57
+ ],
58
+ variantTest: () => {
59
+ const varintRule = { a: 'a', b: 'b' };
60
+ const result = stringify(sort)(toData(varintRule));
61
+ if (result != '[{"":{"a":"0","b":"2"},"0":["1"],"1":1627390049,"2":["3"],"3":1644167266},""]') {
62
+ throw result;
63
+ }
7
64
  },
8
65
  example: () => {
9
66
  const grammar = {
@@ -48,13 +48,18 @@ export const hmac = (sha2) => {
48
48
  const op = p(oPad);
49
49
  const c = computeSync(sha2);
50
50
  const vbl = vec(blockLength);
51
+ // a and b should have the same size
51
52
  const xor = (a) => (b) => vbl(a ^ b);
52
- return k => m => {
53
+ return k => {
53
54
  const k1 = length(k) > blockLength ? c([k]) : k;
54
55
  const k2 = concat(k1)(vec(blockLength - length(k1))(0n));
55
56
  const xk2 = xor(k2);
56
- const f = (p, msg) => c([xk2(p), msg]);
57
- const m1 = f(ip, m);
58
- return f(op, m1);
57
+ const f = (p) => {
58
+ const x = xk2(p);
59
+ return (msg) => c([x, msg]);
60
+ };
61
+ const fip = f(ip);
62
+ const fop = f(op);
63
+ return m => fop(fip(m));
59
64
  };
60
65
  };
@@ -37,7 +37,7 @@ export type Base = {
37
37
  * const s = msbUtf8("The quick brown fox jumps over the lazy dog.")
38
38
  * let state = sha224.init
39
39
  * state = sha224.append(state)(s)
40
- * const h = sha224.end(state) // 0x619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4cn
40
+ * const h = sha224.end(state) // 0x1_619cba8e8e05826e9b8c519c0a5c68f4fb653e8a3d8aa04bb2c8cd4cn
41
41
  * ```
42
42
  */
43
43
  export type Sha2 = {
@@ -0,0 +1,5 @@
1
+ import { type Vec } from '../../types/bit_vec/module.f.ts';
2
+ import { type Init } from '../secp/module.f.ts';
3
+ import type { Sha2 } from '../sha2/module.f.ts';
4
+ export declare const newPrivateKey: (i: Init) => (random: Vec) => Vec;
5
+ export declare const sign: (sha2: Sha2) => (curveInit: Init) => (privateKey: Vec) => (messageHash: Vec) => readonly [bigint, bigint];
@@ -0,0 +1,53 @@
1
+ import { listToVec, msb, uint, vec, vec8, length } from "../../types/bit_vec/module.f.js";
2
+ import { hmac } from "../hmac/module.f.js";
3
+ import { curve } from "../secp/module.f.js";
4
+ const concat = listToVec(msb);
5
+ const v00 = vec8(0x00n);
6
+ const v01 = vec8(0x01n);
7
+ /**
8
+ * The size of the result equals the size of the hash.
9
+ *
10
+ * @param sha2 SHA2 hash function
11
+ * @returns A function that accepts a private key, a message hash and returns `k`.
12
+ */
13
+ const createK = (sha2) => {
14
+ const h = hmac(sha2);
15
+ let vs = vec(sha2.hashLength);
16
+ let k0 = vs(0x00n);
17
+ let v0 = vs(0x01n);
18
+ return (privateKey) => (messageHash) => {
19
+ const pm = concat([privateKey, messageHash]);
20
+ let k = k0;
21
+ let v = v0;
22
+ k = h(k)(concat([v, v00, pm]));
23
+ v = h(k)(v);
24
+ k = h(k)(concat([v, v01, pm]));
25
+ v = h(k)(v);
26
+ return uint(h(k)(v));
27
+ };
28
+ };
29
+ export const newPrivateKey = (i) => (random) => {
30
+ const { nf } = curve(i);
31
+ if (length(nf.max) < length(random)) {
32
+ throw "need more random bits";
33
+ }
34
+ return uint(random) % nf.p;
35
+ };
36
+ export const sign = (sha2) => (curveInit) => (privateKey) => (messageHash) => {
37
+ const { mul, pf } = curve(curveInit);
38
+ // const curveVec = vec(length(pf.max))
39
+ //`k` is a unique for each `z` and secret.
40
+ const k = createK(sha2)(privateKey)(messageHash) % pf.p;
41
+ // `R = G * k`.
42
+ const rp = mul(curveInit.g)(k);
43
+ // `r = R.x`
44
+ const r = rp === null ? 0n : rp[0];
45
+ // `s = ((z + r * d) / k)`.
46
+ const d = uint(privateKey);
47
+ const z = uint(messageHash);
48
+ const rd = pf.mul(r)(d);
49
+ const zrd = pf.add(z)(rd);
50
+ const kn1 = pf.reciprocal(k);
51
+ const s = pf.mul(zrd)(kn1);
52
+ return [r, s];
53
+ };
@@ -0,0 +1,2 @@
1
+ declare const _default: {};
2
+ export default _default;
@@ -0,0 +1 @@
1
+ export default {};
@@ -0,0 +1,8 @@
1
+ type DenoTestStep = {
2
+ readonly step: (name: string, f: () => void | Promise<void>) => Promise<void>;
3
+ };
4
+ type DenoFunc = (t: DenoTestStep) => void | Promise<void>;
5
+ type DenoArg = readonly [string, DenoFunc];
6
+ export type DenoTest = (...arg: DenoArg) => void;
7
+ declare const _default: () => Promise<void>;
8
+ export default _default;
package/deno/module.js ADDED
@@ -0,0 +1,53 @@
1
+ import { io } from "../io/module.js";
2
+ import { loadModuleMap } from "../dev/module.f.js";
3
+ import { isTest } from "../dev/test/module.f.js";
4
+ const denoTest = (x) => async (t) => {
5
+ let subTests = [x];
6
+ while (true) {
7
+ const [first, ...rest] = subTests;
8
+ if (first === undefined) {
9
+ break;
10
+ }
11
+ subTests = rest;
12
+ //
13
+ const [name, value] = first;
14
+ if (value === null) {
15
+ continue;
16
+ }
17
+ switch (typeof value) {
18
+ case "function": {
19
+ if (value.length === 0) {
20
+ const g = value.name === 'throw'
21
+ ? () => {
22
+ try {
23
+ value();
24
+ throw new Error(`Expected ${name} to throw, but it did not.`);
25
+ }
26
+ catch { }
27
+ }
28
+ : () => {
29
+ const r = value();
30
+ subTests = [...subTests, [`${name}()`, r]];
31
+ };
32
+ await t.step(name, g);
33
+ }
34
+ break;
35
+ }
36
+ case "object": {
37
+ for (const [j, y] of Object.entries(value)) {
38
+ const pr = `${name}/${j}`;
39
+ subTests = [...subTests, [pr, y]];
40
+ }
41
+ break;
42
+ }
43
+ }
44
+ }
45
+ };
46
+ export default async () => {
47
+ const x = await loadModuleMap(io);
48
+ for (const [i, v] of Object.entries(x)) {
49
+ if (isTest(i)) {
50
+ Deno.test(i, denoTest(['', v.default]));
51
+ }
52
+ }
53
+ };
package/deno/test.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/deno/test.js ADDED
@@ -0,0 +1,2 @@
1
+ import run from "./module.js";
2
+ await run();
@@ -1,7 +1,8 @@
1
+ import { type CsiConsole } from '../../text/sgr/module.f.ts';
1
2
  import type * as Result from '../../types/result/module.f.ts';
2
3
  import type { Io, Performance } from '../../io/module.f.ts';
3
4
  import { type ModuleMap } from '../module.f.ts';
4
- type Log<T> = (v: string) => (state: T) => T;
5
+ type Log<T> = CsiConsole;
5
6
  type Measure<T> = <R>(f: () => R) => (state: T) => readonly [R, number, T];
6
7
  type Input<T> = {
7
8
  readonly moduleMap: ModuleMap;
@@ -12,6 +13,7 @@ type Input<T> = {
12
13
  readonly tryCatch: <R>(f: () => R) => Result.Result<R, unknown>;
13
14
  readonly env: (n: string) => string | undefined;
14
15
  };
16
+ export declare const isTest: (s: string) => boolean;
15
17
  export declare const test: <T>(input: Input<T>) => readonly [number, T];
16
18
  export declare const anyLog: (f: (s: string) => void) => (s: string) => <T>(state: T) => T;
17
19
  export declare const measure: (p: Performance) => <R>(f: () => R) => <T>(state: T) => readonly [R, number, T];
@@ -1,7 +1,7 @@
1
1
  import { entries, fold } from "../../types/list/module.f.js";
2
- import { reset, fgGreen, fgRed, bold } from "../../text/sgr/module.f.js";
2
+ import { reset, fgGreen, fgRed, bold, stdio, stderr } from "../../text/sgr/module.f.js";
3
3
  import { env, loadModuleMap } from "../module.f.js";
4
- const isTest = (s) => s.endsWith('test.f.js') || s.endsWith('test.f.ts');
4
+ export const isTest = (s) => s.endsWith('test.f.js') || s.endsWith('test.f.ts');
5
5
  const addPass = (delta) => (ts) => ({ ...ts, time: ts.time + delta, pass: ts.pass + 1 });
6
6
  const addFail = (delta) => (ts) => ({ ...ts, time: ts.time + delta, fail: ts.fail + 1 });
7
7
  const timeFormat = (a) => {
@@ -30,16 +30,16 @@ export const test = (input) => {
30
30
  if (isGitHub) {
31
31
  // https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions
32
32
  // https://github.com/OndraM/ci-detector/blob/main/src/Ci/GitHubActions.php
33
- state = error(`::error file=${k},line=1,title=[3]['a']()::${r}`)(state);
33
+ error(`::error file=${k},line=1,title=[3]['a']()::${r}`);
34
34
  }
35
35
  else {
36
- state = error(`${i}() ${fgRed}error${reset}, ${timeFormat(delta)}`)(state);
37
- state = error(`${fgRed}${r}${reset}`)(state);
36
+ error(`${i}() ${fgRed}error${reset}, ${timeFormat(delta)}`);
37
+ error(`${fgRed}${r}${reset}`);
38
38
  }
39
39
  }
40
40
  else {
41
41
  ts = addPass(delta)(ts);
42
- state = log(`${i}() ${fgGreen}ok${reset}, ${timeFormat(delta)}`)(state);
42
+ log(`${i}() ${fgGreen}ok${reset}, ${timeFormat(delta)}`);
43
43
  }
44
44
  [ts, state] = next(r)([ts, state]);
45
45
  }
@@ -48,7 +48,7 @@ export const test = (input) => {
48
48
  case 'object': {
49
49
  if (v !== null) {
50
50
  const f = ([k, v]) => ([time, state]) => {
51
- state = log(`${i}${k}:`)(state);
51
+ log(`${i}${k}:`);
52
52
  [time, state] = next(v)([time, state]);
53
53
  return [time, state];
54
54
  };
@@ -61,7 +61,7 @@ export const test = (input) => {
61
61
  };
62
62
  return ([ts, state]) => {
63
63
  if (isTest(k)) {
64
- state = log(`testing ${k}`)(state);
64
+ log(`testing ${k}`);
65
65
  [ts, state] = test('| ')(v.default)([ts, state]);
66
66
  }
67
67
  return [ts, state];
@@ -70,8 +70,8 @@ export const test = (input) => {
70
70
  let ts = { time: 0, pass: 0, fail: 0 };
71
71
  [ts, state] = fold(f)([ts, state])(Object.entries(moduleMap));
72
72
  const fgFail = ts.fail === 0 ? fgGreen : fgRed;
73
- state = log(`${bold}Number of tests: pass: ${fgGreen}${ts.pass}${reset}${bold}, fail: ${fgFail}${ts.fail}${reset}${bold}, total: ${ts.pass + ts.fail}${reset}`)(state);
74
- state = log(`${bold}Time: ${timeFormat(ts.time)}${reset}`)(state);
73
+ log(`${bold}Number of tests: pass: ${fgGreen}${ts.pass}${reset}${bold}, fail: ${fgFail}${ts.fail}${reset}${bold}, total: ${ts.pass + ts.fail}${reset}`);
74
+ log(`${bold}Time: ${timeFormat(ts.time)}${reset}`);
75
75
  return [ts.fail !== 0 ? 1 : 0, state];
76
76
  };
77
77
  export const anyLog = (f) => (s) => (state) => {
@@ -86,8 +86,8 @@ export const measure = (p) => (f) => (state) => {
86
86
  };
87
87
  export const main = async (io) => test({
88
88
  moduleMap: await loadModuleMap(io),
89
- log: anyLog(io.console.log),
90
- error: anyLog(io.console.error),
89
+ log: stdio(io), // anyLog(io.console.log),
90
+ error: stderr(io), // anyLog(io.console.error),
91
91
  measure: measure(io.performance),
92
92
  tryCatch: io.tryCatch,
93
93
  env: env(io),
package/io/module.f.d.ts CHANGED
@@ -25,6 +25,7 @@ export type MakeDirectoryOptions = {
25
25
  * @see https://nodejs.org/api/fs.html
26
26
  */
27
27
  export type Fs = {
28
+ readonly writeSync: (fd: number, s: string) => void;
28
29
  readonly writeFileSync: (file: string, data: string) => void;
29
30
  readonly readFileSync: (path: string, options: BufferEncoding) => string | null;
30
31
  readonly existsSync: (path: string) => boolean;
@@ -60,6 +61,10 @@ export type Module = {
60
61
  export type Performance = {
61
62
  readonly now: () => number;
62
63
  };
64
+ export type Writable = {
65
+ readonly fd: number;
66
+ readonly isTTY: boolean;
67
+ };
63
68
  /**
64
69
  * Node.js Process interface
65
70
  * @see https://nodejs.org/api/process.html
@@ -69,6 +74,8 @@ export type Process = {
69
74
  readonly env: Env;
70
75
  readonly exit: (code: number) => never;
71
76
  readonly cwd: () => string;
77
+ readonly stdout: Writable;
78
+ readonly stderr: Writable;
72
79
  };
73
80
  /**
74
81
  * Core IO operations interface providing access to system resources
@@ -5,6 +5,7 @@ export const createVirtualIo = (files) => ({
5
5
  error: (..._d) => { }
6
6
  },
7
7
  fs: {
8
+ writeSync: (fd, s) => { },
8
9
  writeFileSync: (_file, _data) => { },
9
10
  readFileSync: (path, _options) => { return at(path)(files); },
10
11
  existsSync: (path) => { return at(path)(files) !== null; },
@@ -22,6 +23,8 @@ export const createVirtualIo = (files) => ({
22
23
  env: {},
23
24
  exit: n => { throw n; },
24
25
  cwd: () => '',
26
+ stdout: { fd: 1, isTTY: false },
27
+ stderr: { fd: 2, isTTY: false },
25
28
  },
26
29
  asyncImport: () => Promise.reject(),
27
30
  performance: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.6.10",
3
+ "version": "0.6.11",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "**/*.js",
@@ -44,7 +44,8 @@
44
44
  },
45
45
  "homepage": "https://github.com/functionalscript/functionalscript#readme",
46
46
  "devDependencies": {
47
- "@types/node": "^22.15.30",
47
+ "@types/node": "^24.0.15",
48
+ "@typescript/native-preview": "^7.0.0-dev.20250719.1",
48
49
  "typescript": "^5.8.3"
49
50
  }
50
51
  }
@@ -1,3 +1,4 @@
1
+ import type { Io, Writable } from "../../io/module.f.ts";
1
2
  export declare const backspace: string;
2
3
  type End = 'm';
3
4
  type Csi = (code: number | string) => string;
@@ -23,4 +24,8 @@ export type Stdout = {
23
24
  };
24
25
  export type WriteText = (text: string) => WriteText;
25
26
  export declare const createConsoleText: (stdout: Stdout) => WriteText;
27
+ export type CsiConsole = (s: string) => void;
28
+ export declare const console: ({ fs: { writeSync } }: Io) => (w: Writable) => CsiConsole;
29
+ export declare const stdio: (io: Io) => CsiConsole;
30
+ export declare const stderr: (io: Io) => CsiConsole;
26
31
  export {};
@@ -1,6 +1,7 @@
1
1
  // Co control codes
2
2
  // https://en.wikipedia.org/wiki/ANSI_escape_code#C0_control_codes
3
3
  export const backspace = '\x08';
4
+ const begin = '\x1b[';
4
5
  /**
5
6
  * Control Sequence Introducer (CSI) escape sequence.
6
7
  * https://en.wikipedia.org/wiki/ANSI_escape_code#Control_Sequence_Introducer_commands
@@ -8,7 +9,7 @@ export const backspace = '\x08';
8
9
  * @param end - The final character that indicates the type of sequence.
9
10
  * @returns A function that takes a code (number or string) and returns the complete ANSI escape sequence.
10
11
  */
11
- export const csi = (end) => code => `\x1b[${code.toString()}${end}`;
12
+ export const csi = (end) => code => `${begin}${code.toString()}${end}`;
12
13
  /**
13
14
  * Specialization of CSI for Select Graphic Rendition (SGR) sequences.
14
15
  * https://en.wikipedia.org/wiki/ANSI_escape_code#SGR
@@ -31,3 +32,11 @@ export const createConsoleText = (stdout) => {
31
32
  };
32
33
  return f('');
33
34
  };
35
+ export const console = ({ fs: { writeSync } }) => (w) => {
36
+ const { isTTY } = w;
37
+ return isTTY
38
+ ? (s) => writeSync(w.fd, s + '\n')
39
+ : (s) => writeSync(w.fd, s.replace(/\x1b\[[0-9;]*m/g, '') + '\n');
40
+ };
41
+ export const stdio = (io) => console(io)(io.process.stdout);
42
+ export const stderr = (io) => console(io)(io.process.stderr);
@@ -152,3 +152,4 @@ export declare const u8ListToVec: (bo: BitOrder) => (list: List<number>) => Vec;
152
152
  * @returns A thunk that produces a list of unsigned 8-bit integers.
153
153
  */
154
154
  export declare const u8List: ({ popFront }: BitOrder) => (v: Vec) => Thunk<number>;
155
+ export declare const listToVec: (bo: BitOrder) => (list: List<Vec>) => Vec;
@@ -136,3 +136,4 @@ export const u8List = ({ popFront }) => {
136
136
  };
137
137
  return f;
138
138
  };
139
+ export const listToVec = (bo) => fold(bo.concat)(empty);