1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2024-11-22 08:20:11 +00:00

Asynchrony.

This commit is contained in:
hacksalot 2016-02-01 21:14:36 -05:00
parent 212b01092c
commit 70f45d468d
77 changed files with 1162 additions and 519 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ doc/
docs/ docs/
local/ local/
npm-debug.log npm-debug.log
*.map
# Emacs detritus # Emacs detritus
# -*- mode: gitignore; -*- # -*- mode: gitignore; -*-

View File

@ -17,6 +17,9 @@ module.exports = function (grunt) {
coffee: { coffee: {
main: { main: {
options: {
sourceMap: true
},
expand: true, expand: true,
cwd: 'src', cwd: 'src',
src: ['**/*.coffee'], src: ['**/*.coffee'],

11
dist/cli/error.js vendored
View File

@ -35,8 +35,7 @@ Error-handling routines for HackMyResume.
require('string.prototype.startswith'); require('string.prototype.startswith');
/** /** Error handler for HackMyResume. All errors are handled here.
Error handler for HackMyResume. All errors are handled here.
@class ErrorHandler @class ErrorHandler
*/ */
@ -62,7 +61,7 @@ Error-handling routines for HackMyResume.
stack = ex.stack || (ex.inner && ex.inner.stack); stack = ex.stack || (ex.inner && ex.inner.stack);
stack && o(chalk.gray(stack)); stack && o(chalk.gray(stack));
} }
if (ex.quit || objError.quit) { if (shouldExit) {
if (this.debug) { if (this.debug) {
o(chalk.cyan('Exiting with error code ' + ex.fluenterror.toString())); o(chalk.cyan('Exiting with error code ' + ex.fluenterror.toString()));
} }
@ -221,6 +220,10 @@ Error-handling routines for HackMyResume.
msg = ex; msg = ex;
} }
etype = 'error'; etype = 'error';
break;
case HMSTATUS.createError:
msg = printf(M2C(this.msgs.createError.msg), ex.inner.path);
etype = 'error';
} }
return { return {
msg: msg, msg: msg,
@ -231,3 +234,5 @@ Error-handling routines for HackMyResume.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=error.js.map

44
dist/cli/main.js vendored
View File

@ -6,7 +6,7 @@ Definition of the `main` function.
*/ */
(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'); HMR = require('../index');
@ -42,6 +42,10 @@ Definition of the `main` function.
_out = new OUTPUT(_opts); _out = new OUTPUT(_opts);
_err = require('./error');
_exitCallback = null;
/* /*
A callable implementation of the HackMyResume CLI. Encapsulates the command 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). process.argv (in production) or custom parameters (in test).
*/ */
main = module.exports = function(rawArgs) { main = module.exports = function(rawArgs, exitCallback) {
var args, initInfo, program; var args, initInfo, program;
initInfo = initialize(rawArgs); initInfo = initialize(rawArgs, exitCallback);
args = initInfo.args; 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 = 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; program.jsonArgs = initInfo.options;
@ -92,8 +96,9 @@ Definition of the `main` function.
/* Massage command-line args and setup Commander.js. */ /* Massage command-line args and setup Commander.js. */
initialize = function(ar) { initialize = function(ar, exitCallback) {
var o; var o;
_exitCallback = exitCallback || process.exit;
o = initOptions(ar); o = initOptions(ar);
o.silent || logMsg(_title); o.silent || logMsg(_title);
if (o.debug) { 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(chalk.cyan(PAD(' FRESCA:', 25, null, PAD.RIGHT)) + chalk.cyan.bold(PKG.dependencies.fresca));
_out.log(''); _out.log('');
} }
_err.init(o.debug, o.assert, o.silent);
if (o.verb && !HMR.verbs[o.verb] && !HMR.alias[o.verb]) { if (o.verb && !HMR.verbs[o.verb] && !HMR.alias[o.verb]) {
throw { _err.err({
fluenterror: HMSTATUS.invalidCommand, fluenterror: HMSTATUS.invalidCommand,
quit: true, quit: true,
attempted: o.orgVerb attempted: o.orgVerb
}; }, true);
} }
Command.prototype.missingArgument = function(name) { Command.prototype.missingArgument = function(name) {
if (this.name() !== 'new') { if (this.name() !== 'new') {
@ -136,7 +142,7 @@ Definition of the `main` function.
initOptions = function(ar) { initOptions = function(ar) {
oVerb; 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 = ''; verb = '';
args = ar.slice(); args = ar.slice();
cleanArgs = args.slice(2); cleanArgs = args.slice(2);
@ -177,6 +183,9 @@ Definition of the `main` function.
isSilent = _.some(args, function(v) { isSilent = _.some(args, function(v) {
return v === '-s' || v === '--silent'; return v === '-s' || v === '--silent';
}); });
isAssert = _.some(args, function(v) {
return v === '-a' || v === '--assert';
});
isMono = _.some(args, function(v) { isMono = _.some(args, function(v) {
return v === '--no-color'; return v === '--no-color';
}); });
@ -184,6 +193,7 @@ Definition of the `main` function.
color: !isMono, color: !isMono,
debug: isDebug, debug: isDebug,
silent: isSilent, silent: isSilent,
assert: isAssert,
orgVerb: oVerb, orgVerb: oVerb,
verb: verb, verb: verb,
json: oJSON, json: oJSON,
@ -195,24 +205,22 @@ Definition of the `main` function.
/* Invoke a HackMyResume verb. */ /* Invoke a HackMyResume verb. */
execute = function(src, dst, opts, log) { execute = function(src, dst, opts, log) {
var hand, v; var onFail, prom, v;
loadOptions.call(this, opts, this.parent.jsonArgs);
hand = require('./error');
hand.init(_opts.debug, _opts.assert, _opts.silent);
v = new HMR.verbs[this.name()](); v = new HMR.verbs[this.name()]();
loadOptions.call(this, opts, this.parent.jsonArgs);
_opts.errHandler = v; _opts.errHandler = v;
_out.init(_opts); _out.init(_opts);
v.on('hmr:status', function() { v.on('hmr:status', function() {
return _out["do"].apply(_out, arguments); return _out["do"].apply(_out, arguments);
}); });
v.on('hmr:error', function() { 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); prom = v.invoke.call(v, src, dst, _opts, log);
if (v.errorCode) { onFail = function(err) {
console.log('Exiting with error code ' + v.errorCode); _exitCallback(err.fluenterror ? err.fluenterror : err);
return process.exit(v.errorCode); };
} prom.then((function() {}), onFail);
}; };
@ -282,3 +290,5 @@ Definition of the `main` function.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=main.js.map

2
dist/cli/msg.js vendored
View File

@ -15,3 +15,5 @@ Message-handling routines for HackMyResume.
module.exports = YAML.load(PATH.join(__dirname, 'msg.yml')); module.exports = YAML.load(PATH.join(__dirname, 'msg.yml'));
}).call(this); }).call(this);
//# sourceMappingURL=msg.js.map

4
dist/cli/msg.yml vendored
View File

@ -3,6 +3,8 @@ events:
msg: Invoking **%s** command. msg: Invoking **%s** command.
beforeCreate: beforeCreate:
msg: Creating new **%s** resume: **%s** msg: Creating new **%s** resume: **%s**
afterCreate:
msg: Creating new **%s** resume: **%s**
afterRead: afterRead:
msg: Reading **%s** resume: **%s** msg: Reading **%s** resume: **%s**
beforeTheme: beforeTheme:
@ -96,3 +98,5 @@ errors:
msg: "Invalid number of parameters. Expected: **%s**." msg: "Invalid number of parameters. Expected: **%s**."
missingParam: missingParam:
msg: The '**%s**' parameter was needed but not supplied. msg: The '**%s**' parameter was needed but not supplied.
createError:
msg: Failed to create **'%s'**.

6
dist/cli/out.js vendored
View File

@ -60,8 +60,8 @@ Output routines for HackMyResume.
switch (evt.sub) { switch (evt.sub) {
case HME.begin: case HME.begin:
return this.opts.debug && L(M2C(this.msgs.begin.msg, dbgStyle), evt.cmd.toUpperCase()); return this.opts.debug && L(M2C(this.msgs.begin.msg, dbgStyle), evt.cmd.toUpperCase());
case HME.beforeCreate: case HME.afterCreate:
L(M2C(this.msgs.beforeCreate.msg, 'green'), evt.fmt, evt.file); L(M2C(this.msgs.beforeCreate.msg, evt.isError ? 'red' : 'green'), evt.fmt, evt.file);
break; break;
case HME.beforeTheme: case HME.beforeTheme:
return this.opts.debug && L(M2C(this.msgs.beforeTheme.msg, dbgStyle), evt.theme.toUpperCase()); return this.opts.debug && L(M2C(this.msgs.beforeTheme.msg, dbgStyle), evt.theme.toUpperCase());
@ -155,3 +155,5 @@ Output routines for HackMyResume.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=out.js.map

View File

@ -69,3 +69,5 @@ Definition of the AbstractResume class.
module.exports = AbstractResume; module.exports = AbstractResume;
}).call(this); }).call(this);
//# sourceMappingURL=abstract-resume.js.map

View File

@ -58,3 +58,5 @@ Event code definitions.
]; ];
}).call(this); }).call(this);
//# sourceMappingURL=default-formats.js.map

View File

@ -16,3 +16,5 @@ Event code definitions.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=default-options.js.map

View File

@ -37,3 +37,5 @@ Event code definitions.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=event-codes.js.map

View File

@ -103,3 +103,5 @@ The HackMyResume date representation.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=fluent-date.js.map

View File

@ -517,3 +517,5 @@ Definition of the FRESHResume class.
module.exports = FreshResume; module.exports = FreshResume;
}).call(this); }).call(this);
//# sourceMappingURL=fresh-resume.js.map

