@wordpress/block-serialization-default-parser 5.32.0 → 5.32.1-next.47f435fc9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.js +91 -269
- package/build/index.js.map +7 -1
- package/build-module/index.js +69 -264
- package/build-module/index.js.map +7 -1
- package/package.json +10 -5
package/build/index.js
CHANGED
|
@@ -1,65 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.
|
|
4
|
-
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var index_exports = {};
|
|
20
|
+
__export(index_exports, {
|
|
21
|
+
parse: () => parse
|
|
5
22
|
});
|
|
6
|
-
exports
|
|
23
|
+
module.exports = __toCommonJS(index_exports);
|
|
7
24
|
let document;
|
|
8
25
|
let offset;
|
|
9
26
|
let output;
|
|
10
27
|
let stack;
|
|
11
|
-
/**
|
|
12
|
-
* Matches block comment delimiters
|
|
13
|
-
*
|
|
14
|
-
* While most of this pattern is straightforward the attribute parsing
|
|
15
|
-
* incorporates a tricks to make sure we don't choke on specific input
|
|
16
|
-
*
|
|
17
|
-
* - since JavaScript has no possessive quantifier or atomic grouping
|
|
18
|
-
* we are emulating it with a trick
|
|
19
|
-
*
|
|
20
|
-
* we want a possessive quantifier or atomic group to prevent backtracking
|
|
21
|
-
* on the `}`s should we fail to match the remainder of the pattern
|
|
22
|
-
*
|
|
23
|
-
* we can emulate this with a positive lookahead and back reference
|
|
24
|
-
* (a++)*c === ((?=(a+))\1)*c
|
|
25
|
-
*
|
|
26
|
-
* let's examine an example:
|
|
27
|
-
* - /(a+)*c/.test('aaaaaaaaaaaaad') fails after over 49,000 steps
|
|
28
|
-
* - /(a++)*c/.test('aaaaaaaaaaaaad') fails after 85 steps
|
|
29
|
-
* - /(?>a+)*c/.test('aaaaaaaaaaaaad') fails after 126 steps
|
|
30
|
-
*
|
|
31
|
-
* this is because the possessive `++` and the atomic group `(?>)`
|
|
32
|
-
* tell the engine that all those `a`s belong together as a single group
|
|
33
|
-
* and so it won't split it up when stepping backwards to try and match
|
|
34
|
-
*
|
|
35
|
-
* if we use /((?=(a+))\1)*c/ then we get the same behavior as the atomic group
|
|
36
|
-
* or possessive and prevent the backtracking because the `a+` is matched but
|
|
37
|
-
* not captured. thus, we find the long string of `a`s and remember it, then
|
|
38
|
-
* reference it as a whole unit inside our pattern
|
|
39
|
-
*
|
|
40
|
-
* @see http://instanceof.me/post/52245507631/regex-emulate-atomic-grouping-with-lookahead
|
|
41
|
-
* @see http://blog.stevenlevithan.com/archives/mimic-atomic-groups
|
|
42
|
-
* @see https://javascript.info/regexp-infinite-backtracking-problem
|
|
43
|
-
*
|
|
44
|
-
* once browsers reliably support atomic grouping or possessive
|
|
45
|
-
* quantifiers natively we should remove this trick and simplify
|
|
46
|
-
*
|
|
47
|
-
* @since 3.8.0
|
|
48
|
-
* @since 4.6.1 added optimization to prevent backtracking on attribute parsing
|
|
49
|
-
*/
|
|
50
28
|
const tokenizer = /<!--\s+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)\s+({(?:(?=([^}]+|}+(?=})|(?!}\s+\/?-->)[^])*)\5|[^]*?)}\s+)?(\/)?-->/g;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Constructs a block object.
|
|
54
|
-
*
|
|
55
|
-
* @param blockName Either the abbreviated core types, e.g. "paragraph", or the fully-qualified
|
|
56
|
-
* block type with namespace and type, e.g. "core/paragraph" or "my-plugin/csv-table".
|
|
57
|
-
* @param attrs The attributes for the block, or null if there are no attributes.
|
|
58
|
-
* @param innerBlocks An array of inner blocks.
|
|
59
|
-
* @param innerHTML The inner HTML of the block.
|
|
60
|
-
* @param innerContent An array of inner content strings.
|
|
61
|
-
* @return The block object.
|
|
62
|
-
*/
|
|
63
29
|
function Block(blockName, attrs, innerBlocks, innerHTML, innerContent) {
|
|
64
30
|
return {
|
|
65
31
|
blockName,
|
|
@@ -69,27 +35,9 @@ function Block(blockName, attrs, innerBlocks, innerHTML, innerContent) {
|
|
|
69
35
|
innerContent
|
|
70
36
|
};
|
|
71
37
|
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Constructs a freeform block object.
|
|
75
|
-
*
|
|
76
|
-
* @param innerHTML The inner HTML of the block.
|
|
77
|
-
* @return The freeform block object.
|
|
78
|
-
*/
|
|
79
38
|
function Freeform(innerHTML) {
|
|
80
39
|
return Block(null, {}, [], innerHTML, [innerHTML]);
|
|
81
40
|
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Constructs a frame object.
|
|
85
|
-
*
|
|
86
|
-
* @param block The block object.
|
|
87
|
-
* @param tokenStart The start offset of the token in the document.
|
|
88
|
-
* @param tokenLength The length of the token in the document.
|
|
89
|
-
* @param prevOffset The offset of the previous token in the document.
|
|
90
|
-
* @param leadingHtmlStart The start offset of leading HTML before the block.
|
|
91
|
-
* @return The frame object.
|
|
92
|
-
*/
|
|
93
41
|
function Frame(block, tokenStart, tokenLength, prevOffset, leadingHtmlStart) {
|
|
94
42
|
return {
|
|
95
43
|
block,
|
|
@@ -99,203 +47,101 @@ function Frame(block, tokenStart, tokenLength, prevOffset, leadingHtmlStart) {
|
|
|
99
47
|
leadingHtmlStart
|
|
100
48
|
};
|
|
101
49
|
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Parser function, that converts input HTML into a block based structure.
|
|
105
|
-
*
|
|
106
|
-
* @param doc The HTML document to parse.
|
|
107
|
-
*
|
|
108
|
-
* @example
|
|
109
|
-
* Input post:
|
|
110
|
-
* ```html
|
|
111
|
-
* <!-- wp:columns {"columns":3} -->
|
|
112
|
-
* <div class="wp-block-columns has-3-columns"><!-- wp:column -->
|
|
113
|
-
* <div class="wp-block-column"><!-- wp:paragraph -->
|
|
114
|
-
* <p>Left</p>
|
|
115
|
-
* <!-- /wp:paragraph --></div>
|
|
116
|
-
* <!-- /wp:column -->
|
|
117
|
-
*
|
|
118
|
-
* <!-- wp:column -->
|
|
119
|
-
* <div class="wp-block-column"><!-- wp:paragraph -->
|
|
120
|
-
* <p><strong>Middle</strong></p>
|
|
121
|
-
* <!-- /wp:paragraph --></div>
|
|
122
|
-
* <!-- /wp:column -->
|
|
123
|
-
*
|
|
124
|
-
* <!-- wp:column -->
|
|
125
|
-
* <div class="wp-block-column"></div>
|
|
126
|
-
* <!-- /wp:column --></div>
|
|
127
|
-
* <!-- /wp:columns -->
|
|
128
|
-
* ```
|
|
129
|
-
*
|
|
130
|
-
* Parsing code:
|
|
131
|
-
* ```js
|
|
132
|
-
* import { parse } from '@wordpress/block-serialization-default-parser';
|
|
133
|
-
*
|
|
134
|
-
* parse( post ) === [
|
|
135
|
-
* {
|
|
136
|
-
* blockName: "core/columns",
|
|
137
|
-
* attrs: {
|
|
138
|
-
* columns: 3
|
|
139
|
-
* },
|
|
140
|
-
* innerBlocks: [
|
|
141
|
-
* {
|
|
142
|
-
* blockName: "core/column",
|
|
143
|
-
* attrs: null,
|
|
144
|
-
* innerBlocks: [
|
|
145
|
-
* {
|
|
146
|
-
* blockName: "core/paragraph",
|
|
147
|
-
* attrs: null,
|
|
148
|
-
* innerBlocks: [],
|
|
149
|
-
* innerHTML: "\n<p>Left</p>\n"
|
|
150
|
-
* }
|
|
151
|
-
* ],
|
|
152
|
-
* innerHTML: '\n<div class="wp-block-column"></div>\n'
|
|
153
|
-
* },
|
|
154
|
-
* {
|
|
155
|
-
* blockName: "core/column",
|
|
156
|
-
* attrs: null,
|
|
157
|
-
* innerBlocks: [
|
|
158
|
-
* {
|
|
159
|
-
* blockName: "core/paragraph",
|
|
160
|
-
* attrs: null,
|
|
161
|
-
* innerBlocks: [],
|
|
162
|
-
* innerHTML: "\n<p><strong>Middle</strong></p>\n"
|
|
163
|
-
* }
|
|
164
|
-
* ],
|
|
165
|
-
* innerHTML: '\n<div class="wp-block-column"></div>\n'
|
|
166
|
-
* },
|
|
167
|
-
* {
|
|
168
|
-
* blockName: "core/column",
|
|
169
|
-
* attrs: null,
|
|
170
|
-
* innerBlocks: [],
|
|
171
|
-
* innerHTML: '\n<div class="wp-block-column"></div>\n'
|
|
172
|
-
* }
|
|
173
|
-
* ],
|
|
174
|
-
* innerHTML: '\n<div class="wp-block-columns has-3-columns">\n\n\n\n</div>\n'
|
|
175
|
-
* }
|
|
176
|
-
* ];
|
|
177
|
-
* ```
|
|
178
|
-
* @return A block-based representation of the input HTML.
|
|
179
|
-
*/
|
|
180
|
-
const parse = doc => {
|
|
50
|
+
const parse = (doc) => {
|
|
181
51
|
document = doc;
|
|
182
52
|
offset = 0;
|
|
183
53
|
output = [];
|
|
184
54
|
stack = [];
|
|
185
55
|
tokenizer.lastIndex = 0;
|
|
186
56
|
do {
|
|
187
|
-
// twiddle our thumbs
|
|
188
57
|
} while (proceed());
|
|
189
58
|
return output;
|
|
190
59
|
};
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Parses the next token in the input document.
|
|
194
|
-
*
|
|
195
|
-
* @return Returns true when there is more tokens to parse.
|
|
196
|
-
*/
|
|
197
|
-
exports.parse = parse;
|
|
198
60
|
function proceed() {
|
|
199
61
|
const stackDepth = stack.length;
|
|
200
62
|
const next = nextToken();
|
|
201
63
|
const [tokenType, blockName, attrs, startOffset, tokenLength] = next;
|
|
202
|
-
|
|
203
|
-
// We may have some HTML soup before the next block.
|
|
204
64
|
const leadingHtmlStart = startOffset > offset ? offset : null;
|
|
205
65
|
switch (tokenType) {
|
|
206
|
-
case
|
|
207
|
-
// If not in a block then flush output.
|
|
66
|
+
case "no-more-tokens":
|
|
208
67
|
if (0 === stackDepth) {
|
|
209
68
|
addFreeform();
|
|
210
69
|
return false;
|
|
211
70
|
}
|
|
212
|
-
|
|
213
|
-
// Otherwise we have a problem
|
|
214
|
-
// This is an error
|
|
215
|
-
// we have options
|
|
216
|
-
// - treat it all as freeform text
|
|
217
|
-
// - assume an implicit closer (easiest when not nesting)
|
|
218
|
-
|
|
219
|
-
// For the easy case we'll assume an implicit closer.
|
|
220
71
|
if (1 === stackDepth) {
|
|
221
72
|
addBlockFromStack();
|
|
222
73
|
return false;
|
|
223
74
|
}
|
|
224
|
-
|
|
225
|
-
// For the nested case where it's more difficult we'll
|
|
226
|
-
// have to assume that multiple closers are missing
|
|
227
|
-
// and so we'll collapse the whole stack piecewise.
|
|
228
75
|
while (0 < stack.length) {
|
|
229
76
|
addBlockFromStack();
|
|
230
77
|
}
|
|
231
78
|
return false;
|
|
232
|
-
case
|
|
233
|
-
// easy case is if we stumbled upon a void block
|
|
234
|
-
// in the top-level of the document.
|
|
79
|
+
case "void-block":
|
|
235
80
|
if (0 === stackDepth) {
|
|
236
81
|
if (null !== leadingHtmlStart) {
|
|
237
|
-
output.push(
|
|
82
|
+
output.push(
|
|
83
|
+
Freeform(
|
|
84
|
+
document.substr(
|
|
85
|
+
leadingHtmlStart,
|
|
86
|
+
startOffset - leadingHtmlStart
|
|
87
|
+
)
|
|
88
|
+
)
|
|
89
|
+
);
|
|
238
90
|
}
|
|
239
|
-
output.push(Block(blockName, attrs, [],
|
|
91
|
+
output.push(Block(blockName, attrs, [], "", []));
|
|
240
92
|
offset = startOffset + tokenLength;
|
|
241
93
|
return true;
|
|
242
94
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
95
|
+
addInnerBlock(
|
|
96
|
+
Block(blockName, attrs, [], "", []),
|
|
97
|
+
startOffset,
|
|
98
|
+
tokenLength
|
|
99
|
+
);
|
|
246
100
|
offset = startOffset + tokenLength;
|
|
247
101
|
return true;
|
|
248
|
-
case
|
|
249
|
-
|
|
250
|
-
|
|
102
|
+
case "block-opener":
|
|
103
|
+
stack.push(
|
|
104
|
+
Frame(
|
|
105
|
+
Block(blockName, attrs, [], "", []),
|
|
106
|
+
startOffset,
|
|
107
|
+
tokenLength,
|
|
108
|
+
startOffset + tokenLength,
|
|
109
|
+
leadingHtmlStart
|
|
110
|
+
)
|
|
111
|
+
);
|
|
251
112
|
offset = startOffset + tokenLength;
|
|
252
113
|
return true;
|
|
253
|
-
case
|
|
254
|
-
// If we're missing an opener we're in trouble
|
|
255
|
-
// This is an error.
|
|
114
|
+
case "block-closer":
|
|
256
115
|
if (0 === stackDepth) {
|
|
257
|
-
// We have options
|
|
258
|
-
// - assume an implicit opener
|
|
259
|
-
// - assume _this_ is the opener
|
|
260
|
-
// - give up and close out the document.
|
|
261
116
|
addFreeform();
|
|
262
117
|
return false;
|
|
263
118
|
}
|
|
264
|
-
|
|
265
|
-
// If we're not nesting then this is easy - close the block.
|
|
266
119
|
if (1 === stackDepth) {
|
|
267
120
|
addBlockFromStack(startOffset);
|
|
268
121
|
offset = startOffset + tokenLength;
|
|
269
122
|
return true;
|
|
270
123
|
}
|
|
271
|
-
|
|
272
|
-
// Otherwise we're nested and we have to close out the current
|
|
273
|
-
// block and add it as a innerBlock to the parent.
|
|
274
124
|
const stackTop = stack.pop();
|
|
275
|
-
const html = document.substr(
|
|
125
|
+
const html = document.substr(
|
|
126
|
+
stackTop.prevOffset,
|
|
127
|
+
startOffset - stackTop.prevOffset
|
|
128
|
+
);
|
|
276
129
|
stackTop.block.innerHTML += html;
|
|
277
130
|
stackTop.block.innerContent.push(html);
|
|
278
131
|
stackTop.prevOffset = startOffset + tokenLength;
|
|
279
|
-
addInnerBlock(
|
|
132
|
+
addInnerBlock(
|
|
133
|
+
stackTop.block,
|
|
134
|
+
stackTop.tokenStart,
|
|
135
|
+
stackTop.tokenLength,
|
|
136
|
+
startOffset + tokenLength
|
|
137
|
+
);
|
|
280
138
|
offset = startOffset + tokenLength;
|
|
281
139
|
return true;
|
|
282
140
|
default:
|
|
283
|
-
// This is an error.
|
|
284
141
|
addFreeform();
|
|
285
142
|
return false;
|
|
286
143
|
}
|
|
287
144
|
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Parse JSON if valid, otherwise return null
|
|
291
|
-
*
|
|
292
|
-
* Note that JSON coming from the block comment
|
|
293
|
-
* delimiters is constrained to be an object
|
|
294
|
-
* and cannot be things like `true` or `null`
|
|
295
|
-
*
|
|
296
|
-
* @param input JSON input string to parse
|
|
297
|
-
* @return parsed JSON if valid or null if invalid
|
|
298
|
-
*/
|
|
299
145
|
function parseJSON(input) {
|
|
300
146
|
try {
|
|
301
147
|
return JSON.parse(input);
|
|
@@ -303,55 +149,38 @@ function parseJSON(input) {
|
|
|
303
149
|
return null;
|
|
304
150
|
}
|
|
305
151
|
}
|
|
306
|
-
|
|
307
|
-
/**
|
|
308
|
-
* Finds the next token in the document.
|
|
309
|
-
*
|
|
310
|
-
* @return The next matched token.
|
|
311
|
-
*/
|
|
312
152
|
function nextToken() {
|
|
313
|
-
// Aye the magic
|
|
314
|
-
// we're using a single RegExp to tokenize the block comment delimiters
|
|
315
|
-
// we're also using a trick here because the only difference between a
|
|
316
|
-
// block opener and a block closer is the leading `/` before `wp:` (and
|
|
317
|
-
// a closer has no attributes). we can trap them both and process the
|
|
318
|
-
// match back in JavaScript to see which one it was.
|
|
319
153
|
const matches = tokenizer.exec(document);
|
|
320
|
-
|
|
321
|
-
// We have no more tokens.
|
|
322
154
|
if (null === matches) {
|
|
323
|
-
return [
|
|
155
|
+
return ["no-more-tokens", "", null, 0, 0];
|
|
324
156
|
}
|
|
325
157
|
const startedAt = matches.index;
|
|
326
|
-
const [
|
|
158
|
+
const [
|
|
159
|
+
match,
|
|
160
|
+
closerMatch,
|
|
161
|
+
namespaceMatch,
|
|
162
|
+
nameMatch,
|
|
163
|
+
attrsMatch,
|
|
164
|
+
,
|
|
165
|
+
voidMatch
|
|
166
|
+
] = matches;
|
|
327
167
|
const length = match.length;
|
|
328
168
|
const isCloser = !!closerMatch;
|
|
329
169
|
const isVoid = !!voidMatch;
|
|
330
|
-
const namespace = namespaceMatch ||
|
|
170
|
+
const namespace = namespaceMatch || "core/";
|
|
331
171
|
const name = namespace + nameMatch;
|
|
332
172
|
const hasAttrs = !!attrsMatch;
|
|
333
173
|
const attrs = hasAttrs ? parseJSON(attrsMatch) : {};
|
|
334
|
-
|
|
335
|
-
// This state isn't allowed
|
|
336
|
-
// This is an error.
|
|
337
174
|
if (isCloser && (isVoid || hasAttrs)) {
|
|
338
|
-
// We can ignore them since they don't hurt anything
|
|
339
|
-
// we may warn against this at some point or reject it.
|
|
340
175
|
}
|
|
341
176
|
if (isVoid) {
|
|
342
|
-
return [
|
|
177
|
+
return ["void-block", name, attrs, startedAt, length];
|
|
343
178
|
}
|
|
344
179
|
if (isCloser) {
|
|
345
|
-
return [
|
|
180
|
+
return ["block-closer", name, null, startedAt, length];
|
|
346
181
|
}
|
|
347
|
-
return [
|
|
182
|
+
return ["block-opener", name, attrs, startedAt, length];
|
|
348
183
|
}
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Adds a freeform block to the output.
|
|
352
|
-
*
|
|
353
|
-
* @param rawLength Optional length of the raw HTML to include as freeform content.
|
|
354
|
-
*/
|
|
355
184
|
function addFreeform(rawLength) {
|
|
356
185
|
const length = rawLength ? rawLength : document.length - offset;
|
|
357
186
|
if (0 === length) {
|
|
@@ -359,20 +188,13 @@ function addFreeform(rawLength) {
|
|
|
359
188
|
}
|
|
360
189
|
output.push(Freeform(document.substr(offset, length)));
|
|
361
190
|
}
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Adds inner block to the parent block.
|
|
365
|
-
*
|
|
366
|
-
* @param block The inner block to be added to the parent.
|
|
367
|
-
* @param tokenStart The start offset of the block token in the document.
|
|
368
|
-
* @param tokenLength The total length of the block token.
|
|
369
|
-
* @param lastOffset Optional offset marking the end of the current block,
|
|
370
|
-
* used to update the parent's HTML content boundaries.
|
|
371
|
-
*/
|
|
372
191
|
function addInnerBlock(block, tokenStart, tokenLength, lastOffset) {
|
|
373
192
|
const parent = stack[stack.length - 1];
|
|
374
193
|
parent.block.innerBlocks.push(block);
|
|
375
|
-
const html = document.substr(
|
|
194
|
+
const html = document.substr(
|
|
195
|
+
parent.prevOffset,
|
|
196
|
+
tokenStart - parent.prevOffset
|
|
197
|
+
);
|
|
376
198
|
if (html) {
|
|
377
199
|
parent.block.innerHTML += html;
|
|
378
200
|
parent.block.innerContent.push(html);
|
|
@@ -380,27 +202,27 @@ function addInnerBlock(block, tokenStart, tokenLength, lastOffset) {
|
|
|
380
202
|
parent.block.innerContent.push(null);
|
|
381
203
|
parent.prevOffset = lastOffset ? lastOffset : tokenStart + tokenLength;
|
|
382
204
|
}
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Adds block from the stack to the output.
|
|
386
|
-
*
|
|
387
|
-
* @param endOffset Optional offset marking the end of the block's HTML content.
|
|
388
|
-
*/
|
|
389
205
|
function addBlockFromStack(endOffset) {
|
|
390
|
-
const {
|
|
391
|
-
block,
|
|
392
|
-
leadingHtmlStart,
|
|
393
|
-
prevOffset,
|
|
394
|
-
tokenStart
|
|
395
|
-
} = stack.pop();
|
|
206
|
+
const { block, leadingHtmlStart, prevOffset, tokenStart } = stack.pop();
|
|
396
207
|
const html = endOffset ? document.substr(prevOffset, endOffset - prevOffset) : document.substr(prevOffset);
|
|
397
208
|
if (html) {
|
|
398
209
|
block.innerHTML += html;
|
|
399
210
|
block.innerContent.push(html);
|
|
400
211
|
}
|
|
401
212
|
if (null !== leadingHtmlStart) {
|
|
402
|
-
output.push(
|
|
213
|
+
output.push(
|
|
214
|
+
Freeform(
|
|
215
|
+
document.substr(
|
|
216
|
+
leadingHtmlStart,
|
|
217
|
+
tokenStart - leadingHtmlStart
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
);
|
|
403
221
|
}
|
|
404
222
|
output.push(block);
|
|
405
223
|
}
|
|
406
|
-
|
|
224
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
225
|
+
0 && (module.exports = {
|
|
226
|
+
parse
|
|
227
|
+
});
|
|
228
|
+
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{"version":3,"names":["document","offset","output","stack","tokenizer","Block","blockName","attrs","innerBlocks","innerHTML","innerContent","Freeform","Frame","block","tokenStart","tokenLength","prevOffset","leadingHtmlStart","parse","doc","lastIndex","proceed","exports","stackDepth","length","next","nextToken","tokenType","startOffset","addFreeform","addBlockFromStack","push","substr","addInnerBlock","stackTop","pop","html","parseJSON","input","JSON","e","matches","exec","startedAt","index","match","closerMatch","namespaceMatch","nameMatch","attrsMatch","voidMatch","isCloser","isVoid","namespace","name","hasAttrs","rawLength","lastOffset","parent","endOffset"],"sources":["@wordpress/block-serialization-default-parser/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":";;;;;;AAAA,IAAIA,QAAgB;AACpB,IAAIC,MAAc;AAClB,IAAIC,MAAqB;AACzB,IAAIC,KAAoB;AA4BxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,SAAS,GACd,8HAA8H;;AAE/H;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,KAAKA,CACbC,SAAwB,EACxBC,KAAiB,EACjBC,WAA0B,EAC1BC,SAAiB,EACjBC,YAAsB,EACR;EACd,OAAO;IACNJ,SAAS;IACTC,KAAK;IACLC,WAAW;IACXC,SAAS;IACTC;EACD,CAAC;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,QAAQA,CAAEF,SAAiB,EAAgB;EACnD,OAAOJ,KAAK,CAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAEI,SAAS,EAAE,CAAEA,SAAS,CAAG,CAAC;AACvD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASG,KAAKA,CACbC,KAAkB,EAClBC,UAAkB,EAClBC,WAAmB,EACnBC,UAAyB,EACzBC,gBAA+B,EACjB;EACd,OAAO;IACNJ,KAAK;IACLC,UAAU;IACVC,WAAW;IACXC,UAAU,EAAEA,UAAU,IAAIF,UAAU,GAAGC,WAAW;IAClDE;EACD,CAAC;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;A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","ignoreList":[]}
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"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"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/build-module/index.js
CHANGED
|
@@ -2,58 +2,7 @@ let document;
|
|
|
2
2
|
let offset;
|
|
3
3
|
let output;
|
|
4
4
|
let stack;
|
|
5
|
-
/**
|
|
6
|
-
* Matches block comment delimiters
|
|
7
|
-
*
|
|
8
|
-
* While most of this pattern is straightforward the attribute parsing
|
|
9
|
-
* incorporates a tricks to make sure we don't choke on specific input
|
|
10
|
-
*
|
|
11
|
-
* - since JavaScript has no possessive quantifier or atomic grouping
|
|
12
|
-
* we are emulating it with a trick
|
|
13
|
-
*
|
|
14
|
-
* we want a possessive quantifier or atomic group to prevent backtracking
|
|
15
|
-
* on the `}`s should we fail to match the remainder of the pattern
|
|
16
|
-
*
|
|
17
|
-
* we can emulate this with a positive lookahead and back reference
|
|
18
|
-
* (a++)*c === ((?=(a+))\1)*c
|
|
19
|
-
*
|
|
20
|
-
* let's examine an example:
|
|
21
|
-
* - /(a+)*c/.test('aaaaaaaaaaaaad') fails after over 49,000 steps
|
|
22
|
-
* - /(a++)*c/.test('aaaaaaaaaaaaad') fails after 85 steps
|
|
23
|
-
* - /(?>a+)*c/.test('aaaaaaaaaaaaad') fails after 126 steps
|
|
24
|
-
*
|
|
25
|
-
* this is because the possessive `++` and the atomic group `(?>)`
|
|
26
|
-
* tell the engine that all those `a`s belong together as a single group
|
|
27
|
-
* and so it won't split it up when stepping backwards to try and match
|
|
28
|
-
*
|
|
29
|
-
* if we use /((?=(a+))\1)*c/ then we get the same behavior as the atomic group
|
|
30
|
-
* or possessive and prevent the backtracking because the `a+` is matched but
|
|
31
|
-
* not captured. thus, we find the long string of `a`s and remember it, then
|
|
32
|
-
* reference it as a whole unit inside our pattern
|
|
33
|
-
*
|
|
34
|
-
* @see http://instanceof.me/post/52245507631/regex-emulate-atomic-grouping-with-lookahead
|
|
35
|
-
* @see http://blog.stevenlevithan.com/archives/mimic-atomic-groups
|
|
36
|
-
* @see https://javascript.info/regexp-infinite-backtracking-problem
|
|
37
|
-
*
|
|
38
|
-
* once browsers reliably support atomic grouping or possessive
|
|
39
|
-
* quantifiers natively we should remove this trick and simplify
|
|
40
|
-
*
|
|
41
|
-
* @since 3.8.0
|
|
42
|
-
* @since 4.6.1 added optimization to prevent backtracking on attribute parsing
|
|
43
|
-
*/
|
|
44
5
|
const tokenizer = /<!--\s+(\/)?wp:([a-z][a-z0-9_-]*\/)?([a-z][a-z0-9_-]*)\s+({(?:(?=([^}]+|}+(?=})|(?!}\s+\/?-->)[^])*)\5|[^]*?)}\s+)?(\/)?-->/g;
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Constructs a block object.
|
|
48
|
-
*
|
|
49
|
-
* @param blockName Either the abbreviated core types, e.g. "paragraph", or the fully-qualified
|
|
50
|
-
* block type with namespace and type, e.g. "core/paragraph" or "my-plugin/csv-table".
|
|
51
|
-
* @param attrs The attributes for the block, or null if there are no attributes.
|
|
52
|
-
* @param innerBlocks An array of inner blocks.
|
|
53
|
-
* @param innerHTML The inner HTML of the block.
|
|
54
|
-
* @param innerContent An array of inner content strings.
|
|
55
|
-
* @return The block object.
|
|
56
|
-
*/
|
|
57
6
|
function Block(blockName, attrs, innerBlocks, innerHTML, innerContent) {
|
|
58
7
|
return {
|
|
59
8
|
blockName,
|
|
@@ -63,27 +12,9 @@ function Block(blockName, attrs, innerBlocks, innerHTML, innerContent) {
|
|
|
63
12
|
innerContent
|
|
64
13
|
};
|
|
65
14
|
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Constructs a freeform block object.
|
|
69
|
-
*
|
|
70
|
-
* @param innerHTML The inner HTML of the block.
|
|
71
|
-
* @return The freeform block object.
|
|
72
|
-
*/
|
|
73
15
|
function Freeform(innerHTML) {
|
|
74
16
|
return Block(null, {}, [], innerHTML, [innerHTML]);
|
|
75
17
|
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Constructs a frame object.
|
|
79
|
-
*
|
|
80
|
-
* @param block The block object.
|
|
81
|
-
* @param tokenStart The start offset of the token in the document.
|
|
82
|
-
* @param tokenLength The length of the token in the document.
|
|
83
|
-
* @param prevOffset The offset of the previous token in the document.
|
|
84
|
-
* @param leadingHtmlStart The start offset of leading HTML before the block.
|
|
85
|
-
* @return The frame object.
|
|
86
|
-
*/
|
|
87
18
|
function Frame(block, tokenStart, tokenLength, prevOffset, leadingHtmlStart) {
|
|
88
19
|
return {
|
|
89
20
|
block,
|
|
@@ -93,202 +24,101 @@ function Frame(block, tokenStart, tokenLength, prevOffset, leadingHtmlStart) {
|
|
|
93
24
|
leadingHtmlStart
|
|
94
25
|
};
|
|
95
26
|
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Parser function, that converts input HTML into a block based structure.
|
|
99
|
-
*
|
|
100
|
-
* @param doc The HTML document to parse.
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* Input post:
|
|
104
|
-
* ```html
|
|
105
|
-
* <!-- wp:columns {"columns":3} -->
|
|
106
|
-
* <div class="wp-block-columns has-3-columns"><!-- wp:column -->
|
|
107
|
-
* <div class="wp-block-column"><!-- wp:paragraph -->
|
|
108
|
-
* <p>Left</p>
|
|
109
|
-
* <!-- /wp:paragraph --></div>
|
|
110
|
-
* <!-- /wp:column -->
|
|
111
|
-
*
|
|
112
|
-
* <!-- wp:column -->
|
|
113
|
-
* <div class="wp-block-column"><!-- wp:paragraph -->
|
|
114
|
-
* <p><strong>Middle</strong></p>
|
|
115
|
-
* <!-- /wp:paragraph --></div>
|
|
116
|
-
* <!-- /wp:column -->
|
|
117
|
-
*
|
|
118
|
-
* <!-- wp:column -->
|
|
119
|
-
* <div class="wp-block-column"></div>
|
|
120
|
-
* <!-- /wp:column --></div>
|
|
121
|
-
* <!-- /wp:columns -->
|
|
122
|
-
* ```
|
|
123
|
-
*
|
|
124
|
-
* Parsing code:
|
|
125
|
-
* ```js
|
|
126
|
-
* import { parse } from '@wordpress/block-serialization-default-parser';
|
|
127
|
-
*
|
|
128
|
-
* parse( post ) === [
|
|
129
|
-
* {
|
|
130
|
-
* blockName: "core/columns",
|
|
131
|
-
* attrs: {
|
|
132
|
-
* columns: 3
|
|
133
|
-
* },
|
|
134
|
-
* innerBlocks: [
|
|
135
|
-
* {
|
|
136
|
-
* blockName: "core/column",
|
|
137
|
-
* attrs: null,
|
|
138
|
-
* innerBlocks: [
|
|
139
|
-
* {
|
|
140
|
-
* blockName: "core/paragraph",
|
|
141
|
-
* attrs: null,
|
|
142
|
-
* innerBlocks: [],
|
|
143
|
-
* innerHTML: "\n<p>Left</p>\n"
|
|
144
|
-
* }
|
|
145
|
-
* ],
|
|
146
|
-
* innerHTML: '\n<div class="wp-block-column"></div>\n'
|
|
147
|
-
* },
|
|
148
|
-
* {
|
|
149
|
-
* blockName: "core/column",
|
|
150
|
-
* attrs: null,
|
|
151
|
-
* innerBlocks: [
|
|
152
|
-
* {
|
|
153
|
-
* blockName: "core/paragraph",
|
|
154
|
-
* attrs: null,
|
|
155
|
-
* innerBlocks: [],
|
|
156
|
-
* innerHTML: "\n<p><strong>Middle</strong></p>\n"
|
|
157
|
-
* }
|
|
158
|
-
* ],
|
|
159
|
-
* innerHTML: '\n<div class="wp-block-column"></div>\n'
|
|
160
|
-
* },
|
|
161
|
-
* {
|
|
162
|
-
* blockName: "core/column",
|
|
163
|
-
* attrs: null,
|
|
164
|
-
* innerBlocks: [],
|
|
165
|
-
* innerHTML: '\n<div class="wp-block-column"></div>\n'
|
|
166
|
-
* }
|
|
167
|
-
* ],
|
|
168
|
-
* innerHTML: '\n<div class="wp-block-columns has-3-columns">\n\n\n\n</div>\n'
|
|
169
|
-
* }
|
|
170
|
-
* ];
|
|
171
|
-
* ```
|
|
172
|
-
* @return A block-based representation of the input HTML.
|
|
173
|
-
*/
|
|
174
|
-
export const parse = doc => {
|
|
27
|
+
const parse = (doc) => {
|
|
175
28
|
document = doc;
|
|
176
29
|
offset = 0;
|
|
177
30
|
output = [];
|
|
178
31
|
stack = [];
|
|
179
32
|
tokenizer.lastIndex = 0;
|
|
180
33
|
do {
|
|
181
|
-
// twiddle our thumbs
|
|
182
34
|
} while (proceed());
|
|
183
35
|
return output;
|
|
184
36
|
};
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Parses the next token in the input document.
|
|
188
|
-
*
|
|
189
|
-
* @return Returns true when there is more tokens to parse.
|
|
190
|
-
*/
|
|
191
37
|
function proceed() {
|
|
192
38
|
const stackDepth = stack.length;
|
|
193
39
|
const next = nextToken();
|
|
194
40
|
const [tokenType, blockName, attrs, startOffset, tokenLength] = next;
|
|
195
|
-
|
|
196
|
-
// We may have some HTML soup before the next block.
|
|
197
41
|
const leadingHtmlStart = startOffset > offset ? offset : null;
|
|
198
42
|
switch (tokenType) {
|
|
199
|
-
case
|
|
200
|
-
// If not in a block then flush output.
|
|
43
|
+
case "no-more-tokens":
|
|
201
44
|
if (0 === stackDepth) {
|
|
202
45
|
addFreeform();
|
|
203
46
|
return false;
|
|
204
47
|
}
|
|
205
|
-
|
|
206
|
-
// Otherwise we have a problem
|
|
207
|
-
// This is an error
|
|
208
|
-
// we have options
|
|
209
|
-
// - treat it all as freeform text
|
|
210
|
-
// - assume an implicit closer (easiest when not nesting)
|
|
211
|
-
|
|
212
|
-
// For the easy case we'll assume an implicit closer.
|
|
213
48
|
if (1 === stackDepth) {
|
|
214
49
|
addBlockFromStack();
|
|
215
50
|
return false;
|
|
216
51
|
}
|
|
217
|
-
|
|
218
|
-
// For the nested case where it's more difficult we'll
|
|
219
|
-
// have to assume that multiple closers are missing
|
|
220
|
-
// and so we'll collapse the whole stack piecewise.
|
|
221
52
|
while (0 < stack.length) {
|
|
222
53
|
addBlockFromStack();
|
|
223
54
|
}
|
|
224
55
|
return false;
|
|
225
|
-
case
|
|
226
|
-
// easy case is if we stumbled upon a void block
|
|
227
|
-
// in the top-level of the document.
|
|
56
|
+
case "void-block":
|
|
228
57
|
if (0 === stackDepth) {
|
|
229
58
|
if (null !== leadingHtmlStart) {
|
|
230
|
-
output.push(
|
|
59
|
+
output.push(
|
|
60
|
+
Freeform(
|
|
61
|
+
document.substr(
|
|
62
|
+
leadingHtmlStart,
|
|
63
|
+
startOffset - leadingHtmlStart
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
);
|
|
231
67
|
}
|
|
232
|
-
output.push(Block(blockName, attrs, [],
|
|
68
|
+
output.push(Block(blockName, attrs, [], "", []));
|
|
233
69
|
offset = startOffset + tokenLength;
|
|
234
70
|
return true;
|
|
235
71
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
72
|
+
addInnerBlock(
|
|
73
|
+
Block(blockName, attrs, [], "", []),
|
|
74
|
+
startOffset,
|
|
75
|
+
tokenLength
|
|
76
|
+
);
|
|
239
77
|
offset = startOffset + tokenLength;
|
|
240
78
|
return true;
|
|
241
|
-
case
|
|
242
|
-
|
|
243
|
-
|
|
79
|
+
case "block-opener":
|
|
80
|
+
stack.push(
|
|
81
|
+
Frame(
|
|
82
|
+
Block(blockName, attrs, [], "", []),
|
|
83
|
+
startOffset,
|
|
84
|
+
tokenLength,
|
|
85
|
+
startOffset + tokenLength,
|
|
86
|
+
leadingHtmlStart
|
|
87
|
+
)
|
|
88
|
+
);
|
|
244
89
|
offset = startOffset + tokenLength;
|
|
245
90
|
return true;
|
|
246
|
-
case
|
|
247
|
-
// If we're missing an opener we're in trouble
|
|
248
|
-
// This is an error.
|
|
91
|
+
case "block-closer":
|
|
249
92
|
if (0 === stackDepth) {
|
|
250
|
-
// We have options
|
|
251
|
-
// - assume an implicit opener
|
|
252
|
-
// - assume _this_ is the opener
|
|
253
|
-
// - give up and close out the document.
|
|
254
93
|
addFreeform();
|
|
255
94
|
return false;
|
|
256
95
|
}
|
|
257
|
-
|
|
258
|
-
// If we're not nesting then this is easy - close the block.
|
|
259
96
|
if (1 === stackDepth) {
|
|
260
97
|
addBlockFromStack(startOffset);
|
|
261
98
|
offset = startOffset + tokenLength;
|
|
262
99
|
return true;
|
|
263
100
|
}
|
|
264
|
-
|
|
265
|
-
// Otherwise we're nested and we have to close out the current
|
|
266
|
-
// block and add it as a innerBlock to the parent.
|
|
267
101
|
const stackTop = stack.pop();
|
|
268
|
-
const html = document.substr(
|
|
102
|
+
const html = document.substr(
|
|
103
|
+
stackTop.prevOffset,
|
|
104
|
+
startOffset - stackTop.prevOffset
|
|
105
|
+
);
|
|
269
106
|
stackTop.block.innerHTML += html;
|
|
270
107
|
stackTop.block.innerContent.push(html);
|
|
271
108
|
stackTop.prevOffset = startOffset + tokenLength;
|
|
272
|
-
addInnerBlock(
|
|
109
|
+
addInnerBlock(
|
|
110
|
+
stackTop.block,
|
|
111
|
+
stackTop.tokenStart,
|
|
112
|
+
stackTop.tokenLength,
|
|
113
|
+
startOffset + tokenLength
|
|
114
|
+
);
|
|
273
115
|
offset = startOffset + tokenLength;
|
|
274
116
|
return true;
|
|
275
117
|
default:
|
|
276
|
-
// This is an error.
|
|
277
118
|
addFreeform();
|
|
278
119
|
return false;
|
|
279
120
|
}
|
|
280
121
|
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Parse JSON if valid, otherwise return null
|
|
284
|
-
*
|
|
285
|
-
* Note that JSON coming from the block comment
|
|
286
|
-
* delimiters is constrained to be an object
|
|
287
|
-
* and cannot be things like `true` or `null`
|
|
288
|
-
*
|
|
289
|
-
* @param input JSON input string to parse
|
|
290
|
-
* @return parsed JSON if valid or null if invalid
|
|
291
|
-
*/
|
|
292
122
|
function parseJSON(input) {
|
|
293
123
|
try {
|
|
294
124
|
return JSON.parse(input);
|
|
@@ -296,55 +126,38 @@ function parseJSON(input) {
|
|
|
296
126
|
return null;
|
|
297
127
|
}
|
|
298
128
|
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Finds the next token in the document.
|
|
302
|
-
*
|
|
303
|
-
* @return The next matched token.
|
|
304
|
-
*/
|
|
305
129
|
function nextToken() {
|
|
306
|
-
// Aye the magic
|
|
307
|
-
// we're using a single RegExp to tokenize the block comment delimiters
|
|
308
|
-
// we're also using a trick here because the only difference between a
|
|
309
|
-
// block opener and a block closer is the leading `/` before `wp:` (and
|
|
310
|
-
// a closer has no attributes). we can trap them both and process the
|
|
311
|
-
// match back in JavaScript to see which one it was.
|
|
312
130
|
const matches = tokenizer.exec(document);
|
|
313
|
-
|
|
314
|
-
// We have no more tokens.
|
|
315
131
|
if (null === matches) {
|
|
316
|
-
return [
|
|
132
|
+
return ["no-more-tokens", "", null, 0, 0];
|
|
317
133
|
}
|
|
318
134
|
const startedAt = matches.index;
|
|
319
|
-
const [
|
|
135
|
+
const [
|
|
136
|
+
match,
|
|
137
|
+
closerMatch,
|
|
138
|
+
namespaceMatch,
|
|
139
|
+
nameMatch,
|
|
140
|
+
attrsMatch,
|
|
141
|
+
,
|
|
142
|
+
voidMatch
|
|
143
|
+
] = matches;
|
|
320
144
|
const length = match.length;
|
|
321
145
|
const isCloser = !!closerMatch;
|
|
322
146
|
const isVoid = !!voidMatch;
|
|
323
|
-
const namespace = namespaceMatch ||
|
|
147
|
+
const namespace = namespaceMatch || "core/";
|
|
324
148
|
const name = namespace + nameMatch;
|
|
325
149
|
const hasAttrs = !!attrsMatch;
|
|
326
150
|
const attrs = hasAttrs ? parseJSON(attrsMatch) : {};
|
|
327
|
-
|
|
328
|
-
// This state isn't allowed
|
|
329
|
-
// This is an error.
|
|
330
151
|
if (isCloser && (isVoid || hasAttrs)) {
|
|
331
|
-
// We can ignore them since they don't hurt anything
|
|
332
|
-
// we may warn against this at some point or reject it.
|
|
333
152
|
}
|
|
334
153
|
if (isVoid) {
|
|
335
|
-
return [
|
|
154
|
+
return ["void-block", name, attrs, startedAt, length];
|
|
336
155
|
}
|
|
337
156
|
if (isCloser) {
|
|
338
|
-
return [
|
|
157
|
+
return ["block-closer", name, null, startedAt, length];
|
|
339
158
|
}
|
|
340
|
-
return [
|
|
159
|
+
return ["block-opener", name, attrs, startedAt, length];
|
|
341
160
|
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Adds a freeform block to the output.
|
|
345
|
-
*
|
|
346
|
-
* @param rawLength Optional length of the raw HTML to include as freeform content.
|
|
347
|
-
*/
|
|
348
161
|
function addFreeform(rawLength) {
|
|
349
162
|
const length = rawLength ? rawLength : document.length - offset;
|
|
350
163
|
if (0 === length) {
|
|
@@ -352,20 +165,13 @@ function addFreeform(rawLength) {
|
|
|
352
165
|
}
|
|
353
166
|
output.push(Freeform(document.substr(offset, length)));
|
|
354
167
|
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Adds inner block to the parent block.
|
|
358
|
-
*
|
|
359
|
-
* @param block The inner block to be added to the parent.
|
|
360
|
-
* @param tokenStart The start offset of the block token in the document.
|
|
361
|
-
* @param tokenLength The total length of the block token.
|
|
362
|
-
* @param lastOffset Optional offset marking the end of the current block,
|
|
363
|
-
* used to update the parent's HTML content boundaries.
|
|
364
|
-
*/
|
|
365
168
|
function addInnerBlock(block, tokenStart, tokenLength, lastOffset) {
|
|
366
169
|
const parent = stack[stack.length - 1];
|
|
367
170
|
parent.block.innerBlocks.push(block);
|
|
368
|
-
const html = document.substr(
|
|
171
|
+
const html = document.substr(
|
|
172
|
+
parent.prevOffset,
|
|
173
|
+
tokenStart - parent.prevOffset
|
|
174
|
+
);
|
|
369
175
|
if (html) {
|
|
370
176
|
parent.block.innerHTML += html;
|
|
371
177
|
parent.block.innerContent.push(html);
|
|
@@ -373,27 +179,26 @@ function addInnerBlock(block, tokenStart, tokenLength, lastOffset) {
|
|
|
373
179
|
parent.block.innerContent.push(null);
|
|
374
180
|
parent.prevOffset = lastOffset ? lastOffset : tokenStart + tokenLength;
|
|
375
181
|
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Adds block from the stack to the output.
|
|
379
|
-
*
|
|
380
|
-
* @param endOffset Optional offset marking the end of the block's HTML content.
|
|
381
|
-
*/
|
|
382
182
|
function addBlockFromStack(endOffset) {
|
|
383
|
-
const {
|
|
384
|
-
block,
|
|
385
|
-
leadingHtmlStart,
|
|
386
|
-
prevOffset,
|
|
387
|
-
tokenStart
|
|
388
|
-
} = stack.pop();
|
|
183
|
+
const { block, leadingHtmlStart, prevOffset, tokenStart } = stack.pop();
|
|
389
184
|
const html = endOffset ? document.substr(prevOffset, endOffset - prevOffset) : document.substr(prevOffset);
|
|
390
185
|
if (html) {
|
|
391
186
|
block.innerHTML += html;
|
|
392
187
|
block.innerContent.push(html);
|
|
393
188
|
}
|
|
394
189
|
if (null !== leadingHtmlStart) {
|
|
395
|
-
output.push(
|
|
190
|
+
output.push(
|
|
191
|
+
Freeform(
|
|
192
|
+
document.substr(
|
|
193
|
+
leadingHtmlStart,
|
|
194
|
+
tokenStart - leadingHtmlStart
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
);
|
|
396
198
|
}
|
|
397
199
|
output.push(block);
|
|
398
200
|
}
|
|
399
|
-
|
|
201
|
+
export {
|
|
202
|
+
parse
|
|
203
|
+
};
|
|
204
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1,7 @@
|
|
|
1
|
-
{"version":3,"names":["document","offset","output","stack","tokenizer","Block","blockName","attrs","innerBlocks","innerHTML","innerContent","Freeform","Frame","block","tokenStart","tokenLength","prevOffset","leadingHtmlStart","parse","doc","lastIndex","proceed","stackDepth","length","next","nextToken","tokenType","startOffset","addFreeform","addBlockFromStack","push","substr","addInnerBlock","stackTop","pop","html","parseJSON","input","JSON","e","matches","exec","startedAt","index","match","closerMatch","namespaceMatch","nameMatch","attrsMatch","voidMatch","isCloser","isVoid","namespace","name","hasAttrs","rawLength","lastOffset","parent","endOffset"],"sources":["@wordpress/block-serialization-default-parser/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":"AAAA,IAAIA,QAAgB;AACpB,IAAIC,MAAc;AAClB,IAAIC,MAAqB;AACzB,IAAIC,KAAoB;AA4BxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,SAAS,GACd,8HAA8H;;AAE/H;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,KAAKA,CACbC,SAAwB,EACxBC,KAAiB,EACjBC,WAA0B,EAC1BC,SAAiB,EACjBC,YAAsB,EACR;EACd,OAAO;IACNJ,SAAS;IACTC,KAAK;IACLC,WAAW;IACXC,SAAS;IACTC;EACD,CAAC;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,QAAQA,CAAEF,SAAiB,EAAgB;EACnD,OAAOJ,KAAK,CAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,EAAEI,SAAS,EAAE,CAAEA,SAAS,CAAG,CAAC;AACvD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASG,KAAKA,CACbC,KAAkB,EAClBC,UAAkB,EAClBC,WAAmB,EACnBC,UAAyB,EACzBC,gBAA+B,EACjB;EACd,OAAO;IACNJ,KAAK;IACLC,UAAU;IACVC,WAAW;IACXC,UAAU,EAAEA,UAAU,IAAIF,UAAU,GAAGC,WAAW;IAClDE;EACD,CAAC;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA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","ignoreList":[]}
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"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"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/block-serialization-default-parser",
|
|
3
|
-
"version": "5.32.0",
|
|
3
|
+
"version": "5.32.1-next.47f435fc9.0",
|
|
4
4
|
"description": "Block serialization specification parser for WordPress posts.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -25,15 +25,20 @@
|
|
|
25
25
|
},
|
|
26
26
|
"main": "build/index.js",
|
|
27
27
|
"module": "build-module/index.js",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./build-types/index.d.ts",
|
|
31
|
+
"import": "./build-module/index.js",
|
|
32
|
+
"require": "./build/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
28
36
|
"react-native": "src/index",
|
|
29
37
|
"wpScript": true,
|
|
30
38
|
"types": "build-types",
|
|
31
39
|
"sideEffects": false,
|
|
32
|
-
"dependencies": {
|
|
33
|
-
"@babel/runtime": "7.25.7"
|
|
34
|
-
},
|
|
35
40
|
"publishConfig": {
|
|
36
41
|
"access": "public"
|
|
37
42
|
},
|
|
38
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "9720f22c138771d2ed1a0522725c3cdf1c242953"
|
|
39
44
|
}
|