payload
Version:
Node, React, Headless CMS and Application Framework built on Next.js
277 lines (276 loc) • 11.2 kB
JavaScript
// @ts-strict-ignore
import { MissingEditorProp } from '../../../errors/index.js';
import { fieldAffectsData, tabHasName } from '../../config/types.js';
import { getFieldPathsModified as getFieldPaths } from '../../getFieldPaths.js';
import { traverseFields } from './traverseFields.js';
// This function is responsible for the following actions, in order:
// - Execute field hooks
export const promise = async ({ blockData, collection, context, data, doc, field, fieldIndex, global, operation, parentIndexPath, parentIsLocalized, parentPath, parentSchemaPath, previousDoc, previousSiblingDoc, req, siblingData, siblingDoc, siblingFields })=>{
const { indexPath, path, schemaPath } = getFieldPaths({
field,
index: fieldIndex,
parentIndexPath,
parentPath,
parentSchemaPath
});
const pathSegments = path ? path.split('.') : [];
const schemaPathSegments = schemaPath ? schemaPath.split('.') : [];
const indexPathSegments = indexPath ? indexPath.split('-').filter(Boolean)?.map(Number) : [];
if (fieldAffectsData(field)) {
// Execute hooks
if (field.hooks?.afterChange) {
for (const hook of field.hooks.afterChange){
const hookedValue = await hook({
blockData,
collection,
context,
data,
field,
global,
indexPath: indexPathSegments,
operation,
originalDoc: doc,
path: pathSegments,
previousDoc,
previousSiblingDoc,
previousValue: previousDoc[field.name],
req,
schemaPath: schemaPathSegments,
siblingData,
siblingFields,
value: siblingDoc[field.name]
});
if (hookedValue !== undefined) {
siblingDoc[field.name] = hookedValue;
}
}
}
}
// Traverse subfields
switch(field.type){
case 'array':
{
const rows = siblingDoc[field.name];
if (Array.isArray(rows)) {
const promises = [];
rows.forEach((row, rowIndex)=>{
promises.push(traverseFields({
blockData,
collection,
context,
data,
doc,
fields: field.fields,
global,
operation,
parentIndexPath: '',
parentIsLocalized: parentIsLocalized || field.localized,
parentPath: path + '.' + rowIndex,
parentSchemaPath: schemaPath,
previousDoc,
previousSiblingDoc: previousDoc?.[field.name]?.[rowIndex] || {},
req,
siblingData: siblingData?.[field.name]?.[rowIndex] || {},
siblingDoc: row ? {
...row
} : {}
}));
});
await Promise.all(promises);
}
break;
}
case 'blocks':
{
const rows = siblingDoc[field.name];
if (Array.isArray(rows)) {
const promises = [];
rows.forEach((row, rowIndex)=>{
const blockTypeToMatch = row.blockType;
const block = req.payload.blocks[blockTypeToMatch] ?? (field.blockReferences ?? field.blocks).find((curBlock)=>typeof curBlock !== 'string' && curBlock.slug === blockTypeToMatch);
if (block) {
promises.push(traverseFields({
blockData: siblingData?.[field.name]?.[rowIndex],
collection,
context,
data,
doc,
fields: block.fields,
global,
operation,
parentIndexPath: '',
parentIsLocalized: parentIsLocalized || field.localized,
parentPath: path + '.' + rowIndex,
parentSchemaPath: schemaPath + '.' + block.slug,
previousDoc,
previousSiblingDoc: previousDoc?.[field.name]?.[rowIndex] || {},
req,
siblingData: siblingData?.[field.name]?.[rowIndex] || {},
siblingDoc: row ? {
...row
} : {}
}));
}
});
await Promise.all(promises);
}
break;
}
case 'collapsible':
case 'row':
{
await traverseFields({
blockData,
collection,
context,
data,
doc,
fields: field.fields,
global,
operation,
parentIndexPath: indexPath,
parentIsLocalized,
parentPath,
parentSchemaPath: schemaPath,
previousDoc,
previousSiblingDoc: {
...previousSiblingDoc
},
req,
siblingData: siblingData || {},
siblingDoc: {
...siblingDoc
}
});
break;
}
case 'group':
{
await traverseFields({
blockData,
collection,
context,
data,
doc,
fields: field.fields,
global,
operation,
parentIndexPath: '',
parentIsLocalized: parentIsLocalized || field.localized,
parentPath: path,
parentSchemaPath: schemaPath,
previousDoc,
previousSiblingDoc: previousDoc[field.name],
req,
siblingData: siblingData?.[field.name] || {},
siblingDoc: siblingDoc[field.name]
});
break;
}
case 'richText':
{
if (!field?.editor) {
throw new MissingEditorProp(field) // while we allow disabling editor functionality, you should not have any richText fields defined if you do not have an editor
;
}
if (typeof field.editor === 'function') {
throw new Error('Attempted to access unsanitized rich text editor.');
}
const editor = field.editor;
if (editor?.hooks?.afterChange?.length) {
for (const hook of editor.hooks.afterChange){
const hookedValue = await hook({
collection,
context,
data,
field,
global,
indexPath: indexPathSegments,
operation,
originalDoc: doc,
parentIsLocalized,
path: pathSegments,
previousDoc,
previousSiblingDoc,
previousValue: previousDoc[field.name],
req,
schemaPath: schemaPathSegments,
siblingData,
value: siblingDoc[field.name]
});
if (hookedValue !== undefined) {
siblingDoc[field.name] = hookedValue;
}
}
}
break;
}
case 'tab':
{
let tabSiblingData = siblingData;
let tabSiblingDoc = siblingDoc;
let tabPreviousSiblingDoc = siblingDoc;
const isNamedTab = tabHasName(field);
if (isNamedTab) {
tabSiblingData = siblingData[field.name] ?? {};
tabSiblingDoc = siblingDoc[field.name] ?? {};
tabPreviousSiblingDoc = previousDoc[field.name] ?? {};
}
await traverseFields({
blockData,
collection,
context,
data,
doc,
fields: field.fields,
global,
operation,
parentIndexPath: isNamedTab ? '' : indexPath,
parentIsLocalized: parentIsLocalized || field.localized,
parentPath: isNamedTab ? path : parentPath,
parentSchemaPath: schemaPath,
previousDoc,
previousSiblingDoc: tabPreviousSiblingDoc,
req,
siblingData: tabSiblingData,
siblingDoc: tabSiblingDoc
});
break;
}
case 'tabs':
{
await traverseFields({
blockData,
collection,
context,
data,
doc,
fields: field.tabs.map((tab)=>({
...tab,
type: 'tab'
})),
global,
operation,
parentIndexPath: indexPath,
parentIsLocalized,
parentPath: path,
parentSchemaPath: schemaPath,
previousDoc,
previousSiblingDoc: {
...previousSiblingDoc
},
req,
siblingData: siblingData || {},
siblingDoc: {
...siblingDoc
}
});
break;
}
default:
{
break;
}
}
};
//# sourceMappingURL=promise.js.map