@wordpress/blocks
Version:
Block API for WordPress.
8 lines (7 loc) • 11.2 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../../../src/api/parser/get-block-attributes.js"],
"sourcesContent": ["/**\n * External dependencies\n */\nimport { parse as hpqParse } from 'hpq';\nimport memoize from 'memize';\n\n/**\n * WordPress dependencies\n */\nimport { applyFilters } from '@wordpress/hooks';\nimport { RichTextData } from '@wordpress/rich-text';\n\n/**\n * Internal dependencies\n */\nimport {\n\tattr,\n\thtml,\n\ttext,\n\tquery,\n\tnode,\n\tchildren,\n\tprop,\n\trichText,\n} from '../matchers';\nimport { normalizeBlockType, getDefault } from '../utils';\n\n/**\n * Higher-order hpq matcher which enhances an attribute matcher to return true\n * or false depending on whether the original matcher returns undefined. This\n * is useful for boolean attributes (e.g. disabled) whose attribute values may\n * be technically falsey (empty string), though their mere presence should be\n * enough to infer as true.\n *\n * @param {Function} matcher Original hpq matcher.\n *\n * @return {Function} Enhanced hpq matcher.\n */\nexport const toBooleanAttributeMatcher = ( matcher ) => ( value ) =>\n\tmatcher( value ) !== undefined;\n\n/**\n * Returns true if value is of the given JSON schema type, or false otherwise.\n *\n * @see http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.25\n *\n * @param {*} value Value to test.\n * @param {string} type Type to test.\n *\n * @return {boolean} Whether value is of type.\n */\nexport function isOfType( value, type ) {\n\tswitch ( type ) {\n\t\tcase 'rich-text':\n\t\t\treturn value instanceof RichTextData;\n\n\t\tcase 'string':\n\t\t\treturn typeof value === 'string';\n\n\t\tcase 'boolean':\n\t\t\treturn typeof value === 'boolean';\n\n\t\tcase 'object':\n\t\t\treturn !! value && value.constructor === Object;\n\n\t\tcase 'null':\n\t\t\treturn value === null;\n\n\t\tcase 'array':\n\t\t\treturn Array.isArray( value );\n\n\t\tcase 'integer':\n\t\tcase 'number':\n\t\t\treturn typeof value === 'number';\n\t}\n\n\treturn true;\n}\n\n/**\n * Returns true if value is of an array of given JSON schema types, or false\n * otherwise.\n *\n * @see http://json-schema.org/latest/json-schema-validation.html#rfc.section.6.25\n *\n * @param {*} value Value to test.\n * @param {string[]} types Types to test.\n *\n * @return {boolean} Whether value is of types.\n */\nexport function isOfTypes( value, types ) {\n\treturn types.some( ( type ) => isOfType( value, type ) );\n}\n\n/**\n * Given an attribute key, an attribute's schema, a block's raw content and the\n * commentAttributes returns the attribute value depending on its source\n * definition of the given attribute key.\n *\n * @param {string} attributeKey Attribute key.\n * @param {Object} attributeSchema Attribute's schema.\n * @param {Node} innerDOM Parsed DOM of block's inner HTML.\n * @param {Object} commentAttributes Block's comment attributes.\n * @param {string} innerHTML Raw HTML from block node's innerHTML property.\n *\n * @return {*} Attribute value.\n */\nexport function getBlockAttribute(\n\tattributeKey,\n\tattributeSchema,\n\tinnerDOM,\n\tcommentAttributes,\n\tinnerHTML\n) {\n\tlet value;\n\n\tswitch ( attributeSchema.source ) {\n\t\t// An undefined source means that it's an attribute serialized to the\n\t\t// block's \"comment\".\n\t\tcase undefined:\n\t\t\tvalue = commentAttributes\n\t\t\t\t? commentAttributes[ attributeKey ]\n\t\t\t\t: undefined;\n\t\t\tbreak;\n\t\t// raw source means that it's the original raw block content.\n\t\tcase 'raw':\n\t\t\tvalue = innerHTML;\n\t\t\tbreak;\n\t\tcase 'attribute':\n\t\tcase 'property':\n\t\tcase 'html':\n\t\tcase 'text':\n\t\tcase 'rich-text':\n\t\tcase 'children':\n\t\tcase 'node':\n\t\tcase 'query':\n\t\tcase 'tag':\n\t\t\tvalue = parseWithAttributeSchema( innerDOM, attributeSchema );\n\t\t\tbreak;\n\t}\n\n\tif (\n\t\t! isValidByType( value, attributeSchema.type ) ||\n\t\t! isValidByEnum( value, attributeSchema.enum )\n\t) {\n\t\t// Reject the value if it is not valid. Reverting to the undefined\n\t\t// value ensures the default is respected, if applicable.\n\t\tvalue = undefined;\n\t}\n\n\tif ( value === undefined ) {\n\t\tvalue = getDefault( attributeSchema );\n\t}\n\n\treturn value;\n}\n\n/**\n * Returns true if value is valid per the given block attribute schema type\n * definition, or false otherwise.\n *\n * @see https://json-schema.org/latest/json-schema-validation.html#rfc.section.6.1.1\n *\n * @param {*} value Value to test.\n * @param {?(Array<string>|string)} type Block attribute schema type.\n *\n * @return {boolean} Whether value is valid.\n */\nexport function isValidByType( value, type ) {\n\treturn (\n\t\ttype === undefined ||\n\t\tisOfTypes( value, Array.isArray( type ) ? type : [ type ] )\n\t);\n}\n\n/**\n * Returns true if value is valid per the given block attribute schema enum\n * definition, or false otherwise.\n *\n * @see https://json-schema.org/latest/json-schema-validation.html#rfc.section.6.1.2\n *\n * @param {*} value Value to test.\n * @param {?Array} enumSet Block attribute schema enum.\n *\n * @return {boolean} Whether value is valid.\n */\nexport function isValidByEnum( value, enumSet ) {\n\treturn ! Array.isArray( enumSet ) || enumSet.includes( value );\n}\n\n/**\n * Returns an hpq matcher given a source object.\n *\n * @param {Object} sourceConfig Attribute Source object.\n *\n * @return {Function} A hpq Matcher.\n */\nexport const matcherFromSource = memoize( ( sourceConfig ) => {\n\tswitch ( sourceConfig.source ) {\n\t\tcase 'attribute': {\n\t\t\tlet matcher = attr( sourceConfig.selector, sourceConfig.attribute );\n\t\t\tif ( sourceConfig.type === 'boolean' ) {\n\t\t\t\tmatcher = toBooleanAttributeMatcher( matcher );\n\t\t\t}\n\t\t\treturn matcher;\n\t\t}\n\t\tcase 'html':\n\t\t\treturn html( sourceConfig.selector, sourceConfig.multiline );\n\t\tcase 'text':\n\t\t\treturn text( sourceConfig.selector );\n\t\tcase 'rich-text':\n\t\t\treturn richText(\n\t\t\t\tsourceConfig.selector,\n\t\t\t\tsourceConfig.__unstablePreserveWhiteSpace\n\t\t\t);\n\t\tcase 'children':\n\t\t\treturn children( sourceConfig.selector );\n\t\tcase 'node':\n\t\t\treturn node( sourceConfig.selector );\n\t\tcase 'query':\n\t\t\tconst subMatchers = Object.fromEntries(\n\t\t\t\tObject.entries( sourceConfig.query ).map(\n\t\t\t\t\t( [ key, subSourceConfig ] ) => [\n\t\t\t\t\t\tkey,\n\t\t\t\t\t\tmatcherFromSource( subSourceConfig ),\n\t\t\t\t\t]\n\t\t\t\t)\n\t\t\t);\n\t\t\treturn query( sourceConfig.selector, subMatchers );\n\t\tcase 'tag': {\n\t\t\tconst matcher = prop( sourceConfig.selector, 'nodeName' );\n\t\t\treturn ( domNode ) => matcher( domNode )?.toLowerCase();\n\t\t}\n\t\tdefault:\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.error( `Unknown source type \"${ sourceConfig.source }\"` );\n\t}\n} );\n\n/**\n * Parse a HTML string into DOM tree.\n *\n * @param {string|Node} innerHTML HTML string or already parsed DOM node.\n *\n * @return {Node} Parsed DOM node.\n */\nfunction parseHtml( innerHTML ) {\n\treturn hpqParse( innerHTML, ( h ) => h );\n}\n\n/**\n * Given a block's raw content and an attribute's schema returns the attribute's\n * value depending on its source.\n *\n * @param {string|Node} innerHTML Block's raw content.\n * @param {Object} attributeSchema Attribute's schema.\n *\n * @return {*} Attribute value.\n */\nexport function parseWithAttributeSchema( innerHTML, attributeSchema ) {\n\treturn matcherFromSource( attributeSchema )( parseHtml( innerHTML ) );\n}\n\n/**\n * Returns the block attributes of a registered block node given its type.\n *\n * @param {string|Object} blockTypeOrName Block type or name.\n * @param {string|Node} innerHTML Raw block content.\n * @param {?Object} attributes Known block attributes (from delimiters).\n *\n * @return {Object} All block attributes.\n */\nexport function getBlockAttributes(\n\tblockTypeOrName,\n\tinnerHTML,\n\tattributes = {}\n) {\n\tconst doc = parseHtml( innerHTML );\n\tconst blockType = normalizeBlockType( blockTypeOrName );\n\n\tconst blockAttributes = Object.fromEntries(\n\t\tObject.entries( blockType.attributes ?? {} ).map(\n\t\t\t( [ key, schema ] ) => [\n\t\t\t\tkey,\n\t\t\t\tgetBlockAttribute( key, schema, doc, attributes, innerHTML ),\n\t\t\t]\n\t\t)\n\t);\n\n\treturn applyFilters(\n\t\t'blocks.getBlockAttributes',\n\t\tblockAttributes,\n\t\tblockType,\n\t\tinnerHTML,\n\t\tattributes\n\t);\n}\n"],
"mappings": "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",
"names": []
}