Skip to content

Commit

Permalink
feat: local property decl
Browse files Browse the repository at this point in the history
  • Loading branch information
ahabhgk committed May 3, 2024
1 parent dd5fb07 commit 42e3aa5
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 60 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Lexes CSS modules returning their dependencies metadata.
- [x] :local, :local(), :global, :global()
- [x] local scope by default
- [x] nesting
- [ ] var(), @property
- [x] var(), @property
- [ ] @keyframe
- [ ] more warnings
- [ ] composes
Expand Down
57 changes: 44 additions & 13 deletions src/dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ pub enum Dependency<'s> {
name: &'s str,
range: Range,
},
LocalPropertyDecl {
name: &'s str,
range: Range,
},
ICSSExport {
prop: &'s str,
value: &'s str,
Expand Down Expand Up @@ -344,10 +348,9 @@ impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> LexDependencies<'s, D, W
lexer.consume_white_space_and_comments()?;
let c = lexer.cur()?;
if c != C_LEFT_CURLY {
let end = lexer.peek_pos()?;
self.handle_warning.handle_warning(Warning::Unexpected {
message: "Expected '{' during parsing of ':export'",
range: Range::new(lexer.cur_pos()?, end),
range: Range::new(lexer.cur_pos()?, lexer.peek_pos()?),
});
return Some(());
}
Expand All @@ -360,10 +363,9 @@ impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> LexDependencies<'s, D, W
let prop_end = lexer.cur_pos()?;
lexer.consume_white_space_and_comments()?;
if lexer.cur()? != C_COLON {
let end = lexer.peek_pos()?;
self.handle_warning.handle_warning(Warning::Unexpected {
message: "Expected ':' during parsing of ':export'",
range: Range::new(lexer.cur_pos()?, end),
range: Range::new(lexer.cur_pos()?, lexer.peek_pos()?),
});
return Some(());
}
Expand Down Expand Up @@ -392,22 +394,21 @@ impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> LexDependencies<'s, D, W

fn lex_local_var(&mut self, lexer: &mut Lexer<'s>) -> Option<()> {
lexer.consume_white_space_and_comments()?;
let minus_start = lexer.cur_pos()?;
let start = lexer.cur_pos()?;
if lexer.cur()? != C_HYPHEN_MINUS || lexer.peek()? != C_HYPHEN_MINUS {
let end = lexer.peek2_pos()?;
self.handle_warning.handle_warning(Warning::Unexpected {
message: "Expected starts with '--' during parsing of CSS variable name",
range: Range::new(minus_start, end),
range: Range::new(start, lexer.peek2_pos()?),
});
return Some(());
}
lexer.consume_ident_sequence()?;
let start = minus_start + 2;
let name_start = start + 2;
let end = lexer.cur_pos()?;
self.handle_dependency
.handle_dependency(Dependency::LocalVar {
name: lexer.slice(start, end)?,
range: Range::new(minus_start, end),
name: lexer.slice(name_start, end)?,
range: Range::new(start, end),
});
Some(())
}
Expand All @@ -421,10 +422,9 @@ impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> LexDependencies<'s, D, W
) -> Option<()> {
lexer.consume_white_space_and_comments()?;
if lexer.cur()? != C_COLON {
let end = lexer.peek_pos()?;
self.handle_warning.handle_warning(Warning::Unexpected {
message: "Expected ':' during parsing of local CSS variable declaration",
range: Range::new(lexer.cur_pos()?, end),
range: Range::new(lexer.cur_pos()?, lexer.peek_pos()?),
});
return Some(());
}
Expand All @@ -436,6 +436,35 @@ impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> LexDependencies<'s, D, W
});
Some(())
}

fn lex_local_property_decl(&mut self, lexer: &mut Lexer<'s>) -> Option<()> {
lexer.consume_white_space_and_comments()?;
let start = lexer.cur_pos()?;
if lexer.cur()? != C_HYPHEN_MINUS || lexer.peek()? != C_HYPHEN_MINUS {
self.handle_warning.handle_warning(Warning::Unexpected {
message: "Expected starts with '--' during parsing of @property name",
range: Range::new(start, lexer.peek2_pos()?),
});
return Some(());
}
lexer.consume_ident_sequence()?;
let name_start = start + 2;
let end = lexer.cur_pos()?;
self.handle_dependency
.handle_dependency(Dependency::LocalPropertyDecl {
name: lexer.slice(name_start, end)?,
range: Range::new(start, end),
});
lexer.consume_white_space_and_comments()?;
if lexer.cur()? != C_LEFT_CURLY {
self.handle_warning.handle_warning(Warning::Unexpected {
message: "Expected '{' during parsing of @property",
range: Range::new(lexer.cur_pos()?, lexer.peek_pos()?),
});
return Some(());
}
Some(())
}
}

impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> Visitor<'s> for LexDependencies<'s, D, W> {
Expand Down Expand Up @@ -526,7 +555,7 @@ impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> Visitor<'s> for LexDepen
Some(())
}

