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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci-manual-rubies.yml +44 -0
  3. data/.overcommit.yml +1 -1
  4. data/.rubocop.yml +96 -4
  5. data/.rubocop_todo.yml +186 -0
  6. data/BENCHMARKS.md +62 -141
  7. data/CHANGELOG.md +20 -0
  8. data/RAGEL_MIGRATION.md +2 -2
  9. data/README.md +37 -4
  10. data/Rakefile +72 -32
  11. data/cataract.gemspec +4 -1
  12. data/ext/cataract/cataract.c +59 -50
  13. data/ext/cataract/cataract.h +5 -3
  14. data/ext/cataract/css_parser.c +173 -65
  15. data/ext/cataract/extconf.rb +2 -2
  16. data/ext/cataract/{merge.c → flatten.c} +526 -468
  17. data/ext/cataract/shorthand_expander.c +164 -115
  18. data/lib/cataract/at_rule.rb +8 -9
  19. data/lib/cataract/declaration.rb +18 -0
  20. data/lib/cataract/import_resolver.rb +63 -43
  21. data/lib/cataract/import_statement.rb +49 -0
  22. data/lib/cataract/pure/byte_constants.rb +69 -0
  23. data/lib/cataract/pure/flatten.rb +1145 -0
  24. data/lib/cataract/pure/helpers.rb +35 -0
  25. data/lib/cataract/pure/imports.rb +268 -0
  26. data/lib/cataract/pure/parser.rb +1340 -0
  27. data/lib/cataract/pure/serializer.rb +590 -0
  28. data/lib/cataract/pure/specificity.rb +206 -0
  29. data/lib/cataract/pure.rb +153 -0
  30. data/lib/cataract/rule.rb +69 -15
  31. data/lib/cataract/stylesheet.rb +356 -49
  32. data/lib/cataract/version.rb +1 -1
  33. data/lib/cataract.rb +43 -26
  34. metadata +14 -26
  35. data/benchmarks/benchmark_harness.rb +0 -193
  36. data/benchmarks/benchmark_merging.rb +0 -121
  37. data/benchmarks/benchmark_optimization_comparison.rb +0 -168
  38. data/benchmarks/benchmark_parsing.rb +0 -153
  39. data/benchmarks/benchmark_ragel_removal.rb +0 -56
  40. data/benchmarks/benchmark_runner.rb +0 -70
  41. data/benchmarks/benchmark_serialization.rb +0 -180
  42. data/benchmarks/benchmark_shorthand.rb +0 -109
  43. data/benchmarks/benchmark_shorthand_expansion.rb +0 -176
  44. data/benchmarks/benchmark_specificity.rb +0 -124
  45. data/benchmarks/benchmark_string_allocation.rb +0 -151
  46. data/benchmarks/benchmark_stylesheet_to_s.rb +0 -62
  47. data/benchmarks/benchmark_to_s_cached.rb +0 -55
  48. data/benchmarks/benchmark_value_splitter.rb +0 -54
  49. data/benchmarks/benchmark_yjit.rb +0 -158
  50. data/benchmarks/benchmark_yjit_workers.rb +0 -61
  51. data/benchmarks/profile_to_s.rb +0 -23
  52. data/benchmarks/speedup_calculator.rb +0 -83
  53. data/benchmarks/system_metadata.rb +0 -81
  54. data/benchmarks/templates/benchmarks.md.erb +0 -221
  55. data/benchmarks/yjit_tests.rb +0 -141
  56. data/scripts/fuzzer/run.rb +0 -828
  57. data/scripts/fuzzer/worker.rb +0 -99
  58. 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