diff --git a/devtools/examples/docusaurus3/docusaurus.config.js b/devtools/examples/docusaurus3/docusaurus.config.js index 0f6c95664..847aaa354 100644 --- a/devtools/examples/docusaurus3/docusaurus.config.js +++ b/devtools/examples/docusaurus3/docusaurus.config.js @@ -60,7 +60,6 @@ const config = { sidebar: { pretty: true }, outputFileStrategy: 'members', cleanOutputDir: true, - plugin: ['typedoc-plugin-coverage'], }, ], [ @@ -77,7 +76,6 @@ const config = { entryPoints: '../../../packages/typedoc-plugin-markdown/test/fixtures/src/groups/**/*.ts', cleanOutputDir: true, - plugin: ['typedoc-plugin-coverage'], }, ], [ @@ -97,7 +95,6 @@ const config = { outputFileStrategy: 'modules', entryModule: 'index', cleanOutputDir: true, - plugin: ['typedoc-plugin-coverage'], }, ], [ @@ -115,7 +112,6 @@ const config = { '../../../packages/typedoc-plugin-markdown/test/fixtures/src/packages/*', entryPointStrategy: 'packages', sidebar: { pretty: true }, - plugin: ['typedoc-plugin-coverage'], }, ], ], diff --git a/devtools/packages/helpers/constants.ts b/devtools/packages/helpers/constants.ts index f250bb0d6..7b10baf57 100644 --- a/devtools/packages/helpers/constants.ts +++ b/devtools/packages/helpers/constants.ts @@ -4,8 +4,8 @@ export const PRESETS_PATH = `${process.cwd()}/src/options/presets.ts`; export const DOCS_CONFIG: Record = { ['typedoc-plugin-markdown']: { - declarationsPath: `${process.cwd()}/src/plugin/options/declarations.ts`, - optionsPath: 'options', + declarationsPath: `${process.cwd()}/src/app/options/declarations.ts`, + optionsPath: '', docsPath: '', declarations: true, presets: false, @@ -27,7 +27,7 @@ export const DOCS_CONFIG: Record = { ['typedoc-github-wiki-theme']: { declarationsPath: `${process.cwd()}/src/options/declarations.ts`, optionsPath: 'themes/github-wiki', - docsPath: '/themes/github-wiki/introduction', + docsPath: '/themes/github-wiki', declarations: true, presets: true, }, diff --git a/devtools/packages/prebuild-options/tasks/generate-docs.ts b/devtools/packages/prebuild-options/tasks/generate-docs.ts index 89420c219..a47f49440 100644 --- a/devtools/packages/prebuild-options/tasks/generate-docs.ts +++ b/devtools/packages/prebuild-options/tasks/generate-docs.ts @@ -146,7 +146,7 @@ ${JSON.stringify( } const optionDocPath = path.join( - getDocsPath(docsConfig.docsPath), + getDocsPath(docsConfig.optionsPath), 'options.mdx', ); diff --git a/devtools/packages/testing/lint.mdx.mjs b/devtools/packages/testing/lint.mdx.mjs index ef07e07df..2f67c69f9 100644 --- a/devtools/packages/testing/lint.mdx.mjs +++ b/devtools/packages/testing/lint.mdx.mjs @@ -16,7 +16,7 @@ lintMdx(); async function lintMdx() { const mdFiles = await glob(`./test/out/**/opts-1/**/*.md`); - console.log(mdFiles); + mdFiles.forEach(async (file) => { const vfile = await read(file); try { diff --git a/docs/pages/_meta.json b/docs/pages/_meta.json index f83c3627b..fcab7be58 100644 --- a/docs/pages/_meta.json +++ b/docs/pages/_meta.json @@ -1,5 +1,6 @@ { "index": "Introduction", + "api": "", "quick-start": "", "options": "", "guide": "Guide", diff --git a/docs/pages/helpers.md b/docs/pages/helpers.md deleted file mode 100644 index 35f9cf6e5..000000000 --- a/docs/pages/helpers.md +++ /dev/null @@ -1,170 +0,0 @@ -# Helpers - -## flattenDeclarations() - -```ts -function flattenDeclarations(props: DeclarationReflection[], includeSignatures: boolean): any[]; -``` - -Flattens declarations into a single array, useful for displaying items in tables. - -### Parameters - -| Parameter | Type | Default value | -| :------------------ | :---------------------------------------------------------------------------------------------- | :------------ | -| `props` | [`DeclarationReflection`](https://typedoc.org/api/classes/Models.DeclarationReflection.html)\[] | `undefined` | -| `includeSignatures` | `boolean` | `false` | - -### Returns - -`any`\[] - ---- - -## getDeclarationType() - -```ts -function getDeclarationType(declaration: DeclarationReflection): undefined | SomeType; -``` - -### Parameters - -| Parameter | Type | -| :------------ | :------------------------------------------------------------------------------------------- | -| `declaration` | [`DeclarationReflection`](https://typedoc.org/api/classes/Models.DeclarationReflection.html) | - -### Returns - -`undefined` | `SomeType` - ---- - -## getIndexTitle() - -```ts -function getIndexTitle(textContent: string, name: string, version?: string): string; -``` - -### Parameters - -| Parameter | Type | -| :------------ | :------- | -| `textContent` | `string` | -| `name` | `string` | -| `version`? | `string` | - -### Returns - -`string` - ---- - -## getKeyword() - -```ts -function getKeyword(kind: ReflectionKind): any; -``` - -### Parameters - -| Parameter | Type | -| :-------- | :--------------- | -| `kind` | `ReflectionKind` | - -### Returns - -`any` - ---- - -## getModifier() - -```ts -function getModifier(reflection: DeclarationReflection): string | null; -``` - -### Parameters - -| Parameter | Type | -| :----------- | :------------------------------------------------------------------------------------------- | -| `reflection` | [`DeclarationReflection`](https://typedoc.org/api/classes/Models.DeclarationReflection.html) | - -### Returns - -`string` | `null` - ---- - -## getParameterDefaultValue() - -```ts -function getParameterDefaultValue(parameter: ParameterReflection): string; -``` - -### Parameters - -| Parameter | Type | -| :---------- | :-------------------- | -| `parameter` | `ParameterReflection` | - -### Returns - -`string` - ---- - -## isGroupKind() - -```ts -function isGroupKind(reflection: DeclarationReflection | SignatureReflection): boolean; -``` - -### Parameters - -| Parameter | Type | -| :----------- | :------------------------------------------------------------------------------------------- | --------------------- | -| `reflection` | [`DeclarationReflection`](https://typedoc.org/api/classes/Models.DeclarationReflection.html) | `SignatureReflection` | - -### Returns - -`boolean` - ---- - -## parseComments() - -```ts -function parseComments(comments: string): string; -``` - -Exposed to additionally parse comments. - -### Parameters - -| Parameter | Type | Description | -| :--------- | :------- | :---------- | -| `comments` | `string` | | - -### Returns - -`string` - ---- - -## parseUrl() - -```ts -function parseUrl(url: string): string; -``` - -Additional url parsing - -### Parameters - -| Parameter | Type | -| :-------- | :------- | -| `url` | `string` | - -### Returns - -`string` diff --git a/docs/pages/options.mdx b/docs/pages/options.mdx index a3e9fa3db..d6e9c161e 100644 --- a/docs/pages/options.mdx +++ b/docs/pages/options.mdx @@ -565,6 +565,26 @@ If undefined all urls will be relative. ___ +### preserveMarkup + +Preserves non-html markup tags in comments. + +> Accepts a boolean value. Defaults to `false`. + +By default non html tags inside comments are escaped. + +This option should be used when parsers require the preservation of non-html tags, for example if some custom JSX tags are required to be interpreted in final output. + + +```json filename="typedoc.json" +{ + "preserveMarkup": false +} + +``` + +___ + ### preserveAnchorCasing Preserve anchor casing when generating link to symbols. diff --git a/docs/styles.css b/docs/styles.css index 36190896b..c2e089934 100644 --- a/docs/styles.css +++ b/docs/styles.css @@ -1,4 +1,6 @@ .nextra-toc a[href^='#parameters'], -.nextra-toc a[href^='#returns'] { +.nextra-toc a[href^='#returns'], +.nextra-toc a[href^='#source'], +.nextra-toc a[href^='#overrides'] { display: none; } diff --git a/package-lock.json b/package-lock.json index 199eaf0d9..6b53586e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@changesets/cli": "^2.27.1", "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.12", - "@types/node": "^20.11.21", + "@types/node": "^20.11.24", "@typescript-eslint/eslint-plugin": "^7.1.0", "@typescript-eslint/parser": "^7.1.0", "consola": "^3.2.3", @@ -39,7 +39,8 @@ "ts-jest": "^29.1.2", "ts-morph": "^21.0.1", "ts-node": "^10.9.2", - "typedoc": "^0.25.9", + "tsc-alias": "^1.8.8", + "typedoc": "0.25.9", "typescript": "^5.3.3", "unified-prettier": "^2.0.1" } @@ -54,6 +55,7 @@ "devtools/packages/generate-readmes": { "name": "@devtools/generate-readmes", "version": "0.0.0", + "extraneous": true, "bin": { "generate-readmes": "cli.ts" } @@ -2335,10 +2337,6 @@ "resolved": "devtools/packages/fixtures", "link": true }, - "node_modules/@devtools/generate-readmes": { - "resolved": "devtools/packages/generate-readmes", - "link": true - }, "node_modules/@devtools/helpers": { "resolved": "devtools/packages/helpers", "link": true @@ -4899,9 +4897,9 @@ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "20.11.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.21.tgz", - "integrity": "sha512-/ySDLGscFPNasfqStUuWWPfL78jompfIoVzLJPVVAHBh6rpG68+pI2Gk+fNLeI8/f1yPYL4s46EleVIc20F1Ow==", + "version": "20.11.24", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", + "integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -15623,6 +15621,19 @@ "multicast-dns": "cli.js" } }, + "node_modules/mylas": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/mylas/-/mylas-2.1.13.tgz", + "integrity": "sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/raouldeheer" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -16346,6 +16357,18 @@ "node": ">=4" } }, + "node_modules/plimit-lit": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/plimit-lit/-/plimit-lit-1.6.1.tgz", + "integrity": "sha512-B7+VDyb8Tl6oMJT9oSO2CW8XC/T4UcJGrwOVoNGwOQsQYhlpfajmrMj5xeejqaASq3V/EqThyOeATEOMuSEXiA==", + "dev": true, + "dependencies": { + "queue-lit": "^1.5.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/postcss": { "version": "8.4.33", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", @@ -17294,6 +17317,15 @@ "inherits": "~2.0.3" } }, + "node_modules/queue-lit": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/queue-lit/-/queue-lit-1.5.2.tgz", + "integrity": "sha512-tLc36IOPeMAubu8BkW8YDBV+WyIgKlYU7zUNs0J5Vk9skSZ4JfGlPOqplP0aHdfv7HL0B2Pg6nwiq60Qc6M2Hw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -20236,6 +20268,32 @@ } } }, + "node_modules/tsc-alias": { + "version": "1.8.8", + "resolved": "https://registry.npmjs.org/tsc-alias/-/tsc-alias-1.8.8.tgz", + "integrity": "sha512-OYUOd2wl0H858NvABWr/BoSKNERw3N9GTi3rHPK8Iv4O1UyUXIrTTOAZNHsjlVpXFOhpJBVARI1s+rzwLivN3Q==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.3", + "commander": "^9.0.0", + "globby": "^11.0.4", + "mylas": "^2.1.9", + "normalize-path": "^3.0.0", + "plimit-lit": "^1.2.6" + }, + "bin": { + "tsc-alias": "dist/bin/index.js" + } + }, + "node_modules/tsc-alias/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", diff --git a/package.json b/package.json index e0b8c9013..58bea8bdf 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "@changesets/cli": "^2.27.1", "@types/fs-extra": "^11.0.4", "@types/jest": "^29.5.12", - "@types/node": "^20.11.21", + "@types/node": "^20.11.24", "@typescript-eslint/eslint-plugin": "^7.1.0", "@typescript-eslint/parser": "^7.1.0", "consola": "^3.2.3", @@ -40,7 +40,8 @@ "ts-jest": "^29.1.2", "ts-morph": "^21.0.1", "ts-node": "^10.9.2", - "typedoc": "^0.25.9", + "tsc-alias": "^1.8.8", + "typedoc": "0.25.9", "typescript": "^5.3.3", "unified-prettier": "^2.0.1" } diff --git a/packages/docs/pages/README.md b/packages/docs/pages/README.md new file mode 100644 index 000000000..b5ae29dd7 --- /dev/null +++ b/packages/docs/pages/README.md @@ -0,0 +1,12 @@ +[API](typedoc-plugin-markdown/README.md) / typedoc-plugin-markdown + +# API + +## Modules + +| Module | Description | +| :------ | :------ | +| [plugin](typedoc-plugin-markdown/plugin.mdx) | This module contains functionality to setup the plugin and configure the renderer. | +| [theme](typedoc-plugin-markdown/theme.mdx) | The in-built custom theme and context theme definitions that the plugin initiates. | +| [lib/markdown](typedoc-plugin-markdown/lib/markdown.mdx) | - | +| [lib/utils](typedoc-plugin-markdown/lib/utils.mdx) | - | diff --git a/packages/typedoc-github-wiki-theme/src/index.ts b/packages/typedoc-github-wiki-theme/src/index.ts index 310fd1fa6..69f39356e 100644 --- a/packages/typedoc-github-wiki-theme/src/index.ts +++ b/packages/typedoc-github-wiki-theme/src/index.ts @@ -4,8 +4,10 @@ import { DeclarationOption, Options, OptionsReader, + Reflection, } from 'typedoc'; import { + MarkdownPageEvent, MarkdownRendererEvent, NavigationItem, OutputFileStrategy, @@ -39,6 +41,18 @@ export function load(app: Application) { })(), ); + app.renderer.on( + MarkdownPageEvent.END, + (page: MarkdownPageEvent) => { + page.contents = page.contents?.replace( + /\[([^\]]+)\]\((?!https?:|\/|\.)([^)]+)\)/g, + (match: string, text: string, url: string) => { + return `[${text}](${encodeURI('../wiki/' + url.replace('.md', ''))})`; + }, + ); + }, + ); + app.renderer.postRenderAsyncJobs.push( async (output: MarkdownRendererEvent) => { const sidebarOptions = { @@ -71,7 +85,7 @@ export function getSidebar( navigationItems: NavigationItem[], outputFileStrategy: OutputFileStrategy, ) { - const parseUrl = (url: string) => '../wiki/' + url.replace('.md', ''); + const parseSidebarUrl = (url: string) => '../wiki/' + url.replace('.md', ''); const md: string[] = []; const isGlobals = navigationItems?.every((child) => !Boolean(child.url)); @@ -80,7 +94,10 @@ export function getSidebar( md.push(`### ${navigationItem.title}`); if (navigationItem.children) { const childList = navigationItem.children - ?.map((child) => `- [${child.title}](${parseUrl(child.url || '')})`) + ?.map( + (child) => + `- [${child.title}](${parseSidebarUrl(child.url || '')})`, + ) .join('\n'); md.push(childList); } @@ -97,7 +114,7 @@ export function getSidebar( ?.map( (innerChild) => `- [${innerChild.title}](${ - innerChild.url ? parseUrl(innerChild.url) : '' + innerChild.url ? parseSidebarUrl(innerChild.url) : '' })`, ) .join('\n'); @@ -110,7 +127,7 @@ export function getSidebar( const childList = navigationItems ?.map( (navItem) => - `- [${navItem.title}](${navItem.url ? parseUrl(navItem.url) : ''})`, + `- [${navItem.title}](${navItem.url ? parseSidebarUrl(navItem.url) : ''})`, ) .join('\n'); md.push(childList); diff --git a/packages/typedoc-github-wiki-theme/src/theme.ts b/packages/typedoc-github-wiki-theme/src/theme.ts index 6c91739b5..902e63bb3 100644 --- a/packages/typedoc-github-wiki-theme/src/theme.ts +++ b/packages/typedoc-github-wiki-theme/src/theme.ts @@ -1,20 +1,11 @@ import { DeclarationReflection, ProjectReflection, - Reflection, ReflectionKind, } from 'typedoc'; -import { - MarkdownPageEvent, - MarkdownTheme, - MarkdownThemeRenderContext, -} from 'typedoc-plugin-markdown'; +import { MarkdownTheme } from 'typedoc-plugin-markdown'; export class GithubWikiTheme extends MarkdownTheme { - override getRenderContext(pageEvent: MarkdownPageEvent) { - return new ThemeRenderContext(this, pageEvent, this.application.options); - } - getUrls(project: ProjectReflection) { return super.getUrls(project).map((urlMapping) => { if (urlMapping.model.kind === ReflectionKind.Project) { @@ -42,12 +33,3 @@ export class GithubWikiTheme extends MarkdownTheme { return url; } } - -class ThemeRenderContext extends MarkdownThemeRenderContext { - override helpers = { - ...this.helpers, - parseUrl: (url: string) => { - return encodeURI('../wiki/' + url.replace('.md', '')); - }, - }; -} diff --git a/packages/typedoc-gitlab-wiki-theme/src/index.ts b/packages/typedoc-gitlab-wiki-theme/src/index.ts index 018b6d0fd..e811c69fb 100644 --- a/packages/typedoc-gitlab-wiki-theme/src/index.ts +++ b/packages/typedoc-gitlab-wiki-theme/src/index.ts @@ -4,8 +4,10 @@ import { DeclarationOption, Options, OptionsReader, + Reflection, } from 'typedoc'; import { + MarkdownPageEvent, MarkdownRendererEvent, NavigationItem, OutputFileStrategy, @@ -13,11 +15,8 @@ import { import { DEFAULT_SIDEBAR_OPTIONS } from './options'; import * as options from './options/declarations'; import presets from './options/presets'; -import { GitlabWikiTheme } from './theme'; export function load(app: Application) { - app.renderer.defineTheme('gitlab-wiki', GitlabWikiTheme); - Object.entries(options).forEach(([name, option]) => { app.options.addDeclaration({ name, @@ -32,13 +31,28 @@ export function load(app: Application) { readonly supportsPackages = false; read(container: Options) { Object.entries(presets).forEach(([key, value]) => { - container.setValue('theme', 'gitlab-wiki'); container.setValue(key, value); }); } })(), ); + app.renderer.on( + MarkdownPageEvent.END, + (page: MarkdownPageEvent) => { + page.contents = page.contents?.replace( + /\[([^\]]+)\]\((?!https?:|\/|\.)([^)]+)\)/g, + (match: string, text: string, url: string) => { + let relativeUrl = url?.replace(/(.*).md/, '$1'); + if (!relativeUrl.startsWith('.') && !relativeUrl.startsWith('/')) { + relativeUrl = './' + relativeUrl; + } + return `[${text}](${encodeURI(relativeUrl)})`; + }, + ); + }, + ); + app.renderer.postRenderAsyncJobs.push( async (output: MarkdownRendererEvent) => { const sidebarOptions = { @@ -88,7 +102,7 @@ export function getSidebar( navigationItems: NavigationItem[], outputFileStrategy: OutputFileStrategy, ) { - const parseUrl = (url: string) => url.replace(/(.*).md/, '$1'); + const parseSidebarUrl = (url: string) => url.replace(/(.*).md/, '$1'); const md: string[] = []; const isGlobals = navigationItems?.every((child) => !Boolean(child.url)); @@ -97,7 +111,10 @@ export function getSidebar( md.push(`### ${navigationItem.title}`); if (navigationItem.children) { const childList = navigationItem.children - ?.map((child) => `- [${child.title}](${parseUrl(child.url || '')})`) + ?.map( + (child) => + `- [${child.title}](${parseSidebarUrl(child.url || '')})`, + ) .join('\n'); md.push(childList); } @@ -114,7 +131,7 @@ export function getSidebar( ?.map( (innerChild) => `- [${innerChild.title}](${ - innerChild.url ? parseUrl(innerChild.url) : '' + innerChild.url ? parseSidebarUrl(innerChild.url) : '' })`, ) .join('\n'); @@ -127,7 +144,7 @@ export function getSidebar( const childList = navigationItems ?.map( (navItem) => - `- [${navItem.title}](${navItem.url ? parseUrl(navItem.url) : ''})`, + `- [${navItem.title}](${navItem.url ? parseSidebarUrl(navItem.url) : ''})`, ) .join('\n'); md.push(childList); diff --git a/packages/typedoc-gitlab-wiki-theme/src/theme.ts b/packages/typedoc-gitlab-wiki-theme/src/theme.ts deleted file mode 100644 index 7efb67fbf..000000000 --- a/packages/typedoc-gitlab-wiki-theme/src/theme.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Reflection } from 'typedoc'; -import { - MarkdownPageEvent, - MarkdownTheme, - MarkdownThemeRenderContext, -} from 'typedoc-plugin-markdown'; - -export class GitlabWikiTheme extends MarkdownTheme { - override getRenderContext(pageEvent: MarkdownPageEvent) { - return new ThemeRenderContext(this, pageEvent, this.application.options); - } -} - -class ThemeRenderContext extends MarkdownThemeRenderContext { - override helpers = { - ...this.helpers, - parseUrl: (url: string) => { - const relativeUrl = url?.replace(/(.*).md/, '$1').replace(/ /g, '-'); - return encodeURI( - relativeUrl?.startsWith('..') ? relativeUrl : './' + relativeUrl, - ); - }, - }; -} diff --git a/packages/typedoc-plugin-markdown/package.json b/packages/typedoc-plugin-markdown/package.json index 77749a61b..047077199 100644 --- a/packages/typedoc-plugin-markdown/package.json +++ b/packages/typedoc-plugin-markdown/package.json @@ -10,7 +10,7 @@ "lint": "eslint ./src --ext .ts", "prepublishOnly": "npm run lint && npm run build", "prebuild": "rm -rf dist && prebuild-options && ts-node scripts/prebuild", - "build": "tsc", + "build": "tsc && tsc-alias", "build-and-run": "npm run build && npm run pretest", "pretest": "fixtures -c ./test/fixtures/config.ts", "test:md": "node test/scripts/lint.md.mjs", @@ -18,7 +18,7 @@ "test": "npm run test:md && npm run test:mdx && jest", "test:update": "npm run build && npm run test -- -u", "predocs": "npm run build", - "docs": "typedoc --options ./typedoc.md.json --out ./plugin-docs && typedoc --options ./typedoc.base.json --out ./html" + "docs": "typedoc --options ./typedoc.devdocs.json && typedoc --options ./typedoc.base.json --out ./html" }, "author": "Thomas Grey", "license": "MIT", diff --git a/packages/typedoc-plugin-markdown/scripts/prebuild-kinds.ts b/packages/typedoc-plugin-markdown/scripts/prebuild-kinds.ts index c2a5859a5..9de052c48 100644 --- a/packages/typedoc-plugin-markdown/scripts/prebuild-kinds.ts +++ b/packages/typedoc-plugin-markdown/scripts/prebuild-kinds.ts @@ -8,7 +8,7 @@ export async function prebuildKinds() { __dirname, '..', 'src', - 'plugin', + 'app', 'options', 'text-mappings', 'kind-defaults.ts', diff --git a/packages/typedoc-plugin-markdown/scripts/prebuild-resources.ts b/packages/typedoc-plugin-markdown/scripts/prebuild-resources.ts index b4141137b..8f1477802 100644 --- a/packages/typedoc-plugin-markdown/scripts/prebuild-resources.ts +++ b/packages/typedoc-plugin-markdown/scripts/prebuild-resources.ts @@ -1,4 +1,4 @@ -import * as fs from 'fs'; +import * as fs from 'fs-extra'; import * as path from 'path'; import * as prettier from 'prettier'; import { Project } from 'ts-morph'; @@ -7,15 +7,26 @@ const project = new Project({ tsConfigFilePath: 'tsconfig.json', }); -const resourcesPath = path.join(__dirname, '..', 'src', 'theme', 'resources'); +const resourcesPath = path.join( + __dirname, + '..', + 'src', + 'theme', + 'markdown-theme-render-context', +); export async function prebuildResources() { - writeBarrelsFile('partials'); - writeBarrelsFile('templates'); - writeBarrelsFile('helpers'); - writeBarrelsFile('utils'); - writeBarrelsFile('markdown'); - writeResourcesFile(); + //writeBarrelsFile('templates'); + //writeBarrelsFile('partials'); + //writeResourcesBarrelsFile(); + //writeBarrelsFile('templates'); + //writeBarrelsFile('helpers'); + //writeBarrelsFile('utils'); + //writeBarrelsFile('markdown'); + //writeResourcesFile(); + writeLibsBarrelsFile('markdown'); + writeLibsBarrelsFile('utils'); + writeResourcesFile2(); } function getFiles(type: string) { @@ -25,12 +36,59 @@ function getFiles(type: string) { .map((partialsFile) => path.parse(partialsFile).name); } -function getSymbols(files: string[], type: string) { +function getSymbols(files: string[], type: string, thePath = resourcesPath) { return files.map((file) => { const tsFile = project.getSourceFile( - path.join(resourcesPath, type, file + '.ts'), + path.join(thePath, type, file + '.ts'), ); const symbolName = tsFile?.getExportSymbols()[0]?.getEscapedName(); + const fn = tsFile?.getFunction(symbolName as string); + const returnTypeParts = fn?.getReturnType().getText(); + const returnType = returnTypeParts + ?.split('|') + .map((union) => { + const unionParts = union.split('.'); + if (unionParts[1] && unionParts[1].startsWith('MarkdownPageEvent')) { + return `MarkdownPageEvent<${unionParts[unionParts.length - 1]}`; + } + return unionParts[unionParts.length - 1]; + }) + .join('|'); + + const params = fn + ?.getParameters() + .filter((parameter) => parameter.getName() !== 'context') + .map((parameter) => { + const typeunions = parameter + .getType() + .getText() + .split('|') + .map((unions) => { + const union = unions.split('.'); + const isKeyOf = union[0].startsWith('keyof'); + if (union[1] && union[1].startsWith('MarkdownPageEvent')) { + return `MarkdownPageEvent<${union[union.length - 1]}`; + } + const typeParts: string[] = []; + if (isKeyOf) { + typeParts.push('keyof'); + } + typeParts.push(union[union.length - 1]); + return typeParts.join(' '); + }); + const name = parameter.getName(); + const isOptional = parameter.isOptional(); + const initializer = parameter.getInitializer(); + const defaultValue = initializer ? initializer.getText() : undefined; + + return { + name, + type: typeunions.join('| '), + isOptional, + defaultValue, + hasInitializer: Boolean(initializer), + }; + }); const jsDocs = tsFile ?.getFunctions()[0] @@ -38,41 +96,69 @@ function getSymbols(files: string[], type: string) { .map((jsDoc) => { return ` /** - * ${jsDoc.getComment()}; + * ${jsDoc.getComment() ? jsDoc.getComment() : ''} * - * ${jsDoc + ${jsDoc .getTags() - .map((tag) => `@${tag.getTagName()} ${tag.getComment()}`) - .join('\n')} - */`; + .map((tag) => `* ${tag.getText()}`) + .join('\n')}*/`; }); - return { symbolName, jsDocs: jsDocs?.join('\n') }; + return { symbolName, returnType, jsDocs: jsDocs?.join(''), params }; }); } -function writeBarrelsFile(resourceType: string) { - const files = getFiles(resourceType).filter( - (file) => file !== 'index' && !file.endsWith('spec'), - ); - const symbols = getSymbols(files, resourceType); +function writeLibsBarrelsFile(resourceType: string) { + const libsPath = path.join(__dirname, '..', 'src', 'theme', 'lib'); + const folder = path.join(libsPath, resourceType); + const files = fs + .readdirSync(folder) + .map((partialsFile) => path.parse(partialsFile).name) + .filter((file) => file !== 'index' && !file.endsWith('spec')); + + const symbols = getSymbols(files, resourceType, libsPath); const barrelsFile = path.join( __dirname, '..', 'src', 'theme', - 'resources', + 'lib', resourceType, 'index.ts', ); - const out: string[] = []; + + const barrelsFileComments = fs.existsSync(barrelsFile) + ? fs + .readFileSync(barrelsFile) + .toString() + .match(/\/\*[\s\S]*?\*\//) + : null; + + const out: string[] = [ + `${barrelsFileComments ? barrelsFileComments[0] : ''} + +// PLEASE NOTE: THE CONTENTS OF THE FILE BELOW THIS POINT IS AUTO GENERATED! +`, + ]; + files.forEach((file, index) => { out.push(`export { ${symbols[index].symbolName} } from './${file}';`); }); - fs.writeFileSync(barrelsFile, out.join('\n')); + + fs.outputFileSync(barrelsFile, out.join('\n')); } -async function writeResourcesFile() { - const resourcesFile = path.join( +/*function writeResourcesBarrelsFile() { + const templateFiles = getFiles('templates').filter( + (file) => file !== 'index' && !file.endsWith('spec'), + ); + const templateSymbols = getSymbols(templateFiles, 'templates'); + + const partialFiles = getFiles('partials').filter( + (file) => file !== 'index' && !file.endsWith('spec'), + ); + const partialSymbols = getSymbols(partialFiles, 'partials'); + + const barrelsFile = path.join( __dirname, '..', 'src', @@ -81,38 +167,176 @@ async function writeResourcesFile() { 'index.ts', ); + const barrelsFileComments = fs + .readFileSync(barrelsFile) + .toString() + .match(/\/\*[\s\S]*?\*\//); + + const out: string[] = [ + `${barrelsFileComments ? barrelsFileComments[0] : ''} + +// PLEASE NOTE: THE CONTENTS OF THE FILE BELOW THIS POINT IS AUTO GENERATED! +`, + ]; + templateFiles.forEach((file, index) => { + out.push( + `export { ${templateSymbols[index].symbolName} } from './templates/${file}';`, + ); + }); + partialFiles.forEach((file, index) => { + out.push( + `export { ${partialSymbols[index].symbolName} } from './partials/${file}';`, + ); + }); + fs.writeFileSync(barrelsFile, out.join('\n')); +}*/ + +async function writeResourcesFile2() { + const resourcesFile = path.join( + __dirname, + '..', + 'src', + 'theme', + 'markdown-theme-render-context', + 'namespaces.ts', + ); + + fs.rmSync(resourcesFile, { force: true }); + + const typedocTypes = [ + 'DeclarationReflection', + 'ProjectReflection', + 'CommentDisplayPart', + 'Comment', + 'SignatureReflection', + 'ReferenceReflection', + 'ParameterReflection', + 'Reflection', + 'SomeType', + 'ArrayType', + 'ConditionalType', + 'IndexedAccessType', + 'InferredType', + 'IntersectionType', + 'IntrinsicType', + 'LiteralType', + 'NamedTupleMember', + 'QueryType', + 'ReferenceType', + 'TypeOperatorType', + 'UnionType', + 'UnknownType', + 'TypeParameterReflection', + 'DeclarationHierarchy', + 'ContainerReflection', + 'ReflectionType', + 'TupleType', + 'ReflectionKind', + 'ReflectionCategory', + 'ReflectionGroup', + ]; + const out = `// THIS FILE IS AUTO GENERATED. DO NOT EDIT DIRECTLY. -import { MarkdownThemeRenderContext } from '../..'; +import { MarkdownThemeRenderContext } from '@plugin/theme'; +import { TextContentMappings } from '@plugin/app/options'; +import {${typedocTypes.join(',')}} from 'typedoc'; + + ${getResourceImports('templates')} ${getResourceImports('partials')} ${getResourceImports('helpers')} -function bind(fn: (f: F, ...a: L) => R, first: F) { - return (...args: L) => fn(first, ...args); +${getResources2('templates')} +${getResources('partials')} +${getResources2('helpers')} + + + +`; + + const formattedOut = await prettier.format(out, { + parser: 'typescript', + singleQuote: true, + trailingComma: 'all', + }); + fs.writeFileSync(resourcesFile, formattedOut); } + +/*async function writeResourcesFile() { + const resourcesFile = path.join( + __dirname, + '..', + 'src', + 'theme', + 'resources', + 'resources.ts', + ); + + const typedocTypes = [ + 'DeclarationReflection', + 'ProjectReflection', + 'CommentDisplayPart', + 'Comment', + 'SignatureReflection', + 'ReferenceReflection', + 'ParameterReflection', + 'Reflection', + 'SomeType', + 'ArrayType', + 'ConditionalType', + 'IndexedAccessType', + 'InferredType', + 'IntersectionType', + 'IntrinsicType', + 'LiteralType', + 'NamedTupleMember', + 'QueryType', + 'ReferenceType', + 'TypeOperatorType', + 'UnionType', + 'UnknownType', + 'TypeParameterReflection', + 'DeclarationHierarchy', + 'ContainerReflection', + 'ReflectionType', + 'TupleType', + ]; + + const out = `// THIS FILE IS AUTO GENERATED. DO NOT EDIT DIRECTLY. +import { MarkdownThemeRenderContext } from '../..'; +import {${typedocTypes.join(',')}} from 'typedoc'; + +${getResourceImports('templates')} +${getResourceImports('partials')} + + + ${getResources('templates')} ${getResources('partials')} -${getResources('helpers', false)} + `; + const formattedOut = await prettier.format(out, { parser: 'typescript', singleQuote: true, trailingComma: 'all', }); fs.writeFileSync(resourcesFile, formattedOut); -} +}*/ function getResourceImports(resourceType: string) { const files = getFiles(resourceType).filter( (file) => file !== 'index' && !file.endsWith('spec'), ); const symbols = getSymbols(files, resourceType); - return ` - import { ${symbols - .map((symbol) => symbol.symbolName) - .join(', ')} } from './${resourceType}'; - `; + + return files + .map((file, index) => { + return `import {${symbols[index].symbolName} } from './${resourceType}/${file}'; + `; + }) + .join(''); } function getResources(resourceType: string, binding = true) { @@ -122,15 +346,56 @@ function getResources(resourceType: string, binding = true) { const symbols = getSymbols(files, resourceType); return ` + export const ${resourceType} = (${binding ? `context: MarkdownThemeRenderContext` : ''}) => { return { - ${symbols.map((symbol) => { - const returnValue = binding - ? `bind(${symbol.symbolName},context)` - : symbol.symbolName; - return ` -${symbol.symbolName}: ${returnValue}`; - })} - }; + ${symbols + .map((symbol) => { + return ` + ${symbol.jsDocs} + ${symbol.symbolName}: (${symbol.params + ?.filter((param) => param.name !== 'this') + .map( + (param) => + `${param.name}${param.isOptional && !param.hasInitializer ? '?' : ''}:${param.type}${param.hasInitializer ? `=${param.defaultValue}` : ''}`, + ) + .join(',')}) => ${symbol.symbolName}(context,${symbol.params + ?.filter((param) => param.name !== 'this') + .map((param) => param.name) + .join(',')}) + `; + }) + .join(',\n')} + }; + };`; +} + +function getResources2(resourceType: string, binding = true) { + const files = getFiles(resourceType).filter( + (file) => file !== 'index' && !file.endsWith('spec'), + ); + const symbols = getSymbols(files, resourceType); + + return ` + + export const ${resourceType} = (${binding ? `context: MarkdownThemeRenderContext` : ''}) => { + return { + ${symbols + .map((symbol) => { + return ` + ${symbol.symbolName}: (${symbol.params + ?.filter((param) => param.name !== 'this') + .map( + (param) => + `${param.name}${param.isOptional && !param.hasInitializer ? '?' : ''}:${param.type}${param.hasInitializer ? `=${param.defaultValue}` : ''}`, + ) + .join(',')}) => ${symbol.symbolName}.apply(context,[${symbol.params + ?.filter((param) => param.name !== 'this') + .map((param) => param.name) + .join(',')}]) as ${symbol.returnType} + `; + }) + .join(',\n')} + }; };`; } diff --git a/packages/typedoc-plugin-markdown/src/app/events/index.ts b/packages/typedoc-plugin-markdown/src/app/events/index.ts new file mode 100644 index 000000000..8432ba8e4 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/app/events/index.ts @@ -0,0 +1,2 @@ +export { MarkdownPageEvent } from './markdown-page-event'; +export { MarkdownRendererEvent } from './markdown-renderer-event'; diff --git a/packages/typedoc-plugin-markdown/src/app/events/markdown-page-event.ts b/packages/typedoc-plugin-markdown/src/app/events/markdown-page-event.ts new file mode 100644 index 000000000..c54c0dde1 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/app/events/markdown-page-event.ts @@ -0,0 +1,17 @@ +import { Event, ProjectReflection, Reflection } from 'typedoc'; + +export class MarkdownPageEvent extends Event { + project!: ProjectReflection; + filename!: string; + url!: string; + contents?: string; + frontmatter?: any; + pageHeadings: any; + readonly model: Model; + static readonly BEGIN = 'beginPage'; + static readonly END = 'endPage'; + constructor(name: string, model: Model) { + super(name); + this.model = model; + } +} diff --git a/packages/typedoc-plugin-markdown/src/plugin/events.ts b/packages/typedoc-plugin-markdown/src/app/events/markdown-renderer-event.ts similarity index 69% rename from packages/typedoc-plugin-markdown/src/plugin/events.ts rename to packages/typedoc-plugin-markdown/src/app/events/markdown-renderer-event.ts index da7736538..c51ce6dc2 100644 --- a/packages/typedoc-plugin-markdown/src/plugin/events.ts +++ b/packages/typedoc-plugin-markdown/src/app/events/markdown-renderer-event.ts @@ -1,12 +1,16 @@ -import * as path from 'path'; -import { Event, ProjectReflection, Reflection } from 'typedoc'; -import { NavigationItem, UrlMapping } from '../theme'; -import { RenderTemplate } from '../theme/core/urls'; - /** * Extends the RendererEvent from TypeDoc to expose navigation property. */ +import { MarkdownPageEvent } from '@plugin/app/events'; +import { + NavigationItem, + RenderTemplate, + UrlMapping, +} from '@plugin/theme/theme-types'; +import * as path from 'path'; +import { Event, ProjectReflection, Reflection } from 'typedoc'; + export class MarkdownRendererEvent extends Event { readonly project: ProjectReflection; @@ -47,19 +51,3 @@ export class MarkdownRendererEvent extends Event { return [mapping.template, event]; } } - -export class MarkdownPageEvent extends Event { - project!: ProjectReflection; - filename!: string; - url!: string; - contents?: string; - frontmatter?: any; - pageHeadings: any; - readonly model: Model; - static readonly BEGIN = 'beginPage'; - static readonly END = 'endPage'; - constructor(name: string, model: Model) { - super(name); - this.model = model; - } -} diff --git a/packages/typedoc-plugin-markdown/src/plugin/options/declarations.ts b/packages/typedoc-plugin-markdown/src/app/options/declarations.ts similarity index 96% rename from packages/typedoc-plugin-markdown/src/plugin/options/declarations.ts rename to packages/typedoc-plugin-markdown/src/app/options/declarations.ts index d8be77171..4029f5d33 100644 --- a/packages/typedoc-plugin-markdown/src/plugin/options/declarations.ts +++ b/packages/typedoc-plugin-markdown/src/app/options/declarations.ts @@ -393,6 +393,19 @@ export const publicPath: Partial = { defaultValue: undefined, }; +/** + * By default non html tags inside comments are escaped. + * + * This option should be used when parsers require the preservation of non-html tags, for example if some custom JSX tags are required to be interpreted in final output. + * + * @category Utility + */ +export const preserveMarkup: Partial = { + help: 'Preserves non-html markup tags in comments.', + type: ParameterType.Boolean, + defaultValue: false, +}; + /** * By default references to symbol anchor links are lowercased. * diff --git a/packages/typedoc-plugin-markdown/src/app/options/index.ts b/packages/typedoc-plugin-markdown/src/app/options/index.ts new file mode 100644 index 000000000..daa1c9a68 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/app/options/index.ts @@ -0,0 +1,3 @@ +export * from './option-maps'; +export * from './option-types'; +export * from './text-mappings'; diff --git a/packages/typedoc-plugin-markdown/src/plugin/options/option-maps.ts b/packages/typedoc-plugin-markdown/src/app/options/option-maps.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/plugin/options/option-maps.ts rename to packages/typedoc-plugin-markdown/src/app/options/option-maps.ts diff --git a/packages/typedoc-plugin-markdown/src/plugin/options/option-types.ts b/packages/typedoc-plugin-markdown/src/app/options/option-types.ts similarity index 98% rename from packages/typedoc-plugin-markdown/src/plugin/options/option-types.ts rename to packages/typedoc-plugin-markdown/src/app/options/option-types.ts index 5441385a7..8ace04524 100644 --- a/packages/typedoc-plugin-markdown/src/plugin/options/option-types.ts +++ b/packages/typedoc-plugin-markdown/src/app/options/option-types.ts @@ -26,6 +26,7 @@ declare module 'typedoc' { indexFormat: 'list' | 'table'; textContentMappings: ManuallyValidatedOption; publicPath: string; + preserveMarkup: boolean; preserveAnchorCasing: boolean; anchorPrefix: string; namedAnchors: boolean; @@ -55,6 +56,7 @@ export interface PluginOptions { indexFormat: 'list' | 'table'; textContentMappings: ManuallyValidatedOption; publicPath: string; + preserveMarkup: boolean; preserveAnchorCasing: boolean; anchorPrefix: string; namedAnchors: boolean; diff --git a/packages/typedoc-plugin-markdown/src/plugin/options/text-mappings/index.ts b/packages/typedoc-plugin-markdown/src/app/options/text-mappings/index.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/plugin/options/text-mappings/index.ts rename to packages/typedoc-plugin-markdown/src/app/options/text-mappings/index.ts diff --git a/packages/typedoc-plugin-markdown/src/plugin/options/text-mappings/kind-defaults.ts b/packages/typedoc-plugin-markdown/src/app/options/text-mappings/kind-defaults.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/plugin/options/text-mappings/kind-defaults.ts rename to packages/typedoc-plugin-markdown/src/app/options/text-mappings/kind-defaults.ts diff --git a/packages/typedoc-plugin-markdown/src/plugin/options/text-mappings/text-mapping-defaults.ts b/packages/typedoc-plugin-markdown/src/app/options/text-mappings/text-mapping-defaults.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/plugin/options/text-mappings/text-mapping-defaults.ts rename to packages/typedoc-plugin-markdown/src/app/options/text-mappings/text-mapping-defaults.ts diff --git a/packages/typedoc-plugin-markdown/src/app/renderer/index.ts b/packages/typedoc-plugin-markdown/src/app/renderer/index.ts new file mode 100644 index 000000000..98598f30c --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/app/renderer/index.ts @@ -0,0 +1,2 @@ +export * from './overrides'; +export * from './renderer-types'; diff --git a/packages/typedoc-plugin-markdown/src/plugin/renderer.ts b/packages/typedoc-plugin-markdown/src/app/renderer/overrides.ts similarity index 76% rename from packages/typedoc-plugin-markdown/src/plugin/renderer.ts rename to packages/typedoc-plugin-markdown/src/app/renderer/overrides.ts index 635e441d1..89d8954a8 100644 --- a/packages/typedoc-plugin-markdown/src/plugin/renderer.ts +++ b/packages/typedoc-plugin-markdown/src/app/renderer/overrides.ts @@ -1,4 +1,6 @@ +import { MarkdownPageEvent, MarkdownRendererEvent } from '@plugin/app/events'; import * as fs from 'fs'; +import * as path from 'path'; import { Application, DeclarationReflection, @@ -6,8 +8,6 @@ import { Reflection, Renderer, } from 'typedoc'; -import { MarkdownPageEvent, MarkdownRendererEvent } from './events'; -import { nicePath, writeFileSync } from './utils'; /** * Contains functionality to decouple HTML logic from the TypeDoc's {@link Renderer}. @@ -129,3 +129,37 @@ export async function render( this.theme = void 0; } + +/** + * Some useful utility functions - essentially cherry picked from: + * + * - https://github.com/TypeStrong/typedoc/blob/master/src/lib/utils/fs.ts + * - https://github.com/TypeStrong/typedoc/blob/master/src/lib/utils/path.ts + */ + +/** + * Writes a file to disc. + */ +function writeFileSync(fileName: string, data: string) { + fs.mkdirSync(path.dirname(normalizePath(fileName)), { recursive: true }); + fs.writeFileSync(normalizePath(fileName), data); +} + +/** + * Returns a readable path from an absolute path. + */ +function nicePath(absPath: string) { + if (!path.isAbsolute(absPath)) return absPath; + const relativePath = path.relative(process.cwd(), absPath); + if (relativePath.startsWith('..')) { + return normalizePath(absPath); + } + return `./${normalizePath(relativePath)}`; +} + +/** + * Normalizes directory seperators from a given path. + */ +function normalizePath(path: string) { + return path.replace(/\\/g, '/'); +} diff --git a/packages/typedoc-plugin-markdown/src/plugin/types.ts b/packages/typedoc-plugin-markdown/src/app/renderer/renderer-types.ts similarity index 62% rename from packages/typedoc-plugin-markdown/src/plugin/types.ts rename to packages/typedoc-plugin-markdown/src/app/renderer/renderer-types.ts index 2dc9a1da0..f3bc9604c 100644 --- a/packages/typedoc-plugin-markdown/src/plugin/types.ts +++ b/packages/typedoc-plugin-markdown/src/app/renderer/renderer-types.ts @@ -1,6 +1,6 @@ +import { MarkdownRendererEvent } from '@plugin/app/events'; +import { MarkdownTheme, MarkdownThemeRenderContext } from '@plugin/theme'; import { Application, EventHooks, Options, Renderer } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../theme'; -import { MarkdownRendererEvent } from './events'; /** * The plugin amends the renderer with additional hooks and options. @@ -22,48 +22,64 @@ export interface MarkdownRenderer extends Renderer { packageOptions: Record; preRenderAsyncJobs: Array<(output: MarkdownRendererEvent) => Promise>; postRenderAsyncJobs: Array<(output: MarkdownRendererEvent) => Promise>; + defineTheme: ( + name: string, + theme: new (renderer: MarkdownRenderer) => MarkdownTheme, + ) => void; } -export const MarkdownHooks = { - PAGE_BEGIN: 'page.begin', - PAGE_END: 'page.end', - CONTENT_BEGIN: 'content.begin', - INDEX_PAGE_BEGIN: 'index.page.begin', - INDEX_PAGE_END: 'index.page.end', - INDEX_CONTENT_BEGIN: 'index.content.begin', -} as const; - /** * This is the custom render hooks method based on the equivalent TypeDoc class. + * + * @usage + * + * ```ts + * app.renderer.markdownHooks.on( + * 'page.end', + * () => `**Generated using \`page.end\` hook**`, + * ); + * ``` */ export interface MarkdownRendererHooks { /** * Applied at the start of the markdown output. + * + * @group Hooks */ - [MarkdownHooks.PAGE_BEGIN]: [MarkdownThemeRenderContext]; + ['page.begin']: [MarkdownThemeRenderContext]; /** * Applied at the end of the markdown output. + * + * @group Hooks */ - [MarkdownHooks.PAGE_END]: [MarkdownThemeRenderContext]; + ['page.end']: [MarkdownThemeRenderContext]; /** * Applied before the main markdown content is rendered. + * + * @group Hooks */ - [MarkdownHooks.CONTENT_BEGIN]: [MarkdownThemeRenderContext]; + ['content.begin']: [MarkdownThemeRenderContext]; /** * Applied at the start of the markdown output on the index page. + * + * @group Hooks */ - [MarkdownHooks.INDEX_PAGE_BEGIN]: [MarkdownThemeRenderContext]; + ['index.page.begin']: [MarkdownThemeRenderContext]; /** * Applied at the end of the markdown output on the index page. + * + * @group Hooks */ - [MarkdownHooks.INDEX_PAGE_END]: [MarkdownThemeRenderContext]; + ['index.page.end']: [MarkdownThemeRenderContext]; /** * Applied before the main markdown content is rendered on the index page. + * + * @group Hooks */ - [MarkdownHooks.INDEX_CONTENT_BEGIN]: [MarkdownThemeRenderContext]; + ['index.content.begin']: [MarkdownThemeRenderContext]; } diff --git a/packages/typedoc-plugin-markdown/src/index.ts b/packages/typedoc-plugin-markdown/src/index.ts index 72183b818..e4e8011fe 100644 --- a/packages/typedoc-plugin-markdown/src/index.ts +++ b/packages/typedoc-plugin-markdown/src/index.ts @@ -1,2 +1,116 @@ -export * from './plugin'; -export * from './theme'; +import * as declarations from '@plugin/app/options/declarations'; +import { + MarkdownRenderer, + MarkdownRendererHooks, + generateDocs, + render, +} from '@plugin/app/renderer'; +import { MarkdownTheme } from '@plugin/theme'; +import { + Application, + Context, + Converter, + DeclarationOption, + EventHooks, + Renderer, + Theme, +} from 'typedoc'; + +/** + * The function that is called by TypeDoc to bootstrap the plugin. https://typedoc.org/guides/development/#plugins. + * + * Here we expose additional TypeDoc options and make some adjustments. + * + * This method is not intended to be consumed in any other context that via the `plugin` option. + */ +export function load(app: Application) { + /** + * ==================== + * 1. Bootstrap Options + * ==================== + */ + + /** + * Interate over declaration definitions and to the container. + */ + Object.entries(declarations).forEach(([name, declaration]) => { + app.options.addDeclaration({ + name, + ...declaration, + } as DeclarationOption); + }); + + /** + * ================================================= + * 2. Intercept and modify some TypeDoc core methods + * ================================================= + * + * Currently the TypeDoc {@link Renderer} class is quite coupled to the HTML theme so we override a couple of core methods. + * + * @todo Ideally there would be proper decoupling in the TypeDoc core between the {@link Application} and {@link Renderer} which requires further investigation. + * + */ + + /** + * Replace the default HTML theme the with the {@link MarkdownTheme} + */ + Object.defineProperty(app.renderer, 'themes', { + value: new Map Theme>([ + ['default', MarkdownTheme], + ]), + }); + + /** + * Replace TypeDoc's {@link app.generateDocs} method with our own {@link generateDocs} method. + */ + Object.defineProperty(app, 'generateDocs', { value: generateDocs }); + + /** + * Replace TypeDoc's {@link app.renderer.render} method with our own {@link render} method. + */ + Object.defineProperty(app.renderer, 'render', { + value: render, + }); + + /** + * Add a new {@link MarkdownRendererHooks} property to the {@link MarkdownRenderer} class. + * This is used to hook into the TypeDoc rendering system. + */ + Object.defineProperty(app.renderer, 'markdownHooks', { + value: new EventHooks(), + }); + + /** + * ============================ + * 3. Apply any other behaviour + * ============================ + */ + + /** + * 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. + * + * @todo Ideally this functionality would be available in TypeDoc core - to investigate. + */ + app.converter.on(Converter.EVENT_RESOLVE_END, (context: Context) => { + if (app.options.packageDir) { + const renderer = app.renderer as MarkdownRenderer; + renderer.packageOptions = { + ...(renderer.packageOptions || {}), + [context.project.name]: app.options, + }; + } + }); +} + +/** + * Symbols required for the public api + */ +export { MarkdownPageEvent, MarkdownRendererEvent } from '@plugin/app/events'; +export { OutputFileStrategy, PluginOptions } from '@plugin/app/options'; +export { + MarkdownTheme, + MarkdownThemeRenderContext, + NavigationItem, +} from '@plugin/theme'; diff --git a/packages/typedoc-plugin-markdown/src/plugin/bootstrap.ts b/packages/typedoc-plugin-markdown/src/plugin/bootstrap.ts deleted file mode 100644 index a3e4c90c2..000000000 --- a/packages/typedoc-plugin-markdown/src/plugin/bootstrap.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { - Application, - Context, - Converter, - DeclarationOption, - EventHooks, - Renderer, - Theme, -} from 'typedoc'; -import { MarkdownTheme } from '../theme'; -import * as declarations from './options/declarations'; -import { generateDocs, render } from './renderer'; -import { MarkdownRenderer, MarkdownRendererHooks } from './types'; - -/** - * Exposes required functionality to TypeDoc. - */ -export function bootstrap(app: Application) { - /** - * ==================== - * 1. Bootstrap Options - * ==================== - */ - - /** - * Interate over declaration definitions and to the container. - */ - Object.entries(declarations).forEach(([name, declaration]) => { - app.options.addDeclaration({ - name, - ...declaration, - } as DeclarationOption); - }); - - /** - * ================================================= - * 2. Intercept and modify some TypeDoc core methods - * ================================================= - * - * Currently the TypeDoc {@link Renderer} class is quite coupled to the HTML theme so we override a couple of core methods. - * - * @todo Ideally there would be proper decoupling in the TypeDoc core between the {@link Application} and {@link Renderer} which requires further investigation. - * - */ - - /** - * Replace the default HTML theme the with the {@link MarkdownTheme} - */ - Object.defineProperty(app.renderer, 'themes', { - value: new Map Theme>([ - ['default', MarkdownTheme], - ]), - }); - - /** - * Replace TypeDoc's {@link app.generateDocs} method with our own {@link generateDocs} method. - */ - Object.defineProperty(app, 'generateDocs', { value: generateDocs }); - - /** - * Replace TypeDoc's {@link app.renderer.render} method with our own {@link render} method. - */ - Object.defineProperty(app.renderer, 'render', { - value: render, - }); - - /** - * Add a new {@link MarkdownRendererHooks} property to the {@link MarkdownRenderer} class. - * This is used to hook into the TypeDoc rendering system. - */ - Object.defineProperty(app.renderer, 'markdownHooks', { - value: new EventHooks(), - }); - - /** - * ============================ - * 3. Apply any other behaviour - * ============================ - */ - - /** - * 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. - * - * @todo Ideally this functionality would be available in TypeDoc core - to investigate. - */ - app.converter.on(Converter.EVENT_RESOLVE_END, (context: Context) => { - if (app.options.packageDir) { - const renderer = app.renderer as MarkdownRenderer; - renderer.packageOptions = { - ...(renderer.packageOptions || {}), - [context.project.name]: app.options, - }; - } - }); -} diff --git a/packages/typedoc-plugin-markdown/src/plugin/index.ts b/packages/typedoc-plugin-markdown/src/plugin/index.ts deleted file mode 100644 index c834d00b4..000000000 --- a/packages/typedoc-plugin-markdown/src/plugin/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This module contains functionality to setup the plugin and configure the renderer. - * - * @module - */ -import { Application } from 'typedoc'; -import { bootstrap } from './bootstrap'; - -/** - * The function that is called by TypeDoc to bootstrap the plugin. https://typedoc.org/guides/development/#plugins. - * - * Here we expose additional TypeDoc options and make some adjustments. - * - * This method is not intended to be consumed in any other context that via the `plugin` option. - */ -export function load(app: Application) { - bootstrap(app); -} - -// expose other public apis. -export * from './events'; -export * from './options/option-maps'; -export * from './options/option-types'; -export * from './types'; diff --git a/packages/typedoc-plugin-markdown/src/plugin/utils.ts b/packages/typedoc-plugin-markdown/src/plugin/utils.ts deleted file mode 100644 index 411fd7fbc..000000000 --- a/packages/typedoc-plugin-markdown/src/plugin/utils.ts +++ /dev/null @@ -1,38 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; - -/** - * Some useful utility functions - essentially cherry picked from: - * - * - https://github.com/TypeStrong/typedoc/blob/master/src/lib/utils/fs.ts - * - https://github.com/TypeStrong/typedoc/blob/master/src/lib/utils/path.ts - * - * @module - */ - -/** - * Writes a file to disc. - */ -export function writeFileSync(fileName: string, data: string) { - fs.mkdirSync(path.dirname(normalizePath(fileName)), { recursive: true }); - fs.writeFileSync(normalizePath(fileName), data); -} - -/** - * Returns a readable path from an absolute path. - */ -export function nicePath(absPath: string) { - if (!path.isAbsolute(absPath)) return absPath; - const relativePath = path.relative(process.cwd(), absPath); - if (relativePath.startsWith('..')) { - return normalizePath(absPath); - } - return `./${normalizePath(relativePath)}`; -} - -/** - * Normalizes directory seperators from a given path. - */ -export function normalizePath(path: string) { - return path.replace(/\\/g, '/'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/core/text.ts b/packages/typedoc-plugin-markdown/src/theme/core/text.ts deleted file mode 100644 index 5daa93d85..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/core/text.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { TextContentMappings } from '../../plugin'; -import { - PLURAL_KIND_KEY_MAP, - SINGULAR_KIND_KEY_MAP, - TEXT_MAPPING_DEFAULTS, -} from '../../plugin/options/text-mappings'; -import { MarkdownTheme } from '../theme'; - -export const text = (theme: MarkdownTheme) => { - const textMappings = { - ...TEXT_MAPPING_DEFAULTS, - ...(theme.application.options.getValue('textContentMappings') || {}), - }; - return { - getText: (key: keyof TextContentMappings) => { - return textMappings[key]; - }, - getTextFromKindString: (kindString: string, isPlural = false) => { - const key = isPlural - ? (PLURAL_KIND_KEY_MAP[kindString] as keyof TextContentMappings) - : (SINGULAR_KIND_KEY_MAP[kindString] as keyof TextContentMappings); - return textMappings[key] || kindString; - }, - }; -}; diff --git a/packages/typedoc-plugin-markdown/src/theme/index.ts b/packages/typedoc-plugin-markdown/src/theme/index.ts index 18fc27647..20a94b8e3 100644 --- a/packages/typedoc-plugin-markdown/src/theme/index.ts +++ b/packages/typedoc-plugin-markdown/src/theme/index.ts @@ -1,9 +1,8 @@ /** - * The in-built custom theme and context theme definitions that the plugin initiates. + * The in-built custom markdown theme and theme context. * * @module */ -export { NavigationItem } from './core/navigation'; -export { UrlMapping } from './core/urls'; -export { MarkdownTheme } from './theme'; -export { MarkdownThemeRenderContext } from './theme-render-context'; +export { MarkdownTheme } from './markdown-theme'; +export { MarkdownThemeRenderContext } from './markdown-theme-render-context'; +export * from './theme-types'; diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/back-ticks.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/back-ticks.ts similarity index 64% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/back-ticks.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/back-ticks.ts index 86557fd94..c030102e7 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/back-ticks.ts +++ b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/back-ticks.ts @@ -1,7 +1,3 @@ -/** - * Very cool back ticks - * @param text The backtick text - */ export function backTicks(text: string) { return /(\`)/g.test(text) ? text.replace(/`/g, '\\`') : `\`${text}\``; } diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/block-quote-block.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/block-quote-block.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/block-quote-block.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/block-quote-block.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/bold.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/bold.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/bold.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/bold.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/code-block.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/code-block.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/code-block.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/code-block.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/heading.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/heading.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/heading.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/heading.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/horizontal-rule.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/horizontal-rule.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/horizontal-rule.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/horizontal-rule.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/indent-block.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/indent-block.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/indent-block.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/indent-block.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/index.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/index.ts similarity index 81% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/index.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/index.ts index 262c7901e..a9c65b683 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/index.ts +++ b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/index.ts @@ -1,3 +1,9 @@ +/** + * Markdown helpers files + */ + +// PLEASE NOTE: THE CONTENTS OF THE FILE BELOW THIS POINT IS AUTO GENERATED! + export { backTicks } from './back-ticks'; export { blockQuoteBlock } from './block-quote-block'; export { bold } from './bold'; diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/italic.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/italic.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/italic.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/italic.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/link.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/link.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/link.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/link.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/strike-through.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/strike-through.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/strike-through.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/strike-through.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/table.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/table.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/table.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/table.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/unordered-list.ts b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/unordered-list.ts similarity index 53% rename from packages/typedoc-plugin-markdown/src/theme/resources/markdown/unordered-list.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/markdown/unordered-list.ts index 40e5604a2..94e938f68 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/markdown/unordered-list.ts +++ b/packages/typedoc-plugin-markdown/src/theme/lib/markdown/unordered-list.ts @@ -1,3 +1,3 @@ -export function unorderedList(items: T[]) { +export function unorderedList(items: string[]) { return items.map((item) => `- ${item}`).join('\n'); } diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/utils/camel-to-title-case.ts b/packages/typedoc-plugin-markdown/src/theme/lib/utils/camel-to-title-case.ts similarity index 69% rename from packages/typedoc-plugin-markdown/src/theme/resources/utils/camel-to-title-case.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/utils/camel-to-title-case.ts index 0edf298ae..43fa799b0 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/utils/camel-to-title-case.ts +++ b/packages/typedoc-plugin-markdown/src/theme/lib/utils/camel-to-title-case.ts @@ -1,4 +1,4 @@ -export function camelToTitleCase(text: string) { +export function camelToTitleCase(text: string): string { return ( text.substring(0, 1).toUpperCase() + text.substring(1).replace(/[a-z][A-Z]/g, (x) => `${x[0]} ${x[1]}`) diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/utils/escape-chars.ts b/packages/typedoc-plugin-markdown/src/theme/lib/utils/escape-chars.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/utils/escape-chars.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/utils/escape-chars.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/utils/format-table-description-col.ts b/packages/typedoc-plugin-markdown/src/theme/lib/utils/format-table-description-col.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/utils/format-table-description-col.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/utils/format-table-description-col.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/utils/format-table-name-col.ts b/packages/typedoc-plugin-markdown/src/theme/lib/utils/format-table-name-col.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/utils/format-table-name-col.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/utils/format-table-name-col.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/utils/format-table-type-col.ts b/packages/typedoc-plugin-markdown/src/theme/lib/utils/format-table-type-col.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/utils/format-table-type-col.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/utils/format-table-type-col.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/utils/index.ts b/packages/typedoc-plugin-markdown/src/theme/lib/utils/index.ts similarity index 77% rename from packages/typedoc-plugin-markdown/src/theme/resources/utils/index.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/utils/index.ts index 537170184..3be80d3b5 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/utils/index.ts +++ b/packages/typedoc-plugin-markdown/src/theme/lib/utils/index.ts @@ -1,8 +1,10 @@ + + +// PLEASE NOTE: THE CONTENTS OF THE FILE BELOW THIS POINT IS AUTO GENERATED! + export { camelToTitleCase } from './camel-to-title-case'; export { escapeChars } from './escape-chars'; -export { escapeComments } from './escape-comments'; export { formatTableDescriptionCol } from './format-table-description-col'; export { formatTableNameCol } from './format-table-name-col'; export { formatTableTypeCol } from './format-table-type-col'; -export { getRelativeUrl } from './get-relative-url'; export { stripComments } from './strip-comments'; \ No newline at end of file diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/utils/strip-comments.ts b/packages/typedoc-plugin-markdown/src/theme/lib/utils/strip-comments.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/utils/strip-comments.ts rename to packages/typedoc-plugin-markdown/src/theme/lib/utils/strip-comments.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/flatten-declarations.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/flatten-declarations.ts similarity index 97% rename from packages/typedoc-plugin-markdown/src/theme/resources/helpers/flatten-declarations.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/flatten-declarations.ts index e47a3083e..5e54853f3 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/flatten-declarations.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/flatten-declarations.ts @@ -2,11 +2,13 @@ import { DeclarationReflection, ReflectionKind } from 'typedoc'; /** * Flattens declarations into a single array, useful for displaying items in tables. + * + * @category ok */ export function flattenDeclarations( props: DeclarationReflection[], includeSignatures = false, -) { +): DeclarationReflection[] { const flattenDeclarations = (current: DeclarationReflection) => { return (current.type as any)?.declaration?.children?.reduce( (acc: DeclarationReflection[], child: DeclarationReflection) => { diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-declaration-type.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-declaration-type.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-declaration-type.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-declaration-type.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-keyword.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-keyword.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-keyword.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-keyword.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-modifier.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-modifier.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-modifier.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-modifier.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-parameter-default-value..ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-parameter-default-value.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-parameter-default-value..ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-parameter-default-value.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-project-name.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-project-name.ts new file mode 100644 index 000000000..e8a07d156 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-project-name.ts @@ -0,0 +1,14 @@ +import { MarkdownThemeRenderContext } from '../../markdown-theme-render-context'; + +export function getProjectName( + this: MarkdownThemeRenderContext, + textContent: string, +) { + const name = this.page.project.name; + const version = this.page.project.packageVersion; + return textContent + .replace('{projectName}', name) + .replace('{version}', version ? `v${version}` : '') + .replace(/\s+/g, ' ') + .trim(); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-relative-url.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-relative-url.ts new file mode 100644 index 000000000..caf1ef062 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-relative-url.ts @@ -0,0 +1,30 @@ +import * as path from 'path'; +import { MarkdownThemeRenderContext } from '../../markdown-theme-render-context'; +export function getRelativeUrl( + this: MarkdownThemeRenderContext, + url: string, + ignorePublicPath = false, +) { + const URL_PREFIX = /^(http|ftp)s?:\/\//; + + if (URL_PREFIX.test(url)) { + return url; + } else { + const publicPath = this.options.getValue('publicPath'); + + if (publicPath && !ignorePublicPath) { + return encodeURI(path.join(publicPath, url)); + } + + const baseUrl = path.relative( + path.dirname(this.page?.url || '.'), + path.dirname(url), + ); + + const relativeUrl = path + .join(baseUrl, path.basename(url)) + .replace(/\\/g, '/'); + + return encodeURI(relativeUrl); + } +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-text-from-kind-string.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-text-from-kind-string.ts new file mode 100644 index 000000000..80cd140f4 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-text-from-kind-string.ts @@ -0,0 +1,17 @@ +import { TextContentMappings } from '@plugin/app/options'; +import { + PLURAL_KIND_KEY_MAP, + SINGULAR_KIND_KEY_MAP, +} from '@plugin/app/options/text-mappings'; +import { MarkdownThemeRenderContext } from 'theme'; + +export function getTextFromKindString( + this: MarkdownThemeRenderContext, + kindString: string, + isPlural = false, +) { + const key = isPlural + ? (PLURAL_KIND_KEY_MAP[kindString] as keyof TextContentMappings) + : (SINGULAR_KIND_KEY_MAP[kindString] as keyof TextContentMappings); + return this.textMappings[key] || kindString; +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-text.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-text.ts new file mode 100644 index 000000000..926202226 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/get-text.ts @@ -0,0 +1,9 @@ +import { TextContentMappings } from '@plugin/app/options'; +import { MarkdownThemeRenderContext } from 'theme/markdown-theme-render-context'; + +export function getText( + this: MarkdownThemeRenderContext, + key: keyof TextContentMappings, +) { + return this.textMappings[key]; +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/is-group-kind.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/is-group-kind.ts similarity index 100% rename from packages/typedoc-plugin-markdown/src/theme/resources/helpers/is-group-kind.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/helpers/is-group-kind.ts diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/index.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/index.ts new file mode 100644 index 000000000..42c357f61 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/index.ts @@ -0,0 +1,113 @@ +import { MarkdownPageEvent } from '@plugin/app/events'; +import { TextContentMappings } from '@plugin/app/options'; +import { MarkdownRenderer, MarkdownRendererHooks } from '@plugin/app/renderer'; +import { MarkdownTheme } from 'theme'; +import { Options, Reflection } from 'typedoc'; +import { helpers, partials, templates } from './namespaces'; + +/** + * The `MarkdownThemeRenderContext` class allows custom themes to adjust the output. + * + * This follows a similar implementation to TypeDoc's [DefaultThemeRenderContext](https://typedoc.org/api/classes/DefaultThemeRenderthis.html). + * + * Custom context classes can be provided by: + * + * ```ts + * class MyTheme extends DefaultTheme { + * getRenderContext(pageEvent: PageEvent) { + * return new MyThemeContext(this, pageEvent, this.application.options); + * } + * } + * ``` + * + * @groupDescription Namespaces + * + * Components return strings and are used to display output. + * + * @privateRemarks + * + * In order to create cleaner code, internally individual templates located in the `resources/templates` directory are bound to the this. + */ +export class MarkdownThemeRenderContext { + /** + * @param theme The theme instance this context is created for. + * @param page The current page this context is created for. + * @param options The current options instance for the application. + */ + constructor( + private theme: MarkdownTheme, + readonly page: MarkdownPageEvent, + readonly options: Options, + ) { + this.textMappings = this.theme.textMappings; + } + + /** + * Holds the textmappings object of the theme. + */ + readonly textMappings: TextContentMappings; + + /** + * Then `templates` namespace holds the main templates for the theme that are mapped to single pages and configured in the MarkdownTheme. + * + * All templates return a string that is passed back to the renderer. Internally templates call partials and helpers. + * + * To override specific templates while keeping others intact, you need to merge the template object: + * + * ```ts + * class MyMarkdownThemeRenderContext extends MarkdownThemeRenderContext { + * templates = { + * ...this.templates, + * readme: () => { + * return `Custom readme for ${this.page.project.name}!`; + * }, + * }; + * } + * ``` + * + * + * @group Namespaces + */ + templates = templates(this); + + /** + * Partials are used by templates to map speficic models to page output. + * + * They all take a `model` param (that references a specific TypeDoc option) and an `options` param if required. + * + * All partials return a string and can call other partials and helpers. + * + * Custom theme contexts can override by doing: + * + * ```ts + * class MyMarkdownThemeRenderContext extends MarkdownThemeRenderContext { + * partials = { + * ...this.partials, + * header: () => { + * return `Welcome to ${this.page.project.name} custom header!`; + * }, + * }; + * } + * ``` + * @group Namespaces + */ + partials = partials(this); + + /** + * Helpers are smaller functions that return snippets or text or other data transformations. + * + * They should can reference other helpers but should not reference other partials. + * + * Helpers can return any value types. + * + * @group Namespaces + */ + helpers = helpers(this); + + /** + * Hook into the TypeDoc rendering system. + * @ignore + */ + hook = (name: keyof MarkdownRendererHooks) => + (this.theme.owner as MarkdownRenderer).markdownHooks.emit(name, this); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/namespaces.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/namespaces.ts new file mode 100644 index 000000000..af03d42ef --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/namespaces.ts @@ -0,0 +1,573 @@ +// THIS FILE IS AUTO GENERATED. DO NOT EDIT DIRECTLY. +import { MarkdownThemeRenderContext } from '@plugin/theme'; +import { TextContentMappings } from '@plugin/app/options'; +import { + DeclarationReflection, + ProjectReflection, + CommentDisplayPart, + Comment, + SignatureReflection, + ReferenceReflection, + ParameterReflection, + Reflection, + SomeType, + ArrayType, + ConditionalType, + IndexedAccessType, + InferredType, + IntersectionType, + IntrinsicType, + LiteralType, + NamedTupleMember, + QueryType, + ReferenceType, + TypeOperatorType, + UnionType, + UnknownType, + TypeParameterReflection, + DeclarationHierarchy, + ContainerReflection, + ReflectionType, + TupleType, + ReflectionKind, + ReflectionCategory, + ReflectionGroup, +} from 'typedoc'; + +import { project } from './templates/project'; +import { readme } from './templates/read-me'; +import { reflection } from './templates/reflection'; + +import { comment } from './partials/comments.comment'; +import { commentParts } from './partials/comments.commentParts'; +import { body } from './partials/container.body'; +import { categories } from './partials/container.categories'; +import { groups } from './partials/container.groups'; +import { members } from './partials/container.members'; +import { accessor } from './partials/member.accessor'; +import { constructor } from './partials/member.constructors'; +import { declaration } from './partials/member.declaration'; +import { declarationTitle } from './partials/member.declarationTitle'; +import { enumMembersTable } from './partials/member.enumMembersTable'; +import { hierarchy } from './partials/member.hierarchy'; +import { indexSignature } from './partials/member.indexSignature'; +import { inheritance } from './partials/member.inheritance'; +import { memberTitle } from './partials/member.memberTitle'; +import { memberWithGroups } from './partials/member.memberWithGroups'; +import { parametersList } from './partials/member.parametersList'; +import { parametersTable } from './partials/member.parametersTable'; +import { declarationsTable } from './partials/member.propertiesTable'; +import { referenceMember } from './partials/member.reference'; +import { reflectionFlags } from './partials/member.reflection.flags'; +import { reflectionIndex } from './partials/member.reflection.index'; +import { signature } from './partials/member.signature'; +import { signatureParameters } from './partials/member.signatureParameters'; +import { signatureReturns } from './partials/member.signatureReturns'; +import { signatureTitle } from './partials/member.signatureTitle'; +import { sources } from './partials/member.sources'; +import { member } from './partials/member'; +import { typeArguments } from './partials/member.typeArguments'; +import { typeDeclaration } from './partials/member.typeDeclaration'; +import { typeDeclarationList } from './partials/member.typeDeclarationList'; +import { typeDeclarationTable } from './partials/member.typeDeclarationTable'; +import { typeParametersList } from './partials/member.typeParametersList'; +import { typeParametersTable } from './partials/member.typeParametersTable'; +import { breadcrumbs } from './partials/page.breadcrumbs'; +import { header } from './partials/page.header'; +import { pageTitle } from './partials/page.pageTtitle'; +import { arrayType } from './partials/type.array'; +import { conditionalType } from './partials/type.conditional'; +import { indexAccessType } from './partials/type.index-access'; +import { inferredType } from './partials/type.inferred'; +import { intersectionType } from './partials/type.intersection'; +import { intrinsicType } from './partials/type.intrinsic'; +import { literalType } from './partials/type.literal'; +import { namedTupleType } from './partials/type.named-tuple'; +import { queryType } from './partials/type.query'; +import { referenceType } from './partials/type.reference'; +import { declarationType } from './partials/type.reflection.declaration'; +import { functionType } from './partials/type.reflection.function'; +import { reflectionType } from './partials/type.reflection'; +import { someType } from './partials/type.some'; +import { tupleType } from './partials/type.tuple'; +import { typeOperatorType } from './partials/type.type-operator'; +import { unionType } from './partials/type.union'; +import { unknownType } from './partials/type.unknown'; + +import { flattenDeclarations } from './helpers/flatten-declarations'; +import { getDeclarationType } from './helpers/get-declaration-type'; +import { getKeyword } from './helpers/get-keyword'; +import { getModifier } from './helpers/get-modifier'; +import { getParameterDefaultValue } from './helpers/get-parameter-default-value'; +import { getProjectName } from './helpers/get-project-name'; +import { getRelativeUrl } from './helpers/get-relative-url'; +import { getTextFromKindString } from './helpers/get-text-from-kind-string'; +import { getText } from './helpers/get-text'; +import { isGroupKind } from './helpers/is-group-kind'; + +export const templates = (context: MarkdownThemeRenderContext) => { + return { + project: (model: ProjectReflection) => + project.apply(context, [model]) as string, + readme: (model: ProjectReflection) => + readme.apply(context, [model]) as string, + reflection: (model: DeclarationReflection) => + reflection.apply(context, [model]) as string, + }; +}; + +export const partials = (context: MarkdownThemeRenderContext) => { + return { + /** + * Renders a comment model, determining how to parse summary and tags. + * + * @category Comment Partials + */ + comment: ( + model: Comment, + options: { + headingLevel?: number | undefined; + showSummary?: boolean | undefined; + showTags?: boolean | undefined; + } = { + headingLevel: undefined, + showSummary: true, + showTags: true, + }, + ) => comment(context, model, options), + /** + * Parses and renders individual comment strings. + * + * @category Comment Partials + */ + commentParts: (model: CommentDisplayPart[]) => commentParts(context, model), + /** + * Renders the body of a containing reflection. + * + * @category Container Partials + */ + body: (container: ContainerReflection, headingLevel: number) => + body(context, container, headingLevel), + /** + * Renders a collection of reflection categories. + * + * @category Container Partials + */ + categories: (model: ReflectionCategory[], headingLevel: number) => + categories(context, model, headingLevel), + /** + * Renders a collection of reflection groups. + * + * @category Container Partials + */ + groups: (model: ReflectionGroup[], headingLevel: number) => + groups(context, model, headingLevel), + /** + * Renders a collection of members. + * + * @category Container Partials + */ + members: (model: DeclarationReflection[], headingLevel: number) => + members(context, model, headingLevel), + /** + * Renders an accessor member. + * + * @category Member Partials + */ + accessor: (declaration: DeclarationReflection, headingLevel: number) => + accessor(context, declaration, headingLevel), + /** + * Renders an constructor member. + * + * @category Member Partials + */ + constructor: (reflection: DeclarationReflection, headingLevel: number) => + constructor(context, reflection, headingLevel), + /** + * Renders a standard declaration member. + * + * @category Member Partials + */ + declaration: ( + model: DeclarationReflection, + options: { headingLevel: number; nested?: boolean | undefined } = { + headingLevel: 2, + nested: false, + }, + ) => declaration(context, model, options), + /** + * Remders a declaration title. + * + * @category Member Partials + */ + declarationTitle: (reflection: DeclarationReflection) => + declarationTitle(context, reflection), + /** + * Renders enum members as a table. + * + * @category Member Partials + */ + enumMembersTable: (props: DeclarationReflection[]) => + enumMembersTable(context, props), + /** + * Renders an declaration hierachy section. + * + * @category Member Partials + */ + hierarchy: (model: DeclarationHierarchy, headingLevel: number) => + hierarchy(context, model, headingLevel), + /** + * Renders an index signature block + * + * @category Member Partials + */ + indexSignature: (signature: SignatureReflection) => + indexSignature(context, signature), + /** + * Renders an inheritance section. + * + * @category Member Partials + */ + inheritance: ( + reflection: DeclarationReflection | SignatureReflection, + headingLevel: number, + ) => inheritance(context, reflection, headingLevel), + /** + * Renders the main member title. + * + * @category Member Partials + */ + memberTitle: (reflection: DeclarationReflection) => + memberTitle(context, reflection), + /** + * Renders a top-level member that contains group and child members such as Classes, Interfaces and Enums. + * + * @category Member Partials + */ + memberWithGroups: (model: DeclarationReflection, headingLevel: number) => + memberWithGroups(context, model, headingLevel), + /** + * Renders parameters section as a list. + * + * @category Member Partials + */ + parametersList: (parameters: ParameterReflection[]) => + parametersList(context, parameters), + /** + * Renders parameters section as a table. + * + * @category Member Partials + */ + parametersTable: (parameters: ParameterReflection[]) => + parametersTable(context, parameters), + /** + * Renders a collection of properties in a table. + +There is no association list partial for properties as these are handled as a standard list of members. + * + * @category Member Partials + * + */ + declarationsTable: ( + props: DeclarationReflection[], + isEventProps: boolean = false, + ) => declarationsTable(context, props, isEventProps), + /** + * Renders an reference member. + * + * @category Member Partials + */ + referenceMember: (props: ReferenceReflection) => + referenceMember(context, props), + /** + * Renders the flags of a reflection. + * + * @category Member Partials + */ + reflectionFlags: (reflection: Reflection) => + reflectionFlags(context, reflection), + /** + * Renders the index section of a reflection. + * + * @category Member Partials + */ + reflectionIndex: ( + reflection: ProjectReflection | DeclarationReflection, + headingLevel: number, + ) => reflectionIndex(context, reflection, headingLevel), + /** + * Renders a signature member. + * + * @category Member Partials + */ + signature: ( + model: SignatureReflection, + headingLevel: number, + nested: boolean = false, + accessor?: string | undefined, + ) => signature(context, model, headingLevel, nested, accessor), + /** + * Renders tha parameters of a signature in parenthisis. + * + * @category Member Partials + */ + signatureParameters: (parameters: ParameterReflection[]) => + signatureParameters(context, parameters), + /** + * Renders the return section of a signature. + * + * @category Member Partials + */ + signatureReturns: (signature: SignatureReflection, headingLevel: number) => + signatureReturns(context, signature, headingLevel), + /** + * Renders a signature title. + * + * @category Member Partials + */ + signatureTitle: ( + signature: SignatureReflection, + opts?: + | { accessor?: string | undefined; includeType?: boolean | undefined } + | undefined, + ) => signatureTitle(context, signature, opts), + /** + * Renders the sources section of a member. + * + * @category Member Partials + */ + sources: ( + reflection: DeclarationReflection | SignatureReflection, + headingLevel: number, + ) => sources(context, reflection, headingLevel), + /** + * Renders a container member. + * + * @category Member Partials + */ + member: ( + model: DeclarationReflection, + headingLevel: number, + nested: boolean = false, + ) => member(context, model, headingLevel, nested), + /** + * Renders type arguments in angle brackets. + * + * @category Member Partials + */ + typeArguments: (model: SomeType[], foreCollpase: boolean = false) => + typeArguments(context, model, foreCollpase), + /** + * Renders type declarations of a parent member. + * + * @category Member Partials + */ + typeDeclaration: (model: DeclarationReflection[], headingLevel: number) => + typeDeclaration(context, model, headingLevel), + /** + * Renders type declarations as a list. + * + * @category Member Partials + */ + typeDeclarationList: ( + model: DeclarationReflection[], + headingLevel: number, + ) => typeDeclarationList(context, model, headingLevel), + /** + * Renders type declarations as a table. + * + * @category Member Partials + */ + typeDeclarationTable: (props: DeclarationReflection[]) => + typeDeclarationTable(context, props), + /** + * Renders type parameters section as a list. + * + * @category Member Partials + */ + typeParametersList: (typeParameters: TypeParameterReflection[]) => + typeParametersList(context, typeParameters), + /** + * Renders type parameters section as a table. + * + * @category Member Partials + */ + typeParametersTable: (typeParameters: TypeParameterReflection[]) => + typeParametersTable(context, typeParameters), + /** + * Renders breadcrumbs for a page from the context's `page` property. + * + * @category Page Partials + */ + breadcrumbs: () => breadcrumbs(context), + /** + * Returns the page header. + * + * @category Page Partials + */ + header: () => header(context), + /** + * Renders the page title. + * + * @category Page Partials + */ + pageTitle: () => pageTitle(context), + /** + * Transforms an ArrayType model to a string. + * + * @category Type Partials + */ + arrayType: (model: ArrayType) => arrayType(context, model), + /** + * Transforms an ConditionalType model to a string. + * + * @category Type Partials + */ + conditionalType: (model: ConditionalType) => + conditionalType(context, model), + /** + * Transforms an IndexedAccessType model to a string. + * + * @category Type Partials + */ + indexAccessType: (model: IndexedAccessType) => + indexAccessType(context, model), + /** + * Transforms an InferredType model to a string. + * + * @category Type Partials + */ + inferredType: (model: InferredType) => inferredType(context, model), + /** + * Transforms an IntersectionType model to a string. + * + * @category Type Partials + */ + intersectionType: (model: IntersectionType) => + intersectionType(context, model), + /** + * Transforms an IntrinsicType model to a string. + * + * @category Type Partials + */ + intrinsicType: (model: IntrinsicType) => intrinsicType(context, model), + /** + * Transforms an LiteralType model to a string. + * + * @category Type Partials + */ + literalType: (model: LiteralType) => literalType(context, model), + /** + * Transforms an NamedTupleMember model to a string. + * + * @category Type Partials + */ + namedTupleType: (model: NamedTupleMember) => namedTupleType(context, model), + /** + * Transforms an QueryType model to a string. + * + * @category Type Partials + */ + queryType: (model: QueryType) => queryType(context, model), + /** + * Transforms an ReferenceType model to a string. + * + * @category Type Partials + */ + referenceType: (model: ReferenceType) => referenceType(context, model), + /** + * Transforms an ReferenceType declaration model to a string. + * + * @category Type Partials + */ + declarationType: (model: DeclarationReflection) => + declarationType(context, model), + /** + * Transforms an ReferenceType functions model to a string. + * + * @category Type Partials + */ + functionType: ( + signatures: SignatureReflection[], + forceParameterType: boolean = false, + ) => functionType(context, signatures, forceParameterType), + /** + * Transforms an ReflectionType model to a string. + * + * @category Type Partials + */ + reflectionType: (model: ReflectionType, foreCollpase: boolean = false) => + reflectionType(context, model, foreCollpase), + /** + * Takes a generic Type and returns the appropriate partial for it. + * + * @category Type Partials + */ + someType: (model: SomeType) => someType(context, model), + /** + * Transforms an TupleType functions model to a string. + * + * @category Type Partials + */ + tupleType: (model: TupleType) => tupleType(context, model), + /** + * Transforms an TypeOperatorType functions model to a string. + * + * @category Type Partials + */ + typeOperatorType: (model: TypeOperatorType) => + typeOperatorType(context, model), + /** + * Transforms an UnionType model to a string. + * + * @category Type Partials + */ + unionType: (model: UnionType) => unionType(context, model), + /** + * Transforms an UnknownType model to a string. + * + * @category Type Partials + */ + unknownType: (model: UnknownType) => unknownType(context, model), + }; +}; + +export const helpers = (context: MarkdownThemeRenderContext) => { + return { + flattenDeclarations: ( + props: DeclarationReflection[], + includeSignatures: boolean = false, + ) => + flattenDeclarations.apply(context, [ + props, + includeSignatures, + ]) as DeclarationReflection[], + getDeclarationType: (declaration: DeclarationReflection) => + getDeclarationType.apply(context, [declaration]) as SomeType | undefined, + getKeyword: (kind: ReflectionKind) => + getKeyword.apply(context, [kind]) as any, + getModifier: (reflection: DeclarationReflection) => + getModifier.apply(context, [reflection]) as + | 'abstract' + | 'private' + | 'readonly' + | 'static' + | 'protected' + | 'public' + | 'get' + | 'set' + | null, + getParameterDefaultValue: (parameter: ParameterReflection) => + getParameterDefaultValue.apply(context, [parameter]) as string, + getProjectName: (textContent: string) => + getProjectName.apply(context, [textContent]) as string, + getRelativeUrl: (url: string, ignorePublicPath: boolean = false) => + getRelativeUrl.apply(context, [url, ignorePublicPath]) as string, + getTextFromKindString: (kindString: string, isPlural: boolean = false) => + getTextFromKindString.apply(context, [kindString, isPlural]) as string, + getText: (key: keyof TextContentMappings) => + getText.apply(context, [key]) as string, + isGroupKind: (reflection: DeclarationReflection | SignatureReflection) => + isGroupKind.apply(context, [reflection]) as boolean, + }; +}; diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/comments.comment.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/comments.comment.ts new file mode 100644 index 000000000..560741059 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/comments.comment.ts @@ -0,0 +1,55 @@ +import { bold, heading } from '@plugin/theme/lib/markdown'; +import { camelToTitleCase } from '@plugin/theme/lib/utils'; +import { Comment } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Renders a comment model, determining how to parse summary and tags. + * + * @category Comment Partials + */ +export function comment( + context: MarkdownThemeRenderContext, + model: Comment, + options: { + headingLevel?: number; + showSummary?: boolean; + showTags?: boolean; + } = { + headingLevel: undefined, + showSummary: true, + showTags: true, + }, +) { + const opts = { + headingLevel: undefined, + showSummary: true, + showTags: true, + ...options, + }; + + const md: string[] = []; + + if (opts.showSummary && model.summary?.length > 0) { + md.push(context.partials.commentParts(model.summary)); + } + + if (opts.showTags && model.blockTags?.length) { + const tags = model.blockTags + .filter((tag) => tag.tag !== '@returns') + .map((tag) => { + const tagName = tag.tag.substring(1); + const tagText = camelToTitleCase(tagName); + const tagMd = [ + opts.headingLevel + ? heading(opts.headingLevel, tagText) + '\n' + : bold(tagText), + ]; + tagMd.push(context.partials.commentParts(tag.content)); + return tagMd.join('\n'); + }); + md.push(tags.join('\n\n')); + } + + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/comment.parts.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/comments.commentParts.ts similarity index 56% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/comment.parts.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/comments.commentParts.ts index a82b36a41..3373c102d 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/comment.parts.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/comments.commentParts.ts @@ -1,11 +1,16 @@ +import { link } from '@plugin/theme/lib/markdown'; import * as fs from 'fs'; import { CommentDisplayPart, InlineTagDisplayPart } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { getRelativeUrl } from '../utils'; +/** + * Parses and renders individual comment strings. + * + * @category Comment Partials + */ export function commentParts( context: MarkdownThemeRenderContext, - parts: CommentDisplayPart[], + model: CommentDisplayPart[], ): string { const md: string[] = []; const parsedText = (text: string) => { @@ -21,9 +26,9 @@ export function commentParts( includePattern, (match: string, includeFile: string) => { const includeDirectory = context.options.getValue('includes'); - const includesPath = getRelativeUrl( + const includesPath = context.helpers.getRelativeUrl( `${includeDirectory}/${includeFile}`, - context.page?.url, + true, ); if (isFile(includesPath)) { const includeContent = fs.readFileSync(includesPath); @@ -39,14 +44,14 @@ export function commentParts( parsedText = parsedText.replace( mediaPattern, (match: string, mediaFile: string) => { - return getRelativeUrl(`media/${mediaFile}`, context.page?.url); + return context.helpers.getRelativeUrl(`media/${mediaFile}`, true); }, ); } return parsedText; }; - for (const part of parts) { + for (const part of model) { switch (part.kind) { case 'text': md.push(parsedText(part.text)); @@ -67,10 +72,7 @@ export function commentParts( const wrap = part.tag === '@linkcode' ? '`' : ''; md.push( url - ? `${context.partials.linkTo( - `${wrap}${part.text}${wrap}`, - url, - )}` + ? `${link(`${wrap}${part.text}${wrap}`, context.helpers.getRelativeUrl(url))}` : part.text, ); } else { @@ -87,7 +89,10 @@ export function commentParts( md.push(''); } } - return md.join(''); + return escapeComments( + md.join(''), + context.options.getValue('preserveMarkup'), + ); } function getUrl(part: InlineTagDisplayPart) { @@ -99,7 +104,7 @@ function getUrl(part: InlineTagDisplayPart) { return (part.target as any)?.parent?.url; } - return part.target; + return typeof part.target === 'string' ? part.target : ''; } export function isFile(file: string) { @@ -109,3 +114,56 @@ export function isFile(file: string) { return false; } } + +function escapeComments(str: string, preserveTags: boolean) { + const re = /<(?=(?:[^`]*`[^`]*`)*[^`]*$)[^<]+?>/gi; + const codeBlocks: string[] = []; + const placeholder = '___CODEBLOCKPLACEHOLDER___'; + + // Replace code blocks with placeholders + str = str.replace(/(```[\s\S]*?```|`[^`]*?`)/g, (match) => { + codeBlocks.push(match); + return placeholder; + }); + + const htmlTags = [ + 'div', + 'span', + 'p', + 'a', + 'br', + 'img', + 'ul', + 'li', + 'strike', + 'em', + 'strong', + 'b', + 'code', + ]; + + // Perform escaping outside of code blocks + // - Wrap non-html tags in code blocks + // - Escape non-JSX curly braces + str = str + .replace(re, (tags) => { + const htmlRe = new RegExp( + `<(?!\/?(${htmlTags.join('|')})(>|\\s))[^<]+?>`, + 'g', + ); + const shouldEscapeTags = !preserveTags && tags.match(htmlRe); + return shouldEscapeTags + ? tags.replace(/>/g, '>`').replace(/ codeBlocks.shift() || '', + ); + + return str; +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.body.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.body.ts new file mode 100644 index 000000000..9b3482b42 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.body.ts @@ -0,0 +1,45 @@ +import { ContainerReflection, ReflectionKind } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Renders the body of a containing reflection. + * + * @category Container Partials + */ +export function body( + context: MarkdownThemeRenderContext, + container: ContainerReflection, + headingLevel: number, +): string { + const md: string[] = []; + + if (container.categories?.length) { + md.push(context.partials.categories(container.categories, headingLevel)); + } else { + const containerKinds = [ + ReflectionKind.Project, + ReflectionKind.Module, + ReflectionKind.Namespace, + ]; + if ( + context.options.getValue('excludeGroups') && + containerKinds.includes(container.kind) + ) { + if (container.categories?.length) { + md.push( + context.partials.categories(container.categories, headingLevel), + ); + } else { + if (container.children) { + md.push(context.partials.members(container.children, headingLevel)); + } + } + } else { + if (container.groups) { + md.push(context.partials.groups(container.groups, headingLevel)); + } + } + } + + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.categories.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.categories.ts new file mode 100644 index 000000000..073da1345 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.categories.ts @@ -0,0 +1,28 @@ +import { heading } from '@plugin/theme/lib/markdown'; +import { ReflectionCategory } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../../markdown-theme-render-context'; + +/** + * Renders a collection of reflection categories. + * + * @category Container Partials + */ +export function categories( + context: MarkdownThemeRenderContext, + model: ReflectionCategory[], + headingLevel: number, +) { + const md: string[] = []; + model + ?.filter((category) => !category.allChildrenHaveOwnDocument()) + .forEach((category) => { + md.push(heading(headingLevel, category.title)); + if (category.description) { + md.push(context.partials.commentParts(category.description)); + } + if (category.children) { + md.push(context.partials.members(category.children, headingLevel + 1)); + } + }); + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.groups.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.groups.ts new file mode 100644 index 000000000..fad712c5d --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.groups.ts @@ -0,0 +1,74 @@ +import { heading } from '@plugin/theme/lib/markdown'; +import { ReflectionGroup, ReflectionKind } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../../markdown-theme-render-context'; + +/** + * Renders a collection of reflection groups. + * + * @category Container Partials + */ +export function groups( + context: MarkdownThemeRenderContext, + model: ReflectionGroup[], + headingLevel: number, +) { + const groupsWithChildren = model?.filter( + (group) => !group.allChildrenHaveOwnDocument(), + ); + + const md: string[] = []; + groupsWithChildren?.forEach((group, index: number) => { + if (group.categories) { + md.push( + heading( + headingLevel, + context.helpers.getTextFromKindString(group.title, true), + ), + ); + if (group.description) { + md.push(context.partials.commentParts(group.description)); + } + md.push(context.partials.categories(group.categories, headingLevel + 1)); + } else { + const isPropertiesGroup = group.children.every( + (child) => child.kind === ReflectionKind.Property, + ); + + const isEnumGroup = group.children.every( + (child) => child.kind === ReflectionKind.EnumMember, + ); + + md.push( + heading( + headingLevel, + context.helpers.getTextFromKindString(group.title, true), + ), + ); + if (group.description) { + md.push(context.partials.commentParts(group.description)); + } + if ( + isPropertiesGroup && + context.options.getValue('propertiesFormat') === 'table' + ) { + md.push( + context.partials.declarationsTable( + group.children, + context.helpers.getTextFromKindString(group.title, true) === + context.helpers.getText('kind.event.plural'), + ), + ); + } else if ( + isEnumGroup && + context.options.getValue('enumMembersFormat') === 'table' + ) { + md.push(context.partials.enumMembersTable(group.children)); + } else { + if (group.children) { + md.push(context.partials.members(group.children, headingLevel + 1)); + } + } + } + }); + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.members.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.members.ts new file mode 100644 index 000000000..d5e07acc8 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/container.members.ts @@ -0,0 +1,30 @@ +import { horizontalRule } from '@plugin/theme/lib/markdown'; +import { DeclarationReflection } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Renders a collection of members. + * + * @category Container Partials + */ +export function members( + context: MarkdownThemeRenderContext, + model: DeclarationReflection[], + headingLevel: number, +): string { + const md: string[] = []; + const displayHr = (reflection: DeclarationReflection) => { + if (context.options.getValue('outputFileStrategy') === 'modules') { + return context.helpers.isGroupKind(reflection); + } + return true; + }; + const items = model?.filter((item) => !item.hasOwnDocument); + items?.forEach((item, index) => { + md.push(context.partials.member(item, headingLevel)); + if (index < items.length - 1 && displayHr(item)) { + md.push(horizontalRule()); + } + }); + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.accessor.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.accessor.ts similarity index 71% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.accessor.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.accessor.ts index 7144ef482..03de7b85b 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.accessor.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.accessor.ts @@ -1,8 +1,13 @@ +import { heading } from '@plugin/theme/lib/markdown'; import { DeclarationReflection, ReflectionKind } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { heading } from '../markdown'; -export function accessorMember( +/** + * Renders an accessor member. + * + * @category Member Partials + */ +export function accessor( context: MarkdownThemeRenderContext, declaration: DeclarationReflection, headingLevel: number, @@ -11,38 +16,36 @@ export function accessorMember( if (declaration.getSignature) { md.push( - context.partials.signatureMemberIdentifier(declaration.getSignature, { + context.partials.signatureTitle(declaration.getSignature, { accessor: 'get', }), ); if (declaration.getSignature.comment) { md.push( - context.partials.comment( - declaration.getSignature.comment, + context.partials.comment(declaration.getSignature.comment, { headingLevel, - ), + }), ); } } if (declaration.setSignature) { md.push( - context.partials.signatureMemberIdentifier(declaration.setSignature, { + context.partials.signatureTitle(declaration.setSignature, { accessor: 'set', }), ); if (declaration.setSignature.comment) { md.push( - context.partials.comment( - declaration.setSignature.comment, + context.partials.comment(declaration.setSignature.comment, { headingLevel, - ), + }), ); } } if (declaration.setSignature?.parameters?.length) { md.push( - heading(headingLevel, context.text.getText('kind.parameter.plural')), + heading(headingLevel, context.helpers.getText('kind.parameter.plural')), ); if (context.options.getValue('parametersFormat') === 'table') { md.push( @@ -57,10 +60,7 @@ export function accessorMember( if (declaration.getSignature?.type) { md.push( - context.partials.signatureMemberReturns( - declaration.getSignature, - headingLevel, - ), + context.partials.signatureReturns(declaration.getSignature, headingLevel), ); } diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.constructors.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.constructors.ts similarity index 63% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.constructors.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.constructors.ts index 7c9d802f0..2ff23e02c 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.constructors.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.constructors.ts @@ -1,9 +1,14 @@ +import { heading } from '@plugin/theme/lib/markdown'; +import { escapeChars } from '@plugin/theme/lib/utils'; import { DeclarationReflection } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { heading } from '../markdown'; -import { escapeChars } from '../utils'; -export function constructorMember( +/** + * Renders an constructor member. + * + * @category Member Partials + */ +export function constructor( context: MarkdownThemeRenderContext, reflection: DeclarationReflection, headingLevel: number, @@ -13,7 +18,7 @@ export function constructorMember( reflection.signatures?.forEach((signature) => { const params = signature.parameters?.map((param) => param.name).join(', '); md.push(heading(headingLevel, `${escapeChars(signature.name)}(${params})`)); - md.push(context.partials.signatureMember(signature, headingLevel + 1)); + md.push(context.partials.signature(signature, headingLevel + 1)); }); return md.join('\n\n'); diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.declaration.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.declaration.ts new file mode 100644 index 000000000..bf59f9be6 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.declaration.ts @@ -0,0 +1,177 @@ +import { heading } from '@plugin/theme/lib/markdown'; +import { + DeclarationReflection, + IntersectionType, + ReferenceType, + ReflectionKind, + ReflectionType, +} from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Renders a standard declaration member. + * + * @category Member Partials + */ +export function declaration( + context: MarkdownThemeRenderContext, + model: DeclarationReflection, + options: { + headingLevel: number; + nested?: boolean; + } = { + headingLevel: 2, + nested: false, + }, +): string { + const md: string[] = []; + + const opts = { + nested: false, + ...options, + }; + + md.push(context.partials.reflectionFlags(model)); + + md.push(context.partials.declarationTitle(model)); + + const typeDeclaration = (model.type as any) + ?.declaration as DeclarationReflection; + + if ( + !typeDeclaration?.signatures?.every((signature) => + Boolean(signature.comment), + ) + ) { + if (model.comment) { + md.push( + context.partials.comment(model.comment, { + headingLevel: opts.headingLevel, + }), + ); + } + } + + if (model.type instanceof IntersectionType) { + model.type?.types?.forEach((intersectionType) => { + if ( + intersectionType instanceof ReflectionType && + !intersectionType.declaration.signatures + ) { + if (intersectionType.declaration.children) { + md.push( + heading( + opts.headingLevel, + context.helpers.getText('label.typeDeclaration'), + ), + ); + + md.push( + context.partials.typeDeclaration( + intersectionType.declaration.children, + opts.headingLevel, + ), + ); + } + } + }); + } + + if (model.type instanceof ReferenceType && model.type.typeArguments?.length) { + if (model.type.typeArguments[0] instanceof ReflectionType) { + if (model.type.typeArguments[0].declaration?.children) { + md.push( + heading( + opts.headingLevel, + context.helpers.getText('label.typeDeclaration'), + ), + ); + md.push( + context.partials.typeDeclaration( + model.type.typeArguments[0].declaration?.children, + opts.headingLevel, + ), + ); + } + } + } + + if (model.typeParameters) { + md.push( + heading( + opts.headingLevel, + context.helpers.getText('kind.typeParameter.plural'), + ), + ); + if (context.options.getValue('parametersFormat') === 'table') { + md.push(context.partials.typeParametersTable(model.typeParameters)); + } else { + md.push(context.partials.typeParametersList(model.typeParameters)); + } + } + + if (typeDeclaration) { + if (typeDeclaration?.indexSignature) { + md.push( + heading( + opts.headingLevel, + context.helpers.getText('label.indexSignature'), + ), + ); + md.push(context.partials.indexSignature(typeDeclaration.indexSignature)); + } + + if (typeDeclaration?.signatures?.length) { + typeDeclaration.signatures.forEach((signature) => { + md.push(context.partials.signature(signature, opts.headingLevel, true)); + }); + } + + if (typeDeclaration?.children?.length) { + const useHeading = + model.kind !== ReflectionKind.Property || + context.options.getValue('propertiesFormat') == 'table'; + if (!opts.nested && typeDeclaration?.children?.length) { + if (useHeading) { + md.push( + heading( + opts.headingLevel, + context.helpers.getText('label.typeDeclaration'), + ), + ); + } + + if (typeDeclaration.categories) { + typeDeclaration.categories.forEach((category) => { + md.push(heading(opts.headingLevel, category.title)); + md.push( + context.partials.typeDeclaration( + category.children, + useHeading ? opts.headingLevel + 1 : opts.headingLevel, + ), + ); + }); + } else { + md.push( + context.partials.typeDeclaration( + typeDeclaration.children, + useHeading ? opts.headingLevel : opts.headingLevel - 1, + ), + ); + } + } + } + } + + md.push(context.partials.inheritance(model, opts.headingLevel)); + + if ( + !opts.nested && + model.sources && + !context.options.getValue('disableSources') + ) { + md.push(context.partials.sources(model, opts.headingLevel)); + } + + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.declaration.identifier.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.declarationTitle.ts similarity index 88% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.declaration.identifier.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.declarationTitle.ts index 8985047b2..42bd12bb8 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.declaration.identifier.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.declarationTitle.ts @@ -1,9 +1,14 @@ +import { backTicks, bold, codeBlock } from '@plugin/theme/lib/markdown'; +import { escapeChars, stripComments } from '@plugin/theme/lib/utils'; import { DeclarationReflection } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks, bold, codeBlock } from '../markdown'; -import { escapeChars, stripComments } from '../utils'; -export function declarationMemberIdentifier( +/** + * Remders a declaration title. + * + * @category Member Partials + */ +export function declarationTitle( context: MarkdownThemeRenderContext, reflection: DeclarationReflection, ): string { diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/table.enum-members.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.enumMembersTable.ts similarity index 81% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/table.enum-members.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.enumMembersTable.ts index a5b946998..0768d2ff5 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/table.enum-members.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.enumMembersTable.ts @@ -1,8 +1,16 @@ +import { backTicks } from '@plugin/theme/lib/markdown'; +import { + formatTableDescriptionCol, + formatTableTypeCol, +} from '@plugin/theme/lib/utils'; import { DeclarationReflection, ReflectionType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks } from '../markdown'; -import { formatTableDescriptionCol, formatTableTypeCol } from '../utils'; +/** + * Renders enum members as a table. + * + * @category Member Partials + */ export function enumMembersTable( context: MarkdownThemeRenderContext, props: DeclarationReflection[], @@ -11,12 +19,12 @@ export function enumMembersTable( const hasComments = comments.some((value) => Boolean(value)); const headers = [ - context.text.getText('kind.enumMember.singular'), - context.text.getText('label.value'), + context.helpers.getText('kind.enumMember.singular'), + context.helpers.getText('label.value'), ]; if (hasComments) { - headers.push(context.text.getText('label.description')); + headers.push(context.helpers.getText('label.description')); } const rows = props.map((property: DeclarationReflection) => { diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.hierarchy.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.hierarchy.ts similarity index 60% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.hierarchy.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.hierarchy.ts index 636bbfd95..9cbbae49b 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.hierarchy.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.hierarchy.ts @@ -1,36 +1,48 @@ +import { + backTicks, + bold, + heading, + unorderedList, +} from '@plugin/theme/lib/markdown'; import { DeclarationHierarchy, SomeType, Type } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks, bold, heading, unorderedList } from '../markdown'; -export function memberHierarchy( +/** + * Renders an declaration hierachy section. + * + * @category Member Partials + */ +export function hierarchy( context: MarkdownThemeRenderContext, - declarationHierarchy: DeclarationHierarchy, + model: DeclarationHierarchy, headingLevel: number, ): string { const md: string[] = []; - const parent = !declarationHierarchy.isTarget - ? declarationHierarchy.types + const parent = !model.isTarget + ? model.types .map((hierarchyType) => { return getHierarchyType( hierarchyType, - declarationHierarchy.isTarget || false, + model.isTarget || false, context, ); }) .join('.') : null; - if (declarationHierarchy.next) { + if (model.next) { if (parent) { - md.push(heading(headingLevel, context.text.getText('label.extends'))); + md.push(heading(headingLevel, context.helpers.getText('label.extends'))); md.push(`- ${parent}`); } else { - md.push(heading(headingLevel, context.text.getText('label.extendedBy'))); + md.push( + heading(headingLevel, context.helpers.getText('label.extendedBy')), + ); const lines: string[] = []; - declarationHierarchy.next.types.forEach((hierarchyType) => { + model.next.types.forEach((hierarchyType) => { lines.push( getHierarchyType( hierarchyType, - declarationHierarchy.next?.isTarget || false, + model.next?.isTarget || false, context, ), ); diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.indexsignature.title.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.indexSignature.ts similarity index 79% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.indexsignature.title.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.indexSignature.ts index 31a348944..a7e008a45 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.indexsignature.title.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.indexSignature.ts @@ -1,8 +1,13 @@ +import { backTicks } from '@plugin/theme/lib/markdown'; import { SignatureReflection } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks } from '../markdown'; -export function indexSignatureTitle( +/** + * Renders an index signature block + * + * @category Member Partials + */ +export function indexSignature( context: MarkdownThemeRenderContext, signature: SignatureReflection, ): string { diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.inheritance.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.inheritance.ts similarity index 75% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.inheritance.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.inheritance.ts index cc509fa70..750502c24 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.inheritance.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.inheritance.ts @@ -1,3 +1,4 @@ +import { backTicks, heading, link } from '@plugin/theme/lib/markdown'; import { ArrayType, DeclarationReflection, @@ -5,8 +6,12 @@ import { SignatureReflection, } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks, heading } from '../markdown'; +/** + * Renders an inheritance section. + * + * @category Member Partials + */ export function inheritance( context: MarkdownThemeRenderContext, reflection: DeclarationReflection | SignatureReflection, @@ -17,7 +22,10 @@ export function inheritance( if (reflection.implementationOf) { if (headingLevel !== -1) { md.push( - heading(headingLevel, context.text.getText('label.implementationOf')), + heading( + headingLevel, + context.helpers.getText('label.implementationOf'), + ), ); } md.push(typeAndParent(context, reflection.implementationOf)); @@ -26,14 +34,14 @@ export function inheritance( if (reflection.inheritedFrom) { if (headingLevel !== -1) { md.push( - heading(headingLevel, context.text.getText('label.inheritedFrom')), + heading(headingLevel, context.helpers.getText('label.inheritedFrom')), ); } md.push(typeAndParent(context, reflection.inheritedFrom)); } if (reflection.overwrites) { - const overridesLabel = context.text.getText('label.overrides'); + const overridesLabel = context.helpers.getText('label.overrides'); if (headingLevel !== -1) { md.push(heading(headingLevel, overridesLabel)); } @@ -65,14 +73,17 @@ const typeAndParent = ( const resultWithParent: string[] = []; if (parent?.url) { resultWithParent.push( - context.partials.linkTo(backTicks(parent.name), parent.url), + link( + backTicks(parent.name), + context.helpers.getRelativeUrl(parent.url), + ), ); } else { resultWithParent.push(backTicks(parent?.name)); } if (refl?.url) { resultWithParent.push( - context.partials.linkTo(backTicks(refl.name), refl.url), + link(backTicks(refl.name), context.helpers.getRelativeUrl(refl.url)), ); } else { resultWithParent.push(backTicks(refl?.name)); diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.title.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.memberTitle.ts similarity index 86% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.title.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.memberTitle.ts index 936127879..d61550bda 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.title.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.memberTitle.ts @@ -1,8 +1,13 @@ +import { backTicks, strikeThrough } from '@plugin/theme/lib/markdown'; +import { escapeChars } from '@plugin/theme/lib/utils'; import { DeclarationReflection, ReflectionKind, ReflectionType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../../..'; -import { backTicks, strikeThrough } from '../markdown'; -import { escapeChars } from '../utils'; +/** + * Renders the main member title. + * + * @category Member Partials + */ export function memberTitle( context: MarkdownThemeRenderContext, reflection: DeclarationReflection, diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.memberWithGroups.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.memberWithGroups.ts new file mode 100644 index 000000000..fbe5a4b12 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.memberWithGroups.ts @@ -0,0 +1,79 @@ +import { heading, unorderedList } from '@plugin/theme/lib/markdown'; +import { DeclarationReflection } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Renders a top-level member that contains group and child members such as Classes, Interfaces and Enums. + * + * @category Member Partials + */ +export function memberWithGroups( + context: MarkdownThemeRenderContext, + model: DeclarationReflection, + headingLevel: number, +): string { + const md: string[] = []; + + if (model.comment) { + md.push(context.partials.comment(model.comment, { headingLevel })); + } + + if (model.typeHierarchy?.next) { + md.push(context.partials.hierarchy(model.typeHierarchy, headingLevel)); + } + + if (model.typeParameters) { + md.push( + heading( + headingLevel, + context.helpers.getText('kind.typeParameter.plural'), + ), + ); + if (context.options.getValue('parametersFormat') === 'table') { + md.push(context.partials.typeParametersTable(model.typeParameters)); + } else { + md.push(context.partials.typeParametersList(model.typeParameters)); + } + } + + if (model.implementedTypes) { + md.push(heading(headingLevel, context.helpers.getText('label.implements'))); + md.push( + unorderedList( + model.implementedTypes.map((implementedType) => + context.partials.someType(implementedType), + ), + ), + ); + } + + if ('signatures' in model && model.signatures) { + model.signatures.forEach((signature) => { + md.push(context.partials.signature(signature, headingLevel)); + }); + } + + if ('indexSignature' in model && model.indexSignature) { + md.push(heading(headingLevel, context.helpers.getText('label.indexable'))); + md.push(context.partials.indexSignature(model.indexSignature)); + } + + if (model?.groups?.some((group) => group.allChildrenHaveOwnDocument())) { + const isAbsolute = model.groups?.every((group) => + group.allChildrenHaveOwnDocument(), + ); + if (isAbsolute) { + md.push(heading(headingLevel, context.helpers.getText('label.index'))); + } + md.push( + context.partials.reflectionIndex( + model, + isAbsolute ? headingLevel + 1 : headingLevel, + ), + ); + } + + md.push(context.partials.body(model, headingLevel)); + + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/list.parameters.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.parametersList.ts similarity index 91% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/list.parameters.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.parametersList.ts index 6f3d12075..9f64fc382 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/list.parameters.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.parametersList.ts @@ -1,8 +1,13 @@ +import { backTicks, bold } from '@plugin/theme/lib/markdown'; +import { escapeChars } from '@plugin/theme/lib/utils'; import { ParameterReflection, ReflectionKind, ReflectionType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks, bold } from '../markdown'; -import { escapeChars } from '../utils'; +/** + * Renders parameters section as a list. + * + * @category Member Partials + */ export function parametersList( context: MarkdownThemeRenderContext, parameters: ParameterReflection[], diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/table.parameters.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.parametersTable.ts similarity index 77% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/table.parameters.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.parametersTable.ts index c7557f3f3..1d37d82a0 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/table.parameters.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.parametersTable.ts @@ -1,8 +1,16 @@ +import { backTicks, table } from '@plugin/theme/lib/markdown'; +import { + formatTableDescriptionCol, + formatTableTypeCol, +} from '@plugin/theme/lib/utils'; import { ParameterReflection, ReflectionKind, ReflectionType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks, table } from '../markdown'; -import { formatTableDescriptionCol, formatTableTypeCol } from '../utils'; +/** + * Renders parameters section as a table. + * + * @category Member Partials + */ export function parametersTable( context: MarkdownThemeRenderContext, parameters: ParameterReflection[], @@ -39,16 +47,16 @@ export function parametersTable( const hasComments = parsedParams.some((param) => Boolean(param.comment)); const headers = [ - context.text.getText('kind.parameter.singular'), - context.text.getText('label.type'), + context.helpers.getText('kind.parameter.singular'), + context.helpers.getText('label.type'), ]; if (showDefaults) { - headers.push(context.text.getText('label.defaultValue')); + headers.push(context.helpers.getText('label.defaultValue')); } if (hasComments) { - headers.push(context.text.getText('label.description')); + headers.push(context.helpers.getText('label.description')); } const firstOptionalParamIndex = parameters.findIndex( @@ -109,3 +117,14 @@ function hasDefaultValues(parameters: ParameterReflection[]) { return !defaultValues.every((value) => !value); } + +/*function hasDefaultValues(parameters: ParameterReflection[]) { + const defaultValues = (parameters as ParameterReflection[]).map((param) => { + if (param.name === 'options.showSummary') { + console.log(param); + } + return Boolean(param.defaultValue); + }); + + return defaultValues.some((value) => value); +}*/ diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/table.properties.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.propertiesTable.ts similarity index 76% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/table.properties.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.propertiesTable.ts index 3c0c27b00..a88bd3481 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/table.properties.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.propertiesTable.ts @@ -1,9 +1,20 @@ +import { backTicks, strikeThrough, table } from '@plugin/theme/lib/markdown'; +import { + formatTableDescriptionCol, + formatTableTypeCol, +} from '@plugin/theme/lib/utils'; import { DeclarationReflection } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks, strikeThrough, table } from '../markdown'; -import { formatTableDescriptionCol, formatTableTypeCol } from '../utils'; -export function propertiesTable( +/** + * Renders a collection of properties in a table. + * + * There is no association list partial for properties as these are handled as a standard list of members. + * + * @category Member Partials + * + */ +export function declarationsTable( context: MarkdownThemeRenderContext, props: DeclarationReflection[], isEventProps = false, @@ -22,30 +33,30 @@ export function propertiesTable( headers.push( isEventProps - ? context.text.getText('kind.event.singular') - : context.text.getText('kind.property.singular'), + ? context.helpers.getText('kind.event.singular') + : context.helpers.getText('kind.property.singular'), ); if (hasModifiers) { - headers.push(context.text.getText('label.modifier')); + headers.push(context.helpers.getText('label.modifier')); } if (hasFlags) { - headers.push(context.text.getText('label.flags')); + headers.push(context.helpers.getText('label.flags')); } - headers.push(context.text.getText('label.type')); + headers.push(context.helpers.getText('label.type')); if (hasComments) { - headers.push(context.text.getText('label.description')); + headers.push(context.helpers.getText('label.description')); } if (hasOverrides) { - headers.push(context.text.getText('label.overrides')); + headers.push(context.helpers.getText('label.overrides')); } if (hasInheritance) { - headers.push(context.text.getText('label.inheritedFrom')); + headers.push(context.helpers.getText('label.inheritedFrom')); } const rows: string[][] = []; diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.reference.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.reference.ts similarity index 61% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.reference.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.reference.ts index bcbb1b62d..57c079908 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.reference.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.reference.ts @@ -1,14 +1,20 @@ +import { link } from '@plugin/theme/lib/markdown'; import { ReferenceReflection, ReflectionKind } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; +/** + * Renders an reference member. + * + * @category Member Partials + */ export function referenceMember( context: MarkdownThemeRenderContext, props: ReferenceReflection, ): string { let referenced = props.tryGetTargetReflectionDeep(); - const reExportsText = context.text.getText('label.reExports'); - const renamesAndReExportsText = context.text.getText( + const reExportsText = context.helpers.getText('label.reExports'); + const renamesAndReExportsText = context.helpers.getText( 'label.renamesAndReExports', ); @@ -25,14 +31,14 @@ export function referenceMember( } if (props.name === referenced.name) { - return `${reExportsText} ${context.partials.linkTo( + return `${reExportsText} ${link( referenced.name, - referenced.url, + context.helpers.getRelativeUrl(referenced.url), )}`; } - return `${renamesAndReExportsText} ${context.partials.linkTo( + return `${renamesAndReExportsText} ${link( referenced.name, - referenced.url, + context.helpers.getRelativeUrl(referenced.url), )}`; } diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/reflection.flags.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.reflection.flags.ts similarity index 76% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/reflection.flags.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.reflection.flags.ts index 23e4bb0f4..e5517000d 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/reflection.flags.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.reflection.flags.ts @@ -1,8 +1,13 @@ +import { backTicks } from '@plugin/theme/lib/markdown'; +import { camelToTitleCase } from '@plugin/theme/lib/utils'; import { Reflection } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks } from '../markdown'; -import { camelToTitleCase } from '../utils'; +/** + * Renders the flags of a reflection. + * + * @category Member Partials + */ export function reflectionFlags( context: MarkdownThemeRenderContext, reflection: Reflection, diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/index.reflection.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.reflection.index.ts similarity index 80% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/index.reflection.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.reflection.index.ts index 849cc57d0..47bae7f10 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/index.reflection.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.reflection.index.ts @@ -1,3 +1,8 @@ +import { heading, link, table } from '@plugin/theme/lib/markdown'; +import { + escapeChars, + formatTableDescriptionCol, +} from '@plugin/theme/lib/utils'; import { DeclarationReflection, ProjectReflection, @@ -6,9 +11,12 @@ import { ReflectionKind, } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { heading, table } from '../markdown'; -import { escapeChars, formatTableDescriptionCol } from '../utils'; +/** + * Renders the index section of a reflection. + * + * @category Member Partials + */ export function reflectionIndex( context: MarkdownThemeRenderContext, reflection: ProjectReflection | DeclarationReflection, @@ -38,7 +46,7 @@ export function reflectionIndex( md.push( heading( subHeadingLevel, - context.text.getTextFromKindString(reflectionGroup.title, true), + context.helpers.getTextFromKindString(reflectionGroup.title, true), ) + '\n', ); md.push(getGroup(context, reflectionGroup) + '\n'); @@ -66,14 +74,21 @@ function getTable( const headers = [ ReflectionKind.singularString(reflectionKind), - context.text.getText('label.description'), + context.helpers.getText('label.description'), ]; const rows: string[][] = []; group.children.forEach((child) => { const row: string[] = []; - row.push(context.partials.linkTo(escapeChars(child.name), child.url)); + if (child.url) { + row.push( + link( + escapeChars(child.name), + context.helpers.getRelativeUrl(child.url), + ), + ); + } const comment = getComment(child); @@ -103,10 +118,12 @@ function getList( ? `${ child.signatures ? child.signatures[0].name - : context.text.getText('kind.constructor.singular') + : context.helpers.getText('kind.constructor.singular') }` : child.name; - return `- ${context.partials.linkTo(escapeChars(name), child.url)}`; + return child.url + ? `- ${link(escapeChars(name), context.helpers.getRelativeUrl(child.url))}` + : ''; }); return children.join('\n'); } diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signature.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signature.ts new file mode 100644 index 000000000..4b35f3623 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signature.ts @@ -0,0 +1,86 @@ +import { heading } from '@plugin/theme/lib/markdown'; +import { ReflectionKind, SignatureReflection } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Renders a signature member. + * + * @category Member Partials + */ +export function signature( + context: MarkdownThemeRenderContext, + model: SignatureReflection, + headingLevel: number, + nested = false, + accessor?: string, +): string { + const md: string[] = []; + + md.push(context.partials.reflectionFlags(model)); + + if (!nested) { + md.push( + context.partials.signatureTitle(model, { + accessor, + }), + ); + } + + if (model.comment) { + md.push( + context.partials.comment(model.comment, { + headingLevel, + showTags: false, + }), + ); + } + + if ( + model.typeParameters?.length && + model.kind !== ReflectionKind.ConstructorSignature + ) { + md.push( + heading( + headingLevel, + context.helpers.getText('kind.typeParameter.plural'), + ), + ); + if (context.options.getValue('parametersFormat') === 'table') { + md.push(context.partials.typeParametersTable(model.typeParameters)); + } else { + md.push(context.partials.typeParametersList(model.typeParameters)); + } + } + + if (model.parameters?.length) { + md.push( + heading(headingLevel, context.helpers.getText('kind.parameter.plural')), + ); + if (context.options.getValue('parametersFormat') === 'table') { + md.push(context.partials.parametersTable(model.parameters)); + } else { + md.push(context.partials.parametersList(model.parameters)); + } + } + + if (model.type) { + md.push(context.partials.signatureReturns(model, headingLevel)); + } + + md.push(context.partials.inheritance(model, headingLevel)); + + if (model.comment) { + md.push( + context.partials.comment(model.comment, { + headingLevel, + showSummary: false, + }), + ); + } + + if (!nested && model.sources && !context.options.getValue('disableSources')) { + md.push(context.partials.sources(model, headingLevel)); + } + + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.parameters.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signatureParameters.ts similarity index 89% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.parameters.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signatureParameters.ts index 595439d8c..8b4cb4c57 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.parameters.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signatureParameters.ts @@ -1,7 +1,12 @@ +import { backTicks } from '@plugin/theme/lib/markdown'; import { ParameterReflection, SomeType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks } from '../markdown'; +/** + * Renders tha parameters of a signature in parenthisis. + * + * @category Member Partials + */ export function signatureParameters( context: MarkdownThemeRenderContext, parameters: ParameterReflection[], diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.returns.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signatureReturns.ts similarity index 70% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.returns.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signatureReturns.ts index 04cfaae46..9b18eee5e 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.returns.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signatureReturns.ts @@ -1,3 +1,9 @@ +import { + backTicks, + blockQuoteBlock, + codeBlock, + heading, +} from '@plugin/theme/lib/markdown'; import { DeclarationReflection, ReferenceType, @@ -6,9 +12,13 @@ import { SomeType, } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks, blockQuoteBlock, codeBlock, heading } from '../markdown'; -export function signatureMemberReturns( +/** + * Renders the return section of a signature. + * + * @category Member Partials + */ +export function signatureReturns( context: MarkdownThemeRenderContext, signature: SignatureReflection, headingLevel: number, @@ -18,7 +28,7 @@ export function signatureMemberReturns( const typeDeclaration = (signature.type as any) ?.declaration as DeclarationReflection; - md.push(heading(headingLevel, context.text.getText('label.returns'))); + md.push(heading(headingLevel, context.helpers.getText('label.returns'))); md.push(getReturnType(context, typeDeclaration, signature.type)); @@ -33,11 +43,14 @@ export function signatureMemberReturns( signature.type instanceof ReferenceType && signature.type.typeArguments?.length ) { - if (signature.type.typeArguments[0] instanceof ReflectionType) { + if ( + signature.type.typeArguments[0] instanceof ReflectionType && + signature.type.typeArguments[0].declaration.children + ) { md.push( blockQuoteBlock( - context.partials.typeDeclarationMember( - signature.type.typeArguments[0].declaration, + context.partials.typeDeclaration( + signature.type.typeArguments[0].declaration.children, headingLevel, ), ), @@ -49,7 +62,7 @@ export function signatureMemberReturns( typeDeclaration.signatures.forEach((signature) => { md.push( blockQuoteBlock( - context.partials.signatureMember(signature, headingLevel + 1, true), + context.partials.signature(signature, headingLevel + 1, true), ), ); }); @@ -57,7 +70,7 @@ export function signatureMemberReturns( if (typeDeclaration?.children) { md.push( - context.partials.typeDeclarationMember(typeDeclaration, headingLevel), + context.partials.typeDeclaration(typeDeclaration.children, headingLevel), ); } diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.identifier.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signatureTitle.ts similarity index 86% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.identifier.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signatureTitle.ts index 357911a2f..fb1ffbd63 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.identifier.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.signatureTitle.ts @@ -1,9 +1,14 @@ +import { backTicks, bold, codeBlock } from '@plugin/theme/lib/markdown'; +import { escapeChars } from '@plugin/theme/lib/utils'; import { SignatureReflection } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks, bold, codeBlock } from '../markdown'; -import { escapeChars } from '../utils'; -export function signatureMemberIdentifier( +/** + * Renders a signature title. + * + * @category Member Partials + */ +export function signatureTitle( context: MarkdownThemeRenderContext, signature: SignatureReflection, opts?: { diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.sources.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.sources.ts similarity index 71% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.sources.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.sources.ts index 1018f3627..c9cebbdee 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.sources.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.sources.ts @@ -1,8 +1,13 @@ +import { heading, link } from '@plugin/theme/lib/markdown'; +import { escapeChars } from '@plugin/theme/lib/utils'; import { DeclarationReflection, SignatureReflection } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { heading, link } from '../markdown'; -import { escapeChars } from '../utils'; +/** + * Renders the sources section of a member. + * + * @category Member Partials + */ export function sources( context: MarkdownThemeRenderContext, reflection: DeclarationReflection | SignatureReflection, @@ -11,7 +16,7 @@ export function sources( const md: string[] = []; if (headingLevel !== -1) { - md.push(heading(headingLevel, context.text.getText('label.source'))); + md.push(heading(headingLevel, context.helpers.getText('label.source'))); } reflection.sources?.forEach((source, index) => { if (index === 0) { diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.ts similarity index 68% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/member.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.ts index 7e692b42a..1a47ce611 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.ts @@ -1,30 +1,31 @@ +import { heading } from '@plugin/theme/lib/markdown'; +import { escapeChars } from '@plugin/theme/lib/utils'; import { DeclarationReflection, ReferenceReflection, ReflectionKind, } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { heading } from '../markdown'; -import { escapeChars } from '../utils'; +/** + * Renders a container member. + * + * @category Member Partials + */ export function member( context: MarkdownThemeRenderContext, - reflection: DeclarationReflection, + model: DeclarationReflection, headingLevel: number, nested = false, - parentDeclaration?: DeclarationReflection, ): string { const md: string[] = []; if (context.options.getValue('namedAnchors')) { - md.push(``); + md.push(``); } - if ( - !reflection.hasOwnDocument && - !(reflection.kind === ReflectionKind.Constructor) - ) { - md.push(heading(headingLevel, context.partials.memberTitle(reflection))); + if (!model.hasOwnDocument && !(model.kind === ReflectionKind.Constructor)) { + md.push(heading(headingLevel, context.partials.memberTitle(model))); } const getMember = (reflection: DeclarationReflection) => { @@ -35,15 +36,15 @@ export function member( ReflectionKind.Enum, ].includes(reflection.kind) ) { - return context.partials.reflectionMember(reflection, headingLevel + 1); + return context.partials.memberWithGroups(reflection, headingLevel + 1); } if (reflection.kind === ReflectionKind.Constructor) { - return context.partials.constructorMember(reflection, headingLevel); + return context.partials.constructor(reflection, headingLevel); } if (reflection.kind === ReflectionKind.Accessor) { - return context.partials.accessorMember(reflection, headingLevel + 1); + return context.partials.accessor(reflection, headingLevel + 1); } if (reflection.signatures) { @@ -64,7 +65,7 @@ export function member( ); } signatureMd.push( - context.partials.signatureMember( + context.partials.signature( signature, multipleSignatures ? headingLevel + 2 : headingLevel + 1, nested, @@ -79,14 +80,13 @@ export function member( return context.partials.referenceMember(reflection); } - return context.partials.declarationMember( - reflection, - headingLevel + 1, + return context.partials.declaration(reflection, { + headingLevel: headingLevel + 1, nested, - ); + }); }; - const member = getMember(reflection); + const member = getMember(model); if (member) { md.push(member); diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type-argumentsts.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeArguments.ts similarity index 77% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type-argumentsts.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeArguments.ts index f05e8186b..d9a0a6858 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type-argumentsts.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeArguments.ts @@ -1,12 +1,17 @@ import { ReflectionType, SomeType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; +/** + * Renders type arguments in angle brackets. + * + * @category Member Partials + */ export function typeArguments( context: MarkdownThemeRenderContext, - typeArguments: SomeType[], + model: SomeType[], foreCollpase = false, ): string { - return `\\<${typeArguments + return `\\<${model .map((typeArgument) => typeArgument instanceof ReflectionType ? context.partials.reflectionType(typeArgument, foreCollpase) diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeDeclaration.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeDeclaration.ts new file mode 100644 index 000000000..402472314 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeDeclaration.ts @@ -0,0 +1,23 @@ +import { DeclarationReflection } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Renders type declarations of a parent member. + * + * @category Member Partials + */ +export function typeDeclaration( + context: MarkdownThemeRenderContext, + model: DeclarationReflection[], + headingLevel: number, +): string { + const md: string[] = []; + + if (context.options.getValue('typeDeclarationFormat') === 'table') { + md.push(context.partials.typeDeclarationTable(model)); + } else { + md.push(context.partials.typeDeclarationList(model, headingLevel)); + } + + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeDeclarationList.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeDeclarationList.ts new file mode 100644 index 000000000..e7d7edd7e --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeDeclarationList.ts @@ -0,0 +1,21 @@ +import { DeclarationReflection } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Renders type declarations as a list. + * + * @category Member Partials + */ +export function typeDeclarationList( + context: MarkdownThemeRenderContext, + model: DeclarationReflection[], + headingLevel: number, +): string { + const md: string[] = []; + const declarations = context.helpers.flattenDeclarations(model, false); + declarations?.forEach((declaration: DeclarationReflection) => { + md.push(context.partials.member(declaration, headingLevel + 1, true)); + }); + + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/table.type-declaration.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeDeclarationTable.ts similarity index 78% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/table.type-declaration.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeDeclarationTable.ts index 68638982d..9db961a36 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/table.type-declaration.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeDeclarationTable.ts @@ -1,12 +1,17 @@ -import { DeclarationReflection, SomeType } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { table } from '../markdown'; +import { table } from '@plugin/theme/lib/markdown'; import { escapeChars, formatTableDescriptionCol, formatTableNameCol, -} from '../utils'; +} from '@plugin/theme/lib/utils'; +import { DeclarationReflection, SomeType } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; +/** + * Renders type declarations as a table. + * + * @category Member Partials + */ export function typeDeclarationTable( context: MarkdownThemeRenderContext, props: DeclarationReflection[], @@ -23,16 +28,16 @@ export function typeDeclarationTable( Boolean(declaration.defaultValue), ); - headers.push(context.text.getText('label.member')); + headers.push(context.helpers.getText('label.member')); - headers.push(context.text.getText('label.type')); + headers.push(context.helpers.getText('label.type')); if (hasDefaultValues) { - headers.push(context.text.getText('label.value')); + headers.push(context.helpers.getText('label.value')); } if (hasComments) { - headers.push(context.text.getText('label.description')); + headers.push(context.helpers.getText('label.description')); } const rows: string[][] = []; diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/list.typeparameters.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeParametersList.ts similarity index 86% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/list.typeparameters.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeParametersList.ts index 16deeba36..957f0c4bd 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/list.typeparameters.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeParametersList.ts @@ -1,7 +1,12 @@ +import { bold } from '@plugin/theme/lib/markdown'; import { TypeParameterReflection } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { bold } from '../markdown'; +/** + * Renders type parameters section as a list. + * + * @category Member Partials + */ export function typeParametersList( context: MarkdownThemeRenderContext, typeParameters: TypeParameterReflection[], diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/table.typeparameters.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeParametersTable.ts similarity index 76% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/table.typeparameters.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeParametersTable.ts index 2a7884d90..1cf18d6ad 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/table.typeparameters.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/member.typeParametersTable.ts @@ -1,8 +1,13 @@ +import { backTicks, table } from '@plugin/theme/lib/markdown'; +import { formatTableDescriptionCol } from '@plugin/theme/lib/utils'; import { TypeParameterReflection } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks, table } from '../markdown'; -import { formatTableDescriptionCol } from '../utils'; +/** + * Renders type parameters section as a table. + * + * @category Member Partials + */ export function typeParametersTable( context: MarkdownThemeRenderContext, typeParameters: TypeParameterReflection[], @@ -15,14 +20,14 @@ export function typeParametersTable( Boolean(typeParameter.comment), ); - const headers = [context.text.getText('kind.typeParameter.singular')]; + const headers = [context.helpers.getText('kind.typeParameter.singular')]; if (hasDefault) { - headers.push(context.text.getText('label.value')); + headers.push(context.helpers.getText('label.value')); } if (hasComments) { - headers.push(context.text.getText('label.description')); + headers.push(context.helpers.getText('label.description')); } const rows: string[][] = []; diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/page.breadcrumbs.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/page.breadcrumbs.ts new file mode 100644 index 000000000..9a80b31df --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/page.breadcrumbs.ts @@ -0,0 +1,66 @@ +import { link } from '@plugin/theme/lib/markdown'; +import { escapeChars } from '@plugin/theme/lib/utils'; +import * as path from 'path'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Renders breadcrumbs for a page from the context's `page` property. + * + * @category Page Partials + */ +export function breadcrumbs(context: MarkdownThemeRenderContext): string { + const md: string[] = []; + + const fileExtension = context.options.getValue('fileExtension'); + const entryFileName = `${path.parse(context.options.getValue('entryFileName')).name}${fileExtension}`; + + if ( + context.page.url === context.page.project.url || + ((context.page.url === entryFileName || + context.page.url === 'readme_.md') && + context.page.url.split(path.sep).length === 1) + ) { + return ''; + } + + const homeLabel = context.helpers.getProjectName( + context.helpers.getText('breadcrumbs.home'), + ); + + md.push(link(homeLabel, context.helpers.getRelativeUrl(entryFileName))); + + const breadcrumb = (model: any) => { + if (model?.parent?.parent) { + breadcrumb(model.parent); + } + + const getUrl = (model: any) => { + if (Boolean(model.readme)) { + return `${path.dirname(model.url)}/${entryFileName}`; + } + return model.url; + }; + if (model.name !== context.options.getValue('entryModule')) { + md.push( + link( + escapeChars(model.name), + context.helpers.getRelativeUrl(getUrl(model)), + ), + ); + } + }; + + const pageName = escapeChars(context.page.model.name); + + if ( + context.page.model?.parent?.parent && + (context.page.url !== context.page.project.url || + context.page.url !== entryFileName) + ) { + breadcrumb(context.page.model.parent); + } + + md.push(pageName); + + return md.length > 1 ? `${md.join(' / ')}` : ''; +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/page.header.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/page.header.ts new file mode 100644 index 000000000..cb9d90435 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/page.header.ts @@ -0,0 +1,183 @@ +import { bold, link } from '@plugin/theme/lib/markdown'; +import * as path from 'path'; +import { + DeclarationReflection, + EntryPointStrategy, + ProjectReflection, + ReflectionKind, +} from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Returns the page header. + * + * @category Page Partials + */ +export function header(context: MarkdownThemeRenderContext): string { + const getHeader = () => { + const isPackages = + context.options.getValue('entryPointStrategy') === + EntryPointStrategy.Packages; + if (isPackages) { + const packageItem = findPackage(context.page.model as ProjectReflection); + if (packageItem) { + return getPackageHeader(); + } + } + return getProjectHeader(); + }; + + const getProjectHeader = () => { + const fileExtension = context.options.getValue('fileExtension'); + const entryFileName = `${path.parse(context.options.getValue('entryFileName')).name}${fileExtension}`; + const titleLink = context.options.getValue('titleLink'); + + const md: string[] = []; + + const title = context.helpers.getProjectName( + context.helpers.getText('header.title'), + ); + + const readmeLabel = context.helpers.getText('header.readme'); + const indexLabel = context.helpers.getText('header.docs'); + + md.push(titleLink ? bold(link(title, titleLink)) : bold(title)); + + md.push('•'); + + const preserveReadme = + Boolean(context.page.project.readme) && + !context.options.getValue('mergeReadme'); + + const useEntryModule = + (context.page.project?.groups && + Boolean( + context.page.project?.groups[0]?.children.find( + (child) => child.name === context.options.getValue('entryModule'), + ), + )) || + false; + + if (preserveReadme) { + const links: string[] = []; + const readMeUrl = useEntryModule + ? `readme_${fileExtension}` + : entryFileName; + + if (context.page.url === readMeUrl) { + links.push(readmeLabel); + } else { + links.push( + link(readmeLabel, context.helpers.getRelativeUrl(readMeUrl)), + ); + } + + links.push('\\|'); + + const indexUrl = useEntryModule + ? entryFileName + : context.page.project.url; + + if (context.page.url === indexUrl) { + links.push(indexLabel); + } else { + if (indexUrl) { + links.push( + link(indexLabel, context.helpers.getRelativeUrl(indexUrl)), + ); + } + } + + md.push(`${links.join(' ')}`); + } else { + if (useEntryModule || context.page.url === context.page.project.url) { + md.push(indexLabel); + } else { + if (context.page.project.url) { + md.push( + link( + indexLabel, + context.helpers.getRelativeUrl(context.page.project.url), + ), + ); + } + } + } + + return `${md.join(' ')}\n\n***\n`; + }; + + const getPackageHeader = () => { + const packageItem = findPackage( + context.page.model as ProjectReflection, + ) as ProjectReflection; + + if (!packageItem) { + return ''; + } + + const md: string[] = []; + + const readmeLabel = context.helpers.getText('header.readme'); + const indexLabel = context.helpers.getText('header.docs'); + + const fileExtension = context.options.getValue('fileExtension'); + const entryFileName = `${path.parse(context.options.getValue('entryFileName')).name}${fileExtension}`; + + const packageItemName = packageItem.packageVersion + ? `${packageItem.name} v${packageItem.packageVersion}` + : packageItem.name; + + md.push(bold(packageItemName)); + + md.push('•'); + + const preservePackageReadme = + Boolean(packageItem.readme) && !context.options.getValue('mergeReadme'); + + if (preservePackageReadme) { + const links: string[] = []; + const readmeUrl = `${packageItem.name}/${entryFileName}`; + + if (context.page.url === readmeUrl) { + links.push(readmeLabel); + } else { + links.push( + link(readmeLabel, context.helpers.getRelativeUrl(readmeUrl)), + ); + } + + links.push('\\|'); + + if (context.page.url === packageItem.url) { + links.push(indexLabel); + } else { + if (packageItem.url) { + links.push( + link(indexLabel, context.helpers.getRelativeUrl(packageItem.url)), + ); + } + } + md.push(`${links.join(' ')}`); + } else { + md.push(indexLabel); + } + + return `${md.join(' ')}\n\n***\n`; + }; + + function findPackage(model: DeclarationReflection | ProjectReflection) { + if ( + model.kind === ReflectionKind.Module && + model.parent?.kind === ReflectionKind.Project + ) { + return model; + } + if (model.parent) { + return findPackage(model.parent as DeclarationReflection); + } + return null; + } + + return getHeader(); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/page.pageTtitle.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/page.pageTtitle.ts new file mode 100644 index 000000000..587934542 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/page.pageTtitle.ts @@ -0,0 +1,37 @@ +import { DeclarationReflection, ReflectionKind } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../../..'; + +/** + * Renders the page title. + * + * @category Page Partials + */ +export function pageTitle(context: MarkdownThemeRenderContext): string { + const page = context.page; + if (page.model?.url === page.project.url) { + const titleContent = context.options.isSet('indexPageTitle') + ? context.options.getValue('indexPageTitle') + : context.helpers.getText('title.indexPage'); + return context.helpers.getProjectName(titleContent); + } + + const name = context.partials.memberTitle( + page.model as DeclarationReflection, + ); + + const textContent = + page.model.kind === ReflectionKind.Module + ? context.helpers.getText('title.modulePage') + : context.options.isSet('memberPageTitle') + ? context.options.getValue('memberPageTitle') + : context.helpers.getText('title.memberPage'); + + return textContent + .replace('{name}', name) + .replace( + '{kind}', + context.helpers.getTextFromKindString( + ReflectionKind.singularString(page.model.kind), + ), + ); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.array.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.array.ts new file mode 100644 index 000000000..6c0a46f3f --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.array.ts @@ -0,0 +1,15 @@ +import { ArrayType } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Transforms an ArrayType model to a string. + * + * @category Type Partials + */ +export function arrayType( + context: MarkdownThemeRenderContext, + model: ArrayType, +): string { + const theType = context.partials.someType(model.elementType); + return model.elementType.type === 'union' ? `(${theType})[]` : `${theType}[]`; +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.conditional.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.conditional.ts new file mode 100644 index 000000000..6589cd904 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.conditional.ts @@ -0,0 +1,30 @@ +import { ConditionalType } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Transforms an ConditionalType model to a string. + * + * @category Type Partials + */ +export function conditionalType( + context: MarkdownThemeRenderContext, + model: ConditionalType, +): string { + const md: string[] = []; + if (model.checkType) { + md.push(context.partials.someType(model.checkType)); + } + md.push('extends'); + if (model.extendsType) { + md.push(context.partials.someType(model.extendsType)); + } + md.push('?'); + if (model.trueType) { + md.push(context.partials.someType(model.trueType)); + } + md.push(':'); + if (model.falseType) { + md.push(context.partials.someType(model.falseType)); + } + return md.join(' '); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.index-access.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.index-access.ts similarity index 82% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.index-access.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.index-access.ts index c25176dec..6ef494d9d 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.index-access.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.index-access.ts @@ -1,6 +1,11 @@ import { IndexedAccessType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; +/** + * Transforms an IndexedAccessType model to a string. + * + * @category Type Partials + */ export function indexAccessType( context: MarkdownThemeRenderContext, model: IndexedAccessType, diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.inferred.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.inferred.ts similarity index 63% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.inferred.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.inferred.ts index e25349d43..c2fb3b06b 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.inferred.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.inferred.ts @@ -1,7 +1,12 @@ +import { escapeChars } from '@plugin/theme/lib/utils'; import { InferredType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { escapeChars } from '../utils'; +/** + * Transforms an InferredType model to a string. + * + * @category Type Partials + */ export function inferredType( context: MarkdownThemeRenderContext, model: InferredType, diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.intersection.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.intersection.ts similarity index 78% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.intersection.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.intersection.ts index fe60df990..46bddf478 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.intersection.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.intersection.ts @@ -1,6 +1,11 @@ import { IntersectionType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; +/** + * Transforms an IntersectionType model to a string. + * + * @category Type Partials + */ export function intersectionType( context: MarkdownThemeRenderContext, model: IntersectionType, diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.intrinsic.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.intrinsic.ts similarity index 61% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.intrinsic.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.intrinsic.ts index 79db99827..844f8e1e7 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.intrinsic.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.intrinsic.ts @@ -1,7 +1,12 @@ +import { backTicks } from '@plugin/theme/lib/markdown'; import { IntrinsicType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks } from '../markdown'; +/** + * Transforms an IntrinsicType model to a string. + * + * @category Type Partials + */ export function intrinsicType( context: MarkdownThemeRenderContext, model: IntrinsicType, diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.literal.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.literal.ts new file mode 100644 index 000000000..e10bb199c --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.literal.ts @@ -0,0 +1,17 @@ +import { LiteralType } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Transforms an LiteralType model to a string. + * + * @category Type Partials + */ +export function literalType( + context: MarkdownThemeRenderContext, + model: LiteralType, +): string { + if (typeof model.value === 'bigint') { + return `\`${model.value}n\``; + } + return `\`\`${JSON.stringify(model.value)}\`\``; +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.named-tuple.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.named-tuple.ts similarity index 51% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.named-tuple.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.named-tuple.ts index a8d576b08..2e27b607d 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.named-tuple.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.named-tuple.ts @@ -1,9 +1,14 @@ import { NamedTupleMember } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; +/** + * Transforms an NamedTupleMember model to a string. + * + * @category Type Partials + */ export function namedTupleType( context: MarkdownThemeRenderContext, - member: NamedTupleMember, + model: NamedTupleMember, ): string { - return context.partials.someType(member.element); + return context.partials.someType(model.element); } diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.query.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.query.ts new file mode 100644 index 000000000..1244752e1 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.query.ts @@ -0,0 +1,15 @@ +import { italic } from '@plugin/theme/lib/markdown'; +import { QueryType } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Transforms an QueryType model to a string. + * + * @category Type Partials + */ +export function queryType( + context: MarkdownThemeRenderContext, + model: QueryType, +): string { + return `${italic('typeof')} ${context.partials.someType(model.queryType)}`; +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reference.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reference.ts new file mode 100644 index 000000000..f40d20549 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reference.ts @@ -0,0 +1,42 @@ +import { backTicks, link } from '@plugin/theme/lib/markdown'; +import { ReferenceType } from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Transforms an ReferenceType model to a string. + * + * @category Type Partials + */ +export function referenceType( + context: MarkdownThemeRenderContext, + model: ReferenceType, +): string { + if (model.reflection || (model.name && model.typeArguments)) { + const reflection: string[] = []; + + if (model.reflection?.url) { + reflection.push( + link( + backTicks(model.reflection.name), + context.helpers.getRelativeUrl(model.reflection.url), + ), + ); + } else { + reflection.push( + model.externalUrl + ? link( + backTicks(model.name), + context.helpers.getRelativeUrl(model.externalUrl), + ) + : backTicks(model.name), + ); + } + if (model.typeArguments && model.typeArguments.length) { + reflection.push(context.partials.typeArguments(model.typeArguments)); + } + return reflection.join(''); + } + return model.externalUrl + ? `[${backTicks(model.name)}]( ${model.externalUrl} )` + : backTicks(model.name); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.declaration.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reflection.declaration.ts similarity index 86% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.declaration.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reflection.declaration.ts index ed3819891..216e26ef5 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.declaration.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reflection.declaration.ts @@ -1,16 +1,21 @@ +import { backTicks } from '@plugin/theme/lib/markdown'; import { DeclarationReflection, SomeType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks } from '../markdown'; +/** + * Transforms an ReferenceType declaration model to a string. + * + * @category Type Partials + */ export function declarationType( context: MarkdownThemeRenderContext, - declarationReflection: DeclarationReflection, + model: DeclarationReflection, ): string { const shouldFormat = context.options.getValue('useCodeBlocks'); - if (declarationReflection.indexSignature || declarationReflection.children) { + if (model.indexSignature || model.children) { let indexSignature = ''; - const declarationIndexSignature = declarationReflection.indexSignature; + const declarationIndexSignature = model.indexSignature; if (declarationIndexSignature) { const key = declarationIndexSignature.parameters ? declarationIndexSignature.parameters.map( @@ -23,7 +28,7 @@ export function declarationType( indexSignature = `${key}: ${obj}; `; } - const children = declarationReflection.children; + const children = model.children; const types = children && diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.function.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reflection.function.ts similarity index 88% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.function.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reflection.function.ts index 90e464e46..3820bb928 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.function.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reflection.function.ts @@ -1,7 +1,12 @@ +import { backTicks } from '@plugin/theme/lib/markdown'; import { SignatureReflection, SomeType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks } from '../markdown'; +/** + * Transforms an ReferenceType functions model to a string. + * + * @category Type Partials + */ export function functionType( context: MarkdownThemeRenderContext, signatures: SignatureReflection[], diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.reflection.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reflection.ts similarity index 66% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.reflection.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reflection.ts index 2178527b7..fd6cf6084 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.reflection.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.reflection.ts @@ -1,16 +1,18 @@ +import { backTicks } from '@plugin/theme/lib/markdown'; import { ReflectionType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { backTicks } from '../markdown'; +/** + * Transforms an ReflectionType model to a string. + * + * @category Type Partials + */ export function reflectionType( context: MarkdownThemeRenderContext, - reflectionType: ReflectionType, + model: ReflectionType, foreCollpase = false, ): string { - const root = - reflectionType instanceof ReflectionType - ? reflectionType.declaration - : reflectionType; + const root = model instanceof ReflectionType ? model.declaration : model; if (root.signatures) { return context.partials.functionType(root.signatures); } diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.some.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.some.ts new file mode 100644 index 000000000..ad9659884 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.some.ts @@ -0,0 +1,95 @@ +import { backTicks } from '@plugin/theme/lib/markdown'; +import { + ArrayType, + ConditionalType, + IndexedAccessType, + InferredType, + IntersectionType, + IntrinsicType, + NamedTupleMember, + QueryType, + ReferenceType, + ReflectionType, + SomeType, + TupleType, + TypeOperatorType, + UnionType, + UnknownType, +} from 'typedoc'; +import { MarkdownThemeRenderContext } from '../..'; + +/** + * Takes a generic Type and returns the appropriate partial for it. + * + * @category Type Partials + */ +export function someType( + context: MarkdownThemeRenderContext, + model: SomeType, +): string { + if (!model) { + return ''; + } + + if (model instanceof ArrayType) { + return context.partials.arrayType(model); + } + + if (model instanceof ConditionalType) { + return context.partials.conditionalType(model); + } + + if (model instanceof IndexedAccessType) { + return context.partials.indexAccessType(model); + } + + if (model instanceof InferredType) { + return context.partials.inferredType(model); + } + + if (model instanceof IntersectionType && model.types) { + return context.partials.intersectionType(model); + } + + if (model instanceof IntrinsicType && model.name) { + return context.partials.intrinsicType(model); + } + + if (model instanceof QueryType) { + return context.partials.queryType(model); + } + + if (model instanceof ReferenceType) { + return context.partials.referenceType(model); + } + + if (model instanceof ReflectionType) { + return context.partials.reflectionType(model); + } + + if (model instanceof TypeOperatorType) { + return context.partials.typeOperatorType(model); + } + + if (model instanceof TupleType && model.elements) { + return context.partials.tupleType(model); + } + + if (model instanceof UnionType && model.types) { + return context.partials.unionType(model); + } + + if (model instanceof UnknownType) { + return context.partials.unknownType(model); + } + + if (model instanceof NamedTupleMember) { + return context.partials.namedTupleType(model); + } + + if (model.toString() == 'null') { + return backTicks('null'); + } + + return backTicks(model?.toString()); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.tuple.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.tuple.ts similarity index 63% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.tuple.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.tuple.ts index a5cd75c75..12e44e37d 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.tuple.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.tuple.ts @@ -1,11 +1,16 @@ import { TupleType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; +/** + * Transforms an TupleType functions model to a string. + * + * @category Type Partials + */ export function tupleType( context: MarkdownThemeRenderContext, - tupleType: TupleType, + model: TupleType, ): string { - return `[${tupleType.elements + return `[${model.elements .map((element) => context.partials.someType(element)) .join(', ')}]`; } diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.type-operator.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.type-operator.ts similarity index 73% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.type-operator.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.type-operator.ts index f312d59f5..37a316385 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.type-operator.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.type-operator.ts @@ -1,6 +1,11 @@ import { TypeOperatorType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; +/** + * Transforms an TypeOperatorType functions model to a string. + * + * @category Type Partials + */ export function typeOperatorType( context: MarkdownThemeRenderContext, model: TypeOperatorType, diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.union.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.union.ts similarity index 67% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.union.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.union.ts index 7a9d438be..086190e42 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.union.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.union.ts @@ -1,13 +1,18 @@ import { UnionType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; +/** + * Transforms an UnionType model to a string. + * + * @category Type Partials + */ export function unionType( context: MarkdownThemeRenderContext, - unionType: UnionType, + model: UnionType, ): string { const useCodeBlocks = context.options.getValue('useCodeBlocks'); - const shouldFormat = useCodeBlocks && unionType.types.length > 4; - const md = unionType.types + const shouldFormat = useCodeBlocks && model.types.length > 4; + const md = model.types .map((unionType) => context.partials.someType(unionType)) .join(shouldFormat ? `\n \\| ` : ` \\| `); return shouldFormat ? `\n \\| ` + md : md; diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.unknown.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.unknown.ts similarity index 61% rename from packages/typedoc-plugin-markdown/src/theme/resources/partials/type.unknown.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.unknown.ts index 49108fcaf..c29894228 100644 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.unknown.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/partials/type.unknown.ts @@ -1,7 +1,12 @@ +import { escapeChars } from '@plugin/theme/lib/utils'; import { UnknownType } from 'typedoc'; import { MarkdownThemeRenderContext } from '../..'; -import { escapeChars } from '../utils'; +/** + * Transforms an UnknownType model to a string. + * + * @category Type Partials + */ export function unknownType( context: MarkdownThemeRenderContext, model: UnknownType, diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/templates/project.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/templates/project.ts new file mode 100644 index 000000000..0e67361b4 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/templates/project.ts @@ -0,0 +1,87 @@ +import { heading, link } from '@plugin/theme/lib/markdown'; +import { escapeChars } from '@plugin/theme/lib/utils'; +import * as path from 'path'; +import { MarkdownThemeRenderContext } from 'theme'; +import { EntryPointStrategy, ProjectReflection } from 'typedoc'; + +/** + * Template that maps to the root project reflection. This will be the index page / documentation root page. + */ +export function project( + this: MarkdownThemeRenderContext, + model: ProjectReflection, +) { + const md: string[] = []; + + md.push(this.hook('index.page.begin').join('\n')); + + if (!this.options.getValue('hidePageHeader')) { + md.push(this.partials.header()); + } + + if (!this.options.getValue('hideBreadcrumbs')) { + md.push(this.partials.breadcrumbs()); + } + + const includeReadme = + this.options.getValue('mergeReadme') && Boolean(model.readme); + + if (includeReadme && model.readme) { + md.push(this.partials.commentParts(model.readme)); + } + + if (!this.options.getValue('hidePageTitle') && !includeReadme) { + md.push(heading(1, this.partials.pageTitle())); + } + + md.push(this.hook('index.content.begin').join('\n')); + + if (model.comment) { + md.push(this.partials.comment(model.comment, { headingLevel: 2 })); + } + + const pageIndex = () => { + const md: string[] = []; + + const model = this.page.model as ProjectReflection; + + if (model?.groups?.some((group) => group.allChildrenHaveOwnDocument())) { + md.push(this.partials.reflectionIndex(model, 2)); + return md.join('\n\n'); + } + + const isPackages = + this.page.project.url === this.page.url && + this.options.getValue('entryPointStrategy') === + EntryPointStrategy.Packages; + + if (isPackages && model.children?.length) { + md.push(heading(2, this.helpers.getText('label.packages'))); + const packagesList = model.children?.map((projectPackage) => { + const urlTo = Boolean(projectPackage.readme) + ? `${path.dirname(projectPackage.url || '')}/${this.options.getValue( + 'entryFileName', + )}` + : projectPackage.url; + return urlTo + ? `- ${link( + escapeChars(projectPackage.name), + this.helpers.getRelativeUrl(urlTo), + )}` + : ''; + }); + md.push(packagesList?.join('\n') || ''); + return md.join('\n\n'); + } + + return md.join('\n\n'); + }; + + md.push(pageIndex()); + + md.push(this.partials.body(model, 2)); + + md.push(this.hook('index.page.end').join('\n')); + + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/templates/read-me.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/templates/read-me.ts new file mode 100644 index 000000000..a79d74975 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/templates/read-me.ts @@ -0,0 +1,26 @@ +import { MarkdownThemeRenderContext } from '@plugin/theme'; +import { CommentDisplayPart, ProjectReflection } from 'typedoc'; + +/** + * Template that specifically maps to the resolved readme file. This template is not used when 'readme' is set to 'none'. + */ +export function readme( + this: MarkdownThemeRenderContext, + model: ProjectReflection, +) { + const md: string[] = []; + + if (!this.options.getValue('hidePageHeader')) { + md.push(this.partials.header()); + } + + if (!this.options.getValue('hideBreadcrumbs')) { + md.push(this.partials.breadcrumbs()); + } + + if (Boolean(model.readme)) { + md.push(this.partials.commentParts(model.readme as CommentDisplayPart[])); + } + + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/templates/reflection.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/templates/reflection.ts new file mode 100644 index 000000000..dff30f810 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme-render-context/templates/reflection.ts @@ -0,0 +1,48 @@ +import { heading } from '@plugin/theme/lib/markdown'; + +import { MarkdownThemeRenderContext } from 'theme'; +import { DeclarationReflection, ReflectionKind } from 'typedoc'; + +/** + * Template that maps to individual reflection models. + */ +export function reflection( + this: MarkdownThemeRenderContext, + model: DeclarationReflection, +) { + const md: string[] = []; + + md.push(this.hook('page.begin').join('\n')); + + if (!this.options.getValue('hidePageHeader')) { + md.push(this.partials.header()); + } + + if (!this.options.getValue('hideBreadcrumbs')) { + md.push(this.partials.breadcrumbs()); + } + + if (!this.options.getValue('hidePageTitle')) { + md.push(heading(1, this.partials.pageTitle())); + } + + md.push(this.hook('content.begin').join('\n')); + + if ( + [ + ReflectionKind.Module, + ReflectionKind.Namespace, + ReflectionKind.Enum, + ReflectionKind.Class, + ReflectionKind.Interface, + ].includes(model.kind) + ) { + md.push(this.partials.memberWithGroups(model, 2)); + } else { + md.push(this.partials.member(model, 1)); + } + + md.push(this.hook('page.end').join('\n')); + + return md.join('\n\n'); +} diff --git a/packages/typedoc-plugin-markdown/src/theme/core/navigation.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme/get-navigation.ts similarity index 91% rename from packages/typedoc-plugin-markdown/src/theme/core/navigation.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme/get-navigation.ts index 3d255c2d4..ed06eb565 100644 --- a/packages/typedoc-plugin-markdown/src/theme/core/navigation.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme/get-navigation.ts @@ -1,3 +1,7 @@ +import { PLURAL_KIND_KEY_MAP } from '@plugin/app/options/text-mappings'; +import { MarkdownRenderer } from '@plugin/app/renderer'; +import { MarkdownTheme } from '@plugin/theme'; +import { NavigationItem } from '@plugin/theme/theme-types'; import * as path from 'path'; import { DeclarationReflection, @@ -7,26 +11,16 @@ import { ReflectionGroup, ReflectionKind, } from 'typedoc'; -import { MarkdownTheme } from '../..'; -import { OutputFileStrategy } from '../../plugin/options/option-maps'; -import { text } from './text'; - -export interface NavigationItem { - title: string; - url?: string; - children?: NavigationItem[]; - isReadme?: boolean; - isGroup?: boolean; -} +import { OutputFileStrategy } from '../../app/options/option-maps'; export function getNavigation( theme: MarkdownTheme, project: ProjectReflection, ) { - const textHelpers = text(theme); const options = theme.application.options; const navigation: NavigationItem[] = []; - const optionsForPackages = (theme.application.renderer as any).packageOptions; + const optionsForPackages = (theme.application.renderer as MarkdownRenderer) + .packageOptions; const isPackages = options.getValue('entryPointStrategy') === EntryPointStrategy.Packages; @@ -78,7 +72,7 @@ export function getNavigation( outputFileStrategy === OutputFileStrategy.Modules ) { children.push({ - title: textHelpers.getText('label.globals'), + title: theme.textMappings['label.globals'], url: projectChild.url, }); } @@ -234,7 +228,9 @@ export function getNavigation( const groupChildren = getGroupChildren(group, outputFileStrategy); return groupChildren.length ? { - title: textHelpers.getTextFromKindString(group.title, true), + title: + theme.textMappings[PLURAL_KIND_KEY_MAP[group.title]] || + group.title, children: groupChildren || null, } : null; diff --git a/packages/typedoc-plugin-markdown/src/theme/core/urls.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme/get-urls.ts similarity index 84% rename from packages/typedoc-plugin-markdown/src/theme/core/urls.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme/get-urls.ts index 821d358af..c98544d0c 100644 --- a/packages/typedoc-plugin-markdown/src/theme/core/urls.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme/get-urls.ts @@ -1,3 +1,4 @@ +import { TemplateMapping, UrlMapping } from '@plugin/theme/theme-types'; import * as path from 'path'; import { DeclarationReflection, @@ -6,30 +7,16 @@ import { Reflection, ReflectionKind, } from 'typedoc'; -import { MarkdownPageEvent, MarkdownTheme } from '../..'; -import { OutputFileStrategy } from '../../plugin/options/option-maps'; +import { MarkdownTheme } from '../..'; +import { OutputFileStrategy } from '../../app/options/option-maps'; -export interface UrlOption { +interface UrlOption { parentUrl?: string; directory?: string | null; forceDirectory?: boolean; outputFileStrategy?: OutputFileStrategy; } -export interface TemplateMapping { - directory: string | null; - template: any; - kind: ReflectionKind; -} - -export interface UrlMapping { - url: string; - model: Model; - template: RenderTemplate>; -} - -export type RenderTemplate = (data: T) => string; - /** * Map the models of the given project to the desired output files. * Based on TypeDoc DefaultTheme.getUrls() @@ -41,59 +28,12 @@ export function getUrls(theme: MarkdownTheme, project: ProjectReflection) { const optionsForPackages = (theme.application.renderer as any).packageOptions; const urls: UrlMapping[] = []; const anchors: Record = {}; - const fileExtension = options.getValue('fileExtension'); const entryFileName = `${path.parse(options.getValue('entryFileName')).name}${fileExtension}`; - - const preserveReadme = - Boolean(project.readme) && !options.getValue('mergeReadme'); - - const isModulesOnly = project.children?.every( - (child) => child.kind === ReflectionKind.Module, - ); - const useEntryModule = - project?.groups && - Boolean( - project?.groups[0]?.children.find( - (child) => child.name === options.getValue('entryModule'), - ), - ) && - isModulesOnly; - const isPackages = options.getValue('entryPointStrategy') === EntryPointStrategy.Packages; - const indexFilename = getIndexFileName(project, isPackages); - - project.url = preserveReadme - ? indexFilename - : useEntryModule - ? indexFilename - : entryFileName; - - if (preserveReadme) { - urls.push({ - url: useEntryModule ? `readme_${fileExtension}` : entryFileName, - model: project, - template: theme.readmeTemplate, - }); - - if (!useEntryModule) { - urls.push({ - url: indexFilename, - model: project, - template: theme.projectTemplate, - }); - } - } else { - if (!useEntryModule) { - urls.push({ - url: entryFileName, - model: project, - template: theme.projectTemplate, - }); - } - } + buildEntryUrls(); if (isPackages) { if (Object.keys(optionsForPackages)?.length === 1) { @@ -109,6 +49,54 @@ export function getUrls(theme: MarkdownTheme, project: ProjectReflection) { return urls; + function buildEntryUrls() { + const preserveReadme = + Boolean(project.readme) && !options.getValue('mergeReadme'); + + const isModulesOnly = project.children?.every( + (child) => child.kind === ReflectionKind.Module, + ); + const useEntryModule = + project?.groups && + Boolean( + project?.groups[0]?.children.find( + (child) => child.name === options.getValue('entryModule'), + ), + ) && + isModulesOnly; + const indexFilename = getIndexFileName(project, isPackages); + + project.url = preserveReadme + ? indexFilename + : useEntryModule + ? indexFilename + : entryFileName; + + if (preserveReadme) { + urls.push({ + url: useEntryModule ? `readme_${fileExtension}` : entryFileName, + model: project, + template: theme.readmeTemplate, + }); + + if (!useEntryModule) { + urls.push({ + url: indexFilename, + model: project, + template: theme.projectTemplate, + }); + } + } else { + if (!useEntryModule) { + urls.push({ + url: entryFileName, + model: project, + template: theme.projectTemplate, + }); + } + } + } + function buildUrlsFromProject( project: ProjectReflection | DeclarationReflection, parentUrl?: string, @@ -162,17 +150,17 @@ export function getUrls(theme: MarkdownTheme, project: ProjectReflection) { function buildUrlsFromGroup( reflection: DeclarationReflection, - options: UrlOption, + urlOptions: UrlOption, ) { const mapping: TemplateMapping = theme.getTemplateMapping( reflection.kind, - options.outputFileStrategy, + urlOptions.outputFileStrategy, ); if (mapping) { - const directory = options.directory || mapping.directory; + const directory = urlOptions.directory || mapping.directory; const urlPath = getUrlPath(reflection, { - ...options, + ...urlOptions, directory, }); @@ -203,12 +191,12 @@ export function getUrls(theme: MarkdownTheme, project: ProjectReflection) { group.children.forEach((groupChild) => { const mapping = theme.getTemplateMapping( groupChild.kind, - options.outputFileStrategy, + urlOptions.outputFileStrategy, ); buildUrlsFromGroup(groupChild, { parentUrl: urlPath, directory: mapping?.directory || null, - outputFileStrategy: options.outputFileStrategy, + outputFileStrategy: urlOptions.outputFileStrategy, }); }); }); diff --git a/packages/typedoc-plugin-markdown/src/theme/theme.ts b/packages/typedoc-plugin-markdown/src/theme/markdown-theme/index.ts similarity index 64% rename from packages/typedoc-plugin-markdown/src/theme/theme.ts rename to packages/typedoc-plugin-markdown/src/theme/markdown-theme/index.ts index 7773787ef..cf0359890 100644 --- a/packages/typedoc-plugin-markdown/src/theme/theme.ts +++ b/packages/typedoc-plugin-markdown/src/theme/markdown-theme/index.ts @@ -1,3 +1,7 @@ +import { MarkdownPageEvent } from '@plugin/app/events'; +import { OutputFileStrategy, TextContentMappings } from '@plugin/app/options'; +import { MarkdownRenderer } from '@plugin/app/renderer'; +import { RenderTemplate } from '@plugin/theme/theme-types'; import { DeclarationReflection, DefaultTheme, @@ -6,10 +10,10 @@ import { ReflectionKind, Theme, } from 'typedoc'; -import { MarkdownPageEvent, OutputFileStrategy } from '../plugin'; -import { getNavigation } from './core/navigation'; -import { RenderTemplate, getUrls } from './core/urls'; -import { MarkdownThemeRenderContext } from './theme-render-context'; +import { TEXT_MAPPING_DEFAULTS } from '../../app/options/text-mappings'; +import { MarkdownThemeRenderContext } from '../markdown-theme-render-context'; +import { getNavigation } from './get-navigation'; +import { getUrls } from './get-urls'; /** * This is in-built MarkdownTheme which extends TypeDocs Theme class. @@ -17,6 +21,16 @@ import { MarkdownThemeRenderContext } from './theme-render-context'; * */ export class MarkdownTheme extends Theme { + readonly textMappings: TextContentMappings; + + constructor(renderer: MarkdownRenderer) { + super(renderer); + this.textMappings = { + ...TEXT_MAPPING_DEFAULTS, + ...(this.application.options.getValue('textContentMappings') || {}), + }; + } + /** * Renders a template and page model to a string. */ @@ -37,23 +51,34 @@ export class MarkdownTheme extends Theme { } } + /** + * Creates a new instance of the current theme context and calls the readme() method on the context's {@link MarkdownThemeRenderContext.templates | templates} namespace. + * + * @internal + */ readmeTemplate = (page: MarkdownPageEvent) => { - return this.getRenderContext(page).templates.readmeTemplate(page); + return this.getRenderContext(page).templates.readme(page.model); }; + /** + * Creates a new instance of the current theme context and calls the project() method on the context's {@link MarkdownThemeRenderContext.templates | templates} namespace. + * + * @internal + */ projectTemplate = (page: MarkdownPageEvent) => { - return this.getRenderContext(page).templates.projectTemplate(page); + return this.getRenderContext(page).templates.project(page.model); }; + /** + * Creates a new instance of the current theme context and calls the reflection() method on the context's {@link MarkdownThemeRenderContext.templates | templates} namespace. + * + * @internal + */ reflectionTemplate = (page: MarkdownPageEvent) => { - return this.getRenderContext(page).templates.reflectionTemplate(page); - }; - - memberTemplate = (page: MarkdownPageEvent) => { - return this.getRenderContext(page).templates.memberTemplate(page); + return this.getRenderContext(page).templates.reflection(page.model); }; - getRenderContext(page: MarkdownPageEvent | null) { + getRenderContext(page: MarkdownPageEvent) { return new MarkdownThemeRenderContext(this, page, this.application.options); } @@ -118,17 +143,17 @@ export class MarkdownTheme extends Theme { ); mappings[ReflectionKind.Function] = memberMapping( - this.memberTemplate, + this.reflectionTemplate, ReflectionKind.Function, ); mappings[ReflectionKind.TypeAlias] = memberMapping( - this.memberTemplate, + this.reflectionTemplate, ReflectionKind.TypeAlias, ); mappings[ReflectionKind.Variable] = memberMapping( - this.memberTemplate, + this.reflectionTemplate, ReflectionKind.Variable, ); } diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-index-title.ts b/packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-index-title.ts deleted file mode 100644 index 1377ea92f..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/get-index-title.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function getIndexTitle( - textContent: string, - name: string, - version?: string, -) { - return textContent - .replace('{projectName}', name) - .replace('{version}', version ? `v${version}` : '') - .replace(/\s+/g, ' ') - .trim(); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/index.ts b/packages/typedoc-plugin-markdown/src/theme/resources/helpers/index.ts deleted file mode 100644 index 7fdcf345e..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export { flattenDeclarations } from './flatten-declarations'; -export { getDeclarationType } from './get-declaration-type'; -export { getIndexTitle } from './get-index-title'; -export { getKeyword } from './get-keyword'; -export { getModifier } from './get-modifier'; -export { getParameterDefaultValue } from './get-parameter-default-value.'; -export { isGroupKind } from './is-group-kind'; -export { parseComments } from './parse-comments'; -export { parseUrl } from './parse-url'; \ No newline at end of file diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/parse-comments.ts b/packages/typedoc-plugin-markdown/src/theme/resources/helpers/parse-comments.ts deleted file mode 100644 index d06bf1276..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/parse-comments.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Exposed to additionally parse comments. - * @param comments - * @returns - */ -export function parseComments(comments: string) { - return comments; -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/parse-url.ts b/packages/typedoc-plugin-markdown/src/theme/resources/helpers/parse-url.ts deleted file mode 100644 index b7624dadc..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/helpers/parse-url.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Additional url parsing - */ -export function parseUrl(url: string) { - return encodeURI(url); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/index.ts b/packages/typedoc-plugin-markdown/src/theme/resources/index.ts deleted file mode 100644 index f84cb24e8..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/index.ts +++ /dev/null @@ -1,162 +0,0 @@ -// THIS FILE IS AUTO GENERATED. DO NOT EDIT DIRECTLY. -import { MarkdownThemeRenderContext } from '../..'; - -import { - memberTemplate, - projectTemplate, - readmeTemplate, - reflectionTemplate, -} from './templates'; - -import { - breadcrumbs, - commentParts, - comment, - header, - pageIndex, - reflectionIndex, - linkTo, - parametersList, - typeParametersList, - accessorMember, - constructorMember, - declarationMemberIdentifier, - declarationMember, - memberHierarchy, - indexSignatureTitle, - inheritance, - referenceMember, - reflectionMember, - signatureMemberIdentifier, - signatureParameters, - signatureMemberReturns, - signatureMember, - sources, - memberTitle, - member, - typeDeclarationMember, - members, - pageTitle, - reflectionFlags, - enumMembersTable, - parametersTable, - propertiesTable, - typeDeclarationTable, - typeParametersTable, - typeArguments, - arrayType, - conditionalType, - declarationType, - functionType, - indexAccessType, - inferredType, - intersectionType, - intrinsicType, - literalType, - namedTupleType, - queryType, - referenceType, - reflectionType, - someType, - tupleType, - typeOperatorType, - unionType, - unknownType, -} from './partials'; - -import { - flattenDeclarations, - getDeclarationType, - getIndexTitle, - getKeyword, - getModifier, - getParameterDefaultValue, - isGroupKind, - parseComments, - parseUrl, -} from './helpers'; - -function bind(fn: (f: F, ...a: L) => R, first: F) { - return (...args: L) => fn(first, ...args); -} - -export const templates = (context: MarkdownThemeRenderContext) => { - return { - memberTemplate: bind(memberTemplate, context), - projectTemplate: bind(projectTemplate, context), - readmeTemplate: bind(readmeTemplate, context), - reflectionTemplate: bind(reflectionTemplate, context), - }; -}; - -export const partials = (context: MarkdownThemeRenderContext) => { - return { - breadcrumbs: bind(breadcrumbs, context), - commentParts: bind(commentParts, context), - comment: bind(comment, context), - header: bind(header, context), - pageIndex: bind(pageIndex, context), - reflectionIndex: bind(reflectionIndex, context), - linkTo: bind(linkTo, context), - parametersList: bind(parametersList, context), - typeParametersList: bind(typeParametersList, context), - accessorMember: bind(accessorMember, context), - constructorMember: bind(constructorMember, context), - declarationMemberIdentifier: bind(declarationMemberIdentifier, context), - declarationMember: bind(declarationMember, context), - memberHierarchy: bind(memberHierarchy, context), - indexSignatureTitle: bind(indexSignatureTitle, context), - inheritance: bind(inheritance, context), - referenceMember: bind(referenceMember, context), - reflectionMember: bind(reflectionMember, context), - signatureMemberIdentifier: bind(signatureMemberIdentifier, context), - signatureParameters: bind(signatureParameters, context), - signatureMemberReturns: bind(signatureMemberReturns, context), - signatureMember: bind(signatureMember, context), - sources: bind(sources, context), - memberTitle: bind(memberTitle, context), - member: bind(member, context), - typeDeclarationMember: bind(typeDeclarationMember, context), - members: bind(members, context), - pageTitle: bind(pageTitle, context), - reflectionFlags: bind(reflectionFlags, context), - enumMembersTable: bind(enumMembersTable, context), - parametersTable: bind(parametersTable, context), - propertiesTable: bind(propertiesTable, context), - typeDeclarationTable: bind(typeDeclarationTable, context), - typeParametersTable: bind(typeParametersTable, context), - typeArguments: bind(typeArguments, context), - arrayType: bind(arrayType, context), - conditionalType: bind(conditionalType, context), - declarationType: bind(declarationType, context), - functionType: bind(functionType, context), - indexAccessType: bind(indexAccessType, context), - inferredType: bind(inferredType, context), - intersectionType: bind(intersectionType, context), - intrinsicType: bind(intrinsicType, context), - literalType: bind(literalType, context), - namedTupleType: bind(namedTupleType, context), - queryType: bind(queryType, context), - referenceType: bind(referenceType, context), - reflectionType: bind(reflectionType, context), - someType: bind(someType, context), - tupleType: bind(tupleType, context), - typeOperatorType: bind(typeOperatorType, context), - unionType: bind(unionType, context), - unknownType: bind(unknownType, context), - }; -}; - -export const helpers = () => { - return { - flattenDeclarations: flattenDeclarations, - getDeclarationType: getDeclarationType, - getIndexTitle: getIndexTitle, - getKeyword: getKeyword, - getModifier: getModifier, - getParameterDefaultValue: getParameterDefaultValue, - isGroupKind: isGroupKind, - parseComments: parseComments, - parseUrl: parseUrl, - }; -}; diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/breadcrumbs.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/breadcrumbs.ts deleted file mode 100644 index c62780270..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/breadcrumbs.ts +++ /dev/null @@ -1,60 +0,0 @@ -import * as path from 'path'; -import { DeclarationReflection, ProjectReflection } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { MarkdownPageEvent } from '../../..'; -import { escapeChars } from '../utils'; - -export function breadcrumbs( - context: MarkdownThemeRenderContext, - page: MarkdownPageEvent, -): string { - const md: string[] = []; - - const fileExtension = context.options.getValue('fileExtension'); - const entryFileName = `${path.parse(context.options.getValue('entryFileName')).name}${fileExtension}`; - - if ( - page.url === page.project.url || - ((page.url === entryFileName || page.url === 'readme_.md') && - page.url.split(path.sep).length === 1) - ) { - return ''; - } - - const homeLabel = context.helpers.getIndexTitle( - context.text.getText('breadcrumbs.home'), - page.project.name, - page.project.packageVersion, - ); - - md.push(context.partials.linkTo(homeLabel, entryFileName)); - - const breadcrumb = (model: any) => { - if (model?.parent?.parent) { - breadcrumb(model.parent); - } - - const getUrl = (model: any) => { - if (Boolean(model.readme)) { - return `${path.dirname(model.url)}/${entryFileName}`; - } - return model.url; - }; - if (model.name !== context.options.getValue('entryModule')) { - md.push(context.partials.linkTo(escapeChars(model.name), getUrl(model))); - } - }; - - const pageName = escapeChars(page.model.name); - - if ( - page.model?.parent?.parent && - (page.url !== page.project.url || page.url !== entryFileName) - ) { - breadcrumb(page.model.parent); - } - - md.push(pageName); - - return md.length > 1 ? `${md.join(' / ')}` : ''; -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/comment.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/comment.ts deleted file mode 100644 index e4e652b9c..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/comment.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Comment } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { bold, heading } from '../markdown'; -import { camelToTitleCase, escapeComments } from '../utils'; - -export function comment( - context: MarkdownThemeRenderContext, - comment: Comment, - headingLevel?: number, - showSummary = true, - showTags = true, -): string { - const md: string[] = []; - - if (showSummary && comment.summary?.length > 0) { - md.push(context.partials.commentParts(comment.summary)); - } - - if (showTags && comment.blockTags?.length) { - const tags = comment.blockTags - .filter((tag) => tag.tag !== '@returns') - .map((tag) => { - const tagName = tag.tag.substring(1); - const tagText = camelToTitleCase(tagName); - const tagMd = [ - headingLevel ? heading(headingLevel, tagText) + '\n' : bold(tagText), - ]; - tagMd.push(context.partials.commentParts(tag.content)); - return tagMd.join('\n'); - }); - md.push(tags.join('\n\n')); - } - - return context.helpers.parseComments(escapeComments(md.join('\n\n'))); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/header.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/header.ts deleted file mode 100644 index 101b4822c..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/header.ts +++ /dev/null @@ -1,162 +0,0 @@ -import * as path from 'path'; -import { - DeclarationReflection, - EntryPointStrategy, - ProjectReflection, - ReflectionKind, -} from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { MarkdownPageEvent } from '../../..'; -import { bold, link } from '../markdown'; - -export function header( - context: MarkdownThemeRenderContext, - page: MarkdownPageEvent, -): string { - const isPackages = - context.options.getValue('entryPointStrategy') === - EntryPointStrategy.Packages; - if (isPackages) { - const packageItem = findPackage(page.model); - if (packageItem) { - return packageHeader(context, page); - } - } - return projectHeader(context, page); -} - -function projectHeader( - context: MarkdownThemeRenderContext, - page: MarkdownPageEvent, -) { - const fileExtension = context.options.getValue('fileExtension'); - const entryFileName = `${path.parse(context.options.getValue('entryFileName')).name}${fileExtension}`; - const titleLink = context.options.getValue('titleLink'); - - const md: string[] = []; - - const title = context.helpers.getIndexTitle( - context.text.getText('header.title'), - page.project.name, - page.project.packageVersion, - ); - - const readmeLabel = context.text.getText('header.readme'); - const indexLabel = context.text.getText('header.docs'); - - md.push(titleLink ? bold(link(title, titleLink)) : bold(title)); - - md.push('•'); - - const preserveReadme = - Boolean(page.project.readme) && !context.options.getValue('mergeReadme'); - - const useEntryModule = - (page.project?.groups && - Boolean( - page.project?.groups[0]?.children.find( - (child) => child.name === context.options.getValue('entryModule'), - ), - )) || - false; - - if (preserveReadme) { - const links: string[] = []; - const readMeUrl = useEntryModule - ? `readme_${fileExtension}` - : entryFileName; - - if (page.url === readMeUrl) { - links.push(readmeLabel); - } else { - links.push(context.partials.linkTo(readmeLabel, readMeUrl)); - } - - links.push('\\|'); - - const indexUrl = useEntryModule ? entryFileName : page.project.url; - - if (page.url === indexUrl) { - links.push(indexLabel); - } else { - links.push(context.partials.linkTo(indexLabel, indexUrl)); - } - - md.push(`${links.join(' ')}`); - } else { - if (useEntryModule || page.url === page.project.url) { - md.push(indexLabel); - } else { - md.push(context.partials.linkTo(indexLabel, page.project.url)); - } - } - - return `${md.join(' ')}\n\n***\n`; -} - -function packageHeader( - context: MarkdownThemeRenderContext, - page: MarkdownPageEvent, -) { - const packageItem = findPackage(page.model) as ProjectReflection; - - if (!packageItem) { - return ''; - } - - const md: string[] = []; - - const readmeLabel = context.text.getText('header.readme'); - const indexLabel = context.text.getText('header.docs'); - - const fileExtension = context.options.getValue('fileExtension'); - const entryFileName = `${path.parse(context.options.getValue('entryFileName')).name}${fileExtension}`; - - const packageItemName = packageItem.packageVersion - ? `${packageItem.name} v${packageItem.packageVersion}` - : packageItem.name; - - md.push(bold(packageItemName)); - - md.push('•'); - - const preservePackageReadme = - Boolean(packageItem.readme) && !context.options.getValue('mergeReadme'); - - if (preservePackageReadme) { - const links: string[] = []; - const readmeUrl = `${packageItem.name}/${entryFileName}`; - - if (page.url === readmeUrl) { - links.push(readmeLabel); - } else { - links.push(context.partials.linkTo(readmeLabel, readmeUrl)); - } - - links.push('\\|'); - - if (page.url === packageItem.url) { - links.push(indexLabel); - } else { - links.push(context.partials.linkTo(indexLabel, packageItem.url)); - } - md.push(`${links.join(' ')}`); - } else { - md.push(indexLabel); - } - - return `${md.join(' ')}\n\n***\n`; -} - -function findPackage(model: DeclarationReflection | ProjectReflection) { - if ( - model.kind === ReflectionKind.Module && - model.parent?.kind === ReflectionKind.Project - ) { - return model; - } - if (model.parent) { - return findPackage(model.parent as DeclarationReflection); - } - return null; -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/index.page.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/index.page.ts deleted file mode 100644 index 71b888a7f..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/index.page.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as path from 'path'; -import { - DeclarationReflection, - EntryPointStrategy, - ProjectReflection, -} from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { MarkdownPageEvent } from '../../..'; -import { heading } from '../markdown'; -import { escapeChars } from '../utils'; - -export function pageIndex( - context: MarkdownThemeRenderContext, - page: MarkdownPageEvent, - headingLevel: number, -): string { - const md: string[] = []; - - if (page.model?.groups?.some((group) => group.allChildrenHaveOwnDocument())) { - md.push(context.partials.reflectionIndex(page.model, headingLevel)); - return md.join('\n\n'); - } - - const isPackages = - page.project.url === page.url && - context.options.getValue('entryPointStrategy') === - EntryPointStrategy.Packages; - - if (isPackages && page.model.children?.length) { - md.push(heading(headingLevel, context.text.getText('label.packages'))); - const packagesList = page.model.children?.map((projectPackage) => { - const urlTo = Boolean(projectPackage.readme) - ? `${path.dirname(projectPackage.url || '')}/${context.options.getValue( - 'entryFileName', - )}` - : projectPackage.url; - return `- ${context.partials.linkTo( - escapeChars(projectPackage.name), - urlTo, - )}`; - }); - md.push(packagesList?.join('\n') || ''); - return md.join('\n\n'); - } - - return md.join('\n\n'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/index.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/index.ts deleted file mode 100644 index 2c2477968..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/index.ts +++ /dev/null @@ -1,53 +0,0 @@ -export { breadcrumbs } from './breadcrumbs'; -export { commentParts } from './comment.parts'; -export { comment } from './comment'; -export { header } from './header'; -export { pageIndex } from './index.page'; -export { reflectionIndex } from './index.reflection'; -export { linkTo } from './link-to'; -export { parametersList } from './list.parameters'; -export { typeParametersList } from './list.typeparameters'; -export { accessorMember } from './member.accessor'; -export { constructorMember } from './member.constructors'; -export { declarationMemberIdentifier } from './member.declaration.identifier'; -export { declarationMember } from './member.declaration'; -export { memberHierarchy } from './member.hierarchy'; -export { indexSignatureTitle } from './member.indexsignature.title'; -export { inheritance } from './member.inheritance'; -export { referenceMember } from './member.reference'; -export { reflectionMember } from './member.reflection'; -export { signatureMemberIdentifier } from './member.signature.identifier'; -export { signatureParameters } from './member.signature.parameters'; -export { signatureMemberReturns } from './member.signature.returns'; -export { signatureMember } from './member.signature'; -export { sources } from './member.sources'; -export { memberTitle } from './member.title'; -export { member } from './member'; -export { typeDeclarationMember } from './member.type-declaration'; -export { members } from './members'; -export { pageTitle } from './page.title'; -export { reflectionFlags } from './reflection.flags'; -export { enumMembersTable } from './table.enum-members'; -export { parametersTable } from './table.parameters'; -export { propertiesTable } from './table.properties'; -export { typeDeclarationTable } from './table.type-declaration'; -export { typeParametersTable } from './table.typeparameters'; -export { typeArguments } from './type-argumentsts'; -export { arrayType } from './type.array'; -export { conditionalType } from './type.conditional'; -export { declarationType } from './type.declaration'; -export { functionType } from './type.function'; -export { indexAccessType } from './type.index-access'; -export { inferredType } from './type.inferred'; -export { intersectionType } from './type.intersection'; -export { intrinsicType } from './type.intrinsic'; -export { literalType } from './type.literal'; -export { namedTupleType } from './type.named-tuple'; -export { queryType } from './type.query'; -export { referenceType } from './type.reference'; -export { reflectionType } from './type.reflection'; -export { someType } from './type.some'; -export { tupleType } from './type.tuple'; -export { typeOperatorType } from './type.type-operator'; -export { unionType } from './type.union'; -export { unknownType } from './type.unknown'; \ No newline at end of file diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/link-to.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/link-to.ts deleted file mode 100644 index 44aae1f94..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/link-to.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as path from 'path'; -import { MarkdownThemeRenderContext } from '../..'; -import { link } from '../markdown'; -import { getRelativeUrl } from '../utils'; - -export function linkTo( - context: MarkdownThemeRenderContext, - label: string, - url?: string, -) { - const URL_PREFIX = /^(http|ftp)s?:\/\//; - - if (typeof url !== 'string') { - return label; - } - if (URL_PREFIX.test(url)) { - return link(label, url); - } else { - const publicPath = context.options.getValue('publicPath'); - - if (publicPath) { - return link(label, context.helpers.parseUrl(path.join(publicPath, url))); - } - - const relativeUrl = getRelativeUrl(url, context.page?.url); - - return link(label, context.helpers.parseUrl(relativeUrl)); - } -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.declaration.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.declaration.ts deleted file mode 100644 index 51c21b49a..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.declaration.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { - DeclarationReflection, - IntersectionType, - ReferenceType, - ReflectionKind, - ReflectionType, -} from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { heading } from '../markdown'; - -export function declarationMember( - context: MarkdownThemeRenderContext, - declaration: DeclarationReflection, - headingLevel: number, - nested = false, -): string { - const md: string[] = []; - - md.push(context.partials.reflectionFlags(declaration)); - - md.push(context.partials.declarationMemberIdentifier(declaration)); - - const typeDeclaration = (declaration.type as any) - ?.declaration as DeclarationReflection; - - if ( - !typeDeclaration?.signatures?.every((signature) => - Boolean(signature.comment), - ) - ) { - if (declaration.comment) { - md.push(context.partials.comment(declaration.comment, headingLevel)); - } - } - - if (declaration.type instanceof IntersectionType) { - declaration.type?.types?.forEach((intersectionType) => { - if ( - intersectionType instanceof ReflectionType && - !intersectionType.declaration.signatures - ) { - md.push( - heading(headingLevel, context.text.getText('label.typeDeclaration')), - ); - md.push( - context.partials.typeDeclarationMember( - intersectionType.declaration, - headingLevel, - ), - ); - } - }); - } - - if ( - declaration.type instanceof ReferenceType && - declaration.type.typeArguments?.length - ) { - if (declaration.type.typeArguments[0] instanceof ReflectionType) { - md.push( - heading(headingLevel, context.text.getText('label.typeDeclaration')), - ); - md.push( - context.partials.typeDeclarationMember( - declaration.type.typeArguments[0].declaration, - headingLevel, - ), - ); - } - } - - if (declaration.typeParameters) { - md.push( - heading(headingLevel, context.text.getText('kind.typeParameter.plural')), - ); - if (context.options.getValue('parametersFormat') === 'table') { - md.push(context.partials.typeParametersTable(declaration.typeParameters)); - } else { - md.push(context.partials.typeParametersList(declaration.typeParameters)); - } - } - - if (typeDeclaration) { - if (typeDeclaration?.indexSignature) { - md.push( - heading(headingLevel, context.text.getText('label.indexSignature')), - ); - md.push( - context.partials.indexSignatureTitle(typeDeclaration.indexSignature), - ); - } - - if (typeDeclaration?.signatures?.length) { - typeDeclaration.signatures.forEach((signature) => { - md.push( - context.partials.signatureMember(signature, headingLevel, true), - ); - }); - } - - if (typeDeclaration?.children?.length) { - const useHeading = - declaration.kind !== ReflectionKind.Property || - context.options.getValue('propertiesFormat') == 'table'; - if (!nested && typeDeclaration?.children?.length) { - if (useHeading) { - md.push( - heading( - headingLevel, - context.text.getText('label.typeDeclaration'), - ), - ); - } - md.push( - context.partials.typeDeclarationMember( - typeDeclaration, - useHeading ? headingLevel : headingLevel - 1, - declaration.kind === ReflectionKind.Property - ? declaration - : undefined, - ), - ); - } - } - } - - md.push(context.partials.inheritance(declaration, headingLevel)); - - if ( - !nested && - declaration.sources && - !context.options.getValue('disableSources') - ) { - md.push(context.partials.sources(declaration, headingLevel)); - } - - return md.join('\n\n'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.reflection.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.reflection.ts deleted file mode 100644 index 4e4cd53e3..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.reflection.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { DeclarationReflection } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { heading, unorderedList } from '../markdown'; - -export function reflectionMember( - context: MarkdownThemeRenderContext, - reflection: DeclarationReflection, - headingLevel: number, -): string { - const md: string[] = []; - - if (reflection.comment) { - md.push(context.partials.comment(reflection.comment, headingLevel)); - } - - if (reflection.typeHierarchy?.next) { - md.push( - context.partials.memberHierarchy(reflection.typeHierarchy, headingLevel), - ); - } - - if (reflection.typeParameters) { - md.push( - heading(headingLevel, context.text.getText('kind.typeParameter.plural')), - ); - if (context.options.getValue('parametersFormat') === 'table') { - md.push(context.partials.typeParametersTable(reflection.typeParameters)); - } else { - md.push(context.partials.typeParametersList(reflection.typeParameters)); - } - } - - if (reflection.implementedTypes) { - md.push(heading(headingLevel, context.text.getText('label.implements'))); - md.push( - unorderedList( - reflection.implementedTypes.map((implementedType) => - context.partials.someType(implementedType), - ), - ), - ); - } - - if ('signatures' in reflection && reflection.signatures) { - reflection.signatures.forEach((signature) => { - md.push(context.partials.signatureMember(signature, headingLevel)); - }); - } - - if ('indexSignature' in reflection && reflection.indexSignature) { - md.push(heading(headingLevel, context.text.getText('label.indexable'))); - md.push(context.partials.indexSignatureTitle(reflection.indexSignature)); - } - - if (reflection?.groups?.some((group) => group.allChildrenHaveOwnDocument())) { - const isAbsolute = reflection.groups?.every((group) => - group.allChildrenHaveOwnDocument(), - ); - if (isAbsolute) { - md.push(heading(headingLevel, context.text.getText('label.index'))); - } - md.push( - context.partials.reflectionIndex( - reflection, - isAbsolute ? headingLevel + 1 : headingLevel, - ), - ); - } - - md.push(context.partials.members(reflection, headingLevel)); - - return md.join('\n\n'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.ts deleted file mode 100644 index de8b19507..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.signature.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { ReflectionKind, SignatureReflection } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { heading } from '../markdown'; - -export function signatureMember( - context: MarkdownThemeRenderContext, - signature: SignatureReflection, - headingLevel: number, - nested = false, - accessor?: string, -): string { - const md: string[] = []; - - md.push(context.partials.reflectionFlags(signature)); - - if (!nested) { - md.push( - context.partials.signatureMemberIdentifier(signature, { - accessor, - }), - ); - } - - if (signature.comment) { - md.push( - context.partials.comment(signature.comment, headingLevel, true, false), - ); - } - - if ( - signature.typeParameters?.length && - signature.kind !== ReflectionKind.ConstructorSignature - ) { - md.push( - heading(headingLevel, context.text.getText('kind.typeParameter.plural')), - ); - if (context.options.getValue('parametersFormat') === 'table') { - md.push(context.partials.typeParametersTable(signature.typeParameters)); - } else { - md.push(context.partials.typeParametersList(signature.typeParameters)); - } - } - - if (signature.parameters?.length) { - md.push( - heading(headingLevel, context.text.getText('kind.parameter.plural')), - ); - if (context.options.getValue('parametersFormat') === 'table') { - md.push(context.partials.parametersTable(signature.parameters)); - } else { - md.push(context.partials.parametersList(signature.parameters)); - } - } - - if (signature.type) { - md.push(context.partials.signatureMemberReturns(signature, headingLevel)); - } - - md.push(context.partials.inheritance(signature, headingLevel)); - - if (signature.comment) { - md.push( - context.partials.comment(signature.comment, headingLevel, false, true), - ); - } - - if ( - !nested && - signature.sources && - !context.options.getValue('disableSources') - ) { - md.push(context.partials.sources(signature, headingLevel)); - } - - return md.join('\n\n'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.type-declaration.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.type-declaration.ts deleted file mode 100644 index cd06bb8db..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/member.type-declaration.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { DeclarationReflection } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; - -export function typeDeclarationMember( - context: MarkdownThemeRenderContext, - typeDeclaration: DeclarationReflection, - headingLevel: number, - parentDeclaration?: DeclarationReflection, -): string { - const md: string[] = []; - - if (typeDeclaration.children) { - if (context.options.getValue('typeDeclarationFormat') === 'table') { - md.push(context.partials.typeDeclarationTable(typeDeclaration.children)); - } else { - const declarations = context.helpers.flattenDeclarations( - typeDeclaration.children, - false, - ); - declarations?.forEach((declaration: DeclarationReflection) => { - md.push( - context.partials.member( - declaration, - headingLevel + 1, - true, - parentDeclaration, - ), - ); - }); - } - } - return md.join('\n\n'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/members.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/members.ts deleted file mode 100644 index 8023950f6..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/members.ts +++ /dev/null @@ -1,123 +0,0 @@ -import { - ContainerReflection, - DeclarationReflection, - ReflectionCategory, - ReflectionKind, -} from 'typedoc'; - -import { MarkdownThemeRenderContext } from '../..'; -import { heading, horizontalRule } from '../markdown'; - -export function members( - context: MarkdownThemeRenderContext, - container: ContainerReflection, - headingLevel: number, -): string { - const md: string[] = []; - - const displayHr = (reflection: DeclarationReflection) => { - if (context.options.getValue('outputFileStrategy') === 'modules') { - return context.helpers.isGroupKind(reflection); - } - return true; - }; - - const pushCategories = ( - categories: ReflectionCategory[], - headingLevel: number, - ) => { - categories - ?.filter((category) => !category.allChildrenHaveOwnDocument()) - .forEach((item) => { - md.push(heading(headingLevel, item.title)); - pushChildren(item.children, headingLevel + 1); - }); - }; - - const pushChildren = ( - children?: DeclarationReflection[], - memberHeadingLevel?: number, - ) => { - const items = children?.filter((item) => !item.hasOwnDocument); - items?.forEach((item, index) => { - md.push( - context.partials.member(item, memberHeadingLevel || headingLevel), - ); - if (index < items.length - 1 && displayHr(item)) { - md.push(horizontalRule()); - } - }); - }; - - if (container.categories?.length) { - pushCategories(container.categories, headingLevel); - } else { - const containerKinds = [ - ReflectionKind.Project, - ReflectionKind.Module, - ReflectionKind.Namespace, - ]; - if ( - context.options.getValue('excludeGroups') && - containerKinds.includes(container.kind) - ) { - if (container.categories?.length) { - pushCategories(container.categories, headingLevel); - } else { - pushChildren(container.children, headingLevel); - } - } else { - const groupsWithChildren = container.groups?.filter( - (group) => !group.allChildrenHaveOwnDocument(), - ); - groupsWithChildren?.forEach((group, index: number) => { - if (group.categories) { - md.push( - heading( - headingLevel, - context.text.getTextFromKindString(group.title, true), - ), - ); - pushCategories(group.categories, headingLevel + 1); - } else { - const isPropertiesGroup = group.children.every( - (child) => child.kind === ReflectionKind.Property, - ); - - const isEnumGroup = group.children.every( - (child) => child.kind === ReflectionKind.EnumMember, - ); - - md.push( - heading( - headingLevel, - context.text.getTextFromKindString(group.title, true), - ), - ); - - if ( - isPropertiesGroup && - context.options.getValue('propertiesFormat') === 'table' - ) { - md.push( - context.partials.propertiesTable( - group.children, - context.text.getTextFromKindString(group.title, true) === - context.text.getText('kind.event.plural'), - ), - ); - } else if ( - isEnumGroup && - context.options.getValue('enumMembersFormat') === 'table' - ) { - md.push(context.partials.enumMembersTable(group.children)); - } else { - pushChildren(group.children, headingLevel + 1); - } - } - }); - } - } - - return md.join('\n\n'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/page.title.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/page.title.ts deleted file mode 100644 index 8eba2f4b8..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/page.title.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { - DeclarationReflection, - ProjectReflection, - ReflectionKind, -} from 'typedoc'; -import { MarkdownPageEvent, MarkdownThemeRenderContext } from '../../..'; - -export function pageTitle( - context: MarkdownThemeRenderContext, - page: MarkdownPageEvent, -): string { - if (page.model?.url === page.project.url) { - const titleContent = context.options.isSet('indexPageTitle') - ? context.options.getValue('indexPageTitle') - : context.text.getText('title.indexPage'); - return context.helpers.getIndexTitle( - titleContent, - page.project.name, - page.project.packageVersion, - ); - } - - const name = context.partials.memberTitle( - page.model as DeclarationReflection, - ); - - const textContent = - page.model.kind === ReflectionKind.Module - ? context.text.getText('title.modulePage') - : context.options.isSet('memberPageTitle') - ? context.options.getValue('memberPageTitle') - : context.text.getText('title.memberPage'); - - return textContent - .replace('{name}', name) - .replace( - '{kind}', - context.text.getTextFromKindString( - ReflectionKind.singularString(page.model.kind), - ), - ); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.array.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.array.ts deleted file mode 100644 index e233ae2d6..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.array.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ArrayType } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; - -export function arrayType( - context: MarkdownThemeRenderContext, - arrayType: ArrayType, -): string { - const theType = context.partials.someType(arrayType.elementType); - return arrayType.elementType.type === 'union' - ? `(${theType})[]` - : `${theType}[]`; -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.conditional.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.conditional.ts deleted file mode 100644 index a4579a41d..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.conditional.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ConditionalType } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; - -export function conditionalType( - context: MarkdownThemeRenderContext, - conditionalType: ConditionalType, -): string { - const md: string[] = []; - if (conditionalType.checkType) { - md.push(context.partials.someType(conditionalType.checkType)); - } - md.push('extends'); - if (conditionalType.extendsType) { - md.push(context.partials.someType(conditionalType.extendsType)); - } - md.push('?'); - if (conditionalType.trueType) { - md.push(context.partials.someType(conditionalType.trueType)); - } - md.push(':'); - if (conditionalType.falseType) { - md.push(context.partials.someType(conditionalType.falseType)); - } - return md.join(' '); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.literal.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.literal.ts deleted file mode 100644 index 7fd62cc31..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.literal.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { LiteralType } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; - -export function literalType( - context: MarkdownThemeRenderContext, - literalType: LiteralType, -): string { - if (typeof literalType.value === 'bigint') { - return `\`${literalType.value}n\``; - } - return `\`\`${JSON.stringify(literalType.value)}\`\``; -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.query.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.query.ts deleted file mode 100644 index 02af2d37d..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.query.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { QueryType } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { italic } from '../markdown'; - -export function queryType( - context: MarkdownThemeRenderContext, - queryType: QueryType, -): string { - return `${italic('typeof')} ${context.partials.someType( - queryType.queryType, - )}`; -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.reference.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.reference.ts deleted file mode 100644 index 7021c6abc..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.reference.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { ReferenceType } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { backTicks } from '../markdown'; - -export function referenceType( - context: MarkdownThemeRenderContext, - referenceType: ReferenceType, -): string { - if ( - referenceType.reflection || - (referenceType.name && referenceType.typeArguments) - ) { - const reflection: string[] = []; - - if (referenceType.reflection?.url) { - reflection.push( - context.partials.linkTo( - backTicks(referenceType.reflection.name), - referenceType.reflection.url, - ), - ); - } else { - reflection.push( - referenceType.externalUrl - ? context.partials.linkTo( - backTicks(referenceType.name), - referenceType.externalUrl, - ) - : backTicks(referenceType.name), - ); - } - if (referenceType.typeArguments && referenceType.typeArguments.length) { - reflection.push( - context.partials.typeArguments(referenceType.typeArguments), - ); - } - return reflection.join(''); - } - return referenceType.externalUrl - ? `[${backTicks(referenceType.name)}]( ${referenceType.externalUrl} )` - : backTicks(referenceType.name); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.some.ts b/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.some.ts deleted file mode 100644 index 73603c33e..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/partials/type.some.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { - ArrayType, - ConditionalType, - IndexedAccessType, - InferredType, - IntersectionType, - IntrinsicType, - NamedTupleMember, - QueryType, - ReferenceType, - ReflectionType, - SomeType, - TupleType, - TypeOperatorType, - UnionType, - UnknownType, -} from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { backTicks } from '../markdown'; - -export function someType( - context: MarkdownThemeRenderContext, - someType: SomeType, -): string { - if (!someType) { - return ''; - } - - if (someType instanceof ArrayType) { - return context.partials.arrayType(someType); - } - - if (someType instanceof ConditionalType) { - return context.partials.conditionalType(someType); - } - - if (someType instanceof IndexedAccessType) { - return context.partials.indexAccessType(someType); - } - - if (someType instanceof InferredType) { - return context.partials.inferredType(someType); - } - - if (someType instanceof IntersectionType && someType.types) { - return context.partials.intersectionType(someType); - } - - if (someType instanceof IntrinsicType && someType.name) { - return context.partials.intrinsicType(someType); - } - - if (someType instanceof QueryType) { - return context.partials.queryType(someType); - } - - if (someType instanceof ReferenceType) { - return context.partials.referenceType(someType); - } - - if (someType instanceof ReflectionType) { - return context.partials.reflectionType(someType); - } - - if (someType instanceof TypeOperatorType) { - return context.partials.typeOperatorType(someType); - } - - if (someType instanceof TupleType && someType.elements) { - return context.partials.tupleType(someType); - } - - if (someType instanceof UnionType && someType.types) { - return context.partials.unionType(someType); - } - - if (someType instanceof UnknownType) { - return context.partials.unknownType(someType); - } - - if (someType instanceof NamedTupleMember) { - return context.partials.namedTupleType(someType); - } - - if (someType.toString() == 'null') { - return backTicks('null'); - } - - return backTicks(someType?.toString()); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/templates/index.ts b/packages/typedoc-plugin-markdown/src/theme/resources/templates/index.ts deleted file mode 100644 index 9076fd795..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/templates/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { memberTemplate } from './member'; -export { projectTemplate } from './project'; -export { readmeTemplate } from './read-me'; -export { reflectionTemplate } from './reflection'; \ No newline at end of file diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/templates/member.ts b/packages/typedoc-plugin-markdown/src/theme/resources/templates/member.ts deleted file mode 100644 index ffea0f9f1..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/templates/member.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { DeclarationReflection } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { MarkdownHooks, MarkdownPageEvent } from '../../..'; -import { heading } from '../markdown'; - -export function memberTemplate( - context: MarkdownThemeRenderContext, - page: MarkdownPageEvent, -) { - const md: string[] = []; - - md.push(context.hook(MarkdownHooks.PAGE_BEGIN).join('\n')); - - if (!context.options.getValue('hidePageHeader')) { - md.push(context.partials.header(page)); - } - - if (!context.options.getValue('hideBreadcrumbs')) { - md.push(context.partials.breadcrumbs(page)); - } - - if (!context.options.getValue('hidePageTitle')) { - md.push(heading(1, context.partials.pageTitle(page))); - } - - md.push(context.hook(MarkdownHooks.CONTENT_BEGIN).join('\n')); - - md.push(context.partials.member(page.model, 1)); - - md.push(context.hook(MarkdownHooks.PAGE_END).join('\n')); - - return md.join('\n\n'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/templates/project.ts b/packages/typedoc-plugin-markdown/src/theme/resources/templates/project.ts deleted file mode 100644 index 87e316fbc..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/templates/project.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { ProjectReflection } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { MarkdownHooks, MarkdownPageEvent } from '../../..'; -import { heading } from '../markdown'; - -export function projectTemplate( - context: MarkdownThemeRenderContext, - page: MarkdownPageEvent, -) { - const md: string[] = []; - - md.push(context.hook(MarkdownHooks.INDEX_PAGE_BEGIN).join('\n')); - - if (!context.options.getValue('hidePageHeader')) { - md.push(context.partials.header(page)); - } - - if (!context.options.getValue('hideBreadcrumbs')) { - md.push(context.partials.breadcrumbs(page)); - } - - const includeReadme = - context.options.getValue('mergeReadme') && Boolean(page.model.readme); - - if (includeReadme && page.model.readme) { - md.push(context.partials.commentParts(page.model.readme)); - } - - if (!context.options.getValue('hidePageTitle') && !includeReadme) { - md.push(heading(1, context.partials.pageTitle(page))); - } - - md.push(context.hook(MarkdownHooks.INDEX_CONTENT_BEGIN).join('\n')); - - if (page.model.comment) { - md.push(context.partials.comment(page.model.comment, 2)); - } - - md.push(context.partials.pageIndex(page, 2)); - - md.push(context.partials.members(page.model, 2)); - - md.push(context.hook(MarkdownHooks.INDEX_PAGE_END).join('\n')); - - return md.join('\n\n'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/templates/read-me.ts b/packages/typedoc-plugin-markdown/src/theme/resources/templates/read-me.ts deleted file mode 100644 index 7c18ea229..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/templates/read-me.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ProjectReflection } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { MarkdownPageEvent } from '../../..'; - -export function readmeTemplate( - context: MarkdownThemeRenderContext, - page: MarkdownPageEvent, -) { - const md: string[] = []; - - if (!context.options.getValue('hidePageHeader')) { - md.push(context.partials.header(page)); - } - - if (!context.options.getValue('hideBreadcrumbs')) { - md.push(context.partials.breadcrumbs(page)); - } - - if (page.model.readme) { - md.push(context.partials.commentParts(page.model.readme)); - } - - return md.join('\n\n'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/templates/reflection.ts b/packages/typedoc-plugin-markdown/src/theme/resources/templates/reflection.ts deleted file mode 100644 index 658d9c5ec..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/templates/reflection.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { DeclarationReflection } from 'typedoc'; -import { MarkdownThemeRenderContext } from '../..'; -import { MarkdownHooks, MarkdownPageEvent } from '../../..'; -import { heading } from '../markdown'; - -export function reflectionTemplate( - context: MarkdownThemeRenderContext, - page: MarkdownPageEvent, -) { - const md: string[] = []; - - md.push(context.hook(MarkdownHooks.PAGE_BEGIN).join('\n')); - - if (!context.options.getValue('hidePageHeader')) { - md.push(context.partials.header(page)); - } - - if (!context.options.getValue('hideBreadcrumbs')) { - md.push(context.partials.breadcrumbs(page)); - } - - if (!context.options.getValue('hidePageTitle')) { - md.push(heading(1, context.partials.pageTitle(page))); - } - - md.push(context.hook(MarkdownHooks.CONTENT_BEGIN).join('\n')); - - md.push(context.partials.reflectionMember(page.model, 2)); - - md.push(context.hook(MarkdownHooks.PAGE_END).join('\n')); - - return md.join('\n\n'); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/utils/escape-comments.ts b/packages/typedoc-plugin-markdown/src/theme/resources/utils/escape-comments.ts deleted file mode 100644 index 97874b0a6..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/utils/escape-comments.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Escapes non html tag angle brackets by wrapping inside backticks. - * - * Ignores strings inside code blocks - */ -export function escapeComments(str: string) { - const re = /<(?=(?:[^`]*`[^`]*`)*[^`]*$)[^<]+?>/gi; - const codeBlocks: string[] = []; - const placeholder = '___CODEBLOCKPLACEHOLDER___'; - - // Replace code blocks with placeholders - str = str.replace(/(```[\s\S]*?```|`[^`]*?`)/g, (match) => { - codeBlocks.push(match); - return placeholder; - }); - - // Perform escaping outside of code blocks - // - Wrap non-html tags in code blocks - // - Escape non-JSX curly braces - str = str - .replace(re, (tags) => { - const htmlRe = - /<(?!\/?(div|span|p|a|br|img|ul|li|strike|em|strong|b)(>|\s))[^<]+?>/g; - const shouldEscapeTags = tags.match(htmlRe); - return shouldEscapeTags - ? tags.replace(/>/g, '>`').replace(/ codeBlocks.shift() || '', - ); - - return str; -} diff --git a/packages/typedoc-plugin-markdown/src/theme/resources/utils/get-relative-url.ts b/packages/typedoc-plugin-markdown/src/theme/resources/utils/get-relative-url.ts deleted file mode 100644 index f8e23c9ed..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/resources/utils/get-relative-url.ts +++ /dev/null @@ -1,8 +0,0 @@ -import * as path from 'path'; -export function getRelativeUrl(url: string, root?: string) { - const baseUrl = path.relative(path.dirname(root || '.'), path.dirname(url)); - const relativeUrl = path - .join(baseUrl, path.basename(url)) - .replace(/\\/g, '/'); - return relativeUrl; -} diff --git a/packages/typedoc-plugin-markdown/src/theme/theme-render-context.ts b/packages/typedoc-plugin-markdown/src/theme/theme-render-context.ts deleted file mode 100644 index 17a2645dd..000000000 --- a/packages/typedoc-plugin-markdown/src/theme/theme-render-context.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Options, Reflection } from 'typedoc'; -import { MarkdownPageEvent, MarkdownTheme } from '..'; -import { MarkdownRenderer, MarkdownRendererHooks } from '../plugin/types'; -import { text } from './core/text'; -import { helpers, partials, templates } from './resources'; -/** - * The render context of the {@link MarkdownTheme}. - * This follows the implementation of TypeDocs [DefaultThemeRenderContext](https://typedoc.org/api/classes/DefaultThemeRenderContext.html) - */ - -export class MarkdownThemeRenderContext { - /** - * @param page The page this context is created for. - * @param options The options used by TypeDoc. See TypeDoc's {@link typedoc!Options | Options} Class. - */ - constructor( - private theme: MarkdownTheme, - readonly page: MarkdownPageEvent | null, - readonly options: Options, - ) {} - - /** - * A set of methods to return strings from specific TypeDoc models. - * - * These can be consumed by theme templates and partials using the syntax `context.models.method()`. - */ - helpers = helpers(); - - /** - * The theme's global templates context. - */ - templates = templates(this); - - /** - * The theme's global partials context. - */ - partials = partials(this); - - /** - * Themes text content - */ - text = text(this.theme); - - /** - * Hook into the TypeDoc rendering system. - */ - hook = (name: keyof MarkdownRendererHooks) => - (this.theme.owner as MarkdownRenderer).markdownHooks.emit(name, this); -} diff --git a/packages/typedoc-plugin-markdown/src/theme/theme-types.ts b/packages/typedoc-plugin-markdown/src/theme/theme-types.ts new file mode 100644 index 000000000..0daa88233 --- /dev/null +++ b/packages/typedoc-plugin-markdown/src/theme/theme-types.ts @@ -0,0 +1,25 @@ +import { MarkdownPageEvent } from '@plugin/app/events'; + +import { ReflectionKind } from 'typedoc'; + +export interface NavigationItem { + title: string; + url?: string; + children?: NavigationItem[]; + isReadme?: boolean; + isGroup?: boolean; +} + +export interface TemplateMapping { + directory: string | null; + template: any; + kind: ReflectionKind; +} + +export interface UrlMapping { + url: string; + model: Model; + template: RenderTemplate>; +} + +export type RenderTemplate = (data: T) => string; diff --git a/packages/typedoc-plugin-markdown/test/fixtures/config.ts b/packages/typedoc-plugin-markdown/test/fixtures/config.ts index e276e832a..f0bc81c8a 100644 --- a/packages/typedoc-plugin-markdown/test/fixtures/config.ts +++ b/packages/typedoc-plugin-markdown/test/fixtures/config.ts @@ -109,7 +109,7 @@ const config: Record = { commonOptions: { plugin: [path.join(__dirname, 'custom-plugins', 'navigation-plugin.mjs')], entryPointStrategy: 'packages', - name: 'packages-example', + name: 'package-example', includeVersion: true, disableSources: true, }, @@ -159,9 +159,11 @@ const config: Record = { only: false, entryPoints: '/customize/index.ts', outputFileStrategies: ['members'], + commonOptions: { disableSources: true, readme: 'none', + preserveMarkup: true, }, options: [ { 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 70f3108e0..119dc6b64 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 @@ -1,7 +1,6 @@ // @ts-check import * as fs from 'fs'; import { - MarkdownHooks, MarkdownTheme, MarkdownThemeRenderContext, } from 'typedoc-plugin-markdown'; @@ -12,33 +11,30 @@ import { export function load(app) { app.renderer.defineTheme('custom-theme', MyMarkdownTheme); - app.renderer.markdownHooks.on( - MarkdownHooks.PAGE_BEGIN, - () => '> `page.begin` hook', - ); + app.renderer.markdownHooks.on('page.begin', () => '> `page.begin` hook'); app.renderer.markdownHooks.on( - MarkdownHooks.PAGE_END, + 'page.end', () => `**Generated using \`page.end\` hook**`, ); app.renderer.markdownHooks.on( - MarkdownHooks.CONTENT_BEGIN, + 'content.begin', () => '> `content.begin` hook', ); app.renderer.markdownHooks.on( - MarkdownHooks.INDEX_PAGE_BEGIN, + 'index.page.begin', () => '> `page.index.begin` hook', ); app.renderer.markdownHooks.on( - MarkdownHooks.INDEX_PAGE_END, + 'index.page.end', () => '> **Generated using `page.index.end` hook**', ); app.renderer.markdownHooks.on( - MarkdownHooks.INDEX_CONTENT_BEGIN, + 'index.content.begin', () => '> `content.index.begin` hook', ); @@ -90,14 +86,11 @@ class MyMarkdownThemeRenderContext extends MarkdownThemeRenderContext { }; partials = { ...this.partials, - /** - * @param {import('typedoc-plugin-markdown').MarkdownPageEvent} page - */ - header: (page) => { + header: () => { return `
My logo - Welcome to ${page.project.name} with a customised header partial!! + Welcome to ${this.page.project.name} with a customised header partial!!
`; }, diff --git a/packages/typedoc-plugin-markdown/test/fixtures/src/customize/index.ts b/packages/typedoc-plugin-markdown/test/fixtures/src/customize/index.ts index a9e53f12e..a66d4daee 100644 --- a/packages/typedoc-plugin-markdown/test/fixtures/src/customize/index.ts +++ b/packages/typedoc-plugin-markdown/test/fixtures/src/customize/index.ts @@ -1,9 +1,7 @@ /** * Module commments * - * :::warning Experimental - * `my-package` is under active development. - * ::: + * **Experimental** \`my-package\` is under active development. * * Some other comments * diff --git a/packages/typedoc-plugin-markdown/tsconfig.json b/packages/typedoc-plugin-markdown/tsconfig.json index 6f9b56ab6..d0e3e242a 100644 --- a/packages/typedoc-plugin-markdown/tsconfig.json +++ b/packages/typedoc-plugin-markdown/tsconfig.json @@ -1,7 +1,11 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "outDir": "./dist" + "outDir": "./dist", + "baseUrl": "src", + "paths": { + "@plugin/*": ["*"] + } }, "include": ["src/**/*.ts"], "exclude": ["./dist", "./test", "./scripts", "**/*.spec.ts"] diff --git a/packages/typedoc-plugin-markdown/typedoc-theme.cjs b/packages/typedoc-plugin-markdown/typedoc-theme.cjs new file mode 100644 index 000000000..84c617f95 --- /dev/null +++ b/packages/typedoc-plugin-markdown/typedoc-theme.cjs @@ -0,0 +1,57 @@ +// @ts-check + +const { MarkdownTheme } = require('./dist'); +const { Reflection, ProjectReflection, ReflectionKind } = require('typedoc'); +const path = require('path'); + +/** + * Local plugin to tweak TypeDoc output for nextra docs + * + * @param {import("./dist").MarkdownApplication} app + */ +module.exports.load = (app) => { + /** + * + * Define a custom theme so we amend the urls of the output. + */ + app.renderer.defineTheme('nextra', NextAuthDocsTheme); + + /*app.renderer.markdownHooks.on( + 'page.begin', + () => `import { Callout } from 'nextra/components';`, + );*/ +}; + +/** + * + */ +class NextAuthDocsTheme extends MarkdownTheme { + /** @param {import("typedoc").ProjectReflection} project */ + + getUrls(project) { + return super.getUrls(project).map((urlMapping) => { + if (urlMapping.model.kind === ReflectionKind.Project) { + return { + ...urlMapping, + url: `../${urlMapping.url}`, + }; + } + return urlMapping; + }); + } + + /*getUrl(reflection) { + const fullname = reflection.getFullName(); + const fullnameParts = fullname.split('.'); + if (reflection.kind !== ReflectionKind.Module) { + fullnameParts.splice( + fullnameParts.length - 1, + 0, + ReflectionKind.singularString(reflection.kind).split(' ')[0], + ); + } + const url = `${fullnameParts.join('.')}.mdx`; + reflection.url = url; + return url; + }*/ +} diff --git a/packages/typedoc-plugin-markdown/typedoc.base.json b/packages/typedoc-plugin-markdown/typedoc.base.json index cce5073fa..7b89bac66 100644 --- a/packages/typedoc-plugin-markdown/typedoc.base.json +++ b/packages/typedoc-plugin-markdown/typedoc.base.json @@ -1,24 +1,67 @@ { "entryPoints": [ - "./src/theme/theme-render-context.ts", - "./src/theme/resources/templates/index.ts", - "./src/theme/resources/partials/index.ts", - "./src/theme/resources/helpers/index.ts" + "./src/app/options", + "./src/app/events", + "./src/app/renderer", + "./src/theme", + "./src/theme/lib/*" ], "readme": "none", "excludePrivate": true, "excludeReferences": true, "excludeExternals": true, + "excludeProtected": true, + "excludeNotDocumented": false, + "hideParameterTypesInTitle": true, "sort": ["instance-first", "required-first"], + "groupOrder": [ + "Functions", + "Constructors", + "Properties", + "Templates", + "Methods", + "Namespaces", + "*" + ], + "categoryOrder": [ + "Page Partials", + "Container Partials", + "Comment Partials", + "Member Partials", + "Type Partials", + "Templates", + "*" + ], "cleanOutputDir": true, - "disableSources": true, - "excludeNotDocumentedKinds": ["Constructor"], + "disableSources": false, + "excludeNotDocumentedKinds": [], "externalSymbolLinkMappings": { "typedoc": { "Application": "https://typedoc.org/api/classes/Application.html", + "Comment": "https://typedoc.org/api/classes/Models.Comment.html", + "ArrayType": "https://typedoc.org/api/classes/Models.ArrayType.html", + "ConditionalType": "https://typedoc.org/api/classes/Models.ConditionalType.html", + "InferredType": "https://typedoc.org/api/classes/Models.InferredType.html", + "IntersectionType": "https://typedoc.org/api/classes/Models.IntersectionType.html", + "IntrinsicType": "https://typedoc.org/api/classes/Models.IntrinsicType.html", + "LiteralType": "https://typedoc.org/api/classes/Models.LiteralType.html", + "MappedType": "https://typedoc.org/api/classes/Models.MappedType.html", + "OptionalType": "https://typedoc.org/api/classes/Models.OptionalType.html", + "ParameterReflection": "https://typedoc.org/api/classes/Models.ParameterReflection.html", + "TypeParameterReflection": "https://typedoc.org/api/classes/Models.TypeParameterReflection.html", + "PredicateType": "https://typedoc.org/api/classes/Models.PredicateType.html", + "ReferenceType": "https://typedoc.org/api/classes/Models.ReferenceType.html", + "ReflectionType": "https://typedoc.org/api/classes/Models.ReflectionType.html", + "RestType": "https://typedoc.org/api/classes/Models.RestType.html", + "StringLiteralType": "https://typedoc.org/api/classes/Models.StringLiteralType.html", + "TupleType": "https://typedoc.org/api/classes/Models.TupleType.html", + "TypeOperatorType": "https://typedoc.org/api/classes/Models.TypeOperatorType.html", + "TypeParameterType": "https://typedoc.org/api/classes/Models.TypeParameterType.html", + "UnionType": "https://typedoc.org/api/classes/Models.UnionType.html", + "UnknownType": "https://typedoc.org/api/classes/Models.UnknownType.html", "CommentDisplayPart": "https://typedoc.org/api/types/Models.CommentDisplayPart.html", "DeclarationReflection": "https://typedoc.org/api/classes/Models.DeclarationReflection.html", - "DefaultThemeRenderContext": "https://typedoc.org/api/classes/DefaultThemeRenderContext.html", + "DefaultThemeRenderContext": "https://typedoc.org/api/classes/DefaultThemeRenderthis.html", "Options": "https://typedoc.org/api/classes/Configuration.Options.html", "PageEvent": "https://typedoc.org/api/classes/PageEvent.html", "ProjectReflection": "https://typedoc.org/api/classes/Models.ProjectReflection.html", diff --git a/packages/typedoc-plugin-markdown/typedoc.devdocs.json b/packages/typedoc-plugin-markdown/typedoc.devdocs.json new file mode 100644 index 000000000..448b79d01 --- /dev/null +++ b/packages/typedoc-plugin-markdown/typedoc.devdocs.json @@ -0,0 +1,16 @@ +{ + "extends": "./typedoc.md.json", + "plugin": ["typedoc-plugin-markdown", "typedoc-plugin-remark"], + + "out": "./plugin-docs", + "remarkPlugins": [ + [ + "remark-toc", + { + "maxDepth": 5, + "tight": true, + "skip": "Parameters|Returns|Source|Overrides|Inherited from" + } + ] + ] +} diff --git a/packages/typedoc-plugin-markdown/typedoc.md.json b/packages/typedoc-plugin-markdown/typedoc.md.json index 3ba014a52..853ab5c20 100644 --- a/packages/typedoc-plugin-markdown/typedoc.md.json +++ b/packages/typedoc-plugin-markdown/typedoc.md.json @@ -1,22 +1,20 @@ { "extends": "./typedoc.base.json", - "plugin": ["typedoc-plugin-markdown", "typedoc-plugin-remark"], + "out": "./plugin-docs", "hidePageHeader": true, "expandObjects": false, - "excludeGroups": true, + "excludeGroups": false, "outputFileStrategy": "members", "useCodeBlocks": false, "expandParameters": false, - "indexFormat": "table", - "parametersFormat": "table", - "entryFileName": "README.md", + "fileExtension": ".md", "textContentMappings": { "breadcrumbs.home": "API", - "title.indexPage": "Resources" + "title.indexPage": "API", + "title.memberPage": "{name}" }, - "remarkPlugins": [ - "remark-gfm", - ["remark-toc", { "skip": "Parameters|Returns" }] - ], - "propertiesFormat": "list" + "indexFormat": "table", + "parametersFormat": "table", + "propertiesFormat": "list", + "hideBreadcrumbs": false } diff --git a/packages/typedoc-plugin-markdown/typedoc.publicdocs.json b/packages/typedoc-plugin-markdown/typedoc.publicdocs.json new file mode 100644 index 000000000..833499882 --- /dev/null +++ b/packages/typedoc-plugin-markdown/typedoc.publicdocs.json @@ -0,0 +1,9 @@ +{ + "extends": "./typedoc.md.json", + "entryPoints": ["./src"], + "plugin": ["typedoc-plugin-markdown", "./typedoc-theme.cjs"], + "out": "../../docs/pages/test-api", + "theme": "nextra", + "excludeInternal": true, + "disableSources": true +} diff --git a/packages/typedoc-vitepress-theme/src/index.ts b/packages/typedoc-vitepress-theme/src/index.ts index aeb48cd39..b3e61f826 100644 --- a/packages/typedoc-vitepress-theme/src/index.ts +++ b/packages/typedoc-vitepress-theme/src/index.ts @@ -5,17 +5,18 @@ import { DeclarationOption, Options, OptionsReader, + Reflection, } from 'typedoc'; -import { MarkdownRendererEvent } from 'typedoc-plugin-markdown'; +import { + MarkdownPageEvent, + MarkdownRendererEvent, +} from 'typedoc-plugin-markdown'; import { DEFAULT_SIDEBAR_OPTIONS } from './options'; import * as options from './options/declarations'; import presets from './options/presets'; import { getSidebar } from './sidebars/sidebars'; -import { VitepressTheme } from './theme'; export function load(app: Application) { - app.renderer.defineTheme('vitepress', VitepressTheme); - Object.entries(options).forEach(([name, option]) => { app.options.addDeclaration({ name, @@ -30,13 +31,29 @@ export function load(app: Application) { readonly supportsPackages = false; read(container: Options) { Object.entries(presets).forEach(([key, value]) => { - container.setValue('theme', 'vitepress'); container.setValue(key, value); }); } })(), ); + app.renderer.on( + MarkdownPageEvent.END, + (page: MarkdownPageEvent) => { + page.contents = page.contents?.replace( + /\[([^\]]+)\]\((?!https?:|\/|\.)([^)]*#?[^)]*)\)/g, + (match: string, text: string, url: string) => { + const urlWithAnchor = url.split('#'); + if (urlWithAnchor.length > 1) { + const anchorPart = slugifyAnchor(urlWithAnchor[1]); + return `[${text}](${encodeURI(`${urlWithAnchor[0]}#${anchorPart}`)})`; + } + return `[${text}](${encodeURI(url)})`; + }, + ); + }, + ); + app.renderer.postRenderAsyncJobs.push( async (output: MarkdownRendererEvent) => { const sidebarOptions = { @@ -66,3 +83,12 @@ export function load(app: Application) { }, ); } + +function slugifyAnchor(anchor: string) { + return anchor + .toLowerCase() + .trim() + .replace(/[^\w\s-]/g, '') + .replace(/[\s_-]+/g, '-') + .replace(/^-+|-+$/g, ''); +} diff --git a/packages/typedoc-vitepress-theme/src/theme.ts b/packages/typedoc-vitepress-theme/src/theme.ts deleted file mode 100644 index ae2b41cd5..000000000 --- a/packages/typedoc-vitepress-theme/src/theme.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Reflection } from 'typedoc'; -import { - MarkdownPageEvent, - MarkdownTheme, - MarkdownThemeRenderContext, -} from 'typedoc-plugin-markdown'; - -export class VitepressTheme extends MarkdownTheme { - override getRenderContext(pageEvent: MarkdownPageEvent) { - return new ThemeRenderContext(this, pageEvent, this.application.options); - } -} - -class ThemeRenderContext extends MarkdownThemeRenderContext { - override helpers = { - ...this.helpers, - parseUrl: (url: string) => { - const urlWithAnchor = url.split('#'); - if (urlWithAnchor.length > 1) { - const anchorPart = slugify(urlWithAnchor[1]); - return encodeURI(`${urlWithAnchor[0]}#${anchorPart}`); - } - return encodeURI(url); - }, - }; -} - -function slugify(str: string) { - return str - .toLowerCase() - .trim() - .replace(/[^\w\s-]/g, '') - .replace(/[\s_-]+/g, '-') - .replace(/^-+|-+$/g, ''); -}