sass 3.3.0 → 3.4.25

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 (208) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -1
  3. data/CODE_OF_CONDUCT.md +10 -0
  4. data/CONTRIBUTING.md +148 -0
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +76 -62
  7. data/Rakefile +104 -24
  8. data/VERSION +1 -1
  9. data/VERSION_DATE +1 -1
  10. data/VERSION_NAME +1 -1
  11. data/bin/sass +1 -1
  12. data/bin/scss +1 -1
  13. data/extra/sass-spec-ref.sh +32 -0
  14. data/extra/update_watch.rb +1 -1
  15. data/lib/sass/cache_stores/filesystem.rb +9 -5
  16. data/lib/sass/cache_stores/memory.rb +4 -5
  17. data/lib/sass/callbacks.rb +2 -2
  18. data/lib/sass/css.rb +12 -13
  19. data/lib/sass/deprecation.rb +55 -0
  20. data/lib/sass/engine.rb +106 -70
  21. data/lib/sass/environment.rb +39 -19
  22. data/lib/sass/error.rb +17 -20
  23. data/lib/sass/exec/base.rb +199 -0
  24. data/lib/sass/exec/sass_convert.rb +283 -0
  25. data/lib/sass/exec/sass_scss.rb +440 -0
  26. data/lib/sass/exec.rb +5 -771
  27. data/lib/sass/features.rb +9 -2
  28. data/lib/sass/importers/base.rb +8 -3
  29. data/lib/sass/importers/filesystem.rb +30 -38
  30. data/lib/sass/logger/base.rb +8 -2
  31. data/lib/sass/logger/delayed.rb +50 -0
  32. data/lib/sass/logger.rb +8 -3
  33. data/lib/sass/media.rb +1 -4
  34. data/lib/sass/plugin/compiler.rb +224 -90
  35. data/lib/sass/plugin/configuration.rb +38 -22
  36. data/lib/sass/plugin/merb.rb +2 -2
  37. data/lib/sass/plugin/rack.rb +3 -3
  38. data/lib/sass/plugin/rails.rb +1 -1
  39. data/lib/sass/plugin/staleness_checker.rb +4 -4
  40. data/lib/sass/plugin.rb +6 -5
  41. data/lib/sass/script/css_lexer.rb +1 -1
  42. data/lib/sass/script/css_parser.rb +2 -3
  43. data/lib/sass/script/css_variable_warning.rb +52 -0
  44. data/lib/sass/script/functions.rb +739 -318
  45. data/lib/sass/script/lexer.rb +134 -54
  46. data/lib/sass/script/parser.rb +252 -56
  47. data/lib/sass/script/tree/funcall.rb +13 -6
  48. data/lib/sass/script/tree/interpolation.rb +127 -4
  49. data/lib/sass/script/tree/list_literal.rb +31 -4
  50. data/lib/sass/script/tree/literal.rb +4 -0
  51. data/lib/sass/script/tree/node.rb +21 -3
  52. data/lib/sass/script/tree/operation.rb +54 -1
  53. data/lib/sass/script/tree/selector.rb +26 -0
  54. data/lib/sass/script/tree/string_interpolation.rb +59 -38
  55. data/lib/sass/script/tree/variable.rb +1 -1
  56. data/lib/sass/script/tree.rb +1 -0
  57. data/lib/sass/script/value/base.rb +17 -14
  58. data/lib/sass/script/value/bool.rb +0 -5
  59. data/lib/sass/script/value/color.rb +78 -42
  60. data/lib/sass/script/value/helpers.rb +119 -2
  61. data/lib/sass/script/value/list.rb +0 -15
  62. data/lib/sass/script/value/map.rb +1 -1
  63. data/lib/sass/script/value/null.rb +0 -5
  64. data/lib/sass/script/value/number.rb +112 -31
  65. data/lib/sass/script/value/string.rb +102 -13
  66. data/lib/sass/script/value.rb +0 -1
  67. data/lib/sass/script.rb +3 -3
  68. data/lib/sass/scss/css_parser.rb +24 -4
  69. data/lib/sass/scss/parser.rb +290 -383
  70. data/lib/sass/scss/rx.rb +17 -9
  71. data/lib/sass/scss/static_parser.rb +306 -4
  72. data/lib/sass/scss.rb +0 -2
  73. data/lib/sass/selector/abstract_sequence.rb +35 -18
  74. data/lib/sass/selector/comma_sequence.rb +114 -19
  75. data/lib/sass/selector/pseudo.rb +266 -0
  76. data/lib/sass/selector/sequence.rb +146 -40
  77. data/lib/sass/selector/simple.rb +22 -33
  78. data/lib/sass/selector/simple_sequence.rb +122 -39
  79. data/lib/sass/selector.rb +57 -197
  80. data/lib/sass/shared.rb +2 -2
  81. data/lib/sass/source/map.rb +31 -14
  82. data/lib/sass/source/position.rb +4 -4
  83. data/lib/sass/stack.rb +2 -8
  84. data/lib/sass/supports.rb +10 -13
  85. data/lib/sass/tree/at_root_node.rb +1 -0
  86. data/lib/sass/tree/charset_node.rb +1 -1
  87. data/lib/sass/tree/comment_node.rb +1 -1
  88. data/lib/sass/tree/css_import_node.rb +9 -1
  89. data/lib/sass/tree/directive_node.rb +8 -2
  90. data/lib/sass/tree/error_node.rb +18 -0
  91. data/lib/sass/tree/extend_node.rb +1 -1
  92. data/lib/sass/tree/function_node.rb +9 -0
  93. data/lib/sass/tree/import_node.rb +6 -5
  94. data/lib/sass/tree/keyframe_rule_node.rb +15 -0
  95. data/lib/sass/tree/node.rb +5 -3
  96. data/lib/sass/tree/prop_node.rb +6 -7
  97. data/lib/sass/tree/rule_node.rb +26 -11
  98. data/lib/sass/tree/visitors/check_nesting.rb +56 -32
  99. data/lib/sass/tree/visitors/convert.rb +59 -44
  100. data/lib/sass/tree/visitors/cssize.rb +34 -30
  101. data/lib/sass/tree/visitors/deep_copy.rb +6 -1
  102. data/lib/sass/tree/visitors/extend.rb +15 -13
  103. data/lib/sass/tree/visitors/perform.rb +87 -50
  104. data/lib/sass/tree/visitors/set_options.rb +15 -1
  105. data/lib/sass/tree/visitors/to_css.rb +72 -43
  106. data/lib/sass/util/multibyte_string_scanner.rb +0 -2
  107. data/lib/sass/util/normalized_map.rb +0 -1
  108. data/lib/sass/util/subset_map.rb +2 -3
  109. data/lib/sass/util.rb +334 -154
  110. data/lib/sass/version.rb +7 -7
  111. data/lib/sass.rb +10 -8
  112. data/test/sass/cache_test.rb +62 -20
  113. data/test/sass/callbacks_test.rb +1 -1
  114. data/test/sass/compiler_test.rb +24 -11
  115. data/test/sass/conversion_test.rb +241 -50
  116. data/test/sass/css2sass_test.rb +73 -5
  117. data/test/sass/css_variable_test.rb +132 -0
  118. data/test/sass/encoding_test.rb +219 -0
  119. data/test/sass/engine_test.rb +343 -260
  120. data/test/sass/exec_test.rb +12 -2
  121. data/test/sass/extend_test.rb +333 -44
  122. data/test/sass/functions_test.rb +353 -260
  123. data/test/sass/importer_test.rb +40 -21
  124. data/test/sass/logger_test.rb +1 -1
  125. data/test/sass/more_results/more_import.css +1 -1
  126. data/test/sass/more_templates/more1.sass +10 -10
  127. data/test/sass/more_templates/more_import.sass +2 -2
  128. data/test/sass/plugin_test.rb +24 -21
  129. data/test/sass/results/compact.css +1 -1
  130. data/test/sass/results/complex.css +4 -4
  131. data/test/sass/results/expanded.css +1 -1
  132. data/test/sass/results/import.css +1 -1
  133. data/test/sass/results/import_charset_ibm866.css +2 -2
  134. data/test/sass/results/mixins.css +17 -17
  135. data/test/sass/results/nested.css +1 -1
  136. data/test/sass/results/parent_ref.css +2 -2
  137. data/test/sass/results/script.css +5 -5
  138. data/test/sass/results/scss_import.css +1 -1
  139. data/test/sass/script_conversion_test.rb +71 -39
  140. data/test/sass/script_test.rb +714 -123
  141. data/test/sass/scss/css_test.rb +213 -30
  142. data/test/sass/scss/rx_test.rb +8 -4
  143. data/test/sass/scss/scss_test.rb +766 -22
  144. data/test/sass/source_map_test.rb +263 -95
  145. data/test/sass/superselector_test.rb +210 -0
  146. data/test/sass/templates/_partial.sass +1 -1
  147. data/test/sass/templates/basic.sass +10 -10
  148. data/test/sass/templates/bork1.sass +1 -1
  149. data/test/sass/templates/bork5.sass +1 -1
  150. data/test/sass/templates/compact.sass +10 -10
  151. data/test/sass/templates/complex.sass +187 -187
  152. data/test/sass/templates/compressed.sass +10 -10
  153. data/test/sass/templates/expanded.sass +10 -10
  154. data/test/sass/templates/import.sass +2 -2
  155. data/test/sass/templates/importee.sass +3 -3
  156. data/test/sass/templates/mixins.sass +22 -22
  157. data/test/sass/templates/multiline.sass +4 -4
  158. data/test/sass/templates/nested.sass +13 -13
  159. data/test/sass/templates/parent_ref.sass +12 -12
  160. data/test/sass/templates/script.sass +70 -70
  161. data/test/sass/templates/scss_import.scss +2 -1
  162. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
  163. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
  164. data/test/sass/templates/subdir/subdir.sass +3 -3
  165. data/test/sass/templates/units.sass +10 -10
  166. data/test/sass/test_helper.rb +1 -1
  167. data/test/sass/util/multibyte_string_scanner_test.rb +11 -3
  168. data/test/sass/util/normalized_map_test.rb +1 -1
  169. data/test/sass/util/subset_map_test.rb +2 -2
  170. data/test/sass/util_test.rb +46 -45
  171. data/test/sass/value_helpers_test.rb +5 -7
  172. data/test/sass-spec.yml +3 -0
  173. data/test/test_helper.rb +7 -6
  174. data/vendor/listen/CHANGELOG.md +1 -228
  175. data/vendor/listen/Gemfile +5 -15
  176. data/vendor/listen/README.md +111 -77
  177. data/vendor/listen/Rakefile +0 -42
  178. data/vendor/listen/lib/listen/adapter.rb +195 -82
  179. data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
  180. data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
  181. data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
  182. data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
  183. data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
  184. data/vendor/listen/lib/listen/directory_record.rb +96 -61
  185. data/vendor/listen/lib/listen/listener.rb +135 -37
  186. data/vendor/listen/lib/listen/turnstile.rb +9 -5
  187. data/vendor/listen/lib/listen/version.rb +1 -1
  188. data/vendor/listen/lib/listen.rb +33 -19
  189. data/vendor/listen/listen.gemspec +6 -0
  190. data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
  191. data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
  192. data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
  193. data/vendor/listen/spec/listen/listener_spec.rb +128 -39
  194. data/vendor/listen/spec/listen_spec.rb +15 -21
  195. data/vendor/listen/spec/spec_helper.rb +4 -0
  196. data/vendor/listen/spec/support/adapter_helper.rb +52 -15
  197. data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
  198. data/vendor/listen/spec/support/listeners_helper.rb +30 -7
  199. metadata +310 -300
  200. data/CONTRIBUTING +0 -3
  201. data/ext/mkrf_conf.rb +0 -27
  202. data/lib/sass/script/value/deprecated_false.rb +0 -55
  203. data/lib/sass/scss/script_lexer.rb +0 -15
  204. data/lib/sass/scss/script_parser.rb +0 -25
  205. data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
  206. data/vendor/listen/lib/listen/multi_listener.rb +0 -143
  207. data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
  208. data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
