@stackbit/sdk 0.3.13-alpha.0 → 0.3.13-alpha.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/config/config-errors.d.ts +12 -1
- package/dist/config/config-errors.d.ts.map +1 -1
- package/dist/config/config-errors.js +23 -1
- package/dist/config/config-errors.js.map +1 -1
- package/dist/config/config-loader-static.d.ts +2 -2
- package/dist/config/config-loader-static.d.ts.map +1 -1
- package/dist/config/config-loader-static.js +1 -1
- package/dist/config/config-loader-static.js.map +1 -1
- package/dist/config/config-loader-utils.d.ts +3 -3
- package/dist/config/config-loader-utils.d.ts.map +1 -1
- package/dist/config/config-loader-utils.js +4 -6
- package/dist/config/config-loader-utils.js.map +1 -1
- package/dist/config/config-loader.d.ts +10 -9
- package/dist/config/config-loader.d.ts.map +1 -1
- package/dist/config/config-loader.js +70 -34
- package/dist/config/config-loader.js.map +1 -1
- package/dist/config/config-schema.d.ts +3 -2
- package/dist/config/config-schema.d.ts.map +1 -1
- package/dist/config/config-schema.js +40 -13
- package/dist/config/config-schema.js.map +1 -1
- package/dist/config/config-validator.d.ts +6 -1
- package/dist/config/config-validator.d.ts.map +1 -1
- package/dist/config/config-validator.js +13 -2
- package/dist/config/config-validator.js.map +1 -1
- package/package.json +3 -3
- package/src/config/config-errors.ts +26 -1
- package/src/config/config-loader-static.ts +4 -4
- package/src/config/config-loader-utils.ts +8 -10
- package/src/config/config-loader.ts +97 -40
- package/src/config/config-schema.ts +44 -14
- package/src/config/config-validator.ts +25 -11
|
@@ -4,11 +4,11 @@ import chokidar from 'chokidar';
|
|
|
4
4
|
import semver from 'semver';
|
|
5
5
|
import _ from 'lodash';
|
|
6
6
|
|
|
7
|
-
import { ModelsSource, Field } from '@stackbit/types';
|
|
7
|
+
import { ModelsSource, Field, ModelExtension, FieldExtension, FieldType } from '@stackbit/types';
|
|
8
8
|
import { append, getFirstExistingFile, prepend, rename } from '@stackbit/utils';
|
|
9
9
|
|
|
10
|
-
import { ConfigValidationResult, validateConfig, validateContentModels } from './config-validator';
|
|
11
|
-
import { ConfigError, ConfigLoadError, ConfigValidationError,
|
|
10
|
+
import { ConfigValidationResult, validateBaseConfig, validateConfig, validateContentModels } from './config-validator';
|
|
11
|
+
import { ConfigError, ConfigLoadError, ModelLoadError, ConfigValidationError, StackbitConfigNotFoundError } from './config-errors';
|
|
12
12
|
import { loadStackbitConfigFromJs } from './config-loader-esbuild';
|
|
13
13
|
import {
|
|
14
14
|
assignLabelFieldIfNeeded,
|
|
@@ -65,14 +65,14 @@ export async function loadConfigWithModelsPresetsAndValidate({
|
|
|
65
65
|
stackbitConfigESBuildOutDir,
|
|
66
66
|
watchCallback: watchCallback
|
|
67
67
|
? async (configResult) => {
|
|
68
|
-
const configLoaderResult = await processConfigLoaderResult({ configResult, dirPath, modelsSource });
|
|
68
|
+
const configLoaderResult = await processConfigLoaderResult({ configResult, dirPath, modelsSource, logger });
|
|
69
69
|
watchCallback(configLoaderResult);
|
|
70
70
|
}
|
|
71
71
|
: undefined,
|
|
72
72
|
logger
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
-
const configLoaderResult = await processConfigLoaderResult({ configResult, dirPath, modelsSource });
|
|
75
|
+
const configLoaderResult = await processConfigLoaderResult({ configResult, dirPath, modelsSource, logger });
|
|
76
76
|
return {
|
|
77
77
|
...configLoaderResult,
|
|
78
78
|
stop: configResult.stop,
|
|
@@ -82,7 +82,7 @@ export async function loadConfigWithModelsPresetsAndValidate({
|
|
|
82
82
|
|
|
83
83
|
export type ConfigWithModelsResult = {
|
|
84
84
|
config: Config | null;
|
|
85
|
-
errors: (ConfigLoadError | ConfigValidationError)[];
|
|
85
|
+
errors: (ConfigLoadError | StackbitConfigNotFoundError | ModelLoadError | ConfigValidationError)[];
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
export async function loadConfigWithModels({
|
|
@@ -130,11 +130,11 @@ export async function loadConfigWithModels({
|
|
|
130
130
|
export type LoadConfigResult =
|
|
131
131
|
| {
|
|
132
132
|
config: Config;
|
|
133
|
-
errors:
|
|
133
|
+
errors: ConfigValidationError[];
|
|
134
134
|
}
|
|
135
135
|
| {
|
|
136
136
|
config: null;
|
|
137
|
-
errors: ConfigLoadError[];
|
|
137
|
+
errors: (ConfigLoadError | StackbitConfigNotFoundError)[];
|
|
138
138
|
};
|
|
139
139
|
|
|
140
140
|
export async function loadConfig({
|
|
@@ -156,11 +156,12 @@ export async function loadConfig({
|
|
|
156
156
|
};
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
const validationResult = validateBaseConfig(rawConfigResult.config);
|
|
160
160
|
const config = normalizeConfig(rawConfigResult.config);
|
|
161
|
+
|
|
161
162
|
return {
|
|
162
163
|
config: config,
|
|
163
|
-
errors:
|
|
164
|
+
errors: validationResult.errors
|
|
164
165
|
};
|
|
165
166
|
};
|
|
166
167
|
|
|
@@ -188,11 +189,13 @@ export async function loadConfig({
|
|
|
188
189
|
async function processConfigLoaderResult({
|
|
189
190
|
configResult,
|
|
190
191
|
dirPath,
|
|
191
|
-
modelsSource
|
|
192
|
+
modelsSource,
|
|
193
|
+
logger
|
|
192
194
|
}: {
|
|
193
195
|
configResult: ConfigWithModelsResult;
|
|
194
196
|
dirPath: string;
|
|
195
197
|
modelsSource?: ModelsSource;
|
|
198
|
+
logger?: Logger;
|
|
196
199
|
}): Promise<ConfigWithModelsPresetsResult> {
|
|
197
200
|
const { config, errors: configLoadErrors } = configResult;
|
|
198
201
|
|
|
@@ -206,7 +209,10 @@ async function processConfigLoaderResult({
|
|
|
206
209
|
|
|
207
210
|
const { models: externalModels, errors: externalModelsLoadErrors } = await loadModelsFromExternalSource(config, dirPath, modelsSource);
|
|
208
211
|
|
|
209
|
-
const mergedModels =
|
|
212
|
+
const mergedModels =
|
|
213
|
+
externalModels.length === 0
|
|
214
|
+
? config.models
|
|
215
|
+
: mergeConfigModelsWithExternalModels({ configModels: config.models as ModelExtension[], externalModels, logger });
|
|
210
216
|
const mergedConfig: Config = {
|
|
211
217
|
...config,
|
|
212
218
|
models: mergedModels
|
|
@@ -234,8 +240,8 @@ async function processConfigLoaderResult({
|
|
|
234
240
|
};
|
|
235
241
|
}
|
|
236
242
|
|
|
237
|
-
export async function loadAndMergeModelsFromFiles(config: Config): Promise<{ config: Config; errors: (
|
|
238
|
-
const { models: modelsFromFiles, errors:
|
|
243
|
+
export async function loadAndMergeModelsFromFiles(config: Config): Promise<{ config: Config; errors: (ModelLoadError | ConfigValidationError)[] }> {
|
|
244
|
+
const { models: modelsFromFiles, errors: modelLoadErrors } = await loadYamlModelsFromFiles(config);
|
|
239
245
|
const { models: mergedModels, errors: mergeModelErrors } = mergeConfigModelsWithModelsFromFiles(config.models, modelsFromFiles);
|
|
240
246
|
|
|
241
247
|
const extendedConfig: Config = {
|
|
@@ -245,7 +251,7 @@ export async function loadAndMergeModelsFromFiles(config: Config): Promise<{ con
|
|
|
245
251
|
|
|
246
252
|
return {
|
|
247
253
|
config: extendedConfig,
|
|
248
|
-
errors: [...
|
|
254
|
+
errors: [...modelLoadErrors, ...mergeModelErrors]
|
|
249
255
|
};
|
|
250
256
|
}
|
|
251
257
|
|
|
@@ -277,7 +283,7 @@ export type RawConfigLoaderResult =
|
|
|
277
283
|
}
|
|
278
284
|
| {
|
|
279
285
|
config: null;
|
|
280
|
-
error: ConfigLoadError;
|
|
286
|
+
error: ConfigLoadError | StackbitConfigNotFoundError;
|
|
281
287
|
};
|
|
282
288
|
|
|
283
289
|
export async function loadConfigFromDir({
|
|
@@ -397,7 +403,7 @@ export async function loadConfigFromDir({
|
|
|
397
403
|
|
|
398
404
|
return {
|
|
399
405
|
config: null,
|
|
400
|
-
error: new
|
|
406
|
+
error: new StackbitConfigNotFoundError()
|
|
401
407
|
};
|
|
402
408
|
}
|
|
403
409
|
|
|
@@ -405,7 +411,7 @@ async function loadModelsFromExternalSource(
|
|
|
405
411
|
config: Config,
|
|
406
412
|
dirPath: string,
|
|
407
413
|
modelsSource?: ModelsSource
|
|
408
|
-
): Promise<{ models: Model[]; errors:
|
|
414
|
+
): Promise<{ models: Model[]; errors: ModelLoadError[] }> {
|
|
409
415
|
modelsSource = _.assign({}, modelsSource, config.modelsSource);
|
|
410
416
|
const sourceType = _.get(modelsSource, 'type', 'files');
|
|
411
417
|
if (sourceType === 'files') {
|
|
@@ -424,13 +430,13 @@ async function loadModelsFromExternalSource(
|
|
|
424
430
|
} catch (error: any) {
|
|
425
431
|
return {
|
|
426
432
|
models: [],
|
|
427
|
-
errors: [new
|
|
433
|
+
errors: [new ModelLoadError(`Error fetching and converting Contentful schema, error: ${error.message}`, { originalError: error })]
|
|
428
434
|
};
|
|
429
435
|
}
|
|
430
436
|
}
|
|
431
437
|
return {
|
|
432
438
|
models: [],
|
|
433
|
-
errors: [new
|
|
439
|
+
errors: [new ModelLoadError(`modelsSource ${modelsSource} is unsupported`)]
|
|
434
440
|
};
|
|
435
441
|
}
|
|
436
442
|
|
|
@@ -468,10 +474,15 @@ async function loadConfigFromDotStackbit(dirPath: string) {
|
|
|
468
474
|
return _.isEmpty(config) ? null : config;
|
|
469
475
|
}
|
|
470
476
|
|
|
471
|
-
export function mergeConfigModelsWithExternalModels({
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
477
|
+
export function mergeConfigModelsWithExternalModels({
|
|
478
|
+
configModels,
|
|
479
|
+
externalModels,
|
|
480
|
+
logger
|
|
481
|
+
}: {
|
|
482
|
+
configModels: ModelExtension[];
|
|
483
|
+
externalModels: Model[];
|
|
484
|
+
logger?: Logger;
|
|
485
|
+
}): Model[] {
|
|
475
486
|
if (configModels.length === 0) {
|
|
476
487
|
return externalModels;
|
|
477
488
|
}
|
|
@@ -489,7 +500,18 @@ export function mergeConfigModelsWithExternalModels({ configModels, externalMode
|
|
|
489
500
|
let mergedModel: Model = Object.assign(
|
|
490
501
|
{},
|
|
491
502
|
externalModel,
|
|
492
|
-
_.pick(configModel, [
|
|
503
|
+
_.pick(configModel, [
|
|
504
|
+
'__metadata',
|
|
505
|
+
'urlPath',
|
|
506
|
+
'label',
|
|
507
|
+
'description',
|
|
508
|
+
'thumbnail',
|
|
509
|
+
'singleInstance',
|
|
510
|
+
'readOnly',
|
|
511
|
+
'labelField',
|
|
512
|
+
'fieldGroups',
|
|
513
|
+
'localized'
|
|
514
|
+
]),
|
|
493
515
|
{ type: modelType }
|
|
494
516
|
);
|
|
495
517
|
|
|
@@ -500,31 +522,66 @@ export function mergeConfigModelsWithExternalModels({ configModels, externalMode
|
|
|
500
522
|
mergedModel = mapModelFieldsRecursively(
|
|
501
523
|
mergedModel,
|
|
502
524
|
(externalField, modelKeyPath): Field => {
|
|
503
|
-
const stackbitField = getModelFieldForModelKeyPath(configModel, modelKeyPath);
|
|
525
|
+
const stackbitField = getModelFieldForModelKeyPath(configModel as Model, modelKeyPath) as FieldExtension;
|
|
504
526
|
if (!stackbitField) {
|
|
505
527
|
return externalField;
|
|
506
528
|
}
|
|
507
529
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
530
|
+
const FieldRemapMatrix: Record<string, FieldType[]> = {
|
|
531
|
+
string: ['text', 'html', 'markdown', 'slug', 'url', 'color', 'date', 'datetime', 'enum', 'json', 'style'],
|
|
532
|
+
text: ['html', 'markdown', 'json', 'style'],
|
|
533
|
+
json: ['style']
|
|
534
|
+
};
|
|
535
|
+
|
|
536
|
+
// override field type if allowed, otherwise show a warning message
|
|
537
|
+
let fieldType: FieldType = externalField.type;
|
|
538
|
+
const allowedOverrideTypes = FieldRemapMatrix[externalField.type];
|
|
539
|
+
if (stackbitField.type && stackbitField.type !== externalField.type) {
|
|
540
|
+
if (allowedOverrideTypes && allowedOverrideTypes.includes(stackbitField.type)) {
|
|
541
|
+
fieldType = stackbitField.type;
|
|
542
|
+
} else {
|
|
543
|
+
logger?.warn(
|
|
544
|
+
`Can't remap field of model '${mergedModel.name}' at path ${modelKeyPath}' ` +
|
|
545
|
+
`from ${externalField.type}' type to '${stackbitField.type}' type. ` +
|
|
546
|
+
`'${externalField.type}' fields can be only mapped to ` +
|
|
547
|
+
(!allowedOverrideTypes
|
|
548
|
+
? 'the same type.'
|
|
549
|
+
: allowedOverrideTypes.length === 1
|
|
550
|
+
? `'${allowedOverrideTypes[0]}' type`
|
|
551
|
+
: `one of [${allowedOverrideTypes.join(', ')}] types.`)
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// add field specific properties
|
|
557
|
+
let fieldSpecificProps = {};
|
|
558
|
+
switch (fieldType) {
|
|
559
|
+
case 'number':
|
|
560
|
+
fieldSpecificProps = _.pick(stackbitField, ['subtype', 'min', 'max', 'step', 'unit']);
|
|
561
|
+
break;
|
|
562
|
+
case 'enum':
|
|
563
|
+
fieldSpecificProps = _.pick(stackbitField, ['options']);
|
|
564
|
+
break;
|
|
565
|
+
case 'style':
|
|
566
|
+
fieldSpecificProps = _.pick(stackbitField, ['styles']);
|
|
567
|
+
break;
|
|
568
|
+
case 'object':
|
|
569
|
+
fieldSpecificProps = _.pick(stackbitField, ['labelField', 'thumbnail', 'fieldGroups']);
|
|
570
|
+
break;
|
|
571
|
+
case 'model':
|
|
572
|
+
fieldSpecificProps = _.pick(stackbitField, ['models']);
|
|
573
|
+
break;
|
|
574
|
+
case 'reference':
|
|
575
|
+
fieldSpecificProps = _.pick(stackbitField, ['models']);
|
|
576
|
+
break;
|
|
521
577
|
}
|
|
522
578
|
|
|
523
579
|
return Object.assign(
|
|
524
580
|
{},
|
|
525
581
|
externalField,
|
|
526
582
|
_.pick(stackbitField, ['label', 'description', 'required', 'default', 'group', 'const', 'hidden', 'readOnly', 'controlType']),
|
|
527
|
-
|
|
583
|
+
fieldSpecificProps,
|
|
584
|
+
{ type: fieldType }
|
|
528
585
|
);
|
|
529
586
|
}
|
|
530
587
|
);
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
import { CMS_NAMES, FIELD_TYPES, SSG_NAMES } from './config-consts';
|
|
23
23
|
import { styleFieldPartialSchema } from './config-schema/style-field-schema';
|
|
24
24
|
import { Config, Model, PageModel, ObjectModel, DataModel, ConfigModel } from './config-types';
|
|
25
|
+
import { RawConfigWithPaths } from './config-loader-utils';
|
|
25
26
|
|
|
26
27
|
function getConfigFromValidationState(state: Joi.State): Config {
|
|
27
28
|
return _.last(state.ancestors)!;
|
|
@@ -139,12 +140,6 @@ function getModelNamesForGroup(group: string, config: Config) {
|
|
|
139
140
|
);
|
|
140
141
|
}
|
|
141
142
|
|
|
142
|
-
const logicField = Joi.string();
|
|
143
|
-
// TODO: validate that all logicFields reference existing fields
|
|
144
|
-
// const logicField = Joi.custom((value) => {
|
|
145
|
-
// return value;
|
|
146
|
-
// });
|
|
147
|
-
|
|
148
143
|
const labelFieldNotFoundError = 'labelField.not.found';
|
|
149
144
|
const labelFieldNotSimple = 'labelField.not.simple';
|
|
150
145
|
const labelFieldSchema = Joi.custom((value, { error, state }) => {
|
|
@@ -645,7 +640,7 @@ const fieldNameUnique = 'field.name.unique';
|
|
|
645
640
|
function errorLabelFromModelAndFieldPath(model: Model, modelIndex: number, fieldPath: (string | number | object)[]): string {
|
|
646
641
|
let fieldSpecificProps: Model | FieldSpecificProps | undefined = model;
|
|
647
642
|
let fields: Field[] | undefined;
|
|
648
|
-
let label = `models[${
|
|
643
|
+
let label = `models[${model.name ? `name='${model.name}'` : modelIndex}]`;
|
|
649
644
|
|
|
650
645
|
for (const pathPart of fieldPath) {
|
|
651
646
|
if (typeof pathPart === 'string') {
|
|
@@ -815,11 +810,14 @@ const sidebarButtonSchema = Joi.object({
|
|
|
815
810
|
]
|
|
816
811
|
});
|
|
817
812
|
|
|
818
|
-
export const
|
|
813
|
+
export const stackbitConfigBaseSchema = Joi.object<RawConfigWithPaths>({
|
|
819
814
|
stackbitVersion: Joi.string().required(),
|
|
820
815
|
ssgName: Joi.string().valid(...SSG_NAMES),
|
|
821
816
|
ssgVersion: Joi.string(),
|
|
822
817
|
nodeVersion: Joi.string(),
|
|
818
|
+
postGitCloneCommand: Joi.string(),
|
|
819
|
+
preInstallCommand: Joi.string(),
|
|
820
|
+
postInstallCommand: Joi.string(),
|
|
823
821
|
devCommand: Joi.string(),
|
|
824
822
|
cmsName: Joi.string().valid(...CMS_NAMES),
|
|
825
823
|
import: importSchema,
|
|
@@ -832,17 +830,41 @@ export const stackbitConfigSchema = Joi.object<Config>({
|
|
|
832
830
|
dataDir: Joi.string().allow('', null),
|
|
833
831
|
pageLayoutKey: Joi.string().allow(null),
|
|
834
832
|
objectTypeKey: Joi.string(),
|
|
835
|
-
styleObjectModelName: styleObjectModelNameSchema,
|
|
836
833
|
excludePages: Joi.array().items(Joi.string()).single(),
|
|
837
|
-
|
|
834
|
+
styleObjectModelName: Joi.string(),
|
|
835
|
+
logicFields: Joi.array().items(Joi.string()),
|
|
838
836
|
contentModels: Joi.any(), // contentModels should have been already validated by now
|
|
839
|
-
sidebarButtons: Joi.array().items(sidebarButtonSchema),
|
|
840
837
|
presetSource: presetSourceSchema,
|
|
841
838
|
modelsSource: modelsSourceSchema,
|
|
842
|
-
|
|
839
|
+
sidebarButtons: Joi.array().items(sidebarButtonSchema),
|
|
840
|
+
models: Joi.any(),
|
|
841
|
+
modelExtensions: Joi.array().items(Joi.any()),
|
|
842
|
+
presetReferenceBehavior: Joi.string().valid('copyReference', 'duplicateContents'),
|
|
843
|
+
nonDuplicatableModels: Joi.array().items(Joi.string()).when('presetReferenceBehavior', {
|
|
844
|
+
is: 'copyReference',
|
|
845
|
+
then: Joi.forbidden()
|
|
846
|
+
}),
|
|
847
|
+
duplicatableModels: Joi.array().items(Joi.string()).when('presetReferenceBehavior', {
|
|
848
|
+
is: 'duplicateContents',
|
|
849
|
+
then: Joi.forbidden()
|
|
850
|
+
}),
|
|
851
|
+
customContentReload: Joi.boolean(),
|
|
852
|
+
experimental: Joi.any(),
|
|
853
|
+
contentSources: Joi.array().items(Joi.any()),
|
|
854
|
+
siteMap: Joi.function(),
|
|
855
|
+
mapModels: Joi.function(),
|
|
856
|
+
// internal properties added by load
|
|
857
|
+
dirPath: Joi.string(),
|
|
858
|
+
filePath: Joi.string()
|
|
843
859
|
})
|
|
844
|
-
.unknown(true)
|
|
845
860
|
.without('assets', ['staticDir', 'uploadDir'])
|
|
861
|
+
.without('contentSources', ['cmsName', 'assets', 'contentModels', 'modelsSource'])
|
|
862
|
+
.when('.modelExtensions', {
|
|
863
|
+
is: Joi.exist(),
|
|
864
|
+
then: Joi.object({
|
|
865
|
+
models: Joi.forbidden()
|
|
866
|
+
})
|
|
867
|
+
})
|
|
846
868
|
.when('.cmsName', {
|
|
847
869
|
is: ['contentful', 'sanity'],
|
|
848
870
|
then: Joi.object({
|
|
@@ -853,5 +875,13 @@ export const stackbitConfigSchema = Joi.object<Config>({
|
|
|
853
875
|
dataDir: Joi.forbidden(),
|
|
854
876
|
excludePages: Joi.forbidden()
|
|
855
877
|
})
|
|
878
|
+
});
|
|
879
|
+
|
|
880
|
+
export const stackbitConfigFullSchema = stackbitConfigBaseSchema.concat(
|
|
881
|
+
Joi.object<Config>({
|
|
882
|
+
styleObjectModelName: styleObjectModelNameSchema,
|
|
883
|
+
models: modelsSchema
|
|
856
884
|
})
|
|
857
|
-
|
|
885
|
+
.unknown(true)
|
|
886
|
+
.shared(fieldsSchema)
|
|
887
|
+
);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import _ from 'lodash';
|
|
2
2
|
import Joi from 'joi';
|
|
3
|
-
import { ContentModelMap } from '@stackbit/types';
|
|
3
|
+
import { ContentModelMap, StackbitConfig } from '@stackbit/types';
|
|
4
4
|
|
|
5
|
-
import { contentModelsSchema,
|
|
5
|
+
import { contentModelsSchema, stackbitConfigBaseSchema, stackbitConfigFullSchema } from './config-schema';
|
|
6
6
|
import { ConfigValidationError } from './config-errors';
|
|
7
7
|
import { Config, Model } from './config-types';
|
|
8
8
|
|
|
@@ -12,9 +12,26 @@ export interface ConfigValidationResult {
|
|
|
12
12
|
errors: ConfigValidationError[];
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export function validateBaseConfig(
|
|
16
|
+
config: StackbitConfig
|
|
17
|
+
): {
|
|
18
|
+
config: StackbitConfig;
|
|
19
|
+
valid: boolean;
|
|
20
|
+
errors: ConfigValidationError[];
|
|
21
|
+
} {
|
|
22
|
+
const validationOptions = { abortEarly: false, context: { config: config } };
|
|
23
|
+
const validationResult = stackbitConfigBaseSchema.validate(config, validationOptions);
|
|
24
|
+
const errors = mapJoiErrorsToConfigValidationErrors(validationResult);
|
|
25
|
+
return {
|
|
26
|
+
config: validationResult.value,
|
|
27
|
+
valid: _.isEmpty(errors),
|
|
28
|
+
errors
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
15
32
|
export function validateConfig(config: Config): ConfigValidationResult {
|
|
16
33
|
const validationOptions = { abortEarly: false, context: { config: config } };
|
|
17
|
-
const validationResult =
|
|
34
|
+
const validationResult = stackbitConfigFullSchema.validate(config, validationOptions);
|
|
18
35
|
const validatedConfig: Config = validationResult.value;
|
|
19
36
|
const errors = mapJoiErrorsToConfigValidationErrors(validationResult);
|
|
20
37
|
const valid = _.isEmpty(errors);
|
|
@@ -41,15 +58,12 @@ export interface ContentModelsValidationResult {
|
|
|
41
58
|
export function validateContentModels(contentModels: ContentModelMap, models: Model[]): ContentModelsValidationResult {
|
|
42
59
|
const modelMap: Record<string, Model> = _.keyBy(models, 'name');
|
|
43
60
|
const config = { contentModels: contentModels };
|
|
44
|
-
const validationResult = contentModelsSchema.validate(
|
|
45
|
-
|
|
46
|
-
{
|
|
47
|
-
|
|
48
|
-
context: {
|
|
49
|
-
modelMap: modelMap
|
|
50
|
-
}
|
|
61
|
+
const validationResult = contentModelsSchema.validate(config, {
|
|
62
|
+
abortEarly: false,
|
|
63
|
+
context: {
|
|
64
|
+
modelMap: modelMap
|
|
51
65
|
}
|
|
52
|
-
);
|
|
66
|
+
});
|
|
53
67
|
const validatedConfig: Config = validationResult.value;
|
|
54
68
|
const errors = mapJoiErrorsToConfigValidationErrors(validationResult);
|
|
55
69
|
const valid = _.isEmpty(errors);
|