oreorenasass 3.4.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 (268) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +11 -0
  3. data/CONTRIBUTING +3 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +221 -0
  6. data/Rakefile +370 -0
  7. data/VERSION +1 -0
  8. data/VERSION_NAME +1 -0
  9. data/bin/sass +13 -0
  10. data/bin/sass-convert +12 -0
  11. data/bin/scss +13 -0
  12. data/extra/update_watch.rb +13 -0
  13. data/init.rb +18 -0
  14. data/lib/sass/cache_stores/base.rb +88 -0
  15. data/lib/sass/cache_stores/chain.rb +34 -0
  16. data/lib/sass/cache_stores/filesystem.rb +60 -0
  17. data/lib/sass/cache_stores/memory.rb +47 -0
  18. data/lib/sass/cache_stores/null.rb +25 -0
  19. data/lib/sass/cache_stores.rb +15 -0
  20. data/lib/sass/callbacks.rb +67 -0
  21. data/lib/sass/css.rb +407 -0
  22. data/lib/sass/engine.rb +1181 -0
  23. data/lib/sass/environment.rb +191 -0
  24. data/lib/sass/error.rb +198 -0
  25. data/lib/sass/exec/base.rb +187 -0
  26. data/lib/sass/exec/sass_convert.rb +264 -0
  27. data/lib/sass/exec/sass_scss.rb +424 -0
  28. data/lib/sass/exec.rb +9 -0
  29. data/lib/sass/features.rb +47 -0
  30. data/lib/sass/importers/base.rb +182 -0
  31. data/lib/sass/importers/filesystem.rb +211 -0
  32. data/lib/sass/importers.rb +22 -0
  33. data/lib/sass/logger/base.rb +30 -0
  34. data/lib/sass/logger/log_level.rb +45 -0
  35. data/lib/sass/logger.rb +12 -0
  36. data/lib/sass/media.rb +210 -0
  37. data/lib/sass/plugin/compiler.rb +565 -0
  38. data/lib/sass/plugin/configuration.rb +118 -0
  39. data/lib/sass/plugin/generic.rb +15 -0
  40. data/lib/sass/plugin/merb.rb +48 -0
  41. data/lib/sass/plugin/rack.rb +60 -0
  42. data/lib/sass/plugin/rails.rb +47 -0
  43. data/lib/sass/plugin/staleness_checker.rb +199 -0
  44. data/lib/sass/plugin.rb +133 -0
  45. data/lib/sass/railtie.rb +10 -0
  46. data/lib/sass/repl.rb +57 -0
  47. data/lib/sass/root.rb +7 -0
  48. data/lib/sass/script/css_lexer.rb +33 -0
  49. data/lib/sass/script/css_parser.rb +34 -0
  50. data/lib/sass/script/functions.rb +2626 -0
  51. data/lib/sass/script/lexer.rb +449 -0
  52. data/lib/sass/script/parser.rb +637 -0
  53. data/lib/sass/script/tree/funcall.rb +306 -0
  54. data/lib/sass/script/tree/interpolation.rb +118 -0
  55. data/lib/sass/script/tree/list_literal.rb +77 -0
  56. data/lib/sass/script/tree/literal.rb +45 -0
  57. data/lib/sass/script/tree/map_literal.rb +64 -0
  58. data/lib/sass/script/tree/node.rb +109 -0
  59. data/lib/sass/script/tree/operation.rb +103 -0
  60. data/lib/sass/script/tree/selector.rb +26 -0
  61. data/lib/sass/script/tree/string_interpolation.rb +104 -0
  62. data/lib/sass/script/tree/unary_operation.rb +69 -0
  63. data/lib/sass/script/tree/variable.rb +57 -0
  64. data/lib/sass/script/tree.rb +16 -0
  65. data/lib/sass/script/value/arg_list.rb +36 -0
  66. data/lib/sass/script/value/base.rb +240 -0
  67. data/lib/sass/script/value/bool.rb +35 -0
  68. data/lib/sass/script/value/color.rb +680 -0
  69. data/lib/sass/script/value/helpers.rb +262 -0
  70. data/lib/sass/script/value/list.rb +113 -0
  71. data/lib/sass/script/value/map.rb +70 -0
  72. data/lib/sass/script/value/null.rb +44 -0
  73. data/lib/sass/script/value/number.rb +530 -0
  74. data/lib/sass/script/value/string.rb +97 -0
  75. data/lib/sass/script/value.rb +11 -0
  76. data/lib/sass/script.rb +66 -0
  77. data/lib/sass/scss/css_parser.rb +42 -0
  78. data/lib/sass/scss/parser.rb +1209 -0
  79. data/lib/sass/scss/rx.rb +141 -0
  80. data/lib/sass/scss/script_lexer.rb +15 -0
  81. data/lib/sass/scss/script_parser.rb +25 -0
  82. data/lib/sass/scss/static_parser.rb +368 -0
  83. data/lib/sass/scss.rb +16 -0
  84. data/lib/sass/selector/abstract_sequence.rb +109 -0
  85. data/lib/sass/selector/comma_sequence.rb +175 -0
  86. data/lib/sass/selector/pseudo.rb +256 -0
  87. data/lib/sass/selector/sequence.rb +600 -0
  88. data/lib/sass/selector/simple.rb +117 -0
  89. data/lib/sass/selector/simple_sequence.rb +325 -0
  90. data/lib/sass/selector.rb +326 -0
  91. data/lib/sass/shared.rb +76 -0
  92. data/lib/sass/source/map.rb +210 -0
  93. data/lib/sass/source/position.rb +39 -0
  94. data/lib/sass/source/range.rb +41 -0
  95. data/lib/sass/stack.rb +120 -0
  96. data/lib/sass/supports.rb +227 -0
  97. data/lib/sass/tree/at_root_node.rb +83 -0
  98. data/lib/sass/tree/charset_node.rb +22 -0
  99. data/lib/sass/tree/comment_node.rb +82 -0
  100. data/lib/sass/tree/content_node.rb +9 -0
  101. data/lib/sass/tree/css_import_node.rb +60 -0
  102. data/lib/sass/tree/debug_node.rb +18 -0
  103. data/lib/sass/tree/directive_node.rb +59 -0
  104. data/lib/sass/tree/each_node.rb +24 -0
  105. data/lib/sass/tree/error_node.rb +18 -0
  106. data/lib/sass/tree/extend_node.rb +43 -0
  107. data/lib/sass/tree/for_node.rb +36 -0
  108. data/lib/sass/tree/function_node.rb +39 -0
  109. data/lib/sass/tree/if_node.rb +52 -0
  110. data/lib/sass/tree/import_node.rb +74 -0
  111. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  112. data/lib/sass/tree/media_node.rb +48 -0
  113. data/lib/sass/tree/mixin_def_node.rb +38 -0
  114. data/lib/sass/tree/mixin_node.rb +52 -0
  115. data/lib/sass/tree/node.rb +238 -0
  116. data/lib/sass/tree/prop_node.rb +171 -0
  117. data/lib/sass/tree/return_node.rb +19 -0
  118. data/lib/sass/tree/root_node.rb +44 -0
  119. data/lib/sass/tree/rule_node.rb +145 -0
  120. data/lib/sass/tree/supports_node.rb +38 -0
  121. data/lib/sass/tree/trace_node.rb +33 -0
  122. data/lib/sass/tree/variable_node.rb +36 -0
  123. data/lib/sass/tree/visitors/base.rb +72 -0
  124. data/lib/sass/tree/visitors/check_nesting.rb +177 -0
  125. data/lib/sass/tree/visitors/convert.rb +334 -0
  126. data/lib/sass/tree/visitors/cssize.rb +369 -0
  127. data/lib/sass/tree/visitors/deep_copy.rb +107 -0
  128. data/lib/sass/tree/visitors/extend.rb +68 -0
  129. data/lib/sass/tree/visitors/perform.rb +539 -0
  130. data/lib/sass/tree/visitors/set_options.rb +139 -0
  131. data/lib/sass/tree/visitors/to_css.rb +381 -0
  132. data/lib/sass/tree/warn_node.rb +18 -0
  133. data/lib/sass/tree/while_node.rb +18 -0
  134. data/lib/sass/util/cross_platform_random.rb +19 -0
  135. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  136. data/lib/sass/util/normalized_map.rb +130 -0
  137. data/lib/sass/util/ordered_hash.rb +192 -0
  138. data/lib/sass/util/subset_map.rb +110 -0
  139. data/lib/sass/util/test.rb +9 -0
  140. data/lib/sass/util.rb +1318 -0
  141. data/lib/sass/version.rb +124 -0
  142. data/lib/sass.rb +102 -0
  143. data/rails/init.rb +1 -0
  144. data/test/sass/cache_test.rb +131 -0
  145. data/test/sass/callbacks_test.rb +61 -0
  146. data/test/sass/compiler_test.rb +232 -0
  147. data/test/sass/conversion_test.rb +2054 -0
  148. data/test/sass/css2sass_test.rb +477 -0
  149. data/test/sass/data/hsl-rgb.txt +319 -0
  150. data/test/sass/encoding_test.rb +219 -0
  151. data/test/sass/engine_test.rb +3301 -0
  152. data/test/sass/exec_test.rb +86 -0
  153. data/test/sass/extend_test.rb +1661 -0
  154. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  155. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  156. data/test/sass/functions_test.rb +1926 -0
  157. data/test/sass/importer_test.rb +412 -0
  158. data/test/sass/logger_test.rb +58 -0
  159. data/test/sass/mock_importer.rb +49 -0
  160. data/test/sass/more_results/more1.css +9 -0
  161. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  162. data/test/sass/more_results/more_import.css +29 -0
  163. data/test/sass/more_templates/_more_partial.sass +2 -0
  164. data/test/sass/more_templates/more1.sass +23 -0
  165. data/test/sass/more_templates/more_import.sass +11 -0
  166. data/test/sass/plugin_test.rb +554 -0
  167. data/test/sass/results/alt.css +4 -0
  168. data/test/sass/results/basic.css +9 -0
  169. data/test/sass/results/cached_import_option.css +3 -0
  170. data/test/sass/results/compact.css +5 -0
  171. data/test/sass/results/complex.css +86 -0
  172. data/test/sass/results/compressed.css +1 -0
  173. data/test/sass/results/expanded.css +19 -0
  174. data/test/sass/results/filename_fn.css +3 -0
  175. data/test/sass/results/if.css +3 -0
  176. data/test/sass/results/import.css +31 -0
  177. data/test/sass/results/import_charset.css +5 -0
  178. data/test/sass/results/import_charset_1_8.css +5 -0
  179. data/test/sass/results/import_charset_ibm866.css +5 -0
  180. data/test/sass/results/import_content.css +1 -0
  181. data/test/sass/results/line_numbers.css +49 -0
  182. data/test/sass/results/mixins.css +95 -0
  183. data/test/sass/results/multiline.css +24 -0
  184. data/test/sass/results/nested.css +22 -0
  185. data/test/sass/results/options.css +1 -0
  186. data/test/sass/results/parent_ref.css +13 -0
  187. data/test/sass/results/script.css +16 -0
  188. data/test/sass/results/scss_import.css +31 -0
  189. data/test/sass/results/scss_importee.css +2 -0
  190. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  191. data/test/sass/results/subdir/subdir.css +3 -0
  192. data/test/sass/results/units.css +11 -0
  193. data/test/sass/results/warn.css +0 -0
  194. data/test/sass/results/warn_imported.css +0 -0
  195. data/test/sass/script_conversion_test.rb +328 -0
  196. data/test/sass/script_test.rb +1054 -0
  197. data/test/sass/scss/css_test.rb +1215 -0
  198. data/test/sass/scss/rx_test.rb +156 -0
  199. data/test/sass/scss/scss_test.rb +3900 -0
  200. data/test/sass/scss/test_helper.rb +37 -0
  201. data/test/sass/source_map_test.rb +977 -0
  202. data/test/sass/superselector_test.rb +191 -0
  203. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  204. data/test/sass/templates/_double_import_loop2.sass +1 -0
  205. data/test/sass/templates/_filename_fn_import.scss +11 -0
  206. data/test/sass/templates/_imported_charset_ibm866.sass +4 -0
  207. data/test/sass/templates/_imported_charset_utf8.sass +4 -0
  208. data/test/sass/templates/_imported_content.sass +3 -0
  209. data/test/sass/templates/_partial.sass +2 -0
  210. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  211. data/test/sass/templates/alt.sass +16 -0
  212. data/test/sass/templates/basic.sass +23 -0
  213. data/test/sass/templates/bork1.sass +2 -0
  214. data/test/sass/templates/bork2.sass +2 -0
  215. data/test/sass/templates/bork3.sass +2 -0
  216. data/test/sass/templates/bork4.sass +2 -0
  217. data/test/sass/templates/bork5.sass +3 -0
  218. data/test/sass/templates/cached_import_option.scss +3 -0
  219. data/test/sass/templates/compact.sass +17 -0
  220. data/test/sass/templates/complex.sass +305 -0
  221. data/test/sass/templates/compressed.sass +15 -0
  222. data/test/sass/templates/double_import_loop1.sass +1 -0
  223. data/test/sass/templates/expanded.sass +17 -0
  224. data/test/sass/templates/filename_fn.scss +18 -0
  225. data/test/sass/templates/if.sass +11 -0
  226. data/test/sass/templates/import.sass +12 -0
  227. data/test/sass/templates/import_charset.sass +9 -0
  228. data/test/sass/templates/import_charset_1_8.sass +6 -0
  229. data/test/sass/templates/import_charset_ibm866.sass +11 -0
  230. data/test/sass/templates/import_content.sass +4 -0
  231. data/test/sass/templates/importee.less +2 -0
  232. data/test/sass/templates/importee.sass +19 -0
  233. data/test/sass/templates/line_numbers.sass +13 -0
  234. data/test/sass/templates/mixin_bork.sass +5 -0
  235. data/test/sass/templates/mixins.sass +76 -0
  236. data/test/sass/templates/multiline.sass +20 -0
  237. data/test/sass/templates/nested.sass +25 -0
  238. data/test/sass/templates/nested_bork1.sass +2 -0
  239. data/test/sass/templates/nested_bork2.sass +2 -0
  240. data/test/sass/templates/nested_bork3.sass +2 -0
  241. data/test/sass/templates/nested_bork4.sass +2 -0
  242. data/test/sass/templates/nested_import.sass +2 -0
  243. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  244. data/test/sass/templates/options.sass +2 -0
  245. data/test/sass/templates/parent_ref.sass +25 -0
  246. data/test/sass/templates/same_name_different_ext.sass +2 -0
  247. data/test/sass/templates/same_name_different_ext.scss +1 -0
  248. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  249. data/test/sass/templates/script.sass +101 -0
  250. data/test/sass/templates/scss_import.scss +12 -0
  251. data/test/sass/templates/scss_importee.scss +1 -0
  252. data/test/sass/templates/single_import_loop.sass +1 -0
  253. data/test/sass/templates/subdir/import_up1.scss +1 -0
  254. data/test/sass/templates/subdir/import_up2.scss +1 -0
  255. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  256. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  257. data/test/sass/templates/subdir/subdir.sass +6 -0
  258. data/test/sass/templates/units.sass +11 -0
  259. data/test/sass/templates/warn.sass +3 -0
  260. data/test/sass/templates/warn_imported.sass +4 -0
  261. data/test/sass/test_helper.rb +8 -0
  262. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  263. data/test/sass/util/normalized_map_test.rb +51 -0
  264. data/test/sass/util/subset_map_test.rb +91 -0
  265. data/test/sass/util_test.rb +467 -0
  266. data/test/sass/value_helpers_test.rb +179 -0
  267. data/test/test_helper.rb +109 -0
  268. metadata +386 -0
@@ -0,0 +1,139 @@
1
+ # A visitor for setting options on the Sass tree
2
+ class Sass::Tree::Visitors::SetOptions < Sass::Tree::Visitors::Base
3
+ # @param root [Tree::Node] The root node of the tree to visit.
4
+ # @param options [{Symbol => Object}] The options has to set.
5
+ def self.visit(root, options); new(options).send(:visit, root); end
6
+
7
+ protected
8
+
9
+ def initialize(options)
10
+ @options = options
11
+ end
12
+
13
+ def visit(node)
14
+ node.instance_variable_set('@options', @options)
15
+ super
16
+ end
17
+
18
+ def visit_comment(node)
19
+ node.value.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
20
+ yield
21
+ end
22
+
23
+ def visit_debug(node)
24
+ node.expr.options = @options
25
+ yield
26
+ end
27
+
28
+ def visit_error(node)
29
+ node.expr.options = @options
30
+ yield
31
+ end
32
+
33
+ def visit_each(node)
34
+ node.list.options = @options
35
+ yield
36
+ end
37
+
38
+ def visit_extend(node)
39
+ node.selector.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
40
+ yield
41
+ end
42
+
43
+ def visit_for(node)
44
+ node.from.options = @options
45
+ node.to.options = @options
46
+ yield
47
+ end
48
+
49
+ def visit_function(node)
50
+ node.args.each do |k, v|
51
+ k.options = @options
52
+ v.options = @options if v
53
+ end
54
+ node.splat.options = @options if node.splat
55
+ yield
56
+ end
57
+
58
+ def visit_if(node)
59
+ node.expr.options = @options if node.expr
60
+ visit(node.else) if node.else
61
+ yield
62
+ end
63
+
64
+ def visit_import(node)
65
+ # We have no good way of propagating the new options through an Engine
66
+ # instance, so we just null it out. This also lets us avoid caching an
67
+ # imported Engine along with the importing source tree.
68
+ node.imported_file = nil
69
+ yield
70
+ end
71
+
72
+ def visit_mixindef(node)
73
+ node.args.each do |k, v|
74
+ k.options = @options
75
+ v.options = @options if v
76
+ end
77
+ node.splat.options = @options if node.splat
78
+ yield
79
+ end
80
+
81
+ def visit_mixin(node)
82
+ node.args.each {|a| a.options = @options}
83
+ node.keywords.each {|k, v| v.options = @options}
84
+ node.splat.options = @options if node.splat
85
+ node.kwarg_splat.options = @options if node.kwarg_splat
86
+ yield
87
+ end
88
+
89
+ def visit_prop(node)
90
+ node.name.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
91
+ node.value.options = @options
92
+ yield
93
+ end
94
+
95
+ def visit_return(node)
96
+ node.expr.options = @options
97
+ yield
98
+ end
99
+
100
+ def visit_rule(node)
101
+ node.rule.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
102
+ yield
103
+ end
104
+
105
+ def visit_variable(node)
106
+ node.expr.options = @options
107
+ yield
108
+ end
109
+
110
+ def visit_warn(node)
111
+ node.expr.options = @options
112
+ yield
113
+ end
114
+
115
+ def visit_while(node)
116
+ node.expr.options = @options
117
+ yield
118
+ end
119
+
120
+ def visit_directive(node)
121
+ node.value.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
122
+ yield
123
+ end
124
+
125
+ def visit_media(node)
126
+ node.query.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)}
127
+ yield
128
+ end
129
+
130
+ def visit_cssimport(node)
131
+ node.query.each {|c| c.options = @options if c.is_a?(Sass::Script::Tree::Node)} if node.query
132
+ yield
133
+ end
134
+
135
+ def visit_supports(node)
136
+ node.condition.options = @options
137
+ yield
138
+ end
139
+ end
@@ -0,0 +1,381 @@
1
+ # A visitor for converting a Sass tree into CSS.
2
+ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
3
+ # The source mapping for the generated CSS file. This is only set if
4
+ # `build_source_mapping` is passed to the constructor and \{Sass::Engine#render} has been
5
+ # run.
6
+ attr_reader :source_mapping
7
+
8
+ # @param build_source_mapping [Boolean] Whether to build a
9
+ # \{Sass::Source::Map} while creating the CSS output. The mapping will
10
+ # be available from \{#source\_mapping} after the visitor has completed.
11
+ def initialize(build_source_mapping = false)
12
+ @tabs = 0
13
+ @line = 1
14
+ @offset = 1
15
+ @result = ""
16
+ @source_mapping = Sass::Source::Map.new if build_source_mapping
17
+ end
18
+
19
+ # Runs the visitor on `node`.
20
+ #
21
+ # @param node [Sass::Tree::Node] The root node of the tree to convert to CSS>
22
+ # @return [String] The CSS output.
23
+ def visit(node)
24
+ super
25
+ rescue Sass::SyntaxError => e
26
+ e.modify_backtrace(:filename => node.filename, :line => node.line)
27
+ raise e
28
+ end
29
+
30
+ protected
31
+
32
+ def with_tabs(tabs)
33
+ old_tabs, @tabs = @tabs, tabs
34
+ yield
35
+ ensure
36
+ @tabs = old_tabs
37
+ end
38
+
39
+ # Associate all output produced in a block with a given node. Used for source
40
+ # mapping.
41
+ def for_node(node, attr_prefix = nil)
42
+ return yield unless @source_mapping
43
+ start_pos = Sass::Source::Position.new(@line, @offset)
44
+ yield
45
+
46
+ range_attr = attr_prefix ? :"#{attr_prefix}_source_range" : :source_range
47
+ return if node.invisible? || !node.send(range_attr)
48
+ source_range = node.send(range_attr)
49
+ target_end_pos = Sass::Source::Position.new(@line, @offset)
50
+ target_range = Sass::Source::Range.new(start_pos, target_end_pos, nil)
51
+ @source_mapping.add(source_range, target_range)
52
+ end
53
+
54
+ # Move the output cursor back `chars` characters.
55
+ def erase!(chars)
56
+ return if chars == 0
57
+ str = @result.slice!(-chars..-1)
58
+ newlines = str.count("\n")
59
+ if newlines > 0
60
+ @line -= newlines
61
+ @offset = @result[@result.rindex("\n") || 0..-1].size
62
+ else
63
+ @offset -= chars
64
+ end
65
+ end
66
+
67
+ # Avoid allocating lots of new strings for `#output`. This is important
68
+ # because `#output` is called all the time.
69
+ NEWLINE = "\n"
70
+
71
+ # Add `s` to the output string and update the line and offset information
72
+ # accordingly.
73
+ def output(s)
74
+ if @lstrip
75
+ s = s.gsub(/\A\s+/, "")
76
+ @lstrip = false
77
+ end
78
+
79
+ newlines = s.count(NEWLINE)
80
+ if newlines > 0
81
+ @line += newlines
82
+ @offset = s[s.rindex(NEWLINE)..-1].size
83
+ else
84
+ @offset += s.size
85
+ end
86
+
87
+ @result << s
88
+ end
89
+
90
+ # Strip all trailing whitespace from the output string.
91
+ def rstrip!
92
+ erase! @result.length - 1 - (@result.rindex(/[^\s]/) || -1)
93
+ end
94
+
95
+ # lstrip the first output in the given block.
96
+ def lstrip
97
+ old_lstrip = @lstrip
98
+ @lstrip = true
99
+ yield
100
+ ensure
101
+ @lstrip = @lstrip && old_lstrip
102
+ end
103
+
104
+ # Prepend `prefix` to the output string.
105
+ def prepend!(prefix)
106
+ @result.insert 0, prefix
107
+ return unless @source_mapping
108
+
109
+ line_delta = prefix.count("\n")
110
+ offset_delta = prefix.gsub(/.*\n/, '').size
111
+ @source_mapping.shift_output_offsets(offset_delta)
112
+ @source_mapping.shift_output_lines(line_delta)
113
+ end
114
+
115
+ def visit_root(node)
116
+ node.children.each do |child|
117
+ next if child.invisible?
118
+ visit(child)
119
+ unless node.style == :compressed
120
+ output "\n"
121
+ if child.is_a?(Sass::Tree::DirectiveNode) && child.has_children && !child.bubbles?
122
+ output "\n"
123
+ end
124
+ end
125
+ end
126
+ rstrip!
127
+ return "" if @result.empty?
128
+
129
+ output "\n"
130
+
131
+ unless Sass::Util.ruby1_8? || @result.ascii_only?
132
+ if node.style == :compressed
133
+ # A byte order mark is sufficient to tell browsers that this
134
+ # file is UTF-8 encoded, and will override any other detection
135
+ # methods as per http://encoding.spec.whatwg.org/#decode-and-encode.
136
+ prepend! "\uFEFF"
137
+ else
138
+ prepend! "@charset \"UTF-8\";\n"
139
+ end
140
+ end
141
+
142
+ @result
143
+ rescue Sass::SyntaxError => e
144
+ e.sass_template ||= node.template
145
+ raise e
146
+ end
147
+
148
+ def visit_charset(node)
149
+ for_node(node) {output("@charset \"#{node.name}\";")}
150
+ end
151
+
152
+ def visit_comment(node)
153
+ return if node.invisible?
154
+ spaces = (' ' * [@tabs - node.resolved_value[/^ */].size, 0].max)
155
+
156
+ content = node.resolved_value.gsub(/^/, spaces)
157
+ if node.type == :silent
158
+ content.gsub!(%r{^(\s*)//(.*)$}) {|md| "#{$1}/*#{$2} */"}
159
+ end
160
+ if (node.style == :compact || node.style == :compressed) && node.type != :loud
161
+ content.gsub!(/\n +(\* *(?!\/))?/, ' ')
162
+ end
163
+ for_node(node) {output(content)}
164
+ end
165
+
166
+ # @comment
167
+ # rubocop:disable MethodLength
168
+ def visit_directive(node)
169
+ was_in_directive = @in_directive
170
+ tab_str = ' ' * @tabs
171
+ if !node.has_children || node.children.empty?
172
+ output(tab_str)
173
+ for_node(node) {output(node.resolved_value)}
174
+ output(!node.has_children ? ";" : " {}")
175
+ return
176
+ end
177
+
178
+ @in_directive = @in_directive || !node.is_a?(Sass::Tree::MediaNode)
179
+ output(tab_str) if node.style != :compressed
180
+ for_node(node) {output(node.resolved_value)}
181
+ output(node.style == :compressed ? "{" : " {")
182
+ output(node.style == :compact ? ' ' : "\n") if node.style != :compressed
183
+
184
+ was_prop = false
185
+ first = true
186
+ node.children.each do |child|
187
+ next if child.invisible?
188
+ if node.style == :compact
189
+ if child.is_a?(Sass::Tree::PropNode)
190
+ with_tabs(first || was_prop ? 0 : @tabs + 1) do
191
+ visit(child)
192
+ output(' ')
193
+ end
194
+ else
195
+ if was_prop
196
+ erase! 1
197
+ output "\n"
198
+ end
199
+
200
+ if first
201
+ lstrip {with_tabs(@tabs + 1) {visit(child)}}
202
+ else
203
+ with_tabs(@tabs + 1) {visit(child)}
204
+ end
205
+
206
+ rstrip!
207
+ output "\n"
208
+ end
209
+ was_prop = child.is_a?(Sass::Tree::PropNode)
210
+ first = false
211
+ elsif node.style == :compressed
212
+ output(was_prop ? ";" : "")
213
+ with_tabs(0) {visit(child)}
214
+ was_prop = child.is_a?(Sass::Tree::PropNode)
215
+ else
216
+ with_tabs(@tabs + 1) {visit(child)}
217
+ output "\n"
218
+ end
219
+ end
220
+ rstrip!
221
+ if node.style == :expanded
222
+ output("\n#{tab_str}")
223
+ elsif node.style != :compressed
224
+ output(" ")
225
+ end
226
+ output("}")
227
+ ensure
228
+ @in_directive = was_in_directive
229
+ end
230
+ # @comment
231
+ # rubocop:enable MethodLength
232
+
233
+ def visit_media(node)
234
+ with_tabs(@tabs + node.tabs) {visit_directive(node)}
235
+ output("\n") if node.style != :compressed && node.group_end
236
+ end
237
+
238
+ def visit_supports(node)
239
+ visit_media(node)
240
+ end
241
+
242
+ def visit_cssimport(node)
243
+ visit_directive(node)
244
+ end
245
+
246
+ def visit_prop(node)
247
+ return if node.resolved_value.empty?
248
+ tab_str = ' ' * (@tabs + node.tabs)
249
+ output(tab_str)
250
+ for_node(node, :name) {output(node.resolved_name)}
251
+ if node.style == :compressed
252
+ output(":")
253
+ for_node(node, :value) {output(node.resolved_value)}
254
+ else
255
+ output(": ")
256
+ for_node(node, :value) {output(node.resolved_value)}
257
+ output(";")
258
+ end
259
+ end
260
+
261
+ # @comment
262
+ # rubocop:disable MethodLength
263
+ def visit_rule(node)
264
+ with_tabs(@tabs + node.tabs) do
265
+ rule_separator = node.style == :compressed ? ',' : ', '
266
+ line_separator =
267
+ case node.style
268
+ when :nested, :expanded; "\n"
269
+ when :compressed; ""
270
+ else; " "
271
+ end
272
+ rule_indent = ' ' * @tabs
273
+ per_rule_indent, total_indent = if [:nested, :expanded].include?(node.style)
274
+ [rule_indent, '']
275
+ else
276
+ ['', rule_indent]
277
+ end
278
+
279
+ joined_rules = node.resolved_rules.members.map do |seq|
280
+ next if seq.has_placeholder?
281
+ rule_part = seq.to_s
282
+ if node.style == :compressed
283
+ rule_part.gsub!(/([^,])\s*\n\s*/m, '\1 ')
284
+ rule_part.gsub!(/\s*([,+>])\s*/m, '\1')
285
+ rule_part.strip!
286
+ end
287
+ rule_part
288
+ end.compact.join(rule_separator)
289
+
290
+ joined_rules.lstrip!
291
+ joined_rules.gsub!(/\s*\n\s*/, "#{line_separator}#{per_rule_indent}")
292
+
293
+ old_spaces = ' ' * @tabs
294
+ if node.style != :compressed
295
+ if node.options[:debug_info] && !@in_directive
296
+ visit(debug_info_rule(node.debug_info, node.options))
297
+ output "\n"
298
+ elsif node.options[:trace_selectors]
299
+ output("#{old_spaces}/* ")
300
+ output(node.stack_trace.gsub("\n", "\n #{old_spaces}"))
301
+ output(" */\n")
302
+ elsif node.options[:line_comments]
303
+ output("#{old_spaces}/* line #{node.line}")
304
+
305
+ if node.filename
306
+ relative_filename =
307
+ if node.options[:css_filename]
308
+ begin
309
+ Sass::Util.pathname(node.filename).relative_path_from(
310
+ Sass::Util.pathname(File.dirname(node.options[:css_filename]))).to_s
311
+ rescue ArgumentError
312
+ nil
313
+ end
314
+ end
315
+ relative_filename ||= node.filename
316
+ output(", #{relative_filename}")
317
+ end
318
+
319
+ output(" */\n")
320
+ end
321
+ end
322
+
323
+ end_props, trailer, tabs = '', '', 0
324
+ if node.style == :compact
325
+ separator, end_props, bracket = ' ', ' ', ' { '
326
+ trailer = "\n" if node.group_end
327
+ elsif node.style == :compressed
328
+ separator, bracket = ';', '{'
329
+ else
330
+ tabs = @tabs + 1
331
+ separator, bracket = "\n", " {\n"
332
+ trailer = "\n" if node.group_end
333
+ end_props = (node.style == :expanded ? "\n" + old_spaces : ' ')
334
+ end
335
+ output(total_indent + per_rule_indent)
336
+ for_node(node, :selector) {output(joined_rules)}
337
+ output(bracket)
338
+
339
+ with_tabs(tabs) do
340
+ node.children.each_with_index do |child, i|
341
+ output(separator) if i > 0
342
+ visit(child)
343
+ end
344
+ end
345
+
346
+ output(end_props)
347
+ output("}" + trailer)
348
+ end
349
+ end
350
+ # @comment
351
+ # rubocop:enable MethodLength
352
+
353
+ def visit_keyframerule(node)
354
+ visit_directive(node)
355
+ end
356
+
357
+ private
358
+
359
+ def debug_info_rule(debug_info, options)
360
+ node = Sass::Tree::DirectiveNode.resolved("@media -sass-debug-info")
361
+ Sass::Util.hash_to_a(debug_info.map {|k, v| [k.to_s, v.to_s]}).each do |k, v|
362
+ rule = Sass::Tree::RuleNode.new([""])
363
+ rule.resolved_rules = Sass::Selector::CommaSequence.new(
364
+ [Sass::Selector::Sequence.new(
365
+ [Sass::Selector::SimpleSequence.new(
366
+ [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)],
367
+ false)
368
+ ])
369
+ ])
370
+ prop = Sass::Tree::PropNode.new([""], Sass::Script::Value::String.new(''), :new)
371
+ prop.resolved_name = "font-family"
372
+ prop.resolved_value = Sass::SCSS::RX.escape_ident(v.to_s)
373
+ rule << prop
374
+ node << rule
375
+ end
376
+ node.options = options.merge(:debug_info => false,
377
+ :line_comments => false,
378
+ :style => :compressed)
379
+ node
380
+ end
381
+ end