@stackbit/cms-core 0.1.21 → 0.1.22-alpha.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/dist/content-store-types.d.ts +34 -8
- package/dist/content-store-types.d.ts.map +1 -1
- package/dist/content-store-utils.d.ts +3 -1
- package/dist/content-store-utils.d.ts.map +1 -1
- package/dist/content-store-utils.js +8 -1
- package/dist/content-store-utils.js.map +1 -1
- package/dist/content-store.d.ts +4 -2
- package/dist/content-store.d.ts.map +1 -1
- package/dist/content-store.js +59 -37
- package/dist/content-store.js.map +1 -1
- package/dist/utils/create-update-csi-docs.d.ts +11 -10
- package/dist/utils/create-update-csi-docs.d.ts.map +1 -1
- package/dist/utils/create-update-csi-docs.js +92 -13
- package/dist/utils/create-update-csi-docs.js.map +1 -1
- package/dist/utils/csi-to-store-docs-converter.d.ts.map +1 -1
- package/dist/utils/csi-to-store-docs-converter.js +74 -5
- package/dist/utils/csi-to-store-docs-converter.js.map +1 -1
- package/dist/utils/duplicate-document.d.ts +3 -2
- package/dist/utils/duplicate-document.d.ts.map +1 -1
- package/dist/utils/duplicate-document.js +86 -6
- package/dist/utils/duplicate-document.js.map +1 -1
- package/dist/utils/model-utils.d.ts +4 -4
- package/dist/utils/model-utils.d.ts.map +1 -1
- package/dist/utils/model-utils.js +67 -2
- package/dist/utils/model-utils.js.map +1 -1
- package/dist/utils/store-to-api-docs-converter.d.ts.map +1 -1
- package/dist/utils/store-to-api-docs-converter.js +53 -8
- package/dist/utils/store-to-api-docs-converter.js.map +1 -1
- package/dist/utils/store-to-csi-docs-converter.js +30 -0
- package/dist/utils/store-to-csi-docs-converter.js.map +1 -1
- package/package.json +5 -5
- package/src/content-store-types.ts +41 -3
- package/src/content-store-utils.ts +9 -1
- package/src/content-store.ts +63 -38
- package/src/utils/create-update-csi-docs.ts +109 -18
- package/src/utils/csi-to-store-docs-converter.ts +96 -21
- package/src/utils/duplicate-document.ts +98 -15
- package/src/utils/model-utils.ts +95 -7
- package/src/utils/store-to-api-docs-converter.ts +50 -6
- package/src/utils/store-to-csi-docs-converter.ts +30 -0
- package/dist/utils/schema-utils.d.ts +0 -87
- package/dist/utils/schema-utils.d.ts.map +0 -1
- package/dist/utils/schema-utils.js +0 -195
- package/dist/utils/schema-utils.js.map +0 -1
- package/src/utils/schema-utils.js +0 -212
package/src/utils/model-utils.ts
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
|
|
3
|
-
import { Logger } from '@stackbit/types';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
import { FieldCrossReferenceModel, Logger, ModelWithSource } from '@stackbit/types';
|
|
4
|
+
import {
|
|
5
|
+
Model,
|
|
6
|
+
assignLabelFieldIfNeeded,
|
|
7
|
+
isObjectField,
|
|
8
|
+
isCrossReferenceField,
|
|
9
|
+
isPageModel,
|
|
10
|
+
mapModelFieldsRecursively,
|
|
11
|
+
mapListItemsPropsOrSelfSpecificProps,
|
|
12
|
+
validateConfig
|
|
13
|
+
} from '@stackbit/sdk';
|
|
14
|
+
|
|
15
|
+
export function normalizeModels({ models, logger }: { models: ModelWithSource[]; logger: Logger }): ModelWithSource[] {
|
|
8
16
|
return models.map((model) => {
|
|
9
17
|
model = { ...model };
|
|
10
18
|
|
|
@@ -45,18 +53,98 @@ export function normalizeModels<T extends Model>({ models, logger }: { models: T
|
|
|
45
53
|
mapListItemsPropsOrSelfSpecificProps(field, (listItemsPropsOrField) => {
|
|
46
54
|
if (isObjectField(listItemsPropsOrField)) {
|
|
47
55
|
assignLabelFieldIfNeeded(listItemsPropsOrField);
|
|
56
|
+
} else if (isCrossReferenceField(listItemsPropsOrField)) {
|
|
57
|
+
listItemsPropsOrField.models = validateAndNormalizeCrossReferenceModels({
|
|
58
|
+
crossReferenceModels: listItemsPropsOrField.models,
|
|
59
|
+
models,
|
|
60
|
+
logger
|
|
61
|
+
});
|
|
48
62
|
}
|
|
49
63
|
return listItemsPropsOrField;
|
|
50
64
|
});
|
|
51
65
|
|
|
52
66
|
return field;
|
|
53
|
-
})
|
|
67
|
+
});
|
|
54
68
|
|
|
55
69
|
return model;
|
|
56
70
|
});
|
|
57
71
|
}
|
|
58
72
|
|
|
59
|
-
|
|
73
|
+
function validateAndNormalizeCrossReferenceModels({
|
|
74
|
+
crossReferenceModels,
|
|
75
|
+
models,
|
|
76
|
+
logger
|
|
77
|
+
}: {
|
|
78
|
+
crossReferenceModels: FieldCrossReferenceModel[];
|
|
79
|
+
models: ModelWithSource[];
|
|
80
|
+
logger: Logger;
|
|
81
|
+
}): FieldCrossReferenceModel[] {
|
|
82
|
+
const modelGroupsByModelName = models.reduce((modelGroups: Record<string, ModelWithSource[]>, model) => {
|
|
83
|
+
if (!(model.name in modelGroups)) {
|
|
84
|
+
modelGroups[model.name] = [];
|
|
85
|
+
}
|
|
86
|
+
modelGroups[model.name]!.push(model);
|
|
87
|
+
return modelGroups;
|
|
88
|
+
}, {});
|
|
89
|
+
|
|
90
|
+
// Match cross-reference models to the group of content source models with
|
|
91
|
+
// the same name. Then, match the cross-reference model to content source
|
|
92
|
+
// model by comparing srcType and srcProjectId. If after the comparison,
|
|
93
|
+
// there are more than one model left, log a warning and filter out that
|
|
94
|
+
// cross-reference model so it won't cause any model ambiguity.
|
|
95
|
+
const nonMatchedCrossReferenceModels: {
|
|
96
|
+
crossReferenceModel: FieldCrossReferenceModel;
|
|
97
|
+
matchedModels: ModelWithSource[];
|
|
98
|
+
}[] = [];
|
|
99
|
+
|
|
100
|
+
const normalizedCrossReferenceModels = crossReferenceModels.reduce((matchedCrossReferenceModels: FieldCrossReferenceModel[], crossReferenceModel) => {
|
|
101
|
+
const models = modelGroupsByModelName[crossReferenceModel.modelName];
|
|
102
|
+
if (!models) {
|
|
103
|
+
nonMatchedCrossReferenceModels.push({ crossReferenceModel, matchedModels: [] });
|
|
104
|
+
return matchedCrossReferenceModels;
|
|
105
|
+
}
|
|
106
|
+
const matchedModels = models.filter((model) => {
|
|
107
|
+
const matchesType = !crossReferenceModel.srcType || model.srcType === crossReferenceModel.srcType;
|
|
108
|
+
const matchesId = !crossReferenceModel.srcProjectId || model.srcProjectId === crossReferenceModel.srcProjectId;
|
|
109
|
+
return matchesType && matchesId;
|
|
110
|
+
});
|
|
111
|
+
if (matchedModels.length !== 1) {
|
|
112
|
+
nonMatchedCrossReferenceModels.push({ crossReferenceModel, matchedModels });
|
|
113
|
+
return matchedCrossReferenceModels;
|
|
114
|
+
}
|
|
115
|
+
const matchedModel = matchedModels[0]!;
|
|
116
|
+
matchedCrossReferenceModels.push({
|
|
117
|
+
modelName: crossReferenceModel.modelName,
|
|
118
|
+
srcType: matchedModel.srcType,
|
|
119
|
+
srcProjectId: matchedModel.srcProjectId
|
|
120
|
+
});
|
|
121
|
+
return matchedCrossReferenceModels;
|
|
122
|
+
}, []);
|
|
123
|
+
|
|
124
|
+
// Log model matching warnings using user logger
|
|
125
|
+
for (const { crossReferenceModel, matchedModels } of nonMatchedCrossReferenceModels) {
|
|
126
|
+
let message = `a model of cross-reference field: '${crossReferenceModel.modelName}'`;
|
|
127
|
+
if (crossReferenceModel.srcType) {
|
|
128
|
+
message += `, srcType: '${crossReferenceModel.srcType}'`;
|
|
129
|
+
}
|
|
130
|
+
if (crossReferenceModel.srcProjectId) {
|
|
131
|
+
message += `, srcProjectId: '${crossReferenceModel.srcProjectId}'`;
|
|
132
|
+
}
|
|
133
|
+
message = message + ` defined in stackbit config`;
|
|
134
|
+
let contentSourceModelsMessage;
|
|
135
|
+
if (matchedModels.length) {
|
|
136
|
+
const matchesModelsMessage = matchedModels.map((model) => `srcType: '${model.srcType}', srcProjectId: '${model.srcProjectId}'`).join('; ');
|
|
137
|
+
contentSourceModelsMessage = ` matches more that 1 model in the following content sources: ${matchesModelsMessage}`;
|
|
138
|
+
} else {
|
|
139
|
+
contentSourceModelsMessage = ' does not match any content source model';
|
|
140
|
+
}
|
|
141
|
+
logger.warn(message + contentSourceModelsMessage);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return normalizedCrossReferenceModels;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function validateModels<T extends Model>({ models, logger }: { models: T[]; logger: Logger }): T[] {
|
|
60
148
|
const { config, errors } = validateConfig({
|
|
61
149
|
stackbitVersion: '0.5.0',
|
|
62
150
|
models: models,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import { omitByNil } from '@stackbit/utils';
|
|
3
3
|
import * as ContentStoreTypes from '../content-store-types';
|
|
4
|
-
import { getDocumentFieldForLocale } from '../content-store-utils';
|
|
5
4
|
|
|
6
5
|
export function mapDocumentsToLocalizedApiObjects(documents: ContentStoreTypes.Document[], locale?: string): ContentStoreTypes.APIDocumentObject[] {
|
|
7
6
|
return documents.map((document) => documentToLocalizedApiObject(document, locale));
|
|
@@ -36,7 +35,7 @@ function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, locale?:
|
|
|
36
35
|
return null;
|
|
37
36
|
}
|
|
38
37
|
return {
|
|
39
|
-
localized:
|
|
38
|
+
localized: true,
|
|
40
39
|
locale: locale
|
|
41
40
|
};
|
|
42
41
|
}
|
|
@@ -144,7 +143,7 @@ function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, locale?:
|
|
|
144
143
|
}),
|
|
145
144
|
...localeFields(docField.localized)
|
|
146
145
|
};
|
|
147
|
-
case 'reference':
|
|
146
|
+
case 'reference': {
|
|
148
147
|
if (docField.localized) {
|
|
149
148
|
const { type, refType, localized, locales, ...base } = docField;
|
|
150
149
|
const localeProps = locales && locale ? locales[locale] : undefined;
|
|
@@ -179,6 +178,43 @@ function toLocalizedAPIField(docField: ContentStoreTypes.DocumentField, locale?:
|
|
|
179
178
|
...base,
|
|
180
179
|
...localeFields(docField.localized)
|
|
181
180
|
};
|
|
181
|
+
}
|
|
182
|
+
case 'cross-reference': {
|
|
183
|
+
if (docField.localized) {
|
|
184
|
+
const { type, refType, localized, locales, ...base } = docField;
|
|
185
|
+
const localeProps = locales && locale ? locales[locale] : undefined;
|
|
186
|
+
// if reference field isUnset === true, it behaves like a regular object
|
|
187
|
+
if (!localeProps) {
|
|
188
|
+
return {
|
|
189
|
+
type: 'object',
|
|
190
|
+
isUnset: true,
|
|
191
|
+
...base,
|
|
192
|
+
...localeFields(localized)
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
type: 'cross-reference',
|
|
197
|
+
refType: refType,
|
|
198
|
+
...base,
|
|
199
|
+
...localeProps,
|
|
200
|
+
...localeFields(localized)
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
const { type, refType, ...base } = docField;
|
|
204
|
+
if (base.isUnset) {
|
|
205
|
+
return {
|
|
206
|
+
type: 'object',
|
|
207
|
+
...base,
|
|
208
|
+
...localeFields(docField.localized)
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
type: 'cross-reference',
|
|
213
|
+
refType: refType,
|
|
214
|
+
...base,
|
|
215
|
+
...localeFields(docField.localized)
|
|
216
|
+
};
|
|
217
|
+
}
|
|
182
218
|
case 'list':
|
|
183
219
|
if (docField.localized) {
|
|
184
220
|
const { localized, locales, ...base } = docField;
|
|
@@ -226,13 +262,21 @@ function localizeAssetFields(assetFields: ContentStoreTypes.AssetFields, locale?
|
|
|
226
262
|
value: null as any
|
|
227
263
|
}
|
|
228
264
|
};
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
265
|
+
const titleField = assetFields.title;
|
|
266
|
+
if (titleField.localized) {
|
|
267
|
+
if (locale) {
|
|
268
|
+
fields.title.value = titleField.locales?.[locale]?.value ?? null;
|
|
269
|
+
fields.title.localized = true;
|
|
270
|
+
fields.title.locale = locale;
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
fields.title.value = titleField.value;
|
|
274
|
+
}
|
|
232
275
|
const assetFileField = assetFields.file;
|
|
233
276
|
if (assetFileField.localized) {
|
|
234
277
|
if (locale) {
|
|
235
278
|
fields.url.value = assetFileField.locales?.[locale]?.url ?? null;
|
|
279
|
+
fields.url.localized = true;
|
|
236
280
|
fields.url.locale = locale;
|
|
237
281
|
}
|
|
238
282
|
} else {
|
|
@@ -179,6 +179,36 @@ function mapStoreFieldToCSIField(documentField: ContentStoreTypes.DocumentField)
|
|
|
179
179
|
refId: documentField.refId
|
|
180
180
|
};
|
|
181
181
|
}
|
|
182
|
+
case 'cross-reference': {
|
|
183
|
+
if (documentField.localized) {
|
|
184
|
+
if (_.isEmpty(documentField.locales)) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
type: 'json',
|
|
189
|
+
localized: true,
|
|
190
|
+
locales: _.mapValues(documentField.locales, (locale) => ({
|
|
191
|
+
locale: locale.locale,
|
|
192
|
+
value: {
|
|
193
|
+
refId: locale.refId,
|
|
194
|
+
refSrcType: locale.refSrcType,
|
|
195
|
+
srcProjectId: locale.refProjectId
|
|
196
|
+
}
|
|
197
|
+
}))
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
if (documentField.isUnset) {
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
type: 'json',
|
|
205
|
+
value: {
|
|
206
|
+
refId: documentField.refId,
|
|
207
|
+
refSrcType: documentField.refSrcType,
|
|
208
|
+
srcProjectId: documentField.refProjectId
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
}
|
|
182
212
|
case 'list': {
|
|
183
213
|
if (documentField.localized) {
|
|
184
214
|
if (_.isEmpty(documentField.locales)) {
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
export const FIELD_TYPES: string[];
|
|
2
|
-
export function isObjectField(field: any): boolean;
|
|
3
|
-
export function isModelField(field: any): boolean;
|
|
4
|
-
export function isModelsField(field: any): boolean;
|
|
5
|
-
export function isReferenceField(field: any): boolean;
|
|
6
|
-
export function isCustomModelField(field: any, modelsByName: any): boolean;
|
|
7
|
-
export function isListField(field: any): boolean;
|
|
8
|
-
export function isListOfObjectsField(field: any): boolean;
|
|
9
|
-
export function isListOfModelField(field: any): boolean;
|
|
10
|
-
export function isListOfModelsField(field: any): boolean;
|
|
11
|
-
export function isListOfCustomModelField(field: any): boolean;
|
|
12
|
-
export function isListOfReferenceField(field: any): boolean;
|
|
13
|
-
/**
|
|
14
|
-
* Gets a list field and returns its items field. If list field does not define
|
|
15
|
-
* items field, the default field is string:
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* listItemField = getListItemsField({
|
|
19
|
-
* type: 'list',
|
|
20
|
-
* name: '...',
|
|
21
|
-
* items: { type: 'object', fields: [] }
|
|
22
|
-
* }
|
|
23
|
-
* listItemField => {
|
|
24
|
-
* type: 'object',
|
|
25
|
-
* name: '...',
|
|
26
|
-
* fields: []
|
|
27
|
-
* }
|
|
28
|
-
*
|
|
29
|
-
* // list field without `items`
|
|
30
|
-
* listItemField = getListItemsField({ type: 'list', name: '...' }
|
|
31
|
-
* listItemField => { type: 'string' }
|
|
32
|
-
*
|
|
33
|
-
* @param {Object} field
|
|
34
|
-
* @return {Object}
|
|
35
|
-
*/
|
|
36
|
-
export function getListItemsField(field: Object): Object;
|
|
37
|
-
/**
|
|
38
|
-
* This function invokes the `iterator` function for every field of the `model`.
|
|
39
|
-
* It recursively traverses through fields of type `object` and `list` with
|
|
40
|
-
* items of type `object` and invokes the `iterator` on their child fields,
|
|
41
|
-
* and so on. The traversal is a depth-first and the `iterator` is invoked
|
|
42
|
-
* before traversing the field's child fields.
|
|
43
|
-
*
|
|
44
|
-
* The iterator is invoked with two parameters, `field` and `fieldPath`. The
|
|
45
|
-
* `field` is the currently iterated field, and `fieldPath` is an array of
|
|
46
|
-
* strings indicating the path of the `field` relative to the model.
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* model = {
|
|
50
|
-
* fields: [
|
|
51
|
-
* { name: "title", type: "string" },
|
|
52
|
-
* {
|
|
53
|
-
* name: "banner",
|
|
54
|
-
* type: "object",
|
|
55
|
-
* fields: [
|
|
56
|
-
* { name: "logo", type: "image" }
|
|
57
|
-
* ]}
|
|
58
|
-
* {
|
|
59
|
-
* name: "actions",
|
|
60
|
-
* type: "list",
|
|
61
|
-
* items: {
|
|
62
|
-
* type: "object",
|
|
63
|
-
* fields: [
|
|
64
|
-
* {name: "label", type: "string"}
|
|
65
|
-
* ]
|
|
66
|
-
* }
|
|
67
|
-
* }
|
|
68
|
-
* ]
|
|
69
|
-
* }
|
|
70
|
-
* iterateModelFieldsRecursively(model, iterator);
|
|
71
|
-
* // will call the iterator with following field.name and fieldPath
|
|
72
|
-
* - 'title', ['fields', 'title']
|
|
73
|
-
* - 'banner', ['fields', 'banner']
|
|
74
|
-
* - 'logo', ['fields', 'banner', 'fields', 'logo']
|
|
75
|
-
* - 'actions', ['fields', 'actions']
|
|
76
|
-
* - 'label', ['fields', 'actions', 'items', 'fields', 'label']
|
|
77
|
-
*
|
|
78
|
-
* @param {Object} model The root model to iterate fields
|
|
79
|
-
* @param {Function} iterator The iterator function
|
|
80
|
-
* @param {Array} [fieldPath]
|
|
81
|
-
*/
|
|
82
|
-
export function iterateModelFieldsRecursively(model: Object, iterator: Function, fieldPath?: any[] | undefined): void;
|
|
83
|
-
export function resolveLabelFieldForModel(model: any, modelLabelFieldPath: any, fields: any): any;
|
|
84
|
-
export function resolveLabelFieldFromFields(fields: any): any;
|
|
85
|
-
export function getUrlPath(stackbitModel: any): any;
|
|
86
|
-
export function getNormalizedModelType(stackbitModel: any): any;
|
|
87
|
-
//# sourceMappingURL=schema-utils.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema-utils.d.ts","sourceRoot":"","sources":["../../src/utils/schema-utils.js"],"names":[],"mappings":"AAEA,mCAuBE;AA6CF,mDAEC;AAUD,kDAEC;AAED,mDAEC;AAdD,sDAEC;AAED,2EAEC;AAUD,iDAEC;AAED,0DAEC;AAED,wDAEC;AAED,yDAEC;AAED,8DAEC;AAED,4DAEC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,yCAHW,MAAM,GACL,MAAM,CAKjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,qDAJW,MAAM,2DAgBhB;AAtJD,kGAMC;AAED,8DAWC;AAqID,oDAMC;AAED,gEAEC"}
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const _ = require('lodash');
|
|
3
|
-
const FIELD_TYPES = [
|
|
4
|
-
'string',
|
|
5
|
-
'text',
|
|
6
|
-
'markdown',
|
|
7
|
-
'html',
|
|
8
|
-
'url',
|
|
9
|
-
'slug',
|
|
10
|
-
'number',
|
|
11
|
-
'boolean',
|
|
12
|
-
'select',
|
|
13
|
-
'enum',
|
|
14
|
-
'date',
|
|
15
|
-
'datetime',
|
|
16
|
-
'color',
|
|
17
|
-
'image',
|
|
18
|
-
'file',
|
|
19
|
-
'json',
|
|
20
|
-
'reference',
|
|
21
|
-
'model',
|
|
22
|
-
'models',
|
|
23
|
-
'object',
|
|
24
|
-
'list',
|
|
25
|
-
'array'
|
|
26
|
-
];
|
|
27
|
-
module.exports = {
|
|
28
|
-
FIELD_TYPES,
|
|
29
|
-
isObjectField,
|
|
30
|
-
isModelField,
|
|
31
|
-
isModelsField,
|
|
32
|
-
isReferenceField,
|
|
33
|
-
isCustomModelField,
|
|
34
|
-
isListField,
|
|
35
|
-
isListOfObjectsField,
|
|
36
|
-
isListOfModelField,
|
|
37
|
-
isListOfModelsField,
|
|
38
|
-
isListOfCustomModelField,
|
|
39
|
-
isListOfReferenceField,
|
|
40
|
-
getListItemsField,
|
|
41
|
-
iterateModelFieldsRecursively,
|
|
42
|
-
resolveLabelFieldForModel,
|
|
43
|
-
resolveLabelFieldFromFields,
|
|
44
|
-
getUrlPath,
|
|
45
|
-
getNormalizedModelType
|
|
46
|
-
};
|
|
47
|
-
function resolveLabelFieldForModel(model, modelLabelFieldPath, fields) {
|
|
48
|
-
let labelField = _.get(model, modelLabelFieldPath, null);
|
|
49
|
-
if (labelField) {
|
|
50
|
-
return labelField;
|
|
51
|
-
}
|
|
52
|
-
return resolveLabelFieldFromFields(fields);
|
|
53
|
-
}
|
|
54
|
-
function resolveLabelFieldFromFields(fields) {
|
|
55
|
-
let labelField = null;
|
|
56
|
-
let titleField = _.find(fields, field => field.name === 'title' && _.includes(['string', 'text'], field.type));
|
|
57
|
-
if (!titleField) {
|
|
58
|
-
// get first string field
|
|
59
|
-
titleField = _.find(fields, { type: 'string' });
|
|
60
|
-
}
|
|
61
|
-
if (titleField) {
|
|
62
|
-
labelField = _.get(titleField, 'name');
|
|
63
|
-
}
|
|
64
|
-
return labelField;
|
|
65
|
-
}
|
|
66
|
-
function isObjectField(field) {
|
|
67
|
-
return field.type === 'object';
|
|
68
|
-
}
|
|
69
|
-
function isReferenceField(field) {
|
|
70
|
-
return field.type === 'reference';
|
|
71
|
-
}
|
|
72
|
-
function isCustomModelField(field, modelsByName) {
|
|
73
|
-
return !FIELD_TYPES.includes(field.type) && (!modelsByName || _.has(modelsByName, field.type));
|
|
74
|
-
}
|
|
75
|
-
function isModelField(field) {
|
|
76
|
-
return field.type === 'model';
|
|
77
|
-
}
|
|
78
|
-
function isModelsField(field) {
|
|
79
|
-
return field.type === 'models';
|
|
80
|
-
}
|
|
81
|
-
function isListField(field) {
|
|
82
|
-
return ['list', 'array'].includes(field.type);
|
|
83
|
-
}
|
|
84
|
-
function isListOfObjectsField(field) {
|
|
85
|
-
return isListField(field) && isObjectField(getListItemsField(field));
|
|
86
|
-
}
|
|
87
|
-
function isListOfModelField(field) {
|
|
88
|
-
return isListField(field) && isModelField(getListItemsField(field));
|
|
89
|
-
}
|
|
90
|
-
function isListOfModelsField(field) {
|
|
91
|
-
return isListField(field) && isModelsField(getListItemsField(field));
|
|
92
|
-
}
|
|
93
|
-
function isListOfCustomModelField(field) {
|
|
94
|
-
return isListField(field) && isCustomModelField(getListItemsField(field));
|
|
95
|
-
}
|
|
96
|
-
function isListOfReferenceField(field) {
|
|
97
|
-
return isListField(field) && isReferenceField(getListItemsField(field));
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Gets a list field and returns its items field. If list field does not define
|
|
101
|
-
* items field, the default field is string:
|
|
102
|
-
*
|
|
103
|
-
* @example
|
|
104
|
-
* listItemField = getListItemsField({
|
|
105
|
-
* type: 'list',
|
|
106
|
-
* name: '...',
|
|
107
|
-
* items: { type: 'object', fields: [] }
|
|
108
|
-
* }
|
|
109
|
-
* listItemField => {
|
|
110
|
-
* type: 'object',
|
|
111
|
-
* name: '...',
|
|
112
|
-
* fields: []
|
|
113
|
-
* }
|
|
114
|
-
*
|
|
115
|
-
* // list field without `items`
|
|
116
|
-
* listItemField = getListItemsField({ type: 'list', name: '...' }
|
|
117
|
-
* listItemField => { type: 'string' }
|
|
118
|
-
*
|
|
119
|
-
* @param {Object} field
|
|
120
|
-
* @return {Object}
|
|
121
|
-
*/
|
|
122
|
-
function getListItemsField(field) {
|
|
123
|
-
// items.type defaults to string
|
|
124
|
-
return _.defaults({}, _.get(field, 'items', {}), { type: 'string' });
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* This function invokes the `iterator` function for every field of the `model`.
|
|
128
|
-
* It recursively traverses through fields of type `object` and `list` with
|
|
129
|
-
* items of type `object` and invokes the `iterator` on their child fields,
|
|
130
|
-
* and so on. The traversal is a depth-first and the `iterator` is invoked
|
|
131
|
-
* before traversing the field's child fields.
|
|
132
|
-
*
|
|
133
|
-
* The iterator is invoked with two parameters, `field` and `fieldPath`. The
|
|
134
|
-
* `field` is the currently iterated field, and `fieldPath` is an array of
|
|
135
|
-
* strings indicating the path of the `field` relative to the model.
|
|
136
|
-
*
|
|
137
|
-
* @example
|
|
138
|
-
* model = {
|
|
139
|
-
* fields: [
|
|
140
|
-
* { name: "title", type: "string" },
|
|
141
|
-
* {
|
|
142
|
-
* name: "banner",
|
|
143
|
-
* type: "object",
|
|
144
|
-
* fields: [
|
|
145
|
-
* { name: "logo", type: "image" }
|
|
146
|
-
* ]}
|
|
147
|
-
* {
|
|
148
|
-
* name: "actions",
|
|
149
|
-
* type: "list",
|
|
150
|
-
* items: {
|
|
151
|
-
* type: "object",
|
|
152
|
-
* fields: [
|
|
153
|
-
* {name: "label", type: "string"}
|
|
154
|
-
* ]
|
|
155
|
-
* }
|
|
156
|
-
* }
|
|
157
|
-
* ]
|
|
158
|
-
* }
|
|
159
|
-
* iterateModelFieldsRecursively(model, iterator);
|
|
160
|
-
* // will call the iterator with following field.name and fieldPath
|
|
161
|
-
* - 'title', ['fields', 'title']
|
|
162
|
-
* - 'banner', ['fields', 'banner']
|
|
163
|
-
* - 'logo', ['fields', 'banner', 'fields', 'logo']
|
|
164
|
-
* - 'actions', ['fields', 'actions']
|
|
165
|
-
* - 'label', ['fields', 'actions', 'items', 'fields', 'label']
|
|
166
|
-
*
|
|
167
|
-
* @param {Object} model The root model to iterate fields
|
|
168
|
-
* @param {Function} iterator The iterator function
|
|
169
|
-
* @param {Array} [fieldPath]
|
|
170
|
-
*/
|
|
171
|
-
function iterateModelFieldsRecursively(model, iterator, fieldPath = []) {
|
|
172
|
-
const fields = _.get(model, 'fields', []);
|
|
173
|
-
fieldPath = fieldPath.concat('fields');
|
|
174
|
-
_.forEach(fields, (field) => {
|
|
175
|
-
const childFieldPath = fieldPath.concat(field.name);
|
|
176
|
-
iterator(field, childFieldPath);
|
|
177
|
-
if (isObjectField(field)) {
|
|
178
|
-
iterateModelFieldsRecursively(field, iterator, childFieldPath);
|
|
179
|
-
}
|
|
180
|
-
else if (isListOfObjectsField(field)) {
|
|
181
|
-
iterateModelFieldsRecursively(getListItemsField(field), iterator, childFieldPath.concat('items'));
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
function getUrlPath(stackbitModel) {
|
|
186
|
-
const modelType = getNormalizedModelType(stackbitModel);
|
|
187
|
-
if (modelType === 'page') {
|
|
188
|
-
return _.get(stackbitModel, 'urlPath', '/{slug}');
|
|
189
|
-
}
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
function getNormalizedModelType(stackbitModel) {
|
|
193
|
-
return stackbitModel ? (stackbitModel.type === 'config' ? 'data' : stackbitModel.type) : 'object';
|
|
194
|
-
}
|
|
195
|
-
//# sourceMappingURL=schema-utils.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"schema-utils.js","sourceRoot":"","sources":["../../src/utils/schema-utils.js"],"names":[],"mappings":"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"}
|