cataract 0.2.5 → 0.3.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.
@@ -51,12 +51,16 @@ extern VALUE eParseError;
51
51
  #define DECL_VALUE 1
52
52
  #define DECL_IMPORTANT 2
53
53
 
54
- // AtRule struct field indices (id, selector, content, specificity)
55
- // Matches Rule interface for duck-typing
54
+ // AtRule struct field indices (id, selector, content, specificity, media_query_id)
55
+ // Matches Rule interface for duck-typing, but AtRule has fewer members - its
56
+ // indices do NOT line up with Rule's past AT_RULE_SPECIFICITY (e.g. index 4
57
+ // is media_query_id here but parent_rule_id on Rule), so never read a field
58
+ // off an AtRule using a RULE_* index beyond AT_RULE_SPECIFICITY.
56
59
  #define AT_RULE_ID 0
57
60
  #define AT_RULE_SELECTOR 1
58
61
  #define AT_RULE_CONTENT 2
59
62
  #define AT_RULE_SPECIFICITY 3
63
+ #define AT_RULE_MEDIA_QUERY_ID 4
60
64
 
61
65
  // ============================================================================
62
66
  // Macros
@@ -88,6 +92,116 @@ static inline void trim_trailing(const char *start, const char **end) {
88
92
  }
89
93
  }
90
94
 
95
+ // Detect and strip a trailing '!important' marker from a value range.
96
+ // Assumes [val_start, *val_end) has already had trailing whitespace trimmed.
97
+ // Shared by every declaration-value scanner (css_parser.c's parse_declarations
98
+ // and parse_mixed_block, and cataract.c's declaration-string parser) so they
99
+ // all agree on what counts as important.
100
+ //
101
+ // The CSS2.1 grammar defines the IMPORTANT_SYM lexical token as:
102
+ // "!"({w}|{comment})*{I}{M}{P}{O}{R}{T}{A}{N}{T}
103
+ // (https://www.w3.org/TR/CSS2/grammar.html) - i.e. zero or more whitespace
104
+ // tokens are allowed between '!' and 'important'.
105
+ //
106
+ // On match, *val_end is updated to exclude the marker (not including any
107
+ // whitespace immediately before the '!' - callers should trim_trailing again)
108
+ // and 1 is returned. Otherwise *val_end is left untouched and 0 is returned.
109
+ static inline int extract_important(const char *val_start, const char **val_end) {
110
+ const char *check = *val_end;
111
+ if (check - val_start < 10) return 0; // strlen("!important") = 10
112
+
113
+ while (check > val_start && IS_WHITESPACE(*(check - 1))) check--;
114
+
115
+ if (check - val_start < 9 || strncmp(check - 9, "important", 9) != 0) return 0;
116
+ check -= 9;
117
+
118
+ while (check > val_start && IS_WHITESPACE(*(check - 1))) check--;
119
+
120
+ if (check <= val_start || *(check - 1) != '!') return 0;
121
+ check--;
122
+
123
+ *val_end = check;
124
+ return 1;
125
+ }
126
+
127
+ // Property/value/important spans found by parse_one_declaration(), in terms
128
+ // of offsets into the original CSS buffer - callers build whatever VALUEs
129
+ // (Declaration structs, error messages, etc.) they need from these.
130
+ struct declaration_span {
131
+ const char *prop_start;
132
+ const char *prop_end; // trimmed
133
+ const char *val_start;
134
+ const char *val_end; // trimmed; excludes a trailing '!important' marker
135
+ int is_important;
136
+ };
137
+
138
+ // Scans one "prop: value" declaration starting at *pos_ptr, stopping at
139
+ // `end` (never reads past it). On success, fills `span`, advances *pos_ptr
140
+ // past the terminating ';' (leaving it at a '}' or `end` if there wasn't
141
+ // one), and returns 1. On failure - no ':' found before a stop character -
142
+ // *pos_ptr is left at the stop character (or `end`) and 0 is returned,
143
+ // leaving recovery (skip-to-semicolon, raise, etc.) to the caller, since
144
+ // that differs by call site.
145
+ //
146
+ // stop_prop_scan_early: if true, ';' and '{' also terminate the property-name
147
+ // scan (used by the two block-oriented parsers, so a missing colon is
148
+ // detected without scanning past the declaration's boundary); if false,
149
+ // only ':' terminates it (used by the standalone declaration-list parser,
150
+ // whose input never contains braces).
151
+ //
152
+ // The value scan always tracks paren depth (so a ';' inside url(...) or
153
+ // rgba(...) doesn't end the value early) and always stops at an unguarded
154
+ // '}', which is harmless for callers whose `end` never contains one.
155
+ static inline int parse_one_declaration(const char **pos_ptr, const char *end,
156
+ int stop_prop_scan_early,
157
+ struct declaration_span *span) {
158
+ const char *pos = *pos_ptr;
159
+ const char *prop_start = pos;
160
+
161
+ if (stop_prop_scan_early) {
162
+ while (pos < end && *pos != ':' && *pos != ';' && *pos != '{') pos++;
163
+ } else {
164
+ while (pos < end && *pos != ':') pos++;
165
+ }
166
+
167
+ if (pos >= end || *pos != ':') {
168
+ *pos_ptr = pos;
169
+ return 0;
170
+ }
171
+
172
+ const char *prop_end = pos;
173
+ trim_trailing(prop_start, &prop_end);
174
+ trim_leading(&prop_start, prop_end);
175
+
176
+ pos++; // Skip ':'
177
+ while (pos < end && IS_WHITESPACE(*pos)) pos++;
178
+
179
+ const char *val_start = pos;
180
+ int paren_depth = 0;
181
+ while (pos < end && *pos != '}') {
182
+ if (*pos == '(') paren_depth++;
183
+ else if (*pos == ')') paren_depth--;
184
+ else if (*pos == ';' && paren_depth == 0) break;
185
+ pos++;
186
+ }
187
+ const char *val_end = pos;
188
+ trim_trailing(val_start, &val_end);
189
+
190
+ int is_important = extract_important(val_start, &val_end) ? 1 : 0;
191
+ trim_trailing(val_start, &val_end);
192
+
193
+ if (pos < end && *pos == ';') pos++;
194
+
195
+ span->prop_start = prop_start;
196
+ span->prop_end = prop_end;
197
+ span->val_start = val_start;
198
+ span->val_end = val_end;
199
+ span->is_important = is_important;
200
+
201
+ *pos_ptr = pos;
202
+ return 1;
203
+ }
204
+
91
205
  // Strip whitespace from both ends and return new string
