Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoSign in
Socket

@wordpress/block-serialization-default-parser

Package Overview
Dependencies
Maintainers
23
Versions
219
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@wordpress/block-serialization-default-parser - npm Package Compare versions

Comparing version
5.36.1-next.738bb1424.0
to
5.36.1-next.76cff8c98.0
+205
build-module/index.mjs
// packages/block-serialization-default-parser/src/index.ts
var document;
var offset;
var output;
var stack;
var tokenizer = /<!--\s+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)\s+({(?:(?=([^}]+|}+(?=})|(?!}\s+\/?-->)[^])*)\5|[^]*?)}\s+)?(\/)?-->/g;
function Block(blockName, attrs, innerBlocks, innerHTML, innerContent) {
return {
blockName,
attrs,
innerBlocks,
innerHTML,
innerContent
};
}
function Freeform(innerHTML) {
return Block(null, {}, [], innerHTML, [innerHTML]);
}
function Frame(block, tokenStart, tokenLength, prevOffset, leadingHtmlStart) {
return {
block,
tokenStart,
tokenLength,
prevOffset: prevOffset || tokenStart + tokenLength,
leadingHtmlStart
};
}
var parse = (doc) => {
document = doc;
offset = 0;
output = [];
stack = [];
tokenizer.lastIndex = 0;
do {
} while (proceed());
return output;
};
function proceed() {
const stackDepth = stack.length;
const next = nextToken();
const [tokenType, blockName, attrs, startOffset, tokenLength] = next;
const leadingHtmlStart = startOffset > offset ? offset : null;
switch (tokenType) {
case "no-more-tokens":
if (0 === stackDepth) {
addFreeform();
return false;
}
if (1 === stackDepth) {
addBlockFromStack();
return false;
}
while (0 < stack.length) {
addBlockFromStack();
}
return false;
case "void-block":
if (0 === stackDepth) {
if (null !== leadingHtmlStart) {
output.push(
Freeform(
document.substr(
leadingHtmlStart,
startOffset - leadingHtmlStart
)
)
);
}
output.push(Block(blockName, attrs, [], "", []));
offset = startOffset + tokenLength;
return true;
}
addInnerBlock(
Block(blockName, attrs, [], "", []),
startOffset,
tokenLength
);
offset = startOffset + tokenLength;
return true;
case "block-opener":
stack.push(
Frame(
Block(blockName, attrs, [], "", []),
startOffset,
tokenLength,
startOffset + tokenLength,
leadingHtmlStart
)
);
offset = startOffset + tokenLength;
return true;
case "block-closer":
if (0 === stackDepth) {
addFreeform();
return false;
}
if (1 === stackDepth) {
addBlockFromStack(startOffset);
offset = startOffset + tokenLength;
return true;
}
const stackTop = stack.pop();
const html = document.substr(
stackTop.prevOffset,
startOffset - stackTop.prevOffset
);
stackTop.block.innerHTML += html;
stackTop.block.innerContent.push(html);
stackTop.prevOffset = startOffset + tokenLength;
addInnerBlock(
stackTop.block,
stackTop.tokenStart,
stackTop.tokenLength,
startOffset + tokenLength
);
offset = startOffset + tokenLength;
return true;
default:
addFreeform();
return false;
}
}
function parseJSON(input) {
try {
return JSON.parse(input);
} catch (e) {
return null;
}
}
function nextToken() {
const matches = tokenizer.exec(document);
if (null === matches) {
return ["no-more-tokens", "", null, 0, 0];
}
const startedAt = matches.index;
const [
match,
closerMatch,
namespaceMatch,
nameMatch,
attrsMatch,
,
voidMatch
] = matches;
const length = match.length;
const isCloser = !!closerMatch;
const isVoid = !!voidMatch;
const namespace = namespaceMatch || "core/";
const name = namespace + nameMatch;
const hasAttrs = !!attrsMatch;
const attrs = hasAttrs ? parseJSON(attrsMatch) : {};
if (isCloser && (isVoid || hasAttrs)) {
}
if (isVoid) {
return ["void-block", name, attrs, startedAt, length];
}
if (isCloser) {
return ["block-closer", name, null, startedAt, length];
}
return ["block-opener", name, attrs, startedAt, length];
}
function addFreeform(rawLength) {
const length = rawLength ? rawLength : document.length - offset;
if (0 === length) {
return;
}
output.push(Freeform(document.substr(offset, length)));
}
function addInnerBlock(block, tokenStart, tokenLength, lastOffset) {
const parent = stack[stack.length - 1];
parent.block.innerBlocks.push(block);
const html = document.substr(
parent.prevOffset,
tokenStart - parent.prevOffset
);
if (html) {
parent.block.innerHTML += html;
parent.block.innerContent.push(html);
}
parent.block.innerContent.push(null);
parent.prevOffset = lastOffset ? lastOffset : tokenStart + tokenLength;
}
function addBlockFromStack(endOffset) {
const { block, leadingHtmlStart, prevOffset, tokenStart } = stack.pop();
const html = endOffset ? document.substr(prevOffset, endOffset - prevOffset) : document.substr(prevOffset);
if (html) {
block.innerHTML += html;
block.innerContent.push(html);
}
if (null !== leadingHtmlStart) {
output.push(
Freeform(
document.substr(
leadingHtmlStart,
tokenStart - leadingHtmlStart
)
)
);
}
output.push(block);
}
export {
parse
};
//# sourceMappingURL=index.mjs.map
{
"version": 3,
"sources": ["../src/index.ts"],
"sourcesContent": ["let document: string;\nlet offset: number;\nlet output: ParsedBlock[];\nlet stack: ParsedFrame[];\n\ntype Attributes = Record< string, any > | null;\n\ntype ParsedBlock = {\n\tblockName: string | null;\n\tattrs: Attributes;\n\tinnerBlocks: ParsedBlock[];\n\tinnerHTML: string;\n\tinnerContent: Array< string | null >;\n};\n\ntype ParsedFrame = {\n\tblock: ParsedBlock;\n\ttokenStart: number;\n\ttokenLength: number;\n\tprevOffset: number;\n\tleadingHtmlStart: number | null;\n};\n\ntype TokenType =\n\t| 'no-more-tokens'\n\t| 'void-block'\n\t| 'block-opener'\n\t| 'block-closer';\n\ntype Token = [ TokenType, string, Attributes, number, number ];\n\n/**\n * Matches block comment delimiters\n *\n * While most of this pattern is straightforward the attribute parsing\n * incorporates a tricks to make sure we don't choke on specific input\n *\n * - since JavaScript has no possessive quantifier or atomic grouping\n * we are emulating it with a trick\n *\n * we want a possessive quantifier or atomic group to prevent backtracking\n * on the `}`s should we fail to match the remainder of the pattern\n *\n * we can emulate this with a positive lookahead and back reference\n * (a++)*c === ((?=(a+))\\1)*c\n *\n * let's examine an example:\n * - /(a+)*c/.test('aaaaaaaaaaaaad') fails after over 49,000 steps\n * - /(a++)*c/.test('aaaaaaaaaaaaad') fails after 85 steps\n * - /(?>a+)*c/.test('aaaaaaaaaaaaad') fails after 126 steps\n *\n * this is because the possessive `++` and the atomic group `(?>)`\n * tell the engine that all those `a`s belong together as a single group\n * and so it won't split it up when stepping backwards to try and match\n *\n * if we use /((?=(a+))\\1)*c/ then we get the same behavior as the atomic group\n * or possessive and prevent the backtracking because the `a+` is matched but\n * not captured. thus, we find the long string of `a`s and remember it, then\n * reference it as a whole unit inside our pattern\n *\n * @see http://instanceof.me/post/52245507631/regex-emulate-atomic-grouping-with-lookahead\n * @see http://blog.stevenlevithan.com/archives/mimic-atomic-groups\n * @see https://javascript.info/regexp-infinite-backtracking-problem\n *\n * once browsers reliably support atomic grouping or possessive\n * quantifiers natively we should remove this trick and simplify\n *\n * @since 3.8.0\n * @since 4.6.1 added optimization to prevent backtracking on attribute parsing\n */\nconst tokenizer =\n\t/<!--\\s+(\\/)?wp:([a-z][a-z0-9_-]*\\/)?([a-z][a-z0-9_-]*)\\s+({(?:(?=([^}]+|}+(?=})|(?!}\\s+\\/?-->)[^])*)\\5|[^]*?)}\\s+)?(\\/)?-->/g;\n\n/**\n * Constructs a block object.\n *\n * @param blockName Either the abbreviated core types, e.g. \"paragraph\", or the fully-qualified\n * block type with namespace and type, e.g. \"core/paragraph\" or \"my-plugin/csv-table\".\n * @param attrs The attributes for the block, or null if there are no attributes.\n * @param innerBlocks An array of inner blocks.\n * @param innerHTML The inner HTML of the block.\n * @param innerContent An array of inner content strings.\n * @return The block object.\n */\nfunction Block(\n\tblockName: string | null,\n\tattrs: Attributes,\n\tinnerBlocks: ParsedBlock[],\n\tinnerHTML: string,\n\tinnerContent: string[]\n): ParsedBlock {\n\treturn {\n\t\tblockName,\n\t\tattrs,\n\t\tinnerBlocks,\n\t\tinnerHTML,\n\t\tinnerContent,\n\t};\n}\n\n/**\n * Constructs a freeform block object.\n *\n * @param innerHTML The inner HTML of the block.\n * @return The freeform block object.\n */\nfunction Freeform( innerHTML: string ): ParsedBlock {\n\treturn Block( null, {}, [], innerHTML, [ innerHTML ] );\n}\n\n/**\n * Constructs a frame object.\n *\n * @param block The block object.\n * @param tokenStart The start offset of the token in the document.\n * @param tokenLength The length of the token in the document.\n * @param prevOffset The offset of the previous token in the document.\n * @param leadingHtmlStart The start offset of leading HTML before the block.\n * @return The frame object.\n */\nfunction Frame(\n\tblock: ParsedBlock,\n\ttokenStart: number,\n\ttokenLength: number,\n\tprevOffset: number | null,\n\tleadingHtmlStart: number | null\n): ParsedFrame {\n\treturn {\n\t\tblock,\n\t\ttokenStart,\n\t\ttokenLength,\n\t\tprevOffset: prevOffset || tokenStart + tokenLength,\n\t\tleadingHtmlStart,\n\t};\n}\n\n/**\n * Parser function, that converts input HTML into a block based structure.\n *\n * @param doc The HTML document to parse.\n *\n * @example\n * Input post:\n * ```html\n * <!-- wp:columns {\"columns\":3} -->\n * <div class=\"wp-block-columns has-3-columns\"><!-- wp:column -->\n * <div class=\"wp-block-column\"><!-- wp:paragraph -->\n * <p>Left</p>\n * <!-- /wp:paragraph --></div>\n * <!-- /wp:column -->\n *\n * <!-- wp:column -->\n * <div class=\"wp-block-column\"><!-- wp:paragraph -->\n * <p><strong>Middle</strong></p>\n * <!-- /wp:paragraph --></div>\n * <!-- /wp:column -->\n *\n * <!-- wp:column -->\n * <div class=\"wp-block-column\"></div>\n * <!-- /wp:column --></div>\n * <!-- /wp:columns -->\n * ```\n *\n * Parsing code:\n * ```js\n * import { parse } from '@wordpress/block-serialization-default-parser';\n *\n * parse( post ) === [\n * {\n * blockName: \"core/columns\",\n * attrs: {\n * columns: 3\n * },\n * innerBlocks: [\n * {\n * blockName: \"core/column\",\n * attrs: null,\n * innerBlocks: [\n * {\n * blockName: \"core/paragraph\",\n * attrs: null,\n * innerBlocks: [],\n * innerHTML: \"\\n<p>Left</p>\\n\"\n * }\n * ],\n * innerHTML: '\\n<div class=\"wp-block-column\"></div>\\n'\n * },\n * {\n * blockName: \"core/column\",\n * attrs: null,\n * innerBlocks: [\n * {\n * blockName: \"core/paragraph\",\n * attrs: null,\n * innerBlocks: [],\n * innerHTML: \"\\n<p><strong>Middle</strong></p>\\n\"\n * }\n * ],\n * innerHTML: '\\n<div class=\"wp-block-column\"></div>\\n'\n * },\n * {\n * blockName: \"core/column\",\n * attrs: null,\n * innerBlocks: [],\n * innerHTML: '\\n<div class=\"wp-block-column\"></div>\\n'\n * }\n * ],\n * innerHTML: '\\n<div class=\"wp-block-columns has-3-columns\">\\n\\n\\n\\n</div>\\n'\n * }\n * ];\n * ```\n * @return A block-based representation of the input HTML.\n */\nexport const parse = ( doc: string ): ParsedBlock[] => {\n\tdocument = doc;\n\toffset = 0;\n\toutput = [];\n\tstack = [];\n\ttokenizer.lastIndex = 0;\n\n\tdo {\n\t\t// twiddle our thumbs\n\t} while ( proceed() );\n\n\treturn output;\n};\n\n/**\n * Parses the next token in the input document.\n *\n * @return Returns true when there is more tokens to parse.\n */\nfunction proceed(): boolean {\n\tconst stackDepth = stack.length;\n\tconst next = nextToken();\n\tconst [ tokenType, blockName, attrs, startOffset, tokenLength ] = next;\n\n\t// We may have some HTML soup before the next block.\n\tconst leadingHtmlStart = startOffset > offset ? offset : null;\n\n\tswitch ( tokenType ) {\n\t\tcase 'no-more-tokens':\n\t\t\t// If not in a block then flush output.\n\t\t\tif ( 0 === stackDepth ) {\n\t\t\t\taddFreeform();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Otherwise we have a problem\n\t\t\t// This is an error\n\t\t\t// we have options\n\t\t\t// - treat it all as freeform text\n\t\t\t// - assume an implicit closer (easiest when not nesting)\n\n\t\t\t// For the easy case we'll assume an implicit closer.\n\t\t\tif ( 1 === stackDepth ) {\n\t\t\t\taddBlockFromStack();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// For the nested case where it's more difficult we'll\n\t\t\t// have to assume that multiple closers are missing\n\t\t\t// and so we'll collapse the whole stack piecewise.\n\t\t\twhile ( 0 < stack.length ) {\n\t\t\t\taddBlockFromStack();\n\t\t\t}\n\t\t\treturn false;\n\t\tcase 'void-block':\n\t\t\t// easy case is if we stumbled upon a void block\n\t\t\t// in the top-level of the document.\n\t\t\tif ( 0 === stackDepth ) {\n\t\t\t\tif ( null !== leadingHtmlStart ) {\n\t\t\t\t\toutput.push(\n\t\t\t\t\t\tFreeform(\n\t\t\t\t\t\t\tdocument.substr(\n\t\t\t\t\t\t\t\tleadingHtmlStart,\n\t\t\t\t\t\t\t\tstartOffset - leadingHtmlStart\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\toutput.push( Block( blockName, attrs, [], '', [] ) );\n\t\t\t\toffset = startOffset + tokenLength;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// Otherwise we found an inner block.\n\t\t\taddInnerBlock(\n\t\t\t\tBlock( blockName, attrs, [], '', [] ),\n\t\t\t\tstartOffset,\n\t\t\t\ttokenLength\n\t\t\t);\n\t\t\toffset = startOffset + tokenLength;\n\t\t\treturn true;\n\n\t\tcase 'block-opener':\n\t\t\t// Track all newly-opened blocks on the stack.\n\t\t\tstack.push(\n\t\t\t\tFrame(\n\t\t\t\t\tBlock( blockName, attrs, [], '', [] ),\n\t\t\t\t\tstartOffset,\n\t\t\t\t\ttokenLength,\n\t\t\t\t\tstartOffset + tokenLength,\n\t\t\t\t\tleadingHtmlStart\n\t\t\t\t)\n\t\t\t);\n\t\t\toffset = startOffset + tokenLength;\n\t\t\treturn true;\n\n\t\tcase 'block-closer':\n\t\t\t// If we're missing an opener we're in trouble\n\t\t\t// This is an error.\n\t\t\tif ( 0 === stackDepth ) {\n\t\t\t\t// We have options\n\t\t\t\t// - assume an implicit opener\n\t\t\t\t// - assume _this_ is the opener\n\t\t\t\t// - give up and close out the document.\n\t\t\t\taddFreeform();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// If we're not nesting then this is easy - close the block.\n\t\t\tif ( 1 === stackDepth ) {\n\t\t\t\taddBlockFromStack( startOffset );\n\t\t\t\toffset = startOffset + tokenLength;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// Otherwise we're nested and we have to close out the current\n\t\t\t// block and add it as a innerBlock to the parent.\n\t\t\tconst stackTop = stack.pop() as ParsedFrame;\n\t\t\tconst html = document.substr(\n\t\t\t\tstackTop.prevOffset,\n\t\t\t\tstartOffset - stackTop.prevOffset\n\t\t\t);\n\t\t\tstackTop.block.innerHTML += html;\n\t\t\tstackTop.block.innerContent.push( html );\n\t\t\tstackTop.prevOffset = startOffset + tokenLength;\n\n\t\t\taddInnerBlock(\n\t\t\t\tstackTop.block,\n\t\t\t\tstackTop.tokenStart,\n\t\t\t\tstackTop.tokenLength,\n\t\t\t\tstartOffset + tokenLength\n\t\t\t);\n\t\t\toffset = startOffset + tokenLength;\n\t\t\treturn true;\n\n\t\tdefault:\n\t\t\t// This is an error.\n\t\t\taddFreeform();\n\t\t\treturn false;\n\t}\n}\n\n/**\n * Parse JSON if valid, otherwise return null\n *\n * Note that JSON coming from the block comment\n * delimiters is constrained to be an object\n * and cannot be things like `true` or `null`\n *\n * @param input JSON input string to parse\n * @return parsed JSON if valid or null if invalid\n */\nfunction parseJSON( input: string ): Object | null {\n\ttry {\n\t\treturn JSON.parse( input );\n\t} catch ( e ) {\n\t\treturn null;\n\t}\n}\n\n/**\n * Finds the next token in the document.\n *\n * @return The next matched token.\n */\nfunction nextToken(): Token {\n\t// Aye the magic\n\t// we're using a single RegExp to tokenize the block comment delimiters\n\t// we're also using a trick here because the only difference between a\n\t// block opener and a block closer is the leading `/` before `wp:` (and\n\t// a closer has no attributes). we can trap them both and process the\n\t// match back in JavaScript to see which one it was.\n\tconst matches = tokenizer.exec( document );\n\n\t// We have no more tokens.\n\tif ( null === matches ) {\n\t\treturn [ 'no-more-tokens', '', null, 0, 0 ];\n\t}\n\n\tconst startedAt = matches.index;\n\tconst [\n\t\tmatch,\n\t\tcloserMatch,\n\t\tnamespaceMatch,\n\t\tnameMatch,\n\t\tattrsMatch /* Internal/unused. */,\n\t\t,\n\t\tvoidMatch,\n\t] = matches;\n\n\tconst length = match.length;\n\tconst isCloser = !! closerMatch;\n\tconst isVoid = !! voidMatch;\n\tconst namespace = namespaceMatch || 'core/';\n\tconst name = namespace + nameMatch;\n\tconst hasAttrs = !! attrsMatch;\n\tconst attrs = hasAttrs ? parseJSON( attrsMatch ) : {};\n\n\t// This state isn't allowed\n\t// This is an error.\n\tif ( isCloser && ( isVoid || hasAttrs ) ) {\n\t\t// We can ignore them since they don't hurt anything\n\t\t// we may warn against this at some point or reject it.\n\t}\n\n\tif ( isVoid ) {\n\t\treturn [ 'void-block', name, attrs, startedAt, length ];\n\t}\n\n\tif ( isCloser ) {\n\t\treturn [ 'block-closer', name, null, startedAt, length ];\n\t}\n\n\treturn [ 'block-opener', name, attrs, startedAt, length ];\n}\n\n/**\n * Adds a freeform block to the output.\n *\n * @param rawLength Optional length of the raw HTML to include as freeform content.\n */\nfunction addFreeform( rawLength?: number ) {\n\tconst length = rawLength ? rawLength : document.length - offset;\n\n\tif ( 0 === length ) {\n\t\treturn;\n\t}\n\n\toutput.push( Freeform( document.substr( offset, length ) ) );\n}\n\n/**\n * Adds inner block to the parent block.\n *\n * @param block The inner block to be added to the parent.\n * @param tokenStart The start offset of the block token in the document.\n * @param tokenLength The total length of the block token.\n * @param lastOffset Optional offset marking the end of the current block,\n * used to update the parent's HTML content boundaries.\n */\nfunction addInnerBlock(\n\tblock: ParsedBlock,\n\ttokenStart: number,\n\ttokenLength: number,\n\tlastOffset?: number\n) {\n\tconst parent = stack[ stack.length - 1 ];\n\tparent.block.innerBlocks.push( block );\n\tconst html = document.substr(\n\t\tparent.prevOffset,\n\t\ttokenStart - parent.prevOffset\n\t);\n\n\tif ( html ) {\n\t\tparent.block.innerHTML += html;\n\t\tparent.block.innerContent.push( html );\n\t}\n\n\tparent.block.innerContent.push( null );\n\tparent.prevOffset = lastOffset ? lastOffset : tokenStart + tokenLength;\n}\n\n/**\n * Adds block from the stack to the output.\n *\n * @param endOffset Optional offset marking the end of the block's HTML content.\n */\nfunction addBlockFromStack( endOffset?: number ) {\n\tconst { block, leadingHtmlStart, prevOffset, tokenStart } =\n\t\tstack.pop() as ParsedFrame;\n\n\tconst html = endOffset\n\t\t? document.substr( prevOffset, endOffset - prevOffset )\n\t\t: document.substr( prevOffset );\n\n\tif ( html ) {\n\t\tblock.innerHTML += html;\n\t\tblock.innerContent.push( html );\n\t}\n\n\tif ( null !== leadingHtmlStart ) {\n\t\toutput.push(\n\t\t\tFreeform(\n\t\t\t\tdocument.substr(\n\t\t\t\t\tleadingHtmlStart,\n\t\t\t\t\ttokenStart - leadingHtmlStart\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n\n\toutput.push( block );\n}\n"],
"mappings": "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",
"names": []
}
+1
-1
## Gutenberg
Copyright 2016-2025 by the contributors
Copyright 2016-2026 by the contributors

