functionalscript 0.12.5 → 0.12.7

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/io/module.f.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type Effect } from '../types/effects/module.f.ts';
2
- import type { Headers, NodeOp } from '../types/effects/node/module.f.ts';
2
+ import type { ExecResult, Headers, IoResult, NodeOp } from '../types/effects/node/module.f.ts';
3
3
  import { type Result } from '../types/result/module.f.ts';
4
4
  /**
5
5
  * Represents a directory entry (file or directory) in the filesystem
@@ -96,6 +96,9 @@ export type RequestListener = (req: IncomingMessage, res: ServerResponse) => Pro
96
96
  export type Http = {
97
97
  readonly createServer: (_: RequestListener) => Server;
98
98
  };
99
+ export type ChildProcess = {
100
+ readonly exec: (command: string) => Promise<IoResult<ExecResult>>;
101
+ };
99
102
  /**
100
103
  * Core IO operations interface providing access to system resources
101
104
  */
@@ -109,6 +112,7 @@ export type Io = {
109
112
  readonly tryCatch: TryCatch;
110
113
  readonly asyncTryCatch: <T>(f: () => Promise<T>) => Promise<Result<T, unknown>>;
111
114
  readonly http: Http;
115
+ readonly childProcess: ChildProcess;
112
116
  };
113
117
  /**
114
118
  * The environment variables.
@@ -124,4 +128,4 @@ export type Run = (f: App) => Promise<never>;
124
128
  */
125
129
  export declare const run: (io: Io) => Run;
126
130
  export type EffectToPromise = <T>(effect: Effect<NodeOp, T>) => Promise<T>;
127
- export declare const fromIo: ({ console: { error, log }, fs: { promises: { mkdir, readFile, readdir, writeFile, rm } }, fetch, http: { createServer }, }: Io) => EffectToPromise;
131
+ export declare const fromIo: ({ console: { error, log }, fs: { promises: { mkdir, readFile, readdir, writeFile, rm } }, fetch, http: { createServer }, childProcess: { exec }, }: Io) => EffectToPromise;
package/io/module.f.js CHANGED
@@ -35,7 +35,7 @@ const collect = async (v) => {
35
35
  }
36
36
  return result;
37
37
  };
