@code-essentials/utils 1.0.2 → 1.0.4
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/LICENSE.md +21 -0
- package/dist/async-variable.d.ts +19 -0
- package/dist/async-variable.js +103 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/lock.d.ts +16 -0
- package/dist/lock.js +39 -0
- package/dist/object.d.ts +10 -0
- package/dist/object.js +34 -0
- package/dist/observable-list.d.ts +24 -0
- package/dist/observable-list.js +75 -0
- package/dist/strings.d.ts +3 -0
- package/dist/strings.js +1 -0
- package/dist/types.d.ts +12 -0
- package/dist/types.js +6 -0
- package/package.json +16 -14
- package/.vscode/launch.json +0 -21
- package/.vscode/tasks.json +0 -22
- package/src/async-variable.ts +0 -146
- package/src/index.ts +0 -5
- package/src/lock.spec.ts +0 -38
- package/src/lock.ts +0 -50
- package/src/object.spec.ts +0 -39
- package/src/object.ts +0 -60
- package/src/observable-list.spec.ts +0 -25
- package/src/observable-list.ts +0 -114
- package/src/types.ts +0 -21
- package/tsconfig.debug.json +0 -9
- package/tsconfig.json +0 -9
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Graph Mind License Agreement
|
|
2
|
+
|
|
3
|
+
Copyright © 2025 Isaac Valdez. All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
1. Ownership
|
|
6
|
+
The source code and all associated intellectual property for the 'graph-math' project (hereinafter referred to as "the Software") are the exclusive private property of Isaac Valdez.
|
|
7
|
+
|
|
8
|
+
2. Permitted Use
|
|
9
|
+
The Software may only be examined in source code form with explicit permission from Isaac Valdez. Individuals or entities wishing to review or utilize the source code must obtain this permission in writing.
|
|
10
|
+
|
|
11
|
+
3. End-User Licensing
|
|
12
|
+
End users are permitted to run the Software on their local computer systems, provided such usage complies with a separate End-User License Agreement (EULA) that will be supplied to the end user.
|
|
13
|
+
|
|
14
|
+
4. License Modifications
|
|
15
|
+
Isaac Valdez reserves the right to update or modify this license at any time. Changes will be effective upon modification of the license text and will apply to all users from that date onward.
|
|
16
|
+
|
|
17
|
+
5. No Warranty
|
|
18
|
+
The Software is provided "as is," without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, or non-infringement.
|
|
19
|
+
|
|
20
|
+
6. Acceptance
|
|
21
|
+
By using the Software, you indicate your acceptance of this license agreement. If you do not agree to abide by the terms of this agreement, you must refrain from using the Software.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare class AsyncVariable<T> implements PromiseLike<T> {
|
|
2
|
+
#private;
|
|
3
|
+
get value(): T;
|
|
4
|
+
set value(value: T);
|
|
5
|
+
get error(): any;
|
|
6
|
+
set error(error: any);
|
|
7
|
+
get complete(): boolean;
|
|
8
|
+
constructor();
|
|
9
|
+
init(): Promise<void>;
|
|
10
|
+
read(): Promise<T>;
|
|
11
|
+
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined): PromiseLike<TResult1 | TResult2>;
|
|
12
|
+
set(value: T, throw_if_set?: boolean): Promise<void>;
|
|
13
|
+
reject(error: unknown, throw_if_set?: boolean): Promise<void>;
|
|
14
|
+
static performCallback<R = void>(fn: (cb: (err?: unknown, res?: R) => void) => void): AsyncVariable<R>;
|
|
15
|
+
perform(fn: () => Promise<T>): this;
|
|
16
|
+
timeout(milliseconds: number): this;
|
|
17
|
+
static perform<T>(fn: () => Promise<T>): AsyncVariable<T>;
|
|
18
|
+
static wait(milliseconds: number): AsyncVariable<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
export class AsyncVariable {
|
|
2
|
+
#result;
|
|
3
|
+
#result_res;
|
|
4
|
+
#result_p;
|
|
5
|
+
#initialization;
|
|
6
|
+
get value() {
|
|
7
|
+
if (!this.#result)
|
|
8
|
+
throw new Error('incomplete');
|
|
9
|
+
if (this.#result.type === "rejected")
|
|
10
|
+
throw this.#result.error;
|
|
11
|
+
return this.#result.value;
|
|
12
|
+
}
|
|
13
|
+
set value(value) {
|
|
14
|
+
this.set(value);
|
|
15
|
+
}
|
|
16
|
+
get error() {
|
|
17
|
+
if (!this.#result)
|
|
18
|
+
throw new Error('incomplete');
|
|
19
|
+
if (this.#result.type === "resolved")
|
|
20
|
+
throw new Error(this.#result.type);
|
|
21
|
+
return this.#result.error;
|
|
22
|
+
}
|
|
23
|
+
set error(error) {
|
|
24
|
+
this.reject(error);
|
|
25
|
+
}
|
|
26
|
+
get complete() {
|
|
27
|
+
return this.#result !== undefined;
|
|
28
|
+
}
|
|
29
|
+
constructor() {
|
|
30
|
+
this.#initialization = new Promise(initialized =>
|
|
31
|
+
// prevents unhandled rejection
|
|
32
|
+
this.#result_p = new Promise(res => {
|
|
33
|
+
this.#result_res = res;
|
|
34
|
+
initialized();
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
async init() {
|
|
38
|
+
await this.#initialization;
|
|
39
|
+
}
|
|
40
|
+
async read() {
|
|
41
|
+
await this.#initialization;
|
|
42
|
+
await this.#result_p;
|
|
43
|
+
return this.value;
|
|
44
|
+
}
|
|
45
|
+
then(onfulfilled, onrejected) {
|
|
46
|
+
return this.read().then(onfulfilled, onrejected);
|
|
47
|
+
}
|
|
48
|
+
async #complete(throw_if_set = true) {
|
|
49
|
+
await this.#initialization;
|
|
50
|
+
if (this.complete) {
|
|
51
|
+
if (throw_if_set)
|
|
52
|
+
throw new Error('already set');
|
|
53
|
+
else
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
async set(value, throw_if_set = true) {
|
|
59
|
+
if (await this.#complete(throw_if_set)) {
|
|
60
|
+
this.#result_res(this.#result = {
|
|
61
|
+
type: "resolved",
|
|
62
|
+
value
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async reject(error, throw_if_set = true) {
|
|
67
|
+
if (await this.#complete(throw_if_set)) {
|
|
68
|
+
this.#result_res(this.#result = {
|
|
69
|
+
type: "rejected",
|
|
70
|
+
error
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
static performCallback(fn) {
|
|
75
|
+
const av = new AsyncVariable();
|
|
76
|
+
fn(async (err, res) => {
|
|
77
|
+
if (err)
|
|
78
|
+
await av.error(err);
|
|
79
|
+
else
|
|
80
|
+
await av.set(res);
|
|
81
|
+
});
|
|
82
|
+
return av;
|
|
83
|
+
}
|
|
84
|
+
perform(fn) {
|
|
85
|
+
fn().then(value => this.set(value)).catch(error => this.reject(error));
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
timeout(milliseconds) {
|
|
89
|
+
AsyncVariable.wait(milliseconds).then(() => {
|
|
90
|
+
if (!this.complete)
|
|
91
|
+
this.reject("timeout");
|
|
92
|
+
});
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
static perform(fn) {
|
|
96
|
+
return new AsyncVariable().perform(fn);
|
|
97
|
+
}
|
|
98
|
+
static wait(milliseconds) {
|
|
99
|
+
const res = new AsyncVariable();
|
|
100
|
+
setTimeout(() => res.set(), milliseconds);
|
|
101
|
+
return res;
|
|
102
|
+
}
|
|
103
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/lock.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare class Lock<Of = void> {
|
|
2
|
+
#private;
|
|
3
|
+
get isAcquired(): boolean;
|
|
4
|
+
acquire(of: Of): LockContext<Of>;
|
|
5
|
+
protected release(_context: LockContext<Of>): void;
|
|
6
|
+
static readonly ERR_ACQUIRED = "lock currently acquired";
|
|
7
|
+
}
|
|
8
|
+
export declare class LockContext<Of> implements Disposable {
|
|
9
|
+
#private;
|
|
10
|
+
readonly lock: Lock<Of>;
|
|
11
|
+
readonly of: Of;
|
|
12
|
+
constructor(lock: Lock<Of>, of: Of, release: (conext: LockContext<Of>) => void);
|
|
13
|
+
release(): void;
|
|
14
|
+
[Symbol.dispose](): void;
|
|
15
|
+
static readonly ERR_LOCK_RELEASED = "lock context already released";
|
|
16
|
+
}
|
package/dist/lock.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class Lock {
|
|
2
|
+
#isAcquired = false;
|
|
3
|
+
get isAcquired() {
|
|
4
|
+
return this.#isAcquired;
|
|
5
|
+
}
|
|
6
|
+
acquire(of) {
|
|
7
|
+
if (this.#isAcquired)
|
|
8
|
+
throw new Error(Lock.ERR_ACQUIRED);
|
|
9
|
+
this.#isAcquired = true;
|
|
10
|
+
return new LockContext(this, of, this.release.bind(this));
|
|
11
|
+
}
|
|
12
|
+
release(_context) {
|
|
13
|
+
if (!this.isAcquired)
|
|
14
|
+
throw new Error();
|
|
15
|
+
this.#isAcquired = false;
|
|
16
|
+
}
|
|
17
|
+
static ERR_ACQUIRED = 'lock currently acquired';
|
|
18
|
+
}
|
|
19
|
+
export class LockContext {
|
|
20
|
+
lock;
|
|
21
|
+
of;
|
|
22
|
+
#release;
|
|
23
|
+
#isAcquired = true;
|
|
24
|
+
constructor(lock, of, release) {
|
|
25
|
+
this.lock = lock;
|
|
26
|
+
this.of = of;
|
|
27
|
+
this.#release = release;
|
|
28
|
+
}
|
|
29
|
+
release() {
|
|
30
|
+
if (!this.#isAcquired)
|
|
31
|
+
throw new Error(LockContext.ERR_LOCK_RELEASED);
|
|
32
|
+
this.#isAcquired = false;
|
|
33
|
+
this.#release(this);
|
|
34
|
+
}
|
|
35
|
+
[Symbol.dispose]() {
|
|
36
|
+
this.release();
|
|
37
|
+
}
|
|
38
|
+
static ERR_LOCK_RELEASED = "lock context already released";
|
|
39
|
+
}
|
package/dist/object.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type Values<T extends object> = T[keyof T];
|
|
2
|
+
export type PropertyPath<T> = [] | T extends object ? Values<{
|
|
3
|
+
[K in keyof T]: [K] | [K, Values<PropertyPath<T[K]>>];
|
|
4
|
+
}> : [];
|
|
5
|
+
export type PropertyType<T, Property extends PropertyPath<T>> = PropertyType_<T, Property>;
|
|
6
|
+
type PropertyType_<T, Property extends any[], Constructed extends any[] = []> = (Property & Constructed) extends never ? Values<{
|
|
7
|
+
[K in keyof T as Property extends [...Constructed, K, ...any[]] ? K : never]: PropertyType_<T[K], Property, [...Constructed, K]>;
|
|
8
|
+
}> : T;
|
|
9
|
+
export declare function replaceProperty<T, Property extends PropertyPath<T> = PropertyPath<T>>(obj: T, property: Property, value: any): T;
|
|
10
|
+
export {};
|
package/dist/object.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// export type PropertyType<T, Property extends PropertyPath<T> & PropertyKey[]> = PropertyType_<T, Property>
|
|
2
|
+
// type PropertyType_<T, Property extends PropertyKey[], Constructed extends PropertyKey[] = []> =
|
|
3
|
+
// (Property & Constructed) extends never ?
|
|
4
|
+
// Values<{
|
|
5
|
+
// [K in keyof T as Property extends [...Constructed, K, ...PropertyKey[]] ? K : never]:
|
|
6
|
+
// PropertyType_<T[K], Property, [...Constructed, K]>
|
|
7
|
+
// }> :
|
|
8
|
+
// T
|
|
9
|
+
// type A = {
|
|
10
|
+
// a: {
|
|
11
|
+
// a: 10,
|
|
12
|
+
// b: 1
|
|
13
|
+
// c: 2
|
|
14
|
+
// }
|
|
15
|
+
// b: {
|
|
16
|
+
// a: {
|
|
17
|
+
// c: 1
|
|
18
|
+
// }
|
|
19
|
+
// }
|
|
20
|
+
// }
|
|
21
|
+
// type a_path = PropertyPath<A>
|
|
22
|
+
// const ac = ["a", "c"] satisfies a_path
|
|
23
|
+
// // type a1 = (typeof ac) extends ["a", "c", ...PropertyKey[]] ? true : false
|
|
24
|
+
// type ac_type = PropertyType_<A, typeof ac>
|
|
25
|
+
export function replaceProperty(obj, property, value) {
|
|
26
|
+
if (property.length === 0)
|
|
27
|
+
return (value ?? obj);
|
|
28
|
+
if (typeof obj !== 'object')
|
|
29
|
+
throw new Error();
|
|
30
|
+
const prototype = Object.create(obj);
|
|
31
|
+
const property0 = property[0];
|
|
32
|
+
prototype[property0] = replaceProperty(obj[property0], property.slice(1), value);
|
|
33
|
+
return prototype;
|
|
34
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface ObservableListProtocols<T> {
|
|
2
|
+
insert(item: T, index: number): void;
|
|
3
|
+
delete(item: T, index: number): void;
|
|
4
|
+
reorder(item: T, index1: number): void;
|
|
5
|
+
}
|
|
6
|
+
export declare class ObservableList<T> extends Array<T> {
|
|
7
|
+
#private;
|
|
8
|
+
constructor(length: number);
|
|
9
|
+
constructor(...items: T[]);
|
|
10
|
+
push(...items: T[]): number;
|
|
11
|
+
pop(): T | undefined;
|
|
12
|
+
reverse(): T[];
|
|
13
|
+
sort(compareFn?: ((a: T, b: T) => number) | undefined): this;
|
|
14
|
+
shift(): T | undefined;
|
|
15
|
+
splice(start: number, deleteCount?: number, ...items: T[]): T[];
|
|
16
|
+
unshift(...items: T[]): number;
|
|
17
|
+
on<Protocol extends keyof ObservableListProtocols<T>>(protocol: Protocol, responder: ObservableListProtocols<T>[Protocol]): void;
|
|
18
|
+
off<Protocol extends keyof ObservableListProtocols<T>>(protocol: Protocol, responder: ObservableListProtocols<T>[Protocol]): void;
|
|
19
|
+
responders<Protocol extends keyof ObservableListProtocols<T>>(protocol: Protocol): {
|
|
20
|
+
insert: Set<(item: T, index: number) => void>;
|
|
21
|
+
delete: Set<(item: T, index: number) => void>;
|
|
22
|
+
reorder: Set<(item: T, index1: number) => void>;
|
|
23
|
+
}[Protocol];
|
|
24
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export class ObservableList extends Array {
|
|
2
|
+
constructor(...itemsOrArrayLength) {
|
|
3
|
+
super(...itemsOrArrayLength);
|
|
4
|
+
}
|
|
5
|
+
push(...items) {
|
|
6
|
+
const length0 = this.length;
|
|
7
|
+
const result = super.push(...items);
|
|
8
|
+
items.forEach((item, i) => this.#emit("insert", item, length0 + i));
|
|
9
|
+
return result;
|
|
10
|
+
}
|
|
11
|
+
pop() {
|
|
12
|
+
const index = this.length - 1;
|
|
13
|
+
const result = super.pop();
|
|
14
|
+
if (index >= 0)
|
|
15
|
+
this.#emit("delete", result, index);
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
reverse() {
|
|
19
|
+
const final_index = this.length - 1;
|
|
20
|
+
const result = super.reverse();
|
|
21
|
+
this.forEach((item, i) => {
|
|
22
|
+
const index0 = final_index - i;
|
|
23
|
+
const index1 = i;
|
|
24
|
+
if (index0 !== index1)
|
|
25
|
+
this.#emit("reorder", item, index1);
|
|
26
|
+
});
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
sort(compareFn) {
|
|
30
|
+
const result = super.sort(compareFn);
|
|
31
|
+
this.forEach((item, i) => this.#emit("reorder", item, i));
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
shift() {
|
|
35
|
+
const length0 = this.length;
|
|
36
|
+
const result = super.shift();
|
|
37
|
+
if (length0 > 0)
|
|
38
|
+
this.#emit("delete", result, 0);
|
|
39
|
+
this.forEach((item, i) => this.#emit("reorder", item, i));
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
splice(start, deleteCount = 0, ...items) {
|
|
43
|
+
const deleted = super.splice(start, deleteCount, ...items);
|
|
44
|
+
deleted.forEach((item, i) => this.#emit("delete", item, start + i));
|
|
45
|
+
if ((deleteCount ?? 0) !== (items?.length ?? 0))
|
|
46
|
+
for (let i = start + (items?.length ?? 0); i < this.length; i++)
|
|
47
|
+
this.#emit("reorder", this[i], i);
|
|
48
|
+
items.forEach((item, i) => this.#emit("insert", item, start + i));
|
|
49
|
+
return deleted;
|
|
50
|
+
}
|
|
51
|
+
unshift(...items) {
|
|
52
|
+
const result = super.unshift(...items);
|
|
53
|
+
for (let i = items.length; i < this.length; i++)
|
|
54
|
+
this.#emit("reorder", this[i], i);
|
|
55
|
+
items.forEach((item, i) => this.#emit("insert", item, i));
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
#responders = {
|
|
59
|
+
insert: new Set(),
|
|
60
|
+
delete: new Set(),
|
|
61
|
+
reorder: new Set(),
|
|
62
|
+
};
|
|
63
|
+
#emit(protocol, ...parameters) {
|
|
64
|
+
return [...this.#responders[protocol]].map(responder => responder(...parameters));
|
|
65
|
+
}
|
|
66
|
+
on(protocol, responder) {
|
|
67
|
+
this.#responders[protocol].add(responder);
|
|
68
|
+
}
|
|
69
|
+
off(protocol, responder) {
|
|
70
|
+
this.#responders[protocol].delete(responder);
|
|
71
|
+
}
|
|
72
|
+
responders(protocol) {
|
|
73
|
+
return this.#responders[protocol];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type StartsWith<Prefix extends string = string, Body extends string = string> = `${Prefix}${Body}`;
|
|
2
|
+
export type EndsWith<Suffix extends string = string, Body extends string = string> = `${Body}${Suffix}`;
|
|
3
|
+
export type Concat<StrArr extends readonly string[] = readonly string[], Separator extends string = ""> = StrArr extends readonly [infer S0 extends string, ...infer Rest extends string[]] ? Rest extends [] ? S0 : `${S0}${Separator}${Concat<Rest, Separator>}` : "";
|
package/dist/strings.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type Deleteable<T, K extends keyof T = keyof T> = {
|
|
2
|
+
-readonly [K1 in K]?: T[K1];
|
|
3
|
+
};
|
|
4
|
+
export type PartlyDeleteable<T, K extends keyof T> = {
|
|
5
|
+
[K1 in keyof T as (K1 extends K ? never : K1)]: T[K1];
|
|
6
|
+
} & Deleteable<T, K>;
|
|
7
|
+
export type UndefinedIf<T, Condition extends boolean = boolean> = Condition extends true ? undefined : T;
|
|
8
|
+
export declare function undefinedIf<T, Condition extends boolean = boolean>(condition: Condition, item: () => T): UndefinedIf<T, Condition>;
|
|
9
|
+
export type Prefixed<Prefix extends string, T extends object> = {
|
|
10
|
+
[K in string & keyof T as `${Prefix}${K}`]: T[K];
|
|
11
|
+
};
|
|
12
|
+
export declare function prefixed<Prefix extends string, T extends object>(prefix: Prefix, o: T): Prefixed<Prefix, T>;
|
package/dist/types.js
ADDED
package/package.json
CHANGED
|
@@ -1,23 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-essentials/utils",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
"prebuild:debug": "npm run clean",
|
|
12
|
-
"build": "tsc",
|
|
13
|
-
"build:debug": "tsc -p tsconfig.debug.json",
|
|
14
|
-
"pretest": "npm run build:debug",
|
|
15
|
-
"test": "ava",
|
|
16
|
-
"prepublishOnly": "npm test && npm run build"
|
|
17
|
-
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/**/*"
|
|
10
|
+
],
|
|
18
11
|
"devDependencies": {
|
|
19
12
|
"@ava/typescript": "^6.0.0",
|
|
20
|
-
"@code-essentials/tsconfig": "^1.0",
|
|
13
|
+
"@code-essentials/tsconfig": "^1.0.3",
|
|
21
14
|
"@types/node": "^24.5.2",
|
|
22
15
|
"ava": "^6.4.1",
|
|
23
16
|
"typescript": "^5.9.2"
|
|
@@ -41,5 +34,14 @@
|
|
|
41
34
|
"email": "isaac_valdez@msn.com",
|
|
42
35
|
"url": "https://i12345.github.io"
|
|
43
36
|
},
|
|
44
|
-
"license": "MIT"
|
|
45
|
-
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"scripts": {
|
|
39
|
+
"clean": "rm -rf dist",
|
|
40
|
+
"prebuild": "npm run clean",
|
|
41
|
+
"prebuild:debug": "npm run clean",
|
|
42
|
+
"build": "tsc",
|
|
43
|
+
"build:debug": "tsc -p tsconfig.debug.json",
|
|
44
|
+
"pretest": "npm run build:debug",
|
|
45
|
+
"test": "ava"
|
|
46
|
+
}
|
|
47
|
+
}
|
package/.vscode/launch.json
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"configurations": [
|
|
3
|
-
{
|
|
4
|
-
"name": "test",
|
|
5
|
-
"request": "launch",
|
|
6
|
-
"runtimeArgs": [
|
|
7
|
-
"run-script",
|
|
8
|
-
"test"
|
|
9
|
-
],
|
|
10
|
-
"runtimeExecutable": "pnpm",
|
|
11
|
-
"sourceMaps": true,
|
|
12
|
-
"pauseForSourceMap": true,
|
|
13
|
-
"preLaunchTask": "npm: build:debug",
|
|
14
|
-
"internalConsoleOptions": "neverOpen",
|
|
15
|
-
"skipFiles": [
|
|
16
|
-
"<node_internals>/**"
|
|
17
|
-
],
|
|
18
|
-
"type": "node"
|
|
19
|
-
}
|
|
20
|
-
]
|
|
21
|
-
}
|
package/.vscode/tasks.json
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "2.0.0",
|
|
3
|
-
"tasks": [
|
|
4
|
-
{
|
|
5
|
-
"label": "npm: build:debug",
|
|
6
|
-
"type": "shell",
|
|
7
|
-
"command": "npm",
|
|
8
|
-
"args": [
|
|
9
|
-
"run-script",
|
|
10
|
-
"build:debug",
|
|
11
|
-
],
|
|
12
|
-
"problemMatcher": [
|
|
13
|
-
"$tsc"
|
|
14
|
-
],
|
|
15
|
-
"presentation": {
|
|
16
|
-
"reveal": "silent",
|
|
17
|
-
"close": true,
|
|
18
|
-
},
|
|
19
|
-
"group": "build"
|
|
20
|
-
}
|
|
21
|
-
]
|
|
22
|
-
}
|
package/src/async-variable.ts
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
interface AsyncVariableResultBase<Type> {
|
|
2
|
-
readonly type: Type
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
interface AsyncVariableResultResolved<T> extends AsyncVariableResultBase<"resolved"> {
|
|
6
|
-
readonly value: T
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
interface AsyncVariableResultRejected extends AsyncVariableResultBase<"rejected"> {
|
|
10
|
-
readonly error: any
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type AsyncVariableResult<T> =
|
|
14
|
-
| AsyncVariableResultResolved<T>
|
|
15
|
-
| AsyncVariableResultRejected
|
|
16
|
-
|
|
17
|
-
export class AsyncVariable<T> implements PromiseLike<T> {
|
|
18
|
-
#result: AsyncVariableResult<T> | undefined
|
|
19
|
-
#result_res!: (res: AsyncVariableResult<T>) => void
|
|
20
|
-
#result_p!: Promise<AsyncVariableResult<T>>
|
|
21
|
-
readonly #initialization: Promise<void>
|
|
22
|
-
|
|
23
|
-
get value(): T {
|
|
24
|
-
if (!this.#result)
|
|
25
|
-
throw new Error('incomplete')
|
|
26
|
-
|
|
27
|
-
if (this.#result.type === "rejected")
|
|
28
|
-
throw this.#result.error
|
|
29
|
-
|
|
30
|
-
return this.#result.value
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
set value(value) {
|
|
34
|
-
this.set(value)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
get error() {
|
|
38
|
-
if (!this.#result)
|
|
39
|
-
throw new Error('incomplete')
|
|
40
|
-
|
|
41
|
-
if (this.#result.type === "resolved")
|
|
42
|
-
throw new Error(this.#result.type)
|
|
43
|
-
|
|
44
|
-
return this.#result.error
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
set error(error) {
|
|
48
|
-
this.reject(error)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
get complete() {
|
|
52
|
-
return this.#result !== undefined
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
constructor() {
|
|
56
|
-
this.#initialization = new Promise(initialized =>
|
|
57
|
-
// prevents unhandled rejection
|
|
58
|
-
this.#result_p = new Promise(res => {
|
|
59
|
-
this.#result_res = res
|
|
60
|
-
initialized()
|
|
61
|
-
})
|
|
62
|
-
)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
async init() {
|
|
66
|
-
await this.#initialization
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
async read() {
|
|
70
|
-
await this.#initialization
|
|
71
|
-
await this.#result_p
|
|
72
|
-
return this.value
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined): PromiseLike<TResult1 | TResult2> {
|
|
76
|
-
return this.read().then(onfulfilled, onrejected)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async #complete(throw_if_set = true) {
|
|
80
|
-
await this.#initialization
|
|
81
|
-
if (this.complete) {
|
|
82
|
-
if (throw_if_set)
|
|
83
|
-
throw new Error('already set')
|
|
84
|
-
else
|
|
85
|
-
return false
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return true
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async set(value: T, throw_if_set = true) {
|
|
92
|
-
if (await this.#complete(throw_if_set)) {
|
|
93
|
-
this.#result_res(this.#result = {
|
|
94
|
-
type: "resolved",
|
|
95
|
-
value
|
|
96
|
-
})
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async reject(error: unknown, throw_if_set = true) {
|
|
101
|
-
if (await this.#complete(throw_if_set)) {
|
|
102
|
-
this.#result_res(this.#result = {
|
|
103
|
-
type: "rejected",
|
|
104
|
-
error
|
|
105
|
-
})
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
static performCallback<R = void>(fn: (cb: (err?: unknown, res?: R) => void) => void): AsyncVariable<R> {
|
|
110
|
-
const av = new AsyncVariable<R>()
|
|
111
|
-
|
|
112
|
-
fn(async (err, res) => {
|
|
113
|
-
if (err)
|
|
114
|
-
await av.error(err)
|
|
115
|
-
else
|
|
116
|
-
await av.set(<R>res)
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
return av
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
perform(fn: () => Promise<T>): this {
|
|
123
|
-
fn().then(value => this.set(value)).catch(error => this.reject(error))
|
|
124
|
-
|
|
125
|
-
return this
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
timeout(milliseconds: number): this {
|
|
129
|
-
AsyncVariable.wait(milliseconds).then(() => {
|
|
130
|
-
if (!this.complete)
|
|
131
|
-
this.reject("timeout")
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
return this
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
static perform<T>(fn: () => Promise<T>): AsyncVariable<T> {
|
|
138
|
-
return new AsyncVariable<T>().perform(fn)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
static wait(milliseconds: number) {
|
|
142
|
-
const res = new AsyncVariable<void>()
|
|
143
|
-
setTimeout(() => res.set(), milliseconds)
|
|
144
|
-
return res
|
|
145
|
-
}
|
|
146
|
-
}
|
package/src/index.ts
DELETED
package/src/lock.spec.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import test from "ava"
|
|
2
|
-
import { Lock } from "./lock.js"
|
|
3
|
-
|
|
4
|
-
test('acquire when free', t => {
|
|
5
|
-
const lock = new Lock()
|
|
6
|
-
const context = lock.acquire()
|
|
7
|
-
context.release()
|
|
8
|
-
t.pass()
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
test('fail to acquire when already acquired', t => {
|
|
12
|
-
const lock = new Lock()
|
|
13
|
-
lock.acquire()
|
|
14
|
-
t.throws(() => lock.acquire(), { message: Lock.ERR_ACQUIRED })
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
test('disposable release', t => {
|
|
18
|
-
const lock = new Lock()
|
|
19
|
-
|
|
20
|
-
function acquire(pass: boolean) {
|
|
21
|
-
if (pass)
|
|
22
|
-
t.notThrows(() => lock.acquire())
|
|
23
|
-
else
|
|
24
|
-
t.throws(() => lock.acquire(), { message: Lock.ERR_ACQUIRED })
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function acquire_0() {
|
|
28
|
-
using _context1 = lock.acquire()
|
|
29
|
-
acquire(false)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function acquire_1() {
|
|
33
|
-
acquire(true)
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
acquire_0()
|
|
37
|
-
acquire_1()
|
|
38
|
-
})
|
package/src/lock.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
export class Lock<Of = void> {
|
|
2
|
-
#isAcquired = false
|
|
3
|
-
|
|
4
|
-
get isAcquired() {
|
|
5
|
-
return this.#isAcquired
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
acquire(of: Of): LockContext<Of> {
|
|
9
|
-
if (this.#isAcquired)
|
|
10
|
-
throw new Error(Lock.ERR_ACQUIRED)
|
|
11
|
-
this.#isAcquired = true
|
|
12
|
-
return new LockContext(this, of, this.release.bind(this))
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
protected release(_context: LockContext<Of>) {
|
|
16
|
-
if (!this.isAcquired)
|
|
17
|
-
throw new Error()
|
|
18
|
-
|
|
19
|
-
this.#isAcquired = false
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
static readonly ERR_ACQUIRED = 'lock currently acquired'
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export class LockContext<Of> implements Disposable {
|
|
26
|
-
readonly #release: (conext: LockContext<Of>) => void
|
|
27
|
-
#isAcquired = true
|
|
28
|
-
|
|
29
|
-
constructor(
|
|
30
|
-
readonly lock: Lock<Of>,
|
|
31
|
-
readonly of: Of,
|
|
32
|
-
release: (conext: LockContext<Of>) => void
|
|
33
|
-
) {
|
|
34
|
-
this.#release = release
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
release() {
|
|
38
|
-
if (!this.#isAcquired)
|
|
39
|
-
throw new Error(LockContext.ERR_LOCK_RELEASED)
|
|
40
|
-
|
|
41
|
-
this.#isAcquired = false
|
|
42
|
-
this.#release(this)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
[Symbol.dispose]() {
|
|
46
|
-
this.release()
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
static readonly ERR_LOCK_RELEASED = "lock context already released"
|
|
50
|
-
}
|
package/src/object.spec.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import test from "ava"
|
|
2
|
-
import { replaceProperty } from "./object.js"
|
|
3
|
-
|
|
4
|
-
test("replace", t => {
|
|
5
|
-
interface A {
|
|
6
|
-
i: number
|
|
7
|
-
b: B
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface B {
|
|
11
|
-
j: number
|
|
12
|
-
c: C
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface C {
|
|
16
|
-
k: number
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const a0: A = {
|
|
20
|
-
i: 0,
|
|
21
|
-
b: {
|
|
22
|
-
j: 0,
|
|
23
|
-
c: {
|
|
24
|
-
k: 0
|
|
25
|
-
},
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
t.is(a0.i, 0)
|
|
30
|
-
|
|
31
|
-
const a1 = replaceProperty(a0, ["i"], 1)
|
|
32
|
-
|
|
33
|
-
t.is(a0.i, 0)
|
|
34
|
-
t.is(a1.i, 1)
|
|
35
|
-
|
|
36
|
-
a0.b.j++
|
|
37
|
-
t.is(a0.b.j, 1)
|
|
38
|
-
t.is(a1.b.j, 1)
|
|
39
|
-
})
|
package/src/object.ts
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
export type Values<T extends object> = T[keyof T]
|
|
2
|
-
|
|
3
|
-
export type PropertyPath<T> =
|
|
4
|
-
| []
|
|
5
|
-
| T extends object ? Values<{
|
|
6
|
-
[K in keyof T]: [K] | [K, Values<PropertyPath<T[K]>>]
|
|
7
|
-
}> : []
|
|
8
|
-
|
|
9
|
-
export type PropertyType<T, Property extends PropertyPath<T>> = PropertyType_<T, Property>
|
|
10
|
-
type PropertyType_<T, Property extends any[], Constructed extends any[] = []> =
|
|
11
|
-
(Property & Constructed) extends never ?
|
|
12
|
-
Values<{
|
|
13
|
-
[K in keyof T as Property extends [...Constructed, K, ...any[]] ? K : never]:
|
|
14
|
-
PropertyType_<T[K], Property, [...Constructed, K]>
|
|
15
|
-
}> :
|
|
16
|
-
T
|
|
17
|
-
|
|
18
|
-
// export type PropertyType<T, Property extends PropertyPath<T> & PropertyKey[]> = PropertyType_<T, Property>
|
|
19
|
-
// type PropertyType_<T, Property extends PropertyKey[], Constructed extends PropertyKey[] = []> =
|
|
20
|
-
// (Property & Constructed) extends never ?
|
|
21
|
-
// Values<{
|
|
22
|
-
// [K in keyof T as Property extends [...Constructed, K, ...PropertyKey[]] ? K : never]:
|
|
23
|
-
// PropertyType_<T[K], Property, [...Constructed, K]>
|
|
24
|
-
// }> :
|
|
25
|
-
// T
|
|
26
|
-
|
|
27
|
-
// type A = {
|
|
28
|
-
// a: {
|
|
29
|
-
// a: 10,
|
|
30
|
-
// b: 1
|
|
31
|
-
// c: 2
|
|
32
|
-
// }
|
|
33
|
-
// b: {
|
|
34
|
-
// a: {
|
|
35
|
-
// c: 1
|
|
36
|
-
// }
|
|
37
|
-
// }
|
|
38
|
-
// }
|
|
39
|
-
|
|
40
|
-
// type a_path = PropertyPath<A>
|
|
41
|
-
// const ac = ["a", "c"] satisfies a_path
|
|
42
|
-
// // type a1 = (typeof ac) extends ["a", "c", ...PropertyKey[]] ? true : false
|
|
43
|
-
// type ac_type = PropertyType_<A, typeof ac>
|
|
44
|
-
|
|
45
|
-
export function replaceProperty<T, Property extends PropertyPath<T> = PropertyPath<T>>(
|
|
46
|
-
obj: T,
|
|
47
|
-
property: Property,
|
|
48
|
-
value: any
|
|
49
|
-
): T {
|
|
50
|
-
if (property.length === 0)
|
|
51
|
-
return <T>((<any>value) ?? obj)
|
|
52
|
-
|
|
53
|
-
if (typeof obj !== 'object')
|
|
54
|
-
throw new Error()
|
|
55
|
-
|
|
56
|
-
const prototype = Object.create(obj)
|
|
57
|
-
const property0 = property[0]!
|
|
58
|
-
prototype[property0] = replaceProperty<any>((<any>obj)[property0]!, <any>property.slice(1), value)
|
|
59
|
-
return <T>prototype
|
|
60
|
-
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { ObservableList, ObservableListProtocols } from "./observable-list.js"
|
|
2
|
-
import test from "ava"
|
|
3
|
-
|
|
4
|
-
test("insert", t => {
|
|
5
|
-
const list = new ObservableList<string>()
|
|
6
|
-
|
|
7
|
-
const words = ["keyboard", "mouse", "display"]
|
|
8
|
-
t.plan(words.length)
|
|
9
|
-
|
|
10
|
-
let itemInserted = ""
|
|
11
|
-
const responder: ObservableListProtocols<string>["insert"] = (item) => t.is(item, itemInserted)
|
|
12
|
-
|
|
13
|
-
list.on("insert", responder)
|
|
14
|
-
|
|
15
|
-
list.push(itemInserted = words[0]!)
|
|
16
|
-
list.push(itemInserted = words[1]!)
|
|
17
|
-
|
|
18
|
-
list.off("insert", responder)
|
|
19
|
-
|
|
20
|
-
list.push("unrelated")
|
|
21
|
-
|
|
22
|
-
list.on("insert", responder)
|
|
23
|
-
|
|
24
|
-
list.push(itemInserted = words[2]!)
|
|
25
|
-
})
|
package/src/observable-list.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
export interface ObservableListProtocols<T> {
|
|
2
|
-
insert(item: T, index: number): void
|
|
3
|
-
delete(item: T, index: number): void
|
|
4
|
-
reorder(item: T, index1: number): void
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export class ObservableList<T> extends Array<T> {
|
|
8
|
-
constructor(length: number)
|
|
9
|
-
constructor(...items: T[])
|
|
10
|
-
constructor(...itemsOrArrayLength: any[]) {
|
|
11
|
-
super(...itemsOrArrayLength)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
override push(...items: T[]): number {
|
|
15
|
-
const length0 = this.length
|
|
16
|
-
const result = super.push(...items)
|
|
17
|
-
|
|
18
|
-
items.forEach((item, i) => this.#emit("insert", item, length0 + i))
|
|
19
|
-
|
|
20
|
-
return result
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
override pop(): T | undefined {
|
|
24
|
-
const index = this.length - 1
|
|
25
|
-
const result = super.pop()
|
|
26
|
-
|
|
27
|
-
if (index >= 0)
|
|
28
|
-
this.#emit("delete", result!, index)
|
|
29
|
-
|
|
30
|
-
return result
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
override reverse(): T[] {
|
|
34
|
-
const final_index = this.length - 1
|
|
35
|
-
const result = super.reverse()
|
|
36
|
-
|
|
37
|
-
this.forEach((item, i) => {
|
|
38
|
-
const index0 = final_index - i
|
|
39
|
-
const index1 = i
|
|
40
|
-
|
|
41
|
-
if (index0 !== index1)
|
|
42
|
-
this.#emit("reorder", item, index1)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
return result
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
override sort(compareFn?: ((a: T, b: T) => number) | undefined): this {
|
|
49
|
-
const result = super.sort(compareFn)
|
|
50
|
-
|
|
51
|
-
this.forEach((item, i) => this.#emit("reorder", item, i))
|
|
52
|
-
|
|
53
|
-
return result
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
override shift(): T | undefined {
|
|
57
|
-
const length0 = this.length
|
|
58
|
-
const result = super.shift()
|
|
59
|
-
|
|
60
|
-
if (length0 > 0)
|
|
61
|
-
this.#emit("delete", result!, 0)
|
|
62
|
-
|
|
63
|
-
this.forEach((item, i) => this.#emit("reorder", item, i))
|
|
64
|
-
|
|
65
|
-
return result
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
override splice(start: number, deleteCount = 0, ...items: T[]): T[] {
|
|
69
|
-
const deleted = super.splice(start, deleteCount, ...items)
|
|
70
|
-
|
|
71
|
-
deleted.forEach((item, i) => this.#emit("delete", item, start + i))
|
|
72
|
-
|
|
73
|
-
if ((deleteCount ?? 0) !== (items?.length ?? 0))
|
|
74
|
-
for (let i = start + (items?.length ?? 0); i < this.length; i++)
|
|
75
|
-
this.#emit("reorder", this[i]!, i)
|
|
76
|
-
|
|
77
|
-
items.forEach((item, i) => this.#emit("insert", item, start + i))
|
|
78
|
-
|
|
79
|
-
return deleted
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
override unshift(...items: T[]): number {
|
|
83
|
-
const result = super.unshift(...items)
|
|
84
|
-
|
|
85
|
-
for (let i = items.length; i < this.length; i++)
|
|
86
|
-
this.#emit("reorder", this[i]!, i)
|
|
87
|
-
|
|
88
|
-
items.forEach((item, i) => this.#emit("insert", item, i))
|
|
89
|
-
|
|
90
|
-
return result
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
#responders: { [Protocol in keyof ObservableListProtocols<T>]: Set<ObservableListProtocols<T>[Protocol]> } = {
|
|
94
|
-
insert: new Set(),
|
|
95
|
-
delete: new Set(),
|
|
96
|
-
reorder: new Set(),
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
#emit<Protocol extends keyof ObservableListProtocols<T>>(protocol: Protocol, ...parameters: Parameters<ObservableListProtocols<T>[Protocol]>): ReturnType<ObservableListProtocols<T>[Protocol]>[] {
|
|
100
|
-
return [...this.#responders[protocol]].map(responder => (<any>responder)(...parameters))
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
on<Protocol extends keyof ObservableListProtocols<T>>(protocol: Protocol, responder: ObservableListProtocols<T>[Protocol]) {
|
|
104
|
-
this.#responders[protocol].add(responder)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
off<Protocol extends keyof ObservableListProtocols<T>>(protocol: Protocol, responder: ObservableListProtocols<T>[Protocol]) {
|
|
108
|
-
this.#responders[protocol].delete(responder)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
responders<Protocol extends keyof ObservableListProtocols<T>>(protocol: Protocol) {
|
|
112
|
-
return this.#responders[protocol]
|
|
113
|
-
}
|
|
114
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
export type Deleteable<T, K extends keyof T = keyof T> = {
|
|
2
|
-
-readonly [K1 in K]?: T[K1]
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export type PartlyDeleteable<T, K extends keyof T> = {
|
|
6
|
-
[K1 in keyof T as (K1 extends K ? never : K1)]: T[K1]
|
|
7
|
-
} & Deleteable<T, K>
|
|
8
|
-
|
|
9
|
-
export type UndefinedIf<T, Condition extends boolean = boolean> = Condition extends true ? undefined : T
|
|
10
|
-
|
|
11
|
-
export function undefinedIf<T, Condition extends boolean = boolean>(condition: Condition, item: () => T): UndefinedIf<T, Condition> {
|
|
12
|
-
return <UndefinedIf<T, Condition>>(condition ? undefined : item())
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export type Prefixed<Prefix extends string, T extends object> = {
|
|
16
|
-
[K in string & keyof T as `${Prefix}${K}`]: T[K]
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function prefixed<Prefix extends string, T extends object>(prefix: Prefix, o: T): Prefixed<Prefix, T> {
|
|
20
|
-
return <Prefixed<Prefix, T>>Object.fromEntries(Object.entries(o).map(([k, v]) => [`${prefix}${k}`, v] as const))
|
|
21
|
-
}
|
package/tsconfig.debug.json
DELETED