mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 23:34:47 -05:00
fix(lsp): support data urls in deno.importMap
option (#11397)
This commit is contained in:
parent
a442821d97
commit
84f8747157
5 changed files with 127 additions and 36 deletions
|
@ -143,6 +143,24 @@ fn fetch_local(specifier: &ModuleSpecifier) -> Result<File, AnyError> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the decoded body and content-type of a provided
|
||||||
|
/// data URL.
|
||||||
|
pub fn get_source_from_data_url(
|
||||||
|
specifier: &ModuleSpecifier,
|
||||||
|
) -> Result<(String, String), AnyError> {
|
||||||
|
let data_url = DataUrl::process(specifier.as_str())
|
||||||
|
.map_err(|e| uri_error(format!("{:?}", e)))?;
|
||||||
|
let mime = data_url.mime_type();
|
||||||
|
let charset = mime.get_parameter("charset").map(|v| v.to_string());
|
||||||
|
let (bytes, _) = data_url
|
||||||
|
.decode_to_vec()
|
||||||
|
.map_err(|e| uri_error(format!("{:?}", e)))?;
|
||||||
|
Ok((
|
||||||
|
strip_shebang(get_source_from_bytes(bytes, charset)?),
|
||||||
|
format!("{}", mime),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
/// Given a vector of bytes and optionally a charset, decode the bytes to a
|
/// Given a vector of bytes and optionally a charset, decode the bytes to a
|
||||||
/// string.
|
/// string.
|
||||||
pub fn get_source_from_bytes(
|
pub fn get_source_from_bytes(
|
||||||
|
@ -340,15 +358,7 @@ impl FileFetcher {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let data_url = DataUrl::process(specifier.as_str())
|
let (source, content_type) = get_source_from_data_url(specifier)?;
|
||||||
.map_err(|e| uri_error(format!("{:?}", e)))?;
|
|
||||||
let mime = data_url.mime_type();
|
|
||||||
let charset = mime.get_parameter("charset").map(|v| v.to_string());
|
|
||||||
let (bytes, _) = data_url
|
|
||||||
.decode_to_vec()
|
|
||||||
.map_err(|e| uri_error(format!("{:?}", e)))?;
|
|
||||||
let source = strip_shebang(get_source_from_bytes(bytes, charset)?);
|
|
||||||
let content_type = format!("{}", mime);
|
|
||||||
let (media_type, _) =
|
let (media_type, _) =
|
||||||
map_content_type(specifier, Some(content_type.clone()));
|
map_content_type(specifier, Some(content_type.clone()));
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ use super::urls;
|
||||||
use crate::config_file::ConfigFile;
|
use crate::config_file::ConfigFile;
|
||||||
use crate::config_file::TsConfig;
|
use crate::config_file::TsConfig;
|
||||||
use crate::deno_dir;
|
use crate::deno_dir;
|
||||||
|
use crate::file_fetcher::get_source_from_data_url;
|
||||||
use crate::fs_util;
|
use crate::fs_util;
|
||||||
use crate::logger;
|
use crate::logger;
|
||||||
use crate::tools::fmt::format_file;
|
use crate::tools::fmt::format_file;
|
||||||
|
@ -474,6 +475,10 @@ impl Inner {
|
||||||
let import_map_url = if let Ok(url) = Url::from_file_path(import_map_str)
|
let import_map_url = if let Ok(url) = Url::from_file_path(import_map_str)
|
||||||
{
|
{
|
||||||
Ok(url)
|
Ok(url)
|
||||||
|
} else if import_map_str.starts_with("data:") {
|
||||||
|
Url::parse(import_map_str).map_err(|_| {
|
||||||
|
anyhow!("Bad data url for import map: {:?}", import_map_str)
|
||||||
|
})
|
||||||
} else if let Some(root_uri) = &maybe_root_uri {
|
} else if let Some(root_uri) = &maybe_root_uri {
|
||||||
let root_path = root_uri
|
let root_path = root_uri
|
||||||
.to_file_path()
|
.to_file_path()
|
||||||
|
@ -488,6 +493,10 @@ impl Inner {
|
||||||
import_map_str
|
import_map_str
|
||||||
))
|
))
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
let import_map_json = if import_map_url.scheme() == "data" {
|
||||||
|
get_source_from_data_url(&import_map_url)?.0
|
||||||
|
} else {
|
||||||
let import_map_path = import_map_url.to_file_path().map_err(|_| {
|
let import_map_path = import_map_url.to_file_path().map_err(|_| {
|
||||||
anyhow!("Cannot convert \"{}\" into a file path.", import_map_url)
|
anyhow!("Cannot convert \"{}\" into a file path.", import_map_url)
|
||||||
})?;
|
})?;
|
||||||
|
@ -495,14 +504,14 @@ impl Inner {
|
||||||
" Resolved import map: \"{}\"",
|
" Resolved import map: \"{}\"",
|
||||||
import_map_path.to_string_lossy()
|
import_map_path.to_string_lossy()
|
||||||
);
|
);
|
||||||
let import_map_json =
|
|
||||||
fs::read_to_string(import_map_path).await.map_err(|err| {
|
fs::read_to_string(import_map_path).await.map_err(|err| {
|
||||||
anyhow!(
|
anyhow!(
|
||||||
"Failed to load the import map at: {}. [{}]",
|
"Failed to load the import map at: {}. [{}]",
|
||||||
import_map_url,
|
import_map_url,
|
||||||
err
|
err
|
||||||
)
|
)
|
||||||
})?;
|
})?
|
||||||
|
};
|
||||||
let import_map =
|
let import_map =
|
||||||
ImportMap::from_json(&import_map_url.to_string(), &import_map_json)?;
|
ImportMap::from_json(&import_map_url.to_string(), &import_map_json)?;
|
||||||
self.maybe_import_map_uri = Some(import_map_url);
|
self.maybe_import_map_uri = Some(import_map_url);
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
use crate::colors;
|
use crate::colors;
|
||||||
use crate::file_fetcher::get_source_from_bytes;
|
use crate::file_fetcher::get_source_from_data_url;
|
||||||
use crate::file_fetcher::strip_shebang;
|
|
||||||
use crate::flags::Flags;
|
use crate::flags::Flags;
|
||||||
use crate::ops;
|
use crate::ops;
|
||||||
use crate::program_state::ProgramState;
|
use crate::program_state::ProgramState;
|
||||||
use crate::version;
|
use crate::version;
|
||||||
use data_url::DataUrl;
|
|
||||||
use deno_core::error::anyhow;
|
use deno_core::error::anyhow;
|
||||||
use deno_core::error::type_error;
|
use deno_core::error::type_error;
|
||||||
use deno_core::error::uri_error;
|
|
||||||
use deno_core::error::AnyError;
|
use deno_core::error::AnyError;
|
||||||
use deno_core::error::Context;
|
use deno_core::error::Context;
|
||||||
use deno_core::futures::FutureExt;
|
use deno_core::futures::FutureExt;
|
||||||
|
@ -123,19 +120,6 @@ fn read_string_slice(
|
||||||
Ok(string)
|
Ok(string)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_source_from_data_url(
|
|
||||||
specifier: &ModuleSpecifier,
|
|
||||||
) -> Result<String, AnyError> {
|
|
||||||
let data_url = DataUrl::process(specifier.as_str())
|
|
||||||
.map_err(|e| uri_error(format!("{:?}", e)))?;
|
|
||||||
let mime = data_url.mime_type();
|
|
||||||
let charset = mime.get_parameter("charset").map(|v| v.to_string());
|
|
||||||
let (bytes, _) = data_url
|
|
||||||
.decode_to_vec()
|
|
||||||
.map_err(|e| uri_error(format!("{:?}", e)))?;
|
|
||||||
Ok(strip_shebang(get_source_from_bytes(bytes, charset)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
const SPECIFIER: &str = "file://$deno$/bundle.js";
|
const SPECIFIER: &str = "file://$deno$/bundle.js";
|
||||||
|
|
||||||
struct EmbeddedModuleLoader(String);
|
struct EmbeddedModuleLoader(String);
|
||||||
|
@ -169,7 +153,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
|
||||||
) -> Pin<Box<deno_core::ModuleSourceFuture>> {
|
) -> Pin<Box<deno_core::ModuleSourceFuture>> {
|
||||||
let module_specifier = module_specifier.clone();
|
let module_specifier = module_specifier.clone();
|
||||||
let is_data_uri = get_source_from_data_url(&module_specifier).ok();
|
let is_data_uri = get_source_from_data_url(&module_specifier).ok();
|
||||||
let code = if let Some(ref source) = is_data_uri {
|
let code = if let Some((ref source, _)) = is_data_uri {
|
||||||
source.to_string()
|
source.to_string()
|
||||||
} else {
|
} else {
|
||||||
self.0.to_string()
|
self.0.to_string()
|
||||||
|
|
|
@ -316,6 +316,32 @@ fn lsp_import_map() {
|
||||||
shutdown(&mut client);
|
shutdown(&mut client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lsp_import_map_data_url() {
|
||||||
|
let mut client = init("initialize_params_import_map.json");
|
||||||
|
let diagnostics = did_open(
|
||||||
|
&mut client,
|
||||||
|
json!({
|
||||||
|
"textDocument": {
|
||||||
|
"uri": "file:///a/file.ts",
|
||||||
|
"languageId": "typescript",
|
||||||
|
"version": 1,
|
||||||
|
"text": "import example from \"example\";\n"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut diagnostics = diagnostics.into_iter().flat_map(|x| x.diagnostics);
|
||||||
|
// This indicates that the import map from initialize_params_import_map.json
|
||||||
|
// is applied correctly.
|
||||||
|
assert!(diagnostics.any(|diagnostic| diagnostic.code
|
||||||
|
== Some(lsp::NumberOrString::String("no-cache".to_string()))
|
||||||
|
&& diagnostic
|
||||||
|
.message
|
||||||
|
.contains("https://deno.land/x/example/mod.ts")));
|
||||||
|
shutdown(&mut client);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn lsp_hover() {
|
fn lsp_hover() {
|
||||||
let mut client = init("initialize_params.json");
|
let mut client = init("initialize_params.json");
|
||||||
|
|
62
cli/tests/testdata/lsp/initialize_params_import_map.json
vendored
Normal file
62
cli/tests/testdata/lsp/initialize_params_import_map.json
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"processId": 0,
|
||||||
|
"clientInfo": {
|
||||||
|
"name": "test-harness",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"rootUri": null,
|
||||||
|
"initializationOptions": {
|
||||||
|
"enable": true,
|
||||||
|
"codeLens": {
|
||||||
|
"implementations": true,
|
||||||
|
"references": true
|
||||||
|
},
|
||||||
|
"importMap": "data:application/json;utf8,{\"imports\": { \"example\": \"https://deno.land/x/example/mod.ts\" }}",
|
||||||
|
"lint": true,
|
||||||
|
"suggest": {
|
||||||
|
"autoImports": true,
|
||||||
|
"completeFunctionCalls": false,
|
||||||
|
"names": true,
|
||||||
|
"paths": true,
|
||||||
|
"imports": {
|
||||||
|
"hosts": {
|
||||||
|
"http://localhost:4545/": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"unstable": false
|
||||||
|
},
|
||||||
|
"capabilities": {
|
||||||
|
"textDocument": {
|
||||||
|
"codeAction": {
|
||||||
|
"codeActionLiteralSupport": {
|
||||||
|
"codeActionKind": {
|
||||||
|
"valueSet": [
|
||||||
|
"quickfix"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"isPreferredSupport": true,
|
||||||
|
"dataSupport": true,
|
||||||
|
"resolveSupport": {
|
||||||
|
"properties": [
|
||||||
|
"edit"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"foldingRange": {
|
||||||
|
"lineFoldingOnly": true
|
||||||
|
},
|
||||||
|
"synchronization": {
|
||||||
|
"dynamicRegistration": true,
|
||||||
|
"willSave": true,
|
||||||
|
"willSaveWaitUntil": true,
|
||||||
|
"didSave": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"workspace": {
|
||||||
|
"configuration": true,
|
||||||
|
"workspaceFolders": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue