oreorenasass 3.4.4 → 3.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +50 -70
  4. data/Rakefile +5 -26
  5. data/VERSION +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/sass +1 -1
  8. data/bin/scss +1 -1
  9. data/lib/sass.rb +12 -19
  10. data/lib/sass/cache_stores/base.rb +2 -2
  11. data/lib/sass/cache_stores/chain.rb +1 -2
  12. data/lib/sass/cache_stores/filesystem.rb +5 -1
  13. data/lib/sass/cache_stores/memory.rb +1 -1
  14. data/lib/sass/cache_stores/null.rb +2 -2
  15. data/lib/sass/callbacks.rb +0 -1
  16. data/lib/sass/css.rb +13 -11
  17. data/lib/sass/engine.rb +173 -424
  18. data/lib/sass/environment.rb +58 -148
  19. data/lib/sass/error.rb +14 -11
  20. data/lib/sass/exec.rb +703 -5
  21. data/lib/sass/importers/base.rb +6 -49
  22. data/lib/sass/importers/filesystem.rb +19 -44
  23. data/lib/sass/logger.rb +4 -1
  24. data/lib/sass/logger/base.rb +4 -2
  25. data/lib/sass/logger/log_level.rb +7 -3
  26. data/lib/sass/media.rb +23 -20
  27. data/lib/sass/plugin.rb +7 -7
  28. data/lib/sass/plugin/compiler.rb +145 -304
  29. data/lib/sass/plugin/configuration.rb +23 -18
  30. data/lib/sass/plugin/merb.rb +1 -1
  31. data/lib/sass/plugin/staleness_checker.rb +3 -3
  32. data/lib/sass/repl.rb +3 -3
  33. data/lib/sass/script.rb +8 -35
  34. data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
  35. data/lib/sass/script/bool.rb +18 -0
  36. data/lib/sass/script/color.rb +606 -0
  37. data/lib/sass/script/css_lexer.rb +4 -8
  38. data/lib/sass/script/css_parser.rb +2 -5
  39. data/lib/sass/script/funcall.rb +245 -0
  40. data/lib/sass/script/functions.rb +408 -1491
  41. data/lib/sass/script/interpolation.rb +79 -0
  42. data/lib/sass/script/lexer.rb +68 -172
  43. data/lib/sass/script/list.rb +85 -0
  44. data/lib/sass/script/literal.rb +221 -0
  45. data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
  46. data/lib/sass/script/{value/null.rb → null.rb} +7 -14
  47. data/lib/sass/script/{value/number.rb → number.rb} +75 -152
  48. data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
  49. data/lib/sass/script/parser.rb +110 -245
  50. data/lib/sass/script/string.rb +51 -0
  51. data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
  52. data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
  53. data/lib/sass/script/variable.rb +58 -0
  54. data/lib/sass/scss/css_parser.rb +3 -9
  55. data/lib/sass/scss/parser.rb +421 -450
  56. data/lib/sass/scss/rx.rb +11 -19
  57. data/lib/sass/scss/static_parser.rb +7 -321
  58. data/lib/sass/selector.rb +194 -68
  59. data/lib/sass/selector/abstract_sequence.rb +14 -29
  60. data/lib/sass/selector/comma_sequence.rb +25 -108
  61. data/lib/sass/selector/sequence.rb +66 -159
  62. data/lib/sass/selector/simple.rb +25 -23
  63. data/lib/sass/selector/simple_sequence.rb +63 -173
  64. data/lib/sass/shared.rb +1 -1
  65. data/lib/sass/supports.rb +15 -13
  66. data/lib/sass/tree/charset_node.rb +1 -1
  67. data/lib/sass/tree/comment_node.rb +3 -3
  68. data/lib/sass/tree/css_import_node.rb +11 -11
  69. data/lib/sass/tree/debug_node.rb +2 -2
  70. data/lib/sass/tree/directive_node.rb +4 -21
  71. data/lib/sass/tree/each_node.rb +8 -8
  72. data/lib/sass/tree/extend_node.rb +7 -14
  73. data/lib/sass/tree/for_node.rb +4 -4
  74. data/lib/sass/tree/function_node.rb +4 -9
  75. data/lib/sass/tree/if_node.rb +1 -1
  76. data/lib/sass/tree/import_node.rb +5 -4
  77. data/lib/sass/tree/media_node.rb +14 -4
  78. data/lib/sass/tree/mixin_def_node.rb +4 -4
  79. data/lib/sass/tree/mixin_node.rb +8 -21
  80. data/lib/sass/tree/node.rb +12 -54
  81. data/lib/sass/tree/prop_node.rb +20 -39
  82. data/lib/sass/tree/return_node.rb +2 -3
  83. data/lib/sass/tree/root_node.rb +3 -19
  84. data/lib/sass/tree/rule_node.rb +22 -35
  85. data/lib/sass/tree/supports_node.rb +13 -0
  86. data/lib/sass/tree/trace_node.rb +1 -2
  87. data/lib/sass/tree/variable_node.rb +3 -9
  88. data/lib/sass/tree/visitors/base.rb +8 -5
  89. data/lib/sass/tree/visitors/check_nesting.rb +19 -49
  90. data/lib/sass/tree/visitors/convert.rb +56 -74
  91. data/lib/sass/tree/visitors/cssize.rb +74 -202
  92. data/lib/sass/tree/visitors/deep_copy.rb +5 -10
  93. data/lib/sass/tree/visitors/extend.rb +7 -7
  94. data/lib/sass/tree/visitors/perform.rb +185 -278
  95. data/lib/sass/tree/visitors/set_options.rb +6 -20
  96. data/lib/sass/tree/visitors/to_css.rb +81 -234
  97. data/lib/sass/tree/warn_node.rb +2 -2
  98. data/lib/sass/tree/while_node.rb +2 -2
  99. data/lib/sass/util.rb +152 -522
  100. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  101. data/lib/sass/util/subset_map.rb +3 -4
  102. data/lib/sass/util/test.rb +1 -0
  103. data/lib/sass/version.rb +22 -20
  104. data/test/Gemfile +3 -0
  105. data/test/Gemfile.lock +10 -0
  106. data/test/sass/cache_test.rb +20 -62
  107. data/test/sass/callbacks_test.rb +1 -1
  108. data/test/sass/conversion_test.rb +2 -296
  109. data/test/sass/css2sass_test.rb +4 -23
  110. data/test/sass/engine_test.rb +354 -411
  111. data/test/sass/exec_test.rb +2 -2
  112. data/test/sass/extend_test.rb +145 -324
  113. data/test/sass/functions_test.rb +86 -873
  114. data/test/sass/importer_test.rb +21 -241
  115. data/test/sass/logger_test.rb +1 -1
  116. data/test/sass/more_results/more_import.css +1 -1
  117. data/test/sass/plugin_test.rb +26 -16
  118. data/test/sass/results/compact.css +1 -1
  119. data/test/sass/results/complex.css +4 -4
  120. data/test/sass/results/expanded.css +1 -1
  121. data/test/sass/results/import.css +1 -1
  122. data/test/sass/results/import_charset_ibm866.css +2 -2
  123. data/test/sass/results/mixins.css +17 -17
  124. data/test/sass/results/nested.css +1 -1
  125. data/test/sass/results/parent_ref.css +2 -2
  126. data/test/sass/results/script.css +3 -3
  127. data/test/sass/results/scss_import.css +1 -1
  128. data/test/sass/script_conversion_test.rb +7 -36
  129. data/test/sass/script_test.rb +53 -485
  130. data/test/sass/scss/css_test.rb +28 -143
  131. data/test/sass/scss/rx_test.rb +4 -4
  132. data/test/sass/scss/scss_test.rb +325 -2119
  133. data/test/sass/templates/scss_import.scss +1 -2
  134. data/test/sass/test_helper.rb +1 -1
  135. data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
  136. data/test/sass/util/subset_map_test.rb +2 -2
  137. data/test/sass/util_test.rb +1 -86
  138. data/test/test_helper.rb +8 -37
  139. metadata +19 -66
  140. data/lib/sass/exec/base.rb +0 -187
  141. data/lib/sass/exec/sass_convert.rb +0 -264
  142. data/lib/sass/exec/sass_scss.rb +0 -424
  143. data/lib/sass/features.rb +0 -47
  144. data/lib/sass/script/tree.rb +0 -16
  145. data/lib/sass/script/tree/funcall.rb +0 -306
  146. data/lib/sass/script/tree/interpolation.rb +0 -118
  147. data/lib/sass/script/tree/list_literal.rb +0 -77
  148. data/lib/sass/script/tree/literal.rb +0 -45
  149. data/lib/sass/script/tree/map_literal.rb +0 -64
  150. data/lib/sass/script/tree/selector.rb +0 -26
  151. data/lib/sass/script/tree/variable.rb +0 -57
  152. data/lib/sass/script/value.rb +0 -11
  153. data/lib/sass/script/value/base.rb +0 -240
  154. data/lib/sass/script/value/bool.rb +0 -35
  155. data/lib/sass/script/value/color.rb +0 -680
  156. data/lib/sass/script/value/helpers.rb +0 -262
  157. data/lib/sass/script/value/list.rb +0 -113
  158. data/lib/sass/script/value/map.rb +0 -70
  159. data/lib/sass/script/value/string.rb +0 -97
  160. data/lib/sass/selector/pseudo.rb +0 -256
  161. data/lib/sass/source/map.rb +0 -210
  162. data/lib/sass/source/position.rb +0 -39
  163. data/lib/sass/source/range.rb +0 -41
  164. data/lib/sass/stack.rb +0 -120
  165. data/lib/sass/tree/at_root_node.rb +0 -83
  166. data/lib/sass/tree/error_node.rb +0 -18
  167. data/lib/sass/tree/keyframe_rule_node.rb +0 -15
  168. data/lib/sass/util/cross_platform_random.rb +0 -19
  169. data/lib/sass/util/normalized_map.rb +0 -130
  170. data/lib/sass/util/ordered_hash.rb +0 -192
  171. data/test/sass/compiler_test.rb +0 -232
  172. data/test/sass/encoding_test.rb +0 -219
  173. data/test/sass/source_map_test.rb +0 -977
  174. data/test/sass/superselector_test.rb +0 -191
  175. data/test/sass/util/normalized_map_test.rb +0 -51
  176. data/test/sass/value_helpers_test.rb +0 -179
