Skip to content

Commit 26b7d57

Browse files
committed
JS: Parse preferred version directly
1 parent 85224aa commit 26b7d57

File tree

2 files changed

+26
-60
lines changed

2 files changed

+26
-60
lines changed

javascript/extractor/src/com/semmle/js/dependencies/DependencyResolver.java

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import java.util.concurrent.CompletableFuture;
1515
import java.util.concurrent.ExecutorService;
1616
import java.util.concurrent.Executors;
17+
import java.util.regex.Matcher;
18+
import java.util.regex.Pattern;
1719

1820
import com.google.gson.Gson;
1921
import com.semmle.js.dependencies.packument.PackageJson;
@@ -55,17 +57,34 @@ private void addConstraint(Constraint constraint) {
5557
}
5658
}
5759

60+
private static final Pattern semVerToken = Pattern.compile("[~^<>=|&-]+|\\d+(?:\\.[\\dx]+)+(?:-[\\w.-]*)?");
61+
5862
/**
5963
* Returns the first version number mentioned in the given constraints, excluding upper bounds such as `< 2.0.0`,
6064
* or `null` if no such version number was found.
6165
* <p>
6266
* To help ensure deterministic version resolution, we prefer the version mentioned in the constraint, rather than
6367
* the latest version satisfying the constraint (as the latter can change in time).
6468
*/
65-
private SemVer getPreferredVersionFromConstraints(List<VersionConstraint> constraints) {
66-
for (VersionConstraint constraint : constraints) {
67-
if (!constraint.getOperator().equals("<") && constraint.getVersion() != null) {
68-
return constraint.getVersion();
69+
public static SemVer getPreferredVersionFromVersionSpec(String versionSpec) {
70+
versionSpec = versionSpec.trim();
71+
boolean isFirst = true;
72+
Matcher m = semVerToken.matcher(versionSpec);
73+
while (m.find()) {
74+
if (isFirst && m.start() != 0) {
75+
return null; // Not a version range
76+
}
77+
isFirst = false;
78+
String text = m.group();
79+
if (text.equals("<")) {
80+
// Skip next token to ignore upper bound constraints like `< 2.0.0`.
81+
if (!m.find()) break;
82+
}
83+
if (text.charAt(0) >= '0' && text.charAt(0) <= '9') {
84+
SemVer semVer = SemVer.tryParse(text.replace("x", "0"));
85+
if (semVer != null) {
86+
return semVer;
87+
}
6988
}
7089
}
7190
return null;
@@ -103,8 +122,8 @@ private CompletableFuture<Void> fetchRelevantPackages(PackageJson pack, int dept
103122
if (packagesInRepo.contains(targetName)) {
104123
return;
105124
}
106-
List<VersionConstraint> constraints = VersionConstraint.parseVersionConstraints(targetVersions);
107-
SemVer preferredVersion = getPreferredVersionFromConstraints(constraints);
125+
SemVer preferredVersion = getPreferredVersionFromVersionSpec(targetVersions);
126+
System.out.println("Prefer " + preferredVersion + " from " + targetVersions);
108127
if (preferredVersion == null) return;
109128
futures.add(fetcher.getPackument(targetName).exceptionally(ex -> null).thenCompose(targetPackument -> {
110129
if (targetPackument == null) {
@@ -198,7 +217,7 @@ public CompletableFuture<Void> installDependencies(PackageJson rootPackage, Path
198217
});
199218
}
200219

201-
/** Entry point which installs dependencies from a given `package.json`, used for testing andbenchmarking. */
220+
/** Entry point which installs dependencies from a given `package.json`, used for testing and benchmarking. */
202221
public static void main(String[] args) throws IOException {
203222
ExecutorService executors = Executors.newFixedThreadPool(50);
204223
try {

javascript/extractor/src/com/semmle/js/dependencies/VersionConstraint.java

Lines changed: 0 additions & 53 deletions
This file was deleted.

0 commit comments

Comments
 (0)