sass 3.2.0.alpha.74 → 3.2.0.alpha.75

Sign up to get free protection for your applications and to get access to all the features.
data/REVISION CHANGED
@@ -1 +1 @@
1
- db51415a323a4fc284f38881ac839f3bbf5e7e31
1
+ b551f92303175e7651794dcf5a70f6148042bf69
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.2.0.alpha.74
1
+ 3.2.0.alpha.75
@@ -77,14 +77,29 @@ module Sass
77
77
  # @return [Tree::Node] The root node of the parsed tree
78
78
  def build_tree
79
79
  root = Sass::SCSS::CssParser.new(@template, @options[:filename]).parse
80
+ parse_selectors root
80
81
  expand_commas root
82
+ nest_seqs root
81
83
  parent_ref_rules root
82
- remove_parent_refs root
83
84
  flatten_rules root
84
85
  fold_commas root
86
+ dump_selectors root
85
87
  root
86
88
  end
87
89
 
90
+ # Parse all the selectors in the document and assign them to
91
+ # {Sass::Tree::RuleNode#parsed_rules}.
92
+ #
93
+ # @param root [Tree::Node] The parent node
94
+ def parse_selectors(root)
95
+ root.children.each do |child|
96
+ next parse_selectors(child) if child.is_a?(Tree::DirectiveNode)
97
+ next unless child.is_a?(Tree::RuleNode)
98
+ parser = Sass::SCSS::CssParser.new(child.rule.first, child.filename, child.line)
99
+ child.parsed_rules = parser.parse_selector
100
+ end
101
+ end
102
+
88
103
  # Transform
89
104
  #
90
105
  # foo, bar, baz
@@ -102,13 +117,14 @@ module Sass
102
117
  # @param root [Tree::Node] The parent node
103
118
  def expand_commas(root)
104
119
  root.children.map! do |child|
105
- unless child.is_a?(Tree::RuleNode) && child.rule.first.include?(',')
120
+ # child.parsed_rules.members.size > 1 iff the rule contains a comma
121
+ unless child.is_a?(Tree::RuleNode) && child.parsed_rules.members.size > 1
106
122
  expand_commas(child) if child.is_a?(Tree::DirectiveNode)
107
123
  next child
108
124
  end
109
- child.rule.first.split(',').map do |rule|
110
- next if rule.strip.empty?
111
- node = Tree::RuleNode.new([rule.strip])
125
+ child.parsed_rules.members.map do |seq|
126
+ node = Tree::RuleNode.new([])
127
+ node.parsed_rules = make_cseq(seq)
112
128
  node.children = child.children
113
129
  node
114
130
  end
@@ -116,22 +132,7 @@ module Sass
116
132
  root.children.flatten!
117
133
  end
118
134
 
119
- # Make rules use parent refs so that
120
- #
121
- # foo
122
- # color: green
123
- # foo.bar
124
- # color: blue
125
- #
126
- # becomes
127
- #
128
- # foo
129
- # color: green
130
- # &.bar
131
- # color: blue
132
- #
133
- # This has the side effect of nesting rules,
134
- # so that
135
+ # Make rules use nesting so that
135
136
  #
136
137
  # foo
137
138
  # color: green
@@ -144,28 +145,31 @@ module Sass
144
145
  #
145
146
  # foo
146
147
  # color: green
147
- # & bar
148
+ # bar
148
149
  # color: red
149
- # & baz
150
+ # baz
150
151
  # color: blue
151
152
  #
152
153
  # @param root [Tree::Node] The parent node
153
- def parent_ref_rules(root)
154
+ def nest_seqs(root)
154
155
  current_rule = nil
155
156
  root.children.map! do |child|
156
157
  unless child.is_a?(Tree::RuleNode)
157
- parent_ref_rules(child) if child.is_a?(Tree::DirectiveNode)
158
+ nest_seqs(child) if child.is_a?(Tree::DirectiveNode)
158
159
  next child
159
160
  end
160
161
 