data/lib/sass/scss/rx.rb CHANGED
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  module Sass
3
2
  module SCSS
4
3
  # A module containing regular expressions used
@@ -23,7 +22,7 @@ module Sass
23
22
  out << escape_char(value.slice!(0...1))
24
23
  end
25
24
  out << value.gsub(/[^a-zA-Z0-9_-]/) {|c| escape_char c}
26
- out
25
+ return out
27
26
  end
28
27
 
29
28
  # Escapes a single character for a CSS identifier.
@@ -33,7 +32,7 @@ module Sass
33
32
  # @private
34
33
  def self.escape_char(c)
35
34
  return "\\%06x" % Sass::Util.ord(c) unless c =~ /[ -\/:-~]/
36
- "\\#{c}"
35
+ return "\\#{c}"
37
36
  end
38
37
 
39
38
  # Creates a Regexp from a plain text string,
@@ -64,9 +63,9 @@ module Sass
64
63
  STRING1 = /\"((?:[^\n\r\f\\"]|\\#{NL}|#{ESCAPE})*)\"/
65
64
  STRING2 = /\'((?:[^\n\r\f\\']|\\#{NL}|#{ESCAPE})*)\'/
66
65
 
67
- IDENT = /-*#{NMSTART}#{NMCHAR}*/
66
+ IDENT = /-?#{NMSTART}#{NMCHAR}*/
68
67
  NAME = /#{NMCHAR}+/
