@vbarbarosh/node-helpers 3.74.0 → 3.74.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@ npm install @vbarbarosh/node-helpers
20
20
  A subset of `@vbarbarosh/node-helpers` is available for browser:
21
21
 
22
22
  ```html
23
- <script src="https://unpkg.com/@vbarbarosh/node-helpers@3.74.0/dist/browser.js"></script>
23
+ <script src="https://unpkg.com/@vbarbarosh/node-helpers@3.74.1/dist/browser.js"></script>
24
24
  ```
25
25
 
26
26
  ⚠️ All browser functions are exposed globally.
package/dist/browser.js CHANGED
@@ -2484,10 +2484,10 @@ var __webpack_exports__ = {};
2484
2484
  \******************************/
2485
2485
  const ns = new URL(document.currentScript.src).searchParams.get('var') ?? 'h';
2486
2486
  if (typeof window[ns] !== 'undefined') {
2487
- console.log(`❌ @vbarbarosh/node-helpers@${"3.74.0"} was not injected — window.${ns} is already in use`);
2487
+ console.log(`❌ @vbarbarosh/node-helpers@${"3.74.1"} was not injected — window.${ns} is already in use`);
2488
2488
  }
2489
2489
  else {
2490
- console.log(`🎉 @vbarbarosh/node-helpers@${"3.74.0"} successfully exposed as window.${ns}`);
2490
+ console.log(`🎉 @vbarbarosh/node-helpers@${"3.74.1"} successfully exposed as window.${ns}`);
2491
2491
  window[ns] = {};
2492
2492
  // https://github.com/webpack/webpack/issues/625
2493
2493
  // https://webpack.js.org/guides/dependency-management/#require-context
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "Vladimir Barbarosh <vladimir.barbarosh@gmail.com>",
3
3
  "license": "MIT",
4
4
  "name": "@vbarbarosh/node-helpers",
5
- "version": "3.74.0",
5
+ "version": "3.74.1",
6
6
  "description": "A set of helpers for JavaScript/Node.js",
7
7
  "unpkg": "dist/browser.js",
8
8
  "jsdelivr": "dist/browser.js",
package/src/cache.js ADDED
@@ -0,0 +1,15 @@
1
+ // read, write, refresh
2
+ async function cache({get, set, refresh})
3
+ {
4
+ try {
5
+ return await get();
6
+ }
7
+ catch {
8
+ }
9
+
10
+ const value = await refresh();
11
+ await set(value);
12
+ return value;
13
+ }
14
+
15
+ module.exports = cache;
package/src/cache.md ADDED
@@ -0,0 +1,9 @@
1
+ Probably the most basic cache engine ever.
2
+
3
+ ```javascript
4
+ await cache({
5
+ get: () => fs_read_json('data.json'),
6
+ set: v => fs_write_json('data.json', v),
7
+ refresh: () => compute(),
8
+ });
9
+ ```
@@ -32,4 +32,9 @@ describe('urlmod', function () {
32
32
  assert.deepEqual(urlmod('/#ex', {b: 2}), '/?b=2#ex');
33
33
  assert.deepEqual(urlmod('http://www.example.com/some/path?a=1#ex', {b: 2}), 'http://www.example.com/some/path?a=1&b=2#ex');
34
34
  });
35
+ it('should keep port', function () {
36
+ const actual = urlmod('http://localhost:3000/auth/sign-in', {return: '/auth/profile'});
37
+ const expected = 'http://localhost:3000/auth/sign-in?return=%2Fauth%2Fprofile';
38
+ assert.strictEqual(actual, expected);
39
+ })
35
40
  });
