angelovcom.net

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

block-serialization-default-parser.js (15053B)


      1 this["wp"] = this["wp"] || {}; this["wp"]["blockSerializationDefaultParser"] =
      2 /******/ (function(modules) { // webpackBootstrap
      3 /******/ 	// The module cache
      4 /******/ 	var installedModules = {};
      5 /******/
      6 /******/ 	// The require function
      7 /******/ 	function __webpack_require__(moduleId) {
      8 /******/
      9 /******/ 		// Check if module is in cache
     10 /******/ 		if(installedModules[moduleId]) {
     11 /******/ 			return installedModules[moduleId].exports;
     12 /******/ 		}
     13 /******/ 		// Create a new module (and put it into the cache)
     14 /******/ 		var module = installedModules[moduleId] = {
     15 /******/ 			i: moduleId,
     16 /******/ 			l: false,
     17 /******/ 			exports: {}
     18 /******/ 		};
     19 /******/
     20 /******/ 		// Execute the module function
     21 /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
     22 /******/
     23 /******/ 		// Flag the module as loaded
     24 /******/ 		module.l = true;
     25 /******/
     26 /******/ 		// Return the exports of the module
     27 /******/ 		return module.exports;
     28 /******/ 	}
     29 /******/
     30 /******/
     31 /******/ 	// expose the modules object (__webpack_modules__)
     32 /******/ 	__webpack_require__.m = modules;
     33 /******/
     34 /******/ 	// expose the module cache
     35 /******/ 	__webpack_require__.c = installedModules;
     36 /******/
     37 /******/ 	// define getter function for harmony exports
     38 /******/ 	__webpack_require__.d = function(exports, name, getter) {
     39 /******/ 		if(!__webpack_require__.o(exports, name)) {
     40 /******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
     41 /******/ 		}
     42 /******/ 	};
     43 /******/
     44 /******/ 	// define __esModule on exports
     45 /******/ 	__webpack_require__.r = function(exports) {
     46 /******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
     47 /******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
     48 /******/ 		}
     49 /******/ 		Object.defineProperty(exports, '__esModule', { value: true });
     50 /******/ 	};
     51 /******/
     52 /******/ 	// create a fake namespace object
     53 /******/ 	// mode & 1: value is a module id, require it
     54 /******/ 	// mode & 2: merge all properties of value into the ns
     55 /******/ 	// mode & 4: return value when already ns object
     56 /******/ 	// mode & 8|1: behave like require
     57 /******/ 	__webpack_require__.t = function(value, mode) {
     58 /******/ 		if(mode & 1) value = __webpack_require__(value);
     59 /******/ 		if(mode & 8) return value;
     60 /******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
     61 /******/ 		var ns = Object.create(null);
     62 /******/ 		__webpack_require__.r(ns);
     63 /******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
     64 /******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
     65 /******/ 		return ns;
     66 /******/ 	};
     67 /******/
     68 /******/ 	// getDefaultExport function for compatibility with non-harmony modules
     69 /******/ 	__webpack_require__.n = function(module) {
     70 /******/ 		var getter = module && module.__esModule ?
     71 /******/ 			function getDefault() { return module['default']; } :
     72 /******/ 			function getModuleExports() { return module; };
     73 /******/ 		__webpack_require__.d(getter, 'a', getter);
     74 /******/ 		return getter;
     75 /******/ 	};
     76 /******/
     77 /******/ 	// Object.prototype.hasOwnProperty.call
     78 /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
     79 /******/
     80 /******/ 	// __webpack_public_path__
     81 /******/ 	__webpack_require__.p = "";
     82 /******/
     83 /******/
     84 /******/ 	// Load entry module and return exports
     85 /******/ 	return __webpack_require__(__webpack_require__.s = "SiJt");
     86 /******/ })
     87 /************************************************************************/
     88 /******/ ({
     89 
     90 /***/ "SiJt":
     91 /***/ (function(module, __webpack_exports__, __webpack_require__) {
     92 
     93 "use strict";
     94 __webpack_require__.r(__webpack_exports__);
     95 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parse", function() { return parse; });
     96 let document;
     97 let offset;
     98 let output;
     99 let stack;
    100 /**
    101  * Matches block comment delimiters
    102  *
    103  * While most of this pattern is straightforward the attribute parsing
    104  * incorporates a tricks to make sure we don't choke on specific input
    105  *
    106  *  - since JavaScript has no possessive quantifier or atomic grouping
    107  *    we are emulating it with a trick
    108  *
    109  *    we want a possessive quantifier or atomic group to prevent backtracking
    110  *    on the `}`s should we fail to match the remainder of the pattern
    111  *
    112  *    we can emulate this with a positive lookahead and back reference
    113  *    (a++)*c === ((?=(a+))\1)*c
    114  *
    115  *    let's examine an example:
    116  *      - /(a+)*c/.test('aaaaaaaaaaaaad') fails after over 49,000 steps
    117  *      - /(a++)*c/.test('aaaaaaaaaaaaad') fails after 85 steps
    118  *      - /(?>a+)*c/.test('aaaaaaaaaaaaad') fails after 126 steps
    119  *
    120  *    this is because the possessive `++` and the atomic group `(?>)`
    121  *    tell the engine that all those `a`s belong together as a single group
    122  *    and so it won't split it up when stepping backwards to try and match
    123  *
    124  *    if we use /((?=(a+))\1)*c/ then we get the same behavior as the atomic group
    125  *    or possessive and prevent the backtracking because the `a+` is matched but
    126  *    not captured. thus, we find the long string of `a`s and remember it, then
    127  *    reference it as a whole unit inside our pattern
    128  *
    129  *    @see http://instanceof.me/post/52245507631/regex-emulate-atomic-grouping-with-lookahead
    130  *    @see http://blog.stevenlevithan.com/archives/mimic-atomic-groups
    131  *    @see https://javascript.info/regexp-infinite-backtracking-problem
    132  *
    133  *    once browsers reliably support atomic grouping or possessive
    134  *    quantifiers natively we should remove this trick and simplify
    135  *
    136  * @type {RegExp}
    137  *
    138  * @since 3.8.0
    139  * @since 4.6.1 added optimization to prevent backtracking on attribute parsing
    140  */
    141 
    142 const tokenizer = /<!--\s+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)\s+({(?:(?=([^}]+|}+(?=})|(?!}\s+\/?-->)[^])*)\5|[^]*?)}\s+)?(\/)?-->/g;
    143 
    144 function Block(blockName, attrs, innerBlocks, innerHTML, innerContent) {
    145   return {
    146     blockName,
    147     attrs,
    148     innerBlocks,
    149     innerHTML,
    150     innerContent
    151   };
    152 }
    153 
    154 function Freeform(innerHTML) {
    155   return Block(null, {}, [], innerHTML, [innerHTML]);
    156 }
    157 
    158 function Frame(block, tokenStart, tokenLength, prevOffset, leadingHtmlStart) {
    159   return {
    160     block,
    161     tokenStart,
    162     tokenLength,
    163     prevOffset: prevOffset || tokenStart + tokenLength,
    164     leadingHtmlStart
    165   };
    166 }
    167 /**
    168  * Parser function, that converts input HTML into a block based structure.
    169  *
    170  * @param {string} doc The HTML document to parse.
    171  *
    172  * @example
    173  * Input post:
    174  * ```html
    175  * <!-- wp:columns {"columns":3} -->
    176  * <div class="wp-block-columns has-3-columns"><!-- wp:column -->
    177  * <div class="wp-block-column"><!-- wp:paragraph -->
    178  * <p>Left</p>
    179  * <!-- /wp:paragraph --></div>
    180  * <!-- /wp:column -->
    181  *
    182  * <!-- wp:column -->
    183  * <div class="wp-block-column"><!-- wp:paragraph -->
    184  * <p><strong>Middle</strong></p>
    185  * <!-- /wp:paragraph --></div>
    186  * <!-- /wp:column -->
    187  *
    188  * <!-- wp:column -->
    189  * <div class="wp-block-column"></div>
    190  * <!-- /wp:column --></div>
    191  * <!-- /wp:columns -->
    192  * ```
    193  *
    194  * Parsing code:
    195  * ```js
    196  * import { parse } from '@wordpress/block-serialization-default-parser';
    197  *
    198  * parse( post ) === [
    199  *     {
    200  *         blockName: "core/columns",
    201  *         attrs: {
    202  *             columns: 3
    203  *         },
    204  *         innerBlocks: [
    205  *             {
    206  *                 blockName: "core/column",
    207  *                 attrs: null,
    208  *                 innerBlocks: [
    209  *                     {
    210  *                         blockName: "core/paragraph",
    211  *                         attrs: null,
    212  *                         innerBlocks: [],
    213  *                         innerHTML: "\n<p>Left</p>\n"
    214  *                     }
    215  *                 ],
    216  *                 innerHTML: '\n<div class="wp-block-column"></div>\n'
    217  *             },
    218  *             {
    219  *                 blockName: "core/column",
    220  *                 attrs: null,
    221  *                 innerBlocks: [
    222  *                     {
    223  *                         blockName: "core/paragraph",
    224  *                         attrs: null,
    225  *                         innerBlocks: [],
    226  *                         innerHTML: "\n<p><strong>Middle</strong></p>\n"
    227  *                     }
    228  *                 ],
    229  *                 innerHTML: '\n<div class="wp-block-column"></div>\n'
    230  *             },
    231  *             {
    232  *                 blockName: "core/column",
    233  *                 attrs: null,
    234  *                 innerBlocks: [],
    235  *                 innerHTML: '\n<div class="wp-block-column"></div>\n'
    236  *             }
    237  *         ],
    238  *         innerHTML: '\n<div class="wp-block-columns has-3-columns">\n\n\n\n</div>\n'
    239  *     }
    240  * ];
    241  * ```
    242  * @return {Array} A block-based representation of the input HTML.
    243  */
    244 
    245 
    246 const parse = doc => {
    247   document = doc;
    248   offset = 0;
    249   output = [];
    250   stack = [];
    251   tokenizer.lastIndex = 0;
    252 
    253   do {// twiddle our thumbs
    254   } while (proceed());
    255 
    256   return output;
    257 };
    258 
    259 function proceed() {
    260   const next = nextToken();
    261   const [tokenType, blockName, attrs, startOffset, tokenLength] = next;
    262   const stackDepth = stack.length; // we may have some HTML soup before the next block
    263 
    264   const leadingHtmlStart = startOffset > offset ? offset : null;
    265 
    266   switch (tokenType) {
    267     case 'no-more-tokens':
    268       // if not in a block then flush output
    269       if (0 === stackDepth) {
    270         addFreeform();
    271         return false;
    272       } // Otherwise we have a problem
    273       // This is an error
    274       // we have options
    275       //  - treat it all as freeform text
    276       //  - assume an implicit closer (easiest when not nesting)
    277       // for the easy case we'll assume an implicit closer
    278 
    279 
    280       if (1 === stackDepth) {
    281         addBlockFromStack();
    282         return false;
    283       } // for the nested case where it's more difficult we'll
    284       // have to assume that multiple closers are missing
    285       // and so we'll collapse the whole stack piecewise
    286 
    287 
    288       while (0 < stack.length) {
    289         addBlockFromStack();
    290       }
    291 
    292       return false;
    293 
    294     case 'void-block':
    295       // easy case is if we stumbled upon a void block
    296       // in the top-level of the document
    297       if (0 === stackDepth) {
    298         if (null !== leadingHtmlStart) {
    299           output.push(Freeform(document.substr(leadingHtmlStart, startOffset - leadingHtmlStart)));
    300         }
    301 
    302         output.push(Block(blockName, attrs, [], '', []));
    303         offset = startOffset + tokenLength;
    304         return true;
    305       } // otherwise we found an inner block
    306 
    307 
    308       addInnerBlock(Block(blockName, attrs, [], '', []), startOffset, tokenLength);
    309       offset = startOffset + tokenLength;
    310       return true;
    311 
    312     case 'block-opener':
    313       // track all newly-opened blocks on the stack
    314       stack.push(Frame(Block(blockName, attrs, [], '', []), startOffset, tokenLength, startOffset + tokenLength, leadingHtmlStart));
    315       offset = startOffset + tokenLength;
    316       return true;
    317 
    318     case 'block-closer':
    319       // if we're missing an opener we're in trouble
    320       // This is an error
    321       if (0 === stackDepth) {
    322         // we have options
    323         //  - assume an implicit opener
    324         //  - assume _this_ is the opener
    325         //  - give up and close out the document
    326         addFreeform();
    327         return false;
    328       } // if we're not nesting then this is easy - close the block
    329 
    330 
    331       if (1 === stackDepth) {
    332         addBlockFromStack(startOffset);
    333         offset = startOffset + tokenLength;
    334         return true;
    335       } // otherwise we're nested and we have to close out the current
    336       // block and add it as a innerBlock to the parent
    337 
    338 
    339       const stackTop = stack.pop();
    340       const html = document.substr(stackTop.prevOffset, startOffset - stackTop.prevOffset);
    341       stackTop.block.innerHTML += html;
    342       stackTop.block.innerContent.push(html);
    343       stackTop.prevOffset = startOffset + tokenLength;
    344       addInnerBlock(stackTop.block, stackTop.tokenStart, stackTop.tokenLength, startOffset + tokenLength);
    345       offset = startOffset + tokenLength;
    346       return true;
    347 
    348     default:
    349       // This is an error
    350       addFreeform();
    351       return false;
    352   }
    353 }
    354 /**
    355  * Parse JSON if valid, otherwise return null
    356  *
    357  * Note that JSON coming from the block comment
    358  * delimiters is constrained to be an object
    359  * and cannot be things like `true` or `null`
    360  *
    361  * @param {string} input JSON input string to parse
    362  * @return {Object|null} parsed JSON if valid
    363  */
    364 
    365 
    366 function parseJSON(input) {
    367   try {
    368     return JSON.parse(input);
    369   } catch (e) {
    370     return null;
    371   }
    372 }
    373 
    374 function nextToken() {
    375   // aye the magic
    376   // we're using a single RegExp to tokenize the block comment delimiters
    377   // we're also using a trick here because the only difference between a
    378   // block opener and a block closer is the leading `/` before `wp:` (and
    379   // a closer has no attributes). we can trap them both and process the
    380   // match back in JavaScript to see which one it was.
    381   const matches = tokenizer.exec(document); // we have no more tokens
    382 
    383   if (null === matches) {
    384     return ['no-more-tokens'];
    385   }
    386 
    387   const startedAt = matches.index;
    388   const [match, closerMatch, namespaceMatch, nameMatch, attrsMatch
    389   /* internal/unused */
    390   ,, voidMatch] = matches;
    391   const length = match.length;
    392   const isCloser = !!closerMatch;
    393   const isVoid = !!voidMatch;
    394   const namespace = namespaceMatch || 'core/';
    395   const name = namespace + nameMatch;
    396   const hasAttrs = !!attrsMatch;
    397   const attrs = hasAttrs ? parseJSON(attrsMatch) : {}; // This state isn't allowed
    398   // This is an error
    399 
    400   if (isCloser && (isVoid || hasAttrs)) {// we can ignore them since they don't hurt anything
    401     // we may warn against this at some point or reject it
    402   }
    403 
    404   if (isVoid) {
    405     return ['void-block', name, attrs, startedAt, length];
    406   }
    407 
    408   if (isCloser) {
    409     return ['block-closer', name, null, startedAt, length];
    410   }
    411 
    412   return ['block-opener', name, attrs, startedAt, length];
    413 }
    414 
    415 function addFreeform(rawLength) {
    416   const length = rawLength ? rawLength : document.length - offset;
    417 
    418   if (0 === length) {
    419     return;
    420   }
    421 
    422   output.push(Freeform(document.substr(offset, length)));
    423 }
    424 
    425 function addInnerBlock(block, tokenStart, tokenLength, lastOffset) {
    426   const parent = stack[stack.length - 1];
    427   parent.block.innerBlocks.push(block);
    428   const html = document.substr(parent.prevOffset, tokenStart - parent.prevOffset);
    429 
    430   if (html) {
    431     parent.block.innerHTML += html;
    432     parent.block.innerContent.push(html);
    433   }
    434 
    435   parent.block.innerContent.push(null);
    436   parent.prevOffset = lastOffset ? lastOffset : tokenStart + tokenLength;
    437 }
    438 
    439 function addBlockFromStack(endOffset) {
    440   const {
    441     block,
    442     leadingHtmlStart,
    443     prevOffset,
    444     tokenStart
    445   } = stack.pop();
    446   const html = endOffset ? document.substr(prevOffset, endOffset - prevOffset) : document.substr(prevOffset);
    447 
    448   if (html) {
    449     block.innerHTML += html;
    450     block.innerContent.push(html);
    451   }
    452 
    453   if (null !== leadingHtmlStart) {
    454     output.push(Freeform(document.substr(leadingHtmlStart, tokenStart - leadingHtmlStart)));
    455   }
    456 
    457   output.push(block);
    458 }
    459 
    460 
    461 /***/ })
    462 
    463 /******/ });