1use crate::compress::generic::GenericCompressor;
2use crate::compress::{Compressor, Specificity};
3
4pub struct PnpmCompressor;
5
6impl Compressor for PnpmCompressor {
7 fn specificity(&self) -> Specificity {
8 Specificity::PackageManager
9 }
10
11 fn matches(&self, command: &str) -> bool {
12 command
13 .split_whitespace()
14 .next()
15 .is_some_and(|head| head == "pnpm")
16 }
17
18 fn compress(&self, command: &str, output: &str) -> String {
19 match pnpm_subcommand(command).as_deref() {
20 Some("install" | "i" | "add" | "remove") => compress_package(output),
21 Some("run" | "test" | "build") => GenericCompressor::compress_output(output),
22 _ => GenericCompressor::compress_output(output),
23 }
24 }
25}
26
27fn pnpm_subcommand(command: &str) -> Option<String> {
28 command
29 .split_whitespace()
30 .skip_while(|token| *token != "pnpm")
31 .skip(1)
32 .find(|token| !token.starts_with('-'))
33 .map(ToString::to_string)
34}
35
36fn compress_package(output: &str) -> String {
37 let mut result = Vec::new();
38 let mut progress_seen = 0usize;
39 let mut up_to_date_seen = false;
40
41 for line in output.lines() {
42 let trimmed = line.trim_start();
43 if trimmed.starts_with("Progress: resolved ") {
44 progress_seen += 1;
45 if progress_seen > 2 {
46 continue;
47 }
48 }
49 if trimmed == "Already up-to-date" {
50 if up_to_date_seen {
51 continue;
52 }
53 up_to_date_seen = true;
54 }
55 if trimmed.contains("WARN GET_NO_AUTH")
56 || trimmed.starts_with("ERR_PNPM_")
57 || trimmed.starts_with("Progress: resolved ")
58 || trimmed == "Already up-to-date"
59 || trimmed.starts_with("dependencies:")
60 || trimmed.starts_with("devDependencies:")
61 || trimmed.starts_with("Done in ")
62 {
63 result.push(line.to_string());
64 }
65 }
66
67 trim_trailing_lines(&result.join("\n"))
68}
69
70fn trim_trailing_lines(input: &str) -> String {
71 input
72 .lines()
73 .map(str::trim_end)
74 .collect::<Vec<_>>()
75 .join("\n")
76}