diff --git a/.vscode/launch.json b/.vscode/launch.json index b16cc28..1a94586 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,8 @@ "type": "node", "request": "launch", "name": "Debug CLI", + // we test in `build` to make cleanup fast and easy + "cwd": "${workspaceFolder}/build", "program": "${workspaceFolder}/src/cli/cli.ts", "outFiles": ["${workspaceFolder}/build/main/**/*.js"], "skipFiles": [ diff --git a/.vscode/settings.json b/.vscode/settings.json index b633007..41d5c67 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "typescript.tsdk": "node_modules/typescript/lib", - "typescript.implementationsCodeLens.enabled": true, - "typescript.referencesCodeLens.enabled": true + "typescript.tsdk": "node_modules/typescript/lib" + // "typescript.implementationsCodeLens.enabled": true + // "typescript.referencesCodeLens.enabled": true } diff --git a/README.md b/README.md index 03e7daf..e233101 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![Build Status](https://travis-ci.org/bitjson/typescript-starter.svg?branch=master)](https://travis-ci.org/bitjson/typescript-starter) [![Codecov](https://img.shields.io/codecov/c/github/bitjson/typescript-starter.svg)](https://codecov.io/gh/bitjson/typescript-starter) [![Standard Version](https://img.shields.io/badge/release-standard%20version-brightgreen.svg)](https://github.com/conventional-changelog/standard-version) +[![GitHub stars](https://img.shields.io/github/stars/bitjson/typescript-starter.svg?style=social&logo=github&label=Stars)](https://github.com/bitjson/typescript-starter) # typescript-starter @@ -21,7 +22,9 @@ Run one simple command to install and use the interactive project generator. You npx typescript-starter ``` -The interactive CLI will help you automatically create and configure your project. +The interactive CLI will help you create and configure your project automatically. + +> Since this repo includes [the CLI and it's tests](./src/cli), you'll only need to fork or clone this project if you want to contribute. If you find this project useful, please consider [leaving a star](https://github.com/bitjson/typescript-starter/stargazers) so others can find it. Thanks! # Features diff --git a/package-lock.json b/package-lock.json index 86c1d07..fc4ca31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -476,6 +476,15 @@ } } }, + "@mrmlnc/readdir-enhanced": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", + "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", + "requires": { + "call-me-maybe": "1.0.1", + "glob-to-regexp": "0.3.0" + } + }, "@sindresorhus/df": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@sindresorhus/df/-/df-2.1.0.tgz", @@ -527,8 +536,7 @@ "@types/events": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-1.1.0.tgz", - "integrity": "sha512-y3bR98mzYOo0pAZuiLari+cQyiKk3UXRuT45h1RjhfeCzqkjaVsfZJNaxdgtk7/3tzOm1ozLTqEqMP3VbI48jw==", - "dev": true + "integrity": "sha512-y3bR98mzYOo0pAZuiLari+cQyiKk3UXRuT45h1RjhfeCzqkjaVsfZJNaxdgtk7/3tzOm1ozLTqEqMP3VbI48jw==" }, "@types/execa": { "version": "0.8.1", @@ -543,13 +551,20 @@ "version": "5.0.35", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.35.tgz", "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==", - "dev": true, "requires": { "@types/events": "1.1.0", "@types/minimatch": "3.0.3", "@types/node": "8.9.5" } }, + "@types/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/globby/-/globby-6.1.0.tgz", + "integrity": "sha512-j3XSDNoK4LO5T+ZviQD6PqfEjm07QFEacOTbJR3hnLWuWX0ZMLJl9oRPgj1PyrfGbXhfHFkksC9QZ9HFltJyrw==", + "requires": { + "@types/glob": "5.0.35" + } + }, "@types/handlebars": { "version": "4.0.36", "resolved": "https://registry.npmjs.org/@types/handlebars/-/handlebars-4.0.36.tgz", @@ -590,8 +605,7 @@ "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" }, "@types/minimist": { "version": "1.2.0", @@ -620,8 +634,7 @@ "@types/node": { "version": "8.9.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.5.tgz", - "integrity": "sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ==", - "dev": true + "integrity": "sha512-jRHfWsvyMtXdbhnz5CVHxaBgnV6duZnPlQuRSo/dm/GnmikNcmZhxIES4E9OZjUmQ8C+HCl4KJux+cXN/ErGDQ==" }, "@types/ora": { "version": "1.3.2", @@ -1160,14 +1173,12 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" }, "arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" }, "array-differ": { "version": "1.0.0", @@ -1249,8 +1260,7 @@ "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, "async": { "version": "2.6.0", @@ -1276,8 +1286,7 @@ "atob": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/atob/-/atob-2.0.3.tgz", - "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=", - "dev": true + "integrity": "sha1-GcenYEc3dEaPILLS0DNyrX1Mv10=" }, "auto-bind": { "version": "1.2.0", @@ -1373,11 +1382,31 @@ "update-notifier": "2.3.0" }, "dependencies": { + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "dir-glob": "2.0.0", + "glob": "7.1.2", + "ignore": "3.3.7", + "pify": "3.0.0", + "slash": "1.0.0" + } + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true } } }, @@ -1517,7 +1546,6 @@ "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, "requires": { "cache-base": "1.0.1", "class-utils": "0.3.6", @@ -1532,7 +1560,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, "requires": { "is-descriptor": "1.0.2" } @@ -1540,8 +1567,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" } } }, @@ -1616,6 +1642,28 @@ "repeat-element": "1.1.2" } }, + "buffer-alloc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.1.0.tgz", + "integrity": "sha1-BVFNM78WVtNUDGhPZbEgLpDsowM=", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "0.1.1", + "buffer-fill": "0.1.0" + } + }, + "buffer-alloc-unsafe": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-0.1.1.tgz", + "integrity": "sha1-/+H2dVHdBVc33iUzN7/oU9+rGmo=", + "dev": true + }, + "buffer-fill": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-0.1.0.tgz", + "integrity": "sha1-ypRw6NTRuXf9dUP04qtqfclRAag=", + "dev": true + }, "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", @@ -1625,7 +1673,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, "requires": { "collection-visit": "1.0.0", "component-emitter": "1.2.1", @@ -1641,8 +1688,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" } } }, @@ -1691,6 +1737,11 @@ "estraverse": "4.2.0" } }, + "call-me-maybe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" + }, "call-signature": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/call-signature/-/call-signature-0.0.2.tgz", @@ -1934,7 +1985,6 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, "requires": { "arr-union": "3.1.0", "define-property": "0.2.5", @@ -1946,7 +1996,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "0.1.6" } @@ -1955,7 +2004,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -1964,7 +2012,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -1975,7 +2022,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -1984,7 +2030,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -1995,7 +2040,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "requires": { "is-accessor-descriptor": "0.1.6", "is-data-descriptor": "0.1.4", @@ -2005,14 +2049,12 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, @@ -2229,7 +2271,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, "requires": { "map-visit": "1.0.0", "object-visit": "1.0.1" @@ -2300,8 +2341,7 @@ "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" }, "concat-map": { "version": "0.0.1", @@ -3144,8 +3184,7 @@ "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "core-js": { "version": "2.5.3", @@ -3471,8 +3510,7 @@ "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, "decompress-response": { "version": "3.3.0", @@ -3524,7 +3562,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, "requires": { "is-descriptor": "1.0.2", "isobject": "3.0.1" @@ -3533,8 +3570,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" } } }, @@ -3599,7 +3635,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz", "integrity": "sha512-37qirFDz8cA5fimp9feo43fSuRo2gHwaIn6dXL8Ber1dGwUosDrGZeCCXq57WnIqE4aQ+u3eQZzsk1yOzhdwag==", - "dev": true, "requires": { "arrify": "1.0.1", "path-type": "3.0.0" @@ -3609,7 +3644,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, "requires": { "pify": "3.0.0" } @@ -3617,8 +3651,7 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" } } }, @@ -3858,7 +3891,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, "requires": { "assign-symbols": "1.0.0", "is-extendable": "1.0.1" @@ -3868,7 +3900,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, "requires": { "is-plain-object": "2.0.4" } @@ -3906,6 +3937,292 @@ "integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==", "dev": true }, + "fast-glob": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.1.0.tgz", + "integrity": "sha512-QSSKZwDHLznUXdVtWvsfdbojmYI5igtVwfVbKW/LwNsy0JdM1cZ5yyP1kl5npg2ddugdnOk66QlNhbJ1c1hErg==", + "requires": { + "@mrmlnc/readdir-enhanced": "2.2.1", + "glob-parent": "3.1.0", + "is-glob": "4.0.0", + "merge2": "1.2.1", + "micromatch": "3.1.9" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "braces": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz", + "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==", + "requires": { + "arr-flatten": "1.1.0", + "array-unique": "0.3.2", + "define-property": "1.0.0", + "extend-shallow": "2.0.1", + "fill-range": "4.0.0", + "isobject": "3.0.1", + "kind-of": "6.0.2", + "repeat-element": "1.1.2", + "snapdragon": "0.8.1", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "to-regex": "3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "2.6.9", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.1", + "to-regex": "3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "0.1.6" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.1", + "to-regex": "3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "2.0.1", + "is-number": "3.0.0", + "repeat-string": "1.6.1", + "to-regex-range": "2.1.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "0.1.1" + } + } + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "3.1.0", + "path-dirname": "1.0.2" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "2.1.1" + } + } + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "requires": { + "is-extglob": "2.1.1" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + }, + "micromatch": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.9.tgz", + "integrity": "sha512-SlIz6sv5UPaAVVFRKodKjCg48EbNoIhgetzfK/Cy0v5U52Z6zB136M8tp0UC9jM53LYbmIRihJszvvqpKkfm9g==", + "requires": { + "arr-diff": "4.0.0", + "array-unique": "0.3.2", + "braces": "2.3.1", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "extglob": "2.0.4", + "fragment-cache": "0.2.1", + "kind-of": "6.0.2", + "nanomatch": "1.2.9", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.1", + "to-regex": "3.0.1" + } + } + } + }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -3956,8 +4273,7 @@ "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" }, "for-own": { "version": "0.1.5", @@ -3995,7 +4311,6 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, "requires": { "map-cache": "0.2.2" } @@ -5268,8 +5583,7 @@ "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" }, "getpass": { "version": "0.1.7", @@ -5751,6 +6065,11 @@ "is-glob": "2.0.1" } }, + "glob-to-regexp": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=" + }, "global-dirs": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", @@ -5766,13 +6085,13 @@ "dev": true }, "globby": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", - "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", - "dev": true, + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-8.0.1.tgz", + "integrity": "sha512-oMrYrJERnKBLXNLVTqhm3vPEdJ/b2ZE28xN4YARiix1NOIOBPEpOUnm844K1iu/BkphCaf2WNFwMszv8Soi1pw==", "requires": { "array-union": "1.0.2", "dir-glob": "2.0.0", + "fast-glob": "2.1.0", "glob": "7.1.2", "ignore": "3.3.7", "pify": "3.0.0", @@ -5782,8 +6101,7 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" } } }, @@ -5921,7 +6239,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, "requires": { "get-value": "2.0.6", "has-values": "1.0.0", @@ -5931,8 +6248,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" } } }, @@ -5940,7 +6256,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, "requires": { "is-number": "3.0.0", "kind-of": "4.0.0" @@ -5950,7 +6265,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -5959,7 +6273,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -5970,7 +6283,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -6077,8 +6389,7 @@ "ignore": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", - "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", - "dev": true + "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==" }, "ignore-by-default": { "version": "1.0.1", @@ -6180,7 +6491,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "requires": { "kind-of": "6.0.2" }, @@ -6188,8 +6498,7 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -6210,8 +6519,7 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, "is-builtin-module": { "version": "1.0.0", @@ -6240,7 +6548,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "requires": { "kind-of": "6.0.2" }, @@ -6248,8 +6555,7 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -6263,7 +6569,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "requires": { "is-accessor-descriptor": "1.0.0", "is-data-descriptor": "1.0.0", @@ -6273,8 +6578,7 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -6302,8 +6606,7 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" }, "is-extglob": { "version": "1.0.0", @@ -6394,7 +6697,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", - "dev": true, "requires": { "is-number": "4.0.0" }, @@ -6402,8 +6704,7 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" } } }, @@ -6437,7 +6738,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, "requires": { "isobject": "3.0.1" }, @@ -6445,8 +6745,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" } } }, @@ -6533,14 +6832,12 @@ "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -6683,7 +6980,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -6718,7 +7014,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", - "dev": true, "requires": { "set-getter": "0.1.0" } @@ -6936,8 +7231,7 @@ "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" }, "map-obj": { "version": "2.0.0", @@ -6954,7 +7248,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, "requires": { "object-visit": "1.0.1" } @@ -6968,6 +7261,15 @@ "escape-string-regexp": "1.0.5" } }, + "md5-file": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/md5-file/-/md5-file-3.2.3.tgz", + "integrity": "sha512-3Tkp1piAHaworfcCgH0jKbTvj1jWWFgbvh2cXaNCgHwyTCBxxvD1Y04rmfpvdPm1P4oXMOpm6+2H7sr7v9v8Fw==", + "dev": true, + "requires": { + "buffer-alloc": "1.1.0" + } + }, "md5-hex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-2.0.0.tgz", @@ -7072,6 +7374,11 @@ } } }, + "merge2": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.1.tgz", + "integrity": "sha512-wUqcG5pxrAcaFI1lkqkMnk3Q7nUxV/NWfpAFSeWUwG9TRODnBDCUHa75mi3o3vLWQ5N4CQERWCauSlP0I3ZqUg==" + }, "micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", @@ -7145,7 +7452,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", - "dev": true, "requires": { "for-in": "1.0.2", "is-extendable": "1.0.1" @@ -7155,7 +7461,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, "requires": { "is-plain-object": "2.0.4" } @@ -7199,8 +7504,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "multimatch": { "version": "2.1.0", @@ -7230,7 +7534,6 @@ "version": "1.2.9", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", - "dev": true, "requires": { "arr-diff": "4.0.0", "array-unique": "0.3.2", @@ -7249,20 +7552,17 @@ "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" } } }, @@ -9313,7 +9613,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, "requires": { "copy-descriptor": "0.1.1", "define-property": "0.2.5", @@ -9324,7 +9623,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "0.1.6" } @@ -9333,7 +9631,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "requires": { "kind-of": "3.2.2" } @@ -9342,7 +9639,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "requires": { "kind-of": "3.2.2" } @@ -9351,7 +9647,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "requires": { "is-accessor-descriptor": "0.1.6", "is-data-descriptor": "0.1.4", @@ -9361,8 +9656,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } } @@ -9378,7 +9672,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, "requires": { "isobject": "3.0.1" }, @@ -9386,8 +9679,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" } } }, @@ -9405,7 +9697,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, "requires": { "isobject": "3.0.1" }, @@ -9413,8 +9704,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" } } }, @@ -9858,14 +10148,12 @@ "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" }, "path-exists": { "version": "3.0.0", @@ -10012,8 +10300,7 @@ "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, "prepend-http": { "version": "1.0.4", @@ -10276,7 +10563,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, "requires": { "extend-shallow": "3.0.2", "safe-regex": "1.1.0" @@ -10354,14 +10640,12 @@ "repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" }, "repeating": { "version": "2.0.1", @@ -10502,8 +10786,7 @@ "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" }, "restore-cursor": { "version": "2.0.0", @@ -10517,8 +10800,7 @@ "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" }, "right-align": { "version": "0.1.3", @@ -10621,7 +10903,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, "requires": { "ret": "0.1.15" } @@ -10654,7 +10935,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", - "dev": true, "requires": { "to-object-path": "0.3.0" } @@ -10669,7 +10949,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "dev": true, "requires": { "extend-shallow": "2.0.1", "is-extendable": "0.1.1", @@ -10681,7 +10960,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "0.1.1" } @@ -10741,8 +11019,7 @@ "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=" }, "slice-ansi": { "version": "1.0.0", @@ -10763,7 +11040,6 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.1.tgz", "integrity": "sha1-4StUh/re0+PeoKyR6UAL91tAE3A=", - "dev": true, "requires": { "base": "0.11.2", "debug": "2.6.9", @@ -10779,7 +11055,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -10788,7 +11063,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "0.1.6" } @@ -10797,7 +11071,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "0.1.1" } @@ -10806,7 +11079,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -10815,7 +11087,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -10826,7 +11097,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -10835,7 +11105,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -10846,7 +11115,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "requires": { "is-accessor-descriptor": "0.1.6", "is-data-descriptor": "0.1.4", @@ -10856,8 +11124,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, @@ -10865,7 +11132,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, "requires": { "define-property": "1.0.0", "isobject": "3.0.1", @@ -10876,7 +11142,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, "requires": { "is-descriptor": "1.0.2" } @@ -10884,8 +11149,7 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" } } }, @@ -10893,7 +11157,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, "requires": { "kind-of": "3.2.2" } @@ -10927,14 +11190,12 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "source-map-resolve": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", - "dev": true, "requires": { "atob": "2.0.3", "decode-uri-component": "0.2.0", @@ -10963,8 +11224,7 @@ "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" }, "spdx-correct": { "version": "1.0.2", @@ -10997,7 +11257,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, "requires": { "extend-shallow": "3.0.2" } @@ -11140,7 +11399,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, "requires": { "define-property": "0.2.5", "object-copy": "0.1.0" @@ -11150,7 +11408,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "0.1.6" } @@ -11159,7 +11416,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -11168,7 +11424,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -11179,7 +11434,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -11188,7 +11442,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -11199,7 +11452,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "requires": { "is-accessor-descriptor": "0.1.6", "is-data-descriptor": "0.1.4", @@ -11209,8 +11461,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, @@ -11446,7 +11697,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, "requires": { "kind-of": "3.2.2" } @@ -11455,7 +11705,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.1.tgz", "integrity": "sha1-FTWL7kosg712N3uh3ASdDxiDeq4=", - "dev": true, "requires": { "define-property": "0.2.5", "extend-shallow": "2.0.1", @@ -11466,7 +11715,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "0.1.6" } @@ -11475,7 +11723,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "0.1.1" } @@ -11484,7 +11731,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -11493,7 +11739,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -11504,7 +11749,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -11513,7 +11757,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -11524,7 +11767,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "requires": { "is-accessor-descriptor": "0.1.6", "is-data-descriptor": "0.1.4", @@ -11534,8 +11776,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, @@ -11543,7 +11784,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, "requires": { "is-number": "3.0.0", "repeat-string": "1.6.1" @@ -11553,7 +11793,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, "requires": { "kind-of": "3.2.2" } @@ -11585,6 +11824,20 @@ "xdg-trashdir": "2.1.1" }, "dependencies": { + "globby": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-7.1.1.tgz", + "integrity": "sha1-+yzP+UAfhgCUXfral0QMypcrhoA=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "dir-glob": "2.0.0", + "glob": "7.1.2", + "ignore": "3.3.7", + "pify": "3.0.0", + "slash": "1.0.0" + } + }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", @@ -12263,7 +12516,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "dev": true, "requires": { "arr-union": "3.1.0", "get-value": "2.0.6", @@ -12275,7 +12527,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "0.1.1" } @@ -12284,7 +12535,6 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, "requires": { "extend-shallow": "2.0.1", "is-extendable": "0.1.1", @@ -12329,7 +12579,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, "requires": { "has-value": "0.3.1", "isobject": "3.0.1" @@ -12339,7 +12588,6 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, "requires": { "get-value": "2.0.6", "has-values": "0.1.4", @@ -12350,7 +12598,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, "requires": { "isarray": "1.0.0" } @@ -12360,14 +12607,12 @@ "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" }, "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" } } }, @@ -12414,8 +12659,7 @@ "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" }, "url-parse-lax": { "version": "1.0.0", @@ -12440,7 +12684,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz", "integrity": "sha1-riig1y+TvyJCKhii43mZMRLeyOg=", - "dev": true, "requires": { "define-property": "0.2.5", "isobject": "3.0.1", @@ -12451,7 +12694,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "0.1.6" } @@ -12460,7 +12702,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -12469,7 +12710,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -12480,7 +12720,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "requires": { "kind-of": "3.2.2" }, @@ -12489,7 +12728,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "1.1.6" } @@ -12500,7 +12738,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "requires": { "is-accessor-descriptor": "0.1.6", "is-data-descriptor": "0.1.4", @@ -12510,14 +12747,12 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" }, "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, diff --git a/package.json b/package.json index 79477a3..d9fd0a2 100644 --- a/package.json +++ b/package.json @@ -73,11 +73,14 @@ "engines": { "node": ">=8.9" }, + "NOTE": "These dependencies are for the CLI, and will be removed automatically.", "dependencies": { + "@types/globby": "^6.1.0", "chalk": "^2.3.1", "del": "^3.0.0", "execa": "^0.9.0", "github-username": "^4.1.0", + "globby": "^8.0.1", "gradient-string": "^1.0.0", "inquirer": "^5.1.0", "meow": "^4.0.0", @@ -100,6 +103,7 @@ "codecov": "^3.0.0", "cz-conventional-changelog": "^2.1.0", "gh-pages": "^1.0.0", + "md5-file": "^3.2.3", "nock": "^9.2.3", "npm-run-all": "^4.1.2", "npm-scripts-info": "^0.3.6", diff --git a/src/cli/args.ts b/src/cli/args.ts index f4e9501..255dab4 100644 --- a/src/cli/args.ts +++ b/src/cli/args.ts @@ -1,9 +1,11 @@ +// tslint:disable:no-console no-if-statement no-expression-statement + import meow from 'meow'; import { Package, UpdateInfo, UpdateNotifier } from 'update-notifier'; -import { Runner, TypescriptStarterOptions, validateName } from './primitives'; +import { Runner, TypescriptStarterUserOptions, validateName } from './utils'; export async function checkArgs(): Promise< - TypescriptStarterOptions | undefined + Partial > { const cli = meow( ` @@ -54,15 +56,12 @@ export async function checkArgs(): Promise< const updateInfo = await new Promise((resolve, reject) => { const notifier = new UpdateNotifier({ callback: (error, update) => { - // tslint:disable-next-line:no-expression-statement error ? reject(error) : resolve(update); }, pkg: cli.pkg as Package }); - // tslint:disable-next-line:no-expression-statement notifier.check(); }); - // tslint:disable-next-line:no-if-statement if (updateInfo.type !== 'latest') { throw new Error(` Your version of typescript-starter is outdated. @@ -71,13 +70,15 @@ export async function checkArgs(): Promise< } const input = cli.input[0]; - // tslint:disable-next-line:no-if-statement if (!input) { // no project-name provided, return to collect options in interactive mode - return undefined; + // note: we always return `install`, so --noinstall always works + // (important for test performance) + return { + install: !cli.flags.noinstall + }; } const validOrMsg = await validateName(input); - // tslint:disable-next-line:no-if-statement if (typeof validOrMsg === 'string') { throw new Error(validOrMsg); } @@ -86,8 +87,8 @@ export async function checkArgs(): Promise< description: cli.flags.description, domDefinitions: cli.flags.dom, install: !cli.flags.noinstall, - name: input, nodeDefinitions: cli.flags.node, + projectName: input, runner: cli.flags.yarn ? Runner.Yarn : Runner.Npm }; } diff --git a/src/cli/cli.ts b/src/cli/cli.ts index cc4f8dc..06a5b25 100644 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -2,19 +2,23 @@ import chalk from 'chalk'; import { checkArgs } from './args'; import { inquire } from './inquire'; -import { getIntro } from './primitives'; -import { LiveTasks } from './tasks'; +import { getInferredOptions, LiveTasks } from './tasks'; import { typescriptStarter } from './typescript-starter'; +import { getIntro, TypescriptStarterUserOptions } from './utils'; (async () => { const cliOptions = await checkArgs(); - const options = cliOptions - ? cliOptions - : await (async () => { - console.log(getIntro(process.stdout.columns)); - return inquire(); - })(); - return typescriptStarter(options, LiveTasks); + const userOptions = cliOptions.projectName + ? (cliOptions as TypescriptStarterUserOptions) + : { + ...(await (async () => { + console.log(getIntro(process.stdout.columns)); + return inquire(); + })()), + ...cliOptions // merge in cliOptions.install + }; + const inferredOptions = await getInferredOptions(); + return typescriptStarter({ ...inferredOptions, ...userOptions }, LiveTasks); })().catch((err: Error) => { console.error(` ${chalk.red(err.message)} diff --git a/src/cli/inquire.ts b/src/cli/inquire.ts index 1153143..dedeaa1 100644 --- a/src/cli/inquire.ts +++ b/src/cli/inquire.ts @@ -1,11 +1,11 @@ import { prompt, Question } from 'inquirer'; -import { Runner, TypescriptStarterOptions, validateName } from './primitives'; +import { Runner, TypescriptStarterUserOptions, validateName } from './utils'; -export async function inquire(): Promise { +export async function inquire(): Promise { const packageNameQuestion: Question = { filter: (answer: string) => answer.trim(), message: 'Enter the new package name:', - name: 'name', + name: 'projectName', type: 'input', validate: validateName }; @@ -81,10 +81,10 @@ export async function inquire(): Promise { runnerQuestion, typeDefsQuestion ]).then(answers => { - const { definitions, description, name, runner } = answers as { + const { definitions, description, projectName, runner } = answers as { readonly definitions?: TypeDefinitions; readonly description: string; - readonly name: string; + readonly projectName: string; readonly runner: Runner; }; return { @@ -95,12 +95,12 @@ export async function inquire(): Promise { ) : false, install: true, - name, nodeDefinitions: definitions ? [TypeDefinitions.Node, TypeDefinitions.NodeAndDOM].includes( definitions ) : false, + projectName, runner }; }); diff --git a/src/cli/tasks.ts b/src/cli/tasks.ts index 0cbe37e..3e5ecaf 100644 --- a/src/cli/tasks.ts +++ b/src/cli/tasks.ts @@ -1,9 +1,8 @@ // tslint:disable:no-console no-if-statement no-expression-statement import execa, { ExecaStatic, Options, StdIOOption } from 'execa'; -import { readFileSync, writeFileSync } from 'fs'; import githubUsername from 'github-username'; import { join } from 'path'; -import { Runner } from './primitives'; +import { Runner, TypescriptStarterInferredOptions } from './utils'; // TODO: await https://github.com/DefinitelyTyped/DefinitelyTyped/pull/24209 const inherit = 'inherit' as StdIOOption; @@ -14,43 +13,18 @@ export enum Placeholders { username = 'YOUR_GITHUB_USER_NAME' } -const repo = - process.env.TYPESCRIPT_STARTER_REPO_URL || - 'https://github.com/bitjson/typescript-starter.git'; -export interface Tasks { - readonly cloneRepo: ( - dir: string - ) => Promise<{ readonly commitHash: string; readonly gitHistoryDir: string }>; - readonly getGithubUsername: (email: string) => Promise; - readonly getUserInfo: () => Promise<{ - readonly gitEmail: string; - readonly gitName: string; - }>; - readonly initialCommit: ( - hash: string, - projectDir: string, - name: string, - email: string - ) => Promise; - readonly install: ( - shouldInstall: boolean, - runner: Runner, - projectDir: string - ) => Promise; - readonly readPackageJson: (path: string) => any; - readonly writePackageJson: (path: string, pkg: any) => void; -} - // We implement these as function factories to make unit testing easier. -export const cloneRepo = (spawner: ExecaStatic) => async (dir: string) => { - const cwd = process.cwd(); - const projectDir = join(cwd, dir); +export const cloneRepo = ( + spawner: ExecaStatic, + suppressOutput = false +) => async (repoURL: string, workingDirectory: string, dir: string) => { + const projectDir = join(workingDirectory, dir); const gitHistoryDir = join(projectDir, '.git'); try { - await spawner('git', ['clone', '--depth=1', repo, dir], { - cwd, - stdio: 'inherit' + await spawner('git', ['clone', '--depth=1', repoURL, dir], { + cwd: workingDirectory, + stdio: suppressOutput ? 'pipe' : 'inherit' }); } catch (err) { if (err.code === 'ENOENT') { @@ -78,7 +52,7 @@ export const cloneRepo = (spawner: ExecaStatic) => async (dir: string) => { export const getGithubUsername = (fetcher: any) => async ( email: string | undefined -) => { +): Promise => { if (email === Placeholders.email) { return Placeholders.username; } @@ -109,10 +83,8 @@ export const getUserInfo = (spawner: ExecaStatic) => async () => { export const initialCommit = (spawner: ExecaStatic) => async ( hash: string, - projectDir: string, - name: string, - email: string -) => { + projectDir: string +): Promise => { const opts: Options = { cwd: projectDir, encoding: 'utf8', @@ -120,9 +92,6 @@ export const initialCommit = (spawner: ExecaStatic) => async ( }; await spawner('git', ['init'], opts); await spawner('git', ['add', '-A'], opts); - if (name === Placeholders.name || email === Placeholders.email) { - return false; - } await spawner( 'git', [ @@ -132,11 +101,9 @@ export const initialCommit = (spawner: ExecaStatic) => async ( ], opts ); - return true; }; export const install = (spawner: ExecaStatic) => async ( - shouldInstall: boolean, runner: Runner, projectDir: string ) => { @@ -145,9 +112,6 @@ export const install = (spawner: ExecaStatic) => async ( encoding: 'utf8', stdio: 'inherit' }; - if (!shouldInstall) { - return; - } try { runner === Runner.Npm ? spawner('npm', ['install'], opts) @@ -157,22 +121,42 @@ export const install = (spawner: ExecaStatic) => async ( } }; -const readPackageJson = (path: string) => - JSON.parse(readFileSync(path, 'utf8')); - -const writePackageJson = (path: string, pkg: any) => { - // write using the same format as npm: - // https://github.com/npm/npm/blob/latest/lib/install/update-package-json.js#L48 - const stringified = JSON.stringify(pkg, null, 2) + '\n'; - return writeFileSync(path, stringified); +export const getRepoUrl = () => { + return ( + process.env.TYPESCRIPT_STARTER_REPO_URL || + 'https://github.com/bitjson/typescript-starter.git' + ); }; +export interface Tasks { + readonly cloneRepo: ( + repoURL: string, + workingDirectory: string, + dir: string + ) => Promise<{ readonly commitHash: string; readonly gitHistoryDir: string }>; + readonly initialCommit: ( + hash: string, + projectDir: string, + name: string + ) => Promise; + readonly install: (runner: Runner, projectDir: string) => Promise; +} + export const LiveTasks: Tasks = { cloneRepo: cloneRepo(execa), - getGithubUsername: getGithubUsername(githubUsername), - getUserInfo: getUserInfo(execa), initialCommit: initialCommit(execa), - install: install(execa), - readPackageJson, - writePackageJson + install: install(execa) +}; +export const getInferredOptions = async (): Promise< + TypescriptStarterInferredOptions +> => { + const { gitName, gitEmail } = await getUserInfo(execa)(); + const username = await getGithubUsername(githubUsername)(gitEmail); + return { + email: gitEmail, + fullName: gitName, + githubUsername: username, + repoURL: getRepoUrl(), + workingDirectory: process.cwd() + }; }; diff --git a/src/cli/tests/cli.integration.spec.ts b/src/cli/tests/cli.integration.spec.ts index f372846..615a10d 100644 --- a/src/cli/tests/cli.integration.spec.ts +++ b/src/cli/tests/cli.integration.spec.ts @@ -1,12 +1,60 @@ -// Tests in this file actually run the CLI and attempt to validate its behavior. -// Git must be installed on the PATH of the testing machine. +/** + * Tests in this file actually run the CLI and attempt to validate its behavior. + * Git must be installed on the PATH of the testing machine. + * + * We hash every file in the directories after each test, and compare the hashes + * to the "approved" hashes in this file. + * + * When making a change to this project, run the tests and note which files have + * been modified. After manually reviewing the file for accuracy, simply update + * the relevant hash below. You may find it helpful to view the differences + * between a certain file in each test project. E.g.: + * + * `diff build/test-one/package.json build/test-two/package.json` + */ // tslint:disable:no-expression-statement import test, { ExecutionContext } from 'ava'; import del from 'del'; import execa from 'execa'; +import globby from 'globby'; +import md5File from 'md5-file'; import meow from 'meow'; -import { join } from 'path'; +import { join, relative } from 'path'; +import { cloneRepo, Placeholders, Tasks } from '../tasks'; +import { typescriptStarter } from '../typescript-starter'; +import { Runner } from '../utils'; +// import { Runner, TypescriptStarterOptions } from '../primitives'; + +/** + * NOTE: many of the tests below validate file modification. The filesystem is + * not mocked, and these tests make real changes. Proceed with caution. + * + * Filesystem changes made by these tests should be contained in the `build` + * directory for easier clean up. + */ + +const repoURL = process.cwd(); +const buildDir = join(process.cwd(), 'build'); + +enum TestDirectories { + one = 'test-one', + two = 'test-two', + three = 'test-three', + four = 'test-four', + five = 'test-five' +} + +// If the tests all pass, the TestDirectories will automatically be cleaned up. +test.after(async () => { + await del([ + `./build/${TestDirectories.one}`, + `./build/${TestDirectories.two}`, + `./build/${TestDirectories.three}`, + `./build/${TestDirectories.four}`, + `./build/${TestDirectories.five}` + ]); +}); test('returns version', async t => { const expected = meow('').pkg.version; @@ -20,32 +68,6 @@ test('returns help/usage', async t => { t.regex(stdout, /Usage/); }); -/** - * NOTE: many of the tests below validate file modification. The filesystem is - * not mocked, and these tests make real changes. Proceed with caution. - * - * TODO: mock the filesystem - https://github.com/avajs/ava/issues/665 - * - * Until the filesystem is mocked, filesystem changes made by these tests should - * be contained in the `build` directory for easier clean up. - */ - -enum testDirectories { - one = 'test-one', - two = 'test-two', - three = 'test-three', - four = 'test-four' -} - -test.after(async () => { - await del([ - `./build/${testDirectories.one}`, - `./build/${testDirectories.two}`, - `./build/${testDirectories.three}`, - `./build/${testDirectories.four}` - ]); -}); - test('errors if project name collides with an existing path', async t => { const existingDir = 'build'; const error = await t.throws( @@ -61,45 +83,103 @@ test('errors if project name is not in kebab-case', async t => { t.regex(error.stderr, /should be in-kebab-case/); }); -test('integration test 1: parses CLI arguments, handles options properly', async t => { +async function hashAllTheThings( + projectName: string +): Promise<{ readonly [filename: string]: string }> { + const projectDir = join(buildDir, projectName); + const filePaths: ReadonlyArray = await globby(projectDir); + const hashAll = filePaths.map>( + path => + new Promise((resolve, reject) => { + md5File(path, (err: Error, result: string) => { + err ? reject(err) : resolve(result); + }); + }) + ); + const hashes = await Promise.all(hashAll); + return hashes.reduce<{ readonly [filename: string]: string }>( + (acc, hash, i) => { + const trimmedFilePath = relative(buildDir, filePaths[i]); + return { + ...acc, + [trimmedFilePath]: hash + }; + }, + {} + ); +} + +test(`${ + TestDirectories.one +}: parses CLI arguments, handles default options`, async t => { + const description = 'example description 1'; const { stdout } = await execa( `../bin/typescript-starter`, - [ - `${testDirectories.one}`, - '-description "example description 1"', - '--noinstall' - ], + [`${TestDirectories.one}`, `-description "${description}"`, '--noinstall'], { - cwd: join(process.cwd(), 'build'), + cwd: buildDir, env: { - TYPESCRIPT_STARTER_REPO_URL: process.cwd() + TYPESCRIPT_STARTER_REPO_URL: repoURL } } ); - t.regex(stdout, new RegExp(`Created ${testDirectories.one} 🎉`)); - // TODO: validate contents of testDirectories.one + t.regex(stdout, new RegExp(`Created ${TestDirectories.one} 🎉`)); + const map = await hashAllTheThings(TestDirectories.one); + t.deepEqual(map, { + 'test-one/LICENSE': 'd814c164ff6999405ccc7bf14dcdb50a', + 'test-one/README.md': '2ab1b6b3e434be0cef6c2b947954198e', + 'test-one/bin/typescript-starter': 'a4ad3923f37f50df986b43b1adb9f6b3', + 'test-one/package.json': 'f8eb20e261b3af91e122f85d8abc6b8d', + 'test-one/src/index.ts': '5991bedc40ac87a01d880c6db16fe349', + 'test-one/src/lib/number.spec.ts': '40ebb014eb7871d1f810c618aba1d589', + 'test-one/src/lib/number.ts': '43756f90e6ac0b1c4ee6c81d8ab969c7', + 'test-one/src/types/example.d.ts': '4221812f6f0434eec77ccb1fba1e3759', + 'test-one/tsconfig.json': 'f36dc6407fc898f41a23cb620b2f4884', + 'test-one/tsconfig.module.json': 'e452fd6ff2580347077ae3fff2443e34', + 'test-one/tslint.json': '7ac167ffbcb724a6c270e8dc4e747067' + }); }); -test('integration test 2: parses CLI arguments, handles options properly', async t => { +test(`${ + TestDirectories.two +}: parses CLI arguments, handles all options`, async t => { + const description = 'example description 2'; const { stdout } = await execa( `../bin/typescript-starter`, [ - `${testDirectories.two}`, - '-description "example description 2"', + `${TestDirectories.two}`, + `-description "${description}"`, '--yarn', '--node', '--dom', '--noinstall' ], { - cwd: join(process.cwd(), 'build'), + cwd: buildDir, env: { - TYPESCRIPT_STARTER_REPO_URL: process.cwd() + TYPESCRIPT_STARTER_REPO_URL: repoURL } } ); - t.regex(stdout, new RegExp(`Created ${testDirectories.two} 🎉`)); - // TODO: validate contents of testDirectories.two + t.regex(stdout, new RegExp(`Created ${TestDirectories.two} 🎉`)); + const map = await hashAllTheThings(TestDirectories.two); + t.deepEqual(map, { + 'test-two/LICENSE': 'd814c164ff6999405ccc7bf14dcdb50a', + 'test-two/README.md': '90745077106bf0554dd02bc967e7e80a', + 'test-two/bin/typescript-starter': 'a4ad3923f37f50df986b43b1adb9f6b3', + 'test-two/package.json': 'e0c7654aa5edcf1ee7a998df3f0f672f', + 'test-two/src/index.ts': 'fbc67c2cbf3a7d37e4e02583bf06eec9', + 'test-two/src/lib/async.spec.ts': '1e83b84de3f3b068244885219acb42bd', + 'test-two/src/lib/async.ts': '9012c267bb25fa98ad2561929de3d4e2', + 'test-two/src/lib/hash.spec.ts': '87bfca3c0116fd86a353750fcf585ecf', + 'test-two/src/lib/hash.ts': 'a4c552897f25da5963f410e375264bd1', + 'test-two/src/lib/number.spec.ts': '40ebb014eb7871d1f810c618aba1d589', + 'test-two/src/lib/number.ts': '43756f90e6ac0b1c4ee6c81d8ab969c7', + 'test-two/src/types/example.d.ts': '4221812f6f0434eec77ccb1fba1e3759', + 'test-two/tsconfig.json': '43817952d399db9e44977b3703edd7cf', + 'test-two/tsconfig.module.json': 'e452fd6ff2580347077ae3fff2443e34', + 'test-two/tslint.json': '7ac167ffbcb724a6c270e8dc4e747067' + }); }); const down = '\x1B\x5B\x42'; @@ -112,14 +192,12 @@ async function testInteractive( t: ExecutionContext<{}>, projectName: string, entry: ReadonlyArray> -): Promise { +): Promise { const lastCheck = entry[3] !== undefined; - t.plan(lastCheck ? 6 : 5); - - const proc = execa(`../bin/typescript-starter`, { - cwd: join(process.cwd(), 'build'), + const proc = execa(`../bin/typescript-starter`, ['--noinstall'], { + cwd: buildDir, env: { - TYPESCRIPT_STARTER_REPO_URL: process.cwd() + TYPESCRIPT_STARTER_REPO_URL: repoURL } }); @@ -169,21 +247,110 @@ async function testInteractive( await ms(200); checkBuffer(new RegExp(`${entry[3][1]}`)); } + return proc; } -test('integration test 3: interactive mode, javascript library', async t => { - await testInteractive(t, `${testDirectories.three}`, [ +test(`${ + TestDirectories.three +}: interactive mode: javascript library`, async t => { + t.plan(7); + const proc = await testInteractive(t, `${TestDirectories.three}`, [ [`${down}${up}${down}`, `Javascript library`], `integration test 3 description${enter}`, [`${down}${up}${down}${enter}`, `yarn`], [`${down}${down}${down}${enter}`, `Both Node.js and DOM`] ]); + await proc; + const map = await hashAllTheThings(TestDirectories.three); + t.deepEqual(map, { + 'test-three/LICENSE': 'd814c164ff6999405ccc7bf14dcdb50a', + 'test-three/README.md': 'cd140f7a5ea693fd265807374efab219', + 'test-three/bin/typescript-starter': 'a4ad3923f37f50df986b43b1adb9f6b3', + 'test-three/package.json': 'b86d8c4e9827a2c72597a36ea5e1a2d6', + 'test-three/src/index.ts': '5991bedc40ac87a01d880c6db16fe349', + 'test-three/src/lib/number.spec.ts': '40ebb014eb7871d1f810c618aba1d589', + 'test-three/src/lib/number.ts': '43756f90e6ac0b1c4ee6c81d8ab969c7', + 'test-three/src/types/example.d.ts': '4221812f6f0434eec77ccb1fba1e3759', + 'test-three/tsconfig.json': 'f36dc6407fc898f41a23cb620b2f4884', + 'test-three/tsconfig.module.json': 'e452fd6ff2580347077ae3fff2443e34', + 'test-three/tslint.json': '7ac167ffbcb724a6c270e8dc4e747067' + }); }); -test('integration test 4: interactive mode, node.js application', async t => { - await testInteractive(t, `${testDirectories.four}`, [ +test(`${ + TestDirectories.four +}: interactive mode: node.js application`, async t => { + t.plan(6); + const proc = await testInteractive(t, `${TestDirectories.four}`, [ [`${down}${up}`, `Node.js application`], `integration test 4 description${enter}`, [`${down}${up}${enter}`, `npm`] ]); + await proc; + const map = await hashAllTheThings(TestDirectories.four); + t.deepEqual(map, { + 'test-four/LICENSE': 'd814c164ff6999405ccc7bf14dcdb50a', + 'test-four/README.md': 'c321a7d2ad331e74ce394c819181a96e', + 'test-four/bin/typescript-starter': 'a4ad3923f37f50df986b43b1adb9f6b3', + 'test-four/package.json': '01393ce262160df70dc2610cd8ff0a81', + 'test-four/src/index.ts': '5991bedc40ac87a01d880c6db16fe349', + 'test-four/src/lib/number.spec.ts': '40ebb014eb7871d1f810c618aba1d589', + 'test-four/src/lib/number.ts': '43756f90e6ac0b1c4ee6c81d8ab969c7', + 'test-four/src/types/example.d.ts': '4221812f6f0434eec77ccb1fba1e3759', + 'test-four/tsconfig.json': 'f36dc6407fc898f41a23cb620b2f4884', + 'test-four/tsconfig.module.json': 'e452fd6ff2580347077ae3fff2443e34', + 'test-four/tslint.json': '7ac167ffbcb724a6c270e8dc4e747067' + }); +}); + +test(`${ + TestDirectories.five +}: Bare API: pretend to npm install, should never commit`, async t => { + t.plan(2); + const tasks: Tasks = { + cloneRepo: cloneRepo(execa, true), + initialCommit: async () => { + t.fail(); + }, + install: async () => { + t.pass(); + } + }; + const options = { + description: 'this is an example description', + domDefinitions: false, + email: Placeholders.email, + fullName: Placeholders.name, + githubUsername: 'REDACTED', + install: true, + nodeDefinitions: false, + projectName: TestDirectories.five, + repoURL, + runner: Runner.Npm, + workingDirectory: buildDir + }; + + const log = console.log; + // tslint:disable-next-line:no-object-mutation + console.log = () => { + // mock console.log to silence it + return; + }; + await typescriptStarter(options, tasks); + // tslint:disable-next-line:no-object-mutation + console.log = log; // and put it back + const map = await hashAllTheThings(TestDirectories.five); + t.deepEqual(map, { + 'test-five/LICENSE': '1dfe8c78c6af40fc14ea3b40133f1fa5', + 'test-five/README.md': '07783e7d4d30b9d57a907854700f1e59', + 'test-five/bin/typescript-starter': 'a4ad3923f37f50df986b43b1adb9f6b3', + 'test-five/package.json': '3d7a95598a98ba956e47ccfde8590689', + 'test-five/src/index.ts': '5991bedc40ac87a01d880c6db16fe349', + 'test-five/src/lib/number.spec.ts': '40ebb014eb7871d1f810c618aba1d589', + 'test-five/src/lib/number.ts': '43756f90e6ac0b1c4ee6c81d8ab969c7', + 'test-five/src/types/example.d.ts': '4221812f6f0434eec77ccb1fba1e3759', + 'test-five/tsconfig.json': 'f36dc6407fc898f41a23cb620b2f4884', + 'test-five/tsconfig.module.json': 'e452fd6ff2580347077ae3fff2443e34', + 'test-five/tslint.json': '7ac167ffbcb724a6c270e8dc4e747067' + }); }); diff --git a/src/cli/tests/cli.unit.spec.ts b/src/cli/tests/cli.unit.spec.ts index 83c6786..2810596 100644 --- a/src/cli/tests/cli.unit.spec.ts +++ b/src/cli/tests/cli.unit.spec.ts @@ -4,16 +4,16 @@ import { ExecaStatic } from 'execa'; import meow from 'meow'; import nock from 'nock'; import { checkArgs } from '../args'; -import { getIntro, Runner } from '../primitives'; import { cloneRepo, getGithubUsername, + getRepoUrl, getUserInfo, initialCommit, install, Placeholders } from '../tasks'; -import { completeSpinner } from '../typescript-starter'; +import { getIntro, Runner } from '../utils'; test('errors if outdated', async t => { nock.disableNetConnect(); @@ -32,25 +32,29 @@ test('errors if outdated', async t => { t.regex(error.message, /is outdated/); }); -test(`doesn't error if not outdated`, async t => { - const currentVersion = meow('').pkg.version; - t.truthy(typeof currentVersion === 'string'); +const passUpdateNotifier = (version: string) => { nock.disableNetConnect(); nock('https://registry.npmjs.org:443') .get('/typescript-starter') .reply(200, { - 'dist-tags': { latest: currentVersion }, + 'dist-tags': { latest: version }, name: 'typescript-starter', versions: { - [currentVersion]: { - version: currentVersion + [version]: { + version } } }); +}; + +test("doesn't error if not outdated", async t => { + const currentVersion = meow('').pkg.version; + t.truthy(typeof currentVersion === 'string'); + passUpdateNotifier(currentVersion); await t.notThrows(checkArgs); }); -test(`errors if update-notifier fails`, async t => { +test('errors if update-notifier fails', async t => { nock.disableNetConnect(); nock('https://registry.npmjs.org:443') .get('/typescript-starter') @@ -59,6 +63,38 @@ test(`errors if update-notifier fails`, async t => { t.regex(error.message, /doesn\'t exist/); }); +test('checkArgs returns the right options', async t => { + passUpdateNotifier('1.0.0'); + // tslint:disable-next-line:no-object-mutation + process.argv = [ + 'path/to/node', + 'path/to/typescript-starter', + 'example-project', + `-description "example description"`, + '--yarn', + '--node', + '--dom', + '--noinstall' + ]; + const opts = await checkArgs(); + t.deepEqual(opts, { + description: '', + domDefinitions: true, + install: false, + nodeDefinitions: true, + projectName: 'example-project', + runner: Runner.Yarn + }); +}); + +test('checkArgs always returns { install } (so --noinstall works in interactive mode)', async t => { + passUpdateNotifier('1.0.0'); + // tslint:disable-next-line:no-object-mutation + process.argv = ['path/to/node', 'path/to/typescript-starter']; + const opts = await checkArgs(); + t.deepEqual(opts, { install: true }); +}); + test('ascii art shows if stdout has 85+ columns', async t => { const jumbo = getIntro(100); const snippet = `| __| | | | '_ \\ / _ \\/ __|/ __| '__| | '_ \\|`; @@ -74,23 +110,23 @@ const mockErr = (code?: string | number) => }) as any) as ExecaStatic; test('cloneRepo: errors when Git is not installed on PATH', async t => { - const error = await t.throws(cloneRepo(mockErr('ENOENT'))('fail')); + const error = await t.throws(cloneRepo(mockErr('ENOENT'))('r', 'd', 'p')); t.regex(error.message, /Git is not installed on your PATH/); }); test('cloneRepo: throws when clone fails', async t => { - const error = await t.throws(cloneRepo(mockErr(128))('fail')); + const error = await t.throws(cloneRepo(mockErr(128))('r', 'd', 'p')); t.regex(error.message, /Git clone failed./); }); test('cloneRepo: throws when rev-parse fails', async t => { // tslint:disable-next-line:prefer-const no-let let calls = 0; - const mock = () => { + const mock = ((async () => { calls++; return calls === 1 ? {} : (mockErr(128) as any)(); - }; - const error = await t.throws(cloneRepo((mock as any) as ExecaStatic)('fail')); + }) as any) as ExecaStatic; + const error = await t.throws(cloneRepo(mock)('r', 'd', 'p')); t.regex(error.message, /Git rev-parse failed./); }); @@ -102,6 +138,14 @@ test('getGithubUsername: returns found users', async t => { t.is(username, 'bitjson'); }); +test("getGithubUsername: returns placeholder if user doesn't have Git user.email set", async t => { + const mockFetcher = async () => t.fail(); + const username: string = await getGithubUsername(mockFetcher)( + Placeholders.email + ); + t.is(username, Placeholders.username); +}); + test('getGithubUsername: returns placeholder if not found', async t => { const mockFetcher = async () => { throw new Error(); @@ -134,60 +178,30 @@ test('getUserInfo: returns results properly', async t => { }); test('initialCommit: throws generated errors', async t => { - const error = await t.throws( - initialCommit(mockErr(1))('deadbeef', 'fail', 'name', 'bitjson@github.com') - ); + const error = await t.throws(initialCommit(mockErr(1))('deadbeef', 'fail')); t.is(error.code, 1); }); -test('initialCommit: attempts to commit', async t => { - // tslint:disable-next-line:no-let +test('initialCommit: spawns 3 times', async t => { t.plan(4); const mock = ((async () => { t.pass(); }) as any) as ExecaStatic; - t.true( - await initialCommit(mock)('commit', 'dir', 'name', 'valid@example.com') - ); -}); - -test("initialCommit: don't attempt to commit if user.name/email is not set", async t => { - // tslint:disable-next-line:no-let - let calls = 0; - const errorIf3 = ((async () => { - calls++; - calls === 1 ? t.pass() : calls === 2 ? t.pass() : t.fail(); - }) as any) as ExecaStatic; - t.false( - await initialCommit(errorIf3)( - 'deadbeef', - 'fail', - Placeholders.name, - Placeholders.email - ) - ); + await t.notThrows(initialCommit(mock)('commit', 'dir')); }); test('install: uses the correct runner', async t => { const mock = ((async (runner: Runner) => { runner === Runner.Yarn ? t.pass() : t.fail(); }) as any) as ExecaStatic; - await install(mock)(true, Runner.Yarn, 'pass'); + await install(mock)(Runner.Yarn, 'pass'); }); test('install: throws pretty error on failure', async t => { - const error = await t.throws(install(mockErr())(true, Runner.Npm, 'fail')); + const error = await t.throws(install(mockErr())(Runner.Npm, 'fail')); t.is(error.message, "Installation failed. You'll need to install manually."); }); -test('completeSpinner: resolves spinners properly', async t => { - t.plan(2); - const never = () => { - t.fail(); - }; - const check = (confirm?: string) => (result?: string) => { - confirm ? t.is(confirm, result) : t.pass(); - }; - completeSpinner({ succeed: check(), fail: never }, true); - completeSpinner({ succeed: never, fail: check('message') }, false, 'message'); +test("getRepoUrl: returns GitHub repo when TYPESCRIPT_STARTER_REPO_URL isn't set", async t => { + t.is(getRepoUrl(), 'https://github.com/bitjson/typescript-starter.git'); }); diff --git a/src/cli/typescript-starter.ts b/src/cli/typescript-starter.ts index 7bf3071..0607172 100644 --- a/src/cli/typescript-starter.ts +++ b/src/cli/typescript-starter.ts @@ -1,42 +1,48 @@ // tslint:disable:no-console no-if-statement no-expression-statement import chalk from 'chalk'; import del from 'del'; -import { renameSync } from 'fs'; +import { readFileSync, renameSync, writeFileSync } from 'fs'; import ora from 'ora'; import { join } from 'path'; import replace from 'replace-in-file'; -import { Runner, TypescriptStarterOptions } from './primitives'; -import { Tasks } from './tasks'; +import { Placeholders, Tasks } from './tasks'; +import { Runner, TypescriptStarterOptions } from './utils'; export async function typescriptStarter( { description, domDefinitions, + email, install, - name, + projectName, nodeDefinitions, - runner + runner, + fullName, + githubUsername, + repoURL, + workingDirectory }: TypescriptStarterOptions, tasks: Tasks ): Promise { console.log(); - const { commitHash, gitHistoryDir } = await tasks.cloneRepo(name); + const { commitHash, gitHistoryDir } = await tasks.cloneRepo( + repoURL, + workingDirectory, + projectName + ); await del([gitHistoryDir]); console.log(` ${chalk.dim(`Cloned at commit: ${commitHash}`)} `); - const { gitName, gitEmail } = await tasks.getUserInfo(); - const username = await tasks.getGithubUsername(gitEmail); - const spinner1 = ora('Updating package.json').start(); - const projectPath = join(process.cwd(), name); + const projectPath = join(workingDirectory, projectName); const pkgPath = join(projectPath, 'package.json'); // dependencies to retain for Node.js applications const nodeKeptDeps: ReadonlyArray = ['sha.js']; - const pkg = tasks.readPackageJson(pkgPath); + const pkg = readPackageJson(pkgPath); const newPkg = { ...pkg, bin: {}, @@ -47,19 +53,19 @@ export async function typescriptStarter( : {}, description, keywords: [], - name, - repository: `https:// github.com/${username}/${name}`, + projectName, + repository: `https:// github.com/${githubUsername}/${projectName}`, scripts: runner === Runner.Yarn ? { ...pkg.scripts, - preinstall: `node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('${name} must be installed with Yarn: https://yarnpkg.com/')\"` + preinstall: `node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('${projectName} must be installed with Yarn: https://yarnpkg.com/')\"` } : { ...pkg.scripts }, version: '1.0.0' }; - tasks.writePackageJson(pkgPath, newPkg); + writePackageJson(pkgPath, newPkg); spinner1.succeed(); const spinner2 = ora('Updating .gitignore').start(); @@ -84,7 +90,7 @@ export async function typescriptStarter( await replace({ files: join(projectPath, 'LICENSE'), from: 'Jason Dreyzehner', - to: gitName + to: fullName }); spinner4.succeed(); @@ -94,7 +100,8 @@ export async function typescriptStarter( join(projectPath, 'CHANGELOG.md'), join(projectPath, 'README.md'), join(projectPath, 'package-lock.json'), - join(projectPath, 'src', 'typescript-starter.ts') + join(projectPath, 'src', 'cli'), + join(projectPath, 'src', 'types', 'cli.d.ts') ]); spinner5.succeed(); @@ -106,7 +113,7 @@ export async function typescriptStarter( await replace({ files: join(projectPath, 'README.md'), from: 'package-name', - to: name + to: projectName }); spinner6.succeed(); @@ -141,25 +148,25 @@ export async function typescriptStarter( spinner6B.succeed(); } - await tasks.install(install, runner, projectPath); + if (install) { + await tasks.install(runner, projectPath); + } - const spinner7 = ora(`Initializing git repository`).start(); - completeSpinner( - spinner7, - await tasks.initialCommit(commitHash, projectPath, gitName, gitEmail), - "Git config user.name and user.email are not configured. You'll need to `git commit` yourself." - ); + if (fullName !== Placeholders.name && email !== Placeholders.email) { + const spinner7 = ora(`Initializing git repository...`).start(); + await tasks.initialCommit(commitHash, projectPath, fullName); + spinner7.succeed(); + } - console.log(`\n${chalk.blue.bold(`Created ${name} 🎉`)}\n`); + console.log(`\n${chalk.blue.bold(`Created ${projectName} 🎉`)}\n`); } -export function completeSpinner( - spinner: { - readonly succeed: (text?: string) => any; - readonly fail: (text?: string) => any; - }, - success: boolean, - message?: string -): void { - success ? spinner.succeed() : spinner.fail(message); -} +const readPackageJson = (path: string) => + JSON.parse(readFileSync(path, 'utf8')); + +const writePackageJson = (path: string, pkg: any) => { + // write using the same format as npm: + // https://github.com/npm/npm/blob/latest/lib/install/update-package-json.js#L48 + const stringified = JSON.stringify(pkg, null, 2) + '\n'; + return writeFileSync(path, stringified); +}; diff --git a/src/cli/primitives.ts b/src/cli/utils.ts similarity index 76% rename from src/cli/primitives.ts rename to src/cli/utils.ts index db53a95..de83144 100644 --- a/src/cli/primitives.ts +++ b/src/cli/utils.ts @@ -6,15 +6,27 @@ export enum Runner { Yarn = 'yarn' } -export interface TypescriptStarterOptions { +export interface TypescriptStarterUserOptions { readonly description: string; readonly domDefinitions: boolean; readonly install: boolean; readonly nodeDefinitions: boolean; - readonly name: string; + readonly projectName: string; readonly runner: Runner; } +export interface TypescriptStarterInferredOptions { + readonly githubUsername: string; + readonly fullName: string; + readonly email: string; + readonly repoURL: string; + readonly workingDirectory: string; +} + +export interface TypescriptStarterOptions + extends TypescriptStarterUserOptions, + TypescriptStarterInferredOptions {} + export function validateName(input: string): true | string { return !/^\s*[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\s*$/.test(input) ? 'Name should be in-kebab-case' diff --git a/src/types/cli.d.ts b/src/types/cli.d.ts index bca2aa5..4ee13d7 100644 --- a/src/types/cli.d.ts +++ b/src/types/cli.d.ts @@ -3,6 +3,5 @@ // so its purpose is just to squelch noImplicitAny errors. declare module 'github-username'; declare module 'gradient-string'; -declare module 'has-ansi'; -declare module 'mock-spawn'; +declare module 'md5-file'; declare module 'replace-in-file';