sass 3.3.0.alpha.16 → 3.3.0.alpha.50

Sign up to get free protection for your applications and to get access to all the features.
data/REVISION CHANGED
@@ -1 +1 @@
1
- 83d6e352af4861f6c8fe852aaee38ca0097b1d9e
1
+ c962fa1b7d90fdb2e9df72ae2527a48f1f770276
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.3.0.alpha.16
1
+ 3.3.0.alpha.50
data/VERSION_DATE CHANGED
@@ -1 +1 @@
1
- 10 November 2012 01:58:43 GMT
1
+ 29 November 2012 19:00:24 GMT
data/lib/sass/engine.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'set'
2
2
  require 'digest/sha1'
3
3
  require 'sass/cache_stores'
4
+ require 'sass/source/position'
5
+ require 'sass/source/range'
6
+ require 'sass/source/map'
4
7
  require 'sass/tree/node'
5
8
  require 'sass/tree/root_node'
6
9
  require 'sass/tree/rule_node'
@@ -259,9 +262,23 @@ module Sass
259
262
  # cannot be converted to UTF-8
260
263
  # @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
261
264
  def render
262
- return _render unless @options[:quiet]
263
- Sass::Util.silence_sass_warnings {_render}
265
+ return encode_and_set_charset(_to_tree.render) unless @options[:quiet]
266
+ Sass::Util.silence_sass_warnings {encode_and_set_charset(_to_tree.render)}
264
267
  end
268
+
269
+ # Render the template to CSS and return the source map.
270
+ #
271
+ # @param sourcemap_uri [String] The sourcemap URI to use in the @sourceMappingURL comment
272
+ # @return [(String, Sass::Source::Map)] The rendered CSS and the associated source map
273
+ # @raise [Sass::SyntaxError] if there's an error in the document
274
+ # @raise [Encoding::UndefinedConversionError] if the source encoding
275
+ # cannot be converted to UTF-8
276
+ # @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
277
+ def render_with_sourcemap(sourcemap_uri)
278
+ return _render_with_sourcemap(sourcemap_uri) unless @options[:quiet]
279
+ Sass::Util.silence_sass_warnings {_render_with_sourcemap(sourcemap_uri)}
280
+ end
281
+
265
282
  alias_method :to_css, :render
266
283
 
267
284
  # Parses the document into its parse tree. Memoized.
@@ -311,8 +328,19 @@ module Sass
311
328
 
312
329
  private
313
330
 
314
- def _render
315
- rendered = _to_tree.render
331
+ def _render_with_sourcemap(sourcemap_uri)
332
+ rendered, sourcemap = _to_tree.render_with_sourcemap
333
+ compressed = @options[:style] == :compressed
334
+ rendered << "\n" if rendered[-1] != ?\n
335
+ rendered << "\n" unless compressed
336
+ rendered << "/*@ sourceMappingURL="
337
+ rendered << URI.encode(sourcemap_uri)
338
+ rendered << " */"
339
+ rendered = encode_and_set_charset(rendered)
340
+ return rendered, sourcemap
341
+ end
342
+
343
+ def encode_and_set_charset(rendered)
316
344
  return rendered if ruby1_8?
317
345
  begin
318
346
  # Try to convert the result to the original encoding,
@@ -424,7 +452,7 @@ END
424
452
  raise SyntaxError.new(message, :line => index)
425
453
  end
426
454
 
427
- lines << Line.new(line.strip, line_tabs, index, tab_str.size, @options[:filename], [])
455
+ lines << Line.new(line.strip, line_tabs, index, line_tab_str.size, @options[:filename], [])
428
456
  end
429
457
  lines
430
458
  end
@@ -468,6 +496,7 @@ MSG
468
496
 
469
497
  def build_tree(parent, line, root = false)
470
498
  @line = line.index
499
+ @offset = line.offset
471
500
  node_or_nodes = parse_line(parent, line, root)
472
501
 
473
502
  Array(node_or_nodes).each do |node|
@@ -553,10 +582,23 @@ WARNING
553
582
  # if we're using the new property syntax
554
583
  Tree::RuleNode.new(parse_interp(line.text))
555
584
  else
585
+ name_start_offset = line.offset + 1 # +1 for the leading ':'
556
586
  name, value = line.text.scan(PROPERTY_OLD)[0]
