From ea603881087aadf68917cfb8d81465004c6662ca Mon Sep 17 00:00:00 2001 From: Marija Najdova Date: Tue, 3 Dec 2024 11:01:21 +0100 Subject: [PATCH] [docs-infra] Change CSS vars generation to be extracted from Enum (#44587) --- .../ApiBuilders/ComponentApiBuilder.ts | 12 ++-- .../utils/extractInfoFromEnum.ts | 71 +++++++++++++++++++ 2 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 packages/api-docs-builder/utils/extractInfoFromEnum.ts diff --git a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts index 02a81285bb3ddb..ba1a6dddea7e2d 100644 --- a/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts +++ b/packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts @@ -32,7 +32,7 @@ import { ParsedProperty, } from '../types/ApiBuilder.types'; import { Slot, ComponentInfo } from '../types/utils.types'; -import extractInfoFromType from '../utils/extractInfoFromType'; +import extractInfoFromEnum from '../utils/extractInfoFromEnum'; const cssComponents = ['Box', 'Grid', 'Typography', 'Stack']; @@ -645,10 +645,10 @@ const attachCssVariables = (reactApi: ComponentReactApi, params: ParsedProperty[ const deprecation = deprecationTag?.text?.[0]?.text; const typeTag = propDescriptor.tags?.type; - const type = typeTag?.text?.[0]?.text ?? 'string'; + const type = (typeTag?.text?.[0]?.text ?? 'string').replace(/{|}/g, ''); return { - name: `--${kebabCase(propName)}`, + name: propName, description: propDescriptor.description, type, deprecated: !!deprecation || undefined, @@ -820,7 +820,11 @@ export default async function generateComponentApi( reactApi.deprecated = !!deprecation || undefined; - const cssVars = await extractInfoFromType(`${componentInfo.name}CssVars`, project); + const cssVars = await extractInfoFromEnum( + `${componentInfo.name}CssVars`, + new RegExp(`${componentInfo.name}(CssVars|Classes)?.tsx?$`, 'i'), + project, + ); attachPropsTable(reactApi, projectSettings.propsSettings); attachCssVariables(reactApi, cssVars); diff --git a/packages/api-docs-builder/utils/extractInfoFromEnum.ts b/packages/api-docs-builder/utils/extractInfoFromEnum.ts new file mode 100644 index 00000000000000..77449c527a3de0 --- /dev/null +++ b/packages/api-docs-builder/utils/extractInfoFromEnum.ts @@ -0,0 +1,71 @@ +import { Symbol, isPropertySignature, isEnumDeclaration, forEachChild, Node } from 'typescript'; +import { TypeScriptProject } from './createTypeScriptProject'; +import { ParsedProperty } from '../types/ApiBuilder.types'; +import { getSymbolDescription, getSymbolJSDocTags, stringifySymbol } from '../buildApiUtils'; + +const parseProperty = async ( + propertySymbol: Symbol, + project: TypeScriptProject, + name: string, +): Promise => ({ + name, + description: getSymbolDescription(propertySymbol, project), + tags: getSymbolJSDocTags(propertySymbol), + required: !propertySymbol.declarations?.find(isPropertySignature)?.questionToken, + typeStr: await stringifySymbol(propertySymbol, project), +}); + +const extractInfoFromEnum = async ( + typeName: string, + sourceFileNamePattern: RegExp, + project: TypeScriptProject, +): Promise => { + // Generate the params + let result: ParsedProperty[] = []; + + try { + const cssVarDeclarationCandidates = project.program + .getSourceFiles() + .filter((file) => sourceFileNamePattern.test(file.fileName)); + + let enumSymbol: Symbol | null = null; + cssVarDeclarationCandidates.forEach((file) => { + forEachChild(file, (node: Node) => { + if (isEnumDeclaration(node) && node.name.getText() === typeName) { + enumSymbol = project.checker.getSymbolAtLocation(node.name)!; + } + }); + }); + + if (!enumSymbol) { + return []; + } + + const type = project.checker.getDeclaredTypeOfSymbol(enumSymbol!); + + // @ts-ignore + const typeDeclaration = type?.types ?? [type]; + if (!typeDeclaration) { + return []; + } + const properties: Record = {}; + + // @ts-ignore + await Promise.all( + typeDeclaration.map(async (t: any) => { + const propertySymbol = t.symbol; + properties[t.value] = await parseProperty(propertySymbol, project, t.value); + }), + ); + + result = Object.values(properties) + .filter((property) => !property.tags.ignore) + .sort((a, b) => a.name.localeCompare(b.name)); + } catch { + console.error(`No declaration for ${typeName}`); + } + + return result; +}; + +export default extractInfoFromEnum;