1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2024-11-25 09:50:11 +00:00

Implement "generate" and "validate" verbs.

Start moving to a more familiar verb-based interface with "generate" and
"validate" commands. Use with "fluentcv generate" or "fluentcv
validate".
This commit is contained in:
devlinjd 2015-11-19 09:46:02 -05:00
parent 9044dff504
commit a410153253
5 changed files with 83 additions and 120 deletions

View File

@ -10,7 +10,8 @@ FRESH character/resume sheet representation.
, validator = require('is-my-json-valid')
, _ = require('underscore')
, PATH = require('path')
, moment = require('moment');
, moment = require('moment')
, CONVERTER = require('./convert');
/**
A FRESH-style resume in JSON or YAML.
@ -66,7 +67,7 @@ FRESH character/resume sheet representation.
var rep = JSON.parse( stringData );
// Convert JSON Resume to FRESH if necessary
rep.basics && (rep = FreshSheet.convert( rep ));
rep.basics && (rep = CONVERTER.toFRESH( rep ));
// Now apply the resume representation onto this object
extend( true, this, rep );
@ -87,106 +88,6 @@ FRESH character/resume sheet representation.
return this;
};
/**
Convert from JSON Resume format
*/
FreshSheet.convert = function( jrs ) {
return {
name: jrs.basics.name,
label: jrs.basics.label,
class: jrs.basics.label,
summary: jrs.basics.summary,
contact: {
email: jrs.basics.email,
phone: jrs.basics.phone,
website: jrs.basics.website,
postal: {
city: jrs.basics.location.city,
region: jrs.basics.location.region,
country: jrs.basics.location.countryCode,
code: jrs.basics.location.postalCode,
address: [
jrs.basics.location.address,
]
}
},
employment: {
history: jrs.work.map( function( job ) {
return {
position: job.position,
employer: job.company,
summary: job.summary,
current: !job.endDate || !job.endDate.trim() || job.endDate.trim().toLowerCase() === 'current',
start: job.startDate,
end: job.endDate,
url: job.website,
keywords: "",
highlights: job.highlights
};
})
},
education: {
history: jrs.education.map(function(edu){
return {
institution: edu.institution,
start: edu.startDate,
end: edu.endDate,
grade: edu.gpa,
curriculum: edu.courses,
url: edu.website || edu.url || null,
summary: null,
// ???: edu.area, TODO
// ???: edu.studyType TODO
};
})
},
service: {
history: jrs.volunteer.map(function(vol) {
return {
type: 'volunteer',
position: vol.position,
organization: vol.organization,
start: vol.startDate,
end: vol.endDate,
url: vol.website,
summary: vol.summary,
highlights: vol.highlights
};
})
},
skills: jrs.skills.map(function(sk){
return {
name: sk.name,
summary: "",
level: sk.level,
summary: sk.keywords.join(', '),
years: null,
proof: null
};
}),
publications: jrs.publications.map(function(pub){
return {
title: pub.name,
publisher: pub.publisher,
link: [
{ 'url': pub.website }
],
year: pub.releaseDate
};
}),
interests: jrs.interests
};
};
/**
Return a unique list of all keywords across all skills.
*/
@ -266,12 +167,17 @@ FRESH character/resume sheet representation.
/**
Validate the sheet against the FRESH Resume schema.
*/
FreshSheet.prototype.isValid = function( ) { // TODO: ↓ fix this path ↓
var schema = FS.readFileSync( PATH.join( __dirname, 'resume.json' ), 'utf8' );
var schemaObj = JSON.parse( schema );
FreshSheet.prototype.isValid = function( info ) {
var schemaObj = require('FRESCA');
//var schemaObj = JSON.parse( schema );
var validator = require('is-my-json-valid')
var validate = validator( schemaObj );
return validate( this );
var ret = validate( this );
if( !ret ) {
this.meta = this.meta || { };
this.meta.validationErrors = validate.errors;
}
return ret;
};
/**

View File

@ -9,7 +9,7 @@ module.exports = function () {
var path = require( 'path' )
, extend = require( './utils/extend' )
, unused = require('./utils/string')
, fs = require('fs')
, FS = require('fs')
, _ = require('underscore')
, FLUENT = require('./fluentlib')
, PATH = require('path')
@ -109,6 +109,46 @@ module.exports = function () {
throw ex;
}
/**
Validate 1 to N resumes as vanilla JSON.
*/
// function validateAsJSON( src, logger ) {
// _log = logger || console.log;
// if( !src || !src.length ) { throw { fluenterror: 3 }; }
// var isValid = true;
// var sheets = src.map( function( res ) {
// try {
// var rawJson = FS.readFileSync( res, 'utf8' );
// var testObj = JSON.parse( rawJson );
// }
// catch(ex) {
// if (!(ex instanceof SyntaxError)) { throw ex; } // [1]
// isValid = false;
// }
//
// _log( 'Validating JSON resume: ' + res + (isValid ? ' (VALID)' : ' (INVALID)'));
// return isValid;
// });
// }
/**
Validate 1 to N resumes in either FRESH or JSON Resume format.
*/
function validate( src, unused, opts, logger ) {
_log = logger || console.log;
if( !src || !src.length ) { throw { fluenterror: 3 }; }
var isValid = true;
var sheets = src.map( function( res ) {
var sheet = (new FLUENT.Sheet()).open( res );
var valid = sheet.isValid();
_log( 'Validating JSON resume: ' + res +
(valid ? ' (VALID)' : ' (INVALID)'));
if( !valid ) {
_log( sheet.meta.validationErrors );
}
});
}
/**
Supported resume formats.
*/
@ -139,10 +179,17 @@ module.exports = function () {
Internal module interface. Used by FCV Desktop and HMR.
*/
return {
generate: gen,
verbs: {
generate: gen,
validate: validate,
convert: convert
},
lib: require('./fluentlib'),
options: _opts,
formats: _fmts
};
}();
// [1]: JSON.parse throws SyntaxError on invalid JSON. See:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse

View File

@ -4,7 +4,7 @@ External API surface for FluentCV:CLI.
*/
module.exports = {
Sheet: require('./core/sheet'),
Sheet: require('./core/fresh-sheet'),
Theme: require('./core/theme'),
FluentDate: require('./core/fluent-date'),
HtmlGenerator: require('./gen/html-generator'),

View File

@ -29,7 +29,9 @@ Base resume generator for FluentCV.
success: 0,
themeNotFound: 1,
copyCss: 2,
resumeNotFound: 3
resumeNotFound: 3,
missingCommand: 4,
invalidCommand: 5
},
/**

View File

@ -23,20 +23,27 @@ catch( ex ) {
function main() {
// Setup.
// Setup
var title = '*** FluentCV v' + PKG.version + ' ***';
if( process.argv.length <= 2 ) { logMsg(title); throw { fluenterror: 3 }; }
var args = ARGS( process.argv.slice(2) );
opts = getOpts( args );
if( process.argv.length <= 2 ) { logMsg(title); throw { fluenterror: 4 }; }
var a = ARGS( process.argv.slice(2) );
opts = getOpts( a );
logMsg( title );
// Convert arguments to source files, target files, options
var src = args._ || [];
var dst = (args.o && ((typeof args.o === 'string' && [ args.o ]) || args.o)) || [];
dst = (dst === true) ? [] : dst; // Handle -o with missing output file
// Get the action to be performed
var verb = a._[0].toLowerCase().trim();
if( !FCMD.verbs[ verb ] ) {
throw 'Invalid command: "' + verb + '"';
}
// Preload our params array
var dst = (a.o && ((typeof a.o === 'string' && [ a.o ]) || a.o)) || [];
dst = (dst === true) ? [] : dst; // Handle -o with missing output file
var parms = [ a._.slice(1) || [], dst, opts, logMsg ];
// Invoke the action
FCMD.verbs[ verb ].apply( null, parms );
// Generate!
FCMD.generate( src, dst, opts, logMsg );
}
function logMsg( msg ) {
@ -60,6 +67,7 @@ function handleError( ex ) {
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 specify a valid JSON resume file."; break;
case 4: msg = "Please specify a valid command (GENERATE, VALIDATE, or CONVERT)."
};
exitCode = ex.fluenterror;
}