161
- first, rest = child.rule.first.scan(/\A(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?\Z/m).first
162
+ seq = first_seq(child)
163
+ seq.members.reject! {|sseq| sseq == "\n"}
164
+ first, rest = seq.members.first, seq.members[1..-1]
162
165
 
163
- if current_rule.nil? || current_rule.rule.first != first
164
- current_rule = Tree::RuleNode.new([first])
166
+ if current_rule.nil? || first_sseq(current_rule) != first
167
+ current_rule = Tree::RuleNode.new([])
168
+ current_rule.parsed_rules = make_seq(first)
165
169
  end
166
170
 
167
- if rest
168
- child.rule = ["&" + rest]
171
+ unless rest.empty?
172
+ child.parsed_rules = make_seq(*rest)
169
173
  current_rule << child
170
174
  else
171
175
  current_rule.children += child.children
@@ -176,32 +180,57 @@ module Sass
176
180
  root.children.compact!
177
181
  root.children.uniq!
178
182
 
179
- root.children.each { |v| parent_ref_rules(v) }
183
+ root.children.each {|v| nest_seqs(v)}
180
184
  end
181
185
 
182
- # Remove useless parent refs so that
186
+ # Make rules use parent refs so that
183
187
  #
184
188
  # foo
185
- # & bar
186
- # color: blue
189
+ # color: green
190
+ # foo.bar
191
+ # color: blue
187
192
  #
188
193
  # becomes
189
194
  #
190
195
  # foo
191
- # bar
196
+ # color: green
197
+ # &.bar
192
198
  # color: blue
193
199
  #
194
200
  # @param root [Tree::Node] The parent node
195
- def remove_parent_refs(root)
196
- root.children.each do |child|
197
- case child
198
- when Tree::RuleNode
199
- child.rule.first.gsub! /^& +/, ''
200
- remove_parent_refs child
201
- when Tree::DirectiveNode
202
- remove_parent_refs child
201
+ def parent_ref_rules(root)
202
+ current_rule = nil
203
+ root.children.map! do |child|
204
+ unless child.is_a?(Tree::RuleNode)
205
+ parent_ref_rules(child) if child.is_a?(Tree::DirectiveNode)
206
+ next child
207
+ end
208
+
209
+ sseq = first_sseq(child)
210
+ next child unless sseq.is_a?(Sass::Selector::SimpleSequence)
211
+
212
+ firsts, rest = [sseq.members.first], sseq.members[1..-1]
213
+ firsts.push rest.shift if firsts.first.is_a?(Sass::Selector::Parent)
214
+
215
+ if current_rule.nil? || first_sseq(current_rule).members != firsts
216
+ current_rule = Tree::RuleNode.new([])
217
+ current_rule.parsed_rules = make_sseq(*firsts)
218
+ end
219
+
220
+ unless rest.empty?
221
+ rest.unshift Sass::Selector::Parent.new
222
+ child.parsed_rules = make_sseq(*rest)
223
+ current_rule << child
224
+ else
225
+ current_rule.children += child.children
203
226
  end
227
+
228
+ current_rule
204
229
  end
230
+ root.children.compact!
231
+ root.children.uniq!
232
+
233
+ root.children.each {|v| parent_ref_rules(v)}
205
234
  end
206
235
 
207
236
  # Flatten rules so that
@@ -238,7 +267,7 @@ module Sass
238
267
  end
239
268
  end
240
269
 
241
- # Flattens a single rule
270
+ # Flattens a single rule.
242
271
  #
243
272
  # @param rule [Tree::RuleNode] The candidate for flattening
244
273
  # @see #flatten_rules
@@ -246,10 +275,10 @@ module Sass
246
275
  while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
247
276
  child = rule.children.first
248
277
 
249
- if child.rule.first[0] == ?&
250
- rule.rule = [child.rule.first.gsub(/^&/, rule.rule.first)]
278
+ if first_simple_sel(child).is_a?(Sass::Selector::Parent)
279
+ rule.parsed_rules = child.parsed_rules.resolve_parent_refs(rule.parsed_rules)
251
280
  else
252
- rule.rule = ["#{rule.rule.first} #{child.rule.first}"]
281
+ rule.parsed_rules = make_seq(first_sseq(rule), *first_seq(child).members)
253
282
  end
254
283
 
255
284
  rule.children = child.children
@@ -282,7 +311,7 @@ module Sass
282
311
  end
283
312
 
284
313
  if prev_rule && prev_rule.children == child.children
285
- prev_rule.rule.first << ", #{child.rule.first}"
314
+ prev_rule.parsed_rules.members << first_seq(child)
286
315
  next nil
287
316
  end
288
317
 
@@ -292,5 +321,72 @@ module Sass
292
321
  end
293
322
  root.children.compact!
294
323
  end
324
+
325
+ # Dump all the parsed {Sass::Tree::RuleNode} selectors to strings.
326
+ #
327
+ # @param root [Tree::Node] The parent node
328
+ def dump_selectors(root)
329
+ root.children.each do |child|
330
+ next dump_selectors(child) if child.is_a?(Tree::DirectiveNode)
331
+ next unless child.is_a?(Tree::RuleNode)
332
+ child.rule = child.parsed_rules.to_s
333
+ dump_selectors(child)
334
+ end
335
+ end
336
+
337
+ # Create a {Sass::Selector::CommaSequence}.
338
+ #
339
+ # @param seqs [Array<Sass::Selector::Sequence>]
340
+ # @return [Sass::Selector::CommaSequence]
341
+ def make_cseq(*seqs)
342
+ Sass::Selector::CommaSequence.new(seqs)
343
+ end
344
+
345
+ # Create a {Sass::Selector::CommaSequence} containing only a single
346
+ # {Sass::Selector::Sequence}.
347
+ #
348
+ # @param sseqs [Array<Sass::Selector::Sequence, String>]
349
+ # @return [Sass::Selector::CommaSequence]
350
+ def make_seq(*sseqs)
351
+ make_cseq(Sass::Selector::Sequence.new(sseqs))
352
+ end
353
+
354
+ # Create a {Sass::Selector::CommaSequence} containing only a single
355
+ # {Sass::Selector::Sequence} which in turn contains only a single
356
+ # {Sass::Selector::SimpleSequence}.
357
+ #
358
+ # @param sseqs [Array<Sass::Selector::Sequence, String>]
359
+ # @return [Sass::Selector::CommaSequence]
360
+ def make_sseq(*sseqs)
361
+ make_seq(Sass::Selector::SimpleSequence.new(sseqs))
362
+ end
363
+
364
+ # Return the first {Sass::Selector::Sequence} in a {Sass::Tree::RuleNode}.
365
+ #
366
+ # @param rule [Sass::Tree::RuleNode]
367
+ # @return [Sass::Selector::Sequence]
368
+ def first_seq(rule)
369
+ rule.parsed_rules.members.first
370
+ end
371
+
372
+ # Return the first {Sass::Selector::SimpleSequence} in a
373
+ # {Sass::Tree::RuleNode}.
374
+ #
375
+ # @param rule [Sass::Tree::RuleNode]
376
+ # @return [Sass::Selector::SimpleSequence, String]
377
+ def first_sseq(rule)
378
+ first_seq(rule).members.first
379
+ end
380
+
381
+ # Return the first {Sass::Selector::Simple} in a {Sass::Tree::RuleNode},
382
+ # unless the rule begins with a combinator.
383
+ #
384
+ # @param rule [Sass::Tree::RuleNode]
385
+ # @return [Sass::Selector::Simple?]
386
+ def first_simple_sel(rule)
387
+ sseq = first_sseq(rule)
388
+ return unless sseq.is_a?(Sass::Selector::SimpleSequence)
389
+ sseq.members.first
390
+ end
295
391
  end
296
392
  end
@@ -835,11 +835,11 @@ MESSAGE
835
835
  @strs.pop
836
836
  end
837
837
 
838
- def str?(&block)
838
+ def str?
839
839
  pos = @scanner.pos
840
840
  line = @line
841
841
  @strs.push ""
842
- throw_error(&block) && @strs.last
842
+ throw_error {yield} && @strs.last
843
843
  rescue Sass::SyntaxError => e
844
844
  @scanner.pos = pos
845
845
  @line = line
@@ -2,8 +2,9 @@ module Sass
2
2
  module Selector
3
3
  # The abstract parent class of the various selector sequence classes.
4
4
  #
5
- # All subclasses should implement a `members` method
6
- # that returns an array of object that respond to `#line=` and `#filename=`.
5
+ # All subclasses should implement a `members` method that returns an array
6
+ # of object that respond to `#line=` and `#filename=`, as well as a `to_a`
7
+ # method that returns an array of strings and script nodes.
7
8
  class AbstractSequence
8
9
  # The line of the Sass template on which this selector was declared.
9
10
  #
@@ -64,6 +65,14 @@ module Sass
64
65
  @has_placeholder ||=
65
66
  members.any? {|m| m.is_a?(AbstractSequence) ? m.has_placeholder? : m.is_a?(Placeholder)}
66
67
  end
68
+
69
+ # Converts the selector into a string. This is the standard selector
70
+ # string, along with any SassScript interpolation that may exist.
71
+ #
72
+ # @return [String]
73
+ def to_s
74
+ to_a.map {|e| e.is_a?(Sass::Script::Node) ? "\#{#{e.to_sass}}" : e}.join
75
+ end
67
76
  end
68
77
  end
69
78
  end
@@ -33,6 +33,12 @@ module Sass
33
33
  to_a.map {|e| e.is_a?(Sass::Script::Node) ? "\#{#{e.to_sass}}" : e}.join
34
34
  end
35
35
 
36
+ # @see \{#inspect}
37
+ # @return [String]
38
+ def to_s
39
+ inspect
40
+ end
41
+
36
42
  # Returns a hash code for this selector object.
37
43
  #
38
44
  # By default, this is based on the value of \{#to\_a},
@@ -159,9 +159,9 @@ module Sass
159
159
  #
160
160
  # @yield node
161
161
  # @yieldparam node [Node] a node in the tree
162
- def each(&block)
162
+ def each
163
163
  yield self
164
- children.each {|c| c.each(&block)}
164
+ children.each {|c| c.each {|n| yield n}}
165
165
  end
166
166
 
167
167
  # Converts a node to Sass code that will generate it.
@@ -143,9 +143,9 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
143
143
  return false
144
144
  end
145
145
 
146
- def try_send(method, *args, &block)
146
+ def try_send(method, *args)
147
147
  return unless respond_to?(method)
148
- send(method, *args, &block)
148
+ send(method, *args)
149
149
  end
150
150
  end
151
151
 
@@ -85,8 +85,9 @@ module Sass
85
85
  # @return [Hash] The mapped hash
86
86
  # @see #map_keys
87
87
  # @see #map_vals
88
- def map_hash(hash, &block)
89
- to_hash(hash.map(&block))
88
+ def map_hash(hash)
89
+ # Using &block here completely hoses performance on 1.8.
90
+ to_hash(hash.map {|k, v| yield k, v})
90
91
  end
91
92
 
92
93
  # Computes the powerset of the given array.
@@ -211,11 +212,11 @@ module Sass
211
212
  # @yieldreturn [Object, nil] If the two values register as equal,
212
213
  # this will return the value to use in the LCS array.
213
214
  # @return [Array] The LCS
214
- def lcs(x, y, &block)
215
+ def lcs(x, y)
215
216
  x = [nil, *x]
216
217
  y = [nil, *y]
217
218
  block ||= proc {|a, b| a == b && a}
218
- lcs_backtrace(lcs_table(x, y, &block), x, y, x.size-1, y.size-1, &block)
219
+ lcs_backtrace(lcs_table(x, y) {|a, b| yield a, b}, x, y, x.size-1, y.size-1) {|a, b| yield a, b}
219
220
  end
220
221
 
221
222
  # Converts a Hash to an Array. This is usually identical to `Hash#to_a`,
@@ -762,14 +763,14 @@ MSG
762
763
 
763
764
  # Computes a single longest common subsequence for arrays x and y.
764
765
  # Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS)
765
- def lcs_backtrace(c, x, y, i, j, &block)
766
+ def lcs_backtrace(c, x, y, i, j)
766
767
  return [] if i == 0 || j == 0
767
768
  if v = yield(x[i], y[j])
768
- return lcs_backtrace(c, x, y, i-1, j-1, &block) << v
769
+ return lcs_backtrace(c, x, y, i-1, j-1) {|a, b| yield a, b} << v
769
770
  end
770
771
 
771
- return lcs_backtrace(c, x, y, i, j-1, &block) if c[i][j-1] > c[i-1][j]
772
- return lcs_backtrace(c, x, y, i-1, j, &block)
772
+ return lcs_backtrace(c, x, y, i, j-1) {|a, b| yield a, b} if c[i][j-1] > c[i-1][j]
773
+ return lcs_backtrace(c, x, y, i-1, j) {|a, b| yield a, b}
773
774
  end
774
775
  end
775
776
  end
@@ -277,6 +277,30 @@ foo, , bar { a: b }
277
277
  CSS
278
278
  end
279
279
 
280
+ def test_selector_splitting
281
+ assert_equal(<<SASS, css2sass(<<CSS))
282
+ .foo >
283
+ .bar
284
+ a: b
285
+ .baz
286
+ c: d
287
+ SASS
288
+ .foo>.bar {a: b}
289
+ .foo>.baz {c: d}
290
+ CSS
291
+
292
+ assert_equal(<<SASS, css2sass(<<CSS))
293
+ .foo
294
+ &::bar
295
+ a: b
296
+ &::baz
297
+ c: d
298
+ SASS
299
+ .foo::bar {a: b}
300
+ .foo::baz {c: d}
301
+ CSS
302
+ end
303
+
280
304
  # Error reporting
281
305
 
282
306
  def test_error_reporting
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sass
3
3
  version: !ruby/object:Gem::Version
4
- hash: 592302985
4
+ hash: 592302987
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 2
9
9
  - 0
10
10
  - alpha
11
- - 74
12
- version: 3.2.0.alpha.74
11
+ - 75
12
+ version: 3.2.0.alpha.75
13
13
  platform: ruby
14
14
  authors:
15
15
  - Nathan Weizenbaum
@@ -86,7 +86,7 @@ files:
86
86
  - lib/sass/logger.rb
87
87
  - lib/sass/logger/base.rb
88
88
  - lib/sass/logger/log_level.rb
89
- - lib/sass/media.rb
89
+ - lib/sass/util.rb
90
90
  - lib/sass/plugin.rb
91
91
  - lib/sass/plugin/compiler.rb
92
92
  - lib/sass/plugin/configuration.rb
@@ -151,6 +151,7 @@ files:
151
151
  - lib/sass/tree/root_node.rb
152
152
  - lib/sass/tree/rule_node.rb
153
153
  - lib/sass/tree/content_node.rb
154
+ - lib/sass/tree/trace_node.rb
154
155
  - lib/sass/tree/variable_node.rb
155
156
  - lib/sass/tree/visitors/base.rb
156
157
  - lib/sass/tree/visitors/check_nesting.rb
@@ -162,8 +163,7 @@ files:
162
163
  - lib/sass/tree/visitors/to_css.rb
163
164
  - lib/sass/tree/warn_node.rb
164
165
  - lib/sass/tree/while_node.rb
165
- - lib/sass/tree/trace_node.rb
166
- - lib/sass/util.rb
166
+ - lib/sass/media.rb
167
167
  - lib/sass/util/multibyte_string_scanner.rb
168
168
  - lib/sass/util/subset_map.rb
169
169
  - lib/sass/version.rb