@antongolub/lockfile 0.0.0-snapshot.2 → 0.0.0-snapshot.21

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.
@@ -1,4 +1,7 @@
1
- // src/main/ts/util.ts
1
+ // src/main/ts/common.ts
2
+ import semver from "semver";
3
+ import { topo, traverseDeps } from "@semrel-extra/topo";
4
+ var getSources = (snapshot) => Object.values(snapshot).map((entry) => entry.source.id).filter(Boolean);
2
5
  var parseIntegrity = (integrity) => integrity ? integrity.split(" ").reduce((m, item) => {
3
6
  const [k, v] = item.split("-");
4
7
  if (k === "sha512" || k === "sha256" || k === "sha1" || k === "checksum") {
@@ -8,7 +11,63 @@ var parseIntegrity = (integrity) => integrity ? integrity.split(" ").reduce((m,
8
11
  }
9
12
  return m;
10
13
  }, {}) : {};
11
- var sortObject = (unordered) => Object.entries({ ...unordered }).sort(([a], [b]) => a > b ? 1 : -1).reduce(
14
+ var formatIntegrity = (hashes) => {
15
+ const checksum = hashes["checksum"];
16
+ if (checksum) {
17
+ return checksum;
18
+ }
19
+ return Object.entries(hashes).map(([k, v]) => `${k}-${v}`).join(" ");
20
+ };
21
+ var parseTarballUrl = (resolution) => {
22
+ const [tgz, br, _name, org, ...rest] = resolution.split("/").reverse();
23
+ if (br !== "-") {
24
+ return null;
25
+ }
26
+ const hasScope = org[0] === "@";
27
+ const name = hasScope ? `${org}/${_name}` : _name;
28
+ const id = tgz.slice(_name.length + 1, tgz.lastIndexOf(".tgz"));
29
+ return {
30
+ type: "npm",
31
+ name,
32
+ id,
33
+ registry: rest.reverse().join("/") + (hasScope ? "" : "/" + org),
34
+ hash: tgz.slice((tgz + "#").indexOf("#"))
35
+ };
36
+ };
37
+ var formatTarballUrl = (name, version6, registry = "https://registry.npmjs.org", hash = "") => `${registry}/${name}/-/${name.slice(name.indexOf("/") + 1)}-${version6}.tgz${hash}`;
38
+ var gitProtocols = ["git", "git+ssh", "git+http", "git+https", "git+file"];
39
+ var refProtocols = ["npm", "github", "workspace", "semver", "tag", "patch", "link", "portal", "file", ...gitProtocols];
40
+ var normalizeDeps = (deps) => processDeps(deps, normalizeReference);
41
+ var processDeps = (deps, formatter = (v) => v, opts = {}) => deps && Object.entries(deps).reduce((m, [k, v]) => {
42
+ m[k] = formatter(v + "", opts);
43
+ return m;
44
+ }, {});
45
+ var normalizeReference = (ref) => {
46
+ if (refProtocols.some((p) => ref.startsWith(p + ":"))) {
47
+ return ref;
48
+ }
49
+ if (semver.validRange(ref)) {
50
+ return "semver:" + ref;
51
+ }
52
+ if (ref.includes(".git")) {
53
+ return "git:" + ref;
54
+ }
55
+ if (ref.includes("/")) {
56
+ return "github:" + ref;
57
+ }
58
+ return "tag:" + ref;
59
+ };
60
+ var referenceKeysSorter = (a, b) => {
61
+ const _a = a.includes("npm:");
62
+ const _b = b.includes("npm:");
63
+ return _a === _b ? 0 : +_b - +_a;
64
+ };
65
+
66
+ // src/main/ts/util.ts
67
+ import fs from "node:fs/promises";
68
+ import path from "node:path";
69
+ import * as process from "node:process";
70
+ var sortObject = (unordered, predicate = ([a], [b]) => a > b ? 1 : -1) => Object.entries({ ...unordered }).sort(predicate).reduce(
12
71
  (obj, [key, value]) => {
13
72
  obj[key] = value;
14
73
  return obj;
@@ -21,41 +80,170 @@ var flushObject = (obj) => {
21
80
  }
22
81
  return obj;
23
82
  };
83
+ var debug = Object.assign((...chunks) => {
84
+ if (!debug.enable)
85
+ return;
86
+ console.log(...chunks);
87
+ }, {
88
+ enable: process.env.DEBUG,
89
+ json(data, name = `debug-${Math.random().toString(16).slice(2)}.json`, base = path.resolve(process.cwd(), "temp")) {
90
+ if (!this.enable)
91
+ return;
92
+ if (typeof data === "string") {
93
+ this.json(name, data);
94
+ return;
95
+ }
96
+ const _data = typeof data === "function" ? data() : data;
97
+ fs.writeFile(path.resolve(base, name), JSON.stringify(_data, null, 2));
98
+ }
99
+ });
100
+ var unique = (arr) => [...new Set(arr)];
24
101
 
25
- // src/main/ts/npm-1.ts
26
- import fs from "fs";
27
- var parse = async (lockfile, pkg) => {
28
- const lf = await JSON.parse(lockfile);
29
- const manifest = await JSON.parse(pkg);
30
- const workspaces = {
31
- "": {
32
- name: manifest.name,
33
- path: ".",
34
- manifest
102
+ // src/main/ts/analyze.ts
103
+ var getDeps = (entry) => {
104
+ if (!getDeps.cache.has(entry)) {
105
+ getDeps.cache.set(entry, {
106
+ ...sortObject(entry.dependencies || {}),
107
+ ...sortObject({ ...entry.devDependencies, ...entry.optionalDependencies })
108
+ });
109
+ }
110
+ return getDeps.cache.get(entry);
111
+ };
112
+ getDeps.cache = /* @__PURE__ */ new WeakMap();
113
+ var walk = (ctx) => {
114
+ const { root, entry = root, prefix, depth = 0, parentId, idx, id = idx.getEntryId(entry), parents = [] } = ctx;
115
+ const key = (prefix ? prefix + "," : "") + entry.name;
116
+ if (id === void 0) {
117
+ throw new TypeError(`Invalid snapshot: ${key}`);
118
+ }
119
+ if (!idx.tree[key]) {
120
+ const chunks = key.split(",");
121
+ idx.tree[key] = {
122
+ key,
123
+ chunks,
124
+ id,
125
+ name: entry.name,
126
+ version: entry.version,
127
+ entry,
128
+ parents
129
+ };
130
+ if (root.dependencies?.[chunks[1]]) {
131
+ idx.prod.add(entry);
132
+ }
133
+ if (parentId !== void 0) {
134
+ idx.edges.push([parentId, id]);
135
+ return;
136
+ }
137
+ if (depth) {
138
+ return;
139
+ }
140
+ }
141
+ const stack = [];
142
+ const dependencies = getDeps(entry);
143
+ Object.entries(dependencies).forEach(([name, range]) => {
144
+ const _entry = idx.getEntryByRange(name, range);
145
+ if (!_entry) {
146
+ throw new Error(`inconsistent snapshot: ${name} ${range}`);
147
+ }
148
+ idx.bound(entry, _entry);
149
+ if (parents.includes(entry)) {
150
+ return;
151
+ }
152
+ const _ctx = { root, entry: _entry, prefix: key, depth: depth + 1, parentId: id, idx, parents: [...parents, entry] };
153
+ stack.push(_ctx);
154
+ walk(_ctx);
155
+ });
156
+ stack.forEach(walk);
157
+ };
158
+ var getId = (name, version6 = "") => name ? `${name}@${version6}` : "";
159
+ var analyze = (snapshot) => {
160
+ const entries = Object.values(snapshot);
161
+ const roots = entries.filter((e) => e.source.type === "workspace");
162
+ const prod = new Set(roots);
163
+ const deps = /* @__PURE__ */ new Map();
164
+ const edges = [];
165
+ const tree = {};
166
+ const rangeMap = /* @__PURE__ */ new Map();
167
+ const idx = {
168
+ snapshot,
169
+ roots,
170
+ edges,
171
+ tree,
172
+ prod,
173
+ entries,
174
+ bound(from, to) {
175
+ const deps2 = this.getEntryDeps(from);
176
+ if (deps2.includes(to)) {
177
+ return;
178
+ }
179
+ deps2.push(to);
180
+ },
181
+ getEntryId({ name, version: version6 }) {
182
+ return getId(name, version6);
183
+ },
184
+ getEntry(name, version6) {
185
+ return snapshot[name] || snapshot[getId(name, version6)];
186
+ },
187
+ getEntryByRange(name, range) {
188
+ const key = getId(name, range);
189
+ if (rangeMap.has(key)) {
190
+ return rangeMap.get(key);
191
+ }
192
+ const _ranges = [range, range.replace("semver:", "npm:"), range.replace("npm:", "semver:")];
193
+ const found = entries.find(({ name: _name, ranges }) => name === _name && _ranges.some(ranges.includes.bind(ranges)));
194
+ rangeMap.set(key, found);
195
+ return found;
196
+ },
197
+ getEntryDeps(entry) {
198
+ if (!deps.has(entry)) {
199
+ deps.set(entry, []);
200
+ }
201
+ return deps.get(entry);
35
202
  }
36
203
  };
37
- const entries = {
204
+ const now = Date.now();
205
+ roots.forEach((root) => {
206
+ const isRoot = root.source.id === ".";
207
+ if (isRoot && !root.manifest)
208
+ return;
209
+ walk({ root, idx, id: isRoot ? "" : void 0 });
210
+ });
211
+ debug("analyze duration=", Date.now() - now, "deptree size=", Object.keys(tree).length);
212
+ debug.json("deptree.json", Object.values(tree).map(({ parents, name }) => [...parents.map((p) => p.name).slice(1), name].join(",")));
213
+ return idx;
214
+ };
215
+
216
+ // src/main/ts/formats/npm-1.ts
217
+ var version = "npm-1";
218
+ var check = (lockfile) => lockfile.includes(' "lockfileVersion": 1');
219
+ var parse = (lockfile, pkg) => {
220
+ const lf = JSON.parse(lockfile);
221
+ const manifest = JSON.parse(pkg);
222
+ const snapshot = {
38
223
  "": {
39
224
  name: manifest.name,
40
225
  version: manifest.version,
41
- dependencies: {
42
- ...manifest.dependencies,
43
- ...manifest.devDependencies
44
- },
226
+ dependencies: manifest.dependencies,
227
+ devDependencies: manifest.devDependencies,
45
228
  hashes: {},
46
- ranges: []
229
+ source: {
230
+ type: "workspace",
231
+ id: "."
232
+ },
233
+ ranges: [],
234
+ manifest
47
235
  }
48
236
  };
49
237
  const getClosestVersion = (name, ...deps) => deps.find((dep) => dep[name])?.[name]?.version;
50
- const upsertEntry = (name, version, data = {}) => {
51
- const key = `${name}@${version}`;
52
- if (!entries[key]) {
53
- entries[key] = { name, version, ranges: [] };
238
+ const upsertEntry = (name, version6, data = {}) => {
239
+ const key = `${name}@${version6}`;
240
+ if (!snapshot[key]) {
241
+ snapshot[key] = { name, version: version6, ranges: [] };
54
242
  }
55
- return Object.assign(entries[key], data);
243
+ return Object.assign(snapshot[key], data);
56
244
  };
57
- const pushRange = (name, version, range) => {
58
- const entry = upsertEntry(name, version);
245
+ const pushRange = (name, version6, range) => {
246
+ const entry = upsertEntry(name, version6);
59
247
  if (!entry.ranges.includes(range)) {
60
248
  entry.ranges.push(range);
61
249
  entry.ranges.sort();
@@ -66,72 +254,37 @@ var parse = async (lockfile, pkg) => {
66
254
  pushRange(_name, _version, range);
67
255
  });
68
256
  const extractEntries = (deps, ...parents) => deps && Object.entries(deps).forEach(([name, entry]) => {
69
- const requires = entry.requires || entry.dependencies && Object.entries(entry.dependencies).reduce((m, [name2, { version }]) => {
70
- m[name2] = version;
257
+ const requires = entry.requires || entry.dependencies && Object.entries(entry.dependencies).reduce((m, [name2, { version: version6 }]) => {
258
+ m[name2] = version6;
71
259
  return m;
72
260
  }, {});
73
261
  upsertEntry(name, entry.version, {
74
262
  hashes: parseIntegrity(entry.integrity),
75
- dependencies: requires
263
+ dependencies: requires,
264
+ source: parseResolution(entry.resolved)
76
265
  });
77
266
  extractEntries(entry.dependencies, deps, ...parents);
78
267
  extractRanges(requires, entry.dependencies || {}, deps, ...parents);
79
268
  });
80
269
  extractEntries(lf.dependencies);
81
- extractRanges(entries[""].dependencies, lf.dependencies || {});
82
- return {
83
- format: "npm-1",
84
- entries: sortObject(entries),
85
- workspaces
86
- };
87
- };
88
- var formatIntegrity = (hashes) => Object.entries(hashes).map(([key, value]) => `${key}-${value}`).join(" ");
89
- var createIndex = () => {
90
- const prod = /* @__PURE__ */ new Set();
91
- const deps = /* @__PURE__ */ new Map();
92
- return {
93
- prod,
94
- deps,
95
- getDeps(entry) {
96
- if (!deps.has(entry)) {
97
- deps.set(entry, []);
98
- }
99
- return deps.get(entry);
100
- }
101
- };
270
+ extractRanges({
271
+ ...snapshot[""].dependencies,
272
+ ...snapshot[""].devDependencies
273
+ }, lf.dependencies || {});
274
+ debug.json("npm1-snapshot.json", snapshot);
275
+ return sortObject(snapshot);
102
276
  };
103
- var isProd = (manifest, name) => !!manifest.dependencies?.[name];
104
- var format = async (snap) => {
105
- const root = snap.workspaces[""].manifest;
106
- const entries = Object.values(snap.entries);
107
- const idx = createIndex();
108
- entries.forEach((entry) => {
109
- entry.dependencies && Object.entries(entry.dependencies).forEach(([_name, range]) => {
110
- const target = entries.find(({ name, ranges }) => name === _name && ranges.includes(range));
111
- if (target) {
112
- idx.getDeps(entry).push(target);
113
- }
114
- });
115
- });
116
- const deptree = [];
117
- const fillTree = (entry, chain = []) => {
118
- const deps = idx.getDeps(entry);
119
- deps.forEach((c) => isProd(root, chain[0]?.name || c.name) && idx.prod.add(c));
120
- deps.sort(
121
- (a, b) => idx.prod.has(a) && !idx.prod.has(b) ? -1 : idx.prod.has(b) && !idx.prod.has(a) ? 1 : a.name.localeCompare(b.name)
122
- );
123
- deps.forEach((dep) => deptree.push([...chain, dep]));
124
- deps.forEach((dep) => fillTree(dep, [...chain, dep]));
125
- };
126
- const getEntry = (name, version) => entries.find((e) => e.name === name && e.version === version);
127
- fillTree(getEntry(root.name, root.version));
277
+ var formatIntegrity2 = (hashes) => Object.entries(hashes).map(([key, value]) => `${key}-${value}`).join(" ");
278
+ var preformat = (idx) => {
279
+ const root = idx.snapshot[""].manifest;
280
+ const deptree = Object.values(idx.tree).slice(1).map(({ parents, entry }) => [...parents.slice(1), entry]);
281
+ debug.json("deptree-npm-1.json", deptree.map((entries) => entries.map((e) => e.name).join(",")));
128
282
  const formatNpm1LockfileEntry = (entry) => {
129
- const { name, version, hashes } = entry;
130
- const _name = name.slice(name.indexOf("/") + 1);
283
+ const { name, version: version6, hashes, source } = entry;
131
284
  const _entry = {
132
- version,
133
- resolved: `https://registry.npmjs.org/${name}/-/${_name}-${version}.tgz`,
134
- integrity: formatIntegrity(hashes)
285
+ version: version6,
286
+ resolved: formatResolution(source),
287
+ integrity: formatIntegrity2(hashes)
135
288
  };
136
289
  if (!idx.prod.has(entry)) {
137
290
  _entry.dev = true;
@@ -150,9 +303,9 @@ var format = async (snap) => {
150
303
  };
151
304
  const nmtree = lf;
152
305
  const nodes = [nmtree];
153
- const processEntry = (name, version, parents) => {
154
- const entry = getEntry(name, version);
155
- const deps = idx.getDeps(entry);
306
+ const processEntry = (name, version6, parents) => {
307
+ const entry = idx.getEntry(name, version6);
308
+ const deps = idx.getEntryDeps(entry);
156
309
  const queue = [];
157
310
  deps.forEach((e) => {
158
311
  const closestIndex = parents.findIndex((p) => p.dependencies?.[e.name]);
@@ -170,7 +323,7 @@ var format = async (snap) => {
170
323
  nodes.push(parent);
171
324
  queue.push([e.name, e.version, _parents]);
172
325
  });
173
- queue.forEach(([name2, version2, parents2]) => processEntry(name2, version2, parents2));
326
+ queue.forEach(([name2, version7, parents2]) => processEntry(name2, version7, parents2));
174
327
  };
175
328
  deptree.forEach((chain) => {
176
329
  const entry = chain[chain.length - 1];
@@ -184,25 +337,256 @@ var format = async (snap) => {
184
337
  sortObject(node.dependencies || {});
185
338
  if (node.requires) {
186
339
  const snap1 = Object.entries(node.requires).map(([name, range]) => `${name}@${range}`).join("");
187
- const snap2 = Object.entries(node.dependencies || {}).map(([name, { version }]) => `${name}@${version}`).join("");
340
+ const snap2 = Object.entries(node.dependencies || {}).map(([name, { version: version6 }]) => `${name}@${version6}`).join("");
188
341
  if (snap1 === snap2) {
189
342
  delete node.requires;
190
343
  }
191
344
  }
192
345
  });
193
- fs.writeFileSync("temp/test.json", JSON.stringify(lf, null, 2));
194
- fs.writeFileSync("temp/tree.json", JSON.stringify(
195
- deptree.map((c) => c.map((e) => `${e.name}@${e.version}`).join(" > ")),
196
- null,
197
- 2
198
- ));
199
- return JSON.stringify(lf, null, 2);
346
+ return lf;
347
+ };
348
+ var format = (snap) => JSON.stringify(preformat(analyze(snap)), null, 2);
349
+ var parseResolution = (input) => {
350
+ if (input.startsWith("github:")) {
351
+ return {
352
+ type: "github",
353
+ name: input.slice(7, -41),
354
+ id: input.slice(-40)
355
+ };
356
+ }
357
+ const npmResolution = parseTarballUrl(input);
358
+ if (!npmResolution)
359
+ throw new TypeError(`Unsupported resolution format: ${input}`);
360
+ return npmResolution;
361
+ };
362
+ var formatResolution = (source) => {
363
+ const { type, name, id, registry = "https://registry.npmjs.org" } = source;
364
+ if (type === "github") {
365
+ return `github:${name}#${id}`;
366
+ }
367
+ return formatTarballUrl(name, id, registry);
200
368
  };
201
369
 
202
- // src/main/ts/yarn-1.ts
370
+ // src/main/ts/formats/npm-3.ts
371
+ import semver2 from "semver";
372
+ var version2 = "npm-3";
373
+ var check2 = (lockfile) => lockfile.includes(' "lockfileVersion": 3');
374
+ var parse2 = (lockfile) => {
375
+ const lf = JSON.parse(lockfile);
376
+ const snapshot = parsePackages(lf.packages);
377
+ snapshot[""].manifest = lf.packages[""];
378
+ debug.json("npm3-snapshot.json", snapshot);
379
+ return snapshot;
380
+ };
381
+ var formatNmKey = (chunks) => `node_modules/` + chunks.join("/node_modules/");
382
+ var parsePackages = (packages) => {
383
+ const entries = {};
384
+ const getClosestPkg = (name, chain, entries2, _range) => {
385
+ const variants3 = [];
386
+ const range = _range?.startsWith("npm:") ? _range.slice(_range.lastIndexOf("@") + 1) : _range;
387
+ let s = 0;
388
+ while (s < chain.length) {
389
+ let l = chain.length + 1;
390
+ while (l--) {
391
+ const variant = formatNmKey([...chain.slice(s, l), name].filter(Boolean));
392
+ const entry = entries2[variant];
393
+ if (entry && (!entry.version || entry.version === range || semver2.satisfies(entry.version, range))) {
394
+ return [variant, entry];
395
+ }
396
+ variants3.push(variant);
397
+ }
398
+ s++;
399
+ }
400
+ throw new Error(`Malformed lockfile: ${name} ${range}
401
+ ${variants3.join("\n")}`);
402
+ };
403
+ const processPackage = (path2, pkg) => {
404
+ if ((pkg.link || path2 === "") && !pkg.name) {
405
+ return processPackage(path2, {
406
+ ...pkg,
407
+ ...packages[pkg.resolved]
408
+ });
409
+ }
410
+ const source = parseResolution2(pkg.resolved);
411
+ const isNpmAlias = path2.startsWith("node_modules/") && pkg.name;
412
+ const chain = path2 ? ("/" + path2).split("/node_modules/").filter(Boolean) : [""];
413
+ const name = !isNpmAlias && pkg.name || chain[chain.length - 1];
414
+ const version6 = pkg.version;
415
+ const id = path2 === "" ? path2 : getId(name, version6);
416
+ if (entries[id]) {
417
+ return entries[id];
418
+ }
419
+ entries[id] = {
420
+ name,
421
+ version: version6,
422
+ ranges: [],
423
+ hashes: parseIntegrity(pkg.integrity),
424
+ source,
425
+ dependencies: pkg.dependencies,
426
+ engines: pkg.engines,
427
+ funding: pkg.funding,
428
+ bin: pkg.bin,
429
+ devDependencies: pkg.devDependencies,
430
+ peerDependencies: pkg.peerDependencies,
431
+ optionalDependencies: pkg.optionalDependencies,
432
+ license: pkg.license
433
+ };
434
+ Object.entries(getDeps(entries[id])).forEach(([_name, range]) => {
435
+ const [_path, _entry] = getClosestPkg(_name, chain, packages, range);
436
+ const { ranges } = processPackage(_path, _entry);
437
+ if (!ranges.includes(range)) {
438
+ ranges.push(range);
439
+ ranges.sort();
440
+ }
441
+ });
442
+ return entries[id];
443
+ };
444
+ Object.entries(packages).forEach(([path2, entry]) => (path2.startsWith("node_modules/") || path2 === "") && processPackage(path2, entry));
445
+ return sortObject(entries);
446
+ };
447
+ var buildNmtree = (idx) => {
448
+ const snap = idx.snapshot;
449
+ const nmtree = Object.values(idx.tree).reduce((result, { key, id, chunks }) => {
450
+ const entry = snap[id];
451
+ if (!entry) {
452
+ throw new Error(`Malformed snapshot: ${id}`);
453
+ }
454
+ const grandparent = chunks[1];
455
+ const cl = chunks.length;
456
+ let l = 0;
457
+ while (l <= cl) {
458
+ const [name, ...parents] = [...chunks].reverse();
459
+ let i = 0;
460
+ while (i < parents.length) {
461
+ const __key = parents.slice(i, i + l).reverse();
462
+ const _key = [...__key, name];
463
+ const variant = formatNmKey(_key);
464
+ const found = result[variant];
465
+ if (found) {
466
+ if (found.entry === entry) {
467
+ return result;
468
+ }
469
+ } else {
470
+ const pEntry = result[formatNmKey(__key)]?.entry;
471
+ const ppEntry = idx.getEntry(idx.tree[chunks.slice(0, cl - i - l).join(",")]?.id);
472
+ if (__key.length && pEntry !== ppEntry) {
473
+ i++;
474
+ continue;
475
+ }
476
+ result[variant] = { entry, parent: grandparent };
477
+ return result;
478
+ }
479
+ i++;
480
+ }
481
+ l++;
482
+ }
483
+ if (entry.source.type === "workspace") {
484
+ result[formatNmKey([entry.name])] = { entry, parent: "" };
485
+ }
486
+ return result;
487
+ }, {});
488
+ debug.json("npm3-nmtree.json", nmtree);
489
+ return nmtree;
490
+ };
491
+ var preformat2 = (idx) => {
492
+ const snap = idx.snapshot;
493
+ const nmtree = buildNmtree(idx);
494
+ const manifest = snap[""].manifest;
495
+ const packages = sortObject(
496
+ Object.entries(nmtree).reduce((m, [k, { entry, parent }]) => {
497
+ if (entry.source.type === "workspace") {
498
+ if (entry.source.id === ".") {
499
+ m[""] = manifest;
500
+ return m;
501
+ }
502
+ m[`node_modules/${entry.name}`] = {
503
+ resolved: entry.source.id,
504
+ link: true
505
+ };
506
+ m[entry.source.id] = {
507
+ name: entry.name,
508
+ version: entry.version,
509
+ license: entry.license,
510
+ dependencies: entry.dependencies,
511
+ bin: entry.bin,
512
+ devDependencies: entry.devDependencies
513
+ };
514
+ return m;
515
+ }
516
+ m[k] = {
517
+ version: entry.version,
518
+ resolved: formatResolution2(entry.source),
519
+ integrity: formatIntegrity(entry.hashes)
520
+ };
521
+ if (!idx.prod.has(entry)) {
522
+ m[k].dev = true;
523
+ }
524
+ m[k].dependencies = entry.dependencies;
525
+ m[k].bin = entry.bin;
526
+ m[k].engines = entry.engines;
527
+ m[k].funding = entry.funding;
528
+ m[k].peerDependencies = entry.peerDependencies;
529
+ m[k].optionalDependencies = entry.optionalDependencies;
530
+ return m;
531
+ }, {})
532
+ );
533
+ return {
534
+ name: manifest.name,
535
+ version: manifest.version,
536
+ lockfileVersion: 3,
537
+ requires: true,
538
+ packages
539
+ };
540
+ };
541
+ var format2 = (snapshot) => JSON.stringify(preformat2(analyze(snapshot)), null, 2);
542
+ var parseResolution2 = (input) => {
543
+ if (!input?.includes("://")) {
544
+ return {
545
+ type: "workspace",
546
+ id: input || "."
547
+ };
548
+ }
549
+ if (input.startsWith("git+ssh://git@github.com/")) {
550
+ return {
551
+ name: input.slice(25, -45),
552
+ id: input.slice(-40),
553
+ type: "github"
554
+ };
555
+ }
556
+ const npmResolution = parseTarballUrl(input);
557
+ if (!npmResolution)
558
+ throw new TypeError(`Unsupported resolution format: ${input}`);
559
+ return npmResolution;
560
+ };
561
+ var formatResolution2 = ({ type, id, name, registry, hash }) => {
562
+ if (type === "github") {
563
+ return `git+ssh://git@github.com/${name}.git#${id}`;
564
+ }
565
+ return formatTarballUrl(name, id, registry, hash);
566
+ };
567
+
568
+ // src/main/ts/formats/npm-2.ts
569
+ var version3 = "npm-2";
570
+ var check3 = (lockfile) => lockfile.includes(' "lockfileVersion": 2');
571
+ var preformat3 = (idx) => {
572
+ const lfnpm1 = preformat(idx);
573
+ const lfnpm3 = preformat2(idx);
574
+ return {
575
+ name: lfnpm1.name,
576
+ version: lfnpm1.version,
577
+ lockfileVersion: 2,
578
+ requires: true,
579
+ packages: lfnpm3.packages,
580
+ dependencies: lfnpm1.dependencies
581
+ };
582
+ };
583
+ var format3 = (snapshot) => JSON.stringify(preformat3(analyze(snapshot)), null, 2);
584
+
585
+ // src/main/ts/formats/yarn-classic.ts
203
586
  import { load, dump } from "js-yaml";
204
587
  var kvEntryPattern = /^(\s+)"?([^"]+)"?\s"?([^"]+)"?$/;
205
- var check = (value) => value.includes("# yarn lockfile v1");
588
+ var version4 = "yarn-classic";
589
+ var check4 = (value) => value.includes("# yarn lockfile v1");
206
590
  var preparse = (value) => {
207
591
  const lines = value.split("\n");
208
592
  const _value = lines.map((line) => {
@@ -220,67 +604,88 @@ var preparse = (value) => {
220
604
  }, "").join("\n");
221
605
  return load(_value);
222
606
  };
223
- var parseIntegrity2 = (integrity) => integrity.split(" ").reduce((m, item) => {
224
- const [k, v] = item.split("-");
225
- if (k === "sha512" || k === "sha256" || k === "sha1" || k === "checksum") {
226
- m[k] = v;
227
- }
228
- return m;
229
- }, {});
230
- var parse2 = async (value) => {
231
- const raw = await preparse(value);
232
- const snapshot = {
233
- entries: {},
234
- workspaces: {},
235
- format: "yarn-1"
236
- };
607
+ var parse3 = (value, pkg) => {
608
+ const manifest = JSON.parse(pkg);
609
+ const raw = preparse(value);
610
+ const snapshot = {};
237
611
  Object.entries(raw).forEach((value2) => {
238
612
  const [_key, _entry] = value2;
613
+ const { version: version6, integrity, dependencies, optionalDependencies, resolved } = _entry;
614
+ const hashes = parseIntegrity(integrity);
615
+ const source = parseResolution3(resolved);
239
616
  const chunks = _key.split(", ");
240
- const ranges = chunks.map((r) => r.slice(r.lastIndexOf("@") + 1)).sort();
241
- const { version, integrity, dependencies, optionalDependencies, resolved: source } = _entry;
242
- const name = chunks[0].slice(0, chunks[0].lastIndexOf("@"));
243
- const key = `${name}@${version}`;
244
- const hashes = parseIntegrity2(integrity);
245
- snapshot.entries[key] = {
246
- name,
247
- version,
248
- ranges,
249
- hashes,
250
- dependencies,
251
- optionalDependencies,
252
- source
253
- };
617
+ const names = unique(chunks.map((c) => c.slice(0, c.indexOf("@", 1))));
618
+ for (const name of names) {
619
+ const ranges = chunks.filter((c) => c.startsWith(`${name}@`)).map((r) => r.slice(r.indexOf("@", 1) + 1)).sort();
620
+ const key = `${name}@${version6}`;
621
+ snapshot[key] = {
622
+ name,
623
+ version: version6,
624
+ ranges,
625
+ hashes,
626
+ dependencies,
627
+ optionalDependencies,
628
+ source
629
+ };
630
+ }
254
631
  });
632
+ snapshot[""] = {
633
+ name: manifest.name,
634
+ version: manifest.version,
635
+ ranges: [],
636
+ hashes: {},
637
+ source: {
638
+ type: "workspace",
639
+ id: "."
640
+ },
641
+ manifest,
642
+ dependencies: manifest.dependencies,
643
+ devDependencies: manifest.devDependencies,
644
+ optionalDependencies: manifest.optionalDependencies
645
+ };
646
+ debug.json("yarn-classic-snapshot.json", snapshot);
255
647
  return snapshot;
256
648
  };
257
- var preformat = (value) => {
649
+ var preformat4 = (idx) => {
650
+ const { snapshot } = idx;
258
651
  const lf = {};
259
- Object.values(value.entries).forEach((entry) => {
260
- const { name, version, ranges, hashes, dependencies, optionalDependencies, source } = entry;
261
- const key = ranges.map((r) => `${name}@${r}`).join(", ");
652
+ const rangemap = {};
653
+ Object.values(snapshot).forEach((entry) => {
654
+ const { name, version: version6, ranges, hashes, dependencies, optionalDependencies, source } = entry;
655
+ const resolved = formatResolution3(source);
656
+ const alias = rangemap[resolved];
262
657
  const integrity = Object.entries(hashes).map(([k, v]) => `${k}-${v}`).join(" ");
658
+ const keys = ranges.map((r) => `${name}@${r}`);
659
+ if (alias) {
660
+ keys.push(...alias.keys);
661
+ keys.sort(referenceKeysSorter);
662
+ delete lf[alias.key];
663
+ }
664
+ const key = keys.join(", ");
665
+ rangemap[resolved] = { keys, key, name };
263
666
  lf[key] = {
264
- version,
265
- resolved: source,
667
+ version: version6,
668
+ resolved,
266
669
  integrity,
267
670
  dependencies,
268
671
  optionalDependencies
269
672
  };
270
673
  });
674
+ delete lf[""];
271
675
  return lf;
272
676
  };
273
- var format2 = (value) => {
274
- const lf = preformat(value);
677
+ var format4 = (snapshot) => {
678
+ const lf = preformat4({ snapshot });
275
679
  const lines = dump(lf, {
276
680
  quotingType: '"',
277
681
  flowLevel: -1,
278
682
  lineWidth: -1,
279
- forceQuotes: true
683
+ forceQuotes: true,
684
+ noRefs: true
280
685
  }).split("\n");
281
686
  const _value = lines.map((line) => {
282
687
  if (line.length !== 0 && line.charAt(0) !== " ") {
283
- const chunks = line.slice(0, -1).replaceAll('"', "").split(", ").map((chunk) => chunk.startsWith("@") || chunk.includes(" ") ? `"${chunk}"` : chunk);
688
+ const chunks = line.slice(0, -1).replaceAll('"', "").split(", ").map((chunk) => chunk.startsWith("@") || chunk.includes(" ") || chunk.includes("npm:") ? `"${chunk}"` : chunk);
284
689
  return `
285
690
  ${chunks.join(", ")}:`;
286
691
  }
@@ -298,61 +703,116 @@ ${chunks.join(", ")}:`;
298
703
 
299
704
  ${_value}`;
300
705
  };
706
+ var parseResolution3 = (input) => {
707
+ if (input.startsWith("https://codeload.github.com/")) {
708
+ return {
709
+ type: "github",
710
+ name: input.slice(28, -48),
711
+ id: input.slice(-40)
712
+ };
713
+ }
714
+ const npmResolution = parseTarballUrl(input);
715
+ if (!npmResolution)
716
+ throw new TypeError(`Unsupported resolution format: ${input}`);
717
+ return npmResolution;
718
+ };
719
+ var formatResolution3 = ({ type, id, name = "", registry = "https://registry.yarnpkg.com", hash = "" }) => {
720
+ if (type === "github") {
721
+ return `https://codeload.github.com/${name}/tar.gz/${id}`;
722
+ }
723
+ return formatTarballUrl(name, id, registry, hash);
724
+ };
301
725
 
302
- // src/main/ts/yarn-5.ts
726
+ // src/main/ts/formats/yarn-berry.ts
303
727
  import { load as load2, dump as dump2 } from "js-yaml";
304
- var check2 = (value) => value.includes(`
728
+ var version5 = "yarn-berry";
729
+ var check5 = (value) => value.includes(`
305
730
  __metadata:
306
- version: 5
307
- `);
308
- var parse3 = async (lockfile, pkg) => {
309
- const snapshot = {
310
- entries: {},
311
- workspaces: {},
312
- format: "yarn-5"
313
- };
731
+ version:`);
732
+ var parse4 = (lockfile, pkg) => {
733
+ const manifest = JSON.parse(pkg);
734
+ const snapshot = {};
314
735
  const raw = load2(lockfile);
315
736
  delete raw.__metadata;
316
737
  Object.entries(raw).forEach((value) => {
317
738
  const [_key, _entry] = value;
739
+ const { version: version6, checksum, dependencies, dependenciesMeta, optionalDependencies, peerDependencies, peerDependenciesMeta, resolution, bin, conditions } = _entry;
318
740
  const chunks = _key.split(", ");
319
- const ranges = chunks.map((r) => r.slice(r.lastIndexOf("@") + 1)).sort();
320
- const { version, checksum, dependencies, dependenciesMeta, optionalDependencies, peerDependencies, peerDependenciesMeta, resolution: source, bin, conditions } = _entry;
321
- const name = chunks[0].slice(0, chunks[0].lastIndexOf("@"));
322
- const key = `${name}@${version}`;
323
- const hashes = parseIntegrity(checksum);
324
- snapshot.entries[key] = {
325
- name,
326
- version,
327
- ranges,
328
- hashes,
329
- dependencies,
330
- dependenciesMeta,
331
- optionalDependencies,
332
- peerDependencies,
333
- peerDependenciesMeta,
334
- source,
335
- bin,
336
- conditions
337
- };
741
+ const names = unique(chunks.map((c) => c.slice(0, c.indexOf("@", 1))));
742
+ for (const name of names) {
743
+ const key = `${name}@${version6}`;
744
+ if (_key.includes("#")) {
745
+ snapshot[key].patch = {
746
+ resolution,
747
+ refs: chunks,
748
+ checksum
749
+ };
750
+ return;
751
+ }
752
+ const ranges = chunks.filter((c) => c.startsWith(`${name}@`)).map((r) => r.slice(r.indexOf("@", 1) + 1)).map(normalizeReference);
753
+ const hashes = parseIntegrity(checksum);
754
+ const source = parseResolution4(resolution);
755
+ snapshot[key] = {
756
+ name,
757
+ version: version6,
758
+ ranges,
759
+ hashes,
760
+ source,
761
+ dependencies: normalizeDeps(dependencies),
762
+ dependenciesMeta,
763
+ optionalDependencies: normalizeDeps(optionalDependencies),
764
+ peerDependencies: normalizeDeps(peerDependencies),
765
+ peerDependenciesMeta,
766
+ bin,
767
+ conditions
768
+ };
769
+ if (source.type === "workspace") {
770
+ }
771
+ }
338
772
  });
773
+ snapshot[""] = {
774
+ name: manifest.name,
775
+ version: manifest.version,
776
+ ranges: [],
777
+ hashes: {},
778
+ source: {
779
+ type: "workspace",
780
+ id: "."
781
+ },
782
+ manifest,
783
+ dependencies: normalizeDeps(manifest.dependencies),
784
+ devDependencies: normalizeDeps(manifest.devDependencies),
785
+ optionalDependencies: normalizeDeps(manifest.optionalDependencies)
786
+ };
787
+ debug.json("yarn-berry-snapshot.json", snapshot);
339
788
  return snapshot;
340
789
  };
341
- var preformat2 = (value) => {
790
+ var preformat5 = (idx) => {
791
+ const { snapshot } = idx;
342
792
  const lf = {};
343
- Object.values(value.entries).forEach((entry) => {
344
- const { name, version, ranges, hashes: { checksum }, dependencies, dependenciesMeta, optionalDependencies, peerDependencies, peerDependenciesMeta, source, bin, conditions } = entry;
345
- const key = ranges.map((r) => `${name}@${r}`).join(", ");
346
- const isLocal = version === "0.0.0-use.local";
793
+ const rangemap = {};
794
+ Object.values(snapshot).forEach((entry) => {
795
+ const { name, version: version6, ranges, hashes: { checksum }, dependencies, dependenciesMeta, optionalDependencies, peerDependencies, peerDependenciesMeta, source, patch, bin, conditions } = entry;
796
+ const resolution = formatResolution4(source);
797
+ const alias = rangemap[resolution];
798
+ const isLocal = version6 === "0.0.0-use.local";
347
799
  const languageName = isLocal ? "unknown" : "node";
348
800
  const linkType = isLocal ? "soft" : "hard";
801
+ const keys = ranges.map((r) => `${name}@${formatReference(r, { semverAsNpm: true, isLocal })}`);
802
+ if (alias) {
803
+ keys.push(...alias.keys);
804
+ keys.sort(referenceKeysSorter);
805
+ delete lf[alias.key];
806
+ }
807
+ const key = keys.join(", ");
808
+ rangemap[resolution] = { keys, key, name };
349
809
  lf[key] = {
350
- version,
351
- resolution: source,
352
- dependencies,
810
+ version: version6,
811
+ resolution,
812
+ dependencies: formatDeps(dependencies),
353
813
  dependenciesMeta,
354
- optionalDependencies,
355
- peerDependencies,
814
+ optionalDependencies: formatDeps(optionalDependencies),
815
+ peerDependencies: formatDeps(peerDependencies),
356
816
  peerDependenciesMeta,
357
817
  bin,
358
818
  checksum,
@@ -360,21 +820,30 @@ var preformat2 = (value) => {
360
820
  languageName,
361
821
  linkType
362
822
  };
823
+ if (patch) {
824
+ lf[patch.refs.join(", ")] = {
825
+ ...lf[key],
826
+ resolution: patch.resolution,
827
+ checksum: patch.checksum
828
+ };
829
+ }
363
830
  });
364
- return lf;
831
+ delete lf[""];
832
+ return sortObject(lf);
365
833
  };
366
- var format3 = (value) => {
834
+ var format5 = (snapshot, { __metadata = {
835
+ version: 5,
836
+ cacheKey: 8
837
+ } } = {}) => {
367
838
  const lines = dump2({
368
- __metadata: {
369
- version: 5,
370
- cacheKey: 8
371
- },
372
- ...preformat2(value)
839
+ __metadata,
840
+ ...preformat5({ snapshot })
373
841
  }, {
374
842
  quotingType: '"',
375
843
  flowLevel: -1,
376
844
  lineWidth: -1,
377
- forceQuotes: false
845
+ forceQuotes: false,
846
+ noRefs: true
378
847
  }).split("\n").map((line) => {
379
848
  if (line === "__metadata:") {
380
849
  return `
@@ -394,30 +863,92 @@ ${line}`;
394
863
  # Manual changes might be lost - proceed with caution!
395
864
  ${_value}`;
396
865
  };
866
+ var formatReference = (input, opts = {}) => {
867
+ const colonPos = input.indexOf(":");
868
+ const protocol = input.slice(0, colonPos);
869
+ const ref = input.slice(colonPos + 1);
870
+ if (protocol === "git" || protocol === "tag") {
871
+ return ref;
872
+ }
873
+ if (protocol === "semver") {
874
+ return opts.semverAsNpm && !opts.isLocal ? "npm:" + ref : /^\d+$/.test(ref) ? +ref : ref;
875
+ }
876
+ return input;
877
+ };
878
+ var formatDeps = (deps, opts) => processDeps(deps, formatReference, opts);
879
+ var parseResolution4 = (input) => {
880
+ const colonPos = input.indexOf(":");
881
+ const atPos = input.indexOf("@", 1);
882
+ const name = input.slice(0, atPos);
883
+ if (colonPos === -1) {
884
+ return {
885
+ name,
886
+ id: input.slice(atPos + 1),
887
+ type: "npm"
888
+ };
889
+ }
890
+ if (input.includes("https://github.com")) {
891
+ return {
892
+ type: "github",
893
+ name: input.slice(atPos + 20, -52),
894
+ id: input.slice(-40),
895
+ alias: input.slice(0, input.indexOf("@", 1))
896
+ };
897
+ }
898
+ return {
899
+ name,
900
+ id: input.slice(colonPos + 1),
901
+ type: input.slice(atPos + 1, colonPos)
902
+ };
903
+ };
904
+ var formatResolution4 = ({ name, id, type = "npm", alias = name, hash }) => {
905
+ if (type === "github") {
906
+ return `${alias}@https://github.com/${name}.git#commit=${id}`;
907
+ }
908
+ return `${name}@${type === "semver" ? "" : type + ":"}${id}`;
909
+ };
397
910
 
398
- // src/main/ts/common.ts
399
- var getSources = (snapshot) => Object.values(snapshot.entries).map((entry) => entry.source).filter(Boolean);
400
-
401
- // src/main/ts/index.ts
402
- var foo = "bar";
403
- var parse4 = async (lockfile, pkg) => {
404
- if (check(lockfile)) {
405
- return parse2(lockfile);
911
+ // src/main/ts/parse.ts
912
+ var isPkgJson = (input) => input.startsWith("{") && input.includes('"name":');
913
+ var variants = [
914
+ [check, parse],
915
+ [check3, parse2],
916
+ [check2, parse2],
917
+ [check4, parse3],
918
+ [check5, parse4]
919
+ ];
920
+ var parse5 = (...inputs) => {
921
+ const [lockfile, ...pkgJsons] = inputs.map((input) => input.toString("utf8"));
922
+ const [, parser] = variants.find(([check6]) => check6(lockfile)) || [];
923
+ if (!parser) {
924
+ throw new TypeError("Unsupported lockfile format");
925
+ }
926
+ if (!pkgJsons.every(isPkgJson)) {
927
+ throw new TypeError("Invalid package json");
406
928
  }
407
- if (check2(lockfile)) {
408
- return parse3(lockfile, pkg);
929
+ return parser(lockfile, ...pkgJsons);
930
+ };
931
+
932
+ // src/main/ts/format.ts
933
+ var variants2 = [
934
+ [version, format],
935
+ [version3, format3],
936
+ [version2, format2],
937
+ [version4, format4],
938
+ [version5, format5]
939
+ ];
940
+ var format6 = (snapshot, version6, opts) => {
941
+ const [, formatter] = variants2.find(([_version]) => version6 === _version) || [];
942
+ if (!formatter) {
943
+ throw new TypeError(`Unsupported lockfile format: ${version6}`);
409
944
  }
410
- return parse(lockfile, pkg);
945
+ return formatter(snapshot, opts);
411
946
  };
412
947
  export {
413
- foo,
414
- format as formatNpm1,
415
- format2 as formatYarn1,
416
- format3 as formatYarn5,
948
+ analyze,
949
+ buildNmtree,
950
+ format6 as format,
417
951
  getSources,
418
- parse4 as parse,
419
- parse as parseNpm1,
420
- parse2 as parseYarn1,
421
- parse3 as parseYarn5
952
+ parse5 as parse
422
953
  };
423
954
  //# sourceMappingURL=index.js.map