@lucidcms/core
Version:
The core of the Lucid CMS. It's responsible for spinning up the API and serving the CMS.
1 lines • 28.5 kB
Source Map (JSON)
{"version":3,"file":"check-validate-bricks-fields.mjs","names":["constants"],"sources":["../../../../src/services/documents-bricks/checks/check-validate-bricks-fields.ts"],"sourcesContent":["import constants from \"../../../constants/constants.js\";\nimport type BrickBuilder from \"../../../libs/collection/builders/brick-builder/index.js\";\nimport type CollectionBuilder from \"../../../libs/collection/builders/collection-builder/index.js\";\nimport {\n\tevaluateFieldCondition,\n\ttype FieldConditionTargetResolver,\n} from \"../../../libs/collection/custom-fields/conditions/index.js\";\nimport type CustomField from \"../../../libs/collection/custom-fields/custom-field.js\";\nimport registeredFields from \"../../../libs/collection/custom-fields/registered-fields.js\";\nimport { isStorageMode } from \"../../../libs/collection/custom-fields/storage/index.js\";\nimport type {\n\tFieldConditionConfig,\n\tFieldConditionTranslationScope,\n\tFieldTypes,\n\tFieldUIConfig,\n} from \"../../../libs/collection/custom-fields/types.js\";\nimport { copy } from \"../../../libs/i18n/index.js\";\nimport logger from \"../../../libs/logger/index.js\";\nimport type { BrickInputSchema } from \"../../../schemas/collection-bricks.js\";\nimport type {\n\tBrickError,\n\tErrorCopy,\n\tFieldError,\n\tFieldInputSchema,\n\tGroupError,\n} from \"../../../types.js\";\nimport { tenantAccessAllowed } from \"../../../utils/helpers/index.js\";\nimport type { ServiceFn } from \"../../../utils/services/types.js\";\nimport fetchValidationData, {\n\ttype ValidationData,\n} from \"../helpers/fetch-validation-data.js\";\n\nconst isRequiredFieldConfig = (\n\tconfig: CustomField<FieldTypes>[\"config\"],\n): config is CustomField<FieldTypes>[\"config\"] & {\n\tvalidation: { required?: boolean };\n} => {\n\treturn (\n\t\t\"validation\" in config &&\n\t\ttypeof config.validation === \"object\" &&\n\t\tconfig.validation !== null\n\t);\n};\n\n/**\n * One level of submitted field input. The first entry is the level the field\n * being evaluated lives in, followed by each ancestor level up to the root.\n */\ntype ConditionScopeLevel = {\n\ttreeParentKey?: string;\n\tfields: Array<FieldInputSchema>;\n};\n\ntype ValidationMeta = {\n\tlocalized: boolean;\n\tdefaultLocale: string;\n\tlocales?: string[];\n};\n\nconst getFieldCondition = (\n\tinstance: CustomField<FieldTypes>,\n): FieldConditionConfig | undefined => {\n\treturn (instance.config as { ui?: FieldUIConfig }).ui?.condition;\n};\n\n/**\n * Maps field keys to the conditions of the structural containers they render\n * inside: the root tab they belong to plus any section/collapsible ancestors.\n * Structural fields are config-only containers, so submitted fields never\n * nest under them - hiding a container must hide its whole subtree.\n */\nconst buildStructuralConditions = (\n\tinstance: CollectionBuilder | BrickBuilder,\n): Map<string, FieldConditionConfig[]> => {\n\tconst conditions = new Map<string, FieldConditionConfig[]>();\n\tlet currentTabCondition: FieldConditionConfig | undefined;\n\n\tfor (const [key, field] of instance.fields) {\n\t\tif (field.type === \"tab\") {\n\t\t\tcurrentTabCondition = getFieldCondition(field);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fieldConditions: FieldConditionConfig[] = [];\n\n\t\tif (field.treeParent === null && currentTabCondition) {\n\t\t\tfieldConditions.push(currentTabCondition);\n\t\t}\n\n\t\tlet structuralParentKey = field.structuralParent;\n\t\twhile (structuralParentKey) {\n\t\t\tconst structuralParent = instance.fields.get(structuralParentKey);\n\t\t\tif (!structuralParent) break;\n\n\t\t\tconst structuralCondition = getFieldCondition(structuralParent);\n\t\t\tif (structuralCondition) fieldConditions.push(structuralCondition);\n\n\t\t\tstructuralParentKey = structuralParent.structuralParent;\n\t\t}\n\n\t\tif (fieldConditions.length > 0) {\n\t\t\tconditions.set(key, fieldConditions);\n\t\t}\n\t}\n\n\treturn conditions;\n};\n\n/**\n * Resolves condition targets against submitted input. Field keys are unique\n * within a tree, so the target's own scope determines which level of the\n * chain its value is read from - targets outside the sibling/ancestor chain\n * stay unresolved.\n */\nconst createConditionTargetResolver = (props: {\n\tinstance: CollectionBuilder | BrickBuilder;\n\tscopes: ConditionScopeLevel[];\n\tlocale: string;\n\tdefaultLocale: string;\n\tcollectionLocalized: boolean;\n\ttranslationScope: FieldConditionTranslationScope;\n}): FieldConditionTargetResolver => {\n\treturn (fieldKey) => {\n\t\tconst target = props.instance.fields.get(fieldKey);\n\t\tif (\n\t\t\t!target ||\n\t\t\ttarget.type === \"repeater\" ||\n\t\t\ttarget.type === \"tab\" ||\n\t\t\ttarget.type === \"section\" ||\n\t\t\ttarget.type === \"collapsible\"\n\t\t) {\n\t\t\treturn { resolved: false };\n\t\t}\n\n\t\tconst scope = props.scopes.find(\n\t\t\t(level) => (level.treeParentKey ?? null) === target.treeParent,\n\t\t);\n\t\tif (!scope) return { resolved: false };\n\n\t\tconst submitted = scope.fields.find((field) => field.key === fieldKey);\n\t\tif (!submitted) {\n\t\t\tif (\n\t\t\t\tprops.collectionLocalized &&\n\t\t\t\ttarget.localizedEnabled &&\n\t\t\t\tprops.translationScope === \"any\"\n\t\t\t) {\n\t\t\t\treturn { resolved: true, match: \"any\", values: [target.defaultValue] };\n\t\t\t}\n\t\t\treturn { resolved: true, value: target.defaultValue };\n\t\t}\n\n\t\tif (\n\t\t\tsubmitted.translations &&\n\t\t\tprops.collectionLocalized &&\n\t\t\ttarget.localizedEnabled\n\t\t) {\n\t\t\tif (props.translationScope === \"any\") {\n\t\t\t\treturn {\n\t\t\t\t\tresolved: true,\n\t\t\t\t\tmatch: \"any\",\n\t\t\t\t\tvalues: Object.values(submitted.translations).map((value) =>\n\t\t\t\t\t\ttarget.normalizeInputValue(value),\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst locale =\n\t\t\t\tprops.translationScope === \"default\"\n\t\t\t\t\t? props.defaultLocale\n\t\t\t\t\t: props.locale;\n\t\t\treturn {\n\t\t\t\tresolved: true,\n\t\t\t\tvalue: target.normalizeInputValue(submitted.translations[locale]),\n\t\t\t};\n\t\t}\n\n\t\treturn {\n\t\t\tresolved: true,\n\t\t\tvalue: target.normalizeInputValue(submitted.value),\n\t\t};\n\t};\n};\n\nconst getConditionTranslationScope = (\n\tcondition: FieldConditionConfig,\n\tconditionedFieldLocalized: boolean,\n): FieldConditionTranslationScope => {\n\tif (condition.translationScope && condition.translationScope !== \"same\") {\n\t\treturn condition.translationScope;\n\t}\n\n\treturn conditionedFieldLocalized ? \"same\" : \"default\";\n};\n\n/**\n * Evaluates whether a field is visible for the given locale, taking the\n * conditions of the structural containers it renders inside into account\n * (root tab plus any section/collapsible ancestors).\n */\nconst isFieldVisible = (props: {\n\tfieldKey: string;\n\tfieldInstance: CustomField<FieldTypes>;\n\tinstance: CollectionBuilder | BrickBuilder;\n\tscopes: ConditionScopeLevel[];\n\tlocale: string;\n\tdefaultLocale: string;\n\tcollectionLocalized: boolean;\n\tstructuralConditions: Map<string, FieldConditionConfig[]>;\n}): boolean => {\n\tconst condition = getFieldCondition(props.fieldInstance);\n\tconst containerConditions = props.structuralConditions.get(props.fieldKey);\n\tif (!condition && !containerConditions) return true;\n\n\tconst evaluateCondition = (\n\t\tvisibilityCondition: FieldConditionConfig,\n\t\tconditionedFieldLocalized: boolean,\n\t) =>\n\t\tevaluateFieldCondition(\n\t\t\tvisibilityCondition,\n\t\t\tcreateConditionTargetResolver({\n\t\t\t\tinstance: props.instance,\n\t\t\t\tscopes: props.scopes,\n\t\t\t\tlocale: props.locale,\n\t\t\t\tdefaultLocale: props.defaultLocale,\n\t\t\t\tcollectionLocalized: props.collectionLocalized,\n\t\t\t\ttranslationScope: getConditionTranslationScope(\n\t\t\t\t\tvisibilityCondition,\n\t\t\t\t\tconditionedFieldLocalized,\n\t\t\t\t),\n\t\t\t}),\n\t\t);\n\n\tfor (const containerCondition of containerConditions ?? []) {\n\t\tif (!evaluateCondition(containerCondition, false)) {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn condition\n\t\t? evaluateCondition(condition, props.fieldInstance.localizedEnabled)\n\t\t: true;\n};\n\nconst checkValidateBricksFields: ServiceFn<\n\t[\n\t\t{\n\t\t\tbricks: Array<BrickInputSchema>;\n\t\t\tfields: Array<FieldInputSchema>;\n\t\t\tcollection: CollectionBuilder;\n\t\t},\n\t],\n\tundefined\n> = async (context, data) => {\n\tconst refDataRes = await fetchValidationData(context, data);\n\tif (refDataRes.error) return refDataRes;\n\n\tconst brickErrors = validateBricks({\n\t\tbricks: data.bricks,\n\t\tcollection: data.collection,\n\t\tvalidationData: refDataRes.data,\n\t\tdefaultLocale: context.config.localization.defaultLocale,\n\t\tlocales: context.config.localization.locales.map((locale) => locale.code),\n\t\ttenantKey: context.request.tenantKey,\n\t});\n\tconst fieldErrors = recursiveFieldValidate({\n\t\tfields: data.fields,\n\t\tinstance: data.collection,\n\t\tvalidationData: refDataRes.data,\n\t\tmeta: {\n\t\t\tlocalized: data.collection.getData.localized,\n\t\t\tdefaultLocale: context.config.localization.defaultLocale,\n\t\t\tlocales: context.config.localization.locales.map((locale) => locale.code),\n\t\t},\n\t});\n\n\tif (brickErrors.length > 0 || fieldErrors.length > 0) {\n\t\treturn {\n\t\t\tdata: undefined,\n\t\t\terror: {\n\t\t\t\ttype: \"basic\",\n\t\t\t\tname: copy(\"server:core.fields.validation.error.name\"),\n\t\t\t\tmessage: copy(\"server:core.fields.validation.error.message\"),\n\t\t\t\tstatus: 400,\n\t\t\t\terrors: {\n\t\t\t\t\tbricks: brickErrors,\n\t\t\t\t\tfields: fieldErrors,\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tdata: undefined,\n\t\terror: undefined,\n\t};\n};\n\n/**\n * Loops over bricks and runs validation against their fields recursively and return errors\n */\nconst validateBricks = (props: {\n\tbricks: Array<BrickInputSchema>;\n\tcollection: CollectionBuilder;\n\tvalidationData: ValidationData;\n\tdefaultLocale: string;\n\tlocales: string[];\n\ttenantKey?: string | null;\n}): Array<BrickError> => {\n\tconst errors: BrickError[] = [];\n\n\tfor (const brick of props.bricks) {\n\t\tlet instance: BrickBuilder | undefined;\n\n\t\tswitch (brick.type) {\n\t\t\tcase \"builder\": {\n\t\t\t\tinstance = props.collection.config.bricks?.builder?.find(\n\t\t\t\t\t(b) => b.key === brick.key,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"fixed\": {\n\t\t\t\tinstance = props.collection.config.bricks?.fixed?.find(\n\t\t\t\t\t(b) => b.key === brick.key,\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (\n\t\t\t!instance ||\n\t\t\t!tenantAccessAllowed(instance.config.tenants, props.tenantKey)\n\t\t) {\n\t\t\tlogger.error({\n\t\t\t\tscope: constants.logScopes.validation,\n\t\t\t\tmessage: \"Brick config was not found during document validation\",\n\t\t\t\tdata: {\n\t\t\t\t\tkey: brick.key || \"\",\n\t\t\t\t},\n\t\t\t});\n\t\t\terrors.push({\n\t\t\t\tref: brick.ref,\n\t\t\t\tkey: brick.key,\n\t\t\t\torder: brick.order,\n\t\t\t\tfields: [\n\t\t\t\t\t{\n\t\t\t\t\t\tkey: brick.key,\n\t\t\t\t\t\tlocaleCode: null,\n\t\t\t\t\t\tmessage: copy(\n\t\t\t\t\t\t\t\"server:core.fields.lookup.not.found.in.collection.or.brick\",\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst fieldErrors = recursiveFieldValidate({\n\t\t\tfields: brick.fields || [],\n\t\t\tinstance: instance,\n\t\t\tvalidationData: props.validationData,\n\t\t\tmeta: {\n\t\t\t\tlocalized: props.collection.getData.localized,\n\t\t\t\tdefaultLocale: props.defaultLocale,\n\t\t\t\tlocales: props.locales,\n\t\t\t},\n\t\t});\n\t\tif (fieldErrors.length === 0) continue;\n\n\t\terrors.push({\n\t\t\tref: brick.ref,\n\t\t\tkey: brick.key,\n\t\t\torder: brick.order,\n\t\t\tfields: fieldErrors,\n\t\t});\n\t}\n\n\treturn errors;\n};\n\n/**\n * Recursively validate fields and return errors\n */\nexport const recursiveFieldValidate = (props: {\n\tfields: Array<FieldInputSchema>;\n\tinstance: CollectionBuilder | BrickBuilder;\n\tvalidationData: ValidationData;\n\tparentTreeFieldKey?: string;\n\tparentScopes?: ConditionScopeLevel[];\n\tstructuralConditions?: Map<string, FieldConditionConfig[]>;\n\tmeta: ValidationMeta;\n}) => {\n\tconst errors: FieldError[] = [];\n\n\tconst scopes: ConditionScopeLevel[] = [\n\t\t{ treeParentKey: props.parentTreeFieldKey, fields: props.fields },\n\t\t...(props.parentScopes ?? []),\n\t];\n\tconst structuralConditions =\n\t\tprops.structuralConditions ?? buildStructuralConditions(props.instance);\n\tconst fieldVisibleForLocale = (\n\t\tfieldKey: string,\n\t\tfieldInstance: CustomField<FieldTypes>,\n\t\tlocale: string,\n\t) =>\n\t\tisFieldVisible({\n\t\t\tfieldKey,\n\t\t\tfieldInstance,\n\t\t\tinstance: props.instance,\n\t\t\tscopes,\n\t\t\tlocale,\n\t\t\tdefaultLocale: props.meta.defaultLocale,\n\t\t\tcollectionLocalized: props.meta.localized,\n\t\t\tstructuralConditions,\n\t\t});\n\n\t//* validate all provided fields\n\tfor (const field of props.fields) {\n\t\tconst fieldInstance = props.instance.fields.get(field.key);\n\t\tif (!fieldInstance) {\n\t\t\terrors.push({\n\t\t\t\tkey: field.key,\n\t\t\t\tlocaleCode: null,\n\t\t\t\tmessage: copy(\n\t\t\t\t\t\"server:core.fields.lookup.not.found.in.collection.or.brick\",\n\t\t\t\t),\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst databaseConfig = registeredFields[fieldInstance.type].config.database;\n\n\t\t//* handle tree-table fields separately with recursive validation\n\t\tif (isStorageMode(databaseConfig, \"tree-table\")) {\n\t\t\t//* hidden containers skip validation for their entire subtree\n\t\t\tif (\n\t\t\t\t!fieldVisibleForLocale(\n\t\t\t\t\tfield.key,\n\t\t\t\t\tfieldInstance,\n\t\t\t\t\tprops.meta.defaultLocale,\n\t\t\t\t)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst groupErrors: Array<GroupError> = [];\n\t\t\tconst groups = field.groups || [];\n\n\t\t\t// validates the tree-table field and its group length\n\t\t\tconst validationResult = fieldInstance.validate({\n\t\t\t\ttype: field.type,\n\t\t\t\tvalue: groups,\n\t\t\t});\n\t\t\tif (!validationResult.valid) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: field.key,\n\t\t\t\t\tlocaleCode: null,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\tvalidationResult.message ||\n\t\t\t\t\t\tcopy(\n\t\t\t\t\t\t\t\"server:core.fields.repeater.validation.field.contains.errors\",\n\t\t\t\t\t\t),\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tfor (let i = 0; i < groups.length; i++) {\n\t\t\t\tconst group = groups[i];\n\t\t\t\tif (!group) continue;\n\n\t\t\t\tconst groupFieldErrors = recursiveFieldValidate({\n\t\t\t\t\tfields: group.fields,\n\t\t\t\t\tinstance: props.instance,\n\t\t\t\t\tvalidationData: props.validationData,\n\t\t\t\t\tparentTreeFieldKey: field.key,\n\t\t\t\t\tparentScopes: scopes,\n\t\t\t\t\tstructuralConditions,\n\t\t\t\t\tmeta: props.meta,\n\t\t\t\t});\n\n\t\t\t\tif (groupFieldErrors.length > 0) {\n\t\t\t\t\tgroupErrors.push({\n\t\t\t\t\t\tref: group.ref,\n\t\t\t\t\t\torder: group.order || i,\n\t\t\t\t\t\tfields: groupFieldErrors,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (groupErrors.length > 0) {\n\t\t\t\terrors.push({\n\t\t\t\t\tkey: field.key,\n\t\t\t\t\tlocaleCode: null,\n\t\t\t\t\tmessage: copy(\n\t\t\t\t\t\t\"server:core.fields.repeater.validation.field.contains.errors\",\n\t\t\t\t\t),\n\t\t\t\t\tgroupErrors: groupErrors,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcontinue;\n\t\t}\n\n\t\t//* handle regular fields\n\t\tconst fieldErrors = validateField({\n\t\t\tfield: field,\n\t\t\tinstance: fieldInstance,\n\t\t\tvalidationData: props.validationData,\n\t\t\tmeta: props.meta,\n\t\t\tisLocaleVisible: (localeCode) =>\n\t\t\t\tfieldVisibleForLocale(\n\t\t\t\t\tfield.key,\n\t\t\t\t\tfieldInstance,\n\t\t\t\t\tlocaleCode ?? props.meta.defaultLocale,\n\t\t\t\t),\n\t\t});\n\t\tif (fieldErrors.length > 0) {\n\t\t\terrors.push(...fieldErrors);\n\t\t}\n\t}\n\n\t//* check for required fields that are missing\n\tconst submittedFieldKeys = new Set(props.fields.map((field) => field.key));\n\tprops.instance.fields.forEach((fieldInstance, key) => {\n\t\tif (submittedFieldKeys.has(key)) return;\n\n\t\t//* skip fields that belong to a different tree-table parent context\n\t\tconst fieldTreeParent = fieldInstance.treeParent;\n\t\tif (\n\t\t\t(fieldTreeParent && fieldTreeParent !== props.parentTreeFieldKey) ||\n\t\t\t(!fieldTreeParent && props.parentTreeFieldKey)\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (\n\t\t\tisRequiredFieldConfig(fieldInstance.config) &&\n\t\t\tfieldInstance.config.validation.required\n\t\t) {\n\t\t\tif (\n\t\t\t\tprops.meta.localized &&\n\t\t\t\tfieldInstance.localizedEnabled &&\n\t\t\t\tprops.meta.locales?.length\n\t\t\t) {\n\t\t\t\tfor (const localeCode of getConfiguredLocaleCodes(props.meta)) {\n\t\t\t\t\tif (!fieldVisibleForLocale(key, fieldInstance, localeCode)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tkey: key,\n\t\t\t\t\t\tlocaleCode,\n\t\t\t\t\t\tmessage: copy(\"server:core.fields.validation.is.required\"),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t//* hidden fields are exempt from required validation\n\t\t\tif (\n\t\t\t\t!fieldVisibleForLocale(key, fieldInstance, props.meta.defaultLocale)\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\terrors.push({\n\t\t\t\tkey: key,\n\t\t\t\tlocaleCode: null,\n\t\t\t\tmessage: copy(\"server:core.fields.validation.is.required\"),\n\t\t\t});\n\t\t}\n\t});\n\n\treturn errors;\n};\n\nconst getConfiguredLocaleCodes = (meta: ValidationMeta) => {\n\tconst localeCodes = new Set(meta.locales ?? []);\n\tlocaleCodes.add(meta.defaultLocale);\n\treturn Array.from(localeCodes);\n};\n\nconst getTranslationLocaleCodes = (\n\tmeta: ValidationMeta,\n\ttranslations: NonNullable<FieldInputSchema[\"translations\"]>,\n) => {\n\tconst submittedLocaleCodes = Object.keys(translations);\n\tif (!meta.locales?.length) return submittedLocaleCodes;\n\n\treturn Array.from(\n\t\tnew Set([...getConfiguredLocaleCodes(meta), ...submittedLocaleCodes]),\n\t);\n};\n\n/**\n * Validates a single field, handling both direct values and translations\n */\nexport const validateField = (props: {\n\tfield: FieldInputSchema;\n\tinstance: CustomField<FieldTypes>;\n\tvalidationData: ValidationData;\n\t/**\n\t * Visibility check for a given locale (null = the direct value branch).\n\t * Hidden locales skip validation entirely.\n\t */\n\tisLocaleVisible?: (localeCode: string | null) => boolean;\n\tmeta: ValidationMeta;\n}): FieldError[] => {\n\tconst errors: FieldError[] = [];\n\tconst refData = props.validationData[props.field.type];\n\tconst fieldUsesTranslations =\n\t\tprops.meta.localized && props.instance.localizedEnabled;\n\tconst toFieldErrors = (localeCode: string | null, message?: ErrorCopy) => {\n\t\treturn (\n\t\t\tmessage\n\t\t\t\t? [{ message }]\n\t\t\t\t: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tmessage: copy(\"server:core.fields.validation.errors.unknown\"),\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t).map((error) => ({\n\t\t\tkey: props.field.key,\n\t\t\tlocaleCode,\n\t\t\tmessage: error.message,\n\t\t}));\n\t};\n\tconst buildFieldErrors = (\n\t\tlocaleCode: string | null,\n\t\tvalidationResult: ReturnType<CustomField<FieldTypes>[\"validate\"]>,\n\t) => {\n\t\tif (validationResult.errors?.length) {\n\t\t\treturn validationResult.errors.map((error) => ({\n\t\t\t\tkey: props.field.key,\n\t\t\t\tlocaleCode,\n\t\t\t\tmessage:\n\t\t\t\t\terror.message || copy(\"server:core.fields.validation.errors.unknown\"),\n\t\t\t\titemIndex: error.itemIndex,\n\t\t\t}));\n\t\t}\n\n\t\treturn toFieldErrors(localeCode, validationResult.message);\n\t};\n\n\t//* handle fields with translations\n\tif (props.field.translations) {\n\t\tconst localeCodes = fieldUsesTranslations\n\t\t\t? getTranslationLocaleCodes(props.meta, props.field.translations)\n\t\t\t: Object.keys(props.field.translations);\n\n\t\tfor (const localeCode of localeCodes) {\n\t\t\tif (props.isLocaleVisible && !props.isLocaleVisible(localeCode)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst value = props.field.translations[localeCode];\n\t\t\tconst validationResult = props.instance.validate({\n\t\t\t\ttype: props.field.type,\n\t\t\t\tvalue,\n\t\t\t\trefData: refData,\n\t\t\t});\n\n\t\t\tif (!validationResult.valid) {\n\t\t\t\terrors.push(...buildFieldErrors(localeCode, validationResult));\n\t\t\t}\n\t\t}\n\t}\n\t//* handle direct value fields\n\telse {\n\t\tif (fieldUsesTranslations && props.meta.locales?.length) {\n\t\t\tfor (const localeCode of getConfiguredLocaleCodes(props.meta)) {\n\t\t\t\tif (props.isLocaleVisible && !props.isLocaleVisible(localeCode)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst validationResult = props.instance.validate({\n\t\t\t\t\ttype: props.field.type,\n\t\t\t\t\tvalue:\n\t\t\t\t\t\tlocaleCode === props.meta.defaultLocale\n\t\t\t\t\t\t\t? props.field.value\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\trefData: refData,\n\t\t\t\t});\n\n\t\t\t\tif (!validationResult.valid) {\n\t\t\t\t\terrors.push(...buildFieldErrors(localeCode, validationResult));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn errors;\n\t\t}\n\n\t\tif (props.isLocaleVisible && !props.isLocaleVisible(null)) {\n\t\t\treturn errors;\n\t\t}\n\n\t\tconst validationResult = props.instance.validate({\n\t\t\ttype: props.field.type,\n\t\t\tvalue: props.field.value,\n\t\t\trefData: refData,\n\t\t});\n\n\t\tif (!validationResult.valid) {\n\t\t\terrors.push(\n\t\t\t\t...buildFieldErrors(\n\t\t\t\t\tfieldUsesTranslations ? props.meta.defaultLocale : null,\n\t\t\t\t\tvalidationResult,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\n\treturn errors;\n};\n\nexport default checkValidateBricksFields;\n"],"mappings":"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"}