From 5b0678860fce694eede15a346b8f5d0607174734 Mon Sep 17 00:00:00 2001 From: Karol Manijak <20098064+kmanijak@users.noreply.github.com> Date: Thu, 2 Jan 2025 11:32:02 +0100 Subject: [PATCH] Fail gracefully when block in `createBlock` function is not registered (#68043) * Make __experimentalSanitizeBlockAttributes fail gracefully when block is not registered * Check if block is registered before sanitizing attributes * Update tests and add new ones * Bring back the error throwing * Simplify the test * Refactor block creation functions for improved readability/ In both cases they rely on internal handling of `createBlock` function. Co-authored-by: kmanijak Co-authored-by: gziolo --- packages/blocks/src/api/factory.js | 55 +++++++++++++++------------ packages/blocks/src/api/templates.js | 13 +------ packages/blocks/src/api/test/utils.js | 15 ++++++++ packages/blocks/src/api/utils.js | 11 ++++++ 4 files changed, 58 insertions(+), 36 deletions(-) diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 25bf64ca65dc90..5eacf96fb1e5b5 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -17,6 +17,7 @@ import { getGroupingBlockName, } from './registration'; import { + isBlockRegistered, normalizeBlockType, __experimentalSanitizeBlockAttributes, } from './utils'; @@ -31,6 +32,14 @@ import { * @return {Object} Block object. */ export function createBlock( name, attributes = {}, innerBlocks = [] ) { + if ( ! isBlockRegistered( name ) ) { + return createBlock( 'core/missing', { + originalName: name, + originalContent: '', + originalUndelimitedContent: '', + } ); + } + const sanitizedAttributes = __experimentalSanitizeBlockAttributes( name, attributes @@ -94,15 +103,22 @@ export function __experimentalCloneSanitizedBlock( mergeAttributes = {}, newInnerBlocks ) { + const { name } = block; + + if ( ! isBlockRegistered( name ) ) { + return createBlock( 'core/missing', { + originalName: name, + originalContent: '', + originalUndelimitedContent: '', + } ); + } + const clientId = uuid(); - const sanitizedAttributes = __experimentalSanitizeBlockAttributes( - block.name, - { - ...block.attributes, - ...mergeAttributes, - } - ); + const sanitizedAttributes = __experimentalSanitizeBlockAttributes( name, { + ...block.attributes, + ...mergeAttributes, + } ); return { ...block, @@ -583,20 +599,11 @@ export function switchToBlockType( blocks, name ) { * * @return {Object} block. */ -export const getBlockFromExample = ( name, example ) => { - try { - return createBlock( - name, - example.attributes, - ( example.innerBlocks ?? [] ).map( ( innerBlock ) => - getBlockFromExample( innerBlock.name, innerBlock ) - ) - ); - } catch { - return createBlock( 'core/missing', { - originalName: name, - originalContent: '', - originalUndelimitedContent: '', - } ); - } -}; +export const getBlockFromExample = ( name, example ) => + createBlock( + name, + example.attributes, + ( example.innerBlocks ?? [] ).map( ( innerBlock ) => + getBlockFromExample( innerBlock.name, innerBlock ) + ) + ); diff --git a/packages/blocks/src/api/templates.js b/packages/blocks/src/api/templates.js index 71231121362a49..6f7e13f27ebe80 100644 --- a/packages/blocks/src/api/templates.js +++ b/packages/blocks/src/api/templates.js @@ -109,23 +109,12 @@ export function synchronizeBlocksWithTemplate( blocks = [], template ) { attributes ); - let [ blockName, blockAttributes ] = + const [ blockName, blockAttributes ] = convertLegacyBlockNameAndAttributes( name, normalizedAttributes ); - // If a Block is undefined at this point, use the core/missing block as - // a placeholder for a better user experience. - if ( undefined === getBlockType( blockName ) ) { - blockAttributes = { - originalName: name, - originalContent: '', - originalUndelimitedContent: '', - }; - blockName = 'core/missing'; - } - return createBlock( blockName, blockAttributes, diff --git a/packages/blocks/src/api/test/utils.js b/packages/blocks/src/api/test/utils.js index 548bbb27da3889..b1906b65b4208f 100644 --- a/packages/blocks/src/api/test/utils.js +++ b/packages/blocks/src/api/test/utils.js @@ -12,6 +12,7 @@ import { isUnmodifiedDefaultBlock, getAccessibleBlockLabel, getBlockLabel, + isBlockRegistered, __experimentalSanitizeBlockAttributes, getBlockAttributesNamesByRole, isContentBlock, @@ -213,6 +214,20 @@ describe( 'getAccessibleBlockLabel', () => { } ); } ); +describe( 'isBlockRegistered', () => { + it( 'returns true if the block is registered', () => { + registerBlockType( 'core/test-block', { title: 'Test block' } ); + expect( isBlockRegistered( 'core/test-block' ) ).toBe( true ); + unregisterBlockType( 'core/test-block' ); + } ); + + it( 'returns false if the block is not registered', () => { + expect( isBlockRegistered( 'core/not-registered-test-block' ) ).toBe( + false + ); + } ); +} ); + describe( 'sanitizeBlockAttributes', () => { afterEach( () => { getBlockTypes().forEach( ( block ) => { diff --git a/packages/blocks/src/api/utils.js b/packages/blocks/src/api/utils.js index 73c34ab3499d63..ad94d9d5c9e0c1 100644 --- a/packages/blocks/src/api/utils.js +++ b/packages/blocks/src/api/utils.js @@ -266,6 +266,17 @@ export function getDefault( attributeSchema ) { } } +/** + * Check if a block is registered. + * + * @param {string} name The block's name. + * + * @return {boolean} Whether the block is registered. + */ +export function isBlockRegistered( name ) { + return getBlockType( name ) !== undefined; +} + /** * Ensure attributes contains only values defined by block type, and merge * default values for missing attributes.