Skip to main content

omena_bridge/
lib.rs

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