Skip to content

Commit e89d228

Browse files
committed
fix: report ok for silent npm scripts
1 parent 4338f02 commit e89d228

1 file changed

Lines changed: 65 additions & 4 deletions

File tree

src/cmds/js/npm_cmd.rs

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -135,17 +135,24 @@ fn run_filtered(name: &str, args: &[String], verbose: u8, skip_env: bool) -> Res
135135
/// Filter npm run output - strip boilerplate, progress bars, npm WARN
136136
fn filter_npm_output(output: &str) -> String {
137137
let mut result = Vec::new();
138+
let mut seen_substantive_output = false;
139+
let mut leading_gt_lines = Vec::new();
138140

139141
for line in output.lines() {
140-
// Skip npm boilerplate
141-
if line.starts_with('>') && line.contains('@') {
142+
let trimmed = line.trim_start();
143+
144+
// npm 7+ emits script name and command as leading `> ` lines without
145+
// package@version. Treat 2+ leading lines as lifecycle echo so silent
146+
// scripts can fall back to `ok`, but preserve one as possible output.
147+
if !seen_substantive_output && trimmed.starts_with("> ") {
148+
leading_gt_lines.push(line.to_string());
142149
continue;
143150
}
144151
// Skip npm lifecycle scripts
145-
if line.trim_start().starts_with("npm WARN") {
152+
if trimmed.starts_with("npm WARN") {
146153
continue;
147154
}
148-
if line.trim_start().starts_with("npm notice") {
155+
if trimmed.starts_with("npm notice") {
149156
continue;
150157
}
151158
// Skip progress indicators
@@ -157,9 +164,21 @@ fn filter_npm_output(output: &str) -> String {
157164
continue;
158165
}
159166

167+
if !seen_substantive_output {
168+
if leading_gt_lines.len() == 1 {
169+
result.extend(leading_gt_lines.drain(..));
170+
} else {
171+
leading_gt_lines.clear();
172+
}
173+
}
174+
seen_substantive_output = true;
160175
result.push(line.to_string());
161176
}
162177

178+
if !seen_substantive_output && leading_gt_lines.len() == 1 {
179+
result.extend(leading_gt_lines);
180+
}
181+
163182
if result.is_empty() {
164183
"ok".to_string()
165184
} else {
@@ -234,4 +253,46 @@ npm notice
234253
let result = filter_npm_output(output);
235254
assert_eq!(result, "ok");
236255
}
256+
257+
#[test]
258+
fn test_filter_npm_output_lifecycle_only_success() {
259+
let output = r#"
260+
> typecheck
261+
> tsc --noEmit
262+
"#;
263+
let result = filter_npm_output(output);
264+
assert_eq!(result, "ok");
265+
}
266+
267+
#[test]
268+
fn test_filter_npm_output_preserves_substantive_output() {
269+
let output = r#"
270+
> test
271+
> node test.js
272+
TEST_PASS
273+
"#;
274+
let result = filter_npm_output(output);
275+
assert_eq!(result, "TEST_PASS");
276+
}
277+
278+
#[test]
279+
fn test_filter_npm_output_preserves_gt_after_substantive_output() {
280+
let output = r#"
281+
> test
282+
> node test.js
283+
error:
284+
> pointer context
285+
"#;
286+
let result = filter_npm_output(output);
287+
assert_eq!(result, "error:\n> pointer context");
288+
}
289+
290+
#[test]
291+
fn test_filter_npm_output_preserves_single_leading_gt_output() {
292+
let output = r#"
293+
> user output
294+
"#;
295+
let result = filter_npm_output(output);
296+
assert_eq!(result, "> user output");
297+
}
237298
}

0 commit comments

Comments
 (0)