Skip to content

Commit

Permalink
feat: Add import.meta.filename and import.meta.dirname (#441)
Browse files Browse the repository at this point in the history
This commit adds two new properties to "import.meta" object:
- "import.meta.filename"
- "import.meta.dirname"

These properties are defined only for "file:///..." URLs and are
not present for any other schemes.
  • Loading branch information
bartlomieju authored Jan 23, 2024
1 parent 920e001 commit 99e1130
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 0 deletions.
36 changes: 36 additions & 0 deletions core/modules/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1673,3 +1673,39 @@ if (typeof internals === "undefined") throw new Error("core missing");
futures::executor::block_on(runtime.run_event_loop(Default::default()))
.unwrap();
}

#[test]
fn import_meta_filename_dirname() {
#[cfg(not(target_os = "windows"))]
let main_specifier = resolve_url("file:///main_module.js").unwrap();
#[cfg(not(target_os = "windows"))]
let code = ascii_str!(
r#"if (import.meta.filename != '/main_module.js') throw Error();
if (import.meta.dirname != '/') throw Error();"#
);

#[cfg(target_os = "windows")]
let main_specifier = resolve_url("file:///C:/main_module.js").unwrap();
#[cfg(target_os = "windows")]
let code = ascii_str!(
r#"if (import.meta.filename != 'C:\\main_module.js') throw Error();
if (import.meta.dirname != 'C:\\') throw Error();"#
);

let loader = StaticModuleLoader::new([(main_specifier.clone(), code)]);

let mut runtime = JsRuntime::new(RuntimeOptions {
module_loader: Some(Rc::new(loader)),
..Default::default()
});

let main_id_fut = runtime
.load_main_module(&main_specifier, None)
.boxed_local();
let main_id = futures::executor::block_on(main_id_fut).unwrap();

#[allow(clippy::let_underscore_future)]
let _ = runtime.mod_evaluate(main_id);
futures::executor::block_on(runtime.run_event_loop(Default::default()))
.unwrap();
}
47 changes: 47 additions & 0 deletions core/runtime/bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use log::debug;
use std::option::Option;
use std::os::raw::c_void;
use std::path::PathBuf;
use url::Url;
use v8::MapFnTo;

use super::jsruntime::CONTEXT_SETUP_SOURCES;
Expand Down Expand Up @@ -455,6 +457,51 @@ pub extern "C" fn host_initialize_import_meta_object_callback(
v8::String::new_external_onebyte_static(scope, v8_static_strings::RESOLVE)
.unwrap();
meta.set(scope, resolve_key.into(), val.into());

maybe_add_import_meta_filename_dirname(scope, meta, &name);
}

fn maybe_add_import_meta_filename_dirname(
scope: &mut v8::HandleScope,
meta: v8::Local<v8::Object>,
name: &str,
) {
// For `file:` URL we provide additional `filename` and `dirname` values
let Ok(name_url) = Url::parse(name) else {
return;
};

if name_url.scheme() != "file" {
return;
}

// If something goes wrong acquiring a filepath, let skip instead of crashing
// (mostly concerned about file paths on Windows).
let Ok(file_path) = name_url.to_file_path() else {
return;
};

// Use display() here so that Rust takes care of proper forward/backward slash
// formatting depending on the OS.
let escaped_filename = file_path.display().to_string();
let Some(filename_val) = v8::String::new(scope, &escaped_filename) else {
return;
};
let filename_key =
v8::String::new_external_onebyte_static(scope, b"filename").unwrap();
meta.create_data_property(scope, filename_key.into(), filename_val.into());

let dir_path = file_path
.parent()
.map(|p| p.to_owned())
.unwrap_or_else(|| PathBuf::from("/"));
let escaped_dirname = dir_path.display().to_string();
let Some(dirname_val) = v8::String::new(scope, &escaped_dirname) else {
return;
};
let dirname_key =
v8::String::new_external_onebyte_static(scope, b"dirname").unwrap();
meta.create_data_property(scope, dirname_key.into(), dirname_val.into());
}

fn import_meta_resolve(
Expand Down

0 comments on commit 99e1130

Please sign in to comment.