@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.
Files changed (89) hide show
  1. package/dist/LICENSE.txt +1 -0
  2. package/dist/cjs/index.cjs +2 -0
  3. package/dist/cjs/index.cjs.map +1 -0
  4. package/dist/cjs/server.cjs +2 -0
  5. package/dist/cjs/server.cjs.map +1 -0
  6. package/dist/esm/index.js +1 -1
  7. package/dist/esm/index.js.map +1 -1
  8. package/dist/esm/server.js +1 -1
  9. package/dist/esm/server.js.map +1 -1
  10. package/dist/system/index.js +1 -1
  11. package/dist/system/index.js.map +1 -1
  12. package/dist/system/server.js +1 -1
  13. package/dist/system/server.js.map +1 -1
  14. package/lib/asyncs/createLazyPromise.js +12 -1
  15. package/lib/asyncs/createLazyPromise.js.map +1 -1
  16. package/lib/browsers/copy.js.map +1 -1
  17. package/lib/crypto/getRandomValues.js +27 -0
  18. package/lib/crypto/getRandomValues.js.map +1 -0
  19. package/lib/crypto/randomUUID.js +1 -1
  20. package/lib/crypto/randomUUID.js.map +1 -1
  21. package/lib/crypto/ulid.js +139 -0
  22. package/lib/crypto/ulid.js.map +1 -0
  23. package/lib/i18n/createTranslate.js +17 -1
  24. package/lib/i18n/createTranslate.js.map +1 -1
  25. package/lib/index.js +11 -4
  26. package/lib/index.js.map +1 -1
  27. package/lib/io/ArrayBuffers.js +30 -24
  28. package/lib/io/ArrayBuffers.js.map +1 -1
  29. package/lib/io/Buffer.js +21 -0
  30. package/lib/io/Buffer.js.map +1 -0
  31. package/lib/isomorphics/structuredClone.js.map +1 -1
  32. package/lib/langs/shallowClone.js +15 -0
  33. package/lib/langs/shallowClone.js.map +1 -0
  34. package/lib/logging/createChildLogger.js +2 -2
  35. package/lib/logging/createChildLogger.js.map +1 -1
  36. package/lib/logging/createLogger.js +26 -0
  37. package/lib/logging/createLogger.js.map +1 -0
  38. package/lib/logging/createNoopLogger.js.map +1 -1
  39. package/lib/objects/get.js.map +1 -1
  40. package/lib/objects/set.js.map +1 -1
  41. package/lib/server/polyfillFetch.js +17 -24
  42. package/lib/server/polyfillFetch.js.map +1 -1
  43. package/lib/validations/isEmptyObject.js +3 -4
  44. package/lib/validations/isEmptyObject.js.map +1 -1
  45. package/lib/validations/isPlainObject.js +11 -0
  46. package/lib/validations/isPlainObject.js.map +1 -0
  47. package/lib/validations/parseBoolean.js +31 -0
  48. package/lib/validations/parseBoolean.js.map +1 -0
  49. package/lib/validations/parseTimestamp.js +25 -0
  50. package/lib/validations/parseTimestamp.js.map +1 -0
  51. package/package.json +8 -11
  52. package/src/asyncs/createLazyPromise.test.ts +16 -1
  53. package/src/asyncs/createLazyPromise.ts +18 -2
  54. package/src/asyncs/isThenable.ts +4 -0
  55. package/src/browsers/copy.ts +1 -1
  56. package/src/crypto/getRandomValues.ts +42 -0
  57. package/src/crypto/randomUUID.ts +1 -1
  58. package/src/crypto/ulid.test.ts +30 -0
  59. package/src/crypto/ulid.ts +183 -0
  60. package/src/i18n/createTranslate.test.ts +15 -0
  61. package/src/i18n/createTranslate.ts +19 -3
  62. package/src/index.ts +16 -6
  63. package/src/io/ArrayBuffers.base64.test.ts +1 -1
  64. package/src/io/ArrayBuffers.ts +41 -25
  65. package/src/io/Buffer.test.ts +23 -0
  66. package/src/io/Buffer.ts +14 -0
  67. package/src/isomorphics/structuredClone.ts +1 -1
  68. package/src/langs/shallowClone.ts +13 -0
  69. package/src/logging/createChildLogger.ts +3 -3
  70. package/src/logging/createLogger.ts +31 -0
  71. package/src/logging/createNoopLogger.ts +1 -1
  72. package/src/logging/logger.test.ts +5 -3
  73. package/src/objects/get.ts +2 -1
  74. package/src/objects/set.ts +2 -1
  75. package/src/server/polyfillBrowser.test.ts +5 -1
  76. package/src/server/polyfillFetch.ts +22 -24
  77. package/src/validations/isEmptyObject.ts +3 -4
  78. package/src/validations/isFunction.ts +3 -0
  79. package/src/validations/isPlainObject.ts +10 -0
  80. package/src/validations/parseBoolean.ts +30 -0
  81. package/src/validations/parseTimestamp.test.ts +7 -0
  82. package/src/validations/parseTimestamp.ts +29 -0
  83. package/dist/cjs/index.js +0 -2
  84. package/dist/cjs/index.js.map +0 -1
  85. package/dist/cjs/server.js +0 -2
  86. package/dist/cjs/server.js.map +0 -1
  87. package/lib/logging/createWriteLogger.js +0 -13
  88. package/lib/logging/createWriteLogger.js.map +0 -1
  89. 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
