@pnpm/cli.default-reporter 1100.3.11 → 1100.3.13

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 (61) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/lib/cli.d.ts +1 -0
  3. package/lib/cli.js +50 -0
  4. package/lib/constants.d.ts +1 -0
  5. package/lib/constants.js +4 -0
  6. package/lib/index.d.ts +54 -0
  7. package/lib/mergeOutputs.d.ts +4 -0
  8. package/lib/mergeOutputs.js +69 -0
  9. package/lib/reportError.d.ts +3 -0
  10. package/lib/reportError.js +426 -0
  11. package/lib/reporterForClient/index.d.ts +53 -0
  12. package/lib/reporterForClient/index.js +98 -0
  13. package/lib/reporterForClient/outputConstants.d.ts +4 -0
  14. package/lib/reporterForClient/outputConstants.js +6 -0
  15. package/lib/reporterForClient/pkgsDiff.d.ts +36 -0
  16. package/lib/reporterForClient/pkgsDiff.js +113 -0
  17. package/lib/reporterForClient/reportBigTarballsProgress.d.ts +8 -0
  18. package/lib/reporterForClient/reportBigTarballsProgress.js +26 -0
  19. package/lib/reporterForClient/reportContext.d.ts +10 -0
  20. package/lib/reporterForClient/reportContext.js +34 -0
  21. package/lib/reporterForClient/reportDeprecations.d.ts +11 -0
  22. package/lib/reporterForClient/reportDeprecations.js +27 -0
  23. package/lib/reporterForClient/reportExecutionTime.d.ts +6 -0
  24. package/lib/reporterForClient/reportExecutionTime.js +13 -0
  25. package/lib/reporterForClient/reportHooks.d.ts +8 -0
  26. package/lib/reporterForClient/reportHooks.js +12 -0
  27. package/lib/reporterForClient/reportIgnoredBuilds.d.ts +11 -0
  28. package/lib/reporterForClient/reportIgnoredBuilds.js +21 -0
  29. package/lib/reporterForClient/reportInstallChecks.d.ts +7 -0
  30. package/lib/reporterForClient/reportInstallChecks.js +19 -0
  31. package/lib/reporterForClient/reportInstallingConfigDeps.d.ts +5 -0
  32. package/lib/reporterForClient/reportInstallingConfigDeps.js +18 -0
  33. package/lib/reporterForClient/reportLifecycleScripts.d.ts +13 -0
  34. package/lib/reporterForClient/reportLifecycleScripts.js +197 -0
  35. package/lib/reporterForClient/reportLockfileVerification.d.ts +15 -0
  36. package/lib/reporterForClient/reportLockfileVerification.js +73 -0
  37. package/lib/reporterForClient/reportMisc.d.ts +17 -0
  38. package/lib/reporterForClient/reportMisc.js +69 -0
  39. package/lib/reporterForClient/reportPeerDependencyIssues.d.ts +7 -0
  40. package/lib/reporterForClient/reportPeerDependencyIssues.js +11 -0
  41. package/lib/reporterForClient/reportProgress.d.ts +16 -0
  42. package/lib/reporterForClient/reportProgress.js +123 -0
  43. package/lib/reporterForClient/reportRequestRetry.d.ts +5 -0
  44. package/lib/reporterForClient/reportRequestRetry.js +18 -0
  45. package/lib/reporterForClient/reportScope.d.ts +8 -0
  46. package/lib/reporterForClient/reportScope.js +41 -0
  47. package/lib/reporterForClient/reportSkippedOptionalDependencies.d.ts +7 -0
  48. package/lib/reporterForClient/reportSkippedOptionalDependencies.js +8 -0
  49. package/lib/reporterForClient/reportStats.d.ts +13 -0
  50. package/lib/reporterForClient/reportStats.js +143 -0
  51. package/lib/reporterForClient/reportSummary.d.ts +19 -0
  52. package/lib/reporterForClient/reportSummary.js +79 -0
  53. package/lib/reporterForClient/reportUpdateCheck.d.ts +8 -0
  54. package/lib/reporterForClient/reportUpdateCheck.js +42 -0
  55. package/lib/reporterForClient/utils/formatPrefix.d.ts +2 -0
  56. package/lib/reporterForClient/utils/formatPrefix.js +19 -0
  57. package/lib/reporterForClient/utils/formatWarn.d.ts +1 -0
  58. package/lib/reporterForClient/utils/formatWarn.js +5 -0
  59. package/lib/reporterForClient/utils/zooming.d.ts +4 -0
  60. package/lib/reporterForClient/utils/zooming.js +13 -0
  61. package/package.json +15 -15
