UNPKG

19.7 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _asyncToGenerator2;
8
9function _load_asyncToGenerator() {
10 return _asyncToGenerator2 = _interopRequireDefault(require('babel-runtime/helpers/asyncToGenerator'));
11}
12
13var _path;
14
15function _load_path() {
16 return _path = _interopRequireDefault(require('path'));
17}
18
19var _invariant;
20
21function _load_invariant() {
22 return _invariant = _interopRequireDefault(require('invariant'));
23}
24
25var _semver;
26
27function _load_semver() {
28 return _semver = _interopRequireDefault(require('semver'));
29}
30
31var _validate;
32
33function _load_validate() {
34 return _validate = require('./util/normalize-manifest/validate.js');
35}
36
37var _lockfile;
38
39function _load_lockfile() {
40 return _lockfile = _interopRequireDefault(require('./lockfile'));
41}
42
43var _packageReference;
44
45function _load_packageReference() {
46 return _packageReference = _interopRequireDefault(require('./package-reference.js'));
47}
48
49var _index;
50
51function _load_index() {
52 return _index = require('./resolvers/index.js');
53}
54
55var _errors;
56
57function _load_errors() {
58 return _errors = require('./errors.js');
59}
60
61var _constants;
62
63function _load_constants() {
64 return _constants = _interopRequireWildcard(require('./constants.js'));
65}
66
67var _version;
68
69function _load_version() {
70 return _version = _interopRequireWildcard(require('./util/version.js'));
71}
72
73var _workspaceResolver;
74
75function _load_workspaceResolver() {
76 return _workspaceResolver = _interopRequireDefault(require('./resolvers/contextual/workspace-resolver.js'));
77}
78
79var _fs;
80
81function _load_fs() {
82 return _fs = _interopRequireWildcard(require('./util/fs.js'));
83}
84
85var _normalizePattern4;
86
87function _load_normalizePattern() {
88 return _normalizePattern4 = require('./util/normalize-pattern.js');
89}
90
91function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
92
93function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
94
95const micromatch = require('micromatch');
96
97class PackageRequest {
98 constructor(req, resolver) {
99 this.parentRequest = req.parentRequest;
100 this.parentNames = req.parentNames || [];
101 this.lockfile = resolver.lockfile;
102 this.registry = req.registry;
103 this.reporter = resolver.reporter;
104 this.resolver = resolver;
105 this.optional = req.optional;
106 this.hint = req.hint;
107 this.pattern = req.pattern;
108 this.config = resolver.config;
109 this.foundInfo = null;
110 }
111
112 init() {
113 this.resolver.usedRegistries.add(this.registry);
114 }
115
116 getLocked(remoteType) {
117 // always prioritise root lockfile
118 const shrunk = this.lockfile.getLocked(this.pattern);
119
120 if (shrunk && shrunk.resolved) {
121 const resolvedParts = (_version || _load_version()).explodeHashedUrl(shrunk.resolved);
122
123 // Detect Git protocols (git://HOST/PATH or git+PROTOCOL://HOST/PATH)
124 const preferredRemoteType = /^git(\+[a-z0-9]+)?:\/\//.test(resolvedParts.url) ? 'git' : remoteType;
125
126 return {
127 name: shrunk.name,
128 version: shrunk.version,
129 _uid: shrunk.uid,
130 _remote: {
131 resolved: shrunk.resolved,
132 type: preferredRemoteType,
133 reference: resolvedParts.url,
134 hash: resolvedParts.hash,
135 integrity: shrunk.integrity,
136 registry: shrunk.registry,
137 packageName: shrunk.name
138 },
139 optionalDependencies: shrunk.optionalDependencies || {},
140 dependencies: shrunk.dependencies || {},
141 prebuiltVariants: shrunk.prebuiltVariants || {}
142 };
143 } else {
144 return null;
145 }
146 }
147
148 /**
149 * If the input pattern matches a registry one then attempt to find it on the registry.
150 * Otherwise fork off to an exotic resolver if one matches.
151 */
152
153 findVersionOnRegistry(pattern) {
154 var _this = this;
155
156 return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
157 var _ref = yield _this.normalize(pattern);
158
159 const range = _ref.range,
160 name = _ref.name;
161
162
163 const exoticResolver = (0, (_index || _load_index()).getExoticResolver)(range);
164 if (exoticResolver) {
165 let data = yield _this.findExoticVersionInfo(exoticResolver, range);
166
167 // clone data as we're manipulating it in place and this could be resolved multiple
168 // times
169 data = Object.assign({}, data);
170
171 // this is so the returned package response uses the overridden name. ie. if the
172 // package's actual name is `bar`, but it's been specified in the manifest like:
173 // "foo": "http://foo.com/bar.tar.gz"
174 // then we use the foo name
175 data.name = name;
176 return data;
177 }
178
179 const Resolver = _this.getRegistryResolver();
180 const resolver = new Resolver(_this, name, range);
181 try {
182 return yield resolver.resolve();
183 } catch (err) {
184 // if it is not an error thrown by yarn and it has a parent request,
185 // thow a more readable error
186 if (!(err instanceof (_errors || _load_errors()).MessageError) && _this.parentRequest && _this.parentRequest.pattern) {
187 throw new (_errors || _load_errors()).MessageError(_this.reporter.lang('requiredPackageNotFoundRegistry', pattern, _this.parentRequest.pattern, _this.registry));
188 }
189 throw err;
190 }
191 })();
192 }
193
194 /**
195 * Get the registry resolver associated with this package request.
196 */
197
198 getRegistryResolver() {
199 const Resolver = (_index || _load_index()).registries[this.registry];
200 if (Resolver) {
201 return Resolver;
202 } else {
203 throw new (_errors || _load_errors()).MessageError(this.reporter.lang('unknownRegistryResolver', this.registry));
204 }
205 }
206
207 normalizeRange(pattern) {
208 var _this2 = this;
209
210 return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
211 if (pattern.indexOf(':') > -1 || pattern.indexOf('@') > -1 || (0, (_index || _load_index()).getExoticResolver)(pattern)) {
212 return pattern;
213 }
214
215 if (!(_semver || _load_semver()).default.validRange(pattern)) {
216 try {
217 if (yield (_fs || _load_fs()).exists((_path || _load_path()).default.join(_this2.config.cwd, pattern, (_constants || _load_constants()).NODE_PACKAGE_JSON))) {
218 _this2.reporter.warn(_this2.reporter.lang('implicitFileDeprecated', pattern));
219 return `file:${pattern}`;
220 }
221 } catch (err) {
222 // pass
223 }
224 }
225
226 return pattern;
227 })();
228 }
229
230 normalize(pattern) {
231 var _this3 = this;
232
233 return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
234 var _normalizePattern = (0, (_normalizePattern4 || _load_normalizePattern()).normalizePattern)(pattern);
235
236 const name = _normalizePattern.name,
237 range = _normalizePattern.range,
238 hasVersion = _normalizePattern.hasVersion;
239
240 const newRange = yield _this3.normalizeRange(range);
241 return { name, range: newRange, hasVersion };
242 })();
243 }
244
245 /**
246 * Construct an exotic resolver instance with the input `ExoticResolver` and `range`.
247 */
248
249 findExoticVersionInfo(ExoticResolver, range) {
250 const resolver = new ExoticResolver(this, range);
251 return resolver.resolve();
252 }
253
254 /**
255 * If the current pattern matches an exotic resolver then delegate to it or else try
256 * the registry.
257 */
258
259 findVersionInfo() {
260 var _this4 = this;
261
262 return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
263 const exoticResolver = (0, (_index || _load_index()).getExoticResolver)(_this4.pattern);
264 if (exoticResolver) {
265 return _this4.findExoticVersionInfo(exoticResolver, _this4.pattern);
266 } else if ((_workspaceResolver || _load_workspaceResolver()).default.isWorkspace(_this4.pattern, _this4.resolver.workspaceLayout)) {
267 (0, (_invariant || _load_invariant()).default)(_this4.resolver.workspaceLayout, 'expected workspaceLayout');
268 const resolver = new (_workspaceResolver || _load_workspaceResolver()).default(_this4, _this4.pattern, _this4.resolver.workspaceLayout);
269 let manifest;
270 if (_this4.config.focus && !_this4.pattern.includes(_this4.resolver.workspaceLayout.virtualManifestName) && !_this4.pattern.startsWith(_this4.config.focusedWorkspaceName + '@')) {
271 const localInfo = _this4.resolver.workspaceLayout.getManifestByPattern(_this4.pattern);
272 (0, (_invariant || _load_invariant()).default)(localInfo, 'expected local info for ' + _this4.pattern);
273 const localManifest = localInfo.manifest;
274 const requestPattern = localManifest.name + '@' + localManifest.version;
275 manifest = yield _this4.findVersionOnRegistry(requestPattern);
276 }
277 return resolver.resolve(manifest);
278 } else {
279 return _this4.findVersionOnRegistry(_this4.pattern);
280 }
281 })();
282 }
283
284 reportResolvedRangeMatch(info, resolved) {}
285
286 /**
287 * Do the final resolve of a package that had a match with an existing version.
288 * After all unique versions have been discovered, so the best available version
289 * is found.
290 */
291 resolveToExistingVersion(info) {
292 // get final resolved version
293 var _normalizePattern2 = (0, (_normalizePattern4 || _load_normalizePattern()).normalizePattern)(this.pattern);
294
295 const range = _normalizePattern2.range,
296 name = _normalizePattern2.name;
297
298 const solvedRange = (_semver || _load_semver()).default.validRange(range) ? info.version : range;
299 const resolved = this.resolver.getHighestRangeVersionMatch(name, solvedRange, info);
300 (0, (_invariant || _load_invariant()).default)(resolved, 'should have a resolved reference');
301
302 this.reportResolvedRangeMatch(info, resolved);
303 const ref = resolved._reference;
304 (0, (_invariant || _load_invariant()).default)(ref, 'Resolved package info has no package reference');
305 ref.addRequest(this);
306 ref.addPattern(this.pattern, resolved);
307 ref.addOptional(this.optional);
308 }
309
310 /**
311 * TODO description
312 */
313 find({ fresh, frozen }) {
314 var _this5 = this;
315
316 return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
317 // find version info for this package pattern
318 const info = yield _this5.findVersionInfo();
319
320 if (!(_semver || _load_semver()).default.valid(info.version)) {
321 throw new (_errors || _load_errors()).MessageError(_this5.reporter.lang('invalidPackageVersion', info.name, info.version));
322 }
323
324 info.fresh = fresh;
325 (0, (_validate || _load_validate()).cleanDependencies)(info, false, _this5.reporter, function () {
326 // swallow warnings
327 });
328
329 // check if while we were resolving this dep we've already resolved one that satisfies
330 // the same range
331
332 var _normalizePattern3 = (0, (_normalizePattern4 || _load_normalizePattern()).normalizePattern)(_this5.pattern);
333
334 const range = _normalizePattern3.range,
335 name = _normalizePattern3.name;
336
337 const solvedRange = (_semver || _load_semver()).default.validRange(range) ? info.version : range;
338 const resolved = !info.fresh || frozen ? _this5.resolver.getExactVersionMatch(name, solvedRange, info) : _this5.resolver.getHighestRangeVersionMatch(name, solvedRange, info);
339
340 if (resolved) {
341 _this5.resolver.reportPackageWithExistingVersion(_this5, info);
342 return;
343 }
344
345 if (info.flat && !_this5.resolver.flat) {
346 throw new (_errors || _load_errors()).MessageError(_this5.reporter.lang('flatGlobalError', `${info.name}@${info.version}`));
347 }
348
349 // validate version info
350 PackageRequest.validateVersionInfo(info, _this5.reporter);
351
352 //
353 const remote = info._remote;
354 (0, (_invariant || _load_invariant()).default)(remote, 'Missing remote');
355
356 // set package reference
357 const ref = new (_packageReference || _load_packageReference()).default(_this5, info, remote);
358 ref.addPattern(_this5.pattern, info);
359 ref.addOptional(_this5.optional);
360 ref.setFresh(fresh);
361 info._reference = ref;
362 info._remote = remote;
363 // start installation of dependencies
364 const promises = [];
365 const deps = [];
366 const parentNames = [..._this5.parentNames, name];
367 // normal deps
368 for (const depName in info.dependencies) {
369 const depPattern = depName + '@' + info.dependencies[depName];
370 deps.push(depPattern);
371 promises.push(_this5.resolver.find({
372 pattern: depPattern,
373 registry: remote.registry,
374 // dependencies of optional dependencies should themselves be optional
375 optional: _this5.optional,
376 parentRequest: _this5,
377 parentNames
378 }));
379 }
380
381 // optional deps
382 for (const depName in info.optionalDependencies) {
383 const depPattern = depName + '@' + info.optionalDependencies[depName];
384 deps.push(depPattern);
385 promises.push(_this5.resolver.find({
386 hint: 'optional',
387 pattern: depPattern,
388 registry: remote.registry,
389 optional: true,
390 parentRequest: _this5,
391 parentNames
392 }));
393 }
394 if (remote.type === 'workspace' && !_this5.config.production) {
395 // workspaces support dev dependencies
396 for (const depName in info.devDependencies) {
397 const depPattern = depName + '@' + info.devDependencies[depName];
398 deps.push(depPattern);
399 promises.push(_this5.resolver.find({
400 hint: 'dev',
401 pattern: depPattern,
402 registry: remote.registry,
403 optional: false,
404 parentRequest: _this5,
405 parentNames
406 }));
407 }
408 }
409
410 for (var _iterator = promises, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
411 var _ref2;
412
413 if (_isArray) {
414 if (_i >= _iterator.length) break;
415 _ref2 = _iterator[_i++];
416 } else {
417 _i = _iterator.next();
418 if (_i.done) break;
419 _ref2 = _i.value;
420 }
421
422 const promise = _ref2;
423
424 yield promise;
425 }
426
427 ref.addDependencies(deps);
428
429 // Now that we have all dependencies, it's safe to propagate optional
430 for (var _iterator2 = ref.requests.slice(1), _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
431 var _ref3;
432
433 if (_isArray2) {
434 if (_i2 >= _iterator2.length) break;
435 _ref3 = _iterator2[_i2++];
436 } else {
437 _i2 = _iterator2.next();
438 if (_i2.done) break;
439 _ref3 = _i2.value;
440 }
441
442 const otherRequest = _ref3;
443
444 ref.addOptional(otherRequest.optional);
445 }
446 })();
447 }
448
449 /**
450 * TODO description
451 */
452
453 static validateVersionInfo(info, reporter) {
454 // human readable name to use in errors
455 const human = `${info.name}@${info.version}`;
456
457 info.version = PackageRequest.getPackageVersion(info);
458
459 for (var _iterator3 = (_constants || _load_constants()).REQUIRED_PACKAGE_KEYS, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
460 var _ref4;
461
462 if (_isArray3) {
463 if (_i3 >= _iterator3.length) break;
464 _ref4 = _iterator3[_i3++];
465 } else {
466 _i3 = _iterator3.next();
467 if (_i3.done) break;
468 _ref4 = _i3.value;
469 }
470
471 const key = _ref4;
472
473 if (!info[key]) {
474 throw new (_errors || _load_errors()).MessageError(reporter.lang('missingRequiredPackageKey', human, key));
475 }
476 }
477 }
478
479 /**
480 * Returns the package version if present, else defaults to the uid
481 */
482
483 static getPackageVersion(info) {
484 // TODO possibly reconsider this behaviour
485 return info.version === undefined ? info._uid : info.version;
486 }
487
488 /**
489 * Gets all of the outdated packages and sorts them appropriately
490 */
491
492 static getOutdatedPackages(lockfile, install, config, reporter, filterByPatterns, flags) {
493 return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
494 var _ref5 = yield install.fetchRequestFromCwd();
495
496 const reqPatterns = _ref5.requests,
497 workspaceLayout = _ref5.workspaceLayout;
498
499 // Filter out workspace patterns if necessary
500
501 let depReqPatterns = workspaceLayout ? reqPatterns.filter(function (p) {
502 return !workspaceLayout.getManifestByPattern(p.pattern);
503 }) : reqPatterns;
504
505 // filter the list down to just the packages requested.
506 // prevents us from having to query the metadata for all packages.
507 if (filterByPatterns && filterByPatterns.length || flags && flags.pattern) {
508 const filterByNames = filterByPatterns && filterByPatterns.length ? filterByPatterns.map(function (pattern) {
509 return (0, (_normalizePattern4 || _load_normalizePattern()).normalizePattern)(pattern).name;
510 }) : [];
511 depReqPatterns = depReqPatterns.filter(function (dep) {
512 return filterByNames.indexOf((0, (_normalizePattern4 || _load_normalizePattern()).normalizePattern)(dep.pattern).name) >= 0 || flags && flags.pattern && micromatch.contains((0, (_normalizePattern4 || _load_normalizePattern()).normalizePattern)(dep.pattern).name, flags.pattern);
513 });
514 }
515
516 const deps = yield Promise.all(depReqPatterns.map((() => {
517 var _ref6 = (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* ({ pattern, hint, workspaceName, workspaceLoc }) {
518 const locked = lockfile.getLocked(pattern);
519 if (!locked) {
520 throw new (_errors || _load_errors()).MessageError(reporter.lang('lockfileOutdated'));
521 }
522
523 const name = locked.name,
524 current = locked.version;
525
526 let latest = '';
527 let wanted = '';
528 let url = '';
529
530 const normalized = (0, (_normalizePattern4 || _load_normalizePattern()).normalizePattern)(pattern);
531
532 if ((0, (_index || _load_index()).getExoticResolver)(pattern) || (0, (_index || _load_index()).getExoticResolver)(normalized.range)) {
533 latest = wanted = 'exotic';
534 url = normalized.range;
535 } else {
536 const registry = config.registries[locked.registry];
537
538 var _ref7 = yield registry.checkOutdated(config, name, normalized.range);
539
540 latest = _ref7.latest;
541 wanted = _ref7.wanted;
542 url = _ref7.url;
543 }
544
545 return {
546 name,
547 current,
548 wanted,
549 latest,
550 url,
551 hint,
552 range: normalized.range,
553 upgradeTo: '',
554 workspaceName: workspaceName || '',
555 workspaceLoc: workspaceLoc || ''
556 };
557 });
558
559 return function (_x) {
560 return _ref6.apply(this, arguments);
561 };
562 })()));
563
564 // Make sure to always output `exotic` versions to be compatible with npm
565 const isDepOld = function isDepOld({ current, latest, wanted }) {
566 return latest === 'exotic' || (_semver || _load_semver()).default.lt(current, wanted) || (_semver || _load_semver()).default.lt(current, latest);
567 };
568 const orderByName = function orderByName(depA, depB) {
569 return depA.name.localeCompare(depB.name);
570 };
571 return deps.filter(isDepOld).sort(orderByName);
572 })();
573 }
574}
575exports.default = PackageRequest;
\No newline at end of file