// <input disabled="disabled">
return value !== undefined;
* Returns true if value is of the given JSON schema type, or false otherwise.
* @see http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.25
* @param {*} value Value to test.
* @param {string} type Type to test.
* @return {boolean} Whether value is of type.
function isOfType(value, type) {
return typeof value === 'string';
return typeof value === 'boolean';
return !!value && value.constructor === Object;
return Array.isArray(value);
return typeof value === 'number';
* Returns true if value is of an array of given JSON schema types, or false
* @see http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.25
* @param {*} value Value to test.
* @param {string[]} types Types to test.
* @return {boolean} Whether value is of types.
function isOfTypes(value, types) {
return types.some(function (type) {
return isOfType(value, type);
* Returns true if value is valid per the given block attribute schema type
* definition, or false otherwise.
* @see https://json-schema.org/latest/json-schema-validation.html#rfc.section.6.1.1
* @param {*} value Value to test.
* @param {?(Array<string>|string)} type Block attribute schema type.
* @return {boolean} Whether value is valid.
function isValidByType(value, type) {
return type === undefined || isOfTypes(value, Object(external_lodash_["castArray"])(type));
* Returns true if value is valid per the given block attribute schema enum
* definition, or false otherwise.
* @see https://json-schema.org/latest/json-schema-validation.html#rfc.section.6.1.2
* @param {*} value Value to test.
* @param {?Array} enumSet Block attribute schema enum.
* @return {boolean} Whether value is valid.
function isValidByEnum(value, enumSet) {
return !Array.isArray(enumSet) || enumSet.includes(value);
* Returns true if the given attribute schema describes a value which may be
* Some sources are ambiguously serialized as strings, for which value casting
* is enabled. This is only possible when a singular type is assigned to the
* attribute schema, since the string ambiguity makes it impossible to know the
* correct type of multiple to which to cast.
* @param {Object} attributeSchema Attribute's schema.
* @return {boolean} Whether attribute schema defines an ambiguous string
function isAmbiguousStringSource(attributeSchema) {
var source = attributeSchema.source,
type = attributeSchema.type;
var isStringSource = STRING_SOURCES.has(source);
var isSingleType = typeof type === 'string';
return isStringSource && isSingleType;
* Returns an hpq matcher given a source object.
* @param {Object} sourceConfig Attribute Source object.
* @return {Function} A hpq Matcher.
function matcherFromSource(sourceConfig) {
switch (sourceConfig.source) {
var matcher = attr(sourceConfig.selector, sourceConfig.attribute);
if (sourceConfig.type === 'boolean') {
matcher = parser_toBooleanAttributeMatcher(matcher);
return matchers_html(sourceConfig.selector, sourceConfig.multiline);
return es_text(sourceConfig.selector);
return children_matcher(sourceConfig.selector);
return node_matcher(sourceConfig.selector);
var subMatchers = Object(external_lodash_["mapValues"])(sourceConfig.query, matcherFromSource);
return query(sourceConfig.selector, subMatchers);
return Object(external_lodash_["flow"])([prop(sourceConfig.selector, 'nodeName'), function (nodeName) {
return nodeName ? nodeName.toLowerCase() : undefined;
// eslint-disable-next-line no-console
console.error("Unknown source type \"".concat(sourceConfig.source, "\""));
* Given a block's raw content and an attribute's schema returns the attribute's
* value depending on its source.
* @param {string} innerHTML Block's raw content.
* @param {Object} attributeSchema Attribute's schema.
* @return {*} Attribute value.
function parseWithAttributeSchema(innerHTML, attributeSchema) {
return es_parse(innerHTML, matcherFromSource(attributeSchema));
* Given an attribute key, an attribute's schema, a block's raw content and the
* commentAttributes returns the attribute value depending on its source
* definition of the given attribute key.
* @param {string} attributeKey Attribute key.
* @param {Object} attributeSchema Attribute's schema.
* @param {string} innerHTML Block's raw content.
* @param {Object} commentAttributes Block's comment attributes.
* @return {*} Attribute value.
function getBlockAttribute(attributeKey, attributeSchema, innerHTML, commentAttributes) {
var type = attributeSchema.type,
enumSet = attributeSchema.enum;
switch (attributeSchema.source) {
// An undefined source means that it's an attribute serialized to the
value = commentAttributes ? commentAttributes[attributeKey] : undefined;
value = parseWithAttributeSchema(innerHTML, attributeSchema);
if (!isValidByType(value, type) || !isValidByEnum(value, enumSet)) {
// Reject the value if it is not valid. Reverting to the undefined
// value ensures the default is respected, if applicable.
if (value === undefined) {
return attributeSchema.default;
* Returns the block attributes of a registered block node given its type.
* @param {string|Object} blockTypeOrName Block type or name.
* @param {string} innerHTML Raw block content.
* @param {?Object} attributes Known block attributes (from delimiters).
* @return {Object} All block attributes.
function getBlockAttributes(blockTypeOrName, innerHTML) {
var attributes = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var blockType = normalizeBlockType(blockTypeOrName);
var blockAttributes = Object(external_lodash_["mapValues"])(blockType.attributes, function (attributeSchema, attributeKey) {
return getBlockAttribute(attributeKey, attributeSchema, innerHTML, attributes);
return Object(external_wp_hooks_["applyFilters"])('blocks.getBlockAttributes', blockAttributes, blockType, innerHTML, attributes);
* Given a block object, returns a new copy of the block with any applicable
* deprecated migrations applied, or the original block if it was both valid
* and no eligible migrations exist.
* @param {WPBlock} block Original block object.
* @param {Object} parsedAttributes Attributes as parsed from the initial
* @return {WPBlock} Migrated block object.
function getMigratedBlock(block, parsedAttributes) {
var blockType = registration_getBlockType(block.name);
var deprecatedDefinitions = blockType.deprecated; // Bail early if there are no registered deprecations to be handled.
if (!deprecatedDefinitions || !deprecatedDefinitions.length) {
originalContent = _block.originalContent,
innerBlocks = _block.innerBlocks; // By design, blocks lack any sort of version tracking. Instead, to process
// outdated content the system operates a queue out of all the defined
// attribute shapes and tries each definition until the input produces a
// valid result. This mechanism seeks to avoid polluting the user-space with
// machine-specific code. An invalid block is thus a block that could not be
// matched successfully with any of the registered deprecation definitions.
for (var i = 0; i < deprecatedDefinitions.length; i++) {
// A block can opt into a migration even if the block is valid by
// defining `isEligible` on its deprecation. If the block is both valid
// and does not opt to migrate, skip.
var _deprecatedDefinition = deprecatedDefinitions[i].isEligible,
isEligible = _deprecatedDefinition === void 0 ? external_lodash_["stubFalse"] : _deprecatedDefinition;
if (block.isValid && !isEligible(parsedAttributes, innerBlocks)) {
} // Block type properties which could impact either serialization or
// parsing are not considered in the deprecated block type by default,
// and must be explicitly provided.
var deprecatedBlockType = Object.assign(Object(external_lodash_["omit"])(blockType, DEPRECATED_ENTRY_KEYS), deprecatedDefinitions[i]);
var migratedAttributes = getBlockAttributes(deprecatedBlockType, originalContent, parsedAttributes); // Ignore the deprecation if it produces a block which is not valid.
var _getBlockContentValid = getBlockContentValidationResult(deprecatedBlockType, migratedAttributes, originalContent),
isValid = _getBlockContentValid.isValid,
validationIssues = _getBlockContentValid.validationIssues; // An invalid block does not imply incorrect HTML but the fact block
// source information could be lost on reserialization.
block = parser_objectSpread(parser_objectSpread({}, block), {}, {
validationIssues: [].concat(Object(toConsumableArray["a" /* default */])(Object(external_lodash_["get"])(block, 'validationIssues', [])), Object(toConsumableArray["a" /* default */])(validationIssues))
var migratedInnerBlocks = innerBlocks; // A block may provide custom behavior to assign new attributes and/or
var migrate = deprecatedBlockType.migrate;
var _castArray = Object(external_lodash_["castArray"])(migrate(migratedAttributes, innerBlocks));
var _castArray2 = Object(slicedToArray["a" /* default */])(_castArray, 2);
var _castArray2$ = _castArray2[0];
migratedAttributes = _castArray2$ === void 0 ? parsedAttributes : _castArray2$;
var _castArray2$2 = _castArray2[1];
migratedInnerBlocks = _castArray2$2 === void 0 ? innerBlocks : _castArray2$2;
block = parser_objectSpread(parser_objectSpread({}, block), {}, {
attributes: migratedAttributes,
innerBlocks: migratedInnerBlocks,
* Convert legacy blocks to their canonical form. This function is used
* both in the parser level for previous content and to convert such blocks
* used in Custom Post Types templates.
* @param {string} name The block's name
* @param {Object} attributes The block's attributes
* @return {Object} The block's name and attributes, changed accordingly if a match was found
function convertLegacyBlocks(name, attributes) {
var newAttributes = parser_objectSpread({}, attributes); // Convert 'core/cover-image' block in existing content to 'core/cover'.
if ('core/cover-image' === name) {
} // Convert 'core/text' blocks in existing content to 'core/paragraph'.
if ('core/text' === name || 'core/cover-text' === name) {
} // Convert derivative blocks such as 'core/social-link-wordpress' to the
// canonical form 'core/social-link'.
if (name && name.indexOf('core/social-link-') === 0) {
// Capture `social-link-wordpress` into `{"service":"wordpress"}`
newAttributes.service = name.substring(17);
name = 'core/social-link';
} // Convert derivative blocks such as 'core-embed/instagram' to the
// canonical form 'core/embed'.
if (name && name.indexOf('core-embed/') === 0) {
// Capture `core-embed/instagram` into `{"providerNameSlug":"instagram"}`
var providerSlug = name.substring(11);
newAttributes.providerNameSlug = providerSlug in deprecated ? deprecated[providerSlug] : providerSlug; // this is needed as the `responsive` attribute was passed
// in a different way before the refactoring to block variations
if (!['amazon-kindle', 'wordpress'].includes(providerSlug)) {
newAttributes.responsive = true;
attributes: newAttributes
* Creates a block with fallback to the unknown type handler.
* @param {Object} blockNode Parsed block node.
* @return {?Object} An initialized block object (if possible).
function createBlockWithFallback(blockNode) {
var originalName = blockNode.blockName; // The fundamental structure of a blocktype includes its attributes, inner
// blocks, and inner HTML. It is important to distinguish inner blocks from
// the HTML content of the block as only the latter is relevant for block
// validation and edit operations.
var attributes = blockNode.attrs,
_blockNode$innerBlock = blockNode.innerBlocks,
innerBlocks = _blockNode$innerBlock === void 0 ? [] : _blockNode$innerBlock,
innerHTML = blockNode.innerHTML;
var innerContent = blockNode.innerContent; // Blocks that don't have a registered handler are considered freeform.
var freeformContentFallbackBlock = getFreeformContentHandlerName();
var unregisteredFallbackBlock = getUnregisteredTypeHandlerName() || freeformContentFallbackBlock;
attributes = attributes || {}; // Trim content to avoid creation of intermediary freeform segments.
innerHTML = innerHTML.trim(); // Use type from block content if available. Otherwise, default to the
// freeform content fallback.
var name = originalName || freeformContentFallbackBlock;
var _convertLegacyBlocks = convertLegacyBlocks(name, attributes);
name = _convertLegacyBlocks.name;
attributes = _convertLegacyBlocks.attributes;
// Fallback content may be upgraded from classic content expecting implicit
// automatic paragraphs, so preserve them. Assumes wpautop is idempotent,
// meaning there are no negative consequences to repeated autop calls.
if (name === freeformContentFallbackBlock) {
innerHTML = Object(external_wp_autop_["autop"])(innerHTML).trim();
} // Try finding the type for known block name, else fall back again.
var blockType = registration_getBlockType(name);
// Since the constituents of the block node are extracted at the start
// of the present function, construct a new object rather than reuse
var reconstitutedBlockNode = {
innerBlocks: innerBlocks,
innerContent: innerContent
}; // Preserve undelimited content for use by the unregistered type
// handler. A block node's `innerHTML` isn't enough, as that field only
// carries the block's own HTML and not its nested blocks.
var originalUndelimitedContent = serializeBlockNode(reconstitutedBlockNode, {
isCommentDelimited: false
}); // Preserve full block content for use by the unregistered type
// handler, block boundaries included.
var originalContent = serializeBlockNode(reconstitutedBlockNode, {
}); // If detected as a block which is not registered, preserve comment
// delimiters in content of unregistered type handler.
innerHTML = originalContent;
name = unregisteredFallbackBlock;
originalName: originalName,
originalContent: originalContent,
originalUndelimitedContent: originalUndelimitedContent
blockType = registration_getBlockType(name);
} // Coerce inner blocks from parsed form to canonical form.
innerBlocks = innerBlocks.map(createBlockWithFallback); // Remove `undefined` innerBlocks.
// This is a temporary fix to prevent unrecoverable TypeErrors when handling unexpectedly
// empty freeform block nodes. See https://github.com/WordPress/gutenberg/pull/17164.
innerBlocks = innerBlocks.filter(function (innerBlock) {
var isFallbackBlock = name === freeformContentFallbackBlock || name === unregisteredFallbackBlock; // Include in set only if type was determined.
if (!blockType || !innerHTML && isFallbackBlock) {
var block = createBlock(name, getBlockAttributes(blockType, innerHTML, attributes), innerBlocks); // Block validation assumes an idempotent operation from source block to serialized block
// provided there are no changes in attributes. The validation procedure thus compares the
// provided source value with the serialized output before there are any modifications to
// the block. When both match, the block is marked as valid.
var _getBlockContentValid2 = getBlockContentValidationResult(blockType, block.attributes, innerHTML),
isValid = _getBlockContentValid2.isValid,
validationIssues = _getBlockContentValid2.validationIssues;
block.validationIssues = validationIssues;
} // Preserve original content for future use in case the block is parsed
// as invalid, or future serialization attempt results in an error.
block.originalContent = block.originalContent || innerHTML; // Ensure all necessary migrations are applied to the block.
block = getMigratedBlock(block, attributes);
if (block.validationIssues && block.validationIssues.length > 0) {
// eslint-disable-next-line no-console
console.info('Block successfully updated for `%s` (%o).\n\nNew content generated by `save` function:\n\n%s\n\nContent retrieved from post body:\n\n%s', blockType.name, blockType, getSaveContent(blockType, block.attributes), block.originalContent);
block.validationIssues.forEach(function (_ref) {