feat(swc): Allow removing filename from error output (#2498)

swc:
 - Add an option to exclude filename from error messages.
This commit is contained in:
Donny/강동윤 2021-10-21 13:45:12 +09:00 committed by GitHub
parent d83bde8ca5
commit ecf0d7507c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 107 additions and 54 deletions

12
Cargo.lock generated
View File

@ -194,9 +194,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "backtrace"
version = "0.3.61"
version = "0.3.62"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01"
checksum = "091bcdf2da9950f96aa522681ce805e6857f6ca8df73833d35736ab2dc78e152"
dependencies = [
"addr2line",
"cc",
@ -1317,9 +1317,9 @@ dependencies = [
[[package]]
name = "object"
version = "0.26.2"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
checksum = "c821014c18301591b89b843809ef953af9e3df0496c232d5c0611b0a52aac363"
dependencies = [
"memchr",
]
@ -2325,7 +2325,7 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "swc"
version = "0.76.1"
version = "0.77.0"
dependencies = [
"ahash",
"anyhow",
@ -2473,7 +2473,7 @@ dependencies = [
[[package]]
name = "swc_common"
version = "0.14.1"
version = "0.14.2"
dependencies = [
"ahash",
"arbitrary",

View File

@ -21,7 +21,7 @@ include = ["Cargo.toml", "src/**/*.rs"]
license = "Apache-2.0/MIT"
name = "swc"
repository = "https://github.com/swc-project/swc.git"
version = "0.76.1"
version = "0.77.0"
[lib]
name = "swc"

View File

@ -6,7 +6,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_common"
repository = "https://github.com/swc-project/swc.git"
version = "0.14.1"
version = "0.14.2"
[features]
concurrent = ["parking_lot"]

View File

@ -139,6 +139,8 @@ pub struct EmitterWriter {
short_message: bool,
teach: bool,
ui_testing: bool,
skip_filename: bool,
}
struct FileWithAnnotatedLines {
@ -162,6 +164,7 @@ impl EmitterWriter {
short_message,
teach,
ui_testing: false,
skip_filename: false,
}
}
}
@ -179,6 +182,7 @@ impl EmitterWriter {
short_message,
teach,
ui_testing: false,
skip_filename: false,
}
}
@ -187,6 +191,11 @@ impl EmitterWriter {
self
}
pub fn skip_filename(mut self, skip_filename: bool) -> Self {
self.skip_filename = skip_filename;
self
}
fn maybe_anonymized(&self, line_num: usize) -> String {
if self.ui_testing {
ANONYMIZED_LINE_NUM.to_string()
@ -1011,17 +1020,21 @@ impl EmitterWriter {
// remember where we are in the output buffer for easy reference
let buffer_msg_line_offset = buffer.num_lines();
buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber);
buffer.append(
buffer_msg_line_offset,
&format!(
"{}:{}:{}",
loc.file.name,
sm.doctest_offset_line(loc.line),
loc.col.0 + 1
),
Style::LineAndColumn,
);
if !self.skip_filename {
buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber);
buffer.append(
buffer_msg_line_offset,
&format!(
"{}:{}:{}",
loc.file.name,
sm.doctest_offset_line(loc.line),
loc.col.0 + 1
),
Style::LineAndColumn,
);
}
for _ in 0..max_line_num_len {
buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle);
}

View File

@ -108,6 +108,7 @@
"stmts",
"succ",
"sugg",
"swcify",
"swcpack",
"swcrc",
"termcolor",
@ -115,7 +116,8 @@
"uncons",
"Unexported",
"Unexporter",
"unimpl"
"unimpl",
"untrusted"
],
"flagWords": [
"actally"

View File

@ -160,3 +160,17 @@ it("should respect `inlineSourcesContent`", async () => {
expect(j).toHaveProperty('sourcesContent')
});
it("should respect `error.filename = false`", async () => {
const src = 'export default <h1>';
try {
await swc.transform(src, {
error: {
filename: false
}
})
} catch (e) {
expect(e).not.toContain("-->")
}
});

View File

@ -48,7 +48,7 @@ impl Task for MinifyTask {
type JsValue = JsObject;
fn compute(&mut self) -> napi::Result<Self::Output> {
try_with(self.c.cm.clone(), |handler| {
try_with(self.c.cm.clone(), false, |handler| {
let fm = self.code.to_file(self.c.cm.clone());
self.c.minify(fm, &handler, &self.opts)
@ -82,7 +82,8 @@ pub fn minify_sync(cx: CallContext) -> napi::Result<JsObject> {
let fm = code.to_file(c.cm.clone());
let output = try_with(c.cm.clone(), |handler| c.minify(fm, &handler, &opts)).convert_err()?;
let output =
try_with(c.cm.clone(), false, |handler| c.minify(fm, &handler, &opts)).convert_err()?;
complete_output(&cx.env, output)
}

View File

@ -38,7 +38,7 @@ impl Task for ParseTask {
type JsValue = JsString;
fn compute(&mut self) -> napi::Result<Self::Output> {
let program = try_with(self.c.cm.clone(), |handler| {
let program = try_with(self.c.cm.clone(), false, |handler| {
self.c.parse_js(
self.fm.clone(),
&handler,
@ -63,7 +63,7 @@ impl Task for ParseFileTask {
type JsValue = JsString;
fn compute(&mut self) -> napi::Result<Self::Output> {
try_with(self.c.cm.clone(), |handler| {
try_with(self.c.cm.clone(), false, |handler| {
self.c.run(|| {
let fm = self
.c
@ -125,7 +125,7 @@ pub fn parse_sync(cx: CallContext) -> napi::Result<JsString> {
FileName::Anon
};
let program = try_with(c.cm.clone(), |handler| {
let program = try_with(c.cm.clone(), false, |handler| {
c.run(|| {
let fm = c.cm.new_source_file(filename, src);
c.parse_js(
@ -150,7 +150,7 @@ pub fn parse_file_sync(cx: CallContext) -> napi::Result<JsString> {
let options: ParseOptions = cx.get_deserialized(1)?;
let program = {
try_with(c.cm.clone(), |handler| {
try_with(c.cm.clone(), false, |handler| {
let fm =
c.cm.load_file(Path::new(path.as_str()?))
.expect("failed to read program file");

View File

@ -35,23 +35,29 @@ impl Task for TransformTask {
type JsValue = JsObject;
fn compute(&mut self) -> napi::Result<Self::Output> {
try_with(self.c.cm.clone(), |handler| {
self.c.run(|| match self.input {
Input::Program(ref s) => {
let program: Program =
deserialize_json(&s).expect("failed to deserialize Program");
// TODO: Source map
self.c.process_js(&handler, program, &self.options)
}
try_with(
self.c.cm.clone(),
!self.options.config.error.filename,
|handler| {
self.c.run(|| match self.input {
Input::Program(ref s) => {
let program: Program =
deserialize_json(&s).expect("failed to deserialize Program");
// TODO: Source map
self.c.process_js(&handler, program, &self.options)
}
Input::File(ref path) => {
let fm = self.c.cm.load_file(path).context("failed to load file")?;
self.c.process_js_file(fm, &handler, &self.options)
}
Input::File(ref path) => {
let fm = self.c.cm.load_file(path).context("failed to load file")?;
self.c.process_js_file(fm, &handler, &self.options)
}
Input::Source(ref s) => self.c.process_js_file(s.clone(), &handler, &self.options),
})
})
Input::Source(ref s) => {
self.c.process_js_file(s.clone(), &handler, &self.options)
}
})
},
)
.convert_err()
}
@ -93,7 +99,7 @@ where
options.config.adjust(Path::new(&options.filename));
}
let output = try_with(c.cm.clone(), |handler| {
let output = try_with(c.cm.clone(), !options.config.error.filename, |handler| {
c.run(|| {
if is_module.get_value()? {
let program: Program =

View File

@ -8,11 +8,11 @@ use std::{
use swc::try_with_handler;
use swc_common::{errors::Handler, sync::Lrc, SourceMap};
pub fn try_with<F, Ret>(cm: Lrc<SourceMap>, op: F) -> Result<Ret, Error>
pub fn try_with<F, Ret>(cm: Lrc<SourceMap>, skip_filename: bool, op: F) -> Result<Ret, Error>
where
F: FnOnce(&Handler) -> Result<Ret, Error>,
{
try_with_handler(cm, |handler| {
try_with_handler(cm, skip_filename, |handler| {
//
let result = catch_unwind(AssertUnwindSafe(|| op(handler)));

View File

@ -290,7 +290,7 @@ impl SwcLoader {
impl Load for SwcLoader {
fn load(&self, name: &FileName) -> Result<ModuleData, Error> {
try_with_handler(self.compiler.cm.clone(), |handler| {
try_with_handler(self.compiler.cm.clone(), false, |handler| {
self.load_with_handler(&handler, name)
})
}

View File

@ -526,6 +526,9 @@ pub struct Config {
#[serde(default = "true_by_default")]
pub inline_sources_content: bool,
#[serde(default)]
pub error: ErrorConfig,
}
/// Second argument of `minify`.
@ -988,6 +991,13 @@ fn default_jsonify_min_cost() -> usize {
1024
}
#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct ErrorConfig {
#[serde(default = "true_by_default")]
pub filename: bool,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct GlobalPassOption {

View File

@ -117,7 +117,7 @@ use crate::config::{
};
use anyhow::{bail, Context, Error};
use atoms::JsWord;
use common::collections::AHashMap;
use common::{collections::AHashMap, errors::EmitterWriter};
use config::{util::BoolOrObject, JsMinifyCommentOption, JsMinifyOptions};
use dashmap::DashMap;
use once_cell::sync::Lazy;
@ -210,13 +210,19 @@ impl Write for LockedWriter {
/// Try operation with a [Handler] and prints the errors as a [String] wrapped
/// by [Err].
pub fn try_with_handler<F, Ret>(cm: Lrc<SourceMap>, op: F) -> Result<Ret, Error>
pub fn try_with_handler<F, Ret>(
cm: Lrc<SourceMap>,
skip_filename: bool,
op: F,
) -> Result<Ret, Error>
where
F: FnOnce(&Handler) -> Result<Ret, Error>,
{
let wr = Box::new(LockedWriter::default());
let handler = Handler::with_emitter_writer(wr.clone(), Some(cm.clone()));
let e_wr =
EmitterWriter::new(wr.clone(), Some(cm.clone()), false, true).skip_filename(skip_filename);
let handler = Handler::with_emitter(true, false, Box::new(e_wr));
let ret = swc_ecma_utils::HANDLER.set(&handler, || op(&handler));

View File

@ -2,12 +2,12 @@ use std::path::Path;
use swc::{config::Options, Compiler};
use testing::{NormalizedOutput, Tester};
fn file(f: &str) -> NormalizedOutput {
fn file(f: impl AsRef<Path>) -> NormalizedOutput {
Tester::new()
.print_errors(|cm, handler| -> Result<NormalizedOutput, _> {
let c = Compiler::new(cm.clone());
let fm = cm.load_file(Path::new(f)).expect("failed to load file");
let fm = cm.load_file(f.as_ref()).expect("failed to load file");
let s = c.process_js_file(
fm,
&handler,

View File

@ -148,6 +148,7 @@ fn shopify_2_same_opt() {
input_source_map: InputSourceMap::Bool(false),
source_maps: None,
inline_sources_content: false,
..Default::default()
},
skip_helper_injection: false,
disable_hygiene: false,

View File

@ -19,7 +19,7 @@ pub fn minify_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
let c = compiler();
try_with_handler(c.cm.clone(), |handler| {
try_with_handler(c.cm.clone(), false, |handler| {
let opts: JsMinifyOptions = opts.into_serde().context("failed to parse options")?;
let fm = c.cm.new_source_file(FileName::Anon, s.into());
@ -38,7 +38,7 @@ pub fn parse_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
let c = compiler();
try_with_handler(c.cm.clone(), |handler| {
try_with_handler(c.cm.clone(), false, |handler| {
let opts: ParseOptions = opts.into_serde().context("failed to parse options")?;
let fm = c.cm.new_source_file(FileName::Anon, s.into());
@ -64,7 +64,7 @@ pub fn print_sync(s: JsValue, opts: JsValue) -> Result<JsValue, JsValue> {
let c = compiler();
try_with_handler(c.cm.clone(), |_handler| {
try_with_handler(c.cm.clone(), false, |_handler| {
let opts: Options = opts.into_serde().context("failed to parse options")?;
let program: Program = s.into_serde().context("failed to deserialize program")?;
@ -97,7 +97,7 @@ pub fn transform_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
let c = compiler();
try_with_handler(c.cm.clone(), |handler| {
try_with_handler(c.cm.clone(), false, |handler| {
let opts: Options = opts.into_serde().context("failed to parse options")?;
let fm = c.cm.new_source_file(