summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2021-10-28 10:11:38 +0200
committerGitHub <noreply@github.com>2021-10-28 10:11:38 +0200
commitf77c5701f774b5f0ba548fb1e0eb53dfd304f440 (patch)
treeeb243ccce5516a8e2ed90484b94cb81b0f67ad1a
parenta065604155991dbf4417b606d4562d275cd8955f (diff)
feat(compat): integrate import map and classic resolutions in ESM resolution (#12549)
This commit integrates import map and "classic" resolutions in the "--compat" mode when using ES modules; in effect "http:", "https:" and "blob:" imports now work in compat mode. The algorithm works as follows: 1. If there's an import map, try to resolve using it and if succeeded return the specifier 2. Try to resolve using "Node ESM resolution", and if succeeded return the specifier 3. Fall back to regular ESM resolution
-rw-r--r--cli/compat/esm_resolver.rs48
-rw-r--r--cli/compat/mod.rs6
-rw-r--r--cli/proc_state.rs4
-rw-r--r--cli/tests/integration/compat_tests.rs5
-rw-r--r--cli/tests/testdata/compat/import_map.json5
-rw-r--r--cli/tests/testdata/compat/import_map_https_imports.mjs7
-rw-r--r--cli/tests/testdata/compat/import_map_https_imports.out3
7 files changed, 70 insertions, 8 deletions
diff --git a/cli/compat/esm_resolver.rs b/cli/compat/esm_resolver.rs
index a4ea8cffc..f069428e5 100644
--- a/cli/compat/esm_resolver.rs
+++ b/cli/compat/esm_resolver.rs
@@ -1,6 +1,7 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use super::errors;
+use crate::resolver::ImportMapResolver;
use deno_core::error::generic_error;
use deno_core::error::AnyError;
use deno_core::serde_json;
@@ -13,21 +14,60 @@ use regex::Regex;
use std::path::PathBuf;
#[derive(Debug, Default)]
-pub struct NodeEsmResolver;
+pub(crate) struct NodeEsmResolver<'a> {
+ maybe_import_map_resolver: Option<ImportMapResolver<'a>>,
+}
+
+impl<'a> NodeEsmResolver<'a> {
+ pub fn new(maybe_import_map_resolver: Option<ImportMapResolver<'a>>) -> Self {
+ Self {
+ maybe_import_map_resolver,
+ }
+ }
-impl NodeEsmResolver {
pub fn as_resolver(&self) -> &dyn Resolver {
self
}
}
-impl Resolver for NodeEsmResolver {
+impl Resolver for NodeEsmResolver<'_> {
fn resolve(
&self,
specifier: &str,
referrer: &ModuleSpecifier,
) -> Result<ModuleSpecifier, AnyError> {
- node_resolve(specifier, referrer.as_str(), &std::env::current_dir()?)
+ // First try to resolve using import map, ignoring any errors
+ if !specifier.starts_with("node:") {
+ if let Some(import_map_resolver) = &self.maybe_import_map_resolver {
+ if let Ok(specifier) = import_map_resolver.resolve(specifier, referrer)
+ {
+ return Ok(specifier);
+ }
+ }
+ }
+
+ let node_resolution =
+ node_resolve(specifier, referrer.as_str(), &std::env::current_dir()?);
+
+ match node_resolution {
+ Ok(specifier) => {
+ // If node resolution succeeded, return the specifier
+ Ok(specifier)
+ }
+ Err(err) => {
+ // If node resolution failed, check if it's because of unsupported
+ // URL scheme, and if so try to resolve using regular resolution algorithm
+ if err
+ .to_string()
+ .starts_with("[ERR_UNSUPPORTED_ESM_URL_SCHEME]")
+ {
+ return deno_core::resolve_import(specifier, referrer.as_str())
+ .map_err(|err| err.into());
+ }
+
+ Err(err)
+ }
+ }
}
}
diff --git a/cli/compat/mod.rs b/cli/compat/mod.rs
index bcc9473eb..997265f96 100644
--- a/cli/compat/mod.rs
+++ b/cli/compat/mod.rs
@@ -8,7 +8,7 @@ use deno_core::located_script_name;
use deno_core::url::Url;
use deno_core::JsRuntime;
-pub use esm_resolver::NodeEsmResolver;
+pub(crate) use esm_resolver::NodeEsmResolver;
// TODO(bartlomieju): this needs to be bumped manually for
// each release, a better mechanism is preferable, but it's a quick and dirty
@@ -86,7 +86,7 @@ fn try_resolve_builtin_module(specifier: &str) -> Option<Url> {
}
}
-pub async fn check_if_should_use_esm_loader(
+pub(crate) async fn check_if_should_use_esm_loader(
js_runtime: &mut JsRuntime,
main_module: &str,
) -> Result<bool, AnyError> {
@@ -113,7 +113,7 @@ pub async fn check_if_should_use_esm_loader(
Ok(use_esm_loader)
}
-pub fn load_cjs_module(
+pub(crate) fn load_cjs_module(
js_runtime: &mut JsRuntime,
main_module: &str,
) -> Result<(), AnyError> {
diff --git a/cli/proc_state.rs b/cli/proc_state.rs
index ecfc94233..0c81ab2e8 100644
--- a/cli/proc_state.rs
+++ b/cli/proc_state.rs
@@ -298,7 +298,9 @@ impl ProcState {
);
let maybe_locker = as_maybe_locker(self.lockfile.clone());
let maybe_imports = self.get_maybe_imports();
- let node_resolver = NodeEsmResolver;
+ let node_resolver = NodeEsmResolver::new(
+ self.maybe_import_map.as_ref().map(ImportMapResolver::new),
+ );
let import_map_resolver =
self.maybe_import_map.as_ref().map(ImportMapResolver::new);
let maybe_resolver = if self.flags.compat {
diff --git a/cli/tests/integration/compat_tests.rs b/cli/tests/integration/compat_tests.rs
index 2886056ec..81d2985b3 100644
--- a/cli/tests/integration/compat_tests.rs
+++ b/cli/tests/integration/compat_tests.rs
@@ -18,6 +18,11 @@ itest!(node_prefix_fs_promises {
output: "compat/fs_promises.out",
});
+itest!(compat_with_import_map_and_https_imports {
+ args: "run --quiet --compat --unstable -A --import-map=compat/import_map.json compat/import_map_https_imports.mjs",
+ output: "compat/import_map_https_imports.out",
+});
+
#[test]
fn globals_in_repl() {
let (out, _err) = util::run_and_collect_output_with_args(
diff --git a/cli/tests/testdata/compat/import_map.json b/cli/tests/testdata/compat/import_map.json
new file mode 100644
index 000000000..2c7b8a6d0
--- /dev/null
+++ b/cli/tests/testdata/compat/import_map.json
@@ -0,0 +1,5 @@
+{
+ "imports": {
+ "std/": "https://deno.land/std@0.113.0/"
+ }
+}
diff --git a/cli/tests/testdata/compat/import_map_https_imports.mjs b/cli/tests/testdata/compat/import_map_https_imports.mjs
new file mode 100644
index 000000000..f4f27fdb9
--- /dev/null
+++ b/cli/tests/testdata/compat/import_map_https_imports.mjs
@@ -0,0 +1,7 @@
+import { sortBy } from "std/collections/sort_by.ts";
+import { findSingle } from "https://deno.land/std@0.113.0/collections/find_single.ts";
+import os from "node:os";
+
+console.log(sortBy([2, 3, 1], (it) => it));
+console.log(findSingle([2, 3, 1], (it) => it == 2));
+console.log("arch", os.arch());
diff --git a/cli/tests/testdata/compat/import_map_https_imports.out b/cli/tests/testdata/compat/import_map_https_imports.out
new file mode 100644
index 000000000..7ee30676e
--- /dev/null
+++ b/cli/tests/testdata/compat/import_map_https_imports.out
@@ -0,0 +1,3 @@
+[ 1, 2, 3 ]
+2
+arch [WILDCARD]