[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/dist/ -> block-serialization-default-parser.js (source)

   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  /******/ });


Generated : Sat Sep 25 08:20:02 2021 Cross-referenced by PHPXref