1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2024-11-24 17:30:10 +00:00
This commit is contained in:
hacksalot 2016-02-11 11:48:44 -05:00
parent aaa5e1fc1f
commit 317a250917
7 changed files with 203 additions and 297 deletions

View File

@ -6,7 +6,7 @@ Definition of the FRESHTheme class.
*/ */
(function() { (function() {
var EXTEND, FRESHTheme, FS, HMSTATUS, PATH, READFILES, _, _load, friendlyName, loadSafeJson, moment, parsePath, pathExists, validator; var EXTEND, FRESHTheme, FS, HMSTATUS, PATH, READFILES, _, _load, _loadOne, friendlyName, loadSafeJson, moment, parsePath, pathExists, validator;
FS = require('fs'); FS = require('fs');
@ -31,9 +31,7 @@ Definition of the FRESHTheme class.
READFILES = require('recursive-readdir-sync'); READFILES = require('recursive-readdir-sync');
/* /* A representation of a FRESH theme asset.
The FRESHTheme class is a representation of a FRESH theme
asset. See also: JRSTheme.
@class FRESHTheme @class FRESHTheme
*/ */
@ -41,9 +39,7 @@ Definition of the FRESHTheme class.
function FRESHTheme() {} function FRESHTheme() {}
/* /* Open and parse the specified theme. */
Open and parse the specified theme.
*/
FRESHTheme.prototype.open = function(themeFolder) { FRESHTheme.prototype.open = function(themeFolder) {
var cached, formatsHash, pathInfo, that, themeFile, themeInfo; var cached, formatsHash, pathInfo, that, themeFile, themeInfo;
@ -96,9 +92,7 @@ Definition of the FRESHTheme class.
})(); })();
/* Load the theme implicitly, by scanning the theme folder for files. TODO: /* Load and parse theme source files. */
Refactor duplicated code with loadExplicit.
*/
_load = function(formatsHash) { _load = function(formatsHash) {
var copyOnly, fmts, major, that, tplFolder; var copyOnly, fmts, major, that, tplFolder;
@ -107,74 +101,8 @@ Definition of the FRESHTheme class.
tplFolder = PATH.join(this.folder, 'src'); tplFolder = PATH.join(this.folder, 'src');
copyOnly = ['.ttf', '.otf', '.png', '.jpg', '.jpeg', '.pdf']; copyOnly = ['.ttf', '.otf', '.png', '.jpg', '.jpeg', '.pdf'];
fmts = READFILES(tplFolder).map(function(absPath) { fmts = READFILES(tplFolder).map(function(absPath) {
var absPathSafe, act, idx, isMajor, obj, outFmt, pathInfo, portion, ref, ref1, reg, res; return _loadOne.call(this, absPath, formatsHash, tplFolder);
pathInfo = parsePath(absPath); }, this);
absPathSafe = absPath.trim().toLowerCase();
outFmt = '';
isMajor = false;
if (that.formats) {
outFmt = _.find(Object.keys(that.formats), function(fmtKey) {
var fmtVal;
fmtVal = that.formats[fmtKey];
return _.some(fmtVal.transform, function(fpath) {
var absPathB;
absPathB = PATH.join(that.folder, fpath).trim().toLowerCase();
return absPathB === absPathSafe;
});
});
if (outFmt) {
isMajor = true;
}
}
if (!outFmt) {
portion = pathInfo.dirname.replace(tplFolder, '');
if (portion && portion.trim()) {
if (portion[1] === '_') {
return;
}
reg = /^(?:\/|\\)(html|latex|doc|pdf|png|partials)(?:\/|\\)?/ig;
res = reg.exec(portion);
if (res) {
if (res[1] !== 'partials') {
outFmt = res[1];
} else {
that.partials = that.partials || [];
that.partials.push({
name: pathInfo.name,
path: absPath
});
return null;
}
}
}
}
if (!outFmt) {
idx = pathInfo.name.lastIndexOf('-');
outFmt = idx === -1 ? pathInfo.name : pathInfo.name.substr(idx + 1);
isMajor = true;
}
act = _.contains(copyOnly, pathInfo.extname) ? 'copy' : 'transform';
formatsHash[outFmt] = formatsHash[outFmt] || {
outFormat: outFmt,
files: []
};
if ((ref = that.formats) != null ? (ref1 = ref[outFmt]) != null ? ref1.symLinks : void 0 : void 0) {
formatsHash[outFmt].symLinks = that.formats[outFmt].symLinks;
}
obj = {
action: act,
path: absPath,
major: isMajor,
orgPath: PATH.relative(tplFolder, absPath),
ext: pathInfo.extname.slice(1),
title: friendlyName(outFmt),
pre: outFmt,
data: FS.readFileSync(absPath, 'utf8'),
css: null
};
formatsHash[outFmt].files.push(obj);
return obj;
});
this.cssFiles = fmts.filter(function(fmt) { this.cssFiles = fmts.filter(function(fmt) {
return fmt && (fmt.ext === 'css'); return fmt && (fmt.ext === 'css');
}); });
@ -200,14 +128,87 @@ Definition of the FRESHTheme class.
}; };
/* /* Load a single theme file. */
Return a more friendly name for certain formats.
TODO: Refactor _loadOne = function(absPath, formatsHash, tplFolder) {
*/ var absPathSafe, act, idx, obj, outFmt, pathInfo, portion, ref, ref1, reg, res, shouldTransform;
pathInfo = parsePath(absPath);
absPathSafe = absPath.trim().toLowerCase();
outFmt = '';
shouldTransform = false;
if (this.explicit) {
outFmt = _.find(Object.keys(this.formats), function(fmtKey) {
var fmtVal;
fmtVal = this.formats[fmtKey];
return _.some(fmtVal.transform, function(fpath) {
var absPathB;
absPathB = PATH.join(this.folder, fpath).trim().toLowerCase();
return absPathB === absPathSafe;
}, this);
}, this);
if (outFmt) {
act = 'transform';
}
}
if (!outFmt) {
portion = pathInfo.dirname.replace(tplFolder, '');
if (portion && portion.trim()) {
if (portion[1] === '_') {
return;
}
reg = /^(?:\/|\\)(html|latex|doc|pdf|png|partials)(?:\/|\\)?/ig;
res = reg.exec(portion);
if (res) {
if (res[1] !== 'partials') {
outFmt = res[1];
if (!this.explicit) {
act = 'transform';
}
} else {
this.partials = this.partials || [];
this.partials.push({
name: pathInfo.name,
path: absPath
});
return null;
}
}
}
}
if (!outFmt) {
idx = pathInfo.name.lastIndexOf('-');
outFmt = idx === -1 ? pathInfo.name : pathInfo.name.substr(idx + 1);
if (!this.explicit) {
act = 'transform';
}
}
formatsHash[outFmt] = formatsHash[outFmt] || {
outFormat: outFmt,
files: []
};
if ((ref = this.formats) != null ? (ref1 = ref[outFmt]) != null ? ref1.symLinks : void 0 : void 0) {
formatsHash[outFmt].symLinks = this.formats[outFmt].symLinks;
}
obj = {
action: act,
path: absPath,
orgPath: PATH.relative(tplFolder, absPath),
ext: pathInfo.extname.slice(1),
title: friendlyName(outFmt),
pre: outFmt,
data: FS.readFileSync(absPath, 'utf8'),
css: null
};
formatsHash[outFmt].files.push(obj);
return obj;
};
/* Return a more friendly name for certain formats. */
friendlyName = function(val) { friendlyName = function(val) {
var friendly; var friendly;
val = val.trim().toLowerCase(); val = (val && val.trim().toLowerCase()) || '';
friendly = { friendly = {
yml: 'yaml', yml: 'yaml',
md: 'markdown', md: 'markdown',

View File

@ -131,7 +131,6 @@ Definition of the TemplateGenerator class. TODO: Refactor
opts.beforeWrite(thisFilePath); opts.beforeWrite(thisFilePath);
} }
MKDIRP.sync(PATH.dirname(thisFilePath)); MKDIRP.sync(PATH.dirname(thisFilePath));
console.log(file.info.path);
if (file.info.action !== 'copy') { if (file.info.action !== 'copy') {
FS.writeFileSync(thisFilePath, file.data, { FS.writeFileSync(thisFilePath, file.data, {
encoding: 'utf8', encoding: 'utf8',

View File

@ -38,18 +38,21 @@ Generic template helper definitions for HackMyResume / FluentCV.
GenericHelpers = module.exports = { GenericHelpers = module.exports = {
/** /**
Convert the input date to a specified format through Moment.js. Display a formatted date with optional fallback text.
If date is invalid, will return the time provided by the user, Convert the input date to the specified format through Moment.js. If date is
or default to the fallback param or 'Present' if that is set to true valid, return the formatted date string. If date is null, undefined, or other
@method formatDate falsy value, return the value of the 'fallback' parameter, if specified, or
null if no fallback was specified. If date is invalid, but not null/undefined/
falsy, return it as-is.
*/ */
formatDate: function(datetime, format, fallback) { formatDate: function(datetime, dtFormat, fallback) {
var momentDate; var momentDate;
if (moment) { if (dtFormat == null) {
dtFormat = 'YYYY-MM';
}
momentDate = moment(datetime); momentDate = moment(datetime);
if (momentDate.isValid()) { if (momentDate.isValid()) {
return momentDate.format(format); return momentDate.format(dtFormat);
}
} }
return datetime || (typeof fallback === 'string' ? fallback : (fallback === true ? 'Present' : null)); return datetime || (typeof fallback === 'string' ? fallback : (fallback === true ? 'Present' : null));
}, },
@ -99,8 +102,8 @@ Generic template helper definitions for HackMyResume / FluentCV.
}, },
/** /**
Return true if the section is present on the resume and has at least one Block-level helper. Emit the enclosed content if the resume has a section with
element. the specified name. Otherwise, emit an empty string ''.
@method section @method section
*/ */
section: function(title, options) { section: function(title, options) {
@ -292,7 +295,7 @@ Generic template helper definitions for HackMyResume / FluentCV.
}, },
/** /**
Return true if the context has the property or subpropery. Emit the enclosed content if the resume has the named property or subproperty.
@method has @method has
*/ */
has: function(title, options) { has: function(title, options) {
@ -328,10 +331,7 @@ Generic template helper definitions for HackMyResume / FluentCV.
return (this.opts.stitles && this.opts.stitles[sname.toLowerCase().trim()]) || stitle; return (this.opts.stitles && this.opts.stitles[sname.toLowerCase().trim()]) || stitle;
}, },
/** /** Convert inline Markdown to inline WordProcessingML. */
Convert inline Markdown to inline WordProcessingML.
@method wpml
*/
wpml: function(txt, inline) { wpml: function(txt, inline) {
if (!txt) { if (!txt) {
return ''; return '';

View File

@ -20,32 +20,26 @@ READFILES = require 'recursive-readdir-sync'
### ### A representation of a FRESH theme asset.
The FRESHTheme class is a representation of a FRESH theme @class FRESHTheme ###
asset. See also: JRSTheme.
@class FRESHTheme
###
class FRESHTheme class FRESHTheme
### Open and parse the specified theme. ###
###
Open and parse the specified theme.
###
open: ( themeFolder ) -> open: ( themeFolder ) ->
this.folder = themeFolder; this.folder = themeFolder;
# Open the [theme-name].json file; should have the same name as folder # Open the [theme-name].json file; should have the same name as folder
pathInfo = parsePath( themeFolder ) pathInfo = parsePath themeFolder
# Set up a formats hash for the theme # Set up a formats hash for the theme
formatsHash = { } formatsHash = { }
# Load the theme # Load the theme
themeFile = PATH.join( themeFolder, 'theme.json' ) themeFile = PATH.join themeFolder, 'theme.json'
themeInfo = loadSafeJson( themeFile ) themeInfo = loadSafeJson themeFile
if themeInfo.ex if themeInfo.ex
throw throw
fluenterror: fluenterror:
@ -87,15 +81,11 @@ class FRESHTheme
### Load the theme implicitly, by scanning the theme folder for files. TODO: ### Load and parse theme source files. ###
Refactor duplicated code with loadExplicit. ###
_load = (formatsHash) -> _load = (formatsHash) ->
# Set up a hash of formats supported by this theme.
that = @ that = @
major = false major = false
# Establish the base theme folder
tplFolder = PATH.join @folder, 'src' tplFolder = PATH.join @folder, 'src'
copyOnly = ['.ttf','.otf', '.png','.jpg','.jpeg','.pdf'] copyOnly = ['.ttf','.otf', '.png','.jpg','.jpeg','.pdf']
@ -104,71 +94,8 @@ _load = (formatsHash) ->
# 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.
fmts = READFILES(tplFolder).map (absPath) -> fmts = READFILES(tplFolder).map (absPath) ->
_loadOne.call @, absPath, formatsHash, tplFolder
pathInfo = parsePath absPath , @
absPathSafe = absPath.trim().toLowerCase()
outFmt = ''
isMajor = false
# If this file is mentioned in the theme's JSON file under "transforms"
if that.formats
outFmt = _.find Object.keys( that.formats ), ( fmtKey ) ->
fmtVal = that.formats[ fmtKey ]
_.some fmtVal.transform, (fpath) ->
absPathB = PATH.join( that.folder, fpath ).trim().toLowerCase()
absPathB == absPathSafe
isMajor = true if outFmt
if !outFmt
# If this file lives in a specific format folder within the theme,
# such as "/latex" or "/html", then that format is the output format
# for all files within the folder.
portion = pathInfo.dirname.replace tplFolder,''
if portion && portion.trim()
return if portion[1] == '_'
reg = /^(?:\/|\\)(html|latex|doc|pdf|png|partials)(?:\/|\\)?/ig
res = reg.exec( portion )
if res
if res[1] != 'partials'
outFmt = res[1]
else
that.partials = that.partials || []
that.partials.push( { name: pathInfo.name, path: absPath } )
return null
# Otherwise, the output format is inferred from the filename, as in
# compact-[outputformat].[extension], for ex, compact-pdf.html.
if !outFmt
idx = pathInfo.name.lastIndexOf '-'
outFmt = if idx == -1 then pathInfo.name else pathInfo.name.substr( idx + 1 )
isMajor = true
act = if _.contains copyOnly, pathInfo.extname then 'copy' else 'transform'
# We should have a valid output format now.
formatsHash[ outFmt ] = formatsHash[outFmt] || {
outFormat: outFmt,
files: []
}
if that.formats?[ outFmt ]?.symLinks
formatsHash[ outFmt ].symLinks = that.formats[ outFmt ].symLinks
# Create the file representation object.
obj =
action: act
path: absPath
major: isMajor
orgPath: PATH.relative tplFolder, absPath
ext: pathInfo.extname.slice 1
title: friendlyName outFmt
pre: outFmt
# outFormat: outFmt || pathInfo.name,
data: FS.readFileSync absPath, 'utf8'
css: null
# Add this file to the list of files for this format type.
formatsHash[ outFmt ].files.push( obj )
obj
# Now, get all the CSS files... # Now, get all the CSS files...
@cssFiles = fmts.filter (fmt) -> fmt and (fmt.ext == 'css') @cssFiles = fmts.filter (fmt) -> fmt and (fmt.ext == 'css')
@ -192,101 +119,86 @@ _load = (formatsHash) ->
# ### ### Load a single theme file. ###
# Load the theme explicitly, by following the 'formats' hash _loadOne = ( absPath, formatsHash, tplFolder ) ->
# in the theme's JSON settings file.
# ### pathInfo = parsePath absPath
# loadExplicit = (formatsHash) -> absPathSafe = absPath.trim().toLowerCase()
# outFmt = ''
# # Housekeeping shouldTransform = false
# tplFolder = PATH.join this.folder, 'src'
# act = null # If this is an "explicit" theme, all files of importance are specified in
# that = this # the "transform" section of the theme.json file.
# if @explicit
# # 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 outFmt = _.find Object.keys( @formats ), ( fmtKey ) ->
# # the formatsHash object. fmtVal = @formats[ fmtKey ]
# fmts = READFILES( tplFolder ).map (absPath) -> _.some fmtVal.transform, (fpath) ->
# absPathB = PATH.join( @folder, fpath ).trim().toLowerCase()
# act = null absPathB == absPathSafe
# , @
# pathInfo = parsePath absPath , @
# absPathSafe = absPath.trim().toLowerCase() act = 'transform' if outFmt
#
# # If this file is mentioned in the theme's JSON file under "transforms" if !outFmt
# outFmt = _.find Object.keys( that.formats ), ( fmtKey ) -> # If this file lives in a specific format folder within the theme,
# fmtVal = that.formats[ fmtKey ] # such as "/latex" or "/html", then that format is the implicit output
# _.some fmtVal.transform, (fpath) -> # format for all files within the folder
# absPathB = PATH.join( that.folder, fpath ).trim().toLowerCase() portion = pathInfo.dirname.replace tplFolder,''
# absPathB == absPathSafe if portion && portion.trim()
# return if portion[1] == '_'
# act = 'transform' if outFmt reg = /^(?:\/|\\)(html|latex|doc|pdf|png|partials)(?:\/|\\)?/ig
# res = reg.exec( portion )
# # If this file lives in a specific format folder within the theme, if res
# # such as "/latex" or "/html", then that format is the output format if res[1] != 'partials'
# # for all files within the folder. outFmt = res[1]
# if !outFmt act = 'transform' if !@explicit
# portion = pathInfo.dirname.replace tplFolder,'' else
# if portion && portion.trim() @partials = @partials || []
# reg = /^(?:\/|\\)(html|latex|doc|pdf)(?:\/|\\)?/ig @partials.push( { name: pathInfo.name, path: absPath } )
# res = reg.exec portion return null
# res && (outFmt = res[1])
# # Otherwise, the output format is inferred from the filename, as in
# # Otherwise, the output format is inferred from the filename, as in # compact-[outputformat].[extension], for ex, compact-pdf.html
# # compact-[outputformat].[extension], for ex, compact-pdf.html. if !outFmt
# if !outFmt idx = pathInfo.name.lastIndexOf '-'
# idx = pathInfo.name.lastIndexOf '-' outFmt = if idx == -1 then pathInfo.name else pathInfo.name.substr idx+1
# outFmt = if (idx == -1) then pathInfo.name else pathInfo.name.substr(idx + 1) act = 'transform' if !@explicit
#
# # We should have a valid output format now. # Make sure we have a valid formatsHash
# formatsHash[ outFmt ] = formatsHash[ outFmt ] = formatsHash[outFmt] || {
# formatsHash[ outFmt ] || { outFormat: outFmt,
# outFormat: outFmt, files: []
# files: [], }
# symLinks: that.formats[ outFmt ].symLinks
# }; # Move symlink descriptions from theme.json to the format
# if @formats?[ outFmt ]?.symLinks
# # Create the file representation object. formatsHash[ outFmt ].symLinks = @formats[ outFmt ].symLinks
# obj =
# action: act # Create the file representation object
# orgPath: PATH.relative(that.folder, absPath) obj =
# path: absPath action: act
# ext: pathInfo.extname.slice(1) path: absPath
# title: friendlyName( outFmt ) orgPath: PATH.relative tplFolder, absPath
# pre: outFmt ext: pathInfo.extname.slice 1
# # outFormat: outFmt || pathInfo.name, title: friendlyName outFmt
# data: FS.readFileSync( absPath, 'utf8' ) pre: outFmt
# css: null # outFormat: outFmt || pathInfo.name,
# data: FS.readFileSync absPath, 'utf8'
# # Add this file to the list of files for this format type. css: null
# formatsHash[ outFmt ].files.push( obj )
# obj # Add this file to the list of files for this format type.
# formatsHash[ outFmt ].files.push( obj )
# # Now, get all the CSS files... obj
# @cssFiles = fmts.filter ( fmt ) -> fmt.ext == 'css'
#
# # For each CSS file, get its corresponding HTML file
# @cssFiles.forEach ( cssf ) ->
# # For each CSS file, get its corresponding HTML file
# idx = _.findIndex fmts, ( fmt ) ->
# fmt.pre == cssf.pre && fmt.ext == 'html'
# fmts[ idx ].css = cssf.data
# fmts[ idx ].cssPath = cssf.path
#
# # Remove CSS files from the formats array
# fmts = fmts.filter ( fmt) -> fmt.ext != 'css'
# formatsHash
### ### Return a more friendly name for certain formats. ###
Return a more friendly name for certain formats.
TODO: Refactor
###
friendlyName = ( val ) -> friendlyName = ( val ) ->
val = val.trim().toLowerCase() val = (val && val.trim().toLowerCase()) || ''
friendly = { yml: 'yaml', md: 'markdown', txt: 'text' } friendly = { yml: 'yaml', md: 'markdown', txt: 'text' }
friendly[val] || val friendly[val] || val
module.exports = FRESHTheme module.exports = FRESHTheme

View File

@ -64,7 +64,7 @@ module.exports = class TemplateGenerator extends BaseGenerator
# Run the transformation! # Run the transformation!
results = curFmt.files.map ( tplInfo, idx ) -> results = curFmt.files.map ( tplInfo, idx ) ->
if tplInfo.action == 'transform' if tplInfo.action == 'transform'
trx = @transform rez, tplInfo.data, this.format, opts, opts.themeObj, curFmt trx = @transform rez, tplInfo.data, @format, opts, opts.themeObj, curFmt
if tplInfo.ext == 'css' if tplInfo.ext == 'css'
curFmt.files[idx].data = trx curFmt.files[idx].data = trx
else tplInfo.ext == 'html' else tplInfo.ext == 'html'
@ -109,20 +109,17 @@ module.exports = class TemplateGenerator extends BaseGenerator
if file.info.action != 'copy' and @onBeforeSave if file.info.action != 'copy' and @onBeforeSave
file.data = this.onBeforeSave file.data = this.onBeforeSave
theme: opts.themeObj theme: opts.themeObj
outputFile: thisFilePath #if file.info.major then f else thisFilePath outputFile: thisFilePath
mk: file.data mk: file.data
opts: this.opts opts: this.opts
if !file.data if !file.data
return # PDF etc return
# Write the file # Write the file
opts.beforeWrite? thisFilePath opts.beforeWrite? thisFilePath
MKDIRP.sync PATH.dirname( thisFilePath ) MKDIRP.sync PATH.dirname( thisFilePath )
#console.log( Object.keys(file.info) )
console.log file.info.path
if file.info.action != 'copy' if file.info.action != 'copy'
FS.writeFileSync thisFilePath, file.data, encoding: 'utf8', flags: 'w' FS.writeFileSync thisFilePath, file.data, encoding: 'utf8', flags: 'w'
else else

View File

@ -27,15 +27,18 @@ GenericHelpers = module.exports =
###* ###*
Convert the input date to a specified format through Moment.js. Display a formatted date with optional fallback text.
If date is invalid, will return the time provided by the user, Convert the input date to the specified format through Moment.js. If date is
or default to the fallback param or 'Present' if that is set to true valid, return the formatted date string. If date is null, undefined, or other
@method formatDate falsy value, return the value of the 'fallback' parameter, if specified, or
null if no fallback was specified. If date is invalid, but not null/undefined/
falsy, return it as-is.
### ###
formatDate: (datetime, format, fallback) -> formatDate: (datetime, dtFormat, fallback) ->
if moment
dtFormat ?= 'YYYY-MM'
momentDate = moment datetime momentDate = moment datetime
return momentDate.format(format) if momentDate.isValid() return momentDate.format(dtFormat) if momentDate.isValid()
datetime || datetime ||
if typeof fallback == 'string' if typeof fallback == 'string'
@ -82,8 +85,8 @@ GenericHelpers = module.exports =
###* ###*
Return true if the section is present on the resume and has at least one Block-level helper. Emit the enclosed content if the resume has a section with
element. the specified name. Otherwise, emit an empty string ''.
@method section @method section
### ###
section: ( title, options ) -> section: ( title, options ) ->
@ -273,7 +276,7 @@ GenericHelpers = module.exports =
###* ###*
Return true if the context has the property or subpropery. Emit the enclosed content if the resume has the named property or subproperty.
@method has @method has
### ###
has: ( title, options ) -> has: ( title, options ) ->
@ -319,10 +322,7 @@ GenericHelpers = module.exports =
###* ###* Convert inline Markdown to inline WordProcessingML. ###
Convert inline Markdown to inline WordProcessingML.
@method wpml
###
wpml: ( txt, inline ) -> wpml: ( txt, inline ) ->
return '' if !txt return '' if !txt
inline = (inline && !inline.hash) || false inline = (inline && !inline.hash) || false

View File

@ -239,10 +239,7 @@ _single = ( targInfo, theme, finished ) ->
ret = theFormat.gen.generate _rezObj, f, _opts ret = theFormat.gen.generate _rezObj, f, _opts
catch e catch e
# Catch any errors caused by generating this file and don't let them ex = e
# propagate -- typically we want to continue processing other formats
# even if this format failed.
ex = e;
this.stat HMEVENT.afterGenerate, this.stat HMEVENT.afterGenerate,
fmt: targInfo.fmt.outFormat, fmt: targInfo.fmt.outFormat,