From f31de7c0cb8e96d0cb4a7a4ee4dfffb316d4bc92 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 07:46:13 +0900 Subject: [PATCH 01/20] Add components readme generator --- docs/tool/components/index.js | 80 ++++++++++++++++++++++++++ docs/tool/components/markdown/index.js | 40 +++++++++++++ docs/tool/components/markdown/props.js | 53 +++++++++++++++++ docs/tool/index.js | 3 + package-lock.json | 20 +++++++ package.json | 2 + 6 files changed, 198 insertions(+) create mode 100644 docs/tool/components/index.js create mode 100644 docs/tool/components/markdown/index.js create mode 100644 docs/tool/components/markdown/props.js diff --git a/docs/tool/components/index.js b/docs/tool/components/index.js new file mode 100644 index 0000000000000..624c185cc1025 --- /dev/null +++ b/docs/tool/components/index.js @@ -0,0 +1,80 @@ +/** + * External dependencies + */ +const docgen = require( 'react-docgen-typescript' ); +const glob = require( 'glob' ); +const fs = require( 'fs' ); +const path = require( 'path' ); + +/** + * Internal dependencies + */ +const { generateMarkdownDocs } = require( './markdown' ); + +// For consistency, options should generally match the options used in Storybook. +const OPTIONS = { + shouldExtractLiteralValuesFromEnum: true, + shouldRemoveUndefinedFromOptional: true, + propFilter: ( prop ) => + prop.parent ? ! /node_modules/.test( prop.parent.fileName ) : true, + savePropValueAsString: true, +}; + +function getTypeDocsForComponent( { + manifestPath, + componentFilePath, + displayName, +} ) { + const resolvedPath = path.resolve( + path.dirname( manifestPath ), + componentFilePath + ); + + return docgen + .parse( resolvedPath, OPTIONS ) + .find( ( obj ) => obj.displayName === displayName ); +} + +function generateComponentDocs() { + const manifests = glob.sync( + 'packages/components/src/**/docs-manifest.json' + ); + + manifests.forEach( ( manifestPath ) => { + const manifest = JSON.parse( fs.readFileSync( manifestPath, 'utf8' ) ); + + const typeDocs = getTypeDocsForComponent( { + manifestPath, + componentFilePath: manifest.filePath, + displayName: manifest.displayName, + } ); + + const subcomponentTypeDocs = manifest.subcomponents.map( + ( subcomponent ) => { + const docs = getTypeDocsForComponent( { + manifestPath, + componentFilePath: subcomponent.filePath, + displayName: subcomponent.displayName, + } ); + + if ( subcomponent.preferredDisplayName ) { + docs.displayName = subcomponent.preferredDisplayName; + } + + return docs; + } + ); + + const docs = generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ); + const outputFile = path.resolve( + path.dirname( manifestPath ), + './README.md' + ); + + fs.writeFileSync( outputFile, docs ); + } ); +} + +module.exports = { + generateComponentDocs, +}; diff --git a/docs/tool/components/markdown/index.js b/docs/tool/components/markdown/index.js new file mode 100644 index 0000000000000..705ac54bf5f60 --- /dev/null +++ b/docs/tool/components/markdown/index.js @@ -0,0 +1,40 @@ +/** + * External dependencies + */ +const json2md = require( 'json2md' ); + +/** + * Internal dependencies + */ +const { generateMarkdownPropsJson } = require( './props' ); + +function generateStorybookCallout( componentId ) { + return `

See the WordPress Storybook for more detailed, interactive documentation.

