mirror of
https://github.com/denoland/deno.git
synced 2025-07-24 05:35:33 +00:00
Fixes #10815
This commit is contained in:
parent
9ae8dbf173
commit
473713c621
8 changed files with 529 additions and 169 deletions
|
@ -178,33 +178,7 @@ pub fn map_content_type(
|
|||
if let Some(content_type) = maybe_content_type {
|
||||
let mut content_types = content_type.split(';');
|
||||
let content_type = content_types.next().unwrap();
|
||||
let media_type = match content_type.trim().to_lowercase().as_ref() {
|
||||
"application/typescript"
|
||||
| "text/typescript"
|
||||
| "video/vnd.dlna.mpeg-tts"
|
||||
| "video/mp2t"
|
||||
| "application/x-typescript" => {
|
||||
map_js_like_extension(specifier, MediaType::TypeScript)
|
||||
}
|
||||
"application/javascript"
|
||||
| "text/javascript"
|
||||
| "application/ecmascript"
|
||||
| "text/ecmascript"
|
||||
| "application/x-javascript"
|
||||
| "application/node" => {
|
||||
map_js_like_extension(specifier, MediaType::JavaScript)
|
||||
}
|
||||
"text/jsx" => MediaType::Jsx,
|
||||
"text/tsx" => MediaType::Tsx,
|
||||
"application/json" | "text/json" => MediaType::Json,
|
||||
"application/wasm" => MediaType::Wasm,
|
||||
// Handle plain and possibly webassembly
|
||||
"text/plain" | "application/octet-stream" => MediaType::from(specifier),
|
||||
_ => {
|
||||
debug!("unknown content type: {}", content_type);
|
||||
MediaType::Unknown
|
||||
}
|
||||
};
|
||||
let media_type = MediaType::from_content_type(specifier, content_type);
|
||||
let charset = content_types
|
||||
.map(str::trim)
|
||||
.find_map(|s| s.strip_prefix("charset="))
|
||||
|
@ -216,55 +190,6 @@ pub fn map_content_type(
|
|||
}
|
||||
}
|
||||
|
||||
/// Used to augment media types by using the path part of a module specifier to
|
||||
/// resolve to a more accurate media type.
|
||||
fn map_js_like_extension(
|
||||
specifier: &ModuleSpecifier,
|
||||
default: MediaType,
|
||||
) -> MediaType {
|
||||
let path = if specifier.scheme() == "file" {
|
||||
if let Ok(path) = specifier.to_file_path() {
|
||||
path
|
||||
} else {
|
||||
PathBuf::from(specifier.path())
|
||||
}
|
||||
} else {
|
||||
PathBuf::from(specifier.path())
|
||||
};
|
||||
match path.extension() {
|
||||
None => default,
|
||||
Some(os_str) => match os_str.to_str() {
|
||||
None => default,
|
||||
Some("jsx") => MediaType::Jsx,
|
||||
Some("tsx") => MediaType::Tsx,
|
||||
// Because DTS files do not have a separate media type, or a unique
|
||||
// extension, we have to "guess" at those things that we consider that
|
||||
// look like TypeScript, and end with `.d.ts` are DTS files.
|
||||
Some("ts") => {
|
||||
if default == MediaType::TypeScript {
|
||||
match path.file_stem() {
|
||||
None => default,
|
||||
Some(os_str) => {
|
||||
if let Some(file_stem) = os_str.to_str() {
|
||||
if file_stem.ends_with(".d") {
|
||||
MediaType::Dts
|
||||
} else {
|
||||
default
|
||||
}
|
||||
} else {
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
default
|
||||
}
|
||||
}
|
||||
Some(_) => default,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove shebangs from the start of source code strings
|
||||
fn strip_shebang(mut value: String) -> String {
|
||||
if value.starts_with("#!") {
|
||||
|
|
|
@ -559,6 +559,7 @@ mod tests {
|
|||
use crate::http_cache::HttpCache;
|
||||
use crate::lsp::analysis;
|
||||
use crate::lsp::documents::DocumentCache;
|
||||
use crate::lsp::documents::LanguageId;
|
||||
use crate::lsp::sources::Sources;
|
||||
use crate::media_type::MediaType;
|
||||
use deno_core::resolve_url;
|
||||
|
@ -567,15 +568,15 @@ mod tests {
|
|||
use tempfile::TempDir;
|
||||
|
||||
fn mock_state_snapshot(
|
||||
fixtures: &[(&str, &str, i32)],
|
||||
fixtures: &[(&str, &str, i32, LanguageId)],
|
||||
source_fixtures: &[(&str, &str)],
|
||||
location: &Path,
|
||||
) -> language_server::StateSnapshot {
|
||||
let mut documents = DocumentCache::default();
|
||||
for (specifier, source, version) in fixtures {
|
||||
for (specifier, source, version, language_id) in fixtures {
|
||||
let specifier =
|
||||
resolve_url(specifier).expect("failed to create specifier");
|
||||
documents.open(specifier.clone(), *version, source);
|
||||
documents.open(specifier.clone(), *version, language_id.clone(), source);
|
||||
let media_type = MediaType::from(&specifier);
|
||||
let parsed_module =
|
||||
analysis::parse_module(&specifier, source, &media_type).unwrap();
|
||||
|
@ -608,7 +609,7 @@ mod tests {
|
|||
}
|
||||
|
||||
fn setup(
|
||||
documents: &[(&str, &str, i32)],
|
||||
documents: &[(&str, &str, i32, LanguageId)],
|
||||
sources: &[(&str, &str)],
|
||||
) -> language_server::StateSnapshot {
|
||||
let temp_dir = TempDir::new().expect("could not create temp dir");
|
||||
|
@ -885,8 +886,13 @@ mod tests {
|
|||
};
|
||||
let state_snapshot = setup(
|
||||
&[
|
||||
("file:///a/b/c.ts", "import * as d from \"h\"", 1),
|
||||
("file:///a/c.ts", r#""#, 1),
|
||||
(
|
||||
"file:///a/b/c.ts",
|
||||
"import * as d from \"h\"",
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
),
|
||||
("file:///a/c.ts", r#""#, 1, LanguageId::TypeScript),
|
||||
],
|
||||
&[("https://deno.land/x/a/b/c.ts", "console.log(1);\n")],
|
||||
);
|
||||
|
|
|
@ -222,17 +222,6 @@ impl<'a> From<&'a diagnostics::Position> for lsp::Position {
|
|||
}
|
||||
}
|
||||
|
||||
/// Check if diagnostics can be generated for the provided media type.
|
||||
pub fn is_diagnosable(media_type: MediaType) -> bool {
|
||||
matches!(
|
||||
media_type,
|
||||
MediaType::TypeScript
|
||||
| MediaType::JavaScript
|
||||
| MediaType::Tsx
|
||||
| MediaType::Jsx
|
||||
)
|
||||
}
|
||||
|
||||
fn get_diagnostic_message(diagnostic: &diagnostics::Diagnostic) -> String {
|
||||
if let Some(message) = diagnostic.message_text.clone() {
|
||||
message
|
||||
|
@ -322,13 +311,16 @@ async fn generate_lint_diagnostics(
|
|||
let mut diagnostics_vec = Vec::new();
|
||||
if workspace_settings.lint {
|
||||
for specifier in documents.open_specifiers() {
|
||||
if !documents.is_diagnosable(specifier) {
|
||||
continue;
|
||||
}
|
||||
let version = documents.version(specifier);
|
||||
let current_version = collection
|
||||
.lock()
|
||||
.await
|
||||
.get_version(specifier, &DiagnosticSource::DenoLint);
|
||||
let media_type = MediaType::from(specifier);
|
||||
if version != current_version && is_diagnosable(media_type) {
|
||||
if version != current_version {
|
||||
if let Ok(Some(source_code)) = documents.content(specifier) {
|
||||
if let Ok(references) = analysis::get_lint_references(
|
||||
specifier,
|
||||
|
@ -366,12 +358,15 @@ async fn generate_ts_diagnostics(
|
|||
.open_specifiers()
|
||||
.iter()
|
||||
.filter_map(|&s| {
|
||||
let version = snapshot.documents.version(s);
|
||||
let current_version =
|
||||
collection.get_version(s, &DiagnosticSource::TypeScript);
|
||||
let media_type = MediaType::from(s);
|
||||
if version != current_version && is_diagnosable(media_type) {
|
||||
Some(s.clone())
|
||||
if snapshot.documents.is_diagnosable(s) {
|
||||
let version = snapshot.documents.version(s);
|
||||
let current_version =
|
||||
collection.get_version(s, &DiagnosticSource::TypeScript);
|
||||
if version != current_version {
|
||||
Some(s.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
use super::analysis;
|
||||
use super::text::LineIndex;
|
||||
|
||||
use crate::media_type::MediaType;
|
||||
|
||||
use deno_core::error::anyhow;
|
||||
use deno_core::error::custom_error;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::error::Context;
|
||||
|
@ -10,6 +13,37 @@ use deno_core::ModuleSpecifier;
|
|||
use lspower::lsp::TextDocumentContentChangeEvent;
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Range;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// A representation of the language id sent from the LSP client, which is used
|
||||
/// to determine how the document is handled within the language server.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum LanguageId {
|
||||
JavaScript,
|
||||
Jsx,
|
||||
TypeScript,
|
||||
Tsx,
|
||||
Json,
|
||||
JsonC,
|
||||
Markdown,
|
||||
}
|
||||
|
||||
impl FromStr for LanguageId {
|
||||
type Err = AnyError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, AnyError> {
|
||||
match s {
|
||||
"javascript" => Ok(Self::JavaScript),
|
||||
"javascriptreact" => Ok(Self::Jsx),
|
||||
"typescript" => Ok(Self::TypeScript),
|
||||
"typescriptreact" => Ok(Self::Tsx),
|
||||
"json" => Ok(Self::Json),
|
||||
"jsonc" => Ok(Self::JsonC),
|
||||
"markdown" => Ok(Self::Markdown),
|
||||
_ => Err(anyhow!("Unsupported language id: {}", s)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum IndexValid {
|
||||
|
@ -29,6 +63,7 @@ impl IndexValid {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct DocumentData {
|
||||
bytes: Option<Vec<u8>>,
|
||||
language_id: LanguageId,
|
||||
line_index: Option<LineIndex>,
|
||||
specifier: ModuleSpecifier,
|
||||
dependencies: Option<HashMap<String, analysis::Dependency>>,
|
||||
|
@ -36,9 +71,15 @@ pub struct DocumentData {
|
|||
}
|
||||
|
||||
impl DocumentData {
|
||||
pub fn new(specifier: ModuleSpecifier, version: i32, source: &str) -> Self {
|
||||
pub fn new(
|
||||
specifier: ModuleSpecifier,
|
||||
version: i32,
|
||||
language_id: LanguageId,
|
||||
source: &str,
|
||||
) -> Self {
|
||||
Self {
|
||||
bytes: Some(source.as_bytes().to_owned()),
|
||||
language_id,
|
||||
line_index: Some(LineIndex::new(source)),
|
||||
specifier,
|
||||
dependencies: None,
|
||||
|
@ -150,6 +191,39 @@ impl DocumentCache {
|
|||
doc.dependencies.clone()
|
||||
}
|
||||
|
||||
/// Determines if the specifier should be processed for diagnostics and other
|
||||
/// related language server features.
|
||||
pub fn is_diagnosable(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
if specifier.scheme() != "file" {
|
||||
// otherwise we look at the media type for the specifier.
|
||||
matches!(
|
||||
MediaType::from(specifier),
|
||||
MediaType::JavaScript
|
||||
| MediaType::Jsx
|
||||
| MediaType::TypeScript
|
||||
| MediaType::Tsx
|
||||
| MediaType::Dts
|
||||
)
|
||||
} else if let Some(doc_data) = self.docs.get(specifier) {
|
||||
// if the document is in the document cache, then use the client provided
|
||||
// language id to determine if the specifier is diagnosable.
|
||||
matches!(
|
||||
doc_data.language_id,
|
||||
LanguageId::JavaScript
|
||||
| LanguageId::Jsx
|
||||
| LanguageId::TypeScript
|
||||
| LanguageId::Tsx
|
||||
)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// Determines if the specifier can be processed for formatting.
|
||||
pub fn is_formattable(&self, specifier: &ModuleSpecifier) -> bool {
|
||||
self.docs.contains_key(specifier)
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.docs.len()
|
||||
}
|
||||
|
@ -159,10 +233,16 @@ impl DocumentCache {
|
|||
doc.line_index.clone()
|
||||
}
|
||||
|
||||
pub fn open(&mut self, specifier: ModuleSpecifier, version: i32, text: &str) {
|
||||
pub fn open(
|
||||
&mut self,
|
||||
specifier: ModuleSpecifier,
|
||||
version: i32,
|
||||
language_id: LanguageId,
|
||||
source: &str,
|
||||
) {
|
||||
self.docs.insert(
|
||||
specifier.clone(),
|
||||
DocumentData::new(specifier, version, text),
|
||||
DocumentData::new(specifier, version, language_id, source),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -219,7 +299,12 @@ mod tests {
|
|||
let mut document_cache = DocumentCache::default();
|
||||
let specifier = resolve_url("file:///a/b.ts").unwrap();
|
||||
let missing_specifier = resolve_url("file:///a/c.ts").unwrap();
|
||||
document_cache.open(specifier.clone(), 1, "console.log(\"Hello Deno\");\n");
|
||||
document_cache.open(
|
||||
specifier.clone(),
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
"console.log(\"Hello Deno\");\n",
|
||||
);
|
||||
assert!(document_cache.contains_key(&specifier));
|
||||
assert!(!document_cache.contains_key(&missing_specifier));
|
||||
}
|
||||
|
@ -228,7 +313,12 @@ mod tests {
|
|||
fn test_document_cache_change() {
|
||||
let mut document_cache = DocumentCache::default();
|
||||
let specifier = resolve_url("file:///a/b.ts").unwrap();
|
||||
document_cache.open(specifier.clone(), 1, "console.log(\"Hello deno\");\n");
|
||||
document_cache.open(
|
||||
specifier.clone(),
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
"console.log(\"Hello deno\");\n",
|
||||
);
|
||||
document_cache
|
||||
.change(
|
||||
&specifier,
|
||||
|
@ -259,7 +349,12 @@ mod tests {
|
|||
fn test_document_cache_change_utf16() {
|
||||
let mut document_cache = DocumentCache::default();
|
||||
let specifier = resolve_url("file:///a/b.ts").unwrap();
|
||||
document_cache.open(specifier.clone(), 1, "console.log(\"Hello 🦕\");\n");
|
||||
document_cache.open(
|
||||
specifier.clone(),
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
"console.log(\"Hello 🦕\");\n",
|
||||
);
|
||||
document_cache
|
||||
.change(
|
||||
&specifier,
|
||||
|
@ -285,4 +380,25 @@ mod tests {
|
|||
.expect("failed to get content");
|
||||
assert_eq!(actual, Some("console.log(\"Hello Deno\");\n".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_diagnosable() {
|
||||
let mut document_cache = DocumentCache::default();
|
||||
let specifier = resolve_url("file:///a/file.ts").unwrap();
|
||||
assert!(!document_cache.is_diagnosable(&specifier));
|
||||
document_cache.open(
|
||||
specifier.clone(),
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
"console.log(\"hello world\");\n",
|
||||
);
|
||||
assert!(document_cache.is_diagnosable(&specifier));
|
||||
let specifier =
|
||||
resolve_url("asset:///lib.es2015.symbol.wellknown.d.ts").unwrap();
|
||||
assert!(document_cache.is_diagnosable(&specifier));
|
||||
let specifier = resolve_url("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap();
|
||||
assert!(document_cache.is_diagnosable(&specifier));
|
||||
let specifier = resolve_url("data:application/json;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=").unwrap();
|
||||
assert!(!document_cache.is_diagnosable(&specifier));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ use super::config::SETTINGS_SECTION;
|
|||
use super::diagnostics;
|
||||
use super::diagnostics::DiagnosticSource;
|
||||
use super::documents::DocumentCache;
|
||||
use super::documents::LanguageId;
|
||||
use super::lsp_custom;
|
||||
use super::performance::Performance;
|
||||
use super::registries;
|
||||
|
@ -59,7 +60,6 @@ use crate::config_file::TsConfig;
|
|||
use crate::deno_dir;
|
||||
use crate::import_map::ImportMap;
|
||||
use crate::logger;
|
||||
use crate::lsp::diagnostics::is_diagnosable;
|
||||
use crate::media_type::MediaType;
|
||||
use crate::tools::fmt::format_file;
|
||||
use crate::tools::fmt::get_typescript_config;
|
||||
|
@ -611,17 +611,27 @@ impl Inner {
|
|||
// already managed by the language service
|
||||
return;
|
||||
}
|
||||
let language_id = match params.text_document.language_id.parse() {
|
||||
Ok(language_id) => language_id,
|
||||
Err(err) => {
|
||||
error!("{}", err);
|
||||
LanguageId::TypeScript
|
||||
}
|
||||
};
|
||||
self.documents.open(
|
||||
specifier.clone(),
|
||||
params.text_document.version,
|
||||
language_id,
|
||||
¶ms.text_document.text,
|
||||
);
|
||||
self.analyze_dependencies(&specifier, ¶ms.text_document.text);
|
||||
self.performance.measure(mark);
|
||||
|
||||
if let Err(err) = self.diagnostics_server.update() {
|
||||
error!("{}", err);
|
||||
if self.documents.is_diagnosable(&specifier) {
|
||||
self.analyze_dependencies(&specifier, ¶ms.text_document.text);
|
||||
if let Err(err) = self.diagnostics_server.update() {
|
||||
error!("{}", err);
|
||||
}
|
||||
}
|
||||
self.performance.measure(mark);
|
||||
}
|
||||
|
||||
async fn did_change(&mut self, params: DidChangeTextDocumentParams) {
|
||||
|
@ -632,15 +642,18 @@ impl Inner {
|
|||
params.text_document.version,
|
||||
params.content_changes,
|
||||
) {
|
||||
Ok(Some(source)) => self.analyze_dependencies(&specifier, &source),
|
||||
Ok(Some(source)) => {
|
||||
if self.documents.is_diagnosable(&specifier) {
|
||||
self.analyze_dependencies(&specifier, &source);
|
||||
if let Err(err) = self.diagnostics_server.update() {
|
||||
error!("{}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(_) => error!("No content returned from change."),
|
||||
Err(err) => error!("{}", err),
|
||||
}
|
||||
self.performance.measure(mark);
|
||||
|
||||
if let Err(err) = self.diagnostics_server.update() {
|
||||
error!("{}", err);
|
||||
}
|
||||
}
|
||||
|
||||
async fn did_close(&mut self, params: DidCloseTextDocumentParams) {
|
||||
|
@ -655,10 +668,12 @@ impl Inner {
|
|||
self.documents.close(&specifier);
|
||||
self.navigation_trees.remove(&specifier);
|
||||
|
||||
self.performance.measure(mark);
|
||||
if let Err(err) = self.diagnostics_server.update() {
|
||||
error!("{}", err);
|
||||
if self.documents.is_diagnosable(&specifier) {
|
||||
if let Err(err) = self.diagnostics_server.update() {
|
||||
error!("{}", err);
|
||||
}
|
||||
}
|
||||
self.performance.measure(mark);
|
||||
}
|
||||
|
||||
async fn did_change_configuration(
|
||||
|
@ -751,11 +766,9 @@ impl Inner {
|
|||
params: DocumentSymbolParams,
|
||||
) -> LspResult<Option<DocumentSymbolResponse>> {
|
||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
return Ok(None);
|
||||
}
|
||||
let media_type = MediaType::from(&specifier);
|
||||
if !is_diagnosable(media_type) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
|
@ -798,8 +811,11 @@ impl Inner {
|
|||
&self,
|
||||
params: DocumentFormattingParams,
|
||||
) -> LspResult<Option<Vec<TextEdit>>> {
|
||||
let mark = self.performance.mark("formatting", Some(¶ms));
|
||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||
if !self.documents.is_formattable(&specifier) {
|
||||
return Ok(None);
|
||||
}
|
||||
let mark = self.performance.mark("formatting", Some(¶ms));
|
||||
let file_text = self
|
||||
.documents
|
||||
.content(&specifier)
|
||||
|
@ -850,7 +866,9 @@ impl Inner {
|
|||
let specifier = self
|
||||
.url_map
|
||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
let mark = self.performance.mark("hover", Some(¶ms));
|
||||
|
@ -891,7 +909,9 @@ impl Inner {
|
|||
params: CodeActionParams,
|
||||
) -> LspResult<Option<CodeActionResponse>> {
|
||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
|
@ -1054,7 +1074,8 @@ impl Inner {
|
|||
params: CodeLensParams,
|
||||
) -> LspResult<Option<Vec<CodeLens>>> {
|
||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier)
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
|| !self.config.get_workspace_settings().enabled_code_lens()
|
||||
{
|
||||
return Ok(None);
|
||||
|
@ -1366,7 +1387,9 @@ impl Inner {
|
|||
let specifier = self
|
||||
.url_map
|
||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
|
@ -1416,9 +1439,12 @@ impl Inner {
|
|||
let specifier = self
|
||||
.url_map
|
||||
.normalize_url(¶ms.text_document_position.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mark = self.performance.mark("references", Some(¶ms));
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
|
@ -1471,9 +1497,12 @@ impl Inner {
|
|||
let specifier = self
|
||||
.url_map
|
||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mark = self.performance.mark("goto_definition", Some(¶ms));
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
|
@ -1514,9 +1543,12 @@ impl Inner {
|
|||
let specifier = self
|
||||
.url_map
|
||||
.normalize_url(¶ms.text_document_position.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mark = self.performance.mark("completion", Some(¶ms));
|
||||
// Import specifiers are something wholly internal to Deno, so for
|
||||
// completions, we will use internal logic and if there are completions
|
||||
|
@ -1632,9 +1664,12 @@ impl Inner {
|
|||
let specifier = self
|
||||
.url_map
|
||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mark = self.performance.mark("goto_implementation", Some(¶ms));
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
|
@ -1680,11 +1715,13 @@ impl Inner {
|
|||
params: FoldingRangeParams,
|
||||
) -> LspResult<Option<Vec<FoldingRange>>> {
|
||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
let mark = self.performance.mark("folding_range", Some(¶ms));
|
||||
|
||||
let mark = self.performance.mark("folding_range", Some(¶ms));
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
line_index
|
||||
|
@ -1737,11 +1774,13 @@ impl Inner {
|
|||
params: CallHierarchyIncomingCallsParams,
|
||||
) -> LspResult<Option<Vec<CallHierarchyIncomingCall>>> {
|
||||
let specifier = self.url_map.normalize_url(¶ms.item.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
let mark = self.performance.mark("incoming_calls", Some(¶ms));
|
||||
|
||||
let mark = self.performance.mark("incoming_calls", Some(¶ms));
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
line_index
|
||||
|
@ -1791,11 +1830,13 @@ impl Inner {
|
|||
params: CallHierarchyOutgoingCallsParams,
|
||||
) -> LspResult<Option<Vec<CallHierarchyOutgoingCall>>> {
|
||||
let specifier = self.url_map.normalize_url(¶ms.item.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
let mark = self.performance.mark("outgoing_calls", Some(¶ms));
|
||||
|
||||
let mark = self.performance.mark("outgoing_calls", Some(¶ms));
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
line_index
|
||||
|
@ -1848,13 +1889,15 @@ impl Inner {
|
|||
let specifier = self
|
||||
.url_map
|
||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mark = self
|
||||
.performance
|
||||
.mark("prepare_call_hierarchy", Some(¶ms));
|
||||
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
line_index
|
||||
|
@ -1927,11 +1970,13 @@ impl Inner {
|
|||
let specifier = self
|
||||
.url_map
|
||||
.normalize_url(¶ms.text_document_position.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
let mark = self.performance.mark("rename", Some(¶ms));
|
||||
|
||||
let mark = self.performance.mark("rename", Some(¶ms));
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
line_index
|
||||
|
@ -2019,11 +2064,13 @@ impl Inner {
|
|||
params: SelectionRangeParams,
|
||||
) -> LspResult<Option<Vec<SelectionRange>>> {
|
||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
let mark = self.performance.mark("selection_range", Some(¶ms));
|
||||
|
||||
let mark = self.performance.mark("selection_range", Some(¶ms));
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
line_index
|
||||
|
@ -2061,11 +2108,13 @@ impl Inner {
|
|||
params: SemanticTokensParams,
|
||||
) -> LspResult<Option<SemanticTokensResult>> {
|
||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
let mark = self.performance.mark("semantic_tokens_full", Some(¶ms));
|
||||
|
||||
let mark = self.performance.mark("semantic_tokens_full", Some(¶ms));
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
line_index
|
||||
|
@ -2108,13 +2157,15 @@ impl Inner {
|
|||
params: SemanticTokensRangeParams,
|
||||
) -> LspResult<Option<SemanticTokensRangeResult>> {
|
||||
let specifier = self.url_map.normalize_url(¶ms.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mark = self
|
||||
.performance
|
||||
.mark("semantic_tokens_range", Some(¶ms));
|
||||
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
line_index
|
||||
|
@ -2158,9 +2209,12 @@ impl Inner {
|
|||
let specifier = self
|
||||
.url_map
|
||||
.normalize_url(¶ms.text_document_position_params.text_document.uri);
|
||||
if !self.config.specifier_enabled(&specifier) {
|
||||
if !self.documents.is_diagnosable(&specifier)
|
||||
|| !self.config.specifier_enabled(&specifier)
|
||||
{
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mark = self.performance.mark("signature_help", Some(¶ms));
|
||||
let line_index =
|
||||
if let Some(line_index) = self.get_line_index_sync(&specifier) {
|
||||
|
@ -2427,8 +2481,12 @@ impl Inner {
|
|||
&mut self,
|
||||
params: lsp_custom::CacheParams,
|
||||
) -> LspResult<Option<Value>> {
|
||||
let mark = self.performance.mark("cache", Some(¶ms));
|
||||
let referrer = self.url_map.normalize_url(¶ms.referrer.uri);
|
||||
if !self.documents.is_diagnosable(&referrer) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let mark = self.performance.mark("cache", Some(¶ms));
|
||||
if !params.uris.is_empty() {
|
||||
for identifier in ¶ms.uris {
|
||||
let specifier = self.url_map.normalize_url(&identifier.uri);
|
||||
|
|
|
@ -2566,6 +2566,7 @@ mod tests {
|
|||
use crate::http_util::HeadersMap;
|
||||
use crate::lsp::analysis;
|
||||
use crate::lsp::documents::DocumentCache;
|
||||
use crate::lsp::documents::LanguageId;
|
||||
use crate::lsp::sources::Sources;
|
||||
use crate::lsp::text::LineIndex;
|
||||
use std::path::Path;
|
||||
|
@ -2573,14 +2574,14 @@ mod tests {
|
|||
use tempfile::TempDir;
|
||||
|
||||
fn mock_state_snapshot(
|
||||
fixtures: &[(&str, &str, i32)],
|
||||
fixtures: &[(&str, &str, i32, LanguageId)],
|
||||
location: &Path,
|
||||
) -> StateSnapshot {
|
||||
let mut documents = DocumentCache::default();
|
||||
for (specifier, source, version) in fixtures {
|
||||
for (specifier, source, version, language_id) in fixtures {
|
||||
let specifier =
|
||||
resolve_url(specifier).expect("failed to create specifier");
|
||||
documents.open(specifier.clone(), *version, source);
|
||||
documents.open(specifier.clone(), *version, language_id.clone(), source);
|
||||
let media_type = MediaType::from(&specifier);
|
||||
if let Ok(parsed_module) =
|
||||
analysis::parse_module(&specifier, source, &media_type)
|
||||
|
@ -2605,7 +2606,7 @@ mod tests {
|
|||
fn setup(
|
||||
debug: bool,
|
||||
config: Value,
|
||||
sources: &[(&str, &str, i32)],
|
||||
sources: &[(&str, &str, i32, LanguageId)],
|
||||
) -> (JsRuntime, StateSnapshot, PathBuf) {
|
||||
let temp_dir = TempDir::new().expect("could not create temp dir");
|
||||
let location = temp_dir.path().join("deps");
|
||||
|
@ -2688,7 +2689,12 @@ mod tests {
|
|||
"module": "esnext",
|
||||
"noEmit": true,
|
||||
}),
|
||||
&[("file:///a.ts", r#"console.log("hello deno");"#, 1)],
|
||||
&[(
|
||||
"file:///a.ts",
|
||||
r#"console.log("hello deno");"#,
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
)],
|
||||
);
|
||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
||||
let result = request(
|
||||
|
@ -2733,7 +2739,12 @@ mod tests {
|
|||
"lib": ["esnext", "dom", "deno.ns"],
|
||||
"noEmit": true,
|
||||
}),
|
||||
&[("file:///a.ts", r#"console.log(document.location);"#, 1)],
|
||||
&[(
|
||||
"file:///a.ts",
|
||||
r#"console.log(document.location);"#,
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
)],
|
||||
);
|
||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
||||
let result = request(
|
||||
|
@ -2766,6 +2777,7 @@ mod tests {
|
|||
console.log(b);
|
||||
"#,
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
)],
|
||||
);
|
||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
||||
|
@ -2795,6 +2807,7 @@ mod tests {
|
|||
import { A } from ".";
|
||||
"#,
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
)],
|
||||
);
|
||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
||||
|
@ -2848,6 +2861,7 @@ mod tests {
|
|||
console.log(b);
|
||||
"#,
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
)],
|
||||
);
|
||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
||||
|
@ -2884,6 +2898,7 @@ mod tests {
|
|||
import * as test from
|
||||
"#,
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
)],
|
||||
);
|
||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
||||
|
@ -2941,7 +2956,12 @@ mod tests {
|
|||
"lib": ["deno.ns", "deno.window"],
|
||||
"noEmit": true,
|
||||
}),
|
||||
&[("file:///a.ts", r#"const url = new URL("b.js", import."#, 1)],
|
||||
&[(
|
||||
"file:///a.ts",
|
||||
r#"const url = new URL("b.js", import."#,
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
)],
|
||||
);
|
||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
||||
let result = request(
|
||||
|
@ -2998,6 +3018,7 @@ mod tests {
|
|||
}
|
||||
"#,
|
||||
1,
|
||||
LanguageId::TypeScript,
|
||||
)],
|
||||
);
|
||||
let cache = HttpCache::new(&location);
|
||||
|
@ -3099,7 +3120,7 @@ mod tests {
|
|||
"lib": ["deno.ns", "deno.window"],
|
||||
"noEmit": true,
|
||||
}),
|
||||
&[("file:///a.ts", fixture, 1)],
|
||||
&[("file:///a.ts", fixture, 1, LanguageId::TypeScript)],
|
||||
);
|
||||
let specifier = resolve_url("file:///a.ts").expect("could not resolve url");
|
||||
let result = request(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use data_url::DataUrl;
|
||||
use deno_core::serde::Serialize;
|
||||
use deno_core::serde::Serializer;
|
||||
use deno_core::ModuleSpecifier;
|
||||
|
@ -45,34 +46,40 @@ impl fmt::Display for MediaType {
|
|||
|
||||
impl<'a> From<&'a Path> for MediaType {
|
||||
fn from(path: &'a Path) -> Self {
|
||||
MediaType::from_path(path)
|
||||
Self::from_path(path)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a PathBuf> for MediaType {
|
||||
fn from(path: &'a PathBuf) -> Self {
|
||||
MediaType::from_path(path)
|
||||
Self::from_path(path)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a String> for MediaType {
|
||||
fn from(specifier: &'a String) -> Self {
|
||||
MediaType::from_path(&PathBuf::from(specifier))
|
||||
Self::from_path(&PathBuf::from(specifier))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a ModuleSpecifier> for MediaType {
|
||||
fn from(specifier: &'a ModuleSpecifier) -> Self {
|
||||
let path = if specifier.scheme() == "file" {
|
||||
if let Ok(path) = specifier.to_file_path() {
|
||||
path
|
||||
if specifier.scheme() != "data" {
|
||||
let path = if specifier.scheme() == "file" {
|
||||
if let Ok(path) = specifier.to_file_path() {
|
||||
path
|
||||
} else {
|
||||
PathBuf::from(specifier.path())
|
||||
}
|
||||
} else {
|
||||
PathBuf::from(specifier.path())
|
||||
}
|
||||
};
|
||||
Self::from_path(&path)
|
||||
} else if let Ok(data_url) = DataUrl::process(specifier.as_str()) {
|
||||
Self::from_content_type(specifier, data_url.mime_type().to_string())
|
||||
} else {
|
||||
PathBuf::from(specifier.path())
|
||||
};
|
||||
MediaType::from_path(&path)
|
||||
Self::Unknown
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -83,6 +90,40 @@ impl Default for MediaType {
|
|||
}
|
||||
|
||||
impl MediaType {
|
||||
pub fn from_content_type<S: AsRef<str>>(
|
||||
specifier: &ModuleSpecifier,
|
||||
content_type: S,
|
||||
) -> Self {
|
||||
match content_type.as_ref().trim().to_lowercase().as_ref() {
|
||||
"application/typescript"
|
||||
| "text/typescript"
|
||||
| "video/vnd.dlna.mpeg-tts"
|
||||
| "video/mp2t"
|
||||
| "application/x-typescript" => {
|
||||
map_js_like_extension(specifier, Self::TypeScript)
|
||||
}
|
||||
"application/javascript"
|
||||
| "text/javascript"
|
||||
| "application/ecmascript"
|
||||
| "text/ecmascript"
|
||||
| "application/x-javascript"
|
||||
| "application/node" => {
|
||||
map_js_like_extension(specifier, Self::JavaScript)
|
||||
}
|
||||
"text/jsx" => Self::Jsx,
|
||||
"text/tsx" => Self::Tsx,
|
||||
"application/json" | "text/json" => Self::Json,
|
||||
"application/wasm" => Self::Wasm,
|
||||
// Handle plain and possibly webassembly
|
||||
"text/plain" | "application/octet-stream"
|
||||
if specifier.scheme() != "data" =>
|
||||
{
|
||||
Self::from(specifier)
|
||||
}
|
||||
_ => Self::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_path(path: &Path) -> Self {
|
||||
match path.extension() {
|
||||
None => match path.file_name() {
|
||||
|
@ -197,6 +238,55 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Used to augment media types by using the path part of a module specifier to
|
||||
/// resolve to a more accurate media type.
|
||||
fn map_js_like_extension(
|
||||
specifier: &ModuleSpecifier,
|
||||
default: MediaType,
|
||||
) -> MediaType {
|
||||
let path = if specifier.scheme() == "file" {
|
||||
if let Ok(path) = specifier.to_file_path() {
|
||||
path
|
||||
} else {
|
||||
PathBuf::from(specifier.path())
|
||||
}
|
||||
} else {
|
||||
PathBuf::from(specifier.path())
|
||||
};
|
||||
match path.extension() {
|
||||
None => default,
|
||||
Some(os_str) => match os_str.to_str() {
|
||||
None => default,
|
||||
Some("jsx") => MediaType::Jsx,
|
||||
Some("tsx") => MediaType::Tsx,
|
||||
// Because DTS files do not have a separate media type, or a unique
|
||||
// extension, we have to "guess" at those things that we consider that
|
||||
// look like TypeScript, and end with `.d.ts` are DTS files.
|
||||
Some("ts") => {
|
||||
if default == MediaType::TypeScript {
|
||||
match path.file_stem() {
|
||||
None => default,
|
||||
Some(os_str) => {
|
||||
if let Some(file_stem) = os_str.to_str() {
|
||||
if file_stem.ends_with(".d") {
|
||||
MediaType::Dts
|
||||
} else {
|
||||
default
|
||||
}
|
||||
} else {
|
||||
default
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
default
|
||||
}
|
||||
}
|
||||
Some(_) => default,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -245,6 +335,9 @@ mod tests {
|
|||
("https://deno.land/x/mod.ts", MediaType::TypeScript),
|
||||
("https://deno.land/x/mod.js", MediaType::JavaScript),
|
||||
("https://deno.land/x/mod.txt", MediaType::Unknown),
|
||||
("data:application/typescript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=", MediaType::TypeScript),
|
||||
("data:application/javascript;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=", MediaType::JavaScript),
|
||||
("data:text/plain;base64,ZXhwb3J0IGNvbnN0IGEgPSAiYSI7CgpleHBvcnQgZW51bSBBIHsKICBBLAogIEIsCiAgQywKfQo=", MediaType::Unknown),
|
||||
];
|
||||
|
||||
for (specifier, expected) in fixtures {
|
||||
|
@ -253,6 +346,52 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_content_type() {
|
||||
let fixtures = vec![
|
||||
(
|
||||
"https://deno.land/x/mod.ts",
|
||||
"application/typescript",
|
||||
MediaType::TypeScript,
|
||||
),
|
||||
(
|
||||
"https://deno.land/x/mod.d.ts",
|
||||
"application/typescript",
|
||||
MediaType::Dts,
|
||||
),
|
||||
("https://deno.land/x/mod.tsx", "text/tsx", MediaType::Tsx),
|
||||
(
|
||||
"https://deno.land/x/mod.js",
|
||||
"application/javascript",
|
||||
MediaType::JavaScript,
|
||||
),
|
||||
("https://deno.land/x/mod.jsx", "text/jsx", MediaType::Jsx),
|
||||
(
|
||||
"https://deno.land/x/mod.ts",
|
||||
"text/plain",
|
||||
MediaType::TypeScript,
|
||||
),
|
||||
(
|
||||
"https://deno.land/x/mod.js",
|
||||
"text/plain",
|
||||
MediaType::JavaScript,
|
||||
),
|
||||
(
|
||||
"https://deno.land/x/mod.wasm",
|
||||
"text/plain",
|
||||
MediaType::Wasm,
|
||||
),
|
||||
];
|
||||
|
||||
for (specifier, content_type, expected) in fixtures {
|
||||
let fixture = deno_core::resolve_url_or_path(specifier).unwrap();
|
||||
assert_eq!(
|
||||
MediaType::from_content_type(&fixture, content_type),
|
||||
expected
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_eq!(json!(MediaType::JavaScript), json!(0));
|
||||
|
|
|
@ -2118,6 +2118,56 @@ fn lsp_format_json() {
|
|||
shutdown(&mut client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_json_no_diagnostics() {
|
||||
let mut client = init("initialize_params.json");
|
||||
client
|
||||
.write_notification(
|
||||
"textDocument/didOpen",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///a/file.json",
|
||||
"languageId": "json",
|
||||
"version": 1,
|
||||
"text": "{\"key\":\"value\"}"
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (maybe_res, maybe_err) = client
|
||||
.write_request(
|
||||
"textDocument/semanticTokens/full",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///a/file.json"
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(maybe_err.is_none());
|
||||
assert_eq!(maybe_res, Some(json!(null)));
|
||||
|
||||
let (maybe_res, maybe_err) = client
|
||||
.write_request::<_, _, Value>(
|
||||
"textDocument/hover",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///a/file.json"
|
||||
},
|
||||
"position": {
|
||||
"line": 0,
|
||||
"character": 3
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(maybe_err.is_none());
|
||||
assert_eq!(maybe_res, Some(json!(null)));
|
||||
|
||||
shutdown(&mut client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_format_markdown() {
|
||||
let mut client = init("initialize_params.json");
|
||||
|
@ -2173,6 +2223,56 @@ fn lsp_format_markdown() {
|
|||
shutdown(&mut client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_markdown_no_diagnostics() {
|
||||
let mut client = init("initialize_params.json");
|
||||
client
|
||||
.write_notification(
|
||||
"textDocument/didOpen",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///a/file.md",
|
||||
"languageId": "markdown",
|
||||
"version": 1,
|
||||
"text": "# Hello World"
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (maybe_res, maybe_err) = client
|
||||
.write_request(
|
||||
"textDocument/semanticTokens/full",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///a/file.md"
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(maybe_err.is_none());
|
||||
assert_eq!(maybe_res, Some(json!(null)));
|
||||
|
||||
let (maybe_res, maybe_err) = client
|
||||
.write_request::<_, _, Value>(
|
||||
"textDocument/hover",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///a/file.md"
|
||||
},
|
||||
"position": {
|
||||
"line": 0,
|
||||
"character": 3
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
assert!(maybe_err.is_none());
|
||||
assert_eq!(maybe_res, Some(json!(null)));
|
||||
|
||||
shutdown(&mut client);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lsp_configuration_did_change() {
|
||||
let _g = http_server();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue