Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Block API: Normalize function arguments #10891

Merged
merged 3 commits into from
Oct 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/reference/deprecated.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Gutenberg's deprecation policy is intended to support backwards-compatibility fo
- `wp.compose.remountOnPropChange` has been removed.
- The following editor store actions have been removed: `createNotice`, `removeNotice`, `createSuccessNotice`, `createInfoNotice`, `createErrorNotice`, `createWarningNotice`. Use the equivalent actions by the same name from the `@wordpress/notices` module.
- The id prop of wp.nux.DotTip has been removed. Please use the tipId prop instead.
- `wp.blocks.isValidBlock` has been removed. Please use `wp.blocks.isValidBlockContent` instead but keep in mind that the order of params has changed.

## 4.3.0

Expand Down
10 changes: 10 additions & 0 deletions packages/blocks/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
## 5.1.0 (Unreleased)

### New feature

- `isValidBlockContent` function has been added ([#10891](https://github.com/WordPress/gutenberg/pull/10891)).

### Deprecation

- `isValidBlock` function has been deprecated ([#10891](https://github.com/WordPress/gutenberg/pull/10891)). Use `isValidBlockContent` instead.

## 5.0.0 (2018-10-29)

### Breaking Changes
Expand Down
19 changes: 8 additions & 11 deletions packages/blocks/src/api/factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,20 @@ import { getBlockType, getBlockTypes } from './registration';
/**
* Returns a block object given its type and attributes.
*
* @param {string} name Block name.
* @param {Object} blockAttributes Block attributes.
* @param {?Array} innerBlocks Nested blocks.
* @param {string} name Block name.
* @param {Object} attributes Block attributes.
* @param {?Array} innerBlocks Nested blocks.
*
* @return {Object} Block object.
*/
export function createBlock( name, blockAttributes = {}, innerBlocks = [] ) {
export function createBlock( name, attributes = {}, innerBlocks = [] ) {
// Get the type definition associated with a registered block.
const blockType = getBlockType( name );

// Ensure attributes contains only values defined by block type, and merge
// default values for missing attributes.
const attributes = reduce( blockType.attributes, ( result, schema, key ) => {
const value = blockAttributes[ key ];
const sanitizedAttributes = reduce( blockType.attributes, ( result, schema, key ) => {
const value = attributes[ key ];

if ( undefined !== value ) {
result[ key ] = value;
Expand Down Expand Up @@ -75,7 +75,7 @@ export function createBlock( name, blockAttributes = {}, innerBlocks = [] ) {
clientId,
name,
isValid: true,
attributes,
attributes: sanitizedAttributes,
innerBlocks,
};
}
Expand All @@ -84,7 +84,7 @@ export function createBlock( name, blockAttributes = {}, innerBlocks = [] ) {
* Given a block object, returns a copy of the block object, optionally merging
* new attributes and/or replacing its inner blocks.
*
* @param {Object} block Block object.
* @param {Object} block Block instance.
* @param {Object} mergeAttributes Block attributes.
* @param {?Array} newInnerBlocks Nested blocks.
*
Expand Down Expand Up @@ -112,7 +112,6 @@ export function cloneBlock( block, mergeAttributes = {}, newInnerBlocks ) {
* @param {Object} transform The transform object to validate.
* @param {string} direction Is this a 'from' or 'to' transform.
* @param {Array} blocks The blocks to transform from.
* @param {boolean} isMultiBlock Have multiple blocks been selected?
*
* @return {boolean} Is the transform possible?
*/
Expand Down Expand Up @@ -157,7 +156,6 @@ const isPossibleTransformForSource = ( transform, direction, blocks ) => {
* 'from' transforms on other blocks.
*
* @param {Array} blocks The blocks to transform from.
* @param {boolean} isMultiBlock Have multiple blocks been selected?
*
* @return {Array} Block types that the blocks can be transformed into.
*/
Expand Down Expand Up @@ -189,7 +187,6 @@ const getBlockTypesForPossibleFromTransforms = ( blocks ) => {
* the source block's own 'to' transforms.
*
* @param {Array} blocks The blocks to transform from.
* @param {boolean} isMultiBlock Have multiple blocks been selected?
*
* @return {Array} Block types that the source can be transformed into.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/blocks/src/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export {
getSaveElement,
getSaveContent,
} from './serializer';
export { isValidBlock } from './validation';
export { isValidBlockContent, isValidBlock } from './validation';
export {
getCategories,
setCategories,
Expand Down
12 changes: 6 additions & 6 deletions packages/blocks/src/api/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
getUnregisteredTypeHandlerName,
} from './registration';
import { createBlock } from './factory';
import { isValidBlock } from './validation';
import { isValidBlockContent } from './validation';
import { getCommentDelimitedContent } from './serializer';
import { attr, html, text, query, node, children, prop } from './matchers';

Expand Down Expand Up @@ -283,7 +283,7 @@ export function getBlockAttribute( attributeKey, attributeSchema, innerHTML, com
*
* @return {Object} All block attributes.
*/
export function getBlockAttributes( blockType, innerHTML, attributes ) {
export function getBlockAttributes( blockType, innerHTML, attributes = {} ) {
const blockAttributes = mapValues( blockType.attributes, ( attributeSchema, attributeKey ) => {
return getBlockAttribute( attributeKey, attributeSchema, innerHTML, attributes );
} );
Expand Down Expand Up @@ -340,10 +340,10 @@ export function getMigratedBlock( block ) {
);

// Ignore the deprecation if it produces a block which is not valid.
const isValid = isValidBlock(
originalContent,
const isValid = isValidBlockContent(
deprecatedBlockType,
migratedAttributes
migratedAttributes,
originalContent
);

if ( ! isValid ) {
Expand Down Expand Up @@ -459,7 +459,7 @@ export function createBlockWithFallback( blockNode ) {
// provided source value with the serialized output before there are any modifications to
// the block. When both match, the block is marked as valid.
if ( ! isFallbackBlock ) {
block.isValid = isValidBlock( innerHTML, blockType, block.attributes );
block.isValid = isValidBlockContent( blockType, block.attributes, innerHTML );
}

// Preserve original content for future use in case the block is parsed as
Expand Down
12 changes: 6 additions & 6 deletions packages/blocks/src/api/registration.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,10 @@ export function unregisterBlockType( name ) {
/**
* Assigns name of block for handling non-block content.
*
* @param {string} name Block name.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we update this, but not unregisterBlockType( name ) -> unregisterBlockType( blockName ). What's the motivation for this change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will revert. It's obvious here what the name is. Other examples where I changed bring more clarity as the function name isn't as specific. e.g.: setFreeformContentHandlerName( blockName ).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't understand your question properly, but I think I answered it anyway :)

It's obvious here what the name is.

name is also used in registerBlockType as the first param - so I wanted to have it consistent. In general I expanded to blockName in cases where the funcion name doesn't say anything about the block.

* @param {string} blockName Block name.
*/
export function setFreeformContentHandlerName( name ) {
dispatch( 'core/blocks' ).setFreeformFallbackBlockName( name );
export function setFreeformContentHandlerName( blockName ) {
dispatch( 'core/blocks' ).setFreeformFallbackBlockName( blockName );
}

/**
Expand All @@ -193,10 +193,10 @@ export function getFreeformContentHandlerName() {
/**
* Assigns name of block handling unregistered block types.
*
* @param {string} name Block name.
* @param {string} blockName Block name.
*/
export function setUnregisteredTypeHandlerName( name ) {
dispatch( 'core/blocks' ).setUnregisteredFallbackBlockName( name );
export function setUnregisteredTypeHandlerName( blockName ) {
dispatch( 'core/blocks' ).setUnregisteredFallbackBlockName( blockName );
}

/**
Expand Down
14 changes: 6 additions & 8 deletions packages/blocks/src/api/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,14 @@ export function getSaveContent( blockType, attributes, innerBlocks ) {
* This function returns only those attributes which are needed to persist and
* which cannot be matched from the block content.
*
* @param {Object<string,*>} allAttributes Attributes from in-memory block data.
* @param {Object<string,*>} blockType Block type.
* @param {Object<string,*>} attributes Attributes from in-memory block data.
*
* @return {Object<string,*>} Subset of attributes for comment serialization.
*/
export function getCommentAttributes( allAttributes, blockType ) {
const attributes = reduce( blockType.attributes, ( result, attributeSchema, key ) => {
const value = allAttributes[ key ];
export function getCommentAttributes( blockType, attributes ) {
return reduce( blockType.attributes, ( result, attributeSchema, key ) => {
const value = attributes[ key ];

// Ignore undefined values.
if ( undefined === value ) {
Expand All @@ -163,8 +163,6 @@ export function getCommentAttributes( allAttributes, blockType ) {
result[ key ] = value;
return result;
}, {} );

return attributes;
}

/**
Expand Down Expand Up @@ -195,7 +193,7 @@ export function serializeAttributes( attributes ) {
/**
* Given a block object, returns the Block's Inner HTML markup.
*
* @param {Object} block Block Object.
* @param {Object} block Block instance.
*
* @return {string} HTML.
*/
Expand Down Expand Up @@ -262,7 +260,7 @@ export function serializeBlock( block ) {
const blockName = block.name;
const blockType = getBlockType( blockName );
const saveContent = getBlockContent( block );
const saveAttributes = getCommentAttributes( block.attributes, blockType );
const saveAttributes = getCommentAttributes( blockType, block.attributes );

switch ( blockName ) {
case getFreeformContentHandlerName():
Expand Down
60 changes: 35 additions & 25 deletions packages/blocks/src/api/test/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,27 @@ describe( 'block serializer', () => {
} );

it( 'should only return attributes which are not matched from content', () => {
const attributes = getCommentAttributes( {
fruit: 'bananas',
category: 'food',
ripeness: 'ripe',
}, { attributes: {
fruit: {
type: 'string',
source: 'text',
},
category: {
type: 'string',
},
ripeness: {
type: 'string',
const attributes = getCommentAttributes(
{
attributes: {
fruit: {
type: 'string',
source: 'text',
},
category: {
type: 'string',
},
ripeness: {
type: 'string',
},
},
},
} } );
{
fruit: 'bananas',
category: 'food',
ripeness: 'ripe',
}
);

expect( attributes ).toEqual( {
category: 'food',
Expand All @@ -103,17 +108,22 @@ describe( 'block serializer', () => {
} );

it( 'should skip attributes whose values are undefined', () => {
const attributes = getCommentAttributes( {
fruit: 'bananas',
ripeness: undefined,
}, { attributes: {
fruit: {
type: 'string',
},
ripeness: {
type: 'string',
const attributes = getCommentAttributes(
{
attributes: {
fruit: {
type: 'string',
},
ripeness: {
type: 'string',
},
},
},
} } );
{
fruit: 'bananas',
ripeness: undefined,
}
);

expect( attributes ).toEqual( { fruit: 'bananas' } );
} );
Expand Down
22 changes: 11 additions & 11 deletions packages/blocks/src/api/test/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
isEqualTokensOfType,
getNextNonWhitespaceToken,
isEquivalentHTML,
isValidBlock,
isValidBlockContent,
isClosedByToken,
} from '../validation';
import {
Expand Down Expand Up @@ -553,14 +553,14 @@ describe( 'validation', () => {
} );
} );

describe( 'isValidBlock()', () => {
describe( 'isValidBlockContent()', () => {
it( 'returns false if block is not valid', () => {
registerBlockType( 'core/test-block', defaultBlockSettings );

const isValid = isValidBlock(
'Apples',
const isValid = isValidBlockContent(
getBlockType( 'core/test-block' ),
{ fruit: 'Bananas' }
{ fruit: 'Bananas' },
'Apples'
);

expect( console ).toHaveWarned();
Expand All @@ -576,10 +576,10 @@ describe( 'validation', () => {
},
} );

const isValid = isValidBlock(
'Bananas',
const isValid = isValidBlockContent(
getBlockType( 'core/test-block' ),
{ fruit: 'Bananas' }
{ fruit: 'Bananas' },
'Bananas'
);

expect( console ).toHaveErrored();
Expand All @@ -589,10 +589,10 @@ describe( 'validation', () => {
it( 'returns true is block is valid', () => {
registerBlockType( 'core/test-block', defaultBlockSettings );

const isValid = isValidBlock(
'Bananas',
const isValid = isValidBlockContent(
getBlockType( 'core/test-block' ),
{ fruit: 'Bananas' }
{ fruit: 'Bananas' },
'Bananas'
);

expect( isValid ).toBe( true );
Expand Down
20 changes: 18 additions & 2 deletions packages/blocks/src/api/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@
import { tokenize } from 'simple-html-tokenizer';
import { xor, fromPairs, isEqual, includes, stubTrue } from 'lodash';

/**
* WordPress dependencies
*/
import deprecated from '@wordpress/deprecated';

/**
* Internal dependencies
*/
Expand Down Expand Up @@ -485,20 +490,31 @@ export function isEquivalentHTML( actual, expected ) {
return true;
}

export function isValidBlock( innerHTML, blockType, attributes ) {
deprecated( 'isValidBlock', {
plugin: 'Gutenberg',
version: '4.4',
alternative: 'isValidBlockContent',
hint: 'The order of params has changed.',
} );

return isValidBlockContent( blockType, attributes, innerHTML );
}

/**
* Returns true if the parsed block is valid given the input content. A block
* is considered valid if, when serialized with assumed attributes, the content
* matches the original value.
*
* Logs to console in development environments when invalid.
*
* @param {string} innerHTML Original block content.
* @param {string} blockType Block type.
* @param {Object} attributes Parsed block attributes.
* @param {string} innerHTML Original block content.
*
* @return {boolean} Whether block is valid.
*/
export function isValidBlock( innerHTML, blockType, attributes ) {
export function isValidBlockContent( blockType, attributes, innerHTML ) {
let saveContent;
try {
saveContent = getSaveContent( blockType, attributes );
Expand Down
Loading