Skip to main content

Mountain/Environment/Utility/
UriParsing.rs

1//! # URI Parsing Utilities
2//!
3//! Functions for parsing and converting URI/URL representations.
4
5use url::Url;
6use CommonLibrary::Error::CommonError::CommonError;
7
8/// Helper to get a `Url` from a `serde_json::Value` which is expected to be a
9/// `UriComponents` DTO from VS Code, a plain URI string, or a UriComponents
10/// object without the `external` convenience field.
11///
12/// Cocoon's wire shapes vary by call site:
13///   - `Diagnostic.Set` and a few others send the URI as a plain string (the
14///     canonical form returned by `Uri.toString()`).
15///   - `MainThread*` boundaries send the `{scheme, authority, path, query,
16///     fragment, external}` object that vs/base/common/uri.ts emits via
17///     `URI.toJSON()`.
18///   - Some legacy paths send `{scheme, path}` with no `external`.
19///
20/// All three are valid; Mountain accepts whichever arrives. Without this the
21/// Diagnostic.Set call from `vscode.languages.createDiagnosticCollection().set`
22/// trips the breaker after 5 publishes and silences every linter / compiler
23/// across all language extensions.
24pub fn GetURLFromURIComponentsDTO(URIDTO:&serde_json::Value) -> Result<Url, CommonError> {
25	// 1. Plain string: parse directly.
26	if let Some(URIString) = URIDTO.as_str() {
27		return Url::parse(URIString).map_err(|Error| {
28			CommonError::InvalidArgument {
29				ArgumentName:"URIDTO".to_string(),
30				Reason:format!("Failed to parse URI string '{}': {}", URIString, Error),
31			}
32		});
33	}
34
35	// 2. Object with `external` field (VS Code's UriComponents).
36	if let Some(URIString) = URIDTO.get("external").and_then(serde_json::Value::as_str) {
37		return Url::parse(URIString).map_err(|Error| {
38			CommonError::InvalidArgument {
39				ArgumentName:"URIDTO.external".to_string(),
40				Reason:format!("Failed to parse URI string '{}': {}", URIString, Error),
41			}
42		});
43	}
44
45	// 3. Object with scheme/authority/path - reconstruct the URI string.
46	let Scheme = URIDTO.get("scheme").and_then(serde_json::Value::as_str);
47	let Path = URIDTO.get("path").and_then(serde_json::Value::as_str);
48	if let (Some(Scheme), Some(Path)) = (Scheme, Path) {
49		let Authority = URIDTO.get("authority").and_then(serde_json::Value::as_str).unwrap_or("");
50		let Query = URIDTO.get("query").and_then(serde_json::Value::as_str).unwrap_or("");
51		let Fragment = URIDTO.get("fragment").and_then(serde_json::Value::as_str).unwrap_or("");
52		let mut Reconstructed = format!("{}://{}{}", Scheme, Authority, Path);
53		if !Query.is_empty() {
54			Reconstructed.push('?');
55			Reconstructed.push_str(Query);
56		}
57		if !Fragment.is_empty() {
58			Reconstructed.push('#');
59			Reconstructed.push_str(Fragment);
60		}
61		return Url::parse(&Reconstructed).map_err(|Error| {
62			CommonError::InvalidArgument {
63				ArgumentName:"URIDTO".to_string(),
64				Reason:format!("Failed to parse reconstructed URI '{}': {}", Reconstructed, Error),
65			}
66		});
67	}
68
69	Err(CommonError::InvalidArgument {
70		ArgumentName:"URIDTO".to_string(),
71		Reason:"Expected a URI string, an object with 'external', or an object with 'scheme' + 'path'".to_string(),
72	})
73}