@dependabot/yarn-lib
Version:
📦🐈 Fast, reliable, and secure dependency management.
928 lines (701 loc) • 25.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _asyncToGenerator2;
function _load_asyncToGenerator() {
return _asyncToGenerator2 = _interopRequireDefault(require('babel-runtime/helpers/asyncToGenerator'));
}
var _index;
function _load_index() {
return _index = require('./resolvers/index.js');
}
var _packageRequest;
function _load_packageRequest() {
return _packageRequest = _interopRequireDefault(require('./package-request.js'));
}
var _normalizePattern2;
function _load_normalizePattern() {
return _normalizePattern2 = require('./util/normalize-pattern.js');
}
var _requestManager;
function _load_requestManager() {
return _requestManager = _interopRequireDefault(require('./util/request-manager.js'));
}
var _blockingQueue;
function _load_blockingQueue() {
return _blockingQueue = _interopRequireDefault(require('./util/blocking-queue.js'));
}
var _lockfile;
function _load_lockfile() {
return _lockfile = _interopRequireDefault(require('./lockfile'));
}
var _map;
function _load_map() {
return _map = _interopRequireDefault(require('./util/map.js'));
}
var _workspaceLayout;
function _load_workspaceLayout() {
return _workspaceLayout = _interopRequireDefault(require('./workspace-layout.js'));
}
var _resolutionMap;
function _load_resolutionMap() {
return _resolutionMap = _interopRequireDefault(require('./resolution-map.js'));
}
var _resolutionMap2;
function _load_resolutionMap2() {
return _resolutionMap2 = require('./resolution-map.js');
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const invariant = require('invariant');
const semver = require('semver');
class PackageResolver {
constructor(config, lockfile, resolutionMap = new (_resolutionMap || _load_resolutionMap()).default(config)) {
this.patternsByPackage = (0, (_map || _load_map()).default)();
this.fetchingPatterns = new Set();
this.fetchingQueue = new (_blockingQueue || _load_blockingQueue()).default('resolver fetching');
this.patterns = (0, (_map || _load_map()).default)();
this.resolutionMap = resolutionMap;
this.usedRegistries = new Set();
this.flat = false;
this.reporter = config.reporter;
this.lockfile = lockfile;
this.config = config;
this.delayedResolveQueue = [];
}
// whether the dependency graph will be flattened
// list of registries that have been used in this resolution
// activity monitor
// patterns we've already resolved or are in the process of resolving
// TODO
// manages and throttles json api http requests
// list of patterns associated with a package
// lockfile instance which we can use to retrieve version info
// a map of dependency patterns to packages
// reporter instance, abstracts out display logic
// environment specific config methods and options
// list of packages need to be resolved later (they found a matching version in the
// resolver, but better matches can still arrive later in the resolve process)
/**
* TODO description
*/
isNewPattern(pattern) {
return !!this.patterns[pattern].fresh;
}
updateManifest(ref, newPkg) {
// inherit fields
const oldPkg = this.patterns[ref.patterns[0]];
newPkg._reference = ref;
newPkg._remote = ref.remote;
newPkg.name = oldPkg.name;
newPkg.fresh = oldPkg.fresh;
newPkg.prebuiltVariants = oldPkg.prebuiltVariants;
// update patterns
for (var _iterator = ref.patterns, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
var _ref;
if (_isArray) {
if (_i >= _iterator.length) break;
_ref = _iterator[_i++];
} else {
_i = _iterator.next();
if (_i.done) break;
_ref = _i.value;
}
const pattern = _ref;
this.patterns[pattern] = newPkg;
}
return Promise.resolve();
}
updateManifests(newPkgs) {
for (var _iterator2 = newPkgs, _isArray2 = Array.isArray(_iterator2), _i2 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
var _ref2;
if (_isArray2) {
if (_i2 >= _iterator2.length) break;
_ref2 = _iterator2[_i2++];
} else {
_i2 = _iterator2.next();
if (_i2.done) break;
_ref2 = _i2.value;
}
const newPkg = _ref2;
if (newPkg._reference) {
for (var _iterator3 = newPkg._reference.patterns, _isArray3 = Array.isArray(_iterator3), _i3 = 0, _iterator3 = _isArray3 ? _iterator3 : _iterator3[Symbol.iterator]();;) {
var _ref3;
if (_isArray3) {
if (_i3 >= _iterator3.length) break;
_ref3 = _iterator3[_i3++];
} else {
_i3 = _iterator3.next();
if (_i3.done) break;
_ref3 = _i3.value;
}
const pattern = _ref3;
const oldPkg = this.patterns[pattern];
newPkg.prebuiltVariants = oldPkg.prebuiltVariants;
this.patterns[pattern] = newPkg;
}
}
}
return Promise.resolve();
}
/**
* Given a list of patterns, dedupe them to a list of unique patterns.
*/
dedupePatterns(patterns) {
const deduped = [];
const seen = new Set();
for (var _iterator4 = patterns, _isArray4 = Array.isArray(_iterator4), _i4 = 0, _iterator4 = _isArray4 ? _iterator4 : _iterator4[Symbol.iterator]();;) {
var _ref4;
if (_isArray4) {
if (_i4 >= _iterator4.length) break;
_ref4 = _iterator4[_i4++];
} else {
_i4 = _iterator4.next();
if (_i4.done) break;
_ref4 = _i4.value;
}
const pattern = _ref4;
const info = this.getResolvedPattern(pattern);
if (seen.has(info)) {
continue;
}
seen.add(info);
deduped.push(pattern);
}
return deduped;
}
/**
* Get a list of all manifests by topological order.
*/
getTopologicalManifests(seedPatterns) {
const pkgs = new Set();
const skip = new Set();
const add = seedPatterns => {
for (var _iterator5 = seedPatterns, _isArray5 = Array.isArray(_iterator5), _i5 = 0, _iterator5 = _isArray5 ? _iterator5 : _iterator5[Symbol.iterator]();;) {
var _ref5;
if (_isArray5) {
if (_i5 >= _iterator5.length) break;
_ref5 = _iterator5[_i5++];
} else {
_i5 = _iterator5.next();
if (_i5.done) break;
_ref5 = _i5.value;
}
const pattern = _ref5;
const pkg = this.getStrictResolvedPattern(pattern);
if (skip.has(pkg)) {
continue;
}
const ref = pkg._reference;
invariant(ref, 'expected reference');
skip.add(pkg);
add(ref.dependencies);
pkgs.add(pkg);
}
};
add(seedPatterns);
return pkgs;
}
/**
* Get a list of all manifests by level sort order.
*/
getLevelOrderManifests(seedPatterns) {
const pkgs = new Set();
const skip = new Set();
const add = seedPatterns => {
const refs = [];
for (var _iterator6 = seedPatterns, _isArray6 = Array.isArray(_iterator6), _i6 = 0, _iterator6 = _isArray6 ? _iterator6 : _iterator6[Symbol.iterator]();;) {
var _ref6;
if (_isArray6) {
if (_i6 >= _iterator6.length) break;
_ref6 = _iterator6[_i6++];
} else {
_i6 = _iterator6.next();
if (_i6.done) break;
_ref6 = _i6.value;
}
const pattern = _ref6;
const pkg = this.getStrictResolvedPattern(pattern);
if (skip.has(pkg)) {
continue;
}
const ref = pkg._reference;
invariant(ref, 'expected reference');
refs.push(ref);
skip.add(pkg);
pkgs.add(pkg);
}
for (var _iterator7 = refs, _isArray7 = Array.isArray(_iterator7), _i7 = 0, _iterator7 = _isArray7 ? _iterator7 : _iterator7[Symbol.iterator]();;) {
var _ref7;
if (_isArray7) {
if (_i7 >= _iterator7.length) break;
_ref7 = _iterator7[_i7++];
} else {
_i7 = _iterator7.next();
if (_i7.done) break;
_ref7 = _i7.value;
}
const ref = _ref7;
add(ref.dependencies);
}
};
add(seedPatterns);
return pkgs;
}
/**
* Get a list of all package names in the dependency graph.
*/
getAllDependencyNamesByLevelOrder(seedPatterns) {
const names = new Set();
for (var _iterator8 = this.getLevelOrderManifests(seedPatterns), _isArray8 = Array.isArray(_iterator8), _i8 = 0, _iterator8 = _isArray8 ? _iterator8 : _iterator8[Symbol.iterator]();;) {
var _ref9;
if (_isArray8) {
if (_i8 >= _iterator8.length) break;
_ref9 = _iterator8[_i8++];
} else {
_i8 = _iterator8.next();
if (_i8.done) break;
_ref9 = _i8.value;
}
const _ref8 = _ref9;
const name = _ref8.name;
names.add(name);
}
return names;
}
/**
* Retrieve all the package info stored for this package name.
*/
getAllInfoForPackageName(name) {
const patterns = this.patternsByPackage[name] || [];
return this.getAllInfoForPatterns(patterns);
}
/**
* Retrieve all the package info stored for a list of patterns.
*/
getAllInfoForPatterns(patterns) {
const infos = [];
const seen = new Set();
for (var _iterator9 = patterns, _isArray9 = Array.isArray(_iterator9), _i9 = 0, _iterator9 = _isArray9 ? _iterator9 : _iterator9[Symbol.iterator]();;) {
var _ref10;
if (_isArray9) {
if (_i9 >= _iterator9.length) break;
_ref10 = _iterator9[_i9++];
} else {
_i9 = _iterator9.next();
if (_i9.done) break;
_ref10 = _i9.value;
}
const pattern = _ref10;
const info = this.patterns[pattern];
if (seen.has(info)) {
continue;
}
seen.add(info);
infos.push(info);
}
return infos;
}
/**
* Get a flat list of all package info.
*/
getManifests() {
const infos = [];
const seen = new Set();
for (const pattern in this.patterns) {
const info = this.patterns[pattern];
if (seen.has(info)) {
continue;
}
infos.push(info);
seen.add(info);
}
return infos;
}
/**
* replace pattern in resolver, e.g. `name` is replaced with `name@^1.0.1`
*/
replacePattern(pattern, newPattern) {
const pkg = this.getResolvedPattern(pattern);
invariant(pkg, `missing package ${pattern}`);
const ref = pkg._reference;
invariant(ref, 'expected package reference');
ref.patterns = [newPattern];
this.addPattern(newPattern, pkg);
this.removePattern(pattern);
}
/**
* Make all versions of this package resolve to it.
*/
collapseAllVersionsOfPackage(name, version) {
const patterns = this.dedupePatterns(this.patternsByPackage[name]);
return this.collapsePackageVersions(name, version, patterns);
}
/**
* Make all given patterns resolve to version.
*/
collapsePackageVersions(name, version, patterns) {
const human = `${name}@${version}`;
// get manifest that matches the version we're collapsing too
let collapseToReference;
let collapseToManifest;
let collapseToPattern;
for (var _iterator10 = patterns, _isArray10 = Array.isArray(_iterator10), _i10 = 0, _iterator10 = _isArray10 ? _iterator10 : _iterator10[Symbol.iterator]();;) {
var _ref11;
if (_isArray10) {
if (_i10 >= _iterator10.length) break;
_ref11 = _iterator10[_i10++];
} else {
_i10 = _iterator10.next();
if (_i10.done) break;
_ref11 = _i10.value;
}
const pattern = _ref11;
const _manifest = this.patterns[pattern];
if (_manifest.version === version) {
collapseToReference = _manifest._reference;
collapseToManifest = _manifest;
collapseToPattern = pattern;
break;
}
}
invariant(collapseToReference && collapseToManifest && collapseToPattern, `Couldn't find package manifest for ${human}`);
for (var _iterator11 = patterns, _isArray11 = Array.isArray(_iterator11), _i11 = 0, _iterator11 = _isArray11 ? _iterator11 : _iterator11[Symbol.iterator]();;) {
var _ref12;
if (_isArray11) {
if (_i11 >= _iterator11.length) break;
_ref12 = _iterator11[_i11++];
} else {
_i11 = _iterator11.next();
if (_i11.done) break;
_ref12 = _i11.value;
}
const pattern = _ref12;
// don't touch the pattern we're collapsing to
if (pattern === collapseToPattern) {
continue;
}
// remove this pattern
const ref = this.getStrictResolvedPattern(pattern)._reference;
invariant(ref, 'expected package reference');
const refPatterns = ref.patterns.slice();
ref.prune();
// add pattern to the manifest we're collapsing to
for (var _iterator12 = refPatterns, _isArray12 = Array.isArray(_iterator12), _i12 = 0, _iterator12 = _isArray12 ? _iterator12 : _iterator12[Symbol.iterator]();;) {
var _ref13;
if (_isArray12) {
if (_i12 >= _iterator12.length) break;
_ref13 = _iterator12[_i12++];
} else {
_i12 = _iterator12.next();
if (_i12.done) break;
_ref13 = _i12.value;
}
const pattern = _ref13;
collapseToReference.addPattern(pattern, collapseToManifest);
}
}
return collapseToPattern;
}
/**
* TODO description
*/
addPattern(pattern, info) {
this.patterns[pattern] = info;
const byName = this.patternsByPackage[info.name] = this.patternsByPackage[info.name] || [];
if (byName.indexOf(pattern) === -1) {
byName.push(pattern);
}
}
/**
* TODO description
*/
removePattern(pattern) {
const pkg = this.patterns[pattern];
if (!pkg) {
return;
}
const byName = this.patternsByPackage[pkg.name];
if (!byName) {
return;
}
byName.splice(byName.indexOf(pattern), 1);
delete this.patterns[pattern];
}
/**
* TODO description
*/
getResolvedPattern(pattern) {
return this.patterns[pattern];
}
/**
* TODO description
*/
getStrictResolvedPattern(pattern) {
const manifest = this.getResolvedPattern(pattern);
invariant(manifest, 'expected manifest');
return manifest;
}
/**
* TODO description
*/
getExactVersionMatch(name, version, manifest) {
const patterns = this.patternsByPackage[name];
if (!patterns) {
return null;
}
for (var _iterator13 = patterns, _isArray13 = Array.isArray(_iterator13), _i13 = 0, _iterator13 = _isArray13 ? _iterator13 : _iterator13[Symbol.iterator]();;) {
var _ref14;
if (_isArray13) {
if (_i13 >= _iterator13.length) break;
_ref14 = _iterator13[_i13++];
} else {
_i13 = _iterator13.next();
if (_i13.done) break;
_ref14 = _i13.value;
}
const pattern = _ref14;
const info = this.getStrictResolvedPattern(pattern);
if (info.version === version) {
return info;
}
}
if (manifest && (0, (_index || _load_index()).getExoticResolver)(version)) {
return this.exoticRangeMatch(patterns.map(this.getStrictResolvedPattern.bind(this)), manifest);
}
return null;
}
/**
* Get the manifest of the highest known version that satisfies a package range
*/
getHighestRangeVersionMatch(name, range, manifest) {
const patterns = this.patternsByPackage[name];
if (!patterns) {
return null;
}
const versionNumbers = [];
const resolvedPatterns = patterns.map(pattern => {
const info = this.getStrictResolvedPattern(pattern);
versionNumbers.push(info.version);
return info;
});
const maxValidRange = semver.maxSatisfying(versionNumbers, range);
if (!maxValidRange) {
return manifest && (0, (_index || _load_index()).getExoticResolver)(range) ? this.exoticRangeMatch(resolvedPatterns, manifest) : null;
}
const indexOfmaxValidRange = versionNumbers.indexOf(maxValidRange);
const maxValidRangeManifest = resolvedPatterns[indexOfmaxValidRange];
return maxValidRangeManifest;
}
/**
* Get the manifest of the package that matches an exotic range
*/
exoticRangeMatch(resolvedPkgs, manifest) {
const remote = manifest._remote;
if (!(remote && remote.reference && remote.type === 'copy')) {
return null;
}
const matchedPkg = resolvedPkgs.find(({ _remote: pkgRemote }) => pkgRemote && pkgRemote.reference === remote.reference && pkgRemote.type === 'copy');
if (matchedPkg) {
manifest._remote = matchedPkg._remote;
}
return matchedPkg;
}
/**
* Determine if LockfileEntry is incorrect, remove it from lockfile cache and consider the pattern as new
*/
isLockfileEntryOutdated(version, range, hasVersion) {
return !!(semver.validRange(range) && semver.valid(version) && !(0, (_index || _load_index()).getExoticResolver)(range) && hasVersion && !semver.satisfies(version, range));
}
/**
* TODO description
*/
find(initialReq) {
var _this = this;
return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
const req = _this.resolveToResolution(initialReq);
// we've already resolved it with a resolution
if (!req) {
return;
}
const request = new (_packageRequest || _load_packageRequest()).default(req, _this);
const fetchKey = `${req.registry}:${req.pattern}:${String(req.optional)}`;
const initialFetch = !_this.fetchingPatterns.has(fetchKey);
let fresh = false;
if (_this.activity) {
_this.activity.tick(req.pattern);
}
if (initialFetch) {
_this.fetchingPatterns.add(fetchKey);
const lockfileEntry = _this.lockfile.getLocked(req.pattern);
if (lockfileEntry) {
var _normalizePattern = (0, (_normalizePattern2 || _load_normalizePattern()).normalizePattern)(req.pattern);
const range = _normalizePattern.range,
hasVersion = _normalizePattern.hasVersion;
if (_this.isLockfileEntryOutdated(lockfileEntry.version, range, hasVersion)) {
_this.reporter.warn(_this.reporter.lang('incorrectLockfileEntry', req.pattern));
_this.removePattern(req.pattern);
_this.lockfile.removePattern(req.pattern);
fresh = true;
}
} else {
fresh = true;
}
request.init();
}
yield request.find({ fresh, frozen: _this.frozen });
})();
}
/**
* TODO description
*/
init(deps, { isFlat, isFrozen, workspaceLayout } = {
isFlat: false,
isFrozen: false,
workspaceLayout: undefined
}) {
var _this2 = this;
return (0, (_asyncToGenerator2 || _load_asyncToGenerator()).default)(function* () {
_this2.flat = Boolean(isFlat);
_this2.frozen = Boolean(isFrozen);
_this2.workspaceLayout = workspaceLayout;
const activity = _this2.activity = _this2.reporter.activity();
for (var _iterator14 = deps, _isArray14 = Array.isArray(_iterator14), _i14 = 0, _iterator14 = _isArray14 ? _iterator14 : _iterator14[Symbol.iterator]();;) {
var _ref15;
if (_isArray14) {
if (_i14 >= _iterator14.length) break;
_ref15 = _iterator14[_i14++];
} else {
_i14 = _iterator14.next();
if (_i14.done) break;
_ref15 = _i14.value;
}
const req = _ref15;
yield _this2.find(req);
}
// all required package versions have been discovered, so now packages that
// resolved to existing versions can be resolved to their best available version
_this2.resolvePackagesWithExistingVersions();
for (var _iterator15 = _this2.resolutionMap.delayQueue, _isArray15 = Array.isArray(_iterator15), _i15 = 0, _iterator15 = _isArray15 ? _iterator15 : _iterator15[Symbol.iterator]();;) {
var _ref16;
if (_isArray15) {
if (_i15 >= _iterator15.length) break;
_ref16 = _iterator15[_i15++];
} else {
_i15 = _iterator15.next();
if (_i15.done) break;
_ref16 = _i15.value;
}
const req = _ref16;
_this2.resolveToResolution(req);
}
if (isFlat) {
for (var _iterator16 = deps, _isArray16 = Array.isArray(_iterator16), _i16 = 0, _iterator16 = _isArray16 ? _iterator16 : _iterator16[Symbol.iterator]();;) {
var _ref17;
if (_isArray16) {
if (_i16 >= _iterator16.length) break;
_ref17 = _iterator16[_i16++];
} else {
_i16 = _iterator16.next();
if (_i16.done) break;
_ref17 = _i16.value;
}
const dep = _ref17;
const name = (0, (_normalizePattern2 || _load_normalizePattern()).normalizePattern)(dep.pattern).name;
_this2.optimizeResolutions(name);
}
}
activity.end();
_this2.activity = null;
})();
}
// for a given package, see if a single manifest can satisfy all ranges
optimizeResolutions(name) {
const patterns = this.dedupePatterns(this.patternsByPackage[name] || []);
// don't optimize things that already have a lockfile entry:
// https://github.com/yarnpkg/yarn/issues/79
const collapsablePatterns = patterns.filter(pattern => {
const remote = this.patterns[pattern]._remote;
return !this.lockfile.getLocked(pattern) && (!remote || remote.type !== 'workspace');
});
if (collapsablePatterns.length < 2) {
return;
}
// reverse sort, so we'll find the maximum satisfying version first
const availableVersions = this.getAllInfoForPatterns(collapsablePatterns).map(manifest => manifest.version);
availableVersions.sort(semver.rcompare);
const ranges = collapsablePatterns.map(pattern => (0, (_normalizePattern2 || _load_normalizePattern()).normalizePattern)(pattern).range);
// find the most recent version that satisfies all patterns (if one exists), and
// collapse to that version.
for (var _iterator17 = availableVersions, _isArray17 = Array.isArray(_iterator17), _i17 = 0, _iterator17 = _isArray17 ? _iterator17 : _iterator17[Symbol.iterator]();;) {
var _ref18;
if (_isArray17) {
if (_i17 >= _iterator17.length) break;
_ref18 = _iterator17[_i17++];
} else {
_i17 = _iterator17.next();
if (_i17.done) break;
_ref18 = _i17.value;
}
const version = _ref18;
if (ranges.every(range => semver.satisfies(version, range))) {
this.collapsePackageVersions(name, version, collapsablePatterns);
return;
}
}
}
/**
* Called by the package requester for packages that this resolver already had
* a matching version for. Delay the resolve, because better matches can still be
* discovered.
*/
reportPackageWithExistingVersion(req, info) {
this.delayedResolveQueue.push({ req, info });
}
/**
* Executes the resolve to existing versions for packages after the find process,
* when all versions that are going to be used have been discovered.
*/
resolvePackagesWithExistingVersions() {
for (var _iterator18 = this.delayedResolveQueue, _isArray18 = Array.isArray(_iterator18), _i18 = 0, _iterator18 = _isArray18 ? _iterator18 : _iterator18[Symbol.iterator]();;) {
var _ref20;
if (_isArray18) {
if (_i18 >= _iterator18.length) break;
_ref20 = _iterator18[_i18++];
} else {
_i18 = _iterator18.next();
if (_i18.done) break;
_ref20 = _i18.value;
}
const _ref19 = _ref20;
const req = _ref19.req,
info = _ref19.info;
req.resolveToExistingVersion(info);
}
}
resolveToResolution(req) {
const parentNames = req.parentNames,
pattern = req.pattern;
if (!parentNames || this.flat) {
return req;
}
const resolution = this.resolutionMap.find(pattern, parentNames);
if (resolution) {
const resolutionManifest = this.getResolvedPattern(resolution);
if (resolutionManifest) {
invariant(resolutionManifest._reference, 'resolutions should have a resolved reference');
resolutionManifest._reference.patterns.push(pattern);
this.addPattern(pattern, resolutionManifest);
const lockManifest = this.lockfile.getLocked(pattern);
if ((0, (_resolutionMap2 || _load_resolutionMap2()).shouldUpdateLockfile)(lockManifest, resolutionManifest._reference)) {
this.lockfile.removePattern(pattern);
}
} else {
this.resolutionMap.addToDelayQueue(req);
}
return null;
}
return req;
}
}
exports.default = PackageResolver;