View File

@ -277,3 +277,5 @@ Definition of the FRESHTheme class.
module.exports = FRESHTheme; module.exports = FRESHTheme;
}).call(this); }).call(this);
//# sourceMappingURL=fresh-theme.js.map

View File

@ -429,3 +429,5 @@ Definition of the JRSResume class.
module.exports = JRSResume; module.exports = JRSResume;
}).call(this); }).call(this);
//# sourceMappingURL=jrs-resume.js.map

View File

@ -103,3 +103,5 @@ Definition of the JRSTheme class.
module.exports = JRSTheme; module.exports = JRSTheme;
}).call(this); }).call(this);
//# sourceMappingURL=jrs-theme.js.map

View File

@ -83,7 +83,7 @@ Definition of the ResumeFactory class.
}; };
_parse = function(fileName, opts, eve) { _parse = function(fileName, opts, eve) {
var ex, orgFormat, rawData, ret; var orgFormat, rawData, ret;
rawData = null; rawData = null;
try { try {
eve && eve.stat(HME.beforeRead, { eve && eve.stat(HME.beforeRead, {
@ -108,20 +108,15 @@ Definition of the ResumeFactory class.
}); });
return ret; return ret;
} catch (_error) { } catch (_error) {
ex = { return {
fluenterror: rawData ? HACKMYSTATUS.parseError : HACKMYSTATUS.readError, fluenterror: rawData ? HACKMYSTATUS.parseError : HACKMYSTATUS.readError,
inner: _error, inner: _error,
raw: rawData, raw: rawData,
file: fileName, file: fileName
shouldExit: false
}; };
opts.quit && (ex.quit = true);
eve && eve.err(ex.fluenterror, ex);
if (opts["throw"]) {
throw ex;
}
return ex;
} }
}; };
}).call(this); }).call(this);
//# sourceMappingURL=resume-factory.js.map

View File

@ -31,7 +31,10 @@ Status codes for HackMyResume.
compileTemplate: 21, compileTemplate: 21,
themeLoad: 22, themeLoad: 22,
invalidParamCount: 23, invalidParamCount: 23,
missingParam: 24 missingParam: 24,
createError: 25
}; };
}).call(this); }).call(this);
//# sourceMappingURL=status-codes.js.map

View File

@ -31,3 +31,5 @@ Definition of the BaseGenerator class.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=base-generator.js.map

View File

@ -40,3 +40,5 @@ Definition of the HTMLGenerator class.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=html-generator.js.map

View File

@ -46,8 +46,19 @@ Definition of the HtmlPdfCLIGenerator class.
return null; 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) { 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); }).call(this);
//# sourceMappingURL=html-pdf-cli-generator.js.map

View File

@ -62,3 +62,5 @@ Definition of the HtmlPngGenerator class.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=html-png-generator.js.map

View File

@ -43,3 +43,5 @@ Definition of the JsonGenerator class.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=json-generator.js.map

View File

@ -31,8 +31,11 @@ Definition of the JsonYamlGenerator class.
generate: function(rez, f, opts) { generate: function(rez, f, opts) {
var data; var data;
data = YAML.stringify(JSON.parse(rez.stringify()), Infinity, 2); data = YAML.stringify(JSON.parse(rez.stringify()), Infinity, 2);
return FS.writeFileSync(f, data, 'utf8'); FS.writeFileSync(f, data, 'utf8');
return data;
} }
}); });
}).call(this); }).call(this);
//# sourceMappingURL=json-yaml-generator.js.map

View File

@ -22,3 +22,5 @@ Definition of the LaTeXGenerator class.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=latex-generator.js.map

View File

@ -22,3 +22,5 @@ Definition of the MarkdownGenerator class.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=markdown-generator.js.map

View File

@ -241,3 +241,5 @@ Definition of the TemplateGenerator class. TODO: Refactor
}; };
}).call(this); }).call(this);
//# sourceMappingURL=template-generator.js.map

View File

@ -22,3 +22,5 @@ Definition of the TextGenerator class.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=text-generator.js.map

View File

@ -17,3 +17,5 @@ Definition of the WordGenerator class.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=word-generator.js.map

View File

@ -22,3 +22,5 @@ Definition of the XMLGenerator class.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=xml-generator.js.map

View File

@ -22,3 +22,5 @@ Definition of the YAMLGenerator class.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=yaml-generator.js.map

View File

@ -62,3 +62,5 @@ Generic template helper definitions for command-line output.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=console-helpers.js.map

View File

@ -614,3 +614,5 @@ Generic template helper definitions for HackMyResume / FluentCV.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=generic-helpers.js.map

View File

@ -27,3 +27,5 @@ Template helper definitions for Handlebars.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=handlebars-helpers.js.map

View File

@ -34,3 +34,5 @@ Template helper definitions for Underscore.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=underscore-helpers.js.map

2
dist/index.js vendored
View File

@ -47,3 +47,5 @@ API facade for HackMyCore.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=index.js.map

View File

@ -136,3 +136,5 @@ Employment gap analysis for HackMyResume.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=gap-inspector.js.map

View File

@ -59,3 +59,5 @@ Keyword analysis for HackMyResume.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=keyword-inspector.js.map

View File

@ -47,3 +47,5 @@ Section analysis for HackMyResume.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=totals-inspector.js.map

View File

@ -98,3 +98,5 @@ Definition of the HandlebarsGenerator class.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=handlebars-generator.js.map

View File

@ -57,3 +57,5 @@ Definition of the JRSGenerator class.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=jrs-generator.js.map

View File

@ -58,3 +58,5 @@ Definition of the UnderscoreGenerator class.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=underscore-generator.js.map

View File

@ -10,3 +10,5 @@ Definition of the SyntaxErrorEx class.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=file-contains.js.map

View File

@ -59,3 +59,5 @@ Definition of the Markdown to WordProcessingML conversion routine.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=html-to-wpml.js.map

View File

@ -26,3 +26,5 @@ Inline Markdown-to-Chalk conversion routines.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=md2chalk.js.map

View File

@ -75,3 +75,5 @@
} }
}).call(this); }).call(this);
//# sourceMappingURL=rasterize.js.map

View File

@ -30,3 +30,5 @@ Definition of the SafeJsonLoader class.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=safe-json-loader.js.map

View File

@ -42,3 +42,5 @@ exception
}; };
}).call(this); }).call(this);
//# sourceMappingURL=safe-spawn.js.map

View File

@ -60,3 +60,5 @@ Object string transformation.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=string-transformer.js.map

View File

@ -25,3 +25,5 @@ See: http://stackoverflow.com/a/32800728/4942583
}; };
}).call(this); }).call(this);
//# sourceMappingURL=string.js.map

View File

@ -37,3 +37,5 @@ See: http://stackoverflow.com/q/13323356
module.exports = SyntaxErrorEx; module.exports = SyntaxErrorEx;
}).call(this); }).call(this);
//# sourceMappingURL=syntax-error-ex.js.map

60
dist/verbs/analyze.js vendored
View File