@@ -0,0 +1,20 @@
1
+ function urlparts(url)
2
+ {
3
+ const tmp = url instanceof URL
4
+ ? url
5
+ : new URL((typeof url === 'string' ? url : ''), 'fake://fake/');
6
+ return {
7
+ href: tmp.href,
8
+ protocol: tmp.protocol,
9
+ hostname: tmp.hostname,
10
+ username: tmp.username,
11
+ password: tmp.password,
12
+ host: tmp.host,
13
+ port: tmp.port,
14
+ path: tmp.pathname,
15
+ search: tmp.search,
16
+ hash: tmp.hash,
17
+ };
18
+ }
19
+
20
+ module.exports = urlparts;
@@ -0,0 +1,294 @@
1
+ const assert = require('assert');
2
+ const edge_values = require('@vbarbarosh/type-helpers/src/edge_values');
3
+ const urlparts = require('./urlparts');
4
+
5
+ const extra_edge_values = [
6
+ // whitespace strings
7
+ {label: '" "', value: ' '},
8
+ {label: '"\\t"', value: '\t'},
9
+ {label: '"\\n"', value: '\n'},
10
+ {label: '"\\r\\n"', value: '\r\n'},
11
+
12
+ // numeric strings
13
+ {label: '"0"', value: '0'},
14
+ {label: '"1"', value: '1'},
15
+ {label: '"NaN"', value: 'NaN'},
16
+ {label: '"Infinity"', value: 'Infinity'},
17
+
18
+ // weird unicode
19
+ {label: '"💩"', value: '💩'},
20
+ {label: '"😀"', value: '😀'},
21
+ {label: '"привет"', value: 'привет'},
22
+ {label: '"こんにちは"', value: 'こんにちは'},
23
+
24
+ // dangerous chars
25
+ {label: '"<script>"', value: '<script>'},
26
+ {label: '"../"', value: '../'},
27
+ {label: '"%20"', value: '%20'},
28
+ {label: '"a?b=c"', value: 'a?b=c'},
29
+ {label: '"a#b"', value: 'a#b'},
30
+
31
+ // arrays
32
+ {label: '[1,2,3]', value: [1, 2, 3]},
33
+ {label: '[null]', value: [null]},
34
+ {label: '[undefined]', value: [undefined]},
35
+ {label: 'new Array(5)', value: new Array(5)},
36
+
37
+ // typed arrays
38
+ {label: 'Uint8Array', value: new Uint8Array([1, 2, 3])},
39
+ {label: 'Buffer', value: Buffer.from('abc')},
40
+
41
+ // objects
42
+ {label: '{a:1}', value: {a: 1}},
43
+ {label: 'Object.create(null)', value: Object.create(null)},
44
+
45
+ // custom coercion
46
+ {label: 'toString() => x', value: {toString() {return 'x';}}},
47
+ {label: 'valueOf() => 123', value: {valueOf() {return 123;}}},
48
+
49
+ // dates
50
+ {label: 'new Date()', value: new Date()},
51
+ {label: 'Invalid Date', value: new Date('invalid')},
52
+
53
+ // regexp
54
+ {label: '/foo/g', value: /foo/g},
55
+
56
+ // maps/sets
57
+ {label: 'Map', value: new Map()},
58
+ {label: 'Set', value: new Set()},
59
+ {label: 'WeakMap', value: new WeakMap()},
60
+ {label: 'WeakSet', value: new WeakSet()},
61
+
62
+ // promises
63
+ {label: 'Promise.resolve(1)', value: Promise.resolve(1)},
64
+
65
+ // errors
66
+ {label: 'Error', value: new Error('boom')},
67
+ {label: 'TypeError', value: new TypeError('boom')},
68
+
69
+ // wrappers
70
+ {label: 'new String()', value: new String('abc')},
71
+ {label: 'new Number()', value: new Number(123)},
72
+ {label: 'new Boolean()', value: new Boolean(false)},
73
+
74
+ // url-like
75
+ {label: 'new URL("https://example.com")', value: new URL('https://example.com')},
76
+
77
+ // bigint
78
+ {label: '1n', value: 1n},
79
+ {label: '-1n', value: -1n},
80
+
81
+ // special numbers
82
+ {label: 'Number.EPSILON', value: Number.EPSILON},
83
+
84
+ // proxy
85
+ {label: 'Proxy', value: new Proxy({}, {})},
86
+ ];
87
+
88
+ const happy_paths = [
89
+ {
90
+ label: 'parses full https url',
91
+ input: 'https://john:secret@example.com:8080/users/15?page=2#top',
92
+ expected: {
93
+ href: 'https://john:secret@example.com:8080/users/15?page=2#top',
94
+ protocol: 'https:',
95
+ hostname: 'example.com',
96
+ username: 'john',
97
+ password: 'secret',
98
+ host: 'example.com:8080',
99
+ port: '8080',
100
+ path: '/users/15',
101
+ search: '?page=2',
102
+ hash: '#top',
103
+ },
104
+ },
105
+ {
106
+ label: 'parses https url without auth',
107
+ input: 'https://example.com/users',
108
+ expected: {
109
+ href: 'https://example.com/users',
110
+ protocol: 'https:',
111
+ hostname: 'example.com',
112
+ username: '',
113
+ password: '',
114
+ host: 'example.com',
115
+ port: '',
116
+ path: '/users',
117
+ search: '',
118
+ hash: '',
119
+ },
120
+ },
121
+ {
122
+ label: 'parses root url',
123
+ input: 'https://example.com',
124
+ expected: {
125
+ href: 'https://example.com/',
126
+ protocol: 'https:',
127
+ hostname: 'example.com',
128
+ username: '',
129
+ password: '',
130
+ host: 'example.com',
131
+ port: '',
132
+ path: '/',
133
+ search: '',
134
+ hash: '',
135
+ },
136
+ },
137
+ {
138
+ label: 'parses relative path',
139
+ input: '/users?page=5',
140
+ expected: {
141
+ href: 'fake://fake/users?page=5',
142
+ protocol: 'fake:',
143
+ hostname: 'fake',
144
+ username: '',
145
+ password: '',
146
+ host: 'fake',
147
+ port: '',
148
+ path: '/users',
149
+ search: '?page=5',
150
+ hash: '',
151
+ },
152
+ },
153
+ {
154
+ label: 'parses hash',
155
+ input: 'https://example.com/docs#intro',
156
+ expected: {
157
+ href: 'https://example.com/docs#intro',
158
+ protocol: 'https:',
159
+ hostname: 'example.com',
160
+ username: '',
161
+ password: '',
162
+ host: 'example.com',
163
+ port: '',
164
+ path: '/docs',
165
+ search: '',
166
+ hash: '#intro',
167
+ },
168
+ },
169
+ {
170
+ label: 'parses query string',
171
+ input: 'https://example.com?a=1&b=2',
172
+ expected: {
173
+ href: 'https://example.com/?a=1&b=2',
174
+ protocol: 'https:',
175
+ hostname: 'example.com',
176
+ username: '',
177
+ password: '',
178
+ host: 'example.com',
179
+ port: '',
180
+ path: '/',
181
+ search: '?a=1&b=2',
182
+ hash: '',
183
+ },
184
+ },
185
+ {
186
+ label: 'parses localhost with port',
187
+ input: 'http://localhost:3000/foo',
188
+ expected: {
189
+ href: 'http://localhost:3000/foo',
190
+ protocol: 'http:',
191
+ hostname: 'localhost',
192
+ username: '',
193
+ password: '',
194
+ host: 'localhost:3000',
195
+ port: '3000',
196
+ path: '/foo',
197
+ search: '',
198
+ hash: '',
199
+ },
200
+ },
201
+ {
202
+ label: 'parses ftp url',
203
+ input: 'ftp://example.com/file.txt',
204
+ expected: {
205
+ href: 'ftp://example.com/file.txt',
206
+ protocol: 'ftp:',
207
+ hostname: 'example.com',
208
+ username: '',
209
+ password: '',
210
+ host: 'example.com',
211
+ port: '',
212
+ path: '/file.txt',
213
+ search: '',
214
+ hash: '',
215
+ },
216
+ },
217
+ ];
218
+
219
+ describe('urlparts', function () {
220
+ it('no args', function () {
221
+ assert.deepStrictEqual(urlparts(), {
222
+ href: 'fake://fake/',
223
+ protocol: 'fake:',
224
+ hostname: 'fake',
225
+ username: '',
226
+ password: '',
227
+ host: 'fake',
228
+ port: '',
229
+ path: '/',
230
+ search: '',
231
+ hash: '',
232
+ });
233
+ });
234
+
235
+ describe('happy paths', function () {
236
+ for (const item of happy_paths) {
237
+ it(item.label, function () {
238
+ const actual = urlparts(item.input);
239
+ assert.deepStrictEqual(actual, item.expected);
240
+ });
241
+ }
242
+ });
243
+
244
+ describe('edge values', function () {
245
+ for (const item of [...edge_values, ...extra_edge_values]) {
246
+ it(item.label, function () {
247
+ if (typeof item.value === 'string') {
248
+ const tmp = new URL(item.value, 'fake://fake/');
249
+ assert.deepStrictEqual(urlparts(item.value), {
250
+ href: tmp.href,
251
+ protocol: tmp.protocol,
252
+ hostname: tmp.hostname,
253
+ username: tmp.username,
254
+ password: tmp.password,
255
+ host: tmp.host,
256
+ port: tmp.port,
257
+ path: tmp.pathname,
258
+ search: tmp.search,
259
+ hash: tmp.hash,
260
+ });
261
+ }
262
+ else if (item.value instanceof URL) {
263
+ const tmp = item.value;
264
+ assert.deepStrictEqual(urlparts(item.value), {
265
+ href: tmp.href,
266
+ protocol: tmp.protocol,
267
+ hostname: tmp.hostname,
268
+ username: tmp.username,
269
+ password: tmp.password,
270
+ host: tmp.host,
271
+ port: tmp.port,
272
+ path: tmp.pathname,
273
+ search: tmp.search,
274
+ hash: tmp.hash,
275
+ });
276
+ }
277
+ else {
278
+ assert.deepStrictEqual(urlparts(item.value), {
279
+ href: 'fake://fake/',
280
+ protocol: 'fake:',
281
+ hostname: 'fake',
282
+ username: '',
283
+ password: '',
284
+ host: 'fake',
285
+ port: '',
286
+ path: '/',
287
+ search: '',
288
+ hash: '',
289
+ });
290
+ }
291
+ });
292
+ }
293
+ });
294
+ });