@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,405 @@
1
+ import test from 'ava';
2
+ import { set } from './set';
3
+
4
+ test('set basics', (t) => {
5
+ t.is(set({}, 'c', 3), undefined, 'should not give return value');
6
+ {
7
+ let item = { foo: 1 };
8
+ set(item, 'bar', 123);
9
+ t.is(item, item);
10
+ t.deepEqual(
11
+ item,
12
+ {
13
+ foo: 1,
14
+ bar: 123,
15
+ },
16
+ 'should mutate original object',
17
+ );
18
+ }
19
+ });
20
+
21
+ test('set objects', (t) => {
22
+ const prepare = (x: any) => ({ input: x, copy: JSON.parse(JSON.stringify(x)) });
23
+ const objects = (s: string, f: Function) => {
24
+ t.log(s);
25
+ f();
26
+ };
27
+ const orig = set;
28
+
29
+ function run(isMerge: boolean) {
30
+ const set = (a: any, b: any, c: any) => orig(a, b, c, isMerge);
31
+ const verb = isMerge ? 'merge' : 'overwrite';
32
+ objects(`should ${verb} existing object value :: simple`, () => {
33
+ let { input } = prepare({
34
+ hello: { a: 1 },
35
+ });
36
+
37
+ set(input, 'hello', { foo: 123 });
38
+
39
+ if (isMerge) {
40
+ t.deepEqual(input, {
41
+ hello: {
42
+ a: 1,
43
+ foo: 123,
44
+ },
45
+ });
46
+ } else {
47
+ t.deepEqual(input, {
48
+ hello: { foo: 123 },
49
+ });
50
+ }
51
+ });
52
+
53
+ objects(`should ${verb} existing object value :: nested`, () => {
54
+ let { input, copy } = prepare({
55
+ a: {
56
+ b: {
57
+ c: 123,
58
+ },
59
+ },
60
+ });
61
+
62
+ set(input, 'a.b', { foo: 123 });
63
+
64
+ if (isMerge) {
65
+ Object.assign(copy.a.b, { foo: 123 });
66
+ } else {
67
+ copy.a.b = { foo: 123 };
68
+ }
69
+
70
+ t.deepEqual(input, copy);
71
+ });
72
+
73
+ objects(`should ${verb} existing array value :: simple`, () => {
74
+ let { input } = prepare([{ foo: 1 }]);
75
+
76
+ set(input, '0', { bar: 2 });
77
+
78
+ if (isMerge) {
79
+ t.deepEqual(input, [{ foo: 1, bar: 2 }]);
80
+ } else {
81
+ t.deepEqual(input, [{ bar: 2 }]);
82
+ }
83
+ });
84
+
85
+ objects(`should ${verb} existing array value :: nested`, () => {
86
+ let { input } = prepare([
87
+ { name: 'bob', age: 56, friends: ['foobar'] },
88
+ { name: 'alice', age: 47, friends: ['mary'] },
89
+ ]);
90
+
91
+ set(input, '0', { age: 57, friends: ['alice', 'mary'] });
92
+ set(input, '1', { friends: ['bob'] });
93
+ set(input, '2', { name: 'mary', age: 49, friends: ['bob'] });
94
+
95
+ if (isMerge) {
96
+ t.deepEqual(input, [
97
+ { name: 'bob', age: 57, friends: ['alice', 'mary'] },
98
+ { name: 'alice', age: 47, friends: ['bob'] },
99
+ { name: 'mary', age: 49, friends: ['bob'] },
100
+ ]);
101
+ } else {
102
+ t.deepEqual(input, [
103
+ { age: 57, friends: ['alice', 'mary'] },
104
+ { friends: ['bob'] },
105
+ { name: 'mary', age: 49, friends: ['bob'] },
106
+ ]);
107
+ }
108
+ });
109
+ }
110
+
111
+ run(true);
112
+ run(false);
113
+ });
114
+
115
+ test('set arrays', (t) => {
116
+ const arrays = (s: string, f: Function) => {
117
+ t.log(s);
118
+ f();
119
+ };
120
+ arrays('should create array instead of object via numeric key :: simple', () => {
121
+ let input: any = { a: 1 };
122
+ set(input, 'e.0', 2);
123
+ t.true(Array.isArray(input.e));
124
+ t.is(input.e[0], 2);
125
+ t.deepEqual(input, {
126
+ a: 1,
127
+ e: [2],
128
+ });
129
+ });
130
+
131
+ arrays('should create array instead of object via numeric key :: nested', () => {
132
+ let input: any = { a: 1 };
133
+ set(input, 'e.0.0', 123);
134
+ t.true(input.e instanceof Array);
135
+ t.is(input.e[0][0], 123);
136
+ t.deepEqual(input, {
137
+ a: 1,
138
+ e: [[123]],
139
+ });
140
+ });
141
+
142
+ arrays('should be able to create object inside of array', () => {
143
+ let input: any = {};
144
+ set(input, ['x', '0', 'z'], 123);
145
+ t.true(input.x instanceof Array);
146
+ t.deepEqual(input, {
147
+ x: [{ z: 123 }],
148
+ });
149
+ });
150
+
151
+ arrays('should create arrays with hole(s) if needed', () => {
152
+ let input: any = {};
153
+ set(input, ['x', '1', 'z'], 123);
154
+ t.true(input.x instanceof Array);
155
+ t.deepEqual(input, {
156
+ x: [, { z: 123 }],
157
+ });
158
+ });
159
+
160
+ arrays('should create object from decimal-like key :: array :: zero :: string', () => {
161
+ let input: any = {};
162
+ set(input, ['x', '10.0', 'z'], 123);
163
+ t.false(input.x instanceof Array);
164
+ t.deepEqual(input, {
165
+ x: {
166
+ '10.0': {
167
+ z: 123,
168
+ },
169
+ },
170
+ });
171
+ });
172
+
173
+ arrays('should create array from decimal-like key :: array :: zero :: number', () => {
174
+ let input: any = {};
175
+ set(input, ['x', 10.0, 'z'], 123);
176
+ t.true(input.x instanceof Array);
177
+
178
+ let x = Array(10);
179
+ x.push({ z: 123 });
180
+ t.deepEqual(input, { x });
181
+ });
182
+
183
+ arrays('should create object from decimal-like key :: array :: nonzero', () => {
184
+ let input: any = {};
185
+ set(input, ['x', '10.2', 'z'], 123);
186
+ t.false(input.x instanceof Array);
187
+ t.deepEqual(input, {
188
+ x: {
189
+ '10.2': {
190
+ z: 123,
191
+ },
192
+ },
193
+ });
194
+ });
195
+ });
196
+
197
+ test('set pollution', (t) => {
198
+ const pollution = (s: string, f: Function) => {
199
+ t.log(s);
200
+ f();
201
+ };
202
+ pollution('should protect against "__proto__" assignment', () => {
203
+ let input: any = { abc: 123 };
204
+ let before = input.__proto__;
205
+ set(input, '__proto__.hello', 123);
206
+
207
+ t.deepEqual(input.__proto__, before);
208
+ t.deepEqual(input, {
209
+ abc: 123,
210
+ });
211
+ });
212
+
213
+ pollution('should protect against "__proto__" assignment :: nested', () => {
214
+ let input: any = { abc: 123 };
215
+ let before = input.__proto__;
216
+ set(input, ['xyz', '__proto__', 'hello'], 123);
217
+
218
+ t.deepEqual(input.__proto__, before);
219
+ t.deepEqual(input, {
220
+ abc: 123,
221
+ xyz: {
222
+ // empty
223
+ },
224
+ });
225
+
226
+ t.is(input.hello, undefined);
227
+ });
228
+
229
+ pollution('should ignore "prototype" assignment', () => {
230
+ let input: any = { a: 123 };
231
+ set(input, 'a.prototype.hello', 'world');
232
+
233
+ t.is(input.a.prototype, undefined);
234
+ t.is(input.a.hello, undefined);
235
+
236
+ t.deepEqual(input, {
237
+ a: {
238
+ // converted, then aborted
239
+ },
240
+ });
241
+
242
+ t.is(JSON.stringify(input), '{"a":{}}');
243
+ });
244
+
245
+ pollution('should ignore "constructor" assignment :: direct', () => {
246
+ let input: any = { a: 123 };
247
+
248
+ function Custom() {
249
+ //
250
+ }
251
+
252
+ set(input, 'a.constructor', Custom);
253
+ t.not(input.a.constructor, Custom);
254
+ t.false(input.a instanceof Custom);
255
+
256
+ t.true(input.a.constructor instanceof Object, '~> 123 -> {}');
257
+ t.is(input.a.hasOwnProperty('constructor'), false);
258
+ t.deepEqual(input, { a: {} });
259
+ });
260
+
261
+ pollution('should ignore "constructor" assignment :: nested', () => {
262
+ let input: any = {};
263
+
264
+ set(input, 'constructor.prototype.hello', 'world');
265
+ t.is(input.hasOwnProperty('constructor'), false);
266
+ t.is(input.hasOwnProperty('hello'), false);
267
+
268
+ t.deepEqual(input, {
269
+ // empty
270
+ });
271
+ });
272
+
273
+ // Test for CVE-2022-25645 - CWE-1321
274
+ pollution('should ignore JSON.parse crafted object with "__proto__" key', () => {
275
+ let a: any = { b: { c: 1 } };
276
+ t.is(a.polluted, undefined);
277
+ set(a, 'b', JSON.parse('{"__proto__":{"polluted":"Yes!"}}'));
278
+ t.is(a.polluted, undefined);
279
+ });
280
+ });
281
+ test('set assigns', (t) => {
282
+ const assigns = (s: string, f: Function) => {
283
+ t.log(s);
284
+ f();
285
+ };
286
+ assigns('should add value to key path :: shallow :: string', () => {
287
+ let input: any = {};
288
+ set(input, 'abc', 123);
289
+ t.deepEqual(input, { abc: 123 });
290
+ });
291
+
292
+ assigns('should add value to key path :: shallow :: array', () => {
293
+ let input: any = {};
294
+ set(input, ['abc'], 123);
295
+ t.deepEqual(input, { abc: 123 });
296
+ });
297
+
298
+ assigns('should add value to key path :: nested :: string', () => {
299
+ let input: any = {};
300
+ set(input, 'a.b.c', 123);
301
+ t.deepEqual(input, {
302
+ a: {
303
+ b: {
304
+ c: 123,
305
+ },
306
+ },
307
+ });
308
+ });
309
+
310
+ assigns('should add value to key path :: nested :: array', () => {
311
+ let input: any = {};
312
+ set(input, ['a', 'b', 'c'], 123);
313
+ t.deepEqual(input, {
314
+ a: {
315
+ b: {
316
+ c: 123,
317
+ },
318
+ },
319
+ });
320
+ });
321
+
322
+ assigns('should create Array via integer key :: string', () => {
323
+ let input: any = {};
324
+ set(input, ['foo', '0'], 123);
325
+ t.true(input.foo instanceof Array);
326
+ t.deepEqual(input, {
327
+ foo: [123],
328
+ });
329
+ });
330
+
331
+ assigns('should create Array via integer key :: number', () => {
332
+ let input: any = {};
333
+ set(input, ['foo', 0], 123);
334
+ t.true(input.foo instanceof Array);
335
+ t.deepEqual(input, {
336
+ foo: [123],
337
+ });
338
+ });
339
+ });
340
+ test('set preserves', (t) => {
341
+ const preserves = (s: string, f: Function) => {
342
+ t.log(s);
343
+ f();
344
+ };
345
+ preserves('should preserve existing object structure', () => {
346
+ let input = {
347
+ a: {
348
+ b: {
349
+ c: 123,
350
+ },
351
+ },
352
+ };
353
+
354
+ set(input, 'a.b.x.y', 456);
355
+
356
+ t.deepEqual(input, {
357
+ a: {
358
+ b: {
359
+ c: 123,
360
+ x: {
361
+ y: 456,
362
+ },
363
+ },
364
+ },
365
+ });
366
+ });
367
+
368
+ preserves('should overwrite existing non-object values as object', () => {
369
+ let input = {
370
+ a: {
371
+ b: 123,
372
+ },
373
+ };
374
+
375
+ set(input, 'a.b.c', 'hello');
376
+
377
+ t.deepEqual(input, {
378
+ a: {
379
+ b: {
380
+ c: 'hello',
381
+ },
382
+ },
383
+ });
384
+ });
385
+
386
+ preserves('should preserve existing object tree w/ array value', () => {
387
+ let input = {
388
+ a: {
389
+ b: {
390
+ c: 123,
391
+ d: {
392
+ e: 5,
393
+ },
394
+ },
395
+ },
396
+ };
397
+
398
+ set(input, 'a.b.d.z', [1, 2, 3, 4]);
399
+
400
+ t.deepEqual(input.a.b.d, {
401
+ e: 5,
402
+ z: [1, 2, 3, 4],
403
+ });
404
+ });
405
+ });
@@ -0,0 +1,48 @@
1
+ import { ObjectKey, ObjectPath, parseObjectPath } from './parseObjectPath';
2
+
3
+ /**
4
+ * Deep set
5
+ *
6
+ * {@link https://github.com/lukeed/dset dset}
7
+ */
8
+ export function set<T extends object, V>(obj: T, key: ObjectKey | ObjectPath, val: V, merging = true) {
9
+ const path = parseObjectPath(key);
10
+ let i = 0;
11
+ const len = path.length;
12
+ let current: any = obj;
13
+ let x, k;
14
+ while (i < len) {
15
+ k = path[i++];
16
+ if (k === '__proto__' || k === 'constructor' || k === 'prototype') break;
17
+ // noinspection PointlessArithmeticExpressionJS
18
+ current = current[k] =
19
+ i === len
20
+ ? merging
21
+ ? merge(current[k], val)
22
+ : val
23
+ : typeof (x = current[k]) === typeof path
24
+ ? x
25
+ : // @ts-ignore hacky type check
26
+ path[i] * 0 !== 0 || !!~('' + path[i]).indexOf('.')
27
+ ? {}
28
+ : [];
29
+ }
30
+ }
31
+
32
+ export function merge(a: any, b: any) {
33
+ let k;
34
+ if (typeof a === 'object' && typeof b === 'object') {
35
+ if (Array.isArray(a) && Array.isArray(b)) {
36
+ for (k = 0; k < b.length; k++) {
37
+ a[k] = merge(a[k], b[k]);
38
+ }
39
+ } else {
40
+ for (k in b) {
41
+ if (k === '__proto__' || k === 'constructor' || k === 'prototype') break;
42
+ a[k] = merge(a[k], b[k]);
43
+ }
44
+ }
45
+ return a;
46
+ }
47
+ return b;
48
+ }
@@ -0,0 +1,15 @@
1
+ import test from 'ava';
2
+ import { polyfillBrowser } from './polyfillBrowser';
3
+
4
+ test.before(async () => {
5
+ await polyfillBrowser();
6
+ });
7
+
8
+ test('polyfillBrowser', (t) => {
9
+ t.truthy(fetch);
10
+ t.truthy(window);
11
+ t.truthy(document);
12
+ t.truthy(crypto);
13
+ // not the same
14
+ t.not(window, globalThis);
15
+ });
@@ -0,0 +1,9 @@
1
+ import { polyfillCrypto } from './polyfillCrypto';
2
+ import { polyfillFetch } from './polyfillFetch';
3
+ import { polyfillJsDom } from './polyfillJsDom';
4
+
5
+ export async function polyfillBrowser() {
6
+ await polyfillCrypto();
7
+ await polyfillFetch();
8
+ await polyfillJsDom();
9
+ }
@@ -0,0 +1,7 @@
1
+ export async function polyfillCrypto() {
2
+ if ('crypto' in globalThis) {
3
+ return false;
4
+ }
5
+ globalThis.crypto = (await import('node:crypto')).webcrypto as Crypto;
6
+ return true;
7
+ }
@@ -0,0 +1,29 @@
1
+ export async function polyfillFetch() {
2
+ if ('fetch' in globalThis) {
3
+ return false;
4
+ }
5
+ const {
6
+ default: fetch,
7
+ Response,
8
+ Headers,
9
+ Request,
10
+ AbortError,
11
+ FetchError,
12
+ FormData,
13
+ Blob,
14
+ File,
15
+ // @ts-ignore
16
+ } = await import('node-fetch');
17
+ Object.assign(globalThis, {
18
+ fetch,
19
+ Response,
20
+ Headers,
21
+ Request,
22
+ AbortError,
23
+ FetchError,
24
+ FormData,
25
+ Blob,
26
+ File,
27
+ });
28
+ return true;
29
+ }
@@ -0,0 +1,84 @@
1
+ import { ConstructorOptions, ResourceLoaderConstructorOptions } from 'jsdom';
2
+
3
+ export async function polyfillJsDom() {
4
+ if (typeof window !== 'undefined') {
5
+ return false;
6
+ }
7
+
8
+ const { ResourceLoader, JSDOM } = await import('jsdom');
9
+
10
+ // https://github.com/lukechilds/window/blob/master/src/index.js
11
+ class Window {
12
+ constructor(opts: ResourceLoaderConstructorOptions & ConstructorOptions = {}) {
13
+ const { proxy, strictSSL, userAgent, ...jsdomOpts } = opts;
14
+ const resources = new ResourceLoader({
15
+ proxy,
16
+ strictSSL,
17
+ userAgent,
18
+ });
19
+ return new JSDOM(
20
+ '',
21
+ Object.assign(jsdomOpts, {
22
+ resources,
23
+ }),
24
+ ).window;
25
+ }
26
+ }
27
+
28
+ // https://github.com/lukechilds/browser-env/blob/master/src/index.js
29
+ // Default jsdom config.
30
+ // These settings must override any custom settings to make sure we can iterate
31
+ // over the window object.
32
+ const defaultJsdomConfig = {
33
+ // features: {
34
+ // FetchExternalResources: false,
35
+ // ProcessExternalResources: false,
36
+ // },
37
+ };
38
+ // IIFE executed on import to return an array of global Node.js properties that
39
+ // conflict with global browser properties.
40
+ const protectedProperties = (() =>
41
+ Object.getOwnPropertyNames(new Window(defaultJsdomConfig)).filter(
42
+ (prop) => typeof globalThis[prop as keyof typeof globalThis] !== 'undefined',
43
+ ))();
44
+
45
+ function installEnv(...args: any[]) {
46
+ // Sets up global browser environment
47
+ // Extract options from args
48
+ const properties = args.filter((arg: any) => Array.isArray(arg))[0];
49
+ const userJsdomConfig = args.filter((arg: any) => !Array.isArray(arg))[0];
50
+
51
+ // Create window object
52
+ const window = new Window(Object.assign({}, userJsdomConfig, defaultJsdomConfig));
53
+
54
+ // Get all global browser properties
55
+ Object.getOwnPropertyNames(window)
56
+
57
+ // Remove protected properties
58
+ .filter((prop) => protectedProperties.indexOf(prop) === -1)
59
+
60
+ // If we're only applying specific required properties remove everything else
61
+ .filter((prop) => !(properties && properties.indexOf(prop) === -1))
62
+ .filter((prop) => {
63
+ switch (prop) {
64
+ case 'undefined':
65
+ return false;
66
+ }
67
+ return true;
68
+ })
69
+
70
+ // Copy what's left to the Node.js global scope
71
+ .forEach((prop) => {
72
+ // console.debug(`define globalThis.${prop}`);
73
+ Object.defineProperty(globalThis, prop, {
74
+ configurable: true,
75
+ get: () => window[prop as keyof Window] as any,
76
+ });
77
+ });
78
+
79
+ return window;
80
+ }
81
+
82
+ installEnv({ url: 'http://localhost' });
83
+ return true;
84
+ }
package/src/server.ts CHANGED
@@ -1 +1,4 @@
1
- export { polyfill } from './server/polyfill';
1
+ export { polyfillCrypto } from './server/polyfillCrypto';
2
+ export { polyfillFetch } from './server/polyfillFetch';
3
+ export { polyfillJsDom } from './server/polyfillJsDom';
4
+ export { polyfillBrowser } from './server/polyfillBrowser';
File without changes
@@ -0,0 +1,25 @@
1
+ import test from 'ava';
2
+ import { renderTemplate } from './renderTemplate';
3
+
4
+ test('renderTemplate', (t) => {
5
+ const obj = {
6
+ name: 'wener',
7
+ authors: [
8
+ {
9
+ name: 'wener',
10
+ },
11
+ ],
12
+ };
13
+ for (const [k, v] of Object.entries({
14
+ 'My name is ${name}': 'My name is wener',
15
+ 'My name is ${ authors[0].name }': 'My name is wener',
16
+ })) {
17
+ t.is(renderTemplate(k, obj), v);
18
+ }
19
+ t.is(
20
+ renderTemplate('My name is ${name}', (v) => v),
21
+ 'My name is name',
22
+ );
23
+ t.is(renderTemplate('My name is ${name}', obj, 'common'), 'My name is ${name}');
24
+ t.is(renderTemplate('My name is {{name}}', obj, 'common'), 'My name is wener');
25
+ });
@@ -0,0 +1,34 @@
1
+ import { get } from '../objects/get';
2
+
3
+ /**
4
+ * 替换类似于 JS 的模板字符串
5
+ *
6
+ * templateString('My name is ${name}',{name:'wener'}) // => 'My name is wener'
7
+ *
8
+ */
9
+ export function renderTemplate(
10
+ template: string,
11
+ data: ((v: string) => any) | object,
12
+ match: 'js' | 'common' | RegExp = 'js',
13
+ ) {
14
+ let getter: Function;
15
+ if (!data) {
16
+ // todo warning in dev
17
+ getter = () => '';
18
+ } else if (typeof data === 'function') {
19
+ getter = data;
20
+ } else {
21
+ getter = (v: string) => get(data, v);
22
+ }
23
+ if (typeof match === 'string') {
24
+ match = Matches[match] || Matches['js'];
25
+ }
26
+ return template.replace(match, (_, g) => {
27
+ return getter(g.trim());
28
+ });
29
+ }
30
+
31
+ const Matches = {
32
+ js: /\${(.*?)}/g,
33
+ common: /{{(.*?)}}/g,
34
+ };
@@ -0,0 +1,3 @@
1
+ export function isUUID(str: string) {
2
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str);
3
+ }
package/tsconfig.json CHANGED
@@ -11,12 +11,8 @@
11
11
  "strict": true,
12
12
  "sourceMap": true,
13
13
  "skipLibCheck": true,
14
- "declaration": false,
15
14
  "esModuleInterop": true,
16
- "importHelpers": true,
17
15
  "allowSyntheticDefaultImports": true,
18
- "experimentalDecorators": true,
19
- "emitDecoratorMetadata": true,
20
16
  "noImplicitAny": true,
21
17
  "noImplicitReturns": true,
22
18
  "noUnusedLocals": true,