generate-typescript-docs.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /* tslint:disable:no-console */
  2. import fs from 'fs-extra';
  3. import klawSync from 'klaw-sync';
  4. import path, { extname } from 'path';
  5. import { deleteGeneratedDocs } from './docgen-utils';
  6. import { TypeMap } from './typescript-docgen-types';
  7. import { TypescriptDocsParser } from './typescript-docs-parser';
  8. import { TypescriptDocsRenderer } from './typescript-docs-renderer';
  9. interface DocsSectionConfig {
  10. sourceDirs: string[];
  11. outputPath: string;
  12. }
  13. const sections: DocsSectionConfig[] = [
  14. {
  15. sourceDirs: ['packages/core/src/', 'packages/common/src/'],
  16. outputPath: 'typescript-api',
  17. },
  18. {
  19. sourceDirs: ['packages/asset-server-plugin/src/'],
  20. outputPath: 'plugins',
  21. },
  22. {
  23. sourceDirs: ['packages/email-plugin/src/'],
  24. outputPath: 'plugins',
  25. },
  26. {
  27. sourceDirs: ['packages/admin-ui-plugin/src/'],
  28. outputPath: 'plugins',
  29. },
  30. ];
  31. generateTypescriptDocs(sections);
  32. const watchMode = !!process.argv.find(arg => arg === '--watch' || arg === '-w');
  33. if (watchMode) {
  34. console.log(`Watching for changes to source files...`);
  35. sections.forEach(section => {
  36. section.sourceDirs.forEach(dir => {
  37. fs.watch(dir, { recursive: true }, (eventType, file) => {
  38. if (extname(file) === '.ts') {
  39. generateTypescriptDocs([section]);
  40. }
  41. });
  42. });
  43. });
  44. }
  45. /**
  46. * Uses the TypeScript compiler API to parse the given files and extract out the documentation
  47. * into markdown files
  48. */
  49. function generateTypescriptDocs(config: DocsSectionConfig[]) {
  50. const timeStart = +new Date();
  51. // This map is used to cache types and their corresponding Hugo path. It is used to enable
  52. // hyperlinking from a member's "type" to the definition of that type.
  53. const globalTypeMap: TypeMap = new Map();
  54. for (const { outputPath, sourceDirs } of config) {
  55. deleteGeneratedDocs(absOutputPath(outputPath));
  56. }
  57. for (const { outputPath, sourceDirs } of config) {
  58. const sourceFilePaths = getSourceFilePaths(sourceDirs);
  59. const parsedDeclarations = new TypescriptDocsParser().parse(sourceFilePaths);
  60. for (const info of parsedDeclarations) {
  61. globalTypeMap.set(info.title, info.category + '/' + info.fileName);
  62. }
  63. const docsUrl = `/docs/${outputPath}`;
  64. const generatedCount = new TypescriptDocsRenderer().render(
  65. parsedDeclarations,
  66. docsUrl,
  67. absOutputPath(outputPath),
  68. globalTypeMap,
  69. );
  70. if (generatedCount) {
  71. console.log(`Generated ${generatedCount} typescript api docs for "${outputPath}" in ${+new Date() - timeStart}ms`);
  72. }
  73. }
  74. }
  75. function absOutputPath(outputPath: string): string {
  76. return path.join(__dirname, '../../docs/content/docs/', outputPath);
  77. }
  78. function getSourceFilePaths(sourceDirs: string[]): string[] {
  79. return sourceDirs
  80. .map(scanPath =>
  81. klawSync(path.join(__dirname, '../../', scanPath), {
  82. nodir: true,
  83. filter: item => path.extname(item.path) === '.ts',
  84. traverseAll: true,
  85. }),
  86. )
  87. .reduce((allFiles, files) => [...allFiles, ...files], [])
  88. .map(item => item.path);
  89. }