Update to be more programmitic compatible

This commit is contained in:
Eric Eastwood 2017-01-31 12:50:14 -06:00
parent 907d33b94b
commit 985fe73348
3 changed files with 67 additions and 39 deletions

View File

@ -1,18 +1,10 @@
#!/usr/bin/env node #!/usr/bin/env node
var program = require('commander'), var program = require('commander'),
tmp = require('tmp'),
fs = require('fs'),
os = require('os'),
path = require('path'),
package = require('../package'), package = require('../package'),
spectacle = require('../index.js'); spectacle = require('../index.js');
// Ensures temporary files are cleaned up on program close, even if errors are encountered.
tmp.setGracefulCleanup();
var cwd = process.cwd(),
root = path.resolve(__dirname, '..');
// //
//= Process CLI input //= Process CLI input
@ -25,12 +17,12 @@ program.version(package.version)
.option('-e, --embeddable', 'omit the HTML <body/> and generate the documentation content only (default: false)') .option('-e, --embeddable', 'omit the HTML <body/> and generate the documentation content only (default: false)')
.option('-d, --development-mode', 'start HTTP server with the file watcher and live reload (default: false)') .option('-d, --development-mode', 'start HTTP server with the file watcher and live reload (default: false)')
.option('-s, --start-server', 'start the HTTP server without any development features') .option('-s, --start-server', 'start the HTTP server without any development features')
.option('-p, --port <dir>', 'the port number for the HTTP server to listen on (default: 4400)', Number, 4400) .option('-p, --port <dir>', 'the port number for the HTTP server to listen on (default: 4400)', Number)
.option('-t, --target-dir <dir>', 'the target build directory (default: public)', String, path.resolve(cwd, 'public')) .option('-t, --target-dir <dir>', 'the target build directory (default: public)', String)
.option('-f, --target-file <file>', 'the target build HTML file (default: index.html)', String, 'index.html') .option('-f, --target-file <file>', 'the target build HTML file (default: index.html)', String)
.option('-a, --app-dir <dir>', 'the application source directory (default: app)', String, path.resolve(root, 'app')) .option('-a, --app-dir <dir>', 'the application source directory (default: app)', String)
.option('-l, --logo-file <file>', 'specify a custom logo file (default: null)', String, null) .option('-l, --logo-file <file>', 'specify a custom logo file (default: null)', String, null)
.option('-c, --config-file <file>', 'specify a custom configuration file (default: app/lib/config.js)', String, path.resolve(root, 'app/lib/config.js')) .option('-c, --config-file <file>', 'specify a custom configuration file (default: app/lib/config.js)')
// .option('-f, --spec-file <file>', 'the input OpenAPI/Swagger spec file (default: test/fixtures/petstore.json)', String, 'test/fixtures/petstore.json') // .option('-f, --spec-file <file>', 'the input OpenAPI/Swagger spec file (default: test/fixtures/petstore.json)', String, 'test/fixtures/petstore.json')
.parse(process.argv); .parse(process.argv);
@ -39,15 +31,7 @@ if (program.args.length < 1) { // && program.rawArgs.length < 1
program.help(); program.help();
} }
// Create a new temporary directory, and set some necessary defaults
program.cacheDir = tmp.dirSync({ unsafeCleanup: true, prefix: 'spectacle-' }).name;
program.specFile = program.args[0]; // || path.resolve(root, 'test/fixtures/cheese.json'); program.specFile = program.args[0]; // || path.resolve(root, 'test/fixtures/cheese.json');
// Replace some absolute paths
if (program.specFile && program.specFile.indexOf('test/fixtures') === 0)
program.specFile = path.resolve(root, program.specFile);
if (program.logoFile && program.logoFile.indexOf('test/fixtures') === 0)
program.logoFile = path.resolve(root, program.logoFile);
// Run the main app with parsed options // Run the main app with parsed options
spectacle(program); spectacle(program);

View File

