-
Notifications
You must be signed in to change notification settings - Fork 59
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Re-Add the
docs
command (#1107)
Re-introducing the `docs` command to generate Docs for a project and publish them to [gh pages](https://docs.github.com/en/pages) Closes #1105 Co-authored-by: achingbrain <[email protected]>
- Loading branch information
1 parent
39638eb
commit 830e826
Showing
6 changed files
with
263 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { loadUserConfig } from '../config/user.js' | ||
import docsCmd from '../docs.js' | ||
|
||
/** | ||
* @typedef {import("yargs").Argv} Argv | ||
* @typedef {import("yargs").ArgumentsCamelCase} Arguments | ||
* @typedef {import("yargs").CommandModule} CommandModule | ||
*/ | ||
const EPILOG = ` | ||
Typescript config file is required to generated docs. Please create a \`tsconfig.json\` file in the root of your project. | ||
` | ||
/** @type {CommandModule} */ | ||
export default { | ||
command: 'docs', | ||
describe: 'Generate documentation from TS type declarations.', | ||
/** | ||
* @param {Argv} yargs | ||
*/ | ||
builder: async (yargs) => { | ||
const userConfig = await loadUserConfig() | ||
|
||
return yargs | ||
.epilog(EPILOG) | ||
.example('aegir docs', 'Build HTML documentation.') | ||
.example('aegir docs -p', 'Build HTML documentation and publish to Github Pages.') | ||
.options({ | ||
publish: { | ||
alias: 'p', | ||
type: 'boolean', | ||
describe: 'Publish to GitHub Pages', | ||
default: userConfig.docs.publish | ||
}, | ||
entryPoint: { | ||
type: 'string', | ||
describe: | ||
'Specifies the entry points to be documented by TypeDoc. TypeDoc will examine the exports of these files and create documentation according to the exports. Either files or directories may be specified. If a directory is specified, all source files within the directory will be included as an entry point.', | ||
default: userConfig.docs.entryPoint | ||
} | ||
}) | ||
}, | ||
/** | ||
* @param {any} argv | ||
*/ | ||
async handler (argv) { | ||
await docsCmd.run(argv) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
import { hasTsconfig, fromAegir, fromRoot, readJson } from './utils.js' | ||
import Listr from 'listr' | ||
import kleur from 'kleur' | ||
import fs from 'fs-extra' | ||
import path from 'path' | ||
import { execa } from 'execa' | ||
import { promisify } from 'util' | ||
import ghPages from 'gh-pages' | ||
import { premove as del } from 'premove/sync' | ||
import { fileURLToPath } from 'url' | ||
|
||
const publishPages = promisify(ghPages.publish) | ||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url)) | ||
|
||
/** | ||
* @typedef {import("./types").GlobalOptions} GlobalOptions | ||
* @typedef {import("./types").DocsOptions} DocsOptions | ||
* @typedef {import("listr").ListrTaskWrapper} Task | ||
* | ||
* @typedef {object} Options | ||
* @property {string} entryPoint - Entry point for typedoc (defaults: 'src/index.js') | ||
* @property {string[]} forwardOptions - Extra options to forward to the backend | ||
*/ | ||
|
||
/** | ||
* Docs command | ||
* | ||
* @param {GlobalOptions & DocsOptions} ctx | ||
* @param {Task} task | ||
*/ | ||
const docs = async (ctx, task) => { | ||
const userTSConfig = readJson(fromRoot('tsconfig.json')) | ||
const configPath = fromRoot('tsconfig-docs.aegir.json') | ||
const exportsMap = readJson(fromRoot('package.json')).exports | ||
|
||
try { | ||
const config = { | ||
...userTSConfig | ||
} | ||
|
||
if (config.compilerOptions) { | ||
// remove config options that cause tsdoc to fail | ||
delete config.compilerOptions.emitDeclarationOnly | ||
} | ||
|
||
fs.writeJsonSync(configPath, config, { | ||
spaces: 2 | ||
}) | ||
|
||
/** @type {Options} */ | ||
const opts = { | ||
forwardOptions: ctx['--'] ? ctx['--'] : [], | ||
entryPoint: ctx.entryPoint | ||
} | ||
|
||
if (!hasTsconfig) { | ||
// eslint-disable-next-line no-console | ||
console.error( | ||
kleur.yellow('Documentation requires typescript config.') | ||
) | ||
return | ||
} | ||
|
||
/** @type {string[]} */ | ||
const entryPoints = [] | ||
|
||
if (exportsMap != null) { | ||
Object.values(exportsMap).forEach(map => { | ||
const path = map.import | ||
|
||
if (path == null) { | ||
return | ||
} | ||
|
||
if (path.includes('./dist/src')) { | ||
// transform `./dist/src/index.js` to `./src/index.ts` | ||
entryPoints.push(`.${path.match(/\.\/dist(\/src\/.*).js/)[1]}.ts`) | ||
} else { | ||
entryPoints.push(path) | ||
} | ||
}) | ||
} else { | ||
entryPoints.push(opts.entryPoint) | ||
} | ||
|
||
// run typedoc | ||
const proc = execa( | ||
'typedoc', | ||
[ | ||
...entryPoints, | ||
'--tsconfig', | ||
configPath, | ||
'--out', | ||
'docs', | ||
'--hideGenerator', | ||
'--includeVersion', | ||
'--gitRevision', | ||
'master', | ||
'--plugin', | ||
'typedoc-theme-hierarchy', | ||
'--theme', | ||
'hierarchy', | ||
'--plugin', | ||
fromAegir('src/docs/typedoc-plugin.cjs'), | ||
...opts.forwardOptions | ||
], | ||
{ | ||
localDir: path.join(__dirname, '..'), | ||
preferLocal: true, | ||
all: true | ||
} | ||
) | ||
proc.all?.on('data', (chunk) => { | ||
task.output = chunk.toString().replace('\n', '') | ||
}) | ||
await proc | ||
|
||
// write .nojekyll file | ||
fs.writeFileSync('docs/.nojekyll', '') | ||
} finally { | ||
fs.removeSync(configPath) | ||
} | ||
} | ||
|
||
const publishDocs = () => { | ||
return publishPages( | ||
'docs', | ||
// @ts-ignore - promisify returns wrong type | ||
{ | ||
dotfiles: true, | ||
message: 'chore: update documentation' | ||
} | ||
) | ||
} | ||
|
||
const tasks = new Listr( | ||
[ | ||
{ | ||
title: 'Clean ./docs', | ||
task: () => { | ||
del('docs') | ||
del('dist') | ||
} | ||
}, | ||
{ | ||
title: 'Generating documentation', | ||
/** | ||
* | ||
* @param {GlobalOptions & DocsOptions} ctx | ||
* @param {Task} task | ||
*/ | ||
task: docs | ||
}, | ||
{ | ||
title: 'Publish to GitHub Pages', | ||
task: publishDocs, | ||
enabled: (ctx) => ctx.publish && hasTsconfig | ||
} | ||
], | ||
{ | ||
renderer: 'verbose' | ||
} | ||
) | ||
|
||
export default tasks |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
const { Converter } = require('typedoc') | ||
const path = require('path') | ||
const fs = require('fs') | ||
|
||
/** | ||
* @param {import("typedoc/dist/lib/application").Application} Application | ||
*/ | ||
const plugin = function (Application) { | ||
const app = Application.owner | ||
const pkg = path.join(process.cwd(), 'package.json') | ||
/** @type {any} */ | ||
let pkgJson | ||
|
||
try { | ||
pkgJson = JSON.parse(fs.readFileSync(pkg).toString()) | ||
} catch (err) { | ||
throw new Error('cant find package.json') | ||
} | ||
|
||
/** | ||
* @param {import("typedoc/dist/lib/converter/context").Context} context | ||
* @param {import("typedoc/dist/lib/models/reflections/abstract").Reflection} reflection | ||
* @param {import("typescript").Node} node | ||
*/ | ||
const cb = (context, reflection, node) => { | ||
|
||
if (pkgJson && reflection.name === 'export=') { | ||
let name | ||
if (node) { | ||
// @ts-ignore | ||
name = node.symbol.escapedName | ||
} | ||
reflection.name = `${name || 'default'}` | ||
} | ||
} | ||
|
||
app.converter.on(Converter.EVENT_CREATE_DECLARATION, cb) | ||
} | ||
|
||
module.exports = { | ||
load: plugin | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters