1use super::*;
2use omena_cascade::{
3 DomClassTokenizationV0, OrderedTokenWordV0, TokenSupportV0, tokenize_dom_class_attribute_v0,
4};
5use omena_query_core::{
6 AbstractClassValueV0, ClassBoundaryEffectV0, ExternalStringTypeFactsV0, FirstWitnessErrorV0,
7 GuardAtomV0, GuardedTokenInputV0, GuardedTokenLanguageV0, GuardedTokenMapInputV0,
8 GuardedTokenMapV0, StringTypeFactsV2, TokenObserverProjectionV0,
9 abstract_class_value_from_facts, abstract_class_value_kind, join_abstract_class_values,
10 top_class_value,
11};
12use omena_syntax::ident::CanonicalClassKeyV0;
13use serde::{Deserialize, Serialize, Serializer};
14use std::collections::{BTreeMap, BTreeSet, VecDeque};
15
16pub type OmenaQueryTsconfigPathMappingV0 = omena_resolver::OmenaResolverTsconfigPathMappingV0;
17pub type OmenaQueryBundlerPathAliasMappingV0 =
18 omena_resolver::OmenaResolverBundlerPathAliasMappingV0;
19pub type OmenaQueryStyleModuleDiskCandidateIdentityV0 =
20 omena_resolver::OmenaResolverStyleModuleDiskCandidateIdentityV0;
21
22#[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, Serialize)]
23#[serde(default, rename_all = "camelCase")]
24pub struct OmenaQueryStyleResolutionInputsV0 {
25 pub package_manifests: Vec<OmenaQueryStylePackageManifestV0>,
26 pub tsconfig_path_mappings: Vec<OmenaQueryTsconfigPathMappingV0>,
27 pub bundler_path_mappings: Vec<OmenaQueryBundlerPathAliasMappingV0>,
28 #[serde(skip_serializing_if = "Vec::is_empty")]
29 pub disk_style_path_identities: Vec<OmenaQueryStyleModuleDiskCandidateIdentityV0>,
30 #[serde(skip_serializing_if = "Option::is_none")]
31 pub external_sif_cache_fingerprint: Option<String>,
32}
33
34pub fn summarize_omena_query_source_import_declarations(
35 source: &str,
36) -> OmenaQuerySourceImportDeclarationSummaryV0 {
37 omena_bridge::summarize_omena_bridge_source_import_declarations(source)
38}
39
40pub fn summarize_omena_query_source_import_declarations_for_source_language(
41 source_path: &str,
42 source: &str,
43 source_language: Option<&str>,
44) -> OmenaQuerySourceImportDeclarationSummaryV0 {
45 omena_bridge::summarize_omena_bridge_source_import_declarations_for_source_language(
46 source_path,
47 source,
48 source_language,
49 )
50}
51
52pub fn resolve_omena_query_style_uri_for_specifier(
53 base_document_uri: &str,
54 workspace_folder_uri: Option<&str>,
55 specifier: &str,
56) -> Option<String> {
57 omena_bridge::resolve_omena_bridge_style_uri_for_specifier(
58 base_document_uri,
59 workspace_folder_uri,
60 specifier,
61 )
62}
63
64pub fn resolve_omena_query_style_uri_for_specifier_with_package_manifests(
65 base_document_uri: &str,
66 workspace_folder_uri: Option<&str>,
67 specifier: &str,
68 package_manifests: &[OmenaQueryStylePackageManifestV0],
69) -> Option<String> {
70 let resolver_package_manifests = package_manifests
71 .iter()
72 .map(|manifest| OmenaResolverStylePackageManifestV0 {
73 package_json_path: manifest.package_json_path.clone(),
74 package_json_source: manifest.package_json_source.clone(),
75 })
76 .collect::<Vec<_>>();
77 omena_bridge::resolve_omena_bridge_style_uri_for_specifier_with_package_manifests(
78 base_document_uri,
79 workspace_folder_uri,
80 specifier,
81 resolver_package_manifests.as_slice(),
82 )
83}
84
85pub fn resolve_omena_query_style_uri_for_specifier_with_resolution_inputs(
86 base_document_uri: &str,
87 workspace_folder_uri: Option<&str>,
88 specifier: &str,
89 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
90) -> Option<String> {
91 let bridge_inputs = omena_bridge::OmenaBridgeStyleResolutionInputsV0 {
92 package_manifests: resolution_inputs
93 .package_manifests
94 .iter()
95 .map(|manifest| OmenaResolverStylePackageManifestV0 {
96 package_json_path: manifest.package_json_path.clone(),
97 package_json_source: manifest.package_json_source.clone(),
98 })
99 .collect(),
100 tsconfig_path_mappings: resolution_inputs.tsconfig_path_mappings.clone(),
101 bundler_path_mappings: resolution_inputs.bundler_path_mappings.clone(),
102 disk_style_path_identities: resolution_inputs.disk_style_path_identities.clone(),
103 };
104 omena_bridge::resolve_omena_bridge_style_uri_for_specifier_with_resolution_inputs(
105 base_document_uri,
106 workspace_folder_uri,
107 specifier,
108 &bridge_inputs,
109 )
110}
111
112pub fn load_omena_query_workspace_style_resolution_inputs(
113 workspace_folder_uri: Option<&str>,
114 configured_package_manifests: &[OmenaQueryStylePackageManifestV0],
115) -> OmenaQueryStyleResolutionInputsV0 {
116 let resolver_package_manifests = configured_package_manifests
117 .iter()
118 .map(|manifest| OmenaResolverStylePackageManifestV0 {
119 package_json_path: manifest.package_json_path.clone(),
120 package_json_source: manifest.package_json_source.clone(),
121 })
122 .collect::<Vec<_>>();
123 let bridge_inputs = omena_bridge::load_omena_bridge_workspace_style_resolution_inputs(
124 workspace_folder_uri,
125 resolver_package_manifests.as_slice(),
126 );
127 OmenaQueryStyleResolutionInputsV0 {
128 package_manifests: bridge_inputs
129 .package_manifests
130 .into_iter()
131 .map(|manifest| OmenaQueryStylePackageManifestV0 {
132 package_json_path: manifest.package_json_path,
133 package_json_source: manifest.package_json_source,
134 })
135 .collect(),
136 tsconfig_path_mappings: bridge_inputs.tsconfig_path_mappings,
137 bundler_path_mappings: bridge_inputs.bundler_path_mappings,
138 disk_style_path_identities: bridge_inputs.disk_style_path_identities,
139 external_sif_cache_fingerprint: None,
140 }
141}
142
143#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
144#[serde(rename_all = "camelCase")]
145pub struct OmenaQueryBridgeExternalSifResolutionV0 {
146 pub external_sifs: Vec<OmenaQueryExternalSifInputV0>,
147 pub bridge_urls: Vec<String>,
148 pub generation_count: usize,
149}
150
151#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
152#[serde(rename_all = "camelCase")]
153pub enum OmenaQueryExternalSifTrustSourceV1 {
154 RecordedVerdict,
155 UnsignedLegacy,
156}
157
158#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
159#[serde(rename_all = "camelCase")]
160pub struct OmenaQueryExternalSifTrustV1 {
161 pub canonical_url: String,
162 pub trust_tier: omena_sif::OmenaSifTrustTierV1,
163 pub trust_source: OmenaQueryExternalSifTrustSourceV1,
164}
165
166#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
167#[serde(rename_all = "camelCase")]
168pub struct OmenaQueryBridgeExternalSifTrustedResolutionV1 {
169 pub resolution: OmenaQueryBridgeExternalSifResolutionV0,
170 pub trust_records: Vec<OmenaQueryExternalSifTrustV1>,
171}
172
173pub fn resolve_omena_query_bridge_external_sifs_for_style_sources(
174 style_sources: &[OmenaQueryStyleSourceInputV0],
175 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
176 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
177) -> OmenaQueryBridgeExternalSifResolutionV0 {
178 resolve_omena_query_bridge_external_sifs_for_style_sources_with_trust(
179 style_sources,
180 existing_external_sifs,
181 resolution_inputs,
182 )
183 .resolution
184}
185
186pub fn resolve_omena_query_bridge_external_sifs_for_style_sources_with_trust(
187 style_sources: &[OmenaQueryStyleSourceInputV0],
188 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
189 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
190) -> OmenaQueryBridgeExternalSifTrustedResolutionV1 {
191 resolve_omena_query_bridge_external_sifs_for_style_sources_with_optional_cache_storage(
192 style_sources,
193 existing_external_sifs,
194 resolution_inputs,
195 None,
196 )
197}
198
199pub fn resolve_omena_query_bridge_external_sifs_for_style_sources_with_cache_storage(
200 style_sources: &[OmenaQueryStyleSourceInputV0],
201 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
202 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
203 cache_storage: &omena_bridge::OmenaBridgeExternalSifStorageV0,
204) -> OmenaQueryBridgeExternalSifResolutionV0 {
205 resolve_omena_query_bridge_external_sifs_for_style_sources_with_cache_storage_and_trust(
206 style_sources,
207 existing_external_sifs,
208 resolution_inputs,
209 cache_storage,
210 )
211 .resolution
212}
213
214pub fn resolve_omena_query_bridge_external_sifs_for_style_sources_with_cache_storage_and_trust(
215 style_sources: &[OmenaQueryStyleSourceInputV0],
216 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
217 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
218 cache_storage: &omena_bridge::OmenaBridgeExternalSifStorageV0,
219) -> OmenaQueryBridgeExternalSifTrustedResolutionV1 {
220 resolve_omena_query_bridge_external_sifs_for_style_sources_with_optional_cache_storage(
221 style_sources,
222 existing_external_sifs,
223 resolution_inputs,
224 Some(cache_storage),
225 )
226}
227
228fn resolve_omena_query_bridge_external_sifs_for_style_sources_with_optional_cache_storage(
229 style_sources: &[OmenaQueryStyleSourceInputV0],
230 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
231 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
232 cache_storage: Option<&omena_bridge::OmenaBridgeExternalSifStorageV0>,
233) -> OmenaQueryBridgeExternalSifTrustedResolutionV1 {
234 let seeds = style_sources
235 .iter()
236 .flat_map(|source| bridge_external_sif_seeds_for_style_source(source, resolution_inputs))
237 .collect::<BTreeSet<_>>();
238 resolve_omena_query_bridge_external_sifs_for_seed_pairs_with_optional_cache_storage(
239 seeds.into_iter(),
240 existing_external_sifs,
241 resolution_inputs,
242 cache_storage,
243 )
244}
245
246pub fn resolve_omena_query_bridge_external_sifs_for_seed_pairs(
247 seeds: impl Iterator<Item = (String, String)>,
248 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
249 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
250) -> OmenaQueryBridgeExternalSifResolutionV0 {
251 resolve_omena_query_bridge_external_sifs_for_seed_pairs_with_trust(
252 seeds,
253 existing_external_sifs,
254 resolution_inputs,
255 )
256 .resolution
257}
258
259pub fn resolve_omena_query_bridge_external_sifs_for_seed_pairs_with_trust(
260 seeds: impl Iterator<Item = (String, String)>,
261 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
262 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
263) -> OmenaQueryBridgeExternalSifTrustedResolutionV1 {
264 resolve_omena_query_bridge_external_sifs_for_seed_pairs_with_optional_cache_storage(
265 seeds,
266 existing_external_sifs,
267 resolution_inputs,
268 None,
269 )
270}
271
272pub fn resolve_omena_query_bridge_external_sifs_for_seed_pairs_with_cache_storage(
273 seeds: impl Iterator<Item = (String, String)>,
274 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
275 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
276 cache_storage: &omena_bridge::OmenaBridgeExternalSifStorageV0,
277) -> OmenaQueryBridgeExternalSifResolutionV0 {
278 resolve_omena_query_bridge_external_sifs_for_seed_pairs_with_cache_storage_and_trust(
279 seeds,
280 existing_external_sifs,
281 resolution_inputs,
282 cache_storage,
283 )
284 .resolution
285}
286
287pub fn resolve_omena_query_bridge_external_sifs_for_seed_pairs_with_cache_storage_and_trust(
288 seeds: impl Iterator<Item = (String, String)>,
289 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
290 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
291 cache_storage: &omena_bridge::OmenaBridgeExternalSifStorageV0,
292) -> OmenaQueryBridgeExternalSifTrustedResolutionV1 {
293 resolve_omena_query_bridge_external_sifs_for_seed_pairs_with_optional_cache_storage(
294 seeds,
295 existing_external_sifs,
296 resolution_inputs,
297 Some(cache_storage),
298 )
299}
300
301fn resolve_omena_query_bridge_external_sifs_for_seed_pairs_with_optional_cache_storage(
302 seeds: impl Iterator<Item = (String, String)>,
303 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
304 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
305 cache_storage: Option<&omena_bridge::OmenaBridgeExternalSifStorageV0>,
306) -> OmenaQueryBridgeExternalSifTrustedResolutionV1 {
307 let mut state = BridgeExternalSifResolutionState::new(
308 existing_external_sifs,
309 resolution_inputs,
310 cache_storage,
311 );
312
313 for (verbatim_source, resolved_url) in seeds {
314 state.enqueue_alias(verbatim_source, resolved_url);
315 }
316
317 while let Some(sif) = state.worklist.pop_front() {
318 let base_file_uri = sif.canonical_url.clone();
319 for forward in &sif.exports.forwards {
320 let specifier = forward.canonical_url.as_str();
321 if !bridge_external_sif_specifier_is_readable(specifier) {
322 continue;
323 }
324 let Some(child_url) =
325 resolve_omena_query_style_uri_for_specifier_with_resolution_inputs(
326 base_file_uri.as_str(),
327 None,
328 specifier,
329 state.resolution_inputs,
330 )
331 .filter(|uri| uri.starts_with("file://"))
332 else {
333 continue;
334 };
335 let alias_key = if specifier.starts_with('.') || specifier.starts_with("file://") {
336 child_url.clone()
337 } else {
338 specifier.to_string()
339 };
340 state.enqueue_alias(alias_key, child_url);
341 }
342 }
343
344 state.into_resolution()
345}
346
347struct BridgeExternalSifResolutionState<'a> {
348 resolution_inputs: &'a OmenaQueryStyleResolutionInputsV0,
349 cache_storage: Option<&'a omena_bridge::OmenaBridgeExternalSifStorageV0>,
350 emitted_keys: BTreeSet<String>,
351 generated_by_resolved_url: BTreeMap<String, omena_sif::OmenaSifV1>,
352 bridge_urls: BTreeSet<String>,
353 external_sifs: Vec<OmenaQueryExternalSifInputV0>,
354 trust_records: BTreeMap<String, OmenaQueryExternalSifTrustV1>,
355 worklist: VecDeque<omena_sif::OmenaSifV1>,
356 generation_count: usize,
357}
358
359impl<'a> BridgeExternalSifResolutionState<'a> {
360 fn new(
361 existing_external_sifs: &[OmenaQueryExternalSifInputV0],
362 resolution_inputs: &'a OmenaQueryStyleResolutionInputsV0,
363 cache_storage: Option<&'a omena_bridge::OmenaBridgeExternalSifStorageV0>,
364 ) -> Self {
365 Self {
366 resolution_inputs,
367 cache_storage,
368 emitted_keys: existing_external_sifs
369 .iter()
370 .flat_map(|input| [input.canonical_url.clone(), input.sif.canonical_url.clone()])
371 .collect(),
372 generated_by_resolved_url: existing_external_sifs
373 .iter()
374 .map(|input| (input.sif.canonical_url.clone(), input.sif.clone()))
375 .collect(),
376 bridge_urls: BTreeSet::new(),
377 external_sifs: Vec::new(),
378 trust_records: BTreeMap::new(),
379 worklist: VecDeque::new(),
380 generation_count: 0,
381 }
382 }
383
384 fn into_resolution(self) -> OmenaQueryBridgeExternalSifTrustedResolutionV1 {
385 OmenaQueryBridgeExternalSifTrustedResolutionV1 {
386 resolution: OmenaQueryBridgeExternalSifResolutionV0 {
387 external_sifs: self.external_sifs,
388 bridge_urls: self.bridge_urls.into_iter().collect(),
389 generation_count: self.generation_count,
390 },
391 trust_records: self.trust_records.into_values().collect(),
392 }
393 }
394
395 fn enqueue_alias(&mut self, alias_key: String, resolved_url: String) {
396 if self.emitted_keys.contains(alias_key.as_str()) {
397 return;
398 }
399 self.bridge_urls.insert(alias_key.clone());
400 self.bridge_urls.insert(resolved_url.clone());
401 if let Some(sif) = self
402 .generated_by_resolved_url
403 .get(resolved_url.as_str())
404 .cloned()
405 {
406 self.emitted_keys.insert(alias_key.clone());
407 self.emitted_keys.insert(sif.canonical_url.clone());
408 self.external_sifs.push(OmenaQueryExternalSifInputV0 {
409 canonical_url: alias_key,
410 sif,
411 });
412 return;
413 }
414 let cache_context = omena_bridge::OmenaBridgeExternalSifCacheContextV0 {
415 freshness_fingerprint: self
416 .resolution_inputs
417 .external_sif_cache_fingerprint
418 .clone(),
419 };
420 let result = if alias_key.starts_with("pkg:") {
421 omena_bridge::generate_omena_bridge_sif_for_resolved_style_path_with_canonical_url_cache_context_storage_and_trust(
422 resolved_url.as_str(),
423 alias_key.as_str(),
424 &cache_context,
425 self.cache_storage,
426 )
427 } else {
428 omena_bridge::generate_omena_bridge_sif_for_resolved_style_path_with_cache_context_storage_and_trust(
429 resolved_url.as_str(),
430 &cache_context,
431 self.cache_storage,
432 )
433 };
434 let Ok(result) = result else {
435 return;
436 };
437 let sif = result.sif;
438 let trust_source = match result.trust_source {
439 omena_bridge::OmenaBridgeExternalSifTrustSourceV1::RecordedVerdict => {
440 OmenaQueryExternalSifTrustSourceV1::RecordedVerdict
441 }
442 omena_bridge::OmenaBridgeExternalSifTrustSourceV1::UnsignedLegacy => {
443 OmenaQueryExternalSifTrustSourceV1::UnsignedLegacy
444 }
445 };
446 self.trust_records.insert(
447 sif.canonical_url.clone(),
448 OmenaQueryExternalSifTrustV1 {
449 canonical_url: sif.canonical_url.clone(),
450 trust_tier: result.trust_envelope.trust_tier,
451 trust_source,
452 },
453 );
454 self.generation_count = self.generation_count.saturating_add(1);
455 self.generated_by_resolved_url
456 .insert(sif.canonical_url.clone(), sif.clone());
457 self.emitted_keys.insert(alias_key.clone());
458 self.emitted_keys.insert(sif.canonical_url.clone());
459 self.bridge_urls.insert(sif.canonical_url.clone());
460 self.worklist.push_back(sif.clone());
461 self.external_sifs.push(OmenaQueryExternalSifInputV0 {
462 canonical_url: alias_key,
463 sif,
464 });
465 }
466}
467
468fn bridge_external_sif_seeds_for_style_source(
469 source: &OmenaQueryStyleSourceInputV0,
470 resolution_inputs: &OmenaQueryStyleResolutionInputsV0,
471) -> Vec<(String, String)> {
472 let Some(module_sources) =
473 summarize_omena_query_sass_module_sources(&source.style_path, &source.style_source)
474 else {
475 return Vec::new();
476 };
477 let base_uri = style_source_path_as_file_uri(source.style_path.as_str());
478 module_sources
479 .module_use_edges
480 .iter()
481 .map(|edge| edge.source.as_str())
482 .chain(
483 module_sources
484 .module_forward_sources
485 .iter()
486 .map(String::as_str),
487 )
488 .filter_map(|specifier| {
489 if !bridge_external_sif_specifier_is_readable(specifier) {
490 return None;
491 }
492 let resolved_url = if specifier.starts_with("file://") {
493 specifier.to_string()
494 } else {
495 resolve_omena_query_style_uri_for_specifier_with_resolution_inputs(
496 base_uri.as_str(),
497 None,
498 specifier,
499 resolution_inputs,
500 )?
501 };
502 resolved_url
503 .starts_with("file://")
504 .then(|| (specifier.to_string(), resolved_url))
505 })
506 .collect()
507}
508
509fn bridge_external_sif_specifier_is_readable(specifier: &str) -> bool {
510 !specifier.starts_with("sass:")
511 && !specifier.starts_with("http://")
512 && !specifier.starts_with("https://")
513}
514
515fn style_source_path_as_file_uri(path: &str) -> String {
516 if path.starts_with("file://") {
517 path.to_string()
518 } else {
519 format!("file://{path}")
520 }
521}
522
523pub fn summarize_omena_query_source_syntax_index(
524 source: &str,
525 style_import_resolutions: Vec<OmenaQuerySourceStyleImportResolutionV0>,
526) -> OmenaQuerySourceSyntaxIndexV0 {
527 omena_bridge::summarize_omena_bridge_source_syntax_index(source, style_import_resolutions)
528}
529
530pub fn summarize_omena_query_source_syntax_index_with_type_fact_attempts(
531 source: &str,
532 style_import_resolutions: Vec<OmenaQuerySourceStyleImportResolutionV0>,
533) -> OmenaQuerySourceSyntaxIndexWithTypeFactAttemptsV0 {
534 omena_bridge::summarize_omena_bridge_source_syntax_index_with_type_fact_attempts(
535 source,
536 style_import_resolutions,
537 )
538}
539
540pub fn summarize_omena_query_source_syntax_index_for_source_language(
541 source_path: &str,
542 source: &str,
543 source_language: Option<&str>,
544 style_import_resolutions: Vec<OmenaQuerySourceStyleImportResolutionV0>,
545) -> OmenaQuerySourceSyntaxIndexV0 {
546 omena_bridge::summarize_omena_bridge_source_syntax_index_for_source_language(
547 source_path,
548 source,
549 source_language,
550 style_import_resolutions,
551 )
552}
553
554pub fn summarize_omena_query_source_syntax_index_for_source_language_with_type_fact_attempts(
555 source_path: &str,
556 source: &str,
557 source_language: Option<&str>,
558 style_import_resolutions: Vec<OmenaQuerySourceStyleImportResolutionV0>,
559) -> OmenaQuerySourceSyntaxIndexWithTypeFactAttemptsV0 {
560 omena_bridge::summarize_omena_bridge_source_syntax_index_for_source_language_with_type_fact_attempts(
561 source_path,
562 source,
563 source_language,
564 style_import_resolutions,
565 )
566}
567
568pub fn summarize_omena_query_source_binding_index(
569 source: &str,
570 style_import_resolutions: Vec<OmenaQuerySourceStyleImportResolutionV0>,
571) -> OmenaQuerySourceBindingIndexV0 {
572 omena_bridge::summarize_omena_bridge_source_binding_index(source, style_import_resolutions)
573}
574
575pub fn summarize_omena_query_source_binding_index_for_source_language(
576 source_path: &str,
577 source: &str,
578 source_language: Option<&str>,
579 style_import_resolutions: Vec<OmenaQuerySourceStyleImportResolutionV0>,
580) -> OmenaQuerySourceBindingIndexV0 {
581 omena_bridge::summarize_omena_bridge_source_binding_index_for_source_language(
582 source_path,
583 source,
584 source_language,
585 style_import_resolutions,
586 )
587}
588
589pub fn summarize_omena_query_source_control_flow_graph_for_source_language(
590 source_path: &str,
591 source: &str,
592 source_language: Option<&str>,
593 variable_name: &str,
594 reference_byte_offset: usize,
595) -> Option<crate::OmenaQuerySourceControlFlowGraphCaptureV0> {
596 omena_bridge::summarize_omena_bridge_source_control_flow_graph_for_source_language(
597 source_path,
598 source,
599 source_language,
600 variable_name,
601 reference_byte_offset,
602 )
603}
604
605#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
606#[serde(rename_all = "camelCase")]
607pub struct OmenaQuerySourcePrecisionReferenceV0 {
608 pub schema_version: &'static str,
609 pub product: &'static str,
610 pub source_path: String,
611 #[serde(skip_serializing_if = "Option::is_none")]
612 pub source_language: Option<String>,
613 pub variable_name: String,
614 pub reference_byte_offset: usize,
615 pub resolved_tier: &'static str,
616 pub resolved_value: AbstractClassValueV0,
617 pub precision: OmenaQueryAnalysisPrecisionV0,
618 #[serde(skip_serializing_if = "Option::is_none")]
619 pub top_cause: Option<&'static str>,
620}
621
622pub fn resolve_omena_query_source_precision_for_source(
623 source_path: &str,
624 source: &str,
625 source_language: Option<&str>,
626 variable_name: &str,
627 reference_byte_offset: usize,
628) -> OmenaQuerySourcePrecisionReferenceV0 {
629 let precision =
630 source_diagnostic_precision("classValueResolution", "sourceControlFlow", "sameFile");
631 let Some(capture) = summarize_omena_query_source_control_flow_graph_for_source_language(
632 source_path,
633 source,
634 source_language,
635 variable_name,
636 reference_byte_offset,
637 ) else {
638 return source_precision_reference(
639 source_path,
640 source_language,
641 variable_name,
642 reference_byte_offset,
643 top_class_value(),
644 precision,
645 Some("noFlowCapture"),
646 );
647 };
648
649 let resolved_flow = resolve_source_precision_flow_from_snapshot(
650 &capture.snapshot,
651 capture.binding.symbol_ordinal,
652 )
653 .unwrap_or(ResolvedSourcePrecisionFlowV0 {
654 value: top_class_value(),
655 top_cause: Some("ambiguousFlowSnapshot"),
656 });
657 let top_cause = if abstract_class_value_kind(&resolved_flow.value) == "top" {
658 resolved_flow.top_cause
659 } else {
660 None
661 };
662
663 source_precision_reference(
664 source_path,
665 source_language,
666 variable_name,
667 reference_byte_offset,
668 resolved_flow.value,
669 precision,
670 top_cause,
671 )
672}
673
674#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)]
675#[serde(rename_all = "camelCase")]
676pub enum OmenaQueryClassSitePlaneV0 {
677 Cfg,
678 TypeFact,
679 Joined,
680}
681
682#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
683#[serde(rename_all = "camelCase")]
684pub enum OmenaQueryClassSiteUnknownCauseV0 {
685 SiteNotEnumerated,
686 SourceValueUnavailable,
687 NonFiniteRawLanguage,
688 TypeFactNotProvided,
689 TypeFactRefused,
690}
691
692#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
693#[serde(rename_all = "camelCase")]
694pub struct OmenaQueryClassSiteTypeFactInputV0 {
695 pub site_byte_span: ParserByteSpanV0,
696 #[serde(skip_serializing_if = "Option::is_none")]
697 pub facts: Option<StringTypeFactsV2>,
698 #[serde(skip_serializing_if = "Option::is_none")]
699 pub refusal_cause: Option<String>,
700}
701
702#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
703#[serde(rename_all = "camelCase")]
704pub struct OmenaQueryClassSiteTokenProvenanceV0 {
705 pub token: OmenaQueryCanonicalClassTokenV0,
706 pub must: bool,
707 pub may: bool,
708 pub planes: Vec<OmenaQueryClassSitePlaneV0>,
709 pub boundary_provenance: Vec<String>,
710 #[serde(skip_serializing_if = "Vec::is_empty")]
711 pub guard_conditions: Vec<String>,
712}
713
714#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
715pub struct OmenaQueryCanonicalClassTokenV0(CanonicalClassKeyV0);
716
717impl OmenaQueryCanonicalClassTokenV0 {
718 pub fn as_str(&self) -> &str {
719 self.0.as_str()
720 }
721}
722
723impl Serialize for OmenaQueryCanonicalClassTokenV0 {
724 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
725 where
726 S: Serializer,
727 {
728 serializer.serialize_str(self.as_str())
729 }
730}
731
732#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
733#[serde(rename_all = "camelCase")]
734pub struct OmenaQueryClassSiteValueV0 {
735 pub schema_version: &'static str,
736 pub product: &'static str,
737 pub source_path: String,
738 #[serde(skip_serializing_if = "Option::is_none")]
739 pub source_language: Option<String>,
740 pub attribute_name: String,
741 pub site_byte_span: ParserByteSpanV0,
742 #[serde(skip_serializing_if = "Option::is_none")]
743 pub value_byte_span: Option<ParserByteSpanV0>,
744 #[serde(skip_serializing_if = "Option::is_none")]
745 pub raw_value: Option<String>,
746 pub target_style_uris: Vec<String>,
747 #[serde(skip_serializing_if = "Option::is_none")]
748 pub ordered_word: Option<OrderedTokenWordV0>,
749 #[serde(skip_serializing_if = "Option::is_none")]
750 pub support: Option<TokenSupportV0>,
751 pub token_provenance: Vec<OmenaQueryClassSiteTokenProvenanceV0>,
752 pub contributing_planes: Vec<OmenaQueryClassSitePlaneV0>,
753 pub precision_tier: &'static str,
754 #[serde(skip_serializing_if = "Option::is_none")]
755 pub unknown_cause: Option<OmenaQueryClassSiteUnknownCauseV0>,
756 #[serde(skip_serializing_if = "Option::is_none")]
757 pub type_fact_cause: Option<String>,
758}
759
760#[derive(Debug, Clone, PartialEq, Eq)]
761struct ClassSitePlaneProjectionV0 {
762 ordered_word: Option<OrderedTokenWordV0>,
763 support: TokenSupportV0,
764 precision_tier: &'static str,
765}
766
767pub fn resolve_omena_query_class_site_values_for_source(
768 source_path: &str,
769 source: &str,
770 source_language: Option<&str>,
771) -> Vec<OmenaQueryClassSiteValueV0> {
772 resolve_omena_query_class_site_values_for_source_with_type_facts(
773 source_path,
774 source,
775 source_language,
776 &[],
777 )
778}
779
780pub fn resolve_omena_query_class_site_values_for_source_with_type_facts(
781 source_path: &str,
782 source: &str,
783 source_language: Option<&str>,
784 type_facts: &[OmenaQueryClassSiteTypeFactInputV0],
785) -> Vec<OmenaQueryClassSiteValueV0> {
786 let imports = summarize_omena_query_source_import_declarations_for_source_language(
787 source_path,
788 source,
789 source_language,
790 );
791 let base_document_uri = style_source_path_as_file_uri(source_path);
792 let style_import_resolutions = imports
793 .imports
794 .iter()
795 .filter(|import| source_specifier_is_style_module(&import.specifier))
796 .filter_map(|import| {
797 resolve_omena_query_style_uri_for_specifier(&base_document_uri, None, &import.specifier)
798 .map(|style_uri| import.style_resolution(style_uri.as_str()))
799 })
800 .collect::<Vec<_>>();
801 let binding_index = summarize_omena_query_source_binding_index_for_source_language(
802 source_path,
803 source,
804 source_language,
805 style_import_resolutions,
806 );
807 binding_index
808 .class_attribute_sites
809 .iter()
810 .map(|site| {
811 let type_fact = type_facts
812 .iter()
813 .find(|fact| fact.site_byte_span == site.site_byte_span);
814 class_site_value_from_binding_fact(
815 source_path,
816 source,
817 source_language,
818 site,
819 type_fact,
820 )
821 })
822 .collect()
823}
824
825pub fn resolve_omena_query_class_site_value_for_source(
826 source_path: &str,
827 source: &str,
828 source_language: Option<&str>,
829 site_byte_span: ParserByteSpanV0,
830) -> Option<OmenaQueryClassSiteValueV0> {
831 resolve_omena_query_class_site_values_for_source(source_path, source, source_language)
832 .into_iter()
833 .find(|site| site.site_byte_span == site_byte_span)
834}
835
836pub fn build_omena_query_guarded_token_map_for_site(
837 site: &OmenaQueryClassSiteValueV0,
838) -> Result<GuardedTokenMapV0, FirstWitnessErrorV0> {
839 let mut tokens = Vec::new();
840 for provenance in &site.token_provenance {
841 let token = GuardedTokenLanguageV0::concrete(provenance.token.as_str());
842 let observers = TokenObserverProjectionV0::exact(&token);
843 if provenance.guard_conditions.is_empty() {
844 tokens.push(GuardedTokenInputV0 {
845 token,
846 guards: Vec::new(),
847 observers,
848 });
849 continue;
850 }
851 tokens.extend(
852 provenance
853 .guard_conditions
854 .iter()
855 .map(|condition| GuardedTokenInputV0 {
856 token: token.clone(),
857 guards: vec![guard_atom_from_source_condition(condition)],
858 observers: observers.clone(),
859 }),
860 );
861 }
862 if tokens.is_empty()
863 && let Some(raw_language) = site
864 .raw_value
865 .as_ref()
866 .filter(|raw| raw.starts_with('`') && raw.contains("${"))
867 {
868 let token = GuardedTokenLanguageV0::symbolic(raw_language.clone());
869 tokens.push(GuardedTokenInputV0 {
870 observers: TokenObserverProjectionV0::exact(&token),
871 token,
872 guards: Vec::new(),
873 });
874 }
875 GuardedTokenMapV0::build(GuardedTokenMapInputV0 {
876 tokens,
877 site_usage_guards: Vec::new(),
878 })
879}
880
881fn guard_atom_from_source_condition(condition: &str) -> GuardAtomV0 {
882 let condition = condition.trim();
883 let negated = condition
884 .strip_prefix("!(")
885 .and_then(|condition| condition.strip_suffix(')'));
886 GuardAtomV0 {
887 atom: negated.unwrap_or(condition).trim().to_string(),
888 polarity: negated.is_none(),
889 }
890}
891
892fn class_site_value_from_binding_fact(
893 source_path: &str,
894 source: &str,
895 source_language: Option<&str>,
896 site: &crate::OmenaQuerySourceClassAttributeSiteFactV0,
897 type_fact: Option<&OmenaQueryClassSiteTypeFactInputV0>,
898) -> OmenaQueryClassSiteValueV0 {
899 let cfg_projection = site
900 .source_facts
901 .as_ref()
902 .and_then(|facts| class_site_projection_from_values(facts.values.as_deref()));
903 let type_projection = type_fact
904 .and_then(|input| input.facts.as_ref())
905 .and_then(|facts| class_site_projection_from_values(facts.values.as_deref()));
906
907 let mut must = BTreeSet::new();
908 let mut may = BTreeSet::new();
909 let mut contributing_planes = Vec::new();
910 for (plane, projection) in [
911 (OmenaQueryClassSitePlaneV0::Cfg, cfg_projection.as_ref()),
912 (
913 OmenaQueryClassSitePlaneV0::TypeFact,
914 type_projection.as_ref(),
915 ),
916 ] {
917 if let Some(projection) = projection {
918 contributing_planes.push(plane);
919 must.extend(projection.support.must().iter().cloned());
920 may.extend(projection.support.may().iter().cloned());
921 }
922 }
923 let mut guard_conditions_by_token = BTreeMap::<CanonicalClassKeyV0, Vec<String>>::new();
924 for guarded in &site.guarded_tokens {
925 if let DomClassTokenizationV0::Known { word, .. } =
926 tokenize_dom_class_attribute_v0(Some(&guarded.token))
927 {
928 for token in word.tokens() {
929 may.insert(token.clone());
930 guard_conditions_by_token
931 .entry(token.clone())
932 .or_default()
933 .push(guarded.condition.clone());
934 }
935 }
936 }
937 if !site.guarded_tokens.is_empty()
938 && !contributing_planes.contains(&OmenaQueryClassSitePlaneV0::Cfg)
939 {
940 contributing_planes.push(OmenaQueryClassSitePlaneV0::Cfg);
941 }
942 if contributing_planes.contains(&OmenaQueryClassSitePlaneV0::Cfg)
943 && contributing_planes.contains(&OmenaQueryClassSitePlaneV0::TypeFact)
944 {
945 contributing_planes.push(OmenaQueryClassSitePlaneV0::Joined);
946 }
947 let support = (!may.is_empty())
948 .then(|| TokenSupportV0::new(must.iter().cloned(), may.iter().cloned()))
949 .flatten();
950 let ordered_word = match (cfg_projection.as_ref(), type_projection.as_ref()) {
951 (Some(cfg), Some(type_fact)) if cfg.ordered_word == type_fact.ordered_word => {
952 cfg.ordered_word.clone()
953 }
954 (Some(cfg), None) => cfg.ordered_word.clone(),
955 (None, Some(type_fact)) => type_fact.ordered_word.clone(),
956 _ => site.ordered_word.clone(),
957 };
958 let mut token_provenance = may
959 .iter()
960 .map(|token| {
961 let mut planes = [
962 (OmenaQueryClassSitePlaneV0::Cfg, cfg_projection.as_ref()),
963 (
964 OmenaQueryClassSitePlaneV0::TypeFact,
965 type_projection.as_ref(),
966 ),
967 ]
968 .into_iter()
969 .filter_map(|(plane, projection)| {
970 projection
971 .is_some_and(|projection| projection.support.may().contains(token))
972 .then_some(plane)
973 })
974 .collect::<Vec<_>>();
975 if guard_conditions_by_token.contains_key(token)
976 && !planes.contains(&OmenaQueryClassSitePlaneV0::Cfg)
977 {
978 planes.push(OmenaQueryClassSitePlaneV0::Cfg);
979 }
980 if planes.contains(&OmenaQueryClassSitePlaneV0::Cfg)
981 && planes.contains(&OmenaQueryClassSitePlaneV0::TypeFact)
982 {
983 planes.push(OmenaQueryClassSitePlaneV0::Joined);
984 }
985 let mut boundary_provenance = Vec::new();
986 if planes.contains(&OmenaQueryClassSitePlaneV0::Cfg) {
987 boundary_provenance.push(class_boundary_effect_label(site.boundary_effect));
988 }
989 if guard_conditions_by_token.contains_key(token) {
990 boundary_provenance.push("guardedClassToken".to_string());
991 }
992 OmenaQueryClassSiteTokenProvenanceV0 {
993 token: OmenaQueryCanonicalClassTokenV0(token.clone()),
994 must: must.contains(token),
995 may: true,
996 planes,
997 boundary_provenance,
998 guard_conditions: guard_conditions_by_token
999 .get(token)
1000 .cloned()
1001 .unwrap_or_default(),
1002 }
1003 })
1004 .collect::<Vec<_>>();
1005 token_provenance.sort_by(|left, right| left.token.cmp(&right.token));
1006
1007 let precision_tier = cfg_projection
1008 .as_ref()
1009 .map(|projection| projection.precision_tier)
1010 .or_else(|| {
1011 type_projection
1012 .as_ref()
1013 .map(|projection| projection.precision_tier)
1014 })
1015 .or_else(|| (!site.guarded_tokens.is_empty()).then_some("finiteSet"))
1016 .unwrap_or("top");
1017 let unknown_cause = if support.is_some() && !may.is_empty() {
1018 None
1019 } else if site.source_facts.is_some()
1020 || type_fact.and_then(|input| input.facts.as_ref()).is_some()
1021 {
1022 Some(OmenaQueryClassSiteUnknownCauseV0::NonFiniteRawLanguage)
1023 } else {
1024 Some(OmenaQueryClassSiteUnknownCauseV0::SourceValueUnavailable)
1025 };
1026 let type_fact_cause = match type_fact {
1027 None => Some("typeFactNotProvided".to_string()),
1028 Some(input) if input.facts.is_none() => Some(
1029 input
1030 .refusal_cause
1031 .clone()
1032 .unwrap_or_else(|| "typeFactRefused".to_string()),
1033 ),
1034 Some(_) => None,
1035 };
1036
1037 OmenaQueryClassSiteValueV0 {
1038 schema_version: "0",
1039 product: "omena-query.class-site-value",
1040 source_path: source_path.to_string(),
1041 source_language: source_language.map(str::to_string),
1042 attribute_name: site.attribute_name.clone(),
1043 site_byte_span: site.site_byte_span,
1044 value_byte_span: site.value_byte_span,
1045 raw_value: site
1046 .value_byte_span
1047 .and_then(|span| source.get(span.start..span.end))
1048 .map(str::to_string),
1049 target_style_uris: site.target_style_uris.clone(),
1050 ordered_word,
1051 support,
1052 token_provenance,
1053 contributing_planes,
1054 precision_tier,
1055 unknown_cause,
1056 type_fact_cause,
1057 }
1058}
1059
1060fn class_site_projection_from_values(
1061 values: Option<&[String]>,
1062) -> Option<ClassSitePlaneProjectionV0> {
1063 let values = values?;
1064 if values.is_empty() {
1065 return None;
1066 }
1067 let mut words = Vec::with_capacity(values.len());
1068 for value in values {
1069 let DomClassTokenizationV0::Known { word, .. } =
1070 tokenize_dom_class_attribute_v0(Some(value))
1071 else {
1072 return None;
1073 };
1074 words.push(word);
1075 }
1076 let may = words
1077 .iter()
1078 .flat_map(|word| word.tokens().iter().cloned())
1079 .collect::<BTreeSet<_>>();
1080 let mut must = words
1081 .first()
1082 .map(|word| word.tokens().iter().cloned().collect::<BTreeSet<_>>())?;
1083 for word in words.iter().skip(1) {
1084 let word = word.tokens().iter().cloned().collect::<BTreeSet<_>>();
1085 must = must.intersection(&word).cloned().collect();
1086 }
1087 let ordered_word = words
1088 .iter()
1089 .all(|word| word == &words[0])
1090 .then(|| words[0].clone());
1091 Some(ClassSitePlaneProjectionV0 {
1092 ordered_word,
1093 support: TokenSupportV0::new(must, may)?,
1094 precision_tier: if values.len() == 1 {
1095 "exact"
1096 } else {
1097 "finiteSet"
1098 },
1099 })
1100}
1101
1102fn class_boundary_effect_label(effect: ClassBoundaryEffectV0) -> String {
1103 match effect {
1104 ClassBoundaryEffectV0::ConcatInsideToken => "concatInsideToken",
1105 ClassBoundaryEffectV0::ConcatAtTokenBoundary => "concatAtTokenBoundary",
1106 ClassBoundaryEffectV0::UnknownBoundary => "unknownBoundary",
1107 }
1108 .to_string()
1109}
1110
1111fn source_specifier_is_style_module(specifier: &str) -> bool {
1112 [".css", ".scss", ".sass", ".less"]
1113 .iter()
1114 .any(|extension| specifier.ends_with(extension))
1115}
1116
1117#[derive(Clone, PartialEq, Eq)]
1118struct ResolvedSourcePrecisionFlowV0 {
1119 value: AbstractClassValueV0,
1120 top_cause: Option<&'static str>,
1121}
1122
1123fn resolve_source_precision_flow_from_snapshot(
1124 snapshot: &crate::OmenaQuerySourceFlowBlockGraphSnapshotV0,
1125 symbol_ordinal: usize,
1126) -> Option<ResolvedSourcePrecisionFlowV0> {
1127 let predecessors = source_precision_predecessor_block_ids(&snapshot.blocks);
1128 let mut states = snapshot
1129 .blocks
1130 .iter()
1131 .map(|block| (block.id.clone(), None::<ResolvedSourcePrecisionFlowV0>))
1132 .collect::<BTreeMap<_, _>>();
1133
1134 for _ in 0..std::cmp::max(snapshot.blocks.len() * 2, 1) {
1135 let mut changed = false;
1136 for block in &snapshot.blocks {
1137 let incoming = source_precision_incoming_state(block, &predecessors, &states);
1138 let next = apply_source_precision_block(block, symbol_ordinal, incoming);
1139 if states.get(&block.id).and_then(Clone::clone) != next {
1140 states.insert(block.id.clone(), next);
1141 changed = true;
1142 }
1143 }
1144 if !changed {
1145 break;
1146 }
1147 }
1148
1149 let exit = snapshot
1150 .blocks
1151 .iter()
1152 .find(|block| block.id == "exit")
1153 .or_else(|| snapshot.blocks.last())?;
1154 states.get(&exit.id).and_then(Clone::clone)
1155}
1156
1157fn source_precision_predecessor_block_ids(
1158 blocks: &[crate::OmenaQuerySourceFlowBlockSnapshotV0],
1159) -> BTreeMap<String, Vec<String>> {
1160 let mut predecessors = BTreeMap::<String, Vec<String>>::new();
1161 for block in blocks {
1162 for successor in &block.successor_block_ids {
1163 predecessors
1164 .entry(successor.clone())
1165 .or_default()
1166 .push(block.id.clone());
1167 }
1168 }
1169 predecessors
1170}
1171
1172fn source_precision_incoming_state(
1173 block: &crate::OmenaQuerySourceFlowBlockSnapshotV0,
1174 predecessors: &BTreeMap<String, Vec<String>>,
1175 states: &BTreeMap<String, Option<ResolvedSourcePrecisionFlowV0>>,
1176) -> Option<ResolvedSourcePrecisionFlowV0> {
1177 predecessors
1178 .get(&block.id)
1179 .into_iter()
1180 .flat_map(|ids| ids.iter())
1181 .filter_map(|id| states.get(id).and_then(Clone::clone))
1182 .reduce(join_source_precision_flows)
1183}
1184
1185fn apply_source_precision_block(
1186 block: &crate::OmenaQuerySourceFlowBlockSnapshotV0,
1187 symbol_ordinal: usize,
1188 incoming: Option<ResolvedSourcePrecisionFlowV0>,
1189) -> Option<ResolvedSourcePrecisionFlowV0> {
1190 if block.symbol_ordinal != Some(symbol_ordinal)
1191 || !matches!(block.transfer_kind, "assignFacts" | "concatFacts")
1192 {
1193 return incoming;
1194 }
1195
1196 let Some(facts) = block.facts.as_ref() else {
1197 return Some(ResolvedSourcePrecisionFlowV0 {
1198 value: top_class_value(),
1199 top_cause: Some("missingValueFacts"),
1200 });
1201 };
1202
1203 let external_facts = ExternalStringTypeFactsV0 {
1204 kind: facts.kind.clone(),
1205 constraint_kind: facts.constraint_kind.clone(),
1206 values: facts.values.clone(),
1207 prefix: facts.prefix.clone(),
1208 suffix: facts.suffix.clone(),
1209 min_len: facts.min_len,
1210 max_len: facts.max_len,
1211 char_must: facts.char_must.clone(),
1212 char_may: facts.char_may.clone(),
1213 may_include_other_chars: facts.may_include_other_chars,
1214 };
1215
1216 Some(ResolvedSourcePrecisionFlowV0 {
1217 value: abstract_class_value_from_facts(&external_facts),
1218 top_cause: None,
1219 })
1220}
1221
1222fn join_source_precision_flows(
1223 left: ResolvedSourcePrecisionFlowV0,
1224 right: ResolvedSourcePrecisionFlowV0,
1225) -> ResolvedSourcePrecisionFlowV0 {
1226 let value = join_abstract_class_values(&left.value, &right.value);
1227 let top_cause = if abstract_class_value_kind(&value) == "top" {
1228 left.top_cause.or(right.top_cause).or(Some("joinedTop"))
1229 } else {
1230 None
1231 };
1232 ResolvedSourcePrecisionFlowV0 { value, top_cause }
1233}
1234
1235fn source_precision_reference(
1236 source_path: &str,
1237 source_language: Option<&str>,
1238 variable_name: &str,
1239 reference_byte_offset: usize,
1240 resolved_value: AbstractClassValueV0,
1241 precision: OmenaQueryAnalysisPrecisionV0,
1242 top_cause: Option<&'static str>,
1243) -> OmenaQuerySourcePrecisionReferenceV0 {
1244 let resolved_tier = abstract_class_value_kind(&resolved_value);
1245 OmenaQuerySourcePrecisionReferenceV0 {
1246 schema_version: "0",
1247 product: "omena-query.source-precision-reference",
1248 source_path: source_path.to_string(),
1249 source_language: source_language.map(str::to_string),
1250 variable_name: variable_name.to_string(),
1251 reference_byte_offset,
1252 resolved_tier,
1253 resolved_value,
1254 precision,
1255 top_cause,
1256 }
1257}
1258
1259pub fn summarize_omena_query_source_type_fact_control_flow_graph_for_source_language(
1260 source_path: &str,
1261 source: &str,
1262 source_language: Option<&str>,
1263 variable_name: &str,
1264 reference_byte_offset: usize,
1265) -> Option<crate::OmenaQuerySourceTypeFactControlFlowGraphV0> {
1266 omena_bridge::summarize_omena_bridge_source_type_fact_control_flow_graph_for_source_language(
1267 source_path,
1268 source,
1269 source_language,
1270 variable_name,
1271 reference_byte_offset,
1272 )
1273}
1274
1275pub fn collect_omena_query_vue_style_module_bindings(
1276 source_path: &str,
1277 source: &str,
1278 source_language: Option<&str>,
1279) -> Vec<String> {
1280 omena_bridge::collect_omena_bridge_vue_style_module_bindings(
1281 source_path,
1282 source,
1283 source_language,
1284 )
1285}
1286
1287pub fn canonicalize_omena_query_source_selector_references(
1288 references: &mut Vec<OmenaQuerySourceSelectorReferenceFactV0>,
1289) {
1290 omena_bridge::canonicalize_source_selector_references(references);
1291}