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:
parent
fb783cdbc6
commit
3b8d100f39
@ -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.
|
||||||
|
18
src/eng/handlebars-generator.js
Normal file
18
src/eng/handlebars-generator.js
Normal 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 || '' } )
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}());
|
37
src/eng/underscore-generator.js
Normal file
37
src/eng/underscore-generator.js
Normal 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;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}());
|
@ -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' )
|
|
||||||
};
|
|
||||||
|
Loading…
Reference in New Issue
Block a user