UNPKG

@r1tsu/payload

Version:

161 lines (160 loc) 7.71 kB
import MissingEditorProp from '../../errors/MissingEditorProp.js'; import { DuplicateFieldName, InvalidFieldName, InvalidFieldRelationship, MissingFieldType } from '../../errors/index.js'; import { formatLabels, toWords } from '../../utilities/formatLabels.js'; import { baseBlockFields } from '../baseFields/baseBlockFields.js'; import { baseIDField } from '../baseFields/baseIDField.js'; import { setDefaultBeforeDuplicate } from '../setDefaultBeforeDuplicate.js'; import validations from '../validations.js'; import { fieldAffectsData, tabHasName } from './types.js'; export const sanitizeFields = ({ config, existingFieldNames = new Set(), fields, requireFieldLevelRichTextEditor = false, validRelationships })=>{ if (!fields) return []; return fields.map((unsanitizedField)=>{ const field = { ...unsanitizedField }; if (!field.type) throw new MissingFieldType(field); // assert that field names do not contain forbidden characters if (fieldAffectsData(field) && field.name.includes('.')) { throw new InvalidFieldName(field, field.name); } // Auto-label if ('name' in field && field.name && typeof field.label !== 'object' && typeof field.label !== 'string' && field.label !== false) { field.label = toWords(field.name); } if (field.type === 'checkbox' && typeof field.defaultValue === 'undefined' && field.required === true) { field.defaultValue = false; } if (field.type === 'relationship' || field.type === 'upload') { if (validRelationships) { const relationships = Array.isArray(field.relationTo) ? field.relationTo : [ field.relationTo ]; relationships.forEach((relationship)=>{ if (!validRelationships.includes(relationship)) { throw new InvalidFieldRelationship(field, relationship); } }); } if (field.type === 'relationship') { if (field.min && !field.minRows) { console.warn(`(payload): The "min" property is deprecated for the Relationship field "${field.name}" and will be removed in a future version. Please use "minRows" instead.`); } if (field.max && !field.maxRows) { console.warn(`(payload): The "max" property is deprecated for the Relationship field "${field.name}" and will be removed in a future version. Please use "maxRows" instead.`); } field.minRows = field.minRows || field.min; field.maxRows = field.maxRows || field.max; } } if (field.type === 'blocks' && field.blocks) { field.blocks = field.blocks.map((block)=>({ ...block, fields: block.fields.concat(baseBlockFields) })); } if (field.type === 'array' && field.fields) { field.fields.push(baseIDField); } if ((field.type === 'blocks' || field.type === 'array') && field.label) { field.labels = field.labels || formatLabels(field.name); } if (fieldAffectsData(field)) { if (existingFieldNames.has(field.name)) { throw new DuplicateFieldName(field.name); } else if (![ 'blockName', 'id' ].includes(field.name)) { existingFieldNames.add(field.name); } if (field.localized && !config.localization) delete field.localized; if (typeof field.validate === 'undefined') { const defaultValidate = validations[field.type]; if (defaultValidate) { field.validate = (val, options)=>defaultValidate(val, { ...field, ...options }); } else { field.validate = ()=>true; } } if (!field.hooks) field.hooks = {}; if (!field.access) field.access = {}; setDefaultBeforeDuplicate(field); } if (!field.admin) { field.admin = {}; } // Make sure that the richText field has an editor if (field.type === 'richText') { if (!field.editor) { if (config.editor && !requireFieldLevelRichTextEditor) { field.editor = config.editor; } else { throw new MissingEditorProp(field); } } // Add editor adapter hooks to field hooks if (!field.hooks) field.hooks = {}; if (field?.editor?.hooks?.afterRead?.length) { field.hooks.afterRead = field.hooks.afterRead ? field.hooks.afterRead.concat(field.editor.hooks.afterRead) : field.editor.hooks.afterRead; } if (field?.editor?.hooks?.beforeChange?.length) { field.hooks.beforeChange = field.hooks.beforeChange ? field.hooks.beforeChange.concat(field.editor.hooks.beforeChange) : field.editor.hooks.beforeChange; } if (field?.editor?.hooks?.beforeValidate?.length) { field.hooks.beforeValidate = field.hooks.beforeValidate ? field.hooks.beforeValidate.concat(field.editor.hooks.beforeValidate) : field.editor.hooks.beforeValidate; } if (field?.editor?.hooks?.beforeChange?.length) { field.hooks.beforeChange = field.hooks.beforeChange ? field.hooks.beforeChange.concat(field.editor.hooks.beforeChange) : field.editor.hooks.beforeChange; } } // TODO: Handle sanitization for any lexical sub-fields here as well if ('fields' in field && field.fields) { field.fields = sanitizeFields({ config, existingFieldNames: fieldAffectsData(field) ? new Set() : existingFieldNames, fields: field.fields, requireFieldLevelRichTextEditor, validRelationships }); } if (field.type === 'tabs') { field.tabs = field.tabs.map((tab)=>{ const unsanitizedTab = { ...tab }; if (tabHasName(tab) && typeof tab.label === 'undefined') { unsanitizedTab.label = toWords(tab.name); } unsanitizedTab.fields = sanitizeFields({ config, existingFieldNames: tabHasName(tab) ? new Set() : existingFieldNames, fields: tab.fields, requireFieldLevelRichTextEditor, validRelationships }); return unsanitizedTab; }); } if ('blocks' in field && field.blocks) { field.blocks = field.blocks.map((block)=>{ const unsanitizedBlock = { ...block }; unsanitizedBlock.labels = !unsanitizedBlock.labels ? formatLabels(unsanitizedBlock.slug) : unsanitizedBlock.labels; unsanitizedBlock.fields = sanitizeFields({ config, existingFieldNames: new Set(), fields: block.fields, requireFieldLevelRichTextEditor, validRelationships }); return unsanitizedBlock; }); } return field; }); }; //# sourceMappingURL=sanitize.js.map