@strapi/utils 4.10.0-beta.0 → 4.10.0-beta.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/.eslintignore +3 -0
- package/.eslintrc.js +4 -0
- package/index.d.ts +3 -0
- package/lib/async.js +2 -3
- package/lib/sanitize/index.js +8 -4
- package/lib/sanitize/sanitizers.js +12 -10
- package/lib/traverse-entity.js +83 -40
- package/package.json +6 -3
package/.eslintignore
ADDED
package/.eslintrc.js
ADDED
package/index.d.ts
ADDED
package/lib/async.js
CHANGED
|
@@ -6,9 +6,8 @@ const { curry, curryN } = require('lodash/fp');
|
|
|
6
6
|
function pipeAsync(...methods) {
|
|
7
7
|
return async (data) => {
|
|
8
8
|
let res = data;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
res = await method(res);
|
|
9
|
+
for (let i = 0; i < methods.length; i += 1) {
|
|
10
|
+
res = await methods[i](res);
|
|
12
11
|
}
|
|
13
12
|
|
|
14
13
|
return res;
|
package/lib/sanitize/index.js
CHANGED
|
@@ -37,12 +37,16 @@ const createContentAPISanitizers = () => {
|
|
|
37
37
|
return pipeAsync(...transforms)(data);
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
-
const
|
|
40
|
+
const sanitizeOutput = async (data, schema, { auth } = {}) => {
|
|
41
41
|
if (isArray(data)) {
|
|
42
|
-
|
|
42
|
+
const res = new Array(data.length);
|
|
43
|
+
for (let i = 0; i < data.length; i += 1) {
|
|
44
|
+
res[i] = await sanitizeOutput(data[i], schema, { auth });
|
|
45
|
+
}
|
|
46
|
+
return res;
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
const transforms = [sanitizers.defaultSanitizeOutput(schema)];
|
|
49
|
+
const transforms = [(data) => sanitizers.defaultSanitizeOutput(schema, data)];
|
|
46
50
|
|
|
47
51
|
if (auth) {
|
|
48
52
|
transforms.push(traverseEntity(visitors.removeRestrictedRelations(auth), { schema }));
|
|
@@ -122,7 +126,7 @@ const createContentAPISanitizers = () => {
|
|
|
122
126
|
|
|
123
127
|
return {
|
|
124
128
|
input: sanitizeInput,
|
|
125
|
-
output:
|
|
129
|
+
output: sanitizeOutput,
|
|
126
130
|
query: sanitizeQuery,
|
|
127
131
|
filters: sanitizeFilters,
|
|
128
132
|
sort: sanitizeSort,
|
|
@@ -20,17 +20,20 @@ const {
|
|
|
20
20
|
removeMorphToRelations,
|
|
21
21
|
} = require('./visitors');
|
|
22
22
|
|
|
23
|
-
const sanitizePasswords =
|
|
23
|
+
const sanitizePasswords = (schema) => async (entity) => {
|
|
24
24
|
return traverseEntity(removePassword, { schema }, entity);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const sanitizePrivates = curry((schema, entity) => {
|
|
28
|
-
return traverseEntity(removePrivate, { schema }, entity);
|
|
29
|
-
});
|
|
25
|
+
};
|
|
30
26
|
|
|
31
|
-
const defaultSanitizeOutput =
|
|
32
|
-
return
|
|
33
|
-
|
|
27
|
+
const defaultSanitizeOutput = async (schema, entity) => {
|
|
28
|
+
return traverseEntity(
|
|
29
|
+
(...args) => {
|
|
30
|
+
removePassword(...args);
|
|
31
|
+
removePrivate(...args);
|
|
32
|
+
},
|
|
33
|
+
{ schema },
|
|
34
|
+
entity
|
|
35
|
+
);
|
|
36
|
+
};
|
|
34
37
|
|
|
35
38
|
const defaultSanitizeFilters = curry((schema, filters) => {
|
|
36
39
|
return pipeAsync(
|
|
@@ -140,7 +143,6 @@ const defaultSanitizePopulate = curry((schema, populate) => {
|
|
|
140
143
|
|
|
141
144
|
module.exports = {
|
|
142
145
|
sanitizePasswords,
|
|
143
|
-
sanitizePrivates,
|
|
144
146
|
defaultSanitizeOutput,
|
|
145
147
|
defaultSanitizeFilters,
|
|
146
148
|
defaultSanitizeSort,
|
package/lib/traverse-entity.js
CHANGED
|
@@ -1,6 +1,42 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { clone, isObject, isArray, isNil, curry } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
const traverseMorphRelationTarget = async (visitor, path, entry) => {
|
|
6
|
+
const targetSchema = strapi.getModel(entry.__type);
|
|
7
|
+
|
|
8
|
+
const traverseOptions = { schema: targetSchema, path };
|
|
9
|
+
|
|
10
|
+
return traverseEntity(visitor, traverseOptions, entry);
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const traverseRelationTarget = (schema) => async (visitor, path, entry) => {
|
|
14
|
+
const traverseOptions = { schema, path };
|
|
15
|
+
|
|
16
|
+
return traverseEntity(visitor, traverseOptions, entry);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const traverseMediaTarget = async (visitor, path, entry) => {
|
|
20
|
+
const targetSchemaUID = 'plugin::upload.file';
|
|
21
|
+
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
22
|
+
|
|
23
|
+
const traverseOptions = { schema: targetSchema, path };
|
|
24
|
+
|
|
25
|
+
return traverseEntity(visitor, traverseOptions, entry);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const traverseComponent = async (visitor, path, schema, entry) => {
|
|
29
|
+
const traverseOptions = { schema, path };
|
|
30
|
+
|
|
31
|
+
return traverseEntity(visitor, traverseOptions, entry);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const visitDynamicZoneEntry = async (visitor, path, entry) => {
|
|
35
|
+
const targetSchema = strapi.getModel(entry.__component);
|
|
36
|
+
const traverseOptions = { schema: targetSchema, path };
|
|
37
|
+
|
|
38
|
+
return traverseEntity(visitor, traverseOptions, entry);
|
|
39
|
+
};
|
|
4
40
|
|
|
5
41
|
const traverseEntity = async (visitor, options, entity) => {
|
|
6
42
|
const { path = { raw: null, attribute: null }, schema } = options;
|
|
@@ -11,9 +47,13 @@ const traverseEntity = async (visitor, options, entity) => {
|
|
|
11
47
|
}
|
|
12
48
|
|
|
13
49
|
// Don't mutate the original entity object
|
|
14
|
-
|
|
50
|
+
// only clone at 1st level as the next level will get clone when traversed
|
|
51
|
+
const copy = clone(entity);
|
|
52
|
+
const visitorUtils = createVisitorUtils({ data: copy });
|
|
15
53
|
|
|
16
|
-
|
|
54
|
+
const keys = Object.keys(copy);
|
|
55
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
56
|
+
const key = keys[i];
|
|
17
57
|
// Retrieve the attribute definition associated to the key from the schema
|
|
18
58
|
const attribute = schema.attributes[key];
|
|
19
59
|
|
|
@@ -32,7 +72,6 @@ const traverseEntity = async (visitor, options, entity) => {
|
|
|
32
72
|
|
|
33
73
|
// Visit the current attribute
|
|
34
74
|
const visitorOptions = { data: copy, schema, key, value: copy[key], attribute, path: newPath };
|
|
35
|
-
const visitorUtils = createVisitorUtils({ data: copy });
|
|
36
75
|
|
|
37
76
|
await visitor(visitorOptions, visitorUtils);
|
|
38
77
|
|
|
@@ -52,58 +91,62 @@ const traverseEntity = async (visitor, options, entity) => {
|
|
|
52
91
|
if (isRelation) {
|
|
53
92
|
const isMorphRelation = attribute.relation.toLowerCase().startsWith('morph');
|
|
54
93
|
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
59
|
-
|
|
60
|
-
const traverseOptions = { schema: targetSchema, path: newPath };
|
|
94
|
+
const method = isMorphRelation
|
|
95
|
+
? traverseMorphRelationTarget
|
|
96
|
+
: traverseRelationTarget(strapi.getModel(attribute.target));
|
|
61
97
|
|
|
62
|
-
|
|
63
|
-
|
|
98
|
+
if (isArray(value)) {
|
|
99
|
+
const res = new Array(value.length);
|
|
100
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
101
|
+
res[i] = await method(visitor, newPath, value[i]);
|
|
102
|
+
}
|
|
103
|
+
copy[key] = res;
|
|
104
|
+
} else {
|
|
105
|
+
copy[key] = await method(visitor, newPath, value);
|
|
106
|
+
}
|
|
64
107
|
|
|
65
|
-
|
|
66
|
-
copy[key] = isArray(value)
|
|
67
|
-
? await Promise.all(value.map(traverseTarget))
|
|
68
|
-
: await traverseTarget(value);
|
|
108
|
+
continue;
|
|
69
109
|
}
|
|
70
110
|
|
|
71
111
|
if (isMedia) {
|
|
72
|
-
const traverseTarget = (entry) => {
|
|
73
|
-
const targetSchemaUID = 'plugin::upload.file';
|
|
74
|
-
const targetSchema = strapi.getModel(targetSchemaUID);
|
|
75
|
-
|
|
76
|
-
const traverseOptions = { schema: targetSchema, path: newPath };
|
|
77
|
-
|
|
78
|
-
return traverseEntity(visitor, traverseOptions, entry);
|
|
79
|
-
};
|
|
80
|
-
|
|
81
112
|
// need to update copy
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
113
|
+
if (isArray(value)) {
|
|
114
|
+
const res = new Array(value.length);
|
|
115
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
116
|
+
res[i] = await traverseMediaTarget(visitor, newPath, value[i]);
|
|
117
|
+
}
|
|
118
|
+
copy[key] = res;
|
|
119
|
+
} else {
|
|
120
|
+
copy[key] = await traverseMediaTarget(visitor, newPath, value);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
continue;
|
|
85
124
|
}
|
|
86
125
|
|
|
87
126
|
if (isComponent) {
|
|
88
127
|
const targetSchema = strapi.getModel(attribute.component);
|
|
89
|
-
const traverseOptions = { schema: targetSchema, path: newPath };
|
|
90
128
|
|
|
91
|
-
|
|
129
|
+
if (isArray(value)) {
|
|
130
|
+
const res = new Array(value.length);
|
|
131
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
132
|
+
res[i] = await traverseComponent(visitor, newPath, targetSchema, value[i]);
|
|
133
|
+
}
|
|
134
|
+
copy[key] = res;
|
|
135
|
+
} else {
|
|
136
|
+
copy[key] = await traverseComponent(visitor, newPath, targetSchema, value);
|
|
137
|
+
}
|
|
92
138
|
|
|
93
|
-
|
|
94
|
-
? await Promise.all(value.map(traverseComponent))
|
|
95
|
-
: await traverseComponent(value);
|
|
139
|
+
continue;
|
|
96
140
|
}
|
|
97
141
|
|
|
98
142
|
if (isDynamicZone && isArray(value)) {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
};
|
|
143
|
+
const res = new Array(value.length);
|
|
144
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
145
|
+
res[i] = await visitDynamicZoneEntry(visitor, newPath, value[i]);
|
|
146
|
+
}
|
|
147
|
+
copy[key] = res;
|
|
105
148
|
|
|
106
|
-
|
|
149
|
+
continue;
|
|
107
150
|
}
|
|
108
151
|
}
|
|
109
152
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/utils",
|
|
3
|
-
"version": "4.10.0-beta.
|
|
3
|
+
"version": "4.10.0-beta.1",
|
|
4
4
|
"description": "Shared utilities for the Strapi packages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"strapi",
|
|
@@ -28,11 +28,14 @@
|
|
|
28
28
|
}
|
|
29
29
|
],
|
|
30
30
|
"main": "./lib",
|
|
31
|
+
"types": "./index.d.ts",
|
|
31
32
|
"directories": {
|
|
32
33
|
"lib": "./lib"
|
|
33
34
|
},
|
|
34
35
|
"scripts": {
|
|
35
|
-
"test:unit": "jest
|
|
36
|
+
"test:unit": "run -T jest",
|
|
37
|
+
"test:unit:watch": "run -T jest --watch",
|
|
38
|
+
"lint": "run -T eslint ."
|
|
36
39
|
},
|
|
37
40
|
"dependencies": {
|
|
38
41
|
"@sindresorhus/slugify": "1.1.0",
|
|
@@ -46,5 +49,5 @@
|
|
|
46
49
|
"node": ">=14.19.1 <=18.x.x",
|
|
47
50
|
"npm": ">=6.0.0"
|
|
48
51
|
},
|
|
49
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "95d581b31bee464af42e5d8db408fa578d8532c7"
|
|
50
53
|
}
|