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

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.
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