- const val = get(tree[lang || locale], key, '') as any;
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
- // validations
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 { classOf } from './langs/classOf';
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 { createWriteLogger } from './logging/createWriteLogger';
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>;
@@ -2,7 +2,7 @@ import test from 'ava';
2
2
  import { ArrayBuffers } from './ArrayBuffers';
3
3
 
4
4
  test.before(() => {
5
- ArrayBuffers._allowedBuffer = false;
5
+ ArrayBuffers.setAllowedNativeBuffer(false);
6
6
  });
7
7
 
8
8
  test('base64: ignore whitespace', function (t) {
@@ -66,21 +66,31 @@ type ToStringEncoding =
66
66
  | 'utf-8'
67
67
  | 'hex';
68
68
 
69
- // eslint-disable-next-line @typescript-eslint/no-redeclare
70
- export const ArrayBuffers = {
71
- _allowedBuffer: true,
72
- isArrayBuffer: (v: any): v is ArrayBuffer => {
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
- slice: (o: TypedArray, start?: number, end?: number) => {
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
- asView: <C extends ArrayBufferViewConstructor<unknown>, I extends InstanceType<C>>(
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._allowedBuffer && typeof Buffer !== 'undefined' && (TypedArray as any) === Buffer) {
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
- toString: (buf: BufferSource | string, encoding: ToStringEncoding = 'utf8') => {
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 (typeof Buffer !== 'undefined' && ArrayBuffers._allowedBuffer) {
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
- toJSON: (v: BufferSource | string, reviver?: (this: any, key: string, value: any) => any) => {
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
- alloc: (size: number, fill?: string | number, encoding?: ToStringEncoding) => {
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
- from: (
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 (typeof Buffer !== 'undefined' && ArrayBuffers._allowedBuffer) {
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
- isEncoding: (encoding?: string) => {
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
- concat: (buffers: Array<BufferSource>, result?: ArrayBuffer, offset = 0) => {
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 { createWriteLogger } from './createWriteLogger';
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 createWriteLogger((o) => {
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,4 +1,4 @@
1
- import { LoggerWithChild } from './Logger';
1
+ import type { LoggerWithChild } from './Logger';
2
2
 
3
3
  export function createNoopLogger(): LoggerWithChild {
4
4
  const noop = (..._: any[]) => undefined;
@@ -1,11 +1,11 @@
1
1
  import test from 'ava';
2
2
  import { createChildLogger } from './createChildLogger';
3
- import { createWriteLogger } from './createWriteLogger';
3
+ import { createLogger } from './createLogger';
4
4
 
5
5
  test('logger', (t) => {
6
6
  {
7
7
  const logs: any[] = [];
8
- const base = createWriteLogger((o) => logs.push(o));
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 = createWriteLogger(
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
  });
@@ -1,4 +1,5 @@
1
- import { ObjectKey, parseObjectPath } from './parseObjectPath';
1
+ import type { ObjectKey} from './parseObjectPath';
2
+ import { parseObjectPath } from './parseObjectPath';
2
3
 
3
4
  /**
4
5
  * get by path
@@ -1,4 +1,5 @@
1
- import { ObjectKey, ObjectPath, parseObjectPath } from './parseObjectPath';
1
+ import type { ObjectKey, ObjectPath} from './parseObjectPath';
2
+ import { parseObjectPath } from './parseObjectPath';
2
3
 
3
4
  /**
4
5
  * Deep set
@@ -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