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

Add baseline Handlebars support.

This commit is contained in:
devlinjd 2015-12-06 16:19:55 -05:00
parent fb783cdbc6
commit 3b8d100f39
4 changed files with 204 additions and 156 deletions

View File

@ -10,10 +10,11 @@ Abstract theme representation.
, validator = require('is-my-json-valid') , validator = require('is-my-json-valid')
, _ = require('underscore') , _ = require('underscore')
, PATH = require('path') , PATH = require('path')
, EXTEND = require('../utils/extend')
, moment = require('moment'); , moment = require('moment');
/** /**
The Theme class represents a specific presentation of a resume. The Theme class is a representation of a FluentCV theme asset.
@class Theme @class Theme
*/ */
function Theme() { function Theme() {
@ -31,8 +32,12 @@ Abstract theme representation.
return friendly[val] || val; return friendly[val] || val;
} }
// Remember the theme folder; might be custom // Open the theme.json file; should have the same name as folder
this.folder = themeFolder; this.folder = themeFolder;
var pathInfo = PATH.parse( themeFolder );
var themeFile = PATH.join( themeFolder, pathInfo.base + '.json' );
var themeInfo = JSON.parse( FS.readFileSync( themeFile, 'utf8' ) );
EXTEND( true, this, themeInfo );
// 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. // containing info for each file.

View File

@ -0,0 +1,18 @@
/**
Handlebars template generate for FluentCV.
@license MIT. Copyright (c) 2015 James M. Devlin / FluentDesk.
*/
(function() {
var _ = require('underscore');
var HANDLEBARS = require('handlebars');
module.exports = function( json, jst, format, cssInfo, opts ) {
var template = HANDLEBARS.compile(jst);
return template( { r: json, filt: opts.filters, cssInfo: cssInfo, headFragment: opts.headFragment || '' } )
};
}());

View File

@ -0,0 +1,37 @@
/**
Underscore template generate for FluentCV.
@license MIT. Copyright (c) 2015 James M. Devlin / FluentDesk.
*/
(function() {
var _ = require('underscore');
module.exports = function( json, jst, format, cssInfo, opts ) {
// Tweak underscore's default template delimeters
_.templateSettings = opts.template;
// Convert {{ someVar }} to {% print(filt.out(someVar) %}
// Convert {{ someVar|someFilter }} to {% print(filt.someFilter(someVar) %}
jst = jst.replace( _.templateSettings.interpolate, function replace(m, p1) {
if( p1.indexOf('|') > -1 ) {
var terms = p1.split('|');
return '{% print( filt.' + terms[1] + '( ' + terms[0] + ' )) %}';
}
else {
return '{% print( filt.out(' + p1 + ') ) %}';
}
});
// Strip {# comments #}
jst = jst.replace( _.templateSettings.comment, '');
// Compile and run the template. TODO: avoid unnecessary recompiles.
jst = _.template(jst)({ r: json, filt: opts.filters, cssInfo: cssInfo, headFragment: opts.headFragment || '' });
return jst;
};
}());

View File