fn at_keyword(&mut self, lexer: &mut Lexer, start: Pos, end: Pos) -> Option<()> {
fn at_keyword(&mut self, lexer: &mut Lexer<'s>, start: Pos, end: Pos) -> Option<()> {
let name = lexer.slice(start, end)?.to_ascii_lowercase();
if name == "@namespace" {
self.scope = Scope::AtNamespaceInvalid;
Expand All @@ -550,6 +579,8 @@ impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> Visitor<'s> for LexDepen
|| name == "@container"
{
self.is_next_rule_prelude = true;
} else if self.mode_data.is_some() && name == "@property" {
self.lex_local_property_decl(lexer)?;
}
// else if self.allow_mode_switch {
// self.is_next_rule_prelude = false;
Expand Down
88 changes: 42 additions & 46 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,7 @@ fn assert_local_ident_dependency(input: &str, dependency: &Dependency, name: &st
assert_eq!(slice_range(input, range).unwrap(), name);
}

fn assert_local_var_dependency(
input: &str,
dependency: &Dependency,
name: &str,
range_content: &str,
) {
fn assert_local_var_dependency(input: &str, dependency: &Dependency, name: &str) {
let Dependency::LocalVar {
name: actual_name,
range,
Expand All @@ -230,15 +225,10 @@ fn assert_local_var_dependency(
return assert!(false);
};
assert_eq!(*actual_name, name);
assert_eq!(slice_range(input, range).unwrap(), range_content);
assert_eq!(slice_range(input, range).unwrap(), format!("--{}", name));
}

fn assert_local_var_decl_dependency(
input: &str,
dependency: &Dependency,
name: &str,
range_content: &str,
) {
fn assert_local_var_decl_dependency(input: &str, dependency: &Dependency, name: &str) {
let Dependency::LocalVarDecl {
range,
name: actual_name,
Expand All @@ -247,7 +237,19 @@ fn assert_local_var_decl_dependency(
return assert!(false);
};
assert_eq!(*actual_name, name);
assert_eq!(slice_range(input, range).unwrap(), range_content);
assert_eq!(slice_range(input, range).unwrap(), format!("--{}", name));
}

fn assert_local_property_decl_dependency(input: &str, dependency: &Dependency, name: &str) {
let Dependency::LocalPropertyDecl {
name: actual_name,
range,
} = dependency
else {
return assert!(false);
};
assert_eq!(*actual_name, name);
assert_eq!(slice_range(input, range).unwrap(), format!("--{}", name));
}

fn assert_replace_dependency(
Expand Down Expand Up @@ -835,8 +837,8 @@ fn css_modules_local_var() {
let (dependencies, warnings) = collect_css_modules_dependencies(input);
assert!(warnings.is_empty());
assert_local_ident_dependency(input, &dependencies[0], "vars");
assert_local_var_dependency(input, &dependencies[1], "local-color", "--local-color");
assert_local_var_decl_dependency(input, &dependencies[2], "local-color", "--local-color");
assert_local_var_dependency(input, &dependencies[1], "local-color");
assert_local_var_decl_dependency(input, &dependencies[2], "local-color");
assert_local_ident_dependency(input, &dependencies[3], "globalVars");
assert_replace_dependency(input, &dependencies[4], "", ":global ");
dbg!(dependencies, warnings);
Expand All @@ -847,12 +849,7 @@ fn css_modules_local_var_minified_1() {
let input = "body{margin:0;font-family:var(--bs-body-font-family);}";
let (dependencies, warnings) = collect_css_modules_dependencies(input);
assert!(warnings.is_empty());
assert_local_var_dependency(
input,
&dependencies[0],
"bs-body-font-family",
"--bs-body-font-family",
);
assert_local_var_dependency(input, &dependencies[0], "bs-body-font-family");
}

#[test]
Expand All @@ -861,30 +858,29 @@ fn css_modules_local_var_minified_2() {
let (dependencies, warnings) = collect_css_modules_dependencies(input);
assert!(warnings.is_empty());
assert_local_ident_dependency(input, &dependencies[0], "table-primary");
assert_local_var_decl_dependency(
input,
&dependencies[1],
"bs-table-color",
"--bs-table-color",
);
assert_local_var_decl_dependency(
input,
&dependencies[2],
"bs-table-border-color",
"--bs-table-border-color",
);
assert_local_var_dependency(
input,
&dependencies[3],
"bs-table-color",
"--bs-table-color",
);
assert_local_var_dependency(
input,
&dependencies[4],
"bs-table-border-color",
"--bs-table-border-color",
);
assert_local_var_decl_dependency(input, &dependencies[1], "bs-table-color");
assert_local_var_decl_dependency(input, &dependencies[2], "bs-table-border-color");
assert_local_var_dependency(input, &dependencies[3], "bs-table-color");
assert_local_var_dependency(input, &dependencies[4], "bs-table-border-color");
}

#[test]
fn css_modules_property() {
let input = indoc! {r#"
@property --my-color {
syntax: "<color>";
inherits: false;
initial-value: #c0ffee;
}
.class {
color: var(--my-color);
}
"#};
let (dependencies, warnings) = collect_css_modules_dependencies(input);
assert!(warnings.is_empty());
assert_local_property_decl_dependency(input, &dependencies[0], "my-color");
assert_local_ident_dependency(input, &dependencies[1], "class");
assert_local_var_dependency(input, &dependencies[2], "my-color");
}

#[test]
Expand Down

0 comments on commit 42e3aa5

Please sign in to comment.