38
- export const fromIo = ({ console: { error, log }, fs: { promises: { mkdir, readFile, readdir, writeFile, rm } }, fetch, http: { createServer }, }) => {
38
+ export const fromIo = ({ console: { error, log }, fs: { promises: { mkdir, readFile, readdir, writeFile, rm } }, fetch, http: { createServer }, childProcess: { exec }, }) => {
39
39
  const result = asyncRun({
40
40
  all: async (effects) => await Promise.all(effects.map(result)),
41
41
  error: async (message) => error(message),
@@ -53,6 +53,7 @@ export const fromIo = ({ console: { error, log }, fs: { promises: { mkdir, readF
53
53
  .map(v => ({ name: v.name, parentPath: normalize(v.parentPath), isFile: v.isFile() }))),
54
54
  writeFile: ([path, data]) => tc(() => writeFile(path, fromVec(data))),
55
55
  rm: path => tc(() => rm(path)),
56
+ exec,
56
57
  createServer: async (requestListener) => {
57
58
  const erl = requestListener;
58
59
  const nodeRl = async (req, res) => {
package/io/module.js CHANGED
@@ -7,6 +7,7 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
7
7
  return path;
8
8
  };
9
9
  import http from 'node:http';
10
+ import { exec } from 'node:child_process';
10
11
  import { fromIo, run } from "./module.f.js";
11
12
  import fs from 'node:fs';
12
13
  import process from 'node:process';
@@ -41,6 +42,9 @@ export const io = {
41
42
  }
42
43
  },
43
44
  http,
45
+ childProcess: {
46
+ exec: command => new Promise(resolve => exec(command, (e, stdout, stderr) => resolve(e !== null ? error(e) : ok({ stdout, stderr })))),
47
+ },
44
48
  };
45
49
  export const legacyRun = run(io);
46
50
  export const ioRun = (io) => {
@@ -36,5 +36,8 @@ export const createVirtualIo = (files) => ({
36
36
  asyncTryCatch: async (f) => ['ok', await f()],
37
37
  http: {
38
38
  createServer: todo
39
- }
39
+ },
40
+ childProcess: {
41
+ exec: todo,
42
+ },
40
43
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.12.5",
3
+ "version": "0.12.7",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "**/*.js",
@@ -188,6 +188,16 @@ export declare const msb: BitOrder;
188
188
  * @returns The resulting vector based on the provided bit order.
189
189
  */
190
190
  export declare const u8ListToVec: ({ unpackConcat }: BitOrder) => (list: List<number>) => Vec;
191
+ /**
192
+ * Chunks a bit vector into fixed-size pieces of `n` bits using the provided bit order.
193
+ * The last chunk may be smaller than `n` bits if the vector length is not a multiple of `n`.
194
+ *
195
+ * @param bitOrder The bit order for the conversion.
196
+ * @param n The chunk size in bits.
197
+ * @param v The vector to be chunked.
198
+ * @returns A thunk that produces a list of bit vectors, each representing one chunk.
199
+ */
200
+ export declare const chunkList: ({ unpackSplit }: BitOrder) => (n: bigint) => (v: Vec) => Thunk<Vec>;
191
201
  /**
192
202
  * Converts a bit vector to a list of unsigned 8-bit integers based on the provided bit order.
193
203
  *
@@ -195,7 +205,7 @@ export declare const u8ListToVec: ({ unpackConcat }: BitOrder) => (list: List<nu
195
205
  * @param v The vector to be converted.
196
206
  * @returns A thunk that produces a list of unsigned 8-bit integers.
197
207
  */
198
- export declare const u8List: ({ unpackSplit }: BitOrder) => (v: Vec) => Thunk<number>;
208
+ export declare const u8List: (bo: BitOrder) => (v: Vec) => Thunk<number>;
199
209
  /**
200
210
  * Concatenates a list of vectors using the provided bit order.
201
211
  */
@@ -21,9 +21,9 @@
21
21
  *
22
22
  * @module
23
23
  */
24
- import { bitLength, mask, max, min, xor } from "../bigint/module.f.js";
24
+ import { bitLength, divUp, mask, max, min, xor } from "../bigint/module.f.js";
25
25
  import { flip } from "../function/module.f.js";
26
- import { fold, iterable } from "../list/module.f.js";
26
+ import { fold, iterable, map } from "../list/module.f.js";
27
27
  import { asBase, asNominal } from "../nominal/module.f.js";
28
28
  import { repeat as mRepeat } from "../monoid/module.f.js";
29
29
  import { cmp } from "../function/compare/module.f.js";
@@ -230,37 +230,54 @@ export const u8ListToVec = ({ unpackConcat }) => (list) => {
230
230
  return pack(result.reduce((p, c) => unpackConcat(c)(p), unpackEmpty));
231
231
  };
232
232
  /**
233
- * Converts a bit vector to a list of unsigned 8-bit integers based on the provided bit order.
233
+ * Chunks a bit vector into fixed-size pieces of `n` bits using the provided bit order.
234
+ * The last chunk may be smaller than `n` bits if the vector length is not a multiple of `n`.
234
235
  *
235
236
  * @param bitOrder The bit order for the conversion.
236
- * @param v The vector to be converted.
237
- * @returns A thunk that produces a list of unsigned 8-bit integers.
237
+ * @param n The chunk size in bits.
238
+ * @param v The vector to be chunked.
239
+ * @returns A thunk that produces a list of bit vectors, each representing one chunk.
238
240
  */
239
- export const u8List = ({ unpackSplit }) => (v) => {
240
- if (v === empty) {
241
- return () => null;
242
- }
243
- const f = (stack) => () => {
244
- while (true) {
245
- const [first, rest] = stack;
246
- const { length, uint } = first;
247
- if (length <= 8n) {
248
- // the last unpack split is required to align data.
249
- const v = length < 8n ? unpackSplit(8n)(first)[0] : uint;
250
- return { first: Number(v), tail: rest !== undefined ? f(rest) : null };
251
- }
252
- // `length` is bigger than `8n` so `newLen` is `8n` or bigger.
253
- const aLength = ((length + 7n) >> 4n) << 3n;
254
- const bLength = length - aLength;
255
- const [a, b] = unpackSplit(aLength)(first);
256
- stack = [
257
- { length: aLength, uint: a & mask(aLength) },
258
- [{ length: bLength, uint: b & mask(bLength) }, rest],
259
- ];
241
+ export const chunkList = ({ unpackSplit }) => (n) => {
242
+ const divUpN2 = divUp(n << 1n);
243
+ return v => {
244
+ if (v === empty) {
245
+ return () => null;
260
246
  }
247
+ const f = (stack) => () => {
248
+ while (true) {
249
+ const [first, rest] = stack;
250
+ const { length } = first;
251
+ if (length <= n) {
252
+ return { first: pack(first), tail: rest !== undefined ? f(rest) : null };
253
+ }
254
+ const aLength = divUpN2(length) * n;
255
+ const bLength = length - aLength;
256
+ const [a, b] = unpackSplit(aLength)(first);
257
+ stack = [
258
+ { length: aLength, uint: a & mask(aLength) },
259
+ [{ length: bLength, uint: b & mask(bLength) }, rest],
260
+ ];
261
+ }
262
+ };
263
+ return f([unpack(v), undefined]);
261
264
  };
262
- return f([unpack(v), undefined]);
263
265
  };
266
+ const vecToU8 = ({ unpackSplit }) => {
267
+ const unpackSplit8 = unpackSplit(8n);
268
+ return chunk => {
269
+ const u = unpack(chunk);
270
+ return Number(u.length < 8n ? unpackSplit8(u)[0] : u.uint);
271
+ };
272
+ };
273
+ /**
274
+ * Converts a bit vector to a list of unsigned 8-bit integers based on the provided bit order.
275
+ *
276
+ * @param bitOrder The bit order for the conversion.
277
+ * @param v The vector to be converted.
278
+ * @returns A thunk that produces a list of unsigned 8-bit integers.
279
+ */
280
+ export const u8List = (bo) => (v) => map(vecToU8(bo))(chunkList(bo)(8n)(v));
264
281
  /**
265
282
  * Concatenates a list of vectors using the provided bit order.
266
283
  */
@@ -41,5 +41,12 @@ declare const _default: {
41
41
  msbCmp: () => void;
42
42
  u8ListToVec: () => () => void;
43
43
  u8ListUnaligned: () => void;
44
+ chunkList: {
45
+ empty: () => void;
46
+ lsb_aligned: () => void;
47
+ msb_aligned: () => void;
48
+ lsb_unaligned: () => void;
49
+ msb_unaligned: () => void;
50
+ };
44
51
  };
45
52
  export default _default;
@@ -1,6 +1,6 @@
1
1
  import { mask } from "../bigint/module.f.js";
2
2
  import { asBase, asNominal } from "../nominal/module.f.js";
3
- import { length, empty, uint, vec, lsb, msb, repeat, vec8, u8ListToVec, u8List } from "./module.f.js";
3
+ import { length, empty, uint, vec, lsb, msb, repeat, vec8, u8ListToVec, u8List, chunkList } from "./module.f.js";
4
4
  import { repeat as listRepeat, toArray } from "../list/module.f.js";
5
5
  const unsafeVec = (a) => asNominal(a);
6
6
  // 0x8 = 0b1000 = 0 + 8
@@ -482,5 +482,73 @@ export default {
482
482
  if (a1 !== 0x80) {
483
483
  throw `a1: ${a1.toString(16)}`;
484
484
  }
485
- }
485
+ },
486
+ chunkList: {
487
+ empty: () => {
488
+ const chunks = toArray(chunkList(lsb)(4n)(empty));
489
+ if (chunks.length !== 0) {
490
+ throw chunks.length;
491
+ }
492
+ },
493
+ // 8-bit vector 0xF5 = 0b1111_0101, aligned to 4-bit chunks
494
+ lsb_aligned: () => {
495
+ const chunks = toArray(chunkList(lsb)(4n)(vec(8n)(0xf5n)));
496
+ // LSB: low nibble first — bits 0-3 = 0101 = 5, bits 4-7 = 1111 = 15
497
+ if (chunks.length !== 2) {
498
+ throw chunks.length;
499
+ }
500
+ if (length(chunks[0]) !== 4n || uint(chunks[0]) !== 5n) {
501
+ throw chunks[0];
502
+ }
503
+ if (length(chunks[1]) !== 4n || uint(chunks[1]) !== 0xfn) {
504
+ throw chunks[1];
505
+ }
506
+ },
507
+ msb_aligned: () => {
508
+ const chunks = toArray(chunkList(msb)(4n)(vec(8n)(0xf5n)));
509
+ // MSB: high nibble first — bits 0-3 = 1111 = 15, bits 4-7 = 0101 = 5
510
+ if (chunks.length !== 2) {
511
+ throw chunks.length;
512
+ }
513
+ if (length(chunks[0]) !== 4n || uint(chunks[0]) !== 0xfn) {
514
+ throw chunks[0];
515
+ }
516
+ if (length(chunks[1]) !== 4n || uint(chunks[1]) !== 5n) {
517
+ throw chunks[1];
518
+ }
519
+ },
520
+ // 10-bit vector 0x1B5 = 0b01_1011_0101, unaligned to 4-bit chunks (last chunk is 2 bits)
521
+ lsb_unaligned: () => {
522
+ const chunks = toArray(chunkList(lsb)(4n)(vec(10n)(0x1b5n)));
523
+ // LSB: bits 0-3 = 0101 = 5, bits 4-7 = 1011 = 11, bits 8-9 = 01 = 1
524
+ if (chunks.length !== 3) {
525
+ throw chunks.length;
526
+ }
527
+ if (length(chunks[0]) !== 4n || uint(chunks[0]) !== 5n) {
528
+ throw chunks[0];
529
+ }
530
+ if (length(chunks[1]) !== 4n || uint(chunks[1]) !== 0xbn) {
531
+ throw chunks[1];
532
+ }
533
+ if (length(chunks[2]) !== 2n || uint(chunks[2]) !== 1n) {
534
+ throw chunks[2];
535
+ }
536
+ },
537
+ msb_unaligned: () => {
538
+ const chunks = toArray(chunkList(msb)(4n)(vec(10n)(0x1b5n)));
539
+ // MSB: bits 0-3 = 0110 = 6, bits 4-7 = 1101 = 13, bits 8-9 = 01 = 1
540
+ if (chunks.length !== 3) {
541
+ throw chunks.length;
542
+ }
543
+ if (length(chunks[0]) !== 4n || uint(chunks[0]) !== 6n) {
544
+ throw chunks[0];
545
+ }
546
+ if (length(chunks[1]) !== 4n || uint(chunks[1]) !== 0xdn) {
547
+ throw chunks[1];
548
+ }
549
+ if (length(chunks[2]) !== 2n || uint(chunks[2]) !== 1n) {
550
+ throw chunks[2];
551
+ }
552
+ },
553
+ },
486
554
  };
@@ -43,7 +43,13 @@ export type WriteFile = readonly ['writeFile', (_: WriteFileParam) => IoResult<v
43
43
  export declare const writeFile: RestFunc<WriteFile>;
44
44
  export type Rm = readonly ['rm', (_: string) => IoResult<void>];
45
45
  export declare const rm: Func<Rm>;
46
- export type Fs = Mkdir | ReadFile | Readdir | WriteFile | Rm;
46
+ export type ExecResult = {
47
+ readonly stdout: string;
48
+ readonly stderr: string;
49
+ };
50
+ export type Exec = readonly ['exec', (_: string) => IoResult<ExecResult>];
51
+ export declare const exec: Func<Exec>;
52
+ export type Fs = Mkdir | ReadFile | Readdir | WriteFile | Rm | Exec;
47
53
  export type Error = ['error', (_: string) => void];
48
54
  export declare const error: Func<Error>;
49
55
  export type Log = ['log', (_: string) => void];
@@ -15,6 +15,7 @@ export const readFile = do_('readFile');
15
15
  export const readdir = doRest('readdir');
16
16
  export const writeFile = doRest('writeFile');
17
17
  export const rm = do_('rm');
18
+ export const exec = do_('exec');
18
19
  export const error = do_('error');
19
20
  export const log = do_('log');
20
21
  export const createServer = do_('createServer');
@@ -131,6 +131,7 @@ const map = {
131
131
  readdir: (state, [path, { recursive }]) => readdir(path, recursive === true)(state, path),
132
132
  writeFile: (state, [path, payload]) => writeFile(payload)(state, path),
133
133
  rm: (state, path) => rm(state, path),
134
+ exec: todo,
134
135
  createServer: todo,
135
136
  listen: todo,
136
137
  forever: todo,