Skip to main content

omena_bridge/
lib.rs

1use engine_input_producers::EngineInputV2;
2use omena_semantic::{
3    CssModulesSemanticSummaryV0, DesignTokenSemanticSummaryV0, LosslessCstContractV0,
4    ParserBoundarySyntaxFactsV0, SelectorIdentityEngineSummaryV0, StyleSemanticBoundarySummaryV0,
5    StyleSemanticFactsV0, Stylesheet,
6};
7pub use omena_semantic::{
8    DesignTokenExternalDeclarationCandidateScopeV0, DesignTokenWorkspaceDeclarationFactV0,
9    ParserRangeV0 as OmenaBridgeParserRangeV0,
10};
11use serde::Serialize;
12
13mod bundler_config_alias;
14mod promotion_evidence;
15mod selector_references;
16mod source_cfg;
17mod source_evidence;
18mod source_imports;
19mod source_language;
20mod source_syntax;
21mod style_intelligence;
22mod style_resolution;
23mod utility_intelligence;
24
25pub type OmenaBridgeSourceTypeFactControlFlowGraphV0 =
26    engine_input_producers::TypeFactControlFlowGraphV2;
27
28pub use bundler_config_alias::{
29    OmenaBridgeBundlerAliasUnrecognizedEntryV0, OmenaBridgeBundlerPathAliasMappingV0,
30    OmenaBridgeBundlerPathAliasSummaryV0, summarize_omena_bridge_bundler_path_aliases_for_config,
31};
32pub use promotion_evidence::{
33    SemanticPromotionEvidenceItemV0, SemanticPromotionEvidenceSummaryV0,
34    summarize_omena_bridge_promotion_evidence_with_source_input,
35    summarize_omena_bridge_semantic_promotion_evidence,
36};
37pub use selector_references::{
38    SelectorEditableDirectReferenceSiteV0, SelectorReferenceEngineSummaryV0,
39    SelectorReferenceSiteV0, SelectorReferenceSummaryV0,
40    summarize_omena_bridge_selector_reference_engine,
41};
42pub use source_cfg::{
43    SourceControlFlowGraphCaptureV0, SourceFlowBindingRefV0, SourceFlowBlockGraphSnapshotV0,
44    SourceFlowBlockSnapshotV0, source_type_fact_control_flow_graph_from_snapshot,
45    summarize_omena_bridge_source_control_flow_graph_for_source_language,
46    summarize_omena_bridge_source_type_fact_control_flow_graph_for_source_language,
47};
48pub use source_evidence::{
49    BindingOriginEvidenceV0, CertaintyReasonEvidenceV0, ReferenceSiteIdentityEvidenceV0,
50    SourceInputPromotionEvidenceSummaryV0, StyleModuleEdgeEvidenceV0,
51    ValueDomainExplanationEvidenceV0, summarize_omena_bridge_source_input_evidence,
52};
53pub use source_imports::{
54    SourceImportDeclarationSummaryV0, SourceImportDeclarationV0,
55    summarize_omena_bridge_source_import_declarations,
56    summarize_omena_bridge_source_import_declarations_for_path,
57    summarize_omena_bridge_source_import_declarations_for_source_language,
58};
59pub use source_language::{
60    SourceLanguageParserBoundarySummaryV0, SourceLanguageParserDescriptorV0,
61    summarize_omena_bridge_source_language_parser_boundary_v0,
62};
63pub use source_syntax::{
64    SourceBindingDeclFactV0, SourceBindingIndexV0, SourceBindingScopeFactV0,
65    SourceBindingStyleImportFactV0, SourceClassExpressionNodeFactV0,
66    SourceClassUtilityBindingFactV0, SourceClassValuePatternMatcherV0, SourceClassValuePatternV0,
67    SourceClassValueUniverseAxisV0, SourceClassValueUniverseEntryV0, SourceClassValueUnresolvedV0,
68    SourceClassnamesBindUtilityBindingFactV0, SourceDeclaresStyleImportFactV0,
69    SourceDeclaresUtilityBindingFactV0, SourceDomainClassReferenceFactV0, SourceElementFactV0,
70    SourceElementIdentityFactV0, SourceElementParentFactV0, SourceExpressionTargetsModuleFactV0,
71    SourceImportedStyleBindingV0, SourceInlineStyleDeclarationFactV0, SourceModuleSpecifierFactV0,
72    SourceScopeContainsDeclFactV0, SourceScopeParentFactV0, SourceSelectorReferenceFactV0,
73    SourceSelectorReferenceMatchKindV0, SourceStyleAccessUsesStyleImportFactV0,
74    SourceStyleImportResolvesModuleFactV0, SourceStylePropertyAccessFactV0,
75    SourceSymbolRefUsesDeclFactV0, SourceSyntaxIndexV0, SourceTypeFactProviderUnavailableFactV0,
76    SourceTypeFactTargetV0, SourceUtilityUsesStyleImportFactV0,
77    canonicalize_source_selector_references, collect_omena_bridge_vue_style_module_bindings,
78    summarize_omena_bridge_source_binding_index,
79    summarize_omena_bridge_source_binding_index_for_source_language,
80    summarize_omena_bridge_source_syntax_index,
81    summarize_omena_bridge_source_syntax_index_for_source_language,
82};
83pub use style_intelligence::{
84    BuiltInStyleIntelligenceProviderV0, StyleIntelligenceClassUniverseV0,
85    StyleIntelligenceCompletionV0, StyleIntelligenceGraphBindingV0, StyleIntelligenceHoverV0,
86    StyleIntelligenceProvider, StyleIntelligenceProviderMetadataV0, StyleIntelligenceSnapshotV0,
87    StyleIntelligenceSourceContextV0, built_in_style_intelligence_provider,
88    built_in_style_intelligence_providers, style_intelligence_completions_at_offset,
89    style_intelligence_hover_at_offset,
90};
91pub use style_resolution::{
92    OmenaBridgeExternalSifCacheContextV0, OmenaBridgeStyleResolutionInputsV0,
93    OmenaBridgeStyleResolutionSummaryV0, generate_omena_bridge_lif_exports_for_resolved_style_path,
94    generate_omena_bridge_sif_for_resolved_style_path,
95    generate_omena_bridge_sif_for_resolved_style_path_with_cache_context,
96    load_omena_bridge_workspace_style_resolution_inputs,
97    resolve_omena_bridge_style_uri_for_specifier,
98    resolve_omena_bridge_style_uri_for_specifier_with_package_manifests,
99    resolve_omena_bridge_style_uri_for_specifier_with_resolution_inputs,
100    summarize_omena_bridge_style_resolution_boundary,
101};
102pub use utility_intelligence::{
103    UtilityClassIntelligenceReportV0, UtilityClassLintSignalV0, UtilityClassMembershipKindV0,
104    UtilityConfigKindV0, append_omena_bridge_utility_class_intelligence,
105    classify_omena_bridge_utility_class, load_omena_bridge_workspace_utility_class_intelligence,
106    summarize_omena_bridge_utility_class_intelligence_for_config,
107};
108
109pub fn collect_omena_bridge_design_token_workspace_declarations(
110    style_path: &str,
111    sheet: &Stylesheet,
112) -> Vec<DesignTokenWorkspaceDeclarationFactV0> {
113    let parser_facts = omena_semantic::summarize_parser_contract_facts(sheet);
114    omena_semantic::collect_design_token_workspace_declarations(style_path, &parser_facts)
115}
116
117pub fn collect_omena_bridge_design_token_workspace_declarations_from_source(
118    style_path: &str,
119    style_source: &str,
120) -> Vec<DesignTokenWorkspaceDeclarationFactV0> {
121    let boundary = omena_semantic::summarize_omena_parser_style_semantic_boundary_from_source(
122        style_path,
123        style_source,
124    );
125    omena_semantic::collect_design_token_workspace_declarations(style_path, &boundary.parser_facts)
126}
127
128#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
129#[serde(rename_all = "camelCase")]
130pub struct OmenaBridgeBoundarySummaryV0 {
131    pub schema_version: &'static str,
132    pub product: &'static str,
133    pub bridge_name: &'static str,
134    pub graph_product: &'static str,
135    pub delegated_semantic_boundary_product: &'static str,
136    pub selector_reference_product: &'static str,
137    pub source_input_evidence_product: &'static str,
138    pub binder_plugin_product: &'static str,
139    pub bridge_owned_surfaces: Vec<&'static str>,
140    pub cme_coupled_surfaces: Vec<&'static str>,
141    pub next_decoupling_targets: Vec<&'static str>,
142}
143
144#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
145#[serde(rename_all = "camelCase")]
146pub struct BinderPluginBoundarySummaryV0 {
147    pub schema_version: &'static str,
148    pub product: &'static str,
149    pub owner_crate: &'static str,
150    pub contract_name: &'static str,
151    pub external_plugin_abi_stable: bool,
152    pub default_plugin: BinderPluginSummaryV0,
153    pub built_in_plugins: Vec<BinderPluginSummaryV0>,
154    pub request_path_policy: Vec<&'static str>,
155    pub next_plugin_targets: Vec<&'static str>,
156}
157
158#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
159#[serde(rename_all = "camelCase")]
160pub struct BinderPluginSummaryV0 {
161    pub id: &'static str,
162    pub version: &'static str,
163    pub stability: &'static str,
164    pub domains: Vec<&'static str>,
165    pub owns_surfaces: Vec<&'static str>,
166    pub import_targets: Vec<&'static str>,
167    pub utility_targets: Vec<&'static str>,
168}
169
170#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
171#[serde(rename_all = "camelCase")]
172pub struct StyleSemanticGraphSummaryV0 {
173    pub schema_version: &'static str,
174    pub product: &'static str,
175    pub language: &'static str,
176    pub parser_facts: ParserBoundarySyntaxFactsV0,
177    pub semantic_facts: StyleSemanticFactsV0,
178    pub css_modules_semantics: CssModulesSemanticSummaryV0,
179    pub design_token_semantics: DesignTokenSemanticSummaryV0,
180    pub selector_identity_engine: SelectorIdentityEngineSummaryV0,
181    pub selector_reference_engine: SelectorReferenceEngineSummaryV0,
182    pub source_input_evidence: SourceInputPromotionEvidenceSummaryV0,
183    pub promotion_evidence: SemanticPromotionEvidenceSummaryV0,
184    pub lossless_cst_contract: LosslessCstContractV0,
185}
186
187pub fn summarize_omena_bridge_boundary() -> OmenaBridgeBoundarySummaryV0 {
188    OmenaBridgeBoundarySummaryV0 {
189        schema_version: "0",
190        product: "omena-bridge.cme-semantic-bridge",
191        bridge_name: "cme-semantic-bridge",
192        graph_product: "omena-semantic.style-semantic-graph",
193        delegated_semantic_boundary_product: "omena-semantic.style-semantic-boundary",
194        selector_reference_product: "omena-semantic.selector-references",
195        source_input_evidence_product: "omena-semantic.source-input-evidence",
196        binder_plugin_product: "omena-bridge.binder-plugin-boundary",
197        bridge_owned_surfaces: vec![
198            "styleSemanticGraph",
199            "styleSemanticGraphFromSource",
200            "omenaParserBackedStyleSemanticBoundaryFromSource",
201            "selectorReferenceEngine",
202            "designTokenWorkspaceDeclarationsFromSource",
203            "sourceInputEvidence",
204            "sourceImportDeclarations",
205            "styleResolution",
206            "sourceSyntaxIndex",
207            "promotionEvidenceWithSourceInput",
208            "binderPluginBoundary",
209        ],
210        cme_coupled_surfaces: vec![
211            "EngineInputV2",
212            "sourceInputEvidence",
213            "selectorReferenceEngine",
214            "promotionEvidenceWithSourceInput",
215            "styleSemanticGraphFromSource",
216            "cssModulesClassnameBinding",
217            "sourceSyntaxIndex",
218            "styleResolution",
219        ],
220        next_decoupling_targets: Vec::new(),
221    }
222}
223
224pub fn summarize_omena_bridge_binder_plugin_boundary() -> BinderPluginBoundarySummaryV0 {
225    let providers = built_in_style_intelligence_providers();
226    BinderPluginBoundarySummaryV0 {
227        schema_version: "0",
228        product: "omena-bridge.binder-plugin-boundary",
229        owner_crate: "omena-bridge",
230        contract_name: "BinderPluginV0",
231        external_plugin_abi_stable: false,
232        default_plugin: binder_plugin_summary_from_provider(&providers[0]),
233        built_in_plugins: providers
234            .iter()
235            .filter(|provider| provider.binder_summary_visible)
236            .map(binder_plugin_summary_from_provider)
237            .collect(),
238        request_path_policy: vec![
239            "builtInPluginsOnlyUntilAbiStabilizes",
240            "pluginOutputFeedsEngineInputV2",
241            "sourceExpressionProjectionMustPreserveBindingIdentity",
242            "styleImportResolutionMustRemainTargetAware",
243            "styleSourceExtractionIsOptionalForUtilityDomains",
244        ],
245        next_plugin_targets: Vec::new(),
246    }
247}
248
249fn binder_plugin_summary_from_provider(
250    provider: &BuiltInStyleIntelligenceProviderV0,
251) -> BinderPluginSummaryV0 {
252    let metadata = provider.metadata();
253    BinderPluginSummaryV0 {
254        id: metadata.provider_id,
255        version: metadata.version,
256        stability: metadata.stability,
257        domains: metadata.domains.to_vec(),
258        owns_surfaces: metadata.owns_surfaces.to_vec(),
259        import_targets: metadata.import_targets.to_vec(),
260        utility_targets: metadata.utility_targets.to_vec(),
261    }
262}
263
264pub fn summarize_omena_bridge_style_semantic_graph(
265    sheet: &Stylesheet,
266    input: &EngineInputV2,
267) -> StyleSemanticGraphSummaryV0 {
268    summarize_omena_bridge_style_semantic_graph_for_path(sheet, input, None)
269}
270
271pub fn summarize_omena_bridge_style_semantic_graph_for_path(
272    sheet: &Stylesheet,
273    input: &EngineInputV2,
274    style_path: Option<&str>,
275) -> StyleSemanticGraphSummaryV0 {
276    summarize_omena_bridge_style_semantic_graph_for_path_with_workspace_declarations(
277        sheet,
278        input,
279        style_path,
280        &[],
281    )
282}
283
284pub fn summarize_omena_bridge_style_semantic_graph_for_path_with_workspace_declarations(
285    sheet: &Stylesheet,
286    input: &EngineInputV2,
287    style_path: Option<&str>,
288    workspace_declarations: &[DesignTokenWorkspaceDeclarationFactV0],
289) -> StyleSemanticGraphSummaryV0 {
290    summarize_omena_bridge_style_semantic_graph_for_path_with_scoped_workspace_declarations(
291        sheet,
292        input,
293        style_path,
294        workspace_declarations,
295        DesignTokenExternalDeclarationCandidateScopeV0::Workspace,
296    )
297}
298
299pub fn summarize_omena_bridge_style_semantic_graph_for_path_with_scoped_workspace_declarations(
300    sheet: &Stylesheet,
301    input: &EngineInputV2,
302    style_path: Option<&str>,
303    workspace_declarations: &[DesignTokenWorkspaceDeclarationFactV0],
304    candidate_scope: DesignTokenExternalDeclarationCandidateScopeV0,
305) -> StyleSemanticGraphSummaryV0 {
306    let boundary = omena_semantic::summarize_style_semantic_boundary(sheet);
307    let css_modules_semantics = omena_semantic::summarize_css_modules_semantics(sheet);
308    summarize_omena_bridge_style_semantic_graph_with_boundary(
309        boundary,
310        css_modules_semantics,
311        input,
312        style_path,
313        workspace_declarations,
314        candidate_scope,
315    )
316}
317
318fn summarize_omena_bridge_style_semantic_graph_with_boundary(
319    boundary: StyleSemanticBoundarySummaryV0,
320    css_modules_semantics: CssModulesSemanticSummaryV0,
321    input: &EngineInputV2,
322    style_path: Option<&str>,
323    workspace_declarations: &[DesignTokenWorkspaceDeclarationFactV0],
324    candidate_scope: DesignTokenExternalDeclarationCandidateScopeV0,
325) -> StyleSemanticGraphSummaryV0 {
326    let parser_facts = boundary.parser_facts;
327    let semantic_facts = boundary.semantic_facts;
328    let design_token_semantics =
329        omena_semantic::summarize_design_token_semantics_with_scoped_workspace_declarations(
330            &parser_facts,
331            &semantic_facts,
332            style_path,
333            workspace_declarations,
334            candidate_scope,
335        );
336    let selector_identity_engine = boundary.selector_identity_engine;
337    let selector_reference_engine =
338        summarize_omena_bridge_selector_reference_engine(input, style_path);
339    let source_input_evidence = summarize_omena_bridge_source_input_evidence(input);
340    let promotion_evidence = summarize_omena_bridge_promotion_evidence_with_source_input(
341        &parser_facts,
342        &semantic_facts,
343        input,
344    );
345    let lossless_cst_contract = boundary.lossless_cst_contract;
346
347    StyleSemanticGraphSummaryV0 {
348        schema_version: "0",
349        product: "omena-semantic.style-semantic-graph",
350        language: boundary.language,
351        parser_facts,
352        semantic_facts,
353        css_modules_semantics,
354        design_token_semantics,
355        selector_identity_engine,
356        selector_reference_engine,
357        source_input_evidence,
358        promotion_evidence,
359        lossless_cst_contract,
360    }
361}
362
363pub fn summarize_omena_bridge_style_semantic_graph_from_source(
364    style_path: &str,
365    style_source: &str,
366    input: &EngineInputV2,
367) -> Option<StyleSemanticGraphSummaryV0> {
368    summarize_omena_bridge_style_semantic_graph_from_source_with_scoped_workspace_declarations(
369        style_path,
370        style_source,
371        input,
372        &[],
373        DesignTokenExternalDeclarationCandidateScopeV0::Workspace,
374    )
375}
376
377pub fn summarize_omena_bridge_style_semantic_graph_from_source_with_scoped_workspace_declarations(
378    style_path: &str,
379    style_source: &str,
380    input: &EngineInputV2,
381    workspace_declarations: &[DesignTokenWorkspaceDeclarationFactV0],
382    candidate_scope: DesignTokenExternalDeclarationCandidateScopeV0,
383) -> Option<StyleSemanticGraphSummaryV0> {
384    let css_modules_semantics =
385        omena_semantic::summarize_css_modules_semantics_from_source(style_path, style_source)?;
386    let boundary = omena_semantic::summarize_omena_parser_style_semantic_boundary_from_source(
387        style_path,
388        style_source,
389    );
390    Some(summarize_omena_bridge_style_semantic_graph_with_boundary(
391        boundary,
392        css_modules_semantics,
393        input,
394        Some(style_path),
395        workspace_declarations,
396        candidate_scope,
397    ))
398}
399
400#[cfg(test)]
401mod tests {
402    use super::{
403        collect_omena_bridge_design_token_workspace_declarations_from_source,
404        summarize_omena_bridge_binder_plugin_boundary, summarize_omena_bridge_boundary,
405        summarize_omena_bridge_promotion_evidence_with_source_input,
406        summarize_omena_bridge_selector_reference_engine,
407        summarize_omena_bridge_source_import_declarations,
408        summarize_omena_bridge_source_input_evidence,
409        summarize_omena_bridge_style_semantic_graph_from_source,
410    };
411    use engine_input_producers::{
412        ClassExpressionInputV2, EngineInputV2, PositionV2, RangeV2, SourceAnalysisInputV2,
413        SourceDocumentV2, StringTypeFactsV2, StyleAnalysisInputV2, StyleDocumentV2,
414        StyleSelectorV2, TypeFactEntryV2,
415    };
416
417    #[test]
418    fn declares_cme_coupled_bridge_boundary() {
419        let boundary = summarize_omena_bridge_boundary();
420
421        assert_eq!(boundary.schema_version, "0");
422        assert_eq!(boundary.product, "omena-bridge.cme-semantic-bridge");
423        assert_eq!(
424            boundary.graph_product,
425            "omena-semantic.style-semantic-graph"
426        );
427        assert_eq!(
428            boundary.delegated_semantic_boundary_product,
429            "omena-semantic.style-semantic-boundary"
430        );
431        assert_eq!(
432            boundary.selector_reference_product,
433            "omena-semantic.selector-references"
434        );
435        assert_eq!(
436            boundary.source_input_evidence_product,
437            "omena-semantic.source-input-evidence"
438        );
439        assert_eq!(
440            boundary.binder_plugin_product,
441            "omena-bridge.binder-plugin-boundary"
442        );
443        assert!(
444            boundary
445                .bridge_owned_surfaces
446                .contains(&"styleSemanticGraphFromSource")
447        );
448        assert!(
449            boundary
450                .bridge_owned_surfaces
451                .contains(&"omenaParserBackedStyleSemanticBoundaryFromSource")
452        );
453        assert!(
454            boundary
455                .bridge_owned_surfaces
456                .contains(&"selectorReferenceEngine")
457        );
458        assert!(
459            boundary
460                .bridge_owned_surfaces
461                .contains(&"designTokenWorkspaceDeclarationsFromSource")
462        );
463        assert!(
464            boundary
465                .bridge_owned_surfaces
466                .contains(&"sourceInputEvidence")
467        );
468        assert!(
469            boundary
470                .bridge_owned_surfaces
471                .contains(&"promotionEvidenceWithSourceInput")
472        );
473        assert!(
474            boundary
475                .bridge_owned_surfaces
476                .contains(&"sourceImportDeclarations")
477        );
478        assert!(boundary.bridge_owned_surfaces.contains(&"styleResolution"));
479        assert!(
480            boundary
481                .bridge_owned_surfaces
482                .contains(&"sourceSyntaxIndex")
483        );
484        assert!(
485            boundary
486                .bridge_owned_surfaces
487                .contains(&"binderPluginBoundary")
488        );
489        assert!(
490            boundary
491                .cme_coupled_surfaces
492                .contains(&"promotionEvidenceWithSourceInput")
493        );
494        assert!(
495            boundary.next_decoupling_targets.is_empty(),
496            "all current omena-bridge decoupling targets should be bridge-owned"
497        );
498    }
499
500    #[test]
501    fn declares_built_in_binder_plugin_boundary() {
502        let boundary = summarize_omena_bridge_binder_plugin_boundary();
503
504        assert_eq!(boundary.schema_version, "0");
505        assert_eq!(boundary.product, "omena-bridge.binder-plugin-boundary");
506        assert_eq!(boundary.contract_name, "BinderPluginV0");
507        assert!(
508            !boundary.external_plugin_abi_stable,
509            "the first boundary cut should not promise a stable external plugin ABI"
510        );
511        assert_eq!(boundary.default_plugin.id, "css-modules-classnames-bind");
512        assert_eq!(boundary.default_plugin.stability, "builtIn");
513        assert!(boundary.default_plugin.domains.contains(&"css-modules"));
514        assert!(
515            boundary
516                .default_plugin
517                .owns_surfaces
518                .contains(&"classReferenceExtraction")
519        );
520        assert!(
521            boundary
522                .default_plugin
523                .utility_targets
524                .contains(&"classnames/bind")
525        );
526        assert!(
527            boundary
528                .request_path_policy
529                .contains(&"pluginOutputFeedsEngineInputV2")
530        );
531        assert!(
532            boundary
533                .request_path_policy
534                .contains(&"styleSourceExtractionIsOptionalForUtilityDomains")
535        );
536        assert!(boundary.built_in_plugins.iter().any(|plugin| {
537            plugin.id == "tailwind-uno-utility-domain"
538                && plugin.domains.contains(&"tailwind-utilities")
539                && plugin
540                    .owns_surfaces
541                    .contains(&"domainClassReferenceExtraction")
542        }));
543        assert!(
544            !boundary
545                .next_plugin_targets
546                .contains(&"tailwind-utility-domain")
547        );
548        assert!(boundary.built_in_plugins.iter().any(|plugin| {
549            plugin.id == "vanilla-extract-recipe-domain"
550                && plugin.domains.contains(&"vanilla-extract-recipes")
551                && plugin
552                    .owns_surfaces
553                    .contains(&"domainClassReferenceExtraction")
554        }));
555        assert!(
556            !boundary
557                .next_plugin_targets
558                .contains(&"vanilla-extract-recipe-domain")
559        );
560        assert!(boundary.built_in_plugins.iter().any(|plugin| {
561            plugin.id == "vue-style-module-domain"
562                && plugin.domains.contains(&"vue-style-modules")
563                && plugin
564                    .owns_surfaces
565                    .contains(&"domainClassReferenceExtraction")
566        }));
567        assert!(
568            boundary.next_plugin_targets.is_empty(),
569            "all planned BinderPluginV0 proof-point domains should now be built in"
570        );
571    }
572
573    #[test]
574    fn summarizes_source_import_declarations_for_css_modules_binding_inputs() {
575        let summary = summarize_omena_bridge_source_import_declarations(
576            r#"
577import bind from "classnames/bind";
578import styles from "./Button.module.scss";
579import * as tokens from "./tokens.module.css";
580import { type BadgeProps } from "./types";
581const lazy = import("./ignored.module.scss");
582"#,
583        );
584
585        assert_eq!(summary.product, "omena-bridge.source-import-declarations");
586        assert_eq!(summary.import_count, 3);
587        assert_eq!(
588            summary
589                .imports
590                .iter()
591                .map(|import| (import.binding.as_str(), import.specifier.as_str()))
592                .collect::<Vec<_>>(),
593            vec![
594                ("bind", "classnames/bind"),
595                ("styles", "./Button.module.scss"),
596                ("tokens", "./tokens.module.css"),
597            ]
598        );
599    }
600
601    #[test]
602    fn exposes_source_input_evidence_through_bridge() {
603        let evidence = summarize_omena_bridge_source_input_evidence(&sample_engine_input());
604
605        assert_eq!(evidence.product, "omena-semantic.source-input-evidence");
606        assert_eq!(evidence.reference_site_identity.status, "ready");
607        assert_eq!(evidence.reference_site_identity.reference_site_count, 1);
608        assert_eq!(evidence.certainty_reason.status, "ready");
609        assert_eq!(evidence.binding_origin.status, "ready");
610        assert!(evidence.blocking_gaps.is_empty());
611    }
612
613    #[test]
614    fn exposes_style_semantic_graph_through_bridge() -> Result<(), String> {
615        let graph = summarize_omena_bridge_style_semantic_graph_from_source(
616            "/tmp/Component.module.scss",
617            ".button { color: red; }",
618            &sample_engine_input(),
619        )
620        .ok_or_else(|| "SCSS module source should parse".to_string())?;
621
622        assert_eq!(graph.product, "omena-semantic.style-semantic-graph");
623        assert_eq!(graph.selector_reference_engine.selector_count, 1);
624        assert_eq!(graph.selector_reference_engine.referenced_selector_count, 1);
625        assert_eq!(
626            graph.source_input_evidence.product,
627            "omena-semantic.source-input-evidence"
628        );
629        assert!(graph.promotion_evidence.blocking_gaps.is_empty());
630        Ok(())
631    }
632
633    #[test]
634    fn exposes_style_semantic_graph_from_source_through_bridge() -> Result<(), String> {
635        let graph = summarize_omena_bridge_style_semantic_graph_from_source(
636            "/tmp/Component.module.scss",
637            r#"@use "./tokens" as tokens; .button { --brand: red; color: var(--brand); color: tokens.$brand; }"#,
638            &sample_engine_input(),
639        )
640        .ok_or_else(|| "bridge should parse SCSS module source".to_string())?;
641
642        assert_eq!(graph.product, "omena-semantic.style-semantic-graph");
643        assert_eq!(
644            graph.parser_facts.custom_properties.decl_names,
645            vec!["--brand".to_string()]
646        );
647        assert_eq!(
648            graph.parser_facts.custom_properties.ref_names,
649            vec!["--brand".to_string()]
650        );
651        assert_eq!(
652            graph.parser_facts.sass.module_use_edges[0].namespace_kind,
653            "alias"
654        );
655        assert_eq!(
656            graph.parser_facts.sass.variable_ref_names,
657            vec!["brand".to_string()]
658        );
659        assert_eq!(
660            graph.selector_reference_engine.style_path,
661            Some("/tmp/Component.module.scss".to_string())
662        );
663        assert_eq!(
664            graph.source_input_evidence.reference_site_identity.status,
665            "ready"
666        );
667        Ok(())
668    }
669
670    #[test]
671    fn collects_design_token_workspace_declarations_from_source_through_bridge() {
672        let declarations = collect_omena_bridge_design_token_workspace_declarations_from_source(
673            "/tmp/tokens.module.scss",
674            r#":root { --brand: red; } .button { --local: blue; color: var(--brand); }"#,
675        );
676
677        assert_eq!(
678            declarations
679                .iter()
680                .map(|declaration| declaration.name.as_str())
681                .collect::<Vec<_>>(),
682            vec!["--brand", "--local"]
683        );
684        assert!(
685            declarations
686                .iter()
687                .all(|declaration| declaration.file_path == "/tmp/tokens.module.scss")
688        );
689        assert_eq!(declarations[0].source_order, 0);
690        assert_eq!(declarations[1].source_order, 1);
691    }
692
693    #[test]
694    fn owns_selector_reference_engine_without_changing_host_product() {
695        let bridge_references = summarize_omena_bridge_selector_reference_engine(
696            &sample_engine_input(),
697            Some("/tmp/Component.module.scss"),
698        );
699        let semantic_references = omena_semantic::summarize_selector_reference_engine(
700            &sample_engine_input(),
701            Some("/tmp/Component.module.scss"),
702        );
703
704        assert_eq!(
705            bridge_references.product,
706            "omena-semantic.selector-references"
707        );
708        assert_eq!(bridge_references.product, semantic_references.product);
709        assert_eq!(bridge_references.style_path, semantic_references.style_path);
710        assert_eq!(
711            bridge_references.selector_count,
712            semantic_references.selector_count
713        );
714        assert_eq!(
715            bridge_references.referenced_selector_count,
716            semantic_references.referenced_selector_count
717        );
718        assert_eq!(
719            bridge_references.total_reference_sites,
720            semantic_references.total_reference_sites
721        );
722        assert_eq!(
723            bridge_references.selectors[0].canonical_id,
724            semantic_references.selectors[0].canonical_id
725        );
726        assert_eq!(
727            bridge_references.selectors[0].editable_direct_reference_count,
728            semantic_references.selectors[0].editable_direct_reference_count
729        );
730    }
731
732    #[test]
733    fn owns_source_input_evidence_without_changing_host_product() {
734        let bridge_evidence = summarize_omena_bridge_source_input_evidence(&sample_engine_input());
735        let semantic_evidence =
736            omena_semantic::summarize_source_input_evidence(&sample_engine_input());
737
738        assert_bridge_source_input_evidence_matches_semantic(&bridge_evidence, &semantic_evidence);
739    }
740
741    #[test]
742    fn owns_source_backed_promotion_evidence_without_changing_host_product() -> Result<(), String> {
743        let boundary = omena_semantic::summarize_omena_parser_style_semantic_boundary_from_source(
744            "/tmp/Component.module.scss",
745            ".button { color: red; }",
746        );
747        let input = sample_engine_input();
748        let bridge_evidence = summarize_omena_bridge_promotion_evidence_with_source_input(
749            &boundary.parser_facts,
750            &boundary.semantic_facts,
751            &input,
752        );
753        let semantic_evidence =
754            omena_semantic::summarize_semantic_promotion_evidence_with_source_input(
755                &boundary.parser_facts,
756                &boundary.semantic_facts,
757                &input,
758            );
759
760        assert_bridge_promotion_evidence_matches_semantic(&bridge_evidence, &semantic_evidence);
761        Ok(())
762    }
763
764    #[test]
765    fn owns_graph_assembly_without_changing_host_product() -> Result<(), String> {
766        let bridge_graph = summarize_omena_bridge_style_semantic_graph_from_source(
767            "/tmp/Component.module.scss",
768            ".button { color: red; }",
769            &sample_engine_input(),
770        )
771        .ok_or_else(|| "bridge should parse SCSS module source".to_string())?;
772        let semantic_graph = omena_semantic::summarize_style_semantic_graph_from_source(
773            "/tmp/Component.module.scss",
774            ".button { color: red; }",
775            &sample_engine_input(),
776        )
777        .ok_or_else(|| "semantic should parse SCSS module source".to_string())?;
778
779        assert_eq!(bridge_graph.product, "omena-semantic.style-semantic-graph");
780        assert_eq!(bridge_graph.product, semantic_graph.product);
781        assert_eq!(bridge_graph.language, semantic_graph.language);
782        assert_eq!(
783            bridge_graph.selector_reference_engine.product,
784            semantic_graph.selector_reference_engine.product
785        );
786        assert_eq!(
787            bridge_graph.selector_reference_engine.selector_count,
788            semantic_graph.selector_reference_engine.selector_count
789        );
790        assert_eq!(
791            bridge_graph.selector_reference_engine.total_reference_sites,
792            semantic_graph
793                .selector_reference_engine
794                .total_reference_sites
795        );
796        assert_bridge_source_input_evidence_matches_semantic(
797            &bridge_graph.source_input_evidence,
798            &semantic_graph.source_input_evidence,
799        );
800        assert_eq!(
801            bridge_graph.design_token_semantics,
802            semantic_graph.design_token_semantics
803        );
804        assert_bridge_promotion_evidence_matches_semantic(
805            &bridge_graph.promotion_evidence,
806            &semantic_graph.promotion_evidence,
807        );
808        Ok(())
809    }
810
811    fn assert_bridge_promotion_evidence_matches_semantic(
812        bridge: &super::SemanticPromotionEvidenceSummaryV0,
813        semantic: &omena_semantic::SemanticPromotionEvidenceSummaryV0,
814    ) {
815        assert_eq!(bridge.schema_version, semantic.schema_version);
816        assert_eq!(bridge.product, semantic.product);
817        assert_eq!(bridge.blocking_gaps, semantic.blocking_gaps);
818        assert_eq!(bridge.next_priorities, semantic.next_priorities);
819        assert_eq!(bridge.items.len(), semantic.items.len());
820
821        for (bridge_item, semantic_item) in bridge.items.iter().zip(&semantic.items) {
822            assert_eq!(bridge_item.evidence, semantic_item.evidence);
823            assert_eq!(bridge_item.status, semantic_item.status);
824            assert_eq!(bridge_item.provider, semantic_item.provider);
825            assert_eq!(bridge_item.observed_count, semantic_item.observed_count);
826            assert_eq!(bridge_item.reason, semantic_item.reason);
827        }
828    }
829
830    fn assert_bridge_source_input_evidence_matches_semantic(
831        bridge: &super::SourceInputPromotionEvidenceSummaryV0,
832        semantic: &omena_semantic::SourceInputPromotionEvidenceSummaryV0,
833    ) {
834        assert_eq!(bridge.schema_version, semantic.schema_version);
835        assert_eq!(bridge.product, semantic.product);
836        assert_eq!(bridge.input_version, semantic.input_version);
837        assert_eq!(
838            bridge.reference_site_identity.status,
839            semantic.reference_site_identity.status
840        );
841        assert_eq!(
842            bridge.reference_site_identity.selector_count,
843            semantic.reference_site_identity.selector_count
844        );
845        assert_eq!(
846            bridge.reference_site_identity.reference_site_count,
847            semantic.reference_site_identity.reference_site_count
848        );
849        assert_eq!(
850            bridge.reference_site_identity.direct_reference_site_count,
851            semantic.reference_site_identity.direct_reference_site_count
852        );
853        assert_eq!(
854            bridge.reference_site_identity.expanded_reference_site_count,
855            semantic
856                .reference_site_identity
857                .expanded_reference_site_count
858        );
859        assert_eq!(
860            bridge
861                .reference_site_identity
862                .style_dependency_reference_site_count,
863            semantic
864                .reference_site_identity
865                .style_dependency_reference_site_count
866        );
867        assert_eq!(
868            bridge.reference_site_identity.editable_direct_site_count,
869            semantic.reference_site_identity.editable_direct_site_count
870        );
871        assert_eq!(
872            bridge.reference_site_identity.reference_kind_counts,
873            semantic.reference_site_identity.reference_kind_counts
874        );
875        assert_eq!(
876            bridge.certainty_reason.status,
877            semantic.certainty_reason.status
878        );
879        assert_eq!(
880            bridge.certainty_reason.expression_count,
881            semantic.certainty_reason.expression_count
882        );
883        assert_eq!(
884            bridge.certainty_reason.exact_count,
885            semantic.certainty_reason.exact_count
886        );
887        assert_eq!(
888            bridge.certainty_reason.inferred_count,
889            semantic.certainty_reason.inferred_count
890        );
891        assert_eq!(
892            bridge.certainty_reason.possible_count,
893            semantic.certainty_reason.possible_count
894        );
895        assert_eq!(
896            bridge.certainty_reason.missing_reason_count,
897            semantic.certainty_reason.missing_reason_count
898        );
899        assert_eq!(
900            bridge.certainty_reason.reason_counts,
901            semantic.certainty_reason.reason_counts
902        );
903        assert_eq!(
904            bridge.certainty_reason.shape_kind_counts,
905            semantic.certainty_reason.shape_kind_counts
906        );
907        assert_eq!(
908            bridge.certainty_reason.shape_label_counts,
909            semantic.certainty_reason.shape_label_counts
910        );
911        assert_eq!(bridge.binding_origin.status, semantic.binding_origin.status);
912        assert_eq!(
913            bridge.binding_origin.expression_count,
914            semantic.binding_origin.expression_count
915        );
916        assert_eq!(
917            bridge.binding_origin.direct_class_name_count,
918            semantic.binding_origin.direct_class_name_count
919        );
920        assert_eq!(
921            bridge.binding_origin.root_binding_count,
922            semantic.binding_origin.root_binding_count
923        );
924        assert_eq!(
925            bridge.binding_origin.access_path_count,
926            semantic.binding_origin.access_path_count
927        );
928        assert_eq!(
929            bridge.binding_origin.access_path_segment_count,
930            semantic.binding_origin.access_path_segment_count
931        );
932        assert_eq!(
933            bridge.binding_origin.expression_kind_counts,
934            semantic.binding_origin.expression_kind_counts
935        );
936        assert_eq!(
937            bridge.style_module_edge.status,
938            semantic.style_module_edge.status
939        );
940        assert_eq!(
941            bridge.style_module_edge.source_style_edge_count,
942            semantic.style_module_edge.source_style_edge_count
943        );
944        assert_eq!(
945            bridge.style_module_edge.distinct_style_module_count,
946            semantic.style_module_edge.distinct_style_module_count
947        );
948        assert_eq!(
949            bridge.style_module_edge.missing_style_document_edge_count,
950            semantic.style_module_edge.missing_style_document_edge_count
951        );
952        assert_eq!(
953            bridge.style_module_edge.composed_edge_count,
954            semantic.style_module_edge.composed_edge_count
955        );
956        assert_eq!(
957            bridge.style_module_edge.imported_composed_edge_count,
958            semantic.style_module_edge.imported_composed_edge_count
959        );
960        assert_eq!(
961            bridge.style_module_edge.global_composed_edge_count,
962            semantic.style_module_edge.global_composed_edge_count
963        );
964        assert_eq!(
965            bridge.value_domain_explanation.status,
966            semantic.value_domain_explanation.status
967        );
968        assert_eq!(
969            bridge.value_domain_explanation.expression_count,
970            semantic.value_domain_explanation.expression_count
971        );
972        assert_eq!(
973            bridge.value_domain_explanation.exact_expression_count,
974            semantic.value_domain_explanation.exact_expression_count
975        );
976        assert_eq!(
977            bridge
978                .value_domain_explanation
979                .finite_value_expression_count,
980            semantic
981                .value_domain_explanation
982                .finite_value_expression_count
983        );
984        assert_eq!(
985            bridge.value_domain_explanation.constrained_expression_count,
986            semantic
987                .value_domain_explanation
988                .constrained_expression_count
989        );
990        assert_eq!(
991            bridge.value_domain_explanation.unknown_expression_count,
992            semantic.value_domain_explanation.unknown_expression_count
993        );
994        assert_eq!(
995            bridge.value_domain_explanation.finite_value_count,
996            semantic.value_domain_explanation.finite_value_count
997        );
998        assert_eq!(
999            bridge.value_domain_explanation.derivation_count,
1000            semantic.value_domain_explanation.derivation_count
1001        );
1002        assert_eq!(
1003            bridge.value_domain_explanation.derivation_step_count,
1004            semantic.value_domain_explanation.derivation_step_count
1005        );
1006        assert_eq!(
1007            bridge.value_domain_explanation.value_domain_kind_counts,
1008            semantic.value_domain_explanation.value_domain_kind_counts
1009        );
1010        assert_eq!(
1011            bridge.value_domain_explanation.constraint_kind_counts,
1012            semantic.value_domain_explanation.constraint_kind_counts
1013        );
1014        assert_eq!(
1015            bridge.value_domain_explanation.derivation_product_counts,
1016            semantic.value_domain_explanation.derivation_product_counts
1017        );
1018        assert_eq!(
1019            bridge
1020                .value_domain_explanation
1021                .derivation_reduced_kind_counts,
1022            semantic
1023                .value_domain_explanation
1024                .derivation_reduced_kind_counts
1025        );
1026        assert_eq!(
1027            bridge.value_domain_explanation.derivation_operation_counts,
1028            semantic
1029                .value_domain_explanation
1030                .derivation_operation_counts
1031        );
1032        assert_eq!(bridge.blocking_gaps, semantic.blocking_gaps);
1033        assert_eq!(bridge.next_priorities, semantic.next_priorities);
1034    }
1035
1036    fn sample_engine_input() -> EngineInputV2 {
1037        EngineInputV2 {
1038            version: "2".to_string(),
1039            sources: vec![SourceAnalysisInputV2 {
1040                document: SourceDocumentV2 {
1041                    class_expressions: vec![ClassExpressionInputV2 {
1042                        id: "expr-literal".to_string(),
1043                        kind: "literal".to_string(),
1044                        scss_module_path: "/tmp/Component.module.scss".to_string(),
1045                        range: range(4, 12, 4, 18),
1046                        class_name: Some("button".to_string()),
1047                        root_binding_decl_id: None,
1048                        access_path: None,
1049                    }],
1050                },
1051            }],
1052            styles: vec![StyleAnalysisInputV2 {
1053                file_path: "/tmp/Component.module.scss".to_string(),
1054                source: None,
1055                document: StyleDocumentV2 {
1056                    selectors: vec![StyleSelectorV2 {
1057                        name: "button".to_string(),
1058                        view_kind: "canonical".to_string(),
1059                        canonical_name: Some("button".to_string()),
1060                        range: range(0, 1, 0, 7),
1061                        nested_safety: Some("flat".to_string()),
1062                        composes: None,
1063                        bem_suffix: None,
1064                    }],
1065                },
1066            }],
1067            type_facts: vec![TypeFactEntryV2 {
1068                file_path: "/tmp/Component.tsx".to_string(),
1069                expression_id: "expr-literal".to_string(),
1070                facts: StringTypeFactsV2 {
1071                    kind: "exact".to_string(),
1072                    constraint_kind: None,
1073                    values: Some(vec!["button".to_string()]),
1074                    prefix: None,
1075                    suffix: None,
1076                    min_len: None,
1077                    max_len: None,
1078                    char_must: None,
1079                    char_may: None,
1080                    may_include_other_chars: None,
1081                    provenance: None,
1082                },
1083                control_flow_graph: None,
1084            }],
1085        }
1086    }
1087
1088    fn range(
1089        start_line: usize,
1090        start_character: usize,
1091        end_line: usize,
1092        end_character: usize,
1093    ) -> RangeV2 {
1094        RangeV2 {
1095            start: PositionV2 {
1096                line: start_line,
1097                character: start_character,
1098            },
1099            end: PositionV2 {
1100                line: end_line,
1101                character: end_character,
1102            },
1103        }
1104    }
1105}