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,361 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getPackageVersion,
|
|
3
|
+
getVersions
|
|
4
|
+
} from "./registry.js";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
generateCandidates
|
|
8
|
+
} from "./candidates.js";
|
|
9
|
+
|
|
10
|
+
import semver from "semver";
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
export class Resolver {
|
|
14
|
+
|
|
15
|
+
constructor(rootDependencies) {
|
|
16
|
+
|
|
17
|
+
this.rootDependencies =
|
|
18
|
+
{ ...rootDependencies };
|
|
19
|
+
|
|
20
|
+
this.selected =
|
|
21
|
+
new Map();
|
|
22
|
+
|
|
23
|
+
this.constraints =
|
|
24
|
+
new Map();
|
|
25
|
+
|
|
26
|
+
this.conflicts =
|
|
27
|
+
new Set();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
async resolve() {
|
|
32
|
+
|
|
33
|
+
console.log(
|
|
34
|
+
"\nStarting resolution...\n"
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
await this.buildInitialState();
|
|
38
|
+
|
|
39
|
+
const result =
|
|
40
|
+
await this.search();
|
|
41
|
+
|
|
42
|
+
if (!result) {
|
|
43
|
+
|
|
44
|
+
throw new Error(
|
|
45
|
+
"Could not find a valid dependency tree."
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
async buildInitialState() {
|
|
54
|
+
|
|
55
|
+
for (
|
|
56
|
+
const [
|
|
57
|
+
name,
|
|
58
|
+
range
|
|
59
|
+
]
|
|
60
|
+
of Object.entries(
|
|
61
|
+
this.rootDependencies
|
|
62
|
+
)
|
|
63
|
+
) {
|
|
64
|
+
|
|
65
|
+
const versions =
|
|
66
|
+
await this.getValidVersions(
|
|
67
|
+
name,
|
|
68
|
+
range
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (versions.length === 0) {
|
|
72
|
+
|
|
73
|
+
throw new Error(
|
|
74
|
+
`No version of ${name} satisfies ${range}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await this.selectPackage(
|
|
79
|
+
name,
|
|
80
|
+
versions[0],
|
|
81
|
+
"ROOT"
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
async getValidVersions(
|
|
88
|
+
name,
|
|
89
|
+
range
|
|
90
|
+
) {
|
|
91
|
+
|
|
92
|
+
const versions =
|
|
93
|
+
await getVersions(name);
|
|
94
|
+
|
|
95
|
+
return versions
|
|
96
|
+
.filter(version =>
|
|
97
|
+
semver.satisfies(
|
|
98
|
+
version,
|
|
99
|
+
range
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
.sort(semver.rcompare);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
async selectPackage(
|
|
107
|
+
name,
|
|
108
|
+
version,
|
|
109
|
+
requestedBy
|
|
110
|
+
) {
|
|
111
|
+
|
|
112
|
+
this.selected.set(
|
|
113
|
+
name,
|
|
114
|
+
{
|
|
115
|
+
name,
|
|
116
|
+
version,
|
|
117
|
+
requestedBy
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const packageData =
|
|
122
|
+
await getPackageVersion(
|
|
123
|
+
name,
|
|
124
|
+
version
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
const dependencies =
|
|
128
|
+
packageData.dependencies || {};
|
|
129
|
+
|
|
130
|
+
for (
|
|
131
|
+
const [
|
|
132
|
+
dependencyName,
|
|
133
|
+
dependencyRange
|
|
134
|
+
]
|
|
135
|
+
of Object.entries(dependencies)
|
|
136
|
+
) {
|
|
137
|
+
|
|
138
|
+
this.addConstraint(
|
|
139
|
+
dependencyName,
|
|
140
|
+
dependencyRange,
|
|
141
|
+
`${name}@${version}`
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
addConstraint(
|
|
148
|
+
name,
|
|
149
|
+
range,
|
|
150
|
+
requester
|
|
151
|
+
) {
|
|
152
|
+
|
|
153
|
+
if (!this.constraints.has(name)) {
|
|
154
|
+
|
|
155
|
+
this.constraints.set(
|
|
156
|
+
name,
|
|
157
|
+
[]
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
this.constraints
|
|
162
|
+
.get(name)
|
|
163
|
+
.push({
|
|
164
|
+
requester,
|
|
165
|
+
range
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
this.checkConflict(name);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
checkConflict(name) {
|
|
173
|
+
|
|
174
|
+
const requirements =
|
|
175
|
+
this.constraints.get(name);
|
|
176
|
+
|
|
177
|
+
if (!requirements) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
for (
|
|
182
|
+
let i = 0;
|
|
183
|
+
i < requirements.length;
|
|
184
|
+
i++
|
|
185
|
+
) {
|
|
186
|
+
|
|
187
|
+
for (
|
|
188
|
+
let j = i + 1;
|
|
189
|
+
j < requirements.length;
|
|
190
|
+
j++
|
|
191
|
+
) {
|
|
192
|
+
|
|
193
|
+
if (
|
|
194
|
+
!semver.intersects(
|
|
195
|
+
requirements[i].range,
|
|
196
|
+
requirements[j].range
|
|
197
|
+
)
|
|
198
|
+
) {
|
|
199
|
+
|
|
200
|
+
this.conflicts.add(name);
|
|
201
|
+
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
this.conflicts.delete(name);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
getFirstConflict() {
|
|
212
|
+
|
|
213
|
+
for (
|
|
214
|
+
const packageName
|
|
215
|
+
of this.conflicts
|
|
216
|
+
) {
|
|
217
|
+
|
|
218
|
+
return {
|
|
219
|
+
packageName,
|
|
220
|
+
|
|
221
|
+
constraints:
|
|
222
|
+
this.constraints.get(
|
|
223
|
+
packageName
|
|
224
|
+
)
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
async search() {
|
|
233
|
+
|
|
234
|
+
const conflict =
|
|
235
|
+
this.getFirstConflict();
|
|
236
|
+
|
|
237
|
+
if (!conflict) {
|
|
238
|
+
|
|
239
|
+
console.log(
|
|
240
|
+
"\n[SUCCESS] Valid dependency tree found."
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
return new Map(
|
|
244
|
+
this.selected
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
console.log(
|
|
249
|
+
`\n[CONFLICT] ${conflict.packageName}`
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
const candidates =
|
|
253
|
+
await generateCandidates(
|
|
254
|
+
conflict
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
for (
|
|
258
|
+
const candidate
|
|
259
|
+
of candidates
|
|
260
|
+
) {
|
|
261
|
+
|
|
262
|
+
console.log(
|
|
263
|
+
`Trying ${candidate.packageName}` +
|
|
264
|
+
`@${candidate.newVersion}`
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
const snapshot =
|
|
268
|
+
this.createSnapshot();
|
|
269
|
+
|
|
270
|
+
try {
|
|
271
|
+
|
|
272
|
+
await this.selectPackage(
|
|
273
|
+
candidate.packageName,
|
|
274
|
+
candidate.newVersion,
|
|
275
|
+
"RESOLUTION"
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
const result =
|
|
279
|
+
await this.search();
|
|
280
|
+
|
|
281
|
+
if (result) {
|
|
282
|
+
return result;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
} catch (error) {
|
|
286
|
+
|
|
287
|
+
console.log(
|
|
288
|
+
error.message
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
this.restoreSnapshot(
|
|
293
|
+
snapshot
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
console.log(
|
|
297
|
+
"[BACKTRACKING] Backtracking..."
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
createSnapshot() {
|
|
306
|
+
|
|
307
|
+
return {
|
|
308
|
+
selected:
|
|
309
|
+
new Map(
|
|
310
|
+
this.selected
|
|
311
|
+
),
|
|
312
|
+
|
|
313
|
+
constraints:
|
|
314
|
+
new Map(
|
|
315
|
+
[...this.constraints].map(
|
|
316
|
+
([name, values]) => [
|
|
317
|
+
name,
|
|
318
|
+
values.map(
|
|
319
|
+
value => ({
|
|
320
|
+
...value
|
|
321
|
+
})
|
|
322
|
+
)
|
|
323
|
+
]
|
|
324
|
+
)
|
|
325
|
+
),
|
|
326
|
+
|
|
327
|
+
conflicts:
|
|
328
|
+
new Set(
|
|
329
|
+
this.conflicts
|
|
330
|
+
)
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
restoreSnapshot(snapshot) {
|
|
336
|
+
|
|
337
|
+
this.selected =
|
|
338
|
+
new Map(
|
|
339
|
+
snapshot.selected
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
this.constraints =
|
|
343
|
+
new Map(
|
|
344
|
+
[...snapshot.constraints].map(
|
|
345
|
+
([name, values]) => [
|
|
346
|
+
name,
|
|
347
|
+
values.map(
|
|
348
|
+
value => ({
|
|
349
|
+
...value
|
|
350
|
+
})
|
|
351
|
+
)
|
|
352
|
+
]
|
|
353
|
+
)
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
this.conflicts =
|
|
357
|
+
new Set(
|
|
358
|
+
snapshot.conflicts
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
}
|