resume-cli 3.0.2 → 3.0.6

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/lib/builder.js DELETED
@@ -1,66 +0,0 @@
1
- const themeServer =
2
- process.env.THEME_SERVER || 'https://themes.jsonresume.org/theme/';
3
- const fs = require('fs');
4
- const request = require('superagent');
5
- const chalk = require('chalk');
6
- const renderHtml = require('./render-html');
7
-
8
- const denormalizeTheme = (value) => {
9
- return value.match(/jsonresume-theme-(.*)/)[1];
10
- };
11
-
12
- const sendExportHTML = (resumeJson, theme, callback) => {
13
- console.log(resumeJson, theme);
14
- console.log('Requesting theme from server...');
15
-
16
- request
17
- .post(themeServer + denormalizeTheme(theme))
18
- .send({
19
- resume: resumeJson,
20
- })
21
- .set('Accept', 'application/json')
22
- .end((err, response) => {
23
- if (err) {
24
- callback(
25
- 'There was an error downloading your generated html resume from our server: ' +
26
- err,
27
- );
28
- } else if (response.text) {
29
- callback(null, response.text);
30
- } else {
31
- callback(
32
- 'There was an error downloading your generated html resume from our server.',
33
- );
34
- }
35
- });
36
- };
37
- module.exports = function resumeBuilder(theme, dir, resumeFilename, cb) {
38
- fs.readFile(resumeFilename, async (err, resumeJson) => {
39
- if (err) {
40
- console.log(chalk.yellow('Could not find:'), resumeFilename);
41
- console.log(
42
- chalk.cyan('Using example resume.json from resume-schema instead...'),
43
- );
44
- resumeJson = require('resume-schema').resumeJson;
45
- } else {
46
- try {
47
- // todo: test resume schema
48
- resumeJson = JSON.parse(resumeJson);
49
- } catch (e) {
50
- err = 'Parse error: ' + resumeFilename;
51
- return cb(err);
52
- }
53
- }
54
-
55
- try {
56
- const html = await renderHtml({ resume: resumeJson, themePath: theme });
57
- cb(null, html);
58
- } catch (err) {
59
- console.log(err);
60
- console.log(
61
- chalk.yellow('Could not run the render function from local theme.'),
62
- );
63
- sendExportHTML(resumeJson, theme, cb);
64
- }
65
- });
66
- };
package/lib/get-resume.js DELETED
@@ -1,38 +0,0 @@
1
- import fs from 'fs';
2
- import { lookup } from 'mime-types';
3
- import { resolve as resolvePath } from 'path';
4
- import quaff from 'quaff';
5
- import toString from 'stream-to-string';
6
- import yaml from 'yaml-js';
7
- import { promisify } from 'util';
8
-
9
- const { createReadStream } = fs;
10
- const stat = promisify(fs.stat);
11
-
12
- const parsers = {
13
- 'text/yaml': (string) => yaml.load(string),
14
- 'application/json': (string) => JSON.parse(string),
15
- };
16
- export default async ({ path, mime: inputMime }) => {
17
- let input;
18
- let mime;
19
- if ('-' === path) {
20
- mime = inputMime || lookup('.json');
21
- input = process.stdin;
22
- } else if (path && (await stat(path)).isDirectory()) {
23
- return quaff(path);
24
- }
25
- if (!input) {
26
- mime = inputMime || lookup(path);
27
- input = createReadStream(resolvePath(process.cwd(), path));
28
- }
29
- if (!input) {
30
- throw new Error('resume could not be gotten from path or stdin');
31
- }
32
- const resumeString = await toString(input);
33
- const parser = parsers[mime];
34
- if (!parser) {
35
- throw new Error(`no parser available for detected mime type ${mime}`);
36
- }
37
- return parser(resumeString);
38
- };
@@ -1,73 +0,0 @@
1
- import wait from 'waait';
2
- import getResume from './get-resume';
3
- import { stdin as mockStdin } from 'mock-stdin';
4
-
5
- jest.mock('fs', () => {
6
- const build = require('./test-utils/mocked-volume-builder');
7
- const { createFsFromVolume } = require('memfs');
8
- const vol = build();
9
- return createFsFromVolume(vol);
10
- });
11
-
12
- describe('get-resume', () => {
13
- it('should consume yaml', async () => {
14
- expect(await getResume({ path: '/resume.yaml' })).toMatchInlineSnapshot(`
15
- Object {
16
- "basics": Object {
17
- "email": "thomas@example.com",
18
- "name": "thomas",
19
- },
20
- }
21
- `);
22
- });
23
- it('should consume json', async () => {
24
- expect(await getResume({ path: '/resume.json' })).toMatchInlineSnapshot(`
25
- Object {
26
- "basics": Object {
27
- "email": "thomas@example.com",
28
- "name": "thomas",
29
- },
30
- }
31
- `);
32
- });
33
- it('should consume an entire directory as if it were a json object', async () => {
34
- expect(await getResume({ path: '/quaff' })).toMatchInlineSnapshot(`
35
- Object {
36
- "basics": Object {
37
- "email": "thomas@example.com",
38
- "name": "thomas",
39
- },
40
- "work": Array [
41
- Object {
42
- "company": "Pied Piper",
43
- "endDate": "2014-12-01",
44
- "position": "CEO/President",
45
- "startDate": "2013-12-01",
46
- },
47
- ],
48
- }
49
- `);
50
- });
51
- it('should read from process.stdin when path is a dash', async () => {
52
- const stdin = mockStdin();
53
- const gotResume = getResume({ path: '-' });
54
- await wait();
55
- stdin.send(
56
- JSON.stringify({
57
- basics: {
58
- name: 'thomas',
59
- email: 'thomas@example.com',
60
- },
61
- }),
62
- );
63
- stdin.send(null);
64
- expect(await gotResume).toMatchInlineSnapshot(`
65
- Object {
66
- "basics": Object {
67
- "email": "thomas@example.com",
68
- "name": "thomas",
69
- },
70
- }
71
- `);
72
- });
73
- });
package/lib/get-schema.js DELETED
@@ -1,16 +0,0 @@
1
- import { readFile as readFileCB } from 'fs';
2
- import { promisify } from 'util';
3
-
4
- const readFile = promisify(readFileCB);
5
-
6
- export default async ({ path: pathArg } = {}) => {
7
- let path = pathArg;
8
- if (!path) {
9
- path = require.resolve('resume-schema/schema.json');
10
- }
11
- return JSON.parse(
12
- await readFile(path, {
13
- encoding: 'utf-8',
14
- }),
15
- );
16
- };
package/lib/init.js DELETED
@@ -1,56 +0,0 @@
1
- import { promisify } from 'util';
2
- import fs from 'fs';
3
- import chalk from 'chalk';
4
- import yesno from 'yesno';
5
- import { set } from 'object-path-immutable';
6
- import exists from 'file-exists';
7
- import readCB from 'read';
8
-
9
- const writeFile = promisify(fs.writeFile);
10
- const read = promisify(readCB);
11
- const resume = require('resume-schema/sample.resume.json');
12
-
13
- export default async ({ resumePath }) => {
14
- if (await exists(resumePath)) {
15
- console.log(
16
- chalk.yellow('There is already a resume.json file in this directory.'),
17
- );
18
- if (!(await yesno({ question: 'Do you want to override?' }))) {
19
- return;
20
- }
21
- }
22
- console.log(`This utility will generate a file at ${resumePath}.`);
23
- console.log(
24
- 'Fill out your name and email to get started, or leave the fields blank.',
25
- );
26
- console.log('All fields are optional.\n');
27
- console.log('Press ^C at any time to quit.');
28
-
29
- const name = await read({
30
- prompt: 'name: ',
31
- });
32
- const email = await read({
33
- prompt: 'email: ',
34
- });
35
-
36
- const personalizedResume = Object.entries({
37
- name,
38
- email,
39
- }).reduce((acc, [key, value]) => set(acc, `basics.${key}`, value), resume);
40
- await writeFile(resumePath, JSON.stringify(personalizedResume, undefined, 2));
41
-
42
- console.log(`Your resume has been created at ${resumePath}`);
43
- console.log('');
44
- console.log(
45
- 'To generate a formatted .html .md .txt or .pdf resume from your resume',
46
- );
47
- console.log(
48
- 'type: `resume export [someFileName]` including file extension eg: `resume export myresume.html`',
49
- );
50
- console.log(
51
- '\nYou can optionally specify an available theme for html and pdf resumes using the --theme flag.',
52
- );
53
- console.log('Example: `resume export myresume.pdf --theme even`');
54
- console.log('Or simply type: `resume export` and follow the prompts.');
55
- console.log('');
56
- };
package/lib/main.js DELETED
@@ -1,136 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import 'dotenv/config';
4
-
5
- import init from './init';
6
- import getResume from './get-resume';
7
- import getSchema from './get-schema';
8
- import validate from './validate';
9
-
10
- const pkg = require('../package.json');
11
- const exportResume = require('./export-resume');
12
- const serve = require('./serve');
13
- const program = require('commander');
14
- const chalk = require('chalk');
15
- const path = require('path');
16
-
17
- const normalizeTheme = (value, defaultValue) => {
18
- const theme = value || defaultValue;
19
- // TODO - This is not great, but bypasses this function if it is a relative path
20
- if (theme[0] === '.') {
21
- return theme;
22
- }
23
- return theme.match('jsonresume-theme-.*')
24
- ? theme
25
- : `jsonresume-theme-${theme}`;
26
- };
27
-
28
- (async () => {
29
- program
30
- .name('resume')
31
- .usage('[command] [options]')
32
- .version(pkg.version)
33
- .option(
34
- '-F, --force',
35
- 'Used by `publish` and `export` - bypasses schema testing.',
36
- )
37
- .option(
38
- '-t, --theme <theme name>',
39
- 'Specify theme used by `export` and `serve` or specify a path starting with . (use . for current directory or ../some/other/dir)',
40
- normalizeTheme,
41
- 'jsonresume-theme-even',
42
- )
43
- .option('-f, --format <file type extension>', 'Used by `export`.')
44
- .option(
45
- '-r, --resume <resume filename>',
46
- "path to the resume in json format. Use '-' to read from stdin",
47
- 'resume.json',
48
- )
49
- .option('-p, --port <port>', 'Used by `serve` (default: 4000)', 4000)
50
- .option(
51
- '-s, --silent',
52
- 'Used by `serve` to tell it if open browser auto or not.',
53
- false,
54
- )
55
- .option(
56
- '-d, --dir <path>',
57
- 'Used by `serve` to indicate a public directory path.',
58
- 'public',
59
- )
60
- .option(
61
- '--schema <relativePath>',
62
- 'Used by `validate` to validate against a custom schema.',
63
- );
64
-
65
- program
66
- .command('init')
67
- .description('Initialize a resume.json file')
68
- .action(async () => {
69
- await init({ resumePath: program.resume });
70
- });
71
-
72
- program
73
- .command('validate')
74
- .description("Validate your resume's schema")
75
- .action(async () => {
76
- const resume = await getResume({ path: program.resume });
77
- const schema = await getSchema({ path: program.schema });
78
- try {
79
- await validate({
80
- resume,
81
- schema,
82
- });
83
- } catch (e) {
84
- console.error(e.message);
85
- process.exitCode = 1;
86
- }
87
- });
88
-
89
- program
90
- .command('export [fileName]')
91
- .description(
92
- 'Export locally to .html or .pdf. Supply a --format <file format> flag and argument to specify export format.',
93
- )
94
- .action(async (fileName) => {
95
- const resume = await getResume({ path: program.resume });
96
- exportResume(
97
- { ...program, resume, fileName },
98
- (err, fileName, format) => {
99
- console.log(
100
- chalk.green(
101
- '\nDone! Find your new',
102
- format,
103
- 'resume at:\n',
104
- path.resolve(process.cwd(), fileName + format),
105
- ),
106
- );
107
- },
108
- );
109
- });
110
-
111
- program
112
- .command('serve')
113
- .description('Serve resume at http://localhost:4000/')
114
- .action(async () => {
115
- serve({
116
- ...program,
117
- resumeFilename: program.resume,
118
- });
119
- });
120
-
121
- await program.parseAsync(process.argv);
122
-
123
- const validCommands = program.commands.map((cmd) => {
124
- return cmd._name;
125
- });
126
-
127
- // https://github.com/tj/commander.js/blob/master/CHANGELOG.md#testing-for-no-arguments
128
- if (program.rawArgs.length < 3) {
129
- console.log(chalk.cyan('resume-cli:'), 'https://jsonresume.org', '\n');
130
- program.help();
131
- } else if (validCommands.indexOf(process.argv[2]) === -1) {
132
- console.log(chalk.red('Invalid argument:'), process.argv[2]);
133
- console.log(chalk.cyan('resume-cli:'), 'https://jsonresume.org', '\n');
134
- program.help();
135
- }
136
- })();
package/lib/main.test.js DELETED
@@ -1,155 +0,0 @@
1
- import { spawn, exec as execCB } from 'child_process';
2
- import streamToString from 'stream-to-string';
3
- import { promisify } from 'util';
4
- import packageJson from '../package.json';
5
-
6
- const exec = promisify(execCB);
7
-
8
- const run = async (argv, { waitForVolumeExport = true, stdin = '' } = {}) => {
9
- let volume;
10
- let exitCode;
11
- const child = spawn(
12
- process.execPath,
13
- ['build/test-utils/cli-test-entry.js', ...argv],
14
- {
15
- stdio: ['pipe', 'pipe', 2, 'ipc'],
16
- },
17
- );
18
- const allChecks = Promise.all([
19
- waitForVolumeExport
20
- ? new Promise((volumeSet) => {
21
- child.on('message', async (message) => {
22
- if (message.type === 'volumeExport') {
23
- volume = message.data;
24
- volumeSet();
25
- }
26
- });
27
- })
28
- : true,
29
- new Promise((processExited) => {
30
- child.on('exit', (code) => {
31
- exitCode = code;
32
- processExited();
33
- });
34
- }),
35
- ]);
36
- child.stdin.write(stdin);
37
- child.stdin.end();
38
- const stdout = await streamToString(child.stdout);
39
- await allChecks;
40
- return {
41
- volume,
42
- code: exitCode,
43
- stdout,
44
- };
45
- };
46
-
47
- describe('cli configuration', () => {
48
- beforeAll(() => exec(packageJson.scripts.prepare));
49
- it('should show help', async () => {
50
- const { stdout } = await run(['help'], { waitForVolumeExport: false });
51
- expect(stdout).toMatchInlineSnapshot(`
52
- "Usage: resume [command] [options]
53
-
54
- Options:
55
- -V, --version output the version number
56
- -F, --force Used by \`publish\` and \`export\` - bypasses
57
- schema testing.
58
- -t, --theme <theme name> Specify theme used by \`export\` and
59
- \`serve\` or specify a path starting with .
60
- (use . for current directory or
61
- ../some/other/dir) (default:
62
- \\"jsonresume-theme-even\\")
63
- -f, --format <file type extension> Used by \`export\`.
64
- -r, --resume <resume filename> path to the resume in json format. Use
65
- '-' to read from stdin (default:
66
- \\"resume.json\\")
67
- -p, --port <port> Used by \`serve\` (default: 4000) (default:
68
- 4000)
69
- -s, --silent Used by \`serve\` to tell it if open
70
- browser auto or not. (default: false)
71
- -d, --dir <path> Used by \`serve\` to indicate a public
72
- directory path. (default: \\"public\\")
73
- --schema <relativePath> Used by \`validate\` to validate against a
74
- custom schema.
75
- -h, --help display help for command
76
-
77
- Commands:
78
- init Initialize a resume.json file
79
- validate Validate your resume's schema
80
- export [fileName] Export locally to .html or .pdf. Supply
81
- a --format <file format> flag and
82
- argument to specify export format.
83
- serve Serve resume at http://localhost:4000/
84
- help [command] display help for command
85
- "
86
- `);
87
- });
88
- describe('validate', () => {
89
- it('should use the schema override arg', async () => {
90
- const { stdout } = await run([
91
- 'validate',
92
- '--schema',
93
- '/test-resumes/only-number-schema.json',
94
- '--resume',
95
- '/test-resumes/only-number.json',
96
- ]);
97
- expect(stdout).toMatchInlineSnapshot(`""`);
98
- });
99
- it('should fail when trying to validate an invalid resume specified by the --resume option', async () => {
100
- expect(
101
- (
102
- await run([
103
- 'validate',
104
- '--resume',
105
- '/test-resumes/invalid-resume.json',
106
- ])
107
- ).code,
108
- ).toEqual(1);
109
- });
110
- it('should validate a resume specified by the --resume option', async () => {
111
- const { stdout } = await run([
112
- 'validate',
113
- '--resume',
114
- '/test-resumes/resume.json',
115
- ]);
116
- expect(stdout).toMatchInlineSnapshot(`""`);
117
- });
118
- });
119
- describe('export', () => {
120
- it('should read from stdin when path is a dash', async () => {
121
- const { stdout, volume } = await run(
122
- [
123
- 'export',
124
- '/test-resumes/exported-resume-from-stdin.html',
125
- '--resume',
126
- '-', // this is the dash
127
- ],
128
- { stdin: JSON.stringify({ basics: { name: 'thomas-from-stdin' } }) },
129
- );
130
- expect(volume['/test-resumes/exported-resume-from-stdin.html']).toEqual(
131
- expect.stringContaining('thomas-from-stdin'),
132
- );
133
- expect(stdout).toMatchInlineSnapshot(`
134
- "
135
- Done! Find your new .html resume at:
136
- /test-resumes/exported-resume-from-stdin.html
137
- "
138
- `);
139
- });
140
- it('should export a resume from the path specified by --resume to the path specified immediately after the export command', async () => {
141
- const { stdout } = await run([
142
- 'export',
143
- '/test-resumes/exported-resume.html',
144
- '--resume',
145
- '/test-resumes/resume.json',
146
- ]);
147
- expect(stdout).toMatchInlineSnapshot(`
148
- "
149
- Done! Find your new .html resume at:
150
- /test-resumes/exported-resume.html
151
- "
152
- `);
153
- });
154
- });
155
- });
@@ -1,35 +0,0 @@
1
- const tryResolve = (...args) => {
2
- try {
3
- return require.resolve(...args);
4
- } catch (err) {
5
- return false;
6
- }
7
- };
8
-
9
- export default async ({ resume, themePath }) => {
10
- const cwd = process.cwd();
11
- let path;
12
- if (themePath[0] === '.') {
13
- path = tryResolve(path.join(cwd, themePath), { paths: [cwd] });
14
- throw new Error(
15
- `Theme ${themePath} could not be resolved relative to ${cwd}`,
16
- );
17
- }
18
- if (!path) {
19
- path = tryResolve(themePath, { paths: [cwd] });
20
- }
21
- if (!path && /^[a-z0-9]/i.test(path)) {
22
- path = tryResolve(`jsonresume-theme-${themePath}`, { paths: [cwd] });
23
- }
24
- if (!path) {
25
- throw new Error(
26
- `theme path ${themePath} could not be resolved from current working directory`,
27
- );
28
- }
29
- const theme = require(path);
30
- if (typeof theme?.render !== 'function') {
31
- throw new Error('theme.render is not a function');
32
- }
33
-
34
- return theme.render(resume);
35
- };
@@ -1,47 +0,0 @@
1
- import renderHTML from './render-html';
2
-
3
- describe('renderHTML', () => {
4
- beforeAll(() => {
5
- const originalRequireResolve = require.resolve;
6
- const mockThemePath = 'mock/path/to/jsonresume-theme-even';
7
- require.resolve = (...args) => {
8
- if (args[0] === 'jsonresume-theme-even') {
9
- return mockThemePath;
10
- }
11
- if (args[0] === 'jsonresume-theme-even') {
12
- return mockThemePath;
13
- }
14
- return originalRequireResolve.apply(require, ...args);
15
- };
16
- require.cache[mockThemePath] = {
17
- render: () => 'here-is-your-mocked-theme',
18
- };
19
- });
20
- const resume = {
21
- basics: {
22
- name: 'test',
23
- label: 'Programmer',
24
- email: 'test4@test.com',
25
- },
26
- };
27
-
28
- it('should reject when theme is not availlable', async () => {
29
- await expect(
30
- renderHTML({ resume, themePath: 'unknown' }),
31
- ).rejects.toBeTruthy();
32
- });
33
-
34
- describe('should render html when theme is availlable', () => {
35
- it('with long theme name', async () => {
36
- expect(
37
- await renderHTML({ resume, themePath: 'jsonresume-theme-even' }),
38
- ).toStartWith('<!doctype html>');
39
- });
40
-
41
- it('with short theme name', async () => {
42
- expect(await renderHTML({ resume, themePath: 'even' })).toStartWith(
43
- '<!doctype html>',
44
- );
45
- });
46
- });
47
- });
@@ -1,12 +0,0 @@
1
- import build from './mocked-volume-builder';
2
- import { patchFs } from 'fs-monkey';
3
- import { ufs } from 'unionfs';
4
- import * as fs from 'fs';
5
-
6
- const mockVolume = build({ mount: '/test-resumes' });
7
- const vol = ufs.use(mockVolume).use(fs);
8
- patchFs(vol);
9
- require('../main.js');
10
- process.once('beforeExit', () => {
11
- process.send({ data: mockVolume.toJSON(), type: 'volumeExport' });
12
- });
@@ -1,45 +0,0 @@
1
- module.exports = ({ mount = '/' } = {}) => {
2
- const dedent = require('dedent');
3
- const flat = require('flat');
4
- const { Volume } = require('memfs');
5
- return Volume.fromJSON(
6
- flat(
7
- {
8
- 'only-number-schema.json': JSON.stringify({ type: 'number' }),
9
- 'only-number.json': '123',
10
- 'invalid-resume.json': JSON.stringify({
11
- notAValidKey: {
12
- foo: 'bar',
13
- },
14
- }),
15
- 'resume.json': JSON.stringify({
16
- basics: {
17
- name: 'thomas',
18
- email: 'thomas@example.com',
19
- },
20
- }),
21
- 'resume.yaml': dedent`
22
- basics:
23
- name: thomas
24
- email: thomas@example.com
25
- `,
26
- quaff: {
27
- 'basics.yaml': dedent`
28
- name: thomas
29
- email: thomas@example.com
30
- `,
31
- 'work.json': JSON.stringify([
32
- {
33
- company: 'Pied Piper',
34
- endDate: '2014-12-01',
35
- position: 'CEO/President',
36
- startDate: '2013-12-01',
37
- },
38
- ]),
39
- },
40
- },
41
- { delimiter: '/' },
42
- ),
43
- mount,
44
- );
45
- };