From c81df49bf0713403c0696f904489509886d208da Mon Sep 17 00:00:00 2001 From: Lars Willighagen Date: Sun, 7 Oct 2018 22:40:16 +0200 Subject: [PATCH 1/6] install: fix checking for optional dep See https://npm.community/t/2569 --- lib/install/is-only-optional.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/install/is-only-optional.js b/lib/install/is-only-optional.js index 72d6f065e6745..f1b731578d942 100644 --- a/lib/install/is-only-optional.js +++ b/lib/install/is-only-optional.js @@ -10,6 +10,7 @@ function isOptional (node, seen) { if (seen.has(node) || node.requiredBy.length === 0) { return false } + seen = new Set(seen) seen.add(node) const swOptional = node.fromShrinkwrap && node.package._optional return node.requiredBy.every(function (req) { From 36dd559ccc3e591b446c2a2fede0c4b5f5120bd5 Mon Sep 17 00:00:00 2001 From: Lars Willighagen Date: Sun, 7 Oct 2018 23:14:35 +0200 Subject: [PATCH 2/6] test: fix install check for optional deps --- .../install-optional-dep-identification.js | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 test/tap/install-optional-dep-identification.js diff --git a/test/tap/install-optional-dep-identification.js b/test/tap/install-optional-dep-identification.js new file mode 100644 index 0000000000000..950dcea64f776 --- /dev/null +++ b/test/tap/install-optional-dep-identification.js @@ -0,0 +1,50 @@ +'use strict' +var path = require('path') +var fs = require('graceful-fs') +var mkdirp = require('mkdirp') +var rimraf = require('rimraf') +var test = require('tap').test +var common = require('../common-tap.js') + +var base = path.join(__dirname, path.basename(__filename, '.js')) +var moduleDir = path.join(base, 'example') +var moduleJson = { + name: 'example', + version: '1.0.0', + optionalDependencies: { + 'aws-sdk': 'latest' + } +} + +function setup () { + cleanup() + mkdirp.sync(moduleDir) + fs.writeFileSync(path.join(moduleDir, 'package.json'), JSON.stringify(moduleJson)) +} + +function cleanup () { + rimraf.sync(base) +} + +test('setup', function (t) { + setup() + t.end() +}) + +test('optional dependency identification', function (t) { + common.npm( + ['install', '--no-optional'], + {cwd: moduleDir}, + function (er, code, stdout, stderr) { + t.is(code, 0, 'no error code') + t.is(stderr, '', 'no error output') + t.notOk(fs.existsSync(path.join(moduleDir, 'node_modules')), 'did not install anything') + t.end() + } + ) +}) + +test('cleanup', function (t) { + cleanup() + t.end() +}) From 7390cd862ede8fd258c131cdaf14ec8ebc2b1b36 Mon Sep 17 00:00:00 2001 From: Lars Willighagen Date: Mon, 8 Oct 2018 15:55:47 +0200 Subject: [PATCH 3/6] test: future-proof install test See 36dd559cc --- .../install-optional-dep-identification.js | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/test/tap/install-optional-dep-identification.js b/test/tap/install-optional-dep-identification.js index 950dcea64f776..15c9c2a6e3ff5 100644 --- a/test/tap/install-optional-dep-identification.js +++ b/test/tap/install-optional-dep-identification.js @@ -12,7 +12,7 @@ var moduleJson = { name: 'example', version: '1.0.0', optionalDependencies: { - 'aws-sdk': 'latest' + 'example': '../example-1.0.0.tgz' } } @@ -20,6 +20,32 @@ function setup () { cleanup() mkdirp.sync(moduleDir) fs.writeFileSync(path.join(moduleDir, 'package.json'), JSON.stringify(moduleJson)) + fs.writeFileSync(path.join(base, 'example-1.0.0.tgz'), Buffer.from( + '1f8b0800000000000003ed8fc10ac2300c8677f62946cedaa5d8f5e0db64' + + '5b1853d795758a38f6ee4607e261370722f4bbfce5cb4f493c9527aa39f3' + + '73aa63e85cb23288688d4997fc136d304df6b945adad45e9c923375a72ed' + + '4596b884817a59e5db7fe65bd277fe0923386a190ec0376afd99610b57ee' + + '43d339715aa14231157b7615bbb2e100871148664a65b47b15d450dfa554' + + 'ccb2f890d3b4f9f57d9148241259e60112d8208a00080000', + 'hex' + )) + fs.writeFileSync(path.join(base, 'a-1.0.0.tgz'), Buffer.from( + '1f8b0800000000000003edcfc10e82300c0660ce3ec5d2b38e4eb71d789b' + + '010d41e358187890f0ee56493c71319218937d977feb9aa50daebab886f2' + + 'b0a43cc7ce671b4344abb558ab3f2934223b198b4a598bdcc707a38f9c5b' + + '0fb2668c83eb79946fff597611effc131378772528c0c11e6ed4c7b6f37c' + + '53122572a5a640be265fb514a198a0e43729f3f2f06a9043738779defd7a' + + '89244992e4630fd69e456800080000', + 'hex' + )) + fs.writeFileSync(path.join(base, 'b-1.0.0.tgz'), Buffer.from( + '1f8b08000000000000032b484cce4e4c4fd52f80d07a59c5f9790c540606' + + '06066626260ad8c4c1c0d85c81c1d8d4ccc0d0d0cccc00a80ec830353103' + + 'd2d4760836505a5c925804740aa5e640bca200a78708a856ca4bcc4d55b2' + + '524a52d2512a4b2d2acecccf03f20cf50cf40c946ab906da79a360148c82' + + '51300a680400106986b400080000', + 'hex' + )) } function cleanup () { From 20815568b1f09ff8f60fc229078e2bb9287061af Mon Sep 17 00:00:00 2001 From: Lars Willighagen Date: Mon, 8 Oct 2018 21:51:36 +0200 Subject: [PATCH 4/6] install: fix checking for dev dep See c81df49bf --- lib/install/is-only-dev.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/install/is-only-dev.js b/lib/install/is-only-dev.js index ef41e8ad1a265..2877c61a227d0 100644 --- a/lib/install/is-only-dev.js +++ b/lib/install/is-only-dev.js @@ -28,6 +28,7 @@ function andIsOnlyDev (name, seen) { return isDev && !isProd } else { if (seen.has(req)) return true + seen = new Set(seen) seen.add(req) return isOnlyDev(req, seen) } From 63d5065fc87863df515e898102a9077397c270b4 Mon Sep 17 00:00:00 2001 From: Lars Willighagen Date: Mon, 8 Oct 2018 21:52:04 +0200 Subject: [PATCH 5/6] test: checking for dev dep --- ...ation.js => install-dep-classification.js} | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) rename test/tap/{install-optional-dep-identification.js => install-dep-classification.js} (69%) diff --git a/test/tap/install-optional-dep-identification.js b/test/tap/install-dep-classification.js similarity index 69% rename from test/tap/install-optional-dep-identification.js rename to test/tap/install-dep-classification.js index 15c9c2a6e3ff5..4b49306ae4be1 100644 --- a/test/tap/install-optional-dep-identification.js +++ b/test/tap/install-dep-classification.js @@ -7,19 +7,30 @@ var test = require('tap').test var common = require('../common-tap.js') var base = path.join(__dirname, path.basename(__filename, '.js')) -var moduleDir = path.join(base, 'example') -var moduleJson = { - name: 'example', +var optionalDir = path.join(base, 'optional') +var optionalJson = { + name: 'optional', version: '1.0.0', optionalDependencies: { 'example': '../example-1.0.0.tgz' } } +var devDir = path.join(base, 'dev') +var devJson = { + name: 'dev', + version: '1.0.0', + devDependencies: { + 'example': '../example-1.0.0.tgz' + } +} function setup () { cleanup() - mkdirp.sync(moduleDir) - fs.writeFileSync(path.join(moduleDir, 'package.json'), JSON.stringify(moduleJson)) + mkdirp.sync(optionalDir) + fs.writeFileSync(path.join(optionalDir, 'package.json'), JSON.stringify(optionalJson)) + mkdirp.sync(devDir) + fs.writeFileSync(path.join(devDir, 'package.json'), JSON.stringify(devJson)) + fs.writeFileSync(path.join(base, 'example-1.0.0.tgz'), Buffer.from( '1f8b0800000000000003ed8fc10ac2300c8677f62946cedaa5d8f5e0db64' + '5b1853d795758a38f6ee4607e261370722f4bbfce5cb4f493c9527aa39f3' + @@ -60,11 +71,24 @@ test('setup', function (t) { test('optional dependency identification', function (t) { common.npm( ['install', '--no-optional'], - {cwd: moduleDir}, + {cwd: optionalDir}, + function (er, code, stdout, stderr) { + t.is(code, 0, 'no error code') + t.is(stderr, '', 'no error output') + t.notOk(fs.existsSync(path.join(optionalDir, 'node_modules')), 'did not install anything') + t.end() + } + ) +}) + +test('development dependency identification', function (t) { + common.npm( + ['install', '--only=prod'], + {cwd: devDir}, function (er, code, stdout, stderr) { t.is(code, 0, 'no error code') t.is(stderr, '', 'no error output') - t.notOk(fs.existsSync(path.join(moduleDir, 'node_modules')), 'did not install anything') + t.notOk(fs.existsSync(path.join(devDir, 'node_modules')), 'did not install anything') t.end() } ) From 26e3e2a26655b753c0bb0aaf9e41a1798ce71a37 Mon Sep 17 00:00:00 2001 From: Philip Harrison Date: Tue, 30 Oct 2018 16:10:20 +0100 Subject: [PATCH 6/6] test: check pkglock is updated correctly --- test/tap/install-dep-classification.js | 60 ++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/test/tap/install-dep-classification.js b/test/tap/install-dep-classification.js index 4b49306ae4be1..b5de7e9b8deb1 100644 --- a/test/tap/install-dep-classification.js +++ b/test/tap/install-dep-classification.js @@ -76,6 +76,22 @@ test('optional dependency identification', function (t) { t.is(code, 0, 'no error code') t.is(stderr, '', 'no error output') t.notOk(fs.existsSync(path.join(optionalDir, 'node_modules')), 'did not install anything') + t.similar(JSON.parse(fs.readFileSync(path.join(optionalDir, 'package-lock.json'), 'utf8')), { + dependencies: { + a: { + version: 'file:../a-1.0.0.tgz', + optional: true, + }, + b: { + version: 'file:../b-1.0.0.tgz', + optional: true + }, + example: { + version: "1.0.0", + optional: true, + } + } + }, 'locks dependencies as optional') t.end() } ) @@ -89,6 +105,50 @@ test('development dependency identification', function (t) { t.is(code, 0, 'no error code') t.is(stderr, '', 'no error output') t.notOk(fs.existsSync(path.join(devDir, 'node_modules')), 'did not install anything') + t.similar(JSON.parse(fs.readFileSync(path.join(devDir, 'package-lock.json'), 'utf8')), { + dependencies: { + a: { + version: 'file:../a-1.0.0.tgz', + dev: true, + }, + b: { + version: 'file:../b-1.0.0.tgz', + dev: true + }, + example: { + version: "1.0.0", + dev: true, + } + } + }, 'locks dependencies as dev') + t.end() + } + ) +}) + +test('default dependency identification', function (t) { + common.npm( + ['install'], + {cwd: optionalDir}, + function (er, code, stdout, stderr) { + t.is(code, 0, 'no error code') + t.is(stderr, '', 'no error output') + t.similar(JSON.parse(fs.readFileSync(path.join(optionalDir, 'package-lock.json'), 'utf8')), { + dependencies: { + a: { + version: 'file:../a-1.0.0.tgz', + optional: true, + }, + b: { + version: 'file:../b-1.0.0.tgz', + optional: true + }, + example: { + version: "1.0.0", + optional: true, + } + } + }, 'locks dependencies as optional') t.end() } )