From f77cced7f38be758aef7d5f95a5726f3ee977e6b Mon Sep 17 00:00:00 2001 From: hacksalot Date: Wed, 20 Jan 2016 19:59:36 -0500 Subject: [PATCH] Improve error handling. --- src/cli/error.js | 85 ++++++++++++++++++--------- src/cli/msg.yml | 4 ++ src/core/status-codes.js | 4 +- src/renderers/handlebars-generator.js | 33 +++++++---- src/verbs/build.js | 4 +- 5 files changed, 88 insertions(+), 42 deletions(-) diff --git a/src/cli/error.js b/src/cli/error.js index 7492e06..e76cb08 100644 --- a/src/cli/error.js +++ b/src/cli/error.js @@ -1,9 +1,9 @@ /** Error-handling routines for HackMyResume. -@module error.js +@module cli/error @license MIT. See LICENSE.md for details. */ -// TODO: Logging library + (function() { @@ -31,6 +31,8 @@ Error-handling routines for HackMyResume. */ var ErrorHandler = module.exports = { + + init: function( debug, assert, silent ) { this.debug = debug; this.assert = assert; @@ -39,29 +41,30 @@ Error-handling routines for HackMyResume. return this; }, + + err: function( ex, shouldExit ) { + // Short-circuit logging output if --silent is on var o = this.silent ? function() { } : _defaultLog; - if( !this.msgs ) { - this.msgs = require('./msg.js').errors; - } + // Special case; can probably be removed. + if( ex.pass ) throw ex; - if( ex.pass ) - throw ex; + // Load error messages + this.msgs = this.msgs || require('./msg.js').errors; + // Handle packaged HMR exceptions if( ex.fluenterror ) { // Output the error message var objError = assembleError.call( this, ex ); - o( this[ 'format' + (objError.warning ? 'Warning' : 'Error')]( - objError.msg - )); + o( this[ 'format_' + objError.etype ]( objError.msg )); // Output the stack (sometimes) if( objError.withStack ) { var stack = ex.stack || (ex.inner && ex.inner.stack); - stack && o( chalk.red( stack ) ); + stack && o( chalk.gray( stack ) ); } // Quit if necessary @@ -73,37 +76,51 @@ Error-handling routines for HackMyResume. } } + + // Handle raw exceptions else { o( ex ); var stackTrace = ex.stack || (ex.inner && ex.inner.stack); if( stackTrace && this.debug ) - o( ex.stack || ex.inner.stack ); - // if( this.debug ) - // o( ex.stack || ex.inner.stack ); + o( M2C(ex.stack || ex.inner.stack, 'gray') ); } }, - formatError: function( msg ) { + + + format_error: function( msg ) { msg = msg || ''; return chalk.red.bold( msg.toUpperCase().startsWith('ERROR:') ? msg : 'Error: ' + msg ); }, - formatWarning: function( brief, msg ) { + + + format_warning: function( brief, msg ) { return chalk.yellow(brief) + chalk.yellow(msg || ''); + }, + + + format_custom: function( msg ) { + return msg; } + + }; + function _defaultLog() { console.log.apply( console.log, arguments ); } + + function assembleError( ex ) { - var msg = '', withStack = false, isError = false, quit = false, warn = true; + var msg = '', withStack = false, quit = false, etype = 'warning'; if( this.debug ) withStack = true; switch( ex.fluenterror ) { @@ -151,23 +168,23 @@ Error-handling routines for HackMyResume. case HMSTATUS.pdfGeneration: msg = M2C( this.msgs.pdfGeneration.msg, 'bold' ); if( ex.inner ) msg += chalk.red('\n' + ex.inner); - withStack = true; quit = false; warn = false; + withStack = true; quit = false; etype = 'error'; break; case HMSTATUS.invalid: msg = M2C( this.msgs.invalid.msg, 'red' ); - warn = false; + etype = 'error'; break; case HMSTATUS.generateError: msg = (ex.inner && ex.inner.toString()) || ex; quit = false; - warn = false; + etype = 'error'; break; case HMSTATUS.fileSaveError: msg = printf( M2C( this.msgs.fileSaveError.msg ), (ex.inner || ex).toString() ); - warn = false; + etype = 'error'; quit = false; break; @@ -181,19 +198,20 @@ Error-handling routines for HackMyResume. case HMSTATUS.invalidHelperUse: msg = printf( M2C( this.msgs.invalidHelperUse.msg ), ex.helper ); quit = false; - warn = true; + etype = 'error'; break; case HMSTATUS.notOnPath: msg = printf( M2C(this.msgs.notOnPath.msg, 'bold'), ex.engine); quit = false; - warn = false; + etype = 'error'; break; case HMSTATUS.readError: - if( !ex.quiet ) console.error( printf( M2C(this.msgs.readError.msg, 'red'), ex.file ) ); + if( !ex.quiet ) + console.error(printf( M2C(this.msgs.readError.msg, 'red'), ex.file)); msg = ex.inner.toString(); - warn = false; + etype = 'error'; break; case HMSTATUS.mixedMerge: @@ -201,6 +219,17 @@ Error-handling routines for HackMyResume. quit = false; break; + case HMSTATUS.invokeTemplate: + msg = M2C( this.msgs.invokeTemplate.msg, 'red' ); + msg += M2C( '\n' + WRAP(ex.inner.toString(), { width: 60, indent: ' ' }), 'gray' ); + etype = 'custom'; + break; + + case HMSTATUS.compileTemplate: + //msg = printf( M2C( this.msgs.compileTemplate.msg ), ex.inner); + etype = 'error'; + break; + case HMSTATUS.parseError: if( SyntaxErrorEx.is( ex.inner )) { console.error( printf( M2C(this.msgs.readError.msg, 'red'), ex.file ) ); @@ -215,16 +244,16 @@ Error-handling routines for HackMyResume. else { msg = ex; } - warn = false; + etype = 'error'; break; } return { - warning: warn, // True if this is a warning, false if error msg: msg, // The error message to display withStack: withStack, // Whether to include the stack - quit: quit + quit: quit, + etype: etype }; } diff --git a/src/cli/msg.yml b/src/cli/msg.yml index f0b84ad..e55e808 100644 --- a/src/cli/msg.yml +++ b/src/cli/msg.yml @@ -86,3 +86,7 @@ errors: msg: An error occurred while writing %s to disk: %s. mixedMerge: msg: "**Warning:** merging mixed resume types. Errors may occur." + invokeTemplate: + msg: "An error occurred during template invocation." + compileTemplate: + msg: "An error occurred during template compilation." diff --git a/src/core/status-codes.js b/src/core/status-codes.js index 7e93d45..302d1d3 100644 --- a/src/core/status-codes.js +++ b/src/core/status-codes.js @@ -26,7 +26,9 @@ Status codes for HackMyResume. fileSaveError: 16, generateError: 17, invalidHelperUse: 18, - mixedMerge: 19 + mixedMerge: 19, + invokeTemplate: 20, + compileTemplate: 21 }; }()); diff --git a/src/renderers/handlebars-generator.js b/src/renderers/handlebars-generator.js index e7b0fa7..811954f 100644 --- a/src/renderers/handlebars-generator.js +++ b/src/renderers/handlebars-generator.js @@ -17,6 +17,7 @@ Definition of the HandlebarsGenerator class. , PATH = require('path') , parsePath = require('parse-filepath') , READFILES = require('recursive-readdir-sync') + , HMSTATUS = require('../core/status-codes') , SLASH = require('slash'); @@ -39,17 +40,27 @@ Definition of the HandlebarsGenerator class. ( format === 'html' || format === 'pdf' ) && (encData = json.markdownify()); ( format === 'doc' ) && (encData = json.xmlify()); - // Compile and run the Handlebars template. - var template = HANDLEBARS.compile(jst, { strict: false, assumeObjects: false }); - return template({ // TODO: Clean - r: encData, - RAW: json, - filt: opts.filters, - cssInfo: cssInfo, - format: format, - opts: opts, - headFragment: opts.headFragment || '' - }); + try { + // Compile and run the Handlebars template. + var template = HANDLEBARS.compile(jst, { strict: false, assumeObjects: false }); + return template({ // TODO: Clean + r: encData, + RAW: json, + filt: opts.filters, + cssInfo: cssInfo, + format: format, + opts: opts, + headFragment: opts.headFragment || '' + }); + + } + catch( ex ) { + throw { + fluenterror: template ? + HMSTATUS.invokeTemplate : HMSTATUS.compileTemplate, + inner: ex + }; + } } diff --git a/src/verbs/build.js b/src/verbs/build.js index f7749f5..dbbe1cb 100644 --- a/src/verbs/build.js +++ b/src/verbs/build.js @@ -160,11 +160,13 @@ Implementation of the 'build' verb for HackMyResume. } + function handleInternalError( ex ) { console.log(ex); } + /** Generate a single target resume such as "out/rez.html" or "out/rez.doc". TODO: Refactor. @@ -194,7 +196,6 @@ Implementation of the 'build' verb for HackMyResume. function(fmt) { return fmt.name === targInfo.fmt.outFormat; })[0]; MKDIRP.sync( PATH.dirname( f ) ); // Ensure dest folder exists; _opts.targets = finished; - _opts.errHandler = handleInternalError; ret = theFormat.gen.generate( _rezObj, f, _opts ); } //Otherwise this is an ad-hoc format (JSON, YML, or PNG) that every theme @@ -205,7 +206,6 @@ Implementation of the 'build' verb for HackMyResume. })[0]; var outFolder = PATH.dirname( f ); MKDIRP.sync( outFolder ); // Ensure dest folder exists; - _opts.errHandler = handleInternalError; ret = theFormat.gen.generate( _rezObj, f, _opts ); } }