@wordpress/shortcode 4.38.0 → 4.39.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/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 4.39.0 (2026-01-29)
6
+
7
+ ### Bug Fixes
8
+
9
+ - Fix non-string attribute values being silently dropped ([#74949](https://github.com/WordPress/gutenberg/pull/74949)).
10
+
5
11
  ## 4.38.0 (2026-01-16)
6
12
 
7
13
  ## 4.36.0 (2025-11-26)
package/build/index.cjs CHANGED
@@ -161,8 +161,8 @@ var Shortcode = class {
161
161
  this.attrs = attributes;
162
162
  } else {
163
163
  Object.entries(attributes).forEach(([key, value]) => {
164
- if (typeof value === "string" || typeof value === "undefined") {
165
- this.set(key, value);
164
+ if (value !== void 0) {
165
+ this.set(key, String(value));
166
166
  }
167
167
  });
168
168
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["/**\n * External dependencies\n */\nimport memize from 'memize';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tShortcodeAttrs,\n\tShortcodeMatch,\n\tShortcodeOptions,\n\tMatch,\n\tReplaceCallback,\n\tShortcodeInstance,\n} from './types';\n\nexport * from './types';\n\n/**\n * Find the next matching shortcode.\n *\n * @param tag Shortcode tag.\n * @param text Text to search.\n * @param index Index to start search from.\n *\n * @return Matched information.\n */\nexport function next(\n\ttag: string,\n\ttext: string,\n\tindex: number = 0\n): ShortcodeMatch | undefined {\n\tconst re = regexp( tag );\n\n\tre.lastIndex = index;\n\n\tconst match = re.exec( text );\n\n\tif ( ! match ) {\n\t\treturn;\n\t}\n\n\t// If we matched an escaped shortcode, try again.\n\tif ( '[' === match[ 1 ] && ']' === match[ 7 ] ) {\n\t\treturn next( tag, text, re.lastIndex );\n\t}\n\n\tconst result: ShortcodeMatch = {\n\t\tindex: match.index,\n\t\tcontent: match[ 0 ],\n\t\tshortcode: fromMatch( match ),\n\t};\n\n\t// If we matched a leading `[`, strip it from the match and increment the\n\t// index accordingly.\n\tif ( match[ 1 ] ) {\n\t\tresult.content = result.content.slice( 1 );\n\t\tresult.index++;\n\t}\n\n\t// If we matched a trailing `]`, strip it from the match.\n\tif ( match[ 7 ] ) {\n\t\tresult.content = result.content.slice( 0, -1 );\n\t}\n\n\treturn result;\n}\n\n/**\n * Replace matching shortcodes in a block of text.\n *\n * @param tag Shortcode tag.\n * @param text Text to search.\n * @param callback Function to process the match and return\n * replacement string.\n *\n * @return Text with shortcodes replaced.\n */\nexport function replace(\n\ttag: string,\n\ttext: string,\n\tcallback: ReplaceCallback\n) {\n\treturn text.replace(\n\t\tregexp( tag ),\n\t\t// Let us use spread syntax to capture the arguments object.\n\t\t( ...args: string[] ): string => {\n\t\t\tconst match = args[ 0 ];\n\t\t\tconst left = args[ 1 ];\n\t\t\tconst right = args[ 7 ];\n\n\t\t\t// If both extra brackets exist, the shortcode has been properly\n\t\t\t// escaped.\n\t\t\tif ( left === '[' && right === ']' ) {\n\t\t\t\treturn match;\n\t\t\t}\n\n\t\t\t// Create the match object and pass it through the callback.\n\t\t\tconst result = callback( fromMatch( args ) );\n\n\t\t\t// Make sure to return any of the extra brackets if they weren't used to\n\t\t\t// escape the shortcode.\n\t\t\treturn result || result === '' ? left + result + right : match;\n\t\t}\n\t);\n}\n\n/**\n * Generate a string from shortcode parameters.\n *\n * Creates a shortcode instance and returns a string.\n *\n * Accepts the same `options` as the `shortcode()` constructor, containing a\n * `tag` string, a string or object of `attrs`, a boolean indicating whether to\n * format the shortcode using a `single` tag, and a `content` string.\n *\n * @param options Shortcode options.\n *\n * @return String representation of the shortcode.\n */\nexport function string( options: ShortcodeOptions ): string {\n\treturn new Shortcode( options ).string();\n}\n\n/**\n * Generate a RegExp to identify a shortcode.\n *\n * The base regex is functionally equivalent to the one found in\n * `get_shortcode_regex()` in `wp-includes/shortcodes.php`.\n *\n * Capture groups:\n *\n * 1. An extra `[` to allow for escaping shortcodes with double `[[]]`\n * 2. The shortcode name\n * 3. The shortcode argument list\n * 4. The self closing `/`\n * 5. The content of a shortcode when it wraps some content.\n * 6. The closing tag.\n * 7. An extra `]` to allow for escaping shortcodes with double `[[]]`\n *\n * @param tag Shortcode tag.\n *\n * @return Shortcode RegExp.\n */\nexport function regexp( tag: string ): RegExp {\n\treturn new RegExp(\n\t\t'\\\\[(\\\\[?)(' +\n\t\t\ttag +\n\t\t\t')(?![\\\\w-])([^\\\\]\\\\/]*(?:\\\\/(?!\\\\])[^\\\\]\\\\/]*)*?)(?:(\\\\/)\\\\]|\\\\](?:([^\\\\[]*(?:\\\\[(?!\\\\/\\\\2\\\\])[^\\\\[]*)*)(\\\\[\\\\/\\\\2\\\\]))?)(\\\\]?)',\n\t\t'g'\n\t);\n}\n\n/**\n * Parse shortcode attributes.\n *\n * Shortcodes accept many types of attributes. These can chiefly be divided into\n * named and numeric attributes:\n *\n * Named attributes are assigned on a key/value basis, while numeric attributes\n * are treated as an array.\n *\n * Named attributes can be formatted as either `name=\"value\"`, `name='value'`,\n * or `name=value`. Numeric attributes can be formatted as `\"value\"` or just\n * `value`.\n *\n * @param {string} text Serialised shortcode attributes.\n *\n * @return {ShortcodeAttrs} Parsed shortcode attributes.\n */\nexport const attrs = memize( ( text: string ): ShortcodeAttrs => {\n\tconst named: Record< string, string | undefined > = {};\n\tconst numeric: string[] = [];\n\n\t// This regular expression is reused from `shortcode_parse_atts()` in\n\t// `wp-includes/shortcodes.php`.\n\t//\n\t// Capture groups:\n\t//\n\t// 1. An attribute name, that corresponds to...\n\t// 2. a value in double quotes.\n\t// 3. An attribute name, that corresponds to...\n\t// 4. a value in single quotes.\n\t// 5. An attribute name, that corresponds to...\n\t// 6. an unquoted value.\n\t// 7. A numeric attribute in double quotes.\n\t// 8. A numeric attribute in single quotes.\n\t// 9. An unquoted numeric attribute.\n\tconst pattern =\n\t\t/([\\w-]+)\\s*=\\s*\"([^\"]*)\"(?:\\s|$)|([\\w-]+)\\s*=\\s*'([^']*)'(?:\\s|$)|([\\w-]+)\\s*=\\s*([^\\s'\"]+)(?:\\s|$)|\"([^\"]*)\"(?:\\s|$)|'([^']*)'(?:\\s|$)|(\\S+)(?:\\s|$)/g;\n\n\t// Map zero-width spaces to actual spaces.\n\ttext = text.replace( /[\\u00a0\\u200b]/g, ' ' );\n\n\tlet match;\n\n\t// Match and normalize attributes.\n\twhile ( ( match = pattern.exec( text ) ) ) {\n\t\tif ( match[ 1 ] ) {\n\t\t\tnamed[ match[ 1 ].toLowerCase() ] = match[ 2 ];\n\t\t} else if ( match[ 3 ] ) {\n\t\t\tnamed[ match[ 3 ].toLowerCase() ] = match[ 4 ];\n\t\t} else if ( match[ 5 ] ) {\n\t\t\tnamed[ match[ 5 ].toLowerCase() ] = match[ 6 ];\n\t\t} else if ( match[ 7 ] ) {\n\t\t\tnumeric.push( match[ 7 ] );\n\t\t} else if ( match[ 8 ] ) {\n\t\t\tnumeric.push( match[ 8 ] );\n\t\t} else if ( match[ 9 ] ) {\n\t\t\tnumeric.push( match[ 9 ] );\n\t\t}\n\t}\n\n\treturn { named, numeric };\n} );\n\n/**\n * Generate a Shortcode Object from a RegExp match.\n *\n * Accepts a `match` object from calling `regexp.exec()` on a `RegExp` generated\n * by `regexp()`. `match` can also be set to the `arguments` from a callback\n * passed to `regexp.replace()`.\n *\n * @param match Match array.\n *\n * @return Shortcode instance.\n */\nexport function fromMatch( match: Match ): ShortcodeInstance {\n\tlet type: 'self-closing' | 'closed' | 'single';\n\n\tif ( match[ 4 ] ) {\n\t\ttype = 'self-closing';\n\t} else if ( match[ 6 ] ) {\n\t\ttype = 'closed';\n\t} else {\n\t\ttype = 'single';\n\t}\n\n\treturn new Shortcode( {\n\t\ttag: match[ 2 ],\n\t\tattrs: match[ 3 ],\n\t\ttype,\n\t\tcontent: match[ 5 ],\n\t} );\n}\n\n/**\n * Creates a shortcode instance.\n *\n * To access a raw representation of a shortcode, pass an `options` object,\n * containing a `tag` string, a string or object of `attrs`, a string indicating\n * the `type` of the shortcode ('single', 'self-closing', or 'closed'), and a\n * `content` string.\n */\nclass Shortcode implements ShortcodeInstance {\n\t// Instance properties\n\ttag: string;\n\ttype?: 'self-closing' | 'closed' | 'single';\n\tcontent?: string;\n\tattrs: ShortcodeAttrs;\n\n\t// Static methods\n\tstatic next = next;\n\tstatic replace = replace;\n\tstatic string = string;\n\tstatic regexp = regexp;\n\tstatic attrs = attrs;\n\tstatic fromMatch = fromMatch;\n\n\tconstructor( options: ShortcodeOptions ) {\n\t\tconst { tag, attrs: attributes, type, content } = options;\n\t\tthis.tag = tag;\n\t\tthis.type = type;\n\t\tthis.content = content;\n\n\t\t// Ensure we have a correctly formatted `attrs` object.\n\t\tthis.attrs = {\n\t\t\tnamed: {},\n\t\t\tnumeric: [],\n\t\t};\n\n\t\tif ( ! attributes ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Parse a string of attributes.\n\t\tif ( typeof attributes === 'string' ) {\n\t\t\tthis.attrs = attrs( attributes );\n\t\t\t// Identify a correctly formatted `attrs` object.\n\t\t} else if (\n\t\t\t'named' in attributes &&\n\t\t\t'numeric' in attributes &&\n\t\t\tattributes.named !== undefined &&\n\t\t\tattributes.numeric !== undefined\n\t\t) {\n\t\t\tthis.attrs = attributes as ShortcodeAttrs;\n\t\t\t// Handle a flat object of attributes (e.g., { foo: 'bar', baz: 'qux' }).\n\t\t} else {\n\t\t\tObject.entries( attributes ).forEach( ( [ key, value ] ) => {\n\t\t\t\tif (\n\t\t\t\t\ttypeof value === 'string' ||\n\t\t\t\t\ttypeof value === 'undefined'\n\t\t\t\t) {\n\t\t\t\t\tthis.set( key, value );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Get a shortcode attribute.\n\t *\n\t * Automatically detects whether `attr` is named or numeric and routes it\n\t * accordingly.\n\t *\n\t * @param attr Attribute key.\n\t *\n\t * @return Attribute value.\n\t */\n\tget( attr: string | number ): string | undefined {\n\t\tif ( typeof attr === 'number' ) {\n\t\t\treturn this.attrs.numeric[ attr ];\n\t\t}\n\t\treturn this.attrs.named[ attr ];\n\t}\n\n\t/**\n\t * Set a shortcode attribute.\n\t *\n\t * Automatically detects whether `attr` is named or numeric and routes it\n\t * accordingly.\n\t *\n\t * @param attr Attribute key.\n\t * @param value Attribute value.\n\t *\n\t * @return Shortcode instance.\n\t */\n\tset( attr: string | number, value: string ): this {\n\t\tif ( typeof attr === 'number' ) {\n\t\t\tthis.attrs.numeric[ attr ] = value;\n\t\t} else {\n\t\t\tthis.attrs.named[ attr ] = value;\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Transform the shortcode into a string.\n\t *\n\t * @return String representation of the shortcode.\n\t */\n\tstring(): string {\n\t\tlet text = '[' + this.tag;\n\n\t\tthis.attrs.numeric.forEach( ( value ) => {\n\t\t\tif ( /\\s/.test( value ) ) {\n\t\t\t\ttext += ' \"' + value + '\"';\n\t\t\t} else {\n\t\t\t\ttext += ' ' + value;\n\t\t\t}\n\t\t} );\n\n\t\tObject.entries( this.attrs.named ).forEach( ( [ name, value ] ) => {\n\t\t\ttext += ' ' + name + '=\"' + value + '\"';\n\t\t} );\n\n\t\t// If the tag is marked as `single` or `self-closing`, close the tag and\n\t\t// ignore any additional content.\n\t\tif ( 'single' === this.type ) {\n\t\t\treturn text + ']';\n\t\t} else if ( 'self-closing' === this.type ) {\n\t\t\treturn text + ' /]';\n\t\t}\n\n\t\t// Complete the opening tag.\n\t\ttext += ']';\n\n\t\tif ( this.content ) {\n\t\t\ttext += this.content;\n\t\t}\n\n\t\t// Add the closing tag.\n\t\treturn text + '[/' + this.tag + ']';\n\t}\n}\n\nexport default Shortcode;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport memize from 'memize';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tShortcodeAttrs,\n\tShortcodeMatch,\n\tShortcodeOptions,\n\tMatch,\n\tReplaceCallback,\n\tShortcodeInstance,\n} from './types';\n\nexport * from './types';\n\n/**\n * Find the next matching shortcode.\n *\n * @param tag Shortcode tag.\n * @param text Text to search.\n * @param index Index to start search from.\n *\n * @return Matched information.\n */\nexport function next(\n\ttag: string,\n\ttext: string,\n\tindex: number = 0\n): ShortcodeMatch | undefined {\n\tconst re = regexp( tag );\n\n\tre.lastIndex = index;\n\n\tconst match = re.exec( text );\n\n\tif ( ! match ) {\n\t\treturn;\n\t}\n\n\t// If we matched an escaped shortcode, try again.\n\tif ( '[' === match[ 1 ] && ']' === match[ 7 ] ) {\n\t\treturn next( tag, text, re.lastIndex );\n\t}\n\n\tconst result: ShortcodeMatch = {\n\t\tindex: match.index,\n\t\tcontent: match[ 0 ],\n\t\tshortcode: fromMatch( match ),\n\t};\n\n\t// If we matched a leading `[`, strip it from the match and increment the\n\t// index accordingly.\n\tif ( match[ 1 ] ) {\n\t\tresult.content = result.content.slice( 1 );\n\t\tresult.index++;\n\t}\n\n\t// If we matched a trailing `]`, strip it from the match.\n\tif ( match[ 7 ] ) {\n\t\tresult.content = result.content.slice( 0, -1 );\n\t}\n\n\treturn result;\n}\n\n/**\n * Replace matching shortcodes in a block of text.\n *\n * @param tag Shortcode tag.\n * @param text Text to search.\n * @param callback Function to process the match and return\n * replacement string.\n *\n * @return Text with shortcodes replaced.\n */\nexport function replace(\n\ttag: string,\n\ttext: string,\n\tcallback: ReplaceCallback\n) {\n\treturn text.replace(\n\t\tregexp( tag ),\n\t\t// Let us use spread syntax to capture the arguments object.\n\t\t( ...args: string[] ): string => {\n\t\t\tconst match = args[ 0 ];\n\t\t\tconst left = args[ 1 ];\n\t\t\tconst right = args[ 7 ];\n\n\t\t\t// If both extra brackets exist, the shortcode has been properly\n\t\t\t// escaped.\n\t\t\tif ( left === '[' && right === ']' ) {\n\t\t\t\treturn match;\n\t\t\t}\n\n\t\t\t// Create the match object and pass it through the callback.\n\t\t\tconst result = callback( fromMatch( args ) );\n\n\t\t\t// Make sure to return any of the extra brackets if they weren't used to\n\t\t\t// escape the shortcode.\n\t\t\treturn result || result === '' ? left + result + right : match;\n\t\t}\n\t);\n}\n\n/**\n * Generate a string from shortcode parameters.\n *\n * Creates a shortcode instance and returns a string.\n *\n * Accepts the same `options` as the `shortcode()` constructor, containing a\n * `tag` string, a string or object of `attrs`, a boolean indicating whether to\n * format the shortcode using a `single` tag, and a `content` string.\n *\n * @param options Shortcode options.\n *\n * @return String representation of the shortcode.\n */\nexport function string( options: ShortcodeOptions ): string {\n\treturn new Shortcode( options ).string();\n}\n\n/**\n * Generate a RegExp to identify a shortcode.\n *\n * The base regex is functionally equivalent to the one found in\n * `get_shortcode_regex()` in `wp-includes/shortcodes.php`.\n *\n * Capture groups:\n *\n * 1. An extra `[` to allow for escaping shortcodes with double `[[]]`\n * 2. The shortcode name\n * 3. The shortcode argument list\n * 4. The self closing `/`\n * 5. The content of a shortcode when it wraps some content.\n * 6. The closing tag.\n * 7. An extra `]` to allow for escaping shortcodes with double `[[]]`\n *\n * @param tag Shortcode tag.\n *\n * @return Shortcode RegExp.\n */\nexport function regexp( tag: string ): RegExp {\n\treturn new RegExp(\n\t\t'\\\\[(\\\\[?)(' +\n\t\t\ttag +\n\t\t\t')(?![\\\\w-])([^\\\\]\\\\/]*(?:\\\\/(?!\\\\])[^\\\\]\\\\/]*)*?)(?:(\\\\/)\\\\]|\\\\](?:([^\\\\[]*(?:\\\\[(?!\\\\/\\\\2\\\\])[^\\\\[]*)*)(\\\\[\\\\/\\\\2\\\\]))?)(\\\\]?)',\n\t\t'g'\n\t);\n}\n\n/**\n * Parse shortcode attributes.\n *\n * Shortcodes accept many types of attributes. These can chiefly be divided into\n * named and numeric attributes:\n *\n * Named attributes are assigned on a key/value basis, while numeric attributes\n * are treated as an array.\n *\n * Named attributes can be formatted as either `name=\"value\"`, `name='value'`,\n * or `name=value`. Numeric attributes can be formatted as `\"value\"` or just\n * `value`.\n *\n * @param {string} text Serialised shortcode attributes.\n *\n * @return {ShortcodeAttrs} Parsed shortcode attributes.\n */\nexport const attrs = memize( ( text: string ): ShortcodeAttrs => {\n\tconst named: Record< string, string | undefined > = {};\n\tconst numeric: string[] = [];\n\n\t// This regular expression is reused from `shortcode_parse_atts()` in\n\t// `wp-includes/shortcodes.php`.\n\t//\n\t// Capture groups:\n\t//\n\t// 1. An attribute name, that corresponds to...\n\t// 2. a value in double quotes.\n\t// 3. An attribute name, that corresponds to...\n\t// 4. a value in single quotes.\n\t// 5. An attribute name, that corresponds to...\n\t// 6. an unquoted value.\n\t// 7. A numeric attribute in double quotes.\n\t// 8. A numeric attribute in single quotes.\n\t// 9. An unquoted numeric attribute.\n\tconst pattern =\n\t\t/([\\w-]+)\\s*=\\s*\"([^\"]*)\"(?:\\s|$)|([\\w-]+)\\s*=\\s*'([^']*)'(?:\\s|$)|([\\w-]+)\\s*=\\s*([^\\s'\"]+)(?:\\s|$)|\"([^\"]*)\"(?:\\s|$)|'([^']*)'(?:\\s|$)|(\\S+)(?:\\s|$)/g;\n\n\t// Map zero-width spaces to actual spaces.\n\ttext = text.replace( /[\\u00a0\\u200b]/g, ' ' );\n\n\tlet match;\n\n\t// Match and normalize attributes.\n\twhile ( ( match = pattern.exec( text ) ) ) {\n\t\tif ( match[ 1 ] ) {\n\t\t\tnamed[ match[ 1 ].toLowerCase() ] = match[ 2 ];\n\t\t} else if ( match[ 3 ] ) {\n\t\t\tnamed[ match[ 3 ].toLowerCase() ] = match[ 4 ];\n\t\t} else if ( match[ 5 ] ) {\n\t\t\tnamed[ match[ 5 ].toLowerCase() ] = match[ 6 ];\n\t\t} else if ( match[ 7 ] ) {\n\t\t\tnumeric.push( match[ 7 ] );\n\t\t} else if ( match[ 8 ] ) {\n\t\t\tnumeric.push( match[ 8 ] );\n\t\t} else if ( match[ 9 ] ) {\n\t\t\tnumeric.push( match[ 9 ] );\n\t\t}\n\t}\n\n\treturn { named, numeric };\n} );\n\n/**\n * Generate a Shortcode Object from a RegExp match.\n *\n * Accepts a `match` object from calling `regexp.exec()` on a `RegExp` generated\n * by `regexp()`. `match` can also be set to the `arguments` from a callback\n * passed to `regexp.replace()`.\n *\n * @param match Match array.\n *\n * @return Shortcode instance.\n */\nexport function fromMatch( match: Match ): ShortcodeInstance {\n\tlet type: 'self-closing' | 'closed' | 'single';\n\n\tif ( match[ 4 ] ) {\n\t\ttype = 'self-closing';\n\t} else if ( match[ 6 ] ) {\n\t\ttype = 'closed';\n\t} else {\n\t\ttype = 'single';\n\t}\n\n\treturn new Shortcode( {\n\t\ttag: match[ 2 ],\n\t\tattrs: match[ 3 ],\n\t\ttype,\n\t\tcontent: match[ 5 ],\n\t} );\n}\n\n/**\n * Creates a shortcode instance.\n *\n * To access a raw representation of a shortcode, pass an `options` object,\n * containing a `tag` string, a string or object of `attrs`, a string indicating\n * the `type` of the shortcode ('single', 'self-closing', or 'closed'), and a\n * `content` string.\n */\nclass Shortcode implements ShortcodeInstance {\n\t// Instance properties\n\ttag: string;\n\ttype?: 'self-closing' | 'closed' | 'single';\n\tcontent?: string;\n\tattrs: ShortcodeAttrs;\n\n\t// Static methods\n\tstatic next = next;\n\tstatic replace = replace;\n\tstatic string = string;\n\tstatic regexp = regexp;\n\tstatic attrs = attrs;\n\tstatic fromMatch = fromMatch;\n\n\tconstructor( options: ShortcodeOptions ) {\n\t\tconst { tag, attrs: attributes, type, content } = options;\n\t\tthis.tag = tag;\n\t\tthis.type = type;\n\t\tthis.content = content;\n\n\t\t// Ensure we have a correctly formatted `attrs` object.\n\t\tthis.attrs = {\n\t\t\tnamed: {},\n\t\t\tnumeric: [],\n\t\t};\n\n\t\tif ( ! attributes ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Parse a string of attributes.\n\t\tif ( typeof attributes === 'string' ) {\n\t\t\tthis.attrs = attrs( attributes );\n\t\t\t// Identify a correctly formatted `attrs` object.\n\t\t} else if (\n\t\t\t'named' in attributes &&\n\t\t\t'numeric' in attributes &&\n\t\t\tattributes.named !== undefined &&\n\t\t\tattributes.numeric !== undefined\n\t\t) {\n\t\t\tthis.attrs = attributes as ShortcodeAttrs;\n\t\t\t// Handle a flat object of attributes (e.g., { foo: 'bar', baz: 'qux' }).\n\t\t} else {\n\t\t\tObject.entries( attributes ).forEach( ( [ key, value ] ) => {\n\t\t\t\tif ( value !== undefined ) {\n\t\t\t\t\t// Coerce non-string values to strings to maintain backward compatibility.\n\t\t\t\t\tthis.set( key, String( value ) );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Get a shortcode attribute.\n\t *\n\t * Automatically detects whether `attr` is named or numeric and routes it\n\t * accordingly.\n\t *\n\t * @param attr Attribute key.\n\t *\n\t * @return Attribute value.\n\t */\n\tget( attr: string | number ): string | undefined {\n\t\tif ( typeof attr === 'number' ) {\n\t\t\treturn this.attrs.numeric[ attr ];\n\t\t}\n\t\treturn this.attrs.named[ attr ];\n\t}\n\n\t/**\n\t * Set a shortcode attribute.\n\t *\n\t * Automatically detects whether `attr` is named or numeric and routes it\n\t * accordingly.\n\t *\n\t * @param attr Attribute key.\n\t * @param value Attribute value.\n\t *\n\t * @return Shortcode instance.\n\t */\n\tset( attr: string | number, value: string ): this {\n\t\tif ( typeof attr === 'number' ) {\n\t\t\tthis.attrs.numeric[ attr ] = value;\n\t\t} else {\n\t\t\tthis.attrs.named[ attr ] = value;\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Transform the shortcode into a string.\n\t *\n\t * @return String representation of the shortcode.\n\t */\n\tstring(): string {\n\t\tlet text = '[' + this.tag;\n\n\t\tthis.attrs.numeric.forEach( ( value ) => {\n\t\t\tif ( /\\s/.test( value ) ) {\n\t\t\t\ttext += ' \"' + value + '\"';\n\t\t\t} else {\n\t\t\t\ttext += ' ' + value;\n\t\t\t}\n\t\t} );\n\n\t\tObject.entries( this.attrs.named ).forEach( ( [ name, value ] ) => {\n\t\t\ttext += ' ' + name + '=\"' + value + '\"';\n\t\t} );\n\n\t\t// If the tag is marked as `single` or `self-closing`, close the tag and\n\t\t// ignore any additional content.\n\t\tif ( 'single' === this.type ) {\n\t\t\treturn text + ']';\n\t\t} else if ( 'self-closing' === this.type ) {\n\t\t\treturn text + ' /]';\n\t\t}\n\n\t\t// Complete the opening tag.\n\t\ttext += ']';\n\n\t\tif ( this.content ) {\n\t\t\ttext += this.content;\n\t\t}\n\n\t\t// Add the closing tag.\n\t\treturn text + '[/' + this.tag + ']';\n\t}\n}\n\nexport default Shortcode;\n"],
5
+ "mappings": "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",
6
6
  "names": ["memize"]
7
7
  }
@@ -120,8 +120,8 @@ var Shortcode = class {
120
120
  this.attrs = attributes;
121
121
  } else {
122
122
  Object.entries(attributes).forEach(([key, value]) => {
123
- if (typeof value === "string" || typeof value === "undefined") {
124
- this.set(key, value);
123
+ if (value !== void 0) {
124
+ this.set(key, String(value));
125
125
  }
126
126
  });
127
127
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts"],
4
- "sourcesContent": ["/**\n * External dependencies\n */\nimport memize from 'memize';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tShortcodeAttrs,\n\tShortcodeMatch,\n\tShortcodeOptions,\n\tMatch,\n\tReplaceCallback,\n\tShortcodeInstance,\n} from './types';\n\nexport * from './types';\n\n/**\n * Find the next matching shortcode.\n *\n * @param tag Shortcode tag.\n * @param text Text to search.\n * @param index Index to start search from.\n *\n * @return Matched information.\n */\nexport function next(\n\ttag: string,\n\ttext: string,\n\tindex: number = 0\n): ShortcodeMatch | undefined {\n\tconst re = regexp( tag );\n\n\tre.lastIndex = index;\n\n\tconst match = re.exec( text );\n\n\tif ( ! match ) {\n\t\treturn;\n\t}\n\n\t// If we matched an escaped shortcode, try again.\n\tif ( '[' === match[ 1 ] && ']' === match[ 7 ] ) {\n\t\treturn next( tag, text, re.lastIndex );\n\t}\n\n\tconst result: ShortcodeMatch = {\n\t\tindex: match.index,\n\t\tcontent: match[ 0 ],\n\t\tshortcode: fromMatch( match ),\n\t};\n\n\t// If we matched a leading `[`, strip it from the match and increment the\n\t// index accordingly.\n\tif ( match[ 1 ] ) {\n\t\tresult.content = result.content.slice( 1 );\n\t\tresult.index++;\n\t}\n\n\t// If we matched a trailing `]`, strip it from the match.\n\tif ( match[ 7 ] ) {\n\t\tresult.content = result.content.slice( 0, -1 );\n\t}\n\n\treturn result;\n}\n\n/**\n * Replace matching shortcodes in a block of text.\n *\n * @param tag Shortcode tag.\n * @param text Text to search.\n * @param callback Function to process the match and return\n * replacement string.\n *\n * @return Text with shortcodes replaced.\n */\nexport function replace(\n\ttag: string,\n\ttext: string,\n\tcallback: ReplaceCallback\n) {\n\treturn text.replace(\n\t\tregexp( tag ),\n\t\t// Let us use spread syntax to capture the arguments object.\n\t\t( ...args: string[] ): string => {\n\t\t\tconst match = args[ 0 ];\n\t\t\tconst left = args[ 1 ];\n\t\t\tconst right = args[ 7 ];\n\n\t\t\t// If both extra brackets exist, the shortcode has been properly\n\t\t\t// escaped.\n\t\t\tif ( left === '[' && right === ']' ) {\n\t\t\t\treturn match;\n\t\t\t}\n\n\t\t\t// Create the match object and pass it through the callback.\n\t\t\tconst result = callback( fromMatch( args ) );\n\n\t\t\t// Make sure to return any of the extra brackets if they weren't used to\n\t\t\t// escape the shortcode.\n\t\t\treturn result || result === '' ? left + result + right : match;\n\t\t}\n\t);\n}\n\n/**\n * Generate a string from shortcode parameters.\n *\n * Creates a shortcode instance and returns a string.\n *\n * Accepts the same `options` as the `shortcode()` constructor, containing a\n * `tag` string, a string or object of `attrs`, a boolean indicating whether to\n * format the shortcode using a `single` tag, and a `content` string.\n *\n * @param options Shortcode options.\n *\n * @return String representation of the shortcode.\n */\nexport function string( options: ShortcodeOptions ): string {\n\treturn new Shortcode( options ).string();\n}\n\n/**\n * Generate a RegExp to identify a shortcode.\n *\n * The base regex is functionally equivalent to the one found in\n * `get_shortcode_regex()` in `wp-includes/shortcodes.php`.\n *\n * Capture groups:\n *\n * 1. An extra `[` to allow for escaping shortcodes with double `[[]]`\n * 2. The shortcode name\n * 3. The shortcode argument list\n * 4. The self closing `/`\n * 5. The content of a shortcode when it wraps some content.\n * 6. The closing tag.\n * 7. An extra `]` to allow for escaping shortcodes with double `[[]]`\n *\n * @param tag Shortcode tag.\n *\n * @return Shortcode RegExp.\n */\nexport function regexp( tag: string ): RegExp {\n\treturn new RegExp(\n\t\t'\\\\[(\\\\[?)(' +\n\t\t\ttag +\n\t\t\t')(?![\\\\w-])([^\\\\]\\\\/]*(?:\\\\/(?!\\\\])[^\\\\]\\\\/]*)*?)(?:(\\\\/)\\\\]|\\\\](?:([^\\\\[]*(?:\\\\[(?!\\\\/\\\\2\\\\])[^\\\\[]*)*)(\\\\[\\\\/\\\\2\\\\]))?)(\\\\]?)',\n\t\t'g'\n\t);\n}\n\n/**\n * Parse shortcode attributes.\n *\n * Shortcodes accept many types of attributes. These can chiefly be divided into\n * named and numeric attributes:\n *\n * Named attributes are assigned on a key/value basis, while numeric attributes\n * are treated as an array.\n *\n * Named attributes can be formatted as either `name=\"value\"`, `name='value'`,\n * or `name=value`. Numeric attributes can be formatted as `\"value\"` or just\n * `value`.\n *\n * @param {string} text Serialised shortcode attributes.\n *\n * @return {ShortcodeAttrs} Parsed shortcode attributes.\n */\nexport const attrs = memize( ( text: string ): ShortcodeAttrs => {\n\tconst named: Record< string, string | undefined > = {};\n\tconst numeric: string[] = [];\n\n\t// This regular expression is reused from `shortcode_parse_atts()` in\n\t// `wp-includes/shortcodes.php`.\n\t//\n\t// Capture groups:\n\t//\n\t// 1. An attribute name, that corresponds to...\n\t// 2. a value in double quotes.\n\t// 3. An attribute name, that corresponds to...\n\t// 4. a value in single quotes.\n\t// 5. An attribute name, that corresponds to...\n\t// 6. an unquoted value.\n\t// 7. A numeric attribute in double quotes.\n\t// 8. A numeric attribute in single quotes.\n\t// 9. An unquoted numeric attribute.\n\tconst pattern =\n\t\t/([\\w-]+)\\s*=\\s*\"([^\"]*)\"(?:\\s|$)|([\\w-]+)\\s*=\\s*'([^']*)'(?:\\s|$)|([\\w-]+)\\s*=\\s*([^\\s'\"]+)(?:\\s|$)|\"([^\"]*)\"(?:\\s|$)|'([^']*)'(?:\\s|$)|(\\S+)(?:\\s|$)/g;\n\n\t// Map zero-width spaces to actual spaces.\n\ttext = text.replace( /[\\u00a0\\u200b]/g, ' ' );\n\n\tlet match;\n\n\t// Match and normalize attributes.\n\twhile ( ( match = pattern.exec( text ) ) ) {\n\t\tif ( match[ 1 ] ) {\n\t\t\tnamed[ match[ 1 ].toLowerCase() ] = match[ 2 ];\n\t\t} else if ( match[ 3 ] ) {\n\t\t\tnamed[ match[ 3 ].toLowerCase() ] = match[ 4 ];\n\t\t} else if ( match[ 5 ] ) {\n\t\t\tnamed[ match[ 5 ].toLowerCase() ] = match[ 6 ];\n\t\t} else if ( match[ 7 ] ) {\n\t\t\tnumeric.push( match[ 7 ] );\n\t\t} else if ( match[ 8 ] ) {\n\t\t\tnumeric.push( match[ 8 ] );\n\t\t} else if ( match[ 9 ] ) {\n\t\t\tnumeric.push( match[ 9 ] );\n\t\t}\n\t}\n\n\treturn { named, numeric };\n} );\n\n/**\n * Generate a Shortcode Object from a RegExp match.\n *\n * Accepts a `match` object from calling `regexp.exec()` on a `RegExp` generated\n * by `regexp()`. `match` can also be set to the `arguments` from a callback\n * passed to `regexp.replace()`.\n *\n * @param match Match array.\n *\n * @return Shortcode instance.\n */\nexport function fromMatch( match: Match ): ShortcodeInstance {\n\tlet type: 'self-closing' | 'closed' | 'single';\n\n\tif ( match[ 4 ] ) {\n\t\ttype = 'self-closing';\n\t} else if ( match[ 6 ] ) {\n\t\ttype = 'closed';\n\t} else {\n\t\ttype = 'single';\n\t}\n\n\treturn new Shortcode( {\n\t\ttag: match[ 2 ],\n\t\tattrs: match[ 3 ],\n\t\ttype,\n\t\tcontent: match[ 5 ],\n\t} );\n}\n\n/**\n * Creates a shortcode instance.\n *\n * To access a raw representation of a shortcode, pass an `options` object,\n * containing a `tag` string, a string or object of `attrs`, a string indicating\n * the `type` of the shortcode ('single', 'self-closing', or 'closed'), and a\n * `content` string.\n */\nclass Shortcode implements ShortcodeInstance {\n\t// Instance properties\n\ttag: string;\n\ttype?: 'self-closing' | 'closed' | 'single';\n\tcontent?: string;\n\tattrs: ShortcodeAttrs;\n\n\t// Static methods\n\tstatic next = next;\n\tstatic replace = replace;\n\tstatic string = string;\n\tstatic regexp = regexp;\n\tstatic attrs = attrs;\n\tstatic fromMatch = fromMatch;\n\n\tconstructor( options: ShortcodeOptions ) {\n\t\tconst { tag, attrs: attributes, type, content } = options;\n\t\tthis.tag = tag;\n\t\tthis.type = type;\n\t\tthis.content = content;\n\n\t\t// Ensure we have a correctly formatted `attrs` object.\n\t\tthis.attrs = {\n\t\t\tnamed: {},\n\t\t\tnumeric: [],\n\t\t};\n\n\t\tif ( ! attributes ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Parse a string of attributes.\n\t\tif ( typeof attributes === 'string' ) {\n\t\t\tthis.attrs = attrs( attributes );\n\t\t\t// Identify a correctly formatted `attrs` object.\n\t\t} else if (\n\t\t\t'named' in attributes &&\n\t\t\t'numeric' in attributes &&\n\t\t\tattributes.named !== undefined &&\n\t\t\tattributes.numeric !== undefined\n\t\t) {\n\t\t\tthis.attrs = attributes as ShortcodeAttrs;\n\t\t\t// Handle a flat object of attributes (e.g., { foo: 'bar', baz: 'qux' }).\n\t\t} else {\n\t\t\tObject.entries( attributes ).forEach( ( [ key, value ] ) => {\n\t\t\t\tif (\n\t\t\t\t\ttypeof value === 'string' ||\n\t\t\t\t\ttypeof value === 'undefined'\n\t\t\t\t) {\n\t\t\t\t\tthis.set( key, value );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Get a shortcode attribute.\n\t *\n\t * Automatically detects whether `attr` is named or numeric and routes it\n\t * accordingly.\n\t *\n\t * @param attr Attribute key.\n\t *\n\t * @return Attribute value.\n\t */\n\tget( attr: string | number ): string | undefined {\n\t\tif ( typeof attr === 'number' ) {\n\t\t\treturn this.attrs.numeric[ attr ];\n\t\t}\n\t\treturn this.attrs.named[ attr ];\n\t}\n\n\t/**\n\t * Set a shortcode attribute.\n\t *\n\t * Automatically detects whether `attr` is named or numeric and routes it\n\t * accordingly.\n\t *\n\t * @param attr Attribute key.\n\t * @param value Attribute value.\n\t *\n\t * @return Shortcode instance.\n\t */\n\tset( attr: string | number, value: string ): this {\n\t\tif ( typeof attr === 'number' ) {\n\t\t\tthis.attrs.numeric[ attr ] = value;\n\t\t} else {\n\t\t\tthis.attrs.named[ attr ] = value;\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Transform the shortcode into a string.\n\t *\n\t * @return String representation of the shortcode.\n\t */\n\tstring(): string {\n\t\tlet text = '[' + this.tag;\n\n\t\tthis.attrs.numeric.forEach( ( value ) => {\n\t\t\tif ( /\\s/.test( value ) ) {\n\t\t\t\ttext += ' \"' + value + '\"';\n\t\t\t} else {\n\t\t\t\ttext += ' ' + value;\n\t\t\t}\n\t\t} );\n\n\t\tObject.entries( this.attrs.named ).forEach( ( [ name, value ] ) => {\n\t\t\ttext += ' ' + name + '=\"' + value + '\"';\n\t\t} );\n\n\t\t// If the tag is marked as `single` or `self-closing`, close the tag and\n\t\t// ignore any additional content.\n\t\tif ( 'single' === this.type ) {\n\t\t\treturn text + ']';\n\t\t} else if ( 'self-closing' === this.type ) {\n\t\t\treturn text + ' /]';\n\t\t}\n\n\t\t// Complete the opening tag.\n\t\ttext += ']';\n\n\t\tif ( this.content ) {\n\t\t\ttext += this.content;\n\t\t}\n\n\t\t// Add the closing tag.\n\t\treturn text + '[/' + this.tag + ']';\n\t}\n}\n\nexport default Shortcode;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * External dependencies\n */\nimport memize from 'memize';\n\n/**\n * Internal dependencies\n */\nimport type {\n\tShortcodeAttrs,\n\tShortcodeMatch,\n\tShortcodeOptions,\n\tMatch,\n\tReplaceCallback,\n\tShortcodeInstance,\n} from './types';\n\nexport * from './types';\n\n/**\n * Find the next matching shortcode.\n *\n * @param tag Shortcode tag.\n * @param text Text to search.\n * @param index Index to start search from.\n *\n * @return Matched information.\n */\nexport function next(\n\ttag: string,\n\ttext: string,\n\tindex: number = 0\n): ShortcodeMatch | undefined {\n\tconst re = regexp( tag );\n\n\tre.lastIndex = index;\n\n\tconst match = re.exec( text );\n\n\tif ( ! match ) {\n\t\treturn;\n\t}\n\n\t// If we matched an escaped shortcode, try again.\n\tif ( '[' === match[ 1 ] && ']' === match[ 7 ] ) {\n\t\treturn next( tag, text, re.lastIndex );\n\t}\n\n\tconst result: ShortcodeMatch = {\n\t\tindex: match.index,\n\t\tcontent: match[ 0 ],\n\t\tshortcode: fromMatch( match ),\n\t};\n\n\t// If we matched a leading `[`, strip it from the match and increment the\n\t// index accordingly.\n\tif ( match[ 1 ] ) {\n\t\tresult.content = result.content.slice( 1 );\n\t\tresult.index++;\n\t}\n\n\t// If we matched a trailing `]`, strip it from the match.\n\tif ( match[ 7 ] ) {\n\t\tresult.content = result.content.slice( 0, -1 );\n\t}\n\n\treturn result;\n}\n\n/**\n * Replace matching shortcodes in a block of text.\n *\n * @param tag Shortcode tag.\n * @param text Text to search.\n * @param callback Function to process the match and return\n * replacement string.\n *\n * @return Text with shortcodes replaced.\n */\nexport function replace(\n\ttag: string,\n\ttext: string,\n\tcallback: ReplaceCallback\n) {\n\treturn text.replace(\n\t\tregexp( tag ),\n\t\t// Let us use spread syntax to capture the arguments object.\n\t\t( ...args: string[] ): string => {\n\t\t\tconst match = args[ 0 ];\n\t\t\tconst left = args[ 1 ];\n\t\t\tconst right = args[ 7 ];\n\n\t\t\t// If both extra brackets exist, the shortcode has been properly\n\t\t\t// escaped.\n\t\t\tif ( left === '[' && right === ']' ) {\n\t\t\t\treturn match;\n\t\t\t}\n\n\t\t\t// Create the match object and pass it through the callback.\n\t\t\tconst result = callback( fromMatch( args ) );\n\n\t\t\t// Make sure to return any of the extra brackets if they weren't used to\n\t\t\t// escape the shortcode.\n\t\t\treturn result || result === '' ? left + result + right : match;\n\t\t}\n\t);\n}\n\n/**\n * Generate a string from shortcode parameters.\n *\n * Creates a shortcode instance and returns a string.\n *\n * Accepts the same `options` as the `shortcode()` constructor, containing a\n * `tag` string, a string or object of `attrs`, a boolean indicating whether to\n * format the shortcode using a `single` tag, and a `content` string.\n *\n * @param options Shortcode options.\n *\n * @return String representation of the shortcode.\n */\nexport function string( options: ShortcodeOptions ): string {\n\treturn new Shortcode( options ).string();\n}\n\n/**\n * Generate a RegExp to identify a shortcode.\n *\n * The base regex is functionally equivalent to the one found in\n * `get_shortcode_regex()` in `wp-includes/shortcodes.php`.\n *\n * Capture groups:\n *\n * 1. An extra `[` to allow for escaping shortcodes with double `[[]]`\n * 2. The shortcode name\n * 3. The shortcode argument list\n * 4. The self closing `/`\n * 5. The content of a shortcode when it wraps some content.\n * 6. The closing tag.\n * 7. An extra `]` to allow for escaping shortcodes with double `[[]]`\n *\n * @param tag Shortcode tag.\n *\n * @return Shortcode RegExp.\n */\nexport function regexp( tag: string ): RegExp {\n\treturn new RegExp(\n\t\t'\\\\[(\\\\[?)(' +\n\t\t\ttag +\n\t\t\t')(?![\\\\w-])([^\\\\]\\\\/]*(?:\\\\/(?!\\\\])[^\\\\]\\\\/]*)*?)(?:(\\\\/)\\\\]|\\\\](?:([^\\\\[]*(?:\\\\[(?!\\\\/\\\\2\\\\])[^\\\\[]*)*)(\\\\[\\\\/\\\\2\\\\]))?)(\\\\]?)',\n\t\t'g'\n\t);\n}\n\n/**\n * Parse shortcode attributes.\n *\n * Shortcodes accept many types of attributes. These can chiefly be divided into\n * named and numeric attributes:\n *\n * Named attributes are assigned on a key/value basis, while numeric attributes\n * are treated as an array.\n *\n * Named attributes can be formatted as either `name=\"value\"`, `name='value'`,\n * or `name=value`. Numeric attributes can be formatted as `\"value\"` or just\n * `value`.\n *\n * @param {string} text Serialised shortcode attributes.\n *\n * @return {ShortcodeAttrs} Parsed shortcode attributes.\n */\nexport const attrs = memize( ( text: string ): ShortcodeAttrs => {\n\tconst named: Record< string, string | undefined > = {};\n\tconst numeric: string[] = [];\n\n\t// This regular expression is reused from `shortcode_parse_atts()` in\n\t// `wp-includes/shortcodes.php`.\n\t//\n\t// Capture groups:\n\t//\n\t// 1. An attribute name, that corresponds to...\n\t// 2. a value in double quotes.\n\t// 3. An attribute name, that corresponds to...\n\t// 4. a value in single quotes.\n\t// 5. An attribute name, that corresponds to...\n\t// 6. an unquoted value.\n\t// 7. A numeric attribute in double quotes.\n\t// 8. A numeric attribute in single quotes.\n\t// 9. An unquoted numeric attribute.\n\tconst pattern =\n\t\t/([\\w-]+)\\s*=\\s*\"([^\"]*)\"(?:\\s|$)|([\\w-]+)\\s*=\\s*'([^']*)'(?:\\s|$)|([\\w-]+)\\s*=\\s*([^\\s'\"]+)(?:\\s|$)|\"([^\"]*)\"(?:\\s|$)|'([^']*)'(?:\\s|$)|(\\S+)(?:\\s|$)/g;\n\n\t// Map zero-width spaces to actual spaces.\n\ttext = text.replace( /[\\u00a0\\u200b]/g, ' ' );\n\n\tlet match;\n\n\t// Match and normalize attributes.\n\twhile ( ( match = pattern.exec( text ) ) ) {\n\t\tif ( match[ 1 ] ) {\n\t\t\tnamed[ match[ 1 ].toLowerCase() ] = match[ 2 ];\n\t\t} else if ( match[ 3 ] ) {\n\t\t\tnamed[ match[ 3 ].toLowerCase() ] = match[ 4 ];\n\t\t} else if ( match[ 5 ] ) {\n\t\t\tnamed[ match[ 5 ].toLowerCase() ] = match[ 6 ];\n\t\t} else if ( match[ 7 ] ) {\n\t\t\tnumeric.push( match[ 7 ] );\n\t\t} else if ( match[ 8 ] ) {\n\t\t\tnumeric.push( match[ 8 ] );\n\t\t} else if ( match[ 9 ] ) {\n\t\t\tnumeric.push( match[ 9 ] );\n\t\t}\n\t}\n\n\treturn { named, numeric };\n} );\n\n/**\n * Generate a Shortcode Object from a RegExp match.\n *\n * Accepts a `match` object from calling `regexp.exec()` on a `RegExp` generated\n * by `regexp()`. `match` can also be set to the `arguments` from a callback\n * passed to `regexp.replace()`.\n *\n * @param match Match array.\n *\n * @return Shortcode instance.\n */\nexport function fromMatch( match: Match ): ShortcodeInstance {\n\tlet type: 'self-closing' | 'closed' | 'single';\n\n\tif ( match[ 4 ] ) {\n\t\ttype = 'self-closing';\n\t} else if ( match[ 6 ] ) {\n\t\ttype = 'closed';\n\t} else {\n\t\ttype = 'single';\n\t}\n\n\treturn new Shortcode( {\n\t\ttag: match[ 2 ],\n\t\tattrs: match[ 3 ],\n\t\ttype,\n\t\tcontent: match[ 5 ],\n\t} );\n}\n\n/**\n * Creates a shortcode instance.\n *\n * To access a raw representation of a shortcode, pass an `options` object,\n * containing a `tag` string, a string or object of `attrs`, a string indicating\n * the `type` of the shortcode ('single', 'self-closing', or 'closed'), and a\n * `content` string.\n */\nclass Shortcode implements ShortcodeInstance {\n\t// Instance properties\n\ttag: string;\n\ttype?: 'self-closing' | 'closed' | 'single';\n\tcontent?: string;\n\tattrs: ShortcodeAttrs;\n\n\t// Static methods\n\tstatic next = next;\n\tstatic replace = replace;\n\tstatic string = string;\n\tstatic regexp = regexp;\n\tstatic attrs = attrs;\n\tstatic fromMatch = fromMatch;\n\n\tconstructor( options: ShortcodeOptions ) {\n\t\tconst { tag, attrs: attributes, type, content } = options;\n\t\tthis.tag = tag;\n\t\tthis.type = type;\n\t\tthis.content = content;\n\n\t\t// Ensure we have a correctly formatted `attrs` object.\n\t\tthis.attrs = {\n\t\t\tnamed: {},\n\t\t\tnumeric: [],\n\t\t};\n\n\t\tif ( ! attributes ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Parse a string of attributes.\n\t\tif ( typeof attributes === 'string' ) {\n\t\t\tthis.attrs = attrs( attributes );\n\t\t\t// Identify a correctly formatted `attrs` object.\n\t\t} else if (\n\t\t\t'named' in attributes &&\n\t\t\t'numeric' in attributes &&\n\t\t\tattributes.named !== undefined &&\n\t\t\tattributes.numeric !== undefined\n\t\t) {\n\t\t\tthis.attrs = attributes as ShortcodeAttrs;\n\t\t\t// Handle a flat object of attributes (e.g., { foo: 'bar', baz: 'qux' }).\n\t\t} else {\n\t\t\tObject.entries( attributes ).forEach( ( [ key, value ] ) => {\n\t\t\t\tif ( value !== undefined ) {\n\t\t\t\t\t// Coerce non-string values to strings to maintain backward compatibility.\n\t\t\t\t\tthis.set( key, String( value ) );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Get a shortcode attribute.\n\t *\n\t * Automatically detects whether `attr` is named or numeric and routes it\n\t * accordingly.\n\t *\n\t * @param attr Attribute key.\n\t *\n\t * @return Attribute value.\n\t */\n\tget( attr: string | number ): string | undefined {\n\t\tif ( typeof attr === 'number' ) {\n\t\t\treturn this.attrs.numeric[ attr ];\n\t\t}\n\t\treturn this.attrs.named[ attr ];\n\t}\n\n\t/**\n\t * Set a shortcode attribute.\n\t *\n\t * Automatically detects whether `attr` is named or numeric and routes it\n\t * accordingly.\n\t *\n\t * @param attr Attribute key.\n\t * @param value Attribute value.\n\t *\n\t * @return Shortcode instance.\n\t */\n\tset( attr: string | number, value: string ): this {\n\t\tif ( typeof attr === 'number' ) {\n\t\t\tthis.attrs.numeric[ attr ] = value;\n\t\t} else {\n\t\t\tthis.attrs.named[ attr ] = value;\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Transform the shortcode into a string.\n\t *\n\t * @return String representation of the shortcode.\n\t */\n\tstring(): string {\n\t\tlet text = '[' + this.tag;\n\n\t\tthis.attrs.numeric.forEach( ( value ) => {\n\t\t\tif ( /\\s/.test( value ) ) {\n\t\t\t\ttext += ' \"' + value + '\"';\n\t\t\t} else {\n\t\t\t\ttext += ' ' + value;\n\t\t\t}\n\t\t} );\n\n\t\tObject.entries( this.attrs.named ).forEach( ( [ name, value ] ) => {\n\t\t\ttext += ' ' + name + '=\"' + value + '\"';\n\t\t} );\n\n\t\t// If the tag is marked as `single` or `self-closing`, close the tag and\n\t\t// ignore any additional content.\n\t\tif ( 'single' === this.type ) {\n\t\t\treturn text + ']';\n\t\t} else if ( 'self-closing' === this.type ) {\n\t\t\treturn text + ' /]';\n\t\t}\n\n\t\t// Complete the opening tag.\n\t\ttext += ']';\n\n\t\tif ( this.content ) {\n\t\t\ttext += this.content;\n\t\t}\n\n\t\t// Add the closing tag.\n\t\treturn text + '[/' + this.tag + ']';\n\t}\n}\n\nexport default Shortcode;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EACX,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,KAAK,EACL,eAAe,EACf,iBAAiB,EACjB,MAAM,SAAS,CAAC;AAEjB,cAAc,SAAS,CAAC;AAExB;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CACnB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAU,GACf,cAAc,GAAG,SAAS,CAmC5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,eAAe,UAwBzB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAE,OAAO,EAAE,gBAAgB,GAAI,MAAM,CAE1D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CAAE,GAAG,EAAE,MAAM,GAAI,MAAM,CAO5C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,KAAK,8EA4Cf,CAAC;AAEJ;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAE,KAAK,EAAE,KAAK,GAAI,iBAAiB,CAiB3D;AAED;;;;;;;GAOG;AACH,cAAM,SAAU,YAAW,iBAAiB;IAE3C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,cAAc,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,cAAc,CAAC;IAGtB,MAAM,CAAC,IAAI,cAAQ;IACnB,MAAM,CAAC,OAAO,iBAAW;IACzB,MAAM,CAAC,MAAM,gBAAU;IACvB,MAAM,CAAC,MAAM,gBAAU;IACvB,MAAM,CAAC,KAAK,+EAAS;IACrB,MAAM,CAAC,SAAS,mBAAa;gBAEhB,OAAO,EAAE,gBAAgB;IAwCtC;;;;;;;;;OASG;IACH,GAAG,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAI,MAAM,GAAG,SAAS;IAOhD;;;;;;;;;;OAUG;IACH,GAAG,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAI,IAAI;IASjD;;;;OAIG;IACH,MAAM,IAAI,MAAM;CAiChB;AAED,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,OAAO,KAAK,EACX,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,KAAK,EACL,eAAe,EACf,iBAAiB,EACjB,MAAM,SAAS,CAAC;AAEjB,cAAc,SAAS,CAAC;AAExB;;;;;;;;GAQG;AACH,wBAAgB,IAAI,CACnB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAU,GACf,cAAc,GAAG,SAAS,CAmC5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CACtB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,eAAe,UAwBzB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,MAAM,CAAE,OAAO,EAAE,gBAAgB,GAAI,MAAM,CAE1D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CAAE,GAAG,EAAE,MAAM,GAAI,MAAM,CAO5C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,KAAK,8EA4Cf,CAAC;AAEJ;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAE,KAAK,EAAE,KAAK,GAAI,iBAAiB,CAiB3D;AAED;;;;;;;GAOG;AACH,cAAM,SAAU,YAAW,iBAAiB;IAE3C,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,cAAc,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,cAAc,CAAC;IAGtB,MAAM,CAAC,IAAI,cAAQ;IACnB,MAAM,CAAC,OAAO,iBAAW;IACzB,MAAM,CAAC,MAAM,gBAAU;IACvB,MAAM,CAAC,MAAM,gBAAU;IACvB,MAAM,CAAC,KAAK,+EAAS;IACrB,MAAM,CAAC,SAAS,mBAAa;gBAEhB,OAAO,EAAE,gBAAgB;IAsCtC;;;;;;;;;OASG;IACH,GAAG,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAI,MAAM,GAAG,SAAS;IAOhD;;;;;;;;;;OAUG;IACH,GAAG,CAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAI,IAAI;IASjD;;;;OAIG;IACH,MAAM,IAAI,MAAM;CAiChB;AAED,eAAe,SAAS,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/shortcode",
3
- "version": "4.38.0",
3
+ "version": "4.39.0",
4
4
  "description": "Shortcode module for WordPress.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -49,5 +49,5 @@
49
49
  "publishConfig": {
50
50
  "access": "public"
51
51
  },
52
- "gitHead": "50c4c0f51e4797c217946ce42adfaa5eb026f33f"
52
+ "gitHead": "eee1cfb1472f11183e40fb77465a5f13145df7ad"
53
53
  }
package/src/index.ts CHANGED
@@ -298,11 +298,9 @@ class Shortcode implements ShortcodeInstance {
298
298
  // Handle a flat object of attributes (e.g., { foo: 'bar', baz: 'qux' }).
299
299
  } else {
300
300
  Object.entries( attributes ).forEach( ( [ key, value ] ) => {
301
- if (
302
- typeof value === 'string' ||
303
- typeof value === 'undefined'
304
- ) {
305
- this.set( key, value );
301
+ if ( value !== undefined ) {
302
+ // Coerce non-string values to strings to maintain backward compatibility.
303
+ this.set( key, String( value ) );
306
304
  }
307
305
  } );
308
306
  }
package/src/test/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import { next, replace, attrs } from '../';
4
+ import { next, replace, attrs, string } from '../';
5
5
 
6
6
  describe( 'shortcode', () => {
7
7
  describe( 'next', () => {
@@ -306,4 +306,27 @@ describe( 'shortcode', () => {
306
306
  expect( result ).toEqual( expected );
307
307
  } );
308
308
  } );
309
+
310
+ describe( 'string', () => {
311
+ it( 'should coerce non-string attribute values to strings and skip undefined', () => {
312
+ const result = string( {
313
+ tag: 'gallery',
314
+ attrs: {
315
+ // @ts-expect-error TS is not happy about unknown properties here.
316
+ ids: [ 1, 2, 3 ],
317
+ columns: 4,
318
+ // Note: Objects are coerced to "[object Object]" which is not useful.
319
+ // Passing objects as attribute values should be avoided in real usage.
320
+ data: { test: 'value' },
321
+ flip: true,
322
+ // Undefined values should be skipped entirely.
323
+ missing: undefined,
324
+ },
325
+ type: 'single',
326
+ } );
327
+ expect( result ).toBe(
328
+ '[gallery ids="1,2,3" columns="4" data="[object Object]" flip="true"]'
329
+ );
330
+ } );
331
+ } );
309
332
  } );