diff --git a/.changeset/curly-lions-allow.md b/.changeset/curly-lions-allow.md new file mode 100644 index 00000000..6e47f3e7 --- /dev/null +++ b/.changeset/curly-lions-allow.md @@ -0,0 +1,6 @@ +--- +'@stylexswc/swc-plugin': patch +'@stylexswc/nextjs-plugin': patch +--- + +rename ModuleCycle to TransformationCycle diff --git a/.changeset/sixty-beers-end.md b/.changeset/sixty-beers-end.md new file mode 100644 index 00000000..492cd3cc --- /dev/null +++ b/.changeset/sixty-beers-end.md @@ -0,0 +1,6 @@ +--- +'@stylexswc/swc-plugin': patch +'@stylexswc/nextjs-plugin': patch +--- + +link counting: improve cleaning unused var declarations diff --git a/.changeset/small-apples-exercise.md b/.changeset/small-apples-exercise.md new file mode 100644 index 00000000..ba48c168 --- /dev/null +++ b/.changeset/small-apples-exercise.md @@ -0,0 +1,6 @@ +--- +'@stylexswc/swc-plugin': patch +'@stylexswc/nextjs-plugin': patch +--- + +state: unbox atom entities diff --git a/packages/swc-plugin/src/shared/enums/core.rs b/packages/swc-plugin/src/shared/enums/core.rs index 12addd1e..7454c7fb 100644 --- a/packages/swc-plugin/src/shared/enums/core.rs +++ b/packages/swc-plugin/src/shared/enums/core.rs @@ -1,15 +1,22 @@ // Represents the current state of a plugin for a file. #[derive(Debug, PartialEq, Eq, Clone, Hash, Copy)] -pub(crate) enum ModuleCycle { - // The plugin is being processed. +pub(crate) enum TransformationCycle { + // The plugin is being processed TransformEnter, + // The plugin has been processed TransformExit, - // The plugin has been processed and the file is being cleaned. + // The plugin has been processed and the file is being cleaned PreCleaning, + // The file is being cleaned Cleaning, - // The file has been processed and the plugin is skipped. + // Recounting variable links + Recounting, + // The file has been processed and the plugin is skipped Initializing, + // Fill the state with expressions data before transformation StateFilling, + // Skip the plugin if import does not exist Skip, + // Inject styles metadata to the file InjectStyles, } diff --git a/packages/swc-plugin/src/shared/structures/state_manager.rs b/packages/swc-plugin/src/shared/structures/state_manager.rs index aa073821..6d78a1bf 100644 --- a/packages/swc-plugin/src/shared/structures/state_manager.rs +++ b/packages/swc-plugin/src/shared/structures/state_manager.rs @@ -15,10 +15,13 @@ use swc_core::{ common::{EqIgnoreSpan, FileName, DUMMY_SP}, }; -use crate::shared::enums::data_structures::{ - import_path_resolution::{ImportPathResolution, ImportPathResolutionType}, - style_vars_to_keep::StyleVarsToKeep, - top_level_expression::{TopLevelExpression, TopLevelExpressionKind}, +use crate::shared::enums::{ + core::TransformationCycle, + data_structures::{ + import_path_resolution::{ImportPathResolution, ImportPathResolutionType}, + style_vars_to_keep::StyleVarsToKeep, + top_level_expression::{TopLevelExpression, TopLevelExpressionKind}, + }, }; use crate::shared::utils::{ ast::factories::binding_ident_factory, @@ -44,30 +47,33 @@ use super::{ seen_value::SeenValue, }; +type AtomHashMap = HashMap; +type AtomHashSet = HashSet; + #[derive(Clone, Debug)] pub struct StateManager { pub(crate) _state: Box, // Imports pub(crate) import_paths: HashSet, - pub(crate) stylex_import: HashSet>, - pub(crate) stylex_props_import: HashSet>, - pub(crate) stylex_attrs_import: HashSet>, - pub(crate) stylex_create_import: HashSet>, - pub(crate) stylex_include_import: HashSet>, - pub(crate) stylex_first_that_works_import: HashSet>, - pub(crate) stylex_keyframes_import: HashSet>, - pub(crate) stylex_define_vars_import: HashSet>, - pub(crate) stylex_create_theme_import: HashSet>, - pub(crate) stylex_types_import: HashSet>, + pub(crate) stylex_import: HashSet, + pub(crate) stylex_props_import: AtomHashSet, + pub(crate) stylex_attrs_import: AtomHashSet, + pub(crate) stylex_create_import: AtomHashSet, + pub(crate) stylex_include_import: AtomHashSet, + pub(crate) stylex_first_that_works_import: AtomHashSet, + pub(crate) stylex_keyframes_import: AtomHashSet, + pub(crate) stylex_define_vars_import: AtomHashSet, + pub(crate) stylex_create_theme_import: AtomHashSet, + pub(crate) stylex_types_import: AtomHashSet, pub(crate) inject_import_inserted: Option<(Box, Box)>, pub(crate) theme_name: Option, pub(crate) declarations: Vec, pub(crate) top_level_expressions: Vec, pub(crate) all_call_expressions: Vec, - pub(crate) var_decl_count_map: HashMap, - pub(crate) seen: HashMap, Box>, + pub(crate) var_decl_count_map: AtomHashMap, + pub(crate) seen: HashMap, (Box, Option)>, // `stylex.create` calls pub(crate) style_map: HashMap>, @@ -75,7 +81,7 @@ pub struct StateManager { // results of `stylex.create` calls that should be kept pub(crate) style_vars_to_keep: HashSet>, - pub(crate) member_object_ident_count_map: HashMap, + pub(crate) member_object_ident_count_map: AtomHashMap, pub(crate) in_stylex_create: bool, @@ -87,6 +93,8 @@ pub struct StateManager { pub(crate) injected_keyframes: IndexMap>, pub(crate) top_imports: Vec, + + pub(crate) cycle: TransformationCycle, } impl Default for StateManager { @@ -137,6 +145,8 @@ impl StateManager { prepend_import_module_items: vec![], injected_keyframes: IndexMap::new(), + + cycle: TransformationCycle::Initializing, } } @@ -177,7 +187,7 @@ impl StateManager { .stylex_import .clone() .into_iter() - .map(|import_source| match import_source.as_ref() { + .map(|import_source| match &import_source { ImportSources::Regular(regular) => regular.clone(), ImportSources::Named(named) => named.clone().r#as, }) diff --git a/packages/swc-plugin/src/shared/structures/types.rs b/packages/swc-plugin/src/shared/structures/types.rs index 09cc7dea..34dadb45 100644 --- a/packages/swc-plugin/src/shared/structures/types.rs +++ b/packages/swc-plugin/src/shared/structures/types.rs @@ -17,7 +17,7 @@ pub(crate) type EvaluateResultFns = IndexMap, IndexMap>)>; pub(crate) type EvaluationCallback = Rc>) -> Expr + 'static>; pub(crate) type FunctionMapMemberExpression = - HashMap, Box, Box>>>; -pub(crate) type FunctionMapIdentifiers = HashMap, Box>; + HashMap>>>; +pub(crate) type FunctionMapIdentifiers = HashMap>; pub(crate) type StylesObjectMap = IndexMap>>>; diff --git a/packages/swc-plugin/src/shared/utils/common.rs b/packages/swc-plugin/src/shared/utils/common.rs index 151513d5..07aac6c1 100644 --- a/packages/swc-plugin/src/shared/utils/common.rs +++ b/packages/swc-plugin/src/shared/utils/common.rs @@ -1,7 +1,7 @@ use radix_fmt::radix; use std::{ any::type_name, - collections::HashSet, + collections::{hash_map::Entry, HashMap, HashSet}, hash::{DefaultHasher, Hash, Hasher}, ops::Deref, path::PathBuf, @@ -92,10 +92,9 @@ pub(crate) fn wrap_key_in_quotes(key: &str, should_wrap_in_quotes: &bool) -> Str } pub fn reduce_ident_count<'a>(state: &'a mut StateManager, ident: &'a Ident) { - *state - .var_decl_count_map - .entry(ident.sym.clone()) - .or_insert(0) -= 1; + if let Entry::Occupied(mut entry) = state.var_decl_count_map.entry(ident.sym.clone()) { + *entry.get_mut() -= 1; + } } pub fn increase_member_ident(state: &mut StateManager, member_obj: &MemberExpr) { @@ -111,10 +110,12 @@ pub fn reduce_member_expression_count(state: &mut StateManager, member_expressio } pub fn reduce_member_ident_count(state: &mut StateManager, ident_atom: &Atom) { - *state + if let Entry::Occupied(mut entry) = state .member_object_ident_count_map .entry(ident_atom.clone()) - .or_insert(0) -= 1; + { + *entry.get_mut() -= 1; + } } pub fn increase_ident_count(state: &mut StateManager, ident: &Ident) { @@ -125,7 +126,7 @@ pub fn increase_member_ident_count(state: &mut StateManager, ident_atom: &Atom) increase_member_ident_count_by_count(state, ident_atom, 1); } -pub fn increase_ident_count_by_count(state: &mut StateManager, ident: &Ident, count: i8) { +pub fn increase_ident_count_by_count(state: &mut StateManager, ident: &Ident, count: i16) { let ident_id = &ident.sym; *state @@ -137,7 +138,7 @@ pub fn increase_ident_count_by_count(state: &mut StateManager, ident: &Ident, co pub fn increase_member_ident_count_by_count( state: &mut StateManager, ident_atom: &Atom, - count: i8, + count: i16, ) { *state .member_object_ident_count_map @@ -351,6 +352,74 @@ pub(crate) fn deep_merge_props( remove_duplicates(new_props.into_iter().rev().collect()) } +pub(crate) fn get_hash_map_difference( + orig_map: &HashMap, + compare_map: &HashMap, +) -> HashMap +where + K: Eq + Hash + Clone, + V: PartialEq + Clone, +{ + let mut diff = HashMap::new(); + + for (key, value) in orig_map { + if let Some(map2_value) = compare_map.get(key) { + if value != map2_value { + diff.insert(key.clone(), value.clone()); + } + } else { + diff.insert(key.clone(), value.clone()); + } + } + + for (key, value) in compare_map { + if !orig_map.contains_key(key) { + diff.insert(key.clone(), value.clone()); + } + } + + diff +} + +pub(crate) fn get_hash_map_value_difference( + orig_map: &HashMap, + map2: &HashMap, +) -> HashMap { + let mut diff = HashMap::new(); + + for (key, value) in orig_map { + if let Some(map2_value) = map2.get(key) { + if value != map2_value { + diff.insert(key.clone(), value - map2_value); + } + } else { + diff.insert(key.clone(), *value); + } + } + + diff +} + +pub(crate) fn sum_hash_map_values( + orig_map: &HashMap, + compare_map: &HashMap, +) -> HashMap { + let mut sum_map = HashMap::new(); + + for (key, value) in orig_map { + sum_map.insert(key.clone(), *value); + } + + for (key, value) in compare_map { + sum_map + .entry(key.clone()) + .and_modify(|e| *e += value) + .or_insert(*value); + } + + sum_map +} + pub(crate) fn get_css_value(key_value: KeyValueProp) -> (Box, Option) { let Some(obj) = key_value.value.as_object() else { return (key_value.value, None); diff --git a/packages/swc-plugin/src/shared/utils/js/evaluate.rs b/packages/swc-plugin/src/shared/utils/js/evaluate.rs index 4aa12d3d..d26c5fa3 100644 --- a/packages/swc-plugin/src/shared/utils/js/evaluate.rs +++ b/packages/swc-plugin/src/shared/utils/js/evaluate.rs @@ -10,9 +10,9 @@ use swc_core::{ common::{EqIgnoreSpan, DUMMY_SP}, ecma::{ ast::{ - ArrayLit, BlockStmtOrExpr, Callee, ComputedPropName, Expr, ExprOrSpread, Ident, KeyValueProp, - Lit, MemberProp, ModuleExportName, Number, ObjectLit, Prop, PropName, PropOrSpread, - TplElement, UnaryOp, VarDeclarator, + ArrayLit, BlockStmtOrExpr, CallExpr, Callee, ComputedPropName, Expr, ExprOrSpread, Ident, + KeyValueProp, Lit, MemberProp, ModuleExportName, Number, ObjectLit, Prop, PropName, + PropOrSpread, TplElement, UnaryOp, VarDeclarator, }, utils::{drop_span, ident::IdentLike, quote_ident, ExprExt}, }, @@ -51,9 +51,10 @@ use crate::shared::{ factories::{array_expression_factory, lit_str_factory, object_expression_factory}, }, common::{ - char_code_at, deep_merge_props, get_import_by_ident, get_key_str, get_string_val_from_lit, - get_var_decl_by_ident, get_var_decl_from, normalize_expr, remove_duplicates, - sort_numbers_factory, + char_code_at, deep_merge_props, get_hash_map_difference, get_hash_map_value_difference, + get_import_by_ident, get_key_str, get_string_val_from_lit, get_var_decl_by_ident, + get_var_decl_from, normalize_expr, reduce_ident_count, reduce_member_expression_count, + remove_duplicates, sort_numbers_factory, sum_hash_map_values, }, js::native_functions::{evaluate_filter, evaluate_join, evaluate_map}, }, @@ -209,12 +210,12 @@ fn _evaluate( takes_path: false, }; functions.insert( - Box::new(ident.clone()), + ident.clone(), Box::new(FunctionConfigType::Regular(function.clone())), ); member_expressions.insert( - Box::new(ImportSources::Regular("entry".to_string())), + ImportSources::Regular("entry".to_string()), Box::new(functions.clone()), ); } @@ -842,6 +843,7 @@ fn _evaluate( if second_arg.spread.is_some() { unimplemented!("Spread") } + let cached_first_arg = evaluate_cached(&first_arg.expr, state, fns); let cached_second_arg = evaluate_cached(&second_arg.expr, state, fns); @@ -1331,18 +1333,14 @@ fn _evaluate( } } } else { - let args: Vec> = call - .args - .iter() - .filter_map(|arg| evaluate_cached(&arg.expr, state, fns)) - .collect(); - if !state.confident { return None; } match func.fn_ptr { FunctionType::ArrayArgs(func) => { + let args = evaluate_func_call_args(call, state, fns); + let func_result = (func)( args .into_iter() @@ -1357,6 +1355,8 @@ fn _evaluate( return Some(Box::new(EvaluateResultValue::Expr(Box::new(func_result)))); } FunctionType::StylexExprFn(func) => { + let args = evaluate_func_call_args(call, state, fns); + let func_result = (func)( args.first().and_then(|arg| arg.as_expr().cloned()).unwrap(), &mut state.traversal_state, @@ -1365,6 +1365,8 @@ fn _evaluate( return Some(Box::new(EvaluateResultValue::Expr(Box::new(func_result)))); } FunctionType::StylexTypeFn(func) => { + let args = evaluate_func_call_args(call, state, fns); + let mut fn_args = IndexMap::default(); let expr = args @@ -1413,12 +1415,18 @@ fn _evaluate( match func.as_ref() { CallbackType::Array(ArrayJS::Map) => { + let args = evaluate_func_call_args(call, state, fns); + return evaluate_map(&args, &context); } CallbackType::Array(ArrayJS::Filter) => { + let args = evaluate_func_call_args(call, state, fns); + return evaluate_filter(&args, &context); } CallbackType::Array(ArrayJS::Join) => { + let args = evaluate_func_call_args(call, state, fns); + return evaluate_join( &args, &context, @@ -1519,8 +1527,6 @@ fn _evaluate( let result = num_args.first().unwrap().powf(*num_args.get(1).unwrap()); - // let trancated_num = trancate_f64(result); - return Some(Box::new(EvaluateResultValue::Expr(Box::new( number_to_expression(result), )))); @@ -1545,7 +1551,7 @@ fn _evaluate( } CallbackType::Math(MathJS::Min | MathJS::Max) => { let Some(Some(EvaluateResultValue::Vec(args))) = context.first() else { - panic!("Math.pow requires an argument") + panic!("Math.(min | max) requires an argument") }; let num_args = args_to_numbers(args, state, fns); @@ -1570,6 +1576,8 @@ fn _evaluate( panic!("String concat requires an argument") }; + let args = evaluate_func_call_args(call, state, fns); + let str_args = args .iter() .map(|arg| { @@ -1594,6 +1602,8 @@ fn _evaluate( let base_str = expr_to_str(base_str, &mut state.traversal_state, fns); + let args = evaluate_func_call_args(call, state, fns); + let num_args = args .iter() .map(|arg| { @@ -1740,6 +1750,19 @@ fn _evaluate( result } +fn evaluate_func_call_args( + call: &mut CallExpr, + state: &mut EvaluationState, + fns: &FunctionMap, +) -> Vec { + let args: Vec = call + .args + .iter() + .filter_map(|arg| evaluate_cached(&arg.expr, state, fns).map(|arg| *arg)) + .collect(); + args +} + fn args_to_numbers( args: &[Option], state: &mut EvaluationState, @@ -1876,24 +1899,56 @@ pub(crate) fn evaluate_cached( let existing = state.traversal_state.seen.get(&cleaned_path); match existing { - Some(evaluated_value) => { + Some((evaluated_value, var_decl_count_value_diff)) => { if evaluated_value.resolved { let resolved = evaluated_value.value.clone(); + match path { + Expr::Ident(ident) => reduce_ident_count(&mut state.traversal_state, ident), + Expr::Member(member) => { + reduce_member_expression_count(&mut state.traversal_state, member) + } + Expr::Object(_) => { + if let Some(var_decl_count_value_diff) = var_decl_count_value_diff { + state.traversal_state.var_decl_count_map = sum_hash_map_values( + var_decl_count_value_diff, + &state.traversal_state.var_decl_count_map, + ); + } + } + _ => {} + } + return resolved; } deopt(path, state) } None => { + let should_save_var_decl_count = path.is_object(); + + let var_decl_count_map_orig = + should_save_var_decl_count.then(|| state.traversal_state.var_decl_count_map.clone()); + let val = _evaluate(&mut cleaned_path, state, fns); + let var_decl_count_value_diff = var_decl_count_map_orig.as_ref().map(|orig| { + let var_decl_count_map_evaluated = &state.traversal_state.var_decl_count_map; + + let var_decl_count_map_diff = get_hash_map_difference(var_decl_count_map_evaluated, orig); + + get_hash_map_value_difference(&var_decl_count_map_diff, orig) + }); + if state.confident { state.traversal_state.seen.insert( Box::new(path.clone()), - Box::new(SeenValue { - value: val.clone(), - resolved: true, - }), + ( + Box::new(SeenValue { + value: val.clone(), + resolved: true, + }), + var_decl_count_value_diff, + ), ); } else { let item = SeenValue { @@ -1901,10 +1956,10 @@ pub(crate) fn evaluate_cached( resolved: false, }; - state - .traversal_state - .seen - .insert(Box::new(cleaned_path.clone()), Box::new(item)); + state.traversal_state.seen.insert( + Box::new(cleaned_path.clone()), + (Box::new(item), var_decl_count_value_diff), + ); } val diff --git a/packages/swc-plugin/src/shared/utils/js/native_functions.rs b/packages/swc-plugin/src/shared/utils/js/native_functions.rs index 30834756..6574c2ab 100644 --- a/packages/swc-plugin/src/shared/utils/js/native_functions.rs +++ b/packages/swc-plugin/src/shared/utils/js/native_functions.rs @@ -13,7 +13,7 @@ use swc_core::{ }; pub(crate) fn evaluate_map( - funcs: &[Box], + funcs: &[EvaluateResultValue], args: &[Option], ) -> Option> { let cb = funcs.first()?; @@ -75,7 +75,7 @@ pub(crate) fn evaluate_map( } pub(crate) fn evaluate_join( - funcs: &[Box], + funcs: &[EvaluateResultValue], args: &[Option], state: &mut StateManager, functions: &FunctionMap, @@ -104,7 +104,7 @@ pub(crate) fn evaluate_join( } pub(crate) fn evaluate_filter( - funcs: &[Box], + funcs: &[EvaluateResultValue], args: &[Option], ) -> Option> { let cb = funcs.first()?; diff --git a/packages/swc-plugin/src/shared/utils/validators.rs b/packages/swc-plugin/src/shared/utils/validators.rs index 823d261c..26789dfb 100644 --- a/packages/swc-plugin/src/shared/utils/validators.rs +++ b/packages/swc-plugin/src/shared/utils/validators.rs @@ -205,7 +205,7 @@ pub(crate) fn is_define_vars_call(call: &CallExpr, state: &StateManager) -> bool } pub(crate) fn is_target_call( - (call_name, imports_map): (&str, &HashSet>), + (call_name, imports_map): (&str, &HashSet), call: &CallExpr, state: &StateManager, ) -> bool { diff --git a/packages/swc-plugin/src/transform/fold.rs b/packages/swc-plugin/src/transform/fold.rs index 85ee95a1..7a423bc9 100644 --- a/packages/swc-plugin/src/transform/fold.rs +++ b/packages/swc-plugin/src/transform/fold.rs @@ -1,3 +1,4 @@ +mod fold_computed_prop_name_impl; mod fold_export_decl; mod fold_export_default_expr; mod fold_expr; @@ -17,8 +18,8 @@ use swc_core::{ common::comments::Comments, ecma::{ ast::{ - ExportDecl, ExportDefaultExpr, Expr, Ident, ImportDecl, MemberExpr, MemberProp, Module, - ModuleItem, PropName, Stmt, VarDeclarator, + ComputedPropName, ExportDecl, ExportDefaultExpr, Expr, Ident, ImportDecl, MemberExpr, + MemberProp, Module, ModuleItem, PropName, Stmt, VarDeclarator, }, visit::{noop_fold_type, Fold}, }, @@ -80,6 +81,10 @@ where self.fold_member_expr_impl(member_expresseion) } + fn fold_computed_prop_name(&mut self, computed_prop_name: ComputedPropName) -> ComputedPropName { + self.fold_computed_prop_name_impl(computed_prop_name) + } + fn fold_export_default_expr( &mut self, export_default_expr: ExportDefaultExpr, diff --git a/packages/swc-plugin/src/transform/fold/fold_computed_prop_name_impl.rs b/packages/swc-plugin/src/transform/fold/fold_computed_prop_name_impl.rs new file mode 100644 index 00000000..e65d5487 --- /dev/null +++ b/packages/swc-plugin/src/transform/fold/fold_computed_prop_name_impl.rs @@ -0,0 +1,41 @@ +use swc_core::{ + common::comments::Comments, + ecma::{ + ast::{ComputedPropName, Ident}, + visit::FoldWith, + }, +}; + +use crate::{ + shared::{ + enums::core::TransformationCycle, + utils::{ast::convertors::expr_to_str, common::increase_ident_count}, + }, + ModuleTransformVisitor, +}; + +impl ModuleTransformVisitor +where + C: Comments, +{ + pub(crate) fn fold_computed_prop_name_impl( + &mut self, + computed_prop_name: ComputedPropName, + ) -> ComputedPropName { + if self.state.cycle == TransformationCycle::Skip { + return computed_prop_name; + } + + if self.state.cycle == TransformationCycle::StateFilling && computed_prop_name.expr.is_lit() { + let expt_str = expr_to_str( + &computed_prop_name.expr, + &mut self.state, + &Default::default(), + ); + + increase_ident_count(&mut self.state, &Ident::from(expt_str.as_str())); + } + + computed_prop_name.fold_children_with(self) + } +} diff --git a/packages/swc-plugin/src/transform/fold/fold_export_decl.rs b/packages/swc-plugin/src/transform/fold/fold_export_decl.rs index 1ffc99b4..83926e93 100644 --- a/packages/swc-plugin/src/transform/fold/fold_export_decl.rs +++ b/packages/swc-plugin/src/transform/fold/fold_export_decl.rs @@ -7,7 +7,7 @@ use swc_core::{ }; use crate::{ - shared::{enums::core::ModuleCycle, utils::common::increase_ident_count_by_count}, + shared::{enums::core::TransformationCycle, utils::common::increase_ident_count_by_count}, ModuleTransformVisitor, }; @@ -16,11 +16,11 @@ where C: Comments, { pub(crate) fn fold_export_decl_impl(&mut self, export_decl: ExportDecl) -> ExportDecl { - if self.cycle == ModuleCycle::Skip { + if self.state.cycle == TransformationCycle::Skip { return export_decl; } - if self.cycle == ModuleCycle::StateFilling { + if self.state.cycle == TransformationCycle::StateFilling { if let Decl::Var(var_decl) = &export_decl.decl { for decl in &var_decl.decls { if let Some(ident) = decl.name.as_ident() { diff --git a/packages/swc-plugin/src/transform/fold/fold_export_default_expr.rs b/packages/swc-plugin/src/transform/fold/fold_export_default_expr.rs index 7100487a..2978b532 100644 --- a/packages/swc-plugin/src/transform/fold/fold_export_default_expr.rs +++ b/packages/swc-plugin/src/transform/fold/fold_export_default_expr.rs @@ -4,7 +4,7 @@ use swc_core::{ }; use crate::{ - shared::{enums::core::ModuleCycle, utils::common::normalize_expr}, + shared::{enums::core::TransformationCycle, utils::common::normalize_expr}, ModuleTransformVisitor, }; @@ -16,15 +16,15 @@ where &mut self, mut export_default_expr: ExportDefaultExpr, ) -> ExportDefaultExpr { - if self.cycle == ModuleCycle::Skip { + if self.state.cycle == TransformationCycle::Skip { return export_default_expr; } - if self.cycle == ModuleCycle::StateFilling { + if self.state.cycle == TransformationCycle::StateFilling { return export_default_expr.fold_children_with(self); } - if self.cycle == ModuleCycle::TransformEnter || self.cycle == ModuleCycle::TransformExit { + if self.state.cycle == TransformationCycle::TransformEnter || self.state.cycle == TransformationCycle::TransformExit { let normalized_expr = normalize_expr(&mut export_default_expr.expr); if let Some(value) = self.transform_call_expression(normalized_expr) { diff --git a/packages/swc-plugin/src/transform/fold/fold_expr.rs b/packages/swc-plugin/src/transform/fold/fold_expr.rs index 549430c3..d2c99cb8 100644 --- a/packages/swc-plugin/src/transform/fold/fold_expr.rs +++ b/packages/swc-plugin/src/transform/fold/fold_expr.rs @@ -3,24 +3,24 @@ use swc_core::{ ecma::{ast::Expr, visit::FoldWith}, }; -use crate::{shared::enums::core::ModuleCycle, ModuleTransformVisitor}; +use crate::{shared::enums::core::TransformationCycle, ModuleTransformVisitor}; impl ModuleTransformVisitor where C: Comments, { pub(crate) fn fold_expr_impl(&mut self, mut expr: Expr) -> Expr { - if self.cycle == ModuleCycle::Skip { + if self.state.cycle == TransformationCycle::Skip { return expr; } - if self.cycle == ModuleCycle::StateFilling { + if self.state.cycle == TransformationCycle::StateFilling { if let Some(call_expr) = expr.as_call() { self.state.all_call_expressions.push(call_expr.clone()); } } - if self.cycle == ModuleCycle::TransformEnter || self.cycle == ModuleCycle::TransformExit { + if self.state.cycle == TransformationCycle::TransformEnter || self.state.cycle == TransformationCycle::TransformExit { if let Some(value) = self.transform_call_expression(&mut expr) { return value; } diff --git a/packages/swc-plugin/src/transform/fold/fold_ident.rs b/packages/swc-plugin/src/transform/fold/fold_ident.rs index 7e0bb934..a9ee9708 100644 --- a/packages/swc-plugin/src/transform/fold/fold_ident.rs +++ b/packages/swc-plugin/src/transform/fold/fold_ident.rs @@ -1,7 +1,10 @@ use swc_core::{common::comments::Comments, ecma::ast::Ident}; use crate::{ - shared::{enums::core::ModuleCycle, utils::common::increase_ident_count}, + shared::{ + enums::core::TransformationCycle, + utils::common::{increase_ident_count, reduce_ident_count}, + }, ModuleTransformVisitor, }; @@ -10,13 +13,15 @@ where C: Comments, { pub(crate) fn fold_ident_impl(&mut self, ident: Ident) -> Ident { - if self.cycle == ModuleCycle::Skip { - return ident; - } - - if self.cycle == ModuleCycle::StateFilling { - increase_ident_count(&mut self.state, &ident); - } + match self.state.cycle { + TransformationCycle::StateFilling => { + increase_ident_count(&mut self.state, &ident); + } + TransformationCycle::Recounting => { + reduce_ident_count(&mut self.state, &ident); + } + _ => {} + }; ident } diff --git a/packages/swc-plugin/src/transform/fold/fold_import_decl.rs b/packages/swc-plugin/src/transform/fold/fold_import_decl.rs index 9e633074..6b011891 100644 --- a/packages/swc-plugin/src/transform/fold/fold_import_decl.rs +++ b/packages/swc-plugin/src/transform/fold/fold_import_decl.rs @@ -5,7 +5,7 @@ use swc_core::{ use crate::{ shared::{ - constants::messages::MUST_BE_DEFAULT_IMPORT, enums::core::ModuleCycle, + constants::messages::MUST_BE_DEFAULT_IMPORT, enums::core::TransformationCycle, structures::named_import_source::ImportSources, }, ModuleTransformVisitor, @@ -16,11 +16,11 @@ where C: Comments, { pub(crate) fn fold_import_decl_impl(&mut self, import_decl: ImportDecl) -> ImportDecl { - if self.cycle == ModuleCycle::Skip { + if self.state.cycle == TransformationCycle::Skip { return import_decl; } - if self.cycle == ModuleCycle::Initializing { + if self.state.cycle == TransformationCycle::Initializing { if import_decl.type_only { return import_decl; } @@ -46,7 +46,7 @@ where self .state .stylex_import - .insert(Box::new(ImportSources::Regular(local_name))); + .insert(ImportSources::Regular(local_name)); }; } ImportSpecifier::Namespace(import_specifier) => { @@ -58,7 +58,7 @@ where self .state .stylex_import - .insert(Box::new(ImportSources::Regular(local_name))); + .insert(ImportSources::Regular(local_name)); } } ImportSpecifier::Named(import_specifier) => { @@ -114,7 +114,7 @@ where self .state .stylex_import - .insert(Box::new(ImportSources::Regular(local_name.to_string()))); + .insert(ImportSources::Regular(local_name.to_string())); } } @@ -128,55 +128,46 @@ where self .state .stylex_create_import - .insert(Box::new(local_name_ident_atom)); + .insert(local_name_ident_atom); } "props" => { - self - .state - .stylex_props_import - .insert(Box::new(local_name_ident_atom)); + self.state.stylex_props_import.insert(local_name_ident_atom); } "attrs" => { - self - .state - .stylex_attrs_import - .insert(Box::new(local_name_ident_atom)); + self.state.stylex_attrs_import.insert(local_name_ident_atom); } "keyframes" => { self .state .stylex_keyframes_import - .insert(Box::new(local_name_ident_atom)); + .insert(local_name_ident_atom); } "include" => { self .state .stylex_include_import - .insert(Box::new(local_name_ident_atom)); + .insert(local_name_ident_atom); } "firstThatWorks" => { self .state .stylex_first_that_works_import - .insert(Box::new(local_name_ident_atom)); + .insert(local_name_ident_atom); } "defineVars" => { self .state .stylex_define_vars_import - .insert(Box::new(local_name_ident_atom)); + .insert(local_name_ident_atom); } "createTheme" => { self .state .stylex_create_theme_import - .insert(Box::new(local_name_ident_atom)); + .insert(local_name_ident_atom); } "types" => { - self - .state - .stylex_types_import - .insert(Box::new(local_name_ident_atom)); + self.state.stylex_types_import.insert(local_name_ident_atom); } _ => { unreachable!("{}", MUST_BE_DEFAULT_IMPORT) diff --git a/packages/swc-plugin/src/transform/fold/fold_member_expression.rs b/packages/swc-plugin/src/transform/fold/fold_member_expression.rs index 580e42d1..261ff32c 100644 --- a/packages/swc-plugin/src/transform/fold/fold_member_expression.rs +++ b/packages/swc-plugin/src/transform/fold/fold_member_expression.rs @@ -1,5 +1,4 @@ use swc_core::{ - atoms::Atom, common::comments::Comments, ecma::{ ast::{Expr, MemberExpr, MemberProp}, @@ -10,10 +9,10 @@ use swc_core::{ use crate::{ shared::{ enums::{ - core::ModuleCycle, + core::TransformationCycle, data_structures::style_vars_to_keep::{NonNullProp, NonNullProps, StyleVarsToKeep}, }, - utils::common::{increase_ident_count, increase_member_ident_count}, + utils::common::{increase_ident_count, increase_member_ident_count, reduce_member_ident_count}, }, ModuleTransformVisitor, }; @@ -23,64 +22,45 @@ where C: Comments, { pub(crate) fn fold_member_expr_impl(&mut self, member_expression: MemberExpr) -> MemberExpr { - if self.cycle == ModuleCycle::Skip { - return member_expression; - } - - if self.cycle == ModuleCycle::StateFilling { - if let Some(obj_ident) = member_expression.obj.as_ident() { - increase_member_ident_count(&mut self.state, &obj_ident.sym); - } - - return member_expression.fold_children_with(self); - } - - if self.cycle == ModuleCycle::PreCleaning { - let object = member_expression.obj.as_ref(); - let property = &member_expression.prop; - - let mut obj_name: Option = None; - let mut prop_name: Option = None; - - if let Expr::Ident(ident) = object { - let obj_ident_name = ident.sym.to_string(); - - obj_name = Some(ident.sym.clone()); - - if self.state.style_map.contains_key(&obj_ident_name) { - if let MemberProp::Ident(ident) = property { - prop_name = Some(ident.sym.clone()); + match self.state.cycle { + TransformationCycle::Skip => member_expression, + TransformationCycle::StateFilling | TransformationCycle::Recounting => { + if let Some(obj_ident) = member_expression.obj.as_ident() { + match self.state.cycle { + TransformationCycle::StateFilling => { + increase_member_ident_count(&mut self.state, &obj_ident.sym) + } + TransformationCycle::Recounting => {reduce_member_ident_count(&mut self.state, &obj_ident.sym)}, + _ => {} } } + member_expression.fold_children_with(self) } - - if let Some(obj_name) = obj_name.as_ref() { - if let Some(prop_name) = prop_name { - if let Some(count) = self.state.member_object_ident_count_map.get(obj_name) { - if self.state.style_map.contains_key(obj_name.as_str()) && count > &0 { - increase_ident_count( - &mut self.state, - object.as_ident().expect("Object not an ident"), - ); - - let style_var_to_keep = StyleVarsToKeep( - obj_name.clone(), - NonNullProp::Atom(prop_name.clone()), - NonNullProps::True, - ); - - self - .state - .style_vars_to_keep - .insert(Box::new(style_var_to_keep)); + TransformationCycle::PreCleaning => { + if let Expr::Ident(ident) = member_expression.obj.as_ref() { + let obj_ident_name = ident.sym.to_string(); + if self.state.style_map.contains_key(&obj_ident_name) { + if let MemberProp::Ident(prop_ident) = &member_expression.prop { + if let Some(count) = self.state.member_object_ident_count_map.get(&ident.sym) { + if count > &0 { + increase_ident_count(&mut self.state, ident); + let style_var_to_keep = StyleVarsToKeep( + ident.sym.clone(), + NonNullProp::Atom(prop_ident.sym.clone()), + NonNullProps::True, + ); + self + .state + .style_vars_to_keep + .insert(Box::new(style_var_to_keep)); + } + } } } } + member_expression } - - return member_expression; + _ => member_expression.fold_children_with(self), } - - member_expression.fold_children_with(self) } } diff --git a/packages/swc-plugin/src/transform/fold/fold_member_prop.rs b/packages/swc-plugin/src/transform/fold/fold_member_prop.rs index e373a4cd..0af88f1e 100644 --- a/packages/swc-plugin/src/transform/fold/fold_member_prop.rs +++ b/packages/swc-plugin/src/transform/fold/fold_member_prop.rs @@ -1,23 +1,22 @@ use swc_core::{ common::comments::Comments, - ecma::{ - ast::MemberProp, - visit::FoldWith, - }, + ecma::{ast::MemberProp, visit::FoldWith}, }; -use crate::{shared::enums::core::ModuleCycle, ModuleTransformVisitor}; +use crate::{shared::enums::core::TransformationCycle, ModuleTransformVisitor}; impl ModuleTransformVisitor where C: Comments, { pub(crate) fn fold_member_prop_impl(&mut self, member_prop: MemberProp) -> MemberProp { - if self.cycle == ModuleCycle::Skip { + if self.state.cycle == TransformationCycle::Skip { return member_prop; } - if self.cycle == ModuleCycle::StateFilling && member_prop.is_ident() { + if (self.state.cycle == TransformationCycle::StateFilling || self.state.cycle == TransformationCycle::Recounting) + && member_prop.is_ident() + { return member_prop; } diff --git a/packages/swc-plugin/src/transform/fold/fold_module.rs b/packages/swc-plugin/src/transform/fold/fold_module.rs index 5e532b93..00dfc7f4 100644 --- a/packages/swc-plugin/src/transform/fold/fold_module.rs +++ b/packages/swc-plugin/src/transform/fold/fold_module.rs @@ -5,7 +5,7 @@ use swc_core::{ use crate::{ shared::{ - enums::core::ModuleCycle, structures::meta_data::MetaData, + enums::core::TransformationCycle, structures::meta_data::MetaData, utils::common::fill_top_level_expressions, }, ModuleTransformVisitor, @@ -19,19 +19,19 @@ where let mut module = module.fold_children_with(self); if !self.state.import_paths.is_empty() { - self.cycle = ModuleCycle::StateFilling; + self.state.cycle = TransformationCycle::StateFilling; module = module.fold_children_with(self); fill_top_level_expressions(&module, &mut self.state); - self.cycle = ModuleCycle::TransformEnter; + self.state.cycle = TransformationCycle::TransformEnter; module = module.fold_children_with(self); - self.cycle = ModuleCycle::TransformExit; + self.state.cycle = TransformationCycle::TransformExit; module = module.fold_children_with(self); if self.state.options.runtime_injection.is_some() { - self.cycle = ModuleCycle::InjectStyles; + self.state.cycle = TransformationCycle::InjectStyles; module = module.fold_children_with(self); } else { // Preparing stylex metadata for css extraction @@ -57,13 +57,23 @@ where ); } - self.cycle = ModuleCycle::PreCleaning; + self.state.cycle = TransformationCycle::PreCleaning; module = module.fold_children_with(self); - self.cycle = ModuleCycle::Cleaning; - module.fold_children_with(self) + self.state.cycle = TransformationCycle::Cleaning; + + // NOTE: Reversing the module body to clean the module items in the correct order, + // so removing unused variable declarations will more efficient + // After cleaning the module items, the module body will be reversed back to its original order + module.body.reverse(); + + module = module.fold_children_with(self); + + module.body.reverse(); + + module } else { - self.cycle = ModuleCycle::Skip; + self.state.cycle = TransformationCycle::Skip; module } } diff --git a/packages/swc-plugin/src/transform/fold/fold_module_items.rs b/packages/swc-plugin/src/transform/fold/fold_module_items.rs index 565bb3fb..48d83f6d 100644 --- a/packages/swc-plugin/src/transform/fold/fold_module_items.rs +++ b/packages/swc-plugin/src/transform/fold/fold_module_items.rs @@ -8,7 +8,7 @@ use swc_core::{ }; use crate::{ - shared::{enums::core::ModuleCycle, utils::ast::factories::binding_ident_factory}, + shared::{enums::core::TransformationCycle, utils::ast::factories::binding_ident_factory}, ModuleTransformVisitor, }; @@ -17,20 +17,20 @@ where C: Comments, { pub(crate) fn fold_module_items(&mut self, module_items: Vec) -> Vec { - match self.cycle { - ModuleCycle::Skip => module_items, - ModuleCycle::Initializing => { + match self.state.cycle { + TransformationCycle::Skip => module_items, + TransformationCycle::Initializing => { let transformed_module_items = module_items.fold_children_with(self); if self.state.import_paths.is_empty() { - self.cycle = ModuleCycle::Skip; + self.state.cycle = TransformationCycle::Skip; return transformed_module_items; } transformed_module_items } - ModuleCycle::StateFilling => { + TransformationCycle::StateFilling => { module_items.iter().for_each(|module_item| { if let ModuleItem::Stmt(Stmt::Decl(Decl::Var(var_decl))) = module_item { var_decl.decls.iter().for_each(|decl| { @@ -45,10 +45,10 @@ where module_items.fold_children_with(self) } - ModuleCycle::TransformEnter => module_items.fold_children_with(self), - ModuleCycle::TransformExit => module_items.fold_children_with(self), - ModuleCycle::PreCleaning => module_items.fold_children_with(self), - ModuleCycle::InjectStyles => { + TransformationCycle::TransformEnter => module_items.fold_children_with(self), + TransformationCycle::TransformExit => module_items.fold_children_with(self), + TransformationCycle::PreCleaning => module_items.fold_children_with(self), + TransformationCycle::InjectStyles => { let mut result_module_items: Vec = self.state.prepend_include_module_items.clone(); @@ -125,7 +125,7 @@ where result_module_items } - ModuleCycle::Cleaning => { + TransformationCycle::Cleaning => { // We need it twice for a clear dead code after declaration transforms let mut module_items = module_items.fold_children_with(self); @@ -138,6 +138,7 @@ where module_items } + TransformationCycle::Recounting => module_items.fold_children_with(self), } } } diff --git a/packages/swc-plugin/src/transform/fold/fold_prop_name.rs b/packages/swc-plugin/src/transform/fold/fold_prop_name.rs index 6091b84b..1f7ba437 100644 --- a/packages/swc-plugin/src/transform/fold/fold_prop_name.rs +++ b/packages/swc-plugin/src/transform/fold/fold_prop_name.rs @@ -3,21 +3,17 @@ use swc_core::{ ecma::{ast::PropName, visit::FoldWith}, }; -use crate::{shared::enums::core::ModuleCycle, ModuleTransformVisitor}; +use crate::{shared::enums::core::TransformationCycle, ModuleTransformVisitor}; impl ModuleTransformVisitor where C: Comments, { pub(crate) fn fold_prop_name_impl(&mut self, prop_name: PropName) -> PropName { - if self.cycle == ModuleCycle::Skip { - return prop_name; + match self.state.cycle { + TransformationCycle::Skip => prop_name, + TransformationCycle::StateFilling | TransformationCycle::Recounting if prop_name.is_ident() => prop_name, + _ => prop_name.fold_children_with(self), } - - if self.cycle == ModuleCycle::StateFilling && prop_name.is_ident() { - return prop_name; - } - - prop_name.fold_children_with(self) } } diff --git a/packages/swc-plugin/src/transform/fold/fold_stmt.rs b/packages/swc-plugin/src/transform/fold/fold_stmt.rs index 4a3c6faa..22be675c 100644 --- a/packages/swc-plugin/src/transform/fold/fold_stmt.rs +++ b/packages/swc-plugin/src/transform/fold/fold_stmt.rs @@ -7,18 +7,18 @@ use swc_core::{ }, }; -use crate::{shared::enums::core::ModuleCycle, ModuleTransformVisitor}; +use crate::{shared::enums::core::TransformationCycle, ModuleTransformVisitor}; impl ModuleTransformVisitor where C: Comments, { pub(crate) fn fold_stmt_impl(&mut self, stmt: Stmt) -> Stmt { - if self.cycle == ModuleCycle::Skip { + if self.state.cycle == TransformationCycle::Skip { return stmt; } - if self.cycle == ModuleCycle::Cleaning { + if self.state.cycle == TransformationCycle::Cleaning { let mut stmt = stmt.fold_children_with(self); if let Some(Stmt::Decl(Decl::Var(var))) = stmt.as_ref() { diff --git a/packages/swc-plugin/src/transform/fold/fold_stmts.rs b/packages/swc-plugin/src/transform/fold/fold_stmts.rs index dd53ffcf..1732b169 100644 --- a/packages/swc-plugin/src/transform/fold/fold_stmts.rs +++ b/packages/swc-plugin/src/transform/fold/fold_stmts.rs @@ -3,18 +3,18 @@ use swc_core::{ ecma::{ast::Stmt, visit::FoldWith}, }; -use crate::{shared::enums::core::ModuleCycle, ModuleTransformVisitor}; +use crate::{shared::enums::core::TransformationCycle, ModuleTransformVisitor}; impl ModuleTransformVisitor where C: Comments, { pub(crate) fn fold_stmts_impl(&mut self, mut stmts: Vec) -> Vec { - if self.cycle == ModuleCycle::Skip { + if self.state.cycle == TransformationCycle::Skip { return stmts; } - if self.cycle == ModuleCycle::Cleaning { + if self.state.cycle == TransformationCycle::Cleaning { stmts.retain(|stmt| { // We use `matches` macro as this match is trivial. !matches!(stmt, Stmt::Empty(..)) diff --git a/packages/swc-plugin/src/transform/fold/fold_var_declarator.rs b/packages/swc-plugin/src/transform/fold/fold_var_declarator.rs index 49f66898..0cfc110d 100644 --- a/packages/swc-plugin/src/transform/fold/fold_var_declarator.rs +++ b/packages/swc-plugin/src/transform/fold/fold_var_declarator.rs @@ -12,7 +12,7 @@ use swc_core::{ use crate::{ shared::{ enums::{ - core::ModuleCycle, + core::TransformationCycle, data_structures::{ style_vars_to_keep::{NonNullProp, NonNullProps, StyleVarsToKeep}, top_level_expression::{TopLevelExpression, TopLevelExpressionKind}, @@ -31,109 +31,108 @@ where &mut self, mut var_declarator: VarDeclarator, ) -> VarDeclarator { - if self.cycle != ModuleCycle::Initializing - && self.cycle != ModuleCycle::StateFilling - && self.cycle != ModuleCycle::TransformEnter - && self.cycle != ModuleCycle::TransformExit - && self.cycle != ModuleCycle::PreCleaning - { - if self.cycle == ModuleCycle::Cleaning { - let mut vars_to_keep: HashMap = HashMap::new(); - - for StyleVarsToKeep(var_name, namespace_name, _) in self - .state - .style_vars_to_keep - .clone() - .into_iter() - .map(|item| *item) - { - match vars_to_keep.entry(var_name) { - Entry::Occupied(mut entry) => { - if let NonNullProps::Vec(vec) = entry.get_mut() { - if let NonNullProp::Atom(id) = namespace_name { - vec.push(id); - } + match self.state.cycle { + TransformationCycle::StateFilling => { + if let Some(Expr::Call(call)) = var_declarator.init.as_deref_mut() { + if let Some((declaration, member)) = self.process_declaration(call) { + let stylex_imports = self.state.stylex_import_stringified(); + + if let Some(declaration_string) = stylex_imports + .into_iter() + .find(|item| item.eq(declaration.0.as_str())) + .or_else(|| { + self + .state + .stylex_create_import + .iter() + .find(|decl| decl.eq_ignore_span(&&declaration.0.clone())) + .map(|decl| decl.to_string()) + }) + { + if self.state.cycle == TransformationCycle::StateFilling + && (member.as_str() == "create" || member.eq(declaration_string.as_str())) + { + self.props_declaration = var_declarator.name.as_ident().map(|ident| ident.to_id()); } } - Entry::Vacant(entry) => { - let value = match namespace_name { - NonNullProp::Atom(namespace_name) => NonNullProps::Vec(vec![namespace_name]), - NonNullProp::True => NonNullProps::True, - }; - entry.insert(value); - } } } - for (_, var_name) in self.state.style_vars.clone().into_iter() { - if var_declarator.name != var_name.name { - continue; - }; - - let var_decl = self.state.top_level_expressions.clone().into_iter().find( - |TopLevelExpression(_, expr, _)| { - var_name.init.clone().unwrap().eq(&Box::new(expr.clone())) - }, - ); - if let Some(TopLevelExpression(kind, _, _)) = var_decl { - if TopLevelExpressionKind::Stmt == kind { - if let Some(object) = var_declarator.init.as_mut() { - if let Some(mut object) = object.as_object().cloned() { - let namespaces_to_keep = - match vars_to_keep.get(&var_name.name.as_ident().unwrap().sym) { - Some(e) => match e { - NonNullProps::Vec(vec) => vec.clone(), - NonNullProps::True => vec![], - }, - None => vec![], - }; - - if !namespaces_to_keep.is_empty() { - let props = - self.retain_object_props(&mut object, namespaces_to_keep, var_name.as_ref()); - - object.props = props; - - var_declarator.init = Some(Box::new(Expr::from(object))); + var_declarator.fold_children_with(self) + } + TransformationCycle::Cleaning => { + { + let mut vars_to_keep: HashMap = HashMap::new(); + + for StyleVarsToKeep(var_name, namespace_name, _) in self + .state + .style_vars_to_keep + .clone() + .into_iter() + .map(|item| *item) + { + match vars_to_keep.entry(var_name) { + Entry::Occupied(mut entry) => { + if let NonNullProps::Vec(vec) = entry.get_mut() { + if let NonNullProp::Atom(id) = namespace_name { + vec.push(id); } } } + Entry::Vacant(entry) => { + let value = match namespace_name { + NonNullProp::Atom(namespace_name) => NonNullProps::Vec(vec![namespace_name]), + NonNullProp::True => NonNullProps::True, + }; + entry.insert(value); + } } } - } - } - - return var_declarator; - } - - if let Some(Expr::Call(call)) = var_declarator.init.as_deref_mut() { - if let Some((declaration, member)) = self.process_declaration(call) { - let stylex_imports = self.state.stylex_import_stringified(); - - let declaration_string = stylex_imports - .into_iter() - .find(|item| item.eq(declaration.0.as_str())) - .or_else(|| { - self - .state - .stylex_create_import - .iter() - .find(|decl| decl.eq_ignore_span(&&Box::new(declaration.0.clone()))) - .map(|decl| decl.to_string()) - }); - if let Some(declaration_string) = declaration_string { - if self.cycle == ModuleCycle::StateFilling - && (member.as_str() == "create" || member.eq(declaration_string.as_str())) - { - self.props_declaration = var_declarator.name.as_ident().map(|ident| ident.to_id()); + for (_, var_name) in self.state.style_vars.clone().into_iter() { + if var_declarator.name != var_name.name { + continue; + }; + + if let Some(TopLevelExpression(kind, _, _)) = + self.state.top_level_expressions.clone().into_iter().find( + |TopLevelExpression(_, expr, _)| { + var_name.init.clone().unwrap().eq(&Box::new(expr.clone())) + }, + ) + { + if TopLevelExpressionKind::Stmt == kind { + if let Some(object) = var_declarator.init.as_mut() { + if let Some(mut object) = object.as_object().cloned() { + let namespaces_to_keep = + match vars_to_keep.get(&var_name.name.as_ident().unwrap().sym) { + Some(NonNullProps::Vec(vec)) => vec.clone(), + _ => vec![], + }; + + if !namespaces_to_keep.is_empty() { + let props = self.retain_object_props( + &mut object, + namespaces_to_keep, + var_name.as_ref(), + ); + + object.props = props; + + var_declarator.init = Some(Box::new(Expr::from(object))); + } + } + } + } + } } } + + var_declarator } + TransformationCycle::Skip | TransformationCycle::InjectStyles => var_declarator, + _ => var_declarator.fold_children_with(self), } - - // Call the fold_children_with method on the VarDecl struct - var_declarator.fold_children_with(self) } fn retain_object_props( diff --git a/packages/swc-plugin/src/transform/fold/fold_var_declarators.rs b/packages/swc-plugin/src/transform/fold/fold_var_declarators.rs index c06aeb40..df3a4ec9 100644 --- a/packages/swc-plugin/src/transform/fold/fold_var_declarators.rs +++ b/packages/swc-plugin/src/transform/fold/fold_var_declarators.rs @@ -6,7 +6,7 @@ use swc_core::{ }, }; -use crate::{shared::enums::core::ModuleCycle, ModuleTransformVisitor}; +use crate::{shared::enums::core::TransformationCycle, ModuleTransformVisitor}; impl ModuleTransformVisitor where @@ -16,20 +16,26 @@ where &mut self, mut var_declarators: Vec, ) -> Vec { - match self.cycle { - ModuleCycle::Skip => { + match self.state.cycle { + TransformationCycle::Skip => { return var_declarators; } - ModuleCycle::Cleaning => { + TransformationCycle::Cleaning => { var_declarators.retain(|decl| { if let Pat::Ident(bind_ident) = &decl.name { let decl_id = &bind_ident.sym; - if self.state.var_decl_count_map.contains_key(decl_id) { - let count = self.state.var_decl_count_map.get(decl_id).unwrap(); - + if let Some(&count) = self.state.var_decl_count_map.get(decl_id) { // Remove the variable declaration if it is used only once after transformation. - let is_used = count > &1; + let is_used = count > 1; + + if !is_used { + self.state.cycle = TransformationCycle::Recounting; + + decl.clone().fold_children_with(self); + + self.state.cycle = TransformationCycle::Cleaning; + } return is_used; } diff --git a/packages/swc-plugin/src/transform/mod.rs b/packages/swc-plugin/src/transform/mod.rs index 0251d4bf..d32ef427 100644 --- a/packages/swc-plugin/src/transform/mod.rs +++ b/packages/swc-plugin/src/transform/mod.rs @@ -7,7 +7,7 @@ use swc_core::{ use crate::{ shared::{ - enums::core::ModuleCycle, + enums::core::TransformationCycle, structures::{ named_import_source::{ImportSources, RuntimeInjection}, plugin_pass::PluginPass, @@ -28,7 +28,6 @@ where C: Comments, { comments: C, - cycle: ModuleCycle, props_declaration: Option, pub(crate) state: Box, } @@ -48,16 +47,12 @@ where state.stylex_import.clone_from(&stylex_imports); - state.options.import_sources = stylex_imports - .into_iter() - .map(|stylex_import| *stylex_import) - .collect(); + state.options.import_sources = stylex_imports.into_iter().collect(); state._state = plugin_pass; ModuleTransformVisitor { comments, - cycle: ModuleCycle::Initializing, props_declaration: None, state, } @@ -88,10 +83,7 @@ where } }); - state.options.import_sources = stylex_imports - .into_iter() - .map(|stylex_import| *stylex_import) - .collect(); + state.options.import_sources = stylex_imports.into_iter().collect(); let plugin_pass = Box::new(plugin_pass.clone()); @@ -99,7 +91,6 @@ where ModuleTransformVisitor { comments, - cycle: ModuleCycle::Initializing, props_declaration: None, state, } @@ -126,7 +117,7 @@ where } }); - state.options.import_sources = stylex_imports.into_iter().map(|s_i| *s_i).collect(); + state.options.import_sources = stylex_imports.into_iter().collect(); let plugin_pass = plugin_pass.clone(); @@ -134,7 +125,6 @@ where ModuleTransformVisitor { comments, - cycle: ModuleCycle::Initializing, props_declaration: None, state, } @@ -148,7 +138,7 @@ where let ident_id = ident.to_id(); if stylex_imports.contains(&ident.sym.to_string()) - || (self.cycle == ModuleCycle::TransformEnter + || (self.state.cycle == TransformationCycle::TransformEnter && (self.state.stylex_create_import.contains(&ident.sym)) || self.state.stylex_props_import.contains(&ident.sym) || self.state.stylex_keyframes_import.contains(&ident.sym) @@ -158,14 +148,8 @@ where .contains(&ident.sym) || self.state.stylex_include_import.contains(&ident.sym) || self.state.stylex_types_import.contains(&ident.sym) - || self - .state - .stylex_create_theme_import - .contains(&ident.sym) - || self - .state - .stylex_define_vars_import - .contains(&ident.sym) + || self.state.stylex_create_theme_import.contains(&ident.sym) + || self.state.stylex_define_vars_import.contains(&ident.sym) || self.state.stylex_attrs_import.contains(&ident.sym)) { increase_ident_count(&mut self.state, ident); @@ -178,7 +162,7 @@ where let ident_id = ident.to_id(); if stylex_imports.contains(&ident.sym.to_string()) - || (self.cycle == ModuleCycle::TransformEnter + || (self.state.cycle == TransformationCycle::TransformEnter && (self.state.stylex_create_import.contains(&ident.sym)) || self.state.stylex_props_import.contains(&ident.sym) || self.state.stylex_keyframes_import.contains(&ident.sym) @@ -187,15 +171,9 @@ where .stylex_first_that_works_import .contains(&ident.sym) || self.state.stylex_include_import.contains(&ident.sym) - || self - .state - .stylex_create_theme_import - .contains(&ident.sym) + || self.state.stylex_create_theme_import.contains(&ident.sym) || self.state.stylex_types_import.contains(&ident.sym) - || self - .state - .stylex_define_vars_import - .contains(&ident.sym) + || self.state.stylex_define_vars_import.contains(&ident.sym) || self.state.stylex_attrs_import.contains(&ident.sym)) { if let MemberProp::Ident(ident) = &member.prop { @@ -253,24 +231,17 @@ where } } -fn fill_stylex_imports(config: &Option<&mut StyleXOptionsParams>) -> HashSet> { +fn fill_stylex_imports(config: &Option<&mut StyleXOptionsParams>) -> HashSet { let mut stylex_imports = HashSet::new(); - stylex_imports.insert(Box::new(ImportSources::Regular("stylex".to_string()))); - stylex_imports.insert(Box::new(ImportSources::Regular( - "@stylexjs/stylex".to_string(), - ))); + stylex_imports.insert(ImportSources::Regular("stylex".to_string())); + stylex_imports.insert(ImportSources::Regular("@stylexjs/stylex".to_string())); if let Some(stylex_imports_extends) = match config { Some(ref config) => config.import_sources.clone(), None => None, } { - stylex_imports.extend( - stylex_imports_extends - .into_iter() - .map(Box::new) - .collect::>>(), - ) + stylex_imports.extend(stylex_imports_extends) } stylex_imports diff --git a/packages/swc-plugin/src/transform/stylex/transform_stylex_calls.rs b/packages/swc-plugin/src/transform/stylex/transform_stylex_calls.rs index 55f3cf03..0befe34d 100644 --- a/packages/swc-plugin/src/transform/stylex/transform_stylex_calls.rs +++ b/packages/swc-plugin/src/transform/stylex/transform_stylex_calls.rs @@ -4,7 +4,7 @@ use swc_core::{ ecma::ast::{CallExpr, Callee, Expr, MemberProp}, }; -use crate::shared::enums::core::ModuleCycle; +use crate::shared::enums::core::TransformationCycle; use crate::ModuleTransformVisitor; impl ModuleTransformVisitor @@ -31,7 +31,7 @@ where } fn transform_stylex_fns(&mut self, ident_name: &Atom, call_expr: &mut CallExpr) -> Option { - if self.cycle == ModuleCycle::TransformEnter { + if self.state.cycle == TransformationCycle::TransformEnter { let (_, parent_var_decl) = &self.get_call_var_name(call_expr); if let Some(parent_var_decl) = parent_var_decl { @@ -57,7 +57,7 @@ where } } - if self.cycle == ModuleCycle::TransformExit { + if self.state.cycle == TransformationCycle::TransformExit { if self.state.stylex_props_import.contains(ident_name) { if let Some(value) = self.transform_stylex_props_call(call_expr) { return Some(value); diff --git a/packages/swc-plugin/src/transform/stylex/transform_stylex_create_call.rs b/packages/swc-plugin/src/transform/stylex/transform_stylex_create_call.rs index e244319a..b3650564 100644 --- a/packages/swc-plugin/src/transform/stylex/transform_stylex_create_call.rs +++ b/packages/swc-plugin/src/transform/stylex/transform_stylex_create_call.rs @@ -100,17 +100,17 @@ where let member_expression = member_expressions.get_mut(name).unwrap(); member_expression.insert( - Box::new("include".into()), + "include".into(), Box::new(FunctionConfigType::Regular(include_fn.clone())), ); member_expression.insert( - Box::new("firstThatWorks".into()), + "firstThatWorks".into(), Box::new(FunctionConfigType::Regular(first_that_works_fn.clone())), ); member_expression.insert( - Box::new("keyframes".into()), + "keyframes".into(), Box::new(FunctionConfigType::Regular(keyframes_fn.clone())), ); } diff --git a/packages/swc-plugin/src/transform/stylex/transform_stylex_create_theme_call.rs b/packages/swc-plugin/src/transform/stylex/transform_stylex_create_theme_call.rs index 9ee29b51..38de4211 100644 --- a/packages/swc-plugin/src/transform/stylex/transform_stylex_create_theme_call.rs +++ b/packages/swc-plugin/src/transform/stylex/transform_stylex_create_theme_call.rs @@ -83,12 +83,12 @@ where let member_expression = member_expressions.entry(name.clone()).or_default(); member_expression.insert( - Box::new("keyframes".into()), + "keyframes".into(), Box::new(FunctionConfigType::Regular(keyframes_fn.clone())), ); let identifier = identifiers - .entry(Box::new(name.get_import_str().into())) + .entry(name.get_import_str().into()) .or_insert(Box::new(FunctionConfigType::Map(HashMap::default()))); if let Some(identifier_map) = identifier.as_map_mut() { diff --git a/packages/swc-plugin/src/transform/stylex/transform_stylex_define_vars_call.rs b/packages/swc-plugin/src/transform/stylex/transform_stylex_define_vars_call.rs index 7ba45d8e..dbb819cc 100644 --- a/packages/swc-plugin/src/transform/stylex/transform_stylex_define_vars_call.rs +++ b/packages/swc-plugin/src/transform/stylex/transform_stylex_define_vars_call.rs @@ -70,12 +70,12 @@ where let member_expression = member_expressions.entry(name.clone()).or_default(); member_expression.insert( - Box::new("keyframes".into()), + "keyframes".into(), Box::new(FunctionConfigType::Regular(keyframes_fn.clone())), ); let identifier = identifiers - .entry(Box::new(name.get_import_str().into())) + .entry(name.get_import_str().into()) .or_insert(Box::new(FunctionConfigType::Map(HashMap::default()))); if let Some(identifier_map) = identifier.as_map_mut() { diff --git a/packages/swc-plugin/src/transform/stylex/transform_stylex_keyframes_call.rs b/packages/swc-plugin/src/transform/stylex/transform_stylex_keyframes_call.rs index 85eddf73..b53f633e 100644 --- a/packages/swc-plugin/src/transform/stylex/transform_stylex_keyframes_call.rs +++ b/packages/swc-plugin/src/transform/stylex/transform_stylex_keyframes_call.rs @@ -84,12 +84,12 @@ where let member_expression = member_expressions.get_mut(name).unwrap(); member_expression.insert( - Box::new("include".into()), + "include".into(), Box::new(FunctionConfigType::Regular(include_fn.clone())), ); member_expression.insert( - Box::new("firstThatWorks".into()), + "firstThatWorks".into(), Box::new(FunctionConfigType::Regular(first_that_works_fn.clone())), ); } diff --git a/packages/swc-plugin/tests/__swc_snapshots__/tests/stylex_transform_create_test/stylex_create_call.rs/transforms_style_object_with_key_containing_differend_types.js b/packages/swc-plugin/tests/__swc_snapshots__/tests/stylex_transform_create_test/stylex_create_call.rs/transforms_style_object_with_key_containing_differend_types.js index 1707c609..029471ef 100644 --- a/packages/swc-plugin/tests/__swc_snapshots__/tests/stylex_transform_create_test/stylex_create_call.rs/transforms_style_object_with_key_containing_differend_types.js +++ b/packages/swc-plugin/tests/__swc_snapshots__/tests/stylex_transform_create_test/stylex_create_call.rs/transforms_style_object_with_key_containing_differend_types.js @@ -1,16 +1,6 @@ import _inject from "@stylexjs/stylex/lib/stylex-inject"; var _inject2 = _inject; import stylex from 'stylex'; -const values = { - paddingBottom: '2px', - paddingLeft: '3px', - paddingRight: '4px', - marginRight: '5px', - marginLeft: '6px', - margin: { - bottom: '7px' - } -}; _inject2(".xrkmrrc{background-color:red}", 3000); _inject2(".xju2f9n{color:blue}", 3000); _inject2(".x4p5aij{padding-top:1px}", 4000); diff --git a/packages/swc-plugin/tests/evaluation/stylex_evaluation/stylex_evaluation_common.rs b/packages/swc-plugin/tests/evaluation/stylex_evaluation/stylex_evaluation_common.rs index b2b328ed..e33ba42c 100644 --- a/packages/swc-plugin/tests/evaluation/stylex_evaluation/stylex_evaluation_common.rs +++ b/packages/swc-plugin/tests/evaluation/stylex_evaluation/stylex_evaluation_common.rs @@ -173,14 +173,14 @@ fn evaluates_customs_functions() { }; identifiers.insert( - Box::new(Atom::from("makeArray")), + Atom::from("makeArray"), Box::new(FunctionConfigType::Regular(make_array)), ); let mut member_expressions = HashMap::new(); member_expressions.insert( - Box::new(ImportSources::Regular("stylex".to_string())), + ImportSources::Regular("stylex".to_string()), Box::new(identifiers.clone()), ); @@ -233,7 +233,7 @@ fn evaluates_custom_functions_that_return_non_static_values() { }; identifiers.insert( - Box::new(Atom::from("makeClass")), + Atom::from("makeClass"), Box::new(FunctionConfigType::Regular(make_class)), ); @@ -282,7 +282,7 @@ fn evaluates_custom_functions_used_as_spread_values() { }; identifiers.insert( - Box::new(Atom::from("makeObj")), + Atom::from("makeObj"), Box::new(FunctionConfigType::Regular(make_obj)), ); @@ -337,7 +337,7 @@ fn evaluates_custom_functions_that_take_paths() { }; identifiers.insert( - Box::new(Atom::from("getNode")), + Atom::from("getNode"), Box::new(FunctionConfigType::Regular(get_node)), ); diff --git a/packages/swc-plugin/tests/fixture/global-tokens-xs/input.js b/packages/swc-plugin/tests/fixture/global-tokens-xs/input.js index 105065e8..1ef5dbcc 100644 --- a/packages/swc-plugin/tests/fixture/global-tokens-xs/input.js +++ b/packages/swc-plugin/tests/fixture/global-tokens-xs/input.js @@ -25,3 +25,49 @@ const INTERCEPT = { export const text = stylex.defineVars({ xs: `${INTERCEPT.xs}rem`, }); + + +/** + * Color Tokens + */ +const DARK_MODE = "@media (prefers-color-scheme: dark)"; + +export const globalTokens = stylex.defineVars({ + foregroundR: { default: "0", [DARK_MODE]: "255" }, + foregroundG: { default: "0", [DARK_MODE]: "255" }, + foregroundB: { default: "0", [DARK_MODE]: "255" }, + + bgStartRGB: { default: "rgb(214, 219, 220)", [DARK_MODE]: "rgb(0, 0, 0)" }, + + bgEndR: { default: "255", [DARK_MODE]: "0" }, + bgEndG: { default: "255", [DARK_MODE]: "0" }, + bgEndB: { default: "255", [DARK_MODE]: "0" }, + + calloutRGB: { default: "rgb(238, 240, 241)", [DARK_MODE]: "rgb(20, 20, 20)" }, + calloutRGB50: { + default: "rgba(238, 240, 241, 0.5)", + [DARK_MODE]: "rgba(20, 20, 20, 0.5)", + }, + + calloutBorderR: { default: "172", [DARK_MODE]: "108" }, + calloutBorderG: { default: "175", [DARK_MODE]: "108" }, + calloutBorderB: { default: "176", [DARK_MODE]: "108" }, + + cardR: { default: "180", [DARK_MODE]: "100" }, + cardG: { default: "185", [DARK_MODE]: "100" }, + cardB: { default: "188", [DARK_MODE]: "100" }, + + cardBorderR: { default: "131", [DARK_MODE]: "200" }, + cardBorderG: { default: "134", [DARK_MODE]: "200" }, + cardBorderB: { default: "135", [DARK_MODE]: "200" }, + + primaryGlow: { + default: + "conic-gradient(from 180deg at 50% 50%, #16abff33 0deg, #0885ff33 55deg, #54d6ff33 120deg, #0071ff33 160deg, transparent 360deg)", + [DARK_MODE]: "radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0))", + }, + secondaryGlow: { + default: "radial-gradient(rgba(255, 255, 255, 1), rgba(255, 255, 255, 0))", + [DARK_MODE]: `linear-gradient(to bottom right, rgba(1, 65, 255, 0), rgba(1, 65, 255, 0), rgba(1, 65, 255, 0.3))`, + }, +}); diff --git a/packages/swc-plugin/tests/fixture/global-tokens-xs/output.js b/packages/swc-plugin/tests/fixture/global-tokens-xs/output.js index 8196f762..ccec8b0d 100644 --- a/packages/swc-plugin/tests/fixture/global-tokens-xs/output.js +++ b/packages/swc-plugin/tests/fixture/global-tokens-xs/output.js @@ -1,13 +1,33 @@ import _inject from "@stylexjs/stylex/lib/stylex-inject"; var _inject2 = _inject; import stylex from "@stylexjs/stylex"; -const MIN_WIDTH = 320; -// Font sizes in `rem` units -const MIN_FONT = { - xs: Math.round(MIN_BASE_SIZE / Math.pow(MIN_SCALE, 2) / 0.16) / 100 -}; _inject2(":root{--x1ogzt1a:0.69rem;}", 0); export const text = { xs: "var(--x1ogzt1a)", __themeName__: "x1lzvrc9" }; +_inject2(":root{--x9q2m40:0;--xpzz690:0;--x16lcx6o:0;--xjk46kt:rgb(214, 219, 220);--x19cfreg:255;--x5f91dp:255;--xtrkg9t:255;--xrj4b28:rgb(238, 240, 241);--x13ytpr0:rgba(238, 240, 241, 0.5);--xjray:172;--x1ats3qd:175;--x12b45e3:176;--x1efhglm:180;--x1w81gmp:185;--x13v9q97:188;--x14edl43:131;--xdi7wre:134;--x1livm2j:135;--x1r7qzpr:conic-gradient(from 180deg at 50% 50%, #16abff33 0deg, #0885ff33 55deg, #54d6ff33 120deg, #0071ff33 160deg, transparent 360deg);--x1xmdc3p:radial-gradient(rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));}", 0); +_inject2("@media (prefers-color-scheme: dark){:root{--x9q2m40:255;--xpzz690:255;--x16lcx6o:255;--xjk46kt:rgb(0, 0, 0);--x19cfreg:0;--x5f91dp:0;--xtrkg9t:0;--xrj4b28:rgb(20, 20, 20);--x13ytpr0:rgba(20, 20, 20, 0.5);--xjray:108;--x1ats3qd:108;--x12b45e3:108;--x1efhglm:100;--x1w81gmp:100;--x13v9q97:100;--x14edl43:200;--xdi7wre:200;--x1livm2j:200;--x1r7qzpr:radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));--x1xmdc3p:linear-gradient(to bottom right, rgba(1, 65, 255, 0), rgba(1, 65, 255, 0), rgba(1, 65, 255, 0.3));}}", 0.1); +export const globalTokens = { + foregroundR: "var(--x9q2m40)", + foregroundG: "var(--xpzz690)", + foregroundB: "var(--x16lcx6o)", + bgStartRGB: "var(--xjk46kt)", + bgEndR: "var(--x19cfreg)", + bgEndG: "var(--x5f91dp)", + bgEndB: "var(--xtrkg9t)", + calloutRGB: "var(--xrj4b28)", + calloutRGB50: "var(--x13ytpr0)", + calloutBorderR: "var(--xjray)", + calloutBorderG: "var(--x1ats3qd)", + calloutBorderB: "var(--x12b45e3)", + cardR: "var(--x1efhglm)", + cardG: "var(--x1w81gmp)", + cardB: "var(--x13v9q97)", + cardBorderR: "var(--x14edl43)", + cardBorderG: "var(--xdi7wre)", + cardBorderB: "var(--x1livm2j)", + primaryGlow: "var(--x1r7qzpr)", + secondaryGlow: "var(--x1xmdc3p)", + __themeName__: "xsbqktv" +}; diff --git a/packages/swc-plugin/tests/fixture/global-tokens/input.js b/packages/swc-plugin/tests/fixture/global-tokens/input.js index 0166221d..89d180da 100644 --- a/packages/swc-plugin/tests/fixture/global-tokens/input.js +++ b/packages/swc-plugin/tests/fixture/global-tokens/input.js @@ -25,6 +25,9 @@ const MAX_SCALE = 1.333; const MIN_BASE_SIZE = 16; const MAX_BASE_SIZE = 20; +const h2 = 'h2'; +const H3 = 'h3'; + // Font sizes in `rem` units const MIN_FONT = { xxs: Math.round(MIN_BASE_SIZE / Math.pow(MIN_SCALE, 3) / 0.16) / 100, @@ -33,8 +36,8 @@ const MIN_FONT = { p: Math.round(MIN_BASE_SIZE / 4) / 4, h5: Math.round((MIN_BASE_SIZE * MIN_SCALE) / 0.16) / 100, h4: Math.round((MIN_BASE_SIZE * Math.pow(MIN_SCALE, 2)) / 0.16) / 100, - h3: Math.round((MIN_BASE_SIZE * Math.pow(MIN_SCALE, 3)) / 0.16) / 100, - h2: Math.round((MIN_BASE_SIZE * Math.pow(MIN_SCALE, 4)) / 0.16) / 100, + [H3]: Math.round((MIN_BASE_SIZE * Math.pow(MIN_SCALE, 3)) / 0.16) / 100, + [h2]: Math.round((MIN_BASE_SIZE * Math.pow(MIN_SCALE, 4)) / 0.16) / 100, h1: Math.round((MIN_BASE_SIZE * Math.pow(MIN_SCALE, 5)) / 0.16) / 100, }; // Font sizes in `rem` units @@ -45,8 +48,8 @@ const MAX_FONT = { p: Math.round(MAX_BASE_SIZE / 4) / 4, h5: Math.round((MAX_BASE_SIZE * MAX_SCALE) / 0.16) / 100, h4: Math.round((MAX_BASE_SIZE * Math.pow(MAX_SCALE, 2)) / 0.16) / 100, - h3: Math.round((MAX_BASE_SIZE * Math.pow(MAX_SCALE, 3)) / 0.16) / 100, - h2: Math.round((MAX_BASE_SIZE * Math.pow(MAX_SCALE, 4)) / 0.16) / 100, + [H3]: Math.round((MAX_BASE_SIZE * Math.pow(MAX_SCALE, 3)) / 0.16) / 100, + [h2]: Math.round((MAX_BASE_SIZE * Math.pow(MAX_SCALE, 4)) / 0.16) / 100, h1: Math.round((MAX_BASE_SIZE * Math.pow(MAX_SCALE, 5)) / 0.16) / 100, }; const SLOPE = { @@ -56,8 +59,8 @@ const SLOPE = { p: (16 * (MAX_FONT.p - MIN_FONT.p)) / (MAX_WIDTH - MIN_WIDTH), h5: (16 * (MAX_FONT.h5 - MIN_FONT.h5)) / (MAX_WIDTH - MIN_WIDTH), h4: (16 * (MAX_FONT.h4 - MIN_FONT.h4)) / (MAX_WIDTH - MIN_WIDTH), - h3: (16 * (MAX_FONT.h3 - MIN_FONT.h3)) / (MAX_WIDTH - MIN_WIDTH), - h2: (16 * (MAX_FONT.h2 - MIN_FONT.h2)) / (MAX_WIDTH - MIN_WIDTH), + [H3]: (16 * (MAX_FONT[H3] - MIN_FONT[H3])) / (MAX_WIDTH - MIN_WIDTH), + [h2]: (16 * (MAX_FONT[h2] - MIN_FONT[h2])) / (MAX_WIDTH - MIN_WIDTH), h1: (16 * (MAX_FONT.h1 - MIN_FONT.h1)) / (MAX_WIDTH - MIN_WIDTH), }; const INTERCEPT = { @@ -67,14 +70,11 @@ const INTERCEPT = { p: Math.round(100 * (MIN_FONT.p - SLOPE.p * (MIN_WIDTH / 16))) / 100, h5: Math.round(100 * (MIN_FONT.h5 - SLOPE.h5 * (MIN_WIDTH / 16))) / 100, h4: Math.round(100 * (MIN_FONT.h4 - SLOPE.h4 * (MIN_WIDTH / 16))) / 100, - h3: Math.round(100 * (MIN_FONT.h3 - SLOPE.h3 * (MIN_WIDTH / 16))) / 100, - h2: Math.round(100 * (MIN_FONT.h2 - SLOPE.h2 * (MIN_WIDTH / 16))) / 100, + [H3]: Math.round(100 * (MIN_FONT[H3] - SLOPE[H3] * (MIN_WIDTH / 16))) / 100, + [h2]: Math.round(100 * (MIN_FONT[h2] - SLOPE[h2] * (MIN_WIDTH / 16))) / 100, h1: Math.round(100 * (MIN_FONT.h1 - SLOPE.h1 * (MIN_WIDTH / 16))) / 100, }; -const h2 = 'h2'; -const H3 = 'h3'; - export const text = stylex.defineVars({ xxs: `clamp(${Math.min(MIN_FONT.xxs)}rem, calc(${INTERCEPT.xxs}rem + ${Math.round(10000 * SLOPE.xxs) / 100 }vw), ${Math.max(MAX_FONT.xxs)}rem)`, @@ -88,10 +88,10 @@ export const text = stylex.defineVars({ }vw), ${Math.max(MAX_FONT.h5)}rem)`, h4: `clamp(${Math.min(MIN_FONT.h4)}rem, calc(${INTERCEPT.h4}rem + ${Math.round(10000 * SLOPE.h4) / 100 }vw), ${Math.max(MAX_FONT.h4)}rem)`, - [H3]: `clamp(${Math.min(MIN_FONT.h3)}rem, calc(${INTERCEPT.h3}rem + ${Math.round(10000 * SLOPE.h3) / 100 - }vw), ${Math.max(MAX_FONT.h3)}rem)`, - [h2]: `clamp(${Math.min(MIN_FONT.h2)}rem, calc(${INTERCEPT.h2}rem + ${Math.round(10000 * SLOPE.h2) / 100 - }vw), ${Math.max(MAX_FONT.h2)}rem)`, + [H3]: `clamp(${Math.min(MIN_FONT[H3])}rem, calc(${INTERCEPT[H3]}rem + ${Math.round(10000 * SLOPE.h3) / 100 + }vw), ${Math.max(MAX_FONT[H3])}rem)`, + [h2]: `clamp(${Math.min(MIN_FONT[h2])}rem, calc(${INTERCEPT[h2]}rem + ${Math.round(10000 * SLOPE[h2]) / 100 + }vw), ${Math.max(MAX_FONT[h2])}rem)`, ['h1']: `clamp(${Math.min(MIN_FONT.h1)}rem, calc(${INTERCEPT.h1}rem + ${Math.round(10000 * SLOPE.h1) / 100 }vw), ${Math.max(MAX_FONT.h1)}rem)`, }); diff --git a/packages/swc-plugin/tests/fixture/global-tokens/output.js b/packages/swc-plugin/tests/fixture/global-tokens/output.js index ce336058..59321328 100644 --- a/packages/swc-plugin/tests/fixture/global-tokens/output.js +++ b/packages/swc-plugin/tests/fixture/global-tokens/output.js @@ -1,75 +1,6 @@ import _inject from "@stylexjs/stylex/lib/stylex-inject"; var _inject2 = _inject; import stylex from "@stylexjs/stylex"; -/** - * o--o o o o o-O-o o-o o--o o-o o o o-O-o o-o - * | | | | | | \ | o o |\ | | | - * O-o | | | | | O O-o | | | \ | | o-o - * | | | | | | / | o o | \| | | - * o O---o o-o o-O-o o-o o o-o o o o o--o - * - * Reference: https://utopia.fyi/type/calculator - * - * The following constants are used to calculate fluid typography. - * Feel free to change these initial numbers to suit your needs. - * - * StyleX can compute all of this at compile time as all the information - * is statically available in the same file and the only functions used are - * the Math.pow and Math.round functions. - * - * NOTE: Any custom functions will not be able to be computed at compile time. - */ const MIN_WIDTH = 320; -const MAX_WIDTH = 1240; -const MIN_SCALE = 1.2; -const MAX_SCALE = 1.333; -const MIN_BASE_SIZE = 16; -const MAX_BASE_SIZE = 20; -// Font sizes in `rem` units -const MIN_FONT = { - xxs: Math.round(MIN_BASE_SIZE / Math.pow(MIN_SCALE, 3) / 0.16) / 100, - xs: Math.round(MIN_BASE_SIZE / Math.pow(MIN_SCALE, 2) / 0.16) / 100, - sm: Math.round(MIN_BASE_SIZE / MIN_SCALE / 0.16) / 100, - p: Math.round(MIN_BASE_SIZE / 4) / 4, - h5: Math.round(MIN_BASE_SIZE * MIN_SCALE / 0.16) / 100, - h4: Math.round(MIN_BASE_SIZE * Math.pow(MIN_SCALE, 2) / 0.16) / 100, - h3: Math.round(MIN_BASE_SIZE * Math.pow(MIN_SCALE, 3) / 0.16) / 100, - h2: Math.round(MIN_BASE_SIZE * Math.pow(MIN_SCALE, 4) / 0.16) / 100, - h1: Math.round(MIN_BASE_SIZE * Math.pow(MIN_SCALE, 5) / 0.16) / 100 -}; -// Font sizes in `rem` units -const MAX_FONT = { - xxs: Math.round(MAX_BASE_SIZE / Math.pow(MAX_SCALE, 3) / 0.16) / 100, - xs: Math.round(MAX_BASE_SIZE / Math.pow(MAX_SCALE, 2) / 0.16) / 100, - sm: Math.round(MAX_BASE_SIZE / MAX_SCALE / 0.16) / 100, - p: Math.round(MAX_BASE_SIZE / 4) / 4, - h5: Math.round(MAX_BASE_SIZE * MAX_SCALE / 0.16) / 100, - h4: Math.round(MAX_BASE_SIZE * Math.pow(MAX_SCALE, 2) / 0.16) / 100, - h3: Math.round(MAX_BASE_SIZE * Math.pow(MAX_SCALE, 3) / 0.16) / 100, - h2: Math.round(MAX_BASE_SIZE * Math.pow(MAX_SCALE, 4) / 0.16) / 100, - h1: Math.round(MAX_BASE_SIZE * Math.pow(MAX_SCALE, 5) / 0.16) / 100 -}; -const SLOPE = { - xxs: 16 * (MAX_FONT.xxs - MIN_FONT.xxs) / (MAX_WIDTH - MIN_WIDTH), - xs: 16 * (MAX_FONT.xs - MIN_FONT.xs) / (MAX_WIDTH - MIN_WIDTH), - sm: 16 * (MAX_FONT.sm - MIN_FONT.sm) / (MAX_WIDTH - MIN_WIDTH), - p: 16 * (MAX_FONT.p - MIN_FONT.p) / (MAX_WIDTH - MIN_WIDTH), - h5: 16 * (MAX_FONT.h5 - MIN_FONT.h5) / (MAX_WIDTH - MIN_WIDTH), - h4: 16 * (MAX_FONT.h4 - MIN_FONT.h4) / (MAX_WIDTH - MIN_WIDTH), - h3: 16 * (MAX_FONT.h3 - MIN_FONT.h3) / (MAX_WIDTH - MIN_WIDTH), - h2: 16 * (MAX_FONT.h2 - MIN_FONT.h2) / (MAX_WIDTH - MIN_WIDTH), - h1: 16 * (MAX_FONT.h1 - MIN_FONT.h1) / (MAX_WIDTH - MIN_WIDTH) -}; -const INTERCEPT = { - xxs: Math.round(100 * (MIN_FONT.xxs - SLOPE.xxs * (MIN_WIDTH / 16))) / 100, - xs: Math.round(100 * (MIN_FONT.xs - SLOPE.xs * (MIN_WIDTH / 16))) / 100, - sm: Math.round(100 * (MIN_FONT.sm - SLOPE.sm * (MIN_WIDTH / 16))) / 100, - p: Math.round(100 * (MIN_FONT.p - SLOPE.p * (MIN_WIDTH / 16))) / 100, - h5: Math.round(100 * (MIN_FONT.h5 - SLOPE.h5 * (MIN_WIDTH / 16))) / 100, - h4: Math.round(100 * (MIN_FONT.h4 - SLOPE.h4 * (MIN_WIDTH / 16))) / 100, - h3: Math.round(100 * (MIN_FONT.h3 - SLOPE.h3 * (MIN_WIDTH / 16))) / 100, - h2: Math.round(100 * (MIN_FONT.h2 - SLOPE.h2 * (MIN_WIDTH / 16))) / 100, - h1: Math.round(100 * (MIN_FONT.h1 - SLOPE.h1 * (MIN_WIDTH / 16))) / 100 -}; _inject2(":root{--x1ql1w94:clamp(0.58rem, calc(0.6rem + -0.09vw), 0.53rem);--x1ogzt1a:clamp(0.69rem, calc(0.69rem + 0.02vw), 0.7rem);--x16zehmx:clamp(0.83rem, calc(0.79rem + 0.19vw), 0.94rem);--xhk4hdt:clamp(1rem, calc(0.91rem + 0.43vw), 1.25rem);--xwuz3e6:clamp(1.2rem, calc(1.04rem + 0.82vw), 1.67rem);--xcuma3z:clamp(1.44rem, calc(1.17rem + 1.36vw), 2.22rem);--x1d2707x:clamp(1.73rem, calc(1.3rem + 2.14vw), 2.96rem);--xvxqfsp:clamp(2.07rem, calc(1.42rem + 3.27vw), 3.95rem);--x1cypdqd:clamp(2.49rem, calc(1.53rem + 4.82vw), 5.26rem);}", 0); export const text = { xxs: "var(--x1ql1w94)", @@ -83,93 +14,6 @@ export const text = { h1: "var(--x1cypdqd)", __themeName__: "x1lzvrc9" }; -/** - * o--o o o o o-O-o o-o o-o o--o O o-o o--o - * | | | | | | \ | | | / \ / | - * O-o | | | | | O o-o O--o o---oO O-o - * | | | | | | / | | | | \ | - * o O---o o-o o-O-o o-o o--o o o o o-o o--o - * - * Reference: https://utopia.fyi/space/calculator - * - * Similar to the fluid typography, we can create fluid values for spacing. - * Using similar formulas and similar scales. - * - * NOTE: It is common to have more varied needs for spacing than for font-size. - * So feel free to add some more values by following the pattern below. - * - * EXCEPT: We are using `px` instead of `rem` - * ------------------------------------------ - * When talking about font-size, it is the best practice to use - * `rem` so that an end user can change the font-size using the - * browser's font-size setting. - * - * However, when talking about spacing, it is the best practice to - * use `px` because using `rems` here makes font-size behave like zoom. - * - * Users that prefer larger text, don't neccessarily want larger spacing as well. - * - */ const MULT = { - xxxs: 0.25, - xxs: 0.5, - xs: 0.75, - sm: 1, - md: 1.5, - lg: 2, - xl: 3, - xxl: 4, - xxxl: 6, - xxxxl: 8 -}; -const MIN_SPACE = { - xxxs: MULT.xxxs * MIN_BASE_SIZE, - xxs: MULT.xxs * MIN_BASE_SIZE, - xs: MULT.xs * MIN_BASE_SIZE, - sm: MULT.sm * MIN_BASE_SIZE, - md: MULT.md * MIN_BASE_SIZE, - lg: MULT.lg * MIN_BASE_SIZE, - xl: MULT.xl * MIN_BASE_SIZE, - xxl: MULT.xxl * MIN_BASE_SIZE, - xxxl: MULT.xxxl * MIN_BASE_SIZE, - xxxxl: MULT.xxxxl * MIN_BASE_SIZE -}; -const MAX_SPACE = { - xxxs: MULT.xxxs * MAX_BASE_SIZE, - xxs: MULT.xxs * MAX_BASE_SIZE, - xs: MULT.xs * MAX_BASE_SIZE, - sm: MULT.sm * MAX_BASE_SIZE, - md: MULT.md * MAX_BASE_SIZE, - lg: MULT.lg * MAX_BASE_SIZE, - xl: MULT.xl * MAX_BASE_SIZE, - xxl: MULT.xxl * MAX_BASE_SIZE, - xxxl: MULT.xxxl * MAX_BASE_SIZE, - xxxxl: MULT.xxxxl * MAX_BASE_SIZE -}; -const SLOPE_SPACE = { - xxxs: (MAX_SPACE.xxxs - MIN_SPACE.xxxs) / (MAX_WIDTH - MIN_WIDTH), - xxs: (MAX_SPACE.xxs - MIN_SPACE.xxs) / (MAX_WIDTH - MIN_WIDTH), - xs: (MAX_SPACE.xs - MIN_SPACE.xs) / (MAX_WIDTH - MIN_WIDTH), - sm: (MAX_SPACE.sm - MIN_SPACE.sm) / (MAX_WIDTH - MIN_WIDTH), - md: (MAX_SPACE.md - MIN_SPACE.md) / (MAX_WIDTH - MIN_WIDTH), - lg: (MAX_SPACE.lg - MIN_SPACE.lg) / (MAX_WIDTH - MIN_WIDTH), - xl: (MAX_SPACE.xl - MIN_SPACE.xl) / (MAX_WIDTH - MIN_WIDTH), - xxl: (MAX_SPACE.xxl - MIN_SPACE.xxl) / (MAX_WIDTH - MIN_WIDTH), - xxxl: (MAX_SPACE.xxxl - MIN_SPACE.xxxl) / (MAX_WIDTH - MIN_WIDTH), - xxxxl: (MAX_SPACE.xxxxl - MIN_SPACE.xxxxl) / (MAX_WIDTH - MIN_WIDTH) -}; -// rounded to the nearest 0.25px -const INTERCEPT_SPACE = { - xxxs: Math.round(4 * (MIN_SPACE.xxxs - SLOPE_SPACE.xxxs * MIN_WIDTH)) / 4, - xxs: Math.round(4 * (MIN_SPACE.xxs - SLOPE_SPACE.xxs * MIN_WIDTH)) / 4, - xs: Math.round(4 * (MIN_SPACE.xs - SLOPE_SPACE.xs * MIN_WIDTH)) / 4, - sm: Math.round(4 * (MIN_SPACE.sm - SLOPE_SPACE.sm * MIN_WIDTH)) / 4, - md: Math.round(4 * (MIN_SPACE.md - SLOPE_SPACE.md * MIN_WIDTH)) / 4, - lg: Math.round(4 * (MIN_SPACE.lg - SLOPE_SPACE.lg * MIN_WIDTH)) / 4, - xl: Math.round(4 * (MIN_SPACE.xl - SLOPE_SPACE.xl * MIN_WIDTH)) / 4, - xxl: Math.round(4 * (MIN_SPACE.xxl - SLOPE_SPACE.xxl * MIN_WIDTH)) / 4, - xxxl: Math.round(4 * (MIN_SPACE.xxxl - SLOPE_SPACE.xxxl * MIN_WIDTH)) / 4, - xxxxl: Math.round(4 * (MIN_SPACE.xxxxl - SLOPE_SPACE.xxxxl * MIN_WIDTH)) / 4 -}; _inject2(":root{--xe27369:clamp(4px, calc(3.75px - 0.11vw), 5px);--xbjetdn:clamp(8px, calc(7.25px - 0.22vw), 10px);--x1ixl80x:clamp(12px, calc(11px - 0.33vw), 15px);--x1kvcwuq:clamp(16px, calc(14.5px - 0.43vw), 20px);--xmdt6tw:clamp(24px, calc(22px - 0.65vw), 30px);--x1wksnfy:clamp(32px, calc(29.25px - 0.87vw), 40px);--xoxmq3b:clamp(48px, calc(43.75px - 1.3vw), 60px);--xdo4ik8:clamp(64px, calc(58.5px - 1.74vw), 80px);--x2u3u4d:clamp(96px, calc(87.75px - 2.61vw), 120px);--xmk1p5w:clamp(128px, calc(116.75px - 3.48vw), 160px);}", 0); export const spacing = { xxxs: "var(--xe27369)", @@ -184,9 +28,6 @@ export const spacing = { xxxxl: "var(--xmk1p5w)", __themeName__: "x14ijk3f" }; -/** - * Color Tokens - */ const DARK_MODE = "@media (prefers-color-scheme: dark)"; _inject2(':root{--xdkvadk:1240px;--x1v9y61d:ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", "Fira Mono", "Droid Sans Mono", "Courier New", monospace;--xu8xumw:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--x9q2m40:0;--xpzz690:0;--x16lcx6o:0;--xjk46kt:rgb(214, 219, 220);--x19cfreg:255;--x5f91dp:255;--xtrkg9t:255;--xrj4b28:rgb(238, 240, 241);--x13ytpr0:rgba(238, 240, 241, 0.5);--xjray:172;--x1ats3qd:175;--x12b45e3:176;--x1efhglm:180;--x1w81gmp:185;--x13v9q97:188;--x14edl43:131;--xdi7wre:134;--x1livm2j:135;--x1r7qzpr:conic-gradient(from 180deg at 50% 50%, #16abff33 0deg, #0885ff33 55deg, #54d6ff33 120deg, #0071ff33 160deg, transparent 360deg);--x1xmdc3p:radial-gradient(rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));}', 0); _inject2("@media (prefers-color-scheme: dark){:root{--x9q2m40:255;--xpzz690:255;--x16lcx6o:255;--xjk46kt:rgb(0, 0, 0);--x19cfreg:0;--x5f91dp:0;--xtrkg9t:0;--xrj4b28:rgb(20, 20, 20);--x13ytpr0:rgba(20, 20, 20, 0.5);--xjray:108;--x1ats3qd:108;--x12b45e3:108;--x1efhglm:100;--x1w81gmp:100;--x13v9q97:100;--x14edl43:200;--xdi7wre:200;--x1livm2j:200;--x1r7qzpr:radial-gradient(rgba(1, 65, 255, 0.4), rgba(1, 65, 255, 0));--x1xmdc3p:linear-gradient(to bottom right, rgba(1, 65, 255, 0), rgba(1, 65, 255, 0), rgba(1, 65, 255, 0.3));}}", 0.1); export const globalTokens = {