@code-essentials/utils 1.0.12 → 1.1.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.
@@ -12,7 +12,8 @@ export declare class AsyncVariable<T> implements PromiseLike<T> {
12
12
  set(value: T, throw_if_set?: boolean): Promise<void>;
13
13
  reject(error: unknown, throw_if_set?: boolean): Promise<void>;
14
14
  static performCallback<R = void>(fn: (cb: (err?: unknown, res?: R) => void) => void): AsyncVariable<R>;
15
- perform(fn: () => Promise<T>): this;
15
+ writeResult(task: PromiseLike<T>): Promise<void>;
16
+ perform(fn: () => PromiseLike<T>): this;
16
17
  timeout(milliseconds: number): this;
17
18
  static perform<T>(fn: () => Promise<T>): AsyncVariable<T>;
18
19
  static wait(milliseconds: number): AsyncVariable<void>;
@@ -81,8 +81,16 @@ export class AsyncVariable {
81
81
  });
82
82
  return av;
83
83
  }
84
+ async writeResult(task) {
85
+ try {
86
+ await this.set(await task);
87
+ }
88
+ catch (error) {
89
+ await this.reject(error);
90
+ }
91
+ }
84
92
  perform(fn) {
85
- fn().then(value => this.set(value)).catch(error => this.reject(error));
93
+ this.writeResult(fn());
86
94
  return this;
87
95
  }
88
96
  timeout(milliseconds) {
@@ -0,0 +1,15 @@
1
+ import { AsyncVariable } from "./async-variable.js";
2
+ interface EnqueuedTask<T> {
3
+ task: PromiseLike<T>;
4
+ completion: AsyncVariable<T>;
5
+ }
6
+ export declare class Barrier<T = any> implements PromiseLike<T[]> {
7
+ #private;
8
+ readonly queue: EnqueuedTask<T>[];
9
+ await(...asyncTasks: PromiseLike<T>[]): void;
10
+ run(...asyncTasks: PromiseLike<T>[]): void;
11
+ clear(): void;
12
+ complete(): Promise<this>;
13
+ then<TResult1 = T[], TResult2 = never>(onfulfilled?: ((value: T[]) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined): Promise<TResult1 | TResult2>;
14
+ }
15
+ export {};
@@ -0,0 +1,33 @@
1
+ import { AsyncVariable } from "./async-variable.js";
2
+ export class Barrier {
3
+ queue = [];
4
+ await(...asyncTasks) {
5
+ this.run(...asyncTasks);
6
+ }
7
+ async #run(task) {
8
+ const completion = new AsyncVariable();
9
+ this.queue.push({ task, completion });
10
+ completion.writeResult(task);
11
+ }
12
+ run(...asyncTasks) {
13
+ for (const task of asyncTasks)
14
+ this.#run(task);
15
+ }
16
+ clear() {
17
+ this.queue.splice(0, this.queue.length);
18
+ }
19
+ async complete() {
20
+ const result = await this;
21
+ this.clear();
22
+ return result;
23
+ }
24
+ async then(onfulfilled, onrejected) {
25
+ try {
26
+ const values = await Promise.all(this.queue.map(({ completion }) => completion));
27
+ return await onfulfilled?.(values);
28
+ }
29
+ catch (reason) {
30
+ return await onrejected?.(reason);
31
+ }
32
+ }
33
+ }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './types.js';
2
2
  export * from './strings.js';
3
3
  export * from './async-variable.js';
4
+ export * from './barrier.js';
4
5
  export * from './observable-list.js';
5
6
  export * from './object.js';
6
7
  export * from './lock.js';
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './types.js';
2
2
  export * from './strings.js';
3
3
  export * from './async-variable.js';
4
+ export * from './barrier.js';
4
5
  export * from './observable-list.js';
5
6
  export * from './object.js';
6
7
  export * from './lock.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-essentials/utils",
3
- "version": "1.0.12",
3
+ "version": "1.1.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -10,9 +10,9 @@
10
10
  ],
11
11
  "devDependencies": {
12
12
  "@ava/typescript": "^6.0.0",
13
- "@code-essentials/tsconfig": "^1.0.3",
14
- "@code-essentials/ava-typescript": "^1.0.0",
15
- "@types/node": "^24.8.1",
13
+ "@code-essentials/ava-typescript": "^1.1.1",
14
+ "@code-essentials/tsconfig": "^1.2.1",
15
+ "@types/node": "^24.10.1",
16
16
  "ava": "^6.4.1",
17
17
  "typescript": "^5.9.3"
18
18
  },
@@ -30,9 +30,11 @@
30
30
  "clean": "rm -rf dist",
31
31
  "prebuild": "pnpm run clean",
32
32
  "prebuild:debug": "pnpm run clean",
33
- "build": "tsc",
33
+ "build": "tsc -p tsconfig.prod.json",
34
34
  "build:debug": "tsc -p tsconfig.debug.json",
35
35
  "pretest": "pnpm run build:debug",
36
- "test": "ava"
36
+ "test": "pnpm run test:run",
37
+ "pretest:run": "",
38
+ "test:run": "ava"
37
39
  }
38
40
  }
