diff --git a/packages/typedoc-plugin-markdown/src/index.ts b/packages/typedoc-plugin-markdown/src/index.ts index 5a21d09ca..14c4a597f 100644 --- a/packages/typedoc-plugin-markdown/src/index.ts +++ b/packages/typedoc-plugin-markdown/src/index.ts @@ -3,20 +3,16 @@ * * @module core */ -import { getTranslatable } from '@plugin/internationalization/translatable.js'; +import { setupInternationalization } from '@plugin/internationalization/index.js'; import { declarations } from '@plugin/options/index.js'; -import { resolvePackages } from '@plugin/renderer/packages.js'; -import { MarkdownRendererHooks, MarkdownTheme } from 'public-api.js'; +import { render, setupRenderer } from '@plugin/renderer/index.js'; +import { MarkdownRenderer } from '@plugin/types/index.js'; import { Application, - Context, - Converter, DeclarationOption, - EventHooks, ParameterHint, ParameterType, } from 'typedoc'; -import { render } from './renderer/render.js'; /** * The function that is called by TypeDoc to bootstrap the plugin. @@ -27,13 +23,6 @@ import { render } from './renderer/render.js'; * * This method is not intended to be consumed in any other context that via the `plugin` option. * - * The load functions: - * - * 1. Bootstrap the plugin options - * 2. Configures markdown outputs - * 3. Configures localization - * 4. Applies any other behaviour - * * The module also exports anything that is available publicly. * */ @@ -43,8 +32,6 @@ export function load(app: Application) { * 1. Bootstrap options * ==================== */ - - // Iterate over declaration definitions and to the container. Object.entries(declarations).forEach(([name, declaration]) => { app.options.addDeclaration({ name, @@ -52,13 +39,6 @@ export function load(app: Application) { } as DeclarationOption); }); - app.renderer.defineTheme('markdown', MarkdownTheme); - - /** - * ============================= - * 2. Configure markdown outputs - * ============================= - */ app.options.addDeclaration({ name: 'markdown', outputShortcut: 'markdown', @@ -68,48 +48,24 @@ export function load(app: Application) { defaultValue: './docs', }); - app.outputs.addOutput('markdown', async (out, project) => { - await render(app.renderer, project, out); - }); - - app.outputs.setDefaultOutputName('markdown'); - - Object.defineProperty(app.renderer, 'markdownHooks', { - value: new EventHooks(), - }); - /** - * ========================= - * 3. Configure localization - * ========================= + * ============================= + * 2. Configure markdown outputs + * ============================= */ - - // Load the additional translations used by the theme for the selected language. - app.converter.on(Converter.EVENT_BEGIN, () => { - app.internationalization.addTranslations( - app.options.getValue('lang'), - { ...getTranslatable(app) }, - true, - ); + app.outputs.addOutput('markdown', async (out, project) => { + await render(app.renderer as unknown as MarkdownRenderer, project, out); }); - /** - * ============================ - * 4. Apply any other behaviour - * ============================ - */ + app.outputs.setDefaultOutputName('markdown'); /** - * Currently options set for packages are only stored on the converter and are destroyed before being passed to the {@link Renderer}. - * - * By intercepting the package options set in the converter and storing them on the renderer we can use them later in the theme. - * + * ===================================== + * 3. Setup up renderer and translations + * ====================================== */ - app.converter.on(Converter.EVENT_RESOLVE_END, (context: Context) => { - if (app.options.packageDir) { - resolvePackages(app, context, app.options.packageDir); - } - }); + setupRenderer(app); + setupInternationalization(app); } /** diff --git a/packages/typedoc-plugin-markdown/src/internationalization/index.ts b/packages/typedoc-plugin-markdown/src/internationalization/index.ts index 95d3a77bf..f6bc2231a 100644 --- a/packages/typedoc-plugin-markdown/src/internationalization/index.ts +++ b/packages/typedoc-plugin-markdown/src/internationalization/index.ts @@ -8,4 +8,4 @@ * @module */ export * from './locales/index.js'; -export * from './translatable.js'; +export * from './setup.js'; diff --git a/packages/typedoc-plugin-markdown/src/internationalization/setup.ts b/packages/typedoc-plugin-markdown/src/internationalization/setup.ts new file mode 100644 index 000000000..921abeff1 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/internationalization/setup.ts @@ -0,0 +1,35 @@ +import { en, jp, ko, zh } from '@plugin/internationalization/index.js'; +import { Application, Converter } from 'typedoc'; + +export function setupInternationalization(app: Application): void { + app.converter.on(Converter.EVENT_BEGIN, () => { + app.internationalization.addTranslations( + app.options.getValue('lang'), + { ...getTranslatable(app) }, + true, + ); + }); +} + +/** + * Returns subset of translatable strings for the plugin. + * + * These will then be merged with the main set of TypeDoc string. + * + * @category Functions + */ +function getTranslatable(app: Application) { + const LOCALES = { + en, + jp, + ko, + zh, + }; + return { + ...LOCALES['en'], + ...(app.lang !== 'en' && Object.keys(LOCALES).includes(app.lang) + ? { ...LOCALES[app.lang] } + : {}), + ...app.options.getValue('locales')[app.lang], + }; +} diff --git a/packages/typedoc-plugin-markdown/src/internationalization/translatable.ts b/packages/typedoc-plugin-markdown/src/internationalization/translatable.ts index 70d647535..da2f4ae9a 100644 --- a/packages/typedoc-plugin-markdown/src/internationalization/translatable.ts +++ b/packages/typedoc-plugin-markdown/src/internationalization/translatable.ts @@ -3,28 +3,3 @@ * * @module */ -import { en, jp, ko, zh } from 'internationalization/index.js'; -import { Application } from 'typedoc'; - -/** - * Returns subset of translatable strings for the plugin. - * - * These will then be merged with the main set of TypeDoc string. - * - * @category Functions - */ -export function getTranslatable(app: Application) { - const LOCALES = { - en, - jp, - ko, - zh, - }; - return { - ...LOCALES['en'], - ...(app.lang !== 'en' && Object.keys(LOCALES).includes(app.lang) - ? { ...LOCALES[app.lang] } - : {}), - ...app.options.getValue('locales')[app.lang], - }; -} diff --git a/packages/typedoc-plugin-markdown/src/renderer/index.ts b/packages/typedoc-plugin-markdown/src/renderer/index.ts index 743b28635..5246863e7 100644 --- a/packages/typedoc-plugin-markdown/src/renderer/index.ts +++ b/packages/typedoc-plugin-markdown/src/renderer/index.ts @@ -4,5 +4,5 @@ * @module */ -export * from './packages.js'; export * from './render.js'; +export * from './setup.js'; diff --git a/packages/typedoc-plugin-markdown/src/renderer/packages.ts b/packages/typedoc-plugin-markdown/src/renderer/packages.ts deleted file mode 100644 index 3b4b2c423..000000000 --- a/packages/typedoc-plugin-markdown/src/renderer/packages.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { MarkdownRenderer } from '@plugin/types/index.js'; -import * as fs from 'fs'; -import * as path from 'path'; -import { Application, Context } from 'typedoc'; - -/** - * Resolves packages meta data for the project. - * - * @remarks - * - * Currently options set for packages are only stored on the converter and are destroyed before being passed to the Renderer. - * - * By intercepting the package options set in the converter and storing them on the renderer we can use them later in the theme. - */ -export function resolvePackages( - app: Application, - context: Context, - packageDir: string, -) { - const packageJsonContents = fs - .readFileSync(path.join(packageDir, 'package.json')) - .toString(); - - const packageJson = packageJsonContents - ? JSON.parse(packageJsonContents) - : {}; - - const renderer = app.renderer as unknown as MarkdownRenderer; - - renderer.packagesMeta = { - ...(renderer.packagesMeta || {}), - [context.project.name]: { - description: packageJson.description, - options: app.options, - }, - }; -} diff --git a/packages/typedoc-plugin-markdown/src/renderer/render.ts b/packages/typedoc-plugin-markdown/src/renderer/render.ts index 2ed738560..5adc713c2 100644 --- a/packages/typedoc-plugin-markdown/src/renderer/render.ts +++ b/packages/typedoc-plugin-markdown/src/renderer/render.ts @@ -2,7 +2,8 @@ import { MarkdownPageEvent, MarkdownRendererEvent, } from '@plugin/events/index.js'; -import { MarkdownTheme } from '@plugin/public-api.js'; +import { MarkdownTheme } from '@plugin/theme/index.js'; +import { MarkdownRenderer } from '@plugin/types/index.js'; import * as fs from 'fs'; import * as path from 'path'; import { @@ -24,7 +25,7 @@ import { * - Adds any logic specific to markdown rendering. */ export async function render( - renderer: Renderer, + renderer: MarkdownRenderer, project: ProjectReflection, outputDirectory: string, ) { @@ -49,13 +50,15 @@ export async function render( renderer.trigger(MarkdownRendererEvent.BEGIN, output); - await executeJobs(renderer.preRenderAsyncJobs, output); + await executeJobs(renderer.preMarkdownRenderAsyncJobs, output); + await executeJobs(renderer.preRenderAsyncJobs, output); // for backward compatibility await renderPages(renderer, output); copyMediaFiles(project, outputDirectory); - await executeJobs(renderer.postRenderAsyncJobs, output); + await executeJobs(renderer.postMarkdownRenderAsyncJobs, output); + await executeJobs(renderer.postRenderAsyncJobs, output); // for backward compatibility renderer.trigger(MarkdownRendererEvent.END, output); diff --git a/packages/typedoc-plugin-markdown/src/renderer/setup.ts b/packages/typedoc-plugin-markdown/src/renderer/setup.ts new file mode 100644 index 000000000..b2bc2811f --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/renderer/setup.ts @@ -0,0 +1,66 @@ +import { MarkdownTheme } from '@plugin/theme/index.js'; +import { + MarkdownRenderer, + MarkdownRendererHooks, +} from '@plugin/types/index.js'; +import * as fs from 'fs'; +import * as path from 'path'; +import { Application, Context, Converter, EventHooks } from 'typedoc'; + +/** + * Create dedicated hooks and async job collections for markdown rendering. + */ +export function setupRenderer(app: Application) { + app.renderer.defineTheme('markdown', MarkdownTheme); + + Object.defineProperty(app.renderer, 'markdownHooks', { + value: new EventHooks(), + }); + + Object.defineProperty(app.renderer, 'preMarkdownRenderAsyncJobs', { + value: [], + }); + + Object.defineProperty(app.renderer, 'postMarkdownRenderAsyncJobs', { + value: [], + }); + + app.converter.on(Converter.EVENT_RESOLVE_END, (context: Context) => { + if (app.options.packageDir) { + resolvePackages(app, context, app.options.packageDir); + } + }); +} + +/** + * Resolves packages meta data for the project. + * + * @remarks + * + * Currently options set for packages are only stored on the converter and are destroyed before being passed to the Renderer. + * + * By intercepting the package options set in the converter and storing them on the renderer we can use them later in the theme. + */ +function resolvePackages( + app: Application, + context: Context, + packageDir: string, +) { + const packageJsonContents = fs + .readFileSync(path.join(packageDir, 'package.json')) + .toString(); + + const packageJson = packageJsonContents + ? JSON.parse(packageJsonContents) + : {}; + + const renderer = app.renderer as unknown as MarkdownRenderer; + + renderer.packagesMeta = { + ...(renderer.packagesMeta || {}), + [context.project.name]: { + description: packageJson.description, + options: app.options, + }, + }; +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme.ts index ce8e8c941..bb57d34d9 100644 --- a/packages/typedoc-plugin-markdown/src/theme/markdown-theme.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme.ts @@ -10,7 +10,6 @@ import { ProjectReflection, Reflection, ReflectionKind, - Renderer, Theme, } from 'typedoc'; @@ -24,10 +23,6 @@ import { * The API follows the implementation of [TypeDoc's custom theming](/~https://github.com/TypeStrong/typedoc/blob/master/internal-docs/custom-themes.md) with some minor adjustments. */ export class MarkdownTheme extends Theme { - constructor(renderer: Renderer) { - super(renderer); - } - /** * Renders a template and page model to a string. */ diff --git a/packages/typedoc-plugin-markdown/src/types/markdown-renderer.ts b/packages/typedoc-plugin-markdown/src/types/markdown-renderer.ts index 70d3957d6..2e7620340 100644 --- a/packages/typedoc-plugin-markdown/src/types/markdown-renderer.ts +++ b/packages/typedoc-plugin-markdown/src/types/markdown-renderer.ts @@ -53,14 +53,25 @@ export interface MarkdownRenderer extends Renderer { theme: new (renderer: Renderer) => MarkdownTheme, ) => void; + /** + * Dedicated markdown hooks to add to the renderer + */ markdownHooks: EventHooks; + /** + * Configure pre and post async jobs + * + * When used with "outputs" is preMarkdownRenderAsyncJobs and postMarkdownRenderAsyncJobs should be used. + */ + /** * A list of async jobs which must be completed before rendering output. * * Note: This array is cleared after calling the contained functions on each call. */ - preRenderAsyncJobs: Array<(output: MarkdownRendererEvent) => Promise>; + preMarkdownRenderAsyncJobs: Array< + (output: MarkdownRendererEvent) => Promise + >; /** * A list of async jobs which must be completed after rendering output files but before generation is considered successful. @@ -68,7 +79,16 @@ export interface MarkdownRenderer extends Renderer { * * Note: This array is cleared after calling the contained functions on each call. */ + postMarkdownRenderAsyncJobs: Array< + (output: MarkdownRendererEvent) => Promise + >; + + // For backwards compatibility + preRenderAsyncJobs: Array<(output: MarkdownRendererEvent) => Promise>; postRenderAsyncJobs: Array<(output: MarkdownRendererEvent) => Promise>; + /** + * Store meta data about packages + */ packagesMeta: Record; } diff --git a/packages/typedoc-plugin-markdown/test/fixtures/custom-plugins/custom-theme.mjs b/packages/typedoc-plugin-markdown/test/fixtures/custom-plugins/custom-theme.mjs index 5b963d878..d0044b662 100644 --- a/packages/typedoc-plugin-markdown/test/fixtures/custom-plugins/custom-theme.mjs +++ b/packages/typedoc-plugin-markdown/test/fixtures/custom-plugins/custom-theme.mjs @@ -57,7 +57,7 @@ export function load(app) { () => '> **Generated using `index.page.end` hook**', ); - app.renderer.preRenderAsyncJobs.push(async (renderer) => { + app.renderer.preMarkdownRenderAsyncJobs.push(async (renderer) => { await new Promise((r) => setTimeout(r, 5)); fs.writeFileSync( `${renderer.outputDirectory}/pre-render-async-job.txt`, @@ -65,7 +65,7 @@ export function load(app) { ); }); - app.renderer.postRenderAsyncJobs.push(async (renderer) => { + app.renderer.postMarkdownRenderAsyncJobs.push(async (renderer) => { await new Promise((r) => setTimeout(r, 5)); fs.writeFileSync( `${renderer.outputDirectory}/post-render-async-job.txt`,