Skip to content

Commit

Permalink
feat: add not allowed nested pseudo function warning
Browse files Browse the repository at this point in the history
  • Loading branch information
ahabhgk committed May 8, 2024
1 parent 80c75c1 commit 4ac316a
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 26 deletions.
86 changes: 61 additions & 25 deletions src/dependencies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,22 @@ impl BalancedStack {
}
}
}

pub fn inside_mode_function(&self) -> Option<Pos> {
let mut iter = self.0.iter();
loop {
if let Some(last) = iter.next_back() {
if matches!(
last.kind,
BalancedItemKind::LocalFn | BalancedItemKind::GlobalFn
) {
return Some(last.range.start);
}
} else {
return None;
}
}
}
}

#[derive(Debug)]
Expand Down Expand Up @@ -473,6 +489,7 @@ pub enum Warning<'s> {
ExpectedUrlBefore { range: Range, when: &'s str },
ExpectedLayerBefore { range: Range, when: &'s str },
InconsistentModeResult { range: Range },
ExpectedNotInside { range: Range, pseudo: &'s str },
}

impl Display for Warning<'_> {
Expand All @@ -498,6 +515,7 @@ impl Display for Warning<'_> {
"The 'layer(...)' in '{when}' should be before 'supports(...)'"
),
Warning::InconsistentModeResult { .. } => write!(f, "Inconsistent rule global/local (multiple selectors must result in the same mode for the rule)"),
Warning::ExpectedNotInside { pseudo, .. } => write!(f, "A '{pseudo}' is not allowed inside of a ':local()' or ':global()'"),
}
}
}
Expand Down Expand Up @@ -1132,29 +1150,33 @@ impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> Visitor<'s> for LexDepen
return Some(());
};
if let Some(mode_data) = &mut self.mode_data {
let is_function = matches!(
let mut is_function = matches!(
last.kind,
BalancedItemKind::LocalFn | BalancedItemKind::GlobalFn
);
if is_function
|| matches!(
last.kind,
BalancedItemKind::LocalClass | BalancedItemKind::GlobalClass
)
{
if is_function {
let start = self.consume_back_white_space_and_comments_pos(lexer, start)?;
self.handle_dependency
.handle_dependency(Dependency::Replace {
content: "",
range: Range::new(start, end),
});
} else {
self.balanced.pop_mode_pseudo_class(mode_data);
let popped = self.balanced.pop_without_moda_data();
debug_assert!(matches!(popped.unwrap().kind, BalancedItemKind::Other));
}
return Some(());
let is_class = matches!(
last.kind,
BalancedItemKind::LocalClass | BalancedItemKind::GlobalClass
);
if is_class {
self.balanced.pop_mode_pseudo_class(mode_data);
let popped = self.balanced.pop_without_moda_data().unwrap();
debug_assert!(!matches!(
popped.kind,
BalancedItemKind::GlobalClass | BalancedItemKind::LocalClass
));
is_function = matches!(
popped.kind,
BalancedItemKind::LocalFn | BalancedItemKind::GlobalFn
);
}
if is_function {
let start = self.consume_back_white_space_and_comments_pos(lexer, start)?;
self.handle_dependency
.handle_dependency(Dependency::Replace {
content: "",
range: Range::new(start, end),
});
}
}
if let Scope::InAtImport(ref mut import_data) = self.scope {
Expand Down Expand Up @@ -1308,20 +1330,27 @@ impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> Visitor<'s> for LexDepen
Some(())
}

fn pseudo_function(&mut self, lexer: &mut Lexer, start: Pos, end: Pos) -> Option<()> {
fn pseudo_function(&mut self, lexer: &mut Lexer<'s>, start: Pos, end: Pos) -> Option<()> {
let name = lexer.slice(start, end)?.to_ascii_lowercase();
self.balanced.push(
BalancedItem::new(&name, start, end),
self.mode_data.as_mut(),
);
if self.mode_data.is_some() && (name == ":global(" || name == ":local(") {
if let Some(inside_start) = self.balanced.inside_mode_function() {
self.handle_warning
.handle_warning(Warning::ExpectedNotInside {
range: Range::new(inside_start, end),
pseudo: lexer.slice(start, end)?,
});
}
lexer.consume_white_space_and_comments()?;
self.handle_dependency
.handle_dependency(Dependency::Replace {
content: "",
range: Range::new(start, lexer.cur_pos()?),
});
}
self.balanced.push(
BalancedItem::new(&name, start, end),
self.mode_data.as_mut(),
);
Some(())
}

Expand All @@ -1331,6 +1360,13 @@ impl<'s, D: HandleDependency<'s>, W: HandleWarning<'s>> Visitor<'s> for LexDepen
};
let name = lexer.slice(start, end)?.to_ascii_lowercase();
if name == ":global" || name == ":local" {
if let Some(inside_start) = self.balanced.inside_mode_function() {
self.handle_warning
.handle_warning(Warning::ExpectedNotInside {
range: Range::new(inside_start, end),
pseudo: lexer.slice(start, end)?,
});
}
self.balanced.push(
BalancedItem::new(&name, start, end),
self.mode_data.as_mut(),
Expand Down
36 changes: 36 additions & 0 deletions tests/postcss_plugins/modules_local_by_default_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,3 +687,39 @@ fn throw_on_inconsistent_selector_result() {
"Inconsistent",
);
}

#[test]
fn throw_on_nested_locals() {
test_with_warning(
":local(:local(.foo)) {}",
":local(.foo) {}",
"is not allowed inside",
);
}

#[test]
fn throw_on_nested_globals() {
test_with_warning(
":global(:global(.foo)) {}",
".foo {}",
"is not allowed inside",
);
}

#[test]
fn throw_on_nested_mixed() {
test_with_warning(
":local(:global(.foo)) {}",
".foo {}",
"is not allowed inside",
);
}

#[test]
fn throw_on_nested_broad_local() {
test_with_warning(
":global(:local .foo) {}",
":local(.foo) {}",
"is not allowed inside",
);
}
10 changes: 9 additions & 1 deletion tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ fn assert_warning(input: &str, warning: &Warning, range_content: &str) {
| Warning::ExpectedUrl { range, .. }
| Warning::ExpectedUrlBefore { range, .. }
| Warning::ExpectedLayerBefore { range, .. }
| Warning::InconsistentModeResult { range } => {
| Warning::InconsistentModeResult { range }
| Warning::ExpectedNotInside { range, .. } => {
assert_eq!(slice_range(input, range).unwrap(), range_content);
}
};
Expand Down Expand Up @@ -905,6 +906,13 @@ fn css_modules_pseudo_6() {
assert_eq!(dependencies.len(), 5);
}

#[test]
fn t() {
let input = ":global(:local .foo) {}";
let (dependencies, warnings) = collect_css_modules_dependencies(input);
dbg!(dependencies, warnings);
}

#[test]
fn css_modules_nesting() {
let input = indoc! {r#"
Expand Down

0 comments on commit 4ac316a

Please sign in to comment.