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