sass 3.1.0 → 3.3.0

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 (260) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING +1 -1
  3. data/MIT-LICENSE +2 -2
  4. data/README.md +29 -17
  5. data/Rakefile +43 -9
  6. data/VERSION +1 -1
  7. data/VERSION_DATE +1 -0
  8. data/VERSION_NAME +1 -1
  9. data/bin/sass +6 -1
  10. data/bin/sass-convert +6 -1
  11. data/bin/scss +6 -1
  12. data/ext/mkrf_conf.rb +27 -0
  13. data/lib/sass/cache_stores/base.rb +7 -3
  14. data/lib/sass/cache_stores/chain.rb +3 -2
  15. data/lib/sass/cache_stores/filesystem.rb +5 -7
  16. data/lib/sass/cache_stores/memory.rb +1 -1
  17. data/lib/sass/cache_stores/null.rb +2 -2
  18. data/lib/sass/callbacks.rb +2 -1
  19. data/lib/sass/css.rb +168 -53
  20. data/lib/sass/engine.rb +502 -174
  21. data/lib/sass/environment.rb +151 -111
  22. data/lib/sass/error.rb +7 -7
  23. data/lib/sass/exec.rb +176 -60
  24. data/lib/sass/features.rb +40 -0
  25. data/lib/sass/importers/base.rb +46 -7
  26. data/lib/sass/importers/deprecated_path.rb +51 -0
  27. data/lib/sass/importers/filesystem.rb +113 -30
  28. data/lib/sass/importers.rb +1 -0
  29. data/lib/sass/logger/base.rb +30 -0
  30. data/lib/sass/logger/log_level.rb +45 -0
  31. data/lib/sass/logger.rb +12 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin/compiler.rb +194 -104
  34. data/lib/sass/plugin/configuration.rb +18 -25
  35. data/lib/sass/plugin/merb.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +37 -11
  37. data/lib/sass/plugin.rb +10 -13
  38. data/lib/sass/railtie.rb +2 -1
  39. data/lib/sass/repl.rb +5 -6
  40. data/lib/sass/script/css_lexer.rb +8 -4
  41. data/lib/sass/script/css_parser.rb +5 -2
  42. data/lib/sass/script/functions.rb +1547 -618
  43. data/lib/sass/script/lexer.rb +122 -72
  44. data/lib/sass/script/parser.rb +304 -135
  45. data/lib/sass/script/tree/funcall.rb +306 -0
  46. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
  47. data/lib/sass/script/tree/list_literal.rb +77 -0
  48. data/lib/sass/script/tree/literal.rb +45 -0
  49. data/lib/sass/script/tree/map_literal.rb +64 -0
  50. data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
  51. data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
  52. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
  53. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
  54. data/lib/sass/script/tree/variable.rb +57 -0
  55. data/lib/sass/script/tree.rb +15 -0
  56. data/lib/sass/script/value/arg_list.rb +36 -0
  57. data/lib/sass/script/value/base.rb +238 -0
  58. data/lib/sass/script/value/bool.rb +40 -0
  59. data/lib/sass/script/{color.rb → value/color.rb} +256 -74
  60. data/lib/sass/script/value/deprecated_false.rb +55 -0
  61. data/lib/sass/script/value/helpers.rb +155 -0
  62. data/lib/sass/script/value/list.rb +128 -0
  63. data/lib/sass/script/value/map.rb +70 -0
  64. data/lib/sass/script/value/null.rb +49 -0
  65. data/lib/sass/script/{number.rb → value/number.rb} +115 -62
  66. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  67. data/lib/sass/script/value.rb +12 -0
  68. data/lib/sass/script.rb +35 -9
  69. data/lib/sass/scss/css_parser.rb +2 -12
  70. data/lib/sass/scss/parser.rb +657 -230
  71. data/lib/sass/scss/rx.rb +17 -12
  72. data/lib/sass/scss/static_parser.rb +37 -6
  73. data/lib/sass/scss.rb +0 -1
  74. data/lib/sass/selector/abstract_sequence.rb +35 -3
  75. data/lib/sass/selector/comma_sequence.rb +29 -14
  76. data/lib/sass/selector/sequence.rb +371 -74
  77. data/lib/sass/selector/simple.rb +28 -13
  78. data/lib/sass/selector/simple_sequence.rb +163 -36
  79. data/lib/sass/selector.rb +138 -36
  80. data/lib/sass/shared.rb +3 -5
  81. data/lib/sass/source/map.rb +196 -0
  82. data/lib/sass/source/position.rb +39 -0
  83. data/lib/sass/source/range.rb +41 -0
  84. data/lib/sass/stack.rb +126 -0
  85. data/lib/sass/supports.rb +228 -0
  86. data/lib/sass/tree/at_root_node.rb +82 -0
  87. data/lib/sass/tree/comment_node.rb +34 -29
  88. data/lib/sass/tree/content_node.rb +9 -0
  89. data/lib/sass/tree/css_import_node.rb +60 -0
  90. data/lib/sass/tree/debug_node.rb +3 -3
  91. data/lib/sass/tree/directive_node.rb +33 -3
  92. data/lib/sass/tree/each_node.rb +9 -9
  93. data/lib/sass/tree/extend_node.rb +20 -6
  94. data/lib/sass/tree/for_node.rb +6 -6
  95. data/lib/sass/tree/function_node.rb +12 -4
  96. data/lib/sass/tree/if_node.rb +2 -15
  97. data/lib/sass/tree/import_node.rb +11 -5
  98. data/lib/sass/tree/media_node.rb +27 -11
  99. data/lib/sass/tree/mixin_def_node.rb +15 -4
  100. data/lib/sass/tree/mixin_node.rb +27 -7
  101. data/lib/sass/tree/node.rb +69 -35
  102. data/lib/sass/tree/prop_node.rb +47 -31
  103. data/lib/sass/tree/return_node.rb +4 -3
  104. data/lib/sass/tree/root_node.rb +20 -4
  105. data/lib/sass/tree/rule_node.rb +37 -26
  106. data/lib/sass/tree/supports_node.rb +38 -0
  107. data/lib/sass/tree/trace_node.rb +33 -0
  108. data/lib/sass/tree/variable_node.rb +10 -4
  109. data/lib/sass/tree/visitors/base.rb +5 -8
  110. data/lib/sass/tree/visitors/check_nesting.rb +67 -52
  111. data/lib/sass/tree/visitors/convert.rb +134 -53
  112. data/lib/sass/tree/visitors/cssize.rb +245 -51
  113. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  114. data/lib/sass/tree/visitors/extend.rb +68 -0
  115. data/lib/sass/tree/visitors/perform.rb +331 -105
  116. data/lib/sass/tree/visitors/set_options.rb +125 -0
  117. data/lib/sass/tree/visitors/to_css.rb +259 -95
  118. data/lib/sass/tree/warn_node.rb +3 -3
  119. data/lib/sass/tree/while_node.rb +3 -3
  120. data/lib/sass/util/cross_platform_random.rb +19 -0
  121. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  122. data/lib/sass/util/normalized_map.rb +130 -0
  123. data/lib/sass/util/ordered_hash.rb +192 -0
  124. data/lib/sass/util/subset_map.rb +11 -2
  125. data/lib/sass/util/test.rb +9 -0
  126. data/lib/sass/util.rb +565 -39
  127. data/lib/sass/version.rb +27 -15
  128. data/lib/sass.rb +39 -4
  129. data/test/sass/cache_test.rb +15 -0
  130. data/test/sass/compiler_test.rb +223 -0
  131. data/test/sass/conversion_test.rb +901 -107
  132. data/test/sass/css2sass_test.rb +94 -0
  133. data/test/sass/engine_test.rb +1059 -164
  134. data/test/sass/exec_test.rb +86 -0
  135. data/test/sass/extend_test.rb +933 -837
  136. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  137. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  138. data/test/sass/functions_test.rb +995 -136
  139. data/test/sass/importer_test.rb +338 -18
  140. data/test/sass/logger_test.rb +58 -0
  141. data/test/sass/more_results/more_import.css +2 -2
  142. data/test/sass/plugin_test.rb +114 -30
  143. data/test/sass/results/cached_import_option.css +3 -0
  144. data/test/sass/results/filename_fn.css +3 -0
  145. data/test/sass/results/import.css +2 -2
  146. data/test/sass/results/import_charset.css +1 -0
  147. data/test/sass/results/import_charset_1_8.css +1 -0
  148. data/test/sass/results/import_charset_ibm866.css +1 -0
  149. data/test/sass/results/import_content.css +1 -0
  150. data/test/sass/results/script.css +1 -1
  151. data/test/sass/results/scss_import.css +2 -2
  152. data/test/sass/results/units.css +2 -2
  153. data/test/sass/script_conversion_test.rb +43 -1
  154. data/test/sass/script_test.rb +380 -36
  155. data/test/sass/scss/css_test.rb +257 -75
  156. data/test/sass/scss/scss_test.rb +2322 -110
  157. data/test/sass/source_map_test.rb +887 -0
  158. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  159. data/test/sass/templates/_double_import_loop2.sass +1 -0
  160. data/test/sass/templates/_filename_fn_import.scss +11 -0
  161. data/test/sass/templates/_imported_content.sass +3 -0
  162. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  163. data/test/sass/templates/bork5.sass +3 -0
  164. data/test/sass/templates/cached_import_option.scss +3 -0
  165. data/test/sass/templates/double_import_loop1.sass +1 -0
  166. data/test/sass/templates/filename_fn.scss +18 -0
  167. data/test/sass/templates/import_charset.sass +2 -0
  168. data/test/sass/templates/import_charset_1_8.sass +2 -0
  169. data/test/sass/templates/import_charset_ibm866.sass +2 -0
  170. data/test/sass/templates/import_content.sass +4 -0
  171. data/test/sass/templates/same_name_different_ext.sass +2 -0
  172. data/test/sass/templates/same_name_different_ext.scss +1 -0
  173. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  174. data/test/sass/templates/single_import_loop.sass +1 -0
  175. data/test/sass/templates/subdir/import_up1.scss +1 -0
  176. data/test/sass/templates/subdir/import_up2.scss +1 -0
  177. data/test/sass/test_helper.rb +1 -1
  178. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  179. data/test/sass/util/normalized_map_test.rb +51 -0
  180. data/test/sass/util_test.rb +183 -0
  181. data/test/sass/value_helpers_test.rb +181 -0
  182. data/test/test_helper.rb +45 -5
  183. data/vendor/listen/CHANGELOG.md +228 -0
  184. data/vendor/listen/CONTRIBUTING.md +38 -0
  185. data/vendor/listen/Gemfile +30 -0
  186. data/vendor/listen/Guardfile +8 -0
  187. data/vendor/{fssm → listen}/LICENSE +1 -1
  188. data/vendor/listen/README.md +315 -0
  189. data/vendor/listen/Rakefile +47 -0
  190. data/vendor/listen/Vagrantfile +96 -0
  191. data/vendor/listen/lib/listen/adapter.rb +214 -0
  192. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  193. data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
  194. data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
  195. data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
  196. data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
  197. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  198. data/vendor/listen/lib/listen/directory_record.rb +371 -0
  199. data/vendor/listen/lib/listen/listener.rb +225 -0
  200. data/vendor/listen/lib/listen/multi_listener.rb +143 -0
  201. data/vendor/listen/lib/listen/turnstile.rb +28 -0
  202. data/vendor/listen/lib/listen/version.rb +3 -0
  203. data/vendor/listen/lib/listen.rb +40 -0
  204. data/vendor/listen/listen.gemspec +22 -0
  205. data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
  206. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  207. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  208. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  209. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  210. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  211. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  212. data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
  213. data/vendor/listen/spec/listen/listener_spec.rb +169 -0
  214. data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
  215. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  216. data/vendor/listen/spec/listen_spec.rb +73 -0
  217. data/vendor/listen/spec/spec_helper.rb +21 -0
  218. data/vendor/listen/spec/support/adapter_helper.rb +629 -0
  219. data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
  220. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  221. data/vendor/listen/spec/support/listeners_helper.rb +156 -0
  222. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  223. metadata +344 -271
  224. data/lib/sass/less.rb +0 -382
  225. data/lib/sass/script/bool.rb +0 -18
  226. data/lib/sass/script/funcall.rb +0 -162
  227. data/lib/sass/script/list.rb +0 -76
  228. data/lib/sass/script/literal.rb +0 -245
  229. data/lib/sass/script/variable.rb +0 -54
  230. data/lib/sass/scss/sass_parser.rb +0 -11
  231. data/test/sass/less_conversion_test.rb +0 -653
  232. data/vendor/fssm/README.markdown +0 -55
  233. data/vendor/fssm/Rakefile +0 -59
  234. data/vendor/fssm/VERSION.yml +0 -5
  235. data/vendor/fssm/example.rb +0 -9
  236. data/vendor/fssm/fssm.gemspec +0 -77
  237. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  238. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  239. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  240. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  241. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  242. data/vendor/fssm/lib/fssm/path.rb +0 -91
  243. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  244. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  245. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  246. data/vendor/fssm/lib/fssm/support.rb +0 -63
  247. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  248. data/vendor/fssm/lib/fssm.rb +0 -33
  249. data/vendor/fssm/profile/prof-cache.rb +0 -40
  250. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  251. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  252. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  253. data/vendor/fssm/profile/prof.html +0 -2379
  254. data/vendor/fssm/spec/path_spec.rb +0 -75
  255. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  256. data/vendor/fssm/spec/root/file.css +0 -0
  257. data/vendor/fssm/spec/root/file.rb +0 -0
  258. data/vendor/fssm/spec/root/file.yml +0 -0
  259. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  260. data/vendor/fssm/spec/spec_helper.rb +0 -14
