brk_string_wizard 0.4.0

manipulate string like a wizard
Documentation
use std::sync::Arc;

use rustc_hash::FxHashMap;

use crate::{
  MagicString,
  source_map::{
    locator::Locator,
    sourcemap_builder::{Hires, SourcemapBuilder},
  },
};

#[derive(Debug)]
pub struct SourceMapOptions {
  pub include_content: bool,
  pub source: Arc<str>,
  pub hires: Hires,
}

impl Default for SourceMapOptions {
  fn default() -> Self {
    Self { include_content: false, source: "".into(), hires: Hires::default() }
  }
}

impl MagicString<'_> {
  pub fn source_map(&self, opts: SourceMapOptions) -> oxc_sourcemap::SourceMap {
    let mut source_builder = SourcemapBuilder::new(opts.hires);

    source_builder.set_source_and_content(&opts.source, &self.source);

    let locator = Locator::new(&self.source);

    self.intro.iter().for_each(|frag| {
      source_builder.advance(frag);
    });

    let utf16_index_map =
      precompute_utf16_index_map(&self.source, self.iter_chunks().map(|chunk| chunk.start()));

    self.iter_chunks().for_each(|chunk| {
      chunk.intro.iter().for_each(|frag| {
        source_builder.advance(frag);
      });
      let name =
        (chunk.keep_in_mappings && chunk.is_edited()).then(|| chunk.span.text(&self.source));

      source_builder.add_chunk(
        chunk,
        utf16_index_map[&chunk.start()],
        &locator,
        &self.source,
        name,
      );

      chunk.outro.iter().for_each(|frag| {
        source_builder.advance(frag);
      });
    });

    source_builder.into_source_map()
  }
}

fn precompute_utf16_index_map(
  source: &str,
  byte_indices: impl Iterator<Item = usize>,
) -> FxHashMap<usize, usize> {
  let mut byte_indices: Vec<usize> = byte_indices.collect();
  byte_indices.sort();
  let mut index = 0;
  let mut index_utf16 = 0;
  let mut map: FxHashMap<usize, usize> = Default::default();
  for &i in &byte_indices {
    index_utf16 += source[index..i].chars().map(|c| c.len_utf16()).sum::<usize>();
    index = i;
    map.insert(i, index_utf16);
  }
  map
}