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 +1 -1
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/lib/sass/engine.rb +135 -31
- data/lib/sass/exec.rb +38 -9
- data/lib/sass/plugin/compiler.rb +26 -13
- data/lib/sass/script/lexer.rb +40 -18
- data/lib/sass/script/node.rb +10 -0
- data/lib/sass/script/parser.rb +50 -18
- data/lib/sass/scss/parser.rb +107 -68
- data/lib/sass/scss/static_parser.rb +1 -1
- data/lib/sass/source/map.rb +159 -0
- data/lib/sass/source/position.rb +26 -0
- data/lib/sass/source/range.rb +34 -0
- data/lib/sass/tree/css_import_node.rb +1 -1
- data/lib/sass/tree/node.rb +19 -3
- data/lib/sass/tree/prop_node.rb +11 -1
- data/lib/sass/tree/root_node.rb +19 -3
- data/lib/sass/tree/visitors/perform.rb +9 -1
- data/lib/sass/tree/visitors/to_css.rb +191 -64
- data/lib/sass/util.rb +94 -0
- data/test/sass/source_map_test.rb +837 -0
- data/test/sass/util_test.rb +41 -0
- metadata +9 -4
data/REVISION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
c962fa1b7d90fdb2e9df72ae2527a48f1f770276
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.3.0.alpha.
|
1
|
+
3.3.0.alpha.50
|
data/VERSION_DATE
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
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
|
263
|
-
Sass::Util.silence_sass_warnings {
|
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
|
315
|
-
rendered = _to_tree.
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =>
|
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
|
-
|
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(
|
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
|
-
|
809
|
-
|
810
|
-
|
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
|
-
|
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
|
-
|
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] ||
|
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
|
-
|
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
|
-
|
330
|
-
|
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!
|
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
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
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
|
|
data/lib/sass/plugin/compiler.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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,
|
351
|
-
|
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(
|
367
|
+
def write_file(fileName, content)
|
355
368
|
flag = 'w'
|
356
369
|
flag = 'wb' if Sass::Util.windows? && options[:unix_newlines]
|
357
|
-
File.open(
|
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
|