`; +} + +function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) { + const docsJson = [ + '\n', + { h1: typeDocs.displayName }, + { p: generateStorybookCallout( typeDocs.displayName.toLowerCase() ) }, + typeDocs.description, + ...generateMarkdownPropsJson( typeDocs.props ), + + { h2: 'Subcomponents' }, + ...subcomponentTypeDocs.flatMap( ( subcomponentTypeDoc ) => [ + { + h3: subcomponentTypeDoc.displayName, + }, + subcomponentTypeDoc.description, + ...generateMarkdownPropsJson( subcomponentTypeDoc.props, { + headingLevel: 4, + } ), + ] ), + ].filter( Boolean ); + + return json2md( docsJson ); +} + +module.exports = { + generateMarkdownDocs, +}; diff --git a/docs/tool/components/markdown/props.js b/docs/tool/components/markdown/props.js new file mode 100644 index 0000000000000..e9e47d5c3ef32 --- /dev/null +++ b/docs/tool/components/markdown/props.js @@ -0,0 +1,53 @@ +function renderPropType( type ) { + switch ( type.name ) { + case 'enum': { + const MAX_ENUM_VALUES = 10; + const string = type.value + .slice( 0, MAX_ENUM_VALUES ) + .map( ( { value } ) => value ) + .join( ' | ' ); + + if ( type.value.length > MAX_ENUM_VALUES ) { + return `${ string } | ...`; + } + return string; + } + default: + return type.name; + } +} + +function generateMarkdownPropsJson( props, { headingLevel = 2 } = {} ) { + const sortedKeys = Object.keys( props ).sort( ( [ a ], [ b ] ) => + a.localeCompare( b ) + ); + + const propsJson = sortedKeys + .flatMap( ( key ) => { + const prop = props[ key ]; + + if ( prop.description.includes( '@ignore' ) ) { + return null; + } + + return [ + { [ `h${ headingLevel + 1 }` ]: `\`${ key }\`` }, + prop.description, + { + ul: [ + `Type: \`${ renderPropType( prop.type ) }\``, + `Required: ${ prop.required ? 'Yes' : 'No' }`, + prop.defaultValue && + `Default: \`${ prop.defaultValue.value }\``, + ].filter( Boolean ), + }, + ]; + } ) + .filter( Boolean ); + + return [ { [ `h${ headingLevel }` ]: 'Props' }, ...propsJson ]; +} + +module.exports = { + generateMarkdownPropsJson, +}; diff --git a/docs/tool/index.js b/docs/tool/index.js index 7f28c110d4141..5b8fd62b9bfae 100644 --- a/docs/tool/index.js +++ b/docs/tool/index.js @@ -8,10 +8,13 @@ const path = require( 'path' ); * Internal dependencies */ const { getRootManifest } = require( './manifest' ); +const { generateComponentDocs } = require( './components' ); const tocFileInput = path.resolve( __dirname, '../toc.json' ); const manifestOutput = path.resolve( __dirname, '../manifest.json' ); +generateComponentDocs(); + // Process TOC file and generate manifest handbook. fs.writeFileSync( manifestOutput, diff --git a/package-lock.json b/package-lock.json index c240bfd178437..465dd3f6877f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -204,6 +204,7 @@ "jest-junit": "13.0.0", "jest-message-util": "29.6.2", "jest-watch-typeahead": "2.2.2", + "json2md": "2.0.1", "lerna": "7.1.4", "lint-staged": "10.0.2", "make-dir": "3.0.0", @@ -223,6 +224,7 @@ "progress": "2.0.3", "puppeteer-core": "23.1.0", "react": "18.3.1", + "react-docgen-typescript": "2.2.2", "react-dom": "18.3.1", "react-native": "0.73.3", "react-native-url-polyfill": "1.1.2", @@ -29748,6 +29750,13 @@ "node": ">=4" } }, + "node_modules/indento": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/indento/-/indento-1.1.13.tgz", + "integrity": "sha512-YZWk3mreBEM7sBPddsiQnW9Z8SGg/gNpFfscJq00HCDS7pxcQWWWMSVKJU7YkTRyDu1Zv2s8zaK8gQWKmCXHlg==", + "dev": true, + "license": "MIT" + }, "node_modules/infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", @@ -32471,6 +32480,16 @@ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, + "node_modules/json2md": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/json2md/-/json2md-2.0.1.tgz", + "integrity": "sha512-VbwmZ83qmUfKBS2pUOHlzNKEZFPBeJSbzEok3trMYyboZUgdHNn1XZfc1uT8UZs1GHCrmRUBXCfqw4YmmQuOhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "indento": "^1.1.13" + } + }, "node_modules/json2php": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/json2php/-/json2php-0.0.7.tgz", @@ -43165,6 +43184,7 @@ "resolved": "https://registry.npmjs.org/react-docgen-typescript/-/react-docgen-typescript-2.2.2.tgz", "integrity": "sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==", "dev": true, + "license": "MIT", "peerDependencies": { "typescript": ">= 4.3.x" } diff --git a/package.json b/package.json index 4c071bf746c15..15f3a3c8aab8e 100644 --- a/package.json +++ b/package.json @@ -216,6 +216,7 @@ "jest-junit": "13.0.0", "jest-message-util": "29.6.2", "jest-watch-typeahead": "2.2.2", + "json2md": "2.0.1", "lerna": "7.1.4", "lint-staged": "10.0.2", "make-dir": "3.0.0", @@ -235,6 +236,7 @@ "progress": "2.0.3", "puppeteer-core": "23.1.0", "react": "18.3.1", + "react-docgen-typescript": "2.2.2", "react-dom": "18.3.1", "react-native": "0.73.3", "react-native-url-polyfill": "1.1.2", From 82cafc723f7a52153bca3528e89c33f57c466620 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 07:56:50 +0900 Subject: [PATCH 02/20] Move --- bin/api-docs/gen-components-docs/index.js | 72 +++++++++++++++++ .../gen-components-docs}/markdown/index.js | 0 .../gen-components-docs}/markdown/props.js | 0 docs/tool/components/index.js | 80 ------------------- docs/tool/index.js | 3 - package.json | 3 +- 6 files changed, 74 insertions(+), 84 deletions(-) create mode 100644 bin/api-docs/gen-components-docs/index.js rename {docs/tool/components => bin/api-docs/gen-components-docs}/markdown/index.js (100%) rename {docs/tool/components => bin/api-docs/gen-components-docs}/markdown/props.js (100%) delete mode 100644 docs/tool/components/index.js diff --git a/bin/api-docs/gen-components-docs/index.js b/bin/api-docs/gen-components-docs/index.js new file mode 100644 index 0000000000000..a409da92b4699 --- /dev/null +++ b/bin/api-docs/gen-components-docs/index.js @@ -0,0 +1,72 @@ +/** + * External dependencies + */ +const docgen = require( 'react-docgen-typescript' ); +const glob = require( 'glob' ); +const fs = require( 'fs' ); +const path = require( 'path' ); + +/** + * Internal dependencies + */ +const { generateMarkdownDocs } = require( './markdown' ); + +// For consistency, options should generally match the options used in Storybook. +const OPTIONS = { + shouldExtractLiteralValuesFromEnum: true, + shouldRemoveUndefinedFromOptional: true, + propFilter: ( prop ) => + prop.parent ? ! /node_modules/.test( prop.parent.fileName ) : true, + savePropValueAsString: true, +}; + +function getTypeDocsForComponent( { + manifestPath, + componentFilePath, + displayName, +} ) { + const resolvedPath = path.resolve( + path.dirname( manifestPath ), + componentFilePath + ); + + return docgen + .parse( resolvedPath, OPTIONS ) + .find( ( obj ) => obj.displayName === displayName ); +} + +const manifests = glob.sync( 'packages/components/src/**/docs-manifest.json' ); + +manifests.forEach( ( manifestPath ) => { + const manifest = JSON.parse( fs.readFileSync( manifestPath, 'utf8' ) ); + + const typeDocs = getTypeDocsForComponent( { + manifestPath, + componentFilePath: manifest.filePath, + displayName: manifest.displayName, + } ); + + const subcomponentTypeDocs = manifest.subcomponents.map( + ( subcomponent ) => { + const docs = getTypeDocsForComponent( { + manifestPath, + componentFilePath: subcomponent.filePath, + displayName: subcomponent.displayName, + } ); + + if ( subcomponent.preferredDisplayName ) { + docs.displayName = subcomponent.preferredDisplayName; + } + + return docs; + } + ); + + const docs = generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ); + const outputFile = path.resolve( + path.dirname( manifestPath ), + './README.md' + ); + + fs.writeFileSync( outputFile, docs ); +} ); diff --git a/docs/tool/components/markdown/index.js b/bin/api-docs/gen-components-docs/markdown/index.js similarity index 100% rename from docs/tool/components/markdown/index.js rename to bin/api-docs/gen-components-docs/markdown/index.js diff --git a/docs/tool/components/markdown/props.js b/bin/api-docs/gen-components-docs/markdown/props.js similarity index 100% rename from docs/tool/components/markdown/props.js rename to bin/api-docs/gen-components-docs/markdown/props.js diff --git a/docs/tool/components/index.js b/docs/tool/components/index.js deleted file mode 100644 index 624c185cc1025..0000000000000 --- a/docs/tool/components/index.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * External dependencies - */ -const docgen = require( 'react-docgen-typescript' ); -const glob = require( 'glob' ); -const fs = require( 'fs' ); -const path = require( 'path' ); - -/** - * Internal dependencies - */ -const { generateMarkdownDocs } = require( './markdown' ); - -// For consistency, options should generally match the options used in Storybook. -const OPTIONS = { - shouldExtractLiteralValuesFromEnum: true, - shouldRemoveUndefinedFromOptional: true, - propFilter: ( prop ) => - prop.parent ? ! /node_modules/.test( prop.parent.fileName ) : true, - savePropValueAsString: true, -}; - -function getTypeDocsForComponent( { - manifestPath, - componentFilePath, - displayName, -} ) { - const resolvedPath = path.resolve( - path.dirname( manifestPath ), - componentFilePath - ); - - return docgen - .parse( resolvedPath, OPTIONS ) - .find( ( obj ) => obj.displayName === displayName ); -} - -function generateComponentDocs() { - const manifests = glob.sync( - 'packages/components/src/**/docs-manifest.json' - ); - - manifests.forEach( ( manifestPath ) => { - const manifest = JSON.parse( fs.readFileSync( manifestPath, 'utf8' ) ); - - const typeDocs = getTypeDocsForComponent( { - manifestPath, - componentFilePath: manifest.filePath, - displayName: manifest.displayName, - } ); - - const subcomponentTypeDocs = manifest.subcomponents.map( - ( subcomponent ) => { - const docs = getTypeDocsForComponent( { - manifestPath, - componentFilePath: subcomponent.filePath, - displayName: subcomponent.displayName, - } ); - - if ( subcomponent.preferredDisplayName ) { - docs.displayName = subcomponent.preferredDisplayName; - } - - return docs; - } - ); - - const docs = generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ); - const outputFile = path.resolve( - path.dirname( manifestPath ), - './README.md' - ); - - fs.writeFileSync( outputFile, docs ); - } ); -} - -module.exports = { - generateComponentDocs, -}; diff --git a/docs/tool/index.js b/docs/tool/index.js index 5b8fd62b9bfae..7f28c110d4141 100644 --- a/docs/tool/index.js +++ b/docs/tool/index.js @@ -8,13 +8,10 @@ const path = require( 'path' ); * Internal dependencies */ const { getRootManifest } = require( './manifest' ); -const { generateComponentDocs } = require( './components' ); const tocFileInput = path.resolve( __dirname, '../toc.json' ); const manifestOutput = path.resolve( __dirname, '../manifest.json' ); -generateComponentDocs(); - // Process TOC file and generate manifest handbook. fs.writeFileSync( manifestOutput, diff --git a/package.json b/package.json index 15f3a3c8aab8e..a609eb406bc48 100644 --- a/package.json +++ b/package.json @@ -284,7 +284,8 @@ "distclean": "git clean --force -d -X", "docs:api-ref": "node ./bin/api-docs/update-api-docs.js", "docs:blocks": "node ./bin/api-docs/gen-block-lib-list.js", - "docs:build": "npm-run-all docs:gen docs:blocks docs:api-ref docs:theme-ref", + "docs:build": "npm-run-all docs:components docs:gen docs:blocks docs:api-ref docs:theme-ref", + "docs:components": "node ./bin/api-docs/gen-components-docs", "docs:gen": "node ./docs/tool/index.js", "docs:theme-ref": "node ./bin/api-docs/gen-theme-reference.mjs", "env": "wp-env", From 04f28a748f3bd7de5a487fdfb47059657cf3fadc Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 07:57:37 +0900 Subject: [PATCH 03/20] AlignmentMatrixControl: Add missing `@deprecated` tag --- packages/components/src/alignment-matrix-control/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/components/src/alignment-matrix-control/types.ts b/packages/components/src/alignment-matrix-control/types.ts index 0f97c2df3b02b..e93f412c1f472 100644 --- a/packages/components/src/alignment-matrix-control/types.ts +++ b/packages/components/src/alignment-matrix-control/types.ts @@ -54,6 +54,8 @@ export type AlignmentMatrixControlIconProps = Pick< * component instead_ * * The size of the icon. + * + * @deprecated * @ignore * @default 24 */ From bbdf0fbfd61cd96aad083ecf3a7a2f59e7490edb Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 07:58:32 +0900 Subject: [PATCH 04/20] Add docs manifest for AlignmentMatrixControl --- .../src/alignment-matrix-control/docs-manifest.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/components/src/alignment-matrix-control/docs-manifest.json diff --git a/packages/components/src/alignment-matrix-control/docs-manifest.json b/packages/components/src/alignment-matrix-control/docs-manifest.json new file mode 100644 index 0000000000000..97fdd5dc9339f --- /dev/null +++ b/packages/components/src/alignment-matrix-control/docs-manifest.json @@ -0,0 +1,11 @@ +{ + "displayName": "AlignmentMatrixControl", + "filePath": "./index.tsx", + "subcomponents": [ + { + "displayName": "AlignmentMatrixControlIcon", + "preferredDisplayName": "AlignmentMatrixControl.Icon", + "filePath": "./icon.tsx" + } + ] +} From a0d09d0ecca542103733d0ed24edc23b8ab40ffa Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 08:09:58 +0900 Subject: [PATCH 05/20] Handle case with no subcomponents --- .../gen-components-docs/markdown/index.js | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/bin/api-docs/gen-components-docs/markdown/index.js b/bin/api-docs/gen-components-docs/markdown/index.js index 705ac54bf5f60..76589fdcf0d2d 100644 --- a/bin/api-docs/gen-components-docs/markdown/index.js +++ b/bin/api-docs/gen-components-docs/markdown/index.js @@ -13,26 +13,32 @@ function generateStorybookCallout( componentId ) { } function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) { - const docsJson = [ + const mainDocsJson = [ '\n', { h1: typeDocs.displayName }, { p: generateStorybookCallout( typeDocs.displayName.toLowerCase() ) }, typeDocs.description, ...generateMarkdownPropsJson( typeDocs.props ), + ]; - { h2: 'Subcomponents' }, - ...subcomponentTypeDocs.flatMap( ( subcomponentTypeDoc ) => [ - { - h3: subcomponentTypeDoc.displayName, - }, - subcomponentTypeDoc.description, - ...generateMarkdownPropsJson( subcomponentTypeDoc.props, { - headingLevel: 4, - } ), - ] ), - ].filter( Boolean ); + const subcomponentDocsJson = subcomponentTypeDocs + ? [ + { h2: 'Subcomponents' }, + ...subcomponentTypeDocs.flatMap( ( subcomponentTypeDoc ) => [ + { + h3: subcomponentTypeDoc.displayName, + }, + subcomponentTypeDoc.description, + ...generateMarkdownPropsJson( subcomponentTypeDoc.props, { + headingLevel: 4, + } ), + ] ), + ] + : []; - return json2md( docsJson ); + return json2md( + [ ...mainDocsJson, ...subcomponentDocsJson ].filter( Boolean ) + ); } module.exports = { From 5a524a358cab70c5d75734cf9a2de9cab9639d58 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 08:23:33 +0900 Subject: [PATCH 06/20] Add JSON schema --- .../components/schemas/docs-manifest.json | 38 +++++++++++++++++++ .../docs-manifest.json | 1 + 2 files changed, 39 insertions(+) create mode 100644 packages/components/schemas/docs-manifest.json diff --git a/packages/components/schemas/docs-manifest.json b/packages/components/schemas/docs-manifest.json new file mode 100644 index 0000000000000..9187b43bf40ad --- /dev/null +++ b/packages/components/schemas/docs-manifest.json @@ -0,0 +1,38 @@ +{ + "title": "JSON schema for @wordpress/components README manifests", + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "The `displayName` of the component, as determined in code." + }, + "filePath": { + "type": "string", + "description": "The file path where the component is located." + }, + "subcomponents": { + "type": "array", + "description": "List of subcomponents related to the component.", + "items": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "The `displayName` of the subcomponent, as determined in code." + }, + "preferredDisplayName": { + "type": "string", + "description": "The display name to use in the README, if it is different from the `displayName` as determined in code." + }, + "filePath": { + "type": "string", + "description": "The file path where the subcomponent is located." + } + }, + "required": [ "displayName", "filePath" ] + } + } + }, + "required": [ "displayName", "filePath" ] +} diff --git a/packages/components/src/alignment-matrix-control/docs-manifest.json b/packages/components/src/alignment-matrix-control/docs-manifest.json index 97fdd5dc9339f..82ee28f4840c4 100644 --- a/packages/components/src/alignment-matrix-control/docs-manifest.json +++ b/packages/components/src/alignment-matrix-control/docs-manifest.json @@ -1,4 +1,5 @@ { + "$schema": "../../schemas/docs-manifest.json", "displayName": "AlignmentMatrixControl", "filePath": "./index.tsx", "subcomponents": [ From b3630023852277ab3e648283bb4cb53a45b2b275 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 08:24:20 +0900 Subject: [PATCH 07/20] Commit AlignmentMatrixControl readme changes --- .../src/alignment-matrix-control/README.md | 82 +++++++++++-------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/packages/components/src/alignment-matrix-control/README.md b/packages/components/src/alignment-matrix-control/README.md index 68ecab6b7adb4..8e6ef324ce8e6 100644 --- a/packages/components/src/alignment-matrix-control/README.md +++ b/packages/components/src/alignment-matrix-control/README.md @@ -1,12 +1,15 @@ + + # AlignmentMatrixControl -AlignmentMatrixControl components enable adjustments to horizontal and vertical alignments for UI. -## Usage +