data/lib/sass/css.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require File.dirname(__FILE__) + '/../sass'
2
2
  require 'sass/tree/node'
3
3
  require 'sass/scss/css_parser'
4
- require 'strscan'
5
4
 
6
5
  module Sass
7
6
  # This class converts CSS documents into Sass or SCSS templates.
@@ -25,6 +24,8 @@ module Sass
25
24
  # (`:color blue` as opposed to `color: blue`).
26
25
  # This is only meaningful when generating Sass code,
27
26
  # rather than SCSS.
27
+ # @option options :indent [String] (" ")
28
+ # The string to use for indenting each line. Defaults to two spaces.
28
29
  def initialize(template, options = {})
29
30
  if template.is_a? IO
30
31
  template = template.read
@@ -75,15 +76,31 @@ module Sass
75
76
  #
76
77
  # @return [Tree::Node] The root node of the parsed tree
77
78
  def build_tree
78
- root = Sass::SCSS::CssParser.new(@template).parse
79
+ root = Sass::SCSS::CssParser.new(@template, @options[:filename], nil).parse
80
+ parse_selectors root
79
81
  expand_commas root
82
+ nest_seqs root
80
83
  parent_ref_rules root
81
- remove_parent_refs root
82
84
  flatten_rules root
85
+ bubble_subject root
83
86
  fold_commas root
87
+ dump_selectors root
84
88
  root
85
89
  end
86
90
 
91
+ # Parse all the selectors in the document and assign them to
92
+ # {Sass::Tree::RuleNode#parsed_rules}.
93
+ #
94
+ # @param root [Tree::Node] The parent node
95
+ def parse_selectors(root)
96
+ root.children.each do |child|
97
+ next parse_selectors(child) if child.is_a?(Tree::DirectiveNode)
98
+ next unless child.is_a?(Tree::RuleNode)
99
+ parser = Sass::SCSS::CssParser.new(child.rule.first, child.filename, nil, child.line)
100
+ child.parsed_rules = parser.parse_selector
101
+ end
102
+ end
103
+
87
104
  # Transform
88
105
  #
89
106
  # foo, bar, baz
@@ -101,12 +118,14 @@ module Sass
101
118
  # @param root [Tree::Node] The parent node
102
119
  def expand_commas(root)
103
120
  root.children.map! do |child|
104
- unless child.is_a?(Tree::RuleNode) && child.rule.first.include?(',')
121
+ # child.parsed_rules.members.size > 1 iff the rule contains a comma
122
+ unless child.is_a?(Tree::RuleNode) && child.parsed_rules.members.size > 1
105
123
  expand_commas(child) if child.is_a?(Tree::DirectiveNode)
