use std::collections::BTreeMap;
use oxc_ast::ast::{Comment, Program};
use crate::instrument::UnhandledPragma;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IgnoreType {
Next,
If,
Else,
}
pub struct PragmaMap {
ignores: BTreeMap<u32, IgnoreType>,
pub ignore_file: bool,
}
impl PragmaMap {
pub fn from_program(program: &Program, source: &str) -> (Self, Vec<UnhandledPragma>) {
let mut ignores = BTreeMap::new();
let mut ignore_file = false;
let mut unhandled = Vec::new();
for comment in &program.comments {
let text = Self::comment_text(comment, source);
if let Some(ignore_type) = Self::parse_pragma(&text) {
match ignore_type {
PragmaResult::Ignore(it) => {
ignores.insert(comment.attached_to, it);
}
PragmaResult::File => {
ignore_file = true;
}
PragmaResult::Unknown(comment_text) => {
let line = source[..comment.span.start as usize]
.chars()
.filter(|&c| c == '\n')
.count() as u32
+ 1;
let line_start =
source[..comment.span.start as usize].rfind('\n').map_or(0, |p| p + 1);
let column = comment.span.start as usize - line_start;
unhandled.push(UnhandledPragma {
comment: comment_text,
line,
column: column as u32,
});
}
}
}
}
(Self { ignores, ignore_file }, unhandled)
}
pub fn get(&self, token_start: u32) -> Option<IgnoreType> {
self.ignores.get(&token_start).copied()
}
fn comment_text(comment: &Comment, source: &str) -> String {
let content_span = comment.content_span();
source[content_span.start as usize..content_span.end as usize].to_string()
}
fn parse_pragma(text: &str) -> Option<PragmaResult> {
let trimmed = text.trim();
if let Some(rest) = trimmed.strip_prefix("istanbul ignore ") {
return Some(Self::parse_ignore_kind(rest.trim_start(), trimmed));
}
if let Some(rest) = trimmed.strip_prefix("istanbul ignore\t") {
return Some(Self::parse_ignore_kind(rest.trim_start(), trimmed));
}
if let Some(rest) = trimmed.strip_prefix("v8 ignore ") {
return Some(Self::parse_ignore_kind(rest.trim_start(), trimmed));
}
if let Some(rest) = trimmed.strip_prefix("v8 ignore\t") {
return Some(Self::parse_ignore_kind(rest.trim_start(), trimmed));
}
if let Some(rest) = trimmed.strip_prefix("c8 ignore ") {
return Some(Self::parse_ignore_kind(rest.trim_start(), trimmed));
}
if let Some(rest) = trimmed.strip_prefix("c8 ignore\t") {
return Some(Self::parse_ignore_kind(rest.trim_start(), trimmed));
}
None
}
fn parse_ignore_kind(kind_str: &str, full_text: &str) -> PragmaResult {
let keyword = kind_str.split_whitespace().next().unwrap_or("");
match keyword {
"next" => PragmaResult::Ignore(IgnoreType::Next),
"if" => PragmaResult::Ignore(IgnoreType::If),
"else" => PragmaResult::Ignore(IgnoreType::Else),
"file" => PragmaResult::File,
_ => PragmaResult::Unknown(full_text.to_string()),
}
}
}
enum PragmaResult {
Ignore(IgnoreType),
File,
Unknown(String),
}