sass 3.3.0.alpha.16 → 3.3.0.alpha.50
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.
- 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
|