1
0
mirror of https://github.com/JuanCanham/HackMyResume.git synced 2025-05-12 00:27:08 +01:00

Compare commits

...

65 Commits

Author SHA1 Message Date
3cf850ea0e Update test exemplars. 2016-02-14 05:32:33 -05:00
1b0bc87b60 Update changelog and version. 2016-02-14 04:54:44 -05:00
5d3b993737 Bump fresh-themes to 0.15.1-beta.
Not 100% necessary given "^" but support naive stripping of the "^"
decorator.
2016-02-14 04:32:39 -05:00
917fd8e3f3 Refactor helpers.
Rebind Handlebars helpers to drop the pesky options hash for standalone
helpers that don't need it. Move block helpers (which do need the
Handlebars options/context) to a separate file for special handling.
2016-02-14 04:10:23 -05:00
6ac2cd490b Bump fresh-test-resumes to 0.7.0. 2016-02-13 23:45:53 -05:00
8100190978 Bump fresh-themes to 0.15.0-beta. 2016-02-13 22:54:43 -05:00
7c36ff8331 Introduce "date" helper. 2016-02-13 22:54:07 -05:00
255a518565 Set test timeout to 30 seconds.
Most themes should generate in < 1s but allow up to 30 seconds for
network latency when opening a remote file, or for fetching remote
resources (CSS, JS, etc) during a local build.
2016-02-13 20:42:03 -05:00
2d595350c6 Escape LaTeX during generation. 2016-02-13 20:40:17 -05:00
ca92d41d9e Numerous fixes. 2016-02-13 16:08:45 -05:00
3f8e795c61 Fix generation glitches.
Fix output file name glitch, writing CSS files to destination folder,
and an issue where the process would evaporate before PDF/PNG generation
could complete.
2016-02-13 03:27:11 -05:00
9927e79900 Clean up CoffeeScript. 2016-02-13 00:40:10 -05:00
dbef9f0a35 Improve VALIDATE error handling. 2016-02-13 00:11:52 -05:00
c889664c31 More VALIDATE fixups. 2016-02-12 23:47:08 -05:00
7a60cd0bab Fixup VALIDATE command.
Introduce MISSING and UNKNOWN states alongside BROKEN, VALID, and
INVALID and fix regressions introduced in previous refactorings.
2016-02-12 22:49:56 -05:00
964350d3c7 Bump fresh-jrs-converter to 0.2.2.
Technically the "^0.2.1" implies v0.2.2 but eventually we'll drop the
"^" and use shrinkwrapped versions in dev, so explicitly bump for now.
2016-02-12 21:42:50 -05:00
b57d9f05af jsHint: Allow == null.
Relax jsHint's barbaric and antiquated default behavior on triple-equals
null comparisons. Allow expressive, precise, and subtle expressions such
as CoffeeScript's use of "== null" for testing against null OR undefined
under the existential operator.
2016-02-12 17:42:48 -05:00
b26799f9fc Improve JSON error handling.
Add support for detection of invalid line breaks in JSON string values.
Fixes #137. Could be improved to fetch the column number and drop the
messy grabbing of the line number from the exception message via regex,
but currently the "jsonlint" library (not to be confused with
"json-lint") only emits an error string. Since this is also the library
that drives http://jsonlint.com, we'll accept the messy regex in return
for more robust error checking when our default json-lint path fails.

All of the above only necessary because standard JSON.parse error
handling is broken in all environments. : )
2016-02-12 17:11:11 -05:00
daeffd27b5 Remove HB reference from generic helpers. 2016-02-11 22:06:43 -05:00
f87eb46549 Fix theme generation error. 2016-02-11 22:04:11 -05:00
da7cd28734 Remove unused var. 2016-02-11 22:03:49 -05:00
31e0bb69cc Introduce "pad()" helper.
Introduce a helper to emit padded strings / arrays of strings.
2016-02-11 22:02:50 -05:00
5c248cca2a Remove output folder. 2016-02-11 12:09:47 -05:00
f83eb018e8 Scrub tests. 2016-02-11 12:08:11 -05:00
317a250917 Gather. 2016-02-11 11:48:44 -05:00
aaa5e1fc1f Refactor generation.
Merge implicit and explicit generation paths, start emitting file
transform & copy signals, fix various bugs, introduce new bugs, support
better --debug outputs in the future.
2016-02-09 15:27:34 -05:00
1bc4263a46 Aerate. 2016-02-09 10:50:10 -05:00
e191af1fb0 Fix glitch in converted CoffeeScript.
Replace naked ternary with if then else.
2016-02-09 10:41:48 -05:00
7c0a9bcc02 Aerate. 2016-02-09 10:37:33 -05:00
d894f62607 Add ResumeFactory to facade.
Until facade is decommissioned and mothballed
2016-02-09 08:55:00 -05:00
2758038858 Cleanup and bug fixes.
Remove file-based open methods from resume classes; force clients to use
clean string-based or JSON overloads; fix processing glitch in
validate(); tweak outputs; adjust tests; update CHANGELOG; etc.
2016-02-04 18:49:16 -05:00
661fb91861 Aerate. 2016-02-04 15:23:47 -05:00
3c551eb923 Point package.json "main" at "dist" folder. 2016-02-04 14:38:11 -05:00
5bf4bda6de Fix PEEK command. 2016-02-03 20:08:17 -05:00
49ae016f08 Deglitch. 2016-02-02 19:02:56 -05:00
89957aed76 Scrub.
Adding slightly heavier function-level comments as a start for API docs.
2016-02-02 17:47:32 -05:00
233025ddcc Fix indentation. 2016-02-02 17:46:38 -05:00
11dd8952d8 Improve PEEK behavior. 2016-02-02 17:34:10 -05:00
d7c83613df Make CLI tests asynchronous. 2016-02-02 16:18:38 -05:00
a456093f13 Clean up a couple regressions. 2016-02-02 14:13:38 -05:00
dd4851498a Remove Resig's class implementation.
Fun while it lasted.
2016-02-02 13:49:02 -05:00
f72b02a0f4 Refactor generators to CoffeeScript classes. 2016-02-02 13:38:12 -05:00
63a0c78fc5 Refactor verbs to CoffeeScript classes.
Retire Resig's class implementation.
2016-02-01 23:16:49 -05:00
fd39cc9fd9 Adjust error handling / tests. 2016-02-01 22:56:08 -05:00
70f45d468d Asynchrony. 2016-02-01 22:52:13 -05:00
212b01092c Improve proc spawn behavior.
Interim until async / promises support is in.
2016-02-01 09:25:22 -05:00
36d641801b Add Gitter chat badge. 2016-01-31 20:02:27 -05:00
bd278268f6 Merge branch 'master' of https://github.com/hacksalot/HackMyResume 2016-01-31 12:21:44 -05:00
abe31e30e0 Update license year range to 2016 2016-01-31 12:21:29 -05:00
314d8d8763 Introduce build instructions. 2016-01-31 12:17:17 -05:00
ed0792e8f8 Fix YML/JSON/PNG invalid output format warning.
Fixes #97 but we still need to support standalone PNG (ie, a PNG not
generated as part of a .all output target).
2016-01-31 09:41:00 -05:00
90765bf90b Refactor verb invocations to base. 2016-01-31 08:37:12 -05:00
f1ba7765ee Include date tests. 2016-01-30 20:20:32 -05:00
27c7a0264a Improve date handling. 2016-01-30 20:06:04 -05:00
8e806dc04f Improve duration calcs, intro base resume class. 2016-01-30 16:40:22 -05:00
8ec6b5ed6a Bump version to 1.7.4. 2016-01-30 12:08:02 -05:00
4ef4ec5d42 Remove Node. 4.5.
Travis support 4.1 and 5.0 but not 4.5.
2016-01-30 11:49:27 -05:00
2f523b845b Travis: Add Node 4.5. 2016-01-30 11:40:36 -05:00
1c416f39d3 Fix JSON Resume theme breakage.
Fixes #128.
2016-01-30 11:31:39 -05:00
1de0eff7b3 Merge pull request #114 from pra85/patch-1
Update license year range to 2016
2016-01-29 22:32:45 -05:00
f8a39b0908 Update license year range to 2016 2016-01-30 07:41:15 +05:30
d69e4635be Bump fresh-themes to 0.14.1-beta. 2016-01-29 16:14:53 -05:00
4b7d594502 Bump version to 1.7.3. 2016-01-29 15:50:34 -05:00
896b7055c1 Fix issue with undefined sections.
Fixes #127.
2016-01-29 15:50:21 -05:00
0f65e4c9f3 Finish HackMyCore reshaping.
Reintroduce HackMyCore, dropping the interim submodule, and reorganize
and improve tests.
2016-01-29 15:23:57 -05:00
175 changed files with 14645 additions and 2020 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@ doc/
docs/
local/
npm-debug.log
*.map
# Emacs detritus
# -*- mode: gitignore; -*-

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "src/hmc"]
path = src/hmc
url = git://github.com/hacksalot/HackMyCore.git

58
BUILDING.md Normal file
View File

@ -0,0 +1,58 @@
Building
========
*See [CONTRIBUTING.md][contrib] for more information on contributing to the
HackMyResume or FluentCV projects.*
HackMyResume is a standard Node.js command line app implemented in a mix of
CoffeeScript and JavaScript. Setting up a build environment is easy:
## Prerequisites ##
1. OS: Linux, OS X, or Windows
2. Install [Node.js][node] and [Grunt][grunt].
## Set up a build environment ###
1. Fork [hacksalot/HackMyResume][hmr] to your GitHub account.
2. Clone your fork locally.
3. From within the top-level HackMyResume folder, run `npm install` to install
project dependencies.
4. Create a new branch, based on the latest HackMyResume `dev` branch, to
contain your work.
5. Run `npm link` in the HackMyResume folder so that the `hackmyresume` command
will reference your local installation (you may need to
`npm uninstall -g hackmyresume` first).
## Making changes
1. HackMyResume sources live in the [`/src`][src] folder. Always make your edits
there, never in the generated `/dist` folder.
2. After making your changes, run `grunt build` to package the HackMyResume
sources to the `/dist` folder. This will transform CoffeeScript files to
JavaScript and perform other build steps as necessary. In the future, a watch
task or guardfile will be added to automate this step.
3. Do local spot testing with `hackmyresume` as normal.
4. When you're ready to submit your changes, run `grunt test` to run the HMR
test suite. Fix any errors that occur.
5. Commit and push your changes.
6. Submit a pull request targeting the HackMyResume `dev` branch.
[node]: https://nodejs.org/en/
[grunt]: http://gruntjs.com/
[hmr]: https://github.com/hacksalot/HackMyResume
[src]: https://github.com/hacksalot/HackMyResume/tree/master/src
[contrib]: https://github.com/hacksalot/HackMyResume/blob/master/CONTRIBUTING.md

View File

