Skip to content

Commit b63fb95

Browse files
authored
[code-infra] Migrate to prettier async APIs (#40668)
Signed-off-by: Jan Potoms <[email protected]>
1 parent 8c039dd commit b63fb95

File tree

12 files changed

+153
-134
lines changed

12 files changed

+153
-134
lines changed

docs/scripts/formattedTSDemos.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -112,19 +112,19 @@ async function transpileFile(tsxPath, project) {
112112
},
113113
});
114114
const codeWithPropTypes = injectPropTypesInFile({ components: propTypesAST, target: code });
115-
const prettierConfig = prettier.resolveConfig.sync(jsPath, {
115+
const prettierConfig = await prettier.resolveConfig(jsPath, {
116116
config: path.join(workspaceRoot, 'prettier.config.js'),
117117
});
118-
const prettierFormat = (jsSource) =>
118+
const prettierFormat = async (jsSource) =>
119119
prettier.format(jsSource, { ...prettierConfig, filepath: jsPath });
120120

121121
const codeWithoutTsIgnoreComments = codeWithPropTypes.replace(/^\s*\/\/ @ts-ignore.*$/gm, '');
122-
const prettified = prettierFormat(codeWithoutTsIgnoreComments);
122+
const prettified = await prettierFormat(codeWithoutTsIgnoreComments);
123123
const formatted = fixBabelGeneratorIssues(prettified);
124124
const correctedLineEndings = fixLineEndings(source, formatted);
125125

126126
// removed blank lines change potential formatting
127-
await fse.writeFile(jsPath, prettierFormat(correctedLineEndings));
127+
await fse.writeFile(jsPath, await prettierFormat(correctedLineEndings));
128128
return TranspileResult.Success;
129129
} catch (err) {
130130
console.error('Something went wrong transpiling %s\n%s\n', tsxPath, err);

packages/api-docs-builder-core/baseUi/generateBaseUiApiPages.ts

+82-80
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,28 @@ import { getHeaders } from '@mui/markdown';
55
import findPagesMarkdown from '@mui-internal/api-docs-builder/utils/findPagesMarkdown';
66
import { writePrettifiedFile } from '@mui-internal/api-docs-builder/buildApiUtils';
77

8-
export function generateBaseUIApiPages() {
9-
findPagesMarkdown().forEach((markdown) => {
10-
const markdownContent = fs.readFileSync(markdown.filename, 'utf8');
11-
const markdownHeaders = getHeaders(markdownContent) as any;
12-
const pathnameTokens = markdown.pathname.split('/');
13-
const productName = pathnameTokens[1];
14-
const componentName = pathnameTokens[3];
15-
16-
// TODO: fix `productName` should be called `productId` and include the full name,
17-
// e.g. base-ui below.
18-
if (
19-
productName === 'base' &&
20-
(markdown.filename.indexOf('\\components\\') >= 0 ||
21-
markdown.filename.indexOf('/components/') >= 0)
22-
) {
23-
const { components, hooks } = markdownHeaders;
24-
25-
const tokens = markdown.pathname.split('/');
26-
const name = tokens[tokens.length - 1];
27-
const importStatement = `docs/data${markdown.pathname}/${name}.md`;
28-
const demosSource = `
8+
export async function generateBaseUIApiPages() {
9+
await Promise.all(
10+
findPagesMarkdown().map(async (markdown) => {
11+
const markdownContent = fs.readFileSync(markdown.filename, 'utf8');
12+
const markdownHeaders = getHeaders(markdownContent) as any;
13+
const pathnameTokens = markdown.pathname.split('/');
14+
const productName = pathnameTokens[1];
15+
const componentName = pathnameTokens[3];
16+
17+
// TODO: fix `productName` should be called `productId` and include the full name,
18+
// e.g. base-ui below.
19+
if (
20+
productName === 'base' &&
21+
(markdown.filename.indexOf('\\components\\') >= 0 ||
22+
markdown.filename.indexOf('/components/') >= 0)
23+
) {
24+
const { components, hooks } = markdownHeaders;
25+
26+
const tokens = markdown.pathname.split('/');
27+
const name = tokens[tokens.length - 1];
28+
const importStatement = `docs/data${markdown.pathname}/${name}.md`;
29+
const demosSource = `
2930
import * as React from 'react';
3031
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2';
3132
import AppFrame from 'docs/src/modules/components/AppFrame';
@@ -41,77 +42,77 @@ Page.getLayout = (page) => {
4142
};
4243
`;
4344

44-
const componentPageDirectory = `docs/pages/${productName}-ui/react-${componentName}/`;
45-
if (!fs.existsSync(componentPageDirectory)) {
46-
fs.mkdirSync(componentPageDirectory, { recursive: true });
47-
}
48-
writePrettifiedFile(
49-
path.join(process.cwd(), `${componentPageDirectory}/index.js`),
50-
demosSource,
51-
);
52-
53-
if ((!components || components.length === 0) && (!hooks || hooks.length === 0)) {
54-
// Early return if it's a markdown file without components/hooks.
55-
return;
56-
}
57-
58-
let apiTabImportStatements = '';
59-
let staticProps = 'export const getStaticProps = () => {';
60-
let componentsApiDescriptions = '';
61-
let componentsPageContents = '';
62-
let hooksApiDescriptions = '';
63-
let hooksPageContents = '';
64-
65-
if (components && components.length > 0) {
66-
components.forEach((component: string) => {
67-
const componentNameKebabCase = kebabCase(component);
68-
apiTabImportStatements += `import ${component}ApiJsonPageContent from '../../api/${componentNameKebabCase}.json';`;
69-
staticProps += `
45+
const componentPageDirectory = `docs/pages/${productName}-ui/react-${componentName}/`;
46+
if (!fs.existsSync(componentPageDirectory)) {
47+
fs.mkdirSync(componentPageDirectory, { recursive: true });
48+
}
49+
await writePrettifiedFile(
50+
path.join(process.cwd(), `${componentPageDirectory}/index.js`),
51+
demosSource,
52+
);
53+
54+
if ((!components || components.length === 0) && (!hooks || hooks.length === 0)) {
55+
// Early return if it's a markdown file without components/hooks.
56+
return;
57+
}
58+
59+
let apiTabImportStatements = '';
60+
let staticProps = 'export const getStaticProps = () => {';
61+
let componentsApiDescriptions = '';
62+
let componentsPageContents = '';
63+
let hooksApiDescriptions = '';
64+
let hooksPageContents = '';
65+
66+
if (components && components.length > 0) {
67+
components.forEach((component: string) => {
68+
const componentNameKebabCase = kebabCase(component);
69+
apiTabImportStatements += `import ${component}ApiJsonPageContent from '../../api/${componentNameKebabCase}.json';`;
70+
staticProps += `
7071
const ${component}ApiReq = require.context(
7172
'docs/translations/api-docs-base/${componentNameKebabCase}',
7273
false,
7374
/${componentNameKebabCase}.*.json$/,
7475
);
7576
const ${component}ApiDescriptions = mapApiPageTranslations(${component}ApiReq);
7677
`;
77-
componentsApiDescriptions += `${component} : ${component}ApiDescriptions ,`;
78-
componentsPageContents += `${component} : ${component}ApiJsonPageContent ,`;
79-
});
80-
}
81-
82-
if (hooks && hooks.length > 0) {
83-
hooks.forEach((hook: string) => {
84-
const hookNameKebabCase = kebabCase(hook);
85-
apiTabImportStatements += `import ${hook}ApiJsonPageContent from '../../api/${hookNameKebabCase}.json';`;
86-
staticProps += `
78+
componentsApiDescriptions += `${component} : ${component}ApiDescriptions ,`;
79+
componentsPageContents += `${component} : ${component}ApiJsonPageContent ,`;
80+
});
81+
}
82+
83+
if (hooks && hooks.length > 0) {
84+
hooks.forEach((hook: string) => {
85+
const hookNameKebabCase = kebabCase(hook);
86+
apiTabImportStatements += `import ${hook}ApiJsonPageContent from '../../api/${hookNameKebabCase}.json';`;
87+
staticProps += `
8788
const ${hook}ApiReq = require.context(
8889
'docs/translations/api-docs/${hookNameKebabCase}',
8990
false,
9091
/${hookNameKebabCase}.*.json$/,
9192
);
9293
const ${hook}ApiDescriptions = mapApiPageTranslations(${hook}ApiReq);
9394
`;
94-
hooksApiDescriptions += `${hook} : ${hook}ApiDescriptions ,`;
95-
hooksPageContents += `${hook} : ${hook}ApiJsonPageContent ,`;
96-
});
97-
}
95+
hooksApiDescriptions += `${hook} : ${hook}ApiDescriptions ,`;
96+
hooksPageContents += `${hook} : ${hook}ApiJsonPageContent ,`;
97+
});
98+
}
9899

99-
staticProps += `
100+
staticProps += `
100101
return { props: { componentsApiDescriptions: {`;
101-
staticProps += componentsApiDescriptions;
102+
staticProps += componentsApiDescriptions;
102103

103-
staticProps += '}, componentsApiPageContents: { ';
104-
staticProps += componentsPageContents;
104+
staticProps += '}, componentsApiPageContents: { ';
105+
staticProps += componentsPageContents;
105106

106-
staticProps += '}, hooksApiDescriptions: {';
107-
staticProps += hooksApiDescriptions;
107+
staticProps += '}, hooksApiDescriptions: {';
108+
staticProps += hooksApiDescriptions;
108109

109-
staticProps += '}, hooksApiPageContents: {';
110-
staticProps += hooksPageContents;
110+
staticProps += '}, hooksApiPageContents: {';
111+
staticProps += hooksPageContents;
111112

112-
staticProps += ` },},};};`;
113+
staticProps += ` },},};};`;
113114

114-
const tabsApiSource = `
115+
const tabsApiSource = `
115116
import * as React from 'react';
116117
import MarkdownDocs from 'docs/src/modules/components/MarkdownDocsV2';
117118
import AppFrame from 'docs/src/modules/components/AppFrame';
@@ -138,14 +139,15 @@ export const getStaticPaths = () => {
138139
${staticProps}
139140
`;
140141

141-
const docsTabsPagesDirectory = `${componentPageDirectory}/[docsTab]`;
142-
if (!fs.existsSync(docsTabsPagesDirectory)) {
143-
fs.mkdirSync(docsTabsPagesDirectory, { recursive: true });
142+
const docsTabsPagesDirectory = `${componentPageDirectory}/[docsTab]`;
143+
if (!fs.existsSync(docsTabsPagesDirectory)) {
144+
fs.mkdirSync(docsTabsPagesDirectory, { recursive: true });
145+
}
146+
await writePrettifiedFile(
147+
path.join(process.cwd(), `${docsTabsPagesDirectory}/index.js`),
148+
tabsApiSource,
149+
);
144150
}
145-
writePrettifiedFile(
146-
path.join(process.cwd(), `${docsTabsPagesDirectory}/index.js`),
147-
tabsApiSource,
148-
);
149-
}
150-
});
151+
}),
152+
);
151153
}

packages/api-docs-builder-core/baseUi/projectSettings.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ export const projectSettings: ProjectSettings = {
2727
getHookInfo: getBaseUiHookInfo,
2828
translationLanguages: LANGUAGES,
2929
skipComponent: () => false,
30-
onCompleted: () => {
31-
generateBaseUIApiPages();
30+
onCompleted: async () => {
31+
await generateBaseUIApiPages();
3232
},
3333
onWritingManifestFile(builds, source) {
3434
const apiLinks = generateApiLinks(builds);

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

+5-5
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ function extractClassCondition(description: string) {
354354
return { description: renderMarkdown(description) };
355355
}
356356

357-
const generateApiPage = (
357+
const generateApiPage = async (
358358
apiPagesDirectory: string,
359359
importTranslationPagesDirectory: string,
360360
reactApi: ReactApi,
@@ -412,13 +412,13 @@ const generateApiPage = (
412412
pageContent.slots = [...pageContent.slots].sort(slotsSort);
413413
}
414414

415-
writePrettifiedFile(
415+
await writePrettifiedFile(
416416
path.resolve(apiPagesDirectory, `${kebabCase(reactApi.name)}.json`),
417417
JSON.stringify(pageContent),
418418
);
419419

420420
if (!onlyJsonFile) {
421-
writePrettifiedFile(
421+
await writePrettifiedFile(
422422
path.resolve(apiPagesDirectory, `${kebabCase(reactApi.name)}.js`),
423423
`import * as React from 'react';
424424
import ApiPage from 'docs/src/modules/components/ApiPage';
@@ -789,14 +789,14 @@ export default async function generateComponentApi(
789789
generateJsonFileOnly,
790790
} = projectSettings;
791791

792-
generateApiTranslations(
792+
await generateApiTranslations(
793793
path.join(process.cwd(), translationPagesDirectory),
794794
reactApi,
795795
projectSettings.translationLanguages,
796796
);
797797

798798
// Once we have the tabs API in all projects, we can make this default
799-
generateApiPage(
799+
await generateApiPage(
800800
componentInfo.apiPagesDirectory,
801801
importTranslationPagesDirectory ?? translationPagesDirectory,
802802
reactApi,

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

+20-12
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,15 @@ interface ParsedProperty {
3030
typeStr: string;
3131
}
3232

33-
const parseProperty = (propertySymbol: ts.Symbol, project: TypeScriptProject): ParsedProperty => ({
33+
const parseProperty = async (
34+
propertySymbol: ts.Symbol,
35+
project: TypeScriptProject,
36+
): Promise<ParsedProperty> => ({
3437
name: propertySymbol.name,
3538
description: getSymbolDescription(propertySymbol, project),
3639
tags: getSymbolJSDocTags(propertySymbol),
3740
required: !propertySymbol.declarations?.find(ts.isPropertySignature)?.questionToken,
38-
typeStr: stringifySymbol(propertySymbol, project),
41+
typeStr: await stringifySymbol(propertySymbol, project),
3942
});
4043

4144
export interface ReactApi extends ReactDocgenApi {
@@ -394,7 +397,7 @@ const attachTranslations = (reactApi: ReactApi) => {
394397
reactApi.translations = translations;
395398
};
396399

397-
const generateApiJson = (outputDirectory: string, reactApi: ReactApi) => {
400+
const generateApiJson = async (outputDirectory: string, reactApi: ReactApi) => {
398401
/**
399402
* Gather the metadata needed for the component's API page.
400403
*/
@@ -430,13 +433,16 @@ const generateApiJson = (outputDirectory: string, reactApi: ReactApi) => {
430433
.join('\n')}</ul>`,
431434
};
432435

433-
writePrettifiedFile(
436+
await writePrettifiedFile(
434437
path.resolve(outputDirectory, `${kebabCase(reactApi.name)}.json`),
435438
JSON.stringify(pageContent),
436439
);
437440
};
438441

439-
const extractInfoFromType = (typeName: string, project: TypeScriptProject): ParsedProperty[] => {
442+
const extractInfoFromType = async (
443+
typeName: string,
444+
project: TypeScriptProject,
445+
): Promise<ParsedProperty[]> => {
440446
// Generate the params
441447
let result: ParsedProperty[] = [];
442448

@@ -454,9 +460,11 @@ const extractInfoFromType = (typeName: string, project: TypeScriptProject): Pars
454460
const propertiesOnProject = type.getProperties();
455461

456462
// @ts-ignore
457-
propertiesOnProject.forEach((propertySymbol) => {
458-
properties[propertySymbol.name] = parseProperty(propertySymbol, project);
459-
});
463+
await Promise.all(
464+
propertiesOnProject.map(async (propertySymbol) => {
465+
properties[propertySymbol.name] = await parseProperty(propertySymbol, project);
466+
}),
467+
);
460468

461469
result = Object.values(properties)
462470
.filter((property) => !property.tags.ignore)
@@ -536,8 +544,8 @@ export default async function generateHookApi(
536544
{ filename },
537545
);
538546

539-
const parameters = extractInfoFromType(`${upperFirst(name)}Parameters`, project);
540-
const returnValue = extractInfoFromType(`${upperFirst(name)}ReturnValue`, project);
547+
const parameters = await extractInfoFromType(`${upperFirst(name)}Parameters`, project);
548+
const returnValue = await extractInfoFromType(`${upperFirst(name)}ReturnValue`, project);
541549

542550
// Ignore what we might have generated in `annotateHookDefinition`
543551
const annotatedDescriptionMatch = reactApi.description.match(/(Demos|API):\r?\n\r?\n/);
@@ -572,12 +580,12 @@ export default async function generateHookApi(
572580

573581
if (!skipApiGeneration) {
574582
// Generate pages, json and translations
575-
generateApiTranslations(
583+
await generateApiTranslations(
576584
path.join(process.cwd(), 'docs/translations/api-docs'),
577585
reactApi,
578586
projectSettings.translationLanguages,
579587
);
580-
generateApiJson(apiPagesDirectory, reactApi);
588+
await generateApiJson(apiPagesDirectory, reactApi);
581589

582590
// Add comment about demo & api links to the component hook file
583591
await annotateHookDefinition(reactApi);

packages/api-docs-builder/ProjectSettings.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export interface ProjectSettings {
4040
/**
4141
* Callback function to be called when the API generation is completed
4242
*/
43-
onCompleted?: () => void;
43+
onCompleted?: () => void | Promise<void>;
4444
/**
4545
* Callback to customize the manifest file before it's written to the disk
4646
*/

packages/api-docs-builder/buildApi.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,8 @@ async function buildSingleProject(
189189
source = projectSettings.onWritingManifestFile(builds, source);
190190
}
191191

192-
writePrettifiedFile(apiPagesManifestPath, source);
192+
await writePrettifiedFile(apiPagesManifestPath, source);
193193

194-
projectSettings.onCompleted?.();
194+
await projectSettings.onCompleted?.();
195195
return builds;
196196
}

0 commit comments

Comments
 (0)