diff --git a/README.md b/README.md index 00300d35..2afea589 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,13 @@ When developing themes, simply change into your theme directory and run `resume # resume data -Resume data is read from `stdin` if [`stdin.isTTY`](https://nodejs.org/api/tty.html#tty_readstream_istty) is falsy. Otherwise, the resume is read from `--path` as resolved from `process.cwd()`. `--type` defaults to `application/json`. Supported resume data mime types are: +- Setting `--resume -` tells the cli to read resume data from standard input (`stdin`), and defaults `--type` to `application/json`. +- Setting `--resume ` reads resume data from `path`. +- Leaving `--resume` unset defaults to reading from `resume.json` on the current working directory. + +# resume mime types + +Supported resume data mime types are: - `application/json` - `text/yaml` diff --git a/lib/get-resume.js b/lib/get-resume.js index 2cded611..fd4f2a2f 100644 --- a/lib/get-resume.js +++ b/lib/get-resume.js @@ -5,7 +5,6 @@ import quaff from 'quaff'; import toString from 'stream-to-string'; import yaml from 'yaml-js'; import { promisify } from 'util'; -import { not as stdinIsNotAPipe } from './utils/stdin-is-pipe'; const { createReadStream } = fs; const stat = promisify(fs.stat); @@ -15,19 +14,20 @@ const parsers = { 'application/json': (string) => JSON.parse(string), }; export default async ({ path, mime: inputMime }) => { - if (path && (await stat(path)).isDirectory()) { - const quaffed = quaff(path); - return quaffed; - } let input; let mime; - if ((await stdinIsNotAPipe()) && path) { + if ('-' === path) { + mime = inputMime || lookup('.json'); + input = process.stdin; + } else if (path && (await stat(path)).isDirectory()) { + return quaff(path); + } + if (!input) { mime = inputMime || lookup(path); input = createReadStream(resolvePath(process.cwd(), path)); } if (!input) { - mime = inputMime || lookup('.json'); - input = process.stdin; + throw new Error('resume could not be gotten from path or stdin'); } const resumeString = await toString(input); const parser = parsers[mime]; diff --git a/lib/get-resume.test.js b/lib/get-resume.test.js index 21b41356..5e80ac93 100644 --- a/lib/get-resume.test.js +++ b/lib/get-resume.test.js @@ -48,9 +48,9 @@ describe('get-resume', () => { } `); }); - it('should read from process.stdin when path is falsy', async () => { + it('should read from process.stdin when path is a dash', async () => { const stdin = mockStdin(); - const gotResume = getResume({}); + const gotResume = getResume({ path: '-' }); await wait(); stdin.send( JSON.stringify({ diff --git a/lib/main.js b/lib/main.js index 9d22484e..e72db6fa 100755 --- a/lib/main.js +++ b/lib/main.js @@ -43,7 +43,7 @@ const normalizeTheme = (value, defaultValue) => { .option('-f, --format ', 'Used by `export`.') .option( '-r, --resume ', - 'path to the resume in json format', + "path to the resume in json format. Use '-' to read from stdin", 'resume.json', ) .option('-p, --port ', 'Used by `serve` (default: 4000)', 4000) diff --git a/lib/main.test.js b/lib/main.test.js index c0445f65..b932b93d 100644 --- a/lib/main.test.js +++ b/lib/main.test.js @@ -1,18 +1,54 @@ -import { exec as execCB } from 'child_process'; +import { spawn, exec as execCB } from 'child_process'; +import streamToString from 'stream-to-string'; import { promisify } from 'util'; import packageJson from '../package.json'; const exec = promisify(execCB); -const run = (argv) => - exec( - [process.execPath, 'build/test-utils/cli-test-entry.js', argv].join(' '), +const run = async (argv, { waitForVolumeExport = true, stdin = '' } = {}) => { + let volume; + let exitCode; + const child = spawn( + process.execPath, + ['build/test-utils/cli-test-entry.js', ...argv], + { + stdio: ['pipe', 'pipe', 2, 'ipc'], + }, ); + const allChecks = Promise.all([ + waitForVolumeExport + ? new Promise((volumeSet) => { + child.on('message', async (message) => { + if (message.type === 'volumeExport') { + volume = message.data; + volumeSet(); + } + }); + }) + : true, + new Promise((processExited) => { + child.on('exit', (code) => { + exitCode = code; + processExited(); + }); + }), + ]); + child.stdin.write(stdin); + child.stdin.end(); + const stdout = await streamToString(child.stdout); + await allChecks; + return { + volume, + code: exitCode, + stdout, + }; +}; describe('cli configuration', () => { beforeAll(() => exec(packageJson.scripts.prepare)); it('should show help', async () => { - expect((await run('help')).stdout).toMatchInlineSnapshot(` + const { stdout } = await run(['help'], { waitForVolumeExport: false }); + expect(stdout).toMatchInlineSnapshot(` "Usage: resume [command] [options] Options: @@ -25,8 +61,9 @@ describe('cli configuration', () => { ../some/other/dir) (default: \\"jsonresume-theme-even\\") -f, --format Used by \`export\`. - -r, --resume path to the resume in json format - (default: \\"resume.json\\") + -r, --resume path to the resume in json format. Use + '-' to read from stdin (default: + \\"resume.json\\") -p, --port Used by \`serve\` (default: 4000) (default: 4000) -s, --silent Used by \`serve\` to tell it if open @@ -50,37 +87,69 @@ describe('cli configuration', () => { }); describe('validate', () => { it('should use the schema override arg', async () => { - const output = await run('validate --schema /test-resumes/only-number-schema.json --resume /test-resumes/only-number.json') - expect(output.stdout).toMatchInlineSnapshot(`""`); - expect(output.stderr).toMatchInlineSnapshot(`""`); - }) + const { stdout } = await run([ + 'validate', + '--schema', + '/test-resumes/only-number-schema.json', + '--resume', + '/test-resumes/only-number.json', + ]); + expect(stdout).toMatchInlineSnapshot(`""`); + }); it('should fail when trying to validate an invalid resume specified by the --resume option', async () => { - await expect( - run('validate --resume /test-resumes/invalid-resume.json'), - ).rejects.toEqual( - expect.objectContaining({ - code: 1, - }), - ); + expect( + ( + await run([ + 'validate', + '--resume', + '/test-resumes/invalid-resume.json', + ]) + ).code, + ).toEqual(1); }); it('should validate a resume specified by the --resume option', async () => { - const output = await run('validate --resume /test-resumes/resume.json'); - expect(output.stdout).toMatchInlineSnapshot(`""`); - expect(output.stderr).toMatchInlineSnapshot(`""`); + const { stdout } = await run([ + 'validate', + '--resume', + '/test-resumes/resume.json', + ]); + expect(stdout).toMatchInlineSnapshot(`""`); }); }); describe('export', () => { - it('should export a resume from the path specified by --resume to the path specified immediately after the export command', async () => { - const output = await run( - 'export /test-resumes/exported-resume.html --resume /test-resumes/resume.json', + it('should read from stdin when path is a dash', async () => { + const { stdout, volume } = await run( + [ + 'export', + '/test-resumes/exported-resume-from-stdin.html', + '--resume', + '-', // this is the dash + ], + { stdin: JSON.stringify({ basics: { name: 'thomas-from-stdin' } }) }, ); - expect(output.stdout).toMatchInlineSnapshot(` + expect(volume['/test-resumes/exported-resume-from-stdin.html']).toEqual( + expect.stringContaining('thomas-from-stdin'), + ); + expect(stdout).toMatchInlineSnapshot(` + " + Done! Find your new .html resume at: + /test-resumes/exported-resume-from-stdin.html + " + `); + }); + it('should export a resume from the path specified by --resume to the path specified immediately after the export command', async () => { + const { stdout } = await run([ + 'export', + '/test-resumes/exported-resume.html', + '--resume', + '/test-resumes/resume.json', + ]); + expect(stdout).toMatchInlineSnapshot(` " Done! Find your new .html resume at: /test-resumes/exported-resume.html " `); - expect(output.stderr).toMatchInlineSnapshot(`""`); }); }); }); diff --git a/lib/test-utils/cli-test-entry.js b/lib/test-utils/cli-test-entry.js index 69bec73d..40e1ee2a 100644 --- a/lib/test-utils/cli-test-entry.js +++ b/lib/test-utils/cli-test-entry.js @@ -3,6 +3,10 @@ import { patchFs } from 'fs-monkey'; import { ufs } from 'unionfs'; import * as fs from 'fs'; -const vol = ufs.use(build({ mount: '/test-resumes' })).use(fs); +const mockVolume = build({ mount: '/test-resumes' }); +const vol = ufs.use(mockVolume).use(fs); patchFs(vol); require('../main.js'); +process.once('beforeExit', () => { + process.send({ data: mockVolume.toJSON(), type: 'volumeExport' }); +}); diff --git a/lib/utils/stdin-is-pipe.js b/lib/utils/stdin-is-pipe.js deleted file mode 100644 index dff4ad2c..00000000 --- a/lib/utils/stdin-is-pipe.js +++ /dev/null @@ -1,16 +0,0 @@ -import { fstat as fstatCB } from 'fs'; -import { promisify } from 'util'; - -const fstat = promisify(fstatCB); - -const is = async () => { - try { - const fstatStdin = await fstat(process.stdin.fd); - return fstatStdin.isFIFO(); - } catch { - // probably EBADF: bad file descriptor, fstat node stdin - } - return !process.stdin.isTTY; -}; -export const not = async () => !(await is()); -export default is; diff --git a/package-lock.json b/package-lock.json index 3f14ac5b..5f979005 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2809,6 +2809,12 @@ "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", "dev": true }, + "@types/minimist": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.1.tgz", + "integrity": "sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg==", + "dev": true + }, "@types/node": { "version": "14.14.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.8.tgz", @@ -3098,6 +3104,12 @@ "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -3808,6 +3820,17 @@ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, + "camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + } + }, "caniuse-lite": { "version": "1.0.30001165", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001165.tgz", @@ -4159,12 +4182,6 @@ "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, - "compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", - "dev": true - }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", @@ -4373,6 +4390,24 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + } + } + }, "decimal.js": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", @@ -4462,6 +4497,12 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "detect-indent": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.0.0.tgz", + "integrity": "sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA==", + "dev": true + }, "detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -5427,15 +5468,6 @@ "locate-path": "^3.0.0" } }, - "find-versions": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", - "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", - "dev": true, - "requires": { - "semver-regex": "^2.0.0" - } - }, "flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -5701,6 +5733,12 @@ "har-schema": "^2.0.0" } }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -5898,22 +5936,10 @@ "dev": true }, "husky": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.5.tgz", - "integrity": "sha512-E5S/1HMoDDaqsH8kDF5zeKEQbYqe3wL9zJDyqyYqc8I4vHBtAoxkDBGXox0lZ9RI+k5GyB728vZdmnM4bYap+g==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "ci-info": "^2.0.0", - "compare-versions": "^3.6.0", - "cosmiconfig": "^7.0.0", - "find-versions": "^3.2.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.2.0", - "slash": "^3.0.0", - "which-pm-runs": "^1.0.0" - } + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/husky/-/husky-5.0.6.tgz", + "integrity": "sha512-SM+evfvcHT3rAYJKvPlatz3L5RqzgeM6xIvDjhs8VuhKj6iKqFDOt/Ov8sPjvWuE4FDB385gJBwWXRj7G3c1hg==", + "dev": true }, "iconv-lite": { "version": "0.4.24", @@ -6184,6 +6210,12 @@ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -9016,6 +9048,32 @@ } } }, + "load-json-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } + } + }, "localtunnel": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.0.tgz", @@ -9194,6 +9252,12 @@ "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", "integrity": "sha1-+4m2WpqAKBgz8LdHizpRBPiY67M=" }, + "lodash.mapkeys": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mapkeys/-/lodash.mapkeys-4.6.0.tgz", + "integrity": "sha1-3yz6Ix18V8eorQA6va1dc9PqUZU=", + "dev": true + }, "lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", @@ -9270,6 +9334,15 @@ } } }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", @@ -9302,6 +9375,12 @@ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" }, + "map-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.1.0.tgz", + "integrity": "sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==", + "dev": true + }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", @@ -9319,6 +9398,60 @@ "fs-monkey": "1.0.1" } }, + "meow": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.0.0.tgz", + "integrity": "sha512-nbsTRz2fwniJBFgUkcdISq8y/q9n9VbiHYbfwklFh5V4V2uAcxtKQkDc0yCLPM/kP0d+inZBewn3zJqewHE7kg==", + "dev": true, + "requires": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "dependencies": { + "hosted-git-info": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.7.tgz", + "integrity": "sha512-fWqc0IcuXs+BmE9orLDyVykAG9GJtGLGuZAAqgcckPgv5xad4AcXGIv8galtQvlwutxSlaMcdw7BUtq2EIvqCQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "normalize-package-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.0.tgz", + "integrity": "sha512-6lUjEI0d3v6kFrtgA/lOx4zHCWULXsFNIjHolnZCKCTLA6m/G625cdn3O7eNmT0iD3jfo6HZ9cdImGZwf21prw==", + "dev": true, + "requires": { + "hosted-git-info": "^3.0.6", + "resolve": "^1.17.0", + "semver": "^7.3.2", + "validate-npm-package-license": "^3.0.1" + } + }, + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + } + } + }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -9393,6 +9526,12 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -9406,6 +9545,17 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "requires": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + } + }, "mitt": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz", @@ -9793,12 +9943,6 @@ "mimic-fn": "^2.1.0" } }, - "opencollective-postinstall": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", - "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", - "dev": true - }, "openurl": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", @@ -9991,6 +10135,18 @@ "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, + "pinst": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pinst/-/pinst-2.1.1.tgz", + "integrity": "sha512-n8P1bTw2B3Ff/wkG2yP7HN3wBIkobfkuNS5WNhsUrM+/QTSJUZc2n/WPUSxONRjaXMffmjCNDTjwDy0ptVHlbw==", + "dev": true, + "requires": { + "load-json-file": "^6.2.0", + "lodash.mapkeys": "^4.6.0", + "meow": "^8.0.0", + "write-json-file": "^4.3.0" + } + }, "pirates": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", @@ -10224,6 +10380,12 @@ "totalist": "^1.1.0" } }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -10342,6 +10504,16 @@ "picomatch": "^2.2.1" } }, + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "requires": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + } + }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -10861,12 +11033,6 @@ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", "dev": true }, - "semver-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", - "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", - "dev": true - }, "send": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", @@ -11348,6 +11514,23 @@ "isarray": "2.0.1" } }, + "sort-keys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.1.0.tgz", + "integrity": "sha512-/sRdxzkkPFUYiCrTr/2t+104nDc9AgDmEpeVYuvOWYQe3Djk1GWO6lVw3Vx2jfh1SsR0eehhd1nvFYlzt5e99w==", + "dev": true, + "requires": { + "is-plain-obj": "^2.0.0" + }, + "dependencies": { + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + } + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -11656,6 +11839,15 @@ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true }, + "strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "requires": { + "min-indent": "^1.0.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -11979,6 +12171,12 @@ "punycode": "^2.1.1" } }, + "trim-newlines": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.0.tgz", + "integrity": "sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==", + "dev": true + }, "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", @@ -12362,12 +12560,6 @@ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "which-pm-runs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", - "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", - "dev": true - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -12480,6 +12672,49 @@ "typedarray-to-buffer": "^3.1.5" } }, + "write-json-file": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/write-json-file/-/write-json-file-4.3.0.tgz", + "integrity": "sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ==", + "dev": true, + "requires": { + "detect-indent": "^6.0.0", + "graceful-fs": "^4.1.15", + "is-plain-obj": "^2.0.0", + "make-dir": "^3.0.0", + "sort-keys": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "ws": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz", @@ -12516,6 +12751,12 @@ "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", "dev": true }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "yaml": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",