p_css 0.2.0.beta1-x86_64-linux

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/Cargo.lock +282 -0
  3. data/Cargo.toml +3 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +357 -0
  6. data/ext/css_native/Cargo.toml +12 -0
  7. data/ext/css_native/extconf.rb +4 -0
  8. data/ext/css_native/src/lib.rs +117 -0
  9. data/ext/css_native/src/matcher.rs +356 -0
  10. data/ext/css_native/src/selectors.rs +411 -0
  11. data/ext/css_native/src/snapshot.rs +370 -0
  12. data/ext/css_native/src/state.rs +174 -0
  13. data/ext/css_native/src/tokenizer.rs +596 -0
  14. data/lib/css/3.3/css_native.so +0 -0
  15. data/lib/css/3.4/css_native.so +0 -0
  16. data/lib/css/4.0/css_native.so +0 -0
  17. data/lib/css/cascade.rb +277 -0
  18. data/lib/css/code_points.rb +59 -0
  19. data/lib/css/escape.rb +82 -0
  20. data/lib/css/media_queries/context.rb +60 -0
  21. data/lib/css/media_queries/evaluator.rb +157 -0
  22. data/lib/css/media_queries/nodes.rb +41 -0
  23. data/lib/css/media_queries/parser.rb +374 -0
  24. data/lib/css/media_queries.rb +9 -0
  25. data/lib/css/native.rb +179 -0
  26. data/lib/css/nesting.rb +229 -0
  27. data/lib/css/nodes.rb +42 -0
  28. data/lib/css/parser.rb +429 -0
  29. data/lib/css/selectors/anb_parser.rb +174 -0
  30. data/lib/css/selectors/matcher.rb +545 -0
  31. data/lib/css/selectors/nodes.rb +61 -0
  32. data/lib/css/selectors/parser.rb +395 -0
  33. data/lib/css/selectors/serializer.rb +102 -0
  34. data/lib/css/selectors/specificity.rb +81 -0
  35. data/lib/css/selectors.rb +11 -0
  36. data/lib/css/serializer.rb +167 -0
  37. data/lib/css/token.rb +107 -0
  38. data/lib/css/token_cursor.rb +49 -0
  39. data/lib/css/tokenizer.rb +447 -0
  40. data/lib/css/urange.rb +45 -0
  41. data/lib/css/version.rb +3 -0
  42. data/lib/css.rb +73 -0
  43. data/lib/p_css.rb +1 -0
  44. data/sig/css/cascade.rbs +22 -0
  45. data/sig/css/media_queries.rbs +107 -0
  46. data/sig/css/nodes.rbs +76 -0
  47. data/sig/css/selectors.rbs +164 -0
  48. data/sig/css/token.rbs +33 -0
  49. data/sig/css.rbs +99 -0
  50. metadata +113 -0
