use super::*;
fn style_import_resolutions_for_test(
source_path: &str,
source: &str,
source_language: Option<&str>,
imported_style_bindings: Vec<SourceImportedStyleBindingV0>,
) -> Vec<SourceStyleImportResolutionV0> {
let declarations = summarize_omena_bridge_source_import_declarations_for_source_language(
source_path,
source,
source_language,
);
imported_style_bindings
.into_iter()
.flat_map(|binding| {
declarations
.imports
.iter()
.filter(move |declaration| declaration.binding == binding.binding)
.map(move |declaration| declaration.style_resolution(binding.style_uri.as_str()))
})
.collect()
}
fn summarize_omena_bridge_source_syntax_index(
source: &str,
imported_style_bindings: Vec<SourceImportedStyleBindingV0>,
_classnames_bind_bindings: Vec<String>,
) -> SourceSyntaxIndexV0 {
super::summarize_omena_bridge_source_syntax_index(
source,
style_import_resolutions_for_test("source.tsx", source, None, imported_style_bindings),
)
}
fn summarize_omena_bridge_source_syntax_index_with_type_fact_attempts(
source: &str,
imported_style_bindings: Vec<SourceImportedStyleBindingV0>,
_classnames_bind_bindings: Vec<String>,
) -> SourceSyntaxIndexWithTypeFactAttemptsV0 {
super::summarize_omena_bridge_source_syntax_index_with_type_fact_attempts(
source,
style_import_resolutions_for_test("source.tsx", source, None, imported_style_bindings),
)
}
fn summarize_omena_bridge_source_syntax_index_for_source_language(
source_path: &str,
source: &str,
source_language: Option<&str>,
imported_style_bindings: Vec<SourceImportedStyleBindingV0>,
_classnames_bind_bindings: Vec<String>,
) -> SourceSyntaxIndexV0 {
super::summarize_omena_bridge_source_syntax_index_for_source_language(
source_path,
source,
source_language,
style_import_resolutions_for_test(
source_path,
source,
source_language,
imported_style_bindings,
),
)
}
fn summarize_omena_bridge_source_binding_index(
source: &str,
imported_style_bindings: Vec<SourceImportedStyleBindingV0>,
_classnames_bind_bindings: Vec<String>,
) -> SourceBindingIndexV0 {
super::summarize_omena_bridge_source_binding_index(
source,
style_import_resolutions_for_test("source.tsx", source, None, imported_style_bindings),
)
}
#[test]
fn source_class_splitter_consumes_dom_ordered_tokenization() {
assert_eq!(split_class_names("b a b"), vec!["b", "a"]);
assert_eq!(split_class_names("a\u{00a0}b"), vec!["a\u{00a0}b"]);
}
#[test]
fn inline_style_declaration_identity_uses_standard_property_keys() -> serde_json::Result<()> {
let fact = |property_name: &str| SourceInlineStyleDeclarationFactV0 {
byte_span: ParserByteSpanV0 { start: 0, end: 5 },
value_byte_span: Some(ParserByteSpanV0 { start: 6, end: 9 }),
property_name: AuthoredPropertyTextV0::new(property_name),
value: Some("red".to_string()),
target_style_uri: None,
cascade_tier: "inline-style",
important: false,
static_value: true,
};
let uppercase = fact("COLOR");
let escaped = fact(r"C\4f LOR");
assert_eq!(uppercase, escaped);
assert_eq!(
serde_json::to_value(&uppercase)?.get("propertyName"),
Some(&serde_json::Value::String("COLOR".to_string()))
);
Ok(())
}
#[test]
fn class_tokenizer_migration_table_names_both_previous_splitters()
-> Result<(), Box<dyn std::error::Error>> {
let rows: serde_json::Value =
serde_json::from_str(include_str!("../../data/class-tokenizer-migration-v0.json"))?;
let rows = rows
.as_array()
.ok_or_else(|| std::io::Error::other("class tokenizer migration table must be an array"))?;
assert_eq!(rows.len(), 3);
assert_eq!(rows[0]["site"], "source_syntax::split_class_names");
assert_eq!(rows[1]["site"], "utility_intelligence::class_tokens");
assert_eq!(
rows[2]["site"],
"utility_intelligence::config::collect_safelist"
);
Ok(())
}
#[test]
fn css_identifier_safety_matches_shared_cases() -> Result<(), Box<dyn std::error::Error>> {
let cases: serde_json::Value = serde_json::from_str(include_str!(
"../../../../omena-css-identifier-safety-cases.json"
))?;
let safe = cases["safe"]
.as_array()
.ok_or_else(|| std::io::Error::other("safe identifier cases must be an array"))?;
let unsafe_cases = cases["unsafe"]
.as_array()
.ok_or_else(|| std::io::Error::other("unsafe identifier cases must be an array"))?;
assert!(!safe.is_empty(), "safe identifier cases must not be empty");
assert!(
!unsafe_cases.is_empty(),
"unsafe identifier cases must not be empty"
);
for value in safe {
let value = value
.as_str()
.ok_or_else(|| std::io::Error::other("safe identifier case must be a string"))?;
assert!(is_safe_css_identifier(value), "expected safe: {value:?}");
}
for value in unsafe_cases {
let value = value
.as_str()
.ok_or_else(|| std::io::Error::other("unsafe identifier case must be a string"))?;
assert!(!is_safe_css_identifier(value), "expected unsafe: {value:?}");
}
Ok(())
}
#[test]
fn builds_target_aware_source_syntax_index_for_css_modules_binding_inputs() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
const variants = { primary: "item--primary", icon: "item__icon" };
export function App({ tone }: { tone: "warm" | "cool" }) {
return <div className={clsx("alert", cx("wrapper", variants.primary, `tone-${tone}`))} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
assert_eq!(index.product, "omena-bridge.source-syntax-index");
assert!(index.class_string_literals.is_empty());
assert!(index.selector_references.iter().any(|reference| {
selector_reference_name(source, reference) == "wrapper"
&& reference.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
assert!(index.selector_references.iter().any(|reference| {
reference.selector_name.as_deref() == Some("item--primary")
&& reference.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
assert!(index.selector_references.iter().any(|reference| {
selector_reference_name(source, reference) == "alert"
&& reference.target_style_uri.as_deref().is_none()
}));
assert!(index.type_fact_targets.iter().any(|target| {
&source[target.byte_span.start..target.byte_span.end] == "tone"
&& target.prefix == "tone-"
&& target.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
}
#[test]
fn style_resolution_accepts_only_an_emitted_rust_declaration_identity() {
let source = r#"import styles from "./App.module.scss";
export const view = <div className={styles.root} />;"#;
let declarations = crate::summarize_omena_bridge_source_import_declarations(source);
let real = &declarations.imports[0];
let ghost = SourceStyleImportResolutionV0 {
declaration_id: "rust-decl:import:ghost:0:5:./Ghost.module.scss".to_string(),
style_uri: "file:///workspace/Ghost.module.scss".to_string(),
};
let ghost_index = super::summarize_omena_bridge_source_syntax_index(source, vec![ghost]);
assert!(ghost_index.imported_style_bindings.is_empty());
assert!(
ghost_index
.selector_references
.iter()
.all(|reference| { reference.target_style_uri.is_none() })
);
let real_index = super::summarize_omena_bridge_source_syntax_index(
source,
vec![real.style_resolution("file:///workspace/App.module.scss")],
);
assert_eq!(
real_index.imported_style_bindings,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}]
);
assert!(real_index.selector_references.iter().any(|reference| {
selector_reference_name(source, reference) == "root"
&& reference.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
}
#[test]
fn ambiguous_resolution_for_one_declaration_id_is_not_bound() {
let source = r#"import styles from "./App.module.scss";
export const view = <div className={styles.root} />;"#;
let declarations = crate::summarize_omena_bridge_source_import_declarations(source);
let declaration = &declarations.imports[0];
let index = super::summarize_omena_bridge_source_syntax_index(
source,
vec![
declaration.style_resolution("file:///workspace/App.module.scss"),
declaration.style_resolution("file:///workspace/Other.module.scss"),
],
);
assert!(index.imported_style_bindings.is_empty());
assert!(
index
.selector_references
.iter()
.all(|reference| { reference.target_style_uri.is_none() })
);
}
#[test]
fn incomplete_editor_buffer_keeps_real_binding_without_recovery_expression_fact() {
let source = format!(
r#"// import phantom from "./Phantom.module.scss";
import styles from "./Card.module.scss";
const value = styles.
{}
"#,
(0..24)
.map(|index| format!("const tail{index} = {index};"))
.collect::<Vec<_>>()
.join("\n")
);
let declaration = crate::summarize_omena_bridge_source_import_declarations(source.as_str())
.imports
.into_iter()
.find(|declaration| declaration.binding == "styles");
assert!(
declaration.is_some(),
"Oxc recovery must preserve the real import declaration"
);
let Some(declaration) = declaration else {
return;
};
let resolution = declaration.style_resolution("file:///workspace/Card.module.scss");
let syntax_index = super::summarize_omena_bridge_source_syntax_index(
source.as_str(),
vec![resolution.clone()],
);
let index =
super::summarize_omena_bridge_source_binding_index(source.as_str(), vec![resolution]);
assert_eq!(index.style_import_bindings.len(), 1);
assert_eq!(index.style_import_bindings[0].local_name, "styles");
assert!(
syntax_index.style_property_accesses.is_empty(),
"the inserted recovery identifier must never become a source fact"
);
assert!(
index
.binding_decls
.iter()
.any(|fact| fact.kind == "import" && fact.name == "styles")
);
assert!(
index.binding_decls.iter().all(|fact| fact.name != "tail23"),
"declarations after the recovery boundary are not trusted facts"
);
}
#[test]
fn binding_index_collects_module_specifiers_for_source_dependencies() {
let source = r#"
import styles from "./Button.module.scss";
import { tokens } from "./theme";
export { tokens };
export { palette } from "./named-reexport";
export * from "./reexported";
import legacy = require("./legacy");
"#;
let index = summarize_omena_bridge_source_binding_index(source, Vec::new(), Vec::new());
assert_eq!(
index
.module_specifiers
.iter()
.map(|fact| (fact.kind, fact.specifier.as_str()))
.collect::<Vec<_>>(),
vec![
("export", "./named-reexport"),
("export", "./reexported"),
("import", "./Button.module.scss"),
("import", "./theme"),
("importEquals", "./legacy"),
],
);
}
#[test]
fn collects_html_like_template_literal_class_attributes() {
let source = r#"<main class="root active">
<section class={dynamic}></section>
<span class=""></span>
<script type="module">
const ignored = "class=\"from-script\"";
</script>
</main>
"#;
let index = summarize_omena_bridge_source_syntax_index_for_source_language(
"Page.html",
source,
Some("html"),
Vec::new(),
Vec::new(),
);
let names = index
.selector_references
.iter()
.map(|reference| selector_reference_name(source, reference))
.collect::<Vec<_>>();
assert_eq!(names, vec!["root", "active"]);
assert!(!names.contains(&"{dynamic}"));
assert!(!names.contains(&"from-script"));
}
#[test]
fn collects_server_template_literal_class_attributes() {
let source = r#"{% if enabled %}
<main class="root active">
<script>const ignored = "class=\"from-script\"";</script>
<style>.ignored::before { content: "class=\"from-style\""; }</style>
</main>
{% endif %}
"#;
let index = summarize_omena_bridge_source_syntax_index_for_source_language(
"card.liquid",
source,
Some("liquid"),
Vec::new(),
Vec::new(),
);
let names = index
.selector_references
.iter()
.map(|reference| selector_reference_name(source, reference))
.collect::<Vec<_>>();
assert_eq!(names, vec!["root", "active"]);
assert!(!names.contains(&"from-script"));
assert!(!names.contains(&"from-style"));
}
#[test]
fn masks_liquid_template_class_interpolations_without_shifting_literal_spans() -> Result<(), String>
{
let source = r#"{% if enabled %}
<main class="card {{ modifier }} active"></main>
<section class="{{ modifier }}"></section>
<aside class="card--{{ m }} stable"></aside>
{% endif %}
"#;
let index = summarize_omena_bridge_source_syntax_index_for_source_language(
"card.liquid",
source,
Some("liquid"),
Vec::new(),
Vec::new(),
);
let names = index
.selector_references
.iter()
.map(|reference| selector_reference_name(source, reference))
.collect::<Vec<_>>();
assert_eq!(names, vec!["card", "active", "stable"]);
assert!(!names.contains(&"modifier"));
assert!(!names.contains(&"card--"));
for expected in ["card", "active", "stable"] {
let reference = index
.selector_references
.iter()
.find(|reference| selector_reference_name(source, reference) == expected)
.ok_or_else(|| format!("literal selector reference is emitted for {expected}"))?;
assert_eq!(
&source[reference.byte_span.start..reference.byte_span.end],
expected
);
}
Ok(())
}
#[test]
fn masks_server_template_delimiter_families_in_literal_class_attributes() {
let cases = [
(
"page.twig",
Some("twig"),
r#"<main class="card {{ modifier }} active item--{{ m }}"></main>"#,
vec!["card", "active"],
),
(
"page.njk",
Some("nunjucks"),
r#"<main class="card {% if active %} active {% endif %} item--{{ m }}"></main>"#,
vec!["card", "active"],
),
(
"page.django-html",
Some("django-html"),
r#"<main class="card {# ignored #} active item--{{ m }}"></main>"#,
vec!["card", "active"],
),
(
"page.jinja",
Some("jinja"),
r#"<main class="card {{ modifier }} active item--{{ m }}"></main>"#,
vec!["card", "active"],
),
(
"page.erb",
Some("erb"),
r#"<main class="card <%= modifier %> active item--<%= m %>"></main>"#,
vec!["card", "active"],
),
(
"page.ejs",
Some("ejs"),
r#"<main class="card <%- modifier %> active item--<%= m %>"></main>"#,
vec!["card", "active"],
),
(
"page.html.eex",
Some("html-eex"),
r#"<main class="card <%= modifier %> active item--<%= m %>"></main>"#,
vec!["card", "active"],
),
(
"page.heex",
Some("heex"),
r#"<main class="card <%= modifier %> active item--<%= m %>"></main>"#,
vec!["card", "active"],
),
(
"page.hbs",
Some("handlebars"),
r#"<main class="card {{{modifier}}} active item--{{m}}"></main>"#,
vec!["card", "active"],
),
(
"page.njk",
None,
r#"<main class="card {{ modifier }} active item--{{ m }}"></main>"#,
vec!["card", "active"],
),
];
for (source_path, source_language, source, expected) in cases {
let index = summarize_omena_bridge_source_syntax_index_for_source_language(
source_path,
source,
source_language,
Vec::new(),
Vec::new(),
);
let names = index
.selector_references
.iter()
.map(|reference| selector_reference_name(source, reference))
.collect::<Vec<_>>();
assert_eq!(names, expected, "{source_path}");
}
}
#[test]
fn collects_template_style_binding_class_expressions() {
let source = r#"<template>
<section class={styles.root}></section>
<section :class="styles['item--primary']"></section>
<section v-bind:class="styles.icon"></section>
</template>
<script setup lang="ts">
import styles from "./Card.module.css";
</script>
"#;
let index = summarize_omena_bridge_source_syntax_index_for_source_language(
"Card.vue",
source,
Some("vue"),
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/Card.vue".to_string(),
}],
Vec::new(),
);
for expected in ["root", "item--primary", "icon"] {
assert!(index.selector_references.iter().any(|reference| {
selector_reference_name(source, reference) == expected
&& reference.target_style_uri.as_deref() == Some("file:///workspace/Card.vue")
}));
}
}
#[test]
fn collects_markdown_inline_html_classes_without_scanning_prose_or_code() {
let source = r#"# Notes
The prose says class="from-prose" but it is not an HTML block.
<main class="root active">
<section
class="card"
></section>
</main>
<span class="from-indented-code"></span>
```html
<span class="from-fence"></span>
```
"#;
let index = summarize_omena_bridge_source_syntax_index_for_source_language(
"Notes.md",
source,
Some("markdown"),
Vec::new(),
Vec::new(),
);
let names = index
.selector_references
.iter()
.map(|reference| selector_reference_name(source, reference))
.collect::<Vec<_>>();
assert_eq!(names, vec!["root", "active", "card"]);
}
#[test]
fn collects_variant_recipe_universes_and_domain_references() -> Result<(), String> {
let source = r#"import { cva } from "class-variance-authority";
const button = cva("btn", {
variants: {
intent: {
primary: "btn-primary",
secondary: ["btn-secondary"],
},
},
});
button({ intent: "primary" });
button({ intent: "ghost" });
"#;
let index = summarize_omena_bridge_source_syntax_index(source, Vec::new(), Vec::new());
let universe = index
.class_value_universes
.iter()
.find(|universe| universe.owner_name == "button")
.ok_or_else(|| "cva recipe should create a class value universe".to_string())?;
assert_eq!(universe.plugin_id, "cva-recipe-domain");
assert_eq!(universe.domain, "cva-recipe");
assert!(universe.class_names.contains(&"btn".to_string()));
assert!(universe.class_names.contains(&"btn-primary".to_string()));
assert!(universe.class_names.contains(&"btn-secondary".to_string()));
assert!(universe.axes.iter().any(|axis| {
axis.axis_name == "intent"
&& axis.values == vec!["primary".to_string(), "secondary".to_string()]
}));
let referenced_options = index
.domain_class_references
.iter()
.filter(|reference| reference.owner_name == "button" && reference.axis_name == "intent")
.filter_map(|reference| reference.option_name.as_deref())
.collect::<Vec<_>>();
assert_eq!(referenced_options, vec!["primary", "ghost"]);
Ok(())
}
#[test]
fn shadowed_local_does_not_resolve_variant_recipe_call() -> Result<(), String> {
let source = r#"import { cva } from "class-variance-authority";
const button = cva("btn", {
variants: {
intent: {
primary: "btn-primary",
},
},
});
export function View(button: (input: unknown) => string) {
button({ intent: "primary" });
}"#;
let index = summarize_omena_bridge_source_syntax_index(source, Vec::new(), Vec::new());
assert!(
index.domain_class_references.is_empty(),
"shadowed button call must not resolve to the recipe binding"
);
assert!(
index
.class_value_universes
.iter()
.any(|universe| universe.owner_name == "button"),
"the recipe declaration should still produce its universe"
);
Ok(())
}
#[test]
fn renamed_variant_recipe_import_still_resolves_calls_by_identity() -> Result<(), String> {
let source = r#"import { cva as makeRecipe } from "class-variance-authority";
const renamedButton = makeRecipe("btn", {
variants: {
intent: {
primary: "btn-primary",
},
},
});
renamedButton({ intent: "primary" });
"#;
let index = summarize_omena_bridge_source_syntax_index(source, Vec::new(), Vec::new());
let universe = index
.class_value_universes
.iter()
.find(|universe| universe.owner_name == "renamedButton")
.ok_or_else(|| "renamed recipe should create a class value universe".to_string())?;
assert_eq!(universe.plugin_id, "cva-recipe-domain");
assert!(index.domain_class_references.iter().any(|reference| {
reference.owner_name == "renamedButton"
&& reference.axis_name == "intent"
&& reference.option_name.as_deref() == Some("primary")
}));
Ok(())
}
#[test]
fn collects_style_property_accesses_from_oxc_ast() {
let source = r#"import styles from "./App.module.scss";
const text = "styles.fake";
export function View() {
return <div className={styles.root} data-token={styles["item--primary"]} data-mode={styles["md\\:flex"]} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
Vec::new(),
);
let access_names = index
.style_property_accesses
.iter()
.map(|access| &source[access.byte_span.start..access.byte_span.end])
.collect::<Vec<_>>();
assert_eq!(access_names, vec!["root", "item--primary", r#"md\\:flex"#]);
assert!(index.style_property_accesses.iter().all(|access| {
access.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
assert!(
!index
.selector_references
.iter()
.any(|reference| selector_reference_name(source, reference) == "fake")
);
assert!(index.selector_references.iter().any(|reference| {
reference.selector_name.as_deref() == Some(r#"md\:flex"#)
&& &source[reference.byte_span.start..reference.byte_span.end] == r#"md\\:flex"#
}));
}
#[test]
fn symbol_resolver_distinguishes_import_binding_from_shadowing_parameter() -> Result<(), String> {
let source = r#"import styles from "./App.module.scss";
function render(styles: Record<string, string>) {
return styles.button;
}"#;
let allocator = Allocator::default();
let ParserReturn {
program, panicked, ..
} = Parser::new(
&allocator,
source,
source_type_for_language("source.tsx", None),
)
.parse();
if panicked {
return Err("fixture parse panicked".to_string());
}
let semantic = SemanticBuilder::new().build(&program).semantic;
let scoping = semantic.scoping();
let import_symbol = program
.body
.iter()
.find_map(|statement| {
let Statement::ImportDeclaration(import) = statement else {
return None;
};
import.specifiers.as_ref()?.iter().find_map(|specifier| {
let ImportDeclarationSpecifier::ImportDefaultSpecifier(specifier) = specifier
else {
return None;
};
(specifier.local.name.as_str() == "styles")
.then(|| binding_identifier_symbol_id(&specifier.local))
.flatten()
})
})
.ok_or_else(|| "import styles symbol should exist".to_string())?;
let (parameter_symbol, object_reference_symbol) = program
.body
.iter()
.find_map(|statement| {
let Statement::FunctionDeclaration(function) = statement else {
return None;
};
let parameter = function.params.items.first()?;
let parameter_symbol =
binding_identifier_symbol_id(binding_pattern_identifier(¶meter.pattern)?)?;
let body = function.body.as_ref()?;
let return_statement = body.statements.iter().find_map(|statement| {
let Statement::ReturnStatement(statement) = statement else {
return None;
};
statement.argument.as_ref()
})?;
let Expression::StaticMemberExpression(member) = return_statement else {
return None;
};
let Expression::Identifier(identifier) = &member.object else {
return None;
};
let object_reference_symbol = reference_symbol_id(scoping, identifier)?;
Some((parameter_symbol, object_reference_symbol))
})
.ok_or_else(|| {
"shadowing parameter and styles.button reference should exist".to_string()
})?;
assert_ne!(import_symbol, parameter_symbol);
assert_eq!(object_reference_symbol, parameter_symbol);
Ok(())
}
#[test]
fn shadowed_parameter_does_not_bind_import_styles_property_access() {
let source = r#"import styles from "./App.module.scss";
export function View(styles: Record<string, string>) {
return <div className={styles.root} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
Vec::new(),
);
assert!(
index.style_property_accesses.iter().all(|access| {
&source[access.byte_span.start..access.byte_span.end] != "root"
|| access.target_style_uri.as_deref() != Some("file:///workspace/App.module.scss")
}),
"shadowed parameter styles.root must not bind to the import"
);
}
#[test]
fn unresolved_style_reference_does_not_fall_back_to_import_name() {
let source = r#"export function View() {
return <div className={styles.root} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
Vec::new(),
);
assert!(
index.style_property_accesses.is_empty(),
"unresolved styles reference must stay Unknown instead of using a name fallback"
);
}
#[test]
fn renamed_style_import_still_binds_property_access_by_identity() {
let source = r#"import moduleStyles from "./App.module.scss";
export function View() {
return <div className={moduleStyles.root} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "moduleStyles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
Vec::new(),
);
assert!(index.style_property_accesses.iter().any(|access| {
&source[access.byte_span.start..access.byte_span.end] == "root"
&& access.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
}
#[test]
fn collects_inline_style_declarations_from_jsx_style_prop() {
let source = r#"import styles from "./App.module.scss";
const token = "dynamic";
export function View() {
return <div className={styles.root} style={{ color: "red", borderColor: `blue`, "--brand": token }} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
Vec::new(),
);
let declarations = index
.inline_style_declarations
.iter()
.map(|declaration| {
(
{
let mut property_name = String::new();
let render_result = omena_syntax::ident::render_authored(
&declaration.property_name,
&mut property_name,
);
assert!(render_result.is_ok(), "writing into a String must succeed");
property_name
},
declaration.value.as_deref(),
declaration.cascade_tier,
declaration.static_value,
declaration.target_style_uri.as_deref(),
)
})
.collect::<Vec<_>>();
assert_eq!(
declarations,
vec![
(
"color".to_string(),
Some("\"red\""),
"authorInlineStyle",
true,
Some("file:///workspace/App.module.scss")
),
(
"border-color".to_string(),
Some("`blue`"),
"authorInlineStyle",
true,
Some("file:///workspace/App.module.scss")
),
(
"--brand".to_string(),
None,
"authorInlineStyle",
false,
Some("file:///workspace/App.module.scss")
),
]
);
}
#[test]
fn records_inline_important_as_a_source_text_observation() {
let source = r#"import styles from "./App.module.scss";
export function View() {
return <div className={styles.root} style={{ color: "red !IMPORTANT", opacity: 0.5 }} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
Vec::new(),
);
assert_eq!(index.inline_style_declarations.len(), 2);
assert!(
index.inline_style_declarations[0].important_suffix_present(),
"the unquoted StringLiteral value carries the source-text suffix"
);
assert!(!index.inline_style_declarations[1].important_suffix_present());
}
#[test]
fn walks_anonymous_arrow_default_export_body_for_style_property_accesses() {
for body in [
"() => <i className={styles.used} />",
"() => { return <i className={styles.used} />; }",
"() => (<i className={styles.used} />)",
] {
let source = format!("import styles from \"./App.module.scss\";\nexport default {body};");
let index = summarize_omena_bridge_source_syntax_index(
&source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
Vec::new(),
);
assert!(
index
.style_property_accesses
.iter()
.any(|access| &source[access.byte_span.start..access.byte_span.end] == "used"),
"anon-arrow default export should collect styles.used: {body}",
);
assert!(
!index
.selector_references
.iter()
.any(|reference| selector_reference_name(&source, reference) == "ghost"),
"no phantom references should appear: {body}",
);
}
}
#[test]
fn collects_classnames_bind_utility_bindings_from_oxc_ast() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind((styles));
export const view = <div className={cx("root")} />;"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
assert!(index.selector_references.iter().any(|reference| {
selector_reference_name(source, reference) == "root"
&& reference.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
}
#[test]
fn shadowed_local_does_not_bind_classnames_bind_import() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
export function View(cx: (...args: string[]) => string) {
return <div className={cx("root")} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
assert!(
index.selector_references.iter().all(|reference| {
selector_reference_name(source, reference) != "root"
|| reference.target_style_uri.as_deref()
!= Some("file:///workspace/App.module.scss")
}),
"shadowed cx call must not bind to the classnames/bind utility"
);
}
#[test]
fn renamed_classnames_bind_import_and_style_import_still_bind_by_identity() {
let source = r#"import renamedBind from "classnames/bind";
import moduleStyles from "./App.module.scss";
const cx = renamedBind.bind(moduleStyles);
export const view = <div className={cx("root")} />;"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "moduleStyles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["renamedBind".to_string()],
);
assert!(index.selector_references.iter().any(|reference| {
selector_reference_name(source, reference) == "root"
&& reference.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
}
#[test]
fn summarizes_classnames_bind_utility_binding_identity_for_binding_index() {
let source = r#"import renamedBind from "classnames/bind";
import moduleStyles from "./App.module.scss";
const cx = renamedBind.bind(moduleStyles);
const localClass = "root";
export const view = <div className={cx(localClass, moduleStyles.icon)} />;"#;
let index = summarize_omena_bridge_source_binding_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "moduleStyles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["renamedBind".to_string()],
);
assert_eq!(index.product, "omena-bridge.source-binding-index");
let renamed_bind_decl_start = source.find("renamedBind").unwrap_or(usize::MAX);
assert_ne!(renamed_bind_decl_start, usize::MAX);
let module_styles_decl_start = source.find("moduleStyles").unwrap_or(usize::MAX);
assert_ne!(module_styles_decl_start, usize::MAX);
let cx_decl_start = source.find("cx =").unwrap_or(usize::MAX);
assert_ne!(cx_decl_start, usize::MAX);
let local_decl_start = source.find("localClass =").unwrap_or(usize::MAX);
assert_ne!(local_decl_start, usize::MAX);
let view_decl_start = source.find("view =").unwrap_or(usize::MAX);
assert_ne!(view_decl_start, usize::MAX);
let source_scope = ParserByteSpanV0 {
start: 0,
end: source.len(),
};
let style_declaration_id = crate::summarize_omena_bridge_source_import_declarations(source)
.imports
.into_iter()
.find(|declaration| declaration.binding == "moduleStyles")
.map(|declaration| declaration.declaration_id)
.unwrap_or_default();
assert!(!style_declaration_id.is_empty());
let cx_declaration_id = source_declaration_id(
source,
"localVar",
"cx",
cx_decl_start,
cx_decl_start + "cx".len(),
"",
);
assert_eq!(
index.binding_scopes,
vec![SourceBindingScopeFactV0 {
kind: "sourceFile",
byte_span: source_scope,
}]
);
assert!(index.scope_parent_edges.is_empty());
assert_eq!(
index.binding_decls,
vec![
SourceBindingDeclFactV0 {
kind: "import",
name: "moduleStyles".to_string(),
byte_span: ParserByteSpanV0 {
start: module_styles_decl_start,
end: module_styles_decl_start + "moduleStyles".len(),
},
import_path: Some("./App.module.scss".to_string()),
},
SourceBindingDeclFactV0 {
kind: "import",
name: "renamedBind".to_string(),
byte_span: ParserByteSpanV0 {
start: renamed_bind_decl_start,
end: renamed_bind_decl_start + "renamedBind".len(),
},
import_path: Some("classnames/bind".to_string()),
},
SourceBindingDeclFactV0 {
kind: "localVar",
name: "cx".to_string(),
byte_span: ParserByteSpanV0 {
start: cx_decl_start,
end: cx_decl_start + "cx".len(),
},
import_path: None,
},
SourceBindingDeclFactV0 {
kind: "localVar",
name: "localClass".to_string(),
byte_span: ParserByteSpanV0 {
start: local_decl_start,
end: local_decl_start + "localClass".len(),
},
import_path: None,
},
SourceBindingDeclFactV0 {
kind: "localVar",
name: "view".to_string(),
byte_span: ParserByteSpanV0 {
start: view_decl_start,
end: view_decl_start + "view".len(),
},
import_path: None,
},
]
);
assert_eq!(
index.scope_contains_decls,
vec![
SourceScopeContainsDeclFactV0 {
scope_kind: "sourceFile",
scope_byte_span: source_scope,
decl_kind: "import",
decl_name: "moduleStyles".to_string(),
decl_byte_span: ParserByteSpanV0 {
start: module_styles_decl_start,
end: module_styles_decl_start + "moduleStyles".len(),
},
import_path: Some("./App.module.scss".to_string()),
},
SourceScopeContainsDeclFactV0 {
scope_kind: "sourceFile",
scope_byte_span: source_scope,
decl_kind: "import",
decl_name: "renamedBind".to_string(),
decl_byte_span: ParserByteSpanV0 {
start: renamed_bind_decl_start,
end: renamed_bind_decl_start + "renamedBind".len(),
},
import_path: Some("classnames/bind".to_string()),
},
SourceScopeContainsDeclFactV0 {
scope_kind: "sourceFile",
scope_byte_span: source_scope,
decl_kind: "localVar",
decl_name: "cx".to_string(),
decl_byte_span: ParserByteSpanV0 {
start: cx_decl_start,
end: cx_decl_start + "cx".len(),
},
import_path: None,
},
SourceScopeContainsDeclFactV0 {
scope_kind: "sourceFile",
scope_byte_span: source_scope,
decl_kind: "localVar",
decl_name: "localClass".to_string(),
decl_byte_span: ParserByteSpanV0 {
start: local_decl_start,
end: local_decl_start + "localClass".len(),
},
import_path: None,
},
SourceScopeContainsDeclFactV0 {
scope_kind: "sourceFile",
scope_byte_span: source_scope,
decl_kind: "localVar",
decl_name: "view".to_string(),
decl_byte_span: ParserByteSpanV0 {
start: view_decl_start,
end: view_decl_start + "view".len(),
},
import_path: None,
},
]
);
assert_eq!(
index.style_import_bindings,
vec![SourceBindingStyleImportFactV0 {
declaration_id: style_declaration_id,
local_name: "moduleStyles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}]
);
assert_eq!(
index.declares_style_imports,
vec![SourceDeclaresStyleImportFactV0 {
decl_name: "moduleStyles".to_string(),
styles_local_name: "moduleStyles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}]
);
assert_eq!(
index.style_import_resolves_modules,
vec![SourceStyleImportResolvesModuleFactV0 {
styles_local_name: "moduleStyles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}]
);
let local_start = source.rfind("localClass").unwrap_or(usize::MAX);
assert_ne!(local_start, usize::MAX);
let icon_start = source.find("icon").unwrap_or(usize::MAX);
assert_ne!(icon_start, usize::MAX);
assert_eq!(
index.expression_targets_modules,
vec![
SourceExpressionTargetsModuleFactV0 {
byte_span: ParserByteSpanV0 {
start: local_start,
end: local_start + "localClass".len(),
},
target_style_uri: "file:///workspace/App.module.scss".to_string(),
},
SourceExpressionTargetsModuleFactV0 {
byte_span: ParserByteSpanV0 {
start: icon_start,
end: icon_start + "icon".len(),
},
target_style_uri: "file:///workspace/App.module.scss".to_string(),
},
]
);
assert_eq!(
index.class_expression_nodes,
vec![
SourceClassExpressionNodeFactV0 {
kind: "symbolRef",
byte_span: ParserByteSpanV0 {
start: local_start,
end: local_start + "localClass".len(),
},
target_style_uri: "file:///workspace/App.module.scss".to_string(),
},
SourceClassExpressionNodeFactV0 {
kind: "styleAccess",
byte_span: ParserByteSpanV0 {
start: icon_start,
end: icon_start + "icon".len(),
},
target_style_uri: "file:///workspace/App.module.scss".to_string(),
},
]
);
assert_eq!(
index.classnames_bind_utility_bindings,
vec![SourceClassnamesBindUtilityBindingFactV0 {
declaration_id: cx_declaration_id.clone(),
local_name: "cx".to_string(),
styles_local_name: "moduleStyles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
classnames_import_name: "renamedBind".to_string(),
}]
);
assert_eq!(
index.declares_utility_bindings,
vec![SourceDeclaresUtilityBindingFactV0 {
declaration_id: cx_declaration_id,
decl_name: "cx".to_string(),
utility_local_name: "cx".to_string(),
utility_kind: "classnamesBind",
}]
);
assert_eq!(
index.utility_uses_style_imports,
vec![SourceUtilityUsesStyleImportFactV0 {
utility_local_name: "cx".to_string(),
styles_local_name: "moduleStyles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}]
);
assert_eq!(
index.style_access_uses_style_imports,
vec![SourceStyleAccessUsesStyleImportFactV0 {
byte_span: ParserByteSpanV0 {
start: icon_start,
end: icon_start + "icon".len(),
},
decl_name: "moduleStyles".to_string(),
styles_local_name: "moduleStyles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}]
);
assert_eq!(
index.symbol_ref_uses_decls,
vec![SourceSymbolRefUsesDeclFactV0 {
byte_span: ParserByteSpanV0 {
start: local_start,
end: local_start + "localClass".len(),
},
raw_reference: "localClass".to_string(),
root_name: "localClass".to_string(),
decl_name: "localClass".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}]
);
}
#[test]
fn binding_index_projects_dynamic_classnames_symbol_refs_without_selector_literals() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
export function App({ status }: { status: string }) {
const statusClass = resolveStatus(status);
return <div className={cx(statusClass)} />;
}"#;
let index = summarize_omena_bridge_source_binding_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
let reference_start = source.rfind("statusClass").unwrap_or(usize::MAX);
assert_ne!(reference_start, usize::MAX);
let reference_span = ParserByteSpanV0 {
start: reference_start,
end: reference_start + "statusClass".len(),
};
assert!(index.class_expression_nodes.iter().any(|expression| {
expression.kind == "symbolRef"
&& expression.byte_span == reference_span
&& expression.target_style_uri == "file:///workspace/App.module.scss"
}));
assert!(index.expression_targets_modules.iter().any(|edge| {
edge.byte_span == reference_span
&& edge.target_style_uri == "file:///workspace/App.module.scss"
}));
assert!(index.symbol_ref_uses_decls.iter().any(|edge| {
edge.byte_span == reference_span
&& edge.root_name == "statusClass"
&& edge.decl_name == "statusClass"
&& edge.style_uri == "file:///workspace/App.module.scss"
}));
}
#[test]
fn does_not_treat_object_shorthand_aliases_as_static_class_values() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
export function View({ primary }: { primary: "medium" | "small" }) {
const variants = { primary };
return <div className={cx(variants.primary)} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
assert!(!index.selector_references.iter().any(|reference| {
selector_reference_name(source, reference) == "primary"
&& reference.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
assert!(index.type_fact_targets.iter().any(|target| {
&source[target.byte_span.start..target.byte_span.end] == "variants.primary"
&& target.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
}
#[test]
fn merges_class_value_reassignments_into_symbol_selector_references() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
export function View({ enabled }: { enabled: boolean }) {
let size = "card";
if (enabled) {
size = "card--active";
}
return <div className={cx(size)} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
let size_references = index
.selector_references
.iter()
.filter(|reference| &source[reference.byte_span.start..reference.byte_span.end] == "size")
.collect::<Vec<_>>();
assert!(size_references.iter().any(|reference| {
reference.selector_name.as_deref() == Some("card")
&& reference.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
assert!(size_references.iter().any(|reference| {
reference.selector_name.as_deref() == Some("card--active")
&& reference.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
}
#[test]
fn keeps_template_prefix_selector_references_as_atomic_flat_class_prefixes() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
export function View({ fontSize }: { fontSize: 10 | 12 }) {
return <div className={cx(`font-size-${fontSize}`)} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
let reference_names = index
.selector_references
.iter()
.filter(|reference| {
reference.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
})
.map(|reference| selector_reference_name(source, reference))
.collect::<Vec<_>>();
assert!(reference_names.contains(&"font-size-"));
assert!(!reference_names.contains(&"font"));
assert!(!reference_names.contains(&"-size"));
assert!(index.type_fact_targets.iter().any(|target| {
&source[target.byte_span.start..target.byte_span.end] == "fontSize"
&& target.prefix == "font-size-"
&& target.suffix.is_empty()
&& target.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
}));
}
#[test]
fn records_template_interpolations_that_cannot_reach_the_type_fact_provider()
-> Result<(), Box<dyn std::error::Error>> {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
export function View({ active }: { active: boolean }) {
return <div className={cx(`theme-${active ? "a" : "legacy"}`)} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
let value = serde_json::to_value(index)?;
let skipped = value
.get("typeFactTargetSkipped")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| {
std::io::Error::other(
"unsupported template interpolation should produce a structured skipped fact",
)
})?;
assert_eq!(skipped.len(), 1);
assert_eq!(
skipped[0].get("reason").and_then(serde_json::Value::as_str),
Some("lexicallyResolvedExpression")
);
assert_eq!(
value
.get("typeFactTargetSkippedCount")
.and_then(serde_json::Value::as_u64),
Some(1)
);
Ok(())
}
#[test]
fn records_one_lexical_attempt_for_every_expression_shape() -> Result<(), String> {
let fixture: serde_json::Value = serde_json::from_str(include_str!(
"../../tests/fixtures/source-type-fact-expression-shapes.json"
))
.map_err(|error| error.to_string())?;
let fixtures = fixture
.get("fixtures")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| "expression-shape fixtures must be an array".to_string())?;
let expected = [
(
"identifier-path",
SourceTypeFactExpressionShapeV0::IdentifierPath,
SourceTypeFactLexicalDispositionV0::TypeProviderCandidate,
None,
),
(
"finite-conditional",
SourceTypeFactExpressionShapeV0::LexicallyEnumerable,
SourceTypeFactLexicalDispositionV0::Resolved,
Some("lexicallyResolvedExpression"),
),
(
"call-expression",
SourceTypeFactExpressionShapeV0::Call,
SourceTypeFactLexicalDispositionV0::Unresolved,
Some("unsupportedCallExpression"),
),
(
"arithmetic-expression",
SourceTypeFactExpressionShapeV0::Arithmetic,
SourceTypeFactLexicalDispositionV0::Unresolved,
Some("unsupportedArithmeticExpression"),
),
(
"logical-expression",
SourceTypeFactExpressionShapeV0::LogicalOperator,
SourceTypeFactLexicalDispositionV0::Unresolved,
Some("unsupportedLogicalExpression"),
),
(
"computed-member",
SourceTypeFactExpressionShapeV0::ComputedNonLiteral,
SourceTypeFactLexicalDispositionV0::Unresolved,
Some("unsupportedComputedMemberExpression"),
),
(
"nested-template",
SourceTypeFactExpressionShapeV0::NestedTemplate,
SourceTypeFactLexicalDispositionV0::Unresolved,
Some("unsupportedNestedTemplateExpression"),
),
(
"multiple-interpolations",
SourceTypeFactExpressionShapeV0::MultiInterpolation,
SourceTypeFactLexicalDispositionV0::Unresolved,
Some("unsupportedMultipleTemplateInterpolations"),
),
(
"aggregate-expression",
SourceTypeFactExpressionShapeV0::Other,
SourceTypeFactLexicalDispositionV0::Unresolved,
Some("unsupportedExpressionShape"),
),
];
for (id, shape, disposition, skipped_reason) in expected {
let source = fixtures
.iter()
.find(|fixture| fixture.get("id").and_then(serde_json::Value::as_str) == Some(id))
.and_then(|fixture| fixture.get("source"))
.and_then(serde_json::Value::as_str)
.ok_or_else(|| format!("missing source fixture {id}"))?;
let result = summarize_omena_bridge_source_syntax_index_with_type_fact_attempts(
source,
Vec::new(),
Vec::new(),
);
assert_eq!(
result.type_fact_attempts.len(),
1,
"{id} must produce exactly one lexical attempt"
);
assert_eq!(result.type_fact_attempts[0].shape_class, shape, "{id}");
assert_eq!(
result.type_fact_attempts[0].lexical_disposition, disposition,
"{id}"
);
match skipped_reason {
Some(reason) => {
assert_eq!(
result
.source_syntax_index
.type_fact_target_skipped
.as_slice(),
&[SourceTypeFactTargetSkippedFactV0 {
byte_span: result.type_fact_attempts[0].byte_span,
expression_id: result.type_fact_attempts[0].expression_id.clone(),
target_style_uri: None,
reason,
}],
"{id}"
);
}
None => {
assert_eq!(
result.source_syntax_index.type_fact_targets.len(),
1,
"{id}"
);
assert!(
result
.source_syntax_index
.type_fact_target_skipped
.is_empty(),
"{id}"
);
}
}
}
Ok(())
}
#[test]
fn records_const_asserted_nested_template_as_the_exact_attempt_span() {
let source = r#"declare const nestedVariant:
| "small-soft"
| "small-strong"
| "large-soft"
| "large-strong";
export const view = <div className={`${`nested-${nestedVariant}` as const}`} />;
"#;
let result = summarize_omena_bridge_source_syntax_index_with_type_fact_attempts(
source,
Vec::new(),
Vec::new(),
);
assert_eq!(result.type_fact_attempts.len(), 1);
let attempt = &result.type_fact_attempts[0];
assert_eq!(
attempt.shape_class,
SourceTypeFactExpressionShapeV0::NestedTemplate
);
assert_eq!(
&source[attempt.byte_span.start..attempt.byte_span.end],
"`nested-${nestedVariant}` as const"
);
assert_eq!(result.source_syntax_index.type_fact_target_skipped.len(), 1);
let skipped = &result.source_syntax_index.type_fact_target_skipped[0];
assert_eq!(
&source[skipped.byte_span.start..skipped.byte_span.end],
"`nested-${nestedVariant}`"
);
}
#[test]
fn narrows_finite_conditional_template_interpolations_without_a_type_provider() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
export function View({ active }: { active: boolean }) {
return <div className={cx(`theme-${active ? "a" : "legacy"}`)} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
let exact = index
.selector_references
.iter()
.filter(|reference| reference.match_kind == SourceSelectorReferenceMatchKindV0::Exact)
.filter_map(|reference| reference.selector_name.as_deref())
.collect::<Vec<_>>();
assert!(exact.contains(&"theme-a"));
assert!(exact.contains(&"theme-legacy"));
assert_eq!(index.type_fact_target_skipped_count, 1);
}
#[test]
fn keeps_template_prefixes_when_a_conditional_arm_is_not_fully_enumerable() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
declare function resolveTheme(): string;
export function View({ active }: { active: boolean }) {
return <div className={cx(`theme-${active ? "a" : resolveTheme()}`)} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
assert!(index.selector_references.iter().any(|reference| {
reference.match_kind == SourceSelectorReferenceMatchKindV0::Prefix
&& reference.selector_name.as_deref() == Some("theme-")
}));
assert!(!index.selector_references.iter().any(|reference| {
reference.match_kind == SourceSelectorReferenceMatchKindV0::Exact
&& reference
.selector_name
.as_deref()
.is_some_and(|name| name.starts_with("theme-"))
}));
}
#[test]
fn preserves_bare_and_multi_interpolation_reference_shapes() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
export function View({ value, left, right }: Record<string, string>) {
return <div className={cx(`${value}`, `theme-${left}-${right}`)} />;
}"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
let references = index
.selector_references
.iter()
.map(|reference| {
(
&source[reference.byte_span.start..reference.byte_span.end],
reference.selector_name.as_deref(),
reference.match_kind,
)
})
.collect::<Vec<_>>();
assert_eq!(
references,
vec![(
"theme-",
Some("theme-"),
SourceSelectorReferenceMatchKindV0::Prefix,
)],
);
assert_eq!(index.type_fact_targets.len(), 1);
assert_eq!(
&source
[index.type_fact_targets[0].byte_span.start..index.type_fact_targets[0].byte_span.end],
"value"
);
assert_eq!(index.type_fact_target_skipped_count, 1);
}
#[test]
fn walks_expression_like_oxc_argument_array_and_property_key_variants() {
let source = r#"import bind from "classnames/bind";
import styles from "./App.module.scss";
const cx = bind.bind(styles);
const items = [1];
const nodes = [<span className={cx("arrayItem")} />];
const keyed = { [items.length ? <span className={cx("keyedItem")} /> : "fallback"]: true };
export const view = <>{items.map(() => <a className={cx("callbackLink")} />)}{nodes}</>;"#;
let index = summarize_omena_bridge_source_syntax_index(
source,
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/App.module.scss".to_string(),
}],
vec!["bind".to_string()],
);
let names = index
.selector_references
.iter()
.filter(|reference| {
reference.target_style_uri.as_deref() == Some("file:///workspace/App.module.scss")
})
.map(|reference| selector_reference_name(source, reference))
.collect::<Vec<_>>();
assert!(
names.contains(&"arrayItem"),
"array literal JSX should be walked"
);
assert!(
names.contains(&"keyedItem"),
"computed property key expression should be walked"
);
assert!(
names.contains(&"callbackLink"),
"callback argument JSX should be walked"
);
}
#[test]
fn collects_class_name_string_literals_from_oxc_ast() {
let source = r#"const text = "className=\"fake\"";
export const view = <div className="root item--primary" data-token="ignored" />;"#;
let index = summarize_omena_bridge_source_syntax_index(source, Vec::new(), Vec::new());
let literal_values = index
.class_string_literals
.iter()
.map(|span| &source[span.start..span.end])
.collect::<Vec<_>>();
assert_eq!(literal_values, vec!["root item--primary"]);
assert!(
index
.selector_references
.iter()
.any(|reference| { selector_reference_name(source, reference) == "root" })
);
assert!(
index
.selector_references
.iter()
.any(|reference| { selector_reference_name(source, reference) == "item--primary" })
);
}
#[test]
fn source_recovery_scanners_keep_multibyte_escape_boundaries()
-> Result<(), Box<dyn std::error::Error>> {
let source = r#"const escaped = "\비";
const view = <div className={cx("root", active && `상태-${tone}`)} />;"#;
let escaped_quote = source
.find(r#""\비""#)
.ok_or_else(|| std::io::Error::other("escaped fixture exists"))?;
let escaped_end = skip_js_string_literal(source, escaped_quote, source.len())
.ok_or_else(|| std::io::Error::other("escaped string should be skipped"))?;
assert!(source.is_char_boundary(escaped_end));
let expression_start = source
.find("cx(")
.ok_or_else(|| std::io::Error::other("cx call exists"))?
+ "cx(".len();
let expression_end = js_call_end(source, expression_start - 1)
.ok_or_else(|| std::io::Error::other("cx call ends"))?;
let segments = split_top_level_js_segments(source, expression_start, expression_end, b',');
assert_eq!(segments.len(), 2);
for (start, end) in segments {
assert!(source.is_char_boundary(start));
assert!(source.is_char_boundary(end));
}
let operator = find_top_level_js_operator(source, expression_start, expression_end, "&&")
.ok_or_else(|| {
std::io::Error::other(
"conditional operator should be found without slicing inside UTF-8",
)
})?;
assert!(source.is_char_boundary(operator));
Ok(())
}
#[test]
fn collects_vue_sfc_use_css_module_bindings_from_projected_script() {
let source = r#"<template><div :class="$style.ignored" /></template>
<script setup lang="ts">
import { useCssModule as useModule } from "vue";
const styles = useModule();
const text = ".not-style";
</script>
<style module>
.root {}
</style>
"#;
let bindings = collect_omena_bridge_vue_style_module_bindings("Card.vue", source, Some("vue"));
assert_eq!(bindings, vec!["styles"]);
}
#[test]
fn indexes_vue_sfc_use_css_module_property_accesses_against_vue_style_uri() {
let source = r#"<template><div /></template>
<script setup lang="ts">
import { useCssModule } from "vue";
const styles = useCssModule();
export const root = styles.root;
</script>
<style module>
.root { color: red; }
</style>
"#;
let index = summarize_omena_bridge_source_syntax_index_for_source_language(
"file:///workspace/Card.vue",
source,
Some("vue"),
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/Card.vue".to_string(),
}],
Vec::new(),
);
assert!(index.selector_references.iter().any(|reference| {
selector_reference_name(source, reference) == "root"
&& reference.target_style_uri.as_deref() == Some("file:///workspace/Card.vue")
}));
}
#[test]
fn indexes_html_script_property_accesses_against_imported_style_uri() {
let source = r#"<main>ignored</main>
<script type="module">
import styles from "./Page.module.scss";
export const root = styles.root;
</script>
"#;
let index = summarize_omena_bridge_source_syntax_index_for_source_language(
"file:///workspace/Page.html",
source,
Some("html"),
vec![SourceImportedStyleBindingV0 {
binding: "styles".to_string(),
style_uri: "file:///workspace/Page.module.scss".to_string(),
}],
Vec::new(),
);
assert!(index.selector_references.iter().any(|reference| {
selector_reference_name(source, reference) == "root"
&& reference.target_style_uri.as_deref() == Some("file:///workspace/Page.module.scss")
}));
assert!(
!index
.selector_references
.iter()
.any(|reference| selector_reference_name(source, reference) == "ignored")
);
}
#[test]
fn indexes_jsx_element_parent_edges_in_the_existing_ast_walk() -> Result<(), &'static str> {
let source = r#"export const view = (
<main>
<section className="panel"><span /></section>
<Footer />
</main>
);"#;
let source_path = "file:///workspace/View.tsx";
let index = summarize_omena_bridge_source_syntax_index_for_source_language(
source_path,
source,
Some("typescriptreact"),
Vec::new(),
Vec::new(),
);
assert_eq!(index.source_elements.len(), 4);
assert_eq!(index.element_parent_edges.len(), 3);
let span = index
.source_elements
.iter()
.find(|element| element.intrinsic_tag_name.as_deref() == Some("span"))
.ok_or("span element should be indexed")?;
let section = index
.source_elements
.iter()
.find(|element| element.intrinsic_tag_name.as_deref() == Some("section"))
.ok_or("section element should be indexed")?;
assert!(
index
.element_parent_edges
.iter()
.any(|edge| { edge.child == span.identity && edge.parent == section.identity })
);
assert_eq!(section.static_class_names, vec!["panel"]);
assert!(section.classes_are_exact);
assert!(
index
.source_elements
.iter()
.all(|element| element.identity.source_path == source_path)
);
Ok(())
}
fn selector_reference_name<'a>(
source: &'a str,
reference: &'a SourceSelectorReferenceFactV0,
) -> &'a str {
reference
.selector_name
.as_deref()
.unwrap_or(&source[reference.byte_span.start..reference.byte_span.end])
}