@wordpress/blocks
Version:
Block API for WordPress.
156 lines (155 loc) • 4.47 kB
JavaScript
// packages/blocks/src/api/parser/get-block-attributes.js
import { parse as hpqParse } from "hpq";
import memoize from "memize";
import { applyFilters } from "@wordpress/hooks";
import { RichTextData } from "@wordpress/rich-text";
import {
attr,
html,
text,
query,
node,
children,
prop,
richText
} from "../matchers";
import { normalizeBlockType, getDefault } from "../utils";
var toBooleanAttributeMatcher = (matcher) => (value) => matcher(value) !== void 0;
function isOfType(value, type) {
switch (type) {
case "rich-text":
return value instanceof RichTextData;
case "string":
return typeof value === "string";
case "boolean":
return typeof value === "boolean";
case "object":
return !!value && value.constructor === Object;
case "null":
return value === null;
case "array":
return Array.isArray(value);
case "integer":
case "number":
return typeof value === "number";
}
return true;
}
function isOfTypes(value, types) {
return types.some((type) => isOfType(value, type));
}
function getBlockAttribute(attributeKey, attributeSchema, innerDOM, commentAttributes, innerHTML) {
let value;
switch (attributeSchema.source) {
// An undefined source means that it's an attribute serialized to the
// block's "comment".
case void 0:
value = commentAttributes ? commentAttributes[attributeKey] : void 0;
break;
// raw source means that it's the original raw block content.
case "raw":
value = innerHTML;
break;
case "attribute":
case "property":
case "html":
case "text":
case "rich-text":
case "children":
case "node":
case "query":
case "tag":
value = parseWithAttributeSchema(innerDOM, attributeSchema);
break;
}
if (!isValidByType(value, attributeSchema.type) || !isValidByEnum(value, attributeSchema.enum)) {
value = void 0;
}
if (value === void 0) {
value = getDefault(attributeSchema);
}
return value;
}
function isValidByType(value, type) {
return type === void 0 || isOfTypes(value, Array.isArray(type) ? type : [type]);
}
function isValidByEnum(value, enumSet) {
return !Array.isArray(enumSet) || enumSet.includes(value);
}
var matcherFromSource = memoize((sourceConfig) => {
switch (sourceConfig.source) {
case "attribute": {
let matcher = attr(sourceConfig.selector, sourceConfig.attribute);
if (sourceConfig.type === "boolean") {
matcher = toBooleanAttributeMatcher(matcher);
}
return matcher;
}
case "html":
return html(sourceConfig.selector, sourceConfig.multiline);
case "text":
return text(sourceConfig.selector);
case "rich-text":
return richText(
sourceConfig.selector,
sourceConfig.__unstablePreserveWhiteSpace
);
case "children":
return children(sourceConfig.selector);
case "node":
return node(sourceConfig.selector);
case "query":
const subMatchers = Object.fromEntries(
Object.entries(sourceConfig.query).map(
([key, subSourceConfig]) => [
key,
matcherFromSource(subSourceConfig)
]
)
);
return query(sourceConfig.selector, subMatchers);
case "tag": {
const matcher = prop(sourceConfig.selector, "nodeName");
return (domNode) => matcher(domNode)?.toLowerCase();
}
default:
console.error(`Unknown source type "${sourceConfig.source}"`);
}
});
function parseHtml(innerHTML) {
return hpqParse(innerHTML, (h) => h);
}
function parseWithAttributeSchema(innerHTML, attributeSchema) {
return matcherFromSource(attributeSchema)(parseHtml(innerHTML));
}
function getBlockAttributes(blockTypeOrName, innerHTML, attributes = {}) {
const doc = parseHtml(innerHTML);
const blockType = normalizeBlockType(blockTypeOrName);
const blockAttributes = Object.fromEntries(
Object.entries(blockType.attributes ?? {}).map(
([key, schema]) => [
key,
getBlockAttribute(key, schema, doc, attributes, innerHTML)
]
)
);
return applyFilters(
"blocks.getBlockAttributes",
blockAttributes,
blockType,
innerHTML,
attributes
);
}
export {
getBlockAttribute,
getBlockAttributes,
isOfType,
isOfTypes,
isValidByEnum,
isValidByType,
matcherFromSource,
parseWithAttributeSchema,
toBooleanAttributeMatcher
};
//# sourceMappingURL=get-block-attributes.js.map