From 7701f3db43e3cffc010687c038e0a72be6a87233 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 30 Jul 2024 21:06:11 +0900 Subject: [PATCH 01/18] chore: init crate --- Cargo.lock | 4 ++++ crates/biome_css_semantic/Cargo.toml | 15 +++++++++++++++ crates/biome_css_semantic/src/lib.rs | 14 ++++++++++++++ knope.toml | 4 ++++ 4 files changed, 37 insertions(+) create mode 100644 crates/biome_css_semantic/Cargo.toml create mode 100644 crates/biome_css_semantic/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 40693894f25f..7802271b4f56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,6 +322,10 @@ dependencies = [ "tracing", ] +[[package]] +name = "biome_css_semantic" +version = "0.1.0" + [[package]] name = "biome_css_syntax" version = "0.5.7" diff --git a/crates/biome_css_semantic/Cargo.toml b/crates/biome_css_semantic/Cargo.toml new file mode 100644 index 000000000000..e49ef2319e04 --- /dev/null +++ b/crates/biome_css_semantic/Cargo.toml @@ -0,0 +1,15 @@ + +[package] +authors.workspace = true +categories.workspace = true +description = "" +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +license.workspace = true +name = "biome_css_semantic" +repository.workspace = true +version = "0.0.0" + +[lints] +workspace = true diff --git a/crates/biome_css_semantic/src/lib.rs b/crates/biome_css_semantic/src/lib.rs new file mode 100644 index 000000000000..7d12d9af8195 --- /dev/null +++ b/crates/biome_css_semantic/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: usize, right: usize) -> usize { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/knope.toml b/knope.toml index b95f730b33b9..17724f1afdc4 100644 --- a/knope.toml +++ b/knope.toml @@ -208,6 +208,10 @@ versioned_files = ["crates/biome_graphql_analyze/Cargo.toml"] changelog = "crates/biome_graphql_semantic/CHANGELOG.md" versioned_files = ["crates/biome_graphql_semantic/Cargo.toml"] +[packages.biome_css_semantic] +versioned_files = ["crates/biome_css_semantic/Cargo.toml"] +changelog = "crates/biome_css_semantic/CHANGELOG.md" + ## End of crates. DO NOT CHANGE! # Workflow to create a changeset From 10c03861772dad58e5b89c024b5e0d2d94e6cfa6 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 30 Jul 2024 21:42:30 +0900 Subject: [PATCH 02/18] feat: init builder and model --- Cargo.lock | 8 ++- crates/biome_css_semantic/Cargo.toml | 8 +++ crates/biome_css_semantic/src/lib.rs | 15 +----- .../src/semantic_model/builder.rs | 47 ++++++++++++++++++ .../src/semantic_model/mod.rs | 49 +++++++++++++++++++ .../src/semantic_model/model.rs | 38 ++++++++++++++ 6 files changed, 150 insertions(+), 15 deletions(-) create mode 100644 crates/biome_css_semantic/src/semantic_model/builder.rs create mode 100644 crates/biome_css_semantic/src/semantic_model/mod.rs create mode 100644 crates/biome_css_semantic/src/semantic_model/model.rs diff --git a/Cargo.lock b/Cargo.lock index 7802271b4f56..4ca443448d1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -324,7 +324,13 @@ dependencies = [ [[package]] name = "biome_css_semantic" -version = "0.1.0" +version = "0.0.0" +dependencies = [ + "biome_css_parser", + "biome_css_syntax", + "biome_rowan", + "rustc-hash", +] [[package]] name = "biome_css_syntax" diff --git a/crates/biome_css_semantic/Cargo.toml b/crates/biome_css_semantic/Cargo.toml index e49ef2319e04..3030dded2d76 100644 --- a/crates/biome_css_semantic/Cargo.toml +++ b/crates/biome_css_semantic/Cargo.toml @@ -11,5 +11,13 @@ name = "biome_css_semantic" repository.workspace = true version = "0.0.0" +[dependencies] +biome_css_syntax = { workspace = true } +biome_rowan = { workspace = true } +rustc-hash = { workspace = true } + +[dev-dependencies] +biome_css_parser = { path = "../biome_css_parser" } + [lints] workspace = true diff --git a/crates/biome_css_semantic/src/lib.rs b/crates/biome_css_semantic/src/lib.rs index 7d12d9af8195..3649507f6ca8 100644 --- a/crates/biome_css_semantic/src/lib.rs +++ b/crates/biome_css_semantic/src/lib.rs @@ -1,14 +1 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} +mod semantic_model; diff --git a/crates/biome_css_semantic/src/semantic_model/builder.rs b/crates/biome_css_semantic/src/semantic_model/builder.rs new file mode 100644 index 000000000000..1cd938a17b92 --- /dev/null +++ b/crates/biome_css_semantic/src/semantic_model/builder.rs @@ -0,0 +1,47 @@ +use biome_css_syntax::{AnyCssRule, AnyCssSelector, CssRoot, CssSyntaxKind, CssSyntaxNode}; +use biome_rowan::TextRange; +use rustc_hash::FxHashMap; + +use super::model::{SemanticModel, SemanticModelData}; + +/// Builds the [SemanticModel] consuming [SemanticEvent] and [GraphqlSyntaxNode]. +/// For a good example on how to use it see [semantic_model]. +/// +/// [SemanticModelBuilder] consumes all the [SemanticEvent] and build all the +/// data necessary to build a semantic model, that is allocated with an +/// [std::rc::Rc] and stored inside the [SemanticModel]. +pub struct SemanticModelBuilder { + root: CssRoot, + node_by_range: FxHashMap, + selectors: Vec, + rules: Vec, +} + +impl SemanticModelBuilder { + pub fn new(root: CssRoot) -> Self { + Self { + root, + node_by_range: FxHashMap::default(), + selectors: Vec::new(), + rules: Vec::new(), + } + } + + pub fn build(self) -> SemanticModel { + let data = SemanticModelData { + root: self.root, + node_by_range: self.node_by_range, + selectors: self.selectors, + rules: self.rules, + }; + SemanticModel::new(data) + } + + #[inline] + pub fn push_node(&mut self, node: &CssSyntaxNode) { + use CssSyntaxKind::*; + if matches!(node.kind(), CSS_QUALIFIED_RULE | CSS_SELECTOR_LIST) { + self.node_by_range.insert(node.text_range(), node.clone()); + } + } +} diff --git a/crates/biome_css_semantic/src/semantic_model/mod.rs b/crates/biome_css_semantic/src/semantic_model/mod.rs new file mode 100644 index 000000000000..58407184fe0b --- /dev/null +++ b/crates/biome_css_semantic/src/semantic_model/mod.rs @@ -0,0 +1,49 @@ +mod builder; +mod model; + +use biome_css_syntax::CssRoot; +use biome_rowan::AstNode; +use builder::SemanticModelBuilder; +use model::SemanticModel; + +pub fn semantic_model(root: &CssRoot) -> SemanticModel { + // let mut extractor = SemanticEventExtractor::default(); + let mut builder = SemanticModelBuilder::new(root.clone()); + + let root = root.syntax(); + for node in root.preorder() { + match node { + biome_css_syntax::WalkEvent::Enter(node) => { + builder.push_node(&node); + // extractor.enter(&node); + } + biome_css_syntax::WalkEvent::Leave(node) => { + // extractor.leave(&node) + } + } + } + + // while let Some(e) = extractor.pop() { + // builder.push_event(e); + // } + + builder.build() +} + +#[cfg(test)] +mod tests { + use biome_css_parser::parse_css; + + #[test] + fn test_semantic_model() { + use biome_css_parser::CssParserOptions; + let parse = parse_css( + r#".class .class { color: red; }"#, + CssParserOptions::default(), + ); + + let root = parse.tree(); + let model = super::semantic_model(&root); + dbg!(&model); + } +} diff --git a/crates/biome_css_semantic/src/semantic_model/model.rs b/crates/biome_css_semantic/src/semantic_model/model.rs new file mode 100644 index 000000000000..7de47f17cad9 --- /dev/null +++ b/crates/biome_css_semantic/src/semantic_model/model.rs @@ -0,0 +1,38 @@ +use std::rc::Rc; + +use biome_css_syntax::{AnyCssRule, AnyCssSelector, CssRoot, CssSyntaxNode}; +use biome_rowan::TextRange; +use rustc_hash::FxHashMap; + +#[derive(Clone, Debug)] +pub struct SemanticModel { + pub(crate) data: Rc, +} + +impl SemanticModel { + pub(crate) fn new(data: SemanticModelData) -> Self { + Self { + data: Rc::new(data), + } + } +} + +#[derive(Debug)] +pub(crate) struct SemanticModelData { + pub(crate) root: CssRoot, + // Map to each by its range + pub(crate) node_by_range: FxHashMap, + pub(crate) selectors: Vec, + pub(crate) rules: Vec, +} + +impl SemanticModelData { + pub(crate) fn new(root: CssRoot) -> Self { + Self { + root, + node_by_range: FxHashMap::default(), + selectors: Vec::new(), + rules: Vec::new(), + } + } +} From 3ad10a4768a157ead5bd7370b14309c9e42f5815 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 30 Jul 2024 21:54:42 +0900 Subject: [PATCH 03/18] chore: init event extractor --- crates/biome_css_semantic/src/events.rs | 19 +++++++++++++++++++ crates/biome_css_semantic/src/lib.rs | 1 + .../src/semantic_model/builder.rs | 5 +++++ .../src/semantic_model/mod.rs | 16 ++++++++-------- 4 files changed, 33 insertions(+), 8 deletions(-) create mode 100644 crates/biome_css_semantic/src/events.rs diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs new file mode 100644 index 000000000000..644a91a729a1 --- /dev/null +++ b/crates/biome_css_semantic/src/events.rs @@ -0,0 +1,19 @@ +use std::collections::VecDeque; + +#[derive(Debug)] +pub enum SemanticEvent {} + +#[derive(Default, Debug)] +pub struct SemanticEventExtractor { + stash: VecDeque, +} + +impl SemanticEventExtractor { + pub fn enter(&mut self, _node: &biome_css_syntax::CssSyntaxNode) {} + + pub fn leave(&mut self, _node: &biome_css_syntax::CssSyntaxNode) {} + + pub fn pop(&mut self) -> Option { + self.stash.pop_front() + } +} diff --git a/crates/biome_css_semantic/src/lib.rs b/crates/biome_css_semantic/src/lib.rs index 3649507f6ca8..fb3b2f66d198 100644 --- a/crates/biome_css_semantic/src/lib.rs +++ b/crates/biome_css_semantic/src/lib.rs @@ -1 +1,2 @@ +mod events; mod semantic_model; diff --git a/crates/biome_css_semantic/src/semantic_model/builder.rs b/crates/biome_css_semantic/src/semantic_model/builder.rs index 1cd938a17b92..7cf8ab4c9b74 100644 --- a/crates/biome_css_semantic/src/semantic_model/builder.rs +++ b/crates/biome_css_semantic/src/semantic_model/builder.rs @@ -2,6 +2,8 @@ use biome_css_syntax::{AnyCssRule, AnyCssSelector, CssRoot, CssSyntaxKind, CssSy use biome_rowan::TextRange; use rustc_hash::FxHashMap; +use crate::events::SemanticEvent; + use super::model::{SemanticModel, SemanticModelData}; /// Builds the [SemanticModel] consuming [SemanticEvent] and [GraphqlSyntaxNode]. @@ -44,4 +46,7 @@ impl SemanticModelBuilder { self.node_by_range.insert(node.text_range(), node.clone()); } } + + #[inline] + pub fn push_event(&mut self, event: SemanticEvent) {} } diff --git a/crates/biome_css_semantic/src/semantic_model/mod.rs b/crates/biome_css_semantic/src/semantic_model/mod.rs index 58407184fe0b..f52656b51162 100644 --- a/crates/biome_css_semantic/src/semantic_model/mod.rs +++ b/crates/biome_css_semantic/src/semantic_model/mod.rs @@ -6,8 +6,10 @@ use biome_rowan::AstNode; use builder::SemanticModelBuilder; use model::SemanticModel; +use crate::events::SemanticEventExtractor; + pub fn semantic_model(root: &CssRoot) -> SemanticModel { - // let mut extractor = SemanticEventExtractor::default(); + let mut extractor = SemanticEventExtractor::default(); let mut builder = SemanticModelBuilder::new(root.clone()); let root = root.syntax(); @@ -15,17 +17,15 @@ pub fn semantic_model(root: &CssRoot) -> SemanticModel { match node { biome_css_syntax::WalkEvent::Enter(node) => { builder.push_node(&node); - // extractor.enter(&node); - } - biome_css_syntax::WalkEvent::Leave(node) => { - // extractor.leave(&node) + extractor.enter(&node); } + biome_css_syntax::WalkEvent::Leave(node) => extractor.leave(&node), } } - // while let Some(e) = extractor.pop() { - // builder.push_event(e); - // } + while let Some(e) = extractor.pop() { + builder.push_event(e); + } builder.build() } From 074d0a779b5187145a7e332b4d324b6582174eac Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 30 Jul 2024 22:33:45 +0900 Subject: [PATCH 04/18] feat: collect selector list --- crates/biome_css_semantic/src/events.rs | 17 ++++++++++++-- .../src/semantic_model/builder.rs | 23 +++++++++++++++---- .../src/semantic_model/mod.rs | 2 +- .../src/semantic_model/model.rs | 4 ++-- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index 644a91a729a1..fd38ebc6b8cb 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -1,7 +1,11 @@ use std::collections::VecDeque; +use biome_rowan::TextRange; + #[derive(Debug)] -pub enum SemanticEvent {} +pub enum SemanticEvent { + SelectorDeclaration { range: TextRange }, +} #[derive(Default, Debug)] pub struct SemanticEventExtractor { @@ -9,7 +13,16 @@ pub struct SemanticEventExtractor { } impl SemanticEventExtractor { - pub fn enter(&mut self, _node: &biome_css_syntax::CssSyntaxNode) {} + pub fn enter(&mut self, node: &biome_css_syntax::CssSyntaxNode) { + match node.kind() { + biome_css_syntax::CssSyntaxKind::CSS_SELECTOR_LIST => { + self.stash.push_back(SemanticEvent::SelectorDeclaration { + range: node.text_range(), + }); + } + _ => {} + } + } pub fn leave(&mut self, _node: &biome_css_syntax::CssSyntaxNode) {} diff --git a/crates/biome_css_semantic/src/semantic_model/builder.rs b/crates/biome_css_semantic/src/semantic_model/builder.rs index 7cf8ab4c9b74..9b7a59691e69 100644 --- a/crates/biome_css_semantic/src/semantic_model/builder.rs +++ b/crates/biome_css_semantic/src/semantic_model/builder.rs @@ -1,5 +1,7 @@ -use biome_css_syntax::{AnyCssRule, AnyCssSelector, CssRoot, CssSyntaxKind, CssSyntaxNode}; -use biome_rowan::TextRange; +use biome_css_syntax::{ + AnyCssRule, AnyCssSelector, CssRoot, CssSelectorList, CssSyntaxKind, CssSyntaxNode, +}; +use biome_rowan::{AstNode, TextRange}; use rustc_hash::FxHashMap; use crate::events::SemanticEvent; @@ -15,7 +17,7 @@ use super::model::{SemanticModel, SemanticModelData}; pub struct SemanticModelBuilder { root: CssRoot, node_by_range: FxHashMap, - selectors: Vec, + selectors: Vec, rules: Vec, } @@ -42,11 +44,22 @@ impl SemanticModelBuilder { #[inline] pub fn push_node(&mut self, node: &CssSyntaxNode) { use CssSyntaxKind::*; - if matches!(node.kind(), CSS_QUALIFIED_RULE | CSS_SELECTOR_LIST) { + if matches!( + node.kind(), + CSS_QUALIFIED_RULE | CSS_SELECTOR_LIST | CSS_COMPOUND_SELECTOR + ) { self.node_by_range.insert(node.text_range(), node.clone()); } } #[inline] - pub fn push_event(&mut self, event: SemanticEvent) {} + pub fn push_event(&mut self, event: SemanticEvent) { + match event { + SemanticEvent::SelectorDeclaration { range } => { + let node = &self.node_by_range[&range]; + self.selectors + .push(CssSelectorList::cast(node.clone()).unwrap()); + } + } + } } diff --git a/crates/biome_css_semantic/src/semantic_model/mod.rs b/crates/biome_css_semantic/src/semantic_model/mod.rs index f52656b51162..08f5c2943d85 100644 --- a/crates/biome_css_semantic/src/semantic_model/mod.rs +++ b/crates/biome_css_semantic/src/semantic_model/mod.rs @@ -38,7 +38,7 @@ mod tests { fn test_semantic_model() { use biome_css_parser::CssParserOptions; let parse = parse_css( - r#".class .class { color: red; }"#, + r#".class .class { color: red; }; .foo .foo { color: green; }"#, CssParserOptions::default(), ); diff --git a/crates/biome_css_semantic/src/semantic_model/model.rs b/crates/biome_css_semantic/src/semantic_model/model.rs index 7de47f17cad9..4ceb443e0017 100644 --- a/crates/biome_css_semantic/src/semantic_model/model.rs +++ b/crates/biome_css_semantic/src/semantic_model/model.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use biome_css_syntax::{AnyCssRule, AnyCssSelector, CssRoot, CssSyntaxNode}; +use biome_css_syntax::{AnyCssRule, CssRoot, CssSelectorList, CssSyntaxNode}; use biome_rowan::TextRange; use rustc_hash::FxHashMap; @@ -22,7 +22,7 @@ pub(crate) struct SemanticModelData { pub(crate) root: CssRoot, // Map to each by its range pub(crate) node_by_range: FxHashMap, - pub(crate) selectors: Vec, + pub(crate) selectors: Vec, pub(crate) rules: Vec, } From f1fdc09ad51c422ef1f1a5411cb6ef40aa32f0b3 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 30 Jul 2024 23:07:30 +0900 Subject: [PATCH 05/18] feat: collect properties --- crates/biome_css_semantic/src/events.rs | 26 ++++++++++++++++++- .../src/semantic_model/builder.rs | 15 ++++++++++- .../src/semantic_model/mod.rs | 2 +- .../src/semantic_model/model.rs | 2 ++ 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index fd38ebc6b8cb..cd5cece778fa 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -4,7 +4,14 @@ use biome_rowan::TextRange; #[derive(Debug)] pub enum SemanticEvent { - SelectorDeclaration { range: TextRange }, + SelectorDeclaration { + range: TextRange, + }, + PropertyDeclaration { + rule_range: TextRange, + name: String, + value_range: TextRange, + }, } #[derive(Default, Debug)] @@ -20,6 +27,23 @@ impl SemanticEventExtractor { range: node.text_range(), }); } + biome_css_syntax::CssSyntaxKind::CSS_DECLARATION_OR_RULE_LIST => { + for block in node.children() { + if let Some(decl) = block.first_child() { + if let Some(property) = decl.first_child() { + if let Some(property_name) = property.first_child() { + if let Some(property_value) = property_name.next_sibling() { + self.stash.push_back(SemanticEvent::PropertyDeclaration { + rule_range: node.text_range(), + name: property_name.text().to_string(), + value_range: property_value.text_range(), + }); + } + } + } + } + } + } _ => {} } } diff --git a/crates/biome_css_semantic/src/semantic_model/builder.rs b/crates/biome_css_semantic/src/semantic_model/builder.rs index 9b7a59691e69..84487aaa9448 100644 --- a/crates/biome_css_semantic/src/semantic_model/builder.rs +++ b/crates/biome_css_semantic/src/semantic_model/builder.rs @@ -19,6 +19,7 @@ pub struct SemanticModelBuilder { node_by_range: FxHashMap, selectors: Vec, rules: Vec, + properties: FxHashMap>, } impl SemanticModelBuilder { @@ -28,6 +29,7 @@ impl SemanticModelBuilder { node_by_range: FxHashMap::default(), selectors: Vec::new(), rules: Vec::new(), + properties: FxHashMap::default(), } } @@ -37,6 +39,7 @@ impl SemanticModelBuilder { node_by_range: self.node_by_range, selectors: self.selectors, rules: self.rules, + properties: self.properties, }; SemanticModel::new(data) } @@ -46,7 +49,7 @@ impl SemanticModelBuilder { use CssSyntaxKind::*; if matches!( node.kind(), - CSS_QUALIFIED_RULE | CSS_SELECTOR_LIST | CSS_COMPOUND_SELECTOR + CSS_SELECTOR_LIST | CSS_DECLARATION | CSS_DECLARATION_OR_RULE_LIST ) { self.node_by_range.insert(node.text_range(), node.clone()); } @@ -60,6 +63,16 @@ impl SemanticModelBuilder { self.selectors .push(CssSelectorList::cast(node.clone()).unwrap()); } + SemanticEvent::PropertyDeclaration { + rule_range, + name, + value_range, + } => { + self.properties + .entry(rule_range) + .or_default() + .push((name, value_range)); + } } } } diff --git a/crates/biome_css_semantic/src/semantic_model/mod.rs b/crates/biome_css_semantic/src/semantic_model/mod.rs index 08f5c2943d85..8bd00377e1a9 100644 --- a/crates/biome_css_semantic/src/semantic_model/mod.rs +++ b/crates/biome_css_semantic/src/semantic_model/mod.rs @@ -38,7 +38,7 @@ mod tests { fn test_semantic_model() { use biome_css_parser::CssParserOptions; let parse = parse_css( - r#".class .class { color: red; }; .foo .foo { color: green; }"#, + r#".class .class { color: red; color: green; } .foo .foo { color: green; }"#, CssParserOptions::default(), ); diff --git a/crates/biome_css_semantic/src/semantic_model/model.rs b/crates/biome_css_semantic/src/semantic_model/model.rs index 4ceb443e0017..d992d720477b 100644 --- a/crates/biome_css_semantic/src/semantic_model/model.rs +++ b/crates/biome_css_semantic/src/semantic_model/model.rs @@ -24,6 +24,7 @@ pub(crate) struct SemanticModelData { pub(crate) node_by_range: FxHashMap, pub(crate) selectors: Vec, pub(crate) rules: Vec, + pub(crate) properties: FxHashMap>, } impl SemanticModelData { @@ -33,6 +34,7 @@ impl SemanticModelData { node_by_range: FxHashMap::default(), selectors: Vec::new(), rules: Vec::new(), + properties: FxHashMap::default(), } } } From 982e872fa9fc9117630a9012ade5b0162b816e8c Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 30 Jul 2024 23:30:40 +0900 Subject: [PATCH 06/18] feat: change data st of selectors --- crates/biome_css_semantic/src/events.rs | 41 ++++++++++++++++--- .../src/semantic_model/builder.rs | 14 ++++--- .../src/semantic_model/model.rs | 4 +- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index cd5cece778fa..9dc522640f4c 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -1,11 +1,13 @@ use std::collections::VecDeque; -use biome_rowan::TextRange; +use biome_css_syntax::AnyCssSelector; +use biome_rowan::{AstNode, TextRange}; #[derive(Debug)] pub enum SemanticEvent { SelectorDeclaration { - range: TextRange, + selector_range: TextRange, + name: String, }, PropertyDeclaration { rule_range: TextRange, @@ -23,9 +25,38 @@ impl SemanticEventExtractor { pub fn enter(&mut self, node: &biome_css_syntax::CssSyntaxNode) { match node.kind() { biome_css_syntax::CssSyntaxKind::CSS_SELECTOR_LIST => { - self.stash.push_back(SemanticEvent::SelectorDeclaration { - range: node.text_range(), - }); + for selector in node.children() { + if let Some(s) = AnyCssSelector::cast(selector) { + match s { + AnyCssSelector::CssComplexSelector(s) => { + if let Ok(l) = s.left() { + self.stash.push_back(SemanticEvent::SelectorDeclaration { + selector_range: node.text_range(), + name: l.text().to_string(), + }); + } + + if let Ok(r) = s.right() { + self.stash.push_back(SemanticEvent::SelectorDeclaration { + selector_range: node.text_range(), + name: r.text().to_string(), + }); + } + } + AnyCssSelector::CssCompoundSelector(selector) => { + self.stash.push_back(SemanticEvent::SelectorDeclaration { + selector_range: node.text_range(), + name: selector.text().to_string(), + }); + } + AnyCssSelector::CssBogusSelector(_) + | AnyCssSelector::CssGritMetavariable(_) => {} + } + } + } + // self.stash.push_back(SemanticEvent::SelectorDeclaration { + // range: node.text_range(), + // }); } biome_css_syntax::CssSyntaxKind::CSS_DECLARATION_OR_RULE_LIST => { for block in node.children() { diff --git a/crates/biome_css_semantic/src/semantic_model/builder.rs b/crates/biome_css_semantic/src/semantic_model/builder.rs index 84487aaa9448..615fd15a8380 100644 --- a/crates/biome_css_semantic/src/semantic_model/builder.rs +++ b/crates/biome_css_semantic/src/semantic_model/builder.rs @@ -17,7 +17,7 @@ use super::model::{SemanticModel, SemanticModelData}; pub struct SemanticModelBuilder { root: CssRoot, node_by_range: FxHashMap, - selectors: Vec, + selectors: FxHashMap>, rules: Vec, properties: FxHashMap>, } @@ -27,7 +27,7 @@ impl SemanticModelBuilder { Self { root, node_by_range: FxHashMap::default(), - selectors: Vec::new(), + selectors: FxHashMap::default(), rules: Vec::new(), properties: FxHashMap::default(), } @@ -58,10 +58,14 @@ impl SemanticModelBuilder { #[inline] pub fn push_event(&mut self, event: SemanticEvent) { match event { - SemanticEvent::SelectorDeclaration { range } => { - let node = &self.node_by_range[&range]; + SemanticEvent::SelectorDeclaration { + selector_range, + name, + } => { self.selectors - .push(CssSelectorList::cast(node.clone()).unwrap()); + .entry(selector_range) + .or_default() + .push((name, selector_range)); } SemanticEvent::PropertyDeclaration { rule_range, diff --git a/crates/biome_css_semantic/src/semantic_model/model.rs b/crates/biome_css_semantic/src/semantic_model/model.rs index d992d720477b..b8749cc2a31c 100644 --- a/crates/biome_css_semantic/src/semantic_model/model.rs +++ b/crates/biome_css_semantic/src/semantic_model/model.rs @@ -22,7 +22,7 @@ pub(crate) struct SemanticModelData { pub(crate) root: CssRoot, // Map to each by its range pub(crate) node_by_range: FxHashMap, - pub(crate) selectors: Vec, + pub(crate) selectors: FxHashMap>, pub(crate) rules: Vec, pub(crate) properties: FxHashMap>, } @@ -32,7 +32,7 @@ impl SemanticModelData { Self { root, node_by_range: FxHashMap::default(), - selectors: Vec::new(), + selectors: FxHashMap::default(), rules: Vec::new(), properties: FxHashMap::default(), } From d80eef33621bec2a679ef32072c4359a9f0a253e Mon Sep 17 00:00:00 2001 From: togami2864 Date: Tue, 30 Jul 2024 23:35:07 +0900 Subject: [PATCH 07/18] chore: remove dead codes --- crates/biome_css_semantic/src/events.rs | 3 --- crates/biome_css_semantic/src/semantic_model/builder.rs | 9 ++------- crates/biome_css_semantic/src/semantic_model/mod.rs | 2 ++ crates/biome_css_semantic/src/semantic_model/model.rs | 4 +--- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index 9dc522640f4c..df1568bb5527 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -54,9 +54,6 @@ impl SemanticEventExtractor { } } } - // self.stash.push_back(SemanticEvent::SelectorDeclaration { - // range: node.text_range(), - // }); } biome_css_syntax::CssSyntaxKind::CSS_DECLARATION_OR_RULE_LIST => { for block in node.children() { diff --git a/crates/biome_css_semantic/src/semantic_model/builder.rs b/crates/biome_css_semantic/src/semantic_model/builder.rs index 615fd15a8380..fd3afa4f1192 100644 --- a/crates/biome_css_semantic/src/semantic_model/builder.rs +++ b/crates/biome_css_semantic/src/semantic_model/builder.rs @@ -1,7 +1,5 @@ -use biome_css_syntax::{ - AnyCssRule, AnyCssSelector, CssRoot, CssSelectorList, CssSyntaxKind, CssSyntaxNode, -}; -use biome_rowan::{AstNode, TextRange}; +use biome_css_syntax::{CssRoot, CssSyntaxKind, CssSyntaxNode}; +use biome_rowan::TextRange; use rustc_hash::FxHashMap; use crate::events::SemanticEvent; @@ -18,7 +16,6 @@ pub struct SemanticModelBuilder { root: CssRoot, node_by_range: FxHashMap, selectors: FxHashMap>, - rules: Vec, properties: FxHashMap>, } @@ -28,7 +25,6 @@ impl SemanticModelBuilder { root, node_by_range: FxHashMap::default(), selectors: FxHashMap::default(), - rules: Vec::new(), properties: FxHashMap::default(), } } @@ -38,7 +34,6 @@ impl SemanticModelBuilder { root: self.root, node_by_range: self.node_by_range, selectors: self.selectors, - rules: self.rules, properties: self.properties, }; SemanticModel::new(data) diff --git a/crates/biome_css_semantic/src/semantic_model/mod.rs b/crates/biome_css_semantic/src/semantic_model/mod.rs index 8bd00377e1a9..615c9b2fe3bd 100644 --- a/crates/biome_css_semantic/src/semantic_model/mod.rs +++ b/crates/biome_css_semantic/src/semantic_model/mod.rs @@ -45,5 +45,7 @@ mod tests { let root = parse.tree(); let model = super::semantic_model(&root); dbg!(&model); + dbg!(&model.data.selectors); + dbg!(&model.data.properties); } } diff --git a/crates/biome_css_semantic/src/semantic_model/model.rs b/crates/biome_css_semantic/src/semantic_model/model.rs index b8749cc2a31c..2629438dfa2e 100644 --- a/crates/biome_css_semantic/src/semantic_model/model.rs +++ b/crates/biome_css_semantic/src/semantic_model/model.rs @@ -1,6 +1,6 @@ use std::rc::Rc; -use biome_css_syntax::{AnyCssRule, CssRoot, CssSelectorList, CssSyntaxNode}; +use biome_css_syntax::{CssRoot, CssSyntaxNode}; use biome_rowan::TextRange; use rustc_hash::FxHashMap; @@ -23,7 +23,6 @@ pub(crate) struct SemanticModelData { // Map to each by its range pub(crate) node_by_range: FxHashMap, pub(crate) selectors: FxHashMap>, - pub(crate) rules: Vec, pub(crate) properties: FxHashMap>, } @@ -33,7 +32,6 @@ impl SemanticModelData { root, node_by_range: FxHashMap::default(), selectors: FxHashMap::default(), - rules: Vec::new(), properties: FxHashMap::default(), } } From 13ddddcb53ae81a79a349683c69a29663c2064b8 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Wed, 31 Jul 2024 22:09:38 +0900 Subject: [PATCH 08/18] fix: use selector range --- crates/biome_css_semantic/src/events.rs | 12 ++++++++---- .../biome_css_semantic/src/semantic_model/builder.rs | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index df1568bb5527..f6263577287c 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -6,8 +6,9 @@ use biome_rowan::{AstNode, TextRange}; #[derive(Debug)] pub enum SemanticEvent { SelectorDeclaration { - selector_range: TextRange, + range: TextRange, name: String, + selector_range: TextRange, }, PropertyDeclaration { rule_range: TextRange, @@ -31,22 +32,25 @@ impl SemanticEventExtractor { AnyCssSelector::CssComplexSelector(s) => { if let Ok(l) = s.left() { self.stash.push_back(SemanticEvent::SelectorDeclaration { - selector_range: node.text_range(), + range: node.text_range(), + selector_range: l.range(), name: l.text().to_string(), }); } if let Ok(r) = s.right() { self.stash.push_back(SemanticEvent::SelectorDeclaration { - selector_range: node.text_range(), + range: node.text_range(), + selector_range: r.range(), name: r.text().to_string(), }); } } AnyCssSelector::CssCompoundSelector(selector) => { self.stash.push_back(SemanticEvent::SelectorDeclaration { - selector_range: node.text_range(), + range: node.text_range(), name: selector.text().to_string(), + selector_range: selector.range(), }); } AnyCssSelector::CssBogusSelector(_) diff --git a/crates/biome_css_semantic/src/semantic_model/builder.rs b/crates/biome_css_semantic/src/semantic_model/builder.rs index fd3afa4f1192..10388b59dcad 100644 --- a/crates/biome_css_semantic/src/semantic_model/builder.rs +++ b/crates/biome_css_semantic/src/semantic_model/builder.rs @@ -54,11 +54,12 @@ impl SemanticModelBuilder { pub fn push_event(&mut self, event: SemanticEvent) { match event { SemanticEvent::SelectorDeclaration { - selector_range, + range, name, + selector_range, } => { self.selectors - .entry(selector_range) + .entry(range) .or_default() .push((name, selector_range)); } From 7030fccc1c59a88b722f7d90410b71a4d4ee2c6a Mon Sep 17 00:00:00 2001 From: togami2864 Date: Wed, 31 Jul 2024 22:30:29 +0900 Subject: [PATCH 09/18] chore: rename --- crates/biome_css_semantic/src/events.rs | 17 ++++++++----- .../src/semantic_model/builder.rs | 25 ++++++++++++------- .../src/semantic_model/mod.rs | 2 +- .../src/semantic_model/model.rs | 12 +++++++-- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index f6263577287c..c4faf1f20ffd 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -11,8 +11,10 @@ pub enum SemanticEvent { selector_range: TextRange, }, PropertyDeclaration { - rule_range: TextRange, - name: String, + ruleset_range: TextRange, + property: String, + property_range: TextRange, + value: String, value_range: TextRange, }, } @@ -61,14 +63,17 @@ impl SemanticEventExtractor { } biome_css_syntax::CssSyntaxKind::CSS_DECLARATION_OR_RULE_LIST => { for block in node.children() { + let ruleset_range = node.parent().unwrap().text_range(); if let Some(decl) = block.first_child() { if let Some(property) = decl.first_child() { if let Some(property_name) = property.first_child() { - if let Some(property_value) = property_name.next_sibling() { + if let Some(value) = property_name.next_sibling() { self.stash.push_back(SemanticEvent::PropertyDeclaration { - rule_range: node.text_range(), - name: property_name.text().to_string(), - value_range: property_value.text_range(), + ruleset_range, + property: property_name.text().to_string(), + property_range: property_name.text_range(), + value: value.text().to_string(), + value_range: value.text_range(), }); } } diff --git a/crates/biome_css_semantic/src/semantic_model/builder.rs b/crates/biome_css_semantic/src/semantic_model/builder.rs index 10388b59dcad..78e77d8cc877 100644 --- a/crates/biome_css_semantic/src/semantic_model/builder.rs +++ b/crates/biome_css_semantic/src/semantic_model/builder.rs @@ -4,7 +4,7 @@ use rustc_hash::FxHashMap; use crate::events::SemanticEvent; -use super::model::{SemanticModel, SemanticModelData}; +use super::model::{Declaration, SemanticModel, SemanticModelData}; /// Builds the [SemanticModel] consuming [SemanticEvent] and [GraphqlSyntaxNode]. /// For a good example on how to use it see [semantic_model]. @@ -16,7 +16,7 @@ pub struct SemanticModelBuilder { root: CssRoot, node_by_range: FxHashMap, selectors: FxHashMap>, - properties: FxHashMap>, + declarations: FxHashMap>, } impl SemanticModelBuilder { @@ -25,7 +25,7 @@ impl SemanticModelBuilder { root, node_by_range: FxHashMap::default(), selectors: FxHashMap::default(), - properties: FxHashMap::default(), + declarations: FxHashMap::default(), } } @@ -34,7 +34,7 @@ impl SemanticModelBuilder { root: self.root, node_by_range: self.node_by_range, selectors: self.selectors, - properties: self.properties, + declarations: self.declarations, }; SemanticModel::new(data) } @@ -64,14 +64,21 @@ impl SemanticModelBuilder { .push((name, selector_range)); } SemanticEvent::PropertyDeclaration { - rule_range, - name, + ruleset_range, + property, + property_range, + value, value_range, } => { - self.properties - .entry(rule_range) + self.declarations + .entry(ruleset_range) .or_default() - .push((name, value_range)); + .push(Declaration { + property, + value, + property_range, + value_range, + }); } } } diff --git a/crates/biome_css_semantic/src/semantic_model/mod.rs b/crates/biome_css_semantic/src/semantic_model/mod.rs index 615c9b2fe3bd..91e4b1f90c46 100644 --- a/crates/biome_css_semantic/src/semantic_model/mod.rs +++ b/crates/biome_css_semantic/src/semantic_model/mod.rs @@ -46,6 +46,6 @@ mod tests { let model = super::semantic_model(&root); dbg!(&model); dbg!(&model.data.selectors); - dbg!(&model.data.properties); + dbg!(&model.data.declarations); } } diff --git a/crates/biome_css_semantic/src/semantic_model/model.rs b/crates/biome_css_semantic/src/semantic_model/model.rs index 2629438dfa2e..404b301b0059 100644 --- a/crates/biome_css_semantic/src/semantic_model/model.rs +++ b/crates/biome_css_semantic/src/semantic_model/model.rs @@ -23,7 +23,15 @@ pub(crate) struct SemanticModelData { // Map to each by its range pub(crate) node_by_range: FxHashMap, pub(crate) selectors: FxHashMap>, - pub(crate) properties: FxHashMap>, + pub(crate) declarations: FxHashMap>, +} + +#[derive(Debug)] +pub struct Declaration { + pub property: String, + pub value: String, + pub property_range: TextRange, + pub value_range: TextRange, } impl SemanticModelData { @@ -32,7 +40,7 @@ impl SemanticModelData { root, node_by_range: FxHashMap::default(), selectors: FxHashMap::default(), - properties: FxHashMap::default(), + declarations: FxHashMap::default(), } } } From 681f05e69868088b78df77aeea8777c8586d4846 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Wed, 31 Jul 2024 22:50:05 +0900 Subject: [PATCH 10/18] fix: index of declations --- crates/biome_css_semantic/src/events.rs | 40 ++++++++++++++++--------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index c4faf1f20ffd..3dad475b5ee1 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -1,6 +1,6 @@ use std::collections::VecDeque; -use biome_css_syntax::AnyCssSelector; +use biome_css_syntax::{AnyCssSelector, CssQualifiedRule}; use biome_rowan::{AstNode, TextRange}; #[derive(Debug)] @@ -22,11 +22,18 @@ pub enum SemanticEvent { #[derive(Default, Debug)] pub struct SemanticEventExtractor { stash: VecDeque, + current_selector_range: Option, } impl SemanticEventExtractor { pub fn enter(&mut self, node: &biome_css_syntax::CssSyntaxNode) { match node.kind() { + biome_css_syntax::CssSyntaxKind::CSS_QUALIFIED_RULE => { + if let Some(qualified_rule) = CssQualifiedRule::cast(node.clone()) { + self.current_selector_range = + Some(qualified_rule.prelude().syntax().text_range()); + } + } biome_css_syntax::CssSyntaxKind::CSS_SELECTOR_LIST => { for selector in node.children() { if let Some(s) = AnyCssSelector::cast(selector) { @@ -63,18 +70,19 @@ impl SemanticEventExtractor { } biome_css_syntax::CssSyntaxKind::CSS_DECLARATION_OR_RULE_LIST => { for block in node.children() { - let ruleset_range = node.parent().unwrap().text_range(); - if let Some(decl) = block.first_child() { - if let Some(property) = decl.first_child() { - if let Some(property_name) = property.first_child() { - if let Some(value) = property_name.next_sibling() { - self.stash.push_back(SemanticEvent::PropertyDeclaration { - ruleset_range, - property: property_name.text().to_string(), - property_range: property_name.text_range(), - value: value.text().to_string(), - value_range: value.text_range(), - }); + if let Some(ruleset_range) = self.current_selector_range { + if let Some(decl) = block.first_child() { + if let Some(property) = decl.first_child() { + if let Some(property_name) = property.first_child() { + if let Some(value) = property_name.next_sibling() { + self.stash.push_back(SemanticEvent::PropertyDeclaration { + ruleset_range, + property: property_name.text().to_string(), + property_range: property_name.text_range(), + value: value.text().to_string(), + value_range: value.text_range(), + }); + } } } } @@ -85,7 +93,11 @@ impl SemanticEventExtractor { } } - pub fn leave(&mut self, _node: &biome_css_syntax::CssSyntaxNode) {} + pub fn leave(&mut self, node: &biome_css_syntax::CssSyntaxNode) { + if node.kind() == biome_css_syntax::CssSyntaxKind::CSS_QUALIFIED_RULE { + self.current_selector_range = None; + } + } pub fn pop(&mut self) -> Option { self.stash.pop_front() From 393a76cf91e688e35d533e5d02e7f865d190072f Mon Sep 17 00:00:00 2001 From: togami2864 Date: Wed, 31 Jul 2024 23:11:40 +0900 Subject: [PATCH 11/18] chore: tests --- crates/biome_css_semantic/src/events.rs | 6 +-- crates/biome_css_semantic/src/lib.rs | 3 ++ .../src/semantic_model/builder.rs | 4 +- .../src/semantic_model/mod.rs | 46 +++++++++++++++++-- .../src/semantic_model/model.rs | 27 ++++++----- 5 files changed, 65 insertions(+), 21 deletions(-) diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index 3dad475b5ee1..6cfa5f6d7846 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -11,7 +11,7 @@ pub enum SemanticEvent { selector_range: TextRange, }, PropertyDeclaration { - ruleset_range: TextRange, + selector_range: TextRange, property: String, property_range: TextRange, value: String, @@ -70,13 +70,13 @@ impl SemanticEventExtractor { } biome_css_syntax::CssSyntaxKind::CSS_DECLARATION_OR_RULE_LIST => { for block in node.children() { - if let Some(ruleset_range) = self.current_selector_range { + if let Some(selector_range) = self.current_selector_range { if let Some(decl) = block.first_child() { if let Some(property) = decl.first_child() { if let Some(property_name) = property.first_child() { if let Some(value) = property_name.next_sibling() { self.stash.push_back(SemanticEvent::PropertyDeclaration { - ruleset_range, + selector_range, property: property_name.text().to_string(), property_range: property_name.text_range(), value: value.text().to_string(), diff --git a/crates/biome_css_semantic/src/lib.rs b/crates/biome_css_semantic/src/lib.rs index fb3b2f66d198..0734f9922a92 100644 --- a/crates/biome_css_semantic/src/lib.rs +++ b/crates/biome_css_semantic/src/lib.rs @@ -1,2 +1,5 @@ mod events; mod semantic_model; + +pub use events::*; +pub use semantic_model::*; diff --git a/crates/biome_css_semantic/src/semantic_model/builder.rs b/crates/biome_css_semantic/src/semantic_model/builder.rs index 78e77d8cc877..890910200ac4 100644 --- a/crates/biome_css_semantic/src/semantic_model/builder.rs +++ b/crates/biome_css_semantic/src/semantic_model/builder.rs @@ -64,14 +64,14 @@ impl SemanticModelBuilder { .push((name, selector_range)); } SemanticEvent::PropertyDeclaration { - ruleset_range, + selector_range, property, property_range, value, value_range, } => { self.declarations - .entry(ruleset_range) + .entry(selector_range) .or_default() .push(Declaration { property, diff --git a/crates/biome_css_semantic/src/semantic_model/mod.rs b/crates/biome_css_semantic/src/semantic_model/mod.rs index 91e4b1f90c46..57a989338351 100644 --- a/crates/biome_css_semantic/src/semantic_model/mod.rs +++ b/crates/biome_css_semantic/src/semantic_model/mod.rs @@ -33,19 +33,55 @@ pub fn semantic_model(root: &CssRoot) -> SemanticModel { #[cfg(test)] mod tests { use biome_css_parser::parse_css; + use biome_css_parser::CssParserOptions; + use biome_rowan::TextRange; + + #[test] + fn test_simple_ruleset() { + let parse = parse_css(r#".class { color: red; }"#, CssParserOptions::default()); + + let root = parse.tree(); + let model = super::semantic_model(&root); + + let selector_range = TextRange::new(0.into(), 7.into()); + assert_eq!(model.selectors(selector_range).unwrap().len(), 1); + assert_eq!(model.selectors(selector_range).unwrap()[0].0, ".class"); + + assert_eq!(model.declarations(selector_range).unwrap().len(), 1); + let declaration = &model.declarations(selector_range).unwrap()[0]; + assert_eq!(declaration.property, "color"); + assert_eq!(declaration.value, "red"); + } #[test] fn test_semantic_model() { - use biome_css_parser::CssParserOptions; let parse = parse_css( - r#".class .class { color: red; color: green; } .foo .foo { color: green; }"#, + r#".foo .bar { color: red; text-align: center; }"#, CssParserOptions::default(), ); let root = parse.tree(); let model = super::semantic_model(&root); - dbg!(&model); - dbg!(&model.data.selectors); - dbg!(&model.data.declarations); + + let selector_range = TextRange::new(0.into(), 10.into()); + + assert_eq!(model.selectors(selector_range).unwrap().len(), 2); + assert_eq!(model.selectors(selector_range).unwrap()[0].0, ".foo"); + assert_eq!(model.selectors(selector_range).unwrap()[1].0, ".bar"); + + assert_eq!(model.declarations(selector_range).unwrap().len(), 2); + assert_eq!( + model.declarations(selector_range).unwrap()[0].property, + "color" + ); + assert_eq!(model.declarations(selector_range).unwrap()[0].value, "red"); + assert_eq!( + model.declarations(selector_range).unwrap()[1].property, + "text-align" + ); + assert_eq!( + model.declarations(selector_range).unwrap()[1].value, + "center" + ); } } diff --git a/crates/biome_css_semantic/src/semantic_model/model.rs b/crates/biome_css_semantic/src/semantic_model/model.rs index 404b301b0059..68ede5bc0269 100644 --- a/crates/biome_css_semantic/src/semantic_model/model.rs +++ b/crates/biome_css_semantic/src/semantic_model/model.rs @@ -15,6 +15,22 @@ impl SemanticModel { data: Rc::new(data), } } + + pub fn root(&self) -> &CssRoot { + &self.data.root + } + + pub fn node_by_range(&self, range: TextRange) -> Option<&CssSyntaxNode> { + self.data.node_by_range.get(&range) + } + + pub fn selectors(&self, range: TextRange) -> Option<&Vec<(String, TextRange)>> { + self.data.selectors.get(&range) + } + + pub fn declarations(&self, range: TextRange) -> Option<&Vec> { + self.data.declarations.get(&range) + } } #[derive(Debug)] @@ -33,14 +49,3 @@ pub struct Declaration { pub property_range: TextRange, pub value_range: TextRange, } - -impl SemanticModelData { - pub(crate) fn new(root: CssRoot) -> Self { - Self { - root, - node_by_range: FxHashMap::default(), - selectors: FxHashMap::default(), - declarations: FxHashMap::default(), - } - } -} From 60762e357d13e1db228741761b7ac7571759ffbc Mon Sep 17 00:00:00 2001 From: togami2864 Date: Wed, 31 Jul 2024 23:39:01 +0900 Subject: [PATCH 12/18] chore: fmt --- crates/biome_css_semantic/Cargo.toml | 6 +++--- knope.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/biome_css_semantic/Cargo.toml b/crates/biome_css_semantic/Cargo.toml index 3030dded2d76..bdddb535a8e1 100644 --- a/crates/biome_css_semantic/Cargo.toml +++ b/crates/biome_css_semantic/Cargo.toml @@ -12,9 +12,9 @@ repository.workspace = true version = "0.0.0" [dependencies] -biome_css_syntax = { workspace = true } -biome_rowan = { workspace = true } -rustc-hash = { workspace = true } +biome_css_syntax = { workspace = true } +biome_rowan = { workspace = true } +rustc-hash = { workspace = true } [dev-dependencies] biome_css_parser = { path = "../biome_css_parser" } diff --git a/knope.toml b/knope.toml index 17724f1afdc4..641743ff4b08 100644 --- a/knope.toml +++ b/knope.toml @@ -209,8 +209,8 @@ changelog = "crates/biome_graphql_semantic/CHANGELOG.md" versioned_files = ["crates/biome_graphql_semantic/Cargo.toml"] [packages.biome_css_semantic] +changelog = "crates/biome_css_semantic/CHANGELOG.md" versioned_files = ["crates/biome_css_semantic/Cargo.toml"] -changelog = "crates/biome_css_semantic/CHANGELOG.md" ## End of crates. DO NOT CHANGE! From 8de21a440680e7eb2b1756be085801b8c37e3324 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Sat, 3 Aug 2024 15:51:52 +0900 Subject: [PATCH 13/18] feat: restructure model data --- crates/biome_css_semantic/src/events.rs | 126 +++++++++--------- .../src/semantic_model/builder.rs | 65 +++++---- .../src/semantic_model/mod.rs | 44 +----- .../src/semantic_model/model.rs | 29 ++-- 4 files changed, 126 insertions(+), 138 deletions(-) diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index 6cfa5f6d7846..1bcc514101ac 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -1,20 +1,23 @@ use std::collections::VecDeque; -use biome_css_syntax::{AnyCssSelector, CssQualifiedRule}; +use biome_css_syntax::{AnyCssSelector, CssRelativeSelector, CssSyntaxKind::*}; use biome_rowan::{AstNode, TextRange}; +use crate::semantic_model::model::Specificity; + #[derive(Debug)] pub enum SemanticEvent { + RuleStart(TextRange), + RuleEnd, SelectorDeclaration { - range: TextRange, name: String, - selector_range: TextRange, + range: TextRange, + specificity: Specificity, }, PropertyDeclaration { - selector_range: TextRange, property: String, - property_range: TextRange, value: String, + property_range: TextRange, value_range: TextRange, }, } @@ -22,80 +25,79 @@ pub enum SemanticEvent { #[derive(Default, Debug)] pub struct SemanticEventExtractor { stash: VecDeque, - current_selector_range: Option, + current_rule_stack: Vec, } impl SemanticEventExtractor { pub fn enter(&mut self, node: &biome_css_syntax::CssSyntaxNode) { match node.kind() { - biome_css_syntax::CssSyntaxKind::CSS_QUALIFIED_RULE => { - if let Some(qualified_rule) = CssQualifiedRule::cast(node.clone()) { - self.current_selector_range = - Some(qualified_rule.prelude().syntax().text_range()); - } + kind if kind == CSS_QUALIFIED_RULE || kind == CSS_NESTED_QUALIFIED_RULE => { + let range = node.text_range(); + self.stash.push_back(SemanticEvent::RuleStart(range)); + self.current_rule_stack.push(range); } - biome_css_syntax::CssSyntaxKind::CSS_SELECTOR_LIST => { - for selector in node.children() { - if let Some(s) = AnyCssSelector::cast(selector) { - match s { - AnyCssSelector::CssComplexSelector(s) => { - if let Ok(l) = s.left() { - self.stash.push_back(SemanticEvent::SelectorDeclaration { - range: node.text_range(), - selector_range: l.range(), - name: l.text().to_string(), - }); - } - - if let Ok(r) = s.right() { - self.stash.push_back(SemanticEvent::SelectorDeclaration { - range: node.text_range(), - selector_range: r.range(), - name: r.text().to_string(), - }); - } - } - AnyCssSelector::CssCompoundSelector(selector) => { - self.stash.push_back(SemanticEvent::SelectorDeclaration { - range: node.text_range(), - name: selector.text().to_string(), - selector_range: selector.range(), - }); - } - AnyCssSelector::CssBogusSelector(_) - | AnyCssSelector::CssGritMetavariable(_) => {} + CSS_SELECTOR_LIST => { + node.children() + .filter_map(AnyCssSelector::cast) + .for_each(|s| self.process_selector(s)); + } + CSS_RELATIVE_SELECTOR_LIST => { + node.children() + .filter_map(CssRelativeSelector::cast) + .filter_map(|s| s.selector().ok()) + .for_each(|s| self.process_selector(s)); + } + CSS_DECLARATION => { + if let Some(property) = node.first_child() { + if let Some(property_name) = property.first_child() { + if let Some(value) = property_name.next_sibling() { + self.stash.push_back(SemanticEvent::PropertyDeclaration { + property: property_name.text().to_string(), + value: value.text().to_string(), + property_range: property_name.text_range(), + value_range: value.text_range(), + }); } } } } - biome_css_syntax::CssSyntaxKind::CSS_DECLARATION_OR_RULE_LIST => { - for block in node.children() { - if let Some(selector_range) = self.current_selector_range { - if let Some(decl) = block.first_child() { - if let Some(property) = decl.first_child() { - if let Some(property_name) = property.first_child() { - if let Some(value) = property_name.next_sibling() { - self.stash.push_back(SemanticEvent::PropertyDeclaration { - selector_range, - property: property_name.text().to_string(), - property_range: property_name.text_range(), - value: value.text().to_string(), - value_range: value.text_range(), - }); - } - } - } - } - } + _ => {} + } + } + + fn process_selector(&mut self, selector: AnyCssSelector) { + match selector { + AnyCssSelector::CssComplexSelector(s) => { + if let Ok(l) = s.left() { + self.add_selector_event(l.text().to_string(), l.range()); } + if let Ok(r) = s.right() { + self.add_selector_event(r.text().to_string(), r.range()); + } + } + AnyCssSelector::CssCompoundSelector(selector) => { + self.add_selector_event(selector.text().to_string(), selector.range()); } _ => {} } } + fn add_selector_event(&mut self, name: String, range: TextRange) { + self.stash.push_back(SemanticEvent::SelectorDeclaration { + name, + range, + specificity: Specificity(0, 0, 0), // TODO: Implement calculate_specificity + }); + } + pub fn leave(&mut self, node: &biome_css_syntax::CssSyntaxNode) { - if node.kind() == biome_css_syntax::CssSyntaxKind::CSS_QUALIFIED_RULE { - self.current_selector_range = None; + if matches!( + node.kind(), + biome_css_syntax::CssSyntaxKind::CSS_QUALIFIED_RULE + | biome_css_syntax::CssSyntaxKind::CSS_NESTED_QUALIFIED_RULE + ) { + self.current_rule_stack.pop(); + self.stash.push_back(SemanticEvent::RuleEnd); } } diff --git a/crates/biome_css_semantic/src/semantic_model/builder.rs b/crates/biome_css_semantic/src/semantic_model/builder.rs index 890910200ac4..296afe99923e 100644 --- a/crates/biome_css_semantic/src/semantic_model/builder.rs +++ b/crates/biome_css_semantic/src/semantic_model/builder.rs @@ -2,21 +2,14 @@ use biome_css_syntax::{CssRoot, CssSyntaxKind, CssSyntaxNode}; use biome_rowan::TextRange; use rustc_hash::FxHashMap; +use super::model::{Declaration, Rule, Selector, SemanticModel, SemanticModelData}; use crate::events::SemanticEvent; -use super::model::{Declaration, SemanticModel, SemanticModelData}; - -/// Builds the [SemanticModel] consuming [SemanticEvent] and [GraphqlSyntaxNode]. -/// For a good example on how to use it see [semantic_model]. -/// -/// [SemanticModelBuilder] consumes all the [SemanticEvent] and build all the -/// data necessary to build a semantic model, that is allocated with an -/// [std::rc::Rc] and stored inside the [SemanticModel]. pub struct SemanticModelBuilder { root: CssRoot, node_by_range: FxHashMap, - selectors: FxHashMap>, - declarations: FxHashMap>, + rules: Vec, + current_rule_stack: Vec, } impl SemanticModelBuilder { @@ -24,8 +17,8 @@ impl SemanticModelBuilder { Self { root, node_by_range: FxHashMap::default(), - selectors: FxHashMap::default(), - declarations: FxHashMap::default(), + rules: Vec::new(), + current_rule_stack: Vec::new(), } } @@ -33,8 +26,7 @@ impl SemanticModelBuilder { let data = SemanticModelData { root: self.root, node_by_range: self.node_by_range, - selectors: self.selectors, - declarations: self.declarations, + rules: self.rules, }; SemanticModel::new(data) } @@ -44,7 +36,7 @@ impl SemanticModelBuilder { use CssSyntaxKind::*; if matches!( node.kind(), - CSS_SELECTOR_LIST | CSS_DECLARATION | CSS_DECLARATION_OR_RULE_LIST + CSS_SELECTOR_LIST | CSS_DECLARATION | CSS_DECLARATION_OR_RULE_LIST | CSS_QUALIFIED_RULE ) { self.node_by_range.insert(node.text_range(), node.clone()); } @@ -53,32 +45,51 @@ impl SemanticModelBuilder { #[inline] pub fn push_event(&mut self, event: SemanticEvent) { match event { + SemanticEvent::RuleStart(range) => { + let new_rule = Rule { + selectors: Vec::new(), + declarations: Vec::new(), + children: Vec::new(), + range, + }; + self.current_rule_stack.push(new_rule); + } + SemanticEvent::RuleEnd => { + if let Some(completed_rule) = self.current_rule_stack.pop() { + if let Some(parent_rule) = self.current_rule_stack.last_mut() { + parent_rule.children.push(completed_rule); + } else { + self.rules.push(completed_rule); + } + } + } SemanticEvent::SelectorDeclaration { - range, name, - selector_range, + range, + specificity, } => { - self.selectors - .entry(range) - .or_default() - .push((name, selector_range)); + if let Some(current_rule) = self.current_rule_stack.last_mut() { + current_rule.selectors.push(Selector { + name, + range, + specificity, + }); + } } SemanticEvent::PropertyDeclaration { - selector_range, property, - property_range, value, + property_range, value_range, } => { - self.declarations - .entry(selector_range) - .or_default() - .push(Declaration { + if let Some(current_rule) = self.current_rule_stack.last_mut() { + current_rule.declarations.push(Declaration { property, value, property_range, value_range, }); + } } } } diff --git a/crates/biome_css_semantic/src/semantic_model/mod.rs b/crates/biome_css_semantic/src/semantic_model/mod.rs index 57a989338351..989b808ffbbc 100644 --- a/crates/biome_css_semantic/src/semantic_model/mod.rs +++ b/crates/biome_css_semantic/src/semantic_model/mod.rs @@ -1,5 +1,5 @@ mod builder; -mod model; +pub(crate) mod model; use biome_css_syntax::CssRoot; use biome_rowan::AstNode; @@ -34,54 +34,16 @@ pub fn semantic_model(root: &CssRoot) -> SemanticModel { mod tests { use biome_css_parser::parse_css; use biome_css_parser::CssParserOptions; - use biome_rowan::TextRange; #[test] fn test_simple_ruleset() { - let parse = parse_css(r#".class { color: red; }"#, CssParserOptions::default()); - - let root = parse.tree(); - let model = super::semantic_model(&root); - - let selector_range = TextRange::new(0.into(), 7.into()); - assert_eq!(model.selectors(selector_range).unwrap().len(), 1); - assert_eq!(model.selectors(selector_range).unwrap()[0].0, ".class"); - - assert_eq!(model.declarations(selector_range).unwrap().len(), 1); - let declaration = &model.declarations(selector_range).unwrap()[0]; - assert_eq!(declaration.property, "color"); - assert_eq!(declaration.value, "red"); - } - - #[test] - fn test_semantic_model() { let parse = parse_css( - r#".foo .bar { color: red; text-align: center; }"#, + r#"a { b, c { color: pink; } }"#, CssParserOptions::default(), ); let root = parse.tree(); let model = super::semantic_model(&root); - - let selector_range = TextRange::new(0.into(), 10.into()); - - assert_eq!(model.selectors(selector_range).unwrap().len(), 2); - assert_eq!(model.selectors(selector_range).unwrap()[0].0, ".foo"); - assert_eq!(model.selectors(selector_range).unwrap()[1].0, ".bar"); - - assert_eq!(model.declarations(selector_range).unwrap().len(), 2); - assert_eq!( - model.declarations(selector_range).unwrap()[0].property, - "color" - ); - assert_eq!(model.declarations(selector_range).unwrap()[0].value, "red"); - assert_eq!( - model.declarations(selector_range).unwrap()[1].property, - "text-align" - ); - assert_eq!( - model.declarations(selector_range).unwrap()[1].value, - "center" - ); + dbg!(&model.rules()); } } diff --git a/crates/biome_css_semantic/src/semantic_model/model.rs b/crates/biome_css_semantic/src/semantic_model/model.rs index 68ede5bc0269..137d745fe280 100644 --- a/crates/biome_css_semantic/src/semantic_model/model.rs +++ b/crates/biome_css_semantic/src/semantic_model/model.rs @@ -24,12 +24,8 @@ impl SemanticModel { self.data.node_by_range.get(&range) } - pub fn selectors(&self, range: TextRange) -> Option<&Vec<(String, TextRange)>> { - self.data.selectors.get(&range) - } - - pub fn declarations(&self, range: TextRange) -> Option<&Vec> { - self.data.declarations.get(&range) + pub fn rules(&self) -> &[Rule] { + &self.data.rules } } @@ -38,14 +34,31 @@ pub(crate) struct SemanticModelData { pub(crate) root: CssRoot, // Map to each by its range pub(crate) node_by_range: FxHashMap, - pub(crate) selectors: FxHashMap>, - pub(crate) declarations: FxHashMap>, + pub(crate) rules: Vec, } #[derive(Debug)] +pub struct Rule { + pub selectors: Vec, + pub declarations: Vec, + pub children: Vec, + pub range: TextRange, +} + +#[derive(Debug, Clone)] pub struct Declaration { pub property: String, pub value: String, pub property_range: TextRange, pub value_range: TextRange, } + +#[derive(Debug, Clone)] +pub struct Selector { + pub name: String, + pub range: TextRange, + pub specificity: Specificity, +} + +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Specificity(pub u32, pub u32, pub u32); From 868c180799661c488c41e0eba925165d892830e7 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Sat, 3 Aug 2024 18:20:03 +0900 Subject: [PATCH 14/18] fix: trim unused char --- crates/biome_css_semantic/src/events.rs | 10 ++--- .../src/semantic_model/mod.rs | 41 ++++++++++++++++++- .../src/semantic_model/model.rs | 2 +- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index 1bcc514101ac..5e333e8bf616 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -52,8 +52,8 @@ impl SemanticEventExtractor { if let Some(property_name) = property.first_child() { if let Some(value) = property_name.next_sibling() { self.stash.push_back(SemanticEvent::PropertyDeclaration { - property: property_name.text().to_string(), - value: value.text().to_string(), + property: property_name.text_trimmed().to_string(), + value: value.text_trimmed().to_string(), property_range: property_name.text_range(), value_range: value.text_range(), }); @@ -69,10 +69,10 @@ impl SemanticEventExtractor { match selector { AnyCssSelector::CssComplexSelector(s) => { if let Ok(l) = s.left() { - self.add_selector_event(l.text().to_string(), l.range()); + self.add_selector_event(l.text(), l.range()); } if let Ok(r) = s.right() { - self.add_selector_event(r.text().to_string(), r.range()); + self.add_selector_event(r.text(), r.range()); } } AnyCssSelector::CssCompoundSelector(selector) => { @@ -86,7 +86,7 @@ impl SemanticEventExtractor { self.stash.push_back(SemanticEvent::SelectorDeclaration { name, range, - specificity: Specificity(0, 0, 0), // TODO: Implement calculate_specificity + specificity: Specificity(0, 0, 0), // TODO: Implement this }); } diff --git a/crates/biome_css_semantic/src/semantic_model/mod.rs b/crates/biome_css_semantic/src/semantic_model/mod.rs index 989b808ffbbc..c1fbcc5c111f 100644 --- a/crates/biome_css_semantic/src/semantic_model/mod.rs +++ b/crates/biome_css_semantic/src/semantic_model/mod.rs @@ -38,7 +38,46 @@ mod tests { #[test] fn test_simple_ruleset() { let parse = parse_css( - r#"a { b, c { color: pink; } }"#, + r#"p { + font-family: verdana; + font-size: 20px; +}"#, + CssParserOptions::default(), + ); + + let root = parse.tree(); + let model = super::semantic_model(&root); + let rule = model.rules().first().unwrap(); + + assert_eq!(rule.selectors.len(), 1); + assert_eq!(rule.declarations.len(), 2); + } + #[test] + fn test_nested_selector() { + let parse = parse_css( + r#".parent { + color: blue; + + .child { + color: red; + } +}"#, + CssParserOptions::default(), + ); + + let root = parse.tree(); + let model = super::semantic_model(&root); + let rule = model.rules().first().unwrap(); + + assert_eq!(rule.selectors.len(), 1); + assert_eq!(rule.declarations.len(), 1); + assert_eq!(rule.children.len(), 1); + } + + #[test] + fn debug() { + let parse = parse_css( + r#"[a="b"i], [ a="b"i], [ a ="b"i], [ a = "b"i], [ a = "b" i], [ a = "b" i ] {}"#, CssParserOptions::default(), ); diff --git a/crates/biome_css_semantic/src/semantic_model/model.rs b/crates/biome_css_semantic/src/semantic_model/model.rs index 137d745fe280..363184e0ade6 100644 --- a/crates/biome_css_semantic/src/semantic_model/model.rs +++ b/crates/biome_css_semantic/src/semantic_model/model.rs @@ -60,5 +60,5 @@ pub struct Selector { pub specificity: Specificity, } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct Specificity(pub u32, pub u32, pub u32); From 0880a43545bcd3b3285d6f0d5ba59e423f952b3d Mon Sep 17 00:00:00 2001 From: togami2864 Date: Wed, 7 Aug 2024 08:52:44 +0900 Subject: [PATCH 15/18] chore: doc --- crates/biome_css_semantic/Cargo.toml | 2 +- crates/biome_css_semantic/src/events.rs | 18 +++++------ .../src/semantic_model/model.rs | 30 +++++++++++++++++++ 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/crates/biome_css_semantic/Cargo.toml b/crates/biome_css_semantic/Cargo.toml index bdddb535a8e1..0ad329e17e3a 100644 --- a/crates/biome_css_semantic/Cargo.toml +++ b/crates/biome_css_semantic/Cargo.toml @@ -2,7 +2,7 @@ [package] authors.workspace = true categories.workspace = true -description = "" +description = "Biome's semantic model for CSS" edition.workspace = true homepage.workspace = true keywords.workspace = true diff --git a/crates/biome_css_semantic/src/events.rs b/crates/biome_css_semantic/src/events.rs index 5e333e8bf616..e0b9ff48973a 100644 --- a/crates/biome_css_semantic/src/events.rs +++ b/crates/biome_css_semantic/src/events.rs @@ -48,16 +48,14 @@ impl SemanticEventExtractor { .for_each(|s| self.process_selector(s)); } CSS_DECLARATION => { - if let Some(property) = node.first_child() { - if let Some(property_name) = property.first_child() { - if let Some(value) = property_name.next_sibling() { - self.stash.push_back(SemanticEvent::PropertyDeclaration { - property: property_name.text_trimmed().to_string(), - value: value.text_trimmed().to_string(), - property_range: property_name.text_range(), - value_range: value.text_range(), - }); - } + if let Some(property_name) = node.first_child().and_then(|p| p.first_child()) { + if let Some(value) = property_name.next_sibling() { + self.stash.push_back(SemanticEvent::PropertyDeclaration { + property: property_name.text_trimmed().to_string(), + value: value.text_trimmed().to_string(), + property_range: property_name.text_range(), + value_range: value.text_range(), + }); } } } diff --git a/crates/biome_css_semantic/src/semantic_model/model.rs b/crates/biome_css_semantic/src/semantic_model/model.rs index 363184e0ade6..cad02c9f5e64 100644 --- a/crates/biome_css_semantic/src/semantic_model/model.rs +++ b/crates/biome_css_semantic/src/semantic_model/model.rs @@ -4,6 +4,10 @@ use biome_css_syntax::{CssRoot, CssSyntaxNode}; use biome_rowan::TextRange; use rustc_hash::FxHashMap; +/// The façade for all semantic information of a CSS document. +/// +/// This struct provides access to the root, rules, and individual nodes of the CSS document. +/// It holds a reference-counted pointer to the internal `SemanticModelData`. #[derive(Clone, Debug)] pub struct SemanticModel { pub(crate) data: Rc, @@ -20,45 +24,71 @@ impl SemanticModel { &self.data.root } + /// Retrieves a node by its text range. pub fn node_by_range(&self, range: TextRange) -> Option<&CssSyntaxNode> { self.data.node_by_range.get(&range) } + /// Returns a slice of all rules in the CSS document. pub fn rules(&self) -> &[Rule] { &self.data.rules } } +/// Contains the internal data of a `SemanticModel`. +/// +/// This struct holds the root of the CSS document, a mapping of nodes by their range, +/// and a list of all rules in the document. #[derive(Debug)] pub(crate) struct SemanticModelData { pub(crate) root: CssRoot, // Map to each by its range pub(crate) node_by_range: FxHashMap, + // List of all the rules pub(crate) rules: Vec, } +/// Represents a CSS rule, including its selectors, declarations, and nested rules. #[derive(Debug)] pub struct Rule { + /// The selectors associated with this rule. pub selectors: Vec, + /// The declarations within this rule. pub declarations: Vec, + /// Any nested rules within this rule. pub children: Vec, + /// The text range of this rule in the source document. pub range: TextRange, } +/// Represents a CSS declaration (property-value pair). #[derive(Debug, Clone)] pub struct Declaration { + /// The property name. pub property: String, + /// The property value. pub value: String, + /// The text range of the property in the source document. pub property_range: TextRange, + /// The text range of the value in the source document. pub value_range: TextRange, } +/// Represents a CSS selector. #[derive(Debug, Clone)] pub struct Selector { + /// The name of the selector. pub name: String, + /// The text range of the selector in the source document. pub range: TextRange, + /// The specificity of the selector. pub specificity: Specificity, } +/// Represents the specificity of a CSS selector. +/// +/// This specificity is represented as a tuple of three `u32` values, +/// corresponding to (ID selectors, class selectors, type selectors). +/// More details https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct Specificity(pub u32, pub u32, pub u32); From e6bc38fb7f77b80731db11070b5a992e5d7d27d0 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Wed, 7 Aug 2024 10:36:51 +0900 Subject: [PATCH 16/18] chore: update cargo.toml --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 5e5aeb302068..6284e42a0b52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,6 +97,7 @@ biome_css_analyze = { version = "0.5.7", path = "./crates/biome_css_a biome_css_factory = { version = "0.5.7", path = "./crates/biome_css_factory" } biome_css_formatter = { version = "0.5.7", path = "./crates/biome_css_formatter" } biome_css_parser = { version = "0.5.7", path = "./crates/biome_css_parser" } +biome_css_semantic = { version = "0.0.0", path = "./crates/biome_css_semantic" } biome_css_syntax = { version = "0.5.7", path = "./crates/biome_css_syntax" } biome_deserialize = { version = "0.6.0", path = "./crates/biome_deserialize" } biome_deserialize_macros = { version = "0.6.0", path = "./crates/biome_deserialize_macros" } From 109d1f9a0f0d3049ae52a9eb45ed1fcf3f96d3ed Mon Sep 17 00:00:00 2001 From: togami2864 Date: Wed, 7 Aug 2024 10:46:55 +0900 Subject: [PATCH 17/18] chore: debug --- .github/workflows/pull_request.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index db391eaf1c35..2a13a9eb1c27 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -5,13 +5,13 @@ on: branches: - main paths: # Only run when changes are made to rust code or root Cargo - - 'crates/**' - - 'fuzz/**' - - 'xtask/**' - - 'Cargo.toml' - - 'Cargo.lock' - - 'rust-toolchain.toml' - - 'rustfmt.toml' + - "crates/**" + - "fuzz/**" + - "xtask/**" + - "Cargo.toml" + - "Cargo.lock" + - "rust-toolchain.toml" + - "rustfmt.toml" # Cancel jobs when the PR is updated concurrency: @@ -184,5 +184,6 @@ jobs: run: | if [[ `git status --porcelain` ]]; then git status + git diff exit 1 fi From a3c2f86eaf6037c8ade5dcfbad9de25860a477e9 Mon Sep 17 00:00:00 2001 From: togami2864 Date: Wed, 7 Aug 2024 20:42:21 +0900 Subject: [PATCH 18/18] chore: update cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 4ca443448d1f..8ab20d883726 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -329,7 +329,7 @@ dependencies = [ "biome_css_parser", "biome_css_syntax", "biome_rowan", - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]]