Skip to content

Commit

Permalink
Merge branch 'main' into custom-class-naming
Browse files Browse the repository at this point in the history
  • Loading branch information
jantimon authored Dec 6, 2024
2 parents 4b0a757 + 4068803 commit d533da5
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 62 deletions.
2 changes: 2 additions & 0 deletions .changeset/strong-falcons-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
---
2 changes: 1 addition & 1 deletion packages/yak-swc/css_in_js_parser/src/parse_css.rs
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ mod tests {
);
let all_declarations = declarations
.into_iter()
.chain(declarations2.into_iter())
.chain(declarations2)
.collect::<Vec<_>>();
assert_debug_snapshot!((state1, state2, all_declarations));
}
Expand Down
34 changes: 17 additions & 17 deletions packages/yak-swc/yak_swc/benches/extension_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@ use regex::Regex;

fn main() {
// These are a quick and dirty replacement for tests just to be sure
assert_eq!(true, ends_with_impl("file.yak.ts"));
assert_eq!(false, ends_with_impl("file.yak"));
assert_eq!(false, ends_with_impl("file.yak.tsx.nope"));

assert_eq!(true, regex_impl("file.yak.ts"));
assert_eq!(false, regex_impl("file.yak"));
assert_eq!(false, regex_impl("file.yak.tsx.nope"));

assert_eq!(true, last_chars_impl("file.yak.ts"));
assert_eq!(false, last_chars_impl("file.yak"));
assert_eq!(false, last_chars_impl("file.yak.tsx.nope"));
assert_eq!(true, last_chars_impl("file.yak.tsx"));

assert_eq!(true, last_chars_impl_macro("file.yak.ts"));
assert_eq!(false, last_chars_impl_macro("file.yak"));
assert_eq!(false, last_chars_impl_macro("file.yak.tsx.nope"));
assert_eq!(true, last_chars_impl_macro("file.yak.tsx"));
assert!(ends_with_impl("file.yak.ts"));
assert!(!ends_with_impl("file.yak"));
assert!(!ends_with_impl("file.yak.tsx.nope"));

assert!(regex_impl("file.yak.ts"));
assert!(!regex_impl("file.yak"));
assert!(!regex_impl("file.yak.tsx.nope"));

assert!(last_chars_impl("file.yak.ts"));
assert!(!last_chars_impl("file.yak"));
assert!(!last_chars_impl("file.yak.tsx.nope"));
assert!(last_chars_impl("file.yak.tsx"));

assert!(last_chars_impl_macro("file.yak.ts"));
assert!(!last_chars_impl_macro("file.yak"));
assert!(!last_chars_impl_macro("file.yak.tsx.nope"));
assert!(last_chars_impl_macro("file.yak.tsx"));

// and that's the actual benchmark
divan::main();
Expand Down
55 changes: 37 additions & 18 deletions packages/yak-swc/yak_swc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use utils::encode_module_import::{encode_module_import, ImportKind};
mod variable_visitor;
use variable_visitor::{ScopedVariableReference, VariableVisitor};
mod yak_imports;
use yak_imports::YakImportVisitor;
use yak_imports::{visit_module_imports, YakImports};
mod yak_file_visitor;
use yak_file_visitor::YakFileVisitor;
mod math_evaluate;
Expand Down Expand Up @@ -86,7 +86,7 @@ where
/// Visitor to gather all imports from the current program
/// Used to check if the current program is using next-yak
/// to idenftify css-in-js expressions
yak_library_imports: YakImportVisitor,
yak_library_imports: Option<YakImports>,
/// Variable Name to Unique CSS Identifier Mapping\
/// e.g. const Rotation = keyframes`...` -> Rotation\
/// e.g. const Button = styled.button`...` -> Button\
Expand Down Expand Up @@ -119,7 +119,7 @@ where
current_condition: vec![],
current_exported: false,
variables: VariableVisitor::new(),
yak_library_imports: YakImportVisitor::new(),
yak_library_imports: None,
naming_convention: NamingConvention::new(filename.clone(), dev_mode, prefix),
variable_name_selector_mapping: FxHashMap::default(),
expression_replacement: None,
Expand All @@ -134,6 +134,13 @@ where
self.current_css_state.is_some()
}

fn yak_imports(&self) -> &YakImports {
self
.yak_library_imports
.as_ref()
.expect("Internal error: yak_library_imports is None - this should be impossible as imports are parsed in the initial program visit before any other processing")
}

