Skip to content

Commit

Permalink
Remove "find-package"-dependency from cli-script (+ refactoring)
Browse files Browse the repository at this point in the history
- Use "fs.readFile" instead of require to load package.json
- Wrap cli-script in a function to allow for better testability
- Test for the cli-script
  - A hard lesson was the one that "commander" has to be cleared from
    the "require.cache" in every cli-test. Otherwise the "done"-callback
    would be called multiple times in some cases.
- Fixed typo on help-message
  • Loading branch information
nknapp committed Jul 2, 2017
1 parent 6e2f575 commit 314d5c3
Show file tree
Hide file tree
Showing 9 changed files with 386 additions and 123 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Usage: thought [options] [command]
Commands:
run [options] Generate documentation from your package.json and some templates.
init Register scripts in the curent module's package.json
init Register scripts in the current module's package.json
check-engines Check that all engines (such as npm) have versions that ensure Thought to run correctly
up-to-date Perform up-to-date check of the current documentation. Exit with non-zero exit-code when thought must be run again.
Expand Down
115 changes: 1 addition & 114 deletions bin/thought.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,117 +5,4 @@
* Copyright (c) 2015 Nils Knappmeier.
* Released under the MIT license.
*/

/**
* @thought-usage
*
* Run this program in your project root folder to generate the documentation.
* It will run your package.json throught templates
*
*/
'use strict'

var program = require('commander')
var thought = require('../')
var debug = require('debug')('thought:bin')
var findPackage = require('find-package')
var path = require('path')

Error.stackTraceLimit = 0

debug('started')
program
.version(require('../package').version)
.option('-d, --debug', 'higher stack-trace-limit, long stack-traces', function (option) {
Error.stackTraceLimit = 30
require('trace-and-clarify-if-possible')
})

program
.command('run')
.option('-a, --add-to-git', 'git-add the modified files')
.description('Generate documentation from your package.json and some templates.')
.action(function (options) {
changeDir()
var packageJson = findPackage()
if (!(packageJson.scripts && packageJson.scripts.thought)) {
/* eslint-disable no-console */
console.log('\nNot registered in package.json yet!\n' +
'I can add a `scripts`-property to your package.json to ensure that ' +
'documentation is generated automatically on version bumps.\n' +
'If you want that, run `thought init`\n')
/* eslint-enable no-console */
}
debug('running thought')
thought({
addToGit: options.addToGit,
debug: program.debug
})
.then(
(filenames) => {
/* eslint-disable no-console */
console.log('The following files were updated: ' + filenames.join(', '))
/* eslint-enable no-console */
},
(err) => console.error(err) // eslint-disable-line no-console
)
})

program
.command('init')
.description('Register scripts in the curent module\'s package.json')
.action(function () {
changeDir()
require('../lib/check-engines.js')()
.then(require('../lib/init.js'))
.then(
() => console.log('OK'), // eslint-disable-line no-console
(err) => console.error(err) // eslint-disable-line no-console
)
})

program
.command('check-engines')
.description('Check that all engines (such as npm) have versions that ensure Thought to run correctly')
.action(function () {
require('../lib/check-engines.js')()
.then(
() => console.log('OK'), // eslint-disable-line no-console
(err) => console.error(err) // eslint-disable-line no-console
)
})

program
.command('up-to-date')
.description('Perform up-to-date check of the current documentation. Exit with non-zero exit-code when thought must be run again.')
.action(function () {
changeDir()
require('../lib/up-to-date.js')()
.then(
() => console.log('OK'), // eslint-disable-line no-console
(err) => console.error(err) // eslint-disable-line no-console
)
})

program.parse(process.argv)

if (program.args.length === 0) {
program.help()
}

// ----------------------------------------
// chdir to local module root
// ----------------------------------------
function changeDir () {
var packageJson = findPackage(process.cwd(), true)
if (!packageJson) {
throw new Error('package.json not found!\n' +
'Please run me from within a node module.\n' +
'My working directory is "' + process.cwd() + '".')
}

var moduleRoot = path.dirname(packageJson.paths.absolute)
process.chdir(moduleRoot)
// eslint-disable-next-line no-console
console.log('I\'m running inside module \'' + packageJson.name + '\' in \'' + moduleRoot)
}
require('../lib/cli.js')(process.argv, console, process.exit)
4 changes: 3 additions & 1 deletion customize.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
const path = require('path')
const fs = require('fs')
const debug = require('debug')
const pify = require('pify')
const readFile = pify(fs.readFile)

