@wener/utils 1.1.4 → 1.1.6

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 (130) hide show
  1. package/README.md +11 -0
  2. package/dist/cjs/_commonjsHelpers-dfec268f.js +2 -0
  3. package/dist/cjs/_commonjsHelpers-dfec268f.js.map +1 -0
  4. package/dist/cjs/api-7db97ae3.js +1085 -0
  5. package/dist/cjs/api-7db97ae3.js.map +1 -0
  6. package/dist/cjs/index-a6d1d653.js +14 -0
  7. package/dist/cjs/index-a6d1d653.js.map +1 -0
  8. package/dist/cjs/index.js +1 -1
  9. package/dist/cjs/index.js.map +1 -1
  10. package/dist/cjs/multipart-parser-141ed517.js +3 -0
  11. package/dist/cjs/multipart-parser-141ed517.js.map +1 -0
  12. package/dist/cjs/server.js +1 -1
  13. package/dist/cjs/server.js.map +1 -1
  14. package/dist/esm/_commonjsHelpers-28e086c5.js +2 -0
  15. package/dist/esm/_commonjsHelpers-28e086c5.js.map +1 -0
  16. package/dist/esm/api-3f555472.js +1085 -0
  17. package/dist/esm/api-3f555472.js.map +1 -0
  18. package/dist/esm/index-b50fef91.js +14 -0
  19. package/dist/esm/index-b50fef91.js.map +1 -0
  20. package/dist/esm/index.js +1 -1
  21. package/dist/esm/index.js.map +1 -1
  22. package/dist/esm/multipart-parser-5c1d6ee9.js +3 -0
  23. package/dist/esm/multipart-parser-5c1d6ee9.js.map +1 -0
  24. package/dist/esm/server.js +1 -1
  25. package/dist/esm/server.js.map +1 -1
  26. package/dist/system/_commonjsHelpers-07f370a7.js +2 -0
  27. package/dist/system/_commonjsHelpers-07f370a7.js.map +1 -0
  28. package/dist/system/api-dc50ebac.js +1085 -0
  29. package/dist/system/api-dc50ebac.js.map +1 -0
  30. package/dist/system/index-8f1807ba.js +14 -0
  31. package/dist/system/index-8f1807ba.js.map +1 -0
  32. package/dist/system/index.js +1 -1
  33. package/dist/system/index.js.map +1 -1
  34. package/dist/system/multipart-parser-53518ee9.js +3 -0
  35. package/dist/system/multipart-parser-53518ee9.js.map +1 -0
  36. package/dist/system/server.js +1 -1
  37. package/dist/system/server.js.map +1 -1
  38. package/lib/asyncs/createLazyPromise.js +55 -0
  39. package/lib/asyncs/createLazyPromise.js.map +1 -0
  40. package/lib/crypto/randomUUID.js +3 -5
  41. package/lib/crypto/randomUUID.js.map +1 -1
  42. package/lib/i18n/createTranslate.js +37 -0
  43. package/lib/i18n/createTranslate.js.map +1 -0
  44. package/lib/index.js +15 -7
  45. package/lib/index.js.map +1 -1
  46. package/lib/io/isBuffer.js.map +1 -1
  47. package/lib/io/isTransferable.js +23 -0
  48. package/lib/io/isTransferable.js.map +1 -0
  49. package/lib/isomorphics/structuredClone.js +70 -0
  50. package/lib/isomorphics/structuredClone.js.map +1 -0
  51. package/lib/langs/classOf.js +6 -0
  52. package/lib/langs/classOf.js.map +1 -0
  53. package/lib/{validations/dequal.js → langs/deepEqual.js} +7 -7
  54. package/lib/langs/deepEqual.js.map +1 -0
  55. package/lib/{validations/shallow.js → langs/shallowEqual.js} +3 -3
  56. package/lib/langs/shallowEqual.js.map +1 -0
  57. package/lib/modules/isModule.js.map +1 -1
  58. package/lib/modules/parseModuleId.js.map +1 -1
  59. package/lib/objects/get.js +14 -0
  60. package/lib/objects/get.js.map +1 -0
  61. package/lib/objects/parseObjectPath.js +27 -0
  62. package/lib/objects/parseObjectPath.js.map +1 -0
  63. package/lib/objects/set.js +36 -0
  64. package/lib/objects/set.js.map +1 -0
  65. package/lib/server/polyfillBrowser.js +12 -0
  66. package/lib/server/polyfillBrowser.js.map +1 -0
  67. package/lib/server/polyfillCrypto.js +10 -0
  68. package/lib/server/polyfillCrypto.js.map +1 -0
  69. package/lib/server/polyfillFetch.js +31 -0
  70. package/lib/server/polyfillFetch.js.map +1 -0
  71. package/lib/server/polyfillJsDom.js +49 -0
  72. package/lib/server/polyfillJsDom.js.map +1 -0
  73. package/lib/server.js +4 -1
  74. package/lib/server.js.map +1 -1
  75. package/lib/{formats → strings}/formatBytes.js +0 -0
  76. package/lib/{formats → strings}/formatBytes.js.map +1 -1
  77. package/lib/strings/renderTemplate.js +25 -0
  78. package/lib/strings/renderTemplate.js.map +1 -0
  79. package/lib/validations/isUUID.js +6 -0
  80. package/lib/validations/isUUID.js.map +1 -0
  81. package/package.json +14 -4
  82. package/src/asyncs/createLazyPromise.test.ts +39 -0
  83. package/src/asyncs/createLazyPromise.ts +63 -0
  84. package/src/crypto/hashing.test.ts +11 -7
  85. package/src/crypto/randomUUID.ts +3 -4
  86. package/src/i18n/createTranslate.test.ts +155 -0
  87. package/src/i18n/createTranslate.ts +52 -0
  88. package/src/index.ts +26 -9
  89. package/src/io/isBuffer.test.ts +7 -0
  90. package/src/io/isBuffer.ts +5 -1
  91. package/src/io/isTransferable.test.ts +10 -0
  92. package/src/io/isTransferable.ts +50 -0
  93. package/src/isomorphics/structuredClone.test.ts +14 -0
  94. package/src/isomorphics/structuredClone.ts +85 -0
  95. package/src/langs/classOf.ts +3 -0
  96. package/src/{validations/dequal.test.ts → langs/deepEqual.test.ts} +2 -2
  97. package/src/{validations/dequal.ts → langs/deepEqual.ts} +5 -5
  98. package/src/langs/langs.test.ts +23 -0
  99. package/src/{validations/shallow.ts → langs/shallowEqual.ts} +1 -1
  100. package/src/logging/logger.test.ts +18 -0
  101. package/src/modules/isModule.ts +8 -1
  102. package/src/modules/parseModuleId.ts +5 -0
  103. package/src/objects/get.test.ts +116 -0
  104. package/src/objects/get.ts +49 -0
  105. package/src/objects/parseObjectPath.test.ts +18 -0
  106. package/src/objects/parseObjectPath.ts +40 -0
  107. package/src/objects/set.test.ts +405 -0
  108. package/src/objects/set.ts +48 -0
  109. package/src/server/polyfillBrowser.test.ts +15 -0
  110. package/src/server/polyfillBrowser.ts +9 -0
  111. package/src/server/polyfillCrypto.ts +7 -0
  112. package/src/server/polyfillFetch.ts +29 -0
  113. package/src/server/polyfillJsDom.ts +84 -0
  114. package/src/server.ts +4 -1
  115. package/src/{formats → strings}/formatBytes.ts +0 -0
  116. package/src/strings/renderTemplate.test.ts +25 -0
  117. package/src/strings/renderTemplate.ts +34 -0
  118. package/src/validations/isUUID.ts +3 -0
  119. package/tsconfig.json +0 -4
  120. package/lib/asyncs/LazyPromise.js +0 -27
  121. package/lib/asyncs/LazyPromise.js.map +0 -1
  122. package/lib/server/polyfill.js +0 -8
  123. package/lib/server/polyfill.js.map +0 -1
  124. package/lib/strings/templates.js +0 -8
  125. package/lib/strings/templates.js.map +0 -1
  126. package/lib/validations/dequal.js.map +0 -1
  127. package/lib/validations/shallow.js.map +0 -1
  128. package/src/asyncs/LazyPromise.ts +0 -29
  129. package/src/server/polyfill.ts +0 -5
  130. package/src/strings/templates.ts +0 -13
