Skip to main content

aft/compress/
pnpm.rs

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}