557
587
  raise SyntaxError.new("Invalid property: \"#{line.text}\".",
558
588
  :line => @line) if name.nil? || value.nil?
559
- parse_property(name, parse_interp(name), value, :old, line)
589
+
590
+ value_start_offset = name_end_offset = name_start_offset + name.length
591
+ if !value.empty?
592
+ # +1 and -1 both compensate for the leading ':', which is part of line.text
593
+ value_start_offset = name_start_offset + line.text.index(value, name.length + 1) - 1
594
+ end
595
+
596
+ property = parse_property(name, parse_interp(name), value, :old, line, value_start_offset)
597
+ property.name_source_range = Sass::Source::Range.new(
598
+ Sass::Source::Position.new(@line, to_parser_offset(name_start_offset)),
599
+ Sass::Source::Position.new(@line, to_parser_offset(name_end_offset)),
600
+ @options[:filename])
601
+ property
560
602
  end
561
603
  when ?$
562
604
  parse_variable(line)
@@ -582,32 +624,50 @@ WARNING
582
624
  def parse_property_or_rule(line)
583
625
  scanner = Sass::Util::MultibyteStringScanner.new(line.text)
584
626
  hack_char = scanner.scan(/[:\*\.]|\#(?!\{)/)
585
- parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
627
+ offset = line.offset
628
+ offset += hack_char.length if hack_char
629
+ parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line, to_parser_offset(offset))
586
630
 
587
631
  unless res = parser.parse_interp_ident
588
- return Tree::RuleNode.new(parse_interp(line.text))
632
+ return Tree::RuleNode.new(parse_interp(line.text, line.offset))
589
633
  end
634
+
635
+ ident_range = Sass::Source::Range.new(
636
+ Sass::Source::Position.new(@line, to_parser_offset(offset)),
637
+ Sass::Source::Position.new(@line, parser.offset),
638
+ @options[:filename])
639
+ offset = parser.offset - 1
590
640
  res.unshift(hack_char) if hack_char
591
641
  if comment = scanner.scan(Sass::SCSS::RX::COMMENT)
592
642
  res << comment
643
+ offset += comment.length
593
644
  end
594
645
 
595
646
  name = line.text[0...scanner.pos]
596
- if scanner.scan(/\s*:(?:\s|$)/)
597
- parse_property(name, res, scanner.rest, :new, line)
647
+ if scanned = scanner.scan(/\s*:(?:\s+|$)/)
648
+ offset += scanned.length
649
+ property = parse_property(name, res, scanner.rest, :new, line, offset)
650
+ property.name_source_range = ident_range
651
+ property
598
652
  else
599
653
  res.pop if comment
600
654
  Tree::RuleNode.new(res + parse_interp(scanner.rest))
601
655
  end
602
656
  end
603
657
 
604
- def parse_property(name, parsed_name, value, prop, line)
658
+ def parse_property(name, parsed_name, value, prop, line, start_offset)
605
659
  if value.strip.empty?
606
660
  expr = Sass::Script::String.new("")
661
+ end_offset = start_offset
607
662
  else
608
- expr = parse_script(value, :offset => line.offset + line.text.index(value))
663
+ expr = parse_script(value, :offset => to_parser_offset(start_offset))
664
+ end_offset = expr.source_range.end_pos.offset - 1
609
665
  end
610
666
  node = Tree::PropNode.new(parse_interp(name), expr, prop)
667
+ node.value_source_range = Sass::Source::Range.new(
668
+ Sass::Source::Position.new(line.index, to_parser_offset(start_offset)),
669
+ Sass::Source::Position.new(line.index, to_parser_offset(end_offset)),
670
+ @options[:filename])
611
671
  if value.strip.empty? && line.children.empty?
