1use std::{
2 io::{stdout, Write},
3 process,
4 str::FromStr,
5};
6#[derive(Parser, Debug, Clone)]
7#[command(version, about, long_about = None)]
8#[clap(name = "rqjs", version = env!("CARGO_PKG_VERSION"), bin_name = "rqjs")]
9pub struct Args {
10 #[clap()]
11 file: Option<String>,
12}
13
14use clap::Parser;
15use rquickjs::{
16 async_with,
17 loader::{BuiltinResolver, ModuleLoader},
18 AsyncContext, AsyncRuntime, Ctx, Function, Module, Object, Result, Value,
19};
20
21
22use rqjs_ext::modules;
23
24pub async fn start(args: Args) {
25 let Args { file } = args;
26 let resolver = (
27 BuiltinResolver::default().with_module("os"),
28 BuiltinResolver::default().with_module("path"),
29 BuiltinResolver::default().with_module("buffer"),
30 BuiltinResolver::default().with_module("util"),
31 BuiltinResolver::default().with_module("uuid"),
32 BuiltinResolver::default().with_module("xml"),
33 BuiltinResolver::default().with_module("fs"),
34 BuiltinResolver::default().with_module("fs/promises"),
35 );
36
37 let loader = (
38 ModuleLoader::default().with_module("os", modules::os::OsModule),
39 ModuleLoader::default().with_module("path", modules::path::PathModule),
40 ModuleLoader::default().with_module("buffer", modules::buffer::BufferModule),
41 ModuleLoader::default().with_module("util", modules::util::UtilModule),
42 ModuleLoader::default().with_module("uuid", modules::uuid::UuidModule),
43 ModuleLoader::default().with_module("xml", modules::xml::XmlModule),
44 ModuleLoader::default().with_module("fs", modules::fs::FsModule),
45 ModuleLoader::default().with_module("fs/promises", modules::fs::FsPromisesModule),
46 );
47
48 let init_global: Vec<fn(&Ctx<'_>) -> Result<()>> = vec![
49 modules::buffer::init,
50 modules::exceptions::init,
51 modules::encoding::init,
52 modules::console::init,
53 ];
54 let rt = AsyncRuntime::new().unwrap();
55 rt.set_loader(resolver, loader).await;
56 let ctx = AsyncContext::full(&rt).await.unwrap();
57
58 if let Some(path) = file {
59 let path = std::path::PathBuf::from_str(&path).unwrap();
60 let path = std::path::Path::new(&path);
61 let name = path.file_name().expect("filename error");
62 let code = std::fs::read_to_string(path).expect("read file error");
63 async_with!(ctx => |ctx| {
64 for i in init_global {
65 i(&ctx).unwrap();
66 }
67
68 Module::evaluate(ctx.clone(), name.to_string_lossy().to_string(), code)
69 .unwrap()
70 .finish::<()>()
71 .unwrap();
72 })
73 .await;
74 rt.idle().await;
75 } else {
76 ctrlc::set_handler(move || {
77 process::exit(0);
78 })
79 .expect("Error setting Ctrl-C handler");
80
81 loop {
82 stdout().write_all(b"> ").unwrap();
83 stdout().flush().unwrap();
84 let mut input = String::new();
85 std::io::stdin().read_line(&mut input).unwrap();
86
87 ctx.with(|ctx| {
88 let r = ctx.eval::<Value, _>(input.as_bytes()).unwrap();
89 let g = ctx.globals();
90 let console: Object = g.get("console").unwrap();
91 let log: Function = console.get("log").unwrap();
92 log.call::<(Value<'_>,), ()>((r,)).unwrap();
93 })
94 .await;
95 }
96 }
97}