From ed66b6abb49be3999e2950079a55bbe28de09e52 Mon Sep 17 00:00:00 2001 From: mnajdova Date: Tue, 10 Dec 2024 08:50:53 +0100 Subject: [PATCH 1/7] [docs-infra] Add support for data attributes in the api generation --- packages/api-docs-builder/utils/extractInfoFromEnum.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/api-docs-builder/utils/extractInfoFromEnum.ts b/packages/api-docs-builder/utils/extractInfoFromEnum.ts index 77449c527a3de0..c3eb6c18a43e56 100644 --- a/packages/api-docs-builder/utils/extractInfoFromEnum.ts +++ b/packages/api-docs-builder/utils/extractInfoFromEnum.ts @@ -22,14 +22,13 @@ const extractInfoFromEnum = async ( ): Promise => { // Generate the params let result: ParsedProperty[] = []; - try { - const cssVarDeclarationCandidates = project.program + const declarationCandidates = project.program .getSourceFiles() .filter((file) => sourceFileNamePattern.test(file.fileName)); let enumSymbol: Symbol | null = null; - cssVarDeclarationCandidates.forEach((file) => { + declarationCandidates.forEach((file) => { forEachChild(file, (node: Node) => { if (isEnumDeclaration(node) && node.name.getText() === typeName) { enumSymbol = project.checker.getSymbolAtLocation(node.name)!; From 876fad0c6c2e24c3e6d7ad30abed92b41d85e160 Mon Sep 17 00:00:00 2001 From: mnajdova Date: Tue, 10 Dec 2024 08:51:15 +0100 Subject: [PATCH 2/7] unsaved changes --- docs/pages/material-ui/api/accordion.json | 3 ++ .../api-docs/accordion/accordion.json | 3 +- .../ApiBuilders/ComponentApiBuilder.ts | 44 ++++++++++++++----- .../types/ApiBuilder.types.ts | 9 ++-- .../api-docs-builder/types/utils.types.ts | 2 +- .../src/Accordion/AccordionDataAttributes.ts | 7 +++ 6 files changed, 52 insertions(+), 16 deletions(-) create mode 100644 packages/mui-material/src/Accordion/AccordionDataAttributes.ts diff --git a/docs/pages/material-ui/api/accordion.json b/docs/pages/material-ui/api/accordion.json index 2120b8585e77e7..02ab397c69e630 100644 --- a/docs/pages/material-ui/api/accordion.json +++ b/docs/pages/material-ui/api/accordion.json @@ -65,6 +65,9 @@ "class": null } ], + "dataAttributes": { + "data-panel-open": { "description": "Indicates whether the panel is opened", "type": "boolean" } + }, "classes": [ { "key": "disabled", diff --git a/docs/translations/api-docs/accordion/accordion.json b/docs/translations/api-docs/accordion/accordion.json index ff954964232c7f..6e078a62ca1c26 100644 --- a/docs/translations/api-docs/accordion/accordion.json +++ b/docs/translations/api-docs/accordion/accordion.json @@ -62,5 +62,6 @@ "slotDescriptions": { "heading": "The component that renders the heading.", "transition": "The component that renders the transition. Follow this guide to learn more about the requirements for this component." - } + }, + "dataAttributesDescriptions": { "data-panel-open": "Indicates whether the panel is opened" } } diff --git a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts index ba1a6dddea7e2d..f8f2b8d309c867 100644 --- a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts +++ b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts @@ -31,7 +31,7 @@ import { ComponentReactApi, ParsedProperty, } from '../types/ApiBuilder.types'; -import { Slot, ComponentInfo } from '../types/utils.types'; +import { Slot, ComponentInfo, ApiItemDescription } from '../types/utils.types'; import extractInfoFromEnum from '../utils/extractInfoFromEnum'; const cssComponents = ['Box', 'Grid', 'Typography', 'Stack']; @@ -324,6 +324,7 @@ const generateApiPage = async ( imports: reactApi.imports, ...(reactApi.slots?.length > 0 && { slots: reactApi.slots }), ...(Object.keys(reactApi.cssVariables).length > 0 && { cssVariables: reactApi.cssVariables }), + ...(Object.keys(reactApi.dataAttributes).length > 0 && { dataAttributes: reactApi.dataAttributes }), classes: reactApi.classes, spread: reactApi.spread, themeDefaultProps: reactApi.themeDefaultProps, @@ -477,6 +478,20 @@ const attachTranslations = ( }); } + /** + * Data attributes descriptions. + */ + if (Object.keys(reactApi.dataAttributes).length > 0) { + translations.dataAttributesDescriptions = {}; + [...Object.keys(reactApi.dataAttributes)] + .sort() // Sort to ensure consistency of object key order + .forEach((dataAttributeName: string) => { + const cssVariable = reactApi.dataAttributes[dataAttributeName]; + const { description } = cssVariable; + translations.dataAttributesDescriptions![dataAttributeName] = renderMarkdown(description); + }); + } + reactApi.translations = translations; }; @@ -624,16 +639,16 @@ const defaultGetComponentImports = (name: string, filename: string) => { return [subpathImport, rootImport]; }; -const attachCssVariables = (reactApi: ComponentReactApi, params: ParsedProperty[]) => { - const cssVarsErrors: Array<[propName: string, error: Error]> = []; - const cssVariables: ComponentReactApi['cssVariables'] = params +const attachTable = (reactApi: ComponentReactApi, params: ParsedProperty[], attribute: 'cssVariables' | 'dataAttributes') => { + const errors: Array<[propName: string, error: Error]> = []; + const data: { [key: string]: ApiItemDescription } = params .map((p) => { const { name: propName, ...propDescriptor } = p; let prop: Omit | null; try { prop = propDescriptor; } catch (error) { - cssVarsErrors.push([propName, error as Error]); + errors.push([propName, error as Error]); prop = null; } if (prop === null) { @@ -663,17 +678,17 @@ const attachCssVariables = (reactApi: ComponentReactApi, params: ParsedProperty[ }; }, {}); - if (cssVarsErrors.length > 0) { + if (errors.length > 0) { throw new Error( - `There were errors creating CSS variable descriptions:\n${cssVarsErrors - .map(([cssVarName, error]) => { - return ` - ${cssVarName}: ${error}`; + `There were errors creating ${attribute.replace(/([A-Z])/g, " $1")} descriptions:\n${errors + .map(([item, error]) => { + return ` - ${item}: ${error}`; }) .join('\n')}`, ); } - reactApi.cssVariables = cssVariables; + reactApi[attribute] = data; }; /** @@ -826,8 +841,15 @@ export default async function generateComponentApi( project, ); + const dataAttributes = await extractInfoFromEnum( + `${componentInfo.name}DataAttributes`, + new RegExp(`${componentInfo.name}(DataAttributes)?.tsx?$`, 'i'), + project, + ); + attachPropsTable(reactApi, projectSettings.propsSettings); - attachCssVariables(reactApi, cssVars); + attachTable(reactApi, cssVars, 'cssVariables'); + attachTable(reactApi, dataAttributes, 'dataAttributes'); attachTranslations(reactApi, deprecationInfo, projectSettings.propsSettings); // eslint-disable-next-line no-console diff --git a/packages/api-docs-builder/types/ApiBuilder.types.ts b/packages/api-docs-builder/types/ApiBuilder.types.ts index 7b7f692c40e851..28425d77ea8760 100644 --- a/packages/api-docs-builder/types/ApiBuilder.types.ts +++ b/packages/api-docs-builder/types/ApiBuilder.types.ts @@ -1,6 +1,6 @@ import { ReactDocgenApi } from 'react-docgen'; import { JSDocTagInfo } from 'typescript'; -import { ComponentInfo, Slot, HookInfo, SeeMore, CssVariable } from './utils.types'; +import { ComponentInfo, Slot, HookInfo, SeeMore, ApiItemDescription } from './utils.types'; export type AdditionalPropsInfo = { cssApi?: boolean; @@ -57,6 +57,7 @@ export interface PropsTranslations { }; slotDescriptions?: { [key: string]: string }; cssVariablesDescriptions?: { [key: string]: string }; + dataAttributesDescriptions?: { [key: string]: string }; } interface PropDescription { @@ -92,7 +93,8 @@ export interface ComponentReactApi extends CommonReactApi { themeDefaultProps: boolean | undefined | null; classes: ComponentClassDefinition[]; slots: Slot[]; - cssVariables: { [key: string]: CssVariable }; + cssVariables: { [key: string]: ApiItemDescription }; + dataAttributes: { [key: string]: ApiItemDescription }; propsTable: _.Dictionary; translations: PropsTranslations; } @@ -102,7 +104,8 @@ export interface ComponentApiContent { name: string; imports: string[]; slots?: Slot[]; - cssVariables?: { [key: string]: CssVariable }; + cssVariables?: { [key: string]: ApiItemDescription }; + dataAttributes?: { [key: string]: ApiItemDescription }; classes: ComponentClassDefinition[]; spread: boolean | undefined; themeDefaultProps: boolean | null | undefined; diff --git a/packages/api-docs-builder/types/utils.types.ts b/packages/api-docs-builder/types/utils.types.ts index f0d1b30d39a97e..0010e638e1f2b4 100644 --- a/packages/api-docs-builder/types/utils.types.ts +++ b/packages/api-docs-builder/types/utils.types.ts @@ -7,7 +7,7 @@ export interface Slot { default?: string; } -export interface CssVariable { +export interface ApiItemDescription { name: string; description: string; } diff --git a/packages/mui-material/src/Accordion/AccordionDataAttributes.ts b/packages/mui-material/src/Accordion/AccordionDataAttributes.ts new file mode 100644 index 00000000000000..26257373d4a14a --- /dev/null +++ b/packages/mui-material/src/Accordion/AccordionDataAttributes.ts @@ -0,0 +1,7 @@ +export enum AccordionDataAttributes { + /** + * Indicates whether the panel is opened + * @type {boolean} + */ + panelOpen = 'data-panel-open', +} From 2f1c080016c8c77219b993bcfc86c26b89cebcaf Mon Sep 17 00:00:00 2001 From: mnajdova Date: Tue, 10 Dec 2024 09:32:42 +0100 Subject: [PATCH 3/7] lint & prettier --- .../ApiBuilders/ComponentApiBuilder.ts | 32 +++++++++++-------- .../src/Accordion/AccordionDataAttributes.ts | 4 ++- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts index f8f2b8d309c867..a1cfd6fb82f4a3 100644 --- a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts +++ b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts @@ -324,7 +324,9 @@ const generateApiPage = async ( imports: reactApi.imports, ...(reactApi.slots?.length > 0 && { slots: reactApi.slots }), ...(Object.keys(reactApi.cssVariables).length > 0 && { cssVariables: reactApi.cssVariables }), - ...(Object.keys(reactApi.dataAttributes).length > 0 && { dataAttributes: reactApi.dataAttributes }), + ...(Object.keys(reactApi.dataAttributes).length > 0 && { + dataAttributes: reactApi.dataAttributes, + }), classes: reactApi.classes, spread: reactApi.spread, themeDefaultProps: reactApi.themeDefaultProps, @@ -481,16 +483,16 @@ const attachTranslations = ( /** * Data attributes descriptions. */ - if (Object.keys(reactApi.dataAttributes).length > 0) { - translations.dataAttributesDescriptions = {}; - [...Object.keys(reactApi.dataAttributes)] - .sort() // Sort to ensure consistency of object key order - .forEach((dataAttributeName: string) => { - const cssVariable = reactApi.dataAttributes[dataAttributeName]; - const { description } = cssVariable; - translations.dataAttributesDescriptions![dataAttributeName] = renderMarkdown(description); - }); - } + if (Object.keys(reactApi.dataAttributes).length > 0) { + translations.dataAttributesDescriptions = {}; + [...Object.keys(reactApi.dataAttributes)] + .sort() // Sort to ensure consistency of object key order + .forEach((dataAttributeName: string) => { + const cssVariable = reactApi.dataAttributes[dataAttributeName]; + const { description } = cssVariable; + translations.dataAttributesDescriptions![dataAttributeName] = renderMarkdown(description); + }); + } reactApi.translations = translations; }; @@ -639,7 +641,11 @@ const defaultGetComponentImports = (name: string, filename: string) => { return [subpathImport, rootImport]; }; -const attachTable = (reactApi: ComponentReactApi, params: ParsedProperty[], attribute: 'cssVariables' | 'dataAttributes') => { +const attachTable = ( + reactApi: ComponentReactApi, + params: ParsedProperty[], + attribute: 'cssVariables' | 'dataAttributes', +) => { const errors: Array<[propName: string, error: Error]> = []; const data: { [key: string]: ApiItemDescription } = params .map((p) => { @@ -680,7 +686,7 @@ const attachTable = (reactApi: ComponentReactApi, params: ParsedProperty[], attr if (errors.length > 0) { throw new Error( - `There were errors creating ${attribute.replace(/([A-Z])/g, " $1")} descriptions:\n${errors + `There were errors creating ${attribute.replace(/([A-Z])/g, ' $1')} descriptions:\n${errors .map(([item, error]) => { return ` - ${item}: ${error}`; }) diff --git a/packages/mui-material/src/Accordion/AccordionDataAttributes.ts b/packages/mui-material/src/Accordion/AccordionDataAttributes.ts index 26257373d4a14a..6433c1e6b5de2a 100644 --- a/packages/mui-material/src/Accordion/AccordionDataAttributes.ts +++ b/packages/mui-material/src/Accordion/AccordionDataAttributes.ts @@ -1,7 +1,9 @@ -export enum AccordionDataAttributes { +enum AccordionDataAttributes { /** * Indicates whether the panel is opened * @type {boolean} */ panelOpen = 'data-panel-open', } + +export default AccordionDataAttributes; From 0eafaa04fa68500cc820076fcf9f7299f28ece5d Mon Sep 17 00:00:00 2001 From: mnajdova Date: Tue, 10 Dec 2024 10:25:52 +0100 Subject: [PATCH 4/7] custom default type --- docs/pages/material-ui/api/accordion.json | 6 +++++- docs/translations/api-docs/accordion/accordion.json | 5 ++++- .../ApiBuilders/ComponentApiBuilder.ts | 13 +++++++++---- .../src/Accordion/AccordionDataAttributes.ts | 8 ++++++-- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/docs/pages/material-ui/api/accordion.json b/docs/pages/material-ui/api/accordion.json index 02ab397c69e630..28d48591acc21e 100644 --- a/docs/pages/material-ui/api/accordion.json +++ b/docs/pages/material-ui/api/accordion.json @@ -66,7 +66,11 @@ } ], "dataAttributes": { - "data-panel-open": { "description": "Indicates whether the panel is opened", "type": "boolean" } + "[data-nested-dialogs]": { + "description": "Indicates how many dialogs are nested within.", + "type": "number" + }, + "[data-panel-open]": { "description": "Indicates whether the panel is opened" } }, "classes": [ { diff --git a/docs/translations/api-docs/accordion/accordion.json b/docs/translations/api-docs/accordion/accordion.json index 6e078a62ca1c26..bcc53d61b99432 100644 --- a/docs/translations/api-docs/accordion/accordion.json +++ b/docs/translations/api-docs/accordion/accordion.json @@ -63,5 +63,8 @@ "heading": "The component that renders the heading.", "transition": "The component that renders the transition. Follow this guide to learn more about the requirements for this component." }, - "dataAttributesDescriptions": { "data-panel-open": "Indicates whether the panel is opened" } + "dataAttributesDescriptions": { + "[data-nested-dialogs]": "Indicates how many dialogs are nested within.", + "[data-panel-open]": "Indicates whether the panel is opened" + } } diff --git a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts index a1cfd6fb82f4a3..6d2884c4a08e0a 100644 --- a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts +++ b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts @@ -488,8 +488,8 @@ const attachTranslations = ( [...Object.keys(reactApi.dataAttributes)] .sort() // Sort to ensure consistency of object key order .forEach((dataAttributeName: string) => { - const cssVariable = reactApi.dataAttributes[dataAttributeName]; - const { description } = cssVariable; + const dataAttribute = reactApi.dataAttributes[dataAttributeName]; + const { description } = dataAttribute; translations.dataAttributesDescriptions![dataAttributeName] = renderMarkdown(description); }); } @@ -645,6 +645,7 @@ const attachTable = ( reactApi: ComponentReactApi, params: ParsedProperty[], attribute: 'cssVariables' | 'dataAttributes', + defaultType: any = undefined, ) => { const errors: Array<[propName: string, error: Error]> = []; const data: { [key: string]: ApiItemDescription } = params @@ -666,7 +667,11 @@ const attachTable = ( const deprecation = deprecationTag?.text?.[0]?.text; const typeTag = propDescriptor.tags?.type; - const type = (typeTag?.text?.[0]?.text ?? 'string').replace(/{|}/g, ''); + + let type = (typeTag?.text?.[0]?.text ?? defaultType) + if (typeof type === 'string') { + type = type.replace(/{|}/g, ''); + } return { name: propName, @@ -854,7 +859,7 @@ export default async function generateComponentApi( ); attachPropsTable(reactApi, projectSettings.propsSettings); - attachTable(reactApi, cssVars, 'cssVariables'); + attachTable(reactApi, cssVars, 'cssVariables', 'string'); attachTable(reactApi, dataAttributes, 'dataAttributes'); attachTranslations(reactApi, deprecationInfo, projectSettings.propsSettings); diff --git a/packages/mui-material/src/Accordion/AccordionDataAttributes.ts b/packages/mui-material/src/Accordion/AccordionDataAttributes.ts index 6433c1e6b5de2a..e912784c236e0a 100644 --- a/packages/mui-material/src/Accordion/AccordionDataAttributes.ts +++ b/packages/mui-material/src/Accordion/AccordionDataAttributes.ts @@ -1,9 +1,13 @@ enum AccordionDataAttributes { /** * Indicates whether the panel is opened - * @type {boolean} */ - panelOpen = 'data-panel-open', + panelOpen = '[data-panel-open]', + /** + * Indicates how many dialogs are nested within. + * @type {number} + */ + nestedDialogs = '[data-nested-dialogs]', } export default AccordionDataAttributes; From 85a87fc59ca635c2b0efe03873d51bdf0d25717c Mon Sep 17 00:00:00 2001 From: mnajdova Date: Tue, 10 Dec 2024 13:30:55 +0100 Subject: [PATCH 5/7] prettier --- packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts index ec3656faf35df9..bd74fc89a84bee 100644 --- a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts +++ b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts @@ -679,7 +679,7 @@ const attachTable = ( const typeTag = propDescriptor.tags?.type; - let type = (typeTag?.text?.[0]?.text ?? defaultType) + let type = typeTag?.text?.[0]?.text ?? defaultType; if (typeof type === 'string') { type = type.replace(/{|}/g, ''); } From 86cc3f341662e2850fa3e9bf21af3ca1a37ec0e1 Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 10 Dec 2024 15:41:55 +0100 Subject: [PATCH 6/7] Update packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts Co-authored-by: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Signed-off-by: Marija Najdova --- packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts index bd74fc89a84bee..d02f449cad1b99 100644 --- a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts +++ b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts @@ -656,7 +656,7 @@ const attachTable = ( reactApi: ComponentReactApi, params: ParsedProperty[], attribute: 'cssVariables' | 'dataAttributes', - defaultType: any = undefined, + defaultType?: string, ) => { const errors: Array<[propName: string, error: Error]> = []; const data: { [key: string]: ApiItemDescription } = params From fd11e17a988f1390e66b9919af992b53481ff097 Mon Sep 17 00:00:00 2001 From: mnajdova Date: Tue, 10 Dec 2024 15:51:06 +0100 Subject: [PATCH 7/7] revert test changes --- docs/pages/material-ui/api/accordion.json | 7 ------- docs/translations/api-docs/accordion/accordion.json | 4 ---- .../src/Accordion/AccordionDataAttributes.ts | 13 ------------- 3 files changed, 24 deletions(-) delete mode 100644 packages/mui-material/src/Accordion/AccordionDataAttributes.ts diff --git a/docs/pages/material-ui/api/accordion.json b/docs/pages/material-ui/api/accordion.json index 28d48591acc21e..2120b8585e77e7 100644 --- a/docs/pages/material-ui/api/accordion.json +++ b/docs/pages/material-ui/api/accordion.json @@ -65,13 +65,6 @@ "class": null } ], - "dataAttributes": { - "[data-nested-dialogs]": { - "description": "Indicates how many dialogs are nested within.", - "type": "number" - }, - "[data-panel-open]": { "description": "Indicates whether the panel is opened" } - }, "classes": [ { "key": "disabled", diff --git a/docs/translations/api-docs/accordion/accordion.json b/docs/translations/api-docs/accordion/accordion.json index bcc53d61b99432..ff954964232c7f 100644 --- a/docs/translations/api-docs/accordion/accordion.json +++ b/docs/translations/api-docs/accordion/accordion.json @@ -62,9 +62,5 @@ "slotDescriptions": { "heading": "The component that renders the heading.", "transition": "The component that renders the transition. Follow this guide to learn more about the requirements for this component." - }, - "dataAttributesDescriptions": { - "[data-nested-dialogs]": "Indicates how many dialogs are nested within.", - "[data-panel-open]": "Indicates whether the panel is opened" } } diff --git a/packages/mui-material/src/Accordion/AccordionDataAttributes.ts b/packages/mui-material/src/Accordion/AccordionDataAttributes.ts deleted file mode 100644 index e912784c236e0a..00000000000000 --- a/packages/mui-material/src/Accordion/AccordionDataAttributes.ts +++ /dev/null @@ -1,13 +0,0 @@ -enum AccordionDataAttributes { - /** - * Indicates whether the panel is opened - */ - panelOpen = '[data-panel-open]', - /** - * Indicates how many dialogs are nested within. - * @type {number} - */ - nestedDialogs = '[data-nested-dialogs]', -} - -export default AccordionDataAttributes;