@@ -0,0 +1,197 @@
1
+ import path from 'node:path';
2
+ import chalk from 'chalk';
3
+ import cliTruncate from 'cli-truncate';
4
+ import prettyTime from 'pretty-ms';
5
+ import * as Rx from 'rxjs';
6
+ import { buffer, filter, groupBy, map, mergeAll, mergeMap } from 'rxjs/operators';
7
+ import { EOL } from '../constants.js';
8
+ import { hlValue } from './outputConstants.js';
9
+ import { formatPrefix, formatPrefixNoTrim } from './utils/formatPrefix.js';
10
+ const NODE_MODULES = `${path.sep}node_modules${path.sep}`;
11
+ const TMP_DIR_IN_STORE = `tmp${path.sep}_tmp_`; // git-hosted dependencies are built in these temporary directories
12
+ // When streaming processes are spawned, use this color for prefix
13
+ const colorWheel = ['cyan', 'magenta', 'blue', 'yellow', 'green', 'red'];
14
+ const NUM_COLORS = colorWheel.length;
15
+ // Ever-increasing index ensures colors are always sequential
16
+ let currentColor = 0;
17
+ export function reportLifecycleScripts(log$, opts) {
18
+ // When the reporter is not append-only, the length of output is limited
19
+ // in order to reduce flickering
20
+ if (opts.appendOnly) {
21
+ let lifecycle$ = log$.lifecycle;
22
+ if (opts.aggregateOutput) {
23
+ lifecycle$ = lifecycle$.pipe(aggregateOutput);
24
+ }
25
+ const streamLifecycleOutput = createStreamLifecycleOutput(opts.cwd, !!opts.hideLifecyclePrefix);
26
+ return lifecycle$.pipe(map((log) => Rx.of({
27
+ msg: streamLifecycleOutput(log),
28
+ })));
29
+ }
30
+ const lifecycleMessages = {};
31
+ const lifecycleStreamByDepPath = {};
32
+ const lifecyclePushStream = new Rx.Subject();
33
+ // TODO: handle promise of .forEach?!
34
+ log$.lifecycle
35
+ .forEach((log) => {
36
+ const key = `${log.stage}:${log.depPath}`;
37
+ lifecycleMessages[key] = lifecycleMessages[key] || {
38
+ collapsed: log.wd.includes(NODE_MODULES) || log.wd.includes(TMP_DIR_IN_STORE),
39
+ output: [],
40
+ startTime: process.hrtime(),
41
+ status: formatIndentedStatus(chalk.magentaBright('Running...')),
42
+ };
43
+ const exit = typeof log['exitCode'] === 'number';
44
+ let msg;
45
+ if (lifecycleMessages[key].collapsed) {
46
+ msg = renderCollapsedScriptOutput(log, lifecycleMessages[key], { cwd: opts.cwd, exit, maxWidth: opts.width });
47
+ }
48
+ else {
49
+ msg = renderScriptOutput(log, lifecycleMessages[key], { cwd: opts.cwd, exit, maxWidth: opts.width });
50
+ }
51
+ if (exit) {
52
+ delete lifecycleMessages[key];
53
+ }
54
+ if (!lifecycleStreamByDepPath[key]) {
55
+ lifecycleStreamByDepPath[key] = new Rx.Subject();
56
+ lifecyclePushStream.next(Rx.from(lifecycleStreamByDepPath[key]));
57
+ }
58
+ lifecycleStreamByDepPath[key].next({ msg });
59
+ if (exit) {
60
+ lifecycleStreamByDepPath[key].complete();
61
+ }
62
+ });
63
+ return Rx.from(lifecyclePushStream);
64
+ }
65
+ function toNano(time) {
66
+ return (time[0] + (time[1] / 1e9)) * 1e3;
67
+ }
68
+ function renderCollapsedScriptOutput(log, messageCache, opts) {
69
+ if (!messageCache.label) {
70
+ messageCache.label = highlightLastFolder(formatPrefixNoTrim(opts.cwd, log.wd));
71
+ if (log.wd.includes(TMP_DIR_IN_STORE)) {
72
+ messageCache.label += ` [${log.depPath}]`;
73
+ }
74
+ messageCache.label += `: Running ${log.stage} script`;
75
+ }
76
+ if (!opts.exit) {
77
+ updateMessageCache(log, messageCache, opts);
78
+ return `${messageCache.label}...`;
79
+ }
80
+ const time = prettyTime(toNano(process.hrtime(messageCache.startTime)));
81
+ if (log.exitCode === 0) {
82
+ return `${messageCache.label}, done in ${time}`;
83
+ }
84
+ if (log.optional === true) {
85
+ return `${messageCache.label}, failed in ${time} (skipped as optional)`;
86
+ }
87
+ return `${messageCache.label}, failed in ${time}${EOL}${renderScriptOutput(log, messageCache, opts)}`;
88
+ }
89
+ function renderScriptOutput(log, messageCache, opts) {
90
+ updateMessageCache(log, messageCache, opts);
91
+ if (opts.exit && log['exitCode'] !== 0) {
92
+ return [
93
+ messageCache.script,
94
+ ...messageCache.output,
95
+ messageCache.status,
96
+ ].join(EOL);
97
+ }
98
+ if (messageCache.output.length > 10) {
99
+ return [
100
+ messageCache.script,
101
+ `[${messageCache.output.length - 10} lines collapsed]`,
102
+ ...messageCache.output.slice(messageCache.output.length - 10),
103
+ messageCache.status,
104
+ ].join(EOL);
105
+ }
106
+ return [
107
+ messageCache.script,
108
+ ...messageCache.output,
109
+ messageCache.status,
110
+ ].join(EOL);
111
+ }
112
+ function updateMessageCache(log, messageCache, opts) {
113
+ if (log.script) {
114
+ const prefix = `${formatPrefix(opts.cwd, log.wd)} ${hlValue(log.stage)}`;
115
+ const maxLineWidth = opts.maxWidth - prefix.length - 2 + ANSI_ESCAPES_LENGTH_OF_PREFIX;
116
+ messageCache.script = `${prefix}$ ${cutLine(log.script, maxLineWidth)}`;
117
+ }
118
+ else if (opts.exit) {
119
+ const time = prettyTime(toNano(process.hrtime(messageCache.startTime)));
120
+ if (log.exitCode === 0) {
121
+ messageCache.status = formatIndentedStatus(chalk.magentaBright(`Done in ${time}`));
122
+ }
123
+ else {
124
+ messageCache.status = formatIndentedStatus(chalk.red(`Failed in ${time} at ${log.wd}`));
125
+ }
126
+ }
127
+ else {
128
+ messageCache.output.push(formatIndentedOutput(opts.maxWidth, log));
129
+ }
130
+ }
131
+ function formatIndentedStatus(status) {
132
+ return `${chalk.magentaBright('└─')} ${status}`;
133
+ }
134
+ function highlightLastFolder(p) {
135
+ const lastSlash = p.lastIndexOf('/') + 1;
136
+ return `${chalk.gray(p.slice(0, lastSlash))}${p.slice(lastSlash)}`;
137
+ }
138
+ const ANSI_ESCAPES_LENGTH_OF_PREFIX = hlValue(' ').length - 1;
139
+ function createStreamLifecycleOutput(cwd, hideLifecyclePrefix) {
140
+ currentColor = 0;
141
+ const colorByPrefix = new Map();
142
+ return streamLifecycleOutput.bind(null, colorByPrefix, cwd, hideLifecyclePrefix);
143
+ }
144
+ function streamLifecycleOutput(colorByPkg, cwd, hideLifecyclePrefix, logObj) {
145
+ const prefix = formatLifecycleScriptPrefix(colorByPkg, cwd, logObj.wd, logObj.stage);
146
+ if (typeof logObj.exitCode === 'number') {
147
+ if (logObj.exitCode === 0) {
148
+ return `${prefix}: Done`;
149
+ }
150
+ else {
151
+ return `${prefix}: Failed`;
152
+ }
153
+ }
154
+ if (logObj['script']) {
155
+ return `${prefix}$ ${logObj['script']}`;
156
+ }
157
+ const line = formatLine(Infinity, logObj);
158
+ return hideLifecyclePrefix ? line : `${prefix}: ${line}`;
159
+ }
160
+ function formatIndentedOutput(maxWidth, logObj) {
161
+ return `${chalk.magentaBright('│')} ${formatLine(maxWidth - 2, logObj)}`;
162
+ }
163
+ function formatLifecycleScriptPrefix(colorByPkg, cwd, wd, stage) {
164
+ if (!colorByPkg.has(wd)) {
165
+ const colorName = colorWheel[currentColor % NUM_COLORS];
166
+ colorByPkg.set(wd, chalk[colorName]);
167
+ currentColor += 1;
168
+ }
169
+ const color = colorByPkg.get(wd);
170
+ return `${color(formatPrefix(cwd, wd))} ${hlValue(stage)}`;
171
+ }
172
+ function formatLine(maxWidth, logObj) {
173
+ const line = cutLine(logObj.line, maxWidth);
174
+ // TODO: strip only the non-color/style ansi escape codes
175
+ if (logObj.stdio === 'stderr') {
176
+ return chalk.gray(line);
177
+ }
178
+ return line;
179
+ }
180
+ function cutLine(line, maxLength) {
181
+ if (!line)
182
+ return '';
183
+ // Streamed lifecycle output is printed in full (maxLength is Infinity).
184
+ // cli-truncate rejects a non-finite width, so skip truncation in that case.
185
+ if (!Number.isFinite(maxLength))
186
+ return line;
187
+ return cliTruncate(line, maxLength);
188
+ }
189
+ function aggregateOutput(source) {
190
+ return source.pipe(
191
+ // The '\0' is a null character which delimits these strings. This works since JS doesn't use
192
+ // null-terminated strings.
193
+ groupBy((data) => `${data.depPath}\0${data.stage}`), mergeMap(group => {
194
+ return group.pipe(buffer(group.pipe(filter(msg => 'exitCode' in msg))));
195
+ }), map(ar => Rx.from(ar)), mergeAll());
196
+ }
197
+ //# sourceMappingURL=reportLifecycleScripts.js.map
@@ -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,73 @@
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 when the reporter redraws in place. In
11
+ // appendOnly mode both lines are printed.
12
+ return Rx.of(lockfileVerification$.pipe(map((log) => {
13
+ const path_ = formatLockfilePath(log.lockfilePath, opts.cwd, expectedDir);
14
+ if (log.status === 'cached') {
15
+ return {
16
+ msg: `${chalk.green('✓')} Lockfile${path_} passes supply-chain policies (${formatCachedVerdict(log.verifiedAt)})`,
17
+ };
18
+ }
19
+ const entries = `${log.entries} ${log.entries === 1 ? 'entry' : 'entries'}`;
20
+ switch (log.status) {
21
+ case 'started':
22
+ return {
23
+ msg: `${chalk.cyan('?')} Verifying lockfile${path_} against supply-chain policies (${entries})...`,
24
+ };
25
+ case 'done':
26
+ return {
27
+ msg: `${chalk.green('✓')} Lockfile${path_} passes supply-chain policies (${entries} in ${prettyMs(log.elapsedMs)})`,
28
+ };
29
+ case 'failed':
30
+ // Brief one-liner so the transient `started` frame doesn't
31
+ // stay on screen above the detailed PnpmError block that the
32
+ // error reporter prints next.
33
+ return {
34
+ msg: `${chalk.red('✗')} Lockfile${path_} failed supply-chain policy check (${entries} in ${prettyMs(log.elapsedMs)})`,
35
+ };
36
+ }
37
+ })));
38
+ }
39
+ // Relative "verified 2h ago" when the cached record carries a parseable
40
+ // timestamp; the timeless "previously verified" otherwise. The elapsed
41
+ // time is clamped at zero so a clock that moved backwards between the
42
+ // verification run and this install doesn't render a negative age.
43
+ function formatCachedVerdict(verifiedAt) {
44
+ if (verifiedAt == null)
45
+ return 'previously verified';
46
+ const elapsedMs = Date.now() - Date.parse(verifiedAt);
47
+ if (Number.isNaN(elapsedMs))
48
+ return 'previously verified';
49
+ return `verified ${prettyMs(Math.max(elapsedMs, 0), { compact: true })} ago`;
50
+ }
51
+ // Returns a leading-space-prefixed `at <path>` suffix only when the
52
+ // lockfile sits outside the obvious project/workspace root — otherwise
53
+ // the path is implied and printing it would just add noise to every
54
+ // install. Empty string when the path is omitted or matches the
55
+ // expected location.
56
+ //
57
+ // Uses `path.relative` rather than a strict `===` between
58
+ // `path.dirname(lockfilePath)` and `expectedDir`: relative path
59
+ // computation normalizes slash direction and trailing separators, so
60
+ // a workspaceDir like `C:/repo/` correctly matches a lockfilePath at
61
+ // `C:\repo\pnpm-lock.yaml` on Windows. The lockfile is considered
62
+ // "inside the expected dir" when the relative path is a bare file
63
+ // name (no separator) that doesn't escape upward.
64
+ function formatLockfilePath(lockfilePath, cwd, expectedDir) {
65
+ if (lockfilePath == null)
66
+ return '';
67
+ const fromExpected = path.relative(expectedDir, lockfilePath);
68
+ const isDirectChild = !fromExpected.includes(path.sep) && !fromExpected.startsWith('..');
69
+ if (isDirectChild)
70
+ return '';
71
+ return ` at ${normalize(path.relative(cwd, lockfilePath))}`;
72
+ }
73
+ //# sourceMappingURL=reportLockfileVerification.js.map
@@ -0,0 +1,17 @@
1
+ import type { Config } from '@pnpm/config.reader';
2
+ import type { Log, RegistryLog } from '@pnpm/core-loggers';
3
+ import type { LogLevel } from '@pnpm/logger';
4
+ import * as Rx from 'rxjs';
5
+ export declare const LOG_LEVEL_NUMBER: Record<LogLevel, number>;
6
+ export declare function reportMisc(log$: {
7
+ registry: Rx.Observable<RegistryLog>;
8
+ other: Rx.Observable<Log>;
9
+ }, opts: {
10
+ appendOnly: boolean;
11
+ cwd: string;
12
+ logLevel?: LogLevel;
13
+ config?: Config;
14
+ zoomOutCurrent: boolean;
15
+ }): Rx.Observable<Rx.Observable<{
16
+ msg: string;
17
+ }>>;
@@ -0,0 +1,69 @@
1
+ import os from 'node:os';
2
+ import * as Rx from 'rxjs';
3
+ import { filter, map } from 'rxjs/operators';
4
+ import { reportError } from '../reportError.js';
5
+ import { formatWarn } from './utils/formatWarn.js';
6
+ import { autozoom } from './utils/zooming.js';
7
+ // eslint-disable:object-literal-sort-keys
8
+ export const LOG_LEVEL_NUMBER = {
9
+ error: 0,
10
+ warn: 1,
11
+ info: 2,
12
+ debug: 3,
13
+ };
14
+ // eslint-enable:object-literal-sort-keys
15
+ const MAX_SHOWN_WARNINGS = 5;
16
+ export function reportMisc(log$, opts) {
17
+ const maxLogLevel = LOG_LEVEL_NUMBER[opts.logLevel ?? 'info'] ?? LOG_LEVEL_NUMBER['info'];
18
+ const reportWarning = makeWarningReporter(opts);
19
+ return Rx.merge(log$.registry, log$.other).pipe(filter((obj) => LOG_LEVEL_NUMBER[obj.level] <= maxLogLevel &&
20
+ (obj.level !== 'info' || !obj['prefix'] || obj['prefix'] === opts.cwd)), map((obj) => {
21
+ switch (obj.level) {
22
+ case 'warn': {
23
+ return reportWarning(obj);
24
+ }
25
+ case 'error': {
26
+ const errorOutput = reportError(obj, opts.config);
27
+ if (!errorOutput)
28
+ return Rx.NEVER;
29
+ if (obj['prefix'] && obj['prefix'] !== opts.cwd) {
30
+ return Rx.of({
31
+ msg: `${obj['prefix']}:` + os.EOL + errorOutput,
32
+ });
33
+ }
34
+ return Rx.of({ msg: errorOutput });
35
+ }
36
+ default:
37
+ return Rx.of({ msg: obj.message });
38
+ }
39
+ }));
40
+ }
41
+ // Sometimes, when installing new dependencies that rely on many peer dependencies,
42
+ // or when running installation on a huge monorepo, there will be hundreds or thousands of warnings.
43
+ // Printing many messages to the terminal is expensive and reduces speed,
44
+ // so pnpm will only print a few warnings and report the total number of the unprinted warnings.
45
+ function makeWarningReporter(opts) {
46
+ let warningsCounter = 0;
47
+ let collapsedWarnings;
48
+ return (obj) => {
49
+ warningsCounter++;
50
+ if (opts.appendOnly || warningsCounter <= MAX_SHOWN_WARNINGS) {
51
+ return Rx.of({ msg: autozoom(opts.cwd, obj.prefix, formatWarn(obj.message), opts) });
52
+ }
53
+ const warningMsg = formatWarn(`${warningsCounter - MAX_SHOWN_WARNINGS} other warnings`);
54
+ if (!collapsedWarnings) {
55
+ collapsedWarnings = new Rx.Subject();
56
+ // For some reason, without using setTimeout, the warning summary is printed above the rest of the warnings
57
+ // Even though the summary event happens last. Probably a bug in "most".
58
+ setTimeout(() => {
59
+ collapsedWarnings.next({ msg: warningMsg });
60
+ }, 0);
61
+ return Rx.from(collapsedWarnings);
62
+ }
63
+ setTimeout(() => {
64
+ collapsedWarnings.next({ msg: warningMsg });
65
+ }, 0);
66
+ return Rx.NEVER;
67
+ };
68
+ }
69
+ //# sourceMappingURL=reportMisc.js.map
@@ -0,0 +1,7 @@
1
+ import type { PeerDependencyIssuesLog } from '@pnpm/core-loggers';
2
+ import * as Rx from 'rxjs';
3
+ export declare function reportPeerDependencyIssues(log$: {
4
+ peerDependencyIssues: Rx.Observable<PeerDependencyIssuesLog>;
5
+ }): Rx.Observable<Rx.Observable<{
6
+ msg: string;
7
+ }>>;
@@ -0,0 +1,11 @@
1
+ import * as Rx from 'rxjs';
2
+ import { map, take } from 'rxjs/operators';
3
+ import { formatWarn } from './utils/formatWarn.js';
4
+ export function reportPeerDependencyIssues(log$) {
5
+ return log$.peerDependencyIssues.pipe(take(1), map(() => {
6
+ return Rx.of({
7
+ msg: formatWarn('Issues with peer dependencies found. Run "pnpm peers check" to list them.'),
8
+ });
9
+ }));
10
+ }
11
+ //# sourceMappingURL=reportPeerDependencyIssues.js.map
@@ -0,0 +1,16 @@
1
+ import type { ProgressLog, StageLog } from '@pnpm/core-loggers';
2
+ import * as Rx from 'rxjs';
3
+ export interface StatusMessage {
4
+ msg: string;
5
+ fixed: boolean;
6
+ done?: boolean;
7
+ }
8
+ export declare function reportProgress(log$: {
9
+ progress: Rx.Observable<ProgressLog>;
10
+ stage: Rx.Observable<StageLog>;
11
+ }, opts: {
12
+ cwd: string;
13
+ throttle?: Rx.OperatorFunction<any, any>;
14
+ hideAddedPkgsProgress?: boolean;
15
+ hideProgressPrefix?: boolean;
16
+ }): Rx.Observable<Rx.Observable<StatusMessage>>;
@@ -0,0 +1,123 @@
1
+ import * as Rx from 'rxjs';
2
+ import { filter, map, mapTo, startWith, take, takeWhile } from 'rxjs/operators';
3
+ import { hlValue } from './outputConstants.js';
4
+ import { zoomOut } from './utils/zooming.js';
5
+ export function reportProgress(log$, opts) {
6
+ const progressOutput = throttledProgressOutput.bind(null, opts);
7
+ return getModulesInstallProgress$(log$.stage, log$.progress).pipe(map(opts.hideProgressPrefix
8
+ ? ({ importingDone$, progress$ }) => progressOutput(importingDone$, progress$)
9
+ : ({ importingDone$, progress$, requirer }) => {
10
+ const output$ = progressOutput(importingDone$, progress$);
11
+ if (requirer === opts.cwd) {
12
+ return output$;
13
+ }
14
+ return output$.pipe(map((msg) => {
15
+ msg['msg'] = zoomOut(opts.cwd, requirer, msg['msg']);
16
+ return msg;
17
+ }));
18
+ }));
19
+ }
20
+ function throttledProgressOutput(opts, importingDone$, progress$) {
21
+ if (opts.throttle != null) {
22
+ progress$ = progress$.pipe(opts.throttle);
23
+ }
24
+ const combinedProgress = Rx.combineLatest(progress$, importingDone$)
25
+ // Avoid logs after all resolved packages were downloaded.
26
+ // Fixing issue: https://github.com/pnpm/pnpm/issues/1028#issuecomment-364782901
27
+ .pipe(takeWhile(([, importingDone]) => !importingDone, true));
28
+ return combinedProgress.pipe(map(opts.hideAddedPkgsProgress ? createStatusMessageWithoutAdded : createStatusMessage));
29
+ }
30
+ function getModulesInstallProgress$(stage$, progress$) {
31
+ const modulesInstallProgressPushStream = new Rx.Subject();
32
+ const progressStatsPushStreamByRequirer = getProgressStatsPushStreamByRequirer(progress$);
33
+ const stagePushStreamByRequirer = {};
34
+ stage$
35
+ .forEach((log) => {
36
+ if (!stagePushStreamByRequirer[log.prefix]) {
37
+ stagePushStreamByRequirer[log.prefix] = new Rx.Subject();
38
+ if (!progressStatsPushStreamByRequirer[log.prefix]) {
39
+ progressStatsPushStreamByRequirer[log.prefix] = new Rx.Subject();
40
+ }
41
+ modulesInstallProgressPushStream.next({
42
+ importingDone$: stage$ToImportingDone$(Rx.from(stagePushStreamByRequirer[log.prefix])),
43
+ progress$: Rx.from(progressStatsPushStreamByRequirer[log.prefix]),
44
+ requirer: log.prefix,
45
+ });
46
+ }
47
+ stagePushStreamByRequirer[log.prefix].next(log);
48
+ if (log.stage === 'importing_done') {
49
+ progressStatsPushStreamByRequirer[log.prefix].complete();
50
+ stagePushStreamByRequirer[log.prefix].complete();
51
+ }
52
+ })
53
+ .catch(() => { });
54
+ return Rx.from(modulesInstallProgressPushStream);
55
+ }
56
+ function stage$ToImportingDone$(stage$) {
57
+ return stage$
58
+ .pipe(filter((log) => log.stage === 'importing_done'), mapTo(true), take(1), startWith(false));
59
+ }
60
+ function getProgressStatsPushStreamByRequirer(progress$) {
61
+ const progressStatsPushStreamByRequirer = {};
62
+ const previousProgressStatsByRequirer = {};
63
+ progress$
64
+ .forEach((log) => {
65
+ if (!previousProgressStatsByRequirer[log.requester]) {
66
+ previousProgressStatsByRequirer[log.requester] = {
67
+ fetched: 0,
68
+ imported: 0,
69
+ resolved: 0,
70
+ reused: 0,
71
+ };
72
+ }
73
+ switch (log.status) {
74
+ case 'resolved':
75
+ previousProgressStatsByRequirer[log.requester].resolved++;
76
+ break;
77
+ case 'fetched':
78
+ previousProgressStatsByRequirer[log.requester].fetched++;
79
+ break;
80
+ case 'found_in_store':
81
+ previousProgressStatsByRequirer[log.requester].reused++;
82
+ break;
83
+ case 'imported':
84
+ previousProgressStatsByRequirer[log.requester].imported++;
85
+ break;
86
+ }
87
+ if (!progressStatsPushStreamByRequirer[log.requester]) {
88
+ progressStatsPushStreamByRequirer[log.requester] = new Rx.Subject();
89
+ }
90
+ progressStatsPushStreamByRequirer[log.requester].next(previousProgressStatsByRequirer[log.requester]);
91
+ })
92
+ .catch(() => { });
93
+ return progressStatsPushStreamByRequirer;
94
+ }
95
+ function createStatusMessage([progress, importingDone]) {
96
+ const msg = `Progress: resolved ${hlValue(progress.resolved.toString())}, reused ${hlValue(progress.reused.toString())}, downloaded ${hlValue(progress.fetched.toString())}, added ${hlValue(progress.imported.toString())}`;
97
+ if (importingDone) {
98
+ return {
99
+ done: true,
100
+ fixed: false,
101
+ msg: `${msg}, done`,
102
+ };
103
+ }
104
+ return {
105
+ fixed: true,
106
+ msg,
107
+ };
108
+ }
109
+ function createStatusMessageWithoutAdded([progress, importingDone]) {
110
+ const msg = `Progress: resolved ${hlValue(progress.resolved.toString())}, reused ${hlValue(progress.reused.toString())}, downloaded ${hlValue(progress.fetched.toString())}`;
111
+ if (importingDone) {
112
+ return {
113
+ done: true,
114
+ fixed: false,
115
+ msg: `${msg}, done`,
116
+ };
117
+ }
118
+ return {
119
+ fixed: true,
120
+ msg,
121
+ };
122
+ }
123
+ //# sourceMappingURL=reportProgress.js.map
@@ -0,0 +1,5 @@
1
+ import type { RequestRetryLog } from '@pnpm/core-loggers';
2
+ import * as Rx from 'rxjs';
3
+ export declare function reportRequestRetry(requestRetry$: Rx.Observable<RequestRetryLog>): Rx.Observable<Rx.Observable<{
4
+ msg: string;
5
+ }>>;
@@ -0,0 +1,18 @@
1
+ import prettyMilliseconds from 'pretty-ms';
2
+ import * as Rx from 'rxjs';
3
+ import { map } from 'rxjs/operators';
4
+ import { formatWarn } from './utils/formatWarn.js';
5
+ export function reportRequestRetry(requestRetry$) {
6
+ return requestRetry$.pipe(map((log) => {
7
+ const retriesLeft = log.maxRetries - log.attempt + 1;
8
+ // Extract error code from various possible locations
9
+ // HTTP status codes are numeric, system error codes are strings
10
+ const errorCode = log.error.status ?? log.error.statusCode ?? log.error.code ?? log.error.errno ??
11
+ log.error.cause?.code ?? log.error.cause?.errno ?? 'unknown';
12
+ const msg = `${log.method} ${log.url} error (${errorCode}). \
13
+ Will retry in ${prettyMilliseconds(log.timeout, { verbose: true })}. \
14
+ ${retriesLeft} retries left.`;
15
+ return Rx.of({ msg: formatWarn(msg) });
16
+ }));
17
+ }
18
+ //# sourceMappingURL=reportRequestRetry.js.map
@@ -0,0 +1,8 @@
1
+ import type { ScopeLog } from '@pnpm/core-loggers';
2
+ import * as Rx from 'rxjs';
3
+ export declare function reportScope(scope$: Rx.Observable<ScopeLog>, opts: {
4
+ isRecursive: boolean;
5
+ cmd: string;
6
+ }): Rx.Observable<Rx.Observable<{
7
+ msg: string;
8
+ }>>;
@@ -0,0 +1,41 @@
1
+ import * as Rx from 'rxjs';
2
+ import { map, take } from 'rxjs/operators';
3
+ const COMMANDS_THAT_REPORT_SCOPE = new Set([
4
+ 'install',
5
+ 'link',
6
+ 'prune',
7
+ 'rebuild',
8
+ 'remove',
9
+ 'unlink',
10
+ 'update',
11
+ 'run',
12
+ 'test',
13
+ ]);
14
+ export function reportScope(scope$, opts) {
15
+ if (!COMMANDS_THAT_REPORT_SCOPE.has(opts.cmd)) {
16
+ return Rx.NEVER;
17
+ }
18
+ return scope$.pipe(take(1), map((log) => {
19
+ if (log.selected === 1) {
20
+ return Rx.NEVER;
21
+ }
22
+ let msg = 'Scope: ';
23
+ if (log.selected === log.total) {
24
+ msg += `all ${log.total}`;
25
+ }
26
+ else {
27
+ msg += `${log.selected}`;
28
+ if (log.total) {
29
+ msg += ` of ${log.total}`;
30
+ }
31
+ }
32
+ if (log.workspacePrefix) {
33
+ msg += ' workspace projects';
34
+ }
35
+ else {
36
+ msg += ' projects';
37
+ }
38
+ return Rx.of({ msg });
39
+ }));
40
+ }
41
+ //# sourceMappingURL=reportScope.js.map
@@ -0,0 +1,7 @@
1
+ import type { SkippedOptionalDependencyLog } from '@pnpm/core-loggers';
2
+ import * as Rx from 'rxjs';
3
+ export declare function reportSkippedOptionalDependencies(skippedOptionalDependency$: Rx.Observable<SkippedOptionalDependencyLog>, opts: {
4
+ cwd: string;
5
+ }): Rx.Observable<Rx.Observable<{
6
+ msg: string;
7
+ }>>;
@@ -0,0 +1,8 @@
1
+ import * as Rx from 'rxjs';
2
+ import { filter, map } from 'rxjs/operators';
3
+ export function reportSkippedOptionalDependencies(skippedOptionalDependency$, opts) {
4
+ return skippedOptionalDependency$.pipe(filter((log) => Boolean(log['prefix'] === opts.cwd && log.parents && log.parents.length === 0)), map((log) => Rx.of({
5
+ msg: `info: ${log.package.id || log.package.name && (`${log.package.name}@${log.package.version}`) || log.package.bareSpecifier} is an optional dependency and failed compatibility check. Excluding it from installation.`,
6
+ })));
7
+ }
8
+ //# sourceMappingURL=reportSkippedOptionalDependencies.js.map
@@ -0,0 +1,13 @@
1
+ import type { StatsLog } from '@pnpm/core-loggers';
2
+ import * as Rx from 'rxjs';
3
+ export declare function reportStats(log$: {
4
+ stats: Rx.Observable<StatsLog>;
5
+ }, opts: {
6
+ cmd: string;
7
+ cwd: string;
8
+ isRecursive: boolean;
9
+ width: number;
10
+ hideProgressPrefix?: boolean;
11
+ }): Array<Rx.Observable<Rx.Observable<{
12
+ msg: string;
13
+ }>>>;