@wener/utils 1.1.7 → 1.1.8

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 (63) hide show
  1. package/dist/cjs/index.cjs +2 -0
  2. package/dist/cjs/index.cjs.map +1 -0
  3. package/dist/cjs/server.cjs +2 -0
  4. package/dist/cjs/server.cjs.map +1 -0
  5. package/dist/esm/index.js +1 -1
  6. package/dist/esm/index.js.map +1 -1
  7. package/dist/system/index.js +1 -1
  8. package/dist/system/index.js.map +1 -1
  9. package/lib/asyncs/createLazyPromise.js +10 -1
  10. package/lib/asyncs/createLazyPromise.js.map +1 -1
  11. package/lib/browsers/copy.js.map +1 -1
  12. package/lib/crypto/getRandomValues.js +37 -0
  13. package/lib/crypto/getRandomValues.js.map +1 -0
  14. package/lib/crypto/ulid.js +139 -0
  15. package/lib/crypto/ulid.js.map +1 -0
  16. package/lib/i18n/createTranslate.js +17 -1
  17. package/lib/i18n/createTranslate.js.map +1 -1
  18. package/lib/index.js +8 -3
  19. package/lib/index.js.map +1 -1
  20. package/lib/io/ArrayBuffers.js +30 -24
  21. package/lib/io/ArrayBuffers.js.map +1 -1
  22. package/lib/io/Buffer.js +21 -0
  23. package/lib/io/Buffer.js.map +1 -0
  24. package/lib/isomorphics/structuredClone.js.map +1 -1
  25. package/lib/langs/shallowClone.js +15 -0
  26. package/lib/langs/shallowClone.js.map +1 -0
  27. package/lib/logging/createChildLogger.js.map +1 -1
  28. package/lib/logging/createNoopLogger.js.map +1 -1
  29. package/lib/logging/createWriteLogger.js.map +1 -1
  30. package/lib/objects/get.js.map +1 -1
  31. package/lib/objects/set.js.map +1 -1
  32. package/lib/validations/isEmptyObject.js +3 -4
  33. package/lib/validations/isEmptyObject.js.map +1 -1
  34. package/lib/validations/isPlainObject.js +11 -0
  35. package/lib/validations/isPlainObject.js.map +1 -0
  36. package/package.json +5 -5
  37. package/src/asyncs/createLazyPromise.test.ts +16 -1
  38. package/src/asyncs/createLazyPromise.ts +17 -2
  39. package/src/browsers/copy.ts +1 -1
  40. package/src/crypto/getRandomValues.ts +40 -0
  41. package/src/crypto/ulid.test.ts +22 -0
  42. package/src/crypto/ulid.ts +182 -0
  43. package/src/i18n/createTranslate.test.ts +15 -0
  44. package/src/i18n/createTranslate.ts +19 -3
  45. package/src/index.ts +11 -5
  46. package/src/io/ArrayBuffers.base64.test.ts +1 -1
  47. package/src/io/ArrayBuffers.ts +41 -25
  48. package/src/io/Buffer.test.ts +23 -0
  49. package/src/io/Buffer.ts +14 -0
  50. package/src/isomorphics/structuredClone.ts +1 -1
  51. package/src/langs/shallowClone.ts +13 -0
  52. package/src/logging/createChildLogger.ts +1 -1
  53. package/src/logging/createNoopLogger.ts +1 -1
  54. package/src/logging/createWriteLogger.ts +1 -1
  55. package/src/objects/get.ts +2 -1
  56. package/src/objects/set.ts +2 -1
  57. package/src/validations/isEmptyObject.ts +3 -4
  58. package/src/validations/isFunction.ts +3 -0
  59. package/src/validations/isPlainObject.ts +10 -0
  60. package/dist/cjs/index.js +0 -2
  61. package/dist/cjs/index.js.map +0 -1
  62. package/dist/cjs/server.js +0 -2
  63. package/dist/cjs/server.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wener/utils",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
4
4
  "type": "module",
5
5
  "description": "Utils for daily use",
6
6
  "repository": {
@@ -14,7 +14,7 @@
14
14
  "node": "16",
15
15
  "npm": "8"
16
16
  },
17
- "main": "dist/cjs/index.js",
17
+ "main": "dist/cjs/index.cjs",
18
18
  "module": "lib/index.js",
