Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 38 additions & 20 deletions packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { visit as remarkVisit } from 'unist-util-visit';
import type { Link } from 'mdast';
import { defaultHandlers, parse as docgenParse } from 'react-docgen';
import { parse as parseDoctrine, Annotation } from 'doctrine';
import escapeRegExp from 'lodash/escapeRegExp';
import { renderCodeTags, renderMarkdown } from '../buildApi';
import { ProjectSettings, SortingStrategiesType } from '../ProjectSettings';
import { toGitHubPath, writePrettifiedFile } from '../buildApiUtils';
Expand Down Expand Up @@ -229,26 +230,36 @@ async function annotateComponentDefinition(
if (markdownLines[markdownLines.length - 1] !== '') {
markdownLines.push('');
}
markdownLines.push(
'Demos:',
'',
...api.demos.map((demo) => {
return `- [${demo.demoPageTitle}](${
demo.demoPathname.startsWith('http') ? demo.demoPathname : `${HOST}${demo.demoPathname}`
})`;
}),
'',
);

markdownLines.push(
'API:',
'',
`- [${api.name} API](${
api.apiPathname.startsWith('http') ? api.apiPathname : `${HOST}${api.apiPathname}`
})`,
);
if (api.inheritance) {
markdownLines.push(`- inherits ${inheritanceAPILink}`);
if (api.customAnnotation) {
markdownLines.push(
...api.customAnnotation
.split('\n')
.map((line) => line.trim())
.filter(Boolean),
);
} else {
markdownLines.push(
'Demos:',
'',
...api.demos.map((demo) => {
return `- [${demo.demoPageTitle}](${
demo.demoPathname.startsWith('http') ? demo.demoPathname : `${HOST}${demo.demoPathname}`
})`;
}),
'',
);

markdownLines.push(
'API:',
'',
`- [${api.name} API](${
api.apiPathname.startsWith('http') ? api.apiPathname : `${HOST}${api.apiPathname}`
})`,
);
if (api.inheritance) {
markdownLines.push(`- inherits ${inheritanceAPILink}`);
}
}

if (componentJsdoc.tags.length > 0) {
Expand Down Expand Up @@ -764,7 +775,13 @@ export default async function generateComponentApi(
reactApi.description = componentJsdoc.description;

// Ignore what we might have generated in `annotateComponentDefinition`
const annotatedDescriptionMatch = reactApi.description.match(/(Demos|API):\r?\n\r?\n/);
let annotationBoundary: RegExp = /(Demos|API):\r?\n\r?\n/;
if (componentInfo.customAnnotation) {
annotationBoundary = new RegExp(
escapeRegExp(componentInfo.customAnnotation.trim().split('\n')[0].trim()),
);
}
const annotatedDescriptionMatch = reactApi.description.match(new RegExp(annotationBoundary));
if (annotatedDescriptionMatch !== null) {
reactApi.description = reactApi.description.slice(0, annotatedDescriptionMatch.index).trim();
}
Expand All @@ -778,6 +795,7 @@ export default async function generateComponentApi(
reactApi.slots = [];
reactApi.classes = [];
reactApi.demos = componentInfo.getDemos();
reactApi.customAnnotation = componentInfo.customAnnotation;
reactApi.inheritance = null;
if (reactApi.demos.length === 0) {
throw new Error(
Expand Down
64 changes: 44 additions & 20 deletions packages/api-docs-builder/ApiBuilders/HookApiBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { defaultHandlers, parse as docgenParse } from 'react-docgen';
import kebabCase from 'lodash/kebabCase';
import upperFirst from 'lodash/upperFirst';
import { parse as parseDoctrine, Annotation } from 'doctrine';
import escapeRegExp from 'lodash/escapeRegExp';
import { escapeEntities, renderMarkdown } from '../buildApi';
import { ProjectSettings } from '../ProjectSettings';
import { computeApiDescription } from './ComponentApiBuilder';
Expand Down Expand Up @@ -184,32 +185,42 @@ async function annotateHookDefinition(
}

const markdownLines = (await computeApiDescription(api, { host: HOST })).split('\n');

// Ensure a newline between manual and generated description.
if (markdownLines[markdownLines.length - 1] !== '') {
markdownLines.push('');
}

if (api.demos && api.demos.length > 0) {
if (api.customAnnotation) {
markdownLines.push(
'Demos:',
'',
...api.demos.map((item) => {
return `- [${item.demoPageTitle}](${
item.demoPathname.startsWith('http') ? item.demoPathname : `${HOST}${item.demoPathname}`
})`;
}),
...api.customAnnotation
.split('\n')
.map((line) => line.trim())
.filter(Boolean),
);
} else {
if (api.demos && api.demos.length > 0) {
markdownLines.push(
'Demos:',
'',
...api.demos.map((item) => {
return `- [${item.demoPageTitle}](${
item.demoPathname.startsWith('http') ? item.demoPathname : `${HOST}${item.demoPathname}`
})`;
}),
'',
);
}

markdownLines.push(
'API:',
'',
`- [${api.name} API](${
api.apiPathname.startsWith('http') ? api.apiPathname : `${HOST}${api.apiPathname}`
})`,
);
}

markdownLines.push(
'API:',
'',
`- [${api.name} API](${
api.apiPathname.startsWith('http') ? api.apiPathname : `${HOST}${api.apiPathname}`
})`,
);

if (hookJsdoc.tags.length > 0) {
markdownLines.push('');
}
Expand Down Expand Up @@ -410,8 +421,16 @@ export default async function generateHookApi(
project: TypeScriptProject,
projectSettings: ProjectSettings,
) {
const { filename, name, apiPathname, apiPagesDirectory, getDemos, readFile, skipApiGeneration } =
hooksInfo;
const {
filename,
name,
apiPathname,
apiPagesDirectory,
getDemos,
readFile,
skipApiGeneration,
customAnnotation,
} = hooksInfo;

const { shouldSkip, EOL, src } = readFile();

Expand Down Expand Up @@ -445,8 +464,12 @@ export default async function generateHookApi(
// the former can include JSDoc tags that we don't want to render in the docs.
reactApi.description = hookJsdoc.description;

// Ignore what we might have generated in `annotateHookDefinition`
const annotatedDescriptionMatch = reactApi.description.match(/(Demos|API):\r?\n\r?\n/);
// Ignore what we might have generated in `annotateComponentDefinition`
let annotationBoundary: RegExp = /(Demos|API):\r?\n\r?\n/;
if (customAnnotation) {
annotationBoundary = new RegExp(escapeRegExp(customAnnotation.trim().split('\n')[0].trim()));
}
const annotatedDescriptionMatch = reactApi.description.match(new RegExp(annotationBoundary));
if (annotatedDescriptionMatch !== null) {
reactApi.description = reactApi.description.slice(0, annotatedDescriptionMatch.index).trim();
}
Expand All @@ -458,6 +481,7 @@ export default async function generateHookApi(
reactApi.apiPathname = apiPathname;
reactApi.EOL = EOL;
reactApi.demos = getDemos();
reactApi.customAnnotation = customAnnotation;
if (reactApi.demos.length === 0) {
// TODO: Enable this error once all public hooks are documented
// throw new Error(
Expand Down
1 change: 1 addition & 0 deletions packages/api-docs-builder/types/ApiBuilder.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ interface CommonReactApi extends ReactDocgenApi {
*/
apiDocsTranslationFolder?: string;
deprecated: true | undefined;
customAnnotation?: string;
}

export interface PropsTableItem {
Expand Down
8 changes: 8 additions & 0 deletions packages/api-docs-builder/types/utils.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ export type ComponentInfo = {
* If `true`, the component's name match one of the MUI System components.
*/
isSystemComponent?: boolean;
/**
* If provided, this annotation will be used instead of the auto-generated demo & API links
*/
customAnnotation?: string;
};

export type HookInfo = {
Expand All @@ -74,4 +78,8 @@ export type HookInfo = {
getDemos: ComponentInfo['getDemos'];
apiPagesDirectory: string;
skipApiGeneration?: boolean;
/**
* If provided, this annotation will be used instead of the auto-generated demo & API links
*/
customAnnotation?: string;
};
Loading