@stackbit/sdk 2.0.8-staging.1 → 2.0.8-staging.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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/config/config-loader.d.ts.map +1 -1
- package/dist/config/config-loader.js +34 -1
- package/dist/config/config-loader.js.map +1 -1
- package/dist/config/config-schema.d.ts.map +1 -1
- package/dist/config/config-schema.js +70 -14
- package/dist/config/config-schema.js.map +1 -1
- package/package.json +4 -4
- package/src/config/config-loader.ts +41 -1
- package/src/config/config-schema.ts +78 -14
|
@@ -4,6 +4,7 @@ import chokidar from 'chokidar';
|
|
|
4
4
|
import semver from 'semver';
|
|
5
5
|
import _ from 'lodash';
|
|
6
6
|
|
|
7
|
+
import * as StackbitTypes from '@stackbit/types';
|
|
7
8
|
import {
|
|
8
9
|
ModelsSource,
|
|
9
10
|
Field,
|
|
@@ -697,7 +698,9 @@ export function mergeConfigModelsWithExternalModels({
|
|
|
697
698
|
break;
|
|
698
699
|
}
|
|
699
700
|
|
|
700
|
-
|
|
701
|
+
const validations = mergeFieldValidations(externalFieldProps, stackbitFieldProps);
|
|
702
|
+
|
|
703
|
+
return Object.assign({}, externalFieldProps, fieldSpecificProps, { type: fieldType }, validations ? { validations } : undefined);
|
|
701
704
|
});
|
|
702
705
|
|
|
703
706
|
const mergedField = Object.assign(
|
|
@@ -718,6 +721,14 @@ export function mergeConfigModelsWithExternalModels({
|
|
|
718
721
|
])
|
|
719
722
|
);
|
|
720
723
|
|
|
724
|
+
// Merge list field specific properties that weren't merged in mapListItemsPropsOrSelfSpecificProps
|
|
725
|
+
if (externalField.type === 'list') {
|
|
726
|
+
const validations = mergeFieldValidations(externalField, stackbitField);
|
|
727
|
+
if (validations) {
|
|
728
|
+
mergedField.validations = validations;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
|
|
721
732
|
const externalActions = 'actions' in externalField && Array.isArray(externalField.actions) ? externalField.actions : [];
|
|
722
733
|
const configActions = 'actions' in stackbitField && Array.isArray(stackbitField.actions) ? stackbitField.actions : [];
|
|
723
734
|
if (externalActions.length || configActions.length) {
|
|
@@ -733,6 +744,35 @@ export function mergeConfigModelsWithExternalModels({
|
|
|
733
744
|
return Object.values(mergedModelsByName);
|
|
734
745
|
}
|
|
735
746
|
|
|
747
|
+
function mergeFieldValidations<T extends StackbitTypes.FieldSpecificProps>(
|
|
748
|
+
externalFieldProps: T,
|
|
749
|
+
stackbitFieldProps: FieldExtension | DistributePartialListItems<FieldListItems>
|
|
750
|
+
): T['validations'] {
|
|
751
|
+
const externalFieldValidations = externalFieldProps.validations;
|
|
752
|
+
const configFieldValidation = stackbitFieldProps.validations;
|
|
753
|
+
if (externalFieldValidations && configFieldValidation) {
|
|
754
|
+
const extendedValidations: StackbitTypes.FieldValidationsCustom = {};
|
|
755
|
+
// concatenate custom validation functions
|
|
756
|
+
if (
|
|
757
|
+
'validate' in externalFieldValidations &&
|
|
758
|
+
externalFieldValidations.validate &&
|
|
759
|
+
'validate' in configFieldValidation &&
|
|
760
|
+
configFieldValidation.validate
|
|
761
|
+
) {
|
|
762
|
+
const externalFileTypes = Array.isArray(externalFieldValidations.validate)
|
|
763
|
+
? externalFieldValidations.validate
|
|
764
|
+
: [externalFieldValidations.validate];
|
|
765
|
+
const stackbitFileTypes = Array.isArray(configFieldValidation.validate) ? configFieldValidation.validate : [configFieldValidation.validate];
|
|
766
|
+
extendedValidations.validate = [...externalFileTypes, ...stackbitFileTypes];
|
|
767
|
+
}
|
|
768
|
+
return Object.assign({}, externalFieldValidations, configFieldValidation, extendedValidations);
|
|
769
|
+
} else if (configFieldValidation) {
|
|
770
|
+
return configFieldValidation;
|
|
771
|
+
} else {
|
|
772
|
+
return externalFieldValidations;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
736
776
|
function normalizeConfig(rawConfig: StackbitConfigWithPaths): Config {
|
|
737
777
|
const stackbitVersion = String(_.get(rawConfig, 'stackbitVersion', LATEST_STACKBIT_VERSION));
|
|
738
778
|
const ver = semver.coerce(stackbitVersion);
|
|
@@ -34,6 +34,8 @@ function getModelsFromValidationState(state: Joi.State): Model[] {
|
|
|
34
34
|
return config.models ?? [];
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
const arrayOfStrings = Joi.array().items(Joi.string());
|
|
38
|
+
|
|
37
39
|
const fieldNamePattern = /^[a-zA-Z0-9_$]([a-zA-Z0-9_-]*[a-zA-Z0-9])?$/;
|
|
38
40
|
const fieldNameError =
|
|
39
41
|
'Invalid field name "{{#value}}" at "{{#label}}". A field name must contain only alphanumeric characters, ' +
|
|
@@ -265,7 +267,7 @@ const importSchema = Joi.alternatives().conditional('.type', {
|
|
|
265
267
|
|
|
266
268
|
const presetSourceFilesSchema = Joi.object<PresetSourceFiles>({
|
|
267
269
|
type: Joi.string().valid(Joi.override, 'files').required(),
|
|
268
|
-
presetDirs:
|
|
270
|
+
presetDirs: arrayOfStrings.required()
|
|
269
271
|
});
|
|
270
272
|
|
|
271
273
|
const presetSourceSchema = Joi.object<PresetSource>({
|
|
@@ -276,7 +278,7 @@ const presetSourceSchema = Joi.object<PresetSource>({
|
|
|
276
278
|
|
|
277
279
|
const modelsSourceFilesSchema = Joi.object<ModelsSourceFiles>({
|
|
278
280
|
type: Joi.string().valid(Joi.override, 'files').required(),
|
|
279
|
-
modelDirs:
|
|
281
|
+
modelDirs: arrayOfStrings.required()
|
|
280
282
|
});
|
|
281
283
|
|
|
282
284
|
const modelsSourceContentfulSchema = Joi.object<ModelsSourceContentful>({
|
|
@@ -400,6 +402,67 @@ const customActionFieldSchema = customActionBaseSchema.concat(
|
|
|
400
402
|
})
|
|
401
403
|
);
|
|
402
404
|
|
|
405
|
+
const stringOrNumber = Joi.alternatives().try(Joi.string(), Joi.number());
|
|
406
|
+
|
|
407
|
+
const fieldValidationSchema = Joi.object({
|
|
408
|
+
unique: Joi.boolean(),
|
|
409
|
+
validate: Joi.alternatives().try(Joi.function(), Joi.array().items(Joi.function())),
|
|
410
|
+
|
|
411
|
+
// string and text
|
|
412
|
+
regexp: Joi.string(),
|
|
413
|
+
regexpNot: Joi.string(),
|
|
414
|
+
regexpPattern: Joi.string(),
|
|
415
|
+
|
|
416
|
+
// ranges
|
|
417
|
+
min: stringOrNumber,
|
|
418
|
+
max: stringOrNumber,
|
|
419
|
+
after: Joi.string(),
|
|
420
|
+
before: Joi.string(),
|
|
421
|
+
exact: Joi.number(),
|
|
422
|
+
step: Joi.number(),
|
|
423
|
+
lessThan: Joi.number(),
|
|
424
|
+
greaterThan: Joi.number(),
|
|
425
|
+
|
|
426
|
+
// file
|
|
427
|
+
fileMinSize: Joi.number(),
|
|
428
|
+
fileMaxSize: Joi.number(),
|
|
429
|
+
fileTypes: arrayOfStrings,
|
|
430
|
+
fileTypeGroups: arrayOfStrings,
|
|
431
|
+
|
|
432
|
+
// image
|
|
433
|
+
minWidth: Joi.number(),
|
|
434
|
+
maxWidth: Joi.number(),
|
|
435
|
+
minHeight: Joi.number(),
|
|
436
|
+
maxHeight: Joi.number(),
|
|
437
|
+
minWidthToHeightRatio: stringOrNumber,
|
|
438
|
+
maxWidthToHeightRatio: stringOrNumber,
|
|
439
|
+
|
|
440
|
+
errors: Joi.object({
|
|
441
|
+
unique: Joi.string(),
|
|
442
|
+
regexp: Joi.string(),
|
|
443
|
+
regexpNot: Joi.string(),
|
|
444
|
+
regexpPattern: Joi.string(),
|
|
445
|
+
min: Joi.string(),
|
|
446
|
+
max: Joi.string(),
|
|
447
|
+
after: Joi.string(),
|
|
448
|
+
before: Joi.string(),
|
|
449
|
+
exact: Joi.string(),
|
|
450
|
+
step: Joi.string(),
|
|
451
|
+
lessThan: Joi.string(),
|
|
452
|
+
greaterThan: Joi.string(),
|
|
453
|
+
fileMinSize: Joi.string(),
|
|
454
|
+
fileMaxSize: Joi.string(),
|
|
455
|
+
fileTypes: Joi.string(),
|
|
456
|
+
fileTypeGroups: Joi.string(),
|
|
457
|
+
minWidth: Joi.string(),
|
|
458
|
+
maxWidth: Joi.string(),
|
|
459
|
+
minHeight: Joi.string(),
|
|
460
|
+
maxHeight: Joi.string(),
|
|
461
|
+
minWidthToHeightRatio: Joi.string(),
|
|
462
|
+
maxWidthToHeightRatio: Joi.string()
|
|
463
|
+
})
|
|
464
|
+
});
|
|
465
|
+
|
|
403
466
|
const customControlTypesSchema = Joi.string().valid('custom-modal-html', 'custom-inline-html', 'custom-modal-script', 'custom-inline-script');
|
|
404
467
|
const fieldCommonPropsSchema = Joi.object({
|
|
405
468
|
type: Joi.string()
|
|
@@ -409,6 +472,7 @@ const fieldCommonPropsSchema = Joi.object({
|
|
|
409
472
|
label: Joi.string(),
|
|
410
473
|
description: Joi.string().allow(''),
|
|
411
474
|
required: Joi.boolean(),
|
|
475
|
+
validations: fieldValidationSchema,
|
|
412
476
|
default: Joi.any(),
|
|
413
477
|
group: inGroups,
|
|
414
478
|
const: Joi.any(),
|
|
@@ -474,7 +538,7 @@ const enumFieldPartialSchema = Joi.object({
|
|
|
474
538
|
is: 'palette-colors',
|
|
475
539
|
then: Joi.array().items(
|
|
476
540
|
enumFieldBaseOptionSchema.append({
|
|
477
|
-
colors:
|
|
541
|
+
colors: arrayOfStrings.required()
|
|
478
542
|
})
|
|
479
543
|
)
|
|
480
544
|
}
|
|
@@ -589,8 +653,8 @@ const contentModelSchema = Joi.object<ContentModel>({
|
|
|
589
653
|
singleInstance: Joi.boolean(),
|
|
590
654
|
file: Joi.string(),
|
|
591
655
|
folder: Joi.string(),
|
|
592
|
-
match:
|
|
593
|
-
exclude:
|
|
656
|
+
match: arrayOfStrings.single(),
|
|
657
|
+
exclude: arrayOfStrings.single()
|
|
594
658
|
})
|
|
595
659
|
.without('file', ['folder', 'match', 'exclude'])
|
|
596
660
|
.when('.isPage', {
|
|
@@ -667,7 +731,7 @@ const baseModelSchema = {
|
|
|
667
731
|
readOnly: Joi.boolean(),
|
|
668
732
|
labelField: labelFieldSchema,
|
|
669
733
|
variantField: variantFieldSchema,
|
|
670
|
-
groups:
|
|
734
|
+
groups: arrayOfStrings,
|
|
671
735
|
context: Joi.any(),
|
|
672
736
|
preview: Joi.alternatives().try(objectPreviewSchema, Joi.function()),
|
|
673
737
|
fieldGroups: fieldGroupsSchema,
|
|
@@ -695,8 +759,8 @@ const dataModelSchema: Joi.ObjectSchema<DataModel & { srcType: string; srcProjec
|
|
|
695
759
|
singleInstance: Joi.boolean(),
|
|
696
760
|
file: Joi.string(),
|
|
697
761
|
folder: Joi.string(),
|
|
698
|
-
match:
|
|
699
|
-
exclude:
|
|
762
|
+
match: arrayOfStrings.single(),
|
|
763
|
+
exclude: arrayOfStrings.single(),
|
|
700
764
|
isList: Joi.boolean()
|
|
701
765
|
})
|
|
702
766
|
.when('.isList', {
|
|
@@ -733,8 +797,8 @@ const pageModelSchema: Joi.ObjectSchema<PageModel & { srcType: string; srcProjec
|
|
|
733
797
|
singleInstance: Joi.boolean(),
|
|
734
798
|
file: Joi.string(),
|
|
735
799
|
folder: Joi.string(),
|
|
736
|
-
match:
|
|
737
|
-
exclude:
|
|
800
|
+
match: arrayOfStrings.single(),
|
|
801
|
+
exclude: arrayOfStrings.single(),
|
|
738
802
|
hideContent: Joi.boolean()
|
|
739
803
|
})
|
|
740
804
|
.when('.file', {
|
|
@@ -983,9 +1047,9 @@ export const stackbitConfigBaseSchema = Joi.object<StackbitConfigWithPaths>({
|
|
|
983
1047
|
dataDir: Joi.string().allow('', null),
|
|
984
1048
|
pageLayoutKey: Joi.string().allow(null),
|
|
985
1049
|
objectTypeKey: Joi.string(),
|
|
986
|
-
excludePages:
|
|
1050
|
+
excludePages: arrayOfStrings.single(),
|
|
987
1051
|
styleObjectModelName: Joi.string(),
|
|
988
|
-
logicFields:
|
|
1052
|
+
logicFields: arrayOfStrings,
|
|
989
1053
|
contentModels: Joi.any(), // contentModels should have been already validated by now
|
|
990
1054
|
presetSource: presetSourceSchema,
|
|
991
1055
|
modelsSource: modelsSourceSchema,
|
|
@@ -995,11 +1059,11 @@ export const stackbitConfigBaseSchema = Joi.object<StackbitConfigWithPaths>({
|
|
|
995
1059
|
models: Joi.any(),
|
|
996
1060
|
modelExtensions: Joi.array().items(Joi.any()),
|
|
997
1061
|
presetReferenceBehavior: Joi.string().valid('copyReference', 'duplicateContents'),
|
|
998
|
-
nonDuplicatableModels:
|
|
1062
|
+
nonDuplicatableModels: arrayOfStrings.when('presetReferenceBehavior', {
|
|
999
1063
|
is: 'copyReference',
|
|
1000
1064
|
then: Joi.forbidden()
|
|
1001
1065
|
}),
|
|
1002
|
-
duplicatableModels:
|
|
1066
|
+
duplicatableModels: arrayOfStrings.when('presetReferenceBehavior', {
|
|
1003
1067
|
is: 'duplicateContents',
|
|
1004
1068
|
then: Joi.forbidden()
|
|
1005
1069
|
}),
|