sassc 2.1.0.pre3 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/CHANGELOG.md +24 -0
  4. data/Rakefile +2 -4
  5. data/ext/extconf.rb +13 -5
  6. data/ext/libsass/VERSION +1 -1
  7. data/ext/libsass/include/sass/base.h +2 -1
  8. data/ext/libsass/include/sass/context.h +4 -0
  9. data/ext/libsass/src/MurmurHash2.hpp +91 -0
  10. data/ext/libsass/src/ast.cpp +158 -168
  11. data/ext/libsass/src/ast.hpp +389 -230
  12. data/ext/libsass/src/ast_def_macros.hpp +18 -10
  13. data/ext/libsass/src/ast_fwd_decl.cpp +4 -3
  14. data/ext/libsass/src/ast_fwd_decl.hpp +98 -165
  15. data/ext/libsass/src/ast_helpers.hpp +292 -0
  16. data/ext/libsass/src/ast_sel_cmp.cpp +219 -732
  17. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  18. data/ext/libsass/src/ast_sel_unify.cpp +207 -212
  19. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  20. data/ext/libsass/src/ast_selectors.cpp +594 -1026
  21. data/ext/libsass/src/ast_selectors.hpp +339 -385
  22. data/ext/libsass/src/ast_supports.cpp +36 -52
  23. data/ext/libsass/src/ast_supports.hpp +29 -29
  24. data/ext/libsass/src/ast_values.cpp +271 -84
  25. data/ext/libsass/src/ast_values.hpp +116 -107
  26. data/ext/libsass/src/backtrace.cpp +9 -9
  27. data/ext/libsass/src/backtrace.hpp +5 -5
  28. data/ext/libsass/src/base64vlq.cpp +2 -2
  29. data/ext/libsass/src/base64vlq.hpp +1 -1
  30. data/ext/libsass/src/bind.cpp +18 -18
  31. data/ext/libsass/src/bind.hpp +1 -1
  32. data/ext/libsass/src/c2ast.cpp +3 -3
  33. data/ext/libsass/src/c2ast.hpp +1 -1
  34. data/ext/libsass/src/cencode.c +4 -6
  35. data/ext/libsass/src/check_nesting.cpp +40 -41
  36. data/ext/libsass/src/check_nesting.hpp +6 -2
  37. data/ext/libsass/src/color_maps.cpp +14 -13
  38. data/ext/libsass/src/color_maps.hpp +1 -9
  39. data/ext/libsass/src/constants.cpp +5 -0
  40. data/ext/libsass/src/constants.hpp +6 -0
  41. data/ext/libsass/src/context.cpp +92 -119
  42. data/ext/libsass/src/context.hpp +41 -53
  43. data/ext/libsass/src/cssize.cpp +66 -149
  44. data/ext/libsass/src/cssize.hpp +17 -23
  45. data/ext/libsass/src/dart_helpers.hpp +199 -0
  46. data/ext/libsass/src/debugger.hpp +451 -295
  47. data/ext/libsass/src/emitter.cpp +15 -16
  48. data/ext/libsass/src/emitter.hpp +10 -12
  49. data/ext/libsass/src/environment.cpp +27 -27
  50. data/ext/libsass/src/environment.hpp +29 -24
  51. data/ext/libsass/src/error_handling.cpp +62 -41
  52. data/ext/libsass/src/error_handling.hpp +61 -51
  53. data/ext/libsass/src/eval.cpp +167 -281
  54. data/ext/libsass/src/eval.hpp +27 -29
  55. data/ext/libsass/src/eval_selectors.cpp +75 -0
  56. data/ext/libsass/src/expand.cpp +275 -222
  57. data/ext/libsass/src/expand.hpp +36 -16
  58. data/ext/libsass/src/extender.cpp +1188 -0
  59. data/ext/libsass/src/extender.hpp +399 -0
  60. data/ext/libsass/src/extension.cpp +43 -0
  61. data/ext/libsass/src/extension.hpp +89 -0
  62. data/ext/libsass/src/file.cpp +81 -72
  63. data/ext/libsass/src/file.hpp +28 -37
  64. data/ext/libsass/src/fn_colors.cpp +20 -18
  65. data/ext/libsass/src/fn_lists.cpp +30 -29
  66. data/ext/libsass/src/fn_maps.cpp +3 -3
  67. data/ext/libsass/src/fn_miscs.cpp +34 -46
  68. data/ext/libsass/src/fn_numbers.cpp +20 -13
  69. data/ext/libsass/src/fn_selectors.cpp +98 -128
  70. data/ext/libsass/src/fn_strings.cpp +47 -33
  71. data/ext/libsass/src/fn_utils.cpp +31 -29
  72. data/ext/libsass/src/fn_utils.hpp +17 -11
  73. data/ext/libsass/src/inspect.cpp +186 -148
  74. data/ext/libsass/src/inspect.hpp +31 -29
  75. data/ext/libsass/src/lexer.cpp +20 -82
  76. data/ext/libsass/src/lexer.hpp +5 -16
  77. data/ext/libsass/src/listize.cpp +23 -37
  78. data/ext/libsass/src/listize.hpp +8 -9
  79. data/ext/libsass/src/mapping.hpp +1 -0
  80. data/ext/libsass/src/memory.hpp +12 -0
  81. data/ext/libsass/src/memory/allocator.cpp +48 -0
  82. data/ext/libsass/src/memory/allocator.hpp +138 -0
  83. data/ext/libsass/src/memory/config.hpp +20 -0
  84. data/ext/libsass/src/memory/memory_pool.hpp +186 -0
  85. data/ext/libsass/src/memory/{SharedPtr.cpp → shared_ptr.cpp} +2 -2
  86. data/ext/libsass/src/memory/{SharedPtr.hpp → shared_ptr.hpp} +55 -9
  87. data/ext/libsass/src/operation.hpp +71 -61
  88. data/ext/libsass/src/operators.cpp +19 -18
  89. data/ext/libsass/src/operators.hpp +11 -11
  90. data/ext/libsass/src/ordered_map.hpp +112 -0
  91. data/ext/libsass/src/output.cpp +45 -64
  92. data/ext/libsass/src/output.hpp +6 -6
  93. data/ext/libsass/src/parser.cpp +512 -700
  94. data/ext/libsass/src/parser.hpp +89 -97
  95. data/ext/libsass/src/parser_selectors.cpp +189 -0
  96. data/ext/libsass/src/permutate.hpp +164 -0
  97. data/ext/libsass/src/plugins.cpp +7 -7
  98. data/ext/libsass/src/plugins.hpp +8 -8
  99. data/ext/libsass/src/position.cpp +7 -26
  100. data/ext/libsass/src/position.hpp +44 -21
  101. data/ext/libsass/src/prelexer.cpp +6 -6
  102. data/ext/libsass/src/remove_placeholders.cpp +55 -56
  103. data/ext/libsass/src/remove_placeholders.hpp +21 -18
  104. data/ext/libsass/src/sass.cpp +16 -15
  105. data/ext/libsass/src/sass.hpp +10 -5
  106. data/ext/libsass/src/sass2scss.cpp +4 -4
  107. data/ext/libsass/src/sass_context.cpp +91 -122
  108. data/ext/libsass/src/sass_context.hpp +2 -2
  109. data/ext/libsass/src/sass_functions.cpp +1 -1
  110. data/ext/libsass/src/sass_values.cpp +8 -11
  111. data/ext/libsass/src/settings.hpp +19 -0
  112. data/ext/libsass/src/source.cpp +69 -0
  113. data/ext/libsass/src/source.hpp +95 -0
  114. data/ext/libsass/src/source_data.hpp +32 -0
  115. data/ext/libsass/src/source_map.cpp +22 -18
  116. data/ext/libsass/src/source_map.hpp +12 -9
  117. data/ext/libsass/src/stylesheet.cpp +22 -0
  118. data/ext/libsass/src/stylesheet.hpp +57 -0
  119. data/ext/libsass/src/to_value.cpp +2 -2
  120. data/ext/libsass/src/to_value.hpp +1 -1
  121. data/ext/libsass/src/units.cpp +24 -22
  122. data/ext/libsass/src/units.hpp +8 -8
  123. data/ext/libsass/src/utf8_string.cpp +9 -10
  124. data/ext/libsass/src/utf8_string.hpp +7 -6
  125. data/ext/libsass/src/util.cpp +48 -50
  126. data/ext/libsass/src/util.hpp +20 -21
  127. data/ext/libsass/src/util_string.cpp +111 -61
  128. data/ext/libsass/src/util_string.hpp +62 -8
  129. data/ext/libsass/src/values.cpp +12 -12
  130. data/lib/sassc/engine.rb +5 -3
  131. data/lib/sassc/functions_handler.rb +11 -13
  132. data/lib/sassc/native.rb +9 -7
  133. data/lib/sassc/script.rb +4 -6
  134. data/lib/sassc/version.rb +1 -1
  135. data/test/functions_test.rb +38 -1
  136. data/test/native_test.rb +4 -4
  137. metadata +31 -18
  138. data/ext/libsass/src/extend.cpp +0 -2132
  139. data/ext/libsass/src/extend.hpp +0 -86
  140. data/ext/libsass/src/node.cpp +0 -322
  141. data/ext/libsass/src/node.hpp +0 -118
  142. data/ext/libsass/src/paths.hpp +0 -71
  143. data/ext/libsass/src/sass_util.cpp +0 -152
  144. data/ext/libsass/src/sass_util.hpp +0 -256
  145. data/ext/libsass/src/subset_map.cpp +0 -58
  146. data/ext/libsass/src/subset_map.hpp +0 -76
  147. data/lib/sassc/native/lib_c.rb +0 -21
