@stackbit/cms-contentstack 0.1.1-staging.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 +1 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/contentstack-api-client.d.ts +63 -0
- package/dist/contentstack-api-client.d.ts.map +1 -0
- package/dist/contentstack-api-client.js +295 -0
- package/dist/contentstack-api-client.js.map +1 -0
- package/dist/contentstack-content-poller.d.ts +46 -0
- package/dist/contentstack-content-poller.d.ts.map +1 -0
- package/dist/contentstack-content-poller.js +111 -0
- package/dist/contentstack-content-poller.js.map +1 -0
- package/dist/contentstack-content-source.d.ts +138 -0
- package/dist/contentstack-content-source.d.ts.map +1 -0
- package/dist/contentstack-content-source.js +544 -0
- package/dist/contentstack-content-source.js.map +1 -0
- package/dist/contentstack-conversion-utils.d.ts +41 -0
- package/dist/contentstack-conversion-utils.d.ts.map +1 -0
- package/dist/contentstack-conversion-utils.js +504 -0
- package/dist/contentstack-conversion-utils.js.map +1 -0
- package/dist/contentstack-entries-converter.d.ts +39 -0
- package/dist/contentstack-entries-converter.d.ts.map +1 -0
- package/dist/contentstack-entries-converter.js +333 -0
- package/dist/contentstack-entries-converter.js.map +1 -0
- package/dist/contentstack-operation-converter.d.ts +42 -0
- package/dist/contentstack-operation-converter.d.ts.map +1 -0
- package/dist/contentstack-operation-converter.js +535 -0
- package/dist/contentstack-operation-converter.js.map +1 -0
- package/dist/contentstack-schema-converter.d.ts +26 -0
- package/dist/contentstack-schema-converter.d.ts.map +1 -0
- package/dist/contentstack-schema-converter.js +379 -0
- package/dist/contentstack-schema-converter.js.map +1 -0
- package/dist/contentstack-types.d.ts +429 -0
- package/dist/contentstack-types.d.ts.map +1 -0
- package/dist/contentstack-types.js +3 -0
- package/dist/contentstack-types.js.map +1 -0
- package/dist/contentstack-utils.d.ts +31 -0
- package/dist/contentstack-utils.d.ts.map +1 -0
- package/dist/contentstack-utils.js +144 -0
- package/dist/contentstack-utils.js.map +1 -0
- package/dist/entries-converter.d.ts +10 -0
- package/dist/entries-converter.d.ts.map +1 -0
- package/dist/entries-converter.js +245 -0
- package/dist/entries-converter.js.map +1 -0
- package/dist/file-download.d.ts +2 -0
- package/dist/file-download.d.ts.map +1 -0
- package/dist/file-download.js +33 -0
- package/dist/file-download.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/schema-converter.d.ts +3 -0
- package/dist/schema-converter.d.ts.map +1 -0
- package/dist/schema-converter.js +169 -0
- package/dist/schema-converter.js.map +1 -0
- package/dist/transformation-utils.d.ts +41 -0
- package/dist/transformation-utils.d.ts.map +1 -0
- package/dist/transformation-utils.js +730 -0
- package/dist/transformation-utils.js.map +1 -0
- package/dist/types.d.ts +120 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +44 -0
- package/src/contentstack-api-client.ts +330 -0
- package/src/contentstack-content-poller.ts +157 -0
- package/src/contentstack-content-source.ts +687 -0
- package/src/contentstack-entries-converter.ts +438 -0
- package/src/contentstack-operation-converter.ts +703 -0
- package/src/contentstack-schema-converter.ts +486 -0
- package/src/contentstack-types.ts +527 -0
- package/src/contentstack-utils.ts +174 -0
- package/src/index.ts +3 -0
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
import _ from 'lodash';
|
|
2
|
+
import * as StackbitTypes from '@stackbit/types';
|
|
3
|
+
import type {
|
|
4
|
+
ContenteStackFieldText,
|
|
5
|
+
ContentStackField,
|
|
6
|
+
ContentStackFieldDate,
|
|
7
|
+
ContentStackFieldNumber,
|
|
8
|
+
ContentStackLocale,
|
|
9
|
+
ContentType,
|
|
10
|
+
GlobalField
|
|
11
|
+
} from './contentstack-types';
|
|
12
|
+
|
|
13
|
+
export type ModelWithContext = StackbitTypes.Model<ModelContext>;
|
|
14
|
+
export type ModelContext = {
|
|
15
|
+
clonedFromModel?: string;
|
|
16
|
+
referencedIn?: ReferencedIn;
|
|
17
|
+
blockMap?: BlockMap;
|
|
18
|
+
};
|
|
19
|
+
export type ReferencedIn = {
|
|
20
|
+
modelName: string;
|
|
21
|
+
fieldPath: string;
|
|
22
|
+
blockUID: string;
|
|
23
|
+
};
|
|
24
|
+
export type BlockMap = Record<
|
|
25
|
+
string,
|
|
26
|
+
{
|
|
27
|
+
modelNameToBlockId: Record<string, string>;
|
|
28
|
+
blockIdToModelName: Record<string, string>;
|
|
29
|
+
}
|
|
30
|
+
>;
|
|
31
|
+
|
|
32
|
+
type AddBlockMap = (options: { blockFieldPath: string; modelName: string; blockUID: string }) => void;
|
|
33
|
+
type AddBlockModel = (model: ModelWithContext) => void;
|
|
34
|
+
type CloneModelOptions = { origModelUID: string; newModelName: string; label: string; referencedIn: ReferencedIn };
|
|
35
|
+
type CloneModel = (options: CloneModelOptions) => void;
|
|
36
|
+
|
|
37
|
+
export function convertLocales({
|
|
38
|
+
contentStackLocales,
|
|
39
|
+
masterLocale,
|
|
40
|
+
logger
|
|
41
|
+
}: {
|
|
42
|
+
contentStackLocales: ContentStackLocale[];
|
|
43
|
+
masterLocale?: string;
|
|
44
|
+
logger: StackbitTypes.Logger;
|
|
45
|
+
}): StackbitTypes.Locale[] {
|
|
46
|
+
const locales: StackbitTypes.Locale[] = contentStackLocales.map((locale) => ({ code: locale.code }));
|
|
47
|
+
|
|
48
|
+
if (masterLocale) {
|
|
49
|
+
const defaultLocale = locales.find((locale) => locale.code === masterLocale);
|
|
50
|
+
if (defaultLocale) {
|
|
51
|
+
defaultLocale.default = true;
|
|
52
|
+
} else {
|
|
53
|
+
throw new Error(
|
|
54
|
+
`The 'masterLocale' '${masterLocale}' provided to ContentStackSource constructor ` +
|
|
55
|
+
`does not match any locale code: [${locales.map((locale) => locale.code).join(', ')}]`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
} else if (locales.length === 1) {
|
|
59
|
+
logger.info(`The Contentstack stack has a single '${locales[0]!.code}' locale, using it as master locale`);
|
|
60
|
+
locales[0]!.default = true;
|
|
61
|
+
} else {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Stack has multiple locales: [${locales.map((locale) => locale.code).join(', ')}], ` +
|
|
64
|
+
`please specify which one should be used as the master locale using the 'masterLocale' property ` +
|
|
65
|
+
`in the ContentStackSource constructor options`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return locales;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function convertModels({ contentStackModels }: { contentStackModels: (ContentType | GlobalField)[] }): ModelWithContext[] {
|
|
73
|
+
const modelsToClone: CloneModelOptions[] = [];
|
|
74
|
+
const models = contentStackModels.reduce((stackbitModels: ModelWithContext[], contentStackModel) => {
|
|
75
|
+
const blockModels: ModelWithContext[] = [];
|
|
76
|
+
const stackbitModel = convertModel({
|
|
77
|
+
contentStackModel: contentStackModel,
|
|
78
|
+
addBlockModel: (model: ModelWithContext) => {
|
|
79
|
+
blockModels.push(model);
|
|
80
|
+
},
|
|
81
|
+
cloneModel: (options) => {
|
|
82
|
+
modelsToClone.push(options);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
return stackbitModels.concat(stackbitModel, blockModels);
|
|
86
|
+
}, []);
|
|
87
|
+
const modelMap = _.keyBy(models, 'name');
|
|
88
|
+
const clonedModels = modelsToClone.map((options): ModelWithContext => {
|
|
89
|
+
const model = modelMap[options.origModelUID];
|
|
90
|
+
if (!model) {
|
|
91
|
+
throw new Error(`could not clone model, model ${options.origModelUID} not found`);
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
...model,
|
|
95
|
+
name: options.newModelName,
|
|
96
|
+
label: options.label,
|
|
97
|
+
context: _.omitBy(
|
|
98
|
+
{
|
|
99
|
+
clonedFromModel: options.origModelUID,
|
|
100
|
+
referencedIn: options.referencedIn
|
|
101
|
+
},
|
|
102
|
+
_.isNil
|
|
103
|
+
)
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
const linkModel: ModelWithContext = {
|
|
107
|
+
type: 'object',
|
|
108
|
+
name: 'CNTSTK_LINK_MODEL',
|
|
109
|
+
label: 'Link',
|
|
110
|
+
fields: [
|
|
111
|
+
{ type: 'string', name: 'title', label: 'Title', default: '' },
|
|
112
|
+
{ type: 'string', name: 'href', label: 'URL', default: '' }
|
|
113
|
+
]
|
|
114
|
+
};
|
|
115
|
+
return [...models, ...clonedModels, linkModel];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function convertModel({
|
|
119
|
+
contentStackModel,
|
|
120
|
+
addBlockModel,
|
|
121
|
+
cloneModel,
|
|
122
|
+
referencedIn
|
|
123
|
+
}: {
|
|
124
|
+
contentStackModel: ContentType | GlobalField;
|
|
125
|
+
addBlockModel: AddBlockModel;
|
|
126
|
+
cloneModel: CloneModel;
|
|
127
|
+
referencedIn?: ReferencedIn;
|
|
128
|
+
}): ModelWithContext {
|
|
129
|
+
const blockMap: BlockMap = {};
|
|
130
|
+
const isContentType = 'options' in contentStackModel;
|
|
131
|
+
return {
|
|
132
|
+
type: isContentType ? (contentStackModel.options?.is_page ? 'page' : 'data') : 'object',
|
|
133
|
+
name: contentStackModel.uid,
|
|
134
|
+
label: contentStackModel.title,
|
|
135
|
+
...(_.isEmpty(contentStackModel.description) ? null : { description: contentStackModel.description }),
|
|
136
|
+
...(isContentType ? { labelField: 'title' } : null),
|
|
137
|
+
...(isContentType && contentStackModel.options?.singleton ? { singleInstance: true } : null),
|
|
138
|
+
fields: convertFields({
|
|
139
|
+
contentStackFields: contentStackModel.schema,
|
|
140
|
+
parentModelName: contentStackModel.uid,
|
|
141
|
+
isNested: !!referencedIn,
|
|
142
|
+
fieldPath: [],
|
|
143
|
+
addBlockMap: ({ blockFieldPath, modelName, blockUID }) => {
|
|
144
|
+
if (!blockMap[blockFieldPath]) {
|
|
145
|
+
blockMap[blockFieldPath] = {
|
|
146
|
+
modelNameToBlockId: {},
|
|
147
|
+
blockIdToModelName: {}
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
blockMap[blockFieldPath]!.modelNameToBlockId[modelName] = blockUID;
|
|
151
|
+
blockMap[blockFieldPath]!.blockIdToModelName[blockUID] = modelName;
|
|
152
|
+
},
|
|
153
|
+
addBlockModel,
|
|
154
|
+
cloneModel
|
|
155
|
+
}),
|
|
156
|
+
context: _.omitBy(
|
|
157
|
+
{
|
|
158
|
+
...(_.isEmpty(blockMap) ? null : { blockMap }),
|
|
159
|
+
referencedIn
|
|
160
|
+
},
|
|
161
|
+
_.isNil
|
|
162
|
+
)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function convertFields(options: {
|
|
167
|
+
contentStackFields: ContentStackField[];
|
|
168
|
+
parentModelName: string;
|
|
169
|
+
isNested: boolean;
|
|
170
|
+
fieldPath: string[];
|
|
171
|
+
addBlockMap: AddBlockMap;
|
|
172
|
+
addBlockModel: AddBlockModel;
|
|
173
|
+
cloneModel: CloneModel;
|
|
174
|
+
}): StackbitTypes.Field[] {
|
|
175
|
+
const { contentStackFields, fieldPath, ...rest } = options;
|
|
176
|
+
return contentStackFields.map((field) =>
|
|
177
|
+
convertField({
|
|
178
|
+
field,
|
|
179
|
+
fieldPath: fieldPath.concat(field.uid),
|
|
180
|
+
...rest
|
|
181
|
+
})
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function convertField({
|
|
186
|
+
field,
|
|
187
|
+
parentModelName,
|
|
188
|
+
isNested,
|
|
189
|
+
fieldPath,
|
|
190
|
+
addBlockMap,
|
|
191
|
+
addBlockModel,
|
|
192
|
+
cloneModel
|
|
193
|
+
}: {
|
|
194
|
+
field: ContentStackField;
|
|
195
|
+
parentModelName: string;
|
|
196
|
+
isNested: boolean;
|
|
197
|
+
fieldPath: string[];
|
|
198
|
+
addBlockMap: AddBlockMap;
|
|
199
|
+
addBlockModel: AddBlockModel;
|
|
200
|
+
cloneModel: CloneModel;
|
|
201
|
+
}): StackbitTypes.Field {
|
|
202
|
+
switch (field.data_type) {
|
|
203
|
+
case 'text': {
|
|
204
|
+
if (field.field_metadata?.multiline) {
|
|
205
|
+
return toFieldOrListField(field, {
|
|
206
|
+
type: 'text'
|
|
207
|
+
});
|
|
208
|
+
} else if (field.field_metadata?.markdown) {
|
|
209
|
+
return toFieldOrListField(field, {
|
|
210
|
+
type: 'markdown'
|
|
211
|
+
});
|
|
212
|
+
} else if (field.field_metadata?.allow_rich_text) {
|
|
213
|
+
return toFieldOrListField(field, {
|
|
214
|
+
// Stackbit doesn't support HTML editor
|
|
215
|
+
// type: 'html'
|
|
216
|
+
type: 'text'
|
|
217
|
+
});
|
|
218
|
+
} else if (field.enum) {
|
|
219
|
+
return toEnumField(field as StackbitTypes.RequiredBy<ContenteStackFieldText, 'enum'>);
|
|
220
|
+
} else if (field.uid === 'slug' || (field.uid === 'url' && field.field_metadata?._default === true)) {
|
|
221
|
+
return toFieldOrListField(field, {
|
|
222
|
+
type: 'slug'
|
|
223
|
+
});
|
|
224
|
+
} else {
|
|
225
|
+
return toFieldOrListField(field, {
|
|
226
|
+
type: 'string'
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
case 'boolean':
|
|
232
|
+
return toFieldOrListField(field, {
|
|
233
|
+
type: 'boolean'
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
case 'json':
|
|
237
|
+
if (field.field_metadata?.allow_json_rte) {
|
|
238
|
+
return toFieldOrListField(field, {
|
|
239
|
+
type: 'richText'
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
return toFieldOrListField(field, {
|
|
243
|
+
type: 'json'
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
case 'file':
|
|
247
|
+
return toFieldOrListField(field, {
|
|
248
|
+
type: field.field_metadata?.image ? 'image' : 'file'
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
case 'isodate': {
|
|
252
|
+
const fieldType = field.field_metadata?.hide_time ? 'date' : 'datetime';
|
|
253
|
+
return toFieldOrListField(
|
|
254
|
+
field,
|
|
255
|
+
{
|
|
256
|
+
type: fieldType
|
|
257
|
+
},
|
|
258
|
+
(defaultValue: ContentStackFieldDate['field_metadata']['default_value']) => {
|
|
259
|
+
if (defaultValue?.custom && defaultValue?.date) {
|
|
260
|
+
if (fieldType === 'datetime' && defaultValue?.time) {
|
|
261
|
+
return new Date(`${defaultValue?.date}T${defaultValue?.time}`).toISOString();
|
|
262
|
+
} else {
|
|
263
|
+
return defaultValue?.date;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
}
|
|
270
|
+
case 'number': {
|
|
271
|
+
if (field.enum) {
|
|
272
|
+
return toEnumField(field as StackbitTypes.RequiredBy<ContentStackFieldNumber, 'enum'>);
|
|
273
|
+
}
|
|
274
|
+
const min = !_.isNil(field.min) ? { min: field.min } : null;
|
|
275
|
+
const max = !_.isNil(field.max) ? { max: field.max } : null;
|
|
276
|
+
return toFieldOrListField(field, {
|
|
277
|
+
type: 'number',
|
|
278
|
+
...min,
|
|
279
|
+
...max
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
case 'link': {
|
|
284
|
+
return toFieldOrListField(
|
|
285
|
+
field,
|
|
286
|
+
{
|
|
287
|
+
type: 'model',
|
|
288
|
+
models: ['CNTSTK_LINK_MODEL']
|
|
289
|
+
},
|
|
290
|
+
(value: any): any => {
|
|
291
|
+
// rewrite url property to href
|
|
292
|
+
if (!value) {
|
|
293
|
+
return value;
|
|
294
|
+
}
|
|
295
|
+
const { url, ...rest } = value;
|
|
296
|
+
return {
|
|
297
|
+
...rest,
|
|
298
|
+
href: url
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
case 'group': {
|
|
305
|
+
return toFieldOrListField(field, {
|
|
306
|
+
type: 'object',
|
|
307
|
+
fields: convertFields({
|
|
308
|
+
contentStackFields: field.schema,
|
|
309
|
+
parentModelName: parentModelName,
|
|
310
|
+
isNested,
|
|
311
|
+
fieldPath,
|
|
312
|
+
addBlockMap,
|
|
313
|
+
addBlockModel,
|
|
314
|
+
cloneModel
|
|
315
|
+
})
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
case 'global_field': {
|
|
320
|
+
// ContentStack global fields can only reference one model
|
|
321
|
+
return toFieldOrListField(field, {
|
|
322
|
+
type: 'model',
|
|
323
|
+
models: field.reference_to ? [field.reference_to] : []
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
case 'reference': {
|
|
328
|
+
// in reference fields, the "field_metadata.ref_multiple" is responsible for marking the field as list, not "multiple".
|
|
329
|
+
return toFieldOrListField(field, {
|
|
330
|
+
type: 'reference',
|
|
331
|
+
models: field.reference_to || []
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
case 'blocks': {
|
|
336
|
+
const commonProps = getStackbitFieldPropsFromContentStackField(field, true);
|
|
337
|
+
// blocks, are always lists
|
|
338
|
+
const referencedModelCountMap: Record<string, number> = {};
|
|
339
|
+
return {
|
|
340
|
+
type: 'list',
|
|
341
|
+
...commonProps,
|
|
342
|
+
items: {
|
|
343
|
+
type: 'model',
|
|
344
|
+
models: field.blocks.map((block) => {
|
|
345
|
+
const modelName = `${isNested ? '' : 'BLOCK_'}${parentModelName}__${fieldPath.length ? fieldPath.join('.') + '__' : ''}${block.uid}`;
|
|
346
|
+
if ('schema' in block) {
|
|
347
|
+
const contentStackModel = {
|
|
348
|
+
uid: modelName,
|
|
349
|
+
title: block.title,
|
|
350
|
+
schema: block.schema
|
|
351
|
+
} as GlobalField;
|
|
352
|
+
const blockModel = convertModel({
|
|
353
|
+
contentStackModel,
|
|
354
|
+
addBlockModel,
|
|
355
|
+
cloneModel,
|
|
356
|
+
referencedIn: {
|
|
357
|
+
modelName: parentModelName,
|
|
358
|
+
fieldPath: fieldPath.join('.'),
|
|
359
|
+
blockUID: block.uid
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
addBlockModel(blockModel);
|
|
363
|
+
addBlockMap({ blockFieldPath: fieldPath.join('.'), modelName, blockUID: block.uid });
|
|
364
|
+
return modelName;
|
|
365
|
+
} else if ('reference_to' in block) {
|
|
366
|
+
// Blocks can reference the same global field in different blocks (with different uid)
|
|
367
|
+
// If the referenced global field (object model) is defined only in one block,
|
|
368
|
+
// then don't create a new model and reuse the referenced model. Add a map entry between
|
|
369
|
+
// the block's uid and the model's name, so when a new object is added to this field,
|
|
370
|
+
// we will know to which block uid to assign.
|
|
371
|
+
if (typeof referencedModelCountMap[block.reference_to] === 'undefined') {
|
|
372
|
+
referencedModelCountMap[block.reference_to] = 1;
|
|
373
|
+
} else {
|
|
374
|
+
referencedModelCountMap[block.reference_to] += 1;
|
|
375
|
+
}
|
|
376
|
+
if (referencedModelCountMap[block.reference_to] === 1) {
|
|
377
|
+
addBlockMap({ blockFieldPath: fieldPath.join('.'), modelName: block.reference_to, blockUID: block.uid });
|
|
378
|
+
return block.reference_to;
|
|
379
|
+
} else {
|
|
380
|
+
// If the referenced global field is used more than once, then create a new model
|
|
381
|
+
// by cloning the original model and ad a mao entry between the block's uid and the
|
|
382
|
+
// cloned model name.
|
|
383
|
+
cloneModel({
|
|
384
|
+
origModelUID: block.reference_to,
|
|
385
|
+
newModelName: modelName,
|
|
386
|
+
label: block.title,
|
|
387
|
+
referencedIn: {
|
|
388
|
+
modelName: parentModelName,
|
|
389
|
+
fieldPath: fieldPath.join('.'),
|
|
390
|
+
blockUID: block.uid
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
addBlockMap({ blockFieldPath: fieldPath.join('.'), modelName, blockUID: block.uid });
|
|
394
|
+
return modelName;
|
|
395
|
+
}
|
|
396
|
+
} else {
|
|
397
|
+
throw new Error(`block doesn't have 'schema' nor 'reference_to'`);
|
|
398
|
+
}
|
|
399
|
+
})
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
default: {
|
|
404
|
+
const _exhaustiveCheck: never = field;
|
|
405
|
+
return _exhaustiveCheck;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function toEnumField(
|
|
411
|
+
field: StackbitTypes.RequiredBy<ContenteStackFieldText, 'enum'> | StackbitTypes.RequiredBy<ContentStackFieldNumber, 'enum'>
|
|
412
|
+
): StackbitTypes.Field {
|
|
413
|
+
const isList = field.multiple;
|
|
414
|
+
const commonProps = getStackbitFieldPropsFromContentStackField(field, isList);
|
|
415
|
+
const options: StackbitTypes.FieldEnumOptionValue[] | StackbitTypes.FieldEnumOptionObject[] = field.enum.advanced
|
|
416
|
+
? field.enum.choices.map((choice) => ({ label: choice.key, value: choice.value }))
|
|
417
|
+
: field.enum.choices.map((choice) => choice.value);
|
|
418
|
+
if (isList) {
|
|
419
|
+
return {
|
|
420
|
+
type: 'list',
|
|
421
|
+
...commonProps,
|
|
422
|
+
...(field.display_type === 'checkbox' ? { controlType: 'checkbox' } : null),
|
|
423
|
+
items: {
|
|
424
|
+
type: 'enum',
|
|
425
|
+
options
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
} else {
|
|
429
|
+
return {
|
|
430
|
+
type: 'enum',
|
|
431
|
+
...commonProps,
|
|
432
|
+
controlType: field.display_type === 'radio' ? 'button-group' : 'dropdown',
|
|
433
|
+
options: options
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function toFieldOrListField(
|
|
439
|
+
field: ContentStackField,
|
|
440
|
+
fieldSpecificProps: Exclude<StackbitTypes.FieldSpecificProps, StackbitTypes.FieldStyleProps | StackbitTypes.FieldListProps>,
|
|
441
|
+
resolveDefault?: (value: unknown) => unknown
|
|
442
|
+
): Exclude<StackbitTypes.Field, StackbitTypes.FieldStyle> {
|
|
443
|
+
// In reference fields, the "field_metadata.ref_multiple" is responsible for marking the field as list, not "multiple".
|
|
444
|
+
const isList = field.data_type === 'reference' ? field.field_metadata?.ref_multiple : field.multiple;
|
|
445
|
+
// In lists resolve defaults to a list with a single value
|
|
446
|
+
const commonProps = getStackbitFieldPropsFromContentStackField(field, isList, resolveDefault);
|
|
447
|
+
if (isList) {
|
|
448
|
+
return {
|
|
449
|
+
type: 'list',
|
|
450
|
+
...commonProps,
|
|
451
|
+
items: fieldSpecificProps
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
return {
|
|
455
|
+
...fieldSpecificProps,
|
|
456
|
+
...commonProps
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function getStackbitFieldPropsFromContentStackField(
|
|
461
|
+
field: ContentStackField,
|
|
462
|
+
isList: boolean,
|
|
463
|
+
resolveDefault?: (value: unknown) => unknown
|
|
464
|
+
): {
|
|
465
|
+
name: string;
|
|
466
|
+
label?: string;
|
|
467
|
+
description?: string;
|
|
468
|
+
required?: boolean;
|
|
469
|
+
default?: any;
|
|
470
|
+
} {
|
|
471
|
+
const description = field.field_metadata?.description;
|
|
472
|
+
const defaultValue = field.field_metadata?.default_value;
|
|
473
|
+
const resolvedDefault = defaultValue === null || defaultValue === '' ? undefined : resolveDefault ? resolveDefault(defaultValue) : defaultValue;
|
|
474
|
+
return {
|
|
475
|
+
name: field.uid,
|
|
476
|
+
label: field.display_name,
|
|
477
|
+
..._.omitBy(
|
|
478
|
+
{
|
|
479
|
+
description: description || undefined,
|
|
480
|
+
required: field.mandatory || undefined,
|
|
481
|
+
default: !_.isNil(resolvedDefault) && isList ? [resolvedDefault] : resolvedDefault
|
|
482
|
+
},
|
|
483
|
+
_.isNil
|
|
484
|
+
)
|
|
485
|
+
};
|
|
486
|
+
}
|