node-dep-resolver 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +55 -0
- package/package.json +39 -0
- package/src/base/candidate/CandidateClass.js +20 -0
- package/src/base/candidate/methods/generateCandidate.js +73 -0
- package/src/base/conflicts/ConflictClass.js +12 -0
- package/src/base/constraints/ConstraintClass.js +27 -0
- package/src/base/constraints/methods/addConstraint.js +69 -0
- package/src/base/dependencies/DependencyClass.js +10 -0
- package/src/base/graph/GraphClass.js +20 -0
- package/src/base/graph/method/buildGraph.js +80 -0
- package/src/base/graph/method/printGraph.js +33 -0
- package/src/base/registry/RegistryClass.js +33 -0
- package/src/base/registry/methods/getPackageMetadata.js +18 -0
- package/src/base/registry/methods/getPackageVersion.js +13 -0
- package/src/base/registry/methods/getVersions.js +5 -0
- package/src/base/registry/methods/resolveVersion.js +17 -0
- package/src/base/resolver/ResolverClass.js +87 -0
- package/src/base/resolver/methods/addConstraint.js +12 -0
- package/src/base/resolver/methods/buildInitialState.js +11 -0
- package/src/base/resolver/methods/checkConflict.js +20 -0
- package/src/base/resolver/methods/createSnapshot.js +12 -0
- package/src/base/resolver/methods/getFirstConflict.js +10 -0
- package/src/base/resolver/methods/getValidVersions.js +9 -0
- package/src/base/resolver/methods/resolve.js +13 -0
- package/src/base/resolver/methods/restoreSnapshot.js +10 -0
- package/src/base/resolver/methods/search.js +39 -0
- package/src/base/resolver/methods/selectPackage.js +19 -0
- package/src/index.js +19 -0
- package/src/rudimentary/candidates.js +121 -0
- package/src/rudimentary/canditate.js +121 -0
- package/src/rudimentary/constraint.js +73 -0
- package/src/rudimentary/graph.js +124 -0
- package/src/rudimentary/registry.js +70 -0
- package/src/rudimentary/resolver.js +361 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export default async function resolve() {
|
|
2
|
+
console.log("\nStarting resolution...\n");
|
|
3
|
+
|
|
4
|
+
await this.buildInitialState();
|
|
5
|
+
|
|
6
|
+
const result = await this.search();
|
|
7
|
+
|
|
8
|
+
if (!result) {
|
|
9
|
+
throw new Error("Could not find a valid dependency tree.");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export default function restoreSnapshot(snapshot) {
|
|
2
|
+
this.selected = new Map(snapshot.selected);
|
|
3
|
+
this.constraints = new Map(
|
|
4
|
+
[...snapshot.constraints].map(([name, values]) => [
|
|
5
|
+
name,
|
|
6
|
+
values.map(value => ({ ...value }))
|
|
7
|
+
])
|
|
8
|
+
);
|
|
9
|
+
this.conflicts = new Set(snapshot.conflicts);
|
|
10
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export default async function search() {
|
|
2
|
+
const conflict = this.getFirstConflict();
|
|
3
|
+
|
|
4
|
+
if (!conflict) {
|
|
5
|
+
console.log("\n[SUCCESS] Valid dependency tree found.");
|
|
6
|
+
return new Map(this.selected);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
console.log(`\n[CONFLICT] ${conflict.packageName}`);
|
|
10
|
+
|
|
11
|
+
const candidates = await this.candidates.generateCandidates(conflict);
|
|
12
|
+
|
|
13
|
+
for (const candidate of candidates) {
|
|
14
|
+
console.log(`Trying ${candidate.packageName}@${candidate.newVersion}`);
|
|
15
|
+
|
|
16
|
+
const snapshot = this.createSnapshot();
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
await this.selectPackage(
|
|
20
|
+
candidate.packageName,
|
|
21
|
+
candidate.newVersion,
|
|
22
|
+
"RESOLUTION"
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const result = await this.search();
|
|
26
|
+
|
|
27
|
+
if (result) {
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.log(error.message);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this.restoreSnapshot(snapshot);
|
|
35
|
+
console.log("[BACKTRACKING] Backtracking...");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export default async function selectPackage(name, version, requestedBy) {
|
|
2
|
+
this.selected.set(name, {
|
|
3
|
+
name,
|
|
4
|
+
version,
|
|
5
|
+
requestedBy
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const packageData = await this.registry.getPackageVersion(name, version);
|
|
9
|
+
|
|
10
|
+
const dependencies = packageData.dependencies || {};
|
|
11
|
+
|
|
12
|
+
for (const [dependencyName, dependencyRange] of Object.entries(dependencies)) {
|
|
13
|
+
this.addConstraint(
|
|
14
|
+
dependencyName,
|
|
15
|
+
dependencyRange,
|
|
16
|
+
`${name}@${version}`
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import Resolver from "./base/resolver/ResolverClass.js";
|
|
2
|
+
import Registry from "./base/registry/RegistryClass.js";
|
|
3
|
+
import Graph from "./base/graph/GraphClass.js";
|
|
4
|
+
import Constraint from "./base/constraints/ConstraintClass.js";
|
|
5
|
+
import Candidates from "./base/candidate/CandidateClass.js";
|
|
6
|
+
import Dependency from "./base/dependencies/DependencyClass.js";
|
|
7
|
+
import Conflict from "./base/conflicts/ConflictClass.js";
|
|
8
|
+
|
|
9
|
+
export {
|
|
10
|
+
Resolver,
|
|
11
|
+
Registry,
|
|
12
|
+
Graph,
|
|
13
|
+
Constraint,
|
|
14
|
+
Candidates,
|
|
15
|
+
Dependency,
|
|
16
|
+
Conflict
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default Resolver;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
import {
|
|
3
|
+
getVersions,
|
|
4
|
+
getPackageVersion
|
|
5
|
+
} from "./registry.js";
|
|
6
|
+
|
|
7
|
+
export async function generateCandidates(
|
|
8
|
+
conflict
|
|
9
|
+
) {
|
|
10
|
+
const candidates = [];
|
|
11
|
+
|
|
12
|
+
const packageName =
|
|
13
|
+
conflict.packageName;
|
|
14
|
+
|
|
15
|
+
for (
|
|
16
|
+
const requirement
|
|
17
|
+
of conflict.constraints
|
|
18
|
+
) {
|
|
19
|
+
|
|
20
|
+
const requester =
|
|
21
|
+
requirement.requester;
|
|
22
|
+
|
|
23
|
+
const requesterParts =
|
|
24
|
+
requester.split("@");
|
|
25
|
+
|
|
26
|
+
const requesterName =
|
|
27
|
+
requesterParts[0];
|
|
28
|
+
|
|
29
|
+
const currentVersion =
|
|
30
|
+
requesterParts.slice(1).join("@");
|
|
31
|
+
|
|
32
|
+
console.log(
|
|
33
|
+
`\nLooking for alternatives for ${requester}`
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const versions =
|
|
37
|
+
await getVersions(requesterName);
|
|
38
|
+
|
|
39
|
+
for (const version of versions) {
|
|
40
|
+
|
|
41
|
+
// Don't try the version we're already using
|
|
42
|
+
if (version === currentVersion) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get this candidate's metadata
|
|
47
|
+
const packageData =
|
|
48
|
+
await getPackageVersion(
|
|
49
|
+
requesterName,
|
|
50
|
+
version
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const dependencies =
|
|
54
|
+
packageData.dependencies || {};
|
|
55
|
+
|
|
56
|
+
// Does this version still depend on
|
|
57
|
+
// the conflicting package?
|
|
58
|
+
if (!dependencies[packageName]) {
|
|
59
|
+
candidates.push({
|
|
60
|
+
packageName: requesterName,
|
|
61
|
+
oldVersion: currentVersion,
|
|
62
|
+
newVersion: version,
|
|
63
|
+
reason: `No longer depends on ${packageName}`
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const newRange =
|
|
70
|
+
dependencies[packageName];
|
|
71
|
+
|
|
72
|
+
// Does this new dependency range
|
|
73
|
+
// overlap with the other constraints?
|
|
74
|
+
let compatible = true;
|
|
75
|
+
|
|
76
|
+
for (
|
|
77
|
+
const other
|
|
78
|
+
of conflict.constraints
|
|
79
|
+
) {
|
|
80
|
+
|
|
81
|
+
if (
|
|
82
|
+
other.requester === requester
|
|
83
|
+
) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
!semver.intersects(
|
|
89
|
+
newRange,
|
|
90
|
+
other.range
|
|
91
|
+
)
|
|
92
|
+
) {
|
|
93
|
+
compatible = false;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (compatible) {
|
|
99
|
+
candidates.push({
|
|
100
|
+
packageName: requesterName,
|
|
101
|
+
oldVersion: currentVersion,
|
|
102
|
+
newVersion: version,
|
|
103
|
+
reason:
|
|
104
|
+
`${requesterName}@${version} requires ` +
|
|
105
|
+
`${packageName} ${newRange}`
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Prefer smaller version changes for now
|
|
112
|
+
candidates.sort((a, b) => {
|
|
113
|
+
|
|
114
|
+
return semver.compare(
|
|
115
|
+
a.newVersion,
|
|
116
|
+
a.oldVersion
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return candidates;
|
|
121
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
import {
|
|
3
|
+
getVersions,
|
|
4
|
+
getPackageVersion
|
|
5
|
+
} from "./registry.js";
|
|
6
|
+
|
|
7
|
+
export async function generateCandidates(
|
|
8
|
+
conflict
|
|
9
|
+
) {
|
|
10
|
+
const candidates = [];
|
|
11
|
+
|
|
12
|
+
const packageName =
|
|
13
|
+
conflict.packageName;
|
|
14
|
+
|
|
15
|
+
for (
|
|
16
|
+
const requirement
|
|
17
|
+
of conflict.constraints
|
|
18
|
+
) {
|
|
19
|
+
|
|
20
|
+
const requester =
|
|
21
|
+
requirement.requester;
|
|
22
|
+
|
|
23
|
+
const requesterParts =
|
|
24
|
+
requester.split("@");
|
|
25
|
+
|
|
26
|
+
const requesterName =
|
|
27
|
+
requesterParts[0];
|
|
28
|
+
|
|
29
|
+
const currentVersion =
|
|
30
|
+
requesterParts.slice(1).join("@");
|
|
31
|
+
|
|
32
|
+
console.log(
|
|
33
|
+
`\nLooking for alternatives for ${requester}`
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const versions =
|
|
37
|
+
await getVersions(requesterName);
|
|
38
|
+
|
|
39
|
+
for (const version of versions) {
|
|
40
|
+
|
|
41
|
+
// Don't try the version we're already using
|
|
42
|
+
if (version === currentVersion) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get this candidate's metadata
|
|
47
|
+
const packageData =
|
|
48
|
+
await getPackageVersion(
|
|
49
|
+
requesterName,
|
|
50
|
+
version
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const dependencies =
|
|
54
|
+
packageData.dependencies || {};
|
|
55
|
+
|
|
56
|
+
// Does this version still depend on
|
|
57
|
+
// the conflicting package?
|
|
58
|
+
if (!dependencies[packageName]) {
|
|
59
|
+
candidates.push({
|
|
60
|
+
packageName: requesterName,
|
|
61
|
+
oldVersion: currentVersion,
|
|
62
|
+
newVersion: version,
|
|
63
|
+
reason: `No longer depends on ${packageName}`
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const newRange =
|
|
70
|
+
dependencies[packageName];
|
|
71
|
+
|
|
72
|
+
// Does this new dependency range
|
|
73
|
+
// overlap with the other constraints?
|
|
74
|
+
let compatible = true;
|
|
75
|
+
|
|
76
|
+
for (
|
|
77
|
+
const other
|
|
78
|
+
of conflict.constraints
|
|
79
|
+
) {
|
|
80
|
+
|
|
81
|
+
if (
|
|
82
|
+
other.requester === requester
|
|
83
|
+
) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (
|
|
88
|
+
!semver.intersects(
|
|
89
|
+
newRange,
|
|
90
|
+
other.range
|
|
91
|
+
)
|
|
92
|
+
) {
|
|
93
|
+
compatible = false;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (compatible) {
|
|
99
|
+
candidates.push({
|
|
100
|
+
packageName: requesterName,
|
|
101
|
+
oldVersion: currentVersion,
|
|
102
|
+
newVersion: version,
|
|
103
|
+
reason:
|
|
104
|
+
`${requesterName}@${version} requires ` +
|
|
105
|
+
`${packageName} ${newRange}`
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Prefer smaller version changes for now
|
|
112
|
+
candidates.sort((a, b) => {
|
|
113
|
+
|
|
114
|
+
return semver.compare(
|
|
115
|
+
a.newVersion,
|
|
116
|
+
a.oldVersion
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return candidates;
|
|
121
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import semver from "semver";
|
|
2
|
+
|
|
3
|
+
const constraints = new Map();
|
|
4
|
+
|
|
5
|
+
const conflicts = new Set();
|
|
6
|
+
|
|
7
|
+
export function addConstraint(
|
|
8
|
+
dependencyName,
|
|
9
|
+
dependencyRange,
|
|
10
|
+
requestedBy
|
|
11
|
+
) {
|
|
12
|
+
|
|
13
|
+
if (!constraints.has(dependencyName)) {
|
|
14
|
+
|
|
15
|
+
constraints.set(
|
|
16
|
+
dependencyName,
|
|
17
|
+
{
|
|
18
|
+
constraints: [],
|
|
19
|
+
conflict: false
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const state =
|
|
25
|
+
constraints.get(dependencyName);
|
|
26
|
+
|
|
27
|
+
// Avoid duplicate constraints
|
|
28
|
+
const alreadyExists =
|
|
29
|
+
state.constraints.some(
|
|
30
|
+
item =>
|
|
31
|
+
item.requester === requestedBy &&
|
|
32
|
+
item.range === dependencyRange
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (alreadyExists) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check against existing constraints
|
|
40
|
+
for (
|
|
41
|
+
const existing
|
|
42
|
+
of state.constraints
|
|
43
|
+
) {
|
|
44
|
+
|
|
45
|
+
const compatible =
|
|
46
|
+
semver.intersects(
|
|
47
|
+
existing.range,
|
|
48
|
+
dependencyRange
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
if (!compatible) {
|
|
52
|
+
|
|
53
|
+
state.conflict = true;
|
|
54
|
+
|
|
55
|
+
conflicts.add(
|
|
56
|
+
dependencyName
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
state.constraints.push({
|
|
62
|
+
requester: requestedBy,
|
|
63
|
+
range: dependencyRange
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getConstraints() {
|
|
68
|
+
return constraints;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function getConflicts() {
|
|
72
|
+
return conflicts;
|
|
73
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
resolveVersion,
|
|
3
|
+
getPackageVersion
|
|
4
|
+
} from "./registry.js";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
addConstraint,
|
|
8
|
+
getConstraints,
|
|
9
|
+
getConflicts
|
|
10
|
+
} from "./constraint.js";
|
|
11
|
+
|
|
12
|
+
export const buildGraph = async (rootDependencies) => {
|
|
13
|
+
|
|
14
|
+
const graph = new Map();
|
|
15
|
+
|
|
16
|
+
async function visit(
|
|
17
|
+
name,
|
|
18
|
+
range,
|
|
19
|
+
requestedBy
|
|
20
|
+
) {
|
|
21
|
+
|
|
22
|
+
console.log(
|
|
23
|
+
`Resolving ${name} ${range}...`
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
// Record constraint immediately
|
|
27
|
+
addConstraint(
|
|
28
|
+
name,
|
|
29
|
+
range,
|
|
30
|
+
requestedBy
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const version =
|
|
34
|
+
await resolveVersion(
|
|
35
|
+
name,
|
|
36
|
+
range
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const key = `${name}@${version}`;
|
|
40
|
+
|
|
41
|
+
// Already processed?
|
|
42
|
+
if (graph.has(key)) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const packageData =
|
|
47
|
+
await getPackageVersion(
|
|
48
|
+
name,
|
|
49
|
+
version
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const node = {
|
|
53
|
+
name,
|
|
54
|
+
version,
|
|
55
|
+
dependencies:
|
|
56
|
+
packageData.dependencies || {}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
graph.set(key, node);
|
|
60
|
+
|
|
61
|
+
// Visit dependencies
|
|
62
|
+
for (
|
|
63
|
+
const [
|
|
64
|
+
dependencyName,
|
|
65
|
+
dependencyRange
|
|
66
|
+
]
|
|
67
|
+
of Object.entries(node.dependencies)
|
|
68
|
+
) {
|
|
69
|
+
|
|
70
|
+
await visit(
|
|
71
|
+
dependencyName,
|
|
72
|
+
dependencyRange,
|
|
73
|
+
`${name}@${version}`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Root dependencies
|
|
79
|
+
for (
|
|
80
|
+
const [
|
|
81
|
+
name,
|
|
82
|
+
range
|
|
83
|
+
]
|
|
84
|
+
of Object.entries(rootDependencies)
|
|
85
|
+
) {
|
|
86
|
+
|
|
87
|
+
await visit(
|
|
88
|
+
name,
|
|
89
|
+
range,
|
|
90
|
+
"ROOT"
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return graph;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export const printGraph = (graph) => {
|
|
98
|
+
for (const [key, node] of graph) {
|
|
99
|
+
console.log(key);
|
|
100
|
+
for (const [name, range] of Object.entries(node.dependencies)) {
|
|
101
|
+
console.log(` └── ${name} ${range}`);
|
|
102
|
+
}
|
|
103
|
+
console.log();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const constraints = getConstraints();
|
|
107
|
+
const conflicts = getConflicts();
|
|
108
|
+
|
|
109
|
+
if (constraints.size > 0) {
|
|
110
|
+
console.log("========== CONSTRAINTS & CONFLICTS ==========\n");
|
|
111
|
+
for (const [depName, state] of constraints) {
|
|
112
|
+
const status = state.conflict ? "CONFLICT" : "OK";
|
|
113
|
+
console.log(`${depName} [${status}]`);
|
|
114
|
+
for (const r of state.constraints) {
|
|
115
|
+
console.log(` └── requested ${r.range} by ${r.requester}`);
|
|
116
|
+
}
|
|
117
|
+
console.log();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (conflicts.size > 0) {
|
|
121
|
+
console.log(`[WARNING] Conflicts detected in ${conflicts.size} package(s): ${Array.from(conflicts).join(", ")}\n`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import semver from "semver";
|
|
3
|
+
//done
|
|
4
|
+
const REGISTRY_URL = "https://registry.npmjs.org";
|
|
5
|
+
//done
|
|
6
|
+
const metadataCache = new Map();
|
|
7
|
+
|
|
8
|
+
export async function getPackageMetadata(name) {
|
|
9
|
+
if (metadataCache.has(name)) {
|
|
10
|
+
return metadataCache.get(name);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const url =
|
|
14
|
+
`${REGISTRY_URL}/${encodeURIComponent(name)}`;
|
|
15
|
+
|
|
16
|
+
const response = await axios.get(url);
|
|
17
|
+
|
|
18
|
+
metadataCache.set(name, response.data);
|
|
19
|
+
|
|
20
|
+
return response.data;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function resolveVersion(name, range) {
|
|
24
|
+
const metadata =
|
|
25
|
+
await getPackageMetadata(name);
|
|
26
|
+
|
|
27
|
+
const versions =
|
|
28
|
+
Object.keys(metadata.versions);
|
|
29
|
+
|
|
30
|
+
const validVersions =
|
|
31
|
+
versions.filter(version =>
|
|
32
|
+
semver.satisfies(version, range)
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
if (validVersions.length === 0) {
|
|
36
|
+
throw new Error(
|
|
37
|
+
`No version of ${name} satisfies ${range}`
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
validVersions.sort(semver.rcompare);
|
|
42
|
+
|
|
43
|
+
return validVersions[0];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function getPackageVersion(
|
|
47
|
+
name,
|
|
48
|
+
version
|
|
49
|
+
) {
|
|
50
|
+
const metadata =
|
|
51
|
+
await getPackageMetadata(name);
|
|
52
|
+
|
|
53
|
+
const packageData =
|
|
54
|
+
metadata.versions[version];
|
|
55
|
+
|
|
56
|
+
if (!packageData) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`${name}@${version} does not exist`
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return packageData;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function getVersions(name) {
|
|
66
|
+
const metadata =
|
|
67
|
+
await getPackageMetadata(name);
|
|
68
|
+
|
|
69
|
+
return Object.keys(metadata.versions);
|
|
70
|
+
}
|