CONVERT: Improve command consistency.

This commit is contained in:
hacksalot 2018-01-30 02:34:58 -05:00
parent 6b125ed907
commit c913de4bf7
No known key found for this signature in database
GPG Key ID: 2F343EC247CA4B06
19 changed files with 208 additions and 50 deletions

4
dist/cli/error.js vendored
View File

@ -258,6 +258,10 @@ Error-handling routines for HackMyResume.
case HMSTATUS.optionsFileNotFound:
msg = M2C(this.msgs.optionsFileNotFound.msg);
etype = 'error';
break;
case HMSTATUS.unknownSchema:
msg = M2C(this.msgs.unknownSchema.msg[0]);
etype = 'error';
}
return {
msg: msg,

9
dist/cli/main.js vendored
View File

@ -257,9 +257,16 @@ Definition of the `main` function.
executeFail = function(err) {
var finalErrorCode, msgs;
console.dir(err);
finalErrorCode = -1;
if (err) {
finalErrorCode = err.fluenterror ? err.fluenterror : err;
if (err.fluenterror) {
finalErrorCode = err.fluenterror;
} else if (err.length) {
finalErrorCode = err[0].fluenterror;
} else {
finalErrorCode = err;
}
}
if (_opts.debug) {
msgs = require('./msg').errors;

17
dist/cli/msg.yml vendored
View File

@ -115,3 +115,20 @@ errors:
- "\nMake sure the options file contains valid JSON."
optionsFileNotFound:
msg: "The specified options file is missing or inaccessible."
unknownSchema:
msg:
- "Unknown resume schema. Did you specify a valid FRESH or JRS resume?"
- |
At a minimum, a FRESH resume must include a "name" field and a "meta"
property.
"name": "John Doe",
"meta": {
"format": "FRESH@0.1.0"
}
JRS-format resumes must include a "basics" section with a "name":
"basics": {
"name": "John Doe"
}

2
dist/cli/out.js vendored
View File

@ -128,7 +128,7 @@ Output routines for HackMyResume.
output = template(info);
return this.log(chalk.cyan(output));
case HME.beforeConvert:
return L(M2C(this.msgs.beforeConvert.msg, 'green'), evt.srcFile, evt.srcFmt, evt.dstFile, evt.dstFmt);
return L(M2C(this.msgs.beforeConvert.msg, evt.error ? 'red' : 'green'), evt.srcFile, evt.srcFmt, evt.dstFile, evt.dstFmt);
case HME.afterInlineConvert:
return L(M2C(this.msgs.afterInlineConvert.msg, 'gray', 'white.dim'), evt.file, evt.fmt);
case HME.afterValidate:

View File

@ -6,11 +6,11 @@ Definition of the ResumeFactory class.
*/
(function() {
var FS, HACKMYSTATUS, HME, ResumeConverter, ResumeFactory, SyntaxErrorEx, _, _parse, chalk;
var FS, HME, HMS, ResumeConverter, ResumeFactory, SyntaxErrorEx, _, _parse, chalk, resumeDetect;
FS = require('fs');
HACKMYSTATUS = require('./status-codes');
HMS = require('./status-codes');
HME = require('./event-codes');
@ -22,6 +22,8 @@ Definition of the ResumeFactory class.
_ = require('underscore');
resumeDetect = require('../utils/resume-detector');
require('string.prototype.startswith');
@ -54,7 +56,7 @@ Definition of the ResumeFactory class.
/** Load a single resume from disk. */
loadOne: function(src, opts, emitter) {
var ResumeClass, info, isFRESH, json, objectify, orgFormat, rez, toFormat;
var ResumeClass, info, json, objectify, orgFormat, reqLib, rez, toFormat;
toFormat = opts.format;
objectify = opts.objectify;
toFormat && (toFormat = toFormat.toLowerCase().trim());
@ -63,14 +65,18 @@ Definition of the ResumeFactory class.
return info;
}
json = info.json;
isFRESH = json.meta && json.meta.format && json.meta.format.startsWith('FRESH@');
orgFormat = isFRESH ? 'fresh' : 'jrs';
orgFormat = resumeDetect(json);
if (orgFormat === 'unk') {
info.fluenterror = HMS.unknownSchema;
return info;
}
if (toFormat && (orgFormat !== toFormat)) {
json = ResumeConverter['to' + toFormat.toUpperCase()](json);
}
rez = null;
if (objectify) {
ResumeClass = require('../core/' + (toFormat || orgFormat) + '-resume');
reqLib = '../core/' + (toFormat || orgFormat) + '-resume';
ResumeClass = require(reqLib);
rez = new ResumeClass().parseJSON(json, opts.inner);
rez.i().file = src;
}
@ -109,7 +115,7 @@ Definition of the ResumeFactory class.
return ret;
} catch (_error) {
return {
fluenterror: rawData ? HACKMYSTATUS.parseError : HACKMYSTATUS.readError,
fluenterror: rawData ? HMS.parseError : HMS.readError,
inner: _error,
raw: rawData,
file: fileName

View File

@ -35,7 +35,8 @@ Status codes for HackMyResume.
createError: 25,
validateError: 26,
invalidOptionsFile: 27,
optionsFileNotFound: 28
optionsFileNotFound: 28,
unknownSchema: 29
};
}).call(this);

View File

@ -34,13 +34,12 @@ Definition of the HandlebarsGenerator class.
HandlebarsGenerator = module.exports = {
generateSimple: function(data, tpl) {
var noesc, template;
var template;
try {
noesc = data.opts.noescape || false;
template = HANDLEBARS.compile(tpl, {
strict: false,
assumeObjects: false,
noEscape: noesc
noEscape: data.opts.noescape || false
});
return template(data);
} catch (_error) {

21
dist/utils/resume-detector.js vendored Normal file
View File

@ -0,0 +1,21 @@
/**
Definition of the ResumeDetector class.
@module utils/resume-detector
@license MIT. See LICENSE.md for details.
*/
(function() {
module.exports = function(rez) {
if (rez.meta && rez.meta.format) {
return 'fresh';
} else if (rez.basics) {
return 'jrs';
} else {
return 'unk';
}
};
}).call(this);
//# sourceMappingURL=resume-detector.js.map

32
dist/verbs/convert.js vendored
View File

@ -65,11 +65,12 @@ Implementation of the 'convert' verb for HackMyResume.
quit: true
});
}
if (this.hasError()) {
this.reject(this.errorCode);
return null;
}
results = _.map(srcs, function(src, idx) {
var r;
if (opts.assert && this.hasError()) {
return {};
}
r = _convertOne.call(this, src, dst, idx);
if (r.fluenterror) {
r.quit = opts.assert;
@ -89,16 +90,31 @@ Implementation of the 'convert' verb for HackMyResume.
/** Private workhorse method. Convert a single resume. */
_convertOne = function(src, dst, idx) {
var rinfo, s, srcFmt, targetFormat;
var rez, rinfo, srcFmt, targetFormat;
rinfo = ResumeFactory.loadOne(src, {
format: null,
objectify: true
});
if (rinfo.fluenterror) {
this.stat(HMEVENT.beforeConvert, {
srcFile: src,
srcFmt: '???',
dstFile: dst[idx],
dstFmt: '???',
error: true
});
return rinfo;
}
rez = rinfo.rez;
srcFmt = '';
if (rez.meta && rez.meta.format) {
srcFmt = 'FRESH';
} else if (rez.basics) {
srcFmt = 'JRS';
} else {
rinfo.fluenterror = HMSTATUS.unknownSchema;
return rinfo;
}
s = rinfo.rez;
srcFmt = ((s.basics && s.basics.imp) || s.imp).orgFormat === 'JRS' ? 'JRS' : 'FRESH';
targetFormat = srcFmt === 'JRS' ? 'FRESH' : 'JRS';
this.stat(HMEVENT.beforeConvert, {
srcFile: rinfo.file,
@ -106,8 +122,8 @@ Implementation of the 'convert' verb for HackMyResume.
dstFile: dst[idx],
dstFmt: targetFormat
});
s.saveAs(dst[idx], targetFormat);
return s;
rez.saveAs(dst[idx], targetFormat);
return rez;
};
}).call(this);

View File

@ -248,6 +248,11 @@ assembleError = ( ex ) ->
msg = M2C( @msgs.optionsFileNotFound.msg )
etype = 'error'
when HMSTATUS.unknownSchema
msg = M2C( @msgs.unknownSchema.msg[0] )
#msg += "\n" + M2C( @msgs.unknownSchema.msg[1], 'yellow' )
etype = 'error'
msg: msg # The error message to display
withStack: withStack # Whether to include the stack
quit: quit

View File

@ -262,7 +262,7 @@ execute = ( src, dst, opts, log ) ->
v = new HMR.verbs[ @name() ]()
# Initialize command-specific options
loadOptions.call( this, opts, this.parent.jsonArgs )
loadOptions.call this, opts, this.parent.jsonArgs
# Set up error/output handling
_opts.errHandler = v
@ -288,9 +288,15 @@ executeSuccess = (obj) ->
### Failure handler for verb invocations. Calls process.exit by default ###
executeFail = (err) ->
console.dir err
finalErrorCode = -1
if err
finalErrorCode = if err.fluenterror then err.fluenterror else err
if err.fluenterror
finalErrorCode = err.fluenterror
else if err.length
finalErrorCode = err[0].fluenterror
else
finalErrorCode = err
if _opts.debug
msgs = require('./msg').errors;
logMsg printf M2C( msgs.exiting.msg, 'cyan' ), finalErrorCode

View File

@ -115,3 +115,20 @@ errors:
- "\nMake sure the options file contains valid JSON."
optionsFileNotFound:
msg: "The specified options file is missing or inaccessible."
unknownSchema:
msg:
- "Unknown resume schema. Did you specify a valid FRESH or JRS resume?"
- |
At a minimum, a FRESH resume must include a "name" field and a "meta"
property.
"name": "John Doe",
"meta": {
"format": "FRESH@0.1.0"
}
JRS-format resumes must include a "basics" section with a "name":
"basics": {
"name": "John Doe"
}

View File

@ -131,7 +131,7 @@ module.exports = class OutputHandler
@log( chalk.cyan(output) )
when HME.beforeConvert
L( M2C( this.msgs.beforeConvert.msg, 'green' ),
L( M2C( this.msgs.beforeConvert.msg, if evt.error then 'red' else 'green' ),
evt.srcFile, evt.srcFmt, evt.dstFile, evt.dstFmt
);

View File

@ -6,14 +6,15 @@ Definition of the ResumeFactory class.
FS = require('fs')
HACKMYSTATUS = require('./status-codes')
HME = require('./event-codes')
ResumeConverter = require('fresh-jrs-converter')
chalk = require('chalk')
SyntaxErrorEx = require('../utils/syntax-error-ex')
_ = require('underscore')
require('string.prototype.startswith')
FS = require 'fs'
HMS = require './status-codes'
HME = require './event-codes'
ResumeConverter = require 'fresh-jrs-converter'
chalk = require 'chalk'
SyntaxErrorEx = require '../utils/syntax-error-ex'
_ = require 'underscore'
resumeDetect = require '../utils/resume-detector'
require 'string.prototype.startswith'
@ -62,20 +63,23 @@ ResumeFactory = module.exports =
# Determine the resume format: FRESH or JRS
json = info.json
isFRESH = json.meta && json.meta.format && json.meta.format.startsWith('FRESH@');
orgFormat = if isFRESH then 'fresh' else 'jrs'
orgFormat = resumeDetect json
if orgFormat == 'unk'
info.fluenterror = HMS.unknownSchema
return info
# Convert between formats if necessary
if toFormat and ( orgFormat != toFormat )
json = ResumeConverter[ 'to' + toFormat.toUpperCase() ]( json )
json = ResumeConverter[ 'to' + toFormat.toUpperCase() ] json
# Objectify the resume, that is, convert it from JSON to a FRESHResume
# or JRSResume object.
rez = null
if objectify
ResumeClass = require('../core/' + (toFormat || orgFormat) + '-resume');
rez = new ResumeClass().parseJSON( json, opts.inner );
rez.i().file = src;
reqLib = '../core/' + (toFormat || orgFormat) + '-resume'
ResumeClass = require reqLib
rez = new ResumeClass().parseJSON( json, opts.inner )
rez.i().file = src
file: src
json: info.json
@ -103,7 +107,7 @@ _parse = ( fileName, opts, eve ) ->
return ret
catch
# Can be ENOENT, EACCES, SyntaxError, etc.
fluenterror: if rawData then HACKMYSTATUS.parseError else HACKMYSTATUS.readError
fluenterror: if rawData then HMS.parseError else HMS.readError
inner: _error
raw: rawData
file: fileName

View File

@ -35,3 +35,4 @@ module.exports =
validateError: 26
invalidOptionsFile: 27
optionsFileNotFound: 28
unknownSchema: 29

View File

@ -0,0 +1,13 @@
###*
Definition of the ResumeDetector class.
@module utils/resume-detector
@license MIT. See LICENSE.md for details.
###
module.exports = ( rez ) ->
if rez.meta && rez.meta.format #&& rez.meta.format.substr(0, 5).toUpperCase() == 'FRESH'
'fresh'
else if rez.basics
'jrs'
else
'unk'

View File

@ -26,10 +26,14 @@ formats. ###
_convert = ( srcs, dst, opts ) ->
# Housekeeping...
# If no source resumes are specified, error out
if !srcs || !srcs.length
@err HMSTATUS.resumeNotFound, { quit: true }
return null
# If no destination resumes are specified, error out except for the special
# case of two resumes:
# hackmyresume CONVERT r1.json r2.json
if !dst || !dst.length
if srcs.length == 1
@err HMSTATUS.inputOutputParity, { quit: true }
@ -37,19 +41,30 @@ _convert = ( srcs, dst, opts ) ->
dst = dst || []; dst.push( srcs.pop() )
else
@err HMSTATUS.inputOutputParity, { quit: true }
# Different number of source and dest resumes? Error out.
if srcs && dst && srcs.length && dst.length && srcs.length != dst.length
@err HMSTATUS.inputOutputParity, { quit: true }
# Load source resumes
# If any errors have occurred this early, we're done.
if @hasError()
@reject @errorCode
return null
# Map each source resume to the converted destination resume
results = _.map srcs, ( src, idx ) ->
return { } if opts.assert and @hasError()
# Convert each resume in turn
r = _convertOne.call @, src, dst, idx
# Handle conversion errors
if r.fluenterror
r.quit = opts.assert
@err r.fluenterror, r
r
, @
if @hasError() and !opts.assert
@reject results
else if !@hasError()
@ -60,17 +75,31 @@ _convert = ( srcs, dst, opts ) ->
###* Private workhorse method. Convert a single resume. ###
_convertOne = (src, dst, idx) ->
# Load the resume
rinfo = ResumeFactory.loadOne src, format: null, objectify: true
# If a load error occurs, report it and move on to the next file (if any)
if rinfo.fluenterror
@stat HMEVENT.beforeConvert,
srcFile: src #rinfo.file
srcFmt: '???'
dstFile: dst[idx]
dstFmt: '???'
error: true
#@err rinfo.fluenterror, rinfo
return rinfo
rez = rinfo.rez
srcFmt = ''
if rez.meta && rez.meta.format #&& rez.meta.format.substr(0, 5).toUpperCase() == 'FRESH'
srcFmt = 'FRESH'
else if rez.basics
srcFmt = 'JRS'
else
rinfo.fluenterror = HMSTATUS.unknownSchema
return rinfo
s = rinfo.rez
srcFmt =
if ((s.basics && s.basics.imp) || s.imp).orgFormat == 'JRS'
then 'JRS' else 'FRESH'
targetFormat = if srcFmt == 'JRS' then 'FRESH' else 'JRS'
this.stat HMEVENT.beforeConvert,
@ -80,5 +109,5 @@ _convertOne = (src, dst, idx) ->
dstFmt: targetFormat
# Save it to the destination format
s.saveAs dst[idx], targetFormat
s
rez.saveAs dst[idx], targetFormat
rez

View File

@ -32,12 +32,20 @@ module.exports = class Verb
###* Invoke the command. ###
invoke: ->
# Sent the 'begin' notification for this verb
@stat HMEVENT.begin, cmd: @moniker
# Prepare command arguments
argsArray = Array::slice.call arguments
# Create a promise for this verb instance
that = @
@promise = new Promise (res, rej) ->
that.resolve = res; that.reject = rej
that.workhorse.apply that, argsArray; return
that.resolve = res
that.reject = rej
that.workhorse.apply that, argsArray
return

View File

@ -13,6 +13,10 @@
0|analyze node_modules/fresh-test-resumes/src/fresh/johnny-trouble.json
3|convert
7|convert doesnt-exist.json
14|convert from.json to.json
7|convert z1.json z2.json z3.json
7|convert z1.json z2.json z3.json z4.json
14|convert z1.json z2.json to z3.json z4.json
3|validate
14|validate doesnt-exist.json
0|validate node_modules/fresh-test-resumes/src/fresh/jane-fullstacker.json