sass 3.3.0.alpha.61 → 3.3.0.alpha.64

Sign up to get free protection for your applications and to get access to all the features.
data/REVISION CHANGED
@@ -1 +1 @@
1
- 0c20f2ff8c4f36a29092ac5eb3e844ac1019ce63
1
+ 62e36b0efe872f1be55de2a82b01d88f2b08d9b1
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.3.0.alpha.61
1
+ 3.3.0.alpha.64
@@ -1 +1 @@
1
- 22 December 2012 02:37:28 GMT
1
+ 27 December 2012 22:38:55 GMT
@@ -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
@@ -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
- # @sourceMappingURL comment. This should be relative to the location of
273
- # the CSS file.
274
- # @return [(String, Sass::Source::Map)] The rendered CSS and the associated source map
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, @options[:filename], @line, to_parser_offset(offset))
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, @options[:filename], @line, to_parser_offset(@offset))
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, @options[:filename], @line, str.source_range.end_pos.offset)
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(str.source_range.start_pos, end_pos, @options[:filename])
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, @options[:filename], @line, offset)
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
@@ -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(@options[:output_filename]))
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
@@ -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
  #
@@ -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
@@ -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
@@ -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 warnings.
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!
@@ -64,16 +64,49 @@ module Sass::Source
64
64
 
65
65
  # Returns the standard JSON representation of the source map.
66
66
  #
67
- # @param target_filename [String] The filename of the output file; that is,
68
- # the target of the mapping. This should be relative to the working
69
- # directory.
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
- def to_json(target_filename)
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
- source_pathname_to_id = {}
76
- id_to_source_pathname = {}
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
- source_pathname = Pathname.pwd.join(Pathname.new(m.input.file)).cleanpath
91
- source_pathname = source_pathname.relative_path_from(target_pathname.dirname)
92
- current_source_id = source_pathname_to_id[source_pathname]
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
- source_pathname_to_id[source_pathname] = current_source_id
98
- id_to_source_pathname[current_source_id] = source_pathname
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(id_to_source_pathname[id].to_s)}
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", target_pathname.basename.to_s)
185
+ write_json_field(result, "file", css_uri)
144
186
 
145
187
  result << "\n}"
146
188
  result
@@ -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
- def initialize(start_pos, end_pos, file)
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.
@@ -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), node.filename, node.line)
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), node.filename, node.line)
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), node.filename, node.line)
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), node.filename, node.line)
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
@@ -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 !~ /["\\\/\b\f\n\r\t]/
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"
@@ -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
- if name =~ %r{fruits/(\w+)(\.s[ac]ss)?}
12
- fruit = $1
13
- color = case $1
14
- when "apple"
15
- "red"
16
- when "orange"
17
- "orange"
18
- else
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
@@ -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
@@ -2010,7 +2010,7 @@ SCSS
2010
2010
  @extend .bbb;
2011
2011
  }
2012
2012
  SCSS
2013
- Sass::SCSS::Parser.new(template, "test.scss").parse
2013
+ Sass::SCSS::Parser.new(template, "test.scss", nil).parse
2014
2014
  end
2015
2015
 
2016
2016
  def test_extend_in_media_in_rule
@@ -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": ["..\\/scss\\/style.scss"],
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": ["..\\/sass\\/style.sass"],
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(start_positions[name], position, file_name)
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, sourcemap.to_json(options[:output] || "test.css")
812
+ assert_equal sourcemap_json.rstrip, rendered_json
800
813
  end
801
814
 
802
815
  def render_with_sourcemap(source, options={})
@@ -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: 592302967
4
+ hash: 592302989
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 3
8
8
  - 3
9
9
  - 0
10
10
  - alpha
11
- - 61
12
- version: 3.3.0.alpha.61
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-21 00:00:00 -05:00
22
+ date: 2012-12-27 00:00:00 -05:00
23
23
  default_executable:
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency