resume-cli 3.0.8 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -47
- package/build/builder.js +1 -9
- package/build/export-resume.js +0 -29
- package/build/get-resume.js +0 -17
- package/build/get-resume.test.js +82 -0
- package/build/get-schema.js +0 -7
- package/build/init.js +0 -14
- package/build/main.js +8 -20
- package/build/main.test.js +136 -0
- package/build/render-html.js +2 -15
- package/build/render-html.test.js +49 -0
- package/build/serve.js +0 -9
- package/build/test-utils/cli-test-entry.js +21 -0
- package/build/test-utils/mocked-volume-builder.js +47 -0
- package/build/validate.js +0 -8
- package/build/validate.test.js +41 -0
- package/package.json +7 -11
package/README.md
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
# resume-cli
|
|
2
2
|
|
|
3
|
-
[](https://david-dm.org/jsonresume/resume-cli)
|
|
6
|
-
[](https://david-dm.org/jsonresume/resume-cli#info=devDependencies)
|
|
3
|
+
[](https://matrix.to/#/#json-resume:one.ems.host)
|
|
4
|
+
[](https://github.com/jsonresume/resume-cli/actions)
|
|
7
5
|
[](https://www.npmjs.org/package/resume-cli)
|
|
8
6
|
|
|
9
|
-
This is the command line tool for [JSON Resume](https://jsonresume.org), the open
|
|
7
|
+
This is the command line tool for [JSON Resume](https://jsonresume.org), the open-source initiative to create a JSON-based standard for resumes.
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
## Project Status
|
|
12
10
|
|
|
11
|
+
This repository is not actively maintained. It's recommended to use one of the third-party clients that support the JSON Resume standard instead:
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
- [Resumed](https://github.com/rbardini/resumed)
|
|
13
|
+
* [Resumed](https://github.com/rbardini/resumed)
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
# Getting Started
|
|
15
|
+
## Getting Started
|
|
19
16
|
|
|
20
17
|
Install the command-line tool:
|
|
21
18
|
|
|
@@ -23,84 +20,77 @@ Install the command-line tool:
|
|
|
23
20
|
npm install -g resume-cli
|
|
24
21
|
```
|
|
25
22
|
|
|
26
|
-
##
|
|
23
|
+
## Usage
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
| ---------------------- | ----------------------------------------- |
|
|
30
|
-
| init | Initialize a `resume.json` file |
|
|
31
|
-
| validate | Schema validation test your `resume.json` |
|
|
32
|
-
| export [fileName.html] | Export locally to `.html` |
|
|
33
|
-
| serve | Serve resume at `http://localhost:4000/` |
|
|
25
|
+
### Commands at a Glance
|
|
34
26
|
|
|
35
|
-
|
|
27
|
+
| Command | Description |
|
|
28
|
+
|---|---|
|
|
29
|
+
| init | Initialize a `resume.json` file. |
|
|
30
|
+
| validate | Schema validation test your `resume.json`. |
|
|
31
|
+
| export path/to/file.html | Export to `.html`. |
|
|
32
|
+
| serve | Serve resume at `http://localhost:4000/`. |
|
|
36
33
|
|
|
37
|
-
|
|
34
|
+
### `resume --help`
|
|
38
35
|
|
|
39
|
-
Show a list of options and commands for the <abbr title="Command
|
|
36
|
+
Show a list of options and commands for the <abbr title="Command-line Interface">CLI</abbr>.
|
|
40
37
|
|
|
41
|
-
|
|
38
|
+
### `resume init`
|
|
42
39
|
|
|
43
40
|
Creates a new `resume.json` file in your current working directory.
|
|
44
41
|
|
|
45
|
-
Complete the `resume.json` with your text editor. Be sure to follow the schema
|
|
46
|
-
(available at http://jsonresume.org).
|
|
42
|
+
Complete the `resume.json` with your text editor. Be sure to follow the schema (available at https://jsonresume.org/schema/).
|
|
47
43
|
|
|
48
|
-
|
|
44
|
+
### `resume validate`
|
|
49
45
|
|
|
50
|
-
Validates your `resume.json` against our schema
|
|
51
|
-
the standard. Tries to identify where any errors may be occurring.
|
|
46
|
+
Validates your `resume.json` against our schema to ensure it complies with the standard. Tries to identify where any errors may be occurring.
|
|
52
47
|
|
|
53
|
-
|
|
48
|
+
### `resume export [fileName]`
|
|
54
49
|
|
|
55
|
-
Exports your resume
|
|
50
|
+
Exports your resume in a stylized HTML or PDF format.
|
|
56
51
|
|
|
57
|
-
A list of available themes can be found here:
|
|
52
|
+
A list of available themes can be found here:
|
|
53
|
+
https://jsonresume.org/themes/
|
|
58
54
|
|
|
59
|
-
Please npm install the theme you wish to use
|
|
55
|
+
Please npm install the theme you wish to use before attempting to export it.
|
|
60
56
|
|
|
61
57
|
Options:
|
|
62
58
|
|
|
63
59
|
- `--format <file type>` Example: `--format pdf`
|
|
64
60
|
- `--theme <name>` Example: `--theme even`
|
|
65
61
|
|
|
66
|
-
|
|
62
|
+
### `resume serve`
|
|
67
63
|
|
|
68
|
-
Starts a web server that serves your local `resume.json`. It will live reload when you make
|
|
64
|
+
Starts a web server that serves your local `resume.json`. It will live reload when you make changes to your `resume.json`.
|
|
69
65
|
|
|
70
66
|
Options:
|
|
71
67
|
|
|
72
68
|
- `--port <port>`
|
|
73
69
|
- `--theme <name>`
|
|
74
70
|
|
|
75
|
-
When developing themes,
|
|
71
|
+
When developing themes, change into your theme directory and run `resume serve --theme .`, which tells it to run the local folder as the specified theme.
|
|
72
|
+
|
|
73
|
+
This is not intended for production use, it's a convenience for theme development or to visualize changes to your resume while editing it.
|
|
76
74
|
|
|
77
|
-
|
|
75
|
+
## Supported Resume Input Types
|
|
78
76
|
|
|
79
77
|
- [`json`](https://www.json.org/json-en.html): via `JSON.parse`.
|
|
80
78
|
- [`yaml`](https://yaml.org/): via [`yaml-js`](https://www.npmjs.com/package/yaml-js)
|
|
81
79
|
- `quaff`: if `--resume` is a directory, then the path is passed to [`quaff`](https://www.npmjs.com/package/quaff) and the resulting json is used as the resume. quaff supports a variety of formats in the directory, including javascript modules.
|
|
82
80
|
|
|
83
|
-
|
|
81
|
+
## Resume Data
|
|
84
82
|
|
|
85
|
-
- Setting `--resume -` tells the
|
|
83
|
+
- Setting `--resume -` tells the CLI to read resume data from standard input (`STDIN`), and defaults `--type` to `application/json`.
|
|
86
84
|
- Setting `--resume <path>` reads resume data from `path`.
|
|
87
85
|
- Leaving `--resume` unset defaults to reading from `resume.json` on the current working directory.
|
|
88
86
|
|
|
89
|
-
|
|
87
|
+
## Resume MIME Types
|
|
90
88
|
|
|
91
|
-
Supported resume data
|
|
89
|
+
Supported resume data MIME types are:
|
|
92
90
|
|
|
93
91
|
- `application/json`
|
|
94
92
|
- `text/yaml`
|
|
95
93
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
to test the cli, run the dev script:
|
|
99
|
-
|
|
100
|
-
```sh
|
|
101
|
-
npm run dev -- [cli arguments can be passed after the double-dash]
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
# License
|
|
94
|
+
## License
|
|
105
95
|
|
|
106
96
|
Available under [the MIT license](http://mths.be/mit).
|
package/build/builder.js
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const themeServer = process.env.THEME_SERVER || 'https://themes.jsonresume.org/theme/';
|
|
4
|
-
|
|
5
4
|
const fs = require('fs');
|
|
6
|
-
|
|
7
5
|
const request = require('superagent');
|
|
8
|
-
|
|
9
6
|
const chalk = require('chalk');
|
|
10
|
-
|
|
11
|
-
const renderHtml = require('./render-html').default;
|
|
12
|
-
|
|
7
|
+
const renderHtml = require('./render-html');
|
|
13
8
|
const denormalizeTheme = value => {
|
|
14
9
|
return value.match(/jsonresume-theme-(.*)/)[1];
|
|
15
10
|
};
|
|
16
|
-
|
|
17
11
|
const sendExportHTML = (resumeJson, theme, callback) => {
|
|
18
12
|
console.log(resumeJson, theme);
|
|
19
13
|
console.log('Requesting theme from server...');
|
|
@@ -29,7 +23,6 @@ const sendExportHTML = (resumeJson, theme, callback) => {
|
|
|
29
23
|
}
|
|
30
24
|
});
|
|
31
25
|
};
|
|
32
|
-
|
|
33
26
|
module.exports = function resumeBuilder(theme, dir, resumeFilename, cb) {
|
|
34
27
|
fs.readFile(resumeFilename, async (err, resumeJson) => {
|
|
35
28
|
if (err) {
|
|
@@ -45,7 +38,6 @@ module.exports = function resumeBuilder(theme, dir, resumeFilename, cb) {
|
|
|
45
38
|
return cb(err);
|
|
46
39
|
}
|
|
47
40
|
}
|
|
48
|
-
|
|
49
41
|
try {
|
|
50
42
|
const html = await renderHtml({
|
|
51
43
|
resume: resumeJson,
|
package/build/export-resume.js
CHANGED
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _renderHtml = _interopRequireDefault(require("./render-html"));
|
|
4
|
-
|
|
5
4
|
var _util = require("util");
|
|
6
|
-
|
|
7
5
|
var _fs = _interopRequireDefault(require("fs"));
|
|
8
|
-
|
|
9
6
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
|
-
|
|
11
7
|
const writeFile = (0, _util.promisify)(_fs.default.writeFile);
|
|
12
|
-
|
|
13
8
|
const path = require('path');
|
|
14
|
-
|
|
15
9
|
const puppeteer = require('puppeteer');
|
|
16
|
-
|
|
17
10
|
const btoa = require('btoa');
|
|
18
|
-
|
|
19
11
|
module.exports = ({
|
|
20
12
|
resume: resumeJson,
|
|
21
13
|
fileName,
|
|
@@ -26,18 +18,15 @@ module.exports = ({
|
|
|
26
18
|
console.error('Please enter a export destination.');
|
|
27
19
|
process.exit(1);
|
|
28
20
|
}
|
|
29
|
-
|
|
30
21
|
const fileNameAndFormat = getFileNameAndFormat(fileName, format);
|
|
31
22
|
fileName = fileNameAndFormat.fileName;
|
|
32
23
|
const fileFormatToUse = fileNameAndFormat.fileFormatToUse;
|
|
33
24
|
const formatToUse = '.' + fileFormatToUse;
|
|
34
|
-
|
|
35
25
|
if (formatToUse === '.html') {
|
|
36
26
|
createHtml(resumeJson, fileName, theme, formatToUse, error => {
|
|
37
27
|
if (error) {
|
|
38
28
|
console.error(error, '`createHtml` errored out');
|
|
39
29
|
}
|
|
40
|
-
|
|
41
30
|
callback(error, fileName, formatToUse);
|
|
42
31
|
});
|
|
43
32
|
} else if (formatToUse === '.pdf') {
|
|
@@ -45,7 +34,6 @@ module.exports = ({
|
|
|
45
34
|
if (error) {
|
|
46
35
|
console.error(error, '`createPdf` errored out');
|
|
47
36
|
}
|
|
48
|
-
|
|
49
37
|
callback(error, fileName, formatToUse);
|
|
50
38
|
});
|
|
51
39
|
} else {
|
|
@@ -53,27 +41,21 @@ module.exports = ({
|
|
|
53
41
|
process.exit(1);
|
|
54
42
|
}
|
|
55
43
|
};
|
|
56
|
-
|
|
57
44
|
const extractFileFormat = fileName => {
|
|
58
45
|
const dotPos = fileName.lastIndexOf('.');
|
|
59
|
-
|
|
60
46
|
if (dotPos === -1) {
|
|
61
47
|
return null;
|
|
62
48
|
}
|
|
63
|
-
|
|
64
49
|
return fileName.substring(dotPos + 1).toLowerCase();
|
|
65
50
|
};
|
|
66
|
-
|
|
67
51
|
const getThemePkg = theme => {
|
|
68
52
|
if (theme[0] === '.') {
|
|
69
53
|
theme = path.join(process.cwd(), theme, 'index.js');
|
|
70
54
|
} else {
|
|
71
55
|
theme = path.join(process.cwd(), 'node_modules', theme, 'index.js');
|
|
72
56
|
}
|
|
73
|
-
|
|
74
57
|
try {
|
|
75
58
|
const themePkg = require(theme);
|
|
76
|
-
|
|
77
59
|
return themePkg;
|
|
78
60
|
} catch (err) {
|
|
79
61
|
// Theme not installed
|
|
@@ -81,7 +63,6 @@ const getThemePkg = theme => {
|
|
|
81
63
|
process.exit();
|
|
82
64
|
}
|
|
83
65
|
};
|
|
84
|
-
|
|
85
66
|
async function createHtml(resumeJson, fileName, themePath, format, callback) {
|
|
86
67
|
const html = await (0, _renderHtml.default)({
|
|
87
68
|
resume: resumeJson,
|
|
@@ -89,23 +70,18 @@ async function createHtml(resumeJson, fileName, themePath, format, callback) {
|
|
|
89
70
|
});
|
|
90
71
|
const pathToStream = path.resolve(process.cwd(), fileName + format);
|
|
91
72
|
await writeFile(pathToStream, ''); // workaround for https://github.com/streamich/unionfs/issues/428
|
|
92
|
-
|
|
93
73
|
const stream = _fs.default.createWriteStream(pathToStream);
|
|
94
|
-
|
|
95
74
|
stream.write(html, () => {
|
|
96
75
|
stream.close(callback);
|
|
97
76
|
});
|
|
98
77
|
}
|
|
99
|
-
|
|
100
78
|
const createPdf = (resumeJson, fileName, theme, format, callback) => {
|
|
101
79
|
(async () => {
|
|
102
80
|
const themePkg = getThemePkg(theme);
|
|
103
81
|
const puppeteerLaunchArgs = [];
|
|
104
|
-
|
|
105
82
|
if (process.env.RESUME_PUPPETEER_NO_SANDBOX) {
|
|
106
83
|
puppeteerLaunchArgs.push('--no-sandbox');
|
|
107
84
|
}
|
|
108
|
-
|
|
109
85
|
const html = await (0, _renderHtml.default)({
|
|
110
86
|
resume: resumeJson,
|
|
111
87
|
themePath: theme
|
|
@@ -118,11 +94,9 @@ const createPdf = (resumeJson, fileName, theme, format, callback) => {
|
|
|
118
94
|
await page.goto(`data:text/html;base64,${btoa(unescape(encodeURIComponent(html)))}`, {
|
|
119
95
|
waitUntil: 'networkidle0'
|
|
120
96
|
});
|
|
121
|
-
|
|
122
97
|
if (themePkg.pdfViewport) {
|
|
123
98
|
await page.setViewport(themePkg.pdfViewport);
|
|
124
99
|
}
|
|
125
|
-
|
|
126
100
|
await page.pdf({
|
|
127
101
|
path: fileName + format,
|
|
128
102
|
format: 'Letter',
|
|
@@ -132,18 +106,15 @@ const createPdf = (resumeJson, fileName, theme, format, callback) => {
|
|
|
132
106
|
await browser.close();
|
|
133
107
|
})().then(callback).catch(callback);
|
|
134
108
|
};
|
|
135
|
-
|
|
136
109
|
const getFileNameAndFormat = (fileName, format) => {
|
|
137
110
|
const fileFormatFound = extractFileFormat(fileName);
|
|
138
111
|
let fileFormatToUse = format;
|
|
139
|
-
|
|
140
112
|
if (format && fileFormatFound && format === fileFormatFound) {
|
|
141
113
|
fileName = fileName.substring(0, fileName.lastIndexOf('.'));
|
|
142
114
|
} else if (fileFormatFound) {
|
|
143
115
|
fileFormatToUse = fileFormatFound;
|
|
144
116
|
fileName = fileName.substring(0, fileName.lastIndexOf('.'));
|
|
145
117
|
}
|
|
146
|
-
|
|
147
118
|
return {
|
|
148
119
|
fileName: fileName,
|
|
149
120
|
fileFormatToUse: fileFormatToUse
|
package/build/get-resume.js
CHANGED
|
@@ -4,23 +4,14 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _fs = _interopRequireDefault(require("fs"));
|
|
9
|
-
|
|
10
8
|
var _mimeTypes = require("mime-types");
|
|
11
|
-
|
|
12
9
|
var _path = require("path");
|
|
13
|
-
|
|
14
10
|
var _quaff = _interopRequireDefault(require("quaff"));
|
|
15
|
-
|
|
16
11
|
var _streamToString = _interopRequireDefault(require("stream-to-string"));
|
|
17
|
-
|
|
18
12
|
var _yamlJs = _interopRequireDefault(require("yaml-js"));
|
|
19
|
-
|
|
20
13
|
var _util = require("util");
|
|
21
|
-
|
|
22
14
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
|
-
|
|
24
15
|
const {
|
|
25
16
|
createReadStream
|
|
26
17
|
} = _fs.default;
|
|
@@ -29,38 +20,30 @@ const parsers = {
|
|
|
29
20
|
'text/yaml': string => _yamlJs.default.load(string),
|
|
30
21
|
'application/json': string => JSON.parse(string)
|
|
31
22
|
};
|
|
32
|
-
|
|
33
23
|
var _default = async ({
|
|
34
24
|
path,
|
|
35
25
|
mime: inputMime
|
|
36
26
|
}) => {
|
|
37
27
|
let input;
|
|
38
28
|
let mime;
|
|
39
|
-
|
|
40
29
|
if ('-' === path) {
|
|
41
30
|
mime = inputMime || (0, _mimeTypes.lookup)('.json');
|
|
42
31
|
input = process.stdin;
|
|
43
32
|
} else if (path && (await stat(path)).isDirectory()) {
|
|
44
33
|
return (0, _quaff.default)(path);
|
|
45
34
|
}
|
|
46
|
-
|
|
47
35
|
if (!input) {
|
|
48
36
|
mime = inputMime || (0, _mimeTypes.lookup)(path);
|
|
49
37
|
input = createReadStream((0, _path.resolve)(process.cwd(), path));
|
|
50
38
|
}
|
|
51
|
-
|
|
52
39
|
if (!input) {
|
|
53
40
|
throw new Error('resume could not be gotten from path or stdin');
|
|
54
41
|
}
|
|
55
|
-
|
|
56
42
|
const resumeString = await (0, _streamToString.default)(input);
|
|
57
43
|
const parser = parsers[mime];
|
|
58
|
-
|
|
59
44
|
if (!parser) {
|
|
60
45
|
throw new Error(`no parser available for detected mime type ${mime}`);
|
|
61
46
|
}
|
|
62
|
-
|
|
63
47
|
return parser(resumeString);
|
|
64
48
|
};
|
|
65
|
-
|
|
66
49
|
exports.default = _default;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _waait = _interopRequireDefault(require("waait"));
|
|
4
|
+
var _getResume = _interopRequireDefault(require("./get-resume"));
|
|
5
|
+
var _mockStdin = require("mock-stdin");
|
|
6
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
7
|
+
jest.mock('fs', () => {
|
|
8
|
+
const build = require('./test-utils/mocked-volume-builder');
|
|
9
|
+
const {
|
|
10
|
+
createFsFromVolume
|
|
11
|
+
} = require('memfs');
|
|
12
|
+
const vol = build();
|
|
13
|
+
return createFsFromVolume(vol);
|
|
14
|
+
});
|
|
15
|
+
describe('get-resume', () => {
|
|
16
|
+
it('should consume yaml', async () => {
|
|
17
|
+
expect(await (0, _getResume.default)({
|
|
18
|
+
path: '/resume.yaml'
|
|
19
|
+
})).toMatchInlineSnapshot(`
|
|
20
|
+
Object {
|
|
21
|
+
"basics": Object {
|
|
22
|
+
"email": "thomas@example.com",
|
|
23
|
+
"name": "thomas",
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
`);
|
|
27
|
+
});
|
|
28
|
+
it('should consume json', async () => {
|
|
29
|
+
expect(await (0, _getResume.default)({
|
|
30
|
+
path: '/resume.json'
|
|
31
|
+
})).toMatchInlineSnapshot(`
|
|
32
|
+
Object {
|
|
33
|
+
"basics": Object {
|
|
34
|
+
"email": "thomas@example.com",
|
|
35
|
+
"name": "thomas",
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
`);
|
|
39
|
+
});
|
|
40
|
+
it('should consume an entire directory as if it were a json object', async () => {
|
|
41
|
+
expect(await (0, _getResume.default)({
|
|
42
|
+
path: '/quaff'
|
|
43
|
+
})).toMatchInlineSnapshot(`
|
|
44
|
+
Object {
|
|
45
|
+
"basics": Object {
|
|
46
|
+
"email": "thomas@example.com",
|
|
47
|
+
"name": "thomas",
|
|
48
|
+
},
|
|
49
|
+
"work": Array [
|
|
50
|
+
Object {
|
|
51
|
+
"company": "Pied Piper",
|
|
52
|
+
"endDate": "2014-12-01",
|
|
53
|
+
"position": "CEO/President",
|
|
54
|
+
"startDate": "2013-12-01",
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
}
|
|
58
|
+
`);
|
|
59
|
+
});
|
|
60
|
+
it('should read from process.stdin when path is a dash', async () => {
|
|
61
|
+
const stdin = (0, _mockStdin.stdin)();
|
|
62
|
+
const gotResume = (0, _getResume.default)({
|
|
63
|
+
path: '-'
|
|
64
|
+
});
|
|
65
|
+
await (0, _waait.default)();
|
|
66
|
+
stdin.send(JSON.stringify({
|
|
67
|
+
basics: {
|
|
68
|
+
name: 'thomas',
|
|
69
|
+
email: 'thomas@example.com'
|
|
70
|
+
}
|
|
71
|
+
}));
|
|
72
|
+
stdin.send(null);
|
|
73
|
+
expect(await gotResume).toMatchInlineSnapshot(`
|
|
74
|
+
Object {
|
|
75
|
+
"basics": Object {
|
|
76
|
+
"email": "thomas@example.com",
|
|
77
|
+
"name": "thomas",
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
`);
|
|
81
|
+
});
|
|
82
|
+
});
|
package/build/get-schema.js
CHANGED
|
@@ -4,25 +4,18 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _fs = require("fs");
|
|
9
|
-
|
|
10
8
|
var _util = require("util");
|
|
11
|
-
|
|
12
9
|
const readFile = (0, _util.promisify)(_fs.readFile);
|
|
13
|
-
|
|
14
10
|
var _default = async ({
|
|
15
11
|
path: pathArg
|
|
16
12
|
} = {}) => {
|
|
17
13
|
let path = pathArg;
|
|
18
|
-
|
|
19
14
|
if (!path) {
|
|
20
15
|
path = require.resolve('resume-schema/schema.json');
|
|
21
16
|
}
|
|
22
|
-
|
|
23
17
|
return JSON.parse(await readFile(path, {
|
|
24
18
|
encoding: 'utf-8'
|
|
25
19
|
}));
|
|
26
20
|
};
|
|
27
|
-
|
|
28
21
|
exports.default = _default;
|
package/build/init.js
CHANGED
|
@@ -4,41 +4,28 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _util = require("util");
|
|
9
|
-
|
|
10
8
|
var _fs = _interopRequireDefault(require("fs"));
|
|
11
|
-
|
|
12
9
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
13
|
-
|
|
14
10
|
var _yesno = _interopRequireDefault(require("yesno"));
|
|
15
|
-
|
|
16
11
|
var _objectPathImmutable = require("object-path-immutable");
|
|
17
|
-
|
|
18
12
|
var _fileExists = _interopRequireDefault(require("file-exists"));
|
|
19
|
-
|
|
20
13
|
var _read = _interopRequireDefault(require("read"));
|
|
21
|
-
|
|
22
14
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
23
|
-
|
|
24
15
|
const writeFile = (0, _util.promisify)(_fs.default.writeFile);
|
|
25
16
|
const read = (0, _util.promisify)(_read.default);
|
|
26
|
-
|
|
27
17
|
const resume = require('resume-schema/sample.resume.json');
|
|
28
|
-
|
|
29
18
|
var _default = async ({
|
|
30
19
|
resumePath
|
|
31
20
|
}) => {
|
|
32
21
|
if (await (0, _fileExists.default)(resumePath)) {
|
|
33
22
|
console.log(_chalk.default.yellow('There is already a resume.json file in this directory.'));
|
|
34
|
-
|
|
35
23
|
if (!(await (0, _yesno.default)({
|
|
36
24
|
question: 'Do you want to override?'
|
|
37
25
|
}))) {
|
|
38
26
|
return;
|
|
39
27
|
}
|
|
40
28
|
}
|
|
41
|
-
|
|
42
29
|
console.log(`This utility will generate a file at ${resumePath}.`);
|
|
43
30
|
console.log('Fill out your name and email to get started, or leave the fields blank.');
|
|
44
31
|
console.log('All fields are optional.\n');
|
|
@@ -63,5 +50,4 @@ var _default = async ({
|
|
|
63
50
|
console.log('Or simply type: `resume export` and follow the prompts.');
|
|
64
51
|
console.log('');
|
|
65
52
|
};
|
|
66
|
-
|
|
67
53
|
exports.default = _default;
|
package/build/main.js
CHANGED
|
@@ -2,39 +2,25 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
require("dotenv/config");
|
|
5
|
-
|
|
6
5
|
var _init = _interopRequireDefault(require("./init"));
|
|
7
|
-
|
|
8
6
|
var _getResume = _interopRequireDefault(require("./get-resume"));
|
|
9
|
-
|
|
10
7
|
var _getSchema = _interopRequireDefault(require("./get-schema"));
|
|
11
|
-
|
|
12
8
|
var _validate = _interopRequireDefault(require("./validate"));
|
|
13
|
-
|
|
14
9
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
-
|
|
16
10
|
const pkg = require('../package.json');
|
|
17
|
-
|
|
18
11
|
const exportResume = require('./export-resume');
|
|
19
|
-
|
|
20
12
|
const serve = require('./serve');
|
|
21
|
-
|
|
22
13
|
const program = require('commander');
|
|
23
|
-
|
|
24
14
|
const chalk = require('chalk');
|
|
25
|
-
|
|
26
15
|
const path = require('path');
|
|
27
|
-
|
|
28
16
|
const normalizeTheme = (value, defaultValue) => {
|
|
29
|
-
const theme = value || defaultValue;
|
|
30
|
-
|
|
17
|
+
const theme = value || defaultValue;
|
|
18
|
+
// TODO - This is not great, but bypasses this function if it is a relative path
|
|
31
19
|
if (theme[0] === '.') {
|
|
32
20
|
return theme;
|
|
33
21
|
}
|
|
34
|
-
|
|
35
22
|
return theme.match('jsonresume-theme-.*') ? theme : `jsonresume-theme-${theme}`;
|
|
36
23
|
};
|
|
37
|
-
|
|
38
24
|
(async () => {
|
|
39
25
|
program.name('resume').usage('[command] [options]').version(pkg.version).option('-F, --force', 'Used by `publish` and `export` - bypasses schema testing.').option('-t, --theme <theme name>', 'Specify theme used by `export` and `serve` or specify a path starting with . (use . for current directory or ../some/other/dir)', normalizeTheme, 'jsonresume-theme-even').option('-f, --format <file type extension>', 'Used by `export`.').option('-r, --resume <resume filename>', "path to the resume in json format. Use '-' to read from stdin", 'resume.json').option('-p, --port <port>', 'Used by `serve` (default: 4000)', 4000).option('-s, --silent', 'Used by `serve` to tell it if open browser auto or not.', false).option('-d, --dir <path>', 'Used by `serve` to indicate a public directory path.', 'public').option('--schema <relativePath>', 'Used by `validate` to validate against a custom schema.');
|
|
40
26
|
program.command('init').description('Initialize a resume.json file').action(async () => {
|
|
@@ -49,7 +35,6 @@ const normalizeTheme = (value, defaultValue) => {
|
|
|
49
35
|
const schema = await (0, _getSchema.default)({
|
|
50
36
|
path: program.schema
|
|
51
37
|
});
|
|
52
|
-
|
|
53
38
|
try {
|
|
54
39
|
await (0, _validate.default)({
|
|
55
40
|
resume,
|
|
@@ -64,7 +49,8 @@ const normalizeTheme = (value, defaultValue) => {
|
|
|
64
49
|
const resume = await (0, _getResume.default)({
|
|
65
50
|
path: program.resume
|
|
66
51
|
});
|
|
67
|
-
exportResume({
|
|
52
|
+
exportResume({
|
|
53
|
+
...program,
|
|
68
54
|
resume,
|
|
69
55
|
fileName
|
|
70
56
|
}, (err, fileName, format) => {
|
|
@@ -72,15 +58,17 @@ const normalizeTheme = (value, defaultValue) => {
|
|
|
72
58
|
});
|
|
73
59
|
});
|
|
74
60
|
program.command('serve').description('Serve resume at http://localhost:4000/').action(async () => {
|
|
75
|
-
serve({
|
|
61
|
+
serve({
|
|
62
|
+
...program,
|
|
76
63
|
resumeFilename: program.resume
|
|
77
64
|
});
|
|
78
65
|
});
|
|
79
66
|
await program.parseAsync(process.argv);
|
|
80
67
|
const validCommands = program.commands.map(cmd => {
|
|
81
68
|
return cmd._name;
|
|
82
|
-
});
|
|
69
|
+
});
|
|
83
70
|
|
|
71
|
+
// https://github.com/tj/commander.js/blob/master/CHANGELOG.md#testing-for-no-arguments
|
|
84
72
|
if (program.rawArgs.length < 3) {
|
|
85
73
|
console.log(chalk.cyan('resume-cli:'), 'https://jsonresume.org', '\n');
|
|
86
74
|
program.help();
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _child_process = require("child_process");
|
|
4
|
+
var _streamToString = _interopRequireDefault(require("stream-to-string"));
|
|
5
|
+
var _util = require("util");
|
|
6
|
+
var _package = _interopRequireDefault(require("../package.json"));
|
|
7
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
8
|
+
const exec = (0, _util.promisify)(_child_process.exec);
|
|
9
|
+
const run = async (argv, {
|
|
10
|
+
waitForVolumeExport = true,
|
|
11
|
+
stdin = ''
|
|
12
|
+
} = {}) => {
|
|
13
|
+
let volume;
|
|
14
|
+
let exitCode;
|
|
15
|
+
const child = (0, _child_process.spawn)(process.execPath, ['build/test-utils/cli-test-entry.js', ...argv], {
|
|
16
|
+
stdio: ['pipe', 'pipe', 2, 'ipc']
|
|
17
|
+
});
|
|
18
|
+
const allChecks = Promise.all([waitForVolumeExport ? new Promise(volumeSet => {
|
|
19
|
+
child.on('message', async message => {
|
|
20
|
+
if (message.type === 'volumeExport') {
|
|
21
|
+
volume = message.data;
|
|
22
|
+
volumeSet();
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}) : true, new Promise(processExited => {
|
|
26
|
+
child.on('exit', code => {
|
|
27
|
+
exitCode = code;
|
|
28
|
+
processExited();
|
|
29
|
+
});
|
|
30
|
+
})]);
|
|
31
|
+
child.stdin.write(stdin);
|
|
32
|
+
child.stdin.end();
|
|
33
|
+
const stdout = await (0, _streamToString.default)(child.stdout);
|
|
34
|
+
await allChecks;
|
|
35
|
+
return {
|
|
36
|
+
volume,
|
|
37
|
+
code: exitCode,
|
|
38
|
+
stdout
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
describe('cli configuration', () => {
|
|
42
|
+
beforeAll(() => exec(_package.default.scripts.prepare));
|
|
43
|
+
it('should show help', async () => {
|
|
44
|
+
const {
|
|
45
|
+
stdout
|
|
46
|
+
} = await run(['help'], {
|
|
47
|
+
waitForVolumeExport: false
|
|
48
|
+
});
|
|
49
|
+
expect(stdout).toMatchInlineSnapshot(`
|
|
50
|
+
"Usage: resume [command] [options]
|
|
51
|
+
|
|
52
|
+
Options:
|
|
53
|
+
-V, --version output the version number
|
|
54
|
+
-F, --force Used by \`publish\` and \`export\` - bypasses
|
|
55
|
+
schema testing.
|
|
56
|
+
-t, --theme <theme name> Specify theme used by \`export\` and
|
|
57
|
+
\`serve\` or specify a path starting with .
|
|
58
|
+
(use . for current directory or
|
|
59
|
+
../some/other/dir) (default:
|
|
60
|
+
\\"jsonresume-theme-even\\")
|
|
61
|
+
-f, --format <file type extension> Used by \`export\`.
|
|
62
|
+
-r, --resume <resume filename> path to the resume in json format. Use
|
|
63
|
+
'-' to read from stdin (default:
|
|
64
|
+
\\"resume.json\\")
|
|
65
|
+
-p, --port <port> Used by \`serve\` (default: 4000) (default:
|
|
66
|
+
4000)
|
|
67
|
+
-s, --silent Used by \`serve\` to tell it if open
|
|
68
|
+
browser auto or not. (default: false)
|
|
69
|
+
-d, --dir <path> Used by \`serve\` to indicate a public
|
|
70
|
+
directory path. (default: \\"public\\")
|
|
71
|
+
--schema <relativePath> Used by \`validate\` to validate against a
|
|
72
|
+
custom schema.
|
|
73
|
+
-h, --help display help for command
|
|
74
|
+
|
|
75
|
+
Commands:
|
|
76
|
+
init Initialize a resume.json file
|
|
77
|
+
validate Validate your resume's schema
|
|
78
|
+
export [fileName] Export locally to .html or .pdf. Supply
|
|
79
|
+
a --format <file format> flag and
|
|
80
|
+
argument to specify export format.
|
|
81
|
+
serve Serve resume at http://localhost:4000/
|
|
82
|
+
help [command] display help for command
|
|
83
|
+
"
|
|
84
|
+
`);
|
|
85
|
+
});
|
|
86
|
+
describe('validate', () => {
|
|
87
|
+
it('should use the schema override arg', async () => {
|
|
88
|
+
const {
|
|
89
|
+
stdout
|
|
90
|
+
} = await run(['validate', '--schema', '/test-resumes/only-number-schema.json', '--resume', '/test-resumes/only-number.json']);
|
|
91
|
+
expect(stdout).toMatchInlineSnapshot(`""`);
|
|
92
|
+
});
|
|
93
|
+
it('should fail when trying to validate an invalid resume specified by the --resume option', async () => {
|
|
94
|
+
expect((await run(['validate', '--resume', '/test-resumes/invalid-resume.json'])).code).toEqual(1);
|
|
95
|
+
});
|
|
96
|
+
it('should validate a resume specified by the --resume option', async () => {
|
|
97
|
+
const {
|
|
98
|
+
stdout
|
|
99
|
+
} = await run(['validate', '--resume', '/test-resumes/resume.json']);
|
|
100
|
+
expect(stdout).toMatchInlineSnapshot(`""`);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
describe('export', () => {
|
|
104
|
+
it('should read from stdin when path is a dash', async () => {
|
|
105
|
+
const {
|
|
106
|
+
stdout,
|
|
107
|
+
volume
|
|
108
|
+
} = await run(['export', '/test-resumes/exported-resume-from-stdin.html', '--resume', '-' // this is the dash
|
|
109
|
+
], {
|
|
110
|
+
stdin: JSON.stringify({
|
|
111
|
+
basics: {
|
|
112
|
+
name: 'thomas-from-stdin'
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
});
|
|
116
|
+
expect(volume['/test-resumes/exported-resume-from-stdin.html']).toEqual(expect.stringContaining('thomas-from-stdin'));
|
|
117
|
+
expect(stdout).toMatchInlineSnapshot(`
|
|
118
|
+
"
|
|
119
|
+
Done! Find your new .html resume at:
|
|
120
|
+
/test-resumes/exported-resume-from-stdin.html
|
|
121
|
+
"
|
|
122
|
+
`);
|
|
123
|
+
});
|
|
124
|
+
it('should export a resume from the path specified by --resume to the path specified immediately after the export command', async () => {
|
|
125
|
+
const {
|
|
126
|
+
stdout
|
|
127
|
+
} = await run(['export', '/test-resumes/exported-resume.html', '--resume', '/test-resumes/resume.json']);
|
|
128
|
+
expect(stdout).toMatchInlineSnapshot(`
|
|
129
|
+
"
|
|
130
|
+
Done! Find your new .html resume at:
|
|
131
|
+
/test-resumes/exported-resume.html
|
|
132
|
+
"
|
|
133
|
+
`);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
package/build/render-html.js
CHANGED
|
@@ -4,7 +4,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
const tryResolve = (...args) => {
|
|
9
8
|
try {
|
|
10
9
|
return require.resolve(...args);
|
|
@@ -12,47 +11,35 @@ const tryResolve = (...args) => {
|
|
|
12
11
|
return false;
|
|
13
12
|
}
|
|
14
13
|
};
|
|
15
|
-
|
|
16
14
|
var _default = async ({
|
|
17
15
|
resume,
|
|
18
16
|
themePath
|
|
19
17
|
}) => {
|
|
20
18
|
const cwd = process.cwd();
|
|
21
19
|
let path;
|
|
22
|
-
|
|
23
20
|
if (themePath[0] === '.') {
|
|
24
|
-
path = tryResolve(
|
|
21
|
+
path = tryResolve(path.join(cwd, themePath), {
|
|
25
22
|
paths: [cwd]
|
|
26
23
|
});
|
|
27
|
-
|
|
28
|
-
if (!path) {
|
|
29
|
-
throw new Error(`Theme ${themePath} could not be resolved relative to ${cwd}`);
|
|
30
|
-
}
|
|
24
|
+
throw new Error(`Theme ${themePath} could not be resolved relative to ${cwd}`);
|
|
31
25
|
}
|
|
32
|
-
|
|
33
26
|
if (!path) {
|
|
34
27
|
path = tryResolve(themePath, {
|
|
35
28
|
paths: [cwd]
|
|
36
29
|
});
|
|
37
30
|
}
|
|
38
|
-
|
|
39
31
|
if (!path && /^[a-z0-9]/i.test(path)) {
|
|
40
32
|
path = tryResolve(`jsonresume-theme-${themePath}`, {
|
|
41
33
|
paths: [cwd]
|
|
42
34
|
});
|
|
43
35
|
}
|
|
44
|
-
|
|
45
36
|
if (!path) {
|
|
46
37
|
throw new Error(`theme path ${themePath} could not be resolved from current working directory`);
|
|
47
38
|
}
|
|
48
|
-
|
|
49
39
|
const theme = require(path);
|
|
50
|
-
|
|
51
40
|
if (typeof (theme === null || theme === void 0 ? void 0 : theme.render) !== 'function') {
|
|
52
41
|
throw new Error('theme.render is not a function');
|
|
53
42
|
}
|
|
54
|
-
|
|
55
43
|
return theme.render(resume);
|
|
56
44
|
};
|
|
57
|
-
|
|
58
45
|
exports.default = _default;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _renderHtml = _interopRequireDefault(require("./render-html"));
|
|
4
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
5
|
+
describe('renderHTML', () => {
|
|
6
|
+
beforeAll(() => {
|
|
7
|
+
const originalRequireResolve = require.resolve;
|
|
8
|
+
const mockThemePath = 'mock/path/to/jsonresume-theme-even';
|
|
9
|
+
require.resolve = (...args) => {
|
|
10
|
+
if (args[0] === 'jsonresume-theme-even') {
|
|
11
|
+
return mockThemePath;
|
|
12
|
+
}
|
|
13
|
+
if (args[0] === 'jsonresume-theme-even') {
|
|
14
|
+
return mockThemePath;
|
|
15
|
+
}
|
|
16
|
+
return originalRequireResolve.apply(require, ...args);
|
|
17
|
+
};
|
|
18
|
+
require.cache[mockThemePath] = {
|
|
19
|
+
render: () => 'here-is-your-mocked-theme'
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
const resume = {
|
|
23
|
+
basics: {
|
|
24
|
+
name: 'test',
|
|
25
|
+
label: 'Programmer',
|
|
26
|
+
email: 'test4@test.com'
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
it('should reject when theme is not availlable', async () => {
|
|
30
|
+
await expect((0, _renderHtml.default)({
|
|
31
|
+
resume,
|
|
32
|
+
themePath: 'unknown'
|
|
33
|
+
})).rejects.toBeTruthy();
|
|
34
|
+
});
|
|
35
|
+
describe('should render html when theme is availlable', () => {
|
|
36
|
+
it('with long theme name', async () => {
|
|
37
|
+
expect(await (0, _renderHtml.default)({
|
|
38
|
+
resume,
|
|
39
|
+
themePath: 'jsonresume-theme-even'
|
|
40
|
+
})).toStartWith('<!doctype html>');
|
|
41
|
+
});
|
|
42
|
+
it('with short theme name', async () => {
|
|
43
|
+
expect(await (0, _renderHtml.default)({
|
|
44
|
+
resume,
|
|
45
|
+
themePath: 'even'
|
|
46
|
+
})).toStartWith('<!doctype html>');
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
});
|
package/build/serve.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const fs = require('fs');
|
|
4
|
-
|
|
5
4
|
const path = require('path');
|
|
6
|
-
|
|
7
5
|
const readline = require('readline');
|
|
8
|
-
|
|
9
6
|
const bs = require('browser-sync').create();
|
|
10
|
-
|
|
11
7
|
const builder = require('./builder');
|
|
12
|
-
|
|
13
8
|
const reBuildResume = (theme, dir, resumeFilename, cb) => {
|
|
14
9
|
builder(theme, dir, resumeFilename, (err, html) => {
|
|
15
10
|
if (err) {
|
|
@@ -17,17 +12,14 @@ const reBuildResume = (theme, dir, resumeFilename, cb) => {
|
|
|
17
12
|
console.log(err);
|
|
18
13
|
html = err;
|
|
19
14
|
}
|
|
20
|
-
|
|
21
15
|
fs.writeFile(path.join(process.cwd(), dir, 'index.html'), html, err => {
|
|
22
16
|
if (err) {
|
|
23
17
|
console.log(err);
|
|
24
18
|
}
|
|
25
|
-
|
|
26
19
|
cb();
|
|
27
20
|
});
|
|
28
21
|
});
|
|
29
22
|
};
|
|
30
|
-
|
|
31
23
|
module.exports = function ({
|
|
32
24
|
port,
|
|
33
25
|
theme,
|
|
@@ -38,7 +30,6 @@ module.exports = function ({
|
|
|
38
30
|
if (!fs.existsSync(dir)) {
|
|
39
31
|
fs.mkdirSync(dir);
|
|
40
32
|
}
|
|
41
|
-
|
|
42
33
|
bs.watch(resumeFilename).on('change', () => {
|
|
43
34
|
reBuildResume(theme, dir, resumeFilename, () => {
|
|
44
35
|
bs.reload();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _mockedVolumeBuilder = _interopRequireDefault(require("./mocked-volume-builder"));
|
|
4
|
+
var _fsMonkey = require("fs-monkey");
|
|
5
|
+
var _unionfs = require("unionfs");
|
|
6
|
+
var fs = _interopRequireWildcard(require("fs"));
|
|
7
|
+
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
|
8
|
+
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
9
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
|
+
const mockVolume = (0, _mockedVolumeBuilder.default)({
|
|
11
|
+
mount: '/test-resumes'
|
|
12
|
+
});
|
|
13
|
+
const vol = _unionfs.ufs.use(mockVolume).use(fs);
|
|
14
|
+
(0, _fsMonkey.patchFs)(vol);
|
|
15
|
+
require('../main.js');
|
|
16
|
+
process.once('beforeExit', () => {
|
|
17
|
+
process.send({
|
|
18
|
+
data: mockVolume.toJSON(),
|
|
19
|
+
type: 'volumeExport'
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
module.exports = ({
|
|
4
|
+
mount = '/'
|
|
5
|
+
} = {}) => {
|
|
6
|
+
const dedent = require('dedent');
|
|
7
|
+
const flat = require('flat');
|
|
8
|
+
const {
|
|
9
|
+
Volume
|
|
10
|
+
} = require('memfs');
|
|
11
|
+
return Volume.fromJSON(flat({
|
|
12
|
+
'only-number-schema.json': JSON.stringify({
|
|
13
|
+
type: 'number'
|
|
14
|
+
}),
|
|
15
|
+
'only-number.json': '123',
|
|
16
|
+
'invalid-resume.json': JSON.stringify({
|
|
17
|
+
notAValidKey: {
|
|
18
|
+
foo: 'bar'
|
|
19
|
+
}
|
|
20
|
+
}),
|
|
21
|
+
'resume.json': JSON.stringify({
|
|
22
|
+
basics: {
|
|
23
|
+
name: 'thomas',
|
|
24
|
+
email: 'thomas@example.com'
|
|
25
|
+
}
|
|
26
|
+
}),
|
|
27
|
+
'resume.yaml': dedent`
|
|
28
|
+
basics:
|
|
29
|
+
name: thomas
|
|
30
|
+
email: thomas@example.com
|
|
31
|
+
`,
|
|
32
|
+
quaff: {
|
|
33
|
+
'basics.yaml': dedent`
|
|
34
|
+
name: thomas
|
|
35
|
+
email: thomas@example.com
|
|
36
|
+
`,
|
|
37
|
+
'work.json': JSON.stringify([{
|
|
38
|
+
company: 'Pied Piper',
|
|
39
|
+
endDate: '2014-12-01',
|
|
40
|
+
position: 'CEO/President',
|
|
41
|
+
startDate: '2013-12-01'
|
|
42
|
+
}])
|
|
43
|
+
}
|
|
44
|
+
}, {
|
|
45
|
+
delimiter: '/'
|
|
46
|
+
}), mount);
|
|
47
|
+
};
|
package/build/validate.js
CHANGED
|
@@ -4,20 +4,13 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.default = void 0;
|
|
7
|
-
|
|
8
7
|
var _util = require("util");
|
|
9
|
-
|
|
10
8
|
var _zSchema = _interopRequireDefault(require("z-schema"));
|
|
11
|
-
|
|
12
9
|
var _zSchemaErrors = _interopRequireDefault(require("z-schema-errors"));
|
|
13
|
-
|
|
14
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
|
-
|
|
16
11
|
const reporter = _zSchemaErrors.default.init();
|
|
17
|
-
|
|
18
12
|
const validator = new _zSchema.default();
|
|
19
13
|
const validate = (0, _util.promisify)((...args) => validator.validate(...args)); // maintains context
|
|
20
|
-
|
|
21
14
|
var _default = async ({
|
|
22
15
|
resume,
|
|
23
16
|
schema
|
|
@@ -32,5 +25,4 @@ var _default = async ({
|
|
|
32
25
|
}));
|
|
33
26
|
}
|
|
34
27
|
};
|
|
35
|
-
|
|
36
28
|
exports.default = _default;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _validate = _interopRequireDefault(require("./validate"));
|
|
4
|
+
var _getSchema = _interopRequireDefault(require("./get-schema"));
|
|
5
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
6
|
+
describe('validate', () => {
|
|
7
|
+
let defaultSchema;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
defaultSchema = await (0, _getSchema.default)();
|
|
10
|
+
});
|
|
11
|
+
it('should not throw an error for a valid resume object', async () => {
|
|
12
|
+
await (0, _validate.default)({
|
|
13
|
+
resume: {
|
|
14
|
+
basics: {}
|
|
15
|
+
},
|
|
16
|
+
schema: defaultSchema
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
it('should throw an error for an invalid resume object', async () => {
|
|
20
|
+
await expect((0, _validate.default)({
|
|
21
|
+
resume: {
|
|
22
|
+
notInTheSchema: true
|
|
23
|
+
},
|
|
24
|
+
schema: defaultSchema
|
|
25
|
+
})).rejects.toMatchInlineSnapshot(`[Error: An error occurred 'Additional properties not allowed: notInTheSchema'.]`);
|
|
26
|
+
});
|
|
27
|
+
it('should accept a schema override', async () => {
|
|
28
|
+
await (0, _validate.default)({
|
|
29
|
+
resume: 123,
|
|
30
|
+
schema: {
|
|
31
|
+
type: 'number'
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
await expect((0, _validate.default)({
|
|
35
|
+
resume: 'thomas',
|
|
36
|
+
schema: {
|
|
37
|
+
type: 'number'
|
|
38
|
+
}
|
|
39
|
+
})).rejects.toMatchInlineSnapshot(`[Error: An error occurred 'Expected type number but found type string'.]`);
|
|
40
|
+
});
|
|
41
|
+
});
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "resume-cli",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "The JSON Resume command line interface",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=12 <18"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"build/*",
|
|
@@ -30,24 +30,22 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"async": "^3.2.0",
|
|
33
|
-
"browser-sync": "^2.
|
|
33
|
+
"browser-sync": "^2.29.3",
|
|
34
34
|
"btoa": "^1.2.1",
|
|
35
35
|
"chalk": "^4.1.0",
|
|
36
36
|
"commander": "^6.0.0",
|
|
37
37
|
"dotenv": "^8.2.0",
|
|
38
38
|
"file-exists": "^5.0.1",
|
|
39
39
|
"jest-extended": "^0.11.5",
|
|
40
|
-
"jsonlint": "^1.6.3",
|
|
41
40
|
"jsonresume-theme-even": "^0.6.0",
|
|
42
41
|
"mime-types": "^2.1.27",
|
|
43
42
|
"object-path-immutable": "^4.1.1",
|
|
44
|
-
"puppeteer": "^
|
|
43
|
+
"puppeteer": "^18.2.1",
|
|
45
44
|
"quaff": "^4.2.0",
|
|
46
45
|
"read": "^1.0.7",
|
|
47
46
|
"resume-schema": "^1.0.0",
|
|
48
|
-
"stream-to-string": "^1.2.
|
|
47
|
+
"stream-to-string": "^1.2.1",
|
|
49
48
|
"superagent": "^6.0.0",
|
|
50
|
-
"util.promisify": "^1.0.1",
|
|
51
49
|
"yaml-js": "^0.2.3",
|
|
52
50
|
"yesno": "^0.3.1",
|
|
53
51
|
"z-schema": "^5.0.0",
|
|
@@ -61,7 +59,7 @@
|
|
|
61
59
|
"@babel/plugin-proposal-optional-chaining": "7.12.7",
|
|
62
60
|
"@babel/preset-env": "7.12.11",
|
|
63
61
|
"babel-eslint": "10.1.0",
|
|
64
|
-
"babel-jest": "
|
|
62
|
+
"babel-jest": "28.1.2",
|
|
65
63
|
"dedent": "0.7.0",
|
|
66
64
|
"eslint": "7.15.0",
|
|
67
65
|
"eslint-config-prettier": "7.0.0",
|
|
@@ -70,12 +68,10 @@
|
|
|
70
68
|
"flat": "5.0.2",
|
|
71
69
|
"fs-monkey": "1.0.1",
|
|
72
70
|
"husky": "5.0.6",
|
|
73
|
-
"jest": "
|
|
74
|
-
"jest-extended": "0.11.5",
|
|
71
|
+
"jest": "28.1.2",
|
|
75
72
|
"lint-staged": "10.5.3",
|
|
76
73
|
"memfs": "3.2.0",
|
|
77
74
|
"mock-stdin": "1.0.0",
|
|
78
|
-
"pinst": "2.1.1",
|
|
79
75
|
"prettier": "2.2.1",
|
|
80
76
|
"unionfs": "4.4.0",
|
|
81
77
|
"waait": "1.0.5"
|