@wener/utils 1.1.7 → 1.1.9
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/LICENSE.txt +1 -0
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/server.cjs +2 -0
- package/dist/cjs/server.cjs.map +1 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/server.js +1 -1
- package/dist/esm/server.js.map +1 -1
- package/dist/system/index.js +1 -1
- package/dist/system/index.js.map +1 -1
- package/dist/system/server.js +1 -1
- package/dist/system/server.js.map +1 -1
- package/lib/asyncs/createLazyPromise.js +12 -1
- package/lib/asyncs/createLazyPromise.js.map +1 -1
- package/lib/browsers/copy.js.map +1 -1
- package/lib/crypto/getRandomValues.js +27 -0
- package/lib/crypto/getRandomValues.js.map +1 -0
- package/lib/crypto/randomUUID.js +1 -1
- package/lib/crypto/randomUUID.js.map +1 -1
- package/lib/crypto/ulid.js +139 -0
- package/lib/crypto/ulid.js.map +1 -0
- package/lib/i18n/createTranslate.js +17 -1
- package/lib/i18n/createTranslate.js.map +1 -1
- package/lib/index.js +11 -4
- package/lib/index.js.map +1 -1
- package/lib/io/ArrayBuffers.js +30 -24
- package/lib/io/ArrayBuffers.js.map +1 -1
- package/lib/io/Buffer.js +21 -0
- package/lib/io/Buffer.js.map +1 -0
- package/lib/isomorphics/structuredClone.js.map +1 -1
- package/lib/langs/shallowClone.js +15 -0
- package/lib/langs/shallowClone.js.map +1 -0
- package/lib/logging/createChildLogger.js +2 -2
- package/lib/logging/createChildLogger.js.map +1 -1
- package/lib/logging/createLogger.js +26 -0
- package/lib/logging/createLogger.js.map +1 -0
- package/lib/logging/createNoopLogger.js.map +1 -1
- package/lib/objects/get.js.map +1 -1
- package/lib/objects/set.js.map +1 -1
- package/lib/server/polyfillFetch.js +17 -24
- package/lib/server/polyfillFetch.js.map +1 -1
- package/lib/validations/isEmptyObject.js +3 -4
- package/lib/validations/isEmptyObject.js.map +1 -1
- package/lib/validations/isPlainObject.js +11 -0
- package/lib/validations/isPlainObject.js.map +1 -0
- package/lib/validations/parseBoolean.js +31 -0
- package/lib/validations/parseBoolean.js.map +1 -0
- package/lib/validations/parseTimestamp.js +25 -0
- package/lib/validations/parseTimestamp.js.map +1 -0
- package/package.json +8 -11
- package/src/asyncs/createLazyPromise.test.ts +16 -1
- package/src/asyncs/createLazyPromise.ts +18 -2
- package/src/asyncs/isThenable.ts +4 -0
- package/src/browsers/copy.ts +1 -1
- package/src/crypto/getRandomValues.ts +42 -0
- package/src/crypto/randomUUID.ts +1 -1
- package/src/crypto/ulid.test.ts +30 -0
- package/src/crypto/ulid.ts +183 -0
- package/src/i18n/createTranslate.test.ts +15 -0
- package/src/i18n/createTranslate.ts +19 -3
- package/src/index.ts +16 -6
- package/src/io/ArrayBuffers.base64.test.ts +1 -1
- package/src/io/ArrayBuffers.ts +41 -25
- package/src/io/Buffer.test.ts +23 -0
- package/src/io/Buffer.ts +14 -0
- package/src/isomorphics/structuredClone.ts +1 -1
- package/src/langs/shallowClone.ts +13 -0
- package/src/logging/createChildLogger.ts +3 -3
- package/src/logging/createLogger.ts +31 -0
- package/src/logging/createNoopLogger.ts +1 -1
- package/src/logging/logger.test.ts +5 -3
- package/src/objects/get.ts +2 -1
- package/src/objects/set.ts +2 -1
- package/src/server/polyfillBrowser.test.ts +5 -1
- package/src/server/polyfillFetch.ts +22 -24
- package/src/validations/isEmptyObject.ts +3 -4
- package/src/validations/isFunction.ts +3 -0
- package/src/validations/isPlainObject.ts +10 -0
- package/src/validations/parseBoolean.ts +30 -0
- package/src/validations/parseTimestamp.test.ts +7 -0
- package/src/validations/parseTimestamp.ts +29 -0
- package/dist/cjs/index.js +0 -2
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/server.js +0 -2
- package/dist/cjs/server.js.map +0 -1
- package/lib/logging/createWriteLogger.js +0 -13
- package/lib/logging/createWriteLogger.js.map +0 -1
- package/src/logging/createWriteLogger.ts +0 -15
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { getRandomValues } from './getRandomValues';
|
|
2
|
+
|
|
3
|
+
type PRNG = () => number;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Universally Unique Lexicographically Sortable Identifier
|
|
7
|
+
*
|
|
8
|
+
* @see https://github.com/ulid/spec ulid/spec
|
|
9
|
+
*/
|
|
10
|
+
export type ULID = (seedTime?: number) => string;
|
|
11
|
+
|
|
12
|
+
export interface ULIDError extends Error {
|
|
13
|
+
source: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function createError(message: string): ULIDError {
|
|
17
|
+
const err = new Error(message) as ULIDError;
|
|
18
|
+
err.source = 'ulid';
|
|
19
|
+
return err;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// These values should NEVER change. If
|
|
23
|
+
// they do, we're no longer making ulids!
|
|
24
|
+
const ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32
|
|
25
|
+
const ENCODING_LEN = ENCODING.length;
|
|
26
|
+
const TIME_MAX = Math.pow(2, 48) - 1;
|
|
27
|
+
const TIME_LEN = 10;
|
|
28
|
+
const RANDOM_LEN = 16;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* check give {@link str} is a valid ulid
|
|
32
|
+
*/
|
|
33
|
+
export function isULID(str: string): boolean {
|
|
34
|
+
// ttttttttttrrrrrrrrrrrrrrrr
|
|
35
|
+
return str?.length === 26 && /^[0-9A-HJKMNP-TV-Z]{26}$/i.test(str);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function replaceCharAt(str: string, index: number, char: string) {
|
|
39
|
+
if (index > str.length - 1) {
|
|
40
|
+
return str;
|
|
41
|
+
}
|
|
42
|
+
return str.substr(0, index) + char + str.substr(index + 1);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function incrementBase32(str: string): string {
|
|
46
|
+
let done;
|
|
47
|
+
let index = str.length;
|
|
48
|
+
let char;
|
|
49
|
+
let charIndex;
|
|
50
|
+
const maxCharIndex = ENCODING_LEN - 1;
|
|
51
|
+
while (!done && index-- >= 0) {
|
|
52
|
+
char = str[index];
|
|
53
|
+
charIndex = ENCODING.indexOf(char);
|
|
54
|
+
if (charIndex === -1) {
|
|
55
|
+
throw createError('incorrectly encoded string');
|
|
56
|
+
}
|
|
57
|
+
if (charIndex === maxCharIndex) {
|
|
58
|
+
str = replaceCharAt(str, index, ENCODING[0]);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
done = replaceCharAt(str, index, ENCODING[charIndex + 1]);
|
|
62
|
+
}
|
|
63
|
+
if (typeof done === 'string') {
|
|
64
|
+
return done;
|
|
65
|
+
}
|
|
66
|
+
throw createError('cannot increment this string');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function randomChar(prng: PRNG): string {
|
|
70
|
+
let rand = Math.floor(prng() * ENCODING_LEN);
|
|
71
|
+
if (rand === ENCODING_LEN) {
|
|
72
|
+
rand = ENCODING_LEN - 1;
|
|
73
|
+
}
|
|
74
|
+
return ENCODING.charAt(rand);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function encodeTime(now: number, len: number): string {
|
|
78
|
+
if (isNaN(now)) {
|
|
79
|
+
throw new Error(`${now} must be a number`);
|
|
80
|
+
}
|
|
81
|
+
if (now > TIME_MAX) {
|
|
82
|
+
throw createError(`cannot encode time greater than ${TIME_MAX}`);
|
|
83
|
+
}
|
|
84
|
+
if (now < 0) {
|
|
85
|
+
throw createError('time must be positive');
|
|
86
|
+
}
|
|
87
|
+
if (!Number.isInteger(now)) {
|
|
88
|
+
throw createError('time must be an integer');
|
|
89
|
+
}
|
|
90
|
+
let mod;
|
|
91
|
+
let str = '';
|
|
92
|
+
for (; len > 0; len--) {
|
|
93
|
+
mod = now % ENCODING_LEN;
|
|
94
|
+
str = ENCODING.charAt(mod) + str;
|
|
95
|
+
now = (now - mod) / ENCODING_LEN;
|
|
96
|
+
}
|
|
97
|
+
return str;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function encodeRandom(len: number, prng: PRNG): string {
|
|
101
|
+
let str = '';
|
|
102
|
+
for (; len > 0; len--) {
|
|
103
|
+
str = randomChar(prng) + str;
|
|
104
|
+
}
|
|
105
|
+
return str;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* extract time & random from ulid
|
|
110
|
+
*
|
|
111
|
+
* @throws ULIDError
|
|
112
|
+
*/
|
|
113
|
+
export function parseULID(id: string): { timestamp: number; random: string } {
|
|
114
|
+
if (id.length !== TIME_LEN + RANDOM_LEN) {
|
|
115
|
+
throw createError('malformed ulid');
|
|
116
|
+
}
|
|
117
|
+
const time = id
|
|
118
|
+
.substr(0, TIME_LEN)
|
|
119
|
+
.split('')
|
|
120
|
+
.reverse()
|
|
121
|
+
.reduce((carry, char, index) => {
|
|
122
|
+
const encodingIndex = ENCODING.indexOf(char);
|
|
123
|
+
if (encodingIndex === -1) {
|
|
124
|
+
throw createError('invalid character found: ' + char);
|
|
125
|
+
}
|
|
126
|
+
return (carry += encodingIndex * Math.pow(ENCODING_LEN, index));
|
|
127
|
+
}, 0);
|
|
128
|
+
if (time > TIME_MAX) {
|
|
129
|
+
throw createError('malformed ulid, timestamp too large');
|
|
130
|
+
}
|
|
131
|
+
return { timestamp: time, random: id.substring(TIME_LEN) };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function createPrng(): PRNG {
|
|
135
|
+
return () => {
|
|
136
|
+
const buffer = new Uint8Array(1);
|
|
137
|
+
getRandomValues(buffer);
|
|
138
|
+
return buffer[0] / 0xff;
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* create a ulid generator
|
|
144
|
+
*/
|
|
145
|
+
export function createULID({
|
|
146
|
+
monotonic = true,
|
|
147
|
+
random = createPrng(),
|
|
148
|
+
now = Date.now,
|
|
149
|
+
}: { monotonic?: boolean; now?: () => number; random?: () => number } = {}) {
|
|
150
|
+
if (!monotonic) {
|
|
151
|
+
return function ulid(seedTime?: number): string {
|
|
152
|
+
seedTime ||= now();
|
|
153
|
+
return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN, random);
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
let lastTime: number = 0;
|
|
158
|
+
let lastRandom: string;
|
|
159
|
+
return function ulid(seedTime?: number): string {
|
|
160
|
+
seedTime ||= now();
|
|
161
|
+
if (seedTime <= lastTime && lastRandom) {
|
|
162
|
+
const incrementedRandom = (lastRandom = incrementBase32(lastRandom));
|
|
163
|
+
return encodeTime(lastTime, TIME_LEN) + incrementedRandom;
|
|
164
|
+
}
|
|
165
|
+
lastTime = seedTime;
|
|
166
|
+
const newRandom = (lastRandom = encodeRandom(RANDOM_LEN, random));
|
|
167
|
+
return encodeTime(seedTime, TIME_LEN) + newRandom;
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* default monotonic ulid generator
|
|
173
|
+
*/
|
|
174
|
+
export let ulid: ULID = (...args) => {
|
|
175
|
+
if (_real) {
|
|
176
|
+
return _real(...args);
|
|
177
|
+
}
|
|
178
|
+
// delay initialize crypto
|
|
179
|
+
_real = createULID();
|
|
180
|
+
ulid = _real;
|
|
181
|
+
return _real(...args);
|
|
182
|
+
};
|
|
183
|
+
let _real: ULID;
|
|
@@ -153,3 +153,18 @@ test('invalid value', (t) => {
|
|
|
153
153
|
|
|
154
154
|
t.deepEqual(ctx.t('foo', null as any, 'en'), ['bar']);
|
|
155
155
|
});
|
|
156
|
+
|
|
157
|
+
test('fallback', (t) => {
|
|
158
|
+
const ctx = createTranslate({
|
|
159
|
+
en: {
|
|
160
|
+
a: 'a',
|
|
161
|
+
},
|
|
162
|
+
'en-US': {
|
|
163
|
+
a: 'a-US',
|
|
164
|
+
},
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// t.deepEqual(ctx.t('a', undefined, 'en'), 'a');
|
|
168
|
+
// t.deepEqual(ctx.t('a', undefined, 'en-US'), 'a-US');
|
|
169
|
+
t.deepEqual(ctx.t('a', undefined, 'en-UK'), 'a');
|
|
170
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { get } from '../objects/get';
|
|
2
|
-
import { ObjectPathLike } from '../objects/parseObjectPath';
|
|
2
|
+
import type { ObjectPathLike } from '../objects/parseObjectPath';
|
|
3
3
|
import { renderTemplate } from '../strings/renderTemplate';
|
|
4
4
|
|
|
5
5
|
export interface Translate<T extends object> {
|
|
@@ -19,7 +19,17 @@ export interface Translate<T extends object> {
|
|
|
19
19
|
export function createTranslate<T extends object>(obj?: Record<string, T>): Translate<T> {
|
|
20
20
|
let locale = '';
|
|
21
21
|
const tree = obj || {};
|
|
22
|
-
|
|
22
|
+
// en-US -> en-US,en
|
|
23
|
+
const keyOfDict = (s: string | string[]) => {
|
|
24
|
+
if (Array.isArray(s)) {
|
|
25
|
+
return s;
|
|
26
|
+
}
|
|
27
|
+
const sp = s.split(/[_-]/);
|
|
28
|
+
if (sp.length > 1) {
|
|
29
|
+
return [s, sp[0]];
|
|
30
|
+
}
|
|
31
|
+
return [s];
|
|
32
|
+
};
|
|
23
33
|
return {
|
|
24
34
|
locale(lang) {
|
|
25
35
|
return (locale = lang || locale);
|
|
@@ -34,7 +44,13 @@ export function createTranslate<T extends object>(obj?: Record<string, T>): Tran
|
|
|
34
44
|
}) as Translate<T>['dict'],
|
|
35
45
|
|
|
36
46
|
t(key, params, lang) {
|
|
37
|
-
|
|
47
|
+
let val: any;
|
|
48
|
+
for (const k of keyOfDict(lang || locale)) {
|
|
49
|
+
val = get(tree[k], key, '');
|
|
50
|
+
if (val) {
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
38
54
|
if (process.env.NODE_ENV === 'development') {
|
|
39
55
|
if (val == null) {
|
|
40
56
|
return console.error(
|
package/src/index.ts
CHANGED
|
@@ -22,15 +22,20 @@ export { timeout, TimeoutError } from './asyncs/timeout';
|
|
|
22
22
|
export { isPromise } from './asyncs/isPromise';
|
|
23
23
|
// export * from './async/promiseOfCallback';
|
|
24
24
|
|
|
25
|
-
//
|
|
25
|
+
// langs
|
|
26
|
+
export { shallowEqual } from './langs/shallowEqual';
|
|
27
|
+
export { deepEqual } from './langs/deepEqual';
|
|
28
|
+
export { classOf } from './langs/classOf';
|
|
29
|
+
export { shallowClone } from './langs/shallowClone';
|
|
30
|
+
|
|
31
|
+
// assertions
|
|
26
32
|
export { isClass } from './validations/isClass';
|
|
27
33
|
export { isDefined } from './validations/isDefined';
|
|
28
34
|
export { isEmptyObject } from './validations/isEmptyObject';
|
|
29
|
-
export { shallowEqual } from './langs/shallowEqual';
|
|
30
|
-
export { deepEqual } from './langs/deepEqual';
|
|
31
35
|
export { isUUID } from './validations/isUUID';
|
|
32
|
-
|
|
33
|
-
export {
|
|
36
|
+
export { isPlainObject } from './validations/isPlainObject';
|
|
37
|
+
export { parseTimestamp } from './validations/parseTimestamp';
|
|
38
|
+
export { parseBoolean } from './validations/parseBoolean';
|
|
34
39
|
|
|
35
40
|
// modules
|
|
36
41
|
export { parseModuleId, type ParsedModuleId } from './modules/parseModuleId';
|
|
@@ -38,7 +43,7 @@ export { isModule, type Module } from './modules/isModule';
|
|
|
38
43
|
|
|
39
44
|
// logging
|
|
40
45
|
export { type Logger, type LogLevel } from './logging/Logger';
|
|
41
|
-
export {
|
|
46
|
+
export { createLogger } from './logging/createLogger';
|
|
42
47
|
export { createNoopLogger } from './logging/createNoopLogger';
|
|
43
48
|
export { createChildLogger } from './logging/createChildLogger';
|
|
44
49
|
|
|
@@ -54,6 +59,7 @@ export { createTranslate } from './i18n/createTranslate';
|
|
|
54
59
|
export { isBuffer } from './io/isBuffer';
|
|
55
60
|
export { isTransferable } from './io/isTransferable';
|
|
56
61
|
export { ArrayBuffers } from './io/ArrayBuffers';
|
|
62
|
+
export { Buffer } from './io/Buffer';
|
|
57
63
|
export type { AbstractEncoding } from './io/AbstractEncoding';
|
|
58
64
|
|
|
59
65
|
// browser
|
|
@@ -68,8 +74,12 @@ export { structuredClone } from './isomorphics/structuredClone';
|
|
|
68
74
|
|
|
69
75
|
// crypto
|
|
70
76
|
export { randomUUID } from './crypto/randomUUID';
|
|
77
|
+
export { getRandomValues } from './crypto/getRandomValues';
|
|
71
78
|
export { sha1, sha256, sha384, sha512 } from './crypto/hashing';
|
|
72
79
|
export { hex } from './crypto/base';
|
|
80
|
+
export { isULID, createULID, ulid, parseULID } from './crypto/ulid';
|
|
73
81
|
|
|
74
82
|
// misc
|
|
75
83
|
export { createRandom } from './maths/random';
|
|
84
|
+
|
|
85
|
+
export type FetchLike = (url: string, init?: RequestInit) => Promise<Response>;
|
package/src/io/ArrayBuffers.ts
CHANGED
|
@@ -66,21 +66,31 @@ type ToStringEncoding =
|
|
|
66
66
|
| 'utf-8'
|
|
67
67
|
| 'hex';
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
export class ArrayBuffers {
|
|
70
|
+
static #_allowedNativeBuffer: boolean = true;
|
|
71
|
+
|
|
72
|
+
static #isNativeBufferValid() {
|
|
73
|
+
return this.#_allowedNativeBuffer && !(globalThis.Buffer as any)?.isPollyfill?.();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static setAllowedNativeBuffer(v: boolean) {
|
|
77
|
+
this.#_allowedNativeBuffer = v;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
static isArrayBuffer = (v: any): v is ArrayBuffer => {
|
|
73
81
|
return v instanceof ArrayBuffer;
|
|
74
|
-
}
|
|
75
|
-
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
static slice = (o: TypedArray, start?: number, end?: number) => {
|
|
76
85
|
// NodeJS Buffer slice is not the same as UInt8Array slice
|
|
77
86
|
// https://nodejs.org/api/buffer.html#bufslicestart-end
|
|
78
87
|
if (isBuffer(o)) {
|
|
79
88
|
return Uint8Array.prototype.slice.call(o, start, end);
|
|
80
89
|
}
|
|
81
90
|
return o.slice(start, end);
|
|
82
|
-
}
|
|
83
|
-
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
static asView = <C extends ArrayBufferViewConstructor<unknown>, I extends InstanceType<C>>(
|
|
84
94
|
TypedArray: C,
|
|
85
95
|
v: BufferSource,
|
|
86
96
|
byteOffset?: number,
|
|
@@ -90,20 +100,21 @@ export const ArrayBuffers = {
|
|
|
90
100
|
return v as I;
|
|
91
101
|
}
|
|
92
102
|
if (ArrayBuffer.isView(v) || isBuffer(v)) {
|
|
93
|
-
if (ArrayBuffers
|
|
103
|
+
if (ArrayBuffers.#isNativeBufferValid() && (TypedArray as any) === Buffer) {
|
|
94
104
|
// new Buffer() is deprecated
|
|
95
105
|
return Buffer.from(v.buffer, byteOffset, byteLength) as I;
|
|
96
106
|
}
|
|
97
107
|
return new TypedArray(v.buffer, v.byteOffset + (byteOffset ?? 0), byteLength ?? v.byteLength) as I;
|
|
98
108
|
}
|
|
99
109
|
return new TypedArray(v, byteOffset, byteLength) as I;
|
|
100
|
-
}
|
|
101
|
-
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
static toString = (buf: BufferSource | string, encoding: ToStringEncoding = 'utf8') => {
|
|
102
113
|
// 'ascii' 'utf16le' | 'ucs2' | 'ucs-2' | 'base64' | 'base64url' | 'latin1' | 'binary' | 'hex'
|
|
103
114
|
if (typeof buf === 'string') {
|
|
104
115
|
return buf;
|
|
105
116
|
}
|
|
106
|
-
if (
|
|
117
|
+
if (ArrayBuffers.#isNativeBufferValid()) {
|
|
107
118
|
return Buffer.from(ArrayBuffers.asView(Uint8Array, buf)).toString(encoding);
|
|
108
119
|
}
|
|
109
120
|
// reference
|
|
@@ -148,11 +159,13 @@ export const ArrayBuffers = {
|
|
|
148
159
|
default:
|
|
149
160
|
throw new Error(`[ArrayBuffers.toString] Unknown encoding: ${encoding}`);
|
|
150
161
|
}
|
|
151
|
-
}
|
|
152
|
-
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
static toJSON = (v: BufferSource | string, reviver?: (this: any, key: string, value: any) => any) => {
|
|
153
165
|
return JSON.parse(ArrayBuffers.toString(v), reviver);
|
|
154
|
-
}
|
|
155
|
-
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
static alloc = (size: number, fill?: string | number, encoding?: ToStringEncoding) => {
|
|
156
169
|
if (fill !== undefined) {
|
|
157
170
|
if (typeof fill === 'number') {
|
|
158
171
|
return new Uint8Array(size).fill(fill);
|
|
@@ -162,8 +175,9 @@ export const ArrayBuffers = {
|
|
|
162
175
|
return ArrayBuffers.asView(Uint8Array, ArrayBuffers.from(fill, encoding)).slice(0, size);
|
|
163
176
|
}
|
|
164
177
|
return new ArrayBuffer(size);
|
|
165
|
-
}
|
|
166
|
-
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
static from = (
|
|
167
181
|
v: string | BufferSource | ArrayLike<number> | Iterable<number>,
|
|
168
182
|
encoding: ToStringEncoding = 'utf8',
|
|
169
183
|
): BufferSource => {
|
|
@@ -171,7 +185,7 @@ export const ArrayBuffers = {
|
|
|
171
185
|
return new ArrayBuffer(0);
|
|
172
186
|
}
|
|
173
187
|
if (typeof v === 'string') {
|
|
174
|
-
if (
|
|
188
|
+
if (ArrayBuffers.#isNativeBufferValid()) {
|
|
175
189
|
return Buffer.from(v, encoding);
|
|
176
190
|
}
|
|
177
191
|
|
|
@@ -203,8 +217,9 @@ export const ArrayBuffers = {
|
|
|
203
217
|
}
|
|
204
218
|
const type = classOf(v);
|
|
205
219
|
throw new TypeError(`ArrayBuffers.from unsupported type ${type}`);
|
|
206
|
-
}
|
|
207
|
-
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
static isEncoding = (encoding?: string) => {
|
|
208
223
|
switch (String(encoding).toLowerCase()) {
|
|
209
224
|
case 'hex':
|
|
210
225
|
case 'utf8':
|
|
@@ -221,8 +236,9 @@ export const ArrayBuffers = {
|
|
|
221
236
|
default:
|
|
222
237
|
return false;
|
|
223
238
|
}
|
|
224
|
-
}
|
|
225
|
-
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
static concat = (buffers: Array<BufferSource>, result?: ArrayBuffer, offset = 0) => {
|
|
226
242
|
// https://stackoverflow.com/questions/10786128/appending-arraybuffers
|
|
227
243
|
|
|
228
244
|
const length = buffers.reduce((a, b) => a + b.byteLength, 0);
|
|
@@ -241,8 +257,8 @@ export const ArrayBuffers = {
|
|
|
241
257
|
offset += buffer.byteLength;
|
|
242
258
|
}
|
|
243
259
|
return r.buffer;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
246
262
|
|
|
247
263
|
export type TypedArray =
|
|
248
264
|
| Uint8Array
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import test from 'ava';
|
|
2
|
+
import { Buffer } from './Buffer';
|
|
3
|
+
import { isBuffer } from './isBuffer';
|
|
4
|
+
|
|
5
|
+
test('basic', (t) => {
|
|
6
|
+
{
|
|
7
|
+
const buf = new Buffer(0);
|
|
8
|
+
t.true(Buffer.isBuffer(buf));
|
|
9
|
+
t.true(isBuffer(buf));
|
|
10
|
+
}
|
|
11
|
+
// const b = new Buffer(10)
|
|
12
|
+
// t.is(b.length,10)
|
|
13
|
+
// t.is(b.byteLength,10)
|
|
14
|
+
// t.is(b.byteOffset,0)
|
|
15
|
+
// t.is(b.buffer.byteLength,10)
|
|
16
|
+
// t.is(b.buffer.byteOffset,0)
|
|
17
|
+
// t.is(b.buffer.length,1)
|
|
18
|
+
// t.is(b.buffer[0].byteLength,10)
|
|
19
|
+
// t.is(b.buffer[0].byteOffset,0)
|
|
20
|
+
// t.is(b.buffer[0].length,10)
|
|
21
|
+
// t.is(b.buffer[0][0],0)
|
|
22
|
+
// t.is(b.buffer[0][9],0)
|
|
23
|
+
});
|
package/src/io/Buffer.ts
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import { ArrayBuffers } from './ArrayBuffers';
|
|
2
|
+
import { isBuffer } from './isBuffer';
|
|
2
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Buffer is a polyfill version of NodeJS Buffer
|
|
6
|
+
*/
|
|
3
7
|
export class Buffer extends Uint8Array {
|
|
4
8
|
// constructor(buffer: ArrayBufferLike, byteOffset?: number, length?: number) {
|
|
5
9
|
// super(buffer, byteOffset, length);
|
|
6
10
|
// }
|
|
7
11
|
|
|
12
|
+
static get isPolyfill() {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static isBuffer(v: any): v is Buffer {
|
|
17
|
+
return v instanceof Buffer || isBuffer(v);
|
|
18
|
+
}
|
|
19
|
+
|
|
8
20
|
static from(array: string | BufferSource | ArrayLike<number> | Iterable<number>, arg2?: any): Buffer {
|
|
9
21
|
// todo mapfn
|
|
10
22
|
return new Buffer(ArrayBuffers.from(array, arg2) as ArrayBuffer);
|
|
11
23
|
}
|
|
12
24
|
|
|
25
|
+
static isEncoding = ArrayBuffers.isEncoding;
|
|
26
|
+
|
|
13
27
|
toString(encoding?: string): string {
|
|
14
28
|
return ArrayBuffers.toString(this, encoding as any);
|
|
15
29
|
}
|
|
@@ -4,7 +4,7 @@ import { classOf } from '../langs/classOf';
|
|
|
4
4
|
/**
|
|
5
5
|
* Clone an object using structured cloning algorithm
|
|
6
6
|
*
|
|
7
|
-
* - Chrome 98, Safari 15.4
|
|
7
|
+
* - Chrome 98, Safari 15.4, NodeJS 17
|
|
8
8
|
*
|
|
9
9
|
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/structuredClone structuredClone}
|
|
10
10
|
* @see {@link https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.structured-clone.js core-js}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function shallowClone<T>(obj: T): T {
|
|
2
|
+
if (!obj) {
|
|
3
|
+
return obj;
|
|
4
|
+
}
|
|
5
|
+
if (Array.isArray(obj)) {
|
|
6
|
+
return obj.slice() as T;
|
|
7
|
+
}
|
|
8
|
+
if (typeof obj === 'object') {
|
|
9
|
+
return Object.assign({}, obj);
|
|
10
|
+
}
|
|
11
|
+
// skip Map, Set, WeakMap, WeakSet, Date, RegExp, etc.
|
|
12
|
+
return obj;
|
|
13
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { Logger, LoggerWithChild } from './Logger';
|
|
2
|
-
import {
|
|
1
|
+
import type { Logger, LoggerWithChild } from './Logger';
|
|
2
|
+
import { createLogger } from './createLogger';
|
|
3
3
|
|
|
4
4
|
export function createChildLogger(l: Logger, ctx: object): LoggerWithChild {
|
|
5
5
|
if (l.child) {
|
|
6
6
|
return l.child(ctx) as LoggerWithChild;
|
|
7
7
|
}
|
|
8
|
-
return
|
|
8
|
+
return createLogger((o) => {
|
|
9
9
|
const { level, values, ...c } = o;
|
|
10
10
|
if (Object.keys(c).length) {
|
|
11
11
|
l[level](c, ...values);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { LoggerWithChild, LogLevel } from './Logger';
|
|
2
|
+
|
|
3
|
+
export function createLogger(
|
|
4
|
+
write: (o: { level: LogLevel; values: any[] } & Record<string | symbol, any>) => void = ({
|
|
5
|
+
level,
|
|
6
|
+
values,
|
|
7
|
+
...ctx
|
|
8
|
+
}) => {
|
|
9
|
+
({ values, ...ctx } = merge(ctx, values));
|
|
10
|
+
console[level]?.(...values, ctx);
|
|
11
|
+
},
|
|
12
|
+
context: object = {},
|
|
13
|
+
): LoggerWithChild {
|
|
14
|
+
return {
|
|
15
|
+
trace: (...values) => write({ ...context, level: 'trace', values }),
|
|
16
|
+
debug: (...values) => write({ ...context, level: 'debug', values }),
|
|
17
|
+
info: (...values) => write({ ...context, level: 'info', values }),
|
|
18
|
+
warn: (...values) => write({ ...context, level: 'warn', values }),
|
|
19
|
+
error: (...values) => write({ ...context, level: 'error', values }),
|
|
20
|
+
child: (ctx) => createLogger(write, { ...context, ...ctx }),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// logger.info({name:'wener'},'message')
|
|
25
|
+
// merge initial context with message object
|
|
26
|
+
function merge(ctx: any, values: any[]) {
|
|
27
|
+
if (values[0] && typeof values[0] === 'object') {
|
|
28
|
+
return { ...ctx, ...values[0], values: values.slice(1) };
|
|
29
|
+
}
|
|
30
|
+
return { ...ctx, values };
|
|
31
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
2
|
import { createChildLogger } from './createChildLogger';
|
|
3
|
-
import {
|
|
3
|
+
import { createLogger } from './createLogger';
|
|
4
4
|
|
|
5
5
|
test('logger', (t) => {
|
|
6
6
|
{
|
|
7
7
|
const logs: any[] = [];
|
|
8
|
-
const base =
|
|
8
|
+
const base = createLogger((o) => logs.push(o));
|
|
9
9
|
const l = createChildLogger(base, { c: 'test' });
|
|
10
10
|
l.info('hello');
|
|
11
11
|
t.deepEqual(logs.shift(), { level: 'info', values: ['hello'], c: 'test' });
|
|
@@ -15,7 +15,7 @@ test('logger', (t) => {
|
|
|
15
15
|
createChildLogger(console, { c: 'test' }).info('hello');
|
|
16
16
|
{
|
|
17
17
|
let pass = 0;
|
|
18
|
-
const l =
|
|
18
|
+
const l = createLogger(
|
|
19
19
|
(o) => {
|
|
20
20
|
pass++;
|
|
21
21
|
t.log(`${o.level}: [${[o.m, o.c].filter(Boolean).join('.') || 'default'}]`, ...o.values);
|
|
@@ -30,5 +30,7 @@ test('logger', (t) => {
|
|
|
30
30
|
t.is(pass, 2);
|
|
31
31
|
createChildLogger(l, { m: 'Child' }).info('nice 3');
|
|
32
32
|
t.is(pass, 3);
|
|
33
|
+
|
|
34
|
+
createLogger().child({ name: 'wener' }).info({ x: 1 }, 'Nice');
|
|
33
35
|
}
|
|
34
36
|
});
|
package/src/objects/get.ts
CHANGED
package/src/objects/set.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
|
+
import * as nodeFetch from 'node-fetch';
|
|
2
3
|
import { polyfillBrowser } from './polyfillBrowser';
|
|
4
|
+
import { polyfillFetch } from './polyfillFetch';
|
|
3
5
|
|
|
4
|
-
test.before(async () => {
|
|
6
|
+
test.before(async (t) => {
|
|
7
|
+
t.true(polyfillFetch(nodeFetch));
|
|
8
|
+
t.false(polyfillFetch());
|
|
5
9
|
await polyfillBrowser();
|
|
6
10
|
});
|
|
7
11
|
|