mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 13:51:19 +03:00
feat(swc): Allow removing filename from error output (#2498)
swc: - Add an option to exclude filename from error messages.
This commit is contained in:
parent
d83bde8ca5
commit
ecf0d7507c
12
Cargo.lock
generated
12
Cargo.lock
generated
@ -194,9 +194,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.61"
|
version = "0.3.62"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e7a905d892734eea339e896738c14b9afce22b5318f64b951e70bf3844419b01"
|
checksum = "091bcdf2da9950f96aa522681ce805e6857f6ca8df73833d35736ab2dc78e152"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
"addr2line",
|
||||||
"cc",
|
"cc",
|
||||||
@ -1317,9 +1317,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.26.2"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
|
checksum = "c821014c18301591b89b843809ef953af9e3df0496c232d5c0611b0a52aac363"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@ -2325,7 +2325,7 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "swc"
|
name = "swc"
|
||||||
version = "0.76.1"
|
version = "0.77.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@ -2473,7 +2473,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "swc_common"
|
name = "swc_common"
|
||||||
version = "0.14.1"
|
version = "0.14.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"arbitrary",
|
"arbitrary",
|
||||||
|
@ -21,7 +21,7 @@ include = ["Cargo.toml", "src/**/*.rs"]
|
|||||||
license = "Apache-2.0/MIT"
|
license = "Apache-2.0/MIT"
|
||||||
name = "swc"
|
name = "swc"
|
||||||
repository = "https://github.com/swc-project/swc.git"
|
repository = "https://github.com/swc-project/swc.git"
|
||||||
version = "0.76.1"
|
version = "0.77.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "swc"
|
name = "swc"
|
||||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
|||||||
license = "Apache-2.0/MIT"
|
license = "Apache-2.0/MIT"
|
||||||
name = "swc_common"
|
name = "swc_common"
|
||||||
repository = "https://github.com/swc-project/swc.git"
|
repository = "https://github.com/swc-project/swc.git"
|
||||||
version = "0.14.1"
|
version = "0.14.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
concurrent = ["parking_lot"]
|
concurrent = ["parking_lot"]
|
||||||
|
@ -139,6 +139,8 @@ pub struct EmitterWriter {
|
|||||||
short_message: bool,
|
short_message: bool,
|
||||||
teach: bool,
|
teach: bool,
|
||||||
ui_testing: bool,
|
ui_testing: bool,
|
||||||
|
|
||||||
|
skip_filename: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FileWithAnnotatedLines {
|
struct FileWithAnnotatedLines {
|
||||||
@ -162,6 +164,7 @@ impl EmitterWriter {
|
|||||||
short_message,
|
short_message,
|
||||||
teach,
|
teach,
|
||||||
ui_testing: false,
|
ui_testing: false,
|
||||||
|
skip_filename: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,6 +182,7 @@ impl EmitterWriter {
|
|||||||
short_message,
|
short_message,
|
||||||
teach,
|
teach,
|
||||||
ui_testing: false,
|
ui_testing: false,
|
||||||
|
skip_filename: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +191,11 @@ impl EmitterWriter {
|
|||||||
self
|
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 {
|
fn maybe_anonymized(&self, line_num: usize) -> String {
|
||||||
if self.ui_testing {
|
if self.ui_testing {
|
||||||
ANONYMIZED_LINE_NUM.to_string()
|
ANONYMIZED_LINE_NUM.to_string()
|
||||||
@ -1011,7 +1020,9 @@ impl EmitterWriter {
|
|||||||
// remember where we are in the output buffer for easy reference
|
// remember where we are in the output buffer for easy reference
|
||||||
let buffer_msg_line_offset = buffer.num_lines();
|
let buffer_msg_line_offset = buffer.num_lines();
|
||||||
|
|
||||||
|
if !self.skip_filename {
|
||||||
buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber);
|
buffer.prepend(buffer_msg_line_offset, "--> ", Style::LineNumber);
|
||||||
|
|
||||||
buffer.append(
|
buffer.append(
|
||||||
buffer_msg_line_offset,
|
buffer_msg_line_offset,
|
||||||
&format!(
|
&format!(
|
||||||
@ -1022,6 +1033,8 @@ impl EmitterWriter {
|
|||||||
),
|
),
|
||||||
Style::LineAndColumn,
|
Style::LineAndColumn,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
for _ in 0..max_line_num_len {
|
for _ in 0..max_line_num_len {
|
||||||
buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle);
|
buffer.prepend(buffer_msg_line_offset, " ", Style::NoStyle);
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,7 @@
|
|||||||
"stmts",
|
"stmts",
|
||||||
"succ",
|
"succ",
|
||||||
"sugg",
|
"sugg",
|
||||||
|
"swcify",
|
||||||
"swcpack",
|
"swcpack",
|
||||||
"swcrc",
|
"swcrc",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
@ -115,7 +116,8 @@
|
|||||||
"uncons",
|
"uncons",
|
||||||
"Unexported",
|
"Unexported",
|
||||||
"Unexporter",
|
"Unexporter",
|
||||||
"unimpl"
|
"unimpl",
|
||||||
|
"untrusted"
|
||||||
],
|
],
|
||||||
"flagWords": [
|
"flagWords": [
|
||||||
"actally"
|
"actally"
|
||||||
|
@ -160,3 +160,17 @@ it("should respect `inlineSourcesContent`", async () => {
|
|||||||
|
|
||||||
expect(j).toHaveProperty('sourcesContent')
|
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("-->")
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
@ -48,7 +48,7 @@ impl Task for MinifyTask {
|
|||||||
type JsValue = JsObject;
|
type JsValue = JsObject;
|
||||||
|
|
||||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
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());
|
let fm = self.code.to_file(self.c.cm.clone());
|
||||||
|
|
||||||
self.c.minify(fm, &handler, &self.opts)
|
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 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)
|
complete_output(&cx.env, output)
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ impl Task for ParseTask {
|
|||||||
type JsValue = JsString;
|
type JsValue = JsString;
|
||||||
|
|
||||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
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.c.parse_js(
|
||||||
self.fm.clone(),
|
self.fm.clone(),
|
||||||
&handler,
|
&handler,
|
||||||
@ -63,7 +63,7 @@ impl Task for ParseFileTask {
|
|||||||
type JsValue = JsString;
|
type JsValue = JsString;
|
||||||
|
|
||||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
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(|| {
|
self.c.run(|| {
|
||||||
let fm = self
|
let fm = self
|
||||||
.c
|
.c
|
||||||
@ -125,7 +125,7 @@ pub fn parse_sync(cx: CallContext) -> napi::Result<JsString> {
|
|||||||
FileName::Anon
|
FileName::Anon
|
||||||
};
|
};
|
||||||
|
|
||||||
let program = try_with(c.cm.clone(), |handler| {
|
let program = try_with(c.cm.clone(), false, |handler| {
|
||||||
c.run(|| {
|
c.run(|| {
|
||||||
let fm = c.cm.new_source_file(filename, src);
|
let fm = c.cm.new_source_file(filename, src);
|
||||||
c.parse_js(
|
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 options: ParseOptions = cx.get_deserialized(1)?;
|
||||||
|
|
||||||
let program = {
|
let program = {
|
||||||
try_with(c.cm.clone(), |handler| {
|
try_with(c.cm.clone(), false, |handler| {
|
||||||
let fm =
|
let fm =
|
||||||
c.cm.load_file(Path::new(path.as_str()?))
|
c.cm.load_file(Path::new(path.as_str()?))
|
||||||
.expect("failed to read program file");
|
.expect("failed to read program file");
|
||||||
|
@ -35,7 +35,10 @@ impl Task for TransformTask {
|
|||||||
type JsValue = JsObject;
|
type JsValue = JsObject;
|
||||||
|
|
||||||
fn compute(&mut self) -> napi::Result<Self::Output> {
|
fn compute(&mut self) -> napi::Result<Self::Output> {
|
||||||
try_with(self.c.cm.clone(), |handler| {
|
try_with(
|
||||||
|
self.c.cm.clone(),
|
||||||
|
!self.options.config.error.filename,
|
||||||
|
|handler| {
|
||||||
self.c.run(|| match self.input {
|
self.c.run(|| match self.input {
|
||||||
Input::Program(ref s) => {
|
Input::Program(ref s) => {
|
||||||
let program: Program =
|
let program: Program =
|
||||||
@ -49,9 +52,12 @@ impl Task for TransformTask {
|
|||||||
self.c.process_js_file(fm, &handler, &self.options)
|
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()
|
.convert_err()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +99,7 @@ where
|
|||||||
options.config.adjust(Path::new(&options.filename));
|
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(|| {
|
c.run(|| {
|
||||||
if is_module.get_value()? {
|
if is_module.get_value()? {
|
||||||
let program: Program =
|
let program: Program =
|
||||||
|
@ -8,11 +8,11 @@ use std::{
|
|||||||
use swc::try_with_handler;
|
use swc::try_with_handler;
|
||||||
use swc_common::{errors::Handler, sync::Lrc, SourceMap};
|
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
|
where
|
||||||
F: FnOnce(&Handler) -> Result<Ret, Error>,
|
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)));
|
let result = catch_unwind(AssertUnwindSafe(|| op(handler)));
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ impl SwcLoader {
|
|||||||
|
|
||||||
impl Load for SwcLoader {
|
impl Load for SwcLoader {
|
||||||
fn load(&self, name: &FileName) -> Result<ModuleData, Error> {
|
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)
|
self.load_with_handler(&handler, name)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -526,6 +526,9 @@ pub struct Config {
|
|||||||
|
|
||||||
#[serde(default = "true_by_default")]
|
#[serde(default = "true_by_default")]
|
||||||
pub inline_sources_content: bool,
|
pub inline_sources_content: bool,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub error: ErrorConfig,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Second argument of `minify`.
|
/// Second argument of `minify`.
|
||||||
@ -988,6 +991,13 @@ fn default_jsonify_min_cost() -> usize {
|
|||||||
1024
|
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)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||||
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
#[serde(deny_unknown_fields, rename_all = "camelCase")]
|
||||||
pub struct GlobalPassOption {
|
pub struct GlobalPassOption {
|
||||||
|
12
src/lib.rs
12
src/lib.rs
@ -117,7 +117,7 @@ use crate::config::{
|
|||||||
};
|
};
|
||||||
use anyhow::{bail, Context, Error};
|
use anyhow::{bail, Context, Error};
|
||||||
use atoms::JsWord;
|
use atoms::JsWord;
|
||||||
use common::collections::AHashMap;
|
use common::{collections::AHashMap, errors::EmitterWriter};
|
||||||
use config::{util::BoolOrObject, JsMinifyCommentOption, JsMinifyOptions};
|
use config::{util::BoolOrObject, JsMinifyCommentOption, JsMinifyOptions};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use once_cell::sync::Lazy;
|
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
|
/// Try operation with a [Handler] and prints the errors as a [String] wrapped
|
||||||
/// by [Err].
|
/// 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
|
where
|
||||||
F: FnOnce(&Handler) -> Result<Ret, Error>,
|
F: FnOnce(&Handler) -> Result<Ret, Error>,
|
||||||
{
|
{
|
||||||
let wr = Box::new(LockedWriter::default());
|
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));
|
let ret = swc_ecma_utils::HANDLER.set(&handler, || op(&handler));
|
||||||
|
|
||||||
|
@ -2,12 +2,12 @@ use std::path::Path;
|
|||||||
use swc::{config::Options, Compiler};
|
use swc::{config::Options, Compiler};
|
||||||
use testing::{NormalizedOutput, Tester};
|
use testing::{NormalizedOutput, Tester};
|
||||||
|
|
||||||
fn file(f: &str) -> NormalizedOutput {
|
fn file(f: impl AsRef<Path>) -> NormalizedOutput {
|
||||||
Tester::new()
|
Tester::new()
|
||||||
.print_errors(|cm, handler| -> Result<NormalizedOutput, _> {
|
.print_errors(|cm, handler| -> Result<NormalizedOutput, _> {
|
||||||
let c = Compiler::new(cm.clone());
|
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(
|
let s = c.process_js_file(
|
||||||
fm,
|
fm,
|
||||||
&handler,
|
&handler,
|
||||||
|
@ -148,6 +148,7 @@ fn shopify_2_same_opt() {
|
|||||||
input_source_map: InputSourceMap::Bool(false),
|
input_source_map: InputSourceMap::Bool(false),
|
||||||
source_maps: None,
|
source_maps: None,
|
||||||
inline_sources_content: false,
|
inline_sources_content: false,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
skip_helper_injection: false,
|
skip_helper_injection: false,
|
||||||
disable_hygiene: false,
|
disable_hygiene: false,
|
||||||
|
@ -19,7 +19,7 @@ pub fn minify_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
|
|||||||
|
|
||||||
let c = compiler();
|
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 opts: JsMinifyOptions = opts.into_serde().context("failed to parse options")?;
|
||||||
|
|
||||||
let fm = c.cm.new_source_file(FileName::Anon, s.into());
|
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();
|
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 opts: ParseOptions = opts.into_serde().context("failed to parse options")?;
|
||||||
|
|
||||||
let fm = c.cm.new_source_file(FileName::Anon, s.into());
|
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();
|
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 opts: Options = opts.into_serde().context("failed to parse options")?;
|
||||||
|
|
||||||
let program: Program = s.into_serde().context("failed to deserialize program")?;
|
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();
|
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 opts: Options = opts.into_serde().context("failed to parse options")?;
|
||||||
|
|
||||||
let fm = c.cm.new_source_file(
|
let fm = c.cm.new_source_file(
|
||||||
|
Loading…
Reference in New Issue
Block a user