106
124
  next child
107
125
  end
108
- child.rule.first.split(',').map do |rule|
109
- node = Tree::RuleNode.new([rule.strip])
126
+ child.parsed_rules.members.map do |seq|
127
+ node = Tree::RuleNode.new([])
128
+ node.parsed_rules = make_cseq(seq)
110
129
  node.children = child.children
111
130
  node
112
131
  end
@@ -114,22 +133,7 @@ module Sass
114
133
  root.children.flatten!
115
134
  end
116
135
 
117
- # Make rules use parent refs so that
118
- #
119
- # foo
120
- # color: green
121
- # foo.bar
122
- # color: blue
123
- #
124
- # becomes
125
- #
126
- # foo
127
- # color: green
128
- # &.bar
129
- # color: blue
130
- #
131
- # This has the side effect of nesting rules,
132
- # so that
136
+ # Make rules use nesting so that
133
137
  #
134
138
  # foo
135
139
  # color: green
@@ -142,31 +146,34 @@ module Sass
142
146
  #
143
147
  # foo
144
148
  # color: green
145
- # & bar
149
+ # bar
146
150
  # color: red
147
- # & baz
151
+ # baz
148
152
  # color: blue
149
153
  #
150
154
  # @param root [Tree::Node] The parent node
151
- def parent_ref_rules(root)
155
+ def nest_seqs(root)
152
156
  current_rule = nil
