diff --git a/.changeset/rude-wasps-judge.md b/.changeset/rude-wasps-judge.md new file mode 100644 index 00000000..7a4cf68c --- /dev/null +++ b/.changeset/rude-wasps-judge.md @@ -0,0 +1,5 @@ +--- +"@devup-ui/wasm": patch +--- + +Fix negative issue, literal issue diff --git a/apps/landing/src/components/SearchModal/SearchContent.tsx b/apps/landing/src/components/SearchModal/SearchContent.tsx index 2922577c..ff473b06 100644 --- a/apps/landing/src/components/SearchModal/SearchContent.tsx +++ b/apps/landing/src/components/SearchModal/SearchContent.tsx @@ -2,7 +2,7 @@ import { Box, Center, css, Flex, Text, VStack } from '@devup-ui/react' import Link from 'next/link' import { useSearchParams } from 'next/navigation' -import { Fragment, useEffect, useState } from 'react' +import { Fragment, useEffect, useMemo, useState } from 'react' import { URL_PREFIX } from '../../constants' @@ -38,6 +38,7 @@ export function SearchContent() { ) } }, [query]) + const reg = useMemo(() => new RegExp(`(${query})`, 'gi'), [query]) if (!query) return const inner = data ? ( <> @@ -58,8 +59,22 @@ export function SearchContent() { p="10px" > {item.title} - - {item.text} + + {item.text + .substring(0, 100) + .split(reg) + .map((part, idx) => + part.toLowerCase() === query.toLowerCase() ? ( + + {part} + + ) : ( + + {part} + + ), + )} + ... diff --git a/libs/extractor/src/lib.rs b/libs/extractor/src/lib.rs index 42efbcde..16e2b53e 100644 --- a/libs/extractor/src/lib.rs +++ b/libs/extractor/src/lib.rs @@ -6,28 +6,20 @@ mod prop_modify_utils; mod style_extractor; mod utils; mod visit; - -use oxc_codegen::Codegen; -use std::collections::BTreeMap; - use crate::extract_style::ExtractStyleValue; use crate::visit::DevupVisitor; use oxc_allocator::Allocator; use oxc_ast::ast::Expression; use oxc_ast::VisitMut; +use oxc_codegen::Codegen; use oxc_parser::{Parser, ParserReturn}; use oxc_span::SourceType; +use std::collections::BTreeMap; use std::error::Error; - -/// result of extracting style properties from props #[derive(Debug)] pub enum ExtractStyleProp<'a> { Static(ExtractStyleValue), StaticArray(Vec>), - /// static + static ex) margin={test?"4px":"8px"} --> className={test?"margin-4px-0":"margin-8px-0"} - /// static + dynamic ex) margin={test?a:"8px"} --> className={test?"margin-0":"margin-8px-0"} style={{ "--margin-0": a }} - /// dynamic + dynamic ex) margin={test?a:b} --> className="margin-0" style={{ "--margin-0": test?a:b }} - /// issue case: dynamic + dynamic ex) margin={test?a:(b ? "8px": c)} --> className="margin-0" style={{ "--margin-0": test?a:(b ? "8px": c) }} Conditional { condition: Expression<'a>, consequent: Option>>, @@ -42,6 +34,7 @@ pub enum ExtractStyleProp<'a> { expression: Expression<'a>, }, } + impl ExtractStyleProp<'_> { pub fn extract(&self) -> Vec { match self { @@ -345,6 +338,19 @@ mod tests { } ) .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.tsx", + r"import {Flex} from '@devup-ui/core' + + ", + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); } #[test] @@ -1427,6 +1433,100 @@ export { ) .unwrap()); } + #[test] + #[serial] + fn negative_props() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } #[test] #[serial] @@ -1932,4 +2032,60 @@ import {Button} from '@devup/ui' ) .unwrap()); } + + #[test] + #[serial] + fn template_literal_props() { + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + + reset_class_map(); + assert_debug_snapshot!(extract( + "test.js", + r#"import {Box} from '@devup-ui/core' + + "#, + ExtractOption { + package: "@devup-ui/core".to_string(), + css_file: None + } + ) + .unwrap()); + } } diff --git a/libs/extractor/src/snapshots/extractor__tests__extract_style_props-6.snap b/libs/extractor/src/snapshots/extractor__tests__extract_style_props-6.snap new file mode 100644 index 00000000..2b47e2a1 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__extract_style_props-6.snap @@ -0,0 +1,27 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.tsx\",\nr\"import {Flex} from '@devup-ui/core'\n \n \",\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "display", + value: "flex", + level: 0, + selector: None, + basic: true, + }, + ), + Static( + ExtractStaticStyle { + property: "padding", + value: "-4px", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__negative_props-2.snap b/libs/extractor/src/snapshots/extractor__tests__negative_props-2.snap new file mode 100644 index 00000000..1b9dfe48 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__negative_props-2.snap @@ -0,0 +1,17 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Dynamic( + ExtractDynamicStyle { + property: "zIndex", + level: 0, + identifier: "-a", + selector: None, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__negative_props-3.snap b/libs/extractor/src/snapshots/extractor__tests__negative_props-3.snap new file mode 100644 index 00000000..6cfcb6d8 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__negative_props-3.snap @@ -0,0 +1,17 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Dynamic( + ExtractDynamicStyle { + property: "zIndex", + level: 0, + identifier: "-(1 + a)", + selector: None, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__negative_props-4.snap b/libs/extractor/src/snapshots/extractor__tests__negative_props-4.snap new file mode 100644 index 00000000..80de2c55 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__negative_props-4.snap @@ -0,0 +1,17 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Dynamic( + ExtractDynamicStyle { + property: "zIndex", + level: 0, + identifier: "-1 * a", + selector: None, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__negative_props-5.snap b/libs/extractor/src/snapshots/extractor__tests__negative_props-5.snap new file mode 100644 index 00000000..ae8131c3 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__negative_props-5.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "zIndex", + value: "-1", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__negative_props-6.snap b/libs/extractor/src/snapshots/extractor__tests__negative_props-6.snap new file mode 100644 index 00000000..bbadc7a3 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__negative_props-6.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "zIndex", + value: "-1", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__negative_props-7.snap b/libs/extractor/src/snapshots/extractor__tests__negative_props-7.snap new file mode 100644 index 00000000..895ebbcf --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__negative_props-7.snap @@ -0,0 +1,36 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "zIndex", + value: "-1", + level: 0, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "zIndex", + value: "-2", + level: 1, + selector: None, + basic: false, + }, + ), + Static( + ExtractStaticStyle { + property: "zIndex", + value: "-3", + level: 2, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__negative_props.snap b/libs/extractor/src/snapshots/extractor__tests__negative_props.snap new file mode 100644 index 00000000..a4191c17 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__negative_props.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "zIndex", + value: "-1", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__template_literal_props-2.snap b/libs/extractor/src/snapshots/extractor__tests__template_literal_props-2.snap new file mode 100644 index 00000000..33affea3 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__template_literal_props-2.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "margin", + value: "4px", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__template_literal_props-3.snap b/libs/extractor/src/snapshots/extractor__tests__template_literal_props-3.snap new file mode 100644 index 00000000..7e53ebf1 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__template_literal_props-3.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "margin", + value: "-4px", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__template_literal_props-4.snap b/libs/extractor/src/snapshots/extractor__tests__template_literal_props-4.snap new file mode 100644 index 00000000..7c01927c --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__template_literal_props-4.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "margin", + value: "1 2", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/snapshots/extractor__tests__template_literal_props.snap b/libs/extractor/src/snapshots/extractor__tests__template_literal_props.snap new file mode 100644 index 00000000..e8694602 --- /dev/null +++ b/libs/extractor/src/snapshots/extractor__tests__template_literal_props.snap @@ -0,0 +1,18 @@ +--- +source: libs/extractor/src/lib.rs +expression: "extract(\"test.js\",\nr#\"import {Box} from '@devup-ui/core'\n \n \"#,\nExtractOption\n{ package: \"@devup-ui/core\".to_string(), css_file: None }).unwrap()" +--- +ExtractOutput { + styles: [ + Static( + ExtractStaticStyle { + property: "background", + value: "red", + level: 0, + selector: None, + basic: false, + }, + ), + ], + code: "import \"@devup-ui/core/devup-ui.css\";\n
;\n", +} diff --git a/libs/extractor/src/style_extractor.rs b/libs/extractor/src/style_extractor.rs index a876ceb9..0ce986af 100644 --- a/libs/extractor/src/style_extractor.rs +++ b/libs/extractor/src/style_extractor.rs @@ -251,272 +251,294 @@ pub fn extract_style_from_expression<'a>( } typo = name == "typography"; } - match expression { - Expression::ComputedMemberExpression(mem) => { - extract_style_from_member_expression(ast_builder, name, mem, level, selector) - } - Expression::NumericLiteral(v) => name - .map(|name| { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(Static( - ExtractStaticStyle::new( - name, - &v.value.to_string(), + if let Some(value) = get_number_by_literal_expression(expression) { + name.map(|name| { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(Static( + ExtractStaticStyle::new( + name, + &value.to_string(), + level, + selector.map(|s| s.into()), + ), + ))]) + }) + .unwrap_or(ExtractResult::Maintain) + } else if let Some(value) = get_string_by_literal_expression(expression) { + name.map(|name| { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(if typo { + Typography(value.as_str().to_string()) + } else { + Static(ExtractStaticStyle::new( + name, + value.as_str(), + level, + selector.map(|s| s.into()), + )) + })]) + }) + .unwrap_or(ExtractResult::Maintain) + } else { + match expression { + Expression::UnaryExpression(_) | Expression::BinaryExpression(_) => { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(Dynamic( + ExtractDynamicStyle::new( + name.unwrap(), level, + expression_to_code(expression).as_str(), selector.map(|s| s.into()), ), ))]) - }) - .unwrap_or(ExtractResult::Maintain), - Expression::TemplateLiteral(tmp) => { - if let Some(name) = name { - if tmp.quasis.len() == 1 { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(if typo { - Typography(tmp.quasis[0].value.raw.as_str().to_string()) + } + Expression::ComputedMemberExpression(mem) => { + extract_style_from_member_expression(ast_builder, name, mem, level, selector) + } + Expression::TemplateLiteral(tmp) => { + if let Some(name) = name { + if tmp.quasis.len() == 1 { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(if typo { + Typography(tmp.quasis[0].value.raw.as_str().to_string()) + } else { + Static(ExtractStaticStyle::new( + name, + tmp.quasis[0].value.raw.as_str(), + level, + selector.map(|s| s.into()), + )) + })]) + } else if typo { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Expression { + expression: ast_builder.expression_template_literal( + SPAN, + ast_builder.vec_from_array([ + ast_builder.template_element( + SPAN, + false, + TemplateElementValue { + raw: ast_builder.atom("typo-"), + cooked: None, + }, + ), + ast_builder.template_element( + SPAN, + true, + TemplateElementValue { + raw: ast_builder.atom(""), + cooked: None, + }, + ), + ]), + ast_builder + .vec_from_array([expression.clone_in(ast_builder.allocator)]), + ), + styles: vec![], + }]) } else { - Static(ExtractStaticStyle::new( - name, - tmp.quasis[0].value.raw.as_str(), - level, - selector.map(|s| s.into()), - )) - })]) - } else if typo { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Expression { - expression: ast_builder.expression_template_literal( - SPAN, - ast_builder.vec_from_array([ - ast_builder.template_element( - SPAN, - false, - TemplateElementValue { - raw: ast_builder.atom("typo-"), - cooked: None, - }, - ), - ast_builder.template_element( - SPAN, - true, - TemplateElementValue { - raw: ast_builder.atom(""), - cooked: None, - }, - ), - ]), - ast_builder - .vec_from_array([expression.clone_in(ast_builder.allocator)]), - ), - styles: vec![], - }]) + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(Dynamic( + ExtractDynamicStyle::new( + name, + level, + expression_to_code(expression).as_str(), + selector.map(|s| s.into()), + ), + ))]) + } } else { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(Dynamic( - ExtractDynamicStyle::new( - name, - level, - expression_to_code(expression).as_str(), - selector.map(|s| s.into()), - ), - ))]) + ExtractResult::Maintain } - } else { - ExtractResult::Maintain } - } - Expression::StringLiteral(v) => name - .map(|name| { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(if typo { - Typography(v.value.as_str().to_string()) - } else { - Static(ExtractStaticStyle::new( - name, - v.value.as_str(), - level, - selector.map(|s| s.into()), - )) - })]) - }) - .unwrap_or(ExtractResult::Maintain), - Expression::Identifier(identifier) => { - if IGNORED_IDENTIFIERS.contains(&identifier.name.as_str()) { - ExtractResult::Maintain - } else if let Some(name) = name { - if typo { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Expression { - expression: ast_builder.expression_template_literal( - SPAN, - ast_builder.vec_from_array([ - ast_builder.template_element( - SPAN, - false, - TemplateElementValue { - raw: ast_builder.atom("typo-"), - cooked: None, - }, - ), - ast_builder.template_element( - SPAN, - true, - TemplateElementValue { - raw: ast_builder.atom(""), - cooked: None, - }, - ), - ]), - ast_builder - .vec_from_array([expression.clone_in(ast_builder.allocator)]), - ), - styles: vec![], - }]) + Expression::Identifier(identifier) => { + if IGNORED_IDENTIFIERS.contains(&identifier.name.as_str()) { + ExtractResult::Maintain + } else if let Some(name) = name { + if typo { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Expression { + expression: ast_builder.expression_template_literal( + SPAN, + ast_builder.vec_from_array([ + ast_builder.template_element( + SPAN, + false, + TemplateElementValue { + raw: ast_builder.atom("typo-"), + cooked: None, + }, + ), + ast_builder.template_element( + SPAN, + true, + TemplateElementValue { + raw: ast_builder.atom(""), + cooked: None, + }, + ), + ]), + ast_builder + .vec_from_array([expression.clone_in(ast_builder.allocator)]), + ), + styles: vec![], + }]) + } else { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(Dynamic( + ExtractDynamicStyle::new( + name, + level, + identifier.name.as_str(), + selector.map(|s| s.into()), + ), + ))]) + } } else { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Static(Dynamic( - ExtractDynamicStyle::new( - name, - level, - identifier.name.as_str(), - selector.map(|s| s.into()), - ), - ))]) + ExtractResult::Maintain } - } else { - ExtractResult::Maintain } - } - Expression::LogicalExpression(logical) => { - let res = name.and_then(|name| { - match extract_style_from_expression( - ast_builder, - Some(name), - &mut logical.right, - level, - selector, - ) { - ExtractResult::ExtractStyle(styles) => { - Some(Box::new(ExtractStyleProp::StaticArray(styles))) + Expression::LogicalExpression(logical) => { + let res = name.and_then(|name| { + match extract_style_from_expression( + ast_builder, + Some(name), + &mut logical.right, + level, + selector, + ) { + ExtractResult::ExtractStyle(styles) => { + Some(Box::new(ExtractStyleProp::StaticArray(styles))) + } + _ => None, } - _ => None, - } - }); - match logical.operator { - LogicalOperator::Or => { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Conditional { - condition: logical.left.clone_in(ast_builder.allocator), - consequent: None, - alternate: res, - }]) - } - LogicalOperator::And => { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Conditional { - condition: logical.left.clone_in(ast_builder.allocator), - consequent: res, - alternate: None, - }]) - } - LogicalOperator::Coalesce => { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Conditional { - condition: Expression::LogicalExpression( - ast_builder.alloc_logical_expression( - SPAN, - Expression::BinaryExpression(ast_builder.alloc_binary_expression( - SPAN, - logical.left.clone_in(ast_builder.allocator), - BinaryOperator::StrictInequality, - Expression::NullLiteral(ast_builder.alloc_null_literal(SPAN)), - )), - LogicalOperator::And, - Expression::BinaryExpression(ast_builder.alloc_binary_expression( + }); + match logical.operator { + LogicalOperator::Or => { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Conditional { + condition: logical.left.clone_in(ast_builder.allocator), + consequent: None, + alternate: res, + }]) + } + LogicalOperator::And => { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Conditional { + condition: logical.left.clone_in(ast_builder.allocator), + consequent: res, + alternate: None, + }]) + } + LogicalOperator::Coalesce => { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Conditional { + condition: Expression::LogicalExpression( + ast_builder.alloc_logical_expression( SPAN, - logical.left.clone_in(ast_builder.allocator), - BinaryOperator::StrictInequality, - Expression::Identifier( - ast_builder.alloc_identifier_reference(SPAN, "undefined"), + Expression::BinaryExpression( + ast_builder.alloc_binary_expression( + SPAN, + logical.left.clone_in(ast_builder.allocator), + BinaryOperator::StrictInequality, + Expression::NullLiteral( + ast_builder.alloc_null_literal(SPAN), + ), + ), ), - )), + LogicalOperator::And, + Expression::BinaryExpression( + ast_builder.alloc_binary_expression( + SPAN, + logical.left.clone_in(ast_builder.allocator), + BinaryOperator::StrictInequality, + Expression::Identifier( + ast_builder + .alloc_identifier_reference(SPAN, "undefined"), + ), + ), + ), + ), ), - ), - consequent: None, - alternate: res, - }]) - } - } - } - Expression::ParenthesizedExpression(parenthesized) => extract_style_from_expression( - ast_builder, - name, - &mut parenthesized.expression, - level, - selector, - ), - Expression::ArrayExpression(array) => { - let mut props = vec![]; - - for (idx, element) in array.elements.iter_mut().enumerate() { - if let ExtractResult::ExtractStyle(mut styles) = extract_style_from_expression( - ast_builder, - name, - element.to_expression_mut(), - idx as u8, - selector, - ) { - props.append(&mut styles); + consequent: None, + alternate: res, + }]) + } } } + Expression::ParenthesizedExpression(parenthesized) => extract_style_from_expression( + ast_builder, + name, + &mut parenthesized.expression, + level, + selector, + ), + Expression::ArrayExpression(array) => { + let mut props = vec![]; - if props.is_empty() { - ExtractResult::Maintain - } else { - ExtractResult::ExtractStyle(props) - } - } - Expression::ConditionalExpression(ref mut conditional) => { - ExtractResult::ExtractStyle(vec![ExtractStyleProp::Conditional { - condition: conditional.test.clone_in(ast_builder.allocator), - consequent: if let ExtractResult::ExtractStyle(styles) = - extract_style_from_expression( - ast_builder, - name, - &mut conditional.consequent, - level, - selector, - ) { - Some(Box::new(ExtractStyleProp::StaticArray(styles))) - } else { - None - }, - alternate: if let ExtractResult::ExtractStyle(styles) = - extract_style_from_expression( + for (idx, element) in array.elements.iter_mut().enumerate() { + if let ExtractResult::ExtractStyle(mut styles) = extract_style_from_expression( ast_builder, name, - &mut conditional.alternate, - level, - selector, - ) { - Some(Box::new(ExtractStyleProp::StaticArray(styles))) - } else { - None - }, - }]) - } - Expression::ObjectExpression(obj) => { - let mut props = vec![]; - for p in obj.properties.iter_mut() { - if let ObjectPropertyKind::ObjectProperty(ref mut o) = p { - if let ExtractResult::ExtractStyle(ref mut ret) = extract_style_from_expression( - ast_builder, - Some(&o.key.name().unwrap()), - &mut o.value, - level, + element.to_expression_mut(), + idx as u8, selector, ) { - props.append(ret); + props.append(&mut styles); } - }; + } + + if props.is_empty() { + ExtractResult::Maintain + } else { + ExtractResult::ExtractStyle(props) + } } - if props.is_empty() { - ExtractResult::Remove - } else { - ExtractResult::ExtractStyle(props) + Expression::ConditionalExpression(ref mut conditional) => { + ExtractResult::ExtractStyle(vec![ExtractStyleProp::Conditional { + condition: conditional.test.clone_in(ast_builder.allocator), + consequent: if let ExtractResult::ExtractStyle(styles) = + extract_style_from_expression( + ast_builder, + name, + &mut conditional.consequent, + level, + selector, + ) { + Some(Box::new(ExtractStyleProp::StaticArray(styles))) + } else { + None + }, + alternate: if let ExtractResult::ExtractStyle(styles) = + extract_style_from_expression( + ast_builder, + name, + &mut conditional.alternate, + level, + selector, + ) { + Some(Box::new(ExtractStyleProp::StaticArray(styles))) + } else { + None + }, + }]) + } + Expression::ObjectExpression(obj) => { + let mut props = vec![]; + for p in obj.properties.iter_mut() { + if let ObjectPropertyKind::ObjectProperty(ref mut o) = p { + if let ExtractResult::ExtractStyle(ref mut ret) = + extract_style_from_expression( + ast_builder, + Some(&o.key.name().unwrap()), + &mut o.value, + level, + selector, + ) + { + props.append(ret); + } + }; + } + if props.is_empty() { + ExtractResult::Remove + } else { + ExtractResult::ExtractStyle(props) + } } + // val if let Some(value) = get_number_by_literal_expression(val) => {} + _ => ExtractResult::Maintain, } - _ => ExtractResult::Maintain, } } @@ -720,33 +742,43 @@ fn extract_style_from_member_expression<'a>( fn get_number_by_literal_expression(expr: &Expression) -> Option { match expr { - Expression::NumericLiteral(num) => Some(num.value), - Expression::UnaryExpression(unary) => { - if let Expression::NumericLiteral(ref num) = unary.argument { - match unary.operator { - UnaryOperator::UnaryNegation => Some(-num.value), - UnaryOperator::UnaryPlus => Some(num.value), - _ => None, - } - } else { - None - } + Expression::ParenthesizedExpression(parenthesized) => { + get_number_by_literal_expression(&parenthesized.expression) } + Expression::NumericLiteral(num) => Some(num.value), + Expression::UnaryExpression(unary) => get_number_by_literal_expression(&unary.argument) + .and_then(|num| match unary.operator { + UnaryOperator::UnaryNegation => Some(-num), + UnaryOperator::UnaryPlus => Some(num), + _ => None, + }), _ => None, } } fn get_string_by_literal_expression(expr: &Expression) -> Option { - match expr { - Expression::StringLiteral(str) => Some(str.value.as_str().to_string()), - Expression::TemplateLiteral(tmp) => { - if tmp.quasis.len() == 1 { - Some(tmp.quasis[0].value.raw.as_str().to_string()) - } else { - None + get_number_by_literal_expression(expr) + .map(|num| num.to_string()) + .or_else(|| match expr { + Expression::ParenthesizedExpression(parenthesized) => { + get_string_by_literal_expression(&parenthesized.expression) } - } - Expression::NumericLiteral(num) => Some(num.value.to_string()), - _ => None, - } + Expression::StringLiteral(str) => Some(str.value.as_str().to_string()), + Expression::TemplateLiteral(tmp) => { + let mut collect = vec![]; + for (idx, q) in tmp.quasis.iter().enumerate() { + collect.push(q.value.raw.to_string()); + if idx < tmp.expressions.len() { + if let Some(value) = get_string_by_literal_expression(&tmp.expressions[idx]) + { + collect.push(value); + } else { + return None; + } + } + } + Some(collect.join("")) + } + _ => None, + }) }