@@ -0,0 +1,440 @@
1
+ module Sass::Exec
2
+ # The `sass` and `scss` executables.
3
+ class SassScss < Base
4
+ attr_reader :default_syntax
5
+
6
+ # @param args [Array<String>] The command-line arguments
7
+ def initialize(args, default_syntax)
8
+ super(args)
9
+ @options[:sourcemap] = :auto
10
+ @options[:for_engine] = {
11
+ :load_paths => default_sass_path
12
+ }
13
+ @default_syntax = default_syntax
14
+ end
15
+
16
+ protected
17
+
18
+ # Tells optparse how to parse the arguments.
19
+ #
20
+ # @param opts [OptionParser]
21
+ def set_opts(opts)
22
+ opts.banner = <<END
23
+ Usage: #{default_syntax} [options] [INPUT] [OUTPUT]
24
+
25
+ Description:
26
+ Converts SCSS or Sass files to CSS.
27
+ END
28
+
29
+ common_options(opts)
30
+ watching_and_updating(opts)
31
+ input_and_output(opts)
32
+ miscellaneous(opts)
33
+ end
34
+
35
+ # Processes the options set by the command-line arguments,
36
+ # and runs the Sass compiler appropriately.
37
+ def process_result
38
+ require 'sass'
39
+
40
+ if !@options[:update] && !@options[:watch] &&
41
+ @args.first && colon_path?(@args.first)
42
+ if @args.size == 1
43
+ @args = split_colon_path(@args.first)
44
+ else
45
+ @fake_update = true
46
+ @options[:update] = true
47
+ end
48
+ end
49
+ load_compass if @options[:compass]
50
+ return interactive if @options[:interactive]
51
+ return watch_or_update if @options[:watch] || @options[:update]
52
+ super
53
+
54
+ if @options[:sourcemap] != :none && @options[:output_filename]
55
+ @options[:sourcemap_filename] = Sass::Util.sourcemap_name(@options[:output_filename])
56
+ end
57
+
58
+ @options[:for_engine][:filename] = @options[:filename]
59
+ @options[:for_engine][:css_filename] = @options[:output] if @options[:output].is_a?(String)
60
+ @options[:for_engine][:sourcemap_filename] = @options[:sourcemap_filename]
61
+ @options[:for_engine][:sourcemap] = @options[:sourcemap]
62
+
63
+ run
64
+ end
65
+
66
+ private
67
+
68
+ def common_options(opts)
69
+ opts.separator ''
70
+ opts.separator 'Common Options:'
71
+
72
+ opts.on('-I', '--load-path PATH', 'Specify a Sass import path.') do |path|
73
+ (@options[:for_engine][:load_paths] ||= []) << path
74
+ end
75
+
76
+ opts.on('-r', '--require LIB', 'Require a Ruby library before running Sass.') do |lib|
77
+ require lib
78
+ end
79
+
80
+ opts.on('--compass', 'Make Compass imports available and load project configuration.') do
81
+ @options[:compass] = true
82
+ end
83
+
84
+ opts.on('-t', '--style NAME', 'Output style. Can be nested (default), compact, ' \
85
+ 'compressed, or expanded.') do |name|
86
+ @options[:for_engine][:style] = name.to_sym
87
+ end
88
+
89
+ opts.on("-?", "-h", "--help", "Show this help message.") do
90
+ puts opts
91
+ exit
92
+ end
93
+
94
+ opts.on("-v", "--version", "Print the Sass version.") do
95
+ puts("Sass #{Sass.version[:string]}")
96
+ exit
97
+ end
98
+ end
99
+
100
+ def watching_and_updating(opts)
101
+ opts.separator ''
102
+ opts.separator 'Watching and Updating:'
103
+
104
+ opts.on('--watch', 'Watch files or directories for changes.',
105
+ 'The location of the generated CSS can be set using a colon:',
106
+ " #{@default_syntax} --watch input.#{@default_syntax}:output.css",
107
+ " #{@default_syntax} --watch input-dir:output-dir") do
108
+ @options[:watch] = true
109
+ end
110
+
111
+ # Polling is used by default on Windows.
112
+ unless Sass::Util.windows?
113
+ opts.on('--poll', 'Check for file changes manually, rather than relying on the OS.',
114
+ 'Only meaningful for --watch.') do
115
+ @options[:poll] = true
116
+ end
117
+ end
118
+
119
+ opts.on('--update', 'Compile files or directories to CSS.',
120
+ 'Locations are set like --watch.') do
121
+ @options[:update] = true
122
+ end
123
+
124
+ opts.on('-f', '--force', 'Recompile every Sass file, even if the CSS file is newer.',
125
+ 'Only meaningful for --update.') do
126
+ @options[:force] = true
127
+ end
128
+
129
+ opts.on('--stop-on-error', 'If a file fails to compile, exit immediately.',
130
+ 'Only meaningful for --watch and --update.') do
131
+ @options[:stop_on_error] = true
132
+ end
133
+ end
134
+
135
+ def input_and_output(opts)
136
+ opts.separator ''
137
+ opts.separator 'Input and Output:'
138
+
139
+ if @default_syntax == :sass
140
+ opts.on('--scss',
141
+ 'Use the CSS-superset SCSS syntax.') do
142
+ @options[:for_engine][:syntax] = :scss
143
+ end
144
+ else
145
+ opts.on('--sass',
146
+ 'Use the indented Sass syntax.') do
147
+ @options[:for_engine][:syntax] = :sass
148
+ end
149
+ end
150
+
151
+ # This is optional for backwards-compatibility with Sass 3.3, which didn't
152
+ # enable sourcemaps by default and instead used "--sourcemap" to do so.
153
+ opts.on(:OPTIONAL, '--sourcemap=TYPE',
154
+ 'How to link generated output to the source files.',
155
+ ' auto (default): relative paths where possible, file URIs elsewhere',
156
+ ' file: always absolute file URIs',
157
+ ' inline: include the source text in the sourcemap',
158
+ ' none: no sourcemaps') do |type|
159
+ if type && !%w(auto file inline none).include?(type)
160
+ $stderr.puts "Unknown sourcemap type #{type}.\n\n"
161
+ $stderr.puts opts
162
+ exit
163
+ elsif type.nil?
164
+ Sass::Util.sass_warn <<MESSAGE.rstrip
165
+ DEPRECATION WARNING: Passing --sourcemap without a value is deprecated.
166
+ Sourcemaps are now generated by default, so this flag has no effect.
167
+ MESSAGE
168
+ end
169
+
170
+ @options[:sourcemap] = (type || :auto).to_sym
171
+ end
172
+
173
+ opts.on('-s', '--stdin', :NONE,
174
+ 'Read input from standard input instead of an input file.',
175
+ 'This is the default if no input file is specified.') do
176
+ @options[:input] = $stdin
177
+ end
178
+
179
+ encoding_option(opts)
180
+
181
+ opts.on('--unix-newlines', 'Use Unix-style newlines in written files.',
182
+ ('Always true on Unix.' unless Sass::Util.windows?)) do
183
+ @options[:unix_newlines] = true if Sass::Util.windows?
184
+ end
185
+
186
+ opts.on('-g', '--debug-info',
187
+ 'Emit output that can be used by the FireSass Firebug plugin.') do
188
+ @options[:for_engine][:debug_info] = true
189
+ end
190
+
191
+ opts.on('-l', '--line-numbers', '--line-comments',
192
+ 'Emit comments in the generated CSS indicating the corresponding source line.') do
193
+ @options[:for_engine][:line_numbers] = true
194
+ end
195
+ end
196
+
197
+ def miscellaneous(opts)
198
+ opts.separator ''
199
+ opts.separator 'Miscellaneous:'
200
+
201
+ opts.on('-i', '--interactive',
202
+ 'Run an interactive SassScript shell.') do
203
+ @options[:interactive] = true
204
+ end
205
+
206
+ opts.on('-c', '--check', "Just check syntax, don't evaluate.") do
207
+ require 'stringio'
208
+ @options[:check_syntax] = true
209
+ @options[:output] = StringIO.new
210
+ end
211
+
212
+ opts.on('--precision NUMBER_OF_DIGITS', Integer,
213
+ "How many digits of precision to use when outputting decimal numbers.",
214
+ "Defaults to #{Sass::Script::Value::Number.precision}.") do |precision|
215
+ Sass::Script::Value::Number.precision = precision
216
+ end
217
+
218
+ opts.on('--cache-location PATH',
219
+ 'The path to save parsed Sass files. Defaults to .sass-cache.') do |loc|
220
+ @options[:for_engine][:cache_location] = loc
221
+ end
222
+
223
+ opts.on('-C', '--no-cache', "Don't cache parsed Sass files.") do
224
+ @options[:for_engine][:cache] = false
225
+ end
226
+
227
+ opts.on('--trace', :NONE, 'Show a full Ruby stack trace on error.') do
228
+ @options[:trace] = true
229
+ end
230
+
231
+ opts.on('-q', '--quiet', 'Silence warnings and status messages during compilation.') do
232
+ @options[:for_engine][:quiet] = true
233
+ end
234
+ end
235
+
236
+ def load_compass
237
+ begin
238
+ require 'compass'
239
+ rescue LoadError
240
+ require 'rubygems'
241
+ begin
242
+ require 'compass'
243
+ rescue LoadError
244
+ puts "ERROR: Cannot load compass."
245
+ exit 1
246
+ end
247
+ end
248
+ Compass.add_project_configuration
249
+ Compass.configuration.project_path ||= Dir.pwd
250
+ @options[:for_engine][:load_paths] ||= []
251
+ @options[:for_engine][:load_paths] += Compass.configuration.sass_load_paths
252
+ end
253
+
254
+ def interactive
255
+ require 'sass/repl'
256
+ Sass::Repl.new(@options).run
257
+ end
258
+
259
+ # @comment
260
+ # rubocop:disable MethodLength
261
+ def watch_or_update
262
+ require 'sass/plugin'
263
+ Sass::Plugin.options.merge! @options[:for_engine]
264
+ Sass::Plugin.options[:unix_newlines] = @options[:unix_newlines]
265
+ Sass::Plugin.options[:poll] = @options[:poll]
266
+ Sass::Plugin.options[:sourcemap] = @options[:sourcemap]
267
+
268
+ if @options[:force]
269
+ raise "The --force flag may only be used with --update." unless @options[:update]
270
+ Sass::Plugin.options[:always_update] = true
271
+ end
272
+
273
+ raise <<MSG if @args.empty?
274
+ What files should I watch? Did you mean something like:
275
+ #{@default_syntax} --watch input.#{@default_syntax}:output.css
276
+ #{@default_syntax} --watch input-dir:output-dir
277
+ MSG
278
+
279
+ if !colon_path?(@args[0]) && probably_dest_dir?(@args[1])
280
+ flag = @options[:update] ? "--update" : "--watch"
281
+ err =
282
+ if !File.exist?(@args[1])
283
+ "doesn't exist"
284
+ elsif @args[1] =~ /\.css$/
285
+ "is a CSS file"
286
+ end
287
+ raise <<MSG if err
288
+ File #{@args[1]} #{err}.
289
+ Did you mean: #{@default_syntax} #{flag} #{@args[0]}:#{@args[1]}
290
+ MSG
291
+ end
292
+
293
+ dirs, files = @args.map {|name| split_colon_path(name)}.
294
+ partition {|i, _| File.directory? i}
295
+
296
+ if @fake_update && !dirs.empty?
297
+ # Issue 1602.
298
+ Sass::Util.sass_warn <<WARNING.strip
299
+ DEPRECATION WARNING: Compiling directories without --update or --watch is
300
+ deprecated and won't work in future versions of Sass. Instead use:
301
+ #{@default_syntax} --update #{@args}
302
+ WARNING
303
+ end
304
+
305
+ files.map! do |from, to|
306
+ to ||= from.gsub(/\.[^.]*?$/, '.css')
307
+ sourcemap = Sass::Util.sourcemap_name(to) if @options[:sourcemap]
308
+ [from, to, sourcemap]
309
+ end
310
+ dirs.map! {|from, to| [from, to || from]}
311
+ Sass::Plugin.options[:template_location] = dirs
312
+
313
+ Sass::Plugin.on_updated_stylesheet do |_, css, sourcemap|
314
+ [css, sourcemap].each do |file|
315
+ next unless file
316
+ puts_action :write, :green, file
317
+ end
318
+ end
319
+
320
+ had_error = false
321
+ Sass::Plugin.on_creating_directory {|dirname| puts_action :directory, :green, dirname}
322
+ Sass::Plugin.on_deleting_css {|filename| puts_action :delete, :yellow, filename}
323
+ Sass::Plugin.on_deleting_sourcemap {|filename| puts_action :delete, :yellow, filename}
324
+ Sass::Plugin.on_compilation_error do |error, _, _|
325
+ if error.is_a?(SystemCallError) && !@options[:stop_on_error]
326
+ had_error = true
327
+ puts_action :error, :red, error.message
328
+ STDOUT.flush
329
+ next
330
+ end
331
+
332
+ raise error unless error.is_a?(Sass::SyntaxError) && !@options[:stop_on_error]
333
+ had_error = true
334
+ puts_action :error, :red,
335
+ "#{error.sass_filename} (Line #{error.sass_line}: #{error.message})"
336
+ STDOUT.flush
337
+ end
338
+
339
+ if @options[:update]
340
+ Sass::Plugin.update_stylesheets(files)
341
+ exit 1 if had_error
342
+ return
343
+ end
344
+
345
+ puts ">>> Sass is watching for changes. Press Ctrl-C to stop."
346
+
347
+ Sass::Plugin.on_template_modified do |template|
348
+ puts ">>> Change detected to: #{template}"
349
+ STDOUT.flush
350
+ end
351
+ Sass::Plugin.on_template_created do |template|
352
+ puts ">>> New template detected: #{template}"
353
+ STDOUT.flush
354
+ end
355
+ Sass::Plugin.on_template_deleted do |template|
356
+ puts ">>> Deleted template detected: #{template}"
357
+ STDOUT.flush
358
+ end
359
+
360
+ Sass::Plugin.watch(files)
361
+ end
362
+ # @comment
363
+ # rubocop:enable MethodLength
364
+
365
+ def run
366
+ input = @options[:input]
367
+ output = @options[:output]
368
+
369
+ if input == $stdin
370
+ # See issue 1745
371
+ (@options[:for_engine][:load_paths] ||= []) << ::Sass::Importers::DeprecatedPath.new(".")
372
+ end
373
+
374
+ @options[:for_engine][:syntax] ||= :scss if input.is_a?(File) && input.path =~ /\.scss$/
375
+ @options[:for_engine][:syntax] ||= @default_syntax
376
+ engine =
377
+ if input.is_a?(File) && !@options[:check_syntax]
378
+ Sass::Engine.for_file(input.path, @options[:for_engine])
379
+ else
380
+ # We don't need to do any special handling of @options[:check_syntax] here,
381
+ # because the Sass syntax checking happens alongside evaluation
382
+ # and evaluation doesn't actually evaluate any code anyway.
383
+ Sass::Engine.new(input.read, @options[:for_engine])
384
+ end
385
+
386
+ input.close if input.is_a?(File)
387
+
388
+ if @options[:sourcemap] != :none && @options[:sourcemap_filename]
389
+ relative_sourcemap_path = Sass::Util.relative_path_from(
390
+ @options[:sourcemap_filename], Sass::Util.pathname(@options[:output_filename]).dirname)
391
+ rendered, mapping = engine.render_with_sourcemap(relative_sourcemap_path.to_s)
392
+ write_output(rendered, output)
393
+ write_output(
394
+ mapping.to_json(
395
+ :type => @options[:sourcemap],
396
+ :css_path => @options[:output_filename],
397
+ :sourcemap_path => @options[:sourcemap_filename]) + "\n",
398
+ @options[:sourcemap_filename])
399
+ else
400
+ write_output(engine.render, output)
401
+ end
402
+ rescue Sass::SyntaxError => e
403
+ write_output(Sass::SyntaxError.exception_to_css(e), output) if output.is_a?(String)
404
+ raise e
405
+ ensure
406
+ output.close if output.is_a? File
407
+ end
408
+
409
+ def colon_path?(path)
410
+ !split_colon_path(path)[1].nil?
411
+ end
412
+
413
+ def split_colon_path(path)
414
+ one, two = path.split(':', 2)
415
+ if one && two && Sass::Util.windows? &&
416
+ one =~ /\A[A-Za-z]\Z/ && two =~ %r{\A[/\\]}
417
+ # If we're on Windows and we were passed a drive letter path,
418
+ # don't split on that colon.
419
+ one2, two = two.split(':', 2)
420
+ one = one + ':' + one2
421
+ end
422
+ return one, two
423
+ end
424
+
425
+ # Whether path is likely to be meant as the destination
426
+ # in a source:dest pair.
427
+ def probably_dest_dir?(path)
428
+ return false unless path
429
+ return false if colon_path?(path)
430
+ Sass::Util.glob(File.join(path, "*.s[ca]ss")).empty?
431
+ end
432
+
433
+ def default_sass_path
434
+ return unless ENV['SASS_PATH']
435
+ # The select here prevents errors when the environment's
436
+ # load paths specified do not exist.
437
+ ENV['SASS_PATH'].split(File::PATH_SEPARATOR).select {|d| File.directory?(d)}
438
+ end
439
+ end
440
+ end