153
157
  root.children.map! do |child|
154
158
  unless child.is_a?(Tree::RuleNode)
155
- parent_ref_rules(child) if child.is_a?(Tree::DirectiveNode)
159
+ nest_seqs(child) if child.is_a?(Tree::DirectiveNode)
156
160
  next child
157
161
  end
158
162
 
159
- first, rest = child.rule.first.scan(/\A(&?(?: .|[^ ])[^.#: \[]*)([.#: \[].*)?\Z/m).first
163
+ seq = first_seq(child)
164
+ seq.members.reject! {|sseq| sseq == "\n"}
165
+ first, rest = seq.members.first, seq.members[1..-1]
160
166
 
161
- if current_rule.nil? || current_rule.rule.first != first
162
- current_rule = Tree::RuleNode.new([first])
167
+ if current_rule.nil? || first_sseq(current_rule) != first
168
+ current_rule = Tree::RuleNode.new([])
169
+ current_rule.parsed_rules = make_seq(first)
163
170
  end
164
171
 
165
- if rest
166
- child.rule = ["&" + rest]
167
- current_rule << child
168
- else
172
+ if rest.empty?
169
173
  current_rule.children += child.children
174
+ else
175
+ child.parsed_rules = make_seq(*rest)
176
+ current_rule << child
170
177
  end
171
178
 
172
179
  current_rule
@@ -174,32 +181,59 @@ module Sass
174
181
  root.children.compact!
175
182
  root.children.uniq!
176
183
 
177
- root.children.each { |v| parent_ref_rules(v) }
184
+ root.children.each {|v| nest_seqs(v)}
178
185
  end
179
186
 
180
- # Remove useless parent refs so that
187
+ # Make rules use parent refs so that
181
188
  #
182
189
  # foo
183
- # & bar
184
- # color: blue
190
+ # color: green
191
+ # foo.bar
192
+ # color: blue
185
193
  #
186
194
  # becomes
187
195
  #
188
196
  # foo
189
- # bar
197
+ # color: green
198
+ # &.bar
190
199
  # color: blue
191
200
  #
192
201
  # @param root [Tree::Node] The parent node
193
- def remove_parent_refs(root)
194
- root.children.each do |child|
195
- case child
196
- when Tree::RuleNode
197
- child.rule.first.gsub! /^& +/, ''
198
- remove_parent_refs child
199
- when Tree::DirectiveNode
200
- remove_parent_refs child
202
+ def parent_ref_rules(root)
203
+ current_rule = nil
204
+ root.children.map! do |child|
205
+ unless child.is_a?(Tree::RuleNode)
206
+ parent_ref_rules(child) if child.is_a?(Tree::DirectiveNode)
207
+ next child
208
+ end
209
+
210
+ sseq = first_sseq(child)
211
+ next child unless sseq.is_a?(Sass::Selector::SimpleSequence)
212
+
213
+ firsts, rest = [sseq.members.first], sseq.members[1..-1]
214
+ firsts.push rest.shift if firsts.first.is_a?(Sass::Selector::Parent)
215
+
216
+ last_simple_subject = rest.empty? && sseq.subject?
217
+ if current_rule.nil? || first_sseq(current_rule).members != firsts ||
218
+ !!first_sseq(current_rule).subject? != !!last_simple_subject
219
+ current_rule = Tree::RuleNode.new([])
220
+ current_rule.parsed_rules = make_sseq(last_simple_subject, *firsts)
201
221
  end
222
+
223
+ if rest.empty?
224
+ current_rule.children += child.children
225
+ else
226
+ rest.unshift Sass::Selector::Parent.new
227
+ child.parsed_rules = make_sseq(sseq.subject?, *rest)
228
+ current_rule << child
229
+ end
230
+
231
+ current_rule
202
232
  end
233
+ root.children.compact!
234
+ root.children.uniq!
235
+
236
+ root.children.each {|v| parent_ref_rules(v)}
203
237
  end
204
238
 
205
239
  # Flatten rules so that
@@ -236,7 +270,7 @@ module Sass
236
270
  end
237
271
  end
238
272
 
239
- # Flattens a single rule
273
+ # Flattens a single rule.
240
274
  #
241
275
  # @param rule [Tree::RuleNode] The candidate for flattening
242
276
  # @see #flatten_rules
@@ -244,10 +278,10 @@ module Sass
244
278
  while rule.children.size == 1 && rule.children.first.is_a?(Tree::RuleNode)
245
279
  child = rule.children.first
246
280
 
247
- if child.rule.first[0] == ?&
248
- rule.rule = [child.rule.first.gsub(/^&/, rule.rule.first)]
281
+ if first_simple_sel(child).is_a?(Sass::Selector::Parent)
282
+ rule.parsed_rules = child.parsed_rules.resolve_parent_refs(rule.parsed_rules)
249
283
  else
250
- rule.rule = ["#{rule.rule.first} #{child.rule.first}"]
284
+ rule.parsed_rules = make_seq(*(first_seq(rule).members + first_seq(child).members))
251
285
  end
252
286
 
253
287
  rule.children = child.children
@@ -256,6 +290,19 @@ module Sass
256
290
  flatten_rules(rule)
257
291
  end
258
292
 
293
+ def bubble_subject(root)
294
+ root.children.each do |child|
295
+ bubble_subject(child) if child.is_a?(Tree::RuleNode) || child.is_a?(Tree::DirectiveNode)
296
+ next unless child.is_a?(Tree::RuleNode) && !child.children.empty?
297
+ next unless child.children.all? do |c|
298
+ next unless c.is_a?(Tree::RuleNode)
299
+ first_simple_sel(c).is_a?(Sass::Selector::Parent) && first_sseq(c).subject?
300
+ end
301
+ first_sseq(child).subject = true
302
+ child.children.each {|c| first_sseq(c).subject = false}
303
+ end
304
+ end
305
+
259
306
  # Transform
260
307
  #
261
308
  # foo
@@ -270,7 +317,7 @@ module Sass
270
317
  # bar, baz
271
318
  # color: blue
272
319
  #
273
- # @param rule [Tree::RuleNode] The candidate for flattening
320
+ # @param root [Tree::Node] The parent node
274
321
  def fold_commas(root)
275
322
  prev_rule = nil
276
323
  root.children.map! do |child|
@@ -279,8 +326,8 @@ module Sass
279
326
  next child
280
327
  end
281
328
 
282
- if prev_rule && prev_rule.children == child.children
283
- prev_rule.rule.first << ", #{child.rule.first}"
329
+ if prev_rule && prev_rule.children.map {|c| c.to_sass} == child.children.map {|c| c.to_sass}
330
+ prev_rule.parsed_rules.members << first_seq(child)
284
331
  next nil
285
332
  end
286
333
 
@@ -290,5 +337,73 @@ module Sass
290
337
  end
291
338
  root.children.compact!
292
339
  end
340
+
341
+ # Dump all the parsed {Sass::Tree::RuleNode} selectors to strings.
342
+ #
343
+ # @param root [Tree::Node] The parent node
344
+ def dump_selectors(root)
345
+ root.children.each do |child|
346
+ next dump_selectors(child) if child.is_a?(Tree::DirectiveNode)
347
+ next unless child.is_a?(Tree::RuleNode)
348
+ child.rule = [child.parsed_rules.to_s]
349
+ dump_selectors(child)
350
+ end
351
+ end
352
+
353
+ # Create a {Sass::Selector::CommaSequence}.
354
+ #
355
+ # @param seqs [Array<Sass::Selector::Sequence>]
356
+ # @return [Sass::Selector::CommaSequence]
357
+ def make_cseq(*seqs)
358
+ Sass::Selector::CommaSequence.new(seqs)
359
+ end
360
+
361
+ # Create a {Sass::Selector::CommaSequence} containing only a single
362
+ # {Sass::Selector::Sequence}.
363
+ #
364
+ # @param sseqs [Array<Sass::Selector::Sequence, String>]
365
+ # @return [Sass::Selector::CommaSequence]
366
+ def make_seq(*sseqs)
367
+ make_cseq(Sass::Selector::Sequence.new(sseqs))
368
+ end
369
+
370
+ # Create a {Sass::Selector::CommaSequence} containing only a single
371
+ # {Sass::Selector::Sequence} which in turn contains only a single
372
+ # {Sass::Selector::SimpleSequence}.
373
+ #
374
+ # @param subject [Boolean] Whether this is a subject selector
375
+ # @param sseqs [Array<Sass::Selector::Sequence, String>]
376
+ # @return [Sass::Selector::CommaSequence]
377
+ def make_sseq(subject, *sseqs)
378
+ make_seq(Sass::Selector::SimpleSequence.new(sseqs, subject))
379
+ end
380
+
381
+ # Return the first {Sass::Selector::Sequence} in a {Sass::Tree::RuleNode}.
382
+ #
383
+ # @param rule [Sass::Tree::RuleNode]
384
+ # @return [Sass::Selector::Sequence]
385
+ def first_seq(rule)
386
+ rule.parsed_rules.members.first
387
+ end
388
+
389
+ # Return the first {Sass::Selector::SimpleSequence} in a
390
+ # {Sass::Tree::RuleNode}.
391
+ #
392
+ # @param rule [Sass::Tree::RuleNode]
393
+ # @return [Sass::Selector::SimpleSequence, String]
394
+ def first_sseq(rule)
395
+ first_seq(rule).members.first
396
+ end
397
+
398
+ # Return the first {Sass::Selector::Simple} in a {Sass::Tree::RuleNode},
399
+ # unless the rule begins with a combinator.
400
+ #
401
+ # @param rule [Sass::Tree::RuleNode]
402
+ # @return [Sass::Selector::Simple?]
403
+ def first_simple_sel(rule)
404
+ sseq = first_sseq(rule)
405
+ return unless sseq.is_a?(Sass::Selector::SimpleSequence)
406
+ sseq.members.first
407
+ end
293
408
  end
294
409
  end