cataract 0.2.5 → 0.4.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/test.yml +6 -6
- data/.gitignore +17 -6
- data/.rubocop_todo.yml +11 -19
- data/BENCHMARKS.md +40 -40
- data/CHANGELOG.md +28 -1
- data/Gemfile +2 -2
- data/examples/css_analyzer/analyzer.rb +9 -3
- data/examples/css_analyzer/analyzers/base.rb +1 -1
- data/ext/cataract/cataract.c +312 -550
- data/ext/cataract/cataract.h +126 -16
- data/ext/cataract/css_parser.c +782 -806
- data/ext/cataract/extconf.rb +1 -2
- data/ext/cataract/flatten.c +279 -991
- data/ext/cataract/shorthand_expander.c +80 -102
- data/ext/cataract_color/color_conversion.c +1 -1
- data/lib/cataract/declarations.rb +26 -10
- data/lib/cataract/import_resolver.rb +36 -16
- data/lib/cataract/native.rb +30 -0
- data/lib/cataract/pure/byte_constants.rb +70 -67
- data/lib/cataract/pure/declarations.rb +125 -0
- data/lib/cataract/pure/flatten.rb +1195 -1182
- data/lib/cataract/pure/parser.rb +1721 -1652
- data/lib/cataract/pure/serializer.rb +575 -710
- data/lib/cataract/pure/specificity.rb +152 -175
- data/lib/cataract/pure.rb +73 -108
- data/lib/cataract/rule.rb +6 -3
- data/lib/cataract/stylesheet.rb +475 -415
- data/lib/cataract/version.rb +1 -1
- data/lib/cataract.rb +41 -30
- data/lib/tasks/profile.rake +6 -3
- metadata +4 -14
- data/ext/cataract/import_scanner.c +0 -174
- data/ext/cataract_old/cataract.c +0 -393
- data/ext/cataract_old/cataract.h +0 -250
- data/ext/cataract_old/css_parser.c +0 -933
- data/ext/cataract_old/extconf.rb +0 -67
- data/ext/cataract_old/import_scanner.c +0 -174
- data/ext/cataract_old/merge.c +0 -776
- data/ext/cataract_old/shorthand_expander.c +0 -902
- data/ext/cataract_old/specificity.c +0 -213
- data/ext/cataract_old/stylesheet.c +0 -290
- data/ext/cataract_old/value_splitter.c +0 -116
- data/lib/cataract/pure/helpers.rb +0 -35
data/ext/cataract/cataract.h
CHANGED
|
@@ -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;
|
|
@@ -148,7 +262,6 @@ static inline VALUE strip_string(const char *str, long len) {
|
|
|
148
262
|
// CSS parser (css_parser_new.c)
|
|
149
263
|
VALUE parse_css_new(int argc, VALUE *argv, VALUE self);
|
|
150
264
|
VALUE parse_css_new_impl(VALUE css_string, VALUE parser_options, int rule_id_offset);
|
|
151
|
-
VALUE parse_media_types(VALUE self, VALUE media_query_sym);
|
|
152
265
|
|
|
153
266
|
// Flatten (flatten.c)
|
|
154
267
|
VALUE cataract_flatten(VALUE self, VALUE rules_array);
|
|
@@ -157,21 +270,18 @@ void init_flatten_constants(void);
|
|
|
157
270
|
// Specificity (specificity.c)
|
|
158
271
|
VALUE calculate_specificity(VALUE self, VALUE selector);
|
|
159
272
|
|
|
160
|
-
// Import scanner (import_scanner.c)
|
|
161
|
-
VALUE extract_imports(VALUE self, VALUE css_string);
|
|
162
|
-
|
|
163
273
|
// Shorthand expander (shorthand_expander_new.c)
|
|
164
274
|
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);
|
|
275
|
+
VALUE cataract_expand_margin(VALUE self, VALUE value, VALUE important);
|
|
276
|
+
VALUE cataract_expand_padding(VALUE self, VALUE value, VALUE important);
|
|
277
|
+
VALUE cataract_expand_border(VALUE self, VALUE value, VALUE important);
|
|
278
|
+
VALUE cataract_expand_border_color(VALUE self, VALUE value, VALUE important);
|
|
279
|
+
VALUE cataract_expand_border_style(VALUE self, VALUE value, VALUE important);
|
|
280
|
+
VALUE cataract_expand_border_width(VALUE self, VALUE value, VALUE important);
|
|
281
|
+
VALUE cataract_expand_border_side(VALUE self, VALUE side, VALUE value, VALUE important);
|
|
282
|
+
VALUE cataract_expand_font(VALUE self, VALUE value, VALUE important);
|
|
283
|
+
VALUE cataract_expand_list_style(VALUE self, VALUE value, VALUE important);
|
|
284
|
+
VALUE cataract_expand_background(VALUE self, VALUE value, VALUE important);
|
|
175
285
|
VALUE cataract_expand_shorthand(VALUE self, VALUE decl);
|
|
176
286
|
VALUE cataract_create_margin_shorthand(VALUE self, VALUE properties);
|
|
177
287
|
VALUE cataract_create_padding_shorthand(VALUE self, VALUE properties);
|