From 70f45d468df5373dd5b100b5f9cdb724ff44e67d Mon Sep 17 00:00:00 2001 From: hacksalot Date: Mon, 1 Feb 2016 21:14:36 -0500 Subject: [PATCH] Asynchrony. --- .gitignore | 1 + Gruntfile.js | 3 + dist/cli/error.js | 11 +- dist/cli/main.js | 44 +-- dist/cli/msg.js | 2 + dist/cli/msg.yml | 4 + dist/cli/out.js | 6 +- dist/core/abstract-resume.js | 2 + dist/core/default-formats.js | 2 + dist/core/default-options.js | 2 + dist/core/event-codes.js | 2 + dist/core/fluent-date.js | 2 + dist/core/fresh-resume.js | 2 + dist/core/fresh-theme.js | 2 + dist/core/jrs-resume.js | 2 + dist/core/jrs-theme.js | 2 + dist/core/resume-factory.js | 15 +- dist/core/status-codes.js | 5 +- dist/generators/base-generator.js | 2 + dist/generators/html-generator.js | 2 + dist/generators/html-pdf-cli-generator.js | 15 +- dist/generators/html-png-generator.js | 2 + dist/generators/json-generator.js | 2 + dist/generators/json-yaml-generator.js | 5 +- dist/generators/latex-generator.js | 2 + dist/generators/markdown-generator.js | 2 + dist/generators/template-generator.js | 2 + dist/generators/text-generator.js | 2 + dist/generators/word-generator.js | 2 + dist/generators/xml-generator.js | 2 + dist/generators/yaml-generator.js | 2 + dist/helpers/console-helpers.js | 2 + dist/helpers/generic-helpers.js | 2 + dist/helpers/handlebars-helpers.js | 2 + dist/helpers/underscore-helpers.js | 2 + dist/index.js | 2 + dist/inspectors/gap-inspector.js | 2 + dist/inspectors/keyword-inspector.js | 2 + dist/inspectors/totals-inspector.js | 2 + dist/renderers/handlebars-generator.js | 2 + dist/renderers/jrs-generator.js | 2 + dist/renderers/underscore-generator.js | 2 + dist/utils/file-contains.js | 2 + dist/utils/html-to-wpml.js | 2 + dist/utils/md2chalk.js | 2 + dist/utils/rasterize.js | 2 + dist/utils/safe-json-loader.js | 2 + dist/utils/safe-spawn.js | 2 + dist/utils/string-transformer.js | 2 + dist/utils/string.js | 2 + dist/utils/syntax-error-ex.js | 2 + dist/verbs/analyze.js | 60 ++-- dist/verbs/build.js | 63 ++-- dist/verbs/convert.js | 98 ++++--- dist/verbs/create.js | 66 ++++- dist/verbs/peek.js | 87 ++++-- dist/verbs/validate.js | 123 ++++---- dist/verbs/verb.js | 27 +- out/rez.yml | 285 +++++++++++++++++++ package.json | 1 + src/cli/error.coffee | 23 +- src/cli/main.coffee | 66 +++-- src/cli/msg.yml | 4 + src/cli/out.coffee | 8 +- src/core/resume-factory.coffee | 14 +- src/core/status-codes.coffee | 1 + src/generators/html-pdf-cli-generator.coffee | 10 +- src/generators/json-yaml-generator.coffee | 1 + src/verbs/analyze.coffee | 48 ++-- src/verbs/build.coffee | 123 ++++---- src/verbs/convert.coffee | 80 +++--- src/verbs/create.coffee | 65 +++-- src/verbs/peek.coffee | 78 ++--- src/verbs/validate.coffee | 104 ++++--- src/verbs/verb.coffee | 20 +- test/scripts/test-cli.js | 33 +-- test/scripts/test-hmr.txt | 2 +- 77 files changed, 1162 insertions(+), 519 deletions(-) create mode 100644 out/rez.yml diff --git a/.gitignore b/.gitignore index ce7e657..f1d9b58 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ doc/ docs/ local/ npm-debug.log +*.map # Emacs detritus # -*- mode: gitignore; -*- diff --git a/Gruntfile.js b/Gruntfile.js index eedafdb..b81b4ac 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,6 +17,9 @@ module.exports = function (grunt) { coffee: { main: { + options: { + sourceMap: true + }, expand: true, cwd: 'src', src: ['**/*.coffee'], diff --git a/dist/cli/error.js b/dist/cli/error.js index c5d9bad..cfa539a 100644 --- a/dist/cli/error.js +++ b/dist/cli/error.js @@ -35,8 +35,7 @@ Error-handling routines for HackMyResume. require('string.prototype.startswith'); - /** - Error handler for HackMyResume. All errors are handled here. + /** Error handler for HackMyResume. All errors are handled here. @class ErrorHandler */ @@ -62,7 +61,7 @@ Error-handling routines for HackMyResume. stack = ex.stack || (ex.inner && ex.inner.stack); stack && o(chalk.gray(stack)); } - if (ex.quit || objError.quit) { + if (shouldExit) { if (this.debug) { o(chalk.cyan('Exiting with error code ' + ex.fluenterror.toString())); } @@ -221,6 +220,10 @@ Error-handling routines for HackMyResume. msg = ex; } etype = 'error'; + break; + case HMSTATUS.createError: + msg = printf(M2C(this.msgs.createError.msg), ex.inner.path); + etype = 'error'; } return { msg: msg, @@ -231,3 +234,5 @@ Error-handling routines for HackMyResume. }; }).call(this); + +//# sourceMappingURL=error.js.map diff --git a/dist/cli/main.js b/dist/cli/main.js index cf71dc5..2f390ce 100644 --- a/dist/cli/main.js +++ b/dist/cli/main.js @@ -6,7 +6,7 @@ Definition of the `main` function. */ (function() { - var Command, EXTEND, FS, HME, HMR, HMSTATUS, OUTPUT, PAD, PATH, PKG, StringUtils, _, _opts, _out, _title, chalk, execute, initOptions, initialize, loadOptions, logMsg, main, safeLoadJSON, splitSrcDest; + var Command, EXTEND, FS, HME, HMR, HMSTATUS, OUTPUT, PAD, PATH, PKG, StringUtils, _, _err, _exitCallback, _opts, _out, _title, chalk, execute, initOptions, initialize, loadOptions, logMsg, main, safeLoadJSON, splitSrcDest; HMR = require('../index'); @@ -42,6 +42,10 @@ Definition of the `main` function. _out = new OUTPUT(_opts); + _err = require('./error'); + + _exitCallback = null; + /* A callable implementation of the HackMyResume CLI. Encapsulates the command @@ -51,9 +55,9 @@ Definition of the `main` function. process.argv (in production) or custom parameters (in test). */ - main = module.exports = function(rawArgs) { + main = module.exports = function(rawArgs, exitCallback) { var args, initInfo, program; - initInfo = initialize(rawArgs); + initInfo = initialize(rawArgs, exitCallback); args = initInfo.args; program = new Command('hackmyresume').version(PKG.version).description(chalk.yellow.bold('*** HackMyResume ***')).option('-s --silent', 'Run in silent mode').option('--no-color', 'Disable colors').option('--color', 'Enable colors').option('-d --debug', 'Enable diagnostics', false).option('-a --assert', 'Treat warnings as errors', false).option('-v --version', 'Show the version').allowUnknownOption(); program.jsonArgs = initInfo.options; @@ -92,8 +96,9 @@ Definition of the `main` function. /* Massage command-line args and setup Commander.js. */ - initialize = function(ar) { + initialize = function(ar, exitCallback) { var o; + _exitCallback = exitCallback || process.exit; o = initOptions(ar); o.silent || logMsg(_title); if (o.debug) { @@ -105,12 +110,13 @@ Definition of the `main` function. _out.log(chalk.cyan(PAD(' FRESCA:', 25, null, PAD.RIGHT)) + chalk.cyan.bold(PKG.dependencies.fresca)); _out.log(''); } + _err.init(o.debug, o.assert, o.silent); if (o.verb && !HMR.verbs[o.verb] && !HMR.alias[o.verb]) { - throw { + _err.err({ fluenterror: HMSTATUS.invalidCommand, quit: true, attempted: o.orgVerb - }; + }, true); } Command.prototype.missingArgument = function(name) { if (this.name() !== 'new') { @@ -136,7 +142,7 @@ Definition of the `main` function. initOptions = function(ar) { oVerb; - var args, cleanArgs, inf, isDebug, isMono, isSilent, oJSON, oVerb, optStr, optsIdx, verb, vidx; + var args, cleanArgs, inf, isAssert, isDebug, isMono, isSilent, oJSON, oVerb, optStr, optsIdx, verb, vidx; verb = ''; args = ar.slice(); cleanArgs = args.slice(2); @@ -177,6 +183,9 @@ Definition of the `main` function. isSilent = _.some(args, function(v) { return v === '-s' || v === '--silent'; }); + isAssert = _.some(args, function(v) { + return v === '-a' || v === '--assert'; + }); isMono = _.some(args, function(v) { return v === '--no-color'; }); @@ -184,6 +193,7 @@ Definition of the `main` function. color: !isMono, debug: isDebug, silent: isSilent, + assert: isAssert, orgVerb: oVerb, verb: verb, json: oJSON, @@ -195,24 +205,22 @@ Definition of the `main` function. /* Invoke a HackMyResume verb. */ execute = function(src, dst, opts, log) { - var hand, v; - loadOptions.call(this, opts, this.parent.jsonArgs); - hand = require('./error'); - hand.init(_opts.debug, _opts.assert, _opts.silent); + var onFail, prom, v; v = new HMR.verbs[this.name()](); + loadOptions.call(this, opts, this.parent.jsonArgs); _opts.errHandler = v; _out.init(_opts); v.on('hmr:status', function() { return _out["do"].apply(_out, arguments); }); v.on('hmr:error', function() { - return hand.err.apply(hand, arguments); + return _err.err.apply(_err, arguments); }); - v.invoke.call(v, src, dst, _opts, log); - if (v.errorCode) { - console.log('Exiting with error code ' + v.errorCode); - return process.exit(v.errorCode); - } + prom = v.invoke.call(v, src, dst, _opts, log); + onFail = function(err) { + _exitCallback(err.fluenterror ? err.fluenterror : err); + }; + prom.then((function() {}), onFail); }; @@ -282,3 +290,5 @@ Definition of the `main` function. }; }).call(this); + +//# sourceMappingURL=main.js.map diff --git a/dist/cli/msg.js b/dist/cli/msg.js index c8038a1..572a2b6 100644 --- a/dist/cli/msg.js +++ b/dist/cli/msg.js @@ -15,3 +15,5 @@ Message-handling routines for HackMyResume. module.exports = YAML.load(PATH.join(__dirname, 'msg.yml')); }).call(this); + +//# sourceMappingURL=msg.js.map diff --git a/dist/cli/msg.yml b/dist/cli/msg.yml index 755dd40..ebcf8a4 100644 --- a/dist/cli/msg.yml +++ b/dist/cli/msg.yml @@ -3,6 +3,8 @@ events: msg: Invoking **%s** command. beforeCreate: msg: Creating new **%s** resume: **%s** + afterCreate: + msg: Creating new **%s** resume: **%s** afterRead: msg: Reading **%s** resume: **%s** beforeTheme: @@ -96,3 +98,5 @@ errors: msg: "Invalid number of parameters. Expected: **%s**." missingParam: msg: The '**%s**' parameter was needed but not supplied. + createError: + msg: Failed to create **'%s'**. diff --git a/dist/cli/out.js b/dist/cli/out.js index db3dd6a..f440915 100644 --- a/dist/cli/out.js +++ b/dist/cli/out.js @@ -60,8 +60,8 @@ Output routines for HackMyResume. switch (evt.sub) { case HME.begin: return this.opts.debug && L(M2C(this.msgs.begin.msg, dbgStyle), evt.cmd.toUpperCase()); - case HME.beforeCreate: - L(M2C(this.msgs.beforeCreate.msg, 'green'), evt.fmt, evt.file); + case HME.afterCreate: + L(M2C(this.msgs.beforeCreate.msg, evt.isError ? 'red' : 'green'), evt.fmt, evt.file); break; case HME.beforeTheme: return this.opts.debug && L(M2C(this.msgs.beforeTheme.msg, dbgStyle), evt.theme.toUpperCase()); @@ -155,3 +155,5 @@ Output routines for HackMyResume. }); }).call(this); + +//# sourceMappingURL=out.js.map diff --git a/dist/core/abstract-resume.js b/dist/core/abstract-resume.js index 00ec0d1..0d99a78 100644 --- a/dist/core/abstract-resume.js +++ b/dist/core/abstract-resume.js @@ -69,3 +69,5 @@ Definition of the AbstractResume class. module.exports = AbstractResume; }).call(this); + +//# sourceMappingURL=abstract-resume.js.map diff --git a/dist/core/default-formats.js b/dist/core/default-formats.js index 44ad54b..3ae80dc 100644 --- a/dist/core/default-formats.js +++ b/dist/core/default-formats.js @@ -58,3 +58,5 @@ Event code definitions. ]; }).call(this); + +//# sourceMappingURL=default-formats.js.map diff --git a/dist/core/default-options.js b/dist/core/default-options.js index edb0975..0498ae9 100644 --- a/dist/core/default-options.js +++ b/dist/core/default-options.js @@ -16,3 +16,5 @@ Event code definitions. }; }).call(this); + +//# sourceMappingURL=default-options.js.map diff --git a/dist/core/event-codes.js b/dist/core/event-codes.js index 2cf736a..8ceeb92 100644 --- a/dist/core/event-codes.js +++ b/dist/core/event-codes.js @@ -37,3 +37,5 @@ Event code definitions. }; }).call(this); + +//# sourceMappingURL=event-codes.js.map diff --git a/dist/core/fluent-date.js b/dist/core/fluent-date.js index 971df34..86c5bda 100644 --- a/dist/core/fluent-date.js +++ b/dist/core/fluent-date.js @@ -103,3 +103,5 @@ The HackMyResume date representation. }; }).call(this); + +//# sourceMappingURL=fluent-date.js.map diff --git a/dist/core/fresh-resume.js b/dist/core/fresh-resume.js index 6fd9932..f48c038 100644 --- a/dist/core/fresh-resume.js +++ b/dist/core/fresh-resume.js @@ -517,3 +517,5 @@ Definition of the FRESHResume class. module.exports = FreshResume; }).call(this); + +//# sourceMappingURL=fresh-resume.js.map diff --git a/dist/core/fresh-theme.js b/dist/core/fresh-theme.js index 1441c03..d70740a 100644 --- a/dist/core/fresh-theme.js +++ b/dist/core/fresh-theme.js @@ -277,3 +277,5 @@ Definition of the FRESHTheme class. module.exports = FRESHTheme; }).call(this); + +//# sourceMappingURL=fresh-theme.js.map diff --git a/dist/core/jrs-resume.js b/dist/core/jrs-resume.js index 0a5b8b5..b3ebc82 100644 --- a/dist/core/jrs-resume.js +++ b/dist/core/jrs-resume.js @@ -429,3 +429,5 @@ Definition of the JRSResume class. module.exports = JRSResume; }).call(this); + +//# sourceMappingURL=jrs-resume.js.map diff --git a/dist/core/jrs-theme.js b/dist/core/jrs-theme.js index 4e5b26d..4c4f136 100644 --- a/dist/core/jrs-theme.js +++ b/dist/core/jrs-theme.js @@ -103,3 +103,5 @@ Definition of the JRSTheme class. module.exports = JRSTheme; }).call(this); + +//# sourceMappingURL=jrs-theme.js.map diff --git a/dist/core/resume-factory.js b/dist/core/resume-factory.js index fbdb313..93430e8 100644 --- a/dist/core/resume-factory.js +++ b/dist/core/resume-factory.js @@ -83,7 +83,7 @@ Definition of the ResumeFactory class. }; _parse = function(fileName, opts, eve) { - var ex, orgFormat, rawData, ret; + var orgFormat, rawData, ret; rawData = null; try { eve && eve.stat(HME.beforeRead, { @@ -108,20 +108,15 @@ Definition of the ResumeFactory class. }); return ret; } catch (_error) { - ex = { + return { fluenterror: rawData ? HACKMYSTATUS.parseError : HACKMYSTATUS.readError, inner: _error, raw: rawData, - file: fileName, - shouldExit: false + file: fileName }; - opts.quit && (ex.quit = true); - eve && eve.err(ex.fluenterror, ex); - if (opts["throw"]) { - throw ex; - } - return ex; } }; }).call(this); + +//# sourceMappingURL=resume-factory.js.map diff --git a/dist/core/status-codes.js b/dist/core/status-codes.js index 3c2f79c..965b2ba 100644 --- a/dist/core/status-codes.js +++ b/dist/core/status-codes.js @@ -31,7 +31,10 @@ Status codes for HackMyResume. compileTemplate: 21, themeLoad: 22, invalidParamCount: 23, - missingParam: 24 + missingParam: 24, + createError: 25 }; }).call(this); + +//# sourceMappingURL=status-codes.js.map diff --git a/dist/generators/base-generator.js b/dist/generators/base-generator.js index 591b972..ee8e159 100644 --- a/dist/generators/base-generator.js +++ b/dist/generators/base-generator.js @@ -31,3 +31,5 @@ Definition of the BaseGenerator class. }); }).call(this); + +//# sourceMappingURL=base-generator.js.map diff --git a/dist/generators/html-generator.js b/dist/generators/html-generator.js index e601852..e4f8385 100644 --- a/dist/generators/html-generator.js +++ b/dist/generators/html-generator.js @@ -40,3 +40,5 @@ Definition of the HTMLGenerator class. }); }).call(this); + +//# sourceMappingURL=html-generator.js.map diff --git a/dist/generators/html-pdf-cli-generator.js b/dist/generators/html-pdf-cli-generator.js index 65bfcf5..9e6ebe3 100644 --- a/dist/generators/html-pdf-cli-generator.js +++ b/dist/generators/html-pdf-cli-generator.js @@ -46,8 +46,19 @@ Definition of the HtmlPdfCLIGenerator class. return null; } }, + + /* Low-level error callback for spawn(). May be called after HMR process + termination, so object references may not be valid here. That's okay; if + the references are invalid, the error was already logged. We could use + spawn-watch here but that causes issues on legacy Node.js. + */ onError: function(ex, param) { - param.errHandler.err(HMSTATUS.pdfGeneration, ex); + var ref; + if ((ref = param.errHandler) != null) { + if (typeof ref.err === "function") { + ref.err(HMSTATUS.pdfGeneration, ex); + } + } } }); @@ -86,3 +97,5 @@ Definition of the HtmlPdfCLIGenerator class. }; }).call(this); + +//# sourceMappingURL=html-pdf-cli-generator.js.map diff --git a/dist/generators/html-png-generator.js b/dist/generators/html-png-generator.js index 730fee0..022c680 100644 --- a/dist/generators/html-png-generator.js +++ b/dist/generators/html-png-generator.js @@ -62,3 +62,5 @@ Definition of the HtmlPngGenerator class. }; }).call(this); + +//# sourceMappingURL=html-png-generator.js.map diff --git a/dist/generators/json-generator.js b/dist/generators/json-generator.js index 03c1f33..dfc1aac 100644 --- a/dist/generators/json-generator.js +++ b/dist/generators/json-generator.js @@ -43,3 +43,5 @@ Definition of the JsonGenerator class. }); }).call(this); + +//# sourceMappingURL=json-generator.js.map diff --git a/dist/generators/json-yaml-generator.js b/dist/generators/json-yaml-generator.js index 5f9caf2..b2f6e04 100644 --- a/dist/generators/json-yaml-generator.js +++ b/dist/generators/json-yaml-generator.js @@ -31,8 +31,11 @@ Definition of the JsonYamlGenerator class. generate: function(rez, f, opts) { var data; data = YAML.stringify(JSON.parse(rez.stringify()), Infinity, 2); - return FS.writeFileSync(f, data, 'utf8'); + FS.writeFileSync(f, data, 'utf8'); + return data; } }); }).call(this); + +//# sourceMappingURL=json-yaml-generator.js.map diff --git a/dist/generators/latex-generator.js b/dist/generators/latex-generator.js index 4daafcd..885e9a6 100644 --- a/dist/generators/latex-generator.js +++ b/dist/generators/latex-generator.js @@ -22,3 +22,5 @@ Definition of the LaTeXGenerator class. }); }).call(this); + +//# sourceMappingURL=latex-generator.js.map diff --git a/dist/generators/markdown-generator.js b/dist/generators/markdown-generator.js index 3bf3e56..eba9d95 100644 --- a/dist/generators/markdown-generator.js +++ b/dist/generators/markdown-generator.js @@ -22,3 +22,5 @@ Definition of the MarkdownGenerator class. }); }).call(this); + +//# sourceMappingURL=markdown-generator.js.map diff --git a/dist/generators/template-generator.js b/dist/generators/template-generator.js index 26dd95a..aaf8455 100644 --- a/dist/generators/template-generator.js +++ b/dist/generators/template-generator.js @@ -241,3 +241,5 @@ Definition of the TemplateGenerator class. TODO: Refactor }; }).call(this); + +//# sourceMappingURL=template-generator.js.map diff --git a/dist/generators/text-generator.js b/dist/generators/text-generator.js index bf33857..25554e8 100644 --- a/dist/generators/text-generator.js +++ b/dist/generators/text-generator.js @@ -22,3 +22,5 @@ Definition of the TextGenerator class. }); }).call(this); + +//# sourceMappingURL=text-generator.js.map diff --git a/dist/generators/word-generator.js b/dist/generators/word-generator.js index 098682a..7d019dd 100644 --- a/dist/generators/word-generator.js +++ b/dist/generators/word-generator.js @@ -17,3 +17,5 @@ Definition of the WordGenerator class. }); }).call(this); + +//# sourceMappingURL=word-generator.js.map diff --git a/dist/generators/xml-generator.js b/dist/generators/xml-generator.js index bb056eb..df87086 100644 --- a/dist/generators/xml-generator.js +++ b/dist/generators/xml-generator.js @@ -22,3 +22,5 @@ Definition of the XMLGenerator class. }); }).call(this); + +//# sourceMappingURL=xml-generator.js.map diff --git a/dist/generators/yaml-generator.js b/dist/generators/yaml-generator.js index 3142c32..b839a39 100644 --- a/dist/generators/yaml-generator.js +++ b/dist/generators/yaml-generator.js @@ -22,3 +22,5 @@ Definition of the YAMLGenerator class. }); }).call(this); + +//# sourceMappingURL=yaml-generator.js.map diff --git a/dist/helpers/console-helpers.js b/dist/helpers/console-helpers.js index 11af8ce..cd6dbdb 100644 --- a/dist/helpers/console-helpers.js +++ b/dist/helpers/console-helpers.js @@ -62,3 +62,5 @@ Generic template helper definitions for command-line output. }; }).call(this); + +//# sourceMappingURL=console-helpers.js.map diff --git a/dist/helpers/generic-helpers.js b/dist/helpers/generic-helpers.js index f2e1fab..f919816 100644 --- a/dist/helpers/generic-helpers.js +++ b/dist/helpers/generic-helpers.js @@ -614,3 +614,5 @@ Generic template helper definitions for HackMyResume / FluentCV. }; }).call(this); + +//# sourceMappingURL=generic-helpers.js.map diff --git a/dist/helpers/handlebars-helpers.js b/dist/helpers/handlebars-helpers.js index 6098873..8b93dca 100644 --- a/dist/helpers/handlebars-helpers.js +++ b/dist/helpers/handlebars-helpers.js @@ -27,3 +27,5 @@ Template helper definitions for Handlebars. }; }).call(this); + +//# sourceMappingURL=handlebars-helpers.js.map diff --git a/dist/helpers/underscore-helpers.js b/dist/helpers/underscore-helpers.js index bf8dbeb..72f96e6 100644 --- a/dist/helpers/underscore-helpers.js +++ b/dist/helpers/underscore-helpers.js @@ -34,3 +34,5 @@ Template helper definitions for Underscore. }; }).call(this); + +//# sourceMappingURL=underscore-helpers.js.map diff --git a/dist/index.js b/dist/index.js index cf5e62e..ea14270 100644 --- a/dist/index.js +++ b/dist/index.js @@ -47,3 +47,5 @@ API facade for HackMyCore. }; }).call(this); + +//# sourceMappingURL=index.js.map diff --git a/dist/inspectors/gap-inspector.js b/dist/inspectors/gap-inspector.js index 78e38b5..364695f 100644 --- a/dist/inspectors/gap-inspector.js +++ b/dist/inspectors/gap-inspector.js @@ -136,3 +136,5 @@ Employment gap analysis for HackMyResume. }; }).call(this); + +//# sourceMappingURL=gap-inspector.js.map diff --git a/dist/inspectors/keyword-inspector.js b/dist/inspectors/keyword-inspector.js index 2d52aa9..9a237fc 100644 --- a/dist/inspectors/keyword-inspector.js +++ b/dist/inspectors/keyword-inspector.js @@ -59,3 +59,5 @@ Keyword analysis for HackMyResume. }; }).call(this); + +//# sourceMappingURL=keyword-inspector.js.map diff --git a/dist/inspectors/totals-inspector.js b/dist/inspectors/totals-inspector.js index 3aac8f7..a9ef275 100644 --- a/dist/inspectors/totals-inspector.js +++ b/dist/inspectors/totals-inspector.js @@ -47,3 +47,5 @@ Section analysis for HackMyResume. }; }).call(this); + +//# sourceMappingURL=totals-inspector.js.map diff --git a/dist/renderers/handlebars-generator.js b/dist/renderers/handlebars-generator.js index 5f0cdca..1409a5a 100644 --- a/dist/renderers/handlebars-generator.js +++ b/dist/renderers/handlebars-generator.js @@ -98,3 +98,5 @@ Definition of the HandlebarsGenerator class. }; }).call(this); + +//# sourceMappingURL=handlebars-generator.js.map diff --git a/dist/renderers/jrs-generator.js b/dist/renderers/jrs-generator.js index 1f6ad80..23b1bc8 100644 --- a/dist/renderers/jrs-generator.js +++ b/dist/renderers/jrs-generator.js @@ -57,3 +57,5 @@ Definition of the JRSGenerator class. }; }).call(this); + +//# sourceMappingURL=jrs-generator.js.map diff --git a/dist/renderers/underscore-generator.js b/dist/renderers/underscore-generator.js index 5e52bc5..4154e07 100644 --- a/dist/renderers/underscore-generator.js +++ b/dist/renderers/underscore-generator.js @@ -58,3 +58,5 @@ Definition of the UnderscoreGenerator class. }; }).call(this); + +//# sourceMappingURL=underscore-generator.js.map diff --git a/dist/utils/file-contains.js b/dist/utils/file-contains.js index a64967f..9f42854 100644 --- a/dist/utils/file-contains.js +++ b/dist/utils/file-contains.js @@ -10,3 +10,5 @@ Definition of the SyntaxErrorEx class. }; }).call(this); + +//# sourceMappingURL=file-contains.js.map diff --git a/dist/utils/html-to-wpml.js b/dist/utils/html-to-wpml.js index 4c00b99..bef0dd6 100644 --- a/dist/utils/html-to-wpml.js +++ b/dist/utils/html-to-wpml.js @@ -59,3 +59,5 @@ Definition of the Markdown to WordProcessingML conversion routine. }; }).call(this); + +//# sourceMappingURL=html-to-wpml.js.map diff --git a/dist/utils/md2chalk.js b/dist/utils/md2chalk.js index 783121a..eb60680 100644 --- a/dist/utils/md2chalk.js +++ b/dist/utils/md2chalk.js @@ -26,3 +26,5 @@ Inline Markdown-to-Chalk conversion routines. }; }).call(this); + +//# sourceMappingURL=md2chalk.js.map diff --git a/dist/utils/rasterize.js b/dist/utils/rasterize.js index b180f1e..9abb69c 100644 --- a/dist/utils/rasterize.js +++ b/dist/utils/rasterize.js @@ -75,3 +75,5 @@ } }).call(this); + +//# sourceMappingURL=rasterize.js.map diff --git a/dist/utils/safe-json-loader.js b/dist/utils/safe-json-loader.js index ecb195f..51f2d2e 100644 --- a/dist/utils/safe-json-loader.js +++ b/dist/utils/safe-json-loader.js @@ -30,3 +30,5 @@ Definition of the SafeJsonLoader class. }; }).call(this); + +//# sourceMappingURL=safe-json-loader.js.map diff --git a/dist/utils/safe-spawn.js b/dist/utils/safe-spawn.js index 8a1b754..83ce914 100644 --- a/dist/utils/safe-spawn.js +++ b/dist/utils/safe-spawn.js @@ -42,3 +42,5 @@ exception }; }).call(this); + +//# sourceMappingURL=safe-spawn.js.map diff --git a/dist/utils/string-transformer.js b/dist/utils/string-transformer.js index 8eb9c1c..52fdc41 100644 --- a/dist/utils/string-transformer.js +++ b/dist/utils/string-transformer.js @@ -60,3 +60,5 @@ Object string transformation. }; }).call(this); + +//# sourceMappingURL=string-transformer.js.map diff --git a/dist/utils/string.js b/dist/utils/string.js index 36b23a3..f2b5912 100644 --- a/dist/utils/string.js +++ b/dist/utils/string.js @@ -25,3 +25,5 @@ See: http://stackoverflow.com/a/32800728/4942583 }; }).call(this); + +//# sourceMappingURL=string.js.map diff --git a/dist/utils/syntax-error-ex.js b/dist/utils/syntax-error-ex.js index 556b726..5ea2cea 100644 --- a/dist/utils/syntax-error-ex.js +++ b/dist/utils/syntax-error-ex.js @@ -37,3 +37,5 @@ See: http://stackoverflow.com/q/13323356 module.exports = SyntaxErrorEx; }).call(this); + +//# sourceMappingURL=syntax-error-ex.js.map diff --git a/dist/verbs/analyze.js b/dist/verbs/analyze.js index 6ddf11c..58e08d1 100644 --- a/dist/verbs/analyze.js +++ b/dist/verbs/analyze.js @@ -6,7 +6,7 @@ Implementation of the 'analyze' verb for HackMyResume. */ (function() { - var AnalyzeVerb, HMEVENT, HMSTATUS, MKDIRP, PATH, ResumeFactory, Verb, _, _analyze, _loadInspectors, analyze, chalk; + var AnalyzeVerb, HMEVENT, HMSTATUS, MKDIRP, PATH, ResumeFactory, Verb, _, _analyze, _analyzeOne, _loadInspectors, chalk; MKDIRP = require('mkdirp'); @@ -24,46 +24,56 @@ Implementation of the 'analyze' verb for HackMyResume. chalk = require('chalk'); + + /** An invokable resume analysis command. */ + AnalyzeVerb = module.exports = Verb.extend({ init: function() { - return this._super('analyze', analyze); + return this._super('analyze', _analyze); } }); - /** - Run the 'analyze' command. - */ + /** Private workhorse for the 'analyze' command. */ - analyze = function(sources, dst, opts) { - var nlzrs; + _analyze = function(sources, dst, opts) { + var nlzrs, results; if (!sources || !sources.length) { - throw { - fluenterror: HMSTATUS.resumeNotFound, + this.err(HMSTATUS.resumeNotFound, { quit: true - }; + }); + return null; } nlzrs = _loadInspectors(); - return _.each(sources, function(src) { - var result; - result = ResumeFactory.loadOne(src, { + results = _.map(sources, function(src) { + var r; + r = ResumeFactory.loadOne(src, { format: 'FRESH', objectify: true }, this); - if (result.fluenterror) { - return this.setError(result.fluenterror, result); + if (opts.assert && this.hasError()) { + return {}; + } + if (r.fluenterror) { + r.quit = opts.assert; + this.err(r.fluenterror, r); + return r; } else { - return _analyze.call(this, result, nlzrs, opts); + return _analyzeOne.call(this, r, nlzrs, opts); } }, this); + if (this.hasError() && !opts.assert) { + this.reject(this.errorCode); + } else if (!this.hasError()) { + this.resolve(results); + } + return results; }; - /** - Analyze a single resume. - */ + /** Analyze a single resume. */ - _analyze = function(resumeObject, nlzrs, opts) { + _analyzeOne = function(resumeObject, nlzrs, opts) { var info, rez, safeFormat; rez = resumeObject.rez; safeFormat = rez.meta && rez.meta.format && rez.meta.format.startsWith('FRESH') ? 'FRESH' : 'JRS'; @@ -74,16 +84,12 @@ Implementation of the 'analyze' verb for HackMyResume. info = _.mapObject(nlzrs, function(val, key) { return val.run(rez); }); - return this.stat(HMEVENT.afterAnalyze, { + this.stat(HMEVENT.afterAnalyze, { info: info }); + return info; }; - - /** - Load inspectors. - */ - _loadInspectors = function() { return { totals: require('../inspectors/totals-inspector'), @@ -93,3 +99,5 @@ Implementation of the 'analyze' verb for HackMyResume. }; }).call(this); + +//# sourceMappingURL=analyze.js.map diff --git a/dist/verbs/build.js b/dist/verbs/build.js index ff570b3..4aacd8f 100644 --- a/dist/verbs/build.js +++ b/dist/verbs/build.js @@ -6,7 +6,7 @@ Implementation of the 'build' verb for HackMyResume. */ (function() { - var BuildVerb, FRESHTheme, FS, HMEVENT, HMSTATUS, JRSTheme, MD, MKDIRP, PATH, RConverter, RTYPES, ResumeFactory, Verb, _, _err, _fmts, _log, _opts, _rezObj, addFreebieFormats, build, expand, extend, loadTheme, parsePath, prep, single, verifyOutputs, verifyTheme; + var BuildVerb, FRESHTheme, FS, HMEVENT, HMSTATUS, JRSTheme, MD, MKDIRP, PATH, RConverter, RTYPES, ResumeFactory, Verb, _, _addFreebieFormats, _build, _err, _expand, _fmts, _loadTheme, _log, _opts, _prep, _rezObj, _single, _verifyOutputs, _verifyTheme, addFreebieFormats, build, expand, extend, loadTheme, parsePath, prep, single, verifyOutputs, verifyTheme; _ = require('underscore'); @@ -74,7 +74,7 @@ Implementation of the 'build' verb for HackMyResume. /** Create a new build verb. */ init: function() { - return this._super('build', build); + return this._super('build', _build); } }); @@ -87,15 +87,15 @@ Implementation of the 'build' verb for HackMyResume. @param opts Generation options. */ - build = function(src, dst, opts) { - var ex, inv, isFRESH, mixed, newEx, orgFormat, problemSheets, rez, sheetObjects, sheets, tFolder, targets, theme, toFormat; + _build = function(src, dst, opts) { + var inv, isFRESH, mixed, newEx, orgFormat, problemSheets, results, rez, sheetObjects, sheets, tFolder, targets, theme, toFormat; if (!src || !src.length) { this.err(HMSTATUS.resumeNotFound, { quit: true }); return null; } - prep(src, dst, opts); + _prep(src, dst, opts); sheetObjects = ResumeFactory.load(src, { format: null, objectify: false, @@ -120,14 +120,13 @@ Implementation of the 'build' verb for HackMyResume. theme: _opts.theme }); try { - tFolder = verifyTheme.call(this, _opts.theme); - theme = _opts.themeObj = loadTheme(tFolder); - addFreebieFormats(theme); + tFolder = _verifyTheme.call(this, _opts.theme); + theme = _opts.themeObj = _loadTheme(tFolder); + _addFreebieFormats(theme); } catch (_error) { - ex = _error; newEx = { fluenterror: HMSTATUS.themeLoad, - inner: ex, + inner: _error, attempted: _opts.theme, quit: true }; @@ -137,7 +136,7 @@ Implementation of the 'build' verb for HackMyResume. this.stat(HMEVENT.afterTheme, { theme: theme }); - inv = verifyOutputs.call(this, dst, theme); + inv = _verifyOutputs.call(this, dst, theme); if (inv && inv.length) { this.err(HMSTATUS.invalidFormat, { data: inv, @@ -187,15 +186,28 @@ Implementation of the 'build' verb for HackMyResume. theme: theme }); _rezObj = new RTYPES[toFormat]().parseJSON(rez); - targets = expand(dst, theme); + targets = _expand(dst, theme); _.each(targets, function(t) { - return t.final = single.call(this, t, theme, targets); + if (this.hasError() && opts.assert) { + return {}; + } + t.final = _single.call(this, t, theme, targets); + if (t.final.fluenterror) { + t.final.quit = opts.assert; + this.err(t.final.fluenterror, t.final); + } }, this); - return { + results = { sheet: _rezObj, targets: targets, processed: targets }; + if (this.hasError() && !opts.assert) { + this.reject(results); + } else if (!this.hasError()) { + this.resolve(results); + } + return results; }; @@ -203,7 +215,7 @@ Implementation of the 'build' verb for HackMyResume. Prepare for a BUILD run. */ - prep = function(src, dst, opts) { + _prep = function(src, dst, opts) { _opts.theme = (opts.theme && opts.theme.toLowerCase().trim()) || 'modern'; _opts.prettify = opts.prettify === true; _opts.css = opts.css; @@ -226,7 +238,7 @@ Implementation of the 'build' verb for HackMyResume. @param theme A FRESHTheme or JRSTheme object. */ - single = function(targInfo, theme, finished) { + _single = function(targInfo, theme, finished) { var e, ex, f, fName, fType, outFolder, ret, theFormat; ret = null; ex = null; @@ -268,11 +280,12 @@ Implementation of the 'build' verb for HackMyResume. }); if (ex) { if (ex.fluenterror) { - this.err(ex.fluenterror, ex); + ret = ex; } else { - this.err(HMSTATUS.generateError, { + ret = { + fluenterror: HMSTATUS.generateError, inner: ex - }); + }; } } return ret; @@ -281,7 +294,7 @@ Implementation of the 'build' verb for HackMyResume. /** Ensure that user-specified outputs/targets are valid. */ - verifyOutputs = function(targets, theme) { + _verifyOutputs = function(targets, theme) { this.stat(HMEVENT.verifyOutputs, { targets: targets, theme: theme @@ -308,7 +321,7 @@ Implementation of the 'build' verb for HackMyResume. @param theTheme A FRESHTheme or JRSTheme object. */ - addFreebieFormats = function(theTheme) { + _addFreebieFormats = function(theTheme) { theTheme.formats.json = theTheme.formats.json || { freebie: true, title: 'json', @@ -347,7 +360,7 @@ Implementation of the 'build' verb for HackMyResume. @param theTheme A FRESHTheme or JRSTheme object. */ - expand = function(dst, theTheme) { + _expand = function(dst, theTheme) { var destColl, targets; destColl = (dst && dst.length && dst) || [PATH.normalize('out/resume.all')]; targets = []; @@ -378,7 +391,7 @@ Implementation of the 'build' verb for HackMyResume. Verify the specified theme name/path. */ - verifyTheme = function(themeNameOrPath) { + _verifyTheme = function(themeNameOrPath) { var exists, tFolder; tFolder = PATH.join(parsePath(require.resolve('fresh-themes')).dirname, '/themes/', themeNameOrPath); exists = require('path-exists').sync; @@ -399,7 +412,7 @@ Implementation of the 'build' verb for HackMyResume. theme. */ - loadTheme = function(tFolder) { + _loadTheme = function(tFolder) { var theTheme; theTheme = _opts.theme.indexOf('jsonresume-theme-') > -1 ? new JRSTheme().open(tFolder) : new FRESHTheme().open(tFolder); _opts.themeObj = theTheme; @@ -407,3 +420,5 @@ Implementation of the 'build' verb for HackMyResume. }; }).call(this); + +//# sourceMappingURL=build.js.map diff --git a/dist/verbs/convert.js b/dist/verbs/convert.js index c4fc978..5e70861 100644 --- a/dist/verbs/convert.js +++ b/dist/verbs/convert.js @@ -6,7 +6,7 @@ Implementation of the 'convert' verb for HackMyResume. */ (function() { - var ConvertVerb, HMEVENT, HMSTATUS, ResumeFactory, Verb, _, chalk, convert; + var ConvertVerb, HMEVENT, HMSTATUS, ResumeFactory, Verb, _, _convert, _convertOne, chalk; ResumeFactory = require('../core/resume-factory'); @@ -22,67 +22,87 @@ Implementation of the 'convert' verb for HackMyResume. ConvertVerb = module.exports = Verb.extend({ init: function() { - return this._super('convert', convert); + return this._super('convert', _convert); } }); - /** - Convert between FRESH and JRS formats. + /** Private workhorse method. Convert 0..N resumes between FRESH and JRS + formats. */ - convert = function(srcs, dst, opts) { + _convert = function(srcs, dst, opts) { + var results; if (!srcs || !srcs.length) { - throw { - fluenterror: 6, + this.err(HMSTATUS.resumeNotFound, { quit: true - }; + }); + return null; } if (!dst || !dst.length) { if (srcs.length === 1) { - throw { - fluenterror: HMSTATUS.inputOutputParity, + this.err(HMSTATUS.inputOutputParity, { quit: true - }; + }); } else if (srcs.length === 2) { dst = dst || []; dst.push(srcs.pop()); } else { - throw { - fluenterror: HMSTATUS.inputOutputParity, + this.err(HMSTATUS.inputOutputParity, { quit: true - }; + }); } } if (srcs && dst && srcs.length && dst.length && srcs.length !== dst.length) { - throw { - fluenterror: HMSTATUS.inputOutputParity({ - quit: true - }) - }; + this.err(HMSTATUS.inputOutputParity, { + quit: true + }); } - _.each(srcs, function(src, idx) { - var rinfo, s, srcFmt, targetFormat; - rinfo = ResumeFactory.loadOne(src, { - format: null, - objectify: true, - "throw": false - }); - if (rinfo.fluenterror) { - this.err(rinfo.fluenterror, rinfo); - return; + results = _.map(srcs, function(src, idx) { + var r; + if (opts.assert && this.hasError()) { + return {}; } - s = rinfo.rez; - srcFmt = ((s.basics && s.basics.imp) || s.imp).orgFormat === 'JRS' ? 'JRS' : 'FRESH'; - targetFormat = srcFmt === 'JRS' ? 'FRESH' : 'JRS'; - this.stat(HMEVENT.beforeConvert, { - srcFile: rinfo.file, - srcFmt: srcFmt, - dstFile: dst[idx], - dstFmt: targetFormat - }); - s.saveAs(dst[idx], targetFormat); + r = _convertOne.call(this, src, dst, idx); + if (r.fluenterror) { + r.quit = opts.assert; + this.err(r.fluenterror, r); + } + return r; }, this); + if (this.hasError() && !opts.assert) { + this.reject(results); + } else if (!this.hasError()) { + this.resolve(results); + } + return results; + }; + + + /** Private workhorse method. Convert a single resume. */ + + _convertOne = function(src, dst, idx) { + var rinfo, s, srcFmt, targetFormat; + rinfo = ResumeFactory.loadOne(src, { + format: null, + objectify: true + }); + if (rinfo.fluenterror) { + return rinfo; + } + s = rinfo.rez; + srcFmt = ((s.basics && s.basics.imp) || s.imp).orgFormat === 'JRS' ? 'JRS' : 'FRESH'; + targetFormat = srcFmt === 'JRS' ? 'FRESH' : 'JRS'; + this.stat(HMEVENT.beforeConvert, { + srcFile: rinfo.file, + srcFmt: srcFmt, + dstFile: dst[idx], + dstFmt: targetFormat + }); + s.saveAs(dst[idx], targetFormat); + return s; }; }).call(this); + +//# sourceMappingURL=convert.js.map diff --git a/dist/verbs/create.js b/dist/verbs/create.js index c74abaf..d27b030 100644 --- a/dist/verbs/create.js +++ b/dist/verbs/create.js @@ -6,7 +6,7 @@ Implementation of the 'create' verb for HackMyResume. */ (function() { - var CreateVerb, HMEVENT, HMSTATUS, MKDIRP, PATH, Verb, _, chalk, create; + var CreateVerb, HMEVENT, HMSTATUS, MKDIRP, PATH, Verb, _, _create, _createOne, chalk; MKDIRP = require('mkdirp'); @@ -24,24 +24,48 @@ Implementation of the 'create' verb for HackMyResume. CreateVerb = module.exports = Verb.extend({ init: function() { - return this._super('new', create); + return this._super('new', _create); } }); - /** - Create a new empty resume in either FRESH or JRS format. - */ + /** Create a new empty resume in either FRESH or JRS format. */ - create = function(src, dst, opts) { + _create = function(src, dst, opts) { + var results; if (!src || !src.length) { - throw { - fluenterror: HMSTATUS.createNameMissing, + this.err(HMSTATUS.createNameMissing, { quit: true - }; + }); + return null; } - _.each(src, function(t) { - var RezClass, safeFmt; + results = _.map(src, function(t) { + var r; + if (opts.assert && this.hasError()) { + return {}; + } + r = _createOne.call(this, t, opts); + if (r.fluenterror) { + r.quit = opts.assert; + this.err(r.fluenterror, r); + } + return r; + }, this); + if (this.hasError() && !opts.assert) { + this.reject(results); + } else if (!this.hasError()) { + this.resolve(results); + } + return results; + }; + + + /** Create a single new resume */ + + _createOne = function(t, opts) { + var RezClass, newRez, ret, safeFmt; + try { + ret = null; safeFmt = opts.format.toUpperCase(); this.stat(HMEVENT.beforeCreate, { fmt: safeFmt, @@ -49,12 +73,24 @@ Implementation of the 'create' verb for HackMyResume. }); MKDIRP.sync(PATH.dirname(t)); RezClass = require('../core/' + safeFmt.toLowerCase() + '-resume'); - RezClass["default"]().save(t); - return this.stat(HMEVENT.afterCreate, { + newRez = RezClass["default"](); + newRez.save(t); + ret = newRez; + } catch (_error) { + ret = { + fluenterror: HMSTATUS.createError, + inner: _error + }; + } finally { + this.stat(HMEVENT.afterCreate, { fmt: safeFmt, - file: t + file: t, + isError: ret.fluenterror }); - }, this); + return ret; + } }; }).call(this); + +//# sourceMappingURL=create.js.map diff --git a/dist/verbs/peek.js b/dist/verbs/peek.js index 0538221..24f640a 100644 --- a/dist/verbs/peek.js +++ b/dist/verbs/peek.js @@ -6,7 +6,7 @@ Implementation of the 'peek' verb for HackMyResume. */ (function() { - var HMEVENT, HMSTATUS, PeekVerb, Verb, _, __, peek, safeLoadJSON; + var HMEVENT, HMSTATUS, PeekVerb, Verb, _, __, _peek, _peekOne, safeLoadJSON; Verb = require('../verbs/verb'); @@ -22,49 +22,74 @@ Implementation of the 'peek' verb for HackMyResume. PeekVerb = module.exports = Verb.extend({ init: function() { - return this._super('peek', peek); + return this._super('peek', _peek); } }); /** Peek at a resume, resume section, or resume field. */ - peek = function(src, dst, opts) { - var objPath; + _peek = function(src, dst, opts) { + var objPath, results; if (!src || !src.length) { - ({ - "throw": { - fluenterror: HMSTATUS.resumeNotFound - } + this.err(HMSTATUS.resumeNotFound, { + quit: true }); + return null; } objPath = (dst && dst[0]) || ''; - _.each(src, function(t) { - var errCode, obj, tgt; - this.stat(HMEVENT.beforePeek, { - file: t, - target: objPath - }); - obj = safeLoadJSON(t); - tgt = null; - if (!obj.ex) { - tgt = objPath ? __.get(obj.json, objPath) : obj.json; + results = _.map(src, function(t) { + var tgt; + if (opts.assert && this.hasError()) { + return {}; } - this.stat(HMEVENT.afterPeek, { - file: t, - requested: objPath, - target: tgt, - error: obj.ex - }); - if (obj.ex) { - errCode = obj.ex.operation === 'parse' ? HMSTATUS.parseError : HMSTATUS.readError; - if (errCode === HMSTATUS.readError) { - obj.ex.quiet = true; - } - this.setError(errCode, obj.ex); - return this.err(errCode, obj.ex); + tgt = _peekOne.call(this, t, objPath); + if (tgt.fluenterror) { + tgt.quit = opts.assert; + return this.err(tgt.fluenterror, tgt); } }, this); + if (this.hasError() && !opts.assert) { + this.reject(this.errorCode); + } else if (!this.hasError()) { + this.resolve(results); + } + return results; + }; + + + /** Peek at a single resume, resume section, or resume field. */ + + _peekOne = function(t, objPath) { + var errCode, obj, tgt; + this.stat(HMEVENT.beforePeek, { + file: t, + target: objPath + }); + obj = safeLoadJSON(t); + tgt = null; + if (!obj.ex) { + tgt = objPath ? __.get(obj.json, objPath) : obj.json; + } + this.stat(HMEVENT.afterPeek, { + file: t, + requested: objPath, + target: tgt, + error: obj.ex + }); + if (obj.ex) { + errCode = obj.ex.operation === 'parse' ? HMSTATUS.parseError : HMSTATUS.readError; + if (errCode === HMSTATUS.readError) { + obj.ex.quiet = true; + } + return { + fluenterror: errCode, + inner: obj.ex + }; + } + return tgt; }; }).call(this); + +//# sourceMappingURL=peek.js.map diff --git a/dist/verbs/validate.js b/dist/verbs/validate.js index d771a28..488ae94 100644 --- a/dist/verbs/validate.js +++ b/dist/verbs/validate.js @@ -6,7 +6,7 @@ Implementation of the 'validate' verb for HackMyResume. */ (function() { - var FS, HMEVENT, HMSTATUS, ResumeFactory, SyntaxErrorEx, ValidateVerb, Verb, _, chalk, safeLoadJSON, validate; + var FS, HMEVENT, HMSTATUS, ResumeFactory, SyntaxErrorEx, ValidateVerb, Verb, _, _validate, _validateOne, chalk, safeLoadJSON; FS = require('fs'); @@ -31,72 +31,95 @@ Implementation of the 'validate' verb for HackMyResume. ValidateVerb = module.exports = Verb.extend({ init: function() { - return this._super('validate', validate); + return this._super('validate', _validate); } }); /** Validate 1 to N resumes in FRESH or JSON Resume format. */ - validate = function(sources, unused, opts) { - var schemas, validator; + _validate = function(sources, unused, opts) { + var results, schemas, validator; if (!sources || !sources.length) { - throw { - fluenterror: HMSTATUS.resumeNotFoundAlt, + this.err(HMSTATUS.resumeNotFoundAlt, { quit: true - }; + }); + return null; } validator = require('is-my-json-valid'); schemas = { fresh: require('fresca'), jars: require('../core/resume.json') }; - return _.map(sources, function(t) { - var errCode, errors, fmt, json, obj, ret; - ret = { - file: t, - isValid: false - }; - obj = safeLoadJSON(t); - if (!obj.ex) { - json = obj.json; - fmt = json.basics ? 'jrs' : 'fresh'; - errors = []; - try { - validate = validator(schemas[fmt], { - formats: { - date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ - } - }); - ret.isValid = validate(json); - if (!ret.isValid) { - errors = validate.errors; - } - } catch (_error) { - ret.ex = _error; - } - } else { - errCode = obj.ex.operation === 'parse' ? HMSTATUS.parseError : HMSTATUS.readError; - if (errCode === HMSTATUS.readError) { - obj.ex.quiet = true; - } - this.setError(errCode, obj.ex); - this.err(errCode, obj.ex); + results = _.map(sources, function(t) { + var r; + if (this.hasError() && opts.assert) { + return {}; } - this.stat(HMEVENT.afterValidate, { - file: t, - isValid: ret.isValid, - fmt: fmt != null ? fmt.replace('jars', 'JSON Resume') : void 0, - errors: errors - }); - if (opts.assert && !ret.isValid) { - throw { - fluenterror: HMSTATUS.invalid, - shouldExit: true - }; + r = _validateOne.call(this, t, validator, schemas); + if (r.fluenterror) { + console.log(r); + r.quit = opts.assert; + this.err(r.fluenterror, r); } - return ret; + return r; }, this); + if (this.hasError() && !opts.assert) { + this.reject(this.errorCode); + } else if (!this.hasError()) { + this.resolve(results); + } + return results; + }; + + _validateOne = function(t, validator, schemas) { + var errCode, errors, fmt, json, obj, ret, validate; + ret = { + file: t, + isValid: false + }; + obj = safeLoadJSON(t); + if (obj.ex) { + errCode = obj.ex.operation === 'parse' ? HMSTATUS.parseError : HMSTATUS.readError; + if (errCode === HMSTATUS.readError) { + obj.ex.quiet = true; + } + return { + fluenterror: errCode, + inner: obj.ex + }; + } + json = obj.json; + fmt = json.basics ? 'jrs' : 'fresh'; + errors = []; + try { + validate = validator(schemas[fmt], { + formats: { + date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ + } + }); + ret.isValid = validate(json); + if (!ret.isValid) { + errors = validate.errors; + } + } catch (_error) { + ret.ex = _error; + } + this.stat(HMEVENT.afterValidate, { + file: t, + isValid: ret.isValid, + fmt: fmt != null ? fmt.replace('jars', 'JSON Resume') : void 0, + errors: errors + }); + if (opts.assert && !ret.isValid) { + return { + fluenterror: HMSTATUS.invalid, + errors: errors + }; + } + return ret; }; }).call(this); + +//# sourceMappingURL=validate.js.map diff --git a/dist/verbs/verb.js b/dist/verbs/verb.js index 873e17a..dda2b0b 100644 --- a/dist/verbs/verb.js +++ b/dist/verbs/verb.js @@ -6,7 +6,7 @@ Definition of the Verb class. */ (function() { - var Class, EVENTS, HMEVENT, Verb; + var Class, EVENTS, HMEVENT, Promise, Verb; Class = require('../utils/class'); @@ -14,6 +14,8 @@ Definition of the Verb class. HMEVENT = require('../core/event-codes'); + Promise = require('pinkie-promise'); + /** An instantiation of a HackMyResume command. @@ -25,19 +27,23 @@ Definition of the Verb class. /** Constructor. Automatically called at creation. */ init: function(moniker, workhorse) { this.moniker = moniker; - this.emitter = new EVENTS.EventEmitter(); this.workhorse = workhorse; + this.emitter = new EVENTS.EventEmitter(); }, /** Invoke the command. */ invoke: function() { - var ret; + var argsArray, that; this.stat(HMEVENT.begin, { cmd: this.moniker }); - ret = this.workhorse.apply(this, arguments); - this.stat(HMEVENT.end); - return ret; + argsArray = Array.prototype.slice.call(arguments); + that = this; + return this.promise = new Promise(function(res, rej) { + that.resolve = res; + that.reject = rej; + that.workhorse.apply(that, argsArray); + }); }, /** Forward subscriptions to the event emitter. */ @@ -58,6 +64,10 @@ Definition of the Verb class. payload = payload || {}; payload.sub = payload.fluenterror = errorCode; payload["throw"] = hot; + this.setError(errorCode, payload); + if (payload.quit) { + this.reject(payload); + } this.fire('error', payload); if (hot) { throw payload; @@ -72,6 +82,9 @@ Definition of the Verb class. this.fire('status', payload); return true; }, + hasError: function() { + return this.errorCode || this.errorObj; + }, /** Associate error info with the invocation. */ setError: function(code, obj) { @@ -81,3 +94,5 @@ Definition of the Verb class. }); }).call(this); + +//# sourceMappingURL=verb.js.map diff --git a/out/rez.yml b/out/rez.yml new file mode 100644 index 0000000..38591a5 --- /dev/null +++ b/out/rez.yml @@ -0,0 +1,285 @@ +name: 'Your Name' +meta: + format: FRESH@0.6.0 + version: 0.1.0 +info: + label: 'Your Profession' + brief: 'A brief description of yourself as a candidate that appears in some résumé themes. You may use **Markdown** and/or HTML formatting here including [links](https://en.wikipedia.org/wiki/Special:Random) or stick to plain text.' + image: "" +contact: + website: 'http://your-website.com' + phone: 1-999-999-9999 + email: your-email@your-website.com + other: [] +location: + address: '123 Somewhere Lane' + city: 'Castle Rock' + region: 'State, province, or region' + code: '90210' + country: US +social: + - + label: "" + network: GitHub + user: your-github-username + url: 'https://github.com/your-github-username' +employment: + summary: 'Optional overall employment summary. Not used in most themes.' + history: + - + employer: 'Most Recent Employer' + url: 'http://employer-website.com' + position: 'Head Honcho' + summary: 'A summary of your role in this position. Can include **Markdown** and inline HTML formatting.' + start: 2013-10 + keywords: + - 'spin widgets' + - CRM + - PM + - Ninjitsu + - 'Six Sigma' + highlights: + - 'Increased profits on left-handed spin widgets by 35%.' + - 'Participated in iterative/incremental devolution.' + - 'Promoted to Head Ninja after 500 successful cage matches.' + - + employer: 'Previous Employer' + url: 'http://employer-website.com' + position: 'Worker Bee' + summary: 'A summary of your previous role. Can include **Markdown** and inline HTML formatting.' + start: 2009-07 + end: 2013-10 + keywords: + - keyword1 + - KW2 + - KW2++ + - YAKW + highlights: + - 'Highlight #1.' + - 'Highlight #2.' + - 'Highlight #3.' +projects: + - + title: 'Awesome Project #1' + category: FOSS + url: 'http://project-page.org' + repo: 'https://project-repo.com' + media: [] + role: Contributor + summary: 'Show off your project work with a Markdown-and-HTML friendly summary of your role on the project. Software projects, creative projects, business projects can all appear here.' + description: 'A description of the project, for audiences that may not be familiar with it. Like the summary section, can include **Markdown** and inline HTML formatting.' + highlights: + - 'Project Highlight #1' + - 'Project Highlight #2' + - 'Project Highlight #3' + keywords: + - Tag1 + - Tag2 + - Tag3 + - Tag4 + - + title: Asteroids + category: FOSS + url: 'http://asteroids-demo.org' + repo: 'https://asteroids-repo.com' + media: [] + role: Creator + summary: 'Conceived, designed, implemented, and created 3D Asteroids space shooter with Unreal Engine IV and C++.' + description: 'A 3D Asteroids clone with Unreal 4 and cross-platform C++.' + highlights: + - 'Project Highlight #1' + - 'Project Highlight #2' + - 'Project Highlight #3' + keywords: + - C++ + - 'Unreal Engine' + - 3D + - DirectX +education: + summary: 'Optional overall education summary. Not used in most themes.' + level: degree + degree: BSCS + history: + - + institution: 'Acme University' + title: BSCS + url: 'http://acmeuniversity.edu' + start: 2004-09 + end: 2009-06 + grade: '3.5' + summary: 'Graduate of Acme University, summer of 2009. Go [Coyotes](https://en.wikipedia.org/wiki/Coyote)!' + curriculum: + - 'Data Algorithms' + - Optimization + - 'Neural Networks' + - C + - C++ + - Java + - HTTP + - TCP/IP +service: + summary: "" + history: + - + flavor: volunteer + position: 'Volunteer Coordinator' + organization: 'The Mommies Network' + url: 'http://themommiesnetwork.org' + start: 2006-06 + summary: 'A summary of your volunteer experience at this organization. Can include **Markdown** and inline HTML formatting.' + highlights: [] + - + flavor: military + position: MOS + organization: 'Air Force' + url: 'https://service-website.mil' + start: '2004' + summary: 'A summary of your service experience with this organization. Can include **Markdown** and inline HTML formatting.' + highlights: [] +skills: + sets: + - + name: 'Web Development' + level: advanced + skills: + - LAMP + - JavaScript + - 'HTML 5' + - Angular.js + - jQuery + - Sass + - LESS + - + name: Ninjitsu + level: intermediate + skills: + - 'Tokagure Ryu' + - Shuriken + - Yogen + - + name: 'Skillset #3' + level: beginner + skills: + - Your + - keywords + - here + list: [] +samples: + - + title: 'Work Sample #1' + summary: 'A technical or creative **work sample**.' + url: 'http://project-repo.com' + date: '2015' + - + title: 'Creative Sample #2' + summary: 'Another technical or creative sample. You can use [Markdown](https://daringfireball.net/projects/markdown/) here.' + url: 'http://project-repo.com' + date: '2015' +writing: + - + title: 'My Blog' + publisher: + name: Medium.com + url: 'https://medium.com' + flavor: blog + date: '2010' + summary: 'Your blog or online home.' + url: 'http://coding-snorer.com' + - + title: 'Something I Wrote Once' + flavor: essay + date: '2009' + summary: 'List your blogs, articles, essays, novels, and dissertations.' + publisher: + name: 'Acme University Press' + url: 'http://press.acmeuniversity.edu' + url: 'http://codeproject.com/something-i-wrote-once' +reading: + - + title: 'Other Copenhagens' + flavor: book + url: 'http://www.amazon.com/Other-Copenhagens-And-Stories/dp/0984749209' + author: 'Edmund Jorgensen' + - + title: r/programming + flavor: website + url: 'https://www.reddit.com/r/programming' + - + title: 'Hacker News' + flavor: website + url: 'https://news.ycombinator.com/' +recognition: + - + flavor: award + from: HackMyResume + title: 'Awesomeness Award' + event: 'HMR Release' + url: 'http://please.hackmyresume.com' + date: '2016' + summary: 'Thanks for being a HackMyResume / FluentCV user!' + - + flavor: industry + from: 'Big Software' + title: 'MVP: SpinWidget Technology' + event: 'Yearly Roundup' + date: '2015-08-03' + summary: 'For work in promotion and popularization of SpinWidget technology.' +references: + - + name: 'John Doe' + category: professional + role: 'Manager @ Somewhere Inc.' + private: true + summary: 'Contact information available on request.' + contact: + - + flavor: email + value: john.doe@somewhere.com + - + name: 'Jane Q. Fullstacker' + category: technical + summary: 'Contact information available on request.' + role: Coworker + private: true + contact: + - + flavor: email + value: jane.fullstacker@somewhere.com +testimonials: + - + name: 'John Doe' + flavor: professional + quote: 'Such-and-such is awesome! I''d hire him/her again in a second!' + private: false + - + name: 'Somebody Important' + flavor: technical + quote: 'Hands-down *the best developer/manager/spelunker/coworker/etc* I''ve ever worked with. Emphasis *mine!*' + private: false +languages: + - + language: English + level: native + - + language: Spanish + level: advanced + - + language: C++ + level: intermediate +interests: + - + name: GitHub + summary: 'Regular GitHub user and tinkerer.' + keywords: + - GitHub + - git + - 'GitHub Desktop (OS X)' + - LFS + - 'GitHub API' + - + name: chess + summary: 'Avid chess player.' + keywords: + - Sicilian + - 'King''s Gambit' + - 'Ruy Lopez' diff --git a/package.json b/package.json index e487421..d7009f6 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "moment": "^2.11.1", "parse-filepath": "^0.6.3", "path-exists": "^2.1.0", + "pinkie-promise": "^2.0.0", "printf": "^0.2.3", "recursive-readdir-sync": "^1.0.6", "simple-html-tokenizer": "^0.2.1", diff --git a/src/cli/error.coffee b/src/cli/error.coffee index d45154f..d9e7d5f 100644 --- a/src/cli/error.coffee +++ b/src/cli/error.coffee @@ -22,10 +22,8 @@ require 'string.prototype.startswith' -###* -Error handler for HackMyResume. All errors are handled here. -@class ErrorHandler -### +###* Error handler for HackMyResume. All errors are handled here. +@class ErrorHandler ### ErrorHandler = module.exports = init: ( debug, assert, silent ) -> @@ -38,7 +36,7 @@ ErrorHandler = module.exports = err: ( ex, shouldExit ) -> # Short-circuit logging output if --silent is on - o = if this.silent then () -> else _defaultLog + o = if @silent then () -> else _defaultLog # Special case; can probably be removed. throw ex if ex.pass @@ -51,7 +49,7 @@ ErrorHandler = module.exports = # Output the error message objError = assembleError.call @, ex - o( this[ 'format_' + objError.etype ]( objError.msg )) + o( @[ 'format_' + objError.etype ]( objError.msg )) # Output the stack (sometimes) if objError.withStack @@ -59,20 +57,20 @@ ErrorHandler = module.exports = stack && o( chalk.gray( stack ) ); # Quit if necessary - if ex.quit || objError.quit + if shouldExit if @debug o chalk.cyan('Exiting with error code ' + ex.fluenterror.toString()) - if this.assert + if @assert ex.pass = true throw ex process.exit ex.fluenterror # Handle raw exceptions else - o( ex ) + o ex stackTrace = ex.stack || (ex.inner && ex.inner.stack) if stackTrace && this.debug - o( M2C(ex.stack || ex.inner.stack, 'gray') ) + o M2C(ex.stack || ex.inner.stack, 'gray') @@ -214,6 +212,11 @@ assembleError = ( ex ) -> msg = ex etype = 'error' + when HMSTATUS.createError + # inner.code could be EPERM, EACCES, etc + msg = printf M2C( this.msgs.createError.msg ), ex.inner.path + etype = 'error' + msg: msg # The error message to display withStack: withStack # Whether to include the stack quit: quit diff --git a/src/cli/main.coffee b/src/cli/main.coffee index a6f3bc9..d8a7606 100644 --- a/src/cli/main.coffee +++ b/src/cli/main.coffee @@ -23,6 +23,8 @@ Command = require('commander').Command _opts = { } _title = chalk.white.bold('\n*** HackMyResume v' +PKG.version+ ' ***') _out = new OUTPUT( _opts ) +_err = require('./error') +_exitCallback = null @@ -33,9 +35,9 @@ line interface as a single method accepting a parameter array. @param rawArgs {Array} An array of command-line parameters. Will either be process.argv (in production) or custom parameters (in test). ### -main = module.exports = (rawArgs) -> +main = module.exports = ( rawArgs, exitCallback ) -> - initInfo = initialize( rawArgs ) + initInfo = initialize( rawArgs, exitCallback ) args = initInfo.args # Create the top-level (application) command... @@ -129,10 +131,10 @@ main = module.exports = (rawArgs) -> ### Massage command-line args and setup Commander.js. ### -initialize = ( ar ) -> - - o = initOptions( ar ); +initialize = ( ar, exitCallback ) -> + _exitCallback = exitCallback || process.exit + o = initOptions ar o.silent || logMsg( _title ) # Emit debug prelude if --debug was specified @@ -147,9 +149,11 @@ initialize = ( ar ) -> #_out.log(chalk.cyan(PAD(' fresh-jrs-converter:',25, null, PAD.RIGHT)) + chalk.cyan.bold( PKG.dependencies['fresh-jrs-converter'] )) _out.log('') + _err.init o.debug, o.assert, o.silent + # Handle invalid verbs here (a bit easier here than in commander.js)... if o.verb && !HMR.verbs[ o.verb ] && !HMR.alias[ o.verb ] - throw { fluenterror: HMSTATUS.invalidCommand, quit: true, attempted: o.orgVerb } + _err.err fluenterror: HMSTATUS.invalidCommand, quit: true, attempted: o.orgVerb, true # Override the .missingArgument behavior Command.prototype.missingArgument = (name) -> @@ -205,23 +209,17 @@ initOptions = ( ar ) -> oJSON = inf.json # TODO: Error handling - # Grab the --debug flag - isDebug = _.some( args, (v) -> - return v == '-d' || v == '--debug' - ) - - # Grab the --silent flag - isSilent = _.some( args, (v) -> - return v == '-s' || v == '--silent' - ) - - # Grab the --no-color flag + # Grab the --debug flag, --silent, --assert and --no-color flags + isDebug = _.some args, (v) -> v == '-d' || v == '--debug' + isSilent = _.some args, (v) -> v == '-s' || v == '--silent' + isAssert = _.some args, (v) -> v == '-a' || v == '--assert' isMono = _.some args, (v) -> v == '--no-color' return { color: !isMono, debug: isDebug, silent: isSilent, + assert: isAssert, orgVerb: oVerb, verb: verb, json: oJSON, @@ -233,19 +231,29 @@ initOptions = ( ar ) -> ### Invoke a HackMyResume verb. ### execute = ( src, dst, opts, log ) -> - loadOptions.call( this, opts, this.parent.jsonArgs ) - hand = require( './error' ) - hand.init( _opts.debug, _opts.assert, _opts.silent ) - v = new HMR.verbs[ this.name() ]() - _opts.errHandler = v - _out.init( _opts ) - v.on( 'hmr:status', -> _out.do.apply( _out, arguments ) ) - v.on( 'hmr:error', -> hand.err.apply( hand, arguments ) ) - v.invoke.call( v, src, dst, _opts, log ) - if v.errorCode - console.log 'Exiting with error code ' + v.errorCode - process.exit(v.errorCode) + # Create the verb + v = new HMR.verbs[ @name() ]() + # Initialize command-specific options + loadOptions.call( this, opts, this.parent.jsonArgs ) + + # Set up error/output handling + _opts.errHandler = v + _out.init _opts + + # Hook up event notifications + v.on 'hmr:status', -> _out.do.apply _out, arguments + v.on 'hmr:error', -> _err.err.apply _err, arguments + + # Invoke the verb! Returns a promise + prom = v.invoke.call v, src, dst, _opts, log + + # Resolved or rejected? + onFail = (err) -> + _exitCallback( if err.fluenterror then err.fluenterror else err ) + return + prom.then (->), onFail + return diff --git a/src/cli/msg.yml b/src/cli/msg.yml index 755dd40..ebcf8a4 100644 --- a/src/cli/msg.yml +++ b/src/cli/msg.yml @@ -3,6 +3,8 @@ events: msg: Invoking **%s** command. beforeCreate: msg: Creating new **%s** resume: **%s** + afterCreate: + msg: Creating new **%s** resume: **%s** afterRead: msg: Reading **%s** resume: **%s** beforeTheme: @@ -96,3 +98,5 @@ errors: msg: "Invalid number of parameters. Expected: **%s**." missingParam: msg: The '**%s**' parameter was needed but not supplied. + createError: + msg: Failed to create **'%s'**. diff --git a/src/cli/out.coffee b/src/cli/out.coffee index 773b300..98fec6f 100644 --- a/src/cli/out.coffee +++ b/src/cli/out.coffee @@ -50,8 +50,12 @@ OutputHandler = module.exports = Class.extend this.opts.debug && L( M2C( this.msgs.begin.msg, dbgStyle), evt.cmd.toUpperCase() ) - when HME.beforeCreate - L( M2C( this.msgs.beforeCreate.msg, 'green' ), evt.fmt, evt.file ) + #when HME.beforeCreate + #L( M2C( this.msgs.beforeCreate.msg, 'green' ), evt.fmt, evt.file ) + #break; + + when HME.afterCreate + L( M2C( @msgs.beforeCreate.msg, if evt.isError then 'red' else 'green' ), evt.fmt, evt.file ) break; when HME.beforeTheme diff --git a/src/core/resume-factory.coffee b/src/core/resume-factory.coffee index 69223e3..f336b81 100644 --- a/src/core/resume-factory.coffee +++ b/src/core/resume-factory.coffee @@ -103,13 +103,7 @@ _parse = ( fileName, opts, eve ) -> return ret catch # Can be ENOENT, EACCES, SyntaxError, etc. - ex = - fluenterror: if rawData then HACKMYSTATUS.parseError else HACKMYSTATUS.readError - inner: _error - raw: rawData - file: fileName - shouldExit: false - opts.quit && (ex.quit = true) - eve && eve.err ex.fluenterror, ex - throw ex if opts.throw - ex + fluenterror: if rawData then HACKMYSTATUS.parseError else HACKMYSTATUS.readError + inner: _error + raw: rawData + file: fileName diff --git a/src/core/status-codes.coffee b/src/core/status-codes.coffee index 9bbd4b9..d8b9515 100644 --- a/src/core/status-codes.coffee +++ b/src/core/status-codes.coffee @@ -31,3 +31,4 @@ module.exports = themeLoad: 22 invalidParamCount: 23 missingParam: 24 + createError: 25 diff --git a/src/generators/html-pdf-cli-generator.coffee b/src/generators/html-pdf-cli-generator.coffee index cd0f431..5af5843 100644 --- a/src/generators/html-pdf-cli-generator.coffee +++ b/src/generators/html-pdf-cli-generator.coffee @@ -24,9 +24,11 @@ If an engine isn't installed for a particular platform, error out gracefully. HtmlPdfCLIGenerator = module.exports = TemplateGenerator.extend + init: () -> @_super 'pdf', 'html' + ###* Generate the binary PDF. ### onBeforeSave: ( info ) -> safe_eng = info.opts.pdf || 'wkhtmltopdf'; @@ -38,8 +40,14 @@ HtmlPdfCLIGenerator = module.exports = TemplateGenerator.extend engines[ safe_eng ].call @, info.mk, info.outputFile, @onError return null # halt further processing + + + ### Low-level error callback for spawn(). May be called after HMR process + termination, so object references may not be valid here. That's okay; if + the references are invalid, the error was already logged. We could use + spawn-watch here but that causes issues on legacy Node.js. ### onError: (ex, param) -> - param.errHandler.err HMSTATUS.pdfGeneration, ex + param.errHandler?.err? HMSTATUS.pdfGeneration, ex return diff --git a/src/generators/json-yaml-generator.coffee b/src/generators/json-yaml-generator.coffee index 351b9ac..e7041c5 100644 --- a/src/generators/json-yaml-generator.coffee +++ b/src/generators/json-yaml-generator.coffee @@ -28,3 +28,4 @@ JsonYamlGenerator = module.exports = BaseGenerator.extend generate: ( rez, f, opts ) -> data = YAML.stringify JSON.parse( rez.stringify() ), Infinity, 2 FS.writeFileSync f, data, 'utf8' + data diff --git a/src/verbs/analyze.coffee b/src/verbs/analyze.coffee index 2ab8602..23c5f84 100644 --- a/src/verbs/analyze.coffee +++ b/src/verbs/analyze.coffee @@ -16,40 +16,44 @@ Verb = require('../verbs/verb') chalk = require('chalk') - +###* An invokable resume analysis command. ### AnalyzeVerb = module.exports = Verb.extend - init: -> @_super 'analyze', analyze + init: -> @_super 'analyze', _analyze -###* -Run the 'analyze' command. -### -analyze = ( sources, dst, opts ) -> +###* Private workhorse for the 'analyze' command. ### +_analyze = ( sources, dst, opts ) -> if !sources || !sources.length - throw - fluenterror: HMSTATUS.resumeNotFound - quit: true + @err HMSTATUS.resumeNotFound, { quit: true } + return null nlzrs = _loadInspectors() + results = _.map sources, (src) -> + r = ResumeFactory.loadOne src, format: 'FRESH', objectify: true, @ + return { } if opts.assert and @hasError() - _.each(sources, (src) -> - result = ResumeFactory.loadOne src, format: 'FRESH', objectify: true, @ - if result.fluenterror - this.setError result.fluenterror, result + if r.fluenterror + r.quit = opts.assert + @err r.fluenterror, r + r else - _analyze.call @, result, nlzrs, opts - , @) + _analyzeOne.call @, r, nlzrs, opts + , @ + + + if @hasError() and !opts.assert + @reject @errorCode + else if !@hasError() + @resolve results + results -###* -Analyze a single resume. -### -_analyze = ( resumeObject, nlzrs, opts ) -> - +###* Analyze a single resume. ### +_analyzeOne = ( resumeObject, nlzrs, opts ) -> rez = resumeObject.rez safeFormat = if rez.meta and rez.meta.format and rez.meta.format.startsWith 'FRESH' @@ -58,12 +62,10 @@ _analyze = ( resumeObject, nlzrs, opts ) -> this.stat( HMEVENT.beforeAnalyze, { fmt: safeFormat, file: resumeObject.file }) info = _.mapObject nlzrs, (val, key) -> val.run rez this.stat HMEVENT.afterAnalyze, { info: info } + info -###* -Load inspectors. -### _loadInspectors = -> totals: require '../inspectors/totals-inspector' coverage: require '../inspectors/gap-inspector' diff --git a/src/verbs/build.coffee b/src/verbs/build.coffee index dbfae25..fb42553 100644 --- a/src/verbs/build.coffee +++ b/src/verbs/build.coffee @@ -6,25 +6,25 @@ Implementation of the 'build' verb for HackMyResume. -_ = require('underscore') -PATH = require('path') -FS = require('fs') -MD = require('marked') -MKDIRP = require('mkdirp') -extend = require('extend') -parsePath = require('parse-filepath') -RConverter = require('fresh-jrs-converter') -HMSTATUS = require('../core/status-codes') -HMEVENT = require('../core/event-codes') +_ = require 'underscore' +PATH = require 'path' +FS = require 'fs' +MD = require 'marked' +MKDIRP = require 'mkdirp' +extend = require 'extend' +parsePath = require 'parse-filepath' +RConverter = require 'fresh-jrs-converter' +HMSTATUS = require '../core/status-codes' +HMEVENT = require '../core/event-codes' RTYPES = - FRESH: require('../core/fresh-resume') - JRS: require('../core/jrs-resume') -_opts = require('../core/default-options') -FRESHTheme = require('../core/fresh-theme') -JRSTheme = require('../core/jrs-theme') -ResumeFactory = require('../core/resume-factory') -_fmts = require('../core/default-formats') -Verb = require('../verbs/verb') + FRESH: require '../core/fresh-resume' + JRS: require '../core/jrs-resume' +_opts = require '../core/default-options' +FRESHTheme = require '../core/fresh-theme' +JRSTheme = require '../core/jrs-theme' +ResumeFactory = require '../core/resume-factory' +_fmts = require '../core/default-formats' +Verb = require '../verbs/verb' _err = null _log = null @@ -42,7 +42,7 @@ loadTheme = null BuildVerb = module.exports = Verb.extend ###* Create a new build verb. ### - init: () -> @_super 'build', build + init: () -> @_super 'build', _build @@ -53,23 +53,23 @@ theme file, generate 0..N resumes in the desired formats. @param dst An array of paths to the target resume file(s). @param opts Generation options. ### -build = ( src, dst, opts ) -> +_build = ( src, dst, opts ) -> if !src || !src.length @err HMSTATUS.resumeNotFound, quit: true return null - prep src, dst, opts + _prep src, dst, opts # Load input resumes as JSON... - sheetObjects = ResumeFactory.load(src, { + sheetObjects = ResumeFactory.load src, format: null, objectify: false, quit: true, inner: { sort: _opts.sort } - }, @); + , @ # Explicit check for any resume loading errors... - problemSheets = _.filter( sheetObjects, (so) -> return so.fluenterror ) - if( problemSheets && problemSheets.length ) - problemSheets[0].quit = true + problemSheets = _.filter sheetObjects, (so) -> so.fluenterror + if problemSheets and problemSheets.length + problemSheets[0].quit = true # can't go on @err problemSheets[0].fluenterror, problemSheets[0] return null @@ -80,27 +80,27 @@ build = ( src, dst, opts ) -> theme = null @stat HMEVENT.beforeTheme, { theme: _opts.theme } try - tFolder = verifyTheme.call @, _opts.theme - theme = _opts.themeObj = loadTheme tFolder - addFreebieFormats theme - catch ex + tFolder = _verifyTheme.call @, _opts.theme + theme = _opts.themeObj = _loadTheme tFolder + _addFreebieFormats theme + catch newEx = fluenterror: HMSTATUS.themeLoad - inner: ex + inner: _error attempted: _opts.theme quit: true @err HMSTATUS.themeLoad, newEx return null - @stat HMEVENT.afterTheme, { theme: theme } + @stat HMEVENT.afterTheme, theme: theme # Check for invalid outputs... - inv = verifyOutputs.call @, dst, theme + inv = _verifyOutputs.call @, dst, theme if inv && inv.length @err HMSTATUS.invalidFormat, data: inv, theme: theme, quit: true return null - ## Merge input resumes, yielding a single source resume. + ## Merge input resumes, yielding a single source resume... rez = null if sheets.length > 1 isFRESH = !sheets[0].basics @@ -108,15 +108,13 @@ build = ( src, dst, opts ) -> @stat HMEVENT.beforeMerge, { f: _.clone(sheetObjects), mixed: mixed } if mixed @err HMSTATUS.mixedMerge - rez = _.reduceRight sheets, ( a, b, idx ) -> extend( true, b, a ) - @stat HMEVENT.afterMerge, { r: rez } else rez = sheets[0]; - # Convert the merged source resume to the theme's format, if necessary + # Convert the merged source resume to the theme's format, if necessary.. orgFormat = if rez.basics then 'JRS' else 'FRESH'; toFormat = if theme.render then 'JRS' else 'FRESH'; if toFormat != orgFormat @@ -125,30 +123,41 @@ build = ( src, dst, opts ) -> @stat HMEVENT.afterInlineConvert, { file: sheetObjects[0].file, fmt: toFormat } # Announce the theme - @stat HMEVENT.applyTheme, { r: rez, theme: theme } + @stat HMEVENT.applyTheme, r: rez, theme: theme # Load the resume into a FRESHResume or JRSResume object _rezObj = new (RTYPES[ toFormat ])().parseJSON( rez ); # Expand output resumes... - targets = expand( dst, theme ); + targets = _expand dst, theme # Run the transformation! _.each targets, (t) -> - t.final = single.call this, t, theme, targets + return { } if @hasError() and opts.assert + t.final = _single.call @, t, theme, targets + if t.final.fluenterror + t.final.quit = opts.assert + @err t.final.fluenterror, t.final + return , @ - # Don't send the client back empty-handed - sheet: _rezObj - targets: targets - processed: targets + results = + sheet: _rezObj + targets: targets + processed: targets + + if @hasError() and !opts.assert + @reject results + else if !@hasError() + @resolve results + results ###* Prepare for a BUILD run. ### -prep = ( src, dst, opts ) -> +_prep = ( src, dst, opts ) -> # Cherry-pick options //_opts = extend( true, _opts, opts ); _opts.theme = (opts.theme && opts.theme.toLowerCase().trim()) || 'modern'; @@ -176,7 +185,7 @@ TODO: Refactor. @param targInfo Information for the target resume. @param theme A FRESHTheme or JRSTheme object. ### -single = ( targInfo, theme, finished ) -> +_single = ( targInfo, theme, finished ) -> ret = null ex = null @@ -207,12 +216,13 @@ single = ( targInfo, theme, finished ) -> # Otherwise this is an ad-hoc format (JSON, YML, or PNG) that every theme # gets "for free". else + theFormat = _fmts.filter( (fmt) -> return fmt.name == targInfo.fmt.outFormat )[0]; outFolder = PATH.dirname f - MKDIRP.sync( outFolder ); # Ensure dest folder exists; - ret = theFormat.gen.generate( _rezObj, f, _opts ); + MKDIRP.sync outFolder # Ensure dest folder exists; + ret = theFormat.gen.generate _rezObj, f, _opts catch e # Catch any errors caused by generating this file and don't let them @@ -227,16 +237,15 @@ single = ( targInfo, theme, finished ) -> if ex if ex.fluenterror - this.err( ex.fluenterror, ex ); + ret = ex else - this.err( HMSTATUS.generateError, { inner: ex } ); - - return ret + ret = fluenterror: HMSTATUS.generateError, inner: ex + ret ###* Ensure that user-specified outputs/targets are valid. ### -verifyOutputs = ( targets, theme ) -> +_verifyOutputs = ( targets, theme ) -> @stat HMEVENT.verifyOutputs, { targets: targets, theme: theme } _.reject targets.map( ( t ) -> pathInfo = parsePath t @@ -256,7 +265,7 @@ that declares an HTML format; the theme doesn't have to provide an explicit PNG template. @param theTheme A FRESHTheme or JRSTheme object. ### -addFreebieFormats = ( theTheme ) -> +_addFreebieFormats = ( theTheme ) -> # Add freebie formats (JSON, YAML, PNG) every theme gets... # Add HTML-driven PNG only if the theme has an HTML format. theTheme.formats.json = theTheme.formats.json || { @@ -282,7 +291,7 @@ Expand output files. For example, "foo.all" should be expanded to @param dst An array of output files as specified by the user. @param theTheme A FRESHTheme or JRSTheme object. ### -expand = ( dst, theTheme ) -> +_expand = ( dst, theTheme ) -> # Set up the destination collection. It's either the array of files passed # by the user or 'out/resume.all' if no targets were specified. @@ -309,7 +318,7 @@ expand = ( dst, theTheme ) -> ###* Verify the specified theme name/path. ### -verifyTheme = ( themeNameOrPath ) -> +_verifyTheme = ( themeNameOrPath ) -> tFolder = PATH.join( parsePath( require.resolve('fresh-themes') ).dirname, '/themes/', @@ -328,7 +337,7 @@ verifyTheme = ( themeNameOrPath ) -> Load the specified theme, which could be either a FRESH theme or a JSON Resume theme. ### -loadTheme = ( tFolder ) -> +_loadTheme = ( tFolder ) -> # Create a FRESH or JRS theme object theTheme = diff --git a/src/verbs/convert.coffee b/src/verbs/convert.coffee index e76ccfb..1ba1655 100644 --- a/src/verbs/convert.coffee +++ b/src/verbs/convert.coffee @@ -17,56 +17,68 @@ HMEVENT = require('../core/event-codes'); ConvertVerb = module.exports = Verb.extend - init: -> @_super 'convert', convert + init: -> @_super 'convert', _convert -###* -Convert between FRESH and JRS formats. -### -convert = ( srcs, dst, opts ) -> +###* Private workhorse method. Convert 0..N resumes between FRESH and JRS +formats. ### - # Housekeeping - throw { fluenterror: 6, quit: true } if !srcs || !srcs.length +_convert = ( srcs, dst, opts ) -> + + # Housekeeping... + if !srcs || !srcs.length + @err HMSTATUS.resumeNotFound, { quit: true } + return null if !dst || !dst.length if srcs.length == 1 - throw { fluenterror: HMSTATUS.inputOutputParity, quit: true }; + @err HMSTATUS.inputOutputParity, { quit: true } else if srcs.length == 2 dst = dst || []; dst.push( srcs.pop() ) else - throw fluenterror: HMSTATUS.inputOutputParity, quit: true - + @err HMSTATUS.inputOutputParity, { quit: true } if srcs && dst && srcs.length && dst.length && srcs.length != dst.length - throw fluenterror: HMSTATUS.inputOutputParity quit: true + @err HMSTATUS.inputOutputParity, { quit: true } # Load source resumes - _.each(srcs, ( src, idx ) -> + results = _.map srcs, ( src, idx ) -> + return { } if opts.assert and @hasError() + r = _convertOne.call @, src, dst, idx + if r.fluenterror + r.quit = opts.assert + @err r.fluenterror, r + r + , @ - # Load the resume - rinfo = ResumeFactory.loadOne src, - format: null, objectify: true, throw: false + if @hasError() and !opts.assert + @reject results + else if !@hasError() + @resolve results + results - # If a load error occurs, report it and move on to the next file (if any) - if rinfo.fluenterror - this.err rinfo.fluenterror, rinfo - return - s = rinfo.rez - srcFmt = - if ((s.basics && s.basics.imp) || s.imp).orgFormat == 'JRS' - then 'JRS' else 'FRESH' - targetFormat = if srcFmt == 'JRS' then 'FRESH' else 'JRS' - this.stat HMEVENT.beforeConvert, - srcFile: rinfo.file - srcFmt: srcFmt - dstFile: dst[idx] - dstFmt: targetFormat +###* Private workhorse method. Convert a single resume. ### +_convertOne = (src, dst, idx) -> + # Load the resume + rinfo = ResumeFactory.loadOne src, format: null, objectify: true - # Save it to the destination format - s.saveAs dst[idx], targetFormat - return + # If a load error occurs, report it and move on to the next file (if any) + if rinfo.fluenterror + return rinfo - , @) + s = rinfo.rez + srcFmt = + if ((s.basics && s.basics.imp) || s.imp).orgFormat == 'JRS' + then 'JRS' else 'FRESH' + targetFormat = if srcFmt == 'JRS' then 'FRESH' else 'JRS' - return + this.stat HMEVENT.beforeConvert, + srcFile: rinfo.file + srcFmt: srcFmt + dstFile: dst[idx] + dstFmt: targetFormat + + # Save it to the destination format + s.saveAs dst[idx], targetFormat + s diff --git a/src/verbs/create.coffee b/src/verbs/create.coffee index 2a42f91..22b0c2a 100644 --- a/src/verbs/create.coffee +++ b/src/verbs/create.coffee @@ -5,37 +5,64 @@ Implementation of the 'create' verb for HackMyResume. ### -MKDIRP = require('mkdirp') -PATH = require('path') -chalk = require('chalk') -Verb = require('../verbs/verb') -_ = require('underscore') -HMSTATUS = require('../core/status-codes') -HMEVENT = require('../core/event-codes') + +MKDIRP = require 'mkdirp' +PATH = require 'path' +chalk = require 'chalk' +Verb = require '../verbs/verb' +_ = require 'underscore' +HMSTATUS = require '../core/status-codes' +HMEVENT = require '../core/event-codes' CreateVerb = module.exports = Verb.extend - init: -> @_super 'new', create + init: -> @_super 'new', _create -###* -Create a new empty resume in either FRESH or JRS format. -### -create = ( src, dst, opts ) -> +###* Create a new empty resume in either FRESH or JRS format. ### +_create = ( src, dst, opts ) -> if !src || !src.length - throw { fluenterror: HMSTATUS.createNameMissing, quit: true } + @err HMSTATUS.createNameMissing, { quit: true } + return null - _.each( src, ( t ) -> + results = _.map src, ( t ) -> + return { } if opts.assert and @hasError() + r = _createOne.call @, t, opts + if r.fluenterror + r.quit = opts.assert + @err r.fluenterror, r + r + , @ + + if @hasError() and !opts.assert + @reject results + else if !@hasError() + @resolve results + results + + + +###* Create a single new resume ### +_createOne = ( t, opts ) -> + try + ret = null safeFmt = opts.format.toUpperCase() @.stat HMEVENT.beforeCreate, { fmt: safeFmt, file: t } MKDIRP.sync PATH.dirname( t ) # Ensure dest folder exists; RezClass = require '../core/' + safeFmt.toLowerCase() + '-resume' - RezClass.default().save t - @.stat( HMEVENT.afterCreate, { fmt: safeFmt, file: t } ) - , @) - - return + newRez = RezClass.default() + newRez.save t + ret = newRez + return + catch + ret = + fluenterror: HMSTATUS.createError + inner: _error + return + finally + @.stat HMEVENT.afterCreate, fmt: safeFmt, file: t, isError: ret.fluenterror + return ret diff --git a/src/verbs/peek.coffee b/src/verbs/peek.coffee index 57565ce..865a721 100644 --- a/src/verbs/peek.coffee +++ b/src/verbs/peek.coffee @@ -17,46 +17,60 @@ HMEVENT = require('../core/event-codes') PeekVerb = module.exports = Verb.extend - init: -> @_super 'peek', peek + init: -> @_super 'peek', _peek ###* Peek at a resume, resume section, or resume field. ### -peek = ( src, dst, opts ) -> +_peek = ( src, dst, opts ) -> if !src || !src.length - throw: fluenterror: HMSTATUS.resumeNotFound + @err HMSTATUS.resumeNotFound, { quit: true } + return null objPath = (dst && dst[0]) || '' - _.each src, ( t ) -> - - # Fire the 'beforePeek' event 2nd, so we have error/warning/success - @.stat HMEVENT.beforePeek, { file: t, target: objPath } - - # Load the input file JSON 1st - obj = safeLoadJSON t - - # Fetch the requested object path (or the entire file) - tgt = null; - if !obj.ex - tgt = if objPath then __.get obj.json, objPath else obj.json; - - # Fire the 'afterPeek' event with collected info - @.stat HMEVENT.afterPeek, - file: t - requested: objPath - target: tgt - error: obj.ex - - # safeLoadJSON can only return a READ error or a PARSE error - if obj.ex - errCode = if obj.ex.operation == 'parse' then HMSTATUS.parseError else HMSTATUS.readError - if errCode == HMSTATUS.readError - obj.ex.quiet = true - @setError errCode, obj.ex - @err errCode, obj.ex - + results = _.map src, ( t ) -> + return { } if opts.assert and @hasError() + tgt = _peekOne.call @, t, objPath + if tgt.fluenterror + tgt.quit = opts.assert + @err tgt.fluenterror, tgt , @ - return + if @hasError() and !opts.assert + @reject @errorCode + else if !@hasError() + @resolve results + results + + + +###* Peek at a single resume, resume section, or resume field. ### +_peekOne = ( t, objPath ) -> + + @.stat HMEVENT.beforePeek, { file: t, target: objPath } + + # Load the input file JSON 1st + obj = safeLoadJSON t + + # Fetch the requested object path (or the entire file) + tgt = null; + if !obj.ex + tgt = if objPath then __.get obj.json, objPath else obj.json; + + # Fire the 'afterPeek' event with collected info + @.stat HMEVENT.afterPeek, + file: t + requested: objPath + target: tgt + error: obj.ex + + ## safeLoadJSON can only return a READ error or a PARSE error + if obj.ex + errCode = if obj.ex.operation == 'parse' then HMSTATUS.parseError else HMSTATUS.readError + if errCode == HMSTATUS.readError + obj.ex.quiet = true + return fluenterror: errCode, inner: obj.ex + + tgt diff --git a/src/verbs/validate.coffee b/src/verbs/validate.coffee index 7119666..370b161 100644 --- a/src/verbs/validate.coffee +++ b/src/verbs/validate.coffee @@ -21,15 +21,16 @@ safeLoadJSON = require '../utils/safe-json-loader' ###* An invokable resume validation command. ### ValidateVerb = module.exports = Verb.extend - init: -> @_super 'validate', validate + init: -> @_super 'validate', _validate ###* Validate 1 to N resumes in FRESH or JSON Resume format. ### -validate = (sources, unused, opts) -> +_validate = (sources, unused, opts) -> if !sources || !sources.length - throw { fluenterror: HMSTATUS.resumeNotFoundAlt, quit: true } + @err HMSTATUS.resumeNotFoundAlt, { quit: true } + return null validator = require 'is-my-json-valid' schemas = @@ -38,47 +39,58 @@ validate = (sources, unused, opts) -> # Validate input resumes. Return a { file: , isValid: } object for # each resume valid, invalid, or broken. - _.map sources, (t) -> - - ret = file: t, isValid: false - - # Load the input file JSON 1st - obj = safeLoadJSON t - - if !obj.ex - - # Successfully read the resume. Now parse it as JSON. - json = obj.json - fmt = if json.basics then 'jrs' else 'fresh' - errors = [] - - try - validate = validator schemas[ fmt ], { # Note [1] - formats: { date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ } - }; - ret.isValid = validate json - if !ret.isValid - errors = validate.errors - catch - ret.ex = _error - - # safeLoadJSON can only return a READ error or a PARSE error - else - errCode = if obj.ex.operation == 'parse' then HMSTATUS.parseError else HMSTATUS.readError - if errCode == HMSTATUS.readError - obj.ex.quiet = true - @setError errCode, obj.ex - @err errCode, obj.ex - - @stat HMEVENT.afterValidate, - file: t - isValid: ret.isValid - fmt: fmt?.replace 'jars', 'JSON Resume' - errors: errors - - if opts.assert and !ret.isValid - throw fluenterror: HMSTATUS.invalid, shouldExit: true - - ret - + results = _.map sources, (t) -> + return { } if @hasError() and opts.assert + r = _validateOne.call @, t, validator, schemas + if r.fluenterror + console.log r + r.quit = opts.assert + @err r.fluenterror, r + r , @ + + if @hasError() and !opts.assert + @reject @errorCode + else if !@hasError() + @resolve results + results + + +_validateOne = (t, validator, schemas) -> + + ret = file: t, isValid: false + + # Load the input file JSON 1st + obj = safeLoadJSON t + if obj.ex + # safeLoadJSON can only return a READ error or a PARSE error + errCode = if obj.ex.operation == 'parse' then HMSTATUS.parseError else HMSTATUS.readError + if errCode == HMSTATUS.readError + obj.ex.quiet = true + return fluenterror: errCode, inner: obj.ex + + # Successfully read the resume. Now parse it as JSON. + json = obj.json + fmt = if json.basics then 'jrs' else 'fresh' + errors = [] + + try + validate = validator schemas[ fmt ], { # Note [1] + formats: { date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ } + }; + ret.isValid = validate json + if !ret.isValid + errors = validate.errors + catch + ret.ex = _error + + @stat HMEVENT.afterValidate, + file: t + isValid: ret.isValid + fmt: fmt?.replace 'jars', 'JSON Resume' + errors: errors + + if opts.assert and !ret.isValid + return fluenterror: HMSTATUS.invalid, errors: errors + + ret diff --git a/src/verbs/verb.coffee b/src/verbs/verb.coffee index d9425c9..85e5272 100644 --- a/src/verbs/verb.coffee +++ b/src/verbs/verb.coffee @@ -10,6 +10,7 @@ Definition of the Verb class. Class = require '../utils/class' EVENTS = require 'events' HMEVENT = require '../core/event-codes' +Promise = require 'pinkie-promise' @@ -24,8 +25,8 @@ Verb = module.exports = Class.extend ###* Constructor. Automatically called at creation. ### init: ( moniker, workhorse ) -> @moniker = moniker - @emitter = new EVENTS.EventEmitter() @workhorse = workhorse + @emitter = new EVENTS.EventEmitter() return @@ -33,9 +34,11 @@ Verb = module.exports = Class.extend ###* Invoke the command. ### invoke: -> @stat HMEVENT.begin, cmd: @moniker - ret = @workhorse.apply @, arguments - @stat HMEVENT.end - ret + argsArray = Array::slice.call arguments + that = @ + @promise = new Promise (res, rej) -> + that.resolve = res; that.reject = rej + that.workhorse.apply that, argsArray; return @@ -59,7 +62,10 @@ Verb = module.exports = Class.extend payload = payload || { } payload.sub = payload.fluenterror = errorCode payload.throw = hot - this.fire 'error', payload + @setError errorCode, payload + if payload.quit + @reject payload + @fire 'error', payload if hot throw payload true @@ -75,6 +81,10 @@ Verb = module.exports = Class.extend + hasError: -> @errorCode || @errorObj + + + ###* Associate error info with the invocation. ### setError: ( code, obj ) -> @errorCode = code diff --git a/test/scripts/test-cli.js b/test/scripts/test-cli.js index 746f129..da8fefe 100644 --- a/test/scripts/test-cli.js +++ b/test/scripts/test-cli.js @@ -14,7 +14,8 @@ var chai = require('chai') , PATH = require('path') , PKG = require('../../package.json') , STRIPCOLOR = require('stripcolorcodes') - , _ = require('underscore'); + , _ = require('underscore') + , EXEC = require('child_process').execSync @@ -40,34 +41,18 @@ function MyConsoleLog() { describe('Testing CLI interface', function () { - - // HackMyResume CLI stub. Handle a single HMR invocation. - function HackMyResumeStub( argsString ) { - - var args = argsString.split(' '); - args.unshift( process.argv[1] ); - args.unshift( process.argv[0] ); - process.exit = MyProcessExit; - - try { - HMRMAIN( args ); - } - catch( ex ) { - require('../../dist/cli/error').err( ex, false ); - if(ex.stack || (ex.inner && ex.inner.stacl)) - console.log(ex.stack || ex.inner.stack); - } - process.exit = ProcessExitOrg; - - } - // Run a test through the stub, gathering console.log output into "gather" // and testing against it. function run( args, expErr ) { var title = args; it( 'Testing: "' + title + '"\n\n', function() { - commandRetVal = 0; - HackMyResumeStub( args ); + try { + EXEC('hackmyresume ' + args); + commandRetVal = 0; + } + catch(ex) { + commandRetVal = ex.status; + } commandRetVal.should.equal( parseInt(expErr, 10) ); }); } diff --git a/test/scripts/test-hmr.txt b/test/scripts/test-hmr.txt index 9546899..55d562b 100644 --- a/test/scripts/test-hmr.txt +++ b/test/scripts/test-hmr.txt @@ -1,4 +1,4 @@ -0| +4| 0|--help 0|-h 0|--debug