1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 15:24:46 -05:00

feat: import.meta.resolve() (#15074)

This commit adds new "import.meta.resolve()" API which
allows to resolve specifiers relative to the module the API
is called in. This API supports resolving using import maps.
This commit is contained in:
Bartek Iwańczuk 2022-07-18 20:05:26 +02:00 committed by GitHub
parent 0d73eb3dd9
commit 999cbfb52b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 101 additions and 1 deletions

View file

@ -21,6 +21,16 @@ declare interface ImportMeta {
* ``` * ```
*/ */
main: boolean; main: boolean;
/** A function that returns resolved specifier as if it would be imported
* using `import(specifier)`.
*
* ```ts
* console.log(import.meta.resolve("./foo.js"));
* // file:///dev/foo.js
* ```
*/
resolve(specifier: string): string;
} }
/** Deno supports user timing Level 3 (see: https://w3c.github.io/user-timing) /** Deno supports user timing Level 3 (see: https://w3c.github.io/user-timing)

View file

@ -952,7 +952,7 @@ itest!(if_main {
}); });
itest!(import_meta { itest!(import_meta {
args: "run --quiet --reload import_meta.ts", args: "run --quiet --reload --import-map=import_meta.importmap.json import_meta.ts",
output: "import_meta.ts.out", output: "import_meta.ts.out",
}); });

View file

@ -0,0 +1,11 @@
{
"imports": {
"bare": "https://example.com/",
"https://example.com/rewrite": "https://example.com/rewritten",
"1": "https://example.com/PASS-1",
"null": "https://example.com/PASS-null",
"undefined": "https://example.com/PASS-undefined",
"[object Object]": "https://example.com/PASS-object"
}
}

View file

@ -1,3 +1,34 @@
import { assertThrows } from "../../../test_util/std/testing/asserts.ts";
console.log("import_meta", import.meta.url, import.meta.main); console.log("import_meta", import.meta.url, import.meta.main);
import "./import_meta2.ts"; import "./import_meta2.ts";
console.log("Resolving ./foo.js", import.meta.resolve("./foo.js"));
console.log("Resolving bare from import map", import.meta.resolve("bare"));
console.log(
"Resolving https://example.com/rewrite from import map",
import.meta.resolve("https://example.com/rewrite"),
);
console.log(
"Resolving without a value from import map",
import.meta.resolve(),
);
console.log(
"Resolving 1 from import map",
import.meta.resolve(1),
);
console.log(
"Resolving null from import map",
import.meta.resolve(null),
);
console.log(
"Resolving object from import map",
import.meta.resolve({}),
);
assertThrows(() => {
import.meta.resolve("too", "many", "arguments");
}, TypeError);
assertThrows(() => {
import.meta.resolve("://malformed/url?asdf");
}, TypeError);

View file

@ -1,2 +1,9 @@
import_meta2 [WILDCARD]import_meta2.ts false import_meta2 [WILDCARD]import_meta2.ts false
import_meta [WILDCARD]import_meta.ts true import_meta [WILDCARD]import_meta.ts true
Resolving ./foo.js file:///[WILDCARD]/foo.js
Resolving bare from import map https://example.com/
Resolving https://example.com/rewrite from import map https://example.com/rewritten
Resolving without a value from import map https://example.com/PASS-undefined
Resolving 1 from import map https://example.com/PASS-1
Resolving null from import map https://example.com/PASS-null
Resolving object from import map https://example.com/PASS-object

View file

@ -271,6 +271,47 @@ pub extern "C" fn host_initialize_import_meta_object_callback(
let main_key = v8::String::new(scope, "main").unwrap(); let main_key = v8::String::new(scope, "main").unwrap();
let main_val = v8::Boolean::new(scope, info.main); let main_val = v8::Boolean::new(scope, info.main);
meta.create_data_property(scope, main_key.into(), main_val.into()); meta.create_data_property(scope, main_key.into(), main_val.into());
let builder =
v8::FunctionBuilder::new(import_meta_resolve).data(url_val.into());
let val = v8::FunctionBuilder::<v8::Function>::build(builder, scope).unwrap();
let resolve_key = v8::String::new(scope, "resolve").unwrap();
meta.set(scope, resolve_key.into(), val.into());
}
fn import_meta_resolve(
scope: &mut v8::HandleScope,
args: v8::FunctionCallbackArguments,
mut rv: v8::ReturnValue,
) {
if args.length() > 1 {
return throw_type_error(scope, "Invalid arguments");
}
let maybe_arg_str = args.get(0).to_string(scope);
if maybe_arg_str.is_none() {
return throw_type_error(scope, "Invalid arguments");
}
let specifier = maybe_arg_str.unwrap();
let referrer = {
let url_prop = args.data().unwrap();
url_prop.to_rust_string_lossy(scope)
};
let module_map_rc = JsRuntime::module_map(scope);
let loader = {
let module_map = module_map_rc.borrow();
module_map.loader.clone()
};
match loader.resolve(&specifier.to_rust_string_lossy(scope), &referrer, false)
{
Ok(resolved) => {
let resolved_val = serde_v8::to_v8(scope, resolved.as_str()).unwrap();
rv.set(resolved_val);
}
Err(err) => {
throw_type_error(scope, &err.to_string());
}
};
} }
pub extern "C" fn promise_reject_callback(message: v8::PromiseRejectMessage) { pub extern "C" fn promise_reject_callback(message: v8::PromiseRejectMessage) {