@fourlights/strapi-plugin-deep-populate 1.3.1 → 1.4.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/README.md +31 -1
- package/dist/server/index.js +93 -5
- package/dist/server/index.mjs +110 -24
- package/dist/server/src/config/index.d.ts +20 -1
- package/dist/server/src/index.d.ts +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ It does not impose a limit on the level of nesting and can cache the populate ob
|
|
|
12
12
|
- Handles circular references and edge cases
|
|
13
13
|
- Includes caching for improved performance
|
|
14
14
|
- Honors `populateCreatorFields` setting
|
|
15
|
+
- Supports optional allow/deny lists for specific relations or components during population
|
|
15
16
|
|
|
16
17
|
## Installation
|
|
17
18
|
|
|
@@ -72,7 +73,36 @@ The plugin caches populate objects to improve performance. Cache can be disabled
|
|
|
72
73
|
|
|
73
74
|
The plugin automatically populates `createdBy` and `updatedBy` fields when `populateCreatorFields` is enabled in the content-type configuration.
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
### Allow / Deny Lists
|
|
77
|
+
|
|
78
|
+
Sometimes you may want to restrict the nested population of certain relations or components. For example if you have a `Page` contentType where a deeply nested `Link` component has a relation to another `Page`.
|
|
79
|
+
In those situations you can use the allow or deny lists to control where the plugin should stop resolving nested relations.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// config/plugins.js
|
|
83
|
+
module.exports = ({ env }) => ({
|
|
84
|
+
'deep-populate': {
|
|
85
|
+
enabled: true,
|
|
86
|
+
config: {
|
|
87
|
+
useCache: true,
|
|
88
|
+
replaceWildcard: true,
|
|
89
|
+
|
|
90
|
+
contentTypes: {
|
|
91
|
+
'api::page.page': {
|
|
92
|
+
deny: {
|
|
93
|
+
relations: ['api::page.page'] // prevent resolving nested pages when populating a page
|
|
94
|
+
// alternatively we could have denied the link component in this case
|
|
95
|
+
// components: ['shared.link']
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## How The Plugin Works
|
|
76
106
|
|
|
77
107
|
The plugin recursively:
|
|
78
108
|
1. Traverses the content-type schema
|
package/dist/server/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
const isEmpty$1 = require("lodash/isEmpty");
|
|
3
|
+
const isObject$4 = require("lodash/isObject");
|
|
2
4
|
const ___default = require("lodash");
|
|
3
5
|
const fp = require("lodash/fp");
|
|
4
6
|
const require$$1 = require("crypto");
|
|
@@ -23,6 +25,8 @@ const get = require("lodash/get");
|
|
|
23
25
|
const mergeWith = require("lodash/mergeWith");
|
|
24
26
|
const set$2 = require("lodash/set");
|
|
25
27
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
28
|
+
const isEmpty__default = /* @__PURE__ */ _interopDefault(isEmpty$1);
|
|
29
|
+
const isObject__default = /* @__PURE__ */ _interopDefault(isObject$4);
|
|
26
30
|
const ___default__default = /* @__PURE__ */ _interopDefault(___default);
|
|
27
31
|
const require$$1__default = /* @__PURE__ */ _interopDefault(require$$1);
|
|
28
32
|
const require$$0__default = /* @__PURE__ */ _interopDefault(require$$0$1);
|
|
@@ -45,8 +49,43 @@ const get__default = /* @__PURE__ */ _interopDefault(get);
|
|
|
45
49
|
const mergeWith__default = /* @__PURE__ */ _interopDefault(mergeWith);
|
|
46
50
|
const set__default = /* @__PURE__ */ _interopDefault(set$2);
|
|
47
51
|
const config = {
|
|
48
|
-
default: ({ env: env2 }) => ({ useCache: true, replaceWildcard: true }),
|
|
52
|
+
default: ({ env: env2 }) => ({ useCache: true, replaceWildcard: true, contentTypes: {} }),
|
|
49
53
|
validator: (config2) => {
|
|
54
|
+
if (!isObject__default.default(config2.contentTypes)) {
|
|
55
|
+
throw new Error("plugin::deep-populate config.contentTypes must be an object");
|
|
56
|
+
}
|
|
57
|
+
if (!isEmpty__default.default(config2.contentTypes)) {
|
|
58
|
+
for (const [uid, contentTypeConfig] of Object.entries(config2.contentTypes)) {
|
|
59
|
+
if (!isObject__default.default(contentTypeConfig)) {
|
|
60
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid} must be an object`);
|
|
61
|
+
}
|
|
62
|
+
if (!contentTypeConfig.allow && !contentTypeConfig.deny) {
|
|
63
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid} must have an "allow" or "deny".`);
|
|
64
|
+
}
|
|
65
|
+
if (contentTypeConfig.allow && !isObject__default.default(contentTypeConfig.allow)) {
|
|
66
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.allow must be an object`);
|
|
67
|
+
}
|
|
68
|
+
if (contentTypeConfig.deny && !isObject__default.default(contentTypeConfig.deny)) {
|
|
69
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.deny must be an object`);
|
|
70
|
+
}
|
|
71
|
+
if (contentTypeConfig.allow) {
|
|
72
|
+
if (contentTypeConfig.allow.relations && !Array.isArray(contentTypeConfig.allow.relations)) {
|
|
73
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.allow.relations must be an array`);
|
|
74
|
+
}
|
|
75
|
+
if (contentTypeConfig.allow.components && !Array.isArray(contentTypeConfig.allow.components)) {
|
|
76
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.allow.components must be an array`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (contentTypeConfig.deny) {
|
|
80
|
+
if (contentTypeConfig.deny.relations && !Array.isArray(contentTypeConfig.deny.relations)) {
|
|
81
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.deny.relations must be an array`);
|
|
82
|
+
}
|
|
83
|
+
if (contentTypeConfig.deny.components && !Array.isArray(contentTypeConfig.deny.components)) {
|
|
84
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.deny.components must be an array`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
50
89
|
}
|
|
51
90
|
};
|
|
52
91
|
const schema$1 = {
|
|
@@ -14636,18 +14675,26 @@ const hasValue = (value) => {
|
|
|
14636
14675
|
return !(value === null || value === void 0 || Array.isArray(value) && value.length === 0 || typeof value === "object" && isEmpty(value));
|
|
14637
14676
|
};
|
|
14638
14677
|
async function _populateComponent({
|
|
14678
|
+
schema: schema2,
|
|
14639
14679
|
populate: populate2 = {},
|
|
14640
14680
|
lookup,
|
|
14641
14681
|
attrName,
|
|
14642
14682
|
inDynamicZone = false,
|
|
14683
|
+
__allow,
|
|
14684
|
+
__deny,
|
|
14643
14685
|
...params
|
|
14644
14686
|
}) {
|
|
14645
14687
|
const componentLookup = lookup.length === 0 ? [attrName] : [...lookup, inDynamicZone ? "on" : "populate", attrName];
|
|
14646
14688
|
const componentPopulate = populate2;
|
|
14647
14689
|
set__default.default(componentPopulate, componentLookup, { populate: "*" });
|
|
14690
|
+
if (__allow?.components && !__allow.components.includes(schema2)) return { populate: "*" };
|
|
14691
|
+
if (__deny?.components?.includes(schema2)) return { populate: "*" };
|
|
14648
14692
|
const nestedPopulate = await _populate({
|
|
14693
|
+
schema: schema2,
|
|
14649
14694
|
populate: componentPopulate,
|
|
14650
14695
|
lookup: componentLookup,
|
|
14696
|
+
__allow,
|
|
14697
|
+
__deny,
|
|
14651
14698
|
...params
|
|
14652
14699
|
});
|
|
14653
14700
|
return isEmpty(nestedPopulate) ? true : { populate: nestedPopulate };
|
|
@@ -14682,7 +14729,9 @@ async function _populateRelation({
|
|
|
14682
14729
|
resolvedRelations,
|
|
14683
14730
|
omitEmpty,
|
|
14684
14731
|
locale: locale2,
|
|
14685
|
-
status: status2
|
|
14732
|
+
status: status2,
|
|
14733
|
+
__deny,
|
|
14734
|
+
__allow
|
|
14686
14735
|
}) {
|
|
14687
14736
|
const isSingleRelation = !Array.isArray(relation);
|
|
14688
14737
|
const relations = isSingleRelation ? [relation] : relation;
|
|
@@ -14696,7 +14745,9 @@ async function _populateRelation({
|
|
|
14696
14745
|
resolvedRelations,
|
|
14697
14746
|
omitEmpty,
|
|
14698
14747
|
locale: locale2,
|
|
14699
|
-
status: status2
|
|
14748
|
+
status: status2,
|
|
14749
|
+
__deny,
|
|
14750
|
+
__allow
|
|
14700
14751
|
});
|
|
14701
14752
|
resolvedRelations.set(relation2.documentId, relationPopulate);
|
|
14702
14753
|
}
|
|
@@ -14746,6 +14797,8 @@ async function _populate({
|
|
|
14746
14797
|
lookup = [],
|
|
14747
14798
|
resolvedRelations,
|
|
14748
14799
|
omitEmpty,
|
|
14800
|
+
__deny,
|
|
14801
|
+
__allow,
|
|
14749
14802
|
...params
|
|
14750
14803
|
}) {
|
|
14751
14804
|
const newPopulate = {};
|
|
@@ -14774,6 +14827,26 @@ async function _populate({
|
|
|
14774
14827
|
if (!omitEmpty) newPopulate[attrName] = true;
|
|
14775
14828
|
continue;
|
|
14776
14829
|
}
|
|
14830
|
+
if (contentTypes.isRelationalAttribute(attr)) {
|
|
14831
|
+
if (__allow?.relations && !__allow.relations.includes(attr.target)) {
|
|
14832
|
+
newPopulate[attrName] = true;
|
|
14833
|
+
continue;
|
|
14834
|
+
}
|
|
14835
|
+
if (__deny?.relations?.includes(attr.target)) {
|
|
14836
|
+
newPopulate[attrName] = true;
|
|
14837
|
+
continue;
|
|
14838
|
+
}
|
|
14839
|
+
}
|
|
14840
|
+
if (contentTypes.isComponentAttribute(attr) && !contentTypes.isDynamicZoneAttribute(attr)) {
|
|
14841
|
+
if (__allow?.components && !__allow.components.includes(attr.component)) {
|
|
14842
|
+
newPopulate[attrName] = true;
|
|
14843
|
+
continue;
|
|
14844
|
+
}
|
|
14845
|
+
if (__deny?.components?.includes(attr.component)) {
|
|
14846
|
+
newPopulate[attrName] = true;
|
|
14847
|
+
continue;
|
|
14848
|
+
}
|
|
14849
|
+
}
|
|
14777
14850
|
resolveRelations.push([attrName, attr, value]);
|
|
14778
14851
|
}
|
|
14779
14852
|
relations = null;
|
|
@@ -14790,6 +14863,8 @@ async function _populate({
|
|
|
14790
14863
|
attrName,
|
|
14791
14864
|
resolvedRelations,
|
|
14792
14865
|
omitEmpty,
|
|
14866
|
+
__deny,
|
|
14867
|
+
__allow,
|
|
14793
14868
|
...params
|
|
14794
14869
|
});
|
|
14795
14870
|
}
|
|
@@ -14800,7 +14875,9 @@ async function _populate({
|
|
|
14800
14875
|
resolvedRelations,
|
|
14801
14876
|
omitEmpty,
|
|
14802
14877
|
locale: params.locale,
|
|
14803
|
-
status: params.status
|
|
14878
|
+
status: params.status,
|
|
14879
|
+
__deny,
|
|
14880
|
+
__allow
|
|
14804
14881
|
});
|
|
14805
14882
|
}
|
|
14806
14883
|
if (contentTypes.isComponentAttribute(attr) && !contentTypes.isDynamicZoneAttribute(attr)) {
|
|
@@ -14811,6 +14888,8 @@ async function _populate({
|
|
|
14811
14888
|
attrName,
|
|
14812
14889
|
resolvedRelations,
|
|
14813
14890
|
omitEmpty,
|
|
14891
|
+
__deny,
|
|
14892
|
+
__allow,
|
|
14814
14893
|
...params
|
|
14815
14894
|
});
|
|
14816
14895
|
}
|
|
@@ -14821,8 +14900,17 @@ async function _populate({
|
|
|
14821
14900
|
return newPopulate;
|
|
14822
14901
|
}
|
|
14823
14902
|
async function populate$1(params) {
|
|
14903
|
+
const { contentTypes: contentTypes2 } = strapi.config.get("plugin::deep-populate");
|
|
14904
|
+
const contentTypeConfig = ___default.has(contentTypes2, params.contentType) ? get__default.default(contentTypes2, params.contentType) : {};
|
|
14905
|
+
const { allow, deny } = contentTypeConfig;
|
|
14824
14906
|
const resolvedRelations = /* @__PURE__ */ new Map();
|
|
14825
|
-
const populated = await _populate({
|
|
14907
|
+
const populated = await _populate({
|
|
14908
|
+
...params,
|
|
14909
|
+
schema: params.contentType,
|
|
14910
|
+
resolvedRelations,
|
|
14911
|
+
__deny: deny,
|
|
14912
|
+
__allow: allow
|
|
14913
|
+
});
|
|
14826
14914
|
return { populate: populated, dependencies: [...resolvedRelations.keys()] };
|
|
14827
14915
|
}
|
|
14828
14916
|
const populate = ({ strapi: strapi2 }) => ({
|
package/dist/server/index.mjs
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import isEmpty$1 from "lodash/isEmpty";
|
|
2
|
+
import isObject$4 from "lodash/isObject";
|
|
3
|
+
import ___default, { has as has$2 } from "lodash";
|
|
4
|
+
import { curry, isArray, isObject as isObject$5, isEmpty as isEmpty$2, cloneDeep, omit, isNil, trim as trim$1, isString, pipe as pipe$1, split as split$1, map as map$2, flatten, first, identity, constant, join, eq, clone as clone$3, get, pick, has as has$1, union, getOr, toPath, isBoolean as isBoolean$1 } from "lodash/fp";
|
|
3
5
|
import require$$1 from "crypto";
|
|
4
6
|
import require$$0$1 from "child_process";
|
|
5
7
|
import has from "lodash/has";
|
|
@@ -22,8 +24,43 @@ import get$1 from "lodash/get";
|
|
|
22
24
|
import mergeWith from "lodash/mergeWith";
|
|
23
25
|
import set$2 from "lodash/set";
|
|
24
26
|
const config = {
|
|
25
|
-
default: ({ env: env2 }) => ({ useCache: true, replaceWildcard: true }),
|
|
27
|
+
default: ({ env: env2 }) => ({ useCache: true, replaceWildcard: true, contentTypes: {} }),
|
|
26
28
|
validator: (config2) => {
|
|
29
|
+
if (!isObject$4(config2.contentTypes)) {
|
|
30
|
+
throw new Error("plugin::deep-populate config.contentTypes must be an object");
|
|
31
|
+
}
|
|
32
|
+
if (!isEmpty$1(config2.contentTypes)) {
|
|
33
|
+
for (const [uid, contentTypeConfig] of Object.entries(config2.contentTypes)) {
|
|
34
|
+
if (!isObject$4(contentTypeConfig)) {
|
|
35
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid} must be an object`);
|
|
36
|
+
}
|
|
37
|
+
if (!contentTypeConfig.allow && !contentTypeConfig.deny) {
|
|
38
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid} must have an "allow" or "deny".`);
|
|
39
|
+
}
|
|
40
|
+
if (contentTypeConfig.allow && !isObject$4(contentTypeConfig.allow)) {
|
|
41
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.allow must be an object`);
|
|
42
|
+
}
|
|
43
|
+
if (contentTypeConfig.deny && !isObject$4(contentTypeConfig.deny)) {
|
|
44
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.deny must be an object`);
|
|
45
|
+
}
|
|
46
|
+
if (contentTypeConfig.allow) {
|
|
47
|
+
if (contentTypeConfig.allow.relations && !Array.isArray(contentTypeConfig.allow.relations)) {
|
|
48
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.allow.relations must be an array`);
|
|
49
|
+
}
|
|
50
|
+
if (contentTypeConfig.allow.components && !Array.isArray(contentTypeConfig.allow.components)) {
|
|
51
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.allow.components must be an array`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (contentTypeConfig.deny) {
|
|
55
|
+
if (contentTypeConfig.deny.relations && !Array.isArray(contentTypeConfig.deny.relations)) {
|
|
56
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.deny.relations must be an array`);
|
|
57
|
+
}
|
|
58
|
+
if (contentTypeConfig.deny.components && !Array.isArray(contentTypeConfig.deny.components)) {
|
|
59
|
+
throw new Error(`plugin::deep-populate config.contentTypes.${uid}.deny.components must be an array`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
27
64
|
}
|
|
28
65
|
};
|
|
29
66
|
const schema$1 = {
|
|
@@ -13117,7 +13154,7 @@ const traverseEntity = async (visitor2, options, entity) => {
|
|
|
13117
13154
|
const traverseOptions = { schema: targetSchema, path: path22, getModel, parent };
|
|
13118
13155
|
return traverseEntity(visitor22, traverseOptions, entry);
|
|
13119
13156
|
};
|
|
13120
|
-
if (!isObject$
|
|
13157
|
+
if (!isObject$5(entity) || isNil(schema2)) {
|
|
13121
13158
|
return entity;
|
|
13122
13159
|
}
|
|
13123
13160
|
const copy = clone$3(entity);
|
|
@@ -13353,7 +13390,7 @@ const removeRestrictedRelations = (auth) => async ({ data, key, attribute, schem
|
|
|
13353
13390
|
return allowedElements;
|
|
13354
13391
|
}
|
|
13355
13392
|
for (const element of elements) {
|
|
13356
|
-
if (!isObject$
|
|
13393
|
+
if (!isObject$5(element) || !("__type" in element)) {
|
|
13357
13394
|
continue;
|
|
13358
13395
|
}
|
|
13359
13396
|
const scopes = ACTIONS_TO_VERIFY$1.map((action) => `${element.__type}.${action}`);
|
|
@@ -13586,7 +13623,7 @@ const traverseFactory = () => {
|
|
|
13586
13623
|
}
|
|
13587
13624
|
};
|
|
13588
13625
|
};
|
|
13589
|
-
const isObj$2 = (value) => isObject$
|
|
13626
|
+
const isObj$2 = (value) => isObject$5(value);
|
|
13590
13627
|
const filters = traverseFactory().intercept(
|
|
13591
13628
|
// Intercept filters arrays and apply the traversal to each one individually
|
|
13592
13629
|
isArray,
|
|
@@ -13597,11 +13634,11 @@ const filters = traverseFactory().intercept(
|
|
|
13597
13634
|
return recurse(visitor2, { ...options, path: newPath }, filter);
|
|
13598
13635
|
})
|
|
13599
13636
|
// todo: move that to the visitors
|
|
13600
|
-
).then((res) => res.filter((val) => !(isObject$
|
|
13637
|
+
).then((res) => res.filter((val) => !(isObject$5(val) && isEmpty$2(val))));
|
|
13601
13638
|
}
|
|
13602
13639
|
).intercept(
|
|
13603
13640
|
// Ignore non object filters and return the value as-is
|
|
13604
|
-
(filters2) => !isObject$
|
|
13641
|
+
(filters2) => !isObject$5(filters2),
|
|
13605
13642
|
(_2, __, filters2) => {
|
|
13606
13643
|
return filters2;
|
|
13607
13644
|
}
|
|
@@ -13668,23 +13705,23 @@ const ORDERS = { asc: "asc", desc: "desc" };
|
|
|
13668
13705
|
const ORDER_VALUES = Object.values(ORDERS);
|
|
13669
13706
|
const isSortOrder = (value) => ORDER_VALUES.includes(value.toLowerCase());
|
|
13670
13707
|
const isStringArray$2 = (value) => Array.isArray(value) && value.every(isString);
|
|
13671
|
-
const isObjectArray = (value) => Array.isArray(value) && value.every(isObject$
|
|
13708
|
+
const isObjectArray = (value) => Array.isArray(value) && value.every(isObject$5);
|
|
13672
13709
|
const isNestedSorts = (value) => isString(value) && value.split(",").length > 1;
|
|
13673
|
-
const isObj$1 = (value) => isObject$
|
|
13710
|
+
const isObj$1 = (value) => isObject$5(value);
|
|
13674
13711
|
const sort = traverseFactory().intercept(
|
|
13675
13712
|
// String with chained sorts (foo,bar,foobar) => split, map(recurse), then recompose
|
|
13676
13713
|
isNestedSorts,
|
|
13677
13714
|
async (visitor2, options, sort2, { recurse }) => {
|
|
13678
13715
|
return Promise.all(
|
|
13679
13716
|
sort2.split(",").map(trim$1).map((nestedSort) => recurse(visitor2, options, nestedSort))
|
|
13680
|
-
).then((res) => res.filter((part) => !isEmpty$
|
|
13717
|
+
).then((res) => res.filter((part) => !isEmpty$2(part)).join(","));
|
|
13681
13718
|
}
|
|
13682
13719
|
).intercept(
|
|
13683
13720
|
// Array of strings ['foo', 'foo,bar'] => map(recurse), then filter out empty items
|
|
13684
13721
|
isStringArray$2,
|
|
13685
13722
|
async (visitor2, options, sort2, { recurse }) => {
|
|
13686
13723
|
return Promise.all(sort2.map((nestedSort) => recurse(visitor2, options, nestedSort))).then(
|
|
13687
|
-
(res) => res.filter((nestedSort) => !isEmpty$
|
|
13724
|
+
(res) => res.filter((nestedSort) => !isEmpty$2(nestedSort))
|
|
13688
13725
|
);
|
|
13689
13726
|
}
|
|
13690
13727
|
).intercept(
|
|
@@ -13692,7 +13729,7 @@ const sort = traverseFactory().intercept(
|
|
|
13692
13729
|
isObjectArray,
|
|
13693
13730
|
async (visitor2, options, sort2, { recurse }) => {
|
|
13694
13731
|
return Promise.all(sort2.map((nestedSort) => recurse(visitor2, options, nestedSort))).then(
|
|
13695
|
-
(res) => res.filter((nestedSort) => !isEmpty$
|
|
13732
|
+
(res) => res.filter((nestedSort) => !isEmpty$2(nestedSort))
|
|
13696
13733
|
);
|
|
13697
13734
|
}
|
|
13698
13735
|
).parse(isString, () => {
|
|
@@ -13702,7 +13739,7 @@ const sort = traverseFactory().intercept(
|
|
|
13702
13739
|
return void 0;
|
|
13703
13740
|
}
|
|
13704
13741
|
return parts.reduce((acc, part) => {
|
|
13705
|
-
if (isEmpty$
|
|
13742
|
+
if (isEmpty$2(part)) {
|
|
13706
13743
|
return acc;
|
|
13707
13744
|
}
|
|
13708
13745
|
if (acc === "") {
|
|
@@ -13797,7 +13834,7 @@ const isPopulateString = (value) => {
|
|
|
13797
13834
|
return isString(value) && !isWildcard(value);
|
|
13798
13835
|
};
|
|
13799
13836
|
const isStringArray$1 = (value) => isArray(value) && value.every(isString);
|
|
13800
|
-
const isObj = (value) => isObject$
|
|
13837
|
+
const isObj = (value) => isObject$5(value);
|
|
13801
13838
|
const populate$2 = traverseFactory().intercept(isPopulateString, async (visitor2, options, populate2, { recurse }) => {
|
|
13802
13839
|
const populateObject = pathsToObjectPopulate([populate2]);
|
|
13803
13840
|
const traversedPopulate = await recurse(visitor2, options, populateObject);
|
|
@@ -13846,7 +13883,7 @@ const populate$2 = traverseFactory().intercept(isPopulateString, async (visitor2
|
|
|
13846
13883
|
if (root2 !== key) {
|
|
13847
13884
|
return data;
|
|
13848
13885
|
}
|
|
13849
|
-
return isNil(value) || isEmpty$
|
|
13886
|
+
return isNil(value) || isEmpty$2(value) ? root2 : `${root2}.${value}`;
|
|
13850
13887
|
},
|
|
13851
13888
|
keys(data) {
|
|
13852
13889
|
const v = first(tokenize(data));
|
|
@@ -13907,7 +13944,7 @@ const populate$2 = traverseFactory().intercept(isPopulateString, async (visitor2
|
|
|
13907
13944
|
}
|
|
13908
13945
|
const parent = { key, path: path2, schema: schema2, attribute };
|
|
13909
13946
|
if (isMorphToRelationalAttribute(attribute)) {
|
|
13910
|
-
if (!isObject$
|
|
13947
|
+
if (!isObject$5(value) || !("on" in value && isObject$5(value?.on))) {
|
|
13911
13948
|
return;
|
|
13912
13949
|
}
|
|
13913
13950
|
const newValue2 = await recurse(
|
|
@@ -13956,7 +13993,7 @@ const populate$2 = traverseFactory().intercept(isPopulateString, async (visitor2
|
|
|
13956
13993
|
}
|
|
13957
13994
|
).onDynamicZone(
|
|
13958
13995
|
async ({ key, value, schema: schema2, visitor: visitor2, path: path2, attribute, getModel }, { set: set2, recurse }) => {
|
|
13959
|
-
if (isNil(value) || !isObject$
|
|
13996
|
+
if (isNil(value) || !isObject$5(value)) {
|
|
13960
13997
|
return;
|
|
13961
13998
|
}
|
|
13962
13999
|
const parent = { key, path: path2, schema: schema2, attribute };
|
|
@@ -14069,7 +14106,7 @@ const defaultSanitizeFilters = curry((ctx, filters2) => {
|
|
|
14069
14106
|
traverseQueryFilters(visitor$7, ctx),
|
|
14070
14107
|
// Remove empty objects
|
|
14071
14108
|
traverseQueryFilters(({ key, value }, { remove: remove2 }) => {
|
|
14072
|
-
if (isObject$
|
|
14109
|
+
if (isObject$5(value) && isEmpty$2(value)) {
|
|
14073
14110
|
remove2(key);
|
|
14074
14111
|
}
|
|
14075
14112
|
}, ctx)
|
|
@@ -14102,7 +14139,7 @@ const defaultSanitizeSort = curry((ctx, sort2) => {
|
|
|
14102
14139
|
if ([ID_ATTRIBUTE$2, DOC_ID_ATTRIBUTE$2].includes(key)) {
|
|
14103
14140
|
return;
|
|
14104
14141
|
}
|
|
14105
|
-
if (!isScalarAttribute(attribute) && isEmpty$
|
|
14142
|
+
if (!isScalarAttribute(attribute) && isEmpty$2(value)) {
|
|
14106
14143
|
remove2(key);
|
|
14107
14144
|
}
|
|
14108
14145
|
}, ctx)
|
|
@@ -14613,18 +14650,26 @@ const hasValue = (value) => {
|
|
|
14613
14650
|
return !(value === null || value === void 0 || Array.isArray(value) && value.length === 0 || typeof value === "object" && isEmpty(value));
|
|
14614
14651
|
};
|
|
14615
14652
|
async function _populateComponent({
|
|
14653
|
+
schema: schema2,
|
|
14616
14654
|
populate: populate2 = {},
|
|
14617
14655
|
lookup,
|
|
14618
14656
|
attrName,
|
|
14619
14657
|
inDynamicZone = false,
|
|
14658
|
+
__allow,
|
|
14659
|
+
__deny,
|
|
14620
14660
|
...params
|
|
14621
14661
|
}) {
|
|
14622
14662
|
const componentLookup = lookup.length === 0 ? [attrName] : [...lookup, inDynamicZone ? "on" : "populate", attrName];
|
|
14623
14663
|
const componentPopulate = populate2;
|
|
14624
14664
|
set$2(componentPopulate, componentLookup, { populate: "*" });
|
|
14665
|
+
if (__allow?.components && !__allow.components.includes(schema2)) return { populate: "*" };
|
|
14666
|
+
if (__deny?.components?.includes(schema2)) return { populate: "*" };
|
|
14625
14667
|
const nestedPopulate = await _populate({
|
|
14668
|
+
schema: schema2,
|
|
14626
14669
|
populate: componentPopulate,
|
|
14627
14670
|
lookup: componentLookup,
|
|
14671
|
+
__allow,
|
|
14672
|
+
__deny,
|
|
14628
14673
|
...params
|
|
14629
14674
|
});
|
|
14630
14675
|
return isEmpty(nestedPopulate) ? true : { populate: nestedPopulate };
|
|
@@ -14659,7 +14704,9 @@ async function _populateRelation({
|
|
|
14659
14704
|
resolvedRelations,
|
|
14660
14705
|
omitEmpty,
|
|
14661
14706
|
locale: locale2,
|
|
14662
|
-
status: status2
|
|
14707
|
+
status: status2,
|
|
14708
|
+
__deny,
|
|
14709
|
+
__allow
|
|
14663
14710
|
}) {
|
|
14664
14711
|
const isSingleRelation = !Array.isArray(relation);
|
|
14665
14712
|
const relations = isSingleRelation ? [relation] : relation;
|
|
@@ -14673,7 +14720,9 @@ async function _populateRelation({
|
|
|
14673
14720
|
resolvedRelations,
|
|
14674
14721
|
omitEmpty,
|
|
14675
14722
|
locale: locale2,
|
|
14676
|
-
status: status2
|
|
14723
|
+
status: status2,
|
|
14724
|
+
__deny,
|
|
14725
|
+
__allow
|
|
14677
14726
|
});
|
|
14678
14727
|
resolvedRelations.set(relation2.documentId, relationPopulate);
|
|
14679
14728
|
}
|
|
@@ -14723,6 +14772,8 @@ async function _populate({
|
|
|
14723
14772
|
lookup = [],
|
|
14724
14773
|
resolvedRelations,
|
|
14725
14774
|
omitEmpty,
|
|
14775
|
+
__deny,
|
|
14776
|
+
__allow,
|
|
14726
14777
|
...params
|
|
14727
14778
|
}) {
|
|
14728
14779
|
const newPopulate = {};
|
|
@@ -14751,6 +14802,26 @@ async function _populate({
|
|
|
14751
14802
|
if (!omitEmpty) newPopulate[attrName] = true;
|
|
14752
14803
|
continue;
|
|
14753
14804
|
}
|
|
14805
|
+
if (contentTypes.isRelationalAttribute(attr)) {
|
|
14806
|
+
if (__allow?.relations && !__allow.relations.includes(attr.target)) {
|
|
14807
|
+
newPopulate[attrName] = true;
|
|
14808
|
+
continue;
|
|
14809
|
+
}
|
|
14810
|
+
if (__deny?.relations?.includes(attr.target)) {
|
|
14811
|
+
newPopulate[attrName] = true;
|
|
14812
|
+
continue;
|
|
14813
|
+
}
|
|
14814
|
+
}
|
|
14815
|
+
if (contentTypes.isComponentAttribute(attr) && !contentTypes.isDynamicZoneAttribute(attr)) {
|
|
14816
|
+
if (__allow?.components && !__allow.components.includes(attr.component)) {
|
|
14817
|
+
newPopulate[attrName] = true;
|
|
14818
|
+
continue;
|
|
14819
|
+
}
|
|
14820
|
+
if (__deny?.components?.includes(attr.component)) {
|
|
14821
|
+
newPopulate[attrName] = true;
|
|
14822
|
+
continue;
|
|
14823
|
+
}
|
|
14824
|
+
}
|
|
14754
14825
|
resolveRelations.push([attrName, attr, value]);
|
|
14755
14826
|
}
|
|
14756
14827
|
relations = null;
|
|
@@ -14767,6 +14838,8 @@ async function _populate({
|
|
|
14767
14838
|
attrName,
|
|
14768
14839
|
resolvedRelations,
|
|
14769
14840
|
omitEmpty,
|
|
14841
|
+
__deny,
|
|
14842
|
+
__allow,
|
|
14770
14843
|
...params
|
|
14771
14844
|
});
|
|
14772
14845
|
}
|
|
@@ -14777,7 +14850,9 @@ async function _populate({
|
|
|
14777
14850
|
resolvedRelations,
|
|
14778
14851
|
omitEmpty,
|
|
14779
14852
|
locale: params.locale,
|
|
14780
|
-
status: params.status
|
|
14853
|
+
status: params.status,
|
|
14854
|
+
__deny,
|
|
14855
|
+
__allow
|
|
14781
14856
|
});
|
|
14782
14857
|
}
|
|
14783
14858
|
if (contentTypes.isComponentAttribute(attr) && !contentTypes.isDynamicZoneAttribute(attr)) {
|
|
@@ -14788,6 +14863,8 @@ async function _populate({
|
|
|
14788
14863
|
attrName,
|
|
14789
14864
|
resolvedRelations,
|
|
14790
14865
|
omitEmpty,
|
|
14866
|
+
__deny,
|
|
14867
|
+
__allow,
|
|
14791
14868
|
...params
|
|
14792
14869
|
});
|
|
14793
14870
|
}
|
|
@@ -14798,8 +14875,17 @@ async function _populate({
|
|
|
14798
14875
|
return newPopulate;
|
|
14799
14876
|
}
|
|
14800
14877
|
async function populate$1(params) {
|
|
14878
|
+
const { contentTypes: contentTypes2 } = strapi.config.get("plugin::deep-populate");
|
|
14879
|
+
const contentTypeConfig = has$2(contentTypes2, params.contentType) ? get$1(contentTypes2, params.contentType) : {};
|
|
14880
|
+
const { allow, deny } = contentTypeConfig;
|
|
14801
14881
|
const resolvedRelations = /* @__PURE__ */ new Map();
|
|
14802
|
-
const populated = await _populate({
|
|
14882
|
+
const populated = await _populate({
|
|
14883
|
+
...params,
|
|
14884
|
+
schema: params.contentType,
|
|
14885
|
+
resolvedRelations,
|
|
14886
|
+
__deny: deny,
|
|
14887
|
+
__allow: allow
|
|
14888
|
+
});
|
|
14803
14889
|
return { populate: populated, dependencies: [...resolvedRelations.keys()] };
|
|
14804
14890
|
}
|
|
14805
14891
|
const populate = ({ strapi: strapi2 }) => ({
|
|
@@ -1,10 +1,29 @@
|
|
|
1
|
+
import type { UID } from "@strapi/strapi";
|
|
2
|
+
export type ContentTypeConfigAllow = {
|
|
3
|
+
relations?: UID.ContentType[];
|
|
4
|
+
components?: UID.Component[];
|
|
5
|
+
};
|
|
6
|
+
export type ContentTypeConfigDeny = {
|
|
7
|
+
relations?: UID.ContentType[];
|
|
8
|
+
components?: UID.Component[];
|
|
9
|
+
};
|
|
10
|
+
type ContentTypeConfig = {
|
|
11
|
+
allow?: ContentTypeConfigAllow;
|
|
12
|
+
deny?: ContentTypeConfigDeny;
|
|
13
|
+
};
|
|
14
|
+
export type Config = {
|
|
15
|
+
useCache: boolean;
|
|
16
|
+
replaceWildcard: boolean;
|
|
17
|
+
contentTypes: Record<UID.ContentType, ContentTypeConfig>;
|
|
18
|
+
};
|
|
1
19
|
declare const _default: {
|
|
2
20
|
default: ({ env }: {
|
|
3
21
|
env: any;
|
|
4
22
|
}) => {
|
|
5
23
|
useCache: boolean;
|
|
6
24
|
replaceWildcard: boolean;
|
|
25
|
+
contentTypes: {};
|
|
7
26
|
};
|
|
8
|
-
validator: (config:
|
|
27
|
+
validator: (config: Config) => void;
|
|
9
28
|
};
|
|
10
29
|
export default _default;
|
package/package.json
CHANGED