diff --git a/packages/blocks/README.md b/packages/blocks/README.md index 8c277868a03321..e04239e0e78c75 100644 --- a/packages/blocks/README.md +++ b/packages/blocks/README.md @@ -607,7 +607,31 @@ _Parameters_ ### registerBlockType -Undocumented declaration. +Registers a new block provided a unique name and an object defining its behavior. Once registered, the block is made available as an option to any editor interface where blocks are implemented. + +For more in-depth information on registering a custom block see the [Create a block tutorial](https://developer.wordpress.org/block-editor/getting-started/create-block/). + +_Usage_ + +```js +import { __ } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; + +registerBlockType( 'namespace/block-name', { + title: __( 'My First Block' ), + edit: () =>
{ __( 'Hello from the editor!' ) }
, + save: () =>
Hello from the saved content!
, +} ); +``` + +_Parameters_ + +- _blockNameOrMetadata_ `string | BlockConfiguration< Attributes >`: Block type name or its metadata. +- _settings_ `Partial< BlockConfiguration< Attributes > >`: Block settings. + +_Returns_ + +- `BlockType | undefined`: The block, if it has been successfully registered; otherwise `undefined`. ### registerBlockVariation diff --git a/packages/compose/README.md b/packages/compose/README.md index 0908e8e559948c..57d1ed4fb53056 100644 --- a/packages/compose/README.md +++ b/packages/compose/README.md @@ -394,17 +394,17 @@ _Returns_ ### useInstanceId -Provides a unique instance ID. +Specify the useInstanceId _function_ signatures. -_Parameters_ +More accurately, useInstanceId distinguishes between three different signatures: -- _object_ `object`: Object reference to create an id for. -- _prefix_ `[string]`: Prefix for the unique id. -- _preferredId_ `[string | number]`: Default ID to use. +1. When only object is given, the returned value is a number +2. When object and prefix is given, the returned value is a string +3. When preferredId is given, the returned value is the type of preferredId -_Returns_ +_Parameters_ -- `string | number`: The unique instance id. +- _object_ `object`: Object reference to create an id for. ### useIsomorphicLayoutEffect diff --git a/packages/docgen/lib/get-intermediate-representation.js b/packages/docgen/lib/get-intermediate-representation.js index 9f49fc4d4f93a2..05705718e8d9b5 100644 --- a/packages/docgen/lib/get-intermediate-representation.js +++ b/packages/docgen/lib/get-intermediate-representation.js @@ -15,6 +15,15 @@ const hasClassWithName = ( node, name ) => const hasFunctionWithName = ( node, name ) => node.type === 'FunctionDeclaration' && node.id.name === name; +const hasTSDeclareFunction = ( node, name ) => + node.type === 'TSDeclareFunction' && node.id?.name === name; + +const hasImplementationWithName = ( node, name ) => + hasFunctionWithName( node, name ) || + ( node.type === 'ExportNamedDeclaration' && + node.declaration && + hasFunctionWithName( node.declaration, name ) ); + const hasVariableWithName = ( node, name ) => node.type === 'VariableDeclaration' && node.declarations.some( ( declaration ) => { @@ -32,6 +41,8 @@ const hasNamedExportWithName = ( node, name ) => node.type === 'ExportNamedDeclaration' && ( ( node.declaration && hasClassWithName( node.declaration, name ) ) || ( node.declaration && hasFunctionWithName( node.declaration, name ) ) || + ( node.declaration && + hasTSDeclareFunction( node.declaration, name ) ) || ( node.declaration && hasVariableWithName( node.declaration, name ) ) ); const hasImportWithName = ( node, name ) => @@ -91,19 +102,27 @@ const getJSDoc = ( token, entry, ast, parseDependency ) => { return ( hasClassWithName( node, entry.localName ) || hasFunctionWithName( node, entry.localName ) || + hasTSDeclareFunction( node, entry.localName ) || hasVariableWithName( node, entry.localName ) || hasNamedExportWithName( node, entry.localName ) || hasImportWithName( node, entry.localName ) ); } ); - if ( candidates.length !== 1 ) { + if ( candidates.length === 0 ) { return doc; } - const node = candidates[ 0 ]; - if ( isImportDeclaration( node ) ) { - doc = getJSDocFromDependency( node, entry, parseDependency ); - } else { - doc = getJSDocFromToken( node ); + const implementationNode = candidates.find( ( node ) => + hasImplementationWithName( node, entry.localName ) + ); + for ( const node of candidates ) { + if ( isImportDeclaration( node ) ) { + doc = getJSDocFromDependency( node, entry, parseDependency ); + } else { + doc = getJSDocFromToken( node, implementationNode ?? node ); + } + if ( doc !== undefined ) { + return doc; + } } return doc; } diff --git a/packages/docgen/lib/get-jsdoc-from-token.js b/packages/docgen/lib/get-jsdoc-from-token.js index 4b364c9a561b08..7bfe5141e55a0a 100644 --- a/packages/docgen/lib/get-jsdoc-from-token.js +++ b/packages/docgen/lib/get-jsdoc-from-token.js @@ -14,10 +14,14 @@ const getTypeAnnotation = require( './get-type-annotation' ); * a object representing the leading JSDoc comment of the token, * if any. * - * @param {Object} token Espree token. + * @param {Object} token Espree token to extract the leading JSDoc comment from. + * @param {Object} [typeAnnotationToken] Espree token to use for type inference. Defaults to `token`. + * Pass the function implementation node when the JSDoc lives on + * an overload signature so that inferred types reflect the + * implementation's parameter/return types. * @return {Object} Object representing the JSDoc comment. */ -module.exports = ( token ) => { +module.exports = ( token, typeAnnotationToken = token ) => { let jsdoc; const comments = getLeadingComments( token ); if ( comments && /^\*\r?\n/.test( comments ) ) { @@ -44,7 +48,7 @@ module.exports = ( token ) => { return { ...tag, - type: getTypeAnnotation( tag, token, index ), + type: getTypeAnnotation( tag, typeAnnotationToken, index ), description: tag.description === '\n' ? tag.description.trim() @@ -55,7 +59,7 @@ module.exports = ( token ) => { if ( jsdoc.tags.length === 0 ) { const potentialTypeAnnotation = getTypeAnnotation( { tag: 'type' }, - token, + typeAnnotationToken, 0 ); if ( potentialTypeAnnotation ) { diff --git a/packages/docgen/test/get-intermediate-representation.js b/packages/docgen/test/get-intermediate-representation.js index e61f3101ad8438..109bc7ecf01815 100644 --- a/packages/docgen/test/get-intermediate-representation.js +++ b/packages/docgen/test/get-intermediate-representation.js @@ -662,6 +662,64 @@ describe( 'Intermediate Representation', () => { } ); } ); + describe( 'TypeScript function overloads', () => { + it( 'extracts description from first overload signature and infers types from the implementation', () => + expect( + parse( ` + /** + * Registers a new block. + * @param blockNameOrMetadata Block type name or its metadata. + * @param settings Block settings. + * @return The block, if registered; otherwise undefined. + */ + export function registerBlockType( blockNameOrMetadata: object, settings?: object ): object | undefined; + export function registerBlockType( blockNameOrMetadata: string, settings: object ): object | undefined; + export function registerBlockType( blockNameOrMetadata: string | object, settings?: object ): object | undefined { + return undefined; + } + ` ) + ).toEqual( [ + expect.objectContaining( { + description: 'Registers a new block.', + name: 'registerBlockType', + tags: expect.arrayContaining( [ + expect.objectContaining( { + tag: 'param', + name: 'blockNameOrMetadata', + type: 'string | object', + } ), + expect.objectContaining( { + tag: 'return', + type: 'object | undefined', + } ), + ] ), + } ), + ] ) ); + + it( 'extracts JSDoc from non-exported overload signatures exported via export { }', () => + expect( + parse( ` + /** + * My overloaded function. + * @param a The argument. + * @return The result. + */ + function myDeclaration( a: string ): string; + function myDeclaration( a: number ): number; + function myDeclaration( a: string | number ): string | number { + return a; + } + + export { myDeclaration }; + ` ) + ).toEqual( [ + expect.objectContaining( { + description: 'My overloaded function.', + name: 'myDeclaration', + } ), + ] ) ); + } ); + describe( 'JSDoc in module dependency through import', () => { describe( 'default export', () => { it( 'default import', () =>