@@ -1 +0,0 @@
1
- export {};
package/dist/lock.spec.js DELETED
@@ -1,93 +0,0 @@
1
- var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
- if (value !== null && value !== void 0) {
3
- if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
- var dispose, inner;
5
- if (async) {
6
- if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
- dispose = value[Symbol.asyncDispose];
8
- }
9
- if (dispose === void 0) {
10
- if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
- dispose = value[Symbol.dispose];
12
- if (async) inner = dispose;
13
- }
14
- if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
- if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
- env.stack.push({ value: value, dispose: dispose, async: async });
17
- }
18
- else if (async) {
19
- env.stack.push({ async: true });
20
- }
21
- return value;
22
- };
23
- var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
- return function (env) {
25
- function fail(e) {
26
- env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
- env.hasError = true;
28
- }
29
- var r, s = 0;
30
- function next() {
31
- while (r = env.stack.pop()) {
32
- try {
33
- if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
- if (r.dispose) {
35
- var result = r.dispose.call(r.value);
36
- if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
- }
38
- else s |= 1;
39
- }
40
- catch (e) {
41
- fail(e);
42
- }
43
- }
44
- if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
- if (env.hasError) throw env.error;
46
- }
47
- return next();
48
- };
49
- })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
- var e = new Error(message);
51
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
- });
53
- import test from "ava";
54
- import { Lock } from "./lock.js";
55
- test('acquire when free', t => {
56
- const lock = new Lock();
57
- const context = lock.acquire();
58
- context.release();
59
- t.pass();
60
- });
61
- test('fail to acquire when already acquired', t => {
62
- const lock = new Lock();
63
- lock.acquire();
64
- t.throws(() => lock.acquire(), { message: Lock.ERR_ACQUIRED });
65
- });
66
- test('disposable release', t => {
67
- const lock = new Lock();
68
- function acquire(pass) {
69
- if (pass)
70
- t.notThrows(() => lock.acquire());
71
- else
72
- t.throws(() => lock.acquire(), { message: Lock.ERR_ACQUIRED });
73
- }
74
- function acquire_0() {
75
- const env_1 = { stack: [], error: void 0, hasError: false };
76
- try {
77
- const _context1 = __addDisposableResource(env_1, lock.acquire(), false);
78
- acquire(false);
79
- }
80
- catch (e_1) {
81
- env_1.error = e_1;
82
- env_1.hasError = true;
83
- }
84
- finally {
85
- __disposeResources(env_1);
86
- }
87
- }
88
- function acquire_1() {
89
- acquire(true);
90
- }
91
- acquire_0();
92
- acquire_1();
93
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,20 +0,0 @@
1
- import test from "ava";
2
- import { replaceProperty } from "./object.js";
3
- test("replace", t => {
4
- const a0 = {
5
- i: 0,
6
- b: {
7
- j: 0,
8
- c: {
9
- k: 0
10
- },
11
- }
12
- };
13
- t.is(a0.i, 0);
14
- const a1 = replaceProperty(a0, ["i"], 1);
15
- t.is(a0.i, 0);
16
- t.is(a1.i, 1);
17
- a0.b.j++;
18
- t.is(a0.b.j, 1);
19
- t.is(a1.b.j, 1);
20
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,16 +0,0 @@
1
- import { ObservableList } from "./observable-list.js";
2
- import test from "ava";
3
- test("insert", t => {
4
- const list = new ObservableList();
5
- const words = ["keyboard", "mouse", "display"];
6
- t.plan(words.length);
7
- let itemInserted = "";
8
- const responder = (item) => t.is(item, itemInserted);
9
- list.on("insert", responder);
10
- list.push(itemInserted = words[0]);
11
- list.push(itemInserted = words[1]);
12
- list.off("insert", responder);
13
- list.push("unrelated");
14
- list.on("insert", responder);
15
- list.push(itemInserted = words[2]);
16
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,20 +0,0 @@
1
- import test from "ava";
2
- function typeCheck(t, _) {
3
- t.pass();
4
- }
5
- test("startsWith", t => {
6
- const prefix = "abc";
7
- typeCheck(t, `abc123`);
8
- });
9
- test("endsWith", t => {
10
- const suffix = "123";
11
- typeCheck(t, `abc123`);
12
- });
13
- test("concat 0", t => {
14
- const arr = ["abc", "def", "gh", "ijk"];
15
- typeCheck(t, "abcdefghijk");
16
- });
17
- test("concat 1", t => {
18
- const arr = ["abc", "def", "gh", "ijk"];
19
- typeCheck(t, "abc def gh ijk");
20
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,28 +0,0 @@
1
- import test from 'ava';
2
- import { assert, valuesPrefixed } from './types.js';
3
- test("valuesPrefixed", t => {
4
- const abc = {
5
- a: '.a',
6
- b: '.b',
7
- c: '.c',
8
- };
9
- const prefix = "prefix1";
10
- const abc_k1 = valuesPrefixed(prefix, abc);
11
- t.deepEqual(abc_k1, {
12
- a: `${prefix}${abc.a}`,
13
- b: `${prefix}${abc.b}`,
14
- c: `${prefix}${abc.c}`,
15
- });
16
- });
17
- test("deeply readonly 1", t => {
18
- assert();
19
- t.pass();
20
- });
21
- test("deeply readonly 2", t => {
22
- assert();
23
- t.pass();
24
- });
25
- test("deeply readonly 3", t => {
26
- assert();
27
- t.pass();
28
- });