@stackbit/cms-core 0.1.16 → 0.1.17-alpha.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/dist/content-store-types.d.ts +1 -1
- package/dist/content-store-types.d.ts.map +1 -1
- package/dist/content-store.d.ts +8 -1
- package/dist/content-store.d.ts.map +1 -1
- package/dist/content-store.js +57 -25
- package/dist/content-store.js.map +1 -1
- package/dist/utils/create-update-csi-docs.d.ts +12 -8
- package/dist/utils/create-update-csi-docs.d.ts.map +1 -1
- package/dist/utils/create-update-csi-docs.js +120 -53
- package/dist/utils/create-update-csi-docs.js.map +1 -1
- package/dist/utils/csi-to-store-docs-converter.js +31 -9
- package/dist/utils/csi-to-store-docs-converter.js.map +1 -1
- package/dist/utils/model-utils.js +2 -2
- package/dist/utils/model-utils.js.map +1 -1
- package/dist/utils/site-map.d.ts +5 -0
- package/dist/utils/site-map.d.ts.map +1 -1
- package/dist/utils/site-map.js +11 -3
- package/dist/utils/site-map.js.map +1 -1
- package/package.json +5 -5
- package/src/content-store-types.ts +1 -1
- package/src/content-store.ts +75 -29
- package/src/utils/create-update-csi-docs.ts +141 -58
- package/src/utils/csi-to-store-docs-converter.ts +31 -9
- package/src/utils/model-utils.ts +2 -2
- package/src/utils/site-map.ts +11 -3
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import slugify from 'slugify';
|
|
3
3
|
|
|
4
|
-
import { Model } from '@stackbit/sdk';
|
|
5
|
-
import { Model as CSIModel, Field,
|
|
6
|
-
import { mapPromise } from '@stackbit/utils';
|
|
4
|
+
import { Model as SDKModel } from '@stackbit/sdk';
|
|
5
|
+
import { Model as CSIModel, Field, FieldSpecificProps, UpdateOperationListFieldItem } from '@stackbit/types';
|
|
6
|
+
import { fieldPathToString, mapPromise } from '@stackbit/utils';
|
|
7
7
|
import * as CSITypes from '@stackbit/types';
|
|
8
8
|
|
|
9
9
|
import * as ContentStoreTypes from '../content-store-types';
|
|
@@ -19,11 +19,13 @@ export type CreateDocumentCallback = ({
|
|
|
19
19
|
export function getCreateDocumentThunk({
|
|
20
20
|
csiModelMap,
|
|
21
21
|
locale,
|
|
22
|
+
defaultLocaleDocumentId,
|
|
22
23
|
userContext,
|
|
23
24
|
contentSourceInstance
|
|
24
25
|
}: {
|
|
25
26
|
csiModelMap: Record<string, CSIModel>;
|
|
26
27
|
locale?: string;
|
|
28
|
+
defaultLocaleDocumentId?: string;
|
|
27
29
|
userContext: unknown;
|
|
28
30
|
contentSourceInstance: CSITypes.ContentSourceInterface;
|
|
29
31
|
}): CreateDocumentCallback {
|
|
@@ -41,6 +43,7 @@ export function getCreateDocumentThunk({
|
|
|
41
43
|
model: csiModel,
|
|
42
44
|
modelMap: csiModelMap,
|
|
43
45
|
locale,
|
|
46
|
+
defaultLocaleDocumentId,
|
|
44
47
|
userContext
|
|
45
48
|
});
|
|
46
49
|
};
|
|
@@ -88,15 +91,18 @@ export async function createDocumentRecursively({
|
|
|
88
91
|
object,
|
|
89
92
|
modelName,
|
|
90
93
|
modelMap,
|
|
94
|
+
csiModelMap,
|
|
91
95
|
createDocument
|
|
92
96
|
}: {
|
|
93
97
|
object?: Record<string, any>;
|
|
94
98
|
modelName: string;
|
|
95
|
-
modelMap: Record<string,
|
|
99
|
+
modelMap: Record<string, SDKModel>;
|
|
100
|
+
csiModelMap: Record<string, CSIModel>;
|
|
96
101
|
createDocument: CreateDocumentCallback;
|
|
97
102
|
}): Promise<{ document: CSITypes.Document; newRefDocuments: CSITypes.Document[] }> {
|
|
98
103
|
const model = modelMap[modelName];
|
|
99
|
-
|
|
104
|
+
const csiModel = csiModelMap[modelName];
|
|
105
|
+
if (!model || !csiModel) {
|
|
100
106
|
throw new Error(`no model with name '${modelName}' was found`);
|
|
101
107
|
}
|
|
102
108
|
if (model.type === 'page') {
|
|
@@ -108,11 +114,13 @@ export async function createDocumentRecursively({
|
|
|
108
114
|
}
|
|
109
115
|
}
|
|
110
116
|
|
|
111
|
-
const nestedResult = await
|
|
117
|
+
const nestedResult = await createObjectRecursively({
|
|
112
118
|
object,
|
|
113
119
|
modelFields: model.fields ?? [],
|
|
114
|
-
|
|
120
|
+
csiModelFields: csiModel.fields ?? [],
|
|
121
|
+
fieldPath: [modelName],
|
|
115
122
|
modelMap,
|
|
123
|
+
csiModelMap,
|
|
116
124
|
createDocument
|
|
117
125
|
});
|
|
118
126
|
|
|
@@ -137,17 +145,21 @@ function sanitizeSlug(slug: string) {
|
|
|
137
145
|
.join('/');
|
|
138
146
|
}
|
|
139
147
|
|
|
140
|
-
async function
|
|
148
|
+
async function createObjectRecursively({
|
|
141
149
|
object,
|
|
142
150
|
modelFields,
|
|
151
|
+
csiModelFields,
|
|
143
152
|
fieldPath,
|
|
144
153
|
modelMap,
|
|
154
|
+
csiModelMap,
|
|
145
155
|
createDocument
|
|
146
156
|
}: {
|
|
147
157
|
object?: Record<string, any>;
|
|
148
158
|
modelFields: Field[];
|
|
159
|
+
csiModelFields: Field[];
|
|
149
160
|
fieldPath: (string | number)[];
|
|
150
|
-
modelMap: Record<string,
|
|
161
|
+
modelMap: Record<string, SDKModel>;
|
|
162
|
+
csiModelMap: Record<string, CSIModel>;
|
|
151
163
|
createDocument: CreateDocumentCallback;
|
|
152
164
|
}): Promise<{
|
|
153
165
|
fields: Record<string, CSITypes.UpdateOperationField>;
|
|
@@ -170,6 +182,10 @@ async function createNestedObjectRecursively({
|
|
|
170
182
|
const objectFieldNames = Object.keys(object);
|
|
171
183
|
for (const modelField of modelFields) {
|
|
172
184
|
const fieldName = modelField.name;
|
|
185
|
+
const csiModelField = csiModelFields.find((field) => field.name === fieldName);
|
|
186
|
+
if (!csiModelField) {
|
|
187
|
+
throw new Error(`no model field found for field at path ${fieldPathToString(fieldPath.concat(fieldName))}`);
|
|
188
|
+
}
|
|
173
189
|
let value;
|
|
174
190
|
if (fieldName in object) {
|
|
175
191
|
// if the object has a field name matching a model field, use it
|
|
@@ -183,11 +199,13 @@ async function createNestedObjectRecursively({
|
|
|
183
199
|
value = modelField.default;
|
|
184
200
|
}
|
|
185
201
|
if (!_.isNil(value)) {
|
|
186
|
-
const fieldResult = await
|
|
202
|
+
const fieldResult = await createUpdateOperationFieldRecursively({
|
|
187
203
|
value,
|
|
188
204
|
modelField,
|
|
205
|
+
csiModelField,
|
|
189
206
|
fieldPath: fieldPath.concat(fieldName),
|
|
190
207
|
modelMap,
|
|
208
|
+
csiModelMap,
|
|
191
209
|
createDocument
|
|
192
210
|
});
|
|
193
211
|
result.fields[fieldName] = fieldResult.field;
|
|
@@ -201,25 +219,34 @@ async function createNestedObjectRecursively({
|
|
|
201
219
|
return result;
|
|
202
220
|
}
|
|
203
221
|
|
|
204
|
-
async function
|
|
222
|
+
async function createUpdateOperationFieldRecursively({
|
|
205
223
|
value,
|
|
206
224
|
modelField,
|
|
225
|
+
csiModelField,
|
|
207
226
|
fieldPath,
|
|
208
227
|
modelMap,
|
|
228
|
+
csiModelMap,
|
|
209
229
|
createDocument
|
|
210
230
|
}: {
|
|
211
231
|
value: any;
|
|
212
232
|
modelField: FieldSpecificProps;
|
|
233
|
+
csiModelField: FieldSpecificProps;
|
|
213
234
|
fieldPath: (string | number)[];
|
|
214
|
-
modelMap: Record<string,
|
|
235
|
+
modelMap: Record<string, SDKModel>;
|
|
236
|
+
csiModelMap: Record<string, CSIModel>;
|
|
215
237
|
createDocument: CreateDocumentCallback;
|
|
216
238
|
}): Promise<{ field: CSITypes.UpdateOperationField; newRefDocuments: CSITypes.Document[] }> {
|
|
217
|
-
if (
|
|
218
|
-
|
|
239
|
+
if (csiModelField.type === 'object') {
|
|
240
|
+
if (modelField.type !== 'object') {
|
|
241
|
+
throw new Error(`field type mismatch between content-source and mapped models at field path ${fieldPathToString(fieldPath)}`);
|
|
242
|
+
}
|
|
243
|
+
const result = await createObjectRecursively({
|
|
219
244
|
object: value,
|
|
220
245
|
modelFields: modelField.fields,
|
|
246
|
+
csiModelFields: csiModelField.fields,
|
|
221
247
|
fieldPath,
|
|
222
248
|
modelMap,
|
|
249
|
+
csiModelMap,
|
|
223
250
|
createDocument
|
|
224
251
|
});
|
|
225
252
|
return {
|
|
@@ -229,7 +256,10 @@ async function createNestedField({
|
|
|
229
256
|
},
|
|
230
257
|
newRefDocuments: result.newRefDocuments
|
|
231
258
|
};
|
|
232
|
-
} else if (
|
|
259
|
+
} else if (csiModelField.type === 'model') {
|
|
260
|
+
if (modelField.type !== 'model') {
|
|
261
|
+
throw new Error(`field type mismatch between content-source and mapped models at field path ${fieldPathToString(fieldPath)}`);
|
|
262
|
+
}
|
|
233
263
|
let { $$type, ...rest } = value;
|
|
234
264
|
const modelNames = modelField.models;
|
|
235
265
|
// for backward compatibility check if the object has 'type' instead of '$$type' because older projects use
|
|
@@ -243,14 +273,17 @@ async function createNestedField({
|
|
|
243
273
|
throw new Error(`no $$type was specified for nested model`);
|
|
244
274
|
}
|
|
245
275
|
const model = modelMap[modelName];
|
|
246
|
-
|
|
276
|
+
const csiModel = csiModelMap[modelName];
|
|
277
|
+
if (!model || !csiModel) {
|
|
247
278
|
throw new Error(`no model with name '${modelName}' was found`);
|
|
248
279
|
}
|
|
249
|
-
const result = await
|
|
280
|
+
const result = await createObjectRecursively({
|
|
250
281
|
object: rest,
|
|
251
282
|
modelFields: model.fields ?? [],
|
|
283
|
+
csiModelFields: csiModel.fields ?? [],
|
|
252
284
|
fieldPath,
|
|
253
285
|
modelMap,
|
|
286
|
+
csiModelMap,
|
|
254
287
|
createDocument
|
|
255
288
|
});
|
|
256
289
|
return {
|
|
@@ -261,7 +294,7 @@ async function createNestedField({
|
|
|
261
294
|
},
|
|
262
295
|
newRefDocuments: result.newRefDocuments
|
|
263
296
|
};
|
|
264
|
-
} else if (
|
|
297
|
+
} else if (csiModelField.type === 'image') {
|
|
265
298
|
let refId: string | undefined;
|
|
266
299
|
// TODO: if modelField.source is cloudinary, the new document field
|
|
267
300
|
// should be of the 'image' type with 'title' and 'url' properties
|
|
@@ -281,7 +314,10 @@ async function createNestedField({
|
|
|
281
314
|
},
|
|
282
315
|
newRefDocuments: []
|
|
283
316
|
};
|
|
284
|
-
} else if (
|
|
317
|
+
} else if (csiModelField.type === 'reference') {
|
|
318
|
+
if (modelField.type !== 'reference') {
|
|
319
|
+
throw new Error(`field type mismatch between content-source and mapped models at field path ${fieldPathToString(fieldPath)}`);
|
|
320
|
+
}
|
|
285
321
|
let { $$ref: refId = null, $$type: modelName = null, ...rest } = _.isPlainObject(value) ? value : { $$ref: value };
|
|
286
322
|
if (refId) {
|
|
287
323
|
return {
|
|
@@ -308,6 +344,7 @@ async function createNestedField({
|
|
|
308
344
|
object: rest,
|
|
309
345
|
modelName,
|
|
310
346
|
modelMap,
|
|
347
|
+
csiModelMap,
|
|
311
348
|
createDocument
|
|
312
349
|
});
|
|
313
350
|
return {
|
|
@@ -319,22 +356,28 @@ async function createNestedField({
|
|
|
319
356
|
newRefDocuments: [document, ...newRefDocuments]
|
|
320
357
|
};
|
|
321
358
|
}
|
|
322
|
-
} else if (
|
|
359
|
+
} else if (csiModelField.type === 'list') {
|
|
360
|
+
if (modelField.type !== 'list') {
|
|
361
|
+
throw new Error(`field type mismatch between external and internal models at field path ${fieldPathToString(fieldPath)}`);
|
|
362
|
+
}
|
|
323
363
|
if (!Array.isArray(value)) {
|
|
324
364
|
throw new Error(`value for list field must be array`);
|
|
325
365
|
}
|
|
326
366
|
const itemsField = modelField.items;
|
|
327
|
-
|
|
367
|
+
const csiItemsField = csiModelField.items;
|
|
368
|
+
if (!itemsField || !csiItemsField) {
|
|
328
369
|
throw new Error(`list field does not define items`);
|
|
329
370
|
}
|
|
330
371
|
const arrayResult = await mapPromise(
|
|
331
372
|
value,
|
|
332
373
|
async (item, index): Promise<{ field: UpdateOperationListFieldItem; newRefDocuments: CSITypes.Document[] }> => {
|
|
333
|
-
const result = await
|
|
374
|
+
const result = await createUpdateOperationFieldRecursively({
|
|
334
375
|
value: item,
|
|
335
376
|
modelField: itemsField,
|
|
377
|
+
csiModelField: csiItemsField,
|
|
336
378
|
fieldPath: fieldPath.concat(index),
|
|
337
379
|
modelMap,
|
|
380
|
+
csiModelMap,
|
|
338
381
|
createDocument
|
|
339
382
|
});
|
|
340
383
|
if (result.field.type === 'list') {
|
|
@@ -353,10 +396,22 @@ async function createNestedField({
|
|
|
353
396
|
},
|
|
354
397
|
newRefDocuments: arrayResult.reduce((result: CSITypes.Document[], { newRefDocuments }) => result.concat(newRefDocuments), [])
|
|
355
398
|
};
|
|
399
|
+
} else if (
|
|
400
|
+
(csiModelField.type === 'string' || csiModelField.type === 'text') &&
|
|
401
|
+
(modelField.type === 'json' || modelField.type === 'style') &&
|
|
402
|
+
_.isPlainObject(value)
|
|
403
|
+
) {
|
|
404
|
+
return {
|
|
405
|
+
field: {
|
|
406
|
+
type: csiModelField.type,
|
|
407
|
+
value: JSON.stringify(value)
|
|
408
|
+
},
|
|
409
|
+
newRefDocuments: []
|
|
410
|
+
};
|
|
356
411
|
}
|
|
357
412
|
return {
|
|
358
413
|
field: {
|
|
359
|
-
type:
|
|
414
|
+
type: csiModelField.type,
|
|
360
415
|
value: value
|
|
361
416
|
},
|
|
362
417
|
newRefDocuments: []
|
|
@@ -367,24 +422,31 @@ export async function convertOperationField({
|
|
|
367
422
|
operationField,
|
|
368
423
|
fieldPath,
|
|
369
424
|
modelField,
|
|
425
|
+
csiModelField,
|
|
370
426
|
modelMap,
|
|
427
|
+
csiModelMap,
|
|
371
428
|
createDocument
|
|
372
429
|
}: {
|
|
373
430
|
operationField: ContentStoreTypes.UpdateOperationField;
|
|
374
431
|
fieldPath: (string | number)[];
|
|
375
|
-
modelField:
|
|
376
|
-
|
|
432
|
+
modelField: FieldSpecificProps;
|
|
433
|
+
csiModelField: FieldSpecificProps;
|
|
434
|
+
modelMap: Record<string, SDKModel>;
|
|
435
|
+
csiModelMap: Record<string, SDKModel>;
|
|
377
436
|
createDocument: CreateDocumentCallback;
|
|
378
437
|
}): Promise<CSITypes.UpdateOperationField> {
|
|
379
|
-
// for insert operations, the modelField will be of the list, so get the modelField of the list items
|
|
380
|
-
const modelFieldOrListItems: FieldSpecificProps = modelField.type === 'list' ? modelField.items! : modelField;
|
|
381
438
|
switch (operationField.type) {
|
|
382
439
|
case 'object': {
|
|
383
|
-
|
|
440
|
+
if (modelField.type !== 'object' || csiModelField.type !== 'object') {
|
|
441
|
+
throw new Error(`the operation field type 'object' does not match the model field type '${modelField.type}'`);
|
|
442
|
+
}
|
|
443
|
+
const result = await createObjectRecursively({
|
|
384
444
|
object: operationField.object,
|
|
385
|
-
modelFields:
|
|
386
|
-
|
|
445
|
+
modelFields: modelField.fields,
|
|
446
|
+
csiModelFields: csiModelField.fields,
|
|
447
|
+
fieldPath,
|
|
387
448
|
modelMap,
|
|
449
|
+
csiModelMap,
|
|
388
450
|
createDocument
|
|
389
451
|
});
|
|
390
452
|
return {
|
|
@@ -394,14 +456,17 @@ export async function convertOperationField({
|
|
|
394
456
|
}
|
|
395
457
|
case 'model': {
|
|
396
458
|
const model = modelMap[operationField.modelName];
|
|
397
|
-
|
|
459
|
+
const csiModel = csiModelMap[operationField.modelName];
|
|
460
|
+
if (!model || !csiModel) {
|
|
398
461
|
throw new Error(`error updating document, could not find document model: '${operationField.modelName}'`);
|
|
399
462
|
}
|
|
400
|
-
const result = await
|
|
463
|
+
const result = await createObjectRecursively({
|
|
401
464
|
object: operationField.object,
|
|
402
|
-
modelFields: model.fields
|
|
465
|
+
modelFields: model.fields ?? [],
|
|
466
|
+
csiModelFields: csiModel.fields ?? [],
|
|
403
467
|
fieldPath,
|
|
404
468
|
modelMap,
|
|
469
|
+
csiModelMap,
|
|
405
470
|
createDocument
|
|
406
471
|
});
|
|
407
472
|
return {
|
|
@@ -410,18 +475,22 @@ export async function convertOperationField({
|
|
|
410
475
|
fields: result.fields
|
|
411
476
|
};
|
|
412
477
|
}
|
|
478
|
+
case 'reference':
|
|
479
|
+
return operationField;
|
|
413
480
|
case 'list': {
|
|
414
|
-
if (modelField.type !== 'list') {
|
|
415
|
-
throw new Error(`
|
|
481
|
+
if (modelField.type !== 'list' || csiModelField.type !== 'list') {
|
|
482
|
+
throw new Error(`the operation field type '${operationField.type}' does not match the model field type '${modelField.type}'`);
|
|
416
483
|
}
|
|
417
484
|
const result: UpdateOperationListFieldItem[] = await mapPromise(
|
|
418
485
|
operationField.items,
|
|
419
|
-
async (item): Promise<UpdateOperationListFieldItem> => {
|
|
420
|
-
const result = await
|
|
486
|
+
async (item, index): Promise<UpdateOperationListFieldItem> => {
|
|
487
|
+
const result = await createUpdateOperationFieldRecursively({
|
|
421
488
|
value: item,
|
|
422
|
-
modelField: modelField.items
|
|
423
|
-
|
|
489
|
+
modelField: modelField.items,
|
|
490
|
+
csiModelField: csiModelField.items,
|
|
491
|
+
fieldPath: fieldPath.concat(index),
|
|
424
492
|
modelMap,
|
|
493
|
+
csiModelMap,
|
|
425
494
|
createDocument
|
|
426
495
|
});
|
|
427
496
|
if (result.field.type === 'list') {
|
|
@@ -435,34 +504,48 @@ export async function convertOperationField({
|
|
|
435
504
|
items: result
|
|
436
505
|
};
|
|
437
506
|
}
|
|
438
|
-
case 'string':
|
|
439
|
-
// When inserting new string value into a list, the client does not
|
|
440
|
-
// send value. Set an empty string value.
|
|
441
|
-
if (typeof operationField.value !== 'string') {
|
|
442
|
-
return {
|
|
443
|
-
type: operationField.type,
|
|
444
|
-
value: ''
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
return operationField as CSITypes.UpdateOperationField;
|
|
448
507
|
case 'enum':
|
|
508
|
+
if (csiModelField.type !== 'enum' && csiModelField.type !== 'string') {
|
|
509
|
+
throw new Error(`the operation field type 'enum' can be performed on 'string' and 'enum' content-source field types '${csiModelField.type}'`);
|
|
510
|
+
}
|
|
449
511
|
// When inserting new enum value into a list, the client does not
|
|
450
512
|
// send value. Set first option as the value.
|
|
451
513
|
if (typeof operationField.value !== 'string') {
|
|
452
|
-
if (
|
|
453
|
-
throw new Error(`
|
|
514
|
+
if (modelField.type !== 'enum') {
|
|
515
|
+
throw new Error(`the operation field type 'enum' does not match the model field type '${modelField.type}'`);
|
|
454
516
|
}
|
|
455
|
-
const option =
|
|
517
|
+
const option = modelField.options[0]!;
|
|
456
518
|
const optionValue = typeof option === 'object' ? option.value : option;
|
|
457
519
|
return {
|
|
458
|
-
type:
|
|
520
|
+
type: csiModelField.type,
|
|
459
521
|
value: optionValue
|
|
460
522
|
};
|
|
461
523
|
}
|
|
462
|
-
return
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
524
|
+
return {
|
|
525
|
+
type: csiModelField.type,
|
|
526
|
+
value: operationField.value
|
|
527
|
+
};
|
|
528
|
+
case 'string':
|
|
529
|
+
// When inserting new string value into a list, the client does not
|
|
530
|
+
// send value. Set an empty string value.
|
|
531
|
+
if (typeof operationField.value !== 'string') {
|
|
532
|
+
return {
|
|
533
|
+
type: operationField.type,
|
|
534
|
+
value: ''
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
return operationField;
|
|
538
|
+
default: {
|
|
539
|
+
const result = await createUpdateOperationFieldRecursively({
|
|
540
|
+
value: operationField.value,
|
|
541
|
+
modelField,
|
|
542
|
+
csiModelField,
|
|
543
|
+
fieldPath,
|
|
544
|
+
modelMap,
|
|
545
|
+
csiModelMap,
|
|
546
|
+
createDocument
|
|
547
|
+
});
|
|
548
|
+
return result.field;
|
|
549
|
+
}
|
|
467
550
|
}
|
|
468
551
|
}
|
|
@@ -166,12 +166,6 @@ function mapCSIFieldsToStoreFields({
|
|
|
166
166
|
localized: modelField.localized,
|
|
167
167
|
context
|
|
168
168
|
});
|
|
169
|
-
// Override document field types with specific model field types.
|
|
170
|
-
// For example when developer re-mapped content-source model "string"
|
|
171
|
-
// field to stackbit "color" field.
|
|
172
|
-
if (modelField.type === 'color' || modelField.type === 'style') {
|
|
173
|
-
docField.type = modelField.type;
|
|
174
|
-
}
|
|
175
169
|
docField.label = modelField.label;
|
|
176
170
|
result[modelField.name] = docField;
|
|
177
171
|
return result;
|
|
@@ -201,8 +195,34 @@ function mapCSIFieldToStoreField({
|
|
|
201
195
|
})
|
|
202
196
|
} as ContentStoreTypes.DocumentField;
|
|
203
197
|
}
|
|
204
|
-
// TODO: check if need to add "options" to "enum" and subtype/min/max to "number"
|
|
205
198
|
switch (modelField.type) {
|
|
199
|
+
case 'string':
|
|
200
|
+
case 'text':
|
|
201
|
+
case 'html':
|
|
202
|
+
case 'url':
|
|
203
|
+
case 'boolean':
|
|
204
|
+
case 'number':
|
|
205
|
+
case 'date':
|
|
206
|
+
case 'datetime':
|
|
207
|
+
case 'enum':
|
|
208
|
+
case 'json':
|
|
209
|
+
case 'style':
|
|
210
|
+
case 'color':
|
|
211
|
+
case 'slug':
|
|
212
|
+
// Override document field types with model field types.
|
|
213
|
+
// Developer can remap content-source model fields to different field using stackbit config.
|
|
214
|
+
// For example, a 'string' field in a content-source can be mapped to 'color' field in stackbit config.
|
|
215
|
+
return {
|
|
216
|
+
...csiDocumentField,
|
|
217
|
+
type: modelField.type
|
|
218
|
+
} as ContentStoreTypes.DocumentField;
|
|
219
|
+
// Don't override types of the following document fields.
|
|
220
|
+
// An 'image' model field can be a 'reference' document field in CMSes like Sanity and Contentful.
|
|
221
|
+
// Rest of the fields must have the same type across document and model fields.
|
|
222
|
+
case 'image':
|
|
223
|
+
case 'file':
|
|
224
|
+
case 'reference':
|
|
225
|
+
return csiDocumentField as ContentStoreTypes.DocumentField;
|
|
206
226
|
case 'object':
|
|
207
227
|
return mapObjectField(csiDocumentField as CSITypes.DocumentObjectField, modelField, context);
|
|
208
228
|
case 'model':
|
|
@@ -214,8 +234,10 @@ function mapCSIFieldToStoreField({
|
|
|
214
234
|
return mapRichTextField(csiDocumentField as CSITypes.DocumentRichTextField);
|
|
215
235
|
case 'markdown':
|
|
216
236
|
return mapMarkdownField(csiDocumentField as CSITypes.DocumentValueField);
|
|
217
|
-
default:
|
|
218
|
-
|
|
237
|
+
default: {
|
|
238
|
+
const _exhaustiveCheck: never = modelField;
|
|
239
|
+
return _exhaustiveCheck;
|
|
240
|
+
}
|
|
219
241
|
}
|
|
220
242
|
}
|
|
221
243
|
|
package/src/utils/model-utils.ts
CHANGED
|
@@ -60,8 +60,8 @@ export function validateModels<T extends Model>({ models, logger }: { models: T[
|
|
|
60
60
|
const { config, errors } = validateConfig({
|
|
61
61
|
stackbitVersion: '0.5.0',
|
|
62
62
|
models: models,
|
|
63
|
-
dirPath: '',
|
|
64
|
-
filePath: ''
|
|
63
|
+
dirPath: '.',
|
|
64
|
+
filePath: 'stackbit.config.js'
|
|
65
65
|
});
|
|
66
66
|
|
|
67
67
|
for (const error of errors) {
|
package/src/utils/site-map.ts
CHANGED
|
@@ -184,10 +184,18 @@ function sanitizeAndGroupSiteMapEntries(siteMapEntries: SiteMapEntry[]): SiteMap
|
|
|
184
184
|
}, {});
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
function getSiteMapGroupKey(siteMapEntry: SiteMapEntry) {
|
|
187
|
+
function getSiteMapGroupKey(siteMapEntry: SiteMapEntry): string {
|
|
188
188
|
return 'document' in siteMapEntry
|
|
189
|
-
?
|
|
190
|
-
|
|
189
|
+
? getSiteMapGroupKeyForDocument({
|
|
190
|
+
srcType: siteMapEntry.document.srcType,
|
|
191
|
+
srcProjectId: siteMapEntry.document.srcProjectId,
|
|
192
|
+
srcDocumentId: siteMapEntry.document.id
|
|
193
|
+
})
|
|
194
|
+
: SiteMapStaticEntriesKey.toString();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function getSiteMapGroupKeyForDocument({ srcType, srcProjectId, srcDocumentId }: { srcType: string; srcProjectId: string; srcDocumentId: string }): string {
|
|
198
|
+
return `${srcType}:${srcProjectId}:${srcDocumentId}`;
|
|
191
199
|
}
|
|
192
200
|
|
|
193
201
|
export function getDocumentFieldLabelValueForSiteMapEntry({
|