@stackbit/sdk 0.3.3-alpha.1 → 0.3.3-alpha.2

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.
Files changed (66) hide show
  1. package/dist/analyzer/analyze-schema-types.d.ts +10 -13
  2. package/dist/analyzer/analyze-schema-types.d.ts.map +1 -1
  3. package/dist/analyzer/analyze-schema-types.js.map +1 -1
  4. package/dist/analyzer/schema-generator.d.ts.map +1 -1
  5. package/dist/analyzer/schema-generator.js +6 -2
  6. package/dist/analyzer/schema-generator.js.map +1 -1
  7. package/dist/analyzer/site-analyzer.d.ts.map +1 -1
  8. package/dist/analyzer/site-analyzer.js.map +1 -1
  9. package/dist/config/config-consts.d.ts +1 -25
  10. package/dist/config/config-consts.d.ts.map +1 -1
  11. package/dist/config/config-consts.js +6 -79
  12. package/dist/config/config-consts.js.map +1 -1
  13. package/dist/config/config-loader-static.d.ts +3 -1
  14. package/dist/config/config-loader-static.d.ts.map +1 -1
  15. package/dist/config/config-loader-static.js +5 -1
  16. package/dist/config/config-loader-static.js.map +1 -1
  17. package/dist/config/config-loader-utils.d.ts +2 -1
  18. package/dist/config/config-loader-utils.d.ts.map +1 -1
  19. package/dist/config/config-loader-utils.js +4 -1
  20. package/dist/config/config-loader-utils.js.map +1 -1
  21. package/dist/config/config-loader.d.ts +2 -1
  22. package/dist/config/config-loader.d.ts.map +1 -1
  23. package/dist/config/config-loader.js.map +1 -1
  24. package/dist/config/config-schema.d.ts +2 -2
  25. package/dist/config/config-schema.d.ts.map +1 -1
  26. package/dist/config/config-schema.js.map +1 -1
  27. package/dist/config/config-types.d.ts +44 -287
  28. package/dist/config/config-types.d.ts.map +1 -1
  29. package/dist/config/config-validator.d.ts +3 -2
  30. package/dist/config/config-validator.d.ts.map +1 -1
  31. package/dist/config/config-validator.js.map +1 -1
  32. package/dist/config/presets-loader.js +3 -0
  33. package/dist/config/presets-loader.js.map +1 -1
  34. package/dist/content/content-schema.js +1 -1
  35. package/dist/content/content-schema.js.map +1 -1
  36. package/dist/utils/model-extender.d.ts +3 -3
  37. package/dist/utils/model-extender.d.ts.map +1 -1
  38. package/dist/utils/model-extender.js +3 -3
  39. package/dist/utils/model-extender.js.map +1 -1
  40. package/dist/utils/model-iterators.d.ts +3 -67
  41. package/dist/utils/model-iterators.d.ts.map +1 -1
  42. package/dist/utils/model-iterators.js.map +1 -1
  43. package/dist/utils/model-matcher.js +1 -1
  44. package/dist/utils/model-matcher.js.map +1 -1
  45. package/dist/utils/model-utils.d.ts +8 -52
  46. package/dist/utils/model-utils.d.ts.map +1 -1
  47. package/dist/utils/model-utils.js +5 -1
  48. package/dist/utils/model-utils.js.map +1 -1
  49. package/package.json +3 -2
  50. package/src/analyzer/analyze-schema-types.ts +12 -16
  51. package/src/analyzer/schema-generator.ts +14 -4
  52. package/src/analyzer/site-analyzer.ts +2 -1
  53. package/src/config/config-consts.ts +1 -83
  54. package/src/config/config-loader-static.ts +11 -3
  55. package/src/config/config-loader-utils.ts +7 -3
  56. package/src/config/config-loader.ts +12 -11
  57. package/src/config/config-schema/style-field-schema.ts +1 -1
  58. package/src/config/config-schema.ts +20 -25
  59. package/src/config/config-types.ts +103 -334
  60. package/src/config/config-validator.ts +3 -2
  61. package/src/config/presets-loader.ts +3 -0
  62. package/src/content/content-schema.ts +1 -1
  63. package/src/utils/model-extender.ts +8 -8
  64. package/src/utils/model-iterators.ts +2 -2
  65. package/src/utils/model-matcher.ts +1 -1
  66. package/src/utils/model-utils.ts +25 -11
