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,
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
433    #[test]
434    fn declares_cme_coupled_bridge_boundary() {
435        let boundary = summarize_omena_bridge_boundary();
436
437        assert_eq!(boundary.schema_version, "0");
438        assert_eq!(boundary.product, "omena-bridge.cme-semantic-bridge");
439        assert_eq!(
440            boundary.graph_product,
441            "omena-semantic.style-semantic-graph"
442        );
443        assert_eq!(
444            boundary.delegated_semantic_boundary_product,
445            "omena-semantic.style-semantic-boundary"
446        );
447        assert_eq!(
448            boundary.selector_reference_product,
449            "omena-semantic.selector-references"
450        );
451        assert_eq!(
452            boundary.source_input_evidence_product,
453            "omena-semantic.source-input-evidence"
454        );
455        assert_eq!(
456            boundary.binder_plugin_product,
457            "omena-bridge.binder-plugin-boundary"
458        );
459        assert!(
460            boundary
461                .bridge_owned_surfaces
462                .contains(&"styleSemanticGraphFromSource")
463        );
464        assert!(
465            boundary
466                .bridge_owned_surfaces
467                .contains(&"omenaParserBackedStyleSemanticBoundaryFromSource")
468        );
469        assert!(
470            boundary
471                .bridge_owned_surfaces
472                .contains(&"selectorReferenceEngine")
473        );
474        assert!(
475            boundary
476                .bridge_owned_surfaces
477                .contains(&"designTokenWorkspaceDeclarationsFromSource")
478        );
479        assert!(
480            boundary
481                .bridge_owned_surfaces
482                .contains(&"sourceInputEvidence")
483        );
484        assert!(
485            boundary
486                .bridge_owned_surfaces
487                .contains(&"promotionEvidenceWithSourceInput")
488        );
489        assert!(
490            boundary
491                .bridge_owned_surfaces
492                .contains(&"sourceImportDeclarations")
493        );
494        assert!(boundary.bridge_owned_surfaces.contains(&"styleResolution"));
495        assert!(
496            boundary
497                .bridge_owned_surfaces
498                .contains(&"sourceSyntaxIndex")
499        );
500        assert!(
501            boundary
502                .bridge_owned_surfaces
503                .contains(&"binderPluginBoundary")
504        );
505        assert!(
506            boundary
507                .cme_coupled_surfaces
508                .contains(&"promotionEvidenceWithSourceInput")
509        );
510        assert!(
511            boundary.next_decoupling_targets.is_empty(),
512            "all current omena-bridge decoupling targets should be bridge-owned"
513        );
514    }
515
516    #[test]
517    fn declares_built_in_binder_plugin_boundary() {
518        let boundary = summarize_omena_bridge_binder_plugin_boundary();
519
520        assert_eq!(boundary.schema_version, "0");
521        assert_eq!(boundary.product, "omena-bridge.binder-plugin-boundary");
522        assert_eq!(boundary.contract_name, "BinderPluginV0");
523        assert!(
524            !boundary.external_plugin_abi_stable,
525            "the first boundary cut should not promise a stable external plugin ABI"
526        );
527        assert_eq!(boundary.default_plugin.id, "css-modules-classnames-bind");
528        assert_eq!(boundary.default_plugin.stability, "builtIn");
529        assert!(boundary.default_plugin.domains.contains(&"css-modules"));
530        assert!(
531            boundary
532                .default_plugin
533                .owns_surfaces
534                .contains(&"classReferenceExtraction")
535        );
536        assert!(
537            boundary
538                .default_plugin
539                .utility_targets
540                .contains(&"classnames/bind")
541        );
542        assert!(
543            boundary
544                .request_path_policy
545                .contains(&"pluginOutputFeedsEngineInputV2")
546        );
547        assert!(
548            boundary
549                .request_path_policy
550                .contains(&"styleSourceExtractionIsOptionalForUtilityDomains")
551        );
552        assert!(boundary.built_in_plugins.iter().any(|plugin| {
553            plugin.id == "tailwind-uno-utility-domain"
554                && plugin.domains.contains(&"tailwind-utilities")
555                && plugin
556                    .owns_surfaces
557                    .contains(&"domainClassReferenceExtraction")
558        }));
559        assert!(
560            !boundary
561                .next_plugin_targets
562                .contains(&"tailwind-utility-domain")
563        );
564        assert!(boundary.built_in_plugins.iter().any(|plugin| {
565            plugin.id == "vanilla-extract-recipe-domain"
566                && plugin.domains.contains(&"vanilla-extract-recipes")
567                && plugin
568                    .owns_surfaces
569                    .contains(&"domainClassReferenceExtraction")
570        }));
571        assert!(
572            !boundary
573                .next_plugin_targets
574                .contains(&"vanilla-extract-recipe-domain")
575        );
576        assert!(boundary.built_in_plugins.iter().any(|plugin| {
577            plugin.id == "vue-style-module-domain"
578                && plugin.domains.contains(&"vue-style-modules")
579                && plugin
580                    .owns_surfaces
581                    .contains(&"domainClassReferenceExtraction")
582        }));
583        assert!(
584            boundary.next_plugin_targets.is_empty(),
585            "all planned BinderPluginV0 proof-point domains should now be built in"
586        );
587    }
588
589    #[test]
590    fn summarizes_source_import_declarations_for_css_modules_binding_inputs() {
591        let summary = summarize_omena_bridge_source_import_declarations(
592            r#"
593import bind from "classnames/bind";
594import styles from "./Button.module.scss";
595import * as tokens from "./tokens.module.css";
596import { type BadgeProps } from "./types";
597const lazy = import("./ignored.module.scss");
598"#,
599        );
600
601        assert_eq!(summary.product, "omena-bridge.source-import-declarations");
602        assert_eq!(summary.import_count, 3);
603        assert_eq!(
604            summary
605                .imports
606                .iter()
607                .map(|import| (import.binding.as_str(), import.specifier.as_str()))
608                .collect::<Vec<_>>(),
609            vec![
610                ("bind", "classnames/bind"),
611                ("styles", "./Button.module.scss"),
612                ("tokens", "./tokens.module.css"),
613            ]
614        );
615    }
616
617    #[test]
618    fn exposes_source_input_evidence_through_bridge() {
619        let evidence = summarize_omena_bridge_source_input_evidence(&sample_engine_input());
620
621        assert_eq!(evidence.product, "omena-semantic.source-input-evidence");
622        assert_eq!(evidence.reference_site_identity.status, "ready");
623        assert_eq!(evidence.reference_site_identity.reference_site_count, 1);
624        assert_eq!(evidence.certainty_reason.status, "ready");
625        assert_eq!(evidence.binding_origin.status, "ready");
626        assert!(evidence.blocking_gaps.is_empty());
627    }
628
629    #[test]
630    fn exposes_style_semantic_graph_through_bridge() -> Result<(), String> {
631        let graph = summarize_omena_bridge_style_semantic_graph_from_source(
632            "/tmp/Component.module.scss",
633            ".button { color: red; }",
634            &sample_engine_input(),
635        )
636        .ok_or_else(|| "SCSS module source should parse".to_string())?;
637
638        assert_eq!(graph.product, "omena-semantic.style-semantic-graph");
639        assert_eq!(graph.selector_reference_engine.selector_count, 1);
640        assert_eq!(graph.selector_reference_engine.referenced_selector_count, 1);
641        assert_eq!(
642            graph.source_input_evidence.product,
643            "omena-semantic.source-input-evidence"
644        );
645        assert!(graph.promotion_evidence.blocking_gaps.is_empty());
646        Ok(())
647    }
648
649    #[test]
650    fn exposes_style_semantic_graph_from_source_through_bridge() -> Result<(), String> {
651        let graph = summarize_omena_bridge_style_semantic_graph_from_source(
652            "/tmp/Component.module.scss",
653            r#"@use "./tokens" as tokens; .button { --brand: red; color: var(--brand); color: tokens.$brand; }"#,
654            &sample_engine_input(),
655        )
656        .ok_or_else(|| "bridge should parse SCSS module source".to_string())?;
657
658        assert_eq!(graph.product, "omena-semantic.style-semantic-graph");
659        assert_eq!(
660            graph.parser_facts.custom_properties.decl_names,
661            vec!["--brand".to_string()]
662        );
663        assert_eq!(
664            graph.parser_facts.custom_properties.ref_names,
665            vec!["--brand".to_string()]
666        );
667        assert_eq!(
668            graph.parser_facts.sass.module_use_edges[0].namespace_kind,
669            "alias"
670        );
671        assert_eq!(
672            graph.parser_facts.sass.variable_ref_names,
673            vec!["brand".to_string()]
674        );
675        assert_eq!(
676            graph.selector_reference_engine.style_path,
677            Some("/tmp/Component.module.scss".to_string())
678        );
679        assert_eq!(
680            graph.source_input_evidence.reference_site_identity.status,
681            "ready"
682        );
683        Ok(())
684    }
685
686    #[test]
687    fn collects_design_token_workspace_declarations_from_source_through_bridge() {
688        let declarations = collect_omena_bridge_design_token_workspace_declarations_from_source(
689            "/tmp/tokens.module.scss",
690            r#":root { --brand: red; } .button { --local: blue; color: var(--brand); }"#,
691        );
692
693        assert_eq!(
694            declarations
695                .iter()
696                .map(|declaration| declaration.name.as_str())
697                .collect::<Vec<_>>(),
698            vec!["--brand", "--local"]
699        );
700        assert!(
701            declarations
702                .iter()
703                .all(|declaration| declaration.file_path == "/tmp/tokens.module.scss")
704        );
705        assert_eq!(declarations[0].source_order, 0);
706        assert_eq!(declarations[1].source_order, 1);
707    }
708
709    #[test]
710    fn owns_selector_reference_engine_without_changing_host_product() {
711        let bridge_references = summarize_omena_bridge_selector_reference_engine(
712            &sample_engine_input(),
713            Some("/tmp/Component.module.scss"),
714        );
715        let semantic_references = omena_semantic::summarize_selector_reference_engine(
716            &sample_engine_input(),
717            Some("/tmp/Component.module.scss"),
718        );
719
720        assert_eq!(
721            bridge_references.product,
722            "omena-semantic.selector-references"
723        );
724        assert_eq!(bridge_references.product, semantic_references.product);
725        assert_eq!(bridge_references.style_path, semantic_references.style_path);
726        assert_eq!(
727            bridge_references.selector_count,
728            semantic_references.selector_count
729        );
730        assert_eq!(
731            bridge_references.referenced_selector_count,
732            semantic_references.referenced_selector_count
733        );
734        assert_eq!(
735            bridge_references.total_reference_sites,
736            semantic_references.total_reference_sites
737        );
738        assert_eq!(
739            bridge_references.selectors[0].canonical_id,
740            semantic_references.selectors[0].canonical_id
741        );
742        assert_eq!(
743            bridge_references.selectors[0].editable_direct_reference_count,
744            semantic_references.selectors[0].editable_direct_reference_count
745        );
746    }
747
748    #[test]
749    fn owns_source_input_evidence_without_changing_host_product() {
750        let bridge_evidence = summarize_omena_bridge_source_input_evidence(&sample_engine_input());
751        let semantic_evidence =
752            omena_semantic::summarize_source_input_evidence(&sample_engine_input());
753
754        assert_bridge_source_input_evidence_matches_semantic(&bridge_evidence, &semantic_evidence);
755    }
756
757    #[test]
758    fn owns_source_backed_promotion_evidence_without_changing_host_product() -> Result<(), String> {
759        let boundary = omena_semantic::summarize_omena_parser_style_semantic_boundary_from_source(
760            "/tmp/Component.module.scss",
761            ".button { color: red; }",
762        );
763        let input = sample_engine_input();
764        let bridge_evidence = summarize_omena_bridge_promotion_evidence_with_source_input(
765            &boundary.parser_facts,
766            &boundary.semantic_facts,
767            &input,
768        );
769        let semantic_evidence =
770            omena_semantic::summarize_semantic_promotion_evidence_with_source_input(
771                &boundary.parser_facts,
772                &boundary.semantic_facts,
773                &input,
774            );
775
776        assert_bridge_promotion_evidence_matches_semantic(&bridge_evidence, &semantic_evidence);
777        Ok(())
778    }
779
780    #[test]
781    fn owns_graph_assembly_without_changing_host_product() -> Result<(), String> {
782        let bridge_graph = summarize_omena_bridge_style_semantic_graph_from_source(
783            "/tmp/Component.module.scss",
784            ".button { color: red; }",
785            &sample_engine_input(),
786        )
787        .ok_or_else(|| "bridge should parse SCSS module source".to_string())?;
788        let semantic_graph = omena_semantic::summarize_style_semantic_graph_from_source(
789            "/tmp/Component.module.scss",
790            ".button { color: red; }",
791            &sample_engine_input(),
792        )
793        .ok_or_else(|| "semantic should parse SCSS module source".to_string())?;
794
795        assert_eq!(bridge_graph.product, "omena-semantic.style-semantic-graph");
796        assert_eq!(bridge_graph.product, semantic_graph.product);
797        assert_eq!(bridge_graph.language, semantic_graph.language);
798        assert_eq!(
799            bridge_graph.selector_reference_engine.product,
800            semantic_graph.selector_reference_engine.product
801        );
802        assert_eq!(
803            bridge_graph.selector_reference_engine.selector_count,
804            semantic_graph.selector_reference_engine.selector_count
805        );
806        assert_eq!(
807            bridge_graph.selector_reference_engine.total_reference_sites,
808            semantic_graph
809                .selector_reference_engine
810                .total_reference_sites
811        );
812        assert_bridge_source_input_evidence_matches_semantic(
813            &bridge_graph.source_input_evidence,
814            &semantic_graph.source_input_evidence,
815        );
816        assert_eq!(
817            bridge_graph.design_token_semantics,
818            semantic_graph.design_token_semantics
819        );
820        assert_bridge_promotion_evidence_matches_semantic(
821            &bridge_graph.promotion_evidence,
822            &semantic_graph.promotion_evidence,
823        );
824        Ok(())
825    }
826
827    fn assert_bridge_promotion_evidence_matches_semantic(
828        bridge: &super::SemanticPromotionEvidenceSummaryV0,
829        semantic: &omena_semantic::SemanticPromotionEvidenceSummaryV0,
830    ) {
831        assert_eq!(bridge.schema_version, semantic.schema_version);
832        assert_eq!(bridge.product, semantic.product);
833        assert_eq!(bridge.blocking_gaps, semantic.blocking_gaps);
834        assert_eq!(bridge.next_priorities, semantic.next_priorities);
835        assert_eq!(bridge.items.len(), semantic.items.len());
836
837        for (bridge_item, semantic_item) in bridge.items.iter().zip(&semantic.items) {
838            assert_eq!(bridge_item.evidence, semantic_item.evidence);
839            assert_eq!(bridge_item.status, semantic_item.status);
840            assert_eq!(bridge_item.provider, semantic_item.provider);
841            assert_eq!(bridge_item.observed_count, semantic_item.observed_count);
842            assert_eq!(bridge_item.reason, semantic_item.reason);
843        }
844    }
845
846    fn assert_bridge_source_input_evidence_matches_semantic(
847        bridge: &super::SourceInputPromotionEvidenceSummaryV0,
848        semantic: &omena_semantic::SourceInputPromotionEvidenceSummaryV0,
849    ) {
850        assert_eq!(bridge.schema_version, semantic.schema_version);
851        assert_eq!(bridge.product, semantic.product);
852        assert_eq!(bridge.input_version, semantic.input_version);
853        assert_eq!(
854            bridge.reference_site_identity.status,
855            semantic.reference_site_identity.status
856        );
857        assert_eq!(
858            bridge.reference_site_identity.selector_count,
859            semantic.reference_site_identity.selector_count
860        );
861        assert_eq!(
862            bridge.reference_site_identity.reference_site_count,
863            semantic.reference_site_identity.reference_site_count
864        );
865        assert_eq!(
866            bridge.reference_site_identity.direct_reference_site_count,
867            semantic.reference_site_identity.direct_reference_site_count
868        );
869        assert_eq!(
870            bridge.reference_site_identity.expanded_reference_site_count,
871            semantic
872                .reference_site_identity
873                .expanded_reference_site_count
874        );
875        assert_eq!(
876            bridge
877                .reference_site_identity
878                .style_dependency_reference_site_count,
879            semantic
880                .reference_site_identity
881                .style_dependency_reference_site_count
882        );
883        assert_eq!(
884            bridge.reference_site_identity.editable_direct_site_count,
885            semantic.reference_site_identity.editable_direct_site_count
886        );
887        assert_eq!(
888            bridge.reference_site_identity.reference_kind_counts,
889            semantic.reference_site_identity.reference_kind_counts
890        );
891        assert_eq!(
892            bridge.certainty_reason.status,
893            semantic.certainty_reason.status
894        );
895        assert_eq!(
896            bridge.certainty_reason.expression_count,
897            semantic.certainty_reason.expression_count
898        );
899        assert_eq!(
900            bridge.certainty_reason.exact_count,
901            semantic.certainty_reason.exact_count
902        );
903        assert_eq!(
904            bridge.certainty_reason.inferred_count,
905            semantic.certainty_reason.inferred_count
906        );
907        assert_eq!(
908            bridge.certainty_reason.possible_count,
909            semantic.certainty_reason.possible_count
910        );
911        assert_eq!(
912            bridge.certainty_reason.missing_reason_count,
913            semantic.certainty_reason.missing_reason_count
914        );
915        assert_eq!(
916            bridge.certainty_reason.reason_counts,
917            semantic.certainty_reason.reason_counts
918        );
919        assert_eq!(
920            bridge.certainty_reason.shape_kind_counts,
921            semantic.certainty_reason.shape_kind_counts
922        );
923        assert_eq!(
924            bridge.certainty_reason.shape_label_counts,
925            semantic.certainty_reason.shape_label_counts
926        );
927        assert_eq!(bridge.binding_origin.status, semantic.binding_origin.status);
928        assert_eq!(
929            bridge.binding_origin.expression_count,
930            semantic.binding_origin.expression_count
931        );
932        assert_eq!(
933            bridge.binding_origin.direct_class_name_count,
934            semantic.binding_origin.direct_class_name_count
935        );
936        assert_eq!(
937            bridge.binding_origin.root_binding_count,
938            semantic.binding_origin.root_binding_count
939        );
940        assert_eq!(
941            bridge.binding_origin.access_path_count,
942            semantic.binding_origin.access_path_count
943        );
944        assert_eq!(
945            bridge.binding_origin.access_path_segment_count,
946            semantic.binding_origin.access_path_segment_count
947        );
948        assert_eq!(
949            bridge.binding_origin.expression_kind_counts,
950            semantic.binding_origin.expression_kind_counts
951        );
952        assert_eq!(
953            bridge.style_module_edge.status,
954            semantic.style_module_edge.status
955        );
956        assert_eq!(
957            bridge.style_module_edge.source_style_edge_count,
958            semantic.style_module_edge.source_style_edge_count
959        );
960        assert_eq!(
961            bridge.style_module_edge.distinct_style_module_count,
962            semantic.style_module_edge.distinct_style_module_count
963        );
964        assert_eq!(
965            bridge.style_module_edge.missing_style_document_edge_count,
966            semantic.style_module_edge.missing_style_document_edge_count
967        );
968        assert_eq!(
969            bridge.style_module_edge.composed_edge_count,
970            semantic.style_module_edge.composed_edge_count
971        );
972        assert_eq!(
973            bridge.style_module_edge.imported_composed_edge_count,
974            semantic.style_module_edge.imported_composed_edge_count
975        );
976        assert_eq!(
977            bridge.style_module_edge.global_composed_edge_count,
978            semantic.style_module_edge.global_composed_edge_count
979        );
980        assert_eq!(
981            bridge.value_domain_explanation.status,
982            semantic.value_domain_explanation.status
983        );
984        assert_eq!(
985            bridge.value_domain_explanation.expression_count,
986            semantic.value_domain_explanation.expression_count
987        );
988        assert_eq!(
989            bridge.value_domain_explanation.exact_expression_count,
990            semantic.value_domain_explanation.exact_expression_count
991        );
992        assert_eq!(
993            bridge
994                .value_domain_explanation
995                .finite_value_expression_count,
996            semantic
997                .value_domain_explanation
998                .finite_value_expression_count
999        );
1000        assert_eq!(
1001            bridge.value_domain_explanation.constrained_expression_count,
1002            semantic
1003                .value_domain_explanation
1004                .constrained_expression_count
1005        );
1006        assert_eq!(
1007            bridge.value_domain_explanation.unknown_expression_count,
1008            semantic.value_domain_explanation.unknown_expression_count
1009        );
1010        assert_eq!(
1011            bridge.value_domain_explanation.finite_value_count,
1012            semantic.value_domain_explanation.finite_value_count
1013        );
1014        assert_eq!(
1015            bridge.value_domain_explanation.derivation_count,
1016            semantic.value_domain_explanation.derivation_count
1017        );
1018        assert_eq!(
1019            bridge.value_domain_explanation.derivation_step_count,
1020            semantic.value_domain_explanation.derivation_step_count
1021        );
1022        assert_eq!(
1023            bridge.value_domain_explanation.value_domain_kind_counts,
1024            semantic.value_domain_explanation.value_domain_kind_counts
1025        );
1026        assert_eq!(
1027            bridge.value_domain_explanation.constraint_kind_counts,
1028            semantic.value_domain_explanation.constraint_kind_counts
1029        );
1030        assert_eq!(
1031            bridge.value_domain_explanation.derivation_product_counts,
1032            semantic.value_domain_explanation.derivation_product_counts
1033        );
1034        assert_eq!(
1035            bridge
1036                .value_domain_explanation
1037                .derivation_reduced_kind_counts,
1038            semantic
1039                .value_domain_explanation
1040                .derivation_reduced_kind_counts
1041        );
1042        assert_eq!(
1043            bridge.value_domain_explanation.derivation_operation_counts,
1044            semantic
1045                .value_domain_explanation
1046                .derivation_operation_counts
1047        );
1048        assert_eq!(bridge.blocking_gaps, semantic.blocking_gaps);
1049        assert_eq!(bridge.next_priorities, semantic.next_priorities);
1050    }
1051
1052    fn sample_engine_input() -> EngineInputV2 {
1053        EngineInputV2 {
1054            version: "2".to_string(),
1055            sources: vec![SourceAnalysisInputV2 {
1056                document: SourceDocumentV2 {
1057                    class_expressions: vec![ClassExpressionInputV2 {
1058                        id: "expr-literal".to_string(),
1059                        kind: "literal".to_string(),
1060                        scss_module_path: "/tmp/Component.module.scss".to_string(),
1061                        range: range(4, 12, 4, 18),
1062                        class_name: Some("button".to_string()),
1063                        root_binding_decl_id: None,
1064                        access_path: None,
1065                    }],
1066                },
1067            }],
1068            styles: vec![StyleAnalysisInputV2 {
1069                file_path: "/tmp/Component.module.scss".to_string(),
1070                source: None,
1071                document: StyleDocumentV2 {
1072                    selectors: vec![StyleSelectorV2 {
1073                        name: "button".to_string(),
1074                        view_kind: "canonical".to_string(),
1075                        canonical_name: Some("button".to_string()),
1076                        range: range(0, 1, 0, 7),
1077                        nested_safety: Some("flat".to_string()),
1078                        composes: None,
1079                        bem_suffix: None,
1080                    }],
1081                },
1082            }],
1083            type_facts: vec![TypeFactEntryV2 {
1084                file_path: "/tmp/Component.tsx".to_string(),
1085                expression_id: "expr-literal".to_string(),
1086                facts: StringTypeFactsV2 {
1087                    kind: "exact".to_string(),
1088                    constraint_kind: None,
1089                    values: Some(vec!["button".to_string()]),
1090                    prefix: None,
1091                    suffix: None,
1092                    min_len: None,
1093                    max_len: None,
1094                    char_must: None,
1095                    char_may: None,
1096                    may_include_other_chars: None,
1097                    provenance: None,
1098                },
1099                control_flow_graph: None,
1100            }],
1101        }
1102    }
1103
1104    fn range(
1105        start_line: usize,
1106        start_character: usize,
1107        end_line: usize,
1108        end_character: usize,
1109    ) -> RangeV2 {
1110        RangeV2 {
1111            start: PositionV2 {
1112                line: start_line,
1113                character: start_character,
1114            },
1115            end: PositionV2 {
1116                line: end_line,
1117                character: end_character,
1118            },
1119        }
1120    }
1121}