From 97b41528739460b2e9e72e09000aded412418cb2 Mon Sep 17 00:00:00 2001 From: Ruy Adorno Date: Thu, 25 Mar 2021 00:45:30 -0400 Subject: [PATCH] add smoke tests Lightweight smoke test suite that runs common commands so that we can also have a holistic check during CI. PR-URL: https://github.com/npm/cli/pull/2959 Credit: @ruyadorno Close: #2959 Reviewed-by: @nlf --- .github/workflows/ci.yml | 42 ++ .npmignore | 4 + Makefile | 5 +- package.json | 3 +- smoke-tests/content/abbrev.json | 449 ++++++++++++ smoke-tests/content/abbrev.min.json | 89 +++ smoke-tests/content/abbrev/-/abbrev-1.0.4.tgz | Bin 0 -> 2295 bytes smoke-tests/content/abbrev/-/abbrev-1.1.1.tgz | Bin 0 -> 2301 bytes .../content/promise-all-reject-late.json | 138 ++++ .../content/promise-all-reject-late.min.json | 44 ++ .../-/promise-all-reject-late-1.0.1.tgz | Bin 0 -> 30838 bytes smoke-tests/index.js | 196 ++++++ smoke-tests/server.js | 276 ++++++++ .../smoke-tests-index.js-TAP.test.js | 649 ++++++++++++++++++ 14 files changed, 1893 insertions(+), 2 deletions(-) create mode 100644 smoke-tests/content/abbrev.json create mode 100644 smoke-tests/content/abbrev.min.json create mode 100644 smoke-tests/content/abbrev/-/abbrev-1.0.4.tgz create mode 100644 smoke-tests/content/abbrev/-/abbrev-1.1.1.tgz create mode 100644 smoke-tests/content/promise-all-reject-late.json create mode 100644 smoke-tests/content/promise-all-reject-late.min.json create mode 100644 smoke-tests/content/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz create mode 100644 smoke-tests/index.js create mode 100644 smoke-tests/server.js create mode 100644 tap-snapshots/smoke-tests-index.js-TAP.test.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 851b3fdcb9fe..14f362b45e30 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,48 @@ jobs: - name: Run linting run: node . run licenses + smoke-tests: + strategy: + fail-fast: false + matrix: + node-version: [10.x, 12.x, 14.x] + platform: + - os: ubuntu-latest + shell: bash + - os: macos-latest + shell: bash + - os: windows-latest + shell: bash + - os: windows-latest + shell: powershell + + runs-on: ${{ matrix.platform.os }} + defaults: + run: + shell: ${{ matrix.platform.shell }} + + steps: + # Checkout the npm/cli repo + - uses: actions/checkout@v2 + + # Installs the specific version of Node.js + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + # Run the installer script + - name: Install dependencies + run: | + node . install --ignore-scripts --no-audit + node . rebuild + + # Run the smoke tests + - name: Run Smoke tests + run: node . run --ignore-scripts smoke-tests -- --no-check-coverage -t600 -Rbase -c + env: + DEPLOY_VERSION: testing + build: strategy: fail-fast: false diff --git a/.npmignore b/.npmignore index 409905efd277..9d02b99f91b3 100644 --- a/.npmignore +++ b/.npmignore @@ -39,3 +39,7 @@ docs/template.html Session.vim .nyc_output /.editorconfig + +# don't ship smoke tests +smoke-tests/ +tap-snapshots/smoke-tests-index.js-TAP.test.js diff --git a/Makefile b/Makefile index 656f64f79efd..b8add91b64d1 100644 --- a/Makefile +++ b/Makefile @@ -76,6 +76,9 @@ docs/content/using-npm/config.md: scripts/config-doc.js lib/utils/config/*.js test: dev-deps node bin/npm-cli.js test +smoke-tests: dev-deps + node bin/npm-cli.js run smoke-tests + ls-ok: node . ls --production >/dev/null @@ -93,7 +96,7 @@ prune: @[[ "$(shell git status -s)" != "" ]] && echo "ERR: found unpruned files" && exit 1 || echo "git status is clean" -publish: gitclean ls-ok link test docs prune +publish: gitclean ls-ok link test smoke-tests docs prune @git push origin :v$(shell node bin/npm-cli.js --no-timing -v) 2>&1 || true git push origin $(BRANCH) &&\ git push origin --tags &&\ diff --git a/package.json b/package.json index 4d531d7de905..2dcc65543f91 100644 --- a/package.json +++ b/package.json @@ -207,7 +207,8 @@ "lint": "npm run eslint -- test/lib test/bin \"lib/**/*.js\"", "lintfix": "npm run lint -- --fix", "prelint": "rimraf test/npm_cache*", - "resetdeps": "bash scripts/resetdeps.sh" + "resetdeps": "bash scripts/resetdeps.sh", + "smoke-tests": "tap smoke-tests/index.js" }, "//": [ "XXX temporarily only run unit tests while v7 beta is in progress", diff --git a/smoke-tests/content/abbrev.json b/smoke-tests/content/abbrev.json new file mode 100644 index 000000000000..ffcf5474a9de --- /dev/null +++ b/smoke-tests/content/abbrev.json @@ -0,0 +1,449 @@ +{ + "_id": "abbrev", + "_rev": "72-d1d46bef3d311d6da6737e109e771869", + "name": "abbrev", + "dist-tags": { + "latest": "1.1.1" + }, + "versions": { + "1.0.3": { + "name": "abbrev", + "version": "1.0.3", + "description": "Like ruby's abbrev module, but in js", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "main": "./lib/abbrev.js", + "scripts": { + "test": "node lib/abbrev.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/isaacs/abbrev-js.git" + }, + "_id": "abbrev@1.0.3", + "engines": { + "node": "*" + }, + "_engineSupported": true, + "_npmVersion": "1.0.0rc7", + "_nodeVersion": "v0.5.0-pre", + "_defaultsLoaded": true, + "dist": { + "shasum": "aa049c967f999222aa42e14434f0c562ef468241", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.3.tgz" + }, + "directories": {} + }, + "1.0.4": { + "name": "abbrev", + "version": "1.0.4", + "description": "Like ruby's abbrev module, but in js", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "main": "./lib/abbrev.js", + "scripts": { + "test": "node lib/abbrev.js" + }, + "repository": { + "type": "git", + "url": "http://github.com/isaacs/abbrev-js" + }, + "license": { + "type": "MIT", + "url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE" + }, + "_id": "abbrev@1.0.4", + "dist": { + "shasum": "bd55ae5e413ba1722ee4caba1f6ea10414a59ecd", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz" + }, + "_npmVersion": "1.1.70", + "_npmUser": { + "name": "isaacs", + "email": "i@izs.me" + }, + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "directories": {} + }, + "1.0.5": { + "name": "abbrev", + "version": "1.0.5", + "description": "Like ruby's abbrev module, but in js", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "main": "abbrev.js", + "scripts": { + "test": "node test.js" + }, + "repository": { + "type": "git", + "url": "http://github.com/isaacs/abbrev-js" + }, + "license": { + "type": "MIT", + "url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE" + }, + "bugs": { + "url": "https://github.com/isaacs/abbrev-js/issues" + }, + "homepage": "https://github.com/isaacs/abbrev-js", + "_id": "abbrev@1.0.5", + "_shasum": "5d8257bd9ebe435e698b2fa431afde4fe7b10b03", + "_from": ".", + "_npmVersion": "1.4.7", + "_npmUser": { + "name": "isaacs", + "email": "i@izs.me" + }, + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "dist": { + "shasum": "5d8257bd9ebe435e698b2fa431afde4fe7b10b03", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz" + }, + "directories": {} + }, + "1.0.6": { + "name": "abbrev", + "version": "1.0.6", + "description": "Like ruby's abbrev module, but in js", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "main": "abbrev.js", + "scripts": { + "test": "node test.js" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/isaacs/abbrev-js.git" + }, + "license": "ISC", + "gitHead": "648a6735d9c5a7a04885e3ada49eed4db36181c2", + "bugs": { + "url": "https://github.com/isaacs/abbrev-js/issues" + }, + "homepage": "https://github.com/isaacs/abbrev-js#readme", + "_id": "abbrev@1.0.6", + "_shasum": "b6d632b859b3fa2d6f7e4b195472461b9e32dc30", + "_from": ".", + "_npmVersion": "2.10.0", + "_nodeVersion": "2.0.1", + "_npmUser": { + "name": "isaacs", + "email": "isaacs@npmjs.com" + }, + "dist": { + "shasum": "b6d632b859b3fa2d6f7e4b195472461b9e32dc30", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.6.tgz" + }, + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "directories": {} + }, + "1.0.7": { + "name": "abbrev", + "version": "1.0.7", + "description": "Like ruby's abbrev module, but in js", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "main": "abbrev.js", + "scripts": { + "test": "tap test.js --cov" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/isaacs/abbrev-js.git" + }, + "license": "ISC", + "devDependencies": { + "tap": "^1.2.0" + }, + "gitHead": "821d09ce7da33627f91bbd8ed631497ed6f760c2", + "bugs": { + "url": "https://github.com/isaacs/abbrev-js/issues" + }, + "homepage": "https://github.com/isaacs/abbrev-js#readme", + "_id": "abbrev@1.0.7", + "_shasum": "5b6035b2ee9d4fb5cf859f08a9be81b208491843", + "_from": ".", + "_npmVersion": "2.10.1", + "_nodeVersion": "2.0.1", + "_npmUser": { + "name": "isaacs", + "email": "isaacs@npmjs.com" + }, + "dist": { + "shasum": "5b6035b2ee9d4fb5cf859f08a9be81b208491843", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" + }, + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "directories": {} + }, + "1.0.9": { + "name": "abbrev", + "version": "1.0.9", + "description": "Like ruby's abbrev module, but in js", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "main": "abbrev.js", + "scripts": { + "test": "tap test.js --cov" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/isaacs/abbrev-js.git" + }, + "license": "ISC", + "devDependencies": { + "tap": "^5.7.2" + }, + "files": [ + "abbrev.js" + ], + "gitHead": "c386cd9dbb1d8d7581718c54d4ba944cc9298d6f", + "bugs": { + "url": "https://github.com/isaacs/abbrev-js/issues" + }, + "homepage": "https://github.com/isaacs/abbrev-js#readme", + "_id": "abbrev@1.0.9", + "_shasum": "91b4792588a7738c25f35dd6f63752a2f8776135", + "_from": ".", + "_npmVersion": "3.9.1", + "_nodeVersion": "4.4.4", + "_npmUser": { + "name": "isaacs", + "email": "i@izs.me" + }, + "dist": { + "shasum": "91b4792588a7738c25f35dd6f63752a2f8776135", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" + }, + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "_npmOperationalInternal": { + "host": "packages-16-east.internal.npmjs.com", + "tmp": "tmp/abbrev-1.0.9.tgz_1466016055839_0.7825860097073019" + }, + "directories": {} + }, + "1.1.0": { + "name": "abbrev", + "version": "1.1.0", + "description": "Like ruby's abbrev module, but in js", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "main": "abbrev.js", + "scripts": { + "test": "tap test.js --100", + "preversion": "npm test", + "postversion": "npm publish", + "postpublish": "git push origin --all; git push origin --tags" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/isaacs/abbrev-js.git" + }, + "license": "ISC", + "devDependencies": { + "tap": "^10.1" + }, + "files": [ + "abbrev.js" + ], + "gitHead": "7136d4d95449dc44115d4f78b80ec907724f64e0", + "bugs": { + "url": "https://github.com/isaacs/abbrev-js/issues" + }, + "homepage": "https://github.com/isaacs/abbrev-js#readme", + "_id": "abbrev@1.1.0", + "_shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f", + "_from": ".", + "_npmVersion": "4.3.0", + "_nodeVersion": "8.0.0-pre", + "_npmUser": { + "name": "isaacs", + "email": "i@izs.me" + }, + "dist": { + "shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz" + }, + "maintainers": [ + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "_npmOperationalInternal": { + "host": "packages-12-west.internal.npmjs.com", + "tmp": "tmp/abbrev-1.1.0.tgz_1487054000015_0.9229173036292195" + }, + "directories": {} + }, + "1.1.1": { + "name": "abbrev", + "version": "1.1.1", + "description": "Like ruby's abbrev module, but in js", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "main": "abbrev.js", + "scripts": { + "test": "tap test.js --100", + "preversion": "npm test", + "postversion": "npm publish", + "postpublish": "git push origin --all; git push origin --tags" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/isaacs/abbrev-js.git" + }, + "license": "ISC", + "devDependencies": { + "tap": "^10.1" + }, + "files": [ + "abbrev.js" + ], + "gitHead": "a9ee72ebc8fe3975f1b0c7aeb3a8f2a806a432eb", + "bugs": { + "url": "https://github.com/isaacs/abbrev-js/issues" + }, + "homepage": "https://github.com/isaacs/abbrev-js#readme", + "_id": "abbrev@1.1.1", + "_npmVersion": "5.4.2", + "_nodeVersion": "8.5.0", + "_npmUser": { + "name": "isaacs", + "email": "i@izs.me" + }, + "dist": { + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "shasum": "f8f2c887ad10bf67f634f005b6987fed3179aac8", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" + }, + "maintainers": [ + { + "name": "gabra", + "email": "jerry+1@npmjs.com" + }, + { + "name": "isaacs", + "email": "i@izs.me" + } + ], + "_npmOperationalInternal": { + "host": "s3://npm-registry-packages", + "tmp": "tmp/abbrev-1.1.1.tgz_1506566833068_0.05750026390887797" + }, + "directories": {} + } + }, + "maintainers": [ + { + "email": "quitlahok@gmail.com", + "name": "nlf" + }, + { + "email": "ruyadorno@hotmail.com", + "name": "ruyadorno" + }, + { + "email": "darcy@darcyclarke.me", + "name": "darcyclarke" + }, + { + "email": "evilpacket@gmail.com", + "name": "adam_baldwin" + }, + { + "email": "i@izs.me", + "name": "isaacs" + } + ], + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "description": "Like ruby's abbrev module, but in js", + "time": { + "modified": "2020-10-13T05:04:03.636Z", + "created": "2011-03-21T22:21:11.183Z", + "1.0.1": "2011-03-21T22:21:11.183Z", + "1.0.2": "2011-03-21T22:21:11.183Z", + "1.0.3": "2011-03-21T22:21:11.183Z", + "1.0.3-1": "2011-03-24T23:01:19.581Z", + "1.0.4": "2013-01-09T00:01:24.135Z", + "1.0.5": "2014-04-17T20:09:12.523Z", + "1.0.6": "2015-05-21T00:58:16.778Z", + "1.0.7": "2015-05-30T22:57:54.685Z", + "1.0.9": "2016-06-15T18:41:01.215Z", + "1.1.0": "2017-02-14T06:33:20.235Z", + "1.1.1": "2017-09-28T02:47:13.220Z" + }, + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/isaacs/abbrev-js.git" + }, + "users": { + "leesei": true, + "ceejbot": true, + "isaacs": true, + "npm-www": true, + "tunnckocore": true, + "ruanyu1": true, + "leodutra": true, + "jessaustin": true, + "jian263994241": true, + "floriannagel": true, + "tdmalone": true, + "ryanve": true, + "detj": true, + "monjer": true, + "d-band": true + }, + "readme": "# abbrev-js\n\nJust like [ruby's Abbrev](http://apidock.com/ruby/Abbrev).\n\nUsage:\n\n var abbrev = require(\"abbrev\");\n abbrev(\"foo\", \"fool\", \"folding\", \"flop\");\n \n // returns:\n { fl: 'flop'\n , flo: 'flop'\n , flop: 'flop'\n , fol: 'folding'\n , fold: 'folding'\n , foldi: 'folding'\n , foldin: 'folding'\n , folding: 'folding'\n , foo: 'foo'\n , fool: 'fool'\n }\n\nThis is handy for command-line scripts, or other cases where you want to be able to accept shorthands.\n", + "readmeFilename": "README.md", + "homepage": "https://github.com/isaacs/abbrev-js#readme", + "bugs": { + "url": "https://github.com/isaacs/abbrev-js/issues" + }, + "license": "ISC" +} diff --git a/smoke-tests/content/abbrev.min.json b/smoke-tests/content/abbrev.min.json new file mode 100644 index 000000000000..c03d91c9c8c1 --- /dev/null +++ b/smoke-tests/content/abbrev.min.json @@ -0,0 +1,89 @@ +{ + "name": "abbrev", + "dist-tags": { + "latest": "1.1.1" + }, + "versions": { + "1.0.3": { + "name": "abbrev", + "version": "1.0.3", + "dist": { + "shasum": "aa049c967f999222aa42e14434f0c562ef468241", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.3.tgz" + }, + "engines": { + "node": "*" + } + }, + "1.0.4": { + "name": "abbrev", + "version": "1.0.4", + "dist": { + "shasum": "bd55ae5e413ba1722ee4caba1f6ea10414a59ecd", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz" + } + }, + "1.0.5": { + "name": "abbrev", + "version": "1.0.5", + "dist": { + "shasum": "5d8257bd9ebe435e698b2fa431afde4fe7b10b03", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.5.tgz" + } + }, + "1.0.6": { + "name": "abbrev", + "version": "1.0.6", + "dist": { + "shasum": "b6d632b859b3fa2d6f7e4b195472461b9e32dc30", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.6.tgz" + } + }, + "1.0.7": { + "name": "abbrev", + "version": "1.0.7", + "devDependencies": { + "tap": "^1.2.0" + }, + "dist": { + "shasum": "5b6035b2ee9d4fb5cf859f08a9be81b208491843", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" + } + }, + "1.0.9": { + "name": "abbrev", + "version": "1.0.9", + "devDependencies": { + "tap": "^5.7.2" + }, + "dist": { + "shasum": "91b4792588a7738c25f35dd6f63752a2f8776135", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz" + } + }, + "1.1.0": { + "name": "abbrev", + "version": "1.1.0", + "devDependencies": { + "tap": "^10.1" + }, + "dist": { + "shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz" + } + }, + "1.1.1": { + "name": "abbrev", + "version": "1.1.1", + "devDependencies": { + "tap": "^10.1" + }, + "dist": { + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "shasum": "f8f2c887ad10bf67f634f005b6987fed3179aac8", + "tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" + } + } + }, + "modified": "2020-10-13T05:04:03.636Z" +} diff --git a/smoke-tests/content/abbrev/-/abbrev-1.0.4.tgz b/smoke-tests/content/abbrev/-/abbrev-1.0.4.tgz new file mode 100644 index 0000000000000000000000000000000000000000..dfd1b55919e2f24febd758561d7640b0c1a7059a GIT binary patch literal 2295 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 {\n return lateReject(files.map(file => writeFile(file, 'some data')))\n .catch(er => {\n // try to clean up, then fail with the initial error\n // we know that all write attempts are finished at this point\n return lateReject(files.map(file => rimraf(file)))\n .catch(er => {\n console.error('failed to clean up, youre on your own i guess', er)\n })\n .then(() => {\n // fail with the original error\n throw er\n })\n })\n}\n```\n\n## API\n\n* `lateReject([array, of, promises])` - Resolve all the promises,\n returning a promise that rejects with the first error, or resolves with\n the array of results, but only after all promises are settled.\n", + "readmeFilename": "README.md", + "_cached": false, + "_contentLength": 0 +} \ No newline at end of file diff --git a/smoke-tests/content/promise-all-reject-late.min.json b/smoke-tests/content/promise-all-reject-late.min.json new file mode 100644 index 000000000000..699be7aaf2e8 --- /dev/null +++ b/smoke-tests/content/promise-all-reject-late.min.json @@ -0,0 +1,44 @@ +{ + "name": "promise-all-reject-late", + "dist-tags": { + "latest": "1.0.1" + }, + "versions": { + "1.0.0": { + "name": "promise-all-reject-late", + "version": "1.0.0", + "devDependencies": { + "tap": "^14.10.5" + }, + "dist": { + "integrity": "sha512-f5XvVl++12pEo7Sv7f7FGfzVuVpeY2msNKjn7nNcXyOSKh5uVu7IAzDO6RE9hDVoHJhxvg+gqEacwkZ891Se5g==", + "shasum": "4fa37515e2d78c3b0462414402a8debce62b8b9f", + "tarball": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.0.tgz", + "fileCount": 7, + "unpackedSize": 123039, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeBmldCRA9TVsSAnZWagAAaigP/2CarvNCbglNS0dgjOoH\n7ZuFo1cG+N8BkZct00TyEJjuB+5UUmv9TSnZogfEOGutvMqUTSRhvm3fOWsJ\n7TXs8zJ6SotDR9+xlxqi/skpYXfRdNjdaMvo9kYO5jaV84pstdbl17sPeYXd\nCudbAKp1sYodlaJyqpyfUd2PWUNe/VGLODmjLogHB4/bevT3tdjsdauKrUS4\n3VFw8sS1Fwp7P2YneNIK3C1TY/Yb66KysZO23VsQemCQFKXpQJMa9B6yj8zs\n5BQp+W5tM70IfW6OXD0+Vt2jWr9jmKmoWVEiL5usJT3zD7vRbeH3xQvSEgDD\nskI8vH8iJ+3EbEOWTGlIu7mX88Dp2KnHOoRUkOR03WJWuGnsTC8Uyqi0F1Xd\nFeFlaeNzynR/R2LcdRNiFOM+1xtzfAtVGF7TIp9UjgJwSNNkEMlkNzQqSiC7\n/AeqsAYoBBNmYWY2fvXdS9HQ4HfIGjI++jCYWX4I7sUvOjqfcwlEz8MwromA\nqeBAFPdvnB0F/q/AOOLkcdsO81jES7ts0nB7bDt0rDbztWWq34BSMDnNoSDo\nDE9q8u7g68tQcr3WmOQr4ro10sSbJVJZmz8DSJKCbVJ+FN0+GM+49oyyhIFl\nOjokXn5U8ASEdiZnmFnt51dr9A4fyjhehotJA6qSs7t2fBe86VnufijC971U\nv3Jc\r\n=lLwf\r\n-----END PGP SIGNATURE-----\r\n" + } + }, + "1.0.1": { + "name": "promise-all-reject-late", + "version": "1.0.1", + "devDependencies": { + "tap": "^14.10.5" + }, + "dist": { + "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "shasum": "f8ebf13483e5ca91ad809ccc2fcf25f26f8643c2", + "tarball": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", + "fileCount": 8, + "unpackedSize": 123171, + "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeL65kCRA9TVsSAnZWagAAas4P/2WFFJvncp0LWb3DbE0t\ndx9BhZEwY3W8V6ug8uKvph24LoQp1PakkncscKS7PsCVHyIslD+fi6V99AmI\nOmL2ECAMUd5N69Cs8eTi4tKTNtUoIslfCu0+SMlCAF11D7oBXSabdOxGQofA\nuksoHdCqGM6M1y2BGjK7FR8dSwvgbQCPaUzazZ5w7w4XqVxDlzbvNj2E5mSF\n5HjlT5q239uNQppwPIFpisyi9DKa0ran2N7F2ioZ1PHvhFCqo6rmL8tAQsxQ\n+3OA4eFD0FJCJuqd3MOaY66mkncfNpmPvQYMyigKBUdJJyrgNsB67yfaFduy\ndK198Bnva5kotttQ4EHxM6gkqRm2d9o1/sYmAUtDELgrVDxzeNl+yG+nCkho\n1ta4cY+wy1dTjqAYaprQJ855nIeGGnr3tvz4dEGX/5eyh5K+oYVOYRFvWFX6\nVlEhBmSRqamfW5N1ndMyY18FM+Vc12yu66yZ3z1FqbgEGqdf3EP3lwWqClpP\nbPdXANzHM1FIz1PGHC7IZFWXH5KV1z+JXXahg/d8CLzz0PY6jaBt4c2xDvo7\nLaEAm7kNMbdewKvuTuG7x2Kqyf1KwjpOhXMrq6h0rlFm0pRt0xAArQ9Sglw8\n2Vq9Ic9EEsSIpzA5iQ86O1xkTREGHTB3uTRXUJixXIGkhLkhBB+Uj9y+GoOh\nX+Dm\r\n=yF+m\r\n-----END PGP SIGNATURE-----\r\n" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + } + }, + "modified": "2020-01-28T03:45:42.154Z", + "_cached": false, + "_contentLength": 2803 +} \ No newline at end of file diff --git a/smoke-tests/content/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz b/smoke-tests/content/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz new file mode 100644 index 0000000000000000000000000000000000000000..7da40442387663b9f251a44867e18246aaa6c25d GIT binary patch literal 30838 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 z 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 z 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 R`1~V({y&|#T>b$50RR?OQ^^1T literal 0 HcmV?d00001 diff --git a/smoke-tests/index.js b/smoke-tests/index.js new file mode 100644 index 000000000000..38c3ed306e5f --- /dev/null +++ b/smoke-tests/index.js @@ -0,0 +1,196 @@ +const fs = require('fs') +const { promisify } = require('util') +const execAsync = promisify(require('child_process').exec) +const { resolve } = require('path') +const t = require('tap') + +const normalizePath = path => path.replace(/[A-Z]:/, '').replace(/\\/g, '/') +const cwd = normalizePath(process.cwd()) +t.cleanSnapshot = s => s.split(cwd).join('{CWD}') + .split(registry).join('https://registry.npmjs.org/') + .split(normalizePath(process.execPath)).join('node') + .split(process.cwd()).join('{CWD}') + .replace(/\\+/g, '/') + .replace(/\r\n/g, '\n') + +// setup server +const registryServer = require('./server.js') +const { registry } = registryServer +t.test('setup server', { bail: true, buffered: false }, registryServer) + +// setup fixtures +const path = t.testdir({ + '.npmrc': '', + cache: {}, + project: {}, + bin: {}, +}) +const localPrefix = resolve(path, 'project') +const userconfigLocation = resolve(path, '.npmrc') +const npmLocation = resolve(__dirname, '..') +const cacheLocation = resolve(path, 'cache') +const binLocation = resolve(path, 'bin') +const env = { + HOME: path, + PATH: `${process.env.PATH}:${binLocation}`, +} +const npmOpts = `--registry=${registry} --cache="${cacheLocation}" --userconfig="${userconfigLocation}" --no-audit --no-update-notifier --loglevel=silly` +const npmBin = `"${process.execPath}" "${npmLocation}" ${npmOpts}` +const exec = async cmd => { + const res = await execAsync(cmd, { cwd: localPrefix, env }) + if (res.stderr) + console.error(res.stderr) + return String(res.stdout) +} +const readFile = filename => + String(fs.readFileSync(resolve(localPrefix, filename))) + +t.test('npm init', async t => { + const cmd = `${npmBin} init -y` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes, 'should have successful npm init result') + const pkg = JSON.parse(fs.readFileSync(resolve(localPrefix, 'package.json'))) + t.equal(pkg.name, 'project', 'should have expected generated name') + t.equal(pkg.version, '1.0.0', 'should have expected generated version') +}) + +t.test('npm install prodDep@version', async t => { + const cmd = `${npmBin} install abbrev@1.0.4` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes.replace(/in.*s/, ''), + 'should have expected install reify output') + t.matchSnapshot( + readFile('package.json'), + 'should have expected package.json result' + ) + t.matchSnapshot( + readFile('package-lock.json'), + 'should have expected lockfile result' + ) +}) + +t.test('npm install dev dep', async t => { + const cmd = `${npmBin} install -D promise-all-reject-late` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes.replace(/in.*s/, ''), + 'should have expected dev dep added reify output') + t.matchSnapshot( + readFile('package.json'), + 'should have expected dev dep added package.json result' + ) + t.matchSnapshot( + readFile('package-lock.json'), + 'should have expected dev dep added lockfile result' + ) +}) + +t.test('npm ls', async t => { + const cmd = `${npmBin} ls` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes, + 'should have expected ls output') +}) + +t.test('npm fund', async t => { + const cmd = `${npmBin} fund` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes, + 'should have expected fund output') +}) + +t.test('npm explain', async t => { + const cmd = `${npmBin} explain abbrev` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes, + 'should have expected explain output') +}) + +t.test('npm diff', async t => { + const cmd = `${npmBin} diff --diff=abbrev@1.0.4 --diff=abbrev@1.1.1` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes, + 'should have expected diff output') +}) + +t.test('npm outdated', async t => { + const cmd = `${npmBin} outdated` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes, + 'should have expected outdated output') +}) + +t.test('npm set-script', async t => { + const cmd = `${npmBin} set-script "hello" "echo Hello"` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes, + 'should have expected set-script output') + t.matchSnapshot( + readFile('package.json'), + 'should have expected script added package.json result' + ) +}) + +t.test('npm run-script', async t => { + const cmd = `${npmBin} run hello` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes, + 'should have expected run-script output') +}) + +t.test('npm prefix', async t => { + const cmd = `${npmBin} prefix` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes, + 'should have expected prefix output') +}) + +t.test('npm view', async t => { + const cmd = `${npmBin} view abbrev@1.0.4` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes, + 'should have expected view output') +}) + +t.test('npm update dep', async t => { + const cmd = `${npmBin} update abbrev` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes.replace(/in.*s/, ''), + 'should have expected update reify output') + t.matchSnapshot( + readFile('package.json'), + 'should have expected update package.json result' + ) + t.matchSnapshot( + readFile('package-lock.json'), + 'should have expected update lockfile result' + ) +}) + +t.test('npm uninstall', async t => { + const cmd = `${npmBin} uninstall promise-all-reject-late` + const cmdRes = await exec(cmd) + + t.matchSnapshot(cmdRes.replace(/in.*s/, ''), + 'should have expected uninstall reify output') + t.matchSnapshot( + readFile('package.json'), + 'should have expected uninstall package.json result' + ) + t.matchSnapshot( + readFile('package-lock.json'), + 'should have expected uninstall lockfile result' + ) +}) diff --git a/smoke-tests/server.js b/smoke-tests/server.js new file mode 100644 index 000000000000..88cb5883da74 --- /dev/null +++ b/smoke-tests/server.js @@ -0,0 +1,276 @@ +const {join, dirname} = require('path') +const {existsSync, readFileSync, writeFileSync} = require('fs') +const PORT = 12345 + (+process.env.TAP_CHILD_ID || 0) +const http = require('http') +const https = require('https') + +const mkdirp = require('mkdirp') +const doProxy = process.env.ARBORIST_TEST_PROXY +const missing = /\/@isaacs(\/|%2[fF])(this-does-not-exist-at-all|testing-missing-tgz\/-\/)/ +const corgiDoc = 'application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*' +const { gzipSync, unzipSync } = require('zlib') + +let advisoryBulkResponse = null +let failAdvisoryBulk = false +let auditResponse = null +let failAudit = false +const startServer = cb => { + const server = module.exports.server = http.createServer((req, res) => { + res.setHeader('connection', 'close') + + if (req.url === '/-/npm/v1/security/advisories/bulk') { + const body = [] + req.on('data', c => body.push(c)) + req.on('end', () => { + res.setHeader('connection', 'close') + if (failAdvisoryBulk) { + res.statusCode = 503 + return res.end('no advisory bulk for you') + } + if (!advisoryBulkResponse) { + if (auditResponse && !failAudit) { + // simulate what the registry does when quick audits are allowed, + // but advisory bulk requests are not + res.statusCode = 405 + return res.end(JSON.stringify({ + code: 'MethodNotAllowedError', + message: 'POST is not allowed', + })) + } else { + res.statusCode = 404 + return res.end('not found') + } + } + if (doProxy && !existsSync(advisoryBulkResponse)) { + // hit the main registry, then fall back to staging for now + // XXX: remove this when bulk advisory endpoint pushed to production! + const opts = { + host: 'registry.npmjs.org', + method: req.method, + path: req.url, + headers: { + ...req.headers, + accept: '*', + host: 'registry.npmjs.org', + connection: 'close', + 'if-none-match': '', + }, + } + const handleUpstream = upstream => { + res.statusCode = upstream.statusCode + if (upstream.statusCode >= 300 || upstream.statusCode < 200) { + console.error('UPSTREAM ERROR', upstream.statusCode) + return upstream.pipe(res) + } + res.setHeader('content-encoding', upstream.headers['content-encoding']) + const file = advisoryBulkResponse + console.error('PROXY', `${req.url} -> ${file} ${upstream.statusCode}`) + mkdirp.sync(dirname(file)) + const data = [] + upstream.on('end', () => { + const out = Buffer.concat(data) + const obj = JSON.parse(unzipSync(out).toString()) + writeFileSync(file, JSON.stringify(obj, 0, 2) + '\n') + res.end(out) + }) + upstream.on('data', c => data.push(c)) + } + return https.request(opts).on('response', upstream => { + if (upstream.statusCode !== 200) { + console.error('ATTEMPTING TO PROXY FROM STAGING') + console.error('NOTE: THIS WILL FAIL WHEN NOT ON VPN!') + opts.host = 'security-microservice-3-west.npm.red' + opts.headers.host = opts.host + opts.path = '/v1/advisories/bulk' + https.request(opts) + .on('response', upstream => handleUpstream(upstream)) + .end(Buffer.concat(body)) + } else + handleUpstream(upstream) + }).end(Buffer.concat(body)) + } else { + res.setHeader('content-encoding', 'gzip') + res.end(gzipSync(readFileSync(advisoryBulkResponse))) + } + }) + return + } else if (req.url === '/-/npm/v1/security/audits/quick') { + const body = [] + req.on('data', c => body.push(c)) + req.on('end', () => { + res.setHeader('connection', 'close') + if (failAudit) { + res.statusCode = 503 + return res.end('no audit for you') + } + if (!auditResponse) { + res.statusCode = 404 + return res.end('not found') + } + if (doProxy && !existsSync(auditResponse)) { + return https.request({ + host: 'registry.npmjs.org', + method: req.method, + path: req.url, + headers: { + ...req.headers, + accept: '*', + host: 'registry.npmjs.org', + connection: 'close', + 'if-none-match': '', + }, + }).on('response', upstream => { + res.statusCode = upstream.statusCode + if (upstream.statusCode >= 300 || upstream.statusCode < 200) { + console.error('UPSTREAM ERROR', upstream.statusCode) + // don't save if it's not a valid response + return upstream.pipe(res) + } + res.setHeader('content-encoding', upstream.headers['content-encoding']) + const file = auditResponse + console.error('PROXY', `${req.url} -> ${file} ${upstream.statusCode}`) + mkdirp.sync(dirname(file)) + const data = [] + upstream.on('end', () => { + const out = Buffer.concat(data) + // make it a bit prettier to read later + const obj = JSON.parse(unzipSync(out).toString()) + writeFileSync(file, JSON.stringify(obj, 0, 2) + '\n') + res.end(out) + }) + upstream.on('data', c => data.push(c)) + }).end(Buffer.concat(body)) + } else { + res.setHeader('content-encoding', 'gzip') + res.end(gzipSync(readFileSync(auditResponse))) + } + }) + return + } + + const f = join(__dirname, 'content', join('/', req.url.replace(/@/, '').replace(/%2f/i, '/'))) + const isCorgi = req.headers.accept.includes('application/vnd.npm.install-v1+json') + const file = f + ( + isCorgi && existsSync(`${f}.min.json`) ? '.min.json' + : existsSync(`${f}.json`) ? '.json' + : existsSync(`${f}/index.json`) ? 'index.json' + : '' + ) + + try { + const body = readFileSync(file) + res.setHeader('content-length', body.length) + res.setHeader('content-type', /\.min\.json$/.test(file) ? corgiDoc + : /\.json$/.test(file) ? 'application/json' + : 'application/octet-stream') + res.end(body) + } catch (er) { + // testing things going missing from the registry somehow + if (missing.test(req.url)) { + res.statusCode = 404 + res.end('{"error": "not found"}') + return + } + + if (doProxy) { + return https.get({ + host: 'registry.npmjs.org', + path: req.url, + headers: { + ...req.headers, + accept: '*', + 'accept-encoding': 'identity', + host: 'registry.npmjs.org', + connection: 'close', + 'if-none-match': '', + }, + }).on('response', upstream => { + const errorStatus = + upstream.statusCode >= 300 || upstream.statusCode < 200 + + if (errorStatus) + console.error('UPSTREAM ERROR', upstream.statusCode) + + const ct = upstream.headers['content-type'] + const isJson = ct.includes('application/json') + const file = isJson ? f + '.json' : f + console.error('PROXY', `${req.url} -> ${file} ${ct}`) + mkdirp.sync(dirname(file)) + const data = [] + res.statusCode = upstream.statusCode + res.setHeader('content-type', ct) + upstream.on('end', () => { + console.error('ENDING', req.url) + const out = Buffer.concat(data) + if (!errorStatus) { + if (isJson) { + const obj = JSON.parse(out.toString()) + writeFileSync(file, JSON.stringify(obj, 0, 2) + '\n') + const mrm = require('minify-registry-metadata') + const minFile = file.replace(/\.json$/, '.min.json') + writeFileSync(minFile, JSON.stringify(mrm(obj), 0, 2) + '\n') + console.error('WROTE JSONS', [file, minFile]) + } else + writeFileSync(file, out) + } + res.end(out) + }) + upstream.on('data', c => data.push(c)) + }).end() + } + + res.statusCode = er.code === 'ENOENT' ? 404 : 500 + if (res.method === 'GET') + console.error(er) + res.setHeader('content-type', 'text/plain') + res.end(er.stack) + } + }) + server.listen(PORT, cb) +} + +module.exports = t => startServer(() => { + t.parent.teardown(() => module.exports.server.close()) + t.end() +}) + +module.exports.auditResponse = value => { + if (auditResponse && auditResponse !== value) { + throw new Error('setting audit response, but already set\n' + + '(did you forget to call the returned function on teardown?)') + } + auditResponse = value + return () => auditResponse = null +} +module.exports.failAudit = () => { + failAudit = true + return () => failAudit = false +} + +module.exports.advisoryBulkResponse = value => { + if (advisoryBulkResponse && advisoryBulkResponse !== value) { + throw new Error('setting advisory bulk response, but already set\n' + + '(did you forget to call the returned function on teardown?)') + } + advisoryBulkResponse = value + return () => advisoryBulkResponse = null +} +module.exports.failAdvisoryBulk = () => { + failAdvisoryBulk = true + return () => failAdvisoryBulk = false +} + +module.exports.registry = `http://localhost:${PORT}/` + +module.exports.start = startServer +module.exports.stop = () => module.exports.server.close() + +if (require.main === module) { + startServer(() => { + console.log(`Mock registry live at: + ${module.exports.registry} +Press ^D to close gracefully.`) + }) + process.openStdin() + process.stdin.on('end', () => module.exports.server.close()) +} diff --git a/tap-snapshots/smoke-tests-index.js-TAP.test.js b/tap-snapshots/smoke-tests-index.js-TAP.test.js new file mode 100644 index 000000000000..aa8977316b1c --- /dev/null +++ b/tap-snapshots/smoke-tests-index.js-TAP.test.js @@ -0,0 +1,649 @@ +/* IMPORTANT + * This snapshot file is auto-generated, but designed for humans. + * It should be checked into source control and tracked carefully. + * Re-generate by setting TAP_SNAPSHOT=1 and running tests. + * Make sure to inspect the output below. Do not ignore changes! + */ +'use strict' +exports[`smoke-tests/index.js TAP npm diff > should have expected diff output 1`] = ` +diff --git a/package.json b/package.json +index v1.0.4..v1.1.1 100644 +--- a/package.json ++++ b/package.json +@@ -1,15 +1,21 @@ + { + "name": "abbrev", +- "version": "1.0.4", ++ "version": "1.1.1", + "description": "Like ruby's abbrev module, but in js", + "author": "Isaac Z. Schlueter ", +- "main": "./lib/abbrev.js", ++ "main": "abbrev.js", + "scripts": { +- "test": "node lib/abbrev.js" ++ "test": "tap test.js --100", ++ "preversion": "npm test", ++ "postversion": "npm publish", ++ "postpublish": "git push origin --all; git push origin --tags" + }, + "repository": "http://github.com/isaacs/abbrev-js", +- "license": { +- "type": "MIT", +- "url": "https://github.com/isaacs/abbrev-js/raw/master/LICENSE" +- } ++ "license": "ISC", ++ "devDependencies": { ++ "tap": "^10.1" ++ }, ++ "files": [ ++ "abbrev.js" ++ ] + } +diff --git a/LICENSE b/LICENSE +index v1.0.4..v1.1.1 100644 +--- a/LICENSE ++++ b/LICENSE +@@ -1,4 +1,27 @@ +-Copyright 2009, 2010, 2011 Isaac Z. Schlueter. ++This software is dual-licensed under the ISC and MIT licenses. ++You may use this software under EITHER of the following licenses. ++ ++---------- ++ ++The ISC License ++ ++Copyright (c) Isaac Z. Schlueter and Contributors ++ ++Permission to use, copy, modify, and/or distribute this software for any ++purpose with or without fee is hereby granted, provided that the above ++copyright notice and this permission notice appear in all copies. ++ ++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++---------- ++ ++Copyright Isaac Z. Schlueter and Contributors + All rights reserved. + + Permission is hereby granted, free of charge, to any person +diff --git a/lib/abbrev.js b/lib/abbrev.js +deleted file mode 100644 +index v1.0.4..v1.1.1 +--- a/lib/abbrev.js ++++ b/lib/abbrev.js +@@ -1,111 +0,0 @@ +- +-module.exports = exports = abbrev.abbrev = abbrev +- +-abbrev.monkeyPatch = monkeyPatch +- +-function monkeyPatch () { +- Object.defineProperty(Array.prototype, 'abbrev', { +- value: function () { return abbrev(this) }, +- enumerable: false, configurable: true, writable: true +- }) +- +- Object.defineProperty(Object.prototype, 'abbrev', { +- value: function () { return abbrev(Object.keys(this)) }, +- enumerable: false, configurable: true, writable: true +- }) +-} +- +-function abbrev (list) { +- if (arguments.length !== 1 || !Array.isArray(list)) { +- list = Array.prototype.slice.call(arguments, 0) +- } +- for (var i = 0, l = list.length, args = [] ; i < l ; i ++) { +- args[i] = typeof list[i] === "string" ? list[i] : String(list[i]) +- } +- +- // sort them lexicographically, so that they're next to their nearest kin +- args = args.sort(lexSort) +- +- // walk through each, seeing how much it has in common with the next and previous +- var abbrevs = {} +- , prev = "" +- for (var i = 0, l = args.length ; i < l ; i ++) { +- var current = args[i] +- , next = args[i + 1] || "" +- , nextMatches = true +- , prevMatches = true +- if (current === next) continue +- for (var j = 0, cl = current.length ; j < cl ; j ++) { +- var curChar = current.charAt(j) +- nextMatches = nextMatches && curChar === next.charAt(j) +- prevMatches = prevMatches && curChar === prev.charAt(j) +- if (!nextMatches && !prevMatches) { +- j ++ +- break +- } +- } +- prev = current +- if (j === cl) { +- abbrevs[current] = current +- continue +- } +- for (var a = current.substr(0, j) ; j <= cl ; j ++) { +- abbrevs[a] = current +- a += current.charAt(j) +- } +- } +- return abbrevs +-} +- +-function lexSort (a, b) { +- return a === b ? 0 : a > b ? 1 : -1 +-} +- +- +-// tests +-if (module === require.main) { +- +-var assert = require("assert") +-var util = require("util") +- +-console.log("running tests") +-function test (list, expect) { +- var actual = abbrev(list) +- assert.deepEqual(actual, expect, +- "abbrev("+util.inspect(list)+") === " + util.inspect(expect) + "/n"+ +- "actual: "+util.inspect(actual)) +- actual = abbrev.apply(exports, list) +- assert.deepEqual(abbrev.apply(exports, list), expect, +- "abbrev("+list.map(JSON.stringify).join(",")+") === " + util.inspect(expect) + "/n"+ +- "actual: "+util.inspect(actual)) +-} +- +-test([ "ruby", "ruby", "rules", "rules", "rules" ], +-{ rub: 'ruby' +-, ruby: 'ruby' +-, rul: 'rules' +-, rule: 'rules' +-, rules: 'rules' +-}) +-test(["fool", "foom", "pool", "pope"], +-{ fool: 'fool' +-, foom: 'foom' +-, poo: 'pool' +-, pool: 'pool' +-, pop: 'pope' +-, pope: 'pope' +-}) +-test(["a", "ab", "abc", "abcd", "abcde", "acde"], +-{ a: 'a' +-, ab: 'ab' +-, abc: 'abc' +-, abcd: 'abcd' +-, abcde: 'abcde' +-, ac: 'acde' +-, acd: 'acde' +-, acde: 'acde' +-}) +- +-console.log("pass") +- +-} +/ No newline at end of file +diff --git a/abbrev.js b/abbrev.js +new file mode 100644 +index v1.0.4..v1.1.1 +--- a/abbrev.js ++++ b/abbrev.js +@@ -0,0 +1,61 @@ ++module.exports = exports = abbrev.abbrev = abbrev ++ ++abbrev.monkeyPatch = monkeyPatch ++ ++function monkeyPatch () { ++ Object.defineProperty(Array.prototype, 'abbrev', { ++ value: function () { return abbrev(this) }, ++ enumerable: false, configurable: true, writable: true ++ }) ++ ++ Object.defineProperty(Object.prototype, 'abbrev', { ++ value: function () { return abbrev(Object.keys(this)) }, ++ enumerable: false, configurable: true, writable: true ++ }) ++} ++ ++function abbrev (list) { ++ if (arguments.length !== 1 || !Array.isArray(list)) { ++ list = Array.prototype.slice.call(arguments, 0) ++ } ++ for (var i = 0, l = list.length, args = [] ; i < l ; i ++) { ++ args[i] = typeof list[i] === "string" ? list[i] : String(list[i]) ++ } ++ ++ // sort them lexicographically, so that they're next to their nearest kin ++ args = args.sort(lexSort) ++ ++ // walk through each, seeing how much it has in common with the next and previous ++ var abbrevs = {} ++ , prev = "" ++ for (var i = 0, l = args.length ; i < l ; i ++) { ++ var current = args[i] ++ , next = args[i + 1] || "" ++ , nextMatches = true ++ , prevMatches = true ++ if (current === next) continue ++ for (var j = 0, cl = current.length ; j < cl ; j ++) { ++ var curChar = current.charAt(j) ++ nextMatches = nextMatches && curChar === next.charAt(j) ++ prevMatches = prevMatches && curChar === prev.charAt(j) ++ if (!nextMatches && !prevMatches) { ++ j ++ ++ break ++ } ++ } ++ prev = current ++ if (j === cl) { ++ abbrevs[current] = current ++ continue ++ } ++ for (var a = current.substr(0, j) ; j <= cl ; j ++) { ++ abbrevs[a] = current ++ a += current.charAt(j) ++ } ++ } ++ return abbrevs ++} ++ ++function lexSort (a, b) { ++ return a === b ? 0 : a > b ? 1 : -1 ++} + +` + +exports[`smoke-tests/index.js TAP npm explain > should have expected explain output 1`] = ` +abbrev@1.0.4 +node_modules/abbrev + abbrev@"^1.0.4" from the root project + +` + +exports[`smoke-tests/index.js TAP npm fund > should have expected fund output 1`] = ` +project@1.0.0 +\`-- https://github.com/sponsors/isaacs + \`-- promise-all-reject-late@1.0.1 + + +` + +exports[`smoke-tests/index.js TAP npm init > should have successful npm init result 1`] = ` +Wrote to {CWD}/smoke-tests/index/project/package.json: + +{ + "name": "project", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo /"Error: no test specified/" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} + + + +` + +exports[`smoke-tests/index.js TAP npm install dev dep > should have expected dev dep added lockfile result 1`] = ` +{ + "name": "project", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.4" + }, + "devDependencies": { + "promise-all-reject-late": "^1.0.1" + } + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "node_modules/promise-all-reject-late": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", + "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + } + }, + "dependencies": { + "abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + }, + "promise-all-reject-late": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", + "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "dev": true + } + } +} + +` + +exports[`smoke-tests/index.js TAP npm install dev dep > should have expected dev dep added package.json result 1`] = ` +{ + "name": "project", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo /"Error: no test specified/" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.4" + }, + "devDependencies": { + "promise-all-reject-late": "^1.0.1" + } +} + +` + +exports[`smoke-tests/index.js TAP npm install dev dep > should have expected dev dep added reify output 1`] = ` + +added 1 package + +1 package is looking for funding + run \`npm fund\` for details + +` + +exports[`smoke-tests/index.js TAP npm install prodDep@version > should have expected install reify output 1`] = ` + +added 1 package + +` + +exports[`smoke-tests/index.js TAP npm install prodDep@version > should have expected lockfile result 1`] = ` +{ + "name": "project", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + } + }, + "dependencies": { + "abbrev": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz", + "integrity": "sha1-vVWuXkE7oXIu5Mq6H26hBBSlns0=" + } + } +} + +` + +exports[`smoke-tests/index.js TAP npm install prodDep@version > should have expected package.json result 1`] = ` +{ + "name": "project", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo /"Error: no test specified/" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.4" + } +} + +` + +exports[`smoke-tests/index.js TAP npm ls > should have expected ls output 1`] = ` +project@1.0.0 {CWD}/smoke-tests/index/project ++-- abbrev@1.0.4 +\`-- promise-all-reject-late@1.0.1 + + +` + +exports[`smoke-tests/index.js TAP npm outdated > should have expected outdated output 1`] = ` +Package Current Wanted Latest Location Depended by +abbrev 1.0.4 1.1.1 1.1.1 node_modules/abbrev project + +` + +exports[`smoke-tests/index.js TAP npm prefix > should have expected prefix output 1`] = ` +{CWD}/smoke-tests/index/project + +` + +exports[`smoke-tests/index.js TAP npm run-script > should have expected run-script output 1`] = ` + +> project@1.0.0 hello +> echo Hello + +Hello + +` + +exports[`smoke-tests/index.js TAP npm set-script > should have expected script added package.json result 1`] = ` +{ + "name": "project", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo /"Error: no test specified/" && exit 1", + "hello": "echo Hello" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.4" + }, + "devDependencies": { + "promise-all-reject-late": "^1.0.1" + } +} + +` + +exports[`smoke-tests/index.js TAP npm set-script > should have expected set-script output 1`] = ` + +` + +exports[`smoke-tests/index.js TAP npm uninstall > should have expected uninstall lockfile result 1`] = ` +{ + "name": "project", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.4" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + } + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + } + } +} + +` + +exports[`smoke-tests/index.js TAP npm uninstall > should have expected uninstall package.json result 1`] = ` +{ + "name": "project", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo /"Error: no test specified/" && exit 1", + "hello": "echo Hello" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.4" + } +} + +` + +exports[`smoke-tests/index.js TAP npm uninstall > should have expected uninstall reify output 1`] = ` + +removed 1 package + +` + +exports[`smoke-tests/index.js TAP npm update dep > should have expected update lockfile result 1`] = ` +{ + "name": "project", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.4" + }, + "devDependencies": { + "promise-all-reject-late": "^1.0.1" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/promise-all-reject-late": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", + "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + } + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "promise-all-reject-late": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", + "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "dev": true + } + } +} + +` + +exports[`smoke-tests/index.js TAP npm update dep > should have expected update package.json result 1`] = ` +{ + "name": "project", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo /"Error: no test specified/" && exit 1", + "hello": "echo Hello" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "abbrev": "^1.0.4" + }, + "devDependencies": { + "promise-all-reject-late": "^1.0.1" + } +} + +` + +exports[`smoke-tests/index.js TAP npm update dep > should have expected update reify output 1`] = ` + +changed 1 package + +1 package is looking for funding + run \`npm fund\` for details + +` + +exports[`smoke-tests/index.js TAP npm view > should have expected view output 1`] = ` + +abbrev@1.0.4 | MIT | deps: none | versions: 8 +Like ruby's abbrev module, but in js +https://github.com/isaacs/abbrev-js#readme + +dist +.tarball: https://registry.npmjs.org/abbrev/-/abbrev-1.0.4.tgz +.shasum: bd55ae5e413ba1722ee4caba1f6ea10414a59ecd + +maintainers: +- nlf <quitlahok@gmail.com> +- ruyadorno <ruyadorno@hotmail.com> +- darcyclarke <darcy@darcyclarke.me> +- adam_baldwin <evilpacket@gmail.com> +- isaacs <i@izs.me> + +dist-tags: +latest: 1.1.1 + +published over a year ago by isaacs <i@izs.me> + +`