Compare commits

...

1 Commits

Author SHA1 Message Date
Dan Ribbens
3dd28e41d8 POC infinite recursion of blocks 2024-04-11 12:28:20 -04:00
5 changed files with 87 additions and 11 deletions

View File

@@ -1,5 +1,5 @@
import type { Config } from '../../config/types'
import type { Field } from './types'
import type { Block, Field } from './types'
import withCondition from '../../admin/components/forms/withCondition'
import {
@@ -18,6 +18,7 @@ type Args = {
config: Config
existingFieldNames?: Set<string>
fields: Field[]
sanitizedBlocksMap?: Record<string, Block>
/**
* If not null, will validate that upload and relationship fields do not relate to a collection that is not in this array.
* This validation will be skipped if validRelationships is null.
@@ -29,6 +30,7 @@ export const sanitizeFields = ({
config,
existingFieldNames = new Set(),
fields,
sanitizedBlocksMap = {},
validRelationships,
}: Args): Field[] => {
if (!fields) return []
@@ -96,10 +98,16 @@ export const sanitizeFields = ({
}
if (field.type === 'blocks' && field.blocks) {
field.blocks = field.blocks.map((block) => ({
...block,
fields: block.fields.concat(baseBlockFields),
}))
field.blocks = field.blocks.map((block) => {
// break recursion
if (!block.slug && Object.keys(block)[0]) {
return sanitizedBlocksMap[Object.keys(block)[0]]
}
return {
...block,
fields: block.fields.concat(baseBlockFields),
}
})
}
if (field.type === 'array' && field.fields) {
@@ -113,7 +121,7 @@ export const sanitizeFields = ({
if (fieldAffectsData(field)) {
if (existingFieldNames.has(field.name)) {
throw new DuplicateFieldName(field.name)
} else if (!['id', 'blockName'].includes(field.name)) {
} else if (!['blockName', 'id'].includes(field.name)) {
existingFieldNames.add(field.name)
}
@@ -169,16 +177,29 @@ export const sanitizeFields = ({
if ('blocks' in field && field.blocks) {
field.blocks = field.blocks.map((block) => {
const unsanitizedBlock = { ...block }
if (sanitizedBlocksMap[block?.interfaceName || block.slug]) {
return sanitizedBlocksMap[block?.interfaceName || block.slug]
}
// break recursion
if (!block.slug && Object.keys(block)[0]) {
return sanitizedBlocksMap[Object.keys(block)[0]]
}
sanitizedBlocksMap[block?.interfaceName || block.slug] = { ...block }
const unsanitizedBlock = sanitizedBlocksMap[block?.interfaceName || block.slug]
unsanitizedBlock.labels = !unsanitizedBlock.labels
? formatLabels(unsanitizedBlock.slug)
: unsanitizedBlock.labels
unsanitizedBlock.fields = sanitizeFields({
config,
fields: block.fields,
validRelationships,
existingFieldNames: new Set(),
fields: block.fields,
sanitizedBlocksMap,
validRelationships,
})
return unsanitizedBlock

19
test/_community/blockA.ts Normal file
View File

@@ -0,0 +1,19 @@
import type { Block } from 'payload/dist/fields/config/types'
import { BlockB } from './blockB'
export const BlockA: Block = {
slug: 'block-a',
fields: [
{
name: 'nestedBlocks',
type: 'blocks',
blocks: [BlockB],
},
{
name: 'title',
type: 'text',
},
],
interfaceName: 'BlockA',
}

15
test/_community/blockB.ts Normal file
View File

@@ -0,0 +1,15 @@
import type { Block } from 'payload/dist/fields/config/types'
import { BlockC } from './blockC'
export const BlockB: Block = {
slug: 'block-b',
fields: [
{
name: 'nestedBlocks',
type: 'blocks',
blocks: [BlockC],
},
],
interfaceName: 'BlockB',
}

15
test/_community/blockC.ts Normal file
View File

@@ -0,0 +1,15 @@
import type { Block } from 'payload/dist/fields/config/types'
const Recurse = require('./blockA')
export const BlockC: Block = {
slug: 'block-C',
fields: [
{
name: 'nestedBlocks',
type: 'blocks',
blocks: [Recurse],
},
],
interfaceName: 'BlockC',
}

View File

@@ -1,24 +1,30 @@
import type { CollectionConfig } from '../../../../packages/payload/src/collections/config/types'
import { BlockA } from '../../blockA'
import { mediaSlug } from '../Media'
export const postsSlug = 'posts'
export const PostsCollection: CollectionConfig = {
slug: postsSlug,
fields: [
{
name: 'text',
type: 'text',
},
{
name: 'blocks',
type: 'blocks',
blocks: [BlockA],
},
{
name: 'associatedMedia',
type: 'upload',
access: {
create: () => true,
update: () => false,
},
relationTo: mediaSlug,
type: 'upload',
},
],
slug: postsSlug,
}