@stackbit/cms-core 0.4.5-develop.1 → 0.4.6-develop.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.d.ts +2 -2
- package/dist/content-store.d.ts.map +1 -1
- package/dist/content-store.js +30 -18
- package/dist/content-store.js.map +1 -1
- package/dist/types/content-store-document-fields.d.ts +3 -3
- package/dist/types/content-store-document-fields.d.ts.map +1 -1
- package/dist/utils/asset-sources-utils.d.ts +12 -0
- package/dist/utils/asset-sources-utils.d.ts.map +1 -0
- package/dist/utils/asset-sources-utils.js +101 -0
- package/dist/utils/asset-sources-utils.js.map +1 -0
- package/dist/utils/create-update-csi-docs.d.ts +4 -2
- package/dist/utils/create-update-csi-docs.d.ts.map +1 -1
- package/dist/utils/create-update-csi-docs.js +62 -11
- package/dist/utils/create-update-csi-docs.js.map +1 -1
- package/dist/utils/csi-to-store-docs-converter.d.ts +2 -1
- package/dist/utils/csi-to-store-docs-converter.d.ts.map +1 -1
- package/dist/utils/csi-to-store-docs-converter.js +95 -4
- package/dist/utils/csi-to-store-docs-converter.js.map +1 -1
- package/dist/utils/duplicate-document.js +5 -7
- package/dist/utils/duplicate-document.js.map +1 -1
- package/dist/utils/store-to-csi-docs-converter.d.ts.map +1 -1
- package/dist/utils/store-to-csi-docs-converter.js +9 -8
- package/dist/utils/store-to-csi-docs-converter.js.map +1 -1
- package/package.json +5 -5
- package/src/content-store.ts +26 -16
- package/src/types/content-store-document-fields.ts +10 -5
- package/src/utils/asset-sources-utils.ts +106 -0
- package/src/utils/create-update-csi-docs.ts +79 -13
- package/src/utils/csi-to-store-docs-converter.ts +102 -2
- package/src/utils/duplicate-document.ts +5 -7
- package/src/utils/store-to-csi-docs-converter.ts +9 -8
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Config } from '@stackbit/sdk';
|
|
2
|
+
import { AssetSource, DistributiveOmit, FieldImageProps } from '@stackbit/types';
|
|
3
|
+
import * as ContentStoreTypes from '../types';
|
|
4
|
+
|
|
5
|
+
export function getAssetSourcesForClient(stackbitConfig: Config | null): DistributiveOmit<AssetSource, 'transform' | 'preview'>[] {
|
|
6
|
+
if (!stackbitConfig) {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
const assetSources = stackbitConfig.assetSources ?? [];
|
|
10
|
+
return assetSources.reduce((accum: DistributiveOmit<AssetSource, 'transform' | 'preview'>[], assetSource: AssetSource) => {
|
|
11
|
+
if (assetSource.type === 'iframe') {
|
|
12
|
+
if (!assetSource.name || !assetSource.url) {
|
|
13
|
+
return accum;
|
|
14
|
+
}
|
|
15
|
+
const { transform, preview, ...rest } = assetSource;
|
|
16
|
+
return accum.concat(rest);
|
|
17
|
+
} else {
|
|
18
|
+
const buildInAssetSources = ['cloudinary'];
|
|
19
|
+
const name = assetSource.name ?? (buildInAssetSources.includes(assetSource.type) ? assetSource.type : null);
|
|
20
|
+
if (!name) {
|
|
21
|
+
return accum;
|
|
22
|
+
}
|
|
23
|
+
const { transform, preview, ...rest } = assetSource;
|
|
24
|
+
return accum.concat({
|
|
25
|
+
...rest,
|
|
26
|
+
name: name
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return accum;
|
|
30
|
+
}, []);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function transformAssetSourceDataForAssetSource(sourceData: any, assetSource: AssetSource): any {
|
|
34
|
+
if (typeof assetSource.transform === 'function') {
|
|
35
|
+
return assetSource.transform({ assetData: sourceData });
|
|
36
|
+
} else {
|
|
37
|
+
return sourceData;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getImageFieldsFromSourceData({
|
|
42
|
+
sourceData,
|
|
43
|
+
imageModelField,
|
|
44
|
+
assetSources
|
|
45
|
+
}: {
|
|
46
|
+
sourceData: any;
|
|
47
|
+
imageModelField: FieldImageProps;
|
|
48
|
+
assetSources: AssetSource[];
|
|
49
|
+
}): ContentStoreTypes.ImageFields {
|
|
50
|
+
const imageAssetSource = getAssetSourceBySourceName(assetSources, imageModelField.source);
|
|
51
|
+
|
|
52
|
+
if (imageAssetSource?.preview) {
|
|
53
|
+
const preview = typeof imageAssetSource.preview === 'function' ? imageAssetSource.preview({ assetData: sourceData }) : imageAssetSource.preview;
|
|
54
|
+
return {
|
|
55
|
+
title: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
value: preview?.title ?? ''
|
|
58
|
+
},
|
|
59
|
+
url: {
|
|
60
|
+
type: 'string',
|
|
61
|
+
value: preview.image ?? ''
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (imageAssetSource?.type === 'cloudinary') {
|
|
67
|
+
return {
|
|
68
|
+
title: {
|
|
69
|
+
type: 'string',
|
|
70
|
+
value: sourceData?.public_id
|
|
71
|
+
},
|
|
72
|
+
url: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
value: sourceData?.derived?.[0]?.secure_url ?? sourceData?.secure_url
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
title: {
|
|
81
|
+
type: 'string',
|
|
82
|
+
value: ''
|
|
83
|
+
},
|
|
84
|
+
url: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
value: typeof sourceData === 'string' ? sourceData : ''
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getAssetSourceBySourceName(assetSources: AssetSource[], assetSourceName: string | undefined): AssetSource | undefined {
|
|
92
|
+
if (!assetSourceName) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
const assetSource = assetSources.find((assetSources) => assetSources.name === assetSourceName);
|
|
96
|
+
if (!assetSource) {
|
|
97
|
+
// for build-in asset sources, use the name of the source (field[type=image].source) as its type
|
|
98
|
+
if (assetSourceName === 'cloudinary') {
|
|
99
|
+
return {
|
|
100
|
+
type: assetSourceName,
|
|
101
|
+
name: assetSourceName
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return assetSource;
|
|
106
|
+
}
|
|
@@ -2,12 +2,20 @@ import _ from 'lodash';
|
|
|
2
2
|
import slugify from 'slugify';
|
|
3
3
|
|
|
4
4
|
import { Model as SDKModel } from '@stackbit/sdk';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
Model as CSIModel,
|
|
7
|
+
Field,
|
|
8
|
+
FieldSpecificProps,
|
|
9
|
+
UpdateOperationListFieldItem,
|
|
10
|
+
isOneOfFieldTypes,
|
|
11
|
+
isModelFieldSpecificPropsOneOfFieldTypes
|
|
12
|
+
} from '@stackbit/types';
|
|
6
13
|
import { fieldPathToString, mapPromise } from '@stackbit/utils';
|
|
7
14
|
import * as CSITypes from '@stackbit/types';
|
|
8
15
|
|
|
9
16
|
import * as ContentStoreTypes from '../types';
|
|
10
17
|
import { getContentSourceId, getUserContextForSrcType, updateOperationValueFieldWithCrossReference } from '../content-store-utils';
|
|
18
|
+
import { getAssetSourceBySourceName, transformAssetSourceDataForAssetSource } from './asset-sources-utils';
|
|
11
19
|
|
|
12
20
|
export type CreateDocumentCallback = ({
|
|
13
21
|
updateOperationFields,
|
|
@@ -92,12 +100,14 @@ export async function createDocumentRecursively({
|
|
|
92
100
|
modelName,
|
|
93
101
|
contentSourceId,
|
|
94
102
|
contentSourceDataById,
|
|
103
|
+
assetSources,
|
|
95
104
|
createDocument
|
|
96
105
|
}: {
|
|
97
106
|
object?: Record<string, any>;
|
|
98
107
|
modelName: string;
|
|
99
108
|
contentSourceId: string;
|
|
100
109
|
contentSourceDataById: Record<string, ContentStoreTypes.ContentSourceData>;
|
|
110
|
+
assetSources: CSITypes.AssetSource[];
|
|
101
111
|
createDocument: CreateDocumentCallback;
|
|
102
112
|
}): Promise<{ documentId: string; newRefDocumentIds: string[] }> {
|
|
103
113
|
const contentSourceData = contentSourceDataById[contentSourceId];
|
|
@@ -120,15 +130,21 @@ export async function createDocumentRecursively({
|
|
|
120
130
|
if (object && slugField && (slugField in object || '_stackbit_slug' in object)) {
|
|
121
131
|
const slugFieldValue = object[slugField] || object['_stackbit_slug'];
|
|
122
132
|
object[slugField] = sanitizeSlug(slugFieldValue);
|
|
123
|
-
if (!modelFields.find(field => field.name === slugField)) {
|
|
124
|
-
modelFields = [
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
133
|
+
if (!modelFields.find((field) => field.name === slugField)) {
|
|
134
|
+
modelFields = [
|
|
135
|
+
...modelFields,
|
|
136
|
+
{
|
|
137
|
+
type: 'slug',
|
|
138
|
+
name: slugField
|
|
139
|
+
}
|
|
140
|
+
];
|
|
141
|
+
csiModelFields = [
|
|
142
|
+
...csiModelFields,
|
|
143
|
+
{
|
|
144
|
+
type: 'slug',
|
|
145
|
+
name: slugField
|
|
146
|
+
}
|
|
147
|
+
];
|
|
132
148
|
}
|
|
133
149
|
}
|
|
134
150
|
}
|
|
@@ -142,6 +158,7 @@ export async function createDocumentRecursively({
|
|
|
142
158
|
csiModelMap,
|
|
143
159
|
contentSourceId,
|
|
144
160
|
contentSourceDataById,
|
|
161
|
+
assetSources,
|
|
145
162
|
createDocument
|
|
146
163
|
});
|
|
147
164
|
|
|
@@ -161,7 +178,8 @@ function extractTokensFromString(input: string): string[] {
|
|
|
161
178
|
}
|
|
162
179
|
|
|
163
180
|
function sanitizeSlug(slug?: string) {
|
|
164
|
-
return slug
|
|
181
|
+
return slug
|
|
182
|
+
?.split('/')
|
|
165
183
|
.map((part) => slugify(part, { lower: true }))
|
|
166
184
|
.join('/');
|
|
167
185
|
}
|
|
@@ -175,6 +193,7 @@ async function createObjectRecursively({
|
|
|
175
193
|
csiModelMap,
|
|
176
194
|
contentSourceId,
|
|
177
195
|
contentSourceDataById,
|
|
196
|
+
assetSources,
|
|
178
197
|
createDocument
|
|
179
198
|
}: {
|
|
180
199
|
object?: Record<string, any>;
|
|
@@ -185,6 +204,7 @@ async function createObjectRecursively({
|
|
|
185
204
|
csiModelMap: Record<string, CSIModel>;
|
|
186
205
|
contentSourceId: string;
|
|
187
206
|
contentSourceDataById: Record<string, ContentStoreTypes.ContentSourceData>;
|
|
207
|
+
assetSources: CSITypes.AssetSource[];
|
|
188
208
|
createDocument: CreateDocumentCallback;
|
|
189
209
|
}): Promise<{
|
|
190
210
|
fields: Record<string, CSITypes.UpdateOperationField>;
|
|
@@ -233,6 +253,7 @@ async function createObjectRecursively({
|
|
|
233
253
|
csiModelMap,
|
|
234
254
|
contentSourceId,
|
|
235
255
|
contentSourceDataById,
|
|
256
|
+
assetSources,
|
|
236
257
|
createDocument
|
|
237
258
|
});
|
|
238
259
|
result.fields[fieldName] = fieldResult.field;
|
|
@@ -256,6 +277,7 @@ async function createUpdateOperationFieldRecursively({
|
|
|
256
277
|
csiModelMap,
|
|
257
278
|
contentSourceId,
|
|
258
279
|
contentSourceDataById,
|
|
280
|
+
assetSources,
|
|
259
281
|
createDocument
|
|
260
282
|
}: {
|
|
261
283
|
value: any;
|
|
@@ -266,6 +288,7 @@ async function createUpdateOperationFieldRecursively({
|
|
|
266
288
|
csiModelMap: Record<string, CSIModel>;
|
|
267
289
|
contentSourceId: string;
|
|
268
290
|
contentSourceDataById: Record<string, ContentStoreTypes.ContentSourceData>;
|
|
291
|
+
assetSources: CSITypes.AssetSource[];
|
|
269
292
|
createDocument: CreateDocumentCallback;
|
|
270
293
|
}): Promise<{ field: CSITypes.UpdateOperationField; newRefDocumentIds: string[] }> {
|
|
271
294
|
if (csiModelField.type === 'object') {
|
|
@@ -281,6 +304,7 @@ async function createUpdateOperationFieldRecursively({
|
|
|
281
304
|
csiModelMap,
|
|
282
305
|
contentSourceId,
|
|
283
306
|
contentSourceDataById,
|
|
307
|
+
assetSources,
|
|
284
308
|
createDocument
|
|
285
309
|
});
|
|
286
310
|
return {
|
|
@@ -320,6 +344,7 @@ async function createUpdateOperationFieldRecursively({
|
|
|
320
344
|
csiModelMap,
|
|
321
345
|
contentSourceId,
|
|
322
346
|
contentSourceDataById,
|
|
347
|
+
assetSources,
|
|
323
348
|
createDocument
|
|
324
349
|
});
|
|
325
350
|
return {
|
|
@@ -332,15 +357,33 @@ async function createUpdateOperationFieldRecursively({
|
|
|
332
357
|
};
|
|
333
358
|
} else if (csiModelField.type === 'image') {
|
|
334
359
|
let refId: string | undefined;
|
|
335
|
-
|
|
360
|
+
const assetSource = getAssetSourceBySourceName(assetSources, csiModelField.source);
|
|
361
|
+
if (assetSource) {
|
|
362
|
+
// omit $$type for backwards compatibility with legacy presets
|
|
363
|
+
const sourceData = _.omit(value, ['$$type']);
|
|
336
364
|
return {
|
|
337
365
|
field: {
|
|
338
366
|
type: 'image',
|
|
339
|
-
value:
|
|
367
|
+
value: transformAssetSourceDataForAssetSource(sourceData, assetSource)
|
|
340
368
|
},
|
|
341
369
|
newRefDocumentIds: []
|
|
342
370
|
};
|
|
343
371
|
}
|
|
372
|
+
// - when setting images in git, the UpdateOperationField is:
|
|
373
|
+
// { type: 'image', value: 'stackbit_asset_id:static:images/elephants.jpg' }
|
|
374
|
+
// so the 'value' will be a string 'stackbit_asset_id:static:images/elephants.jpg'
|
|
375
|
+
// - when setting images in Contentful, the UpdateOperationField is:
|
|
376
|
+
// { type: 'image', value: '6rEF3N6lFlEscOq8U63gYg' }
|
|
377
|
+
// so the 'value' will be a string representing the Asset ID - '6rEF3N6lFlEscOq8U63gYg'
|
|
378
|
+
// - when creating images from presets or default values the asset ID can
|
|
379
|
+
// can be specified as $$ref or as plain value
|
|
380
|
+
// - when duplicating documents with images, the duplicated image field will be:
|
|
381
|
+
// { $$ref: '...' }
|
|
382
|
+
// TODO: A bug!
|
|
383
|
+
// - when the image is specified as an absolute URL - https://... or //...
|
|
384
|
+
// the absolute URL value will will be set as 'refId', with field
|
|
385
|
+
// type: 'reference'. There is currently no way to solve it because we
|
|
386
|
+
// use 'image' type both for referenced images and for literal images.
|
|
344
387
|
if (_.isPlainObject(value)) {
|
|
345
388
|
refId = value.$$ref ?? value.url;
|
|
346
389
|
} else {
|
|
@@ -391,6 +434,7 @@ async function createUpdateOperationFieldRecursively({
|
|
|
391
434
|
modelName,
|
|
392
435
|
contentSourceId,
|
|
393
436
|
contentSourceDataById,
|
|
437
|
+
assetSources,
|
|
394
438
|
createDocument
|
|
395
439
|
});
|
|
396
440
|
return {
|
|
@@ -431,6 +475,7 @@ async function createUpdateOperationFieldRecursively({
|
|
|
431
475
|
modelName,
|
|
432
476
|
contentSourceId: getContentSourceId(refSrcType, refProjectId),
|
|
433
477
|
contentSourceDataById,
|
|
478
|
+
assetSources,
|
|
434
479
|
createDocument
|
|
435
480
|
});
|
|
436
481
|
_newRefDocumentIds.push(documentId, ...newRefDocumentIds);
|
|
@@ -462,6 +507,7 @@ async function createUpdateOperationFieldRecursively({
|
|
|
462
507
|
csiModelMap,
|
|
463
508
|
contentSourceId,
|
|
464
509
|
contentSourceDataById,
|
|
510
|
+
assetSources,
|
|
465
511
|
createDocument
|
|
466
512
|
});
|
|
467
513
|
if (result.field.type === 'list') {
|
|
@@ -491,6 +537,20 @@ async function createUpdateOperationFieldRecursively({
|
|
|
491
537
|
},
|
|
492
538
|
newRefDocumentIds: []
|
|
493
539
|
};
|
|
540
|
+
} else if (isModelFieldSpecificPropsOneOfFieldTypes(csiModelField, ['string', 'text', 'json']) && modelField.type === 'image') {
|
|
541
|
+
if (modelField.source) {
|
|
542
|
+
const assetSource = getAssetSourceBySourceName(assetSources, modelField.source);
|
|
543
|
+
if (assetSource) {
|
|
544
|
+
value = transformAssetSourceDataForAssetSource(value, assetSource);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return {
|
|
548
|
+
field: {
|
|
549
|
+
type: csiModelField.type,
|
|
550
|
+
value: csiModelField.type !== 'json' && _.isPlainObject(value) ? JSON.stringify(value) : value
|
|
551
|
+
},
|
|
552
|
+
newRefDocumentIds: []
|
|
553
|
+
};
|
|
494
554
|
}
|
|
495
555
|
return {
|
|
496
556
|
field: {
|
|
@@ -510,6 +570,7 @@ export async function convertOperationField({
|
|
|
510
570
|
csiModelMap,
|
|
511
571
|
contentSourceId,
|
|
512
572
|
contentSourceDataById,
|
|
573
|
+
assetSources,
|
|
513
574
|
createDocument
|
|
514
575
|
}: {
|
|
515
576
|
operationField: ContentStoreTypes.UpdateOperationField;
|
|
@@ -520,6 +581,7 @@ export async function convertOperationField({
|
|
|
520
581
|
csiModelMap: Record<string, SDKModel>;
|
|
521
582
|
contentSourceId: string;
|
|
522
583
|
contentSourceDataById: Record<string, ContentStoreTypes.ContentSourceData>;
|
|
584
|
+
assetSources: CSITypes.AssetSource[];
|
|
523
585
|
createDocument: CreateDocumentCallback;
|
|
524
586
|
}): Promise<CSITypes.UpdateOperationField> {
|
|
525
587
|
switch (operationField.type) {
|
|
@@ -536,6 +598,7 @@ export async function convertOperationField({
|
|
|
536
598
|
csiModelMap,
|
|
537
599
|
contentSourceId,
|
|
538
600
|
contentSourceDataById,
|
|
601
|
+
assetSources,
|
|
539
602
|
createDocument
|
|
540
603
|
});
|
|
541
604
|
return {
|
|
@@ -558,6 +621,7 @@ export async function convertOperationField({
|
|
|
558
621
|
csiModelMap,
|
|
559
622
|
contentSourceId,
|
|
560
623
|
contentSourceDataById,
|
|
624
|
+
assetSources,
|
|
561
625
|
createDocument
|
|
562
626
|
});
|
|
563
627
|
return {
|
|
@@ -600,6 +664,7 @@ export async function convertOperationField({
|
|
|
600
664
|
csiModelMap,
|
|
601
665
|
contentSourceId,
|
|
602
666
|
contentSourceDataById,
|
|
667
|
+
assetSources,
|
|
603
668
|
createDocument
|
|
604
669
|
});
|
|
605
670
|
if (result.field.type === 'list') {
|
|
@@ -656,6 +721,7 @@ export async function convertOperationField({
|
|
|
656
721
|
csiModelMap,
|
|
657
722
|
contentSourceId,
|
|
658
723
|
contentSourceDataById,
|
|
724
|
+
assetSources,
|
|
659
725
|
createDocument
|
|
660
726
|
});
|
|
661
727
|
return result.field;
|
|
@@ -16,6 +16,7 @@ import * as CSITypes from '@stackbit/types';
|
|
|
16
16
|
import * as ContentStoreTypes from '../types';
|
|
17
17
|
import { IMAGE_MODEL } from '../common/common-schema';
|
|
18
18
|
import { BackCompatContentSourceInterface } from './backward-compatibility';
|
|
19
|
+
import { getImageFieldsFromSourceData } from './asset-sources-utils';
|
|
19
20
|
|
|
20
21
|
export function mapCSIAssetsToStoreAssets({
|
|
21
22
|
csiAssets,
|
|
@@ -98,12 +99,14 @@ export function mapCSIDocumentsToStoreDocuments({
|
|
|
98
99
|
contentSourceInstance,
|
|
99
100
|
modelMap,
|
|
100
101
|
defaultLocaleCode,
|
|
102
|
+
assetSources,
|
|
101
103
|
createConfigDelegate
|
|
102
104
|
}: {
|
|
103
105
|
csiDocuments: CSITypes.Document[];
|
|
104
106
|
contentSourceInstance: BackCompatContentSourceInterface;
|
|
105
107
|
modelMap: Record<string, Model>;
|
|
106
108
|
defaultLocaleCode?: string;
|
|
109
|
+
assetSources: CSITypes.AssetSource[];
|
|
107
110
|
createConfigDelegate: () => CSITypes.ConfigDelegate;
|
|
108
111
|
}): ContentStoreTypes.Document[] {
|
|
109
112
|
const meta = getMetadataFromContentStore({ contentSourceInstance });
|
|
@@ -114,6 +117,7 @@ export function mapCSIDocumentsToStoreDocuments({
|
|
|
114
117
|
modelMap,
|
|
115
118
|
defaultLocaleCode,
|
|
116
119
|
meta,
|
|
120
|
+
assetSources,
|
|
117
121
|
createConfigDelegate
|
|
118
122
|
})
|
|
119
123
|
);
|
|
@@ -125,6 +129,7 @@ function mapCSIDocumentToStoreDocument({
|
|
|
125
129
|
modelMap,
|
|
126
130
|
defaultLocaleCode,
|
|
127
131
|
meta,
|
|
132
|
+
assetSources,
|
|
128
133
|
createConfigDelegate
|
|
129
134
|
}: {
|
|
130
135
|
csiDocument: CSITypes.Document;
|
|
@@ -132,6 +137,7 @@ function mapCSIDocumentToStoreDocument({
|
|
|
132
137
|
modelMap: Record<string, Model>;
|
|
133
138
|
defaultLocaleCode?: string;
|
|
134
139
|
meta: { srcType: string; srcProjectId: string; srcProjectUrl: string; srcEnvironment: string };
|
|
140
|
+
assetSources: CSITypes.AssetSource[];
|
|
135
141
|
createConfigDelegate: () => CSITypes.ConfigDelegate;
|
|
136
142
|
}): ContentStoreTypes.Document {
|
|
137
143
|
return omitByNil({
|
|
@@ -166,6 +172,7 @@ function mapCSIDocumentToStoreDocument({
|
|
|
166
172
|
parentDocument: csiDocument,
|
|
167
173
|
modelMap,
|
|
168
174
|
defaultLocaleCode,
|
|
175
|
+
assetSources,
|
|
169
176
|
createConfigDelegate
|
|
170
177
|
}
|
|
171
178
|
})
|
|
@@ -178,6 +185,7 @@ type MapContext = {
|
|
|
178
185
|
parentDocument: CSITypes.Document;
|
|
179
186
|
modelMap: Record<string, Model>;
|
|
180
187
|
defaultLocaleCode?: string;
|
|
188
|
+
assetSources: CSITypes.AssetSource[];
|
|
181
189
|
createConfigDelegate: () => CSITypes.ConfigDelegate;
|
|
182
190
|
};
|
|
183
191
|
|
|
@@ -237,6 +245,7 @@ function mapCSIFieldToStoreField({
|
|
|
237
245
|
case 'date':
|
|
238
246
|
case 'datetime':
|
|
239
247
|
case 'enum':
|
|
248
|
+
// TODO: 'json' and 'style' fields can be remapped from 'string' and 'text', in this case parse the JSON object
|
|
240
249
|
case 'json':
|
|
241
250
|
case 'style':
|
|
242
251
|
case 'color':
|
|
@@ -248,10 +257,14 @@ function mapCSIFieldToStoreField({
|
|
|
248
257
|
...csiDocumentField,
|
|
249
258
|
type: modelField.type
|
|
250
259
|
} as ContentStoreTypes.DocumentField;
|
|
260
|
+
case 'image':
|
|
261
|
+
// The 'image' model field can be a 'reference' document field in CMSes like Sanity and Contentful.
|
|
262
|
+
if (csiDocumentField.type === 'reference') {
|
|
263
|
+
return csiDocumentField;
|
|
264
|
+
}
|
|
265
|
+
return mapImageField(csiDocumentField, modelField, context.assetSources);
|
|
251
266
|
// Don't override types of the following document fields.
|
|
252
|
-
// An 'image' model field can be a 'reference' document field in CMSes like Sanity and Contentful.
|
|
253
267
|
// Rest of the fields must have the same type across document and model fields.
|
|
254
|
-
case 'image':
|
|
255
268
|
case 'file':
|
|
256
269
|
case 'reference':
|
|
257
270
|
return csiDocumentField as ContentStoreTypes.DocumentField;
|
|
@@ -275,6 +288,93 @@ function mapCSIFieldToStoreField({
|
|
|
275
288
|
}
|
|
276
289
|
}
|
|
277
290
|
|
|
291
|
+
function mapImageField(
|
|
292
|
+
csiDocumentField: CSITypes.DocumentField,
|
|
293
|
+
imageModelField: CSITypes.FieldImageProps,
|
|
294
|
+
assetSources: CSITypes.AssetSource[]
|
|
295
|
+
): ContentStoreTypes.DocumentImageField {
|
|
296
|
+
// the image can be remapped from 'string', 'text' or 'json' fields
|
|
297
|
+
if (isDocumentFieldOneOfFieldTypes(csiDocumentField, ['string', 'text', 'json'])) {
|
|
298
|
+
try {
|
|
299
|
+
if (!isLocalizedField(csiDocumentField)) {
|
|
300
|
+
if (imageModelField.source) {
|
|
301
|
+
return omitByNil({
|
|
302
|
+
type: 'image',
|
|
303
|
+
source: imageModelField.source,
|
|
304
|
+
sourceData: csiDocumentField.value,
|
|
305
|
+
fields: getImageFieldsFromSourceData({
|
|
306
|
+
sourceData: csiDocumentField.value,
|
|
307
|
+
imageModelField: imageModelField,
|
|
308
|
+
assetSources
|
|
309
|
+
})
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
} else {
|
|
313
|
+
return omitByNil({
|
|
314
|
+
type: 'image',
|
|
315
|
+
source: imageModelField.source,
|
|
316
|
+
localized: true,
|
|
317
|
+
locales: _.mapValues(csiDocumentField.locales, (locale) => {
|
|
318
|
+
return {
|
|
319
|
+
locale: locale.locale,
|
|
320
|
+
sourceData: locale.value,
|
|
321
|
+
fields: getImageFieldsFromSourceData({
|
|
322
|
+
sourceData: locale.value,
|
|
323
|
+
imageModelField: imageModelField,
|
|
324
|
+
assetSources
|
|
325
|
+
})
|
|
326
|
+
};
|
|
327
|
+
})
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
} catch (e) {
|
|
331
|
+
return {
|
|
332
|
+
type: 'image',
|
|
333
|
+
...(isLocalizedField(csiDocumentField) ? { localized: true, locales: {} } : { isUnset: true })
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
if (csiDocumentField.type !== 'image') {
|
|
338
|
+
return {
|
|
339
|
+
type: 'image',
|
|
340
|
+
...(isLocalizedField(csiDocumentField) ? { localized: true, locales: {} } : { isUnset: true })
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
if (!isLocalizedField(csiDocumentField)) {
|
|
344
|
+
return omitByNil({
|
|
345
|
+
type: 'image',
|
|
346
|
+
source: csiDocumentField.source,
|
|
347
|
+
sourceData: csiDocumentField.sourceData,
|
|
348
|
+
fields:
|
|
349
|
+
csiDocumentField.fields ??
|
|
350
|
+
getImageFieldsFromSourceData({
|
|
351
|
+
sourceData: csiDocumentField.sourceData,
|
|
352
|
+
imageModelField: imageModelField,
|
|
353
|
+
assetSources
|
|
354
|
+
})
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
return omitByNil({
|
|
358
|
+
type: 'image',
|
|
359
|
+
source: csiDocumentField.source,
|
|
360
|
+
localized: true,
|
|
361
|
+
locales: _.mapValues(csiDocumentField.locales, (locale) => {
|
|
362
|
+
return {
|
|
363
|
+
locale: locale.locale,
|
|
364
|
+
sourceData: locale.sourceData,
|
|
365
|
+
fields:
|
|
366
|
+
// for backward compatibility use, fields if provided
|
|
367
|
+
locale.fields ??
|
|
368
|
+
getImageFieldsFromSourceData({
|
|
369
|
+
sourceData: locale.sourceData,
|
|
370
|
+
imageModelField: imageModelField,
|
|
371
|
+
assetSources
|
|
372
|
+
})
|
|
373
|
+
};
|
|
374
|
+
})
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
278
378
|
function mapCrossReferenceField(csiDocumentField: CSITypes.DocumentField): ContentStoreTypes.DocumentCrossReferenceField {
|
|
279
379
|
const unlocalizedUnset = {
|
|
280
380
|
type: 'cross-reference',
|
|
@@ -114,20 +114,18 @@ function mergeObjectWithDocumentField({
|
|
|
114
114
|
break;
|
|
115
115
|
}
|
|
116
116
|
case 'image': {
|
|
117
|
+
// if an image value was provided explicitly, use it to override the image
|
|
118
|
+
// of the matching field in the duplicated document.
|
|
117
119
|
if (typeof value !== 'undefined') {
|
|
118
120
|
return value;
|
|
119
121
|
}
|
|
120
122
|
const localizedField = getDocumentFieldForLocale(documentField, locale);
|
|
121
|
-
if (localizedField && !localizedField.isUnset
|
|
123
|
+
if (localizedField && !localizedField.isUnset) {
|
|
122
124
|
if (localizedField?.sourceData) {
|
|
123
125
|
return localizedField?.sourceData;
|
|
124
126
|
}
|
|
125
|
-
|
|
126
|
-
return
|
|
127
|
-
object: value,
|
|
128
|
-
documentFields: localizedField.fields,
|
|
129
|
-
...context
|
|
130
|
-
});
|
|
127
|
+
const localizedUrl = getDocumentFieldForLocale(localizedField.fields.url, locale);
|
|
128
|
+
return localizedUrl?.value;
|
|
131
129
|
}
|
|
132
130
|
break;
|
|
133
131
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import * as CSITypes from '@stackbit/types';
|
|
3
|
+
import { omitByNil } from '@stackbit/utils';
|
|
3
4
|
import * as ContentStoreTypes from '../types';
|
|
4
5
|
|
|
5
6
|
export function mapStoreDocumentsToCSIDocumentsWithSource(documents: ContentStoreTypes.Document[]): CSITypes.DocumentWithSource[] {
|
|
@@ -92,26 +93,26 @@ function mapStoreFieldToCSIField(documentField: ContentStoreTypes.DocumentField)
|
|
|
92
93
|
if (_.isEmpty(documentField.locales)) {
|
|
93
94
|
return;
|
|
94
95
|
}
|
|
95
|
-
return {
|
|
96
|
+
return omitByNil({
|
|
96
97
|
type: 'image',
|
|
97
98
|
localized: true,
|
|
98
99
|
source: documentField.source,
|
|
99
|
-
|
|
100
|
-
locales: _.mapValues(documentField.locales, (locale) => ({
|
|
100
|
+
locales: _.mapValues(documentField.locales, (locale) => omitByNil({
|
|
101
101
|
locale: locale.locale,
|
|
102
|
-
|
|
102
|
+
sourceData: locale.sourceData,
|
|
103
|
+
...(locale.sourceData ? null : { fields: mapStoreFieldsToCSIFields(locale.fields) })
|
|
103
104
|
}))
|
|
104
|
-
} as CSITypes.DocumentImageFieldLocalized;
|
|
105
|
+
}) as CSITypes.DocumentImageFieldLocalized;
|
|
105
106
|
}
|
|
106
107
|
if (documentField.isUnset) {
|
|
107
108
|
return;
|
|
108
109
|
}
|
|
109
|
-
return {
|
|
110
|
+
return omitByNil({
|
|
110
111
|
type: 'image',
|
|
111
112
|
source: documentField.source,
|
|
112
113
|
sourceData: documentField.sourceData,
|
|
113
|
-
fields: mapStoreFieldsToCSIFields(documentField.fields)
|
|
114
|
-
} as CSITypes.DocumentImageFieldNonLocalized;
|
|
114
|
+
...(documentField.sourceData ? null : { fields: mapStoreFieldsToCSIFields(documentField.fields) })
|
|
115
|
+
}) as CSITypes.DocumentImageFieldNonLocalized;
|
|
115
116
|
}
|
|
116
117
|
case 'object': {
|
|
117
118
|
if (documentField.localized) {
|