cataract 0.1.3 → 0.2.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/ci-manual-rubies.yml +44 -0
- data/.overcommit.yml +1 -1
- data/.rubocop.yml +96 -4
- data/.rubocop_todo.yml +186 -0
- data/BENCHMARKS.md +62 -141
- data/CHANGELOG.md +20 -0
- data/RAGEL_MIGRATION.md +2 -2
- data/README.md +37 -4
- data/Rakefile +72 -32
- data/cataract.gemspec +4 -1
- data/ext/cataract/cataract.c +59 -50
- data/ext/cataract/cataract.h +5 -3
- data/ext/cataract/css_parser.c +173 -65
- data/ext/cataract/extconf.rb +2 -2
- data/ext/cataract/{merge.c → flatten.c} +526 -468
- data/ext/cataract/shorthand_expander.c +164 -115
- data/lib/cataract/at_rule.rb +8 -9
- data/lib/cataract/declaration.rb +18 -0
- data/lib/cataract/import_resolver.rb +63 -43
- data/lib/cataract/import_statement.rb +49 -0
- data/lib/cataract/pure/byte_constants.rb +69 -0
- data/lib/cataract/pure/flatten.rb +1145 -0
- data/lib/cataract/pure/helpers.rb +35 -0
- data/lib/cataract/pure/imports.rb +268 -0
- data/lib/cataract/pure/parser.rb +1340 -0
- data/lib/cataract/pure/serializer.rb +590 -0
- data/lib/cataract/pure/specificity.rb +206 -0
- data/lib/cataract/pure.rb +153 -0
- data/lib/cataract/rule.rb +69 -15
- data/lib/cataract/stylesheet.rb +356 -49
- data/lib/cataract/version.rb +1 -1
- data/lib/cataract.rb +43 -26
- metadata +14 -26
- data/benchmarks/benchmark_harness.rb +0 -193
- data/benchmarks/benchmark_merging.rb +0 -121
- data/benchmarks/benchmark_optimization_comparison.rb +0 -168
- data/benchmarks/benchmark_parsing.rb +0 -153
- data/benchmarks/benchmark_ragel_removal.rb +0 -56
- data/benchmarks/benchmark_runner.rb +0 -70
- data/benchmarks/benchmark_serialization.rb +0 -180
- data/benchmarks/benchmark_shorthand.rb +0 -109
- data/benchmarks/benchmark_shorthand_expansion.rb +0 -176
- data/benchmarks/benchmark_specificity.rb +0 -124
- data/benchmarks/benchmark_string_allocation.rb +0 -151
- data/benchmarks/benchmark_stylesheet_to_s.rb +0 -62
- data/benchmarks/benchmark_to_s_cached.rb +0 -55
- data/benchmarks/benchmark_value_splitter.rb +0 -54
- data/benchmarks/benchmark_yjit.rb +0 -158
- data/benchmarks/benchmark_yjit_workers.rb +0 -61
- data/benchmarks/profile_to_s.rb +0 -23
- data/benchmarks/speedup_calculator.rb +0 -83
- data/benchmarks/system_metadata.rb +0 -81
- data/benchmarks/templates/benchmarks.md.erb +0 -221
- data/benchmarks/yjit_tests.rb +0 -141
- data/scripts/fuzzer/run.rb +0 -828
- data/scripts/fuzzer/worker.rb +0 -99
- data/scripts/generate_benchmarks_md.rb +0 -155
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cataract
|
|
4
|
+
# Represents a CSS @import statement
|
|
5
|
+
#
|
|
6
|
+
# @import statements are parsed and stored separately in the stylesheet's @_imports array.
|
|
7
|
+
# They can later be resolved by the ImportResolver to fetch and inline the imported CSS.
|
|
8
|
+
#
|
|
9
|
+
# Per CSS spec, @import must appear before all rules except @charset and @layer.
|
|
10
|
+
# Any @import that appears after a style rule is invalid and will be ignored with a warning.
|
|
11
|
+
#
|
|
12
|
+
# @example Basic import
|
|
13
|
+
# @import "styles.css";
|
|
14
|
+
# # => ImportStatement(url: "styles.css", media: nil)
|
|
15
|
+
#
|
|
16
|
+
# @example Import with media query
|
|
17
|
+
# @import "mobile.css" screen and (max-width: 768px);
|
|
18
|
+
# # => ImportStatement(url: "mobile.css", media: :"screen and (max-width: 768px)")
|
|
19
|
+
#
|
|
20
|
+
# @attr [Integer] id The import's position in the source (0-indexed)
|
|
21
|
+
# @attr [String] url The URL to import (without quotes or url() wrapper)
|
|
22
|
+
# @attr [Symbol, nil] media The media query as a symbol, or nil if no media query
|
|
23
|
+
# @attr [Boolean] resolved Whether this import has been resolved/processed
|
|
24
|
+
ImportStatement = Struct.new(:id, :url, :media, :resolved) unless const_defined?(:ImportStatement)
|
|
25
|
+
|
|
26
|
+
class ImportStatement
|
|
27
|
+
# Compare two ImportStatement objects for equality.
|
|
28
|
+
# Two imports are equal if they have the same URL and media query.
|
|
29
|
+
# The ID is ignored as it's an implementation detail.
|
|
30
|
+
#
|
|
31
|
+
# @param other [Object] Object to compare with
|
|
32
|
+
# @return [Boolean] true if equal, false otherwise
|
|
33
|
+
def ==(other)
|
|
34
|
+
return false unless other.is_a?(ImportStatement)
|
|
35
|
+
|
|
36
|
+
url == other.url && media == other.media
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
alias eql? ==
|
|
40
|
+
|
|
41
|
+
# Generate hash code for ImportStatement.
|
|
42
|
+
# Uses URL and media query (ignores ID).
|
|
43
|
+
#
|
|
44
|
+
# @return [Integer] Hash code
|
|
45
|
+
def hash
|
|
46
|
+
[url, media].hash
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Pure Ruby CSS parser - Byte constants for fast parsing
|
|
4
|
+
# Using getbyte() instead of String#[] to avoid allocating millions of string objects
|
|
5
|
+
|
|
6
|
+
module Cataract
|
|
7
|
+
# Whitespace bytes
|
|
8
|
+
BYTE_SPACE = 32 # ' '
|
|
9
|
+
BYTE_TAB = 9 # '\t'
|
|
10
|
+
BYTE_NEWLINE = 10 # '\n'
|
|
11
|
+
BYTE_CR = 13 # '\r'
|
|
12
|
+
|
|
13
|
+
# CSS structural characters
|
|
14
|
+
BYTE_AT = 64 # '@'
|
|
15
|
+
BYTE_LBRACE = 123 # '{'
|
|
16
|
+
BYTE_RBRACE = 125 # '}'
|
|
17
|
+
BYTE_LPAREN = 40 # '('
|
|
18
|
+
BYTE_RPAREN = 41 # ')'
|
|
19
|
+
BYTE_LBRACKET = 91 # '['
|
|
20
|
+
BYTE_RBRACKET = 93 # ']'
|
|
21
|
+
BYTE_SEMICOLON = 59 # ';'
|
|
22
|
+
BYTE_COLON = 58 # ':'
|
|
23
|
+
BYTE_COMMA = 44 # ','
|
|
24
|
+
|
|
25
|
+
# Comment characters
|
|
26
|
+
BYTE_SLASH = 47 # '/'
|
|
27
|
+
BYTE_STAR = 42 # '*'
|
|
28
|
+
|
|
29
|
+
# Quote characters
|
|
30
|
+
BYTE_SQUOTE = 39 # "'"
|
|
31
|
+
BYTE_DQUOTE = 34 # '"'
|
|
32
|
+
|
|
33
|
+
# Selector characters
|
|
34
|
+
BYTE_HASH = 35 # '#'
|
|
35
|
+
BYTE_DOT = 46 # '.'
|
|
36
|
+
BYTE_GT = 62 # '>'
|
|
37
|
+
BYTE_PLUS = 43 # '+'
|
|
38
|
+
BYTE_TILDE = 126 # '~'
|
|
39
|
+
BYTE_ASTERISK = 42 # '*'
|
|
40
|
+
BYTE_AMPERSAND = 38 # '&'
|
|
41
|
+
|
|
42
|
+
# Other
|
|
43
|
+
BYTE_HYPHEN = 45 # '-'
|
|
44
|
+
BYTE_UNDERSCORE = 95 # '_'
|
|
45
|
+
BYTE_BACKSLASH = 92 # '\\'
|
|
46
|
+
BYTE_BANG = 33 # '!'
|
|
47
|
+
BYTE_PERCENT = 37 # '%'
|
|
48
|
+
BYTE_SLASH_FWD = 47 # '/' (also defined as BYTE_SLASH above)
|
|
49
|
+
|
|
50
|
+
# Specific lowercase letters (for keyword matching)
|
|
51
|
+
BYTE_LOWER_U = 117 # 'u'
|
|
52
|
+
BYTE_LOWER_R = 114 # 'r'
|
|
53
|
+
BYTE_LOWER_L = 108 # 'l'
|
|
54
|
+
|
|
55
|
+
# Letter ranges (a-z, A-Z)
|
|
56
|
+
BYTE_LOWER_A = 97 # 'a'
|
|
57
|
+
BYTE_LOWER_Z = 122 # 'z'
|
|
58
|
+
BYTE_UPPER_A = 65 # 'A'
|
|
59
|
+
BYTE_UPPER_Z = 90 # 'Z'
|
|
60
|
+
BYTE_CASE_DIFF = 32 # Difference between lowercase and uppercase ('a' - 'A')
|
|
61
|
+
|
|
62
|
+
# Digit range (0-9)
|
|
63
|
+
BYTE_DIGIT_0 = 48 # '0'
|
|
64
|
+
BYTE_DIGIT_9 = 57 # '9'
|
|
65
|
+
|
|
66
|
+
# Nesting styles (for CSS nesting support)
|
|
67
|
+
NESTING_STYLE_IMPLICIT = 0 # Implicit nesting: .parent { .child { ... } } => .parent .child
|
|
68
|
+
NESTING_STYLE_EXPLICIT = 1 # Explicit nesting: .parent { &:hover { ... } } => .parent:hover
|
|
69
|
+
end
|