Skip to content

Commit

Permalink
🦄 refactor: Add anyhow to revise error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
caoccao committed Jul 30, 2024
1 parent dab9ddd commit 6e025b2
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 136 deletions.
4 changes: 4 additions & 0 deletions docs/release_notes.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Release Notes

## 0.11.0

* Revised internal error handling

## 0.10.0

* Upgraded deno_ast to v0.40.0
Expand Down
1 change: 1 addition & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
crate_type = ["cdylib", "rlib"]
crate-type = ["cdylib", "rlib"]

[dependencies]
base64 = "0.22.1"
Expand All @@ -32,3 +32,4 @@ deno_ast = { version = "0.40.0", features = [
] }
jni = "0.21.1"
num-bigint = "0.4.5"
anyhow = "1.0.86"
217 changes: 95 additions & 122 deletions rust/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
* limitations under the License.
*/

use anyhow::{Error, Result};
use base64::Engine;

use deno_ast::swc::ast::Program;
use deno_ast::swc::codegen::{text_writer::JsWriter, Config, Emitter};
use deno_ast::swc::common::{sync::Lrc, FileName, FilePathMapping, SourceMap};
Expand All @@ -30,8 +30,8 @@ fn parse_by_mode(
parse_params: ParseParams,
parse_mode: enums::ParseMode,
plugin_host: &mut Option<plugin_utils::PluginHost>,
) -> Result<ParsedSource, ParseDiagnostic> {
if let Some(plugin_host) = plugin_host {
) -> Result<ParsedSource> {
let result = if let Some(plugin_host) = plugin_host {
let code: &str = &parse_params.text.to_owned();
match parse_mode {
enums::ParseMode::Module => {
Expand All @@ -48,10 +48,11 @@ fn parse_by_mode(
enums::ParseMode::Script => parse_script(parse_params),
_ => parse_program(parse_params),
}
}
};
result.map_err(Error::msg)
}

pub fn parse<'local>(code: String, options: options::ParseOptions) -> Result<outputs::ParseOutput, String> {
pub fn parse<'local>(code: String, options: options::ParseOptions) -> Result<outputs::ParseOutput> {
let parse_params = ParseParams {
specifier: options.get_specifier(),
text: code.into(),
Expand All @@ -61,13 +62,11 @@ pub fn parse<'local>(code: String, options: options::ParseOptions) -> Result<out
scope_analysis: options.scope_analysis,
};
let mut plugin_host = options.plugin_host.clone();
match parse_by_mode(parse_params, options.parse_mode, &mut plugin_host) {
Ok(parsed_source) => Ok(outputs::ParseOutput::new(&options, &parsed_source)),
Err(e) => Err(e.to_string()),
}
let parsed_source = parse_by_mode(parse_params, options.parse_mode, &mut plugin_host)?;
Ok(outputs::ParseOutput::new(&options, &parsed_source))
}

pub fn transform<'local>(code: String, options: options::TransformOptions) -> Result<outputs::TransformOutput, String> {
pub fn transform<'local>(code: String, options: options::TransformOptions) -> Result<outputs::TransformOutput> {
let parse_params = ParseParams {
specifier: options.get_specifier(),
text: code.into(),
Expand All @@ -78,87 +77,68 @@ pub fn transform<'local>(code: String, options: options::TransformOptions) -> Re
};
let mut plugin_host = options.plugin_host.clone();
let code: String = parse_params.text.clone().to_string();
match parse_by_mode(parse_params, options.parse_mode, &mut plugin_host) {
Ok(parsed_source) => {
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
source_map.new_source_file(FileName::Url(options.get_specifier()), code);
let mut buffer = vec![];
let mut source_map_buffer = vec![];
let mut writer = Box::new(JsWriter::new(
source_map.clone(),
"\n",
&mut buffer,
Some(&mut source_map_buffer),
));
writer.set_indent_str(" "); // two spaces
let config = Config::default()
.with_minify(options.minify)
.with_ascii_only(options.ascii_only)
.with_omit_last_semi(options.omit_last_semi)
.with_target(options.target)
.with_emit_assert_for_import_attributes(options.emit_assert_for_import_attributes);
let swc_comments = parsed_source.comments().as_single_threaded();
let mut emitter = Emitter {
cfg: config,
comments: if options.keep_comments {
Some(&swc_comments)
} else {
None
},
cm: source_map.clone(),
wr: writer,
};
let result = match parsed_source.program_ref() {
Program::Module(module) => emitter.emit_module(module),
Program::Script(script) => emitter.emit_script(script),
};
match result {
Ok(_) => match String::from_utf8(buffer.to_vec()) {
Ok(mut code) => {
if options.omit_last_semi && code.ends_with(";") {
code.truncate(code.len() - 1);
}
let source_map: Option<String> = if options.source_map != SourceMapOption::None {
let mut buffer = Vec::new();
let source_map_config = SourceMapConfig {
inline_sources: options.inline_sources,
};
match source_map
.build_source_map_with_config(&source_map_buffer, None, source_map_config)
.to_writer(&mut buffer)
{
Ok(_) => {
if options.source_map == SourceMapOption::Inline {
if !code.ends_with("\n") {
code.push_str("\n");
}
code.push_str("//# sourceMappingURL=data:application/json;base64,");
base64::prelude::BASE64_STANDARD.encode_string(buffer, &mut code);
None
} else {
match String::from_utf8(buffer) {
Ok(source_map) => Some(source_map),
Err(_) => None,
}
}
}
Err(_) => None,
}
} else {
None
};
Ok(outputs::TransformOutput::new(&parsed_source, code, source_map))
}
Err(e) => Err(e.to_string()),
},
Err(e) => Err(e.to_string()),
let parsed_source = parse_by_mode(parse_params, options.parse_mode, &mut plugin_host)?;
let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
source_map.new_source_file(FileName::Url(options.get_specifier()), code);
let mut buffer = vec![];
let mut source_map_buffer = vec![];
let mut writer = Box::new(JsWriter::new(
source_map.clone(),
"\n",
&mut buffer,
Some(&mut source_map_buffer),
));
writer.set_indent_str(" "); // two spaces
let config = Config::default()
.with_minify(options.minify)
.with_ascii_only(options.ascii_only)
.with_omit_last_semi(options.omit_last_semi)
.with_target(options.target)
.with_emit_assert_for_import_attributes(options.emit_assert_for_import_attributes);
let swc_comments = parsed_source.comments().as_single_threaded();
let mut emitter = Emitter {
cfg: config,
comments: if options.keep_comments {
Some(&swc_comments)
} else {
None
},
cm: source_map.clone(),
wr: writer,
};
match parsed_source.program_ref() {
Program::Module(module) => emitter.emit_module(module)?,
Program::Script(script) => emitter.emit_script(script)?,
};
let mut code = String::from_utf8(buffer.to_vec()).map_err(Error::msg)?;
if options.omit_last_semi && code.ends_with(";") {
code.truncate(code.len() - 1);
}
let source_map: Option<String> = if options.source_map != SourceMapOption::None {
let mut buffer = Vec::new();
let source_map_config = SourceMapConfig {
inline_sources: options.inline_sources,
};
source_map
.build_source_map_with_config(&source_map_buffer, None, source_map_config)
.to_writer(&mut buffer)?;
if options.source_map == SourceMapOption::Inline {
if !code.ends_with("\n") {
code.push_str("\n");
}
code.push_str("//# sourceMappingURL=data:application/json;base64,");
base64::prelude::BASE64_STANDARD.encode_string(buffer, &mut code);
None
} else {
Some(String::from_utf8(buffer).map_err(Error::msg)?)
}
Err(e) => Err(e.to_string()),
}
} else {
None
};
Ok(outputs::TransformOutput::new(&parsed_source, code, source_map))
}

pub fn transpile<'local>(code: String, options: options::TranspileOptions) -> Result<outputs::TranspileOutput, String> {
pub fn transpile<'local>(code: String, options: options::TranspileOptions) -> Result<outputs::TranspileOutput> {
let parse_params = ParseParams {
specifier: options.get_specifier(),
text: code.into(),
Expand All @@ -168,41 +148,34 @@ pub fn transpile<'local>(code: String, options: options::TranspileOptions) -> Re
scope_analysis: options.scope_analysis,
};
let mut plugin_host = options.plugin_host.clone();
match parse_by_mode(parse_params, options.parse_mode, &mut plugin_host) {
Ok(parsed_source) => {
let transpile_options = TranspileOptions {
emit_metadata: options.emit_metadata,
imports_not_used_as_values: options.imports_not_used_as_values.to_owned(),
jsx_automatic: options.jsx_automatic,
jsx_development: options.jsx_development,
jsx_factory: options.jsx_factory.to_owned(),
jsx_fragment_factory: options.jsx_fragment_factory.to_owned(),
jsx_import_source: options.jsx_import_source.to_owned(),
precompile_jsx: options.precompile_jsx,
precompile_jsx_dynamic_props: options.precompile_jsx_dynamic_props.to_owned(),
precompile_jsx_skip_elements: options.precompile_jsx_skip_elements.to_owned(),
transform_jsx: options.transform_jsx,
var_decl_imports: options.var_decl_imports,
use_decorators_proposal: options.use_decorators_proposal,
use_ts_decorators: options.use_ts_decorators,
};
let emit_options = EmitOptions {
inline_sources: options.inline_sources,
remove_comments: !options.keep_comments,
source_map: options.source_map,
source_map_file: None,
};
match parsed_source.clone().transpile(&transpile_options, &emit_options) {
Ok(transpile_result) => Ok(outputs::TranspileOutput::new(
&options,
&parsed_source,
&transpile_result,
)),
Err(e) => Err(e.to_string()),
}
}
Err(e) => Err(e.to_string()),
}
let parsed_source = parse_by_mode(parse_params, options.parse_mode, &mut plugin_host)?;
let transpile_options = TranspileOptions {
emit_metadata: options.emit_metadata,
imports_not_used_as_values: options.imports_not_used_as_values.to_owned(),
jsx_automatic: options.jsx_automatic,
jsx_development: options.jsx_development,
jsx_factory: options.jsx_factory.to_owned(),
jsx_fragment_factory: options.jsx_fragment_factory.to_owned(),
jsx_import_source: options.jsx_import_source.to_owned(),
precompile_jsx: options.precompile_jsx,
precompile_jsx_dynamic_props: options.precompile_jsx_dynamic_props.to_owned(),
precompile_jsx_skip_elements: options.precompile_jsx_skip_elements.to_owned(),
transform_jsx: options.transform_jsx,
var_decl_imports: options.var_decl_imports,
use_decorators_proposal: options.use_decorators_proposal,
use_ts_decorators: options.use_ts_decorators,
};
let emit_options = EmitOptions {
inline_sources: options.inline_sources,
remove_comments: !options.keep_comments,
source_map: options.source_map,
source_map_file: None,
};
parsed_source
.clone()
.transpile(&transpile_options, &emit_options)
.map(|transpile_result| outputs::TranspileOutput::new(&options, &parsed_source, &transpile_result))
.map_err(Error::msg)
}

pub fn get_version<'local>() -> &'local str {
Expand Down
12 changes: 6 additions & 6 deletions rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ pub extern "system" fn Java_com_caoccao_javet_swc4j_Swc4jNative_coreParse<'local
let options = options::ParseOptions::from_java(&mut env, &options);
match core::parse(code, options) {
Ok(output) => output.to_java(&mut env).as_raw(),
Err(message) => {
error::throw_parse_error(&mut env, message.as_str());
Err(err) => {
error::throw_parse_error(&mut env, err.to_string().as_str());
null_mut()
}
}
Expand All @@ -94,8 +94,8 @@ pub extern "system" fn Java_com_caoccao_javet_swc4j_Swc4jNative_coreTransform<'l
let options = options::TransformOptions::from_java(&mut env, &options);
match core::transform(code, options) {
Ok(output) => output.to_java(&mut env).as_raw(),
Err(message) => {
error::throw_parse_error(&mut env, message.as_str());
Err(err) => {
error::throw_parse_error(&mut env, err.to_string().as_str());
null_mut()
}
}
Expand All @@ -113,8 +113,8 @@ pub extern "system" fn Java_com_caoccao_javet_swc4j_Swc4jNative_coreTranspile<'l
let options = options::TranspileOptions::from_java(&mut env, &options);
match core::transpile(code, options) {
Ok(output) => output.to_java(&mut env).as_raw(),
Err(message) => {
error::throw_transpile_error(&mut env, message.as_str());
Err(err) => {
error::throw_transpile_error(&mut env, err.to_string().as_str());
null_mut()
}
}
Expand Down
16 changes: 9 additions & 7 deletions rust/tests/test_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ fn test_parse_typescript_with_comments() {
#[test]
fn test_parse_wrong_media_type() {
let code = "function add(a:number, b:number) { return a+b; }";
let expected_error = String::from("Expected ',', got ':' at file:///main.js:1:15\n")
let expected_message = String::from("Expected ',', got ':' at file:///main.js:1:15\n")
+ "\n"
+ " function add(a:number, b:number) { return a+b; }\n"
+ " ~";
Expand All @@ -170,14 +170,15 @@ fn test_parse_wrong_media_type() {
};
let output = core::parse(code.to_owned(), options);
assert!(output.is_err());
let output_error = output.err().unwrap();
assert_eq!(expected_error, output_error);
let err = output.err().unwrap();
let output_message = err.to_string();
assert_eq!(expected_message, output_message);
}

#[test]
fn test_transform_with_default_options() {
let code = "function add(a:number, b:number) { return a+b; }";
let expected_code ="function add(a:number,b:number){return a+b;}\n";
let expected_code = "function add(a:number,b:number){return a+b;}\n";
let expected_source_map_prefix = "//# sourceMappingURL=data:application/json;base64,";
let options = options::TransformOptions {
media_type: MediaType::TypeScript,
Expand Down Expand Up @@ -295,7 +296,7 @@ fn test_transpile_type_script_without_inline_source_map() {
#[test]
fn test_transpile_wrong_media_type() {
let code = "function add(a:number, b:number) { return a+b; }";
let expected_error = String::from("Expected ',', got ':' at file:///main.js:1:15\n")
let expected_message = String::from("Expected ',', got ':' at file:///main.js:1:15\n")
+ "\n"
+ " function add(a:number, b:number) { return a+b; }\n"
+ " ~";
Expand All @@ -305,6 +306,7 @@ fn test_transpile_wrong_media_type() {
};
let output = core::transpile(code.to_owned(), options);
assert!(output.is_err());
let output_error = output.err().unwrap();
assert_eq!(expected_error, output_error);
let err = output.err().unwrap();
let output_message = err.to_string();
assert_eq!(expected_message, output_message);
}

0 comments on commit 6e025b2

Please sign in to comment.