Skip to content

experiment: use typedoc's own html instead of markdown #3410

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 7 commits into
base: v2
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ pnpm-debug.log*

# macOS-specific files
.DS_Store
packages/js-api-generator/build.js
/public/reference/javascript
5 changes: 5 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ pnpm-lock.yaml
.github
!.github/**.md

# Generated files
public/generated/*
src/content/docs/release
src/_generated-javascript-reference-sidebar.js

# TODO: Figure out why this format isn't acceptable
# https://github.com/withastro/prettier-plugin-astro/issues/407
src/components/overrides/Header.astro
Expand Down
17 changes: 9 additions & 8 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import path from 'path';
import { fileURLToPath } from 'url';
import lunaria from '@lunariajs/starlight';
import { readFileSync } from 'fs';
import referenceJavascriptSidebar from './src/_generated-javascript-reference-sidebar.js';

const authors = {
nothingismagick: {
Expand Down Expand Up @@ -291,9 +292,9 @@ export default defineConfig({
autogenerate: { directory: 'release' },
},
{
label: 'JavaScript',
collapsed: true,
autogenerate: { directory: 'reference/javascript' },
label: 'JavaScript (TypeDoc)',
// generated by js-api-generator
items: referenceJavascriptSidebar,
},
{
label: 'Rust (docs.rs)',
Expand All @@ -318,11 +319,11 @@ export default defineConfig({
},
}
),
starlightLinksValidator({
errorOnFallbackPages: false,
errorOnRelativeLinks: false,
exclude: ['/plugin/*/#default-permission', '/plugin/*/#permission-table'],
}),
// starlightLinksValidator({
// errorOnFallbackPages: false,
// errorOnRelativeLinks: false,
// exclude: ['/plugin/*/#default-permission', '/plugin/*/#permission-table'],
// }),
lunaria({ configPath: './lunaria.config.json', route: '/contribute/translate-status' }),
],
title: 'Tauri',
Expand Down
1 change: 1 addition & 0 deletions packages/js-api-generator/assets/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/js-api-generator/assets/logo_light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions packages/js-api-generator/assets/pico.slate.min.css

Large diffs are not rendered by default.

242 changes: 121 additions & 121 deletions packages/js-api-generator/build.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,41 @@
import {
Application,
DeclarationReflection,
Options,
PageEvent,
Reflection,
SignatureReflection,
TSConfigReader,
type TypeDocOptions,
} from 'typedoc';
import {
MarkdownPageEvent,
MarkdownTheme,
MarkdownThemeContext,
type MarkdownApplication,
type PluginOptions,
} from 'typedoc-plugin-markdown';
import { existsSync } from 'node:fs';

