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.
- package/CHANGELOG.md +27 -1
- package/README.md +8 -4
- package/bin/reslop.js +4 -2
- package/lib/api.js +2 -1
- package/lib/capabilities.js +0 -4
- package/lib/cli.js +19 -10
- package/lib/clipboard.js +45 -4
- package/lib/deps-diff.js +61 -118
- package/lib/deps.js +166 -235
- package/lib/detect.js +4 -2
- package/lib/diff/align.js +2 -1
- package/lib/diff/diff.js +6 -3
- package/lib/diff/display.js +2 -1
- package/lib/diff/inline.js +68 -2
- package/lib/diff/patch.js +2 -1
- package/lib/diff/unit.js +15 -30
- package/lib/editor.js +91 -13
- package/lib/files.js +54 -27
- package/lib/git-branches.js +107 -154
- package/lib/git-deps.js +78 -155
- package/lib/git-worktree.js +508 -0
- package/lib/git.js +23 -580
- package/lib/github.js +9 -8
- package/lib/gitlab.js +5 -4
- package/lib/highlight/bash.js +2 -1
- package/lib/highlight/core.js +11 -0
- package/lib/highlight/css.js +2 -1
- package/lib/highlight/csv.js +2 -1
- package/lib/highlight/dot.js +3 -12
- package/lib/highlight/html.js +2 -1
- package/lib/highlight/json.js +2 -1
- package/lib/highlight/log.js +5 -11
- package/lib/highlight/txt.js +3 -12
- package/lib/highlight.js +2 -1
- package/lib/keys.js +22 -12
- package/lib/manifest.js +4 -6
- package/lib/npm-commands.js +82 -24
- package/lib/remote.js +21 -20
- package/lib/render/branches.js +9 -27
- package/lib/render/chrome.js +109 -35
- package/lib/render/commits.js +216 -216
- package/lib/render/diff.js +160 -47
- package/lib/render/files.js +9 -26
- package/lib/render/frame.js +97 -118
- package/lib/render/notes.js +74 -26
- package/lib/render/npm.js +104 -30
- package/lib/render/present.js +2 -1
- package/lib/render/primitives.js +128 -52
- package/lib/render/render.js +2 -1
- package/lib/render/unit.js +17 -11
- package/lib/report-model.js +6 -4
- package/lib/report-parse.js +8 -14
- package/lib/report-render.js +38 -21
- package/lib/report-run.js +12 -11
- package/lib/report-test.js +45 -51
- package/lib/report-tools.js +44 -25
- package/lib/review-merge.js +102 -131
- package/lib/review.js +69 -78
- package/lib/select.js +52 -0
- package/lib/session/actions.js +72 -87
- package/lib/session/branches.js +18 -52
- package/lib/session/change-actions.js +175 -147
- package/lib/session/commit.js +65 -61
- package/lib/session/compose.js +152 -83
- package/lib/session/dispatch.js +53 -46
- package/lib/session/edit-click.js +57 -0
- package/lib/session/files-pane.js +30 -51
- package/lib/session/items.js +73 -90
- package/lib/session/lifecycle.js +37 -98
- package/lib/session/load.js +52 -57
- package/lib/session/navigation.js +105 -95
- package/lib/session/npm.js +205 -71
- package/lib/session/ops.js +200 -45
- package/lib/session/pointer.js +33 -8
- package/lib/session/progress.js +9 -6
- package/lib/session/review.js +35 -53
- package/lib/session/tasks.js +292 -0
- package/lib/session/terminal.js +17 -19
- package/lib/session/unit.js +3 -4
- package/lib/session/update.js +76 -96
- package/lib/session/view.js +45 -16
- package/lib/session/watch.js +47 -27
- package/lib/session.js +66 -97
- package/lib/source.js +6 -3
- package/lib/update.js +5 -13
- package/lib/utilities.js +25 -3
- package/lib/wrap.js +18 -1
- package/package.json +1 -1
- 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
|
|
6
|
-
const {
|
|
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 (
|
|
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
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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:
|
|
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
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
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
|
|
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
|
|
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
|
|
415
|
-
const
|
|
416
|
-
if (!pkgHasExportEntry(pkg)) return
|
|
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
|
|
422
|
-
keys.sort()
|
|
423
|
-
|
|
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
|
|
403
|
+
return found;
|
|
429
404
|
};
|
|
430
405
|
|
|
431
406
|
const markUnusedChanges = (changes, used, pkg, exportEntries) => {
|
|
432
|
-
if (!pkgHasExportEntry(pkg)) return changes;
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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
|
|
458
|
-
if (
|
|
459
|
-
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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
|
|
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
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
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
|
|
504
|
-
const
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
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
|
|
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
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
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(
|
|
584
|
+
leftoverNames.set(key, foldedDepNames(changes));
|
|
628
585
|
const taken = takeManifestItems(next);
|
|
629
|
-
if (next.foldLock)
|
|
630
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
|
4
|
+
const metautil = require('metautil');
|
|
5
|
+
const { fileExt } = metautil;
|
|
5
6
|
|
|
6
|
-
const
|
|
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
package/lib/diff/diff.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
const
|
|
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');
|
package/lib/diff/display.js
CHANGED