Skip to content

Commit 4c5d9eb

Browse files
authored
[docs-infra] Add a rawDescriptions option (#44390)
1 parent d74e950 commit 4c5d9eb

File tree

8 files changed

+66
-36
lines changed

8 files changed

+66
-36
lines changed

packages/api-docs-builder/ApiBuilders/ComponentApiBuilder.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import { remark } from 'remark';
99
import { visit as remarkVisit } from 'unist-util-visit';
1010
import type { Link } from 'mdast';
1111
import { defaultHandlers, parse as docgenParse } from 'react-docgen';
12-
import { renderMarkdown } from '@mui/internal-markdown';
1312
import { parse as parseDoctrine, Annotation } from 'doctrine';
13+
import { renderCodeTags, renderMarkdown } from '../buildApi';
1414
import { ProjectSettings, SortingStrategiesType } from '../ProjectSettings';
1515
import { toGitHubPath, writePrettifiedFile } from '../buildApiUtils';
1616
import muiDefaultPropsHandler from '../utils/defaultPropsHandler';
@@ -279,7 +279,7 @@ function extractClassCondition(description: string) {
279279
description.replace(stylesRegex, '$1{{nodeName}}$5{{conditions}}.'),
280280
),
281281
nodeName: renderMarkdown(conditions[3]),
282-
conditions: renderMarkdown(conditions[6].replace(/`(.*?)`/g, '<code>$1</code>')),
282+
conditions: renderMarkdown(renderCodeTags(conditions[6])),
283283
};
284284
}
285285