612
672
  raise SyntaxError.new(
613
673
  "Invalid property: \"#{node.declaration}\" (no value)." +
@@ -624,7 +684,12 @@ WARNING
624
684
  raise SyntaxError.new("Invalid variable: \"#{line.text}\".",
625
685
  :line => @line) unless name && value
626
686
 
627
- expr = parse_script(value, :offset => line.offset + line.text.index(value))
687
+ # This workaround is needed for the case when the variable value is part of the identifier,
688
+ # otherwise we end up with the offset equal to the value index inside the name:
689
+ # $red_color: red;
690
+ var_lhs_length = 1 + name.length # 1 stands for '$'
691
+ index = line.text.index(value, line.offset + var_lhs_length) || 0
692
+ expr = parse_script(value, :offset => to_parser_offset(line.offset + index))
628
693
 
629
694
  Tree::VariableNode.new(name, expr, default)
630
695
  end
@@ -636,7 +701,8 @@ WARNING
636
701
  if silent
637
702
  value = [line.text]
638
703
  else
639
- value = self.class.parse_interp(line.text, line.index, line.offset, :filename => @filename)
704
+ value = self.class.parse_interp(
705
+ line.text, line.index, to_parser_offset(line.offset), :filename => @filename)
640
706
  value[0].slice!(2) if loud # get rid of the "!"
641
707
  end
642
708
  value = with_extracted_values(value) do |str|
@@ -711,7 +777,7 @@ WARNING
711
777
  :line => @line + 1) unless line.children.empty?
712
778
  Tree::CharsetNode.new(name)
713
779
  when 'media'
714
- parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
780
+ parser = Sass::SCSS::Parser.new(value, @options[:filename], @line, to_parser_offset(@offset))
715
781
  Tree::MediaNode.new(parser.parse_media_query_list.to_a)
716
782
  else
