Skip to content

Commit a24c36e

Browse files
committed
refactor(language-server/tsgolint): use an iterator for tsgolint message parsing (#14298)
1 parent 8be432a commit a24c36e

File tree

1 file changed

+45
-75
lines changed

1 file changed

+45
-75
lines changed

crates/oxc_linter/src/tsgolint.rs

Lines changed: 45 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -292,91 +292,61 @@ impl TsGoLintState {
292292
drop(stdin);
293293

294294
// Stream diagnostics as they are emitted, rather than waiting for all output
295-
let mut stdout = child.stdout.take().expect("Failed to open tsgolint stdout");
295+
let stdout = child.stdout.take().expect("Failed to open tsgolint stdout");
296296

297297
let stdout_handler =
298298
std::thread::spawn(move || -> Result<Vec<MessageWithPosition<'_>>, String> {
299-
let mut buffer = Vec::with_capacity(8192);
300-
let mut read_buf = [0u8; 8192];
299+
let msg_iter = TsGoLintMessageStream::new(stdout);
301300

302301
let mut result = vec![];
303302

304-
loop {
305-
match stdout.read(&mut read_buf) {
306-
Ok(0) => break, // EOF
307-
Ok(n) => {
308-
buffer.extend_from_slice(&read_buf[..n]);
309-
310-
// Try to parse complete messages from buffer
311-
let mut cursor = std::io::Cursor::new(buffer.as_slice());
312-
let mut processed_up_to: u64 = 0;
313-
314-
while cursor.position() < buffer.len() as u64 {
315-
let start_pos = cursor.position();
316-
match parse_single_message(&mut cursor) {
317-
Ok(TsGoLintMessage::Error(err)) => {
318-
return Err(err.error);
319-
}
320-
Ok(TsGoLintMessage::Diagnostic(tsgolint_diagnostic)) => {
321-
processed_up_to = cursor.position();
322-
323-
let path = tsgolint_diagnostic.file_path.clone();
324-
let Some(resolved_config) = resolved_configs.get(&path)
325-
else {
326-
// If we don't have a resolved config for this path, skip it. We should always
327-
// have a resolved config though, since we processed them already above.
328-
continue;
329-
};
330-
331-
let severity = resolved_config.rules.iter().find_map(
332-
|(rule, status)| {
333-
if rule.name() == tsgolint_diagnostic.rule {
334-
Some(*status)
335-
} else {
336-
None
337-
}
338-
},
339-
);
340-
let Some(severity) = severity else {
341-
// If the severity is not found, we should not report the diagnostic
342-
continue;
343-
};
344-
345-
let mut message_with_position: MessageWithPosition<'_> =
346-
message_to_message_with_position(
347-
Message::from_tsgo_lint_diagnostic(
348-
tsgolint_diagnostic,
349-
&source_text,
350-
),
351-
&source_text,
352-
&Rope::from_str(&source_text),
353-
);
354-
355-
message_with_position.severity =
356-
if severity == AllowWarnDeny::Deny {
357-
Severity::Error
358-
} else {
359-
Severity::Warning
360-
};
361-
362-
result.push(message_with_position);
363-
}
364-
Err(_) => {
365-
// Could not parse a complete message, break and keep remaining data
366-
cursor.set_position(start_pos);
367-
break;
303+
for msg in msg_iter {
304+
match msg {
305+
Ok(TsGoLintMessage::Error(err)) => {
306+
return Err(err.error);
307+
}
308+
Ok(TsGoLintMessage::Diagnostic(tsgolint_diagnostic)) => {
309+
let path = tsgolint_diagnostic.file_path.clone();
310+
let Some(resolved_config) = resolved_configs.get(&path) else {
311+
// If we don't have a resolved config for this path, skip it. We should always
312+
// have a resolved config though, since we processed them already above.
313+
continue;
314+
};
315+
316+
let severity =
317+
resolved_config.rules.iter().find_map(|(rule, status)| {
318+
if rule.name() == tsgolint_diagnostic.rule {
319+
Some(*status)
320+
} else {
321+
None
368322
}
369-
}
370-
}
323+
});
324+
let Some(severity) = severity else {
325+
// If the severity is not found, we should not report the diagnostic
326+
continue;
327+
};
328+
329+
let mut message_with_position: MessageWithPosition<'_> =
330+
message_to_message_with_position(
331+
Message::from_tsgo_lint_diagnostic(
332+
tsgolint_diagnostic,
333+
&source_text,
334+
),
335+
&source_text,
336+
&Rope::from_str(&source_text),
337+
);
338+
339+
message_with_position.severity = if severity == AllowWarnDeny::Deny
340+
{
341+
Severity::Error
342+
} else {
343+
Severity::Warning
344+
};
371345

372-
// Keep unprocessed data for next iteration
373-
if processed_up_to > 0 {
374-
#[expect(clippy::cast_possible_truncation)]
375-
buffer.drain(..processed_up_to as usize);
376-
}
346+
result.push(message_with_position);
377347
}
378348
Err(e) => {
379-
return Err(format!("Failed to read from tsgolint stdout: {e}"));
349+
return Err(e);
380350
}
381351
}
382352
}

0 commit comments

Comments
 (0)