diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8dec30f1..e841c3ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,26 @@ jobs: - name: Lint & Format run: npm run lint && npm run format:check + test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: Setup Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: lts/* + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Run tests + run: npm run test + build: runs-on: ubuntu-latest steps: diff --git a/package.json b/package.json index 5ccdd27c..00dbd473 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build:html": "node scripts/html/index.mjs && node scripts/html/sitemap-index.mjs", "build:rss-feed": "node scripts/rss-feed/index.mjs", "build": "npm-run-all build:*", + "test": "node --test", "lint": "npm-run-all \"lint:!(fix)\"", "lint:fix": "npm-run-all lint:*:fix", "lint:js": "eslint .", diff --git a/scripts/markdown/api/configuration.mjs b/scripts/markdown/api/configuration.mjs index 5f40b54e..cbc087b6 100644 --- a/scripts/markdown/api/configuration.mjs +++ b/scripts/markdown/api/configuration.mjs @@ -1,7 +1,7 @@ import { writeFile } from 'node:fs/promises'; import { join } from 'node:path/posix'; import { major } from 'semver'; -import { sources, getPackageFile, outputDir } from './utils.mjs'; +import { getSources, getPackageFile, outputDir } from './utils.mjs'; const definitionName = ref => ref?.startsWith('#/definitions/') ? ref.slice('#/definitions/'.length) : ''; @@ -413,6 +413,7 @@ const generate = async packageDir => { ); }; +const sources = await getSources(); for (const source of sources) { await generate(source); } diff --git a/scripts/markdown/api/index.mjs b/scripts/markdown/api/index.mjs index a4718a79..848a7af3 100644 --- a/scripts/markdown/api/index.mjs +++ b/scripts/markdown/api/index.mjs @@ -1,43 +1,28 @@ import { join } from 'node:path/posix'; import { Application } from 'typedoc'; import { major } from 'semver'; -import { sources, outputDir, getPackageFile } from './utils.mjs'; +import { + getSources, + outputDir, + getPackageFile, + typeDocConfig, +} from './utils.mjs'; const generate = async packageDir => { const { version } = await getPackageFile(packageDir); const app = await Application.bootstrapWithPlugins({ + ...typeDocConfig, entryPoints: [join(packageDir, 'types.d.ts')], out: join(outputDir, `v${major(version)}.x`), publicPath: `/docs/api/v${major(version)}.x/`, - - plugin: [ - 'typedoc-plugin-markdown', - 'typedoc-plugin-missing-exports', - './plugins/processor/index.mjs', - './plugins/theme/index.mjs', - ], - theme: 'doc-kit', - router: 'doc-kit', - - hideGroupHeadings: true, - hideBreadcrumbs: true, - hidePageHeader: true, - readme: 'none', - disableSources: true, - propertiesFormat: 'table', - membersWithOwnFile: ['Class'], - - modulesFileName: 'index', - entryFileName: 'index', - tsconfig: 'tsconfig.json', - excludeExternals: true, }); const project = await app.convert(); await app.generateOutputs(project); }; +const sources = await getSources(); for (const source of sources) { await generate(source); } diff --git a/scripts/markdown/api/utils.mjs b/scripts/markdown/api/utils.mjs index dd9ebbd6..e854cc62 100644 --- a/scripts/markdown/api/utils.mjs +++ b/scripts/markdown/api/utils.mjs @@ -4,13 +4,39 @@ import { join } from 'node:path/posix'; const [packageDir] = process.argv.slice(2); const cacheDir = join('.', '.cache', 'webpack'); -export const sources = packageDir - ? [packageDir] - : (await readdir(cacheDir, { withFileTypes: true })) - .filter(entry => entry.isDirectory()) - .map(entry => join(cacheDir, entry.name)); +export const getSources = async () => { + if (packageDir) return [packageDir]; + const sources = await readdir(cacheDir, { withFileTypes: true }); + return sources + .filter(entry => entry.isDirectory()) + .map(entry => join(cacheDir, entry.name)); +}; export const outputDir = join('pages', 'docs', 'api'); export const getPackageFile = async (packageDir, file = 'package.json') => JSON.parse(await readFile(join(packageDir, file), 'utf8')); + +export const typeDocConfig = { + plugin: [ + 'typedoc-plugin-markdown', + 'typedoc-plugin-missing-exports', + './plugins/processor/index.mjs', + './plugins/theme/index.mjs', + ], + theme: 'doc-kit', + router: 'doc-kit', + + hideGroupHeadings: true, + hideBreadcrumbs: true, + hidePageHeader: true, + readme: 'none', + disableSources: true, + propertiesFormat: 'table', + membersWithOwnFile: ['Class'], + + modulesFileName: 'index', + entryFileName: 'index', + tsconfig: 'tsconfig.json', + excludeExternals: true, +}; diff --git a/tests/theme/fixtures/input.js b/tests/theme/fixtures/input.js new file mode 100644 index 00000000..4eb241a0 --- /dev/null +++ b/tests/theme/fixtures/input.js @@ -0,0 +1,25 @@ +/* eslint-disable */ + +export class OverloadedTest { + /** + * First overload signature. + * @overload + * @param {string} name A simple string parameter + * @param {number} count A simple number parameter + * @returns {void} + */ + /** + * Second overload signature. + * @overload + * @param {boolean} isEnabled A simple boolean parameter + * @returns {string} + */ + /** + * Third overload signature. + * @overload + * @param {number} id A simple string parameter + * @param {boolean} isEnabled A simple boolean parameter + * @returns {void} + */ + overloadedMethod(id, isEnabled) {} +} diff --git a/tests/theme/fixtures/tsconfig.json b/tests/theme/fixtures/tsconfig.json new file mode 100644 index 00000000..caddb7f2 --- /dev/null +++ b/tests/theme/fixtures/tsconfig.json @@ -0,0 +1,9 @@ +{ + "include": ["**/*.js"], + "compilerOptions": { + "allowJs": true, + "esModuleInterop": true, + "noEmit": true, + "skipLibCheck": true + } +} diff --git a/tests/theme/theme.test.mjs b/tests/theme/theme.test.mjs new file mode 100644 index 00000000..8243c696 --- /dev/null +++ b/tests/theme/theme.test.mjs @@ -0,0 +1,39 @@ +import { test } from 'node:test'; +import { Application } from 'typedoc'; +import { readdirSync, readFileSync, rmSync } from 'node:fs'; +import { join } from 'node:path/posix'; +import { typeDocConfig } from '../../scripts/markdown/api/utils.mjs'; + +const fixturesDir = './tests/theme/fixtures'; +const outputDir = './tests/theme/.temp'; + +test('TypeDoc Theme - Edge Cases Fixture', async t => { + const inputFilePath = join(fixturesDir, 'input.js'); + + const app = await Application.bootstrapWithPlugins({ + ...typeDocConfig, + entryPoints: [inputFilePath], + out: outputDir, + publicPath: '/', + tsconfig: join(fixturesDir, 'tsconfig.json'), + }); + + const project = await app.convert(); + await app.generateOutputs(project); + + const mdFiles = readdirSync(outputDir, { recursive: true }).filter( + f => f.endsWith('.md') && !f.endsWith('index.md') + ); + + if (mdFiles.length === 0) throw new Error('No markdown file generated'); + + mdFiles.sort(); + + const actualMarkdown = mdFiles + .map(f => readFileSync(join(outputDir, f), 'utf-8')) + .join('\n\n---\n\n'); + + rmSync(outputDir, { recursive: true, force: true }); + + t.assert.snapshot(actualMarkdown); +}); diff --git a/tests/theme/theme.test.mjs.snapshot b/tests/theme/theme.test.mjs.snapshot new file mode 100644 index 00000000..06ca5ffd --- /dev/null +++ b/tests/theme/theme.test.mjs.snapshot @@ -0,0 +1,3 @@ +exports[`TypeDoc Theme - Edge Cases Fixture 1`] = ` +"# Class: \`webpack.js.org.OverloadedTest\`\\n\\n## Constructors\\n\\n### \`new OverloadedTest()\`\\n\\n* Returns: {OverloadedTest}\\n\\n## Methods\\n\\n### \`overloadedMethod(name, count)\`\\n\\n#### Call Signature\\n\\n* \`name\` {string} A simple string parameter\\n* \`count\` {number} A simple number parameter\\n* Returns: {void} \\n\\nFirst overload signature.\\n\\n#### Call Signature\\n\\n* \`isEnabled\` {boolean} A simple boolean parameter\\n* Returns: {string} \\n\\nSecond overload signature.\\n\\n#### Call Signature\\n\\n* \`id\` {number} A simple string parameter\\n* \`isEnabled\` {boolean} A simple boolean parameter\\n* Returns: {void} \\n\\nThird overload signature.\\n" +`;