PluginProbe
Gutenberg / 20.0.1
Gutenberg v20.0.1
24.0.0 23.9.1 23.9.0 23.8.0 23.7.2 23.7.1 23.7.0 23.6.1 23.6.2 23.6.0 23.5.3 23.5.2 23.5.1 23.5.0 23.4.0 23.3.2 23.3.1 23.3.0 23.2.0 23.2.1 23.2.2 23.1.1 23.1.0 23.0.1 12.6.0 All 403 releases
gutenberg / build / shortcode / index.js

index.js in Gutenberg 20.0.1, at build/shortcode/index.js

526 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /******/ (() => { // webpackBootstrap
2 /******/ "use strict";
3 /******/ // The require scope
4 /******/ var __webpack_require__ = {};
5 /******/
6 /************************************************************************/
7 /******/ /* webpack/runtime/define property getters */
8 /******/ (() => {
9 /******/ // define getter functions for harmony exports
10 /******/ __webpack_require__.d = (exports, definition) => {
11 /******/ for(var key in definition) {
12 /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
13 /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
14 /******/ }
15 /******/ }
16 /******/ };
17 /******/ })();
18 /******/
19 /******/ /* webpack/runtime/hasOwnProperty shorthand */
20 /******/ (() => {
21 /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
22 /******/ })();
23 /******/
24 /************************************************************************/
25 var __webpack_exports__ = {};
26
27 // EXPORTS
28 __webpack_require__.d(__webpack_exports__, {
29 "default": () => (/* binding */ build_module)
30 });
31
32 // UNUSED EXPORTS: attrs, fromMatch, next, regexp, replace, string
33
34 ;// ./node_modules/memize/dist/index.js
35 /**
36 * Memize options object.
37 *
38 * @typedef MemizeOptions
39 *
40 * @property {number} [maxSize] Maximum size of the cache.
41 */
42
43 /**
44 * Internal cache entry.
45 *
46 * @typedef MemizeCacheNode
47 *
48 * @property {?MemizeCacheNode|undefined} [prev] Previous node.
49 * @property {?MemizeCacheNode|undefined} [next] Next node.
50 * @property {Array<*>} args Function arguments for cache
51 * entry.
52 * @property {*} val Function result.
53 */
54
55 /**
56 * Properties of the enhanced function for controlling cache.
57 *
58 * @typedef MemizeMemoizedFunction
59 *
60 * @property {()=>void} clear Clear the cache.
61 */
62
63 /**
64 * Accepts a function to be memoized, and returns a new memoized function, with
65 * optional options.
66 *
67 * @template {(...args: any[]) => any} F
68 *
69 * @param {F} fn Function to memoize.
70 * @param {MemizeOptions} [options] Options object.
71 *
72 * @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function.
73 */
74 function memize(fn, options) {
75 var size = 0;
76
77 /** @type {?MemizeCacheNode|undefined} */
78 var head;
79
80 /** @type {?MemizeCacheNode|undefined} */
81 var tail;
82
83 options = options || {};
84
85 function memoized(/* ...args */) {
86 var node = head,
87 len = arguments.length,
88 args,
89 i;
90
91 searchCache: while (node) {
92 // Perform a shallow equality test to confirm that whether the node
93 // under test is a candidate for the arguments passed. Two arrays
94 // are shallowly equal if their length matches and each entry is
95 // strictly equal between the two sets. Avoid abstracting to a
96 // function which could incur an arguments leaking deoptimization.
97
98 // Check whether node arguments match arguments length
99 if (node.args.length !== arguments.length) {
100 node = node.next;
101 continue;
102 }
103
104 // Check whether node arguments match arguments values
105 for (i = 0; i < len; i++) {
106 if (node.args[i] !== arguments[i]) {
107 node = node.next;
108 continue searchCache;
109 }
110 }
111
112 // At this point we can assume we've found a match
113
114 // Surface matched node to head if not already
115 if (node !== head) {
116 // As tail, shift to previous. Must only shift if not also
117 // head, since if both head and tail, there is no previous.
118 if (node === tail) {
119 tail = node.prev;
120 }
121
122 // Adjust siblings to point to each other. If node was tail,
123 // this also handles new tail's empty `next` assignment.
124 /** @type {MemizeCacheNode} */ (node.prev).next = node.next;
125 if (node.next) {
126 node.next.prev = node.prev;
127 }
128
129 node.next = head;
130 node.prev = null;
131 /** @type {MemizeCacheNode} */ (head).prev = node;
132 head = node;
133 }
134
135 // Return immediately
136 return node.val;
137 }
138
139 // No cached value found. Continue to insertion phase:
140
141 // Create a copy of arguments (avoid leaking deoptimization)
142 args = new Array(len);
143 for (i = 0; i < len; i++) {
144 args[i] = arguments[i];
145 }
146
147 node = {
148 args: args,
149
150 // Generate the result from original function
151 val: fn.apply(null, args),
152 };
153
154 // Don't need to check whether node is already head, since it would
155 // have been returned above already if it was
156
157 // Shift existing head down list
158 if (head) {
159 head.prev = node;
160 node.next = head;
161 } else {
162 // If no head, follows that there's no tail (at initial or reset)
163 tail = node;
164 }
165
166 // Trim tail if we're reached max size and are pending cache insertion
167 if (size === /** @type {MemizeOptions} */ (options).maxSize) {
168 tail = /** @type {MemizeCacheNode} */ (tail).prev;
169 /** @type {MemizeCacheNode} */ (tail).next = null;
170 } else {
171 size++;
172 }
173
174 head = node;
175
176 return node.val;
177 }
178
179 memoized.clear = function () {
180 head = null;
181 tail = null;
182 size = 0;
183 };
184
185 // Ignore reason: There's not a clear solution to create an intersection of
186 // the function with additional properties, where the goal is to retain the
187 // function signature of the incoming argument and add control properties
188 // on the return value.
189
190 // @ts-ignore
191 return memoized;
192 }
193
194
195
196 ;// ./packages/shortcode/build-module/index.js
197 /* wp:polyfill */
198 /**
199 * External dependencies
200 */
201
202
203
204 /**
205 * Find the next matching shortcode.
206 *
207 * @param {string} tag Shortcode tag.
208 * @param {string} text Text to search.
209 * @param {number} index Index to start search from.
210 *
211 * @return {import('./types').ShortcodeMatch | undefined} Matched information.
212 */
213 function next(tag, text, index = 0) {
214 const re = regexp(tag);
215 re.lastIndex = index;
216 const match = re.exec(text);
217 if (!match) {
218 return;
219 }
220
221 // If we matched an escaped shortcode, try again.
222 if ('[' === match[1] && ']' === match[7]) {
223 return next(tag, text, re.lastIndex);
224 }
225 const result = {
226 index: match.index,
227 content: match[0],
228 shortcode: fromMatch(match)
229 };
230
231 // If we matched a leading `[`, strip it from the match and increment the
232 // index accordingly.
233 if (match[1]) {
234 result.content = result.content.slice(1);
235 result.index++;
236 }
237
238 // If we matched a trailing `]`, strip it from the match.
239 if (match[7]) {
240 result.content = result.content.slice(0, -1);
241 }
242 return result;
243 }
244
245 /**
246 * Replace matching shortcodes in a block of text.
247 *
248 * @param {string} tag Shortcode tag.
249 * @param {string} text Text to search.
250 * @param {import('./types').ReplaceCallback} callback Function to process the match and return
251 * replacement string.
252 *
253 * @return {string} Text with shortcodes replaced.
254 */
255 function replace(tag, text, callback) {
256 return text.replace(regexp(tag), function (match, left, $3, attrs, slash, content, closing, right) {
257 // If both extra brackets exist, the shortcode has been properly
258 // escaped.
259 if (left === '[' && right === ']') {
260 return match;
261 }
262
263 // Create the match object and pass it through the callback.
264 const result = callback(fromMatch(arguments));
265
266 // Make sure to return any of the extra brackets if they weren't used to
267 // escape the shortcode.
268 return result || result === '' ? left + result + right : match;
269 });
270 }
271
272 /**
273 * Generate a string from shortcode parameters.
274 *
275 * Creates a shortcode instance and returns a string.
276 *
277 * Accepts the same `options` as the `shortcode()` constructor, containing a
278 * `tag` string, a string or object of `attrs`, a boolean indicating whether to
279 * format the shortcode using a `single` tag, and a `content` string.
280 *
281 * @param {Object} options
282 *
283 * @return {string} String representation of the shortcode.
284 */
285 function string(options) {
286 return new shortcode(options).string();
287 }
288
289 /**
290 * Generate a RegExp to identify a shortcode.
291 *
292 * The base regex is functionally equivalent to the one found in
293 * `get_shortcode_regex()` in `wp-includes/shortcodes.php`.
294 *
295 * Capture groups:
296 *
297 * 1. An extra `[` to allow for escaping shortcodes with double `[[]]`
298 * 2. The shortcode name
299 * 3. The shortcode argument list
300 * 4. The self closing `/`
301 * 5. The content of a shortcode when it wraps some content.
302 * 6. The closing tag.
303 * 7. An extra `]` to allow for escaping shortcodes with double `[[]]`
304 *
305 * @param {string} tag Shortcode tag.
306 *
307 * @return {RegExp} Shortcode RegExp.
308 */
309 function regexp(tag) {
310 return new RegExp('\\[(\\[?)(' + tag + ')(?![\\w-])([^\\]\\/]*(?:\\/(?!\\])[^\\]\\/]*)*?)(?:(\\/)\\]|\\](?:([^\\[]*(?:\\[(?!\\/\\2\\])[^\\[]*)*)(\\[\\/\\2\\]))?)(\\]?)', 'g');
311 }
312
313 /**
314 * Parse shortcode attributes.
315 *
316 * Shortcodes accept many types of attributes. These can chiefly be divided into
317 * named and numeric attributes:
318 *
319 * Named attributes are assigned on a key/value basis, while numeric attributes
320 * are treated as an array.
321 *
322 * Named attributes can be formatted as either `name="value"`, `name='value'`,
323 * or `name=value`. Numeric attributes can be formatted as `"value"` or just
324 * `value`.
325 *
326 * @param {string} text Serialised shortcode attributes.
327 *
328 * @return {import('./types').ShortcodeAttrs} Parsed shortcode attributes.
329 */
330 const attrs = memize(text => {
331 const named = {};
332 const numeric = [];
333
334 // This regular expression is reused from `shortcode_parse_atts()` in
335 // `wp-includes/shortcodes.php`.
336 //
337 // Capture groups:
338 //
339 // 1. An attribute name, that corresponds to...
340 // 2. a value in double quotes.
341 // 3. An attribute name, that corresponds to...
342 // 4. a value in single quotes.
343 // 5. An attribute name, that corresponds to...
344 // 6. an unquoted value.
345 // 7. A numeric attribute in double quotes.
346 // 8. A numeric attribute in single quotes.
347 // 9. An unquoted numeric attribute.
348 const pattern = /([\w-]+)\s*=\s*"([^"]*)"(?:\s|$)|([\w-]+)\s*=\s*'([^']*)'(?:\s|$)|([\w-]+)\s*=\s*([^\s'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|'([^']*)'(?:\s|$)|(\S+)(?:\s|$)/g;
349
350 // Map zero-width spaces to actual spaces.
351 text = text.replace(/[\u00a0\u200b]/g, ' ');
352 let match;
353
354 // Match and normalize attributes.
355 while (match = pattern.exec(text)) {
356 if (match[1]) {
357 named[match[1].toLowerCase()] = match[2];
358 } else if (match[3]) {
359 named[match[3].toLowerCase()] = match[4];
360 } else if (match[5]) {
361 named[match[5].toLowerCase()] = match[6];
362 } else if (match[7]) {
363 numeric.push(match[7]);
364 } else if (match[8]) {
365 numeric.push(match[8]);
366 } else if (match[9]) {
367 numeric.push(match[9]);
368 }
369 }
370 return {
371 named,
372 numeric
373 };
374 });
375
376 /**
377 * Generate a Shortcode Object from a RegExp match.
378 *
379 * Accepts a `match` object from calling `regexp.exec()` on a `RegExp` generated
380 * by `regexp()`. `match` can also be set to the `arguments` from a callback
381 * passed to `regexp.replace()`.
382 *
383 * @param {import('./types').Match} match Match array.
384 *
385 * @return {InstanceType<import('./types').shortcode>} Shortcode instance.
386 */
387 function fromMatch(match) {
388 let type;
389 if (match[4]) {
390 type = 'self-closing';
391 } else if (match[6]) {
392 type = 'closed';
393 } else {
394 type = 'single';
395 }
396 return new shortcode({
397 tag: match[2],
398 attrs: match[3],
399 type,
400 content: match[5]
401 });
402 }
403
404 /**
405 * Creates a shortcode instance.
406 *
407 * To access a raw representation of a shortcode, pass an `options` object,
408 * containing a `tag` string, a string or object of `attrs`, a string indicating
409 * the `type` of the shortcode ('single', 'self-closing', or 'closed'), and a
410 * `content` string.
411 *
412 * @type {import('./types').shortcode} Shortcode instance.
413 */
414 const shortcode = Object.assign(function (options) {
415 const {
416 tag,
417 attrs: attributes,
418 type,
419 content
420 } = options || {};
421 Object.assign(this, {
422 tag,
423 type,
424 content
425 });
426
427 // Ensure we have a correctly formatted `attrs` object.
428 this.attrs = {
429 named: {},
430 numeric: []
431 };
432 if (!attributes) {
433 return;
434 }
435 const attributeTypes = ['named', 'numeric'];
436
437 // Parse a string of attributes.
438 if (typeof attributes === 'string') {
439 this.attrs = attrs(attributes);
440 // Identify a correctly formatted `attrs` object.
441 } else if (attributes.length === attributeTypes.length && attributeTypes.every((t, key) => t === attributes[key])) {
442 this.attrs = attributes;
443 // Handle a flat object of attributes.
444 } else {
445 Object.entries(attributes).forEach(([key, value]) => {
446 this.set(key, value);
447 });
448 }
449 }, {
450 next,
451 replace,
452 string,
453 regexp,
454 attrs,
455 fromMatch
456 });
457 Object.assign(shortcode.prototype, {
458 /**
459 * Get a shortcode attribute.
460 *
461 * Automatically detects whether `attr` is named or numeric and routes it
462 * accordingly.
463 *
464 * @param {(number|string)} attr Attribute key.
465 *
466 * @return {string} Attribute value.
467 */
468 get(attr) {
469 return this.attrs[typeof attr === 'number' ? 'numeric' : 'named'][attr];
470 },
471 /**
472 * Set a shortcode attribute.
473 *
474 * Automatically detects whether `attr` is named or numeric and routes it
475 * accordingly.
476 *
477 * @param {(number|string)} attr Attribute key.
478 * @param {string} value Attribute value.
479 *
480 * @return {InstanceType< import('./types').shortcode >} Shortcode instance.
481 */
482 set(attr, value) {
483 this.attrs[typeof attr === 'number' ? 'numeric' : 'named'][attr] = value;
484 return this;
485 },
486 /**
487 * Transform the shortcode into a string.
488 *
489 * @return {string} String representation of the shortcode.
490 */
491 string() {
492 let text = '[' + this.tag;
493 this.attrs.numeric.forEach(value => {
494 if (/\s/.test(value)) {
495 text += ' "' + value + '"';
496 } else {
497 text += ' ' + value;
498 }
499 });
500 Object.entries(this.attrs.named).forEach(([name, value]) => {
501 text += ' ' + name + '="' + value + '"';
502 });
503
504 // If the tag is marked as `single` or `self-closing`, close the tag and
505 // ignore any additional content.
506 if ('single' === this.type) {
507 return text + ']';
508 } else if ('self-closing' === this.type) {
509 return text + ' /]';
510 }
511
512 // Complete the opening tag.
513 text += ']';
514 if (this.content) {
515 text += this.content;
516 }
517
518 // Add the closing tag.
519 return text + '[/' + this.tag + ']';
520 }
521 });
522 /* harmony default export */ const build_module = (shortcode);
523
524 (window.wp = window.wp || {}).shortcode = __webpack_exports__["default"];
525 /******/ })()
526 ;