mirror of
https://github.com/JuanCanham/HackMyResume.git
synced 2025-05-15 10:07:07 +01:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
78a8b9c58e | |||
5e7abb66bd | |||
358c397bb9 | |||
3d41528059 | |||
79637b611a | |||
5de796b119 | |||
bf84341acf | |||
bbac1fdceb | |||
c5ee1ee33c | |||
c74eda90ed | |||
ef2fe95bd8 | |||
e2589b3730 | |||
ebad1677bc | |||
dab6ebfd82 | |||
dd61b5360a | |||
fced92a5a0 |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hackmyresume",
|
"name": "hackmyresume",
|
||||||
"version": "1.2.0",
|
"version": "1.2.2",
|
||||||
"description": "Generate polished résumés and CVs in HTML, Markdown, LaTeX, MS Word, PDF, plain text, JSON, XML, YAML, smoke signal, and carrier pigeon.",
|
"description": "Generate polished résumés and CVs in HTML, Markdown, LaTeX, MS Word, PDF, plain text, JSON, XML, YAML, smoke signal, and carrier pigeon.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -24,7 +24,7 @@
|
|||||||
"Underscore",
|
"Underscore",
|
||||||
"template"
|
"template"
|
||||||
],
|
],
|
||||||
"author": "hacksalot <hacksalot@fluentdesk.com> (https://github.com/hacksalot)",
|
"author": "hacksalot <hacksalot@indevious.com> (https://github.com/hacksalot)",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"preferGlobal": "true",
|
"preferGlobal": "true",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
@ -37,17 +37,20 @@
|
|||||||
"homepage": "https://github.com/hacksalot/HackMyResume",
|
"homepage": "https://github.com/hacksalot/HackMyResume",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"colors": "^1.1.2",
|
"colors": "^1.1.2",
|
||||||
"fluent-themes": "~0.7.0-beta",
|
"fluent-themes": "~0.7.1-beta",
|
||||||
"fresca": "~0.2.2",
|
"fresca": "~0.2.2",
|
||||||
"fs-extra": "^0.24.0",
|
"fs-extra": "^0.24.0",
|
||||||
"handlebars": "^4.0.5",
|
"handlebars": "^4.0.5",
|
||||||
"html": "0.0.10",
|
"html": "0.0.10",
|
||||||
"is-my-json-valid": "^2.12.2",
|
"is-my-json-valid": "^2.12.2",
|
||||||
"jst": "0.0.13",
|
"jst": "0.0.13",
|
||||||
|
"lodash": "^3.10.1",
|
||||||
"marked": "^0.3.5",
|
"marked": "^0.3.5",
|
||||||
"minimist": "^1.2.0",
|
"minimist": "^1.2.0",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"moment": "^2.10.6",
|
"moment": "^2.10.6",
|
||||||
|
"parse-filepath": "^0.6.3",
|
||||||
|
"path-exists": "^2.1.0",
|
||||||
"recursive-readdir-sync": "^1.0.6",
|
"recursive-readdir-sync": "^1.0.6",
|
||||||
"simple-html-tokenizer": "^0.2.0",
|
"simple-html-tokenizer": "^0.2.0",
|
||||||
"underscore": "^1.8.3",
|
"underscore": "^1.8.3",
|
||||||
|
@ -16,6 +16,7 @@ FRESH to JSON Resume conversion routiens.
|
|||||||
/**
|
/**
|
||||||
Convert from JSON Resume format to FRESH.
|
Convert from JSON Resume format to FRESH.
|
||||||
@method toFresh
|
@method toFresh
|
||||||
|
@todo Refactor
|
||||||
*/
|
*/
|
||||||
toFRESH: function( src, foreign ) {
|
toFRESH: function( src, foreign ) {
|
||||||
|
|
||||||
@ -67,6 +68,7 @@ FRESH to JSON Resume conversion routiens.
|
|||||||
Convert from FRESH format to JSON Resume.
|
Convert from FRESH format to JSON Resume.
|
||||||
@param foreign True if non-JSON-Resume properties should be included in
|
@param foreign True if non-JSON-Resume properties should be included in
|
||||||
the result, false if those properties should be excluded.
|
the result, false if those properties should be excluded.
|
||||||
|
@todo Refactor
|
||||||
*/
|
*/
|
||||||
toJRS: function( src, foreign ) {
|
toJRS: function( src, foreign ) {
|
||||||
|
|
||||||
@ -112,6 +114,7 @@ FRESH to JSON Resume conversion routiens.
|
|||||||
};
|
};
|
||||||
|
|
||||||
function meta( direction, obj ) {
|
function meta( direction, obj ) {
|
||||||
|
if( !obj ) return obj; // preserve null and undefined
|
||||||
if( direction ) {
|
if( direction ) {
|
||||||
obj = obj || { };
|
obj = obj || { };
|
||||||
obj.format = obj.format || "FRESH@0.1.0";
|
obj.format = obj.format || "FRESH@0.1.0";
|
||||||
@ -121,6 +124,7 @@ FRESH to JSON Resume conversion routiens.
|
|||||||
}
|
}
|
||||||
|
|
||||||
function employment( obj, direction ) {
|
function employment( obj, direction ) {
|
||||||
|
if( !obj ) return obj;
|
||||||
if( !direction ) {
|
if( !direction ) {
|
||||||
return obj && obj.history ?
|
return obj && obj.history ?
|
||||||
obj.history.map(function(emp){
|
obj.history.map(function(emp){
|
||||||
@ -157,6 +161,7 @@ FRESH to JSON Resume conversion routiens.
|
|||||||
|
|
||||||
|
|
||||||
function education( obj, direction ) {
|
function education( obj, direction ) {
|
||||||
|
if( !obj ) return obj;
|
||||||
if( direction ) {
|
if( direction ) {
|
||||||
return obj && obj.length ? {
|
return obj && obj.length ? {
|
||||||
history: obj.map(function(edu){
|
history: obj.map(function(edu){
|
||||||
@ -191,6 +196,7 @@ FRESH to JSON Resume conversion routiens.
|
|||||||
}
|
}
|
||||||
|
|
||||||
function service( obj, direction, foreign ) {
|
function service( obj, direction, foreign ) {
|
||||||
|
if( !obj ) return obj;
|
||||||
if( direction ) {
|
if( direction ) {
|
||||||
return {
|
return {
|
||||||
history: obj && obj.length ? obj.map(function(vol) {
|
history: obj && obj.length ? obj.map(function(vol) {
|
||||||
@ -225,6 +231,7 @@ FRESH to JSON Resume conversion routiens.
|
|||||||
}
|
}
|
||||||
|
|
||||||
function social( obj, direction ) {
|
function social( obj, direction ) {
|
||||||
|
if( !obj ) return obj;
|
||||||
if( direction ) {
|
if( direction ) {
|
||||||
return obj.map(function(pro){
|
return obj.map(function(pro){
|
||||||
return {
|
return {
|
||||||
@ -247,6 +254,7 @@ FRESH to JSON Resume conversion routiens.
|
|||||||
}
|
}
|
||||||
|
|
||||||
function recognition( obj, direction, foreign ) {
|
function recognition( obj, direction, foreign ) {
|
||||||
|
if( !obj ) return obj;
|
||||||
if( direction ) {
|
if( direction ) {
|
||||||
return obj && obj.length ? obj.map(
|
return obj && obj.length ? obj.map(
|
||||||
function(awd){
|
function(awd){
|
||||||
@ -275,6 +283,7 @@ FRESH to JSON Resume conversion routiens.
|
|||||||
}
|
}
|
||||||
|
|
||||||
function references( obj, direction ) {
|
function references( obj, direction ) {
|
||||||
|
if( !obj ) return obj;
|
||||||
if( direction ) {
|
if( direction ) {
|
||||||
return obj && obj.length && obj.map(function(ref){
|
return obj && obj.length && obj.map(function(ref){
|
||||||
return {
|
return {
|
||||||
@ -296,6 +305,7 @@ FRESH to JSON Resume conversion routiens.
|
|||||||
}
|
}
|
||||||
|
|
||||||
function writing( obj, direction ) {
|
function writing( obj, direction ) {
|
||||||
|
if( !obj ) return obj;
|
||||||
if( direction ) {
|
if( direction ) {
|
||||||
return obj.map(function( pub ) {
|
return obj.map(function( pub ) {
|
||||||
return {
|
return {
|
||||||
|
@ -10,6 +10,7 @@ Definition of the FRESHResume class.
|
|||||||
, extend = require('../utils/extend')
|
, extend = require('../utils/extend')
|
||||||
, validator = require('is-my-json-valid')
|
, validator = require('is-my-json-valid')
|
||||||
, _ = require('underscore')
|
, _ = require('underscore')
|
||||||
|
, __ = require('lodash')
|
||||||
, PATH = require('path')
|
, PATH = require('path')
|
||||||
, moment = require('moment')
|
, moment = require('moment')
|
||||||
, MD = require('marked')
|
, MD = require('marked')
|
||||||
@ -187,15 +188,6 @@ Definition of the FRESHResume class.
|
|||||||
return flatSkills;
|
return flatSkills;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
Update the sheet's raw data. TODO: remove/refactor
|
|
||||||
*/
|
|
||||||
FreshResume.prototype.updateData = function( str ) {
|
|
||||||
this.clear( false );
|
|
||||||
this.parse( str );
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reset the sheet to an empty state.
|
Reset the sheet to an empty state.
|
||||||
*/
|
*/
|
||||||
@ -299,7 +291,7 @@ Definition of the FRESHResume class.
|
|||||||
Validate the sheet against the FRESH Resume schema.
|
Validate the sheet against the FRESH Resume schema.
|
||||||
*/
|
*/
|
||||||
FreshResume.prototype.isValid = function( info ) {
|
FreshResume.prototype.isValid = function( info ) {
|
||||||
var schemaObj = require('FRESCA');
|
var schemaObj = require('fresca');
|
||||||
var validator = require('is-my-json-valid');
|
var validator = require('is-my-json-valid');
|
||||||
var validate = validator( schemaObj, { // Note [1]
|
var validate = validator( schemaObj, { // Note [1]
|
||||||
formats: { date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ }
|
formats: { date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ }
|
||||||
@ -321,7 +313,8 @@ Definition of the FRESHResume class.
|
|||||||
sheets that have overlapping jobs.
|
sheets that have overlapping jobs.
|
||||||
*/
|
*/
|
||||||
FreshResume.prototype.duration = function() {
|
FreshResume.prototype.duration = function() {
|
||||||
if( this.employment.history && this.employment.history.length ) {
|
var empHist = __.get(this, 'employment.history');
|
||||||
|
if( empHist && empHist.length ) {
|
||||||
var firstJob = _.last( this.employment.history );
|
var firstJob = _.last( this.employment.history );
|
||||||
var careerStart = firstJob.start ? firstJob.safe.start : '';
|
var careerStart = firstJob.start ? firstJob.safe.start : '';
|
||||||
if ((typeof careerStart === 'string' || careerStart instanceof String) &&
|
if ((typeof careerStart === 'string' || careerStart instanceof String) &&
|
||||||
@ -341,9 +334,9 @@ Definition of the FRESHResume class.
|
|||||||
*/
|
*/
|
||||||
FreshResume.prototype.sort = function( ) {
|
FreshResume.prototype.sort = function( ) {
|
||||||
|
|
||||||
this.employment.history && this.employment.history.sort( byDateDesc );
|
__.get(this, 'employment.history') && this.employment.history.sort( byDateDesc );
|
||||||
this.education.history && this.education.history.sort( byDateDesc );
|
__.get(this, 'education.history') && this.education.history.sort( byDateDesc );
|
||||||
this.service.history && this.service.history.sort( byDateDesc );
|
__.get(this, 'service.history') && this.service.history.sort( byDateDesc );
|
||||||
|
|
||||||
// this.awards && this.awards.sort( function(a, b) {
|
// this.awards && this.awards.sort( function(a, b) {
|
||||||
// return( a.safeDate.isBefore(b.safeDate) ) ? 1
|
// return( a.safeDate.isBefore(b.safeDate) ) ? 1
|
||||||
|
@ -107,15 +107,6 @@ Definition of the JRSResume class.
|
|||||||
return flatSkills;
|
return flatSkills;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
Update the sheet's raw data. TODO: remove/refactor
|
|
||||||
*/
|
|
||||||
JRSResume.prototype.updateData = function( str ) {
|
|
||||||
this.clear( false );
|
|
||||||
this.parse( str );
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Reset the sheet to an empty state.
|
Reset the sheet to an empty state.
|
||||||
*/
|
*/
|
||||||
|
@ -11,6 +11,7 @@ Definition of the Theme class.
|
|||||||
, validator = require('is-my-json-valid')
|
, validator = require('is-my-json-valid')
|
||||||
, _ = require('underscore')
|
, _ = require('underscore')
|
||||||
, PATH = require('path')
|
, PATH = require('path')
|
||||||
|
, parsePath = require('parse-filepath')
|
||||||
, EXTEND = require('../utils/extend')
|
, EXTEND = require('../utils/extend')
|
||||||
, moment = require('moment')
|
, moment = require('moment')
|
||||||
, RECURSIVE_READ_DIR = require('recursive-readdir-sync');
|
, RECURSIVE_READ_DIR = require('recursive-readdir-sync');
|
||||||
@ -30,8 +31,8 @@ Definition of the Theme class.
|
|||||||
|
|
||||||
// Open the [theme-name].json file; should have the same name as folder
|
// Open the [theme-name].json file; should have the same name as folder
|
||||||
this.folder = themeFolder;
|
this.folder = themeFolder;
|
||||||
var pathInfo = PATH.parse( themeFolder );
|
var pathInfo = parsePath( themeFolder );
|
||||||
var themeFile = PATH.join( themeFolder, pathInfo.base + '.json' );
|
var themeFile = PATH.join( themeFolder, pathInfo.basename + '.json' );
|
||||||
var themeInfo = JSON.parse( FS.readFileSync( themeFile, 'utf8' ) );
|
var themeInfo = JSON.parse( FS.readFileSync( themeFile, 'utf8' ) );
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ Definition of the Theme class.
|
|||||||
this.formats = formatsHash;
|
this.formats = formatsHash;
|
||||||
|
|
||||||
// Set the official theme name
|
// Set the official theme name
|
||||||
this.name = PATH.parse( this.folder ).name;
|
this.name = parsePath( this.folder ).name;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@ -96,9 +97,9 @@ Definition of the Theme class.
|
|||||||
// If this file lives in a specific format folder within the theme,
|
// If this file lives in a specific format folder within the theme,
|
||||||
// such as "/latex" or "/html", then that format is the output format
|
// such as "/latex" or "/html", then that format is the output format
|
||||||
// for all files within the folder.
|
// for all files within the folder.
|
||||||
var pathInfo = PATH.parse(absPath);
|
var pathInfo = parsePath(absPath);
|
||||||
var outFmt = '', isMajor = false;
|
var outFmt = '', isMajor = false;
|
||||||
var portion = pathInfo.dir.replace(tplFolder,'');
|
var portion = pathInfo.dirname.replace(tplFolder,'');
|
||||||
if( portion && portion.trim() ) {
|
if( portion && portion.trim() ) {
|
||||||
if( portion[1] === '_' ) return;
|
if( portion[1] === '_' ) return;
|
||||||
var reg = /^(?:\/|\\)(html|latex|doc|pdf|partials)(?:\/|\\)?/ig;
|
var reg = /^(?:\/|\\)(html|latex|doc|pdf|partials)(?:\/|\\)?/ig;
|
||||||
@ -135,7 +136,7 @@ Definition of the Theme class.
|
|||||||
path: absPath,
|
path: absPath,
|
||||||
major: isMajor,
|
major: isMajor,
|
||||||
orgPath: PATH.relative(tplFolder, absPath),
|
orgPath: PATH.relative(tplFolder, absPath),
|
||||||
ext: pathInfo.ext.slice(1),
|
ext: pathInfo.extname.slice(1),
|
||||||
title: friendlyName( outFmt ),
|
title: friendlyName( outFmt ),
|
||||||
pre: outFmt,
|
pre: outFmt,
|
||||||
// outFormat: outFmt || pathInfo.name,
|
// outFormat: outFmt || pathInfo.name,
|
||||||
@ -186,7 +187,7 @@ Definition of the Theme class.
|
|||||||
|
|
||||||
act = null;
|
act = null;
|
||||||
// If this file is mentioned in the theme's JSON file under "transforms"
|
// If this file is mentioned in the theme's JSON file under "transforms"
|
||||||
var pathInfo = PATH.parse(absPath);
|
var pathInfo = parsePath(absPath);
|
||||||
var absPathSafe = absPath.trim().toLowerCase();
|
var absPathSafe = absPath.trim().toLowerCase();
|
||||||
var outFmt = _.find( Object.keys( that.formats ), function( fmtKey ) {
|
var outFmt = _.find( Object.keys( that.formats ), function( fmtKey ) {
|
||||||
var fmtVal = that.formats[ fmtKey ];
|
var fmtVal = that.formats[ fmtKey ];
|
||||||
@ -203,7 +204,7 @@ Definition of the Theme class.
|
|||||||
// such as "/latex" or "/html", then that format is the output format
|
// such as "/latex" or "/html", then that format is the output format
|
||||||
// for all files within the folder.
|
// for all files within the folder.
|
||||||
if( !outFmt ) {
|
if( !outFmt ) {
|
||||||
var portion = pathInfo.dir.replace(tplFolder,'');
|
var portion = pathInfo.dirname.replace(tplFolder,'');
|
||||||
if( portion && portion.trim() ) {
|
if( portion && portion.trim() ) {
|
||||||
var reg = /^(?:\/|\\)(html|latex|doc|pdf)(?:\/|\\)?/ig;
|
var reg = /^(?:\/|\\)(html|latex|doc|pdf)(?:\/|\\)?/ig;
|
||||||
var res = reg.exec( portion );
|
var res = reg.exec( portion );
|
||||||
@ -231,7 +232,7 @@ Definition of the Theme class.
|
|||||||
action: act,
|
action: act,
|
||||||
orgPath: PATH.relative(that.folder, absPath),
|
orgPath: PATH.relative(that.folder, absPath),
|
||||||
path: absPath,
|
path: absPath,
|
||||||
ext: pathInfo.ext.slice(1),
|
ext: pathInfo.extname.slice(1),
|
||||||
title: friendlyName( outFmt ),
|
title: friendlyName( outFmt ),
|
||||||
pre: outFmt,
|
pre: outFmt,
|
||||||
// outFormat: outFmt || pathInfo.name,
|
// outFormat: outFmt || pathInfo.name,
|
||||||
|
@ -13,6 +13,7 @@ Definition of the TemplateGenerator class.
|
|||||||
, MD = require( 'marked' )
|
, MD = require( 'marked' )
|
||||||
, XML = require( 'xml-escape' )
|
, XML = require( 'xml-escape' )
|
||||||
, PATH = require('path')
|
, PATH = require('path')
|
||||||
|
, parsePath = require('parse-filepath')
|
||||||
, MKDIRP = require('mkdirp')
|
, MKDIRP = require('mkdirp')
|
||||||
, BaseGenerator = require( './base-generator' )
|
, BaseGenerator = require( './base-generator' )
|
||||||
, EXTEND = require('../utils/extend')
|
, EXTEND = require('../utils/extend')
|
||||||
@ -127,7 +128,7 @@ Definition of the TemplateGenerator class.
|
|||||||
var theme = themeInfo.theme;
|
var theme = themeInfo.theme;
|
||||||
var tFolder = themeInfo.folder;
|
var tFolder = themeInfo.folder;
|
||||||
var tplFolder = PATH.join( tFolder, 'src' );
|
var tplFolder = PATH.join( tFolder, 'src' );
|
||||||
var outFolder = PATH.parse(f).dir;
|
var outFolder = parsePath(f).dirname;
|
||||||
var curFmt = theme.getFormat( this.format );
|
var curFmt = theme.getFormat( this.format );
|
||||||
var that = this;
|
var that = this;
|
||||||
|
|
||||||
@ -176,7 +177,7 @@ Definition of the TemplateGenerator class.
|
|||||||
var absLoc = PATH.join(outFolder, loc);
|
var absLoc = PATH.join(outFolder, loc);
|
||||||
var absTarg = PATH.join(PATH.dirname(absLoc), curFmt.symLinks[loc]);
|
var absTarg = PATH.join(PATH.dirname(absLoc), curFmt.symLinks[loc]);
|
||||||
// 'file', 'dir', or 'junction' (Windows only)
|
// 'file', 'dir', or 'junction' (Windows only)
|
||||||
var type = PATH.parse( absLoc ).ext ? 'file' : 'junction';
|
var type = parsePath( absLoc ).extname ? 'file' : 'junction';
|
||||||
FS.symlinkSync( absTarg, absLoc, type);
|
FS.symlinkSync( absTarg, absLoc, type);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -221,10 +222,10 @@ Definition of the TemplateGenerator class.
|
|||||||
function themeFromMoniker() {
|
function themeFromMoniker() {
|
||||||
// Verify the specified theme name/path
|
// Verify the specified theme name/path
|
||||||
var tFolder = PATH.join(
|
var tFolder = PATH.join(
|
||||||
PATH.parse( require.resolve('fluent-themes') ).dir,
|
parsePath( require.resolve('fluent-themes') ).dirname,
|
||||||
this.opts.theme
|
this.opts.theme
|
||||||
);
|
);
|
||||||
var exists = require('../utils/file-exists');
|
var exists = require('path-exists').sync;
|
||||||
if( !exists( tFolder ) ) {
|
if( !exists( tFolder ) ) {
|
||||||
tFolder = PATH.resolve( this.opts.theme );
|
tFolder = PATH.resolve( this.opts.theme );
|
||||||
if( !exists( tFolder ) ) {
|
if( !exists( tFolder ) ) {
|
||||||
|
@ -91,6 +91,7 @@ function getOpts( args ) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: refactor
|
||||||
function handleError( ex ) {
|
function handleError( ex ) {
|
||||||
var msg = '', exitCode;
|
var msg = '', exitCode;
|
||||||
|
|
||||||
@ -123,8 +124,10 @@ function handleError( ex ) {
|
|||||||
|
|
||||||
var idx = msg.indexOf('Error: ');
|
var idx = msg.indexOf('Error: ');
|
||||||
var trimmed = idx === -1 ? msg : msg.substring( idx + 7 );
|
var trimmed = idx === -1 ? msg : msg.substring( idx + 7 );
|
||||||
if( !ex.fluenterror || ex.fluenterror < 3 )
|
if( !ex.fluenterror || ex.fluenterror < 3 ) { // TODO: magic #s
|
||||||
console.log( ('ERROR: ' + trimmed.toString()).red.bold );
|
console.log( ('ERROR: ' + trimmed.toString()).red.bold );
|
||||||
|
console.log( ex.stack.gray);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
console.log( trimmed.toString() );
|
console.log( trimmed.toString() );
|
||||||
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
/**
|
|
||||||
Definition of the `fileExists` method.
|
|
||||||
@license MIT. Copyright (c) 2015 James Devlin / FluentDesk.
|
|
||||||
@module file-exists.js
|
|
||||||
*/
|
|
||||||
|
|
||||||
var FS = require('fs');
|
|
||||||
|
|
||||||
// Yup, this is now the recommended way to check for file existence on Node.
|
|
||||||
// fs.exists is deprecated and the recommended fs.statSync/lstatSync throws
|
|
||||||
// exceptions on non-existent paths :)
|
|
||||||
module.exports = function (path) {
|
|
||||||
try {
|
|
||||||
FS.statSync( path );
|
|
||||||
return true;
|
|
||||||
} catch( err ) {
|
|
||||||
return !(err && err.code === 'ENOENT');
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,6 +1,7 @@
|
|||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
var PATH = require('path')
|
var PATH = require('path')
|
||||||
|
, parsePath = require('parse-filepath')
|
||||||
, MKDIRP = require('mkdirp')
|
, MKDIRP = require('mkdirp')
|
||||||
, _opts = require('../core/default-options')
|
, _opts = require('../core/default-options')
|
||||||
, FluentTheme = require('../core/theme')
|
, FluentTheme = require('../core/theme')
|
||||||
@ -51,7 +52,7 @@
|
|||||||
// Verify the specified theme name/path
|
// Verify the specified theme name/path
|
||||||
var relativeThemeFolder = '../../node_modules/fluent-themes/themes';
|
var relativeThemeFolder = '../../node_modules/fluent-themes/themes';
|
||||||
var tFolder = PATH.resolve( __dirname, relativeThemeFolder, _opts.theme);
|
var tFolder = PATH.resolve( __dirname, relativeThemeFolder, _opts.theme);
|
||||||
var exists = require('../utils/file-exists');
|
var exists = require('path-exists').sync;
|
||||||
if (!exists( tFolder )) {
|
if (!exists( tFolder )) {
|
||||||
tFolder = PATH.resolve( _opts.theme );
|
tFolder = PATH.resolve( _opts.theme );
|
||||||
if (!exists( tFolder )) {
|
if (!exists( tFolder )) {
|
||||||
@ -60,7 +61,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the theme
|
// Load the theme
|
||||||
var theTheme = new FluentTheme().open( tFolder );
|
var theTheme = (new FluentTheme()).open( tFolder );
|
||||||
_opts.themeObj = theTheme;
|
_opts.themeObj = theTheme;
|
||||||
_log( 'Applying '.info + theTheme.name.toUpperCase().infoBold +
|
_log( 'Applying '.info + theTheme.name.toUpperCase().infoBold +
|
||||||
(' theme (' + Object.keys(theTheme.formats).length + ' formats)').info);
|
(' theme (' + Object.keys(theTheme.formats).length + ' formats)').info);
|
||||||
@ -70,8 +71,8 @@
|
|||||||
( (dst && dst.length && dst) || ['resume.all'] ).forEach( function(t) {
|
( (dst && dst.length && dst) || ['resume.all'] ).forEach( function(t) {
|
||||||
|
|
||||||
var to = PATH.resolve(t),
|
var to = PATH.resolve(t),
|
||||||
pa = PATH.parse(to),
|
pa = parsePath(to),
|
||||||
fmat = pa.ext || '.all';
|
fmat = pa.extname || '.all';
|
||||||
|
|
||||||
targets.push.apply(targets, fmat === '.all' ?
|
targets.push.apply(targets, fmat === '.all' ?
|
||||||
Object.keys( theTheme.formats ).map(function(k){
|
Object.keys( theTheme.formats ).map(function(k){
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
var validator = require('is-my-json-valid');
|
var validator = require('is-my-json-valid');
|
||||||
var schemas = {
|
var schemas = {
|
||||||
fresh: require('FRESCA'),
|
fresh: require('fresca'),
|
||||||
jars: require('../core/resume.json')
|
jars: require('../core/resume.json')
|
||||||
};
|
};
|
||||||
|
|
||||||
|
91
tests/resumes/jrs-0.0.0/empty.json
Normal file
91
tests/resumes/jrs-0.0.0/empty.json
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
{
|
||||||
|
"basics": {
|
||||||
|
"name": "",
|
||||||
|
"label": "",
|
||||||
|
"picture": "",
|
||||||
|
"email": "",
|
||||||
|
"phone": "",
|
||||||
|
"degree": "",
|
||||||
|
"website": "",
|
||||||
|
"summary": "",
|
||||||
|
"location": {
|
||||||
|
"address": "",
|
||||||
|
"postalCode": "",
|
||||||
|
"city": "",
|
||||||
|
"countryCode": "",
|
||||||
|
"region": ""
|
||||||
|
},
|
||||||
|
"profiles": [
|
||||||
|
{
|
||||||
|
"network": "",
|
||||||
|
"username": "",
|
||||||
|
"url": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"work": [
|
||||||
|
{
|
||||||
|
"company": "",
|
||||||
|
"position": "",
|
||||||
|
"website": "",
|
||||||
|
"startDate": "",
|
||||||
|
"endDate": "",
|
||||||
|
"summary": "",
|
||||||
|
"highlights": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"awards": [
|
||||||
|
{
|
||||||
|
"title": "",
|
||||||
|
"date": "",
|
||||||
|
"awarder": "",
|
||||||
|
"summary": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"education": [
|
||||||
|
{
|
||||||
|
"institution": "",
|
||||||
|
"area": "",
|
||||||
|
"studyType": "",
|
||||||
|
"startDate": "",
|
||||||
|
"endDate": "",
|
||||||
|
"gpa": "",
|
||||||
|
"courses": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"publications": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"publisher": "",
|
||||||
|
"releaseDate": "",
|
||||||
|
"website": "",
|
||||||
|
"summary": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"volunteer": [
|
||||||
|
{
|
||||||
|
"organization": "",
|
||||||
|
"position": "",
|
||||||
|
"website": "",
|
||||||
|
"startDate": "",
|
||||||
|
"endDate": "",
|
||||||
|
"summary": "",
|
||||||
|
"highlights": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"skills": [
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"level": "",
|
||||||
|
"keywords": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
104
tests/resumes/jrs-0.0.0/jane-incomplete.json
Normal file
104
tests/resumes/jrs-0.0.0/jane-incomplete.json
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
{
|
||||||
|
"basics": {
|
||||||
|
"name": "Jane Q. Fullstacker"
|
||||||
|
},
|
||||||
|
"education": [
|
||||||
|
{
|
||||||
|
"gpa": "3.5",
|
||||||
|
"courses": [
|
||||||
|
"Course 1",
|
||||||
|
"Course 2",
|
||||||
|
"Course 2"
|
||||||
|
],
|
||||||
|
"startDate": "2005-09",
|
||||||
|
"endDate": "2008-05"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"institution": "Medfield College",
|
||||||
|
"gpa": "3.2",
|
||||||
|
"courses": [
|
||||||
|
"Course 1",
|
||||||
|
"Course 2",
|
||||||
|
"Course 2"
|
||||||
|
],
|
||||||
|
"startDate": "2003-09",
|
||||||
|
"endDate": "2005-06"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"skills": [
|
||||||
|
{
|
||||||
|
"name": "Web Dev",
|
||||||
|
"keywords": [
|
||||||
|
"JavaScript",
|
||||||
|
"HTML 5",
|
||||||
|
"CSS",
|
||||||
|
"LAMP",
|
||||||
|
"MVC",
|
||||||
|
"REST"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "JavaScript"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"volunteer": [],
|
||||||
|
"publications": [
|
||||||
|
{
|
||||||
|
"name": "Building User Interfaces with Electron and Atom",
|
||||||
|
"releaseDate": "2011",
|
||||||
|
"website": "http://codeproject.com/build-ui-electron-atom.aspx"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jane Fullstacker's Blog",
|
||||||
|
"publisher": "self",
|
||||||
|
"releaseDate": "2011",
|
||||||
|
"website": "http://janef.me"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Teach Yourself GORFF in 21 Days",
|
||||||
|
"publisher": "Amazon"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"interests": [
|
||||||
|
{
|
||||||
|
"name": "reading",
|
||||||
|
"summary": "Jane is a fan of mystery novels and courtroom dramas including Agatha Christie and John Grisham.",
|
||||||
|
"keywords": [
|
||||||
|
"mystery",
|
||||||
|
"Agatha Christie",
|
||||||
|
"John Grisham"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "hiking",
|
||||||
|
"summary": "Jane enjoys hiking, light mountain climbing, and has four summits under her belt!"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "yoga"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"name": "John Davidson",
|
||||||
|
"reference": "Jane is awesome! I'd hire her again in a heartbeat."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Elias Fullstacker",
|
||||||
|
"reference": "I worked with Jane on Jabberwocky and can vouch for her awesome technical capabilities and attention to detail. Insta-hire."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dana Nevins",
|
||||||
|
"reference": "I've known Jane personally and professionally for almost ten years. She is one in a million."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"languages": [
|
||||||
|
{
|
||||||
|
"language": "English",
|
||||||
|
"level": "Native"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"language": "Spanish",
|
||||||
|
"level": "Moderate"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -18,7 +18,7 @@ describe('FRESH/JRS converter', function () {
|
|||||||
|
|
||||||
it('should round-trip from JRS to FRESH to JRS without modifying or losing data', function () {
|
it('should round-trip from JRS to FRESH to JRS without modifying or losing data', function () {
|
||||||
|
|
||||||
var fileA = path.join( __dirname, 'resumes/jrs/richard-hendriks.json' );
|
var fileA = path.join( __dirname, 'resumes/jrs-0.0.0/richard-hendriks.json' );
|
||||||
var fileB = path.join( __dirname, 'sandbox/richard-hendriks.json' );
|
var fileB = path.join( __dirname, 'sandbox/richard-hendriks.json' );
|
||||||
|
|
||||||
_sheet = new FRESHResume().open( fileA );
|
_sheet = new FRESHResume().open( fileA );
|
||||||
|
@ -55,7 +55,7 @@ describe('jane-doe.json (FRESH)', function () {
|
|||||||
|
|
||||||
it('should validate against the FRESH resume schema', function() {
|
it('should validate against the FRESH resume schema', function() {
|
||||||
var result = _sheet.isValid();
|
var result = _sheet.isValid();
|
||||||
// var schemaJson = require('FRESCA');
|
// var schemaJson = require('fresca');
|
||||||
// var validate = validator( schemaJson, { verbose: true } );
|
// var validate = validator( schemaJson, { verbose: true } );
|
||||||
// var result = validate( JSON.parse( _sheet.imp.raw ) );
|
// var result = validate( JSON.parse( _sheet.imp.raw ) );
|
||||||
result || console.log("\n\nOops, resume didn't validate. " +
|
result || console.log("\n\nOops, resume didn't validate. " +
|
||||||
|
@ -9,55 +9,61 @@ var chai = require('chai')
|
|||||||
|
|
||||||
chai.config.includeStack = false;
|
chai.config.includeStack = false;
|
||||||
|
|
||||||
describe('jane-doe.json (JRS)', function () {
|
function testResume( opts ) {
|
||||||
|
|
||||||
|
describe( opts.title + ' (JRS)', function() {
|
||||||
|
|
||||||
|
opts.isValid = opts.isValid !== false;
|
||||||
|
|
||||||
var _sheet;
|
var _sheet;
|
||||||
|
|
||||||
it('should open without throwing an exception', function () {
|
it('should open without throwing an exception', function () {
|
||||||
|
var that = this;
|
||||||
function tryOpen() {
|
function tryOpen() {
|
||||||
_sheet = new JRSResume().open(
|
_sheet = new JRSResume().open(
|
||||||
path.join( __dirname, 'resumes/jrs/jane-q-fullstacker.json' ) );
|
path.join( __dirname, 'resumes/jrs-0.0.0/' + opts.title + '.json' ) );
|
||||||
}
|
}
|
||||||
tryOpen.should.not.Throw();
|
tryOpen.should.not.Throw();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have one or more of each section', function() {
|
it('should have one or more of each section', function() {
|
||||||
expect(
|
var newObj = _.pick( _sheet, opts.sections );
|
||||||
(_sheet.basics) &&
|
expect( Object.keys(newObj).length ).to.equal( opts.sections.length );
|
||||||
(_sheet.work && _sheet.work.length > 0) &&
|
|
||||||
(_sheet.skills && _sheet.skills.length > 0) &&
|
|
||||||
(_sheet.education && _sheet.education.length > 0) &&
|
|
||||||
(_sheet.volunteer && _sheet.volunteer.length > 0) &&
|
|
||||||
(_sheet.publications && _sheet.publications.length > 0) &&
|
|
||||||
(_sheet.awards && _sheet.awards.length > 0)
|
|
||||||
).to.equal( true );
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should have a work duration of 7 years', function() {
|
it('should have a work duration of ' + opts.duration + ' years', function() {
|
||||||
_sheet.basics.computed.numYears.should.equal( 7 );
|
_sheet.basics.computed.numYears.should.equal( opts.duration );
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should save without throwing an exception', function(){
|
it('should save without throwing an exception', function() {
|
||||||
|
var that = this;
|
||||||
function trySave() {
|
function trySave() {
|
||||||
_sheet.save( 'tests/sandbox/jane-q-fullstacker.json' );
|
_sheet.save( 'tests/sandbox/' + opts.title + '.json' );
|
||||||
}
|
}
|
||||||
trySave.should.not.Throw();
|
trySave.should.not.Throw();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not be modified after saving', function() {
|
it('should not be modified after saving', function() {
|
||||||
var savedSheet = new JRSResume().open( 'tests/sandbox/jane-q-fullstacker.json' );
|
var savedSheet = new JRSResume().open( 'tests/sandbox/' + opts.title + '.json' );
|
||||||
_sheet.stringify().should.equal( savedSheet.stringify() )
|
_sheet.stringify().should.equal( savedSheet.stringify() )
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should validate against the JSON Resume schema', function() {
|
it('should ' + (opts.isValid ? '' : 'NOT ') + 'validate against the JSON Resume schema', function() {
|
||||||
var result = _sheet.isValid();
|
var result = _sheet.isValid();
|
||||||
// var schemaJson = require('../src/core/resume.json');
|
// var schemaJson = require('../src/core/resume.json');
|
||||||
// var validate = validator( schemaJson, { verbose: true } );
|
// var validate = validator( schemaJson, { verbose: true } );
|
||||||
// var result = validate( JSON.parse( _sheet.imp.raw ) );
|
// var result = validate( JSON.parse( _sheet.imp.raw ) );
|
||||||
result || console.log("\n\nOops, resume didn't validate. " +
|
result || console.log("\n\nOops, resume didn't validate. " +
|
||||||
"Validation errors:\n\n", _sheet.basics.imp.validationErrors, "\n\n");
|
"Validation errors:\n\n", _sheet.basics.imp.validationErrors, "\n\n");
|
||||||
result.should.equal( true );
|
result.should.equal( opts.isValid );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
});
|
var sects = [ 'basics', 'work', 'volunteer', 'skills', 'education', 'publications', 'awards', 'references' ];
|
||||||
|
|
||||||
|
testResume({ title: 'jane-q-fullstacker', duration: 7, sections: sects });
|
||||||
|
testResume({ title: 'jane-incomplete', duration: 0, sections: _.without(sects, 'awards', 'work') });
|
||||||
|
testResume({ title: 'richard-hendriks', duration: 1, sections: sects });
|
||||||
|
testResume({ title: 'empty', duration: 0, sections: [], isValid: false });
|
||||||
|
Reference in New Issue
Block a user