dropcap 1.0.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/dist/types/types.d.ts +7 -0
- package/dist/types/types.js +0 -0
- package/dist/utils/utils-color-hash.d.ts +4 -0
- package/dist/utils/utils-color-hash.js +42 -0
- package/dist/utils/utils-create-log.d.ts +9 -0
- package/dist/utils/utils-create-log.js +54 -0
- package/dist/utils/utils-ensure-array.d.ts +3 -0
- package/dist/utils/utils-ensure-array.js +7 -0
- package/dist/utils/utils-is.d.ts +33 -0
- package/dist/utils/utils-is.js +33 -0
- package/dist/utils/utils-queue.d.ts +20 -0
- package/dist/utils/utils-queue.js +88 -0
- package/dist/utils/utils-safe.d.ts +4 -0
- package/dist/utils/utils-safe.js +54 -0
- package/dist/utils/utils-unique.d.ts +3 -0
- package/dist/utils/utils-unique.js +14 -0
- package/dist/utils/utils-unit.d.ts +14 -0
- package/dist/utils/utils-unit.js +84 -0
- package/dist/utils/utils-wait.d.ts +3 -0
- package/dist/utils/utils-wait.js +7 -0
- package/dist/utils/utils.d.ts +10 -0
- package/dist/utils/utils.js +210 -0
- package/package.json +30 -0
- package/src/types/types.ts +5 -0
- package/src/utils/utils-color-hash.ts +55 -0
- package/src/utils/utils-create-log.ts +16 -0
- package/src/utils/utils-ensure-array.ts +3 -0
- package/src/utils/utils-is.ts +32 -0
- package/src/utils/utils-queue.ts +57 -0
- package/src/utils/utils-safe.ts +23 -0
- package/src/utils/utils-unique.ts +11 -0
- package/src/utils/utils-unit.ts +35 -0
- package/src/utils/utils-wait.ts +3 -0
- package/src/utils/utils.ts +13 -0
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// src/utils/utils-color-hash.ts
|
|
2
|
+
function colorHash(str) {
|
|
3
|
+
let hash = 5381;
|
|
4
|
+
for (let i = 0; i < str.length; i++) {
|
|
5
|
+
hash = hash * 33 ^ str.charCodeAt(i);
|
|
6
|
+
}
|
|
7
|
+
hash >>>= 0;
|
|
8
|
+
const hue = Math.floor(hash * 0.618033988749895 % 1 * 360);
|
|
9
|
+
const sat = 70;
|
|
10
|
+
let light = 50;
|
|
11
|
+
for (let i = 0; i < 20; i++) {
|
|
12
|
+
const rgb = hsl2rgb(hue, sat, light);
|
|
13
|
+
const l = lum(rgb);
|
|
14
|
+
const cW = contrast(1, l);
|
|
15
|
+
const cB = contrast(0, l);
|
|
16
|
+
if (cW >= 4.5 && cB >= 4.5) break;
|
|
17
|
+
light += cW < cB ? -5 : 5;
|
|
18
|
+
}
|
|
19
|
+
const hex = hsl2rgb(hue, sat, light).map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
20
|
+
return `#${hex}`;
|
|
21
|
+
}
|
|
22
|
+
function hsl2rgb(hh, ss, ll) {
|
|
23
|
+
ss /= 100;
|
|
24
|
+
ll /= 100;
|
|
25
|
+
const k = (n) => (n + hh / 30) % 12;
|
|
26
|
+
const a = ss * Math.min(ll, 1 - ll);
|
|
27
|
+
const f = (n) => ll - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
|
|
28
|
+
return [f(0), f(8), f(4)].map((v) => Math.round(v * 255));
|
|
29
|
+
}
|
|
30
|
+
function lum([r, g, b]) {
|
|
31
|
+
const c = (x) => {
|
|
32
|
+
x /= 255;
|
|
33
|
+
return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
|
|
34
|
+
};
|
|
35
|
+
return 0.2126 * c(r) + 0.7152 * c(g) + 0.0722 * c(b);
|
|
36
|
+
}
|
|
37
|
+
function contrast(l1, l2) {
|
|
38
|
+
return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
colorHash
|
|
42
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/utils/utils-color-hash.ts
|
|
2
|
+
function colorHash(str) {
|
|
3
|
+
let hash = 5381;
|
|
4
|
+
for (let i = 0; i < str.length; i++) {
|
|
5
|
+
hash = hash * 33 ^ str.charCodeAt(i);
|
|
6
|
+
}
|
|
7
|
+
hash >>>= 0;
|
|
8
|
+
const hue = Math.floor(hash * 0.618033988749895 % 1 * 360);
|
|
9
|
+
const sat = 70;
|
|
10
|
+
let light = 50;
|
|
11
|
+
for (let i = 0; i < 20; i++) {
|
|
12
|
+
const rgb = hsl2rgb(hue, sat, light);
|
|
13
|
+
const l = lum(rgb);
|
|
14
|
+
const cW = contrast(1, l);
|
|
15
|
+
const cB = contrast(0, l);
|
|
16
|
+
if (cW >= 4.5 && cB >= 4.5) break;
|
|
17
|
+
light += cW < cB ? -5 : 5;
|
|
18
|
+
}
|
|
19
|
+
const hex = hsl2rgb(hue, sat, light).map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
20
|
+
return `#${hex}`;
|
|
21
|
+
}
|
|
22
|
+
function hsl2rgb(hh, ss, ll) {
|
|
23
|
+
ss /= 100;
|
|
24
|
+
ll /= 100;
|
|
25
|
+
const k = (n) => (n + hh / 30) % 12;
|
|
26
|
+
const a = ss * Math.min(ll, 1 - ll);
|
|
27
|
+
const f = (n) => ll - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
|
|
28
|
+
return [f(0), f(8), f(4)].map((v) => Math.round(v * 255));
|
|
29
|
+
}
|
|
30
|
+
function lum([r, g, b]) {
|
|
31
|
+
const c = (x) => {
|
|
32
|
+
x /= 255;
|
|
33
|
+
return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
|
|
34
|
+
};
|
|
35
|
+
return 0.2126 * c(r) + 0.7152 * c(g) + 0.0722 * c(b);
|
|
36
|
+
}
|
|
37
|
+
function contrast(l1, l2) {
|
|
38
|
+
return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/utils/utils-create-log.ts
|
|
42
|
+
function createLog(name) {
|
|
43
|
+
const color = colorHash(name);
|
|
44
|
+
const log = print.bind(null, "log", name, color);
|
|
45
|
+
log.warn = print.bind(null, "warn", name, color);
|
|
46
|
+
log.error = print.bind(null, "error", name, color);
|
|
47
|
+
return log;
|
|
48
|
+
}
|
|
49
|
+
function print(type, name, color, ...args) {
|
|
50
|
+
console[type](`%c[${name}]`, `color: ${color}`, ...args);
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
createLog
|
|
54
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Fn, Obj, Arr } from '../types/types.js';
|
|
2
|
+
|
|
3
|
+
declare const is: {
|
|
4
|
+
null: (v: unknown) => v is null;
|
|
5
|
+
undefined: (v: unknown) => v is undefined;
|
|
6
|
+
boolean: (v: unknown) => v is boolean;
|
|
7
|
+
number: (v: unknown) => v is number;
|
|
8
|
+
string: (v: unknown) => v is string;
|
|
9
|
+
symbol: (v: unknown) => v is symbol;
|
|
10
|
+
function: (v: unknown) => v is Fn;
|
|
11
|
+
object: (v: unknown) => v is Obj;
|
|
12
|
+
array: (v: unknown) => v is Arr;
|
|
13
|
+
set: (v: unknown) => v is Set<any>;
|
|
14
|
+
map: (v: unknown) => v is Map<any, any>;
|
|
15
|
+
blob: (v: unknown) => v is Blob;
|
|
16
|
+
date: (v: unknown) => v is Date;
|
|
17
|
+
error: (v: unknown) => v is Error;
|
|
18
|
+
regex: (v: unknown) => v is RegExp;
|
|
19
|
+
promise: (v: unknown) => v is Promise<any>;
|
|
20
|
+
uint8Array: (v: unknown) => v is Uint8Array<ArrayBufferLike>;
|
|
21
|
+
uint16Array: (v: unknown) => v is Uint16Array<ArrayBufferLike>;
|
|
22
|
+
uint32Array: (v: unknown) => v is Uint32Array<ArrayBufferLike>;
|
|
23
|
+
nan: (v: unknown) => boolean;
|
|
24
|
+
numeric: (v: unknown) => boolean;
|
|
25
|
+
integer: (v: unknown) => v is number;
|
|
26
|
+
absent: (v: unknown) => v is null | undefined;
|
|
27
|
+
present: <T>(v: T) => v is NonNullable<T>;
|
|
28
|
+
primitive: (v: unknown) => boolean;
|
|
29
|
+
collection: (v: unknown) => v is Obj | Arr;
|
|
30
|
+
compound: (v: unknown) => v is object;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export { is };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/utils/utils-is.ts
|
|
2
|
+
var is = {
|
|
3
|
+
null: (v) => v === null,
|
|
4
|
+
undefined: (v) => v === void 0,
|
|
5
|
+
boolean: (v) => typeof v === "boolean",
|
|
6
|
+
number: (v) => typeof v === "number",
|
|
7
|
+
string: (v) => typeof v === "string",
|
|
8
|
+
symbol: (v) => typeof v === "symbol",
|
|
9
|
+
function: (v) => typeof v === "function",
|
|
10
|
+
object: (v) => Object.prototype.toString.call(v) === "[object Object]",
|
|
11
|
+
array: (v) => Array.isArray(v),
|
|
12
|
+
set: (v) => v instanceof Set,
|
|
13
|
+
map: (v) => v instanceof Map,
|
|
14
|
+
blob: (v) => v instanceof Blob,
|
|
15
|
+
date: (v) => v instanceof Date,
|
|
16
|
+
error: (v) => v instanceof Error,
|
|
17
|
+
regex: (v) => v instanceof RegExp,
|
|
18
|
+
promise: (v) => v instanceof Promise,
|
|
19
|
+
uint8Array: (v) => v instanceof Uint8Array,
|
|
20
|
+
uint16Array: (v) => v instanceof Uint16Array,
|
|
21
|
+
uint32Array: (v) => v instanceof Uint32Array,
|
|
22
|
+
nan: (v) => Number.isNaN(v),
|
|
23
|
+
numeric: (v) => !is.nan(Number(v)),
|
|
24
|
+
integer: (v) => Number.isInteger(v),
|
|
25
|
+
absent: (v) => v === null || v === void 0,
|
|
26
|
+
present: (v) => !is.absent(v),
|
|
27
|
+
primitive: (v) => v !== Object(v),
|
|
28
|
+
collection: (v) => is.array(v) || is.object(v),
|
|
29
|
+
compound: (v) => v !== null && typeof v === "object"
|
|
30
|
+
};
|
|
31
|
+
export {
|
|
32
|
+
is
|
|
33
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AsyncFn } from '../types/types.js';
|
|
2
|
+
|
|
3
|
+
type TaskFn<T> = () => Promise<T>;
|
|
4
|
+
type Task<T = any> = {
|
|
5
|
+
fn: TaskFn<T>;
|
|
6
|
+
result$: PromiseWithResolvers<T>;
|
|
7
|
+
};
|
|
8
|
+
declare class Queue {
|
|
9
|
+
name: string | null;
|
|
10
|
+
tasks: Task[];
|
|
11
|
+
private running;
|
|
12
|
+
constructor(name?: string | null);
|
|
13
|
+
add<T>(fn: TaskFn<T>): Promise<T>;
|
|
14
|
+
wrap<T extends AsyncFn>(fn: T, thisValue?: unknown): (...args: Parameters<T>) => Promise<any>;
|
|
15
|
+
wait(): Promise<void>;
|
|
16
|
+
isEmpty(): boolean;
|
|
17
|
+
private start;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { Queue };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// src/utils/utils-is.ts
|
|
2
|
+
var is = {
|
|
3
|
+
null: (v) => v === null,
|
|
4
|
+
undefined: (v) => v === void 0,
|
|
5
|
+
boolean: (v) => typeof v === "boolean",
|
|
6
|
+
number: (v) => typeof v === "number",
|
|
7
|
+
string: (v) => typeof v === "string",
|
|
8
|
+
symbol: (v) => typeof v === "symbol",
|
|
9
|
+
function: (v) => typeof v === "function",
|
|
10
|
+
object: (v) => Object.prototype.toString.call(v) === "[object Object]",
|
|
11
|
+
array: (v) => Array.isArray(v),
|
|
12
|
+
set: (v) => v instanceof Set,
|
|
13
|
+
map: (v) => v instanceof Map,
|
|
14
|
+
blob: (v) => v instanceof Blob,
|
|
15
|
+
date: (v) => v instanceof Date,
|
|
16
|
+
error: (v) => v instanceof Error,
|
|
17
|
+
regex: (v) => v instanceof RegExp,
|
|
18
|
+
promise: (v) => v instanceof Promise,
|
|
19
|
+
uint8Array: (v) => v instanceof Uint8Array,
|
|
20
|
+
uint16Array: (v) => v instanceof Uint16Array,
|
|
21
|
+
uint32Array: (v) => v instanceof Uint32Array,
|
|
22
|
+
nan: (v) => Number.isNaN(v),
|
|
23
|
+
numeric: (v) => !is.nan(Number(v)),
|
|
24
|
+
integer: (v) => Number.isInteger(v),
|
|
25
|
+
absent: (v) => v === null || v === void 0,
|
|
26
|
+
present: (v) => !is.absent(v),
|
|
27
|
+
primitive: (v) => v !== Object(v),
|
|
28
|
+
collection: (v) => is.array(v) || is.object(v),
|
|
29
|
+
compound: (v) => v !== null && typeof v === "object"
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/utils/utils-safe.ts
|
|
33
|
+
async function safe(effect) {
|
|
34
|
+
try {
|
|
35
|
+
const result = is.function(effect) ? await effect() : await effect;
|
|
36
|
+
return [result, null];
|
|
37
|
+
} catch (e) {
|
|
38
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
39
|
+
return [null, error];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// src/utils/utils-queue.ts
|
|
44
|
+
var Queue = class {
|
|
45
|
+
name;
|
|
46
|
+
tasks = [];
|
|
47
|
+
running = false;
|
|
48
|
+
constructor(name = null) {
|
|
49
|
+
this.name = name;
|
|
50
|
+
}
|
|
51
|
+
async add(fn) {
|
|
52
|
+
const task = { fn, result$: Promise.withResolvers() };
|
|
53
|
+
this.tasks.push(task);
|
|
54
|
+
this.start();
|
|
55
|
+
return await task.result$.promise;
|
|
56
|
+
}
|
|
57
|
+
wrap(fn, thisValue = null) {
|
|
58
|
+
return async (...args) => {
|
|
59
|
+
return await this.add(() => fn.call(thisValue, ...args));
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
async wait() {
|
|
63
|
+
const lastTask = this.tasks.at(-1);
|
|
64
|
+
if (lastTask) await safe(lastTask.result$.promise);
|
|
65
|
+
}
|
|
66
|
+
isEmpty() {
|
|
67
|
+
return this.tasks.length === 0;
|
|
68
|
+
}
|
|
69
|
+
async start() {
|
|
70
|
+
if (this.running) return;
|
|
71
|
+
if (this.isEmpty()) return;
|
|
72
|
+
this.running = true;
|
|
73
|
+
while (this.tasks.length > 0) {
|
|
74
|
+
const task = this.tasks[0];
|
|
75
|
+
const [result, error] = await safe(task.fn);
|
|
76
|
+
this.tasks.shift();
|
|
77
|
+
if (error) {
|
|
78
|
+
task.result$.reject(error);
|
|
79
|
+
} else {
|
|
80
|
+
task.result$.resolve(result);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
this.running = false;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
export {
|
|
87
|
+
Queue
|
|
88
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/utils/utils-is.ts
|
|
2
|
+
var is = {
|
|
3
|
+
null: (v) => v === null,
|
|
4
|
+
undefined: (v) => v === void 0,
|
|
5
|
+
boolean: (v) => typeof v === "boolean",
|
|
6
|
+
number: (v) => typeof v === "number",
|
|
7
|
+
string: (v) => typeof v === "string",
|
|
8
|
+
symbol: (v) => typeof v === "symbol",
|
|
9
|
+
function: (v) => typeof v === "function",
|
|
10
|
+
object: (v) => Object.prototype.toString.call(v) === "[object Object]",
|
|
11
|
+
array: (v) => Array.isArray(v),
|
|
12
|
+
set: (v) => v instanceof Set,
|
|
13
|
+
map: (v) => v instanceof Map,
|
|
14
|
+
blob: (v) => v instanceof Blob,
|
|
15
|
+
date: (v) => v instanceof Date,
|
|
16
|
+
error: (v) => v instanceof Error,
|
|
17
|
+
regex: (v) => v instanceof RegExp,
|
|
18
|
+
promise: (v) => v instanceof Promise,
|
|
19
|
+
uint8Array: (v) => v instanceof Uint8Array,
|
|
20
|
+
uint16Array: (v) => v instanceof Uint16Array,
|
|
21
|
+
uint32Array: (v) => v instanceof Uint32Array,
|
|
22
|
+
nan: (v) => Number.isNaN(v),
|
|
23
|
+
numeric: (v) => !is.nan(Number(v)),
|
|
24
|
+
integer: (v) => Number.isInteger(v),
|
|
25
|
+
absent: (v) => v === null || v === void 0,
|
|
26
|
+
present: (v) => !is.absent(v),
|
|
27
|
+
primitive: (v) => v !== Object(v),
|
|
28
|
+
collection: (v) => is.array(v) || is.object(v),
|
|
29
|
+
compound: (v) => v !== null && typeof v === "object"
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/utils/utils-safe.ts
|
|
33
|
+
async function safe(effect) {
|
|
34
|
+
try {
|
|
35
|
+
const result = is.function(effect) ? await effect() : await effect;
|
|
36
|
+
return [result, null];
|
|
37
|
+
} catch (e) {
|
|
38
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
39
|
+
return [null, error];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function safeSync(effect) {
|
|
43
|
+
try {
|
|
44
|
+
const result = effect();
|
|
45
|
+
return [result, null];
|
|
46
|
+
} catch (e) {
|
|
47
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
48
|
+
return [null, error];
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
safe,
|
|
53
|
+
safeSync
|
|
54
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/utils/utils-unique.ts
|
|
2
|
+
function unique(items, keyFn) {
|
|
3
|
+
if (!keyFn) return [...new Set(items)];
|
|
4
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5
|
+
return items.filter((item) => {
|
|
6
|
+
const key = keyFn(item);
|
|
7
|
+
if (seen.has(key)) return false;
|
|
8
|
+
seen.add(key);
|
|
9
|
+
return true;
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
unique
|
|
14
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Log } from './utils-create-log.js';
|
|
2
|
+
import { Cls } from '../types/types.js';
|
|
3
|
+
|
|
4
|
+
declare class Unit<TRoot = unknown> {
|
|
5
|
+
#private;
|
|
6
|
+
$: TRoot;
|
|
7
|
+
log: Log;
|
|
8
|
+
constructor(parent?: Unit<TRoot> | null);
|
|
9
|
+
closest<T extends Unit<TRoot>>(Ancestor: Cls<T>): T | null;
|
|
10
|
+
never(message?: string): Error;
|
|
11
|
+
Error(message?: string): Error;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export { Unit };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// src/utils/utils-color-hash.ts
|
|
2
|
+
function colorHash(str) {
|
|
3
|
+
let hash = 5381;
|
|
4
|
+
for (let i = 0; i < str.length; i++) {
|
|
5
|
+
hash = hash * 33 ^ str.charCodeAt(i);
|
|
6
|
+
}
|
|
7
|
+
hash >>>= 0;
|
|
8
|
+
const hue = Math.floor(hash * 0.618033988749895 % 1 * 360);
|
|
9
|
+
const sat = 70;
|
|
10
|
+
let light = 50;
|
|
11
|
+
for (let i = 0; i < 20; i++) {
|
|
12
|
+
const rgb = hsl2rgb(hue, sat, light);
|
|
13
|
+
const l = lum(rgb);
|
|
14
|
+
const cW = contrast(1, l);
|
|
15
|
+
const cB = contrast(0, l);
|
|
16
|
+
if (cW >= 4.5 && cB >= 4.5) break;
|
|
17
|
+
light += cW < cB ? -5 : 5;
|
|
18
|
+
}
|
|
19
|
+
const hex = hsl2rgb(hue, sat, light).map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
20
|
+
return `#${hex}`;
|
|
21
|
+
}
|
|
22
|
+
function hsl2rgb(hh, ss, ll) {
|
|
23
|
+
ss /= 100;
|
|
24
|
+
ll /= 100;
|
|
25
|
+
const k = (n) => (n + hh / 30) % 12;
|
|
26
|
+
const a = ss * Math.min(ll, 1 - ll);
|
|
27
|
+
const f = (n) => ll - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
|
|
28
|
+
return [f(0), f(8), f(4)].map((v) => Math.round(v * 255));
|
|
29
|
+
}
|
|
30
|
+
function lum([r, g, b]) {
|
|
31
|
+
const c = (x) => {
|
|
32
|
+
x /= 255;
|
|
33
|
+
return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
|
|
34
|
+
};
|
|
35
|
+
return 0.2126 * c(r) + 0.7152 * c(g) + 0.0722 * c(b);
|
|
36
|
+
}
|
|
37
|
+
function contrast(l1, l2) {
|
|
38
|
+
return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/utils/utils-create-log.ts
|
|
42
|
+
function createLog(name) {
|
|
43
|
+
const color = colorHash(name);
|
|
44
|
+
const log = print.bind(null, "log", name, color);
|
|
45
|
+
log.warn = print.bind(null, "warn", name, color);
|
|
46
|
+
log.error = print.bind(null, "error", name, color);
|
|
47
|
+
return log;
|
|
48
|
+
}
|
|
49
|
+
function print(type, name, color, ...args) {
|
|
50
|
+
console[type](`%c[${name}]`, `color: ${color}`, ...args);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/utils/utils-unit.ts
|
|
54
|
+
var Unit = class {
|
|
55
|
+
$;
|
|
56
|
+
log = createLog(this.constructor.name);
|
|
57
|
+
#parent = null;
|
|
58
|
+
constructor(parent) {
|
|
59
|
+
this.$ = parent?.$ ?? this;
|
|
60
|
+
this.#parent = parent ?? null;
|
|
61
|
+
}
|
|
62
|
+
closest(Ancestor) {
|
|
63
|
+
let cursor = this.#parent;
|
|
64
|
+
while (cursor) {
|
|
65
|
+
if (cursor instanceof Ancestor) return cursor;
|
|
66
|
+
cursor = cursor.#parent;
|
|
67
|
+
}
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
never(message) {
|
|
71
|
+
const details = message ? `: ${message}` : "";
|
|
72
|
+
const error = new Error(`[${this.constructor.name}] This should never happen${details}`);
|
|
73
|
+
Error.captureStackTrace(error, this.never);
|
|
74
|
+
return error;
|
|
75
|
+
}
|
|
76
|
+
Error(message) {
|
|
77
|
+
const error = new Error(`[${this.constructor.name}] ${message}`);
|
|
78
|
+
Error.captureStackTrace(error, this.Error);
|
|
79
|
+
return error;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
export {
|
|
83
|
+
Unit
|
|
84
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { colorHash } from './utils-color-hash.js';
|
|
2
|
+
export { Log, createLog } from './utils-create-log.js';
|
|
3
|
+
export { ensureArray } from './utils-ensure-array.js';
|
|
4
|
+
export { is } from './utils-is.js';
|
|
5
|
+
export { Queue } from './utils-queue.js';
|
|
6
|
+
export { safe, safeSync } from './utils-safe.js';
|
|
7
|
+
export { unique } from './utils-unique.js';
|
|
8
|
+
export { Unit } from './utils-unit.js';
|
|
9
|
+
export { wait } from './utils-wait.js';
|
|
10
|
+
import '../types/types.js';
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// src/utils/utils-color-hash.ts
|
|
2
|
+
function colorHash(str) {
|
|
3
|
+
let hash = 5381;
|
|
4
|
+
for (let i = 0; i < str.length; i++) {
|
|
5
|
+
hash = hash * 33 ^ str.charCodeAt(i);
|
|
6
|
+
}
|
|
7
|
+
hash >>>= 0;
|
|
8
|
+
const hue = Math.floor(hash * 0.618033988749895 % 1 * 360);
|
|
9
|
+
const sat = 70;
|
|
10
|
+
let light = 50;
|
|
11
|
+
for (let i = 0; i < 20; i++) {
|
|
12
|
+
const rgb = hsl2rgb(hue, sat, light);
|
|
13
|
+
const l = lum(rgb);
|
|
14
|
+
const cW = contrast(1, l);
|
|
15
|
+
const cB = contrast(0, l);
|
|
16
|
+
if (cW >= 4.5 && cB >= 4.5) break;
|
|
17
|
+
light += cW < cB ? -5 : 5;
|
|
18
|
+
}
|
|
19
|
+
const hex = hsl2rgb(hue, sat, light).map((v) => v.toString(16).padStart(2, "0")).join("");
|
|
20
|
+
return `#${hex}`;
|
|
21
|
+
}
|
|
22
|
+
function hsl2rgb(hh, ss, ll) {
|
|
23
|
+
ss /= 100;
|
|
24
|
+
ll /= 100;
|
|
25
|
+
const k = (n) => (n + hh / 30) % 12;
|
|
26
|
+
const a = ss * Math.min(ll, 1 - ll);
|
|
27
|
+
const f = (n) => ll - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
|
|
28
|
+
return [f(0), f(8), f(4)].map((v) => Math.round(v * 255));
|
|
29
|
+
}
|
|
30
|
+
function lum([r, g, b]) {
|
|
31
|
+
const c = (x) => {
|
|
32
|
+
x /= 255;
|
|
33
|
+
return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4;
|
|
34
|
+
};
|
|
35
|
+
return 0.2126 * c(r) + 0.7152 * c(g) + 0.0722 * c(b);
|
|
36
|
+
}
|
|
37
|
+
function contrast(l1, l2) {
|
|
38
|
+
return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/utils/utils-create-log.ts
|
|
42
|
+
function createLog(name) {
|
|
43
|
+
const color = colorHash(name);
|
|
44
|
+
const log = print.bind(null, "log", name, color);
|
|
45
|
+
log.warn = print.bind(null, "warn", name, color);
|
|
46
|
+
log.error = print.bind(null, "error", name, color);
|
|
47
|
+
return log;
|
|
48
|
+
}
|
|
49
|
+
function print(type, name, color, ...args) {
|
|
50
|
+
console[type](`%c[${name}]`, `color: ${color}`, ...args);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/utils/utils-ensure-array.ts
|
|
54
|
+
function ensureArray(value) {
|
|
55
|
+
return Array.isArray(value) ? value : [value];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/utils/utils-is.ts
|
|
59
|
+
var is = {
|
|
60
|
+
null: (v) => v === null,
|
|
61
|
+
undefined: (v) => v === void 0,
|
|
62
|
+
boolean: (v) => typeof v === "boolean",
|
|
63
|
+
number: (v) => typeof v === "number",
|
|
64
|
+
string: (v) => typeof v === "string",
|
|
65
|
+
symbol: (v) => typeof v === "symbol",
|
|
66
|
+
function: (v) => typeof v === "function",
|
|
67
|
+
object: (v) => Object.prototype.toString.call(v) === "[object Object]",
|
|
68
|
+
array: (v) => Array.isArray(v),
|
|
69
|
+
set: (v) => v instanceof Set,
|
|
70
|
+
map: (v) => v instanceof Map,
|
|
71
|
+
blob: (v) => v instanceof Blob,
|
|
72
|
+
date: (v) => v instanceof Date,
|
|
73
|
+
error: (v) => v instanceof Error,
|
|
74
|
+
regex: (v) => v instanceof RegExp,
|
|
75
|
+
promise: (v) => v instanceof Promise,
|
|
76
|
+
uint8Array: (v) => v instanceof Uint8Array,
|
|
77
|
+
uint16Array: (v) => v instanceof Uint16Array,
|
|
78
|
+
uint32Array: (v) => v instanceof Uint32Array,
|
|
79
|
+
nan: (v) => Number.isNaN(v),
|
|
80
|
+
numeric: (v) => !is.nan(Number(v)),
|
|
81
|
+
integer: (v) => Number.isInteger(v),
|
|
82
|
+
absent: (v) => v === null || v === void 0,
|
|
83
|
+
present: (v) => !is.absent(v),
|
|
84
|
+
primitive: (v) => v !== Object(v),
|
|
85
|
+
collection: (v) => is.array(v) || is.object(v),
|
|
86
|
+
compound: (v) => v !== null && typeof v === "object"
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// src/utils/utils-safe.ts
|
|
90
|
+
async function safe(effect) {
|
|
91
|
+
try {
|
|
92
|
+
const result = is.function(effect) ? await effect() : await effect;
|
|
93
|
+
return [result, null];
|
|
94
|
+
} catch (e) {
|
|
95
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
96
|
+
return [null, error];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function safeSync(effect) {
|
|
100
|
+
try {
|
|
101
|
+
const result = effect();
|
|
102
|
+
return [result, null];
|
|
103
|
+
} catch (e) {
|
|
104
|
+
const error = e instanceof Error ? e : new Error(String(e));
|
|
105
|
+
return [null, error];
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/utils/utils-queue.ts
|
|
110
|
+
var Queue = class {
|
|
111
|
+
name;
|
|
112
|
+
tasks = [];
|
|
113
|
+
running = false;
|
|
114
|
+
constructor(name = null) {
|
|
115
|
+
this.name = name;
|
|
116
|
+
}
|
|
117
|
+
async add(fn) {
|
|
118
|
+
const task = { fn, result$: Promise.withResolvers() };
|
|
119
|
+
this.tasks.push(task);
|
|
120
|
+
this.start();
|
|
121
|
+
return await task.result$.promise;
|
|
122
|
+
}
|
|
123
|
+
wrap(fn, thisValue = null) {
|
|
124
|
+
return async (...args) => {
|
|
125
|
+
return await this.add(() => fn.call(thisValue, ...args));
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
async wait() {
|
|
129
|
+
const lastTask = this.tasks.at(-1);
|
|
130
|
+
if (lastTask) await safe(lastTask.result$.promise);
|
|
131
|
+
}
|
|
132
|
+
isEmpty() {
|
|
133
|
+
return this.tasks.length === 0;
|
|
134
|
+
}
|
|
135
|
+
async start() {
|
|
136
|
+
if (this.running) return;
|
|
137
|
+
if (this.isEmpty()) return;
|
|
138
|
+
this.running = true;
|
|
139
|
+
while (this.tasks.length > 0) {
|
|
140
|
+
const task = this.tasks[0];
|
|
141
|
+
const [result, error] = await safe(task.fn);
|
|
142
|
+
this.tasks.shift();
|
|
143
|
+
if (error) {
|
|
144
|
+
task.result$.reject(error);
|
|
145
|
+
} else {
|
|
146
|
+
task.result$.resolve(result);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
this.running = false;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// src/utils/utils-unique.ts
|
|
154
|
+
function unique(items, keyFn) {
|
|
155
|
+
if (!keyFn) return [...new Set(items)];
|
|
156
|
+
const seen = /* @__PURE__ */ new Set();
|
|
157
|
+
return items.filter((item) => {
|
|
158
|
+
const key = keyFn(item);
|
|
159
|
+
if (seen.has(key)) return false;
|
|
160
|
+
seen.add(key);
|
|
161
|
+
return true;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/utils/utils-unit.ts
|
|
166
|
+
var Unit = class {
|
|
167
|
+
$;
|
|
168
|
+
log = createLog(this.constructor.name);
|
|
169
|
+
#parent = null;
|
|
170
|
+
constructor(parent) {
|
|
171
|
+
this.$ = parent?.$ ?? this;
|
|
172
|
+
this.#parent = parent ?? null;
|
|
173
|
+
}
|
|
174
|
+
closest(Ancestor) {
|
|
175
|
+
let cursor = this.#parent;
|
|
176
|
+
while (cursor) {
|
|
177
|
+
if (cursor instanceof Ancestor) return cursor;
|
|
178
|
+
cursor = cursor.#parent;
|
|
179
|
+
}
|
|
180
|
+
return null;
|
|
181
|
+
}
|
|
182
|
+
never(message) {
|
|
183
|
+
const details = message ? `: ${message}` : "";
|
|
184
|
+
const error = new Error(`[${this.constructor.name}] This should never happen${details}`);
|
|
185
|
+
Error.captureStackTrace(error, this.never);
|
|
186
|
+
return error;
|
|
187
|
+
}
|
|
188
|
+
Error(message) {
|
|
189
|
+
const error = new Error(`[${this.constructor.name}] ${message}`);
|
|
190
|
+
Error.captureStackTrace(error, this.Error);
|
|
191
|
+
return error;
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// src/utils/utils-wait.ts
|
|
196
|
+
async function wait(ms) {
|
|
197
|
+
await new Promise((r) => setTimeout(r, ms));
|
|
198
|
+
}
|
|
199
|
+
export {
|
|
200
|
+
Queue,
|
|
201
|
+
Unit,
|
|
202
|
+
colorHash,
|
|
203
|
+
createLog,
|
|
204
|
+
ensureArray,
|
|
205
|
+
is,
|
|
206
|
+
safe,
|
|
207
|
+
safeSync,
|
|
208
|
+
unique,
|
|
209
|
+
wait
|
|
210
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dropcap",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "imkost",
|
|
7
|
+
"description": "",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "tsup --config ../../tsup.config.ts --watch",
|
|
10
|
+
"build": "tsup --config ../../tsup.config.ts",
|
|
11
|
+
"lint": "tsc --noEmit",
|
|
12
|
+
"release": "sh -c 'npm version ${1:-minor} && npm run build && npm publish' --"
|
|
13
|
+
},
|
|
14
|
+
"exports": {
|
|
15
|
+
"./utils": {
|
|
16
|
+
"source": "./src/utils/utils.ts",
|
|
17
|
+
"import": "./dist/utils/utils.js",
|
|
18
|
+
"types": "./dist/utils/utils.d.ts"
|
|
19
|
+
},
|
|
20
|
+
"./types": {
|
|
21
|
+
"source": "./src/types/types.ts",
|
|
22
|
+
"import": "./dist/types/types.js",
|
|
23
|
+
"types": "./dist/types/types.d.ts"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"src",
|
|
28
|
+
"dist"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export type Rgb = [number, number, number]
|
|
2
|
+
|
|
3
|
+
export function colorHash(str: string) {
|
|
4
|
+
// Calculate hash (djb2 xor) as 32‑bit unsigned
|
|
5
|
+
let hash = 5381
|
|
6
|
+
for (let i = 0; i < str.length; i++) {
|
|
7
|
+
hash = (hash * 33) ^ str.charCodeAt(i)
|
|
8
|
+
}
|
|
9
|
+
hash >>>= 0
|
|
10
|
+
|
|
11
|
+
// Calculate hue. Golden‑ratio scramble gives maximum spread for 'near' strings.
|
|
12
|
+
const hue = Math.floor(((hash * 0.618033988749895) % 1) * 360)
|
|
13
|
+
|
|
14
|
+
// Start with vivid mid‑tone
|
|
15
|
+
const sat = 70
|
|
16
|
+
let light = 50
|
|
17
|
+
|
|
18
|
+
// Adjust lightness until it reads on both white and black backgrounds.
|
|
19
|
+
for (let i = 0; i < 20; i++) {
|
|
20
|
+
const rgb = hsl2rgb(hue, sat, light)
|
|
21
|
+
const l = lum(rgb)
|
|
22
|
+
const cW = contrast(1, l) // Versus white
|
|
23
|
+
const cB = contrast(0, l) // Versus black
|
|
24
|
+
if (cW >= 4.5 && cB >= 4.5) break // Good on both
|
|
25
|
+
light += cW < cB ? -5 : 5 // Move toward darker or lighter
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Convert to hex
|
|
29
|
+
const hex = hsl2rgb(hue, sat, light)
|
|
30
|
+
.map(v => v.toString(16).padStart(2, '0'))
|
|
31
|
+
.join('')
|
|
32
|
+
|
|
33
|
+
return `#${hex}`
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function hsl2rgb(hh: number, ss: number, ll: number): Rgb {
|
|
37
|
+
ss /= 100
|
|
38
|
+
ll /= 100
|
|
39
|
+
const k = (n: number) => (n + hh / 30) % 12
|
|
40
|
+
const a = ss * Math.min(ll, 1 - ll)
|
|
41
|
+
const f = (n: number) => ll - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)))
|
|
42
|
+
return [f(0), f(8), f(4)].map(v => Math.round(v * 255)) as Rgb
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function lum([r, g, b]: Rgb) {
|
|
46
|
+
const c = (x: number) => {
|
|
47
|
+
x /= 255
|
|
48
|
+
return x <= 0.03928 ? x / 12.92 : ((x + 0.055) / 1.055) ** 2.4
|
|
49
|
+
}
|
|
50
|
+
return 0.2126 * c(r) + 0.7152 * c(g) + 0.0722 * c(b)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function contrast(l1: number, l2: number) {
|
|
54
|
+
return (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05)
|
|
55
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Fn } from '../types/types.js'
|
|
2
|
+
import { colorHash } from './utils-color-hash.js'
|
|
3
|
+
|
|
4
|
+
export type Log = Fn<void> & { warn: Fn<void>; error: Fn<void> }
|
|
5
|
+
|
|
6
|
+
export function createLog(name: string) {
|
|
7
|
+
const color = colorHash(name)
|
|
8
|
+
const log = print.bind(null, 'log', name, color) as Log
|
|
9
|
+
log.warn = print.bind(null, 'warn', name, color) as Log['warn']
|
|
10
|
+
log.error = print.bind(null, 'error', name, color) as Log['error']
|
|
11
|
+
return log
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function print(type: 'log' | 'warn' | 'error', name: string, color: string, ...args: unknown[]) {
|
|
15
|
+
console[type](`%c[${name}]`, `color: ${color}`, ...args)
|
|
16
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Fn, Obj, Arr } from '../types/types.js'
|
|
2
|
+
|
|
3
|
+
export const is = {
|
|
4
|
+
null: (v: unknown) => v === null,
|
|
5
|
+
undefined: (v: unknown) => v === undefined,
|
|
6
|
+
boolean: (v: unknown) => typeof v === 'boolean',
|
|
7
|
+
number: (v: unknown) => typeof v === 'number',
|
|
8
|
+
string: (v: unknown) => typeof v === 'string',
|
|
9
|
+
symbol: (v: unknown) => typeof v === 'symbol',
|
|
10
|
+
function: (v: unknown): v is Fn => typeof v === 'function',
|
|
11
|
+
object: (v: unknown): v is Obj => Object.prototype.toString.call(v) === '[object Object]',
|
|
12
|
+
array: (v: unknown): v is Arr => Array.isArray(v),
|
|
13
|
+
set: (v: unknown) => v instanceof Set,
|
|
14
|
+
map: (v: unknown) => v instanceof Map,
|
|
15
|
+
blob: (v: unknown) => v instanceof Blob,
|
|
16
|
+
date: (v: unknown) => v instanceof Date,
|
|
17
|
+
error: (v: unknown) => v instanceof Error,
|
|
18
|
+
regex: (v: unknown) => v instanceof RegExp,
|
|
19
|
+
promise: (v: unknown) => v instanceof Promise,
|
|
20
|
+
uint8Array: (v: unknown) => v instanceof Uint8Array,
|
|
21
|
+
uint16Array: (v: unknown) => v instanceof Uint16Array,
|
|
22
|
+
uint32Array: (v: unknown) => v instanceof Uint32Array,
|
|
23
|
+
|
|
24
|
+
nan: (v: unknown) => Number.isNaN(v),
|
|
25
|
+
numeric: (v: unknown) => !is.nan(Number(v)),
|
|
26
|
+
integer: (v: unknown): v is number => Number.isInteger(v),
|
|
27
|
+
absent: (v: unknown) => v === null || v === undefined,
|
|
28
|
+
present: <T>(v: T): v is NonNullable<T> => !is.absent(v),
|
|
29
|
+
primitive: (v: unknown) => v !== Object(v),
|
|
30
|
+
collection: (v: unknown) => is.array(v) || is.object(v),
|
|
31
|
+
compound: (v: unknown) => v !== null && typeof v === 'object',
|
|
32
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { safe } from './utils-safe.js'
|
|
2
|
+
import type { AsyncFn } from '../types/types.js'
|
|
3
|
+
|
|
4
|
+
type TaskFn<T> = () => Promise<T>
|
|
5
|
+
type Task<T = any> = { fn: TaskFn<T>; result$: PromiseWithResolvers<T> }
|
|
6
|
+
|
|
7
|
+
export class Queue {
|
|
8
|
+
name: string | null
|
|
9
|
+
tasks: Task[] = []
|
|
10
|
+
private running = false
|
|
11
|
+
|
|
12
|
+
constructor(name: string | null = null) {
|
|
13
|
+
this.name = name
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async add<T>(fn: TaskFn<T>): Promise<T> {
|
|
17
|
+
const task: Task<T> = { fn, result$: Promise.withResolvers<T>() }
|
|
18
|
+
this.tasks.push(task)
|
|
19
|
+
this.start()
|
|
20
|
+
return await task.result$.promise
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
wrap<T extends AsyncFn>(fn: T, thisValue: unknown = null) {
|
|
24
|
+
return async (...args: Parameters<T>) => {
|
|
25
|
+
return await this.add(() => fn.call(thisValue, ...args))
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async wait() {
|
|
30
|
+
const lastTask = this.tasks.at(-1)
|
|
31
|
+
if (lastTask) await safe(lastTask.result$.promise)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
isEmpty() {
|
|
35
|
+
return this.tasks.length === 0
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private async start() {
|
|
39
|
+
if (this.running) return
|
|
40
|
+
if (this.isEmpty()) return
|
|
41
|
+
|
|
42
|
+
this.running = true
|
|
43
|
+
|
|
44
|
+
while (this.tasks.length > 0) {
|
|
45
|
+
const task = this.tasks[0]
|
|
46
|
+
const [result, error] = await safe(task.fn)
|
|
47
|
+
this.tasks.shift()
|
|
48
|
+
if (error) {
|
|
49
|
+
task.result$.reject(error)
|
|
50
|
+
} else {
|
|
51
|
+
task.result$.resolve(result)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
this.running = false
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { is } from './utils-is.js'
|
|
2
|
+
|
|
3
|
+
export async function safe<T>(
|
|
4
|
+
effect: (() => T | Promise<T>) | Promise<T>,
|
|
5
|
+
): Promise<[T, null] | [null, Error]> {
|
|
6
|
+
try {
|
|
7
|
+
const result = is.function(effect) ? await effect() : await effect
|
|
8
|
+
return [result, null]
|
|
9
|
+
} catch (e) {
|
|
10
|
+
const error = e instanceof Error ? e : new Error(String(e))
|
|
11
|
+
return [null, error]
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function safeSync<T>(effect: () => T): [T, null] | [null, Error] {
|
|
16
|
+
try {
|
|
17
|
+
const result = effect()
|
|
18
|
+
return [result, null]
|
|
19
|
+
} catch (e) {
|
|
20
|
+
const error = e instanceof Error ? e : new Error(String(e))
|
|
21
|
+
return [null, error]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function unique<T = unknown>(items: T[], keyFn?: (item: T) => unknown) {
|
|
2
|
+
if (!keyFn) return [...new Set(items)]
|
|
3
|
+
|
|
4
|
+
const seen = new Set()
|
|
5
|
+
return items.filter(item => {
|
|
6
|
+
const key = keyFn(item)
|
|
7
|
+
if (seen.has(key)) return false
|
|
8
|
+
seen.add(key)
|
|
9
|
+
return true
|
|
10
|
+
})
|
|
11
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { Cls } from '../types/types.js'
|
|
2
|
+
import { createLog } from './utils-create-log.js'
|
|
3
|
+
|
|
4
|
+
export class Unit<TRoot = unknown> {
|
|
5
|
+
$: TRoot
|
|
6
|
+
log = createLog(this.constructor.name)
|
|
7
|
+
#parent: Unit<TRoot> | null = null
|
|
8
|
+
|
|
9
|
+
constructor(parent?: Unit<TRoot> | null) {
|
|
10
|
+
this.$ = (parent?.$ ?? this) as TRoot
|
|
11
|
+
this.#parent = parent ?? null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
closest<T extends Unit<TRoot>>(Ancestor: Cls<T>): T | null {
|
|
15
|
+
let cursor = this.#parent
|
|
16
|
+
while (cursor) {
|
|
17
|
+
if (cursor instanceof Ancestor) return cursor as T
|
|
18
|
+
cursor = cursor.#parent
|
|
19
|
+
}
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
never(message?: string) {
|
|
24
|
+
const details = message ? `: ${message}` : ''
|
|
25
|
+
const error = new Error(`[${this.constructor.name}] This should never happen${details}`)
|
|
26
|
+
Error.captureStackTrace(error, this.never)
|
|
27
|
+
return error
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Error(message?: string) {
|
|
31
|
+
const error = new Error(`[${this.constructor.name}] ${message}`)
|
|
32
|
+
Error.captureStackTrace(error, this.Error)
|
|
33
|
+
return error
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { colorHash } from './utils-color-hash.js'
|
|
2
|
+
import { createLog, type Log } from './utils-create-log.js'
|
|
3
|
+
import { ensureArray } from './utils-ensure-array.js'
|
|
4
|
+
import { is } from './utils-is.js'
|
|
5
|
+
import { Queue } from './utils-queue.js'
|
|
6
|
+
import { safe, safeSync } from './utils-safe.js'
|
|
7
|
+
import { unique } from './utils-unique.js'
|
|
8
|
+
import { Unit } from './utils-unit.js'
|
|
9
|
+
import { wait } from './utils-wait.js'
|
|
10
|
+
|
|
11
|
+
export type { Log }
|
|
12
|
+
|
|
13
|
+
export { colorHash, createLog, ensureArray, is, Queue, safe, safeSync, unique, Unit, wait }
|