use std::borrow::Cow;
use std::fmt;
use failure::Fail;
#[derive(Debug)]
pub struct ParseSourceMapError(sourcemap::Error);
impl fmt::Display for ParseSourceMapError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
sourcemap::Error::Io(..) => write!(f, "sourcemap parsing failed with io error"),
sourcemap::Error::Utf8(..) => write!(f, "sourcemap parsing failed due to bad utf-8"),
sourcemap::Error::BadJson(..) => write!(f, "invalid json data on sourcemap parsing"),
ref other => write!(f, "{}", other),
}
}
}
impl Fail for ParseSourceMapError {
fn cause(&self) -> Option<&dyn Fail> {
Some(match self.0 {
sourcemap::Error::Io(ref err) => err,
sourcemap::Error::Utf8(ref err) => err,
sourcemap::Error::BadJson(ref err) => err,
_ => return None,
})
}
}
impl From<sourcemap::Error> for ParseSourceMapError {
fn from(error: sourcemap::Error) -> ParseSourceMapError {
ParseSourceMapError(error)
}
}
pub struct SourceView<'a> {
sv: sourcemap::SourceView<'a>,
}
pub struct SourceMapView {
sm: sourcemap::SourceMap,
}
pub struct TokenMatch<'a> {
pub src_line: u32,
pub src_col: u32,
pub dst_line: u32,
pub dst_col: u32,
pub src_id: u32,
pub name: Option<&'a str>,
pub src: Option<&'a str>,
pub function_name: Option<String>,
}
impl<'a> SourceView<'a> {
pub fn new(source: &'a str) -> SourceView<'a> {
SourceView {
sv: sourcemap::SourceView::new(source),
}
}
pub fn from_string(source: String) -> SourceView<'static> {
SourceView {
sv: sourcemap::SourceView::from_string(source),
}
}
pub fn from_bytes(source: &'a [u8]) -> SourceView<'a> {
match String::from_utf8_lossy(source) {
Cow::Owned(s) => SourceView::from_string(s),
Cow::Borrowed(s) => SourceView::new(s),
}
}
pub fn as_str(&self) -> &str {
self.sv.source()
}
pub fn get_line(&self, idx: u32) -> Option<&str> {
self.sv.get_line(idx)
}
pub fn line_count(&self) -> usize {
self.sv.line_count()
}
}
impl SourceMapView {
pub fn from_json_slice(buffer: &[u8]) -> Result<SourceMapView, ParseSourceMapError> {
Ok(SourceMapView {
sm: match sourcemap::decode_slice(buffer)? {
sourcemap::DecodedMap::Regular(sm) => sm,
sourcemap::DecodedMap::Index(smi) => smi.flatten()?,
},
})
}
pub fn lookup_token(&self, line: u32, col: u32) -> Option<TokenMatch<'_>> {
self.sm
.lookup_token(line, col)
.map(|tok| self.make_token_match(tok))
}
pub fn get_token(&self, idx: u32) -> Option<TokenMatch<'_>> {
self.sm.get_token(idx).map(|tok| self.make_token_match(tok))
}
pub fn get_token_count(&self) -> u32 {
self.sm.get_token_count()
}
pub fn get_source_view(&self, idx: u32) -> Option<&SourceView<'_>> {
self.sm
.get_source_view(idx)
.map(|s| unsafe { &*(s as *const _ as *const SourceView<'_>) })
}
pub fn get_source_name(&self, idx: u32) -> Option<&str> {
self.sm.get_source(idx)
}
pub fn get_source_count(&self) -> u32 {
self.sm.get_source_count()
}
pub fn lookup_token_with_function_name<'a, 'b>(
&'a self,
line: u32,
col: u32,
minified_name: &str,
source: &SourceView<'b>,
) -> Option<TokenMatch<'a>> {
self.sm.lookup_token(line, col).map(|token| {
let mut rv = self.make_token_match(token);
rv.function_name = source
.sv
.get_original_function_name(token, minified_name)
.map(|x| x.to_string());
rv
})
}
fn make_token_match<'a>(&'a self, tok: sourcemap::Token<'a>) -> TokenMatch<'a> {
TokenMatch {
src_line: tok.get_src_line(),
src_col: tok.get_src_col(),
dst_line: tok.get_dst_line(),
dst_col: tok.get_dst_col(),
src_id: tok.get_src_id(),
name: tok.get_name(),
src: tok.get_source(),
function_name: None,
}
}
}