@@ -0,0 +1,39 @@
1
+ import test from 'ava';
2
+ import { createLazyPromise } from './createLazyPromise';
3
+ import { sleep } from './sleep';
4
+
5
+ test('basic', async (t) => {
6
+ let promise = createLazyPromise();
7
+ let r = 0;
8
+ promise.then((v) => (r = v));
9
+ t.is(r, 0);
10
+ const { resolve, reject } = promise;
11
+ t.truthy(resolve);
12
+ t.truthy(reject);
13
+ resolve(1);
14
+ t.is(r, 0);
15
+ await promise;
16
+ t.is(r, 1);
17
+ });
18
+
19
+ test('manual resolve skip exec', async (t) => {
20
+ let promise = createLazyPromise(() => {
21
+ t.fail();
22
+ });
23
+ promise.resolve(-1);
24
+ t.is(await promise, -1);
25
+ });
26
+
27
+ test('exec', async (t) => {
28
+ let r = 0;
29
+ let promise = createLazyPromise((resolve) => {
30
+ r++;
31
+ resolve(10);
32
+ });
33
+ await sleep(10);
34
+ t.is(r, 0);
35
+ t.is(await promise, 10);
36
+ t.is(r, 1);
37
+ promise.resolve(20);
38
+ t.is(await promise, 10);
39
+ });
@@ -0,0 +1,63 @@
1
+ export type LazyPromise<T> = Promise<T> & {
2
+ reject(reason?: any): void;
3
+ resolve(v?: T | PromiseLike<T>): void;
4
+ };
5
+
6
+ /**
7
+ * createLazyPromise return a promise that can be resolved or rejected manually.
8
+ * if you pass a function to it, it will be executed when the promise try to resolve.
9
+ */
10
+ export function createLazyPromise<T = any>(
11
+ executor?: (resolve: LazyPromise<T>['resolve'], reject: LazyPromise<T>['reject']) => void,
12
+ ): LazyPromise<T> {
13
+ const holder = {
14
+ resolve(_: any): void {
15
+ throw new Error('pending resolve');
16
+ },
17
+ reject(_: any): void {
18
+ throw new Error('pending reject');
19
+ },
20
+ };
21
+ let future = Object.assign(
22
+ new Promise<T>((resolve, reject) => {
23
+ holder.reject = reject;
24
+ holder.resolve = resolve;
25
+ }),
26
+ {
27
+ resolve(v: any) {
28
+ holder.resolve(v);
29
+ },
30
+ reject(v: any) {
31
+ holder.resolve(v);
32
+ },
33
+ },
34
+ );
35
+ if (executor) {
36
+ const r = holder.resolve;
37
+ let shouldExec = true;
38
+ holder.resolve = (v: any) => {
39
+ shouldExec = false;
40
+ r(v);
41
+ };
42
+ const then = future.then.bind(future);
43
+ future.then = (...args) => {
44
+ if (shouldExec) {
45
+ shouldExec = false;
46
+ executor(holder.resolve, holder.reject);
47
+ }
48
+ return then(...args);
49
+ };
50
+ const like = holder as LazyPromise<T>;
51
+ like.then = future.then;
52
+ like.catch = future.catch.bind(future);
53
+ if (future.finally) like.finally = future.finally;
54
+
55
+ Object.defineProperty(like, Symbol.species, {
56
+ get() {
57
+ return Promise;
58
+ },
59
+ });
60
+ return like;
61
+ }
62
+ return future;
63
+ }
@@ -1,13 +1,12 @@
1
1
  import test from 'ava';