packages/api-docs-builder/ApiBuilders/HookApiBuilder.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { defaultHandlers, parse as docgenParse } from 'react-docgen';
99
import kebabCase from 'lodash/kebabCase';
1010
import upperFirst from 'lodash/upperFirst';
1111
import { parse as parseDoctrine, Annotation } from 'doctrine';
12-
import { renderMarkdown } from '@mui/internal-markdown';
12+
import { escapeEntities, renderMarkdown } from '../buildApi';
1313
import { ProjectSettings } from '../ProjectSettings';
1414
import { computeApiDescription } from './ComponentApiBuilder';
1515
import {
@@ -268,12 +268,7 @@ const attachTable = (
268268
const requiredProp = prop.required;
269269

270270
const deprecation = (propDescriptor.description || '').match(/@deprecated(\s+(?<info>.*))?/);
271-
const typeDescription = (propDescriptor.typeStr ?? '')
272-
.replace(/&/g, '&amp;')
273-
.replace(/</g, '&lt;')
274-
.replace(/>/g, '&gt;')
275-
.replace(/"/g, '&quot;')
276-
.replace(/'/g, '&#39;');
271+
const typeDescription = escapeEntities(propDescriptor.typeStr ?? '');
277272
return {
278273
[propName]: {
279274
type: {

packages/api-docs-builder/buildApi.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { mkdirSync } from 'fs';
22
import path from 'path';
33
import * as fse from 'fs-extra';
4+
import { renderMarkdown as _renderMarkdown } from '@mui/internal-markdown';
45
import findComponents from './utils/findComponents';
56
import findHooks from './utils/findHooks';
67
import { writePrettifiedFile } from './buildApiUtils';
@@ -13,6 +14,8 @@ import {
1314
} from './utils/createTypeScriptProject';
1415
import { ProjectSettings } from './ProjectSettings';
1516
import { ComponentReactApi } from './types/ApiBuilder.types';
17+
import _escapeCell from './utils/escapeCell';
18+
import _escapeEntities from './utils/escapeEntities';
1619

1720
async function removeOutdatedApiDocsTranslations(
1821
components: readonly ComponentReactApi[],
@@ -64,7 +67,14 @@ async function removeOutdatedApiDocsTranslations(
6467
);
6568
}
6669

67-
export async function buildApi(projectsSettings: ProjectSettings[], grep: RegExp | null = null) {
70+
let rawDescriptionsCurrent = false;
71+
72+
export async function buildApi(
73+
projectsSettings: ProjectSettings[],
74+
grep: RegExp | null = null,
75+
rawDescriptions = false,
76+
) {
77+
rawDescriptionsCurrent = rawDescriptions;
6878
const allTypeScriptProjects = projectsSettings
6979
.flatMap((setting) => setting.typeScriptProjects)
7080
.reduce(
@@ -118,7 +128,6 @@ async function buildSingleProject(
118128
if (manifestDir) {
119129
mkdirSync(manifestDir, { recursive: true });
120130
}
121-
122131
const apiBuilds = tsProjects.flatMap((project) => {
123132
const projectComponents = findComponents(path.join(project.rootPath, 'src')).filter(
124133
(component) => {
@@ -202,3 +211,20 @@ async function buildSingleProject(
202211
await projectSettings.onCompleted?.();
203212
return builds;
204213
}
214+
215+
export function renderMarkdown(markdown: string) {
216+
return rawDescriptionsCurrent ? markdown : _renderMarkdown(markdown);
217+
}
218+
export function renderCodeTags(value: string) {
219+
return rawDescriptionsCurrent ? value : value.replace(/`(.*?)`/g, '<code>$1</code>');
220+
}
221+
export function escapeEntities(value: string) {
222+
return rawDescriptionsCurrent ? value : _escapeEntities(value);
223+
}
224+
export function escapeCell(value: string) {
225+
return rawDescriptionsCurrent ? value : _escapeCell(value);
226+
}
227+
export function joinUnionTypes(value: string[]) {
228+
// Use unopinionated formatting for raw descriptions
229+
return rawDescriptionsCurrent ? value.join(' | ') : value.join('<br>&#124;&nbsp;');
230+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default function escapeEntities(value: string): string {
2+
return value
3+
.replace(/&/g, '&amp;')
4+
.replace(/</g, '&lt;')
5+
.replace(/>/g, '&gt;')
6+
.replace(/"/g, '&quot;')
7+
.replace(/'/g, '&#39;');
8+
}

packages/api-docs-builder/utils/generatePropDescription.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import * as doctrine from 'doctrine';
22
import * as recast from 'recast';
33
import { PropTypeDescriptor } from 'react-docgen';
4+
import { escapeCell } from '../buildApi';
45
import {
56
isElementTypeAcceptingRefProp,
67
isElementAcceptingRefProp,
78
} from './generatePropTypeDescription';
89
import { DescribeablePropDescriptor } from './createDescribeableProp';
9-
import escapeCell from './escapeCell';
1010
import { SeeMore } from '../types/utils.types';
1111

1212
function resolveType(type: NonNullable<doctrine.Tag['type']>): string {

packages/api-docs-builder/utils/generatePropTypeDescription.ts

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as recast from 'recast';
22
import { parse as docgenParse, PropTypeDescriptor } from 'react-docgen';
3-
import escapeCell from './escapeCell';
3+
import { escapeCell, escapeEntities, joinUnionTypes } from '../buildApi';
44

55
function getDeprecatedInfo(type: PropTypeDescriptor) {
66
const marker = /deprecatedPropType\((\r*\n)*\s*PropTypes\./g;
@@ -113,26 +113,20 @@ export default function generatePropTypeDescription(type: PropTypeDescriptor): s
113113
.join(', ')} }`;
114114

115115
case 'union':
116-
return (
117-
type.value
118-
.map((type2) => {
119-
return generatePropTypeDescription(type2);
120-
})
121-
// Display one value per line as it's better for visibility.
122-
.join('<br>&#124;&nbsp;')
116+
return joinUnionTypes(
117+
type.value.map((type2) => {
118+
return generatePropTypeDescription(type2) ?? '';
119+
}),
123120
);
124121
case 'enum':
125-
return (
126-
type.value
127-
.map((type2) => {
128-
return escapeCell(type2.value);
129-
})
130-
// Display one value per line as it's better for visibility.
131-
.join('<br>&#124;&nbsp;')
122+
return joinUnionTypes(
123+
type.value.map((type2) => {
124+
return escapeCell(type2.value);
125+
}),
132126
);
133127

134128
case 'arrayOf': {
135-
return `Array&lt;${generatePropTypeDescription(type.value)}&gt;`;
129+
return `Array${escapeEntities('<')}${generatePropTypeDescription(type.value)}${escapeEntities('>')}`;
136130
}
137131

138132
case 'instanceOf': {

packages/api-docs-builder/utils/parseSlotsAndClasses.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as ts from 'typescript';
22
import { ComponentClassDefinition } from '@mui-internal/api-docs-builder';
3-
import { renderMarkdown } from '@mui/internal-markdown';
3+
import { renderMarkdown } from '../buildApi';
44
import { getSymbolDescription, getSymbolJSDocTags } from '../buildApiUtils';
55
import { TypeScriptProject } from './createTypeScriptProject';
66
import { getPropsFromComponentNode } from './getPropsFromComponentNode';

scripts/buidApiDocs/index.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,30 @@ const projectSettings: ProjectSettings[] = [
1414
muiSystemProjectSettings,
1515
];
1616

17-
type CommandOptions = { grep?: string };
17+
type CommandOptions = { grep?: string; rawDescriptions?: boolean };
1818

1919
async function run(argv: ArgumentsCamelCase<CommandOptions>) {
2020
const grep = argv.grep == null ? null : new RegExp(argv.grep);
21-
return buildApi(projectSettings, grep);
21+
const rawDescriptions = argv.rawDescriptions === true;
22+
return buildApi(projectSettings, grep, rawDescriptions);
2223
}
2324

2425
yargs(process.argv.slice(2))
2526
.command({
2627
command: '$0',
2728
describe: 'Generates API documentation for the MUI packages.',
2829
builder: (command) => {
29-
return command.option('grep', {
30-
description:
31-
'Only generate files for component filenames matching the pattern. The string is treated as a RegExp.',
32-
type: 'string',
33-
});
30+
return command
31+
.option('grep', {
32+
description:
33+
'Only generate files for component filenames matching the pattern. The string is treated as a RegExp.',
34+
type: 'string',
35+
})
36+
.option('rawDescriptions', {
37+
description: 'Whether to output raw JSDoc descriptions or process them as markdown.',
38+
type: 'boolean',
39+
default: false,
40+
});
3441
},
3542
handler: run,
3643
})

0 commit comments

Comments
 (0)