See the WordPress Storybook for more detailed, interactive documentation.

+ +AlignmentMatrixControl components enable adjustments to horizontal and vertical alignments for UI. ```jsx -import { useState } from 'react'; import { AlignmentMatrixControl } from '@wordpress/components'; +import { useState } from '@wordpress/element'; const Example = () => { const [ alignment, setAlignment ] = useState( 'center center' ); @@ -14,63 +17,70 @@ const Example = () => { return ( setAlignment( newAlignment ) } + onChange={ setAlignment } /> ); }; ``` - ## Props -The component accepts the following props: +### `defaultValue` -### className +If provided, sets the default alignment value. -The class that will be added to the classes of the underlying `grid` widget. -- Type: `string` -- Required: No + - Type: `"center" | "top left" | "top center" | "top right" | "center left" | "center center" | "center right" | "bottom left" | "bottom center" | "bottom right"` + - Required: No + - Default: `'center center'` -### id +### `label` -Unique ID for the component. +Accessible label. If provided, sets the `aria-label` attribute of the +underlying `grid` widget. -- Type: `string` -- Required: No + - Type: `string` + - Required: No + - Default: `'Alignment Matrix Control'` -### label +### `onChange` -Accessible label. If provided, sets the `aria-label` attribute of the underlying `grid` widget. +A function that receives the updated alignment value. -- Type: `string` -- Required: No -- Default: `Alignment Matrix Control` + - Type: `(newValue: AlignmentMatrixControlValue) => void` + - Required: No -### defaultValue +### `value` -If provided, sets the default alignment value. +The current alignment value. -- Type: `AlignmentMatrixControlValue` -- Required: No -- Default: `center center` + - Type: `"center" | "top left" | "top center" | "top right" | "center left" | "center center" | "center right" | "bottom left" | "bottom center" | "bottom right"` + - Required: No -### value +### `width` -The current alignment value. +If provided, sets the width of the control. -- Type: `AlignmentMatrixControlValue` -- Required: No + - Type: `number` + - Required: No + - Default: `92` -### onChange +## Subcomponents -A function that receives the updated alignment value. +### AlignmentMatrixControl.Icon -- Type: `( newValue: AlignmentMatrixControlValue ) => void` -- Required: No +#### Props -### width +##### `disablePointerEvents` -If provided, sets the width of the control. +If `true`, disables pointer events on the icon. - - Type: `number` + - Type: `boolean` - Required: No - - Default: `92` + - Default: `true` + +##### `value` + +The current alignment value. + + - Type: `"center" | "top left" | "top center" | "top right" | "center left" | "center center" | "center right" | "bottom left" | "bottom center" | "bottom right"` + - Required: No + - Default: `center` From 5d69c1b915e0760105b37ee688d1f58dfcfac5ab Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 08:26:29 +0900 Subject: [PATCH 08/20] Fixup: Handle case with no subcomponents --- bin/api-docs/gen-components-docs/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/api-docs/gen-components-docs/index.js b/bin/api-docs/gen-components-docs/index.js index a409da92b4699..1a5a807c968cc 100644 --- a/bin/api-docs/gen-components-docs/index.js +++ b/bin/api-docs/gen-components-docs/index.js @@ -46,7 +46,7 @@ manifests.forEach( ( manifestPath ) => { displayName: manifest.displayName, } ); - const subcomponentTypeDocs = manifest.subcomponents.map( + const subcomponentTypeDocs = manifest.subcomponents?.map( ( subcomponent ) => { const docs = getTypeDocsForComponent( { manifestPath, From 680a420b705785c97838e58ae64d6c44e72a900d Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 08:31:42 +0900 Subject: [PATCH 09/20] Add manifest for AnglePickerControl --- .../src/angle-picker-control/README.md | 59 +++++++++++-------- .../angle-picker-control/docs-manifest.json | 5 ++ 2 files changed, 41 insertions(+), 23 deletions(-) create mode 100644 packages/components/src/angle-picker-control/docs-manifest.json diff --git a/packages/components/src/angle-picker-control/README.md b/packages/components/src/angle-picker-control/README.md index deed41089fdc1..f5f2627409e13 100644 --- a/packages/components/src/angle-picker-control/README.md +++ b/packages/components/src/angle-picker-control/README.md @@ -1,44 +1,57 @@ + + # AnglePickerControl -`AnglePickerControl` is a React component to render a UI that allows users to pick an angle. -Users can choose an angle in a visual UI with the mouse by dragging an angle indicator inside a circle or by directly inserting the desired angle in a text field. -## Usage +

