cataract 0.4.0 → 0.5.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/.yardopts +9 -0
- data/CHANGELOG.md +8 -0
- data/ext/cataract/cataract.c +124 -11
- data/ext/cataract/cataract.h +13 -2
- data/ext/cataract/css_parser.c +298 -36
- data/ext/cataract/flatten.c +6 -2
- data/ext/cataract/specificity.c +13 -2
- data/lib/cataract/at_rule.rb +4 -2
- data/lib/cataract/conditional_group.rb +72 -0
- data/lib/cataract/native.rb +1 -0
- data/lib/cataract/pure/flatten.rb +7 -1
- data/lib/cataract/pure/parser.rb +266 -24
- data/lib/cataract/pure/serializer.rb +95 -8
- data/lib/cataract/pure/specificity.rb +10 -2
- data/lib/cataract/pure.rb +1 -0
- data/lib/cataract/rule.rb +8 -4
- data/lib/cataract/stylesheet.rb +67 -20
- data/lib/cataract/version.rb +1 -1
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4f107809adb744598338be592626fc5ebbfdb81c2813957c7e5ed1652f37a607
|
|
4
|
+
data.tar.gz: 810a6aadbe0a8c2ce4eff7c307c17c9de354f1a3bc0d9509ae4e83f1d7e1c8b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b7e85ed2f9ad0b9154e78c795bc0548ca1eaeb55f8f24b2b644852394a506173afb64042f55a3c02c13c21e1b539738695a83c8f774aaf0311bdda8f00da42b9
|
|
7
|
+
data.tar.gz: f6ea7361ad3d180aaf9e4faa72bf686906a0f81345df59f70856734e50f17b79d4dc20823d0fae520279767cd289fb8e42bbd619230f095d1d26f9ed95aa1094
|
data/.yardopts
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [0.5.0] - 2026-07-09
|
|
2
|
+
|
|
3
|
+
- Feature: `@supports (condition) { ... }` now preserves its condition and the rules it wraps through parse -> serialize, in both backends - previously the condition was discarded entirely and the wrapped rules were silently flattened into the surrounding document with no trace of ever being conditional.
|
|
4
|
+
- Feature: `@container name (condition) { ... }` (container queries) now preserves its name, condition, and wrapped rules the same way - handles named, anonymous, and name-only forms, and nests correctly with `@media`/`@supports`/itself.
|
|
5
|
+
- Feature: `@layer` (cascade layers) now preserves its name and wrapped rules, both in block form (`@layer name { ... }`, including anonymous and dotted/nested names like `framework.layout`) and statement form (`@layer a, b;`, which declares layer order with no wrapped rules at all - previously silently corrupted parsing of whatever rule came right after it).
|
|
6
|
+
- Fix: `@media`/`@supports`/`@container`/`@scope`/`@layer` with no whitespace before a following `(` (e.g. minified `@supports(display:grid){...}`) no longer misparses the at-rule name, which silently corrupted the rest of the block. Present in both backends since `@media`/`@supports` shipped.
|
|
7
|
+
- Feature: `@namespace` (default and prefixed, e.g. `@namespace svg url(http://www.w3.org/2000/svg);`) is now preserved through parse -> serialize, in both backends - previously it wasn't modelled at all. Namespaced selectors (`ns|E`, `*|E`, `|E`, and the attribute-selector equivalents) already parsed as opaque text, but their specificity was miscounted - a namespace prefix was counted as its own type selector instead of contributing nothing, e.g. `svg|rect` computed as specificity 2 instead of 1. Both are fixed now.
|
|
8
|
+
|
|
1
9
|
## [0.4.0] - 2026-07-08
|
|
2
10
|
|
|
3
11
|
- Fix: `Declarations.new(some_string)` (standalone CSS declaration-block parsing) now works under the pure Ruby backend (`CATARACT_PURE=1`) - previously raised `NoMethodError`.
|
data/ext/cataract/cataract.c
CHANGED
|
@@ -9,6 +9,7 @@ VALUE cAtRule;
|
|
|
9
9
|
VALUE cStylesheet;
|
|
10
10
|
VALUE cImportStatement;
|
|
11
11
|
VALUE cMediaQuery;
|
|
12
|
+
VALUE cConditionalGroup;
|
|
12
13
|
|
|
13
14
|
// Error class definitions (shared with main extension)
|
|
14
15
|
VALUE eCataractError;
|
|
@@ -168,6 +169,13 @@ static void serialize_at_rule(VALUE result, VALUE at_rule) {
|
|
|
168
169
|
VALUE selector = rb_struct_aref(at_rule, INT2FIX(AT_RULE_SELECTOR));
|
|
169
170
|
VALUE content = rb_struct_aref(at_rule, INT2FIX(AT_RULE_CONTENT));
|
|
170
171
|
|
|
172
|
+
if (NIL_P(content)) {
|
|
173
|
+
// Statement form (e.g. `@layer a, b;`) - no block to wrap.
|
|
174
|
+
rb_str_append(result, selector);
|
|
175
|
+
rb_str_cat2(result, ";\n");
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
171
179
|
rb_str_append(result, selector);
|
|
172
180
|
rb_str_cat2(result, " {\n");
|
|
173
181
|
|
|
@@ -277,6 +285,14 @@ static void serialize_at_rule_formatted(VALUE result, VALUE at_rule, const char
|
|
|
277
285
|
VALUE selector = rb_struct_aref(at_rule, INT2FIX(AT_RULE_SELECTOR));
|
|
278
286
|
VALUE content = rb_struct_aref(at_rule, INT2FIX(AT_RULE_CONTENT));
|
|
279
287
|
|
|
288
|
+
if (NIL_P(content)) {
|
|
289
|
+
// Statement form (e.g. `@layer a, b;`) - no block to wrap.
|
|
290
|
+
rb_str_cat2(result, indent);
|
|
291
|
+
rb_str_append(result, selector);
|
|
292
|
+
rb_str_cat2(result, ";\n");
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
|
|
280
296
|
rb_str_cat2(result, indent);
|
|
281
297
|
rb_str_append(result, selector);
|
|
282
298
|
rb_str_cat2(result, " {\n");
|
|
@@ -408,6 +424,77 @@ static VALUE build_rules_by_id(VALUE rules_array) {
|
|
|
408
424
|
return rules_by_id;
|
|
409
425
|
}
|
|
410
426
|
|
|
427
|
+
// A rule's conditional-group wrapping chain, outermost first, found by
|
|
428
|
+
// walking parent_id from its own conditional_group_id up to the root. Only
|
|
429
|
+
// @supports currently populates conditional_group_id (see the parser), but
|
|
430
|
+
// this walks whatever's there generically.
|
|
431
|
+
static VALUE conditional_group_chain(VALUE conditional_groups, VALUE conditional_group_id) {
|
|
432
|
+
VALUE chain = rb_ary_new();
|
|
433
|
+
VALUE id = conditional_group_id;
|
|
434
|
+
while (!NIL_P(id)) {
|
|
435
|
+
VALUE group = rb_ary_entry(conditional_groups, FIX2INT(id));
|
|
436
|
+
if (NIL_P(group)) break;
|
|
437
|
+
|
|
438
|
+
rb_ary_unshift(chain, group);
|
|
439
|
+
id = rb_struct_aref(group, INT2FIX(CONDITIONAL_GROUP_PARENT_ID));
|
|
440
|
+
}
|
|
441
|
+
return chain;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Reconcile the currently-open conditional-group blocks with the ones a
|
|
445
|
+
// rule needs, like diffing two paths down a tree: close whatever's open
|
|
446
|
+
// past where the chains diverge (innermost first), then open whatever the
|
|
447
|
+
// target chain adds from that point on. Nested entirely inside whatever
|
|
448
|
+
// media block is currently open (conditional groups don't affect media
|
|
449
|
+
// context). Returns target_chain, for the caller to track as current.
|
|
450
|
+
static VALUE sync_conditional_group_chain(VALUE result, VALUE current_chain, VALUE target_chain, const char *indent) {
|
|
451
|
+
long current_len = RARRAY_LEN(current_chain);
|
|
452
|
+
long target_len = RARRAY_LEN(target_chain);
|
|
453
|
+
long common = 0;
|
|
454
|
+
while (common < current_len && common < target_len) {
|
|
455
|
+
VALUE cur_id = rb_struct_aref(rb_ary_entry(current_chain, common), INT2FIX(CONDITIONAL_GROUP_ID));
|
|
456
|
+
VALUE tgt_id = rb_struct_aref(rb_ary_entry(target_chain, common), INT2FIX(CONDITIONAL_GROUP_ID));
|
|
457
|
+
if (!rb_equal(cur_id, tgt_id)) break;
|
|
458
|
+
|
|
459
|
+
common++;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
for (long i = current_len - 1; i >= common; i--) {
|
|
463
|
+
rb_str_cat2(result, indent);
|
|
464
|
+
rb_str_cat2(result, "}\n");
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
for (long i = common; i < target_len; i++) {
|
|
468
|
+
VALUE group = rb_ary_entry(target_chain, i);
|
|
469
|
+
VALUE name = rb_struct_aref(group, INT2FIX(CONDITIONAL_GROUP_NAME));
|
|
470
|
+
VALUE condition = rb_struct_aref(group, INT2FIX(CONDITIONAL_GROUP_CONDITION));
|
|
471
|
+
|
|
472
|
+
rb_str_cat2(result, indent);
|
|
473
|
+
rb_str_cat2(result, "@");
|
|
474
|
+
rb_str_append(result, rb_sym2str(rb_struct_aref(group, INT2FIX(CONDITIONAL_GROUP_TYPE))));
|
|
475
|
+
if (!NIL_P(name) || !NIL_P(condition)) {
|
|
476
|
+
rb_str_cat2(result, " ");
|
|
477
|
+
if (!NIL_P(name)) {
|
|
478
|
+
rb_str_append(result, name);
|
|
479
|
+
if (!NIL_P(condition)) rb_str_cat2(result, " ");
|
|
480
|
+
}
|
|
481
|
+
if (!NIL_P(condition)) {
|
|
482
|
+
rb_str_append(result, condition);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
rb_str_cat2(result, " {\n");
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
return target_chain;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
static void close_conditional_groups(VALUE result, long count, const char *indent) {
|
|
492
|
+
for (long i = 0; i < count; i++) {
|
|
493
|
+
rb_str_cat2(result, indent);
|
|
494
|
+
rb_str_cat2(result, "}\n");
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
411
498
|
// Rule and AtRule don't share a member layout past their first few fields
|
|
412
499
|
// (see the AT_RULE_* comment in cataract.h), so reading parent_rule_id or
|
|
413
500
|
// media_query_id off a rule of unknown type needs to dispatch on which
|
|
@@ -425,6 +512,12 @@ static inline VALUE rule_media_query_id_of(VALUE rule) {
|
|
|
425
512
|
: rb_struct_aref(rule, INT2FIX(RULE_MEDIA_QUERY_ID));
|
|
426
513
|
}
|
|
427
514
|
|
|
515
|
+
static inline VALUE rule_conditional_group_id_of(VALUE rule) {
|
|
516
|
+
return rb_obj_is_kind_of(rule, cAtRule)
|
|
517
|
+
? rb_struct_aref(rule, INT2FIX(AT_RULE_CONDITIONAL_GROUP_ID))
|
|
518
|
+
: rb_struct_aref(rule, INT2FIX(RULE_CONDITIONAL_GROUP_ID));
|
|
519
|
+
}
|
|
520
|
+
|
|
428
521
|
// Formatting options for stylesheet serialization
|
|
429
522
|
// Avoids mode flags and if/else branches - all behavior controlled by struct values
|
|
430
523
|
struct format_opts {
|
|
@@ -564,6 +657,7 @@ static VALUE serialize_stylesheet_with_grouping(
|
|
|
564
657
|
VALUE media_query_lists,
|
|
565
658
|
VALUE result,
|
|
566
659
|
VALUE selector_lists,
|
|
660
|
+
VALUE conditional_groups,
|
|
567
661
|
const struct format_opts *opts
|
|
568
662
|
) {
|
|
569
663
|
long total_rules = RARRAY_LEN(rules_array);
|
|
@@ -589,6 +683,7 @@ static VALUE serialize_stylesheet_with_grouping(
|
|
|
589
683
|
// Iterate through rules in insertion order, grouping consecutive media queries
|
|
590
684
|
VALUE current_media = Qnil;
|
|
591
685
|
int in_media_block = 0;
|
|
686
|
+
VALUE current_cg_chain = rb_ary_new();
|
|
592
687
|
|
|
593
688
|
for (long i = 0; i < total_rules; i++) {
|
|
594
689
|
VALUE rule = rb_ary_entry(rules_array, i);
|
|
@@ -606,10 +701,12 @@ static VALUE serialize_stylesheet_with_grouping(
|
|
|
606
701
|
rule_media = rb_ary_entry(media_queries, FIX2INT(rule_media_query_id));
|
|
607
702
|
}
|
|
608
703
|
int is_first_rule = (i == 0);
|
|
704
|
+
VALUE rule_cg_chain = conditional_group_chain(conditional_groups, rule_conditional_group_id_of(rule));
|
|
609
705
|
|
|
610
706
|
if (NIL_P(rule_media)) {
|
|
611
707
|
// Not in any media query - close any open media block first
|
|
612
708
|
if (in_media_block) {
|
|
709
|
+
current_cg_chain = sync_conditional_group_chain(result, current_cg_chain, rb_ary_new(), opts->media_indent);
|
|
613
710
|
rb_str_cat2(result, "}\n");
|
|
614
711
|
in_media_block = 0;
|
|
615
712
|
current_media = Qnil;
|
|
@@ -620,11 +717,15 @@ static VALUE serialize_stylesheet_with_grouping(
|
|
|
620
717
|
rb_str_cat2(result, "\n");
|
|
621
718
|
}
|
|
622
719
|
|
|
623
|
-
|
|
720
|
+
current_cg_chain = sync_conditional_group_chain(result, current_cg_chain, rule_cg_chain, "");
|
|
721
|
+
|
|
722
|
+
serialize_rule_in_group(result, rule, rule_id, rule_media_query_id, &group_ctx, RARRAY_LEN(current_cg_chain) > 0);
|
|
624
723
|
} else {
|
|
625
724
|
// This rule is in a media query
|
|
626
725
|
// Check if media query changed from previous rule (compare MediaQuery objects by value)
|
|
627
726
|
if (NIL_P(current_media) || !rb_equal(current_media, rule_media)) {
|
|
727
|
+
current_cg_chain = sync_conditional_group_chain(result, current_cg_chain, rb_ary_new(), opts->media_indent);
|
|
728
|
+
|
|
628
729
|
// Close previous media block if open
|
|
629
730
|
if (in_media_block) {
|
|
630
731
|
rb_str_cat2(result, "}\n");
|
|
@@ -648,19 +749,23 @@ static VALUE serialize_stylesheet_with_grouping(
|
|
|
648
749
|
in_media_block = 1;
|
|
649
750
|
}
|
|
650
751
|
|
|
752
|
+
current_cg_chain = sync_conditional_group_chain(result, current_cg_chain, rule_cg_chain, opts->media_indent);
|
|
753
|
+
|
|
651
754
|
serialize_rule_in_group(result, rule, rule_id, rule_media_query_id, &group_ctx, 1);
|
|
652
755
|
}
|
|
653
756
|
}
|
|
654
757
|
|
|
655
|
-
// Close final media
|
|
758
|
+
// Close final conditional-group and media blocks if still open
|
|
759
|
+
close_conditional_groups(result, RARRAY_LEN(current_cg_chain), in_media_block ? opts->media_indent : "");
|
|
656
760
|
if (in_media_block) {
|
|
657
761
|
rb_str_cat2(result, "}\n");
|
|
658
762
|
}
|
|
659
763
|
|
|
660
|
-
// Guard hash objects we created and used throughout
|
|
764
|
+
// Guard hash/array objects we created and used throughout
|
|
661
765
|
RB_GC_GUARD(mq_id_to_list_id);
|
|
662
766
|
RB_GC_GUARD(rules_by_id);
|
|
663
767
|
RB_GC_GUARD(processed_rule_ids);
|
|
768
|
+
RB_GC_GUARD(current_cg_chain);
|
|
664
769
|
return result;
|
|
665
770
|
}
|
|
666
771
|
|
|
@@ -1010,11 +1115,12 @@ static VALUE serialize_stylesheet_with_nesting(
|
|
|
1010
1115
|
// this, differing only in which format_opts they select. Dispatches on has_nesting
|
|
1011
1116
|
// to pick the selector-list-grouping serializer (no nesting - zero overhead) or the
|
|
1012
1117
|
// parent/child lookahead serializer (has nesting).
|
|
1013
|
-
static VALUE stylesheet_serialize_impl(VALUE rules_array, VALUE charset, VALUE has_nesting, VALUE selector_lists, VALUE media_queries, VALUE media_query_lists, int formatted) {
|
|
1118
|
+
static VALUE stylesheet_serialize_impl(VALUE rules_array, VALUE charset, VALUE has_nesting, VALUE selector_lists, VALUE media_queries, VALUE media_query_lists, VALUE conditional_groups, int formatted) {
|
|
1014
1119
|
Check_Type(rules_array, T_ARRAY);
|
|
1015
1120
|
Check_Type(media_queries, T_ARRAY);
|
|
1016
1121
|
if (!NIL_P(media_query_lists)) Check_Type(media_query_lists, T_HASH);
|
|
1017
1122
|
if (!NIL_P(selector_lists)) Check_Type(selector_lists, T_HASH);
|
|
1123
|
+
if (!NIL_P(conditional_groups)) Check_Type(conditional_groups, T_ARRAY);
|
|
1018
1124
|
|
|
1019
1125
|
VALUE result = rb_str_new_cstr("");
|
|
1020
1126
|
|
|
@@ -1048,22 +1154,23 @@ static VALUE stylesheet_serialize_impl(VALUE rules_array, VALUE charset, VALUE h
|
|
|
1048
1154
|
|
|
1049
1155
|
// Fast path: if no nesting, use the selector-list-grouping serializer (zero overhead)
|
|
1050
1156
|
if (!RTEST(has_nesting)) {
|
|
1051
|
-
return serialize_stylesheet_with_grouping(rules_array, media_queries, media_query_lists, result, selector_lists, &opts);
|
|
1157
|
+
return serialize_stylesheet_with_grouping(rules_array, media_queries, media_query_lists, result, selector_lists, conditional_groups, &opts);
|
|
1052
1158
|
}
|
|
1053
1159
|
|
|
1054
1160
|
// Has nesting - use the parent/child lookahead serializer
|
|
1055
1161
|
// TODO: Phase 2 - use selector_lists for grouping on the nesting path too
|
|
1162
|
+
// TODO: conditional_groups (@supports etc.) aren't reconstructed on this path yet
|
|
1056
1163
|
return serialize_stylesheet_with_nesting(rules_array, media_queries, media_query_lists, result, &opts);
|
|
1057
1164
|
}
|
|
1058
1165
|
|
|
1059
1166
|
// New stylesheet serialization entry point - checks for nesting and delegates
|
|
1060
|
-
static VALUE stylesheet_to_s(VALUE self, VALUE rules_array, VALUE charset, VALUE has_nesting, VALUE selector_lists, VALUE media_queries, VALUE media_query_lists) {
|
|
1061
|
-
return stylesheet_serialize_impl(rules_array, charset, has_nesting, selector_lists, media_queries, media_query_lists, 0);
|
|
1167
|
+
static VALUE stylesheet_to_s(VALUE self, VALUE rules_array, VALUE charset, VALUE has_nesting, VALUE selector_lists, VALUE media_queries, VALUE media_query_lists, VALUE conditional_groups) {
|
|
1168
|
+
return stylesheet_serialize_impl(rules_array, charset, has_nesting, selector_lists, media_queries, media_query_lists, conditional_groups, 0);
|
|
1062
1169
|
}
|
|
1063
1170
|
|
|
1064
1171
|
// Formatted version with indentation and newlines (with nesting support)
|
|
1065
|
-
static VALUE stylesheet_to_formatted_s(VALUE self, VALUE rules_array, VALUE charset, VALUE has_nesting, VALUE selector_lists, VALUE media_queries, VALUE media_query_lists) {
|
|
1066
|
-
return stylesheet_serialize_impl(rules_array, charset, has_nesting, selector_lists, media_queries, media_query_lists, 1);
|
|
1172
|
+
static VALUE stylesheet_to_formatted_s(VALUE self, VALUE rules_array, VALUE charset, VALUE has_nesting, VALUE selector_lists, VALUE media_queries, VALUE media_query_lists, VALUE conditional_groups) {
|
|
1173
|
+
return stylesheet_serialize_impl(rules_array, charset, has_nesting, selector_lists, media_queries, media_query_lists, conditional_groups, 1);
|
|
1067
1174
|
}
|
|
1068
1175
|
|
|
1069
1176
|
/*
|
|
@@ -1207,6 +1314,12 @@ void Init_native_extension(void) {
|
|
|
1207
1314
|
rb_raise(rb_eLoadError, "Cataract::MediaQuery not defined. Do not require 'cataract/native_extension' directly, use require 'cataract'");
|
|
1208
1315
|
}
|
|
1209
1316
|
|
|
1317
|
+
if (rb_const_defined(mCataract, rb_intern("ConditionalGroup"))) {
|
|
1318
|
+
cConditionalGroup = rb_const_get(mCataract, rb_intern("ConditionalGroup"));
|
|
1319
|
+
} else {
|
|
1320
|
+
rb_raise(rb_eLoadError, "Cataract::ConditionalGroup not defined. Do not require 'cataract/native_extension' directly, use require 'cataract'");
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1210
1323
|
// Define Stylesheet class (Ruby will add instance methods like each_selector).
|
|
1211
1324
|
// Declarations is left alone here - it's a plain Ruby class (declarations.rb)
|
|
1212
1325
|
// with its own #to_s, not something this backend attaches methods to.
|
|
@@ -1219,8 +1332,8 @@ void Init_native_extension(void) {
|
|
|
1219
1332
|
VALUE mNative = rb_define_module_under(mBackends, "Native");
|
|
1220
1333
|
|
|
1221
1334
|
rb_define_module_function(mNative, "parse", parse_css_new, -1);
|
|
1222
|
-
rb_define_module_function(mNative, "stylesheet_to_s", stylesheet_to_s,
|
|
1223
|
-
rb_define_module_function(mNative, "stylesheet_to_formatted_s", stylesheet_to_formatted_s,
|
|
1335
|
+
rb_define_module_function(mNative, "stylesheet_to_s", stylesheet_to_s, 7);
|
|
1336
|
+
rb_define_module_function(mNative, "stylesheet_to_formatted_s", stylesheet_to_formatted_s, 7);
|
|
1224
1337
|
rb_define_module_function(mNative, "parse_declarations", new_parse_declarations, 1);
|
|
1225
1338
|
rb_define_module_function(mNative, "flatten", cataract_flatten, 1);
|
|
1226
1339
|
rb_define_module_function(mNative, "calculate_specificity", calculate_specificity, 1);
|
data/ext/cataract/cataract.h
CHANGED
|
@@ -14,6 +14,7 @@ extern VALUE cAtRule;
|
|
|
14
14
|
extern VALUE cStylesheet;
|
|
15
15
|
extern VALUE cImportStatement;
|
|
16
16
|
extern VALUE cMediaQuery;
|
|
17
|
+
extern VALUE cConditionalGroup;
|
|
17
18
|
|
|
18
19
|
// Error class references
|
|
19
20
|
extern VALUE eCataractError;
|
|
@@ -25,7 +26,7 @@ extern VALUE eParseError;
|
|
|
25
26
|
// Struct field indices
|
|
26
27
|
// ============================================================================
|
|
27
28
|
|
|
28
|
-
// Rule struct field indices (id, selector, declarations, specificity, parent_rule_id, nesting_style, selector_list_id, media_query_id)
|
|
29
|
+
// Rule struct field indices (id, selector, declarations, specificity, parent_rule_id, nesting_style, selector_list_id, media_query_id, conditional_group_id)
|
|
29
30
|
#define RULE_ID 0
|
|
30
31
|
#define RULE_SELECTOR 1
|
|
31
32
|
#define RULE_DECLARATIONS 2
|
|
@@ -34,6 +35,7 @@ extern VALUE eParseError;
|
|
|
34
35
|
#define RULE_NESTING_STYLE 5
|
|
35
36
|
#define RULE_SELECTOR_LIST_ID 6
|
|
36
37
|
#define RULE_MEDIA_QUERY_ID 7
|
|
38
|
+
#define RULE_CONDITIONAL_GROUP_ID 8
|
|
37
39
|
|
|
38
40
|
// Nesting style constants
|
|
39
41
|
#define NESTING_STYLE_IMPLICIT 0 // .parent { .child { } } - no &
|
|
@@ -45,13 +47,14 @@ extern VALUE eParseError;
|
|
|
45
47
|
#define NO_PARENT_SELECTOR Qnil
|
|
46
48
|
#define NO_PARENT_RULE_ID Qnil
|
|
47
49
|
#define NO_MEDIA_QUERY_ID (-1)
|
|
50
|
+
#define NO_CONDITIONAL_GROUP_ID (-1)
|
|
48
51
|
|
|
49
52
|
// Declaration struct field indices (property, value, important)
|
|
50
53
|
#define DECL_PROPERTY 0
|
|
51
54
|
#define DECL_VALUE 1
|
|
52
55
|
#define DECL_IMPORTANT 2
|
|
53
56
|
|
|
54
|
-
// AtRule struct field indices (id, selector, content, specificity, media_query_id)
|
|
57
|
+
// AtRule struct field indices (id, selector, content, specificity, media_query_id, conditional_group_id)
|
|
55
58
|
// Matches Rule interface for duck-typing, but AtRule has fewer members - its
|
|
56
59
|
// indices do NOT line up with Rule's past AT_RULE_SPECIFICITY (e.g. index 4
|
|
57
60
|
// is media_query_id here but parent_rule_id on Rule), so never read a field
|
|
@@ -61,6 +64,14 @@ extern VALUE eParseError;
|
|
|
61
64
|
#define AT_RULE_CONTENT 2
|
|
62
65
|
#define AT_RULE_SPECIFICITY 3
|
|
63
66
|
#define AT_RULE_MEDIA_QUERY_ID 4
|
|
67
|
+
#define AT_RULE_CONDITIONAL_GROUP_ID 5
|
|
68
|
+
|
|
69
|
+
// ConditionalGroup struct field indices (id, type, name, condition, parent_id)
|
|
70
|
+
#define CONDITIONAL_GROUP_ID 0
|
|
71
|
+
#define CONDITIONAL_GROUP_TYPE 1
|
|
72
|
+
#define CONDITIONAL_GROUP_NAME 2
|
|
73
|
+
#define CONDITIONAL_GROUP_CONDITION 3
|
|
74
|
+
#define CONDITIONAL_GROUP_PARENT_ID 4
|
|
64
75
|
|
|
65
76
|
// ============================================================================
|
|
66
77
|
// Macros
|