vue-docgen-cli
Version:
Generate documentation markdown files from VueJs components using the vue-docgen-api.
148 lines (135 loc) • 4.63 kB
text/typescript
import * as path from 'path'
import { FSWatcher } from 'chokidar'
import * as log from 'loglevel'
import type { ComponentDoc } from 'vue-docgen-api'
import { writeDownMdFile } from './utils'
import { DocgenCLIConfigWithComponents } from './docgen'
import compileTemplates from './compileTemplates'
import { FileEventType } from './config'
export interface DocgenCLIConfigWithOutFile extends DocgenCLIConfigWithComponents {
outFile: string
}
/**
* Build one md file combining all documentations for components in files
* if `config.watch` is true will keep on watch file changes
* and update the current file if needed
* @param files
* @param watcher
* @param config
* @param _compile
*/
export default async function (
files: string[],
watcher: FSWatcher,
config: DocgenCLIConfigWithOutFile,
docMap: { [filepath: string]: string },
_compile = compile
) {
// This fileCache contains will, because it is
// bound, the same along usage of this function.
// it will contain
// `key`: filePath of source component
// `content`: markdown compiled for it
const fileCache = {}
const docsCache = {}
const compileSingleDocWithConfig = (event: FileEventType, changedFilePath?: string) =>
_compile(config, files, fileCache, docsCache, docMap, watcher, event, changedFilePath)
await compileSingleDocWithConfig('init')
if (config.watch) {
watcher
.on('add', (filePath) => {
files.push(filePath)
compileSingleDocWithConfig('add', filePath)
})
.on('change', compileSingleDocWithConfig.bind(null, 'change'))
.on('unlink', compileSingleDocWithConfig.bind(null, 'delete'))
}
}
/**
* Compile all components in `files` into one single
* markdown file and save it to the `config.outFile`
* @param files the component files relative paths
* @param config config passed to the current chunk
* @param cachedContent in order to avoid re-parsing unchanged components pass an object where to store for future reference
* @param docMap a map of each documentation file to the component they refer to
* @param changedFilePath When in wtch mode, provide the relative path of the file that changes to only re-parse this file
*/
export async function compile(
config: DocgenCLIConfigWithOutFile,
files: string[],
cachedContent: { [filepath: string]: string },
cachedDocs: { [filepath: string]: ComponentDoc[] },
docMap: { [filepath: string]: string },
watcher: FSWatcher,
event: FileEventType,
changedFilePath?: string,
fromWatcher: boolean = true
) {
if (fromWatcher) {
log.info(`[vue-docgen-cli] ${event} to ${changedFilePath} detected`)
}
// this local function will enrich the cachedContent with the
// current components documentation
const cacheMarkDownContent = async (filePath: string) => {
const { content, dependencies, docs } = await compileTemplates(
event,
path.join(config.componentsRoot, filePath),
config,
filePath
)
dependencies.forEach(d => {
watcher.add(d)
docMap[d] = filePath
})
cachedContent[filePath] = content
cachedDocs[filePath] = docs
return true
}
if (changedFilePath) {
// resolve the real component file path before updating if needed
changedFilePath = docMap[changedFilePath] || changedFilePath
try {
// if in chokidar mode (watch), the path of the file that was just changed
// is passed as an argument. We only affect the changed file and avoid re-parsing the rest
await cacheMarkDownContent(changedFilePath)
} catch (e) {
if (config.watch) {
log.error(
'\x1b[31m%s\x1b[0m',
`[vue-docgen-cli] Error compiling file ${config.outFile}:`
)
log.error(e)
} else {
const err = e as Error
throw new Error(
`Error compiling file ${config.outFile} when file ${changedFilePath} has changed: ${err.message}`
)
}
}
} else {
try {
// if we are initializing the current file, parse all components
await Promise.all(files.map(cacheMarkDownContent))
} catch (e) {
if (config.watch) {
log.error(
`[vue-docgen-cli] Error compiling file ${config.outFile}:`
)
log.error(e)
} else {
const err = e as Error
throw new Error(`[vue-docgen-cli] Error compiling file ${config.outFile}: ${err.message}`)
}
}
}
// first sort the updated cachedContent
const sortedMd = Object.entries(cachedContent)
.map(([filePath, mdValue]) => ({ filePath, mdValue, docs: cachedDocs[filePath] }))
.sort(config.sortComponents)
// and finally save all concatenated values to the markdown file
await writeDownMdFile(
sortedMd.map(part => part.mdValue),
config.outFile
)
log.info(`[vue-docgen-cli] File ${config.outFile} updated.`)
}