Skip to content

Commit

Permalink
Fix: incorrect optional ignore in nested dependencies (#4448)
Browse files Browse the repository at this point in the history
**Summary**

Fixes #4445. The bug was introduced in
https://github.com/yarnpkg/yarn/pull/3976/files#diff-7066979f95168f7bb59e4f9cfb3ba8fcR211
with an incomplete package optional check. This caused many transient
dependencies to be ignored at linking stage when `--ignore-optional`
flag is passed. This patch fixes the check to combine the flag with
the package's actual optional mark.

**Test plan**

Manually verified #4445 is resolved. Also added a unit test.
  • Loading branch information
BYK committed Sep 14, 2017
1 parent cf3a5f2 commit ef8185b
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 11 deletions.
3 changes: 3 additions & 0 deletions __tests__/commands/install/integration.js
Expand Up @@ -64,6 +64,9 @@ test.concurrent('install optional subdependencies by default', async () => {
test.concurrent('installing with --ignore-optional should not install optional subdependencies', async () => {
await runInstall({ignoreOptional: true}, 'install-optional-dependencies', async (config): Promise<void> => {
expect(await fs.exists(`${config.cwd}/node_modules/dep-b`)).toEqual(false);
expect(await fs.exists(`${config.cwd}/node_modules/dep-c`)).toEqual(true);
expect(await fs.exists(`${config.cwd}/node_modules/dep-d`)).toEqual(true);
expect(await fs.exists(`${config.cwd}/node_modules/dep-e`)).toEqual(true);
});
});

Expand Down
@@ -1,6 +1,9 @@
{
"name": "dep-a",
"version": "1.0.0",
"dependencies": {
"dep-c": "file:../dep-c"
},
"optionalDependencies": {
"dep-b": "file:../dep-b"
}
Expand Down
@@ -0,0 +1,10 @@
{
"name": "dep-c",
"version": "1.0.0",
"optionalDependencies": {
"dep-e": "file:../dep-e"
},
"dependencies": {
"dep-d": "file:../dep-d"
}
}
@@ -0,0 +1,7 @@
{
"name": "dep-d",
"version": "1.0.0",
"dependencies": {
"dep-e": "file:../dep-e"
}
}
@@ -0,0 +1,4 @@
{
"name": "dep-e",
"version": "1.0.0"
}
2 changes: 1 addition & 1 deletion src/package-hoister.js
Expand Up @@ -242,7 +242,7 @@ export default class PackageHoister {
continue;
}

const isMarkedAsOptional = !depinfo.pkg._reference || this.ignoreOptional;
const isMarkedAsOptional = depinfo.pkg._reference && depinfo.pkg._reference.optional && this.ignoreOptional;
if (!depinfo.isRequired && !depinfo.isIncompatible && !isMarkedAsOptional) {
depinfo.isRequired = true;
depinfo.addHistory(`Mark as non-ignored because of usage by ${info.key}`);
Expand Down
1 change: 1 addition & 0 deletions src/package-request.js
Expand Up @@ -193,6 +193,7 @@ export default class PackageRequest {
invariant(ref, 'Resolved package info has no package reference');
ref.addRequest(this);
ref.addPattern(this.pattern, resolved);
ref.addOptional(this.optional);
}

/**
Expand Down
15 changes: 5 additions & 10 deletions src/package-resolver.js
Expand Up @@ -27,7 +27,7 @@ export type ResolverOptions = {|
export default class PackageResolver {
constructor(config: Config, lockfile: Lockfile, resolutionMap: ResolutionMap = new ResolutionMap(config)) {
this.patternsByPackage = map();
this.fetchingPatterns = map();
this.fetchingPatterns = new Set();
this.fetchingQueue = new BlockingQueue('resolver fetching');
this.patterns = map();
this.resolutionMap = resolutionMap;
Expand Down Expand Up @@ -59,9 +59,7 @@ export default class PackageResolver {
};

// patterns we've already resolved or are in the process of resolving
fetchingPatterns: {
[key: string]: true,
};
fetchingPatterns: Set<string>;

// TODO
fetchingQueue: BlockingQueue;
Expand Down Expand Up @@ -477,13 +475,11 @@ export default class PackageResolver {
return;
}

const fetchKey = `${req.registry}:${req.pattern}`;

if (this.fetchingPatterns[fetchKey]) {
const fetchKey = `${req.registry}:${req.pattern}:${String(req.optional)}`;
if (this.fetchingPatterns.has(fetchKey)) {
return;
} else {
this.fetchingPatterns[fetchKey] = true;
}
this.fetchingPatterns.add(fetchKey);

if (this.activity) {
this.activity.tick(req.pattern);
Expand Down Expand Up @@ -579,7 +575,6 @@ export default class PackageResolver {
} else {
this.resolutionMap.addToDelayQueue(req);
}

return null;
}

Expand Down

0 comments on commit ef8185b

Please sign in to comment.