use crate::language::SourceSpan;
use swc_common::SourceMap;
pub fn extract_suppression(
source: &str,
span: SourceSpan,
_source_map: &SourceMap,
) -> Option<String> {
let func_line = span.start_line;
if func_line <= 1 {
return None;
}
let prev_line_num = (func_line - 1) as usize;
let lines: Vec<&str> = source.lines().collect();
if prev_line_num == 0 || prev_line_num > lines.len() {
return None;
}
let prev_line = lines[prev_line_num - 1].trim();
if !prev_line.starts_with("// hotspots-ignore") {
return None;
}
if let Some(colon_pos) = prev_line.find(':') {
let reason = prev_line[colon_pos + 1..].trim();
if reason.is_empty() {
Some(String::new()) } else {
Some(reason.to_string()) }
} else {
Some(String::new())
}
}
#[cfg(test)]
mod tests {
use super::*;
use swc_common::{sync::Lrc, FileName, SourceMap};
use swc_ecma_ast::EsVersion;
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax};
fn parse_and_extract(source: &str) -> Option<String> {
let source_map = SourceMap::default();
let source_file = source_map.new_source_file(
Lrc::new(FileName::Custom("test.ts".to_string())),
source.to_string(),
);
let lexer = Lexer::new(
Syntax::Typescript(Default::default()),
EsVersion::Es2022,
StringInput::from(&*source_file),
None,
);
let mut parser = Parser::new_from(lexer);
let module = parser.parse_module().expect("parse failed");
let function_span = module
.body
.iter()
.find_map(|item| {
if let swc_ecma_ast::ModuleItem::Stmt(swc_ecma_ast::Stmt::Decl(
swc_ecma_ast::Decl::Fn(fn_decl),
)) = item
{
Some(fn_decl.function.span)
} else {
None
}
})
.expect("no function found");
let source_span = crate::language::span::span_with_location(function_span, &source_map);
extract_suppression(source, source_span, &source_map)
}
#[test]
fn test_no_suppression() {
let source = r#"
function foo() {
return 42;
}
"#;
assert_eq!(parse_and_extract(source), None);
}
#[test]
fn test_suppression_with_reason() {
let source = r#"
// hotspots-ignore: legacy code, will refactor later
function foo() {
return 42;
}
"#;
assert_eq!(
parse_and_extract(source),
Some("legacy code, will refactor later".to_string())
);
}
#[test]
fn test_suppression_without_reason() {
let source = r#"
// hotspots-ignore:
function foo() {
return 42;
}
"#;
assert_eq!(parse_and_extract(source), Some(String::new()));
}
#[test]
fn test_suppression_no_colon() {
let source = r#"
// hotspots-ignore
function foo() {
return 42;
}
"#;
assert_eq!(parse_and_extract(source), Some(String::new()));
}
#[test]
fn test_blank_line_between() {
let source = r#"
// hotspots-ignore: should not be recognized
function foo() {
return 42;
}
"#;
assert_eq!(parse_and_extract(source), None);
}
#[test]
fn test_function_on_first_line() {
let source = "function foo() { return 42; }";
assert_eq!(parse_and_extract(source), None);
}
#[test]
fn test_suppression_with_whitespace() {
let source = r#"
// hotspots-ignore: whitespace test
function foo() {
return 42;
}
"#;
assert_eq!(
parse_and_extract(source),
Some("whitespace test".to_string())
);
}
#[test]
fn test_different_comment() {
let source = r#"
// This is just a regular comment
function foo() {
return 42;
}
"#;
assert_eq!(parse_and_extract(source), None);
}
}