Skip to content

Commit 0d5dd14

Browse files
Add coverage tests for stylex extraction
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
1 parent 74a0d1b commit 0d5dd14

5 files changed

Lines changed: 123 additions & 14 deletions

libs/extractor/src/extractor/extract_style_from_stylex.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -323,21 +323,22 @@ fn extract_stylex_dynamic_namespace<'a>(
323323
if !arrow.expression {
324324
return None;
325325
}
326-
let stmt = arrow.body.statements.first()?;
327-
let Statement::ExpressionStatement(expr_stmt) = stmt else {
328-
return None;
329-
};
330-
// Handle both direct ObjectExpression and ParenthesizedExpression wrapping
331-
let body_obj = match &expr_stmt.expression {
332-
Expression::ObjectExpression(obj) => obj,
333-
Expression::ParenthesizedExpression(paren) => {
334-
if let Expression::ObjectExpression(obj) = &paren.expression {
335-
obj
336-
} else {
337-
return None;
338-
}
326+
// Expression arrow body: Oxc always wraps in ExpressionStatement.
327+
// Unwrap ParenthesizedExpression since Oxc preserves parens for `(x) => ({...})`.
328+
let body_expr = arrow.body.statements.first().and_then(|stmt| {
329+
if let Statement::ExpressionStatement(e) = stmt {
330+
Some(&e.expression)
331+
} else {
332+
None
339333
}
340-
_ => return None,
334+
})?;
335+
let inner = if let Expression::ParenthesizedExpression(paren) = body_expr {
336+
&paren.expression
337+
} else {
338+
body_expr
339+
};
340+
let Expression::ObjectExpression(body_obj) = inner else {
341+
return None;
341342
};
342343

343344
// 3. Process each property

libs/extractor/src/lib.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16226,4 +16226,77 @@ const composed = stylex.create({ test: { ...stylex.include(base.empty), color: '
1622616226
.unwrap()
1622716227
));
1622816228
}
16229+
16230+
/// Dynamic namespace with bare expression body (not object): (x) => x
16231+
/// Covers: extract_style_from_stylex.rs ObjectExpression else branch
16232+
#[test]
16233+
#[serial]
16234+
fn test_stylex_dynamic_bare_expression_body() {
16235+
reset_class_map();
16236+
reset_file_map();
16237+
assert_debug_snapshot!(ToBTreeSet::from(
16238+
extract(
16239+
"test.tsx",
16240+
r#"import stylex from '@stylexjs/stylex';
16241+
const styles = stylex.create({ base: (x) => x });"#,
16242+
ExtractOption {
16243+
package: "@devup-ui/react".to_string(),
16244+
css_dir: "@devup-ui/react".to_string(),
16245+
single_css: true,
16246+
import_main_css: false,
16247+
import_aliases: HashMap::new()
16248+
},
16249+
)
16250+
.unwrap()
16251+
));
16252+
}
16253+
16254+
/// Dynamic namespace with parenthesized non-object body: (x) => (x)
16255+
/// Covers: extract_style_from_stylex.rs ParenthesizedExpression unwrap + ObjectExpression else
16256+
#[test]
16257+
#[serial]
16258+
fn test_stylex_dynamic_paren_non_object_body() {
16259+
reset_class_map();
16260+
reset_file_map();
16261+
assert_debug_snapshot!(ToBTreeSet::from(
16262+
extract(
16263+
"test.tsx",
16264+
r#"import stylex from '@stylexjs/stylex';
16265+
const styles = stylex.create({ base: (x) => (x) });"#,
16266+
ExtractOption {
16267+
package: "@devup-ui/react".to_string(),
16268+
css_dir: "@devup-ui/react".to_string(),
16269+
single_css: true,
16270+
import_main_css: false,
16271+
import_aliases: HashMap::new()
16272+
},
16273+
)
16274+
.unwrap()
16275+
));
16276+
}
16277+
16278+
/// Include-only namespace with no own styles — class_name_str starts empty
16279+
/// Covers: visit.rs line 332 (class_name_str = included_class when empty)
16280+
#[test]
16281+
#[serial]
16282+
fn test_stylex_include_only_no_own_styles() {
16283+
reset_class_map();
16284+
reset_file_map();
16285+
assert_debug_snapshot!(ToBTreeSet::from(
16286+
extract(
16287+
"test.tsx",
16288+
r#"import stylex from '@stylexjs/stylex';
16289+
const base = stylex.create({ root: { color: 'red' } });
16290+
const composed = stylex.create({ combined: { ...stylex.include(base.root) } });"#,
16291+
ExtractOption {
16292+
package: "@devup-ui/react".to_string(),
16293+
css_dir: "@devup-ui/react".to_string(),
16294+
single_css: true,
16295+
import_main_css: false,
16296+
import_aliases: HashMap::new()
16297+
},
16298+
)
16299+
.unwrap()
16300+
));
16301+
}
1622916302
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
source: libs/extractor/src/lib.rs
3+
expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import stylex from '@stylexjs/stylex';\nconst styles = stylex.create({ base: (x) => x });\"#,\nExtractOption\n{\n package: \"@devup-ui/react\".to_string(), css_dir:\n \"@devup-ui/react\".to_string(), single_css: true, import_main_css: false,\n import_aliases: HashMap::new()\n},).unwrap())"
4+
---
5+
ToBTreeSet {
6+
styles: {},
7+
code: "import stylex from \"@stylexjs/stylex\";\nconst styles = { \"base\": \"\" };\n",
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
source: libs/extractor/src/lib.rs
3+
expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import stylex from '@stylexjs/stylex';\nconst styles = stylex.create({ base: (x) => (x) });\"#,\nExtractOption\n{\n package: \"@devup-ui/react\".to_string(), css_dir:\n \"@devup-ui/react\".to_string(), single_css: true, import_main_css: false,\n import_aliases: HashMap::new()\n},).unwrap())"
4+
---
5+
ToBTreeSet {
6+
styles: {},
7+
code: "import stylex from \"@stylexjs/stylex\";\nconst styles = { \"base\": \"\" };\n",
8+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
source: libs/extractor/src/lib.rs
3+
expression: "ToBTreeSet::from(extract(\"test.tsx\",\nr#\"import stylex from '@stylexjs/stylex';\nconst base = stylex.create({ root: { color: 'red' } });\nconst composed = stylex.create({ combined: { ...stylex.include(base.root) } });\"#,\nExtractOption\n{\n package: \"@devup-ui/react\".to_string(), css_dir:\n \"@devup-ui/react\".to_string(), single_css: true, import_main_css: false,\n import_aliases: HashMap::new()\n},).unwrap())"
4+
---
5+
ToBTreeSet {
6+
styles: {
7+
Static(
8+
ExtractStaticStyle {
9+
property: "color",
10+
value: "red",
11+
level: 0,
12+
selector: None,
13+
style_order: None,
14+
layer: None,
15+
},
16+
),
17+
},
18+
code: "import \"@devup-ui/react/devup-ui.css\";\nimport stylex from \"@stylexjs/stylex\";\nconst base = { \"root\": \"a\" };\nconst composed = { \"combined\": \"a\" };\n",
19+
}

0 commit comments

Comments
 (0)