@ -6,7 +6,7 @@ Implementation of the 'analyze' verb for HackMyResume.
*/ */
(function() { (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'); MKDIRP = require('mkdirp');
@ -24,46 +24,56 @@ Implementation of the 'analyze' verb for HackMyResume.
chalk = require('chalk'); chalk = require('chalk');
/** An invokable resume analysis command. */
AnalyzeVerb = module.exports = Verb.extend({ AnalyzeVerb = module.exports = Verb.extend({
init: function() { init: function() {
return this._super('analyze', analyze); return this._super('analyze', _analyze);
} }
}); });
/** /** Private workhorse for the 'analyze' command. */
Run the 'analyze' command.
*/
analyze = function(sources, dst, opts) { _analyze = function(sources, dst, opts) {
var nlzrs; var nlzrs, results;
if (!sources || !sources.length) { if (!sources || !sources.length) {
throw { this.err(HMSTATUS.resumeNotFound, {
fluenterror: HMSTATUS.resumeNotFound,
quit: true quit: true
}; });
return null;
} }
nlzrs = _loadInspectors(); nlzrs = _loadInspectors();
return _.each(sources, function(src) { results = _.map(sources, function(src) {
var result; var r;
result = ResumeFactory.loadOne(src, { r = ResumeFactory.loadOne(src, {
format: 'FRESH', format: 'FRESH',
objectify: true objectify: true
}, this); }, this);
if (result.fluenterror) { if (opts.assert && this.hasError()) {
return this.setError(result.fluenterror, result); return {};
}
if (r.fluenterror) {
r.quit = opts.assert;
this.err(r.fluenterror, r);
return r;
} else { } else {
return _analyze.call(this, result, nlzrs, opts); return _analyzeOne.call(this, r, nlzrs, opts);
} }
}, this); }, 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; var info, rez, safeFormat;
rez = resumeObject.rez; rez = resumeObject.rez;
safeFormat = rez.meta && rez.meta.format && rez.meta.format.startsWith('FRESH') ? 'FRESH' : 'JRS'; 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) { info = _.mapObject(nlzrs, function(val, key) {
return val.run(rez); return val.run(rez);
}); });
return this.stat(HMEVENT.afterAnalyze, { this.stat(HMEVENT.afterAnalyze, {
info: info info: info
}); });
return info;
}; };
/**
Load inspectors.
*/
_loadInspectors = function() { _loadInspectors = function() {
return { return {
totals: require('../inspectors/totals-inspector'), totals: require('../inspectors/totals-inspector'),
@ -93,3 +99,5 @@ Implementation of the 'analyze' verb for HackMyResume.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=analyze.js.map

63
dist/verbs/build.js vendored
View File

@ -6,7 +6,7 @@ Implementation of the 'build' verb for HackMyResume.
*/ */
(function() { (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'); _ = require('underscore');
@ -74,7 +74,7 @@ Implementation of the 'build' verb for HackMyResume.
/** Create a new build verb. */ /** Create a new build verb. */
init: function() { 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. @param opts Generation options.
*/ */
build = function(src, dst, opts) { _build = function(src, dst, opts) {
var ex, inv, isFRESH, mixed, newEx, orgFormat, problemSheets, rez, sheetObjects, sheets, tFolder, targets, theme, toFormat; var inv, isFRESH, mixed, newEx, orgFormat, problemSheets, results, rez, sheetObjects, sheets, tFolder, targets, theme, toFormat;
if (!src || !src.length) { if (!src || !src.length) {
this.err(HMSTATUS.resumeNotFound, { this.err(HMSTATUS.resumeNotFound, {
quit: true quit: true
}); });
return null; return null;
} }
prep(src, dst, opts); _prep(src, dst, opts);
sheetObjects = ResumeFactory.load(src, { sheetObjects = ResumeFactory.load(src, {
format: null, format: null,
objectify: false, objectify: false,
@ -120,14 +120,13 @@ Implementation of the 'build' verb for HackMyResume.
theme: _opts.theme theme: _opts.theme
}); });
try { try {
tFolder = verifyTheme.call(this, _opts.theme); tFolder = _verifyTheme.call(this, _opts.theme);
theme = _opts.themeObj = loadTheme(tFolder); theme = _opts.themeObj = _loadTheme(tFolder);
addFreebieFormats(theme); _addFreebieFormats(theme);
} catch (_error) { } catch (_error) {
ex = _error;
newEx = { newEx = {
fluenterror: HMSTATUS.themeLoad, fluenterror: HMSTATUS.themeLoad,
inner: ex, inner: _error,
attempted: _opts.theme, attempted: _opts.theme,
quit: true quit: true
}; };
@ -137,7 +136,7 @@ Implementation of the 'build' verb for HackMyResume.
this.stat(HMEVENT.afterTheme, { this.stat(HMEVENT.afterTheme, {
theme: theme theme: theme
}); });
inv = verifyOutputs.call(this, dst, theme); inv = _verifyOutputs.call(this, dst, theme);
if (inv && inv.length) { if (inv && inv.length) {
this.err(HMSTATUS.invalidFormat, { this.err(HMSTATUS.invalidFormat, {
data: inv, data: inv,
@ -187,15 +186,28 @@ Implementation of the 'build' verb for HackMyResume.
theme: theme theme: theme
}); });
_rezObj = new RTYPES[toFormat]().parseJSON(rez); _rezObj = new RTYPES[toFormat]().parseJSON(rez);
targets = expand(dst, theme); targets = _expand(dst, theme);
_.each(targets, function(t) { _.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); }, this);
return { results = {
sheet: _rezObj, sheet: _rezObj,
targets: targets, targets: targets,
processed: 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. 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.theme = (opts.theme && opts.theme.toLowerCase().trim()) || 'modern';
_opts.prettify = opts.prettify === true; _opts.prettify = opts.prettify === true;
_opts.css = opts.css; _opts.css = opts.css;
@ -226,7 +238,7 @@ Implementation of the 'build' verb for HackMyResume.
@param theme A FRESHTheme or JRSTheme object. @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; var e, ex, f, fName, fType, outFolder, ret, theFormat;
ret = null; ret = null;
ex = null; ex = null;
@ -268,11 +280,12 @@ Implementation of the 'build' verb for HackMyResume.
}); });
if (ex) { if (ex) {
if (ex.fluenterror) { if (ex.fluenterror) {
this.err(ex.fluenterror, ex); ret = ex;
} else { } else {
this.err(HMSTATUS.generateError, { ret = {
fluenterror: HMSTATUS.generateError,
inner: ex inner: ex
}); };
} }
} }
return ret; return ret;
@ -281,7 +294,7 @@ Implementation of the 'build' verb for HackMyResume.
/** Ensure that user-specified outputs/targets are valid. */ /** Ensure that user-specified outputs/targets are valid. */
verifyOutputs = function(targets, theme) { _verifyOutputs = function(targets, theme) {
this.stat(HMEVENT.verifyOutputs, { this.stat(HMEVENT.verifyOutputs, {
targets: targets, targets: targets,
theme: theme theme: theme
@ -308,7 +321,7 @@ Implementation of the 'build' verb for HackMyResume.
@param theTheme A FRESHTheme or JRSTheme object. @param theTheme A FRESHTheme or JRSTheme object.
*/ */
addFreebieFormats = function(theTheme) { _addFreebieFormats = function(theTheme) {
theTheme.formats.json = theTheme.formats.json || { theTheme.formats.json = theTheme.formats.json || {
freebie: true, freebie: true,
title: 'json', title: 'json',
@ -347,7 +360,7 @@ Implementation of the 'build' verb for HackMyResume.
@param theTheme A FRESHTheme or JRSTheme object. @param theTheme A FRESHTheme or JRSTheme object.
*/ */
expand = function(dst, theTheme) { _expand = function(dst, theTheme) {
var destColl, targets; var destColl, targets;
destColl = (dst && dst.length && dst) || [PATH.normalize('out/resume.all')]; destColl = (dst && dst.length && dst) || [PATH.normalize('out/resume.all')];
targets = []; targets = [];
@ -378,7 +391,7 @@ Implementation of the 'build' verb for HackMyResume.
Verify the specified theme name/path. Verify the specified theme name/path.
*/ */
verifyTheme = function(themeNameOrPath) { _verifyTheme = function(themeNameOrPath) {
var exists, tFolder; var exists, tFolder;
tFolder = PATH.join(parsePath(require.resolve('fresh-themes')).dirname, '/themes/', themeNameOrPath); tFolder = PATH.join(parsePath(require.resolve('fresh-themes')).dirname, '/themes/', themeNameOrPath);
exists = require('path-exists').sync; exists = require('path-exists').sync;
@ -399,7 +412,7 @@ Implementation of the 'build' verb for HackMyResume.
theme. theme.
*/ */
loadTheme = function(tFolder) { _loadTheme = function(tFolder) {
var theTheme; var theTheme;
theTheme = _opts.theme.indexOf('jsonresume-theme-') > -1 ? new JRSTheme().open(tFolder) : new FRESHTheme().open(tFolder); theTheme = _opts.theme.indexOf('jsonresume-theme-') > -1 ? new JRSTheme().open(tFolder) : new FRESHTheme().open(tFolder);
_opts.themeObj = theTheme; _opts.themeObj = theTheme;
@ -407,3 +420,5 @@ Implementation of the 'build' verb for HackMyResume.
}; };
}).call(this); }).call(this);
//# sourceMappingURL=build.js.map

68
dist/verbs/convert.js vendored
View File

@ -6,7 +6,7 @@ Implementation of the 'convert' verb for HackMyResume.
*/ */
(function() { (function() {
var ConvertVerb, HMEVENT, HMSTATUS, ResumeFactory, Verb, _, chalk, convert; var ConvertVerb, HMEVENT, HMSTATUS, ResumeFactory, Verb, _, _convert, _convertOne, chalk;
ResumeFactory = require('../core/resume-factory'); ResumeFactory = require('../core/resume-factory');
@ -22,55 +22,73 @@ Implementation of the 'convert' verb for HackMyResume.
ConvertVerb = module.exports = Verb.extend({ ConvertVerb = module.exports = Verb.extend({
init: function() { init: function() {
return this._super('convert', convert); return this._super('convert', _convert);
} }
}); });
/** /** Private workhorse method. Convert 0..N resumes between FRESH and JRS
Convert between FRESH and JRS formats. formats.
*/ */
convert = function(srcs, dst, opts) { _convert = function(srcs, dst, opts) {
var results;
if (!srcs || !srcs.length) { if (!srcs || !srcs.length) {
throw { this.err(HMSTATUS.resumeNotFound, {
fluenterror: 6,
quit: true quit: true
}; });
return null;
} }
if (!dst || !dst.length) { if (!dst || !dst.length) {
if (srcs.length === 1) { if (srcs.length === 1) {
throw { this.err(HMSTATUS.inputOutputParity, {
fluenterror: HMSTATUS.inputOutputParity,
quit: true quit: true
}; });
} else if (srcs.length === 2) { } else if (srcs.length === 2) {
dst = dst || []; dst = dst || [];
dst.push(srcs.pop()); dst.push(srcs.pop());
} else { } else {
throw { this.err(HMSTATUS.inputOutputParity, {
fluenterror: HMSTATUS.inputOutputParity,
quit: true quit: true
}; });
} }
} }
if (srcs && dst && srcs.length && dst.length && srcs.length !== dst.length) { if (srcs && dst && srcs.length && dst.length && srcs.length !== dst.length) {
throw { this.err(HMSTATUS.inputOutputParity, {
fluenterror: HMSTATUS.inputOutputParity({
quit: true quit: true
}) });
};
} }
_.each(srcs, function(src, idx) { results = _.map(srcs, function(src, idx) {
var r;
if (opts.assert && this.hasError()) {
return {};
}
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; var rinfo, s, srcFmt, targetFormat;
rinfo = ResumeFactory.loadOne(src, { rinfo = ResumeFactory.loadOne(src, {
format: null, format: null,
objectify: true, objectify: true
"throw": false
}); });
if (rinfo.fluenterror) { if (rinfo.fluenterror) {
this.err(rinfo.fluenterror, rinfo); return rinfo;
return;
} }
s = rinfo.rez; s = rinfo.rez;
srcFmt = ((s.basics && s.basics.imp) || s.imp).orgFormat === 'JRS' ? 'JRS' : 'FRESH'; srcFmt = ((s.basics && s.basics.imp) || s.imp).orgFormat === 'JRS' ? 'JRS' : 'FRESH';
@ -82,7 +100,9 @@ Implementation of the 'convert' verb for HackMyResume.
dstFmt: targetFormat dstFmt: targetFormat
}); });
s.saveAs(dst[idx], targetFormat); s.saveAs(dst[idx], targetFormat);
}, this); return s;
}; };
}).call(this); }).call(this);
//# sourceMappingURL=convert.js.map

66
dist/verbs/create.js vendored
View File

@ -6,7 +6,7 @@ Implementation of the 'create' verb for HackMyResume.
*/ */
(function() { (function() {
var CreateVerb, HMEVENT, HMSTATUS, MKDIRP, PATH, Verb, _, chalk, create; var CreateVerb, HMEVENT, HMSTATUS, MKDIRP, PATH, Verb, _, _create, _createOne, chalk;
MKDIRP = require('mkdirp'); MKDIRP = require('mkdirp');
@ -24,24 +24,48 @@ Implementation of the 'create' verb for HackMyResume.
CreateVerb = module.exports = Verb.extend({ CreateVerb = module.exports = Verb.extend({
init: function() { 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) { if (!src || !src.length) {
throw { this.err(HMSTATUS.createNameMissing, {
fluenterror: HMSTATUS.createNameMissing,
quit: true quit: true
}; });
return null;
} }
_.each(src, function(t) { results = _.map(src, function(t) {
var RezClass, safeFmt; 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(); safeFmt = opts.format.toUpperCase();
this.stat(HMEVENT.beforeCreate, { this.stat(HMEVENT.beforeCreate, {
fmt: safeFmt, fmt: safeFmt,
@ -49,12 +73,24 @@ Implementation of the 'create' verb for HackMyResume.
}); });
MKDIRP.sync(PATH.dirname(t)); MKDIRP.sync(PATH.dirname(t));
RezClass = require('../core/' + safeFmt.toLowerCase() + '-resume'); RezClass = require('../core/' + safeFmt.toLowerCase() + '-resume');
RezClass["default"]().save(t); newRez = RezClass["default"]();
return this.stat(HMEVENT.afterCreate, { newRez.save(t);
ret = newRez;
} catch (_error) {
ret = {
fluenterror: HMSTATUS.createError,
inner: _error
};
} finally {
this.stat(HMEVENT.afterCreate, {
fmt: safeFmt, fmt: safeFmt,
file: t file: t,
isError: ret.fluenterror
}); });
}, this); return ret;
}
}; };
}).call(this); }).call(this);
//# sourceMappingURL=create.js.map

49
dist/verbs/peek.js vendored
View File

@ -6,7 +6,7 @@ Implementation of the 'peek' verb for HackMyResume.
*/ */
(function() { (function() {
var HMEVENT, HMSTATUS, PeekVerb, Verb, _, __, peek, safeLoadJSON; var HMEVENT, HMSTATUS, PeekVerb, Verb, _, __, _peek, _peekOne, safeLoadJSON;
Verb = require('../verbs/verb'); Verb = require('../verbs/verb');
@ -22,24 +22,45 @@ Implementation of the 'peek' verb for HackMyResume.
PeekVerb = module.exports = Verb.extend({ PeekVerb = module.exports = Verb.extend({
init: function() { init: function() {
return this._super('peek', peek); return this._super('peek', _peek);
} }
}); });
/** Peek at a resume, resume section, or resume field. */ /** Peek at a resume, resume section, or resume field. */
peek = function(src, dst, opts) { _peek = function(src, dst, opts) {
var objPath; var objPath, results;
if (!src || !src.length) { if (!src || !src.length) {
({ this.err(HMSTATUS.resumeNotFound, {
"throw": { quit: true
fluenterror: HMSTATUS.resumeNotFound
}
}); });
return null;
} }
objPath = (dst && dst[0]) || ''; objPath = (dst && dst[0]) || '';
_.each(src, function(t) { results = _.map(src, function(t) {
var tgt;
if (opts.assert && this.hasError()) {
return {};
}
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; var errCode, obj, tgt;
this.stat(HMEVENT.beforePeek, { this.stat(HMEVENT.beforePeek, {
file: t, file: t,
@ -61,10 +82,14 @@ Implementation of the 'peek' verb for HackMyResume.
if (errCode === HMSTATUS.readError) { if (errCode === HMSTATUS.readError) {
obj.ex.quiet = true; obj.ex.quiet = true;
} }
this.setError(errCode, obj.ex); return {
return this.err(errCode, obj.ex); fluenterror: errCode,
inner: obj.ex
};
} }
}, this); return tgt;
}; };
}).call(this); }).call(this);
//# sourceMappingURL=peek.js.map

View File

@ -6,7 +6,7 @@ Implementation of the 'validate' verb for HackMyResume.
*/ */
(function() { (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'); FS = require('fs');
@ -31,34 +31,64 @@ Implementation of the 'validate' verb for HackMyResume.
ValidateVerb = module.exports = Verb.extend({ ValidateVerb = module.exports = Verb.extend({
init: function() { init: function() {
return this._super('validate', validate); return this._super('validate', _validate);
} }
}); });
/** Validate 1 to N resumes in FRESH or JSON Resume format. */ /** Validate 1 to N resumes in FRESH or JSON Resume format. */
validate = function(sources, unused, opts) { _validate = function(sources, unused, opts) {
var schemas, validator; var results, schemas, validator;
if (!sources || !sources.length) { if (!sources || !sources.length) {
throw { this.err(HMSTATUS.resumeNotFoundAlt, {
fluenterror: HMSTATUS.resumeNotFoundAlt,
quit: true quit: true
}; });
return null;
} }
validator = require('is-my-json-valid'); validator = require('is-my-json-valid');
schemas = { schemas = {
fresh: require('fresca'), fresh: require('fresca'),
jars: require('../core/resume.json') jars: require('../core/resume.json')
}; };
return _.map(sources, function(t) { results = _.map(sources, function(t) {
var errCode, errors, fmt, json, obj, ret; var r;
if (this.hasError() && opts.assert) {
return {};
}
r = _validateOne.call(this, t, validator, schemas);
if (r.fluenterror) {
console.log(r);
r.quit = opts.assert;
this.err(r.fluenterror, r);
}
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 = { ret = {
file: t, file: t,
isValid: false isValid: false
}; };
obj = safeLoadJSON(t); obj = safeLoadJSON(t);
if (!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
};
}
json = obj.json; json = obj.json;
fmt = json.basics ? 'jrs' : 'fresh'; fmt = json.basics ? 'jrs' : 'fresh';
errors = []; errors = [];
@ -75,14 +105,6 @@ Implementation of the 'validate' verb for HackMyResume.
} catch (_error) { } catch (_error) {
ret.ex = _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);
}
this.stat(HMEVENT.afterValidate, { this.stat(HMEVENT.afterValidate, {
file: t, file: t,
isValid: ret.isValid, isValid: ret.isValid,
@ -90,13 +112,14 @@ Implementation of the 'validate' verb for HackMyResume.
errors: errors errors: errors
}); });
if (opts.assert && !ret.isValid) { if (opts.assert && !ret.isValid) {
throw { return {
fluenterror: HMSTATUS.invalid, fluenterror: HMSTATUS.invalid,
shouldExit: true errors: errors
}; };
} }
return ret; return ret;
}, this);
}; };
}).call(this); }).call(this);
//# sourceMappingURL=validate.js.map

27
dist/verbs/verb.js vendored
View File

@ -6,7 +6,7 @@ Definition of the Verb class.
*/ */
(function() { (function() {
var Class, EVENTS, HMEVENT, Verb; var Class, EVENTS, HMEVENT, Promise, Verb;
Class = require('../utils/class'); Class = require('../utils/class');
@ -14,6 +14,8 @@ Definition of the Verb class.
HMEVENT = require('../core/event-codes'); HMEVENT = require('../core/event-codes');
Promise = require('pinkie-promise');
/** /**
An instantiation of a HackMyResume command. An instantiation of a HackMyResume command.
@ -25,19 +27,23 @@ Definition of the Verb class.
/** Constructor. Automatically called at creation. */ /** Constructor. Automatically called at creation. */
init: function(moniker, workhorse) { init: function(moniker, workhorse) {
this.moniker = moniker; this.moniker = moniker;
this.emitter = new EVENTS.EventEmitter();
this.workhorse = workhorse; this.workhorse = workhorse;
this.emitter = new EVENTS.EventEmitter();
}, },
/** Invoke the command. */ /** Invoke the command. */
invoke: function() { invoke: function() {
var ret; var argsArray, that;
this.stat(HMEVENT.begin, { this.stat(HMEVENT.begin, {
cmd: this.moniker cmd: this.moniker
}); });
ret = this.workhorse.apply(this, arguments); argsArray = Array.prototype.slice.call(arguments);
this.stat(HMEVENT.end); that = this;
return ret; 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. */ /** Forward subscriptions to the event emitter. */
@ -58,6 +64,10 @@ Definition of the Verb class.
payload = payload || {}; payload = payload || {};
payload.sub = payload.fluenterror = errorCode; payload.sub = payload.fluenterror = errorCode;
payload["throw"] = hot; payload["throw"] = hot;
this.setError(errorCode, payload);
if (payload.quit) {
this.reject(payload);
}
this.fire('error', payload); this.fire('error', payload);
if (hot) { if (hot) {
throw payload; throw payload;
@ -72,6 +82,9 @@ Definition of the Verb class.
this.fire('status', payload); this.fire('status', payload);
return true; return true;
}, },
hasError: function() {
return this.errorCode || this.errorObj;
},
/** Associate error info with the invocation. */ /** Associate error info with the invocation. */
setError: function(code, obj) { setError: function(code, obj) {
@ -81,3 +94,5 @@ Definition of the Verb class.
}); });
}).call(this); }).call(this);
//# sourceMappingURL=verb.js.map

285
out/rez.yml Normal file
View File

@ -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 <strong>HTML</strong> 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 <strong>HTML</strong> 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 <strong>HTML</strong> 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 <strong>HTML</strong> 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 <strong>HTML</strong> 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 <strong>HTML</strong> 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'

View File

@ -67,6 +67,7 @@
"moment": "^2.11.1", "moment": "^2.11.1",
"parse-filepath": "^0.6.3", "parse-filepath": "^0.6.3",
"path-exists": "^2.1.0", "path-exists": "^2.1.0",
"pinkie-promise": "^2.0.0",
"printf": "^0.2.3", "printf": "^0.2.3",
"recursive-readdir-sync": "^1.0.6", "recursive-readdir-sync": "^1.0.6",
"simple-html-tokenizer": "^0.2.1", "simple-html-tokenizer": "^0.2.1",

View File

@ -22,10 +22,8 @@ require 'string.prototype.startswith'
###* ###* Error handler for HackMyResume. All errors are handled here.
Error handler for HackMyResume. All errors are handled here. @class ErrorHandler ###
@class ErrorHandler
###
ErrorHandler = module.exports = ErrorHandler = module.exports =
init: ( debug, assert, silent ) -> init: ( debug, assert, silent ) ->
@ -38,7 +36,7 @@ ErrorHandler = module.exports =
err: ( ex, shouldExit ) -> err: ( ex, shouldExit ) ->
# Short-circuit logging output if --silent is on # 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. # Special case; can probably be removed.
throw ex if ex.pass throw ex if ex.pass
@ -51,7 +49,7 @@ ErrorHandler = module.exports =
# Output the error message # Output the error message
objError = assembleError.call @, ex objError = assembleError.call @, ex
o( this[ 'format_' + objError.etype ]( objError.msg )) o( @[ 'format_' + objError.etype ]( objError.msg ))
# Output the stack (sometimes) # Output the stack (sometimes)
if objError.withStack if objError.withStack
@ -59,20 +57,20 @@ ErrorHandler = module.exports =
stack && o( chalk.gray( stack ) ); stack && o( chalk.gray( stack ) );
# Quit if necessary # Quit if necessary
if ex.quit || objError.quit if shouldExit
if @debug if @debug
o chalk.cyan('Exiting with error code ' + ex.fluenterror.toString()) o chalk.cyan('Exiting with error code ' + ex.fluenterror.toString())
if this.assert if @assert
ex.pass = true ex.pass = true
throw ex throw ex
process.exit ex.fluenterror process.exit ex.fluenterror
# Handle raw exceptions # Handle raw exceptions
else else
o( ex ) o ex
stackTrace = ex.stack || (ex.inner && ex.inner.stack) stackTrace = ex.stack || (ex.inner && ex.inner.stack)
if stackTrace && this.debug 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 msg = ex
etype = 'error' 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 msg: msg # The error message to display
withStack: withStack # Whether to include the stack withStack: withStack # Whether to include the stack
quit: quit quit: quit

View File

@ -23,6 +23,8 @@ Command = require('commander').Command
_opts = { } _opts = { }
_title = chalk.white.bold('\n*** HackMyResume v' +PKG.version+ ' ***') _title = chalk.white.bold('\n*** HackMyResume v' +PKG.version+ ' ***')
_out = new OUTPUT( _opts ) _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 @param rawArgs {Array} An array of command-line parameters. Will either be
process.argv (in production) or custom parameters (in test). 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 args = initInfo.args
# Create the top-level (application) command... # Create the top-level (application) command...
@ -129,10 +131,10 @@ main = module.exports = (rawArgs) ->
### Massage command-line args and setup Commander.js. ### ### Massage command-line args and setup Commander.js. ###
initialize = ( ar ) -> initialize = ( ar, exitCallback ) ->
o = initOptions( ar );
_exitCallback = exitCallback || process.exit
o = initOptions ar
o.silent || logMsg( _title ) o.silent || logMsg( _title )
# Emit debug prelude if --debug was specified # 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(chalk.cyan(PAD(' fresh-jrs-converter:',25, null, PAD.RIGHT)) + chalk.cyan.bold( PKG.dependencies['fresh-jrs-converter'] ))
_out.log('') _out.log('')
_err.init o.debug, o.assert, o.silent
# Handle invalid verbs here (a bit easier here than in commander.js)... # Handle invalid verbs here (a bit easier here than in commander.js)...
if o.verb && !HMR.verbs[ o.verb ] && !HMR.alias[ o.verb ] 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 # Override the .missingArgument behavior
Command.prototype.missingArgument = (name) -> Command.prototype.missingArgument = (name) ->
@ -205,23 +209,17 @@ initOptions = ( ar ) ->
oJSON = inf.json oJSON = inf.json
# TODO: Error handling # TODO: Error handling
# Grab the --debug flag # Grab the --debug flag, --silent, --assert and --no-color flags
isDebug = _.some( args, (v) -> isDebug = _.some args, (v) -> v == '-d' || v == '--debug'
return v == '-d' || v == '--debug' isSilent = _.some args, (v) -> v == '-s' || v == '--silent'
) isAssert = _.some args, (v) -> v == '-a' || v == '--assert'
# Grab the --silent flag
isSilent = _.some( args, (v) ->
return v == '-s' || v == '--silent'
)
# Grab the --no-color flag
isMono = _.some args, (v) -> v == '--no-color' isMono = _.some args, (v) -> v == '--no-color'
return { return {
color: !isMono, color: !isMono,
debug: isDebug, debug: isDebug,
silent: isSilent, silent: isSilent,
assert: isAssert,
orgVerb: oVerb, orgVerb: oVerb,
verb: verb, verb: verb,
json: oJSON, json: oJSON,
@ -233,19 +231,29 @@ initOptions = ( ar ) ->
### Invoke a HackMyResume verb. ### ### Invoke a HackMyResume verb. ###
execute = ( src, dst, opts, log ) -> execute = ( src, dst, opts, log ) ->
loadOptions.call( this, opts, this.parent.jsonArgs ) # Create the verb
hand = require( './error' ) v = new HMR.verbs[ @name() ]()
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)
# 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

View File

@ -3,6 +3,8 @@ events:
msg: Invoking **%s** command. msg: Invoking **%s** command.
beforeCreate: beforeCreate:
msg: Creating new **%s** resume: **%s** msg: Creating new **%s** resume: **%s**
afterCreate:
msg: Creating new **%s** resume: **%s**
afterRead: afterRead:
msg: Reading **%s** resume: **%s** msg: Reading **%s** resume: **%s**
beforeTheme: beforeTheme:
@ -96,3 +98,5 @@ errors:
msg: "Invalid number of parameters. Expected: **%s**." msg: "Invalid number of parameters. Expected: **%s**."
missingParam: missingParam:
msg: The '**%s**' parameter was needed but not supplied. msg: The '**%s**' parameter was needed but not supplied.
createError:
msg: Failed to create **'%s'**.

View File

@ -50,8 +50,12 @@ OutputHandler = module.exports = Class.extend
this.opts.debug && this.opts.debug &&
L( M2C( this.msgs.begin.msg, dbgStyle), evt.cmd.toUpperCase() ) L( M2C( this.msgs.begin.msg, dbgStyle), evt.cmd.toUpperCase() )
when HME.beforeCreate #when HME.beforeCreate
L( M2C( this.msgs.beforeCreate.msg, 'green' ), evt.fmt, evt.file ) #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; break;
when HME.beforeTheme when HME.beforeTheme

View File

@ -103,13 +103,7 @@ _parse = ( fileName, opts, eve ) ->
return ret return ret
catch catch
# Can be ENOENT, EACCES, SyntaxError, etc. # Can be ENOENT, EACCES, SyntaxError, etc.
ex =
fluenterror: if rawData then HACKMYSTATUS.parseError else HACKMYSTATUS.readError fluenterror: if rawData then HACKMYSTATUS.parseError else HACKMYSTATUS.readError
inner: _error inner: _error
raw: rawData raw: rawData
file: fileName file: fileName
shouldExit: false
opts.quit && (ex.quit = true)
eve && eve.err ex.fluenterror, ex
throw ex if opts.throw
ex

View File

@ -31,3 +31,4 @@ module.exports =
themeLoad: 22 themeLoad: 22
invalidParamCount: 23 invalidParamCount: 23
missingParam: 24 missingParam: 24
createError: 25

View File

@ -24,9 +24,11 @@ If an engine isn't installed for a particular platform, error out gracefully.
HtmlPdfCLIGenerator = module.exports = TemplateGenerator.extend HtmlPdfCLIGenerator = module.exports = TemplateGenerator.extend
init: () -> @_super 'pdf', 'html' init: () -> @_super 'pdf', 'html'
###* Generate the binary PDF. ### ###* Generate the binary PDF. ###
onBeforeSave: ( info ) -> onBeforeSave: ( info ) ->
safe_eng = info.opts.pdf || 'wkhtmltopdf'; safe_eng = info.opts.pdf || 'wkhtmltopdf';
@ -38,8 +40,14 @@ HtmlPdfCLIGenerator = module.exports = TemplateGenerator.extend
engines[ safe_eng ].call @, info.mk, info.outputFile, @onError engines[ safe_eng ].call @, info.mk, info.outputFile, @onError
return null # halt further processing 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) -> onError: (ex, param) ->
param.errHandler.err HMSTATUS.pdfGeneration, ex param.errHandler?.err? HMSTATUS.pdfGeneration, ex
return return

View File

@ -28,3 +28,4 @@ JsonYamlGenerator = module.exports = BaseGenerator.extend
generate: ( rez, f, opts ) -> generate: ( rez, f, opts ) ->
data = YAML.stringify JSON.parse( rez.stringify() ), Infinity, 2 data = YAML.stringify JSON.parse( rez.stringify() ), Infinity, 2
FS.writeFileSync f, data, 'utf8' FS.writeFileSync f, data, 'utf8'
data

View File

@ -16,40 +16,44 @@ Verb = require('../verbs/verb')
chalk = require('chalk') chalk = require('chalk')
###* An invokable resume analysis command. ###
AnalyzeVerb = module.exports = Verb.extend AnalyzeVerb = module.exports = Verb.extend
init: -> @_super 'analyze', analyze init: -> @_super 'analyze', _analyze
###* ###* Private workhorse for the 'analyze' command. ###
Run the 'analyze' command. _analyze = ( sources, dst, opts ) ->
###
analyze = ( sources, dst, opts ) ->
if !sources || !sources.length if !sources || !sources.length
throw @err HMSTATUS.resumeNotFound, { quit: true }
fluenterror: HMSTATUS.resumeNotFound return null
quit: true
nlzrs = _loadInspectors() nlzrs = _loadInspectors()
results = _.map sources, (src) ->
r = ResumeFactory.loadOne src, format: 'FRESH', objectify: true, @
return { } if opts.assert and @hasError()
_.each(sources, (src) -> if r.fluenterror
result = ResumeFactory.loadOne src, format: 'FRESH', objectify: true, @ r.quit = opts.assert
if result.fluenterror @err r.fluenterror, r
this.setError result.fluenterror, result r
else 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 a single resume. _analyzeOne = ( resumeObject, nlzrs, opts ) ->
###
_analyze = ( resumeObject, nlzrs, opts ) ->
rez = resumeObject.rez rez = resumeObject.rez
safeFormat = safeFormat =
if rez.meta and rez.meta.format and rez.meta.format.startsWith 'FRESH' 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 }) this.stat( HMEVENT.beforeAnalyze, { fmt: safeFormat, file: resumeObject.file })
info = _.mapObject nlzrs, (val, key) -> val.run rez info = _.mapObject nlzrs, (val, key) -> val.run rez
this.stat HMEVENT.afterAnalyze, { info: info } this.stat HMEVENT.afterAnalyze, { info: info }
info
###*
Load inspectors.
###
_loadInspectors = -> _loadInspectors = ->
totals: require '../inspectors/totals-inspector' totals: require '../inspectors/totals-inspector'
coverage: require '../inspectors/gap-inspector' coverage: require '../inspectors/gap-inspector'

View File

@ -6,25 +6,25 @@ Implementation of the 'build' verb for HackMyResume.
_ = require('underscore') _ = require 'underscore'
PATH = require('path') PATH = require 'path'
FS = require('fs') FS = require 'fs'
MD = require('marked') MD = require 'marked'
MKDIRP = require('mkdirp') MKDIRP = require 'mkdirp'
extend = require('extend') extend = require 'extend'
parsePath = require('parse-filepath') parsePath = require 'parse-filepath'
RConverter = require('fresh-jrs-converter') RConverter = require 'fresh-jrs-converter'
HMSTATUS = require('../core/status-codes') HMSTATUS = require '../core/status-codes'
HMEVENT = require('../core/event-codes') HMEVENT = require '../core/event-codes'
RTYPES = RTYPES =
FRESH: require('../core/fresh-resume') FRESH: require '../core/fresh-resume'
JRS: require('../core/jrs-resume') JRS: require '../core/jrs-resume'
_opts = require('../core/default-options') _opts = require '../core/default-options'
FRESHTheme = require('../core/fresh-theme') FRESHTheme = require '../core/fresh-theme'
JRSTheme = require('../core/jrs-theme') JRSTheme = require '../core/jrs-theme'
ResumeFactory = require('../core/resume-factory') ResumeFactory = require '../core/resume-factory'
_fmts = require('../core/default-formats') _fmts = require '../core/default-formats'
Verb = require('../verbs/verb') Verb = require '../verbs/verb'
_err = null _err = null
_log = null _log = null
@ -42,7 +42,7 @@ loadTheme = null
BuildVerb = module.exports = Verb.extend BuildVerb = module.exports = Verb.extend
###* Create a new build verb. ### ###* 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 dst An array of paths to the target resume file(s).
@param opts Generation options. @param opts Generation options.
### ###
build = ( src, dst, opts ) -> _build = ( src, dst, opts ) ->
if !src || !src.length if !src || !src.length
@err HMSTATUS.resumeNotFound, quit: true @err HMSTATUS.resumeNotFound, quit: true
return null return null
prep src, dst, opts _prep src, dst, opts
# Load input resumes as JSON... # Load input resumes as JSON...
sheetObjects = ResumeFactory.load(src, { sheetObjects = ResumeFactory.load src,
format: null, objectify: false, quit: true, inner: { sort: _opts.sort } format: null, objectify: false, quit: true, inner: { sort: _opts.sort }
}, @); , @
# Explicit check for any resume loading errors... # Explicit check for any resume loading errors...
problemSheets = _.filter( sheetObjects, (so) -> return so.fluenterror ) problemSheets = _.filter sheetObjects, (so) -> so.fluenterror
if( problemSheets && problemSheets.length ) if problemSheets and problemSheets.length
problemSheets[0].quit = true problemSheets[0].quit = true # can't go on
@err problemSheets[0].fluenterror, problemSheets[0] @err problemSheets[0].fluenterror, problemSheets[0]
return null return null
@ -80,27 +80,27 @@ build = ( src, dst, opts ) ->
theme = null theme = null
@stat HMEVENT.beforeTheme, { theme: _opts.theme } @stat HMEVENT.beforeTheme, { theme: _opts.theme }
try try
tFolder = verifyTheme.call @, _opts.theme tFolder = _verifyTheme.call @, _opts.theme
theme = _opts.themeObj = loadTheme tFolder theme = _opts.themeObj = _loadTheme tFolder
addFreebieFormats theme _addFreebieFormats theme
catch ex catch
newEx = newEx =
fluenterror: HMSTATUS.themeLoad fluenterror: HMSTATUS.themeLoad
inner: ex inner: _error
attempted: _opts.theme attempted: _opts.theme
quit: true quit: true
@err HMSTATUS.themeLoad, newEx @err HMSTATUS.themeLoad, newEx
return null return null
@stat HMEVENT.afterTheme, { theme: theme } @stat HMEVENT.afterTheme, theme: theme
# Check for invalid outputs... # Check for invalid outputs...
inv = verifyOutputs.call @, dst, theme inv = _verifyOutputs.call @, dst, theme
if inv && inv.length if inv && inv.length
@err HMSTATUS.invalidFormat, data: inv, theme: theme, quit: true @err HMSTATUS.invalidFormat, data: inv, theme: theme, quit: true
return null return null
## Merge input resumes, yielding a single source resume. ## Merge input resumes, yielding a single source resume...
rez = null rez = null
if sheets.length > 1 if sheets.length > 1
isFRESH = !sheets[0].basics isFRESH = !sheets[0].basics
@ -108,15 +108,13 @@ build = ( src, dst, opts ) ->
@stat HMEVENT.beforeMerge, { f: _.clone(sheetObjects), mixed: mixed } @stat HMEVENT.beforeMerge, { f: _.clone(sheetObjects), mixed: mixed }
if mixed if mixed
@err HMSTATUS.mixedMerge @err HMSTATUS.mixedMerge
rez = _.reduceRight sheets, ( a, b, idx ) -> rez = _.reduceRight sheets, ( a, b, idx ) ->
extend( true, b, a ) extend( true, b, a )
@stat HMEVENT.afterMerge, { r: rez } @stat HMEVENT.afterMerge, { r: rez }
else else
rez = sheets[0]; 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'; orgFormat = if rez.basics then 'JRS' else 'FRESH';
toFormat = if theme.render then 'JRS' else 'FRESH'; toFormat = if theme.render then 'JRS' else 'FRESH';
if toFormat != orgFormat if toFormat != orgFormat
@ -125,30 +123,41 @@ build = ( src, dst, opts ) ->
@stat HMEVENT.afterInlineConvert, { file: sheetObjects[0].file, fmt: toFormat } @stat HMEVENT.afterInlineConvert, { file: sheetObjects[0].file, fmt: toFormat }
# Announce the theme # 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 # Load the resume into a FRESHResume or JRSResume object
_rezObj = new (RTYPES[ toFormat ])().parseJSON( rez ); _rezObj = new (RTYPES[ toFormat ])().parseJSON( rez );
# Expand output resumes... # Expand output resumes...
targets = expand( dst, theme ); targets = _expand dst, theme
# Run the transformation! # Run the transformation!
_.each targets, (t) -> _.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 results =
sheet: _rezObj sheet: _rezObj
targets: targets targets: targets
processed: targets processed: targets
if @hasError() and !opts.assert
@reject results
else if !@hasError()
@resolve results
results
###* ###*
Prepare for a BUILD run. Prepare for a BUILD run.
### ###
prep = ( src, dst, opts ) -> _prep = ( src, dst, opts ) ->
# Cherry-pick options //_opts = extend( true, _opts, opts ); # Cherry-pick options //_opts = extend( true, _opts, opts );
_opts.theme = (opts.theme && opts.theme.toLowerCase().trim()) || 'modern'; _opts.theme = (opts.theme && opts.theme.toLowerCase().trim()) || 'modern';
@ -176,7 +185,7 @@ TODO: Refactor.
@param targInfo Information for the target resume. @param targInfo Information for the target resume.
@param theme A FRESHTheme or JRSTheme object. @param theme A FRESHTheme or JRSTheme object.
### ###
single = ( targInfo, theme, finished ) -> _single = ( targInfo, theme, finished ) ->
ret = null ret = null
ex = 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 # Otherwise this is an ad-hoc format (JSON, YML, or PNG) that every theme
# gets "for free". # gets "for free".
else else
theFormat = _fmts.filter( (fmt) -> theFormat = _fmts.filter( (fmt) ->
return fmt.name == targInfo.fmt.outFormat return fmt.name == targInfo.fmt.outFormat
)[0]; )[0];
outFolder = PATH.dirname f outFolder = PATH.dirname f
MKDIRP.sync( outFolder ); # Ensure dest folder exists; MKDIRP.sync outFolder # Ensure dest folder exists;
ret = theFormat.gen.generate( _rezObj, f, _opts ); ret = theFormat.gen.generate _rezObj, f, _opts
catch e catch e
# Catch any errors caused by generating this file and don't let them # 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
if ex.fluenterror if ex.fluenterror
this.err( ex.fluenterror, ex ); ret = ex
else else
this.err( HMSTATUS.generateError, { inner: ex } ); ret = fluenterror: HMSTATUS.generateError, inner: ex
ret
return ret
###* Ensure that user-specified outputs/targets are valid. ### ###* Ensure that user-specified outputs/targets are valid. ###
verifyOutputs = ( targets, theme ) -> _verifyOutputs = ( targets, theme ) ->
@stat HMEVENT.verifyOutputs, { targets: targets, theme: theme } @stat HMEVENT.verifyOutputs, { targets: targets, theme: theme }
_.reject targets.map( ( t ) -> _.reject targets.map( ( t ) ->
pathInfo = parsePath t pathInfo = parsePath t
@ -256,7 +265,7 @@ that declares an HTML format; the theme doesn't have to provide an explicit
PNG template. PNG template.
@param theTheme A FRESHTheme or JRSTheme object. @param theTheme A FRESHTheme or JRSTheme object.
### ###
addFreebieFormats = ( theTheme ) -> _addFreebieFormats = ( theTheme ) ->
# Add freebie formats (JSON, YAML, PNG) every theme gets... # Add freebie formats (JSON, YAML, PNG) every theme gets...
# Add HTML-driven PNG only if the theme has an HTML format. # Add HTML-driven PNG only if the theme has an HTML format.
theTheme.formats.json = theTheme.formats.json || { 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 dst An array of output files as specified by the user.
@param theTheme A FRESHTheme or JRSTheme object. @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 # 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. # 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. Verify the specified theme name/path.
### ###
verifyTheme = ( themeNameOrPath ) -> _verifyTheme = ( themeNameOrPath ) ->
tFolder = PATH.join( tFolder = PATH.join(
parsePath( require.resolve('fresh-themes') ).dirname, parsePath( require.resolve('fresh-themes') ).dirname,
'/themes/', '/themes/',
@ -328,7 +337,7 @@ verifyTheme = ( themeNameOrPath ) ->
Load the specified theme, which could be either a FRESH theme or a JSON Resume Load the specified theme, which could be either a FRESH theme or a JSON Resume
theme. theme.
### ###
loadTheme = ( tFolder ) -> _loadTheme = ( tFolder ) ->
# Create a FRESH or JRS theme object # Create a FRESH or JRS theme object
theTheme = theTheme =

View File

@ -17,39 +17,55 @@ HMEVENT = require('../core/event-codes');
ConvertVerb = module.exports = Verb.extend ConvertVerb = module.exports = Verb.extend
init: -> @_super 'convert', convert init: -> @_super 'convert', _convert
###* ###* Private workhorse method. Convert 0..N resumes between FRESH and JRS
Convert between FRESH and JRS formats. formats. ###
###
convert = ( srcs, dst, opts ) ->
# Housekeeping _convert = ( srcs, dst, opts ) ->
throw { fluenterror: 6, quit: true } if !srcs || !srcs.length
# Housekeeping...
if !srcs || !srcs.length
@err HMSTATUS.resumeNotFound, { quit: true }
return null
if !dst || !dst.length if !dst || !dst.length
if srcs.length == 1 if srcs.length == 1
throw { fluenterror: HMSTATUS.inputOutputParity, quit: true }; @err HMSTATUS.inputOutputParity, { quit: true }
else if srcs.length == 2 else if srcs.length == 2
dst = dst || []; dst.push( srcs.pop() ) dst = dst || []; dst.push( srcs.pop() )
else else
throw fluenterror: HMSTATUS.inputOutputParity, quit: true @err HMSTATUS.inputOutputParity, { quit: true }
if srcs && dst && srcs.length && dst.length && srcs.length != dst.length 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 # 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
, @
if @hasError() and !opts.assert
@reject results
else if !@hasError()
@resolve results
results
###* Private workhorse method. Convert a single resume. ###
_convertOne = (src, dst, idx) ->
# Load the resume # Load the resume
rinfo = ResumeFactory.loadOne src, rinfo = ResumeFactory.loadOne src, format: null, objectify: true
format: null, objectify: true, throw: false
# If a load error occurs, report it and move on to the next file (if any) # If a load error occurs, report it and move on to the next file (if any)
if rinfo.fluenterror if rinfo.fluenterror
this.err rinfo.fluenterror, rinfo return rinfo
return
s = rinfo.rez s = rinfo.rez
srcFmt = srcFmt =
@ -65,8 +81,4 @@ convert = ( srcs, dst, opts ) ->
# Save it to the destination format # Save it to the destination format
s.saveAs dst[idx], targetFormat s.saveAs dst[idx], targetFormat
return s
, @)
return

View File

@ -5,37 +5,64 @@ Implementation of the 'create' verb for HackMyResume.
### ###
MKDIRP = require('mkdirp')
PATH = require('path') MKDIRP = require 'mkdirp'
chalk = require('chalk') PATH = require 'path'
Verb = require('../verbs/verb') chalk = require 'chalk'
_ = require('underscore') Verb = require '../verbs/verb'
HMSTATUS = require('../core/status-codes') _ = require 'underscore'
HMEVENT = require('../core/event-codes') HMSTATUS = require '../core/status-codes'
HMEVENT = require '../core/event-codes'
CreateVerb = module.exports = Verb.extend 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 a new empty resume in either FRESH or JRS format. _create = ( src, dst, opts ) ->
###
create = ( src, dst, opts ) ->
if !src || !src.length 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() safeFmt = opts.format.toUpperCase()
@.stat HMEVENT.beforeCreate, { fmt: safeFmt, file: t } @.stat HMEVENT.beforeCreate, { fmt: safeFmt, file: t }
MKDIRP.sync PATH.dirname( t ) # Ensure dest folder exists; MKDIRP.sync PATH.dirname( t ) # Ensure dest folder exists;
RezClass = require '../core/' + safeFmt.toLowerCase() + '-resume' RezClass = require '../core/' + safeFmt.toLowerCase() + '-resume'
RezClass.default().save t newRez = RezClass.default()
@.stat( HMEVENT.afterCreate, { fmt: safeFmt, file: t } ) newRez.save t
, @) ret = newRez
return return
catch
ret =
fluenterror: HMSTATUS.createError
inner: _error
return
finally
@.stat HMEVENT.afterCreate, fmt: safeFmt, file: t, isError: ret.fluenterror
return ret

View File

@ -17,21 +17,38 @@ HMEVENT = require('../core/event-codes')
PeekVerb = module.exports = Verb.extend PeekVerb = module.exports = Verb.extend
init: -> @_super 'peek', peek init: -> @_super 'peek', _peek
###* Peek at a resume, resume section, or resume field. ### ###* Peek at a resume, resume section, or resume field. ###
peek = ( src, dst, opts ) -> _peek = ( src, dst, opts ) ->
if !src || !src.length if !src || !src.length
throw: fluenterror: HMSTATUS.resumeNotFound @err HMSTATUS.resumeNotFound, { quit: true }
return null
objPath = (dst && dst[0]) || '' objPath = (dst && dst[0]) || ''
_.each src, ( t ) -> 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
, @
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 ) ->
# Fire the 'beforePeek' event 2nd, so we have error/warning/success
@.stat HMEVENT.beforePeek, { file: t, target: objPath } @.stat HMEVENT.beforePeek, { file: t, target: objPath }
# Load the input file JSON 1st # Load the input file JSON 1st
@ -49,14 +66,11 @@ peek = ( src, dst, opts ) ->
target: tgt target: tgt
error: obj.ex error: obj.ex
# safeLoadJSON can only return a READ error or a PARSE error ## safeLoadJSON can only return a READ error or a PARSE error
if obj.ex if obj.ex
errCode = if obj.ex.operation == 'parse' then HMSTATUS.parseError else HMSTATUS.readError errCode = if obj.ex.operation == 'parse' then HMSTATUS.parseError else HMSTATUS.readError
if errCode == HMSTATUS.readError if errCode == HMSTATUS.readError
obj.ex.quiet = true obj.ex.quiet = true
@setError errCode, obj.ex return fluenterror: errCode, inner: obj.ex
@err errCode, obj.ex
, @ tgt
return

View File

@ -21,15 +21,16 @@ safeLoadJSON = require '../utils/safe-json-loader'
###* An invokable resume validation command. ### ###* An invokable resume validation command. ###
ValidateVerb = module.exports = Verb.extend 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 1 to N resumes in FRESH or JSON Resume format. ###
validate = (sources, unused, opts) -> _validate = (sources, unused, opts) ->
if !sources || !sources.length if !sources || !sources.length
throw { fluenterror: HMSTATUS.resumeNotFoundAlt, quit: true } @err HMSTATUS.resumeNotFoundAlt, { quit: true }
return null
validator = require 'is-my-json-valid' validator = require 'is-my-json-valid'
schemas = schemas =
@ -38,14 +39,35 @@ validate = (sources, unused, opts) ->
# Validate input resumes. Return a { file: <f>, isValid: <v>} object for # Validate input resumes. Return a { file: <f>, isValid: <v>} object for
# each resume valid, invalid, or broken. # each resume valid, invalid, or broken.
_.map sources, (t) -> 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 ret = file: t, isValid: false
# Load the input file JSON 1st # Load the input file JSON 1st
obj = safeLoadJSON t obj = safeLoadJSON t
if obj.ex
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. # Successfully read the resume. Now parse it as JSON.
json = obj.json json = obj.json
@ -62,14 +84,6 @@ validate = (sources, unused, opts) ->
catch catch
ret.ex = _error 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, @stat HMEVENT.afterValidate,
file: t file: t
isValid: ret.isValid isValid: ret.isValid
@ -77,8 +91,6 @@ validate = (sources, unused, opts) ->
errors: errors errors: errors
if opts.assert and !ret.isValid if opts.assert and !ret.isValid
throw fluenterror: HMSTATUS.invalid, shouldExit: true return fluenterror: HMSTATUS.invalid, errors: errors
ret ret
, @

View File

@ -10,6 +10,7 @@ Definition of the Verb class.
Class = require '../utils/class' Class = require '../utils/class'
EVENTS = require 'events' EVENTS = require 'events'
HMEVENT = require '../core/event-codes' HMEVENT = require '../core/event-codes'
Promise = require 'pinkie-promise'
@ -24,8 +25,8 @@ Verb = module.exports = Class.extend
###* Constructor. Automatically called at creation. ### ###* Constructor. Automatically called at creation. ###
init: ( moniker, workhorse ) -> init: ( moniker, workhorse ) ->
@moniker = moniker @moniker = moniker
@emitter = new EVENTS.EventEmitter()
@workhorse = workhorse @workhorse = workhorse
@emitter = new EVENTS.EventEmitter()
return return
@ -33,9 +34,11 @@ Verb = module.exports = Class.extend
###* Invoke the command. ### ###* Invoke the command. ###
invoke: -> invoke: ->
@stat HMEVENT.begin, cmd: @moniker @stat HMEVENT.begin, cmd: @moniker
ret = @workhorse.apply @, arguments argsArray = Array::slice.call arguments
@stat HMEVENT.end that = @
ret @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 = payload || { }
payload.sub = payload.fluenterror = errorCode payload.sub = payload.fluenterror = errorCode
payload.throw = hot payload.throw = hot
this.fire 'error', payload @setError errorCode, payload
if payload.quit
@reject payload
@fire 'error', payload
if hot if hot
throw payload throw payload
true true
@ -75,6 +81,10 @@ Verb = module.exports = Class.extend
hasError: -> @errorCode || @errorObj
###* Associate error info with the invocation. ### ###* Associate error info with the invocation. ###
setError: ( code, obj ) -> setError: ( code, obj ) ->
@errorCode = code @errorCode = code

View File

@ -14,7 +14,8 @@ var chai = require('chai')
, PATH = require('path') , PATH = require('path')
, PKG = require('../../package.json') , PKG = require('../../package.json')
, STRIPCOLOR = require('stripcolorcodes') , STRIPCOLOR = require('stripcolorcodes')
, _ = require('underscore'); , _ = require('underscore')
, EXEC = require('child_process').execSync
@ -40,34 +41,18 @@ function MyConsoleLog() {
describe('Testing CLI interface', function () { 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" // Run a test through the stub, gathering console.log output into "gather"
// and testing against it. // and testing against it.
function run( args, expErr ) { function run( args, expErr ) {
var title = args; var title = args;
it( 'Testing: "' + title + '"\n\n', function() { it( 'Testing: "' + title + '"\n\n', function() {
try {
EXEC('hackmyresume ' + args);
commandRetVal = 0; commandRetVal = 0;
HackMyResumeStub( args ); }
catch(ex) {
commandRetVal = ex.status;
}
commandRetVal.should.equal( parseInt(expErr, 10) ); commandRetVal.should.equal( parseInt(expErr, 10) );
}); });
} }

View File

@ -1,4 +1,4 @@
0| 4|
0|--help 0|--help
0|-h 0|-h
0|--debug 0|--debug