From f1bc37829711e97de8935b5ba319e3e790f1ef00 Mon Sep 17 00:00:00 2001 From: roadup Date: Sun, 4 Feb 2024 09:26:13 +0800 Subject: [PATCH] print js error in console.log --- src/compile.rs | 66 +++++++++++++++---------------------- src/graph.rs | 5 ++- src/runner/console.rs | 17 +++++++--- src/runtime/asynchronous.rs | 33 +++++++++++++------ src/runtime/mod.rs | 7 ++-- src/runtime/static_fn.rs | 2 +- test/test.ts | 15 ++++----- test/test1.ts | 12 +++---- 8 files changed, 80 insertions(+), 77 deletions(-) diff --git a/src/compile.rs b/src/compile.rs index 6484ee2..c21afa9 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -1,4 +1,9 @@ -use std::{path::PathBuf, sync::Arc}; +use crate::{ + graph::resolve, + runtime::{ModuleInstance, Runtime}, +}; +use anyhow::anyhow; +use std::{io::Result, path::PathBuf, sync::Arc}; use swc::{ config::{Config, JscConfig, ModuleConfig, Options, SourceMapsConfig}, Compiler, @@ -12,11 +17,6 @@ use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax}; use swc_ecma_visit::{Visit, VisitWith}; use v8::Isolate; -use crate::{ - graph::resolve, - runtime::{ModuleInstance, Runtime}, -}; - struct ImportParser { sync_imports: Vec, async_imports: Vec, @@ -187,7 +187,7 @@ impl ModuleDependency { } } -pub fn compile(file_name: &str, source: &str) -> ModuleDependency { +pub fn compile(file_name: &str, source: &str) -> anyhow::Result { let cm = Arc::::default(); let handler = Arc::new(Handler::with_tty_emitter( ColorConfig::Auto, @@ -220,11 +220,26 @@ pub fn compile(file_name: &str, source: &str) -> ModuleDependency { let parsed = parser .parse_module() .map_err(|e| e.into_diagnostic(&handler).emit()) - .expect(&format!("parse {file_name} fail")); + .map_err(|e| anyhow!("parse {file_name} fail"))?; + // .expect(&format!("parse {file_name} fail")); let mut import_parser = ImportParser::new(); parsed.visit_with(&mut import_parser); + let config = Config { + jsc: JscConfig { + target: Some(EsVersion::Es2022), + syntax: Some(Syntax::Typescript(Default::default())), + ..Default::default() + }, + module: Some(ModuleConfig::Es6( + swc_ecma_transforms_module::EsModuleConfig { + resolve_fully: true, + }, + )), + source_maps: Some(SourceMapsConfig::Bool(false)), + ..Default::default() + }; let result = GLOBALS.set(&Default::default(), || { compiler.run(|| { compiler @@ -232,43 +247,16 @@ pub fn compile(file_name: &str, source: &str) -> ModuleDependency { fm, &handler, &Options { - config: Config { - jsc: JscConfig { - target: Some(EsVersion::Es2022), - syntax: Some(Syntax::Typescript(Default::default())), - ..Default::default() - }, - module: Some(ModuleConfig::Es6( - swc_ecma_transforms_module::EsModuleConfig { - resolve_fully: true, - }, - )), - source_maps: Some(SourceMapsConfig::Bool(false)), - ..Default::default() - }, + config, ..Default::default() }, ) + // .map_err(|e| anyhow!("compiler error")) .expect("compiler error") }) }); - // let filename = path.file_name().unwrap().to_str().unwrap(); - // let mut file = fs::OpenOptions::new() - // .write(true) - // .truncate(true) - // .create(true) - // .open(PathBuf::from(format!("output/{filename}.js"))) - // .unwrap(); - - // if let Some(map) = &result.map { - // fs::write( - // PathBuf::from(format!("output/{filename}.js.map")), - // map.as_bytes(), - // ) - // .unwrap(); - // } - ModuleDependency { + Ok(ModuleDependency { deps: import_parser.sync_imports, async_deps: import_parser.async_imports, specifier: vec![], @@ -276,5 +264,5 @@ pub fn compile(file_name: &str, source: &str) -> ModuleDependency { map: result.map, filename: file_name.to_string(), is_main: false, - } + }) } diff --git a/src/graph.rs b/src/graph.rs index 3c3be5f..2a1538f 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -37,7 +37,7 @@ pub async fn load(filename: &String) -> anyhow::Result { let now = Local::now().timestamp_millis(); let data = reqwest::get(filename).await?; let data = data.text().await?; - let data = compile(filename, &data); + let data = compile(filename, &data)?; println!( "{} {}", "Downland ".green(), @@ -50,8 +50,7 @@ pub async fn load(filename: &String) -> anyhow::Result { return Ok(data); }; let data = tokio::fs::read(&filename).await?; - let data = compile(filename, &String::from_utf8_lossy(&data).to_string()); - return Ok(data); + compile(filename, &String::from_utf8_lossy(&data).to_string()) } #[derive(Debug)] diff --git a/src/runner/console.rs b/src/runner/console.rs index c6989b1..8f1cf66 100644 --- a/src/runner/console.rs +++ b/src/runner/console.rs @@ -80,10 +80,20 @@ pub fn console_format( } if v.is_object() { let obj = v8::Local::::try_from(*v).unwrap(); + + if v.is_native_error() { + let stack = v8::String::new(scope, "stack").unwrap(); + let stack = obj + .get(scope, stack.into()) + .unwrap() + .to_rust_string_lossy(scope); + return format!("{stack}"); + } + let names = obj .get_own_property_names(scope, Default::default()) .unwrap(); - // let prototype = obj.get_prototype(scope).unwrap(); + let mut fmt = (0..names.length()) .map(|index| { let name = names.get_index(scope, index).unwrap(); @@ -128,8 +138,5 @@ pub fn console_log( .collect::>() .join(" "); - println!( - "{} {result}", - format!("{}", Utc::now().format("%Y-%m-%d %H:%M:%S%.3f")).color("gray") - ); + println!("{result}"); } diff --git a/src/runtime/asynchronous.rs b/src/runtime/asynchronous.rs index 5cedf15..54dcffa 100644 --- a/src/runtime/asynchronous.rs +++ b/src/runtime/asynchronous.rs @@ -1,25 +1,29 @@ +use anyhow::anyhow; use std::task::Poll; - use v8::Isolate; use super::Runtime; #[derive(Debug, PartialEq)] pub enum AsynchronousKind { - Operation(u32), Import((String, v8::Global)), + Operation(u32), } impl AsynchronousKind { pub fn exec(&self, isolate: &mut Isolate) -> Poll<()> { - match self { + match match self { AsynchronousKind::Operation(id) => Self::operation(isolate, id.clone()), AsynchronousKind::Import((specifier, resolver)) => { Self::import(isolate, specifier, resolver) } + } { + Ok(v) => v, + Err(e) => panic!("error {}", e), } } - fn operation(isolate: &mut Isolate, id: u32) -> Poll<()> { + + fn operation(isolate: &mut Isolate, id: u32) -> anyhow::Result> { let state_rc = Runtime::state(isolate); let context = { @@ -41,15 +45,23 @@ impl AsynchronousKind { false, ); let source = v8::String::new(scope, &format!("globalThis.exec({id});")).unwrap(); - let script = v8::Script::compile(scope, source, Some(&origin)).unwrap(); - script.run(scope).unwrap(); - return Poll::Ready(()); + let tc_scope = &mut v8::TryCatch::new(scope); + let script = v8::Script::compile(tc_scope, source, Some(&origin)) + .ok_or(anyhow!("compile script failure"))?; + script + .run(tc_scope) + .ok_or(anyhow!("run script failure {}", id))?; + + if tc_scope.has_caught() { + panic!("exec error"); + } + return Ok(Poll::Ready(())); } fn import( isolate: &mut Isolate, specifier: &String, resolver: &v8::Global, - ) -> Poll<()> { + ) -> anyhow::Result> { let state_rc = Runtime::state(isolate); let graph_rc = Runtime::graph(isolate); @@ -71,7 +83,8 @@ impl AsynchronousKind { let table = graph.table.borrow(); let dep = table .get(specifier) - .expect(&format!("specifier `{}` not found", specifier)); + .ok_or(anyhow!("specifier `{}` not found", specifier))?; + // .expect(&format!("specifier `{}` not found", specifier)); if dep.initialize(isolate).is_some() { dep.evaluate(isolate); @@ -90,6 +103,6 @@ impl AsynchronousKind { }; }; - return Poll::Ready(()); + return Ok(Poll::Ready(())); } } diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index 887be50..a60d57b 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -110,7 +110,7 @@ impl Runtime { state } - fn bootstrap(&mut self, entry: &String) { + fn bootstrap(&mut self, entry: &String) -> anyhow::Result<()> { let isolate = self.isolate.as_mut(); let state_rc = Self::state(isolate); let graph_rc = Self::graph(isolate); @@ -121,7 +121,7 @@ impl Runtime { let dependency = compile::compile( &bootstrap_js.to_string_lossy().to_string(), &include_str!("../../bootstrap/main.ts").to_string(), - ); + )?; dependency.initialize(isolate); dependency.evaluate(isolate); @@ -153,10 +153,11 @@ impl Runtime { let entry = v8::String::new(tc_scope, &entry).unwrap(); fun.call(tc_scope, this.into(), &[entry.into()]); + Ok(()) } pub async fn run(&mut self, entry: &String) -> anyhow::Result<()> { - self.bootstrap(entry); + self.bootstrap(entry)?; let isolate = self.isolate.as_mut(); let state_rc = Self::state(isolate); diff --git a/src/runtime/static_fn.rs b/src/runtime/static_fn.rs index 34f0d71..ead3b84 100644 --- a/src/runtime/static_fn.rs +++ b/src/runtime/static_fn.rs @@ -82,7 +82,7 @@ impl Runtime { pub fn timer_send( scope: &mut v8::HandleScope, info: v8::FunctionCallbackArguments, - mut rv: v8::ReturnValue, + rv: v8::ReturnValue, ) { let state_rc = Runtime::state(scope); let id = info diff --git a/test/test.ts b/test/test.ts index eeb377b..682f841 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,12 +1,9 @@ -import "https://deno.land/std@0.182.0/examples/welcome.ts"; -import "https://deno.land/std@0.182.0/examples/welcome.ts"; +// import "https://deno.land/std@0.182.0/examples/welcome.ts"; +// import "https://deno.land/std@0.182.0/examples/welcome.ts"; const res = await import("./test1.ts"); console.log("res", res); -try { - const text = await res.json(); - console.log("🚀 text", text); - test.copy(); -} catch (err) { - console.error("err => ", err); -} +const text = await res.json(); +console.log("🚀 text", text); +test.copy(); + diff --git a/test/test1.ts b/test/test1.ts index f7daaa7..99c0d57 100644 --- a/test/test1.ts +++ b/test/test1.ts @@ -2,20 +2,18 @@ setTimeout( (...arg: number[]) => { console.log("Hello Timeout", ...arg); }, - 1000, + 100, 1, 2, - 3, + 3 ); -console.log("Welcome Timeout!"); + setTimeout((...arg: number[]) => { - console.log("Timeout 2", ...arg, /^bin$/g); -}, 100); + console.log("Timeout 2", /^bin$/g); +}, 10); export default { copy() { console.log("1121"); }, }; - -export function* x() {}