Skip to content

Commit

Permalink
[docs-infra] Add support for data attributes in the API generation (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mnajdova authored Dec 10, 2024
1 parent 817470c commit 332c01f
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 19 deletions.
57 changes: 45 additions & 12 deletions packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,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'];
Expand Down Expand Up @@ -335,6 +335,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,
}),
classes: reactApi.classes,
spread: reactApi.spread,
themeDefaultProps: reactApi.themeDefaultProps,
Expand Down Expand Up @@ -488,6 +491,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 dataAttribute = reactApi.dataAttributes[dataAttributeName];
const { description } = dataAttribute;
translations.dataAttributesDescriptions![dataAttributeName] = renderMarkdown(description);
});
}

reactApi.translations = translations;
};

Expand Down Expand Up @@ -635,16 +652,21 @@ 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',
defaultType?: string,
) => {
const errors: Array<[propName: string, error: Error]> = [];
const data: { [key: string]: ApiItemDescription } = params
.map((p) => {
const { name: propName, ...propDescriptor } = p;
let prop: Omit<ParsedProperty, 'name'> | null;
try {
prop = propDescriptor;
} catch (error) {
cssVarsErrors.push([propName, error as Error]);
errors.push([propName, error as Error]);
prop = null;
}
if (prop === null) {
Expand All @@ -656,7 +678,11 @@ const attachCssVariables = (reactApi: ComponentReactApi, params: ParsedProperty[
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,
Expand All @@ -674,17 +700,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;
};

/**
Expand Down Expand Up @@ -844,8 +870,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', 'string');
attachTable(reactApi, dataAttributes, 'dataAttributes');
attachTranslations(reactApi, deprecationInfo, projectSettings.propsSettings);

// eslint-disable-next-line no-console
Expand Down
9 changes: 6 additions & 3 deletions packages/api-docs-builder/types/ApiBuilder.types.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -58,6 +58,7 @@ export interface PropsTranslations {
};
slotDescriptions?: { [key: string]: string };
cssVariablesDescriptions?: { [key: string]: string };
dataAttributesDescriptions?: { [key: string]: string };
}

interface PropDescription {
Expand Down Expand Up @@ -93,7 +94,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<PropsTableItem>;
translations: PropsTranslations;
}
Expand All @@ -103,7 +105,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;
Expand Down
2 changes: 1 addition & 1 deletion packages/api-docs-builder/types/utils.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface Slot {
default?: string;
}

export interface CssVariable {
export interface ApiItemDescription {
name: string;
description: string;
}
Expand Down
5 changes: 2 additions & 3 deletions packages/api-docs-builder/utils/extractInfoFromEnum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,13 @@ const extractInfoFromEnum = async (
): Promise<ParsedProperty[]> => {
// 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)!;
Expand Down

0 comments on commit 332c01f

Please sign in to comment.