mirror of
https://github.com/JuanCanham/HackMyResume.git
synced 2024-11-05 01:56:21 +00:00
Gather.
This commit is contained in:
parent
19b30d55ec
commit
7af50c51f6
34
README.md
34
README.md
@ -279,6 +279,36 @@ hackmyresume BUILD me.json TO out/resume.all
|
|||||||
`out/resume.doc`, `out/resume.html`, `out/resume.txt`, `out/resume.pdf`, and
|
`out/resume.doc`, `out/resume.html`, `out/resume.txt`, `out/resume.pdf`, and
|
||||||
`out/resume.json`.
|
`out/resume.json`.
|
||||||
|
|
||||||
|
### Building PDFs
|
||||||
|
|
||||||
|
HackMyResume takes a unique approach to PDF generation. Instead of enforcing
|
||||||
|
a specific PDF engine on users, HackMyResume will attempt to work with whatever
|
||||||
|
PDF engine you have installed through the engine's command-line interface (CLI).
|
||||||
|
Currently that means one or both of...
|
||||||
|
|
||||||
|
- [wkhtmltopdf][3]
|
||||||
|
- [Phantom.js][3]
|
||||||
|
|
||||||
|
..with support for other engines planned in the future. **One or both of these
|
||||||
|
engines must be installed and accessible on your PATH in order to generate PDF
|
||||||
|
resumes with HackMyResume**. That means you should be able to invoke either of
|
||||||
|
these tools directly from your shell or terminal without error:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
wkhtmltopdf input.html output.pdf
|
||||||
|
phantomjs script.js input.html output.pdf
|
||||||
|
```
|
||||||
|
|
||||||
|
Assuming you've installed one or both of these engines on your system, you can
|
||||||
|
tell HackMyResume which flavor of PDF generation to use via the `--pdf` option
|
||||||
|
(`-p` for short):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
hackmyresume BUILD resume.json TO out.all --pdf phantom
|
||||||
|
hackmyresume BUILD resume.json TO out.all --pdf wkhtmltopdf
|
||||||
|
hackmyresume BUILD resume.json TO out.all --pdf none
|
||||||
|
```
|
||||||
|
|
||||||
### Analyzing
|
### Analyzing
|
||||||
|
|
||||||
HackMyResume can analyze your resume for keywords, employment gaps, and other
|
HackMyResume can analyze your resume for keywords, employment gaps, and other
|
||||||
@ -292,7 +322,7 @@ Depending on the HackMyResume version, you should see output similar to:
|
|||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
*** HackMyResume v1.4.1 ***
|
*** HackMyResume v1.6.0 ***
|
||||||
Reading resume: resume.json
|
Reading resume: resume.json
|
||||||
Analyzing FRESH resume: resume.json
|
Analyzing FRESH resume: resume.json
|
||||||
|
|
||||||
@ -388,7 +418,7 @@ hackmyresume VALIDATE resumeA.json resumeB.json
|
|||||||
HackMyResume will validate each specified resume in turn:
|
HackMyResume will validate each specified resume in turn:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
*** HackMyResume v0.9.0 ***
|
*** HackMyResume v1.6.0 ***
|
||||||
Validating JSON resume: resumeA.json (INVALID)
|
Validating JSON resume: resumeA.json (INVALID)
|
||||||
Validating JSON resume: resumeB.json (VALID)
|
Validating JSON resume: resumeB.json (VALID)
|
||||||
```
|
```
|
||||||
|
@ -18,89 +18,90 @@ Error-handling routines for HackMyResume.
|
|||||||
, WRAP = require('word-wrap')
|
, WRAP = require('word-wrap')
|
||||||
, chalk = require('chalk')
|
, chalk = require('chalk')
|
||||||
, SyntaxErrorEx = require('../utils/syntax-error-ex');
|
, SyntaxErrorEx = require('../utils/syntax-error-ex');
|
||||||
|
require('string.prototype.startswith');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
An amorphous blob of error handling code for HackMyResume.
|
Error handler for HackMyResume. All errors are handled here.
|
||||||
@class ErrorHandler
|
@class ErrorHandler
|
||||||
*/
|
*/
|
||||||
var ErrorHandler = module.exports = {
|
var ErrorHandler = module.exports = {
|
||||||
|
|
||||||
init: function( debug ) {
|
init: function( debug ) {
|
||||||
this.debug = debug;
|
this.debug = debug;
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
err: function( ex, shouldExit ) {
|
err: function( ex, shouldExit ) {
|
||||||
|
|
||||||
var msg = '', exitCode, log = console.log, showStack = ex.showStack;
|
if( ex.fluenterror ) {
|
||||||
|
|
||||||
// If the exception has been handled elsewhere and shouldExit is true,
|
var objError = assembleError( ex );
|
||||||
// let's get out of here, otherwise silently return.
|
o( this[ 'format' + (objError.warning ? 'Warning' : 'Error')]( objError.msg ) );
|
||||||
if( ex.handled ) {
|
|
||||||
if( shouldExit )
|
|
||||||
process.exit( exitCode );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get an error message -- either a HackMyResume error message or the
|
if( objError.showStack )
|
||||||
// exception's associated error message
|
o( chalk.red( ex.stack || ex.inner.stack ) );
|
||||||
if( ex.fluenterror ){
|
|
||||||
var errInfo = get_error_msg( ex );
|
if( objError.quit ) {
|
||||||
msg = errInfo.msg;
|
this.debug && o(
|
||||||
exitCode = ex.fluenterror;
|
chalk.cyan('Exiting with error code ' + ex.fluenterror.toString()));
|
||||||
showStack = errInfo.showStack;
|
process.exit( ex.fluenterror );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
msg = ex.toString();
|
o( ex );
|
||||||
exitCode = -1;
|
var stackTrace = ex.stack || (ex.inner && ex.inner.stack)
|
||||||
// Deal with pesky 'Error:' prefix.
|
if( stackTrace && this.debug )
|
||||||
var idx = msg.indexOf('Error: ');
|
o( ex.stack || ex.inner.stack );
|
||||||
msg = idx === -1 ? msg : msg.substring( idx + 7 );
|
|
||||||
|
// if( this.debug )
|
||||||
|
// o( ex.stack || ex.inner.stack );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log non-HackMyResume-handled errors in red with ERROR prefix. Log HMR
|
},
|
||||||
// errors as-is.
|
|
||||||
ex.fluenterror ?
|
|
||||||
log( msg.toString() ) :
|
|
||||||
log( chalk.red.bold('ERROR: ' + msg.toString()) );
|
|
||||||
|
|
||||||
// Selectively show the stack trace
|
formatError: function( msg ) {
|
||||||
if( (ex.stack || (ex.inner && ex.inner.stack)) &&
|
return chalk.red.bold(
|
||||||
((showStack && ex.code !== 'ENOENT' ) || (this.debug) ))
|
msg.toUpperCase().startsWith('ERROR:') ? msg : 'Error: ' + msg );
|
||||||
log( chalk.red( ex.stack || ex.inner.stack ) );
|
},
|
||||||
|
|
||||||
// Let the error code be the process's return code.
|
formatWarning: function( brief, msg ) {
|
||||||
( shouldExit || ex.shouldExit ) && process.exit( exitCode );
|
return chalk.yellow(brief) + chalk.yellow(msg || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var o = function() {
|
||||||
|
console.log.apply( console.log, arguments );
|
||||||
|
};
|
||||||
|
|
||||||
function get_error_msg( ex ) {
|
function assembleError( ex ) {
|
||||||
|
|
||||||
|
var msg = '', withStack = false, isError = false, quit = true, warn = true;
|
||||||
|
|
||||||
var msg = '', withStack = false, isError = false;
|
|
||||||
switch( ex.fluenterror ) {
|
switch( ex.fluenterror ) {
|
||||||
|
|
||||||
case HACKMYSTATUS.themeNotFound:
|
case HACKMYSTATUS.themeNotFound:
|
||||||
msg = formatWarning(
|
msg =
|
||||||
chalk.bold("Couldn't find the '" + ex.data + "' theme."),
|
chalk.bold("Couldn't find the '" + ex.data + "' theme."),
|
||||||
" Please specify the name of a preinstalled FRESH theme " +
|
" Please specify the name of a preinstalled FRESH theme " +
|
||||||
"or the path to a locally installed FRESH or JSON Resume theme.");
|
"or the path to a locally installed FRESH or JSON Resume theme.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.copyCSS:
|
case HACKMYSTATUS.copyCSS:
|
||||||
msg = formatWarning("Couldn't copy CSS file to destination folder.");
|
msg = "Couldn't copy CSS file to destination folder.";
|
||||||
|
quit = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.resumeNotFound:
|
case HACKMYSTATUS.resumeNotFound:
|
||||||
msg = formatWarning('Please ' + chalk.bold('feed me a resume') +
|
msg = 'Please ' + chalk.bold('feed me a resume') +
|
||||||
' in FRESH or JSON Resume format.');
|
' in FRESH or JSON Resume format.';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.missingCommand:
|
case HACKMYSTATUS.missingCommand:
|
||||||
msg = formatWarning("Please " +chalk.bold("give me a command") + " (");
|
msg = "Please " +chalk.bold("give me a command") + " (";
|
||||||
|
|
||||||
msg += Object.keys( FCMD.verbs ).map( function(v, idx, ar) {
|
msg += Object.keys( FCMD.verbs ).map( function(v, idx, ar) {
|
||||||
return (idx === ar.length - 1 ? chalk.yellow('or ') : '') +
|
return (idx === ar.length - 1 ? chalk.yellow('or ') : '') +
|
||||||
@ -112,79 +113,81 @@ Error-handling routines for HackMyResume.
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.invalidCommand:
|
case HACKMYSTATUS.invalidCommand:
|
||||||
msg = formatWarning('Invalid command: "'+chalk.bold(ex.attempted)+'"');
|
msg = 'Invalid command: "'+chalk.bold(ex.attempted)+'"';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.resumeNotFoundAlt:
|
case HACKMYSTATUS.resumeNotFoundAlt:
|
||||||
msg = formatWarning('Please ' + chalk.bold('feed me a resume') +
|
msg = 'Please ' + chalk.bold('feed me a resume') +
|
||||||
' in either FRESH or JSON Resume format.');
|
' in either FRESH or JSON Resume format.';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.inputOutputParity:
|
case HACKMYSTATUS.inputOutputParity:
|
||||||
msg = formatWarning('Please ' +
|
msg = 'Please ' +
|
||||||
chalk.bold('specify an output file name') +
|
chalk.bold('specify an output file name') +
|
||||||
' for every input file you wish to convert.');
|
' for every input file you wish to convert.';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.createNameMissing:
|
case HACKMYSTATUS.createNameMissing:
|
||||||
msg = formatWarning('Please ' +
|
msg = 'Please ' +
|
||||||
chalk.bold('specify the filename of the resume') + ' to create.');
|
chalk.bold('specify the filename of the resume') + ' to create.';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.pdfGeneration:
|
case HACKMYSTATUS.pdfGeneration:
|
||||||
msg = formatError(chalk.bold('ERROR: PDF generation failed. ') +
|
msg = chalk.bold('PDF generation failed. ') +
|
||||||
'Make sure wkhtmltopdf is installed and accessible from your path.');
|
'Make sure wkhtmltopdf is installed and accessible from your path.';
|
||||||
if( ex.inner ) msg += chalk.red('\n' + ex.inner);
|
if( ex.inner ) msg += chalk.red('\n' + ex.inner);
|
||||||
withStack = true;
|
withStack = true; quit = false; warn = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.invalid:
|
case HACKMYSTATUS.invalid:
|
||||||
msg = formatError('Validation failed and the --assert option was ' +
|
msg = 'Validation failed and the --assert option was ' +
|
||||||
'specified.');
|
'specified.';
|
||||||
|
warn = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.invalidFormat:
|
case HACKMYSTATUS.invalidFormat:
|
||||||
ex.data.forEach(function(d){ msg +=
|
ex.data.forEach(function(d){ msg +=
|
||||||
formatWarning('The ' + chalk.bold(ex.theme.name.toUpperCase()) +
|
'The ' + chalk.bold(ex.theme.name.toUpperCase()) +
|
||||||
" theme doesn't support the " + chalk.bold(d.format.toUpperCase()) +
|
" theme doesn't support the " + chalk.bold(d.format.toUpperCase()) +
|
||||||
" format.\n");
|
" format.\n";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.notOnPath:
|
case HACKMYSTATUS.notOnPath:
|
||||||
msg = formatError( ex.engine + " wasn't found on your system path or" +
|
msg = ex.engine + " wasn't found on your system path or" +
|
||||||
" is inaccessible. PDF not generated." );
|
" is inaccessible. PDF not generated.";
|
||||||
|
quit = false;
|
||||||
|
warn = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.readError:
|
case HACKMYSTATUS.readError:
|
||||||
msg = formatError( ex.inner.toString() );
|
msg = ex.inner.toString();
|
||||||
|
warn = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HACKMYSTATUS.parseError:
|
case HACKMYSTATUS.parseError:
|
||||||
if( SyntaxErrorEx.is( ex.inner )) {
|
if( SyntaxErrorEx.is( ex.inner )) {
|
||||||
var se = new SyntaxErrorEx( ex, ex.raw );
|
var se = new SyntaxErrorEx( ex, ex.raw );
|
||||||
msg = formatError( 'Invalid or corrupt JSON on line ' + se.line +
|
msg = 'Invalid or corrupt JSON on line ' + se.line +
|
||||||
' column ' + se.col );
|
' column ' + se.col + '.';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
msg = formatError( ex.inner.toString() );
|
msg = formatError( ex.inner.toString() );
|
||||||
}
|
}
|
||||||
|
warn = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
msg: msg,
|
warning: warn, // True if this is a warning, false if error
|
||||||
withStack: withStack
|
msg: msg, // The error message to display
|
||||||
|
withStack: withStack, // Whether to include the stack
|
||||||
|
quit: quit
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatError( msg ) {
|
|
||||||
return chalk.red.bold( 'ERROR: ' + msg );
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatWarning( brief, msg ) {
|
|
||||||
return chalk.yellow(brief) + chalk.yellow(msg || '');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}());
|
}());
|
||||||
|
@ -19,8 +19,6 @@ Definition of the `main` function.
|
|||||||
, HACKMYSTATUS = require('../core/status-codes')
|
, HACKMYSTATUS = require('../core/status-codes')
|
||||||
, HME = require('../core/event-codes')
|
, HME = require('../core/event-codes')
|
||||||
, safeLoadJSON = require('../utils/safe-json-loader')
|
, safeLoadJSON = require('../utils/safe-json-loader')
|
||||||
, _opts = { }
|
|
||||||
, title = chalk.white.bold('\n*** HackMyResume v' + PKG.version + ' ***')
|
|
||||||
, StringUtils = require('../utils/string.js')
|
, StringUtils = require('../utils/string.js')
|
||||||
, _ = require('underscore')
|
, _ = require('underscore')
|
||||||
, OUTPUT = require('./out')
|
, OUTPUT = require('./out')
|
||||||
@ -28,6 +26,10 @@ Definition of the `main` function.
|
|||||||
, PAD = require('string-padding')
|
, PAD = require('string-padding')
|
||||||
, Command = require('commander').Command;
|
, Command = require('commander').Command;
|
||||||
|
|
||||||
|
var _opts = { };
|
||||||
|
var _title = chalk.white.bold('\n*** HackMyResume v' +PKG.version+ ' ***');
|
||||||
|
var _out = new OUTPUT( _opts );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,9 +122,19 @@ Definition of the `main` function.
|
|||||||
*/
|
*/
|
||||||
function initialize( ar ) {
|
function initialize( ar ) {
|
||||||
|
|
||||||
logMsg( title );
|
logMsg( _title );
|
||||||
|
|
||||||
var o = initOptions( ar );
|
var o = initOptions( ar );
|
||||||
|
if( o.debug ) {
|
||||||
|
_out.log(chalk.cyan('The -d or --debug switch was specified. DEBUG mode engaged.'));
|
||||||
|
_out.log('');
|
||||||
|
_out.log(chalk.cyan(PAD(' Platform:',20, null, PAD.RIGHT)) + chalk.cyan.bold( process.platform ));
|
||||||
|
_out.log(chalk.cyan(PAD(' Node.js:',20, null, PAD.RIGHT)) + chalk.cyan.bold( process.version ));
|
||||||
|
_out.log(chalk.cyan(PAD(' HackMyResume:',20, null, PAD.RIGHT)) + chalk.cyan.bold('v' + PKG.version ));
|
||||||
|
_out.log(chalk.cyan(PAD(' FRESCA:',20, null, PAD.RIGHT)) + chalk.cyan.bold( PKG.dependencies.fresca ));
|
||||||
|
_out.log(chalk.cyan(PAD(' fresh-themes:',20, null, PAD.RIGHT)) + chalk.cyan.bold( PKG.dependencies['fresh-themes'] ));
|
||||||
|
_out.log('');
|
||||||
|
}
|
||||||
|
|
||||||
// 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 ] ) {
|
||||||
@ -150,6 +162,10 @@ Definition of the `main` function.
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Init options prior to setting up command infrastructure.
|
||||||
|
*/
|
||||||
function initOptions( ar ) {
|
function initOptions( ar ) {
|
||||||
var oVerb, verb = '', args = ar.slice(), cleanArgs = args.slice(2), oJSON;
|
var oVerb, verb = '', args = ar.slice(), cleanArgs = args.slice(2), oJSON;
|
||||||
if( cleanArgs.length ) {
|
if( cleanArgs.length ) {
|
||||||
@ -179,7 +195,13 @@ Definition of the `main` function.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grab the --debug flag
|
||||||
|
var isDebug = _.some( args, function(v) {
|
||||||
|
return v === '-d' || v === '--debug';
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
debug: isDebug,
|
||||||
orgVerb: oVerb,
|
orgVerb: oVerb,
|
||||||
verb: verb,
|
verb: verb,
|
||||||
json: oJSON,
|
json: oJSON,
|
||||||
@ -194,10 +216,11 @@ Definition of the `main` function.
|
|||||||
function execute( src, dst, opts, log ) {
|
function execute( src, dst, opts, log ) {
|
||||||
|
|
||||||
loadOptions.call( this, opts, this.parent.jsonArgs );
|
loadOptions.call( this, opts, this.parent.jsonArgs );
|
||||||
require( './error-handler' ).init( _opts.debug );
|
var hand = require( './error-handler' ).init( _opts.debug );
|
||||||
var out = new OUTPUT( _opts );
|
|
||||||
var v = new HMR.verbs[ this.name() ]();
|
var v = new HMR.verbs[ this.name() ]();
|
||||||
v.on( 'hmr:status', function() { out.do.apply( out, arguments ); });
|
_out.init( _opts );
|
||||||
|
v.on( 'hmr:status', function() { _out.do.apply( _out, arguments ); });
|
||||||
|
v.on( 'hmr:error', function() { hand.err.apply( hand, arguments ); });
|
||||||
v.invoke.call( v, src, dst, _opts, log );
|
v.invoke.call( v, src, dst, _opts, log );
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -228,14 +251,15 @@ Definition of the `main` function.
|
|||||||
o.debug = this.parent.debug;
|
o.debug = this.parent.debug;
|
||||||
|
|
||||||
if( o.debug ) {
|
if( o.debug ) {
|
||||||
logMsg(chalk.cyan('Merged options: '));
|
logMsg(chalk.cyan('OPTIONS:') + '\n');
|
||||||
_.each(o, function(val, key) {
|
_.each(o, function(val, key) {
|
||||||
logMsg(chalk.cyan('%s: %s'), PAD(key,10), val);
|
logMsg(chalk.cyan(' %s') + chalk.cyan.bold(' %s'), PAD(key,17,null,PAD.RIGHT), val);
|
||||||
});
|
});
|
||||||
|
logMsg('');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache
|
// Cache
|
||||||
_opts = o;
|
EXTEND(true, _opts, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,50 +14,71 @@ Output routines for HackMyResume.
|
|||||||
, HME = require('../core/event-codes')
|
, HME = require('../core/event-codes')
|
||||||
, _ = require('underscore')
|
, _ = require('underscore')
|
||||||
, Class = require('../utils/class.js')
|
, Class = require('../utils/class.js')
|
||||||
|
, M2C = require('../utils/md2chalk.js')
|
||||||
, PATH = require('path')
|
, PATH = require('path')
|
||||||
, LO = require('lodash')
|
, LO = require('lodash')
|
||||||
, FS = require('fs')
|
, FS = require('fs')
|
||||||
|
, EXTEND = require('../utils/extend')
|
||||||
, HANDLEBARS = require('handlebars')
|
, HANDLEBARS = require('handlebars')
|
||||||
, pad = require('string-padding');
|
, pad = require('string-padding');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A stateful output handler. All HMR console output handled here.
|
A stateful output module. All HMR console output handled here.
|
||||||
*/
|
*/
|
||||||
var OutputHandler = module.exports = Class.extend({
|
var OutputHandler = module.exports = Class.extend({
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
init: function( opts ) {
|
init: function( opts ) {
|
||||||
this.opts = opts;
|
this.opts = EXTEND( true, this.opts || { }, opts );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
log: function( msg ) {
|
log: function( msg ) {
|
||||||
msg = msg || '';
|
msg = msg || '';
|
||||||
this.opts.silent || console.log( msg );
|
this.opts.silent || console.log.apply( console.log, arguments );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
do: function( evt ) {
|
do: function( evt ) {
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
function L() {
|
||||||
|
that.log.apply( that, arguments );
|
||||||
|
}
|
||||||
|
|
||||||
switch( evt.sub ) {
|
switch( evt.sub ) {
|
||||||
|
|
||||||
|
case HME.error:
|
||||||
|
//L('ERROR occured');
|
||||||
|
break;
|
||||||
|
|
||||||
case HME.beforeCreate:
|
case HME.beforeCreate:
|
||||||
this.log( chalk.green('Creating new ') +
|
L(
|
||||||
chalk.green.bold(evt.fmt) +
|
M2C('Creating new **%s** resume: **%s**', 'green'),
|
||||||
chalk.green(' resume: ') + chalk.green.bold(evt.file));
|
evt.fmt, evt.file
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HME.beforeRead:
|
case HME.beforeRead:
|
||||||
this.log( chalk.cyan('Reading resume: ' + chalk.bold( evt.file )));
|
L(
|
||||||
|
M2C('Reading resume: **%s**', 'cyan'), evt.file
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HME.beforeTheme:
|
||||||
|
this.opts.debug && L(
|
||||||
|
M2C('Verifying theme: **%s**', 'cyan'), evt.theme.toUpperCase()
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HME.afterTheme:
|
case HME.afterTheme:
|
||||||
this.theme = evt.theme;
|
this.theme = evt.theme;
|
||||||
|
this.opts.debug && L( M2C('Verifying outputs: ???', 'cyan') );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HME.beforeMerge:
|
case HME.beforeMerge:
|
||||||
@ -66,15 +87,14 @@ Output routines for HackMyResume.
|
|||||||
msg += ((idx === 0) ? chalk.cyan('Merging ') :
|
msg += ((idx === 0) ? chalk.cyan('Merging ') :
|
||||||
chalk.cyan(' onto ')) + chalk.cyan.bold(a.i().file);
|
chalk.cyan(' onto ')) + chalk.cyan.bold(a.i().file);
|
||||||
});
|
});
|
||||||
this.log( msg );
|
L( msg );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HME.afterMerge:
|
case HME.afterMerge:
|
||||||
var numFormats = Object.keys(this.theme.formats).length;
|
var numFormats = Object.keys( this.theme.formats ).length;
|
||||||
this.log( chalk.yellow('Applying ') +
|
L( M2C('Applying **%s** theme (%s format%s)', 'yellow'),
|
||||||
chalk.yellow.bold( this.theme.name.toUpperCase() ) +
|
this.theme.name.toUpperCase(),
|
||||||
chalk.yellow(' theme (' + numFormats + ' format' +
|
numFormats, ( numFormats === 1 ? '' : 's') );
|
||||||
( evt.numFormats === 1 ? ')' : 's)') ));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HME.end:
|
case HME.end:
|
||||||
@ -83,23 +103,21 @@ Output routines for HackMyResume.
|
|||||||
if( this.opts.tips && (this.theme.message || this.theme.render) ) {
|
if( this.opts.tips && (this.theme.message || this.theme.render) ) {
|
||||||
var WRAP = require('word-wrap');
|
var WRAP = require('word-wrap');
|
||||||
if( this.theme.message ) {
|
if( this.theme.message ) {
|
||||||
this.log( WRAP( chalk.gray('The ' + themeName + ' theme says: "') +
|
L( WRAP( chalk.gray('The ' + themeName + ' theme says: "') +
|
||||||
chalk.white(this.theme.message) + chalk.gray('"'),
|
chalk.white(this.theme.message) + chalk.gray('"'),
|
||||||
{ width: this.opts.wrap, indent: '' } ));
|
{ width: this.opts.wrap, indent: '' } ));
|
||||||
}
|
}
|
||||||
else if ( this.theme.render ) {
|
else if ( this.theme.render ) {
|
||||||
this.log( WRAP( chalk.gray('The ' + themeName +
|
L( M2C( 'The **' + themeName + '** theme says:', 'cyan'));
|
||||||
' theme says: "') + chalk.white('For best results view JSON ' +
|
L( WRAP( '"For best results view JSON Resume themes over a ' +
|
||||||
'Resume themes over a local or remote HTTP connection. For ' +
|
'local or remote HTTP connection. For example:',
|
||||||
'example:'), { width: this.opts.wrap, indent: '' }
|
{ width: this.opts.wrap, indent: '' })
|
||||||
));
|
);
|
||||||
this.log( '');
|
L('');
|
||||||
this.log(
|
L(' npm install http-server -g\r' +
|
||||||
' npm install http-server -g\r' +
|
|
||||||
' http-server <resume-folder>' );
|
' http-server <resume-folder>' );
|
||||||
this.log('');
|
L('');
|
||||||
this.log(chalk.white('For more information, see the README."'),
|
L(chalk.white('For more information, see the README."'));
|
||||||
{ width: this.opts.wrap, indent: '' } );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +131,7 @@ Output routines for HackMyResume.
|
|||||||
suffix = chalk.green(' (with ' + this.opts.pdf + ')');
|
suffix = chalk.green(' (with ' + this.opts.pdf + ')');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.log( chalk.gray('Skipping ') +
|
L( chalk.gray('Skipping ') +
|
||||||
chalk.white.bold( pad(evt.fmt.toUpperCase(),4,null,pad.RIGHT)) +
|
chalk.white.bold( pad(evt.fmt.toUpperCase(),4,null,pad.RIGHT)) +
|
||||||
chalk.gray(' resume') + suffix + chalk.green(': ') +
|
chalk.gray(' resume') + suffix + chalk.green(': ') +
|
||||||
chalk.white( evt.file ));
|
chalk.white( evt.file ));
|
||||||
@ -122,7 +140,7 @@ Output routines for HackMyResume.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log( chalk.green('Generating ') +
|
L( chalk.green('Generating ') +
|
||||||
chalk.green.bold(
|
chalk.green.bold(
|
||||||
pad(evt.fmt.toUpperCase(),4,null,pad.RIGHT)) +
|
pad(evt.fmt.toUpperCase(),4,null,pad.RIGHT)) +
|
||||||
chalk.green(' resume') + suffix + chalk.green(': ') +
|
chalk.green(' resume') + suffix + chalk.green(': ') +
|
||||||
@ -130,7 +148,7 @@ Output routines for HackMyResume.
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case HME.beforeAnalyze:
|
case HME.beforeAnalyze:
|
||||||
this.log(chalk.cyan('Analyzing ') + chalk.cyan.bold(evt.fmt) +
|
L(chalk.cyan('Analyzing ') + chalk.cyan.bold(evt.fmt) +
|
||||||
chalk.cyan(' resume: ') + chalk.cyan.bold(evt.file));
|
chalk.cyan(' resume: ') + chalk.cyan.bold(evt.file));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -148,20 +166,20 @@ Output routines for HackMyResume.
|
|||||||
|
|
||||||
case HME.beforeConvert:
|
case HME.beforeConvert:
|
||||||
// TODO: Core should not log
|
// TODO: Core should not log
|
||||||
this.log( chalk.green('Converting ') + chalk.green.bold(evt.srcFile) +
|
L( chalk.green('Converting ') + chalk.green.bold(evt.srcFile) +
|
||||||
chalk.green(' (' + evt.srcFmt + ') to ') + chalk.green.bold(evt.dstFile) +
|
chalk.green(' (' + evt.srcFmt + ') to ') + chalk.green.bold(evt.dstFile) +
|
||||||
chalk.green(' (' + evt.dstFmt + ').'));
|
chalk.green(' (' + evt.dstFmt + ').'));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HME.afterValidate:
|
case HME.afterValidate:
|
||||||
var style = evt.isValid ? 'green' : 'yellow';
|
var style = evt.isValid ? 'green' : 'yellow';
|
||||||
this.log( chalk.white('Validating ') + chalk.white.bold(evt.file) + chalk.white(' against ') +
|
L( chalk.white('Validating ') + chalk.white.bold(evt.file) + chalk.white(' against ') +
|
||||||
chalk.white.bold( evt.fmt ).toUpperCase() +
|
chalk.white.bold( evt.fmt ).toUpperCase() +
|
||||||
chalk.white(' schema: ') + chalk[style].bold(evt.isValid ? 'VALID!' : 'INVALID'));
|
chalk.white(' schema: ') + chalk[style].bold(evt.isValid ? 'VALID!' : 'INVALID'));
|
||||||
|
|
||||||
if( evt.errors ) {
|
if( evt.errors ) {
|
||||||
_.each(evt.errors, function(err,idx) {
|
_.each(evt.errors, function(err,idx) {
|
||||||
this.log( chalk.yellow.bold('--> ') +
|
L( chalk.yellow.bold('--> ') +
|
||||||
chalk.yellow(err.field.replace('data.','resume.').toUpperCase() + ' ' +
|
chalk.yellow(err.field.replace('data.','resume.').toUpperCase() + ' ' +
|
||||||
err.message) );
|
err.message) );
|
||||||
}, this);
|
}, this);
|
||||||
|
@ -104,21 +104,25 @@ Definition of the ResumeFactory class.
|
|||||||
var rawData;
|
var rawData;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
// Read the file
|
||||||
eve && eve.stat( HME.beforeRead, { file: fileName });
|
eve && eve.stat( HME.beforeRead, { file: fileName });
|
||||||
rawData = FS.readFileSync( fileName, 'utf8' );
|
rawData = FS.readFileSync( fileName, 'utf8' );
|
||||||
eve && eve.stat( HME.afterRead, { data: rawData });
|
eve && eve.stat( HME.afterRead, { data: rawData });
|
||||||
|
|
||||||
|
// Parse the file
|
||||||
eve && eve.stat( HME.beforeParse, { data: rawData });
|
eve && eve.stat( HME.beforeParse, { data: rawData });
|
||||||
var ret = {
|
var ret = { json: JSON.parse( rawData ) };
|
||||||
json: JSON.parse( rawData )
|
|
||||||
};
|
|
||||||
eve && eve.stat( HME.afterParse, { data: ret.json } );
|
eve && eve.stat( HME.afterParse, { data: ret.json } );
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
catch( ex ) {
|
catch( e ) {
|
||||||
throw {
|
// Can be ENOENT, EACCES, SyntaxError, etc.
|
||||||
|
var ex = {
|
||||||
fluenterror: rawData ? HACKMYSTATUS.parseError : HACKMYSTATUS.readError,
|
fluenterror: rawData ? HACKMYSTATUS.parseError : HACKMYSTATUS.readError,
|
||||||
inner: ex, raw: rawData, file: fileName, shouldExit: false
|
inner: e, raw: rawData, file: fileName, shouldExit: false
|
||||||
};
|
};
|
||||||
|
eve && eve.err( ex.fluenterror, ex );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
18
src/utils/md2chalk.js
Normal file
18
src/utils/md2chalk.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
Inline Markdown-to-Chalk conversion routines.
|
||||||
|
@license MIT. See LICENSE.md for details.
|
||||||
|
@module md2chalk.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
var MD = require('marked');
|
||||||
|
var CHALK = require('chalk');
|
||||||
|
var LO = require('lodash');
|
||||||
|
|
||||||
|
module.exports = function( v, style ) {
|
||||||
|
var temp = v.replace(/\*\*(.*?)\*\*/g, CHALK.bold('$1'));
|
||||||
|
return style ? LO.get(CHALK, style)(temp) : temp;
|
||||||
|
};
|
||||||
|
|
||||||
|
}());
|
@ -66,6 +66,7 @@ Implementation of the 'build' verb for HackMyResume.
|
|||||||
|
|
||||||
// Load the theme...we do this first because the theme choice (FRESH or
|
// Load the theme...we do this first because the theme choice (FRESH or
|
||||||
// JSON Resume) determines what format we'll convert the resume to.
|
// JSON Resume) determines what format we'll convert the resume to.
|
||||||
|
this.stat( HME.beforeTheme, { theme: _opts.theme });
|
||||||
var tFolder = verifyTheme( _opts.theme );
|
var tFolder = verifyTheme( _opts.theme );
|
||||||
var theme = loadTheme( tFolder );
|
var theme = loadTheme( tFolder );
|
||||||
this.stat( HME.afterTheme, { theme: theme });
|
this.stat( HME.afterTheme, { theme: theme });
|
||||||
@ -73,15 +74,15 @@ Implementation of the 'build' verb for HackMyResume.
|
|||||||
// Check for invalid outputs
|
// Check for invalid outputs
|
||||||
var inv = verifyOutputs.call( this, dst, theme );
|
var inv = verifyOutputs.call( this, dst, theme );
|
||||||
if( inv && inv.length ) {
|
if( inv && inv.length ) {
|
||||||
throw {fluenterror: HACKMYSTATUS.invalidFormat, data: inv, theme: theme};
|
this.err( HACKMYSTATUS.invalidFormat, { data: inv, theme: theme } );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load input resumes...
|
// Load input resumes...
|
||||||
if( !src || !src.length ) { throw { fluenterror: 3 }; }
|
if( !src || !src.length ) { this.err( HACKMYSTATUS.resumeNotFound ); }
|
||||||
var sheets = ResumeFactory.load(src, {
|
var sheets = ResumeFactory.load(src, {
|
||||||
format: theme.render ? 'JRS' : 'FRESH',
|
format: theme.render ? 'JRS' : 'FRESH',
|
||||||
objectify: true, throw: true, inner: { sort: _opts.sort }
|
objectify: true, throw: true, inner: { sort: _opts.sort }
|
||||||
}, this).map(function(sh){ return sh.rez; });
|
}, this).map( function(sh){ return sh.rez; });
|
||||||
|
|
||||||
// Merge input resumes...
|
// Merge input resumes...
|
||||||
(sheets.length > 1) && this.stat( HME.beforeMerge, { f: _.clone(sheets) });
|
(sheets.length > 1) && this.stat( HME.beforeMerge, { f: _.clone(sheets) });
|
||||||
@ -179,8 +180,10 @@ Implementation of the 'build' verb for HackMyResume.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch( ex ) {
|
catch( ex ) {
|
||||||
console.log('Exception thrown');
|
// Catch any errors caused by generating this file and don't let them
|
||||||
console.log(ex); // TODO
|
// propagate -- typically we want to continue processing other formats
|
||||||
|
// even if this format failed.
|
||||||
|
this.err( HME.generate, { inner: ex } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +285,7 @@ Implementation of the 'build' verb for HackMyResume.
|
|||||||
if( !exists( tFolder ) ) {
|
if( !exists( tFolder ) ) {
|
||||||
tFolder = PATH.resolve( themeNameOrPath );
|
tFolder = PATH.resolve( themeNameOrPath );
|
||||||
if( !exists( tFolder ) ) {
|
if( !exists( tFolder ) ) {
|
||||||
throw { fluenterror: 1, data: _opts.theme };
|
this.err( HACKMYSTATUS.themeNotFound, { data: _opts.theme } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tFolder;
|
return tFolder;
|
||||||
|
@ -23,15 +23,30 @@ Definition of the Verb class.
|
|||||||
*/
|
*/
|
||||||
var Verb = module.exports = Class.extend({
|
var Verb = module.exports = Class.extend({
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Constructor. Automatically called at creation.
|
||||||
|
*/
|
||||||
init: function( moniker ) {
|
init: function( moniker ) {
|
||||||
this.moniker = moniker;
|
this.moniker = moniker;
|
||||||
this.emitter = new EVENTS.EventEmitter();
|
this.emitter = new EVENTS.EventEmitter();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Forward subscriptions to the event emitter.
|
||||||
|
*/
|
||||||
on: function() {
|
on: function() {
|
||||||
this.emitter.on.apply( this.emitter, arguments );
|
this.emitter.on.apply( this.emitter, arguments );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Fire an arbitrary event, scoped to "hmr:".
|
||||||
|
*/
|
||||||
fire: function(evtName, payload) {
|
fire: function(evtName, payload) {
|
||||||
payload = payload || { };
|
payload = payload || { };
|
||||||
payload.cmd = this.moniker;
|
payload.cmd = this.moniker;
|
||||||
@ -39,11 +54,29 @@ Definition of the Verb class.
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Fire the 'hmr:error' error event.
|
||||||
|
*/
|
||||||
|
err: function( errorCode, payload, hot ) {
|
||||||
|
payload = payload || { };
|
||||||
|
payload.sub = payload.fluenterror = errorCode;
|
||||||
|
payload.throw = hot;
|
||||||
|
this.fire('error', payload);
|
||||||
|
if( hot ) throw payload;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Fire the 'hmr:status' error event.
|
||||||
|
*/
|
||||||
stat: function( subEvent, payload ) {
|
stat: function( subEvent, payload ) {
|
||||||
payload = payload || { };
|
payload = payload || { };
|
||||||
payload.cmd = this.moniker;
|
|
||||||
payload.sub = subEvent;
|
payload.sub = subEvent;
|
||||||
this.emitter.emit( 'hmr:status', payload );
|
this.fire('status', payload);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,12 +70,17 @@ describe('Testing Ouput interface', function () {
|
|||||||
run('BUILD should output a tip when no source is specified',
|
run('BUILD should output a tip when no source is specified',
|
||||||
['build'], [ title, feedMe ]);
|
['build'], [ title, feedMe ]);
|
||||||
|
|
||||||
run('VALIATE should output a tip when no source is specified',
|
run('VALIDATE should output a tip when no source is specified',
|
||||||
['validate'], [ title, feedMe ]);
|
['validate'], [ title, feedMe ]);
|
||||||
|
|
||||||
run('ANALYZE should output a tip when no source is specified',
|
run('ANALYZE should output a tip when no source is specified',
|
||||||
['analyze'], [ title, feedMe ]);
|
['analyze'], [ title, feedMe ]);
|
||||||
|
|
||||||
|
run('BUILD should display an error on a broken resume',
|
||||||
|
['build',
|
||||||
|
'node_modules/fresh-test-resumes/src/johnny-trouble.broken.fresh.json'
|
||||||
|
], [ title, 'Error: Invalid or corrupt JSON on line' ]);
|
||||||
|
|
||||||
run('CONVERT should output a tip when no source is specified',
|
run('CONVERT should output a tip when no source is specified',
|
||||||
['convert'], [ title, feedMe ]);
|
['convert'], [ title, feedMe ]);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user