diff --git a/dist/cli/error.js b/dist/cli/error.js index d8d1c28..5df9bda 100644 --- a/dist/cli/error.js +++ b/dist/cli/error.js @@ -266,6 +266,10 @@ Error-handling routines for HackMyResume. case HMSTATUS.themeHelperLoad: msg = printf(M2C(this.msgs.themeHelperLoad.msg), ex.glob); etype = 'error'; + break; + case HMSTATUS.invalidSchemaVersion: + msg = printf(M2C(this.msgs.invalidSchemaVersion.msg), ex.data); + etype = 'error'; } return { msg: msg, diff --git a/dist/cli/main.js b/dist/cli/main.js index e9ff5d2..ca0636d 100644 --- a/dist/cli/main.js +++ b/dist/cli/main.js @@ -74,7 +74,7 @@ Definition of the `main` function. program.command('validate')["arguments"]('').description('Validate a resume in FRESH or JSON RESUME format.').action(function(sources) { execute.call(this, sources, [], this.opts(), logMsg); }); - program.command('convert').description('Convert a resume to/from FRESH or JSON RESUME format.').action(function() { + program.command('convert').description('Convert a resume to/from FRESH or JSON RESUME format.').option('-f --format ', 'FRESH or JRS format and optional version', void 0).action(function() { var x; x = splitSrcDest.call(this); execute.call(this, x.src, x.dst, this.opts(), logMsg); diff --git a/dist/cli/msg.yml b/dist/cli/msg.yml index b7fe231..862dbba 100644 --- a/dist/cli/msg.yml +++ b/dist/cli/msg.yml @@ -137,3 +137,5 @@ errors: An error occurred while attempting to load the '%s' theme helper. Is the theme correctly installed? dummy: dontcare + invalidSchemaVersion: + msg: "'%s' is not recognized as a valid schema version." diff --git a/dist/core/fresh-resume.js b/dist/core/fresh-resume.js index 5546a41..a053163 100644 --- a/dist/core/fresh-resume.js +++ b/dist/core/fresh-resume.js @@ -109,14 +109,27 @@ Definition of the FRESHResume class. Save the sheet to disk in a specific format, either FRESH or JSON Resume. */ - FreshResume.prototype.saveAs = function(filename, format) { - var newRep; - if (format !== 'JRS') { + FreshResume.prototype.saveAs = function(filename, format, version) { + var freshVersionReg, newRep, parts, safeFormat, safeVersion; + safeFormat = (format || 'FRESH').trim(); + safeVersion = version || "0"; + freshVersionReg = require('../utils/fresh-version-regex'); + if (!freshVersionReg().test(safeFormat)) { + throw { + badVer: safeFormat + }; + } + parts = safeFormat.split('@'); + if (parts[0] === 'FRESH') { this.imp.file = filename || this.imp.file; FS.writeFileSync(this.imp.file, this.stringify(), 'utf8'); - } else { - newRep = CONVERTER.toJRS(this); + } else if (parts[0] === 'JRS') { + newRep = CONVERTER.toJRS(this, null, parts.length > 1 ? parts[1] : "1.0.0"); FS.writeFileSync(filename, JRSResume.stringify(newRep), 'utf8'); + } else { + throw { + badVer: safeFormat + }; } return this; }; diff --git a/dist/core/status-codes.js b/dist/core/status-codes.js index 4eedca5..77e8c36 100644 --- a/dist/core/status-codes.js +++ b/dist/core/status-codes.js @@ -37,7 +37,8 @@ Status codes for HackMyResume. invalidOptionsFile: 27, optionsFileNotFound: 28, unknownSchema: 29, - themeHelperLoad: 30 + themeHelperLoad: 30, + invalidSchemaVersion: 31 }; }).call(this); diff --git a/dist/verbs/convert.js b/dist/verbs/convert.js index f3e4806..9101672 100644 --- a/dist/verbs/convert.js +++ b/dist/verbs/convert.js @@ -39,7 +39,7 @@ Implementation of the 'convert' verb for HackMyResume. */ _convert = function(srcs, dst, opts) { - var results; + var fmtUp, freshVerRegex, matches, results, targetSchema, targetVer; if (!srcs || !srcs.length) { this.err(HMSTATUS.resumeNotFound, { quit: true @@ -65,13 +65,27 @@ Implementation of the 'convert' verb for HackMyResume. quit: true }); } + targetVer = null; + if (opts.format) { + fmtUp = opts.format.trim().toUpperCase(); + freshVerRegex = require('../utils/fresh-version-regex'); + matches = fmtUp.match(freshVerRegex()); + if (!matches) { + this.err(HMSTATUS.invalidSchemaVersion, { + data: opts.format.trim(), + quit: true + }); + } + targetSchema = matches[1]; + targetVer = matches[2] || '1'; + } if (this.hasError()) { this.reject(this.errorCode); return null; } results = _.map(srcs, function(src, idx) { var r; - r = _convertOne.call(this, src, dst, idx); + r = _convertOne.call(this, src, dst, idx, targetSchema, targetVer); if (r.fluenterror) { r.quit = opts.assert; this.err(r.fluenterror, r); @@ -89,8 +103,8 @@ Implementation of the 'convert' verb for HackMyResume. /** Private workhorse method. Convert a single resume. */ - _convertOne = function(src, dst, idx) { - var rez, rinfo, srcFmt, targetFormat; + _convertOne = function(src, dst, idx, targetSchema, targetVer) { + var err, rez, rinfo, srcFmt, targetFormat; rinfo = ResumeFactory.loadOne(src, { format: null, objectify: true, @@ -118,14 +132,25 @@ Implementation of the 'convert' verb for HackMyResume. rinfo.fluenterror = HMSTATUS.unknownSchema; return rinfo; } - targetFormat = srcFmt === 'JRS' ? 'FRESH' : 'JRS'; + targetFormat = targetSchema || (srcFmt === 'JRS' ? 'FRESH' : 'JRS'); this.stat(HMEVENT.beforeConvert, { srcFile: rinfo.file, srcFmt: srcFmt, dstFile: dst[idx], dstFmt: targetFormat }); - rez.saveAs(dst[idx], targetFormat); + try { + rez.saveAs(dst[idx], targetFormat, targetVer); + } catch (_error) { + err = _error; + if (err.badVer) { + return { + fluenterror: HMSTATUS.invalidSchemaVersion, + quit: true, + data: err.badVer + }; + } + } return rez; }; diff --git a/src/cli/error.coffee b/src/cli/error.coffee index 815902e..1112120 100644 --- a/src/cli/error.coffee +++ b/src/cli/error.coffee @@ -257,6 +257,9 @@ assembleError = ( ex ) -> msg = printf M2C( @msgs.themeHelperLoad.msg ), ex.glob etype = 'error' + when HMSTATUS.invalidSchemaVersion + msg = printf M2C( @msgs.invalidSchemaVersion.msg ), ex.data + etype = 'error' msg: msg # The error message to display withStack: withStack # Whether to include the stack diff --git a/src/cli/main.coffee b/src/cli/main.coffee index bbcb67d..79b6f86 100644 --- a/src/cli/main.coffee +++ b/src/cli/main.coffee @@ -84,6 +84,7 @@ main = module.exports = ( rawArgs, exitCallback ) -> program .command('convert') .description('Convert a resume to/from FRESH or JSON RESUME format.') + .option('-f --format ', 'FRESH or JRS format and optional version', undefined) .action(-> x = splitSrcDest.call( this ); execute.call( this, x.src, x.dst, this.opts(), logMsg) diff --git a/src/cli/msg.yml b/src/cli/msg.yml index b7fe231..862dbba 100644 --- a/src/cli/msg.yml +++ b/src/cli/msg.yml @@ -137,3 +137,5 @@ errors: An error occurred while attempting to load the '%s' theme helper. Is the theme correctly installed? dummy: dontcare + invalidSchemaVersion: + msg: "'%s' is not recognized as a valid schema version." diff --git a/src/core/fresh-resume.coffee b/src/core/fresh-resume.coffee index a17d9fd..d6b6bea 100644 --- a/src/core/fresh-resume.coffee +++ b/src/core/fresh-resume.coffee @@ -94,13 +94,26 @@ class FreshResume# extends AbstractResume ###* Save the sheet to disk in a specific format, either FRESH or JSON Resume. ### - saveAs: ( filename, format ) -> - if format != 'JRS' + saveAs: ( filename, format, version ) -> + + # If format isn't specified, default to FRESH + safeFormat = (format || 'FRESH').trim() + safeVersion = version || "0" + + # Validate against the FRESH version regex + # freshVersionReg = require '../utils/fresh-version-regex' + # if (not freshVersionReg().test( safeFormat )) + # throw badVer: safeFormat + + parts = safeFormat.split '@' + if parts[0] == 'FRESH' @imp.file = filename || @imp.file FS.writeFileSync @imp.file, @stringify(), 'utf8' - else - newRep = CONVERTER.toJRS this + else if parts[0] == 'JRS' + newRep = CONVERTER.toJRS @, null, if parts.length > 1 then parts[1] else "1" FS.writeFileSync filename, JRSResume.stringify( newRep ), 'utf8' + else + throw badVer: safeFormat @ diff --git a/src/core/status-codes.coffee b/src/core/status-codes.coffee index 8252796..4a34cc9 100644 --- a/src/core/status-codes.coffee +++ b/src/core/status-codes.coffee @@ -37,3 +37,4 @@ module.exports = optionsFileNotFound: 28 unknownSchema: 29 themeHelperLoad: 30 + invalidSchemaVersion: 31 diff --git a/src/verbs/convert.coffee b/src/verbs/convert.coffee index 00272bf..7604034 100644 --- a/src/verbs/convert.coffee +++ b/src/verbs/convert.coffee @@ -46,6 +46,20 @@ _convert = ( srcs, dst, opts ) -> if srcs && dst && srcs.length && dst.length && srcs.length != dst.length @err HMSTATUS.inputOutputParity, { quit: true } + # Validate the destination format (if specified) + targetVer = null + if opts.format + fmtUp = opts.format.trim().toUpperCase() + freshVerRegex = require '../utils/fresh-version-regex' + matches = fmtUp.match freshVerRegex() + # null + # [ 'JRS@1.0', 'JRS', '1.0', index: 0, input: 'FRESH' ] + # [ 'FRESH', 'FRESH', undefined, index: 0, input: 'FRESH' ] + if not matches + @err HMSTATUS.invalidSchemaVersion, data: opts.format.trim(), quit: true + targetSchema = matches[1] + targetVer = matches[2] || '1' + # If any errors have occurred this early, we're done. if @hasError() @reject @errorCode @@ -55,7 +69,7 @@ _convert = ( srcs, dst, opts ) -> results = _.map srcs, ( src, idx ) -> # Convert each resume in turn - r = _convertOne.call @, src, dst, idx + r = _convertOne.call @, src, dst, idx, targetSchema, targetVer # Handle conversion errors if r.fluenterror @@ -74,12 +88,12 @@ _convert = ( srcs, dst, opts ) -> ###* Private workhorse method. Convert a single resume. ### -_convertOne = (src, dst, idx) -> +_convertOne = (src, dst, idx, targetSchema, targetVer) -> # Load the resume rinfo = ResumeFactory.loadOne src, format: null - objectify: true, + objectify: true inner: privatize: false @@ -94,6 +108,8 @@ _convertOne = (src, dst, idx) -> #@err rinfo.fluenterror, rinfo return rinfo + # Determine the resume's SOURCE format + # TODO: replace with detector component rez = rinfo.rez srcFmt = '' if rez.meta && rez.meta.format #&& rez.meta.format.substr(0, 5).toUpperCase() == 'FRESH' @@ -104,8 +120,10 @@ _convertOne = (src, dst, idx) -> rinfo.fluenterror = HMSTATUS.unknownSchema return rinfo - targetFormat = if srcFmt == 'JRS' then 'FRESH' else 'JRS' + # Determine the TARGET format for the conversion + targetFormat = targetSchema or (if srcFmt == 'JRS' then 'FRESH' else 'JRS') + # Fire the beforeConvert event this.stat HMEVENT.beforeConvert, srcFile: rinfo.file srcFmt: srcFmt @@ -113,5 +131,9 @@ _convertOne = (src, dst, idx) -> dstFmt: targetFormat # Save it to the destination format - rez.saveAs dst[idx], targetFormat + try + rez.saveAs dst[idx], targetFormat, targetVer + catch err + if err.badVer + return fluenterror: HMSTATUS.invalidSchemaVersion, quit: true, data: err.badVer rez