mirror of
https://github.com/JuanCanham/HackMyResume.git
synced 2024-12-23 13:47:22 +00:00
Multiple enhancements.
A set of rough enhancements supporting FRESH: - Added ability to process multiple sources for all commands (BUILD, VALIDATE, CONVERT). - Added new HELP command to show usage. - Improved error-handling and color-coding.
This commit is contained in:
parent
992069b22d
commit
5735ddc495
@ -15,7 +15,7 @@ module.exports = function () {
|
||||
, FLUENT = require('./fluentlib')
|
||||
, PATH = require('path')
|
||||
, MKDIRP = require('mkdirp')
|
||||
, COLORS = require('colors')
|
||||
//, COLORS = require('colors')
|
||||
, rez, _log, _err;
|
||||
|
||||
/**
|
||||
@ -62,8 +62,8 @@ module.exports = function () {
|
||||
// Load the theme
|
||||
var theTheme = new FLUENT.Theme().open( tFolder );
|
||||
_opts.themeObj = theTheme;
|
||||
_log( 'Applying '.yellow + theTheme.name.toUpperCase().yellow.bold + (' theme (' +
|
||||
Object.keys(theTheme.formats).length + ' formats)').yellow );
|
||||
_log( 'Applying '.status + theTheme.name.toUpperCase().infoBold + (' theme (' +
|
||||
Object.keys(theTheme.formats).length + ' formats)').status );
|
||||
|
||||
// Expand output resumes... (can't use map() here)
|
||||
var targets = [], that = this;
|
||||
@ -99,8 +99,8 @@ module.exports = function () {
|
||||
var fObj = _.property( fi.fmt.pre )( theme.formats );
|
||||
var fOut = path.join( f.substring( 0, f.lastIndexOf('.')+1 ) + fObj.pre);
|
||||
|
||||
_log( 'Generating '.green + fi.fmt.title.toUpperCase().green.bold + ' resume: '.green +
|
||||
path.relative(process.cwd(), f ).green.bold );
|
||||
_log( 'Generating '.useful + fi.fmt.title.toUpperCase().useful.bold + ' resume: '.useful +
|
||||
path.relative(process.cwd(), f ).useful.bold );
|
||||
|
||||
var theFormat = _fmts.filter(
|
||||
function( fmt ) { return fmt.name === fi.fmt.pre; })[0];
|
||||
@ -124,7 +124,7 @@ module.exports = function () {
|
||||
*/
|
||||
function validate( src, unused, opts, logger ) {
|
||||
_log = logger || console.log;
|
||||
if( !src || !src.length ) { throw { fluenterror: 3 }; }
|
||||
if( !src || !src.length ) { throw { fluenterror: 6 }; }
|
||||
var isValid = true;
|
||||
|
||||
var validator = require('is-my-json-valid');
|
||||
@ -152,7 +152,7 @@ module.exports = function () {
|
||||
var rez = JSON.parse( rep.raw );
|
||||
}
|
||||
catch( ex ) {
|
||||
_log('Validating '.gray + rep.file.cyan.bold + ' against FRESH/JRS schema: '.gray + 'ERROR!'.red.bold);
|
||||
_log('Validating '.info + rep.file.infoBold + ' against FRESH/JRS schema: '.info + 'ERROR!'.error.bold);
|
||||
|
||||
if (ex instanceof SyntaxError) {
|
||||
// Invalid JSON
|
||||
@ -166,27 +166,39 @@ module.exports = function () {
|
||||
return;
|
||||
}
|
||||
|
||||
var fmt = rez.meta && rez.meta.format === 'FRESH@0.1.0' ? 'fresh':'jars';
|
||||
process.stdout.write( 'Validating '.gray + rep.file + ' against '.gray +
|
||||
fmt.replace('jars','JSON Resume').toUpperCase() + ' schema: '.gray );
|
||||
var isValid = false;
|
||||
var style = 'useful';
|
||||
var errors = [];
|
||||
|
||||
var validate = validator( schemas[ fmt ], { // Note [1]
|
||||
formats: { date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ }
|
||||
try {
|
||||
|
||||
|
||||
|
||||
var fmt = rez.meta && rez.meta.format === 'FRESH@0.1.0' ? 'fresh':'jars';
|
||||
var validate = validator( schemas[ fmt ], { // Note [1]
|
||||
formats: { date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ }
|
||||
});
|
||||
|
||||
isValid = validate( rez );
|
||||
if( !isValid ) {
|
||||
style = 'warn';
|
||||
errors = validate.errors;
|
||||
}
|
||||
|
||||
}
|
||||
catch(ex) {
|
||||
|
||||
}
|
||||
|
||||
_log( 'Validating '.info + rep.file.infoBold + ' against '.info +
|
||||
fmt.replace('jars','JSON Resume').toUpperCase().infoBold + ' schema: '.info + (isValid ? 'VALID!' : 'INVALID')[style].bold );
|
||||
|
||||
errors.forEach(function(err,idx){
|
||||
_log( '--> '.bold.yellow + ( err.field.replace('data.','resume.').toUpperCase()
|
||||
+ ' ' + err.message).yellow );
|
||||
});
|
||||
|
||||
var ret = validate( rez );
|
||||
if( !ret ) {
|
||||
rez.imp = rez.imp || { };
|
||||
rez.imp.validationErrors = validate.errors;
|
||||
_log('INVALID'.bold.yellow);
|
||||
rez.imp.validationErrors.forEach(function(err,idx){
|
||||
_log( '--> '.bold.yellow + ( err.field.replace('data.','resume.').toUpperCase()
|
||||
+ ' ' + err.message).yellow );
|
||||
});
|
||||
}
|
||||
else {
|
||||
_log('VALID!'.bold.green);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
@ -196,19 +208,35 @@ module.exports = function () {
|
||||
*/
|
||||
function convert( src, dst, opts, logger ) {
|
||||
_log = logger || console.log;
|
||||
if( !src || !src.length ) { throw { fluenterror: 3 }; }
|
||||
if( !dst || !dst.length ) { throw { fluenterror: 5 }; }
|
||||
var sheet = loadSourceResumes( src )[ 0 ];
|
||||
var sourceFormat = sheet.imp.orgFormat === 'JRS' ? 'JRS' : 'FRESH';
|
||||
var targetFormat = sourceFormat === 'JRS' ? 'FRESH' : 'JRS';
|
||||
_log( 'Converting '.gray + src[0] + (' (' + sourceFormat + ') to ').gray + dst[0] +
|
||||
(' (' + targetFormat + ').').gray );
|
||||
sheet.saveAs( dst[0], targetFormat );
|
||||
if( !src || !src.length ) { throw { fluenterror: 6 }; }
|
||||
if( !dst || !dst.length ) {
|
||||
if( src.length === 1 ) { throw { fluenterror: 5 }; }
|
||||
else if( src.length === 2 ) { dst = [ src[1] ]; src = [ src[0] ]; }
|
||||
else { throw { fluenterror: 5 }; }
|
||||
}
|
||||
if( src && dst && src.length && dst.length && src.length !== dst.length ) {
|
||||
throw { fluenterror: 7 };
|
||||
}
|
||||
var sheets = loadSourceResumes( src );
|
||||
sheets.forEach(function(sheet, idx){
|
||||
var sourceFormat = sheet.imp.orgFormat === 'JRS' ? 'JRS' : 'FRESH';
|
||||
var targetFormat = sourceFormat === 'JRS' ? 'FRESH' : 'JRS';
|
||||
_log( 'Converting '.useful + sheet.imp.fileName.useful.bold + (' (' + sourceFormat + ') to ').useful + dst[0].useful.bold +
|
||||
(' (' + targetFormat + ').').useful );
|
||||
sheet.saveAs( dst[idx], targetFormat );
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
Display help documentation.
|
||||
*/
|
||||
function help() {
|
||||
console.log( FS.readFileSync( PATH.join(__dirname, 'use.txt'), 'utf8' ).useful.bold );
|
||||
}
|
||||
|
||||
function loadSourceResumes( src, fn ) {
|
||||
return src.map( function( res ) {
|
||||
_log( 'Reading '.gray + 'SOURCE' + ' resume: '.gray + res.cyan.bold );
|
||||
_log( 'Reading '.info + 'SOURCE'.infoBold + ' resume: '.status + res.cyan.bold );
|
||||
return (fn && fn(res)) || (new FLUENT.FRESHResume()).open( res );
|
||||
});
|
||||
}
|
||||
@ -246,7 +274,8 @@ module.exports = function () {
|
||||
verbs: {
|
||||
build: generate,
|
||||
validate: validate,
|
||||
convert: convert
|
||||
convert: convert,
|
||||
help: help
|
||||
},
|
||||
lib: require('./fluentlib'),
|
||||
options: _opts,
|
||||
|
44
src/index.js
44
src/index.js
@ -8,8 +8,11 @@ Command-line interface (CLI) for FluentCV:CLI.
|
||||
var ARGS = require( 'minimist' )
|
||||
, FCMD = require( './fluentcmd')
|
||||
, PKG = require('../package.json')
|
||||
, COLORS = require('colors')
|
||||
, FS = require('fs')
|
||||
, PATH = require('path')
|
||||
, opts = { }
|
||||
, title = ('*** FluentCV v' + PKG.version + ' ***').white.bold
|
||||
, title = ('*** FluentCV v' + PKG.version + ' ***').bold.white
|
||||
, _ = require('underscore');
|
||||
|
||||
|
||||
@ -25,16 +28,30 @@ catch( ex ) {
|
||||
|
||||
function main() {
|
||||
|
||||
// Colorize
|
||||
COLORS.setTheme({
|
||||
title: ['white','bold'],
|
||||
info: process.platform === 'win32' ? 'gray' : ['white','dim'],
|
||||
infoBold: ['white','dim'],
|
||||
warn: 'yellow',
|
||||
error: 'red',
|
||||
guide: 'yellow',
|
||||
status: 'gray',//['white','dim'],
|
||||
useful: 'green',
|
||||
});
|
||||
|
||||
// Setup
|
||||
if( process.argv.length <= 2 ) { throw { fluenterror: 4 }; }
|
||||
var a = ARGS( process.argv.slice(2) );
|
||||
opts = getOpts( a );
|
||||
logMsg( title );
|
||||
|
||||
|
||||
// Get the action to be performed
|
||||
var params = a._.map( function(p){ return p.toLowerCase().trim(); });
|
||||
var verb = params[0];
|
||||
if( !FCMD.verbs[ verb ] ) {
|
||||
logMsg('Invalid command: "'.yellow + verb.yellow.bold + '"'.yellow);
|
||||
logMsg('Invalid command: "'.warn + verb.warn.bold + '"'.warn);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -42,7 +59,8 @@ function main() {
|
||||
var splitAt = _.indexOf( params, 'to' );
|
||||
if( splitAt === a._.length - 1 ) {
|
||||
// 'TO' cannot be the last argument
|
||||
logMsg('Please '.gray + 'specify an output file' + ' for this operation or '.gray + 'omit the TO keyword' + '.'.gray);
|
||||
logMsg('Please '.warn + 'specify an output file'.warnBold +
|
||||
' for this operation or '.warn + 'omit the TO keyword'.warnBold + '.'.warn );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -75,20 +93,27 @@ function getOpts( args ) {
|
||||
|
||||
function handleError( ex ) {
|
||||
var msg = '', exitCode;
|
||||
|
||||
|
||||
|
||||
if( ex.fluenterror ){
|
||||
switch( ex.fluenterror ) { // TODO: Remove magic numbers
|
||||
case 1: msg = "The specified theme couldn't be found: " + ex.data; break;
|
||||
case 2: msg = "Couldn't copy CSS file to destination folder"; break;
|
||||
case 3: msg = 'Please '.gray + 'specify a valid input resume' + ' in '.gray + 'FRESH' + ' or '.gray + 'JSON Resume' + ' format.'.gray; break;
|
||||
case 4: msg = title + "\nPlease specify a command (".gray +
|
||||
case 3: msg = 'Please '.guide + 'specify a valid input resume'.guide.bold + ' in FRESH or JSON Resume format.'.guide; break;
|
||||
case 4: msg = title + "\nPlease ".guide + "specify a command".guide.bold + " (".guide +
|
||||
Object.keys( FCMD.verbs ).map( function(v, idx, ar) {
|
||||
return (idx === ar.length - 1 ? 'or '.gray : '')
|
||||
+ v.toUpperCase();
|
||||
}).join(', ') + ")";
|
||||
return (idx === ar.length - 1 ? 'or '.guide : '')
|
||||
+ v.toUpperCase().guide;
|
||||
}).join(', '.guide) + ") to get started.\n\n".guide + FS.readFileSync( PATH.join(__dirname, 'use.txt'), 'utf8' ).info.bold;
|
||||
break;
|
||||
case 5: msg = "Please specify the name of the TARGET file to convert to.".gray;
|
||||
//case 4: msg = title + '\n' + ; break;
|
||||
case 5: msg = 'Please '.guide + 'specify the output resume file'.guide.bold + ' that should be created in the new format.'.guide; break;
|
||||
case 6: msg = 'Please '.guide + 'specify a valid input resume'.guide.bold + ' in either FRESH or JSON Resume format.'.guide; break;
|
||||
case 7: msg = 'Please '.guide + 'specify an output file name'.guide.bold + ' for every input file you wish to convert.'.guide; break;
|
||||
};
|
||||
exitCode = ex.fluenterror;
|
||||
|
||||
}
|
||||
else {
|
||||
msg = ex.toString();
|
||||
@ -101,6 +126,7 @@ function handleError( ex ) {
|
||||
console.log( ('ERROR: ' + trimmed.toString()).red.bold );
|
||||
else
|
||||
console.log( trimmed.toString() );
|
||||
|
||||
process.exit( exitCode );
|
||||
|
||||
}
|
||||
|
22
src/use.txt
Normal file
22
src/use.txt
Normal file
@ -0,0 +1,22 @@
|
||||
Usage:
|
||||
|
||||
fluentcv <COMMAND> <SOURCES> [TO <TARGETS>] [-t <THEME>]
|
||||
|
||||
<COMMAND> should be BUILD, CONVERT, VALIDATE, 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> 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.
|
||||
|
||||
fluentcv BUILD resume.json TO out/resume.all
|
||||
fluentcv CONVERT resume.json TO resume-jrs.json
|
||||
fluentcv VALIDATE resume.json
|
||||
|
||||
Both SOURCES and TARGETS can accept multiple files:
|
||||
|
||||
fluentCV BUILD r1.json r2.json TO out/resume.all out2/resume.html
|
||||
fluentCV VALIDATE resume.json resume2.json resume3.json
|
||||
|
||||
See https://github.com/fluentdesk/fluentCV/blob/master/README.md
|
||||
for more information.
|
Loading…
Reference in New Issue
Block a user