diff --git a/packages/constraint-solver/benchmark-tests.js b/packages/constraint-solver/benchmark-tests.js index 28def3db61..4712929053 100644 --- a/packages/constraint-solver/benchmark-tests.js +++ b/packages/constraint-solver/benchmark-tests.js @@ -273,7 +273,7 @@ runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - rails, gi var solution = r.resolve(args.dependencies, args.constraints, { previousSolution: previousSolution }).answer; // check that root deps are the same - _.each(args.dependencies, function (dep) { + args.dependencies.forEach(function (dep) { if (previousSolution[dep]) test.equal(solution[dep], previousSolution[dep], dep); }); @@ -284,17 +284,17 @@ runBenchmarks && Tinytest.add("constraint solver - benchmark on gems - rails, gi function getCatalogStub (gems) { return { getSortedVersionRecords(name) { - var versions = _.chain(gems) - .filter(function (pv) { return pv.name === name; }) - .pluck('number') + var versions = Object.values(gems.filter(function (pv) { return pv.name === name; }) + .map(function(gem) { + return gem.number + }) .filter(function (v) { return PackageVersion.getValidServerVersion(v); }) - .sort(PackageVersion.compare) - .uniq(true) - .value(); - return _.map(versions, function (version) { - var gem = _.find(gems, function (pv) { + .sort(PackageVersion.compare)); + + return versions.map(function (version) { + var gem = gems.find(function (pv) { return pv.name === name && pv.number === version; }); @@ -304,7 +304,7 @@ function getCatalogStub (gems) { dependencies: {} }; - _.each(gem.dependencies, function (dep) { + gem.dependencies.forEach(function (dep) { var name = dep[0]; var constraint = dep[1]; @@ -332,4 +332,4 @@ function getCatalogStub (gems) { return result; } }; -} +} \ No newline at end of file diff --git a/packages/constraint-solver/catalog-cache-tests.js b/packages/constraint-solver/catalog-cache-tests.js index f7bb34710d..7ea312ab9b 100644 --- a/packages/constraint-solver/catalog-cache-tests.js +++ b/packages/constraint-solver/catalog-cache-tests.js @@ -38,8 +38,8 @@ Tinytest.add("constraint solver - CatalogCache", function (test) { var pvs = {}; cache.eachPackageVersion(function (pv, deps) { check(pv, CS.PackageAndVersion); - check(_.values(deps), [CS.Dependency]); - pvs[pv.package+' '+pv.version] = _.keys(deps).sort(); + check(Object.values(deps), [CS.Dependency]); + pvs[`${pv.package} ${pv.version}`] = Object.keys(deps).sort(); }); test.equal(pvs, {'foo 1.0.0': ['bar'], 'foo 1.0.1': ['bar', 'bzzz', 'weakly1', 'weakly2']}); @@ -52,9 +52,9 @@ Tinytest.add("constraint solver - CatalogCache", function (test) { test.equal(oneVersion.length, 1); // don't know which it is var foos = []; - _.each(cache.getPackageVersions('foo'), function (v) { + cache.getPackageVersions('foo').forEach(function (v) { var depMap = cache.getDependencyMap('foo', v); - foos.push([v, _.map(depMap, String).sort()]); + foos.push([v, Object.values(depMap).map(String).sort()]); }); // versions should come out sorted, just like this. test.equal(foos, @@ -81,4 +81,4 @@ Tinytest.add("constraint solver - CatalogCache", function (test) { return true; }); test.equal(onePackage.length, 1); // don't know which package it is -}); +}); \ No newline at end of file diff --git a/packages/constraint-solver/catalog-cache.js b/packages/constraint-solver/catalog-cache.js index 1c3d311421..798496d447 100644 --- a/packages/constraint-solver/catalog-cache.js +++ b/packages/constraint-solver/catalog-cache.js @@ -1,3 +1,6 @@ +const has = Npm.require('lodash.has'); +const memoize = Npm.require('lodash.memoize'); + var CS = ConstraintSolver; var PV = PackageVersion; @@ -18,7 +21,7 @@ CS.CatalogCache = function () { }; CS.CatalogCache.prototype.hasPackageVersion = function (pkg, version) { - return _.has(this._dependencies, pvkey(pkg, version)); + return has(this._dependencies, pvkey(pkg, version)); }; CS.CatalogCache.prototype.addPackageVersion = function (p, v, deps) { @@ -28,11 +31,11 @@ CS.CatalogCache.prototype.addPackageVersion = function (p, v, deps) { check(deps, [CS.Dependency]); var key = pvkey(p, v); - if (_.has(this._dependencies, key)) { + if (has(this._dependencies, key)) { throw new Error("Already have an entry for " + key); } - if (! _.has(this._versions, p)) { + if (!has(this._versions, p)) { this._versions[p] = []; } this._versions[p].push(v); @@ -40,9 +43,9 @@ CS.CatalogCache.prototype.addPackageVersion = function (p, v, deps) { var depsByPackage = {}; this._dependencies[key] = depsByPackage; - _.each(deps, function (d) { + deps.forEach(function (d) { var p2 = d.packageConstraint.package; - if (_.has(depsByPackage, p2)) { + if (has(depsByPackage, p2)) { throw new Error("Can't have two dependencies on " + p2 + " in " + key); } @@ -55,7 +58,7 @@ CS.CatalogCache.prototype.addPackageVersion = function (p, v, deps) { // `d.packageConstraint.package`. (Don't mutate the map.) CS.CatalogCache.prototype.getDependencyMap = function (p, v) { var key = pvkey(p, v); - if (! _.has(this._dependencies, key)) { + if (!has(this._dependencies, key)) { throw new Error("No entry for " + key); } return this._dependencies[key]; @@ -64,14 +67,14 @@ CS.CatalogCache.prototype.getDependencyMap = function (p, v) { // Returns an array of version strings, sorted, possibly empty. // (Don't mutate the result.) CS.CatalogCache.prototype.getPackageVersions = function (pkg) { - var result = (_.has(this._versions, pkg) ? + var result = (has(this._versions, pkg) ? this._versions[pkg] : []); if ((!result.length) || result.sorted) { return result; } else { // sort in place, and record so that we don't sort redundantly // (we'll sort again if more versions are pushed onto the array) - var pvParse = _.memoize(PV.parse); + var pvParse = memoize(PV.parse); result.sort(function (a, b) { return PV.compare(pvParse(a), pvParse(b)); }); @@ -81,16 +84,16 @@ CS.CatalogCache.prototype.getPackageVersions = function (pkg) { }; CS.CatalogCache.prototype.hasPackage = function (pkg) { - return _.has(this._versions, pkg); + return has(this._versions, pkg); }; CS.CatalogCache.prototype.toJSONable = function () { var self = this; var data = {}; - _.each(self._dependencies, function (depsByPackage, key) { + Object.entries(self._dependencies).forEach(function ([key, depsByPackage]) { // depsByPackage is a map of String -> Dependency. // Map over the values to get an array of String. - data[key] = _.map(depsByPackage, function (dep) { + data[key] = Object.values(depsByPackage).map(function (dep) { return dep.toString(); }); }); @@ -101,12 +104,12 @@ CS.CatalogCache.fromJSONable = function (obj) { check(obj, { data: Object }); var cache = new CS.CatalogCache(); - _.each(obj.data, function (depsArray, pv) { + Object.entries(obj.data).forEach(function ([pv, depsArray]) { check(depsArray, [String]); pv = CS.PackageAndVersion.fromString(pv); cache.addPackageVersion( pv.package, pv.version, - _.map(depsArray, function (str) { + depsArray.map(function (str) { return CS.Dependency.fromString(str); })); }); @@ -118,8 +121,8 @@ CS.CatalogCache.fromJSONable = function (obj) { // iteration is stopped. There's no particular order to the iteration. CS.CatalogCache.prototype.eachPackageVersion = function (iter) { var self = this; - _.find(self._dependencies, function (value, key) { - var stop = iter(CS.PackageAndVersion.fromString(key), value); + Object.keys(self._dependencies).find(function (key) { + var stop = iter(CS.PackageAndVersion.fromString(key), self._dependencies[key]); return stop; }); }; @@ -129,8 +132,8 @@ CS.CatalogCache.prototype.eachPackageVersion = function (iter) { // If `iter` returns true, iteration is stopped. ConstraintSolver.CatalogCache.prototype.eachPackage = function (iter) { var self = this; - _.find(_.keys(self._versions), function (key) { + Object.keys(self._versions).find(function (key) { var stop = iter(key, self.getPackageVersions(key)); return stop; }); -}; +}; \ No newline at end of file diff --git a/packages/constraint-solver/catalog-loader.js b/packages/constraint-solver/catalog-loader.js index 22f666b699..41ef143f1c 100644 --- a/packages/constraint-solver/catalog-loader.js +++ b/packages/constraint-solver/catalog-loader.js @@ -1,3 +1,5 @@ +const has = Npm.require('lodash.has'); + var PV = PackageVersion; var CS = ConstraintSolver; @@ -35,10 +37,10 @@ CS.CatalogLoader = function (fromCatalog, toCatalogCache) { }; var convertDeps = function (catalogDeps) { - return _.map(catalogDeps, function (dep, pkg) { + return Object.entries(catalogDeps).map(function ([pkg, dep], ) { // The dependency is strong if any of its "references" // (for different architectures) are strong. - var isStrong = _.any(dep.references, function (ref) { + var isStrong = dep.references.some(function (ref) { return !ref.weak; }); @@ -52,7 +54,7 @@ var convertDeps = function (catalogDeps) { // Since we don't fetch different versions of a package independently // at the moment, this helper is where we get our data. CS.CatalogLoader.prototype._getSortedVersionRecords = function (pkg) { - if (! _.has(this._sortedVersionRecordsCache, pkg)) { + if (!has(this._sortedVersionRecordsCache, pkg)) { this._sortedVersionRecordsCache[pkg] = this.catalog.getSortedVersionRecords(pkg); } @@ -65,8 +67,8 @@ CS.CatalogLoader.prototype.loadSingleVersion = function (pkg, version) { var cache = self.catalogCache; if (! cache.hasPackageVersion(pkg, version)) { var rec; - if (_.has(self._sortedVersionRecordsCache, pkg)) { - rec = _.find(self._sortedVersionRecordsCache[pkg], + if (has(self._sortedVersionRecordsCache, pkg)) { + rec = self._sortedVersionRecordsCache[pkg].find( function (r) { return r.version === version; }); @@ -84,7 +86,7 @@ CS.CatalogLoader.prototype.loadAllVersions = function (pkg) { var self = this; var cache = self.catalogCache; var versionRecs = self._getSortedVersionRecords(pkg); - _.each(versionRecs, function (rec) { + versionRecs.forEach(function (rec) { var version = rec.version; if (! cache.hasPackageVersion(pkg, version)) { var deps = convertDeps(rec.dependencies); @@ -106,22 +108,22 @@ CS.CatalogLoader.prototype.loadAllVersionsRecursive = function (packageList) { var packagesEverEnqueued = {}; var enqueue = function (pkg) { - if (! _.has(packagesEverEnqueued, pkg)) { + if (!has(packagesEverEnqueued, pkg)) { packagesEverEnqueued[pkg] = true; loadQueue.push(pkg); } }; - _.each(packageList, enqueue); + packageList.forEach(enqueue); while (loadQueue.length) { var pkg = loadQueue.pop(); self.loadAllVersions(pkg); - _.each(self.catalogCache.getPackageVersions(pkg), function (v) { + self.catalogCache.getPackageVersions(pkg).forEach(function (v) { var depMap = self.catalogCache.getDependencyMap(pkg, v); - _.each(depMap, function (dep, package2) { + Object.entries(depMap).forEach(function ([package2, dep]) { enqueue(package2); }); }); } -}; +}; \ No newline at end of file diff --git a/packages/constraint-solver/constraint-solver-input.js b/packages/constraint-solver/constraint-solver-input.js index 9835e44030..e2a0bf2ae2 100644 --- a/packages/constraint-solver/constraint-solver-input.js +++ b/packages/constraint-solver/constraint-solver-input.js @@ -1,3 +1,7 @@ +const has = Npm.require('lodash.has'); +const isEqual = Npm.require('lodash.isequal'); +const isEmpty = Npm.require('lodash.isempty'); + var PV = PackageVersion; var CS = ConstraintSolver; @@ -18,7 +22,7 @@ CS.Input = function (dependencies, constraints, catalogCache, options) { // Convert them to our PackageConstraint class if necessary. (This is // just top-level constraints from .meteor/packages or running from // checkout, so it's not a lot of data.) - constraints = _.map(constraints, function (c) { + constraints = constraints.map(function (c) { if (c instanceof PV.PackageConstraint) { return c; } else { @@ -62,27 +66,27 @@ CS.Input = function (dependencies, constraints, catalogCache, options) { validatePackageName(packageName); }); self.catalogCache.eachPackageVersion(function (packageName, depsMap) { - _.each(depsMap, function (deps, depPackageName) { + Object.entries(depsMap).forEach(function ([depPackageName, deps]) { validatePackageName(depPackageName); }); }); - _.each(self.dependencies, validatePackageName); - _.each(self.upgrade, validatePackageName); - _.each(self.constraints, function (c) { + self.dependencies.forEach(validatePackageName); + self.upgrade.forEach(validatePackageName); + self.constraints.forEach(function (c) { validatePackageName(c.package); }); if (self.previousSolution) { - _.each(_.keys(self.previousSolution), + Object.keys(self.previousSolution).forEach( validatePackageName); } self._dependencySet = {}; // package name -> true - _.each(self.dependencies, function (d) { + self.dependencies.forEach(function (d) { self._dependencySet[d] = true; }); self._upgradeSet = {}; - _.each(self.upgrade, function (u) { + self.upgrade.forEach(function (u) { self._upgradeSet[u] = true; }); }; @@ -107,33 +111,33 @@ CS.Input.prototype.isKnownPackage = function (p) { }; CS.Input.prototype.isRootDependency = function (p) { - return _.has(this._dependencySet, p); + return has(this._dependencySet, p); }; CS.Input.prototype.isUpgrading = function (p) { - return _.has(this._upgradeSet, p); + return has(this._upgradeSet, p); }; CS.Input.prototype.isInPreviousSolution = function (p) { - return !! (this.previousSolution && _.has(this.previousSolution, p)); + return !! (this.previousSolution && has(this.previousSolution, p)); }; function getMentionedPackages(input) { var packages = {}; // package -> true - _.each(input.dependencies, function (pkg) { + input.dependencies.forEach(function (pkg) { packages[pkg] = true; }); - _.each(input.constraints, function (constraint) { + input.constraints.forEach(function (constraint) { packages[constraint.package] = true; }); if (input.previousSolution) { - _.each(input.previousSolution, function (version, pkg) { + Object.entries(input.previousSolution).forEach(function ([pkg, version]) { packages[pkg] = true; }); } - return _.keys(packages); + return Object.keys(packages); } CS.Input.prototype.loadFromCatalog = function (catalogLoader) { @@ -146,7 +150,7 @@ CS.Input.prototype.loadOnlyPreviousSolution = function (catalogLoader) { // load just the exact versions from the previousSolution if (self.previousSolution) { - _.each(self.previousSolution, function (version, pkg) { + Object.entries(self.previousSolution).forEach(function ([pkg, version]) { catalogLoader.loadSingleVersion(pkg, version); }); } @@ -170,7 +174,7 @@ CS.Input.prototype.isEqual = function (otherInput) { // the same input. So by omitting `catalogCache` we no longer need // to reload the entire relevant part of the catalog from SQLite on // every rebuild! - return _.isEqual( + return isEqual( a.toJSONable(true), b.toJSONable(true) ); @@ -180,7 +184,7 @@ CS.Input.prototype.toJSONable = function (omitCatalogCache) { var self = this; var obj = { dependencies: self.dependencies, - constraints: _.map(self.constraints, function (c) { + constraints: self.constraints.map(function (c) { return c.toString(); }) }; @@ -194,7 +198,7 @@ CS.Input.prototype.toJSONable = function (omitCatalogCache) { if (self.upgrade.length) { obj.upgrade = self.upgrade; } - if (! _.isEmpty(self.anticipatedPrereleases)) { + if (!isEmpty(self.anticipatedPrereleases)) { obj.anticipatedPrereleases = self.anticipatedPrereleases; } if (self.previousSolution !== null) { @@ -225,7 +229,7 @@ CS.Input.fromJSONable = function (obj) { return new CS.Input( obj.dependencies, - _.map(obj.constraints, function (cstr) { + obj.constraints.map(function (cstr) { return PV.parsePackageConstraint(cstr); }), CS.CatalogCache.fromJSONable(obj.catalogCache), @@ -236,4 +240,4 @@ CS.Input.fromJSONable = function (obj) { allowIncompatibleUpdate: obj.allowIncompatibleUpdate, upgradeIndirectDepPatchVersions: obj.upgradeIndirectDepPatchVersions }); -}; +}; \ No newline at end of file diff --git a/packages/constraint-solver/constraint-solver-tests.js b/packages/constraint-solver/constraint-solver-tests.js index 660db6da78..74838ddfba 100644 --- a/packages/constraint-solver/constraint-solver-tests.js +++ b/packages/constraint-solver/constraint-solver-tests.js @@ -1,16 +1,20 @@ +const has = Npm.require('lodash.has'); +const isString = Npm.require('lodash.isstring'); +const isEmpty = Npm.require('lodash.isempty'); + var PV = PackageVersion; var CS = ConstraintSolver; var makeResolver = function (data) { var Versions = new LocalCollection; - _.each(data, function (versionDescription) { + data.forEach(function (versionDescription) { var packageName = versionDescription.shift(); var version = versionDescription.shift(); var deps = versionDescription.shift(); - var constructedDeps = {}; - _.each(deps, function (constraint, name) { + if (!isEmpty(deps)) { + Object.entries(deps).forEach(function ([name, constraint]) { constructedDeps[name] = { constraint: constraint, references: [ @@ -20,6 +24,7 @@ var makeResolver = function (data) { ] }; }); + } Versions.insert({ packageName: packageName, version: version, dependencies: constructedDeps }); }); @@ -73,8 +78,7 @@ var defaultResolver = makeResolver([ // in the returned arrays. splitArgs = function (deps) { var dependencies = [], constraints = []; - - _.each(deps, function (constr, dep) { + Object.entries(deps).forEach(function ([dep, constr]) { if (constr && constr.charAt(0) === 'w') { constr = constr.slice(1); } else { @@ -89,7 +93,7 @@ splitArgs = function (deps) { var testWithResolver = function (test, resolver, f) { var answerToString = function (answer) { - var pvs = _.map(answer, function (v, p) { return p + ' ' + v; }); + var pvs = Object.keys(answer).map(function (p) { return p + ' ' + answer[p]; }); return pvs.sort().join('\n'); }; var t = function (deps, expected, options) { @@ -306,7 +310,7 @@ Tinytest.add("constraint solver - previousSolution", function (test) { Tinytest.add("constraint solver - no constraint dependency - anything", function (test) { var versions = defaultResolver.resolve(["sparkle"], []).answer; - test.isTrue(_.isString(versions.sparkle)); + test.isTrue(isString(versions.sparkle)); }); @@ -333,9 +337,9 @@ Tinytest.add("constraint solver - input serialization", function (test) { test.equal(input1.upgradeIndirectDepPatchVersions, false); var obj1 = input1.toJSONable(); - test.isFalse(_.has(obj1, 'upgrade')); - test.isFalse(_.has(obj1, 'anticipatedPrereleases')); - test.isFalse(_.has(obj1, 'previousSolution')); + test.isFalse(has(obj1, 'upgrade')); + test.isFalse(has(obj1, 'anticipatedPrereleases')); + test.isFalse(has(obj1, 'previousSolution')); var input2 = CS.Input.fromJSONable(obj1); var obj2 = input2.toJSONable(); @@ -377,4 +381,4 @@ Tinytest.add("constraint solver - non-existent indirect package", function (test return error.message.match(/unknown package: bar/); }); }); -}); +}); \ No newline at end of file diff --git a/packages/constraint-solver/constraint-solver.js b/packages/constraint-solver/constraint-solver.js index f185894d09..10c6d4484e 100644 --- a/packages/constraint-solver/constraint-solver.js +++ b/packages/constraint-solver/constraint-solver.js @@ -1,3 +1,5 @@ +const isEqual = Npm.require('lodash.isequal'); + var PV = PackageVersion; var CS = ConstraintSolver; @@ -50,13 +52,17 @@ CS.PackagesResolver.prototype.resolve = function (dependencies, constraints, var input; Profile.time("new CS.Input", function () { + const { upgrade, + anticipatedPrereleases, + previousSolution, + allowIncompatibleUpdate, + upgradeIndirectDepPatchVersions } = options; input = new CS.Input(dependencies, constraints, self.catalogCache, - _.pick(options, - 'upgrade', - 'anticipatedPrereleases', - 'previousSolution', - 'allowIncompatibleUpdate', - 'upgradeIndirectDepPatchVersions')); + { upgrade, + anticipatedPrereleases, + previousSolution, + allowIncompatibleUpdate, + upgradeIndirectDepPatchVersions }); }); // The constraint solver avoids re-solving everything from scratch on @@ -78,14 +84,14 @@ CS.PackagesResolver.prototype.resolve = function (dependencies, constraints, resultCache = null; } else if (resultCache && resultCache.lastInput && - _.isEqual(resultCache.lastInput, + isEqual(resultCache.lastInput, input.toJSONable(true))) { return resultCache.lastOutput; } if (options.supportedIsobuildFeaturePackages) { - _.each(options.supportedIsobuildFeaturePackages, function (versions, pkg) { - _.each(versions, function (version) { + Object.entries(options.supportedIsobuildFeaturePackages).forEach(function ([pkg, versions]) { + versions.forEach(function (version) { input.catalogCache.addPackageVersion(pkg, version, []); }); }); @@ -100,7 +106,7 @@ CS.PackagesResolver.prototype.resolve = function (dependencies, constraints, if (options.previousSolution && options.missingPreviousVersionIsError) { // see comment where missingPreviousVersionIsError is passed in Profile.time("check for previous versions in catalog", function () { - _.each(options.previousSolution, function (version, pkg) { + Object.entries(options.previousSolution).forEach(function ([pkg, version]) { if (! input.catalogCache.hasPackageVersion(pkg, version)) { CS.throwConstraintSolverError( "Package version not in catalog: " + pkg + " " + version); @@ -193,7 +199,7 @@ CS.PackagesResolver._resolveWithInput = function (input, options) { // with an `alternatives` property lifted from one. // - version: version String CS.isConstraintSatisfied = function (pkg, vConstraint, version) { - return _.some(vConstraint.alternatives, function (simpleConstraint) { + return vConstraint.alternatives.some(function (simpleConstraint) { var type = simpleConstraint.type; if (type === "any-reasonable") { @@ -263,4 +269,4 @@ CS.DummyProfile = function (bucket, f) { }; CS.DummyProfile.time = function (bucket, f) { return f(); -}; +}; \ No newline at end of file diff --git a/packages/constraint-solver/datatypes-tests.js b/packages/constraint-solver/datatypes-tests.js index 88275ee8c9..8d07079088 100644 --- a/packages/constraint-solver/datatypes-tests.js +++ b/packages/constraint-solver/datatypes-tests.js @@ -2,7 +2,7 @@ var PV = PackageVersion; var CS = ConstraintSolver; Tinytest.add("constraint solver - datatypes - Dependency", function (test) { - _.each(["foo", "foo@1.0.0"], function (foo) { + ["foo", "foo@1.0.0"].forEach(function (foo) { var d1 = new CS.Dependency(PV.parsePackageConstraint(foo)); test.equal(d1.packageConstraint.toString(), foo); test.equal(d1.isWeak, false); diff --git a/packages/constraint-solver/input-tests.js b/packages/constraint-solver/input-tests.js index e302fef6d7..944e689b57 100644 --- a/packages/constraint-solver/input-tests.js +++ b/packages/constraint-solver/input-tests.js @@ -12,7 +12,7 @@ var CS = ConstraintSolver; // in that order. If that's not true, these tests will break. var sortKeys = function (obj) { var result = {}; - _.each(_.keys(obj).sort(), function (k) { + Object.keys(obj).sort().forEach(function (k) { result[k] = obj[k]; }); return result; @@ -22,7 +22,7 @@ var formatSolution = function (obj) { // results into tests. return JSON.stringify({ answer: sortKeys(obj.answer), - allAnswers: obj.allAnswers && _.map(obj.allAnswers, sortKeys), + allAnswers: obj.allAnswers && obj.allAnswers.map(sortKeys), neededToUseUnanticipatedPrereleases: obj.neededToUseUnanticipatedPrereleases }, null, 2); }; @@ -36,7 +36,7 @@ var doTest = function (test, inputJSONable, outputJSONable, options) { } if (typeof outputJSONable.neededToUseUnanticipatedPrereleases !== 'boolean') { - outputJSONable = _.extend(outputJSONable, { + outputJSONable = Object.assign(outputJSONable, { neededToUseUnanticipatedPrereleases: ( !! outputJSONable.neededToUseUnanticipatedPrereleases) }); diff --git a/packages/constraint-solver/package.js b/packages/constraint-solver/package.js index babea7efa6..0b28df8555 100644 --- a/packages/constraint-solver/package.js +++ b/packages/constraint-solver/package.js @@ -3,10 +3,20 @@ Package.describe({ version: "1.2.0" }); +Npm.depends({ + 'lodash.has': '4.5.2', + 'lodash.memoize': '4.1.2', + 'lodash.isequal': '4.5.0', + 'lodash.isempty': '4.4.0', + 'lodash.zip': '4.2.0', + 'lodash.groupby': '4.6.0', + 'lodash.isstring': '4.0.1', + 'lodash.isobject': '3.0.2' +}); + Package.onUse(function (api) { api.export('ConstraintSolver'); api.use([ - 'underscore', 'check', 'package-version-parser', 'logic-solver' @@ -27,7 +37,6 @@ Package.onTest(function (api) { 'tinytest', 'minimongo', 'package-version-parser', - 'underscore', 'check' ]); diff --git a/packages/constraint-solver/solver.js b/packages/constraint-solver/solver.js index c92bb67843..8c715d33cd 100644 --- a/packages/constraint-solver/solver.js +++ b/packages/constraint-solver/solver.js @@ -1,3 +1,8 @@ +const has = Npm.require('lodash.has'); +const zip = Npm.require('lodash.zip'); +const memoize = Npm.require('lodash.memoize'); +const groupBy = Npm.require('lodash.groupby'); + var CS = ConstraintSolver; var PV = PackageVersion; @@ -16,10 +21,10 @@ CS.Solver = function (input, options) { self.errors = []; // [String] self.pricer = new CS.VersionPricer(); - self.getConstraintFormula = _.memoize(_getConstraintFormula, - function (p, vConstraint) { - return p + "@" + vConstraint.raw; - }); + self.getConstraintFormula = memoize(_getConstraintFormula, + function (p, vConstraint) { + return p + "@" + vConstraint.raw; + }); self.options = options || {}; self.Profile = (self.options.Profile || CS.DummyProfile); @@ -38,7 +43,7 @@ CS.Solver = function (input, options) { CS.Solver.prototype.throwAnyErrors = function () { if (this.errors.length) { - var multiline = _.any(this.errors, function (e) { + var multiline = this.errors.some(function (e) { return /\n/.test(e); }); CS.throwConstraintSolverError(this.errors.join( @@ -48,7 +53,7 @@ CS.Solver.prototype.throwAnyErrors = function () { CS.Solver.prototype.getVersions = function (pkg) { var self = this; - if (_.has(self.analysis.allowedVersions, pkg)) { + if (has(self.analysis.allowedVersions, pkg)) { return self.analysis.allowedVersions[pkg]; } else { return self.input.catalogCache.getPackageVersions(pkg); @@ -90,20 +95,20 @@ CS.Solver.prototype.analyze = function () { // track such packages in packagesWithNoAllowedVersions so that we // throw a good error later. Profile.time("analyze allowed versions", function () { - _.each(_.groupBy(input.constraints, 'package'), function (cs, p) { + Object.entries(groupBy(input.constraints, 'package')).forEach(function ([p, cs]) { var versions = cache.getPackageVersions(p); - if (! versions.length) { + if (!versions.length) { // deal with wholly unknown packages later return; } - _.each(cs, function (constr) { - versions = _.filter(versions, function (v) { + cs.forEach(function (constr) { + versions = versions.filter(function (v) { return CS.isConstraintSatisfied(p, constr.versionConstraint, v); }); }); - if (! versions.length) { - analysis.packagesWithNoAllowedVersions[p] = _.filter(cs, function (c) { - return !! c.constraintString; + if (!versions.length) { + analysis.packagesWithNoAllowedVersions[p] = cs.filter(function (c) { + return !!c.constraintString; }); } analysis.allowedVersions[p] = versions; @@ -118,11 +123,11 @@ CS.Solver.prototype.analyze = function () { analysis.previousRootDepVersions = []; Profile.time("analyze root dependencies", function () { - _.each(input.dependencies, function (p) { - if (! input.isKnownPackage(p)) { + input.dependencies.forEach(function (p) { + if (!input.isKnownPackage(p)) { analysis.unknownRootDeps.push(p); } else if (input.isInPreviousSolution(p) && - ! input.isUpgrading(p)) { + !input.isUpgrading(p)) { analysis.previousRootDepVersions.push(new CS.PackageAndVersion( p, input.previousSolution[p])); } @@ -130,7 +135,7 @@ CS.Solver.prototype.analyze = function () { // throw if there are unknown packages in root deps if (analysis.unknownRootDeps.length) { - _.each(analysis.unknownRootDeps, function (p) { + analysis.unknownRootDeps.forEach(function (p) { if (CS.isIsobuildFeaturePackage(p)) { self.errors.push( 'unsupported Isobuild feature "' + p + @@ -171,21 +176,21 @@ CS.Solver.prototype.analyze = function () { var markReachable = function (p) { analysis.reachablePackages[p] = true; - _.each(self.getVersions(p), function (v) { - _.each(cache.getDependencyMap(p, v), function (dep) { + self.getVersions(p).forEach(function (v) { + Object.values(cache.getDependencyMap(p, v)).forEach(function (dep) { // `dep` is a CS.Dependency var p2 = dep.packageConstraint.package; - if (! input.isKnownPackage(p2)) { + if (!input.isKnownPackage(p2)) { // record this package so we will generate a variable // for it. we'll try not to select it, and ultimately // throw an error if we are forced to. - if (! _.has(analysis.unknownPackages, p2)) { + if (!has(analysis.unknownPackages, p2)) { analysis.unknownPackages[p2] = []; } analysis.unknownPackages[p2].push(pvVar(p, v)); } else { - if (! dep.isWeak) { - if (! _.has(analysis.reachablePackages, p2)) { + if (!dep.isWeak) { + if (!has(analysis.reachablePackages, p2)) { markReachable(p2); } } @@ -195,7 +200,7 @@ CS.Solver.prototype.analyze = function () { }; Profile.time("analyze reachability", function () { - _.each(input.dependencies, markReachable); + input.dependencies.forEach(markReachable); }); ////////// ANALYZE CONSTRAINTS @@ -217,9 +222,9 @@ CS.Solver.prototype.analyze = function () { // version constraints is a power-tool that should be used sparingly // by application developers, and never abused by package authors. var overrides = new Set; - _.each(input.constraints, function (c) { + input.constraints.forEach(function (c) { if (c.constraintString && - c.versionConstraint.override) { + c.versionConstraint.override) { overrides.add(c.package); } }); @@ -260,28 +265,28 @@ CS.Solver.prototype.analyze = function () { } // top-level constraints - _.each(input.constraints, function (c) { + input.constraints.forEach(function (c) { if (c.constraintString) { analysis.constraints.push(new CS.Solver.Constraint( null, c.package, getVersionConstraint(c), "constraint#" + analysis.constraints.length)); if (c.versionConstraint.alternatives.length === 1 && - c.versionConstraint.alternatives[0].type === 'exactly') { + c.versionConstraint.alternatives[0].type === 'exactly') { analysis.topLevelEqualityConstrainedPackages[c.package] = true; } } }); // constraints specified in package dependencies - _.each(_.keys(analysis.reachablePackages), function (p) { - _.each(self.getVersions(p), function (v) { + Object.keys(analysis.reachablePackages).forEach(function (p) { + self.getVersions(p).forEach(function (v) { var pv = pvVar(p, v); - _.each(cache.getDependencyMap(p, v), function (dep) { + Object.values(cache.getDependencyMap(p, v)).forEach(function (dep) { // `dep` is a CS.Dependency var p2 = dep.packageConstraint.package; if (input.isKnownPackage(p2) && - dep.packageConstraint.constraintString) { + dep.packageConstraint.constraintString) { analysis.constraints.push(new CS.Solver.Constraint( pv, p2, getVersionConstraint(dep.packageConstraint), "constraint#" + analysis.constraints.length)); @@ -295,11 +300,11 @@ CS.Solver.prototype.analyze = function () { Profile.time("analyze pre-releases", function () { var unanticipatedPrereleases = []; - _.each(_.keys(analysis.reachablePackages), function (p) { + Object.keys(analysis.reachablePackages).forEach(function (p) { var anticipatedPrereleases = input.anticipatedPrereleases[p]; - _.each(self.getVersions(p), function (v) { - if (/-/.test(v) && ! (anticipatedPrereleases && - _.has(anticipatedPrereleases, v))) { + self.getVersions(p).forEach(function (v) { + if (/-/.test(v) && !(anticipatedPrereleases && + has(anticipatedPrereleases, v))) { unanticipatedPrereleases.push(pvVar(p, v)); } }); @@ -357,7 +362,7 @@ CS.Solver.Step.prototype.addTerm = function (term, weight) { if (typeof this.weights === 'number') { if (weight !== this.weights) { throw new Error("Can't specify a different weight now: " + - weight + " != " + this.weights); + weight + " != " + this.weights); } } else { this.weights.push(weight); @@ -374,9 +379,9 @@ var DEBUG = false; CS.Solver.prototype.minimize = function (step, options) { var self = this; - if (_.isArray(step)) { + if (Array.isArray(step)) { // minimize([steps...], options) - _.each(step, function (st) { + step.forEach(function (st) { self.minimize(st, options); }); return; @@ -389,7 +394,7 @@ CS.Solver.prototype.minimize = function (step, options) { var costWeights_ = arguments[2]; var options_ = arguments[3]; if (costWeights_ && typeof costWeights_ === 'object' && - ! _.isArray(costWeights_)) { + !Array.isArray(costWeights_)) { options_ = costWeights_; costWeights_ = null; } @@ -419,29 +424,29 @@ CS.Solver.prototype.minimize = function (step, options) { self.setSolution(logic.minimizeWeightedSum( self.solution, optimized.costTerms, optimized.costWeights, { - progress: function (status, cost) { - if (self.options.nudge) { - self.options.nudge(); + progress: function (status, cost) { + if (self.options.nudge) { + self.options.nudge(); + } + if (DEBUG) { + if (status === 'improving') { + console.log(cost + " ... trying to improve ..."); + } else if (status === 'trying') { + console.log("... trying " + cost + " ... "); } - if (DEBUG) { - if (status === 'improving') { - console.log(cost + " ... trying to improve ..."); - } else if (status === 'trying') { - console.log("... trying " + cost + " ... "); - } - } - }, - strategy: (options && options.strategy) - })); + } + }, + strategy: (options && options.strategy) + })); step.optimum = self.solution.getWeightedSum(costTerms, costWeights); if (DEBUG) { console.log(step.optimum + " is optimal"); if (step.optimum) { - _.each(costTerms, function (t, i) { + costTerms.forEach(function (t, i) { var w = (typeof costWeights === 'number' ? costWeights : - costWeights[i]); + costWeights[i]); if (w && self.solution.evaluate(t)) { console.log(" " + w + ": " + t); } @@ -474,32 +479,38 @@ var groupMutuallyExclusiveTerms = function (costTerms, costWeights) { // first space. So "foo 1.0.0" becomes "foo " and "foo" stays "foo". var getTermKey = function (t) { var firstSpace = t.indexOf(' '); - return firstSpace < 0 ? t : t.slice(0, firstSpace+1); + return firstSpace < 0 ? t : t.slice(0, firstSpace + 1); }; // costWeights, as usual, may be a number or an array if (typeof costWeights === 'number') { return { - costTerms: _.map(_.groupBy(costTerms, getTermKey), function (group) { + costTerms: Object.values(groupBy(costTerms, getTermKey)).map(function (group) { return Logic.or(group); }), costWeights: costWeights }; - } else if (! costTerms.length) { + } else if (!costTerms.length) { return { costTerms: costTerms, costWeights: costWeights }; } else { - var weightedTerms = _.zip(costWeights, costTerms); - var newWeightedTerms = _.map(_.groupBy(weightedTerms, function (wt) { + var weightedTerms = zip(costWeights, costTerms); + var newWeightedTerms = Object.values(groupBy(weightedTerms, function (wt) { // construct a string from the weight and term key, for grouping // purposes. since the weight comes first, there's no ambiguity // and the separator char could be pretty much anything. return wt[0] + ' ' + getTermKey(wt[1]); - }), function (wts) { - return [wts[0][0], Logic.or(_.pluck(wts, 1))]; + })).map(function (wts) { + return [wts[0][0], Logic.or(wts.map(function(x){ + return x[1] + }))]; }); return { - costTerms: _.pluck(newWeightedTerms, 1), - costWeights: _.pluck(newWeightedTerms, 0) + costTerms: newWeightedTerms.map(function(x){ + return x[1] + }), + costWeights: newWeightedTerms.map(function(x){ + return x[0] + }) }; } @@ -513,7 +524,7 @@ CS.Solver.prototype.getStepContributions = function (step) { var solution = self.solution; var contributions = {}; var weights = step.weights; - _.each(step.terms, function (t, i) { + step.terms.forEach(function (t, i) { var w = (typeof weights === 'number' ? weights : weights[i]); if (w && self.solution.evaluate(t)) { contributions[t] = w; @@ -523,7 +534,7 @@ CS.Solver.prototype.getStepContributions = function (step) { }; var addCostsToSteps = function (pkg, versions, costs, steps) { - var pvs = _.map(versions, function (v) { + var pvs = versions.map(function (v) { return pvVar(pkg, v); }); for (var j = 0; j < steps.length; j++) { @@ -546,7 +557,7 @@ var addCostsToSteps = function (pkg, versions, costs, steps) { // the cost of every version of every package. This function iterates // over `packages` and puts the result into `Step` objects. CS.Solver.prototype.getVersionCostSteps = function (stepBaseName, packages, - pricerMode) { + pricerMode) { var self = this; var major = new CS.Solver.Step(stepBaseName + '_major'); var minor = new CS.Solver.Step(stepBaseName + '_minor'); @@ -556,7 +567,7 @@ CS.Solver.prototype.getVersionCostSteps = function (stepBaseName, packages, self.Profile.time( "calculate " + stepBaseName + " version costs", function () { - _.each(packages, function (p) { + packages.forEach(function (p) { var versions = self.getVersions(p); if (versions.length >= 2) { var costs = self.pricer.priceVersions(versions, pricerMode); @@ -574,8 +585,8 @@ CS.Solver.prototype.getVersionCostSteps = function (stepBaseName, packages, // as `packageAndVersion`. (Actually it's a complicated function of the // previous and new version.) CS.Solver.prototype.getVersionDistanceSteps = function (stepBaseName, - packageAndVersions, - takePatches) { + packageAndVersions, + takePatches) { var self = this; var incompat = new CS.Solver.Step(stepBaseName + '_incompat'); @@ -587,7 +598,7 @@ CS.Solver.prototype.getVersionDistanceSteps = function (stepBaseName, self.Profile.time( "calculate " + stepBaseName + " distance costs", function () { - _.each(packageAndVersions, function (pvArg) { + packageAndVersions.forEach(function (pvArg) { var pkg = pvArg.package; var previousVersion = pvArg.version; var versions = self.getVersions(pkg); @@ -595,7 +606,7 @@ CS.Solver.prototype.getVersionDistanceSteps = function (stepBaseName, var costs = self.pricer.priceVersionsWithPrevious( versions, previousVersion, takePatches); addCostsToSteps(pkg, versions, costs, - [incompat, major, minor, patch, rest]); + [incompat, major, minor, patch, rest]); } }); }); @@ -606,7 +617,7 @@ CS.Solver.prototype.getVersionDistanceSteps = function (stepBaseName, CS.Solver.prototype.currentVersionMap = function () { var self = this; var pvs = []; - _.each(self.solution.getTrueVars(), function (x) { + self.solution.getTrueVars().forEach(function (x) { if (x.indexOf(' ') >= 0) { // all variables with spaces in them are PackageAndVersions var pv = CS.PackageAndVersion.fromString(x); @@ -615,11 +626,11 @@ CS.Solver.prototype.currentVersionMap = function () { }); var versionMap = {}; - _.each(pvs, function (pv) { - if (_.has(versionMap, pv.package)) { + pvs.forEach(function (pv) { + if (has(versionMap, pv.package)) { throw new Error("Assertion failure: Selected two versions of " + - pv.package + ", " +versionMap[pv.package] + - " and " + pv.version); + pv.package + ", " + versionMap[pv.package] + + " and " + pv.version); } versionMap[pv.package] = pv.version; }); @@ -632,7 +643,7 @@ CS.Solver.prototype.currentVersionMap = function () { CS.Solver.prototype.setSolution = function (solution) { var self = this; self.solution = solution; - if (! self.solution) { + if (!self.solution) { throw new Error("Unexpected unsatisfiability"); } // When we query a Solution, we always want to treat unknown variables @@ -671,19 +682,19 @@ CS.Solver.prototype._getAnswer = function (options) { // require root dependencies Profile.time("require root dependencies", function () { - _.each(input.dependencies, function (p) { + input.dependencies.forEach(function (p) { logic.require(p); }); }); // generate package version variables for known, reachable packages Profile.time("generate package variables", function () { - _.each(_.keys(analysis.reachablePackages), function (p) { - if (! _.has(analysis.packagesWithNoAllowedVersions, p)) { - var versionVars = _.map(self.getVersions(p), - function (v) { - return pvVar(p, v); - }); + Object.keys(analysis.reachablePackages).forEach(function (p) { + if (!has(analysis.packagesWithNoAllowedVersions, p)) { + var versionVars = self.getVersions(p).map( + function (v) { + return pvVar(p, v); + }); // At most one of ["foo 1.0.0", "foo 1.0.1", ...] is true. logic.require(Logic.atMostOne(versionVars)); // The variable "foo" is true if and only if at least one of the @@ -695,11 +706,11 @@ CS.Solver.prototype._getAnswer = function (options) { // generate strong dependency requirements Profile.time("generate dependency requirements", function () { - _.each(_.keys(analysis.reachablePackages), function (p) { - _.each(self.getVersions(p), function (v) { - _.each(cache.getDependencyMap(p, v), function (dep) { + Object.keys(analysis.reachablePackages).forEach(function (p) { + self.getVersions(p).forEach(function (v) { + Object.values(cache.getDependencyMap(p, v)).forEach(function (dep) { // `dep` is a CS.Dependency - if (! dep.isWeak) { + if (!dep.isWeak) { var p2 = dep.packageConstraint.package; logic.require(Logic.implies(pvVar(p, v), p2)); } @@ -711,7 +722,7 @@ CS.Solver.prototype._getAnswer = function (options) { // generate constraints -- but technically don't enforce them, because // we haven't forced the conflictVars to be false Profile.time("generate constraints", function () { - _.each(analysis.constraints, function (c) { + analysis.constraints.forEach(function (c) { // We logically require that EITHER a constraint is marked as a // conflict OR it comes from a package version that is not selected // OR its constraint formula must be true. @@ -719,8 +730,8 @@ CS.Solver.prototype._getAnswer = function (options) { // then a version of it that satisfies our constraint must be true.) logic.require( Logic.or(c.conflictVar, - c.fromVar ? Logic.not(c.fromVar) : [], - self.getConstraintFormula(c.toPackage, c.vConstraint))); + c.fromVar ? Logic.not(c.fromVar) : [], + self.getConstraintFormula(c.toPackage, c.vConstraint))); }); }); @@ -754,7 +765,7 @@ CS.Solver.prototype._getAnswer = function (options) { // initial solution before asking the solver if it's possible to // not use these packages. Profile.time("forbid packages with no matching versions", function () { - _.each(analysis.packagesWithNoAllowedVersions, function (constrs, p) { + Object.entries(analysis.packagesWithNoAllowedVersions).forEach(function ([p, constrs]) { var newSolution = logic.solveAssuming(Logic.not(p)); if (newSolution) { self.setSolution(newSolution); @@ -762,9 +773,9 @@ CS.Solver.prototype._getAnswer = function (options) { } else { var error = 'No version of ' + p + ' satisfies all constraints: ' + - _.map(constrs, function (constr) { - return '@' + constr.constraintString; - }).join(', '); + constrs.map(function (constr) { + return '@' + constr.constraintString; + }).join(', '); error += '\n' + self.listConstraintsOnPackage(p); self.errors.push(error); } @@ -776,7 +787,7 @@ CS.Solver.prototype._getAnswer = function (options) { // than 0, we'll throw an error later, after we apply the constraints // and the cost function, so that we can explain the problem to the // user in a convincing way. - self.minimize('unknown_packages', _.keys(analysis.unknownPackages)); + self.minimize('unknown_packages', Object.keys(analysis.unknownPackages)); // try not to set the conflictVar on any constraint. If the minimum // is greater than 0, we'll throw an error later, after we've run the @@ -784,12 +795,14 @@ CS.Solver.prototype._getAnswer = function (options) { // If there are conflicts, this minimization can be time-consuming // (several seconds or more). The strategy 'bottom-up' helps by // looking for solutions with few conflicts first. - self.minimize('conflicts', _.pluck(analysis.constraints, 'conflictVar'), - { strategy: 'bottom-up' }); + self.minimize('conflicts', analysis.constraints.map(function (constraint) { + return constraint.conflictVar + }), + { strategy: 'bottom-up' }); // Try not to use "unanticipated" prerelease versions self.minimize('unanticipated_prereleases', - analysis.unanticipatedPrereleases); + analysis.unanticipatedPrereleases); var previousRootSteps = self.getVersionDistanceSteps( 'previous_root', analysis.previousRootDepVersions); @@ -798,25 +811,25 @@ CS.Solver.prototype._getAnswer = function (options) { // the "previous_root_major", "previous_root_minor", etc. steps var previousRootVersionParts = previousRootSteps.slice(1); - var toUpdate = _.filter(input.upgrade, function (p) { + var toUpdate = input.upgrade.filter(function (p) { return analysis.reachablePackages[p] === true; }); // make sure packages that are being updated can still count as // a previous_root for the purposes of previous_root_incompat Profile.time("add terms to previous_root_incompat", function () { - _.each(toUpdate, function (p) { + toUpdate.forEach(function (p) { if (input.isRootDependency(p) && input.isInPreviousSolution(p)) { var parts = self.pricer.partitionVersions( self.getVersions(p), input.previousSolution[p]); - _.each(parts.older.concat(parts.higherMajor), function (v) { + parts.older.concat(parts.higherMajor).forEach(function (v) { previousRootIncompat.addTerm(pvVar(p, v), 1); }); } }); }); - if (! input.allowIncompatibleUpdate) { + if (!input.allowIncompatibleUpdate) { // Enforce that we don't make breaking changes to your root dependencies, // unless you pass --allow-incompatible-update. It will actually be enforced // farther down, but for now, we want to apply this constraint before handling @@ -836,20 +849,20 @@ CS.Solver.prototype._getAnswer = function (options) { self.minimize(previousRootVersionParts); - var otherPrevious = _.filter(_.map(input.previousSolution, function (v, p) { + var otherPrevious = Object.entries(input.previousSolution || []).map(function ([p, v]) { return new CS.PackageAndVersion(p, v); - }), function (pv) { + }).filter(function (pv) { var p = pv.package; return analysis.reachablePackages[p] === true && - ! input.isRootDependency(p); + !input.isRootDependency(p); }); self.minimize(self.getVersionDistanceSteps( 'previous_indirect', otherPrevious, input.upgradeIndirectDepPatchVersions)); - var newRootDeps = _.filter(input.dependencies, function (p) { - return ! input.isInPreviousSolution(p); + var newRootDeps = input.dependencies.filter(function (p) { + return !input.isInPreviousSolution(p); }); self.minimize(self.getVersionCostSteps( @@ -876,10 +889,10 @@ CS.Solver.prototype._getAnswer = function (options) { // signal. In other words, the user might be better off with some tie-breaker // that looks only at the important packages anyway. Profile.time("lock down important versions", function () { - _.each(self.currentVersionMap(), function (v, pkg) { + Object.entries(self.currentVersionMap()).forEach(function ([pkg, v]) { if (input.isRootDependency(pkg) || - input.isInPreviousSolution(pkg) || - input.isUpgrading(pkg)) { + input.isInPreviousSolution(pkg) || + input.isUpgrading(pkg)) { logic.require(Logic.implies(pkg, pvVar(pkg, v))); } }); @@ -887,10 +900,10 @@ CS.Solver.prototype._getAnswer = function (options) { // new, indirect packages are the lowest priority var otherPackages = []; - _.each(_.keys(analysis.reachablePackages), function (p) { - if (! (input.isRootDependency(p) || - input.isInPreviousSolution(p) || - input.isUpgrading(p))) { + Object.keys(analysis.reachablePackages).forEach(function (p) { + if (!(input.isRootDependency(p) || + input.isInPreviousSolution(p) || + input.isUpgrading(p))) { otherPackages.push(p); } }); @@ -899,17 +912,17 @@ CS.Solver.prototype._getAnswer = function (options) { 'new_indirect', otherPackages, CS.VersionPricer.MODE_GRAVITY_WITH_PATCHES)); - self.minimize('total_packages', _.keys(analysis.reachablePackages)); + self.minimize('total_packages', Object.keys(analysis.reachablePackages)); // throw errors about unknown packages if (self.stepsByName['unknown_packages'].optimum > 0) { Profile.time("generate error for unknown packages", function () { - var unknownPackages = _.keys(analysis.unknownPackages); - var unknownPackagesNeeded = _.filter(unknownPackages, function (p) { + var unknownPackages = Object.keys(analysis.unknownPackages); + var unknownPackagesNeeded = unknownPackages.filter(function (p) { return self.solution.evaluate(p); }); - _.each(unknownPackagesNeeded, function (p) { - var requirers = _.filter(analysis.unknownPackages[p], function (pv) { + unknownPackagesNeeded.forEach(function (p) { + var requirers = analysis.unknownPackages[p].filter(function (pv) { return self.solution.evaluate(pv); }); var errorStr; @@ -920,7 +933,7 @@ CS.Solver.prototype._getAnswer = function (options) { } else { errorStr = 'unknown package: ' + p; } - _.each(requirers, function (pv) { + requirers.forEach(function (pv) { errorStr += '\nRequired by: ' + pv; }); self.errors.push(errorStr); @@ -934,36 +947,36 @@ CS.Solver.prototype._getAnswer = function (options) { self.throwConflicts(); } - if ((! input.allowIncompatibleUpdate) && - self.stepsByName['previous_root_incompat'].optimum > 0) { + if ((!input.allowIncompatibleUpdate) && + self.stepsByName['previous_root_incompat'].optimum > 0) { // we have some "incompatible root changes", where we needed to change a // version of a root dependency to a new version incompatible with the // original, but --allow-incompatible-update hasn't been passed in. // these are in the form of PackageAndVersion strings that we need. - var incompatRootChanges = _.keys(self.getStepContributions( + var incompatRootChanges = Object.keys(self.getStepContributions( self.stepsByName['previous_root_incompat'])); Profile.time("generate errors for incompatible root change", function () { var numActualErrors = 0; - _.each(incompatRootChanges, function (pvStr) { + incompatRootChanges.forEach(function (pvStr) { var pv = CS.PackageAndVersion.fromString(pvStr); // exclude packages with top-level equality constraints (added by user // or by the tool pinning a version) - if (! _.has(analysis.topLevelEqualityConstrainedPackages, pv.package)) { + if (!has(analysis.topLevelEqualityConstrainedPackages, pv.package)) { var prevVersion = input.previousSolution[pv.package]; self.errors.push( 'Potentially incompatible change required to ' + - 'top-level dependency: ' + - pvStr + ', was ' + prevVersion + '.\n' + - self.listConstraintsOnPackage(pv.package)); + 'top-level dependency: ' + + pvStr + ', was ' + prevVersion + '.\n' + + self.listConstraintsOnPackage(pv.package)); numActualErrors++; } }); if (numActualErrors) { self.errors.push( 'To allow potentially incompatible changes to top-level ' + - 'dependencies, you must pass --allow-incompatible-update ' + - 'on the command line.'); + 'dependencies, you must pass --allow-incompatible-update ' + + 'on the command line.'); } }); self.throwAnyErrors(); @@ -1001,13 +1014,13 @@ CS.Solver.prototype._getAnswer = function (options) { // Get a list of package-version variables that satisfy a given constraint. var getOkVersions = function (toPackage, vConstraint, targetVersions) { - return _.compact(_.map(targetVersions, function (v) { + return (targetVersions.map(function (v) { if (CS.isConstraintSatisfied(toPackage, vConstraint, v)) { return pvVar(toPackage, v); } else { return null; } - })); + })).filter(Boolean); }; // The CS.Solver constructor turns this into a memoized method. @@ -1031,7 +1044,7 @@ CS.Solver.prototype.listConstraintsOnPackage = function (pkg) { var result = 'Constraints on package "' + pkg + '":'; - _.each(constraints, function (c) { + constraints.forEach(function (c) { if (c.toPackage === pkg) { var paths; if (c.fromVar) { @@ -1040,7 +1053,7 @@ CS.Solver.prototype.listConstraintsOnPackage = function (pkg) { } else { paths = [['top level']]; } - _.each(paths, function (path) { + paths.forEach(function (path) { result += '\n* ' + (new PV.PackageConstraint( pkg, c.vConstraint.raw)) + ' <- ' + path.join(' <- '); }); @@ -1057,15 +1070,15 @@ CS.Solver.prototype.throwConflicts = function () { var constraints = self.analysis.constraints; self.Profile.time("generate error about conflicts", function () { - _.each(constraints, function (c) { + constraints.forEach(function (c) { // c is a CS.Solver.Constraint if (solution.evaluate(c.conflictVar)) { // skipped this constraint var possibleVersions = self.getVersions(c.toPackage); - var chosenVersion = _.find(possibleVersions, function (v) { + var chosenVersion = possibleVersions.find(function (v) { return solution.evaluate(pvVar(c.toPackage, v)); }); - if (! chosenVersion) { + if (!chosenVersion) { // this can't happen, because for a constraint to be a problem, // we must have chosen some version of the package it applies to! throw new Error("Internal error: Version not found"); @@ -1073,7 +1086,7 @@ CS.Solver.prototype.throwConflicts = function () { var error = ( 'Conflict: Constraint ' + (new PV.PackageConstraint( c.toPackage, c.vConstraint)) + - ' is not satisfied by ' + c.toPackage + ' ' + chosenVersion + '.'); + ' is not satisfied by ' + c.toPackage + ' ' + chosenVersion + '.'); error += '\n' + self.listConstraintsOnPackage(c.toPackage); @@ -1112,12 +1125,12 @@ CS.Solver.prototype.getPathsToPackageVersion = function (packageAndVersion) { var versionMap = self.currentVersionMap(); var hasDep = function (p1, p2) { // Include weak dependencies, because their constraints matter. - return _.has(cache.getDependencyMap(p1, versionMap[p1]), p2); + return has(cache.getDependencyMap(p1, versionMap[p1]), p2); }; - var allPackages = _.keys(versionMap); + var allPackages = Object.keys(versionMap); var getPaths = function (pv, _ignorePackageSet) { - if (! solution.evaluate(pv.toString())) { + if (!solution.evaluate(pv.toString())) { return []; } var pkg = pv.package; @@ -1126,20 +1139,20 @@ CS.Solver.prototype.getPathsToPackageVersion = function (packageAndVersion) { return [[pv]]; } - var newIgnorePackageSet = _.clone(_ignorePackageSet); + var newIgnorePackageSet = Object.assign({}, _ignorePackageSet); newIgnorePackageSet[pkg] = true; var paths = []; var shortestLength = null; - _.each(allPackages, function (p) { - if ((! _.has(newIgnorePackageSet, p)) && - solution.evaluate(p) && - hasDep(p, pkg)) { + allPackages.forEach(function (p) { + if ((!has(newIgnorePackageSet, p)) && + solution.evaluate(p) && + hasDep(p, pkg)) { var newPV = new CS.PackageAndVersion(p, versionMap[p]); - _.each(getPaths(newPV, newIgnorePackageSet), function (path) { + getPaths(newPV, newIgnorePackageSet).forEach(function (path) { var newPath = [pv].concat(path); - if ((! paths.length) || newPath.length < shortestLength) { + if ((!paths.length) || newPath.length < shortestLength) { paths.push(newPath); shortestLength = newPath.length; } @@ -1166,4 +1179,4 @@ CS.Solver.Constraint = function (fromVar, toPackage, vConstraint, conflictVar) { check(this.toPackage, String); // package name check(this.vConstraint, PV.VersionConstraint); check(this.conflictVar, String); -}; +}; \ No newline at end of file diff --git a/packages/constraint-solver/version-pricer-tests.js b/packages/constraint-solver/version-pricer-tests.js index e6a2429882..49bf9b5cc1 100644 --- a/packages/constraint-solver/version-pricer-tests.js +++ b/packages/constraint-solver/version-pricer-tests.js @@ -1,3 +1,6 @@ +const zip = Npm.require('lodash.zip'); +const isObject = Npm.require('lodash.isobject'); + var CS = ConstraintSolver; var PV = PackageVersion; @@ -7,24 +10,26 @@ Tinytest.add("constraint solver - version pricer", function (test) { var pricer = new CS.VersionPricer(); var testScanVersions = function (versions, mode, options, expected) { - if (options && _.isArray(options)) { + if (options && Array.isArray(options)) { expected = options; options = null; } var result, tuples; // Accepts either a mode like CS.VersionPricer.MODE_UPDATE or // an object that looks like `{ previous: version }` - if (_.isObject(mode) && mode.previous) { + if (isObject(mode) && mode.previous) { result = pricer.priceVersionsWithPrevious(versions, mode.previous); - tuples = _.zip(versions, result[0], result[1], result[2], result[3], + tuples = zip(versions, result[0], result[1], result[2], result[3], result[4]); } else { result = pricer.priceVersions(versions, mode, options); - tuples = _.zip(versions, result[0], result[1], result[2], result[3]); + tuples = zip(versions, result[0], result[1], result[2], result[3]); } test.equal(tuples.length, expected.length); - test.equal(_.pluck(tuples, 0), versions); - _.each(_.zip(tuples, expected), function (x) { + test.equal(tuples.map(function(x){ + return x[0] + }), versions); + zip(tuples, expected).forEach(function (x) { var tuple = x[0]; var expectedTuple = x[1]; if (typeof expectedTuple[0] !== 'string') { @@ -200,4 +205,4 @@ Tinytest.add("constraint solver - version pricer", function (test) { ["4.0.0", 1, 3, 0, 0, 1], ["4.0.0_1", 1, 3, 0, 0, 0]]); -}); +}); \ No newline at end of file diff --git a/packages/constraint-solver/version-pricer.js b/packages/constraint-solver/version-pricer.js index 7b94d868e8..5e7a9612ea 100644 --- a/packages/constraint-solver/version-pricer.js +++ b/packages/constraint-solver/version-pricer.js @@ -1,3 +1,5 @@ +const memoize = Npm.require('lodash.memoize'); + var CS = ConstraintSolver; var PV = PackageVersion; @@ -9,7 +11,7 @@ CS.VersionPricer = function () { // // The VersionPricer instance stores a memoization table for // efficiency. - self.getVersionInfo = _.memoize(PV.parse); + self.getVersionInfo = memoize(PV.parse); }; CS.VersionPricer.MODE_UPDATE = 1;