@@ -5,0 +5,0 @@ **License for Contributions (on and after April 15, 2021)**

{
"name": "@wordpress/block-serialization-default-parser",
"version": "5.36.1-next.738bb1424.0",
"version": "5.36.1-next.76cff8c98.0",
"description": "Block serialization specification parser for WordPress posts.",

@@ -33,9 +33,8 @@ "author": "The WordPress Contributors",

],
"type": "module",
"main": "build/index.cjs",
"module": "build-module/index.js",
"module": "build-module/index.mjs",
"exports": {
".": {
"types": "./build-types/index.d.ts",
"import": "./build-module/index.js",
"import": "./build-module/index.mjs",
"require": "./build/index.cjs"

@@ -52,3 +51,3 @@ },

},
"gitHead": "ab1b004c0d61c295aa34bc86ea07f979343983ce"
"gitHead": "368727f14b858e75179e140967c2d9ec965c8790"
}
// packages/block-serialization-default-parser/src/index.ts
var document;
var offset;
var output;
var stack;
var tokenizer = /<!--\s+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)\s+({(?:(?=([^}]+|}+(?=})|(?!}\s+\/?-->)[^])*)\5|[^]*?)}\s+)?(\/)?-->/g;
function Block(blockName, attrs, innerBlocks, innerHTML, innerContent) {
return {
blockName,
attrs,
innerBlocks,
innerHTML,
innerContent
};
}
function Freeform(innerHTML) {
return Block(null, {}, [], innerHTML, [innerHTML]);
}
function Frame(block, tokenStart, tokenLength, prevOffset, leadingHtmlStart) {
return {
block,
tokenStart,
tokenLength,
prevOffset: prevOffset || tokenStart + tokenLength,
leadingHtmlStart
};
}
var parse = (doc) => {
document = doc;
offset = 0;
output = [];
stack = [];
tokenizer.lastIndex = 0;
do {
} while (proceed());
return output;
};
function proceed() {
const stackDepth = stack.length;
const next = nextToken();
const [tokenType, blockName, attrs, startOffset, tokenLength] = next;
const leadingHtmlStart = startOffset > offset ? offset : null;
switch (tokenType) {
case "no-more-tokens":
if (0 === stackDepth) {
addFreeform();
return false;
}
if (1 === stackDepth) {
addBlockFromStack();
return false;
}
while (0 < stack.length) {
addBlockFromStack();
}
return false;
case "void-block":
if (0 === stackDepth) {
if (null !== leadingHtmlStart) {
output.push(
Freeform(
document.substr(
leadingHtmlStart,
startOffset - leadingHtmlStart
)
)
);
}
output.push(Block(blockName, attrs, [], "", []));
offset = startOffset + tokenLength;
return true;
}
addInnerBlock(
Block(blockName, attrs, [], "", []),
startOffset,
tokenLength
);
offset = startOffset + tokenLength;
return true;
case "block-opener":
stack.push(
Frame(
Block(blockName, attrs, [], "", []),
startOffset,
tokenLength,
startOffset + tokenLength,
leadingHtmlStart
)
);
offset = startOffset + tokenLength;
return true;
case "block-closer":
if (0 === stackDepth) {
addFreeform();
return false;
}
if (1 === stackDepth) {
addBlockFromStack(startOffset);
offset = startOffset + tokenLength;
return true;
}
const stackTop = stack.pop();
const html = document.substr(
stackTop.prevOffset,
startOffset - stackTop.prevOffset
);
stackTop.block.innerHTML += html;
stackTop.block.innerContent.push(html);
stackTop.prevOffset = startOffset + tokenLength;
addInnerBlock(
stackTop.block,
stackTop.tokenStart,
stackTop.tokenLength,
startOffset + tokenLength
);
offset = startOffset + tokenLength;
return true;
default:
addFreeform();
return false;
}
}
function parseJSON(input) {
try {
return JSON.parse(input);
} catch (e) {
return null;
}
}
function nextToken() {
const matches = tokenizer.exec(document);
if (null === matches) {
return ["no-more-tokens", "", null, 0, 0];
}
const startedAt = matches.index;
const [
match,
closerMatch,
namespaceMatch,
nameMatch,
attrsMatch,
,
voidMatch
] = matches;
const length = match.length;
const isCloser = !!closerMatch;
const isVoid = !!voidMatch;
const namespace = namespaceMatch || "core/";
const name = namespace + nameMatch;
const hasAttrs = !!attrsMatch;
const attrs = hasAttrs ? parseJSON(attrsMatch) : {};
if (isCloser && (isVoid || hasAttrs)) {
}
if (isVoid) {
return ["void-block", name, attrs, startedAt, length];
}
if (isCloser) {
return ["block-closer", name, null, startedAt, length];
}
return ["block-opener", name, attrs, startedAt, length];
}
function addFreeform(rawLength) {
const length = rawLength ? rawLength : document.length - offset;
if (0 === length) {
return;
}
output.push(Freeform(document.substr(offset, length)));
}
function addInnerBlock(block, tokenStart, tokenLength, lastOffset) {
const parent = stack[stack.length - 1];
parent.block.innerBlocks.push(block);
const html = document.substr(
parent.prevOffset,
tokenStart - parent.prevOffset
);
if (html) {
parent.block.innerHTML += html;
parent.block.innerContent.push(html);
}
parent.block.innerContent.push(null);
parent.prevOffset = lastOffset ? lastOffset : tokenStart + tokenLength;
}
function addBlockFromStack(endOffset) {
const { block, leadingHtmlStart, prevOffset, tokenStart } = stack.pop();
const html = endOffset ? document.substr(prevOffset, endOffset - prevOffset) : document.substr(prevOffset);
if (html) {
block.innerHTML += html;
block.innerContent.push(html);
}
if (null !== leadingHtmlStart) {
output.push(
Freeform(
document.substr(
leadingHtmlStart,
tokenStart - leadingHtmlStart
)
)
);
}
output.push(block);
}
export {
parse
};
//# sourceMappingURL=index.js.map
{
"version": 3,
"sources": ["../src/index.ts"],
"sourcesContent": ["let document: string;\nlet offset: number;\nlet output: ParsedBlock[];\nlet stack: ParsedFrame[];\n\ntype Attributes = Record< string, any > | null;\n\ntype ParsedBlock = {\n\tblockName: string | null;\n\tattrs: Attributes;\n\tinnerBlocks: ParsedBlock[];\n\tinnerHTML: string;\n\tinnerContent: Array< string | null >;\n};\n\ntype ParsedFrame = {\n\tblock: ParsedBlock;\n\ttokenStart: number;\n\ttokenLength: number;\n\tprevOffset: number;\n\tleadingHtmlStart: number | null;\n};\n\ntype TokenType =\n\t| 'no-more-tokens'\n\t| 'void-block'\n\t| 'block-opener'\n\t| 'block-closer';\n\ntype Token = [ TokenType, string, Attributes, number, number ];\n\n/**\n * Matches block comment delimiters\n *\n * While most of this pattern is straightforward the attribute parsing\n * incorporates a tricks to make sure we don't choke on specific input\n *\n * - since JavaScript has no possessive quantifier or atomic grouping\n * we are emulating it with a trick\n *\n * we want a possessive quantifier or atomic group to prevent backtracking\n * on the `}`s should we fail to match the remainder of the pattern\n *\n * we can emulate this with a positive lookahead and back reference\n * (a++)*c === ((?=(a+))\\1)*c\n *\n * let's examine an example:\n * - /(a+)*c/.test('aaaaaaaaaaaaad') fails after over 49,000 steps\n * - /(a++)*c/.test('aaaaaaaaaaaaad') fails after 85 steps\n * - /(?>a+)*c/.test('aaaaaaaaaaaaad') fails after 126 steps\n *\n * this is because the possessive `++` and the atomic group `(?>)`\n * tell the engine that all those `a`s belong together as a single group\n * and so it won't split it up when stepping backwards to try and match\n *\n * if we use /((?=(a+))\\1)*c/ then we get the same behavior as the atomic group\n * or possessive and prevent the backtracking because the `a+` is matched but\n * not captured. thus, we find the long string of `a`s and remember it, then\n * reference it as a whole unit inside our pattern\n *\n * @see http://instanceof.me/post/52245507631/regex-emulate-atomic-grouping-with-lookahead\n * @see http://blog.stevenlevithan.com/archives/mimic-atomic-groups\n * @see https://javascript.info/regexp-infinite-backtracking-problem\n *\n * once browsers reliably support atomic grouping or possessive\n * quantifiers natively we should remove this trick and simplify\n *\n * @since 3.8.0\n * @since 4.6.1 added optimization to prevent backtracking on attribute parsing\n */\nconst tokenizer =\n\t/<!--\\s+(\\/)?wp:([a-z][a-z0-9_-]*\\/)?([a-z][a-z0-9_-]*)\\s+({(?:(?=([^}]+|}+(?=})|(?!}\\s+\\/?-->)[^])*)\\5|[^]*?)}\\s+)?(\\/)?-->/g;\n\n/**\n * Constructs a block object.\n *\n * @param blockName Either the abbreviated core types, e.g. \"paragraph\", or the fully-qualified\n * block type with namespace and type, e.g. \"core/paragraph\" or \"my-plugin/csv-table\".\n * @param attrs The attributes for the block, or null if there are no attributes.\n * @param innerBlocks An array of inner blocks.\n * @param innerHTML The inner HTML of the block.\n * @param innerContent An array of inner content strings.\n * @return The block object.\n */\nfunction Block(\n\tblockName: string | null,\n\tattrs: Attributes,\n\tinnerBlocks: ParsedBlock[],\n\tinnerHTML: string,\n\tinnerContent: string[]\n): ParsedBlock {\n\treturn {\n\t\tblockName,\n\t\tattrs,\n\t\tinnerBlocks,\n\t\tinnerHTML,\n\t\tinnerContent,\n\t};\n}\n\n/**\n * Constructs a freeform block object.\n *\n * @param innerHTML The inner HTML of the block.\n * @return The freeform block object.\n */\nfunction Freeform( innerHTML: string ): ParsedBlock {\n\treturn Block( null, {}, [], innerHTML, [ innerHTML ] );\n}\n\n/**\n * Constructs a frame object.\n *\n * @param block The block object.\n * @param tokenStart The start offset of the token in the document.\n * @param tokenLength The length of the token in the document.\n * @param prevOffset The offset of the previous token in the document.\n * @param leadingHtmlStart The start offset of leading HTML before the block.\n * @return The frame object.\n */\nfunction Frame(\n\tblock: ParsedBlock,\n\ttokenStart: number,\n\ttokenLength: number,\n\tprevOffset: number | null,\n\tleadingHtmlStart: number | null\n): ParsedFrame {\n\treturn {\n\t\tblock,\n\t\ttokenStart,\n\t\ttokenLength,\n\t\tprevOffset: prevOffset || tokenStart + tokenLength,\n\t\tleadingHtmlStart,\n\t};\n}\n\n/**\n * Parser function, that converts input HTML into a block based structure.\n *\n * @param doc The HTML document to parse.\n *\n * @example\n * Input post:\n * ```html\n * <!-- wp:columns {\"columns\":3} -->\n * <div class=\"wp-block-columns has-3-columns\"><!-- wp:column -->\n * <div class=\"wp-block-column\"><!-- wp:paragraph -->\n * <p>Left</p>\n * <!-- /wp:paragraph --></div>\n * <!-- /wp:column -->\n *\n * <!-- wp:column -->\n * <div class=\"wp-block-column\"><!-- wp:paragraph -->\n * <p><strong>Middle</strong></p>\n * <!-- /wp:paragraph --></div>\n * <!-- /wp:column -->\n *\n * <!-- wp:column -->\n * <div class=\"wp-block-column\"></div>\n * <!-- /wp:column --></div>\n * <!-- /wp:columns -->\n * ```\n *\n * Parsing code:\n * ```js\n * import { parse } from '@wordpress/block-serialization-default-parser';\n *\n * parse( post ) === [\n * {\n * blockName: \"core/columns\",\n * attrs: {\n * columns: 3\n * },\n * innerBlocks: [\n * {\n * blockName: \"core/column\",\n * attrs: null,\n * innerBlocks: [\n * {\n * blockName: \"core/paragraph\",\n * attrs: null,\n * innerBlocks: [],\n * innerHTML: \"\\n<p>Left</p>\\n\"\n * }\n * ],\n * innerHTML: '\\n<div class=\"wp-block-column\"></div>\\n'\n * },\n * {\n * blockName: \"core/column\",\n * attrs: null,\n * innerBlocks: [\n * {\n * blockName: \"core/paragraph\",\n * attrs: null,\n * innerBlocks: [],\n * innerHTML: \"\\n<p><strong>Middle</strong></p>\\n\"\n * }\n * ],\n * innerHTML: '\\n<div class=\"wp-block-column\"></div>\\n'\n * },\n * {\n * blockName: \"core/column\",\n * attrs: null,\n * innerBlocks: [],\n * innerHTML: '\\n<div class=\"wp-block-column\"></div>\\n'\n * }\n * ],\n * innerHTML: '\\n<div class=\"wp-block-columns has-3-columns\">\\n\\n\\n\\n</div>\\n'\n * }\n * ];\n * ```\n * @return A block-based representation of the input HTML.\n */\nexport const parse = ( doc: string ): ParsedBlock[] => {\n\tdocument = doc;\n\toffset = 0;\n\toutput = [];\n\tstack = [];\n\ttokenizer.lastIndex = 0;\n\n\tdo {\n\t\t// twiddle our thumbs\n\t} while ( proceed() );\n\n\treturn output;\n};\n\n/**\n * Parses the next token in the input document.\n *\n * @return Returns true when there is more tokens to parse.\n */\nfunction proceed(): boolean {\n\tconst stackDepth = stack.length;\n\tconst next = nextToken();\n\tconst [ tokenType, blockName, attrs, startOffset, tokenLength ] = next;\n\n\t// We may have some HTML soup before the next block.\n\tconst leadingHtmlStart = startOffset > offset ? offset : null;\n\n\tswitch ( tokenType ) {\n\t\tcase 'no-more-tokens':\n\t\t\t// If not in a block then flush output.\n\t\t\tif ( 0 === stackDepth ) {\n\t\t\t\taddFreeform();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Otherwise we have a problem\n\t\t\t// This is an error\n\t\t\t// we have options\n\t\t\t// - treat it all as freeform text\n\t\t\t// - assume an implicit closer (easiest when not nesting)\n\n\t\t\t// For the easy case we'll assume an implicit closer.\n\t\t\tif ( 1 === stackDepth ) {\n\t\t\t\taddBlockFromStack();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// For the nested case where it's more difficult we'll\n\t\t\t// have to assume that multiple closers are missing\n\t\t\t// and so we'll collapse the whole stack piecewise.\n\t\t\twhile ( 0 < stack.length ) {\n\t\t\t\taddBlockFromStack();\n\t\t\t}\n\t\t\treturn false;\n\t\tcase 'void-block':\n\t\t\t// easy case is if we stumbled upon a void block\n\t\t\t// in the top-level of the document.\n\t\t\tif ( 0 === stackDepth ) {\n\t\t\t\tif ( null !== leadingHtmlStart ) {\n\t\t\t\t\toutput.push(\n\t\t\t\t\t\tFreeform(\n\t\t\t\t\t\t\tdocument.substr(\n\t\t\t\t\t\t\t\tleadingHtmlStart,\n\t\t\t\t\t\t\t\tstartOffset - leadingHtmlStart\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\toutput.push( Block( blockName, attrs, [], '', [] ) );\n\t\t\t\toffset = startOffset + tokenLength;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// Otherwise we found an inner block.\n\t\t\taddInnerBlock(\n\t\t\t\tBlock( blockName, attrs, [], '', [] ),\n\t\t\t\tstartOffset,\n\t\t\t\ttokenLength\n\t\t\t);\n\t\t\toffset = startOffset + tokenLength;\n\t\t\treturn true;\n\n\t\tcase 'block-opener':\n\t\t\t// Track all newly-opened blocks on the stack.\n\t\t\tstack.push(\n\t\t\t\tFrame(\n\t\t\t\t\tBlock( blockName, attrs, [], '', [] ),\n\t\t\t\t\tstartOffset,\n\t\t\t\t\ttokenLength,\n\t\t\t\t\tstartOffset + tokenLength,\n\t\t\t\t\tleadingHtmlStart\n\t\t\t\t)\n\t\t\t);\n\t\t\toffset = startOffset + tokenLength;\n\t\t\treturn true;\n\n\t\tcase 'block-closer':\n\t\t\t// If we're missing an opener we're in trouble\n\t\t\t// This is an error.\n\t\t\tif ( 0 === stackDepth ) {\n\t\t\t\t// We have options\n\t\t\t\t// - assume an implicit opener\n\t\t\t\t// - assume _this_ is the opener\n\t\t\t\t// - give up and close out the document.\n\t\t\t\taddFreeform();\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// If we're not nesting then this is easy - close the block.\n\t\t\tif ( 1 === stackDepth ) {\n\t\t\t\taddBlockFromStack( startOffset );\n\t\t\t\toffset = startOffset + tokenLength;\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// Otherwise we're nested and we have to close out the current\n\t\t\t// block and add it as a innerBlock to the parent.\n\t\t\tconst stackTop = stack.pop() as ParsedFrame;\n\t\t\tconst html = document.substr(\n\t\t\t\tstackTop.prevOffset,\n\t\t\t\tstartOffset - stackTop.prevOffset\n\t\t\t);\n\t\t\tstackTop.block.innerHTML += html;\n\t\t\tstackTop.block.innerContent.push( html );\n\t\t\tstackTop.prevOffset = startOffset + tokenLength;\n\n\t\t\taddInnerBlock(\n\t\t\t\tstackTop.block,\n\t\t\t\tstackTop.tokenStart,\n\t\t\t\tstackTop.tokenLength,\n\t\t\t\tstartOffset + tokenLength\n\t\t\t);\n\t\t\toffset = startOffset + tokenLength;\n\t\t\treturn true;\n\n\t\tdefault:\n\t\t\t// This is an error.\n\t\t\taddFreeform();\n\t\t\treturn false;\n\t}\n}\n\n/**\n * Parse JSON if valid, otherwise return null\n *\n * Note that JSON coming from the block comment\n * delimiters is constrained to be an object\n * and cannot be things like `true` or `null`\n *\n * @param input JSON input string to parse\n * @return parsed JSON if valid or null if invalid\n */\nfunction parseJSON( input: string ): Object | null {\n\ttry {\n\t\treturn JSON.parse( input );\n\t} catch ( e ) {\n\t\treturn null;\n\t}\n}\n\n/**\n * Finds the next token in the document.\n *\n * @return The next matched token.\n */\nfunction nextToken(): Token {\n\t// Aye the magic\n\t// we're using a single RegExp to tokenize the block comment delimiters\n\t// we're also using a trick here because the only difference between a\n\t// block opener and a block closer is the leading `/` before `wp:` (and\n\t// a closer has no attributes). we can trap them both and process the\n\t// match back in JavaScript to see which one it was.\n\tconst matches = tokenizer.exec( document );\n\n\t// We have no more tokens.\n\tif ( null === matches ) {\n\t\treturn [ 'no-more-tokens', '', null, 0, 0 ];\n\t}\n\n\tconst startedAt = matches.index;\n\tconst [\n\t\tmatch,\n\t\tcloserMatch,\n\t\tnamespaceMatch,\n\t\tnameMatch,\n\t\tattrsMatch /* Internal/unused. */,\n\t\t,\n\t\tvoidMatch,\n\t] = matches;\n\n\tconst length = match.length;\n\tconst isCloser = !! closerMatch;\n\tconst isVoid = !! voidMatch;\n\tconst namespace = namespaceMatch || 'core/';\n\tconst name = namespace + nameMatch;\n\tconst hasAttrs = !! attrsMatch;\n\tconst attrs = hasAttrs ? parseJSON( attrsMatch ) : {};\n\n\t// This state isn't allowed\n\t// This is an error.\n\tif ( isCloser && ( isVoid || hasAttrs ) ) {\n\t\t// We can ignore them since they don't hurt anything\n\t\t// we may warn against this at some point or reject it.\n\t}\n\n\tif ( isVoid ) {\n\t\treturn [ 'void-block', name, attrs, startedAt, length ];\n\t}\n\n\tif ( isCloser ) {\n\t\treturn [ 'block-closer', name, null, startedAt, length ];\n\t}\n\n\treturn [ 'block-opener', name, attrs, startedAt, length ];\n}\n\n/**\n * Adds a freeform block to the output.\n *\n * @param rawLength Optional length of the raw HTML to include as freeform content.\n */\nfunction addFreeform( rawLength?: number ) {\n\tconst length = rawLength ? rawLength : document.length - offset;\n\n\tif ( 0 === length ) {\n\t\treturn;\n\t}\n\n\toutput.push( Freeform( document.substr( offset, length ) ) );\n}\n\n/**\n * Adds inner block to the parent block.\n *\n * @param block The inner block to be added to the parent.\n * @param tokenStart The start offset of the block token in the document.\n * @param tokenLength The total length of the block token.\n * @param lastOffset Optional offset marking the end of the current block,\n * used to update the parent's HTML content boundaries.\n */\nfunction addInnerBlock(\n\tblock: ParsedBlock,\n\ttokenStart: number,\n\ttokenLength: number,\n\tlastOffset?: number\n) {\n\tconst parent = stack[ stack.length - 1 ];\n\tparent.block.innerBlocks.push( block );\n\tconst html = document.substr(\n\t\tparent.prevOffset,\n\t\ttokenStart - parent.prevOffset\n\t);\n\n\tif ( html ) {\n\t\tparent.block.innerHTML += html;\n\t\tparent.block.innerContent.push( html );\n\t}\n\n\tparent.block.innerContent.push( null );\n\tparent.prevOffset = lastOffset ? lastOffset : tokenStart + tokenLength;\n}\n\n/**\n * Adds block from the stack to the output.\n *\n * @param endOffset Optional offset marking the end of the block's HTML content.\n */\nfunction addBlockFromStack( endOffset?: number ) {\n\tconst { block, leadingHtmlStart, prevOffset, tokenStart } =\n\t\tstack.pop() as ParsedFrame;\n\n\tconst html = endOffset\n\t\t? document.substr( prevOffset, endOffset - prevOffset )\n\t\t: document.substr( prevOffset );\n\n\tif ( html ) {\n\t\tblock.innerHTML += html;\n\t\tblock.innerContent.push( html );\n\t}\n\n\tif ( null !== leadingHtmlStart ) {\n\t\toutput.push(\n\t\t\tFreeform(\n\t\t\t\tdocument.substr(\n\t\t\t\t\tleadingHtmlStart,\n\t\t\t\t\ttokenStart - leadingHtmlStart\n\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n\n\toutput.push( block );\n}\n"],
"mappings": "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",
"names": []
}