UNPKG

contentful-migration

Version:
377 lines 16 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateTag = exports.validateFields = exports.validateEditorInterface = exports.validateContentType = void 0; const _ = __importStar(require("lodash")); const hoek_1 = require("@hapi/hoek"); const kind_of_1 = __importDefault(require("kind-of")); const errors_1 = __importDefault(require("../errors")); const content_type_schema_1 = require("./content-type-schema"); const tag_schema_1 = require("./tag-schema"); const fields_schema_1 = require("./fields-schema"); const editor_layout_schema_1 = require("./editor-layout-schema"); const validateContentType = function (contentType) { const contentTypeId = contentType.id; const { error } = content_type_schema_1.contentTypeSchema.validate(_.omit(contentType.toAPI(), ['sys']), { abortEarly: false }); if (!error) { return []; } return error.details.map(({ path, type }) => { if (type === 'any.required') { return { type: 'InvalidPayload', message: errors_1.default.contentType.REQUIRED_PROPERTY(path) }; } if (type === 'array.max' && path[0] === 'fields' && path.length === 1) { return { type: 'InvalidPayload', message: errors_1.default.contentType.TOO_MANY_FIELDS(contentTypeId, content_type_schema_1.MAX_FIELDS) }; } }); }; exports.validateContentType = validateContentType; const validateEditorInterface = function (editorInterface) { const groupControls = editorInterface.getGroupControls() || []; const tabsIds = groupControls .filter((control) => control.widgetNamespace === 'builtin' && control.widgetId === 'topLevelTab') .map((control) => control.groupId); const validateResult = (0, editor_layout_schema_1.createEditorLayoutSchema)(tabsIds).validate(editorInterface.getEditorLayout(), { abortEarly: false }); const { error } = validateResult; if (!error) { return []; } return error.details.map((err) => { if (err.type === 'array.max' && err.path.length === 0) { return { type: 'InvalidPayload', message: errors_1.default.editorLayout.TOO_MANY_TABS() }; } if (err.type === 'any.only') { return { type: 'InvalidPayload', message: errors_1.default.editorLayout.TAB_CONTROL_INVALID(err.context.value) }; } if (err.type === 'any.invalid') { return { type: 'InvalidPayload', message: errors_1.default.editorLayout.FIELD_SET_CONTROL_INVALID(err.context.value) }; } if (err.type === 'any.required') { return { type: 'InvalidPayload', message: errors_1.default.editorLayout.FIELD_GROUP_LEVEL_TOO_DEEP() }; } }); }; exports.validateEditorInterface = validateEditorInterface; const validateTag = function (tag) { const { error } = tag_schema_1.tagSchema.validate(_.omit(tag.toApiTag(), ['sys']), { abortEarly: false }); if (!error) { return []; } return error.details.map(({ path, type }) => { if (type === 'any.required') { return { type: 'InvalidPayload', message: errors_1.default.tag.REQUIRED_PROPERTY(path) }; } }); }; exports.validateTag = validateTag; const unknownCombinationError = function ({ path, keys }) { const type = 'object.unknownCombination'; const message = `"${keys.join()}" is not allowed`; const context = { keys }; return { message, path, type, context }; }; // Receives ValidationError[] with this structure: // [{ // message: '"foo" is not allowed', // path: [0, 'validations', 2, 'foo'], // type: 'object.allowUnknown', // context: { child: 'foo', key: 'foo' } // }] const combineErrors = function (fieldValidationsError) { const fieldValidationsErrors = fieldValidationsError.context.details; const byItemPath = _.groupBy(fieldValidationsErrors, ({ path }) => { return path.slice(0, -1).join('.'); }); // Remove object.unknown error for alternatives.match field validation if there are deeper nested validation errors if (fieldValidationsError.type === 'alternatives.match' && Object.keys(byItemPath).length > 1) { const alternativesMatchErrorPath = fieldValidationsError.path.join('.'); delete byItemPath[alternativesMatchErrorPath]; } const pathErrorTuples = _.entries(byItemPath); const uniqPropErrorsByPath = _.map(pathErrorTuples, ([path, itemErrors]) => { const uniqErrors = _.uniqBy(itemErrors, 'context.key'); return [path, uniqErrors]; }); return uniqPropErrorsByPath.map(([path, errors]) => { const keys = errors.map((error) => (0, hoek_1.reach)(error, 'context.key')); // Invalid property if (keys.length === 1) { const [errorSample] = errors; return errorSample; } // Invalid combined properties return unknownCombinationError({ path: path.split('.'), keys }); }); }; // Joi might return an `object.unknown` error for each // non-matched field validation in `Joi.alternatives.try()`. // They are noise, execept when all error types are the same. const cleanNoiseFromJoiErrors = function (error) { const [normalErrors, fieldValidationsErrors] = _.partition(error.details, (detail) => { const [, fieldProp] = detail.path; return fieldProp !== 'validations'; }); if (!fieldValidationsErrors.length) { return normalErrors; } let allErrors = [...normalErrors]; for (const fieldValidationsError of fieldValidationsErrors) { const errorDetails = fieldValidationsError.context.details; if (!errorDetails) { allErrors = [...allErrors, fieldValidationsError]; continue; } const isUnknownValidationsProp = errorDetails.every(({ type }) => type === 'object.unknown'); if (isUnknownValidationsProp) { const combinedErrors = combineErrors(fieldValidationsError); allErrors = [...allErrors, ...combinedErrors]; continue; } const remainingFieldValidationsErrors = errorDetails.filter(({ type }) => type !== 'object.unknown'); allErrors = [...allErrors, ...remainingFieldValidationsErrors]; } return allErrors; }; const validateFields = function (contentType, locales) { const fields = contentType.fields.toRaw(); const validateResult = (0, fields_schema_1.createFieldsSchema)(locales).validate(fields, { abortEarly: false }); const { error } = validateResult; if (!error) { return []; } const cleanErrors = cleanNoiseFromJoiErrors(error); return cleanErrors.map((details) => { const { path, type, context } = details; // `path` looks like [0, 'field'] // look up the field const [index, ...fieldNames] = path; const prop = fieldNames.join('.'); const field = fields[index]; if (prop.startsWith('defaultValue')) { if (type === 'object.unknown') { return { type: 'InvalidPayload', message: errors_1.default.field.defaultValue.INVALID_LOCALE(field.id, context.key) }; } if (type === 'any.unknown') { if (field.type === 'Array') { return { type: 'InvalidPayload', message: errors_1.default.field.defaultValue.UNSUPPORTED_ARRAY_ITEMS_TYPE(field.id, path[1], field.items.type) }; } return { type: 'InvalidPayload', message: errors_1.default.field.defaultValue.UNSUPPORTED_FIELD_TYPE(field.id, path[1], field.type) }; } if (field.type === 'Date') { return { type: 'InvalidPayload', message: errors_1.default.field.defaultValue.DATE_TYPE_MISMATCH(field.id, (0, kind_of_1.default)(context.value), context.value, context.key, field.type) }; } return { type: 'InvalidPayload', message: errors_1.default.field.defaultValue.TYPE_MISMATCH(field.id, (0, kind_of_1.default)(context.value), context.key, field.type) }; } // Field `allowedResources` errors if (prop.startsWith('allowedResources')) { if (path.length > 3) { const error = details.message.replace(/".+?"/, `"${context.key}"`); return { type: 'InvalidPayload', message: errors_1.default.allowedResources.INVALID_RESOURCE_PROPERTY(field.id, path[2], error) }; } if (type === 'object.base') { const actualType = (0, kind_of_1.default)((0, hoek_1.reach)(field, prop)); return { type: 'InvalidPayload', message: errors_1.default.allowedResources.INVALID_RESOURCE(field.id, context.key, actualType) }; } if (type === 'array.min') { return { type: 'InvalidPayload', message: errors_1.default.allowedResources.TOO_FEW_ITEMS(field.id, 'allowedResources') }; } if (type === 'array.max') { return { type: 'InvalidPayload', message: errors_1.default.allowedResources.TOO_MANY_ITEMS(field.id, 'allowedResources') }; } if (type === 'array.unique') { return { type: 'InvalidPayload', message: errors_1.default.allowedResources.DUPLICATE_SOURCE(field.id, context.value.source, 'allowedResources') }; } } else if (path.slice(-2).includes('allowedResources')) { if (type === 'array.min') { return { type: 'InvalidPayload', message: errors_1.default.allowedResources.TOO_FEW_ITEMS(field.id, prop) }; } if (type === 'array.max') { return { type: 'InvalidPayload', message: errors_1.default.allowedResources.TOO_MANY_ITEMS(field.id, prop) }; } if (type === 'array.unique') { return { type: 'InvalidPayload', message: errors_1.default.allowedResources.DUPLICATE_SOURCE(field.id, context.value.source, prop) }; } } else if (['validations', 'nodes', 'allowedResources'].every((pathItem) => path.includes(pathItem))) { const error = details.message.replace(/".+?"/, `"${context.key}"`); return { type: 'InvalidPayload', message: errors_1.default.allowedResources.INVALID_RESOURCE_PROPERTY(field.id, path[6], error) }; } if (type === 'any.required') { if (context.isRequiredDependency) { const dependentProp = context.dependsOn.key; const dependentValue = context.dependsOn.value; return { type: 'InvalidPayload', message: errors_1.default.field.REQUIRED_DEPENDENT_PROPERTY(prop, field.id, dependentProp, dependentValue) }; } return { type: 'InvalidPayload', message: errors_1.default.field.REQUIRED_PROPERTY(prop, field.id) }; } if (type === 'any.unknown') { if (context.isForbiddenDependency) { const dependentProp = context.dependsOn.key; const dependentValue = context.dependsOn.value; return { type: 'InvalidPayload', message: errors_1.default.field.FORBIDDEN_DEPENDENT_PROPERTY(prop, field.id, dependentProp, dependentValue) }; } return { type: 'InvalidPayload', message: errors_1.default.field.FORBIDDEN_PROPERTY(prop, field.id) }; } if (type === 'any.only') { return { type: 'InvalidPayload', message: errors_1.default.field.PROPERTY_MUST_BE_ONE_OF(prop, field.id, context.valids) }; } if (type === 'any.invalid' && path.includes('newId')) { return { type: 'InvalidPayload', message: errors_1.default.field.ID_MUST_BE_DIFFERENT(field.id) }; } const isIdSchemaError = (type) => { return ['string.max', 'string.empty', 'string.pattern.base'].includes(type); }; if (path.includes('newId') && isIdSchemaError(type)) { return { type: 'InvalidPayload', message: errors_1.default.field.ID_MUST_MATCH_SCHEMA(field.id, field.newId) }; } // Field `validations` errors if (prop.startsWith('validations')) { if (type === 'array.unique') { return { type: 'InvalidPayload', message: errors_1.default.field.validations.DUPLICATED_VALIDATION(context.dupeValue) }; } if (type === 'object.unknown') { return { type: 'InvalidPayload', message: errors_1.default.field.validations.INVALID_VALIDATION_PROPERTY(context.key) }; } if (type === 'object.unknownCombination') { return { type: 'InvalidPayload', message: errors_1.default.field.validations.INVALID_VALIDATION_PROPERTY_COMBINATION(context.keys) }; } if (type.endsWith('.base')) { const [expectedType] = type.split('.base'); const actualType = (0, kind_of_1.default)((0, hoek_1.reach)(field, prop)); return { type: 'InvalidPayload', message: errors_1.default.field.validations.INVALID_VALIDATION_PARAMETER(context.key, expectedType, actualType) }; } } }); }; exports.validateFields = validateFields; //# sourceMappingURL=schema-validation.js.map