See the WordPress Storybook for more detailed, interactive documentation.

+ +`AnglePickerControl` is a React component to render a UI that allows users to +pick an angle. Users can choose an angle in a visual UI with the mouse by +dragging an angle indicator inside a circle or by directly inserting the +desired angle in a text field. ```jsx -import { useState } from 'react'; +import { useState } from '@wordpress/element'; import { AnglePickerControl } from '@wordpress/components'; function Example() { - const [ angle, setAngle ] = useState( 0 ); - return ( - - ); -}; + const [ angle, setAngle ] = useState( 0 ); + return ( + + ); +} ``` - ## Props -The component accepts the following props. +### `as` + +The HTML element or React component to render the component as. -### `label`: `string` + - Type: `"symbol" | "object" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | ...` + - Required: No + +### `label` Label to use for the angle picker. -- Required: No -- Default: `__( 'Angle' )` + - Type: `string` + - Required: No + - Default: `__( 'Angle' )` -### `value`: `number | string` +### `onChange` -The current value of the input. The value represents an angle in degrees and should be a value between 0 and 360. +A function that receives the new value of the input. -- Required: Yes + - Type: `(value: number) => void` + - Required: Yes -### `onChange`: `( value: number ) => void` +### `value` -A function that receives the new value of the input. +The current value of the input. The value represents an angle in degrees +and should be a value between 0 and 360. -- Required: Yes + - Type: `string | number` + - Required: Yes diff --git a/packages/components/src/angle-picker-control/docs-manifest.json b/packages/components/src/angle-picker-control/docs-manifest.json new file mode 100644 index 0000000000000..bcbfb353ac9e3 --- /dev/null +++ b/packages/components/src/angle-picker-control/docs-manifest.json @@ -0,0 +1,5 @@ +{ + "$schema": "../../schemas/docs-manifest.json", + "displayName": "AnglePickerControl", + "filePath": "./index.tsx" +} From 1d01ecf54e8d287979a1c812d018b241f35e26ca Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 09:03:06 +0900 Subject: [PATCH 10/20] Simplify --- bin/api-docs/gen-components-docs/markdown/index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/bin/api-docs/gen-components-docs/markdown/index.js b/bin/api-docs/gen-components-docs/markdown/index.js index 76589fdcf0d2d..bad11e22a14fe 100644 --- a/bin/api-docs/gen-components-docs/markdown/index.js +++ b/bin/api-docs/gen-components-docs/markdown/index.js @@ -8,15 +8,13 @@ const json2md = require( 'json2md' ); */ const { generateMarkdownPropsJson } = require( './props' ); -function generateStorybookCallout( componentId ) { - return `

