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