use anyhow::{Result, anyhow};
use std::collections::{BTreeMap, HashMap};
use std::path::{Path, PathBuf};
use std::fs::File;
use rusty_v8 as v8;
use std::task::Context;
pub fn setup_nodejs_apis(scope: &mut v8::ContextScope<v8::HandleScope>) -> Result<()> {
setup_process(scope)?;
setup_path(scope)?;
setup_fs(scope)?;
setup_module_system(scope)?;
Ok(())
}
fn setup_process(scope: &mut v8::ContextScope<v8::HandleScope>) -> Result<()> {
let process: _ = v8::Object::new(scope);
let argv: _ = v8::Array::new_with_length(scope, 2);
let val_0: _ = v8::String::new(scope, "amber").unwrap().into();
argv.set_index(scope, 0, val_0);
let val_1: _ = v8::String::new(scope, "<eval>").unwrap().into();
argv.set_index(scope, 1, val_1);
let process_key: _ = v8::String::new(scope, "process").unwrap();
let global: _ = scope.global();
global.set(scope, process_key.clone(), process.clone().into())?;
process.set(scope, "argv", argv.into())?;
process.set(scope, "version", v8::String::new(scope, "1.0.0-amber").unwrap().into())?;
let cwd_func: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, _args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let result: _ = match env::current_dir() {
Ok(path) => path.to_string_lossy().to_string(),
Err(_) => ".".to_string(),
};
retval.set(v8::String::new(scope, &result).unwrap().into());
});
let cwd_func_instance: _ = cwd_func.get_function(scope).unwrap();
process.set(scope, "cwd", cwd_func_instance.into())?;
let next_tick_func: _ = v8::FunctionTemplate::new(scope, |_scope: &mut v8::PinScope, _args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
retval.set_undefined();
});
let next_tick_func_instance: _ = next_tick_func.get_function(scope).unwrap();
process.set(scope, "nextTick", next_tick_func_instance.into())?;
let env: _ = v8::Object::new(scope);
for (key, value) in env::vars() {
env.set(scope, v8::String::new(scope, &key).unwrap().into(), v8::String::new(scope, &value).unwrap().into())?;
}
process.set(scope, "env", env.into())?;
Ok(())
}
fn setup_path(scope: &mut v8::ContextScope<v8::HandleScope>) -> Result<()> {
let path: _ = v8::Object::new(scope);
let join_func: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let mut paths = Vec::new();
for i in 0..args.length() {
let arg: _ = args.get(i);
let arg_str: _ = arg.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
if !arg_str.is_empty() {
paths.push(arg_str);
}
}
let result: _ = paths.join("/");
retval.set(v8::String::new(scope, &result).unwrap().into());
});
let join_func_instance: _ = join_func.get_function(scope).unwrap();
path.set(scope, "join", join_func_instance.into())?;
let resolve_func: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let mut paths = Vec::new();
for i in 0..args.length() {
let arg: _ = args.get(i);
let arg_str: _ = arg.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
if !arg_str.is_empty() {
paths.push(arg_str);
}
}
let mut result = PathBuf::new();
for p in paths {
let path: _ = Path::new(&p);
if path.is_absolute() {
result = path.to_path_buf();
} else {
result = result.join(path);
}
}
if result.as_os_str().is_empty() {
result = env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
}
let result_str: _ = result.to_string_lossy().to_string();
retval.set(v8::String::new(scope, &result_str).unwrap().into());
});
let resolve_func_instance: _ = resolve_func.get_function(scope).unwrap();
path.set(scope, "resolve", resolve_func_instance.into())?;
let dirname_func: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let arg: _ = args.get(0);
let arg_str: _ = arg.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
let path: _ = Path::new(&arg_str);
let result: _ = if let Some(parent) = path.parent() {
parent.to_string_lossy().to_string()
} else {
".".to_string()
};
retval.set(v8::String::new(scope, &result).unwrap().into());
});
let dirname_func_instance: _ = dirname_func.get_function(scope).unwrap();
path.set(scope, "dirname", dirname_func_instance.into())?;
let basename_func: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let arg: _ = args.get(0);
let arg_str: _ = arg.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
let path: _ = Path::new(&arg_str);
let result: _ = path.file_name()
.and_then(|s| s.to_str())
.unwrap_or(&arg_str)
.to_string();
retval.set(v8::String::new(scope, &result).unwrap().into());
});
let basename_func_instance: _ = basename_func.get_function(scope).unwrap();
path.set(scope, "basename", basename_func_instance.into())?;
let extname_func: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let arg: _ = args.get(0);
let arg_str: _ = arg.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
let path: _ = Path::new(&arg_str);
let result: _ = path.extension()
.and_then(|s| {
let ext: _ = s.to_str()?;
Some(format!(".{}", ext))
})
.unwrap_or_else(|| "".to_string());
retval.set(v8::String::new(scope, &result).unwrap().into());
});
let extname_func_instance: _ = extname_func.get_function(scope).unwrap();
path.set(scope, "extname", extname_func_instance.into())?;
let global: _ = scope.global();
let global_key: _ = v8::String::new(scope, "path").unwrap();
let global_val: _ = path.into(;
global.set(scope, global_key.into(), global_val);)?;
Ok(())
}
fn setup_fs(scope: &mut v8::ContextScope<v8::HandleScope>) -> Result<()> {
let fs_obj: _ = v8::Object::new(scope);
let read_file_sync: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let path: _ = args.get(0);
let _encoding: _ = args.get(1); let path_str: _ = path.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
let content: _ = match fs::read_to_string(&path_str) {
Ok(content) => content,
Err(_) => "".to_string(),
};
retval.set(v8::String::new(scope, &content).unwrap().into());
});
let read_file_sync_instance: _ = read_file_sync.get_function(scope).unwrap();
fs_obj.set(scope, "readFileSync", read_file_sync_instance.into())?;
let write_file_sync: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let path: _ = args.get(0);
let data: _ = args.get(1);
let _encoding: _ = args.get(2); let path_str: _ = path.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
let data_str: _ = data.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
let _: _ = fs::write(&path_str, data_str);
retval.set_undefined();
});
let write_file_sync_instance: _ = write_file_sync.get_function(scope).unwrap();
fs_obj.set(scope, "writeFileSync", write_file_sync_instance.into())?;
let exists_sync: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let path: _ = args.get(0);
let path_str: _ = path.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
let result: _ = Path::new(&path_str).exists();
retval.set(v8::Boolean::new(scope, result).into());
});
let exists_sync_instance: _ = exists_sync.get_function(scope).unwrap();
fs_obj.set(scope, "existsSync", exists_sync_instance.into())?;
let mkdir_sync: _ = v8::FunctionTemplate::new(scope, |_scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let path: _ = args.get(0);
let path_str: _ = path.to_string(_scope)
.unwrap_or_else(|| v8::String::new(_scope, "<error>").unwrap())
.to_rust_string_lossy(_scope);
let _: _ = fs::create_dir_all(&path_str);
retval.set_undefined();
});
let mkdir_sync_instance: _ = mkdir_sync.get_function(_scope).unwrap();
fs_obj.set(scope, "mkdirSync", mkdir_sync_instance.into())?;
let readdir_sync: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let path: _ = args.get(0);
let path_str: _ = path.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
let mut result_vec = Vec::new();
if let Ok(entries) = fs::read_dir(&path_str) {
for entry in entries {
if let Ok(entry) = entry {
if let Some(name) = entry.file_name().to_str() {
result_vec.push(name.to_string());
}
}
}
}
let array: _ = v8::Array::new_with_length(scope, result_vec.len());
for (i, name) in result_vec.iter().enumerate() {
array.set_index(scope, i, v8::String::new(scope, name).unwrap().into());
}
retval.set(array.into());
});
let readdir_sync_instance: _ = readdir_sync.get_function(scope).unwrap();
fs_obj.set(scope, "readdirSync", readdir_sync_instance.into())?;
let stat_sync: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let path: _ = args.get(0);
let path_str: _ = path.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
let result: _ = Path::new(&path_str).is_file();
retval.set(v8::Boolean::new(scope, result).into());
});
let stat_sync_instance: _ = stat_sync.get_function(scope).unwrap();
fs_obj.set(scope, "statSync", stat_sync_instance.into())?;
let global: _ = scope.global();
let global_key: _ = v8::String::new(scope, "fs").unwrap();
let global_val: _ = fs_obj.into(;
global.set(scope, global_key.into(), global_val);)?;
Ok(())
}
fn setup_module_system(scope: &mut v8::ContextScope<v8::HandleScope>) -> Result<()> {
let require_func: _ = v8::FunctionTemplate::new(scope, |scope: &mut v8::PinScope, args: v8::FunctionCallbackArguments, mut retval: v8::ReturnValue| {
let module_name: _ = args.get(0);
let module_name_str: _ = module_name.to_string(scope)
.unwrap_or_else(|| v8::String::new(scope, "<error>").unwrap())
.to_rust_string_lossy(scope);
let result: _ = format!("[Module: {}]", module_name_str));
retval.set(v8::String::new(scope, &result).unwrap().into());
});
let require_func_instance: _ = require_func.get_function(scope).unwrap();
let global: _ = scope.global();
let global_key: _ = v8::String::new(scope, "require").unwrap();
let global_val: _ = require_func_instance.into(;
global.set(scope, global_key.into(), global_val);)?;
let module: _ = v8::Object::new(scope);
let exports: _ = v8::Object::new(scope);
module.set(scope, "exports", exports.into())?;
let global_key: _ = v8::String::new(scope, "module").unwrap();
let global_val: _ = module.into(;
global.set(scope, global_key.into(), global_val);)?;
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
fn test_setup_nodejs_apis() {
let platform: _ = v8::new_default_platform(0, false).unwrap().make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();
let mut isolate = v8::Isolate::new(v8::CreateParams::default()).unwrap();
let scope: _ = &mut v8::HandleScope::new(&mut isolate);
let context: _ = v8::Context::new(scope, Default::default());
let scope: _ = &mut v8::ContextScope::new(scope, context);
let result: _ = setup_nodejs_apis(scope);
assert!(result.is_ok());
let global: _ = scope.global();
let process_key: _ = v8::String::new(scope, "process").unwrap();
let process: _ = global.get(scope, process_key.into()).unwrap();
assert!(process.is_object());
let path_key: _ = v8::String::new(scope, "path").unwrap();
let path: _ = global.get(scope, path_key.into()).unwrap();
assert!(path.is_object());
let fs_key: _ = v8::String::new(scope, "fs").unwrap();
let fs: _ = global.get(scope, fs_key.into()).unwrap();
assert!(fs.is_object());
}
}