717
783
  Tree::DirectiveNode.new(
@@ -802,29 +868,61 @@ WARNING
802
868
  def parse_import_arg(scanner, offset)
803
869
  return if scanner.eos?
804
870
 
805
- if scanner.match?(/url\(/i)
806
- script_parser = Sass::Script::Parser.new(scanner, @line, offset, @options)
871
+ if match_length = scanner.match?(/url\(/i)
872
+ script_parser = Sass::Script::Parser.new(scanner, @line, to_parser_offset(offset), @options)
807
873
  str = script_parser.parse_string
808
- media_parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
809
- media = media_parser.parse_media_query_list
810
- return Tree::CssImportNode.new(str, media.to_a)
874
+
875
+ media_parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line, str.source_range.end_pos.offset)
876
+ if media = media_parser.parse_media_query_list
877
+ end_pos = Sass::Source::Position.new(@line, media_parser.offset + 1)
878
+ node = Tree::CssImportNode.new(str, media.to_a)
879
+ else
880
+ end_pos = str.source_range.end_pos
881
+ node = Tree::CssImportNode.new(str)
882
+ end
883
+
884
+ node.source_range = Sass::Source::Range.new(str.source_range.start_pos, end_pos, @options[:filename])
885
+ return node
811
886
  end
812
887
 
813
888
  unless str = scanner.scan(Sass::SCSS::RX::STRING)
814
- return Tree::ImportNode.new(scanner.scan(/[^,;]+/))
889
+ scanned = scanner.scan(/[^,;]+/)
890
+ node = Tree::ImportNode.new(scanned)
891
+ start_parser_offset = to_parser_offset(offset)
892
+ node.source_range = Sass::Source::Range.new(
893
+ Sass::Source::Position.new(@line, start_parser_offset),
894
+ Sass::Source::Position.new(@line, start_parser_offset + scanned.length),
895
+ @options[:filename])
896
+ return node
815
897
  end
816
898
 
899
+ start_offset = offset
900
+ offset += str.length
817
901
  val = scanner[1] || scanner[2]
818
- scanner.scan(/\s*/)
902
+ scanned = scanner.scan(/\s*/)
819
903
  if !scanner.match?(/[,;]|$/)
820
- media_parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
904
+ offset += scanned.length if scanned
905
+ media_parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line, offset)
821
906
  media = media_parser.parse_media_query_list
822
- Tree::CssImportNode.new(str || uri, media.to_a)
907
+ node = Tree::CssImportNode.new(str || uri, media.to_a)
908
+ node.source_range = Sass::Source::Range.new(
909
+ Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
910
+ Sass::Source::Position.new(@line, media_parser.offset),
911
+ @options[:filename])
823
912
  elsif val =~ /^(https?:)?\/\//
824
- Tree::CssImportNode.new("url(#{val})")
913
+ node = Tree::CssImportNode.new("url(#{val})")
914
+ node.source_range = Sass::Source::Range.new(
915
+ Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
916
+ Sass::Source::Position.new(@line, to_parser_offset(offset)),
917
+ @options[:filename])
825
918
  else
826
- Tree::ImportNode.new(val)
919
+ node = Tree::ImportNode.new(val)
920
+ node.source_range = Sass::Source::Range.new(
921
+ Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
922
+ Sass::Source::Position.new(@line, to_parser_offset(offset)),
923
+ @options[:filename])
827
924
  end
925
+ node
828
926
  end
829
927
 
830
928
  MIXIN_DEF_RE = /^(?:=|@mixin)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
@@ -833,7 +931,7 @@ WARNING
833
931
  raise SyntaxError.new("Invalid mixin \"#{line.text[1..-1]}\".") if name.nil?
834
932
 
835
933
  offset = line.offset + line.text.size - arg_string.size
836
- args, splat = Script::Parser.new(arg_string.strip, @line, offset, @options).
934
+ args, splat = Script::Parser.new(arg_string.strip, @line, to_parser_offset(offset), @options).
837
935
  parse_mixin_definition_arglist
838
936
  Tree::MixinDefNode.new(name, args, splat)
839
937
  end
@@ -853,7 +951,7 @@ WARNING
853
951
  raise SyntaxError.new("Invalid mixin include \"#{line.text}\".") if name.nil?
854
952
 
855
953
  offset = line.offset + line.text.size - arg_string.size
856
- args, keywords, splat = Script::Parser.new(arg_string.strip, @line, offset, @options).
954
+ args, keywords, splat = Script::Parser.new(arg_string.strip, @line, to_parser_offset(offset), @options).
857
955
  parse_mixin_include_arglist
858
956
  Tree::MixinNode.new(name, args, keywords, splat)
859
957
  end
@@ -864,14 +962,14 @@ WARNING
864
962
  raise SyntaxError.new("Invalid function definition \"#{line.text}\".") if name.nil?
865
963
 
866
964
  offset = line.offset + line.text.size - arg_string.size
867
- args, splat = Script::Parser.new(arg_string.strip, @line, offset, @options).
965
+ args, splat = Script::Parser.new(arg_string.strip, @line, to_parser_offset(offset), @options).
868
966
  parse_function_definition_arglist
869
967
  Tree::FunctionNode.new(name, args, splat)
870
968
  end
871
969
 
872
970
  def parse_script(script, options = {})
873
971
  line = options[:line] || @line
874
- offset = options[:offset] || 0
972
+ offset = options[:offset] || @offset + 1
875
973
  Script.parse(script, line, offset, @options)
876
974
  end
877
975
 
@@ -899,6 +997,11 @@ WARNING
899
997
  self.class.parse_interp(text, @line, offset, :filename => @filename)
900
998
  end
901
999
 
1000
+ # Parser tracks 1-based line and offset, so our offset should be converted.
1001
+ def to_parser_offset(offset)
1002
+ offset + 1
1003
+ end
1004
+
902
1005
  # It's important that this have strings (at least)
903
1006
  # at the beginning, the end, and between each Script::Node.
904
1007
  #
@@ -912,8 +1015,9 @@ WARNING
912
1015
  res << "\\" * (escapes - 1) << '#{'
913
1016
  else
914
1017
  res << "\\" * [0, escapes - 1].max
1018
+ # Add 1 to emulate to_parser_offset.
915
1019
  res << Script::Parser.new(
916
- scan, line, offset + scan.pos - scan.matched_size, options).
1020
+ scan, line, offset + scan.pos - scan.matched_size + 1, options).
917
1021
  parse_interpolated
918
1022
  end
919
1023
  end
data/lib/sass/exec.rb CHANGED
@@ -95,6 +95,7 @@ module Sass
95
95
 
96
96
  # Processes the options set by the command-line arguments.
97
97
  # In particular, sets `@options[:input]` and `@options[:output]`
98
+ # (and `@options[:sourcemap]` if one has been specified)
98
99
  # to appropriate IO streams.
99
100
  #
100
101
  # This is meant to be overridden by subclasses
@@ -108,7 +109,13 @@ module Sass
108
109
  @options[:filename] = filename
109
110
  open_file(filename) || $stdin
110
111
  end
