Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inserting node with DUMMY_SP reuses (next) existing source mapping #6767

Open
mischnic opened this issue Jan 8, 2023 · 1 comment · Fixed by #6773
Open

Inserting node with DUMMY_SP reuses (next) existing source mapping #6767

mischnic opened this issue Jan 8, 2023 · 1 comment · Fixed by #6773
Labels

Comments

@mischnic
Copy link
Contributor

mischnic commented Jan 8, 2023

Describe the bug

When a node with DUMMY_SP is inserted, it should create no source mapping, but it does.

                module.body.splice(
                    0..0,
                    vec![ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
                        specifiers: vec![],
                        asserts: None,
                        span: DUMMY_SP,
                        src: Box::new("new".into()),
                        type_only: false,
                    }))],
                );

Input code

/*------------------------------------
  ------------------------------------*/
var _a;
import z from "./z.js";
console.log("xyz", z);

Config

use std::collections::HashSet;

use swc::{self};
use swc_atoms::JsWord;
use swc_common::{
    chain,
    comments::SingleThreadedComments,
    errors::{DiagnosticBuilder, Emitter, Handler},
    source_map::SourceMapGenConfig,
    sync::Lrc,
    FileName, Globals, Mark, SourceMap, SyntaxContext, DUMMY_SP,
};
use swc_ecma_ast::{
    CatchClause, Decl, Id, Ident, ImportDecl, Module, ModuleDecl, ModuleItem, Pat, Stmt,
    VarDeclKind,
};
use swc_ecma_codegen::{text_writer::JsWriter, Config};
use swc_ecma_parser::{lexer::Lexer, EsConfig, PResult, Parser, StringInput, Syntax, TsConfig};
use swc_ecma_preset_env::{preset_env, BrowserData, Mode, Targets, Version};
use swc_ecma_transforms::{
    compat::reserved_words::reserved_words,
    fixer,
    fixer::paren_remover,
    helpers, hygiene,
    optimization::simplify::{dead_branch_remover, expr_simplifier},
    react::{self, Runtime},
    resolver,
};
use swc_ecma_visit::{Fold, FoldWith, Visit, VisitWith};

#[derive(Debug, Clone, Default)]
pub struct ErrorBuffer(std::sync::Arc<std::sync::Mutex<Vec<swc_common::errors::Diagnostic>>>);

type SourceMapBuffer = Vec<(swc_common::BytePos, swc_common::LineCol)>;

impl Emitter for ErrorBuffer {
    fn emit(&mut self, db: &DiagnosticBuilder) {
        self.0.lock().unwrap().push((**db).clone());
    }
}

fn main() {
    let cm = Lrc::<SourceMap>::default();

    let src = r#"/*------------------------------------
  ------------------------------------*/
var _a;
import z from "./z.js";
console.log("xyz", z);
"#;

    let (module, comments) = parse(&src, "test.js", &cm).unwrap();

    let error_buffer = ErrorBuffer::default();
    let handler = Handler::with_emitter(true, false, Box::new(error_buffer.clone()));
    swc_common::errors::HANDLER.set(&handler, || {
        swc_common::GLOBALS.set(&Globals::new(), || {
            helpers::HELPERS.set(&helpers::Helpers::new(true), || {
                let unresolved_mark = Mark::fresh(Mark::root());
                let top_level_mark = Mark::fresh(Mark::root());
                let mut module =
                    module.fold_with(&mut resolver(unresolved_mark, top_level_mark, false));

                module.body.splice(
                    0..0,
                    vec![ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
                        specifiers: vec![],
                        asserts: None,
                        span: DUMMY_SP,
                        src: Box::new("new".into()),
                        type_only: false,
                    }))],
                );

                let module = module.fold_with(&mut chain!(
                    reserved_words(),
                    hygiene(),
                    fixer(Some(&comments))
                ));

                let mut map_buf = vec![];
                let (code, src_map_buf) = emit(cm.clone(), comments, &module).unwrap();

                struct SourceMapConfigImpl;

                impl SourceMapGenConfig for SourceMapConfigImpl {
                    fn file_name_to_source(&self, f: &swc_common::FileName) -> String {
                        f.to_string()
                    }

                    fn inline_sources_content(&self, _: &swc_common::FileName) -> bool {
                        true
                    }
                }
                cm.build_source_map_with_config(&src_map_buf, None, SourceMapConfigImpl)
                    .to_writer(&mut map_buf)
                    .unwrap();

                println!(
                    "{}",
                    visualizer_url(&code, &String::from_utf8(map_buf).unwrap())
                );
            });
        });
    });
}

