@pnpm/cli.default-reporter 1100.1.1 → 1100.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +5 -0
- package/lib/reportError.js +14 -5
- package/lib/reporterForClient/index.d.ts +1 -0
- package/lib/reporterForClient/index.js +5 -1
- package/lib/reporterForClient/reportLockfileVerification.d.ts +15 -0
- package/lib/reporterForClient/reportLockfileVerification.js +56 -0
- package/package.json +9 -9
package/lib/index.js
CHANGED
|
@@ -69,6 +69,7 @@ export function toOutput$(opts) {
|
|
|
69
69
|
const deprecationPushStream = new Rx.Subject();
|
|
70
70
|
const summaryPushStream = new Rx.Subject();
|
|
71
71
|
const lifecyclePushStream = new Rx.Subject();
|
|
72
|
+
const lockfileVerificationPushStream = new Rx.Subject();
|
|
72
73
|
const statsPushStream = new Rx.Subject();
|
|
73
74
|
const packageImportMethodPushStream = new Rx.Subject();
|
|
74
75
|
const installCheckPushStream = new Rx.Subject();
|
|
@@ -112,6 +113,9 @@ export function toOutput$(opts) {
|
|
|
112
113
|
case 'pnpm:lifecycle':
|
|
113
114
|
lifecyclePushStream.next(log);
|
|
114
115
|
break;
|
|
116
|
+
case 'pnpm:lockfile-verification':
|
|
117
|
+
lockfileVerificationPushStream.next(log);
|
|
118
|
+
break;
|
|
115
119
|
case 'pnpm:stats':
|
|
116
120
|
statsPushStream.next(log);
|
|
117
121
|
break;
|
|
@@ -185,6 +189,7 @@ export function toOutput$(opts) {
|
|
|
185
189
|
ignoredScripts: Rx.from(ignoredScriptsPushStream),
|
|
186
190
|
lifecycle: Rx.from(lifecyclePushStream),
|
|
187
191
|
link: Rx.from(linkPushStream),
|
|
192
|
+
lockfileVerification: Rx.from(lockfileVerificationPushStream),
|
|
188
193
|
other,
|
|
189
194
|
packageImportMethod: Rx.from(packageImportMethodPushStream),
|
|
190
195
|
packageManifest: Rx.from(packageManifestPushStream),
|
package/lib/reportError.js
CHANGED
|
@@ -51,6 +51,11 @@ function getErrorInfo(logObj, config) {
|
|
|
51
51
|
return { title: err.message, body: 'If you cannot fix this registry issue, then set "resolution-mode" to "highest".' };
|
|
52
52
|
case 'ERR_PNPM_NO_MATCHING_VERSION':
|
|
53
53
|
case 'ERR_PNPM_NO_MATURE_MATCHING_VERSION':
|
|
54
|
+
// ERR_PNPM_NO_MATURE_MATCHING_VERSION used to come from the resolver
|
|
55
|
+
// with `packageMeta` attached; it now comes from the install / dlx /
|
|
56
|
+
// self-update callers as a plain PnpmError once the resolver has
|
|
57
|
+
// surfaced the violations. `packageMeta` may be undefined, in which
|
|
58
|
+
// case the formatter falls back to the bare title+message.
|
|
54
59
|
return formatNoMatchingVersion(err, logObj);
|
|
55
60
|
case 'ERR_PNPM_RECURSIVE_FAIL':
|
|
56
61
|
return formatRecursiveCommandSummary(logObj); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
@@ -94,10 +99,17 @@ ${formatPkgNameVer(pkgsStack[0])}\
|
|
|
94
99
|
${pkgsStack.slice(1).map((pkgInfo) => `${EOL} at ${formatPkgNameVer(pkgInfo)}`).join('')}`;
|
|
95
100
|
}
|
|
96
101
|
function formatNoMatchingVersion(err, msg) {
|
|
102
|
+
// Errors raised by the install/dlx/self-update layer after the resolver
|
|
103
|
+
// surfaces violations may not carry the original packageMeta. In that
|
|
104
|
+
// case the error message alone already names every offending entry,
|
|
105
|
+
// so we just echo it through without the registry-metadata appendix.
|
|
97
106
|
const meta = msg.packageMeta;
|
|
107
|
+
if (!meta) {
|
|
108
|
+
return { title: err.message };
|
|
109
|
+
}
|
|
98
110
|
const latestVersion = meta['dist-tags'].latest;
|
|
99
111
|
let output = `The latest release of ${meta.name} is "${latestVersion}".`;
|
|
100
|
-
const latestTime =
|
|
112
|
+
const latestTime = meta.time?.[latestVersion];
|
|
101
113
|
if (latestTime) {
|
|
102
114
|
output += ` Published at ${stringifyDate(latestTime)}`;
|
|
103
115
|
}
|
|
@@ -108,7 +120,7 @@ function formatNoMatchingVersion(err, msg) {
|
|
|
108
120
|
if (tag !== 'latest') {
|
|
109
121
|
const version = meta['dist-tags'][tag];
|
|
110
122
|
output += ` * ${tag}: ${version}`;
|
|
111
|
-
const time =
|
|
123
|
+
const time = meta.time?.[version];
|
|
112
124
|
if (time) {
|
|
113
125
|
output += ` published at ${stringifyDate(time)}`;
|
|
114
126
|
}
|
|
@@ -117,9 +129,6 @@ function formatNoMatchingVersion(err, msg) {
|
|
|
117
129
|
}
|
|
118
130
|
}
|
|
119
131
|
output += `${EOL}If you need the full list of all ${Object.keys(meta.versions).length} published versions run "pnpm view ${meta.name} versions".`;
|
|
120
|
-
if (msg.immatureVersion) {
|
|
121
|
-
output += `${EOL}${EOL}If you want to install the matched version ignoring the time it was published, you can add the package name to the minimumReleaseAgeExclude setting. Read more about it: https://pnpm.io/settings#minimumreleaseageexclude`;
|
|
122
|
-
}
|
|
123
132
|
return {
|
|
124
133
|
title: err.message,
|
|
125
134
|
body: output,
|
|
@@ -13,6 +13,7 @@ export declare function reporterForClient(log$: {
|
|
|
13
13
|
deprecation: Rx.Observable<logs.DeprecationLog>;
|
|
14
14
|
summary: Rx.Observable<logs.SummaryLog>;
|
|
15
15
|
lifecycle: Rx.Observable<logs.LifecycleLog>;
|
|
16
|
+
lockfileVerification: Rx.Observable<logs.LockfileVerificationLog>;
|
|
16
17
|
stats: Rx.Observable<logs.StatsLog>;
|
|
17
18
|
installCheck: Rx.Observable<logs.InstallCheckLog>;
|
|
18
19
|
installingConfigDeps: Rx.Observable<logs.InstallingConfigDepsLog>;
|
|
@@ -8,6 +8,7 @@ import { reportIgnoredBuilds } from './reportIgnoredBuilds.js';
|
|
|
8
8
|
import { reportInstallChecks } from './reportInstallChecks.js';
|
|
9
9
|
import { reportInstallingConfigDeps } from './reportInstallingConfigDeps.js';
|
|
10
10
|
import { reportLifecycleScripts } from './reportLifecycleScripts.js';
|
|
11
|
+
import { reportLockfileVerification } from './reportLockfileVerification.js';
|
|
11
12
|
import { LOG_LEVEL_NUMBER, reportMisc } from './reportMisc.js';
|
|
12
13
|
import { reportPeerDependencyIssues } from './reportPeerDependencyIssues.js';
|
|
13
14
|
import { reportProgress } from './reportProgress.js';
|
|
@@ -60,7 +61,10 @@ export function reporterForClient(log$, opts) {
|
|
|
60
61
|
hideLifecyclePrefix: opts.hideLifecyclePrefix,
|
|
61
62
|
cwd,
|
|
62
63
|
width,
|
|
63
|
-
}), reportInstallChecks(log$.installCheck, { cwd }), reportInstallingConfigDeps(log$.installingConfigDeps),
|
|
64
|
+
}), reportInstallChecks(log$.installCheck, { cwd }), reportInstallingConfigDeps(log$.installingConfigDeps), reportLockfileVerification(log$.lockfileVerification, {
|
|
65
|
+
cwd,
|
|
66
|
+
workspaceDir: opts.pnpmConfig?.workspaceDir,
|
|
67
|
+
}), reportScope(log$.scope, { isRecursive: opts.isRecursive, cmd: opts.cmd }), reportSkippedOptionalDependencies(log$.skippedOptionalDependency, { cwd }), reportHooks(log$.hook, { cwd, isRecursive: opts.isRecursive }), reportUpdateCheck(log$.updateCheck, opts), reportProgress(log$, {
|
|
64
68
|
cwd,
|
|
65
69
|
throttle,
|
|
66
70
|
hideAddedPkgsProgress: opts.hideAddedPkgsProgress,
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { LockfileVerificationLog } from '@pnpm/core-loggers';
|
|
2
|
+
import * as Rx from 'rxjs';
|
|
3
|
+
export interface ReportLockfileVerificationOptions {
|
|
4
|
+
cwd: string;
|
|
5
|
+
/**
|
|
6
|
+
* The workspace root, when one exists. Used as the "expected"
|
|
7
|
+
* location for the lockfile — when the lockfile lives there, the
|
|
8
|
+
* path is implied and we don't repeat it in the rendered message.
|
|
9
|
+
* Falls back to `cwd` for single-project installs.
|
|
10
|
+
*/
|
|
11
|
+
workspaceDir?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function reportLockfileVerification(lockfileVerification$: Rx.Observable<LockfileVerificationLog>, opts: ReportLockfileVerificationOptions): Rx.Observable<Rx.Observable<{
|
|
14
|
+
msg: string;
|
|
15
|
+
}>>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import normalize from 'normalize-path';
|
|
4
|
+
import prettyMs from 'pretty-ms';
|
|
5
|
+
import * as Rx from 'rxjs';
|
|
6
|
+
import { map } from 'rxjs/operators';
|
|
7
|
+
export function reportLockfileVerification(lockfileVerification$, opts) {
|
|
8
|
+
const expectedDir = opts.workspaceDir ?? opts.cwd;
|
|
9
|
+
// A single inner observable so the `done` message overwrites the
|
|
10
|
+
// transient `started` message in ansi-diff mode. In appendOnly mode
|
|
11
|
+
// both lines are printed.
|
|
12
|
+
return Rx.of(lockfileVerification$.pipe(map((log) => {
|
|
13
|
+
const path_ = formatLockfilePath(log.lockfilePath, opts.cwd, expectedDir);
|
|
14
|
+
const entries = `${log.entries} ${log.entries === 1 ? 'entry' : 'entries'}`;
|
|
15
|
+
switch (log.status) {
|
|
16
|
+
case 'started':
|
|
17
|
+
return {
|
|
18
|
+
msg: `${chalk.cyan('?')} Verifying lockfile${path_} against supply-chain policies (${entries})...`,
|
|
19
|
+
};
|
|
20
|
+
case 'done':
|
|
21
|
+
return {
|
|
22
|
+
msg: `${chalk.green('✓')} Lockfile${path_} passes supply-chain policies (${entries} in ${prettyMs(log.elapsedMs)})`,
|
|
23
|
+
};
|
|
24
|
+
case 'failed':
|
|
25
|
+
// Brief one-liner so the transient `started` frame doesn't
|
|
26
|
+
// stay on screen above the detailed PnpmError block that the
|
|
27
|
+
// error reporter prints next.
|
|
28
|
+
return {
|
|
29
|
+
msg: `${chalk.red('✗')} Lockfile${path_} failed supply-chain policy check (${entries} in ${prettyMs(log.elapsedMs)})`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
})));
|
|
33
|
+
}
|
|
34
|
+
// Returns a leading-space-prefixed `at <path>` suffix only when the
|
|
35
|
+
// lockfile sits outside the obvious project/workspace root — otherwise
|
|
36
|
+
// the path is implied and printing it would just add noise to every
|
|
37
|
+
// install. Empty string when the path is omitted or matches the
|
|
38
|
+
// expected location.
|
|
39
|
+
//
|
|
40
|
+
// Uses `path.relative` rather than a strict `===` between
|
|
41
|
+
// `path.dirname(lockfilePath)` and `expectedDir`: relative path
|
|
42
|
+
// computation normalizes slash direction and trailing separators, so
|
|
43
|
+
// a workspaceDir like `C:/repo/` correctly matches a lockfilePath at
|
|
44
|
+
// `C:\repo\pnpm-lock.yaml` on Windows. The lockfile is considered
|
|
45
|
+
// "inside the expected dir" when the relative path is a bare file
|
|
46
|
+
// name (no separator) that doesn't escape upward.
|
|
47
|
+
function formatLockfilePath(lockfilePath, cwd, expectedDir) {
|
|
48
|
+
if (lockfilePath == null)
|
|
49
|
+
return '';
|
|
50
|
+
const fromExpected = path.relative(expectedDir, lockfilePath);
|
|
51
|
+
const isDirectChild = !fromExpected.includes(path.sep) && !fromExpected.startsWith('..');
|
|
52
|
+
if (isDirectChild)
|
|
53
|
+
return '';
|
|
54
|
+
return ` at ${normalize(path.relative(cwd, lockfilePath))}`;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=reportLockfileVerification.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/cli.default-reporter",
|
|
3
|
-
"version": "1100.
|
|
3
|
+
"version": "1100.2.0",
|
|
4
4
|
"description": "The default reporter of pnpm",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -42,14 +42,14 @@
|
|
|
42
42
|
"semver": "^7.7.2",
|
|
43
43
|
"stacktracey": "^2.2.0",
|
|
44
44
|
"string-length": "^7.0.1",
|
|
45
|
-
"@pnpm/
|
|
46
|
-
"@pnpm/core-loggers": "1100.0
|
|
47
|
-
"@pnpm/error": "1100.0.0",
|
|
45
|
+
"@pnpm/config.reader": "1101.3.2",
|
|
46
|
+
"@pnpm/core-loggers": "1100.1.0",
|
|
48
47
|
"@pnpm/deps.inspection.peers-issues-renderer": "1100.0.1",
|
|
49
|
-
"@pnpm/
|
|
50
|
-
"@pnpm/
|
|
48
|
+
"@pnpm/error": "1100.0.0",
|
|
49
|
+
"@pnpm/installing.dedupe.issues-renderer": "1100.0.1",
|
|
51
50
|
"@pnpm/installing.dedupe.types": "1100.0.1",
|
|
52
|
-
"@pnpm/
|
|
51
|
+
"@pnpm/types": "1101.1.0",
|
|
52
|
+
"@pnpm/cli.meta": "1100.0.3"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@pnpm/logger": ">=1001.0.0 <1002.0.0"
|
|
@@ -62,8 +62,8 @@
|
|
|
62
62
|
"ghooks": "2.0.4",
|
|
63
63
|
"load-json-file": "^7.0.1",
|
|
64
64
|
"normalize-newline": "5.0.0",
|
|
65
|
-
"@pnpm/
|
|
66
|
-
"@pnpm/
|
|
65
|
+
"@pnpm/logger": "1100.0.0",
|
|
66
|
+
"@pnpm/cli.default-reporter": "1100.2.0"
|
|
67
67
|
},
|
|
68
68
|
"engines": {
|
|
69
69
|
"node": ">=22.13"
|