@stackbit/cms-core 0.0.3
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/annotator/html.d.ts +1 -0
- package/dist/annotator/html.js +54 -0
- package/dist/annotator/html.js.map +1 -0
- package/dist/annotator/index.d.ts +13 -0
- package/dist/annotator/index.js +120 -0
- package/dist/annotator/index.js.map +1 -0
- package/dist/annotator/react.d.ts +1 -0
- package/dist/annotator/react.js +53 -0
- package/dist/annotator/react.js.map +1 -0
- package/dist/consts.d.ts +27 -0
- package/dist/consts.js +43 -0
- package/dist/consts.js.map +1 -0
- package/dist/encoder.d.ts +8 -0
- package/dist/encoder.js +272 -0
- package/dist/encoder.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/stackbit/index.d.ts +4 -0
- package/dist/stackbit/index.js +54 -0
- package/dist/stackbit/index.js.map +1 -0
- package/dist/utils/index.d.ts +172 -0
- package/dist/utils/index.js +928 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +43 -0
- package/src/annotator/html.js +55 -0
- package/src/annotator/index.js +135 -0
- package/src/annotator/react.js +56 -0
- package/src/consts.js +41 -0
- package/src/encoder.js +315 -0
- package/src/index.js +13 -0
- package/src/stackbit/index.js +55 -0
- package/src/utils/index.js +997 -0
package/src/encoder.js
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const consts = require('./consts');
|
|
3
|
+
const { mergeAtPath, omitByNil } = require('./utils');
|
|
4
|
+
|
|
5
|
+
function mapObjectFields({ data, model, fieldDataPath, fieldDataPathsInverted, fieldModelPath, encodeValue, delegate }) {
|
|
6
|
+
if (!fieldModelPath) {
|
|
7
|
+
fieldModelPath = [model.name];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const isRoot = fieldDataPath.length === 1;
|
|
11
|
+
const metadata = delegate.getItemMetadata(data, model, isRoot);
|
|
12
|
+
const fields = delegate.getItemFields(data, model);
|
|
13
|
+
|
|
14
|
+
return _.reduce(
|
|
15
|
+
fields,
|
|
16
|
+
(accum, field) => {
|
|
17
|
+
const fieldModel = _.find(model.fields, { name: field.name });
|
|
18
|
+
|
|
19
|
+
// if field model wasn't found ignore this field
|
|
20
|
+
if (!fieldModel) {
|
|
21
|
+
return accum;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// don't include const fields
|
|
25
|
+
if (_.has(fieldModel, 'const')) {
|
|
26
|
+
return accum;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let childFieldModelPath;
|
|
30
|
+
if (_.get(model, 'isList') && field.name === 'items') {
|
|
31
|
+
childFieldModelPath = fieldModelPath;
|
|
32
|
+
} else {
|
|
33
|
+
childFieldModelPath = _.concat(fieldModelPath, field.name);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const fieldPath = ['fields', field.name];
|
|
37
|
+
|
|
38
|
+
const mapLocalizedField = (accum, localizedField) => {
|
|
39
|
+
const localePath = fieldModel.localized ? ['locales', localizedField.locale] : [];
|
|
40
|
+
const fullFieldDataPath = _.concat(fieldPath, localePath);
|
|
41
|
+
|
|
42
|
+
const mappedData = mapField({
|
|
43
|
+
fieldValue: localizedField.value,
|
|
44
|
+
fieldModel: fieldModel,
|
|
45
|
+
fieldDataPath: _.concat(fieldDataPath, fullFieldDataPath),
|
|
46
|
+
fieldDataPaths: accum.fieldDataPaths,
|
|
47
|
+
fieldDataPathsInverted: fieldDataPathsInverted,
|
|
48
|
+
fieldModelPath: childFieldModelPath,
|
|
49
|
+
delegate: delegate
|
|
50
|
+
});
|
|
51
|
+
if (localizedField.locale && localizedField.locale !== '_unset') {
|
|
52
|
+
mappedData.fieldData.locale = localizedField.locale;
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
fieldData: mergeAtPath(accum.fieldData, fullFieldDataPath, omitByNil(mappedData.fieldData))
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// always create 'fields' as object, even for objects that have field names as numbers
|
|
60
|
+
_.setWith(accum.fieldData, fieldPath, fieldModelToFieldData(fieldModel), Object);
|
|
61
|
+
|
|
62
|
+
if (fieldModel.localized) {
|
|
63
|
+
accum = mapLocalizedField(accum, { locale: '_unset' });
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (_.has(field, 'locales')) {
|
|
67
|
+
return _.reduce(
|
|
68
|
+
field.locales,
|
|
69
|
+
(accum, localizedField) => {
|
|
70
|
+
return mapLocalizedField(accum, localizedField);
|
|
71
|
+
},
|
|
72
|
+
accum
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return mapLocalizedField(accum, field);
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
fieldData: metadata
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function mapField({ fieldValue, fieldModel, fieldDataPath, fieldModelPath, delegate }) {
|
|
85
|
+
if (_.includes(consts.SIMPLE_VALUE_FIELDS, fieldModel.type)) {
|
|
86
|
+
return {
|
|
87
|
+
fieldData: { value: fieldValue }
|
|
88
|
+
};
|
|
89
|
+
} else if (['enum', 'style'].includes(fieldModel.type)) {
|
|
90
|
+
return {
|
|
91
|
+
fieldData: { value: fieldValue }
|
|
92
|
+
};
|
|
93
|
+
} else if (fieldModel.type === 'list') {
|
|
94
|
+
const itemsModel = _.get(fieldModel, 'items');
|
|
95
|
+
let getListItemModel;
|
|
96
|
+
if (_.isArray(itemsModel)) {
|
|
97
|
+
// in Sanity, list items may have multiple types, in this case, 'items' will be an array
|
|
98
|
+
getListItemModel = (listItem, fieldModel) => delegate.getItemTypeForListItem(listItem, fieldModel);
|
|
99
|
+
} else {
|
|
100
|
+
// get the type of list items, if type is not defined, set string as it is the default
|
|
101
|
+
const listItemsType = _.get(itemsModel, 'type', 'string');
|
|
102
|
+
getListItemModel = _.constant(_.defaults({}, itemsModel, { type: listItemsType }));
|
|
103
|
+
}
|
|
104
|
+
return _.reduce(
|
|
105
|
+
fieldValue,
|
|
106
|
+
(accum, listItem, listIdx) => {
|
|
107
|
+
const itemModel = getListItemModel(listItem, fieldModel);
|
|
108
|
+
let mappedData;
|
|
109
|
+
if (!itemModel) {
|
|
110
|
+
mappedData = unresolvedModel();
|
|
111
|
+
accum.fieldData.items = _.concat(accum.fieldData.items, mappedData.fieldData);
|
|
112
|
+
} else {
|
|
113
|
+
mappedData = mapField({
|
|
114
|
+
fieldValue: listItem,
|
|
115
|
+
fieldModel: itemModel,
|
|
116
|
+
fieldDataPath: _.concat(fieldDataPath, ['items', listIdx]),
|
|
117
|
+
fieldModelPath: fieldModelPath,
|
|
118
|
+
delegate
|
|
119
|
+
});
|
|
120
|
+
accum.fieldData.items = _.concat(accum.fieldData.items, fieldModelToFieldData(itemModel, mappedData.fieldData));
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
fieldData: accum.fieldData
|
|
124
|
+
};
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
fieldData: { items: [] }
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
} else if (fieldModel.type === 'object') {
|
|
131
|
+
// inline object
|
|
132
|
+
if (!fieldValue) {
|
|
133
|
+
return unsetObject();
|
|
134
|
+
}
|
|
135
|
+
return mapObjectFields({
|
|
136
|
+
data: fieldValue,
|
|
137
|
+
model: fieldModel,
|
|
138
|
+
fieldDataPath,
|
|
139
|
+
fieldModelPath,
|
|
140
|
+
delegate
|
|
141
|
+
});
|
|
142
|
+
} else if (fieldModel.type === 'reference') {
|
|
143
|
+
if (!fieldValue) {
|
|
144
|
+
return unsetObject();
|
|
145
|
+
}
|
|
146
|
+
const isLink = delegate.isLinkItem(fieldValue);
|
|
147
|
+
if (isLink) {
|
|
148
|
+
return unresolvedReference(fieldValue, delegate);
|
|
149
|
+
}
|
|
150
|
+
const model = delegate.getModelForItemOfReferenceType(fieldValue);
|
|
151
|
+
if (!model) {
|
|
152
|
+
return unresolvedModel();
|
|
153
|
+
}
|
|
154
|
+
return mapObjectFields({
|
|
155
|
+
data: fieldValue,
|
|
156
|
+
model,
|
|
157
|
+
fieldDataPath,
|
|
158
|
+
delegate
|
|
159
|
+
});
|
|
160
|
+
} else if (fieldModel.type === 'model') {
|
|
161
|
+
if (!fieldValue) {
|
|
162
|
+
return unsetObject();
|
|
163
|
+
}
|
|
164
|
+
const fieldModels = _.get(fieldModel, 'models', []);
|
|
165
|
+
const modelsByName = delegate.getModelsByName();
|
|
166
|
+
const model = fieldModels.length === 1 ? _.get(modelsByName, fieldModels[0]) : delegate.getModelForItemOfModelsType(fieldValue);
|
|
167
|
+
if (!model) {
|
|
168
|
+
return unresolvedModel();
|
|
169
|
+
}
|
|
170
|
+
return mapObjectFields({
|
|
171
|
+
data: fieldValue,
|
|
172
|
+
model,
|
|
173
|
+
fieldDataPath,
|
|
174
|
+
delegate
|
|
175
|
+
});
|
|
176
|
+
} else {
|
|
177
|
+
// for everything else, delegate encoding to the delegate
|
|
178
|
+
const fieldData = {};
|
|
179
|
+
const encodedField = delegate.encodeField(fieldValue, fieldModel, fieldDataPath);
|
|
180
|
+
if (encodedField) {
|
|
181
|
+
if (_.has(encodedField, 'fieldData')) {
|
|
182
|
+
_.assign(fieldData, encodedField.fieldData);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
fieldData: omitByNil(fieldData)
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function fieldModelToFieldData(fieldModel, overrides) {
|
|
192
|
+
const type = ['reference', 'model'].includes(fieldModel.type) ? 'object' : fieldModel.type;
|
|
193
|
+
return omitByNil(
|
|
194
|
+
_.assign(
|
|
195
|
+
{
|
|
196
|
+
type: type,
|
|
197
|
+
label: fieldModel.label,
|
|
198
|
+
description: fieldModel.description,
|
|
199
|
+
// fieldType: fieldModel.type,
|
|
200
|
+
// fieldLabel: fieldModel.label,
|
|
201
|
+
|
|
202
|
+
// "localized" field will be excluded from final fieldData by decoder
|
|
203
|
+
localized: fieldModel.localized,
|
|
204
|
+
|
|
205
|
+
// "models" field will be excluded from final fieldData by decoder
|
|
206
|
+
models: getFieldModelNames(fieldModel)
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
fieldModel.type === 'markdown'
|
|
210
|
+
? {
|
|
211
|
+
multiElement: true
|
|
212
|
+
}
|
|
213
|
+
: null,
|
|
214
|
+
|
|
215
|
+
fieldModel.type === 'enum'
|
|
216
|
+
? {
|
|
217
|
+
options: _.get(fieldModel, 'options', []),
|
|
218
|
+
source: _.get(fieldModel, 'source')
|
|
219
|
+
}
|
|
220
|
+
: null,
|
|
221
|
+
|
|
222
|
+
overrides
|
|
223
|
+
)
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function getFieldModelNames(fieldModel) {
|
|
228
|
+
const fieldType = fieldModel.type;
|
|
229
|
+
if (fieldType === 'reference' || fieldType === 'model') {
|
|
230
|
+
return _.clone(_.get(fieldModel, 'models', []));
|
|
231
|
+
} else if (fieldModel.type === 'list') {
|
|
232
|
+
const itemsModel = _.get(fieldModel, 'items');
|
|
233
|
+
// in Sanity, array can have items of multiple types
|
|
234
|
+
if (_.isArray(itemsModel)) {
|
|
235
|
+
return Array.from(
|
|
236
|
+
_.reduce(
|
|
237
|
+
itemsModel,
|
|
238
|
+
(accum, itemModel) => {
|
|
239
|
+
return new Set([...accum, ...(getFieldModelNames(itemModel) || [])]);
|
|
240
|
+
},
|
|
241
|
+
new Set()
|
|
242
|
+
)
|
|
243
|
+
);
|
|
244
|
+
} else {
|
|
245
|
+
return getFieldModelNames(itemsModel);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function unsetObject() {
|
|
252
|
+
return {
|
|
253
|
+
fieldData: {
|
|
254
|
+
isUnset: true
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function unresolvedReference(fieldValue, delegate) {
|
|
260
|
+
return {
|
|
261
|
+
fieldData: {
|
|
262
|
+
type: 'unresolved_reference',
|
|
263
|
+
refId: delegate.getReferenceId(fieldValue),
|
|
264
|
+
refType: 'object'
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function unresolvedModel() {
|
|
270
|
+
return {
|
|
271
|
+
fieldData: {
|
|
272
|
+
type: 'unresolved_model'
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function mapData(data, prevEncodingResult, delegate) {
|
|
278
|
+
// scan model instances and replace their 'data' with an identity-mapped data
|
|
279
|
+
return _.reduce(
|
|
280
|
+
data,
|
|
281
|
+
(accum, item) => {
|
|
282
|
+
const model = delegate.getModelForRootItem(item);
|
|
283
|
+
if (!model) {
|
|
284
|
+
return {
|
|
285
|
+
fieldData: accum.fieldData
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
const itemId = delegate.getItemId(item);
|
|
289
|
+
// todo: pass the accumulated hashedData to all children, because we need to remove duplicate fieldPaths from it per strategy when a field has changed (because we might get partial field data)
|
|
290
|
+
// todo: create inverse map to find duplications
|
|
291
|
+
const mappedData = mapObjectFields({
|
|
292
|
+
data: item,
|
|
293
|
+
model: model,
|
|
294
|
+
fieldDataPath: [itemId],
|
|
295
|
+
delegate: delegate
|
|
296
|
+
});
|
|
297
|
+
return {
|
|
298
|
+
fieldData: _.assign(accum.fieldData, { [itemId]: mappedData.fieldData })
|
|
299
|
+
};
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
fieldData: _.get(prevEncodingResult, 'fieldData', {})
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function encodeData({ data, prevEncodingResult, delegate }) {
|
|
308
|
+
data = _.cloneDeep(data);
|
|
309
|
+
const mappedData = mapData(data, prevEncodingResult, delegate);
|
|
310
|
+
return {
|
|
311
|
+
fieldData: mappedData.fieldData
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
module.exports = encodeData;
|
package/src/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const encodeData = require('./encoder');
|
|
2
|
+
const stackbit = require('./stackbit');
|
|
3
|
+
const annotator = require('./annotator');
|
|
4
|
+
const utils = require('./utils');
|
|
5
|
+
const consts = require('./consts');
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
utils,
|
|
9
|
+
consts,
|
|
10
|
+
annotator,
|
|
11
|
+
encodeData,
|
|
12
|
+
stackbit
|
|
13
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const { loadConfig, isListDataModel } = require('@stackbit/sdk');
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
fetchAndConvertSchema
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
function fetchAndConvertSchema(options) {
|
|
9
|
+
return loadConfig({ dirPath: options.dirPath }).then(({ config, errors }) => {
|
|
10
|
+
if (!config) {
|
|
11
|
+
return { schema: {}, errors };
|
|
12
|
+
}
|
|
13
|
+
wrapListDataModels(config);
|
|
14
|
+
const schema = _.pick(config, [
|
|
15
|
+
'stackbitVersion',
|
|
16
|
+
'ssgName',
|
|
17
|
+
'ssgVersion',
|
|
18
|
+
'nodeVersion',
|
|
19
|
+
'devCommand',
|
|
20
|
+
'cmsName',
|
|
21
|
+
'import',
|
|
22
|
+
'publishDir',
|
|
23
|
+
'staticDir',
|
|
24
|
+
'uploadDir',
|
|
25
|
+
'assets',
|
|
26
|
+
'dataDir',
|
|
27
|
+
'pagesDir',
|
|
28
|
+
'pageLayoutKey',
|
|
29
|
+
'objectTypeKey',
|
|
30
|
+
'excludePages',
|
|
31
|
+
'logicFields',
|
|
32
|
+
'contentModels',
|
|
33
|
+
'modelsSource',
|
|
34
|
+
'models',
|
|
35
|
+
'presets'
|
|
36
|
+
]);
|
|
37
|
+
return { schema, errors };
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function wrapListDataModels(config) {
|
|
42
|
+
_.forEach(config.models, (model) => {
|
|
43
|
+
if (!isListDataModel(model)) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
_.set(model, 'fields', [
|
|
47
|
+
{
|
|
48
|
+
type: 'list',
|
|
49
|
+
name: 'items',
|
|
50
|
+
items: model.items
|
|
51
|
+
}
|
|
52
|
+
]);
|
|
53
|
+
_.unset(model, 'items');
|
|
54
|
+
});
|
|
55
|
+
}
|