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.
Files changed (34) hide show
  1. package/bin/cli.js +55 -0
  2. package/package.json +39 -0
  3. package/src/base/candidate/CandidateClass.js +20 -0
  4. package/src/base/candidate/methods/generateCandidate.js +73 -0
  5. package/src/base/conflicts/ConflictClass.js +12 -0
  6. package/src/base/constraints/ConstraintClass.js +27 -0
  7. package/src/base/constraints/methods/addConstraint.js +69 -0
  8. package/src/base/dependencies/DependencyClass.js +10 -0
  9. package/src/base/graph/GraphClass.js +20 -0
  10. package/src/base/graph/method/buildGraph.js +80 -0
  11. package/src/base/graph/method/printGraph.js +33 -0
  12. package/src/base/registry/RegistryClass.js +33 -0
  13. package/src/base/registry/methods/getPackageMetadata.js +18 -0
  14. package/src/base/registry/methods/getPackageVersion.js +13 -0
  15. package/src/base/registry/methods/getVersions.js +5 -0
  16. package/src/base/registry/methods/resolveVersion.js +17 -0
  17. package/src/base/resolver/ResolverClass.js +87 -0
  18. package/src/base/resolver/methods/addConstraint.js +12 -0
  19. package/src/base/resolver/methods/buildInitialState.js +11 -0
  20. package/src/base/resolver/methods/checkConflict.js +20 -0
  21. package/src/base/resolver/methods/createSnapshot.js +12 -0
  22. package/src/base/resolver/methods/getFirstConflict.js +10 -0
  23. package/src/base/resolver/methods/getValidVersions.js +9 -0
  24. package/src/base/resolver/methods/resolve.js +13 -0
  25. package/src/base/resolver/methods/restoreSnapshot.js +10 -0
  26. package/src/base/resolver/methods/search.js +39 -0
  27. package/src/base/resolver/methods/selectPackage.js +19 -0
  28. package/src/index.js +19 -0
  29. package/src/rudimentary/candidates.js +121 -0
  30. package/src/rudimentary/canditate.js +121 -0
  31. package/src/rudimentary/constraint.js +73 -0
  32. package/src/rudimentary/graph.js +124 -0
  33. package/src/rudimentary/registry.js +70 -0
  34. 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
+ }