reslop 0.2.3 → 0.2.5

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 (89) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/README.md +8 -4
  3. package/bin/reslop.js +4 -2
  4. package/lib/api.js +2 -1
  5. package/lib/capabilities.js +0 -4
  6. package/lib/cli.js +19 -10
  7. package/lib/clipboard.js +45 -4
  8. package/lib/deps-diff.js +61 -118
  9. package/lib/deps.js +166 -235
  10. package/lib/detect.js +4 -2
  11. package/lib/diff/align.js +2 -1
  12. package/lib/diff/diff.js +6 -3
  13. package/lib/diff/display.js +2 -1
  14. package/lib/diff/inline.js +68 -2
  15. package/lib/diff/patch.js +2 -1
  16. package/lib/diff/unit.js +15 -30
  17. package/lib/editor.js +91 -13
  18. package/lib/files.js +54 -27
  19. package/lib/git-branches.js +107 -154
  20. package/lib/git-deps.js +78 -155
  21. package/lib/git-worktree.js +508 -0
  22. package/lib/git.js +23 -580
  23. package/lib/github.js +9 -8
  24. package/lib/gitlab.js +5 -4
  25. package/lib/highlight/bash.js +2 -1
  26. package/lib/highlight/core.js +11 -0
  27. package/lib/highlight/css.js +2 -1
  28. package/lib/highlight/csv.js +2 -1
  29. package/lib/highlight/dot.js +3 -12
  30. package/lib/highlight/html.js +2 -1
  31. package/lib/highlight/json.js +2 -1
  32. package/lib/highlight/log.js +5 -11
  33. package/lib/highlight/txt.js +3 -12
  34. package/lib/highlight.js +2 -1
  35. package/lib/keys.js +22 -12
  36. package/lib/manifest.js +4 -6
  37. package/lib/npm-commands.js +82 -24
  38. package/lib/remote.js +21 -20
  39. package/lib/render/branches.js +9 -27
  40. package/lib/render/chrome.js +109 -35
  41. package/lib/render/commits.js +216 -216
  42. package/lib/render/diff.js +160 -47
  43. package/lib/render/files.js +9 -26
  44. package/lib/render/frame.js +97 -118
  45. package/lib/render/notes.js +74 -26
  46. package/lib/render/npm.js +104 -30
  47. package/lib/render/present.js +2 -1
  48. package/lib/render/primitives.js +128 -52
  49. package/lib/render/render.js +2 -1
  50. package/lib/render/unit.js +17 -11
  51. package/lib/report-model.js +6 -4
  52. package/lib/report-parse.js +8 -14
  53. package/lib/report-render.js +38 -21
  54. package/lib/report-run.js +12 -11
  55. package/lib/report-test.js +45 -51
  56. package/lib/report-tools.js +44 -25
  57. package/lib/review-merge.js +102 -131
  58. package/lib/review.js +69 -78
  59. package/lib/select.js +52 -0
  60. package/lib/session/actions.js +72 -87
  61. package/lib/session/branches.js +18 -52
  62. package/lib/session/change-actions.js +175 -147
  63. package/lib/session/commit.js +65 -61
  64. package/lib/session/compose.js +152 -83
  65. package/lib/session/dispatch.js +53 -46
  66. package/lib/session/edit-click.js +57 -0
  67. package/lib/session/files-pane.js +30 -51
  68. package/lib/session/items.js +73 -90
  69. package/lib/session/lifecycle.js +37 -98
  70. package/lib/session/load.js +52 -57
  71. package/lib/session/navigation.js +105 -95
  72. package/lib/session/npm.js +205 -71
  73. package/lib/session/ops.js +200 -45
  74. package/lib/session/pointer.js +33 -8
  75. package/lib/session/progress.js +9 -6
  76. package/lib/session/review.js +35 -53
  77. package/lib/session/tasks.js +292 -0
  78. package/lib/session/terminal.js +17 -19
  79. package/lib/session/unit.js +3 -4
  80. package/lib/session/update.js +76 -96
  81. package/lib/session/view.js +45 -16
  82. package/lib/session/watch.js +47 -27
  83. package/lib/session.js +66 -97
  84. package/lib/source.js +6 -3
  85. package/lib/update.js +5 -13
  86. package/lib/utilities.js +25 -3
  87. package/lib/wrap.js +18 -1
  88. package/package.json +1 -1
  89. package/lib/session/todos.js +0 -293
