sass 3.3.0.alpha.61 → 3.3.0.alpha.64
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/css.rb +2 -2
- data/lib/sass/engine.rb +26 -16
- data/lib/sass/exec.rb +3 -1
- data/lib/sass/importers/base.rb +12 -0
- data/lib/sass/script/lexer.rb +1 -1
- data/lib/sass/script/parser.rb +1 -1
- data/lib/sass/scss/parser.rb +7 -3
- data/lib/sass/source/map.rb +56 -14
- data/lib/sass/source/range.rb +9 -1
- data/lib/sass/tree/rule_node.rb +1 -1
- data/lib/sass/tree/visitors/perform.rb +8 -4
- data/lib/sass/util.rb +2 -2
- data/test/sass/importer_test.rb +142 -17
- data/test/sass/scss/css_test.rb +1 -1
- data/test/sass/scss/scss_test.rb +1 -1
- data/test/sass/source_map_test.rb +17 -4
- data/test/sass/util_test.rb +1 -1
- metadata +4 -4
data/REVISION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
62e36b0efe872f1be55de2a82b01d88f2b08d9b1
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.3.0.alpha.
|
|
1
|
+
3.3.0.alpha.64
|
data/VERSION_DATE
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
27 December 2012 22:38:55 GMT
|
data/lib/sass/css.rb
CHANGED
|
@@ -76,7 +76,7 @@ module Sass
|
|
|
76
76
|
#
|
|
77
77
|
# @return [Tree::Node] The root node of the parsed tree
|
|
78
78
|
def build_tree
|
|
79
|
-
root = Sass::SCSS::CssParser.new(@template, @options[:filename]).parse
|
|
79
|
+
root = Sass::SCSS::CssParser.new(@template, @options[:filename], nil).parse
|
|
80
80
|
parse_selectors root
|
|
81
81
|
expand_commas root
|
|
82
82
|
nest_seqs root
|
|
@@ -96,7 +96,7 @@ module Sass
|
|
|
96
96
|
root.children.each do |child|
|
|
97
97
|
next parse_selectors(child) if child.is_a?(Tree::DirectiveNode)
|
|
98
98
|
next unless child.is_a?(Tree::RuleNode)
|
|
99
|
-
parser = Sass::SCSS::CssParser.new(child.rule.first, child.filename, child.line)
|
|
99
|
+
parser = Sass::SCSS::CssParser.new(child.rule.first, child.filename, nil, child.line)
|
|
100
100
|
child.parsed_rules = parser.parse_selector
|
|
101
101
|
end
|
|
102
102
|
end
|
data/lib/sass/engine.rb
CHANGED
|
@@ -269,9 +269,10 @@ module Sass
|
|
|
269
269
|
# Render the template to CSS and return the source map.
|
|
270
270
|
#
|
|
271
271
|
# @param sourcemap_uri [String] The sourcemap URI to use in the
|
|
272
|
-
#
|
|
273
|
-
# the CSS file.
|
|
274
|
-
# @return [(String, Sass::Source::Map)] The rendered CSS and the associated
|
|
272
|
+
# `@sourceMappingURL` comment. If this is relative, it should be relative
|
|
273
|
+
# to the location of the CSS file.
|
|
274
|
+
# @return [(String, Sass::Source::Map)] The rendered CSS and the associated
|
|
275
|
+
# source map
|
|
275
276
|
# @raise [Sass::SyntaxError] if there's an error in the document
|
|
276
277
|
# @raise [Encoding::UndefinedConversionError] if the source encoding
|
|
277
278
|
# cannot be converted to UTF-8
|
|
@@ -369,7 +370,7 @@ module Sass
|
|
|
369
370
|
check_encoding!
|
|
370
371
|
|
|
371
372
|
if @options[:syntax] == :scss
|
|
372
|
-
root = Sass::SCSS::Parser.new(@template, @options[:filename]).parse
|
|
373
|
+
root = Sass::SCSS::Parser.new(@template, @options[:filename], @options[:importer]).parse
|
|
373
374
|
else
|
|
374
375
|
root = Tree::RootNode.new(@template)
|
|
375
376
|
append_children(root, tree(tabulate(@template)).first, true)
|
|
@@ -599,7 +600,7 @@ WARNING
|
|
|
599
600
|
property.name_source_range = Sass::Source::Range.new(
|
|
600
601
|
Sass::Source::Position.new(@line, to_parser_offset(name_start_offset)),
|
|
601
602
|
Sass::Source::Position.new(@line, to_parser_offset(name_end_offset)),
|
|
602
|
-
@options[:filename])
|
|
603
|
+
@options[:filename], @options[:importer])
|
|
603
604
|
property
|
|
604
605
|
end
|
|
605
606
|
when ?$
|
|
@@ -628,7 +629,9 @@ WARNING
|
|
|
628
629
|
hack_char = scanner.scan(/[:\*\.]|\#(?!\{)/)
|
|
629
630
|
offset = line.offset
|
|
630
631
|
offset += hack_char.length if hack_char
|
|
631
|
-
parser = Sass::SCSS::Parser.new(scanner,
|
|
632
|
+
parser = Sass::SCSS::Parser.new(scanner,
|
|
633
|
+
@options[:filename], @options[:importer],
|
|
634
|
+
@line, to_parser_offset(offset))
|
|
632
635
|
|
|
633
636
|
unless res = parser.parse_interp_ident
|
|
634
637
|
return Tree::RuleNode.new(parse_interp(line.text, line.offset))
|
|
@@ -637,7 +640,7 @@ WARNING
|
|
|
637
640
|
ident_range = Sass::Source::Range.new(
|
|
638
641
|
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
|
639
642
|
Sass::Source::Position.new(@line, parser.offset),
|
|
640
|
-
@options[:filename])
|
|
643
|
+
@options[:filename], @options[:importer])
|
|
641
644
|
offset = parser.offset - 1
|
|
642
645
|
res.unshift(hack_char) if hack_char
|
|
643
646
|
if comment = scanner.scan(Sass::SCSS::RX::COMMENT)
|
|
@@ -669,7 +672,7 @@ WARNING
|
|
|
669
672
|
node.value_source_range = Sass::Source::Range.new(
|
|
670
673
|
Sass::Source::Position.new(line.index, to_parser_offset(start_offset)),
|
|
671
674
|
Sass::Source::Position.new(line.index, to_parser_offset(end_offset)),
|
|
672
|
-
@options[:filename])
|
|
675
|
+
@options[:filename], @options[:importer])
|
|
673
676
|
if value.strip.empty? && line.children.empty?
|
|
674
677
|
raise SyntaxError.new(
|
|
675
678
|
"Invalid property: \"#{node.declaration}\" (no value)." +
|
|
@@ -779,7 +782,9 @@ WARNING
|
|
|
779
782
|
:line => @line + 1) unless line.children.empty?
|
|
780
783
|
Tree::CharsetNode.new(name)
|
|
781
784
|
when 'media'
|
|
782
|
-
parser = Sass::SCSS::Parser.new(value,
|
|
785
|
+
parser = Sass::SCSS::Parser.new(value,
|
|
786
|
+
@options[:filename], @options[:importer],
|
|
787
|
+
@line, to_parser_offset(@offset))
|
|
783
788
|
Tree::MediaNode.new(parser.parse_media_query_list.to_a)
|
|
784
789
|
else
|
|
785
790
|
Tree::DirectiveNode.new(
|
|
@@ -874,7 +879,9 @@ WARNING
|
|
|
874
879
|
script_parser = Sass::Script::Parser.new(scanner, @line, to_parser_offset(offset), @options)
|
|
875
880
|
str = script_parser.parse_string
|
|
876
881
|
|
|
877
|
-
media_parser = Sass::SCSS::Parser.new(scanner,
|
|
882
|
+
media_parser = Sass::SCSS::Parser.new(scanner,
|
|
883
|
+
@options[:filename], @options[:importer],
|
|
884
|
+
@line, str.source_range.end_pos.offset)
|
|
878
885
|
if media = media_parser.parse_media_query_list
|
|
879
886
|
end_pos = Sass::Source::Position.new(@line, media_parser.offset + 1)
|
|
880
887
|
node = Tree::CssImportNode.new(str, media.to_a)
|
|
@@ -883,7 +890,9 @@ WARNING
|
|
|
883
890
|
node = Tree::CssImportNode.new(str)
|
|
884
891
|
end
|
|
885
892
|
|
|
886
|
-
node.source_range = Sass::Source::Range.new(
|
|
893
|
+
node.source_range = Sass::Source::Range.new(
|
|
894
|
+
str.source_range.start_pos, end_pos,
|
|
895
|
+
@options[:filename], @options[:importer])
|
|
887
896
|
return node
|
|
888
897
|
end
|
|
889
898
|
|
|
@@ -894,7 +903,7 @@ WARNING
|
|
|
894
903
|
node.source_range = Sass::Source::Range.new(
|
|
895
904
|
Sass::Source::Position.new(@line, start_parser_offset),
|
|
896
905
|
Sass::Source::Position.new(@line, start_parser_offset + scanned.length),
|
|
897
|
-
@options[:filename])
|
|
906
|
+
@options[:filename], @options[:importer])
|
|
898
907
|
return node
|
|
899
908
|
end
|
|
900
909
|
|
|
@@ -904,25 +913,26 @@ WARNING
|
|
|
904
913
|
scanned = scanner.scan(/\s*/)
|
|
905
914
|
if !scanner.match?(/[,;]|$/)
|
|
906
915
|
offset += scanned.length if scanned
|
|
907
|
-
media_parser = Sass::SCSS::Parser.new(scanner,
|
|
916
|
+
media_parser = Sass::SCSS::Parser.new(scanner,
|
|
917
|
+
@options[:filename], @options[:importer], @line, offset)
|
|
908
918
|
media = media_parser.parse_media_query_list
|
|
909
919
|
node = Tree::CssImportNode.new(str || uri, media.to_a)
|
|
910
920
|
node.source_range = Sass::Source::Range.new(
|
|
911
921
|
Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
|
|
912
922
|
Sass::Source::Position.new(@line, media_parser.offset),
|
|
913
|
-
@options[:filename])
|
|
923
|
+
@options[:filename], @options[:importer])
|
|
914
924
|
elsif val =~ /^(https?:)?\/\//
|
|
915
925
|
node = Tree::CssImportNode.new("url(#{val})")
|
|
916
926
|
node.source_range = Sass::Source::Range.new(
|
|
917
927
|
Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
|
|
918
928
|
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
|
919
|
-
@options[:filename])
|
|
929
|
+
@options[:filename], @options[:importer])
|
|
920
930
|
else
|
|
921
931
|
node = Tree::ImportNode.new(val)
|
|
922
932
|
node.source_range = Sass::Source::Range.new(
|
|
923
933
|
Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
|
|
924
934
|
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
|
925
|
-
@options[:filename])
|
|
935
|
+
@options[:filename], @options[:importer])
|
|
926
936
|
end
|
|
927
937
|
node
|
|
928
938
|
end
|
data/lib/sass/exec.rb
CHANGED
|
@@ -342,7 +342,9 @@ END
|
|
|
342
342
|
relative_path_from(Pathname.new(@options[:output_filename]).dirname)
|
|
343
343
|
rendered, mapping = engine.render_with_sourcemap(relative_sourcemap_path.to_s)
|
|
344
344
|
output.write(rendered)
|
|
345
|
-
sourcemap.puts(mapping.to_json(
|
|
345
|
+
sourcemap.puts(mapping.to_json(
|
|
346
|
+
:css_path => @options[:output_filename],
|
|
347
|
+
:sourcemap_path => @options[:sourcemap_filename]))
|
|
346
348
|
else
|
|
347
349
|
output.write(engine.render)
|
|
348
350
|
end
|
data/lib/sass/importers/base.rb
CHANGED
|
@@ -122,6 +122,18 @@ module Sass
|
|
|
122
122
|
Sass::Util.abstract(self)
|
|
123
123
|
end
|
|
124
124
|
|
|
125
|
+
# Get the publicly-visible URL for an imported file. This URL is used by
|
|
126
|
+
# source maps to link to the source stylesheet. This may return `nil` to
|
|
127
|
+
# indicate that no public URL is available; however, this will cause
|
|
128
|
+
# sourcemap generation to fail if any CSS is generated from files imported
|
|
129
|
+
# from this importer.
|
|
130
|
+
#
|
|
131
|
+
# @param uri [String] A URI known to be valid for this importer.
|
|
132
|
+
# @return [String?] The publicly-visible URL for this file.
|
|
133
|
+
def public_url(uri)
|
|
134
|
+
nil
|
|
135
|
+
end
|
|
136
|
+
|
|
125
137
|
# A string representation of the importer.
|
|
126
138
|
# Should be overridden by subclasses.
|
|
127
139
|
#
|
data/lib/sass/script/lexer.rb
CHANGED
|
@@ -361,7 +361,7 @@ MESSAGE
|
|
|
361
361
|
end
|
|
362
362
|
|
|
363
363
|
def range(start_pos, end_pos = source_position)
|
|
364
|
-
Sass::Source::Range.new(start_pos, end_pos, @options[:filename])
|
|
364
|
+
Sass::Source::Range.new(start_pos, end_pos, @options[:filename], @options[:importer])
|
|
365
365
|
end
|
|
366
366
|
|
|
367
367
|
def source_position
|
data/lib/sass/script/parser.rb
CHANGED
|
@@ -259,7 +259,7 @@ RUBY
|
|
|
259
259
|
end
|
|
260
260
|
|
|
261
261
|
def range(start_pos, end_pos=source_position)
|
|
262
|
-
Sass::Source::Range.new(start_pos, end_pos, @options[:filename])
|
|
262
|
+
Sass::Source::Range.new(start_pos, end_pos, @options[:filename], @options[:importer])
|
|
263
263
|
end
|
|
264
264
|
|
|
265
265
|
# @private
|
data/lib/sass/scss/parser.rb
CHANGED
|
@@ -12,15 +12,19 @@ module Sass
|
|
|
12
12
|
# @param str [String, StringScanner] The source document to parse.
|
|
13
13
|
# Note that `Parser` *won't* raise a nice error message if this isn't properly parsed;
|
|
14
14
|
# for that, you should use the higher-level {Sass::Engine} or {Sass::CSS}.
|
|
15
|
-
# @param filename [String] The name of the file being parsed. Used for
|
|
15
|
+
# @param filename [String] The name of the file being parsed. Used for
|
|
16
|
+
# warnings and source maps.
|
|
17
|
+
# @param importer [Sass::Importers::Base] The importer used to import the
|
|
18
|
+
# file being parsed. Used for source maps.
|
|
16
19
|
# @param line [Fixnum] The 1-based line on which the source string appeared,
|
|
17
20
|
# if it's part of another document.
|
|
18
21
|
# @param offset [Fixnum] The 1-based character (not byte) offset in the line on
|
|
19
22
|
# which the source string starts. Used for error reporting and sourcemap
|
|
20
23
|
# building.
|
|
21
|
-
def initialize(str, filename, line = 1, offset = 1)
|
|
24
|
+
def initialize(str, filename, importer, line = 1, offset = 1)
|
|
22
25
|
@template = str
|
|
23
26
|
@filename = filename
|
|
27
|
+
@importer = importer
|
|
24
28
|
@line = line
|
|
25
29
|
@offset = offset
|
|
26
30
|
@strs = []
|
|
@@ -69,7 +73,7 @@ module Sass
|
|
|
69
73
|
end
|
|
70
74
|
|
|
71
75
|
def range(start_pos, end_pos=source_position)
|
|
72
|
-
Sass::Source::Range.new(start_pos, end_pos, @filename)
|
|
76
|
+
Sass::Source::Range.new(start_pos, end_pos, @filename, @importer)
|
|
73
77
|
end
|
|
74
78
|
|
|
75
79
|
def init_scanner!
|
data/lib/sass/source/map.rb
CHANGED
|
@@ -64,16 +64,49 @@ module Sass::Source
|
|
|
64
64
|
|
|
65
65
|
# Returns the standard JSON representation of the source map.
|
|
66
66
|
#
|
|
67
|
-
#
|
|
68
|
-
#
|
|
69
|
-
#
|
|
67
|
+
# If the `:css_uri` option isn't specified, the `:css_path` and
|
|
68
|
+
# `:sourcemap_path` options must both be specified. Any options may also be
|
|
69
|
+
# specified alongside the `:css_uri` option. If `:css_uri` isn't specified,
|
|
70
|
+
# it will be inferred from `:css_path` and `:sourcemap_path` using the
|
|
71
|
+
# assumption that the local file system has the same layout as the server.
|
|
72
|
+
#
|
|
73
|
+
# If any source stylesheets use the default filesystem importer, sourcemap
|
|
74
|
+
# generation will fail unless the ``:sourcemap_path` option is specified.
|
|
75
|
+
# The layout of the local file system is assumed to be the same as the
|
|
76
|
+
# layout of the server for the purposes of linking to source stylesheets
|
|
77
|
+
# that use the filesystem importer.
|
|
78
|
+
#
|
|
79
|
+
# Regardless of which options are passed to this method, sourcemap
|
|
80
|
+
# generation will fail if the source stylesheet contains any import that
|
|
81
|
+
# uses a non-default importer that doesn't implement
|
|
82
|
+
# \{Sass::Importers::Base#public\_url\}.
|
|
83
|
+
#
|
|
84
|
+
# @option options :css_uri [String]
|
|
85
|
+
# The publicly-visible URI of the CSS output file.
|
|
86
|
+
# @option options :css_path [String]
|
|
87
|
+
# The local path of the CSS output file.
|
|
88
|
+
# @option options :sourcemap_path [String]
|
|
89
|
+
# The (eventual) local path of the sourcemap file.
|
|
70
90
|
# @return [String] The JSON string.
|
|
71
|
-
|
|
91
|
+
# @raise [ArgumentError] If neither `:css_uri` nor `:css_path` are
|
|
92
|
+
# specified.
|
|
93
|
+
# @raise [Sass::SyntaxError] If the public URL of a stylesheet cannot be
|
|
94
|
+
# determined.
|
|
95
|
+
def to_json(options)
|
|
96
|
+
css_uri, css_path, sourcemap_path = [:css_uri, :css_path, :sourcemap_path].map {|o| options[o]}
|
|
97
|
+
unless css_uri || (css_path && sourcemap_path)
|
|
98
|
+
raise ArgumentError.new("Sass::Source::Map#to_json requires either " +
|
|
99
|
+
"the :css_uri option or both the :css_path and :soucemap_path options.")
|
|
100
|
+
end
|
|
101
|
+
css_path &&= Pathname.pwd.join(Pathname.new(css_path)).cleanpath
|
|
102
|
+
sourcemap_path &&= Pathname.pwd.join(Pathname.new(sourcemap_path)).cleanpath
|
|
103
|
+
css_uri ||= css_path.relative_path_from(sourcemap_path.dirname).to_s
|
|
104
|
+
|
|
72
105
|
result = "{\n"
|
|
73
106
|
write_json_field(result, "version", "3", true)
|
|
74
107
|
|
|
75
|
-
|
|
76
|
-
|
|
108
|
+
source_uri_to_id = {}
|
|
109
|
+
id_to_source_uri = {}
|
|
77
110
|
next_source_id = 0
|
|
78
111
|
line_data = []
|
|
79
112
|
segment_data_for_line = []
|
|
@@ -85,17 +118,26 @@ module Sass::Source
|
|
|
85
118
|
previous_source_offset = 1
|
|
86
119
|
previous_source_id = 0
|
|
87
120
|
|
|
88
|
-
target_pathname = Pathname.pwd.join(Pathname.new(target_filename)).cleanpath
|
|
89
121
|
@data.each do |m|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
122
|
+
file, importer = m.input.file, m.input.importer
|
|
123
|
+
unless source_uri = importer && importer.public_url(file)
|
|
124
|
+
if importer.is_a?(Sass::Importers::Filesystem) && sourcemap_path
|
|
125
|
+
file_path = Pathname.new(importer.root).join(file)
|
|
126
|
+
source_uri = file_path.relative_path_from(sourcemap_path.dirname).to_s
|
|
127
|
+
else
|
|
128
|
+
raise Sass::SyntaxError.new(<<ERR)
|
|
129
|
+
Error generating source map: couldn't determine public URL for "#{file}".
|
|
130
|
+
ERR
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
current_source_id = source_uri_to_id[source_uri]
|
|
93
135
|
unless current_source_id
|
|
94
136
|
current_source_id = next_source_id
|
|
95
137
|
next_source_id += 1
|
|
96
138
|
|
|
97
|
-
|
|
98
|
-
|
|
139
|
+
source_uri_to_id[source_uri] = current_source_id
|
|
140
|
+
id_to_source_uri[current_source_id] = source_uri
|
|
99
141
|
end
|
|
100
142
|
|
|
101
143
|
[
|
|
@@ -138,9 +180,9 @@ module Sass::Source
|
|
|
138
180
|
write_json_field(result, "mappings", line_data.join(";"))
|
|
139
181
|
|
|
140
182
|
source_names = []
|
|
141
|
-
(0...next_source_id).each {|id| source_names.push(
|
|
183
|
+
(0...next_source_id).each {|id| source_names.push(id_to_source_uri[id].to_s)}
|
|
142
184
|
write_json_field(result, "sources", source_names)
|
|
143
|
-
write_json_field(result, "file",
|
|
185
|
+
write_json_field(result, "file", css_uri)
|
|
144
186
|
|
|
145
187
|
result << "\n}"
|
|
146
188
|
result
|
data/lib/sass/source/range.rb
CHANGED
|
@@ -16,13 +16,21 @@ module Sass::Source
|
|
|
16
16
|
# @return [String]
|
|
17
17
|
attr_accessor :file
|
|
18
18
|
|
|
19
|
+
# The importer that imported the file in which this source range appears.
|
|
20
|
+
# This is nil for target ranges.
|
|
21
|
+
#
|
|
22
|
+
# @return [Sass::Importers::Base]
|
|
23
|
+
attr_accessor :importer
|
|
24
|
+
|
|
19
25
|
# @param start_pos [Sass::Source::Position] See \{#start_pos}
|
|
20
26
|
# @param end_pos [Sass::Source::Position] See \{#end_pos}
|
|
21
27
|
# @param file [String] See \{#file}
|
|
22
|
-
|
|
28
|
+
# @param importer [Sass::Importers::Base] See \{#importer}
|
|
29
|
+
def initialize(start_pos, end_pos, file, importer=nil)
|
|
23
30
|
@start_pos = start_pos
|
|
24
31
|
@end_pos = end_pos
|
|
25
32
|
@file = file
|
|
33
|
+
@importer = importer
|
|
26
34
|
end
|
|
27
35
|
|
|
28
36
|
# @return [String] A string representation of the source range.
|
data/lib/sass/tree/rule_node.rb
CHANGED
|
@@ -124,7 +124,7 @@ module Sass::Tree
|
|
|
124
124
|
if @rule.all? {|t| t.kind_of?(String)}
|
|
125
125
|
# We don't use real filename/line info because we don't have it yet.
|
|
126
126
|
# When we get it, we'll set it on the parsed rules if possible.
|
|
127
|
-
parser = Sass::SCSS::StaticParser.new(@rule.join.strip, '', 1)
|
|
127
|
+
parser = Sass::SCSS::StaticParser.new(@rule.join.strip, '', nil, 1)
|
|
128
128
|
@parsed_rules = parser.parse_selector rescue nil
|
|
129
129
|
end
|
|
130
130
|
end
|
|
@@ -164,7 +164,8 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
|
164
164
|
# Runs SassScript interpolation in the selector,
|
|
165
165
|
# and then parses the result into a {Sass::Selector::CommaSequence}.
|
|
166
166
|
def visit_extend(node)
|
|
167
|
-
parser = Sass::SCSS::StaticParser.new(run_interp(node.selector),
|
|
167
|
+
parser = Sass::SCSS::StaticParser.new(run_interp(node.selector),
|
|
168
|
+
node.filename, node.options[:importer], node.line)
|
|
168
169
|
node.resolved_selector = parser.parse_selector
|
|
169
170
|
node
|
|
170
171
|
end
|
|
@@ -311,7 +312,8 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
|
311
312
|
def visit_rule(node)
|
|
312
313
|
rule = node.rule
|
|
313
314
|
rule = rule.map {|e| e.is_a?(String) && e != ' ' ? e.strip : e} if node.style == :compressed
|
|
314
|
-
parser = Sass::SCSS::StaticParser.new(run_interp(node.rule),
|
|
315
|
+
parser = Sass::SCSS::StaticParser.new(run_interp(node.rule),
|
|
316
|
+
node.filename, node.options[:importer], node.line)
|
|
315
317
|
node.parsed_rules ||= parser.parse_selector
|
|
316
318
|
if node.options[:trace_selectors]
|
|
317
319
|
@stack.push(:filename => node.filename, :line => node.line)
|
|
@@ -363,7 +365,8 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
|
363
365
|
end
|
|
364
366
|
|
|
365
367
|
def visit_media(node)
|
|
366
|
-
parser = Sass::SCSS::StaticParser.new(run_interp(node.query),
|
|
368
|
+
parser = Sass::SCSS::StaticParser.new(run_interp(node.query),
|
|
369
|
+
node.filename, node.options[:importer], node.line)
|
|
367
370
|
node.resolved_query ||= parser.parse_media_query_list
|
|
368
371
|
yield
|
|
369
372
|
end
|
|
@@ -377,7 +380,8 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
|
377
380
|
def visit_cssimport(node)
|
|
378
381
|
node.resolved_uri = run_interp([node.uri])
|
|
379
382
|
if node.query
|
|
380
|
-
parser = Sass::SCSS::StaticParser.new(run_interp(node.query),
|
|
383
|
+
parser = Sass::SCSS::StaticParser.new(run_interp(node.query),
|
|
384
|
+
node.filename, node.options[:importer], node.line)
|
|
381
385
|
node.resolved_query ||= parser.parse_media_query_list
|
|
382
386
|
end
|
|
383
387
|
yield
|
data/lib/sass/util.rb
CHANGED
|
@@ -803,12 +803,12 @@ MSG
|
|
|
803
803
|
# @param s [String] The string to be escaped
|
|
804
804
|
# @return [String] The escaped string
|
|
805
805
|
def json_escape_string(s)
|
|
806
|
-
return s if s !~ /["
|
|
806
|
+
return s if s !~ /["\\\b\f\n\r\t]/
|
|
807
807
|
|
|
808
808
|
result = ""
|
|
809
809
|
s.split("").each do |c|
|
|
810
810
|
case c
|
|
811
|
-
when '"', "\\"
|
|
811
|
+
when '"', "\\"
|
|
812
812
|
result << "\\" << c
|
|
813
813
|
when "\n" then result << "\\n"
|
|
814
814
|
when "\t" then result << "\\t"
|
data/test/sass/importer_test.rb
CHANGED
|
@@ -8,29 +8,37 @@ class ImporterTest < Test::Unit::TestCase
|
|
|
8
8
|
|
|
9
9
|
class FruitImporter < Sass::Importers::Base
|
|
10
10
|
def find(name, context = nil)
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"blue"
|
|
20
|
-
end
|
|
21
|
-
contents = %Q{
|
|
22
|
-
$#{fruit}-color: #{color} !default;
|
|
23
|
-
@mixin #{fruit} {
|
|
24
|
-
color: $#{fruit}-color;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
Sass::Engine.new(contents, :filename => name, :syntax => :scss, :importer => self)
|
|
11
|
+
return unless fruit = parse(name)
|
|
12
|
+
color = case fruit
|
|
13
|
+
when "apple"
|
|
14
|
+
"red"
|
|
15
|
+
when "orange"
|
|
16
|
+
"orange"
|
|
17
|
+
else
|
|
18
|
+
"blue"
|
|
28
19
|
end
|
|
20
|
+
contents = %Q{
|
|
21
|
+
$#{fruit}-color: #{color} !default;
|
|
22
|
+
@mixin #{fruit} {
|
|
23
|
+
color: $#{fruit}-color;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
Sass::Engine.new(contents, :filename => name, :syntax => :scss, :importer => self)
|
|
29
27
|
end
|
|
30
28
|
|
|
31
29
|
def key(name, context)
|
|
32
30
|
[self.class.name, name]
|
|
33
31
|
end
|
|
32
|
+
|
|
33
|
+
def public_url(name)
|
|
34
|
+
"http://#{parse(name)}.example.com/style.scss"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def parse(name)
|
|
40
|
+
name[%r{fruits/(\w+)(\.s[ac]ss)?}, 1]
|
|
41
|
+
end
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
# This class proves that you can override the extension scheme for importers
|
|
@@ -177,6 +185,123 @@ CSS
|
|
|
177
185
|
)
|
|
178
186
|
end
|
|
179
187
|
|
|
188
|
+
def test_source_map_with_only_css_uri_supports_public_url_imports
|
|
189
|
+
fruit_importer = FruitImporter.new
|
|
190
|
+
|
|
191
|
+
options = {
|
|
192
|
+
:filename => 'fruits/orange',
|
|
193
|
+
:importer => fruit_importer,
|
|
194
|
+
:syntax => :scss
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
engine = Sass::Engine.new(<<SCSS, options)
|
|
198
|
+
.orchard {
|
|
199
|
+
color: blue;
|
|
200
|
+
}
|
|
201
|
+
SCSS
|
|
202
|
+
|
|
203
|
+
rendered, sourcemap = engine.render_with_sourcemap('sourcemap_uri')
|
|
204
|
+
assert_equal <<JSON.strip, sourcemap.to_json(:css_uri => 'css_uri')
|
|
205
|
+
{
|
|
206
|
+
"version": "3",
|
|
207
|
+
"mappings": ";EACE,KAAK,EAAE,IAAI",
|
|
208
|
+
"sources": ["http://orange.example.com/style.scss"],
|
|
209
|
+
"file": "css_uri"
|
|
210
|
+
}
|
|
211
|
+
JSON
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def test_source_map_with_only_css_uri_doesnt_support_filesystem_importer
|
|
215
|
+
file_system_importer = Sass::Importers::Filesystem.new('.')
|
|
216
|
+
options = {
|
|
217
|
+
:filename => filename_for_test(:scss),
|
|
218
|
+
:importer => file_system_importer,
|
|
219
|
+
:syntax => :scss
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
engine = Sass::Engine.new(<<SCSS, options)
|
|
223
|
+
.foo {a: b}
|
|
224
|
+
SCSS
|
|
225
|
+
|
|
226
|
+
rendered, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
|
|
227
|
+
|
|
228
|
+
assert_raise_message(Sass::SyntaxError, <<MESSAGE) {sourcemap.to_json(:css_uri => 'css_uri')}
|
|
229
|
+
Error generating source map: couldn't determine public URL for "#{filename_for_test(:scss)}".
|
|
230
|
+
MESSAGE
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def test_source_map_with_css_uri_and_css_path_doesnt_support_filesystem_importer
|
|
234
|
+
file_system_importer = Sass::Importers::Filesystem.new('.')
|
|
235
|
+
options = {
|
|
236
|
+
:filename => filename_for_test(:scss),
|
|
237
|
+
:importer => file_system_importer,
|
|
238
|
+
:syntax => :scss
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
engine = Sass::Engine.new(<<SCSS, options)
|
|
242
|
+
.foo {a: b}
|
|
243
|
+
SCSS
|
|
244
|
+
|
|
245
|
+
rendered, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
|
|
246
|
+
|
|
247
|
+
assert_raise_message(Sass::SyntaxError, <<MESSAGE) {sourcemap.to_json(:css_uri => 'css_uri', :css_path => 'css_path')}
|
|
248
|
+
Error generating source map: couldn't determine public URL for "#{filename_for_test(:scss)}".
|
|
249
|
+
MESSAGE
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def test_source_map_with_css_uri_and_sourcemap_path_supports_filesystem_importer
|
|
253
|
+
file_system_importer = Sass::Importers::Filesystem.new('.')
|
|
254
|
+
options = {
|
|
255
|
+
:filename => 'sass/style.scss',
|
|
256
|
+
:importer => file_system_importer,
|
|
257
|
+
:syntax => :scss
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
engine = Sass::Engine.new(<<SCSS, options)
|
|
261
|
+
.foo {a: b}
|
|
262
|
+
SCSS
|
|
263
|
+
|
|
264
|
+
rendered, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
rendered, sourcemap = engine.render_with_sourcemap('http://map.example.com/map/style.map')
|
|
268
|
+
css_uri = 'css_uri'
|
|
269
|
+
sourcemap_path = 'map/style.map'
|
|
270
|
+
assert_equal <<JSON.strip, sourcemap.to_json(:css_uri => css_uri, :sourcemap_path => sourcemap_path)
|
|
271
|
+
{
|
|
272
|
+
"version": "3",
|
|
273
|
+
"mappings": ";EAAM,CAAC,EAAE,CAAC",
|
|
274
|
+
"sources": ["../sass/style.scss"],
|
|
275
|
+
"file": "css_uri"
|
|
276
|
+
}
|
|
277
|
+
JSON
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def test_source_map_with_css_path_and_sourcemap_path_supports_file_system_importer
|
|
281
|
+
file_system_importer = Sass::Importers::Filesystem.new('.')
|
|
282
|
+
options = {
|
|
283
|
+
:filename => 'sass/style.scss',
|
|
284
|
+
:importer => file_system_importer,
|
|
285
|
+
:syntax => :scss
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
engine = Sass::Engine.new(<<SCSS, options)
|
|
289
|
+
.foo {a: b}
|
|
290
|
+
SCSS
|
|
291
|
+
|
|
292
|
+
rendered, sourcemap = engine.render_with_sourcemap('http://map.example.com/map/style.map')
|
|
293
|
+
css_path = 'static/style.css'
|
|
294
|
+
sourcemap_path = 'map/style.map'
|
|
295
|
+
assert_equal <<JSON.strip, sourcemap.to_json(:css_path => css_path, :sourcemap_path => sourcemap_path)
|
|
296
|
+
{
|
|
297
|
+
"version": "3",
|
|
298
|
+
"mappings": ";EAAM,CAAC,EAAE,CAAC",
|
|
299
|
+
"sources": ["../sass/style.scss"],
|
|
300
|
+
"file": "../static/style.css"
|
|
301
|
+
}
|
|
302
|
+
JSON
|
|
303
|
+
end
|
|
304
|
+
|
|
180
305
|
def fixture_dir
|
|
181
306
|
File.join(File.dirname(__FILE__), "fixtures")
|
|
182
307
|
end
|
data/test/sass/scss/css_test.rb
CHANGED
|
@@ -1064,7 +1064,7 @@ SCSS
|
|
|
1064
1064
|
end
|
|
1065
1065
|
|
|
1066
1066
|
def render(scss, options = {})
|
|
1067
|
-
tree = Sass::SCSS::CssParser.new(scss, options[:filename]).parse
|
|
1067
|
+
tree = Sass::SCSS::CssParser.new(scss, options[:filename], nil).parse
|
|
1068
1068
|
tree.options = Sass::Engine::DEFAULT_OPTIONS.merge(options)
|
|
1069
1069
|
tree.render
|
|
1070
1070
|
end
|
data/test/sass/scss/scss_test.rb
CHANGED
|
@@ -4,6 +4,13 @@ require File.dirname(__FILE__) + '/../test_helper'
|
|
|
4
4
|
require File.dirname(__FILE__) + '/test_helper'
|
|
5
5
|
|
|
6
6
|
class SourcemapTest < Test::Unit::TestCase
|
|
7
|
+
def test_to_json_requires_args
|
|
8
|
+
rendered, sourcemap = render_with_sourcemap('')
|
|
9
|
+
assert_raise(ArgumentError) {sourcemap.to_json({})}
|
|
10
|
+
assert_raise(ArgumentError) {sourcemap.to_json({:css_path => 'foo'})}
|
|
11
|
+
assert_raise(ArgumentError) {sourcemap.to_json({:sourcemap_path => 'foo'})}
|
|
12
|
+
end
|
|
13
|
+
|
|
7
14
|
def test_simple_mapping_scss
|
|
8
15
|
assert_parses_with_sourcemap <<SCSS, <<CSS, <<JSON
|
|
9
16
|
a {
|
|
@@ -70,7 +77,7 @@ CSS
|
|
|
70
77
|
{
|
|
71
78
|
"version": "3",
|
|
72
79
|
"mappings": ";EACE,GAAG,EAAE,GAAG;;EAER,SAAS,EAAE,IAAI",
|
|
73
|
-
"sources": ["
|
|
80
|
+
"sources": ["../scss/style.scss"],
|
|
74
81
|
"file": "style.css"
|
|
75
82
|
}
|
|
76
83
|
JSON
|
|
@@ -94,7 +101,7 @@ CSS
|
|
|
94
101
|
{
|
|
95
102
|
"version": "3",
|
|
96
103
|
"mappings": ";EACE,GAAG,EAAE,GAAG;;EAEP,SAAS,EAAC,IAAI",
|
|
97
|
-
"sources": ["
|
|
104
|
+
"sources": ["../sass/style.sass"],
|
|
98
105
|
"file": "style.css"
|
|
99
106
|
}
|
|
100
107
|
JSON
|
|
@@ -725,7 +732,9 @@ CSS
|
|
|
725
732
|
assert(!closing || start_positions[name], "Closing annotation #{name} found before opening one.")
|
|
726
733
|
position = Sass::Source::Position.new(line, offset)
|
|
727
734
|
if closing
|
|
728
|
-
ranges[name] << Sass::Source::Range.new(
|
|
735
|
+
ranges[name] << Sass::Source::Range.new(
|
|
736
|
+
start_positions[name], position, file_name,
|
|
737
|
+
Sass::Importers::Filesystem.new('.'))
|
|
729
738
|
start_positions.delete name
|
|
730
739
|
else
|
|
731
740
|
assert(!start_positions[name], "Overlapping range annotation #{name} encountered on line #{line}")
|
|
@@ -795,8 +804,12 @@ MESSAGE
|
|
|
795
804
|
|
|
796
805
|
def assert_parses_with_sourcemap(source, css, sourcemap_json, options={})
|
|
797
806
|
rendered, sourcemap = render_with_sourcemap(source, options)
|
|
807
|
+
css_path = options[:output] || "test.css"
|
|
808
|
+
sourcemap_path = Sass::Util.sourcemap_name(css_path)
|
|
809
|
+
rendered_json = sourcemap.to_json(:css_path => css_path, :sourcemap_path => sourcemap_path)
|
|
810
|
+
|
|
798
811
|
assert_equal css.rstrip, rendered.rstrip
|
|
799
|
-
assert_equal sourcemap_json.rstrip,
|
|
812
|
+
assert_equal sourcemap_json.rstrip, rendered_json
|
|
800
813
|
end
|
|
801
814
|
|
|
802
815
|
def render_with_sourcemap(source, options={})
|
data/test/sass/util_test.rb
CHANGED
|
@@ -314,7 +314,7 @@ class UtilTest < Test::Unit::TestCase
|
|
|
314
314
|
assert_json_string "", ""
|
|
315
315
|
alphanum = (("0".."9").to_a).concat(("a".."z").to_a).concat(("A".."Z").to_a).join
|
|
316
316
|
assert_json_string alphanum, alphanum
|
|
317
|
-
assert_json_string "'\"
|
|
317
|
+
assert_json_string "'\"\\'", "'\\\"\\\\'"
|
|
318
318
|
assert_json_string "\b\f\n\r\t", "\\b\\f\\n\\r\\t"
|
|
319
319
|
end
|
|
320
320
|
|
metadata
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sass
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 592302989
|
|
5
5
|
prerelease: 6
|
|
6
6
|
segments:
|
|
7
7
|
- 3
|
|
8
8
|
- 3
|
|
9
9
|
- 0
|
|
10
10
|
- alpha
|
|
11
|
-
-
|
|
12
|
-
version: 3.3.0.alpha.
|
|
11
|
+
- 64
|
|
12
|
+
version: 3.3.0.alpha.64
|
|
13
13
|
platform: ruby
|
|
14
14
|
authors:
|
|
15
15
|
- Nathan Weizenbaum
|
|
@@ -19,7 +19,7 @@ autorequire:
|
|
|
19
19
|
bindir: bin
|
|
20
20
|
cert_chain: []
|
|
21
21
|
|
|
22
|
-
date: 2012-12-
|
|
22
|
+
date: 2012-12-27 00:00:00 -05:00
|
|
23
23
|
default_executable:
|
|
24
24
|
dependencies:
|
|
25
25
|
- !ruby/object:Gem::Dependency
|