@@ -1,136 +1,72 @@
1
- import { StricterUnion } from '../utils';
2
- import { CMS_NAMES, FIELD_TYPES, SSG_NAMES, STYLE_PROPS } from './config-consts';
3
-
4
- export interface Config extends BaseConfig {
5
- stackbitVersion: string;
1
+ import {
2
+ StackbitConfig,
3
+ ObjectModel as StackbitConfigObjectModel,
4
+ ConfigModel as StackbitConfigConfigModel,
5
+ PageModel as StackbitConfigPageModel,
6
+ DataModel as StackbitConfigDataModel,
7
+ ModelCommonFields,
8
+ Field,
9
+ FieldListItems
10
+ } from '@stackbit/types';
11
+
12
+ // re-export types for backward compatibility
13
+ export {
14
+ StackbitConfig as RawConfig,
15
+ Import,
16
+ ContentfulImport,
17
+ SanityImport,
18
+ ContentModelMap,
19
+ ContentModel,
20
+ PresetSource,
21
+ PresetSourceFiles,
22
+ ModelsSource,
23
+ ModelsSourceFiles,
24
+ ModelsSourceContentful,
25
+ ModelsSourceSanity,
26
+ Field,
27
+ FieldType,
28
+ FieldSpecificProps,
29
+ FieldCommonProps,
30
+ FieldBasic as FieldSimple,
31
+ FieldEnum,
32
+ FieldImage,
33
+ FieldNumber,
34
+ FieldObject,
35
+ FieldModel,
36
+ FieldReference,
37
+ FieldStyle,
38
+ FieldList,
39
+ FieldListObject,
40
+ FieldListModel,
41
+ FieldListReference,
42
+ FieldBasicProps as FieldSimpleProps,
43
+ FieldEnumProps,
44
+ FieldEnumDropdownProps,
45
+ FieldEnumThumbnailsProps,
46
+ FieldEnumPaletteProps,
47
+ FieldEnumOptionValue,
48
+ FieldEnumOptionObject,
49
+ FieldEnumOptionThumbnails,
50
+ FieldEnumOptionPalette,
51
+ FieldImageProps,
52
+ FieldNumberProps,
53
+ FieldObjectProps,
54
+ FieldGroupItem,
55
+ FieldModelProps,
56
+ FieldReferenceProps,
57
+ StyleProps,
58
+ FieldStyleProps,
59
+ FieldListProps,
60
+ FieldListItems
61
+ } from '@stackbit/types';
62
+
63
+ export interface Config extends Omit<StackbitConfig, 'models' | 'customContentReload' | 'experimental'> {
64
+ dirPath: string;
65
+ filePath: string;
6
66
  models: Model[];
7
67
  presets?: Record<string, Preset>;
8
- hcrHandled?: boolean;
9
68
  internalStackbitRunnerOptions?: SSGRunOptions;
10
- dirPath: string;
11
- filePath: string;
12
- }
13
-
14
- export interface RawConfig extends BaseConfig {
15
- stackbitVersion?: string;
16
- models?: ModelMap;
17
- }
18
-
19
- interface BaseConfig {
20
- ssgName?: typeof SSG_NAMES[number];
21
- ssgVersion?: string;
22
- nodeVersion?: string;
23
- postGitCloneCommand?: string;
24
- preInstallCommand?: string;
25
- postInstallCommand?: string;
26
- devCommand?: string;
27
- cmsName?: typeof CMS_NAMES[number];
28
- import?: Import;
29
- buildCommand?: string;
30
- publishDir?: string;
31
- staticDir?: string;
32
- uploadDir?: string;
33
- assets?: Assets;
34
- pagesDir?: string | null;
35
- dataDir?: string | null;
36
- pageLayoutKey?: string | null;
37
- objectTypeKey?: string;
38
- styleObjectModelName?: string | null;
39
- excludePages?: string | string[];
40
- logicFields?: LogicField[];
41
- contentModels?: ContentModelMap;
42
- presetSource?: PresetSource;
43
- modelsSource?: ModelsSource;
44
- presetReferenceBehavior?: 'copyReference' | 'duplicateContents';
45
- nonDuplicatableModels?: string[];
46
- duplicatableModels?: string[];
47
- contentSources?: any[]; // TODO: set to ContentSourceInterface[], move it to @stackbit/types first
48
- mapModels?: (options: { models: Model[]; contentSourceType: string; contentSourceProjectId: string }) => Model[];
49
-
50
- // DEPRECATED
51
- noEncodeFields?: string[]; // DEPRECATED, for backward compatibility and typescript support
52
- omitFields?: string[]; // DEPRECATED, for backward compatibility and typescript support
53
- encodedFieldTypes?: string[]; // DEPRECATED, for backward compatibility and typescript support
54
- }
55
-
56
- export type Import = ContentfulImport | SanityImport;
57
-
58
- export interface ContentfulImport {
59
- type: 'contentful';
60
- contentFile: string;
61
- uploadAssets?: boolean;
62
- assetsDirectory?: string;
63
- spaceIdEnvVar?: string;
64
- accessTokenEnvVar?: string;
65
- deliveryTokenEnvVar?: string;
66
- previewTokenEnvVar?: string;
67
- }
68
-
69
- export interface SanityImport {
70
- type: 'sanity';
71
- contentFile: string;
72
- sanityStudioPath: string;
73
- deployStudio?: boolean;
74
- deployGraphql?: boolean;
75
- projectIdEnvVar?: string;
76
- datasetEnvVar?: string;
77
- tokenEnvVar?: string;
78
- }
79
-
80
- export type Assets = StricterUnion<StaticAssets | RelativeAssets>;
81
-
82
- export interface StaticAssets {
83
- referenceType: 'static';
84
- assetsDir?: string;
85
- staticDir: string;
86
- publicPath: string;
87
- uploadDir?: string;
88
- }
89
-
90
- export interface RelativeAssets {
91
- referenceType: 'relative';
92
- assetsDir: string;
93
- staticDir?: string;
94
- publicPath?: string;
95
- uploadDir?: string;
96
- }
97
-
98
- export type LogicField = string;
99
-
100
- export type ContentModelMap = Record<string, ContentModel>;
101
-
102
- export interface ContentModel extends BaseMatch {
103
- isPage?: boolean;
104
- urlPath?: string;
105
- hideContent?: boolean;
106
- newFilePath?: string;
107
- }
108
-
109
- export type PresetSource = PresetSourceFiles;
110
-
111
- export interface PresetSourceFiles {
112
- type: 'files';
113
- presetDirs: string[];
114
- }
115
-
116
- export type ModelsSource = ModelsSourceFiles | ModelsSourceContentful | ModelsSourceSanity;
117
-
118
- export interface ModelsSourceFiles {
119
- type: 'files';
120
- modelDirs: string[];
121
- }
122
-
123
- export interface ModelsSourceContentful {
124
- type: 'contentful';
125
- module?: string;
126
- [key: string]: any;
127
- }
128
-
129
- export interface ModelsSourceSanity {
130
- type: 'sanity';
131
- sanityStudioPath: string;
132
- module?: string;
133
- [key: string]: any;
69
+ hcrHandled?: boolean;
134
70
  }
135
71
 
136
72
  export interface Preset {
@@ -151,235 +87,68 @@ export interface SSGRunOptions {
151
87
  };
152
88
  }
153
89
 
154
- /*******************
155
- *** Model Types ***
156
- *******************/
157
-
158
- export type Model = StricterUnion<ObjectModel | DataModel | PageModel | ConfigModel | ImageModel>;
159
-
160
- export type ObjectModel = YamlObjectModel & BaseModel;
161
- export type DataModel = YamlDataModel & BaseModel;
162
- export type PageModel = YamlPageModel & BaseModel;
163
- export type ConfigModel = YamlConfigModel & BaseModel;
164
-
165
- export type BaseModel = {
166
- name: string;
167
- presets?: string[];
168
- };
169
-
170
- export type ModelMap = Record<string, YamlModel>;
171
-
172
- export type YamlModel = StricterUnion<YamlObjectModel | YamlDataModel | YamlPageModel | YamlConfigModel>;
173
-
174
- export interface YamlBaseModel {
175
- type: 'object' | 'data' | 'page' | 'config';
176
- __metadata?: {
177
- filePath?: string;
178
- invalid?: boolean;
179
- };
180
- label?: string;
181
- description?: string;
182
- thumbnail?: string;
183
- extends?: string | string[];
184
- readOnly?: boolean;
185
- labelField?: string;
186
- variantField?: string;
187
- groups?: string[];
188
- fieldGroups?: FieldGroupItem[];
189
- fields?: Field[];
190
- }
191
-
192
- interface BaseMatch {
193
- singleInstance?: boolean;
194
- file?: string;
195
- folder?: string;
196
- match?: string | string[];
197
- exclude?: string | string[];
198
- }
90
+ /******************************
91
+ *** Normalized Model Types ***
92
+ ******************************/
199
93
 
200
- export interface YamlObjectModel extends YamlBaseModel {
201
- type: 'object';
202
- }
94
+ export type Model = ObjectModel | DataModel | PageModel | ConfigModel | ImageModel;
203
95
 
204
- export interface BaseDataModel extends YamlBaseModel, BaseMatch {
205
- type: 'data';
206
- filePath?: string;
207
- }
208
-
209
- export interface YamlPageModel extends YamlBaseModel, BaseMatch {
210
- type: 'page';
211
- layout?: string;
212
- urlPath?: string;
213
- filePath?: string;
214
- hideContent?: boolean;
215
- }
216
-
217
- export interface YamlConfigModel extends YamlBaseModel {
218
- type: 'config';
219
- file?: string;
220
- }
221
-
222
- export type YamlDataModel = StricterUnion<BaseDataModelFields | BaseDataModeList>;
223
-
224
- export interface BaseDataModelFields extends BaseDataModel {
225
- isList?: false;
226
- }
227
-
228
- export interface BaseDataModeList extends Omit<BaseDataModel, 'fields'> {
229
- isList: true;
230
- items: FieldListItems;
231
- }
232
-
233
- export interface FieldGroupItem {
234
- name: string;
235
- label: string;
236
- icon?: string;
237
- }
238
-
239
- export interface ImageModel {
96
+ export type ObjectModel = StackbitConfigObjectModel & BaseModel;
97
+ export type DataModel = DataModelSingle | DataModelList;
98
+ export type PageModel = StackbitConfigPageModel & BaseModel;
99
+ export type ConfigModel = StackbitConfigConfigModel & BaseModel;
100
+ export type ImageModel = {
240
101
  type: 'image';
241
102
  name: '__image_model';
242
103
  label?: string;
243
104
  labelField?: string;
244
105
  fields?: Field[];
245
106
  source?: string;
246
- }
247
-
248
- /*******************
249
- *** Field Types ***
250
- *******************/
251
-
252
- export type Field = FieldSimple | FieldEnum | FieldImage | FieldNumber | FieldObject | FieldModel | FieldReference | FieldStyle | FieldList;
253
-
254
- export type FieldSpecificProps =
255
- | FieldSimpleProps
256
- | FieldEnumProps
257
- | FieldImageProps
258
- | FieldNumberProps
259
- | FieldObjectProps
260
- | FieldModelProps
261
- | FieldReferenceProps
262
- | FieldStyleProps
263
- | FieldListProps;
264
-
265
- export type FieldSimple = FieldCommonProps & FieldSimpleProps;
266
- export type FieldEnum = FieldCommonProps & FieldEnumProps;
267
- export type FieldImage = FieldCommonProps & FieldImageProps;
268
- export type FieldNumber = FieldCommonProps & FieldNumberProps;
269
- export type FieldObject = FieldCommonProps & FieldObjectProps;
270
- export type FieldModel = FieldCommonProps & FieldModelProps;
271
- export type FieldReference = FieldCommonProps & FieldReferenceProps;
272
- export type FieldStyle = FieldCommonProps & FieldStyleProps;
273
- export type FieldList = FieldCommonProps & FieldListProps;
274
-
275
- export type FieldListObject = FieldList & { items?: FieldObjectProps };
276
- export type FieldListModel = FieldList & { items?: FieldModelProps };
277
- export type FieldListReference = FieldList & { items?: FieldReferenceProps };
278
-
279
- export interface FieldCommonProps {
280
- type: FieldType;
281
- name: string;
282
- label?: string;
283
- description?: string;
284
- required?: boolean;
285
- default?: unknown;
286
- group?: string;
287
- const?: unknown;
288
- hidden?: boolean;
289
- readOnly?: boolean;
290
- localized?: boolean;
291
- }
292
-
293
- export type FieldType = typeof FIELD_TYPES[number];
294
-
295
- export interface FieldSimpleProps {
296
- type: 'string' | 'url' | 'slug' | 'text' | 'markdown' | 'html' | 'boolean' | 'date' | 'datetime' | 'color' | 'file' | 'json' | 'richText';
297
- }
298
-
299
- export type FieldEnumProps = FieldEnumDropdownProps | FieldEnumThumbnailsProps | FieldEnumPaletteProps;
300
-
301
- export interface FieldEnumDropdownProps {
302
- type: 'enum';
303
- controlType?: 'dropdown' | 'button-group';
304
- options: FieldEnumOptionValue[] | FieldEnumOptionObject[];
305
- }
107
+ };
306
108
 
307
- export interface FieldEnumThumbnailsProps {
308
- type: 'enum';
309
- controlType: 'thumbnails';
310
- options: FieldEnumOptionThumbnails[];
109
+ export interface DataModelSingle extends StackbitConfigDataModel, BaseModel {
110
+ isList?: false;
311
111
  }
312
112
 
313
- export interface FieldEnumPaletteProps {
314
- type: 'enum';
315
- controlType: 'palette';
316
- options: FieldEnumOptionPalette[];
113
+ export interface DataModelList extends StackbitConfigDataModel, BaseModel {
114
+ isList: true;
115
+ items: FieldListItems;
317
116
  }
318
117
 
319
- export type FieldEnumOptionValue = string | number;
118
+ type BaseModel = ModelMetadata & { presets?: string[] };
320
119
 
321
- export interface FieldEnumOptionObject {
322
- label: string;
323
- value: FieldEnumOptionValue;
120
+ interface ModelMetadata {
121
+ __metadata?: {
122
+ filePath?: string;
123
+ invalid?: boolean;
124
+ };
324
125
  }
325
126
 
326
- export interface FieldEnumOptionThumbnails extends FieldEnumOptionObject {
327
- thumbnail?: string;
328
- }
127
+ /***********************
128
+ *** Raw Model Types ***
129
+ ***********************/
329
130
 
330
- export interface FieldEnumOptionPalette extends FieldEnumOptionObject {
331
- textColor?: string;
332
- backgroundColor?: string;
333
- borderColor?: string;
334
- }
131
+ export type YamlModel = YamlObjectModel | YamlPageModel | YamlConfigModel | YamlDataModel;
335
132
 
336
- export interface FieldImageProps {
337
- type: 'image';
338
- source?: string;
339
- }
133
+ export type YamlModelMap = Record<string, YamlModel>;
340
134
 
341
- export interface FieldNumberProps {
342
- type: 'number';
343
- controlType?: 'slider';
344
- subtype?: 'int' | 'float';
345
- min?: number;
346
- max?: number;
347
- step?: number;
348
- unit?: string;
135
+ export interface YamlBaseModel extends Omit<ModelCommonFields, 'name'>, ModelMetadata {
136
+ type: YamlModel['type'];
349
137
  }
350
138
 
351
- export interface FieldObjectProps {
352
- type: 'object';
353
- labelField?: string;
354
- thumbnail?: string;
355
- variantField?: string;
356
- fieldGroups?: FieldGroupItem[];
357
- fields: Field[];
358
- }
139
+ export interface YamlObjectModel extends Omit<StackbitConfigObjectModel, 'name'>, ModelMetadata {}
359
140
 
360
- export interface FieldModelProps {
361
- type: 'model';
362
- models: string[];
363
- groups?: string[];
364
- }
141
+ export interface YamlPageModel extends Omit<StackbitConfigPageModel, 'name'>, ModelMetadata {}
365
142
 
366
- export interface FieldReferenceProps {
367
- type: 'reference';
368
- models: string[];
369
- groups?: string[];
370
- }
143
+ export interface YamlConfigModel extends Omit<StackbitConfigConfigModel, 'name'>, ModelMetadata {}
371
144
 
372
- export type StyleProps = typeof STYLE_PROPS[number];
145
+ export type YamlDataModel = YamlDataModelSingle | YamlDataModelList;
373
146
 
374
- export interface FieldStyleProps {
375
- type: 'style';
376
- styles: Record<string, Partial<Record<StyleProps, any>>>;
147
+ export interface YamlDataModelSingle extends Omit<StackbitConfigDataModel, 'name'>, ModelMetadata {
148
+ isList?: false;
377
149
  }
378
150
 
379
- export interface FieldListProps {
380
- type: 'list';
381
- items?: FieldListItems;
382
- controlType?: 'checkbox';
151
+ export interface YamlDataModelList extends Omit<StackbitConfigDataModel, 'name'>, ModelMetadata {
152
+ isList: true;
153
+ items: FieldListItems;
383
154
  }
384
-
385
- export type FieldListItems = FieldSimpleProps | FieldEnumProps | FieldImageProps | FieldNumberProps | FieldObjectProps | FieldModelProps | FieldReferenceProps;
@@ -1,10 +1,11 @@
1
1
  import _ from 'lodash';
2
2
  import Joi from 'joi';
3
+ import { ContentModelMap } from '@stackbit/types';
3
4
 
4
5
  import { stackbitConfigSchema, contentModelsSchema } from './config-schema';
5
6
  import { ConfigValidationError } from './config-errors';
6
7
  import { RawConfigWithPaths } from './config-loader-utils';
7
- import { ContentModelMap, ModelMap } from './config-types';
8
+ import { YamlModelMap } from './config-types';
8
9
 
9
10
  export interface ConfigValidationResult {
10
11
  value: RawConfigWithPaths;
@@ -26,7 +27,7 @@ export function validateConfig(config: RawConfigWithPaths): ConfigValidationResu
26
27
  };
27
28
  }
28
29
 
29
- export function validateContentModels(contentModels: ContentModelMap, models: ModelMap): ConfigValidationResult {
30
+ export function validateContentModels(contentModels: ContentModelMap, models: YamlModelMap): ConfigValidationResult {
30
31
  const validationResult = contentModelsSchema.validate(
31
32
  { contentModels: contentModels },
32
33
  {
@@ -90,6 +90,9 @@ export async function loadPresets(dirPath: string, config: Config): Promise<Pres
90
90
  }
91
91
 
92
92
  function resolveThumbnailPath(thumbnail: string, dir: string) {
93
+ if (thumbnail.startsWith('//') || /https?:\/\//.test(thumbnail)) {
94
+ return thumbnail;
95
+ }
93
96
  if (thumbnail.startsWith('/')) {
94
97
  if (dir.endsWith('@stackbit/components/presets')) {
95
98
  dir = dir.replace(/\/presets$/, '');
@@ -37,7 +37,7 @@ export function joiSchemasForModels(config: Config) {
37
37
  config.models,
38
38
  (modelSchemas: ModelSchemaMap, model: Model) => {
39
39
  let joiSchema: Joi.ObjectSchema;
40
- if (model.__metadata?.invalid) {
40
+ if (model.type !== 'image' && model.__metadata?.invalid) {
41
41
  // if root model is invalid, replace the label with "file" otherwise joi outputs "value" which is not descriptive
42
42
  let objectLabel = '{{#label}}';
43
43
  if (isDataModel(model) || isPageModel(model)) {
@@ -1,7 +1,7 @@
1
1
  import _ from 'lodash';
2
2
  import { copyIfNotSet } from '@stackbit/utils';
3
3
 
4
- import { Model, YamlModel, ModelMap } from '../config/config-types';
4
+ import { Model, YamlModel, YamlModelMap } from '../config/config-types';
5
5
  import { ConfigValidationError } from '../config/config-errors';
6
6
 
7
7
  export function extendModelArray(models: Model[]): { models: Model[]; errors: ConfigValidationError[] } {
@@ -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 as ModelMap);
14
+ const { model: extendedModel, errors } = memorized(model, model.name, modelsByName as YamlModelMap);
15
15
  return {
16
16
  models: result.models.concat(extendedModel),
17
17
  errors: result.errors.concat(errors)
@@ -21,11 +21,11 @@ export function extendModelArray(models: Model[]): { models: Model[]; errors: Co
21
21
  );
22
22
  }
23
23
 
24
- export function extendModelMap(models?: ModelMap): { models: ModelMap; errors: ConfigValidationError[] } {
24
+ export function extendModelMap(models?: YamlModelMap): { models: YamlModelMap; errors: ConfigValidationError[] } {
25
25
  const memorized = _.memoize(extendModel, (model, modelName) => modelName);
26
26
  return _.reduce(
27
27
  models,
28
- (result: { models: ModelMap; errors: ConfigValidationError[] }, model, modelName) => {
28
+ (result: { models: YamlModelMap; errors: ConfigValidationError[] }, model, modelName) => {
29
29
  const { model: extendedModel, errors } = memorized(model, modelName, models!);
30
30
  return {
31
31
  models: _.assign(result.models, { [modelName]: extendedModel }),
@@ -39,7 +39,7 @@ export function extendModelMap(models?: ModelMap): { models: ModelMap; errors: C
39
39
  function extendModel<T extends Model | YamlModel>(
40
40
  model: T,
41
41
  modelName: string,
42
- modelsByName: ModelMap,
42
+ modelsByName: YamlModelMap,
43
43
  _extendPath: string[] = []
44
44
  ): { model: T; errors: ConfigValidationError[] } {
45
45
  if (_.includes(_extendPath, modelName)) {
@@ -63,7 +63,7 @@ function extendModel<T extends Model | YamlModel>(
63
63
  return { model, errors: [] };
64
64
  }
65
65
 
66
- delete model['extends'];
66
+ _.unset(model, 'extends');
67
67
 
68
68
  if (!_.isArray(_extends)) {
69
69
  _extends = [_extends];
@@ -95,8 +95,8 @@ function extendModel<T extends Model | YamlModel>(
95
95
  copyIfNotSet(extendedSuperModel, 'singleInstance', model, 'singleInstance');
96
96
  copyIfNotSet(extendedSuperModel, 'labelField', model, 'labelField');
97
97
  copyIfNotSet(extendedSuperModel, 'variantField', model, 'variantField');
98
- if (Array.isArray(extendedSuperModel.fieldGroups) && extendedSuperModel.fieldGroups.length > 0) {
99
- model.fieldGroups = _.uniqBy(_.concat(extendedSuperModel.fieldGroups, _.get(model, 'fieldGroups', [])), 'name');
98
+ if (model.type !== 'image' && Array.isArray(extendedSuperModel.fieldGroups) && extendedSuperModel.fieldGroups.length > 0) {
99
+ _.set(model, 'fieldGroups', _.uniqBy(_.concat(extendedSuperModel.fieldGroups, _.get(model, 'fieldGroups', [])), 'name'));
100
100
  }
101
101
  let idx = 0;
102
102
  _.forEach(extendedSuperModel.fields, (superField) => {
@@ -2,7 +2,7 @@ import _ from 'lodash';
2
2
 
3
3
  import { mapPromise, mapValuesPromise } from '@stackbit/utils';
4
4
  import { getListFieldItems, isListDataModel, isListField, isObjectListItems, isModelField, isObjectField, isModelListItems } from './model-utils';
5
- import { DataModel, Field, FieldList, FieldListItems, FieldModelProps, FieldObjectProps, Model } from '../config/config-types';
5
+ import { Model, YamlModel, DataModel, Field, FieldList, FieldListItems, FieldModelProps, FieldObjectProps } from '../config/config-types';
6
6
 
7
7
  /**
8
8
  * This function invokes the `iteratee` function for every field of the `model`.
@@ -40,7 +40,7 @@ import { DataModel, Field, FieldList, FieldListItems, FieldModelProps, FieldObje
40
40
  * @param model The model to iterate fields
41
41
  * @param iteratee The callback function
42
42
  */
43
- export function iterateModelFieldsRecursively(model: Model, iteratee: (field: Field, modelKeyPath: string[]) => void) {
43
+ export function iterateModelFieldsRecursively(model: Model | YamlModel, iteratee: (field: Field, modelKeyPath: string[]) => void) {
44
44
  function _iterateDeep({ fields, modelKeyPath }: { fields: Field[]; modelKeyPath: string[] }) {
45
45
  modelKeyPath = modelKeyPath.concat('fields');
46
46
  _.forEach(fields, (field) => {
@@ -91,7 +91,7 @@ export function getModelsByQuery(query: ModelQuery, models: Model[]): Model[] {
91
91
  );
92
92
 
93
93
  const fileMatchedModels = _.filter(modelMatchGroups.byFile, (model) => {
94
- if (!_.isString(model.file)) {
94
+ if (!('file' in model) || !_.isString(model.file)) {
95
95
  return false;
96
96
  }
97
97
  try {