@cellajs/cli 0.6.0 → 0.6.2
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/README.md +2 -1
- package/dist/index.js +166 -127
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -414,7 +414,8 @@ previous value, and a package.json without `type` gets upstream's. Set it yourse
|
|
|
414
414
|
|
|
415
415
|
1. **Updates.** It lists the outdated packages and runtime pins in one table and asks once which to
|
|
416
416
|
update. Rows with a high or critical advisory start ticked; submitting with nothing ticked skips
|
|
417
|
-
this layer.
|
|
417
|
+
this layer. Above the prompt it prints what `pnpm audit` reports right now, including packages
|
|
418
|
+
that have no row, so a run you cancel has shown them too.
|
|
418
419
|
2. **Security.** It audits the workspace as the picked updates leave it and brings three settings
|
|
419
420
|
in `pnpm-workspace.yaml` in line with that audit.
|
|
420
421
|
|
package/dist/index.js
CHANGED
|
@@ -228,7 +228,7 @@ import process5 from "process";
|
|
|
228
228
|
// package.json
|
|
229
229
|
var package_default = {
|
|
230
230
|
name: "@cellajs/cli",
|
|
231
|
-
version: "0.6.
|
|
231
|
+
version: "0.6.2",
|
|
232
232
|
private: false,
|
|
233
233
|
license: "MIT",
|
|
234
234
|
description: "CLI for managing your monorepo and upgrading it with upstream Cella.",
|
|
@@ -1436,6 +1436,129 @@ function formatAlignmentsLine(total, open) {
|
|
|
1436
1436
|
return `alignments: ${parts.join(" \xB7 ")}`;
|
|
1437
1437
|
}
|
|
1438
1438
|
|
|
1439
|
+
// src/utils/upstream-overrides.ts
|
|
1440
|
+
import { Node, Project as Project2, SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
1441
|
+
var LIST_KEYS = ["pinned", "ignored"];
|
|
1442
|
+
function resolveExpression(node, sourceFile, depth = 0) {
|
|
1443
|
+
if (!node || depth > 8) return node;
|
|
1444
|
+
if (Node.isParenthesizedExpression(node) || Node.isAsExpression(node) || Node.isSatisfiesExpression(node)) {
|
|
1445
|
+
return resolveExpression(node.getExpression(), sourceFile, depth + 1);
|
|
1446
|
+
}
|
|
1447
|
+
if (Node.isIdentifier(node)) {
|
|
1448
|
+
return resolveExpression(
|
|
1449
|
+
sourceFile.getVariableDeclaration(node.getText())?.getInitializer(),
|
|
1450
|
+
sourceFile,
|
|
1451
|
+
depth + 1
|
|
1452
|
+
);
|
|
1453
|
+
}
|
|
1454
|
+
return node;
|
|
1455
|
+
}
|
|
1456
|
+
function findConfigObject(sourceFile) {
|
|
1457
|
+
for (const call of sourceFile.getDescendantsOfKind(SyntaxKind2.CallExpression)) {
|
|
1458
|
+
if (call.getExpression().getText() !== "defineConfig") continue;
|
|
1459
|
+
const arg = resolveExpression(call.getArguments()[0], sourceFile);
|
|
1460
|
+
if (Node.isObjectLiteralExpression(arg)) return arg;
|
|
1461
|
+
}
|
|
1462
|
+
const exported = sourceFile.getExportAssignment((assignment) => !assignment.isExportEquals());
|
|
1463
|
+
const value = resolveExpression(exported?.getExpression(), sourceFile);
|
|
1464
|
+
return Node.isObjectLiteralExpression(value) ? value : void 0;
|
|
1465
|
+
}
|
|
1466
|
+
function readProperty(object, name, sourceFile) {
|
|
1467
|
+
for (const property of object.getProperties()) {
|
|
1468
|
+
if (Node.isPropertyAssignment(property)) {
|
|
1469
|
+
if (property.getName().replace(/^['"`]|['"`]$/g, "") !== name) continue;
|
|
1470
|
+
return resolveExpression(property.getInitializer(), sourceFile) ?? null;
|
|
1471
|
+
}
|
|
1472
|
+
if (Node.isShorthandPropertyAssignment(property) && property.getName() === name) {
|
|
1473
|
+
return resolveExpression(property.getNameNode(), sourceFile) ?? null;
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
return void 0;
|
|
1477
|
+
}
|
|
1478
|
+
function readStringEntries(node) {
|
|
1479
|
+
if (!Node.isArrayLiteralExpression(node)) return null;
|
|
1480
|
+
const entries = [];
|
|
1481
|
+
for (const element of node.getElements()) {
|
|
1482
|
+
if (Node.isStringLiteral(element) || Node.isNoSubstitutionTemplateLiteral(element)) {
|
|
1483
|
+
entries.push(element.getLiteralValue());
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
return entries;
|
|
1487
|
+
}
|
|
1488
|
+
function readPackageJsonKeys(config, sourceFile) {
|
|
1489
|
+
const settings = readProperty(config, "settings", sourceFile);
|
|
1490
|
+
if (settings === void 0) return [...DEFAULT_PACKAGE_JSON_KEYS];
|
|
1491
|
+
if (!settings || !Node.isObjectLiteralExpression(settings)) return null;
|
|
1492
|
+
const current = readProperty(settings, "packageJsonKeys", sourceFile);
|
|
1493
|
+
const keys = current === void 0 ? readProperty(settings, "packageJsonSync", sourceFile) : current;
|
|
1494
|
+
if (keys === void 0) return [...DEFAULT_PACKAGE_JSON_KEYS];
|
|
1495
|
+
return keys ? readStringEntries(keys) : null;
|
|
1496
|
+
}
|
|
1497
|
+
function parseOverrideLists(source) {
|
|
1498
|
+
try {
|
|
1499
|
+
const project = new Project2({ useInMemoryFileSystem: true, skipLoadingLibFiles: true });
|
|
1500
|
+
const sourceFile = project.createSourceFile("cella.config.ts", source);
|
|
1501
|
+
const config = findConfigObject(sourceFile);
|
|
1502
|
+
if (!config) return null;
|
|
1503
|
+
const lists = {
|
|
1504
|
+
pinned: [],
|
|
1505
|
+
ignored: [],
|
|
1506
|
+
packageJsonKeys: readPackageJsonKeys(config, sourceFile)
|
|
1507
|
+
};
|
|
1508
|
+
const overrides = readProperty(config, "overrides", sourceFile);
|
|
1509
|
+
if (overrides === void 0) return lists;
|
|
1510
|
+
if (!overrides || !Node.isObjectLiteralExpression(overrides)) return null;
|
|
1511
|
+
for (const key of LIST_KEYS) {
|
|
1512
|
+
const list = readProperty(overrides, key, sourceFile);
|
|
1513
|
+
if (list === void 0) continue;
|
|
1514
|
+
const entries = list ? readStringEntries(list) : null;
|
|
1515
|
+
if (!entries) return null;
|
|
1516
|
+
lists[key] = entries;
|
|
1517
|
+
}
|
|
1518
|
+
return lists;
|
|
1519
|
+
} catch {
|
|
1520
|
+
return null;
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
function diffOverrideLists(base, incoming, fork) {
|
|
1524
|
+
const diff = (key) => {
|
|
1525
|
+
const baseSet = new Set(base[key].map(normalizeEntry).filter(Boolean));
|
|
1526
|
+
const incomingSet = new Set(incoming[key].map(normalizeEntry).filter(Boolean));
|
|
1527
|
+
const forkEntries = fork[key].map(normalizeEntry).filter(Boolean);
|
|
1528
|
+
return {
|
|
1529
|
+
added: [...incomingSet].filter((entry) => !baseSet.has(entry) && !isUnderAnyFolder(entry, forkEntries)),
|
|
1530
|
+
removed: [...baseSet].filter((entry) => !incomingSet.has(entry) && forkEntries.includes(entry))
|
|
1531
|
+
};
|
|
1532
|
+
};
|
|
1533
|
+
const diffKeys = () => {
|
|
1534
|
+
const [baseKeys, incomingKeys, forkKeys] = [base.packageJsonKeys, incoming.packageJsonKeys, fork.packageJsonKeys];
|
|
1535
|
+
if (!baseKeys || !incomingKeys || !forkKeys) return { added: [], removed: [] };
|
|
1536
|
+
return {
|
|
1537
|
+
added: [...new Set(incomingKeys)].filter((key) => !baseKeys.includes(key) && !forkKeys.includes(key)),
|
|
1538
|
+
removed: [...new Set(baseKeys)].filter((key) => !incomingKeys.includes(key) && forkKeys.includes(key))
|
|
1539
|
+
};
|
|
1540
|
+
};
|
|
1541
|
+
return { pinned: diff("pinned"), ignored: diff("ignored"), packageJsonKeys: diffKeys() };
|
|
1542
|
+
}
|
|
1543
|
+
async function compareUpstreamOverrides(repoPath, mergeBaseRef, incomingRef, forkConfig) {
|
|
1544
|
+
const [baseSource, incomingSource] = await Promise.all(
|
|
1545
|
+
[mergeBaseRef, incomingRef].map((ref) => git(["show", `${ref}:${CONFIG_FILE}`], repoPath, { ignoreErrors: true }))
|
|
1546
|
+
);
|
|
1547
|
+
if (baseSource === incomingSource) return void 0;
|
|
1548
|
+
const base = baseSource ? parseOverrideLists(baseSource) : null;
|
|
1549
|
+
if (!base) return { kind: "unreadable", side: "base" };
|
|
1550
|
+
const incoming = incomingSource ? parseOverrideLists(incomingSource) : null;
|
|
1551
|
+
if (!incoming) return { kind: "unreadable", side: "incoming" };
|
|
1552
|
+
const fork = {
|
|
1553
|
+
pinned: forkConfig.overrides?.pinned ?? [],
|
|
1554
|
+
ignored: forkConfig.overrides?.ignored ?? [],
|
|
1555
|
+
packageJsonKeys: forkConfig.settings.packageJsonKeys ?? DEFAULT_PACKAGE_JSON_KEYS
|
|
1556
|
+
};
|
|
1557
|
+
const changes = diffOverrideLists(base, incoming, fork);
|
|
1558
|
+
const count3 = Object.values(changes).reduce((n, list) => n + list.added.length + list.removed.length, 0);
|
|
1559
|
+
return count3 > 0 ? { kind: "changes", ...changes } : void 0;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1439
1562
|
// src/utils/overrides.ts
|
|
1440
1563
|
function normalizeEntry(entry) {
|
|
1441
1564
|
return entry.trim().replace(/^\.\//, "").replace(/\/+$/, "");
|
|
@@ -1491,8 +1614,11 @@ async function validateOverrides(config, forkPath, upstreamRef) {
|
|
|
1491
1614
|
}
|
|
1492
1615
|
if (upstream && pinsUpstreamHas.length > 0) {
|
|
1493
1616
|
const differs = await listChangedSinceRef(forkPath, upstream, pinsUpstreamHas.map(normalizeEntry));
|
|
1617
|
+
const upstreamSource = await git(["show", `${upstream}:${CONFIG_FILE}`], forkPath, { ignoreErrors: true });
|
|
1618
|
+
const upstreamPins = upstreamSource && parseOverrideLists(upstreamSource)?.pinned.map(normalizeEntry) || [];
|
|
1494
1619
|
for (const entry of pinsUpstreamHas) {
|
|
1495
1620
|
if (differs.some((changed) => isUnderAnyFolder(changed, [entry]))) continue;
|
|
1621
|
+
if (upstreamPins.includes(normalizeEntry(entry))) continue;
|
|
1496
1622
|
warnings.push(`pin is identical to upstream, it only drops upstream's next change: ${entry}`);
|
|
1497
1623
|
}
|
|
1498
1624
|
}
|
|
@@ -1814,129 +1940,6 @@ function cliVersionMismatch(running, range) {
|
|
|
1814
1940
|
].join("\n");
|
|
1815
1941
|
}
|
|
1816
1942
|
|
|
1817
|
-
// src/utils/upstream-overrides.ts
|
|
1818
|
-
import { Node, Project as Project2, SyntaxKind as SyntaxKind2 } from "ts-morph";
|
|
1819
|
-
var LIST_KEYS = ["pinned", "ignored"];
|
|
1820
|
-
function resolveExpression(node, sourceFile, depth = 0) {
|
|
1821
|
-
if (!node || depth > 8) return node;
|
|
1822
|
-
if (Node.isParenthesizedExpression(node) || Node.isAsExpression(node) || Node.isSatisfiesExpression(node)) {
|
|
1823
|
-
return resolveExpression(node.getExpression(), sourceFile, depth + 1);
|
|
1824
|
-
}
|
|
1825
|
-
if (Node.isIdentifier(node)) {
|
|
1826
|
-
return resolveExpression(
|
|
1827
|
-
sourceFile.getVariableDeclaration(node.getText())?.getInitializer(),
|
|
1828
|
-
sourceFile,
|
|
1829
|
-
depth + 1
|
|
1830
|
-
);
|
|
1831
|
-
}
|
|
1832
|
-
return node;
|
|
1833
|
-
}
|
|
1834
|
-
function findConfigObject(sourceFile) {
|
|
1835
|
-
for (const call of sourceFile.getDescendantsOfKind(SyntaxKind2.CallExpression)) {
|
|
1836
|
-
if (call.getExpression().getText() !== "defineConfig") continue;
|
|
1837
|
-
const arg = resolveExpression(call.getArguments()[0], sourceFile);
|
|
1838
|
-
if (Node.isObjectLiteralExpression(arg)) return arg;
|
|
1839
|
-
}
|
|
1840
|
-
const exported = sourceFile.getExportAssignment((assignment) => !assignment.isExportEquals());
|
|
1841
|
-
const value = resolveExpression(exported?.getExpression(), sourceFile);
|
|
1842
|
-
return Node.isObjectLiteralExpression(value) ? value : void 0;
|
|
1843
|
-
}
|
|
1844
|
-
function readProperty(object, name, sourceFile) {
|
|
1845
|
-
for (const property of object.getProperties()) {
|
|
1846
|
-
if (Node.isPropertyAssignment(property)) {
|
|
1847
|
-
if (property.getName().replace(/^['"`]|['"`]$/g, "") !== name) continue;
|
|
1848
|
-
return resolveExpression(property.getInitializer(), sourceFile) ?? null;
|
|
1849
|
-
}
|
|
1850
|
-
if (Node.isShorthandPropertyAssignment(property) && property.getName() === name) {
|
|
1851
|
-
return resolveExpression(property.getNameNode(), sourceFile) ?? null;
|
|
1852
|
-
}
|
|
1853
|
-
}
|
|
1854
|
-
return void 0;
|
|
1855
|
-
}
|
|
1856
|
-
function readStringEntries(node) {
|
|
1857
|
-
if (!Node.isArrayLiteralExpression(node)) return null;
|
|
1858
|
-
const entries = [];
|
|
1859
|
-
for (const element of node.getElements()) {
|
|
1860
|
-
if (Node.isStringLiteral(element) || Node.isNoSubstitutionTemplateLiteral(element)) {
|
|
1861
|
-
entries.push(element.getLiteralValue());
|
|
1862
|
-
}
|
|
1863
|
-
}
|
|
1864
|
-
return entries;
|
|
1865
|
-
}
|
|
1866
|
-
function readPackageJsonKeys(config, sourceFile) {
|
|
1867
|
-
const settings = readProperty(config, "settings", sourceFile);
|
|
1868
|
-
if (settings === void 0) return [...DEFAULT_PACKAGE_JSON_KEYS];
|
|
1869
|
-
if (!settings || !Node.isObjectLiteralExpression(settings)) return null;
|
|
1870
|
-
const current = readProperty(settings, "packageJsonKeys", sourceFile);
|
|
1871
|
-
const keys = current === void 0 ? readProperty(settings, "packageJsonSync", sourceFile) : current;
|
|
1872
|
-
if (keys === void 0) return [...DEFAULT_PACKAGE_JSON_KEYS];
|
|
1873
|
-
return keys ? readStringEntries(keys) : null;
|
|
1874
|
-
}
|
|
1875
|
-
function parseOverrideLists(source) {
|
|
1876
|
-
try {
|
|
1877
|
-
const project = new Project2({ useInMemoryFileSystem: true, skipLoadingLibFiles: true });
|
|
1878
|
-
const sourceFile = project.createSourceFile("cella.config.ts", source);
|
|
1879
|
-
const config = findConfigObject(sourceFile);
|
|
1880
|
-
if (!config) return null;
|
|
1881
|
-
const lists = {
|
|
1882
|
-
pinned: [],
|
|
1883
|
-
ignored: [],
|
|
1884
|
-
packageJsonKeys: readPackageJsonKeys(config, sourceFile)
|
|
1885
|
-
};
|
|
1886
|
-
const overrides = readProperty(config, "overrides", sourceFile);
|
|
1887
|
-
if (overrides === void 0) return lists;
|
|
1888
|
-
if (!overrides || !Node.isObjectLiteralExpression(overrides)) return null;
|
|
1889
|
-
for (const key of LIST_KEYS) {
|
|
1890
|
-
const list = readProperty(overrides, key, sourceFile);
|
|
1891
|
-
if (list === void 0) continue;
|
|
1892
|
-
const entries = list ? readStringEntries(list) : null;
|
|
1893
|
-
if (!entries) return null;
|
|
1894
|
-
lists[key] = entries;
|
|
1895
|
-
}
|
|
1896
|
-
return lists;
|
|
1897
|
-
} catch {
|
|
1898
|
-
return null;
|
|
1899
|
-
}
|
|
1900
|
-
}
|
|
1901
|
-
function diffOverrideLists(base, incoming, fork) {
|
|
1902
|
-
const diff = (key) => {
|
|
1903
|
-
const baseSet = new Set(base[key].map(normalizeEntry).filter(Boolean));
|
|
1904
|
-
const incomingSet = new Set(incoming[key].map(normalizeEntry).filter(Boolean));
|
|
1905
|
-
const forkEntries = fork[key].map(normalizeEntry).filter(Boolean);
|
|
1906
|
-
return {
|
|
1907
|
-
added: [...incomingSet].filter((entry) => !baseSet.has(entry) && !isUnderAnyFolder(entry, forkEntries)),
|
|
1908
|
-
removed: [...baseSet].filter((entry) => !incomingSet.has(entry) && forkEntries.includes(entry))
|
|
1909
|
-
};
|
|
1910
|
-
};
|
|
1911
|
-
const diffKeys = () => {
|
|
1912
|
-
const [baseKeys, incomingKeys, forkKeys] = [base.packageJsonKeys, incoming.packageJsonKeys, fork.packageJsonKeys];
|
|
1913
|
-
if (!baseKeys || !incomingKeys || !forkKeys) return { added: [], removed: [] };
|
|
1914
|
-
return {
|
|
1915
|
-
added: [...new Set(incomingKeys)].filter((key) => !baseKeys.includes(key) && !forkKeys.includes(key)),
|
|
1916
|
-
removed: [...new Set(baseKeys)].filter((key) => !incomingKeys.includes(key) && forkKeys.includes(key))
|
|
1917
|
-
};
|
|
1918
|
-
};
|
|
1919
|
-
return { pinned: diff("pinned"), ignored: diff("ignored"), packageJsonKeys: diffKeys() };
|
|
1920
|
-
}
|
|
1921
|
-
async function compareUpstreamOverrides(repoPath, mergeBaseRef, incomingRef, forkConfig) {
|
|
1922
|
-
const [baseSource, incomingSource] = await Promise.all(
|
|
1923
|
-
[mergeBaseRef, incomingRef].map((ref) => git(["show", `${ref}:${CONFIG_FILE}`], repoPath, { ignoreErrors: true }))
|
|
1924
|
-
);
|
|
1925
|
-
if (baseSource === incomingSource) return void 0;
|
|
1926
|
-
const base = baseSource ? parseOverrideLists(baseSource) : null;
|
|
1927
|
-
if (!base) return { kind: "unreadable", side: "base" };
|
|
1928
|
-
const incoming = incomingSource ? parseOverrideLists(incomingSource) : null;
|
|
1929
|
-
if (!incoming) return { kind: "unreadable", side: "incoming" };
|
|
1930
|
-
const fork = {
|
|
1931
|
-
pinned: forkConfig.overrides?.pinned ?? [],
|
|
1932
|
-
ignored: forkConfig.overrides?.ignored ?? [],
|
|
1933
|
-
packageJsonKeys: forkConfig.settings.packageJsonKeys ?? DEFAULT_PACKAGE_JSON_KEYS
|
|
1934
|
-
};
|
|
1935
|
-
const changes = diffOverrideLists(base, incoming, fork);
|
|
1936
|
-
const count3 = Object.values(changes).reduce((n, list) => n + list.added.length + list.removed.length, 0);
|
|
1937
|
-
return count3 > 0 ? { kind: "changes", ...changes } : void 0;
|
|
1938
|
-
}
|
|
1939
|
-
|
|
1940
1943
|
// src/services/analyze-core.ts
|
|
1941
1944
|
function isReportableIgnored(filePath) {
|
|
1942
1945
|
return !isManagedFile(filePath) && !isGeneratedFile(filePath);
|
|
@@ -4466,8 +4469,9 @@ async function runAudit(config) {
|
|
|
4466
4469
|
}
|
|
4467
4470
|
const runtimes = planRuntimeUpdates(pins, feeds, { releaseAgeMinutes, now });
|
|
4468
4471
|
const localTools = planLocalTools(machine, { releaseAgeMinutes, now });
|
|
4472
|
+
const advisories = auditResult ? advisoriesFromAudit(auditResult) : null;
|
|
4469
4473
|
const rows = [
|
|
4470
|
-
...packageRows(outdated,
|
|
4474
|
+
...packageRows(outdated, advisories ?? []),
|
|
4471
4475
|
...runtimes.updates.map(runtimeRow)
|
|
4472
4476
|
];
|
|
4473
4477
|
if (rows.length === 0) {
|
|
@@ -4487,6 +4491,7 @@ async function runAudit(config) {
|
|
|
4487
4491
|
await runSecurityPass(forkPath, { apply: false, releaseAgeMinutes });
|
|
4488
4492
|
return;
|
|
4489
4493
|
}
|
|
4494
|
+
printReported(advisories);
|
|
4490
4495
|
const selected = await promptForUpdates(rows);
|
|
4491
4496
|
if (!selected) return;
|
|
4492
4497
|
const { edits, bumped } = await planEdits(forkPath, rows, selected, pins.nodeImageSuffixes);
|
|
@@ -4495,8 +4500,8 @@ async function runAudit(config) {
|
|
|
4495
4500
|
spinner.stop();
|
|
4496
4501
|
}
|
|
4497
4502
|
}
|
|
4503
|
+
var worstSeverity = (advisories, name) => SEVERITIES.find((severity) => advisories.some((a) => a.module === name && a.severity === severity)) ?? null;
|
|
4498
4504
|
function packageRows(outdated, advisories) {
|
|
4499
|
-
const severityOf = (name) => SEVERITIES.find((severity) => advisories.some((a) => a.module === name && a.severity === severity)) ?? null;
|
|
4500
4505
|
const readDependentPkg = createDependentPkgReader();
|
|
4501
4506
|
const rows = Object.entries(outdated).map(([key, pkg]) => {
|
|
4502
4507
|
const name = outdatedPackageName(key);
|
|
@@ -4520,7 +4525,7 @@ function packageRows(outdated, advisories) {
|
|
|
4520
4525
|
pinnedIn,
|
|
4521
4526
|
repoUrl,
|
|
4522
4527
|
releasesUrl: getReleasesUrl(repoUrl),
|
|
4523
|
-
severity:
|
|
4528
|
+
severity: worstSeverity(advisories, name)
|
|
4524
4529
|
};
|
|
4525
4530
|
});
|
|
4526
4531
|
return rows.sort((a, b) => inText(a).localeCompare(inText(b)) || a.name.localeCompare(b.name));
|
|
@@ -4626,6 +4631,40 @@ function printLocalTools(checks) {
|
|
|
4626
4631
|
}
|
|
4627
4632
|
console.info();
|
|
4628
4633
|
}
|
|
4634
|
+
function printReported(advisories) {
|
|
4635
|
+
if (!advisories) {
|
|
4636
|
+
console.info(`${warningMark} pnpm audit gave no answer: a row in the table can lack its dot`);
|
|
4637
|
+
console.info();
|
|
4638
|
+
return;
|
|
4639
|
+
}
|
|
4640
|
+
if (advisories.length === 0) {
|
|
4641
|
+
console.info(`${checkMark} pnpm audit reports nothing ${colors_default.dim("\xB7 with the current overrides and ignores")}`);
|
|
4642
|
+
console.info();
|
|
4643
|
+
return;
|
|
4644
|
+
}
|
|
4645
|
+
const modules = [...new Set(advisories.map((a) => a.module))].map((name) => {
|
|
4646
|
+
const own = advisories.filter((a) => a.module === name);
|
|
4647
|
+
return {
|
|
4648
|
+
name,
|
|
4649
|
+
severity: worstSeverity(own, name) ?? own[0].severity,
|
|
4650
|
+
installed: [...new Set(own.flatMap((a) => a.installed))].join(", "),
|
|
4651
|
+
via: formatDependents([...new Set(own.flatMap((a) => a.via))]),
|
|
4652
|
+
direct: own.some((a) => a.direct)
|
|
4653
|
+
};
|
|
4654
|
+
});
|
|
4655
|
+
modules.sort((a, b) => SEVERITIES.indexOf(a.severity) - SEVERITIES.indexOf(b.severity));
|
|
4656
|
+
const nameWidth = Math.min(30, Math.max(...modules.map((m) => m.name.length)));
|
|
4657
|
+
const versionWidth = Math.max(...modules.map((m) => m.installed.length));
|
|
4658
|
+
console.info(`${colors_default.bold("pnpm audit")} ${colors_default.dim("\xB7 with the current overrides and ignores")}`);
|
|
4659
|
+
for (const m of modules) {
|
|
4660
|
+
const name = colors_default.white(middleTruncate(m.name, nameWidth).padEnd(nameWidth));
|
|
4661
|
+
const source = `${m.via}${m.direct ? " (direct)" : ""}`;
|
|
4662
|
+
console.info(
|
|
4663
|
+
`${getVulnIcon(m.severity)} ${name} ${m.severity.padEnd(8)} ${m.installed.padEnd(versionWidth)} ${colors_default.dim(source)}`
|
|
4664
|
+
);
|
|
4665
|
+
}
|
|
4666
|
+
console.info();
|
|
4667
|
+
}
|
|
4629
4668
|
function buildUpdateChoices(rows) {
|
|
4630
4669
|
const makeChoice = (row) => {
|
|
4631
4670
|
const devTag = row.isDev ? colors_default.dim(" (dev)") : "";
|