Skip to content

Commit 055e1d5

Browse files
maschadachingbrain
andauthored
feat: Add support for compiling Typescript snippets in markdown (#1134)
Closes #1117 Co-authored-by: Alex Potsides <[email protected]>
1 parent 1cf5c45 commit 055e1d5

10 files changed

+155
-3
lines changed

README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Commands:
7373
aegir build Builds a browser bundle and TS type declarations from the `src` folder.
7474
aegir check Check project
7575
aegir docs Generate documentation from TS type declarations.
76+
aegir doc-check Verify TS code snippets in documentation.
7677
aegir lint Lint all project files
7778
aegir release Release your code onto the world
7879
aegir test-dependant [repo] Run the tests of an module that depends on this module to see if the current changes have caused a regression
@@ -103,8 +104,6 @@ Aegir can be fully configured using a config file named `.aegir.js` or the packa
103104
```js
104105
// file: .aegir.js
105106

106-
107-
108107
/** @type {import('aegir').PartialOptions} */
109108
module.exports = {
110109
tsRepo: true,

md/github-actions.md

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ jobs:
1919
- run: npx aegir lint
2020
- run: npx aegir build
2121
- run: npx aegir dep-check
22+
- run: npx aegir doc-check
2223
- uses: ipfs/aegir/actions/bundle-size@master
2324
with:
2425
github_token: ${{ secrets.GITHUB_TOKEN }}

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@
213213
"test": "node src/index.js test",
214214
"docs": "node src/index.js docs",
215215
"dep-check": "node src/index.js dep-check",
216+
"doc-check": "node src/index.js doc-check",
216217
"test:node": "node src/index.js test -t node --cov",
217218
"test:chrome": "node src/index.js test -t browser --cov",
218219
"test:chrome-webworker": "node src/index.js test -t webworker",
@@ -310,6 +311,7 @@
310311
"typedoc-plugin-mdn-links": "^2.0.0",
311312
"typedoc-plugin-missing-exports": "^1.0.0",
312313
"typescript": "^4.6.3",
314+
"typescript-docs-verifier": "2.4.0",
313315
"uint8arrays": "^4.0.2",
314316
"undici": "^5.0.0",
315317
"update-notifier": "^6.0.2",

src/cmds/document-check.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/* eslint-disable no-console */
2+
3+
import { loadUserConfig } from '../config/user.js'
4+
import docCheck from '../document-check.js'
5+
6+
/**
7+
* @typedef {import("yargs").Argv} Argv
8+
* @typedef {import("yargs").Arguments} Arguments
9+
* @typedef {import("yargs").CommandModule} CommandModule
10+
*/
11+
12+
const EPILOG = `
13+
Docs are verified using typescript-docs-verifier (https://github.com/bbc/typescript-docs-verifier#typescript-docs-verifier)
14+
For more info read: https://github.com/bbc/typescript-docs-verifier#how-it-works
15+
`
16+
17+
/** @type {CommandModule} */
18+
export default {
19+
command: 'document-check [input...]',
20+
aliases: ['doc-check'],
21+
describe: 'Run `document-check` cli with aegir defaults.',
22+
/**
23+
* @param {Argv} yargs
24+
*/
25+
builder: async (yargs) => {
26+
const userConfig = await loadUserConfig()
27+
28+
return yargs
29+
.epilog(EPILOG)
30+
.options({
31+
inputFiles: {
32+
array: true,
33+
describe: 'The files to verify, defaults to `README.md`',
34+
default: userConfig.documentCheck.inputFiles
35+
},
36+
tsConfigPath: {
37+
type: 'string',
38+
describe: 'The path to the `tsconfig.json`, defaults to the root.',
39+
default: userConfig.documentCheck.tsConfigPath
40+
}
41+
})
42+
},
43+
/**
44+
* @param {any} argv
45+
*/
46+
async handler (argv) {
47+
await docCheck.run(argv)
48+
}
49+
}

src/config/user.js

+8
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ const defaults = {
6868
email: 'aegir[bot]@users.noreply.github.com',
6969
directory: '.docs'
7070
},
71+
// document check cmd options
72+
documentCheck: {
73+
inputFiles: [
74+
'*.md',
75+
'src/*.md'
76+
],
77+
tsConfigPath: '.'
78+
},
7179
// ts cmd options
7280
ts: {
7381
preset: undefined,

src/document-check.js

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/* eslint-disable no-console */
2+
3+
import Listr from 'listr'
4+
import { hasTsconfig } from './utils.js'
5+
import { globby } from 'globby'
6+
import { compileSnippets } from 'typescript-docs-verifier'
7+
/**
8+
* @typedef {import("./types").GlobalOptions} GlobalOptions
9+
* @typedef {import("./types").DocsVerifierOptions} DocsVerifierOptions
10+
* @typedef {import("listr").ListrTaskWrapper} Task
11+
*/
12+
13+
const tasks = new Listr(
14+
[
15+
{
16+
title: 'typescript-doc-verify',
17+
/**
18+
* @param {GlobalOptions & DocsVerifierOptions} ctx
19+
*/
20+
enabled: ctx => hasTsconfig,
21+
/**
22+
* @param {GlobalOptions & DocsVerifierOptions} ctx
23+
* @param {Task} task
24+
*/
25+
task: async (ctx, task) => {
26+
let tsconfigPath = 'tsconfig.json'
27+
let markdownFiles = ['README.md']
28+
29+
if (ctx.tsConfigPath) {
30+
tsconfigPath = `${ctx.tsConfigPath}/tsconfig.json`
31+
}
32+
33+
if (ctx.inputFiles) {
34+
markdownFiles = await globby(ctx.inputFiles)
35+
}
36+
37+
compileSnippets({ markdownFiles, project: tsconfigPath })
38+
.then((results) => {
39+
results.forEach((result) => {
40+
if (result.error) {
41+
console.log(`Error compiling example code block ${result.index} in file ${result.file}`)
42+
console.log(result.error.message)
43+
console.log('Original code:')
44+
console.log(result.snippet)
45+
}
46+
})
47+
})
48+
.catch((error) => {
49+
console.error('Error compiling TypeScript snippets', error)
50+
})
51+
}
52+
53+
}
54+
],
55+
{
56+
renderer: 'verbose'
57+
}
58+
)
59+
60+
export default tasks

src/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import releaseRcCmd from './cmds/release-rc.js'
1818
import testDependantCmd from './cmds/test-dependant.js'
1919
import testCmd from './cmds/test.js'
2020
import docsCmd from './cmds/docs.js'
21+
import docVerifyCmd from './cmds/document-check.js'
2122
import execCmd from './cmds/exec.js'
2223
import runCmd from './cmds/run.js'
2324

@@ -87,6 +88,7 @@ async function main () {
8788
res.command(cleanCmd)
8889
res.command(dependencyCheckCmd)
8990
res.command(docsCmd)
91+
res.command(docVerifyCmd)
9092
res.command(lintPackageJsonCmd)
9193
res.command(lintCmd)
9294
res.command(releaseCmd)

src/lint.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import path from 'path'
77
import { execa } from 'execa'
88
import fs from 'fs-extra'
99
import merge from 'merge-options'
10-
import { fromRoot, readJson, hasTsconfig, isTypescript, findBinary } from './utils.js'
10+
import { fromRoot, readJson, hasTsconfig, isTypescript, findBinary, hasDocCheck } from './utils.js'
1111
import { fileURLToPath } from 'url'
1212
import kleur from 'kleur'
1313

@@ -99,6 +99,15 @@ const tasks = new Listr(
9999
fs.removeSync(fromRoot('dist', 'tsconfig-check.aegir.tsbuildinfo'))
100100
}
101101
}
102+
},
103+
{
104+
title: 'doc-check',
105+
enabled: () => hasDocCheck,
106+
task: async () => {
107+
await execa('npm', ['run', 'doc-check', '--if-present', '--', '--publish', 'false'], {
108+
stdio: 'inherit'
109+
})
110+
}
102111
}
103112
],
104113
{

src/types.ts

+21
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ interface Options extends GlobalOptions {
3636
* Options for the `dependency-check` command
3737
*/
3838
dependencyCheck: DependencyCheckOptions
39+
/**
40+
* Options for the `document-check` command
41+
*/
42+
documentCheck: DocsVerifierOptions
3943
/**
4044
* Options for the `exec` command
4145
*/
@@ -82,6 +86,10 @@ interface PartialOptions {
8286
* Options for the `dependency-check` command
8387
*/
8488
dependencyCheck?: DependencyCheckOptions
89+
/**
90+
* Options for the `document-check` command
91+
*/
92+
documentCheck?: DocsVerifierOptions
8593
}
8694

8795
interface GlobalOptions {
@@ -164,6 +172,18 @@ interface DocsOptions {
164172
directory: string
165173
}
166174

175+
interface DocsVerifierOptions {
176+
/**
177+
* The Markdown files to be verified, defaults to `README.md`
178+
*/
179+
inputFiles?: string[]
180+
181+
/**
182+
* An alternative `.tsconfig.json` path to be used seperately from the default
183+
*/
184+
tsConfigPath?: string
185+
}
186+
167187
interface LintOptions {
168188
/**
169189
* Automatically fix errors if possible.
@@ -350,6 +370,7 @@ export type {
350370
LintOptions,
351371
TestOptions,
352372
ReleaseOptions,
373+
DocsVerifierOptions,
353374
ReleaseRcOptions,
354375
DependencyCheckOptions,
355376
ExecOptions,

src/utils.js

+1
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ export const hasIndexTs = hasFile('src/index.ts')
252252
export const hasIndexJs = hasFile('src/index.js')
253253
export const isMonorepoParent = Boolean(pkg.workspaces)
254254
export const hasDocs = Boolean(pkg.scripts?.docs)
255+
export const hasDocCheck = Boolean(pkg.scripts && pkg.scripts['doc-check'])
255256

256257
// our project types:
257258

0 commit comments

Comments
 (0)