mirror of
https://github.com/JuanCanham/HackMyResume.git
synced 2024-11-24 01:10:11 +00:00
chore: decaffeinate: fix eslint violations
This commit is contained in:
parent
8a46d642e5
commit
42d249b407
@ -17,13 +17,10 @@ const extend = require('extend');
|
|||||||
let validator = require('is-my-json-valid');
|
let validator = require('is-my-json-valid');
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const __ = require('lodash');
|
const __ = require('lodash');
|
||||||
const PATH = require('path');
|
|
||||||
const moment = require('moment');
|
|
||||||
const XML = require('xml-escape');
|
const XML = require('xml-escape');
|
||||||
const MD = require('marked');
|
const MD = require('marked');
|
||||||
const CONVERTER = require('fresh-jrs-converter');
|
const CONVERTER = require('fresh-jrs-converter');
|
||||||
const JRSResume = require('./jrs-resume');
|
const JRSResume = require('./jrs-resume');
|
||||||
const FluentDate = require('./fluent-date');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -62,9 +59,9 @@ class FreshResume {// extends AbstractResume
|
|||||||
let scrubbed;
|
let scrubbed;
|
||||||
if (opts && opts.privatize) {
|
if (opts && opts.privatize) {
|
||||||
// Ignore any element with the 'ignore: true' or 'private: true' designator.
|
// Ignore any element with the 'ignore: true' or 'private: true' designator.
|
||||||
let ignoreList, privateList;
|
|
||||||
const scrubber = require('../utils/resume-scrubber');
|
const scrubber = require('../utils/resume-scrubber');
|
||||||
({ scrubbed, ignoreList, privateList } = scrubber.scrubResume(rep, opts));
|
var ret = scrubber.scrubResume(rep, opts);
|
||||||
|
scrubbed = ret.scrubbed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now apply the resume representation onto this object
|
// Now apply the resume representation onto this object
|
||||||
@ -287,11 +284,11 @@ class FreshResume {// extends AbstractResume
|
|||||||
const defSheet = FreshResume.default();
|
const defSheet = FreshResume.default();
|
||||||
const newObject =
|
const newObject =
|
||||||
defSheet[moniker].history
|
defSheet[moniker].history
|
||||||
? $.extend( true, {}, defSheet[ moniker ].history[0] )
|
? extend( true, {}, defSheet[ moniker ].history[0] )
|
||||||
:
|
:
|
||||||
moniker === 'skills'
|
moniker === 'skills'
|
||||||
? $.extend( true, {}, defSheet.skills.sets[0] )
|
? extend( true, {}, defSheet.skills.sets[0] )
|
||||||
: $.extend( true, {}, defSheet[ moniker ][0] );
|
: extend( true, {}, defSheet[ moniker ][0] );
|
||||||
|
|
||||||
this[ moniker ] = this[ moniker ] || [];
|
this[ moniker ] = this[ moniker ] || [];
|
||||||
if (this[ moniker ].history) {
|
if (this[ moniker ].history) {
|
||||||
@ -346,7 +343,7 @@ class FreshResume {// extends AbstractResume
|
|||||||
|
|
||||||
|
|
||||||
/** Validate the sheet against the FRESH Resume schema. */
|
/** Validate the sheet against the FRESH Resume schema. */
|
||||||
isValid( info ) {
|
isValid() {
|
||||||
const schemaObj = require('fresh-resume-schema');
|
const schemaObj = require('fresh-resume-schema');
|
||||||
validator = require('is-my-json-valid');
|
validator = require('is-my-json-valid');
|
||||||
const validate = validator( schemaObj, { // See Note [1].
|
const validate = validator( schemaObj, { // See Note [1].
|
||||||
@ -385,7 +382,7 @@ class FreshResume {// extends AbstractResume
|
|||||||
const sortSection = function( key ) {
|
const sortSection = function( key ) {
|
||||||
const ar = __.get(this, key);
|
const ar = __.get(this, key);
|
||||||
if (ar && ar.length) {
|
if (ar && ar.length) {
|
||||||
const datedThings = obj.filter(o => o.start);
|
const datedThings = ar.filter(o => o.start);
|
||||||
return datedThings.sort( byDateDesc );
|
return datedThings.sort( byDateDesc );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -14,14 +14,11 @@ Definition of the FRESHTheme class.
|
|||||||
|
|
||||||
|
|
||||||
const FS = require('fs');
|
const FS = require('fs');
|
||||||
const validator = require('is-my-json-valid');
|
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const PATH = require('path');
|
const PATH = require('path');
|
||||||
const parsePath = require('parse-filepath');
|
const parsePath = require('parse-filepath');
|
||||||
const pathExists = require('path-exists').sync;
|
|
||||||
const EXTEND = require('extend');
|
const EXTEND = require('extend');
|
||||||
const HMSTATUS = require('./status-codes');
|
const HMSTATUS = require('./status-codes');
|
||||||
const moment = require('moment');
|
|
||||||
const loadSafeJson = require('../utils/safe-json-loader');
|
const loadSafeJson = require('../utils/safe-json-loader');
|
||||||
const READFILES = require('recursive-readdir-sync');
|
const READFILES = require('recursive-readdir-sync');
|
||||||
|
|
||||||
@ -40,9 +37,6 @@ class FRESHTheme {
|
|||||||
|
|
||||||
this.folder = themeFolder;
|
this.folder = themeFolder;
|
||||||
|
|
||||||
// Open the [theme-name].json file; should have the same name as folder
|
|
||||||
const pathInfo = parsePath(themeFolder);
|
|
||||||
|
|
||||||
// Set up a formats hash for the theme
|
// Set up a formats hash for the theme
|
||||||
let formatsHash = { };
|
let formatsHash = { };
|
||||||
|
|
||||||
@ -59,8 +53,6 @@ class FRESHTheme {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const that = this;
|
|
||||||
|
|
||||||
// Move properties from the theme JSON file to the theme object
|
// Move properties from the theme JSON file to the theme object
|
||||||
EXTEND(true, this, themeInfo.json);
|
EXTEND(true, this, themeInfo.json);
|
||||||
|
|
||||||
@ -116,11 +108,8 @@ class FRESHTheme {
|
|||||||
var _load = function(formatsHash) {
|
var _load = function(formatsHash) {
|
||||||
|
|
||||||
const that = this;
|
const that = this;
|
||||||
const major = false;
|
|
||||||
const tplFolder = PATH.join(this.folder, this.baseFolder);
|
const tplFolder = PATH.join(this.folder, this.baseFolder);
|
||||||
|
|
||||||
const copyOnly = ['.ttf','.otf', '.png','.jpg','.jpeg','.pdf'];
|
|
||||||
|
|
||||||
// Iterate over all files in the theme folder, producing an array, fmts,
|
// Iterate over all files in the theme folder, producing an array, fmts,
|
||||||
// containing info for each file. While we're doing that, also build up
|
// containing info for each file. While we're doing that, also build up
|
||||||
// the formatsHash object.
|
// the formatsHash object.
|
||||||
|
@ -18,9 +18,7 @@ const extend = require('extend');
|
|||||||
let validator = require('is-my-json-valid');
|
let validator = require('is-my-json-valid');
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const PATH = require('path');
|
const PATH = require('path');
|
||||||
const MD = require('marked');
|
|
||||||
const CONVERTER = require('fresh-jrs-converter');
|
const CONVERTER = require('fresh-jrs-converter');
|
||||||
const moment = require('moment');
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,270 +26,268 @@ A JRS resume or CV. JRS resumes are backed by JSON, and each JRSResume object
|
|||||||
is an instantiation of that JSON decorated with utility methods.
|
is an instantiation of that JSON decorated with utility methods.
|
||||||
@class JRSResume
|
@class JRSResume
|
||||||
*/
|
*/
|
||||||
var JRSResume = (function() {
|
|
||||||
let clear = undefined;
|
|
||||||
JRSResume = class JRSResume {
|
class JRSResume {
|
||||||
static initClass() {
|
|
||||||
|
static initClass() {
|
||||||
|
/** Reset the sheet to an empty state. */
|
||||||
|
// clear = function( clearMeta ) {
|
||||||
|
// clearMeta = ((clearMeta === undefined) && true) || clearMeta;
|
||||||
|
// if (clearMeta) { delete this.imp; }
|
||||||
|
// delete this.basics.computed; // Don't use Object.keys() here
|
||||||
|
// delete this.work;
|
||||||
|
// delete this.volunteer;
|
||||||
|
// delete this.education;
|
||||||
|
// delete this.awards;
|
||||||
|
// delete this.publications;
|
||||||
|
// delete this.interests;
|
||||||
|
// delete this.skills;
|
||||||
|
// return delete this.basics.profiles;
|
||||||
|
// };
|
||||||
|
// extends AbstractResume
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Reset the sheet to an empty state. */
|
/** Initialize the the JSResume from string. */
|
||||||
clear = function( clearMeta ) {
|
parse( stringData, opts ) {
|
||||||
clearMeta = ((clearMeta === undefined) && true) || clearMeta;
|
this.imp = this.imp != null ? this.imp : {raw: stringData};
|
||||||
if (clearMeta) { delete this.imp; }
|
return this.parseJSON(JSON.parse( stringData ), opts);
|
||||||
delete this.basics.computed; // Don't use Object.keys() here
|
}
|
||||||
delete this.work;
|
|
||||||
delete this.volunteer;
|
|
||||||
delete this.education;
|
|
||||||
delete this.awards;
|
/**
|
||||||
delete this.publications;
|
Initialize the JRSResume object from JSON.
|
||||||
delete this.interests;
|
Open and parse the specified JRS resume. Merge the JSON object model onto
|
||||||
delete this.skills;
|
this Sheet instance with extend() and convert sheet dates to a safe &
|
||||||
return delete this.basics.profiles;
|
consistent format. Then sort each section by startDate descending.
|
||||||
};
|
@param rep {Object} The raw JSON representation.
|
||||||
// extends AbstractResume
|
@param opts {Object} Resume loading and parsing options.
|
||||||
|
{
|
||||||
|
date: Perform safe date conversion.
|
||||||
|
sort: Sort resume items by date.
|
||||||
|
compute: Prepare computed resume totals.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
parseJSON( rep, opts ) {
|
||||||
|
let scrubbed;
|
||||||
|
opts = opts || { };
|
||||||
|
if (opts.privatize) {
|
||||||
|
const scrubber = require('../utils/resume-scrubber');
|
||||||
|
// Ignore any element with the 'ignore: true' or 'private: true' designator.
|
||||||
|
var ret = scrubber.scrubResume(rep, opts);
|
||||||
|
scrubbed = ret.scrubbed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extend resume properties onto ourself.
|
||||||
|
extend(true, this, opts.privatize ? scrubbed : rep);
|
||||||
|
|
||||||
|
// Set up metadata
|
||||||
/** Initialize the the JSResume from string. */
|
if (!(this.imp != null ? this.imp.processed : undefined)) {
|
||||||
parse( stringData, opts ) {
|
// Set up metadata TODO: Clean up metadata on the object model.
|
||||||
this.imp = this.imp != null ? this.imp : {raw: stringData};
|
|
||||||
return this.parseJSON(JSON.parse( stringData ), opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Initialize the JRSResume object from JSON.
|
|
||||||
Open and parse the specified JRS resume. Merge the JSON object model onto
|
|
||||||
this Sheet instance with extend() and convert sheet dates to a safe &
|
|
||||||
consistent format. Then sort each section by startDate descending.
|
|
||||||
@param rep {Object} The raw JSON representation.
|
|
||||||
@param opts {Object} Resume loading and parsing options.
|
|
||||||
{
|
|
||||||
date: Perform safe date conversion.
|
|
||||||
sort: Sort resume items by date.
|
|
||||||
compute: Prepare computed resume totals.
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
parseJSON( rep, opts ) {
|
|
||||||
let scrubbed;
|
|
||||||
opts = opts || { };
|
opts = opts || { };
|
||||||
if (opts.privatize) {
|
if ((opts.imp === undefined) || opts.imp) {
|
||||||
let ignoreList, privateList;
|
|
||||||
const scrubber = require('../utils/resume-scrubber');
|
|
||||||
// Ignore any element with the 'ignore: true' or 'private: true' designator.
|
|
||||||
({ scrubbed, ignoreList, privateList } = scrubber.scrubResume(rep, opts));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extend resume properties onto ourself.
|
|
||||||
extend(true, this, opts.privatize ? scrubbed : rep);
|
|
||||||
|
|
||||||
// Set up metadata
|
|
||||||
if (!(this.imp != null ? this.imp.processed : undefined)) {
|
|
||||||
// Set up metadata TODO: Clean up metadata on the object model.
|
|
||||||
opts = opts || { };
|
|
||||||
if ((opts.imp === undefined) || opts.imp) {
|
|
||||||
this.imp = this.imp || { };
|
|
||||||
this.imp.title = (opts.title || this.imp.title) || this.basics.name;
|
|
||||||
if (!this.imp.raw) {
|
|
||||||
this.imp.raw = JSON.stringify(rep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.imp.processed = true;
|
|
||||||
}
|
|
||||||
// Parse dates, sort dates, and calculate computed values
|
|
||||||
((opts.date === undefined) || opts.date) && _parseDates.call( this );
|
|
||||||
((opts.sort === undefined) || opts.sort) && this.sort();
|
|
||||||
if ((opts.compute === undefined) || opts.compute) {
|
|
||||||
this.basics.computed = {
|
|
||||||
numYears: this.duration(),
|
|
||||||
keywords: this.keywords()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Save the sheet to disk (for environments that have disk access). */
|
|
||||||
save( filename ) {
|
|
||||||
this.imp.file = filename || this.imp.file;
|
|
||||||
FS.writeFileSync(this.imp.file, this.stringify( this ), 'utf8');
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Save the sheet to disk in a specific format, either FRESH or JRS. */
|
|
||||||
saveAs( filename, format ) {
|
|
||||||
if (format === 'JRS') {
|
|
||||||
this.imp.file = filename || this.imp.file;
|
|
||||||
FS.writeFileSync( this.imp.file, this.stringify(), 'utf8' );
|
|
||||||
} else {
|
|
||||||
const newRep = CONVERTER.toFRESH(this);
|
|
||||||
const stringRep = CONVERTER.toSTRING(newRep);
|
|
||||||
FS.writeFileSync(filename, stringRep, 'utf8');
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Return the resume format. */
|
|
||||||
format() { return 'JRS'; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
stringify() { return JRSResume.stringify( this ); }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Return a unique list of all keywords across all skills. */
|
|
||||||
keywords() {
|
|
||||||
let flatSkills = [];
|
|
||||||
if (this.skills && this.skills.length) {
|
|
||||||
this.skills.forEach( s => flatSkills = _.union(flatSkills, s.keywords));
|
|
||||||
}
|
|
||||||
return flatSkills;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Return internal metadata. Create if it doesn't exist.
|
|
||||||
JSON Resume v0.0.0 doesn't allow additional properties at the root level,
|
|
||||||
so tuck this into the .basic sub-object.
|
|
||||||
*/
|
|
||||||
i() {
|
|
||||||
return this.imp = this.imp != null ? this.imp : { };
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Add work experience to the sheet. */
|
|
||||||
add( moniker ) {
|
|
||||||
const defSheet = JRSResume.default();
|
|
||||||
const newObject = $.extend( true, {}, defSheet[ moniker ][0] );
|
|
||||||
this[ moniker ] = this[ moniker ] || [];
|
|
||||||
this[ moniker ].push( newObject );
|
|
||||||
return newObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Determine if the sheet includes a specific social profile (eg, GitHub). */
|
|
||||||
hasProfile( socialNetwork ) {
|
|
||||||
socialNetwork = socialNetwork.trim().toLowerCase();
|
|
||||||
return this.basics.profiles && _.some(this.basics.profiles, p => p.network.trim().toLowerCase() === socialNetwork);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Determine if the sheet includes a specific skill. */
|
|
||||||
hasSkill( skill ) {
|
|
||||||
skill = skill.trim().toLowerCase();
|
|
||||||
return this.skills && _.some(this.skills, sk =>
|
|
||||||
sk.keywords && _.some(sk.keywords, kw => kw.trim().toLowerCase() === skill)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Validate the sheet against the JSON Resume schema. */
|
|
||||||
isValid( ) { // TODO: ↓ fix this path ↓
|
|
||||||
const schema = FS.readFileSync(PATH.join( __dirname, 'resume.json' ), 'utf8');
|
|
||||||
const schemaObj = JSON.parse(schema);
|
|
||||||
validator = require('is-my-json-valid');
|
|
||||||
const validate = validator( schemaObj, { // Note [1]
|
|
||||||
formats: { date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ }
|
|
||||||
});
|
|
||||||
const temp = this.imp;
|
|
||||||
delete this.imp;
|
|
||||||
const ret = validate(this);
|
|
||||||
this.imp = temp;
|
|
||||||
if (!ret) {
|
|
||||||
this.imp = this.imp || { };
|
this.imp = this.imp || { };
|
||||||
this.imp.validationErrors = validate.errors;
|
this.imp.title = (opts.title || this.imp.title) || this.basics.name;
|
||||||
|
if (!this.imp.raw) {
|
||||||
|
this.imp.raw = JSON.stringify(rep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
this.imp.processed = true;
|
||||||
}
|
}
|
||||||
|
// Parse dates, sort dates, and calculate computed values
|
||||||
|
((opts.date === undefined) || opts.date) && _parseDates.call( this );
|
||||||
|
((opts.sort === undefined) || opts.sort) && this.sort();
|
||||||
duration(unit) {
|
if ((opts.compute === undefined) || opts.compute) {
|
||||||
const inspector = require('../inspectors/duration-inspector');
|
this.basics.computed = {
|
||||||
return inspector.run(this, 'work', 'startDate', 'endDate', unit);
|
numYears: this.duration(),
|
||||||
}
|
keywords: this.keywords()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Sort dated things on the sheet by start date descending. Assumes that dates
|
|
||||||
on the sheet have been processed with _parseDates().
|
|
||||||
*/
|
|
||||||
sort( ) {
|
|
||||||
|
|
||||||
const byDateDesc = function(a,b) {
|
|
||||||
if (a.safeStartDate.isBefore(b.safeStartDate)) {
|
|
||||||
return 1;
|
|
||||||
} else { return ( a.safeStartDate.isAfter(b.safeStartDate) && -1 ) || 0; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.work && this.work.sort(byDateDesc);
|
|
||||||
this.education && this.education.sort(byDateDesc);
|
|
||||||
this.volunteer && this.volunteer.sort(byDateDesc);
|
|
||||||
|
|
||||||
this.awards && this.awards.sort(function(a, b) {
|
|
||||||
if (a.safeDate.isBefore(b.safeDate)) {
|
|
||||||
return 1;
|
|
||||||
} else { return (a.safeDate.isAfter(b.safeDate) && -1 ) || 0; }
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.publications && this.publications.sort(function(a, b) {
|
|
||||||
if ( a.safeReleaseDate.isBefore(b.safeReleaseDate) ) {
|
|
||||||
return 1;
|
|
||||||
} else { return ( a.safeReleaseDate.isAfter(b.safeReleaseDate) && -1 ) || 0; }
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dupe() {
|
/** Save the sheet to disk (for environments that have disk access). */
|
||||||
const rnew = new JRSResume();
|
save( filename ) {
|
||||||
rnew.parse(this.stringify(), { });
|
this.imp.file = filename || this.imp.file;
|
||||||
return rnew;
|
FS.writeFileSync(this.imp.file, this.stringify( this ), 'utf8');
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Save the sheet to disk in a specific format, either FRESH or JRS. */
|
||||||
|
saveAs( filename, format ) {
|
||||||
|
if (format === 'JRS') {
|
||||||
|
this.imp.file = filename || this.imp.file;
|
||||||
|
FS.writeFileSync( this.imp.file, this.stringify(), 'utf8' );
|
||||||
|
} else {
|
||||||
|
const newRep = CONVERTER.toFRESH(this);
|
||||||
|
const stringRep = CONVERTER.toSTRING(newRep);
|
||||||
|
FS.writeFileSync(filename, stringRep, 'utf8');
|
||||||
}
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/** Return the resume format. */
|
||||||
Create a copy of this resume in which all fields have been interpreted as
|
format() { return 'JRS'; }
|
||||||
Markdown.
|
|
||||||
*/
|
|
||||||
harden() {
|
|
||||||
|
|
||||||
const ret = this.dupe();
|
|
||||||
|
|
||||||
const HD = txt => `@@@@~${txt}~@@@@`;
|
|
||||||
|
|
||||||
const HDIN = txt =>
|
stringify() { return JRSResume.stringify( this ); }
|
||||||
//return MD(txt || '' ).replace(/^\s*<p>|<\/p>\s*$/gi, '');
|
|
||||||
HD(txt)
|
|
||||||
;
|
|
||||||
|
|
||||||
const transformer = require('../utils/string-transformer');
|
|
||||||
return transformer(ret,
|
|
||||||
[ 'skills','url','website','startDate','endDate', 'releaseDate', 'date',
|
/** Return a unique list of all keywords across all skills. */
|
||||||
'phone','email','address','postalCode','city','country','region',
|
keywords() {
|
||||||
'safeStartDate','safeEndDate' ],
|
let flatSkills = [];
|
||||||
(key, val) => HD(val));
|
if (this.skills && this.skills.length) {
|
||||||
|
this.skills.forEach( s => flatSkills = _.union(flatSkills, s.keywords));
|
||||||
}
|
}
|
||||||
};
|
return flatSkills;
|
||||||
JRSResume.initClass();
|
}
|
||||||
return JRSResume;
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return internal metadata. Create if it doesn't exist.
|
||||||
|
JSON Resume v0.0.0 doesn't allow additional properties at the root level,
|
||||||
|
so tuck this into the .basic sub-object.
|
||||||
|
*/
|
||||||
|
i() {
|
||||||
|
return this.imp = this.imp != null ? this.imp : { };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Add work experience to the sheet. */
|
||||||
|
add( moniker ) {
|
||||||
|
const defSheet = JRSResume.default();
|
||||||
|
const newObject = extend( true, {}, defSheet[ moniker ][0] );
|
||||||
|
this[ moniker ] = this[ moniker ] || [];
|
||||||
|
this[ moniker ].push( newObject );
|
||||||
|
return newObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Determine if the sheet includes a specific social profile (eg, GitHub). */
|
||||||
|
hasProfile( socialNetwork ) {
|
||||||
|
socialNetwork = socialNetwork.trim().toLowerCase();
|
||||||
|
return this.basics.profiles && _.some(this.basics.profiles, p => p.network.trim().toLowerCase() === socialNetwork);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Determine if the sheet includes a specific skill. */
|
||||||
|
hasSkill( skill ) {
|
||||||
|
skill = skill.trim().toLowerCase();
|
||||||
|
return this.skills && _.some(this.skills, sk =>
|
||||||
|
sk.keywords && _.some(sk.keywords, kw => kw.trim().toLowerCase() === skill)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Validate the sheet against the JSON Resume schema. */
|
||||||
|
isValid( ) { // TODO: ↓ fix this path ↓
|
||||||
|
const schema = FS.readFileSync(PATH.join( __dirname, 'resume.json' ), 'utf8');
|
||||||
|
const schemaObj = JSON.parse(schema);
|
||||||
|
validator = require('is-my-json-valid');
|
||||||
|
const validate = validator( schemaObj, { // Note [1]
|
||||||
|
formats: { date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ }
|
||||||
|
});
|
||||||
|
const temp = this.imp;
|
||||||
|
delete this.imp;
|
||||||
|
const ret = validate(this);
|
||||||
|
this.imp = temp;
|
||||||
|
if (!ret) {
|
||||||
|
this.imp = this.imp || { };
|
||||||
|
this.imp.validationErrors = validate.errors;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
duration(unit) {
|
||||||
|
const inspector = require('../inspectors/duration-inspector');
|
||||||
|
return inspector.run(this, 'work', 'startDate', 'endDate', unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sort dated things on the sheet by start date descending. Assumes that dates
|
||||||
|
on the sheet have been processed with _parseDates().
|
||||||
|
*/
|
||||||
|
sort( ) {
|
||||||
|
|
||||||
|
const byDateDesc = function(a,b) {
|
||||||
|
if (a.safeStartDate.isBefore(b.safeStartDate)) {
|
||||||
|
return 1;
|
||||||
|
} else { return ( a.safeStartDate.isAfter(b.safeStartDate) && -1 ) || 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
this.work && this.work.sort(byDateDesc);
|
||||||
|
this.education && this.education.sort(byDateDesc);
|
||||||
|
this.volunteer && this.volunteer.sort(byDateDesc);
|
||||||
|
|
||||||
|
this.awards && this.awards.sort(function(a, b) {
|
||||||
|
if (a.safeDate.isBefore(b.safeDate)) {
|
||||||
|
return 1;
|
||||||
|
} else { return (a.safeDate.isAfter(b.safeDate) && -1 ) || 0; }
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.publications && this.publications.sort(function(a, b) {
|
||||||
|
if ( a.safeReleaseDate.isBefore(b.safeReleaseDate) ) {
|
||||||
|
return 1;
|
||||||
|
} else { return ( a.safeReleaseDate.isAfter(b.safeReleaseDate) && -1 ) || 0; }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
dupe() {
|
||||||
|
const rnew = new JRSResume();
|
||||||
|
rnew.parse(this.stringify(), { });
|
||||||
|
return rnew;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Create a copy of this resume in which all fields have been interpreted as
|
||||||
|
Markdown.
|
||||||
|
*/
|
||||||
|
harden() {
|
||||||
|
|
||||||
|
const ret = this.dupe();
|
||||||
|
|
||||||
|
const HD = txt => `@@@@~${txt}~@@@@`;
|
||||||
|
|
||||||
|
// const HDIN = txt =>
|
||||||
|
// //return MD(txt || '' ).replace(/^\s*<p>|<\/p>\s*$/gi, '');
|
||||||
|
// HD(txt)
|
||||||
|
// ;
|
||||||
|
|
||||||
|
const transformer = require('../utils/string-transformer');
|
||||||
|
return transformer(ret,
|
||||||
|
[ 'skills','url','website','startDate','endDate', 'releaseDate', 'date',
|
||||||
|
'phone','email','address','postalCode','city','country','region',
|
||||||
|
'safeStartDate','safeEndDate' ],
|
||||||
|
(key, val) => HD(val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JRSResume.initClass();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -347,6 +343,6 @@ var _parseDates = function() {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Export the JRSResume function/ctor.
|
Export the JRSResume class.
|
||||||
*/
|
*/
|
||||||
module.exports = JRSResume;
|
module.exports = JRSResume;
|
||||||
|
@ -13,7 +13,6 @@ Definition of the JRSTheme class.
|
|||||||
|
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const PATH = require('path');
|
const PATH = require('path');
|
||||||
const parsePath = require('parse-filepath');
|
|
||||||
const pathExists = require('path-exists').sync;
|
const pathExists = require('path-exists').sync;
|
||||||
const errors = require('./status-codes');
|
const errors = require('./status-codes');
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ class JRSTheme {
|
|||||||
open( thFolder ) {
|
open( thFolder ) {
|
||||||
|
|
||||||
this.folder = thFolder;
|
this.folder = thFolder;
|
||||||
const pathInfo = parsePath(thFolder);
|
//const pathInfo = parsePath(thFolder);
|
||||||
|
|
||||||
// Open and parse the theme's package.json file
|
// Open and parse the theme's package.json file
|
||||||
const pkgJsonPath = PATH.join(thFolder, 'package.json');
|
const pkgJsonPath = PATH.join(thFolder, 'package.json');
|
||||||
|
@ -15,9 +15,6 @@ const FS = require('fs');
|
|||||||
const HMS = require('./status-codes');
|
const HMS = require('./status-codes');
|
||||||
const HME = require('./event-codes');
|
const HME = require('./event-codes');
|
||||||
const ResumeConverter = require('fresh-jrs-converter');
|
const ResumeConverter = require('fresh-jrs-converter');
|
||||||
const chalk = require('chalk');
|
|
||||||
const SyntaxErrorEx = require('../utils/syntax-error-ex');
|
|
||||||
const _ = require('underscore');
|
|
||||||
const resumeDetect = require('../utils/resume-detector');
|
const resumeDetect = require('../utils/resume-detector');
|
||||||
require('string.prototype.startswith');
|
require('string.prototype.startswith');
|
||||||
|
|
||||||
@ -28,7 +25,7 @@ A simple factory class for FRESH and JSON Resumes.
|
|||||||
@class ResumeFactory
|
@class ResumeFactory
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const ResumeFactory = (module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -96,7 +93,7 @@ const ResumeFactory = (module.exports = {
|
|||||||
rez
|
rez
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
var _parse = function( fileName, opts, eve ) {
|
var _parse = function( fileName, opts, eve ) {
|
||||||
|
@ -11,16 +11,13 @@ Definition of the HTMLGenerator class.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let HtmlGenerator;
|
|
||||||
const TemplateGenerator = require('./template-generator');
|
const TemplateGenerator = require('./template-generator');
|
||||||
const FS = require('fs-extra');
|
|
||||||
const HTML = require('html');
|
const HTML = require('html');
|
||||||
const PATH = require('path');
|
|
||||||
require('string.prototype.endswith');
|
require('string.prototype.endswith');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = (HtmlGenerator = class HtmlGenerator extends TemplateGenerator {
|
class HtmlGenerator extends TemplateGenerator {
|
||||||
|
|
||||||
constructor() { super('html'); }
|
constructor() { super('html'); }
|
||||||
|
|
||||||
@ -36,4 +33,7 @@ module.exports = (HtmlGenerator = class HtmlGenerator extends TemplateGenerator
|
|||||||
return HTML.prettyPrint(info.mk, this.opts.prettify);
|
return HTML.prettyPrint(info.mk, this.opts.prettify);
|
||||||
} else { return info.mk; }
|
} else { return info.mk; }
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = HtmlGenerator;
|
||||||
|
@ -11,7 +11,6 @@ Definition of the HtmlPdfCLIGenerator class.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let HtmlPdfCLIGenerator;
|
|
||||||
const TemplateGenerator = require('./template-generator');
|
const TemplateGenerator = require('./template-generator');
|
||||||
const FS = require('fs-extra');
|
const FS = require('fs-extra');
|
||||||
const PATH = require('path');
|
const PATH = require('path');
|
||||||
@ -27,7 +26,7 @@ wkhtmltopdf, and other PDF engines over a CLI (command-line interface).
|
|||||||
If an engine isn't installed for a particular platform, error out gracefully.
|
If an engine isn't installed for a particular platform, error out gracefully.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = (HtmlPdfCLIGenerator = class HtmlPdfCLIGenerator extends TemplateGenerator {
|
class HtmlPdfCLIGenerator extends TemplateGenerator {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -57,9 +56,9 @@ module.exports = (HtmlPdfCLIGenerator = class HtmlPdfCLIGenerator extends Templa
|
|||||||
onError(ex, param) {
|
onError(ex, param) {
|
||||||
__guardMethod__(param.errHandler, 'err', o => o.err(HMSTATUS.pdfGeneration, ex));
|
__guardMethod__(param.errHandler, 'err', o => o.err(HMSTATUS.pdfGeneration, ex));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = HtmlPdfCLIGenerator;
|
||||||
|
|
||||||
// TODO: Move each engine to a separate module
|
// TODO: Move each engine to a separate module
|
||||||
var engines = {
|
var engines = {
|
||||||
|
@ -11,10 +11,8 @@ Definition of the HtmlPngGenerator class.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let HtmlPngGenerator;
|
|
||||||
const TemplateGenerator = require('./template-generator');
|
const TemplateGenerator = require('./template-generator');
|
||||||
const FS = require('fs-extra');
|
const FS = require('fs-extra');
|
||||||
const HTML = require('html');
|
|
||||||
const SLASH = require('slash');
|
const SLASH = require('slash');
|
||||||
const SPAWN = require('../utils/safe-spawn');
|
const SPAWN = require('../utils/safe-spawn');
|
||||||
const PATH = require('path');
|
const PATH = require('path');
|
||||||
@ -23,11 +21,11 @@ const PATH = require('path');
|
|||||||
/**
|
/**
|
||||||
An HTML-based PNG resume generator for HackMyResume.
|
An HTML-based PNG resume generator for HackMyResume.
|
||||||
*/
|
*/
|
||||||
module.exports = (HtmlPngGenerator = class HtmlPngGenerator extends TemplateGenerator {
|
class HtmlPngGenerator extends TemplateGenerator {
|
||||||
|
|
||||||
constructor() { super('png', 'html'); }
|
constructor() { super('png', 'html'); }
|
||||||
|
|
||||||
invoke( rez, themeMarkup, cssInfo, opts ) {}
|
invoke( /*rez, themeMarkup, cssInfo, opts*/ ) {}
|
||||||
// TODO: Not currently called or callable.
|
// TODO: Not currently called or callable.
|
||||||
|
|
||||||
generate( rez, f, opts ) {
|
generate( rez, f, opts ) {
|
||||||
@ -35,7 +33,9 @@ module.exports = (HtmlPngGenerator = class HtmlPngGenerator extends TemplateGene
|
|||||||
const htmlFile = htmlResults[0].final.files.filter(fl => fl.info.ext === 'html');
|
const htmlFile = htmlResults[0].final.files.filter(fl => fl.info.ext === 'html');
|
||||||
phantom(htmlFile[0].data, f);
|
phantom(htmlFile[0].data, f);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = HtmlPngGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Generate a PDF from HTML using Phantom's CLI interface.
|
Generate a PDF from HTML using Phantom's CLI interface.
|
||||||
@ -54,5 +54,5 @@ var phantom = function( markup, fOut ) {
|
|||||||
PATH.resolve( __dirname, '../utils/rasterize.js' ) ) );
|
PATH.resolve( __dirname, '../utils/rasterize.js' ) ) );
|
||||||
const sourcePath = SLASH( PATH.relative( process.cwd(), tempFile) );
|
const sourcePath = SLASH( PATH.relative( process.cwd(), tempFile) );
|
||||||
const destPath = SLASH( PATH.relative( process.cwd(), fOut) );
|
const destPath = SLASH( PATH.relative( process.cwd(), fOut) );
|
||||||
const info = SPAWN('phantomjs', [ scriptPath, sourcePath, destPath ]);
|
SPAWN('phantomjs', [ scriptPath, sourcePath, destPath ]);
|
||||||
};
|
};
|
||||||
|
@ -9,15 +9,13 @@ Definition of the JsonGenerator class.
|
|||||||
@license MIT. See LICENSE.md for details.
|
@license MIT. See LICENSE.md for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let JsonGenerator;
|
|
||||||
const BaseGenerator = require('./base-generator');
|
const BaseGenerator = require('./base-generator');
|
||||||
const FS = require('fs');
|
const FS = require('fs');
|
||||||
const _ = require('underscore');
|
|
||||||
const FJCV = require('fresh-jrs-converter');
|
const FJCV = require('fresh-jrs-converter');
|
||||||
|
|
||||||
/** The JsonGenerator generates a FRESH or JRS resume as an output. */
|
/** The JsonGenerator generates a FRESH or JRS resume as an output. */
|
||||||
|
|
||||||
module.exports = (JsonGenerator = class JsonGenerator extends BaseGenerator {
|
class JsonGenerator extends BaseGenerator {
|
||||||
|
|
||||||
constructor() { super('json'); }
|
constructor() { super('json'); }
|
||||||
|
|
||||||
@ -30,4 +28,6 @@ module.exports = (JsonGenerator = class JsonGenerator extends BaseGenerator {
|
|||||||
generate( rez, f ) {
|
generate( rez, f ) {
|
||||||
FS.writeFileSync(f, this.invoke(rez), 'utf8');
|
FS.writeFileSync(f, this.invoke(rez), 'utf8');
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = JsonGenerator;
|
||||||
|
@ -11,7 +11,6 @@ Definition of the JsonYamlGenerator class.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let JsonYamlGenerator;
|
|
||||||
const BaseGenerator = require('./base-generator');
|
const BaseGenerator = require('./base-generator');
|
||||||
const FS = require('fs');
|
const FS = require('fs');
|
||||||
const YAML = require('yamljs');
|
const YAML = require('yamljs');
|
||||||
@ -24,17 +23,19 @@ JSON without a template, producing an equivalent YAML-formatted resume. See
|
|||||||
also YamlGenerator (yaml-generator.js).
|
also YamlGenerator (yaml-generator.js).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = (JsonYamlGenerator = class JsonYamlGenerator extends BaseGenerator {
|
class JsonYamlGenerator extends BaseGenerator {
|
||||||
|
|
||||||
constructor() { super('yml'); }
|
constructor() { super('yml'); }
|
||||||
|
|
||||||
invoke( rez, themeMarkup, cssInfo, opts ) {
|
invoke( rez/*, themeMarkup, cssInfo, opts*/ ) {
|
||||||
return YAML.stringify(JSON.parse( rez.stringify() ), Infinity, 2);
|
return YAML.stringify(JSON.parse( rez.stringify() ), Infinity, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
generate( rez, f, opts ) {
|
generate( rez, f/*, opts */) {
|
||||||
const data = YAML.stringify(JSON.parse( rez.stringify() ), Infinity, 2);
|
const data = YAML.stringify(JSON.parse( rez.stringify() ), Infinity, 2);
|
||||||
FS.writeFileSync(f, data, 'utf8');
|
FS.writeFileSync(f, data, 'utf8');
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = JsonYamlGenerator;
|
||||||
|
@ -4,13 +4,14 @@ Definition of the LaTeXGenerator class.
|
|||||||
@license MIT. See LICENSE.md for details.
|
@license MIT. See LICENSE.md for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let LaTeXGenerator;
|
|
||||||
const TemplateGenerator = require('./template-generator');
|
const TemplateGenerator = require('./template-generator');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
LaTeXGenerator generates a LaTeX resume via TemplateGenerator.
|
LaTeXGenerator generates a LaTeX resume via TemplateGenerator.
|
||||||
*/
|
*/
|
||||||
module.exports = (LaTeXGenerator = class LaTeXGenerator extends TemplateGenerator {
|
class LaTeXGenerator extends TemplateGenerator {
|
||||||
|
|
||||||
constructor() { super('latex', 'tex'); }
|
constructor() { super('latex', 'tex'); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = LaTeXGenerator;
|
||||||
|
@ -4,13 +4,14 @@ Definition of the MarkdownGenerator class.
|
|||||||
@license MIT. See LICENSE.md for details.
|
@license MIT. See LICENSE.md for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let MarkdownGenerator;
|
|
||||||
const TemplateGenerator = require('./template-generator');
|
const TemplateGenerator = require('./template-generator');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
MarkdownGenerator generates a Markdown-formatted resume via TemplateGenerator.
|
MarkdownGenerator generates a Markdown-formatted resume via TemplateGenerator.
|
||||||
*/
|
*/
|
||||||
module.exports = (MarkdownGenerator = class MarkdownGenerator extends TemplateGenerator {
|
class MarkdownGenerator extends TemplateGenerator {
|
||||||
|
|
||||||
constructor() { super('md', 'txt'); }
|
constructor() { super('md', 'txt'); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = MarkdownGenerator;
|
||||||
|
@ -11,7 +11,6 @@ Definition of the TemplateGenerator class. TODO: Refactor
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let TemplateGenerator;
|
|
||||||
const FS = require('fs-extra');
|
const FS = require('fs-extra');
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const MD = require('marked');
|
const MD = require('marked');
|
||||||
@ -21,8 +20,6 @@ const parsePath = require('parse-filepath');
|
|||||||
const MKDIRP = require('mkdirp');
|
const MKDIRP = require('mkdirp');
|
||||||
const BaseGenerator = require('./base-generator');
|
const BaseGenerator = require('./base-generator');
|
||||||
const EXTEND = require('extend');
|
const EXTEND = require('extend');
|
||||||
const FRESHTheme = require('../core/fresh-theme');
|
|
||||||
const JRSTheme = require('../core/jrs-theme');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -33,7 +30,7 @@ plain text, and XML versions of Microsoft Word, Excel, and OpenOffice.
|
|||||||
@class TemplateGenerator
|
@class TemplateGenerator
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = (TemplateGenerator = class TemplateGenerator extends BaseGenerator {
|
class TemplateGenerator extends BaseGenerator {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +38,7 @@ module.exports = (TemplateGenerator = class TemplateGenerator extends BaseGenera
|
|||||||
generator. Will usually be called by a derived generator such as
|
generator. Will usually be called by a derived generator such as
|
||||||
HTMLGenerator or MarkdownGenerator. */
|
HTMLGenerator or MarkdownGenerator. */
|
||||||
|
|
||||||
constructor( outputFormat, templateFormat, cssFile ) {
|
constructor( outputFormat, templateFormat/*, cssFile */) {
|
||||||
super(outputFormat);
|
super(outputFormat);
|
||||||
this.tplFormat = templateFormat || outputFormat;
|
this.tplFormat = templateFormat || outputFormat;
|
||||||
}
|
}
|
||||||
@ -78,7 +75,7 @@ module.exports = (TemplateGenerator = class TemplateGenerator extends BaseGenera
|
|||||||
}
|
}
|
||||||
//tplInfo.css contains the CSS data loaded by theme
|
//tplInfo.css contains the CSS data loaded by theme
|
||||||
//tplInfo.cssPath contains the absolute path to the source CSS File
|
//tplInfo.cssPath contains the absolute path to the source CSS File
|
||||||
else {}
|
//else {}
|
||||||
// Images and non-transformable binary files
|
// Images and non-transformable binary files
|
||||||
if (typeof opts.onTransform === 'function') {
|
if (typeof opts.onTransform === 'function') {
|
||||||
opts.onTransform(tplInfo);
|
opts.onTransform(tplInfo);
|
||||||
@ -153,7 +150,7 @@ module.exports = (TemplateGenerator = class TemplateGenerator extends BaseGenera
|
|||||||
|
|
||||||
// Post-processing
|
// Post-processing
|
||||||
if (this.onAfterSave) {
|
if (this.onAfterSave) {
|
||||||
return this.onAfterSave({outputFile: fileName, mk: file.data, opts: this.opts});
|
return this.onAfterSave({outputFile: thisFilePath, mk: file.data, opts: this.opts});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +183,10 @@ module.exports = (TemplateGenerator = class TemplateGenerator extends BaseGenera
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = TemplateGenerator;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -208,10 +208,12 @@ var createSymLinks = function( curFmt, outFolder ) {
|
|||||||
try {
|
try {
|
||||||
FS.symlinkSync(absTarg, absLoc, type);
|
FS.symlinkSync(absTarg, absLoc, type);
|
||||||
succeeded = true;
|
succeeded = true;
|
||||||
} catch (error) {}
|
} catch (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!succeeded) {
|
if (!succeeded) {
|
||||||
throw ex;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -245,9 +247,9 @@ var _defaultOpts = {
|
|||||||
rSym: '&retn;', // return entity
|
rSym: '&retn;', // return entity
|
||||||
template: {
|
template: {
|
||||||
interpolate: /\{\{(.+?)\}\}/g,
|
interpolate: /\{\{(.+?)\}\}/g,
|
||||||
escape: /\{\{\=(.+?)\}\}/g,
|
escape: /\{\{=(.+?)\}\}/g,
|
||||||
evaluate: /\{\%(.+?)\%\}/g,
|
evaluate: /\{%(.+?)%\}/g,
|
||||||
comment: /\{\#(.+?)\#\}/g
|
comment: /\{#(.+?)#\}/g
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
out( txt ) { return txt; },
|
out( txt ) { return txt; },
|
||||||
@ -271,9 +273,11 @@ var _defaultOpts = {
|
|||||||
|
|
||||||
|
|
||||||
/** Regexes for linebreak preservation. */
|
/** Regexes for linebreak preservation. */
|
||||||
|
/* eslint-disable no-control-regex */
|
||||||
var _reg = {
|
var _reg = {
|
||||||
regN: new RegExp( '\n', 'g' ),
|
regN: new RegExp( '\n', 'g' ),
|
||||||
regR: new RegExp( '\r', 'g' ),
|
regR: new RegExp( '\r', 'g' ),
|
||||||
regSymN: new RegExp( _defaultOpts.nSym, 'g' ),
|
regSymN: new RegExp( _defaultOpts.nSym, 'g' ),
|
||||||
regSymR: new RegExp( _defaultOpts.rSym, 'g' )
|
regSymR: new RegExp( _defaultOpts.rSym, 'g' )
|
||||||
};
|
};
|
||||||
|
/* eslint-enable no-control-regex */
|
||||||
|
@ -4,13 +4,13 @@ Definition of the TextGenerator class.
|
|||||||
@license MIT. See LICENSE.md for details.
|
@license MIT. See LICENSE.md for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let TextGenerator;
|
|
||||||
const TemplateGenerator = require('./template-generator');
|
const TemplateGenerator = require('./template-generator');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The TextGenerator generates a plain-text resume via the TemplateGenerator.
|
The TextGenerator generates a plain-text resume via the TemplateGenerator.
|
||||||
*/
|
*/
|
||||||
module.exports = (TextGenerator = class TextGenerator extends TemplateGenerator {
|
class TextGenerator extends TemplateGenerator {
|
||||||
|
|
||||||
constructor() { super('txt'); }
|
constructor() { super('txt'); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = TextGenerator;
|
||||||
|
@ -5,10 +5,10 @@ Definition of the WordGenerator class.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
let WordGenerator;
|
|
||||||
const TemplateGenerator = require('./template-generator');
|
const TemplateGenerator = require('./template-generator');
|
||||||
|
|
||||||
module.exports = (WordGenerator = class WordGenerator extends TemplateGenerator {
|
class WordGenerator extends TemplateGenerator {
|
||||||
|
|
||||||
constructor() { super('doc', 'xml'); }
|
constructor() { super('doc', 'xml'); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = WordGenerator;
|
||||||
|
@ -4,11 +4,11 @@ Definition of the XMLGenerator class.
|
|||||||
@module generatprs/xml-generator
|
@module generatprs/xml-generator
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let XMLGenerator;
|
|
||||||
const BaseGenerator = require('./base-generator');
|
const BaseGenerator = require('./base-generator');
|
||||||
|
|
||||||
/** The XmlGenerator generates an XML resume via the TemplateGenerator. */
|
/** The XmlGenerator generates an XML resume via the TemplateGenerator. */
|
||||||
module.exports = (XMLGenerator = class XMLGenerator extends BaseGenerator {
|
class XMLGenerator extends BaseGenerator {
|
||||||
|
|
||||||
constructor() { super('xml'); }
|
constructor() { super('xml'); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = XMLGenerator;
|
||||||
|
@ -5,14 +5,15 @@ Definition of the YAMLGenerator class.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
let YAMLGenerator;
|
|
||||||
const TemplateGenerator = require('./template-generator');
|
const TemplateGenerator = require('./template-generator');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
YamlGenerator generates a YAML-formatted resume via TemplateGenerator.
|
YamlGenerator generates a YAML-formatted resume via TemplateGenerator.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = (YAMLGenerator = class YAMLGenerator extends TemplateGenerator {
|
class YAMLGenerator extends TemplateGenerator {
|
||||||
|
|
||||||
constructor() { super('yml', 'yml'); }
|
constructor() { super('yml', 'yml'); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = YAMLGenerator;
|
||||||
|
@ -11,15 +11,14 @@ Block helper definitions for HackMyResume / FluentCV.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const HMSTATUS = require('../core/status-codes');
|
|
||||||
const LO = require('lodash');
|
const LO = require('lodash');
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const unused = require('../utils/string');
|
require('../utils/string');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Block helper function definitions. */
|
/** Block helper function definitions. */
|
||||||
const BlockHelpers = (module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -75,4 +74,4 @@ const BlockHelpers = (module.exports = {
|
|||||||
@method either
|
@method either
|
||||||
*/
|
*/
|
||||||
either( lhs, rhs, options ) { if (lhs || rhs) { return options.fn(this); } }
|
either( lhs, rhs, options ) { if (lhs || rhs) { return options.fn(this); } }
|
||||||
});
|
};
|
||||||
|
@ -19,7 +19,7 @@ require('../utils/string');
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const consoleFormatHelpers = (module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
v( val, defaultVal, padding, style ) {
|
v( val, defaultVal, padding, style ) {
|
||||||
let retVal = ( (val === null) || (val === undefined) ) ? defaultVal : val;
|
let retVal = ( (val === null) || (val === undefined) ) ? defaultVal : val;
|
||||||
@ -64,4 +64,4 @@ const consoleFormatHelpers = (module.exports = {
|
|||||||
pad( val, spaces ) {
|
pad( val, spaces ) {
|
||||||
return PAD(val, Math.abs(spaces), null, spaces > 0 ? PAD.LEFT : PAD.RIGHT);
|
return PAD(val, Math.abs(spaces), null, spaces > 0 ? PAD.LEFT : PAD.RIGHT);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
@ -23,7 +23,7 @@ const LO = require('lodash');
|
|||||||
const PATH = require('path');
|
const PATH = require('path');
|
||||||
const printf = require('printf');
|
const printf = require('printf');
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const unused = require('../utils/string');
|
require('../utils/string');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -152,7 +152,7 @@ var GenericHelpers = (module.exports = {
|
|||||||
@param key {String} A named style from the "fonts" section of the theme's
|
@param key {String} A named style from the "fonts" section of the theme's
|
||||||
theme.json file. For example: 'default' or 'heading1'.
|
theme.json file. For example: 'default' or 'heading1'.
|
||||||
*/
|
*/
|
||||||
fontSize( key, defSize, units ) {
|
fontSize( key, defSize/*, units*/ ) {
|
||||||
|
|
||||||
let ret = '';
|
let ret = '';
|
||||||
const hasDef = defSize && ( String.is( defSize ) || _.isNumber( defSize ));
|
const hasDef = defSize && ( String.is( defSize ) || _.isNumber( defSize ));
|
||||||
@ -534,9 +534,9 @@ var GenericHelpers = (module.exports = {
|
|||||||
*/
|
*/
|
||||||
compare(lvalue, rvalue, options) {
|
compare(lvalue, rvalue, options) {
|
||||||
if (arguments.length < 3) {
|
if (arguments.length < 3) {
|
||||||
throw new Error("Template helper 'compare' needs 2 parameters");
|
throw new Error('Template helper \'compare\' needs 2 parameters');
|
||||||
}
|
}
|
||||||
const operator = options.hash.operator || "==";
|
const operator = options.hash.operator || '==';
|
||||||
const operators = {
|
const operators = {
|
||||||
'=='(l,r) { return l === r; },
|
'=='(l,r) { return l === r; },
|
||||||
'==='(l,r) { return l === r; },
|
'==='(l,r) { return l === r; },
|
||||||
@ -559,7 +559,7 @@ var GenericHelpers = (module.exports = {
|
|||||||
/**
|
/**
|
||||||
Emit padded text.
|
Emit padded text.
|
||||||
*/
|
*/
|
||||||
pad(stringOrArray, padAmount, unused ) {
|
pad(stringOrArray, padAmount/*, unused*/ ) {
|
||||||
stringOrArray = stringOrArray || '';
|
stringOrArray = stringOrArray || '';
|
||||||
padAmount = padAmount || 0;
|
padAmount = padAmount || 0;
|
||||||
let ret = '';
|
let ret = '';
|
||||||
@ -591,7 +591,7 @@ var GenericHelpers = (module.exports = {
|
|||||||
Given an object that may be a string or an object, return it as-is if it's a
|
Given an object that may be a string or an object, return it as-is if it's a
|
||||||
string, otherwise return the value at obj[objPath].
|
string, otherwise return the value at obj[objPath].
|
||||||
*/
|
*/
|
||||||
stringOrObject( obj, objPath, rez ) {
|
stringOrObject( obj, objPath/*, rez */) {
|
||||||
if (_.isString(obj)) { return obj; } else { return LO.get(obj, objPath); }
|
if (_.isString(obj)) { return obj; } else { return LO.get(obj, objPath); }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -30,7 +30,7 @@ module.exports = function( theme, rez, opts ) {
|
|||||||
|
|
||||||
// Prepare generic helpers for use with Handlebars. We do this by wrapping them
|
// Prepare generic helpers for use with Handlebars. We do this by wrapping them
|
||||||
// in a Handlebars-aware wrapper which calls the helper internally.
|
// in a Handlebars-aware wrapper which calls the helper internally.
|
||||||
const wrappedHelpers = _.mapObject(helpers, function( hVal, hKey ) {
|
const wrappedHelpers = _.mapObject(helpers, function( hVal/*, hKey*/ ) {
|
||||||
if (_.isFunction(hVal)) {
|
if (_.isFunction(hVal)) {
|
||||||
return _.wrap(hVal, function(func) {
|
return _.wrap(hVal, function(func) {
|
||||||
const args = Array.prototype.slice.call(arguments);
|
const args = Array.prototype.slice.call(arguments);
|
||||||
@ -68,7 +68,7 @@ module.exports = function( theme, rez, opts ) {
|
|||||||
HANDLEBARS.registerHelper(require(f)); // ..register the path
|
HANDLEBARS.registerHelper(require(f)); // ..register the path
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw {fluenterror: HMS.themeHelperLoad, inner: er, glob: fGlob};
|
throw {fluenterror: HMS.themeHelperLoad, inner: null, glob: fGlob};
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@ -78,7 +78,6 @@ module.exports = function( theme, rez, opts ) {
|
|||||||
inner: ex,
|
inner: ex,
|
||||||
glob: curGlob, exit: true
|
glob: curGlob, exit: true
|
||||||
};
|
};
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -11,7 +11,6 @@ Template helper definitions for Underscore.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const HANDLEBARS = require('handlebars');
|
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const helpers = require('./generic-helpers');
|
const helpers = require('./generic-helpers');
|
||||||
|
|
||||||
@ -27,7 +26,7 @@ module.exports = function( theme, opts, cssInfo, ctx, eng ) {
|
|||||||
helpers.cssInfo = cssInfo;
|
helpers.cssInfo = cssInfo;
|
||||||
helpers.engine = eng;
|
helpers.engine = eng;
|
||||||
ctx.h = helpers;
|
ctx.h = helpers;
|
||||||
_.each(helpers, function( hVal, hKey ) {
|
_.each(helpers, function( hVal ) {
|
||||||
if (_.isFunction(hVal)) {
|
if (_.isFunction(hVal)) {
|
||||||
return _.bind(hVal, ctx);
|
return _.bind(hVal, ctx);
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ const LO = require('lodash');
|
|||||||
/**
|
/**
|
||||||
Identify gaps in the candidate's employment history.
|
Identify gaps in the candidate's employment history.
|
||||||
*/
|
*/
|
||||||
const gapInspector = (module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
moniker: 'gap-inspector',
|
moniker: 'gap-inspector',
|
||||||
|
|
||||||
@ -84,10 +84,8 @@ const gapInspector = (module.exports = {
|
|||||||
// When the reference count is > 0, the candidate is employed. When the
|
// When the reference count is > 0, the candidate is employed. When the
|
||||||
// reference count reaches 2, the candidate is overlapped.
|
// reference count reaches 2, the candidate is overlapped.
|
||||||
|
|
||||||
const num_gaps = 0;
|
|
||||||
let ref_count = 0;
|
let ref_count = 0;
|
||||||
let total_gap_days = 0;
|
let total_gap_days = 0;
|
||||||
const gap_start = null;
|
|
||||||
|
|
||||||
new_e.forEach(function(point) {
|
new_e.forEach(function(point) {
|
||||||
|
|
||||||
@ -156,4 +154,4 @@ const gapInspector = (module.exports = {
|
|||||||
coverage.duration = dur;
|
coverage.duration = dur;
|
||||||
return coverage;
|
return coverage;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
@ -9,16 +9,13 @@ Keyword analysis for HackMyResume.
|
|||||||
@module inspectors/keyword-inspector
|
@module inspectors/keyword-inspector
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const _ = require('underscore');
|
|
||||||
const FluentDate = require('../core/fluent-date');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Analyze the resume's use of keywords.
|
Analyze the resume's use of keywords.
|
||||||
TODO: BUG: Keyword search regex is inaccurate, especially for one or two
|
TODO: BUG: Keyword search regex is inaccurate, especially for one or two
|
||||||
letter keywords like "C" or "CLI".
|
letter keywords like "C" or "CLI".
|
||||||
@class keywordInspector
|
@class keywordInspector
|
||||||
*/
|
*/
|
||||||
const keywordInspector = (module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
/** A unique name for this inspector. */
|
/** A unique name for this inspector. */
|
||||||
moniker: 'keyword-inspector',
|
moniker: 'keyword-inspector',
|
||||||
@ -33,7 +30,7 @@ const keywordInspector = (module.exports = {
|
|||||||
// "Quote" or safely escape a keyword so it can be used as a regex. For
|
// "Quote" or safely escape a keyword so it can be used as a regex. For
|
||||||
// example, if the keyword is "C++", yield "C\+\+".
|
// example, if the keyword is "C++", yield "C\+\+".
|
||||||
// http://stackoverflow.com/a/2593661/4942583
|
// http://stackoverflow.com/a/2593661/4942583
|
||||||
const regex_quote = str => (str + '').replace(/[.?*+^$[\]\\(){}|-]/ig, "\\$&");
|
const regex_quote = str => (str + '').replace(/[.?*+^$[\]\\(){}|-]/ig, '\\$&');
|
||||||
|
|
||||||
// Create a searchable plain-text digest of the resume
|
// Create a searchable plain-text digest of the resume
|
||||||
// TODO: BUG: Don't search within keywords for other keywords. Job A
|
// TODO: BUG: Don't search within keywords for other keywords. Job A
|
||||||
@ -64,9 +61,8 @@ const keywordInspector = (module.exports = {
|
|||||||
|
|
||||||
const regex_str = prefix + regex_quote( kw ) + suffix;
|
const regex_str = prefix + regex_quote( kw ) + suffix;
|
||||||
const regex = new RegExp( regex_str, 'ig');
|
const regex = new RegExp( regex_str, 'ig');
|
||||||
let myArray = null;
|
|
||||||
let count = 0;
|
let count = 0;
|
||||||
while ((myArray = regex.exec( searchable )) !== null) {
|
while (regex.exec( searchable ) !== null) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -75,4 +71,4 @@ const keywordInspector = (module.exports = {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
@ -10,13 +10,12 @@ Section analysis for HackMyResume.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const FluentDate = require('../core/fluent-date');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Retrieve sectional overview and summary information.
|
Retrieve sectional overview and summary information.
|
||||||
@class totalsInspector
|
@class totalsInspector
|
||||||
*/
|
*/
|
||||||
const totalsInspector = (module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
moniker: 'totals-inspector',
|
moniker: 'totals-inspector',
|
||||||
|
|
||||||
@ -44,4 +43,4 @@ const totalsInspector = (module.exports = {
|
|||||||
numSections: Object.keys( sectionTotals ).length
|
numSections: Object.keys( sectionTotals ).length
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
@ -26,7 +26,7 @@ const SLASH = require('slash');
|
|||||||
Perform template-based resume generation using Handlebars.js.
|
Perform template-based resume generation using Handlebars.js.
|
||||||
@class HandlebarsGenerator
|
@class HandlebarsGenerator
|
||||||
*/
|
*/
|
||||||
const HandlebarsGenerator = (module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ const HandlebarsGenerator = (module.exports = {
|
|||||||
// Render the template
|
// Render the template
|
||||||
return this.generateSimple(ctx, jst);
|
return this.generateSimple(ctx, jst);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -100,8 +100,7 @@ var registerPartials = function(format, theme) {
|
|||||||
|
|
||||||
// Register global partials in the /partials/[format] folder
|
// Register global partials in the /partials/[format] folder
|
||||||
// TODO: Only do this once per HMR invocation.
|
// TODO: Only do this once per HMR invocation.
|
||||||
_.each(READFILES( partialsFolder, error=> ({ })), function( el ) {
|
_.each(READFILES( partialsFolder ), function( el ) {
|
||||||
const pathInfo = parsePath(el);
|
|
||||||
const name = SLASH(PATH.relative( partialsFolder, el ).replace(/\.(?:html|xml|hbs|md|txt)$/i, ''));
|
const name = SLASH(PATH.relative( partialsFolder, el ).replace(/\.(?:html|xml|hbs|md|txt)$/i, ''));
|
||||||
const tplData = FS.readFileSync(el, 'utf8');
|
const tplData = FS.readFileSync(el, 'utf8');
|
||||||
const compiledTemplate = HANDLEBARS.compile(tplData);
|
const compiledTemplate = HANDLEBARS.compile(tplData);
|
||||||
|
@ -9,14 +9,6 @@ Definition of the JRSGenerator class.
|
|||||||
@module renderers/jrs-generator
|
@module renderers/jrs-generator
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const _ = require('underscore');
|
|
||||||
const HANDLEBARS = require('handlebars');
|
|
||||||
const FS = require('fs');
|
|
||||||
const registerHelpers = require('../helpers/handlebars-helpers');
|
|
||||||
const PATH = require('path');
|
|
||||||
const parsePath = require('parse-filepath');
|
|
||||||
const READFILES = require('recursive-readdir-sync');
|
|
||||||
const SLASH = require('slash');
|
|
||||||
const MD = require('marked');
|
const MD = require('marked');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -24,15 +16,15 @@ Perform template-based resume generation for JSON Resume themes.
|
|||||||
@class JRSGenerator
|
@class JRSGenerator
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const JRSGenerator = (module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
generate( json, jst, format, cssInfo, opts, theme ) {
|
generate( json, jst, format, cssInfo, opts, theme ) {
|
||||||
|
|
||||||
// Disable JRS theme chatter (console.log, console.error, etc.)
|
// Disable JRS theme chatter (console.log, console.error, etc.)
|
||||||
const turnoff = ['log', 'error', 'dir'];
|
const turnoff = ['log', 'error', 'dir'];
|
||||||
const org = turnoff.map(function(c) {
|
const org = turnoff.map(function(c) {
|
||||||
const ret = console[c];
|
const ret = console[c]; // eslint-disable-line no-console
|
||||||
console[c] = function() {};
|
console[c] = function() {}; // eslint-disable-line no-console
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -40,12 +32,12 @@ const JRSGenerator = (module.exports = {
|
|||||||
let rezHtml = theme.render(json.harden());
|
let rezHtml = theme.render(json.harden());
|
||||||
|
|
||||||
// Turn logging back on
|
// Turn logging back on
|
||||||
turnoff.forEach((c, idx) => console[c] = org[idx]);
|
turnoff.forEach((c, idx) => console[c] = org[idx]); // eslint-disable-line no-console
|
||||||
|
|
||||||
// Unfreeze and apply Markdown
|
// Unfreeze and apply Markdown
|
||||||
return rezHtml = rezHtml.replace(/@@@@~[\s\S]*?~@@@@/g, val => MDIN( val.replace( /~@@@@/g,'' ).replace( /@@@@~/g,'' ) ));
|
return rezHtml = rezHtml.replace(/@@@@~[\s\S]*?~@@@@/g, val => MDIN( val.replace( /~@@@@/g,'' ).replace( /@@@@~/g,'' ) ));
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
|
||||||
var MDIN = txt => // TODO: Move this
|
var MDIN = txt => // TODO: Move this
|
||||||
|
@ -20,7 +20,7 @@ const escapeLaTeX = require('escape-latex');
|
|||||||
Perform template-based resume generation using Underscore.js.
|
Perform template-based resume generation using Underscore.js.
|
||||||
@class UnderscoreGenerator
|
@class UnderscoreGenerator
|
||||||
*/
|
*/
|
||||||
const UnderscoreGenerator = (module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ const UnderscoreGenerator = (module.exports = {
|
|||||||
// Tweak underscore's default template delimeters
|
// Tweak underscore's default template delimeters
|
||||||
let delims = (opts.themeObj && opts.themeObj.delimeters) || opts.template;
|
let delims = (opts.themeObj && opts.themeObj.delimeters) || opts.template;
|
||||||
if (opts.themeObj && opts.themeObj.delimeters) {
|
if (opts.themeObj && opts.themeObj.delimeters) {
|
||||||
delims = _.mapObject(delims, (val,key) => new RegExp(val, "ig"));
|
delims = _.mapObject(delims, (val) => new RegExp(val, 'ig'));
|
||||||
}
|
}
|
||||||
_.templateSettings = delims;
|
_.templateSettings = delims;
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ const UnderscoreGenerator = (module.exports = {
|
|||||||
case 'png': r = json.markdownify(); break;
|
case 'png': r = json.markdownify(); break;
|
||||||
case 'latex':
|
case 'latex':
|
||||||
var traverse = require('traverse');
|
var traverse = require('traverse');
|
||||||
r = traverse(json).map(function(x) {
|
r = traverse(json).map(function() {
|
||||||
if (this.isLeaf && String.is(this.node)) {
|
if (this.isLeaf && String.is(this.node)) {
|
||||||
return escapeLaTeX(this.node);
|
return escapeLaTeX(this.node);
|
||||||
}
|
}
|
||||||
@ -87,4 +87,4 @@ const UnderscoreGenerator = (module.exports = {
|
|||||||
// Generate!
|
// Generate!
|
||||||
return this.generateSimple(ctx, jst);
|
return this.generateSimple(ctx, jst);
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
@ -10,7 +10,6 @@ Inline Markdown-to-Chalk conversion routines.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
const MD = require('marked');
|
|
||||||
const CHALK = require('chalk');
|
const CHALK = require('chalk');
|
||||||
const LO = require('lodash');
|
const LO = require('lodash');
|
||||||
|
|
||||||
|
@ -7,8 +7,10 @@
|
|||||||
// https://raw.githubusercontent.com/ariya/phantomjs/master/examples/rasterize.js
|
// https://raw.githubusercontent.com/ariya/phantomjs/master/examples/rasterize.js
|
||||||
// Converted to CoffeeScript by hacksalot
|
// Converted to CoffeeScript by hacksalot
|
||||||
|
|
||||||
"use strict";let output, size;
|
/* eslint-disable */
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
let output, size;
|
||||||
const page = require('webpage').create();
|
const page = require('webpage').create();
|
||||||
const system = require('system');
|
const system = require('system');
|
||||||
let address = (output = (size = null));
|
let address = (output = (size = null));
|
||||||
@ -27,14 +29,14 @@ if ((system.args.length < 3) || (system.args.length > 5)) {
|
|||||||
output = system.args[2];
|
output = system.args[2];
|
||||||
page.viewportSize = {width: 600, height: 600};
|
page.viewportSize = {width: 600, height: 600};
|
||||||
|
|
||||||
if ((system.args.length > 3) && (system.args[2].substr(-4) === ".pdf")) {
|
if ((system.args.length > 3) && (system.args[2].substr(-4) === '.pdf')) {
|
||||||
|
|
||||||
size = system.args[3].split('*');
|
size = system.args[3].split('*');
|
||||||
page.paperSize =
|
page.paperSize =
|
||||||
size.length === 2 ? {width: size[0], height: size[1], margin: '0px'}
|
size.length === 2 ? {width: size[0], height: size[1], margin: '0px'}
|
||||||
: {format: system.args[3], orientation: 'portrait', margin: '1cm'};
|
: {format: system.args[3], orientation: 'portrait', margin: '1cm'};
|
||||||
|
|
||||||
} else if ((system.args.length > 3) && (system.args[3].substr(-2) === "px")) {
|
} else if ((system.args.length > 3) && (system.args[3].substr(-2) === 'px')) {
|
||||||
let pageHeight, pageWidth;
|
let pageHeight, pageWidth;
|
||||||
size = system.args[3].split('*');
|
size = system.args[3].split('*');
|
||||||
if (size.length === 2) {
|
if (size.length === 2) {
|
||||||
@ -43,10 +45,12 @@ if ((system.args.length < 3) || (system.args.length > 5)) {
|
|||||||
page.viewportSize = {width: pageWidth, height: pageHeight};
|
page.viewportSize = {width: pageWidth, height: pageHeight};
|
||||||
page.clipRect = {top: 0, left: 0, width: pageWidth, height: pageHeight};
|
page.clipRect = {top: 0, left: 0, width: pageWidth, height: pageHeight};
|
||||||
} else {
|
} else {
|
||||||
console.log("size:", system.args[3]);
|
// eslint-ignore-next-line no-console
|
||||||
|
console.log('size:', system.args[3]);
|
||||||
pageWidth = parseInt(system.args[3], 10);
|
pageWidth = parseInt(system.args[3], 10);
|
||||||
pageHeight = parseInt((pageWidth * 3)/4, 10); // it's as good an assumption as any
|
pageHeight = parseInt((pageWidth * 3)/4, 10); // it's as good an assumption as any
|
||||||
console.log("pageHeight:", pageHeight);
|
// eslint-ignore-next-line no-console
|
||||||
|
console.log('pageHeight:', pageHeight);
|
||||||
page.viewportSize = {width: pageWidth, height: pageHeight};
|
page.viewportSize = {width: pageWidth, height: pageHeight};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,3 +73,4 @@ if ((system.args.length < 3) || (system.args.length > 5)) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/* esline-enable */
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
* DS102: Remove unnecessary code created because of implicit returns
|
* DS102: Remove unnecessary code created because of implicit returns
|
||||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const _ = require('underscore');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,8 +19,6 @@ a transformation function (such as a Markdown filter or XML encoder).
|
|||||||
|
|
||||||
module.exports = function( ret, filt, transformer ) {
|
module.exports = function( ret, filt, transformer ) {
|
||||||
|
|
||||||
const that = this;
|
|
||||||
|
|
||||||
// TODO: refactor recursion
|
// TODO: refactor recursion
|
||||||
var transformStringsInObject = function( obj, filters ) {
|
var transformStringsInObject = function( obj, filters ) {
|
||||||
if (!obj) { return; }
|
if (!obj) { return; }
|
||||||
|
@ -22,8 +22,6 @@ See: http://stackoverflow.com/q/13323356
|
|||||||
|
|
||||||
class SyntaxErrorEx {
|
class SyntaxErrorEx {
|
||||||
constructor( ex, rawData ) {
|
constructor( ex, rawData ) {
|
||||||
const lineNum = null;
|
|
||||||
const colNum = null;
|
|
||||||
let JSONLint = require('json-lint');
|
let JSONLint = require('json-lint');
|
||||||
const lint = JSONLint(rawData, { comments: false });
|
const lint = JSONLint(rawData, { comments: false });
|
||||||
if (lint.error) { [this.line, this.col] = Array.from([lint.line, lint.character]); }
|
if (lint.error) { [this.line, this.col] = Array.from([lint.line, lint.character]); }
|
||||||
|
@ -11,23 +11,20 @@ Implementation of the 'analyze' verb for HackMyResume.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let AnalyzeVerb;
|
|
||||||
const MKDIRP = require('mkdirp');
|
|
||||||
const PATH = require('path');
|
|
||||||
const HMEVENT = require('../core/event-codes');
|
const HMEVENT = require('../core/event-codes');
|
||||||
const HMSTATUS = require('../core/status-codes');
|
const HMSTATUS = require('../core/status-codes');
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const ResumeFactory = require('../core/resume-factory');
|
const ResumeFactory = require('../core/resume-factory');
|
||||||
const Verb = require('../verbs/verb');
|
const Verb = require('../verbs/verb');
|
||||||
const chalk = require('chalk');
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** An invokable resume analysis command. */
|
/** An invokable resume analysis command. */
|
||||||
module.exports = (AnalyzeVerb = class AnalyzeVerb extends Verb {
|
class AnalyzeVerb extends Verb {
|
||||||
|
|
||||||
constructor() { super('analyze', _analyze); }
|
constructor() { super('analyze', _analyze); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = AnalyzeVerb;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -69,14 +66,14 @@ var _analyze = function( sources, dst, opts ) {
|
|||||||
|
|
||||||
|
|
||||||
/** Analyze a single resume. */
|
/** Analyze a single resume. */
|
||||||
var _analyzeOne = function( resumeObject, nlzrs, opts ) {
|
var _analyzeOne = function( resumeObject, nlzrs ) {
|
||||||
const { rez } = resumeObject;
|
const { rez } = resumeObject;
|
||||||
const safeFormat =
|
const safeFormat =
|
||||||
rez.meta && rez.meta.format && rez.meta.format.startsWith('FRESH')
|
rez.meta && rez.meta.format && rez.meta.format.startsWith('FRESH')
|
||||||
? 'FRESH' : 'JRS';
|
? 'FRESH' : 'JRS';
|
||||||
|
|
||||||
this.stat( HMEVENT.beforeAnalyze, { fmt: safeFormat, file: resumeObject.file });
|
this.stat( HMEVENT.beforeAnalyze, { fmt: safeFormat, file: resumeObject.file });
|
||||||
const info = _.mapObject(nlzrs, (val, key) => val.run(rez));
|
const info = _.mapObject(nlzrs, (val) => val.run(rez));
|
||||||
this.stat(HMEVENT.afterAnalyze, { info });
|
this.stat(HMEVENT.afterAnalyze, { info });
|
||||||
return info;
|
return info;
|
||||||
};
|
};
|
||||||
|
@ -12,11 +12,8 @@ Implementation of the 'build' verb for HackMyResume.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let BuildVerb;
|
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const PATH = require('path');
|
const PATH = require('path');
|
||||||
const FS = require('fs');
|
|
||||||
const MD = require('marked');
|
|
||||||
const MKDIRP = require('mkdirp');
|
const MKDIRP = require('mkdirp');
|
||||||
const extend = require('extend');
|
const extend = require('extend');
|
||||||
const parsePath = require('parse-filepath');
|
const parsePath = require('parse-filepath');
|
||||||
@ -34,24 +31,27 @@ const ResumeFactory = require('../core/resume-factory');
|
|||||||
const _fmts = require('../core/default-formats');
|
const _fmts = require('../core/default-formats');
|
||||||
const Verb = require('../verbs/verb');
|
const Verb = require('../verbs/verb');
|
||||||
|
|
||||||
const _err = null;
|
//const _err = null;
|
||||||
const _log = null;
|
//const _log = null;
|
||||||
let _rezObj = null;
|
let _rezObj = null;
|
||||||
const build = null;
|
//const build = null;
|
||||||
const prep = null;
|
//const prep = null;
|
||||||
const single = null;
|
//const single = null;
|
||||||
const verifyOutputs = null;
|
//const verifyOutputs = null;
|
||||||
const addFreebieFormats = null;
|
//const addFreebieFormats = null;
|
||||||
const expand = null;
|
//const expand = null;
|
||||||
const verifyTheme = null;
|
//const verifyTheme = null;
|
||||||
const loadTheme = null;
|
//const loadTheme = null;
|
||||||
|
|
||||||
/** An invokable resume generation command. */
|
/** An invokable resume generation command. */
|
||||||
module.exports = (BuildVerb = class BuildVerb extends Verb {
|
class BuildVerb extends Verb {
|
||||||
|
|
||||||
/** Create a new build verb. */
|
/** Create a new build verb. */
|
||||||
constructor() { super('build', _build); }
|
constructor() { super('build', _build); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = BuildVerb;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ var _build = function( src, dst, opts ) {
|
|||||||
if (mixed) {
|
if (mixed) {
|
||||||
this.err(HMSTATUS.mixedMerge);
|
this.err(HMSTATUS.mixedMerge);
|
||||||
}
|
}
|
||||||
rez = _.reduceRight(sheets, ( a, b, idx ) => extend( true, b, a ));
|
rez = _.reduceRight(sheets, ( a, b ) => extend( true, b, a ));
|
||||||
this.stat(HMEVENT.afterMerge, { r: rez });
|
this.stat(HMEVENT.afterMerge, { r: rez });
|
||||||
} else {
|
} else {
|
||||||
rez = sheets[0];
|
rez = sheets[0];
|
||||||
@ -243,8 +243,6 @@ var _single = function( targInfo, theme, finished ) {
|
|||||||
if (!targInfo.fmt) {
|
if (!targInfo.fmt) {
|
||||||
return { };
|
return { };
|
||||||
}
|
}
|
||||||
const fType = targInfo.fmt.outFormat;
|
|
||||||
const fName = PATH.basename(f, `.${fType}`);
|
|
||||||
let theFormat = null;
|
let theFormat = null;
|
||||||
|
|
||||||
this.stat(HMEVENT.beforeGenerate, {
|
this.stat(HMEVENT.beforeGenerate, {
|
||||||
|
@ -11,9 +11,7 @@ Implementation of the 'convert' verb for HackMyResume.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let ConvertVerb;
|
|
||||||
const ResumeFactory = require('../core/resume-factory');
|
const ResumeFactory = require('../core/resume-factory');
|
||||||
const chalk = require('chalk');
|
|
||||||
const Verb = require('../verbs/verb');
|
const Verb = require('../verbs/verb');
|
||||||
const HMSTATUS = require('../core/status-codes');
|
const HMSTATUS = require('../core/status-codes');
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
@ -21,10 +19,11 @@ const HMEVENT = require('../core/event-codes');
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = (ConvertVerb = class ConvertVerb extends Verb {
|
class ConvertVerb extends Verb {
|
||||||
|
|
||||||
constructor() { super('convert', _convert); }
|
constructor() { super('convert', _convert); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = ConvertVerb;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -59,7 +58,7 @@ var _convert = function( srcs, dst, opts ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate the destination format (if specified)
|
// Validate the destination format (if specified)
|
||||||
const targetVer = null;
|
//const targetVer = null;
|
||||||
if (opts.format) {
|
if (opts.format) {
|
||||||
fmtUp = opts.format.trim().toUpperCase();
|
fmtUp = opts.format.trim().toUpperCase();
|
||||||
if (!_.contains(['FRESH','FRESCA','JRS','JRS@1','JRS@edge'], fmtUp)) {
|
if (!_.contains(['FRESH','FRESCA','JRS','JRS@1','JRS@edge'], fmtUp)) {
|
||||||
|
@ -11,10 +11,8 @@ Implementation of the 'create' verb for HackMyResume.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let CreateVerb;
|
|
||||||
const MKDIRP = require('mkdirp');
|
const MKDIRP = require('mkdirp');
|
||||||
const PATH = require('path');
|
const PATH = require('path');
|
||||||
const chalk = require('chalk');
|
|
||||||
const Verb = require('../verbs/verb');
|
const Verb = require('../verbs/verb');
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const HMSTATUS = require('../core/status-codes');
|
const HMSTATUS = require('../core/status-codes');
|
||||||
@ -22,10 +20,13 @@ const HMEVENT = require('../core/event-codes');
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = (CreateVerb = class CreateVerb extends Verb {
|
class CreateVerb extends Verb {
|
||||||
|
|
||||||
constructor() { super('new', _create); }
|
constructor() { super('new', _create); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = CreateVerb;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -76,10 +77,9 @@ var _createOne = function( t, opts ) {
|
|||||||
fluenterror: HMSTATUS.createError,
|
fluenterror: HMSTATUS.createError,
|
||||||
inner: err
|
inner: err
|
||||||
};
|
};
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
this.stat(HMEVENT.afterCreate, {fmt: safeFmt, file: t, isError: ret.fluenterror});
|
this.stat(HMEVENT.afterCreate, {fmt: safeFmt, file: t, isError: ret.fluenterror});
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
};
|
};
|
||||||
|
@ -11,7 +11,6 @@ Implementation of the 'peek' verb for HackMyResume.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let PeekVerb;
|
|
||||||
const Verb = require('../verbs/verb');
|
const Verb = require('../verbs/verb');
|
||||||
const _ = require('underscore');
|
const _ = require('underscore');
|
||||||
const __ = require('lodash');
|
const __ = require('lodash');
|
||||||
@ -21,12 +20,14 @@ const HMEVENT = require('../core/event-codes');
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = (PeekVerb = class PeekVerb extends Verb {
|
class PeekVerb extends Verb {
|
||||||
|
|
||||||
constructor() { super('peek', _peek); }
|
constructor() { super('peek', _peek); }
|
||||||
});
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = PeekVerb;
|
||||||
|
|
||||||
/** Peek at a resume, resume section, or resume field. */
|
/** Peek at a resume, resume section, or resume field. */
|
||||||
var _peek = function( src, dst, opts ) {
|
var _peek = function( src, dst, opts ) {
|
||||||
|
@ -11,11 +11,6 @@ Implementation of the 'validate' verb for HackMyResume.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let ValidateVerb;
|
|
||||||
const FS = require('fs');
|
|
||||||
const ResumeFactory = require('../core/resume-factory');
|
|
||||||
const SyntaxErrorEx = require('../utils/syntax-error-ex');
|
|
||||||
const chalk = require('chalk');
|
|
||||||
const Verb = require('../verbs/verb');
|
const Verb = require('../verbs/verb');
|
||||||
const HMSTATUS = require('../core/status-codes');
|
const HMSTATUS = require('../core/status-codes');
|
||||||
const HMEVENT = require('../core/event-codes');
|
const HMEVENT = require('../core/event-codes');
|
||||||
@ -25,12 +20,9 @@ const safeLoadJSON = require('../utils/safe-json-loader');
|
|||||||
|
|
||||||
|
|
||||||
/** An invokable resume validation command. */
|
/** An invokable resume validation command. */
|
||||||
module.exports = (ValidateVerb = class ValidateVerb extends Verb {
|
class ValidateVerb extends Verb {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
constructor() { super('validate', _validate); }
|
constructor() { super('validate', _validate); }
|
||||||
});
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -63,6 +55,7 @@ var _validate = function(sources, unused, opts) {
|
|||||||
return results;
|
return results;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports = ValidateVerb;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Validate a single resume.
|
Validate a single resume.
|
||||||
@ -75,7 +68,7 @@ Validate a single resume.
|
|||||||
error: <errorObject>
|
error: <errorObject>
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
var _validateOne = function(t, validator, schemas, opts) {
|
var _validateOne = function(t, validator, schemas) {
|
||||||
|
|
||||||
const ret = {file: t, isValid: false, status: 'unknown', schema: '-----'};
|
const ret = {file: t, isValid: false, status: 'unknown', schema: '-----'};
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ Definition of the Verb class.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
let Verb;
|
|
||||||
const EVENTS = require('events');
|
const EVENTS = require('events');
|
||||||
const HMEVENT = require('../core/event-codes');
|
const HMEVENT = require('../core/event-codes');
|
||||||
const Promise = require('pinkie-promise');
|
const Promise = require('pinkie-promise');
|
||||||
@ -25,7 +24,7 @@ error handling, event management, and promise support.
|
|||||||
@class Verb
|
@class Verb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
module.exports = (Verb = class Verb {
|
class Verb {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -111,4 +110,6 @@ module.exports = (Verb = class Verb {
|
|||||||
this.errorCode = code;
|
this.errorCode = code;
|
||||||
this.errorObj = obj;
|
this.errorObj = obj;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
module.exports = Verb;
|
||||||
|
Loading…
Reference in New Issue
Block a user