111
- output ||= open_file(args.shift, 'w') || $stdout
112
+ @options[:output_filename] = args.shift
113
+ output ||= open_file(@options[:output_filename], 'w') || $stdout
114
+
115
+ if @options[:sourcemap] && @options[:output_filename]
116
+ @options[:sourcemap_filename] = Util::sourcemap_name(@options[:output_filename])
117
+ @options[:sourcemap] = open_file(@options[:sourcemap_filename], 'w')
118
+ end
112
119
 
113
120
  @options[:input], @options[:output] = input, output
114
121
  end
@@ -281,6 +288,9 @@ END
281
288
  opts.on('-C', '--no-cache', "Don't cache to sassc files.") do
282
289
  @options[:for_engine][:cache] = false
283
290
  end
291
+ opts.on('--sourcemap', 'Create sourcemap files next to the generated CSS files.') do
292
+ @options[:sourcemap] = true
293
+ end
284
294
 
285
295
  unless ::Sass::Util.ruby1_8?
286
296
  opts.on('-E encoding', 'Specify the default encoding for Sass files.') do |encoding|
@@ -311,6 +321,7 @@ END
311
321
  begin
312
322
  input = @options[:input]
313
323
  output = @options[:output]
324
+ sourcemap = @options[:sourcemap]
314
325
 
315
326
  @options[:for_engine][:syntax] ||= :scss if input.is_a?(File) && input.path =~ /\.scss$/
316
327
  @options[:for_engine][:syntax] ||= @default_syntax
@@ -326,11 +337,21 @@ END
326
337
 
327
338
  input.close() if input.is_a?(File)
328
339
 
329
- output.write(engine.render)
330
- output.close() if output.is_a? File
340
+ if sourcemap.is_a? File
341
+ relative_sourcemap_path = Pathname.new(@options[:sourcemap_filename]).
342
+ relative_path_from(Pathname.new(@options[:output_filename]).dirname)
343
+ rendered, mapping = engine.render_with_sourcemap(relative_sourcemap_path.to_s)
344
+ output.write(rendered)
345
+ sourcemap.puts(mapping.to_json(@options[:output_filename]))
346
+ else
347
+ output.write(engine.render)
348
+ end
331
349
  rescue ::Sass::SyntaxError => e
332
350
  raise e if @options[:trace]
333
351
  raise e.sass_backtrace_str("standard input")
352
+ ensure
353
+ output.close if output.is_a? File
354
+ sourcemap.close if sourcemap.is_a? File
334
355
  end
335
356
  end
336
357
 
@@ -363,6 +384,7 @@ END
363
384
  ::Sass::Plugin.options.merge! @options[:for_engine]
364
385
  ::Sass::Plugin.options[:unix_newlines] = @options[:unix_newlines]
365
386
  ::Sass::Plugin.options[:poll] = @options[:poll]
387
+ ::Sass::Plugin.options[:sourcemap] = @options[:sourcemap]
366
388
 
367
389
  if @options[:force]
368
390
  raise "The --force flag may only be used with --update." unless @options[:update]
@@ -391,15 +413,22 @@ MSG
391
413
 
392
414
  dirs, files = @args.map {|name| split_colon_path(name)}.
393
415
  partition {|i, _| File.directory? i}
394
- files.map! {|from, to| [from, to || from.gsub(/\.[^.]*?$/, '.css')]}
416
+ files.map! do |from, to|
417
+ to ||= from.gsub(/\.[^.]*?$/, '.css')
418
+ sourcemap = Util::sourcemap_name(to) if @options[:sourcemap]
419
+ [from, to, sourcemap]
420
+ end
395
421
  dirs.map! {|from, to| [from, to || from]}
396
422
  ::Sass::Plugin.options[:template_location] = dirs
397
423
 
398
- ::Sass::Plugin.on_updated_stylesheet do |_, css|
399
- if File.exists? css
400
- puts_action :overwrite, :yellow, css
401
- else
402
- puts_action :create, :green, css
424
+ ::Sass::Plugin.on_updated_stylesheet do |_, css, sourcemap|
425
+ [css, sourcemap].each do |file|
426
+ next unless file
427
+ if File.exists? file
428
+ puts_action :overwrite, :yellow, file
429
+ else
430
+ puts_action :create, :green, file
431
+ end
403
432
  end
