oreorenasass 3.4.4 → 3.4.5

Sign up to get free protection for your applications and to get access to all the features.
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