@ -6,32 +6,65 @@
var fs = require('fs'), var fs = require('fs'),
path = require('path'), path = require('path'),
Promise = require('bluebird'),
tmp = require('tmp'),
grunt = require('grunt'), grunt = require('grunt'),
package = require('./package'), package = require('./package'),
_ = require('lodash'); _ = require('lodash');
// Ensures temporary files are cleaned up on program close, even if errors are encountered.
tmp.setGracefulCleanup();
var defaults = {
silent: false,
port: 4400,
targetDir: path.resolve(process.cwd(), 'public'),
targetFile: 'index.html',
appDir: path.resolve(__dirname, 'app'),
configFile: path.resolve(__dirname, 'app/lib/config.js'),
cacheDir: tmp.dirSync({ unsafeCleanup: true, prefix: 'spectacle-' }).name
};
function resolveOptions(options) {
var opts = _.extend({}, defaults, options);
// Replace some absolute paths
if (opts.specFile && opts.specFile.indexOf('test/fixtures') === 0)
opts.specFile = path.resolve(__dirname, opts.specFile);
if (opts.logoFile && opts.logoFile.indexOf('test/fixtures') === 0)
opts.logoFile = path.resolve(__dirname, opts.logoFile);
return opts;
}
/** /**
* Run Spectacle and configured tasks * Run Spectacle and configured tasks
**/ **/
module.exports = function (options) { module.exports = function (options) {
var opts = resolveOptions(options);
// //
//= Load the specification and init configuration //= Load the specification and init configuration
function loadData() { function loadData() {
var specPath = path.resolve(options.specFile); var specPath = path.resolve(opts.specFile);
delete require.cache[specPath]; delete require.cache[specPath];
return require(path.resolve(options.appDir + '/lib/preprocessor'))( return require(path.resolve(opts.appDir + '/lib/preprocessor'))(
options, require(specPath)); options, require(specPath));
} }
var config = require(path.resolve(options.configFile))(grunt, options, loadData()); var config = require(path.resolve(opts.configFile))(grunt, opts, loadData());
// //
//= Setup Grunt to do the heavy lifting //= Setup Grunt to do the heavy lifting
grunt.initConfig(_.merge({ pkg: package }, config)); grunt.initConfig(_.merge({ pkg: package }, config));
if(opts.silent) {
grunt.log.writeln = function() {}
grunt.log.write = function() {}
grunt.log.header = function() {}
grunt.log.ok = function() {}
}
var cwd = process.cwd(); // change CWD for loadNpmTasks global install var cwd = process.cwd(); // change CWD for loadNpmTasks global install
var exists = grunt.file.exists(path.join(path.resolve('node_modules'), var exists = grunt.file.exists(path.join(path.resolve('node_modules'),
@ -54,7 +87,7 @@ module.exports = function (options) {
process.chdir(cwd); process.chdir(cwd);
grunt.registerTask('predentation', 'Remove indentation from generated <pre> tags.', function() { grunt.registerTask('predentation', 'Remove indentation from generated <pre> tags.', function() {
var html = fs.readFileSync(options.cacheDir + '/' + options.targetFile, 'utf8'); var html = fs.readFileSync(opts.cacheDir + '/' + opts.targetFile, 'utf8');
html = html.replace(/<pre.*?><code.*?>([\s\S]*?)<\/code><\/pre>/gmi, function(x, y) { html = html.replace(/<pre.*?><code.*?>([\s\S]*?)<\/code><\/pre>/gmi, function(x, y) {
var lines = x.split('\n'), level = null; var lines = x.split('\n'), level = null;
if (lines) { if (lines) {
@ -74,7 +107,7 @@ module.exports = function (options) {
} }
return lines.join('\n'); return lines.join('\n');
}); });
fs.writeFileSync(options.cacheDir + '/' + options.targetFile, html); fs.writeFileSync(opts.cacheDir + '/' + opts.targetFile, html);
}); });
grunt.registerTask('stylesheets', ['sass:scss', 'concat:css', 'cssmin']); grunt.registerTask('stylesheets', ['sass:scss', 'concat:css', 'cssmin']);
@ -92,38 +125,48 @@ module.exports = function (options) {
}); });
// Report, etc when all tasks have completed. // Report, etc when all tasks have completed.
grunt.task.options({ var donePromise = new Promise(function(resolve, reject) {
error: function(e) { grunt.task.options({
console.warn('Task error:', e); error: function(e) {
// TODO: fail here or push on? if(!opts.silent) {
}, console.warn('Task error:', e);
done: function() { }
console.log('All tasks complete'); // TODO: fail here or push on?
} reject(e);
},
done: function() {
if(!opts.silent) {
console.log('All tasks complete');
}
resolve();
}
});
}); });
// //
//= Run the shiz //= Run the shiz
if (options.startServer) { if (opts.startServer) {
grunt.task.run('server'); grunt.task.run('server');
} }
else { else {
if (!options.disableCss) { if (!opts.disableCss) {
grunt.task.run(['foundation', 'stylesheets']); grunt.task.run(['foundation', 'stylesheets']);
} }
if (!options.disableJs) { if (!opts.disableJs) {
grunt.task.run('javascripts'); grunt.task.run('javascripts');
} }
if (options.logoFile) { if (opts.logoFile) {
grunt.task.run('copy:logo'); grunt.task.run('copy:logo');
} }
grunt.task.run('templates'); grunt.task.run('templates');
if (options.developmentMode) { if (opts.developmentMode) {
grunt.task.run('develop'); grunt.task.run('develop');
} }
} }
grunt.task.start(); grunt.task.start();
return donePromise;
}; };

View File

@ -31,6 +31,7 @@
}, },
"homepage": "https://sourcey.com/spectacle", "homepage": "https://sourcey.com/spectacle",
"dependencies": { "dependencies": {
"bluebird": "^3.4.7",
"cheerio": "^0.19.0", "cheerio": "^0.19.0",
"clarify": "^1.0.5", "clarify": "^1.0.5",
"commander": "*", "commander": "*",