404
433
  end
405
434
 
@@ -65,6 +65,8 @@ module Sass::Plugin
65
65
  # The location of the Sass/SCSS file being updated.
66
66
  # @yieldparam css [String]
67
67
  # The location of the CSS file being generated.
68
+ # @yieldparam sourcemap [String]
69
+ # The location of the sourcemap being generated, if any.
68
70
  define_callback :updated_stylesheet
69
71
 
70
72
  # Register a callback to be run before a single stylesheet is updated.
@@ -81,6 +83,8 @@ module Sass::Plugin
81
83
  # The location of the Sass/SCSS file being updated.
82
84
  # @yieldparam css [String]
83
85
  # The location of the CSS file being generated.
86
+ # @yieldparam sourcemap [String]
87
+ # The location of the sourcemap file being generated, if any.
84
88
  define_callback :updating_stylesheet
85
89
 
86
90
  def on_updating_stylesheet_with_deprecation_warning(&block)
@@ -192,17 +196,19 @@ module Sass::Plugin
192
196
  # Get the relative path to the file
193
197
  name = file.sub(template_location.to_s.sub(/\/*$/, '/'), "")
194
198
  css = css_filename(name, css_location)
195
- individual_files << [file, css]
199
+ sourcemap = Util::sourcemap_name(css) if engine_options[:sourcemap]
200
+ individual_files << [file, css, sourcemap]
196
201
  end
197
202
  end
198
203
 
199
204
  run_updating_stylesheets individual_files
200
205
 
201
- individual_files.each do |file, css|
206
+ individual_files.each do |file, css, sourcemap|
207
+ # TODO: Does staleness_checker need to check the sourcemap file as well?
202
208
  if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
203
- update_stylesheet(file, css)
209
+ update_stylesheet(file, css, sourcemap)
204
210
  else
205
- run_not_updating_stylesheet(file, css)
211
+ run_not_updating_stylesheet(file, css, sourcemap)
206
212
  end
207
213
  end
208
214
  end
@@ -328,7 +334,7 @@ module Sass::Plugin
328
334
 
329
335
  private
330
336
 
331
- def update_stylesheet(filename, css)
337
+ def update_stylesheet(filename, css, sourcemap)
332
338
  dir = File.dirname(css)
333
339
  unless File.exists?(dir)
334
340
  run_creating_directory dir
@@ -338,23 +344,30 @@ module Sass::Plugin
338
344
  begin
339
345
  File.read(filename) unless File.readable?(filename) # triggers an error for handling
340
346
  engine_opts = engine_options(:css_filename => css, :filename => filename)
341
- result = Sass::Engine.for_file(filename, engine_opts).render
347
+ mapping = nil
348
+ engine = Sass::Engine.for_file(filename, engine_opts)
349
+ if sourcemap
350
+ rendered, mapping = engine.render_with_sourcemap(File.basename(sourcemap))
351
+ else
352
+ rendered = engine.render
353
+ end
342
354
  rescue Exception => e
343
355
  compilation_error_occured = true
344
- run_compilation_error e, filename, css
345
- result = Sass::SyntaxError.exception_to_css(e, options)
356
+ run_compilation_error e, filename, css, sourcemap
357
+ rendered = Sass::SyntaxError.exception_to_css(e, options)
346
358
  else
347
- run_updating_stylesheet filename, css
359
+ run_updating_stylesheet filename, css, sourcemap
348
360
  end
349
361
 
350
- write_file(css, result)
351
- run_updated_stylesheet(filename, css) unless compilation_error_occured
362
+ write_file(css, rendered)
363
+ write_file(sourcemap, mapping.to_json(css)) if mapping
364
+ run_updated_stylesheet(filename, css, sourcemap) unless compilation_error_occured
352
365
  end
353
366
 
354
- def write_file(css, content)
367
+ def write_file(fileName, content)
355
368
  flag = 'w'
356
369
  flag = 'wb' if Sass::Util.windows? && options[:unix_newlines]
357
- File.open(css, flag) do |file|
370
+ File.open(fileName, flag) do |file|
358
371
  file.set_encoding(content.encoding) unless Sass::Util.ruby1_8?
359
372
  file.print(content)
360
373
  end