19
19
  "exports": {
20
20
  ".": {
@@ -24,7 +24,7 @@
24
24
  "system": {
25
25
  "default": "./dist/system/index.js"
26
26
  },
27
- "require": "./dist/cjs/index.js"
27
+ "require": "./dist/cjs/index.cjs"
28
28
  },
29
29
  "./types": {
30
30
  "types": "./types.d.ts"
@@ -36,7 +36,7 @@
36
36
  "system": {
37
37
  "default": "./dist/system/server.js"
38
38
  },
39
- "require": "./dist/cjs/server.js"
39
+ "require": "./dist/cjs/server.cjs"
40
40
  },
41
41
  "./src/*": "./src/*",
42
42
  "./package.json": "./package.json"
@@ -62,7 +62,7 @@
62
62
  ],
63
63
  "devDependencies": {
64
64
  "@types/lodash": "^4.14.186",
65
- "ava": "^4.3.3",
65
+ "ava": "^5.0.1",
66
66
  "lodash": "^4",
67
67
  "tsd": "^0.24.1"
68
68
  },
@@ -17,7 +17,7 @@ test('basic', async (t) => {
17
17
  });
18
18
 
19
19
  test('manual resolve skip exec', async (t) => {
20
- const promise = createLazyPromise(() => {
20
+ const promise = createLazyPromise<number>(() => {
21
21
  t.fail();
22
22
  });
23
23
  promise.resolve(-1);
@@ -37,3 +37,18 @@ test('exec', async (t) => {
37
37
  promise.resolve(20);
38
38
  t.is(await promise, 10);
39
39
  });
40
+
41
+ test('exec auto', async (t) => {
42
+ let r = 0;
43
+ const promise = createLazyPromise(() => {
44
+ r++;
45
+ return 10;
46
+ });
47
+ await sleep(10);
48
+ t.is(r, 0);
49
+ void promise.then(() => undefined);
50
+ t.is(await promise, 10);
51
+ t.is(r, 1);
52
+ t.is(await promise, 10);
53
+ t.is(r, 1);
54
+ });
@@ -1,3 +1,5 @@
1
+ import type { MaybePromise } from './MaybePromise';
2
+
1
3
  export type LazyPromise<T> = Promise<T> & {
2
4
  reject(reason?: any): void;
3
5
  resolve(v?: T | PromiseLike<T>): void;
@@ -8,7 +10,9 @@ export type LazyPromise<T> = Promise<T> & {
8
10
  * if you pass a function to it, it will be executed when the promise try to resolve.
9
11
  */
10
12
  export function createLazyPromise<T = any>(
11
- executor?: (resolve: LazyPromise<T>['resolve'], reject: LazyPromise<T>['reject']) => void,
13
+ executor?:
14
+ | ((resolve: LazyPromise<T>['resolve'], reject: LazyPromise<T>['reject']) => void)
15
+ | ((resolve: LazyPromise<T>['resolve'], reject: LazyPromise<T>['reject']) => MaybePromise<T>),
12
16
  ): LazyPromise<T> {
13
17
  const holder = {
14
18
  resolve(_: any): void {
@@ -43,7 +47,18 @@ export function createLazyPromise<T = any>(
43
47
  future.then = (...args) => {
44
48
  if (shouldExec) {
45
49
  shouldExec = false;
46
- executor(holder.resolve, holder.reject);
50
+ try {
51
+ // kind of bad
52
+ const result = executor(holder.resolve, holder.reject);
53
+ // ensure resolve/reject is called
54
+ if (result && 'then' in result) {
55
+ result.then(holder.resolve, holder.reject);
56
+ } else if (result !== undefined) {
57
+ holder.resolve(result);
58
+ }
59
+ } catch (e) {
60
+ holder.reject(e);
61
+ }
47
62
  }
48
63
  return then(...args);
49
64
  };
@@ -1,4 +1,4 @@
1
- import { MaybePromise } from '../asyncs/MaybePromise';
1
+ import type { MaybePromise } from '../asyncs/MaybePromise';
2
2
 
3
3
  let _copy: (s: any) => void;
4
4
 
@@ -0,0 +1,40 @@
1
+ // eslint-disable-next-line @typescript-eslint/consistent-type-imports
2
+ let nodeCrypto: Awaited<typeof import('node:crypto')>;
3
+ // globalThis.process?.release?.name
4
+
5
+ // typedoc error
6
+ if (!(process as any).browser) {
7
+ try {
8
+ if (typeof require === 'undefined') {
9
+ void import('node:crypto').then((v) => (nodeCrypto = v.default));
10
+ } else {
11
+ nodeCrypto = require('node:crypto');
12
+ }
13
+ } catch (e) {}
14
+ }
15
+
16
+ export let getRandomValues: <T extends Exclude<NodeJS.TypedArray, Float32Array | Float64Array>>(typedArray: T) => T =
17
+ globalThis.crypto?.getRandomValues || (globalThis as any).msCrypto?.getRandomValues || _getRandomValues;
18
+
19
+ function _getRandomValues<T extends Exclude<NodeJS.TypedArray, Float32Array | Float64Array>>(buf: T) {
20
+ if (nodeCrypto?.webcrypto?.getRandomValues) {
21
+ getRandomValues = nodeCrypto?.webcrypto?.getRandomValues;
22
+ return nodeCrypto.webcrypto.getRandomValues(buf);
23
+ }
24
+ if (nodeCrypto?.randomBytes) {
25
+ if (!(buf instanceof Uint8Array)) {
26
+ throw new TypeError('expected Uint8Array');
27
+ }
28
+ if (buf.length > 65536) {
29
+ const e: any = new Error();
30
+ e.code = 22;
31
+ e.message = `Failed to execute 'getRandomValues' on 'Crypto': The ArrayBufferView's byte length (${buf.length}) exceeds the number of bytes of entropy available via this API (65536).`;
32
+ e.name = 'QuotaExceededError';
33
+ throw e;
34
+ }
35
+ const bytes = nodeCrypto.randomBytes(buf.length);
36
+ buf.set(bytes);
37
+ return buf;
38
+ }
39
+ throw new Error('No secure random number generator available.');
40
+ }
@@ -0,0 +1,22 @@
1
+ import test from 'ava';
2
+ import { createULID, parseULID } from './ulid';
3
+
4
+ test('ulid', (t) => {
5
+ // monotonic
6
+ {
7
+ let lastTime = 0;
8
+ const ulid = createULID({
9
+ now: () => {
10
+ lastTime ||= Date.now();
11
+ return lastTime;
12
+ },
13
+ });
14
+
15
+ const ulid1 = ulid();
16
+ t.is(parseULID(ulid1).time, lastTime);
17
+
18
+ const ulid2 = ulid();
19
+ t.true(ulid1 < ulid2);
20
+ t.is(parseULID(ulid2).time, lastTime);
21
+ }
22
+ });
@@ -0,0 +1,182 @@
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
+ return str?.length === 26 && /^[0-9A-HJKMNP-TV-Z]{26}$/.test(str);
35
+ }
36
+
37
+ function replaceCharAt(str: string, index: number, char: string) {
38
+ if (index > str.length - 1) {
39
+ return str;
40
+ }
41
+ return str.substr(0, index) + char + str.substr(index + 1);
42
+ }
43
+
44
+ function incrementBase32(str: string): string {
45
+ let done;
46
+ let index = str.length;
47
+ let char;
48
+ let charIndex;
49
+ const maxCharIndex = ENCODING_LEN - 1;
50
+ while (!done && index-- >= 0) {
51
+ char = str[index];
52
+ charIndex = ENCODING.indexOf(char);
53
+ if (charIndex === -1) {
54
+ throw createError('incorrectly encoded string');
55
+ }
56
+ if (charIndex === maxCharIndex) {
57
+ str = replaceCharAt(str, index, ENCODING[0]);
58
+ continue;
59
+ }
60
+ done = replaceCharAt(str, index, ENCODING[charIndex + 1]);
61
+ }
62
+ if (typeof done === 'string') {
63
+ return done;
64
+ }
65
+ throw createError('cannot increment this string');
66
+ }
67
+
68
+ function randomChar(prng: PRNG): string {
69
+ let rand = Math.floor(prng() * ENCODING_LEN);
70
+ if (rand === ENCODING_LEN) {
71
+ rand = ENCODING_LEN - 1;
72
+ }
73
+ return ENCODING.charAt(rand);
74
+ }
75
+
76
+ function encodeTime(now: number, len: number): string {
77
+ if (isNaN(now)) {
78
+ throw new Error(`${now} must be a number`);
79
+ }
80
+ if (now > TIME_MAX) {
81
+ throw createError(`cannot encode time greater than ${TIME_MAX}`);
82
+ }
83
+ if (now < 0) {
84
+ throw createError('time must be positive');
85
+ }
86
+ if (!Number.isInteger(now)) {
87
+ throw createError('time must be an integer');
88
+ }
89
+ let mod;
90
+ let str = '';
91
+ for (; len > 0; len--) {
92
+ mod = now % ENCODING_LEN;
93
+ str = ENCODING.charAt(mod) + str;
94
+ now = (now - mod) / ENCODING_LEN;
95
+ }
96
+ return str;
97
+ }
98
+
99
+ function encodeRandom(len: number, prng: PRNG): string {
100
+ let str = '';
101
+ for (; len > 0; len--) {
102
+ str = randomChar(prng) + str;
103
+ }
104
+ return str;
105
+ }
106
+
107
+ /**
108
+ * extract time & random from ulid
109
+ *
110
+ * @throws ULIDError
111
+ */
112
+ export function parseULID(id: string): { time: number; random: string } {
113
+ if (id.length !== TIME_LEN + RANDOM_LEN) {
114
+ throw createError('malformed ulid');
115
+ }
116
+ const time = id
117
+ .substr(0, TIME_LEN)
118
+ .split('')
119
+ .reverse()
120
+ .reduce((carry, char, index) => {
121
+ const encodingIndex = ENCODING.indexOf(char);
122
+ if (encodingIndex === -1) {
123
+ throw createError('invalid character found: ' + char);
124
+ }
125
+ return (carry += encodingIndex * Math.pow(ENCODING_LEN, index));
126
+ }, 0);
127
+ if (time > TIME_MAX) {
128
+ throw createError('malformed ulid, timestamp too large');
129
+ }
130
+ return { time, random: id.substring(TIME_LEN) };
131
+ }
132
+
133
+ function createPrng(): PRNG {
134
+ return () => {
135
+ const buffer = new Uint8Array(1);
136
+ getRandomValues(buffer);
137
+ return buffer[0] / 0xff;
138
+ };
139
+ }
140
+
141
+ /**
142
+ * create a ulid generator
143
+ */
144
+ export function createULID({
145
+ monotonic = true,
146
+ random = createPrng(),
147
+ now = Date.now,
148
+ }: { monotonic?: boolean; now?: () => number; random?: () => number } = {}) {
149
+ if (!monotonic) {
150
+ return function ulid(seedTime?: number): string {
151
+ seedTime ||= now();
152
+ return encodeTime(seedTime, TIME_LEN) + encodeRandom(RANDOM_LEN, random);
153
+ };
154
+ }
155
+
156
+ let lastTime: number = 0;
157
+ let lastRandom: string;
158
+ return function ulid(seedTime?: number): string {
159
+ seedTime ||= now();
160
+ if (seedTime <= lastTime) {
161
+ const incrementedRandom = (lastRandom = incrementBase32(lastRandom));
162
+ return encodeTime(lastTime, TIME_LEN) + incrementedRandom;
163
+ }
164
+ lastTime = seedTime;
165
+ const newRandom = (lastRandom = encodeRandom(RANDOM_LEN, random));
166
+ return encodeTime(seedTime, TIME_LEN) + newRandom;
167
+ };
168
+ }
169
+
170
+ /**
171
+ * default monotonic ulid generator
172
+ */
173
+ export let ulid: ULID = (...args) => {
174
+ if (_real) {
175
+ return _real(...args);
176
+ }
177
+ // delay initialize crypto
178
+ _real = createULID();
179
+ ulid = _real;
180
+ return _real(...args);
181
+ };
182
+ 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,18 @@ 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';
34
37
 
35
38
  // modules
36
39
  export { parseModuleId, type ParsedModuleId } from './modules/parseModuleId';
@@ -54,6 +57,7 @@ export { createTranslate } from './i18n/createTranslate';
54
57
  export { isBuffer } from './io/isBuffer';
55
58
  export { isTransferable } from './io/isTransferable';
56
59
  export { ArrayBuffers } from './io/ArrayBuffers';
60
+ export { Buffer } from './io/Buffer';
57
61
  export type { AbstractEncoding } from './io/AbstractEncoding';
58
62
 
59
63
  // browser
@@ -68,8 +72,10 @@ export { structuredClone } from './isomorphics/structuredClone';
68
72
 
69
73
  // crypto
70
74
  export { randomUUID } from './crypto/randomUUID';
75
+ export { getRandomValues } from './crypto/getRandomValues';
71
76
  export { sha1, sha256, sha384, sha512 } from './crypto/hashing';
72
77
  export { hex } from './crypto/base';
78
+ export { isULID, createULID, ulid, parseULID } from './crypto/ulid';
73
79
 
74
80
  // misc
75
81
  export { createRandom } from './maths/random';
@@ -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}