data/sig/css/nodes.rbs ADDED
@@ -0,0 +1,76 @@
1
+ module CSS
2
+ module Nodes
3
+ # `Token` here covers preserved comments when the stylesheet was
4
+ # parsed with `preserve_comments: true`.
5
+ type rule = AtRule | QualifiedRule | Token
6
+
7
+ type block_item = Declaration | QualifiedRule | AtRule | Token
8
+
9
+ class Stylesheet < Data
10
+ attr_reader rules: Array[rule]
11
+
12
+ def self.new: (rules: Array[rule]) -> Stylesheet
13
+ end
14
+
15
+ # `prelude` is the list of component values before `{` or `;`;
16
+ # `block` is `nil` for at-rules ending with `;` (e.g. `@charset "UTF-8";`).
17
+ class AtRule < Data
18
+ attr_reader name: String
19
+ attr_reader prelude: Array[component_value]
20
+ attr_reader block: Block?
21
+
22
+ def self.new: (name: String, prelude: Array[component_value], block: Block?) -> AtRule
23
+ end
24
+
25
+ class QualifiedRule < Data
26
+ attr_reader prelude: Array[component_value]
27
+ attr_reader block: Block
28
+
29
+ def self.new: (prelude: Array[component_value], block: Block) -> QualifiedRule
30
+ end
31
+
32
+ class Block < Data
33
+ attr_reader items: Array[block_item]
34
+
35
+ def self.new: (items: Array[block_item]) -> Block
36
+ end
37
+
38
+ class Declaration < Data
39
+ attr_reader name: String
40
+ attr_reader value: Array[component_value]
41
+ attr_reader important: bool
42
+
43
+ def self.new: (name: String, value: Array[component_value], important: bool) -> Declaration
44
+ end
45
+
46
+ class Function < Data
47
+ attr_reader name: String
48
+ attr_reader value: Array[component_value]
49
+
50
+ def self.new: (name: String, value: Array[component_value]) -> Function
51
+ end
52
+
53
+ # `open` is one of `(`, `[`, `{`.
54
+ class SimpleBlock < Data
55
+ attr_reader open: String
56
+ attr_reader value: Array[component_value]
57
+
58
+ def self.new: (open: String, value: Array[component_value]) -> SimpleBlock
59
+
60
+ def braced?: () -> bool
61
+ def bracketed?: () -> bool
62
+ def parenthesized?: () -> bool
63
+ end
64
+
65
+ # Inclusive code-point range produced by `CSS.parse_urange`.
66
+ class UnicodeRange < Data
67
+ attr_reader first: Integer
68
+ attr_reader last: Integer
69
+
70
+ def self.new: (first: Integer, last: Integer) -> UnicodeRange
71
+
72
+ def cover?: (Integer cp) -> bool
73
+ def to_s: () -> String
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,164 @@
1
+ module CSS
2
+ module Selectors
3
+ # Marker module included by every Selector AST node so callers can
4
+ # discriminate `Selectors::Node` from raw component values.
5
+ module Node
6
+ end
7
+
8
+ type combinator = :descendant | :child | :next_sibling | :subsequent_sibling
9
+
10
+ type simple_selector =
11
+ TypeSelector | UniversalSelector | NestingSelector
12
+ | IdSelector | ClassSelector | AttributeSelector
13
+ | PseudoClass | PseudoElement
14
+
15
+ type attribute_matcher = :exact | :includes | :dash | :prefix | :suffix | :substring
16
+
17
+ type case_flag = :i | :s
18
+
19
+ # `argument` is `nil` for plain `:hover` etc., a `SelectorList` for
20
+ # `:not / :is / :where / :matches`, an `AnB` for `:nth-*`, or an
21
+ # opaque component-value array for unrecognized functional pseudos
22
+ # (including `:has`, which is intentionally not parsed as a selector
23
+ # list yet).
24
+ type pseudo_argument = nil | SelectorList | AnB | Array[component_value]
25
+
26
+ class SelectorList < Data
27
+ include Node
28
+
29
+ attr_reader selectors: Array[ComplexSelector]
30
+
31
+ def self.new: (selectors: Array[ComplexSelector]) -> SelectorList
32
+
33
+ def to_s: () -> String
34
+ end
35
+
36
+ # `compounds.size == combinators.size + 1`. `combinators[i]` joins
37
+ # `compounds[i]` to `compounds[i + 1]`.
38
+ class ComplexSelector < Data
39
+ include Node
40
+
41
+ attr_reader compounds: Array[CompoundSelector]
42
+ attr_reader combinators: Array[combinator]
43
+
44
+ def self.new: (compounds: Array[CompoundSelector], combinators: Array[combinator]) -> ComplexSelector
45
+
46
+ def to_s: () -> String
47
+ end
48
+
49
+ class CompoundSelector < Data
50
+ include Node
51
+
52
+ attr_reader components: Array[simple_selector]
53
+
54
+ def self.new: (components: Array[simple_selector]) -> CompoundSelector
55
+
56
+ def to_s: () -> String
57
+ end
58
+
59
+ class TypeSelector < Data
60
+ include Node
61
+
62
+ attr_reader name: String
63
+
64
+ def self.new: (name: String) -> TypeSelector
65
+ end
66
+
67
+ class UniversalSelector < Data
68
+ include Node
69
+
70
+ def self.new: () -> UniversalSelector
71
+ end
72
+
73
+ class NestingSelector < Data
74
+ include Node
75
+
76
+ def self.new: () -> NestingSelector
77
+ end
78
+
79
+ class IdSelector < Data
80
+ include Node
81
+
82
+ attr_reader name: String
83
+
84
+ def self.new: (name: String) -> IdSelector
85
+ end
86
+
87
+ class ClassSelector < Data
88
+ include Node
89
+
90
+ attr_reader name: String
91
+
92
+ def self.new: (name: String) -> ClassSelector
93
+ end
94
+
95
+ class AttributeSelector < Data
96
+ include Node
97
+
98
+ attr_reader name: String
99
+ attr_reader matcher: attribute_matcher?
100
+ attr_reader value: String?
101
+ attr_reader case_flag: case_flag?
102
+
103
+ def self.new: (name: String, matcher: attribute_matcher?, value: String?, case_flag: case_flag?) -> AttributeSelector
104
+ end
105
+
106
+ class PseudoClass < Data
107
+ include Node
108
+
109
+ attr_reader name: String
110
+ attr_reader argument: pseudo_argument
111
+
112
+ def self.new: (name: String, argument: pseudo_argument) -> PseudoClass
113
+ end
114
+
115
+ class PseudoElement < Data
116
+ include Node
117
+
118
+ attr_reader name: String
119
+ attr_reader argument: pseudo_argument
120
+
121
+ def self.new: (name: String, argument: pseudo_argument) -> PseudoElement
122
+ end
123
+
124
+ class AnB < Data
125
+ include Node
126
+
127
+ attr_reader step: Integer
128
+ attr_reader offset: Integer
129
+
130
+ def self.new: (step: Integer, offset: Integer) -> AnB
131
+
132
+ def to_s: () -> String
133
+ end
134
+
135
+ # Selectors §16 specificity tuple `(a, b, c)` — id / class+attr+pseudo /
136
+ # type+pseudo-element counts.
137
+ class Specificity < Data
138
+ include Comparable
139
+
140
+ ZERO: Specificity
141
+
142
+ attr_reader a: Integer
143
+ attr_reader b: Integer
144
+ attr_reader c: Integer
145
+
146
+ def self.new: (a: Integer, b: Integer, c: Integer) -> Specificity
147
+
148
+ def <=>: (untyped other) -> Integer?
149
+ def +: (Specificity other) -> Specificity
150
+ def to_s: () -> String
151
+ end
152
+
153
+ module Matcher
154
+ STATEFUL_PSEUDOS: Set[String]
155
+ PROPAGATING_STATEFUL_PSEUDOS: Set[String]
156
+
157
+ def self.matches?: (untyped element, untyped selector, ?cache: Hash[Integer, untyped], ?state: matcher_state?) -> bool
158
+
159
+ def self.tag_of: (untyped element, ?Hash[Integer, untyped]?) -> String
160
+ def self.id_of: (untyped element, ?Hash[Integer, untyped]?) -> String?
161
+ def self.classes_of: (untyped element, ?Hash[Integer, untyped]?) -> Set[String]
162
+ end
163
+ end
164
+ end
data/sig/css/token.rbs ADDED
@@ -0,0 +1,33 @@
1
+ module CSS
2
+ class Token
3
+ TYPES: Array[Symbol]
4
+
5
+ type token_type =
6
+ :ident | :function | :at_keyword | :hash | :string | :bad_string
7
+ | :url | :bad_url | :delim | :number | :percentage | :dimension
8
+ | :whitespace | :cdo | :cdc | :comment
9
+ | :colon | :semicolon | :comma
10
+ | :lbracket | :rbracket | :lparen | :rparen | :lbrace | :rbrace
11
+ | :eof
12
+
13
+ attr_reader type: token_type
14
+ attr_reader value: untyped
15
+ attr_reader flag: Symbol?
16
+ attr_reader unit: String?
17
+ attr_reader position: Position?
18
+
19
+ def initialize: (token_type type, ?untyped value, ?flag: Symbol?, ?unit: String?, ?position: Position?) -> void
20
+
21
+ def whitespace?: () -> bool
22
+ def comment?: () -> bool
23
+ def trivia?: () -> bool
24
+
25
+ def assign_source!: (Integer start_offset, Integer end_offset, Array[Integer] newlines) -> self
26
+
27
+ def ==: (untyped other) -> bool
28
+ def eql?: (untyped other) -> bool
29
+ def hash: () -> Integer
30
+
31
+ def inspect: () -> String
32
+ end
33
+ end
data/sig/css.rbs ADDED
@@ -0,0 +1,99 @@
1
+ # CSS Syntax Level 4 toolkit — top-level entry points and shared types.
2
+ #
3
+ # Public API surface lives directly on `CSS`; AST nodes live under
4
+ # `CSS::Nodes`, `CSS::Selectors`, and `CSS::MediaQueries`. Per-token
5
+ # source positions are `CSS::Position`.
6
+ module CSS
7
+ # Inputs that carry CSS source. `String` is tokenized internally; an
8
+ # array of component values (as produced by `CSS.parse_component_values`
9
+ # or by reading a rule's `prelude`) is consumed structurally.
10
+ type input = String | Array[component_value]
11
+
12
+ # The output of `CSS.parse_component_value` and the element type of a
13
+ # rule's `prelude` / declaration's `value`.
14
+ type component_value = Token | Nodes::Function | Nodes::SimpleBlock
15
+
16
+ # Bracket-pair information used by both the parser (open token type →
17
+ # open char, close token type) and the serializer.
18
+ BRACKET_OPEN_CHAR: Hash[Symbol, String]
19
+ BRACKET_CLOSE_TYPE: Hash[Symbol, Symbol]
20
+ BRACKET_PAIRS: Hash[String, String]
21
+
22
+ class ParseError < StandardError
23
+ attr_reader position: Position?
24
+
25
+ def initialize: (String message, ?position: Position?) -> void
26
+ end
27
+
28
+ # 1-based line / column with 0-based character offsets into the
29
+ # preprocessed input.
30
+ class Position < Data
31
+ attr_reader line: Integer
32
+ attr_reader column: Integer
33
+ attr_reader offset: Integer
34
+ attr_reader end_offset: Integer
35
+
36
+ def self.new: (line: Integer, column: Integer, offset: Integer, end_offset: Integer) -> Position
37
+
38
+ def to_s: () -> String
39
+ end
40
+
41
+ # Tokenization (Syntax 4 §4)
42
+ # ---------------------------------------------------------------
43
+
44
+ def self.tokenize: (String input, ?preserve_comments: bool) -> Array[Token]
45
+
46
+ # Parsing (Syntax 4 §5.3)
47
+ # ---------------------------------------------------------------
48
+
49
+ def self.parse_stylesheet: (input input, ?preserve_comments: bool) -> Nodes::Stylesheet
50
+ def self.parse: (input input, ?preserve_comments: bool) -> Nodes::Stylesheet
51
+
52
+ def self.parse_rule: (input input, ?preserve_comments: bool) -> (Nodes::AtRule | Nodes::QualifiedRule)
53
+ def self.parse_declaration: (input input, ?preserve_comments: bool) -> Nodes::Declaration
54
+ def self.parse_block_contents: (input input, ?preserve_comments: bool) -> Nodes::Block
55
+
56
+ def self.parse_component_value: (input input, ?preserve_comments: bool) -> component_value
57
+ def self.parse_component_values: (input input, ?preserve_comments: bool) -> Array[component_value]
58
+ def self.parse_comma_separated_values: (input input, ?preserve_comments: bool) -> Array[Array[component_value]]
59
+
60
+ # Selectors (Selectors 4)
61
+ # ---------------------------------------------------------------
62
+
63
+ def self.parse_selector_list: (String | Array[component_value] input) -> Selectors::SelectorList
64
+ def self.parse_selector: (String | Array[component_value] input) -> Selectors::ComplexSelector
65
+ def self.parse_anb: (String | Array[Token] input) -> Selectors::AnB
66
+
67
+ def self.specificity: (Selectors::Node selector) -> Selectors::Specificity
68
+
69
+ type selector = Selectors::SelectorList | Selectors::ComplexSelector | Selectors::CompoundSelector
70
+
71
+ # Per-pseudo state. Keys are pseudo-class names (Symbol or String);
72
+ # values are `true` (match every element), a `Set` / `Array` of the
73
+ # specific elements in that state, or falsy (no match).
74
+ type matcher_state = Hash[Symbol | String, bool | Set[untyped] | Array[untyped]]
75
+
76
+ def self.matches?: (untyped element, String | selector selector, ?cache: Hash[Integer, untyped], ?state: matcher_state?) -> bool
77
+
78
+ # Media queries (Media Queries 4)
79
+ # ---------------------------------------------------------------
80
+
81
+ def self.parse_media_query_list: (String | Array[component_value] input) -> MediaQueries::MediaQueryList
82
+
83
+ type media_context_input = MediaQueries::Context | Hash[String, untyped]
84
+
85
+ def self.media_matches?: (String | MediaQueries::MediaQueryList query_list, media_context_input context) -> bool
86
+
87
+ # Other transformations
88
+ # ---------------------------------------------------------------
89
+
90
+ def self.parse_urange: (_ToS input) -> Nodes::UnicodeRange
91
+
92
+ def self.desugar: (Nodes::Stylesheet stylesheet) -> Nodes::Stylesheet
93
+
94
+ def self.cascade: (Nodes::Stylesheet stylesheet, ?context: MediaQueries::Context) -> Cascade
95
+
96
+ def self.serialize: (untyped node) -> String
97
+
98
+ VERSION: String
99
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: p_css
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0.beta1
5
+ platform: x86_64-linux
6
+ authors:
7
+ - Keita Urashima
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-05-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rb_sys
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.9'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.9'
27
+ description: p_css is a Ruby implementation of the CSS Syntax Level 4 tokenizer and
28
+ parser, including support for CSS nesting.
29
+ email:
30
+ - ursm@ursm.jp
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - Cargo.lock
36
+ - Cargo.toml
37
+ - LICENSE.txt
38
+ - README.md
39
+ - ext/css_native/Cargo.toml
40
+ - ext/css_native/extconf.rb
41
+ - ext/css_native/src/lib.rs
42
+ - ext/css_native/src/matcher.rs
43
+ - ext/css_native/src/selectors.rs
44
+ - ext/css_native/src/snapshot.rs
45
+ - ext/css_native/src/state.rs
46
+ - ext/css_native/src/tokenizer.rs
47
+ - lib/css.rb
48
+ - lib/css/3.3/css_native.so
49
+ - lib/css/3.4/css_native.so
50
+ - lib/css/4.0/css_native.so
51
+ - lib/css/cascade.rb
52
+ - lib/css/code_points.rb
53
+ - lib/css/escape.rb
54
+ - lib/css/media_queries.rb
55
+ - lib/css/media_queries/context.rb
56
+ - lib/css/media_queries/evaluator.rb
57
+ - lib/css/media_queries/nodes.rb
58
+ - lib/css/media_queries/parser.rb
59
+ - lib/css/native.rb
60
+ - lib/css/nesting.rb
61
+ - lib/css/nodes.rb
62
+ - lib/css/parser.rb
63
+ - lib/css/selectors.rb
64
+ - lib/css/selectors/anb_parser.rb
65
+ - lib/css/selectors/matcher.rb
66
+ - lib/css/selectors/nodes.rb
67
+ - lib/css/selectors/parser.rb
68
+ - lib/css/selectors/serializer.rb
69
+ - lib/css/selectors/specificity.rb
70
+ - lib/css/serializer.rb
71
+ - lib/css/token.rb
72
+ - lib/css/token_cursor.rb
73
+ - lib/css/tokenizer.rb
74
+ - lib/css/urange.rb
75
+ - lib/css/version.rb
76
+ - lib/p_css.rb
77
+ - sig/css.rbs
78
+ - sig/css/cascade.rbs
79
+ - sig/css/media_queries.rbs
80
+ - sig/css/nodes.rbs
81
+ - sig/css/selectors.rbs
82
+ - sig/css/token.rbs
83
+ homepage: https://github.com/ursm/p_css
84
+ licenses:
85
+ - MIT
86
+ metadata:
87
+ bug_tracker_uri: https://github.com/ursm/p_css/issues
88
+ changelog_uri: https://github.com/ursm/p_css/releases
89
+ source_code_uri: https://github.com/ursm/p_css
90
+ rubygems_mfa_required: 'true'
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '3.3'
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: 4.1.dev
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubygems_version: 3.5.22
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: A CSS Syntax Level 4 parser for Ruby, with nesting support.
113
+ test_files: []