Skip to content

Commit

Permalink
Add types for shortcode package (#67416)
Browse files Browse the repository at this point in the history
* Add types for shortcode package

* Remove WP Prefix

* Update CHANGELOG.md

Co-authored-by: manzoorwanijk <[email protected]>
Co-authored-by: gziolo <[email protected]>
  • Loading branch information
3 people authored Nov 30, 2024
1 parent 9defe9f commit 9610000
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 51 deletions.
4 changes: 4 additions & 0 deletions packages/shortcode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

## Enhancements

- The package now has built-in TypeScript definitions 🎉 ([#67416](https://github.com/WordPress/gutenberg/pull/67416))

## 4.13.0 (2024-11-27)

## 4.12.0 (2024-11-16)
Expand Down
18 changes: 7 additions & 11 deletions packages/shortcode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,17 @@ _Parameters_

_Returns_

- `WPShortcodeAttrs`: Parsed shortcode attributes.
- `import('./types').ShortcodeAttrs`: Parsed shortcode attributes.

### default

Creates a shortcode instance.

To access a raw representation of a shortcode, pass an `options` object, containing a `tag` string, a string or object of `attrs`, a string indicating the `type` of the shortcode ('single', 'self-closing', or 'closed'), and a `content` string.

_Parameters_

- _options_ `Object`: Options as described.

_Returns_
_Type_

- `WPShortcode`: Shortcode instance.
- `import('./types').shortcode`Shortcode instance.

### fromMatch

Expand All @@ -56,11 +52,11 @@ Accepts a `match` object from calling `regexp.exec()` on a `RegExp` generated by

_Parameters_

- _match_ `Array`: Match array.
- _match_ `import('./types').Match`: Match array.

_Returns_

- `WPShortcode`: Shortcode instance.
- `InstanceType<import('./types').shortcode>`: Shortcode instance.

### next

Expand All @@ -74,7 +70,7 @@ _Parameters_

_Returns_

- `WPShortcodeMatch | undefined`: Matched information.
- `import('./types').ShortcodeMatch | undefined`: Matched information.

### regexp

Expand Down Expand Up @@ -108,7 +104,7 @@ _Parameters_

- _tag_ `string`: Shortcode tag.
- _text_ `string`: Text to search.
- _callback_ `Function`: Function to process the match and return replacement string.
- _callback_ `import('./types').ReplaceCallback`: Function to process the match and return replacement string.

_Returns_

Expand Down
1 change: 1 addition & 0 deletions packages/shortcode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"module": "build-module/index.js",
"react-native": "src/index",
"wpScript": true,
"types": "build-types",
"dependencies": {
"@babel/runtime": "7.25.7",
"memize": "^2.0.1"
Expand Down
51 changes: 11 additions & 40 deletions packages/shortcode/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,7 @@
*/
import memize from 'memize';

/**
* Shortcode attributes object.
*
* @typedef {Object} WPShortcodeAttrs
*
* @property {Object} named Object with named attributes.
* @property {Array} numeric Array with numeric attributes.
*/

/**
* Shortcode object.
*
* @typedef {Object} WPShortcode
*
* @property {string} tag Shortcode tag.
* @property {WPShortcodeAttrs} attrs Shortcode attributes.
* @property {string} content Shortcode content.
* @property {string} type Shortcode type: `self-closing`,
* `closed`, or `single`.
*/

/**
* @typedef {Object} WPShortcodeMatch
*
* @property {number} index Index the shortcode is found at.
* @property {string} content Matched content.
* @property {WPShortcode} shortcode Shortcode instance of the match.
*/
export * from './types';

/**
* Find the next matching shortcode.
Expand All @@ -39,7 +12,7 @@ import memize from 'memize';
* @param {string} text Text to search.
* @param {number} index Index to start search from.
*
* @return {WPShortcodeMatch | undefined} Matched information.
* @return {import('./types').ShortcodeMatch | undefined} Matched information.
*/
export function next( tag, text, index = 0 ) {
const re = regexp( tag );
Expand Down Expand Up @@ -81,10 +54,10 @@ export function next( tag, text, index = 0 ) {
/**
* Replace matching shortcodes in a block of text.
*
* @param {string} tag Shortcode tag.
* @param {string} text Text to search.
* @param {Function} callback Function to process the match and return
* replacement string.
* @param {string} tag Shortcode tag.
* @param {string} text Text to search.
* @param {import('./types').ReplaceCallback} callback Function to process the match and return
* replacement string.
*
* @return {string} Text with shortcodes replaced.
*/
Expand Down Expand Up @@ -169,7 +142,7 @@ export function regexp( tag ) {
*
* @param {string} text Serialised shortcode attributes.
*
* @return {WPShortcodeAttrs} Parsed shortcode attributes.
* @return {import('./types').ShortcodeAttrs} Parsed shortcode attributes.
*/
export const attrs = memize( ( text ) => {
const named = {};
Expand Down Expand Up @@ -224,9 +197,9 @@ export const attrs = memize( ( text ) => {
* by `regexp()`. `match` can also be set to the `arguments` from a callback
* passed to `regexp.replace()`.
*
* @param {Array} match Match array.
* @param {import('./types').Match} match Match array.
*
* @return {WPShortcode} Shortcode instance.
* @return {InstanceType<import('./types').shortcode>} Shortcode instance.
*/
export function fromMatch( match ) {
let type;
Expand Down Expand Up @@ -255,9 +228,7 @@ export function fromMatch( match ) {
* the `type` of the shortcode ('single', 'self-closing', or 'closed'), and a
* `content` string.
*
* @param {Object} options Options as described.
*
* @return {WPShortcode} Shortcode instance.
* @type {import('./types').shortcode} Shortcode instance.
*/
const shortcode = Object.assign(
function ( options ) {
Expand Down Expand Up @@ -328,7 +299,7 @@ Object.assign( shortcode.prototype, {
* @param {(number|string)} attr Attribute key.
* @param {string} value Attribute value.
*
* @return {WPShortcode} Shortcode instance.
* @return {InstanceType< import('./types').shortcode >} Shortcode instance.
*/
set( attr, value ) {
this.attrs[ typeof attr === 'number' ? 'numeric' : 'named' ][ attr ] =
Expand Down
210 changes: 210 additions & 0 deletions packages/shortcode/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/**
* Shortcode attributes object.
*/
export type ShortcodeAttrs = {
/**
* Object with named attributes.
*/
named: Record< string, string | undefined >;

/**
* Array with numeric attributes.
*/
numeric: string[];
};

export type ShortcodeMatch = {
/**
* Index the shortcode is found at.
*/
index: number;

/**
* Matched content.
*/
content: string;

/**
* Shortcode instance of the match.
*/
shortcode: Shortcode;
};

/**
* Shortcode options.
*/
export interface ShortcodeOptions {
/**
* Shortcode tag.
*/
tag: string;

/**
* Shortcode attributes.
*/
attrs?: Partial< ShortcodeAttrs > | string;

/**
* Shortcode content.
*/
content?: string;

/**
* Shortcode type: `self-closing`, `closed`, or `single`.
*/
type?: 'self-closing' | 'closed' | 'single';
}

/**
* Shortcode object.
*/
export interface Shortcode extends ShortcodeOptions {
/**
* Shortcode attributes.
*/
attrs: ShortcodeAttrs;
}

export type Match =
| NonNullable< ReturnType< RegExp[ 'exec' ] > >
| Array< string >;

export type ReplaceCallback = ( shortcode: Shortcode ) => string;

/**
* WordPress Shortcode instance.
*/
export interface shortcode {
new ( options: Partial< ShortcodeOptions > ): Shortcode & {
/**
* Transform the shortcode into a string.
*
* @return {string} String representation of the shortcode.
*/
string: () => string;

/**
* Get a shortcode attribute.
*
* Automatically detects whether `attr` is named or numeric and routes it
* accordingly.
*
* @param {(number|string)} attr Attribute key.
*
* @return {string} Attribute value.
*/
get: ( attr: string | number ) => string | undefined;

/**
* Set a shortcode attribute.
*
* Automatically detects whether `attr` is named or numeric and routes it
* accordingly.
*
* @param {(number|string)} attr Attribute key.
* @param {string} value Attribute value.
*
* @return {InstanceType< shortcode >} Shortcode instance.
*/
set: (
attr: string | number,
value: string
) => InstanceType< shortcode >;
};

/**
* Parse shortcode attributes.
*
* Shortcodes accept many types of attributes. These can chiefly be divided into
* named and numeric attributes:
*
* Named attributes are assigned on a key/value basis, while numeric attributes
* are treated as an array.
*
* Named attributes can be formatted as either `name="value"`, `name='value'`,
* or `name=value`. Numeric attributes can be formatted as `"value"` or just
* `value`.
*
* @param text Serialised shortcode attributes.
*
* @return Parsed shortcode attributes.
*/
attrs: ( text: string ) => ShortcodeAttrs;

/**
* Generate a Shortcode Object from a RegExp match.
*
* Accepts a `match` object from calling `regexp.exec()` on a `RegExp` generated
* by `regexp()`. `match` can also be set to the `arguments` from a callback
* passed to `regexp.replace()`.
*
* @param match Match array.
*
* @return Shortcode instance.
*/
fromMatch: ( match: Match ) => InstanceType< shortcode >;

/**
* Find the next matching shortcode.
*
* @param tag Shortcode tag.
* @param text Text to search.
* @param index Index to start search from.
*
* @return Matched information.
*/
next: (
tag: string,
text: string,
index?: number
) => ShortcodeMatch | undefined;

/**
* Generate a RegExp to identify a shortcode.
*
* The base regex is functionally equivalent to the one found in
* `get_shortcode_regex()` in `wp-includes/shortcodes.php`.
*
* Capture groups:
*
* 1. An extra `[` to allow for escaping shortcodes with double `[[]]`
* 2. The shortcode name
* 3. The shortcode argument list
* 4. The self closing `/`
* 5. The content of a shortcode when it wraps some content.
* 6. The closing tag.
* 7. An extra `]` to allow for escaping shortcodes with double `[[]]`
*
* @param tag Shortcode tag.
*
* @return Shortcode RegExp.
*/
regexp: ( tag: string ) => RegExp;

/**
* Replace matching shortcodes in a block of text.
*
* @param tag Shortcode tag.
* @param text Text to search.
* @param callback Function to process the match and return
* replacement string.
*
* @return Text with shortcodes replaced.
*/
replace: ( tag: string, text: string, callback: ReplaceCallback ) => string;

/**
* Generate a string from shortcode parameters.
*
* Creates a shortcode instance and returns a string.
*
* Accepts the same `options` as the `shortcode()` constructor, containing a
* `tag` string, a string or object of `attrs`, a boolean indicating whether to
* format the shortcode using a `single` tag, and a `content` string.
*
* @param options
*
* @return String representation of the shortcode.
*/
string: ( options: ShortcodeOptions ) => string;
}
11 changes: 11 additions & 0 deletions packages/shortcode/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://json.schemastore.org/tsconfig.json",
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"declarationDir": "build-types",
"checkJs": false
},
"references": [],
"include": [ "src" ]
}
Loading

1 comment on commit 9610000

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in 9610000.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/12094749140
📝 Reported issues:

Please sign in to comment.