package/lib/deps.js CHANGED
@@ -2,8 +2,12 @@
2
2
 
3
3
  const fs = require('node:fs');
4
4
  const path = require('node:path');
5
- const { jsonParse, isHashObject } = require('metautil');
6
- const { itemPath } = require('./files.js');
5
+ const metautil = require('metautil');
6
+ const { jsonParse, isHashObject } = metautil;
7
+ const files = require('./files.js');
8
+ const { itemPath } = files;
9
+ const utilities = require('./utilities.js');
10
+ const { asText } = utilities;
7
11
  const manifest = require('./manifest.js');
8
12
  const { MANIFEST, LOCKFILE, SECTION_KEYS, depFileMeta, relOf } = manifest;
9
13
  const { listFilePath, readSections, lockEntries, lockPackageCount } = manifest;
@@ -73,8 +77,6 @@ const pkgHasExportEntry = (pkg) => {
73
77
  return Object.keys(exported).length > 0;
74
78
  };
75
79
 
76
- const isTypeKey = (key) => key === 'types' || key === 'typings';
77
-
78
80
  const isRuntimeFile = (value) => {
79
81
  if (typeof value !== 'string' || !value) return false;
80
82
  return !value.endsWith('.d.ts');
@@ -82,16 +84,11 @@ const isRuntimeFile = (value) => {
82
84
 
83
85
  const hasRuntimeExport = (value) => {
84
86
  if (isRuntimeFile(value)) return true;
85
- if (Array.isArray(value)) {
86
- for (const item of value) {
87
- if (hasRuntimeExport(item)) return true;
88
- }
89
- return false;
90
- }
87
+ if (Array.isArray(value)) return value.some(hasRuntimeExport);
91
88
  if (!value || typeof value !== 'object') return false;
92
89
  const keys = Object.keys(value);
93
90
  for (const key of keys) {
94
- if (isTypeKey(key)) continue;
91
+ if (key === 'types' || key === 'typings') continue;
95
92
  if (hasRuntimeExport(value[key])) return true;
96
93
  }
97
94
  return false;
@@ -220,14 +217,7 @@ const declaredDepNames = (root, pkgDir) => {
220
217
  return [];
221
218
  }
222
219
  const maps = readSections(jsonParse(text));
223
- let size = 0;
224
- for (const key of SECTION_KEYS) size += maps[key].size;
225
- const names = new Array(size);
226
- let i = 0;
227
- for (const key of SECTION_KEYS) {
228
- for (const name of maps[key].keys()) names[i++] = name;
229
- }
230
- return names;
220
+ return SECTION_KEYS.flatMap((key) => [...maps[key].keys()]);
231
221
  };
232
222
 
233
223
  const collectExportMeta = (root, extra = {}) => {
@@ -252,7 +242,7 @@ const viaNotes = (via, pkgName) => {
252
242
  const notes = [];
253
243
  for (const item of via) {
254
244
  if (!item || typeof item !== 'object') continue;
255
- const title = typeof item.title === 'string' ? item.title : '';
245
+ const title = asText(item.title);
256
246
  if (!title) continue;
257
247
  const hasName = typeof item.name === 'string' && item.name;
258
248
  const named = hasName ? item.name : pkgName;
@@ -283,32 +273,52 @@ const auditEntryNames = (key, entry) => {
283
273
  return names;
284
274
  };
285
275
 
286
- const keepHighestAudit = (audit, name, severity, fix, range, notes) => {
276
+ const uniqueTexts = (list) => [...new Set(list.filter(Boolean))];
277
+
278
+ const keepHighestAudit = (audit, found) => {
279
+ const { name, severity } = found;
287
280
  if (!name || !severity || severity === 'info') return;
288
- const titles = [];
289
- for (const note of notes) {
290
- if (note && !titles.includes(note)) titles.push(note);
291
- }
281
+ const titles = uniqueTexts(found.titles);
292
282
  const prev = audit.get(name);
293
283
  if (prev && severityRank(prev.severity) >= severityRank(severity)) {
294
- const merged = [...prev.titles];
295
- for (const note of titles) {
296
- if (!merged.includes(note)) merged.push(note);
297
- }
298
- const next = {
284
+ audit.set(name, {
299
285
  ...prev,
300
- titles: merged,
301
- fix: prev.fix || fix,
302
- range: prev.range || range,
303
- };
304
- audit.set(name, next);
286
+ titles: uniqueTexts([...prev.titles, ...titles]),
287
+ fix: prev.fix || found.fix,
288
+ range: prev.range || found.range,
289
+ });
305
290
  return;
306
291
  }
307
292
  const title = titles[0] || '';
308
- const next = { name, severity, title, titles, fix, range };
309
- next.fix ||= '';
310
- next.range ||= '';
311
- audit.set(name, next);
293
+ const fix = found.fix || '';
294
+ const range = found.range || '';
295
+ audit.set(name, { name, severity, title, titles, fix, range });
296
+ };
297
+
298
+ const isEntry = (value) => Boolean(value) && typeof value === 'object';
299
+
300
+ const vulnFindings = (vulns) => {
301
+ const found = [];
302
+ for (const [key, entry] of Object.entries(vulns)) {
303
+ if (!isEntry(entry)) continue;
304
+ const { severity } = entry;
305
+ const titles = viaNotes(entry.via, entry.name || key);
306
+ const fix = auditFix(entry);
307
+ const range = asText(entry.range);
308
+ for (const name of auditEntryNames(key, entry)) {
309
+ found.push({ name, severity, fix, range, titles });
310
+ }
311
+ }
312
+ return found;
313
+ };
314
+
315
+ const advisoryFinding = (entry) => {
316
+ const name = entry.module_name || entry.name;
317
+ const title = namedTitle(name, asText(entry.title));
318
+ const titles = title ? [title] : [];
319
+ const fix = auditFix(entry);
320
+ const range = asText(entry.range);
321
+ return { name, severity: entry.severity, fix, range, titles };
312
322
  };
313
323
 
314
324
  const parseAuditReport = (text) => {
@@ -316,36 +326,13 @@ const parseAuditReport = (text) => {
316
326
  if (!text || !`${text}`.trim()) return audit;
317
327
  const data = jsonParse(text);
318
328
  if (!isHashObject(data)) return audit;
319
- const vulns = data.vulnerabilities;
320
- if (vulns && typeof vulns === 'object') {
321
- for (const key of Object.keys(vulns)) {
322
- const entry = vulns[key];
323
- if (!entry || typeof entry !== 'object') continue;
324
- const severity = entry.severity;
325
- const names = auditEntryNames(key, entry);
326
- const pkgName = entry.name || key;
327
- const titles = viaNotes(entry.via, pkgName);
328
- const fix = auditFix(entry);
329
- const range = typeof entry.range === 'string' ? entry.range : '';
330
- for (const name of names) {
331
- keepHighestAudit(audit, name, severity, fix, range, titles);
332
- }
333
- }
334
- }
335
- const advisories = data.advisories;
336
- if (advisories && typeof advisories === 'object') {
337
- for (const entry of Object.values(advisories)) {
338
- if (!entry || typeof entry !== 'object') continue;
339
- const name = entry.module_name || entry.name;
340
- const severity = entry.severity;
341
- const raw = typeof entry.title === 'string' ? entry.title : '';
342
- const title = namedTitle(name, raw);
343
- const titles = title ? [title] : [];
344
- const fix = auditFix(entry);
345
- const range = typeof entry.range === 'string' ? entry.range : '';
346
- keepHighestAudit(audit, name, severity, fix, range, titles);
347
- }
329
+ const { vulnerabilities, advisories } = data;
330
+ const found = isEntry(vulnerabilities) ? vulnFindings(vulnerabilities) : [];
331
+ if (isEntry(advisories)) {
332
+ const listed = Object.values(advisories).filter(isEntry);
333
+ found.push(...listed.map(advisoryFinding));
348
334
  }
335
+ for (const entry of found) keepHighestAudit(audit, entry);
349
336
  return audit;
350
337
  };
351
338
 
@@ -357,11 +344,11 @@ const parseOutdatedReport = (text) => {
357
344
  for (const name of Object.keys(data)) {
358
345
  const entry = data[name];
359
346
  if (!entry || typeof entry !== 'object') continue;
360
- const current = typeof entry.current === 'string' ? entry.current : '';
361
- const wanted = typeof entry.wanted === 'string' ? entry.wanted : '';
362
- const latest = typeof entry.latest === 'string' ? entry.latest : '';
363
- const type = typeof entry.type === 'string' ? entry.type : '';
347
+ const wanted = asText(entry.wanted);
364
348
  if (!wanted) continue;
349
+ const current = asText(entry.current);
350
+ const latest = asText(entry.latest);
351
+ const type = asText(entry.type);
365
352
  outdated.set(name, { current, wanted, latest, type });
366
353
  }
367
354
  return outdated;
@@ -382,16 +369,7 @@ const markChanges = (changes, report, kind) => {
382
369
  });
383
370
  };
384
371
 
385
- const markAuditChanges = (changes, audit) =>
386
- markChanges(changes, audit, 'audit');
387
-
388
- const markOutdatedChanges = (changes, outdated) =>
389
- markChanges(changes, outdated, 'outdated');
390
-
391
- const depExports = (exportEntries, name) => {
392
- if (!exportEntries || !exportEntries.has(name)) return false;
393
- return exportEntries.get(name) === true;
394
- };
372
+ const depExports = (exportEntries, name) => exportEntries?.get(name) === true;
395
373
 
396
374
  const isAddedDep = (change) => {
397
375
  if (change.action !== 'added') return false;
@@ -411,131 +389,94 @@ const unusedChangeNames = (changes, used) => {
411
389
  return names;
412
390
  };
413
391
 
414
- const unusedDeclaredNames = (pkg, used) => {
415
- const names = [];
416
- if (!pkgHasExportEntry(pkg)) return names;
417
- if (!used || !used.size) return names;
392
+ const unusedDeclared = (pkg, used) => {
393
+ const found = [];
394
+ if (!pkgHasExportEntry(pkg) || !used?.size) return found;
418
395
  const maps = readSections(pkg);
419
396
  for (const section of SECTION_KEYS) {
420
397
  if (section === 'peerDependencies') continue;
421
- const keys = [...maps[section].keys()];
422
- keys.sort();
423
- for (const name of keys) {
424
- if (used.has(name)) continue;
425
- names.push(name);
398
+ const map = maps[section];
399
+ for (const name of [...map.keys()].sort()) {
400
+ if (!used.has(name)) found.push({ name, section, from: map.get(name) });
426
401
  }
427
402
  }
428
- return names;
403
+ return found;
429
404
  };
430
405
 
431
406
  const markUnusedChanges = (changes, used, pkg, exportEntries) => {
432
- if (!pkgHasExportEntry(pkg)) return changes;
433
- if (!used || !used.size) return changes;
434
- const { length } = changes;
435
- const marked = new Array(length);
436
- for (let i = 0; i < length; i++) {
437
- const change = changes[i];
438
- if (!isAddedDep(change) || used.has(change.name)) {
439
- marked[i] = change;
440
- continue;
441
- }
442
- if (!depExports(exportEntries, change.name)) {
443
- marked[i] = change;
444
- continue;
445
- }
446
- marked[i] = { ...change, unused: true, propose: true };
447
- }
448
- return marked;
407
+ if (!pkgHasExportEntry(pkg) || !used?.size) return changes;
408
+ return changes.map((change) => {
409
+ if (!isAddedDep(change) || used.has(change.name)) return change;
410
+ if (!depExports(exportEntries, change.name)) return change;
411
+ return { ...change, unused: true, propose: true };
412
+ });
449
413
  };
450
414
 
451
415
  const unusedDeclaredChanges = (pkg, used, exportEntries) => {
452
416
  const changes = [];
453
- if (!pkgHasExportEntry(pkg)) return changes;
454
- if (!used || !used.size) return changes;
455
- const maps = readSections(pkg);
456
417
  const taken = new Set();
457
- for (const section of SECTION_KEYS) {
458
- if (section === 'peerDependencies') continue;
459
- const map = maps[section];
460
- const names = [...map.keys()];
461
- names.sort();
462
- for (const name of names) {
463
- if (used.has(name)) continue;
464
- if (taken.has(name)) continue;
465
- if (!depExports(exportEntries, name)) continue;
466
- taken.add(name);
467
- const version = map.get(name);
468
- changes.push({
469
- name,
470
- section,
471
- action: 'removed',
472
- from: version,
473
- to: '',
474
- propose: true,
475
- unused: true,
476
- });
477
- }
418
+ for (const { name, section, from } of unusedDeclared(pkg, used)) {
419
+ if (taken.has(name) || !depExports(exportEntries, name)) continue;
420
+ taken.add(name);
421
+ const action = 'removed';
422
+ const to = '';
423
+ changes.push({
424
+ name,
425
+ section,
426
+ action,
427
+ from,
428
+ to,
429
+ propose: true,
430
+ unused: true,
431
+ });
478
432
  }
479
433
  return changes;
480
434
  };
481
435
 
436
+ const resolvedChange = (name, vul, resolved) => {
437
+ const from = resolved.get(name) || '';
438
+ if (!vul || !from) return null;
439
+ const to = proposedLockVersion(from, vul);
440
+ const section = 'resolved';
441
+ const action = 'vulnerable';
442
+ return { name, section, action, from, to, propose: true, audit: vul };
443
+ };
444
+
445
+ const declaredChange = (name, declared, out, vul) => {
446
+ const wanted = proposedWanted(out, vul);
447
+ if (!wanted && !vul) return null;
448
+ const from = declared.version;
449
+ const to = wanted ? applyWantedRange(from, wanted) : from;
450
+ if (to === from && !vul) return null;
451
+ const action = to === from ? 'vulnerable' : 'changed';
452
+ const { section } = declared;
453
+ const change = { name, section, action, from, to, propose: true };
454
+ if (out) change.outdated = out;
455
+ if (vul) change.audit = vul;
456
+ return change;
457
+ };
458
+
459
+ const mapKeys = (map) => (map ? [...map.keys()] : []);
460
+
482
461
  const buildProposedChanges = (pkg, outdated, audit, lock, options = {}) => {
483
- const used = options.used;
484
- const exportEntries = options.exportEntries;
485
- const names = new Set();
486
- if (outdated) {
487
- for (const name of outdated.keys()) names.add(name);
488
- }
489
- if (audit) {
490
- for (const name of audit.keys()) names.add(name);
491
- }
492
- const listed = [...names];
462
+ const listed = [...new Set([...mapKeys(outdated), ...mapKeys(audit)])];
493
463
  listed.sort();
494
464
  const resolved = lockEntries(lock);
495
- const unused = unusedDeclaredChanges(pkg, used, exportEntries);
496
- const taken = new Set();
497
- for (const change of unused) taken.add(change.name);
498
- const changes = [...unused];
465
+ const changes = unusedDeclaredChanges(
466
+ pkg,
467
+ options.used,
468
+ options.exportEntries,
469
+ );
470
+ const taken = new Set(changes.map((change) => change.name));
499
471
  for (const name of listed) {
500
472
  if (taken.has(name)) continue;
501
473
  const out = outdated ? outdated.get(name) : null;
502
474
  const vul = audit ? audit.get(name) : null;
503
- const type = out ? out.type : '';
504
- const declared = findDeclared(pkg, name, type);
505
- if (!declared) {
506
- if (!vul) continue;
507
- const version = resolved.get(name) || '';
508
- if (!version) continue;
509
- const to = proposedLockVersion(version, vul);
510
- changes.push({
511
- name,
512
- section: 'resolved',
513
- action: 'vulnerable',
514
- from: version,
515
- to,
516
- propose: true,
517
- audit: vul,
518
- });
519
- continue;
520
- }
521
- const wanted = proposedWanted(out, vul);
522
- if (!wanted && !vul) continue;
523
- let to = declared.version;
524
- if (wanted) to = applyWantedRange(declared.version, wanted);
525
- if (to === declared.version && !vul) continue;
526
- let action = 'changed';
527
- if (to === declared.version) action = 'vulnerable';
528
- const change = {
529
- name,
530
- section: declared.section,
531
- action,
532
- from: declared.version,
533
- to,
534
- propose: true,
535
- };
536
- if (out) change.outdated = out;
537
- if (vul) change.audit = vul;
538
- changes.push(change);
475
+ const declared = findDeclared(pkg, name, out ? out.type : '');
476
+ const change = declared
477
+ ? declaredChange(name, declared, out, vul)
478
+ : resolvedChange(name, vul, resolved);
479
+ if (change) changes.push(change);
539
480
  }
540
481
  return changes;
541
482
  };
@@ -551,18 +492,16 @@ const loadExportEntries = (names, extra = {}, pkgDir) => {
551
492
  if (!missing.length) return supplied ?? new Map();
552
493
  const found = collectExportEntries(extra.root, dir, missing);
553
494
  if (!supplied) return found;
554
- const merged = new Map(supplied);
555
- for (const name of found.keys()) merged.set(name, found.get(name));
556
- return merged;
495
+ return new Map([...supplied, ...found]);
557
496
  };
558
497
 
559
498
  const groupedSynthetics = (synthetic) => {
560
499
  const byPath = new Map();
561
- for (const key of synthetic.keys()) {
500
+ for (const [key, items] of synthetic) {
562
501
  const dir = key.slice(key.indexOf('\0') + 1);
563
502
  const rel = relOf(dir, MANIFEST);
564
503
  const list = byPath.get(rel) ?? [];
565
- for (const item of synthetic.get(key)) list.push(item);
504
+ for (const item of items) list.push(item);
566
505
  byPath.set(rel, list);
567
506
  }
568
507
  return byPath;
@@ -570,12 +509,10 @@ const groupedSynthetics = (synthetic) => {
570
509
 
571
510
  const spliceAtSlots = (out, synthetic, slot) => {
572
511
  const byPath = groupedSynthetics(synthetic);
573
- const inserts = new Array(byPath.size);
574
- let i = 0;
575
- for (const rel of byPath.keys()) {
576
- const at = slot.has(rel) ? slot.get(rel) : out.length;
577
- inserts[i++] = { at, items: byPath.get(rel) };
578
- }
512
+ const inserts = [...byPath].map(([rel, items]) => ({
513
+ at: slot.get(rel) ?? out.length,
514
+ items,
515
+ }));
579
516
  inserts.sort((left, right) => right.at - left.at);
580
517
  for (const insert of inserts) {
581
518
  out.splice(insert.at, 0, ...insert.items);
@@ -597,6 +534,30 @@ const insertAfterPath = (items, added, rel) => {
597
534
  return [...items.slice(0, at + 1), ...added, ...items.slice(at + 1)];
598
535
  };
599
536
 
537
+ const placeFolded = (items, { folded, synthetic, leftoverNames }) => {
538
+ const out = [];
539
+ const slot = new Map();
540
+ for (const item of items) {
541
+ const meta = depFileMeta(itemPath(item));
542
+ const pkgRel = meta ? relOf(meta.dir, MANIFEST) : '';
543
+ const key = meta ? `${item.origin}\0${meta.dir}` : '';
544
+ if (meta && synthetic.has(key) && !slot.has(pkgRel)) {
545
+ slot.set(pkgRel, out.length);
546
+ }
547
+ if (folded.has(item)) continue;
548
+ if (!meta || meta.kind !== 'manifest') {
549
+ out.push(item);
550
+ continue;
551
+ }
552
+ const names = leftoverNames.get(key);
553
+ const kept = names ? stripFoldedDepItem(item, names) : item;
554
+ if (!kept) continue;
555
+ out.push(kept);
556
+ slot.set(pkgRel, out.length);
557
+ }
558
+ return spliceAtSlots(out, synthetic, slot);
559
+ };
560
+
600
561
  const foldDepItems = (
601
562
  items,
602
563
  readSides = () => ({ oldText: '', newText: '' }),
@@ -610,56 +571,26 @@ const foldDepItems = (
610
571
  const folded = new Set();
611
572
  const synthetic = new Map();
612
573
  const leftoverNames = new Map();
613
- for (const key of groups.keys()) {
614
- const group = groups.get(key);
574
+ for (const [key, group] of groups) {
615
575
  const summary = summarizeGroup(group, readSides);
616
576
  const unusedNames = unusedChangeNames(summary.changes, usedNames);
617
577
  const exportEntries = loadExportEntries(unusedNames, extra, group.dir);
618
- const unused = markUnusedChanges(
619
- summary.changes,
620
- usedNames,
621
- summary.pkg,
622
- exportEntries,
623
- );
624
- const audited = markAuditChanges(unused, audit);
625
- const changes = markOutdatedChanges(audited, outdated);
578
+ const { pkg } = summary;
579
+ let changes = summary.changes;
580
+ changes = markUnusedChanges(changes, usedNames, pkg, exportEntries);
581
+ changes = markChanges(changes, audit, 'audit');
582
+ changes = markChanges(changes, outdated, 'outdated');
626
583
  const next = { ...summary, changes };
627
- leftoverNames.set(key, foldedDepNames(next.changes));
584
+ leftoverNames.set(key, foldedDepNames(changes));
628
585
  const taken = takeManifestItems(next);
629
- if (next.foldLock) {
630
- for (const item of next.lockItems) taken.push(item);
631
- }
632
- if (!taken.length && !next.changes.length) continue;
586
+ if (next.foldLock) taken.push(...next.lockItems);
587
+ if (!taken.length && !changes.length) continue;
633
588
  const made = makeDepItems(group.origin, group.items, taken, next);
634
589
  if (made.length) synthetic.set(key, made);
635
590
  for (const item of taken) folded.add(item);
636
591
  }
637
592
  if (!synthetic.size && !folded.size) return items;
638
- const out = [];
639
- const slot = new Map();
640
- for (const item of items) {
641
- const rel = itemPath(item);
642
- const meta = depFileMeta(rel);
643
- if (meta) {
644
- const pkgRel = relOf(meta.dir, MANIFEST);
645
- const key = `${item.origin}\0${meta.dir}`;
646
- if (synthetic.has(key) && !slot.has(pkgRel)) {
647
- slot.set(pkgRel, out.length);
648
- }
649
- }
650
- if (folded.has(item)) continue;
651
- if (meta && meta.kind === 'manifest') {
652
- const names = leftoverNames.get(`${item.origin}\0${meta.dir}`);
653
- const kept = names ? stripFoldedDepItem(item, names) : item;
654
- if (kept) {
655
- out.push(kept);
656
- slot.set(relOf(meta.dir, MANIFEST), out.length);
657
- }
658
- continue;
659
- }
660
- out.push(item);
661
- }
662
- return spliceAtSlots(out, synthetic, slot);
593
+ return placeFolded(items, { folded, synthetic, leftoverNames });
663
594
  };
664
595
 
665
596
  const proposeDepItems = (pkgText, outdated, audit, extra = {}) => {
@@ -667,7 +598,7 @@ const proposeDepItems = (pkgText, outdated, audit, extra = {}) => {
667
598
  if (!pkg) return [];
668
599
  const lock = jsonParse(extra.lockText ?? '');
669
600
  const used = extra.usedNames;
670
- const names = unusedDeclaredNames(pkg, used);
601
+ const names = unusedDeclared(pkg, used).map((dep) => dep.name);
671
602
  const exportEntries = loadExportEntries(names, extra, extra.dir);
672
603
  const options = { used, exportEntries };
673
604
  const changes = buildProposedChanges(pkg, outdated, audit, lock, options);
package/lib/detect.js CHANGED
@@ -1,9 +1,11 @@
1
1
  'use strict';
2
2
 
3
3
  const path = require('node:path');
4
- const { fileExt } = require('metautil');
4
+ const metautil = require('metautil');
5
+ const { fileExt } = metautil;
5
6
 
6
- const { mapLang } = require('./highlight.js');
7
+ const highlight = require('./highlight.js');
8
+ const { mapLang } = highlight;
7
9
 
8
10
  const PROSE_BASENAMES = [
9
11
  'license',
package/lib/diff/align.js CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
- const { diffChars, tokenSimilarity } = require('./inline.js');
3
+ const inline = require('./inline.js');
4
+ const { diffChars, tokenSimilarity } = inline;
4
5
 
5
6
  const PAIR_MIN_SIM = 0.3;
6
7
  const PAIR_HEAD_WEIGHT = 0.4;
package/lib/diff/diff.js CHANGED
@@ -1,8 +1,11 @@
1
1
  'use strict';
2
2
 
3
- const { diffChars } = require('./inline.js');
4
- const { isCtxType, pairIndices, attachInline } = require('./align.js');
5
- const { parseDiff } = require('./parse.js');
3
+ const inline = require('./inline.js');
4
+ const { diffChars } = inline;
5
+ const align = require('./align.js');
6
+ const { isCtxType, pairIndices, attachInline } = align;
7
+ const parse = require('./parse.js');
8
+ const { parseDiff } = parse;
6
9
  const patch = require('./patch.js');
7
10
  const { splitHunk, flattenBlock, countSides, formatPatch } = patch;
8
11
  const display = require('./display.js');
@@ -2,7 +2,8 @@
2
2
 
3
3
  const align = require('./align.js');
4
4
  const { isCtxType, attachInline, LAYOUT_ALIGN } = align;
5
- const { flattenBlock } = require('./patch.js');
5
+ const patch = require('./patch.js');
6
+ const { flattenBlock } = patch;
6
7
 
7
8
  const DISPLAY_CONTEXT = 3;
8
9