69
- NUM = //
68
+ NUM = /[0-9]+|[0-9]*\.[0-9]+/
70
69
  STRING = /#{STRING1}|#{STRING2}/
71
70
  URLCHAR = /[#%&*-~]|#{NONASCII}|#{ESCAPE}/
72
71
  URL = /(#{URLCHAR}*)/
@@ -81,8 +80,8 @@ module Sass
81
80
 
82
81
  S = /[ \t\r\n\f]+/
83
82
 
84
- COMMENT = %r{/\*([^*]|\*+[^/*])*\**\*/}
85
- SINGLE_LINE_COMMENT = %r{//.*(\n[ \t]*//.*)*}
83
+ COMMENT = /\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\//
84
+ SINGLE_LINE_COMMENT = /\/\/.*(\n[ \t]*\/\/.*)*/
86
85
 
87
86
  CDO = quote("<!--")
88
87
  CDC = quote("-->")
@@ -95,10 +94,9 @@ module Sass
95
94
  HASH = /##{NAME}/
96
95
 
97
96
  IMPORTANT = /!#{W}important/i
97
+ DEFAULT = /!#{W}default/i
98
98
 
99
- UNITLESS_NUMBER = /(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?\d+)?/
100
- NUMBER = /#{UNITLESS_NUMBER}(?:#{IDENT}|%)?/
101
- PERCENTAGE = /#{UNITLESS_NUMBER}%/
99
+ NUMBER = /#{NUM}(?:#{IDENT}|%)?/
102
100
 
103
101
  URI = /url\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
104
102
  FUNCTION = /#{IDENT}\(/
@@ -121,21 +119,15 @@ module Sass
121
119
  INTERP_START = /#\{/
122
120
  ANY = /:(-[-\w]+-)?any\(/i
123
121
  OPTIONAL = /!#{W}optional/i
124
- IDENT_START = /-|#{NMSTART}/
125
-
126
- # A unit is like an IDENT, but disallows a hyphen followed by a digit.
127
- # This allows "1px-2px" to be interpreted as subtraction rather than "1"
128
- # with the unit "px-2px". It also allows "%".
129
- UNIT = /-?#{NMSTART}(?:[a-zA-Z0-9_]|#{NONASCII}|#{ESCAPE}|-(?!\d))*|%/
130
122
 
131
123
  IDENT_HYPHEN_INTERP = /-(#\{)/
132
- STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|#{ESCAPE})*)\"/
133
- STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|#{ESCAPE})*)\'/
124
+ STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|\\#{NL}|#{ESCAPE})*)\"/
125
+ STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|\\#{NL}|#{ESCAPE})*)\'/
134
126
  STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
135
127
 
136
128
  STATIC_COMPONENT = /#{IDENT}|#{STRING_NOINTERP}|#{HEXCOLOR}|[+-]?#{NUMBER}|\!important/i
137
129
  STATIC_VALUE = /#{STATIC_COMPONENT}(\s*[\s,\/]\s*#{STATIC_COMPONENT})*([;}])/i
138
- STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){1,50}([{])/i
130
+ STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){0,50}([{])/i
139
131
  end
140
132
  end
141
133
  end
@@ -24,343 +24,29 @@ module Sass
24
24
  seq
25
25
  end
26
26
 
27
- # Parses a static at-root query.
28
- #
29
- # @return [(Symbol, Array<String>)] The type of the query
30
- # (`:with` or `:without`) and the values that are being filtered.
31
- # @raise [Sass::SyntaxError] if there's a syntax error in the query,
32
- # or if it doesn't take up the entire input string.
33
- def parse_static_at_root_query
34
- init_scanner!
35
- tok!(/\(/); ss
36
- type = tok!(/\b(without|with)\b/).to_sym; ss
37
- tok!(/:/); ss
38
- directives = expr!(:at_root_directive_list); ss
39
- tok!(/\)/)
40
- expected("@at-root query list") unless @scanner.eos?
41
- return type, directives
42
- end
43
-
44
- def parse_keyframes_selector
45
- init_scanner!
46
- sel = expr!(:keyframes_selector)
47
- expected("keyframes selector") unless @scanner.eos?
48
- sel
49
- end
50
-
51
- # @see Parser#initialize
52
- # @param allow_parent_ref [Boolean] Whether to allow the
53
- # parent-reference selector, `&`, when parsing the document.
54
- # @comment
55
- # rubocop:disable ParameterLists
56
- def initialize(str, filename, importer, line = 1, offset = 1, allow_parent_ref = true)
57
- # rubocop:enable ParameterLists
58
- super(str, filename, importer, line, offset)
59
- @allow_parent_ref = allow_parent_ref
60
- end
61
-
62
27
  private
63
28
 
64
29
  def moz_document_function
65
- val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(!:allow_var)
66
- return unless val
30
+ return unless val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) ||
31
+ function(!:allow_var)
67
32
  ss
68
33
  [val]
69
34
  end
70
35
 
71
36
  def variable; nil; end
72
37
  def script_value; nil; end
73
- def interpolation(warn_for_color = false); nil; end
38
+ def interpolation; nil; end
74
39
  def var_expr; nil; end
75
- def interp_string; (s = tok(STRING)) && [s]; end
76
- def interp_uri; (s = tok(URI)) && [s]; end
77
- def interp_ident(ident = IDENT); (s = tok(ident)) && [s]; end
40
+ def interp_string; s = tok(STRING) and [s]; end
41
+ def interp_uri; s = tok(URI) and [s]; end
42
+ def interp_ident(ident = IDENT); s = tok(ident) and [s]; end
78
43
  def use_css_import?; true; end
79
44
 
80
- def special_directive(name, start_pos)
45
+ def special_directive(name)
81
46
  return unless %w[media import charset -moz-document].include?(name)
82
47
  super
83
48
  end
84
49
 
85
- def selector_comma_sequence
86
- sel = selector
87
- return unless sel
88
- selectors = [sel]
89
- ws = ''
90
- while tok(/,/)
91
- ws << str {ss}
92
- if (sel = selector)
93
- selectors << sel
94
- if ws.include?("\n")
95
- selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members)
96
- end
97
- ws = ''
98
- end
99
- end
100
- Selector::CommaSequence.new(selectors)
101
- end
102
-
103
- def selector_string
104
- sel = selector
105
- return unless sel
106
- sel.to_s
107
- end
108
-
109
- def selector
110
- start_pos = source_position
111
- # The combinator here allows the "> E" hack
112
- val = combinator || simple_selector_sequence
113
- return unless val
114
- nl = str {ss}.include?("\n")
115
- res = []
116
- res << val
117
- res << "\n" if nl
118
-
119
- while (val = combinator || simple_selector_sequence)
120
- res << val
121
- res << "\n" if str {ss}.include?("\n")
122
- end
123
- seq = Selector::Sequence.new(res.compact)
124
-
125
- if seq.members.any? {|sseq| sseq.is_a?(Selector::SimpleSequence) && sseq.subject?}
126
- location = " of #{@filename}" if @filename
127
- Sass::Util.sass_warn <<MESSAGE
128
- DEPRECATION WARNING on line #{start_pos.line}, column #{start_pos.offset}#{location}:
129
- The subject selector operator "!" is deprecated and will be removed in a future release.
130
- This operator has been replaced by ":has()" in the CSS spec.
131
- For example: #{seq.subjectless}
132
- MESSAGE
133
- end
134
-
135
- seq
136
- end
137
-
138
- def combinator
139
- tok(PLUS) || tok(GREATER) || tok(TILDE) || reference_combinator
140
- end
141
-
142
- def reference_combinator
143
- return unless tok(/\//)
144
- res = '/'
145
- ns, name = expr!(:qualified_name)
146
- res << ns << '|' if ns
147
- res << name << tok!(/\//)
148
- res
149
- end
150
-
151
- def simple_selector_sequence
152
- start_pos = source_position
153
- e = element_name || id_selector || class_selector || placeholder_selector || attrib ||
154
- pseudo || parent_selector
155
- return unless e
156
- res = [e]
157
-
158
- # The tok(/\*/) allows the "E*" hack
159
- while (v = id_selector || class_selector || placeholder_selector ||
160
- attrib || pseudo || (tok(/\*/) && Selector::Universal.new(nil)))
161
- res << v
162
- end
163
-
164
- pos = @scanner.pos
165
- line = @line
166
- if (sel = str? {simple_selector_sequence})
167
- @scanner.pos = pos
168
- @line = line
169
- begin
170
- # If we see "*E", don't force a throw because this could be the
171
- # "*prop: val" hack.
172
- expected('"{"') if res.length == 1 && res[0].is_a?(Selector::Universal)
173
- throw_error {expected('"{"')}
174
- rescue Sass::SyntaxError => e
175
- e.message << "\n\n\"#{sel}\" may only be used at the beginning of a compound selector."
176
- raise e
177
- end
178
- end
179
-
180
- Selector::SimpleSequence.new(res, tok(/!/), range(start_pos))
181
- end
182
-
183
- def parent_selector
184
- return unless @allow_parent_ref && tok(/&/)
185
- Selector::Parent.new(tok(NAME))
186
- end
187
-
188
- def class_selector
189
- return unless tok(/\./)
190
- @expected = "class name"
191
- Selector::Class.new(tok!(IDENT))
192
- end
193
-
194
- def id_selector
195
- return unless tok(/#(?!\{)/)
196
- @expected = "id name"
197
- Selector::Id.new(tok!(NAME))
198
- end
199
-
200
- def placeholder_selector
201
- return unless tok(/%/)
202
- @expected = "placeholder name"
203
- Selector::Placeholder.new(tok!(IDENT))
204
- end
205
-
206
- def element_name
207
- ns, name = Sass::Util.destructure(qualified_name(:allow_star_name))
208
- return unless ns || name
209
-
210
- if name == '*'
211
- Selector::Universal.new(ns)
212
- else
213
- Selector::Element.new(name, ns)
214
- end
215
- end
216
-
217
- def qualified_name(allow_star_name = false)
218
- name = tok(IDENT) || tok(/\*/) || (tok?(/\|/) && "")
219
- return unless name
220
- return nil, name unless tok(/\|/)
221
-
222
- return name, tok!(IDENT) unless allow_star_name
223
- @expected = "identifier or *"
224
- return name, tok(IDENT) || tok!(/\*/)
225
- end
226
-
227
- def attrib
228
- return unless tok(/\[/)
229
- ss
230
- ns, name = attrib_name!
231
- ss
232
-
233
- op = tok(/=/) ||
234
- tok(INCLUDES) ||
235
- tok(DASHMATCH) ||
236
- tok(PREFIXMATCH) ||
237
- tok(SUFFIXMATCH) ||
238
- tok(SUBSTRINGMATCH)
239
- if op
240
- @expected = "identifier or string"
241
- ss
242
- val = tok(IDENT) || tok!(STRING)
243
- ss
244
- end
245
- flags = tok(IDENT) || tok(STRING)
246
- tok!(/\]/)
247
-
248
- Selector::Attribute.new(name, ns, op, val, flags)
249
- end
250
-
251
- def attrib_name!
252
- if (name_or_ns = tok(IDENT))
253
- # E, E|E
254
- if tok(/\|(?!=)/)
255
- ns = name_or_ns
256
- name = tok(IDENT)
257
- else
258
- name = name_or_ns
259
- end
260
- else
261
- # *|E or |E
262
- ns = tok(/\*/) || ""
263
- tok!(/\|/)
264
- name = tok!(IDENT)
265
- end
266
- return ns, name
267
- end
268
-
269
- SELECTOR_PSEUDO_CLASSES = %w[not matches current any has host host-context].to_set
270
-
271
- PREFIXED_SELECTOR_PSEUDO_CLASSES = %w[nth-child nth-last-child].to_set
272
-
273
- def pseudo
274
- s = tok(/::?/)
275
- return unless s
276
- @expected = "pseudoclass or pseudoelement"
277
- name = tok!(IDENT)
278
- if tok(/\(/)
279
- ss
280
- deprefixed = deprefix(name)
281
- if s == ':' && SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
282
- sel = selector_comma_sequence
283
- elsif s == ':' && PREFIXED_SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
284
- arg, sel = prefixed_selector_pseudo
285
- else
286
- arg = expr!(:pseudo_args)
287
- end
288
-
289
- tok!(/\)/)
290
- end
291
- Selector::Pseudo.new(s == ':' ? :class : :element, name, arg, sel)
292
- end
293
-
294
- def pseudo_args
295
- arg = expr!(:pseudo_expr)
296
- while tok(/,/)
297
- arg << ',' << str {ss}
298
- arg.concat expr!(:pseudo_expr)
299
- end
300
- arg
301
- end
302
-
303
- def pseudo_expr
304
- res = pseudo_expr_token
305
- return unless res
306
- res << str {ss}
307
- while (e = pseudo_expr_token)
308
- res << e << str {ss}
309
- end
310
- res
311
- end
312
-
313
- def pseudo_expr_token
314
- tok(PLUS) || tok(/[-*]/) || tok(NUMBER) || tok(STRING) || tok(IDENT)
315
- end
316
-
317
- def prefixed_selector_pseudo
318
- prefix = str do
319
- expr = str {expr!(:a_n_plus_b)}
320
- ss
321
- return expr, nil unless tok(/of/)
322
- ss
323
- end
324
- return prefix, expr!(:selector_comma_sequence)
325
- end
326
-
327
- def a_n_plus_b
328
- if (parity = tok(/even|odd/i))
329
- return parity
330
- end
331
-
332
- if tok(/[+-]?[0-9]+/)
333
- ss
334
- return true unless tok(/n/)
335
- else
336
- return unless tok(/[+-]?n/i)
337
- end
338
- ss
339
-
340
- return true unless tok(/[+-]/)
341
- ss
342
- @expected = "number"
343
- tok!(/[0-9]+/)
344
- true
345
- end
346
-
347
- def keyframes_selector
348
- ss
349
- str do
350
- return unless keyframes_selector_component
351
- ss
352
- while tok(/,/)
353
- ss
354
- expr!(:keyframes_selector_component)
355
- ss
356
- end
357
- end
358
- end
359
-
360
- def keyframes_selector_component
361
- tok(/from|to/i) || tok(PERCENTAGE)
362
- end
363
-
364
50
  @sass_script_parser = Class.new(Sass::Script::CssParser)
365
51
  @sass_script_parser.send(:include, ScriptParser)
366
52
  end
data/lib/sass/selector.rb CHANGED
@@ -1,14 +1,13 @@
1
1
  require 'sass/selector/simple'
2
2
  require 'sass/selector/abstract_sequence'
3
3
  require 'sass/selector/comma_sequence'
4
- require 'sass/selector/pseudo'
5
4
  require 'sass/selector/sequence'
6
5
  require 'sass/selector/simple_sequence'
7
6
 
8
7
  module Sass
9
8
  # A namespace for nodes in the parse tree for selectors.
10
9
  #
11
- # {CommaSequence} is the toplevel selector,
10
+ # {CommaSequence} is the toplevel seelctor,
12
11
  # representing a comma-separated sequence of {Sequence}s,
13
12
  # such as `foo bar, baz bang`.
14
13
  # {Sequence} is the next level,
@@ -22,25 +21,17 @@ module Sass
22
21
  # The base used for calculating selector specificity. The spec says this
23
22
  # should be "sufficiently high"; it's extremely unlikely that any single
24
23
  # selector sequence will contain 1,000 simple selectors.
24
+ #
25
+ # @type [Fixnum]
25
26
  SPECIFICITY_BASE = 1_000
26
27
 
27
28
  # A parent-referencing selector (`&` in Sass).
28
29
  # The function of this is to be replaced by the parent selector
29
30
  # in the nested hierarchy.
30
31
  class Parent < Simple
31
- # The identifier following the `&`. `nil` indicates no suffix.
32
- #
33
- # @return [String, nil]
34
- attr_reader :suffix
35
-
36
- # @param name [String, nil] See \{#suffix}
37
- def initialize(suffix = nil)
38
- @suffix = suffix
39
- end
40
-
41
- # @see Selector#to_s
42
- def to_s
43
- "&" + (@suffix || '')
32
+ # @see Selector#to_a
33
+ def to_a
34
+ ["&"]
44
35
  end
45
36
 
46
37
  # Always raises an exception.
@@ -56,17 +47,17 @@ module Sass
56
47
  class Class < Simple
57
48
  # The class name.
58
49
  #
59
- # @return [String]
50
+ # @return [Array<String, Sass::Script::Node>]
60
51
  attr_reader :name
61
52
 
62
- # @param name [String] The class name
53
+ # @param name [Array<String, Sass::Script::Node>] The class name
63
54
  def initialize(name)
64
55
  @name = name
65
56
  end
66
57
 
67
- # @see Selector#to_s
68
- def to_s
69
- "." + @name
58
+ # @see Selector#to_a
59
+ def to_a
60
+ [".", *@name]
70
61
  end
71
62
 
72
63
  # @see AbstractSequence#specificity
@@ -79,17 +70,17 @@ module Sass
79
70
  class Id < Simple
80
71
  # The id name.
81
72
  #
82
- # @return [String]
73
+ # @return [Array<String, Sass::Script::Node>]
83
74
  attr_reader :name
84
75
 
85
- # @param name [String] The id name
76
+ # @param name [Array<String, Sass::Script::Node>] The id name
86
77
  def initialize(name)
87
78
  @name = name
88
79
  end
89
80
 
90
- # @see Selector#to_s
91
- def to_s
92
- "#" + @name
81
+ # @see Selector#to_a
82
+ def to_a
83
+ ["#", *@name]
93
84
  end
94
85
 
95
86
  # Returns `nil` if `sels` contains an {Id} selector
@@ -97,7 +88,7 @@ module Sass
97
88
  #
98
89
  # @see Selector#unify
99
90
  def unify(sels)
100
- return if sels.any? {|sel2| sel2.is_a?(Id) && name != sel2.name}
91
+ return if sels.any? {|sel2| sel2.is_a?(Id) && self.name != sel2.name}
101
92
  super
102
93
  end
103
94
 
@@ -114,17 +105,17 @@ module Sass
114
105
  class Placeholder < Simple
115
106
  # The placeholder name.
116
107
  #
117
- # @return [String]
108
+ # @return [Array<String, Sass::Script::Node>]
118
109
  attr_reader :name
119
110
 
120
- # @param name [String] The placeholder name
111
+ # @param name [Array<String, Sass::Script::Node>] The placeholder name
121
112
  def initialize(name)
122
113
  @name = name
123
114
  end
124
115
 
125
- # @see Selector#to_s
126
- def to_s
127
- "%" + @name
116
+ # @see Selector#to_a
117
+ def to_a
118
+ ["%", *@name]
128
119
  end
129
120
 
130
121
  # @see AbstractSequence#specificity
@@ -135,20 +126,22 @@ module Sass
135
126
 
136
127
  # A universal selector (`*` in CSS).
137
128
  class Universal < Simple
138
- # The selector namespace. `nil` means the default namespace, `""` means no
139
- # namespace, `"*"` means any namespace.
129
+ # The selector namespace.
130
+ # `nil` means the default namespace,
131
+ # `[""]` means no namespace,
132
+ # `["*"]` means any namespace.
140
133
  #
141
- # @return [String, nil]
134
+ # @return [Array<String, Sass::Script::Node>, nil]
142
135
  attr_reader :namespace
143
136
 
144
- # @param namespace [String, nil] See \{#namespace}
137
+ # @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
145
138
  def initialize(namespace)
146
139
  @namespace = namespace
147
140
  end
148
141
 
149
- # @see Selector#to_s
150
- def to_s
151
- @namespace ? "#{@namespace}|*" : "*"
142
+ # @see Selector#to_a
143
+ def to_a
144
+ @namespace ? @namespace + ["|*"] : ["*"]
152
145
  end
153
146
 
154
147
  # Unification of a universal selector is somewhat complicated,
@@ -182,7 +175,7 @@ module Sass
182
175
  when Universal; :universal
183
176
  when Element; sels.first.name
184
177
  else
185
- return [self] + sels unless namespace.nil? || namespace == '*'
178
+ return [self] + sels unless namespace.nil? || namespace == ['*']
186
179
  return sels unless sels.empty?
187
180
  return [self]
188
181
  end
@@ -202,25 +195,27 @@ module Sass
202
195
  class Element < Simple
203
196
  # The element name.
204
197
  #
205
- # @return [String]
198
+ # @return [Array<String, Sass::Script::Node>]
206
199
  attr_reader :name
207
200
 
208
- # The selector namespace. `nil` means the default namespace, `""` means no
209
- # namespace, `"*"` means any namespace.
201
+ # The selector namespace.
202
+ # `nil` means the default namespace,
203
+ # `[""]` means no namespace,
204
+ # `["*"]` means any namespace.
210
205
  #
211
- # @return [String, nil]
206
+ # @return [Array<String, Sass::Script::Node>, nil]
212
207
  attr_reader :namespace
213
208
 
214
- # @param name [String] The element name
215
- # @param namespace [String, nil] See \{#namespace}
209
+ # @param name [Array<String, Sass::Script::Node>] The element name
210
+ # @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
216
211
  def initialize(name, namespace)
217
212
  @name = name
218
213
  @namespace = namespace
219
214
  end
220
215
 
221
- # @see Selector#to_s
222
- def to_s
223
- @namespace ? "#{@namespace}|#{@name}" : @name
216
+ # @see Selector#to_a
217
+ def to_a
218
+ @namespace ? @namespace + ["|"] + @name : @name
224
219
  end
225
220
 
226
221
  # Unification of an element selector is somewhat complicated,
@@ -263,17 +258,45 @@ module Sass
263
258
  end
264
259
  end
265
260
 
261
+ # Selector interpolation (`#{}` in Sass).
262
+ class Interpolation < Simple
263
+ # The script to run.
264
+ #
265
+ # @return [Sass::Script::Node]
266
+ attr_reader :script
267
+
268
+ # @param script [Sass::Script::Node] The script to run
269
+ def initialize(script)
270
+ @script = script
271
+ end
272
+
273
+ # @see Selector#to_a
274
+ def to_a
275
+ [@script]
276
+ end
277
+
278
+ # Always raises an exception.
279
+ #
280
+ # @raise [Sass::SyntaxError] Interpolation selectors should be resolved before unification
281
+ # @see Selector#unify
282
+ def unify(sels)
283
+ raise Sass::SyntaxError.new("[BUG] Cannot unify interpolation selectors.")
284
+ end
285
+ end
286
+
266
287
  # An attribute selector (e.g. `[href^="http://"]`).
267
288
  class Attribute < Simple
268
289
  # The attribute name.
269
290
  #
270
- # @return [Array<String, Sass::Script::Tree::Node>]
291
+ # @return [Array<String, Sass::Script::Node>]
271
292
  attr_reader :name
272
293
 
273
- # The attribute namespace. `nil` means the default namespace, `""` means
274
- # no namespace, `"*"` means any namespace.
294
+ # The attribute namespace.
295
+ # `nil` means the default namespace,
296
+ # `[""]` means no namespace,
297
+ # `["*"]` means any namespace.
275
298
  #
276
- # @return [String, nil]
299
+ # @return [Array<String, Sass::Script::Node>, nil]
277
300
  attr_reader :namespace
278
301
 
279
302
  # The matching operator, e.g. `"="` or `"^="`.
@@ -283,23 +306,20 @@ module Sass
283
306
 
284
307
  # The right-hand side of the operator.
285
308
  #
286
- # @return [String]
309
+ # @return [Array<String, Sass::Script::Node>]
287
310
  attr_reader :value
288
311
 
289
312
  # Flags for the attribute selector (e.g. `i`).
290
313
  #
291
- # @return [String]
314
+ # @return [Array<String, Sass::Script::Node>]
292
315
  attr_reader :flags
293
316
 
294
- # @param name [String] The attribute name
295
- # @param namespace [String, nil] See \{#namespace}
317
+ # @param name [Array<String, Sass::Script::Node>] The attribute name
318
+ # @param namespace [Array<String, Sass::Script::Node>, nil] See \{#namespace}
296
319
  # @param operator [String] The matching operator, e.g. `"="` or `"^="`
297
- # @param value [String] See \{#value}
298
- # @param flags [String] See \{#flags}
299
- # @comment
300
- # rubocop:disable ParameterLists
320
+ # @param value [Array<String, Sass::Script::Node>] See \{#value}
321
+ # @param value [Array<String, Sass::Script::Node>] See \{#flags}
301
322
  def initialize(name, namespace, operator, value, flags)
302
- # rubocop:enable ParameterLists
303
323
  @name = name
304
324
  @namespace = namespace
305
325
  @operator = operator
@@ -307,13 +327,13 @@ module Sass
307
327
  @flags = flags
308
328
  end
309
329
 
310
- # @see Selector#to_s
311
- def to_s
312
- res = "["
313
- res << @namespace << "|" if @namespace
314
- res << @name
315
- res << @operator << @value if @value
316
- res << " " << @flags if @flags
330
+ # @see Selector#to_a
331
+ def to_a
332
+ res = ["["]
333
+ res.concat(@namespace) << "|" if @namespace
334
+ res.concat @name
335
+ (res << @operator).concat @value if @value
336
+ (res << " ").concat @flags if @flags
317
337
  res << "]"
318
338
  end
319
339
 
@@ -322,5 +342,111 @@ module Sass
322
342
  SPECIFICITY_BASE
323
343
  end
324
344
  end
345
+
346
+ # A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`) selector.
347
+ # It can have arguments (e.g. `:nth-child(2n+1)`).
348
+ class Pseudo < Simple
349
+ # Some psuedo-class-syntax selectors are actually considered
350
+ # pseudo-elements and must be treated differently. This is a list of such
351
+ # selectors
352
+ #
353
+ # @return [Array<String>]
354
+ ACTUALLY_ELEMENTS = %w[after before first-line first-letter]
355
+
356
+ # Like \{#type}, but returns the type of selector this looks like, rather
357
+ # than the type it is semantically. This only differs from type for
358
+ # selectors in \{ACTUALLY\_ELEMENTS}.
359
+ #
360
+ # @return [Symbol]
361
+ attr_reader :syntactic_type
362
+
363
+ # The name of the selector.
364
+ #
365
+ # @return [Array<String, Sass::Script::Node>]
366
+ attr_reader :name
367
+
368
+ # The argument to the selector,
369
+ # or `nil` if no argument was given.
370
+ #
371
+ # This may include SassScript nodes that will be run during resolution.
372
+ # Note that this should not include SassScript nodes
373
+ # after resolution has taken place.
374
+ #
375
+ # @return [Array<String, Sass::Script::Node>, nil]
376
+ attr_reader :arg
377
+
378
+ # @param type [Symbol] See \{#type}
379
+ # @param name [Array<String, Sass::Script::Node>] The name of the selector
380
+ # @param arg [nil, Array<String, Sass::Script::Node>] The argument to the selector,
381
+ # or nil if no argument was given
382
+ def initialize(type, name, arg)
383
+ @syntactic_type = type
384
+ @name = name
385
+ @arg = arg
386
+ end
387
+
388
+ # The type of the selector. `:class` if this is a pseudoclass selector,
389
+ # `:element` if it's a pseudoelement.
390
+ #
391
+ # @return [Symbol]
392
+ def type
393
+ ACTUALLY_ELEMENTS.include?(name.first) ? :element : syntactic_type
394
+ end
395
+
396
+ # @see Selector#to_a
397
+ def to_a
398
+ res = [syntactic_type == :class ? ":" : "::"] + @name
399
+ (res << "(").concat(Sass::Util.strip_string_array(@arg)) << ")" if @arg
400
+ res
401
+ end
402
+
403
+ # Returns `nil` if this is a pseudoelement selector
404
+ # and `sels` contains a pseudoelement selector different than this one.
405
+ #
406
+ # @see Selector#unify
407
+ def unify(sels)
408
+ return if type == :element && sels.any? do |sel|
409
+ sel.is_a?(Pseudo) && sel.type == :element &&
410
+ (sel.name != self.name || sel.arg != self.arg)
411
+ end
412
+ super
413
+ end
414
+
415
+ # @see AbstractSequence#specificity
416
+ def specificity
417
+ type == :class ? SPECIFICITY_BASE : 1
418
+ end
419
+ end
420
+
421
+ # A pseudoclass selector whose argument is itself a selector
422
+ # (e.g. `:not(.foo)` or `:-moz-all(.foo, .bar)`).
423
+ class SelectorPseudoClass < Simple
424
+ # The name of the pseudoclass.
425
+ #
426
+ # @return [String]
427
+ attr_reader :name
428
+
429
+ # The selector argument.
430
+ #
431
+ # @return [Selector::Sequence]
432
+ attr_reader :selector
433
+
434
+ # @param [String] The name of the pseudoclass
435
+ # @param [Selector::CommaSequence] The selector argument
436
+ def initialize(name, selector)
437
+ @name = name
438
+ @selector = selector
439
+ end
440
+
441
+ # @see Selector#to_a
442
+ def to_a
443
+ [":", @name, "("] + @selector.to_a + [")"]
444
+ end
445
+
446
+ # @see AbstractSequence#specificity
447
+ def specificity
448
+ SPECIFICITY_BASE
449
+ end
450
+ end
325
451
  end
326
452
  end