2024-01-01 14:58:21 -05:00
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
2020-12-07 05:46:39 -05:00
2022-03-20 21:33:37 -04:00
use super ::logging ::lsp_log ;
2023-07-10 17:45:09 -04:00
use crate ::args ::ConfigFile ;
use crate ::lsp ::logging ::lsp_warn ;
use crate ::util ::fs ::canonicalize_path_maybe_not_exists ;
2022-11-28 17:28:54 -05:00
use crate ::util ::path ::specifier_to_file_path ;
2023-09-21 01:46:39 -04:00
use deno_ast ::MediaType ;
2024-01-15 19:15:39 -05:00
use deno_config ::glob ::PathOrPattern ;
use deno_config ::glob ::PathOrPatternSet ;
2023-10-16 21:51:42 -04:00
use deno_config ::FmtOptionsConfig ;
2023-07-10 17:45:09 -04:00
use deno_core ::parking_lot ::Mutex ;
2023-09-21 01:46:39 -04:00
use deno_core ::serde ::de ::DeserializeOwned ;
2020-12-07 05:46:39 -05:00
use deno_core ::serde ::Deserialize ;
2021-07-20 21:50:43 -04:00
use deno_core ::serde ::Serialize ;
2020-12-07 05:46:39 -05:00
use deno_core ::serde_json ;
use deno_core ::serde_json ::Value ;
2021-05-09 21:16:04 -04:00
use deno_core ::ModuleSpecifier ;
2023-07-10 17:45:09 -04:00
use deno_lockfile ::Lockfile ;
2023-03-15 10:34:23 -04:00
use lsp ::Url ;
2021-05-20 05:56:48 -04:00
use std ::collections ::BTreeMap ;
2021-04-08 21:27:27 -04:00
use std ::collections ::HashMap ;
2023-07-10 17:45:09 -04:00
use std ::path ::PathBuf ;
2021-05-20 05:56:48 -04:00
use std ::sync ::Arc ;
2022-04-03 00:17:30 -04:00
use tower_lsp ::lsp_types as lsp ;
2021-12-15 13:23:43 -05:00
2021-05-09 21:16:04 -04:00
pub const SETTINGS_SECTION : & str = " deno " ;
2020-12-07 05:46:39 -05:00
#[ derive(Debug, Clone, Default) ]
pub struct ClientCapabilities {
2021-08-09 19:56:34 -04:00
pub code_action_disabled_support : bool ,
pub line_folding_only : bool ,
2022-10-14 08:04:38 -04:00
pub snippet_support : bool ,
2020-12-07 05:46:39 -05:00
pub status_notification : bool ,
2022-03-29 18:59:27 -04:00
/// The client provides the `experimental.testingApi` capability, which is
/// built around VSCode's testing API. It indicates that the server should
/// send notifications about tests discovered in modules.
pub testing_api : bool ,
2021-01-04 16:52:20 -05:00
pub workspace_configuration : bool ,
pub workspace_did_change_watched_files : bool ,
2023-08-25 20:50:47 -04:00
pub workspace_will_rename_files : bool ,
2020-12-07 05:46:39 -05:00
}
2021-06-07 07:38:07 -04:00
fn is_true ( ) -> bool {
true
}
2021-07-20 21:50:43 -04:00
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
2021-01-31 22:30:41 -05:00
#[ serde(rename_all = " camelCase " ) ]
pub struct CodeLensSettings {
2021-02-08 05:45:10 -05:00
/// Flag for providing implementation code lenses.
#[ serde(default) ]
pub implementations : bool ,
/// Flag for providing reference code lenses.
2021-01-31 22:30:41 -05:00
#[ serde(default) ]
pub references : bool ,
/// Flag for providing reference code lens on all functions. For this to have
/// an impact, the `references` flag needs to be `true`.
#[ serde(default) ]
pub references_all_functions : bool ,
2021-06-07 07:38:07 -04:00
/// Flag for providing test code lens on `Deno.test` statements. There is
/// also the `test_args` setting, but this is not used by the server.
#[ serde(default = " is_true " ) ]
pub test : bool ,
2021-01-31 22:30:41 -05:00
}
2021-03-15 18:01:41 -04:00
impl Default for CodeLensSettings {
fn default ( ) -> Self {
Self {
implementations : false ,
references : false ,
references_all_functions : false ,
2021-06-07 07:38:07 -04:00
test : true ,
2021-03-15 18:01:41 -04:00
}
}
}
2023-09-21 01:46:39 -04:00
#[ derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct DenoCompletionSettings {
#[ serde(default) ]
pub imports : ImportCompletionSettings ,
}
2023-09-25 22:54:07 -04:00
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct ClassMemberSnippets {
#[ serde(default = " is_true " ) ]
pub enabled : bool ,
}
impl Default for ClassMemberSnippets {
fn default ( ) -> Self {
Self { enabled : true }
}
}
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct ObjectLiteralMethodSnippets {
#[ serde(default = " is_true " ) ]
pub enabled : bool ,
}
impl Default for ObjectLiteralMethodSnippets {
fn default ( ) -> Self {
Self { enabled : true }
}
}
2021-07-20 21:50:43 -04:00
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
2021-03-15 18:01:41 -04:00
#[ serde(rename_all = " camelCase " ) ]
pub struct CompletionSettings {
#[ serde(default) ]
pub complete_function_calls : bool ,
2021-06-01 07:53:08 -04:00
#[ serde(default = " is_true " ) ]
2023-09-25 22:54:07 -04:00
pub include_automatic_optional_chain_completions : bool ,
#[ serde(default = " is_true " ) ]
pub include_completions_for_import_statements : bool ,
#[ serde(default = " is_true " ) ]
2021-03-15 18:01:41 -04:00
pub names : bool ,
2021-06-01 07:53:08 -04:00
#[ serde(default = " is_true " ) ]
2021-03-15 18:01:41 -04:00
pub paths : bool ,
2021-06-01 07:53:08 -04:00
#[ serde(default = " is_true " ) ]
2021-03-15 18:01:41 -04:00
pub auto_imports : bool ,
2023-09-25 22:54:07 -04:00
#[ serde(default = " is_true " ) ]
pub enabled : bool ,
#[ serde(default) ]
pub class_member_snippets : ClassMemberSnippets ,
#[ serde(default) ]
pub object_literal_method_snippets : ObjectLiteralMethodSnippets ,
2021-03-15 18:01:41 -04:00
}
impl Default for CompletionSettings {
fn default ( ) -> Self {
Self {
complete_function_calls : false ,
2023-09-25 22:54:07 -04:00
include_automatic_optional_chain_completions : true ,
include_completions_for_import_statements : true ,
2021-03-15 18:01:41 -04:00
names : true ,
paths : true ,
auto_imports : true ,
2023-09-25 22:54:07 -04:00
enabled : true ,
class_member_snippets : Default ::default ( ) ,
object_literal_method_snippets : Default ::default ( ) ,
2021-04-08 21:27:27 -04:00
}
}
}
2022-10-15 22:39:43 -04:00
#[ derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct InlayHintsSettings {
#[ serde(default) ]
pub parameter_names : InlayHintsParamNamesOptions ,
#[ serde(default) ]
pub parameter_types : InlayHintsParamTypesOptions ,
#[ serde(default) ]
pub variable_types : InlayHintsVarTypesOptions ,
#[ serde(default) ]
pub property_declaration_types : InlayHintsPropDeclTypesOptions ,
#[ serde(default) ]
pub function_like_return_types : InlayHintsFuncLikeReturnTypesOptions ,
#[ serde(default) ]
pub enum_member_values : InlayHintsEnumMemberValuesOptions ,
}
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct InlayHintsParamNamesOptions {
#[ serde(default) ]
pub enabled : InlayHintsParamNamesEnabled ,
#[ serde(default = " is_true " ) ]
pub suppress_when_argument_matches_name : bool ,
}
impl Default for InlayHintsParamNamesOptions {
fn default ( ) -> Self {
Self {
enabled : InlayHintsParamNamesEnabled ::None ,
suppress_when_argument_matches_name : true ,
}
}
}
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub enum InlayHintsParamNamesEnabled {
None ,
Literals ,
All ,
}
impl Default for InlayHintsParamNamesEnabled {
fn default ( ) -> Self {
Self ::None
}
}
#[ derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct InlayHintsParamTypesOptions {
#[ serde(default) ]
pub enabled : bool ,
}
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct InlayHintsVarTypesOptions {
#[ serde(default) ]
pub enabled : bool ,
#[ serde(default = " is_true " ) ]
2022-10-28 14:48:14 -04:00
pub suppress_when_type_matches_name : bool ,
2022-10-15 22:39:43 -04:00
}
impl Default for InlayHintsVarTypesOptions {
fn default ( ) -> Self {
Self {
enabled : false ,
2022-10-28 14:48:14 -04:00
suppress_when_type_matches_name : true ,
2022-10-15 22:39:43 -04:00
}
}
}
#[ derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct InlayHintsPropDeclTypesOptions {
#[ serde(default) ]
pub enabled : bool ,
}
#[ derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct InlayHintsFuncLikeReturnTypesOptions {
#[ serde(default) ]
pub enabled : bool ,
}
#[ derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct InlayHintsEnumMemberValuesOptions {
#[ serde(default) ]
pub enabled : bool ,
}
2021-07-20 21:50:43 -04:00
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
2021-04-08 21:27:27 -04:00
#[ serde(rename_all = " camelCase " ) ]
pub struct ImportCompletionSettings {
2021-06-01 07:53:08 -04:00
/// A flag that indicates if non-explicitly set origins should be checked for
/// supporting import suggestions.
#[ serde(default = " is_true " ) ]
pub auto_discover : bool ,
/// A map of origins which have had explicitly set if import suggestions are
/// enabled.
2021-04-08 21:27:27 -04:00
#[ serde(default) ]
pub hosts : HashMap < String , bool > ,
}
impl Default for ImportCompletionSettings {
fn default ( ) -> Self {
Self {
2021-06-01 07:53:08 -04:00
auto_discover : true ,
2021-04-08 21:27:27 -04:00
hosts : HashMap ::default ( ) ,
2021-03-15 18:01:41 -04:00
}
}
}
2022-03-29 18:59:27 -04:00
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct TestingSettings {
/// A vector of arguments which should be used when running the tests for
/// a workspace.
#[ serde(default) ]
pub args : Vec < String > ,
}
impl Default for TestingSettings {
fn default ( ) -> Self {
Self {
args : vec ! [ " --allow-all " . to_string ( ) , " --no-check " . to_string ( ) ] ,
}
}
}
2022-05-16 07:10:08 -04:00
fn default_to_true ( ) -> bool {
true
}
2023-05-11 17:17:14 -04:00
fn default_document_preload_limit ( ) -> usize {
1000
}
2023-01-03 10:59:48 -05:00
fn empty_string_none < ' de , D : serde ::Deserializer < ' de > > (
d : D ,
) -> Result < Option < String > , D ::Error > {
let o : Option < String > = Option ::deserialize ( d ) ? ;
Ok ( o . filter ( | s | ! s . is_empty ( ) ) )
}
2023-09-25 22:54:07 -04:00
#[ derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " kebab-case " ) ]
pub enum ImportModuleSpecifier {
NonRelative ,
ProjectRelative ,
Relative ,
Shortest ,
}
impl Default for ImportModuleSpecifier {
fn default ( ) -> Self {
Self ::Shortest
}
}
#[ derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " kebab-case " ) ]
pub enum JsxAttributeCompletionStyle {
Auto ,
Braces ,
None ,
}
impl Default for JsxAttributeCompletionStyle {
fn default ( ) -> Self {
Self ::Auto
}
}
2023-10-16 21:51:42 -04:00
#[ derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " kebab-case " ) ]
pub enum QuoteStyle {
Auto ,
Double ,
Single ,
}
impl Default for QuoteStyle {
fn default ( ) -> Self {
Self ::Auto
}
}
impl From < & FmtOptionsConfig > for QuoteStyle {
fn from ( config : & FmtOptionsConfig ) -> Self {
match config . single_quote {
Some ( true ) = > QuoteStyle ::Single ,
_ = > QuoteStyle ::Double ,
}
}
}
2023-09-25 22:54:07 -04:00
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct LanguagePreferences {
#[ serde(default) ]
pub import_module_specifier : ImportModuleSpecifier ,
#[ serde(default) ]
pub jsx_attribute_completion_style : JsxAttributeCompletionStyle ,
#[ serde(default) ]
pub auto_import_file_exclude_patterns : Vec < String > ,
#[ serde(default = " is_true " ) ]
pub use_aliases_for_renames : bool ,
2023-10-16 21:51:42 -04:00
#[ serde(default) ]
pub quote_style : QuoteStyle ,
2023-09-25 22:54:07 -04:00
}
impl Default for LanguagePreferences {
fn default ( ) -> Self {
LanguagePreferences {
import_module_specifier : Default ::default ( ) ,
jsx_attribute_completion_style : Default ::default ( ) ,
auto_import_file_exclude_patterns : vec ! [ ] ,
use_aliases_for_renames : true ,
2023-10-16 21:51:42 -04:00
quote_style : Default ::default ( ) ,
2023-09-25 22:54:07 -04:00
}
}
}
#[ derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct UpdateImportsOnFileMoveOptions {
#[ serde(default) ]
pub enabled : UpdateImportsOnFileMoveEnabled ,
}
#[ derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " kebab-case " ) ]
pub enum UpdateImportsOnFileMoveEnabled {
Always ,
Prompt ,
Never ,
}
impl Default for UpdateImportsOnFileMoveEnabled {
fn default ( ) -> Self {
Self ::Prompt
}
}
2023-09-21 01:46:39 -04:00
#[ derive(Debug, Default, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct LanguageWorkspaceSettings {
#[ serde(default) ]
pub inlay_hints : InlayHintsSettings ,
#[ serde(default) ]
2023-09-25 22:54:07 -04:00
pub preferences : LanguagePreferences ,
#[ serde(default) ]
2023-09-21 01:46:39 -04:00
pub suggest : CompletionSettings ,
2023-09-25 22:54:07 -04:00
#[ serde(default) ]
pub update_imports_on_file_move : UpdateImportsOnFileMoveOptions ,
2023-09-21 01:46:39 -04:00
}
2023-12-21 20:04:02 -05:00
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
#[ serde(untagged) ]
pub enum InspectSetting {
Bool ( bool ) ,
String ( String ) ,
}
impl Default for InspectSetting {
fn default ( ) -> Self {
InspectSetting ::Bool ( false )
}
}
impl InspectSetting {
pub fn to_address ( & self ) -> Option < String > {
match self {
InspectSetting ::Bool ( false ) = > None ,
InspectSetting ::Bool ( true ) = > Some ( " 127.0.0.1:9222 " . to_string ( ) ) ,
InspectSetting ::String ( s ) = > Some ( s . clone ( ) ) ,
}
}
}
2021-05-09 21:16:04 -04:00
/// Deno language server specific settings that are applied to a workspace.
2023-01-03 10:59:48 -05:00
#[ derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq) ]
2020-12-07 05:46:39 -05:00
#[ serde(rename_all = " camelCase " ) ]
pub struct WorkspaceSettings {
2021-05-09 21:16:04 -04:00
/// A flag that indicates if Deno is enabled for the workspace.
2023-09-01 16:13:13 -04:00
pub enable : Option < bool > ,
2021-05-09 21:16:04 -04:00
2023-09-13 12:30:27 -04:00
/// A list of paths, using the root_uri as a base that should be Deno
/// disabled.
#[ serde(default) ]
pub disable_paths : Vec < String > ,
2022-03-20 21:33:37 -04:00
/// A list of paths, using the root_uri as a base that should be Deno enabled.
2023-09-09 10:04:21 -04:00
pub enable_paths : Option < Vec < String > > ,
2022-03-20 21:33:37 -04:00
2021-07-27 17:25:09 -04:00
/// An option that points to a path string of the path to utilise as the
/// cache/DENO_DIR for the language server.
2023-01-03 10:59:48 -05:00
#[ serde(default, deserialize_with = " empty_string_none " ) ]
2021-07-27 17:25:09 -04:00
pub cache : Option < String > ,
2023-09-24 12:59:42 -04:00
/// Cache local modules and their dependencies on `textDocument/didSave`
/// notifications corresponding to them.
#[ serde(default) ]
pub cache_on_save : bool ,
2022-01-23 19:27:52 -05:00
/// Override the default stores used to validate certificates. This overrides
/// the environment variable `DENO_TLS_CA_STORE` if present.
pub certificate_stores : Option < Vec < String > > ,
2021-05-10 12:16:39 -04:00
/// An option that points to a path string of the config file to apply to
2021-05-09 21:16:04 -04:00
/// code within the workspace.
2023-01-03 10:59:48 -05:00
#[ serde(default, deserialize_with = " empty_string_none " ) ]
2020-12-07 05:46:39 -05:00
pub config : Option < String > ,
2021-05-09 21:16:04 -04:00
/// An option that points to a path string of the import map to apply to the
/// code within the workspace.
2023-01-03 10:59:48 -05:00
#[ serde(default, deserialize_with = " empty_string_none " ) ]
2020-12-07 05:46:39 -05:00
pub import_map : Option < String > ,
2021-05-09 21:16:04 -04:00
/// Code lens specific settings for the workspace.
2021-03-15 18:01:41 -04:00
#[ serde(default) ]
pub code_lens : CodeLensSettings ,
2021-05-09 21:16:04 -04:00
2021-05-11 00:54:10 -04:00
/// A flag that indicates if internal debug logging should be made available.
#[ serde(default) ]
pub internal_debug : bool ,
2021-01-04 16:52:20 -05:00
2023-12-21 20:04:02 -05:00
#[ serde(default) ]
pub internal_inspect : InspectSetting ,
2023-12-08 12:04:56 -05:00
/// Write logs to a file in a project-local directory.
#[ serde(default) ]
pub log_file : bool ,
2021-05-09 21:16:04 -04:00
/// A flag that indicates if linting is enabled for the workspace.
2022-05-16 07:10:08 -04:00
#[ serde(default = " default_to_true " ) ]
2020-12-07 05:46:39 -05:00
pub lint : bool ,
2021-05-09 21:16:04 -04:00
2023-05-11 17:17:14 -04:00
/// Limits the number of files that can be preloaded by the language server.
#[ serde(default = " default_document_preload_limit " ) ]
pub document_preload_limit : usize ,
2021-05-11 00:54:10 -04:00
#[ serde(default) ]
2023-09-21 01:46:39 -04:00
pub suggest : DenoCompletionSettings ,
2021-05-11 00:54:10 -04:00
2022-03-29 18:59:27 -04:00
/// Testing settings for the workspace.
#[ serde(default) ]
pub testing : TestingSettings ,
2022-01-23 19:27:52 -05:00
/// An option which sets the cert file to use when attempting to fetch remote
/// resources. This overrides `DENO_CERT` if present.
2023-01-03 10:59:48 -05:00
#[ serde(default, deserialize_with = " empty_string_none " ) ]
2022-01-23 19:27:52 -05:00
pub tls_certificate : Option < String > ,
/// An option, if set, will unsafely ignore certificate errors when fetching
/// remote resources.
#[ serde(default) ]
pub unsafely_ignore_certificate_errors : Option < Vec < String > > ,
2021-01-04 16:52:20 -05:00
#[ serde(default) ]
2020-12-07 05:46:39 -05:00
pub unstable : bool ,
2023-09-21 01:46:39 -04:00
#[ serde(default) ]
pub javascript : LanguageWorkspaceSettings ,
#[ serde(default) ]
pub typescript : LanguageWorkspaceSettings ,
2020-12-07 05:46:39 -05:00
}
2023-01-03 10:59:48 -05:00
impl Default for WorkspaceSettings {
fn default ( ) -> Self {
WorkspaceSettings {
2023-09-01 16:13:13 -04:00
enable : None ,
2023-09-13 12:30:27 -04:00
disable_paths : vec ! [ ] ,
2023-09-09 10:04:21 -04:00
enable_paths : None ,
2023-01-03 10:59:48 -05:00
cache : None ,
2023-09-24 12:59:42 -04:00
cache_on_save : false ,
2023-01-03 10:59:48 -05:00
certificate_stores : None ,
config : None ,
import_map : None ,
code_lens : Default ::default ( ) ,
internal_debug : false ,
2023-12-21 20:04:02 -05:00
internal_inspect : Default ::default ( ) ,
2023-12-08 12:04:56 -05:00
log_file : false ,
2023-01-03 10:59:48 -05:00
lint : true ,
2023-05-11 17:17:14 -04:00
document_preload_limit : default_document_preload_limit ( ) ,
2023-01-03 10:59:48 -05:00
suggest : Default ::default ( ) ,
testing : Default ::default ( ) ,
tls_certificate : None ,
unsafely_ignore_certificate_errors : None ,
unstable : false ,
2023-09-21 01:46:39 -04:00
javascript : Default ::default ( ) ,
typescript : Default ::default ( ) ,
2023-01-03 10:59:48 -05:00
}
}
}
2021-01-31 22:30:41 -05:00
impl WorkspaceSettings {
2023-09-21 01:46:39 -04:00
pub fn from_raw_settings (
deno : Value ,
javascript : Value ,
typescript : Value ,
) -> Self {
fn parse_or_default < T : Default + DeserializeOwned > (
value : Value ,
description : & str ,
) -> T {
if value . is_null ( ) {
return T ::default ( ) ;
}
match serde_json ::from_value ( value ) {
Ok ( v ) = > v ,
Err ( err ) = > {
lsp_warn! ( " Couldn't parse {description}: {err} " ) ;
T ::default ( )
}
}
}
let deno_inlay_hints =
deno . as_object ( ) . and_then ( | o | o . get ( " inlayHints " ) . cloned ( ) ) ;
let deno_suggest = deno . as_object ( ) . and_then ( | o | o . get ( " suggest " ) . cloned ( ) ) ;
let mut settings : Self = parse_or_default ( deno , " settings under \" deno \" " ) ;
settings . javascript =
parse_or_default ( javascript , " settings under \" javascript \" " ) ;
settings . typescript =
parse_or_default ( typescript , " settings under \" typescript \" " ) ;
if let Some ( inlay_hints ) = deno_inlay_hints {
let inlay_hints : InlayHintsSettings =
parse_or_default ( inlay_hints , " settings under \" deno.inlayHints \" " ) ;
if inlay_hints . parameter_names . enabled ! = Default ::default ( ) {
lsp_warn! ( " \" deno.inlayHints.parameterNames.enabled \" is deprecated. Instead use \" javascript.inlayHints.parameterNames.enabled \" and \" typescript.inlayHints.parameterNames.enabled \" . " ) ;
settings . javascript . inlay_hints . parameter_names . enabled =
inlay_hints . parameter_names . enabled . clone ( ) ;
settings . typescript . inlay_hints . parameter_names . enabled =
inlay_hints . parameter_names . enabled ;
}
if ! inlay_hints
. parameter_names
. suppress_when_argument_matches_name
{
lsp_warn! ( " \" deno.inlayHints.parameterNames.suppressWhenArgumentMatchesName \" is deprecated. Instead use \" javascript.inlayHints.parameterNames.suppressWhenArgumentMatchesName \" and \" typescript.inlayHints.parameterNames.suppressWhenArgumentMatchesName \" . " ) ;
settings
. javascript
. inlay_hints
. parameter_names
. suppress_when_argument_matches_name = inlay_hints
. parameter_names
. suppress_when_argument_matches_name ;
settings
. typescript
. inlay_hints
. parameter_names
. suppress_when_argument_matches_name = inlay_hints
. parameter_names
. suppress_when_argument_matches_name ;
}
if inlay_hints . parameter_types . enabled {
lsp_warn! ( " \" deno.inlayHints.parameterTypes.enabled \" is deprecated. Instead use \" javascript.inlayHints.parameterTypes.enabled \" and \" typescript.inlayHints.parameterTypes.enabled \" . " ) ;
settings . javascript . inlay_hints . parameter_types . enabled =
inlay_hints . parameter_types . enabled ;
settings . typescript . inlay_hints . parameter_types . enabled =
inlay_hints . parameter_types . enabled ;
}
if inlay_hints . variable_types . enabled {
lsp_warn! ( " \" deno.inlayHints.variableTypes.enabled \" is deprecated. Instead use \" javascript.inlayHints.variableTypes.enabled \" and \" typescript.inlayHints.variableTypes.enabled \" . " ) ;
settings . javascript . inlay_hints . variable_types . enabled =
inlay_hints . variable_types . enabled ;
settings . typescript . inlay_hints . variable_types . enabled =
inlay_hints . variable_types . enabled ;
}
if ! inlay_hints . variable_types . suppress_when_type_matches_name {
lsp_warn! ( " \" deno.inlayHints.variableTypes.suppressWhenTypeMatchesName \" is deprecated. Instead use \" javascript.inlayHints.variableTypes.suppressWhenTypeMatchesName \" and \" typescript.inlayHints.variableTypes.suppressWhenTypeMatchesName \" . " ) ;
settings
. javascript
. inlay_hints
. variable_types
. suppress_when_type_matches_name =
inlay_hints . variable_types . suppress_when_type_matches_name ;
settings
. typescript
. inlay_hints
. variable_types
. suppress_when_type_matches_name =
inlay_hints . variable_types . suppress_when_type_matches_name ;
}
if inlay_hints . property_declaration_types . enabled {
lsp_warn! ( " \" deno.inlayHints.propertyDeclarationTypes.enabled \" is deprecated. Instead use \" javascript.inlayHints.propertyDeclarationTypes.enabled \" and \" typescript.inlayHints.propertyDeclarationTypes.enabled \" . " ) ;
settings
. javascript
. inlay_hints
. property_declaration_types
. enabled = inlay_hints . property_declaration_types . enabled ;
settings
. typescript
. inlay_hints
. property_declaration_types
. enabled = inlay_hints . property_declaration_types . enabled ;
}
if inlay_hints . function_like_return_types . enabled {
lsp_warn! ( " \" deno.inlayHints.functionLikeReturnTypes.enabled \" is deprecated. Instead use \" javascript.inlayHints.functionLikeReturnTypes.enabled \" and \" typescript.inlayHints.functionLikeReturnTypes.enabled \" . " ) ;
settings
. javascript
. inlay_hints
. function_like_return_types
. enabled = inlay_hints . function_like_return_types . enabled ;
settings
. typescript
. inlay_hints
. function_like_return_types
. enabled = inlay_hints . function_like_return_types . enabled ;
}
if inlay_hints . enum_member_values . enabled {
lsp_warn! ( " \" deno.inlayHints.enumMemberValues.enabled \" is deprecated. Instead use \" javascript.inlayHints.enumMemberValues.enabled \" and \" typescript.inlayHints.enumMemberValues.enabled \" . " ) ;
settings . javascript . inlay_hints . enum_member_values . enabled =
inlay_hints . enum_member_values . enabled ;
settings . typescript . inlay_hints . enum_member_values . enabled =
inlay_hints . enum_member_values . enabled ;
}
}
if let Some ( suggest ) = deno_suggest {
let suggest : CompletionSettings =
parse_or_default ( suggest , " settings under \" deno.suggest \" " ) ;
if suggest . complete_function_calls {
lsp_warn! ( " \" deno.suggest.completeFunctionCalls \" is deprecated. Instead use \" javascript.suggest.completeFunctionCalls \" and \" typescript.suggest.completeFunctionCalls \" . " ) ;
settings . javascript . suggest . complete_function_calls =
suggest . complete_function_calls ;
settings . typescript . suggest . complete_function_calls =
suggest . complete_function_calls ;
}
if ! suggest . names {
lsp_warn! ( " \" deno.suggest.names \" is deprecated. Instead use \" javascript.suggest.names \" and \" typescript.suggest.names \" . " ) ;
settings . javascript . suggest . names = suggest . names ;
settings . typescript . suggest . names = suggest . names ;
}
if ! suggest . paths {
lsp_warn! ( " \" deno.suggest.paths \" is deprecated. Instead use \" javascript.suggest.paths \" and \" typescript.suggest.paths \" . " ) ;
settings . javascript . suggest . paths = suggest . paths ;
settings . typescript . suggest . paths = suggest . paths ;
}
if ! suggest . auto_imports {
lsp_warn! ( " \" deno.suggest.autoImports \" is deprecated. Instead use \" javascript.suggest.autoImports \" and \" typescript.suggest.autoImports \" . " ) ;
settings . javascript . suggest . auto_imports = suggest . auto_imports ;
settings . typescript . suggest . auto_imports = suggest . auto_imports ;
}
}
settings
}
pub fn from_initialization_options ( options : Value ) -> Self {
let deno = options ;
let javascript = deno
. as_object ( )
. and_then ( | o | o . get ( " javascript " ) . cloned ( ) )
. unwrap_or_default ( ) ;
let typescript = deno
. as_object ( )
. and_then ( | o | o . get ( " typescript " ) . cloned ( ) )
. unwrap_or_default ( ) ;
Self ::from_raw_settings ( deno , javascript , typescript )
}
2021-01-31 22:30:41 -05:00
}
2021-05-20 05:56:48 -04:00
#[ derive(Debug, Clone, Default) ]
pub struct ConfigSnapshot {
pub client_capabilities : ClientCapabilities ,
2023-09-09 14:37:01 -04:00
pub config_file : Option < ConfigFile > ,
2021-05-20 05:56:48 -04:00
pub settings : Settings ,
2023-09-09 10:04:21 -04:00
pub workspace_folders : Vec < ( ModuleSpecifier , lsp ::WorkspaceFolder ) > ,
2021-05-20 05:56:48 -04:00
}
impl ConfigSnapshot {
2023-10-24 16:27:27 -04:00
pub fn workspace_settings_for_specifier (
& self ,
specifier : & ModuleSpecifier ,
) -> & WorkspaceSettings {
self . settings . get_for_specifier ( specifier ) . 0
}
2022-03-20 21:33:37 -04:00
/// Determine if the provided specifier is enabled or not.
2021-05-20 05:56:48 -04:00
pub fn specifier_enabled ( & self , specifier : & ModuleSpecifier ) -> bool {
2023-07-10 21:03:19 -04:00
specifier_enabled (
2023-09-09 10:04:21 -04:00
specifier ,
2023-09-09 14:37:01 -04:00
self . config_file . as_ref ( ) ,
2023-09-08 11:48:26 -04:00
& self . settings ,
2023-09-09 10:04:21 -04:00
& self . workspace_folders ,
2023-07-10 21:03:19 -04:00
)
2021-05-20 05:56:48 -04:00
}
2023-09-09 14:37:01 -04:00
pub fn specifier_enabled_for_test (
& self ,
specifier : & ModuleSpecifier ,
) -> bool {
if let Some ( cf ) = & self . config_file {
if let Some ( options ) = cf . to_test_config ( ) . ok ( ) . flatten ( ) {
if ! options . files . matches_specifier ( specifier ) {
return false ;
}
}
}
2024-01-15 19:15:39 -05:00
self . specifier_enabled ( specifier )
2023-09-09 14:37:01 -04:00
}
2021-05-20 05:56:48 -04:00
}
2021-03-09 21:41:35 -05:00
#[ derive(Debug, Default, Clone) ]
2021-05-20 05:56:48 -04:00
pub struct Settings {
2023-10-24 16:27:27 -04:00
pub unscoped : WorkspaceSettings ,
pub by_workspace_folder : Option < BTreeMap < ModuleSpecifier , WorkspaceSettings > > ,
}
impl Settings {
pub fn get_unscoped ( & self ) -> & WorkspaceSettings {
& self . unscoped
}
pub fn get_for_specifier (
& self ,
specifier : & ModuleSpecifier ,
) -> ( & WorkspaceSettings , Option < & ModuleSpecifier > ) {
let Ok ( path ) = specifier_to_file_path ( specifier ) else {
return ( & self . unscoped , None ) ;
} ;
if let Some ( by_workspace_folder ) = & self . by_workspace_folder {
for ( folder_uri , settings ) in by_workspace_folder . iter ( ) . rev ( ) {
let Ok ( folder_path ) = specifier_to_file_path ( folder_uri ) else {
continue ;
} ;
if path . starts_with ( folder_path ) {
return ( settings , Some ( folder_uri ) ) ;
}
}
}
( & self . unscoped , None )
}
pub fn set_unscoped ( & mut self , mut settings : WorkspaceSettings ) {
// See https://github.com/denoland/vscode_deno/issues/908.
if settings . enable_paths = = Some ( vec! [ ] ) {
settings . enable_paths = None ;
}
self . unscoped = settings ;
}
pub fn set_for_workspace_folders (
& mut self ,
mut by_workspace_folder : Option <
BTreeMap < ModuleSpecifier , WorkspaceSettings > ,
> ,
) {
if let Some ( by_workspace_folder ) = & mut by_workspace_folder {
for settings in by_workspace_folder . values_mut ( ) {
// See https://github.com/denoland/vscode_deno/issues/908.
if settings . enable_paths = = Some ( vec! [ ] ) {
settings . enable_paths = None ;
}
}
}
self . by_workspace_folder = by_workspace_folder ;
}
2021-05-20 05:56:48 -04:00
}
2023-07-21 09:12:26 -04:00
#[ derive(Debug) ]
struct WithCanonicalizedSpecifier < T > {
/// Stored canonicalized specifier, which is used for file watcher events.
canonicalized_specifier : ModuleSpecifier ,
file : T ,
}
2023-07-10 17:45:09 -04:00
/// Contains the config file and dependent information.
#[ derive(Debug) ]
struct LspConfigFileInfo {
2023-07-21 09:12:26 -04:00
config_file : WithCanonicalizedSpecifier < ConfigFile > ,
2023-07-10 17:45:09 -04:00
/// An optional deno.lock file, which is resolved relative to the config file.
2023-07-21 09:12:26 -04:00
maybe_lockfile : Option < WithCanonicalizedSpecifier < Arc < Mutex < Lockfile > > > > ,
2023-07-10 17:45:09 -04:00
/// The canonicalized node_modules directory, which is found relative to the config file.
2023-07-10 21:03:19 -04:00
maybe_node_modules_dir : Option < PathBuf > ,
2023-07-10 17:45:09 -04:00
}
2021-05-20 05:56:48 -04:00
#[ derive(Debug) ]
2020-12-07 05:46:39 -05:00
pub struct Config {
pub client_capabilities : ClientCapabilities ,
2022-01-25 10:30:38 -05:00
settings : Settings ,
2023-09-09 10:04:21 -04:00
pub workspace_folders : Vec < ( ModuleSpecifier , lsp ::WorkspaceFolder ) > ,
2023-07-10 17:45:09 -04:00
/// An optional configuration file which has been specified in the client
/// options along with some data that is computed after the config file is set.
maybe_config_file_info : Option < LspConfigFileInfo > ,
2020-12-07 05:46:39 -05:00
}
impl Config {
2022-01-25 10:30:38 -05:00
pub fn new ( ) -> Self {
2021-05-20 05:56:48 -04:00
Self {
client_capabilities : ClientCapabilities ::default ( ) ,
2023-11-17 10:06:28 -05:00
// Root provided by the initialization parameters.
2022-01-25 10:30:38 -05:00
settings : Default ::default ( ) ,
2023-09-09 10:04:21 -04:00
workspace_folders : vec ! [ ] ,
2023-07-10 17:45:09 -04:00
maybe_config_file_info : None ,
2021-05-20 05:56:48 -04:00
}
}
2023-09-09 10:04:21 -04:00
#[ cfg(test) ]
pub fn new_with_root ( root_uri : Url ) -> Self {
let mut config = Self ::new ( ) ;
let name = root_uri . path_segments ( ) . and_then ( | s | s . last ( ) ) ;
let name = name . unwrap_or_default ( ) . to_string ( ) ;
config . workspace_folders = vec! [ (
root_uri . clone ( ) ,
lsp ::WorkspaceFolder {
uri : root_uri ,
name ,
} ,
) ] ;
config
}
2023-10-24 16:27:27 -04:00
pub fn set_workspace_settings (
& mut self ,
unscoped : WorkspaceSettings ,
by_workspace_folder : Option < BTreeMap < ModuleSpecifier , WorkspaceSettings > > ,
) {
self . settings . set_unscoped ( unscoped ) ;
self . settings . set_for_workspace_folders ( by_workspace_folder ) ;
}
pub fn workspace_settings ( & self ) -> & WorkspaceSettings {
self . settings . get_unscoped ( )
}
pub fn workspace_settings_for_specifier (
& self ,
specifier : & ModuleSpecifier ,
) -> & WorkspaceSettings {
self . settings . get_for_specifier ( specifier ) . 0
}
pub fn language_settings_for_specifier (
& self ,
specifier : & ModuleSpecifier ,
) -> Option < & LanguageWorkspaceSettings > {
let workspace_settings = self . workspace_settings_for_specifier ( specifier ) ;
match MediaType ::from_specifier ( specifier ) {
MediaType ::JavaScript
| MediaType ::Jsx
| MediaType ::Mjs
| MediaType ::Cjs = > Some ( & workspace_settings . javascript ) ,
MediaType ::TypeScript
| MediaType ::Mts
| MediaType ::Cts
| MediaType ::Dts
| MediaType ::Dmts
| MediaType ::Dcts
| MediaType ::Tsx = > Some ( & workspace_settings . typescript ) ,
MediaType ::Json
| MediaType ::Wasm
| MediaType ::TsBuildInfo
| MediaType ::SourceMap
| MediaType ::Unknown = > None ,
}
}
/// Determine if any inlay hints are enabled. This allows short circuiting
/// when there are no inlay hints enabled.
pub fn enabled_inlay_hints_for_specifier (
& self ,
specifier : & ModuleSpecifier ,
) -> bool {
let Some ( settings ) = self . language_settings_for_specifier ( specifier ) else {
return false ;
} ;
! matches! (
settings . inlay_hints . parameter_names . enabled ,
InlayHintsParamNamesEnabled ::None
) | | settings . inlay_hints . parameter_types . enabled
| | settings . inlay_hints . variable_types . enabled
| | settings . inlay_hints . property_declaration_types . enabled
| | settings . inlay_hints . function_like_return_types . enabled
| | settings . inlay_hints . enum_member_values . enabled
}
2023-09-09 10:04:21 -04:00
pub fn root_uri ( & self ) -> Option < & Url > {
2024-01-01 17:22:48 -05:00
self . workspace_folders . first ( ) . map ( | p | & p . 0 )
2023-09-09 10:04:21 -04:00
}
2023-07-10 17:45:09 -04:00
pub fn maybe_node_modules_dir_path ( & self ) -> Option < & PathBuf > {
self
. maybe_config_file_info
. as_ref ( )
. and_then ( | p | p . maybe_node_modules_dir . as_ref ( ) )
}
2023-08-06 21:56:56 -04:00
pub fn maybe_vendor_dir_path ( & self ) -> Option < PathBuf > {
self . maybe_config_file ( ) . and_then ( | c | c . vendor_dir_path ( ) )
2023-08-01 20:49:09 -04:00
}
2023-07-10 17:45:09 -04:00
pub fn maybe_config_file ( & self ) -> Option < & ConfigFile > {
2023-07-21 09:12:26 -04:00
self
. maybe_config_file_info
. as_ref ( )
. map ( | c | & c . config_file . file )
}
/// Canonicalized specifier of the config file, which should only be used for
/// file watcher events. Otherwise, prefer using the non-canonicalized path
/// as the rest of the CLI does for config files.
pub fn maybe_config_file_canonicalized_specifier (
& self ,
) -> Option < & ModuleSpecifier > {
self
. maybe_config_file_info
. as_ref ( )
. map ( | c | & c . config_file . canonicalized_specifier )
2023-07-10 17:45:09 -04:00
}
pub fn maybe_lockfile ( & self ) -> Option < & Arc < Mutex < Lockfile > > > {
self
. maybe_config_file_info
. as_ref ( )
2023-07-21 09:12:26 -04:00
. and_then ( | c | c . maybe_lockfile . as_ref ( ) . map ( | l | & l . file ) )
}
/// Canonicalized specifier of the lockfile, which should only be used for
/// file watcher events. Otherwise, prefer using the non-canonicalized path
/// as the rest of the CLI does for config files.
pub fn maybe_lockfile_canonicalized_specifier (
& self ,
) -> Option < & ModuleSpecifier > {
self . maybe_config_file_info . as_ref ( ) . and_then ( | c | {
c . maybe_lockfile
. as_ref ( )
. map ( | l | & l . canonicalized_specifier )
} )
2023-07-10 17:45:09 -04:00
}
pub fn clear_config_file ( & mut self ) {
self . maybe_config_file_info = None ;
}
2023-09-01 16:13:13 -04:00
pub fn has_config_file ( & self ) -> bool {
self . maybe_config_file_info . is_some ( )
}
2023-07-10 17:45:09 -04:00
pub fn set_config_file ( & mut self , config_file : ConfigFile ) {
self . maybe_config_file_info = Some ( LspConfigFileInfo {
2023-07-21 09:12:26 -04:00
maybe_lockfile : resolve_lockfile_from_config ( & config_file ) . map (
| lockfile | {
let path = canonicalize_path_maybe_not_exists ( & lockfile . filename )
. unwrap_or_else ( | _ | lockfile . filename . clone ( ) ) ;
WithCanonicalizedSpecifier {
canonicalized_specifier : ModuleSpecifier ::from_file_path ( path )
. unwrap ( ) ,
file : Arc ::new ( Mutex ::new ( lockfile ) ) ,
}
} ,
) ,
2023-07-10 17:45:09 -04:00
maybe_node_modules_dir : resolve_node_modules_dir ( & config_file ) ,
2023-07-21 09:12:26 -04:00
config_file : WithCanonicalizedSpecifier {
canonicalized_specifier : config_file
. specifier
. to_file_path ( )
. ok ( )
. and_then ( | p | canonicalize_path_maybe_not_exists ( & p ) . ok ( ) )
. and_then ( | p | ModuleSpecifier ::from_file_path ( p ) . ok ( ) )
. unwrap_or_else ( | | config_file . specifier . clone ( ) ) ,
file : config_file ,
} ,
2023-07-10 17:45:09 -04:00
} ) ;
}
2022-01-19 17:10:14 -05:00
pub fn snapshot ( & self ) -> Arc < ConfigSnapshot > {
Arc ::new ( ConfigSnapshot {
2021-05-20 05:56:48 -04:00
client_capabilities : self . client_capabilities . clone ( ) ,
2023-09-09 14:37:01 -04:00
config_file : self . maybe_config_file ( ) . cloned ( ) ,
2022-01-25 10:30:38 -05:00
settings : self . settings . clone ( ) ,
2023-09-09 10:04:21 -04:00
workspace_folders : self . workspace_folders . clone ( ) ,
2021-05-20 05:56:48 -04:00
} )
2021-05-09 21:16:04 -04:00
}
pub fn specifier_enabled ( & self , specifier : & ModuleSpecifier ) -> bool {
2023-07-10 21:03:19 -04:00
specifier_enabled (
2023-09-09 10:04:21 -04:00
specifier ,
2023-09-09 14:37:01 -04:00
self . maybe_config_file ( ) ,
2023-09-09 10:04:21 -04:00
& self . settings ,
& self . workspace_folders ,
2023-07-10 21:03:19 -04:00
)
2021-06-07 07:38:07 -04:00
}
2023-09-09 14:37:01 -04:00
pub fn specifier_enabled_for_test (
& self ,
specifier : & ModuleSpecifier ,
) -> bool {
if let Some ( cf ) = self . maybe_config_file ( ) {
if let Some ( options ) = cf . to_test_config ( ) . ok ( ) . flatten ( ) {
if ! options . files . matches_specifier ( specifier ) {
return false ;
}
}
}
if ! self . specifier_enabled ( specifier ) {
return false ;
}
true
}
2024-01-15 19:15:39 -05:00
pub fn get_enabled_paths ( & self ) -> PathOrPatternSet {
2023-09-18 15:58:16 -04:00
let mut paths = vec! [ ] ;
2023-09-09 10:04:21 -04:00
for ( workspace_uri , _ ) in & self . workspace_folders {
2023-09-13 12:30:27 -04:00
let Ok ( workspace_path ) = specifier_to_file_path ( workspace_uri ) else {
lsp_log! ( " Unable to convert uri \" {} \" to path. " , workspace_uri ) ;
continue ;
} ;
2023-10-24 16:27:27 -04:00
let settings = self . workspace_settings_for_specifier ( workspace_uri ) ;
if let Some ( enable_paths ) = & settings . enable_paths {
2023-09-09 10:04:21 -04:00
for path in enable_paths {
2024-01-15 19:15:39 -05:00
match PathOrPattern ::from_relative ( & workspace_path , path ) {
Ok ( path_or_pattern ) = > paths . push ( path_or_pattern ) ,
Err ( err ) = > {
lsp_log! ( " Invalid enable path '{}': {:#} " , path , err ) ;
}
}
2023-09-09 10:04:21 -04:00
}
2023-09-18 15:58:16 -04:00
} else {
2024-01-15 19:15:39 -05:00
paths . push ( PathOrPattern ::Path ( workspace_path ) ) ;
2023-03-30 17:47:53 -04:00
}
}
2023-09-18 15:58:16 -04:00
paths . sort ( ) ;
paths . dedup ( ) ;
2024-01-15 19:15:39 -05:00
PathOrPatternSet ::new ( paths )
2023-09-13 12:30:27 -04:00
}
2024-01-15 19:15:39 -05:00
pub fn get_disabled_paths ( & self ) -> PathOrPatternSet {
let mut path_or_patterns = vec! [ ] ;
2023-09-13 12:30:27 -04:00
if let Some ( cf ) = self . maybe_config_file ( ) {
if let Some ( files ) = cf . to_files_config ( ) . ok ( ) . flatten ( ) {
2024-01-15 19:15:39 -05:00
for path in files . exclude . into_path_or_patterns ( ) {
path_or_patterns . push ( path ) ;
2023-09-13 12:30:27 -04:00
}
}
}
for ( workspace_uri , _ ) in & self . workspace_folders {
let Ok ( workspace_path ) = specifier_to_file_path ( workspace_uri ) else {
lsp_log! ( " Unable to convert uri \" {} \" to path. " , workspace_uri ) ;
continue ;
} ;
2023-10-24 16:27:27 -04:00
let settings = self . workspace_settings_for_specifier ( workspace_uri ) ;
if settings . enable . unwrap_or_else ( | | self . has_config_file ( ) ) {
for path in & settings . disable_paths {
2024-01-15 19:15:39 -05:00
path_or_patterns . push ( PathOrPattern ::Path ( workspace_path . join ( path ) ) ) ;
2023-09-13 12:30:27 -04:00
}
} else {
2024-01-15 19:15:39 -05:00
path_or_patterns . push ( PathOrPattern ::Path ( workspace_path ) ) ;
2023-09-13 12:30:27 -04:00
}
}
2024-01-15 19:15:39 -05:00
path_or_patterns . sort ( ) ;
path_or_patterns . dedup ( ) ;
PathOrPatternSet ::new ( path_or_patterns )
2023-03-30 17:47:53 -04:00
}
2023-12-08 12:04:56 -05:00
pub fn log_file ( & self ) -> bool {
self . settings . unscoped . log_file
}
2023-12-21 20:04:02 -05:00
pub fn internal_inspect ( & self ) -> & InspectSetting {
& self . settings . unscoped . internal_inspect
}
2020-12-07 05:46:39 -05:00
pub fn update_capabilities (
& mut self ,
2021-01-29 14:34:33 -05:00
capabilities : & lsp ::ClientCapabilities ,
2020-12-07 05:46:39 -05:00
) {
if let Some ( experimental ) = & capabilities . experimental {
2021-06-15 13:22:28 -04:00
self . client_capabilities . status_notification = experimental
. get ( " statusNotification " )
. and_then ( | it | it . as_bool ( ) )
2022-03-29 18:59:27 -04:00
= = Some ( true ) ;
self . client_capabilities . testing_api =
experimental . get ( " testingApi " ) . and_then ( | it | it . as_bool ( ) )
= = Some ( true ) ;
2020-12-07 05:46:39 -05:00
}
2021-01-04 16:52:20 -05:00
if let Some ( workspace ) = & capabilities . workspace {
self . client_capabilities . workspace_configuration =
workspace . configuration . unwrap_or ( false ) ;
self . client_capabilities . workspace_did_change_watched_files = workspace
. did_change_watched_files
. and_then ( | it | it . dynamic_registration )
. unwrap_or ( false ) ;
2023-08-25 20:50:47 -04:00
if let Some ( file_operations ) = & workspace . file_operations {
if let Some ( true ) = file_operations . dynamic_registration {
self . client_capabilities . workspace_will_rename_files =
file_operations . will_rename . unwrap_or ( false ) ;
}
}
2021-01-04 16:52:20 -05:00
}
2021-04-02 02:21:07 -04:00
if let Some ( text_document ) = & capabilities . text_document {
self . client_capabilities . line_folding_only = text_document
. folding_range
. as_ref ( )
. and_then ( | it | it . line_folding_only )
. unwrap_or ( false ) ;
2021-08-09 19:56:34 -04:00
self . client_capabilities . code_action_disabled_support = text_document
. code_action
. as_ref ( )
. and_then ( | it | it . disabled_support )
. unwrap_or ( false ) ;
2022-10-14 08:04:38 -04:00
self . client_capabilities . snippet_support =
if let Some ( completion ) = & text_document . completion {
completion
. completion_item
. as_ref ( )
. and_then ( | it | it . snippet_support )
. unwrap_or ( false )
} else {
false
} ;
2021-04-02 02:21:07 -04:00
}
2020-12-07 05:46:39 -05:00
}
2021-05-09 21:16:04 -04:00
}
2023-07-10 21:03:19 -04:00
fn specifier_enabled (
2023-09-09 10:04:21 -04:00
specifier : & Url ,
2023-09-09 14:37:01 -04:00
config_file : Option < & ConfigFile > ,
2023-07-10 21:03:19 -04:00
settings : & Settings ,
2023-10-24 16:27:27 -04:00
workspace_folders : & [ ( Url , lsp ::WorkspaceFolder ) ] ,
2023-07-10 21:03:19 -04:00
) -> bool {
2023-09-09 14:37:01 -04:00
if let Some ( cf ) = config_file {
if let Some ( files ) = cf . to_files_config ( ) . ok ( ) . flatten ( ) {
if ! files . matches_specifier ( specifier ) {
2023-09-09 10:04:21 -04:00
return false ;
}
}
}
2023-09-12 09:36:50 -04:00
let Ok ( path ) = specifier_to_file_path ( specifier ) else {
// Non-file URLs are not disabled by these settings.
return true ;
} ;
2023-10-24 16:27:27 -04:00
let ( settings , mut folder_uri ) = settings . get_for_specifier ( specifier ) ;
2024-01-01 17:22:48 -05:00
folder_uri = folder_uri . or_else ( | | workspace_folders . first ( ) . map ( | f | & f . 0 ) ) ;
2023-10-24 16:27:27 -04:00
let mut disable_paths = vec! [ ] ;
let mut enable_paths = None ;
if let Some ( folder_uri ) = folder_uri {
if let Ok ( folder_path ) = specifier_to_file_path ( folder_uri ) {
disable_paths = settings
. disable_paths
2023-09-13 12:30:27 -04:00
. iter ( )
2023-10-24 16:27:27 -04:00
. map ( | p | folder_path . join ( p ) )
2023-09-13 12:30:27 -04:00
. collect ::< Vec < _ > > ( ) ;
2023-10-24 16:27:27 -04:00
enable_paths = settings . enable_paths . as_ref ( ) . map ( | enable_paths | {
enable_paths
. iter ( )
. map ( | p | folder_path . join ( p ) )
. collect ::< Vec < _ > > ( )
} ) ;
}
}
if let Some ( enable_paths ) = & enable_paths {
for enable_path in enable_paths {
if path . starts_with ( enable_path )
& & ! disable_paths . iter ( ) . any ( | p | path . starts_with ( p ) )
{
return true ;
2023-07-10 21:03:19 -04:00
}
}
2023-10-24 16:27:27 -04:00
false
} else {
settings . enable . unwrap_or_else ( | | config_file . is_some ( ) )
& & ! disable_paths . iter ( ) . any ( | p | path . starts_with ( p ) )
2023-07-10 21:03:19 -04:00
}
}
2023-07-21 09:12:26 -04:00
fn resolve_lockfile_from_config ( config_file : & ConfigFile ) -> Option < Lockfile > {
2023-07-10 17:45:09 -04:00
let lockfile_path = match config_file . resolve_lockfile_path ( ) {
Ok ( Some ( value ) ) = > value ,
Ok ( None ) = > return None ,
Err ( err ) = > {
lsp_warn! ( " Error resolving lockfile: {:#} " , err ) ;
return None ;
}
} ;
resolve_lockfile_from_path ( lockfile_path )
}
fn resolve_node_modules_dir ( config_file : & ConfigFile ) -> Option < PathBuf > {
// For the language server, require an explicit opt-in via the
// `nodeModulesDir: true` setting in the deno.json file. This is to
// reduce the chance of modifying someone's node_modules directory
// without them having asked us to do so.
2023-08-06 21:56:56 -04:00
let explicitly_disabled = config_file . node_modules_dir_flag ( ) = = Some ( false ) ;
if explicitly_disabled {
return None ;
}
let enabled = config_file . node_modules_dir_flag ( ) = = Some ( true )
| | config_file . vendor_dir_flag ( ) = = Some ( true ) ;
if ! enabled {
2023-07-10 17:45:09 -04:00
return None ;
}
if config_file . specifier . scheme ( ) ! = " file " {
return None ;
}
let file_path = config_file . specifier . to_file_path ( ) . ok ( ) ? ;
let node_modules_dir = file_path . parent ( ) ? . join ( " node_modules " ) ;
canonicalize_path_maybe_not_exists ( & node_modules_dir ) . ok ( )
}
2023-07-21 09:12:26 -04:00
fn resolve_lockfile_from_path ( lockfile_path : PathBuf ) -> Option < Lockfile > {
2023-07-10 17:45:09 -04:00
match Lockfile ::new ( lockfile_path , false ) {
2023-07-20 14:05:52 -04:00
Ok ( value ) = > {
if let Ok ( specifier ) = ModuleSpecifier ::from_file_path ( & value . filename ) {
lsp_log! ( " Resolved lock file: \" {} \" " , specifier ) ;
}
2023-07-21 09:12:26 -04:00
Some ( value )
2023-07-20 14:05:52 -04:00
}
2023-07-10 17:45:09 -04:00
Err ( err ) = > {
lsp_warn! ( " Error loading lockfile: {:#} " , err ) ;
None
}
}
}
2021-05-09 21:16:04 -04:00
#[ cfg(test) ]
mod tests {
use super ::* ;
use deno_core ::resolve_url ;
2023-09-21 01:46:39 -04:00
use deno_core ::serde_json ;
2021-05-09 21:16:04 -04:00
use deno_core ::serde_json ::json ;
2023-04-01 15:10:30 -04:00
use pretty_assertions ::assert_eq ;
2021-05-09 21:16:04 -04:00
#[ test ]
fn test_config_specifier_enabled ( ) {
2023-09-09 10:04:21 -04:00
let root_uri = resolve_url ( " file:/// " ) . unwrap ( ) ;
let mut config = Config ::new_with_root ( root_uri ) ;
2021-05-09 21:16:04 -04:00
let specifier = resolve_url ( " file:///a.ts " ) . unwrap ( ) ;
assert! ( ! config . specifier_enabled ( & specifier ) ) ;
2023-09-21 01:46:39 -04:00
config . set_workspace_settings (
serde_json ::from_value ( json! ( {
2021-05-09 21:16:04 -04:00
" enable " : true
} ) )
2023-09-21 01:46:39 -04:00
. unwrap ( ) ,
2023-10-24 16:27:27 -04:00
None ,
2023-09-21 01:46:39 -04:00
) ;
2021-05-09 21:16:04 -04:00
assert! ( config . specifier_enabled ( & specifier ) ) ;
}
2021-06-01 07:53:08 -04:00
2022-03-20 21:33:37 -04:00
#[ test ]
fn test_config_snapshot_specifier_enabled ( ) {
2023-09-09 10:04:21 -04:00
let root_uri = resolve_url ( " file:/// " ) . unwrap ( ) ;
let mut config = Config ::new_with_root ( root_uri ) ;
2022-03-20 21:33:37 -04:00
let specifier = resolve_url ( " file:///a.ts " ) . unwrap ( ) ;
assert! ( ! config . specifier_enabled ( & specifier ) ) ;
2023-09-21 01:46:39 -04:00
config . set_workspace_settings (
serde_json ::from_value ( json! ( {
2022-03-20 21:33:37 -04:00
" enable " : true
} ) )
2023-09-21 01:46:39 -04:00
. unwrap ( ) ,
2023-10-24 16:27:27 -04:00
None ,
2023-09-21 01:46:39 -04:00
) ;
2022-03-20 21:33:37 -04:00
let config_snapshot = config . snapshot ( ) ;
assert! ( config_snapshot . specifier_enabled ( & specifier ) ) ;
}
#[ test ]
fn test_config_specifier_enabled_path ( ) {
2023-09-09 10:04:21 -04:00
let root_uri = resolve_url ( " file:///project/ " ) . unwrap ( ) ;
let mut config = Config ::new_with_root ( root_uri ) ;
2022-03-20 21:33:37 -04:00
let specifier_a = resolve_url ( " file:///project/worker/a.ts " ) . unwrap ( ) ;
let specifier_b = resolve_url ( " file:///project/other/b.ts " ) . unwrap ( ) ;
assert! ( ! config . specifier_enabled ( & specifier_a ) ) ;
assert! ( ! config . specifier_enabled ( & specifier_b ) ) ;
2023-09-09 10:04:21 -04:00
let workspace_settings =
serde_json ::from_str ( r # "{ "enablePaths": ["worker"] }"# ) . unwrap ( ) ;
2023-10-24 16:27:27 -04:00
config . set_workspace_settings ( workspace_settings , None ) ;
2022-03-20 21:33:37 -04:00
assert! ( config . specifier_enabled ( & specifier_a ) ) ;
assert! ( ! config . specifier_enabled ( & specifier_b ) ) ;
let config_snapshot = config . snapshot ( ) ;
assert! ( config_snapshot . specifier_enabled ( & specifier_a ) ) ;
assert! ( ! config_snapshot . specifier_enabled ( & specifier_b ) ) ;
}
2023-09-13 12:30:27 -04:00
#[ test ]
fn test_config_specifier_disabled_path ( ) {
let root_uri = resolve_url ( " file:///root/ " ) . unwrap ( ) ;
let mut config = Config ::new_with_root ( root_uri . clone ( ) ) ;
2023-10-24 16:27:27 -04:00
config . settings . unscoped . enable = Some ( true ) ;
config . settings . unscoped . enable_paths =
2023-09-13 12:30:27 -04:00
Some ( vec! [ " mod1.ts " . to_string ( ) , " mod2.ts " . to_string ( ) ] ) ;
2023-10-24 16:27:27 -04:00
config . settings . unscoped . disable_paths = vec! [ " mod2.ts " . to_string ( ) ] ;
2023-09-13 12:30:27 -04:00
assert! ( config . specifier_enabled ( & root_uri . join ( " mod1.ts " ) . unwrap ( ) ) ) ;
assert! ( ! config . specifier_enabled ( & root_uri . join ( " mod2.ts " ) . unwrap ( ) ) ) ;
assert! ( ! config . specifier_enabled ( & root_uri . join ( " mod3.ts " ) . unwrap ( ) ) ) ;
}
2021-06-01 07:53:08 -04:00
#[ test ]
fn test_set_workspace_settings_defaults ( ) {
2022-03-20 21:33:37 -04:00
let mut config = Config ::new ( ) ;
2023-10-24 16:27:27 -04:00
config
. set_workspace_settings ( serde_json ::from_value ( json! ( { } ) ) . unwrap ( ) , None ) ;
2021-06-01 07:53:08 -04:00
assert_eq! (
2023-05-11 17:17:14 -04:00
config . workspace_settings ( ) . clone ( ) ,
2021-06-01 07:53:08 -04:00
WorkspaceSettings {
2023-09-01 16:13:13 -04:00
enable : None ,
2023-09-13 12:30:27 -04:00
disable_paths : vec ! [ ] ,
2023-09-09 10:04:21 -04:00
enable_paths : None ,
2021-07-27 17:25:09 -04:00
cache : None ,
2023-09-24 12:59:42 -04:00
cache_on_save : false ,
2022-01-23 19:27:52 -05:00
certificate_stores : None ,
2021-06-01 07:53:08 -04:00
config : None ,
import_map : None ,
code_lens : CodeLensSettings {
implementations : false ,
references : false ,
references_all_functions : false ,
2021-06-07 07:38:07 -04:00
test : true ,
2021-06-01 07:53:08 -04:00
} ,
internal_debug : false ,
2023-12-21 20:04:02 -05:00
internal_inspect : InspectSetting ::Bool ( false ) ,
2023-12-08 12:04:56 -05:00
log_file : false ,
2022-05-16 07:10:08 -04:00
lint : true ,
2023-05-11 17:17:14 -04:00
document_preload_limit : 1_000 ,
2023-09-21 01:46:39 -04:00
suggest : DenoCompletionSettings {
2021-06-01 07:53:08 -04:00
imports : ImportCompletionSettings {
auto_discover : true ,
hosts : HashMap ::new ( ) ,
}
} ,
2022-03-29 18:59:27 -04:00
testing : TestingSettings {
args : vec ! [ " --allow-all " . to_string ( ) , " --no-check " . to_string ( ) ] ,
} ,
2022-01-23 19:27:52 -05:00
tls_certificate : None ,
unsafely_ignore_certificate_errors : None ,
2021-06-01 07:53:08 -04:00
unstable : false ,
2023-09-21 01:46:39 -04:00
javascript : LanguageWorkspaceSettings {
inlay_hints : InlayHintsSettings {
parameter_names : InlayHintsParamNamesOptions {
enabled : InlayHintsParamNamesEnabled ::None ,
suppress_when_argument_matches_name : true
} ,
parameter_types : InlayHintsParamTypesOptions { enabled : false } ,
variable_types : InlayHintsVarTypesOptions {
enabled : false ,
suppress_when_type_matches_name : true
} ,
property_declaration_types : InlayHintsPropDeclTypesOptions {
enabled : false
} ,
function_like_return_types : InlayHintsFuncLikeReturnTypesOptions {
enabled : false
} ,
enum_member_values : InlayHintsEnumMemberValuesOptions {
enabled : false
} ,
} ,
2023-09-25 22:54:07 -04:00
preferences : LanguagePreferences {
import_module_specifier : ImportModuleSpecifier ::Shortest ,
jsx_attribute_completion_style : JsxAttributeCompletionStyle ::Auto ,
auto_import_file_exclude_patterns : vec ! [ ] ,
use_aliases_for_renames : true ,
2023-10-16 21:51:42 -04:00
quote_style : QuoteStyle ::Auto ,
2023-09-25 22:54:07 -04:00
} ,
2023-09-21 01:46:39 -04:00
suggest : CompletionSettings {
complete_function_calls : false ,
2023-09-25 22:54:07 -04:00
include_automatic_optional_chain_completions : true ,
include_completions_for_import_statements : true ,
2023-09-21 01:46:39 -04:00
names : true ,
paths : true ,
auto_imports : true ,
2023-09-25 22:54:07 -04:00
enabled : true ,
class_member_snippets : ClassMemberSnippets { enabled : true } ,
object_literal_method_snippets : ObjectLiteralMethodSnippets {
enabled : true ,
} ,
2023-09-21 01:46:39 -04:00
} ,
2023-09-25 22:54:07 -04:00
update_imports_on_file_move : UpdateImportsOnFileMoveOptions {
enabled : UpdateImportsOnFileMoveEnabled ::Prompt
}
2023-09-21 01:46:39 -04:00
} ,
typescript : LanguageWorkspaceSettings {
inlay_hints : InlayHintsSettings {
parameter_names : InlayHintsParamNamesOptions {
enabled : InlayHintsParamNamesEnabled ::None ,
suppress_when_argument_matches_name : true
} ,
parameter_types : InlayHintsParamTypesOptions { enabled : false } ,
variable_types : InlayHintsVarTypesOptions {
enabled : false ,
suppress_when_type_matches_name : true
} ,
property_declaration_types : InlayHintsPropDeclTypesOptions {
enabled : false
} ,
function_like_return_types : InlayHintsFuncLikeReturnTypesOptions {
enabled : false
} ,
enum_member_values : InlayHintsEnumMemberValuesOptions {
enabled : false
} ,
} ,
2023-09-25 22:54:07 -04:00
preferences : LanguagePreferences {
import_module_specifier : ImportModuleSpecifier ::Shortest ,
jsx_attribute_completion_style : JsxAttributeCompletionStyle ::Auto ,
auto_import_file_exclude_patterns : vec ! [ ] ,
use_aliases_for_renames : true ,
2023-10-16 21:51:42 -04:00
quote_style : QuoteStyle ::Auto ,
2023-09-25 22:54:07 -04:00
} ,
2023-09-21 01:46:39 -04:00
suggest : CompletionSettings {
complete_function_calls : false ,
2023-09-25 22:54:07 -04:00
include_automatic_optional_chain_completions : true ,
include_completions_for_import_statements : true ,
2023-09-21 01:46:39 -04:00
names : true ,
paths : true ,
auto_imports : true ,
2023-09-25 22:54:07 -04:00
enabled : true ,
class_member_snippets : ClassMemberSnippets { enabled : true } ,
object_literal_method_snippets : ObjectLiteralMethodSnippets {
enabled : true ,
} ,
2023-09-21 01:46:39 -04:00
} ,
2023-09-25 22:54:07 -04:00
update_imports_on_file_move : UpdateImportsOnFileMoveOptions {
enabled : UpdateImportsOnFileMoveEnabled ::Prompt
}
2023-09-21 01:46:39 -04:00
} ,
2021-06-01 07:53:08 -04:00
}
) ;
}
2023-01-03 10:59:48 -05:00
#[ test ]
fn test_empty_cache ( ) {
let mut config = Config ::new ( ) ;
2023-09-21 01:46:39 -04:00
config . set_workspace_settings (
serde_json ::from_value ( json! ( { " cache " : " " } ) ) . unwrap ( ) ,
2023-10-24 16:27:27 -04:00
None ,
2023-09-21 01:46:39 -04:00
) ;
2023-01-03 10:59:48 -05:00
assert_eq! (
2023-05-11 17:17:14 -04:00
config . workspace_settings ( ) . clone ( ) ,
2023-01-03 10:59:48 -05:00
WorkspaceSettings ::default ( )
) ;
}
#[ test ]
fn test_empty_import_map ( ) {
let mut config = Config ::new ( ) ;
2023-09-21 01:46:39 -04:00
config . set_workspace_settings (
serde_json ::from_value ( json! ( { " import_map " : " " } ) ) . unwrap ( ) ,
2023-10-24 16:27:27 -04:00
None ,
2023-09-21 01:46:39 -04:00
) ;
2023-01-03 10:59:48 -05:00
assert_eq! (
2023-05-11 17:17:14 -04:00
config . workspace_settings ( ) . clone ( ) ,
2023-01-03 10:59:48 -05:00
WorkspaceSettings ::default ( )
) ;
}
#[ test ]
fn test_empty_tls_certificate ( ) {
let mut config = Config ::new ( ) ;
2023-09-21 01:46:39 -04:00
config . set_workspace_settings (
serde_json ::from_value ( json! ( { " tls_certificate " : " " } ) ) . unwrap ( ) ,
2023-10-24 16:27:27 -04:00
None ,
2023-09-21 01:46:39 -04:00
) ;
2023-01-03 10:59:48 -05:00
assert_eq! (
2023-05-11 17:17:14 -04:00
config . workspace_settings ( ) . clone ( ) ,
2023-01-03 10:59:48 -05:00
WorkspaceSettings ::default ( )
) ;
}
#[ test ]
fn test_empty_config ( ) {
let mut config = Config ::new ( ) ;
2023-09-21 01:46:39 -04:00
config . set_workspace_settings (
serde_json ::from_value ( json! ( { " config " : " " } ) ) . unwrap ( ) ,
2023-10-24 16:27:27 -04:00
None ,
2023-09-21 01:46:39 -04:00
) ;
2023-01-03 10:59:48 -05:00
assert_eq! (
2023-05-11 17:17:14 -04:00
config . workspace_settings ( ) . clone ( ) ,
2023-01-03 10:59:48 -05:00
WorkspaceSettings ::default ( )
) ;
}
2023-03-30 17:47:53 -04:00
#[ test ]
2023-09-18 15:58:16 -04:00
fn config_get_enabled_paths ( ) {
let mut config = Config ::new ( ) ;
2023-09-09 10:04:21 -04:00
config . workspace_folders = vec! [
2023-03-30 17:47:53 -04:00
(
2023-09-18 15:58:16 -04:00
Url ::parse ( " file:///root1/ " ) . unwrap ( ) ,
2023-09-09 10:04:21 -04:00
lsp ::WorkspaceFolder {
2023-09-18 15:58:16 -04:00
uri : Url ::parse ( " file:///root1/ " ) . unwrap ( ) ,
2023-09-09 10:04:21 -04:00
name : " 1 " . to_string ( ) ,
} ,
2023-03-30 17:47:53 -04:00
) ,
2023-09-09 10:04:21 -04:00
(
2023-09-18 15:58:16 -04:00
Url ::parse ( " file:///root2/ " ) . unwrap ( ) ,
2023-09-09 10:04:21 -04:00
lsp ::WorkspaceFolder {
2023-09-18 15:58:16 -04:00
uri : Url ::parse ( " file:///root2/ " ) . unwrap ( ) ,
2023-09-09 10:04:21 -04:00
name : " 2 " . to_string ( ) ,
} ,
) ,
(
2023-09-18 15:58:16 -04:00
Url ::parse ( " file:///root3/ " ) . unwrap ( ) ,
2023-09-09 10:04:21 -04:00
lsp ::WorkspaceFolder {
2023-09-18 15:58:16 -04:00
uri : Url ::parse ( " file:///root3/ " ) . unwrap ( ) ,
2023-09-09 10:04:21 -04:00
name : " 3 " . to_string ( ) ,
} ,
) ,
] ;
2023-10-24 16:27:27 -04:00
config . set_workspace_settings (
Default ::default ( ) ,
Some (
vec! [
(
Url ::parse ( " file:///root1/ " ) . unwrap ( ) ,
WorkspaceSettings {
enable_paths : Some ( vec! [
" sub_dir " . to_string ( ) ,
" sub_dir/other " . to_string ( ) ,
" test.ts " . to_string ( ) ,
] ) ,
.. Default ::default ( )
} ,
) ,
(
Url ::parse ( " file:///root2/ " ) . unwrap ( ) ,
WorkspaceSettings {
enable_paths : Some ( vec! [ " other.ts " . to_string ( ) ] ) ,
.. Default ::default ( )
} ,
) ,
(
Url ::parse ( " file:///root3/ " ) . unwrap ( ) ,
WorkspaceSettings {
enable : Some ( true ) ,
.. Default ::default ( )
} ,
) ,
]
. into_iter ( )
. collect ( ) ,
) ,
2023-09-09 10:04:21 -04:00
) ;
2023-03-30 17:47:53 -04:00
assert_eq! (
2023-09-18 15:58:16 -04:00
config . get_enabled_paths ( ) ,
2024-01-15 19:15:39 -05:00
PathOrPatternSet ::new ( vec! [
PathOrPattern ::Path ( PathBuf ::from ( " /root1/sub_dir " ) ) ,
PathOrPattern ::Path ( PathBuf ::from ( " /root1/sub_dir/other " ) ) ,
PathOrPattern ::Path ( PathBuf ::from ( " /root1/test.ts " ) ) ,
PathOrPattern ::Path ( PathBuf ::from ( " /root2/other.ts " ) ) ,
PathOrPattern ::Path ( PathBuf ::from ( " /root3/ " ) ) ,
] )
2023-03-30 17:47:53 -04:00
) ;
}
2023-09-01 16:13:13 -04:00
#[ test ]
fn config_enable_via_config_file_detection ( ) {
2023-09-09 10:04:21 -04:00
let root_uri = resolve_url ( " file:///root/ " ) . unwrap ( ) ;
let mut config = Config ::new_with_root ( root_uri . clone ( ) ) ;
2023-10-24 16:27:27 -04:00
config . settings . unscoped . enable = None ;
2023-09-18 15:58:16 -04:00
assert! ( ! config . specifier_enabled ( & root_uri ) ) ;
2023-09-01 16:13:13 -04:00
config . set_config_file (
ConfigFile ::new ( " {} " , root_uri . join ( " deno.json " ) . unwrap ( ) ) . unwrap ( ) ,
) ;
2023-09-18 15:58:16 -04:00
assert! ( config . specifier_enabled ( & root_uri ) ) ;
2023-09-01 16:13:13 -04:00
}
2023-09-09 14:37:01 -04:00
2023-09-12 09:36:50 -04:00
// Regression test for https://github.com/denoland/vscode_deno/issues/917.
#[ test ]
fn config_specifier_enabled_matches_by_path_component ( ) {
let root_uri = resolve_url ( " file:///root/ " ) . unwrap ( ) ;
let mut config = Config ::new_with_root ( root_uri . clone ( ) ) ;
2023-10-24 16:27:27 -04:00
config . settings . unscoped . enable_paths = Some ( vec! [ " mo " . to_string ( ) ] ) ;
2023-09-12 09:36:50 -04:00
assert! ( ! config . specifier_enabled ( & root_uri . join ( " mod.ts " ) . unwrap ( ) ) ) ;
}
2023-09-09 14:37:01 -04:00
#[ test ]
fn config_specifier_enabled_for_test ( ) {
let root_uri = resolve_url ( " file:///root/ " ) . unwrap ( ) ;
let mut config = Config ::new_with_root ( root_uri . clone ( ) ) ;
2023-10-24 16:27:27 -04:00
config . settings . unscoped . enable = Some ( true ) ;
2023-09-09 14:37:01 -04:00
2023-10-24 16:27:27 -04:00
config . settings . unscoped . enable_paths =
2023-09-13 12:30:27 -04:00
Some ( vec! [ " mod1.ts " . to_string ( ) , " mod2.ts " . to_string ( ) ] ) ;
2023-10-24 16:27:27 -04:00
config . settings . unscoped . disable_paths = vec! [ " mod2.ts " . to_string ( ) ] ;
2023-09-09 14:37:01 -04:00
assert! (
config . specifier_enabled_for_test ( & root_uri . join ( " mod1.ts " ) . unwrap ( ) )
) ;
assert! (
! config . specifier_enabled_for_test ( & root_uri . join ( " mod2.ts " ) . unwrap ( ) )
) ;
2023-09-13 12:30:27 -04:00
assert! (
! config . specifier_enabled_for_test ( & root_uri . join ( " mod3.ts " ) . unwrap ( ) )
) ;
2023-10-24 16:27:27 -04:00
config . settings . unscoped . enable_paths = None ;
2023-09-09 14:37:01 -04:00
config . set_config_file (
ConfigFile ::new (
& json! ( {
" exclude " : [ " mod2.ts " ] ,
" test " : {
" exclude " : [ " mod3.ts " ] ,
} ,
} )
. to_string ( ) ,
root_uri . join ( " deno.json " ) . unwrap ( ) ,
)
. unwrap ( ) ,
) ;
assert! (
config . specifier_enabled_for_test ( & root_uri . join ( " mod1.ts " ) . unwrap ( ) )
) ;
assert! (
! config . specifier_enabled_for_test ( & root_uri . join ( " mod2.ts " ) . unwrap ( ) )
) ;
assert! (
! config . specifier_enabled_for_test ( & root_uri . join ( " mod3.ts " ) . unwrap ( ) )
) ;
config . set_config_file (
ConfigFile ::new (
& json! ( {
" test " : {
" include " : [ " mod1.ts " ] ,
} ,
} )
. to_string ( ) ,
root_uri . join ( " deno.json " ) . unwrap ( ) ,
)
. unwrap ( ) ,
) ;
assert! (
config . specifier_enabled_for_test ( & root_uri . join ( " mod1.ts " ) . unwrap ( ) )
) ;
assert! (
! config . specifier_enabled_for_test ( & root_uri . join ( " mod2.ts " ) . unwrap ( ) )
) ;
config . set_config_file (
ConfigFile ::new (
& json! ( {
" test " : {
" exclude " : [ " mod2.ts " ] ,
" include " : [ " mod2.ts " ] ,
} ,
} )
. to_string ( ) ,
root_uri . join ( " deno.json " ) . unwrap ( ) ,
)
. unwrap ( ) ,
) ;
assert! (
! config . specifier_enabled_for_test ( & root_uri . join ( " mod1.ts " ) . unwrap ( ) )
) ;
assert! (
! config . specifier_enabled_for_test ( & root_uri . join ( " mod2.ts " ) . unwrap ( ) )
) ;
}
#[ test ]
fn config_snapshot_specifier_enabled_for_test ( ) {
let root_uri = resolve_url ( " file:///root/ " ) . unwrap ( ) ;
let mut config = Config ::new_with_root ( root_uri . clone ( ) ) ;
2023-10-24 16:27:27 -04:00
config . settings . unscoped . enable = Some ( true ) ;
2023-09-09 14:37:01 -04:00
config . set_config_file (
ConfigFile ::new (
& json! ( {
" exclude " : [ " mod2.ts " ] ,
" test " : {
" exclude " : [ " mod3.ts " ] ,
} ,
} )
. to_string ( ) ,
root_uri . join ( " deno.json " ) . unwrap ( ) ,
)
. unwrap ( ) ,
) ;
let config_snapshot = config . snapshot ( ) ;
assert! ( config_snapshot
. specifier_enabled_for_test ( & root_uri . join ( " mod1.ts " ) . unwrap ( ) ) ) ;
assert! ( ! config_snapshot
. specifier_enabled_for_test ( & root_uri . join ( " mod2.ts " ) . unwrap ( ) ) ) ;
assert! ( ! config_snapshot
. specifier_enabled_for_test ( & root_uri . join ( " mod3.ts " ) . unwrap ( ) ) ) ;
}
2020-12-07 05:46:39 -05:00
}