├── .github └── FUNDING.yml ├── .gitignore ├── .npmignore ├── .nycrc ├── .prettierrc ├── LICENSE ├── README.md ├── docker ├── alpine ├── fedora └── jessie ├── package-lock.json ├── package.json ├── src ├── engine.ts ├── index.ts ├── tester.ts ├── utils.ts ├── verifier.ts └── verify.ts ├── tsconfig.json └── tslint.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [skonves] 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # see: https://raw.githubusercontent.com/github/gitignore/master/Node.gitignore 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # Bower dependency directory (https://bower.io/) 29 | bower_components 30 | 31 | # node-waf configuration 32 | .lock-wscript 33 | 34 | # Compiled binary addons (https://nodejs.org/api/addons.html) 35 | build/Release 36 | 37 | # Dependency directories 38 | node_modules/ 39 | jspm_packages/ 40 | 41 | # TypeScript v1 declaration files 42 | typings/ 43 | 44 | # Optional npm cache directory 45 | .npm 46 | 47 | # Optional eslint cache 48 | .eslintcache 49 | 50 | # Optional REPL history 51 | .node_repl_history 52 | 53 | # Output of 'npm pack' 54 | *.tgz 55 | 56 | # Yarn Integrity file 57 | .yarn-integrity 58 | 59 | # dotenv environment variables file 60 | .env 61 | 62 | # next.js build output 63 | .next 64 | 65 | # Build output 66 | lib/ 67 | 68 | # IDE files 69 | *.iml 70 | .idea 71 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !/lib/* -------------------------------------------------------------------------------- /.nycrc: -------------------------------------------------------------------------------- 1 | { 2 | "extension": [".ts"], 3 | "reporter": ["lcov"], 4 | "include": "src", 5 | "exclude": "**/*tests.*" 6 | } 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "useTabs": false, 4 | "tabWidth": 2, 5 | "trailingComma": "all" 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Steve Konves 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![npm](https://img.shields.io/npm/v/tbv.svg)](https://www.npmjs.com/package/tbv) 2 | [![verification](https://api.verifynpm.com/v0/packages/tbv/badge.svg)](https://api.verifynpm.com/v0/packages/tbv) 3 | 4 | # TBV (Trust but Verify) 5 | 6 | Package verification for npm. 7 | 8 | ## How to: 9 | 10 | ### Verify packages from npm 11 | 12 | 1. Install globally: `npm i -g tbv` 13 | 1. Verify a package: `tbv verify {package}` 14 | * To verify latest, use package name only (eg. `redux`) 15 | * To verify a specific version, use name@version (eg. `redux@4.0.1`) 16 | 17 | ### View verbose output 18 | 19 | 1. Use the `verbose` option: `npm verify {package} --verbose` 20 | 21 | ### Run in a Docker container 22 | 23 | 1. Build the container: `npm run docker-build:{distro}` 24 | * Current supported distros are `alpine`, `fedora`, and `jessie` 25 | 1. Run the container: `npm run docker-run:{distro} -- {package} [--verbose]` 26 | 27 | ### Test a package before publication 28 | 29 | 1. Ensure that all commits have been pushed. 30 | 1. Test local directory: `tbv test` 31 | 32 | ### Build from source 33 | 34 | 1. Run the build script: `npm run build` 35 | -------------------------------------------------------------------------------- /docker/alpine: -------------------------------------------------------------------------------- 1 | FROM node:8-alpine 2 | WORKDIR /usr/src/app 3 | 4 | RUN apk add --no-cache 'git=2.18.1-r0' 'nodejs=8.14.0-r0' 5 | 6 | COPY package*.json ts*.json ./ 7 | COPY src/* ./src/ 8 | RUN npm ci && \ 9 | npm run build && \ 10 | rm -rf node_modules && \ 11 | npm i -g . 12 | RUN npm i -g npm@5.6.0 # ensure npm ci cannot run from global 13 | 14 | ENTRYPOINT tbv verify $0 $1 15 | -------------------------------------------------------------------------------- /docker/fedora: -------------------------------------------------------------------------------- 1 | FROM fedora:29 2 | WORKDIR /usr/src/app 3 | 4 | RUN yum install -y nodejs git 5 | 6 | COPY package*.json ts*.json ./ 7 | COPY src/* ./src/ 8 | RUN npm ci && \ 9 | npm run build && \ 10 | rm -rf node_modules && \ 11 | npm i -g . 12 | RUN npm i -g npm@5.6.0 # ensure npm ci cannot run from global 13 | 14 | ENTRYPOINT tbv verify $0 $1 15 | -------------------------------------------------------------------------------- /docker/jessie: -------------------------------------------------------------------------------- 1 | FROM node:carbon-jessie 2 | WORKDIR /usr/src/app 3 | 4 | COPY package*.json ts*.json ./ 5 | COPY src/* ./src/ 6 | RUN npm ci && \ 7 | npm run build && \ 8 | rm -rf node_modules && \ 9 | npm i -g . 10 | RUN npm i -g npm@5.6.0 # ensure npm ci cannot run from global 11 | 12 | ENTRYPOINT tbv verify $0 $1 13 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tbv", 3 | "version": "0.3.6", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@babel/code-frame": { 8 | "version": "7.0.0-beta.51", 9 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.51.tgz", 10 | "integrity": "sha1-vXHZsZKvl435FYKdOdQJRFZDmgw=", 11 | "dev": true, 12 | "requires": { 13 | "@babel/highlight": "7.0.0-beta.51" 14 | } 15 | }, 16 | "@babel/generator": { 17 | "version": "7.0.0-beta.51", 18 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.0.0-beta.51.tgz", 19 | "integrity": "sha1-bHV1/952HQdIXgS67cA5LG2eMPY=", 20 | "dev": true, 21 | "requires": { 22 | "@babel/types": "7.0.0-beta.51", 23 | "jsesc": "^2.5.1", 24 | "lodash": "^4.17.5", 25 | "source-map": "^0.5.0", 26 | "trim-right": "^1.0.1" 27 | } 28 | }, 29 | "@babel/helper-function-name": { 30 | "version": "7.0.0-beta.51", 31 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.51.tgz", 32 | "integrity": "sha1-IbSHSiJ8+Z7K/MMKkDAtpaJkBWE=", 33 | "dev": true, 34 | "requires": { 35 | "@babel/helper-get-function-arity": "7.0.0-beta.51", 36 | "@babel/template": "7.0.0-beta.51", 37 | "@babel/types": "7.0.0-beta.51" 38 | } 39 | }, 40 | "@babel/helper-get-function-arity": { 41 | "version": "7.0.0-beta.51", 42 | "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.51.tgz", 43 | "integrity": "sha1-MoGy0EWvlcFyzpGyCCXYXqRnZBE=", 44 | "dev": true, 45 | "requires": { 46 | "@babel/types": "7.0.0-beta.51" 47 | } 48 | }, 49 | "@babel/helper-split-export-declaration": { 50 | "version": "7.0.0-beta.51", 51 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.51.tgz", 52 | "integrity": "sha1-imw/ZsTSZTUvwHdIT59ugKUauXg=", 53 | "dev": true, 54 | "requires": { 55 | "@babel/types": "7.0.0-beta.51" 56 | } 57 | }, 58 | "@babel/highlight": { 59 | "version": "7.0.0-beta.51", 60 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0-beta.51.tgz", 61 | "integrity": "sha1-6IRK4loVlcz9QriWI7Q3bKBtIl0=", 62 | "dev": true, 63 | "requires": { 64 | "chalk": "^2.0.0", 65 | "esutils": "^2.0.2", 66 | "js-tokens": "^3.0.0" 67 | } 68 | }, 69 | "@babel/parser": { 70 | "version": "7.0.0-beta.51", 71 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.0.0-beta.51.tgz", 72 | "integrity": "sha1-J87C30Cd9gr1gnDtj2qlVAnqhvY=", 73 | "dev": true 74 | }, 75 | "@babel/template": { 76 | "version": "7.0.0-beta.51", 77 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.51.tgz", 78 | "integrity": "sha1-lgKkCuvPNXrpZ34lMu9fyBD1+/8=", 79 | "dev": true, 80 | "requires": { 81 | "@babel/code-frame": "7.0.0-beta.51", 82 | "@babel/parser": "7.0.0-beta.51", 83 | "@babel/types": "7.0.0-beta.51", 84 | "lodash": "^4.17.5" 85 | } 86 | }, 87 | "@babel/traverse": { 88 | "version": "7.0.0-beta.51", 89 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.51.tgz", 90 | "integrity": "sha1-mB2vLOw0emIx06odnhgDsDqqpKg=", 91 | "dev": true, 92 | "requires": { 93 | "@babel/code-frame": "7.0.0-beta.51", 94 | "@babel/generator": "7.0.0-beta.51", 95 | "@babel/helper-function-name": "7.0.0-beta.51", 96 | "@babel/helper-split-export-declaration": "7.0.0-beta.51", 97 | "@babel/parser": "7.0.0-beta.51", 98 | "@babel/types": "7.0.0-beta.51", 99 | "debug": "^3.1.0", 100 | "globals": "^11.1.0", 101 | "invariant": "^2.2.0", 102 | "lodash": "^4.17.5" 103 | } 104 | }, 105 | "@babel/types": { 106 | "version": "7.0.0-beta.51", 107 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.51.tgz", 108 | "integrity": "sha1-2AK3tUO1g2x3iqaReXq/APPZfqk=", 109 | "dev": true, 110 | "requires": { 111 | "esutils": "^2.0.2", 112 | "lodash": "^4.17.5", 113 | "to-fast-properties": "^2.0.0" 114 | } 115 | }, 116 | "@types/chai": { 117 | "version": "4.1.7", 118 | "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.7.tgz", 119 | "integrity": "sha512-2Y8uPt0/jwjhQ6EiluT0XCri1Dbplr0ZxfFXUz+ye13gaqE8u5gL5ppao1JrUYr9cIip5S6MvQzBS7Kke7U9VA==", 120 | "dev": true 121 | }, 122 | "@types/del": { 123 | "version": "3.0.1", 124 | "resolved": "https://registry.npmjs.org/@types/del/-/del-3.0.1.tgz", 125 | "integrity": "sha512-y6qRq6raBuu965clKgx6FHuiPu3oHdtmzMPXi8Uahsjdq1L6DL5fS/aY5/s71YwM7k6K1QIWvem5vNwlnNGIkQ==", 126 | "dev": true, 127 | "requires": { 128 | "@types/glob": "*" 129 | } 130 | }, 131 | "@types/events": { 132 | "version": "1.2.0", 133 | "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", 134 | "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", 135 | "dev": true 136 | }, 137 | "@types/glob": { 138 | "version": "7.1.1", 139 | "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", 140 | "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", 141 | "dev": true, 142 | "requires": { 143 | "@types/events": "*", 144 | "@types/minimatch": "*", 145 | "@types/node": "*" 146 | } 147 | }, 148 | "@types/minimatch": { 149 | "version": "3.0.3", 150 | "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", 151 | "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", 152 | "dev": true 153 | }, 154 | "@types/mocha": { 155 | "version": "5.2.5", 156 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.5.tgz", 157 | "integrity": "sha512-lAVp+Kj54ui/vLUFxsJTMtWvZraZxum3w3Nwkble2dNuV5VnPA+Mi2oGX9XYJAaIvZi3tn3cbjS/qcJXRb6Bww==", 158 | "dev": true 159 | }, 160 | "@types/node": { 161 | "version": "10.12.15", 162 | "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.15.tgz", 163 | "integrity": "sha512-9kROxduaN98QghwwHmxXO2Xz3MaWf+I1sLVAA6KJDF5xix+IyXVhds0MAfdNwtcpSrzhaTsNB0/jnL86fgUhqA==", 164 | "dev": true 165 | }, 166 | "@types/semver": { 167 | "version": "5.5.0", 168 | "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", 169 | "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==", 170 | "dev": true 171 | }, 172 | "@types/tar-stream": { 173 | "version": "1.6.0", 174 | "resolved": "https://registry.npmjs.org/@types/tar-stream/-/tar-stream-1.6.0.tgz", 175 | "integrity": "sha512-XG7FGVmxUvC5NW4h63K3PbB0xdC21xZBfoqmEz7YP2DdiTeYKmYAg8quSHMndNP3iXfs7C73rg4Q0W1dOPHBXQ==", 176 | "dev": true, 177 | "requires": { 178 | "@types/node": "*" 179 | } 180 | }, 181 | "ansi-regex": { 182 | "version": "2.1.1", 183 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 184 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 185 | "dev": true 186 | }, 187 | "ansi-styles": { 188 | "version": "3.2.1", 189 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 190 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 191 | "dev": true, 192 | "requires": { 193 | "color-convert": "^1.9.0" 194 | } 195 | }, 196 | "argparse": { 197 | "version": "1.0.10", 198 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 199 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 200 | "dev": true, 201 | "requires": { 202 | "sprintf-js": "~1.0.2" 203 | } 204 | }, 205 | "arrify": { 206 | "version": "1.0.1", 207 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", 208 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", 209 | "dev": true 210 | }, 211 | "assertion-error": { 212 | "version": "1.1.0", 213 | "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", 214 | "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", 215 | "dev": true 216 | }, 217 | "axios": { 218 | "version": "0.18.0", 219 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", 220 | "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", 221 | "requires": { 222 | "follow-redirects": "^1.3.0", 223 | "is-buffer": "^1.1.5" 224 | } 225 | }, 226 | "babel-code-frame": { 227 | "version": "6.26.0", 228 | "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", 229 | "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", 230 | "dev": true, 231 | "requires": { 232 | "chalk": "^1.1.3", 233 | "esutils": "^2.0.2", 234 | "js-tokens": "^3.0.2" 235 | }, 236 | "dependencies": { 237 | "ansi-styles": { 238 | "version": "2.2.1", 239 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 240 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 241 | "dev": true 242 | }, 243 | "chalk": { 244 | "version": "1.1.3", 245 | "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 246 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 247 | "dev": true, 248 | "requires": { 249 | "ansi-styles": "^2.2.1", 250 | "escape-string-regexp": "^1.0.2", 251 | "has-ansi": "^2.0.0", 252 | "strip-ansi": "^3.0.0", 253 | "supports-color": "^2.0.0" 254 | } 255 | }, 256 | "supports-color": { 257 | "version": "2.0.0", 258 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 259 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 260 | "dev": true 261 | } 262 | } 263 | }, 264 | "balanced-match": { 265 | "version": "1.0.0", 266 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 267 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 268 | "dev": true 269 | }, 270 | "bl": { 271 | "version": "1.2.2", 272 | "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", 273 | "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", 274 | "requires": { 275 | "readable-stream": "^2.3.5", 276 | "safe-buffer": "^5.1.1" 277 | } 278 | }, 279 | "brace-expansion": { 280 | "version": "1.1.11", 281 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 282 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 283 | "dev": true, 284 | "requires": { 285 | "balanced-match": "^1.0.0", 286 | "concat-map": "0.0.1" 287 | } 288 | }, 289 | "browser-stdout": { 290 | "version": "1.3.1", 291 | "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", 292 | "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", 293 | "dev": true 294 | }, 295 | "browserify-zlib": { 296 | "version": "0.1.4", 297 | "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", 298 | "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", 299 | "requires": { 300 | "pako": "~0.2.0" 301 | } 302 | }, 303 | "buffer-alloc": { 304 | "version": "1.2.0", 305 | "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", 306 | "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", 307 | "requires": { 308 | "buffer-alloc-unsafe": "^1.1.0", 309 | "buffer-fill": "^1.0.0" 310 | } 311 | }, 312 | "buffer-alloc-unsafe": { 313 | "version": "1.1.0", 314 | "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", 315 | "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" 316 | }, 317 | "buffer-fill": { 318 | "version": "1.0.0", 319 | "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", 320 | "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" 321 | }, 322 | "buffer-from": { 323 | "version": "1.1.1", 324 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 325 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 326 | }, 327 | "builtin-modules": { 328 | "version": "1.1.1", 329 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 330 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 331 | "dev": true 332 | }, 333 | "chai": { 334 | "version": "4.2.0", 335 | "resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz", 336 | "integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==", 337 | "dev": true, 338 | "requires": { 339 | "assertion-error": "^1.1.0", 340 | "check-error": "^1.0.2", 341 | "deep-eql": "^3.0.1", 342 | "get-func-name": "^2.0.0", 343 | "pathval": "^1.1.0", 344 | "type-detect": "^4.0.5" 345 | } 346 | }, 347 | "chalk": { 348 | "version": "2.4.1", 349 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 350 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 351 | "dev": true, 352 | "requires": { 353 | "ansi-styles": "^3.2.1", 354 | "escape-string-regexp": "^1.0.5", 355 | "supports-color": "^5.3.0" 356 | } 357 | }, 358 | "check-error": { 359 | "version": "1.0.2", 360 | "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", 361 | "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", 362 | "dev": true 363 | }, 364 | "color-convert": { 365 | "version": "1.9.3", 366 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 367 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 368 | "dev": true, 369 | "requires": { 370 | "color-name": "1.1.3" 371 | } 372 | }, 373 | "color-name": { 374 | "version": "1.1.3", 375 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 376 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 377 | "dev": true 378 | }, 379 | "commander": { 380 | "version": "2.15.1", 381 | "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz", 382 | "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", 383 | "dev": true 384 | }, 385 | "concat-map": { 386 | "version": "0.0.1", 387 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 388 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 389 | "dev": true 390 | }, 391 | "core-util-is": { 392 | "version": "1.0.2", 393 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 394 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 395 | }, 396 | "debug": { 397 | "version": "3.1.0", 398 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 399 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 400 | "requires": { 401 | "ms": "2.0.0" 402 | } 403 | }, 404 | "deep-eql": { 405 | "version": "3.0.1", 406 | "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", 407 | "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", 408 | "dev": true, 409 | "requires": { 410 | "type-detect": "^4.0.0" 411 | } 412 | }, 413 | "diff": { 414 | "version": "3.5.0", 415 | "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", 416 | "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", 417 | "dev": true 418 | }, 419 | "duplexify": { 420 | "version": "3.6.1", 421 | "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", 422 | "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", 423 | "requires": { 424 | "end-of-stream": "^1.0.0", 425 | "inherits": "^2.0.1", 426 | "readable-stream": "^2.0.0", 427 | "stream-shift": "^1.0.0" 428 | } 429 | }, 430 | "end-of-stream": { 431 | "version": "1.4.1", 432 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", 433 | "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", 434 | "requires": { 435 | "once": "^1.4.0" 436 | } 437 | }, 438 | "escape-string-regexp": { 439 | "version": "1.0.5", 440 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 441 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 442 | "dev": true 443 | }, 444 | "esprima": { 445 | "version": "4.0.1", 446 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 447 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 448 | "dev": true 449 | }, 450 | "esutils": { 451 | "version": "2.0.2", 452 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 453 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 454 | "dev": true 455 | }, 456 | "follow-redirects": { 457 | "version": "1.6.1", 458 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", 459 | "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", 460 | "requires": { 461 | "debug": "=3.1.0" 462 | } 463 | }, 464 | "fs-constants": { 465 | "version": "1.0.0", 466 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", 467 | "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" 468 | }, 469 | "fs.realpath": { 470 | "version": "1.0.0", 471 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 472 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 473 | "dev": true 474 | }, 475 | "get-func-name": { 476 | "version": "2.0.0", 477 | "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", 478 | "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", 479 | "dev": true 480 | }, 481 | "glob": { 482 | "version": "7.1.2", 483 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 484 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 485 | "dev": true, 486 | "requires": { 487 | "fs.realpath": "^1.0.0", 488 | "inflight": "^1.0.4", 489 | "inherits": "2", 490 | "minimatch": "^3.0.4", 491 | "once": "^1.3.0", 492 | "path-is-absolute": "^1.0.0" 493 | } 494 | }, 495 | "globals": { 496 | "version": "11.8.0", 497 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz", 498 | "integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==", 499 | "dev": true 500 | }, 501 | "growl": { 502 | "version": "1.10.5", 503 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", 504 | "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", 505 | "dev": true 506 | }, 507 | "gunzip-maybe": { 508 | "version": "1.4.1", 509 | "resolved": "https://registry.npmjs.org/gunzip-maybe/-/gunzip-maybe-1.4.1.tgz", 510 | "integrity": "sha512-qtutIKMthNJJgeHQS7kZ9FqDq59/Wn0G2HYCRNjpup7yKfVI6/eqwpmroyZGFoCYaG+sW6psNVb4zoLADHpp2g==", 511 | "requires": { 512 | "browserify-zlib": "^0.1.4", 513 | "is-deflate": "^1.0.0", 514 | "is-gzip": "^1.0.0", 515 | "peek-stream": "^1.1.0", 516 | "pumpify": "^1.3.3", 517 | "through2": "^2.0.3" 518 | } 519 | }, 520 | "has-ansi": { 521 | "version": "2.0.0", 522 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 523 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 524 | "dev": true, 525 | "requires": { 526 | "ansi-regex": "^2.0.0" 527 | } 528 | }, 529 | "has-flag": { 530 | "version": "3.0.0", 531 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 532 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 533 | "dev": true 534 | }, 535 | "he": { 536 | "version": "1.1.1", 537 | "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", 538 | "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", 539 | "dev": true 540 | }, 541 | "inflight": { 542 | "version": "1.0.6", 543 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 544 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 545 | "dev": true, 546 | "requires": { 547 | "once": "^1.3.0", 548 | "wrappy": "1" 549 | } 550 | }, 551 | "inherits": { 552 | "version": "2.0.3", 553 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 554 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 555 | }, 556 | "invariant": { 557 | "version": "2.2.4", 558 | "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", 559 | "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", 560 | "dev": true, 561 | "requires": { 562 | "loose-envify": "^1.0.0" 563 | } 564 | }, 565 | "is-buffer": { 566 | "version": "1.1.6", 567 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 568 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 569 | }, 570 | "is-deflate": { 571 | "version": "1.0.0", 572 | "resolved": "https://registry.npmjs.org/is-deflate/-/is-deflate-1.0.0.tgz", 573 | "integrity": "sha1-yGKQHDwWH7CdrHzcfnhPgOmPLxQ=" 574 | }, 575 | "is-gzip": { 576 | "version": "1.0.0", 577 | "resolved": "https://registry.npmjs.org/is-gzip/-/is-gzip-1.0.0.tgz", 578 | "integrity": "sha1-bKiwe5nHeZgCWQDlVc7Y7YCHmoM=" 579 | }, 580 | "isarray": { 581 | "version": "1.0.0", 582 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 583 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 584 | }, 585 | "istanbul-lib-coverage": { 586 | "version": "2.0.1", 587 | "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", 588 | "integrity": "sha512-nPvSZsVlbG9aLhZYaC3Oi1gT/tpyo3Yt5fNyf6NmcKIayz4VV/txxJFFKAK/gU4dcNn8ehsanBbVHVl0+amOLA==", 589 | "dev": true 590 | }, 591 | "istanbul-lib-instrument": { 592 | "version": "2.3.2", 593 | "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-2.3.2.tgz", 594 | "integrity": "sha512-l7TD/VnBsIB2OJvSyxaLW/ab1+92dxZNH9wLH7uHPPioy3JZ8tnx2UXUdKmdkgmP2EFPzg64CToUP6dAS3U32Q==", 595 | "dev": true, 596 | "requires": { 597 | "@babel/generator": "7.0.0-beta.51", 598 | "@babel/parser": "7.0.0-beta.51", 599 | "@babel/template": "7.0.0-beta.51", 600 | "@babel/traverse": "7.0.0-beta.51", 601 | "@babel/types": "7.0.0-beta.51", 602 | "istanbul-lib-coverage": "^2.0.1", 603 | "semver": "^5.5.0" 604 | } 605 | }, 606 | "js-tokens": { 607 | "version": "3.0.2", 608 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", 609 | "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", 610 | "dev": true 611 | }, 612 | "js-yaml": { 613 | "version": "3.12.0", 614 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", 615 | "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", 616 | "dev": true, 617 | "requires": { 618 | "argparse": "^1.0.7", 619 | "esprima": "^4.0.0" 620 | } 621 | }, 622 | "jsesc": { 623 | "version": "2.5.1", 624 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", 625 | "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", 626 | "dev": true 627 | }, 628 | "lodash": { 629 | "version": "4.17.11", 630 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 631 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", 632 | "dev": true 633 | }, 634 | "loose-envify": { 635 | "version": "1.4.0", 636 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 637 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 638 | "dev": true, 639 | "requires": { 640 | "js-tokens": "^3.0.0 || ^4.0.0" 641 | } 642 | }, 643 | "make-error": { 644 | "version": "1.3.5", 645 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz", 646 | "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==", 647 | "dev": true 648 | }, 649 | "minimatch": { 650 | "version": "3.0.4", 651 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 652 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 653 | "dev": true, 654 | "requires": { 655 | "brace-expansion": "^1.1.7" 656 | } 657 | }, 658 | "minimist": { 659 | "version": "0.0.8", 660 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 661 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 662 | "dev": true 663 | }, 664 | "mkdirp": { 665 | "version": "0.5.1", 666 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 667 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 668 | "dev": true, 669 | "requires": { 670 | "minimist": "0.0.8" 671 | } 672 | }, 673 | "mocha": { 674 | "version": "5.2.0", 675 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", 676 | "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", 677 | "dev": true, 678 | "requires": { 679 | "browser-stdout": "1.3.1", 680 | "commander": "2.15.1", 681 | "debug": "3.1.0", 682 | "diff": "3.5.0", 683 | "escape-string-regexp": "1.0.5", 684 | "glob": "7.1.2", 685 | "growl": "1.10.5", 686 | "he": "1.1.1", 687 | "minimatch": "3.0.4", 688 | "mkdirp": "0.5.1", 689 | "supports-color": "5.4.0" 690 | } 691 | }, 692 | "ms": { 693 | "version": "2.0.0", 694 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 695 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 696 | }, 697 | "nyc": { 698 | "version": "13.0.1", 699 | "resolved": "https://registry.npmjs.org/nyc/-/nyc-13.0.1.tgz", 700 | "integrity": "sha512-Op/bjhEF74IMtzMmgYt+ModTeMHoPZzHe4qseUguPBwg5qC6r4rYMBt1L3yRXQIbjUpEqmn24/1xAC/umQGU7w==", 701 | "dev": true, 702 | "requires": { 703 | "archy": "^1.0.0", 704 | "arrify": "^1.0.1", 705 | "caching-transform": "^2.0.0", 706 | "convert-source-map": "^1.5.1", 707 | "debug-log": "^1.0.1", 708 | "find-cache-dir": "^2.0.0", 709 | "find-up": "^3.0.0", 710 | "foreground-child": "^1.5.6", 711 | "glob": "^7.1.2", 712 | "istanbul-lib-coverage": "^2.0.1", 713 | "istanbul-lib-hook": "^2.0.1", 714 | "istanbul-lib-instrument": "^2.3.2", 715 | "istanbul-lib-report": "^2.0.1", 716 | "istanbul-lib-source-maps": "^2.0.1", 717 | "istanbul-reports": "^2.0.0", 718 | "make-dir": "^1.3.0", 719 | "merge-source-map": "^1.1.0", 720 | "resolve-from": "^4.0.0", 721 | "rimraf": "^2.6.2", 722 | "signal-exit": "^3.0.2", 723 | "spawn-wrap": "^1.4.2", 724 | "test-exclude": "^5.0.0", 725 | "uuid": "^3.3.2", 726 | "yargs": "11.1.0", 727 | "yargs-parser": "^9.0.2" 728 | }, 729 | "dependencies": { 730 | "align-text": { 731 | "version": "0.1.4", 732 | "bundled": true, 733 | "dev": true, 734 | "optional": true, 735 | "requires": { 736 | "kind-of": "^3.0.2", 737 | "longest": "^1.0.1", 738 | "repeat-string": "^1.5.2" 739 | } 740 | }, 741 | "amdefine": { 742 | "version": "1.0.1", 743 | "bundled": true, 744 | "dev": true 745 | }, 746 | "ansi-regex": { 747 | "version": "3.0.0", 748 | "bundled": true, 749 | "dev": true 750 | }, 751 | "append-transform": { 752 | "version": "1.0.0", 753 | "bundled": true, 754 | "dev": true, 755 | "requires": { 756 | "default-require-extensions": "^2.0.0" 757 | } 758 | }, 759 | "archy": { 760 | "version": "1.0.0", 761 | "bundled": true, 762 | "dev": true 763 | }, 764 | "arrify": { 765 | "version": "1.0.1", 766 | "bundled": true, 767 | "dev": true 768 | }, 769 | "async": { 770 | "version": "1.5.2", 771 | "bundled": true, 772 | "dev": true 773 | }, 774 | "balanced-match": { 775 | "version": "1.0.0", 776 | "bundled": true, 777 | "dev": true 778 | }, 779 | "brace-expansion": { 780 | "version": "1.1.11", 781 | "bundled": true, 782 | "dev": true, 783 | "requires": { 784 | "balanced-match": "^1.0.0", 785 | "concat-map": "0.0.1" 786 | } 787 | }, 788 | "builtin-modules": { 789 | "version": "1.1.1", 790 | "bundled": true, 791 | "dev": true 792 | }, 793 | "caching-transform": { 794 | "version": "2.0.0", 795 | "bundled": true, 796 | "dev": true, 797 | "requires": { 798 | "make-dir": "^1.0.0", 799 | "md5-hex": "^2.0.0", 800 | "package-hash": "^2.0.0", 801 | "write-file-atomic": "^2.0.0" 802 | } 803 | }, 804 | "camelcase": { 805 | "version": "1.2.1", 806 | "bundled": true, 807 | "dev": true, 808 | "optional": true 809 | }, 810 | "center-align": { 811 | "version": "0.1.3", 812 | "bundled": true, 813 | "dev": true, 814 | "optional": true, 815 | "requires": { 816 | "align-text": "^0.1.3", 817 | "lazy-cache": "^1.0.3" 818 | } 819 | }, 820 | "cliui": { 821 | "version": "2.1.0", 822 | "bundled": true, 823 | "dev": true, 824 | "optional": true, 825 | "requires": { 826 | "center-align": "^0.1.1", 827 | "right-align": "^0.1.1", 828 | "wordwrap": "0.0.2" 829 | }, 830 | "dependencies": { 831 | "wordwrap": { 832 | "version": "0.0.2", 833 | "bundled": true, 834 | "dev": true, 835 | "optional": true 836 | } 837 | } 838 | }, 839 | "code-point-at": { 840 | "version": "1.1.0", 841 | "bundled": true, 842 | "dev": true 843 | }, 844 | "commondir": { 845 | "version": "1.0.1", 846 | "bundled": true, 847 | "dev": true 848 | }, 849 | "concat-map": { 850 | "version": "0.0.1", 851 | "bundled": true, 852 | "dev": true 853 | }, 854 | "convert-source-map": { 855 | "version": "1.5.1", 856 | "bundled": true, 857 | "dev": true 858 | }, 859 | "cross-spawn": { 860 | "version": "4.0.2", 861 | "bundled": true, 862 | "dev": true, 863 | "requires": { 864 | "lru-cache": "^4.0.1", 865 | "which": "^1.2.9" 866 | } 867 | }, 868 | "debug": { 869 | "version": "3.1.0", 870 | "bundled": true, 871 | "dev": true, 872 | "requires": { 873 | "ms": "2.0.0" 874 | } 875 | }, 876 | "debug-log": { 877 | "version": "1.0.1", 878 | "bundled": true, 879 | "dev": true 880 | }, 881 | "decamelize": { 882 | "version": "1.2.0", 883 | "bundled": true, 884 | "dev": true 885 | }, 886 | "default-require-extensions": { 887 | "version": "2.0.0", 888 | "bundled": true, 889 | "dev": true, 890 | "requires": { 891 | "strip-bom": "^3.0.0" 892 | } 893 | }, 894 | "error-ex": { 895 | "version": "1.3.2", 896 | "bundled": true, 897 | "dev": true, 898 | "requires": { 899 | "is-arrayish": "^0.2.1" 900 | } 901 | }, 902 | "es6-error": { 903 | "version": "4.1.1", 904 | "bundled": true, 905 | "dev": true 906 | }, 907 | "execa": { 908 | "version": "0.7.0", 909 | "bundled": true, 910 | "dev": true, 911 | "requires": { 912 | "cross-spawn": "^5.0.1", 913 | "get-stream": "^3.0.0", 914 | "is-stream": "^1.1.0", 915 | "npm-run-path": "^2.0.0", 916 | "p-finally": "^1.0.0", 917 | "signal-exit": "^3.0.0", 918 | "strip-eof": "^1.0.0" 919 | }, 920 | "dependencies": { 921 | "cross-spawn": { 922 | "version": "5.1.0", 923 | "bundled": true, 924 | "dev": true, 925 | "requires": { 926 | "lru-cache": "^4.0.1", 927 | "shebang-command": "^1.2.0", 928 | "which": "^1.2.9" 929 | } 930 | } 931 | } 932 | }, 933 | "find-cache-dir": { 934 | "version": "2.0.0", 935 | "bundled": true, 936 | "dev": true, 937 | "requires": { 938 | "commondir": "^1.0.1", 939 | "make-dir": "^1.0.0", 940 | "pkg-dir": "^3.0.0" 941 | } 942 | }, 943 | "find-up": { 944 | "version": "3.0.0", 945 | "bundled": true, 946 | "dev": true, 947 | "requires": { 948 | "locate-path": "^3.0.0" 949 | } 950 | }, 951 | "foreground-child": { 952 | "version": "1.5.6", 953 | "bundled": true, 954 | "dev": true, 955 | "requires": { 956 | "cross-spawn": "^4", 957 | "signal-exit": "^3.0.0" 958 | } 959 | }, 960 | "fs.realpath": { 961 | "version": "1.0.0", 962 | "bundled": true, 963 | "dev": true 964 | }, 965 | "get-caller-file": { 966 | "version": "1.0.3", 967 | "bundled": true, 968 | "dev": true 969 | }, 970 | "get-stream": { 971 | "version": "3.0.0", 972 | "bundled": true, 973 | "dev": true 974 | }, 975 | "glob": { 976 | "version": "7.1.2", 977 | "bundled": true, 978 | "dev": true, 979 | "requires": { 980 | "fs.realpath": "^1.0.0", 981 | "inflight": "^1.0.4", 982 | "inherits": "2", 983 | "minimatch": "^3.0.4", 984 | "once": "^1.3.0", 985 | "path-is-absolute": "^1.0.0" 986 | } 987 | }, 988 | "graceful-fs": { 989 | "version": "4.1.11", 990 | "bundled": true, 991 | "dev": true 992 | }, 993 | "handlebars": { 994 | "version": "4.0.11", 995 | "bundled": true, 996 | "dev": true, 997 | "requires": { 998 | "async": "^1.4.0", 999 | "optimist": "^0.6.1", 1000 | "source-map": "^0.4.4", 1001 | "uglify-js": "^2.6" 1002 | }, 1003 | "dependencies": { 1004 | "source-map": { 1005 | "version": "0.4.4", 1006 | "bundled": true, 1007 | "dev": true, 1008 | "requires": { 1009 | "amdefine": ">=0.0.4" 1010 | } 1011 | } 1012 | } 1013 | }, 1014 | "has-flag": { 1015 | "version": "3.0.0", 1016 | "bundled": true, 1017 | "dev": true 1018 | }, 1019 | "hosted-git-info": { 1020 | "version": "2.7.1", 1021 | "bundled": true, 1022 | "dev": true 1023 | }, 1024 | "imurmurhash": { 1025 | "version": "0.1.4", 1026 | "bundled": true, 1027 | "dev": true 1028 | }, 1029 | "inflight": { 1030 | "version": "1.0.6", 1031 | "bundled": true, 1032 | "dev": true, 1033 | "requires": { 1034 | "once": "^1.3.0", 1035 | "wrappy": "1" 1036 | } 1037 | }, 1038 | "inherits": { 1039 | "version": "2.0.3", 1040 | "bundled": true, 1041 | "dev": true 1042 | }, 1043 | "invert-kv": { 1044 | "version": "1.0.0", 1045 | "bundled": true, 1046 | "dev": true 1047 | }, 1048 | "is-arrayish": { 1049 | "version": "0.2.1", 1050 | "bundled": true, 1051 | "dev": true 1052 | }, 1053 | "is-buffer": { 1054 | "version": "1.1.6", 1055 | "bundled": true, 1056 | "dev": true, 1057 | "optional": true 1058 | }, 1059 | "is-builtin-module": { 1060 | "version": "1.0.0", 1061 | "bundled": true, 1062 | "dev": true, 1063 | "requires": { 1064 | "builtin-modules": "^1.0.0" 1065 | } 1066 | }, 1067 | "is-fullwidth-code-point": { 1068 | "version": "2.0.0", 1069 | "bundled": true, 1070 | "dev": true 1071 | }, 1072 | "is-stream": { 1073 | "version": "1.1.0", 1074 | "bundled": true, 1075 | "dev": true 1076 | }, 1077 | "isexe": { 1078 | "version": "2.0.0", 1079 | "bundled": true, 1080 | "dev": true 1081 | }, 1082 | "istanbul-lib-coverage": { 1083 | "version": "2.0.1", 1084 | "bundled": true, 1085 | "dev": true 1086 | }, 1087 | "istanbul-lib-hook": { 1088 | "version": "2.0.1", 1089 | "bundled": true, 1090 | "dev": true, 1091 | "requires": { 1092 | "append-transform": "^1.0.0" 1093 | } 1094 | }, 1095 | "istanbul-lib-report": { 1096 | "version": "2.0.1", 1097 | "bundled": true, 1098 | "dev": true, 1099 | "requires": { 1100 | "istanbul-lib-coverage": "^2.0.1", 1101 | "make-dir": "^1.3.0", 1102 | "supports-color": "^5.4.0" 1103 | } 1104 | }, 1105 | "istanbul-lib-source-maps": { 1106 | "version": "2.0.1", 1107 | "bundled": true, 1108 | "dev": true, 1109 | "requires": { 1110 | "debug": "^3.1.0", 1111 | "istanbul-lib-coverage": "^2.0.1", 1112 | "make-dir": "^1.3.0", 1113 | "rimraf": "^2.6.2", 1114 | "source-map": "^0.6.1" 1115 | }, 1116 | "dependencies": { 1117 | "source-map": { 1118 | "version": "0.6.1", 1119 | "bundled": true, 1120 | "dev": true 1121 | } 1122 | } 1123 | }, 1124 | "istanbul-reports": { 1125 | "version": "2.0.0", 1126 | "bundled": true, 1127 | "dev": true, 1128 | "requires": { 1129 | "handlebars": "^4.0.11" 1130 | } 1131 | }, 1132 | "json-parse-better-errors": { 1133 | "version": "1.0.2", 1134 | "bundled": true, 1135 | "dev": true 1136 | }, 1137 | "kind-of": { 1138 | "version": "3.2.2", 1139 | "bundled": true, 1140 | "dev": true, 1141 | "optional": true, 1142 | "requires": { 1143 | "is-buffer": "^1.1.5" 1144 | } 1145 | }, 1146 | "lazy-cache": { 1147 | "version": "1.0.4", 1148 | "bundled": true, 1149 | "dev": true, 1150 | "optional": true 1151 | }, 1152 | "lcid": { 1153 | "version": "1.0.0", 1154 | "bundled": true, 1155 | "dev": true, 1156 | "requires": { 1157 | "invert-kv": "^1.0.0" 1158 | } 1159 | }, 1160 | "load-json-file": { 1161 | "version": "4.0.0", 1162 | "bundled": true, 1163 | "dev": true, 1164 | "requires": { 1165 | "graceful-fs": "^4.1.2", 1166 | "parse-json": "^4.0.0", 1167 | "pify": "^3.0.0", 1168 | "strip-bom": "^3.0.0" 1169 | } 1170 | }, 1171 | "locate-path": { 1172 | "version": "3.0.0", 1173 | "bundled": true, 1174 | "dev": true, 1175 | "requires": { 1176 | "p-locate": "^3.0.0", 1177 | "path-exists": "^3.0.0" 1178 | } 1179 | }, 1180 | "lodash.flattendeep": { 1181 | "version": "4.4.0", 1182 | "bundled": true, 1183 | "dev": true 1184 | }, 1185 | "longest": { 1186 | "version": "1.0.1", 1187 | "bundled": true, 1188 | "dev": true, 1189 | "optional": true 1190 | }, 1191 | "lru-cache": { 1192 | "version": "4.1.3", 1193 | "bundled": true, 1194 | "dev": true, 1195 | "requires": { 1196 | "pseudomap": "^1.0.2", 1197 | "yallist": "^2.1.2" 1198 | } 1199 | }, 1200 | "make-dir": { 1201 | "version": "1.3.0", 1202 | "bundled": true, 1203 | "dev": true, 1204 | "requires": { 1205 | "pify": "^3.0.0" 1206 | } 1207 | }, 1208 | "md5-hex": { 1209 | "version": "2.0.0", 1210 | "bundled": true, 1211 | "dev": true, 1212 | "requires": { 1213 | "md5-o-matic": "^0.1.1" 1214 | } 1215 | }, 1216 | "md5-o-matic": { 1217 | "version": "0.1.1", 1218 | "bundled": true, 1219 | "dev": true 1220 | }, 1221 | "mem": { 1222 | "version": "1.1.0", 1223 | "bundled": true, 1224 | "dev": true, 1225 | "requires": { 1226 | "mimic-fn": "^1.0.0" 1227 | } 1228 | }, 1229 | "merge-source-map": { 1230 | "version": "1.1.0", 1231 | "bundled": true, 1232 | "dev": true, 1233 | "requires": { 1234 | "source-map": "^0.6.1" 1235 | }, 1236 | "dependencies": { 1237 | "source-map": { 1238 | "version": "0.6.1", 1239 | "bundled": true, 1240 | "dev": true 1241 | } 1242 | } 1243 | }, 1244 | "mimic-fn": { 1245 | "version": "1.2.0", 1246 | "bundled": true, 1247 | "dev": true 1248 | }, 1249 | "minimatch": { 1250 | "version": "3.0.4", 1251 | "bundled": true, 1252 | "dev": true, 1253 | "requires": { 1254 | "brace-expansion": "^1.1.7" 1255 | } 1256 | }, 1257 | "minimist": { 1258 | "version": "0.0.10", 1259 | "bundled": true, 1260 | "dev": true 1261 | }, 1262 | "mkdirp": { 1263 | "version": "0.5.1", 1264 | "bundled": true, 1265 | "dev": true, 1266 | "requires": { 1267 | "minimist": "0.0.8" 1268 | }, 1269 | "dependencies": { 1270 | "minimist": { 1271 | "version": "0.0.8", 1272 | "bundled": true, 1273 | "dev": true 1274 | } 1275 | } 1276 | }, 1277 | "ms": { 1278 | "version": "2.0.0", 1279 | "bundled": true, 1280 | "dev": true 1281 | }, 1282 | "normalize-package-data": { 1283 | "version": "2.4.0", 1284 | "bundled": true, 1285 | "dev": true, 1286 | "requires": { 1287 | "hosted-git-info": "^2.1.4", 1288 | "is-builtin-module": "^1.0.0", 1289 | "semver": "2 || 3 || 4 || 5", 1290 | "validate-npm-package-license": "^3.0.1" 1291 | } 1292 | }, 1293 | "npm-run-path": { 1294 | "version": "2.0.2", 1295 | "bundled": true, 1296 | "dev": true, 1297 | "requires": { 1298 | "path-key": "^2.0.0" 1299 | } 1300 | }, 1301 | "number-is-nan": { 1302 | "version": "1.0.1", 1303 | "bundled": true, 1304 | "dev": true 1305 | }, 1306 | "once": { 1307 | "version": "1.4.0", 1308 | "bundled": true, 1309 | "dev": true, 1310 | "requires": { 1311 | "wrappy": "1" 1312 | } 1313 | }, 1314 | "optimist": { 1315 | "version": "0.6.1", 1316 | "bundled": true, 1317 | "dev": true, 1318 | "requires": { 1319 | "minimist": "~0.0.1", 1320 | "wordwrap": "~0.0.2" 1321 | } 1322 | }, 1323 | "os-homedir": { 1324 | "version": "1.0.2", 1325 | "bundled": true, 1326 | "dev": true 1327 | }, 1328 | "os-locale": { 1329 | "version": "2.1.0", 1330 | "bundled": true, 1331 | "dev": true, 1332 | "requires": { 1333 | "execa": "^0.7.0", 1334 | "lcid": "^1.0.0", 1335 | "mem": "^1.1.0" 1336 | } 1337 | }, 1338 | "p-finally": { 1339 | "version": "1.0.0", 1340 | "bundled": true, 1341 | "dev": true 1342 | }, 1343 | "p-limit": { 1344 | "version": "2.0.0", 1345 | "bundled": true, 1346 | "dev": true, 1347 | "requires": { 1348 | "p-try": "^2.0.0" 1349 | } 1350 | }, 1351 | "p-locate": { 1352 | "version": "3.0.0", 1353 | "bundled": true, 1354 | "dev": true, 1355 | "requires": { 1356 | "p-limit": "^2.0.0" 1357 | } 1358 | }, 1359 | "p-try": { 1360 | "version": "2.0.0", 1361 | "bundled": true, 1362 | "dev": true 1363 | }, 1364 | "package-hash": { 1365 | "version": "2.0.0", 1366 | "bundled": true, 1367 | "dev": true, 1368 | "requires": { 1369 | "graceful-fs": "^4.1.11", 1370 | "lodash.flattendeep": "^4.4.0", 1371 | "md5-hex": "^2.0.0", 1372 | "release-zalgo": "^1.0.0" 1373 | } 1374 | }, 1375 | "parse-json": { 1376 | "version": "4.0.0", 1377 | "bundled": true, 1378 | "dev": true, 1379 | "requires": { 1380 | "error-ex": "^1.3.1", 1381 | "json-parse-better-errors": "^1.0.1" 1382 | } 1383 | }, 1384 | "path-exists": { 1385 | "version": "3.0.0", 1386 | "bundled": true, 1387 | "dev": true 1388 | }, 1389 | "path-is-absolute": { 1390 | "version": "1.0.1", 1391 | "bundled": true, 1392 | "dev": true 1393 | }, 1394 | "path-key": { 1395 | "version": "2.0.1", 1396 | "bundled": true, 1397 | "dev": true 1398 | }, 1399 | "path-type": { 1400 | "version": "3.0.0", 1401 | "bundled": true, 1402 | "dev": true, 1403 | "requires": { 1404 | "pify": "^3.0.0" 1405 | } 1406 | }, 1407 | "pify": { 1408 | "version": "3.0.0", 1409 | "bundled": true, 1410 | "dev": true 1411 | }, 1412 | "pkg-dir": { 1413 | "version": "3.0.0", 1414 | "bundled": true, 1415 | "dev": true, 1416 | "requires": { 1417 | "find-up": "^3.0.0" 1418 | } 1419 | }, 1420 | "pseudomap": { 1421 | "version": "1.0.2", 1422 | "bundled": true, 1423 | "dev": true 1424 | }, 1425 | "read-pkg": { 1426 | "version": "3.0.0", 1427 | "bundled": true, 1428 | "dev": true, 1429 | "requires": { 1430 | "load-json-file": "^4.0.0", 1431 | "normalize-package-data": "^2.3.2", 1432 | "path-type": "^3.0.0" 1433 | } 1434 | }, 1435 | "read-pkg-up": { 1436 | "version": "4.0.0", 1437 | "bundled": true, 1438 | "dev": true, 1439 | "requires": { 1440 | "find-up": "^3.0.0", 1441 | "read-pkg": "^3.0.0" 1442 | } 1443 | }, 1444 | "release-zalgo": { 1445 | "version": "1.0.0", 1446 | "bundled": true, 1447 | "dev": true, 1448 | "requires": { 1449 | "es6-error": "^4.0.1" 1450 | } 1451 | }, 1452 | "repeat-string": { 1453 | "version": "1.6.1", 1454 | "bundled": true, 1455 | "dev": true, 1456 | "optional": true 1457 | }, 1458 | "require-directory": { 1459 | "version": "2.1.1", 1460 | "bundled": true, 1461 | "dev": true 1462 | }, 1463 | "require-main-filename": { 1464 | "version": "1.0.1", 1465 | "bundled": true, 1466 | "dev": true 1467 | }, 1468 | "resolve-from": { 1469 | "version": "4.0.0", 1470 | "bundled": true, 1471 | "dev": true 1472 | }, 1473 | "right-align": { 1474 | "version": "0.1.3", 1475 | "bundled": true, 1476 | "dev": true, 1477 | "optional": true, 1478 | "requires": { 1479 | "align-text": "^0.1.1" 1480 | } 1481 | }, 1482 | "rimraf": { 1483 | "version": "2.6.2", 1484 | "bundled": true, 1485 | "dev": true, 1486 | "requires": { 1487 | "glob": "^7.0.5" 1488 | } 1489 | }, 1490 | "semver": { 1491 | "version": "5.5.0", 1492 | "bundled": true, 1493 | "dev": true 1494 | }, 1495 | "set-blocking": { 1496 | "version": "2.0.0", 1497 | "bundled": true, 1498 | "dev": true 1499 | }, 1500 | "shebang-command": { 1501 | "version": "1.2.0", 1502 | "bundled": true, 1503 | "dev": true, 1504 | "requires": { 1505 | "shebang-regex": "^1.0.0" 1506 | } 1507 | }, 1508 | "shebang-regex": { 1509 | "version": "1.0.0", 1510 | "bundled": true, 1511 | "dev": true 1512 | }, 1513 | "signal-exit": { 1514 | "version": "3.0.2", 1515 | "bundled": true, 1516 | "dev": true 1517 | }, 1518 | "source-map": { 1519 | "version": "0.5.7", 1520 | "bundled": true, 1521 | "dev": true, 1522 | "optional": true 1523 | }, 1524 | "spawn-wrap": { 1525 | "version": "1.4.2", 1526 | "bundled": true, 1527 | "dev": true, 1528 | "requires": { 1529 | "foreground-child": "^1.5.6", 1530 | "mkdirp": "^0.5.0", 1531 | "os-homedir": "^1.0.1", 1532 | "rimraf": "^2.6.2", 1533 | "signal-exit": "^3.0.2", 1534 | "which": "^1.3.0" 1535 | } 1536 | }, 1537 | "spdx-correct": { 1538 | "version": "3.0.0", 1539 | "bundled": true, 1540 | "dev": true, 1541 | "requires": { 1542 | "spdx-expression-parse": "^3.0.0", 1543 | "spdx-license-ids": "^3.0.0" 1544 | } 1545 | }, 1546 | "spdx-exceptions": { 1547 | "version": "2.1.0", 1548 | "bundled": true, 1549 | "dev": true 1550 | }, 1551 | "spdx-expression-parse": { 1552 | "version": "3.0.0", 1553 | "bundled": true, 1554 | "dev": true, 1555 | "requires": { 1556 | "spdx-exceptions": "^2.1.0", 1557 | "spdx-license-ids": "^3.0.0" 1558 | } 1559 | }, 1560 | "spdx-license-ids": { 1561 | "version": "3.0.0", 1562 | "bundled": true, 1563 | "dev": true 1564 | }, 1565 | "string-width": { 1566 | "version": "2.1.1", 1567 | "bundled": true, 1568 | "dev": true, 1569 | "requires": { 1570 | "is-fullwidth-code-point": "^2.0.0", 1571 | "strip-ansi": "^4.0.0" 1572 | } 1573 | }, 1574 | "strip-ansi": { 1575 | "version": "4.0.0", 1576 | "bundled": true, 1577 | "dev": true, 1578 | "requires": { 1579 | "ansi-regex": "^3.0.0" 1580 | } 1581 | }, 1582 | "strip-bom": { 1583 | "version": "3.0.0", 1584 | "bundled": true, 1585 | "dev": true 1586 | }, 1587 | "strip-eof": { 1588 | "version": "1.0.0", 1589 | "bundled": true, 1590 | "dev": true 1591 | }, 1592 | "supports-color": { 1593 | "version": "5.4.0", 1594 | "bundled": true, 1595 | "dev": true, 1596 | "requires": { 1597 | "has-flag": "^3.0.0" 1598 | } 1599 | }, 1600 | "test-exclude": { 1601 | "version": "5.0.0", 1602 | "bundled": true, 1603 | "dev": true, 1604 | "requires": { 1605 | "arrify": "^1.0.1", 1606 | "minimatch": "^3.0.4", 1607 | "read-pkg-up": "^4.0.0", 1608 | "require-main-filename": "^1.0.1" 1609 | } 1610 | }, 1611 | "uglify-js": { 1612 | "version": "2.8.29", 1613 | "bundled": true, 1614 | "dev": true, 1615 | "optional": true, 1616 | "requires": { 1617 | "source-map": "~0.5.1", 1618 | "uglify-to-browserify": "~1.0.0", 1619 | "yargs": "~3.10.0" 1620 | }, 1621 | "dependencies": { 1622 | "yargs": { 1623 | "version": "3.10.0", 1624 | "bundled": true, 1625 | "dev": true, 1626 | "optional": true, 1627 | "requires": { 1628 | "camelcase": "^1.0.2", 1629 | "cliui": "^2.1.0", 1630 | "decamelize": "^1.0.0", 1631 | "window-size": "0.1.0" 1632 | } 1633 | } 1634 | } 1635 | }, 1636 | "uglify-to-browserify": { 1637 | "version": "1.0.2", 1638 | "bundled": true, 1639 | "dev": true, 1640 | "optional": true 1641 | }, 1642 | "uuid": { 1643 | "version": "3.3.2", 1644 | "bundled": true, 1645 | "dev": true 1646 | }, 1647 | "validate-npm-package-license": { 1648 | "version": "3.0.3", 1649 | "bundled": true, 1650 | "dev": true, 1651 | "requires": { 1652 | "spdx-correct": "^3.0.0", 1653 | "spdx-expression-parse": "^3.0.0" 1654 | } 1655 | }, 1656 | "which": { 1657 | "version": "1.3.1", 1658 | "bundled": true, 1659 | "dev": true, 1660 | "requires": { 1661 | "isexe": "^2.0.0" 1662 | } 1663 | }, 1664 | "which-module": { 1665 | "version": "2.0.0", 1666 | "bundled": true, 1667 | "dev": true 1668 | }, 1669 | "window-size": { 1670 | "version": "0.1.0", 1671 | "bundled": true, 1672 | "dev": true, 1673 | "optional": true 1674 | }, 1675 | "wordwrap": { 1676 | "version": "0.0.3", 1677 | "bundled": true, 1678 | "dev": true 1679 | }, 1680 | "wrap-ansi": { 1681 | "version": "2.1.0", 1682 | "bundled": true, 1683 | "dev": true, 1684 | "requires": { 1685 | "string-width": "^1.0.1", 1686 | "strip-ansi": "^3.0.1" 1687 | }, 1688 | "dependencies": { 1689 | "ansi-regex": { 1690 | "version": "2.1.1", 1691 | "bundled": true, 1692 | "dev": true 1693 | }, 1694 | "is-fullwidth-code-point": { 1695 | "version": "1.0.0", 1696 | "bundled": true, 1697 | "dev": true, 1698 | "requires": { 1699 | "number-is-nan": "^1.0.0" 1700 | } 1701 | }, 1702 | "string-width": { 1703 | "version": "1.0.2", 1704 | "bundled": true, 1705 | "dev": true, 1706 | "requires": { 1707 | "code-point-at": "^1.0.0", 1708 | "is-fullwidth-code-point": "^1.0.0", 1709 | "strip-ansi": "^3.0.0" 1710 | } 1711 | }, 1712 | "strip-ansi": { 1713 | "version": "3.0.1", 1714 | "bundled": true, 1715 | "dev": true, 1716 | "requires": { 1717 | "ansi-regex": "^2.0.0" 1718 | } 1719 | } 1720 | } 1721 | }, 1722 | "wrappy": { 1723 | "version": "1.0.2", 1724 | "bundled": true, 1725 | "dev": true 1726 | }, 1727 | "write-file-atomic": { 1728 | "version": "2.3.0", 1729 | "bundled": true, 1730 | "dev": true, 1731 | "requires": { 1732 | "graceful-fs": "^4.1.11", 1733 | "imurmurhash": "^0.1.4", 1734 | "signal-exit": "^3.0.2" 1735 | } 1736 | }, 1737 | "y18n": { 1738 | "version": "3.2.1", 1739 | "bundled": true, 1740 | "dev": true 1741 | }, 1742 | "yallist": { 1743 | "version": "2.1.2", 1744 | "bundled": true, 1745 | "dev": true 1746 | }, 1747 | "yargs": { 1748 | "version": "11.1.0", 1749 | "bundled": true, 1750 | "dev": true, 1751 | "requires": { 1752 | "cliui": "^4.0.0", 1753 | "decamelize": "^1.1.1", 1754 | "find-up": "^2.1.0", 1755 | "get-caller-file": "^1.0.1", 1756 | "os-locale": "^2.0.0", 1757 | "require-directory": "^2.1.1", 1758 | "require-main-filename": "^1.0.1", 1759 | "set-blocking": "^2.0.0", 1760 | "string-width": "^2.0.0", 1761 | "which-module": "^2.0.0", 1762 | "y18n": "^3.2.1", 1763 | "yargs-parser": "^9.0.2" 1764 | }, 1765 | "dependencies": { 1766 | "cliui": { 1767 | "version": "4.1.0", 1768 | "bundled": true, 1769 | "dev": true, 1770 | "requires": { 1771 | "string-width": "^2.1.1", 1772 | "strip-ansi": "^4.0.0", 1773 | "wrap-ansi": "^2.0.0" 1774 | } 1775 | }, 1776 | "find-up": { 1777 | "version": "2.1.0", 1778 | "bundled": true, 1779 | "dev": true, 1780 | "requires": { 1781 | "locate-path": "^2.0.0" 1782 | } 1783 | }, 1784 | "locate-path": { 1785 | "version": "2.0.0", 1786 | "bundled": true, 1787 | "dev": true, 1788 | "requires": { 1789 | "p-locate": "^2.0.0", 1790 | "path-exists": "^3.0.0" 1791 | } 1792 | }, 1793 | "p-limit": { 1794 | "version": "1.3.0", 1795 | "bundled": true, 1796 | "dev": true, 1797 | "requires": { 1798 | "p-try": "^1.0.0" 1799 | } 1800 | }, 1801 | "p-locate": { 1802 | "version": "2.0.0", 1803 | "bundled": true, 1804 | "dev": true, 1805 | "requires": { 1806 | "p-limit": "^1.1.0" 1807 | } 1808 | }, 1809 | "p-try": { 1810 | "version": "1.0.0", 1811 | "bundled": true, 1812 | "dev": true 1813 | } 1814 | } 1815 | }, 1816 | "yargs-parser": { 1817 | "version": "9.0.2", 1818 | "bundled": true, 1819 | "dev": true, 1820 | "requires": { 1821 | "camelcase": "^4.1.0" 1822 | }, 1823 | "dependencies": { 1824 | "camelcase": { 1825 | "version": "4.1.0", 1826 | "bundled": true, 1827 | "dev": true 1828 | } 1829 | } 1830 | } 1831 | } 1832 | }, 1833 | "once": { 1834 | "version": "1.4.0", 1835 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1836 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1837 | "requires": { 1838 | "wrappy": "1" 1839 | } 1840 | }, 1841 | "pako": { 1842 | "version": "0.2.9", 1843 | "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", 1844 | "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" 1845 | }, 1846 | "path-is-absolute": { 1847 | "version": "1.0.1", 1848 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1849 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1850 | "dev": true 1851 | }, 1852 | "path-parse": { 1853 | "version": "1.0.6", 1854 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1855 | "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", 1856 | "dev": true 1857 | }, 1858 | "pathval": { 1859 | "version": "1.1.0", 1860 | "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", 1861 | "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", 1862 | "dev": true 1863 | }, 1864 | "peek-stream": { 1865 | "version": "1.1.3", 1866 | "resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz", 1867 | "integrity": "sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA==", 1868 | "requires": { 1869 | "buffer-from": "^1.0.0", 1870 | "duplexify": "^3.5.0", 1871 | "through2": "^2.0.3" 1872 | } 1873 | }, 1874 | "prettier": { 1875 | "version": "1.14.3", 1876 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz", 1877 | "integrity": "sha512-qZDVnCrnpsRJJq5nSsiHCE3BYMED2OtsI+cmzIzF1QIfqm5ALf8tEJcO27zV1gKNKRPdhjO0dNWnrzssDQ1tFg==", 1878 | "dev": true 1879 | }, 1880 | "process-nextick-args": { 1881 | "version": "2.0.0", 1882 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 1883 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" 1884 | }, 1885 | "pump": { 1886 | "version": "2.0.1", 1887 | "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", 1888 | "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", 1889 | "requires": { 1890 | "end-of-stream": "^1.1.0", 1891 | "once": "^1.3.1" 1892 | } 1893 | }, 1894 | "pumpify": { 1895 | "version": "1.5.1", 1896 | "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", 1897 | "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", 1898 | "requires": { 1899 | "duplexify": "^3.6.0", 1900 | "inherits": "^2.0.3", 1901 | "pump": "^2.0.0" 1902 | } 1903 | }, 1904 | "readable-stream": { 1905 | "version": "2.3.6", 1906 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 1907 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 1908 | "requires": { 1909 | "core-util-is": "~1.0.0", 1910 | "inherits": "~2.0.3", 1911 | "isarray": "~1.0.0", 1912 | "process-nextick-args": "~2.0.0", 1913 | "safe-buffer": "~5.1.1", 1914 | "string_decoder": "~1.1.1", 1915 | "util-deprecate": "~1.0.1" 1916 | } 1917 | }, 1918 | "resolve": { 1919 | "version": "1.8.1", 1920 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", 1921 | "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", 1922 | "dev": true, 1923 | "requires": { 1924 | "path-parse": "^1.0.5" 1925 | } 1926 | }, 1927 | "safe-buffer": { 1928 | "version": "5.1.2", 1929 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1930 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 1931 | }, 1932 | "semver": { 1933 | "version": "5.6.0", 1934 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", 1935 | "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" 1936 | }, 1937 | "source-map": { 1938 | "version": "0.5.7", 1939 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 1940 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 1941 | "dev": true 1942 | }, 1943 | "source-map-support": { 1944 | "version": "0.5.9", 1945 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.9.tgz", 1946 | "integrity": "sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA==", 1947 | "dev": true, 1948 | "requires": { 1949 | "buffer-from": "^1.0.0", 1950 | "source-map": "^0.6.0" 1951 | }, 1952 | "dependencies": { 1953 | "source-map": { 1954 | "version": "0.6.1", 1955 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 1956 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 1957 | "dev": true 1958 | } 1959 | } 1960 | }, 1961 | "sprintf-js": { 1962 | "version": "1.0.3", 1963 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1964 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1965 | "dev": true 1966 | }, 1967 | "stream-shift": { 1968 | "version": "1.0.0", 1969 | "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", 1970 | "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" 1971 | }, 1972 | "string_decoder": { 1973 | "version": "1.1.1", 1974 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1975 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1976 | "requires": { 1977 | "safe-buffer": "~5.1.0" 1978 | } 1979 | }, 1980 | "strip-ansi": { 1981 | "version": "3.0.1", 1982 | "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1983 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1984 | "dev": true, 1985 | "requires": { 1986 | "ansi-regex": "^2.0.0" 1987 | } 1988 | }, 1989 | "supports-color": { 1990 | "version": "5.4.0", 1991 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", 1992 | "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", 1993 | "dev": true, 1994 | "requires": { 1995 | "has-flag": "^3.0.0" 1996 | } 1997 | }, 1998 | "tar-stream": { 1999 | "version": "1.6.2", 2000 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", 2001 | "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", 2002 | "requires": { 2003 | "bl": "^1.0.0", 2004 | "buffer-alloc": "^1.2.0", 2005 | "end-of-stream": "^1.0.0", 2006 | "fs-constants": "^1.0.0", 2007 | "readable-stream": "^2.3.0", 2008 | "to-buffer": "^1.1.1", 2009 | "xtend": "^4.0.0" 2010 | } 2011 | }, 2012 | "through2": { 2013 | "version": "2.0.5", 2014 | "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", 2015 | "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", 2016 | "requires": { 2017 | "readable-stream": "~2.3.6", 2018 | "xtend": "~4.0.1" 2019 | } 2020 | }, 2021 | "to-buffer": { 2022 | "version": "1.1.1", 2023 | "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", 2024 | "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" 2025 | }, 2026 | "to-fast-properties": { 2027 | "version": "2.0.0", 2028 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 2029 | "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", 2030 | "dev": true 2031 | }, 2032 | "trim-right": { 2033 | "version": "1.0.1", 2034 | "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", 2035 | "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", 2036 | "dev": true 2037 | }, 2038 | "ts-node": { 2039 | "version": "7.0.1", 2040 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", 2041 | "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", 2042 | "dev": true, 2043 | "requires": { 2044 | "arrify": "^1.0.0", 2045 | "buffer-from": "^1.1.0", 2046 | "diff": "^3.1.0", 2047 | "make-error": "^1.1.1", 2048 | "minimist": "^1.2.0", 2049 | "mkdirp": "^0.5.1", 2050 | "source-map-support": "^0.5.6", 2051 | "yn": "^2.0.0" 2052 | }, 2053 | "dependencies": { 2054 | "minimist": { 2055 | "version": "1.2.0", 2056 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 2057 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 2058 | "dev": true 2059 | } 2060 | } 2061 | }, 2062 | "tslib": { 2063 | "version": "1.9.3", 2064 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", 2065 | "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", 2066 | "dev": true 2067 | }, 2068 | "tslint": { 2069 | "version": "5.11.0", 2070 | "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.11.0.tgz", 2071 | "integrity": "sha1-mPMMAurjzecAYgHkwzywi0hYHu0=", 2072 | "dev": true, 2073 | "requires": { 2074 | "babel-code-frame": "^6.22.0", 2075 | "builtin-modules": "^1.1.1", 2076 | "chalk": "^2.3.0", 2077 | "commander": "^2.12.1", 2078 | "diff": "^3.2.0", 2079 | "glob": "^7.1.1", 2080 | "js-yaml": "^3.7.0", 2081 | "minimatch": "^3.0.4", 2082 | "resolve": "^1.3.2", 2083 | "semver": "^5.3.0", 2084 | "tslib": "^1.8.0", 2085 | "tsutils": "^2.27.2" 2086 | } 2087 | }, 2088 | "tsutils": { 2089 | "version": "2.29.0", 2090 | "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 2091 | "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", 2092 | "dev": true, 2093 | "requires": { 2094 | "tslib": "^1.8.1" 2095 | } 2096 | }, 2097 | "type-detect": { 2098 | "version": "4.0.8", 2099 | "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", 2100 | "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", 2101 | "dev": true 2102 | }, 2103 | "typescript": { 2104 | "version": "3.2.1", 2105 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.1.tgz", 2106 | "integrity": "sha512-jw7P2z/h6aPT4AENXDGjcfHTu5CSqzsbZc6YlUIebTyBAq8XaKp78x7VcSh30xwSCcsu5irZkYZUSFP1MrAMbg==", 2107 | "dev": true 2108 | }, 2109 | "util-deprecate": { 2110 | "version": "1.0.2", 2111 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2112 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 2113 | }, 2114 | "wrappy": { 2115 | "version": "1.0.2", 2116 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2117 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 2118 | }, 2119 | "xtend": { 2120 | "version": "4.0.1", 2121 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 2122 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" 2123 | }, 2124 | "yn": { 2125 | "version": "2.0.0", 2126 | "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", 2127 | "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", 2128 | "dev": true 2129 | } 2130 | } 2131 | } 2132 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tbv", 3 | "version": "0.4.0", 4 | "description": "Package verification for npm", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "ci": "cipm", 8 | "prebuild": "npm run lint && rm -rf lib/*", 9 | "build": "tsc", 10 | "lint": "tslint --project .", 11 | "lint-fix": "tslint --project . --fix", 12 | "start": "node ./lib/index.js", 13 | "test": "NODE_ENV=test nyc mocha --require source-map-support/register --require ts-node/register --recursive './src/**/*.tests.ts'", 14 | "prepack": "npm run build", 15 | "docker-build:alpine": "docker build -t tbv:alpine -f ./docker/alpine .", 16 | "docker-build:fedora": "docker build -t tbv:fedora -f ./docker/fedora .", 17 | "docker-build:jessie": "docker build -t tbv:jessie -f ./docker/jessie .", 18 | "docker-run:alpine": "docker run --rm tbv:alpine", 19 | "docker-run:fedora": "docker run --rm tbv:fedora", 20 | "docker-run:jessie": "docker run --rm tbv:jessie" 21 | }, 22 | "keywords": [], 23 | "author": "", 24 | "license": "MIT", 25 | "bin": "./lib/index.js", 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/skonves/tbv" 29 | }, 30 | "devDependencies": { 31 | "@types/chai": "^4.1.7", 32 | "@types/del": "^3.0.1", 33 | "@types/mocha": "^5.2.5", 34 | "@types/node": "^10.12.15", 35 | "@types/semver": "^5.5.0", 36 | "@types/tar-stream": "^1.6.0", 37 | "chai": "^4.2.0", 38 | "mocha": "^5.2.0", 39 | "nyc": "^13.0.1", 40 | "prettier": "^1.14.3", 41 | "source-map-support": "^0.5.9", 42 | "ts-node": "^7.0.1", 43 | "tslint": "^5.11.0", 44 | "typescript": "^3.2.1" 45 | }, 46 | "dependencies": { 47 | "axios": "^0.18.0", 48 | "gunzip-maybe": "^1.4.1", 49 | "semver": "^5.6.0", 50 | "tar-stream": "^1.6.2" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/engine.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from 'events'; 2 | import { exec } from 'child_process'; 3 | import * as os from 'os'; 4 | import * as readline from 'readline'; 5 | import * as fs from 'fs'; 6 | import * as path from 'path'; 7 | 8 | import axios, { AxiosResponse } from 'axios'; 9 | 10 | export class Engine< 11 | TProgress extends { [key: string]: Step } 12 | > extends EventEmitter { 13 | protected progress: TProgress = undefined; 14 | protected hasPrinted: boolean = false; 15 | protected hasFailed: boolean = false; 16 | 17 | printSteps(steps: { [key: string]: Step }) { 18 | if (this.hasPrinted) { 19 | const lineCount = Object.keys(steps).length; 20 | readline.moveCursor(process.stdout, 0, -lineCount); 21 | } 22 | 23 | for (const key in steps) { 24 | const step = steps[key] as Step; 25 | switch (step.status) { 26 | case 'pass': 27 | if (this.hasPrinted) readline.clearLine(process.stdout, 0); 28 | console.log(`\x1b[32m✓\x1b[0m ${step.title}`); 29 | break; 30 | case 'fail': 31 | if (this.hasPrinted) readline.clearLine(process.stdout, 0); 32 | console.log(`\x1b[31m✗ ${step.title} >>>> ${step.reason}\x1b[0m`); 33 | break; 34 | case 'warn': 35 | if (this.hasPrinted) readline.clearLine(process.stdout, 0); 36 | console.log(`\x1b[33m- ${step.title} [WARNING]\x1b[0m`); 37 | break; 38 | case 'skipped': 39 | if (this.hasPrinted) readline.clearLine(process.stdout, 0); 40 | console.log(`\x1b[36m- ${step.title} [SKIPPED]\x1b[0m`); 41 | break; 42 | case 'pending': 43 | if (this.hasPrinted) readline.clearLine(process.stdout, 0); 44 | console.log(`- ${step.title}`); 45 | break; 46 | case 'working': 47 | if (this.hasPrinted) readline.clearLine(process.stdout, 0); 48 | console.log(`\x1b[37m> ${step.title}\x1b[0m`); 49 | break; 50 | } 51 | } 52 | 53 | this.hasPrinted = true; 54 | } 55 | 56 | protected async exec(command: string): Promise { 57 | return new Promise((resolve, reject) => { 58 | this.trace( 59 | '====================' + 60 | os.EOL + 61 | 'Running command:' + 62 | os.EOL + 63 | command + 64 | os.EOL, 65 | ); 66 | exec(command, (error, stdout, stderr) => { 67 | if (stderr && !error) this.trace(stderr); 68 | if (stderr && error) this.failure(stderr); 69 | if (stdout) this.trace(stdout); 70 | if (error) { 71 | reject(stderr); 72 | } else { 73 | resolve(stdout); 74 | } 75 | }); 76 | }); 77 | } 78 | 79 | protected async get(url: string): Promise { 80 | let res: AxiosResponse; 81 | try { 82 | this.trace( 83 | '====================' + 84 | os.EOL + 85 | 'Web request:' + 86 | os.EOL + 87 | url + 88 | os.EOL, 89 | ); 90 | res = await axios.get(url); 91 | return res.data; 92 | } catch (err) { 93 | this.failure(err.message); 94 | throw err.message; 95 | } 96 | } 97 | 98 | protected async createTemp(): Promise { 99 | return new Promise((resolve, reject) => { 100 | this.trace( 101 | '====================' + os.EOL + 'Creating temp folder:' + os.EOL, 102 | ); 103 | fs.mkdtemp(path.join(os.tmpdir(), 'tbv-'), (err, folder) => { 104 | if (err) { 105 | this.failure(`${err}`); 106 | reject(err); 107 | } else { 108 | this.trace(folder); 109 | resolve(folder); 110 | } 111 | }); 112 | }); 113 | } 114 | 115 | protected async readJson(filename: string): Promise { 116 | return new Promise((resolve, reject) => { 117 | this.trace( 118 | '====================' + 119 | os.EOL + 120 | `Reading file "${filename}":` + 121 | os.EOL, 122 | ); 123 | fs.readFile(filename, (err, data) => { 124 | if (err) { 125 | this.failure(`${err}`); 126 | reject(err); 127 | } else { 128 | try { 129 | const json = JSON.parse(data.toString()); 130 | this.trace(JSON.stringify(json, null, ' ')); 131 | resolve(json); 132 | } catch (parseErr) { 133 | this.failure(`${parseErr}`); 134 | reject(`${parseErr}`); 135 | } 136 | } 137 | }); 138 | }); 139 | } 140 | 141 | protected updateProgress( 142 | step: keyof TProgress, 143 | status: Step['status'], 144 | reason?: string, 145 | ) { 146 | this.progress[step].status = status; 147 | if (reason) this.progress[step].reason = reason; 148 | if (status === 'fail') this.hasFailed = true; 149 | this.emit('progress', this.progress); 150 | } 151 | 152 | protected failure(message: string) { 153 | this.emit('failure', message); 154 | } 155 | protected warning(message: string) { 156 | this.emit('warning', message); 157 | } 158 | protected notice(message: string) { 159 | this.emit('notice', message); 160 | } 161 | protected trace(message: string) { 162 | this.emit('trace', message); 163 | } 164 | } 165 | 166 | export type Step = { 167 | status: 'pass' | 'fail' | 'warn' | 'skipped' | 'pending' | 'working'; 168 | title: string; 169 | reason?: string; 170 | }; 171 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { Verifier } from './verifier'; 4 | import { Tester } from './tester'; 5 | 6 | const task = process.argv[2]; 7 | const mode = process.argv[4]; 8 | 9 | if (task === 'test') { 10 | const tester = new Tester(); 11 | if (mode === '--verbose') { 12 | tester.on('failure', console.error); 13 | tester.on('warning', console.error); 14 | tester.on('notice', console.log); 15 | tester.on('trace', console.log); 16 | } else { 17 | tester.on('progress', progress => tester.printSteps(progress)); 18 | } 19 | tester.test().then(success => { 20 | if (success) { 21 | console.log(); 22 | console.log('\x1b[32mPASSED\x1b[0m'); 23 | console.log(); 24 | } else { 25 | console.log(); 26 | console.error('\x1b[31mFAILED\x1b[0m'); 27 | console.log(); 28 | process.exit(1); 29 | } 30 | }); 31 | } else if (task === 'verify') { 32 | const verifier = new Verifier(); 33 | if (mode === '--verbose') { 34 | verifier.on('failure', console.error); 35 | verifier.on('warning', console.error); 36 | verifier.on('notice', console.log); 37 | verifier.on('trace', console.log); 38 | } else { 39 | verifier.on('progress', progress => verifier.printSteps(progress)); 40 | } 41 | 42 | const packageDescriptor = process.argv[3]; 43 | verifier.verify(packageDescriptor).then(success => { 44 | if (success) { 45 | console.log(); 46 | console.log('\x1b[32mPASSED\x1b[0m'); 47 | console.log(); 48 | } else { 49 | console.log(); 50 | console.error('\x1b[31mFAILED\x1b[0m'); 51 | console.log(); 52 | process.exit(1); 53 | } 54 | }); 55 | } else { 56 | console.error('Please supply task {verify|test}'); 57 | } 58 | -------------------------------------------------------------------------------- /src/tester.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { Engine, Step } from './engine'; 4 | 5 | export class Tester extends Engine { 6 | async test(): Promise { 7 | this.progress = createProgress(); 8 | this.hasPrinted = false; 9 | 10 | const { repoUrl } = await this.getRepo(); 11 | if (this.hasFailed) return false; 12 | 13 | const { localShasum } = await this.packLocal(); 14 | if (this.hasFailed) return false; 15 | 16 | const { tempDir, localCommit } = await this.checkout(repoUrl); 17 | if (this.hasFailed) return false; 18 | 19 | const { remoteShasum } = await this.packRemote(tempDir); 20 | if (this.hasFailed) return false; 21 | 22 | this.compare(localShasum, remoteShasum); 23 | if (this.hasFailed) return false; 24 | 25 | return true; 26 | } 27 | 28 | private async getRepo(): Promise<{ repoUrl?: string }> { 29 | this.updateProgress('repo', 'working'); 30 | 31 | // read package.json 32 | let packageJson: any; 33 | try { 34 | packageJson = await this.readJson( 35 | path.join(process.cwd(), 'package.json'), 36 | ); 37 | } catch (err) { 38 | this.updateProgress('repo', 'fail', 'Error reading package.json'); 39 | return {}; 40 | } 41 | 42 | // look for repository data 43 | const repository = packageJson && packageJson.repository; 44 | if (!repository) { 45 | this.updateProgress( 46 | 'repo', 47 | 'fail', 48 | 'Repository not defined in package.json', 49 | ); 50 | return {}; 51 | } 52 | 53 | // Ensure git repo 54 | if (repository.type !== 'git') { 55 | this.updateProgress( 56 | 'repo', 57 | 'fail', 58 | 'Non-git repository defined in package.json', 59 | ); 60 | return {}; 61 | } 62 | 63 | // Ensure URL exists 64 | if (!repository.url) { 65 | this.updateProgress( 66 | 'repo', 67 | 'fail', 68 | 'Repository URL not defined in package.json', 69 | ); 70 | return {}; 71 | } 72 | 73 | this.updateProgress('repo', 'pass'); 74 | return { repoUrl: repository.url }; 75 | } 76 | 77 | private async packLocal(): Promise<{ localShasum?: string }> { 78 | this.updateProgress('packLocal', 'working'); 79 | 80 | // npm pack 81 | let stdout = ''; 82 | try { 83 | stdout = await this.exec('npm pack --dry-run'); 84 | } catch (err) { 85 | this.updateProgress( 86 | 'packLocal', 87 | 'fail', 88 | 'Error creating package from local files', 89 | ); 90 | return {}; 91 | } 92 | 93 | // parse shasum from stdout 94 | let localShasum = ''; 95 | try { 96 | localShasum = /shasum:\s+([0-9a-f]{40})/.exec(stdout)[1]; 97 | } catch (parseErr) { 98 | this.updateProgress( 99 | 'packLocal', 100 | 'fail', 101 | 'Error parsing shasum from pack output', 102 | ); 103 | return {}; 104 | } 105 | 106 | this.updateProgress('packLocal', 'pass'); 107 | return { localShasum }; 108 | } 109 | 110 | private async checkout( 111 | repoUrl, 112 | ): Promise<{ tempDir?: string; localCommit?: string }> { 113 | this.updateProgress('checkout', 'working'); 114 | const cwd = process.cwd(); 115 | let tempDir = ''; 116 | 117 | // Create temp directory 118 | try { 119 | tempDir = await this.createTemp(); 120 | } catch (err) { 121 | this.updateProgress('checkout', 'fail', 'Error creating temp directory'); 122 | return {}; 123 | } 124 | 125 | // get current commit hash 126 | let localCommit = ''; 127 | try { 128 | localCommit = await this.exec('git log --format="%H" -n 1'); 129 | } catch (err) { 130 | this.updateProgress( 131 | 'checkout', 132 | 'fail', 133 | 'Unable to determine current local commit', 134 | ); 135 | return {}; 136 | } 137 | 138 | process.chdir(tempDir); 139 | 140 | // git init 141 | try { 142 | await this.exec('git init'); 143 | } catch (err) { 144 | this.updateProgress( 145 | 'checkout', 146 | 'fail', 147 | 'Error initializing git repo in temp directory', 148 | ); 149 | process.chdir(cwd); 150 | return { localCommit }; 151 | } 152 | 153 | // add remote 154 | try { 155 | await this.exec(`git remote add origin "${repoUrl}"`); 156 | } catch (err) { 157 | this.updateProgress( 158 | 'checkout', 159 | 'fail', 160 | 'Error initializing git repo in temp directory', 161 | ); 162 | process.chdir(cwd); 163 | return { localCommit }; 164 | } 165 | 166 | // fetch commit from remote 167 | try { 168 | await this.exec(`git fetch --depth 1 origin ${localCommit}`); 169 | } catch (err) { 170 | this.updateProgress( 171 | 'checkout', 172 | 'fail', 173 | `Unable fetch local commit from remote (${localCommit.substring( 174 | 0, 175 | 7, 176 | )})`, 177 | ); 178 | process.chdir(cwd); 179 | return { localCommit }; 180 | } 181 | 182 | // checkout fetch head 183 | try { 184 | await this.exec('git checkout FETCH_HEAD'); 185 | } catch (err) { 186 | this.updateProgress('checkout', 'fail', 'Unable to checkout FETCH_HEAD'); 187 | process.chdir(cwd); 188 | return { localCommit }; 189 | } 190 | 191 | process.chdir(cwd); 192 | this.updateProgress('checkout', 'pass'); 193 | return { tempDir, localCommit }; 194 | } 195 | 196 | private async packRemote( 197 | tempDir: string, 198 | ): Promise<{ remoteShasum?: string }> { 199 | this.updateProgress('packRemote', 'working'); 200 | 201 | const cwd = process.cwd(); 202 | process.chdir(tempDir); 203 | 204 | // npm pack 205 | let stdout: string = null; 206 | let failedWithoutDependencies = false; 207 | try { 208 | stdout = await this.exec(`npm pack --dry-run`); 209 | this.updateProgress('install', 'skipped'); 210 | } catch (err) { 211 | failedWithoutDependencies = true; 212 | } 213 | 214 | if (failedWithoutDependencies) { 215 | // install dependencies 216 | try { 217 | this.updateProgress( 218 | 'packRemote', 219 | 'pending', 220 | 'Waiting for dependencies', 221 | ); 222 | this.updateProgress('install', 'working'); 223 | await this.exec(`npm ci`); 224 | this.updateProgress('install', 'pass'); 225 | } catch (err) { 226 | this.updateProgress('install', 'fail', 'Error installing dependencies'); 227 | process.chdir(cwd); 228 | return {}; 229 | } 230 | 231 | // npm pack (again) 232 | try { 233 | this.updateProgress('packRemote', 'working'); 234 | stdout = await this.exec(`npm pack --dry-run`); 235 | } catch (err) { 236 | this.updateProgress( 237 | 'packRemote', 238 | 'fail', 239 | 'Error creating package from remote files' + err, 240 | ); 241 | process.chdir(cwd); 242 | return {}; 243 | } 244 | } 245 | 246 | // parse shasum from stdout 247 | let remoteShasum = ''; 248 | try { 249 | remoteShasum = /shasum:\s+([0-9a-f]{40})/.exec(stdout)[1]; 250 | } catch (parseErr) { 251 | this.updateProgress( 252 | 'packRemote', 253 | 'fail', 254 | 'Error parsing shasum from pack output', 255 | ); 256 | process.chdir(cwd); 257 | return {}; 258 | } 259 | 260 | this.updateProgress('packRemote', 'pass'); 261 | process.chdir(cwd); 262 | return { remoteShasum }; 263 | } 264 | 265 | private compare(localShasum: string, remoteShasum: string): void { 266 | this.updateProgress('compare', 'working'); 267 | 268 | if (localShasum === remoteShasum) { 269 | this.updateProgress('compare', 'pass'); 270 | } else { 271 | this.updateProgress('compare', 'fail', 'Shasums do not match'); 272 | } 273 | } 274 | } 275 | 276 | function createProgress(): TestProgress { 277 | return { 278 | repo: { 279 | status: 'pending', 280 | title: 'Package includes repository', 281 | }, 282 | packLocal: { 283 | status: 'pending', 284 | title: 'Create package from local directory', 285 | }, 286 | checkout: { 287 | status: 'pending', 288 | title: 'Shallow checkout from repo', 289 | }, 290 | install: { 291 | status: 'pending', 292 | title: 'Install dependencies', 293 | }, 294 | packRemote: { 295 | status: 'pending', 296 | title: 'Create package from remote repository', 297 | }, 298 | compare: { 299 | status: 'pending', 300 | title: 'Compare shasums', 301 | }, 302 | }; 303 | } 304 | 305 | export type TestProgress = { 306 | repo: Step; 307 | packLocal: Step; 308 | checkout: Step; 309 | install: Step; 310 | packRemote: Step; 311 | compare: Step; 312 | }; 313 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as crypto from 'crypto'; 2 | import * as fs from 'fs'; 3 | import * as https from 'https'; 4 | import { Readable } from 'stream'; 5 | 6 | import * as gunzip from 'gunzip-maybe'; 7 | import { extract } from 'tar-stream'; 8 | 9 | export type Manifest = { [filepath: string]: string }; 10 | export type Diff = { added: string[]; modified: string[]; removed: string[] }; 11 | 12 | export async function getManifestFromUri(url: string): Promise { 13 | return new Promise((resolve, reject) => { 14 | try { 15 | https.get(url, res => { 16 | resolve(getManifestFromStream(res)); 17 | }); 18 | } catch (err) { 19 | reject(err); 20 | } 21 | }); 22 | } 23 | 24 | export async function getManifestFromFile(filepath: string): Promise { 25 | return getManifestFromStream(fs.createReadStream(filepath)); 26 | } 27 | 28 | export function compareManifests(a: Manifest, b: Manifest): Diff { 29 | const diff: Diff = { added: [], modified: [], removed: [] }; 30 | for (const filepath in a) { 31 | if (!b[filepath]) { 32 | diff.removed.push(filepath); 33 | } else if (a[filepath] !== b[filepath]) { 34 | diff.modified.push(filepath); 35 | } 36 | } 37 | 38 | for (const filepath in b) { 39 | if (!a[filepath]) { 40 | diff.added.push(filepath); 41 | } 42 | } 43 | 44 | return diff; 45 | } 46 | 47 | export async function getManifestFromStream( 48 | readable: Readable, 49 | ): Promise { 50 | return new Promise((resolve, reject) => { 51 | try { 52 | const manifest = {}; 53 | const extractor = extract(); 54 | 55 | readable.pipe(gunzip({ maxRecursion: 3 })).pipe(extractor); 56 | readable.on('error', reject); 57 | 58 | extractor.on('entry', (header, stream, next) => { 59 | try { 60 | const hash = crypto.createHash('sha1', { encoding: 'hex' }); 61 | stream.pipe(hash); 62 | 63 | stream.on('error', reject); 64 | 65 | stream.on('end', () => { 66 | try { 67 | manifest[header.name] = hash.read(); 68 | next(); 69 | } catch (err) { 70 | reject(err); 71 | } 72 | }); 73 | } catch (err) { 74 | reject(err); 75 | } 76 | }); 77 | 78 | extractor.on('finish', () => resolve(manifest)); 79 | } catch (err) { 80 | reject(err); 81 | } 82 | }); 83 | } 84 | -------------------------------------------------------------------------------- /src/verifier.ts: -------------------------------------------------------------------------------- 1 | import { Engine, Step } from './engine'; 2 | import { join } from 'path'; 3 | import { compare } from 'semver'; 4 | import { 5 | compareManifests, 6 | getManifestFromUri, 7 | getManifestFromFile, 8 | } from './utils'; 9 | import { parse as parseUrl } from 'url'; 10 | 11 | export class Verifier extends Engine { 12 | private nodeVersion = ''; 13 | private npmVersion = ''; 14 | async verify(packageDescriptor: string): Promise { 15 | const { scope, packageName, version } = this.splitPackageDescriptor( 16 | packageDescriptor, 17 | ); 18 | this.progress = createProgress(); 19 | this.hasFailed = false; 20 | this.hasPrinted = false; 21 | 22 | this.nodeVersion = await this.exec('node --version'); 23 | this.npmVersion = await this.exec('npm --version'); 24 | 25 | const { 26 | resolvedVersion, 27 | repoUrl, 28 | gitHead, 29 | shasum, 30 | tarballUri, 31 | } = await this.registry(packageName, version, scope); 32 | if (this.hasFailed) return false; 33 | 34 | let cleanupDir: string; 35 | try { 36 | const { tempDir, refspec } = await this.checkout( 37 | repoUrl, 38 | gitHead, 39 | resolvedVersion, 40 | ); 41 | cleanupDir = tempDir; 42 | if (this.hasFailed) return false; 43 | 44 | const { outputFile } = await this.pack(tempDir); 45 | if (this.hasFailed) return false; 46 | 47 | await this.compare(tarballUri, tempDir, outputFile); 48 | if (this.hasFailed) return false; 49 | 50 | return true; 51 | } finally { 52 | if (cleanupDir) this.exec(`rm -rf ${cleanupDir}`); 53 | } 54 | } 55 | 56 | private splitPackageDescriptor( 57 | packageDescriptor: string, 58 | ): { scope?: string; packageName: string; version: string } { 59 | if (packageDescriptor.startsWith('@')) { 60 | const scopeSplit = packageDescriptor.split('/'); 61 | const packageSplit = scopeSplit[1].split('@'); 62 | return { 63 | scope: scopeSplit[0], 64 | packageName: packageSplit[0], 65 | version: packageSplit[1], 66 | }; 67 | } else { 68 | let packageSplit = packageDescriptor.split('@'); 69 | return { packageName: packageSplit[0], version: packageSplit[1] }; 70 | } 71 | } 72 | 73 | private async registry( 74 | packageName: string, 75 | version: string, 76 | scope?: string, 77 | ): Promise<{ 78 | resolvedVersion?: string; 79 | repoUrl?: string; 80 | shasum?: string; 81 | gitHead?: string; 82 | tarballUri?: string; 83 | }> { 84 | this.updateProgress('registry', 'working'); 85 | 86 | // Get package info 87 | let info: any; 88 | try { 89 | const path = 90 | scope != undefined ? `${scope}/${packageName}` : `${packageName}`; 91 | info = await this.get(`https://registry.npmjs.com/${path}`); 92 | } catch (err) { 93 | this.updateProgress( 94 | 'registry', 95 | 'fail', 96 | 'Error fetching package data from registry', 97 | ); 98 | return {}; 99 | } 100 | 101 | // Resolve package version 102 | const resolvedVersion = 103 | (info['dist-tags'] && info['dist-tags'][version || 'latest']) || version; 104 | if (!resolvedVersion) { 105 | this.updateProgress( 106 | 'registry', 107 | 'fail', 108 | `Cannot resolve version ${version}`, 109 | ); 110 | return {}; 111 | } 112 | 113 | // Find version info 114 | const versionInfo = !!info.versions && info.versions[resolvedVersion]; 115 | if (!versionInfo) { 116 | this.updateProgress( 117 | 'registry', 118 | 'fail', 119 | `Cannot find info for version ${resolvedVersion} <<<<`, 120 | ); 121 | return {}; 122 | } 123 | 124 | this.updateProgress('registry', 'pass'); 125 | this.updateProgress('repo', 'working'); 126 | 127 | // Find repository info 128 | if (!versionInfo.repository) { 129 | this.updateProgress( 130 | 'repo', 131 | 'fail', 132 | `Repository is not specified for version ${resolvedVersion}`, 133 | ); 134 | return {}; 135 | } 136 | 137 | // Check repository type 138 | if (versionInfo.repository.type !== 'git') { 139 | this.updateProgress( 140 | 'repo', 141 | 'fail', 142 | `Non-git (${ 143 | versionInfo.repository.type 144 | }) repository specified for version ${resolvedVersion}`, 145 | ); 146 | return {}; 147 | } 148 | 149 | // Check repository URL 150 | if (!versionInfo.repository.url) { 151 | this.updateProgress( 152 | 'repo', 153 | 'fail', 154 | `Repository URL is not specified for version ${resolvedVersion}`, 155 | ); 156 | return {}; 157 | } 158 | 159 | const url = parseUrl(versionInfo.repository.url); 160 | const repoUrl = `https://${url.host}${url.path}`; 161 | 162 | this.updateProgress('repo', 'pass'); 163 | this.updateProgress('gitHead', 'working'); 164 | 165 | // Check for gitHead 166 | if (!versionInfo.gitHead) { 167 | this.updateProgress( 168 | 'gitHead', 169 | 'warn', 170 | `GitHead is not specified for version ${resolvedVersion}`, 171 | ); 172 | } 173 | 174 | this.updateProgress('gitHead', 'pass'); 175 | 176 | const shasum = 177 | versionInfo['_shasum'] || (versionInfo.dist && versionInfo.dist.shasum); 178 | 179 | const tarballUri = versionInfo.dist && versionInfo.dist.tarball; 180 | 181 | return { resolvedVersion, repoUrl, shasum, tarballUri }; 182 | } 183 | 184 | private async checkout( 185 | repoUrl: string, 186 | gitHead: string, 187 | resolvedVersion: string, 188 | ): Promise<{ tempDir?: string; refspec?: string }> { 189 | this.updateProgress('checkout', 'working'); 190 | const cwd = process.cwd(); 191 | let tempDir = ''; 192 | 193 | // Create temp directory 194 | try { 195 | tempDir = await this.createTemp(); 196 | } catch (err) { 197 | this.updateProgress('checkout', 'fail', 'Error creating temp directory'); 198 | return {}; 199 | } 200 | 201 | process.chdir(tempDir); 202 | 203 | // git init 204 | try { 205 | await this.exec('git init'); 206 | } catch (err) { 207 | this.updateProgress( 208 | 'checkout', 209 | 'fail', 210 | 'Error initializing git repo in temp directory', 211 | ); 212 | process.chdir(cwd); 213 | return { tempDir }; 214 | } 215 | 216 | // add remote 217 | try { 218 | await this.exec(`git remote add origin "${repoUrl}"`); 219 | } catch (err) { 220 | this.updateProgress( 221 | 'checkout', 222 | 'fail', 223 | 'Error initializing git repo in temp directory', 224 | ); 225 | process.chdir(cwd); 226 | return { tempDir }; 227 | } 228 | 229 | // fetch from remote 230 | let refspec: string; 231 | if (gitHead) { 232 | // Try by gitHead 233 | try { 234 | await this.exec(`git fetch --depth 1 origin ${gitHead}`); 235 | refspec = gitHead; 236 | } catch (err) { 237 | this.updateProgress( 238 | 'checkout', 239 | 'fail', 240 | `Unable fetch commit from remote (${gitHead.substring(0, 7)})`, 241 | ); 242 | process.chdir(cwd); 243 | return { tempDir }; 244 | } 245 | } else { 246 | // Try by v-prefixed version tag 247 | try { 248 | await this.exec(`git fetch --depth 1 origin tags/v${resolvedVersion}`); 249 | refspec = `tags/v${resolvedVersion}`; 250 | } catch { 251 | // Try by non-prefixed version tag 252 | try { 253 | await this.exec(`git fetch --depth 1 origin tags/${resolvedVersion}`); 254 | refspec = `tags/${resolvedVersion}`; 255 | } catch (err) { 256 | this.updateProgress( 257 | 'checkout', 258 | 'fail', 259 | `Unable fetch tag from remote (tags/${resolvedVersion} or tags/v${resolvedVersion})`, 260 | ); 261 | process.chdir(cwd); 262 | return { tempDir }; 263 | } 264 | } 265 | } 266 | 267 | // checkout fetch head 268 | try { 269 | await this.exec('git checkout FETCH_HEAD'); 270 | } catch (err) { 271 | this.updateProgress('checkout', 'fail', 'Unable to checkout FETCH_HEAD'); 272 | process.chdir(cwd); 273 | return { tempDir, refspec }; 274 | } 275 | 276 | process.chdir(cwd); 277 | this.updateProgress('checkout', 'pass'); 278 | return { tempDir, refspec }; 279 | } 280 | 281 | private async pack(tempDir: string): Promise<{ outputFile?: string }> { 282 | this.updateProgress('pack', 'working'); 283 | 284 | const cwd = process.cwd(); 285 | process.chdir(tempDir); 286 | 287 | // npm pack 288 | let stdout: string = null; 289 | let failedWithoutDependencies = false; 290 | try { 291 | stdout = await this.exec(`npm pack --unsafe-perm`); 292 | this.updateProgress('install', 'skipped'); 293 | } catch (err) { 294 | failedWithoutDependencies = true; 295 | } 296 | 297 | if (failedWithoutDependencies) { 298 | // install dependencies 299 | try { 300 | this.updateProgress('pack', 'pending', 'Waiting for dependencies'); 301 | this.updateProgress('install', 'working'); 302 | await this.npmci(); 303 | this.updateProgress('install', 'pass'); 304 | } catch (err) { 305 | this.updateProgress( 306 | 'install', 307 | 'fail', 308 | `Error installing dependencies: ${err.message}`, 309 | ); 310 | process.chdir(cwd); 311 | return {}; 312 | } 313 | 314 | // npm pack (again) 315 | try { 316 | this.updateProgress('pack', 'working'); 317 | stdout = await this.exec(`npm pack --unsafe-perm`); 318 | } catch (err) { 319 | this.updateProgress( 320 | 'pack', 321 | 'fail', 322 | 'Error creating package from remote files' + err, 323 | ); 324 | process.chdir(cwd); 325 | return {}; 326 | } 327 | } 328 | 329 | this.updateProgress('pack', 'pass'); 330 | process.chdir(cwd); 331 | return { 332 | outputFile: stdout 333 | .trim() 334 | .split('\n') 335 | .reverse()[0] 336 | .trim(), 337 | }; 338 | } 339 | 340 | private async compare( 341 | tarballUri: string, 342 | tempDir: string, 343 | outputFile: string, 344 | ): Promise { 345 | this.updateProgress('compare', 'working'); 346 | 347 | const [generatedManifest, publishedManifest] = await Promise.all([ 348 | getManifestFromFile(join(tempDir, outputFile)), 349 | getManifestFromUri(tarballUri), 350 | ]); 351 | 352 | try { 353 | const diff = compareManifests(generatedManifest, publishedManifest); 354 | this.trace(JSON.stringify(diff, null, 2)); 355 | 356 | if (!diff.added.length && !diff.modified.length && !diff.removed.length) { 357 | this.updateProgress('compare', 'pass'); 358 | } else { 359 | this.updateProgress( 360 | 'compare', 361 | 'fail', 362 | `${diff.added.length} files added, ${ 363 | diff.modified.length 364 | } files modified, and ${diff.removed.length} files removed.`, 365 | ); 366 | } 367 | } catch (err) { 368 | this.updateProgress('compare', 'fail', `${err}`); 369 | } 370 | } 371 | 372 | private async npmci(): Promise { 373 | if (compare(this.npmVersion, '5.7.0') < 0) { 374 | await this.exec('cipm'); 375 | } else { 376 | await this.exec('npm ci'); 377 | } 378 | } 379 | } 380 | 381 | function createProgress(): VerifyProgress { 382 | return { 383 | registry: { 384 | status: 'pending', 385 | title: 'Fetch package data from registry', 386 | }, 387 | repo: { 388 | status: 'pending', 389 | title: 'Version contains repository URL', 390 | }, 391 | gitHead: { 392 | status: 'pending', 393 | title: 'Version contains gitHead', 394 | }, 395 | checkout: { 396 | status: 'pending', 397 | title: 'Shallow checkout', 398 | }, 399 | install: { 400 | status: 'pending', 401 | title: 'Install npm packages', 402 | }, 403 | pack: { 404 | status: 'pending', 405 | title: 'Create package', 406 | }, 407 | compare: { 408 | status: 'pending', 409 | title: 'Compare package contents', 410 | }, 411 | }; 412 | } 413 | 414 | export type VerifyProgress = { 415 | registry: Step; 416 | repo: Step; 417 | gitHead: Step; 418 | checkout: Step; 419 | install: Step; 420 | pack: Step; 421 | compare: Step; 422 | }; 423 | -------------------------------------------------------------------------------- /src/verify.ts: -------------------------------------------------------------------------------- 1 | import * as fs from 'fs'; 2 | import { exec } from 'child_process'; 3 | import * as path from 'path'; 4 | import * as os from 'os'; 5 | 6 | import axios from 'axios'; 7 | import * as del from 'del'; 8 | 9 | export async function verify( 10 | packageName: string, 11 | version?: string, 12 | ): Promise { 13 | const hashes = await getHashes(packageName, version); 14 | 15 | if (!hashes.repoUrl) { 16 | console.error( 17 | `Could not find repository URL for ${hashes.packageName}@${ 18 | hashes.version 19 | }`, 20 | ); 21 | process.exit(1); 22 | } 23 | 24 | if (!hashes.gitHead) { 25 | console.error( 26 | `Could not find git head for ${hashes.packageName}@${hashes.version}`, 27 | ); 28 | process.exit(1); 29 | } 30 | 31 | const dir = await getShallowClone(hashes); 32 | const shasum = await getNpmShasum(dir); 33 | 34 | console.log(); 35 | console.log(`expected shasum => ${hashes.shasum}`); 36 | console.log(` actual shasum => ${shasum}`); 37 | console.log(); 38 | 39 | if (hashes.shasum === shasum) { 40 | console.log( 41 | `Shasum of package ${hashes.packageName}@${ 42 | hashes.version 43 | } matches code at ${hashes.repoUrl} (${hashes.gitHead.substring(0, 7)})`, 44 | ); 45 | console.log(); 46 | } else { 47 | console.log( 48 | `Shasum of package ${hashes.packageName}@${ 49 | hashes.version 50 | } does not match code at ${hashes.repoUrl} (${hashes.gitHead.substring( 51 | 0, 52 | 7, 53 | )})`, 54 | ); 55 | console.log(); 56 | process.exit(1); 57 | } 58 | } 59 | 60 | async function getHashes( 61 | packageName: string, 62 | version?: string, 63 | ): Promise { 64 | const res = await axios.get(`https://registry.npmjs.com/${packageName}`); 65 | 66 | const v = version || (res.data['dist-tags'] && res.data['dist-tags'].latest); 67 | 68 | const meta = res.data.versions && res.data.versions[v]; 69 | 70 | const repo = 71 | meta && 72 | meta.repository && 73 | meta.repository.type === 'git' && 74 | meta.repository.url; 75 | 76 | const gitHead = meta && meta.gitHead; 77 | 78 | const shasum = meta && meta.dist && meta.dist.shasum; 79 | 80 | return { 81 | packageName, 82 | version: meta ? v : undefined, 83 | repoUrl: repo.substring(4), 84 | gitHead, 85 | shasum, 86 | }; 87 | } 88 | 89 | async function getShallowClone(hashes: PackageHashes): Promise { 90 | const cwd = process.cwd(); 91 | const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'tbv-')); 92 | process.chdir(dir); 93 | 94 | console.log( 95 | `Shallow cloning ${hashes.packageName}@${hashes.version} from ${ 96 | hashes.repoUrl 97 | } ...`, 98 | ); 99 | 100 | await gitInit(); 101 | await gitAddRemote(hashes.repoUrl); 102 | try { 103 | await gitShallowFetchByCommit(hashes.gitHead); 104 | } catch (err) { 105 | console.error( 106 | `WARNING: git HEAD ${ 107 | hashes.gitHead 108 | } could not be fetched. Fetching by tag instead.`, 109 | ); 110 | await gitShallowFetchByTag(hashes.version); 111 | } 112 | await gitCheckoutFetchHead(); 113 | 114 | console.log(`Cloned at ${hashes.gitHead}`); 115 | 116 | process.chdir(cwd); 117 | return dir; 118 | } 119 | 120 | function gitInit(): Promise { 121 | return new Promise((resolve, reject) => { 122 | exec('git init', (error, stdout, stderr) => { 123 | if (error) reject(new Error('Cannot run git init')); 124 | else resolve(); 125 | }); 126 | }); 127 | } 128 | 129 | function gitAddRemote(origin: string): Promise { 130 | return new Promise((resolve, reject) => { 131 | exec(`git remote add origin "${origin}"`, (error, stdout, stderr) => { 132 | if (error) reject(new Error(`Cannot add remote ${origin}`)); 133 | else resolve(); 134 | }); 135 | }); 136 | } 137 | 138 | function gitShallowFetchByCommit(sha1: string): Promise { 139 | return new Promise((resolve, reject) => { 140 | exec(`git fetch --depth 1 origin ${sha1}`, (error, stdout, stderr) => { 141 | if (error) reject(new Error(`Cannot fetch ${sha1}`)); 142 | else resolve(); 143 | }); 144 | }); 145 | } 146 | 147 | function gitShallowFetchByTag(version: string): Promise { 148 | return new Promise((resolve, reject) => { 149 | exec(`git fetch --depth 1 origin v${version}`, (error, stdout, stderr) => { 150 | if (error) reject(new Error(`Cannot fetch tag v${version}`)); 151 | else resolve(); 152 | }); 153 | }); 154 | } 155 | 156 | function gitCheckoutFetchHead(): Promise { 157 | return new Promise((resolve, reject) => { 158 | exec(`git checkout FETCH_HEAD`, (error, stdout, stderr) => { 159 | if (error) reject(new Error('Cannot checkout FETCH_HEAD')); 160 | else resolve(); 161 | }); 162 | }); 163 | } 164 | 165 | async function getNpmShasum(dir: string): Promise { 166 | const cwd = process.cwd(); 167 | process.chdir(dir); 168 | 169 | let pack = ''; 170 | try { 171 | pack = await npmPack(); 172 | } catch (e) { 173 | console.log( 174 | 'Installing dependencies for npm prepack. This may take a while ...', 175 | ); 176 | await npmCi(); 177 | pack = await npmPack(); 178 | } 179 | 180 | process.chdir(cwd); 181 | 182 | const shasum = /shasum:\s+([0-9a-f]{40})/.exec(pack)[1]; 183 | 184 | return shasum; 185 | } 186 | 187 | function npmCi(): Promise { 188 | return new Promise((resolve, reject) => { 189 | exec(`npm ci`, (error, stdout, stderr) => { 190 | if (error) reject(new Error('Cannot run npm ci')); 191 | else resolve(stderr + stdout); 192 | }); 193 | }); 194 | } 195 | 196 | function npmPack(): Promise { 197 | return new Promise((resolve, reject) => { 198 | exec(`npm pack --dry-run`, (error, stdout, stderr) => { 199 | if (error) reject(new Error('Cannot run npm pack')); 200 | else resolve(stderr + stdout); 201 | }); 202 | }); 203 | } 204 | 205 | type PackageHashes = { 206 | packageName: string; 207 | version: string; 208 | repoUrl: string; 209 | gitHead: string; 210 | shasum: string; 211 | }; 212 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es6"], 4 | "module": "commonjs", 5 | "noImplicitReturns": true, 6 | "outDir": "lib", 7 | "sourceMap": true, 8 | "target": "es6", 9 | "declaration": true 10 | }, 11 | "include": ["src"] 12 | } 13 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "adjacent-overload-signatures": true, 4 | "ban-comma-operator": true, 5 | "no-namespace": true, 6 | "no-parameter-reassignment": true, 7 | "no-reference": true, 8 | "label-position": true, 9 | "no-conditional-assignment": true, 10 | "no-construct": true, 11 | "no-duplicate-super": true, 12 | "no-duplicate-switch-case": true, 13 | "no-duplicate-variable": [true, "check-parameters"], 14 | "no-shadowed-variable": true, 15 | "no-empty": [true, "allow-empty-catch"], 16 | "no-invalid-this": true, 17 | "no-string-throw": true, 18 | "no-unsafe-finally": true, 19 | "no-duplicate-imports": true, 20 | "no-empty-interface": { 21 | "severity": "warning" 22 | }, 23 | "no-import-side-effect": { 24 | "severity": "warning" 25 | }, 26 | "no-var-keyword": { 27 | "severity": "warning" 28 | }, 29 | "triple-equals": { 30 | "severity": "warning" 31 | }, 32 | "prefer-for-of": { 33 | "severity": "warning" 34 | }, 35 | "unified-signatures": { 36 | "severity": "warning" 37 | }, 38 | "prefer-const": { 39 | "severity": "warning" 40 | }, 41 | "trailing-comma": { 42 | "severity": "warning" 43 | } 44 | }, 45 | "defaultSeverity": "error" 46 | } 47 | --------------------------------------------------------------------------------