Skip to content

Commit a549898

Browse files
committed
feat: implementing the base @scope
1 parent 856d460 commit a549898

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-0
lines changed

node/src/transformer.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ impl<'i> Visitor<'i, AtRule<'i>> for JsVisitor {
277277
CssRule::LayerStatement(..) => "layer-statement",
278278
CssRule::Property(..) => "property",
279279
CssRule::Container(..) => "container",
280+
CssRule::Scope(..) => "scope",
280281
CssRule::MozDocument(..) => "moz-document",
281282
CssRule::Nesting(..) => "nesting",
282283
CssRule::Viewport(..) => "viewport",

src/lib.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21823,6 +21823,29 @@ mod tests {
2182321823
);
2182421824
}
2182521825

21826+
#[test]
21827+
fn test_at_scope() {
21828+
minify_test(
21829+
r#"
21830+
@scope {
21831+
.foo {
21832+
display: flex;
21833+
}
21834+
}"#,
21835+
"@scope{.foo{display:flex}}",
21836+
);
21837+
minify_test(
21838+
r#"
21839+
@scope {
21840+
:scope {
21841+
display: flex;
21842+
color: lightblue;
21843+
}
21844+
}"#,
21845+
"@scope{:scope{color:#add8e6;display:flex}}",
21846+
);
21847+
}
21848+
2182621849
#[test]
2182721850
fn test_custom_media() {
2182821851
custom_media_test(

src/parser.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use crate::rules::container::{ContainerName, ContainerRule};
77
use crate::rules::font_palette_values::FontPaletteValuesRule;
88
use crate::rules::layer::{LayerBlockRule, LayerStatementRule};
99
use crate::rules::property::PropertyRule;
10+
use crate::rules::scope::ScopeRule;
1011
use crate::rules::viewport::ViewportRule;
12+
1113
use crate::rules::{
1214
counter_style::CounterStyleRule,
1315
custom_media::CustomMediaRule,
@@ -137,6 +139,10 @@ impl<'a, 'o, 'b, 'i, T> TopLevelRuleParser<'a, 'o, 'i, T> {
137139
pub enum AtRulePrelude<'i, T> {
138140
/// A @font-face rule prelude.
139141
FontFace,
142+
143+
/// A @scope rule prelude.
144+
Scope,
145+
140146
/// A @font-feature-values rule prelude, with its FamilyName list.
141147
FontFeatureValues, //(Vec<FamilyName>),
142148
/// A @font-palette-values rule prelude, with its name.
@@ -423,6 +429,9 @@ impl<'a, 'o, 'b, 'i, T: crate::traits::AtRuleParser<'i>> AtRuleParser<'i> for Ne
423429
"font-face" => {
424430
Ok(AtRulePrelude::FontFace)
425431
},
432+
"scope" => {
433+
Ok(AtRulePrelude::Scope)
434+
},
426435
// "font-feature-values" => {
427436
// if !cfg!(feature = "gecko") {
428437
// // Support for this rule is not fully implemented in Servo yet.
@@ -563,6 +572,10 @@ impl<'a, 'o, 'b, 'i, T: crate::traits::AtRuleParser<'i>> AtRuleParser<'i> for Ne
563572
rules: self.parse_nested_rules(input)?,
564573
loc,
565574
})),
575+
AtRulePrelude::Scope => Ok(CssRule::Scope(ScopeRule {
576+
rules: self.parse_nested_rules(input)?,
577+
loc,
578+
})),
566579
AtRulePrelude::Viewport(vendor_prefix) => {
567580
Ok(CssRule::Viewport(ViewportRule {
568581
vendor_prefix,

src/rules/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub mod namespace;
5050
pub mod nesting;
5151
pub mod page;
5252
pub mod property;
53+
pub mod scope;
5354
pub mod style;
5455
pub mod supports;
5556
pub mod unknown;
@@ -88,6 +89,7 @@ use media::MediaRule;
8889
use namespace::NamespaceRule;
8990
use nesting::NestingRule;
9091
use page::PageRule;
92+
use scope::ScopeRule;
9193
use std::collections::{HashMap, HashSet};
9294
use style::StyleRule;
9395
use supports::SupportsRule;
@@ -163,6 +165,8 @@ pub enum CssRule<'i, R = DefaultAtRule> {
163165
Property(PropertyRule<'i>),
164166
/// A `@container` rule.
165167
Container(ContainerRule<'i, R>),
168+
/// A `@scope` rule.
169+
Scope(ScopeRule<'i, R>),
166170
/// A placeholder for a rule that was removed.
167171
Ignored,
168172
/// An unknown at-rule.
@@ -299,6 +303,10 @@ impl<'i, 'de: 'i, R: serde::Deserialize<'de>> serde::Deserialize<'de> for CssRul
299303
let rule = ContainerRule::deserialize(deserializer)?;
300304
Ok(CssRule::Container(rule))
301305
}
306+
"scope" => {
307+
let rule = ScopeRule::deserialize(deserializer)?;
308+
Ok(CssRule::Scope(rule))
309+
}
302310
"ignored" => Ok(CssRule::Ignored),
303311
"unknown" => {
304312
let rule = UnknownAtRule::deserialize(deserializer)?;
@@ -337,6 +345,7 @@ impl<'a, 'i, T: ToCss> ToCss for CssRule<'i, T> {
337345
CssRule::LayerBlock(layer) => layer.to_css(dest),
338346
CssRule::Property(property) => property.to_css(dest),
339347
CssRule::Container(container) => container.to_css(dest),
348+
CssRule::Scope(scope) => scope.to_css(dest),
340349
CssRule::Unknown(unknown) => unknown.to_css(dest),
341350
CssRule::Custom(rule) => rule.to_css(dest).map_err(|_| PrinterError {
342351
kind: PrinterErrorKind::FmtError,
@@ -641,6 +650,7 @@ impl<'i, T> CssRuleList<'i, T> {
641650
continue;
642651
}
643652
}
653+
CssRule::Scope(scope) => scope.minify(context)?,
644654
CssRule::Nesting(nesting) => {
645655
if nesting.minify(context, parent_is_unused)? {
646656
continue;

src/rules/scope.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//! The `@scope` rule.
2+
3+
use super::Location;
4+
use super::{CssRuleList, MinifyContext};
5+
use crate::error::{MinifyError, PrinterError};
6+
use crate::parser::DefaultAtRule;
7+
use crate::printer::Printer;
8+
use crate::traits::ToCss;
9+
#[cfg(feature = "visitor")]
10+
use crate::visitor::Visit;
11+
12+
/// A [@scope](https://drafts.csswg.org/css-cascade-6/#scope-atrule) rule.
13+
///
14+
/// @scope (<scope-start>) [to (<scope-end>)]? {
15+
/// <stylesheet>
16+
/// }
17+
#[derive(Debug, PartialEq, Clone)]
18+
#[cfg_attr(feature = "visitor", derive(Visit))]
19+
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20+
#[cfg_attr(feature = "jsonschema", derive(schemars::JsonSchema))]
21+
pub struct ScopeRule<'i, R = DefaultAtRule> {
22+
// TODO: support (<scope-start>) [to (<scope-end>)]?
23+
/// Nested rules within the `@scope` rule.
24+
#[cfg_attr(feature = "serde", serde(borrow))]
25+
pub rules: CssRuleList<'i, R>,
26+
/// The location of the rule in the source file.
27+
#[cfg_attr(feature = "visitor", skip_visit)]
28+
pub loc: Location,
29+
}
30+
31+
impl<'i, T> ScopeRule<'i, T> {
32+
pub(crate) fn minify(&mut self, context: &mut MinifyContext<'_, 'i>) -> Result<(), MinifyError> {
33+
self.rules.minify(context, false)
34+
}
35+
}
36+
37+
impl<'i, T: ToCss> ToCss for ScopeRule<'i, T> {
38+
fn to_css<W>(&self, dest: &mut Printer<W>) -> Result<(), PrinterError>
39+
where
40+
W: std::fmt::Write,
41+
{
42+
#[cfg(feature = "sourcemap")]
43+
dest.add_mapping(self.loc);
44+
dest.write_str("@scope")?;
45+
dest.whitespace()?;
46+
dest.write_char('{')?;
47+
dest.indent();
48+
dest.newline()?;
49+
self.rules.to_css(dest)?;
50+
dest.dedent();
51+
dest.newline()?;
52+
dest.write_char('}')
53+
}
54+
}

0 commit comments

Comments
 (0)