diff --git a/__tests__/commands/install/integration.js b/__tests__/commands/install/integration.js index a7d88af412..9101947fc2 100644 --- a/__tests__/commands/install/integration.js +++ b/__tests__/commands/install/integration.js @@ -29,7 +29,7 @@ async function mockConstants(base: Config, mocks: Object, cb: (config: Config) = // the Yarn environment. const opts = {}; - + opts.binLinks = base.binLinks; opts.cwd = base.cwd; opts.globalFolder = base.globalFolder; @@ -231,6 +231,17 @@ test.concurrent('--production flag does not link dev dependency bin scripts', () }); }); +test.concurrent('--production flag installs transitive dependencies even if they are top-level devDependencies', () => { + // Root package: dependencies: ['a'], devDependencies: ['b'] + // 'a' package: dependencies: ['b'] + // 'b' should be installed, even with --production + return runInstall({production: true}, 'install-production-transitive-dep', async (config) => { + assert.ok( + await fs.exists(path.join(config.cwd, 'node_modules', 'dep-b')), + ); + }); +}); + test.concurrent("doesn't write new lockfile if existing one satisfied", (): Promise => { return runInstall({}, 'install-dont-write-lockfile-if-satisfied', async (config): Promise => { const lockfile = await fs.readFile(path.join(config.cwd, 'yarn.lock')); diff --git a/__tests__/fixtures/install/install-production-transitive-dep/.npmrc b/__tests__/fixtures/install/install-production-transitive-dep/.npmrc new file mode 100644 index 0000000000..9465b97ac3 --- /dev/null +++ b/__tests__/fixtures/install/install-production-transitive-dep/.npmrc @@ -0,0 +1 @@ +yarn-offline-mirror=./mirror-for-offline diff --git a/__tests__/fixtures/install/install-production-transitive-dep/mirror-for-offline/dep-a-1.0.0.tar b/__tests__/fixtures/install/install-production-transitive-dep/mirror-for-offline/dep-a-1.0.0.tar new file mode 100644 index 0000000000..a2283283e2 Binary files /dev/null and b/__tests__/fixtures/install/install-production-transitive-dep/mirror-for-offline/dep-a-1.0.0.tar differ diff --git a/__tests__/fixtures/install/install-production-transitive-dep/mirror-for-offline/dep-b-1.0.0.tar b/__tests__/fixtures/install/install-production-transitive-dep/mirror-for-offline/dep-b-1.0.0.tar new file mode 100644 index 0000000000..8db7ba27e2 Binary files /dev/null and b/__tests__/fixtures/install/install-production-transitive-dep/mirror-for-offline/dep-b-1.0.0.tar differ diff --git a/__tests__/fixtures/install/install-production-transitive-dep/package.json b/__tests__/fixtures/install/install-production-transitive-dep/package.json new file mode 100644 index 0000000000..97b6c4a4ed --- /dev/null +++ b/__tests__/fixtures/install/install-production-transitive-dep/package.json @@ -0,0 +1,9 @@ +{ + "dependencies": { + "dep-a": "1.0.0" + }, + "devDependencies": { + "dep-b": "1.0.0" + }, + "license": "MIT" +} diff --git a/__tests__/fixtures/install/install-production-transitive-dep/yarn.lock b/__tests__/fixtures/install/install-production-transitive-dep/yarn.lock new file mode 100644 index 0000000000..6bbcb03037 --- /dev/null +++ b/__tests__/fixtures/install/install-production-transitive-dep/yarn.lock @@ -0,0 +1,11 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 +dep-a@1.0.0: + version "1.0.0" + resolved dep-a-1.0.0.tar + dependencies: + dep-b "1.0.0" + +dep-b@1.0.0: + version "1.0.0" + resolved dep-b-1.0.0.tar diff --git a/src/package-resolver.js b/src/package-resolver.js index 4cca3a7dfa..98856ac61c 100644 --- a/src/package-resolver.js +++ b/src/package-resolver.js @@ -17,9 +17,8 @@ const semver = require('semver'); export default class PackageResolver { constructor(config: Config, lockfile: Lockfile) { this.patternsByPackage = map(); - this.fetchingPatterns = map(); this.fetchingQueue = new BlockingQueue('resolver fetching'); - this.newPatterns = []; + this.newPatterns = new Set(); this.patterns = map(); this.usedRegistries = new Set(); this.flat = false; @@ -41,13 +40,8 @@ export default class PackageResolver { end: () => void }; - // patterns we've already resolved or are in the process of resolving - fetchingPatterns: { - [key: string]: true - }; - // new patterns that didn't exist in the lockfile - newPatterns: Array; + newPatterns: Set; // TODO fetchingQueue: BlockingQueue; @@ -83,7 +77,7 @@ export default class PackageResolver { */ isNewPattern(pattern: string): boolean { - return this.newPatterns.indexOf(pattern) >= 0; + return this.newPatterns.has(pattern); } /** @@ -269,7 +263,8 @@ export default class PackageResolver { const ref = pkg._reference; invariant(ref, 'expected package reference'); ref.patterns = [newPattern]; - this.newPatterns.splice(this.newPatterns.indexOf(pattern), 1, newPattern); + this.newPatterns.delete(pattern); + this.newPatterns.add(newPattern); this.addPattern(newPattern, pkg); this.removePattern(pattern); } @@ -423,19 +418,12 @@ export default class PackageResolver { */ async find(req: DependencyRequestPattern): Promise { - const fetchKey = `${req.registry}:${req.pattern}`; - if (this.fetchingPatterns[fetchKey]) { - return; - } else { - this.fetchingPatterns[fetchKey] = true; - } - if (this.activity) { this.activity.tick(req.pattern); } if (!this.lockfile.getLocked(req.pattern, true)) { - this.newPatterns.push(req.pattern); + this.newPatterns.add(req.pattern); } const request = new PackageRequest(req, this);