Skip to main content

DevelopmentNodeEnvironment_MicrosoftVSCodeDependency_22NodeVersion_Bundle_Clean_Debug_ElectronProfile_EsbuildCompiler_Mountain/Environment/ConfigurationProvider/
GetValue.rs

1//! Configuration value retrieval.
2//!
3//! Implements `GetConfigurationValue` for `MountainEnvironment`. Reads
4//! from the pre-merged `ApplicationState::Configuration::GlobalConfiguration`
5//! cache - no disk I/O on the hot path.
6//!
7//! If `section` is `None`, the entire merged object is returned. If it
8//! is `Some("a.b.c")`, the key is split on `.` and the function walks
9//! the nested JSON tree one segment at a time, returning `Value::Null`
10//! (not an error) for any missing intermediate or leaf node. This
11//! matches VS Code's behaviour where `getConfiguration('a.b').get('c')`
12//! returns `undefined` rather than throwing.
13
14use CommonLibrary::{
15	Configuration::DTO::ConfigurationOverridesDTO::ConfigurationOverridesDTO,
16	Error::CommonError::CommonError,
17};
18use serde_json::Value;
19
20use crate::dev_log;
21
22/// Retrieves a configuration value from the cached, merged configuration.
23/// When `overrides.OverrideIdentifier` is set, language-scoped values
24/// from `[<language>]` blocks in settings.json take precedence over base
25/// values.
26pub(super) async fn get_configuration_value(
27	environment:&crate::Environment::MountainEnvironment::MountainEnvironment,
28
29	section:Option<String>,
30
31	overrides:ConfigurationOverridesDTO,
32) -> Result<Value, CommonError> {
33	dev_log!(
34		"config",
35		"[ConfigurationProvider] Getting configuration for section: {:?} (language: {:?})",
36		section,
37		overrides.OverrideIdentifier
38	);
39
40	let configuration_guard = environment
41		.ApplicationState
42		.Configuration
43		.GlobalConfiguration
44		.lock()
45		.map_err(|e| CommonError::StateLockPoisoned { Context:format!("Failed to lock configuration: {}", e) })?;
46
47	// Base value from merged config.
48	let base_value = match section.as_deref() {
49		None => (*configuration_guard).clone(),
50
51		Some(section_path) => {
52			let mut current = &*configuration_guard;
53
54			for key in section_path.split('.') {
55				current = match current.get(key) {
56					Some(value) => value,
57
58					None => {
59						dev_log!(
60							"config",
61							"warn: [ConfigurationProvider] Configuration section '{}' not found in path: {:?}",
62							key,
63							section_path
64						);
65
66						return Ok(Value::Null);
67					},
68				};
69			}
70
71			current.clone()
72		},
73	};
74
75	// If a language override is requested, check for `[<language>]` blocks in
76	// the merged config and overlay any matching keys on top of the base value.
77	// VS Code uses `[rust]`, `[typescript]`, etc. as top-level keys.
78	let configuration_value = if let Some(ref lang_id) = overrides.OverrideIdentifier {
79		let lang = lang_id.as_str();
80
81		let lang_block_key = format!("[{}]", lang);
82
83		if let Some(lang_block) = configuration_guard.get(&lang_block_key).and_then(|v| v.as_object()) {
84			match section.as_deref() {
85				None => {
86					// Return the whole merged config with language block applied.
87					let mut merged = if let Some(obj) = base_value.as_object() {
88						obj.clone()
89					} else {
90						return Ok(base_value);
91					};
92
93					for (k, v) in lang_block {
94						merged.insert(k.clone(), v.clone());
95					}
96
97					Value::Object(merged)
98				},
99
100				Some(section_path) => {
101					// Check if the language block overrides this specific section key.
102					let top_key = section_path.split('.').next().unwrap_or(section_path);
103
104					if let Some(lang_value) = lang_block.get(top_key) {
105						let remainder:Vec<&str> = section_path.splitn(2, '.').skip(1).collect();
106
107						if remainder.is_empty() {
108							lang_value.clone()
109						} else {
110							let mut cur = lang_value;
111
112							for k in remainder[0].split('.') {
113								match cur.get(k) {
114									Some(v) => cur = v,
115
116									None => return Ok(base_value),
117								}
118							}
119
120							cur.clone()
121						}
122					} else {
123						base_value
124					}
125				},
126			}
127		} else {
128			base_value
129		}
130	} else {
131		base_value
132	};
133
134	// Validate that the configuration value exists
135	if configuration_value.is_null() {
136		dev_log!(
137			"config",
138			"warn: [ConfigurationProvider] Configuration section not found: {:?}",
139			section
140		);
141	}
142
143	Ok(configuration_value)
144}