From f668388c9e5268297300abc054f22395c158b20e Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Thu, 16 Jul 2020 11:43:06 +0200 Subject: [PATCH] docgen: restructure docs into index + type docs --- packages/docgen/src/compiler.ts | 27 ++++-- packages/docgen/src/docgen/ApiDocPrinter.ts | 96 +++++++++++++++++++-- 2 files changed, 107 insertions(+), 16 deletions(-) diff --git a/packages/docgen/src/compiler.ts b/packages/docgen/src/compiler.ts index 74ba1db974..ebb370f550 100644 --- a/packages/docgen/src/compiler.ts +++ b/packages/docgen/src/compiler.ts @@ -68,7 +68,6 @@ async function main() { ); const apiDocGenerator = ApiDocGenerator.fromProgram(program, rootDir, srcDir); - const apiDocs = apis .map(api => { try { @@ -79,7 +78,13 @@ async function main() { ); } }) - .sort(sortSelector(x => x.id)); + .sort(sortSelector(x => x.name)); + + const apiTypes = Object.values( + Object.fromEntries( + apiDocs.flatMap(d => d.interfaceInfos).map(i => [i.name, i]), + ), + ).sort(sortSelector(i => i.name)); const apiDocPrinter = new ApiDocPrinter( () => new MarkdownPrinter(new TypescriptHighlighter()), @@ -87,11 +92,16 @@ async function main() { fs.ensureDirSync(resolve(apiRefsDir, 'docs')); - await Promise.all( - apiDocs.map(apiDoc => { - const data = apiDocPrinter.print(apiDoc); + await writeFile( + join(apiRefsDir, 'docs', 'README.md'), + apiDocPrinter.printApiIndex(apiDocs), + ); - return writeFile(join(apiRefsDir, 'docs', `${apiDoc.name}.md`), data); + await Promise.all( + Object.values(apiTypes).map(apiType => { + const data = apiDocPrinter.printInterface(apiType, apiDocs); + + return writeFile(join(apiRefsDir, 'docs', `${apiType.name}.md`), data); }), ); @@ -100,7 +110,10 @@ async function main() { [ 'site_name: api-references', 'nav:', - ...apiDocs.map(({ id, name }) => ` - ${id}: '${name}.md'`), + ` - Utility API Index: 'README.md'`, + ...apiTypes.map(({ name }) => ` - ${name}: '${name}.md'`), + 'plugins:', + ' - techdocs-core', ].join('\n'), 'utf8', ); diff --git a/packages/docgen/src/docgen/ApiDocPrinter.ts b/packages/docgen/src/docgen/ApiDocPrinter.ts index 5047885fc2..a97885430a 100644 --- a/packages/docgen/src/docgen/ApiDocPrinter.ts +++ b/packages/docgen/src/docgen/ApiDocPrinter.ts @@ -17,7 +17,7 @@ import { execSync } from 'child_process'; import MarkdownPrinter from './MarkdownPrinter'; import sortSelector from './sortSelector'; -import { ApiDoc } from './types'; +import { ApiDoc, InterfaceInfo } from './types'; const GH_BASE_URL = 'https://github.com/spotify/backstage'; @@ -67,7 +67,88 @@ export default class ApiDocPrinter { ); printer.paragraph('All members of the interface are listed below.'); - for (const member of ifInfo.members) { + this.addInterfaceMembers(printer, ifInfo); + + if (ifInfo.dependentTypes.length) { + printer.header(2, 'Types'); + + this.addInterfaceTypes(printer, ifInfo); + } + + return printer.toBuffer(); + } + + printApiIndex(apiDocs: ApiDoc[]): Buffer { + const printer = this.printerFactory(); + + printer.header(1, 'Backstage Utility APIs'); + + for (const api of apiDocs) { + printer.header(3, `${api.name.replace(/ApiRef$/, '')}`, api.id); + + printer.paragraph(api.description); + + const typeLinks = api.interfaceInfos.map(i => `[${i.name}](${i.name})`); + printer.paragraph( + `Implemented type${typeLinks.length > 1 ? 's' : ''}: ${typeLinks.join( + ', ', + )}`, + ); + + printer.paragraph(`ApiRef: ${api.name}`); + } + + return printer.toBuffer(); + } + + printInterface(apiType: InterfaceInfo, apiDocs: ApiDoc[]): Buffer { + const printer = this.printerFactory(); + + // Remove line numbers from codeblocks + printer.style('.linenodiv{ display: none }'); + + printer.header(1, apiType.name); + + printer.paragraph( + `The ${apiType.name} type is defined at ${this.mkTypeLink(apiType)}.`, + ); + + const apiLinks = apiDocs + .filter(ad => ad.interfaceInfos.some(i => i.name === apiType.name)) + .map(ad => `[${ad.name}](../#${ad.id})`); + + if (apiLinks.length === 1) { + printer.paragraph( + `The following Utility API implements this type: ${apiLinks}`, + ); + } else { + printer.paragraph(`The following Utility APIs implement this type:`); + for (const link of apiLinks) { + printer.text(` - ${link}`); + } + } + + printer.header(2, 'Members'); + + this.addInterfaceMembers(printer, apiType); + + if (apiType.dependentTypes.length) { + printer.header(2, 'Supporting types'); + printer.paragraph( + 'These types are part of the API declaration, but may not be unique to this API.', + ); + + this.addInterfaceTypes(printer, apiType); + } + + return printer.toBuffer(); + } + + private addInterfaceMembers( + printer: MarkdownPrinter, + apiType: InterfaceInfo, + ) { + for (const member of apiType.members) { printer.header( 3, `${member.name}${member.type === 'method' ? '()' : ''}`, @@ -80,11 +161,10 @@ export default class ApiDocPrinter { printer.codeWithLinks(member); } + } - if (ifInfo.dependentTypes.length) { - printer.header(2, 'Types'); - } - for (const type of ifInfo.dependentTypes + private addInterfaceTypes(printer: MarkdownPrinter, apiType: InterfaceInfo) { + for (const type of apiType.dependentTypes .slice() .sort(sortSelector(x => x.name))) { printer.header(3, `${type.name}`, type.path); @@ -96,7 +176,7 @@ export default class ApiDocPrinter { printer.paragraph(`Defined at ${this.mkTypeLink(type)}.`); - const usageLinks = [...ifInfo.members, ...ifInfo.dependentTypes] + const usageLinks = [...apiType.members, ...apiType.dependentTypes] .filter(member => { return member.links.some(link => link.id === type.id); }) @@ -106,7 +186,5 @@ export default class ApiDocPrinter { printer.paragraph(`Referenced by: ${usageLinks.join(', ')}.`); } } - - return printer.toBuffer(); } }