mirror of
				https://github.com/JuanCanham/HackMyResume.git
				synced 2025-10-31 13:17:26 +00:00 
			
		
		
		
	| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "hackmyresume", | ||||
|   "version": "1.3.0-beta", | ||||
|   "version": "1.3.0", | ||||
|   "description": "Generate polished résumés and CVs in HTML, Markdown, LaTeX, MS Word, PDF, plain text, JSON, XML, YAML, smoke signal, and carrier pigeon.", | ||||
|   "repository": { | ||||
|     "type": "git", | ||||
| @@ -47,12 +47,13 @@ | ||||
|   "dependencies": { | ||||
|     "colors": "^1.1.2", | ||||
|     "copy": "^0.1.3", | ||||
|     "fresh-themes": "~0.9.3-beta", | ||||
|     "fresca": "~0.2.2", | ||||
|     "fresh-themes": "~0.9.3-beta", | ||||
|     "fs-extra": "^0.24.0", | ||||
|     "handlebars": "^4.0.5", | ||||
|     "html": "0.0.10", | ||||
|     "is-my-json-valid": "^2.12.2", | ||||
|     "json-lint": "^0.1.0", | ||||
|     "jst": "0.0.13", | ||||
|     "lodash": "^3.10.1", | ||||
|     "marked": "^0.3.5", | ||||
|   | ||||
| @@ -1,11 +1,13 @@ | ||||
| /** | ||||
| FRESH to JSON Resume conversion routiens. | ||||
| @license MIT. Copyright (c) 2015 James Devlin / FluentDesk. | ||||
| @license MIT. See LICENSE.md for details. | ||||
| @module convert.js | ||||
| */ | ||||
|  | ||||
| (function(){ | ||||
|  | ||||
|   var _ = require('underscore'); | ||||
|  | ||||
|   /** | ||||
|   Convert between FRESH and JRS resume/CV formats. | ||||
|   @class FRESHConverter | ||||
| @@ -26,6 +28,8 @@ FRESH to JSON Resume conversion routiens. | ||||
|  | ||||
|         name: src.basics.name, | ||||
|  | ||||
|         imp: src.basics.imp, | ||||
|  | ||||
|         info: { | ||||
|           label: src.basics.label, | ||||
|           class: src.basics.class, // <--> round-trip | ||||
| @@ -92,7 +96,8 @@ FRESH to JSON Resume conversion routiens. | ||||
|             countryCode: src.location.country, | ||||
|             region: src.location.region | ||||
|           }, | ||||
|           profiles: social( src.social, false ) | ||||
|           profiles: social( src.social, false ), | ||||
|           imp: src.imp | ||||
|         }, | ||||
|  | ||||
|         work: employment( src.employment, false ), | ||||
| @@ -109,12 +114,30 @@ FRESH to JSON Resume conversion routiens. | ||||
|  | ||||
|       }; | ||||
|  | ||||
|     }, | ||||
|  | ||||
|     toSTRING: function( src ) { | ||||
|       function replacerJRS( key,value ) { // Exclude these keys from stringification | ||||
|         return _.some(['imp', 'warnings', 'computed', 'filt', 'ctrl', 'index', | ||||
|           'safeStartDate', 'safeEndDate', 'safeDate', 'safeReleaseDate', 'result', | ||||
|         'isModified', 'htmlPreview', 'display_progress_bar'], | ||||
|           function( val ) { return key.trim() === val; } | ||||
|         ) ? undefined : value; | ||||
|       } | ||||
|       function replacerFRESH( key,value ) { // Exclude these keys from stringification | ||||
|         return _.some(['imp', 'warnings', 'computed', 'filt', 'ctrl', 'index', | ||||
|           'safe', 'result', 'isModified', 'htmlPreview', 'display_progress_bar'], | ||||
|           function( val ) { return key.trim() === val; } | ||||
|         ) ? undefined : value; | ||||
|       } | ||||
|  | ||||
|       return JSON.stringify( src, src.basics ? replacerJRS : replacerFRESH, 2 ); | ||||
|     } | ||||
|  | ||||
|   }; | ||||
|  | ||||
|   function meta( direction, obj ) { | ||||
|     if( !obj ) return obj; // preserve null and undefined | ||||
|     //if( !obj ) return obj; // preserve null and undefined | ||||
|     if( direction ) { | ||||
|       obj = obj || { }; | ||||
|       obj.format = obj.format || "FRESH@0.1.0"; | ||||
| @@ -151,7 +174,7 @@ FRESH to JSON Resume conversion routiens. | ||||
|               start: job.startDate, | ||||
|               end: job.endDate, | ||||
|               url: job.website, | ||||
|               keywords: "", | ||||
|               keywords: [], | ||||
|               highlights: job.highlights | ||||
|             }; | ||||
|           }) : undefined | ||||
| @@ -164,6 +187,7 @@ FRESH to JSON Resume conversion routiens. | ||||
|     if( !obj ) return obj; | ||||
|     if( direction ) { | ||||
|       return obj && obj.length ? { | ||||
|         level: "", | ||||
|         history: obj.map(function(edu){ | ||||
|           return { | ||||
|             institution: edu.institution, | ||||
| @@ -171,8 +195,8 @@ FRESH to JSON Resume conversion routiens. | ||||
|             end: edu.endDate, | ||||
|             grade: edu.gpa, | ||||
|             curriculum: edu.courses, | ||||
|             url: edu.website || edu.url || null, | ||||
|             summary: null, | ||||
|             url: edu.website || edu.url || undefined, | ||||
|             summary: edu.summary || "", | ||||
|             area: edu.area, | ||||
|             studyType: edu.studyType | ||||
|           }; | ||||
|   | ||||
| @@ -13,6 +13,7 @@ Definition of the FRESHResume class. | ||||
|     , __ = require('lodash') | ||||
|     , PATH = require('path') | ||||
|     , moment = require('moment') | ||||
|     , XML = require('xml-escape') | ||||
|     , MD = require('marked') | ||||
|     , CONVERTER = require('./convert') | ||||
|     , JRSResume = require('./jrs-resume'); | ||||
| @@ -81,12 +82,90 @@ Definition of the FRESHResume class. | ||||
|     return JSON.stringify( obj, replacer, 2 ); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|   Create a copy of this resume in which all string fields have been run through | ||||
|   a transformation function (such as a Markdown filter or XML encoder). | ||||
|   */ | ||||
|   FreshResume.prototype.transformStrings = function( filters, transformer ) { | ||||
|  | ||||
|     var that = this; | ||||
|     var ret = this.dupe(); | ||||
|  | ||||
|     // TODO: refactor recursion | ||||
|     function transformStringsInObject( obj ) { | ||||
|  | ||||
|       if( !obj ) return; | ||||
|       if( moment.isMoment( obj ) ) return; | ||||
|  | ||||
|       if( _.isArray( obj ) ) { | ||||
|         obj.forEach( function(elem, idx, ar) { | ||||
|           if( typeof elem === 'string' || elem instanceof String ) | ||||
|             ar[idx] = transformer( null, elem ); | ||||
|           else if (_.isObject(elem)) | ||||
|             transformStringsInObject( elem ); | ||||
|         }); | ||||
|       } | ||||
|       else if (_.isObject( obj )) { | ||||
|         Object.keys( obj ).forEach(function(k) { | ||||
|           var sub = obj[k]; | ||||
|           if( typeof sub === 'string' || sub instanceof String ) { | ||||
|             if( filters.length && _.contains(filters, k) ) | ||||
|               return; | ||||
|             obj[k] = transformer( k, sub ); | ||||
|           } | ||||
|           else if (_.isObject( sub )) | ||||
|             transformStringsInObject( sub ); | ||||
|         }); | ||||
|       } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     Object.keys( ret ).forEach(function(member){ | ||||
|       transformStringsInObject( ret[ member ] ); | ||||
|     }); | ||||
|  | ||||
|     return ret; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|   Create a copy of this resume in which all fields have been interpreted as | ||||
|   Markdown. | ||||
|   */ | ||||
|   FreshResume.prototype.markdownify = function() { | ||||
|  | ||||
|     function MDIN( txt ){ | ||||
|       return MD(txt || '' ).replace(/^\s*<p>|<\/p>\s*$/gi, ''); | ||||
|     } | ||||
|  | ||||
|     function trx(key, val) { | ||||
|       if( key === 'summary' ) { | ||||
|         return MD(val); | ||||
|       } | ||||
|       return MDIN(val); | ||||
|     } | ||||
|  | ||||
|     return this.transformStrings( ['skills','url','start','end','date'], trx ); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|   Create a copy of this resume in which all fields have been interpreted as | ||||
|   Markdown. | ||||
|   */ | ||||
|   FreshResume.prototype.xmlify = function() { | ||||
|  | ||||
|     function trx(key, val) { | ||||
|       return XML(val); | ||||
|     } | ||||
|  | ||||
|     return this.transformStrings( [], trx ); | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|   Create a copy of this resume in which all fields have been interpreted as | ||||
|   Markdown. | ||||
|   */ | ||||
|   FreshResume.prototype.markdownify2 = function() { | ||||
|  | ||||
|     var that = this; | ||||
|     var ret = this.dupe(); | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| /** | ||||
| Definition of the JRSResume class. | ||||
| @license MIT. Copyright (c) 2015 James Devlin / FluentDesk. | ||||
| @license MIT. See LICENSE.md for details. | ||||
| @module jrs-resume.js | ||||
| */ | ||||
|  | ||||
| @@ -12,6 +12,7 @@ Definition of the JRSResume class. | ||||
|     , _ = require('underscore') | ||||
|     , PATH = require('path') | ||||
|     , MD = require('marked') | ||||
|     , CONVERTER = require('./convert') | ||||
|     , moment = require('moment'); | ||||
|  | ||||
|   /** | ||||
| @@ -51,6 +52,24 @@ Definition of the JRSResume class. | ||||
|     return this; | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|   Save the sheet to disk in a specific format, either FRESH or JRS. | ||||
|   */ | ||||
|   JRSResume.prototype.saveAs = function( filename, format ) { | ||||
|  | ||||
|     if( format === 'JRS' ) { | ||||
|       this.basics.imp.fileName = filename || this.imp.fileName; | ||||
|       FS.writeFileSync( this.basics.imp.fileName, this.stringify(), 'utf8' ); | ||||
|     } | ||||
|     else { | ||||
|       var newRep = CONVERTER.toFRESH( this ); | ||||
|       var stringRep = CONVERTER.toSTRING( newRep ); | ||||
|       FS.writeFileSync( filename, stringRep, 'utf8' ); | ||||
|     } | ||||
|     return this; | ||||
|  | ||||
|   }; | ||||
|  | ||||
|   /** | ||||
|   Convert this object to a JSON string, sanitizing meta-properties along the | ||||
|   way. Don't override .toString(). | ||||
| @@ -92,6 +111,7 @@ Definition of the JRSResume class. | ||||
|     if( opts.imp === undefined || opts.imp ) { | ||||
|       this.basics.imp = this.basics.imp || { }; | ||||
|       this.basics.imp.title = (opts.title || this.basics.imp.title) || this.basics.name; | ||||
|       this.basics.imp.orgFormat = 'JRS'; | ||||
|     } | ||||
|     // Parse dates, sort dates, and calculate computed values | ||||
|     (opts.date === undefined || opts.date) && _parseDates.call( this ); | ||||
|   | ||||
| @@ -1,43 +1,107 @@ | ||||
| /** | ||||
| Core resume-loading logic for HackMyResume. | ||||
| Definition of the ResumeFactory class. | ||||
| @license MIT. See LICENSE.md for details. | ||||
| @module resume-factory.js | ||||
| */ | ||||
|  | ||||
|  | ||||
|  | ||||
| (function(){ | ||||
|  | ||||
|  | ||||
|  | ||||
|   require('string.prototype.startswith'); | ||||
|   var FS = require('fs'); | ||||
|   var ResumeConverter = require('./convert'); | ||||
|  | ||||
|  | ||||
|  | ||||
|   /** | ||||
|   A simple factory class for FRESH and JSON Resumes. | ||||
|   @class ResumeFactory | ||||
|   */ | ||||
|   module.exports = { | ||||
|   var ResumeFactory = module.exports = { | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|     Load one or more resumes in a specific source format. | ||||
|     Load one or more resumes from disk. | ||||
|     */ | ||||
|     load: function ( src, log, fn, toFormat ) { | ||||
|  | ||||
|       toFormat = toFormat && (toFormat.toLowerCase().trim()) || 'fresh'; | ||||
|       var ResumeClass = require('../core/' + toFormat + '-resume'); | ||||
|  | ||||
|       return src.map( function( res ) { | ||||
|         var rezJson = JSON.parse( FS.readFileSync( res ) ); | ||||
|         var orgFormat = ( rezJson.meta && rezJson.meta.format && | ||||
|                           rezJson.meta.format.startsWith('FRESH@') ) ? | ||||
|                           'fresh' : 'jrs'; | ||||
|         if(orgFormat !== toFormat) { | ||||
|           rezJson = ResumeConverter[ 'to' + toFormat.toUpperCase() ]( rezJson ); | ||||
|         } | ||||
|         // TODO: Core should not log | ||||
|         log( 'Reading '.info + orgFormat.toUpperCase().infoBold + ' resume: '.info + res.cyan.bold ); | ||||
|         return (fn && fn(res)) || (new ResumeClass()).parseJSON( rezJson ); | ||||
|     load: function ( sources, log, toFormat, objectify ) { | ||||
|       // Loop over all inputs, parsing each to JSON and then to a FRESHResume | ||||
|       // or JRSResume object. | ||||
|       var that = this; | ||||
|       return sources.map( function( src ) { | ||||
|         return that.loadOne( src, log, toFormat, objectify ); | ||||
|       }); | ||||
|  | ||||
|     }, | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|     Load a single resume from disk. | ||||
|     */ | ||||
|     loadOne: function( src, log, toFormat, objectify ) { | ||||
|  | ||||
|       // Get the destination format. Can be 'fresh', 'jrs', or null/undefined. | ||||
|       toFormat && (toFormat = toFormat.toLowerCase().trim()); | ||||
|  | ||||
|       // Load and parse the resume JSON | ||||
|       var info = _parse( src, log, toFormat ); | ||||
|       if( info.error ) return info; | ||||
|       var json = info.json; | ||||
|  | ||||
|       // Determine the resume format: FRESH or JRS | ||||
|       var orgFormat = ( json.meta && json.meta.format && | ||||
|                         json.meta.format.startsWith('FRESH@') ) ? | ||||
|                         'fresh' : 'jrs'; | ||||
|  | ||||
|       // Convert between formats if necessary | ||||
|       if( toFormat && (orgFormat !== toFormat) ) { | ||||
|         json = ResumeConverter[ 'to' + toFormat.toUpperCase() ]( json ); | ||||
|       } | ||||
|  | ||||
|       // Objectify the resume, that is, convert it from JSON to a FRESHResume | ||||
|       // or JRSResume object. | ||||
|       var rez; | ||||
|       if( objectify ) { | ||||
|         var ResumeClass = require('../core/' + (toFormat || orgFormat) + '-resume'); | ||||
|         rez = new ResumeClass().parseJSON( json ); | ||||
|       } | ||||
|  | ||||
|       return { | ||||
|         file: src, | ||||
|         json: info.json, | ||||
|         rez: rez | ||||
|       }; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
|  | ||||
|  | ||||
|   function _parse( fileName, log, toFormat ) { | ||||
|     var rawData; | ||||
|     try { | ||||
|  | ||||
|       // TODO: Core should not log | ||||
|       log( 'Reading '.info + /*orgFormat.toUpperCase().infoBold +*/ | ||||
|         'resume: '.info + fileName.cyan.bold ); | ||||
|  | ||||
|       rawData = FS.readFileSync( fileName, 'utf8' ); | ||||
|       return { | ||||
|         json: JSON.parse( rawData ) | ||||
|       }; | ||||
|  | ||||
|     } | ||||
|     catch(ex) { | ||||
|       return { | ||||
|         error: ex, | ||||
|         raw: rawData | ||||
|       }; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
|  | ||||
| }()); | ||||
|   | ||||
| @@ -9,6 +9,7 @@ Generic template helper definitions for HackMyResume / FluentCV. | ||||
|  | ||||
|   var MD = require('marked') | ||||
|     , H2W = require('../utils/html-to-wpml') | ||||
|     , XML = require('xml-escape') | ||||
|     , moment = require('moment') | ||||
|     , _ = require('underscore'); | ||||
|  | ||||
| @@ -33,10 +34,12 @@ Generic template helper definitions for HackMyResume / FluentCV. | ||||
|     wpml: function( txt, inline ) { | ||||
|       if(!txt) return ''; | ||||
|       inline = (inline && !inline.hash) || false; | ||||
|       txt = XML(txt.trim()); | ||||
|       txt = inline ? | ||||
|         MD(txt.trim()).replace(/^\s*<p>|<\/p>\s*$/gi, '') : | ||||
|         MD(txt.trim()); | ||||
|       txt = H2W( txt.trim() ); | ||||
|         MD(txt).replace(/^\s*<p>|<\/p>\s*$/gi, '') : | ||||
|         MD(txt); | ||||
|       txt = H2W( txt ); | ||||
|       console.log(txt); | ||||
|       return txt; | ||||
|     }, | ||||
|  | ||||
|   | ||||
| @@ -35,8 +35,13 @@ Definition of the HandlebarsGenerator class. | ||||
|  | ||||
|       // Compile and run the Handlebars template. | ||||
|       var template = HANDLEBARS.compile(jst); | ||||
|  | ||||
|       var encData = json; | ||||
|       ( format === 'html' || format === 'pdf' ) && (encData = json.markdownify()); | ||||
|       ( format === 'doc' ) && (encData = json.xmlify()); | ||||
|  | ||||
|       return template({ | ||||
|         r: format === 'html' || format === 'pdf' || format === 'png' ? json.markdownify() : json, | ||||
|         r: encData, | ||||
|         RAW: json, | ||||
|         filt: opts.filters, | ||||
|         cssInfo: cssInfo, | ||||
|   | ||||
| @@ -73,7 +73,7 @@ function main() { | ||||
|   // Massage inputs and outputs | ||||
|   var src = a._.slice(1, splitAt === -1 ? undefined : splitAt ); | ||||
|   var dst = splitAt === -1 ? [] : a._.slice( splitAt + 1 ); | ||||
|   ( splitAt === -1 ) && src.length > 1 && dst.push( src.pop() ); // Allow omitting TO keyword | ||||
|   ( splitAt === -1 ) && (src.length > 1) && (verb !== 'validate') && dst.push( src.pop() ); // Allow omitting TO keyword | ||||
|  | ||||
|   // Invoke the action | ||||
|   (FCMD.verbs[verb] || FCMD.alias[verb]).apply(null, [src, dst, opts, logMsg]); | ||||
|   | ||||
| @@ -47,6 +47,7 @@ Definition of the Markdown to WordProcessingML conversion routine. | ||||
|           break; | ||||
|  | ||||
|         case 'Chars': | ||||
|           if( tok.chars.trim().length ) { | ||||
|           var style = is_bold ? '<w:b/>' : ''; | ||||
|           style += is_italic ? '<w:i/>': ''; | ||||
|           style += is_link ? '<w:rStyle w:val="Hyperlink"/>' : ''; | ||||
| @@ -54,6 +55,7 @@ Definition of the Markdown to WordProcessingML conversion routine. | ||||
|             (is_link ? ('<w:hlink w:dest="' + link_url + '">') : '') + | ||||
|             '<w:r><w:rPr>' + style + '</w:rPr><w:t>' + tok.chars + | ||||
|             '</w:t></w:r>' + (is_link ? '</w:hlink>' : ''); | ||||
|           } | ||||
|           break; | ||||
|       } | ||||
|     }); | ||||
|   | ||||
							
								
								
									
										40
									
								
								src/utils/syntax-error-ex.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/utils/syntax-error-ex.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| /** | ||||
| Definition of the SyntaxErrorEx class. | ||||
| @module syntax-error-ex.js | ||||
| */ | ||||
|  | ||||
| (function() { | ||||
|  | ||||
|  | ||||
|   /** | ||||
|   Represents a SyntaxError exception with line and column info. | ||||
|   Collect syntax error information from the provided exception object. The | ||||
|   JavaScript `SyntaxError` exception isn't interpreted uniformly across environ- | ||||
|   ments, so we first check for a .lineNumber and .columnNumber and, if that's | ||||
|   not present, fall back to the JSONLint library, which provides that info. | ||||
|   See: http://stackoverflow.com/q/13323356 | ||||
|   @class SyntaxErrorEx | ||||
|   */ | ||||
|  | ||||
|   module.exports = function SyntaxErrorEx( ex, rawData ) { | ||||
|  | ||||
|     var lineNum = null, colNum = null; | ||||
|     if( ex.lineNumber !== undefined && ex.lineNumber !== null ) { | ||||
|       lineNum = ex.lineNumber; | ||||
|     } | ||||
|     if( ex.columnNumber !== undefined && ex.columnNumber !== null ) { | ||||
|       colNum = ex.columnNumber; | ||||
|     } | ||||
|     if( lineNum === null || colNum === null ) { | ||||
|       var JSONLint = require('json-lint'); | ||||
|       var lint = JSONLint( rawData, { comments: false } ); | ||||
|       if( lineNum === null ) lineNum = (lint.error ? lint.line : '???'); | ||||
|       if( colNum === null ) colNum = (lint.error ? lint.character : '???'); | ||||
|     } | ||||
|     this.line = lineNum; | ||||
|     this.col = colNum; | ||||
|  | ||||
|   }; | ||||
|  | ||||
|  | ||||
| }()); | ||||
| @@ -1,3 +1,9 @@ | ||||
| /** | ||||
| Implementation of the 'convert' verb for HackMyResume. | ||||
| @module convert.js | ||||
| @license MIT. See LICENSE.md for details. | ||||
| */ | ||||
|  | ||||
| (function(){ | ||||
|  | ||||
|   var ResumeFactory = require('../core/resume-factory'); | ||||
| @@ -5,22 +11,23 @@ | ||||
|   /** | ||||
|   Convert between FRESH and JRS formats. | ||||
|   */ | ||||
|   module.exports = function convert( src, dst, opts, logger ) { | ||||
|   module.exports = function convert( sources, dst, opts, logger ) { | ||||
|     var _log = logger || console.log; | ||||
|     if( !src || !src.length ) { throw { fluenterror: 6 }; } | ||||
|     if( !sources || !sources.length ) { throw { fluenterror: 6 }; } | ||||
|     if( !dst || !dst.length ) { | ||||
|       if( src.length === 1 ) { throw { fluenterror: 5 }; } | ||||
|       else if( src.length === 2 ) { dst = [ src[1] ]; src = [ src[0] ]; } | ||||
|       if( sources.length === 1 ) { throw { fluenterror: 5 }; } | ||||
|       else if( sources.length === 2 ) { dst = [ sources[1] ]; sources = [ sources[0] ]; } | ||||
|       else { throw { fluenterror: 5 }; } | ||||
|     } | ||||
|     if( src && dst && src.length && dst.length && src.length !== dst.length ) { | ||||
|     if( sources && dst && sources.length && dst.length && sources.length !== dst.length ) { | ||||
|       throw { fluenterror: 7 }; | ||||
|     } | ||||
|     var sheets = ResumeFactory.load( src, _log ); | ||||
|     sheets.forEach(function(sheet, idx){ | ||||
|       var sourceFormat = sheet.imp.orgFormat === 'JRS' ? 'JRS' : 'FRESH'; | ||||
|     var sourceResumes = ResumeFactory.load( sources, _log, null, true ); | ||||
|     sourceResumes.forEach(function( src, idx ) { | ||||
|       var sheet = src.rez; | ||||
|       var sourceFormat = ((sheet.basics && sheet.basics.imp) || sheet.imp).orgFormat === 'JRS' ? 'JRS' : 'FRESH'; | ||||
|       var targetFormat = sourceFormat === 'JRS' ? 'FRESH' : 'JRS'; | ||||
|       _log( 'Converting '.useful + sheet.imp.fileName.useful.bold + (' (' + | ||||
|       _log( 'Converting '.useful + src.file.useful.bold + (' (' + | ||||
|         sourceFormat + ') to ').useful + dst[0].useful.bold + | ||||
|         (' (' + targetFormat + ').').useful ); | ||||
|       sheet.saveAs( dst[idx], targetFormat ); | ||||
|   | ||||
| @@ -1,3 +1,9 @@ | ||||
| /** | ||||
| Implementation of the 'create' verb for HackMyResume. | ||||
| @module create.js | ||||
| @license MIT. See LICENSE.md for details. | ||||
| */ | ||||
|  | ||||
| (function(){ | ||||
|  | ||||
|   var FLUENT = require('../hackmyapi') | ||||
|   | ||||
| @@ -54,28 +54,28 @@ Implementation of the 'generate' verb for HackMyResume. | ||||
|  | ||||
|     // Load the theme... | ||||
|     var tFolder = verify_theme( _opts.theme ); | ||||
|     var theTheme = load_theme( tFolder ); | ||||
|     var theme = load_theme( tFolder ); | ||||
|  | ||||
|     // Load input resumes... | ||||
|     if( !src || !src.length ) { throw { fluenterror: 3 }; } | ||||
|     var sheets = ResumeFactory.load( src, _log, null, | ||||
|       theTheme.render ? 'JRS' : 'FRESH' ); | ||||
|     var sheets = ResumeFactory.load(src, _log, theme.render ? 'JRS' : 'FRESH', true); | ||||
|  | ||||
|     // Merge input resumes... | ||||
|     var msg = ''; | ||||
|     rez = _.reduceRight( sheets, function( a, b, idx ) { | ||||
|     var rezRep = _.reduceRight( sheets, function( a, b, idx ) { | ||||
|       msg += ((idx == sheets.length - 2) ? | ||||
|       'Merging '.gray+ a.imp.fileName : '') + ' onto '.gray + b.imp.fileName; | ||||
|       return extend( true, b, a ); | ||||
|       'Merging '.gray + a.rez.imp.fileName : '') + ' onto '.gray + b.rez.fileName; | ||||
|       return extend( true, b.rez, a.rez ); | ||||
|     }); | ||||
|     rez = rezRep.rez; | ||||
|     msg && _log(msg); | ||||
|  | ||||
|     // Expand output resumes... | ||||
|     var targets = expand( dst, theTheme ); | ||||
|     var targets = expand( dst, theme ); | ||||
|  | ||||
|     // Run the transformation! | ||||
|     targets.forEach( function(t) { | ||||
|       t.final = single( t, theTheme, targets ); | ||||
|       t.final = single( t, theme, targets ); | ||||
|     }); | ||||
|  | ||||
|     // Don't send the client back empty-handed | ||||
|   | ||||
| @@ -1,16 +1,23 @@ | ||||
| /** | ||||
| Implementation of the 'validate' verb for HackMyResume. | ||||
| @module validate.js | ||||
| @license MIT. See LICENSE.md for details. | ||||
| */ | ||||
|  | ||||
| (function() { | ||||
|  | ||||
|   var FS = require('fs'); | ||||
|   var ResumeFactory = require('../core/resume-factory'); | ||||
|   var SyntaxErrorEx = require('../utils/syntax-error-ex'); | ||||
|  | ||||
|   module.exports = | ||||
|  | ||||
|   /** | ||||
|   Validate 1 to N resumes in either FRESH or JSON Resume format. | ||||
|   */ | ||||
|   function validate( src, unused, opts, logger ) { | ||||
|   function validate( sources, unused, opts, logger ) { | ||||
|     var _log = logger || console.log; | ||||
|     if( !src || !src.length ) { throw { fluenterror: 6 }; } | ||||
|     if( !sources || !sources.length ) { throw { fluenterror: 6 }; } | ||||
|     var isValid = true; | ||||
|  | ||||
|     var validator = require('is-my-json-valid'); | ||||
| @@ -20,67 +27,51 @@ | ||||
|     }; | ||||
|  | ||||
|     // Load input resumes... | ||||
|     var sheets = ResumeFactory.load(src, _log, function( res ) { | ||||
|       try { | ||||
|         return { | ||||
|           file: res, | ||||
|           raw: FS.readFileSync( res, 'utf8' ) | ||||
|         }; | ||||
|       } | ||||
|       catch( ex ) { | ||||
|         throw ex; | ||||
|       } | ||||
|     }); | ||||
|     sources.forEach(function( src ) { | ||||
|  | ||||
|     sheets.forEach( function( rep ) { | ||||
|       var result = ResumeFactory.loadOne( src, function(){}, null, false ); | ||||
|       if( result.error ) { | ||||
|         _log( 'Validating '.info + src.infoBold + ' against '.info + 'AUTO'.infoBold + ' schema:'.info + ' BROKEN'.red.bold ); | ||||
|  | ||||
|       var rez; | ||||
|       try { | ||||
|         rez = JSON.parse( rep.raw ); | ||||
|       } | ||||
|       catch( ex ) { // Note [1] | ||||
|         _log('Validating '.info + rep.file.infoBold + | ||||
|           ' against FRESH/JRS schema: '.info + 'ERROR!'.error.bold); | ||||
|  | ||||
|         if (ex instanceof SyntaxError) { | ||||
|           // Invalid JSON | ||||
|           _log( '--> '.bold.red + rep.file.toUpperCase().red + | ||||
|             ' contains invalid JSON. Unable to validate.'.red ); | ||||
|           _log( ('    INTERNAL: ' + ex).red ); | ||||
|         var ex = result.error; // alias | ||||
|         if ( ex instanceof SyntaxError) { | ||||
|           var info = new SyntaxErrorEx( ex, result.raw ); | ||||
|           _log( ('--> '.warn.bold + src.toUpperCase() + ' contains invalid JSON on line ' + | ||||
|             info.line + ' column ' + info.col + '.').warn + | ||||
|             ' Unable to validate.'.warn ); | ||||
|           _log( ('    INTERNAL: ' + ex).warn ); | ||||
|         } | ||||
|         else { | ||||
|  | ||||
|           _log(('ERROR: ' + ex.toString()).red.bold); | ||||
|           _log(('ERROR: ' + ex.toString()).warn.bold); | ||||
|         } | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       var json = result.json; | ||||
|       var isValid = false; | ||||
|       var style = 'useful'; | ||||
|       var errors = []; | ||||
|       var fmt = rez.meta && | ||||
|         (rez.meta.format === 'FRESH@0.1.0') ? 'fresh':'jars'; | ||||
|       var fmt = json.meta && (json.meta.format==='FRESH@0.1.0') ? 'fresh':'jars'; | ||||
|  | ||||
|       try { | ||||
|  | ||||
|         var validate = validator( schemas[ fmt ], { // Note [1] | ||||
|           formats: { | ||||
|             date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/ | ||||
|           } | ||||
|         }); | ||||
|  | ||||
|         isValid = validate( rez ); | ||||
|         isValid = validate( json ); | ||||
|         if( !isValid ) { | ||||
|           style = 'warn'; | ||||
|           errors = validate.errors; | ||||
|         } | ||||
|  | ||||
|       } | ||||
|       catch(ex) { | ||||
|       catch(exc) { | ||||
|         return; | ||||
|       } | ||||
|  | ||||
|       _log( 'Validating '.info + rep.file.infoBold + ' against '.info + | ||||
|       _log( 'Validating '.info + result.file.infoBold + ' against '.info + | ||||
|         fmt.replace('jars','JSON Resume').toUpperCase().infoBold + | ||||
|         ' schema: '.info + (isValid ? 'VALID!' : 'INVALID')[style].bold ); | ||||
|  | ||||
| @@ -93,5 +84,4 @@ | ||||
|     }); | ||||
|   }; | ||||
|  | ||||
|  | ||||
| }()); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user