Skip to content

Commit 5bd9d74

Browse files
author
Sebastian McKenzie
committed
don't allow optional dependency resolution to fail - fixes #103
1 parent 63290c7 commit 5bd9d74

File tree

6 files changed

+78
-38
lines changed

6 files changed

+78
-38
lines changed

src/cli/commands/install.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
* @flow
1010
*/
1111

12-
import type { RegistryNames } from "../../registries/index.js";
1312
import type { Reporter } from "kreporters";
13+
import type { DependencyRequestPatterns } from "../../types.js";
1414
import type Config from "../../config.js";
1515
import Lockfile from "../../lockfile/index.js";
1616
import lockStringify from "../../lockfile/stringify.js";
@@ -76,11 +76,7 @@ export class Install {
7676
*/
7777

7878
async fetchRequestFromCwd(excludePatterns?: Array<string> = []): Promise<[
79-
Array<{
80-
pattern: string,
81-
registry: RegistryNames,
82-
optional?: boolean
83-
}>,
79+
DependencyRequestPatterns,
8480
Array<string>
8581
]> {
8682
let patterns = [];
@@ -122,7 +118,7 @@ export class Install {
122118
}
123119

124120
patterns.push(pattern);
125-
deps.push({ pattern, registry });
121+
deps.push({ pattern, registry, ignore: !!this.flags.production });
126122
}
127123

128124
// optional deps
@@ -394,7 +390,7 @@ export function setFlags(commander: Object) {
394390
commander.option("-O, --save-optional", "save package to your `optionalDependencies`");
395391
commander.option("-E, --save-exact", "");
396392
commander.option("-T, --save-tilde", "");
397-
commander.option("--no-optional"); // TODO
393+
commander.option("--production, --prod", "");
398394
commander.option("--no-lockfile");
399395
commander.option("--init-mirror", "initialise local package mirror and copy module tarballs");
400396
}

src/package-linker.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -217,19 +217,26 @@ export default class PackageLinker {
217217
let flatTree = [];
218218
for (let key in tree) {
219219
let info = tree[key];
220-
let loc = path.join(this.config.modulesFolder, key.replace(/#/g, "/node_modules/"));
220+
221+
// should we ignore this module from linking?
222+
let ref = info.pkg.reference;
223+
invariant(ref, "expected reference");
224+
if (ref.ignore) continue;
225+
226+
// decompress the location and push it to the flat tree
227+
let loc = path.join(this.config.modulesFolder, key.replace(/#/g, "/node_modules/"));
221228
flatTree.push([loc, info]);
222229
}
223230
return flatTree;
224231
}
225232

226233
async copyModules(patterns: Array<string>): Promise<void> {
227234
let flatTree = await this.initCopyModules(patterns);
235+
228236
// sorted tree makes file creation and copying not to interfere with each other
229237
flatTree = flatTree.sort((dep1, dep2) => {
230238
return dep1[0].localeCompare(dep2[0]);
231239
});
232-
let self = this;
233240

234241
//
235242
let tickCopyModule = this.reporter.progress(flatTree.length);
@@ -246,9 +253,9 @@ export default class PackageLinker {
246253

247254
//
248255
let tickBin = this.reporter.progress(flatTree.length);
249-
await promise.queue(flatTree, async function ([dest, { pkg }]) {
256+
await promise.queue(flatTree, async ([dest, { pkg }]) => {
250257
let binLoc = path.join(dest, "node_modules");
251-
await self.linkBinDependencies([], pkg, binLoc);
258+
await this.linkBinDependencies([], pkg, binLoc);
252259
tickBin(dest);
253260
}, 4);
254261
}

src/package-reference.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export default class PackageReference {
4040
this.permissions = {};
4141
this.patterns = [];
4242
this.optional = null;
43+
this.ignore = null;
4344
this.location = null;
4445
this.saveForOffline = !!saveForOffline;
4546
}
@@ -52,6 +53,7 @@ export default class PackageReference {
5253
version: string;
5354
uid: string;
5455
optional: ?boolean;
56+
ignore: ?boolean;
5557
saveForOffline: boolean;
5658
dependencies: Array<string>;
5759
patterns: Array<string>;
@@ -113,4 +115,13 @@ export default class PackageReference {
113115
this.optional = false;
114116
}
115117
}
118+
119+
addIgnore(ignore: boolean) {
120+
// see comments in addOptional
121+
if (this.ignore == null) {
122+
this.ignore = ignore;
123+
} else if (!ignore) {
124+
this.ignore = false;
125+
}
126+
}
116127
}

src/package-request.js

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,16 @@ export default class PackageRequest {
3333
registry,
3434
resolver,
3535
lockfile,
36-
parentRequest
36+
parentRequest,
37+
optional,
38+
ignore
3739
}: {
3840
pattern: string,
3941
lockfile: ?Lockfile,
4042
registry: RegistryNames,
4143
resolver: PackageResolver,
44+
optional: boolean,
45+
ignore: boolean,
4246
parentRequest: ?PackageRequest // eslint-disable-line no-unused-vars
4347
}) {
4448
this.parentRequest = parentRequest;
@@ -47,8 +51,10 @@ export default class PackageRequest {
4751
this.registry = registry;
4852
this.reporter = resolver.reporter;
4953
this.resolver = resolver;
54+
this.optional = optional;
5055
this.pattern = pattern;
5156
this.config = resolver.config;
57+
this.ignore = ignore;
5258
}
5359

5460
static getExoticResolver(pattern: string): ?Function { // TODO make this type more refined
@@ -65,6 +71,8 @@ export default class PackageRequest {
6571
pattern: string;
6672
config: Config;
6773
registry: RegistryNames;
74+
ignore: boolean;
75+
optional: boolean;
6876

6977
getHuman(): string {
7078
let chain = [];
@@ -214,22 +222,10 @@ export default class PackageRequest {
214222
* TODO description
215223
*/
216224

217-
async find(optional: boolean): Promise<void> {
218-
let info: ?Manifest;
219-
225+
async find(): Promise<void> {
220226
// find verison info for this package pattern
221-
try {
222-
info = await this.findVersionInfo();
223-
if (!info) throw new MessageError(`Couldn't find package ${this.pattern}`);
224-
} catch (err) {
225-
if (optional) {
226-
// TODO add verbose flag
227-
this.reporter.error(err.message);
228-
return;
229-
} else {
230-
throw err;
231-
}
232-
}
227+
let info: ?Manifest = await this.findVersionInfo();
228+
if (!info) throw new MessageError(`Couldn't find package ${this.pattern}`);
233229

234230
// check if while we were resolving this dep we've already resolved one that satisfies
235231
// the same range
@@ -239,7 +235,8 @@ export default class PackageRequest {
239235
invariant(ref, "Resolved package info has no package reference");
240236
ref.addRequest(this);
241237
ref.addPattern(this.pattern);
242-
ref.addOptional(optional);
238+
ref.addOptional(this.optional);
239+
ref.addIgnore(this.ignore);
243240
this.resolver.addPattern(this.pattern, resolved);
244241
return;
245242
}
@@ -304,22 +301,35 @@ export default class PackageRequest {
304301
for (let depName in info.dependencies) {
305302
let depPattern = depName + "@" + info.dependencies[depName];
306303
deps.push(depPattern);
307-
promises.push(this.resolver.find(depPattern, remote.registry, false, this, subLockfile));
304+
promises.push(this.resolver.find({
305+
pattern: depPattern,
306+
registry: remote.registry,
307+
optional: false,
308+
parentRequest: this,
309+
subLockfile
310+
}));
308311
}
309312

310313
// optional deps
311314
for (let depName in info.optionalDependencies) {
312315
let depPattern = depName + "@" + info.optionalDependencies[depName];
313316
deps.push(depPattern);
314-
promises.push(this.resolver.find(depPattern, remote.registry, true, this, subLockfile));
317+
promises.push(this.resolver.find({
318+
pattern: depPattern,
319+
registry: remote.registry,
320+
optional: true,
321+
parentRequest: this,
322+
subLockfile
323+
}));
315324
}
316325

317326
await Promise.all(promises);
318327

319328
this.resolver.addPattern(this.pattern, info);
320329
ref.setDependencies(deps);
321330
ref.addPattern(this.pattern);
322-
ref.addOptional(optional);
331+
ref.addOptional(this.optional);
332+
ref.addIgnore(this.ignore);
323333
this.resolver.registerPackageReference(ref);
324334
}
325335

src/package-resolver.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,13 +289,21 @@ export default class PackageResolver {
289289
* TODO description
290290
*/
291291

292-
async find(
292+
async find({
293+
pattern,
294+
registry,
295+
ignore = false,
296+
optional = false,
297+
parentRequest,
298+
subLockfile
299+
}: {
293300
pattern: string,
294301
registry: RegistryNames,
295-
optional?: boolean = false,
302+
optional?: boolean,
303+
ignore?: boolean,
296304
parentRequest?: ?PackageRequest,
297305
subLockfile?: ?Lockfile
298-
): Promise<void> {
306+
}): Promise<void> {
299307
let fetchKey = `${registry}:${pattern}`;
300308
if (this.fetchingPatterns[fetchKey]) {
301309
return;
@@ -311,13 +319,20 @@ export default class PackageResolver {
311319
this.newPatterns.push(pattern);
312320
}
313321

322+
// propagate `ignore` option
323+
if (parentRequest && parentRequest.ignore) {
324+
ignore = true;
325+
}
326+
314327
return new PackageRequest({
315328
lockfile: subLockfile,
316329
pattern,
317330
registry,
318331
parentRequest,
332+
optional,
333+
ignore,
319334
resolver: this
320-
}).find(optional);
335+
}).find();
321336
}
322337

323338
/**
@@ -334,7 +349,7 @@ export default class PackageResolver {
334349
// build up promises
335350
let promises = [];
336351
for (let { pattern, registry, optional } of deps) {
337-
promises.push(this.find(pattern, registry, optional));
352+
promises.push(this.find({ pattern, registry, optional }));
338353
}
339354
await Promise.all(promises);
340355

src/types.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ import type PackageReference from "./package-reference.js";
1717
export type DependencyRequestPatterns = Array<{
1818
pattern: string,
1919
registry: RegistryNames,
20-
optional?: boolean
20+
optional?: boolean,
21+
ignore?: boolean
2122
}>;
2223

2324
// person object, the exploded version of a `maintainers`/`authors` field

0 commit comments

Comments
 (0)