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 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