lean_ctx/core/patterns/
prisma.rs1pub fn compress(cmd: &str, output: &str) -> Option<String> {
2 let trimmed = output.trim();
3 if trimmed.is_empty() {
4 return Some("ok".to_string());
5 }
6
7 if cmd.contains("generate") {
8 return Some(compress_generate(trimmed));
9 }
10 if cmd.contains("migrate") {
11 return Some(compress_migrate(trimmed));
12 }
13 if cmd.contains("db push") || cmd.contains("db pull") {
14 return Some(compress_db_sync(trimmed));
15 }
16 if cmd.contains("studio") {
17 return Some("Prisma Studio started".to_string());
18 }
19 if cmd.contains("format") {
20 return Some(compress_format(trimmed));
21 }
22 if cmd.contains("validate") {
23 return Some(compress_validate(trimmed));
24 }
25
26 Some(compact_lines(trimmed, 10))
27}
28
29fn compress_generate(output: &str) -> String {
30 let mut generated = Vec::new();
31 for line in output.lines() {
32 let trimmed = line.trim();
33 let plain = strip_ansi(trimmed);
34 if plain.contains("Generated") || plain.contains("generated") {
35 generated.push(plain);
36 }
37 }
38 if generated.is_empty() {
39 return strip_noise(output);
40 }
41 generated.join("\n")
42}
43
44fn compress_migrate(output: &str) -> String {
45 let mut results = Vec::new();
46 let mut migration_name = String::new();
47
48 for line in output.lines() {
49 let plain = strip_ansi(line.trim());
50 if plain.contains("migration") && plain.contains("created") {
51 migration_name = plain.clone();
52 }
53 if plain.contains("applied")
54 || plain.contains("Already in sync")
55 || plain.contains("Database is up to date")
56 {
57 results.push(plain);
58 }
59 }
60
61 if results.is_empty() && migration_name.is_empty() {
62 return strip_noise(output);
63 }
64
65 let mut parts = Vec::new();
66 if !migration_name.is_empty() {
67 parts.push(migration_name);
68 }
69 parts.extend(results);
70 parts.join("\n")
71}
72
73fn compress_db_sync(output: &str) -> String {
74 let lines: Vec<String> = output
75 .lines()
76 .map(|l| strip_ansi(l.trim()))
77 .filter(|l| !l.is_empty() && !l.contains("warn") && !l.starts_with("Prisma schema"))
78 .collect();
79
80 if lines.is_empty() {
81 return "ok (synced)".to_string();
82 }
83 lines.join("\n")
84}
85
86fn compress_format(output: &str) -> String {
87 if output.contains("already formatted") || output.contains("unchanged") {
88 return "ok (already formatted)".to_string();
89 }
90 strip_noise(output)
91}
92
93fn compress_validate(output: &str) -> String {
94 let plain = strip_ansi(output.trim());
95 if plain.contains("valid") && !plain.contains("invalid") {
96 return "ok (schema valid)".to_string();
97 }
98 compact_lines(&plain, 10)
99}
100
101fn strip_noise(output: &str) -> String {
102 output
103 .lines()
104 .map(|l| strip_ansi(l.trim()))
105 .filter(|l| !l.is_empty() && !l.contains("████") && !l.contains("▀") && !l.contains("━"))
106 .collect::<Vec<_>>()
107 .join("\n")
108}
109
110fn strip_ansi(s: &str) -> String {
111 let mut result = String::with_capacity(s.len());
112 let mut in_escape = false;
113 for c in s.chars() {
114 if c == '\x1b' {
115 in_escape = true;
116 } else if in_escape {
117 if c.is_ascii_alphabetic() {
118 in_escape = false;
119 }
120 } else {
121 result.push(c);
122 }
123 }
124 result
125}
126
127fn compact_lines(text: &str, max: usize) -> String {
128 let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
129 if lines.len() <= max {
130 return lines.join("\n");
131 }
132 format!(
133 "{}\n... ({} more lines)",
134 lines[..max].join("\n"),
135 lines.len() - max
136 )
137}