@ -1,176 +1,164 @@
/** /**
Template-based resume generator base for FluentCV. Template-based resume generator base for FluentCV.
@license Copyright (c) 2015 | James M. Devlin @license MIT. Copyright (c) 2015 James M. Devlin / FluentDesk.
*/ */
var FS = require( 'fs' ) (function() {
, _ = require( 'underscore' )
, MD = require( 'marked' )
, XML = require( 'xml-escape' )
, PATH = require('path')
, BaseGenerator = require( './base-generator' )
, EXTEND = require('../utils/extend')
, Theme = require('../core/theme');
// Default options. var FS = require( 'fs' )
var _defaultOpts = { , _ = require( 'underscore' )
keepBreaks: true, , MD = require( 'marked' )
freezeBreaks: true, , XML = require( 'xml-escape' )
nSym: '&newl;', // newline entity , PATH = require('path')
rSym: '&retn;', // return entity , BaseGenerator = require( './base-generator' )
template: { , EXTEND = require('../utils/extend')
interpolate: /\{\{(.+?)\}\}/g, , Theme = require('../core/theme');
escape: /\{\{\=(.+?)\}\}/g,
evaluate: /\{\%(.+?)\%\}/g,
comment: /\{\#(.+?)\#\}/g
},
filters: {
out: function( txt ) { return txt; },
raw: function( txt ) { return txt; },
xml: function( txt ) { return XML(txt); },
md: function( txt ) { return MD( txt || '' ); },
mdin: function( txt ) { return MD(txt || '' ).replace(/^\s*\<p\>|\<\/p\>\s*$/gi, ''); },
lower: function( txt ) { return txt.toLowerCase(); },
link: function( name, url ) { return url ?
'<a href="' + url + '">' + name + '</a>' : name }
},
prettify: { // ← See https://github.com/beautify-web/js-beautify#options
indent_size: 2,
unformatted: ['em','strong','a'],
max_char: 80, // ← See lib/html.js in above-linked repo
//wrap_line_length: 120, <-- Don't use this
}
};
/** // Default options.
TemplateGenerator performs resume generation via Underscore-style template var _defaultOpts = {
expansion and is appropriate for text-based formats like HTML, plain text, engine: 'underscore',
and XML versions of Microsoft Word, Excel, and OpenOffice. keepBreaks: true,
*/ freezeBreaks: true,
var TemplateGenerator = module.exports = BaseGenerator.extend({ nSym: '&newl;', // newline entity
rSym: '&retn;', // return entity
/** outputFormat: html, txt, pdf, doc template: {
templateFormat: html or txt interpolate: /\{\{(.+?)\}\}/g,
**/ escape: /\{\{\=(.+?)\}\}/g,
init: function( outputFormat, templateFormat, cssFile ){ evaluate: /\{\%(.+?)\%\}/g,
this._super( outputFormat ); comment: /\{\#(.+?)\#\}/g
this.tplFormat = templateFormat || outputFormat; },
}, filters: {
out: function( txt ) { return txt; },
/** Default generation method for template-based generators. */ raw: function( txt ) { return txt; },
invoke: function( rez, themeMarkup, cssInfo, opts ) { xml: function( txt ) { return XML(txt); },
md: function( txt ) { return MD( txt || '' ); },
// Compile and invoke the template! mdin: function( txt ) { return MD(txt || '' ).replace(/^\s*\<p\>|\<\/p\>\s*$/gi, ''); },
this.opts = EXTEND( true, {}, _defaultOpts, opts ); lower: function( txt ) { return txt.toLowerCase(); },
mk = this.single( rez, themeMarkup, this.format, cssInfo, { } ); link: function( name, url ) { return url ?
this.onBeforeSave && (mk = this.onBeforeSave( mk, themeFile, f )); '<a href="' + url + '">' + name + '</a>' : name }
return mk; },
prettify: { // ← See https://github.com/beautify-web/js-beautify#options
}, indent_size: 2,
unformatted: ['em','strong','a'],
/** Default generation method for template-based generators. */ max_char: 80, // ← See lib/html.js in above-linked repo
generate: function( rez, f, opts ) { //wrap_line_length: 120, <-- Don't use this
// Carry over options
this.opts = EXTEND( true, { }, _defaultOpts, opts );
// Verify the specified theme name/path
var tFolder = PATH.join(
PATH.parse( require.resolve('fluent-themes') ).dir,
this.opts.theme
);
var exists = require('../utils/file-exists');
if (!exists( tFolder )) {
tFolder = PATH.resolve( this.opts.theme );
if (!exists( tFolder )) {
throw { fluenterror: this.codes.themeNotFound, data: this.opts.theme };
}
} }
};
// Load the theme
var theme = opts.themeObj || new Theme().open( tFolder );
// Load theme and CSS data
var tplFolder = PATH.join( tFolder, 'templates' );
var curFmt = theme.getFormat( this.format );
var cssInfo = { file: curFmt.css ? curFmt.cssPath : null, data: curFmt.css || null };
// Compile and invoke the template!
var mk = this.single( rez, curFmt.data, this.format, cssInfo, opts );
this.onBeforeSave && (mk = this.onBeforeSave( { mk: mk, theme: theme, outputFile: f } ));
FS.writeFileSync( f, mk, { encoding: 'utf8', flags: 'w' } );
},
/** /**
Perform a single resume JSON-to-DEST resume transformation. Exists as a TemplateGenerator performs resume generation via local Handlebar or Underscore
separate function in order to expose string-based transformations to clients style template expansion and is appropriate for text-based formats like HTML,
who don't have access to filesystem resources (in-browser, etc.). plain text, and XML versions of Microsoft Word, Excel, and OpenOffice.
*/ */
single: function( json, jst, format, cssInfo, opts ) { var TemplateGenerator = module.exports = BaseGenerator.extend({
// Freeze whitespace in the template. /** outputFormat: html, txt, pdf, doc
this.opts.freezeBreaks && ( jst = freeze(jst) ); templateFormat: html or txt
**/
init: function( outputFormat, templateFormat, cssFile ){
this._super( outputFormat );
this.tplFormat = templateFormat || outputFormat;
},
// Tweak underscore's default template delimeters /** Default generation method for template-based generators. */
_.templateSettings = this.opts.template; invoke: function( rez, themeMarkup, cssInfo, opts ) {
// Convert {{ someVar }} to {% print(filt.out(someVar) %} // Compile and invoke the template!
// Convert {{ someVar|someFilter }} to {% print(filt.someFilter(someVar) %} this.opts = EXTEND( true, {}, _defaultOpts, opts );
jst = jst.replace( _.templateSettings.interpolate, function replace(m, p1) { mk = this.single( rez, themeMarkup, this.format, cssInfo, { } );
if( p1.indexOf('|') > -1 ) { this.onBeforeSave && (mk = this.onBeforeSave( mk, themeFile, f ));
var terms = p1.split('|'); return mk;
return '{% print( filt.' + terms[1] + '( ' + terms[0] + ' )) %}';
},
/** Default generation method for template-based generators. */
generate: function( rez, f, opts ) {
// Carry over options
this.opts = EXTEND( true, { }, _defaultOpts, opts );
// Verify the specified theme name/path
var tFolder = PATH.join(
PATH.parse( require.resolve('fluent-themes') ).dir,
this.opts.theme
);
var exists = require('../utils/file-exists');
if (!exists( tFolder )) {
tFolder = PATH.resolve( this.opts.theme );
if (!exists( tFolder )) {
throw { fluenterror: this.codes.themeNotFound, data: this.opts.theme };
}
} }
else {
return '{% print( filt.out(' + p1 + ') ) %}';
}
});
// Strip {# comments #} // Load the theme
jst = jst.replace( _.templateSettings.comment, ''); var theme = opts.themeObj || new Theme().open( tFolder );
// Compile and run the template. TODO: avoid unnecessary recompiles. // Load theme and CSS data
jst = _.template(jst)({ r: json, filt: this.opts.filters, cssInfo: cssInfo, headFragment: this.opts.headFragment || '' }); var tplFolder = PATH.join( tFolder, 'templates' );
var curFmt = theme.getFormat( this.format );
var cssInfo = { file: curFmt.css ? curFmt.cssPath : null, data: curFmt.css || null };
// Unfreeze whitespace // Compile and invoke the template!
this.opts.freezeBreaks && ( jst = unfreeze(jst) ); var mk = this.single( rez, curFmt.data, this.format, cssInfo, this.opts );
this.onBeforeSave && (mk = this.onBeforeSave( { mk: mk, theme: theme, outputFile: f } ));
FS.writeFileSync( f, mk, { encoding: 'utf8', flags: 'w' } );
return jst; },
/**
Perform a single resume JSON-to-DEST resume transformation. Exists as a
separate function in order to expose string-based transformations to clients
who don't have access to filesystem resources (in-browser, etc.).
*/
single: function( json, jst, format, cssInfo, opts ) {
// Freeze whitespace in the template.
this.opts.freezeBreaks && ( jst = freeze(jst) );
// Apply the template.
var eng = require( '../eng/' + opts.themeObj.engine + '-generator' );
var result = eng( json, jst, format, cssInfo, opts );
// Unfreeze whitespace.
this.opts.freezeBreaks && ( result = unfreeze(result) );
return result;
}
});
/**
Export the TemplateGenerator function/ctor.
*/
module.exports = TemplateGenerator;
/**
Freeze newlines for protection against errant JST parsers.
*/
function freeze( markup ) {
return markup
.replace( _reg.regN, _defaultOpts.nSym )
.replace( _reg.regR, _defaultOpts.rSym );
} }
/**
Unfreeze newlines when the coast is clear.
*/
function unfreeze( markup ) {
return markup
.replace( _reg.regSymR, '\r' )
.replace( _reg.regSymN, '\n' );
}
}); /**
Regexes for linebreak preservation.
*/
var _reg = {
regN: new RegExp( '\n', 'g' ),
regR: new RegExp( '\r', 'g' ),
regSymN: new RegExp( _defaultOpts.nSym, 'g' ),
regSymR: new RegExp( _defaultOpts.rSym, 'g' )
};
/** }());
Export the TemplateGenerator function/ctor.
*/
module.exports = TemplateGenerator;
/**
Freeze newlines for protection against errant JST parsers.
*/
function freeze( markup ) {
return markup
.replace( _reg.regN, _defaultOpts.nSym )
.replace( _reg.regR, _defaultOpts.rSym );
}
/**
Unfreeze newlines when the coast is clear.
*/
function unfreeze( markup ) {
return markup
.replace( _reg.regSymR, '\r' )
.replace( _reg.regSymN, '\n' );
}
/**
Regexes for linebreak preservation.
*/
var _reg = {
regN: new RegExp( '\n', 'g' ),
regR: new RegExp( '\r', 'g' ),
regSymN: new RegExp( _defaultOpts.nSym, 'g' ),
regSymR: new RegExp( _defaultOpts.rSym, 'g' )
};