const typeDocConfigBaseOptions: Partial<TypeDocOptions | PluginOptions> = {
import { Application, TSConfigReader, LogLevel, DefaultTheme, type TypeDocOptions } from 'typedoc';
import { existsSync, mkdirSync, writeFileSync, readdirSync, readFileSync, cpSync } from 'node:fs';
import { resolve, join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const BASE_OUTPUT_DIR = resolve(__dirname, '../../public/reference/javascript');

const OUTPUT_DOCS_SRC_DIR = resolve(__dirname, '../../src');

const typeDocConfigBaseOptions: Partial<TypeDocOptions> = {
// TypeDoc options
// https://typedoc.org/options/
githubPages: false,
hideGenerator: true,
theme: 'tauri-theme',
plugin: ['typedoc-plugin-mdn-links', 'typedoc-plugin-markdown'],
plugin: ['typedoc-plugin-mdn-links'],
readme: 'none',
logLevel: 'Warn',
parametersFormat: 'table',
// typedoc-plugin-markdown options
// https://github.com/tgreyuk/typedoc-plugin-markdown/blob/next/packages/typedoc-plugin-markdown/docs/usage/options.md
outputFileStrategy: 'modules',
flattenOutputFiles: true,
entryFileName: 'index.md',
hidePageHeader: true,
hidePageTitle: true,
hideBreadcrumbs: true,
useCodeBlocks: true,
propertiesFormat: 'table',
typeDeclarationFormat: 'table',
useHTMLAnchors: true,
logLevel: LogLevel.Warn,
includeVersion: true,
searchInComments: true,
navigationLinks: {
'Tauri Docs': 'https://tauri.app',
GitHub: 'https://github.com/tauri-apps/tauri',
},
visibilityFilters: {
protected: true,
private: false,
inherited: true,
external: false,
},
categorizeByGroup: true,
cleanOutputDir: true,
// disableSources: false,
sort: ['source-order'],
highlightLanguages: ['typescript', 'javascript', 'json', 'bash', 'shell', 'rust', 'toml'],
};

async function generator() {
Expand All @@ -47,8 +44,8 @@ async function generator() {
entryPoints: ['../tauri/packages/api/src/index.ts'],
tsconfig: '../tauri/packages/api/tsconfig.json',
gitRevision: 'dev',
publicPath: '/reference/javascript/api/',
basePath: '/reference/javascript/api/',
out: join(BASE_OUTPUT_DIR, 'core'),
name: 'Tauri Core API',
...typeDocConfigBaseOptions,
};

Expand Down Expand Up @@ -88,119 +85,122 @@ async function generator() {
];

if (existsSync('../plugins-workspace/node_modules')) {
plugins.forEach(async (plugin) => {
const pluginsPromises = plugins.map(async (plugin) => {
const pluginJsOptions: Partial<TypeDocOptions> = {
entryPoints: [`../plugins-workspace/plugins/${plugin}/guest-js/index.ts`],
tsconfig: `../plugins-workspace/plugins/${plugin}/tsconfig.json`,
gitRevision: 'v2',
publicPath: `/reference/javascript/`,
basePath: `/reference/javascript/`,
out: join(BASE_OUTPUT_DIR, 'plugins', plugin),
name: `@tauri-apps/plugin-${plugin}`,
...typeDocConfigBaseOptions,
// Must go after to override base
entryFileName: `${plugin}.md`,
};

await generateDocs(pluginJsOptions);
return generateDocs(pluginJsOptions);
});
} else {
console.log(
'Plugins workspace submodule is not initialized, respective API routes will not be rendered.'
);
}

if (existsSync('../tauri/packages/api/node_modules')) {
const coreJsOptions: Partial<TypeDocOptions> = {
entryPoints: ['../tauri/packages/api/src/index.ts'],
tsconfig: '../tauri/packages/api/tsconfig.json',
gitRevision: 'dev',
publicPath: '/reference/javascript/api/',
basePath: '/reference/javascript/api/',
...typeDocConfigBaseOptions,
};

await generateDocs(coreJsOptions);
await Promise.all(pluginsPromises);
} else {
console.log(
'Tauri V2 submodule is not initialized, respective API routes will not be rendered.'
'Plugins workspace submodule is not initialized, respective API routes will not be rendered.'
);
}
await generateIndexPage();
}

// Adapted from https://github.com/HiDeoo/starlight-typedoc
async function generateDocs(options: Partial<TypeDocOptions>) {
const outputDir = `../../src/content/docs${options.publicPath}`;
// console.log(`Generating docs for ${options.name}`);

const outDir = options.out as string;
if (!existsSync(outDir)) {
mkdirSync(outDir, { recursive: true });
}
const app = await Application.bootstrapWithPlugins(options);
app.options.addReader(new TSConfigReader());
// @ts-ignore
app.renderer.defineTheme('tauri-theme', TauriTheme);

app.renderer.on(PageEvent.END, (event: PageEvent<DeclarationReflection>) => {
pageEventEnd(event);
});
options.theme = 'tauri-theme';
app.renderer.defineTheme('tauri-theme', TauriDefaultTheme);

const project = await app.convert();

if (project) {
await app.generateDocs(project, outputDir);
if (!project) {
throw new Error(`Failed to convert project: ${options.name}`);
}
}

// Adds frontmatter to the top of the file
// Adapted from https://github.com/HiDeoo/starlight-typedoc
function pageEventEnd(event: PageEvent<DeclarationReflection>) {
if (!event.contents) {
return;
}
const frontmatter = [
'---',
`title: "${event.model.name}"`,
'editUrl: false',
'sidebar:',
` label: "${event.model.name.replace('@tauri-apps/plugin-', '')}"`,
'tableOfContents:',
' maxHeadingLevel: 5',
'---',
'',
event.contents,
];
event.contents = frontmatter.join('\n');
await app.generateDocs(project, outDir);
}
class TauriThemeRenderContext extends MarkdownThemeContext {
constructor(theme: MarkdownTheme, page: MarkdownPageEvent<Reflection>, options: Options) {
super(theme, page, options);
this.partials = {
...this.partials,
// Formats `@source` to be a single line
sources: (model: DeclarationReflection | SignatureReflection, options: object) => {
if (!model.sources) {
return '';
}
let label = model.sources.length > 1 ? '**Sources**: ' : '**Source**: ';
const sources = model.sources.map((source) => `${source.url}`);
return label + sources.join(', ');
},
};
}

// Adapted from https://github.com/HiDeoo/starlight-typedoc/blob/d95072e218004276942a5132ec8a4e3561425903/packages/starlight-typedoc/src/libs/theme.ts#L28
override getRelativeUrl = (url: string) => {
if (/^(http|ftp)s?:\/\//.test(url)) {
return url;
}
async function generateIndexPage() {
const indexPath = join(BASE_OUTPUT_DIR, 'index.html');

url = decodeURI(
super.getRelativeUrl(url).replaceAll('.md', '/').replaceAll('.', '').toLowerCase()
).replaceAll('\\', '/');
return url;
const cardTemplate = (name: string, path: string) => {
return ` <article>
<hgroup>
<h4>${name}</h4>
<a href="${path}">View</a>
</hgroup>
</article>`;
};
}

// Overrides and extensions based on https://github.com/tgreyuk/typedoc-plugin-markdown/blob/next/packages/typedoc-plugin-markdown/docs/usage/customizing.md
class TauriTheme extends MarkdownTheme {
getRenderContext(page: MarkdownPageEvent<Reflection>): MarkdownThemeContext {
return new TauriThemeRenderContext(this, page, this.application.options);
let pluginsGridHtml;
if (existsSync(join(BASE_OUTPUT_DIR, 'plugins'))) {
const pluginDirs = readdirSync(join(BASE_OUTPUT_DIR, 'plugins'));

pluginsGridHtml = pluginDirs
.map((plugin: string) => cardTemplate(plugin, `./plugins/${plugin}/index.html`))
.join('');
}

// TODO: improve layout
// TODO: improve theme switcher
// TODO: link to docs
// TODO: make docs link to here
const indexTemplatePath = join(__dirname, 'indexTemplate.html');
const indexContent = readFileSync(indexTemplatePath, 'utf-8')
.replace('{{ pluginsGridHtml }}', pluginsGridHtml || '')
.replace('{{ tauriCard }}', cardTemplate('Tauri Core API', '/reference/javascript/core/'));

const assetsDir = join(BASE_OUTPUT_DIR, 'assets');
if (!existsSync(assetsDir)) {
mkdirSync(assetsDir, { recursive: true });
}
const distAssetsDir = join(__dirname, 'assets');
if (existsSync(distAssetsDir)) {
try {
cpSync(distAssetsDir, assetsDir, { recursive: true, force: true });
} catch (err) {
console.error('Failed to copy assets:', err);
}
} else {
console.warn(`Assets directory not found at ${distAssetsDir}`);
}
try {
writeFileSync(indexPath, indexContent);
// Starlight topics especific sidebar structure
const sidebar = [
{
label: 'Index',
link: '/reference/javascript/index.html',
},
{
label: 'Tauri Core API',
link: '/reference/javascript/core/index.html',
},
...(pluginsGridHtml && existsSync(join(BASE_OUTPUT_DIR, 'plugins'))
? readdirSync(join(BASE_OUTPUT_DIR, 'plugins')).map((plugin) => ({
label: plugin,
link: `/reference/javascript/plugins/${plugin}/index.html`,
}))
: []),
];
const sidebarFilePath = join(OUTPUT_DOCS_SRC_DIR, '_generated-javascript-reference-sidebar.js');
writeFileSync(sidebarFilePath, 'export default ' + JSON.stringify(sidebar, null, 2) + ';\n');
} catch (error) {
console.error('Failed to write index files:', error);
}
}

generator();
class TauriDefaultTheme extends DefaultTheme {}

generator().catch((error) => {
console.error('Failed to generate documentation:', error);
process.exit(1);
});
Loading
Loading