1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2024-11-25 09:50:11 +00:00
This commit is contained in:
hacksalot 2016-01-10 14:53:22 -05:00
parent a4ee7127ee
commit 656dbe2fc2
8 changed files with 146 additions and 101 deletions

View File

@ -52,6 +52,10 @@ Output routines for HackMyResume.
chalk.green(' resume: ') + chalk.green.bold(evt.file));
break;
case HME.beforeRead:
this.log( chalk.cyan('Reading resume: ' + chalk.bold( evt.file )));
break;
case HME.afterTheme:
this.theme = evt.theme;
break;
@ -148,6 +152,23 @@ Output routines for HackMyResume.
chalk.green(' (' + evt.srcFmt + ') to ') + chalk.green.bold(evt.dstFile) +
chalk.green(' (' + evt.dstFmt + ').'));
break;
case HME.afterValidate:
var style = evt.isValid ? 'green' : 'yellow';
this.log( chalk.white('Validating ') + chalk.white.bold(evt.file) + chalk.white(' against ') +
chalk.white.bold( evt.fmt ).toUpperCase() +
chalk.white(' schema: ') + chalk[style].bold(evt.isValid ? 'VALID!' : 'INVALID'));
if( evt.errors ) {
_.each(evt.errors, function(err,idx) {
this.log( chalk.yellow.bold('--> ') +
chalk.yellow(err.field.replace('data.','resume.').toUpperCase() + ' ' +
err.message) );
}, this);
}
break;
}
}

View File

@ -2,26 +2,63 @@ Usage:
hackmyresume <COMMAND> <SOURCES> [TO <TARGETS>] [-t <THEME>] [-f <FORMAT>]
<COMMAND> should be BUILD, NEW, CONVERT, VALIDATE, ANALYZE or HELP. <SOURCES>
should be the path to one or more FRESH or JSON Resume format resumes. <TARGETS>
should be the name of the destination resume to be created, if any. The <THEME>
<COMMAND> should be BUILD, ANALYZE, NEW, CONVERT, or VALIDATE. <SOURCES> should
be the path to one or more FRESH or JSON Resume format resumes. <TARGETS> should
be the name of the destination resume to be created, if any. The <THEME>
parameter should be the name of a predefined theme (for example: COMPACT,
MINIMIST, MODERN, or HELLO-WORLD) or the relative path to a custom theme.
<FORMAT> should be either FRESH (for a FRESH-format resume) or JRS (for a JSON
Resume-format resume).
hackmyresume BUILD resume.json TO out/resume.all
hackmyresume NEW resume.json
hackmyresume CONVERT resume.json TO resume-jrs.json
hackmyresume ANALYZE resume.json
hackmyresume VALIDATE resume.json
hackmyresume BUILD resume.json TO out/resume.all
hackmyresume ANALYZE resume.json
hackmyresume NEW resume.json
hackmyresume CONVERT resume.json TO resume-jrs.json
hackmyresume VALIDATE resume.json
Both SOURCES and TARGETS can accept multiple files:
hackmyresume BUILD r1.json r2.json TO out/resume.all out2/resume.html
hackmyresume NEW r1.json r2.json r3.json
hackmyresume ANALYZE r1.json r2.json r3.json
hackmyresume VALIDATE resume.json resume2.json resume3.json
hackmyresume BUILD r1.json r2.json TO out/resume.all out2/resume.html
hackmyresume ANALYZE r1.json r2.json r3.json
hackmyresume NEW r1.json r2.json r3.json
hackmyresume CONVERT r1.json r2.json TO o1.json o2.json
hackmyresume VALIDATE r1.json r2.json r3.json
Available options:
--theme <theme> Specify a theme for the BUILD command. Can be the path
-t <theme> to any FRESH or JSON Resume theme, or the name of one
of HackMyResume's predefined themes.
--pdf <engine> Specify a PDF rendering engine. Can be "wkhtmltopdf",
-p <engine> "phantom", or "none". Requires that the corresponding
engine be installed and path-accessible.
--opts <path> Load HackMyResume options via an external file.
-o <path>
--color Enable/disable terminal colors.
--no-color
--tips Enable/disable theme tips and messages.
--no-tips
--debug Emit debug info.
-d
--help Display help documentation.
-h
--version Display the current HackMyResume version.
-v
See https://github.com/hacksalot/hackmyresume/blob/master/README.md for more
information.

