rqjs_cli/
start.rs

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}