150 lines
3.5 KiB
JavaScript
150 lines
3.5 KiB
JavaScript
const arrayify = require('array-back')
|
|
const path = require('path')
|
|
|
|
/**
|
|
* @module jsdoc-command
|
|
*/
|
|
|
|
/**
|
|
* Command base class. The command `receiver` being the `child_process` module.
|
|
* @abstract
|
|
*/
|
|
class JsdocCommand {
|
|
constructor (options, cache) {
|
|
options = options || {}
|
|
options.files = arrayify(options.files)
|
|
|
|
this.cache = cache
|
|
this.tempFile = null
|
|
const TempFile = require('./temp-file')
|
|
if (options.source) this.tempFile = new TempFile(options.source)
|
|
|
|
const jsdocOptions = Object.assign({}, options)
|
|
delete jsdocOptions.files
|
|
delete jsdocOptions.source
|
|
delete jsdocOptions.cache
|
|
|
|
this.options = options
|
|
this.jsdocOptions = jsdocOptions
|
|
|
|
const walkBack = require('walk-back')
|
|
this.jsdocPath = walkBack(
|
|
path.join(__dirname, '..'),
|
|
path.join('node_modules', 'jsdoc', 'jsdoc.js')
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Template method returning the jsdoc output. Invoke later (for example via a command-queuing system) or immediately as required.
|
|
*
|
|
* 1. preExecute
|
|
* 2. validate
|
|
* 3. getOutput
|
|
* 4. postExecute
|
|
*
|
|
*/
|
|
execute () {
|
|
this.preExecute()
|
|
const err = this.validate()
|
|
this.output = this.getOutput(err)
|
|
if (this.output instanceof Promise) {
|
|
return this.output
|
|
.then(result => {
|
|
this.postExecute()
|
|
return result
|
|
})
|
|
.catch(err => {
|
|
this.postExecute()
|
|
throw err
|
|
})
|
|
} else {
|
|
this.postExecute()
|
|
return this.output
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform pre-execution processing here, e.g. expand input glob patterns.
|
|
*/
|
|
preExecute () {
|
|
const FileSet = require('file-set')
|
|
this.inputFileSet = new FileSet(this.options.files)
|
|
}
|
|
|
|
/**
|
|
* Return an Error instance if execution should not proceed.
|
|
* @returns {null|Error}
|
|
*/
|
|
validate () {
|
|
const assert = require('assert')
|
|
assert.ok(
|
|
this.options.files.length || this.options.source,
|
|
'Must set either .files or .source'
|
|
)
|
|
|
|
if (this.inputFileSet.notExisting.length) {
|
|
const err = new Error('These files do not exist: ' + this.inputFileSet.notExisting)
|
|
err.name = 'JSDOC_ERROR'
|
|
return err
|
|
}
|
|
}
|
|
|
|
/**
|
|
* perform post-execution cleanup
|
|
*/
|
|
postExecute () {
|
|
if (this.tempFile) {
|
|
this.tempFile.delete()
|
|
}
|
|
}
|
|
|
|
verifyOutput (code, output) {
|
|
let parseFailed = false
|
|
let parsedOutput
|
|
try {
|
|
parsedOutput = JSON.parse(output.stdout)
|
|
} catch (err) {
|
|
parseFailed = true
|
|
}
|
|
|
|
if (code > 0 || parseFailed) {
|
|
const firstLineOfStdout = output.stdout.split(/\r?\n/)[0]
|
|
const err = new Error(output.stderr.trim() || firstLineOfStdout || 'Jsdoc failed.')
|
|
err.name = 'JSDOC_ERROR'
|
|
throw err
|
|
} else {
|
|
return parsedOutput
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns a cached recordset
|
|
* @returns {Promise}
|
|
* @fulfil {object[]}
|
|
*/
|
|
readCache () {
|
|
if (this.cache) {
|
|
const fs = require('fs-then-native')
|
|
const promises = this.inputFileSet.files.map(file => fs.readFile(file, 'utf8'))
|
|
return Promise.all(promises)
|
|
.then(contents => {
|
|
this.cacheKey = contents.concat(this.inputFileSet.files)
|
|
return this.cache.read(this.cacheKey)
|
|
})
|
|
} else {
|
|
return Promise.reject()
|
|
}
|
|
}
|
|
|
|
readCacheSync () {
|
|
if (this.cache) {
|
|
const fs = require('fs')
|
|
const contents = this.inputFileSet.files.map(file => fs.readFileSync(file, 'utf8'))
|
|
this.cacheKey = contents.concat(this.inputFileSet.files)
|
|
return this.cache.readSync(this.cacheKey)
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = JsdocCommand
|