use crate::{
JSONSourceMap, SourceMap, SourceViewToken, Token, error::Result, sourcemap::SourceMapParts,
};
#[derive(Debug, Clone, Default)]
pub struct OwnedSourceMap {
inner: SourceMap<'static>,
}
impl OwnedSourceMap {
#[inline]
pub fn new(inner: SourceMap<'static>) -> Self {
Self { inner }
}
#[inline]
pub fn as_source_map(&self) -> &SourceMap<'static> {
&self.inner
}
#[inline]
pub fn as_source_map_mut(&mut self) -> &mut SourceMap<'static> {
&mut self.inner
}
#[inline]
pub fn into_inner(self) -> SourceMap<'static> {
self.inner
}
pub fn from_json(value: JSONSourceMap) -> Result<Self> {
SourceMap::from_json(value).map(Self::new)
}
pub fn from_json_string(value: &str) -> Result<Self> {
SourceMap::from_json_string(value).map(SourceMap::into_owned).map(Self::new)
}
pub fn to_json(&self) -> JSONSourceMap {
self.inner.to_json()
}
pub fn to_json_string(&self) -> String {
self.inner.to_json_string()
}
pub fn to_data_url(&self) -> String {
self.inner.to_data_url()
}
pub fn get_file(&self) -> Option<&str> {
self.inner.get_file()
}
pub fn set_file(&mut self, file: &str) {
self.inner.set_file(file);
}
pub fn get_source_root(&self) -> Option<&str> {
self.inner.get_source_root()
}
pub fn get_x_google_ignore_list(&self) -> Option<&[u32]> {
self.inner.get_x_google_ignore_list()
}
pub fn set_x_google_ignore_list(&mut self, list: Vec<u32>) {
self.inner.set_x_google_ignore_list(list);
}
pub fn get_debug_id(&self) -> Option<&str> {
self.inner.get_debug_id()
}
pub fn set_debug_id(&mut self, debug_id: &str) {
self.inner.set_debug_id(debug_id);
}
pub fn get_names(&self) -> impl Iterator<Item = &str> {
self.inner.get_names()
}
pub fn get_sources(&self) -> impl Iterator<Item = &str> {
self.inner.get_sources()
}
pub fn set_sources<S: AsRef<str>, I: IntoIterator<Item = S>>(&mut self, sources: I) {
self.inner.set_sources(sources);
}
pub fn get_source_contents(&self) -> impl Iterator<Item = Option<&str>> {
self.inner.get_source_contents()
}
pub fn set_source_contents(&mut self, contents: Vec<Option<&str>>) {
self.inner.set_source_contents(contents);
}
pub fn get_name(&self, id: u32) -> Option<&str> {
self.inner.get_name(id)
}
pub fn get_source(&self, id: u32) -> Option<&str> {
self.inner.get_source(id)
}
pub fn get_source_content(&self, id: u32) -> Option<&str> {
self.inner.get_source_content(id)
}
pub fn get_source_and_content(&self, id: u32) -> Option<(&str, &str)> {
self.inner.get_source_and_content(id)
}
pub fn get_token(&self, index: u32) -> Option<Token> {
self.inner.get_token(index)
}
pub fn get_tokens(&self) -> impl Iterator<Item = Token> {
self.inner.get_tokens()
}
pub fn get_source_view_token(&self, index: u32) -> Option<SourceViewToken<'_, 'static>> {
self.inner.get_source_view_token(index)
}
pub fn get_source_view_tokens(&self) -> impl Iterator<Item = SourceViewToken<'_, 'static>> {
self.inner.get_source_view_tokens()
}
pub fn generate_lookup_table(&self) -> Vec<&[Token]> {
self.inner.generate_lookup_table()
}
pub fn lookup_token(&self, lookup_table: &[&[Token]], line: u32, col: u32) -> Option<Token> {
self.inner.lookup_token(lookup_table, line, col)
}
pub fn lookup_source_view_token(
&self,
lookup_table: &[&[Token]],
line: u32,
col: u32,
) -> Option<SourceViewToken<'_, 'static>> {
self.inner.lookup_source_view_token(lookup_table, line, col)
}
pub fn into_parts(self) -> SourceMapParts<'static> {
self.inner.into_parts()
}
pub fn from_parts(parts: SourceMapParts<'static>) -> Self {
Self::new(SourceMap::from_parts(parts))
}
}
impl From<SourceMap<'static>> for OwnedSourceMap {
#[inline]
fn from(inner: SourceMap<'static>) -> Self {
Self::new(inner)
}
}
impl From<OwnedSourceMap> for SourceMap<'static> {
#[inline]
fn from(owned: OwnedSourceMap) -> Self {
owned.into_inner()
}
}
impl std::ops::Deref for OwnedSourceMap {
type Target = SourceMap<'static>;
#[inline]
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl std::ops::DerefMut for OwnedSourceMap {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
impl<'a> SourceMap<'a> {
#[inline]
pub fn into_owned_sourcemap(self) -> OwnedSourceMap {
OwnedSourceMap::new(self.into_owned())
}
}
#[cfg(test)]
mod tests {
use super::*;
const JSON: &str = r#"{
"version": 3,
"file": "out.js",
"sourceRoot": "root",
"names": ["n0"],
"sources": ["a.js"],
"sourcesContent": ["AC"],
"mappings": "AAAAA",
"x_google_ignoreList": [0],
"debugId": "dbg"
}"#;
#[test]
fn accessors() {
let sm = OwnedSourceMap::from_json_string(JSON).unwrap();
assert_eq!(sm.get_file(), Some("out.js"));
assert_eq!(sm.get_source_root(), Some("root"));
assert_eq!(sm.get_x_google_ignore_list(), Some(&[0][..]));
assert_eq!(sm.get_debug_id(), Some("dbg"));
assert_eq!(sm.get_names().collect::<Vec<_>>(), vec!["n0"]);
assert_eq!(sm.get_sources().collect::<Vec<_>>(), vec!["a.js"]);
assert_eq!(sm.get_source_contents().collect::<Vec<_>>(), vec![Some("AC")]);
assert_eq!(sm.get_name(0), Some("n0"));
assert_eq!(sm.get_source(0), Some("a.js"));
assert_eq!(sm.get_source_content(0), Some("AC"));
assert_eq!(sm.get_source_and_content(0), Some(("a.js", "AC")));
assert!(sm.get_token(0).is_some());
assert_eq!(sm.get_tokens().count(), 1);
assert!(sm.get_source_view_token(0).is_some());
assert_eq!(sm.get_source_view_tokens().count(), 1);
}
#[test]
fn mutators() {
let mut sm = OwnedSourceMap::from_json_string(JSON).unwrap();
sm.set_file("new.js");
assert_eq!(sm.get_file(), Some("new.js"));
sm.set_sources(vec!["b.js"]);
assert_eq!(sm.get_source(0), Some("b.js"));
sm.set_source_contents(vec![Some("new content")]);
assert_eq!(sm.get_source_content(0), Some("new content"));
sm.set_x_google_ignore_list(vec![]);
assert_eq!(sm.get_x_google_ignore_list(), Some(&[][..]));
sm.set_debug_id("newdbg");
assert_eq!(sm.get_debug_id(), Some("newdbg"));
}
#[test]
fn lookup() {
let sm = OwnedSourceMap::from_json_string(JSON).unwrap();
let table = sm.generate_lookup_table();
assert!(sm.lookup_token(&table, 0, 0).is_some());
assert!(sm.lookup_source_view_token(&table, 0, 0).is_some());
}
#[test]
fn serialize() {
let sm = OwnedSourceMap::from_json_string(JSON).unwrap();
assert_eq!(sm.to_json().file.as_deref(), Some("out.js"));
assert!(sm.to_json_string().contains("\"file\":\"out.js\""));
assert!(sm.to_data_url().starts_with("data:application/json;charset=utf-8;base64,"));
}
#[test]
fn from_json_value() {
let json = SourceMap::from_json_string(JSON).unwrap().to_json();
let sm = OwnedSourceMap::from_json(json).unwrap();
assert_eq!(sm.get_file(), Some("out.js"));
}
#[test]
fn conversions_and_inner_access() {
let inner = SourceMap::from_json_string(JSON).unwrap().into_owned();
let owned = OwnedSourceMap::new(inner.clone());
assert_eq!(owned.as_source_map().get_file(), Some("out.js"));
let mut from_sm = OwnedSourceMap::from(inner.clone());
from_sm.as_source_map_mut().set_file("z.js");
assert_eq!(from_sm.get_file(), Some("z.js"));
let deref: &SourceMap<'static> = &owned;
assert_eq!(deref.get_file(), Some("out.js"));
let mut owned_mut = owned.clone();
let deref_mut: &mut SourceMap<'static> = &mut owned_mut;
deref_mut.set_file("deref.js");
assert_eq!(owned_mut.get_file(), Some("deref.js"));
let back: SourceMap<'static> = owned.into_inner();
let round: SourceMap<'static> = OwnedSourceMap::from(back.clone()).into();
assert_eq!(round.get_file(), Some("out.js"));
assert_eq!(back.into_owned_sourcemap().get_file(), Some("out.js"));
}
#[test]
fn parts_roundtrip() {
let owned = OwnedSourceMap::from_json_string(JSON).unwrap();
let parts = owned.into_parts();
assert_eq!(parts.file.as_deref(), Some("out.js"));
let rebuilt = OwnedSourceMap::from_parts(parts);
assert_eq!(rebuilt.get_file(), Some("out.js"));
assert_eq!(rebuilt.get_source(0), Some("a.js"));
}
}