@@ -19,7 +19,18 @@ namespace Sass {
19
19
  public:
20
20
 
21
21
  Env* environment();
22
- Selector_List_Obj selector();
22
+ SelectorListObj& selector();
23
+ SelectorListObj& original();
24
+ SelectorListObj popFromSelectorStack();
25
+ SelectorStack getOriginalStack();
26
+ SelectorStack getSelectorStack();
27
+ void pushNullSelector();
28
+ void popNullSelector();
29
+ void pushToSelectorStack(SelectorListObj selector);
30
+
31
+ SelectorListObj popFromOriginalStack();
32
+
33
+ void pushToOriginalStack(SelectorListObj selector);
23
34
 
24
35
  Context& ctx;
25
36
  Backtraces& traces;
@@ -33,38 +44,47 @@ namespace Sass {
33
44
  EnvStack env_stack;
34
45
  BlockStack block_stack;
35
46
  CallStack call_stack;
47
+ private:
36
48
  SelectorStack selector_stack;
37
- MediaStack media_stack;
49
+ public:
50
+ SelectorStack originalStack;
51
+ MediaStack mediaStack;
38
52
 
39
53
  Boolean_Obj bool_true;
40
54
 
41
55
  private:
42
- void expand_selector_list(Selector_Obj, Selector_List_Obj extender);
56
+
57
+ sass::vector<CssMediaQuery_Obj> mergeMediaQueries(const sass::vector<CssMediaQuery_Obj>& lhs, const sass::vector<CssMediaQuery_Obj>& rhs);
43
58
 
44
59
  public:
45
- Expand(Context&, Env*, SelectorStack* stack = NULL);
60
+ Expand(Context&, Env*, SelectorStack* stack = nullptr, SelectorStack* original = nullptr);
46
61
  ~Expand() { }
47
62
 
48
63
  Block* operator()(Block*);
49
- Statement* operator()(Ruleset*);
50
- Statement* operator()(Media_Block*);
51
- Statement* operator()(Supports_Block*);
52
- Statement* operator()(At_Root_Block*);
53
- Statement* operator()(Directive*);
64
+ Statement* operator()(StyleRule*);
65
+
66
+ Statement* operator()(MediaRule*);
67
+
68
+ // Css StyleRule is already static
69
+ // Statement* operator()(CssMediaRule*);
70
+
71
+ Statement* operator()(SupportsRule*);
72
+ Statement* operator()(AtRootRule*);
73
+ Statement* operator()(AtRule*);
54
74
  Statement* operator()(Declaration*);
55
75
  Statement* operator()(Assignment*);
56
76
  Statement* operator()(Import*);
57
77
  Statement* operator()(Import_Stub*);
58
- Statement* operator()(Warning*);
59
- Statement* operator()(Error*);
60
- Statement* operator()(Debug*);
78
+ Statement* operator()(WarningRule*);
79
+ Statement* operator()(ErrorRule*);
80
+ Statement* operator()(DebugRule*);
61
81
  Statement* operator()(Comment*);
62
82
  Statement* operator()(If*);
63
- Statement* operator()(For*);
64
- Statement* operator()(Each*);
65
- Statement* operator()(While*);
83
+ Statement* operator()(ForRule*);
84
+ Statement* operator()(EachRule*);
85
+ Statement* operator()(WhileRule*);
66
86
  Statement* operator()(Return*);
67
- Statement* operator()(Extension*);
87
+ Statement* operator()(ExtendRule*);
68
88
  Statement* operator()(Definition*);
69
89
  Statement* operator()(Mixin_Call*);
70
90
  Statement* operator()(Content*);
@@ -0,0 +1,1188 @@
1
+ // sass.hpp must go before all system headers to get the
2
+ // __EXTENSIONS__ fix on Solaris.
3
+ #include "sass.hpp"
4
+ #include "ast.hpp"
5
+
6
+ #include "extender.hpp"
7
+ #include "permutate.hpp"
8
+ #include "dart_helpers.hpp"
9
+
10
+ namespace Sass {
11
+
12
+ // ##########################################################################
13
+ // Constructor without default [mode].
14
+ // [traces] are needed to throw errors.
15
+ // ##########################################################################
16
+ Extender::Extender(Backtraces& traces) :
17
+ mode(NORMAL),
18
+ traces(traces),
19
+ selectors(),
20
+ extensions(),
21
+ extensionsByExtender(),
22
+ mediaContexts(),
23
+ sourceSpecificity(),
24
+ originals()
25
+ {}
26
+
27
+ // ##########################################################################
28
+ // Constructor with specific [mode].
29
+ // [traces] are needed to throw errors.
30
+ // ##########################################################################
31
+ Extender::Extender(ExtendMode mode, Backtraces& traces) :
32
+ mode(mode),
33
+ traces(traces),
34
+ selectors(),
35
+ extensions(),
36
+ extensionsByExtender(),
37
+ mediaContexts(),
38
+ sourceSpecificity(),
39
+ originals()
40
+ {}
41
+
42
+ // ##########################################################################
43
+ // Extends [selector] with [source] extender and [targets] extendees.
44
+ // This works as though `source {@extend target}` were written in the
45
+ // stylesheet, with the exception that [target] can contain compound
46
+ // selectors which must be extended as a unit.
47
+ // ##########################################################################
48
+ SelectorListObj Extender::extend(
49
+ SelectorListObj& selector,
50
+ const SelectorListObj& source,
51
+ const SelectorListObj& targets,
52
+ Backtraces& traces)
53
+ {
54
+ return extendOrReplace(selector, source, targets, ExtendMode::TARGETS, traces);
55
+ }
56
+ // EO Extender::extend
57
+
58
+ // ##########################################################################
59
+ // Returns a copy of [selector] with [targets] replaced by [source].
60
+ // ##########################################################################
61
+ SelectorListObj Extender::replace(
62
+ SelectorListObj& selector,
63
+ const SelectorListObj& source,
64
+ const SelectorListObj& targets,
65
+ Backtraces& traces)
66
+ {
67
+ return extendOrReplace(selector, source, targets, ExtendMode::REPLACE, traces);
68
+ }
69
+ // EO Extender::replace
70
+
71
+ // ##########################################################################
72
+ // A helper function for [extend] and [replace].
73
+ // ##########################################################################
74
+ SelectorListObj Extender::extendOrReplace(
75
+ SelectorListObj& selector,
76
+ const SelectorListObj& source,
77
+ const SelectorListObj& targets,
78
+ const ExtendMode mode,
79
+ Backtraces& traces)
80
+ {
81
+ ExtSelExtMapEntry extenders;
82
+
83
+ for (auto complex : source->elements()) {
84
+ // Extension.oneOff(complex as ComplexSelector)
85
+ extenders.insert(complex, Extension(complex));
86
+ }
87
+
88
+ for (auto complex : targets->elements()) {
89
+
90
+ // This seems superfluous, check is done before!?
91
+ // if (complex->length() != 1) {
92
+ // error("complex selectors may not be extended.", complex->pstate(), traces);
93
+ // }
94
+
95
+ if (const CompoundSelector* compound = complex->first()->getCompound()) {
96
+
97
+ ExtSelExtMap extensions;
98
+
99
+ for (const SimpleSelectorObj& simple : compound->elements()) {
100
+ extensions.insert(std::make_pair(simple, extenders));
101
+ }
102
+
103
+ Extender extender(mode, traces);
104
+
105
+ if (!selector->is_invisible()) {
106
+ for (auto sel : selector->elements()) {
107
+ extender.originals.insert(sel);
108
+ }
109
+ }
110
+
111
+ selector = extender.extendList(selector, extensions, {});
112
+
113
+ }
114
+
115
+ }
116
+
117
+ return selector;
118
+
119
+ }
120
+ // EO extendOrReplace
121
+
122
+ // ##########################################################################
123
+ // The set of all simple selectors in style rules handled
124
+ // by this extender. This includes simple selectors that
125
+ // were added because of downstream extensions.
126
+ // ##########################################################################
127
+ ExtSmplSelSet Extender::getSimpleSelectors() const
128
+ {
129
+ ExtSmplSelSet set;
130
+ for (auto& entry : selectors) {
131
+ set.insert(entry.first);
132
+ }
133
+ return set;
134
+ }
135
+ // EO getSimpleSelectors
136
+
137
+ // ##########################################################################
138
+ // Check for extends that have not been satisfied.
139
+ // Returns true if any non-optional extension did not
140
+ // extend any selector. Updates the passed reference
141
+ // to point to that Extension for further analysis.
142
+ // ##########################################################################
143
+ bool Extender::checkForUnsatisfiedExtends(Extension& unsatisfied) const
144
+ {
145
+ if (selectors.empty()) return false;
146
+ ExtSmplSelSet originals = getSimpleSelectors();
147
+ for (auto target : extensions) {
148
+ SimpleSelector* key = target.first;
149
+ ExtSelExtMapEntry& val = target.second;
150
+ if (val.empty()) continue;
151
+ if (originals.find(key) == originals.end()) {
152
+ const Extension& extension = val.front().second;
153
+ if (extension.isOptional) continue;
154
+ unsatisfied = extension;
155
+ return true;
156
+ }
157
+ }
158
+ return false;
159
+ }
160
+ // EO checkUnsatisfiedExtends
161
+
162
+ // ##########################################################################
163
+ // Adds [selector] to this extender, with [selectorSpan] as the span covering
164
+ // the selector and [ruleSpan] as the span covering the entire style rule.
165
+ // Extends [selector] using any registered extensions, then returns an empty
166
+ // [ModifiableCssStyleRule] with the resulting selector. If any more relevant
167
+ // extensions are added, the returned rule is automatically updated.
168
+ // The [mediaContext] is the media query context in which the selector was
169
+ // defined, or `null` if it was defined at the top level of the document.
170
+ // ##########################################################################
171
+ void Extender::addSelector(
172
+ const SelectorListObj& selector,
173
+ const CssMediaRuleObj& mediaContext)
174
+ {
175
+
176
+ // Note: dart-sass makes a copy here AFAICT
177
+ // Note: probably why we have originalStack
178
+ // SelectorListObj original = selector;
179
+
180
+ if (!selector->isInvisible()) {
181
+ for (auto complex : selector->elements()) {
182
+ originals.insert(complex);
183
+ }
184
+ }
185
+
186
+ if (!extensions.empty()) {
187
+
188
+ SelectorListObj res = extendList(selector, extensions, mediaContext);
189
+
190
+ selector->elements(res->elements());
191
+
192
+ }
193
+
194
+ if (!mediaContext.isNull()) {
195
+ mediaContexts.insert(selector, mediaContext);
196
+ }
197
+
198
+ registerSelector(selector, selector);
199
+
200
+ }
201
+ // EO addSelector
202
+
203
+ // ##########################################################################
204
+ // Registers the [SimpleSelector]s in [list]
205
+ // to point to [rule] in [selectors].
206
+ // ##########################################################################
207
+ void Extender::registerSelector(
208
+ const SelectorListObj& list,
209
+ const SelectorListObj& rule)
210
+ {
211
+ if (list.isNull() || list->empty()) return;
212
+ for (auto complex : list->elements()) {
213
+ for (auto component : complex->elements()) {
214
+ if (auto compound = component->getCompound()) {
215
+ for (SimpleSelector* simple : compound->elements()) {
216
+ selectors[simple].insert(rule);
217
+ if (auto pseudo = simple->getPseudoSelector()) {
218
+ if (pseudo->selector()) {
219
+ auto sel = pseudo->selector();
220
+ registerSelector(sel, rule);
221
+ }
222
+ }
223
+ }
224
+ }
225
+ }
226
+ }
227
+ }
228
+ // EO registerSelector
229
+
230
+ // ##########################################################################
231
+ // Returns an extension that combines [left] and [right]. Throws
232
+ // a [SassException] if [left] and [right] have incompatible
233
+ // media contexts. Throws an [ArgumentError] if [left]
234
+ // and [right] don't have the same extender and target.
235
+ // ##########################################################################
236
+ Extension Extender::mergeExtension(
237
+ const Extension& lhs,
238
+ const Extension& rhs)
239
+ {
240
+ // If one extension is optional and doesn't add a
241
+ // special media context, it doesn't need to be merged.
242
+ if (rhs.isOptional && rhs.mediaContext.isNull()) return lhs;
243
+ if (lhs.isOptional && lhs.mediaContext.isNull()) return rhs;
244
+
245
+ Extension rv(lhs);
246
+ // ToDo: is this right?
247
+ rv.isOptional = true;
248
+ rv.isOriginal = false;
249
+ return rv;
250
+ }
251
+ // EO mergeExtension
252
+
253
+ // ##########################################################################
254
+ // Helper function to copy extension between maps
255
+ // ##########################################################################
256
+ // Seems only relevant for sass 4.0 modules
257
+ // ##########################################################################
258
+ /* void mapCopyExts(
259
+ ExtSelExtMap& dest,
260
+ const ExtSelExtMap& source)
261
+ {
262
+ for (auto it : source) {
263
+ SimpleSelectorObj key = it.first;
264
+ ExtSelExtMapEntry& inner = it.second;
265
+ ExtSelExtMap::iterator dmap = dest.find(key);
266
+ if (dmap == dest.end()) {
267
+ dest.insert(std::make_pair(key, inner));
268
+ }
269
+ else {
270
+ ExtSelExtMapEntry& imap = dmap->second;
271
+ // ToDo: optimize ordered_map API!
272
+ // ToDo: we iterate and fetch the value
273
+ for (ComplexSelectorObj& it2 : inner) {
274
+ imap.insert(it2, inner.get(it2));
275
+ }
276
+ }
277
+ }
278
+ } */
279
+ // EO mapCopyExts
280
+
281
+ // ##########################################################################
282
+ // Adds an extension to this extender. The [extender] is the selector for the
283
+ // style rule in which the extension is defined, and [target] is the selector
284
+ // passed to `@extend`. The [extend] provides the extend span and indicates
285
+ // whether the extension is optional. The [mediaContext] defines the media query
286
+ // context in which the extension is defined. It can only extend selectors
287
+ // within the same context. A `null` context indicates no media queries.
288
+ // ##########################################################################
289
+ // ToDo: rename extender to parent, since it is not involved in extending stuff
290
+ // ToDo: check why dart sass passes the ExtendRule around (is this the main selector?)
291
+ // ##########################################################################
292
+ // Note: this function could need some logic cleanup
293
+ // ##########################################################################
294
+ void Extender::addExtension(
295
+ const SelectorListObj& extender,
296
+ const SimpleSelectorObj& target,
297
+ const CssMediaRuleObj& mediaQueryContext,
298
+ bool is_optional)
299
+ {
300
+
301
+ auto rules = selectors.find(target);
302
+ bool hasRule = rules != selectors.end();
303
+
304
+ ExtSelExtMapEntry newExtensions;
305
+
306
+ // ToDo: we check this here first and fetch the same? item again after the loop!?
307
+ bool hasExistingExtensions = extensionsByExtender.find(target) != extensionsByExtender.end();
308
+
309
+ ExtSelExtMapEntry& sources = extensions[target];
310
+
311
+ for (auto& complex : extender->elements()) {
312
+
313
+ Extension state(complex);
314
+ // ToDo: fine-tune public API
315
+ state.target = target;
316
+ state.isOptional = is_optional;
317
+ state.mediaContext = mediaQueryContext;
318
+
319
+ if (sources.hasKey(complex)) {
320
+ // If there's already an extend from [extender] to [target],
321
+ // we don't need to re-run the extension. We may need to
322
+ // mark the extension as mandatory, though.
323
+ // sources.insert(complex, mergeExtension(existingState->second, state);
324
+ // ToDo: implement behavior once use case is found!?
325
+ continue;
326
+ }
327
+
328
+ sources.insert(complex, state);
329
+
330
+ for (auto& component : complex->elements()) {
331
+ if (auto compound = component->getCompound()) {
332
+ for (auto& simple : compound->elements()) {
333
+ extensionsByExtender[simple].push_back(state);
334
+ if (sourceSpecificity.find(simple) == sourceSpecificity.end()) {
335
+ // Only source specificity for the original selector is relevant.
336
+ // Selectors generated by `@extend` don't get new specificity.
337
+ sourceSpecificity[simple] = complex->maxSpecificity();
338
+ }
339
+ }
340
+ }
341
+ }
342
+
343
+ if (hasRule || hasExistingExtensions) {
344
+ newExtensions.insert(complex, state);
345
+ }
346
+
347
+ }
348
+ // EO foreach complex
349
+
350
+ if (newExtensions.empty()) {
351
+ return;
352
+ }
353
+
354
+ ExtSelExtMap newExtensionsByTarget;
355
+ newExtensionsByTarget.insert(std::make_pair(target, newExtensions));
356
+ // ToDo: do we really need to fetch again (see top off fn)
357
+ auto existingExtensions = extensionsByExtender.find(target);
358
+ if (existingExtensions != extensionsByExtender.end()) {
359
+ if (hasExistingExtensions && !existingExtensions->second.empty()) {
360
+ // Seems only relevant for sass 4.0 modules
361
+ // auto additionalExtensions =
362
+ extendExistingExtensions(existingExtensions->second, newExtensionsByTarget);
363
+ // Seems only relevant for sass 4.0 modules
364
+ /* if (!additionalExtensions.empty()) {
365
+ mapCopyExts(newExtensionsByTarget, additionalExtensions);
366
+ } */
367
+ }
368
+ }
369
+
370
+ if (hasRule) {
371
+ extendExistingStyleRules(selectors[target], newExtensionsByTarget);
372
+ }
373
+
374
+ }
375
+ // EO addExtension
376
+
377
+ // ##########################################################################
378
+ // Extend [extensions] using [newExtensions].
379
+ // ##########################################################################
380
+ // Note: dart-sass throws an error in here
381
+ // ##########################################################################
382
+ void Extender::extendExistingStyleRules(
383
+ const ExtListSelSet& rules,
384
+ const ExtSelExtMap& newExtensions)
385
+ {
386
+ // Is a modifyableCssStyleRUle in dart sass
387
+ for (const SelectorListObj& rule : rules) {
388
+ const SelectorListObj& oldValue = SASS_MEMORY_COPY(rule);
389
+ CssMediaRuleObj mediaContext;
390
+ if (mediaContexts.hasKey(rule)) mediaContext = mediaContexts.get(rule);
391
+ SelectorListObj ext = extendList(rule, newExtensions, mediaContext);
392
+ // If no extends actually happened (for example because unification
393
+ // failed), we don't need to re-register the selector.
394
+ if (ObjEqualityFn(oldValue, ext)) continue;
395
+ rule->elements(ext->elements());
396
+ registerSelector(rule, rule);
397
+
398
+ }
399
+ }
400
+ // EO extendExistingStyleRules
401
+
402
+ // ##########################################################################
403
+ // Extend [extensions] using [newExtensions]. Note that this does duplicate
404
+ // some work done by [_extendExistingStyleRules], but it's necessary to
405
+ // expand each extension's extender separately without reference to the full
406
+ // selector list, so that relevant results don't get trimmed too early.
407
+ //
408
+ // Returns extensions that should be added to [newExtensions] before
409
+ // extending selectors in order to properly handle extension loops such as:
410
+ //
411
+ // .c {x: y; @extend .a}
412
+ // .x.y.a {@extend .b}
413
+ // .z.b {@extend .c}
414
+ //
415
+ // Returns `null` (Note: empty map) if there are no extensions to add.
416
+ // ##########################################################################
417
+ // Note: maybe refactor to return `bool` (and pass reference)
418
+ // Note: dart-sass throws an error in here
419
+ // ##########################################################################
420
+ ExtSelExtMap Extender::extendExistingExtensions(
421
+ // Taking in a reference here makes MSVC debug stuck!?
422
+ const sass::vector<Extension>& oldExtensions,
423
+ const ExtSelExtMap& newExtensions)
424
+ {
425
+
426
+ ExtSelExtMap additionalExtensions;
427
+
428
+ // During the loop `oldExtensions` vector might be changed.
429
+ // Callers normally pass this from `extensionsByExtender` and
430
+ // that points back to the `sources` vector from `extensions`.
431
+ for (size_t i = 0, iL = oldExtensions.size(); i < iL; i += 1) {
432
+ const Extension& extension = oldExtensions[i];
433
+ ExtSelExtMapEntry& sources = extensions[extension.target];
434
+ sass::vector<ComplexSelectorObj> selectors(extendComplex(
435
+ extension.extender,
436
+ newExtensions,
437
+ extension.mediaContext
438
+ ));
439
+
440
+ if (selectors.empty()) {
441
+ continue;
442
+ }
443
+
444
+ // ToDo: "catch" error from extend
445
+
446
+ bool first = false, containsExtension =
447
+ ObjEqualityFn(selectors.front(), extension.extender);
448
+ for (const ComplexSelectorObj& complex : selectors) {
449
+ // If the output contains the original complex
450
+ // selector, there's no need to recreate it.
451
+ if (containsExtension && first) {
452
+ first = false;
453
+ continue;
454
+ }
455
+
456
+ const Extension withExtender =
457
+ extension.withExtender(complex);
458
+ if (sources.hasKey(complex)) {
459
+ sources.insert(complex, mergeExtension(
460
+ sources.get(complex), withExtender));
461
+ }
462
+ else {
463
+ sources.insert(complex, withExtender);
464
+ /*
465
+ // Seems only relevant for sass 4.0 modules
466
+ for (auto& component : complex->elements()) {
467
+ if (auto compound = component->getCompound()) {
468
+ for (auto& simple : compound->elements()) {
469
+ extensionsByExtender[simple].push_back(withExtender);
470
+ }
471
+ }
472
+ }
473
+ if (newExtensions.find(extension.target) != newExtensions.end()) {
474
+ additionalExtensions[extension.target].insert(complex, withExtender);
475
+ }
476
+ */
477
+ }
478
+ }
479
+
480
+ // If [selectors] doesn't contain [extension.extender],
481
+ // for example if it was replaced due to :not() expansion,
482
+ // we must get rid of the old version.
483
+ /*
484
+ // Seems only relevant for sass 4.0 modules
485
+ if (!containsExtension) {
486
+ sources.erase(extension.extender);
487
+ }
488
+ */
489
+
490
+ }
491
+
492
+ return additionalExtensions;
493
+
494
+ }
495
+ // EO extendExistingExtensions
496
+
497
+ // ##########################################################################
498
+ // Extends [list] using [extensions].
499
+ // ##########################################################################
500
+ SelectorListObj Extender::extendList(
501
+ const SelectorListObj& list,
502
+ const ExtSelExtMap& extensions,
503
+ const CssMediaRuleObj& mediaQueryContext)
504
+ {
505
+
506
+ // This could be written more simply using [List.map], but we want to
507
+ // avoid any allocations in the common case where no extends apply.
508
+ sass::vector<ComplexSelectorObj> extended;
509
+ for (size_t i = 0; i < list->length(); i++) {
510
+ const ComplexSelectorObj& complex = list->get(i);
511
+ sass::vector<ComplexSelectorObj> result =
512
+ extendComplex(complex, extensions, mediaQueryContext);
513
+ if (result.empty()) {
514
+ if (!extended.empty()) {
515
+ extended.push_back(complex);
516
+ }
517
+ }
518
+ else {
519
+ if (extended.empty()) {
520
+ for (size_t n = 0; n < i; n += 1) {
521
+ extended.push_back(list->get(n));
522
+ }
523
+ }
524
+ for (auto sel : result) {
525
+ extended.push_back(sel);
526
+ }
527
+ }
528
+ }
529
+
530
+ if (extended.empty()) {
531
+ return list;
532
+ }
533
+
534
+ SelectorListObj rv = SASS_MEMORY_NEW(SelectorList, list->pstate());
535
+ rv->concat(trim(extended, originals));
536
+ return rv;
537
+
538
+ }
539
+ // EO extendList
540
+
541
+ // ##########################################################################
542
+ // Extends [complex] using [extensions], and
543
+ // returns the contents of a [SelectorList].
544
+ // ##########################################################################
545
+ sass::vector<ComplexSelectorObj> Extender::extendComplex(
546
+ // Taking in a reference here makes MSVC debug stuck!?
547
+ const ComplexSelectorObj& complex,
548
+ const ExtSelExtMap& extensions,
549
+ const CssMediaRuleObj& mediaQueryContext)
550
+ {
551
+
552
+ // The complex selectors that each compound selector in [complex.components]
553
+ // can expand to.
554
+ //
555
+ // For example, given
556
+ //
557
+ // .a .b {...}
558
+ // .x .y {@extend .b}
559
+ //
560
+ // this will contain
561
+ //
562
+ // [
563
+ // [.a],
564
+ // [.b, .x .y]
565
+ // ]
566
+ //
567
+ // This could be written more simply using [List.map], but we want to avoid
568
+ // any allocations in the common case where no extends apply.
569
+
570
+ sass::vector<ComplexSelectorObj> result;
571
+ sass::vector<sass::vector<ComplexSelectorObj>> extendedNotExpanded;
572
+ bool isOriginal = originals.find(complex) != originals.end();
573
+ for (size_t i = 0; i < complex->length(); i += 1) {
574
+ const SelectorComponentObj& component = complex->get(i);
575
+ if (CompoundSelector* compound = Cast<CompoundSelector>(component)) {
576
+ sass::vector<ComplexSelectorObj> extended = extendCompound(
577
+ compound, extensions, mediaQueryContext, isOriginal);
578
+ if (extended.empty()) {
579
+ if (!extendedNotExpanded.empty()) {
580
+ extendedNotExpanded.push_back({
581
+ compound->wrapInComplex()
582
+ });
583
+ }
584
+ }
585
+ else {
586
+ // Note: dart-sass checks for null!?
587
+ if (extendedNotExpanded.empty()) {
588
+ for (size_t n = 0; n < i; n++) {
589
+ extendedNotExpanded.push_back({
590
+ complex->at(n)->wrapInComplex()
591
+ });
592
+ }
593
+ }
594
+ extendedNotExpanded.push_back(extended);
595
+ }
596
+ }
597
+ else {
598
+ // Note: dart-sass checks for null!?
599
+ if (!extendedNotExpanded.empty()) {
600
+ extendedNotExpanded.push_back({
601
+ component->wrapInComplex()
602
+ });
603
+ }
604
+ }
605
+ }
606
+
607
+ // Note: dart-sass checks for null!?
608
+ if (extendedNotExpanded.empty()) {
609
+ return {};
610
+ }
611
+
612
+ bool first = true;
613
+
614
+ // ToDo: either change weave or paths to work with the same data?
615
+ sass::vector<sass::vector<ComplexSelectorObj>>
616
+ paths = permutate(extendedNotExpanded);
617
+
618
+ for (const sass::vector<ComplexSelectorObj>& path : paths) {
619
+ // Unpack the inner complex selector to component list
620
+ sass::vector<sass::vector<SelectorComponentObj>> _paths;
621
+ for (const ComplexSelectorObj& sel : path) {
622
+ _paths.insert(_paths.end(), sel->elements());
623
+ }
624
+
625
+ sass::vector<sass::vector<SelectorComponentObj>> weaved = weave(_paths);
626
+
627
+ for (sass::vector<SelectorComponentObj>& components : weaved) {
628
+
629
+ ComplexSelectorObj cplx = SASS_MEMORY_NEW(ComplexSelector, "[phony]");
630
+ cplx->hasPreLineFeed(complex->hasPreLineFeed());
631
+ for (auto& pp : path) {
632
+ if (pp->hasPreLineFeed()) {
633
+ cplx->hasPreLineFeed(true);
634
+ }
635
+ }
636
+ cplx->elements(components);
637
+
638
+ // Make sure that copies of [complex] retain their status
639
+ // as "original" selectors. This includes selectors that
640
+ // are modified because a :not() was extended into.
641
+ if (first && originals.find(complex) != originals.end()) {
642
+ originals.insert(cplx);
643
+ }
644
+ first = false;
645
+
646
+ result.push_back(cplx);
647
+
648
+ }
649
+
650
+ }
651
+
652
+ return result;
653
+ }
654
+ // EO extendComplex
655
+
656
+ // ##########################################################################
657
+ // Returns a one-off [Extension] whose
658
+ // extender is composed solely of [simple].
659
+ // ##########################################################################
660
+ Extension Extender::extensionForSimple(
661
+ const SimpleSelectorObj& simple) const
662
+ {
663
+ Extension extension(simple->wrapInComplex());
664
+ extension.specificity = maxSourceSpecificity(simple);
665
+ extension.isOriginal = true;
666
+ return extension;
667
+ }
668
+ // Extender::extensionForSimple
669
+
670
+ // ##########################################################################
671
+ // Returns a one-off [Extension] whose extender is composed
672
+ // solely of a compound selector containing [simples].
673
+ // ##########################################################################
674
+ Extension Extender::extensionForCompound(
675
+ // Taking in a reference here makes MSVC debug stuck!?
676
+ const sass::vector<SimpleSelectorObj>& simples) const
677
+ {
678
+ CompoundSelectorObj compound = SASS_MEMORY_NEW(CompoundSelector, SourceSpan("[ext]"));
679
+ compound->concat(simples);
680
+ Extension extension(compound->wrapInComplex());
681
+ // extension.specificity = sourceSpecificity[simple];
682
+ extension.isOriginal = true;
683
+ return extension;
684
+ }
685
+ // EO extensionForCompound
686
+
687
+ // ##########################################################################
688
+ // Extends [compound] using [extensions], and returns the
689
+ // contents of a [SelectorList]. The [inOriginal] parameter
690
+ // indicates whether this is in an original complex selector,
691
+ // meaning that [compound] should not be trimmed out.
692
+ // ##########################################################################
693
+ sass::vector<ComplexSelectorObj> Extender::extendCompound(
694
+ const CompoundSelectorObj& compound,
695
+ const ExtSelExtMap& extensions,
696
+ const CssMediaRuleObj& mediaQueryContext,
697
+ bool inOriginal)
698
+ {
699
+
700
+ // If there's more than one target and they all need to
701
+ // match, we track which targets are actually extended.
702
+ ExtSmplSelSet targetsUsed2;
703
+
704
+ ExtSmplSelSet* targetsUsed = nullptr;
705
+
706
+ if (mode != ExtendMode::NORMAL && extensions.size() > 1) {
707
+ targetsUsed = &targetsUsed2;
708
+ }
709
+
710
+ sass::vector<ComplexSelectorObj> result;
711
+ // The complex selectors produced from each component of [compound].
712
+ sass::vector<sass::vector<Extension>> options;
713
+
714
+ for (size_t i = 0; i < compound->length(); i++) {
715
+ const SimpleSelectorObj& simple = compound->get(i);
716
+ auto extended = extendSimple(simple, extensions, mediaQueryContext, targetsUsed);
717
+ if (extended.empty()) {
718
+ if (!options.empty()) {
719
+ options.push_back({ extensionForSimple(simple) });
720
+ }
721
+ }
722
+ else {
723
+ if (options.empty()) {
724
+ if (i != 0) {
725
+ sass::vector<SimpleSelectorObj> in;
726
+ for (size_t n = 0; n < i; n += 1) {
727
+ in.push_back(compound->get(n));
728
+ }
729
+ options.push_back({ extensionForCompound(in) });
730
+ }
731
+ }
732
+ options.insert(options.end(),
733
+ extended.begin(), extended.end());
734
+ }
735
+ }
736
+
737
+ if (options.empty()) {
738
+ return {};
739
+ }
740
+
741
+ // If [_mode] isn't [ExtendMode.normal] and we didn't use all
742
+ // the targets in [extensions], extension fails for [compound].
743
+ if (targetsUsed != nullptr) {
744
+
745
+ if (targetsUsed->size() != extensions.size()) {
746
+ if (!targetsUsed->empty()) {
747
+ return {};
748
+ }
749
+ }
750
+ }
751
+
752
+ // Optimize for the simple case of a single simple
753
+ // selector that doesn't need any unification.
754
+ if (options.size() == 1) {
755
+ sass::vector<Extension> exts = options[0];
756
+ for (size_t n = 0; n < exts.size(); n += 1) {
757
+ exts[n].assertCompatibleMediaContext(mediaQueryContext, traces);
758
+ result.push_back(exts[n].extender);
759
+ }
760
+ return result;
761
+ }
762
+
763
+ // Find all paths through [options]. In this case, each path represents a
764
+ // different unification of the base selector. For example, if we have:
765
+ //
766
+ // .a.b {...}
767
+ // .w .x {@extend .a}
768
+ // .y .z {@extend .b}
769
+ //
770
+ // then [options] is `[[.a, .w .x], [.b, .y .z]]` and `paths(options)` is
771
+ //
772
+ // [
773
+ // [.a, .b],
774
+ // [.a, .y .z],
775
+ // [.w .x, .b],
776
+ // [.w .x, .y .z]
777
+ // ]
778
+ //
779
+ // We then unify each path to get a list of complex selectors:
780
+ //
781
+ // [
782
+ // [.a.b],
783
+ // [.y .a.z],
784
+ // [.w .x.b],
785
+ // [.w .y .x.z, .y .w .x.z]
786
+ // ]
787
+
788
+ bool first = mode != ExtendMode::REPLACE;
789
+ sass::vector<ComplexSelectorObj> unifiedPaths;
790
+ sass::vector<sass::vector<Extension>> prePaths = permutate(options);
791
+
792
+ for (size_t i = 0; i < prePaths.size(); i += 1) {
793
+ sass::vector<sass::vector<SelectorComponentObj>> complexes;
794
+ const sass::vector<Extension>& path = prePaths[i];
795
+ if (first) {
796
+ // The first path is always the original selector. We can't just
797
+ // return [compound] directly because pseudo selectors may be
798
+ // modified, but we don't have to do any unification.
799
+ first = false;
800
+ CompoundSelectorObj mergedSelector =
801
+ SASS_MEMORY_NEW(CompoundSelector, "[ext]");
802
+ for (size_t n = 0; n < path.size(); n += 1) {
803
+ const ComplexSelectorObj& sel = path[n].extender;
804
+ if (CompoundSelectorObj compound = Cast<CompoundSelector>(sel->last())) {
805
+ mergedSelector->concat(compound->elements());
806
+ }
807
+ }
808
+ complexes.push_back({ mergedSelector });
809
+ }
810
+ else {
811
+ sass::vector<SimpleSelectorObj> originals;
812
+ sass::vector<sass::vector<SelectorComponentObj>> toUnify;
813
+
814
+ for (auto& state : path) {
815
+ if (state.isOriginal) {
816
+ const ComplexSelectorObj& sel = state.extender;
817
+ if (const CompoundSelector* compound = Cast<CompoundSelector>(sel->last())) {
818
+ originals.insert(originals.end(), compound->last());
819
+ }
820
+ }
821
+ else {
822
+ toUnify.push_back(state.extender->elements());
823
+ }
824
+ }
825
+ if (!originals.empty()) {
826
+ CompoundSelectorObj merged =
827
+ SASS_MEMORY_NEW(CompoundSelector, "[phony]");
828
+ merged->concat(originals);
829
+ toUnify.insert(toUnify.begin(), { merged });
830
+ }
831
+ complexes = unifyComplex(toUnify);
832
+ if (complexes.empty()) {
833
+ return {};
834
+ }
835
+
836
+ }
837
+
838
+ bool lineBreak = false;
839
+ // var specificity = _sourceSpecificityFor(compound);
840
+ for (const Extension& state : path) {
841
+ state.assertCompatibleMediaContext(mediaQueryContext, traces);
842
+ lineBreak = lineBreak || state.extender->hasPreLineFeed();
843
+ // specificity = math.max(specificity, state.specificity);
844
+ }
845
+
846
+ for (sass::vector<SelectorComponentObj>& components : complexes) {
847
+ auto sel = SASS_MEMORY_NEW(ComplexSelector, "[ext]");
848
+ sel->hasPreLineFeed(lineBreak);
849
+ sel->elements(components);
850
+ unifiedPaths.push_back(sel);
851
+ }
852
+
853
+ }
854
+
855
+ return unifiedPaths;
856
+ }
857
+ // EO extendCompound
858
+
859
+ // ##########################################################################
860
+ // Extends [simple] without extending the
861
+ // contents of any selector pseudos it contains.
862
+ // ##########################################################################
863
+ sass::vector<Extension> Extender::extendWithoutPseudo(
864
+ const SimpleSelectorObj& simple,
865
+ const ExtSelExtMap& extensions,
866
+ ExtSmplSelSet* targetsUsed) const
867
+ {
868
+
869
+ auto extension = extensions.find(simple);
870
+ if (extension == extensions.end()) return {};
871
+ const ExtSelExtMapEntry& extenders = extension->second;
872
+
873
+ if (targetsUsed != nullptr) {
874
+ targetsUsed->insert(simple);
875
+ }
876
+ if (mode == ExtendMode::REPLACE) {
877
+ return extenders.values();
878
+ }
879
+
880
+ const sass::vector<Extension>&
881
+ values = extenders.values();
882
+ sass::vector<Extension> result;
883
+ result.reserve(values.size() + 1);
884
+ result.push_back(extensionForSimple(simple));
885
+ result.insert(result.end(), values.begin(), values.end());
886
+ return result;
887
+ }
888
+ // EO extendWithoutPseudo
889
+
890
+ // ##########################################################################
891
+ // Extends [simple] and also extending the
892
+ // contents of any selector pseudos it contains.
893
+ // ##########################################################################
894
+ sass::vector<sass::vector<Extension>> Extender::extendSimple(
895
+ const SimpleSelectorObj& simple,
896
+ const ExtSelExtMap& extensions,
897
+ const CssMediaRuleObj& mediaQueryContext,
898
+ ExtSmplSelSet* targetsUsed)
899
+ {
900
+ if (PseudoSelector* pseudo = Cast<PseudoSelector>(simple)) {
901
+ if (pseudo->selector()) {
902
+ sass::vector<sass::vector<Extension>> merged;
903
+ sass::vector<PseudoSelectorObj> extended =
904
+ extendPseudo(pseudo, extensions, mediaQueryContext);
905
+ for (PseudoSelectorObj& extend : extended) {
906
+ SimpleSelectorObj simple = extend;
907
+ sass::vector<Extension> result =
908
+ extendWithoutPseudo(simple, extensions, targetsUsed);
909
+ if (result.empty()) result = { extensionForSimple(extend) };
910
+ merged.push_back(result);
911
+ }
912
+ if (!extended.empty()) {
913
+ return merged;
914
+ }
915
+ }
916
+ }
917
+ sass::vector<Extension> result =
918
+ extendWithoutPseudo(simple, extensions, targetsUsed);
919
+ if (result.empty()) return {};
920
+ return { result };
921
+ }
922
+ // extendSimple
923
+
924
+ // ##########################################################################
925
+ // Inner loop helper for [extendPseudo] function
926
+ // ##########################################################################
927
+ sass::vector<ComplexSelectorObj> Extender::extendPseudoComplex(
928
+ const ComplexSelectorObj& complex,
929
+ const PseudoSelectorObj& pseudo,
930
+ const CssMediaRuleObj& mediaQueryContext)
931
+ {
932
+
933
+ if (complex->length() != 1) { return { complex }; }
934
+ auto compound = Cast<CompoundSelector>(complex->get(0));
935
+ if (compound == nullptr) { return { complex }; }
936
+ if (compound->length() != 1) { return { complex }; }
937
+ auto innerPseudo = Cast<PseudoSelector>(compound->get(0));
938
+ if (innerPseudo == nullptr) { return { complex }; }
939
+ if (!innerPseudo->selector()) { return { complex }; }
940
+
941
+ sass::string name(pseudo->normalized());
942
+
943
+ if (name == "not") {
944
+ // In theory, if there's a `:not` nested within another `:not`, the
945
+ // inner `:not`'s contents should be unified with the return value.
946
+ // For example, if `:not(.foo)` extends `.bar`, `:not(.bar)` should
947
+ // become `.foo:not(.bar)`. However, this is a narrow edge case and
948
+ // supporting it properly would make this code and the code calling it
949
+ // a lot more complicated, so it's not supported for now.
950
+ if (innerPseudo->normalized() != "matches") return {};
951
+ return innerPseudo->selector()->elements();
952
+ }
953
+ else if (name == "matches" && name == "any" && name == "current" && name == "nth-child" && name == "nth-last-child") {
954
+ // As above, we could theoretically support :not within :matches, but
955
+ // doing so would require this method and its callers to handle much
956
+ // more complex cases that likely aren't worth the pain.
957
+ if (innerPseudo->name() != pseudo->name()) return {};
958
+ if (!ObjEquality()(innerPseudo->argument(), pseudo->argument())) return {};
959
+ return innerPseudo->selector()->elements();
960
+ }
961
+ else if (name == "has" && name == "host" && name == "host-context" && name == "slotted") {
962
+ // We can't expand nested selectors here, because each layer adds an
963
+ // additional layer of semantics. For example, `:has(:has(img))`
964
+ // doesn't match `<div><img></div>` but `:has(img)` does.
965
+ return { complex };
966
+ }
967
+
968
+ return {};
969
+
970
+ }
971
+ // EO extendPseudoComplex
972
+
973
+ // ##########################################################################
974
+ // Extends [pseudo] using [extensions], and returns
975
+ // a list of resulting pseudo selectors.
976
+ // ##########################################################################
977
+ sass::vector<PseudoSelectorObj> Extender::extendPseudo(
978
+ const PseudoSelectorObj& pseudo,
979
+ const ExtSelExtMap& extensions,
980
+ const CssMediaRuleObj& mediaQueryContext)
981
+ {
982
+ auto selector = pseudo->selector();
983
+ SelectorListObj extended = extendList(
984
+ selector, extensions, mediaQueryContext);
985
+ if (!extended || !pseudo || !pseudo->selector()) { return {}; }
986
+ if (ObjEqualityFn(pseudo->selector(), extended)) { return {}; }
987
+
988
+ // For `:not()`, we usually want to get rid of any complex selectors because
989
+ // that will cause the selector to fail to parse on all browsers at time of
990
+ // writing. We can keep them if either the original selector had a complex
991
+ // selector, or the result of extending has only complex selectors, because
992
+ // either way we aren't breaking anything that isn't already broken.
993
+ sass::vector<ComplexSelectorObj> complexes = extended->elements();
994
+
995
+ if (pseudo->normalized() == "not") {
996
+ if (!hasAny(pseudo->selector()->elements(), hasMoreThanOne)) {
997
+ if (hasAny(extended->elements(), hasExactlyOne)) {
998
+ complexes.clear();
999
+ for (auto& complex : extended->elements()) {
1000
+ if (complex->length() <= 1) {
1001
+ complexes.push_back(complex);
1002
+ }
1003
+ }
1004
+ }
1005
+ }
1006
+ }
1007
+
1008
+ sass::vector<ComplexSelectorObj> expanded = expand(
1009
+ complexes, extendPseudoComplex, pseudo, mediaQueryContext);
1010
+
1011
+ // Older browsers support `:not`, but only with a single complex selector.
1012
+ // In order to support those browsers, we break up the contents of a `:not`
1013
+ // unless it originally contained a selector list.
1014
+ if (pseudo->normalized() == "not") {
1015
+ if (pseudo->selector()->length() == 1) {
1016
+ sass::vector<PseudoSelectorObj> pseudos;
1017
+ for (size_t i = 0; i < expanded.size(); i += 1) {
1018
+ pseudos.push_back(pseudo->withSelector(
1019
+ expanded[i]->wrapInList()
1020
+ ));
1021
+ }
1022
+ return pseudos;
1023
+ }
1024
+ }
1025
+
1026
+ SelectorListObj list = SASS_MEMORY_NEW(SelectorList, "[phony]");
1027
+ list->concat(complexes);
1028
+ return { pseudo->withSelector(list) };
1029
+
1030
+ }
1031
+ // EO extendPseudo
1032
+
1033
+ // ##########################################################################
1034
+ // Rotates the element in list from [start] (inclusive) to [end] (exclusive)
1035
+ // one index higher, looping the final element back to [start].
1036
+ // ##########################################################################
1037
+ void Extender::rotateSlice(
1038
+ sass::vector<ComplexSelectorObj>& list,
1039
+ size_t start, size_t end)
1040
+ {
1041
+ auto element = list[end - 1];
1042
+ for (size_t i = start; i < end; i++) {
1043
+ auto next = list[i];
1044
+ list[i] = element;
1045
+ element = next;
1046
+ }
1047
+ }
1048
+ // EO rotateSlice
1049
+
1050
+ // ##########################################################################
1051
+ // Removes elements from [selectors] if they're subselectors of other
1052
+ // elements. The [isOriginal] callback indicates which selectors are
1053
+ // original to the document, and thus should never be trimmed.
1054
+ // ##########################################################################
1055
+ // Note: for adaption I pass in the set directly, there is some
1056
+ // code path in selector-trim that might need this special callback
1057
+ // ##########################################################################
1058
+ sass::vector<ComplexSelectorObj> Extender::trim(
1059
+ const sass::vector<ComplexSelectorObj>& selectors,
1060
+ const ExtCplxSelSet& existing) const
1061
+ {
1062
+
1063
+ // Avoid truly horrific quadratic behavior.
1064
+ // TODO(nweiz): I think there may be a way to get perfect trimming
1065
+ // without going quadratic by building some sort of trie-like
1066
+ // data structure that can be used to look up superselectors.
1067
+ // TODO(mgreter): Check how this performs in C++ (up the limit)
1068
+ if (selectors.size() > 100) return selectors;
1069
+
1070
+ // This is n² on the sequences, but only comparing between separate sequences
1071
+ // should limit the quadratic behavior. We iterate from last to first and reverse
1072
+ // the result so that, if two selectors are identical, we keep the first one.
1073
+ sass::vector<ComplexSelectorObj> result; size_t numOriginals = 0;
1074
+
1075
+ size_t i = selectors.size();
1076
+ outer: // Use label to continue loop
1077
+ while (--i != sass::string::npos) {
1078
+
1079
+ const ComplexSelectorObj& complex1 = selectors[i];
1080
+ // Check if selector in known in existing "originals"
1081
+ // For custom behavior dart-sass had `isOriginal(complex1)`
1082
+ if (existing.find(complex1) != existing.end()) {
1083
+ // Make sure we don't include duplicate originals, which could
1084
+ // happen if a style rule extends a component of its own selector.
1085
+ for (size_t j = 0; j < numOriginals; j++) {
1086
+ if (ObjEqualityFn(result[j], complex1)) {
1087
+ rotateSlice(result, 0, j + 1);
1088
+ goto outer;
1089
+ }
1090
+ }
1091
+ result.insert(result.begin(), complex1);
1092
+ numOriginals++;
1093
+ continue;
1094
+ }
1095
+
1096
+ // The maximum specificity of the sources that caused [complex1]
1097
+ // to be generated. In order for [complex1] to be removed, there
1098
+ // must be another selector that's a superselector of it *and*
1099
+ // that has specificity greater or equal to this.
1100
+ size_t maxSpecificity = 0;
1101
+ for (const SelectorComponentObj& component : complex1->elements()) {
1102
+ if (const CompoundSelectorObj compound = Cast<CompoundSelector>(component)) {
1103
+ maxSpecificity = std::max(maxSpecificity, maxSourceSpecificity(compound));
1104
+ }
1105
+ }
1106
+
1107
+
1108
+ // Look in [result] rather than [selectors] for selectors after [i]. This
1109
+ // ensures we aren't comparing against a selector that's already been trimmed,
1110
+ // and thus that if there are two identical selectors only one is trimmed.
1111
+ if (hasAny(result, dontTrimComplex, complex1, maxSpecificity)) {
1112
+ continue;
1113
+ }
1114
+
1115
+ // Check if any element (up to [i]) from [selector] returns true
1116
+ // when passed to [dontTrimComplex]. The arguments [complex1] and
1117
+ // [maxSepcificity] will be passed to the invoked function.
1118
+ if (hasSubAny(selectors, i, dontTrimComplex, complex1, maxSpecificity)) {
1119
+ continue;
1120
+ }
1121
+
1122
+ // ToDo: Maybe use deque for front insert?
1123
+ result.insert(result.begin(), complex1);
1124
+
1125
+ }
1126
+
1127
+ return result;
1128
+
1129
+ }
1130
+ // EO trim
1131
+
1132
+ // ##########################################################################
1133
+ // Returns the maximum specificity of the given [simple] source selector.
1134
+ // ##########################################################################
1135
+ size_t Extender::maxSourceSpecificity(const SimpleSelectorObj& simple) const
1136
+ {
1137
+ auto it = sourceSpecificity.find(simple);
1138
+ if (it == sourceSpecificity.end()) return 0;
1139
+ return it->second;
1140
+ }
1141
+ // EO maxSourceSpecificity(SimpleSelectorObj)
1142
+
1143
+ // ##########################################################################
1144
+ // Returns the maximum specificity for sources that went into producing [compound].
1145
+ // ##########################################################################
1146
+ size_t Extender::maxSourceSpecificity(const CompoundSelectorObj& compound) const
1147
+ {
1148
+ size_t specificity = 0;
1149
+ for (auto simple : compound->elements()) {
1150
+ size_t src = maxSourceSpecificity(simple);
1151
+ specificity = std::max(specificity, src);
1152
+ }
1153
+ return specificity;
1154
+ }
1155
+ // EO maxSourceSpecificity(CompoundSelectorObj)
1156
+
1157
+ // ##########################################################################
1158
+ // Helper function used as callbacks on lists
1159
+ // ##########################################################################
1160
+ bool Extender::dontTrimComplex(
1161
+ const ComplexSelector* complex2,
1162
+ const ComplexSelector* complex1,
1163
+ const size_t maxSpecificity)
1164
+ {
1165
+ if (complex2->minSpecificity() < maxSpecificity) return false;
1166
+ return complex2->isSuperselectorOf(complex1);
1167
+ }
1168
+ // EO dontTrimComplex
1169
+
1170
+ // ##########################################################################
1171
+ // Helper function used as callbacks on lists
1172
+ // ##########################################################################
1173
+ bool Extender::hasExactlyOne(const ComplexSelectorObj& vec)
1174
+ {
1175
+ return vec->length() == 1;
1176
+ }
1177
+ // EO hasExactlyOne
1178
+
1179
+ // ##########################################################################
1180
+ // Helper function used as callbacks on lists
1181
+ // ##########################################################################
1182
+ bool Extender::hasMoreThanOne(const ComplexSelectorObj& vec)
1183
+ {
1184
+ return vec->length() > 1;
1185
+ }
1186
+ // hasMoreThanOne
1187
+
1188
+ }