92
206
  static inline VALUE strip_string(const char *str, long len) {
93
207
  const char *start = str;
@@ -157,21 +271,18 @@ void init_flatten_constants(void);
157
271
  // Specificity (specificity.c)
158
272
  VALUE calculate_specificity(VALUE self, VALUE selector);
159
273
 
160
- // Import scanner (import_scanner.c)
161
- VALUE extract_imports(VALUE self, VALUE css_string);
162
-
163
274
  // Shorthand expander (shorthand_expander_new.c)
164
275
  VALUE cataract_split_value(VALUE self, VALUE value);
165
- VALUE cataract_expand_margin(VALUE self, VALUE value);
166
- VALUE cataract_expand_padding(VALUE self, VALUE value);
167
- VALUE cataract_expand_border(VALUE self, VALUE value);
168
- VALUE cataract_expand_border_color(VALUE self, VALUE value);
169
- VALUE cataract_expand_border_style(VALUE self, VALUE value);
170
- VALUE cataract_expand_border_width(VALUE self, VALUE value);
171
- VALUE cataract_expand_border_side(VALUE self, VALUE side, VALUE value);
172
- VALUE cataract_expand_font(VALUE self, VALUE value);
173
- VALUE cataract_expand_list_style(VALUE self, VALUE value);
174
- VALUE cataract_expand_background(VALUE self, VALUE value);
276
+ VALUE cataract_expand_margin(VALUE self, VALUE value, VALUE important);
277
+ VALUE cataract_expand_padding(VALUE self, VALUE value, VALUE important);
278
+ VALUE cataract_expand_border(VALUE self, VALUE value, VALUE important);
279
+ VALUE cataract_expand_border_color(VALUE self, VALUE value, VALUE important);
280
+ VALUE cataract_expand_border_style(VALUE self, VALUE value, VALUE important);
281
+ VALUE cataract_expand_border_width(VALUE self, VALUE value, VALUE important);
282
+ VALUE cataract_expand_border_side(VALUE self, VALUE side, VALUE value, VALUE important);
283
+ VALUE cataract_expand_font(VALUE self, VALUE value, VALUE important);
284
+ VALUE cataract_expand_list_style(VALUE self, VALUE value, VALUE important);
285
+ VALUE cataract_expand_background(VALUE self, VALUE value, VALUE important);
175
286
  VALUE cataract_expand_shorthand(VALUE self, VALUE decl);
176
287
  VALUE cataract_create_margin_shorthand(VALUE self, VALUE properties);
177
288
  VALUE cataract_create_padding_shorthand(VALUE self, VALUE properties);