fn visualizer_url(code: &str, map: &str) -> String {
    println!("{}", code);
    println!("{}", map);
    let code_len = format!("{}\0", code.len());
    let map_len = format!("{}\0", map.len());
    let hash = base64::encode(format!("{}{}{}{}", code_len, code, map_len, map));
    format!("https://evanw.github.io/source-map-visualization/#{}", hash)
}

struct ShowSyntaxContext {
    top_level_mark: Mark,
    unresolved_mark: Mark,
}
impl Fold for ShowSyntaxContext {
    fn fold_ident(&mut self, node: Ident) -> Ident {
        let new_name: JsWord = format!(
            "{}_{}{}{}",
            node.sym,
            node.span.ctxt().as_u32(),
            if node.span.has_mark(self.top_level_mark) {
                "_top"
            } else {
                ""
            },
            if node.span.has_mark(self.unresolved_mark) {
                "_unres"
            } else {
                ""
            },
        )
        .into();
        Ident::new(new_name, node.span)
    }
}

fn parse(
    code: &str,
    filename: &str,
    cm: &Lrc<SourceMap>,
) -> PResult<(Module, SingleThreadedComments)> {
    let source_file = cm.new_source_file(FileName::Real(filename.into()), code.into());
    let comments = SingleThreadedComments::default();

    let lexer = Lexer::new(
        // Syntax::Es(EsConfig {
        //     jsx: true,
        //     ..Default::default()
        // }),
        Syntax::Typescript(TsConfig {
            tsx: true,
            ..Default::default()
        }),
        Default::default(),
        StringInput::from(&*source_file),
        Some(&comments),
    );
    let mut parser = Parser::new_from(lexer);
    match parser.parse_module() {
        Err(err) => Err(err),
        Ok(module) => Ok((module, comments)),
    }
}

fn emit(
    source_map: Lrc<SourceMap>,
    comments: SingleThreadedComments,
    module: &Module,
) -> Result<(String, SourceMapBuffer), std::io::Error> {
    let mut src_map_buf = vec![];
    let mut buf = vec![];
    {
        let writer = Box::new(JsWriter::new(
            source_map.clone(),
            "\n",
            &mut buf,
            Some(&mut src_map_buf),
        ));
        let config = Config {
            minify: false,
            ascii_only: false,
            omit_last_semi: false,
            ..Default::default()
        };
        let mut emitter = swc_ecma_codegen::Emitter {
            cfg: config,
            comments: Some(&comments),
            cm: source_map,
            wr: writer,
        };

        emitter.emit_module(module)?;
    }

    Ok((String::from_utf8(buf).unwrap(), src_map_buf))
}

Playground link

No response

Expected behavior

The mapping shouldn't exist.

Actual behavior

Bildschirm­foto 2023-01-08 um 19 20 32

Sourcemap

Version

a225efe

Additional context

No response

@mischnic mischnic added the C-bug label Jan 8, 2023
@mischnic mischnic changed the title Inserting node with DUMMY_SP reuses/overwrites existing source mapping Inserting node with DUMMY_SP reuses (next) existing source mapping Jan 8, 2023
@kdy1 kdy1 added this to the Planned milestone Jan 9, 2023
@kdy1 kdy1 self-assigned this Jan 9, 2023
kdy1 added a commit that referenced this issue Jan 10, 2023
@kdy1 kdy1 modified the milestones: Planned, v1.3.26 Jan 11, 2023
@mischnic
Copy link
Contributor Author

With that linked PR, the behaviour is now to (apparently at least in this specific case) use the previous existing mapping. So the problems isn't really solved. New output:

Bildschirm­foto 2023-01-17 um 21 55 31

Link

@kdy1 kdy1 reopened this Jan 18, 2023
@kdy1 kdy1 removed this from the v1.3.26 milestone Jan 18, 2023
@kdy1 kdy1 removed their assignment Jan 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging a pull request may close this issue.

2 participants