View File

@ -156,6 +156,21 @@ Error-handling routines for HackMyResume.
" is inaccessible. PDF not generated." );
break;
case HACKMYSTATUS.readError:
msg = formatError( ex.inner.toString() );
break;
case HACKMYSTATUS.parseError:
if( SyntaxErrorEx.is( ex.inner )) {
var se = new SyntaxErrorEx( ex, ex.raw );
msg = formatError( 'Invalid or corrupt JSON on line ' + se.line +
' column ' + se.col );
}
else {
msg = formatError( ex.inner.toString() );
}
break;
}
return {
msg: msg,

View File

@ -40,7 +40,12 @@ Event code definitions.
afterAnalyze: 14,
beforeConvert: 15,
afterConvert: 16
afterConvert: 16,
verifyOutputs: 17,
beforeParse: 18,
afterParse: 19
};

View File

@ -10,11 +10,14 @@ Definition of the ResumeFactory class.
require('string.prototype.startswith');
var FS = require('fs');
var ResumeConverter = require('./convert');
var chalk = require('chalk');
var SyntaxErrorEx = require('../utils/syntax-error-ex');
var FS = require('fs'),
HACKMYSTATUS = require('./status-codes'),
HME = require('./event-codes'),
ResumeConverter = require('./convert'),
chalk = require('chalk'),
SyntaxErrorEx = require('../utils/syntax-error-ex'),
_ = require('underscore');
require('string.prototype.startswith');
@ -29,14 +32,11 @@ Definition of the ResumeFactory class.
/**
Load one or more resumes from disk.
*/
load: function ( sources, opts ) {
load: function ( sources, opts, emitter ) {
// Loop over all inputs, parsing each to JSON and then to a FRESHResume
// or JRSResume object.
var that = this;
return sources.map( function( src ) {
return that.loadOne( src, opts );
});
return this.loadOne( src, opts, emitter );
}, this);
},
@ -45,9 +45,8 @@ Definition of the ResumeFactory class.
/**
Load a single resume from disk.
*/
loadOne: function( src, opts ) {
loadOne: function( src, opts, emitter ) {
var log = opts.log;
var toFormat = opts.format;
var objectify = opts.objectify;
@ -55,7 +54,7 @@ Definition of the ResumeFactory class.
toFormat && (toFormat = toFormat.toLowerCase().trim());
// Load and parse the resume JSON
var info = _parse( src, opts );
var info = _parse( src, opts, emitter );
if( info.error ) return info;
// Determine the resume format: FRESH or JRS
@ -88,44 +87,28 @@ Definition of the ResumeFactory class.
function _parse( fileName, opts ) {
function _parse( fileName, opts, eve ) {
var rawData;
try {
// TODO: Core should not log
opts.log( chalk.cyan('Reading resume: ') + chalk.cyan.bold(fileName) );
// Read the file
eve && eve.stat( HME.beforeRead, { file: fileName });
rawData = FS.readFileSync( fileName, 'utf8' );
// Parse it to JSON
return {
eve && eve.stat( HME.afterRead, { data: rawData });
eve && eve.stat( HME.beforeParse, { data: rawData });
var ret = {
json: JSON.parse( rawData )
};
eve && eve.stat( HME.afterParse, { data: ret.json } );
return ret;
}
catch( ex ) {
// JSON.parse failed due to invalid JSON
if ( !opts.muffle && ex instanceof SyntaxError) {
var info = new SyntaxErrorEx( ex, rawData );
opts.log( chalk.red.bold(fileName.toUpperCase() + ' contains invalid JSON on line ' +
info.line + ' column ' + info.col + '.' +
chalk.red(' Unable to validate.')));
opts.log( chalk.red.bold('INTERNAL: ' + ex) );
ex.handled = true;
}
// FS.readFileSync failed
if( !rawData || opts.throw ) throw ex;
return {
error: ex,
raw: rawData,
file: fileName
throw {
fluenterror: rawData ? HACKMYSTATUS.parseError : HACKMYSTATUS.readError,
inner: ex, raw: rawData, file: fileName, shouldExit: false
};
}
}

View File

@ -20,7 +20,9 @@ Status codes for HackMyResume.
missingPackageJSON: 10,
invalid: 11,
invalidFormat: 12,
notOnPath: 13
notOnPath: 13,
readError: 14,
parseError: 15
};
}());

View File

@ -31,6 +31,7 @@ Implementation of the 'generate' verb for HackMyResume.
, _err, _log, rez;
var BuildVerb = module.exports = Verb.extend({
init: function() {
@ -64,7 +65,7 @@ Implementation of the 'generate' verb for HackMyResume.
this.stat( HME.afterTheme, { theme: theme });
// Check for invalid outputs
var inv = verifyOutputs( dst, theme );
var inv = verifyOutputs.call( this, dst, theme );
if( inv && inv.length ) {
throw {fluenterror: HACKMYSTATUS.invalidFormat, data: inv, theme: theme};
}
@ -181,6 +182,8 @@ Implementation of the 'generate' verb for HackMyResume.
*/
function verifyOutputs( targets, theme ) {
this.stat(HME.verifyOutputs, { targets: targets, theme: theme });
return _.reject(
targets.map( function( t ) {
var pathInfo = parsePath( t );

View File

@ -12,6 +12,8 @@ Implementation of the 'validate' verb for HackMyResume.
var chalk = require('chalk');
var Verb = require('../core/verb');
var HACKMYSTATUS = require('../core/status-codes');
var HME = require('../core/event-codes');
var _ = require('underscore');
@ -45,74 +47,51 @@ Implementation of the 'validate' verb for HackMyResume.
var resumes = ResumeFactory.load( sources, {
format: null,
objectify: false,
throw: false,
muffle: true
});
objectify: false
}, this );
// Load input resumes...
resumes.forEach(function( src ) {
// Validate input resumes. Return a { file: <f>, isValid: <v>} object for
// each resume (valid, invalid, or broken).
return resumes.map( function( src ) {
var ret = { file: src, isValid: false };
// If there was an error reading the resume
if( src.error ) {
// TODO: Core should not log
_log( chalk.white('Validating ') + chalk.gray.bold(src.file) +
chalk.white(' against ') + chalk.gray.bold('AUTO') +
chalk.white(' schema:') + chalk.red.bold(' BROKEN') );
var ex = src.error; // alias
if ( ex instanceof SyntaxError) {
var info = new SyntaxErrorEx( ex, src.raw );
_log( chalk.red.bold('--> ' + src.file.toUpperCase() + ' contains invalid JSON on line ' +
info.line + ' column ' + info.col + '.' +
chalk.red(' Unable to validate.') ) );
_log( chalk.red.bold(' INTERNAL: ' + ex) );
}
else {
_log(chalk.red.bold('ERROR: ' + ex.toString()));
}
if( opts.assert ) throw { fluenterror: HACKMYSTATUS.invalid };
return;
return ret;
}
var json = src.json;
var isValid = false;
var style = 'green';
var errors = [];
var fmt = json.basics ? 'jrs' : 'fresh';
// Successfully read the resume. Now parse it as JSON.
var json = src.json, fmt = json.basics ? 'jrs' : 'fresh', errors = [];
try {
var validate = validator( schemas[ fmt ], { // Note [1]
formats: {
date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/
date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/
}
});
isValid = validate( json );
if( !isValid ) {
style = 'yellow';
ret.isValid = validate( json );
if( !ret.isValid ) {
errors = validate.errors;
}
}
catch(exc) {
return;
return ret;
}
_log( chalk.white('Validating ') + chalk.white.bold(src.file) + chalk.white(' against ') +
chalk.white.bold(fmt.replace('jars','JSON Resume').toUpperCase()) +
chalk.white(' schema: ') + chalk[style].bold(isValid ? 'VALID!' : 'INVALID') );
errors.forEach(function(err,idx) {
_log( chalk.yellow.bold('--> ') +
chalk.yellow(err.field.replace('data.','resume.').toUpperCase() + ' ' +
err.message) );
});
this.stat(HME.afterValidate, { file: src.file, isValid: isValid,
fmt: fmt.replace('jars', 'JSON Resume'), errors: errors });
if( opts.assert && !isValid ) {
throw { fluenterror: HACKMYSTATUS.invalid, shouldExit: true };
}
});
return ret;
}, this);
}
}());