2
+ import { polyfillCrypto } from '../server/polyfillCrypto';
3
+ import { isUUID } from '../validations/isUUID';
2
4
  import { sha1, sha256, sha384, sha512 } from './hashing';
3
5
  import { hex } from './hex';
4
- import { randomUUID } from './randomUUID';
6
+ import { _randomUUID } from './randomUUID';
5
7
 
6
- test.before(async (t) => {
7
- if (!('crypto' in globalThis)) {
8
- (globalThis as any).crypto = (await import('node:crypto')).webcrypto;
9
- t.log(`load node:crypto`);
10
- }
8
+ test.before(async () => {
9
+ await polyfillCrypto();
11
10
  });
12
11
 
13
12
  test('sha', async (t) => {
@@ -22,5 +21,10 @@ test('sha', async (t) => {
22
21
  hex(await sha512('')),
23
22
  'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e',
24
23
  );
25
- t.regex(randomUUID(), /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
24
+ });
25
+
26
+ test('randomUUID', (t) => {
27
+ for (let i = 0; i < 20; i++) {
28
+ t.true(isUUID(_randomUUID()));
29
+ }
26
30
  });
@@ -1,10 +1,9 @@
1
1
  /**
2
2
  * generate random UUIDv4
3
3
  */
4
- export function randomUUID() {
5
- if ('randomUUID' in crypto) {
6
- return crypto.randomUUID();
7
- }
4
+ export const randomUUID: () => string = globalThis.crypto?.randomUUID || _randomUUID;
5
+
6
+ export function _randomUUID() {
8
7
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
9
8
  const r = (Math.random() * 16) | 0;
10
9
  const v = c === 'x' ? r : (r & 0x3) | 0x8;
@@ -0,0 +1,155 @@
1
+ import test from 'ava';
2
+ import { createTranslate } from './createTranslate';
3
+
4
+ test('exports', (t) => {
5
+ let out = createTranslate();
6
+ t.is(typeof out, 'object', 'returns an object');
7
+ t.is(typeof out.t, 'function', '~> has "t" function');
8
+ t.is(typeof out.dict, 'function', '~> has "set" function');
9
+ t.is(typeof out.locale, 'function', '~> has "locale" function');
10
+ });
11
+
12
+ test('usage', (t) => {
13
+ let ctx = createTranslate({
14
+ en: { hello: 'Hello, {{name}}!' },
15
+ es: { hello: 'Hola {{name}}!' },
16
+ pt: { foo: 'foo {{name}}~!' },
17
+ });
18
+
19
+ t.deepEqual(ctx.dict('en'), { hello: 'Hello, {{name}}!' });
20
+
21
+ t.is(ctx.dict('foobar'), undefined);
22
+
23
+ let foo = ctx.t('hello');
24
+ t.is(foo, '', '~> "" w/o locale');
25
+
26
+ t.is(ctx.locale('en'), 'en', '>>> ctx.locale()');
27
+
28
+ t.is(ctx.locale(), 'en');
29
+
30
+ let bar = ctx.t('hello');
31
+ t.not(bar, '', '(en) found "hello" key');
32
+ t.is(bar, 'Hello, !', '~> interpolations empty if missing param');
33
+
34
+ let baz = ctx.t('hello', { name: 'world' });
35
+ t.is(baz, 'Hello, world!', '~> interpolations successful');
36
+
37
+ let bat = ctx.t('hello', { name: 'world' }, 'es');
38
+ t.not(bat, '', '(es) found "hello" key');
39
+ t.is(bat, 'Hola world!', '~> success');
40
+
41
+ t.is(ctx.t('hello', { name: 'world' }, 'pt'), '', '(pt) did NOT find "hello" key');
42
+
43
+ t.is(ctx.dict('pt', { hello: 'Oí {{name}}!' }), undefined, '>>> ctx.dict()');
44
+
45
+ let quz = ctx.t('hello', { name: 'world' }, 'pt');
46
+ t.not(quz, '', '(pt) found "hello" key');
47
+ t.is(quz, 'Oí world!', '~> success');
48
+
49
+ let qut = ctx.t('foo', { name: 'bar' }, 'pt');
50
+ t.not(qut, '', '(pt) found "foo" key');
51
+ t.is(qut, 'foo bar~!', '~> success');
52
+
53
+ t.is(ctx.locale('es'), 'es', '>>> ctx.locale()');
54
+
55
+ t.is(ctx.locale(), 'es');
56
+ t.is(ctx.locale(''), 'es');
57
+ t.is(ctx.locale(false as any), 'es');
58
+ t.is(ctx.locale(null as any), 'es');
59
+ t.is(ctx.locale(0 as any), 'es');
60
+
61
+ let qux = ctx.t('hello', { name: 'default' });
62
+ t.not(qux, '', '(es) found "hello" key');
63
+ t.is(qux, 'Hola default!', '~> success');
64
+
65
+ t.is(ctx.t('hello', { name: 'world' }, 'de'), '', '(de) did NOT find "hello" key');
66
+
67
+ t.is(ctx.dict('de', { hello: 'Hallo {{name}}!' }), undefined, '>>> ctx.dict(de)');
68
+
69
+ let qar = ctx.t('hello', { name: 'world' }, 'de');
70
+ t.not(qar, '', '(de) found "hello" key');
71
+ t.is(qar, 'Hallo world!', '~> success');
72
+ });
73
+
74
+ test('functional', (t) => {
75
+ let ctx = createTranslate({
76
+ en: {
77
+ hello(value: any) {
78
+ return `hello ${value || 'stranger'}~!`;
79
+ },
80
+ },
81
+ });
82
+
83
+ ctx.locale('en');
84
+
85
+ let foo = ctx.t('hello');
86
+ t.is(foo, 'hello stranger~!', '~> called function w/o param');
87
+
88
+ let bar = ctx.t('hello', 'world' as any);
89
+ t.is(bar, 'hello world~!', '~> called function w/ param (string)');
90
+
91
+ let baz = ctx.t('hello', [1, 2, 3]);
92
+ t.is(baz, 'hello 1,2,3~!', '~> called function w/ param (array)');
93
+ });
94
+
95
+ test('nested', (t) => {
96
+ let ctx = createTranslate({
97
+ en: {
98
+ fruits: {
99
+ apple: 'apple',
100
+ orange: 'orange',
101
+ grape: 'grape',
102
+ },
103
+ },
104
+ es: {
105
+ fruits: {
106
+ apple: 'manzana',
107
+ orange: 'naranja',
108
+ grape: 'uva',
109
+ },
110
+ },
111
+ });
112
+
113
+ ctx.locale('en');
114
+ t.is(ctx.t('fruits.apple'), 'apple', '(en) fruits.apple');
115
+ t.is(ctx.t('fruits.orange'), 'orange', '(en) fruits.orange');
116
+ t.is(ctx.t(['fruits', 'grape']), 'grape', '(en) ["fruits","grape"]');
117
+ t.is(ctx.t('fruits.404'), '', '(en) fruits.404 ~> ""');
118
+ t.is(ctx.t('error.404'), '', '(en) error.404 ~> ""');
119
+
120
+ ctx.locale('es');
121
+ t.is(ctx.t('fruits.apple'), 'manzana', '(es) fruits.apple');
122
+ t.is(ctx.t('fruits.orange'), 'naranja', '(es) fruits.orange');
123
+ t.is(ctx.t(['fruits', 'grape']), 'uva', '(es) ["fruits","grape"]');
124
+ t.is(ctx.t('fruits.404'), '', '(es) fruits.404 ~> ""');
125
+ t.is(ctx.t('error.404'), '', '(es) error.404 ~> ""');
126
+ });
127
+
128
+ test('arrays', (t) => {
129
+ let ctx = createTranslate({
130
+ en: {
131
+ foo: '{{0}} + {{1}} = {{2}}',
132
+ bar: [
133
+ {
134
+ baz: 'roses are {{colors.0}}, violets are {{colors.1}}',
135
+ },
136
+ ],
137
+ },
138
+ });
139
+
140
+ ctx.locale('en');
141
+
142
+ t.is(ctx.t('foo', [1, 2, 3]), '1 + 2 = 3', '~> foo');
143
+
144
+ t.is(ctx.t('bar.0.baz', { colors: ['red', 'blue'] }), 'roses are red, violets are blue', '~> bar.0.baz');
145
+ });
146
+
147
+ test('invalid value', (t) => {
148
+ let ctx = createTranslate({
149
+ en: {
150
+ foo: ['bar'],
151
+ },
152
+ });
153
+
154
+ t.deepEqual(ctx.t('foo', null as any, 'en'), ['bar']);
155
+ });
@@ -0,0 +1,52 @@
1
+ import { get } from '../objects/get';
2
+ import { ObjectPathLike } from '../objects/parseObjectPath';
3
+ import { renderTemplate } from '../strings/renderTemplate';
4
+
5
+ export interface Translate<T extends object> {
6
+ /** Get/Set the language key */
7
+ locale(lang?: string): string;
8
+
9
+ /** Define the dict of translations for a language */
10
+ dict(lang: string, dict: T): void;
11
+
12
+ /** Get the dict of translations for a language */
13
+ dict(lang: string): T;
14
+
15
+ /** Retrieve a translation segment for the current language */
16
+ t<X extends Record<string, any> | any[]>(key: ObjectPathLike, params?: X, lang?: string): string;
17
+ }
18
+
19
+ export function createTranslate<T extends object>(obj?: Record<string, T>): Translate<T> {
20
+ let locale = '';
21
+ const tree = obj || {};
22
+
23
+ return {
24
+ locale(lang) {
25
+ return (locale = lang || locale);
26
+ },
27
+
28
+ dict: ((lang, dict?) => {
29
+ if (dict) {
30
+ tree[lang] = Object.assign(tree[lang] || {}, dict);
31
+ return;
32
+ }
33
+ return tree[lang];
34
+ }) as Translate<T>['dict'],
35
+
36
+ t(key, params, lang) {
37
+ const val = get(tree[lang || locale], key, '') as any;
38
+ if (process.env.NODE_ENV === 'development') {
39
+ if (val == null) {
40
+ return console.error(
41
+ `[Translate] Missing the "${[].concat(key as any).join('.')}" key within the "${
42
+ lang || locale
43
+ }" dictionary`,
44
+ );
45
+ }
46
+ }
47
+ if (typeof val === 'function') return val(params);
48
+ if (typeof val === 'string') return renderTemplate(val, params!, 'common');
49
+ return val;
50
+ },
51
+ };
52
+ }
package/src/index.ts CHANGED
@@ -7,8 +7,13 @@ export {
7
7
  type MaybeArray,
8
8
  } from './arrays/MaybeArray';
9
9
 
10
+ // object
11
+ export { get } from './objects/get';
12
+ export { set } from './objects/set';
13
+ export { parseObjectPath } from './objects/parseObjectPath';
14
+
10
15
  // async
11
- export { createLazyPromise, type LazyPromise } from './asyncs/LazyPromise';
16
+ export { createLazyPromise, type LazyPromise } from './asyncs/createLazyPromise';
12
17
  export { setAsyncInterval, clearAsyncInterval } from './asyncs/AsyncInterval';
13
18
  export { type MaybePromise } from './asyncs/MaybePromise';
14
19
 
@@ -21,12 +26,15 @@ export { isPromise } from './asyncs/isPromise';
21
26
  export { isClass } from './validations/isClass';
22
27
  export { isDefined } from './validations/isDefined';
23
28
  export { isEmptyObject } from './validations/isEmptyObject';
24
- export { shallow } from './validations/shallow';
25
- export { dequal } from './validations/dequal';
29
+ export { shallowEqual } from './langs/shallowEqual';
30
+ export { deepEqual } from './langs/deepEqual';
31
+ export { isUUID } from './validations/isUUID';
32
+
33
+ export { classOf } from './langs/classOf';
26
34
 
27
35
  // modules
28
36
  export { parseModuleId, type ParsedModuleId } from './modules/parseModuleId';
29
- export { isModule } from './modules/isModule';
37
+ export { isModule, type Module } from './modules/isModule';
30
38
 
31
39
  // logging
32
40
  export { type Logger, type LogLevel } from './logging/Logger';
@@ -36,22 +44,31 @@ export { createChildLogger } from './logging/createChildLogger';
36
44
 
37
45
  // strings
38
46
  export { pascalCase, camelCase } from './strings/camelCase';
39
- export { templateString } from './strings/templates';
47
+ export { renderTemplate } from './strings/renderTemplate';
48
+ export { formatBytes } from './strings/formatBytes';
40
49
 
41
- export { createRandom } from './maths/random';
50
+ // i18n
51
+ export { createTranslate } from './i18n/createTranslate';
52
+
53
+ // io
42
54
  export { isBuffer } from './io/isBuffer';
55
+ export { isTransferable } from './io/isTransferable';
43
56
 
57
+ // browser
44
58
  export { copy } from './browsers/copy';
45
59
  export { download } from './browsers/download';
46
60
  export { loadScripts, loadStyles } from './browsers/loaders';
47
61
  export { getFileFromDataTransfer } from './browsers/getFileFromDataTransfer';
48
62
 
63
+ // polyfills
49
64
  export { getGlobalThis } from './isomorphics/getGlobalThis';
50
-
51
- export { formatBytes } from './formats/formatBytes';
52
- export { urljoin } from './shim/urljoin';
65
+ export { structuredClone } from './isomorphics/structuredClone';
53
66
 
54
67
  // crypto
55
68
  export { randomUUID } from './crypto/randomUUID';
56
69
  export { sha1, sha256, sha384, sha512 } from './crypto/hashing';
57
70
  export { hex } from './crypto/hex';
71
+
72
+ // misc
73
+ export { createRandom } from './maths/random';
74
+ export { urljoin } from './shim/urljoin';
@@ -0,0 +1,7 @@
1
+ import test from 'ava';
2
+ import { Buffer } from 'node:buffer';
3
+ import { isBuffer } from './isBuffer';
4
+
5
+ test('isBuffer', (t) => {
6
+ t.true(isBuffer(Buffer.from('')));
7
+ });
@@ -1,4 +1,8 @@
1
- // https://github.com/feross/is-buffer/blob/master/index.js
1
+ /**
2
+ * check {@code obj} is Buffer
3
+ *
4
+ * {@link https://github.com/feross/is-buffer feross/is-buffer}
5
+ */
2
6
  export function isBuffer(obj: any): obj is Buffer {
3
7
  return (
4
8
  obj != null &&
@@ -0,0 +1,10 @@
1
+ import test from 'ava';
2
+ import { Buffer } from 'node:buffer';
3
+ import { isTransferable } from './isTransferable';
4
+
5
+ test('isTransferable', (t) => {
6
+ t.false(isTransferable(0));
7
+ t.false(isTransferable(Buffer.from('')));
8
+ t.true(new ArrayBuffer(0) instanceof ArrayBuffer);
9
+ t.true(isTransferable(new ArrayBuffer(0)));
10
+ });
@@ -0,0 +1,50 @@
1
+ /**
2
+ * transferable object pass between workers, can work with structuredClone
3
+ *
4
+ * - Chrome 87, FF 103, Safari X, NodeJS X
5
+ *
6
+ * {@link https://developer.mozilla.org/en-US/docs/Glossary/Transferable_objects | Transferable objects}
7
+ */
8
+ export function isTransferable(v: any): v is TransferableObject {
9
+ _ctors ||= ctors();
10
+ return _ctors.some((ctor) => v instanceof ctor);
11
+ }
12
+
13
+ let _ctors: any[];
14
+
15
+ function ctors() {
16
+ const o: any = globalThis.window || globalThis || global;
17
+ return [
18
+ o.ArrayBuffer,
19
+ o.MessagePort,
20
+ o.ReadableStream,
21
+ o.WritableStream,
22
+ o.TransformStream,
23
+ o.AudioData,
24
+ o.ImageBitmap,
25
+ o.VideoFrame,
26
+ o.OffscreenCanvas,
27
+ o.RTCDataChannel,
28
+ ].filter(Boolean);
29
+ }
30
+
31
+ export type TransferableObject =
32
+ | Transferable
33
+ | ArrayBuffer
34
+ | MessagePort
35
+ | ReadableStream
36
+ | WritableStream
37
+ | TransformStream
38
+ | AudioData
39
+ | ImageBitmap
40
+ | VideoFrame
41
+ | OffscreenCanvas
42
+ | RTCDataChannel;
43
+
44
+ declare global {
45
+ interface OffscreenCanvas {}
46
+
47
+ interface VideoFrame {}
48
+
49
+ interface AudioData {}
50
+ }
@@ -0,0 +1,14 @@
1
+ import test from 'ava';
2
+ import { classOf } from '../langs/classOf';
3
+ import { _clone } from './structuredClone';
4
+
5
+ test('structuredClone', (t) => {
6
+ for (const [k, v] of [
7
+ ['', ''],
8
+ [Number(1), 1],
9
+ ]) {
10
+ let c = _clone(k);
11
+ t.deepEqual(c, v);
12
+ t.is(classOf(c), classOf(v));
13
+ }
14
+ });
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Chrome 98, Safari 15.4
3
+ *
4
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/structuredClone structuredClone}
5
+ * {@link https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.structured-clone.js core-js}
6
+ */
7
+ import { classOf } from '../langs/classOf';
8
+
9
+ export const structuredClone: <T>(value: T, options?: StructuredSerializeOptions) => T =
10
+ globalThis.structuredClone || _clone;
11
+
12
+ function set(obj: any, key: any, val: any) {
13
+ if (typeof val.value === 'object') val.value = _clone(val.value);
14
+ if (!val.enumerable || val.get || val.set || !val.configurable || !val.writable || key === '__proto__') {
15
+ Object.defineProperty(obj, key, val);
16
+ } else obj[key] = val.value;
17
+ }
18
+
19
+ /**
20
+ * {@link https://github.com/lukeed/klona/blob/master/src/full.js klona}
21
+ */
22
+ export function _clone(x: any): any {
23
+ // too complex
24
+ // https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/web.structured-clone.js
25
+
26
+ if (typeof x !== 'object') return x;
27
+
28
+ let i = 0;
29
+ let k;
30
+ let list;
31
+ let tmp: any;
32
+ const str = classOf(x);
33
+ switch (str) {
34
+ case 'Array':
35
+ tmp = Array(x.length);
36
+ break;
37
+ case 'Object':
38
+ tmp = Object.create(x.__proto__ || null);
39
+ break;
40
+ case 'Set':
41
+ tmp = new Set();
42
+ x.forEach(function (val: any) {
43
+ tmp.add(_clone(val));
44
+ });
45
+ break;
46
+ case 'Map':
47
+ tmp = new Map();
48
+ x.forEach(function (val: any, key: any) {
49
+ tmp.set(_clone(key), _clone(val));
50
+ });
51
+ break;
52
+ case 'Date':
53
+ tmp = new Date(+x);
54
+ break;
55
+ case 'RegExp':
56
+ tmp = new RegExp(x.source, x.flags);
57
+ break;
58
+ case 'DataView':
59
+ tmp = new x.constructor(_clone(x.buffer));
60
+ break;
61
+ case 'ArrayBuffer':
62
+ tmp = x.slice(0);
63
+ break;
64
+ default:
65
+ // typed arrays
66
+ if (str.endsWith('Array')) {
67
+ // ArrayBuffer.isView(x)
68
+ // ~> `new` bcuz `Buffer.slice` => ref
69
+ tmp = new x.constructor(x);
70
+ }
71
+ }
72
+
73
+ if (tmp) {
74
+ for (list = Object.getOwnPropertySymbols(x); i < list.length; i++) {
75
+ set(tmp, list[i], Object.getOwnPropertyDescriptor(x, list[i]));
76
+ }
77
+
78
+ for (i = 0, list = Object.getOwnPropertyNames(x); i < list.length; i++) {
79
+ if (Object.hasOwnProperty.call(tmp, (k = list[i])) && tmp[k] === x[k]) continue;
80
+ set(tmp, k, Object.getOwnPropertyDescriptor(x, k));
81
+ }
82
+ }
83
+
84
+ return tmp || x;
85
+ }
@@ -0,0 +1,3 @@
1
+ export function classOf(o: any) {
2
+ return Object.prototype.toString.call(o).slice(8, -1);
3
+ }
@@ -1,9 +1,9 @@
1
1
  import test from 'ava';
2
- import { dequal } from './dequal';
2
+ import { deepEqual } from './deepEqual';
3
3
 
4
4
  test('deep equal', (t) => {
5
5
  t.true(
6
- dequal(
6
+ deepEqual(
7
7
  {
8
8
  a: null,
9
9
  b: Infinity,
@@ -3,7 +3,7 @@ const hasElementType = typeof Element !== 'undefined';
3
3
 
4
4
  function find(iter: any, tar: any, key?: any) {
5
5
  for (key of iter.keys()) {
6
- if (dequal(key, tar)) return key;
6
+ if (deepEqual(key, tar)) return key;
7
7
  }
8
8
  }
9
9
 
@@ -12,7 +12,7 @@ function find(iter: any, tar: any, key?: any) {
12
12
  * @see {@link https://github.com/lukeed/dequal/blob/master/src/lite.js dequal/src/lite.js}
13
13
  * @see {@link https://github.com/FormidableLabs/react-fast-compare/blob/master/index.js react-fast-compare/index.js}
14
14
  */
15
- export function dequal(foo: any, bar: any) {
15
+ export function deepEqual(foo: any, bar: any) {
16
16
  let ctor, len, tmp;
17
17
  if (foo === bar) return true;
18
18
 
@@ -22,7 +22,7 @@ export function dequal(foo: any, bar: any) {
22
22
 
23
23
  if (ctor === Array) {
24
24
  if ((len = foo.length) === bar.length) {
25
- while (len-- && dequal(foo[len], bar[len]));
25
+ while (len-- && deepEqual(foo[len], bar[len]));
26
26
  }
27
27
  return len === -1;
28
28
  }
@@ -52,7 +52,7 @@ export function dequal(foo: any, bar: any) {
52
52
  tmp = find(bar, tmp);
53
53
  if (!tmp) return false;
54
54
  }
55
- if (!dequal(len[1], bar.get(tmp))) {
55
+ if (!deepEqual(len[1], bar.get(tmp))) {
56
56
  return false;
57
57
  }
58
58
  }
@@ -95,7 +95,7 @@ export function dequal(foo: any, bar: any) {
95
95
  }
96
96
 
97
97
  if (has.call(foo, ctor) && ++len && !has.call(bar, ctor)) return false;
98
- if (!(ctor in bar) || !dequal(foo[ctor], bar[ctor])) return false;
98
+ if (!(ctor in bar) || !deepEqual(foo[ctor], bar[ctor])) return false;
99
99
  }
100
100
  return Object.keys(bar).length === len;
101
101
  }