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