@stackbit/sdk 0.2.19 → 0.2.23
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/config/config-consts.d.ts +1 -1
- package/dist/config/config-consts.js +2 -0
- package/dist/config/config-consts.js.map +1 -1
- package/dist/config/config-loader.d.ts +3 -2
- package/dist/config/config-loader.js +256 -72
- package/dist/config/config-loader.js.map +1 -1
- package/dist/config/config-schema.js +28 -7
- package/dist/config/config-schema.js.map +1 -1
- package/dist/config/config-types.d.ts +22 -5
- package/dist/config/config-writer.js +3 -0
- package/dist/config/config-writer.js.map +1 -1
- package/dist/config/presets-loader.js +18 -11
- package/dist/config/presets-loader.js.map +1 -1
- package/dist/content/content-loader.js +1 -1
- package/dist/content/content-schema.js +8 -0
- package/dist/content/content-schema.js.map +1 -1
- package/dist/utils/model-extender.js +3 -2
- package/dist/utils/model-extender.js.map +1 -1
- package/dist/utils/model-iterators.d.ts +61 -1
- package/dist/utils/model-iterators.js +60 -11
- package/dist/utils/model-iterators.js.map +1 -1
- package/dist/utils/model-utils.d.ts +44 -3
- package/dist/utils/model-utils.js +93 -10
- package/dist/utils/model-utils.js.map +1 -1
- package/package.json +2 -2
- package/src/.DS_Store +0 -0
- package/src/config/config-consts.ts +2 -0
- package/src/config/config-loader.ts +281 -83
- package/src/config/config-schema.ts +35 -8
- package/src/config/config-types.ts +26 -5
- package/src/config/config-writer.ts +3 -0
- package/src/config/presets-loader.ts +19 -15
- package/src/content/content-loader.ts +2 -2
- package/src/content/content-schema.ts +9 -0
- package/src/utils/model-extender.ts +4 -3
- package/src/utils/model-iterators.ts +61 -13
- package/src/utils/model-utils.ts +91 -8
|
@@ -3,7 +3,7 @@ import { CMS_NAMES, FIELD_TYPES, SSG_NAMES, STYLE_PROPS } from './config-consts'
|
|
|
3
3
|
|
|
4
4
|
export interface Config extends BaseConfig {
|
|
5
5
|
models: Model[];
|
|
6
|
-
presets?: any
|
|
6
|
+
presets?: Record<string, any>;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
export interface YamlConfig extends BaseConfig {
|
|
@@ -85,16 +85,29 @@ export interface ContentModel extends BaseMatch {
|
|
|
85
85
|
newFilePath?: string;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
export
|
|
88
|
+
export type ModelsSource = ModelsSourceFiles | ModelsSourceContentful | ModelsSourceSanity;
|
|
89
|
+
|
|
90
|
+
export interface ModelsSourceFiles {
|
|
89
91
|
type: 'files';
|
|
90
92
|
modelDirs: string[];
|
|
91
93
|
}
|
|
92
94
|
|
|
95
|
+
export interface ModelsSourceContentful {
|
|
96
|
+
type: 'contentful';
|
|
97
|
+
module?: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface ModelsSourceSanity {
|
|
101
|
+
type: 'sanity';
|
|
102
|
+
sanityStudioPath: string;
|
|
103
|
+
module?: string;
|
|
104
|
+
}
|
|
105
|
+
|
|
93
106
|
/*******************
|
|
94
107
|
*** Model Types ***
|
|
95
108
|
*******************/
|
|
96
109
|
|
|
97
|
-
export type Model = StricterUnion<ObjectModel | DataModel | PageModel | ConfigModel>;
|
|
110
|
+
export type Model = StricterUnion<ObjectModel | DataModel | PageModel | ConfigModel | ImageModel>;
|
|
98
111
|
|
|
99
112
|
export type ObjectModel = YamlObjectModel & BaseModel;
|
|
100
113
|
export type DataModel = YamlDataModel & BaseModel;
|
|
@@ -116,7 +129,7 @@ export interface YamlBaseModel {
|
|
|
116
129
|
filePath?: string;
|
|
117
130
|
invalid?: boolean;
|
|
118
131
|
};
|
|
119
|
-
label
|
|
132
|
+
label?: string;
|
|
120
133
|
description?: string;
|
|
121
134
|
thumbnail?: string;
|
|
122
135
|
extends?: string | string[];
|
|
@@ -174,6 +187,14 @@ export interface FieldGroupItem {
|
|
|
174
187
|
label: string;
|
|
175
188
|
}
|
|
176
189
|
|
|
190
|
+
export interface ImageModel {
|
|
191
|
+
type: 'image';
|
|
192
|
+
name: '__image_model';
|
|
193
|
+
label?: string;
|
|
194
|
+
labelField?: string;
|
|
195
|
+
fields?: Field[];
|
|
196
|
+
}
|
|
197
|
+
|
|
177
198
|
/*******************
|
|
178
199
|
*** Field Types ***
|
|
179
200
|
*******************/
|
|
@@ -209,7 +230,7 @@ export interface FieldCommonProps {
|
|
|
209
230
|
export type FieldType = typeof FIELD_TYPES[number];
|
|
210
231
|
|
|
211
232
|
export interface FieldSimpleProps {
|
|
212
|
-
type: 'string' | 'url' | 'slug' | 'text' | 'markdown' | 'html' | 'boolean' | 'date' | 'datetime' | 'color' | 'image' | 'file';
|
|
233
|
+
type: 'string' | 'url' | 'slug' | 'text' | 'markdown' | 'html' | 'boolean' | 'date' | 'datetime' | 'color' | 'image' | 'file' | 'json' | 'richText';
|
|
213
234
|
}
|
|
214
235
|
|
|
215
236
|
export type FieldEnumProps = FieldEnumDropdownProps | FieldEnumThumbnailsProps | FieldEnumPaletteProps;
|
|
@@ -29,6 +29,9 @@ export function convertToYamlConfig({ config }: { config: Config }): YamlConfig
|
|
|
29
29
|
yamlConfig.models = _.reduce(
|
|
30
30
|
config.models,
|
|
31
31
|
(yamlModels: ModelMap, model: Model) => {
|
|
32
|
+
if (model.type === 'image') {
|
|
33
|
+
return yamlModels;
|
|
34
|
+
}
|
|
32
35
|
const yamlModel = _.omit(model, ['name', '__metadata']) as YamlModel;
|
|
33
36
|
if (yamlModel.type === 'page' && !yamlModel.hideContent && yamlModel.fields) {
|
|
34
37
|
_.remove(yamlModel.fields, (field) => field.name === 'markdown_content');
|
|
@@ -20,13 +20,14 @@ export async function loadPresets(dirPath: string, config: Config): Promise<Pres
|
|
|
20
20
|
if (!(await fse.pathExists(presetsDir))) {
|
|
21
21
|
continue;
|
|
22
22
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
const files = (await fse.readdir(presetsDir))
|
|
24
|
+
.filter((fileName) => ['.json', '.yaml', '.yml'].includes(path.parse(fileName).ext))
|
|
25
|
+
.map((fileName) => path.join(presetsRelDir, fileName));
|
|
26
|
+
presetFiles.push(...files);
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
const presets: any = {};
|
|
29
|
-
const
|
|
29
|
+
const presets: Record<string, any> = {};
|
|
30
|
+
const presetsIdsByModel: Record<string, any> = {};
|
|
30
31
|
const errors: ConfigPresetsError[] = [];
|
|
31
32
|
|
|
32
33
|
for (const presetFile of presetFiles) {
|
|
@@ -45,22 +46,25 @@ export async function loadPresets(dirPath: string, config: Config): Promise<Pres
|
|
|
45
46
|
if (preset.thumbnail) {
|
|
46
47
|
preset.thumbnail = resolveThumbnailPath(preset.thumbnail, presetsRelDir);
|
|
47
48
|
}
|
|
48
|
-
|
|
49
|
+
_.set(preset, 'modelName', presetData.model);
|
|
50
|
+
append(presetsIdsByModel, presetData.model, presetId);
|
|
49
51
|
});
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
// update
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
if (
|
|
56
|
-
model
|
|
54
|
+
// update models with presets IDs
|
|
55
|
+
const models = _.map(config.models, (model) => {
|
|
56
|
+
const presetIdsForModel = presetsIdsByModel[model.name];
|
|
57
|
+
if (!presetIdsForModel) {
|
|
58
|
+
return model;
|
|
57
59
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
config.presets = presets;
|
|
60
|
+
return { ...model, presets: presetIdsForModel };
|
|
61
|
+
});
|
|
61
62
|
|
|
62
63
|
return {
|
|
63
|
-
config,
|
|
64
|
+
config: Object.assign({}, config, {
|
|
65
|
+
models,
|
|
66
|
+
presets
|
|
67
|
+
}),
|
|
64
68
|
errors
|
|
65
69
|
};
|
|
66
70
|
}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
isDataModel,
|
|
11
11
|
isPageModel,
|
|
12
12
|
getModelsByQuery,
|
|
13
|
-
|
|
13
|
+
getListFieldItems,
|
|
14
14
|
isListField,
|
|
15
15
|
isModelField,
|
|
16
16
|
isListDataModel,
|
|
@@ -480,7 +480,7 @@ function addMetadataRecursively({
|
|
|
480
480
|
} else if (_.isArray(value)) {
|
|
481
481
|
let fieldListItems: FieldListItems;
|
|
482
482
|
if (field && isListField(field)) {
|
|
483
|
-
fieldListItems =
|
|
483
|
+
fieldListItems = getListFieldItems(field);
|
|
484
484
|
} else if (model && isListDataModel(model)) {
|
|
485
485
|
fieldListItems = model.items;
|
|
486
486
|
} else {
|
|
@@ -106,6 +106,10 @@ function joiSchemaForModelFields(fields: Field[] | undefined, config: Config, fi
|
|
|
106
106
|
);
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
function assertUnreachable(field: never): never {
|
|
110
|
+
throw new Error('Unhandled field.type case');
|
|
111
|
+
}
|
|
112
|
+
|
|
109
113
|
function joiSchemaForField(field: Field | FieldListItems, config: Config, fieldPath: FieldPath) {
|
|
110
114
|
let fieldSchema;
|
|
111
115
|
switch (field.type) {
|
|
@@ -148,6 +152,11 @@ function joiSchemaForField(field: Field | FieldListItems, config: Config, fieldP
|
|
|
148
152
|
case 'list':
|
|
149
153
|
fieldSchema = listFieldValueSchema(field, config, fieldPath);
|
|
150
154
|
break;
|
|
155
|
+
case 'json':
|
|
156
|
+
case 'richText':
|
|
157
|
+
return Joi.any().forbidden();
|
|
158
|
+
default:
|
|
159
|
+
assertUnreachable(field);
|
|
151
160
|
}
|
|
152
161
|
if ('const' in field) {
|
|
153
162
|
fieldSchema = fieldSchema.valid(field.const).invalid(null, '').required();
|
|
@@ -11,7 +11,7 @@ export function extendModelArray(models: Model[]): { models: Model[]; errors: Co
|
|
|
11
11
|
models,
|
|
12
12
|
(result: { models: Model[]; errors: ConfigValidationError[] }, model) => {
|
|
13
13
|
// YamlModel is the same as Model just without 'name' and '__metadata' properties
|
|
14
|
-
const { model: extendedModel, errors } = memorized(model, model.name, modelsByName);
|
|
14
|
+
const { model: extendedModel, errors } = memorized(model, model.name, modelsByName as ModelMap);
|
|
15
15
|
return {
|
|
16
16
|
models: result.models.concat(extendedModel),
|
|
17
17
|
errors: result.errors.concat(errors)
|
|
@@ -101,10 +101,11 @@ function extendModel<T extends Model | YamlModel>(
|
|
|
101
101
|
let idx = 0;
|
|
102
102
|
_.forEach(extendedSuperModel.fields, (superField) => {
|
|
103
103
|
const field = _.find(fields, { name: superField.name });
|
|
104
|
+
superField = _.cloneDeep(superField);
|
|
104
105
|
if (field) {
|
|
105
|
-
_.
|
|
106
|
+
_.defaults(field, superField);
|
|
106
107
|
} else {
|
|
107
|
-
fields!.splice(idx++, 0,
|
|
108
|
+
fields!.splice(idx++, 0, superField);
|
|
108
109
|
}
|
|
109
110
|
});
|
|
110
111
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { Field, FieldListItems, FieldModelProps, Model } from '../config/config-types';
|
|
3
|
+
import { getListFieldItems, isListDataModel, isListField, isObjectListItems, isModelField, isObjectField, isModelListItems } from './model-utils';
|
|
4
|
+
import { DataModel, Field, FieldList, FieldListItems, FieldModelProps, FieldObjectProps, Model } from '../config/config-types';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* This function invokes the `iteratee` function for every field of the `model`.
|
|
@@ -39,24 +39,24 @@ import { Field, FieldListItems, FieldModelProps, Model } from '../config/config-
|
|
|
39
39
|
* @param model The model to iterate fields
|
|
40
40
|
* @param iteratee The callback function
|
|
41
41
|
*/
|
|
42
|
-
export function iterateModelFieldsRecursively(model: Model, iteratee: (field: Field,
|
|
43
|
-
function _iterateDeep({ fields,
|
|
44
|
-
|
|
42
|
+
export function iterateModelFieldsRecursively(model: Model, iteratee: (field: Field, modelKeyPath: string[]) => void) {
|
|
43
|
+
function _iterateDeep({ fields, modelKeyPath }: { fields: Field[]; modelKeyPath: string[] }) {
|
|
44
|
+
modelKeyPath = modelKeyPath.concat('fields');
|
|
45
45
|
_.forEach(fields, (field) => {
|
|
46
46
|
if (!field) {
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
|
-
const
|
|
50
|
-
iteratee(field,
|
|
49
|
+
const childModelKeyPath = modelKeyPath.concat(field.name);
|
|
50
|
+
iteratee(field, childModelKeyPath);
|
|
51
51
|
if (isObjectField(field)) {
|
|
52
52
|
_iterateDeep({
|
|
53
53
|
fields: field.fields,
|
|
54
|
-
|
|
54
|
+
modelKeyPath: childModelKeyPath
|
|
55
55
|
});
|
|
56
56
|
} else if (isListField(field) && field.items && isObjectListItems(field.items)) {
|
|
57
57
|
_iterateDeep({
|
|
58
58
|
fields: field.items?.fields,
|
|
59
|
-
|
|
59
|
+
modelKeyPath: childModelKeyPath.concat('items')
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
62
|
});
|
|
@@ -65,16 +65,64 @@ export function iterateModelFieldsRecursively(model: Model, iteratee: (field: Fi
|
|
|
65
65
|
if (model && isListDataModel(model) && model.items && isObjectListItems(model.items)) {
|
|
66
66
|
_iterateDeep({
|
|
67
67
|
fields: model.items?.fields,
|
|
68
|
-
|
|
68
|
+
modelKeyPath: ['items']
|
|
69
69
|
});
|
|
70
70
|
} else {
|
|
71
71
|
_iterateDeep({
|
|
72
72
|
fields: model?.fields || [],
|
|
73
|
-
|
|
73
|
+
modelKeyPath: []
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
export function mapModelFieldsRecursively(model: Model, iteratee: (field: Field, modelKeyPath: string[]) => Field) {
|
|
79
|
+
function _mapField(field: Field, modelKeyPath: string[]): Field {
|
|
80
|
+
if (!field) {
|
|
81
|
+
return field;
|
|
82
|
+
}
|
|
83
|
+
modelKeyPath = modelKeyPath.concat(field.name);
|
|
84
|
+
field = iteratee(field, modelKeyPath);
|
|
85
|
+
if (isObjectField(field)) {
|
|
86
|
+
return _mapObjectField(field, modelKeyPath);
|
|
87
|
+
} else if (isListField(field)) {
|
|
88
|
+
return _mapListField(field, modelKeyPath);
|
|
89
|
+
} else {
|
|
90
|
+
return field;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function _mapObjectField<T extends FieldObjectProps | Model>(field: T, modelKeyPath: string[]): T {
|
|
95
|
+
const fields = field.fields;
|
|
96
|
+
if (!fields) {
|
|
97
|
+
return field;
|
|
98
|
+
}
|
|
99
|
+
modelKeyPath = modelKeyPath.concat('fields');
|
|
100
|
+
return {
|
|
101
|
+
...field,
|
|
102
|
+
fields: _.map(fields, (field) => _mapField(field, modelKeyPath))
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function _mapListField<T extends FieldList | (DataModel & { isList: true })>(field: T, modelKeyPath: string[]): T {
|
|
107
|
+
const items = field.items;
|
|
108
|
+
if (!items || !isObjectListItems(items)) {
|
|
109
|
+
return field;
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
...field,
|
|
113
|
+
items: _mapObjectField(items, modelKeyPath.concat('items'))
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!model) {
|
|
118
|
+
return model;
|
|
119
|
+
} else if (isListDataModel(model)) {
|
|
120
|
+
return _mapListField(model, []);
|
|
121
|
+
} else {
|
|
122
|
+
return _mapObjectField(model, []);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
78
126
|
export function iterateObjectFieldsWithModelRecursively(
|
|
79
127
|
value: any,
|
|
80
128
|
model: Model,
|
|
@@ -165,7 +213,7 @@ export function iterateObjectFieldsWithModelRecursively(
|
|
|
165
213
|
} else if (_.isArray(value)) {
|
|
166
214
|
let fieldListItems: FieldListItems | null = null;
|
|
167
215
|
if (field && isListField(field)) {
|
|
168
|
-
fieldListItems =
|
|
216
|
+
fieldListItems = getListFieldItems(field);
|
|
169
217
|
} else if (model && isListDataModel(model)) {
|
|
170
218
|
fieldListItems = model.items;
|
|
171
219
|
}
|
|
@@ -287,7 +335,7 @@ export function mapObjectFieldsWithModelRecursively(
|
|
|
287
335
|
} else if (_.isArray(value)) {
|
|
288
336
|
let fieldListItems: FieldListItems | null = null;
|
|
289
337
|
if (field && isListField(field)) {
|
|
290
|
-
fieldListItems =
|
|
338
|
+
fieldListItems = getListFieldItems(field);
|
|
291
339
|
} else if (model && isListDataModel(model)) {
|
|
292
340
|
fieldListItems = model.items;
|
|
293
341
|
}
|
package/src/utils/model-utils.ts
CHANGED
|
@@ -79,20 +79,20 @@ export function isEnumField(field: Field): field is FieldEnum {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export function isListOfObjectsField(field: Field): field is FieldListObject {
|
|
82
|
-
return isListField(field) && isObjectListItems(
|
|
82
|
+
return isListField(field) && isObjectListItems(getListFieldItems(field));
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
export function isListOfModelsField(field: Field): field is FieldListModel {
|
|
86
|
-
return isListField(field) && isModelListItems(
|
|
86
|
+
return isListField(field) && isModelListItems(getListFieldItems(field));
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
export function isListOfReferencesField(field: Field): field is FieldListReference {
|
|
90
|
-
return isListField(field) && isReferenceListItems(
|
|
90
|
+
return isListField(field) && isReferenceListItems(getListFieldItems(field));
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
export function isListOfCustomModelsField(field: Field, modelsByName?: Record<string, Model>): field is FieldList {
|
|
94
94
|
// custom model field types are deprecated
|
|
95
|
-
return isListField(field) && isCustomModelListItems(
|
|
95
|
+
return isListField(field) && isCustomModelListItems(getListFieldItems(field), modelsByName);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
export function isListField(field: Field): field is FieldList {
|
|
@@ -122,7 +122,7 @@ export function isCustomModelListItems(items: FieldListItems, modelsByName?: Rec
|
|
|
122
122
|
* items field, the default field is string:
|
|
123
123
|
*
|
|
124
124
|
* @example
|
|
125
|
-
* listItemField =
|
|
125
|
+
* listItemField = getListFieldItems({
|
|
126
126
|
* type: 'list',
|
|
127
127
|
* name: '...',
|
|
128
128
|
* items: { type: 'object', fields: [] }
|
|
@@ -134,15 +134,36 @@ export function isCustomModelListItems(items: FieldListItems, modelsByName?: Rec
|
|
|
134
134
|
* }
|
|
135
135
|
*
|
|
136
136
|
* // list field without `items`
|
|
137
|
-
* listItemField =
|
|
137
|
+
* listItemField = getListFieldItems({ type: 'list', name: '...' }
|
|
138
138
|
* listItemField => { type: 'string' }
|
|
139
139
|
*
|
|
140
140
|
* @param {Object} field
|
|
141
141
|
* @return {Object}
|
|
142
142
|
*/
|
|
143
|
-
export function
|
|
143
|
+
export function getListFieldItems(field: FieldList): FieldListItems {
|
|
144
144
|
// items.type defaults to string
|
|
145
|
-
return
|
|
145
|
+
return Object.assign({ type: 'string' }, field.items);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function normalizeListField(field: FieldList): FieldList {
|
|
149
|
+
if (field.items?.type) {
|
|
150
|
+
return field;
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
...field,
|
|
154
|
+
items: {
|
|
155
|
+
type: 'string',
|
|
156
|
+
...(field.items ?? {})
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function normalizeListFieldInPlace(field: FieldList): FieldList {
|
|
162
|
+
// 'items.type' of list field default to 'string', set it explicitly
|
|
163
|
+
if (!_.has(field, 'items.type')) {
|
|
164
|
+
_.set(field, 'items.type', 'string');
|
|
165
|
+
}
|
|
166
|
+
return field;
|
|
146
167
|
}
|
|
147
168
|
|
|
148
169
|
export function assignLabelFieldIfNeeded(modelOrField: Model | FieldObjectProps) {
|
|
@@ -176,3 +197,65 @@ export function resolveLabelFieldForModel(modelOrField: Model | FieldObjectProps
|
|
|
176
197
|
}
|
|
177
198
|
return labelField || null;
|
|
178
199
|
}
|
|
200
|
+
|
|
201
|
+
export function getModelFieldForModelKeyPath(model: Model, modelKeyPath: string[]) {
|
|
202
|
+
function _getField(field: Field, modelKeyPath: string[]): Model | Field | FieldListItems | FieldObjectProps | null {
|
|
203
|
+
if (modelKeyPath.length === 0) {
|
|
204
|
+
return field;
|
|
205
|
+
} else if (isObjectField(field)) {
|
|
206
|
+
return _getObjectFields(field, modelKeyPath);
|
|
207
|
+
} else if (isListField(field)) {
|
|
208
|
+
return _getListItems(field, modelKeyPath);
|
|
209
|
+
} else {
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function _getObjectFields<T extends FieldObjectProps | Model>(field: T, modelKeyPath: string[]): Model | Field | FieldListItems | FieldObjectProps | null {
|
|
215
|
+
if (modelKeyPath.length === 0) {
|
|
216
|
+
return field;
|
|
217
|
+
}
|
|
218
|
+
const key = modelKeyPath.shift();
|
|
219
|
+
if (key !== 'fields' || !field.fields) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
if (modelKeyPath.length === 0) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const fieldName = modelKeyPath.shift();
|
|
226
|
+
const childField = _.find(field.fields, (field) => field.name === fieldName);
|
|
227
|
+
if (!childField) {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
return _getField(childField, modelKeyPath);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function _getListItems<T extends FieldList | (DataModel & { isList: true })>(
|
|
234
|
+
field: T,
|
|
235
|
+
modelKeyPath: string[]
|
|
236
|
+
): Model | Field | FieldListItems | FieldObjectProps | null {
|
|
237
|
+
if (modelKeyPath.length === 0) {
|
|
238
|
+
return field;
|
|
239
|
+
}
|
|
240
|
+
const key = modelKeyPath.shift();
|
|
241
|
+
if (key !== 'items' || !field.items) {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
if (modelKeyPath.length === 0) {
|
|
245
|
+
return field.items;
|
|
246
|
+
}
|
|
247
|
+
if (!isObjectListItems(field.items)) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
return _getObjectFields(field.items, modelKeyPath);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
modelKeyPath = modelKeyPath.slice();
|
|
254
|
+
if (!model) {
|
|
255
|
+
return null;
|
|
256
|
+
} else if (isListDataModel(model)) {
|
|
257
|
+
return _getListItems(model, modelKeyPath);
|
|
258
|
+
} else {
|
|
259
|
+
return _getObjectFields(model, modelKeyPath);
|
|
260
|
+
}
|
|
261
|
+
}
|