mirror of
				https://github.com/JuanCanham/HackMyResume.git
				synced 2025-11-03 22:37:27 +00:00 
			
		
		
		
	Compare commits
	
		
			1 Commits
		
	
	
		
			dev
			...
			juan-canha
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					901659cc4f | 
@@ -1,17 +0,0 @@
 | 
				
			|||||||
env:
 | 
					 | 
				
			||||||
  es6: true
 | 
					 | 
				
			||||||
  node: true
 | 
					 | 
				
			||||||
extends: 'eslint:recommended'
 | 
					 | 
				
			||||||
rules:
 | 
					 | 
				
			||||||
  # indent:
 | 
					 | 
				
			||||||
  #   - error
 | 
					 | 
				
			||||||
  #   - 4
 | 
					 | 
				
			||||||
  linebreak-style:
 | 
					 | 
				
			||||||
    - error
 | 
					 | 
				
			||||||
    - unix
 | 
					 | 
				
			||||||
  quotes:
 | 
					 | 
				
			||||||
    - error
 | 
					 | 
				
			||||||
    - single
 | 
					 | 
				
			||||||
  semi:
 | 
					 | 
				
			||||||
    - error
 | 
					 | 
				
			||||||
    - always
 | 
					 | 
				
			||||||
							
								
								
									
										6
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							@@ -1,11 +1,9 @@
 | 
				
			|||||||
# Auto detect text files and perform LF normalization
 | 
					# Auto detect text files and perform LF normalization
 | 
				
			||||||
 | 
					 | 
				
			||||||
* text=auto
 | 
					* text=auto
 | 
				
			||||||
*.js text eol=lf
 | 
					*.js text eol=lf
 | 
				
			||||||
*.json text eol=lf
 | 
					*.json text eol=lf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Standard to msysgit
 | 
					# Standard to msysgit
 | 
				
			||||||
 | 
					 | 
				
			||||||
*.doc	 diff=astextplain
 | 
					*.doc	 diff=astextplain
 | 
				
			||||||
*.DOC	 diff=astextplain
 | 
					*.DOC	 diff=astextplain
 | 
				
			||||||
*.docx diff=astextplain
 | 
					*.docx diff=astextplain
 | 
				
			||||||
@@ -16,7 +14,3 @@
 | 
				
			|||||||
*.PDF	 diff=astextplain
 | 
					*.PDF	 diff=astextplain
 | 
				
			||||||
*.rtf	 diff=astextplain
 | 
					*.rtf	 diff=astextplain
 | 
				
			||||||
*.RTF	 diff=astextplain
 | 
					*.RTF	 diff=astextplain
 | 
				
			||||||
 | 
					 | 
				
			||||||
# Git LFS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
*.ai filter=lfs diff=lfs merge=lfs -text
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,4 +1,5 @@
 | 
				
			|||||||
node_modules/
 | 
					node_modules/
 | 
				
			||||||
 | 
					tests/sandbox/
 | 
				
			||||||
doc/
 | 
					doc/
 | 
				
			||||||
docs/
 | 
					docs/
 | 
				
			||||||
local/
 | 
					local/
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,7 @@
 | 
				
			|||||||
 | 
					src/
 | 
				
			||||||
assets/
 | 
					assets/
 | 
				
			||||||
test/
 | 
					test/
 | 
				
			||||||
doc/
 | 
					doc/
 | 
				
			||||||
.travis.yml
 | 
					.travis.yml
 | 
				
			||||||
.eslintrc.yml
 | 
					 | 
				
			||||||
Gruntfile.js
 | 
					Gruntfile.js
 | 
				
			||||||
.gitattributes
 | 
					.gitattributes
 | 
				
			||||||
ROADMAP.md
 | 
					 | 
				
			||||||
BUILDING.md
 | 
					 | 
				
			||||||
CONTRIBUTING.md
 | 
					 | 
				
			||||||
CHANGELOG.md
 | 
					 | 
				
			||||||
FAQ.md
 | 
					 | 
				
			||||||
*.map
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										28
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								.travis.yml
									
									
									
									
									
								
							@@ -1,23 +1,9 @@
 | 
				
			|||||||
sudo: required
 | 
					 | 
				
			||||||
before_install:
 | 
					 | 
				
			||||||
  # Prevents a shared object .so error when running wkhtmltopdf on certain
 | 
					 | 
				
			||||||
  # platforms (e.g., vanilla Ubuntu 16.04 LTS). Not necessary on current Travis.
 | 
					 | 
				
			||||||
  # - sudo apt-get install libxrender1
 | 
					 | 
				
			||||||
install:
 | 
					 | 
				
			||||||
  # Install & link HackMyResume
 | 
					 | 
				
			||||||
  - npm install && npm link
 | 
					 | 
				
			||||||
  # Download and extract the latest wkhtmltopdf binaries
 | 
					 | 
				
			||||||
  - mkdir tmp && wget https://github.com/wkhtmltopdf/wkhtmltopdf/releases/download/0.12.4/wkhtmltox-0.12.4_linux-generic-amd64.tar.xz -O tmp/wk.tar.xz
 | 
					 | 
				
			||||||
  - tar -xf tmp/wk.tar.xz -C ./tmp
 | 
					 | 
				
			||||||
  # Copy wkhtmltopdf binaries to /usr/bin (also makes them path-accessible)
 | 
					 | 
				
			||||||
  - sudo cp -R ./tmp/wkhtmltox/bin/* /usr/bin/
 | 
					 | 
				
			||||||
  # Now you can invoke "wkhtmltopdf" and "wkhtmltoimage" safely in tests.
 | 
					 | 
				
			||||||
  - wkhtmltopdf -V
 | 
					 | 
				
			||||||
  - wkhtmltoimage -V
 | 
					 | 
				
			||||||
language: node_js
 | 
					language: node_js
 | 
				
			||||||
node_js:
 | 
					node_js:
 | 
				
			||||||
  - "6"
 | 
					  - "0.10"
 | 
				
			||||||
  - "7"
 | 
					  - "0.11"
 | 
				
			||||||
  - "8"
 | 
					  - "0.12"
 | 
				
			||||||
  - "9"
 | 
					  - "4.0"
 | 
				
			||||||
  - "lts/*"
 | 
					  - "4.1"
 | 
				
			||||||
 | 
					  - "4.2"
 | 
				
			||||||
 | 
					  - "5.0"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								BUILDING.md
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								BUILDING.md
									
									
									
									
									
								
							@@ -33,14 +33,22 @@ will reference your local installation (you may need to
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Making changes
 | 
					## Making changes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. HackMyResume sources live in the [`/src`][src] folder.
 | 
					1. HackMyResume sources live in the [`/src`][src] folder. Always make your edits
 | 
				
			||||||
 | 
					there, never in the generated `/dist` folder.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
2. When you're ready to submit your changes, run `grunt test` to run the HMR
 | 
					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.
 | 
					test suite. Fix any errors that occur.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
3. Commit and push your changes.
 | 
					5. Commit and push your changes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
4. Submit a pull request targeting the HackMyResume `dev` branch.
 | 
					6. Submit a pull request targeting the HackMyResume `dev` branch.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[node]: https://nodejs.org/en/
 | 
					[node]: https://nodejs.org/en/
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										96
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,96 +1,5 @@
 | 
				
			|||||||
CHANGELOG
 | 
					CHANGELOG
 | 
				
			||||||
=========
 | 
					=========
 | 
				
			||||||
 | 
					 | 
				
			||||||
## v1.9.0-beta
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
*Welcome to the first new version of HackMyResume in over a year. The purpose of
 | 
					 | 
				
			||||||
this release is to gather feature enhancements and bug fixes collected over the
 | 
					 | 
				
			||||||
past 18 months as we reorganize, rebrand, and prepare for the 2.0 release.*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Added
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Support for **private resume fields**. Mark any non-leaf node in your resume
 | 
					 | 
				
			||||||
JSON with the `private` property and it will be omitted from outbound resumes.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ```json
 | 
					 | 
				
			||||||
    "employment": {
 | 
					 | 
				
			||||||
      "history": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "employer": "Acme Real Estate"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "employer": "Area 51 Alien Research Laboratory",
 | 
					 | 
				
			||||||
          "private": true
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
          "employer": "H&R Block"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      ]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    ```
 | 
					 | 
				
			||||||
- Support for **PDF generation through WeasyPrint** in addition to the
 | 
					 | 
				
			||||||
existing support for wkhtmltopdf and PhantomJS.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Theme authors can now develop and package **custom Handlebars theme helpers**
 | 
					 | 
				
			||||||
via the `helpers` key of the `theme.json` file (FRESH themes only) (#158).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Help system has been updated with a `HELP` command and dedicated help pages
 | 
					 | 
				
			||||||
for each command.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Theme authors can **relocate theme assets** with the `baseFolder` property in
 | 
					 | 
				
			||||||
the FRESH `theme.json`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- HackMyResume will now **validate the options file** (if any) loaded with `-o`
 | 
					 | 
				
			||||||
or `--options` and warn the user if necessary.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Ability to **disable Handlebars encoding/escaping** of resume fields with
 | 
					 | 
				
			||||||
`--no-escape`.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Introduced the [fresh-test-themes][ftt] project as a repository for simple,
 | 
					 | 
				
			||||||
test-only resume themes in the FRESH format.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Changed
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Dropped support for Node 4 and 5. HackMyResume officially runs on Node 6+.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- The FRESCA project has been renamed to [fresh-resume-schema][fresca]. FRESCA
 | 
					 | 
				
			||||||
is still the nickname.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- The HackMyResume web page has moved to https://fluentdesk.com/hackmyresume.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Fixed
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Fixed an issue that would cause the `convert` command to detect the inbound
 | 
					 | 
				
			||||||
resume type (FRESH or JRS) incorrectly (#162).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Fixed an issue where generating new JRS resumes would cause a `null` or
 | 
					 | 
				
			||||||
`undefined` error (#165).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Fixed an issue preventing mixed-case themes from being loaded (#172).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Fixed an issue requiring JSON Resume themes contain `json-resume-theme` in the
 | 
					 | 
				
			||||||
theme path (#173).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Fixed an issue that would cause strange `@@@@` characters to appear in
 | 
					 | 
				
			||||||
generated resumes (#207, #168, #198).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Fixed an issue that would cause resume generation to hang after a JSON Resume
 | 
					 | 
				
			||||||
themed resume was generated (#182).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Fixed an issue that would cause nothing to be generated for Markdown (.md)
 | 
					 | 
				
			||||||
formats (#179).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Fixed an issue that would prevent a JRS resume from being converted to FRESH
 | 
					 | 
				
			||||||
via the `convert` command (#180).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Fixed an issue that would cause broken styling for JSON Resume themes (#155).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Internal
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Tests: fixed resume duration tests (#181).
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
- Style: move to
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## v1.8.0
 | 
					## v1.8.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Added
 | 
					### Added
 | 
				
			||||||
@@ -496,8 +405,7 @@ theme.
 | 
				
			|||||||
[i92]: https://github.com/hacksalot/HackMyResume/issues/92
 | 
					[i92]: https://github.com/hacksalot/HackMyResume/issues/92
 | 
				
			||||||
[i101]: https://github.com/hacksalot/HackMyResume/issues/101
 | 
					[i101]: https://github.com/hacksalot/HackMyResume/issues/101
 | 
				
			||||||
[i111]: https://github.com/hacksalot/HackMyResume/issues/111
 | 
					[i111]: https://github.com/hacksalot/HackMyResume/issues/111
 | 
				
			||||||
[fresca]: https://github.com/fresh-standard/fresh-resume-schema
 | 
					[fresca]: https://github.com/fluentdesk/FRESCA
 | 
				
			||||||
[themes]: https://github.com/fresh-standard/fresh-themes
 | 
					[themes]: https://github.com/fluentdesk/fresh-themes
 | 
				
			||||||
[awefork]: https://github.com/fluentdesk/Awesome-CV
 | 
					[awefork]: https://github.com/fluentdesk/Awesome-CV
 | 
				
			||||||
[acv]: https://github.com/posquit0/Awesome-CV
 | 
					[acv]: https://github.com/posquit0/Awesome-CV
 | 
				
			||||||
[ftt]: https://github.com/fresh-standard/fresh-test-themes
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ HackMyResume is currently maintained by [hacksalot][ha] with assistance from
 | 
				
			|||||||
or internal inquiries to:
 | 
					or internal inquiries to:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
admin@fluentdesk.com
 | 
					admin@hackmyresume.com
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can reach hacksalot directly at:
 | 
					You can reach hacksalot directly at:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										88
									
								
								Gruntfile.js
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								Gruntfile.js
									
									
									
									
									
								
							@@ -6,6 +6,28 @@ module.exports = function (grunt) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    pkg: grunt.file.readJSON('package.json'),
 | 
					    pkg: grunt.file.readJSON('package.json'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    copy: {
 | 
				
			||||||
 | 
					      main: {
 | 
				
			||||||
 | 
					        expand: true,
 | 
				
			||||||
 | 
					        cwd: 'src',
 | 
				
			||||||
 | 
					        src: ['**/*','!**/*.coffee'],
 | 
				
			||||||
 | 
					        dest: 'dist/',
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    coffee: {
 | 
				
			||||||
 | 
					      main: {
 | 
				
			||||||
 | 
					        options: {
 | 
				
			||||||
 | 
					          sourceMap: true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        expand: true,
 | 
				
			||||||
 | 
					        cwd: 'src',
 | 
				
			||||||
 | 
					        src: ['**/*.coffee'],
 | 
				
			||||||
 | 
					        dest: 'dist/',
 | 
				
			||||||
 | 
					        ext: '.js'
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    simplemocha: {
 | 
					    simplemocha: {
 | 
				
			||||||
      options: {
 | 
					      options: {
 | 
				
			||||||
        globals: ['expect', 'should'],
 | 
					        globals: ['expect', 'should'],
 | 
				
			||||||
@@ -17,29 +39,73 @@ module.exports = function (grunt) {
 | 
				
			|||||||
      all: { src: ['test/*.js'] }
 | 
					      all: { src: ['test/*.js'] }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    clean: {
 | 
					    jsdoc : {
 | 
				
			||||||
      test: ['test/sandbox']
 | 
					      dist : {
 | 
				
			||||||
 | 
					        src: ['src/**/*.js'],
 | 
				
			||||||
 | 
					        options: {
 | 
				
			||||||
 | 
					          private: true,
 | 
				
			||||||
 | 
					          destination: 'doc'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    eslint: {
 | 
					    clean: {
 | 
				
			||||||
      target: ['Gruntfile.js', 'src/**/*.js', 'test/*.js']
 | 
					      test: ['test/sandbox'],
 | 
				
			||||||
 | 
					      dist: ['dist']
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    yuidoc: {
 | 
				
			||||||
 | 
					      compile: {
 | 
				
			||||||
 | 
					        name: '<%= pkg.name %>',
 | 
				
			||||||
 | 
					        description: '<%= pkg.description %>',
 | 
				
			||||||
 | 
					        version: '<%= pkg.version %>',
 | 
				
			||||||
 | 
					        url: '<%= pkg.homepage %>',
 | 
				
			||||||
 | 
					        options: {
 | 
				
			||||||
 | 
					          paths: 'src/',
 | 
				
			||||||
 | 
					          outdir: 'docs/'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    jshint: {
 | 
				
			||||||
 | 
					      options: {
 | 
				
			||||||
 | 
					        laxcomma: true,
 | 
				
			||||||
 | 
					        expr: true,
 | 
				
			||||||
 | 
					        eqnull: true
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      all: ['Gruntfile.js', 'dist/cli/**/*.js', 'test/*.js']
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  grunt.initConfig( opts );
 | 
					  grunt.initConfig( opts );
 | 
				
			||||||
 | 
					  grunt.loadNpmTasks('grunt-contrib-coffee');
 | 
				
			||||||
 | 
					  grunt.loadNpmTasks('grunt-contrib-copy');
 | 
				
			||||||
  grunt.loadNpmTasks('grunt-simple-mocha');
 | 
					  grunt.loadNpmTasks('grunt-simple-mocha');
 | 
				
			||||||
  grunt.loadNpmTasks('grunt-eslint');
 | 
					  grunt.loadNpmTasks('grunt-contrib-yuidoc');
 | 
				
			||||||
 | 
					  grunt.loadNpmTasks('grunt-jsdoc');
 | 
				
			||||||
 | 
					  grunt.loadNpmTasks('grunt-contrib-jshint');
 | 
				
			||||||
  grunt.loadNpmTasks('grunt-contrib-clean');
 | 
					  grunt.loadNpmTasks('grunt-contrib-clean');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Use 'grunt test' for local testing
 | 
					  // Use 'grunt test' for local testing
 | 
				
			||||||
  grunt.registerTask('test', 'Test the HackMyResume application.',
 | 
					  grunt.registerTask('test', 'Test the HackMyResume application.',
 | 
				
			||||||
    function() {
 | 
					    function( config ) {
 | 
				
			||||||
      grunt.task.run(['clean:test','eslint','simplemocha:all']);
 | 
					      grunt.task.run(['clean:test','build','jshint','simplemocha:all']);
 | 
				
			||||||
    }
 | 
					    });
 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Default task - nothing to do but test
 | 
					  // Use 'grunt document' to build docs
 | 
				
			||||||
  grunt.registerTask('default', [ 'test' ]);
 | 
					  grunt.registerTask('document', 'Generate HackMyResume documentation.',
 | 
				
			||||||
 | 
					    function( config ) {
 | 
				
			||||||
 | 
					      grunt.task.run( ['jsdoc'] );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Use 'grunt build' to build HMR
 | 
				
			||||||
 | 
					  grunt.registerTask('build', 'Build the HackMyResume application.',
 | 
				
			||||||
 | 
					    function( config ) {
 | 
				
			||||||
 | 
					      grunt.task.run( ['clean:dist','copy','coffee'] );
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Default task does everything
 | 
				
			||||||
 | 
					  grunt.registerTask('default', [ 'test', 'document' ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								LICENSE.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								LICENSE.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					The MIT License
 | 
				
			||||||
 | 
					===============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					in the Software without restriction, including without limitation the rights
 | 
				
			||||||
 | 
					to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
				
			||||||
 | 
					copies of the Software, and to permit persons to whom the Software is
 | 
				
			||||||
 | 
					furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The above copyright notice and this permission notice shall be included in
 | 
				
			||||||
 | 
					all copies or substantial portions of the Software.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
				
			||||||
 | 
					AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
				
			||||||
 | 
					OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
				
			||||||
 | 
					THE SOFTWARE.
 | 
				
			||||||
							
								
								
									
										21
									
								
								LICENSE.txt
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								LICENSE.txt
									
									
									
									
									
								
							@@ -1,21 +0,0 @@
 | 
				
			|||||||
The MIT License
 | 
					 | 
				
			||||||
===============
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Copyright (c) 2015-2018
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
					 | 
				
			||||||
this software and associated documentation files (the "Software"), to deal in
 | 
					 | 
				
			||||||
the Software without restriction, including without limitation the rights to
 | 
					 | 
				
			||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 | 
					 | 
				
			||||||
the Software, and to permit persons to whom the Software is furnished to do so,
 | 
					 | 
				
			||||||
subject to the following conditions:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The above copyright notice and this permission notice shall be included in all
 | 
					 | 
				
			||||||
copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 | 
					 | 
				
			||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 | 
					 | 
				
			||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 | 
					 | 
				
			||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | 
					 | 
				
			||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
					 | 
				
			||||||
							
								
								
									
										219
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										219
									
								
								README.md
									
									
									
									
									
								
							@@ -1,17 +1,17 @@
 | 
				
			|||||||
HackMyResume
 | 
					HackMyResume
 | 
				
			||||||
===
 | 
					============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[![Latest release][img-release]][latest-release]
 | 
					[![Latest release][img-release]][latest-release]
 | 
				
			||||||
[![Build status (MASTER)][img-master]][travis-url-master]
 | 
					[![Build status (MASTER)][img-master]][travis-url-master]
 | 
				
			||||||
[![Build status (DEV)][img-dev]][travis-url-dev]
 | 
					[![Build status (DEV)][img-dev]][travis-url-dev]
 | 
				
			||||||
[![Join the chat at https://gitter.im/hacksalot/HackMyResume][badge]][gh]
 | 
					[](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
 | 
					*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,
 | 
					shell. Author in clean Markdown and JSON, export to Word, HTML, PDF, LaTeX,
 | 
				
			||||||
plain text, and other arbitrary formats. Fight the power, save trees. Compatible
 | 
					plain text, and other arbitrary formats. Fight the power, save trees. Compatible
 | 
				
			||||||
with [FRESH][fresca] and [JRS][6] resumes.*
 | 
					with [FRESH][fresca] and [JRS][6] resumes.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HackMyResume is a dev-friendly, local-only Swiss Army knife for resumes and CVs.
 | 
					HackMyResume is a dev-friendly, local-only Swiss Army knife for resumes and CVs.
 | 
				
			||||||
Use it to:
 | 
					Use it to:
 | 
				
			||||||
@@ -27,8 +27,6 @@ metrics.
 | 
				
			|||||||
HackMyResume is built with Node.js and runs on recent versions of OS X, Linux,
 | 
					HackMyResume is built with Node.js and runs on recent versions of OS X, Linux,
 | 
				
			||||||
or Windows. View the [FAQ](FAQ.md).
 | 
					or Windows. View the [FAQ](FAQ.md).
 | 
				
			||||||
 | 
					
 | 
				
			||||||

 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Features
 | 
					## Features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- OS X, Linux, and Windows.
 | 
					- OS X, Linux, and Windows.
 | 
				
			||||||
@@ -64,9 +62,9 @@ Alternately, install the latest bleeding-edge version (updated daily):
 | 
				
			|||||||
HackMyResume tries not to impose a specific PDF engine requirement on
 | 
					HackMyResume tries not to impose a specific PDF engine requirement on
 | 
				
			||||||
the user, but will instead work with whatever PDF engines you have installed.
 | 
					the user, but will instead work with whatever PDF engines you have installed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Currently, HackMyResume's PDF generation requires one of [Phantom.js][2],
 | 
					Currently, HackMyResume's PDF generation requires either [Phantom.js][2] or
 | 
				
			||||||
[wkhtmltopdf][3], or [WeasyPrint][11] to be installed on your system and the
 | 
					[wkhtmltopdf][3] to be installed on your system and the `phantomjs` and/or
 | 
				
			||||||
corresponding binary to be accessible on your PATH. This is an optional
 | 
					`wkhtmltopdf` binaries to be accessible on your PATH. This is an optional
 | 
				
			||||||
requirement for users who care about PDF formats. If you don't care about PDF
 | 
					requirement for users who care about PDF formats. If you don't care about PDF
 | 
				
			||||||
formats, skip this step.
 | 
					formats, skip this step.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,7 +91,7 @@ Then when you're ready to generate your resume, just reference the location of
 | 
				
			|||||||
the theme folder as you installed it:
 | 
					the theme folder as you installed it:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume build resume.json TO out/resume.all -t node_modules/jsonresume-theme-classy
 | 
					hackmyresume BUILD resume.json TO out/resume.all -t node_modules/jsonresume-theme-classy
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Note: You can use install themes anywhere on your file system. You don't need a
 | 
					Note: You can use install themes anywhere on your file system. You don't need a
 | 
				
			||||||
@@ -110,26 +108,26 @@ Use it when you need to submit, upload, print, or email resumes in specific
 | 
				
			|||||||
formats.
 | 
					formats.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ```bash
 | 
					    ```bash
 | 
				
			||||||
    # hackmyresume build <INPUTS...> TO <OUTPUTS...> [-t THEME]
 | 
					    # hackmyresume BUILD <INPUTS...> TO <OUTPUTS...> [-t THEME]
 | 
				
			||||||
    hackmyresume build resume.json TO out/resume.all
 | 
					    hackmyresume BUILD resume.json TO out/resume.all
 | 
				
			||||||
    hackmyresume build r1.json r2.json TO out/rez.html out/rez.md foo/rez.all
 | 
					    hackmyresume BUILD r1.json r2.json TO out/rez.html out/rez.md foo/rez.all
 | 
				
			||||||
    ```
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **new** creates a new resume in FRESH or JSON Resume format.
 | 
					- **new** creates a new resume in FRESH or JSON Resume format.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ```bash
 | 
					    ```bash
 | 
				
			||||||
    # hackmyresume new <OUTPUTS...> [-f <FORMAT>]
 | 
					    # hackmyresume NEW <OUTPUTS...> [-f <FORMAT>]
 | 
				
			||||||
    hackmyresume new resume.json
 | 
					    hackmyresume NEW resume.json
 | 
				
			||||||
    hackmyresume new resume.json -f fresh
 | 
					    hackmyresume NEW resume.json -f fresh
 | 
				
			||||||
    hackmyresume new r1.json r2.json -f jrs
 | 
					    hackmyresume NEW r1.json r2.json -f jrs
 | 
				
			||||||
    ```
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **analyze** inspects your resume for keywords, duration, and other metrics.
 | 
					- **analyze** inspects your resume for keywords, duration, and other metrics.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ```bash
 | 
					    ```bash
 | 
				
			||||||
    # hackmyresume analyze <INPUTS...>
 | 
					    # hackmyresume ANALYZE <INPUTS...>
 | 
				
			||||||
    hackmyresume analyze resume.json
 | 
					    hackmyresume ANALYZE resume.json
 | 
				
			||||||
    hackmyresume analyze r1.json r2.json
 | 
					    hackmyresume ANALYZE r1.json r2.json
 | 
				
			||||||
    ```
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **convert** converts your source resume between FRESH and JSON Resume
 | 
					- **convert** converts your source resume between FRESH and JSON Resume
 | 
				
			||||||
@@ -137,29 +135,29 @@ formats. Use it to convert between the two formats to take advantage of tools
 | 
				
			|||||||
and services.
 | 
					and services.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ```bash
 | 
					    ```bash
 | 
				
			||||||
    # hackmyresume convert <INPUTS...> TO <OUTPUTS...>
 | 
					    # hackmyresume CONVERT <INPUTS...> TO <OUTPUTS...>
 | 
				
			||||||
    hackmyresume convert resume.json TO resume-jrs.json
 | 
					    hackmyresume CONVERT resume.json TO resume-jrs.json
 | 
				
			||||||
    hackmyresume convert 1.json 2.json 3.json TO out/1.json out/2.json out/3.json
 | 
					    hackmyresume CONVERT 1.json 2.json 3.json TO out/1.json out/2.json out/3.json
 | 
				
			||||||
    ```
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **validate** validates the specified resume against either the FRESH or JSON
 | 
					- **validate** validates the specified resume against either the FRESH or JSON
 | 
				
			||||||
Resume schema. Use it to make sure your resume data is sufficient and complete.
 | 
					Resume schema. Use it to make sure your resume data is sufficient and complete.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ```bash
 | 
					    ```bash
 | 
				
			||||||
    # hackmyresume validate <INPUTS...>
 | 
					    # hackmyresume VALIDATE <INPUTS...>
 | 
				
			||||||
    hackmyresume validate resume.json
 | 
					    hackmyresume VALIDATE resume.json
 | 
				
			||||||
    hackmyresume validate r1.json r2.json r3.json
 | 
					    hackmyresume VALIDATE r1.json r2.json r3.json
 | 
				
			||||||
    ```
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **peek** echoes your resume or any field, property, or object path on your
 | 
					- **peek** echoes your resume or any field, property, or object path on your
 | 
				
			||||||
resume to standard output.
 | 
					resume to standard output.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ```bash
 | 
					    ```bash
 | 
				
			||||||
    # hackmyresume peek <INPUTS...> [OBJECT-PATH]
 | 
					    # hackmyresume PEEK <INPUTS...> [OBJECT-PATH]
 | 
				
			||||||
    hackmyresume peek rez.json # Echo the whole resume
 | 
					    hackmyresume PEEK rez.json # Echo the whole resume
 | 
				
			||||||
    hackmyresume peek rez.json info.brief # Echo the "info.brief" field
 | 
					    hackmyresume PEEK rez.json info.brief # Echo the "info.brief" field
 | 
				
			||||||
    hackmyresume peek rez.json employment.history[1] # Echo the 1st job
 | 
					    hackmyresume PEEK rez.json employment.history[1] # Echo the 1st job
 | 
				
			||||||
    hackmyresume peek rez.json rez2.json info.brief # Compare value
 | 
					    hackmyresume PEEK rez.json rez2.json info.brief # Compare value
 | 
				
			||||||
    ```    
 | 
					    ```    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Supported Output Formats
 | 
					## Supported Output Formats
 | 
				
			||||||
@@ -186,7 +184,7 @@ Assuming you've got a JSON-formatted resume handy, generating resumes in
 | 
				
			|||||||
different formats and combinations is easy. Just run:
 | 
					different formats and combinations is easy. Just run:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume build <inputs> to <outputs> [-t theme].
 | 
					hackmyresume BUILD <INPUTS> <OUTPUTS> [-t theme].
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Where `<INPUTS>` is one or more .json resume files, separated by spaces;
 | 
					Where `<INPUTS>` is one or more .json resume files, separated by spaces;
 | 
				
			||||||
@@ -195,19 +193,19 @@ theme (default to Modern). For example:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
# Generate all resume formats (HTML, PDF, DOC, TXT, YML, etc.)
 | 
					# Generate all resume formats (HTML, PDF, DOC, TXT, YML, etc.)
 | 
				
			||||||
hackmyresume build resume.json TO out/resume.all -t modern
 | 
					hackmyresume BUILD resume.json TO out/resume.all -t modern
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Generate a specific resume format
 | 
					# Generate a specific resume format
 | 
				
			||||||
hackmyresume build resume.json TO out/resume.html
 | 
					hackmyresume BUILD resume.json TO out/resume.html
 | 
				
			||||||
hackmyresume build resume.json TO out/resume.pdf
 | 
					hackmyresume BUILD resume.json TO out/resume.pdf
 | 
				
			||||||
hackmyresume build resume.json TO out/resume.md
 | 
					hackmyresume BUILD resume.json TO out/resume.md
 | 
				
			||||||
hackmyresume build resume.json TO out/resume.doc
 | 
					hackmyresume BUILD resume.json TO out/resume.doc
 | 
				
			||||||
hackmyresume build resume.json TO out/resume.json
 | 
					hackmyresume BUILD resume.json TO out/resume.json
 | 
				
			||||||
hackmyresume build resume.json TO out/resume.txt
 | 
					hackmyresume BUILD resume.json TO out/resume.txt
 | 
				
			||||||
hackmyresume build resume.json TO out/resume.yml
 | 
					hackmyresume BUILD resume.json TO out/resume.yml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Specify 2 inputs and 3 outputs
 | 
					# Specify 2 inputs and 3 outputs
 | 
				
			||||||
hackmyresume build in1.json in2.json TO out.html out.doc out.pdf
 | 
					hackmyresume BUILD in1.json in2.json TO out.html out.doc out.pdf
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You should see something to the effect of:
 | 
					You should see something to the effect of:
 | 
				
			||||||
@@ -234,16 +232,16 @@ installed first). To specify a theme when generating your resume, use the `-t`
 | 
				
			|||||||
or `--theme` parameter:
 | 
					or `--theme` parameter:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume build resume.json TO out/rez.all -t [theme]
 | 
					hackmyresume BUILD resume.json TO out/rez.all -t [theme]
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The `[theme]` parameter can be the name of a predefined theme OR the path to any
 | 
					The `[theme]` parameter can be the name of a predefined theme OR the path to any
 | 
				
			||||||
FRESH or JSON Resume theme folder:
 | 
					FRESH or JSON Resume theme folder:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume build resume.json TO out/rez.all -t modern
 | 
					hackmyresume BUILD resume.json TO out/rez.all -t modern
 | 
				
			||||||
hackmyresume build resume.json TO OUT.rez.all -t ../some-folder/my-custom-theme/
 | 
					hackmyresume BUILD resume.json TO OUT.rez.all -t ../some-folder/my-custom-theme/
 | 
				
			||||||
hackmyresume build resume.json TO OUT.rez.all -t node_modules/jsonresume-theme-classy
 | 
					hackmyresume BUILD resume.json TO OUT.rez.all -t node_modules/jsonresume-theme-classy
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FRESH themes are currently pre-installed with HackMyResume. JSON Resume themes
 | 
					FRESH themes are currently pre-installed with HackMyResume. JSON Resume themes
 | 
				
			||||||
@@ -267,7 +265,7 @@ most generic to most specific:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
# Merge specific.json onto base.json and generate all formats
 | 
					# Merge specific.json onto base.json and generate all formats
 | 
				
			||||||
hackmyresume build base.json specific.json TO resume.all
 | 
					hackmyresume BUILD base.json specific.json TO resume.all
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This can be useful for overriding a base (generic) resume with information from
 | 
					This can be useful for overriding a base (generic) resume with information from
 | 
				
			||||||
@@ -278,7 +276,7 @@ resume. Merging follows conventional [extend()][9]-style behavior and there's
 | 
				
			|||||||
no arbitrary limit to how many resumes you can merge:
 | 
					no arbitrary limit to how many resumes you can merge:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume build in1.json in2.json in3.json in4.json TO out.html out.doc
 | 
					hackmyresume BUILD in1.json in2.json in3.json in4.json TO out.html out.doc
 | 
				
			||||||
Reading JSON resume: in1.json
 | 
					Reading JSON resume: in1.json
 | 
				
			||||||
Reading JSON resume: in2.json
 | 
					Reading JSON resume: in2.json
 | 
				
			||||||
Reading JSON resume: in3.json
 | 
					Reading JSON resume: in3.json
 | 
				
			||||||
@@ -294,7 +292,7 @@ You can specify **multiple output targets** and HackMyResume will build them:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
# Generate out1.doc, out1.pdf, and foo.txt from me.json.
 | 
					# Generate out1.doc, out1.pdf, and foo.txt from me.json.
 | 
				
			||||||
hackmyresume build me.json TO out1.doc out1.pdf foo.txt
 | 
					hackmyresume BUILD me.json TO out1.doc out1.pdf foo.txt
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Using .all
 | 
					### Using .all
 | 
				
			||||||
@@ -304,7 +302,7 @@ formats for the given resume. For example, this...
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
# Generate all resume formats (HTML, PDF, DOC, TXT, etc.)
 | 
					# Generate all resume formats (HTML, PDF, DOC, TXT, etc.)
 | 
				
			||||||
hackmyresume build me.json TO out/resume.all
 | 
					hackmyresume BUILD me.json TO out/resume.all
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
..tells HackMyResume to read `me.json` and generate `out/resume.md`,
 | 
					..tells HackMyResume to read `me.json` and generate `out/resume.md`,
 | 
				
			||||||
@@ -319,21 +317,19 @@ and formats with the `--pdf none` switch.*
 | 
				
			|||||||
HackMyResume takes a unique approach to PDF generation. Instead of enforcing
 | 
					HackMyResume takes a unique approach to PDF generation. Instead of enforcing
 | 
				
			||||||
a specific PDF engine on users, HackMyResume will attempt to work with whatever
 | 
					a specific PDF engine on users, HackMyResume will attempt to work with whatever
 | 
				
			||||||
PDF engine you have installed through the engine's command-line interface (CLI).
 | 
					PDF engine you have installed through the engine's command-line interface (CLI).
 | 
				
			||||||
Currently that means any of...
 | 
					Currently that means one or both of...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- [wkhtmltopdf][3]
 | 
					- [wkhtmltopdf][3]
 | 
				
			||||||
- [Phantom.js][2]
 | 
					- [Phantom.js][3]
 | 
				
			||||||
- [WeasyPrint][11]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
..with support for other engines planned in the future. But for now, **one or
 | 
					..with support for other engines planned in the future. But for now, **one or
 | 
				
			||||||
more of these engines must be installed and accessible on your PATH in order
 | 
					both of these engines must be installed and accessible on your PATH in order to
 | 
				
			||||||
to generate PDF resumes with HackMyResume**. That means you should be able to
 | 
					generate PDF resumes with HackMyResume**. That means you should be able to
 | 
				
			||||||
invoke either of these tools directly from your shell or terminal without error:
 | 
					invoke either of these tools directly from your shell or terminal without error:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
wkhtmltopdf input.html output.pdf
 | 
					wkhtmltopdf input.html output.pdf
 | 
				
			||||||
phantomjs script.js input.html output.pdf
 | 
					phantomjs script.js input.html output.pdf
 | 
				
			||||||
weasyprint input.html output.pdf
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Assuming you've installed one or both of these engines on your system, you can
 | 
					Assuming you've installed one or both of these engines on your system, you can
 | 
				
			||||||
@@ -341,10 +337,9 @@ tell HackMyResume which flavor of PDF generation to use via the `--pdf` option
 | 
				
			|||||||
(`-p` for short):
 | 
					(`-p` for short):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume build resume.json TO out.all --pdf phantom
 | 
					hackmyresume BUILD resume.json TO out.all --pdf phantom
 | 
				
			||||||
hackmyresume build resume.json TO out.all --pdf wkhtmltopdf
 | 
					hackmyresume BUILD resume.json TO out.all --pdf wkhtmltopdf
 | 
				
			||||||
hackmyresume build resume.json TO out.all --pdf weasyprint
 | 
					hackmyresume BUILD resume.json TO out.all --pdf none
 | 
				
			||||||
hackmyresume build resume.json TO out.all --pdf none
 | 
					 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Analyzing
 | 
					### Analyzing
 | 
				
			||||||
@@ -353,7 +348,7 @@ HackMyResume can analyze your resume for keywords, employment gaps, and other
 | 
				
			|||||||
metrics. Run:
 | 
					metrics. Run:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume analyze <my-resume>.json
 | 
					hackmyresume ANALYZE <my-resume>.json
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Depending on the HackMyResume version, you should see output similar to:
 | 
					Depending on the HackMyResume version, you should see output similar to:
 | 
				
			||||||
@@ -450,7 +445,7 @@ resumes, use the `validate` command:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
# Validate myresume.json against either the FRESH or JSON Resume schema.
 | 
					# Validate myresume.json against either the FRESH or JSON Resume schema.
 | 
				
			||||||
hackmyresume validate resumeA.json resumeB.json
 | 
					hackmyresume VALIDATE resumeA.json resumeB.json
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HackMyResume will validate each specified resume in turn:
 | 
					HackMyResume will validate each specified resume in turn:
 | 
				
			||||||
@@ -467,7 +462,7 @@ HackMyResume can convert between the [FRESH][fresca] and [JSON Resume][6]
 | 
				
			|||||||
formats. Just run:
 | 
					formats. Just run:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume convert <INPUTS> <OUTPUTS>
 | 
					hackmyresume CONVERT <INPUTS> <OUTPUTS>
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
where <INPUTS> is one or more resumes in FRESH or JSON Resume format, and
 | 
					where <INPUTS> is one or more resumes in FRESH or JSON Resume format, and
 | 
				
			||||||
@@ -481,34 +476,31 @@ You can pass options into HackMyResume via an external options or ".hackmyrc"
 | 
				
			|||||||
file with the `--options` or `-o` switch:
 | 
					file with the `--options` or `-o` switch:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume build resume.json -o path/to/options.json
 | 
					hackmyresume BUILD resume.json -o path/to/options.json
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The options file can contain any documented HackMyResume option, including
 | 
					The options file can contain any documented HackMyResume option, including
 | 
				
			||||||
`theme`, `silent`, `debug`, `pdf`, `css`, and other settings.
 | 
					`theme`, `silent`, `debug`, `pdf`, `css`, and other settings.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```json
 | 
					```javascript
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					  // Set the default theme to "compact"
 | 
				
			||||||
  "theme": "compact",
 | 
					  "theme": "compact",
 | 
				
			||||||
 | 
					  // Change the "employment" section title text to "Work"
 | 
				
			||||||
  "sectionTitles": {
 | 
					  "sectionTitles": {
 | 
				
			||||||
    "employment": "Work"
 | 
					    "employment": "Work"
 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  "wkhtmltopdf": {
 | 
					 | 
				
			||||||
    "margin-top": "20mm"
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If an option is specified on both the command line and in an external options
 | 
					If a particular option is specified both on the command line and in an external
 | 
				
			||||||
file, the command-line option wins.
 | 
					options file, the explicit command-line option takes precedence.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
# path/to/options.json specifes the POSITIVE theme
 | 
					# path/to/options.json specifes the POSITIVE theme
 | 
				
			||||||
# -t parameter specifies the COMPACT theme
 | 
					# -t parameter specifies the COMPACT theme
 | 
				
			||||||
# The -t parameter wins.
 | 
					# The -t parameter wins.
 | 
				
			||||||
hackmyresume build resume.json -o path/to/options.json -t compact
 | 
					hackmyresume BUILD resume.json -o path/to/options.json -t compact
 | 
				
			||||||
> Reading resume: resume.json
 | 
					> Reading resume: resume.json
 | 
				
			||||||
> Applying COMPACT theme (7 formats)
 | 
					> Applying COMPACT theme (7 formats)
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
@@ -520,7 +512,7 @@ HTML-formatted resumes. To disable prettification, the `--no-prettify` or `-n`
 | 
				
			|||||||
flag can be used:
 | 
					flag can be used:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume build resume.json out.all --no-prettify
 | 
					hackmyresume BUILD resume.json out.all --no-prettify
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Silent Mode
 | 
					### Silent Mode
 | 
				
			||||||
@@ -528,8 +520,8 @@ hackmyresume build resume.json out.all --no-prettify
 | 
				
			|||||||
Use `-s` or `--silent` to run in silent mode:
 | 
					Use `-s` or `--silent` to run in silent mode:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume build resume.json -o someFile.all -s
 | 
					hackmyresume BUILD resume.json -o someFile.all -s
 | 
				
			||||||
hackmyresume build resume.json -o someFile.all --silent
 | 
					hackmyresume BUILD resume.json -o someFile.all --silent
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Debug Mode
 | 
					### Debug Mode
 | 
				
			||||||
@@ -538,80 +530,15 @@ Use `-d` or `--debug` to force HMR to emit a call stack when errors occur. In
 | 
				
			|||||||
the future, this option will emit detailed error logging.
 | 
					the future, this option will emit detailed error logging.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```bash
 | 
					```bash
 | 
				
			||||||
hackmyresume build resume.json -d
 | 
					hackmyresume BUILD resume.json -d
 | 
				
			||||||
hackmyresume analyze resume.json --debug
 | 
					hackmyresume ANALYZE resume.json --debug
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Disable Encoding
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Use the `--no-escape` option to disable encoding in Handlebars themes. Note:
 | 
					 | 
				
			||||||
this option has no effect for non-Handlebars themes.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
hackmyresume build resume.json --no-escape
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Private Resume Fields
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Have a gig, education stint, membership, or other relevant history that you'd
 | 
					 | 
				
			||||||
like to hide from *most* (e.g. public) resumes but sometimes show on others? Tag it with
 | 
					 | 
				
			||||||
`"private": true` to omit it from outbound generated resumes by default.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```json
 | 
					 | 
				
			||||||
"employment": {
 | 
					 | 
				
			||||||
  "history": [
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "employer": "Acme Real Estate"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "employer": "Area 51 Alien Research Laboratory",
 | 
					 | 
				
			||||||
      "private": true
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "employer": "H&R Block"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  ]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Then, when you want a copy of your resume that includes the private gig / stint
 | 
					 | 
				
			||||||
/ etc., tell HackMyResume that it's OK to emit private fields. The way you do
 | 
					 | 
				
			||||||
that is with the `--private` switch.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```bash
 | 
					 | 
				
			||||||
hackmyresume build resume.json private-resume.all --private
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
### Custom theme helpers
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
You can attach your own custom Handlebars helpers to a FRESH theme with the
 | 
					 | 
				
			||||||
`helpers` key of your theme's `theme.json` file.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
```js
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
  "title": "my-cool-theme",
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // ...
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  "helpers": [
 | 
					 | 
				
			||||||
    "../path/to/helpers/*.js",
 | 
					 | 
				
			||||||
    "some-other-helper.js"
 | 
					 | 
				
			||||||
  ]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
```
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
HackMyResume will attempt to load each path or glob and register any specified
 | 
					 | 
				
			||||||
files with [Handlebars.registerHelper][hrh], making them available to your
 | 
					 | 
				
			||||||
theme.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Contributing
 | 
					## Contributing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
HackMyResume is a community-driven free and open source project under the MIT
 | 
					HackMyResume is a community-driven free and open source project under the MIT
 | 
				
			||||||
License. Contributions are encouraged and we respond to all PRs and issues in
 | 
					License. Contributions are encouraged and we respond to all PRs and issues,
 | 
				
			||||||
time. See [CONTRIBUTING.md][contribute] for details.
 | 
					usually within 24 hours. See [CONTRIBUTING.md][contribute] for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## License
 | 
					## License
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -627,9 +554,8 @@ MIT. Go crazy. See [LICENSE.md][1] for details.
 | 
				
			|||||||
[8]: https://youtu.be/N9wsjroVlu8
 | 
					[8]: https://youtu.be/N9wsjroVlu8
 | 
				
			||||||
[9]: https://api.jquery.com/jquery.extend/
 | 
					[9]: https://api.jquery.com/jquery.extend/
 | 
				
			||||||
[10]: https://github.com/beautify-web/js-beautify
 | 
					[10]: https://github.com/beautify-web/js-beautify
 | 
				
			||||||
[11]: http://weasyprint.org/
 | 
					 | 
				
			||||||
[fresh]: https://github.com/fluentdesk/FRESH
 | 
					[fresh]: https://github.com/fluentdesk/FRESH
 | 
				
			||||||
[fresca]: https://github.com/fresh-standard/fresh-resume-schema
 | 
					[fresca]: https://github.com/fluentdesk/FRESCA
 | 
				
			||||||
[dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
 | 
					[dry]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
 | 
				
			||||||
[img-release]: https://img.shields.io/github/release/hacksalot/HackMyResume.svg?label=version
 | 
					[img-release]: https://img.shields.io/github/release/hacksalot/HackMyResume.svg?label=version
 | 
				
			||||||
[img-master]: https://img.shields.io/travis/hacksalot/HackMyResume/master.svg
 | 
					[img-master]: https://img.shields.io/travis/hacksalot/HackMyResume/master.svg
 | 
				
			||||||
@@ -640,6 +566,3 @@ MIT. Go crazy. See [LICENSE.md][1] for details.
 | 
				
			|||||||
[contribute]: CONTRIBUTING.md
 | 
					[contribute]: CONTRIBUTING.md
 | 
				
			||||||
[fresh-themes]: https://github.com/fluentdesk/fresh-themes
 | 
					[fresh-themes]: https://github.com/fluentdesk/fresh-themes
 | 
				
			||||||
[jrst]: https://www.npmjs.com/search?q=jsonresume-theme
 | 
					[jrst]: https://www.npmjs.com/search?q=jsonresume-theme
 | 
				
			||||||
[gh]: https://gitter.im/hacksalot/HackMyResume?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
 | 
					 | 
				
			||||||
[badge]: https://badges.gitter.im/hacksalot/HackMyResume.svg
 | 
					 | 
				
			||||||
[hrh]: http://handlebarsjs.com/reference.html#base-registerHelper
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								assets/hackmyresume.cli.1.6.0.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/hackmyresume.cli.1.6.0.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 83 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								assets/hackmyresume_cli.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/hackmyresume_cli.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 83 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 20 KiB  | 
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 18 KiB  | 
@@ -1,3 +0,0 @@
 | 
				
			|||||||
version https://git-lfs.github.com/spec/v1
 | 
					 | 
				
			||||||
oid sha256:a476ee59e7d86b5a7599780b5efca57ee6b6d60e1a722343277057ea793703b6
 | 
					 | 
				
			||||||
size 1642116
 | 
					 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 39 KiB  | 
							
								
								
									
										30
									
								
								dist/cli/analyze.hbs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								dist/cli/analyze.hbs
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					{{style "SECTIONS (" "bold"}}{{style totals.numSections "white" }}{{style ")" "bold"}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        employment:     {{v totals.totals.employment "-" 2 "bold" }}
 | 
				
			||||||
 | 
					          projects:     {{v totals.totals.projects "-" 2 "bold" }}
 | 
				
			||||||
 | 
					         education:     {{v totals.totals.education "-" 2 "bold" }}
 | 
				
			||||||
 | 
					           service:     {{v totals.totals.service "-" 2 "bold" }}
 | 
				
			||||||
 | 
					            skills:     {{v totals.totals.skills "-" 2 "bold" }}
 | 
				
			||||||
 | 
					           writing:     {{v totals.totals.writing "-" 2 "bold" }}
 | 
				
			||||||
 | 
					          speaking:     {{v totals.totals.speaking "-" 2 "bold" }}
 | 
				
			||||||
 | 
					           reading:     {{v totals.totals.reading "-" 2 "bold" }}
 | 
				
			||||||
 | 
					            social:     {{v totals.totals.social "-" 2 "bold" }}
 | 
				
			||||||
 | 
					        references:     {{v totals.totals.references "-" 2 "bold" }}
 | 
				
			||||||
 | 
					      testimonials:     {{v totals.totals.testimonials "-" 2 "bold" }}
 | 
				
			||||||
 | 
					         languages:     {{v totals.totals.languages "-" 2 "bold" }}
 | 
				
			||||||
 | 
					         interests:     {{v totals.totals.interests "-" 2 "bold" }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{style "COVERAGE (" "bold"}}{{style coverage.pct "white"}}{{style ")" "bold"}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Total Days:  {{v coverage.duration.total "-" 5 "bold" }}
 | 
				
			||||||
 | 
					          Employed:  {{v coverage.duration.work "-" 5 "bold" }}
 | 
				
			||||||
 | 
					              Gaps:  {{v coverage.gaps.length "-" 5 "bold" }}  [{{#if coverage.gaps.length }}{{#each coverage.gaps }}{{#unless @first}} {{/unless}}{{gapLength duration }}{{/each}}{{/if}}]
 | 
				
			||||||
 | 
					          Overlaps:  {{v coverage.overlaps.length "-" 5 "bold" }}  [{{#if coverage.overlaps.length }}{{#each coverage.overlaps }}{{#unless @first}} {{/unless}}{{gapLength duration }}{{/each}}{{/if}}]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{style "KEYWORDS (" "bold"}}{{style keywords.length "white" }}{{style ")" "bold"}}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{{#each keywords }}{{{pad name 18}}}:  {{v count "-" 5 "bold"}} mention{{#isPlural count}}s{{/isPlural}}
 | 
				
			||||||
 | 
					{{/each}}
 | 
				
			||||||
 | 
					    -------------------------------
 | 
				
			||||||
 | 
					{{v keywords.length "0" 9 "bold"}} {{style "KEYWORDS" "bold"}}   {{v keywords.totalKeywords "0" 5 "bold"}} {{style "mentions" "bold"}}
 | 
				
			||||||
							
								
								
									
										248
									
								
								dist/cli/error.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								dist/cli/error.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,248 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Error-handling routines for HackMyResume.
 | 
				
			||||||
 | 
					@module cli/error
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var ErrorHandler, FCMD, FS, HMSTATUS, M2C, PATH, PKG, SyntaxErrorEx, WRAP, YAML, _defaultLog, assembleError, chalk, extend, printf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ErrorHandler = module.exports = {
 | 
				
			||||||
 | 
					    init: function(debug, assert, silent) {
 | 
				
			||||||
 | 
					      this.debug = debug;
 | 
				
			||||||
 | 
					      this.assert = assert;
 | 
				
			||||||
 | 
					      this.silent = silent;
 | 
				
			||||||
 | 
					      this.msgs = require('./msg').errors;
 | 
				
			||||||
 | 
					      return this;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    err: function(ex, shouldExit) {
 | 
				
			||||||
 | 
					      var o, objError, stack, stackTrace;
 | 
				
			||||||
 | 
					      o = this.silent ? function() {} : _defaultLog;
 | 
				
			||||||
 | 
					      if (ex.pass) {
 | 
				
			||||||
 | 
					        throw ex;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      this.msgs = this.msgs || require('./msg').errors;
 | 
				
			||||||
 | 
					      if (ex.fluenterror) {
 | 
				
			||||||
 | 
					        objError = assembleError.call(this, ex);
 | 
				
			||||||
 | 
					        o(this['format_' + objError.etype](objError.msg));
 | 
				
			||||||
 | 
					        if (objError.withStack) {
 | 
				
			||||||
 | 
					          stack = ex.stack || (ex.inner && ex.inner.stack);
 | 
				
			||||||
 | 
					          stack && o(chalk.gray(stack));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (shouldExit) {
 | 
				
			||||||
 | 
					          if (this.debug) {
 | 
				
			||||||
 | 
					            o(chalk.cyan('Exiting with error code ' + ex.fluenterror.toString()));
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          if (this.assert) {
 | 
				
			||||||
 | 
					            ex.pass = true;
 | 
				
			||||||
 | 
					            throw ex;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return process.exit(ex.fluenterror);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        o(ex);
 | 
				
			||||||
 | 
					        stackTrace = ex.stack || (ex.inner && ex.inner.stack);
 | 
				
			||||||
 | 
					        if (stackTrace && this.debug) {
 | 
				
			||||||
 | 
					          return o(M2C(ex.stack || ex.inner.stack, 'gray'));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    format_error: function(msg) {
 | 
				
			||||||
 | 
					      msg = msg || '';
 | 
				
			||||||
 | 
					      return chalk.red.bold(msg.toUpperCase().startsWith('ERROR:') ? msg : 'Error: ' + msg);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    format_warning: function(brief, msg) {
 | 
				
			||||||
 | 
					      return chalk.yellow(brief) + chalk.yellow(msg || '');
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    format_custom: function(msg) {
 | 
				
			||||||
 | 
					      return msg;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _defaultLog = function() {
 | 
				
			||||||
 | 
					    return console.log.apply(console.log, arguments);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  assembleError = function(ex) {
 | 
				
			||||||
 | 
					    var etype, msg, quit, se, withStack;
 | 
				
			||||||
 | 
					    msg = '';
 | 
				
			||||||
 | 
					    withStack = false;
 | 
				
			||||||
 | 
					    quit = false;
 | 
				
			||||||
 | 
					    etype = 'warning';
 | 
				
			||||||
 | 
					    if (this.debug) {
 | 
				
			||||||
 | 
					      withStack = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    switch (ex.fluenterror) {
 | 
				
			||||||
 | 
					      case HMSTATUS.themeNotFound:
 | 
				
			||||||
 | 
					        msg = printf(M2C(this.msgs.themeNotFound.msg, 'yellow'), ex.data);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.copyCSS:
 | 
				
			||||||
 | 
					        msg = M2C(this.msgs.copyCSS.msg, 'red');
 | 
				
			||||||
 | 
					        quit = false;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.resumeNotFound:
 | 
				
			||||||
 | 
					        msg = M2C(this.msgs.resumeNotFound.msg, 'yellow');
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.missingCommand:
 | 
				
			||||||
 | 
					        msg = M2C(this.msgs.missingCommand.msg + " (", 'yellow');
 | 
				
			||||||
 | 
					        msg += Object.keys(FCMD.verbs).map(function(v, idx, ar) {
 | 
				
			||||||
 | 
					          return (idx === ar.length - 1 ? chalk.yellow('or ') : '') + chalk.yellow.bold(v.toUpperCase());
 | 
				
			||||||
 | 
					        }).join(chalk.yellow(', ')) + chalk.yellow(").\n\n");
 | 
				
			||||||
 | 
					        msg += chalk.gray(FS.readFileSync(PATH.resolve(__dirname, '../cli/use.txt'), 'utf8'));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.invalidCommand:
 | 
				
			||||||
 | 
					        msg = printf(M2C(this.msgs.invalidCommand.msg, 'yellow'), ex.attempted);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.resumeNotFoundAlt:
 | 
				
			||||||
 | 
					        msg = M2C(this.msgs.resumeNotFoundAlt.msg, 'yellow');
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.inputOutputParity:
 | 
				
			||||||
 | 
					        msg = M2C(this.msgs.inputOutputParity.msg);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.createNameMissing:
 | 
				
			||||||
 | 
					        msg = M2C(this.msgs.createNameMissing.msg);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.pdfGeneration:
 | 
				
			||||||
 | 
					        msg = M2C(this.msgs.pdfGeneration.msg, 'bold');
 | 
				
			||||||
 | 
					        if (ex.inner) {
 | 
				
			||||||
 | 
					          msg += chalk.red('\n' + ex.inner);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        quit = false;
 | 
				
			||||||
 | 
					        etype = 'error';
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.invalid:
 | 
				
			||||||
 | 
					        msg = M2C(this.msgs.invalid.msg, 'red');
 | 
				
			||||||
 | 
					        etype = 'error';
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.generateError:
 | 
				
			||||||
 | 
					        msg = (ex.inner && ex.inner.toString()) || ex;
 | 
				
			||||||
 | 
					        quit = false;
 | 
				
			||||||
 | 
					        etype = 'error';
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.fileSaveError:
 | 
				
			||||||
 | 
					        msg = printf(M2C(this.msgs.fileSaveError.msg), (ex.inner || ex).toString());
 | 
				
			||||||
 | 
					        etype = 'error';
 | 
				
			||||||
 | 
					        quit = false;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.invalidFormat:
 | 
				
			||||||
 | 
					        ex.data.forEach(function(d) {
 | 
				
			||||||
 | 
					          return msg += printf(M2C(this.msgs.invalidFormat.msg, 'bold'), ex.theme.name.toUpperCase(), d.format.toUpperCase());
 | 
				
			||||||
 | 
					        }, this);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.missingParam:
 | 
				
			||||||
 | 
					        msg = printf(M2C(this.msgs.missingParam.msg), ex.expected, ex.helper);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.invalidHelperUse:
 | 
				
			||||||
 | 
					        msg = printf(M2C(this.msgs.invalidHelperUse.msg), ex.helper);
 | 
				
			||||||
 | 
					        if (ex.error) {
 | 
				
			||||||
 | 
					          msg += '\n--> ' + assembleError.call(this, extend(true, {}, ex, {
 | 
				
			||||||
 | 
					            fluenterror: ex.error
 | 
				
			||||||
 | 
					          })).msg;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        quit = false;
 | 
				
			||||||
 | 
					        etype = 'warning';
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.notOnPath:
 | 
				
			||||||
 | 
					        msg = printf(M2C(this.msgs.notOnPath.msg, 'bold'), ex.engine);
 | 
				
			||||||
 | 
					        quit = false;
 | 
				
			||||||
 | 
					        etype = 'error';
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.readError:
 | 
				
			||||||
 | 
					        if (!ex.quiet) {
 | 
				
			||||||
 | 
					          console.error(printf(M2C(this.msgs.readError.msg, 'red'), ex.file));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        msg = ex.inner.toString();
 | 
				
			||||||
 | 
					        etype = 'error';
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.mixedMerge:
 | 
				
			||||||
 | 
					        msg = M2C(this.msgs.mixedMerge.msg);
 | 
				
			||||||
 | 
					        quit = false;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.invokeTemplate:
 | 
				
			||||||
 | 
					        msg = M2C(this.msgs.invokeTemplate.msg, 'red');
 | 
				
			||||||
 | 
					        msg += M2C('\n' + WRAP(ex.inner.toString(), {
 | 
				
			||||||
 | 
					          width: 60,
 | 
				
			||||||
 | 
					          indent: '   '
 | 
				
			||||||
 | 
					        }), 'gray');
 | 
				
			||||||
 | 
					        etype = 'custom';
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.compileTemplate:
 | 
				
			||||||
 | 
					        etype = 'error';
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.themeLoad:
 | 
				
			||||||
 | 
					        msg = M2C(printf(this.msgs.themeLoad.msg, ex.attempted.toUpperCase()), 'red');
 | 
				
			||||||
 | 
					        if (ex.inner && ex.inner.fluenterror) {
 | 
				
			||||||
 | 
					          msg += M2C('\nError: ', 'red') + assembleError.call(this, ex.inner).msg;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        quit = true;
 | 
				
			||||||
 | 
					        etype = 'custom';
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      case HMSTATUS.parseError:
 | 
				
			||||||
 | 
					        if (SyntaxErrorEx.is(ex.inner)) {
 | 
				
			||||||
 | 
					          console.error(printf(M2C(this.msgs.readError.msg, 'red'), ex.file));
 | 
				
			||||||
 | 
					          se = new SyntaxErrorEx(ex, ex.raw);
 | 
				
			||||||
 | 
					          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,
 | 
				
			||||||
 | 
					      withStack: withStack,
 | 
				
			||||||
 | 
					      quit: quit,
 | 
				
			||||||
 | 
					      etype: etype
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=error.js.map
 | 
				
			||||||
							
								
								
									
										22
									
								
								dist/cli/index.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								dist/cli/index.js
									
									
									
									
										vendored
									
									
										Normal 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 );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										316
									
								
								dist/cli/main.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								dist/cli/main.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,316 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the `main` function.
 | 
				
			||||||
 | 
					@module cli/main
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  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('../index');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PKG = require('../../package.json');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FS = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXTEND = require('extend');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  chalk = require('chalk');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					  A callable implementation of the HackMyResume CLI. Encapsulates the command
 | 
				
			||||||
 | 
					  line interface as a single method accepting a parameter array.
 | 
				
			||||||
 | 
					  @alias module:cli/main.main
 | 
				
			||||||
 | 
					  @param rawArgs {Array} An array of command-line parameters. Will either be
 | 
				
			||||||
 | 
					  process.argv (in production) or custom parameters (in test).
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  main = module.exports = function(rawArgs, exitCallback) {
 | 
				
			||||||
 | 
					    var args, initInfo, program;
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    program.command('new')["arguments"]('<sources...>').option('-f --format <fmt>', 'FRESH or JRS format', 'FRESH').alias('create').description('Create resume(s) in FRESH or JSON RESUME format.').action((function(sources) {
 | 
				
			||||||
 | 
					      execute.call(this, sources, [], this.opts(), logMsg);
 | 
				
			||||||
 | 
					    }));
 | 
				
			||||||
 | 
					    program.command('validate')["arguments"]('<sources...>').description('Validate a resume in FRESH or JSON RESUME format.').action(function(sources) {
 | 
				
			||||||
 | 
					      execute.call(this, sources, [], this.opts(), logMsg);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    program.command('convert').description('Convert a resume to/from FRESH or JSON RESUME format.').action(function() {
 | 
				
			||||||
 | 
					      var x;
 | 
				
			||||||
 | 
					      x = splitSrcDest.call(this);
 | 
				
			||||||
 | 
					      execute.call(this, x.src, x.dst, this.opts(), logMsg);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    program.command('analyze')["arguments"]('<sources...>').description('Analyze one or more resumes.').action(function(sources) {
 | 
				
			||||||
 | 
					      execute.call(this, sources, [], this.opts(), logMsg);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    program.command('peek')["arguments"]('<sources...>').description('Peek at a resume field or section').action(function(sources, sectionOrField) {
 | 
				
			||||||
 | 
					      var dst;
 | 
				
			||||||
 | 
					      dst = sources && sources.length > 1 ? [sources.pop()] : [];
 | 
				
			||||||
 | 
					      execute.call(this, sources, dst, this.opts(), logMsg);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    program.command('build').alias('generate').option('-t --theme <theme>', 'Theme name or path').option('-n --no-prettify', 'Disable HTML prettification', true).option('-c --css <option>', 'CSS linking / embedding').option('-p --pdf <engine>', 'PDF generation engine').option('--no-sort', 'Sort resume sections by date', false).option('--tips', 'Display theme tips and warnings.', false).description('Generate resume to multiple formats').action(function(sources, targets, options) {
 | 
				
			||||||
 | 
					      var x;
 | 
				
			||||||
 | 
					      x = splitSrcDest.call(this);
 | 
				
			||||||
 | 
					      execute.call(this, x.src, x.dst, this.opts(), logMsg);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    program.parse(args);
 | 
				
			||||||
 | 
					    if (!program.args.length) {
 | 
				
			||||||
 | 
					      throw {
 | 
				
			||||||
 | 
					        fluenterror: 4
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Massage command-line args and setup Commander.js. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  initialize = function(ar, exitCallback) {
 | 
				
			||||||
 | 
					    var o;
 | 
				
			||||||
 | 
					    _exitCallback = exitCallback || process.exit;
 | 
				
			||||||
 | 
					    o = initOptions(ar);
 | 
				
			||||||
 | 
					    o.silent || logMsg(_title);
 | 
				
			||||||
 | 
					    if (o.debug) {
 | 
				
			||||||
 | 
					      _out.log(chalk.cyan('The -d or --debug switch was specified. DEBUG mode engaged.'));
 | 
				
			||||||
 | 
					      _out.log('');
 | 
				
			||||||
 | 
					      _out.log(chalk.cyan(PAD('  Platform:', 25, null, PAD.RIGHT)) + chalk.cyan.bold(process.platform === 'win32' ? 'windows' : process.platform));
 | 
				
			||||||
 | 
					      _out.log(chalk.cyan(PAD('  Node.js:', 25, null, PAD.RIGHT)) + chalk.cyan.bold(process.version));
 | 
				
			||||||
 | 
					      _out.log(chalk.cyan(PAD('  HackMyResume:', 25, null, PAD.RIGHT)) + chalk.cyan.bold('v' + PKG.version));
 | 
				
			||||||
 | 
					      _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]) {
 | 
				
			||||||
 | 
					      _err.err({
 | 
				
			||||||
 | 
					        fluenterror: HMSTATUS.invalidCommand,
 | 
				
			||||||
 | 
					        quit: true,
 | 
				
			||||||
 | 
					        attempted: o.orgVerb
 | 
				
			||||||
 | 
					      }, true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Command.prototype.missingArgument = function(name) {
 | 
				
			||||||
 | 
					      _err.err({
 | 
				
			||||||
 | 
					        fluenterror: this.name() !== 'new' ? HMSTATUS.resumeNotFound : HMSTATUS.createNameMissing
 | 
				
			||||||
 | 
					      }, true);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    Command.prototype.helpInformation = function() {
 | 
				
			||||||
 | 
					      var manPage;
 | 
				
			||||||
 | 
					      manPage = FS.readFileSync(PATH.join(__dirname, 'use.txt'), 'utf8');
 | 
				
			||||||
 | 
					      return chalk.green.bold(manPage);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      args: o.args,
 | 
				
			||||||
 | 
					      options: o.json
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Init options prior to setting up command infrastructure. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  initOptions = function(ar) {
 | 
				
			||||||
 | 
					    oVerb;
 | 
				
			||||||
 | 
					    var args, cleanArgs, inf, isAssert, isDebug, isMono, isSilent, oJSON, oVerb, optStr, optsIdx, verb, vidx;
 | 
				
			||||||
 | 
					    verb = '';
 | 
				
			||||||
 | 
					    args = ar.slice();
 | 
				
			||||||
 | 
					    cleanArgs = args.slice(2);
 | 
				
			||||||
 | 
					    oJSON;
 | 
				
			||||||
 | 
					    if (cleanArgs.length) {
 | 
				
			||||||
 | 
					      vidx = _.findIndex(cleanArgs, function(v) {
 | 
				
			||||||
 | 
					        return v[0] !== '-';
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      if (vidx !== -1) {
 | 
				
			||||||
 | 
					        oVerb = cleanArgs[vidx];
 | 
				
			||||||
 | 
					        verb = args[vidx + 2] = oVerb.trim().toLowerCase();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      optsIdx = _.findIndex(cleanArgs, function(v) {
 | 
				
			||||||
 | 
					        return v === '-o' || v === '--options' || v === '--opts';
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      if (optsIdx !== -1) {
 | 
				
			||||||
 | 
					        optStr = cleanArgs[optsIdx + 1];
 | 
				
			||||||
 | 
					        args.splice(optsIdx + 2, 2);
 | 
				
			||||||
 | 
					        if (optStr && (optStr = optStr.trim())) {
 | 
				
			||||||
 | 
					          if (optStr[0] === '{') {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* jshint ignore:start */
 | 
				
			||||||
 | 
					            oJSON = eval('(' + optStr + ')');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* jshint ignore:end */
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            inf = safeLoadJSON(optStr);
 | 
				
			||||||
 | 
					            if (!inf.ex) {
 | 
				
			||||||
 | 
					              oJSON = inf.json;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    isDebug = _.some(args, function(v) {
 | 
				
			||||||
 | 
					      return v === '-d' || v === '--debug';
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    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';
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      color: !isMono,
 | 
				
			||||||
 | 
					      debug: isDebug,
 | 
				
			||||||
 | 
					      silent: isSilent,
 | 
				
			||||||
 | 
					      assert: isAssert,
 | 
				
			||||||
 | 
					      orgVerb: oVerb,
 | 
				
			||||||
 | 
					      verb: verb,
 | 
				
			||||||
 | 
					      json: oJSON,
 | 
				
			||||||
 | 
					      args: args
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Invoke a HackMyResume verb. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  execute = function(src, dst, opts, log) {
 | 
				
			||||||
 | 
					    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 _err.err.apply(_err, arguments);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					  Initialize HackMyResume options.
 | 
				
			||||||
 | 
					  TODO: Options loading is a little hacky, for two reasons:
 | 
				
			||||||
 | 
					    - Commander.js idiosyncracies
 | 
				
			||||||
 | 
					    - Need to accept JSON inputs from the command line.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loadOptions = function(o, cmdO) {
 | 
				
			||||||
 | 
					    if (cmdO) {
 | 
				
			||||||
 | 
					      o = EXTEND(true, o, cmdO);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    o = EXTEND(true, o, this.opts());
 | 
				
			||||||
 | 
					    if (this.parent.silent !== void 0 && this.parent.silent !== null) {
 | 
				
			||||||
 | 
					      o.silent = this.parent.silent;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (this.parent.debug !== void 0 && this.parent.debug !== null) {
 | 
				
			||||||
 | 
					      o.debug = this.parent.debug;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (this.parent.assert !== void 0 && this.parent.assert !== null) {
 | 
				
			||||||
 | 
					      o.assert = this.parent.assert;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (o.debug) {
 | 
				
			||||||
 | 
					      logMsg(chalk.cyan('OPTIONS:') + '\n');
 | 
				
			||||||
 | 
					      _.each(o, function(val, key) {
 | 
				
			||||||
 | 
					        return logMsg(chalk.cyan('  %s') + chalk.cyan.bold(' %s'), PAD(key, 22, null, PAD.RIGHT), val);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      logMsg('');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    EXTEND(true, _opts, o);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Split multiple command-line filenames by the 'TO' keyword */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  splitSrcDest = function() {
 | 
				
			||||||
 | 
					    var params, splitAt;
 | 
				
			||||||
 | 
					    params = this.parent.args.filter(function(j) {
 | 
				
			||||||
 | 
					      return String.is(j);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if (params.length === 0) {
 | 
				
			||||||
 | 
					      throw {
 | 
				
			||||||
 | 
					        fluenterror: HMSTATUS.resumeNotFound,
 | 
				
			||||||
 | 
					        quit: true
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    splitAt = _.findIndex(params, function(p) {
 | 
				
			||||||
 | 
					      return p.toLowerCase() === 'to';
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if (splitAt === params.length - 1 && splitAt !== -1) {
 | 
				
			||||||
 | 
					      logMsg(chalk.yellow('Please ') + chalk.yellow.bold('specify an output file') + chalk.yellow(' for this operation or ') + chalk.yellow.bold('omit the TO keyword') + chalk.yellow('.'));
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      src: params.slice(0, splitAt === -1 ? void 0 : splitAt),
 | 
				
			||||||
 | 
					      dst: splitAt === -1 ? [] : params.slice(splitAt + 1)
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Simple logging placeholder. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  logMsg = function() {
 | 
				
			||||||
 | 
					    return _opts.silent || console.log.apply(console.log, arguments);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=main.js.map
 | 
				
			||||||
							
								
								
									
										19
									
								
								dist/cli/msg.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								dist/cli/msg.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Message-handling routines for HackMyResume.
 | 
				
			||||||
 | 
					@module cli/msg
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var PATH, YAML;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  YAML = require('yamljs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = YAML.load(PATH.join(__dirname, 'msg.yml'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=msg.js.map
 | 
				
			||||||
							
								
								
									
										111
									
								
								dist/cli/msg.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								dist/cli/msg.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
				
			|||||||
 | 
					events:
 | 
				
			||||||
 | 
					  begin:
 | 
				
			||||||
 | 
					    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:
 | 
				
			||||||
 | 
					    msg: Verifying **%s** theme.
 | 
				
			||||||
 | 
					  afterTheme:
 | 
				
			||||||
 | 
					    msg: Verifying outputs:  ???
 | 
				
			||||||
 | 
					  beforeMerge:
 | 
				
			||||||
 | 
					    msg:
 | 
				
			||||||
 | 
					      - "Merging **%s**"
 | 
				
			||||||
 | 
					      - " onto **%s**"
 | 
				
			||||||
 | 
					  applyTheme:
 | 
				
			||||||
 | 
					    msg: Applying **%s** theme (**%s** format%s)
 | 
				
			||||||
 | 
					  afterBuild:
 | 
				
			||||||
 | 
					    msg:
 | 
				
			||||||
 | 
					      - "The **%s** theme says:"
 | 
				
			||||||
 | 
					      - |
 | 
				
			||||||
 | 
					          "For best results view JSON Resume themes over a
 | 
				
			||||||
 | 
					          local or remote HTTP connection. For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            npm install http-server -g
 | 
				
			||||||
 | 
					            http-server <resume-folder>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          For more information, see the README."
 | 
				
			||||||
 | 
					  afterGenerate:
 | 
				
			||||||
 | 
					    msg:
 | 
				
			||||||
 | 
					      - " (with %s)"
 | 
				
			||||||
 | 
					      - "Skipping %s resume: %s"
 | 
				
			||||||
 | 
					      - "Generating **%s** resume: **%s**"
 | 
				
			||||||
 | 
					  beforeAnalyze:
 | 
				
			||||||
 | 
					    msg: "Analyzing **%s** resume: **%s**"
 | 
				
			||||||
 | 
					  beforeConvert:
 | 
				
			||||||
 | 
					    msg: "Converting **%s** (**%s**) to **%s** (**%s**)"
 | 
				
			||||||
 | 
					  afterValidate:
 | 
				
			||||||
 | 
					    msg:
 | 
				
			||||||
 | 
					      - "Validating **%s** against the **%s** schema: "
 | 
				
			||||||
 | 
					      - "VALID!"
 | 
				
			||||||
 | 
					      - "INVALID"
 | 
				
			||||||
 | 
					      - "BROKEN"
 | 
				
			||||||
 | 
					      - "MISSING"
 | 
				
			||||||
 | 
					      - "ERROR"
 | 
				
			||||||
 | 
					  beforePeek:
 | 
				
			||||||
 | 
					    msg:
 | 
				
			||||||
 | 
					      - Peeking at **%s** in **%s**
 | 
				
			||||||
 | 
					      - Peeking at **%s**
 | 
				
			||||||
 | 
					  afterPeek:
 | 
				
			||||||
 | 
					    msg: "The specified key **%s** was not found in **%s**."
 | 
				
			||||||
 | 
					  afterInlineConvert:
 | 
				
			||||||
 | 
					    msg: Converting **%s** to **%s** format.
 | 
				
			||||||
 | 
					errors:
 | 
				
			||||||
 | 
					  themeNotFound:
 | 
				
			||||||
 | 
					    msg: >
 | 
				
			||||||
 | 
					      **Couldn't find the '%s' theme.** Please specify the name of a preinstalled
 | 
				
			||||||
 | 
					      FRESH theme or the path to a locally installed FRESH or JSON Resume theme.
 | 
				
			||||||
 | 
					  copyCSS:
 | 
				
			||||||
 | 
					    msg: Couldn't copy CSS file to destination folder.
 | 
				
			||||||
 | 
					  resumeNotFound:
 | 
				
			||||||
 | 
					    msg: Please **feed me a resume** in FRESH or JSON Resume format.
 | 
				
			||||||
 | 
					  missingCommand:
 | 
				
			||||||
 | 
					    msg: Please **give me a command**
 | 
				
			||||||
 | 
					  invalidCommand:
 | 
				
			||||||
 | 
					    msg: Invalid command: '%s'
 | 
				
			||||||
 | 
					  resumeNotFoundAlt:
 | 
				
			||||||
 | 
					    msg: Please **feed me a resume** in either FRESH or JSON Resume format.
 | 
				
			||||||
 | 
					  inputOutputParity:
 | 
				
			||||||
 | 
					    msg: Please **specify an output file name** for every input file you wish to convert.
 | 
				
			||||||
 | 
					  createNameMissing:
 | 
				
			||||||
 | 
					    msg: Please **specify the filename** of the resume to create.
 | 
				
			||||||
 | 
					  pdfGeneration:
 | 
				
			||||||
 | 
					    msg: PDF generation failed. Make sure wkhtmltopdf is installed and accessible from your path.
 | 
				
			||||||
 | 
					  invalid:
 | 
				
			||||||
 | 
					    msg: Validation failed and the --assert option was specified.
 | 
				
			||||||
 | 
					  invalidFormat:
 | 
				
			||||||
 | 
					    msg: The **%s** theme doesn't support the **%s** format.
 | 
				
			||||||
 | 
					  notOnPath:
 | 
				
			||||||
 | 
					    msg: %s wasn't found on your system path or is inaccessible. PDF not generated.
 | 
				
			||||||
 | 
					  readError:
 | 
				
			||||||
 | 
					    msg: Reading **???** resume: **%s**
 | 
				
			||||||
 | 
					  parseError:
 | 
				
			||||||
 | 
					    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:
 | 
				
			||||||
 | 
					    msg: An error occurred while writing %s to disk: %s.
 | 
				
			||||||
 | 
					  mixedMerge:
 | 
				
			||||||
 | 
					    msg: "**Warning:** merging mixed resume types. Errors may occur."
 | 
				
			||||||
 | 
					  invokeTemplate:
 | 
				
			||||||
 | 
					    msg: "An error occurred during template invocation."
 | 
				
			||||||
 | 
					  compileTemplate:
 | 
				
			||||||
 | 
					    msg: "An error occurred during template compilation."
 | 
				
			||||||
 | 
					  themeLoad:
 | 
				
			||||||
 | 
					    msg: "Applying **%s** theme (? formats)"
 | 
				
			||||||
 | 
					  invalidParamCount:
 | 
				
			||||||
 | 
					    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"
 | 
				
			||||||
							
								
								
									
										193
									
								
								dist/cli/out.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								dist/cli/out.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,193 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Output routines for HackMyResume.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module cli/out
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var EXTEND, FS, HANDLEBARS, HME, LO, M2C, OutputHandler, PATH, YAML, _, chalk, dbgStyle, pad, printf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  chalk = require('chalk');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HME = require('../core/event-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  M2C = require('../utils/md2chalk.js');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LO = require('lodash');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FS = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXTEND = require('extend');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HANDLEBARS = require('handlebars');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  YAML = require('yamljs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  printf = require('printf');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  pad = require('string-padding');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  dbgStyle = 'cyan';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** A stateful output module. All HMR console output handled here. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    OutputHandler.prototype.log = function(msg) {
 | 
				
			||||||
 | 
					      var finished;
 | 
				
			||||||
 | 
					      msg = msg || '';
 | 
				
			||||||
 | 
					      printf = require('printf');
 | 
				
			||||||
 | 
					      finished = printf.apply(printf, arguments);
 | 
				
			||||||
 | 
					      return this.opts.silent || console.log(finished);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      switch (evt.sub) {
 | 
				
			||||||
 | 
					        case HME.begin:
 | 
				
			||||||
 | 
					          return this.opts.debug && L(M2C(this.msgs.begin.msg, dbgStyle), evt.cmd.toUpperCase());
 | 
				
			||||||
 | 
					        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());
 | 
				
			||||||
 | 
					        case HME.afterParse:
 | 
				
			||||||
 | 
					          return L(M2C(this.msgs.afterRead.msg, 'gray', 'white.dim'), evt.fmt.toUpperCase(), evt.file);
 | 
				
			||||||
 | 
					        case HME.beforeMerge:
 | 
				
			||||||
 | 
					          msg = '';
 | 
				
			||||||
 | 
					          evt.f.reverse().forEach(function(a, idx) {
 | 
				
			||||||
 | 
					            return msg += printf((idx === 0 ? this.msgs.beforeMerge.msg[0] : this.msgs.beforeMerge.msg[1]), a.file);
 | 
				
			||||||
 | 
					          }, this);
 | 
				
			||||||
 | 
					          return L(M2C(msg, (evt.mixed ? 'yellow' : 'gray'), 'white.dim'));
 | 
				
			||||||
 | 
					        case HME.applyTheme:
 | 
				
			||||||
 | 
					          this.theme = evt.theme;
 | 
				
			||||||
 | 
					          numFormats = Object.keys(evt.theme.formats).length;
 | 
				
			||||||
 | 
					          return L(M2C(this.msgs.applyTheme.msg, evt.status === 'error' ? 'red' : 'gray', evt.status === 'error' ? 'bold' : 'white.dim'), evt.theme.name.toUpperCase(), numFormats, numFormats === 1 ? '' : 's');
 | 
				
			||||||
 | 
					        case HME.end:
 | 
				
			||||||
 | 
					          if (evt.cmd === 'build') {
 | 
				
			||||||
 | 
					            themeName = this.theme.name.toUpperCase();
 | 
				
			||||||
 | 
					            if (this.opts.tips && (this.theme.message || this.theme.render)) {
 | 
				
			||||||
 | 
					              WRAP = require('word-wrap');
 | 
				
			||||||
 | 
					              if (this.theme.message) {
 | 
				
			||||||
 | 
					                L(M2C(this.msgs.afterBuild.msg[0], 'cyan'), themeName);
 | 
				
			||||||
 | 
					                return L(M2C(this.theme.message, 'white'));
 | 
				
			||||||
 | 
					              } else if (this.theme.render) {
 | 
				
			||||||
 | 
					                L(M2C(this.msgs.afterBuild.msg[0], 'cyan'), themeName);
 | 
				
			||||||
 | 
					                return L(M2C(this.msgs.afterBuild.msg[1], 'white'));
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case HME.afterGenerate:
 | 
				
			||||||
 | 
					          suffix = '';
 | 
				
			||||||
 | 
					          if (evt.fmt === 'pdf') {
 | 
				
			||||||
 | 
					            if (this.opts.pdf) {
 | 
				
			||||||
 | 
					              if (this.opts.pdf !== 'none') {
 | 
				
			||||||
 | 
					                suffix = printf(M2C(this.msgs.afterGenerate.msg[0], evt.error ? 'red' : 'green'), this.opts.pdf);
 | 
				
			||||||
 | 
					              } else {
 | 
				
			||||||
 | 
					                L(M2C(this.msgs.afterGenerate.msg[1], 'gray'), evt.fmt.toUpperCase(), evt.file);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          return L(M2C(this.msgs.afterGenerate.msg[2] + suffix, evt.error ? 'red' : 'green'), pad(evt.fmt.toUpperCase(), 4, null, pad.RIGHT), PATH.relative(process.cwd(), evt.file));
 | 
				
			||||||
 | 
					        case HME.beforeAnalyze:
 | 
				
			||||||
 | 
					          return L(M2C(this.msgs.beforeAnalyze.msg, 'green'), evt.fmt, evt.file);
 | 
				
			||||||
 | 
					        case HME.afterAnalyze:
 | 
				
			||||||
 | 
					          info = evt.info;
 | 
				
			||||||
 | 
					          rawTpl = FS.readFileSync(PATH.join(__dirname, 'analyze.hbs'), 'utf8');
 | 
				
			||||||
 | 
					          HANDLEBARS.registerHelper(require('../helpers/console-helpers'));
 | 
				
			||||||
 | 
					          template = HANDLEBARS.compile(rawTpl, {
 | 
				
			||||||
 | 
					            strict: false,
 | 
				
			||||||
 | 
					            assumeObjects: false
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          tot = 0;
 | 
				
			||||||
 | 
					          info.keywords.forEach(function(g) {
 | 
				
			||||||
 | 
					            return tot += g.count;
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          info.keywords.totalKeywords = tot;
 | 
				
			||||||
 | 
					          output = template(info);
 | 
				
			||||||
 | 
					          return this.log(chalk.cyan(output));
 | 
				
			||||||
 | 
					        case HME.beforeConvert:
 | 
				
			||||||
 | 
					          return L(M2C(this.msgs.beforeConvert.msg, 'green'), evt.srcFile, evt.srcFmt, evt.dstFile, evt.dstFmt);
 | 
				
			||||||
 | 
					        case HME.afterInlineConvert:
 | 
				
			||||||
 | 
					          return L(M2C(this.msgs.afterInlineConvert.msg, 'gray', 'white.dim'), evt.file, evt.fmt);
 | 
				
			||||||
 | 
					        case HME.afterValidate:
 | 
				
			||||||
 | 
					          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;
 | 
				
			||||||
 | 
					        case HME.afterPeek:
 | 
				
			||||||
 | 
					          sty = evt.error ? 'red' : (evt.target !== void 0 ? 'green' : 'yellow');
 | 
				
			||||||
 | 
					          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 !== 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
 | 
				
			||||||
							
								
								
									
										51
									
								
								dist/cli/use.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								dist/cli/use.txt
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					Usage:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hackmyresume <command> <sources> [TO <targets>] [<options>]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Available commands:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BUILD         Build your resume to the destination format(s).
 | 
				
			||||||
 | 
					  ANALYZE       Analyze your resume for keywords, gaps, and metrics.
 | 
				
			||||||
 | 
					  VALIDATE      Validate your resume for errors and typos.
 | 
				
			||||||
 | 
					  CONVERT       Convert your resume between FRESH and JSON Resume.
 | 
				
			||||||
 | 
					  NEW           Create a new resume in FRESH or JSON Resume format.
 | 
				
			||||||
 | 
					  PEEK          View a specific field or element on your resume.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Available options:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  --theme -t    Path to a FRESH or JSON Resume theme.
 | 
				
			||||||
 | 
					  --pdf -p      Specify the PDF engine to use (wkhtmltopdf or phantom).
 | 
				
			||||||
 | 
					  --options -o  Load options from an external JSON file.
 | 
				
			||||||
 | 
					  --format -f   The format (FRESH or JSON Resume) to use.
 | 
				
			||||||
 | 
					  --debug -d    Emit extended debugging info.
 | 
				
			||||||
 | 
					  --assert -a   Treat resume validation warnings as errors.
 | 
				
			||||||
 | 
					  --no-colors   Disable terminal colors.
 | 
				
			||||||
 | 
					  --tips        Display theme messages and tips.
 | 
				
			||||||
 | 
					  --help -h     Display help documentation.
 | 
				
			||||||
 | 
					  --version -v  Display the current version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Not all options are supported for all commands. For example, the
 | 
				
			||||||
 | 
					--theme option is only supported for the BUILD command.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Examples:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hackmyresume  BUILD resume.json TO out/resume.all --theme modern
 | 
				
			||||||
 | 
					  hackmyresume  ANALYZE resume.json
 | 
				
			||||||
 | 
					  hackmyresume  NEW my-new-resume.json --format JRS
 | 
				
			||||||
 | 
					  hackmyresume  CONVERT resume-fresh.json TO resume-jrs.json
 | 
				
			||||||
 | 
					  hackmyresume  VALIDATE resume.json
 | 
				
			||||||
 | 
					  hackmyresume  PEEK resume.json employment[2].summary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tips:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - You can specify multiple sources and/or targets for all commands.
 | 
				
			||||||
 | 
					  - You can use any FRESH or JSON Resume theme with HackMyResume.
 | 
				
			||||||
 | 
					  - Specify a file extension of .all to generate your resume to all
 | 
				
			||||||
 | 
					    available formats supported by the theme. (BUILD command.)
 | 
				
			||||||
 | 
					  - The --theme parameter can specify either the name of a preinstalled
 | 
				
			||||||
 | 
					    theme, or the path to a local FRESH or JSON Resume theme.
 | 
				
			||||||
 | 
					  - Visit https://www.npmjs.com/search?q=jsonresume-theme for a full
 | 
				
			||||||
 | 
					    listing of all available JSON Resume themes.
 | 
				
			||||||
 | 
					  - Visit https://github.com/fluentdesk/fresh-themes for a complete
 | 
				
			||||||
 | 
					    listing of all available FRESH themes.
 | 
				
			||||||
 | 
					  - Report bugs to https://githut.com/hacksalot/HackMyResume/issues.
 | 
				
			||||||
							
								
								
									
										73
									
								
								dist/core/abstract-resume.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								dist/core/abstract-resume.js
									
									
									
									
										vendored
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										62
									
								
								dist/core/default-formats.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								dist/core/default-formats.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,62 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					Event code definitions.
 | 
				
			||||||
 | 
					@module core/default-formats
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Supported resume formats. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  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'))()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=default-formats.js.map
 | 
				
			||||||
							
								
								
									
										20
									
								
								dist/core/default-options.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								dist/core/default-options.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					Event code definitions.
 | 
				
			||||||
 | 
					@module core/default-options
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  module.exports = {
 | 
				
			||||||
 | 
					    theme: 'modern',
 | 
				
			||||||
 | 
					    prettify: {
 | 
				
			||||||
 | 
					      indent_size: 2,
 | 
				
			||||||
 | 
					      unformatted: ['em', 'strong'],
 | 
				
			||||||
 | 
					      max_char: 80
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=default-options.js.map
 | 
				
			||||||
							
								
								
									
										77
									
								
								dist/core/empty-jrs.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								dist/core/empty-jrs.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "basics": {
 | 
				
			||||||
 | 
					    "name": "",
 | 
				
			||||||
 | 
					    "label": "",
 | 
				
			||||||
 | 
					    "picture": "",
 | 
				
			||||||
 | 
					    "email": "",
 | 
				
			||||||
 | 
					    "phone": "",
 | 
				
			||||||
 | 
					    "degree": "",
 | 
				
			||||||
 | 
					    "website": "",
 | 
				
			||||||
 | 
					    "summary": "",
 | 
				
			||||||
 | 
					    "location": {
 | 
				
			||||||
 | 
					      "address": "",
 | 
				
			||||||
 | 
					      "postalCode": "",
 | 
				
			||||||
 | 
					      "city": "",
 | 
				
			||||||
 | 
					      "countryCode": "",
 | 
				
			||||||
 | 
					      "region": ""
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "profiles": [{
 | 
				
			||||||
 | 
					      "network": "",
 | 
				
			||||||
 | 
					      "username": "",
 | 
				
			||||||
 | 
					      "url": ""
 | 
				
			||||||
 | 
					    }]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  "work": [{
 | 
				
			||||||
 | 
					    "company": "",
 | 
				
			||||||
 | 
					    "position": "",
 | 
				
			||||||
 | 
					    "website": "",
 | 
				
			||||||
 | 
					    "startDate": "",
 | 
				
			||||||
 | 
					    "endDate": "",
 | 
				
			||||||
 | 
					    "summary": "",
 | 
				
			||||||
 | 
					    "highlights": [
 | 
				
			||||||
 | 
					      ""
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  }],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  "awards": [{
 | 
				
			||||||
 | 
					    "title": "",
 | 
				
			||||||
 | 
					    "date": "",
 | 
				
			||||||
 | 
					    "awarder": "",
 | 
				
			||||||
 | 
					    "summary": ""
 | 
				
			||||||
 | 
					  }],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  "education": [{
 | 
				
			||||||
 | 
					    "institution": "",
 | 
				
			||||||
 | 
					    "area": "",
 | 
				
			||||||
 | 
					    "studyType": "",
 | 
				
			||||||
 | 
					    "startDate": "",
 | 
				
			||||||
 | 
					    "endDate": "",
 | 
				
			||||||
 | 
					    "gpa": "",
 | 
				
			||||||
 | 
					    "courses": [ "" ]
 | 
				
			||||||
 | 
					  }],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  "publications": [{
 | 
				
			||||||
 | 
					    "name": "",
 | 
				
			||||||
 | 
					    "publisher": "",
 | 
				
			||||||
 | 
					    "releaseDate": "",
 | 
				
			||||||
 | 
					    "website": "",
 | 
				
			||||||
 | 
					    "summary": ""
 | 
				
			||||||
 | 
					  }],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  "volunteer": [{
 | 
				
			||||||
 | 
					    "organization": "",
 | 
				
			||||||
 | 
					    "position": "",
 | 
				
			||||||
 | 
					    "website": "",
 | 
				
			||||||
 | 
					    "startDate": "",
 | 
				
			||||||
 | 
					    "endDate": "",
 | 
				
			||||||
 | 
					    "summary": "",
 | 
				
			||||||
 | 
					    "highlights": [ "" ]
 | 
				
			||||||
 | 
					  }],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  "skills": [{
 | 
				
			||||||
 | 
					      "name": "",
 | 
				
			||||||
 | 
					      "level": "",
 | 
				
			||||||
 | 
					      "keywords": [""]
 | 
				
			||||||
 | 
					  }]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										44
									
								
								dist/core/event-codes.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								dist/core/event-codes.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					Event code definitions.
 | 
				
			||||||
 | 
					@module core/event-codes
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  module.exports = {
 | 
				
			||||||
 | 
					    error: -1,
 | 
				
			||||||
 | 
					    success: 0,
 | 
				
			||||||
 | 
					    begin: 1,
 | 
				
			||||||
 | 
					    end: 2,
 | 
				
			||||||
 | 
					    beforeRead: 3,
 | 
				
			||||||
 | 
					    afterRead: 4,
 | 
				
			||||||
 | 
					    beforeCreate: 5,
 | 
				
			||||||
 | 
					    afterCreate: 6,
 | 
				
			||||||
 | 
					    beforeTheme: 7,
 | 
				
			||||||
 | 
					    afterTheme: 8,
 | 
				
			||||||
 | 
					    beforeMerge: 9,
 | 
				
			||||||
 | 
					    afterMerge: 10,
 | 
				
			||||||
 | 
					    beforeGenerate: 11,
 | 
				
			||||||
 | 
					    afterGenerate: 12,
 | 
				
			||||||
 | 
					    beforeAnalyze: 13,
 | 
				
			||||||
 | 
					    afterAnalyze: 14,
 | 
				
			||||||
 | 
					    beforeConvert: 15,
 | 
				
			||||||
 | 
					    afterConvert: 16,
 | 
				
			||||||
 | 
					    verifyOutputs: 17,
 | 
				
			||||||
 | 
					    beforeParse: 18,
 | 
				
			||||||
 | 
					    afterParse: 19,
 | 
				
			||||||
 | 
					    beforePeek: 20,
 | 
				
			||||||
 | 
					    afterPeek: 21,
 | 
				
			||||||
 | 
					    beforeInlineConvert: 22,
 | 
				
			||||||
 | 
					    afterInlineConvert: 23,
 | 
				
			||||||
 | 
					    beforeValidate: 24,
 | 
				
			||||||
 | 
					    afterValidate: 25,
 | 
				
			||||||
 | 
					    beforeWrite: 26,
 | 
				
			||||||
 | 
					    afterWrite: 27,
 | 
				
			||||||
 | 
					    applyTheme: 28
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=event-codes.js.map
 | 
				
			||||||
							
								
								
									
										107
									
								
								dist/core/fluent-date.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								dist/core/fluent-date.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					The HackMyResume date representation.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module core/fluent-date
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var FluentDate, abbr, moment, months;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moment = require('moment');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  require('../utils/string');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Create a FluentDate from a string or Moment date object. There are a few date
 | 
				
			||||||
 | 
					  formats to be aware of here.
 | 
				
			||||||
 | 
					  1. The words "Present" and "Now", referring to the current date
 | 
				
			||||||
 | 
					  2. The default "YYYY-MM-DD" format used in JSON Resume ("2015-02-10")
 | 
				
			||||||
 | 
					  3. Year-and-month only ("2015-04")
 | 
				
			||||||
 | 
					  4. Year-only "YYYY" ("2015")
 | 
				
			||||||
 | 
					  5. The friendly HackMyResume "mmm YYYY" format ("Mar 2015" or "Dec 2008")
 | 
				
			||||||
 | 
					  6. Empty dates ("", " ")
 | 
				
			||||||
 | 
					  7. Any other date format that Moment.js can parse from
 | 
				
			||||||
 | 
					  Note: Moment can transparently parse all or most of these, without requiring us
 | 
				
			||||||
 | 
					  to specify a date format...but for maximum parsing safety and to avoid Moment
 | 
				
			||||||
 | 
					  deprecation warnings, it's recommended to either a) explicitly specify the date
 | 
				
			||||||
 | 
					  format or b) use an ISO format. For clarity, we handle these cases explicitly.
 | 
				
			||||||
 | 
					  @class FluentDate
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FluentDate = (function() {
 | 
				
			||||||
 | 
					    function FluentDate(dt) {
 | 
				
			||||||
 | 
					      this.rep = this.fmt(dt);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FluentDate.isCurrent = function(dt) {
 | 
				
			||||||
 | 
					      return !dt || (String.is(dt) && /^(present|now|current)$/.test(dt));
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return FluentDate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  })();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  months = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  abbr = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moment.months().forEach(function(m, idx) {
 | 
				
			||||||
 | 
					    return months[m.toLowerCase()] = idx + 1;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moment.monthsShort().forEach(function(m, idx) {
 | 
				
			||||||
 | 
					    return abbr[m.toLowerCase()] = idx + 1;
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  abbr.sept = 9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = FluentDate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FluentDate.fmt = function(dt, throws) {
 | 
				
			||||||
 | 
					    var month, mt, parts, ref, temp;
 | 
				
			||||||
 | 
					    throws = (throws === void 0 || throws === null) || throws;
 | 
				
			||||||
 | 
					    if (typeof dt === 'string' || dt instanceof String) {
 | 
				
			||||||
 | 
					      dt = dt.toLowerCase().trim();
 | 
				
			||||||
 | 
					      if (/^(present|now|current)$/.test(dt)) {
 | 
				
			||||||
 | 
					        return moment();
 | 
				
			||||||
 | 
					      } else if (/^\D+\s+\d{4}$/.test(dt)) {
 | 
				
			||||||
 | 
					        parts = dt.split(' ');
 | 
				
			||||||
 | 
					        month = months[parts[0]] || abbr[parts[0]];
 | 
				
			||||||
 | 
					        temp = parts[1] + '-' + ((ref = month < 10) != null ? ref : '0' + {
 | 
				
			||||||
 | 
					          month: month.toString()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return moment(temp, 'YYYY-MM');
 | 
				
			||||||
 | 
					      } else if (/^\d{4}-\d{1,2}$/.test(dt)) {
 | 
				
			||||||
 | 
					        return moment(dt, 'YYYY-MM');
 | 
				
			||||||
 | 
					      } else if (/^\s*\d{4}\s*$/.test(dt)) {
 | 
				
			||||||
 | 
					        return moment(dt, 'YYYY');
 | 
				
			||||||
 | 
					      } else if (/^\s*$/.test(dt)) {
 | 
				
			||||||
 | 
					        return moment();
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        mt = moment(dt);
 | 
				
			||||||
 | 
					        if (mt.isValid()) {
 | 
				
			||||||
 | 
					          return mt;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (throws) {
 | 
				
			||||||
 | 
					          throw 'Invalid date format encountered.';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      if (!dt) {
 | 
				
			||||||
 | 
					        return moment();
 | 
				
			||||||
 | 
					      } else if (dt.isValid && dt.isValid()) {
 | 
				
			||||||
 | 
					        return dt;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (throws) {
 | 
				
			||||||
 | 
					        throw 'Unknown date object encountered.';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=fluent-date.js.map
 | 
				
			||||||
							
								
								
									
										510
									
								
								dist/core/fresh-resume.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								dist/core/fresh-resume.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,510 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the FRESHResume class.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module core/fresh-resume
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  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');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  extend = require('extend');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  validator = require('is-my-json-valid');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  __ = require('lodash');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moment = require('moment');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  XML = require('xml-escape');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MD = require('marked');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CONVERTER = require('fresh-jrs-converter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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
 | 
				
			||||||
 | 
					  object is an instantiation of that JSON decorated with utility methods.
 | 
				
			||||||
 | 
					  @constructor
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FreshResume = (function(superClass) {
 | 
				
			||||||
 | 
					    extend1(FreshResume, superClass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Initialize the FreshResume from JSON.
 | 
				
			||||||
 | 
					    Open and parse the specified FRESH resume. Merge the JSON object model onto
 | 
				
			||||||
 | 
					    this Sheet instance with extend() and convert sheet dates to a safe &
 | 
				
			||||||
 | 
					    consistent format. Then sort each section by startDate descending.
 | 
				
			||||||
 | 
					    @param rep {Object} The raw JSON representation.
 | 
				
			||||||
 | 
					    @param opts {Object} Resume loading and parsing options.
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      date: Perform safe date conversion.
 | 
				
			||||||
 | 
					      sort: Sort resume items by date.
 | 
				
			||||||
 | 
					      compute: Prepare computed resume totals.
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.parseJSON = function(rep, opts) {
 | 
				
			||||||
 | 
					      var ignoreList, ref, scrubbed, that, traverse;
 | 
				
			||||||
 | 
					      that = this;
 | 
				
			||||||
 | 
					      traverse = require('traverse');
 | 
				
			||||||
 | 
					      ignoreList = [];
 | 
				
			||||||
 | 
					      scrubbed = traverse(rep).map(function(x) {
 | 
				
			||||||
 | 
					        if (!this.isLeaf && this.node.ignore) {
 | 
				
			||||||
 | 
					          if (this.node.ignore === true || this.node.ignore === 'true') {
 | 
				
			||||||
 | 
					            ignoreList.push(this.node);
 | 
				
			||||||
 | 
					            return this.remove();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      extend(true, this, scrubbed);
 | 
				
			||||||
 | 
					      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 = {
 | 
				
			||||||
 | 
					          numYears: this.duration(),
 | 
				
			||||||
 | 
					          keywords: this.keywords()
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return this;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Save the sheet to disk (for environments that have disk access). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.save = function(filename) {
 | 
				
			||||||
 | 
					      this.imp.file = filename || this.imp.file;
 | 
				
			||||||
 | 
					      FS.writeFileSync(this.imp.file, this.stringify(), 'utf8');
 | 
				
			||||||
 | 
					      return this;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Save the sheet to disk in a specific format, either FRESH or JSON Resume.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.saveAs = function(filename, format) {
 | 
				
			||||||
 | 
					      var newRep;
 | 
				
			||||||
 | 
					      if (format !== 'JRS') {
 | 
				
			||||||
 | 
					        this.imp.file = filename || this.imp.file;
 | 
				
			||||||
 | 
					        FS.writeFileSync(this.imp.file, this.stringify(), 'utf8');
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        newRep = CONVERTER.toJRS(this);
 | 
				
			||||||
 | 
					        FS.writeFileSync(filename, JRSResume.stringify(newRep), 'utf8');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return this;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Duplicate this FreshResume instance.
 | 
				
			||||||
 | 
					    This method first extend()s this object onto an empty, creating a deep copy,
 | 
				
			||||||
 | 
					    and then passes the result into a new FreshResume instance via .parseJSON.
 | 
				
			||||||
 | 
					    We do it this way to create a true clone of the object without re-running any
 | 
				
			||||||
 | 
					    of the associated processing.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.dupe = function() {
 | 
				
			||||||
 | 
					      var jso, rnew;
 | 
				
			||||||
 | 
					      jso = extend(true, {}, this);
 | 
				
			||||||
 | 
					      rnew = new FreshResume();
 | 
				
			||||||
 | 
					      rnew.parseJSON(jso, {});
 | 
				
			||||||
 | 
					      return rnew;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Convert this object to a JSON string, sanitizing meta-properties along the
 | 
				
			||||||
 | 
					    way.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.stringify = function() {
 | 
				
			||||||
 | 
					      return FreshResume.stringify(this);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Create a copy of this resume in which all string fields have been run through
 | 
				
			||||||
 | 
					    a transformation function (such as a Markdown filter or XML encoder).
 | 
				
			||||||
 | 
					    TODO: Move this out of FRESHResume.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.transformStrings = function(filt, transformer) {
 | 
				
			||||||
 | 
					      var ret, trx;
 | 
				
			||||||
 | 
					      ret = this.dupe();
 | 
				
			||||||
 | 
					      trx = require('../utils/string-transformer');
 | 
				
			||||||
 | 
					      return trx(ret, filt, transformer);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Create a copy of this resume in which all fields have been interpreted as
 | 
				
			||||||
 | 
					    Markdown.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.markdownify = function() {
 | 
				
			||||||
 | 
					      var MDIN, trx;
 | 
				
			||||||
 | 
					      MDIN = function(txt) {
 | 
				
			||||||
 | 
					        return MD(txt || '').replace(/^\s*<p>|<\/p>\s*$/gi, '');
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      trx = function(key, val) {
 | 
				
			||||||
 | 
					        if (key === 'summary') {
 | 
				
			||||||
 | 
					          return MD(val);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return MDIN(val);
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      return this.transformStrings(['skills', 'url', 'start', 'end', 'date'], trx);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Create a copy of this resume in which all fields have been interpreted as
 | 
				
			||||||
 | 
					    Markdown.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.xmlify = function() {
 | 
				
			||||||
 | 
					      var trx;
 | 
				
			||||||
 | 
					      trx = function(key, val) {
 | 
				
			||||||
 | 
					        return XML(val);
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      return this.transformStrings([], trx);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Return the resume format. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.format = function() {
 | 
				
			||||||
 | 
					      return 'FRESH';
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Return internal metadata. Create if it doesn't exist.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.i = function() {
 | 
				
			||||||
 | 
					      return this.imp = this.imp || {};
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Return a unique list of all keywords across all skills. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.keywords = function() {
 | 
				
			||||||
 | 
					      var flatSkills;
 | 
				
			||||||
 | 
					      flatSkills = [];
 | 
				
			||||||
 | 
					      if (this.skills) {
 | 
				
			||||||
 | 
					        if (this.skills.sets) {
 | 
				
			||||||
 | 
					          flatSkills = this.skills.sets.map(function(sk) {
 | 
				
			||||||
 | 
					            return sk.skills;
 | 
				
			||||||
 | 
					          }).reduce(function(a, b) {
 | 
				
			||||||
 | 
					            return a.concat(b);
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        } else if (this.skills.list) {
 | 
				
			||||||
 | 
					          flatSkills = flatSkills.concat(this.skills.list.map(function(sk) {
 | 
				
			||||||
 | 
					            return sk.name;
 | 
				
			||||||
 | 
					          }));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        flatSkills = _.uniq(flatSkills);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return flatSkills;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Reset the sheet to an empty state. TODO: refactor/review
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.clear = function(clearMeta) {
 | 
				
			||||||
 | 
					      clearMeta = ((clearMeta === void 0) && true) || clearMeta;
 | 
				
			||||||
 | 
					      if (clearMeta) {
 | 
				
			||||||
 | 
					        delete this.imp;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      delete this.computed;
 | 
				
			||||||
 | 
					      delete this.employment;
 | 
				
			||||||
 | 
					      delete this.service;
 | 
				
			||||||
 | 
					      delete this.education;
 | 
				
			||||||
 | 
					      delete this.recognition;
 | 
				
			||||||
 | 
					      delete this.reading;
 | 
				
			||||||
 | 
					      delete this.writing;
 | 
				
			||||||
 | 
					      delete this.interests;
 | 
				
			||||||
 | 
					      delete this.skills;
 | 
				
			||||||
 | 
					      return delete this.social;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Get a safe count of the number of things in a section.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.count = function(obj) {
 | 
				
			||||||
 | 
					      if (!obj) {
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (obj.history) {
 | 
				
			||||||
 | 
					        return obj.history.length;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (obj.sets) {
 | 
				
			||||||
 | 
					        return obj.sets.length;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return obj.length || 0;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Add work experience to the sheet. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.add = function(moniker) {
 | 
				
			||||||
 | 
					      var defSheet, newObject;
 | 
				
			||||||
 | 
					      defSheet = FreshResume["default"]();
 | 
				
			||||||
 | 
					      newObject = defSheet[moniker].history ? $.extend(true, {}, defSheet[moniker].history[0]) : moniker === 'skills' ? $.extend(true, {}, defSheet.skills.sets[0]) : $.extend(true, {}, defSheet[moniker][0]);
 | 
				
			||||||
 | 
					      this[moniker] = this[moniker] || [];
 | 
				
			||||||
 | 
					      if (this[moniker].history) {
 | 
				
			||||||
 | 
					        this[moniker].history.push(newObject);
 | 
				
			||||||
 | 
					      } else if (moniker === 'skills') {
 | 
				
			||||||
 | 
					        this.skills.sets.push(newObject);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this[moniker].push(newObject);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return newObject;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Determine if the sheet includes a specific social profile (eg, GitHub).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.hasProfile = function(socialNetwork) {
 | 
				
			||||||
 | 
					      socialNetwork = socialNetwork.trim().toLowerCase();
 | 
				
			||||||
 | 
					      return this.social && _.some(this.social, function(p) {
 | 
				
			||||||
 | 
					        return p.network.trim().toLowerCase() === socialNetwork;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Return the specified network profile. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.getProfile = function(socialNetwork) {
 | 
				
			||||||
 | 
					      socialNetwork = socialNetwork.trim().toLowerCase();
 | 
				
			||||||
 | 
					      return this.social && _.find(this.social, function(sn) {
 | 
				
			||||||
 | 
					        return sn.network.trim().toLowerCase() === socialNetwork;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Return an array of profiles for the specified network, for when the user
 | 
				
			||||||
 | 
					    has multiple eg. GitHub accounts.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.getProfiles = function(socialNetwork) {
 | 
				
			||||||
 | 
					      socialNetwork = socialNetwork.trim().toLowerCase();
 | 
				
			||||||
 | 
					      return this.social && _.filter(this.social, function(sn) {
 | 
				
			||||||
 | 
					        return sn.network.trim().toLowerCase() === socialNetwork;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Determine if the sheet includes a specific skill. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.hasSkill = function(skill) {
 | 
				
			||||||
 | 
					      skill = skill.trim().toLowerCase();
 | 
				
			||||||
 | 
					      return this.skills && _.some(this.skills, function(sk) {
 | 
				
			||||||
 | 
					        return sk.keywords && _.some(sk.keywords, function(kw) {
 | 
				
			||||||
 | 
					          return kw.trim().toLowerCase() === skill;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Validate the sheet against the FRESH Resume schema. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.isValid = function(info) {
 | 
				
			||||||
 | 
					      var ret, schemaObj, validate;
 | 
				
			||||||
 | 
					      schemaObj = require('fresca');
 | 
				
			||||||
 | 
					      validator = require('is-my-json-valid');
 | 
				
			||||||
 | 
					      validate = validator(schemaObj, {
 | 
				
			||||||
 | 
					        formats: {
 | 
				
			||||||
 | 
					          date: /^\d{4}(?:-(?:0[0-9]{1}|1[0-2]{1})(?:-[0-9]{2})?)?$/
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      ret = validate(this);
 | 
				
			||||||
 | 
					      if (!ret) {
 | 
				
			||||||
 | 
					        this.imp = this.imp || {};
 | 
				
			||||||
 | 
					        this.imp.validationErrors = validate.errors;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return ret;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.duration = function(unit) {
 | 
				
			||||||
 | 
					      return FreshResume.__super__.duration.call(this, 'employment.history', 'start', 'end', unit);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Sort dated things on the sheet by start date descending. Assumes that dates
 | 
				
			||||||
 | 
					    on the sheet have been processed with _parseDates().
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FreshResume.prototype.sort = function() {
 | 
				
			||||||
 | 
					      var byDateDesc, sortSection;
 | 
				
			||||||
 | 
					      byDateDesc = function(a, b) {
 | 
				
			||||||
 | 
					        if (a.safe.start.isBefore(b.safe.start)) {
 | 
				
			||||||
 | 
					          return 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          if (a.safe.start.isAfter(b.safe.start)) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      sortSection = function(key) {
 | 
				
			||||||
 | 
					        var ar, datedThings;
 | 
				
			||||||
 | 
					        ar = __.get(this, key);
 | 
				
			||||||
 | 
					        if (ar && ar.length) {
 | 
				
			||||||
 | 
					          datedThings = obj.filter(function(o) {
 | 
				
			||||||
 | 
					            return o.start;
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          return datedThings.sort(byDateDesc);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      sortSection('employment.history');
 | 
				
			||||||
 | 
					      sortSection('education.history');
 | 
				
			||||||
 | 
					      sortSection('service.history');
 | 
				
			||||||
 | 
					      sortSection('projects');
 | 
				
			||||||
 | 
					      return this.writing && this.writing.sort(function(a, b) {
 | 
				
			||||||
 | 
					        if (a.safe.date.isBefore(b.safe.date)) {
 | 
				
			||||||
 | 
					          return 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return (a.safe.date.isAfter(b.safe.date) && -1) || 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return FreshResume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  })(AbstractResume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Get the default (starter) sheet.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FreshResume["default"] = function() {
 | 
				
			||||||
 | 
					    return new FreshResume().parseJSON(require('fresh-resume-starter').fresh);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Convert the supplied FreshResume to a JSON string, sanitizing meta-properties
 | 
				
			||||||
 | 
					  along the way.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FreshResume.stringify = function(obj) {
 | 
				
			||||||
 | 
					    var replacer;
 | 
				
			||||||
 | 
					    replacer = function(key, value) {
 | 
				
			||||||
 | 
					      var exKeys;
 | 
				
			||||||
 | 
					      exKeys = ['imp', 'warnings', 'computed', 'filt', 'ctrl', 'index', 'safe', 'result', 'isModified', 'htmlPreview', 'display_progress_bar'];
 | 
				
			||||||
 | 
					      if (_.some(exKeys, function(val) {
 | 
				
			||||||
 | 
					        return key.trim() === val;
 | 
				
			||||||
 | 
					      })) {
 | 
				
			||||||
 | 
					        return void 0;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return value;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return JSON.stringify(obj, replacer, 2);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Convert human-friendly dates into formal Moment.js dates for all collections.
 | 
				
			||||||
 | 
					  We don't want to lose the raw textual date as entered by the user, so we store
 | 
				
			||||||
 | 
					  the Moment-ified date as a separate property with a prefix of .safe. For ex:
 | 
				
			||||||
 | 
					  job.startDate is the date as entered by the user. job.safeStartDate is the
 | 
				
			||||||
 | 
					  parsed Moment.js date that we actually use in processing.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _parseDates = function() {
 | 
				
			||||||
 | 
					    var _fmt, replaceDatesInObject, that;
 | 
				
			||||||
 | 
					    _fmt = require('./fluent-date').fmt;
 | 
				
			||||||
 | 
					    that = this;
 | 
				
			||||||
 | 
					    replaceDatesInObject = function(obj) {
 | 
				
			||||||
 | 
					      if (!obj) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (Object.prototype.toString.call(obj) === '[object Array]') {
 | 
				
			||||||
 | 
					        obj.forEach(function(elem) {
 | 
				
			||||||
 | 
					          return replaceDatesInObject(elem);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      } else if (typeof obj === 'object') {
 | 
				
			||||||
 | 
					        if (obj._isAMomentObject || obj.safe) {
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Object.keys(obj).forEach(function(key) {
 | 
				
			||||||
 | 
					          return replaceDatesInObject(obj[key]);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        ['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) {
 | 
				
			||||||
 | 
					              obj.safe.end = _fmt('current');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    Object.keys(this).forEach(function(member) {
 | 
				
			||||||
 | 
					      replaceDatesInObject(that[member]);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Export the Sheet function/ctor. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = FreshResume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=fresh-resume.js.map
 | 
				
			||||||
							
								
								
									
										230
									
								
								dist/core/fresh-theme.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								dist/core/fresh-theme.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,230 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the FRESHTheme class.
 | 
				
			||||||
 | 
					@module core/fresh-theme
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var EXTEND, FRESHTheme, FS, HMSTATUS, PATH, READFILES, _, _load, _loadOne, friendlyName, loadSafeJson, moment, parsePath, pathExists, validator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FS = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  validator = require('is-my-json-valid');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  parsePath = require('parse-filepath');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  pathExists = require('path-exists').sync;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXTEND = require('extend');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HMSTATUS = require('./status-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moment = require('moment');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loadSafeJson = require('../utils/safe-json-loader');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  READFILES = require('recursive-readdir-sync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* A representation of a FRESH theme asset.
 | 
				
			||||||
 | 
					  @class FRESHTheme
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FRESHTheme = (function() {
 | 
				
			||||||
 | 
					    function FRESHTheme() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Open and parse the specified theme. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FRESHTheme.prototype.open = function(themeFolder) {
 | 
				
			||||||
 | 
					      var cached, formatsHash, pathInfo, that, themeFile, themeInfo;
 | 
				
			||||||
 | 
					      this.folder = themeFolder;
 | 
				
			||||||
 | 
					      pathInfo = parsePath(themeFolder);
 | 
				
			||||||
 | 
					      formatsHash = {};
 | 
				
			||||||
 | 
					      themeFile = PATH.join(themeFolder, 'theme.json');
 | 
				
			||||||
 | 
					      themeInfo = loadSafeJson(themeFile);
 | 
				
			||||||
 | 
					      if (themeInfo.ex) {
 | 
				
			||||||
 | 
					        throw {
 | 
				
			||||||
 | 
					          fluenterror: themeInfo.ex.operation === 'parse' ? HMSTATUS.parseError : HMSTATUS.readError,
 | 
				
			||||||
 | 
					          inner: themeInfo.ex.inner
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      that = this;
 | 
				
			||||||
 | 
					      EXTEND(true, this, themeInfo.json);
 | 
				
			||||||
 | 
					      if (this.inherits) {
 | 
				
			||||||
 | 
					        cached = {};
 | 
				
			||||||
 | 
					        _.each(this.inherits, function(th, key) {
 | 
				
			||||||
 | 
					          var d, themePath, themesFolder;
 | 
				
			||||||
 | 
					          themesFolder = require.resolve('fresh-themes');
 | 
				
			||||||
 | 
					          d = parsePath(themeFolder).dirname;
 | 
				
			||||||
 | 
					          themePath = PATH.join(d, th);
 | 
				
			||||||
 | 
					          cached[th] = cached[th] || new FRESHTheme().open(themePath);
 | 
				
			||||||
 | 
					          return formatsHash[key] = cached[th].getFormat(key);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      formatsHash = _load.call(this, formatsHash);
 | 
				
			||||||
 | 
					      this.formats = formatsHash;
 | 
				
			||||||
 | 
					      this.name = parsePath(this.folder).name;
 | 
				
			||||||
 | 
					      return this;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Determine if the theme supports the specified output format. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FRESHTheme.prototype.hasFormat = function(fmt) {
 | 
				
			||||||
 | 
					      return _.has(this.formats, fmt);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Determine if the theme supports the specified output format. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FRESHTheme.prototype.getFormat = function(fmt) {
 | 
				
			||||||
 | 
					      return this.formats[fmt];
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return FRESHTheme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  })();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Load and parse theme source files. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _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) {
 | 
				
			||||||
 | 
					      return _loadOne.call(this, absPath, formatsHash, tplFolder);
 | 
				
			||||||
 | 
					    }, this);
 | 
				
			||||||
 | 
					    this.cssFiles = fmts.filter(function(fmt) {
 | 
				
			||||||
 | 
					      return fmt && (fmt.ext === 'css');
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.cssFiles.forEach(function(cssf) {
 | 
				
			||||||
 | 
					      var idx;
 | 
				
			||||||
 | 
					      idx = _.findIndex(fmts, function(fmt) {
 | 
				
			||||||
 | 
					        return fmt && fmt.pre === cssf.pre && fmt.ext === 'html';
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      cssf.major = false;
 | 
				
			||||||
 | 
					      if (idx > -1) {
 | 
				
			||||||
 | 
					        fmts[idx].css = cssf.data;
 | 
				
			||||||
 | 
					        return fmts[idx].cssPath = cssf.path;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        if (that.inherits) {
 | 
				
			||||||
 | 
					          return that.overrides = {
 | 
				
			||||||
 | 
					            file: cssf.path,
 | 
				
			||||||
 | 
					            data: cssf.data
 | 
				
			||||||
 | 
					          };
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return formatsHash;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /* Load a single theme file. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _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 = this.formats[fmtKey];
 | 
				
			||||||
 | 
					        return _.some(fmtVal.transform, function(fpath) {
 | 
				
			||||||
 | 
					          var absPathB;
 | 
				
			||||||
 | 
					          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()) {
 | 
				
			||||||
 | 
					        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 (!this.explicit) {
 | 
				
			||||||
 | 
					        act = 'transform';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      defFormats = require('./default-formats');
 | 
				
			||||||
 | 
					      isPrimary = _.some(defFormats, function(form) {
 | 
				
			||||||
 | 
					        return form.name === outFmt && pathInfo.extname !== '.css';
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  friendlyName = function(val) {
 | 
				
			||||||
 | 
					    var friendly;
 | 
				
			||||||
 | 
					    val = (val && val.trim().toLowerCase()) || '';
 | 
				
			||||||
 | 
					    friendly = {
 | 
				
			||||||
 | 
					      yml: 'yaml',
 | 
				
			||||||
 | 
					      md: 'markdown',
 | 
				
			||||||
 | 
					      txt: 'text'
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return friendly[val] || val;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = FRESHTheme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=fresh-theme.js.map
 | 
				
			||||||
							
								
								
									
										422
									
								
								dist/core/jrs-resume.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										422
									
								
								dist/core/jrs-resume.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,422 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the JRSResume class.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module core/jrs-resume
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  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');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  extend = require('extend');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  validator = require('is-my-json-valid');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MD = require('marked');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CONVERTER = require('fresh-jrs-converter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moment = require('moment');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  AbstractResume = require('./abstract-resume');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  A JRS resume or CV. JRS resumes are backed by JSON, and each JRSResume object
 | 
				
			||||||
 | 
					  is an instantiation of that JSON decorated with utility methods.
 | 
				
			||||||
 | 
					  @class JRSResume
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  JRSResume = (function(superClass) {
 | 
				
			||||||
 | 
					    var clear;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    extend1(JRSResume, superClass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function JRSResume() {
 | 
				
			||||||
 | 
					      return JRSResume.__super__.constructor.apply(this, arguments);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Initialize the the JSResume from string. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.parse = function(stringData, opts) {
 | 
				
			||||||
 | 
					      var ref;
 | 
				
			||||||
 | 
					      this.imp = (ref = this.imp) != null ? ref : {
 | 
				
			||||||
 | 
					        raw: stringData
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      return this.parseJSON(JSON.parse(stringData), opts);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Initialize the JRSResume object from JSON.
 | 
				
			||||||
 | 
					    Open and parse the specified JRS resume. Merge the JSON object model onto
 | 
				
			||||||
 | 
					    this Sheet instance with extend() and convert sheet dates to a safe &
 | 
				
			||||||
 | 
					    consistent format. Then sort each section by startDate descending.
 | 
				
			||||||
 | 
					    @param rep {Object} The raw JSON representation.
 | 
				
			||||||
 | 
					    @param opts {Object} Resume loading and parsing options.
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      date: Perform safe date conversion.
 | 
				
			||||||
 | 
					      sort: Sort resume items by date.
 | 
				
			||||||
 | 
					      compute: Prepare computed resume totals.
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.parseJSON = function(rep, opts) {
 | 
				
			||||||
 | 
					      var ignoreList, ref, scrubbed, that, traverse;
 | 
				
			||||||
 | 
					      opts = opts || {};
 | 
				
			||||||
 | 
					      that = this;
 | 
				
			||||||
 | 
					      traverse = require('traverse');
 | 
				
			||||||
 | 
					      ignoreList = [];
 | 
				
			||||||
 | 
					      scrubbed = traverse(rep).map(function(x) {
 | 
				
			||||||
 | 
					        if (!this.isLeaf && this.node.ignore) {
 | 
				
			||||||
 | 
					          if (this.node.ignore === true || this.node.ignore === 'true') {
 | 
				
			||||||
 | 
					            ignoreList.push(this.node);
 | 
				
			||||||
 | 
					            return this.remove();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      extend(true, this, scrubbed);
 | 
				
			||||||
 | 
					      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();
 | 
				
			||||||
 | 
					      if (opts.compute === void 0 || opts.compute) {
 | 
				
			||||||
 | 
					        this.basics.computed = {
 | 
				
			||||||
 | 
					          numYears: this.duration(),
 | 
				
			||||||
 | 
					          keywords: this.keywords()
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return this;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Save the sheet to disk (for environments that have disk access). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.save = function(filename) {
 | 
				
			||||||
 | 
					      this.imp.file = filename || this.imp.file;
 | 
				
			||||||
 | 
					      FS.writeFileSync(this.imp.file, this.stringify(this), 'utf8');
 | 
				
			||||||
 | 
					      return this;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Save the sheet to disk in a specific format, either FRESH or JRS. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.saveAs = function(filename, format) {
 | 
				
			||||||
 | 
					      var newRep, stringRep;
 | 
				
			||||||
 | 
					      if (format === 'JRS') {
 | 
				
			||||||
 | 
					        this.imp.file = filename || this.imp.file;
 | 
				
			||||||
 | 
					        FS.writeFileSync(this.imp.file, this.stringify(), 'utf8');
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        newRep = CONVERTER.toFRESH(this);
 | 
				
			||||||
 | 
					        stringRep = CONVERTER.toSTRING(newRep);
 | 
				
			||||||
 | 
					        FS.writeFileSync(filename, stringRep, 'utf8');
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return this;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Return the resume format. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.format = function() {
 | 
				
			||||||
 | 
					      return 'JRS';
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.stringify = function() {
 | 
				
			||||||
 | 
					      return JRSResume.stringify(this);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Return a unique list of all keywords across all skills. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.keywords = function() {
 | 
				
			||||||
 | 
					      var flatSkills;
 | 
				
			||||||
 | 
					      flatSkills = [];
 | 
				
			||||||
 | 
					      if (this.skills && this.skills.length) {
 | 
				
			||||||
 | 
					        this.skills.forEach(function(s) {
 | 
				
			||||||
 | 
					          return flatSkills = _.union(flatSkills, s.keywords);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return flatSkills;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Return internal metadata. Create if it doesn't exist.
 | 
				
			||||||
 | 
					    JSON Resume v0.0.0 doesn't allow additional properties at the root level,
 | 
				
			||||||
 | 
					    so tuck this into the .basic sub-object.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.i = function() {
 | 
				
			||||||
 | 
					      var ref;
 | 
				
			||||||
 | 
					      return this.imp = (ref = this.imp) != null ? ref : {};
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Reset the sheet to an empty state. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    clear = function(clearMeta) {
 | 
				
			||||||
 | 
					      clearMeta = ((clearMeta === void 0) && true) || clearMeta;
 | 
				
			||||||
 | 
					      if (clearMeta) {
 | 
				
			||||||
 | 
					        delete this.imp;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      delete this.basics.computed;
 | 
				
			||||||
 | 
					      delete this.work;
 | 
				
			||||||
 | 
					      delete this.volunteer;
 | 
				
			||||||
 | 
					      delete this.education;
 | 
				
			||||||
 | 
					      delete this.awards;
 | 
				
			||||||
 | 
					      delete this.publications;
 | 
				
			||||||
 | 
					      delete this.interests;
 | 
				
			||||||
 | 
					      delete this.skills;
 | 
				
			||||||
 | 
					      return delete this.basics.profiles;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Add work experience to the sheet. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.add = function(moniker) {
 | 
				
			||||||
 | 
					      var defSheet, newObject;
 | 
				
			||||||
 | 
					      defSheet = JRSResume["default"]();
 | 
				
			||||||
 | 
					      newObject = $.extend(true, {}, defSheet[moniker][0]);
 | 
				
			||||||
 | 
					      this[moniker] = this[moniker] || [];
 | 
				
			||||||
 | 
					      this[moniker].push(newObject);
 | 
				
			||||||
 | 
					      return newObject;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Determine if the sheet includes a specific social profile (eg, GitHub). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.hasProfile = function(socialNetwork) {
 | 
				
			||||||
 | 
					      socialNetwork = socialNetwork.trim().toLowerCase();
 | 
				
			||||||
 | 
					      return this.basics.profiles && _.some(this.basics.profiles, function(p) {
 | 
				
			||||||
 | 
					        return p.network.trim().toLowerCase() === socialNetwork;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Determine if the sheet includes a specific skill. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.hasSkill = function(skill) {
 | 
				
			||||||
 | 
					      skill = skill.trim().toLowerCase();
 | 
				
			||||||
 | 
					      return this.skills && _.some(this.skills, function(sk) {
 | 
				
			||||||
 | 
					        return sk.keywords && _.some(sk.keywords, function(kw) {
 | 
				
			||||||
 | 
					          return kw.trim().toLowerCase() === skill;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Validate the sheet against the JSON Resume schema. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.isValid = function() {
 | 
				
			||||||
 | 
					      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');
 | 
				
			||||||
 | 
					      validate = validator(schemaObj, {
 | 
				
			||||||
 | 
					        formats: {
 | 
				
			||||||
 | 
					          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.imp = this.imp || {};
 | 
				
			||||||
 | 
					        this.imp.validationErrors = validate.errors;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return ret;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.duration = function(unit) {
 | 
				
			||||||
 | 
					      return JRSResume.__super__.duration.call(this, 'work', 'startDate', 'endDate', unit);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Sort dated things on the sheet by start date descending. Assumes that dates
 | 
				
			||||||
 | 
					    on the sheet have been processed with _parseDates().
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.sort = function() {
 | 
				
			||||||
 | 
					      var byDateDesc;
 | 
				
			||||||
 | 
					      byDateDesc = function(a, b) {
 | 
				
			||||||
 | 
					        if (a.safeStartDate.isBefore(b.safeStartDate)) {
 | 
				
			||||||
 | 
					          return 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return (a.safeStartDate.isAfter(b.safeStartDate) && -1) || 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      this.work && this.work.sort(byDateDesc);
 | 
				
			||||||
 | 
					      this.education && this.education.sort(byDateDesc);
 | 
				
			||||||
 | 
					      this.volunteer && this.volunteer.sort(byDateDesc);
 | 
				
			||||||
 | 
					      this.awards && this.awards.sort(function(a, b) {
 | 
				
			||||||
 | 
					        if (a.safeDate.isBefore(b.safeDate)) {
 | 
				
			||||||
 | 
					          return 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return (a.safeDate.isAfter(b.safeDate) && -1) || 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return this.publications && this.publications.sort(function(a, b) {
 | 
				
			||||||
 | 
					        if (a.safeReleaseDate.isBefore(b.safeReleaseDate)) {
 | 
				
			||||||
 | 
					          return 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return (a.safeReleaseDate.isAfter(b.safeReleaseDate) && -1) || 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.dupe = function() {
 | 
				
			||||||
 | 
					      var rnew;
 | 
				
			||||||
 | 
					      rnew = new JRSResume();
 | 
				
			||||||
 | 
					      rnew.parse(this.stringify(), {});
 | 
				
			||||||
 | 
					      return rnew;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Create a copy of this resume in which all fields have been interpreted as
 | 
				
			||||||
 | 
					    Markdown.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSResume.prototype.harden = function() {
 | 
				
			||||||
 | 
					      var HD, HDIN, hardenStringsInObject, ret, that;
 | 
				
			||||||
 | 
					      that = this;
 | 
				
			||||||
 | 
					      ret = this.dupe();
 | 
				
			||||||
 | 
					      HD = function(txt) {
 | 
				
			||||||
 | 
					        return '@@@@~' + txt + '~@@@@';
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      HDIN = function(txt) {
 | 
				
			||||||
 | 
					        return HD(txt);
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      hardenStringsInObject = function(obj, inline) {
 | 
				
			||||||
 | 
					        if (!obj) {
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        inline = inline === void 0 || inline;
 | 
				
			||||||
 | 
					        if (Object.prototype.toString.call(obj) === '[object Array]') {
 | 
				
			||||||
 | 
					          return obj.forEach(function(elem, idx, ar) {
 | 
				
			||||||
 | 
					            if (typeof elem === 'string' || elem instanceof String) {
 | 
				
			||||||
 | 
					              return ar[idx] = inline ? HDIN(elem) : HD(elem);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              return hardenStringsInObject(elem);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        } else if (typeof obj === 'object') {
 | 
				
			||||||
 | 
					          return Object.keys(obj).forEach(function(key) {
 | 
				
			||||||
 | 
					            var sub;
 | 
				
			||||||
 | 
					            sub = obj[key];
 | 
				
			||||||
 | 
					            if (typeof sub === 'string' || sub instanceof String) {
 | 
				
			||||||
 | 
					              if (_.contains(['skills', 'url', 'website', 'startDate', 'endDate', 'releaseDate', 'date', 'phone', 'email', 'address', 'postalCode', 'city', 'country', 'region'], key)) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					              if (key === 'summary') {
 | 
				
			||||||
 | 
					                return obj[key] = HD(obj[key]);
 | 
				
			||||||
 | 
					              } else {
 | 
				
			||||||
 | 
					                return obj[key] = inline ? HDIN(obj[key]) : HD(obj[key]);
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              return hardenStringsInObject(sub);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      Object.keys(ret).forEach(function(member) {
 | 
				
			||||||
 | 
					        return hardenStringsInObject(ret[member]);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return ret;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return JRSResume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  })(AbstractResume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Get the default (empty) sheet. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  JRSResume["default"] = function() {
 | 
				
			||||||
 | 
					    return new JRSResume().parseJSON(require('fresh-resume-starter').jrs);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Convert this object to a JSON string, sanitizing meta-properties along the
 | 
				
			||||||
 | 
					  way. Don't override .toString().
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  JRSResume.stringify = function(obj) {
 | 
				
			||||||
 | 
					    var replacer;
 | 
				
			||||||
 | 
					    replacer = function(key, value) {
 | 
				
			||||||
 | 
					      var temp;
 | 
				
			||||||
 | 
					      temp = _.some(['imp', 'warnings', 'computed', 'filt', 'ctrl', 'index', 'safeStartDate', 'safeEndDate', 'safeDate', 'safeReleaseDate', 'result', 'isModified', 'htmlPreview', 'display_progress_bar'], function(val) {
 | 
				
			||||||
 | 
					        return key.trim() === val;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      if (temp) {
 | 
				
			||||||
 | 
					        return void 0;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return value;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    return JSON.stringify(obj, replacer, 2);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Convert human-friendly dates into formal Moment.js dates for all collections.
 | 
				
			||||||
 | 
					  We don't want to lose the raw textual date as entered by the user, so we store
 | 
				
			||||||
 | 
					  the Moment-ified date as a separate property with a prefix of .safe. For ex:
 | 
				
			||||||
 | 
					  job.startDate is the date as entered by the user. job.safeStartDate is the
 | 
				
			||||||
 | 
					  parsed Moment.js date that we actually use in processing.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _parseDates = function() {
 | 
				
			||||||
 | 
					    var _fmt;
 | 
				
			||||||
 | 
					    _fmt = require('./fluent-date').fmt;
 | 
				
			||||||
 | 
					    this.work && this.work.forEach(function(job) {
 | 
				
			||||||
 | 
					      job.safeStartDate = _fmt(job.startDate);
 | 
				
			||||||
 | 
					      return job.safeEndDate = _fmt(job.endDate);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.education && this.education.forEach(function(edu) {
 | 
				
			||||||
 | 
					      edu.safeStartDate = _fmt(edu.startDate);
 | 
				
			||||||
 | 
					      return edu.safeEndDate = _fmt(edu.endDate);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.volunteer && this.volunteer.forEach(function(vol) {
 | 
				
			||||||
 | 
					      vol.safeStartDate = _fmt(vol.startDate);
 | 
				
			||||||
 | 
					      return vol.safeEndDate = _fmt(vol.endDate);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    this.awards && this.awards.forEach(function(awd) {
 | 
				
			||||||
 | 
					      return awd.safeDate = _fmt(awd.date);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return this.publications && this.publications.forEach(function(pub) {
 | 
				
			||||||
 | 
					      return pub.safeReleaseDate = _fmt(pub.releaseDate);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Export the JRSResume function/ctor.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = JRSResume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=jrs-resume.js.map
 | 
				
			||||||
							
								
								
									
										107
									
								
								dist/core/jrs-theme.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								dist/core/jrs-theme.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the JRSTheme class.
 | 
				
			||||||
 | 
					@module core/jrs-theme
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.MD for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var JRSTheme, PATH, _, parsePath, pathExists;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  parsePath = require('parse-filepath');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  pathExists = require('path-exists').sync;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  The JRSTheme class is a representation of a JSON Resume theme asset.
 | 
				
			||||||
 | 
					  @class JRSTheme
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  JRSTheme = (function() {
 | 
				
			||||||
 | 
					    function JRSTheme() {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Open and parse the specified theme.
 | 
				
			||||||
 | 
					    @method open
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSTheme.prototype.open = function(thFolder) {
 | 
				
			||||||
 | 
					      var pathInfo, pkgJsonPath, thApi, thPkg;
 | 
				
			||||||
 | 
					      this.folder = thFolder;
 | 
				
			||||||
 | 
					      pathInfo = parsePath(thFolder);
 | 
				
			||||||
 | 
					      pkgJsonPath = PATH.join(thFolder, 'package.json');
 | 
				
			||||||
 | 
					      if (pathExists(pkgJsonPath)) {
 | 
				
			||||||
 | 
					        thApi = require(thFolder);
 | 
				
			||||||
 | 
					        thPkg = require(pkgJsonPath);
 | 
				
			||||||
 | 
					        this.name = thPkg.name;
 | 
				
			||||||
 | 
					        this.render = (thApi && thApi.render) || void 0;
 | 
				
			||||||
 | 
					        this.engine = 'jrs';
 | 
				
			||||||
 | 
					        this.formats = {
 | 
				
			||||||
 | 
					          html: {
 | 
				
			||||||
 | 
					            outFormat: 'html',
 | 
				
			||||||
 | 
					            files: [
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                action: 'transform',
 | 
				
			||||||
 | 
					                render: this.render,
 | 
				
			||||||
 | 
					                primary: true,
 | 
				
			||||||
 | 
					                ext: 'html',
 | 
				
			||||||
 | 
					                css: null
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          pdf: {
 | 
				
			||||||
 | 
					            outFormat: 'pdf',
 | 
				
			||||||
 | 
					            files: [
 | 
				
			||||||
 | 
					              {
 | 
				
			||||||
 | 
					                action: 'transform',
 | 
				
			||||||
 | 
					                render: this.render,
 | 
				
			||||||
 | 
					                primary: true,
 | 
				
			||||||
 | 
					                ext: 'pdf',
 | 
				
			||||||
 | 
					                css: null
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        throw {
 | 
				
			||||||
 | 
					          fluenterror: HACKMYSTATUS.missingPackageJSON
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return this;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Determine if the theme supports the output format.
 | 
				
			||||||
 | 
					    @method hasFormat
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSTheme.prototype.hasFormat = function(fmt) {
 | 
				
			||||||
 | 
					      return _.has(this.formats, fmt);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Return the requested output format.
 | 
				
			||||||
 | 
					    @method getFormat
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    JRSTheme.prototype.getFormat = function(fmt) {
 | 
				
			||||||
 | 
					      return this.formats[fmt];
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return JRSTheme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  })();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = JRSTheme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=jrs-theme.js.map
 | 
				
			||||||
							
								
								
									
										122
									
								
								dist/core/resume-factory.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								dist/core/resume-factory.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,122 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the ResumeFactory class.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module core/resume-factory
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var FS, HACKMYSTATUS, HME, ResumeConverter, ResumeFactory, SyntaxErrorEx, _, _parse, chalk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FS = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HACKMYSTATUS = require('./status-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HME = require('./event-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ResumeConverter = require('fresh-jrs-converter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  chalk = require('chalk');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SyntaxErrorEx = require('../utils/syntax-error-ex');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  require('string.prototype.startswith');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  A simple factory class for FRESH and JSON Resumes.
 | 
				
			||||||
 | 
					  @class ResumeFactory
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ResumeFactory = module.exports = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Load one or more resumes from disk.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @param {Object} opts An options object with settings for the factory as well
 | 
				
			||||||
 | 
					    as passthrough settings for FRESHResume or JRSResume. Structure:
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          format: 'FRESH',    // Format to open as. ('FRESH', 'JRS', null)
 | 
				
			||||||
 | 
					          objectify: true,    // FRESH/JRSResume or raw JSON?
 | 
				
			||||||
 | 
					          inner: {            // Passthru options for FRESH/JRSResume
 | 
				
			||||||
 | 
					            sort: false
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    load: function(sources, opts, emitter) {
 | 
				
			||||||
 | 
					      return sources.map(function(src) {
 | 
				
			||||||
 | 
					        return this.loadOne(src, opts, emitter);
 | 
				
			||||||
 | 
					      }, this);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Load a single resume from disk. */
 | 
				
			||||||
 | 
					    loadOne: function(src, opts, emitter) {
 | 
				
			||||||
 | 
					      var ResumeClass, info, isFRESH, json, objectify, orgFormat, rez, toFormat;
 | 
				
			||||||
 | 
					      toFormat = opts.format;
 | 
				
			||||||
 | 
					      objectify = opts.objectify;
 | 
				
			||||||
 | 
					      toFormat && (toFormat = toFormat.toLowerCase().trim());
 | 
				
			||||||
 | 
					      info = _parse(src, opts, emitter);
 | 
				
			||||||
 | 
					      if (info.fluenterror) {
 | 
				
			||||||
 | 
					        return info;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      json = info.json;
 | 
				
			||||||
 | 
					      isFRESH = json.meta && json.meta.format && json.meta.format.startsWith('FRESH@');
 | 
				
			||||||
 | 
					      orgFormat = isFRESH ? 'fresh' : 'jrs';
 | 
				
			||||||
 | 
					      if (toFormat && (orgFormat !== toFormat)) {
 | 
				
			||||||
 | 
					        json = ResumeConverter['to' + toFormat.toUpperCase()](json);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      rez = null;
 | 
				
			||||||
 | 
					      if (objectify) {
 | 
				
			||||||
 | 
					        ResumeClass = require('../core/' + (toFormat || orgFormat) + '-resume');
 | 
				
			||||||
 | 
					        rez = new ResumeClass().parseJSON(json, opts.inner);
 | 
				
			||||||
 | 
					        rez.i().file = src;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        file: src,
 | 
				
			||||||
 | 
					        json: info.json,
 | 
				
			||||||
 | 
					        rez: rez
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _parse = function(fileName, opts, eve) {
 | 
				
			||||||
 | 
					    var orgFormat, rawData, ret;
 | 
				
			||||||
 | 
					    rawData = null;
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      eve && eve.stat(HME.beforeRead, {
 | 
				
			||||||
 | 
					        file: fileName
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      rawData = FS.readFileSync(fileName, 'utf8');
 | 
				
			||||||
 | 
					      eve && eve.stat(HME.afterRead, {
 | 
				
			||||||
 | 
					        file: fileName,
 | 
				
			||||||
 | 
					        data: rawData
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      eve && eve.stat(HME.beforeParse, {
 | 
				
			||||||
 | 
					        data: rawData
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      ret = {
 | 
				
			||||||
 | 
					        json: JSON.parse(rawData)
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      orgFormat = ret.json.meta && ret.json.meta.format && ret.json.meta.format.startsWith('FRESH@') ? 'fresh' : 'jrs';
 | 
				
			||||||
 | 
					      eve && eve.stat(HME.afterParse, {
 | 
				
			||||||
 | 
					        file: fileName,
 | 
				
			||||||
 | 
					        data: ret.json,
 | 
				
			||||||
 | 
					        fmt: orgFormat
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return ret;
 | 
				
			||||||
 | 
					    } catch (_error) {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        fluenterror: rawData ? HACKMYSTATUS.parseError : HACKMYSTATUS.readError,
 | 
				
			||||||
 | 
					        inner: _error,
 | 
				
			||||||
 | 
					        raw: rawData,
 | 
				
			||||||
 | 
					        file: fileName
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=resume-factory.js.map
 | 
				
			||||||
							
								
								
									
										380
									
								
								dist/core/resume.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								dist/core/resume.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,380 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "$schema": "http://json-schema.org/draft-04/schema#",
 | 
				
			||||||
 | 
					  "title": "Resume Schema",
 | 
				
			||||||
 | 
					  "type": "object",
 | 
				
			||||||
 | 
					  "additionalProperties": false,
 | 
				
			||||||
 | 
					  "properties": {
 | 
				
			||||||
 | 
					    "basics": {
 | 
				
			||||||
 | 
					      "type": "object",
 | 
				
			||||||
 | 
					      "additionalProperties": true,
 | 
				
			||||||
 | 
					      "properties": {
 | 
				
			||||||
 | 
					        "name": {
 | 
				
			||||||
 | 
					          "type": "string"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "label": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "description": "e.g. Web Developer"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "picture": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "description": "URL (as per RFC 3986) to a picture in JPEG or PNG format"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "email": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "description": "e.g. thomas@gmail.com",
 | 
				
			||||||
 | 
					          "format": "email"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "phone": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "description": "Phone numbers are stored as strings so use any format you like, e.g. 712-117-2923"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "website": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "description": "URL (as per RFC 3986) to your website, e.g. personal homepage",
 | 
				
			||||||
 | 
					          "format": "uri"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "summary": {
 | 
				
			||||||
 | 
					          "type": "string",
 | 
				
			||||||
 | 
					          "description": "Write a short 2-3 sentence biography about yourself"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "location": {
 | 
				
			||||||
 | 
					          "type": "object",
 | 
				
			||||||
 | 
					          "additionalProperties": true,
 | 
				
			||||||
 | 
					          "properties": {
 | 
				
			||||||
 | 
					            "address": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "To add multiple address lines, use \n. For example, 1234 Glücklichkeit Straße\nHinterhaus 5. Etage li."
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "postalCode": {
 | 
				
			||||||
 | 
					              "type": "string"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "city": {
 | 
				
			||||||
 | 
					              "type": "string"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "countryCode": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "code as per ISO-3166-1 ALPHA-2, e.g. US, AU, IN"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "region": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "The general region where you live. Can be a US state, or a province, for instance."
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "profiles": {
 | 
				
			||||||
 | 
					          "type": "array",
 | 
				
			||||||
 | 
					          "description": "Specify any number of social networks that you participate in",
 | 
				
			||||||
 | 
					          "additionalItems": false,
 | 
				
			||||||
 | 
					          "items": {
 | 
				
			||||||
 | 
					            "type": "object",
 | 
				
			||||||
 | 
					            "additionalProperties": true,
 | 
				
			||||||
 | 
					            "properties": {
 | 
				
			||||||
 | 
					              "network": {
 | 
				
			||||||
 | 
					                "type": "string",
 | 
				
			||||||
 | 
					                "description": "e.g. Facebook or Twitter"
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              "username": {
 | 
				
			||||||
 | 
					                "type": "string",
 | 
				
			||||||
 | 
					                "description": "e.g. neutralthoughts"
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              "url": {
 | 
				
			||||||
 | 
					                "type": "string",
 | 
				
			||||||
 | 
					                "description": "e.g. http://twitter.com/neutralthoughts"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "work": {
 | 
				
			||||||
 | 
					      "type": "array",
 | 
				
			||||||
 | 
					      "additionalItems": false,
 | 
				
			||||||
 | 
					      "items": {
 | 
				
			||||||
 | 
					        "type": "object",
 | 
				
			||||||
 | 
					        "additionalProperties": true,
 | 
				
			||||||
 | 
					      "properties": {
 | 
				
			||||||
 | 
					          "company": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. Facebook"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "position": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. Software Engineer"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "website": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. http://facebook.com",
 | 
				
			||||||
 | 
					            "format": "uri"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "startDate": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "resume.json uses the ISO 8601 date standard e.g. 2014-06-29",
 | 
				
			||||||
 | 
					            "format": "date"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "endDate": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. 2012-06-29",
 | 
				
			||||||
 | 
					            "format": "date"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "summary": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "Give an overview of your responsibilities at the company"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "highlights": {
 | 
				
			||||||
 | 
					            "type": "array",
 | 
				
			||||||
 | 
					            "description": "Specify multiple accomplishments",
 | 
				
			||||||
 | 
					            "additionalItems": false,
 | 
				
			||||||
 | 
					            "items": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. Increased profits by 20% from 2011-2012 through viral advertising"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "volunteer": {
 | 
				
			||||||
 | 
					      "type": "array",
 | 
				
			||||||
 | 
					      "additionalItems": false,
 | 
				
			||||||
 | 
					      "items": {
 | 
				
			||||||
 | 
					        "type": "object",
 | 
				
			||||||
 | 
					        "additionalProperties": true,
 | 
				
			||||||
 | 
					      "properties": {
 | 
				
			||||||
 | 
					          "organization": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. Facebook"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "position": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. Software Engineer"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "website": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. http://facebook.com",
 | 
				
			||||||
 | 
					            "format": "uri"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "startDate": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "resume.json uses the ISO 8601 date standard e.g. 2014-06-29",
 | 
				
			||||||
 | 
					            "format": "date"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "endDate": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. 2012-06-29",
 | 
				
			||||||
 | 
					            "format": "date"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "summary": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "Give an overview of your responsibilities at the company"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "highlights": {
 | 
				
			||||||
 | 
					            "type": "array",
 | 
				
			||||||
 | 
					            "description": "Specify multiple accomplishments",
 | 
				
			||||||
 | 
					            "additionalItems": false,
 | 
				
			||||||
 | 
					            "items": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. Increased profits by 20% from 2011-2012 through viral advertising"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "education": {
 | 
				
			||||||
 | 
					      "type": "array",
 | 
				
			||||||
 | 
					      "additionalItems": false,
 | 
				
			||||||
 | 
					      "items": {
 | 
				
			||||||
 | 
					        "type": "object",
 | 
				
			||||||
 | 
					        "additionalProperties": true,
 | 
				
			||||||
 | 
					      "properties": {
 | 
				
			||||||
 | 
					            "institution": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. Massachusetts Institute of Technology"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "area": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. Arts"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "studyType": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. Bachelor"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "startDate": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. 2014-06-29",
 | 
				
			||||||
 | 
					              "format": "date"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "endDate": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. 2012-06-29",
 | 
				
			||||||
 | 
					              "format": "date"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "gpa": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "grade point average, e.g. 3.67/4.0"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "courses": {
 | 
				
			||||||
 | 
					              "type": "array",
 | 
				
			||||||
 | 
					              "description": "List notable courses/subjects",
 | 
				
			||||||
 | 
					              "additionalItems": false,
 | 
				
			||||||
 | 
					              "items": {
 | 
				
			||||||
 | 
					                "type": "string",
 | 
				
			||||||
 | 
					                "description": "e.g. H1302 - Introduction to American history"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "awards": {
 | 
				
			||||||
 | 
					      "type": "array",
 | 
				
			||||||
 | 
					      "description": "Specify any awards you have received throughout your professional career",
 | 
				
			||||||
 | 
					      "additionalItems": false,
 | 
				
			||||||
 | 
					      "items": {
 | 
				
			||||||
 | 
					          "type": "object",
 | 
				
			||||||
 | 
					          "additionalProperties": true,
 | 
				
			||||||
 | 
					        "properties": {
 | 
				
			||||||
 | 
					            "title": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. One of the 100 greatest minds of the century"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "date": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. 1989-06-12",
 | 
				
			||||||
 | 
					              "format": "date"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "awarder": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. Time Magazine"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "summary": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. Received for my work with Quantum Physics"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "publications": {
 | 
				
			||||||
 | 
					      "type": "array",
 | 
				
			||||||
 | 
					      "description": "Specify your publications through your career",
 | 
				
			||||||
 | 
					      "additionalItems": false,
 | 
				
			||||||
 | 
					      "items": {
 | 
				
			||||||
 | 
					          "type": "object",
 | 
				
			||||||
 | 
					          "additionalProperties": true,
 | 
				
			||||||
 | 
					        "properties": {
 | 
				
			||||||
 | 
					            "name": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. The World Wide Web"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "publisher": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. IEEE, Computer Magazine"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "releaseDate": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. 1990-08-01"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "website": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. http://www.computer.org/csdl/mags/co/1996/10/rx069-abs.html"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "summary": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "Short summary of publication. e.g. Discussion of the World Wide Web, HTTP, HTML."
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "skills": {
 | 
				
			||||||
 | 
					      "type": "array",
 | 
				
			||||||
 | 
					      "description": "List out your professional skill-set",
 | 
				
			||||||
 | 
					      "additionalItems": false,
 | 
				
			||||||
 | 
					      "items": {
 | 
				
			||||||
 | 
					          "type": "object",
 | 
				
			||||||
 | 
					          "additionalProperties": true,
 | 
				
			||||||
 | 
					        "properties": {
 | 
				
			||||||
 | 
					            "name": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. Web Development"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "level": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. Master"
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "keywords": {
 | 
				
			||||||
 | 
					              "type": "array",
 | 
				
			||||||
 | 
					              "description": "List some keywords pertaining to this skill",
 | 
				
			||||||
 | 
					              "additionalItems": false,
 | 
				
			||||||
 | 
					              "items": {
 | 
				
			||||||
 | 
					                "type": "string",
 | 
				
			||||||
 | 
					                "description": "e.g. HTML"
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "languages": {
 | 
				
			||||||
 | 
					      "type": "array",
 | 
				
			||||||
 | 
					      "description": "List any other languages you speak",
 | 
				
			||||||
 | 
					      "additionalItems": false,
 | 
				
			||||||
 | 
					      "items": {
 | 
				
			||||||
 | 
					        "type": "object",
 | 
				
			||||||
 | 
					        "additionalProperties": true,
 | 
				
			||||||
 | 
					        "properties": {
 | 
				
			||||||
 | 
					          "language": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. English, Spanish"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "fluency": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. Fluent, Beginner"
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "interests": {
 | 
				
			||||||
 | 
					      "type": "array",
 | 
				
			||||||
 | 
					      "additionalItems": false,
 | 
				
			||||||
 | 
					      "items": {
 | 
				
			||||||
 | 
					        "type": "object",
 | 
				
			||||||
 | 
					        "additionalProperties": true,
 | 
				
			||||||
 | 
					      "properties": {
 | 
				
			||||||
 | 
					          "name": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. Philosophy"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "keywords": {
 | 
				
			||||||
 | 
					            "type": "array",
 | 
				
			||||||
 | 
					            "additionalItems": false,
 | 
				
			||||||
 | 
					            "items": {
 | 
				
			||||||
 | 
					              "type": "string",
 | 
				
			||||||
 | 
					              "description": "e.g. Friedrich Nietzsche"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "references": {
 | 
				
			||||||
 | 
					      "type": "array",
 | 
				
			||||||
 | 
					      "description": "List references you have received",
 | 
				
			||||||
 | 
					      "additionalItems": false,
 | 
				
			||||||
 | 
					      "items": {
 | 
				
			||||||
 | 
					        "type": "object",
 | 
				
			||||||
 | 
					        "additionalProperties": true,
 | 
				
			||||||
 | 
					      "properties": {
 | 
				
			||||||
 | 
					          "name": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. Timothy Cook"
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          "reference": {
 | 
				
			||||||
 | 
					            "type": "string",
 | 
				
			||||||
 | 
					            "description": "e.g. Joe blogs was a great employee, who turned up to work at least once a week. He exceeded my expectations when it came to doing nothing."
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										41
									
								
								dist/core/status-codes.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								dist/core/status-codes.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Status codes for HackMyResume.
 | 
				
			||||||
 | 
					@module core/status-codes
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.MD for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  module.exports = {
 | 
				
			||||||
 | 
					    success: 0,
 | 
				
			||||||
 | 
					    themeNotFound: 1,
 | 
				
			||||||
 | 
					    copyCss: 2,
 | 
				
			||||||
 | 
					    resumeNotFound: 3,
 | 
				
			||||||
 | 
					    missingCommand: 4,
 | 
				
			||||||
 | 
					    invalidCommand: 5,
 | 
				
			||||||
 | 
					    resumeNotFoundAlt: 6,
 | 
				
			||||||
 | 
					    inputOutputParity: 7,
 | 
				
			||||||
 | 
					    createNameMissing: 8,
 | 
				
			||||||
 | 
					    pdfGeneration: 9,
 | 
				
			||||||
 | 
					    missingPackageJSON: 10,
 | 
				
			||||||
 | 
					    invalid: 11,
 | 
				
			||||||
 | 
					    invalidFormat: 12,
 | 
				
			||||||
 | 
					    notOnPath: 13,
 | 
				
			||||||
 | 
					    readError: 14,
 | 
				
			||||||
 | 
					    parseError: 15,
 | 
				
			||||||
 | 
					    fileSaveError: 16,
 | 
				
			||||||
 | 
					    generateError: 17,
 | 
				
			||||||
 | 
					    invalidHelperUse: 18,
 | 
				
			||||||
 | 
					    mixedMerge: 19,
 | 
				
			||||||
 | 
					    invokeTemplate: 20,
 | 
				
			||||||
 | 
					    compileTemplate: 21,
 | 
				
			||||||
 | 
					    themeLoad: 22,
 | 
				
			||||||
 | 
					    invalidParamCount: 23,
 | 
				
			||||||
 | 
					    missingParam: 24,
 | 
				
			||||||
 | 
					    createError: 25,
 | 
				
			||||||
 | 
					    validateError: 26
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=status-codes.js.map
 | 
				
			||||||
							
								
								
									
										40
									
								
								dist/generators/base-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								dist/generators/base-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										53
									
								
								dist/generators/html-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										117
									
								
								dist/generators/html-pdf-cli-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								dist/generators/html-pdf-cli-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										75
									
								
								dist/generators/html-png-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								dist/generators/html-png-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,75 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the HtmlPngGenerator class.
 | 
				
			||||||
 | 
					@module generators/html-png-generator
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.MD for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  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');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FS = require('fs-extra');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HTML = require('html');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SLASH = require('slash');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SPAWN = require('../utils/safe-spawn');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  An HTML-based PNG resume generator for HackMyResume.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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';
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      htmlFile = htmlResults[0].final.files.filter(function(fl) {
 | 
				
			||||||
 | 
					        return fl.info.ext === 'html';
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      phantom(htmlFile[0].data, f);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return HtmlPngGenerator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  })(TemplateGenerator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  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(/\.png$/i, '.png.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));
 | 
				
			||||||
 | 
					    info = SPAWN('phantomjs', [scriptPath, sourcePath, destPath]);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=html-png-generator.js.map
 | 
				
			||||||
							
								
								
									
										47
									
								
								dist/generators/json-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								dist/generators/json-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										50
									
								
								dist/generators/json-yaml-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										33
									
								
								dist/generators/latex-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										33
									
								
								dist/generators/markdown-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										288
									
								
								dist/generators/template-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								dist/generators/template-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,288 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the TemplateGenerator class. TODO: Refactor
 | 
				
			||||||
 | 
					@module generators/template-generator
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  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');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MD = require('marked');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  XML = require('xml-escape');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  parsePath = require('parse-filepath');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MKDIRP = require('mkdirp');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BaseGenerator = require('./base-generator');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  EXTEND = require('extend');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FRESHTheme = require('../core/fresh-theme');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  JRSTheme = require('../core/jrs-theme');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  TemplateGenerator performs resume generation via local Handlebar or Underscore
 | 
				
			||||||
 | 
					  style template expansion and is appropriate for text-based formats like HTML,
 | 
				
			||||||
 | 
					  plain text, and XML versions of Microsoft Word, Excel, and OpenOffice.
 | 
				
			||||||
 | 
					  @class TemplateGenerator
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  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.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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.
 | 
				
			||||||
 | 
					    @method invoke
 | 
				
			||||||
 | 
					    @param rez A FreshResume object.
 | 
				
			||||||
 | 
					    @param opts Generator options.
 | 
				
			||||||
 | 
					    @returns {Array} An array of objects representing the generated output
 | 
				
			||||||
 | 
					    files.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					      curFmt.files = _.sortBy(curFmt.files, function(fi) {
 | 
				
			||||||
 | 
					        return fi.ext !== 'css';
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      results = curFmt.files.map(function(tplInfo, idx) {
 | 
				
			||||||
 | 
					        var 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 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (typeof opts.onTransform === "function") {
 | 
				
			||||||
 | 
					          opts.onTransform(tplInfo);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          info: tplInfo,
 | 
				
			||||||
 | 
					          data: trx
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }, this);
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        files: results
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Generate a resume using file-based inputs and outputs. Requires access
 | 
				
			||||||
 | 
					    to the local filesystem.
 | 
				
			||||||
 | 
					    @method generate
 | 
				
			||||||
 | 
					    @param rez A FreshResume object.
 | 
				
			||||||
 | 
					    @param f Full path to the output resume file to generate.
 | 
				
			||||||
 | 
					    @param opts Generator options.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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 thisFilePath;
 | 
				
			||||||
 | 
					        file.info.orgPath = file.info.orgPath || '';
 | 
				
			||||||
 | 
					        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: thisFilePath,
 | 
				
			||||||
 | 
					            mk: file.data,
 | 
				
			||||||
 | 
					            opts: this.opts,
 | 
				
			||||||
 | 
					            ext: file.info.ext
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          if (!file.data) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        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,
 | 
				
			||||||
 | 
					            mk: file.data,
 | 
				
			||||||
 | 
					            opts: this.opts
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }, this);
 | 
				
			||||||
 | 
					      createSymLinks(curFmt, outFolder);
 | 
				
			||||||
 | 
					      return genInfo;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Perform a single resume resume transformation using string-based inputs
 | 
				
			||||||
 | 
					    and outputs without touching the local file system.
 | 
				
			||||||
 | 
					    @param json A FRESH or JRS resume object.
 | 
				
			||||||
 | 
					    @param jst The stringified template data
 | 
				
			||||||
 | 
					    @param format The format name, such as "html" or "latex"
 | 
				
			||||||
 | 
					    @param cssInfo Needs to be refactored.
 | 
				
			||||||
 | 
					    @param opts Options and passthrough data.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    TemplateGenerator.prototype.transform = function(json, jst, format, opts, theme, curFmt) {
 | 
				
			||||||
 | 
					      var eng, result;
 | 
				
			||||||
 | 
					      if (this.opts.freezeBreaks) {
 | 
				
			||||||
 | 
					        jst = freeze(jst);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      eng = require('../renderers/' + theme.engine + '-generator');
 | 
				
			||||||
 | 
					      result = eng.generate(json, jst, format, curFmt, opts, theme);
 | 
				
			||||||
 | 
					      if (this.opts.freezeBreaks) {
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Freeze newlines for protection against errant JST parsers. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  freeze = function(markup) {
 | 
				
			||||||
 | 
					    markup.replace(_reg.regN, _defaultOpts.nSym);
 | 
				
			||||||
 | 
					    return markup.replace(_reg.regR, _defaultOpts.rSym);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Unfreeze newlines when the coast is clear. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  unfreeze = function(markup) {
 | 
				
			||||||
 | 
					    markup.replace(_reg.regSymR, '\r');
 | 
				
			||||||
 | 
					    return markup.replace(_reg.regSymN, '\n');
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Default template generator options. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _defaultOpts = {
 | 
				
			||||||
 | 
					    engine: 'underscore',
 | 
				
			||||||
 | 
					    keepBreaks: true,
 | 
				
			||||||
 | 
					    freezeBreaks: false,
 | 
				
			||||||
 | 
					    nSym: '&newl;',
 | 
				
			||||||
 | 
					    rSym: '&retn;',
 | 
				
			||||||
 | 
					    template: {
 | 
				
			||||||
 | 
					      interpolate: /\{\{(.+?)\}\}/g,
 | 
				
			||||||
 | 
					      escape: /\{\{\=(.+?)\}\}/g,
 | 
				
			||||||
 | 
					      evaluate: /\{\%(.+?)\%\}/g,
 | 
				
			||||||
 | 
					      comment: /\{\#(.+?)\#\}/g
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    filters: {
 | 
				
			||||||
 | 
					      out: function(txt) {
 | 
				
			||||||
 | 
					        return txt;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      raw: function(txt) {
 | 
				
			||||||
 | 
					        return txt;
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      xml: function(txt) {
 | 
				
			||||||
 | 
					        return XML(txt);
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      md: function(txt) {
 | 
				
			||||||
 | 
					        return MD(txt || '');
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      mdin: function(txt) {
 | 
				
			||||||
 | 
					        return MD(txt || '').replace(/^\s*<p>|<\/p>\s*$/gi, '');
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      lower: function(txt) {
 | 
				
			||||||
 | 
					        return txt.toLowerCase();
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      link: function(name, url) {
 | 
				
			||||||
 | 
					        if (url) {
 | 
				
			||||||
 | 
					          return '<a href="' + url + '">' + name + '</a>';
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return name;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    prettify: {
 | 
				
			||||||
 | 
					      indent_size: 2,
 | 
				
			||||||
 | 
					      unformatted: ['em', 'strong', 'a'],
 | 
				
			||||||
 | 
					      max_char: 80
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Regexes for linebreak preservation. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _reg = {
 | 
				
			||||||
 | 
					    regN: new RegExp('\n', 'g'),
 | 
				
			||||||
 | 
					    regR: new RegExp('\r', 'g'),
 | 
				
			||||||
 | 
					    regSymN: new RegExp(_defaultOpts.nSym, 'g'),
 | 
				
			||||||
 | 
					    regSymR: new RegExp(_defaultOpts.rSym, 'g')
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=template-generator.js.map
 | 
				
			||||||
							
								
								
									
										33
									
								
								dist/generators/text-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								dist/generators/text-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										28
									
								
								dist/generators/word-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										31
									
								
								dist/generators/xml-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										33
									
								
								dist/generators/yaml-generator.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										71
									
								
								dist/helpers/block-helpers.js
									
									
									
									
										vendored
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										66
									
								
								dist/helpers/console-helpers.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								dist/helpers/console-helpers.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Generic template helper definitions for command-line output.
 | 
				
			||||||
 | 
					@module console-helpers.js
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var CHALK, LO, PAD, _, consoleFormatHelpers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PAD = require('string-padding');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LO = require('lodash');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CHALK = require('chalk');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  require('../utils/string');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  consoleFormatHelpers = module.exports = {
 | 
				
			||||||
 | 
					    v: function(val, defaultVal, padding, style) {
 | 
				
			||||||
 | 
					      var retVal, spaces;
 | 
				
			||||||
 | 
					      retVal = val === null || val === void 0 ? defaultVal : val;
 | 
				
			||||||
 | 
					      spaces = 0;
 | 
				
			||||||
 | 
					      if (String.is(padding)) {
 | 
				
			||||||
 | 
					        spaces = parseInt(padding, 10);
 | 
				
			||||||
 | 
					        if (isNaN(spaces)) {
 | 
				
			||||||
 | 
					          spaces = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else if (_.isNumber(padding)) {
 | 
				
			||||||
 | 
					        spaces = padding;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (spaces !== 0) {
 | 
				
			||||||
 | 
					        retVal = PAD(retVal, Math.abs(spaces), null, spaces > 0 ? PAD.LEFT : PAD.RIGHT);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (style && String.is(style)) {
 | 
				
			||||||
 | 
					        retVal = LO.get(CHALK, style)(retVal);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return retVal;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    gapLength: function(val) {
 | 
				
			||||||
 | 
					      if (val < 35) {
 | 
				
			||||||
 | 
					        return CHALK.green.bold(val);
 | 
				
			||||||
 | 
					      } else if (val < 95) {
 | 
				
			||||||
 | 
					        return CHALK.yellow.bold(val);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return CHALK.red.bold(val);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    style: function(val, style) {
 | 
				
			||||||
 | 
					      return LO.get(CHALK, style)(val);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    isPlural: function(val, options) {
 | 
				
			||||||
 | 
					      if (val > 1) {
 | 
				
			||||||
 | 
					        return options.fn(this);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    pad: function(val, spaces) {
 | 
				
			||||||
 | 
					      return PAD(val, Math.abs(spaces), null, spaces > 0 ? PAD.LEFT : PAD.RIGHT);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=console-helpers.js.map
 | 
				
			||||||
							
								
								
									
										633
									
								
								dist/helpers/generic-helpers.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										633
									
								
								dist/helpers/generic-helpers.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,633 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Generic template helper definitions for HackMyResume / FluentCV.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module helpers/generic-helpers
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var FS, FluentDate, GenericHelpers, H2W, HMSTATUS, LO, MD, PATH, XML, _, _fromTo, _reportError, moment, printf, skillLevelToIndex, unused;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MD = require('marked');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  H2W = require('../utils/html-to-wpml');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  XML = require('xml-escape');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FluentDate = require('../core/fluent-date');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HMSTATUS = require('../core/status-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moment = require('moment');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FS = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LO = require('lodash');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  printf = require('printf');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  unused = require('../utils/string');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Generic template helper function definitions. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GenericHelpers = module.exports = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    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, 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(dtFormat);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      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.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    dateRange: function(obj, fmt, sep, fallback) {
 | 
				
			||||||
 | 
					      if (!obj) {
 | 
				
			||||||
 | 
					        return '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return _fromTo(obj.start, obj.end, fmt, sep, fallback);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Format a from/to date range for display.
 | 
				
			||||||
 | 
					    @method toFrom
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fromTo: function() {
 | 
				
			||||||
 | 
					      return _fromTo.apply(this, arguments);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Return a named color value as an RRGGBB string.
 | 
				
			||||||
 | 
					    @method toFrom
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    color: function(colorName, colorDefault) {
 | 
				
			||||||
 | 
					      var ret;
 | 
				
			||||||
 | 
					      if (!(colorName && colorName.trim())) {
 | 
				
			||||||
 | 
					        return _reportError(HMSTATUS.invalidHelperUse, {
 | 
				
			||||||
 | 
					          helper: 'fontList',
 | 
				
			||||||
 | 
					          error: HMSTATUS.missingParam,
 | 
				
			||||||
 | 
					          expected: 'name'
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        if (!GenericHelpers.theme.colors) {
 | 
				
			||||||
 | 
					          return colorDefault;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ret = GenericHelpers.theme.colors[colorName];
 | 
				
			||||||
 | 
					        if (!(ret && ret.trim())) {
 | 
				
			||||||
 | 
					          return colorDefault;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Emit the size of the specified named font.
 | 
				
			||||||
 | 
					    @param key {String} A named style from the "fonts" section of the theme's
 | 
				
			||||||
 | 
					    theme.json file. For example: 'default' or 'heading1'.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fontSize: function(key, defSize, units) {
 | 
				
			||||||
 | 
					      var fontSpec, hasDef, ret;
 | 
				
			||||||
 | 
					      ret = '';
 | 
				
			||||||
 | 
					      hasDef = defSize && (String.is(defSize) || _.isNumber(defSize));
 | 
				
			||||||
 | 
					      if (!(key && key.trim())) {
 | 
				
			||||||
 | 
					        _reportError(HMSTATUS.invalidHelperUse, {
 | 
				
			||||||
 | 
					          helper: 'fontSize',
 | 
				
			||||||
 | 
					          error: HMSTATUS.missingParam,
 | 
				
			||||||
 | 
					          expected: 'key'
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					      } else if (GenericHelpers.theme.fonts) {
 | 
				
			||||||
 | 
					        fontSpec = LO.get(GenericHelpers.theme.fonts, this.format + '.' + key);
 | 
				
			||||||
 | 
					        if (!fontSpec) {
 | 
				
			||||||
 | 
					          if (GenericHelpers.theme.fonts.all) {
 | 
				
			||||||
 | 
					            fontSpec = GenericHelpers.theme.fonts.all[key];
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (fontSpec) {
 | 
				
			||||||
 | 
					          if (String.is(fontSpec)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          } else if (_.isArray(fontSpec)) {
 | 
				
			||||||
 | 
					            if (!String.is(fontSpec[0])) {
 | 
				
			||||||
 | 
					              ret = fontSpec[0].size;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            ret = fontSpec.size;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!ret) {
 | 
				
			||||||
 | 
					        if (hasDef) {
 | 
				
			||||||
 | 
					          ret = defSize;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          _reportError(HMSTATUS.invalidHelperUse, {
 | 
				
			||||||
 | 
					            helper: 'fontSize',
 | 
				
			||||||
 | 
					            error: HMSTATUS.missingParam,
 | 
				
			||||||
 | 
					            expected: 'defSize'
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          ret = '';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return ret;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Emit the font face (such as 'Helvetica' or 'Calibri') associated with the
 | 
				
			||||||
 | 
					    provided key.
 | 
				
			||||||
 | 
					    @param key {String} A named style from the "fonts" section of the theme's
 | 
				
			||||||
 | 
					    theme.json file. For example: 'default' or 'heading1'.
 | 
				
			||||||
 | 
					    @param defFont {String} The font to use if the specified key isn't present.
 | 
				
			||||||
 | 
					    Can be any valid font-face name such as 'Helvetica Neue' or 'Calibri'.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fontFace: function(key, defFont) {
 | 
				
			||||||
 | 
					      var fontSpec, hasDef, ret;
 | 
				
			||||||
 | 
					      ret = '';
 | 
				
			||||||
 | 
					      hasDef = defFont && String.is(defFont);
 | 
				
			||||||
 | 
					      if (!(key && key.trim())) {
 | 
				
			||||||
 | 
					        _reportError(HMSTATUS.invalidHelperUse, {
 | 
				
			||||||
 | 
					          helper: 'fontFace',
 | 
				
			||||||
 | 
					          error: HMSTATUS.missingParam,
 | 
				
			||||||
 | 
					          expected: 'key'
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					      } else if (GenericHelpers.theme.fonts) {
 | 
				
			||||||
 | 
					        fontSpec = LO.get(GenericHelpers.theme.fonts, this.format + '.' + key);
 | 
				
			||||||
 | 
					        if (!fontSpec) {
 | 
				
			||||||
 | 
					          if (GenericHelpers.theme.fonts.all) {
 | 
				
			||||||
 | 
					            fontSpec = GenericHelpers.theme.fonts.all[key];
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (fontSpec) {
 | 
				
			||||||
 | 
					          if (String.is(fontSpec)) {
 | 
				
			||||||
 | 
					            ret = fontSpec;
 | 
				
			||||||
 | 
					          } else if (_.isArray(fontSpec)) {
 | 
				
			||||||
 | 
					            ret = String.is(fontSpec[0]) ? fontSpec[0] : fontSpec[0].name;
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            ret = fontSpec.name;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!(ret && ret.trim())) {
 | 
				
			||||||
 | 
					        ret = defFont;
 | 
				
			||||||
 | 
					        if (!hasDef) {
 | 
				
			||||||
 | 
					          _reportError(HMSTATUS.invalidHelperUse, {
 | 
				
			||||||
 | 
					            helper: 'fontFace',
 | 
				
			||||||
 | 
					            error: HMSTATUS.missingParam,
 | 
				
			||||||
 | 
					            expected: 'defFont'
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          ret = '';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return ret;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Emit a comma-delimited list of font names suitable associated with the
 | 
				
			||||||
 | 
					    provided key.
 | 
				
			||||||
 | 
					    @param key {String} A named style from the "fonts" section of the theme's
 | 
				
			||||||
 | 
					    theme.json file. For example: 'default' or 'heading1'.
 | 
				
			||||||
 | 
					    @param defFontList {Array} The font list to use if the specified key isn't
 | 
				
			||||||
 | 
					    present. Can be an array of valid font-face name such as 'Helvetica Neue'
 | 
				
			||||||
 | 
					    or 'Calibri'.
 | 
				
			||||||
 | 
					    @param sep {String} The default separator to use in the rendered output.
 | 
				
			||||||
 | 
					    Defaults to ", " (comma with a space).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    fontList: function(key, defFontList, sep) {
 | 
				
			||||||
 | 
					      var fontSpec, hasDef, ret;
 | 
				
			||||||
 | 
					      ret = '';
 | 
				
			||||||
 | 
					      hasDef = defFontList && String.is(defFontList);
 | 
				
			||||||
 | 
					      if (!(key && key.trim())) {
 | 
				
			||||||
 | 
					        _reportError(HMSTATUS.invalidHelperUse, {
 | 
				
			||||||
 | 
					          helper: 'fontList',
 | 
				
			||||||
 | 
					          error: HMSTATUS.missingParam,
 | 
				
			||||||
 | 
					          expected: 'key'
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      } else if (GenericHelpers.theme.fonts) {
 | 
				
			||||||
 | 
					        fontSpec = LO.get(GenericHelpers.theme.fonts, this.format + '.' + key);
 | 
				
			||||||
 | 
					        if (!fontSpec) {
 | 
				
			||||||
 | 
					          if (GenericHelpers.theme.fonts.all) {
 | 
				
			||||||
 | 
					            fontSpec = GenericHelpers.theme.fonts.all[key];
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (fontSpec) {
 | 
				
			||||||
 | 
					          if (String.is(fontSpec)) {
 | 
				
			||||||
 | 
					            ret = fontSpec;
 | 
				
			||||||
 | 
					          } else if (_.isArray(fontSpec)) {
 | 
				
			||||||
 | 
					            fontSpec = fontSpec.map(function(ff) {
 | 
				
			||||||
 | 
					              return "'" + (String.is(ff) ? ff : ff.name) + "'";
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            ret = fontSpec.join(sep === void 0 ? ', ' : sep || '');
 | 
				
			||||||
 | 
					          } else {
 | 
				
			||||||
 | 
					            ret = fontSpec.name;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!(ret && ret.trim())) {
 | 
				
			||||||
 | 
					        if (!hasDef) {
 | 
				
			||||||
 | 
					          _reportError(HMSTATUS.invalidHelperUse, {
 | 
				
			||||||
 | 
					            helper: 'fontList',
 | 
				
			||||||
 | 
					            error: HMSTATUS.missingParam,
 | 
				
			||||||
 | 
					            expected: 'defFontList'
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					          ret = '';
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          ret = defFontList;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return ret;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Capitalize the first letter of the word. TODO: Rename
 | 
				
			||||||
 | 
					    @method section
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    camelCase: function(val) {
 | 
				
			||||||
 | 
					      val = (val && val.trim()) || '';
 | 
				
			||||||
 | 
					      if (val) {
 | 
				
			||||||
 | 
					        return val.charAt(0).toUpperCase() + val.slice(1);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return val;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Display a user-overridable section title for a FRESH resume theme. Use this in
 | 
				
			||||||
 | 
					    lieue of hard-coding section titles.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    Usage:
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        {{sectionTitle "sectionName"}}
 | 
				
			||||||
 | 
					        {{sectionTitle "sectionName" "sectionTitle"}}
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    Example:
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        {{sectionTitle "Education"}}
 | 
				
			||||||
 | 
					        {{sectionTitle "Employment" "Project History"}}
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @param sect_name The name of the section being title. Must be one of the
 | 
				
			||||||
 | 
					    top-level FRESH resume sections ("info", "education", "employment", etc.).
 | 
				
			||||||
 | 
					    @param sect_title The theme-specified section title. May be replaced by the
 | 
				
			||||||
 | 
					    user.
 | 
				
			||||||
 | 
					    @method sectionTitle
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    sectionTitle: function(sname, stitle) {
 | 
				
			||||||
 | 
					      stitle = (stitle && String.is(stitle) && stitle) || sname;
 | 
				
			||||||
 | 
					      return (this.opts.stitles && this.opts.stitles[sname.toLowerCase().trim()]) || stitle;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Convert inline Markdown to inline WordProcessingML. */
 | 
				
			||||||
 | 
					    wpml: function(txt, inline) {
 | 
				
			||||||
 | 
					      if (!txt) {
 | 
				
			||||||
 | 
					        return '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      inline = (inline && !inline.hash) || false;
 | 
				
			||||||
 | 
					      txt = XML(txt.trim());
 | 
				
			||||||
 | 
					      txt = inline ? MD(txt).replace(/^\s*<p>|<\/p>\s*$/gi, '') : MD(txt);
 | 
				
			||||||
 | 
					      txt = H2W(txt);
 | 
				
			||||||
 | 
					      return txt;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Emit a conditional link.
 | 
				
			||||||
 | 
					    @method link
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    link: function(text, url) {
 | 
				
			||||||
 | 
					      if (url && url.trim()) {
 | 
				
			||||||
 | 
					        return '<a href="' + url + '">' + text + '</a>';
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return text;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Return the last word of the specified text.
 | 
				
			||||||
 | 
					    @method lastWord
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    lastWord: function(txt) {
 | 
				
			||||||
 | 
					      if (txt && txt.trim()) {
 | 
				
			||||||
 | 
					        return _.last(txt.split(' '));
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Convert a skill level to an RGB color triplet. TODO: refactor
 | 
				
			||||||
 | 
					    @method skillColor
 | 
				
			||||||
 | 
					    @param lvl Input skill level. Skill level can be expressed as a string
 | 
				
			||||||
 | 
					    ("beginner", "intermediate", etc.), as an integer (1,5,etc), as a string
 | 
				
			||||||
 | 
					    integer ("1", "5", etc.), or as an RRGGBB color triplet ('#C00000',
 | 
				
			||||||
 | 
					    '#FFFFAA').
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    skillColor: function(lvl) {
 | 
				
			||||||
 | 
					      var idx, skillColors;
 | 
				
			||||||
 | 
					      idx = skillLevelToIndex(lvl);
 | 
				
			||||||
 | 
					      skillColors = (this.theme && this.theme.palette && this.theme.palette.skillLevels) || ['#FFFFFF', '#5CB85C', '#F1C40F', '#428BCA', '#C00000'];
 | 
				
			||||||
 | 
					      return skillColors[idx];
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Return an appropriate height. TODO: refactor
 | 
				
			||||||
 | 
					    @method lastWord
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    skillHeight: function(lvl) {
 | 
				
			||||||
 | 
					      var idx;
 | 
				
			||||||
 | 
					      idx = skillLevelToIndex(lvl);
 | 
				
			||||||
 | 
					      return ['38.25', '30', '16', '8', '0'][idx];
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Return all but the last word of the input text.
 | 
				
			||||||
 | 
					    @method initialWords
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    initialWords: function(txt) {
 | 
				
			||||||
 | 
					      if (txt && txt.trim()) {
 | 
				
			||||||
 | 
					        return _.initial(txt.split(' ')).join(' ');
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Trim the protocol (http or https) from a URL/
 | 
				
			||||||
 | 
					    @method trimURL
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    trimURL: function(url) {
 | 
				
			||||||
 | 
					      if (url && url.trim()) {
 | 
				
			||||||
 | 
					        return url.trim().replace(/^https?:\/\//i, '');
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Convert text to lowercase.
 | 
				
			||||||
 | 
					    @method toLower
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    toLower: function(txt) {
 | 
				
			||||||
 | 
					      if (txt && txt.trim()) {
 | 
				
			||||||
 | 
					        return txt.toLowerCase();
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Convert text to lowercase.
 | 
				
			||||||
 | 
					    @method toLower
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    toUpper: function(txt) {
 | 
				
			||||||
 | 
					      if (txt && txt.trim()) {
 | 
				
			||||||
 | 
					        return txt.toUpperCase();
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        return '';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Conditional stylesheet link. Creates a link to the specified stylesheet with
 | 
				
			||||||
 | 
					    <link> or embeds the styles inline with <style></style>, depending on the
 | 
				
			||||||
 | 
					    theme author's and user's preferences.
 | 
				
			||||||
 | 
					    @param url {String} The path to the CSS file.
 | 
				
			||||||
 | 
					    @param linkage {String} The default link method. Can be either `embed` or
 | 
				
			||||||
 | 
					    `link`. If omitted, defaults to `embed`. Can be overridden by the `--css`
 | 
				
			||||||
 | 
					    command-line switch.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    styleSheet: function(url, linkage) {
 | 
				
			||||||
 | 
					      var rawCss, renderedCss, ret;
 | 
				
			||||||
 | 
					      linkage = this.opts.css || linkage || 'embed';
 | 
				
			||||||
 | 
					      ret = '';
 | 
				
			||||||
 | 
					      if (linkage === 'link') {
 | 
				
			||||||
 | 
					        ret = printf('<link href="%s" rel="stylesheet" type="text/css">', url);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        rawCss = FS.readFileSync(PATH.join(this.opts.themeObj.folder, '/src/', url), 'utf8');
 | 
				
			||||||
 | 
					        renderedCss = this.engine.generateSimple(this, rawCss);
 | 
				
			||||||
 | 
					        ret = printf('<style>%s</style>', renderedCss);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (this.opts.themeObj.inherits && this.opts.themeObj.inherits.html && this.format === 'html') {
 | 
				
			||||||
 | 
					        ret += linkage === 'link' ? '<link href="' + this.opts.themeObj.overrides.path + '" rel="stylesheet" type="text/css">' : '<style>' + this.opts.themeObj.overrides.data + '</style>';
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return ret;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Perform a generic comparison.
 | 
				
			||||||
 | 
					    See: http://doginthehat.com.au/2012/02/comparison-block-helper-for-handlebars-templates
 | 
				
			||||||
 | 
					    @method compare
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    compare: function(lvalue, rvalue, options) {
 | 
				
			||||||
 | 
					      var operator, operators, result;
 | 
				
			||||||
 | 
					      if (arguments.length < 3) {
 | 
				
			||||||
 | 
					        throw new Error("Template helper 'compare' needs 2 parameters");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      operator = options.hash.operator || "==";
 | 
				
			||||||
 | 
					      operators = {
 | 
				
			||||||
 | 
					        '==': function(l, r) {
 | 
				
			||||||
 | 
					          return l === r;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        '===': function(l, r) {
 | 
				
			||||||
 | 
					          return l === r;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        '!=': function(l, r) {
 | 
				
			||||||
 | 
					          return l !== r;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        '<': function(l, r) {
 | 
				
			||||||
 | 
					          return l < r;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        '>': function(l, r) {
 | 
				
			||||||
 | 
					          return l > r;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        '<=': function(l, r) {
 | 
				
			||||||
 | 
					          return l <= r;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        '>=': function(l, r) {
 | 
				
			||||||
 | 
					          return l >= r;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        'typeof': function(l, r) {
 | 
				
			||||||
 | 
					          return typeof l === r;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      if (!operators[operator]) {
 | 
				
			||||||
 | 
					        throw new Error("Helper 'compare' doesn't know the operator " + operator);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      result = operators[operator](lvalue, rvalue);
 | 
				
			||||||
 | 
					      if (result) {
 | 
				
			||||||
 | 
					        return options.fn(this);
 | 
				
			||||||
 | 
					      } 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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Report an error to the outside world without throwing an exception. Currently
 | 
				
			||||||
 | 
					  relies on kludging the running verb into. opts.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _reportError = function(code, params) {
 | 
				
			||||||
 | 
					    return GenericHelpers.opts.errHandler.err(code, params);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Format a from/to date range for display.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _fromTo = function(dateA, dateB, fmt, sep, fallback) {
 | 
				
			||||||
 | 
					    var dateATrim, dateBTrim, dateFrom, dateTemp, dateTo, reserved;
 | 
				
			||||||
 | 
					    if (moment.isMoment(dateA) || moment.isMoment(dateB)) {
 | 
				
			||||||
 | 
					      _reportError(HMSTATUS.invalidHelperUse, {
 | 
				
			||||||
 | 
					        helper: 'dateRange'
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return '';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    dateFrom = null;
 | 
				
			||||||
 | 
					    dateTo = null;
 | 
				
			||||||
 | 
					    dateTemp = null;
 | 
				
			||||||
 | 
					    dateA = dateA || '';
 | 
				
			||||||
 | 
					    dateB = dateB || '';
 | 
				
			||||||
 | 
					    dateATrim = dateA.trim().toLowerCase();
 | 
				
			||||||
 | 
					    dateBTrim = dateB.trim().toLowerCase();
 | 
				
			||||||
 | 
					    reserved = ['current', 'present', 'now', ''];
 | 
				
			||||||
 | 
					    fmt = (fmt && String.is(fmt) && fmt) || 'YYYY-MM';
 | 
				
			||||||
 | 
					    sep = (sep && String.is(sep) && sep) || ' — ';
 | 
				
			||||||
 | 
					    if (_.contains(reserved, dateATrim)) {
 | 
				
			||||||
 | 
					      dateFrom = fallback || '???';
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      dateTemp = FluentDate.fmt(dateA);
 | 
				
			||||||
 | 
					      dateFrom = dateTemp.format(fmt);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (_.contains(reserved, dateBTrim)) {
 | 
				
			||||||
 | 
					      dateTo = fallback || 'Present';
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      dateTemp = FluentDate.fmt(dateB);
 | 
				
			||||||
 | 
					      dateTo = dateTemp.format(fmt);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (dateFrom && dateTo) {
 | 
				
			||||||
 | 
					      return dateFrom + sep + dateTo;
 | 
				
			||||||
 | 
					    } else if (dateFrom || dateTo) {
 | 
				
			||||||
 | 
					      return dateFrom || dateTo;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return '';
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  skillLevelToIndex = function(lvl) {
 | 
				
			||||||
 | 
					    var idx, intVal;
 | 
				
			||||||
 | 
					    idx = 0;
 | 
				
			||||||
 | 
					    if (String.is(lvl)) {
 | 
				
			||||||
 | 
					      lvl = lvl.trim().toLowerCase();
 | 
				
			||||||
 | 
					      intVal = parseInt(lvl);
 | 
				
			||||||
 | 
					      if (isNaN(intVal)) {
 | 
				
			||||||
 | 
					        switch (lvl) {
 | 
				
			||||||
 | 
					          case 'beginner':
 | 
				
			||||||
 | 
					            idx = 1;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'intermediate':
 | 
				
			||||||
 | 
					            idx = 2;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'advanced':
 | 
				
			||||||
 | 
					            idx = 3;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          case 'master':
 | 
				
			||||||
 | 
					            idx = 4;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        idx = Math.min(intVal / 2, 4);
 | 
				
			||||||
 | 
					        idx = Math.max(0, idx);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      idx = Math.min(lvl / 2, 4);
 | 
				
			||||||
 | 
					      idx = Math.max(0, idx);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return idx;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=generic-helpers.js.map
 | 
				
			||||||
							
								
								
									
										48
									
								
								dist/helpers/handlebars-helpers.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								dist/helpers/handlebars-helpers.js
									
									
									
									
										vendored
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										38
									
								
								dist/helpers/underscore-helpers.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								dist/helpers/underscore-helpers.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Template helper definitions for Underscore.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module handlebars-helpers.js
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var HANDLEBARS, _, helpers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HANDLEBARS = require('handlebars');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  helpers = require('./generic-helpers');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Register useful Underscore helpers.
 | 
				
			||||||
 | 
					  @method registerHelpers
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = function(theme, opts, cssInfo, ctx, eng) {
 | 
				
			||||||
 | 
					    helpers.theme = theme;
 | 
				
			||||||
 | 
					    helpers.opts = opts;
 | 
				
			||||||
 | 
					    helpers.cssInfo = cssInfo;
 | 
				
			||||||
 | 
					    helpers.engine = eng;
 | 
				
			||||||
 | 
					    ctx.h = helpers;
 | 
				
			||||||
 | 
					    _.each(helpers, function(hVal, hKey) {
 | 
				
			||||||
 | 
					      if (_.isFunction(hVal)) {
 | 
				
			||||||
 | 
					        return _.bind(hVal, ctx);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }, this);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=underscore-helpers.js.map
 | 
				
			||||||
							
								
								
									
										48
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								dist/index.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					External API surface for HackMyResume.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module hackmycore/index
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** API facade for HackMyResume. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(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')
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=index.js.map
 | 
				
			||||||
							
								
								
									
										140
									
								
								dist/inspectors/gap-inspector.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								dist/inspectors/gap-inspector.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,140 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Employment gap analysis for HackMyResume.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module inspectors/gap-inspector
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var FluentDate, LO, _, gapInspector, moment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FluentDate = require('../core/fluent-date');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moment = require('moment');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LO = require('lodash');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Identify gaps in the candidate's employment history.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  gapInspector = module.exports = {
 | 
				
			||||||
 | 
					    moniker: 'gap-inspector',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Run the Gap Analyzer on a resume.
 | 
				
			||||||
 | 
					    @method run
 | 
				
			||||||
 | 
					    @return {Array} An array of object representing gaps in the candidate's
 | 
				
			||||||
 | 
					    employment history. Each object provides the start, end, and duration of the
 | 
				
			||||||
 | 
					    gap:
 | 
				
			||||||
 | 
					        { <-- gap
 | 
				
			||||||
 | 
					          start: // A Moment.js date
 | 
				
			||||||
 | 
					          end: // A Moment.js date
 | 
				
			||||||
 | 
					          duration: // Gap length
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    run: function(rez) {
 | 
				
			||||||
 | 
					      var coverage, dur, g, gap_start, hist, new_e, num_gaps, o, ref_count, tdur, total_gap_days;
 | 
				
			||||||
 | 
					      coverage = {
 | 
				
			||||||
 | 
					        gaps: [],
 | 
				
			||||||
 | 
					        overlaps: [],
 | 
				
			||||||
 | 
					        pct: '0%',
 | 
				
			||||||
 | 
					        duration: {
 | 
				
			||||||
 | 
					          total: 0,
 | 
				
			||||||
 | 
					          work: 0,
 | 
				
			||||||
 | 
					          gaps: 0
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      hist = LO.get(rez, 'employment.history');
 | 
				
			||||||
 | 
					      if (!hist || !hist.length) {
 | 
				
			||||||
 | 
					        return coverage;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      new_e = hist.map(function(job) {
 | 
				
			||||||
 | 
					        var obj;
 | 
				
			||||||
 | 
					        obj = _.pick(job, ['start', 'end']);
 | 
				
			||||||
 | 
					        if (obj && (obj.start || obj.end)) {
 | 
				
			||||||
 | 
					          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 coverage;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      new_e = _.sortBy(new_e, function(elem) {
 | 
				
			||||||
 | 
					        return elem[1].unix();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      num_gaps = 0;
 | 
				
			||||||
 | 
					      ref_count = 0;
 | 
				
			||||||
 | 
					      total_gap_days = 0;
 | 
				
			||||||
 | 
					      gap_start = null;
 | 
				
			||||||
 | 
					      new_e.forEach(function(point) {
 | 
				
			||||||
 | 
					        var inc, lastGap, lastOver;
 | 
				
			||||||
 | 
					        inc = point[0] === 'start' ? 1 : -1;
 | 
				
			||||||
 | 
					        ref_count += inc;
 | 
				
			||||||
 | 
					        if (ref_count === 0) {
 | 
				
			||||||
 | 
					          return coverage.gaps.push({
 | 
				
			||||||
 | 
					            start: point[1],
 | 
				
			||||||
 | 
					            end: null
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        } else if (ref_count === 1 && inc === 1) {
 | 
				
			||||||
 | 
					          lastGap = _.last(coverage.gaps);
 | 
				
			||||||
 | 
					          if (lastGap) {
 | 
				
			||||||
 | 
					            lastGap.end = point[1];
 | 
				
			||||||
 | 
					            lastGap.duration = lastGap.end.diff(lastGap.start, 'days');
 | 
				
			||||||
 | 
					            return total_gap_days += lastGap.duration;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        } else if (ref_count === 2 && inc === 1) {
 | 
				
			||||||
 | 
					          return coverage.overlaps.push({
 | 
				
			||||||
 | 
					            start: point[1],
 | 
				
			||||||
 | 
					            end: null
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					        } else if (ref_count === 1 && inc === -1) {
 | 
				
			||||||
 | 
					          lastOver = _.last(coverage.overlaps);
 | 
				
			||||||
 | 
					          if (lastOver) {
 | 
				
			||||||
 | 
					            lastOver.end = point[1];
 | 
				
			||||||
 | 
					            lastOver.duration = lastOver.end.diff(lastOver.start, 'days');
 | 
				
			||||||
 | 
					            if (lastOver.duration === 0) {
 | 
				
			||||||
 | 
					              return coverage.overlaps.pop();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      if (coverage.overlaps.length) {
 | 
				
			||||||
 | 
					        o = _.last(coverage.overlaps);
 | 
				
			||||||
 | 
					        if (o && !o.end) {
 | 
				
			||||||
 | 
					          o.end = moment();
 | 
				
			||||||
 | 
					          o.duration = o.end.diff(o.start, 'days');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (coverage.gaps.length) {
 | 
				
			||||||
 | 
					        g = _.last(coverage.gaps);
 | 
				
			||||||
 | 
					        if (g && !g.end) {
 | 
				
			||||||
 | 
					          g.end = moment();
 | 
				
			||||||
 | 
					          g.duration = g.end.diff(g.start, 'days');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      tdur = rez.duration('days');
 | 
				
			||||||
 | 
					      dur = {
 | 
				
			||||||
 | 
					        total: tdur,
 | 
				
			||||||
 | 
					        work: tdur - total_gap_days,
 | 
				
			||||||
 | 
					        gaps: total_gap_days
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      coverage.pct = dur.total > 0 && dur.work > 0 ? (((dur.total - dur.gaps) / dur.total) * 100).toFixed(1) + '%' : '???';
 | 
				
			||||||
 | 
					      coverage.duration = dur;
 | 
				
			||||||
 | 
					      return coverage;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=gap-inspector.js.map
 | 
				
			||||||
							
								
								
									
										63
									
								
								dist/inspectors/keyword-inspector.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								dist/inspectors/keyword-inspector.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Keyword analysis for HackMyResume.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module inspectors/keyword-inspector
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var FluentDate, _, keywordInspector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FluentDate = require('../core/fluent-date');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Analyze the resume's use of keywords.
 | 
				
			||||||
 | 
					  TODO: BUG: Keyword search regex is inaccurate, especially for one or two
 | 
				
			||||||
 | 
					  letter keywords like "C" or "CLI".
 | 
				
			||||||
 | 
					  @class keywordInspector
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  keywordInspector = module.exports = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** A unique name for this inspector. */
 | 
				
			||||||
 | 
					    moniker: 'keyword-inspector',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Run the Keyword Inspector on a resume.
 | 
				
			||||||
 | 
					    @method run
 | 
				
			||||||
 | 
					    @return An collection of statistical keyword data.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    run: function(rez) {
 | 
				
			||||||
 | 
					      var prefix, regex_quote, searchable, suffix;
 | 
				
			||||||
 | 
					      regex_quote = function(str) {
 | 
				
			||||||
 | 
					        return (str + '').replace(/[.?*+^$[\]\\(){}|-]/ig, "\\$&");
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      searchable = '';
 | 
				
			||||||
 | 
					      rez.transformStrings(['imp', 'computed', 'safe'], function(key, val) {
 | 
				
			||||||
 | 
					        return searchable += ' ' + val;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      prefix = '(?:' + ['^', '\\s+', '[\\.,]+'].join('|') + ')';
 | 
				
			||||||
 | 
					      suffix = '(?:' + ['$', '\\s+', '[\\.,]+'].join('|') + ')';
 | 
				
			||||||
 | 
					      return rez.keywords().map(function(kw) {
 | 
				
			||||||
 | 
					        var count, myArray, regex, regex_str;
 | 
				
			||||||
 | 
					        regex_str = prefix + regex_quote(kw) + suffix;
 | 
				
			||||||
 | 
					        regex = new RegExp(regex_str, 'ig');
 | 
				
			||||||
 | 
					        myArray = null;
 | 
				
			||||||
 | 
					        count = 0;
 | 
				
			||||||
 | 
					        while ((myArray = regex.exec(searchable)) !== null) {
 | 
				
			||||||
 | 
					          count++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          name: kw,
 | 
				
			||||||
 | 
					          count: count
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=keyword-inspector.js.map
 | 
				
			||||||
							
								
								
									
										51
									
								
								dist/inspectors/totals-inspector.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								dist/inspectors/totals-inspector.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Section analysis for HackMyResume.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module inspectors/totals-inspector
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var FluentDate, _, totalsInspector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FluentDate = require('../core/fluent-date');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Retrieve sectional overview and summary information.
 | 
				
			||||||
 | 
					  @class totalsInspector
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  totalsInspector = module.exports = {
 | 
				
			||||||
 | 
					    moniker: 'totals-inspector',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					    Run the Totals Inspector on a resume.
 | 
				
			||||||
 | 
					    @method run
 | 
				
			||||||
 | 
					    @return An object containing summary information for each section on the
 | 
				
			||||||
 | 
					    resume.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    run: function(rez) {
 | 
				
			||||||
 | 
					      var sectionTotals;
 | 
				
			||||||
 | 
					      sectionTotals = {};
 | 
				
			||||||
 | 
					      _.each(rez, function(val, key) {
 | 
				
			||||||
 | 
					        if (_.isArray(val) && !_.isString(val)) {
 | 
				
			||||||
 | 
					          return sectionTotals[key] = val.length;
 | 
				
			||||||
 | 
					        } else if (val.history && _.isArray(val.history)) {
 | 
				
			||||||
 | 
					          return sectionTotals[key] = val.history.length;
 | 
				
			||||||
 | 
					        } else if (val.sets && _.isArray(val.sets)) {
 | 
				
			||||||
 | 
					          return sectionTotals[key] = val.sets.length;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        totals: sectionTotals,
 | 
				
			||||||
 | 
					        numSections: Object.keys(sectionTotals).length
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=totals-inspector.js.map
 | 
				
			||||||
							
								
								
									
										102
									
								
								dist/renderers/handlebars-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								dist/renderers/handlebars-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the HandlebarsGenerator class.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module renderers/handlebars-generator
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var FS, HANDLEBARS, HMSTATUS, HandlebarsGenerator, PATH, READFILES, SLASH, _, parsePath, registerHelpers, registerPartials;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HANDLEBARS = require('handlebars');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FS = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  registerHelpers = require('../helpers/handlebars-helpers');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  parsePath = require('parse-filepath');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  READFILES = require('recursive-readdir-sync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HMSTATUS = require('../core/status-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SLASH = require('slash');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Perform template-based resume generation using Handlebars.js.
 | 
				
			||||||
 | 
					  @class HandlebarsGenerator
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HandlebarsGenerator = module.exports = {
 | 
				
			||||||
 | 
					    generateSimple: function(data, tpl) {
 | 
				
			||||||
 | 
					      var template;
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        template = HANDLEBARS.compile(tpl, {
 | 
				
			||||||
 | 
					          strict: false,
 | 
				
			||||||
 | 
					          assumeObjects: false
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return template(data);
 | 
				
			||||||
 | 
					      } catch (_error) {
 | 
				
			||||||
 | 
					        throw {
 | 
				
			||||||
 | 
					          fluenterror: HMSTATUS[template ? 'invokeTemplate' : 'compileTemplate'],
 | 
				
			||||||
 | 
					          inner: _error
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    generate: function(json, jst, format, curFmt, opts, theme) {
 | 
				
			||||||
 | 
					      var ctx, encData;
 | 
				
			||||||
 | 
					      registerPartials(format, theme);
 | 
				
			||||||
 | 
					      registerHelpers(theme, opts);
 | 
				
			||||||
 | 
					      encData = json;
 | 
				
			||||||
 | 
					      if (format === 'html' || format === 'pdf') {
 | 
				
			||||||
 | 
					        encData = json.markdownify();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (format === 'doc') {
 | 
				
			||||||
 | 
					        encData = json.xmlify();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      ctx = {
 | 
				
			||||||
 | 
					        r: encData,
 | 
				
			||||||
 | 
					        RAW: json,
 | 
				
			||||||
 | 
					        filt: opts.filters,
 | 
				
			||||||
 | 
					        format: format,
 | 
				
			||||||
 | 
					        opts: opts,
 | 
				
			||||||
 | 
					        engine: this,
 | 
				
			||||||
 | 
					        results: curFmt.files,
 | 
				
			||||||
 | 
					        headFragment: opts.headFragment || ''
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      return this.generateSimple(ctx, jst);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  registerPartials = function(format, theme) {
 | 
				
			||||||
 | 
					    var partialsFolder;
 | 
				
			||||||
 | 
					    if (_.contains(['html', 'doc', 'md', 'txt', 'pdf'], format)) {
 | 
				
			||||||
 | 
					      partialsFolder = PATH.join(parsePath(require.resolve('fresh-themes')).dirname, '/partials/', format === 'pdf' ? 'html' : format);
 | 
				
			||||||
 | 
					      _.each(READFILES(partialsFolder, function(error) {
 | 
				
			||||||
 | 
					        return {};
 | 
				
			||||||
 | 
					      }), function(el) {
 | 
				
			||||||
 | 
					        var compiledTemplate, name, pathInfo, tplData;
 | 
				
			||||||
 | 
					        pathInfo = parsePath(el);
 | 
				
			||||||
 | 
					        name = SLASH(PATH.relative(partialsFolder, el).replace(/\.(?:html|xml|hbs|md|txt)$/i, ''));
 | 
				
			||||||
 | 
					        tplData = FS.readFileSync(el, 'utf8');
 | 
				
			||||||
 | 
					        compiledTemplate = HANDLEBARS.compile(tplData);
 | 
				
			||||||
 | 
					        HANDLEBARS.registerPartial(name, compiledTemplate);
 | 
				
			||||||
 | 
					        return theme.partialsInitialized = true;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return _.each(theme.partials, function(el) {
 | 
				
			||||||
 | 
					      var compiledTemplate, tplData;
 | 
				
			||||||
 | 
					      tplData = FS.readFileSync(el.path, 'utf8');
 | 
				
			||||||
 | 
					      compiledTemplate = HANDLEBARS.compile(tplData);
 | 
				
			||||||
 | 
					      return HANDLEBARS.registerPartial(el.name, compiledTemplate);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=handlebars-generator.js.map
 | 
				
			||||||
							
								
								
									
										61
									
								
								dist/renderers/jrs-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								dist/renderers/jrs-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the JRSGenerator class.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module renderers/jrs-generator
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var FS, HANDLEBARS, JRSGenerator, MD, MDIN, PATH, READFILES, SLASH, _, parsePath, registerHelpers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HANDLEBARS = require('handlebars');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FS = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  registerHelpers = require('../helpers/handlebars-helpers');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  parsePath = require('parse-filepath');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  READFILES = require('recursive-readdir-sync');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SLASH = require('slash');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MD = require('marked');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Perform template-based resume generation for JSON Resume themes.
 | 
				
			||||||
 | 
					  @class JRSGenerator
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  JRSGenerator = module.exports = {
 | 
				
			||||||
 | 
					    generate: function(json, jst, format, cssInfo, opts, theme) {
 | 
				
			||||||
 | 
					      var org, rezHtml, turnoff;
 | 
				
			||||||
 | 
					      turnoff = ['log', 'error', 'dir'];
 | 
				
			||||||
 | 
					      org = turnoff.map(function(c) {
 | 
				
			||||||
 | 
					        var ret;
 | 
				
			||||||
 | 
					        ret = console[c];
 | 
				
			||||||
 | 
					        console[c] = function() {};
 | 
				
			||||||
 | 
					        return ret;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      rezHtml = theme.render(json.harden());
 | 
				
			||||||
 | 
					      turnoff.forEach(function(c, idx) {
 | 
				
			||||||
 | 
					        return console[c] = org[idx];
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return rezHtml = rezHtml.replace(/@@@@~.*?~@@@@/gm, function(val) {
 | 
				
			||||||
 | 
					        return MDIN(val.replace(/~@@@@/gm, '').replace(/@@@@~/gm, ''));
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MDIN = function(txt) {
 | 
				
			||||||
 | 
					    return MD(txt || '').replace(/^\s*<p>|<\/p>\s*$/gi, '');
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=jrs-generator.js.map
 | 
				
			||||||
							
								
								
									
										87
									
								
								dist/renderers/underscore-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								dist/renderers/underscore-generator.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the UnderscoreGenerator class.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module underscore-generator.js
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var UnderscoreGenerator, _, escapeLaTeX, registerHelpers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  registerHelpers = require('../helpers/underscore-helpers');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  require('../utils/string');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  escapeLaTeX = require('escape-latex');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Perform template-based resume generation using Underscore.js.
 | 
				
			||||||
 | 
					  @class UnderscoreGenerator
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  UnderscoreGenerator = module.exports = {
 | 
				
			||||||
 | 
					    generateSimple: function(data, tpl) {
 | 
				
			||||||
 | 
					      var HMS, t;
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        t = _.template(tpl);
 | 
				
			||||||
 | 
					        return t(data);
 | 
				
			||||||
 | 
					      } catch (_error) {
 | 
				
			||||||
 | 
					        HMS = require('../core/status-codes');
 | 
				
			||||||
 | 
					        throw {
 | 
				
			||||||
 | 
					          fluenterror: HMS[t ? 'invokeTemplate' : 'compileTemplate'],
 | 
				
			||||||
 | 
					          inner: _error
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    generate: function(json, jst, format, cssInfo, opts, theme) {
 | 
				
			||||||
 | 
					      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) {
 | 
				
			||||||
 | 
					          return new RegExp(val, "ig");
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      _.templateSettings = delims;
 | 
				
			||||||
 | 
					      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: r,
 | 
				
			||||||
 | 
					        filt: opts.filters,
 | 
				
			||||||
 | 
					        XML: require('xml-escape'),
 | 
				
			||||||
 | 
					        RAW: json,
 | 
				
			||||||
 | 
					        cssInfo: cssInfo,
 | 
				
			||||||
 | 
					        headFragment: opts.headFragment || '',
 | 
				
			||||||
 | 
					        opts: opts
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      registerHelpers(theme, opts, cssInfo, ctx, this);
 | 
				
			||||||
 | 
					      return this.generateSimple(ctx, jst);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=underscore-generator.js.map
 | 
				
			||||||
							
								
								
									
										14
									
								
								dist/utils/file-contains.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								dist/utils/file-contains.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the SyntaxErrorEx class.
 | 
				
			||||||
 | 
					@module file-contains.js
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  module.exports = function(file, needle) {
 | 
				
			||||||
 | 
					    return require('fs').readFileSync(file, 'utf-8').indexOf(needle) > -1;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=file-contains.js.map
 | 
				
			||||||
							
								
								
									
										63
									
								
								dist/utils/html-to-wpml.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								dist/utils/html-to-wpml.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the Markdown to WordProcessingML conversion routine.
 | 
				
			||||||
 | 
					@license MIT. Copyright (c) 2015 James Devlin / FluentDesk.
 | 
				
			||||||
 | 
					@module utils/html-to-wpml
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var HTML5Tokenizer, _;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HTML5Tokenizer = require('simple-html-tokenizer');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = function(html) {
 | 
				
			||||||
 | 
					    var final, is_bold, is_italic, is_link, link_url, tokens;
 | 
				
			||||||
 | 
					    tokens = HTML5Tokenizer.tokenize(html);
 | 
				
			||||||
 | 
					    final = is_bold = is_italic = is_link = link_url = '';
 | 
				
			||||||
 | 
					    _.each(tokens, function(tok) {
 | 
				
			||||||
 | 
					      var style;
 | 
				
			||||||
 | 
					      switch (tok.type) {
 | 
				
			||||||
 | 
					        case 'StartTag':
 | 
				
			||||||
 | 
					          switch (tok.tagName) {
 | 
				
			||||||
 | 
					            case 'p':
 | 
				
			||||||
 | 
					              return final += '<w:p>';
 | 
				
			||||||
 | 
					            case 'strong':
 | 
				
			||||||
 | 
					              return is_bold = true;
 | 
				
			||||||
 | 
					            case 'em':
 | 
				
			||||||
 | 
					              return is_italic = true;
 | 
				
			||||||
 | 
					            case 'a':
 | 
				
			||||||
 | 
					              is_link = true;
 | 
				
			||||||
 | 
					              return link_url = tok.attributes.filter(function(attr) {
 | 
				
			||||||
 | 
					                return attr[0] === 'href';
 | 
				
			||||||
 | 
					              })[0][1];
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case 'EndTag':
 | 
				
			||||||
 | 
					          switch (tok.tagName) {
 | 
				
			||||||
 | 
					            case 'p':
 | 
				
			||||||
 | 
					              return final += '</w:p>';
 | 
				
			||||||
 | 
					            case 'strong':
 | 
				
			||||||
 | 
					              return is_bold = false;
 | 
				
			||||||
 | 
					            case 'em':
 | 
				
			||||||
 | 
					              return is_italic = false;
 | 
				
			||||||
 | 
					            case 'a':
 | 
				
			||||||
 | 
					              return is_link = false;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case 'Chars':
 | 
				
			||||||
 | 
					          if ((tok.chars.trim().length)) {
 | 
				
			||||||
 | 
					            style = is_bold ? '<w:b/>' : '';
 | 
				
			||||||
 | 
					            style += is_italic ? '<w:i/>' : '';
 | 
				
			||||||
 | 
					            style += is_link ? '<w:rStyle w:val="Hyperlink"/>' : '';
 | 
				
			||||||
 | 
					            return final += (is_link ? '<w:hlink w:dest="' + link_url + '">' : '') + '<w:r><w:rPr>' + style + '</w:rPr><w:t>' + tok.chars + '</w:t></w:r>' + (is_link ? '</w:hlink>' : '');
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return final;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=html-to-wpml.js.map
 | 
				
			||||||
							
								
								
									
										30
									
								
								dist/utils/md2chalk.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								dist/utils/md2chalk.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Inline Markdown-to-Chalk conversion routines.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module utils/md2chalk
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var CHALK, LO, MD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MD = require('marked');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CHALK = require('chalk');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  LO = require('lodash');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = function(v, style, boldStyle) {
 | 
				
			||||||
 | 
					    var temp;
 | 
				
			||||||
 | 
					    boldStyle = boldStyle || 'bold';
 | 
				
			||||||
 | 
					    temp = v.replace(/\*\*(.*?)\*\*/g, LO.get(CHALK, boldStyle)('$1'));
 | 
				
			||||||
 | 
					    if (style) {
 | 
				
			||||||
 | 
					      return LO.get(CHALK, style)(temp);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      return temp;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=md2chalk.js.map
 | 
				
			||||||
@@ -1,8 +1,4 @@
 | 
				
			|||||||
/* eslint-disable */
 | 
					 | 
				
			||||||
(function() {
 | 
					(function() {
 | 
				
			||||||
  // Exemplar script for generating documents with Phantom.js.
 | 
					 | 
				
			||||||
  // https://raw.githubusercontent.com/ariya/phantomjs/master/examples/rasterize.js
 | 
					 | 
				
			||||||
  // Converted to CoffeeScript by hacksalot
 | 
					 | 
				
			||||||
  "use strict";
 | 
					  "use strict";
 | 
				
			||||||
  var address, output, page, pageHeight, pageWidth, size, system;
 | 
					  var address, output, page, pageHeight, pageWidth, size, system;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -54,7 +50,7 @@
 | 
				
			|||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        console.log("size:", system.args[3]);
 | 
					        console.log("size:", system.args[3]);
 | 
				
			||||||
        pageWidth = parseInt(system.args[3], 10);
 | 
					        pageWidth = parseInt(system.args[3], 10);
 | 
				
			||||||
        pageHeight = parseInt(pageWidth * 3 / 4, 10); // it's as good an assumption as any
 | 
					        pageHeight = parseInt(pageWidth * 3 / 4, 10);
 | 
				
			||||||
        console.log("pageHeight:", pageHeight);
 | 
					        console.log("pageHeight:", pageHeight);
 | 
				
			||||||
        page.viewportSize = {
 | 
					        page.viewportSize = {
 | 
				
			||||||
          width: pageWidth,
 | 
					          width: pageWidth,
 | 
				
			||||||
@@ -80,5 +76,4 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}).call(this);
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* eslint-enable */
 | 
					 | 
				
			||||||
//# sourceMappingURL=rasterize.js.map
 | 
					//# sourceMappingURL=rasterize.js.map
 | 
				
			||||||
							
								
								
									
										34
									
								
								dist/utils/safe-json-loader.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								dist/utils/safe-json-loader.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definition of the SafeJsonLoader class.
 | 
				
			||||||
 | 
					@module utils/safe-json-loader
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var FS, SyntaxErrorEx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FS = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SyntaxErrorEx = require('./syntax-error-ex');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = function(file) {
 | 
				
			||||||
 | 
					    var ret, retRaw;
 | 
				
			||||||
 | 
					    ret = {};
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      ret.raw = FS.readFileSync(file, 'utf8');
 | 
				
			||||||
 | 
					      ret.json = JSON.parse(ret.raw);
 | 
				
			||||||
 | 
					    } catch (_error) {
 | 
				
			||||||
 | 
					      retRaw = ret.raw && ret.raw.trim();
 | 
				
			||||||
 | 
					      ret.ex = {
 | 
				
			||||||
 | 
					        operation: retRaw ? 'parse' : 'read',
 | 
				
			||||||
 | 
					        inner: SyntaxErrorEx.is(_error) ? new SyntaxErrorEx(_error, retRaw) : _error,
 | 
				
			||||||
 | 
					        file: file
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=safe-json-loader.js.map
 | 
				
			||||||
							
								
								
									
										46
									
								
								dist/utils/safe-spawn.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								dist/utils/safe-spawn.js
									
									
									
									
										vendored
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										64
									
								
								dist/utils/string-transformer.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								dist/utils/string-transformer.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Object string transformation.
 | 
				
			||||||
 | 
					@module utils/string-transformer
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  var _, moment;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _ = require('underscore');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  moment = require('moment');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Create a copy of this object in which all string fields have been run through
 | 
				
			||||||
 | 
					  a transformation function (such as a Markdown filter or XML encoder).
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = function(ret, filt, transformer) {
 | 
				
			||||||
 | 
					    var that, transformStringsInObject;
 | 
				
			||||||
 | 
					    that = this;
 | 
				
			||||||
 | 
					    transformStringsInObject = function(obj, filters) {
 | 
				
			||||||
 | 
					      if (!obj) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (moment.isMoment(obj)) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (_.isArray(obj)) {
 | 
				
			||||||
 | 
					        return obj.forEach(function(elem, idx, ar) {
 | 
				
			||||||
 | 
					          if (typeof elem === 'string' || elem instanceof String) {
 | 
				
			||||||
 | 
					            return ar[idx] = transformer(null, elem);
 | 
				
			||||||
 | 
					          } else if (_.isObject(elem)) {
 | 
				
			||||||
 | 
					            return transformStringsInObject(elem, filters);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      } else if (_.isObject(obj)) {
 | 
				
			||||||
 | 
					        return Object.keys(obj).forEach(function(k) {
 | 
				
			||||||
 | 
					          var sub;
 | 
				
			||||||
 | 
					          if (filters.length && _.contains(filters, k)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          sub = obj[k];
 | 
				
			||||||
 | 
					          if (typeof sub === 'string' || sub instanceof String) {
 | 
				
			||||||
 | 
					            return obj[k] = transformer(k, sub);
 | 
				
			||||||
 | 
					          } else if (_.isObject(sub)) {
 | 
				
			||||||
 | 
					            return transformStringsInObject(sub, filters);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    Object.keys(ret).forEach(function(member) {
 | 
				
			||||||
 | 
					      if (!filt || !filt.length || !_.contains(filt, member)) {
 | 
				
			||||||
 | 
					        return transformStringsInObject(ret[member], filt || []);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=string-transformer.js.map
 | 
				
			||||||
							
								
								
									
										29
									
								
								dist/utils/string.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								dist/utils/string.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Definitions of string utility functions.
 | 
				
			||||||
 | 
					@module utils/string
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Determine if the string is null, empty, or whitespace.
 | 
				
			||||||
 | 
					See: http://stackoverflow.com/a/32800728/4942583
 | 
				
			||||||
 | 
					@method isNullOrWhitespace
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  String.isNullOrWhitespace = function(input) {
 | 
				
			||||||
 | 
					    return !input || !input.trim();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  String.prototype.endsWith = function(suffix) {
 | 
				
			||||||
 | 
					    return this.indexOf(suffix, this.length - suffix.length) !== -1;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  String.is = function(val) {
 | 
				
			||||||
 | 
					    return typeof val === 'string' || val instanceof String;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=string.js.map
 | 
				
			||||||
							
								
								
									
										55
									
								
								dist/utils/syntax-error-ex.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								dist/utils/syntax-error-ex.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										110
									
								
								dist/verbs/analyze.js
									
									
									
									
										vendored
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										450
									
								
								dist/verbs/build.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										450
									
								
								dist/verbs/build.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,450 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					Implementation of the 'build' verb for HackMyResume.
 | 
				
			||||||
 | 
					@module verbs/build
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(function() {
 | 
				
			||||||
 | 
					  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');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PATH = require('path');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FS = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MD = require('marked');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MKDIRP = require('mkdirp');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  extend = require('extend');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  parsePath = require('parse-filepath');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  RConverter = require('fresh-jrs-converter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HMSTATUS = require('../core/status-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  HMEVENT = require('../core/event-codes');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  RTYPES = {
 | 
				
			||||||
 | 
					    FRESH: require('../core/fresh-resume'),
 | 
				
			||||||
 | 
					    JRS: require('../core/jrs-resume')
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _opts = require('../core/default-options');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  FRESHTheme = require('../core/fresh-theme');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  JRSTheme = require('../core/jrs-theme');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ResumeFactory = require('../core/resume-factory');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _fmts = require('../core/default-formats');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Verb = require('../verbs/verb');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _err = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _log = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _rezObj = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  build = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  prep = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  single = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  verifyOutputs = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  addFreebieFormats = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  expand = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  verifyTheme = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  loadTheme = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** An invokable resume generation command. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  module.exports = BuildVerb = (function(superClass) {
 | 
				
			||||||
 | 
					    extend1(BuildVerb, superClass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Create a new build verb. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function BuildVerb() {
 | 
				
			||||||
 | 
					      BuildVerb.__super__.constructor.call(this, 'build', _build);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return BuildVerb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  })(Verb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Given a source resume in FRESH or JRS format, a destination resume path, and a
 | 
				
			||||||
 | 
					  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 opts Generation options.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _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.call(this, src, dst, opts);
 | 
				
			||||||
 | 
					    sheetObjects = ResumeFactory.load(src, {
 | 
				
			||||||
 | 
					      format: null,
 | 
				
			||||||
 | 
					      objectify: false,
 | 
				
			||||||
 | 
					      quit: true,
 | 
				
			||||||
 | 
					      inner: {
 | 
				
			||||||
 | 
					        sort: _opts.sort
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }, this);
 | 
				
			||||||
 | 
					    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) {
 | 
				
			||||||
 | 
					      return r.json;
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    theme = null;
 | 
				
			||||||
 | 
					    this.stat(HMEVENT.beforeTheme, {
 | 
				
			||||||
 | 
					      theme: _opts.theme
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      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) {
 | 
				
			||||||
 | 
					      newEx = {
 | 
				
			||||||
 | 
					        fluenterror: HMSTATUS.themeLoad,
 | 
				
			||||||
 | 
					        inner: _error,
 | 
				
			||||||
 | 
					        attempted: _opts.theme,
 | 
				
			||||||
 | 
					        quit: true
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					      this.err(HMSTATUS.themeLoad, newEx);
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.stat(HMEVENT.afterTheme, {
 | 
				
			||||||
 | 
					      theme: theme
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    inv = _verifyOutputs.call(this, dst, theme);
 | 
				
			||||||
 | 
					    if (inv && inv.length) {
 | 
				
			||||||
 | 
					      this.err(HMSTATUS.invalidFormat, {
 | 
				
			||||||
 | 
					        data: inv,
 | 
				
			||||||
 | 
					        theme: theme,
 | 
				
			||||||
 | 
					        quit: true
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    rez = null;
 | 
				
			||||||
 | 
					    if (sheets.length > 1) {
 | 
				
			||||||
 | 
					      isFRESH = !sheets[0].basics;
 | 
				
			||||||
 | 
					      mixed = _.any(sheets, function(s) {
 | 
				
			||||||
 | 
					        if (isFRESH) {
 | 
				
			||||||
 | 
					          return s.basics;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          return !s.basics;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      this.stat(HMEVENT.beforeMerge, {
 | 
				
			||||||
 | 
					        f: _.clone(sheetObjects),
 | 
				
			||||||
 | 
					        mixed: mixed
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      if (mixed) {
 | 
				
			||||||
 | 
					        this.err(HMSTATUS.mixedMerge);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      rez = _.reduceRight(sheets, function(a, b, idx) {
 | 
				
			||||||
 | 
					        return extend(true, b, a);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      this.stat(HMEVENT.afterMerge, {
 | 
				
			||||||
 | 
					        r: rez
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      rez = sheets[0];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    orgFormat = rez.basics ? 'JRS' : 'FRESH';
 | 
				
			||||||
 | 
					    toFormat = theme.render ? 'JRS' : 'FRESH';
 | 
				
			||||||
 | 
					    if (toFormat !== orgFormat) {
 | 
				
			||||||
 | 
					      this.stat(HMEVENT.beforeInlineConvert);
 | 
				
			||||||
 | 
					      rez = RConverter['to' + toFormat](rez);
 | 
				
			||||||
 | 
					      this.stat(HMEVENT.afterInlineConvert, {
 | 
				
			||||||
 | 
					        file: sheetObjects[0].file,
 | 
				
			||||||
 | 
					        fmt: toFormat
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.stat(HMEVENT.applyTheme, {
 | 
				
			||||||
 | 
					      r: rez,
 | 
				
			||||||
 | 
					      theme: theme
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    _rezObj = new RTYPES[toFormat]().parseJSON(rez);
 | 
				
			||||||
 | 
					    targets = _expand(dst, theme);
 | 
				
			||||||
 | 
					    _.each(targets, function(t) {
 | 
				
			||||||
 | 
					      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);
 | 
				
			||||||
 | 
					    results = {
 | 
				
			||||||
 | 
					      sheet: _rezObj,
 | 
				
			||||||
 | 
					      targets: targets,
 | 
				
			||||||
 | 
					      processed: targets
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    if (this.hasError() && !opts.assert) {
 | 
				
			||||||
 | 
					      this.reject(results);
 | 
				
			||||||
 | 
					    } else if (!this.hasError()) {
 | 
				
			||||||
 | 
					      this.resolve(results);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return results;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Prepare for a BUILD run.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _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;
 | 
				
			||||||
 | 
					    _opts.pdf = opts.pdf;
 | 
				
			||||||
 | 
					    _opts.wrap = opts.wrap || 60;
 | 
				
			||||||
 | 
					    _opts.stitles = opts.sectionTitles;
 | 
				
			||||||
 | 
					    _opts.tips = opts.tips;
 | 
				
			||||||
 | 
					    _opts.errHandler = opts.errHandler;
 | 
				
			||||||
 | 
					    _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());
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Generate a single target resume such as "out/rez.html" or "out/rez.doc".
 | 
				
			||||||
 | 
					  TODO: Refactor.
 | 
				
			||||||
 | 
					  @param targInfo Information for the target resume.
 | 
				
			||||||
 | 
					  @param theme A FRESHTheme or JRSTheme object.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _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 {};
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      fType = targInfo.fmt.outFormat;
 | 
				
			||||||
 | 
					      fName = PATH.basename(f, '.' + fType);
 | 
				
			||||||
 | 
					      theFormat = null;
 | 
				
			||||||
 | 
					      this.stat(HMEVENT.beforeGenerate, {
 | 
				
			||||||
 | 
					        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));
 | 
				
			||||||
 | 
					        ret = theFormat.gen.generate(_rezObj, f, _opts);
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        theFormat = _fmts.filter(function(fmt) {
 | 
				
			||||||
 | 
					          return fmt.name === targInfo.fmt.outFormat;
 | 
				
			||||||
 | 
					        })[0];
 | 
				
			||||||
 | 
					        outFolder = PATH.dirname(f);
 | 
				
			||||||
 | 
					        MKDIRP.sync(outFolder);
 | 
				
			||||||
 | 
					        ret = theFormat.gen.generate(_rezObj, f, _opts);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } catch (_error) {
 | 
				
			||||||
 | 
					      e = _error;
 | 
				
			||||||
 | 
					      ex = e;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.stat(HMEVENT.afterGenerate, {
 | 
				
			||||||
 | 
					      fmt: targInfo.fmt.outFormat,
 | 
				
			||||||
 | 
					      file: PATH.relative(process.cwd(), f),
 | 
				
			||||||
 | 
					      error: ex
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    if (ex) {
 | 
				
			||||||
 | 
					      if (ex.fluenterror) {
 | 
				
			||||||
 | 
					        ret = ex;
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        ret = {
 | 
				
			||||||
 | 
					          fluenterror: HMSTATUS.generateError,
 | 
				
			||||||
 | 
					          inner: ex
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return ret;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** Ensure that user-specified outputs/targets are valid. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _verifyOutputs = function(targets, theme) {
 | 
				
			||||||
 | 
					    this.stat(HMEVENT.verifyOutputs, {
 | 
				
			||||||
 | 
					      targets: targets,
 | 
				
			||||||
 | 
					      theme: theme
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return _.reject(targets.map(function(t) {
 | 
				
			||||||
 | 
					      var pathInfo;
 | 
				
			||||||
 | 
					      pathInfo = parsePath(t);
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        format: pathInfo.extname.substr(1)
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }), function(t) {
 | 
				
			||||||
 | 
					      return t.format === 'all' || theme.hasFormat(t.format);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Reinforce the chosen theme with "freebie" formats provided by HackMyResume.
 | 
				
			||||||
 | 
					  A "freebie" format is an output format such as JSON, YML, or PNG that can be
 | 
				
			||||||
 | 
					  generated directly from the resume model or from one of the theme's declared
 | 
				
			||||||
 | 
					  output formats. For example, the PNG format can be generated for any theme
 | 
				
			||||||
 | 
					  that declares an HTML format; the theme doesn't have to provide an explicit
 | 
				
			||||||
 | 
					  PNG template.
 | 
				
			||||||
 | 
					  @param theTheme A FRESHTheme or JRSTheme object.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _addFreebieFormats = function(theTheme) {
 | 
				
			||||||
 | 
					    theTheme.formats.json = theTheme.formats.json || {
 | 
				
			||||||
 | 
					      freebie: true,
 | 
				
			||||||
 | 
					      title: 'json',
 | 
				
			||||||
 | 
					      outFormat: 'json',
 | 
				
			||||||
 | 
					      pre: 'json',
 | 
				
			||||||
 | 
					      ext: 'json',
 | 
				
			||||||
 | 
					      path: null,
 | 
				
			||||||
 | 
					      data: null
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    theTheme.formats.yml = theTheme.formats.yml || {
 | 
				
			||||||
 | 
					      freebie: true,
 | 
				
			||||||
 | 
					      title: 'yaml',
 | 
				
			||||||
 | 
					      outFormat: 'yml',
 | 
				
			||||||
 | 
					      pre: 'yml',
 | 
				
			||||||
 | 
					      ext: 'yml',
 | 
				
			||||||
 | 
					      path: null,
 | 
				
			||||||
 | 
					      data: null
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    if (theTheme.formats.html && !theTheme.formats.png) {
 | 
				
			||||||
 | 
					      theTheme.formats.png = {
 | 
				
			||||||
 | 
					        freebie: true,
 | 
				
			||||||
 | 
					        title: 'png',
 | 
				
			||||||
 | 
					        outFormat: 'png',
 | 
				
			||||||
 | 
					        ext: 'yml',
 | 
				
			||||||
 | 
					        path: null,
 | 
				
			||||||
 | 
					        data: null
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Expand output files. For example, "foo.all" should be expanded to
 | 
				
			||||||
 | 
					  ["foo.html", "foo.doc", "foo.pdf", "etc"].
 | 
				
			||||||
 | 
					  @param dst An array of output files as specified by the user.
 | 
				
			||||||
 | 
					  @param theTheme A FRESHTheme or JRSTheme object.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _expand = function(dst, theTheme) {
 | 
				
			||||||
 | 
					    var destColl, targets;
 | 
				
			||||||
 | 
					    destColl = (dst && dst.length && dst) || [PATH.normalize('out/resume.all')];
 | 
				
			||||||
 | 
					    targets = [];
 | 
				
			||||||
 | 
					    destColl.forEach(function(t) {
 | 
				
			||||||
 | 
					      var fmat, pa, to;
 | 
				
			||||||
 | 
					      to = PATH.resolve(t);
 | 
				
			||||||
 | 
					      pa = parsePath(to);
 | 
				
			||||||
 | 
					      fmat = pa.extname || '.all';
 | 
				
			||||||
 | 
					      return targets.push.apply(targets, fmat === '.all' ? Object.keys(theTheme.formats).map(function(k) {
 | 
				
			||||||
 | 
					        var z;
 | 
				
			||||||
 | 
					        z = theTheme.formats[k];
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          file: to.replace(/all$/g, z.outFormat),
 | 
				
			||||||
 | 
					          fmt: z
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }) : [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          file: to,
 | 
				
			||||||
 | 
					          fmt: theTheme.getFormat(fmat.slice(1))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ]);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    return targets;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Verify the specified theme name/path.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _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)) {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					          fluenterror: HMSTATUS.themeNotFound,
 | 
				
			||||||
 | 
					          data: _opts.theme
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return tFolder;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					  Load the specified theme, which could be either a FRESH theme or a JSON Resume
 | 
				
			||||||
 | 
					  theme.
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _loadTheme = function(tFolder) {
 | 
				
			||||||
 | 
					    var theTheme;
 | 
				
			||||||
 | 
					    theTheme = _opts.theme.indexOf('jsonresume-theme-') > -1 ? new JRSTheme().open(tFolder) : new FRESHTheme().open(tFolder);
 | 
				
			||||||
 | 
					    _opts.themeObj = theTheme;
 | 
				
			||||||
 | 
					    return theTheme;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}).call(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//# sourceMappingURL=build.js.map
 | 
				
			||||||
							
								
								
									
										115
									
								
								dist/verbs/convert.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								dist/verbs/convert.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										103
									
								
								dist/verbs/create.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										106
									
								
								dist/verbs/peek.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										139
									
								
								dist/verbs/validate.js
									
									
									
									
										vendored
									
									
										Normal 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
									
								
							
							
						
						
									
										118
									
								
								dist/verbs/verb.js
									
									
									
									
										vendored
									
									
										Normal 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
 | 
				
			||||||
							
								
								
									
										2800
									
								
								npm-shrinkwrap.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2800
									
								
								npm-shrinkwrap.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										62
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								package.json
									
									
									
									
									
								
							@@ -1,13 +1,13 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "hackmyresume",
 | 
					  "name": "hackmyresume",
 | 
				
			||||||
  "version": "1.9.0",
 | 
					  "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.",
 | 
					  "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": {
 | 
					  "repository": {
 | 
				
			||||||
    "type": "git",
 | 
					    "type": "git",
 | 
				
			||||||
    "url": "https://github.com/hacksalot/HackMyResume.git"
 | 
					    "url": "https://github.com/hacksalot/HackMyResume.git"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "scripts": {
 | 
					  "scripts": {
 | 
				
			||||||
    "test": "grunt clean:test && mocha --exit",
 | 
					    "test": "grunt clean:test && mocha",
 | 
				
			||||||
    "grunt": "grunt"
 | 
					    "grunt": "grunt"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "keywords": [
 | 
					  "keywords": [
 | 
				
			||||||
@@ -31,7 +31,6 @@
 | 
				
			|||||||
  "author": "hacksalot <hacksalot@indevious.com> (https://github.com/hacksalot)",
 | 
					  "author": "hacksalot <hacksalot@indevious.com> (https://github.com/hacksalot)",
 | 
				
			||||||
  "contributors": [
 | 
					  "contributors": [
 | 
				
			||||||
    "aruberto (https://github.com/aruberto)",
 | 
					    "aruberto (https://github.com/aruberto)",
 | 
				
			||||||
    "daniele-rapagnani (https://github.com/daniele-rapagnani)",
 | 
					 | 
				
			||||||
    "jjanusch (https://github.com/driftdev)",
 | 
					    "jjanusch (https://github.com/driftdev)",
 | 
				
			||||||
    "robertmain (https://github.com/robertmain)",
 | 
					    "robertmain (https://github.com/robertmain)",
 | 
				
			||||||
    "tomheon (https://github.com/tomheon)",
 | 
					    "tomheon (https://github.com/tomheon)",
 | 
				
			||||||
@@ -41,41 +40,39 @@
 | 
				
			|||||||
  "license": "MIT",
 | 
					  "license": "MIT",
 | 
				
			||||||
  "preferGlobal": "true",
 | 
					  "preferGlobal": "true",
 | 
				
			||||||
  "bugs": {
 | 
					  "bugs": {
 | 
				
			||||||
    "url": "https://github.com/hacksalot/HackMyResume/issues"
 | 
					    "url": "https://github.com/JuanCanham/HackMyResume/issues"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "bin": {
 | 
					  "bin": {
 | 
				
			||||||
    "hackmyresume": "src/cli/index.js"
 | 
					    "hackmyresume": "dist/cli/index.js"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "main": "src/index.js",
 | 
					  "main": "dist/index.js",
 | 
				
			||||||
  "homepage": "https://github.com/hacksalot/HackMyResume",
 | 
					  "homepage": "https://github.com/JuanCanham/HackMyResume",
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "chalk": "^2.3.1",
 | 
					    "chalk": "^1.1.1",
 | 
				
			||||||
    "commander": "^2.9.0",
 | 
					    "commander": "^2.9.0",
 | 
				
			||||||
    "copy": "^0.3.1",
 | 
					    "copy": "^0.1.3",
 | 
				
			||||||
    "escape-latex": "^1.0.0",
 | 
					    "escape-latex": "^0.1.2",
 | 
				
			||||||
    "extend": "^3.0.0",
 | 
					    "extend": "^3.0.0",
 | 
				
			||||||
    "fresh-jrs-converter": "^1.0.0",
 | 
					    "fresca": "~0.6.0",
 | 
				
			||||||
    "fresh-resume-schema": "^1.0.0-beta",
 | 
					    "fresh-jrs-converter": "^0.2.2",
 | 
				
			||||||
    "fresh-resume-starter": "^0.3.1",
 | 
					    "fresh-resume-starter": "^0.2.2",
 | 
				
			||||||
    "fresh-resume-validator": "^0.2.0",
 | 
					    "fresh-themes": "git+https://git.juancanham.com/JuanCanham/fresh-themes.git#feature/certifications",
 | 
				
			||||||
    "fresh-themes": "^0.17.0-beta",
 | 
					    "fs-extra": "^0.26.4",
 | 
				
			||||||
    "fs-extra": "^5.0.0",
 | 
					 | 
				
			||||||
    "glob": "^7.1.2",
 | 
					 | 
				
			||||||
    "handlebars": "^4.0.5",
 | 
					    "handlebars": "^4.0.5",
 | 
				
			||||||
    "html": "^1.0.0",
 | 
					    "html": "0.0.10",
 | 
				
			||||||
    "is-my-json-valid": "^2.12.4",
 | 
					    "is-my-json-valid": "^2.12.4",
 | 
				
			||||||
    "json-lint": "^0.1.0",
 | 
					    "json-lint": "^0.1.0",
 | 
				
			||||||
    "jsonlint": "^1.6.2",
 | 
					    "jsonlint": "^1.6.2",
 | 
				
			||||||
    "lodash": "^4.17.5",
 | 
					    "lodash": "^3.10.1",
 | 
				
			||||||
    "marked": "^0.3.5",
 | 
					    "marked": "^0.3.5",
 | 
				
			||||||
    "mkdirp": "^0.5.1",
 | 
					    "mkdirp": "^0.5.1",
 | 
				
			||||||
    "moment": "^2.11.1",
 | 
					    "moment": "^2.11.1",
 | 
				
			||||||
    "parse-filepath": "^1.0.2",
 | 
					    "parse-filepath": "^0.6.3",
 | 
				
			||||||
    "path-exists": "^3.0.0",
 | 
					    "path-exists": "^2.1.0",
 | 
				
			||||||
    "pinkie-promise": "^2.0.0",
 | 
					    "pinkie-promise": "^2.0.0",
 | 
				
			||||||
    "printf": "^0.2.3",
 | 
					    "printf": "^0.2.3",
 | 
				
			||||||
    "recursive-readdir-sync": "^1.0.6",
 | 
					    "recursive-readdir-sync": "^1.0.6",
 | 
				
			||||||
    "simple-html-tokenizer": "^0.4.3",
 | 
					    "simple-html-tokenizer": "^0.2.1",
 | 
				
			||||||
    "slash": "^1.0.0",
 | 
					    "slash": "^1.0.0",
 | 
				
			||||||
    "string-padding": "^1.0.2",
 | 
					    "string-padding": "^1.0.2",
 | 
				
			||||||
    "string.prototype.endswith": "^0.2.0",
 | 
					    "string.prototype.endswith": "^0.2.0",
 | 
				
			||||||
@@ -84,26 +81,27 @@
 | 
				
			|||||||
    "underscore": "^1.8.3",
 | 
					    "underscore": "^1.8.3",
 | 
				
			||||||
    "word-wrap": "^1.1.0",
 | 
					    "word-wrap": "^1.1.0",
 | 
				
			||||||
    "xml-escape": "^1.0.0",
 | 
					    "xml-escape": "^1.0.0",
 | 
				
			||||||
    "yamljs": "^0.3.0"
 | 
					    "yamljs": "^0.2.4"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "chai": "*",
 | 
					    "chai": "*",
 | 
				
			||||||
    "chai-as-promised": "^7.1.1",
 | 
					    "dir-compare": "0.0.2",
 | 
				
			||||||
    "dir-compare": "^1.4.0",
 | 
					    "fresh-test-resumes": "^0.7.0",
 | 
				
			||||||
    "fresh-test-resumes": "^0.9.2",
 | 
					 | 
				
			||||||
    "fresh-test-themes": "^0.2.0",
 | 
					 | 
				
			||||||
    "fresh-theme-underscore": "^0.1.1",
 | 
					 | 
				
			||||||
    "grunt": "*",
 | 
					    "grunt": "*",
 | 
				
			||||||
    "grunt-contrib-clean": "^1.1.0",
 | 
					    "grunt-cli": "^0.1.13",
 | 
				
			||||||
    "grunt-contrib-coffee": "^2.0.0",
 | 
					    "grunt-contrib-clean": "^0.7.0",
 | 
				
			||||||
    "grunt-contrib-copy": "^1.0.0",
 | 
					    "grunt-contrib-coffee": "^0.13.0",
 | 
				
			||||||
    "grunt-eslint": "^20.1.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": "*",
 | 
					    "grunt-simple-mocha": "*",
 | 
				
			||||||
    "jsonresume-theme-boilerplate": "^0.1.2",
 | 
					    "jsonresume-theme-boilerplate": "^0.1.2",
 | 
				
			||||||
    "jsonresume-theme-classy": "^1.0.9",
 | 
					    "jsonresume-theme-classy": "^1.0.9",
 | 
				
			||||||
    "jsonresume-theme-modern": "0.0.18",
 | 
					    "jsonresume-theme-modern": "0.0.18",
 | 
				
			||||||
    "jsonresume-theme-sceptile": "^1.0.5",
 | 
					    "jsonresume-theme-sceptile": "^1.0.5",
 | 
				
			||||||
    "mocha": "*",
 | 
					    "mocha": "*",
 | 
				
			||||||
 | 
					    "resample": "fluentdesk/resample",
 | 
				
			||||||
    "stripcolorcodes": "^0.1.0"
 | 
					    "stripcolorcodes": "^0.1.0"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										232
									
								
								src/cli/error.coffee
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								src/cli/error.coffee
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,232 @@
 | 
				
			|||||||
 | 
					###*
 | 
				
			||||||
 | 
					Error-handling routines for HackMyResume.
 | 
				
			||||||
 | 
					@module cli/error
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					###
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 ###
 | 
				
			||||||
 | 
					ErrorHandler = module.exports =
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  init: ( debug, assert, silent ) ->
 | 
				
			||||||
 | 
					    @debug = debug
 | 
				
			||||||
 | 
					    @assert = assert
 | 
				
			||||||
 | 
					    @silent = silent
 | 
				
			||||||
 | 
					    @msgs = require('./msg').errors
 | 
				
			||||||
 | 
					    @
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  err: ( ex, shouldExit ) ->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Short-circuit logging output if --silent is on
 | 
				
			||||||
 | 
					    o = if @silent then () -> else _defaultLog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Special case; can probably be removed.
 | 
				
			||||||
 | 
					    throw ex if ex.pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Load error messages
 | 
				
			||||||
 | 
					    @msgs = @msgs || require('./msg').errors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Handle packaged HMR exceptions
 | 
				
			||||||
 | 
					    if ex.fluenterror
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Output the error message
 | 
				
			||||||
 | 
					      objError = assembleError.call @, ex
 | 
				
			||||||
 | 
					      o( @[ 'format_' + objError.etype ]( objError.msg ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Output the stack (sometimes)
 | 
				
			||||||
 | 
					      if objError.withStack
 | 
				
			||||||
 | 
					        stack = ex.stack || (ex.inner && ex.inner.stack);
 | 
				
			||||||
 | 
					        stack && o( chalk.gray( stack ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      # Quit if necessary
 | 
				
			||||||
 | 
					      if shouldExit
 | 
				
			||||||
 | 
					        if @debug
 | 
				
			||||||
 | 
					          o chalk.cyan('Exiting with error code ' + ex.fluenterror.toString())
 | 
				
			||||||
 | 
					        if @assert
 | 
				
			||||||
 | 
					          ex.pass = true
 | 
				
			||||||
 | 
					          throw ex
 | 
				
			||||||
 | 
					        process.exit ex.fluenterror
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Handle raw exceptions
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      o ex
 | 
				
			||||||
 | 
					      stackTrace = ex.stack || (ex.inner && ex.inner.stack)
 | 
				
			||||||
 | 
					      if stackTrace && this.debug
 | 
				
			||||||
 | 
					        o M2C(ex.stack || ex.inner.stack, 'gray')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  format_error: ( msg ) ->
 | 
				
			||||||
 | 
					    msg = msg || ''
 | 
				
			||||||
 | 
					    chalk.red.bold( if msg.toUpperCase().startsWith('ERROR:') then msg else 'Error: ' + msg )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  format_warning: ( brief, msg ) ->
 | 
				
			||||||
 | 
					    chalk.yellow(brief) + chalk.yellow(msg || '')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  format_custom: ( msg ) -> msg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_defaultLog = () -> console.log.apply console.log, arguments
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					assembleError = ( ex ) ->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  msg = ''
 | 
				
			||||||
 | 
					  withStack = false
 | 
				
			||||||
 | 
					  quit = false
 | 
				
			||||||
 | 
					  etype = 'warning'
 | 
				
			||||||
 | 
					  withStack = true if @debug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  switch ex.fluenterror
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.themeNotFound
 | 
				
			||||||
 | 
					      msg = printf( M2C( this.msgs.themeNotFound.msg, 'yellow' ), ex.data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.copyCSS
 | 
				
			||||||
 | 
					      msg = M2C( this.msgs.copyCSS.msg, 'red' )
 | 
				
			||||||
 | 
					      quit = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.resumeNotFound
 | 
				
			||||||
 | 
					      msg = M2C( this.msgs.resumeNotFound.msg, 'yellow' );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.missingCommand
 | 
				
			||||||
 | 
					      msg = M2C( this.msgs.missingCommand.msg + " (", 'yellow');
 | 
				
			||||||
 | 
					      msg += Object.keys( FCMD.verbs ).map( (v, idx, ar) ->
 | 
				
			||||||
 | 
					        return ( if idx == ar.length - 1 then chalk.yellow('or ') else '') +
 | 
				
			||||||
 | 
					          chalk.yellow.bold(v.toUpperCase());
 | 
				
			||||||
 | 
					      ).join( chalk.yellow(', ')) + chalk.yellow(").\n\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      msg += chalk.gray(FS.readFileSync(
 | 
				
			||||||
 | 
					        PATH.resolve(__dirname, '../cli/use.txt'), 'utf8' ))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.invalidCommand
 | 
				
			||||||
 | 
					      msg = printf( M2C( this.msgs.invalidCommand.msg, 'yellow'), ex.attempted )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.resumeNotFoundAlt
 | 
				
			||||||
 | 
					      msg = M2C( this.msgs.resumeNotFoundAlt.msg, 'yellow' )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.inputOutputParity
 | 
				
			||||||
 | 
					      msg = M2C( this.msgs.inputOutputParity.msg )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.createNameMissing
 | 
				
			||||||
 | 
					      msg = M2C( this.msgs.createNameMissing.msg )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.pdfGeneration
 | 
				
			||||||
 | 
					      msg = M2C( this.msgs.pdfGeneration.msg, 'bold' )
 | 
				
			||||||
 | 
					      msg += chalk.red('\n' + ex.inner) if ex.inner
 | 
				
			||||||
 | 
					      quit = false
 | 
				
			||||||
 | 
					      etype = 'error'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.invalid
 | 
				
			||||||
 | 
					      msg = M2C( this.msgs.invalid.msg, 'red' )
 | 
				
			||||||
 | 
					      etype = 'error'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.generateError
 | 
				
			||||||
 | 
					      msg = (ex.inner && ex.inner.toString()) || ex
 | 
				
			||||||
 | 
					      quit = false
 | 
				
			||||||
 | 
					      etype = 'error'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.fileSaveError
 | 
				
			||||||
 | 
					      msg = printf( M2C( this.msgs.fileSaveError.msg ), (ex.inner || ex).toString() )
 | 
				
			||||||
 | 
					      etype = 'error'
 | 
				
			||||||
 | 
					      quit = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.invalidFormat
 | 
				
			||||||
 | 
					      ex.data.forEach( (d) ->
 | 
				
			||||||
 | 
					        msg += printf( M2C( this.msgs.invalidFormat.msg, 'bold' ),
 | 
				
			||||||
 | 
					          ex.theme.name.toUpperCase(), d.format.toUpperCase())
 | 
				
			||||||
 | 
					      , @);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.missingParam
 | 
				
			||||||
 | 
					      msg = printf(M2C( this.msgs.missingParam.msg ), ex.expected, ex.helper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.invalidHelperUse
 | 
				
			||||||
 | 
					      msg = printf( M2C( this.msgs.invalidHelperUse.msg ), ex.helper )
 | 
				
			||||||
 | 
					      if ex.error
 | 
				
			||||||
 | 
					        msg += '\n--> ' + assembleError.call( this, extend( true, {}, ex, {fluenterror: ex.error} )).msg;
 | 
				
			||||||
 | 
					        #msg += printf( '\n--> ' + M2C( this.msgs.invalidParamCount.msg ), ex.expected );
 | 
				
			||||||
 | 
					      quit = false
 | 
				
			||||||
 | 
					      etype = 'warning'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.notOnPath
 | 
				
			||||||
 | 
					      msg = printf( M2C(this.msgs.notOnPath.msg, 'bold'), ex.engine)
 | 
				
			||||||
 | 
					      quit = false
 | 
				
			||||||
 | 
					      etype = 'error'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.readError
 | 
				
			||||||
 | 
					      if !ex.quiet
 | 
				
			||||||
 | 
					        console.error(printf( M2C(this.msgs.readError.msg, 'red'), ex.file))
 | 
				
			||||||
 | 
					      msg = ex.inner.toString()
 | 
				
			||||||
 | 
					      etype = 'error'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.mixedMerge
 | 
				
			||||||
 | 
					      msg = M2C this.msgs.mixedMerge.msg
 | 
				
			||||||
 | 
					      quit = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.invokeTemplate
 | 
				
			||||||
 | 
					      msg = M2C this.msgs.invokeTemplate.msg, 'red'
 | 
				
			||||||
 | 
					      msg += M2C( '\n' + WRAP(ex.inner.toString(), { width: 60, indent: '   ' }), 'gray' );
 | 
				
			||||||
 | 
					      etype = 'custom'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.compileTemplate
 | 
				
			||||||
 | 
					      etype = 'error'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.themeLoad
 | 
				
			||||||
 | 
					      msg = M2C( printf( this.msgs.themeLoad.msg, ex.attempted.toUpperCase() ), 'red');
 | 
				
			||||||
 | 
					      if ex.inner && ex.inner.fluenterror
 | 
				
			||||||
 | 
					        msg += M2C('\nError: ', 'red') + assembleError.call( this, ex.inner ).msg
 | 
				
			||||||
 | 
					      quit = true
 | 
				
			||||||
 | 
					      etype = 'custom'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    when HMSTATUS.parseError
 | 
				
			||||||
 | 
					      if SyntaxErrorEx.is ex.inner
 | 
				
			||||||
 | 
					        console.error printf( M2C(this.msgs.readError.msg, 'red'), ex.file )
 | 
				
			||||||
 | 
					        se = new SyntaxErrorEx ex, ex.raw
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					  etype: etype
 | 
				
			||||||
							
								
								
									
										328
									
								
								src/cli/error.js
									
									
									
									
									
								
							
							
						
						
									
										328
									
								
								src/cli/error.js
									
									
									
									
									
								
							@@ -1,328 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * decaffeinate suggestions:
 | 
					 | 
				
			||||||
 * DS102: Remove unnecessary code created because of implicit returns
 | 
					 | 
				
			||||||
 * DS207: Consider shorter variations of null checks
 | 
					 | 
				
			||||||
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
Error-handling routines for HackMyResume.
 | 
					 | 
				
			||||||
@module cli/error
 | 
					 | 
				
			||||||
@license MIT. See LICENSE.md for details.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const HMSTATUS = require('../core/status-codes');
 | 
					 | 
				
			||||||
const FS = require('fs');
 | 
					 | 
				
			||||||
const PATH = require('path');
 | 
					 | 
				
			||||||
const WRAP = require('word-wrap');
 | 
					 | 
				
			||||||
const M2C = require('../utils/md2chalk');
 | 
					 | 
				
			||||||
const chalk = require('chalk');
 | 
					 | 
				
			||||||
const extend = require('extend');
 | 
					 | 
				
			||||||
const printf = require('printf');
 | 
					 | 
				
			||||||
const SyntaxErrorEx = require('../utils/syntax-error-ex');
 | 
					 | 
				
			||||||
require('string.prototype.startswith');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Error handler for HackMyResume. All errors are handled here.
 | 
					 | 
				
			||||||
@class ErrorHandler */
 | 
					 | 
				
			||||||
module.exports = {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  init( debug, assert, silent ) {
 | 
					 | 
				
			||||||
    this.debug = debug;
 | 
					 | 
				
			||||||
    this.assert = assert;
 | 
					 | 
				
			||||||
    this.silent = silent;
 | 
					 | 
				
			||||||
    this.msgs = require('./msg').errors;
 | 
					 | 
				
			||||||
    return this;
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  err( ex, shouldExit ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Short-circuit logging output if --silent is on
 | 
					 | 
				
			||||||
    let stack;
 | 
					 | 
				
			||||||
    const o = this.silent ? function() {} : _defaultLog;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Special case; can probably be removed.
 | 
					 | 
				
			||||||
    if (ex.pass) { throw ex; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Load error messages
 | 
					 | 
				
			||||||
    this.msgs = this.msgs || require('./msg').errors;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Handle packaged HMR exceptions
 | 
					 | 
				
			||||||
    if (ex.fluenterror) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Output the error message
 | 
					 | 
				
			||||||
      const objError = assembleError.call(this, ex);
 | 
					 | 
				
			||||||
      o( this[ `format_${objError.etype}` ]( objError.msg ));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Output the stack (sometimes)
 | 
					 | 
				
			||||||
      if (objError.withStack) {
 | 
					 | 
				
			||||||
        stack = ex.stack || (ex.inner && ex.inner.stack);
 | 
					 | 
				
			||||||
        stack && o( chalk.gray( stack ) );
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Quit if necessary
 | 
					 | 
				
			||||||
      if (shouldExit || ex.exit) {
 | 
					 | 
				
			||||||
        if (this.debug) {
 | 
					 | 
				
			||||||
          o(chalk.cyan(`Exiting with error code ${ex.fluenterror.toString()}`));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (this.assert) {
 | 
					 | 
				
			||||||
          ex.pass = true;
 | 
					 | 
				
			||||||
          throw ex;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return process.exit(ex.fluenterror);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Handle raw exceptions
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      o(ex);
 | 
					 | 
				
			||||||
      const stackTrace = ex.stack || (ex.inner && ex.inner.stack);
 | 
					 | 
				
			||||||
      if (stackTrace && this.debug) {
 | 
					 | 
				
			||||||
        return o(M2C(ex.stack || ex.inner.stack, 'gray'));
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  format_error( msg ) {
 | 
					 | 
				
			||||||
    msg = msg || '';
 | 
					 | 
				
			||||||
    return chalk.red.bold( msg.toUpperCase().startsWith('ERROR:') ? msg : `Error: ${msg}` );
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  format_warning( brief, msg ) {
 | 
					 | 
				
			||||||
    return chalk.yellow(brief) + chalk.yellow(msg || '');
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  format_custom( msg ) { return msg; }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var _defaultLog = function() { return console.log.apply(console.log, arguments); }; // eslint-disable-line no-console
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
var assembleError = function( ex ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let se;
 | 
					 | 
				
			||||||
  let msg = '';
 | 
					 | 
				
			||||||
  let withStack = false;
 | 
					 | 
				
			||||||
  let quit = false;
 | 
					 | 
				
			||||||
  let etype = 'warning';
 | 
					 | 
				
			||||||
  if (this.debug) { withStack = true; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (ex.fluenterror) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.themeNotFound:
 | 
					 | 
				
			||||||
      msg = printf( M2C( this.msgs.themeNotFound.msg, 'yellow' ), ex.data);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.copyCSS:
 | 
					 | 
				
			||||||
      msg = M2C( this.msgs.copyCSS.msg, 'red' );
 | 
					 | 
				
			||||||
      quit = false;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.resumeNotFound:
 | 
					 | 
				
			||||||
      //msg = M2C( this.msgs.resumeNotFound.msg, 'yellow' );
 | 
					 | 
				
			||||||
      msg += M2C(FS.readFileSync(
 | 
					 | 
				
			||||||
        PATH.resolve(__dirname, `help/${ex.verb}.txt`), 'utf8' ), 'white', 'yellow');
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.missingCommand:
 | 
					 | 
				
			||||||
      // msg = M2C( this.msgs.missingCommand.msg + " (", 'yellow');
 | 
					 | 
				
			||||||
      // msg += Object.keys( FCMD.verbs ).map( (v, idx, ar) ->
 | 
					 | 
				
			||||||
      //   return ( if idx == ar.length - 1 then chalk.yellow('or ') else '') +
 | 
					 | 
				
			||||||
      //     chalk.yellow.bold(v.toUpperCase());
 | 
					 | 
				
			||||||
      // ).join( chalk.yellow(', ')) + chalk.yellow(").\n\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      msg += M2C(FS.readFileSync(
 | 
					 | 
				
			||||||
        PATH.resolve(__dirname, 'help/use.txt'), 'utf8' ), 'white', 'yellow');
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.invalidCommand:
 | 
					 | 
				
			||||||
      msg = printf( M2C( this.msgs.invalidCommand.msg, 'yellow'), ex.attempted );
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.resumeNotFoundAlt:
 | 
					 | 
				
			||||||
      msg = M2C( this.msgs.resumeNotFoundAlt.msg, 'yellow' );
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.inputOutputParity:
 | 
					 | 
				
			||||||
      msg = M2C( this.msgs.inputOutputParity.msg );
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.createNameMissing:
 | 
					 | 
				
			||||||
      msg = M2C( this.msgs.createNameMissing.msg );
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.pdfGeneration:
 | 
					 | 
				
			||||||
      msg = M2C( this.msgs.pdfGeneration.msg, 'bold' );
 | 
					 | 
				
			||||||
      if (ex.inner) { msg += chalk.red(`\n${ex.inner}`); }
 | 
					 | 
				
			||||||
      quit = false;
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.invalid:
 | 
					 | 
				
			||||||
      msg = M2C( this.msgs.invalid.msg, 'red' );
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.generateError:
 | 
					 | 
				
			||||||
      msg = (ex.inner && ex.inner.toString()) || ex;
 | 
					 | 
				
			||||||
      quit = false;
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.fileSaveError:
 | 
					 | 
				
			||||||
      msg = printf( M2C( this.msgs.fileSaveError.msg ), (ex.inner || ex).toString() );
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      quit = false;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.invalidFormat:
 | 
					 | 
				
			||||||
      ex.data.forEach( function(d) {
 | 
					 | 
				
			||||||
        return msg += printf( M2C( this.msgs.invalidFormat.msg, 'bold' ),
 | 
					 | 
				
			||||||
          ex.theme.name.toUpperCase(), d.format.toUpperCase());
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      , this);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.missingParam:
 | 
					 | 
				
			||||||
      msg = printf(M2C( this.msgs.missingParam.msg ), ex.expected, ex.helper);
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.invalidHelperUse:
 | 
					 | 
				
			||||||
      msg = printf( M2C( this.msgs.invalidHelperUse.msg ), ex.helper );
 | 
					 | 
				
			||||||
      if (ex.error) {
 | 
					 | 
				
			||||||
        msg += `\n--> ${assembleError.call( this, extend( true, {}, ex, {fluenterror: ex.error} )).msg}`;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
        //msg += printf( '\n--> ' + M2C( this.msgs.invalidParamCount.msg ), ex.expected );
 | 
					 | 
				
			||||||
      quit = false;
 | 
					 | 
				
			||||||
      etype = 'warning';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.notOnPath:
 | 
					 | 
				
			||||||
      msg = printf( M2C(this.msgs.notOnPath.msg, 'bold'), ex.engine);
 | 
					 | 
				
			||||||
      quit = false;
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.readError:
 | 
					 | 
				
			||||||
      if (!ex.quiet) {
 | 
					 | 
				
			||||||
        // eslint-disable-next-line no-console
 | 
					 | 
				
			||||||
        console.error(printf( M2C(this.msgs.readError.msg, 'red'), ex.file));
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      msg = ex.inner.toString();
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.mixedMerge:
 | 
					 | 
				
			||||||
      msg = M2C(this.msgs.mixedMerge.msg);
 | 
					 | 
				
			||||||
      quit = false;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.invokeTemplate:
 | 
					 | 
				
			||||||
      msg = M2C(this.msgs.invokeTemplate.msg, 'red');
 | 
					 | 
				
			||||||
      msg += M2C( `\n${WRAP(ex.inner.toString(), { width: 60, indent: '   ' })}`, 'gray' );
 | 
					 | 
				
			||||||
      etype = 'custom';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.compileTemplate:
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.themeLoad:
 | 
					 | 
				
			||||||
      msg = M2C( printf( this.msgs.themeLoad.msg, ex.attempted.toUpperCase() ), 'red');
 | 
					 | 
				
			||||||
      if (ex.inner && ex.inner.fluenterror) {
 | 
					 | 
				
			||||||
        msg += M2C('\nError: ', 'red') + assembleError.call( this, ex.inner ).msg;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      quit = true;
 | 
					 | 
				
			||||||
      etype = 'custom';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.parseError:
 | 
					 | 
				
			||||||
      if (SyntaxErrorEx.is(ex.inner)) {
 | 
					 | 
				
			||||||
        // eslint-disable-next-line no-console
 | 
					 | 
				
			||||||
        console.error(printf( M2C(this.msgs.readError.msg, 'red'), ex.file ));
 | 
					 | 
				
			||||||
        se = new SyntaxErrorEx(ex, ex.raw);
 | 
					 | 
				
			||||||
        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:
 | 
					 | 
				
			||||||
      // inner.code could be EPERM, EACCES, etc
 | 
					 | 
				
			||||||
      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';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.invalidOptionsFile:
 | 
					 | 
				
			||||||
      msg = M2C(this.msgs.invalidOptionsFile.msg[0]);
 | 
					 | 
				
			||||||
      if (SyntaxErrorEx.is(ex.inner)) {
 | 
					 | 
				
			||||||
        // eslint-disable-next-line no-console
 | 
					 | 
				
			||||||
        console.error(printf( M2C(this.msgs.readError.msg, 'red'), ex.file ));
 | 
					 | 
				
			||||||
        se = new SyntaxErrorEx(ex, ex.raw);
 | 
					 | 
				
			||||||
        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;
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      msg += this.msgs.invalidOptionsFile.msg[1];
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.optionsFileNotFound:
 | 
					 | 
				
			||||||
      msg = M2C( this.msgs.optionsFileNotFound.msg );
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.unknownSchema:
 | 
					 | 
				
			||||||
      msg = M2C( this.msgs.unknownSchema.msg[0] );
 | 
					 | 
				
			||||||
      //msg += "\n" + M2C( @msgs.unknownSchema.msg[1], 'yellow' )
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.themeHelperLoad:
 | 
					 | 
				
			||||||
      msg = printf(M2C( this.msgs.themeHelperLoad.msg ), ex.glob);
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case HMSTATUS.invalidSchemaVersion:
 | 
					 | 
				
			||||||
      msg = printf(M2C( this.msgs.invalidSchemaVersion.msg ), ex.data);
 | 
					 | 
				
			||||||
      etype = 'error';
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    msg,              // The error message to display
 | 
					 | 
				
			||||||
    withStack,  // Whether to include the stack
 | 
					 | 
				
			||||||
    quit,
 | 
					 | 
				
			||||||
    etype
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
@@ -1,25 +0,0 @@
 | 
				
			|||||||
**analyze** | Analyze a resume for statistical insight
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Usage:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **hackmyresume ANALYZE <resume>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The ANALYZE command evaluates the specified resume(s) for
 | 
					 | 
				
			||||||
   coverage, duration, gaps, keywords, and other metrics.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   This command can be run against multiple resumes. Each
 | 
					 | 
				
			||||||
   will be analyzed in turn.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Parameters:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **<resume>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Path to a FRESH or JRS resume. Multiple resumes can be
 | 
					 | 
				
			||||||
      specified, separated by spaces.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      hackmyresume ANALYZE resume.json
 | 
					 | 
				
			||||||
      hackmyresume ANALYZE r1.json r2.json r3.json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Options:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **None.**
 | 
					 | 
				
			||||||
@@ -1,69 +0,0 @@
 | 
				
			|||||||
**build** | Generate themed resumes in multiple formats
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Usage:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **hackmyresume BUILD <resume> TO <target> [--theme]**
 | 
					 | 
				
			||||||
      **[--pdf] [--no-escape] [--private]**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The BUILD command generates themed resumes and CVs in
 | 
					 | 
				
			||||||
   multiple formats. Use it to create outbound resumes in
 | 
					 | 
				
			||||||
   specific formats such HTML, MS Word, and PDF.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Parameters:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **<resume>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Path to a FRESH or JRS resume (*.json) containing your
 | 
					 | 
				
			||||||
      resume data. Multiple resumes may be specified.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      If multiple resumes are specified, they will be merged
 | 
					 | 
				
			||||||
      into a single resume prior to transformation.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **<target>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Path to the desired output resume. Multiple resumes
 | 
					 | 
				
			||||||
      may be specified. The file extension will determine
 | 
					 | 
				
			||||||
      the format.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
         .all        Generate all supported formats
 | 
					 | 
				
			||||||
         .html       HTML 5
 | 
					 | 
				
			||||||
         .doc        MS Word
 | 
					 | 
				
			||||||
         .pdf        Adobe Acrobat PDF
 | 
					 | 
				
			||||||
         .txt        plain text
 | 
					 | 
				
			||||||
         .md         Markdown
 | 
					 | 
				
			||||||
         .png        PNG Image
 | 
					 | 
				
			||||||
         .latex      LaTeX
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Note: not all formats are supported by all themes!
 | 
					 | 
				
			||||||
      Check the theme's documentation for details or use
 | 
					 | 
				
			||||||
      the .all extension to build all available formats.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Options:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **--theme -t <theme-name-or-path>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Path to a FRESH or JSON Resume theme OR the name of a
 | 
					 | 
				
			||||||
      built-in theme. Valid theme names are 'modern',
 | 
					 | 
				
			||||||
      'positive', 'compact', 'awesome', and 'basis'.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **--pdf -p <engine>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Specify the PDF engine to use. Legal values are
 | 
					 | 
				
			||||||
      'none', 'wkhtmltopdf', 'phantom', or 'weasyprint'.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **--no-escape**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Disable escaping / encoding of resume data during
 | 
					 | 
				
			||||||
      resume generation. Handlebars themes only.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **--private**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Include resume fields marked as private.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Notes:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The BUILD command can be run against multiple source as well
 | 
					 | 
				
			||||||
as multiple target resumes. If multiple source resumes are
 | 
					 | 
				
			||||||
provided, they will be merged into a single source resume
 | 
					 | 
				
			||||||
before generation. If multiple output resumes are provided,
 | 
					 | 
				
			||||||
each will be generated in turn.
 | 
					 | 
				
			||||||
@@ -1,33 +0,0 @@
 | 
				
			|||||||
**convert** | Convert resumes between FRESH and JRS formats
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Usage:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **hackmyresume CONVERT <resume> TO <target> [--format]**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The CONVERT command converts one or more resume documents
 | 
					 | 
				
			||||||
   between the FRESH Resume Schema and JSON Resume formats.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Parameters:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **<resume>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Path to a FRESH or JRS resume. Multiple resumes can be
 | 
					 | 
				
			||||||
      specified.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **<targets>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      The path of the converted resume. Multiple resumes can
 | 
					 | 
				
			||||||
      be specified, one per provided input resume.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Options:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **--format -f <fmt>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      The desired format for the new resume(s). Valid values
 | 
					 | 
				
			||||||
      are 'FRESH', 'JRS', or, to target the latest edge
 | 
					 | 
				
			||||||
      version of the JSON Resume Schema, 'JRS@1'.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      If this parameter is omitted, the destination format
 | 
					 | 
				
			||||||
      will be inferred from the source resume's format. If
 | 
					 | 
				
			||||||
      the source format is FRESH, the destination format
 | 
					 | 
				
			||||||
      will be JSON Resume, and vice-versa.
 | 
					 | 
				
			||||||
@@ -1,23 +0,0 @@
 | 
				
			|||||||
**help** | View help on a specific HackMyResume command
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Usage:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **hackmyresume HELP [<command>]**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The HELP command displays help information for a specific
 | 
					 | 
				
			||||||
   HackMyResume command, including the HELP command itself.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Parameters:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **<command>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      The HackMyResume command to view help information for.
 | 
					 | 
				
			||||||
      Must be BUILD, NEW, CONVERT, ANALYZE, VALIDATE, PEEK,
 | 
					 | 
				
			||||||
      or HELP.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
         hackmyresume help convert
 | 
					 | 
				
			||||||
         hackmyresume help help
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Options:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **None.**
 | 
					 | 
				
			||||||
@@ -1,29 +0,0 @@
 | 
				
			|||||||
**new** | Create a new FRESH or JRS resume document
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Usage:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **hackmyresume NEW <fileName> [--format]**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The NEW command generates a new resume document in FRESH
 | 
					 | 
				
			||||||
   or JSON Resume format. This document can serve as an
 | 
					 | 
				
			||||||
   official source of truth for your resume and career data
 | 
					 | 
				
			||||||
   as well an input to tools like HackMyResume.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Parameters:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **<fileName>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      The filename (relative or absolute path) of the resume
 | 
					 | 
				
			||||||
      to be created. Multiple resume paths can be specified,
 | 
					 | 
				
			||||||
      and each will be created in turn.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
         hackmyresume NEW resume.json
 | 
					 | 
				
			||||||
         hackmyresume NEW r1.json foo/r2.json ../r3.json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Options:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **--format -f <fmt>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      The desired format for the new resume(s). Valid values
 | 
					 | 
				
			||||||
      are 'FRESH', 'JRS', or, to target the latest edge
 | 
					 | 
				
			||||||
      version of the JSON Resume Schema, 'JRS@1'.
 | 
					 | 
				
			||||||
@@ -1,31 +0,0 @@
 | 
				
			|||||||
**peek** | View portions of a resume from the command line
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Usage:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **hackmyresume PEEK <resume> <at>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The PEEK command displays a specific piece or part of the
 | 
					 | 
				
			||||||
   resume without requiring the resume to be opened in an
 | 
					 | 
				
			||||||
   editor.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Parameters:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **<resume>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
     Path to a FRESH or JRS resume. Multiple resumes can be
 | 
					 | 
				
			||||||
     specified, separated by spaces.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
         hackmyresume PEEK r1.json r2.json r3.json "employment.history[2]"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **<at>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      The resume property or field to be displayed. Can be
 | 
					 | 
				
			||||||
      any valid resume path, for example:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
         education[0]
 | 
					 | 
				
			||||||
         info.name
 | 
					 | 
				
			||||||
         employment.history[3].start
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Options:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **None.**
 | 
					 | 
				
			||||||
@@ -1,70 +0,0 @@
 | 
				
			|||||||
**HackMyResume** | A Swiss Army knife for resumes and CVs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Usage:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **hackmyresume [--version] [--help] [--silent] [--debug]**
 | 
					 | 
				
			||||||
      **[--options] [--no-colors] <command> [<args>]**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Commands: (type "hackmyresume help COMMAND" for details)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **BUILD**         Build your resume to the destination format(s).
 | 
					 | 
				
			||||||
   **ANALYZE**       Analyze your resume for keywords, gaps, and metrics.
 | 
					 | 
				
			||||||
   **VALIDATE**      Validate your resume for errors and typos.
 | 
					 | 
				
			||||||
   **NEW**           Create a new resume in FRESH or JSON Resume format.
 | 
					 | 
				
			||||||
   **CONVERT**       Convert your resume between FRESH and JSON Resume.
 | 
					 | 
				
			||||||
   **PEEK**          View a specific field or element on your resume.
 | 
					 | 
				
			||||||
   **HELP**          View help on a specific HackMyResume command.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Common Tasks:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Generate a resume in a specific format (HTML, Word, PDF, etc.)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      **hackmyresume build rez.json to out/rez.html**
 | 
					 | 
				
			||||||
      **hackmyresume build rez.json to out/rez.doc**
 | 
					 | 
				
			||||||
      **hackmyresume build rez.json to out/rez.pdf**
 | 
					 | 
				
			||||||
      **hackmyresume build rez.json to out/rez.txt**
 | 
					 | 
				
			||||||
      **hackmyresume build rez.json to out/rez.md**
 | 
					 | 
				
			||||||
      **hackmyresume build rez.json to out/rez.png**
 | 
					 | 
				
			||||||
      **hackmyresume build rez.json to out/rez.tex**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Build a resume to ALL available formats:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      **hackmyresume build rez.json to out/rez.all**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Build a resume with a specific theme:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      **hackmyresume build rez.json to out/rez.all -t themeName**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Create a new empty resume:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      **hackmyresume new rez.json**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Convert a resume between FRESH and JRS formats:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      **hackmyresume convert rez.json converted.json**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Analyze a resume for important metrics
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      **hackmyresume analyze rez.json**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Find more resume themes:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      **https://www.npmjs.com/search?q=jsonresume-theme**
 | 
					 | 
				
			||||||
      **https://www.npmjs.com/search?q=fresh-theme**
 | 
					 | 
				
			||||||
      **https://github.com/fresh-standard/fresh-themes**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Validate a resume's structure and syntax:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      **hackmyresume validate resume.json**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   View help on a specific command:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      **hackmyresume help [build|convert|new|analyze|validate|peek|help]**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   Submit a bug or request:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      **https://githut.com/hacksalot/HackMyResume/issues**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
HackMyResume is free and open source software published
 | 
					 | 
				
			||||||
under the MIT license. For more information, visit the
 | 
					 | 
				
			||||||
HackMyResume website or GitHub project page.
 | 
					 | 
				
			||||||
@@ -1,26 +0,0 @@
 | 
				
			|||||||
**validate** | Validate a resume for correctness
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Usage:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **hackmyresume VALIDATE <resume> [--assert]**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   The VALIDATE command validates a FRESH or JRS document
 | 
					 | 
				
			||||||
   against its governing schema, verifying that the resume
 | 
					 | 
				
			||||||
   is correctly structured and formatted.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Parameters:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **<resume>**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Path to a FRESH or JRS resume. Multiple resumes can be
 | 
					 | 
				
			||||||
      specified.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
         hackmyresume ANALYZE resume.json
 | 
					 | 
				
			||||||
         hackmyresume ANALYZE r1.json r2.json r3.json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Options:
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
   **--assert -a**
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      Tell HackMyResume to return a non-zero process exit
 | 
					 | 
				
			||||||
      code if a resume fails to validate.
 | 
					 | 
				
			||||||
							
								
								
									
										349
									
								
								src/cli/main.coffee
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										349
									
								
								src/cli/main.coffee
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,349 @@
 | 
				
			|||||||
 | 
					###*
 | 
				
			||||||
 | 
					Definition of the `main` function.
 | 
				
			||||||
 | 
					@module cli/main
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					###
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					HMR = require '../index'
 | 
				
			||||||
 | 
					PKG = require '../../package.json'
 | 
				
			||||||
 | 
					FS = require 'fs'
 | 
				
			||||||
 | 
					EXTEND = require 'extend'
 | 
				
			||||||
 | 
					chalk = require 'chalk'
 | 
				
			||||||
 | 
					PATH = require 'path'
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###
 | 
				
			||||||
 | 
					A callable implementation of the HackMyResume CLI. Encapsulates the command
 | 
				
			||||||
 | 
					line interface as a single method accepting a parameter array.
 | 
				
			||||||
 | 
					@alias module:cli/main.main
 | 
				
			||||||
 | 
					@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, exitCallback ) ->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  initInfo = initialize( rawArgs, exitCallback )
 | 
				
			||||||
 | 
					  args = initInfo.args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Create the top-level (application) command...
 | 
				
			||||||
 | 
					  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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Create the NEW command
 | 
				
			||||||
 | 
					  program
 | 
				
			||||||
 | 
					    .command 'new'
 | 
				
			||||||
 | 
					    .arguments '<sources...>'
 | 
				
			||||||
 | 
					    .option '-f --format <fmt>', 'FRESH or JRS format', 'FRESH'
 | 
				
			||||||
 | 
					    .alias 'create'
 | 
				
			||||||
 | 
					    .description 'Create resume(s) in FRESH or JSON RESUME format.'
 | 
				
			||||||
 | 
					    .action (( sources ) ->
 | 
				
			||||||
 | 
					      execute.call( this, sources, [], this.opts(), logMsg)
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Create the VALIDATE command
 | 
				
			||||||
 | 
					  program
 | 
				
			||||||
 | 
					    .command('validate')
 | 
				
			||||||
 | 
					    .arguments('<sources...>')
 | 
				
			||||||
 | 
					    .description('Validate a resume in FRESH or JSON RESUME format.')
 | 
				
			||||||
 | 
					    .action((sources) ->
 | 
				
			||||||
 | 
					      execute.call( this, sources, [], this.opts(), logMsg)
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Create the CONVERT command
 | 
				
			||||||
 | 
					  program
 | 
				
			||||||
 | 
					    .command('convert')
 | 
				
			||||||
 | 
					    .description('Convert a resume to/from FRESH or JSON RESUME format.')
 | 
				
			||||||
 | 
					    .action(->
 | 
				
			||||||
 | 
					      x = splitSrcDest.call( this );
 | 
				
			||||||
 | 
					      execute.call( this, x.src, x.dst, this.opts(), logMsg)
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Create the ANALYZE command
 | 
				
			||||||
 | 
					  program
 | 
				
			||||||
 | 
					    .command('analyze')
 | 
				
			||||||
 | 
					    .arguments('<sources...>')
 | 
				
			||||||
 | 
					    .description('Analyze one or more resumes.')
 | 
				
			||||||
 | 
					    .action(( sources ) ->
 | 
				
			||||||
 | 
					      execute.call( this, sources, [], this.opts(), logMsg)
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Create the PEEK command
 | 
				
			||||||
 | 
					  program
 | 
				
			||||||
 | 
					    .command('peek')
 | 
				
			||||||
 | 
					    .arguments('<sources...>')
 | 
				
			||||||
 | 
					    .description('Peek at a resume field or section')
 | 
				
			||||||
 | 
					    .action(( sources, sectionOrField ) ->
 | 
				
			||||||
 | 
					      dst = if (sources && sources.length > 1) then [sources.pop()] else []
 | 
				
			||||||
 | 
					      execute.call( this, sources, dst, this.opts(), logMsg)
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Create the BUILD command
 | 
				
			||||||
 | 
					  program
 | 
				
			||||||
 | 
					    .command('build')
 | 
				
			||||||
 | 
					    .alias('generate')
 | 
				
			||||||
 | 
					    .option('-t --theme <theme>', 'Theme name or path')
 | 
				
			||||||
 | 
					    .option('-n --no-prettify', 'Disable HTML prettification', true)
 | 
				
			||||||
 | 
					    .option('-c --css <option>', 'CSS linking / embedding')
 | 
				
			||||||
 | 
					    .option('-p --pdf <engine>', 'PDF generation engine')
 | 
				
			||||||
 | 
					    .option('--no-sort', 'Sort resume sections by date', false)
 | 
				
			||||||
 | 
					    .option('--tips', 'Display theme tips and warnings.', false)
 | 
				
			||||||
 | 
					    .description('Generate resume to multiple formats')
 | 
				
			||||||
 | 
					    .action(( sources, targets, options ) ->
 | 
				
			||||||
 | 
					      x = splitSrcDest.call( this );
 | 
				
			||||||
 | 
					      execute.call( this, x.src, x.dst, this.opts(), logMsg)
 | 
				
			||||||
 | 
					      return
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  program.parse( args )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if !program.args.length
 | 
				
			||||||
 | 
					    throw fluenterror: 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Massage command-line args and setup Commander.js. ###
 | 
				
			||||||
 | 
					initialize = ( ar, exitCallback ) ->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  _exitCallback = exitCallback || process.exit
 | 
				
			||||||
 | 
					  o = initOptions ar
 | 
				
			||||||
 | 
					  o.silent || logMsg( _title )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Emit debug prelude if --debug was specified
 | 
				
			||||||
 | 
					  if o.debug
 | 
				
			||||||
 | 
					    _out.log(chalk.cyan('The -d or --debug switch was specified. DEBUG mode engaged.'))
 | 
				
			||||||
 | 
					    _out.log('')
 | 
				
			||||||
 | 
					    _out.log(chalk.cyan(PAD('  Platform:',25, null, PAD.RIGHT)) + chalk.cyan.bold( if process.platform == 'win32' then 'windows' else process.platform ))
 | 
				
			||||||
 | 
					    _out.log(chalk.cyan(PAD('  Node.js:',25, null, PAD.RIGHT)) + chalk.cyan.bold( process.version ))
 | 
				
			||||||
 | 
					    _out.log(chalk.cyan(PAD('  HackMyResume:',25, null, PAD.RIGHT)) + chalk.cyan.bold('v' + PKG.version ))
 | 
				
			||||||
 | 
					    _out.log(chalk.cyan(PAD('  FRESCA:',25, null, PAD.RIGHT)) + chalk.cyan.bold( PKG.dependencies.fresca ))
 | 
				
			||||||
 | 
					    #_out.log(chalk.cyan(PAD('  fresh-themes:',25, null, PAD.RIGHT)) + chalk.cyan.bold( PKG.dependencies['fresh-themes'] ))
 | 
				
			||||||
 | 
					    #_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 ]
 | 
				
			||||||
 | 
					    _err.err fluenterror: HMSTATUS.invalidCommand, quit: true, attempted: o.orgVerb, true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Override the .missingArgument behavior
 | 
				
			||||||
 | 
					  Command.prototype.missingArgument = (name) ->
 | 
				
			||||||
 | 
					    _err.err
 | 
				
			||||||
 | 
					      fluenterror:
 | 
				
			||||||
 | 
					        if this.name() != 'new'
 | 
				
			||||||
 | 
					        then HMSTATUS.resumeNotFound
 | 
				
			||||||
 | 
					        else HMSTATUS.createNameMissing
 | 
				
			||||||
 | 
					      , true
 | 
				
			||||||
 | 
					    return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Override the .helpInformation behavior
 | 
				
			||||||
 | 
					  Command.prototype.helpInformation = ->
 | 
				
			||||||
 | 
					    manPage = FS.readFileSync(
 | 
				
			||||||
 | 
					      PATH.join(__dirname, 'use.txt'), 'utf8' )
 | 
				
			||||||
 | 
					    return chalk.green.bold(manPage)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    args: o.args,
 | 
				
			||||||
 | 
					    options: o.json
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Init options prior to setting up command infrastructure. ###
 | 
				
			||||||
 | 
					initOptions = ( ar ) ->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  oVerb
 | 
				
			||||||
 | 
					  verb = ''
 | 
				
			||||||
 | 
					  args = ar.slice()
 | 
				
			||||||
 | 
					  cleanArgs = args.slice( 2 )
 | 
				
			||||||
 | 
					  oJSON
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if cleanArgs.length
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Support case-insensitive sub-commands (build, generate, validate, etc)
 | 
				
			||||||
 | 
					    vidx = _.findIndex cleanArgs, (v) -> v[0] != '-'
 | 
				
			||||||
 | 
					    if vidx != -1
 | 
				
			||||||
 | 
					      oVerb = cleanArgs[ vidx ]
 | 
				
			||||||
 | 
					      verb = args[ vidx + 2 ] = oVerb.trim().toLowerCase()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Remove --options --opts -o and process separately
 | 
				
			||||||
 | 
					    optsIdx = _.findIndex cleanArgs, (v) ->
 | 
				
			||||||
 | 
					      v == '-o' || v == '--options' || v == '--opts'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if optsIdx != -1
 | 
				
			||||||
 | 
					      optStr = cleanArgs[ optsIdx + 1]
 | 
				
			||||||
 | 
					      args.splice( optsIdx + 2, 2 )
 | 
				
			||||||
 | 
					      if optStr && (optStr = optStr.trim())
 | 
				
			||||||
 | 
					        #var myJSON = JSON.parse(optStr);
 | 
				
			||||||
 | 
					        if( optStr[0] == '{')
 | 
				
			||||||
 | 
					          ### jshint ignore:start ###
 | 
				
			||||||
 | 
					          oJSON = eval('(' + optStr + ')') # jshint ignore:line <-- no worky
 | 
				
			||||||
 | 
					          ### jshint ignore:end ###
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          inf = safeLoadJSON( optStr )
 | 
				
			||||||
 | 
					          if( !inf.ex )
 | 
				
			||||||
 | 
					            oJSON = inf.json
 | 
				
			||||||
 | 
					          # TODO: Error handling
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # 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,
 | 
				
			||||||
 | 
					    args: args
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 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 )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Set up error/output handling
 | 
				
			||||||
 | 
					  _opts.errHandler = v
 | 
				
			||||||
 | 
					  _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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###
 | 
				
			||||||
 | 
					Initialize HackMyResume options.
 | 
				
			||||||
 | 
					TODO: Options loading is a little hacky, for two reasons:
 | 
				
			||||||
 | 
					  - Commander.js idiosyncracies
 | 
				
			||||||
 | 
					  - Need to accept JSON inputs from the command line.
 | 
				
			||||||
 | 
					###
 | 
				
			||||||
 | 
					loadOptions = ( o, cmdO ) ->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # o and this.opts() seem to be the same (command-specific options)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Load the specified options file (if any) and apply options
 | 
				
			||||||
 | 
					  if( cmdO )
 | 
				
			||||||
 | 
					    o = EXTEND(true, o, cmdO)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Merge in command-line options
 | 
				
			||||||
 | 
					  o = EXTEND( true, o, this.opts() )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Kludge parent-level options until piping issue is resolved
 | 
				
			||||||
 | 
					  if this.parent.silent != undefined && this.parent.silent != null
 | 
				
			||||||
 | 
					    o.silent = this.parent.silent
 | 
				
			||||||
 | 
					  if this.parent.debug != undefined && this.parent.debug != null
 | 
				
			||||||
 | 
					    o.debug = this.parent.debug
 | 
				
			||||||
 | 
					  if this.parent.assert != undefined && this.parent.assert != null
 | 
				
			||||||
 | 
					    o.assert = this.parent.assert
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if o.debug
 | 
				
			||||||
 | 
					    logMsg(chalk.cyan('OPTIONS:') + '\n')
 | 
				
			||||||
 | 
					    _.each(o, (val, key) ->
 | 
				
			||||||
 | 
					      logMsg(chalk.cyan('  %s') + chalk.cyan.bold(' %s'),
 | 
				
			||||||
 | 
					        PAD(key,22,null,PAD.RIGHT), val)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    logMsg('');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Cache
 | 
				
			||||||
 | 
					  EXTEND( true, _opts, o )
 | 
				
			||||||
 | 
					  return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Split multiple command-line filenames by the 'TO' keyword ###
 | 
				
			||||||
 | 
					splitSrcDest = () ->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  params = this.parent.args.filter((j) -> return String.is(j) )
 | 
				
			||||||
 | 
					  if params.length == 0
 | 
				
			||||||
 | 
					    throw { fluenterror: HMSTATUS.resumeNotFound, quit: true }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Find the TO keyword, if any
 | 
				
			||||||
 | 
					  splitAt = _.findIndex( params, (p) -> return p.toLowerCase() == 'to'; )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # TO can't be the last keyword
 | 
				
			||||||
 | 
					  if splitAt == params.length - 1 && splitAt != -1
 | 
				
			||||||
 | 
					    logMsg(chalk.yellow('Please ') +
 | 
				
			||||||
 | 
					      chalk.yellow.bold('specify an output file') +
 | 
				
			||||||
 | 
					      chalk.yellow(' for this operation or ') +
 | 
				
			||||||
 | 
					      chalk.yellow.bold('omit the TO keyword') +
 | 
				
			||||||
 | 
					      chalk.yellow('.') )
 | 
				
			||||||
 | 
					    return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    src: params.slice(0, if splitAt == -1 then undefined else splitAt ),
 | 
				
			||||||
 | 
					    dst: if splitAt == -1 then [] else params.slice( splitAt + 1 )
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Simple logging placeholder. ###
 | 
				
			||||||
 | 
					logMsg = () ->
 | 
				
			||||||
 | 
					  _opts.silent || console.log.apply( console.log, arguments )
 | 
				
			||||||
							
								
								
									
										421
									
								
								src/cli/main.js
									
									
									
									
									
								
							
							
						
						
									
										421
									
								
								src/cli/main.js
									
									
									
									
									
								
							@@ -1,421 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * decaffeinate suggestions:
 | 
					 | 
				
			||||||
 * DS102: Remove unnecessary code created because of implicit returns
 | 
					 | 
				
			||||||
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
Definition of the `main` function.
 | 
					 | 
				
			||||||
@module cli/main
 | 
					 | 
				
			||||||
@license MIT. See LICENSE.md for details.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const HMR = require('../index');
 | 
					 | 
				
			||||||
const PKG = require('../../package.json');
 | 
					 | 
				
			||||||
const FS = require('fs');
 | 
					 | 
				
			||||||
const EXTEND = require('extend');
 | 
					 | 
				
			||||||
const chalk = require('chalk');
 | 
					 | 
				
			||||||
const PATH = require('path');
 | 
					 | 
				
			||||||
const HMSTATUS = require('../core/status-codes');
 | 
					 | 
				
			||||||
const safeLoadJSON = require('../utils/safe-json-loader');
 | 
					 | 
				
			||||||
//StringUtils = require '../utils/string.js'
 | 
					 | 
				
			||||||
const _ = require('underscore');
 | 
					 | 
				
			||||||
const OUTPUT = require('./out');
 | 
					 | 
				
			||||||
const PAD = require('string-padding');
 | 
					 | 
				
			||||||
const { Command } = require('commander');
 | 
					 | 
				
			||||||
const M2C = require('../utils/md2chalk');
 | 
					 | 
				
			||||||
const printf = require('printf');
 | 
					 | 
				
			||||||
const _opts = { };
 | 
					 | 
				
			||||||
const _title = chalk.white.bold(`\n*** HackMyResume v${PKG.version} ***`);
 | 
					 | 
				
			||||||
const _out = new OUTPUT( _opts );
 | 
					 | 
				
			||||||
const _err = require('./error');
 | 
					 | 
				
			||||||
let _exitCallback = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
A callable implementation of the HackMyResume CLI. Encapsulates the command
 | 
					 | 
				
			||||||
line interface as a single method accepting a parameter array.
 | 
					 | 
				
			||||||
@alias module:cli/main.main
 | 
					 | 
				
			||||||
@param rawArgs {Array} An array of command-line parameters. Will either be
 | 
					 | 
				
			||||||
process.argv (in production) or custom parameters (in test).
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
module.exports = function( rawArgs, exitCallback ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const initInfo = initialize( rawArgs, exitCallback );
 | 
					 | 
				
			||||||
  if (initInfo === null) {
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const { args } = initInfo;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create the top-level (application) command...
 | 
					 | 
				
			||||||
  const 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;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create the NEW command
 | 
					 | 
				
			||||||
  program
 | 
					 | 
				
			||||||
    .command('new')
 | 
					 | 
				
			||||||
    .arguments('<sources...>')
 | 
					 | 
				
			||||||
    .option('-f --format <fmt>', 'FRESH or JRS format', 'FRESH')
 | 
					 | 
				
			||||||
    .alias('create')
 | 
					 | 
				
			||||||
    .description('Create resume(s) in FRESH or JSON RESUME format.')
 | 
					 | 
				
			||||||
    .action((function( sources ) {
 | 
					 | 
				
			||||||
      execute.call( this, sources, [], this.opts(), logMsg);
 | 
					 | 
				
			||||||
    })
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create the VALIDATE command
 | 
					 | 
				
			||||||
  program
 | 
					 | 
				
			||||||
    .command('validate')
 | 
					 | 
				
			||||||
    .arguments('<sources...>')
 | 
					 | 
				
			||||||
    .description('Validate a resume in FRESH or JSON RESUME format.')
 | 
					 | 
				
			||||||
    .action(function(sources) {
 | 
					 | 
				
			||||||
      execute.call( this, sources, [], this.opts(), logMsg);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create the CONVERT command
 | 
					 | 
				
			||||||
  program
 | 
					 | 
				
			||||||
    .command('convert')
 | 
					 | 
				
			||||||
    .description('Convert a resume to/from FRESH or JSON RESUME format.')
 | 
					 | 
				
			||||||
    .option('-f --format <fmt>', 'FRESH or JRS format and optional version', undefined)
 | 
					 | 
				
			||||||
    .action(function() {
 | 
					 | 
				
			||||||
      const x = splitSrcDest.call( this );
 | 
					 | 
				
			||||||
      execute.call( this, x.src, x.dst, this.opts(), logMsg);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create the ANALYZE command
 | 
					 | 
				
			||||||
  program
 | 
					 | 
				
			||||||
    .command('analyze')
 | 
					 | 
				
			||||||
    .arguments('<sources...>')
 | 
					 | 
				
			||||||
    .option('--private', 'Include resume fields marked as private', false)
 | 
					 | 
				
			||||||
    .description('Analyze one or more resumes.')
 | 
					 | 
				
			||||||
    .action(function( sources ) {
 | 
					 | 
				
			||||||
      execute.call( this, sources, [], this.opts(), logMsg);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create the PEEK command
 | 
					 | 
				
			||||||
  program
 | 
					 | 
				
			||||||
    .command('peek')
 | 
					 | 
				
			||||||
    .arguments('<sources...>')
 | 
					 | 
				
			||||||
    .description('Peek at a resume field or section')
 | 
					 | 
				
			||||||
    //.action(( sources, sectionOrField ) ->
 | 
					 | 
				
			||||||
    .action(function( sources ) {
 | 
					 | 
				
			||||||
      const dst = (sources && (sources.length > 1)) ? [sources.pop()] : [];
 | 
					 | 
				
			||||||
      execute.call( this, sources, dst, this.opts(), logMsg);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create the BUILD command
 | 
					 | 
				
			||||||
  program
 | 
					 | 
				
			||||||
    .command('build')
 | 
					 | 
				
			||||||
    .alias('generate')
 | 
					 | 
				
			||||||
    .option('-t --theme <theme>', 'Theme name or path')
 | 
					 | 
				
			||||||
    .option('-n --no-prettify', 'Disable HTML prettification', true)
 | 
					 | 
				
			||||||
    .option('-c --css <option>', 'CSS linking / embedding')
 | 
					 | 
				
			||||||
    .option('-p --pdf <engine>', 'PDF generation engine')
 | 
					 | 
				
			||||||
    .option('--no-sort', 'Sort resume sections by date', false)
 | 
					 | 
				
			||||||
    .option('--tips', 'Display theme tips and warnings.', false)
 | 
					 | 
				
			||||||
    .option('--private', 'Include resume fields marked as private', false)
 | 
					 | 
				
			||||||
    .option('--no-escape', 'Turn off encoding in Handlebars themes.', false)
 | 
					 | 
				
			||||||
    .description('Generate resume to multiple formats')
 | 
					 | 
				
			||||||
    //.action(( sources, targets, options ) ->
 | 
					 | 
				
			||||||
    .action(function() {
 | 
					 | 
				
			||||||
      const x = splitSrcDest.call( this );
 | 
					 | 
				
			||||||
      execute.call( this, x.src, x.dst, this.opts(), logMsg);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create the HELP command
 | 
					 | 
				
			||||||
  program
 | 
					 | 
				
			||||||
    .command('help')
 | 
					 | 
				
			||||||
    .arguments('[command]')
 | 
					 | 
				
			||||||
    .description('Get help on a HackMyResume command')
 | 
					 | 
				
			||||||
    .action(function( cmd ) {
 | 
					 | 
				
			||||||
      cmd = cmd || 'use';
 | 
					 | 
				
			||||||
      const manPage = FS.readFileSync(
 | 
					 | 
				
			||||||
        PATH.join(__dirname, `help/${cmd}.txt`),
 | 
					 | 
				
			||||||
        'utf8');
 | 
					 | 
				
			||||||
      _out.log(M2C(manPage, 'white', 'yellow.bold'));
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  program.parse( args );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!program.args.length) {
 | 
					 | 
				
			||||||
    throw {fluenterror: 4};
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Massage command-line args and setup Commander.js. */
 | 
					 | 
				
			||||||
var initialize = function( ar, exitCallback ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  _exitCallback = exitCallback || process.exit;
 | 
					 | 
				
			||||||
  const o = initOptions(ar);
 | 
					 | 
				
			||||||
  if (o.ex) {
 | 
					 | 
				
			||||||
    _err.init(false, true, false);
 | 
					 | 
				
			||||||
    if( o.ex.op === 'parse' ) {
 | 
					 | 
				
			||||||
      _err.err({
 | 
					 | 
				
			||||||
        fluenterror: o.ex.op === 'parse' ? HMSTATUS.invalidOptionsFile : HMSTATUS.optionsFileNotFound,
 | 
					 | 
				
			||||||
        inner: o.ex.inner,
 | 
					 | 
				
			||||||
        quit: true
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      _err.err({fluenterror: HMSTATUS.optionsFileNotFound, inner: o.ex.inner, quit: true});
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return null;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  o.silent || logMsg( _title );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Emit debug prelude if --debug was specified
 | 
					 | 
				
			||||||
  if (o.debug) {
 | 
					 | 
				
			||||||
    _out.log(chalk.cyan('The -d or --debug switch was specified. DEBUG mode engaged.'));
 | 
					 | 
				
			||||||
    _out.log('');
 | 
					 | 
				
			||||||
    _out.log(chalk.cyan(PAD('  Platform:',25, null, PAD.RIGHT)) + chalk.cyan.bold( process.platform === 'win32' ? 'windows' : process.platform ));
 | 
					 | 
				
			||||||
    _out.log(chalk.cyan(PAD('  Node.js:',25, null, PAD.RIGHT)) + chalk.cyan.bold( process.version ));
 | 
					 | 
				
			||||||
    _out.log(chalk.cyan(PAD('  HackMyResume:',25, null, PAD.RIGHT)) + chalk.cyan.bold(`v${PKG.version}` ));
 | 
					 | 
				
			||||||
    _out.log(chalk.cyan(PAD('  FRESCA:',25, null, PAD.RIGHT)) + chalk.cyan.bold( PKG.dependencies.fresca ));
 | 
					 | 
				
			||||||
    //_out.log(chalk.cyan(PAD('  fresh-themes:',25, null, PAD.RIGHT)) + chalk.cyan.bold( PKG.dependencies['fresh-themes'] ))
 | 
					 | 
				
			||||||
    //_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 ] && (o.verb !== 'help')) {
 | 
					 | 
				
			||||||
    _err.err({fluenterror: HMSTATUS.invalidCommand, quit: true, attempted: o.orgVerb}, true);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Override the .missingArgument behavior
 | 
					 | 
				
			||||||
  Command.prototype.missingArgument = function() {
 | 
					 | 
				
			||||||
    if (this.name() !== 'help') {
 | 
					 | 
				
			||||||
      _err.err({
 | 
					 | 
				
			||||||
        verb: this.name(),
 | 
					 | 
				
			||||||
        fluenterror: HMSTATUS.resumeNotFound
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
        , true);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Override the .helpInformation behavior
 | 
					 | 
				
			||||||
  Command.prototype.helpInformation = function() {
 | 
					 | 
				
			||||||
    const manPage = FS.readFileSync(
 | 
					 | 
				
			||||||
      PATH.join(__dirname, 'help/use.txt'), 'utf8' );
 | 
					 | 
				
			||||||
    return M2C(manPage, 'white', 'yellow');
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    args: o.args,
 | 
					 | 
				
			||||||
    options: o.json
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Init options prior to setting up command infrastructure. */
 | 
					 | 
				
			||||||
var initOptions = function( ar ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  let oJSON, oVerb;
 | 
					 | 
				
			||||||
  oVerb;
 | 
					 | 
				
			||||||
  let verb = '';
 | 
					 | 
				
			||||||
  const args = ar.slice();
 | 
					 | 
				
			||||||
  const cleanArgs = args.slice( 2 );
 | 
					 | 
				
			||||||
  oJSON;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (cleanArgs.length) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Support case-insensitive sub-commands (build, generate, validate, etc)
 | 
					 | 
				
			||||||
    const vidx = _.findIndex(cleanArgs, v => v[0] !== '-');
 | 
					 | 
				
			||||||
    if (vidx !== -1) {
 | 
					 | 
				
			||||||
      oVerb = cleanArgs[ vidx ];
 | 
					 | 
				
			||||||
      verb = (args[ vidx + 2 ] = oVerb.trim().toLowerCase());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Remove --options --opts -o and process separately
 | 
					 | 
				
			||||||
    const optsIdx = _.findIndex(cleanArgs, v => (v === '-o') || (v === '--options') || (v === '--opts'));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (optsIdx !== -1) {
 | 
					 | 
				
			||||||
      let optStr = cleanArgs[ optsIdx + 1];
 | 
					 | 
				
			||||||
      args.splice( optsIdx + 2, 2 );
 | 
					 | 
				
			||||||
      if (optStr && (optStr = optStr.trim())) {
 | 
					 | 
				
			||||||
        //var myJSON = JSON.parse(optStr);
 | 
					 | 
				
			||||||
        if( optStr[0] === '{') {
 | 
					 | 
				
			||||||
          // TODO: remove use of evil(). - hacksalot
 | 
					 | 
				
			||||||
          /* jshint ignore:start */
 | 
					 | 
				
			||||||
          oJSON = eval(`(${optStr})`); // jshint ignore:line <-- no worky
 | 
					 | 
				
			||||||
          /* jshint ignore:end */
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
          const inf = safeLoadJSON( optStr );
 | 
					 | 
				
			||||||
          if( !inf.ex ) {
 | 
					 | 
				
			||||||
            oJSON = inf.json;
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            return inf;
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Grab the --debug flag, --silent, --assert and --no-color flags
 | 
					 | 
				
			||||||
  const isDebug = _.some(args, v => (v === '-d') || (v === '--debug'));
 | 
					 | 
				
			||||||
  const isSilent = _.some(args, v => (v === '-s') || (v === '--silent'));
 | 
					 | 
				
			||||||
  const isAssert = _.some(args, v => (v === '-a') || (v === '--assert'));
 | 
					 | 
				
			||||||
  const isMono = _.some(args, v => v === '--no-color');
 | 
					 | 
				
			||||||
  const isNoEscape = _.some(args, v => v === '--no-escape');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    color: !isMono,
 | 
					 | 
				
			||||||
    debug: isDebug,
 | 
					 | 
				
			||||||
    silent: isSilent,
 | 
					 | 
				
			||||||
    assert: isAssert,
 | 
					 | 
				
			||||||
    noescape: isNoEscape,
 | 
					 | 
				
			||||||
    orgVerb: oVerb,
 | 
					 | 
				
			||||||
    verb,
 | 
					 | 
				
			||||||
    json: oJSON,
 | 
					 | 
				
			||||||
    args
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Invoke a HackMyResume verb. */
 | 
					 | 
				
			||||||
var execute = function( src, dst, opts, log ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Create the verb
 | 
					 | 
				
			||||||
  const v = new (HMR.verbs[ this.name() ])();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Initialize command-specific options
 | 
					 | 
				
			||||||
  loadOptions.call(this, opts, this.parent.jsonArgs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Set up error/output handling
 | 
					 | 
				
			||||||
  _opts.errHandler = v;
 | 
					 | 
				
			||||||
  _out.init(_opts);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Hook up event notifications
 | 
					 | 
				
			||||||
  v.on('hmr:status', function() { return _out.do.apply(_out, arguments); });
 | 
					 | 
				
			||||||
  v.on('hmr:error', function() {  return _err.err.apply(_err, arguments); });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Invoke the verb using promise syntax
 | 
					 | 
				
			||||||
  const prom = v.invoke.call(v, src, dst, _opts, log);
 | 
					 | 
				
			||||||
  prom.then(executeSuccess, executeFail);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Success handler for verb invocations. Calls process.exit by default */
 | 
					 | 
				
			||||||
var executeSuccess = function() {};
 | 
					 | 
				
			||||||
  // 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 */
 | 
					 | 
				
			||||||
var executeFail = function(err) {
 | 
					 | 
				
			||||||
  //console.dir err
 | 
					 | 
				
			||||||
  let finalErrorCode = -1;
 | 
					 | 
				
			||||||
  if (err) {
 | 
					 | 
				
			||||||
    if (err.fluenterror) {
 | 
					 | 
				
			||||||
      finalErrorCode = err.fluenterror;
 | 
					 | 
				
			||||||
    } else if (err.length) {
 | 
					 | 
				
			||||||
      finalErrorCode = err[0].fluenterror;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      finalErrorCode = err;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (_opts.debug) {
 | 
					 | 
				
			||||||
    const msgs = require('./msg').errors;
 | 
					 | 
				
			||||||
    logMsg(printf(M2C( msgs.exiting.msg, 'cyan' ), finalErrorCode));
 | 
					 | 
				
			||||||
    if (err.stack) { logMsg(err.stack); }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  _exitCallback(finalErrorCode);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
Initialize HackMyResume options.
 | 
					 | 
				
			||||||
TODO: Options loading is a little hacky, for two reasons:
 | 
					 | 
				
			||||||
  - Commander.js idiosyncracies
 | 
					 | 
				
			||||||
  - Need to accept JSON inputs from the command line.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
var loadOptions = function( o, cmdO ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // o and this.opts() seem to be the same (command-specific options)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Load the specified options file (if any) and apply options
 | 
					 | 
				
			||||||
  if( cmdO ) {
 | 
					 | 
				
			||||||
    o = EXTEND(true, o, cmdO);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Merge in command-line options
 | 
					 | 
				
			||||||
  o = EXTEND( true, o, this.opts() );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Kludge parent-level options until piping issue is resolved
 | 
					 | 
				
			||||||
  if ((this.parent.silent !== undefined) && (this.parent.silent !== null)) {
 | 
					 | 
				
			||||||
    o.silent = this.parent.silent;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if ((this.parent.debug !== undefined) && (this.parent.debug !== null)) {
 | 
					 | 
				
			||||||
    o.debug = this.parent.debug;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if ((this.parent.assert !== undefined) && (this.parent.assert !== null)) {
 | 
					 | 
				
			||||||
    o.assert = this.parent.assert;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (o.debug) {
 | 
					 | 
				
			||||||
    logMsg(chalk.cyan('OPTIONS:') + '\n');
 | 
					 | 
				
			||||||
    _.each(o, (val, key) =>
 | 
					 | 
				
			||||||
      logMsg(chalk.cyan('  %s') + chalk.cyan.bold(' %s'),
 | 
					 | 
				
			||||||
        PAD(key,22,null,PAD.RIGHT), val)
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
    logMsg('');
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Cache
 | 
					 | 
				
			||||||
  EXTEND( true, _opts, o );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Split multiple command-line filenames by the 'TO' keyword */
 | 
					 | 
				
			||||||
var splitSrcDest = function() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const params = this.parent.args.filter(j => String.is(j));
 | 
					 | 
				
			||||||
  if (params.length === 0) {
 | 
					 | 
				
			||||||
    //tmpName = @name()
 | 
					 | 
				
			||||||
    throw { fluenterror: HMSTATUS.resumeNotFound, verb: this.name(), quit: true };
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Find the TO keyword, if any
 | 
					 | 
				
			||||||
  const splitAt = _.findIndex( params, p => p.toLowerCase() === 'to');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // TO can't be the last keyword
 | 
					 | 
				
			||||||
  if ((splitAt === (params.length - 1)) && (splitAt !== -1)) {
 | 
					 | 
				
			||||||
    logMsg(chalk.yellow('Please ') +
 | 
					 | 
				
			||||||
      chalk.yellow.bold('specify an output file') +
 | 
					 | 
				
			||||||
      chalk.yellow(' for this operation or ') +
 | 
					 | 
				
			||||||
      chalk.yellow.bold('omit the TO keyword') +
 | 
					 | 
				
			||||||
      chalk.yellow('.') );
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return {
 | 
					 | 
				
			||||||
    src: params.slice(0, splitAt === -1 ? undefined : splitAt ),
 | 
					 | 
				
			||||||
    dst: splitAt === -1 ? [] : params.slice( splitAt + 1 )
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Simple logging placeholder. */
 | 
					 | 
				
			||||||
var logMsg = function() {
 | 
					 | 
				
			||||||
  // eslint-disable-next-line no-console
 | 
					 | 
				
			||||||
  return _opts.silent || console.log.apply( console.log, arguments );
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
							
								
								
									
										10
									
								
								src/cli/msg.coffee
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/cli/msg.coffee
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					###*
 | 
				
			||||||
 | 
					Message-handling routines for HackMyResume.
 | 
				
			||||||
 | 
					@module cli/msg
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					###
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PATH = require 'path'
 | 
				
			||||||
 | 
					YAML = require 'yamljs'
 | 
				
			||||||
 | 
					module.exports = YAML.load PATH.join __dirname, 'msg.yml'
 | 
				
			||||||
@@ -1,10 +0,0 @@
 | 
				
			|||||||
/**
 | 
					 | 
				
			||||||
Message-handling routines for HackMyResume.
 | 
					 | 
				
			||||||
@module cli/msg
 | 
					 | 
				
			||||||
@license MIT. See LICENSE.md for details.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const PATH = require('path');
 | 
					 | 
				
			||||||
const YAML = require('yamljs');
 | 
					 | 
				
			||||||
module.exports = YAML.load(PATH.join(__dirname, 'msg.yml'));
 | 
					 | 
				
			||||||
@@ -109,33 +109,3 @@ errors:
 | 
				
			|||||||
    msg: Exiting with status code **%s**.
 | 
					    msg: Exiting with status code **%s**.
 | 
				
			||||||
  validateError:
 | 
					  validateError:
 | 
				
			||||||
    msg: "An error occurred during validation:\n%s"
 | 
					    msg: "An error occurred during validation:\n%s"
 | 
				
			||||||
  invalidOptionsFile:
 | 
					 | 
				
			||||||
    msg:
 | 
					 | 
				
			||||||
      - "The specified options file is invalid:\n"
 | 
					 | 
				
			||||||
      - "\nMake sure the options file contains valid JSON."
 | 
					 | 
				
			||||||
  optionsFileNotFound:
 | 
					 | 
				
			||||||
    msg: "The specified options file is missing or inaccessible."
 | 
					 | 
				
			||||||
  unknownSchema:
 | 
					 | 
				
			||||||
    msg:
 | 
					 | 
				
			||||||
      - "Unknown resume schema. Did you specify a valid FRESH or JRS resume?"
 | 
					 | 
				
			||||||
      - |
 | 
					 | 
				
			||||||
          At a minimum, a FRESH resume must include a "name" field and a "meta"
 | 
					 | 
				
			||||||
          property.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          "name": "John Doe",
 | 
					 | 
				
			||||||
          "meta": {
 | 
					 | 
				
			||||||
            "format": "FRESH@0.1.0"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          JRS-format resumes must include a "basics" section with a "name":
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          "basics": {
 | 
					 | 
				
			||||||
            "name": "John Doe"
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
  themeHelperLoad:
 | 
					 | 
				
			||||||
    msg: >-
 | 
					 | 
				
			||||||
      An error occurred while attempting to load the '%s' theme helper. Is the
 | 
					 | 
				
			||||||
      theme correctly installed?
 | 
					 | 
				
			||||||
    dummy: dontcare
 | 
					 | 
				
			||||||
  invalidSchemaVersion:
 | 
					 | 
				
			||||||
    msg: "'%s' is not recognized as a valid schema version."
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										182
									
								
								src/cli/out.coffee
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								src/cli/out.coffee
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,182 @@
 | 
				
			|||||||
 | 
					###*
 | 
				
			||||||
 | 
					Output routines for HackMyResume.
 | 
				
			||||||
 | 
					@license MIT. See LICENSE.md for details.
 | 
				
			||||||
 | 
					@module cli/out
 | 
				
			||||||
 | 
					###
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					chalk = require('chalk')
 | 
				
			||||||
 | 
					HME = require('../core/event-codes')
 | 
				
			||||||
 | 
					_ = require('underscore')
 | 
				
			||||||
 | 
					M2C = require('../utils/md2chalk.js')
 | 
				
			||||||
 | 
					PATH = require('path')
 | 
				
			||||||
 | 
					LO = require('lodash')
 | 
				
			||||||
 | 
					FS = require('fs')
 | 
				
			||||||
 | 
					EXTEND = require('extend')
 | 
				
			||||||
 | 
					HANDLEBARS = require('handlebars')
 | 
				
			||||||
 | 
					YAML = require('yamljs')
 | 
				
			||||||
 | 
					printf = require('printf')
 | 
				
			||||||
 | 
					pad = require('string-padding')
 | 
				
			||||||
 | 
					dbgStyle = 'cyan';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###* 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  log: ( msg ) ->
 | 
				
			||||||
 | 
					    msg = msg || ''
 | 
				
			||||||
 | 
					    printf = require('printf')
 | 
				
			||||||
 | 
					    finished = printf.apply( printf, arguments )
 | 
				
			||||||
 | 
					    @opts.silent || console.log( finished )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  do: ( evt ) ->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    that = @
 | 
				
			||||||
 | 
					    L = () -> that.log.apply( that, arguments )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch evt.sub
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.begin
 | 
				
			||||||
 | 
					        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 )
 | 
				
			||||||
 | 
					        #break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.afterCreate
 | 
				
			||||||
 | 
					        L( M2C( @msgs.beforeCreate.msg, if evt.isError then 'red' else 'green' ), evt.fmt, evt.file )
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.beforeTheme
 | 
				
			||||||
 | 
					        this.opts.debug &&
 | 
				
			||||||
 | 
					          L( M2C( this.msgs.beforeTheme.msg, dbgStyle), evt.theme.toUpperCase() )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.afterParse
 | 
				
			||||||
 | 
					        L( M2C( this.msgs.afterRead.msg, 'gray', 'white.dim'), evt.fmt.toUpperCase(), evt.file )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.beforeMerge
 | 
				
			||||||
 | 
					        msg = ''
 | 
				
			||||||
 | 
					        evt.f.reverse().forEach ( a, idx ) ->
 | 
				
			||||||
 | 
					          msg += printf( (if idx == 0 then @msgs.beforeMerge.msg[0] else @msgs.beforeMerge.msg[1]), a.file )
 | 
				
			||||||
 | 
					        , @
 | 
				
			||||||
 | 
					        L( M2C(msg, (if evt.mixed then 'yellow' else 'gray'), 'white.dim') )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.applyTheme
 | 
				
			||||||
 | 
					        @theme = evt.theme;
 | 
				
			||||||
 | 
					        numFormats = Object.keys( evt.theme.formats ).length;
 | 
				
			||||||
 | 
					        L( M2C(this.msgs.applyTheme.msg,
 | 
				
			||||||
 | 
					          if evt.status == 'error' then 'red' else 'gray',
 | 
				
			||||||
 | 
					          if evt.status == 'error' then 'bold' else 'white.dim'),
 | 
				
			||||||
 | 
					          evt.theme.name.toUpperCase(),
 | 
				
			||||||
 | 
					          numFormats, if numFormats == 1 then '' else 's' )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.end
 | 
				
			||||||
 | 
					        if evt.cmd == 'build'
 | 
				
			||||||
 | 
					          themeName = this.theme.name.toUpperCase()
 | 
				
			||||||
 | 
					          if this.opts.tips && (this.theme.message || this.theme.render)
 | 
				
			||||||
 | 
					            WRAP = require('word-wrap')
 | 
				
			||||||
 | 
					            if this.theme.message
 | 
				
			||||||
 | 
					              L( M2C( this.msgs.afterBuild.msg[0], 'cyan' ), themeName )
 | 
				
			||||||
 | 
					              L( M2C( this.theme.message, 'white' ))
 | 
				
			||||||
 | 
					            else if this.theme.render
 | 
				
			||||||
 | 
					              L( M2C( this.msgs.afterBuild.msg[0], 'cyan'), themeName)
 | 
				
			||||||
 | 
					              L( M2C( this.msgs.afterBuild.msg[1], 'white'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.afterGenerate
 | 
				
			||||||
 | 
					        suffix = ''
 | 
				
			||||||
 | 
					        if evt.fmt == 'pdf'
 | 
				
			||||||
 | 
					          if this.opts.pdf
 | 
				
			||||||
 | 
					            if this.opts.pdf != 'none'
 | 
				
			||||||
 | 
					              suffix = printf( M2C( this.msgs.afterGenerate.msg[0], if evt.error then 'red' else 'green' ), this.opts.pdf )
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					              L( M2C( this.msgs.afterGenerate.msg[1], 'gray' ), evt.fmt.toUpperCase(), evt.file )
 | 
				
			||||||
 | 
					              return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        L( M2C( this.msgs.afterGenerate.msg[2] + suffix, if evt.error then 'red' else 'green' ),
 | 
				
			||||||
 | 
					            pad( evt.fmt.toUpperCase(),4,null,pad.RIGHT ),
 | 
				
			||||||
 | 
					            PATH.relative( process.cwd(), evt.file ) );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.beforeAnalyze
 | 
				
			||||||
 | 
					        L( M2C( this.msgs.beforeAnalyze.msg, 'green' ), evt.fmt, evt.file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.afterAnalyze
 | 
				
			||||||
 | 
					        info = evt.info
 | 
				
			||||||
 | 
					        rawTpl = FS.readFileSync( PATH.join( __dirname, 'analyze.hbs' ), 'utf8')
 | 
				
			||||||
 | 
					        HANDLEBARS.registerHelper( require('../helpers/console-helpers') )
 | 
				
			||||||
 | 
					        template = HANDLEBARS.compile(rawTpl, { strict: false, assumeObjects: false })
 | 
				
			||||||
 | 
					        tot = 0
 | 
				
			||||||
 | 
					        info.keywords.forEach (g) -> tot += g.count
 | 
				
			||||||
 | 
					        info.keywords.totalKeywords = tot
 | 
				
			||||||
 | 
					        output = template( info )
 | 
				
			||||||
 | 
					        @log( chalk.cyan(output) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.beforeConvert
 | 
				
			||||||
 | 
					        L( M2C( this.msgs.beforeConvert.msg, 'green' ),
 | 
				
			||||||
 | 
					          evt.srcFile, evt.srcFmt, evt.dstFile, evt.dstFmt
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.afterInlineConvert
 | 
				
			||||||
 | 
					        L( M2C( this.msgs.afterInlineConvert.msg, 'gray', 'white.dim' ),
 | 
				
			||||||
 | 
					          evt.file, evt.fmt );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      when HME.afterValidate
 | 
				
			||||||
 | 
					        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.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 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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        else if evt.error
 | 
				
			||||||
 | 
					          L chalk.red( evt.error.inner.inner )
 | 
				
			||||||
							
								
								
									
										204
									
								
								src/cli/out.js
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								src/cli/out.js
									
									
									
									
									
								
							@@ -1,204 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * decaffeinate suggestions:
 | 
					 | 
				
			||||||
 * DS102: Remove unnecessary code created because of implicit returns
 | 
					 | 
				
			||||||
 * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
Output routines for HackMyResume.
 | 
					 | 
				
			||||||
@license MIT. See LICENSE.md for details.
 | 
					 | 
				
			||||||
@module cli/out
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const chalk = require('chalk');
 | 
					 | 
				
			||||||
const HME = require('../core/event-codes');
 | 
					 | 
				
			||||||
const _ = require('underscore');
 | 
					 | 
				
			||||||
const M2C = require('../utils/md2chalk.js');
 | 
					 | 
				
			||||||
const PATH = require('path');
 | 
					 | 
				
			||||||
const FS = require('fs');
 | 
					 | 
				
			||||||
const EXTEND = require('extend');
 | 
					 | 
				
			||||||
const HANDLEBARS = require('handlebars');
 | 
					 | 
				
			||||||
const YAML = require('yamljs');
 | 
					 | 
				
			||||||
let printf = require('printf');
 | 
					 | 
				
			||||||
const pad = require('string-padding');
 | 
					 | 
				
			||||||
const dbgStyle = 'cyan';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** A stateful output module. All HMR console output handled here. */
 | 
					 | 
				
			||||||
class OutputHandler {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  constructor( opts ) {
 | 
					 | 
				
			||||||
    this.init(opts);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  init(opts) {
 | 
					 | 
				
			||||||
    this.opts = EXTEND( true, this.opts || { }, opts );
 | 
					 | 
				
			||||||
    this.msgs = YAML.load(PATH.join( __dirname, 'msg.yml' )).events;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  log() {
 | 
					 | 
				
			||||||
    printf = require('printf');
 | 
					 | 
				
			||||||
    const finished = printf.apply( printf, arguments );
 | 
					 | 
				
			||||||
    return this.opts.silent || console.log( finished ); // eslint-disable-line no-console
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  do( evt ) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const that = this;
 | 
					 | 
				
			||||||
    const L = function() { return that.log.apply( that, arguments ); };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    switch (evt.sub) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.begin:
 | 
					 | 
				
			||||||
        return 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 )
 | 
					 | 
				
			||||||
        //break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      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() );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.afterParse:
 | 
					 | 
				
			||||||
        return L( M2C( this.msgs.afterRead.msg, 'gray', 'white.dim'), evt.fmt.toUpperCase(), evt.file );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.beforeMerge:
 | 
					 | 
				
			||||||
        var msg = '';
 | 
					 | 
				
			||||||
        evt.f.reverse().forEach(function( a, idx ) {
 | 
					 | 
				
			||||||
          return msg += printf( (idx === 0 ? this.msgs.beforeMerge.msg[0] : this.msgs.beforeMerge.msg[1]), a.file );
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        , this);
 | 
					 | 
				
			||||||
        return L( M2C(msg, (evt.mixed ? 'yellow' : 'gray'), 'white.dim') );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.applyTheme:
 | 
					 | 
				
			||||||
        this.theme = evt.theme;
 | 
					 | 
				
			||||||
        var numFormats = Object.keys( evt.theme.formats ).length;
 | 
					 | 
				
			||||||
        return L( M2C(this.msgs.applyTheme.msg,
 | 
					 | 
				
			||||||
          evt.status === 'error' ? 'red' : 'gray',
 | 
					 | 
				
			||||||
          evt.status === 'error' ? 'bold' : 'white.dim'),
 | 
					 | 
				
			||||||
          evt.theme.name.toUpperCase(),
 | 
					 | 
				
			||||||
          numFormats, numFormats === 1 ? '' : 's' );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.end:
 | 
					 | 
				
			||||||
        if (evt.cmd === 'build') {
 | 
					 | 
				
			||||||
          const themeName = this.theme.name.toUpperCase();
 | 
					 | 
				
			||||||
          if (this.opts.tips && (this.theme.message || this.theme.render)) {
 | 
					 | 
				
			||||||
            if (this.theme.message) {
 | 
					 | 
				
			||||||
              L( M2C( this.msgs.afterBuild.msg[0], 'cyan' ), themeName );
 | 
					 | 
				
			||||||
              return L( M2C( this.theme.message, 'white' ));
 | 
					 | 
				
			||||||
            } else if (this.theme.render) {
 | 
					 | 
				
			||||||
              L( M2C( this.msgs.afterBuild.msg[0], 'cyan'), themeName);
 | 
					 | 
				
			||||||
              return L( M2C( this.msgs.afterBuild.msg[1], 'white'));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.afterGenerate:
 | 
					 | 
				
			||||||
        var suffix = '';
 | 
					 | 
				
			||||||
        if (evt.fmt === 'pdf') {
 | 
					 | 
				
			||||||
          if (this.opts.pdf) {
 | 
					 | 
				
			||||||
            if (this.opts.pdf !== 'none') {
 | 
					 | 
				
			||||||
              suffix = printf( M2C( this.msgs.afterGenerate.msg[0], evt.error ? 'red' : 'green' ), this.opts.pdf );
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
              L( M2C( this.msgs.afterGenerate.msg[1], 'gray' ), evt.fmt.toUpperCase(), evt.file );
 | 
					 | 
				
			||||||
              return;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return L( M2C( this.msgs.afterGenerate.msg[2] + suffix, evt.error ? 'red' : 'green' ),
 | 
					 | 
				
			||||||
            pad( evt.fmt.toUpperCase(),4,null,pad.RIGHT ),
 | 
					 | 
				
			||||||
            PATH.relative( process.cwd(), evt.file ) );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.beforeAnalyze:
 | 
					 | 
				
			||||||
        return L( M2C( this.msgs.beforeAnalyze.msg, 'green' ), evt.fmt, evt.file);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.afterAnalyze:
 | 
					 | 
				
			||||||
        var { info } = evt;
 | 
					 | 
				
			||||||
        var rawTpl = FS.readFileSync( PATH.join( __dirname, 'analyze.hbs' ), 'utf8');
 | 
					 | 
				
			||||||
        HANDLEBARS.registerHelper( require('../helpers/console-helpers') );
 | 
					 | 
				
			||||||
        var template = HANDLEBARS.compile(rawTpl, { strict: false, assumeObjects: false });
 | 
					 | 
				
			||||||
        var tot = 0;
 | 
					 | 
				
			||||||
        info.keywords.forEach(g => tot += g.count);
 | 
					 | 
				
			||||||
        info.keywords.totalKeywords = tot;
 | 
					 | 
				
			||||||
        var output = template( info );
 | 
					 | 
				
			||||||
        return this.log( chalk.cyan(output) );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.beforeConvert:
 | 
					 | 
				
			||||||
        return L( M2C( this.msgs.beforeConvert.msg, evt.error ? 'red' : 'green' ),
 | 
					 | 
				
			||||||
          evt.srcFile, evt.srcFmt, evt.dstFile, evt.dstFmt
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.afterInlineConvert:
 | 
					 | 
				
			||||||
        return L( M2C( this.msgs.afterInlineConvert.msg, 'gray', 'white.dim' ),
 | 
					 | 
				
			||||||
          evt.file, evt.fmt );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.afterValidate:
 | 
					 | 
				
			||||||
        var style = 'red';
 | 
					 | 
				
			||||||
        var adj = '';
 | 
					 | 
				
			||||||
        var 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]; break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        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) {
 | 
					 | 
				
			||||||
            L( chalk.yellow.bold('--> ') +
 | 
					 | 
				
			||||||
               chalk.yellow(err.field.replace('data.','resume.').toUpperCase() +
 | 
					 | 
				
			||||||
               ' ' + err.message));
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          , this);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      case HME.afterPeek:
 | 
					 | 
				
			||||||
        var sty = evt.error ? 'red' : ( evt.target !== undefined ? 'green' : '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 the key was present, print it
 | 
					 | 
				
			||||||
        if ((evt.target !== undefined) && !evt.error) {
 | 
					 | 
				
			||||||
          // eslint-disable-next-line no-console
 | 
					 | 
				
			||||||
          return console.dir( evt.target, { depth: null, colors: true } );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // If the key was not present, but no error occurred, print it
 | 
					 | 
				
			||||||
        } 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 ));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module.exports = OutputHandler;
 | 
					 | 
				
			||||||
							
								
								
									
										51
									
								
								src/cli/use.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/cli/use.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
				
			|||||||
 | 
					Usage:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hackmyresume <command> <sources> [TO <targets>] [<options>]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Available commands:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  BUILD         Build your resume to the destination format(s).
 | 
				
			||||||
 | 
					  ANALYZE       Analyze your resume for keywords, gaps, and metrics.
 | 
				
			||||||
 | 
					  VALIDATE      Validate your resume for errors and typos.
 | 
				
			||||||
 | 
					  CONVERT       Convert your resume between FRESH and JSON Resume.
 | 
				
			||||||
 | 
					  NEW           Create a new resume in FRESH or JSON Resume format.
 | 
				
			||||||
 | 
					  PEEK          View a specific field or element on your resume.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Available options:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  --theme -t    Path to a FRESH or JSON Resume theme.
 | 
				
			||||||
 | 
					  --pdf -p      Specify the PDF engine to use (wkhtmltopdf or phantom).
 | 
				
			||||||
 | 
					  --options -o  Load options from an external JSON file.
 | 
				
			||||||
 | 
					  --format -f   The format (FRESH or JSON Resume) to use.
 | 
				
			||||||
 | 
					  --debug -d    Emit extended debugging info.
 | 
				
			||||||
 | 
					  --assert -a   Treat resume validation warnings as errors.
 | 
				
			||||||
 | 
					  --no-colors   Disable terminal colors.
 | 
				
			||||||
 | 
					  --tips        Display theme messages and tips.
 | 
				
			||||||
 | 
					  --help -h     Display help documentation.
 | 
				
			||||||
 | 
					  --version -v  Display the current version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Not all options are supported for all commands. For example, the
 | 
				
			||||||
 | 
					--theme option is only supported for the BUILD command.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Examples:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  hackmyresume  BUILD resume.json TO out/resume.all --theme modern
 | 
				
			||||||
 | 
					  hackmyresume  ANALYZE resume.json
 | 
				
			||||||
 | 
					  hackmyresume  NEW my-new-resume.json --format JRS
 | 
				
			||||||
 | 
					  hackmyresume  CONVERT resume-fresh.json TO resume-jrs.json
 | 
				
			||||||
 | 
					  hackmyresume  VALIDATE resume.json
 | 
				
			||||||
 | 
					  hackmyresume  PEEK resume.json employment[2].summary
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tips:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - You can specify multiple sources and/or targets for all commands.
 | 
				
			||||||
 | 
					  - You can use any FRESH or JSON Resume theme with HackMyResume.
 | 
				
			||||||
 | 
					  - Specify a file extension of .all to generate your resume to all
 | 
				
			||||||
 | 
					    available formats supported by the theme. (BUILD command.)
 | 
				
			||||||
 | 
					  - The --theme parameter can specify either the name of a preinstalled
 | 
				
			||||||
 | 
					    theme, or the path to a local FRESH or JSON Resume theme.
 | 
				
			||||||
 | 
					  - Visit https://www.npmjs.com/search?q=jsonresume-theme for a full
 | 
				
			||||||
 | 
					    listing of all available JSON Resume themes.
 | 
				
			||||||
 | 
					  - Visit https://github.com/fluentdesk/fresh-themes for a complete
 | 
				
			||||||
 | 
					    listing of all available FRESH themes.
 | 
				
			||||||
 | 
					  - Report bugs to https://githut.com/hacksalot/HackMyResume/issues.
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user