mirror of
https://github.com/denoland/deno.git
synced 2024-12-21 23:04:45 -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:
parent
0d73eb3dd9
commit
999cbfb52b
6 changed files with 101 additions and 1 deletions
10
cli/dts/lib.deno.ns.d.ts
vendored
10
cli/dts/lib.deno.ns.d.ts
vendored
|
@ -21,6 +21,16 @@ declare interface ImportMeta {
|
|||
* ```
|
||||
*/
|
||||
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)
|
||||
|
|
|
@ -952,7 +952,7 @@ itest!(if_main {
|
|||
});
|
||||
|
||||
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",
|
||||
});
|
||||
|
||||
|
|
11
cli/tests/testdata/import_meta.importmap.json
vendored
Normal file
11
cli/tests/testdata/import_meta.importmap.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
31
cli/tests/testdata/import_meta.ts
vendored
31
cli/tests/testdata/import_meta.ts
vendored
|
@ -1,3 +1,34 @@
|
|||
import { assertThrows } from "../../../test_util/std/testing/asserts.ts";
|
||||
|
||||
console.log("import_meta", import.meta.url, import.meta.main);
|
||||
|
||||
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);
|
||||
|
|
7
cli/tests/testdata/import_meta.ts.out
vendored
7
cli/tests/testdata/import_meta.ts.out
vendored
|
@ -1,2 +1,9 @@
|
|||
import_meta2 [WILDCARD]import_meta2.ts false
|
||||
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
|
||||
|
|
|
@ -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_val = v8::Boolean::new(scope, info.main);
|
||||
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) {
|
||||
|
|
Loading…
Reference in a new issue