From 765aa6867dba653aeee57a9506a11fa22a890f91 Mon Sep 17 00:00:00 2001 From: "guodeshi.gds" Date: Thu, 2 Mar 2023 21:44:51 +0800 Subject: [PATCH] fix: Fix the problem that the inline sourcemap file reports an error when inputSourceMap is set to true --- crates/swc/src/lib.rs | 174 ++++++++++--------- crates/swc/tests/source_map.rs | 5 + crates/swc/tests/srcmap/case-inline/.swcrc | 3 + crates/swc/tests/srcmap/case-inline/index.js | 26 +++ 4 files changed, 129 insertions(+), 79 deletions(-) create mode 100644 crates/swc/tests/srcmap/case-inline/.swcrc create mode 100644 crates/swc/tests/srcmap/case-inline/index.js diff --git a/crates/swc/src/lib.rs b/crates/swc/src/lib.rs index ba24f069dd9d..833403ac0489 100644 --- a/crates/swc/src/lib.rs +++ b/crates/swc/src/lib.rs @@ -269,99 +269,115 @@ impl Compiler { self.run(|| -> Result<_, Error> { let name = &fm.name; - // Load original source map - match input_src_map { - InputSourceMap::Bool(false) => Ok(None), - InputSourceMap::Bool(true) => { - let s = "sourceMappingURL="; - let idx = fm.src.rfind(s); - let src_mapping_url = idx.map(|idx| &fm.src[idx + s.len()..]); - - // Load original source map if possible - match &name { - FileName::Real(filename) => { - let dir = match filename.parent() { + let read_inline_sourcemap = + |data_url: Option<&str>| -> Result, Error> { + match data_url { + Some(data_url) => { + let url = Url::parse(data_url).with_context(|| { + format!("failed to parse inline source map url\n{}", data_url) + })?; + + let idx = match url.path().find("base64,") { Some(v) => v, None => { - bail!("unexpected: root directory is given as a input file") - } - }; - - let path = match src_mapping_url { - Some(src_mapping_url) => { - dir.join(src_mapping_url).display().to_string() - } - None => { - format!("{}.map", dir.join(filename).display()) + bail!( + "failed to parse inline source map: not base64: {:?}", + url + ) } }; - let file = File::open(&path) - .or_else(|err| { - // Old behavior. This check would prevent regressions. - let f = format!("{}.map", filename.display()); + let content = url.path()[idx + "base64,".len()..].trim(); - match File::open(&f) { - Ok(v) => Ok(v), - Err(_) => Err(err), - } - }) - .context("failed to open input source map file"); - - let file = if !is_default { - file? - } else { - match file { - Ok(v) => v, - Err(_) => return Ok(None), - } - }; + let res = base64::decode_config( + content.as_bytes(), + base64::Config::new(base64::CharacterSet::Standard, true), + ) + .context("failed to decode base64-encoded source map")?; - Ok(Some(sourcemap::SourceMap::from_reader(file).with_context( - || format!("failed to read input source map from file at {}", path), + Ok(Some(sourcemap::SourceMap::from_slice(&res).context( + "failed to read input source map from inlined base64 encoded \ + string", )?)) } - _ => { - tracing::error!("Failed to load source map for non-file input"); - Ok(None) + None => { + bail!("failed to parse inline source map: `sourceMappingURL` not found") } } - } - InputSourceMap::Str(ref s) => { - if s == "inline" { - const NEEDLE: &str = "sourceMappingURL="; - // Load inline source map by simple string - // operations - let idx = fm.src.rfind(NEEDLE); - let idx = match idx { - None => bail!( - "failed to parse inline source map: `sourceMappingURL` not found" - ), - Some(v) => v, - }; - let data_url = fm.src[idx + NEEDLE.len()..].trim(); - let url = Url::parse(data_url).with_context(|| { - format!("failed to parse inline source map url\n{}", data_url) - })?; - - let idx = match url.path().find("base64,") { - Some(v) => v, - None => { - bail!("failed to parse inline source map: not base64: {:?}", url) - } - }; + }; - let content = url.path()[idx + "base64,".len()..].trim(); + let read_sourcemap = || -> Result, Error> { + let s = "sourceMappingURL="; + let idx = fm.src.rfind(s); + let data_url = idx.map(|idx| &fm.src[idx + s.len()..]); + + match read_inline_sourcemap(data_url) { + Ok(r) => Ok(r), + Err(_) => { + // Load original source map if possible + match &name { + FileName::Real(filename) => { + let dir = match filename.parent() { + Some(v) => v, + None => { + bail!("unexpected: root directory is given as a input file") + } + }; - let res = base64::decode_config( - content.as_bytes(), - base64::Config::new(base64::CharacterSet::Standard, true), - ) - .context("failed to decode base64-encoded source map")?; + let path = match data_url { + Some(data_url) => dir.join(data_url).display().to_string(), + None => { + format!("{}.map", dir.join(filename).display()) + } + }; + + let file = File::open(&path) + .or_else(|err| { + // Old behavior. This check would prevent + // regressions. + let f = format!("{}.map", filename.display()); + + match File::open(&f) { + Ok(v) => Ok(v), + Err(_) => Err(err), + } + }) + .context("failed to open input source map file"); + + let file = if !is_default { + file? + } else { + match file { + Ok(v) => v, + Err(_) => return Ok(None), + } + }; + + Ok(Some(sourcemap::SourceMap::from_reader(file).with_context( + || { + format!( + "failed to read input source map from file at {}", + path + ) + }, + )?)) + } + _ => { + tracing::error!("Failed to load source map for non-file input"); + Ok(None) + } + } + } + } + }; - Ok(Some(sourcemap::SourceMap::from_slice(&res).context( - "failed to read input source map from inlined base64 encoded string", - )?)) + // Load original source map + match input_src_map { + InputSourceMap::Bool(false) => Ok(None), + InputSourceMap::Bool(true) => read_sourcemap(), + InputSourceMap::Str(ref s) => { + if s == "inline" { + read_sourcemap() } else { // Load source map passed by user Ok(Some( diff --git a/crates/swc/tests/source_map.rs b/crates/swc/tests/source_map.rs index 340c720185dd..8088c0322118 100644 --- a/crates/swc/tests/source_map.rs +++ b/crates/swc/tests/source_map.rs @@ -69,6 +69,11 @@ fn file(f: &str, config: Config) -> Result<(), StdErr> { }) } +#[test] +fn case_inline() { + inline("tests/srcmap/case-inline/index.js"); +} + #[test] fn issue_622() { file("tests/srcmap/issue-622/index.js", Default::default()).unwrap(); diff --git a/crates/swc/tests/srcmap/case-inline/.swcrc b/crates/swc/tests/srcmap/case-inline/.swcrc new file mode 100644 index 000000000000..8a045416438b --- /dev/null +++ b/crates/swc/tests/srcmap/case-inline/.swcrc @@ -0,0 +1,3 @@ +{ + "inputSourceMap": true, +} \ No newline at end of file diff --git a/crates/swc/tests/srcmap/case-inline/index.js b/crates/swc/tests/srcmap/case-inline/index.js new file mode 100644 index 000000000000..7db3ed91a601 --- /dev/null +++ b/crates/swc/tests/srcmap/case-inline/index.js @@ -0,0 +1,26 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var Foo = /** @class */ (function () { + function Foo() { + } + return Foo; +}()); +var Bar = /** @class */ (function (_super) { + __extends(Bar, _super); + function Bar() { + return _super !== null && _super.apply(this, arguments) || this; + } + return Bar; +}(Foo)); +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7O0FBQUE7SUFBQTtJQUVBLENBQUM7SUFBRCxVQUFDO0FBQUQsQ0FBQyxBQUZELElBRUM7QUFFRDtJQUFrQix1QkFBRztJQUFyQjs7SUFFQSxDQUFDO0lBQUQsVUFBQztBQUFELENBQUMsQUFGRCxDQUFrQixHQUFHLEdBRXBCIn0= \ No newline at end of file