@ -1,5 +1,108 @@
CHANGELOG
=========
## v1.8.0
### Added
- Updated `Awesome` theme to latest version of [Awesome-CV][acv].
- Introduced new theme helpers: `pad`, `date`.
### Fixed
- Fixed an issue where the `Awesome` theme wouldn't correctly generate LaTeX
outputs (#138).
- Emit a line number for syntax errors around embedded newlines in JSON strings
(#137).
- Fix several PDF / PNG generation errors (#132, others).
- Display a more helpful error message when attempting to generate a PDF or PNG
on a machine where PhantomJS and/or wkhtmltopdf are either not installed or
not path-accessible.
- Fixed an issue that would cause long-running PDF/PNG generation to fail in
certain environments.
- Fixed an issue involving an unhelpful spawn-related exception (#136).
### Internal
- JSHint will no longer gripe at the use of `== null` and `!= null` in
CoffeeScript transpilation.
- Introduced [template-friendly Awesome-CV fork][awefork] to isolate template
expansion logic & provide better durability for HackMyResume's `awesome` theme.
- Fixed a couple temporary regressions (#139, #140) on the dev branch.
- Additional tests.
- Minor breaking HackMyResume API changes.
## v1.7.4
### Added
- [Build instructions](https://github.com/hacksalot/HackMyResume/blob/master/BUILDING.md).
### Changed
- More precise date handling.
### Fixed
- Issue with incomplete PDF generation (#127).
- Issue with building JSON Resume themes (#128).
- Issue with generating `.json` output format by itself (#97).
## v1.7.3
### Fixed
- Issue with generated PDFs being chopped off and displaying a mysterious sequence of numbers of unknown and possibly alien origin (#127).
- Unsightly border on Modern:PDF.
- Modern|Positive:PDF formats now correctly reference their PDF-specific CSS files.
- `Incorrect helper use` warning in Positive:DOC.
## v1.7.2
### Changed
- Interim release supporting FluentCV Desktop.
### Internal
- Moved [HackMyCore](https://github.com/hacksalot/HackMyCore) dependency to
submodule.
## v1.7.1
### Changed
- Caffeinate. CoffeeScript now used throughout
[HackMyResume](https://github.com/hacksalot/HackMyResume) and
[HackMyCore](https://github.com/hacksalot/HackMyCore); generated JavaScript
lives in `/dist`.
### Fixed
- Issue with generating a single PDF with the `.pdf` extension (#99).
## v1.7.0
### Changed
- [Internal] Relocated HMR processing code to the
[HackMyCore](https://github.com/hacksalot/HackMyCore) project. Shouldn't affect
normal use.
## v1.6.0
### Major Improvements
@ -304,3 +407,5 @@ theme.
[i111]: https://github.com/hacksalot/HackMyResume/issues/111
[fresca]: https://github.com/fluentdesk/FRESCA
[themes]: https://github.com/fluentdesk/fresh-themes
[awefork]: https://github.com/fluentdesk/Awesome-CV
[acv]: https://github.com/posquit0/Awesome-CV

View File

@ -4,17 +4,11 @@ Contributing
*Note: HackMyResume is also available as [FluentCV][fcv]. Contributors are
credited in both.*
HackMyResume needs your help! Our contribution workflow is based on [GitHub
Flow][flow] and we respond to all pull requests and issues, usually within 24
hours. HackMyResume has no corporate affiliation and no commercial basis, which
allows the project to maintain a strict user-first policy, rapid development
velocity, and a liberal stance on contributions and exotic functionality in
keeping with the spirit (and name) of the tool.
In short, your code is welcome here.
## How To Contribute
*See [BUILDING.md][building] for instructions on setting up a HackMyResume
development environment.*
1. Optional: [**open an issue**][iss] identifying the feature or bug you'd like
to implement or fix. This step isn't required — you can start hacking away on
HackMyResume without clearing it with us — but helps avoid duplication of work
@ -25,7 +19,7 @@ similar; call it whatever you like) to perform your work in.
4. **Install dependencies** by running `npm install` in the top-level
HackMyResume folder.
5. Make your **commits** as usual.
6. **Verify** your changes locally with `npm test`.
6. **Verify** your changes locally with `grunt test`.
7. **Push** your commits.
7. **Submit a pull request** from your feature branch to the HackMyResume `dev`
branch.
@ -48,7 +42,7 @@ You can reach hacksalot directly at:
hacksalot@indevious.com
```
Thanks! See you out there in the trenches.
Thanks for your interest in the HackMyResume project.
[fcv]: https://github.com/fluentdesk/fluentcv
[flow]: https://guides.github.com/introduction/flow/
@ -56,3 +50,4 @@ Thanks! See you out there in the trenches.
[ha]: https://github.com/hacksalot
[th]: https://github.com/tomheon
[awesome]: https://github.com/hacksalot/HackMyResume/graphs/contributors
[building]: https://github.com/hacksalot/HackMyResume/blob/master/BUILDING.md

View File

@ -10,22 +10,19 @@ module.exports = function (grunt) {
main: {
expand: true,
cwd: 'src',
src: ['**/*','!**/*.coffee','!hmc/**'],
dest: 'dist/',
},
core: {
expand: true,
cwd: 'src',
src: ['hmc/dist/**/*','hmc/package.json'],
src: ['**/*','!**/*.coffee'],
dest: 'dist/',
}
},
coffee: {
main: {
options: {
sourceMap: true
},
expand: true,
cwd: 'src',
src: ['cli/**/*.coffee'],
src: ['**/*.coffee'],
dest: 'dist/',
ext: '.js'
}
@ -73,7 +70,8 @@ module.exports = function (grunt) {
jshint: {
options: {
laxcomma: true,
expr: true
expr: true,
eqnull: true
},
all: ['Gruntfile.js', 'dist/cli/**/*.js', 'test/*.js']
}

View File

@ -1,7 +1,7 @@
The MIT License
===============
Copyright (c) 2016 hacksalot (https://github.com/hacksalot)
Copyright (c) 2015-2016 hacksalot (https://github.com/hacksalot)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -4,6 +4,7 @@ HackMyResume
[![Latest release][img-release]][latest-release]
[![Build status (MASTER)][img-master]][travis-url-master]
[![Build status (DEV)][img-dev]][travis-url-dev]
[![Join the chat at https://gitter.im/hacksalot/HackMyResume](https://badges.gitter.im/hacksalot/HackMyResume.svg)](https://gitter.im/hacksalot/HackMyResume?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
*Create polished résumés and CVs in multiple formats from your command line or
shell. Author in clean Markdown and JSON, export to Word, HTML, PDF, LaTeX,

36
dist/cli/error.js vendored
View File

@ -8,19 +8,19 @@ Error-handling routines for HackMyResume.
(function() {
var ErrorHandler, FCMD, FS, HMSTATUS, M2C, PATH, PKG, SyntaxErrorEx, WRAP, YAML, _defaultLog, assembleError, chalk, extend, printf;
HMSTATUS = require('../hmc/dist/core/status-codes');
HMSTATUS = require('../core/status-codes');
PKG = require('../../package.json');
FS = require('fs');
FCMD = require('../hmc');
FCMD = require('../index');
PATH = require('path');
WRAP = require('word-wrap');
M2C = require('../hmc/dist/utils/md2chalk.js');
M2C = require('../utils/md2chalk');
chalk = require('chalk');
@ -30,13 +30,12 @@ Error-handling routines for HackMyResume.
printf = require('printf');
SyntaxErrorEx = require('../hmc/dist/utils/syntax-error-ex');
SyntaxErrorEx = require('../utils/syntax-error-ex');
require('string.prototype.startswith');
/**
Error handler for HackMyResume. All errors are handled here.
/** Error handler for HackMyResume. All errors are handled here.
@class ErrorHandler
*/
@ -62,7 +61,7 @@ Error-handling routines for HackMyResume.
stack = ex.stack || (ex.inner && ex.inner.stack);
stack && o(chalk.gray(stack));
}
if (ex.quit || objError.quit) {
if (shouldExit) {
if (this.debug) {
o(chalk.cyan('Exiting with error code ' + ex.fluenterror.toString()));
}
@ -140,7 +139,6 @@ Error-handling routines for HackMyResume.
if (ex.inner) {
msg += chalk.red('\n' + ex.inner);
}
withStack = true;
quit = false;
etype = 'error';
break;
@ -215,13 +213,27 @@ Error-handling routines for HackMyResume.
if (SyntaxErrorEx.is(ex.inner)) {
console.error(printf(M2C(this.msgs.readError.msg, 'red'), ex.file));
se = new SyntaxErrorEx(ex, ex.raw);
msg = printf(M2C(this.msgs.parseError.msg, 'red'), se.line, se.col);
} else if (ex.inner && ex.inner.line !== void 0 && ex.inner.col !== void 0) {
msg = printf(M2C(this.msgs.parseError.msg, 'red'), ex.inner.line, ex.inner.col);
if ((se.line != null) && (se.col != null)) {
msg = printf(M2C(this.msgs.parseError.msg[0], 'red'), se.line, se.col);
} else if (se.line != null) {
msg = printf(M2C(this.msgs.parseError.msg[1], 'red'), se.line);
} else {
msg = M2C(this.msgs.parseError.msg[2], 'red');
}
} else if (ex.inner && (ex.inner.line != null) && (ex.inner.col != null)) {
msg = printf(M2C(this.msgs.parseError.msg[0], 'red'), ex.inner.line, ex.inner.col);
} else {
msg = ex;
}
etype = 'error';
break;
case HMSTATUS.createError:
msg = printf(M2C(this.msgs.createError.msg), ex.inner.path);
etype = 'error';
break;
case HMSTATUS.validateError:
msg = printf(M2C(this.msgs.validateError.msg), ex.inner.toString());
etype = 'error';
}
return {
msg: msg,
@ -232,3 +244,5 @@ Error-handling routines for HackMyResume.
};
}).call(this);
//# sourceMappingURL=error.js.map

View File

@ -12,11 +12,11 @@ Command-line interface (CLI) for HackMyResume.
try {
require('./cli/main')( process.argv );
require('./main')( process.argv );
}
catch( ex ) {
require('./cli/error').err( ex, true );
require('./error').err( ex, true );
}

85
dist/cli/main.js vendored
View File

@ -6,9 +6,9 @@ Definition of the `main` function.
*/
(function() {
var Command, EXTEND, FS, HME, HMR, HMSTATUS, OUTPUT, PAD, PATH, PKG, StringUtils, _, _opts, _out, _title, chalk, execute, initOptions, initialize, loadOptions, logMsg, main, safeLoadJSON, splitSrcDest;
var Command, EXTEND, FS, HME, HMR, HMSTATUS, M2C, OUTPUT, PAD, PATH, PKG, StringUtils, _, _err, _exitCallback, _opts, _out, _title, chalk, execute, executeFail, executeSuccess, initOptions, initialize, loadOptions, logMsg, main, printf, safeLoadJSON, splitSrcDest;
HMR = require('../hmc');
HMR = require('../index');
PKG = require('../../package.json');
@ -20,13 +20,13 @@ Definition of the `main` function.
PATH = require('path');
HMSTATUS = require('../hmc/dist/core/status-codes');
HMSTATUS = require('../core/status-codes');
HME = require('../hmc/dist/core/event-codes');
HME = require('../core/event-codes');
safeLoadJSON = require('../hmc/dist/utils/safe-json-loader');
safeLoadJSON = require('../utils/safe-json-loader');
StringUtils = require('../hmc/dist/utils/string.js');
StringUtils = require('../utils/string.js');
_ = require('underscore');
@ -36,12 +36,20 @@ Definition of the `main` function.
Command = require('commander').Command;
M2C = require('../utils/md2chalk');
printf = require('printf');
_opts = {};
_title = chalk.white.bold('\n*** HackMyResume v' + PKG.version + ' ***');
_out = new OUTPUT(_opts);
_err = require('./error');
_exitCallback = null;
/*
A callable implementation of the HackMyResume CLI. Encapsulates the command
@ -51,9 +59,9 @@ Definition of the `main` function.
process.argv (in production) or custom parameters (in test).
*/
main = module.exports = function(rawArgs) {
main = module.exports = function(rawArgs, exitCallback) {
var args, initInfo, program;
initInfo = initialize(rawArgs);
initInfo = initialize(rawArgs, exitCallback);
args = initInfo.args;
program = new Command('hackmyresume').version(PKG.version).description(chalk.yellow.bold('*** HackMyResume ***')).option('-s --silent', 'Run in silent mode').option('--no-color', 'Disable colors').option('--color', 'Enable colors').option('-d --debug', 'Enable diagnostics', false).option('-a --assert', 'Treat warnings as errors', false).option('-v --version', 'Show the version').allowUnknownOption();
program.jsonArgs = initInfo.options;
@ -92,8 +100,9 @@ Definition of the `main` function.
/* Massage command-line args and setup Commander.js. */
initialize = function(ar) {
initialize = function(ar, exitCallback) {
var o;
_exitCallback = exitCallback || process.exit;
o = initOptions(ar);
o.silent || logMsg(_title);
if (o.debug) {
@ -105,20 +114,18 @@ Definition of the `main` function.
_out.log(chalk.cyan(PAD(' FRESCA:', 25, null, PAD.RIGHT)) + chalk.cyan.bold(PKG.dependencies.fresca));
_out.log('');
}
_err.init(o.debug, o.assert, o.silent);
if (o.verb && !HMR.verbs[o.verb] && !HMR.alias[o.verb]) {
throw {
_err.err({
fluenterror: HMSTATUS.invalidCommand,
quit: true,
attempted: o.orgVerb
};
}, true);
}
Command.prototype.missingArgument = function(name) {
if (this.name() !== 'new') {
throw {
fluenterror: HMSTATUS.resumeNotFound,
quit: true
};
}
_err.err({
fluenterror: this.name() !== 'new' ? HMSTATUS.resumeNotFound : HMSTATUS.createNameMissing
}, true);
};
Command.prototype.helpInformation = function() {
var manPage;
@ -136,7 +143,7 @@ Definition of the `main` function.
initOptions = function(ar) {
oVerb;
var args, cleanArgs, inf, isDebug, isMono, isSilent, oJSON, oVerb, optStr, optsIdx, verb, vidx;
var args, cleanArgs, inf, isAssert, isDebug, isMono, isSilent, oJSON, oVerb, optStr, optsIdx, verb, vidx;
verb = '';
args = ar.slice();
cleanArgs = args.slice(2);
@ -177,6 +184,9 @@ Definition of the `main` function.
isSilent = _.some(args, function(v) {
return v === '-s' || v === '--silent';
});
isAssert = _.some(args, function(v) {
return v === '-a' || v === '--assert';
});
isMono = _.some(args, function(v) {
return v === '--no-color';
});
@ -184,6 +194,7 @@ Definition of the `main` function.
color: !isMono,
debug: isDebug,
silent: isSilent,
assert: isAssert,
orgVerb: oVerb,
verb: verb,
json: oJSON,
@ -195,23 +206,43 @@ Definition of the `main` function.
/* Invoke a HackMyResume verb. */
execute = function(src, dst, opts, log) {
var hand, v;
loadOptions.call(this, opts, this.parent.jsonArgs);
hand = require('./error');
hand.init(_opts.debug, _opts.assert, _opts.silent);
var prom, v;
v = new HMR.verbs[this.name()]();
loadOptions.call(this, opts, this.parent.jsonArgs);
_opts.errHandler = v;
_out.init(_opts);
v.on('hmr:status', function() {
return _out["do"].apply(_out, arguments);
});
v.on('hmr:error', function() {
return hand.err.apply(hand, arguments);
return _err.err.apply(_err, arguments);
});
v.invoke.call(v, src, dst, _opts, log);
if (v.errorCode) {
return process.exit(v.errorCode);
prom = v.invoke.call(v, src, dst, _opts, log);
prom.then(executeSuccess, executeFail);
};
/* Success handler for verb invocations. Calls process.exit by default */
executeSuccess = function(obj) {};
/* Failure handler for verb invocations. Calls process.exit by default */
executeFail = function(err) {
var finalErrorCode, msgs;
finalErrorCode = -1;
if (err) {
finalErrorCode = err.fluenterror ? err.fluenterror : err;
}
if (_opts.debug) {
msgs = require('./msg').errors;
logMsg(printf(M2C(msgs.exiting.msg, 'cyan'), finalErrorCode));
if (err.stack) {
logMsg(err.stack);
}
}
_exitCallback(finalErrorCode);
};
@ -281,3 +312,5 @@ Definition of the `main` function.
};
}).call(this);
//# sourceMappingURL=main.js.map

2
dist/cli/msg.js vendored
View File

@ -15,3 +15,5 @@ Message-handling routines for HackMyResume.
module.exports = YAML.load(PATH.join(__dirname, 'msg.yml'));
}).call(this);
//# sourceMappingURL=msg.js.map

15
dist/cli/msg.yml vendored
View File

@ -3,6 +3,8 @@ events:
msg: Invoking **%s** command.
beforeCreate:
msg: Creating new **%s** resume: **%s**
afterCreate:
msg: Creating new **%s** resume: **%s**
afterRead:
msg: Reading **%s** resume: **%s**
beforeTheme:
@ -41,6 +43,8 @@ events:
- "VALID!"
- "INVALID"
- "BROKEN"
- "MISSING"
- "ERROR"
beforePeek:
msg:
- Peeking at **%s** in **%s**
@ -79,7 +83,10 @@ errors:
readError:
msg: Reading **???** resume: **%s**
parseError:
msg: Invalid or corrupt JSON on line %s column %s.
msg:
- Invalid or corrupt JSON on line %s column %s.
- Invalid or corrupt JSON on line %s.
- Invalid or corrupt JSON.
invalidHelperUse:
msg: "**Warning**: Incorrect use of the **%s** theme helper."
fileSaveError:
@ -96,3 +103,9 @@ errors:
msg: "Invalid number of parameters. Expected: **%s**."
missingParam:
msg: The '**%s**' parameter was needed but not supplied.
createError:
msg: Failed to create **'%s'**.
exiting:
msg: Exiting with status code **%s**.
validateError:
msg: "An error occurred during validation:\n%s"

82
dist/cli/out.js vendored
View File

@ -6,17 +6,15 @@ Output routines for HackMyResume.
*/
(function() {
var Class, EXTEND, FS, HANDLEBARS, HME, LO, M2C, OutputHandler, PATH, YAML, _, chalk, dbgStyle, pad, printf;
var EXTEND, FS, HANDLEBARS, HME, LO, M2C, OutputHandler, PATH, YAML, _, chalk, dbgStyle, pad, printf;
chalk = require('chalk');
HME = require('../hmc/dist/core/event-codes');
HME = require('../core/event-codes');
_ = require('underscore');
Class = require('../hmc/dist/utils/class.js');
M2C = require('../hmc/dist/utils/md2chalk.js');
M2C = require('../utils/md2chalk.js');
PATH = require('path');
@ -39,20 +37,27 @@ Output routines for HackMyResume.
/** A stateful output module. All HMR console output handled here. */
OutputHandler = module.exports = Class.extend({
init: function(opts) {
module.exports = OutputHandler = (function() {
function OutputHandler(opts) {
this.init(opts);
return;
}
OutputHandler.prototype.init = function(opts) {
this.opts = EXTEND(true, this.opts || {}, opts);
this.msgs = YAML.load(PATH.join(__dirname, 'msg.yml')).events;
},
log: function(msg) {
};
OutputHandler.prototype.log = function(msg) {
var finished;
msg = msg || '';
printf = require('printf');
finished = printf.apply(printf, arguments);
return this.opts.silent || console.log(finished);
},
"do": function(evt) {
var L, WRAP, info, msg, numFormats, output, rawTpl, sty, style, suffix, template, that, themeName, tot;
};
OutputHandler.prototype["do"] = function(evt) {
var L, WRAP, adj, info, msg, msgs, numFormats, output, rawTpl, sty, style, suffix, template, that, themeName, tot;
that = this;
L = function() {
return that.log.apply(that, arguments);
@ -60,8 +65,8 @@ Output routines for HackMyResume.
switch (evt.sub) {
case HME.begin:
return this.opts.debug && L(M2C(this.msgs.begin.msg, dbgStyle), evt.cmd.toUpperCase());
case HME.beforeCreate:
L(M2C(this.msgs.beforeCreate.msg, 'green'), evt.fmt, evt.file);
case HME.afterCreate:
L(M2C(this.msgs.beforeCreate.msg, evt.isError ? 'red' : 'green'), evt.fmt, evt.file);
break;
case HME.beforeTheme:
return this.opts.debug && L(M2C(this.msgs.beforeTheme.msg, dbgStyle), evt.theme.toUpperCase());
@ -110,7 +115,7 @@ Output routines for HackMyResume.
case HME.afterAnalyze:
info = evt.info;
rawTpl = FS.readFileSync(PATH.join(__dirname, 'analyze.hbs'), 'utf8');
HANDLEBARS.registerHelper(require('../hmc/dist/helpers/console-helpers'));
HANDLEBARS.registerHelper(require('../helpers/console-helpers'));
template = HANDLEBARS.compile(rawTpl, {
strict: false,
assumeObjects: false
@ -127,11 +132,35 @@ Output routines for HackMyResume.
case HME.afterInlineConvert:
return L(M2C(this.msgs.afterInlineConvert.msg, 'gray', 'white.dim'), evt.file, evt.fmt);
case HME.afterValidate:
style = evt.isValid ? 'green' : 'yellow';
L(M2C(this.msgs.afterValidate.msg[0], 'white') + chalk[style].bold(evt.isValid ? this.msgs.afterValidate.msg[1] : this.msgs.afterValidate.msg[2]), evt.file, evt.fmt);
if (evt.errors) {
return _.each(evt.errors, function(err, idx) {
return L(chalk.yellow.bold('--> ') + chalk.yellow(err.field.replace('data.', 'resume.').toUpperCase() + ' ' + err.message));
style = 'red';
adj = '';
msgs = this.msgs.afterValidate.msg;
switch (evt.status) {
case 'valid':
style = 'green';
adj = msgs[1];
break;
case 'invalid':
style = 'yellow';
adj = msgs[2];
break;
case 'broken':
style = 'red';
adj = msgs[3];
break;
case 'missing':
style = 'red';
adj = msgs[4];
break;
case 'unknown':
style = 'red';
adj = msgs[5];
}
evt.schema = evt.schema.replace('jars', 'JSON Resume').toUpperCase();
L(M2C(msgs[0], 'white') + chalk[style].bold(adj), evt.file, evt.schema);
if (evt.violations) {
_.each(evt.violations, function(err, idx) {
L(chalk.yellow.bold('--> ') + chalk.yellow(err.field.replace('data.', 'resume.').toUpperCase() + ' ' + err.message));
}, this);
}
break;
@ -142,16 +171,23 @@ Output routines for HackMyResume.
} else {
L(M2C(this.msgs.beforePeek.msg[1], sty), evt.file);
}
if (evt.target !== void 0) {
if (evt.target !== void 0 && !evt.error) {
return console.dir(evt.target, {
depth: null,
colors: true
});
} else if (!evt.error) {
return L(M2C(this.msgs.afterPeek.msg, 'yellow'), evt.requested, evt.file);
} else if (evt.error) {
return L(chalk.red(evt.error.inner.inner));
}
}
}
});
};
return OutputHandler;
})();
}).call(this);
//# sourceMappingURL=out.js.map

73
dist/core/abstract-resume.js vendored Normal file
View File

@ -0,0 +1,73 @@
/**
Definition of the AbstractResume class.
@license MIT. See LICENSE.md for details.
@module core/abstract-resume
*/
(function() {
var AbstractResume, FluentDate, _, __;
_ = require('underscore');
__ = require('lodash');
FluentDate = require('./fluent-date');
AbstractResume = (function() {
function AbstractResume() {}
/**
Compute the total duration of the work history.
@returns The total duration of the sheet's work history, that is, the number
of years between the start date of the earliest job on the resume and the
*latest end date of all jobs in the work history*. This last condition is for
sheets that have overlapping jobs.
*/
AbstractResume.prototype.duration = function(collKey, startKey, endKey, unit) {
var firstDate, hist, lastDate, new_e;
unit = unit || 'years';
hist = __.get(this, collKey);
if (!hist || !hist.length) {
return 0;
}
new_e = hist.map(function(job) {
var obj;
obj = _.pick(job, [startKey, endKey]);
if (!_.has(obj, endKey)) {
obj[endKey] = 'current';
}
if (obj && (obj[startKey] || obj[endKey])) {
obj = _.pairs(obj);
obj[0][1] = FluentDate.fmt(obj[0][1]);
if (obj.length > 1) {
obj[1][1] = FluentDate.fmt(obj[1][1]);
}
}
return obj;
});
new_e = _.filter(_.flatten(new_e, true), function(v) {
return v && v.length && v[0] && v[0].length;
});
if (!new_e || !new_e.length) {
return 0;
}
new_e = _.sortBy(new_e, function(elem) {
return elem[1].unix();
});
firstDate = _.first(new_e)[1];
lastDate = _.last(new_e)[1];
return lastDate.diff(firstDate, unit);
};
return AbstractResume;
})();
module.exports = AbstractResume;
}).call(this);
//# sourceMappingURL=abstract-resume.js.map

View File

@ -58,3 +58,5 @@ Event code definitions.
];
}).call(this);
//# sourceMappingURL=default-formats.js.map

View File

@ -16,3 +16,5 @@ Event code definitions.
};
}).call(this);
//# sourceMappingURL=default-options.js.map

View File

@ -33,7 +33,12 @@ Event code definitions.
beforeInlineConvert: 22,
afterInlineConvert: 23,
beforeValidate: 24,
afterValidate: 25
afterValidate: 25,
beforeWrite: 26,
afterWrite: 27,
applyTheme: 28
};
}).call(this);
//# sourceMappingURL=event-codes.js.map

View File

@ -10,6 +10,8 @@ The HackMyResume date representation.
moment = require('moment');
require('../utils/string');
/**
Create a FluentDate from a string or Moment date object. There are a few date
@ -33,6 +35,10 @@ The HackMyResume date representation.
this.rep = this.fmt(dt);
}
FluentDate.isCurrent = function(dt) {
return !dt || (String.is(dt) && /^(present|now|current)$/.test(dt));
};
return FluentDate;
})();
@ -54,7 +60,7 @@ The HackMyResume date representation.
module.exports = FluentDate;
FluentDate.fmt = function(dt, throws) {
var defTime, month, mt, parts, ref, temp;
var month, mt, parts, ref, temp;
throws = (throws === void 0 || throws === null) || throws;
if (typeof dt === 'string' || dt instanceof String) {
dt = dt.toLowerCase().trim();
@ -72,33 +78,7 @@ The HackMyResume date representation.
} else if (/^\s*\d{4}\s*$/.test(dt)) {
return moment(dt, 'YYYY');
} else if (/^\s*$/.test(dt)) {
defTime = {
isNull: true,
isBefore: function(other) {
if (other && !other.isNull) {
return true;
} else {
return false;
}
},
isAfter: function(other) {
if (other && !other.isNull) {
return false;
} else {
return false;
}
},
unix: function() {
return 0;
},
format: function() {
return '';
},
diff: function() {
return 0;
}
};
return defTime;
return moment();
} else {
mt = moment(dt);
if (mt.isValid()) {
@ -123,3 +103,5 @@ The HackMyResume date representation.
};
}).call(this);
//# sourceMappingURL=fluent-date.js.map

View File

@ -6,7 +6,9 @@ Definition of the FRESHResume class.
*/
(function() {
var CONVERTER, FS, FreshResume, JRSResume, MD, PATH, XML, _, __, _parseDates, extend, moment, validator;
var AbstractResume, CONVERTER, FS, FluentDate, FreshResume, JRSResume, MD, PATH, XML, _, __, _parseDates, extend, moment, validator,
extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
FS = require('fs');
@ -30,6 +32,10 @@ Definition of the FRESHResume class.
JRSResume = require('./jrs-resume');
FluentDate = require('./fluent-date');
AbstractResume = require('./abstract-resume');
/**
A FRESH resume or CV. FRESH resumes are backed by JSON, and each FreshResume
@ -37,24 +43,21 @@ Definition of the FRESHResume class.
@constructor
*/
FreshResume = (function() {
function FreshResume() {}
FreshResume = (function(superClass) {
extend1(FreshResume, superClass);
/** Initialize the FreshResume from file. */
FreshResume.prototype.open = function(file, opts) {
var raw, ret;
raw = FS.readFileSync(file, 'utf8');
ret = this.parse(raw, opts);
this.imp.file = file;
return ret;
};
function FreshResume() {
return FreshResume.__super__.constructor.apply(this, arguments);
}
/** Initialize the the FreshResume from JSON string data. */
FreshResume.prototype.parse = function(stringData, opts) {
var ref;
this.imp = (ref = this.imp) != null ? ref : {
raw: stringData
};
return this.parseJSON(JSON.parse(stringData), opts);
};
@ -74,7 +77,7 @@ Definition of the FRESHResume class.
*/
FreshResume.prototype.parseJSON = function(rep, opts) {
var ignoreList, scrubbed, that, traverse;
var ignoreList, ref, scrubbed, that, traverse;
that = this;
traverse = require('traverse');
ignoreList = [];
@ -87,12 +90,16 @@ Definition of the FRESHResume class.
}
});
extend(true, this, scrubbed);
if (!this.imp) {
if (!((ref = this.imp) != null ? ref.processed : void 0)) {
opts = opts || {};
if (opts.imp === void 0 || opts.imp) {
this.imp = this.imp || {};
this.imp.title = (opts.title || this.imp.title) || this.name;
if (!this.imp.raw) {
this.imp.raw = JSON.stringify(rep);
}
}
this.imp.processed = true;
(opts.date === void 0 || opts.date) && _parseDates.call(this);
(opts.sort === void 0 || opts.sort) && this.sort();
(opts.compute === void 0 || opts.compute) && (this.computed = {
@ -368,36 +375,8 @@ Definition of the FRESHResume class.
return ret;
};
/**
Calculate the total duration of the sheet. Assumes this.work has been sorted
by start date descending, perhaps via a call to Sheet.sort().
@returns The total duration of the sheet's work history, that is, the number
of years between the start date of the earliest job on the resume and the
*latest end date of all jobs in the work history*. This last condition is for
sheets that have overlapping jobs.
*/
FreshResume.prototype.duration = function(unit) {
var careerLast, careerStart, empHist, firstJob;
unit = unit || 'years';
empHist = __.get(this, 'employment.history');
if (empHist && empHist.length) {
firstJob = _.last(empHist);
careerStart = firstJob.start ? firstJob.safe.start : '';
if ((typeof careerStart === 'string' || careerStart instanceof String) && !careerStart.trim()) {
return 0;
}
careerLast = _.max(empHist, function(w) {
if (w.safe && w.safe.end) {
return w.safe.end.unix();
} else {
return moment().unix();
}
});
return careerLast.safe.end.diff(careerStart, unit);
}
return 0;
return FreshResume.__super__.duration.call(this, 'employment.history', 'start', 'end', unit);
};
@ -412,7 +391,11 @@ Definition of the FRESHResume class.
if (a.safe.start.isBefore(b.safe.start)) {
return 1;
} else {
return (a.safe.start.isAfter(b.safe.start) && -1) || 0;
if (a.safe.start.isAfter(b.safe.start)) {
return -1;
} else {
return 0;
}
}
};
sortSection = function(key) {
@ -440,7 +423,7 @@ Definition of the FRESHResume class.
return FreshResume;
})();
})(AbstractResume);
/**
@ -448,7 +431,7 @@ Definition of the FRESHResume class.
*/
FreshResume["default"] = function() {
return new FreshResume().parseJSON(require('fresh-resume-starter'));
return new FreshResume().parseJSON(require('fresh-resume-starter').fresh);
};
@ -491,7 +474,7 @@ Definition of the FRESHResume class.
return;
}
if (Object.prototype.toString.call(obj) === '[object Array]') {
return obj.forEach(function(elem) {
obj.forEach(function(elem) {
return replaceDatesInObject(elem);
});
} else if (typeof obj === 'object') {
@ -501,19 +484,19 @@ Definition of the FRESHResume class.
Object.keys(obj).forEach(function(key) {
return replaceDatesInObject(obj[key]);
});
return ['start', 'end', 'date'].forEach(function(val) {
['start', 'end', 'date'].forEach(function(val) {
if ((obj[val] !== void 0) && (!obj.safe || !obj.safe[val])) {
obj.safe = obj.safe || {};
obj.safe[val] = _fmt(obj[val]);
if (obj[val] && (val === 'start') && !obj.end) {
return obj.safe.end = _fmt('current');
obj.safe.end = _fmt('current');
}
}
});
}
};
return Object.keys(this).forEach(function(member) {
return replaceDatesInObject(that[member]);
Object.keys(this).forEach(function(member) {
replaceDatesInObject(that[member]);
});
};
@ -523,3 +506,5 @@ Definition of the FRESHResume class.
module.exports = FreshResume;
}).call(this);
//# sourceMappingURL=fresh-resume.js.map

View File

@ -6,7 +6,7 @@ Definition of the FRESHTheme class.
*/
(function() {
var EXTEND, FRESHTheme, FS, HMSTATUS, PATH, READFILES, _, friendlyName, loadExplicit, loadImplicit, loadSafeJson, moment, parsePath, pathExists, validator;
var EXTEND, FRESHTheme, FS, HMSTATUS, PATH, READFILES, _, _load, _loadOne, friendlyName, loadSafeJson, moment, parsePath, pathExists, validator;
FS = require('fs');
@ -31,9 +31,7 @@ Definition of the FRESHTheme class.
READFILES = require('recursive-readdir-sync');
/*
The FRESHTheme class is a representation of a FRESH theme
asset. See also: JRSTheme.
/* A representation of a FRESH theme asset.
@class FRESHTheme
*/
@ -41,9 +39,7 @@ Definition of the FRESHTheme class.
function FRESHTheme() {}
/*
Open and parse the specified theme.
*/
/* Open and parse the specified theme. */
FRESHTheme.prototype.open = function(themeFolder) {
var cached, formatsHash, pathInfo, that, themeFile, themeInfo;
@ -71,12 +67,7 @@ Definition of the FRESHTheme class.
return formatsHash[key] = cached[th].getFormat(key);
});
}
if (!!this.formats) {
formatsHash = loadExplicit.call(this, formatsHash);
this.explicit = true;
} else {
formatsHash = loadImplicit.call(this, formatsHash);
}
formatsHash = _load.call(this, formatsHash);
this.formats = formatsHash;
this.name = parsePath(this.folder).name;
return this;
@ -101,63 +92,17 @@ Definition of the FRESHTheme class.
})();
/* Load the theme implicitly, by scanning the theme folder for files. TODO:
Refactor duplicated code with loadExplicit.
*/
/* Load and parse theme source files. */
loadImplicit = function(formatsHash) {
var fmts, major, that, tplFolder;
_load = function(formatsHash) {
var copyOnly, fmts, major, that, tplFolder;
that = this;
major = false;
tplFolder = PATH.join(this.folder, 'src');
copyOnly = ['.ttf', '.otf', '.png', '.jpg', '.jpeg', '.pdf'];
fmts = READFILES(tplFolder).map(function(absPath) {
var idx, isMajor, obj, outFmt, pathInfo, portion, reg, res;
pathInfo = parsePath(absPath);
outFmt = '';
isMajor = false;
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;
}
formatsHash[outFmt] = formatsHash[outFmt] || {
outFormat: outFmt,
files: []
};
obj = {
action: 'transform',
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;
});
return _loadOne.call(this, absPath, formatsHash, tplFolder);
}, this);
this.cssFiles = fmts.filter(function(fmt) {
return fmt && (fmt.ext === 'css');
});
@ -183,89 +128,93 @@ Definition of the FRESHTheme class.
};
/*
Load the theme explicitly, by following the 'formats' hash
in the theme's JSON settings file.
*/
/* Load a single theme file. */
loadExplicit = function(formatsHash) {
var act, fmts, that, tplFolder;
tplFolder = PATH.join(this.folder, 'src');
act = null;
that = this;
fmts = READFILES(tplFolder).map(function(absPath) {
var absPathSafe, idx, obj, outFmt, pathInfo, portion, reg, res;
act = null;
pathInfo = parsePath(absPath);
absPathSafe = absPath.trim().toLowerCase();
outFmt = _.find(Object.keys(that.formats), function(fmtKey) {
_loadOne = function(absPath, formatsHash, tplFolder) {
var absPathSafe, act, defFormats, idx, isPrimary, obj, outFmt, pathInfo, portion, ref, ref1, reg, res;
pathInfo = parsePath(absPath);
absPathSafe = absPath.trim().toLowerCase();
outFmt = '';
act = 'copy';
isPrimary = false;
if (this.explicit) {
outFmt = _.find(Object.keys(this.formats), function(fmtKey) {
var fmtVal;
fmtVal = that.formats[fmtKey];
fmtVal = this.formats[fmtKey];
return _.some(fmtVal.transform, function(fpath) {
var absPathB;
absPathB = PATH.join(that.folder, fpath).trim().toLowerCase();
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()) {
reg = /^(?:\/|\\)(html|latex|doc|pdf)(?:\/|\\)?/ig;
res = reg.exec(portion);
res && (outFmt = res[1]);
}
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 (!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: [],
symLinks: that.formats[outFmt].symLinks
};
obj = {
action: act,
orgPath: PATH.relative(that.folder, absPath),
path: 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) {
return fmt.ext === 'css';
});
this.cssFiles.forEach(function(cssf) {
var idx;
idx = _.findIndex(fmts, function(fmt) {
return fmt.pre === cssf.pre && fmt.ext === 'html';
defFormats = require('./default-formats');
isPrimary = _.some(defFormats, function(form) {
return form.name === outFmt && pathInfo.extname !== '.css';
});
fmts[idx].css = cssf.data;
return fmts[idx].cssPath = cssf.path;
});
fmts = fmts.filter(function(fmt) {
return fmt.ext !== 'css';
});
return formatsHash;
}
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,
primary: isPrimary,
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.
TODO: Refactor
*/
/* Return a more friendly name for certain formats. */
friendlyName = function(val) {
var friendly;
val = val.trim().toLowerCase();
val = (val && val.trim().toLowerCase()) || '';
friendly = {
yml: 'yaml',
md: 'markdown',
@ -277,3 +226,5 @@ Definition of the FRESHTheme class.
module.exports = FRESHTheme;
}).call(this);
//# sourceMappingURL=fresh-theme.js.map

View File

@ -6,7 +6,9 @@ Definition of the JRSResume class.
*/
(function() {
var CONVERTER, FS, JRSResume, MD, PATH, _, _parseDates, extend, moment, validator;
var AbstractResume, CONVERTER, FS, JRSResume, MD, PATH, _, _parseDates, extend, moment, validator,
extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
FS = require('fs');
@ -24,6 +26,8 @@ Definition of the JRSResume class.
moment = require('moment');
AbstractResume = require('./abstract-resume');
/**
A JRS resume or CV. JRS resumes are backed by JSON, and each JRSResume object
@ -31,32 +35,24 @@ Definition of the JRSResume class.
@class JRSResume
*/
JRSResume = (function() {
var clear, format;
JRSResume = (function(superClass) {
var clear;
function JRSResume() {}
extend1(JRSResume, superClass);
/** Initialize the JSResume from file. */
JRSResume.prototype.open = function(file, title) {
this.basics = {
imp: {
file: file,
raw: FS.readFileSync(file, 'utf8')
}
};
return this.parse(this.basics.imp.raw, title);
};
function JRSResume() {
return JRSResume.__super__.constructor.apply(this, arguments);
}
/** Initialize the the JSResume from string. */
JRSResume.prototype.parse = function(stringData, opts) {
var rep;
opts = opts || {};
rep = JSON.parse(stringData);
return this.parseJSON(rep, opts);
var ref;
this.imp = (ref = this.imp) != null ? ref : {
raw: stringData
};
return this.parseJSON(JSON.parse(stringData), opts);
};
@ -75,7 +71,7 @@ Definition of the JRSResume class.
*/
JRSResume.prototype.parseJSON = function(rep, opts) {
var ignoreList, scrubbed, that, traverse;
var ignoreList, ref, scrubbed, that, traverse;
opts = opts || {};
that = this;
traverse = require('traverse');
@ -89,10 +85,16 @@ Definition of the JRSResume class.
}
});
extend(true, this, scrubbed);
if (opts.imp === void 0 || 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';
if (!((ref = this.imp) != null ? ref.processed : void 0)) {
opts = opts || {};
if (opts.imp === void 0 || opts.imp) {
this.imp = this.imp || {};
this.imp.title = (opts.title || this.imp.title) || this.basics.name;
if (!this.imp.raw) {
this.imp.raw = JSON.stringify(rep);
}
}
this.imp.processed = true;
}
(opts.date === void 0 || opts.date) && _parseDates.call(this);
(opts.sort === void 0 || opts.sort) && this.sort();
@ -109,8 +111,8 @@ Definition of the JRSResume class.
/** Save the sheet to disk (for environments that have disk access). */
JRSResume.prototype.save = function(filename) {
this.basics.imp.file = filename || this.basics.imp.file;
FS.writeFileSync(this.basics.imp.file, this.stringify(this), 'utf8');
this.imp.file = filename || this.imp.file;
FS.writeFileSync(this.imp.file, this.stringify(this), 'utf8');
return this;
};
@ -120,8 +122,8 @@ Definition of the JRSResume class.
JRSResume.prototype.saveAs = function(filename, format) {
var newRep, stringRep;
if (format === 'JRS') {
this.basics.imp.file = filename || this.basics.imp.file;
FS.writeFileSync(this.basics.imp.file, this.stringify(), 'utf8');
this.imp.file = filename || this.imp.file;
FS.writeFileSync(this.imp.file, this.stringify(), 'utf8');
} else {
newRep = CONVERTER.toFRESH(this);
stringRep = CONVERTER.toSTRING(newRep);
@ -133,7 +135,7 @@ Definition of the JRSResume class.
/** Return the resume format. */
format = function() {
JRSResume.prototype.format = function() {
return 'JRS';
};
@ -163,9 +165,8 @@ Definition of the JRSResume class.
*/
JRSResume.prototype.i = function() {
this.basics = this.basics || {};
this.basics.imp = this.basics.imp || {};
return this.basics.imp;
var ref;
return this.imp = (ref = this.imp) != null ? ref : {};
};
@ -225,7 +226,7 @@ Definition of the JRSResume class.
/** Validate the sheet against the JSON Resume schema. */
JRSResume.prototype.isValid = function() {
var ret, schema, schemaObj, validate;
var ret, schema, schemaObj, temp, validate;
schema = FS.readFileSync(PATH.join(__dirname, 'resume.json'), 'utf8');
schemaObj = JSON.parse(schema);
validator = require('is-my-json-valid');
@ -234,38 +235,19 @@ Definition of the JRSResume class.
date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/
}
});
temp = this.imp;
delete this.imp;
ret = validate(this);
this.imp = temp;
if (!ret) {
this.basics.imp = this.basics.imp || {};
this.basics.imp.validationErrors = validate.errors;
this.imp = this.imp || {};
this.imp.validationErrors = validate.errors;
}
return ret;
};
/**
Calculate the total duration of the sheet. Assumes this.work has been sorted
by start date descending, perhaps via a call to Sheet.sort().
@returns The total duration of the sheet's work history, that is, the number
of years between the start date of the earliest job on the resume and the
*latest end date of all jobs in the work history*. This last condition is for
sheets that have overlapping jobs.
*/
JRSResume.prototype.duration = function(unit) {
var careerLast, careerStart;
unit = unit || 'years';
if (this.work && this.work.length) {
careerStart = this.work[this.work.length - 1].safeStartDate;
if ((typeof careerStart === 'string' || careerStart instanceof String) && !careerStart.trim()) {
return 0;
}
careerLast = _.max(this.work, function(w) {
return w.safeEndDate.unix();
}).safeEndDate;
return careerLast.diff(careerStart, unit);
}
return 0;
return JRSResume.__super__.duration.call(this, 'work', 'startDate', 'endDate', unit);
};
@ -365,13 +347,13 @@ Definition of the JRSResume class.
return JRSResume;
})();
})(AbstractResume);
/** Get the default (empty) sheet. */
JRSResume["default"] = function() {
return new JRSResume().open(PATH.join(__dirname, 'empty-jrs.json'), 'Empty');
return new JRSResume().parseJSON(require('fresh-resume-starter').jrs);
};
@ -436,3 +418,5 @@ Definition of the JRSResume class.
module.exports = JRSResume;
}).call(this);
//# sourceMappingURL=jrs-resume.js.map

View File

@ -6,7 +6,7 @@ Definition of the JRSTheme class.
*/
(function() {
var JRSTheme, PATH, _, getFormat, parsePath, pathExists;
var JRSTheme, PATH, _, parsePath, pathExists;
_ = require('underscore');
@ -25,17 +25,13 @@ Definition of the JRSTheme class.
JRSTheme = (function() {
function JRSTheme() {}
return JRSTheme;
})();
({
/**
Open and parse the specified theme.
@method open
*/
open: function(thFolder) {
JRSTheme.prototype.open = function(thFolder) {
var pathInfo, pkgJsonPath, thApi, thPkg;
this.folder = thFolder;
pathInfo = parsePath(thFolder);
@ -53,7 +49,7 @@ Definition of the JRSTheme class.
{
action: 'transform',
render: this.render,
major: true,
primary: true,
ext: 'html',
css: null
}
@ -65,7 +61,7 @@ Definition of the JRSTheme class.
{
action: 'transform',
render: this.render,
major: true,
primary: true,
ext: 'pdf',
css: null
}
@ -78,26 +74,34 @@ Definition of the JRSTheme class.
};
}
return this;
},
};
/**
Determine if the theme supports the output format.
@method hasFormat
*/
hasFormat: function(fmt) {
JRSTheme.prototype.hasFormat = function(fmt) {
return _.has(this.formats, fmt);
}
};
/**
Return the requested output format.
@method getFormat
*/
});
getFormat = function(fmt) {
return this.formats[fmt];
};
JRSTheme.prototype.getFormat = function(fmt) {
return this.formats[fmt];
};
return JRSTheme;
})();
module.exports = JRSTheme;
}).call(this);
//# sourceMappingURL=jrs-theme.js.map

View File

@ -83,7 +83,7 @@ Definition of the ResumeFactory class.
};
_parse = function(fileName, opts, eve) {
var ex, orgFormat, rawData, ret;
var orgFormat, rawData, ret;
rawData = null;
try {
eve && eve.stat(HME.beforeRead, {
@ -108,20 +108,15 @@ Definition of the ResumeFactory class.
});
return ret;
} catch (_error) {
ex = {
return {
fluenterror: rawData ? HACKMYSTATUS.parseError : HACKMYSTATUS.readError,
inner: _error,
raw: rawData,
file: fileName,
shouldExit: false
file: fileName
};
opts.quit && (ex.quit = true);
eve && eve.err(ex.fluenterror, ex);
if (opts["throw"]) {
throw ex;
}
return ex;
}
};
}).call(this);
//# sourceMappingURL=resume-factory.js.map

View File

@ -16,7 +16,7 @@ Status codes for HackMyResume.
resumeNotFoundAlt: 6,
inputOutputParity: 7,
createNameMissing: 8,
pdfgeneration: 9,
pdfGeneration: 9,
missingPackageJSON: 10,
invalid: 11,
invalidFormat: 12,
@ -31,7 +31,11 @@ Status codes for HackMyResume.
compileTemplate: 21,
themeLoad: 22,
invalidParamCount: 23,
missingParam: 24
missingParam: 24,
createError: 25,
validateError: 26
};
}).call(this);
//# sourceMappingURL=status-codes.js.map

40
dist/generators/base-generator.js vendored Normal file
View File

@ -0,0 +1,40 @@
/**
Definition of the BaseGenerator class.
@module generators/base-generator
@license MIT. See LICENSE.md for details.
*/
/**
The BaseGenerator class is the root of the generator hierarchy. Functionality
common to ALL generators lives here.
*/
(function() {
var BaseGenerator;
module.exports = BaseGenerator = (function() {
/** Base-class initialize. */
function BaseGenerator(format) {
this.format = format;
}
/** Status codes. */
BaseGenerator.prototype.codes = require('../core/status-codes');
/** Generator options. */
BaseGenerator.prototype.opts = {};
return BaseGenerator;
})();
}).call(this);
//# sourceMappingURL=base-generator.js.map

53
dist/generators/html-generator.js vendored Normal file
View File

@ -0,0 +1,53 @@
/**
Definition of the HTMLGenerator class.
@module generators/html-generator
@license MIT. See LICENSE.md for details.
*/
(function() {
var FS, HTML, HtmlGenerator, PATH, TemplateGenerator,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
TemplateGenerator = require('./template-generator');
FS = require('fs-extra');
HTML = require('html');
PATH = require('path');
require('string.prototype.endswith');
module.exports = HtmlGenerator = (function(superClass) {
extend(HtmlGenerator, superClass);
function HtmlGenerator() {
HtmlGenerator.__super__.constructor.call(this, 'html');
}
/**
Copy satellite CSS files to the destination and optionally pretty-print
the HTML resume prior to saving.
*/
HtmlGenerator.prototype.onBeforeSave = function(info) {
if (info.outputFile.endsWith('.css')) {
return info.mk;
}
if (this.opts.prettify) {
return HTML.prettyPrint(info.mk, this.opts.prettify);
} else {
return info.mk;
}
};
return HtmlGenerator;
})(TemplateGenerator);
}).call(this);
//# sourceMappingURL=html-generator.js.map

View File

@ -0,0 +1,117 @@
/**
Definition of the HtmlPdfCLIGenerator class.
@module generators/html-pdf-generator.js
@license MIT. See LICENSE.md for details.
*/
(function() {
var FS, HMSTATUS, HtmlPdfCLIGenerator, PATH, SLASH, SPAWN, TemplateGenerator, _, engines,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
TemplateGenerator = require('./template-generator');
FS = require('fs-extra');
PATH = require('path');
SLASH = require('slash');
_ = require('underscore');
HMSTATUS = require('../core/status-codes');
SPAWN = require('../utils/safe-spawn');
/**
An HTML-driven PDF resume generator for HackMyResume. Talks to Phantom,
wkhtmltopdf, and other PDF engines over a CLI (command-line interface).
If an engine isn't installed for a particular platform, error out gracefully.
*/
module.exports = HtmlPdfCLIGenerator = (function(superClass) {
extend(HtmlPdfCLIGenerator, superClass);
function HtmlPdfCLIGenerator() {
HtmlPdfCLIGenerator.__super__.constructor.call(this, 'pdf', 'html');
}
/** Generate the binary PDF. */
HtmlPdfCLIGenerator.prototype.onBeforeSave = function(info) {
var safe_eng;
if (info.ext !== 'html' && info.ext !== 'pdf') {
return info.mk;
}
safe_eng = info.opts.pdf || 'wkhtmltopdf';
if (safe_eng === 'phantom') {
safe_eng = 'phantomjs';
}
if (_.has(engines, safe_eng)) {
this.errHandler = info.opts.errHandler;
engines[safe_eng].call(this, info.mk, info.outputFile, this.onError);
return null;
}
};
/* Low-level error callback for spawn(). May be called after HMR process
termination, so object references may not be valid here. That's okay; if
the references are invalid, the error was already logged. We could use
spawn-watch here but that causes issues on legacy Node.js.
*/
HtmlPdfCLIGenerator.prototype.onError = function(ex, param) {
var ref;
if ((ref = param.errHandler) != null) {
if (typeof ref.err === "function") {
ref.err(HMSTATUS.pdfGeneration, ex);
}
}
};
return HtmlPdfCLIGenerator;
})(TemplateGenerator);
engines = {
/**
Generate a PDF from HTML using wkhtmltopdf's CLI interface.
Spawns a child process with `wkhtmltopdf <source> <target>`. wkhtmltopdf
must be installed and path-accessible.
TODO: If HTML generation has run, reuse that output
TODO: Local web server to ease wkhtmltopdf rendering
*/
wkhtmltopdf: function(markup, fOut, on_error) {
var tempFile;
tempFile = fOut.replace(/\.pdf$/i, '.pdf.html');
FS.writeFileSync(tempFile, markup, 'utf8');
SPAWN('wkhtmltopdf', [tempFile, fOut], false, on_error, this);
},
/**
Generate a PDF from HTML using Phantom's CLI interface.
Spawns a child process with `phantomjs <script> <source> <target>`. Phantom
must be installed and path-accessible.
TODO: If HTML generation has run, reuse that output
TODO: Local web server to ease Phantom rendering
*/
phantomjs: function(markup, fOut, on_error) {
var destPath, scriptPath, sourcePath, tempFile;
tempFile = fOut.replace(/\.pdf$/i, '.pdf.html');
FS.writeFileSync(tempFile, markup, 'utf8');
scriptPath = PATH.relative(process.cwd(), PATH.resolve(__dirname, '../utils/rasterize.js'));
scriptPath = SLASH(scriptPath);
sourcePath = SLASH(PATH.relative(process.cwd(), tempFile));
destPath = SLASH(PATH.relative(process.cwd(), fOut));
SPAWN('phantomjs', [scriptPath, sourcePath, destPath], false, on_error, this);
}
};
}).call(this);
//# sourceMappingURL=html-pdf-cli-generator.js.map

View File

@ -1,12 +1,14 @@
/**
Definition of the HtmlPngGenerator class.
@module generators/html-png-generator
@license MIT. See LICENSE.MD for details.
@module html-png-generator.js
*/
(function() {
var FS, HTML, HtmlPngGenerator, PATH, SLASH, SPAWN, TemplateGenerator, phantom;
var FS, HTML, HtmlPngGenerator, PATH, SLASH, SPAWN, TemplateGenerator, phantom,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
TemplateGenerator = require('./template-generator');
@ -25,12 +27,16 @@ Definition of the HtmlPngGenerator class.
An HTML-based PNG resume generator for HackMyResume.
*/
HtmlPngGenerator = module.exports = TemplateGenerator.extend({
init: function() {
return this._super('png', 'html');
},
invoke: function(rez, themeMarkup, cssInfo, opts) {},
generate: function(rez, f, opts) {
module.exports = HtmlPngGenerator = (function(superClass) {
extend(HtmlPngGenerator, superClass);
function HtmlPngGenerator() {
HtmlPngGenerator.__super__.constructor.call(this, 'png', 'html');
}
HtmlPngGenerator.prototype.invoke = function(rez, themeMarkup, cssInfo, opts) {};
HtmlPngGenerator.prototype.generate = function(rez, f, opts) {
var htmlFile, htmlResults;
htmlResults = opts.targets.filter(function(t) {
return t.fmt.outFormat === 'html';
@ -39,8 +45,11 @@ Definition of the HtmlPngGenerator class.
return fl.info.ext === 'html';
});
phantom(htmlFile[0].data, f);
}
});
};
return HtmlPngGenerator;
})(TemplateGenerator);
/**
@ -62,3 +71,5 @@ Definition of the HtmlPngGenerator class.
};
}).call(this);
//# sourceMappingURL=html-png-generator.js.map

47
dist/generators/json-generator.js vendored Normal file
View File

@ -0,0 +1,47 @@
/**
Definition of the JsonGenerator class.
@module generators/json-generator
@license MIT. See LICENSE.md for details.
*/
(function() {
var BaseGenerator, FJCV, FS, JsonGenerator, _,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
BaseGenerator = require('./base-generator');
FS = require('fs');
_ = require('underscore');
FJCV = require('fresh-jrs-converter');
/** The JsonGenerator generates a FRESH or JRS resume as an output. */
module.exports = JsonGenerator = (function(superClass) {
extend(JsonGenerator, superClass);
function JsonGenerator() {
JsonGenerator.__super__.constructor.call(this, 'json');
}
JsonGenerator.prototype.invoke = function(rez) {
var altRez;
altRez = FJCV['to' + (rez.format() === 'FRESH' ? 'JRS' : 'FRESH')](rez);
return altRez = FJCV.toSTRING(altRez);
};
JsonGenerator.prototype.generate = function(rez, f) {
FS.writeFileSync(f, this.invoke(rez), 'utf8');
};
return JsonGenerator;
})(BaseGenerator);
}).call(this);
//# sourceMappingURL=json-generator.js.map

50
dist/generators/json-yaml-generator.js vendored Normal file
View File

@ -0,0 +1,50 @@
/**
Definition of the JsonYamlGenerator class.
@module generators/json-yaml-generator
@license MIT. See LICENSE.md for details.
*/
(function() {
var BaseGenerator, FS, JsonYamlGenerator, YAML,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
BaseGenerator = require('./base-generator');
FS = require('fs');
YAML = require('yamljs');
/**
JsonYamlGenerator takes a JSON resume object and translates it directly to
JSON without a template, producing an equivalent YAML-formatted resume. See
also YamlGenerator (yaml-generator.js).
*/
module.exports = JsonYamlGenerator = (function(superClass) {
extend(JsonYamlGenerator, superClass);
function JsonYamlGenerator() {
JsonYamlGenerator.__super__.constructor.call(this, 'yml');
}
JsonYamlGenerator.prototype.invoke = function(rez, themeMarkup, cssInfo, opts) {
return YAML.stringify(JSON.parse(rez.stringify()), Infinity, 2);
};
JsonYamlGenerator.prototype.generate = function(rez, f, opts) {
var data;
data = YAML.stringify(JSON.parse(rez.stringify()), Infinity, 2);
FS.writeFileSync(f, data, 'utf8');
return data;
};
return JsonYamlGenerator;
})(BaseGenerator);
}).call(this);
//# sourceMappingURL=json-yaml-generator.js.map

33
dist/generators/latex-generator.js vendored Normal file
View File

@ -0,0 +1,33 @@
/**
Definition of the LaTeXGenerator class.
@module generators/latex-generator
@license MIT. See LICENSE.md for details.
*/
(function() {
var LaTeXGenerator, TemplateGenerator,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
TemplateGenerator = require('./template-generator');
/**
LaTeXGenerator generates a LaTeX resume via TemplateGenerator.
*/
module.exports = LaTeXGenerator = (function(superClass) {
extend(LaTeXGenerator, superClass);
function LaTeXGenerator() {
LaTeXGenerator.__super__.constructor.call(this, 'latex', 'tex');
}
return LaTeXGenerator;
})(TemplateGenerator);
}).call(this);
//# sourceMappingURL=latex-generator.js.map

33
dist/generators/markdown-generator.js vendored Normal file
View File

@ -0,0 +1,33 @@
/**
Definition of the MarkdownGenerator class.
@module generators/markdown-generator
@license MIT. See LICENSE.md for details.
*/
(function() {
var MarkdownGenerator, TemplateGenerator,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
TemplateGenerator = require('./template-generator');
/**
MarkdownGenerator generates a Markdown-formatted resume via TemplateGenerator.
*/
module.exports = MarkdownGenerator = (function(superClass) {
extend(MarkdownGenerator, superClass);
function MarkdownGenerator() {
MarkdownGenerator.__super__.constructor.call(this, 'md', 'txt');
}
return MarkdownGenerator;
})(TemplateGenerator);
}).call(this);
//# sourceMappingURL=markdown-generator.js.map

View File

@ -1,12 +1,14 @@
/**
Definition of the TemplateGenerator class. TODO: Refactor
@module generators/template-generator
@license MIT. See LICENSE.md for details.
@module template-generator.js
*/
(function() {
var BaseGenerator, EXTEND, FRESHTheme, FS, JRSTheme, MD, MKDIRP, PATH, TemplateGenerator, XML, _, _defaultOpts, _reg, freeze, parsePath, unfreeze;
var BaseGenerator, EXTEND, FRESHTheme, FS, JRSTheme, MD, MKDIRP, PATH, TemplateGenerator, XML, _, _defaultOpts, _reg, createSymLinks, freeze, parsePath, unfreeze,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
FS = require('fs-extra');
@ -38,16 +40,21 @@ Definition of the TemplateGenerator class. TODO: Refactor
@class TemplateGenerator
*/
TemplateGenerator = module.exports = BaseGenerator.extend({
module.exports = TemplateGenerator = (function(superClass) {
extend(TemplateGenerator, superClass);
/** Constructor. Set the output format and template format for this
generator. Will usually be called by a derived generator such as
HTMLGenerator or MarkdownGenerator.
*/
init: function(outputFormat, templateFormat, cssFile) {
this._super(outputFormat);
function TemplateGenerator(outputFormat, templateFormat, cssFile) {
TemplateGenerator.__super__.constructor.call(this, outputFormat);
this.tplFormat = templateFormat || outputFormat;
},
return;
}
/** Generate a resume using string-based inputs and outputs without touching
the filesystem.
@ -57,7 +64,8 @@ Definition of the TemplateGenerator class. TODO: Refactor
@returns {Array} An array of objects representing the generated output
files.
*/
invoke: function(rez, opts) {
TemplateGenerator.prototype.invoke = function(rez, opts) {
var curFmt, results;
opts = opts ? (this.opts = EXTEND(true, {}, _defaultOpts, opts)) : this.opts;
curFmt = opts.themeObj.getFormat(this.format);
@ -66,11 +74,18 @@ Definition of the TemplateGenerator class. TODO: Refactor
});
results = curFmt.files.map(function(tplInfo, idx) {
var trx;
trx = this.single(rez, tplInfo.data, this.format, opts, opts.themeObj, curFmt);
if (tplInfo.ext === 'css') {
curFmt.files[idx].data = trx;
if (tplInfo.action === 'transform') {
trx = this.transform(rez, tplInfo.data, this.format, opts, opts.themeObj, curFmt);
if (tplInfo.ext === 'css') {
curFmt.files[idx].data = trx;
} else {
tplInfo.ext === 'html';
}
} else {
tplInfo.ext === 'html';
}
if (typeof opts.onTransform === "function") {
opts.onTransform(tplInfo);
}
return {
info: tplInfo,
@ -80,7 +95,8 @@ Definition of the TemplateGenerator class. TODO: Refactor
return {
files: results
};
},
};
/** Generate a resume using file-based inputs and outputs. Requires access
to the local filesystem.
@ -89,33 +105,44 @@ Definition of the TemplateGenerator class. TODO: Refactor
@param f Full path to the output resume file to generate.
@param opts Generator options.
*/
generate: function(rez, f, opts) {
TemplateGenerator.prototype.generate = function(rez, f, opts) {
var curFmt, genInfo, outFolder;
this.opts = EXTEND(true, {}, _defaultOpts, opts);
genInfo = this.invoke(rez, null);
outFolder = parsePath(f).dirname;
curFmt = opts.themeObj.getFormat(this.format);
genInfo.files.forEach(function(file) {
var fileName, thisFilePath;
var thisFilePath;
file.info.orgPath = file.info.orgPath || '';
thisFilePath = PATH.join(outFolder, file.info.orgPath);
if (this.onBeforeSave) {
thisFilePath = file.info.primary ? f : PATH.join(outFolder, file.info.orgPath);
if (file.info.action !== 'copy' && this.onBeforeSave) {
file.data = this.onBeforeSave({
theme: opts.themeObj,
outputFile: file.info.major ? f : thisFilePath,
outputFile: thisFilePath,
mk: file.data,
opts: this.opts
opts: this.opts,
ext: file.info.ext
});
if (!file.data) {
return;
}
}
fileName = file.info.major ? f : thisFilePath;
MKDIRP.sync(PATH.dirname(fileName));
FS.writeFileSync(fileName, file.data, {
encoding: 'utf8',
flags: 'w'
});
if (typeof opts.beforeWrite === "function") {
opts.beforeWrite(thisFilePath);
}
MKDIRP.sync(PATH.dirname(thisFilePath));
if (file.info.action !== 'copy') {
FS.writeFileSync(thisFilePath, file.data, {
encoding: 'utf8',
flags: 'w'
});
} else {
FS.copySync(file.info.path, thisFilePath);
}
if (typeof opts.afterWrite === "function") {
opts.afterWrite(thisFilePath);
}
if (this.onAfterSave) {
return this.onAfterSave({
outputFile: fileName,
@ -124,19 +151,10 @@ Definition of the TemplateGenerator class. TODO: Refactor
});
}
}, this);
if (curFmt.symLinks) {
Object.keys(curFmt.symLinks).forEach(function(loc) {
var absLoc, absTarg, ref, type;
absLoc = PATH.join(outFolder, loc);
absTarg = PATH.join(PATH.dirname(absLoc), curFmt.symLinks[loc]);
type = (ref = parsePath(absLoc).extname) != null ? ref : {
'file': 'junction'
};
return FS.symlinkSync(absTarg, absLoc, type);
});
}
createSymLinks(curFmt, outFolder);
return genInfo;
},
};
/** Perform a single resume resume transformation using string-based inputs
and outputs without touching the local file system.
@ -146,7 +164,8 @@ Definition of the TemplateGenerator class. TODO: Refactor
@param cssInfo Needs to be refactored.
@param opts Options and passthrough data.
*/
single: function(json, jst, format, opts, theme, curFmt) {
TemplateGenerator.prototype.transform = function(json, jst, format, opts, theme, curFmt) {
var eng, result;
if (this.opts.freezeBreaks) {
jst = freeze(jst);
@ -157,13 +176,37 @@ Definition of the TemplateGenerator class. TODO: Refactor
result = unfreeze(result);
}
return result;
};
return TemplateGenerator;
})(BaseGenerator);
createSymLinks = function(curFmt, outFolder) {
if (curFmt.symLinks) {
Object.keys(curFmt.symLinks).forEach(function(loc) {
var absLoc, absTarg, succeeded, type;
absLoc = PATH.join(outFolder, loc);
absTarg = PATH.join(PATH.dirname(absLoc), curFmt.symLinks[loc]);
type = parsePath(absLoc).extname ? 'file' : 'junction';
try {
return FS.symlinkSync(absTarg, absLoc, type);
} catch (_error) {
succeeded = false;
if (_error.code === 'EEXIST') {
FS.unlinkSync(absLoc);
try {
FS.symlinkSync(absTarg, absLoc, type);
succeeded = true;
} catch (_error) {}
}
if (!succeeded) {
throw ex;
}
}
});
}
});
/** Export the TemplateGenerator function/ctor. */
module.exports = TemplateGenerator;
};
/** Freeze newlines for protection against errant JST parsers. */
@ -241,3 +284,5 @@ Definition of the TemplateGenerator class. TODO: Refactor
};
}).call(this);
//# sourceMappingURL=template-generator.js.map

33
dist/generators/text-generator.js vendored Normal file
View File

@ -0,0 +1,33 @@
/**
Definition of the TextGenerator class.
@module generators/text-generator
@license MIT. See LICENSE.md for details.
*/
(function() {
var TemplateGenerator, TextGenerator,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
TemplateGenerator = require('./template-generator');
/**
The TextGenerator generates a plain-text resume via the TemplateGenerator.
*/
module.exports = TextGenerator = (function(superClass) {
extend(TextGenerator, superClass);
function TextGenerator() {
TextGenerator.__super__.constructor.call(this, 'txt');
}
return TextGenerator;
})(TemplateGenerator);
}).call(this);
//# sourceMappingURL=text-generator.js.map

28
dist/generators/word-generator.js vendored Normal file
View File

@ -0,0 +1,28 @@
/*
Definition of the WordGenerator class.
@module generators/word-generator
@license MIT. See LICENSE.md for details.
*/
(function() {
var TemplateGenerator, WordGenerator,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
TemplateGenerator = require('./template-generator');
module.exports = WordGenerator = (function(superClass) {
extend(WordGenerator, superClass);
function WordGenerator() {
WordGenerator.__super__.constructor.call(this, 'doc', 'xml');
}
return WordGenerator;
})(TemplateGenerator);
}).call(this);
//# sourceMappingURL=word-generator.js.map

31
dist/generators/xml-generator.js vendored Normal file
View File

@ -0,0 +1,31 @@
/**
Definition of the XMLGenerator class.
@license MIT. See LICENSE.md for details.
@module generatprs/xml-generator
*/
(function() {
var BaseGenerator, XMLGenerator,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
BaseGenerator = require('./base-generator');
/** The XmlGenerator generates an XML resume via the TemplateGenerator. */
module.exports = XMLGenerator = (function(superClass) {
extend(XMLGenerator, superClass);
function XMLGenerator() {
XMLGenerator.__super__.constructor.call(this, 'xml');
}
return XMLGenerator;
})(BaseGenerator);
}).call(this);
//# sourceMappingURL=xml-generator.js.map

33
dist/generators/yaml-generator.js vendored Normal file
View File

@ -0,0 +1,33 @@
/**
Definition of the YAMLGenerator class.
@module yaml-generator.js
@license MIT. See LICENSE.md for details.
*/
(function() {
var TemplateGenerator, YAMLGenerator,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
TemplateGenerator = require('./template-generator');
/**
YamlGenerator generates a YAML-formatted resume via TemplateGenerator.
*/
module.exports = YAMLGenerator = (function(superClass) {
extend(YAMLGenerator, superClass);
function YAMLGenerator() {
YAMLGenerator.__super__.constructor.call(this, 'yml', 'yml');
}
return YAMLGenerator;
})(TemplateGenerator);
}).call(this);
//# sourceMappingURL=yaml-generator.js.map

71
dist/helpers/block-helpers.js vendored Normal file
View File

@ -0,0 +1,71 @@
/**
Block helper definitions for HackMyResume / FluentCV.
@license MIT. See LICENSE.md for details.
@module helpers/generic-helpers
*/
(function() {
var BlockHelpers, HMSTATUS, LO, _, unused;
HMSTATUS = require('../core/status-codes');
LO = require('lodash');
_ = require('underscore');
unused = require('../utils/string');
/** Block helper function definitions. */
BlockHelpers = module.exports = {
/**
Emit the enclosed content if the resume has a section with
the specified name. Otherwise, emit an empty string ''.
*/
section: function(title, options) {
var obj, ret;
title = title.trim().toLowerCase();
obj = LO.get(this.r, title);
ret = '';
if (obj) {
if (_.isArray(obj)) {
if (obj.length) {
ret = options.fn(this);
}
} else if (_.isObject(obj)) {
if ((obj.history && obj.history.length) || (obj.sets && obj.sets.length)) {
ret = options.fn(this);
}
}
}
return ret;
},
/**
Emit the enclosed content if the resume has the named
property or subproperty.
*/
has: function(title, options) {
title = title && title.trim().toLowerCase();
if (LO.get(this.r, title)) {
return options.fn(this);
}
},
/**
Return true if either value is truthy.
@method either
*/
either: function(lhs, rhs, options) {
if (lhs || rhs) {
return options.fn(this);
}
}
};
}).call(this);
//# sourceMappingURL=block-helpers.js.map

View File

@ -62,3 +62,5 @@ Generic template helper definitions for command-line output.
};
}).call(this);
//# sourceMappingURL=console-helpers.js.map

View File

@ -38,36 +38,85 @@ Generic template helper definitions for HackMyResume / FluentCV.
GenericHelpers = module.exports = {
/**
Convert the input date to a specified format through Moment.js.
If date is invalid, will return the time provided by the user,
or default to the fallback param or 'Present' if that is set to true
@method formatDate
Emit a formatted string representing the specified datetime.
Convert the input date to the specified format through Moment.js. If date is
valid, return the formatted date string. If date is null, undefined, or other
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.
@param {string|Moment} datetime A date value.
@param {string} [dtFormat='YYYY-MM'] The desired datetime format. Must be a
Moment.js-compatible datetime format.
@param {string|Moment} fallback A fallback value to use if the specified date
is null, undefined, or falsy.
*/
formatDate: function(datetime, format, fallback) {
var momentDate, ref, ref1;
if (moment) {
formatDate: function(datetime, dtFormat, fallback) {
var momentDate;
if (datetime == null) {
datetime = void 0;
}
if (dtFormat == null) {
dtFormat = 'YYYY-MM';
}
if (datetime && moment.isMoment(datetime)) {
return datetime.format(dtFormat);
}
if (String.is(datetime)) {
momentDate = moment(datetime, dtFormat);
if (momentDate.isValid()) {
return momentDate.format(dtFormat);
}
momentDate = moment(datetime);
if (momentDate.isValid()) {
return momentDate.format(format);
return momentDate.format(dtFormat);
}
}
return datetime || ((ref = typeof fallback === 'string') != null ? ref : {
fallback: (ref1 = fallback === true) != null ? ref1 : {
'Present': null
}
});
return datetime || (typeof fallback === 'string' ? fallback : (fallback === true ? 'Present' : ''));
},
/**
Emit a formatted string representing the specified datetime.
@param {string} dateValue A raw date value from the FRESH or JRS resume.
@param {string} [dateFormat='YYYY-MM'] The desired datetime format. Must be
compatible with Moment.js datetime formats.
@param {string} [dateDefault=null] The default date value to use if the dateValue
parameter is null, undefined, or falsy.
*/
date: function(dateValue, dateFormat, dateDefault) {
var dateValueMoment, dateValueSafe, reserved;
if (!dateDefault || !String.is(dateDefault)) {
dateDefault = 'Current';
}
if (!dateFormat || !String.is(dateFormat)) {
dateFormat = 'YYYY-MM';
}
if (!dateValue || !String.is(dateValue)) {
dateValue = null;
}
if (!dateValue) {
return dateDefault;
}
reserved = ['current', 'present', 'now'];
dateValueSafe = dateValue.trim().toLowerCase();
if (_.contains(reserved, dateValueSafe)) {
return dateValue;
}
dateValueMoment = moment(dateValue, dateFormat);
if (dateValueMoment.isValid()) {
return dateValueMoment.format(dateFormat);
}
return dateValue;
},
/**
Given a resume sub-object with a start/end date, format a representation of
the date range.
@method dateRange
*/
dateRange: function(obj, fmt, sep, fallback, options) {
dateRange: function(obj, fmt, sep, fallback) {
if (!obj) {
return '';
}
return _fromTo(obj.start, obj.end, fmt, sep, fallback, options);
return _fromTo(obj.start, obj.end, fmt, sep, fallback);
},
/**
@ -102,26 +151,6 @@ Generic template helper definitions for HackMyResume / FluentCV.
}
},
/**
Return true if the section is present on the resume and has at least one
element.
@method section
*/
section: function(title, options) {
var obj;
title = title.trim().toLowerCase();
obj = LO.get(this.r, title);
if (_.isArray(obj)) {
if (obj.length) {
return options.fn(this);
} else {
return void 0;
}
} else if (_.isObject(obj)) {
return (obj.history && obj.history.length) || (obj.sets && obj.sets.length ? options.fn(this) : void 0);
}
},
/**
Emit the size of the specified named font.
@param key {String} A named style from the "fonts" section of the theme's
@ -279,7 +308,7 @@ Generic template helper definitions for HackMyResume / FluentCV.
},
/**
Capitalize the first letter of the word.
Capitalize the first letter of the word. TODO: Rename
@method section
*/
camelCase: function(val) {
@ -292,20 +321,8 @@ Generic template helper definitions for HackMyResume / FluentCV.
},
/**
Return true if the context has the property or subpropery.
@method has
*/
has: function(title, options) {
title = title && title.trim().toLowerCase();
if (LO.get(this.r, title)) {
return options.fn(this);
}
},
/**
Generic template helper function to display a user-overridable section
title for a FRESH resume theme. Use this in lieue of hard-coding section
titles.
Display a user-overridable section title for a FRESH resume theme. Use this in
lieue of hard-coding section titles.
Usage:
@ -328,10 +345,7 @@ Generic template helper definitions for HackMyResume / FluentCV.
return (this.opts.stitles && this.opts.stitles[sname.toLowerCase().trim()]) || stitle;
},
/**
Convert inline Markdown to inline WordProcessingML.
@method wpml
*/
/** Convert inline Markdown to inline WordProcessingML. */
wpml: function(txt, inline) {
if (!txt) {
return '';
@ -440,16 +454,6 @@ Generic template helper definitions for HackMyResume / FluentCV.
}
},
/**
Return true if either value is truthy.
@method either
*/
either: function(lhs, rhs, options) {
if (lhs || rhs) {
return options.fn(this);
}
},
/**
Conditional stylesheet link. Creates a link to the specified stylesheet with
<link> or embeds the styles inline with <style></style>, depending on the
@ -484,7 +488,7 @@ Generic template helper definitions for HackMyResume / FluentCV.
compare: function(lvalue, rvalue, options) {
var operator, operators, result;
if (arguments.length < 3) {
throw new Error("Handlerbars Helper 'compare' needs 2 parameters");
throw new Error("Template helper 'compare' needs 2 parameters");
}
operator = options.hash.operator || "==";
operators = {
@ -514,7 +518,7 @@ Generic template helper definitions for HackMyResume / FluentCV.
}
};
if (!operators[operator]) {
throw new Error("Handlerbars Helper 'compare' doesn't know the operator " + operator);
throw new Error("Helper 'compare' doesn't know the operator " + operator);
}
result = operators[operator](lvalue, rvalue);
if (result) {
@ -522,6 +526,21 @@ Generic template helper definitions for HackMyResume / FluentCV.
} else {
return options.inverse(this);
}
},
pad: function(stringOrArray, padAmount, unused) {
var PAD, ret;
stringOrArray = stringOrArray || '';
padAmount = padAmount || 0;
ret = '';
PAD = require('string-padding');
if (!String.is(stringOrArray)) {
ret = stringOrArray.map(function(line) {
return PAD(line, line.length + Math.abs(padAmount), null, padAmount < 0 ? PAD.LEFT : PAD.RIGHT);
}).join('\n');
} else {
ret = PAD(stringOrArray, stringOrArray.length + Math.abs(padAmount), null, padAmount < 0 ? PAD.LEFT : PAD.RIGHT);
}
return ret;
}
};
@ -565,7 +584,7 @@ Generic template helper definitions for HackMyResume / FluentCV.
dateFrom = dateTemp.format(fmt);
}
if (_.contains(reserved, dateBTrim)) {
dateTo = fallback || 'Current';
dateTo = fallback || 'Present';
} else {
dateTemp = FluentDate.fmt(dateB);
dateTo = dateTemp.format(fmt);
@ -610,3 +629,5 @@ Generic template helper definitions for HackMyResume / FluentCV.
};
}).call(this);
//# sourceMappingURL=generic-helpers.js.map

48
dist/helpers/handlebars-helpers.js vendored Normal file
View File

@ -0,0 +1,48 @@
/**
Template helper definitions for Handlebars.
@license MIT. See LICENSE.md for details.
@module handlebars-helpers.js
*/
(function() {
var HANDLEBARS, _, blockHelpers, helpers;
HANDLEBARS = require('handlebars');
_ = require('underscore');
helpers = require('./generic-helpers');
blockHelpers = require('./block-helpers');
/**
Register useful Handlebars helpers.
@method registerHelpers
*/
module.exports = function(theme, opts) {
var wrappedHelpers;
helpers.theme = theme;
helpers.opts = opts;
helpers.type = 'handlebars';
wrappedHelpers = _.mapObject(helpers, function(hVal, hKey) {
if (_.isFunction(hVal)) {
_.wrap(hVal, function(func) {
var args;
args = Array.prototype.slice.call(arguments);
args.shift();
args.pop();
return func.apply(this, args);
});
}
return hVal;
}, this);
HANDLEBARS.registerHelper(wrappedHelpers);
HANDLEBARS.registerHelper(blockHelpers);
};
}).call(this);
//# sourceMappingURL=handlebars-helpers.js.map

View File

@ -1,7 +1,7 @@
/**
Template helper definitions for Underscore.
@license MIT. Copyright (c) 2016 hacksalot (https://github.com/hacksalot)
@license MIT. See LICENSE.md for details.
@module handlebars-helpers.js
*/
@ -26,7 +26,7 @@ Template helper definitions for Underscore.
helpers.cssInfo = cssInfo;
helpers.engine = eng;
ctx.h = helpers;
return _.each(helpers, function(hVal, hKey) {
_.each(helpers, function(hVal, hKey) {
if (_.isFunction(hVal)) {
return _.bind(hVal, ctx);
}
@ -34,3 +34,5 @@ Template helper definitions for Underscore.
};
}).call(this);
//# sourceMappingURL=underscore-helpers.js.map

View File

@ -1,33 +0,0 @@
/**
Definition of the BaseGenerator class.
@module base-generator.js
@license MIT. See LICENSE.md for details.
*/
(function() {
var BaseGenerator, Class;
Class = require('../utils/class');
/**
The BaseGenerator class is the root of the generator hierarchy. Functionality
common to ALL generators lives here.
*/
BaseGenerator = module.exports = Class.extend({
/** Base-class initialize. */
init: function(outputFormat) {
return this.format = outputFormat;
},
/** Status codes. */
codes: require('../core/status-codes'),
/** Generator options. */
opts: {}
});
}).call(this);

View File

@ -1,42 +0,0 @@
/**
Definition of the HTMLGenerator class.
@license MIT. See LICENSE.md for details.
@module html-generator.js
*/
(function() {
var FS, HTML, HtmlGenerator, PATH, TemplateGenerator;
TemplateGenerator = require('./template-generator');
FS = require('fs-extra');
HTML = require('html');
PATH = require('path');
require('string.prototype.endswith');
HtmlGenerator = module.exports = TemplateGenerator.extend({
init: function() {
return this._super('html');
},
/**
Copy satellite CSS files to the destination and optionally pretty-print
the HTML resume prior to saving.
*/
onBeforeSave: function(info) {
if (info.outputFile.endsWith('.css')) {
return info.mk;
}
if (this.opts.prettify) {
return HTML.prettyPrint(info.mk, this.opts.prettify);
} else {
return info.mk;
}
}
});
}).call(this);

View File

@ -1,98 +0,0 @@
/**
Definition of the HtmlPdfCLIGenerator class.
@module html-pdf-generator.js
@license MIT. See LICENSE.md for details.
*/
(function() {
var FS, HTML, HtmlPdfCLIGenerator, PATH, SLASH, SPAWN, TemplateGenerator, engines;
TemplateGenerator = require('./template-generator');
FS = require('fs-extra');
HTML = require('html');
PATH = require('path');
SPAWN = require('../utils/safe-spawn');
SLASH = require('slash');
/**
An HTML-driven PDF resume generator for HackMyResume. Talks to Phantom,
wkhtmltopdf, and other PDF engines over a CLI (command-line interface).
If an engine isn't installed for a particular platform, error out gracefully.
*/
HtmlPdfCLIGenerator = module.exports = TemplateGenerator.extend({
init: function() {
return this._super('pdf', 'html');
},
/** Generate the binary PDF. */
onBeforeSave: function(info) {
var ex, safe_eng;
try {
safe_eng = info.opts.pdf || 'wkhtmltopdf';
if (safe_eng !== 'none') {
engines[safe_eng].call(this, info.mk, info.outputFile);
return null;
}
} catch (_error) {
ex = _error;
if (ex.inner && ex.inner.code === 'ENOENT') {
throw {
fluenterror: this.codes.notOnPath,
inner: ex.inner,
engine: ex.cmd,
stack: ex.inner && ex.inner.stack
};
} else {
throw {
fluenterror: this.codes.pdfGeneration,
inner: ex,
stack: ex.stack
};
}
}
}
});
engines = {
/**
Generate a PDF from HTML using wkhtmltopdf's CLI interface.
Spawns a child process with `wkhtmltopdf <source> <target>`. wkhtmltopdf
must be installed and path-accessible.
TODO: If HTML generation has run, reuse that output
TODO: Local web server to ease wkhtmltopdf rendering
*/
wkhtmltopdf: function(markup, fOut) {
var info, tempFile;
tempFile = fOut.replace(/\.pdf$/i, '.pdf.html');
FS.writeFileSync(tempFile, markup, 'utf8');
return info = SPAWN('wkhtmltopdf', [tempFile, fOut]);
},
/**
Generate a PDF from HTML using Phantom's CLI interface.
Spawns a child process with `phantomjs <script> <source> <target>`. Phantom
must be installed and path-accessible.
TODO: If HTML generation has run, reuse that output
TODO: Local web server to ease Phantom rendering
*/
phantom: function(markup, fOut) {
var destPath, info, scriptPath, sourcePath, tempFile;
tempFile = fOut.replace(/\.pdf$/i, '.pdf.html');
FS.writeFileSync(tempFile, markup, 'utf8');
scriptPath = SLASH(PATH.relative(process.cwd(), PATH.resolve(__dirname, '../utils/rasterize.js')));
sourcePath = SLASH(PATH.relative(process.cwd(), tempFile));
destPath = SLASH(PATH.relative(process.cwd(), fOut));
return info = SPAWN('phantomjs', [scriptPath, sourcePath, destPath]);
}
};
}).call(this);

View File

@ -1,45 +0,0 @@
/**
Definition of the JsonGenerator class.
@license MIT. See LICENSE.md for details.
@module generators/json-generator
*/
(function() {
var BaseGenerator, FS, JsonGenerator, _;
BaseGenerator = require('./base-generator');
FS = require('fs');
_ = require('underscore');
/**
The JsonGenerator generates a JSON resume directly.
*/
JsonGenerator = module.exports = BaseGenerator.extend({
init: function() {
return this._super('json');
},
keys: ['imp', 'warnings', 'computed', 'filt', 'ctrl', 'index', 'safeStartDate', 'safeEndDate', 'safeDate', 'safeReleaseDate', 'result', 'isModified', 'htmlPreview', 'safe'],
invoke: function(rez) {
var replacer;
replacer = function(key, value) {
if (_.some(this.keys, function(val) {
return key.trim() === val;
})) {
return void 0;
} else {
return value;
}
};
return JSON.stringify(rez, replacer, 2);
},
generate: function(rez, f) {
FS.writeFileSync(f, this.invoke(rez), 'utf8');
}
});
}).call(this);

View File

@ -1,38 +0,0 @@
/**
Definition of the JsonYamlGenerator class.
@module json-yaml-generator.js
@license MIT. See LICENSE.md for details.
*/
(function() {
var BaseGenerator, FS, JsonYamlGenerator, YAML;
BaseGenerator = require('./base-generator');
FS = require('fs');
YAML = require('yamljs');
/**
JsonYamlGenerator takes a JSON resume object and translates it directly to
JSON without a template, producing an equivalent YAML-formatted resume. See
also YamlGenerator (yaml-generator.js).
*/
JsonYamlGenerator = module.exports = BaseGenerator.extend({
init: function() {
return this._super('yml');
},
invoke: function(rez, themeMarkup, cssInfo, opts) {
return YAML.stringify(JSON.parse(rez.stringify()), Infinity, 2);
},
generate: function(rez, f, opts) {
var data;
data = YAML.stringify(JSON.parse(rez.stringify()), Infinity, 2);
return FS.writeFileSync(f, data, 'utf8');
}
});
}).call(this);

View File

@ -1,24 +0,0 @@
/**
Definition of the LaTeXGenerator class.
@license MIT. See LICENSE.md for details.
@module generators/latex-generator
*/
(function() {
var LaTeXGenerator, TemplateGenerator;
TemplateGenerator = require('./template-generator');
/**
LaTeXGenerator generates a LaTeX resume via TemplateGenerator.
*/
LaTeXGenerator = module.exports = TemplateGenerator.extend({
init: function() {
return this._super('latex', 'tex');
}
});
}).call(this);

View File

@ -1,24 +0,0 @@
/**
Definition of the MarkdownGenerator class.
@license MIT. Copyright (c) 2015 James Devlin / FluentDesk.
@module markdown-generator.js
*/
(function() {
var MarkdownGenerator, TemplateGenerator;
TemplateGenerator = require('./template-generator');
/**
MarkdownGenerator generates a Markdown-formatted resume via TemplateGenerator.
*/
MarkdownGenerator = module.exports = TemplateGenerator.extend({
init: function() {
return this._super('md', 'txt');
}
});
}).call(this);

View File

@ -1,24 +0,0 @@
/**
Definition of the TextGenerator class.
@license MIT. See LICENSE.md for details.
@module text-generator.js
*/
(function() {
var TemplateGenerator, TextGenerator;
TemplateGenerator = require('./template-generator');
/**
The TextGenerator generates a plain-text resume via the TemplateGenerator.
*/
TextGenerator = module.exports = TemplateGenerator.extend({
init: function() {
return this._super('txt');
}
});
}).call(this);

View File

@ -1,19 +0,0 @@
/*
Definition of the WordGenerator class.
@license MIT. See LICENSE.md for details.
@module generators/word-generator
*/
(function() {
var TemplateGenerator, WordGenerator;
TemplateGenerator = require('./template-generator');
WordGenerator = module.exports = TemplateGenerator.extend({
init: function() {
return this._super('doc', 'xml');
}
});
}).call(this);

View File

@ -1,24 +0,0 @@
/**
Definition of the XMLGenerator class.
@license MIT. See LICENSE.md for details.
@module generatprs/xml-generator
*/
(function() {
var BaseGenerator, XMLGenerator;
BaseGenerator = require('./base-generator');
/**
The XmlGenerator generates an XML resume via the TemplateGenerator.
*/
XMLGenerator = module.exports = BaseGenerator.extend({
init: function() {
return this._super('xml');
}
});
}).call(this);

View File

@ -1,24 +0,0 @@
/**
Definition of the YAMLGenerator class.
@module yaml-generator.js
@license MIT. See LICENSE.md for details.
*/
(function() {
var TemplateGenerator, YAMLGenerator;
TemplateGenerator = require('./template-generator');
/**
YamlGenerator generates a YAML-formatted resume via TemplateGenerator.
*/
YAMLGenerator = module.exports = TemplateGenerator.extend({
init: function() {
return this._super('yml', 'yml');
}
});
}).call(this);

View File

@ -1,29 +0,0 @@
/**
Template helper definitions for Handlebars.
@license MIT. Copyright (c) 2015 James Devlin / FluentDesk.
@module handlebars-helpers.js
*/
(function() {
var HANDLEBARS, _, helpers;
HANDLEBARS = require('handlebars');
_ = require('underscore');
helpers = require('./generic-helpers');
/**
Register useful Handlebars helpers.
@method registerHelpers
*/
module.exports = function(theme, opts) {
helpers.theme = theme;
helpers.opts = opts;
return HANDLEBARS.registerHelper(helpers);
};
}).call(this);

View File

@ -1,49 +0,0 @@
/**
External API surface for HackMyResume.
@license MIT. See LICENSE.md for details.
@module hackmycore/index
*/
/**
API facade for HackMyCore.
*/
(function() {
var HackMyCore;
HackMyCore = module.exports = {
verbs: {
build: require('./verbs/build'),
analyze: require('./verbs/analyze'),
validate: require('./verbs/validate'),
convert: require('./verbs/convert'),
"new": require('./verbs/create'),
peek: require('./verbs/peek')
},
alias: {
generate: require('./verbs/build'),
create: require('./verbs/create')
},
options: require('./core/default-options'),
formats: require('./core/default-formats'),
Sheet: require('./core/fresh-resume'),
FRESHResume: require('./core/fresh-resume'),
JRSResume: require('./core/jrs-resume'),
FRESHTheme: require('./core/fresh-theme'),
JRSTheme: require('./core/jrs-theme'),
FluentDate: require('./core/fluent-date'),
HtmlGenerator: require('./generators/html-generator'),
TextGenerator: require('./generators/text-generator'),
HtmlPdfCliGenerator: require('./generators/html-pdf-cli-generator'),
WordGenerator: require('./generators/word-generator'),
MarkdownGenerator: require('./generators/markdown-generator'),
JsonGenerator: require('./generators/json-generator'),
YamlGenerator: require('./generators/yaml-generator'),
JsonYamlGenerator: require('./generators/json-yaml-generator'),
LaTeXGenerator: require('./generators/latex-generator'),
HtmlPngGenerator: require('./generators/html-png-generator')
};
}).call(this);

View File

@ -1,72 +0,0 @@
/**
Definition of John Resig's `Class` class.
@module class.js
*/
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
* http://ejohn.org/blog/simple-javascript-inheritance/
*/
// Inspired by base2 and Prototype
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
module.exports = Class;
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) : // jshint ignore:line
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();

View File

@ -1,34 +0,0 @@
/**
Safe spawn utility for HackMyResume / FluentCV.
@module utils/safe-spawn
@license MIT. See LICENSE.md for details.
*/
(function() {
module.exports = function(cmd, args, isSync) {
var info, spawn;
try {
spawn = require('child_process')[isSync ? 'spawnSync' : 'spawn'];
info = spawn(cmd, args);
if (!isSync) {
return info.on('error', function(err) {
throw {
cmd: 'wkhtmltopdf',
inner: err
};
});
} else {
if (info.error) {
throw {
cmd: 'wkhtmltopdf',
inner: info.error
};
}
}
} catch (_error) {
throw _error;
}
};
}).call(this);

View File

@ -1,39 +0,0 @@
/**
Definition of the SyntaxErrorEx class.
@module utils/syntax-error-ex
@license MIT. See LICENSE.md for details.
*/
/**
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 reparse on error to grab the line and column.
See: http://stackoverflow.com/q/13323356
@class SyntaxErrorEx
*/
(function() {
var SyntaxErrorEx;
SyntaxErrorEx = function(ex, rawData) {
var JSONLint, colNum, lineNum, lint;
lineNum = null;
colNum = null;
JSONLint = require('json-lint');
lint = JSONLint(rawData, {
comments: false
});
this.line = lint.error ? lint.line : '???';
return this.col = lint.error ? lint.character : '???';
};
SyntaxErrorEx.is = function(ex) {
return ex instanceof SyntaxError;
};
module.exports = SyntaxErrorEx;
}).call(this);

View File

@ -1,102 +0,0 @@
/**
Implementation of the 'analyze' verb for HackMyResume.
@module verbs/analyze
@license MIT. See LICENSE.md for details.
*/
(function() {
var AnalyzeVerb, HMEVENT, HMSTATUS, MKDIRP, PATH, ResumeFactory, Verb, _, _analyze, _loadInspectors, analyze, chalk;
MKDIRP = require('mkdirp');
PATH = require('path');
HMEVENT = require('../core/event-codes');
HMSTATUS = require('../core/status-codes');
_ = require('underscore');
ResumeFactory = require('../core/resume-factory');
Verb = require('../verbs/verb');
chalk = require('chalk');
AnalyzeVerb = module.exports = Verb.extend({
init: function() {
return this._super('analyze');
},
invoke: function() {
this.stat(HMEVENT.begin, {
cmd: 'analyze'
});
analyze.apply(this, arguments);
return this.stat(HMEVENT.end);
}
});
/**
Run the 'analyze' command.
*/
analyze = function(sources, dst, opts) {
var nlzrs;
if (!sources || !sources.length) {
throw {
fluenterror: HMSTATUS.resumeNotFound,
quit: true
};
}
nlzrs = _loadInspectors();
return _.each(sources, function(src) {
var result;
result = ResumeFactory.loadOne(src, {
format: 'FRESH',
objectify: true
}, this);
if (result.fluenterror) {
return this.setError(result.fluenterror, result);
} else {
return _analyze.call(this, result, nlzrs, opts);
}
}, this);
};
/**
Analyze a single resume.
*/
_analyze = function(resumeObject, nlzrs, opts) {
var info, rez, safeFormat;
rez = resumeObject.rez;
safeFormat = rez.meta && rez.meta.format && rez.meta.format.startsWith('FRESH') ? 'FRESH' : 'JRS';
this.stat(HMEVENT.beforeAnalyze, {
fmt: safeFormat,
file: resumeObject.file
});
info = _.mapObject(nlzrs, function(val, key) {
return val.run(rez);
});
return this.stat(HMEVENT.afterAnalyze, {
info: info
});
};
/**
Load inspectors.
*/
_loadInspectors = function() {
return {
totals: require('../inspectors/totals-inspector'),
coverage: require('../inspectors/gap-inspector'),
keywords: require('../inspectors/keyword-inspector')
};
};
}).call(this);

View File

@ -1,95 +0,0 @@
/**
Implementation of the 'convert' verb for HackMyResume.
@module verbs/convert
@license MIT. See LICENSE.md for details.
*/
(function() {
var ConvertVerb, HMEVENT, HMSTATUS, ResumeFactory, Verb, _, chalk, convert;
ResumeFactory = require('../core/resume-factory');
chalk = require('chalk');
Verb = require('../verbs/verb');
HMSTATUS = require('../core/status-codes');
_ = require('underscore');
HMEVENT = require('../core/event-codes');
ConvertVerb = module.exports = Verb.extend({
init: function() {
return this._super('convert');
},
invoke: function() {
this.stat(HMEVENT.begin, {
cmd: 'convert'
});
convert.apply(this, arguments);
return this.stat(HMEVENT.end);
}
});
/**
Convert between FRESH and JRS formats.
*/
convert = function(srcs, dst, opts) {
if (!srcs || !srcs.length) {
throw {
fluenterror: 6,
quit: true
};
}
if (!dst || !dst.length) {
if (srcs.length === 1) {
throw {
fluenterror: HMSTATUS.inputOutputParity,
quit: true
};
} else if (srcs.length === 2) {
dst = dst || [];
dst.push(srcs.pop());
} else {
throw {
fluenterror: HMSTATUS.inputOutputParity,
quit: true
};
}
}
if (srcs && dst && srcs.length && dst.length && srcs.length !== dst.length) {
throw {
fluenterror: HMSTATUS.inputOutputParity({
quit: true
})
};
}
_.each(srcs, function(src, idx) {
var rinfo, s, srcFmt, targetFormat;
rinfo = ResumeFactory.loadOne(src, {
format: null,
objectify: true,
"throw": false
});
if (rinfo.fluenterror) {
this.err(rinfo.fluenterror, rinfo);
return;
}
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,
srcFmt: srcFmt,
dstFile: dst[idx],
dstFmt: targetFormat
});
s.saveAs(dst[idx], targetFormat);
}, this);
};
}).call(this);

View File

@ -1,69 +0,0 @@
/**
Implementation of the 'create' verb for HackMyResume.
@module verbs/create
@license MIT. See LICENSE.md for details.
*/
(function() {
var CreateVerb, HMEVENT, HMSTATUS, MKDIRP, PATH, Verb, _, chalk, create;
MKDIRP = require('mkdirp');
PATH = require('path');
chalk = require('chalk');
Verb = require('../verbs/verb');
_ = require('underscore');
HMSTATUS = require('../core/status-codes');
HMEVENT = require('../core/event-codes');
CreateVerb = module.exports = Verb.extend({
init: function() {
return this._super('new');
},
invoke: function() {
this.stat(HMEVENT.begin, {
cmd: 'create'
});
create.apply(this, arguments);
this.stat(HMEVENT.begin, {
cmd: 'convert'
});
}
});
/**
Create a new empty resume in either FRESH or JRS format.
*/
create = function(src, dst, opts) {
if (!src || !src.length) {
throw {
fluenterror: HMSTATUS.createNameMissing,
quit: true
};
}
_.each(src, function(t) {
var RezClass, safeFmt;
safeFmt = opts.format.toUpperCase();
this.stat(HMEVENT.beforeCreate, {
fmt: safeFmt,
file: t
});
MKDIRP.sync(PATH.dirname(t));
RezClass = require('../core/' + safeFmt.toLowerCase() + '-resume');
RezClass["default"]().save(t);
return this.stat(HMEVENT.afterCreate, {
fmt: safeFmt,
file: t
});
}, this);
};
}).call(this);

View File

@ -1,79 +0,0 @@
/**
Implementation of the 'peek' verb for HackMyResume.
@module verbs/peek
@license MIT. See LICENSE.md for details.
*/
(function() {
var HMEVENT, HMSTATUS, PeekVerb, Verb, _, __, peek, safeLoadJSON;
Verb = require('../verbs/verb');
_ = require('underscore');
__ = require('lodash');
safeLoadJSON = require('../utils/safe-json-loader');
HMSTATUS = require('../core/status-codes');
HMEVENT = require('../core/event-codes');
PeekVerb = module.exports = Verb.extend({
init: function() {
return this._super('peek');
},
invoke: function() {
this.stat(HMEVENT.begin, {
cmd: 'peek'
});
peek.apply(this, arguments);
return this.stat(HMEVENT.end);
}
});
/**
Peek at a resume, resume section, or resume field.
*/
peek = function(src, dst, opts) {
var objPath;
if (!src || !src.length) {
({
"throw": {
fluenterror: HMSTATUS.resumeNotFound
}
});
}
objPath = (dst && dst[0]) || '';
_.each(src, function(t) {
var errCode, obj, tgt;
this.stat(HMEVENT.beforePeek, {
file: t,
target: objPath
});
obj = safeLoadJSON(t);
tgt = null;
if (!obj.ex) {
tgt = objPath ? __.get(obj.json, objPath) : obj.json;
}
this.stat(HMEVENT.afterPeek, {
file: t,
requested: objPath,
target: tgt,
error: obj.ex
});
if (obj.ex) {
errCode = obj.ex.operation === 'parse' ? HMSTATUS.parseError : HMSTATUS.readError;
if (errCode === HMSTATUS.readError) {
obj.ex.quiet = true;
}
this.setError(errCode, obj.ex);
return this.err(errCode, obj.ex);
}
}, this);
};
}).call(this);

View File

@ -1,110 +0,0 @@
/**
Implementation of the 'validate' verb for HackMyResume.
@module verbs/validate
@license MIT. See LICENSE.md for details.
*/
(function() {
var FS, HMEVENT, HMSTATUS, ResumeFactory, SyntaxErrorEx, ValidateVerb, Verb, _, chalk, validate;
FS = require('fs');
ResumeFactory = require('../core/resume-factory');
SyntaxErrorEx = require('../utils/syntax-error-ex');
chalk = require('chalk');
Verb = require('../verbs/verb');
HMSTATUS = require('../core/status-codes');
HMEVENT = require('../core/event-codes');
_ = require('underscore');
/** An invokable resume validation command. */
ValidateVerb = module.exports = Verb.extend({
init: function() {
return this._super('validate');
},
invoke: function() {
this.stat(HMEVENT.begin, {
cmd: 'validate'
});
validate.apply(this, arguments);
this.stat(HMEVENT.end);
}
});
/** Validate 1 to N resumes in FRESH or JSON Resume format. */
validate = function(sources, unused, opts) {
var resumes, schemas, validator;
if (!sources || !sources.length) {
throw {
fluenterror: HMSTATUS.resumeNotFoundAlt,
quit: true
};
}
validator = require('is-my-json-valid');
schemas = {
fresh: require('fresca'),
jars: require('../core/resume.json')
};
resumes = ResumeFactory.load(sources, {
format: null,
objectify: false
}, this);
return resumes.map(function(src) {
var errors, exc, fmt, json, ret;
ret = {
file: src,
isValid: false
};
if (src.fluenterror) {
if (opts.assert) {
throw src;
}
this.setError(src.fluenterror, src);
return ret;
}
json = src.json;
fmt = json.basics ? 'jrs' : 'fresh';
errors = [];
try {
validate = validator(schemas[fmt], {
formats: {
date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/
}
});
ret.isValid = validate(json);
if (!ret.isValid) {
errors = validate.errors;
}
} catch (_error) {
exc = _error;
return ret;
}
this.stat(HMEVENT.afterValidate, {
file: src.file,
isValid: ret.isValid,
fmt: fmt.replace('jars', 'JSON Resume'),
errors: errors
});
if (opts.assert && !ret.isValid) {
throw {
fluenterror: HMSTATUS.invalid({
shouldExit: true
})
};
}
return ret;
}, this);
};
}).call(this);

View File

@ -1,69 +0,0 @@
/**
Definition of the Verb class.
@module verbs/verb
@license MIT. See LICENSE.md for details.
*/
(function() {
var Class, EVENTS, Verb;
Class = require('../utils/class');
EVENTS = require('events');
/**
An instantiation of a HackMyResume command.
@class Verb
*/
Verb = module.exports = Class.extend({
/** Constructor. Automatically called at creation. */
init: function(moniker) {
this.moniker = moniker;
this.emitter = new EVENTS.EventEmitter();
},
/** Forward subscriptions to the event emitter. */
on: function() {
return this.emitter.on.apply(this.emitter, arguments);
},
/** Fire an arbitrary event, scoped to "hmr:". */
fire: function(evtName, payload) {
payload = payload || {};
payload.cmd = this.moniker;
this.emitter.emit('hmr:' + evtName, payload);
return true;
},
/** Handle an error condition. */
err: function(errorCode, payload, hot) {
payload = payload || {};
payload.sub = payload.fluenterror = errorCode;
payload["throw"] = hot;
this.fire('error', payload);
if (hot) {
throw payload;
}
return true;
},
/** Fire the 'hmr:status' error event. */
stat: function(subEvent, payload) {
payload = payload || {};
payload.sub = subEvent;
this.fire('status', payload);
return true;
},
/** Associate error info with the invocation. */
setError: function(code, obj) {
this.errorCode = code;
this.errorObj = obj;
}
});
}).call(this);

92
dist/hmc/package.json vendored
View File

@ -1,92 +0,0 @@
{
"name": "hackmycore",
"version": "0.4.0",
"description": "The open core library for HackMyResume and FluentCV.",
"repository": {
"type": "git",
"url": "https://github.com/hacksalot/HackMyCore.git"
},
"scripts": {
"test": "grunt clean:test && mocha",
"grunt": "grunt"
},
"author": "hacksalot <hacksalot@indevious.com> (https://github.com/hacksalot)",
"contributors": [],
"license": "MIT",
"bugs": {
"url": "https://github.com/hacksalot/HackMyCore/issues"
},
"main": "dist/index.js",
"homepage": "https://github.com/hacksalot/HackMyCore",
"dependencies": {
"copy": "^0.1.3",
"extend": "^3.0.0",
"fresca": "~0.6.0",
"fresh-jrs-converter": "^0.2.0",
"fresh-resume-starter": "^0.2.2",
"fresh-themes": "~0.14.0-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",
"mkdirp": "^0.5.1",
"moment": "^2.10.6",
"parse-filepath": "^0.6.3",
"path-exists": "^2.1.0",
"printf": "^0.2.3",
"recursive-readdir-sync": "^1.0.6",
"simple-html-tokenizer": "^0.2.0",
"slash": "^1.0.0",
"string-padding": "^1.0.2",
"string.prototype.endswith": "^0.2.0",
"string.prototype.startswith": "^0.2.0",
"traverse": "^0.6.6",
"underscore": "^1.8.3",
"word-wrap": "^1.1.0",
"xml-escape": "^1.0.0",
"yamljs": "^0.2.4"
},
"devDependencies": {
"chai": "*",
"chalk": "^1.1.1",
"fresh-test-resumes": "^0.6.0",
"grunt": "*",
"grunt-cli": "^0.1.13",
"grunt-contrib-clean": "^0.7.0",
"grunt-contrib-coffee": "^0.13.0",
"grunt-contrib-copy": "^0.8.2",
"grunt-contrib-jshint": "^0.11.3",
"grunt-contrib-yuidoc": "^0.10.0",
"grunt-jsdoc": "^1.1.0",
"grunt-simple-mocha": "*",
"jsonresume-theme-boilerplate": "^0.1.2",
"jsonresume-theme-classy": "^1.0.9",
"jsonresume-theme-modern": "0.0.18",
"jsonresume-theme-sceptile": "^1.0.5",
"mocha": "*",
"resample": "fluentdesk/resample"
},
"keywords": [
"resume",
"CV",
"portfolio",
"employment",
"career",
"HackMyResume",
"Markdown",
"JSON",
"Word",
"PDF",
"YAML",
"HTML",
"LaTeX",
"CLI",
"Handlebars",
"Underscore",
"template"
]
}

54
dist/index.js vendored
View File

@ -1,22 +1,48 @@
#! /usr/bin/env node
/**
Command-line interface (CLI) for HackMyResume.
External API surface for HackMyResume.
@license MIT. See LICENSE.md for details.
@module index.js
*/
@module hackmycore/index
*/
/** API facade for HackMyResume. */
try {
(function() {
module.exports = {
verbs: {
build: require('./verbs/build'),
analyze: require('./verbs/analyze'),
validate: require('./verbs/validate'),
convert: require('./verbs/convert'),
"new": require('./verbs/create'),
peek: require('./verbs/peek')
},
alias: {
generate: require('./verbs/build'),
create: require('./verbs/create')
},
options: require('./core/default-options'),
formats: require('./core/default-formats'),
Sheet: require('./core/fresh-resume'),
FRESHResume: require('./core/fresh-resume'),
JRSResume: require('./core/jrs-resume'),
FRESHTheme: require('./core/fresh-theme'),
JRSTheme: require('./core/jrs-theme'),
ResumeFactory: require('./core/resume-factory'),
FluentDate: require('./core/fluent-date'),
HtmlGenerator: require('./generators/html-generator'),
TextGenerator: require('./generators/text-generator'),
HtmlPdfCliGenerator: require('./generators/html-pdf-cli-generator'),
WordGenerator: require('./generators/word-generator'),
MarkdownGenerator: require('./generators/markdown-generator'),
JsonGenerator: require('./generators/json-generator'),
YamlGenerator: require('./generators/yaml-generator'),
JsonYamlGenerator: require('./generators/json-yaml-generator'),
LaTeXGenerator: require('./generators/latex-generator'),
HtmlPngGenerator: require('./generators/html-png-generator')
};
require('./cli/main')( process.argv );
}).call(this);
}
catch( ex ) {
require('./cli/error').err( ex, true );
}
//# sourceMappingURL=index.js.map

View File

@ -136,3 +136,5 @@ Employment gap analysis for HackMyResume.
};
}).call(this);
//# sourceMappingURL=gap-inspector.js.map

View File

@ -59,3 +59,5 @@ Keyword analysis for HackMyResume.
};
}).call(this);
//# sourceMappingURL=keyword-inspector.js.map

View File

@ -47,3 +47,5 @@ Section analysis for HackMyResume.
};
}).call(this);
//# sourceMappingURL=totals-inspector.js.map

View File

@ -43,7 +43,7 @@ Definition of the HandlebarsGenerator class.
return template(data);
} catch (_error) {
throw {
fluenterror: template ? HMSTATUS.invokeTemplate : HMSTATUS.compileTemplate,
fluenterror: HMSTATUS[template ? 'invokeTemplate' : 'compileTemplate'],
inner: _error
};
}
@ -98,3 +98,5 @@ Definition of the HandlebarsGenerator class.
};
}).call(this);
//# sourceMappingURL=handlebars-generator.js.map

View File

@ -36,10 +36,11 @@ Definition of the JRSGenerator class.
generate: function(json, jst, format, cssInfo, opts, theme) {
var org, rezHtml, turnoff;
turnoff = ['log', 'error', 'dir'];
org = turnoff.map(c)(function() {
org = turnoff.map(function(c) {
var ret;
ret = console[c];
return console[c] = function() {};
console[c] = function() {};
return ret;
});
rezHtml = theme.render(json.harden());
turnoff.forEach(function(c, idx) {
@ -56,3 +57,5 @@ Definition of the JRSGenerator class.
};
}).call(this);
//# sourceMappingURL=jrs-generator.js.map

View File

@ -6,13 +6,15 @@ Definition of the UnderscoreGenerator class.
*/
(function() {
var HMSTATUS, UnderscoreGenerator, _, registerHelpers;
var UnderscoreGenerator, _, escapeLaTeX, registerHelpers;
_ = require('underscore');
registerHelpers = require('../helpers/underscore-helpers');
HMSTATUS = require('../core/status-codes');
require('../utils/string');
escapeLaTeX = require('escape-latex');
/**
@ -22,19 +24,20 @@ Definition of the UnderscoreGenerator class.
UnderscoreGenerator = module.exports = {
generateSimple: function(data, tpl) {
var template;
var HMS, t;
try {
template = _.template(tpl);
return template(data);
t = _.template(tpl);
return t(data);
} catch (_error) {
HMS = require('../core/status-codes');
throw {
fluenterror: template ? HMSTATUS.invokeTemplate : HMSTATUS.compileTemplate,
fluenterror: HMS[t ? 'invokeTemplate' : 'compileTemplate'],
inner: _error
};
}
},
generate: function(json, jst, format, cssInfo, opts, theme) {
var ctx, delims;
var ctx, delims, r, traverse;
delims = (opts.themeObj && opts.themeObj.delimeters) || opts.template;
if (opts.themeObj && opts.themeObj.delimeters) {
delims = _.mapObject(delims, function(val, key) {
@ -42,9 +45,31 @@ Definition of the UnderscoreGenerator class.
});
}
_.templateSettings = delims;
jst = jst.replace(delims.comment, '');
r = null;
switch (format) {
case 'html':
r = json.markdownify();
break;
case 'pdf':
r = json.markdownify();
break;
case 'png':
r = json.markdownify();
break;
case 'latex':
traverse = require('traverse');
r = traverse(json).map(function(x) {
if (this.isLeaf && String.is(this.node)) {
return escapeLaTeX(this.node);
}
return this.node;
});
break;
default:
r = json;
}
ctx = {
r: format === 'html' || format === 'pdf' || format === 'png' ? json.markdownify() : json,
r: r,
filt: opts.filters,
XML: require('xml-escape'),
RAW: json,
@ -58,3 +83,5 @@ Definition of the UnderscoreGenerator class.
};
}).call(this);
//# sourceMappingURL=underscore-generator.js.map

View File

@ -10,3 +10,5 @@ Definition of the SyntaxErrorEx class.
};
}).call(this);
//# sourceMappingURL=file-contains.js.map

View File

@ -59,3 +59,5 @@ Definition of the Markdown to WordProcessingML conversion routine.
};
}).call(this);
//# sourceMappingURL=html-to-wpml.js.map

View File

@ -26,3 +26,5 @@ Inline Markdown-to-Chalk conversion routines.
};
}).call(this);
//# sourceMappingURL=md2chalk.js.map

View File

@ -75,3 +75,5 @@
}
}).call(this);
//# sourceMappingURL=rasterize.js.map

View File

@ -30,3 +30,5 @@ Definition of the SafeJsonLoader class.
};
}).call(this);
//# sourceMappingURL=safe-json-loader.js.map

46
dist/utils/safe-spawn.js vendored Normal file
View File

@ -0,0 +1,46 @@
/**
Safe spawn utility for HackMyResume / FluentCV.
@module utils/safe-spawn
@license MIT. See LICENSE.md for details.
*/
/** Safely spawn a process synchronously or asynchronously without throwing an
exception
*/
(function() {
module.exports = function(cmd, args, isSync, callback, param) {
var info, spawn;
try {
spawn = require('child_process')[isSync ? 'spawnSync' : 'spawn'];
info = spawn(cmd, args);
if (!isSync) {
info.on('error', function(err) {
if (typeof callback === "function") {
callback(err, param);
}
});
} else {
if (info.error) {
if (typeof callback === "function") {
callback(info.error, param);
}
return {
cmd: cmd,
inner: info.error
};
}
}
} catch (_error) {
if (typeof callback === "function") {
callback(_error, param);
}
return _error;
}
};
}).call(this);
//# sourceMappingURL=safe-spawn.js.map

View File

@ -60,3 +60,5 @@ Object string transformation.
};
}).call(this);
//# sourceMappingURL=string-transformer.js.map

View File

@ -25,3 +25,5 @@ See: http://stackoverflow.com/a/32800728/4942583
};
}).call(this);
//# sourceMappingURL=string.js.map

55
dist/utils/syntax-error-ex.js vendored Normal file
View File

@ -0,0 +1,55 @@
/**
Definition of the SyntaxErrorEx class.
@module utils/syntax-error-ex
@license MIT. See LICENSE.md for details.
*/
/**
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 reparse on error to grab the line and column.
See: http://stackoverflow.com/q/13323356
@class SyntaxErrorEx
*/
(function() {
var SyntaxErrorEx;
SyntaxErrorEx = (function() {
function SyntaxErrorEx(ex, rawData) {
var JSONLint, colNum, lineNum, lint, ref;
lineNum = null;
colNum = null;
JSONLint = require('json-lint');
lint = JSONLint(rawData, {
comments: false
});
if (lint.error) {
ref = [lint.line, lint.character], this.line = ref[0], this.col = ref[1];
}
if (!lint.error) {
JSONLint = require('jsonlint');
try {
JSONLint.parse(rawData);
} catch (_error) {
this.line = (/on line (\d+)/.exec(_error))[1];
}
}
}
return SyntaxErrorEx;
})();
SyntaxErrorEx.is = function(ex) {
return ex instanceof SyntaxError;
};
module.exports = SyntaxErrorEx;
}).call(this);
//# sourceMappingURL=syntax-error-ex.js.map

110
dist/verbs/analyze.js vendored Normal file
View File

@ -0,0 +1,110 @@
/**
Implementation of the 'analyze' verb for HackMyResume.
@module verbs/analyze
@license MIT. See LICENSE.md for details.
*/
(function() {
var AnalyzeVerb, HMEVENT, HMSTATUS, MKDIRP, PATH, ResumeFactory, Verb, _, _analyze, _analyzeOne, _loadInspectors, chalk,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
MKDIRP = require('mkdirp');
PATH = require('path');
HMEVENT = require('../core/event-codes');
HMSTATUS = require('../core/status-codes');
_ = require('underscore');
ResumeFactory = require('../core/resume-factory');
Verb = require('../verbs/verb');
chalk = require('chalk');
/** An invokable resume analysis command. */
module.exports = AnalyzeVerb = (function(superClass) {
extend(AnalyzeVerb, superClass);
function AnalyzeVerb() {
AnalyzeVerb.__super__.constructor.call(this, 'analyze', _analyze);
}
return AnalyzeVerb;
})(Verb);
/** Private workhorse for the 'analyze' command. */
_analyze = function(sources, dst, opts) {
var nlzrs, results;
if (!sources || !sources.length) {
this.err(HMSTATUS.resumeNotFound, {
quit: true
});
return null;
}
nlzrs = _loadInspectors();
results = _.map(sources, function(src) {
var r;
r = ResumeFactory.loadOne(src, {
format: 'FRESH',
objectify: true
}, this);
if (opts.assert && this.hasError()) {
return {};
}
if (r.fluenterror) {
r.quit = opts.assert;
this.err(r.fluenterror, r);
return r;
} else {
return _analyzeOne.call(this, r, nlzrs, opts);
}
}, this);
if (this.hasError() && !opts.assert) {
this.reject(this.errorCode);
} else if (!this.hasError()) {
this.resolve(results);
}
return results;
};
/** Analyze a single resume. */
_analyzeOne = function(resumeObject, nlzrs, opts) {
var info, rez, safeFormat;
rez = resumeObject.rez;
safeFormat = rez.meta && rez.meta.format && rez.meta.format.startsWith('FRESH') ? 'FRESH' : 'JRS';
this.stat(HMEVENT.beforeAnalyze, {
fmt: safeFormat,
file: resumeObject.file
});
info = _.mapObject(nlzrs, function(val, key) {
return val.run(rez);
});
this.stat(HMEVENT.afterAnalyze, {
info: info
});
return info;
};
_loadInspectors = function() {
return {
totals: require('../inspectors/totals-inspector'),
coverage: require('../inspectors/gap-inspector'),
keywords: require('../inspectors/keyword-inspector')
};
};
}).call(this);
//# sourceMappingURL=analyze.js.map

View File

@ -6,7 +6,9 @@ Implementation of the 'build' verb for HackMyResume.
*/
(function() {
var BuildVerb, FRESHTheme, FS, HMEVENT, HMSTATUS, JRSTheme, MD, MKDIRP, PATH, RConverter, RTYPES, ResumeFactory, Verb, _, _err, _fmts, _log, _opts, _rezObj, addFreebieFormats, build, expand, extend, loadTheme, parsePath, prep, single, verifyOutputs, verifyTheme;
var BuildVerb, FRESHTheme, FS, HMEVENT, HMSTATUS, JRSTheme, MD, MKDIRP, PATH, RConverter, RTYPES, ResumeFactory, Verb, _, _addFreebieFormats, _build, _err, _expand, _fmts, _loadTheme, _log, _opts, _prep, _rezObj, _single, _verifyOutputs, _verifyTheme, addFreebieFormats, build, expand, extend, loadTheme, parsePath, prep, single, verifyOutputs, verifyTheme,
extend1 = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
_ = require('underscore');
@ -70,24 +72,19 @@ Implementation of the 'build' verb for HackMyResume.
/** An invokable resume generation command. */
BuildVerb = module.exports = Verb.extend({
module.exports = BuildVerb = (function(superClass) {
extend1(BuildVerb, superClass);
/** Create a new build verb. */
init: function() {
return this._super('build');
},
/** Invoke the Build command. */
invoke: function() {
var ret;
this.stat(HMEVENT.begin, {
cmd: 'build'
});
ret = build.apply(this, arguments);
this.stat(HMEVENT.end);
return ret;
function BuildVerb() {
BuildVerb.__super__.constructor.call(this, 'build', _build);
}
});
return BuildVerb;
})(Verb);
/**
@ -95,18 +92,18 @@ Implementation of the 'build' verb for HackMyResume.
theme file, generate 0..N resumes in the desired formats.
@param src Path to the source JSON resume file: "rez/resume.json".
@param dst An array of paths to the target resume file(s).
@param theme Friendly name of the resume theme. Defaults to "modern".
@param logger Optional logging override.
@param opts Generation options.
*/
build = function(src, dst, opts) {
var ex, inv, isFRESH, mixed, newEx, orgFormat, rez, sheetObjects, sheets, tFolder, targets, theme, toFormat;
_build = function(src, dst, opts) {
var inv, isFRESH, mixed, newEx, orgFormat, problemSheets, results, rez, sheetObjects, sheets, tFolder, targets, theme, toFormat;
if (!src || !src.length) {
this.err(HMSTATUS.resumeNotFound, {
quit: true
});
return null;
}
prep(src, dst, opts);
_prep.call(this, src, dst, opts);
sheetObjects = ResumeFactory.load(src, {
format: null,
objectify: false,
@ -115,9 +112,12 @@ Implementation of the 'build' verb for HackMyResume.
sort: _opts.sort
}
}, this);
if (!sheetObjects || _.some(sheetObjects, function(so) {
problemSheets = _.filter(sheetObjects, function(so) {
return so.fluenterror;
})) {
});
if (problemSheets && problemSheets.length) {
problemSheets[0].quit = true;
this.err(problemSheets[0].fluenterror, problemSheets[0]);
return null;
}
sheets = sheetObjects.map(function(r) {
@ -128,14 +128,20 @@ Implementation of the 'build' verb for HackMyResume.
theme: _opts.theme
});
try {
tFolder = verifyTheme.call(this, _opts.theme);
theme = _opts.themeObj = loadTheme(tFolder);
tFolder = _verifyTheme.call(this, _opts.theme);
if (tFolder.fluenterror) {
tFolder.quit = true;
this.err(tFolder.fluenterror, tFolder);
return;
}
theme = _opts.themeObj = _loadTheme(tFolder);
_addFreebieFormats(theme);
} catch (_error) {
ex = _error;
newEx = {
fluenterror: HMSTATUS.themeLoad,
inner: ex,
attempted: _opts.theme
inner: _error,
attempted: _opts.theme,
quit: true
};
this.err(HMSTATUS.themeLoad, newEx);
return null;
@ -143,12 +149,14 @@ Implementation of the 'build' verb for HackMyResume.
this.stat(HMEVENT.afterTheme, {
theme: theme
});
inv = verifyOutputs.call(this, dst, theme);
inv = _verifyOutputs.call(this, dst, theme);
if (inv && inv.length) {
this.err(HMSTATUS.invalidFormat, {
data: inv,
theme: theme
theme: theme,
quit: true
});
return null;
}
rez = null;
if (sheets.length > 1) {
@ -186,21 +194,34 @@ Implementation of the 'build' verb for HackMyResume.
fmt: toFormat
});
}
addFreebieFormats(theme);
this.stat(HMEVENT.applyTheme, {
r: rez,
theme: theme
});
_rezObj = new RTYPES[toFormat]().parseJSON(rez);
targets = expand(dst, theme);
targets = _expand(dst, theme);
_.each(targets, function(t) {
return t.final = single.call(this, t, theme, targets);
var ref;
if (this.hasError() && opts.assert) {
return {};
}
t.final = _single.call(this, t, theme, targets);
if ((ref = t.final) != null ? ref.fluenterror : void 0) {
t.final.quit = opts.assert;
this.err(t.final.fluenterror, t.final);
}
}, this);
return {
results = {
sheet: _rezObj,
targets: targets,
processed: targets
};
if (this.hasError() && !opts.assert) {
this.reject(results);
} else if (!this.hasError()) {
this.resolve(results);
}
return results;
};
@ -208,7 +229,8 @@ Implementation of the 'build' verb for HackMyResume.
Prepare for a BUILD run.
*/
prep = function(src, dst, opts) {
_prep = function(src, dst, opts) {
var that;
_opts.theme = (opts.theme && opts.theme.toLowerCase().trim()) || 'modern';
_opts.prettify = opts.prettify === true;
_opts.css = opts.css;
@ -220,6 +242,16 @@ Implementation of the 'build' verb for HackMyResume.
_opts.noTips = opts.noTips;
_opts.debug = opts.debug;
_opts.sort = opts.sort;
that = this;
_opts.onTransform = function(info) {
that.stat(HMEVENT.afterTransform, info);
};
_opts.beforeWrite = function(info) {
that.stat(HMEVENT.beforeWrite, info);
};
_opts.afterWrite = function(info) {
that.stat(HMEVENT.afterWrite, info);
};
(src.length > 1 && (!dst || !dst.length)) && dst.push(src.pop());
};
@ -231,14 +263,14 @@ Implementation of the 'build' verb for HackMyResume.
@param theme A FRESHTheme or JRSTheme object.
*/
single = function(targInfo, theme, finished) {
_single = function(targInfo, theme, finished) {
var e, ex, f, fName, fType, outFolder, ret, theFormat;
ret = null;
ex = null;
f = targInfo.file;
try {
if (!targInfo.fmt) {
return;
return {};
}
fType = targInfo.fmt.outFormat;
fName = PATH.basename(f, '.' + fType);
@ -247,12 +279,12 @@ Implementation of the 'build' verb for HackMyResume.
fmt: targInfo.fmt.outFormat,
file: PATH.relative(process.cwd(), f)
});
_opts.targets = finished;
if (targInfo.fmt.files && targInfo.fmt.files.length) {
theFormat = _fmts.filter(function(fmt) {
return fmt.name === targInfo.fmt.outFormat;
})[0];
MKDIRP.sync(PATH.dirname(f));
_opts.targets = finished;
ret = theFormat.gen.generate(_rezObj, f, _opts);
} else {
theFormat = _fmts.filter(function(fmt) {
@ -273,22 +305,21 @@ Implementation of the 'build' verb for HackMyResume.
});
if (ex) {
if (ex.fluenterror) {
this.err(ex.fluenterror, ex);
ret = ex;
} else {
this.err(HMSTATUS.generateError, {
ret = {
fluenterror: HMSTATUS.generateError,
inner: ex
});
};
}
}
return ret;
};
/**
Ensure that user-specified outputs/targets are valid.
*/
/** Ensure that user-specified outputs/targets are valid. */
verifyOutputs = function(targets, theme) {
_verifyOutputs = function(targets, theme) {
this.stat(HMEVENT.verifyOutputs, {
targets: targets,
theme: theme
@ -315,7 +346,7 @@ Implementation of the 'build' verb for HackMyResume.
@param theTheme A FRESHTheme or JRSTheme object.
*/
addFreebieFormats = function(theTheme) {
_addFreebieFormats = function(theTheme) {
theTheme.formats.json = theTheme.formats.json || {
freebie: true,
title: 'json',
@ -354,7 +385,7 @@ Implementation of the 'build' verb for HackMyResume.
@param theTheme A FRESHTheme or JRSTheme object.
*/
expand = function(dst, theTheme) {
_expand = function(dst, theTheme) {
var destColl, targets;
destColl = (dst && dst.length && dst) || [PATH.normalize('out/resume.all')];
targets = [];
@ -385,16 +416,17 @@ Implementation of the 'build' verb for HackMyResume.
Verify the specified theme name/path.
*/
verifyTheme = function(themeNameOrPath) {
_verifyTheme = function(themeNameOrPath) {
var exists, tFolder;
tFolder = PATH.join(parsePath(require.resolve('fresh-themes')).dirname, '/themes/', themeNameOrPath);
exists = require('path-exists').sync;
if (!exists(tFolder)) {
tFolder = PATH.resolve(themeNameOrPath);
if (!exists(tFolder)) {
this.err(HMSTATUS.themeNotFound, {
return {
fluenterror: HMSTATUS.themeNotFound,
data: _opts.theme
});
};
}
}
return tFolder;
@ -406,7 +438,7 @@ Implementation of the 'build' verb for HackMyResume.
theme.
*/
loadTheme = function(tFolder) {
_loadTheme = function(tFolder) {
var theTheme;
theTheme = _opts.theme.indexOf('jsonresume-theme-') > -1 ? new JRSTheme().open(tFolder) : new FRESHTheme().open(tFolder);
_opts.themeObj = theTheme;
@ -414,3 +446,5 @@ Implementation of the 'build' verb for HackMyResume.
};
}).call(this);
//# sourceMappingURL=build.js.map

115
dist/verbs/convert.js vendored Normal file
View File

@ -0,0 +1,115 @@
/**
Implementation of the 'convert' verb for HackMyResume.
@module verbs/convert
@license MIT. See LICENSE.md for details.
*/
(function() {
var ConvertVerb, HMEVENT, HMSTATUS, ResumeFactory, Verb, _, _convert, _convertOne, chalk,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
ResumeFactory = require('../core/resume-factory');
chalk = require('chalk');
Verb = require('../verbs/verb');
HMSTATUS = require('../core/status-codes');
_ = require('underscore');
HMEVENT = require('../core/event-codes');
module.exports = ConvertVerb = (function(superClass) {
extend(ConvertVerb, superClass);
function ConvertVerb() {
ConvertVerb.__super__.constructor.call(this, 'convert', _convert);
}
return ConvertVerb;
})(Verb);
/** Private workhorse method. Convert 0..N resumes between FRESH and JRS
formats.
*/
_convert = function(srcs, dst, opts) {
var results;
if (!srcs || !srcs.length) {
this.err(HMSTATUS.resumeNotFound, {
quit: true
});
return null;
}
if (!dst || !dst.length) {
if (srcs.length === 1) {
this.err(HMSTATUS.inputOutputParity, {
quit: true
});
} else if (srcs.length === 2) {
dst = dst || [];
dst.push(srcs.pop());
} else {
this.err(HMSTATUS.inputOutputParity, {
quit: true
});
}
}
if (srcs && dst && srcs.length && dst.length && srcs.length !== dst.length) {
this.err(HMSTATUS.inputOutputParity, {
quit: true
});
}
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;
this.err(r.fluenterror, r);
}
return r;
}, this);
if (this.hasError() && !opts.assert) {
this.reject(results);
} else if (!this.hasError()) {
this.resolve(results);
}
return results;
};
/** Private workhorse method. Convert a single resume. */
_convertOne = function(src, dst, idx) {
var rinfo, s, srcFmt, targetFormat;
rinfo = ResumeFactory.loadOne(src, {
format: null,
objectify: true
});
if (rinfo.fluenterror) {
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,
srcFmt: srcFmt,
dstFile: dst[idx],
dstFmt: targetFormat
});
s.saveAs(dst[idx], targetFormat);
return s;
};
}).call(this);
//# sourceMappingURL=convert.js.map

103
dist/verbs/create.js vendored Normal file
View File

@ -0,0 +1,103 @@
/**
Implementation of the 'create' verb for HackMyResume.
@module verbs/create
@license MIT. See LICENSE.md for details.
*/
(function() {
var CreateVerb, HMEVENT, HMSTATUS, MKDIRP, PATH, Verb, _, _create, _createOne, chalk,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
MKDIRP = require('mkdirp');
PATH = require('path');
chalk = require('chalk');
Verb = require('../verbs/verb');
_ = require('underscore');
HMSTATUS = require('../core/status-codes');
HMEVENT = require('../core/event-codes');
module.exports = CreateVerb = (function(superClass) {
extend(CreateVerb, superClass);
function CreateVerb() {
CreateVerb.__super__.constructor.call(this, 'new', _create);
}
return CreateVerb;
})(Verb);
/** Create a new empty resume in either FRESH or JRS format. */
_create = function(src, dst, opts) {
var results;
if (!src || !src.length) {
this.err(HMSTATUS.createNameMissing, {
quit: true
});
return null;
}
results = _.map(src, function(t) {
var r;
if (opts.assert && this.hasError()) {
return {};
}
r = _createOne.call(this, t, opts);
if (r.fluenterror) {
r.quit = opts.assert;
this.err(r.fluenterror, r);
}
return r;
}, this);
if (this.hasError() && !opts.assert) {
this.reject(this.errorCode);
} else if (!this.hasError()) {
this.resolve(results);
}
return results;
};
/** Create a single new resume */
_createOne = function(t, opts) {
var RezClass, newRez, ret, safeFmt;
try {
ret = null;
safeFmt = opts.format.toUpperCase();
this.stat(HMEVENT.beforeCreate, {
fmt: safeFmt,
file: t
});
MKDIRP.sync(PATH.dirname(t));
RezClass = require('../core/' + safeFmt.toLowerCase() + '-resume');
newRez = RezClass["default"]();
newRez.save(t);
ret = newRez;
} catch (_error) {
ret = {
fluenterror: HMSTATUS.createError,
inner: _error
};
} finally {
this.stat(HMEVENT.afterCreate, {
fmt: safeFmt,
file: t,
isError: ret.fluenterror
});
return ret;
}
};
}).call(this);
//# sourceMappingURL=create.js.map

106
dist/verbs/peek.js vendored Normal file
View File

@ -0,0 +1,106 @@
/**
Implementation of the 'peek' verb for HackMyResume.
@module verbs/peek
@license MIT. See LICENSE.md for details.
*/
(function() {
var HMEVENT, HMSTATUS, PeekVerb, Verb, _, __, _peek, _peekOne, safeLoadJSON,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
Verb = require('../verbs/verb');
_ = require('underscore');
__ = require('lodash');
safeLoadJSON = require('../utils/safe-json-loader');
HMSTATUS = require('../core/status-codes');
HMEVENT = require('../core/event-codes');
module.exports = PeekVerb = (function(superClass) {
extend(PeekVerb, superClass);
function PeekVerb() {
PeekVerb.__super__.constructor.call(this, 'peek', _peek);
}
return PeekVerb;
})(Verb);
/** Peek at a resume, resume section, or resume field. */
_peek = function(src, dst, opts) {
var objPath, results;
if (!src || !src.length) {
this.err(HMSTATUS.resumeNotFound, {
quit: true
});
return null;
}
objPath = (dst && dst[0]) || '';
results = _.map(src, function(t) {
var tgt;
if (opts.assert && this.hasError()) {
return {};
}
tgt = _peekOne.call(this, t, objPath);
if (tgt.error) {
this.setError(tgt.error.fluenterror, tgt.error);
}
return tgt;
}, this);
if (this.hasError() && !opts.assert) {
this.reject(this.errorCode);
} else if (!this.hasError()) {
this.resolve(results);
}
return results;
};
/** Peek at a single resume, resume section, or resume field. */
_peekOne = function(t, objPath) {
var errCode, obj, pkgError, tgt;
this.stat(HMEVENT.beforePeek, {
file: t,
target: objPath
});
obj = safeLoadJSON(t);
tgt = null;
if (!obj.ex) {
tgt = objPath ? __.get(obj.json, objPath) : obj.json;
}
pkgError = null;
if (obj.ex) {
errCode = obj.ex.operation === 'parse' ? HMSTATUS.parseError : HMSTATUS.readError;
if (errCode === HMSTATUS.readError) {
obj.ex.quiet = true;
}
pkgError = {
fluenterror: errCode,
inner: obj.ex
};
}
this.stat(HMEVENT.afterPeek, {
file: t,
requested: objPath,
target: obj.ex ? void 0 : tgt,
error: pkgError
});
return {
val: obj.ex ? void 0 : tgt,
error: pkgError
};
};
}).call(this);
//# sourceMappingURL=peek.js.map

139
dist/verbs/validate.js vendored Normal file
View File

@ -0,0 +1,139 @@
/**
Implementation of the 'validate' verb for HackMyResume.
@module verbs/validate
@license MIT. See LICENSE.md for details.
*/
(function() {
var FS, HMEVENT, HMSTATUS, ResumeFactory, SyntaxErrorEx, ValidateVerb, Verb, _, _validate, _validateOne, chalk, safeLoadJSON,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
FS = require('fs');
ResumeFactory = require('../core/resume-factory');
SyntaxErrorEx = require('../utils/syntax-error-ex');
chalk = require('chalk');
Verb = require('../verbs/verb');
HMSTATUS = require('../core/status-codes');
HMEVENT = require('../core/event-codes');
_ = require('underscore');
safeLoadJSON = require('../utils/safe-json-loader');
/** An invokable resume validation command. */
module.exports = ValidateVerb = (function(superClass) {
extend(ValidateVerb, superClass);
function ValidateVerb() {
ValidateVerb.__super__.constructor.call(this, 'validate', _validate);
}
return ValidateVerb;
})(Verb);
_validate = function(sources, unused, opts) {
var results, schemas, validator;
if (!sources || !sources.length) {
this.err(HMSTATUS.resumeNotFoundAlt, {
quit: true
});
return null;
}
validator = require('is-my-json-valid');
schemas = {
fresh: require('fresca'),
jars: require('../core/resume.json')
};
results = _.map(sources, function(t) {
var r;
r = _validateOne.call(this, t, validator, schemas, opts);
if (r.error) {
this.err(r.error.fluenterror, r.error);
}
return r;
}, this);
if (this.hasError() && !opts.assert) {
this.reject(this.errorCode);
} else if (!this.hasError()) {
this.resolve(results);
}
return results;
};
/**
Validate a single resume.
@returns {
file: <fileName>,
isValid: <validFlag>,
status: <validationStatus>,
violations: <validationErrors>,
schema: <schemaType>,
error: <errorObject>
}
*/
_validateOne = function(t, validator, schemas, opts) {
var errCode, obj, ret, validate;
ret = {
file: t,
isValid: false,
status: 'unknown',
schema: '-----'
};
try {
obj = safeLoadJSON(t);
if (!obj.ex) {
if (obj.json.basics) {
ret.schema = 'jars';
} else {
ret.schema = 'fresh';
}
validate = validator(schemas[ret.schema], {
formats: {
date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/
}
});
ret.isValid = validate(obj.json);
ret.status = ret.isValid ? 'valid' : 'invalid';
if (!ret.isValid) {
ret.violations = validate.errors;
}
} else {
if (obj.ex.operation === 'parse') {
errCode = HMSTATUS.parseError;
ret.status = 'broken';
} else {
errCode = HMSTATUS.readError;
ret.status = 'missing';
}
ret.error = {
fluenterror: errCode,
inner: obj.ex.inner,
quiet: errCode === HMSTATUS.readError
};
}
} catch (_error) {
ret.error = {
fluenterror: HMSTATUS.validateError,
inner: _error
};
}
this.stat(HMEVENT.afterValidate, ret);
return ret;
};
}).call(this);
//# sourceMappingURL=validate.js.map

118
dist/verbs/verb.js vendored Normal file
View File

@ -0,0 +1,118 @@
/**
Definition of the Verb class.
@module verbs/verb
@license MIT. See LICENSE.md for details.
*/
(function() {
var EVENTS, HMEVENT, Promise, Verb;
EVENTS = require('events');
HMEVENT = require('../core/event-codes');
Promise = require('pinkie-promise');
/**
An abstract invokable verb.
Provides base class functionality for verbs. Provide common services such as
error handling, event management, and promise support.
@class Verb
*/
module.exports = Verb = (function() {
/** Constructor. Automatically called at creation. */
function Verb(moniker, workhorse) {
this.moniker = moniker;
this.workhorse = workhorse;
this.emitter = new EVENTS.EventEmitter();
return;
}
/** Invoke the command. */
Verb.prototype.invoke = function() {
var argsArray, that;
this.stat(HMEVENT.begin, {
cmd: this.moniker
});
argsArray = Array.prototype.slice.call(arguments);
that = this;
return this.promise = new Promise(function(res, rej) {
that.resolve = res;
that.reject = rej;
that.workhorse.apply(that, argsArray);
});
};
/** Forward subscriptions to the event emitter. */
Verb.prototype.on = function() {
return this.emitter.on.apply(this.emitter, arguments);
};
/** Fire an arbitrary event, scoped to "hmr:". */
Verb.prototype.fire = function(evtName, payload) {
payload = payload || {};
payload.cmd = this.moniker;
this.emitter.emit('hmr:' + evtName, payload);
return true;
};
/** Handle an error condition. */
Verb.prototype.err = function(errorCode, payload, hot) {
payload = payload || {};
payload.sub = payload.fluenterror = errorCode;
payload["throw"] = hot;
this.setError(errorCode, payload);
if (payload.quit) {
this.reject(errorCode);
}
this.fire('error', payload);
if (hot) {
throw payload;
}
return true;
};
/** Fire the 'hmr:status' error event. */
Verb.prototype.stat = function(subEvent, payload) {
payload = payload || {};
payload.sub = subEvent;
this.fire('status', payload);
return true;
};
/** Has an error occurred during this verb invocation? */
Verb.prototype.hasError = function() {
return this.errorCode || this.errorObj;
};
/** Associate error info with the invocation. */
Verb.prototype.setError = function(code, obj) {
this.errorCode = code;
this.errorObj = obj;
};
return Verb;
})();
}).call(this);
//# sourceMappingURL=verb.js.map

View File

@ -1,6 +1,6 @@
{
"name": "hackmyresume",
"version": "1.7.2",
"version": "1.8.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",
@ -43,29 +43,33 @@
"url": "https://github.com/hacksalot/HackMyResume/issues"
},
"bin": {
"hackmyresume": "dist/index.js"
"hackmyresume": "dist/cli/index.js"
},
"main": "dist/index.js",
"homepage": "https://github.com/hacksalot/HackMyResume",
"dependencies": {
"chalk": "^1.1.1",
"commander": "^2.9.0",
"copy": "^0.1.3",
"escape-latex": "^0.1.2",
"extend": "^3.0.0",
"fresca": "~0.6.0",
"fresh-jrs-converter": "^0.2.0",
"fresh-jrs-converter": "^0.2.2",
"fresh-resume-starter": "^0.2.2",
"fresh-themes": "^0.14.0-beta",
"fresh-themes": "^0.15.1-beta",
"fs-extra": "^0.26.4",
"handlebars": "^4.0.5",
"html": "0.0.10",
"is-my-json-valid": "^2.12.4",
"json-lint": "^0.1.0",
"jsonlint": "^1.6.2",
"lodash": "^3.10.1",
"marked": "^0.3.5",
"mkdirp": "^0.5.1",
"moment": "^2.11.1",
"parse-filepath": "^0.6.3",
"path-exists": "^2.1.0",
"pinkie-promise": "^2.0.0",
"printf": "^0.2.3",
"recursive-readdir-sync": "^1.0.6",
"simple-html-tokenizer": "^0.2.1",
@ -81,7 +85,8 @@
},
"devDependencies": {
"chai": "*",
"fresh-test-resumes": "^0.6.0",
"dir-compare": "0.0.2",
"fresh-test-resumes": "^0.7.0",
"grunt": "*",
"grunt-cli": "^0.1.13",
"grunt-contrib-clean": "^0.7.0",

View File

@ -6,26 +6,24 @@ Error-handling routines for HackMyResume.
HMSTATUS = require('../hmc/dist/core/status-codes')
PKG = require('../../package.json')
FS = require('fs')
FCMD = require('../hmc')
PATH = require('path')
WRAP = require('word-wrap')
M2C = require('../hmc/dist/utils/md2chalk.js')
chalk = require('chalk')
extend = require('extend')
YAML = require('yamljs')
printf = require('printf')
SyntaxErrorEx = require('../hmc/dist/utils/syntax-error-ex')
require('string.prototype.startswith')
HMSTATUS = require '../core/status-codes'
PKG = require '../../package.json'
FS = require 'fs'
FCMD = require '../index'
PATH = require 'path'
WRAP = require 'word-wrap'
M2C = require '../utils/md2chalk'
chalk = require 'chalk'
extend = require 'extend'
YAML = require 'yamljs'
printf = require 'printf'
SyntaxErrorEx = require '../utils/syntax-error-ex'
require 'string.prototype.startswith'
###*
Error handler for HackMyResume. All errors are handled here.
@class ErrorHandler
###
###* Error handler for HackMyResume. All errors are handled here.
@class ErrorHandler ###
ErrorHandler = module.exports =
init: ( debug, assert, silent ) ->
@ -38,7 +36,7 @@ ErrorHandler = module.exports =
err: ( ex, shouldExit ) ->
# Short-circuit logging output if --silent is on
o = if this.silent then () -> else _defaultLog
o = if @silent then () -> else _defaultLog
# Special case; can probably be removed.
throw ex if ex.pass
@ -51,7 +49,7 @@ ErrorHandler = module.exports =
# Output the error message
objError = assembleError.call @, ex
o( this[ 'format_' + objError.etype ]( objError.msg ))
o( @[ 'format_' + objError.etype ]( objError.msg ))
# Output the stack (sometimes)
if objError.withStack
@ -59,20 +57,20 @@ ErrorHandler = module.exports =
stack && o( chalk.gray( stack ) );
# Quit if necessary
if ex.quit || objError.quit
if shouldExit
if @debug
o chalk.cyan('Exiting with error code ' + ex.fluenterror.toString())
if this.assert
if @assert
ex.pass = true
throw ex
process.exit ex.fluenterror
# Handle raw exceptions
else
o( ex )
o ex
stackTrace = ex.stack || (ex.inner && ex.inner.stack)
if stackTrace && this.debug
o( M2C(ex.stack || ex.inner.stack, 'gray') )
o M2C(ex.stack || ex.inner.stack, 'gray')
@ -139,7 +137,6 @@ assembleError = ( ex ) ->
when HMSTATUS.pdfGeneration
msg = M2C( this.msgs.pdfGeneration.msg, 'bold' )
msg += chalk.red('\n' + ex.inner) if ex.inner
withStack = true
quit = false
etype = 'error'
@ -205,16 +202,30 @@ assembleError = ( ex ) ->
etype = 'custom'
when HMSTATUS.parseError
if SyntaxErrorEx.is( ex.inner )
if SyntaxErrorEx.is ex.inner
console.error printf( M2C(this.msgs.readError.msg, 'red'), ex.file )
se = new SyntaxErrorEx ex, ex.raw
msg = printf M2C( this.msgs.parseError.msg, 'red' ), se.line, se.col
else if ex.inner && ex.inner.line != undefined && ex.inner.col != undefined
msg = printf( M2C( this.msgs.parseError.msg, 'red' ), ex.inner.line, ex.inner.col)
if se.line? and se.col?
msg = printf M2C( this.msgs.parseError.msg[0], 'red' ), se.line, se.col
else if se.line?
msg = printf M2C( this.msgs.parseError.msg[1], 'red' ), se.line
else
msg = M2C @msgs.parseError.msg[2], 'red'
else if ex.inner && ex.inner.line? && ex.inner.col?
msg = printf( M2C( this.msgs.parseError.msg[0], 'red' ), ex.inner.line, ex.inner.col)
else
msg = ex
etype = 'error'
when HMSTATUS.createError
# inner.code could be EPERM, EACCES, etc
msg = printf M2C( this.msgs.createError.msg ), ex.inner.path
etype = 'error'
when HMSTATUS.validateError
msg = printf M2C( @msgs.validateError.msg ), ex.inner.toString()
etype = 'error'
msg: msg # The error message to display
withStack: withStack # Whether to include the stack
quit: quit

22
src/cli/index.js Normal file
View File

@ -0,0 +1,22 @@
#! /usr/bin/env node
/**
Command-line interface (CLI) for HackMyResume.
@license MIT. See LICENSE.md for details.
@module index.js
*/
try {
require('./main')( process.argv );
}
catch( ex ) {
require('./error').err( ex, true );
}

View File

@ -6,23 +6,27 @@ Definition of the `main` function.
HMR = require '../hmc'
HMR = require '../index'
PKG = require '../../package.json'
FS = require 'fs'
EXTEND = require 'extend'
chalk = require 'chalk'
PATH = require 'path'
HMSTATUS = require '../hmc/dist/core/status-codes'
HME = require '../hmc/dist/core/event-codes'
safeLoadJSON = require '../hmc/dist/utils/safe-json-loader'
StringUtils = require '../hmc/dist/utils/string.js'
HMSTATUS = require '../core/status-codes'
HME = require '../core/event-codes'
safeLoadJSON = require '../utils/safe-json-loader'
StringUtils = require '../utils/string.js'
_ = require 'underscore'
OUTPUT = require './out'
PAD = require 'string-padding'
Command = require('commander').Command
M2C = require '../utils/md2chalk'
printf = require 'printf'
_opts = { }
_title = chalk.white.bold('\n*** HackMyResume v' +PKG.version+ ' ***')
_out = new OUTPUT( _opts )
_err = require('./error')
_exitCallback = null
@ -33,9 +37,9 @@ line interface as a single method accepting a parameter array.
@param rawArgs {Array} An array of command-line parameters. Will either be
process.argv (in production) or custom parameters (in test).
###
main = module.exports = (rawArgs) ->
main = module.exports = ( rawArgs, exitCallback ) ->
initInfo = initialize( rawArgs )
initInfo = initialize( rawArgs, exitCallback )
args = initInfo.args
# Create the top-level (application) command...
@ -124,15 +128,15 @@ main = module.exports = (rawArgs) ->
program.parse( args )
if !program.args.length
throw { fluenterror: 4 }
throw fluenterror: 4
### Massage command-line args and setup Commander.js. ###
initialize = ( ar ) ->
o = initOptions( ar );
initialize = ( ar, exitCallback ) ->
_exitCallback = exitCallback || process.exit
o = initOptions ar
o.silent || logMsg( _title )
# Emit debug prelude if --debug was specified
@ -147,14 +151,22 @@ initialize = ( ar ) ->
#_out.log(chalk.cyan(PAD(' fresh-jrs-converter:',25, null, PAD.RIGHT)) + chalk.cyan.bold( PKG.dependencies['fresh-jrs-converter'] ))
_out.log('')
_err.init o.debug, o.assert, o.silent
# Handle invalid verbs here (a bit easier here than in commander.js)...
if o.verb && !HMR.verbs[ o.verb ] && !HMR.alias[ o.verb ]
throw { fluenterror: HMSTATUS.invalidCommand, quit: true, attempted: o.orgVerb }
_err.err fluenterror: HMSTATUS.invalidCommand, quit: true, attempted: o.orgVerb, true
# Override the .missingArgument behavior
Command.prototype.missingArgument = (name) ->
if this.name() != 'new'
throw { fluenterror: HMSTATUS.resumeNotFound, quit: true }
_err.err
fluenterror:
if this.name() != 'new'
then HMSTATUS.resumeNotFound
else HMSTATUS.createNameMissing
, true
return
# Override the .helpInformation behavior
Command.prototype.helpInformation = ->
@ -205,23 +217,17 @@ initOptions = ( ar ) ->
oJSON = inf.json
# TODO: Error handling
# Grab the --debug flag
isDebug = _.some( args, (v) ->
return v == '-d' || v == '--debug'
)
# Grab the --silent flag
isSilent = _.some( args, (v) ->
return v == '-s' || v == '--silent'
)
# Grab the --no-color flag
# Grab the --debug flag, --silent, --assert and --no-color flags
isDebug = _.some args, (v) -> v == '-d' || v == '--debug'
isSilent = _.some args, (v) -> v == '-s' || v == '--silent'
isAssert = _.some args, (v) -> v == '-a' || v == '--assert'
isMono = _.some args, (v) -> v == '--no-color'
return {
color: !isMono,
debug: isDebug,
silent: isSilent,
assert: isAssert,
orgVerb: oVerb,
verb: verb,
json: oJSON,
@ -233,17 +239,45 @@ initOptions = ( ar ) ->
### Invoke a HackMyResume verb. ###
execute = ( src, dst, opts, log ) ->
# Create the verb
v = new HMR.verbs[ @name() ]()
# Initialize command-specific options
loadOptions.call( this, opts, this.parent.jsonArgs )
hand = require( './error' )
hand.init( _opts.debug, _opts.assert, _opts.silent )
v = new HMR.verbs[ this.name() ]()
# Set up error/output handling
_opts.errHandler = v
_out.init( _opts )
v.on( 'hmr:status', -> _out.do.apply( _out, arguments ) )
v.on( 'hmr:error', -> hand.err.apply( hand, arguments ) )
v.invoke.call( v, src, dst, _opts, log )
if v.errorCode
process.exit(v.errorCode)
_out.init _opts
# Hook up event notifications
v.on 'hmr:status', -> _out.do.apply _out, arguments
v.on 'hmr:error', -> _err.err.apply _err, arguments
# Invoke the verb using promise syntax
prom = v.invoke.call v, src, dst, _opts, log
prom.then executeSuccess, executeFail
return
### Success handler for verb invocations. Calls process.exit by default ###
executeSuccess = (obj) ->
# Can't call _exitCallback here (process.exit) when PDF is running in BK
#_exitCallback 0; return
### Failure handler for verb invocations. Calls process.exit by default ###
executeFail = (err) ->
finalErrorCode = -1
if err
finalErrorCode = if err.fluenterror then err.fluenterror else err
if _opts.debug
msgs = require('./msg').errors;
logMsg printf M2C( msgs.exiting.msg, 'cyan' ), finalErrorCode
logMsg err.stack if err.stack
_exitCallback finalErrorCode
return

View File

@ -3,6 +3,8 @@ events:
msg: Invoking **%s** command.
beforeCreate:
msg: Creating new **%s** resume: **%s**
afterCreate:
msg: Creating new **%s** resume: **%s**
afterRead:
msg: Reading **%s** resume: **%s**
beforeTheme:
@ -41,6 +43,8 @@ events:
- "VALID!"
- "INVALID"
- "BROKEN"
- "MISSING"
- "ERROR"
beforePeek:
msg:
- Peeking at **%s** in **%s**
@ -79,7 +83,10 @@ errors:
readError:
msg: Reading **???** resume: **%s**
parseError:
msg: Invalid or corrupt JSON on line %s column %s.
msg:
- Invalid or corrupt JSON on line %s column %s.
- Invalid or corrupt JSON on line %s.
- Invalid or corrupt JSON.
invalidHelperUse:
msg: "**Warning**: Incorrect use of the **%s** theme helper."
fileSaveError:
@ -96,3 +103,9 @@ errors:
msg: "Invalid number of parameters. Expected: **%s**."
missingParam:
msg: The '**%s**' parameter was needed but not supplied.
createError:
msg: Failed to create **'%s'**.
exiting:
msg: Exiting with status code **%s**.
validateError:
msg: "An error occurred during validation:\n%s"

View File

@ -7,10 +7,9 @@ Output routines for HackMyResume.
chalk = require('chalk')
HME = require('../hmc/dist/core/event-codes')
HME = require('../core/event-codes')
_ = require('underscore')
Class = require('../hmc/dist/utils/class.js')
M2C = require('../hmc/dist/utils/md2chalk.js')
M2C = require('../utils/md2chalk.js')
PATH = require('path')
LO = require('lodash')
FS = require('fs')
@ -22,11 +21,20 @@ pad = require('string-padding')
dbgStyle = 'cyan';
###* A stateful output module. All HMR console output handled here. ###
OutputHandler = module.exports = Class.extend
init: ( opts ) ->
@opts = EXTEND( true, this.opts || { }, opts )
###* A stateful output module. All HMR console output handled here. ###
module.exports = class OutputHandler
constructor: ( opts ) ->
@init opts
return
init: (opts) ->
@opts = EXTEND( true, @opts || { }, opts )
@msgs = YAML.load(PATH.join( __dirname, 'msg.yml' )).events
return
@ -39,6 +47,7 @@ OutputHandler = module.exports = Class.extend
@opts.silent || console.log( finished )
do: ( evt ) ->
that = @
@ -50,8 +59,12 @@ OutputHandler = module.exports = Class.extend
this.opts.debug &&
L( M2C( this.msgs.begin.msg, dbgStyle), evt.cmd.toUpperCase() )
when HME.beforeCreate
L( M2C( this.msgs.beforeCreate.msg, 'green' ), evt.fmt, evt.file )
#when HME.beforeCreate
#L( M2C( this.msgs.beforeCreate.msg, 'green' ), evt.fmt, evt.file )
#break;
when HME.afterCreate
L( M2C( @msgs.beforeCreate.msg, if evt.isError then 'red' else 'green' ), evt.fmt, evt.file )
break;
when HME.beforeTheme
@ -109,7 +122,7 @@ OutputHandler = module.exports = Class.extend
when HME.afterAnalyze
info = evt.info
rawTpl = FS.readFileSync( PATH.join( __dirname, 'analyze.hbs' ), 'utf8')
HANDLEBARS.registerHelper( require('../hmc/dist/helpers/console-helpers') )
HANDLEBARS.registerHelper( require('../helpers/console-helpers') )
template = HANDLEBARS.compile(rawTpl, { strict: false, assumeObjects: false })
tot = 0
info.keywords.forEach (g) -> tot += g.count
@ -127,29 +140,43 @@ OutputHandler = module.exports = Class.extend
evt.file, evt.fmt );
when HME.afterValidate
style = if evt.isValid then 'green' else 'yellow'
L(
M2C( this.msgs.afterValidate.msg[0], 'white' ) +
chalk[style].bold(
if evt.isValid
then this.msgs.afterValidate.msg[1]
else this.msgs.afterValidate.msg[2] ),
evt.file, evt.fmt
);
style = 'red'
adj = ''
msgs = @msgs.afterValidate.msg;
switch evt.status
when 'valid' then style = 'green'; adj = msgs[1]
when 'invalid' then style = 'yellow'; adj = msgs[2]
when 'broken' then style = 'red'; adj = msgs[3]
when 'missing' then style = 'red'; adj = msgs[4]
when 'unknown' then style = 'red'; adj = msgs[5]
evt.schema = evt.schema.replace('jars','JSON Resume').toUpperCase()
L(M2C( msgs[0], 'white' ) + chalk[style].bold(adj), evt.file, evt.schema)
if evt.errors
_.each( evt.errors, (err,idx) ->
L( chalk.yellow.bold('--> ') + chalk.yellow(err.field.replace('data.','resume.').toUpperCase() + ' ' + err.message))
, @)
if evt.violations
_.each evt.violations, (err,idx) ->
L( chalk.yellow.bold('--> ') +
chalk.yellow(err.field.replace('data.','resume.').toUpperCase() +
' ' + err.message))
return
, @
return
when HME.afterPeek
sty = if evt.error then 'red' else ( if evt.target != undefined then 'green' else 'yellow' )
# "Peeking at 'someKey' in 'someFile'."
if evt.requested
L(M2C(this.msgs.beforePeek.msg[0], sty), evt.requested, evt.file)
else
L(M2C(this.msgs.beforePeek.msg[1], sty), evt.file)
if evt.target != undefined
# If the key was present, print it
if evt.target != undefined and !evt.error
console.dir( evt.target, { depth: null, colors: true } )
# If the key was not present, but no error occurred, print it
else if !evt.error
L(M2C( this.msgs.afterPeek.msg, 'yellow'), evt.requested, evt.file);
L M2C( this.msgs.afterPeek.msg, 'yellow'), evt.requested, evt.file
else if evt.error
L chalk.red( evt.error.inner.inner )

View File

@ -0,0 +1,53 @@
###*
Definition of the AbstractResume class.
@license MIT. See LICENSE.md for details.
@module core/abstract-resume
###
_ = require 'underscore'
__ = require 'lodash'
FluentDate = require('./fluent-date')
class AbstractResume
###*
Compute the total duration of the work history.
@returns The total duration of the sheet's work history, that is, the number
of years between the start date of the earliest job on the resume and the
*latest end date of all jobs in the work history*. This last condition is for
sheets that have overlapping jobs.
###
duration: (collKey, startKey, endKey, unit) ->
unit = unit || 'years'
hist = __.get @, collKey
return 0 if !hist or !hist.length
# BEGIN CODE DUPLICATION --> src/inspectors/gap-inspector.coffee (TODO)
# Convert the candidate's employment history to an array of dates,
# where each element in the array is a start date or an end date of a
# job -- it doesn't matter which.
new_e = hist.map ( job ) ->
obj = _.pick( job, [startKey, endKey] )
# Synthesize an end date if this is a "current" gig
obj[endKey] = 'current' if !_.has obj, endKey
if obj && (obj[startKey] || obj[endKey])
obj = _.pairs obj
obj[0][1] = FluentDate.fmt( obj[0][1] )
if obj.length > 1
obj[1][1] = FluentDate.fmt( obj[1][1] )
obj
# Flatten the array, remove empties, and sort
new_e = _.filter _.flatten( new_e, true ), (v) ->
return v && v.length && v[0] && v[0].length
return 0 if !new_e or !new_e.length
new_e = _.sortBy new_e, ( elem ) -> return elem[1].unix()
# END CODE DUPLICATION
firstDate = _.first( new_e )[1];
lastDate = _.last( new_e )[1];
lastDate.diff firstDate, unit
module.exports = AbstractResume

View File

@ -0,0 +1,18 @@
###
Event code definitions.
@module core/default-formats
@license MIT. See LICENSE.md for details.
###
###* Supported resume formats. ###
module.exports = [
{ name: 'html', ext: 'html', gen: new (require('../generators/html-generator'))() },
{ name: 'txt', ext: 'txt', gen: new (require('../generators/text-generator'))() },
{ name: 'doc', ext: 'doc', fmt: 'xml', gen: new (require('../generators/word-generator'))() },
{ name: 'pdf', ext: 'pdf', fmt: 'html', is: false, gen: new (require('../generators/html-pdf-cli-generator'))() },
{ name: 'png', ext: 'png', fmt: 'html', is: false, gen: new (require('../generators/html-png-generator'))() },
{ name: 'md', ext: 'md', fmt: 'txt', gen: new (require('../generators/markdown-generator'))() },
{ name: 'json', ext: 'json', gen: new (require('../generators/json-generator'))() },
{ name: 'yml', ext: 'yml', fmt: 'yml', gen: new (require('../generators/json-yaml-generator'))() },
{ name: 'latex', ext: 'tex', fmt: 'latex', gen: new (require('../generators/latex-generator'))() }
]

View File

@ -0,0 +1,13 @@
###
Event code definitions.
@module core/default-options
@license MIT. See LICENSE.md for details.
###
module.exports =
theme: 'modern'
prettify: # ← See https://github.com/beautify-web/js-beautify#options
indent_size: 2
unformatted: ['em','strong']
max_char: 80, # ← See lib/html.js in above-linked repo
# wrap_line_length: 120, ← Don't use this

Some files were not shown because too many files have changed in this diff Show More