@strapi/utils 4.6.0 → 4.6.2
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/lib/async.d.ts +21 -0
- package/lib/async.js +46 -0
- package/lib/convert-query-params.js +60 -28
- package/lib/file.js +60 -0
- package/lib/index.js +6 -1
- package/lib/sanitize/index.js +1 -1
- package/lib/sanitize/sanitizers.js +1 -1
- package/package.json +3 -2
- package/lib/pipe-async.js +0 -13
package/lib/async.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CurriedFunction3 } from 'lodash';
|
|
2
|
+
|
|
3
|
+
export type MapAsync<T = any, R = any> = CurriedFunction3<
|
|
4
|
+
T[],
|
|
5
|
+
(element: T, index: number) => R | Promise<R>,
|
|
6
|
+
{ concurrency?: number },
|
|
7
|
+
Promise<R[]>
|
|
8
|
+
>;
|
|
9
|
+
|
|
10
|
+
export type ForEachAsync<T = any, R = any> = (
|
|
11
|
+
array: T[],
|
|
12
|
+
func: (element: T, index: number) => R | Promise<R>,
|
|
13
|
+
options?: { concurrency?: number }
|
|
14
|
+
) => Promise<R[]>;
|
|
15
|
+
|
|
16
|
+
export type ReduceAsync<T = any, V = T, R = V> = CurriedFunction3<
|
|
17
|
+
T[],
|
|
18
|
+
(accumulator: V | R, current: Awaited<T>, index: number) => R | Promise<R>,
|
|
19
|
+
V,
|
|
20
|
+
Promise<R>
|
|
21
|
+
>;
|
package/lib/async.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const pMap = require('p-map');
|
|
4
|
+
const { curry, curryN } = require('lodash/fp');
|
|
5
|
+
|
|
6
|
+
function pipeAsync(...methods) {
|
|
7
|
+
return async (data) => {
|
|
8
|
+
let res = data;
|
|
9
|
+
|
|
10
|
+
for (const method of methods) {
|
|
11
|
+
res = await method(res);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return res;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @type { import('./async').MapAsync }
|
|
20
|
+
*/
|
|
21
|
+
const mapAsync = curry(pMap);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @type { import('./async').ReduceAsync }
|
|
25
|
+
*/
|
|
26
|
+
const reduceAsync = curryN(2, async (mixedArray, iteratee, initialValue) => {
|
|
27
|
+
let acc = initialValue;
|
|
28
|
+
for (let i = 0; i < mixedArray.length; i += 1) {
|
|
29
|
+
acc = await iteratee(acc, await mixedArray[i], i);
|
|
30
|
+
}
|
|
31
|
+
return acc;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @type { import('./async').ForEachAsync }
|
|
36
|
+
*/
|
|
37
|
+
const forEachAsync = curry(async (array, func, options) => {
|
|
38
|
+
await mapAsync(array, func, options);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
module.exports = {
|
|
42
|
+
mapAsync,
|
|
43
|
+
reduceAsync,
|
|
44
|
+
forEachAsync,
|
|
45
|
+
pipeAsync,
|
|
46
|
+
};
|
|
@@ -139,6 +139,41 @@ const convertLimitQueryParams = (limitQuery) => {
|
|
|
139
139
|
return limitAsANumber;
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
+
const convertPageQueryParams = (page) => {
|
|
143
|
+
const pageVal = toNumber(page);
|
|
144
|
+
|
|
145
|
+
if (!isInteger(pageVal) || pageVal <= 0) {
|
|
146
|
+
throw new PaginationError(
|
|
147
|
+
`Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return pageVal;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const convertPageSizeQueryParams = (pageSize, page) => {
|
|
155
|
+
const pageSizeVal = toNumber(pageSize);
|
|
156
|
+
|
|
157
|
+
if (!isInteger(pageSizeVal) || pageSizeVal <= 0) {
|
|
158
|
+
throw new PaginationError(
|
|
159
|
+
`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return pageSizeVal;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
const validatePaginationParams = (page, pageSize, start, limit) => {
|
|
167
|
+
const isPagePagination = !isNil(page) || !isNil(pageSize);
|
|
168
|
+
const isOffsetPagination = !isNil(start) || !isNil(limit);
|
|
169
|
+
|
|
170
|
+
if (isPagePagination && isOffsetPagination) {
|
|
171
|
+
throw new PaginationError(
|
|
172
|
+
'Invalid pagination attributes. You cannot use page and offset pagination in the same query'
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
142
177
|
class InvalidPopulateError extends Error {
|
|
143
178
|
constructor() {
|
|
144
179
|
super();
|
|
@@ -280,8 +315,8 @@ const convertNestedPopulate = (subPopulate, schema) => {
|
|
|
280
315
|
throw new Error(`Invalid nested populate. Expected '*' or an object`);
|
|
281
316
|
}
|
|
282
317
|
|
|
283
|
-
|
|
284
|
-
|
|
318
|
+
const { sort, filters, fields, populate, count, ordering, page, pageSize, start, limit } =
|
|
319
|
+
subPopulate;
|
|
285
320
|
|
|
286
321
|
const query = {};
|
|
287
322
|
|
|
@@ -309,6 +344,26 @@ const convertNestedPopulate = (subPopulate, schema) => {
|
|
|
309
344
|
query.ordering = convertOrderingQueryParams(ordering);
|
|
310
345
|
}
|
|
311
346
|
|
|
347
|
+
validatePaginationParams(page, pageSize, start, limit);
|
|
348
|
+
|
|
349
|
+
if (!isNil(page)) {
|
|
350
|
+
query.page = convertPageQueryParams(page);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (!isNil(pageSize)) {
|
|
354
|
+
query.pageSize = convertPageSizeQueryParams(pageSize, page);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (!isNil(start)) {
|
|
358
|
+
query.offset = convertStartQueryParams(start);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (!isNil(limit)) {
|
|
362
|
+
query.limit = convertLimitQueryParams(limit);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
convertPublicationStateParams(schema, subPopulate, query);
|
|
366
|
+
|
|
312
367
|
return query;
|
|
313
368
|
};
|
|
314
369
|
|
|
@@ -466,37 +521,14 @@ const transformParamsToQuery = (uid, params) => {
|
|
|
466
521
|
query.populate = convertPopulateQueryParams(populate, schema);
|
|
467
522
|
}
|
|
468
523
|
|
|
469
|
-
|
|
470
|
-
const isOffsetPagination = !isNil(start) || !isNil(limit);
|
|
471
|
-
|
|
472
|
-
if (isPagePagination && isOffsetPagination) {
|
|
473
|
-
throw new PaginationError(
|
|
474
|
-
'Invalid pagination attributes. You cannot use page and offset pagination in the same query'
|
|
475
|
-
);
|
|
476
|
-
}
|
|
524
|
+
validatePaginationParams(page, pageSize, start, limit);
|
|
477
525
|
|
|
478
526
|
if (!isNil(page)) {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
if (!isInteger(pageVal) || pageVal <= 0) {
|
|
482
|
-
throw new PaginationError(
|
|
483
|
-
`Invalid 'page' parameter. Expected an integer > 0, received: ${page}`
|
|
484
|
-
);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
query.page = pageVal;
|
|
527
|
+
query.page = convertPageQueryParams(page);
|
|
488
528
|
}
|
|
489
529
|
|
|
490
530
|
if (!isNil(pageSize)) {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
if (!isInteger(pageSizeVal) || pageSizeVal <= 0) {
|
|
494
|
-
throw new PaginationError(
|
|
495
|
-
`Invalid 'pageSize' parameter. Expected an integer > 0, received: ${page}`
|
|
496
|
-
);
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
query.pageSize = pageSizeVal;
|
|
531
|
+
query.pageSize = convertPageSizeQueryParams(pageSize, page);
|
|
500
532
|
}
|
|
501
533
|
|
|
502
534
|
if (!isNil(start)) {
|
package/lib/file.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utils file containing file treatment utils
|
|
5
|
+
*/
|
|
6
|
+
const { Writable } = require('stream');
|
|
7
|
+
|
|
8
|
+
const kbytesToBytes = (kbytes) => kbytes * 1000;
|
|
9
|
+
const bytesToKbytes = (bytes) => Math.round((bytes / 1000) * 100) / 100;
|
|
10
|
+
const bytesToHumanReadable = (bytes) => {
|
|
11
|
+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
|
12
|
+
if (bytes === 0) return '0 Bytes';
|
|
13
|
+
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1000)), 10);
|
|
14
|
+
return `${Math.round(bytes / 1000 ** i, 2)} ${sizes[i]}`;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const streamToBuffer = (stream) =>
|
|
18
|
+
new Promise((resolve, reject) => {
|
|
19
|
+
const chunks = [];
|
|
20
|
+
stream.on('data', (chunk) => {
|
|
21
|
+
chunks.push(chunk);
|
|
22
|
+
});
|
|
23
|
+
stream.on('end', () => {
|
|
24
|
+
resolve(Buffer.concat(chunks));
|
|
25
|
+
});
|
|
26
|
+
stream.on('error', reject);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const getStreamSize = (stream) =>
|
|
30
|
+
new Promise((resolve, reject) => {
|
|
31
|
+
let size = 0;
|
|
32
|
+
stream.on('data', (chunk) => {
|
|
33
|
+
size += Buffer.byteLength(chunk);
|
|
34
|
+
});
|
|
35
|
+
stream.on('close', () => resolve(size));
|
|
36
|
+
stream.on('error', reject);
|
|
37
|
+
stream.resume();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Create a writeable Node.js stream that discards received data.
|
|
42
|
+
* Useful for testing, draining a stream of data, etc.
|
|
43
|
+
*/
|
|
44
|
+
function writableDiscardStream(options) {
|
|
45
|
+
return new Writable({
|
|
46
|
+
...options,
|
|
47
|
+
write(chunk, encding, callback) {
|
|
48
|
+
setImmediate(callback);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
streamToBuffer,
|
|
55
|
+
bytesToHumanReadable,
|
|
56
|
+
bytesToKbytes,
|
|
57
|
+
kbytesToBytes,
|
|
58
|
+
getStreamSize,
|
|
59
|
+
writableDiscardStream,
|
|
60
|
+
};
|
package/lib/index.js
CHANGED
|
@@ -37,10 +37,11 @@ const providerFactory = require('./provider-factory');
|
|
|
37
37
|
const pagination = require('./pagination');
|
|
38
38
|
const sanitize = require('./sanitize');
|
|
39
39
|
const traverseEntity = require('./traverse-entity');
|
|
40
|
-
const pipeAsync = require('./
|
|
40
|
+
const { pipeAsync, mapAsync, reduceAsync, forEachAsync } = require('./async');
|
|
41
41
|
const convertQueryParams = require('./convert-query-params');
|
|
42
42
|
const importDefault = require('./import-default');
|
|
43
43
|
const template = require('./template');
|
|
44
|
+
const file = require('./file');
|
|
44
45
|
|
|
45
46
|
module.exports = {
|
|
46
47
|
yup,
|
|
@@ -81,9 +82,13 @@ module.exports = {
|
|
|
81
82
|
providerFactory,
|
|
82
83
|
pagination,
|
|
83
84
|
pipeAsync,
|
|
85
|
+
mapAsync,
|
|
86
|
+
reduceAsync,
|
|
87
|
+
forEachAsync,
|
|
84
88
|
errors,
|
|
85
89
|
validateYupSchema,
|
|
86
90
|
validateYupSchemaSync,
|
|
87
91
|
convertQueryParams,
|
|
88
92
|
importDefault,
|
|
93
|
+
file,
|
|
89
94
|
};
|
package/lib/sanitize/index.js
CHANGED
|
@@ -4,7 +4,7 @@ const { isArray } = require('lodash/fp');
|
|
|
4
4
|
|
|
5
5
|
const traverseEntity = require('../traverse-entity');
|
|
6
6
|
const { getNonWritableAttributes } = require('../content-types');
|
|
7
|
-
const pipeAsync = require('../
|
|
7
|
+
const { pipeAsync } = require('../async');
|
|
8
8
|
|
|
9
9
|
const visitors = require('./visitors');
|
|
10
10
|
const sanitizers = require('./sanitizers');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/utils",
|
|
3
|
-
"version": "4.6.
|
|
3
|
+
"version": "4.6.2",
|
|
4
4
|
"description": "Shared utilities for the Strapi packages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"strapi",
|
|
@@ -39,11 +39,12 @@
|
|
|
39
39
|
"date-fns": "2.29.3",
|
|
40
40
|
"http-errors": "1.8.1",
|
|
41
41
|
"lodash": "4.17.21",
|
|
42
|
+
"p-map": "4.0.0",
|
|
42
43
|
"yup": "0.32.9"
|
|
43
44
|
},
|
|
44
45
|
"engines": {
|
|
45
46
|
"node": ">=14.19.1 <=18.x.x",
|
|
46
47
|
"npm": ">=6.0.0"
|
|
47
48
|
},
|
|
48
|
-
"gitHead": "
|
|
49
|
+
"gitHead": "bae505f44c3a779905f6b8dbc0c497e24d9eabfb"
|
|
49
50
|
}
|