/**
* Default configuration for .thought. Override this configuration by creating a file `.thought/config.js`
Expand Down Expand Up @@ -48,7 +50,7 @@ module.exports = function createSpec (workingDir) {
templates: path.join(__dirname, 'handlebars', 'templates'),
helpers: require.resolve('./handlebars/helpers/index.js'),
data: {
'package': require(path.resolve(workingDir, 'package.json')),
'package': readFile(path.resolve(workingDir, 'package.json'), 'utf-8').then(JSON.parse),
config: config,
workingDir: workingDir
},
Expand Down
127 changes: 127 additions & 0 deletions lib/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env node
/*!
* thought <https://github.com/nknapp/thought>
*
* Copyright (c) 2015 Nils Knappmeier.
* Released under the MIT license.
*/
var thought = require('../')
var debug = require('debug')('thought:bin')
const {resolvePackageRoot} = require('../lib/utils/resolve-package-root')

/**
* @thought-usage
*
* Called by the cli-script. Exports a function for better testability
*
*/
module.exports = function (argv, console, done) {
Error.stackTraceLimit = 0
debug('started')

var program = require('commander')
program
.version(require('../package').version)
.option('-d, --debug', 'higher stack-trace-limit, long stack-traces', function (option) {
Error.stackTraceLimit = 30
require('trace-and-clarify-if-possible')
})

program
.command('run')
.option('-a, --add-to-git', 'git-add the modified files')
.description('Generate documentation from your package.json and some templates.')
.action(function (options) {
changeDir()
.then(() => resolvePackageRoot('package.json'))
.then((root) => {
if (!(root.packageJson.scripts && root.packageJson.scripts.thought)) {
/* eslint-disable no-console */
console.log('\nNot registered in package.json yet!\n' +
'I can add a `scripts`-property to your package.json to ensure that ' +
'documentation is generated automatically on version bumps.\n' +
'If you want that, run `thought init`\n')
/* eslint-enable no-console */
}
debug('running thought')
})
.then(() => thought({addToGit: options.addToGit, debug: program.debug}))
.then(
(filenames) => quit(null, 'The following files were updated: ' + filenames.join(', ')),
quit
)
})

program
.command('init')
.description('Register scripts in the current module\'s package.json')
.action(function () {
changeDir()
.then(require('../lib/check-engines.js'))
.then(require('../lib/init.js'))
.then(
() => quit(null, 'OK'),
quit
)
})

program
.command('check-engines')
.description('Check that all engines (such as npm) have versions that ensure Thought to run correctly')
.action(function () {
require('../lib/check-engines.js')()
.then(
() => quit(null, 'OK'),
quit
)
})

program
.command('up-to-date')
.description('Perform up-to-date check of the current documentation. Exit with non-zero exit-code when thought must be run again.')
.action(function () {
changeDir()
.then(require('../lib/up-to-date.js'))
.then(
() => quit(null, 'OK'),
quit
)
})

program.parse(argv)

/* istanbul ignore if: Not testable because it exits the process */
if (program.args.length === 0) {
program.help()
quit(null, '')
}

// ----------------------------------------
// chdir to local module root
// ----------------------------------------
function changeDir () {
return resolvePackageRoot('package.json')
.then(root => {
/* istanbul ignore if: Situation very hard to reproduce */
if (!root.packageJson) {
throw new Error('package.json not found!\n' +
'Please run me from within a node module.\n' +
'My working directory is "' + process.cwd() + '".')
}
process.chdir(root.packageRoot)
// eslint-disable-next-line no-console
console.log('I\'m running inside module \'' + root.packageJson.name + '\' in \'' + process.cwd())
})
}

function quit (err, message) {
/* eslint-disable no-console */
if (err) {
console.error(err, message)
return done(1)
}
console.log(message)
return done(0)
/* eslint-enable no-console */
}
}
2 changes: 0 additions & 2 deletions lib/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
* Copyright (c) 2015 Nils Knappmeier.
* Released under the MIT license.
*/
// var path = require('path')
var qfs = require('m-io/fs')
// var _ = require('lodash')
var debug = require('debug')('thought:init')
var exec = require('./utils/exeq')
var thoughtPackageJson = require('../package.json')
Expand Down
16 changes: 11 additions & 5 deletions lib/utils/resolve-package-root.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
const path = require('path')
const fs = require('fs')
const pify = require('pify')
const readFile = pify(fs.readFile)
const debug = require('debug')('thought:resolve-package')

module.exports = {resolvePackageRoot}
Expand All @@ -23,11 +25,15 @@ function resolvePackageRoot (file) {
let packagePath = path.join(lead, 'package.json')
try {
if (fs.statSync(packagePath).isFile()) {
return Promise.resolve({
packageRoot: path.relative(process.cwd(), lead),
relativeFile: path.relative(lead, fullPath),
packageJson: require(packagePath)
})
return readFile(packagePath)
.then(JSON.parse)
.then(packageJson => {
return {
packageRoot: path.relative(process.cwd(), lead) || '.',
relativeFile: path.relative(lead, fullPath),
packageJson
}
})
}
} catch (e) {
/* istanbul ignore else */
Expand Down
Loading

0 comments on commit 314d5c3

Please sign in to comment.