From 88edb71e0ae2d882e324cf7a85ec86f7ed62c5b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Tue, 9 Jun 2020 20:20:20 +0900 Subject: [PATCH] Handle input source map correctly (#830) --- native/src/lib.rs | 43 +++++--------- package.json | 2 +- src/config.rs | 3 +- src/lib.rs | 146 +++++++++++++++++++++++----------------------- wasm/src/lib.rs | 25 ++------ 5 files changed, 96 insertions(+), 123 deletions(-) diff --git a/native/src/lib.rs b/native/src/lib.rs index eabb474abfb..8e064f762e1 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -76,7 +76,7 @@ impl Task for TransformTask { let program: Program = serde_json::from_str(&s).expect("failed to deserialize Program"); // TODO: Source map - self.c.process_js(program, None, &self.options) + self.c.process_js(program, &self.options) } Input::File(ref path) => { @@ -144,8 +144,7 @@ where if is_module.value() { let program: Program = serde_json::from_str(&s.value()).expect("failed to deserialize Program"); - // TODO: Source map - c.process_js(program, None, &options) + c.process_js(program, &options) } else { let fm = op(&c, s.value(), &options).expect("failed to create fm"); c.process_js_file(fm, &options) @@ -246,16 +245,13 @@ impl Task for ParseTask { fn perform(&self) -> Result { self.c.run(|| { - self.c - .parse_js( - self.fm.clone(), - self.options.target, - self.options.syntax, - self.options.is_module, - self.options.comments, - &Default::default(), - ) - .map(|v| v.0) + self.c.parse_js( + self.fm.clone(), + self.options.target, + self.options.syntax, + self.options.is_module, + self.options.comments, + ) }) } @@ -281,16 +277,13 @@ impl Task for ParseFileTask { .load_file(&self.path) .context("failed to read module")?; - self.c - .parse_js( - fm, - self.options.target, - self.options.syntax, - self.options.is_module, - self.options.comments, - &Default::default(), - ) - .map(|v| v.0) + self.c.parse_js( + fm, + self.options.target, + self.options.syntax, + self.options.is_module, + self.options.comments, + ) }) } @@ -348,9 +341,7 @@ fn parse_sync(mut cx: MethodContext) -> JsResult { options.syntax, options.is_module, options.comments, - &Default::default(), ) - .map(|v| v.0) }; complete_parse(cx, program, &c) @@ -381,9 +372,7 @@ fn parse_file_sync(mut cx: MethodContext) -> JsResult { options.syntax, options.is_module, options.comments, - &Default::default(), ) - .map(|v| v.0) }; complete_parse(cx, program, &c) diff --git a/package.json b/package.json index 036eb09f711..3eed27de005 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@swc/core", - "version": "1.1.54", + "version": "1.1.55", "description": "Super-fast alternative for babel", "main": "./index.js", "author": "강동윤 ", diff --git a/src/config.rs b/src/config.rs index a177ec88cd5..82ce2b8829a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -101,6 +101,7 @@ fn default_is_module() -> bool { true } +/// Configuration related to source map generaged by swc. #[derive(Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum SourceMapsConfig { @@ -135,7 +136,7 @@ pub enum InputSourceMap { impl Default for InputSourceMap { fn default() -> Self { - InputSourceMap::Bool(true) + InputSourceMap::Bool(false) } } diff --git a/src/lib.rs b/src/lib.rs index ca2f7d44654..23335abf564 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,15 +5,12 @@ pub use swc_atoms as atoms; pub use swc_common as common; pub use swc_ecmascript as ecmascript; -mod builder; -pub mod config; - pub use crate::builder::PassBuilder; use crate::config::{ BuiltConfig, Config, ConfigFile, InputSourceMap, JscTarget, Merge, Options, Rc, RootMode, SourceMapsConfig, }; -use anyhow::{Context, Error}; +use anyhow::{bail, Context, Error}; use common::{ comments::{Comment, Comments}, errors::Handler, @@ -41,6 +38,9 @@ use std::{ sync::Arc, }; +mod builder; +pub mod config; + pub struct Compiler { /// swc uses rustc's span interning. /// @@ -81,6 +81,65 @@ impl Compiler { }) } + fn get_orig_src_map( + &self, + name: &FileName, + input_src_map: &InputSourceMap, + ) -> Result, Error> { + self.run(|| -> Result<_, Error> { + // Load original source map + match input_src_map { + InputSourceMap::Bool(false) => Ok(None), + InputSourceMap::Bool(true) => { + // Load original source map if possible + match &name { + FileName::Real(filename) => { + let path = format!("{}.map", filename.display()); + let file = File::open(&path) + .context("failed to open input source map file")?; + Ok(Some(sourcemap::SourceMap::from_reader(file).with_context( + || format!("failed to read input source map from file at {}", path), + )?)) + } + _ => { + log::error!("Failed to load source map for non-file input"); + return Ok(None); + } + } + } + InputSourceMap::Str(ref s) => { + if s == "inline" { + // Load inline source map by simple string + // operations + let s = "sourceMappingURL=data:application/json;base64,"; + let idx = s.rfind(s); + let idx = match idx { + None => bail!( + "failed to parse inline source map: `sourceMappingURL` not found" + ), + Some(v) => v, + }; + let encoded = &s[idx + s.len()..]; + + let res = base64::decode(encoded.as_bytes()) + .context("failed to decode base64-encoded source map")?; + + Ok(Some(sourcemap::SourceMap::from_slice(&res).context( + "failed to read input source map from inlined base64 encoded string", + )?)) + } else { + // Load source map passed by user + Ok(Some( + sourcemap::SourceMap::from_slice(s.as_bytes()).context( + "failed to read input source map from user-provided sourcemap", + )?, + )) + } + } + } + }) + } + /// This method parses a javascript / typescript file pub fn parse_js( &self, @@ -89,63 +148,8 @@ impl Compiler { syntax: Syntax, is_module: bool, parse_comments: bool, - input_source_map: &InputSourceMap, - ) -> Result<(Program, Option), Error> { + ) -> Result { self.run(|| { - let orig = (|| { - // Load original source map - match input_source_map { - InputSourceMap::Bool(false) => None, - InputSourceMap::Bool(true) => { - // Load original source map if possible - match &fm.name { - FileName::Real(filename) => { - let path = format!("{}.map", filename.display()); - let file = File::open(&path).ok()?; - Some(sourcemap::SourceMap::from_reader(file).with_context(|| { - format!("failed to read input source map from file at {}", path) - })) - } - _ => { - log::error!("Failed to load source map for non-file input"); - return None; - } - } - } - InputSourceMap::Str(ref s) => { - if s == "inline" { - // Load inline source map by simple string - // operations - let s = "sourceMappingURL=data:application/json;base64,"; - let idx = s.rfind(s)?; - let encoded = &s[idx + s.len()..]; - - let res = base64::decode(encoded.as_bytes()) - .context("failed to decode base64-encoded source map"); - let res = match res { - Ok(v) => v, - Err(err) => return Some(Err(err)), - }; - - Some(sourcemap::SourceMap::from_slice(&res).context( - "failed to read input source map from inlined base64 encoded \ - string", - )) - } else { - // Load source map passed by user - Some(sourcemap::SourceMap::from_slice(s.as_bytes()).context( - "failed to read input source map from user-provided sourcemap", - )) - } - } - } - })(); - - let orig = match orig { - None => None, - Some(v) => Some(v?), - }; - let session = ParseSess { handler: &self.handler, }; @@ -179,7 +183,7 @@ impl Compiler { .map(Program::Script)? }; - Ok((program, orig)) + Ok(program) }) } @@ -365,16 +369,16 @@ impl Compiler { ) -> Result { self.run(|| -> Result<_, Error> { let config = self.run(|| self.config_for_file(opts, &fm.name))?; - let (program, src_map) = self.parse_js( + let orig = self.get_orig_src_map(&fm.name, &opts.input_source_map)?; + let program = self.parse_js( fm.clone(), config.target, config.syntax, config.is_module, true, - &config.input_source_map, )?; - self.process_js_inner(program, src_map, config) + self.process_js_inner(program, orig.as_ref(), config) }) .context("failed to process js file") } @@ -382,19 +386,15 @@ impl Compiler { /// You can use custom pass with this method. /// /// There exists a [PassBuilder] to help building custom passes. - pub fn process_js( - &self, - program: Program, - src_map: Option, - opts: &Options, - ) -> Result { + pub fn process_js(&self, program: Program, opts: &Options) -> Result { self.run(|| -> Result<_, Error> { let loc = self.cm.lookup_char_pos(program.span().lo()); let fm = loc.file; + let orig = self.get_orig_src_map(&fm.name, &opts.input_source_map)?; let config = self.run(|| self.config_for_file(opts, &fm.name))?; - self.process_js_inner(program, src_map, config) + self.process_js_inner(program, orig.as_ref(), config) }) .context("failed to process js module") } @@ -402,7 +402,7 @@ impl Compiler { fn process_js_inner( &self, program: Program, - src_map: Option, + orig: Option<&sourcemap::SourceMap>, config: BuiltConfig, ) -> Result { self.run(|| { @@ -426,7 +426,7 @@ impl Compiler { &program, &self.comments, config.source_maps, - src_map.as_ref(), + orig, config.minify, ) }) diff --git a/wasm/src/lib.rs b/wasm/src/lib.rs index 0f1c022d462..93b92ef792e 100644 --- a/wasm/src/lib.rs +++ b/wasm/src/lib.rs @@ -11,7 +11,7 @@ use swc::{ errors::{EmitterWriter, Handler, HandlerFlags, SourceMapperDyn}, FileName, FilePathMapping, SourceMap, }, - config::{InputSourceMap, Options, ParseOptions, SourceMapsConfig}, + config::{Options, ParseOptions, SourceMapsConfig}, ecmascript::ast::Program, Compiler, }; @@ -28,28 +28,11 @@ pub fn parse_sync(s: &str, opts: JsValue) -> Result { let (c, errors) = compiler(); let fm = c.cm.new_source_file(FileName::Anon, s.into()); - let (prog, src_map) = c - .parse_js( - fm, - opts.target, - opts.syntax, - opts.is_module, - opts.comments, - &InputSourceMap::Bool(false), - ) + let program = c + .parse_js(fm, opts.target, opts.syntax, opts.is_module, opts.comments) .map_err(|err| format!("failed to parse: {}\n{}", err, errors))?; - let mut source_map = vec![]; - if let Some(src_map) = src_map { - src_map - .to_writer(&mut source_map) - .map_err(|err| format!("failed to print source map file: {}", err))?; - } - - Ok( - JsValue::from_serde(&(prog, &*String::from_utf8_lossy(&source_map))) - .map_err(|err| format!("failed to return value: {}", err))?, - ) + Ok(JsValue::from_serde(&program).map_err(|err| format!("failed to return value: {}", err))?) } #[wasm_bindgen(js_name = "printSync")]