See the WordPress Storybook for more detailed, interactive documentation.

`; -} - function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) { const mainDocsJson = [ '\n', { h1: typeDocs.displayName }, - { p: generateStorybookCallout( typeDocs.displayName.toLowerCase() ) }, + { + p: `

See the WordPress Storybook for more detailed, interactive documentation.

`, + }, typeDocs.description, ...generateMarkdownPropsJson( typeDocs.props ), ]; From 9bf7678c795cf5422b050fbd4202192bd13078bc Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Fri, 11 Oct 2024 09:14:42 +0900 Subject: [PATCH 11/20] Improve schema descriptions --- packages/components/schemas/docs-manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/schemas/docs-manifest.json b/packages/components/schemas/docs-manifest.json index 9187b43bf40ad..7d1e40f4f696d 100644 --- a/packages/components/schemas/docs-manifest.json +++ b/packages/components/schemas/docs-manifest.json @@ -5,7 +5,7 @@ "properties": { "displayName": { "type": "string", - "description": "The `displayName` of the component, as determined in code." + "description": "The `displayName` of the component, as determined in code. Used to identify the component in the specified source file." }, "filePath": { "type": "string", @@ -19,7 +19,7 @@ "properties": { "displayName": { "type": "string", - "description": "The `displayName` of the subcomponent, as determined in code." + "description": "The `displayName` of the subcomponent, as determined in code. Used to identify the component in the specified source file." }, "preferredDisplayName": { "type": "string", From 8fe2ca8122ea731434877fa72f24472c7c89b7bb Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Tue, 15 Oct 2024 08:30:16 +0900 Subject: [PATCH 12/20] Handle docgen errors --- bin/api-docs/gen-components-docs/index.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/bin/api-docs/gen-components-docs/index.js b/bin/api-docs/gen-components-docs/index.js index 1a5a807c968cc..ae07020867bc0 100644 --- a/bin/api-docs/gen-components-docs/index.js +++ b/bin/api-docs/gen-components-docs/index.js @@ -30,9 +30,17 @@ function getTypeDocsForComponent( { componentFilePath ); - return docgen + const typeDocs = docgen .parse( resolvedPath, OPTIONS ) .find( ( obj ) => obj.displayName === displayName ); + + if ( typeof typeDocs === 'undefined' ) { + throw new Error( + `react-docgen-typescript could not generate type docs for ${ displayName } in ${ resolvedPath }` + ); + } + + return typeDocs; } const manifests = glob.sync( 'packages/components/src/**/docs-manifest.json' ); From 7c66c588aefb01818a69837e243ca40cd2de64c6 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Tue, 15 Oct 2024 23:20:59 +0900 Subject: [PATCH 13/20] Convert to async --- bin/api-docs/gen-components-docs/index.js | 80 ----------------- bin/api-docs/gen-components-docs/index.mjs | 87 +++++++++++++++++++ .../markdown/{index.js => index.mjs} | 10 +-- .../markdown/{props.js => props.mjs} | 5 +- package.json | 2 +- 5 files changed, 92 insertions(+), 92 deletions(-) delete mode 100644 bin/api-docs/gen-components-docs/index.js create mode 100644 bin/api-docs/gen-components-docs/index.mjs rename bin/api-docs/gen-components-docs/markdown/{index.js => index.mjs} (82%) rename bin/api-docs/gen-components-docs/markdown/{props.js => props.mjs} (89%) diff --git a/bin/api-docs/gen-components-docs/index.js b/bin/api-docs/gen-components-docs/index.js deleted file mode 100644 index ae07020867bc0..0000000000000 --- a/bin/api-docs/gen-components-docs/index.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * External dependencies - */ -const docgen = require( 'react-docgen-typescript' ); -const glob = require( 'glob' ); -const fs = require( 'fs' ); -const path = require( 'path' ); - -/** - * Internal dependencies - */ -const { generateMarkdownDocs } = require( './markdown' ); - -// For consistency, options should generally match the options used in Storybook. -const OPTIONS = { - shouldExtractLiteralValuesFromEnum: true, - shouldRemoveUndefinedFromOptional: true, - propFilter: ( prop ) => - prop.parent ? ! /node_modules/.test( prop.parent.fileName ) : true, - savePropValueAsString: true, -}; - -function getTypeDocsForComponent( { - manifestPath, - componentFilePath, - displayName, -} ) { - const resolvedPath = path.resolve( - path.dirname( manifestPath ), - componentFilePath - ); - - const typeDocs = docgen - .parse( resolvedPath, OPTIONS ) - .find( ( obj ) => obj.displayName === displayName ); - - if ( typeof typeDocs === 'undefined' ) { - throw new Error( - `react-docgen-typescript could not generate type docs for ${ displayName } in ${ resolvedPath }` - ); - } - - return typeDocs; -} - -const manifests = glob.sync( 'packages/components/src/**/docs-manifest.json' ); - -manifests.forEach( ( manifestPath ) => { - const manifest = JSON.parse( fs.readFileSync( manifestPath, 'utf8' ) ); - - const typeDocs = getTypeDocsForComponent( { - manifestPath, - componentFilePath: manifest.filePath, - displayName: manifest.displayName, - } ); - - const subcomponentTypeDocs = manifest.subcomponents?.map( - ( subcomponent ) => { - const docs = getTypeDocsForComponent( { - manifestPath, - componentFilePath: subcomponent.filePath, - displayName: subcomponent.displayName, - } ); - - if ( subcomponent.preferredDisplayName ) { - docs.displayName = subcomponent.preferredDisplayName; - } - - return docs; - } - ); - - const docs = generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ); - const outputFile = path.resolve( - path.dirname( manifestPath ), - './README.md' - ); - - fs.writeFileSync( outputFile, docs ); -} ); diff --git a/bin/api-docs/gen-components-docs/index.mjs b/bin/api-docs/gen-components-docs/index.mjs new file mode 100644 index 0000000000000..365c61ec7143f --- /dev/null +++ b/bin/api-docs/gen-components-docs/index.mjs @@ -0,0 +1,87 @@ +/** + * External dependencies + */ +import docgen from 'react-docgen-typescript'; +import glob from 'glob'; +import fs from 'node:fs/promises'; +import path from 'path'; + +/** + * Internal dependencies + */ +import { generateMarkdownDocs } from './markdown/index.mjs'; + +// For consistency, options should generally match the options used in Storybook. +const OPTIONS = { + shouldExtractLiteralValuesFromEnum: true, + shouldRemoveUndefinedFromOptional: true, + propFilter: ( prop ) => + prop.parent ? ! /node_modules/.test( prop.parent.fileName ) : true, + savePropValueAsString: true, +}; + +function getTypeDocsForComponent( { + manifestPath, + componentFilePath, + displayName, +} ) { + const resolvedPath = path.resolve( + path.dirname( manifestPath ), + componentFilePath + ); + + const typeDocs = docgen + .parse( resolvedPath, OPTIONS ) + .find( ( obj ) => obj.displayName === displayName ); + + if ( typeof typeDocs === 'undefined' ) { + throw new Error( + `react-docgen-typescript could not generate type docs for ${ displayName } in ${ resolvedPath }` + ); + } + + return typeDocs; +} + +const manifests = glob.sync( 'packages/components/src/**/docs-manifest.json' ); + +await Promise.all( + manifests.map( async ( manifestPath ) => { + const manifest = JSON.parse( + await fs.readFile( manifestPath, 'utf8' ) + ); + + const typeDocs = getTypeDocsForComponent( { + manifestPath, + componentFilePath: manifest.filePath, + displayName: manifest.displayName, + } ); + + const subcomponentTypeDocs = ! manifest.subcomponents + ? undefined + : await Promise.all( + manifest.subcomponents.map( async ( subcomponent ) => { + const docs = getTypeDocsForComponent( { + manifestPath, + componentFilePath: subcomponent.filePath, + displayName: subcomponent.displayName, + } ); + + if ( subcomponent.preferredDisplayName ) { + docs.displayName = + subcomponent.preferredDisplayName; + } + + return docs; + } ) + ); + + const docs = generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ); + const outputFile = path.resolve( + path.dirname( manifestPath ), + './README.md' + ); + + return fs.writeFile( outputFile, docs ); + } ) +); diff --git a/bin/api-docs/gen-components-docs/markdown/index.js b/bin/api-docs/gen-components-docs/markdown/index.mjs similarity index 82% rename from bin/api-docs/gen-components-docs/markdown/index.js rename to bin/api-docs/gen-components-docs/markdown/index.mjs index bad11e22a14fe..7aa42ce69edb9 100644 --- a/bin/api-docs/gen-components-docs/markdown/index.js +++ b/bin/api-docs/gen-components-docs/markdown/index.mjs @@ -1,14 +1,14 @@ /** * External dependencies */ -const json2md = require( 'json2md' ); +import json2md from 'json2md'; /** * Internal dependencies */ -const { generateMarkdownPropsJson } = require( './props' ); +import { generateMarkdownPropsJson } from './props.mjs'; -function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) { +export function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) { const mainDocsJson = [ '\n', { h1: typeDocs.displayName }, @@ -38,7 +38,3 @@ function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) { [ ...mainDocsJson, ...subcomponentDocsJson ].filter( Boolean ) ); } - -module.exports = { - generateMarkdownDocs, -}; diff --git a/bin/api-docs/gen-components-docs/markdown/props.js b/bin/api-docs/gen-components-docs/markdown/props.mjs similarity index 89% rename from bin/api-docs/gen-components-docs/markdown/props.js rename to bin/api-docs/gen-components-docs/markdown/props.mjs index e9e47d5c3ef32..0cf787239c1ea 100644 --- a/bin/api-docs/gen-components-docs/markdown/props.js +++ b/bin/api-docs/gen-components-docs/markdown/props.mjs @@ -17,7 +17,7 @@ function renderPropType( type ) { } } -function generateMarkdownPropsJson( props, { headingLevel = 2 } = {} ) { +export function generateMarkdownPropsJson( props, { headingLevel = 2 } = {} ) { const sortedKeys = Object.keys( props ).sort( ( [ a ], [ b ] ) => a.localeCompare( b ) ); @@ -48,6 +48,3 @@ function generateMarkdownPropsJson( props, { headingLevel = 2 } = {} ) { return [ { [ `h${ headingLevel }` ]: 'Props' }, ...propsJson ]; } -module.exports = { - generateMarkdownPropsJson, -}; diff --git a/package.json b/package.json index a609eb406bc48..14af2c94f6266 100644 --- a/package.json +++ b/package.json @@ -285,7 +285,7 @@ "docs:api-ref": "node ./bin/api-docs/update-api-docs.js", "docs:blocks": "node ./bin/api-docs/gen-block-lib-list.js", "docs:build": "npm-run-all docs:components docs:gen docs:blocks docs:api-ref docs:theme-ref", - "docs:components": "node ./bin/api-docs/gen-components-docs", + "docs:components": "node ./bin/api-docs/gen-components-docs/index.mjs", "docs:gen": "node ./docs/tool/index.js", "docs:theme-ref": "node ./bin/api-docs/gen-theme-reference.mjs", "env": "wp-env", From 38b6d34c8e24b4bc0aab4815341b869ec71442e9 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Tue, 15 Oct 2024 23:22:51 +0900 Subject: [PATCH 14/20] Move glob further up --- bin/api-docs/gen-components-docs/index.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/api-docs/gen-components-docs/index.mjs b/bin/api-docs/gen-components-docs/index.mjs index 365c61ec7143f..b64b472b3822a 100644 --- a/bin/api-docs/gen-components-docs/index.mjs +++ b/bin/api-docs/gen-components-docs/index.mjs @@ -11,6 +11,8 @@ import path from 'path'; */ import { generateMarkdownDocs } from './markdown/index.mjs'; +const MANIFEST_GLOB = 'packages/components/src/**/docs-manifest.json'; + // For consistency, options should generally match the options used in Storybook. const OPTIONS = { shouldExtractLiteralValuesFromEnum: true, @@ -43,7 +45,7 @@ function getTypeDocsForComponent( { return typeDocs; } -const manifests = glob.sync( 'packages/components/src/**/docs-manifest.json' ); +const manifests = glob.sync( MANIFEST_GLOB ); await Promise.all( manifests.map( async ( manifestPath ) => { From 60f9cc94af0ac4a13413a95927fd97ef30597d92 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Tue, 15 Oct 2024 23:27:50 +0900 Subject: [PATCH 15/20] Handle unparseable JSON --- bin/api-docs/gen-components-docs/index.mjs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/bin/api-docs/gen-components-docs/index.mjs b/bin/api-docs/gen-components-docs/index.mjs index b64b472b3822a..16545052bafda 100644 --- a/bin/api-docs/gen-components-docs/index.mjs +++ b/bin/api-docs/gen-components-docs/index.mjs @@ -45,13 +45,21 @@ function getTypeDocsForComponent( { return typeDocs; } +async function parseManifest( manifestPath ) { + try { + return JSON.parse( await fs.readFile( manifestPath, 'utf8' ) ); + } catch ( e ) { + throw new Error( + `Error parsing docs manifest at ${ manifestPath }: ${ e.message }` + ); + } +} + const manifests = glob.sync( MANIFEST_GLOB ); await Promise.all( manifests.map( async ( manifestPath ) => { - const manifest = JSON.parse( - await fs.readFile( manifestPath, 'utf8' ) - ); + const manifest = await parseManifest( manifestPath ); const typeDocs = getTypeDocsForComponent( { manifestPath, From eb4cb40ecf69158229c503888c373cc0de30520e Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Tue, 15 Oct 2024 23:31:59 +0900 Subject: [PATCH 16/20] Handle write file progress --- bin/api-docs/gen-components-docs/index.mjs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bin/api-docs/gen-components-docs/index.mjs b/bin/api-docs/gen-components-docs/index.mjs index 16545052bafda..639470ac0ae92 100644 --- a/bin/api-docs/gen-components-docs/index.mjs +++ b/bin/api-docs/gen-components-docs/index.mjs @@ -92,6 +92,13 @@ await Promise.all( './README.md' ); - return fs.writeFile( outputFile, docs ); + try { + console.log( `Writing docs to ${ outputFile }` ); + return fs.writeFile( outputFile, docs ); + } catch ( e ) { + throw new Error( + `Error writing docs to ${ outputFile }: ${ e.message }` + ); + } } ) ); From d2a2487c7b41763c436f0f2a4270f4f907a6f311 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 16 Oct 2024 03:15:38 +0900 Subject: [PATCH 17/20] Fixup --- bin/api-docs/gen-components-docs/index.mjs | 30 ++++++++++------------ 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/bin/api-docs/gen-components-docs/index.mjs b/bin/api-docs/gen-components-docs/index.mjs index 639470ac0ae92..0c4e02a209dc9 100644 --- a/bin/api-docs/gen-components-docs/index.mjs +++ b/bin/api-docs/gen-components-docs/index.mjs @@ -69,23 +69,19 @@ await Promise.all( const subcomponentTypeDocs = ! manifest.subcomponents ? undefined - : await Promise.all( - manifest.subcomponents.map( async ( subcomponent ) => { - const docs = getTypeDocsForComponent( { - manifestPath, - componentFilePath: subcomponent.filePath, - displayName: subcomponent.displayName, - } ); - - if ( subcomponent.preferredDisplayName ) { - docs.displayName = - subcomponent.preferredDisplayName; - } - - return docs; - } ) - ); - + : manifest.subcomponents.map( ( subcomponent ) => { + const docs = getTypeDocsForComponent( { + manifestPath, + componentFilePath: subcomponent.filePath, + displayName: subcomponent.displayName, + } ); + + if ( subcomponent.preferredDisplayName ) { + docs.displayName = subcomponent.preferredDisplayName; + } + + return docs; + } ); const docs = generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ); const outputFile = path.resolve( path.dirname( manifestPath ), From 752792d5e37bec25b69954f5ca16b6b02f595244 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 16 Oct 2024 03:15:55 +0900 Subject: [PATCH 18/20] Apply feedback in markdown props handling --- bin/api-docs/gen-components-docs/markdown/props.mjs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/api-docs/gen-components-docs/markdown/props.mjs b/bin/api-docs/gen-components-docs/markdown/props.mjs index 0cf787239c1ea..9d019c4240f00 100644 --- a/bin/api-docs/gen-components-docs/markdown/props.mjs +++ b/bin/api-docs/gen-components-docs/markdown/props.mjs @@ -1,7 +1,8 @@ function renderPropType( type ) { + const MAX_ENUM_VALUES = 10; + switch ( type.name ) { case 'enum': { - const MAX_ENUM_VALUES = 10; const string = type.value .slice( 0, MAX_ENUM_VALUES ) .map( ( { value } ) => value ) @@ -26,7 +27,7 @@ export function generateMarkdownPropsJson( props, { headingLevel = 2 } = {} ) { .flatMap( ( key ) => { const prop = props[ key ]; - if ( prop.description.includes( '@ignore' ) ) { + if ( prop.description?.includes( '@ignore' ) ) { return null; } From 6fbf877fd3584de2135ed2fa24679236a0e58b88 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 16 Oct 2024 03:21:09 +0900 Subject: [PATCH 19/20] Simplify --- bin/api-docs/gen-components-docs/index.mjs | 26 +++++++++---------- .../gen-components-docs/markdown/index.mjs | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bin/api-docs/gen-components-docs/index.mjs b/bin/api-docs/gen-components-docs/index.mjs index 0c4e02a209dc9..5f01f7984f768 100644 --- a/bin/api-docs/gen-components-docs/index.mjs +++ b/bin/api-docs/gen-components-docs/index.mjs @@ -67,21 +67,21 @@ await Promise.all( displayName: manifest.displayName, } ); - const subcomponentTypeDocs = ! manifest.subcomponents - ? undefined - : manifest.subcomponents.map( ( subcomponent ) => { - const docs = getTypeDocsForComponent( { - manifestPath, - componentFilePath: subcomponent.filePath, - displayName: subcomponent.displayName, - } ); + const subcomponentTypeDocs = manifest.subcomponents?.map( + ( subcomponent ) => { + const docs = getTypeDocsForComponent( { + manifestPath, + componentFilePath: subcomponent.filePath, + displayName: subcomponent.displayName, + } ); - if ( subcomponent.preferredDisplayName ) { - docs.displayName = subcomponent.preferredDisplayName; - } + if ( subcomponent.preferredDisplayName ) { + docs.displayName = subcomponent.preferredDisplayName; + } - return docs; - } ); + return docs; + } + ); const docs = generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ); const outputFile = path.resolve( path.dirname( manifestPath ), diff --git a/bin/api-docs/gen-components-docs/markdown/index.mjs b/bin/api-docs/gen-components-docs/markdown/index.mjs index 7aa42ce69edb9..85655b89f0841 100644 --- a/bin/api-docs/gen-components-docs/markdown/index.mjs +++ b/bin/api-docs/gen-components-docs/markdown/index.mjs @@ -19,7 +19,7 @@ export function generateMarkdownDocs( { typeDocs, subcomponentTypeDocs } ) { ...generateMarkdownPropsJson( typeDocs.props ), ]; - const subcomponentDocsJson = subcomponentTypeDocs + const subcomponentDocsJson = subcomponentTypeDocs?.length ? [ { h2: 'Subcomponents' }, ...subcomponentTypeDocs.flatMap( ( subcomponentTypeDoc ) => [ From 0623f5b1cf343ab583425e56483266ec8369e046 Mon Sep 17 00:00:00 2001 From: Lena Morita Date: Wed, 16 Oct 2024 03:38:53 +0900 Subject: [PATCH 20/20] Handle cases when `displayName` in manifest is wrong --- bin/api-docs/gen-components-docs/index.mjs | 24 ++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/bin/api-docs/gen-components-docs/index.mjs b/bin/api-docs/gen-components-docs/index.mjs index 5f01f7984f768..e036995b4c4f7 100644 --- a/bin/api-docs/gen-components-docs/index.mjs +++ b/bin/api-docs/gen-components-docs/index.mjs @@ -32,17 +32,29 @@ function getTypeDocsForComponent( { componentFilePath ); - const typeDocs = docgen - .parse( resolvedPath, OPTIONS ) - .find( ( obj ) => obj.displayName === displayName ); + const typeDocs = docgen.parse( resolvedPath, OPTIONS ); - if ( typeof typeDocs === 'undefined' ) { + if ( typeDocs.length === 0 ) { throw new Error( - `react-docgen-typescript could not generate type docs for ${ displayName } in ${ resolvedPath }` + `react-docgen-typescript could not generate any type docs from ${ resolvedPath }` ); } - return typeDocs; + const matchingTypeDoc = typeDocs.find( + ( obj ) => obj.displayName === displayName + ); + + if ( typeof matchingTypeDoc === 'undefined' ) { + const unmatchedTypeDocs = typeDocs + .map( ( obj ) => `\`${ obj.displayName }\`` ) + .join( ', ' ); + + throw new Error( + `react-docgen-typescript could not find type docs for ${ displayName } in ${ resolvedPath }. (Found ${ unmatchedTypeDocs })` + ); + } + + return matchingTypeDoc; } async function parseManifest( manifestPath ) {