1use std::ffi::OsStr;
8use std::fs::read_to_string;
9use std::io::ErrorKind;
10use std::path::Path;
11
12use ion::Context;
13use ion::format::{Config as FormatConfig, format_value};
14use ion::module::Module;
15use ion::script::Script;
16use modules::Modules;
17use mozjs::rust::{JSEngine, Runtime as RustRuntime};
18use runtime::cache::locate_in_cache;
19use runtime::cache::map::{save_sourcemap, transform_error_report_with_sourcemaps};
20use runtime::config::Config;
21use runtime::module::Loader;
22use runtime::{Runtime, RuntimeBuilder};
23use swc_sourcemap::SourceMap;
24
25pub(crate) async fn eval_inline(rt: &Runtime<'_>, source: &str) {
26 let result = Script::compile_and_evaluate(rt.cx(), Path::new("inline.js"), source);
27
28 match result {
29 Ok(v) => println!("{}", format_value(rt.cx(), FormatConfig::default().quoted(true), &v)),
30 Err(report) => eprintln!("{}", report.format(rt.cx())),
31 }
32 run_event_loop(rt).await;
33}
34
35pub(crate) async fn eval_script(path: &Path) {
36 let engine = JSEngine::init().unwrap();
37 let rt = RustRuntime::new(engine.handle());
38
39 let cx = &mut Context::from_runtime(&rt);
40 let rt = RuntimeBuilder::<(), _>::new()
41 .microtask_queue()
42 .macrotask_queue()
43 .standard_modules(Modules)
44 .build(cx);
45
46 if let Some((script, _)) = read_script(path) {
47 let (script, sourcemap) = cache(path, script);
48 if let Some(sourcemap) = sourcemap {
49 save_sourcemap(path, sourcemap);
50 }
51 let result = Script::compile_and_evaluate(rt.cx(), path, &script);
52
53 match result {
54 Ok(v) => println!("{}", format_value(rt.cx(), FormatConfig::default().quoted(true), &v)),
55 Err(mut report) => {
56 transform_error_report_with_sourcemaps(&mut report);
57 eprintln!("{}", report.format(rt.cx()));
58 }
59 }
60 run_event_loop(&rt).await;
61 }
62}
63
64pub(crate) async fn eval_module(path: &Path) {
65 let engine = JSEngine::init().unwrap();
66 let rt = RustRuntime::new(engine.handle());
67
68 let cx = &mut Context::from_runtime(&rt);
69 let rt = RuntimeBuilder::new()
70 .microtask_queue()
71 .macrotask_queue()
72 .modules(Loader::default())
73 .standard_modules(Modules)
74 .build(cx);
75
76 if let Some((script, filename)) = read_script(path) {
77 let (script, sourcemap) = cache(path, script);
78 if let Some(sourcemap) = sourcemap {
79 save_sourcemap(path, sourcemap);
80 }
81 let result = Module::compile_and_evaluate(rt.cx(), &filename, Some(path), &script);
82
83 if let Err(mut error) = result {
84 transform_error_report_with_sourcemaps(&mut error.report);
85 eprintln!("{}", error.format(rt.cx()));
86 }
87 run_event_loop(&rt).await;
88 }
89}
90
91fn read_script(path: &Path) -> Option<(String, String)> {
92 match read_to_string(path) {
93 Ok(script) => {
94 let filename = String::from(path.file_name().unwrap().to_str().unwrap());
95 Some((script, filename))
96 }
97 Err(error) => {
98 eprintln!("Failed to read file: {}", path.display());
99 match error.kind() {
100 ErrorKind::NotFound => eprintln!("(File was not found)"),
101 ErrorKind::PermissionDenied => eprintln!("Current User lacks permissions to read the file)"),
102 _ => eprintln!("{error:?}"),
103 }
104 None
105 }
106 }
107}
108
109async fn run_event_loop(rt: &Runtime<'_>) {
110 if let Err(err) = rt.run_event_loop().await {
111 if let Some(err) = err {
112 eprintln!("{}", err.format(rt.cx()));
113 } else {
114 eprintln!("Unknown error occurred while executing microtask.");
115 }
116 }
117}
118
119fn cache(path: &Path, script: String) -> (String, Option<SourceMap>) {
120 let is_typescript = Config::global().typescript && path.extension() == Some(OsStr::new("ts"));
121 is_typescript
122 .then(|| locate_in_cache(path, &script))
123 .flatten()
124 .map(|(s, sm)| (s, Some(sm)))
125 .unwrap_or_else(|| (script, None))
126}