/// Try to get the component id of the current styled component mixin or animation
/// e.g. const Button = styled.button`color: red;` -> Button#1
fn get_current_component_id(&self) -> ScopedVariableReference {
Expand Down Expand Up @@ -290,7 +297,7 @@ where
// constant mixins e.g.
// const highlight = css`color: red;`
// const Button = styled.button`&:hover { ${highlight}; }`
if is_valid_tagged_tpl(&tagged_tpl, &self.yak_library_imports.yak_css_idents) {
if is_valid_tagged_tpl(&tagged_tpl, self.yak_imports().yak_css_idents()) {
let (inline_runtime_exprs, inline_runtime_css_vars) =
self.process_yak_literal(&mut tagged_tpl.clone(), css_state.clone());
runtime_expressions.extend(inline_runtime_exprs);
Expand All @@ -299,10 +306,8 @@ where
// keyframes - of animations which have not been parsed yet
// const Button = styled.button`animation: ${highlight};`
// const highlight = keyframes`from { color: red; }`
else if is_valid_tagged_tpl(
&tagged_tpl,
&self.yak_library_imports.yak_keyframes_idents,
) {
else if is_valid_tagged_tpl(&tagged_tpl, self.yak_imports().yak_keyframes_idents())
{
// Create a unique name for the keyframe
let keyframe_name = self
.naming_convention
Expand Down Expand Up @@ -376,7 +381,7 @@ ${{() => {var}}};\n",
// Handle inline css literals
// e.g. styled.button`${css`color: red;`};`
else if let Expr::TaggedTpl(tpl) = &mut **expr {
if is_valid_tagged_tpl(tpl, &self.yak_library_imports.yak_css_idents) {
if is_valid_tagged_tpl(tpl, self.yak_imports().yak_css_idents()) {
let (inline_runtime_exprs, inline_runtime_css_vars) =
self.process_yak_literal(tpl, css_state.clone());
runtime_expressions.extend(inline_runtime_exprs);
Expand Down Expand Up @@ -442,6 +447,8 @@ ${{() => {var}}};\n",
*expr.clone(),
self
.yak_library_imports
.as_mut()
.unwrap()
.get_yak_utility_ident("unitPostFix".to_string()),
unit.to_string(),
)
Expand Down Expand Up @@ -481,12 +488,14 @@ where
GenericComments: Comments,
{
fn visit_mut_program(&mut self, program: &mut Program) {
let mut yak_import_visitor = YakImportVisitor::new();
program.visit_mut_children_with(&mut yak_import_visitor);
self.yak_library_imports = yak_import_visitor;
if let Program::Module(module) = program {
self.yak_library_imports = Some(visit_module_imports(module));
} else {
return;
}

// Skip this program only if yak is not used at all
if !self.yak_library_imports.is_using_next_yak() {
if !self.yak_imports().is_using_next_yak() {
return;
}

Expand Down Expand Up @@ -517,6 +526,8 @@ where
import_declaration.specifiers.extend(
self
.yak_library_imports
.as_ref()
.unwrap()
.get_yak_utility_import_declaration(),
);
break;
Expand Down Expand Up @@ -568,7 +579,7 @@ where
/// To store the current name which can be used for class names
/// e.g. Button for const Button = styled.button`color: red;`
fn visit_mut_var_decl(&mut self, n: &mut VarDecl) {
if !self.yak_library_imports.is_using_next_yak() {
if !self.yak_imports().is_using_next_yak() {
return;
}
for decl in &mut n.decls {
Expand All @@ -588,7 +599,7 @@ where
/// To store the current name which can be used for class names
/// e.g. Button for const obj = { Button: styled.button`color: red;` }
fn visit_mut_object_lit(&mut self, n: &mut ObjectLit) {
if !self.yak_library_imports.is_using_next_yak() {
if !self.yak_imports().is_using_next_yak() {
return;
}
if self.current_variable_name.is_none() {
Expand Down Expand Up @@ -627,7 +638,7 @@ where

// Visit JSX expressions for css prop support
fn visit_mut_jsx_opening_element(&mut self, n: &mut JSXOpeningElement) {
if !self.yak_library_imports.is_using_next_yak() {
if !self.yak_imports().is_using_next_yak() {
return;
}
let css_prop = n.has_css_prop();
Expand All @@ -640,6 +651,8 @@ where
n,
&self
.yak_library_imports
.as_mut()
.unwrap()
.get_yak_utility_ident("mergeCssProp".into()),
);
}
Expand All @@ -655,7 +668,7 @@ where
if let Some(scoped_name) = extract_ident_and_parts(n) {
if let Some(constant_value) = self.variables.get_const_value(&scoped_name) {
if let Expr::TaggedTpl(tpl) = *constant_value {
if is_valid_tagged_tpl(&tpl, &self.yak_library_imports.yak_css_idents) {
if is_valid_tagged_tpl(&tpl, self.yak_imports().yak_css_idents()) {
let replacement_before = self.expression_replacement.clone();
let tpl = &mut tpl.clone();
tpl.span = n.span();
Expand Down Expand Up @@ -730,7 +743,11 @@ where
/// Visit tagged template literals
/// This is where the css-in-js expressions are
fn visit_mut_tagged_tpl(&mut self, n: &mut TaggedTpl) {
let yak_library_function_name = self.yak_library_imports.get_yak_library_function_name(n);
let yak_library_function_name = self
.yak_library_imports
.as_mut()
.unwrap()
.get_yak_library_function_name(n);
if yak_library_function_name.is_none() {
n.visit_mut_children_with(self);
return;
Expand Down Expand Up @@ -841,6 +858,8 @@ where
if let Expr::Ident(ident) = &**callee {
if self
.yak_library_imports
.as_mut()
.unwrap()
.get_yak_library_name_for_ident(&ident.to_id())
== Some(atom!("atoms"))
{
Expand Down
32 changes: 25 additions & 7 deletions packages/yak-swc/yak_swc/src/yak_file_visitor.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::yak_imports::YakImportVisitor;
use swc_core::atoms::atom;
use swc_core::common::Spanned;
use swc_core::ecma::ast::*;
use swc_core::ecma::visit::{Fold, VisitMut, VisitMutWith};
use swc_core::plugin::errors::HANDLER;

use crate::yak_imports::{visit_module_imports, YakImports};

pub struct YakFileVisitor {
yak_imports: YakImportVisitor,
yak_imports: Option<YakImports>,
is_inside_css_tpl: bool,
}

Expand All @@ -16,7 +17,7 @@ pub struct YakFileVisitor {
impl YakFileVisitor {
pub fn new() -> Self {
Self {
yak_imports: YakImportVisitor::new(),
yak_imports: None,
is_inside_css_tpl: false,
}
}
Expand All @@ -33,12 +34,19 @@ impl YakFileVisitor {
true
});
}

fn yak_imports(&self) -> &YakImports {
self
.yak_imports
.as_ref()
.expect("Internal error: yak_library_imports is None - this should be impossible as imports are parsed in the initial program visit before any other processing")
}
}

impl VisitMut for YakFileVisitor {
fn visit_mut_module(&mut self, module: &mut Module) {
module.visit_mut_children_with(&mut self.yak_imports);
if self.yak_imports.is_using_next_yak() {
self.yak_imports = Some(visit_module_imports(module));
if self.yak_imports().is_using_next_yak() {
self.remove_next_yak_imports(module);
module.visit_mut_children_with(self);
}
Expand All @@ -51,7 +59,12 @@ impl VisitMut for YakFileVisitor {
// This is necessary as the mixin is also imported at runtime and a string would be
// interpreted as a class name
if let Expr::TaggedTpl(n) = expr {
if let Some(name) = self.yak_imports.get_yak_library_function_name(n) {
if let Some(name) = self
.yak_imports
.as_mut()
.unwrap()
.get_yak_library_function_name(n)
{
if name == atom!("css") {
*expr = ObjectLit {
span: n.span,
Expand All @@ -73,7 +86,12 @@ impl VisitMut for YakFileVisitor {
}

fn visit_mut_tagged_tpl(&mut self, n: &mut TaggedTpl) {
if let Some(name) = self.yak_imports.get_yak_library_function_name(n) {
if let Some(name) = self
.yak_imports
.as_mut()
.unwrap()
.get_yak_library_function_name(n)
{
// Right now only css template literals are allowed
if name != atom!("css") {
HANDLER.with(|handler| {
Expand Down
Loading

0 comments on commit d533da5

Please sign in to comment.