fix(lsp): support data urls in deno.importMap option (#11397)

This commit is contained in:
Satya Rohith 2021-09-13 09:49:23 +05:30 committed by GitHub
parent a442821d97
commit 84f8747157
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 127 additions and 36 deletions

View file

@ -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
/// string.
pub fn get_source_from_bytes(
@ -340,15 +358,7 @@ impl FileFetcher {
));
}
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)))?;
let source = strip_shebang(get_source_from_bytes(bytes, charset)?);
let content_type = format!("{}", mime);
let (source, content_type) = get_source_from_data_url(specifier)?;
let (media_type, _) =
map_content_type(specifier, Some(content_type.clone()));

View file

@ -56,6 +56,7 @@ use super::urls;
use crate::config_file::ConfigFile;
use crate::config_file::TsConfig;
use crate::deno_dir;
use crate::file_fetcher::get_source_from_data_url;
use crate::fs_util;
use crate::logger;
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)
{
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 {
let root_path = root_uri
.to_file_path()
@ -488,21 +493,25 @@ impl Inner {
import_map_str
))
}?;
let import_map_path = import_map_url.to_file_path().map_err(|_| {
anyhow!("Cannot convert \"{}\" into a file path.", import_map_url)
})?;
info!(
" Resolved import map: \"{}\"",
import_map_path.to_string_lossy()
);
let import_map_json =
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(|_| {
anyhow!("Cannot convert \"{}\" into a file path.", import_map_url)
})?;
info!(
" Resolved import map: \"{}\"",
import_map_path.to_string_lossy()
);
fs::read_to_string(import_map_path).await.map_err(|err| {
anyhow!(
"Failed to load the import map at: {}. [{}]",
import_map_url,
err
)
})?;
})?
};
let import_map =
ImportMap::from_json(&import_map_url.to_string(), &import_map_json)?;
self.maybe_import_map_uri = Some(import_map_url);

View file

@ -1,16 +1,13 @@
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
use crate::colors;
use crate::file_fetcher::get_source_from_bytes;
use crate::file_fetcher::strip_shebang;
use crate::file_fetcher::get_source_from_data_url;
use crate::flags::Flags;
use crate::ops;
use crate::program_state::ProgramState;
use crate::version;
use data_url::DataUrl;
use deno_core::error::anyhow;
use deno_core::error::type_error;
use deno_core::error::uri_error;
use deno_core::error::AnyError;
use deno_core::error::Context;
use deno_core::futures::FutureExt;
@ -123,19 +120,6 @@ fn read_string_slice(
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";
struct EmbeddedModuleLoader(String);
@ -169,7 +153,7 @@ impl ModuleLoader for EmbeddedModuleLoader {
) -> Pin<Box<deno_core::ModuleSourceFuture>> {
let module_specifier = module_specifier.clone();
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()
} else {
self.0.to_string()

View file

@ -316,6 +316,32 @@ fn lsp_import_map() {
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]
fn lsp_hover() {
let mut client = init("initialize_params.json");

View 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
}
}
}