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