1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2024-07-02 16:30:04 +01: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 ANALYZE resume.json
hackmyresume NEW resume.json
hackmyresume CONVERT resume.json TO resume-jrs.json
hackmyresume ANALYZE resume.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 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.
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');
var FS = require('fs');
var ResumeConverter = require('./convert');
var chalk = require('chalk');
var SyntaxErrorEx = require('../utils/syntax-error-ex');
@ -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,41 +47,23 @@ 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: {
@ -87,32 +71,27 @@ Implementation of the 'validate' verb for HackMyResume.
}
});
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);
}
}());