sass 3.4.21 → 3.4.22
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.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +122 -0
- data/MIT-LICENSE +1 -1
- data/README.md +15 -9
- data/Rakefile +71 -18
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/lib/sass.rb +7 -0
- data/lib/sass/callbacks.rb +2 -2
- data/lib/sass/css.rb +9 -8
- data/lib/sass/engine.rb +14 -8
- data/lib/sass/environment.rb +8 -1
- data/lib/sass/error.rb +5 -5
- data/lib/sass/exec/sass_convert.rb +14 -2
- data/lib/sass/exec/sass_scss.rb +2 -25
- data/lib/sass/features.rb +2 -2
- data/lib/sass/importers/filesystem.rb +6 -3
- data/lib/sass/plugin/compiler.rb +15 -7
- data/lib/sass/script/css_variable_warning.rb +52 -0
- data/lib/sass/script/functions.rb +5 -5
- data/lib/sass/script/lexer.rb +3 -1
- data/lib/sass/script/parser.rb +67 -15
- data/lib/sass/script/tree/funcall.rb +10 -3
- data/lib/sass/script/tree/node.rb +8 -0
- data/lib/sass/script/tree/operation.rb +7 -0
- data/lib/sass/script/value/base.rb +1 -0
- data/lib/sass/script/value/color.rb +6 -4
- data/lib/sass/script/value/helpers.rb +2 -2
- data/lib/sass/script/value/number.rb +5 -5
- data/lib/sass/scss.rb +0 -2
- data/lib/sass/scss/css_parser.rb +1 -2
- data/lib/sass/scss/parser.rb +20 -10
- data/lib/sass/scss/rx.rb +2 -2
- data/lib/sass/scss/static_parser.rb +11 -13
- data/lib/sass/selector/pseudo.rb +1 -1
- data/lib/sass/selector/sequence.rb +2 -2
- data/lib/sass/selector/simple_sequence.rb +4 -4
- data/lib/sass/stack.rb +2 -2
- data/lib/sass/tree/function_node.rb +1 -1
- data/lib/sass/tree/node.rb +2 -0
- data/lib/sass/tree/visitors/check_nesting.rb +2 -0
- data/lib/sass/tree/visitors/convert.rb +8 -7
- data/lib/sass/tree/visitors/perform.rb +4 -2
- data/lib/sass/tree/visitors/to_css.rb +10 -10
- data/lib/sass/util.rb +8 -7
- data/test/sass-spec.yml +3 -0
- data/test/sass/compiler_test.rb +1 -1
- data/test/sass/css_variable_test.rb +132 -0
- data/test/sass/exec_test.rb +10 -0
- data/test/sass/script_test.rb +1 -1
- data/test/sass/scss/scss_test.rb +10 -0
- metadata +79 -77
- data/lib/sass/scss/script_lexer.rb +0 -15
- data/lib/sass/scss/script_parser.rb +0 -25
@@ -128,12 +128,15 @@ module Sass::Script::Tree
|
|
128
128
|
splat = Sass::Tree::Visitors::Perform.perform_splat(
|
129
129
|
@splat, keywords, @kwarg_splat, environment)
|
130
130
|
if (fn = environment.function(@name))
|
131
|
+
css_variable_warning.warn! if css_variable_warning
|
131
132
|
return without_original(perform_sass_fn(fn, args, splat, environment))
|
132
133
|
end
|
133
134
|
|
134
135
|
args = construct_ruby_args(ruby_name, args, splat, environment)
|
135
136
|
|
136
137
|
if Sass::Script::Functions.callable?(ruby_name)
|
138
|
+
css_variable_warning.warn! if css_variable_warning
|
139
|
+
|
137
140
|
local_environment = Sass::Environment.new(environment.global_env, environment.options)
|
138
141
|
local_environment.caller = Sass::ReadOnlyEnvironment.new(environment, environment.options)
|
139
142
|
result = opts(Sass::Script::Functions::EvaluationContext.new(
|
@@ -208,7 +211,7 @@ module Sass::Script::Tree
|
|
208
211
|
|
209
212
|
argnames = signature.args[args.size..-1] || []
|
210
213
|
deprecated_argnames = (signature.deprecated && signature.deprecated[args.size..-1]) || []
|
211
|
-
args
|
214
|
+
args += argnames.zip(deprecated_argnames).map do |(argname, deprecated_argname)|
|
212
215
|
if keywords.has_key?(argname)
|
213
216
|
keywords.delete(argname)
|
214
217
|
elsif deprecated_argname && keywords.has_key?(deprecated_argname)
|
@@ -296,8 +299,12 @@ module Sass::Script::Tree
|
|
296
299
|
message = "wrong number of arguments (#{given} for #{expected})"
|
297
300
|
end
|
298
301
|
end
|
299
|
-
elsif
|
300
|
-
|
302
|
+
elsif (md = /^wrong number of arguments \(given (\d+), expected (\d+)\)/.match(e.message)) &&
|
303
|
+
e.backtrace[0] =~ /:in `#{ruby_name}'$/
|
304
|
+
# Handle ruby 2.3 error formatting
|
305
|
+
message = "wrong number of arguments (#{md[1]} for #{md[2]})"
|
306
|
+
elsif e.message =~ /^wrong number of arguments/ &&
|
307
|
+
e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
|
301
308
|
raise e
|
302
309
|
end
|
303
310
|
raise Sass::SyntaxError.new("#{message} for `#{name}'")
|
@@ -23,6 +23,14 @@ module Sass::Script::Tree
|
|
23
23
|
# @return [String]
|
24
24
|
attr_accessor :filename
|
25
25
|
|
26
|
+
# The warning that this node should emit if it executes in a way that's not
|
27
|
+
# safe for a CSS variable value.
|
28
|
+
#
|
29
|
+
# This is `nil` if this is not in a CSS variable value.
|
30
|
+
#
|
31
|
+
# @return [Sass::Script::CssVariableWarning]
|
32
|
+
attr_accessor :css_variable_warning
|
33
|
+
|
26
34
|
# Sets the options hash for this node,
|
27
35
|
# as well as for all child nodes.
|
28
36
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
@@ -78,6 +78,13 @@ module Sass::Script::Tree
|
|
78
78
|
"Invalid null operation: \"#{value1.inspect} #{@operator} #{value2.inspect}\".")
|
79
79
|
end
|
80
80
|
|
81
|
+
if css_variable_warning && @operator == :div &&
|
82
|
+
!(value1.is_a?(Sass::Script::Value::Number) && value1.original &&
|
83
|
+
value2.is_a?(Sass::Script::Value::Number) && value2.original) &&
|
84
|
+
!(value1.is_a?(Sass::Script::Value::String) && value2.is_a?(Sass::Script::Value::String))
|
85
|
+
css_variable_warning.warn!
|
86
|
+
end
|
87
|
+
|
81
88
|
begin
|
82
89
|
result = opts(value1.send(@operator, value2))
|
83
90
|
rescue NoMethodError => e
|
@@ -25,7 +25,8 @@ module Sass::Script::Value
|
|
25
25
|
rgba
|
26
26
|
end
|
27
27
|
|
28
|
-
ALTERNATE_COLOR_NAMES = Sass::Util.map_vals(
|
28
|
+
ALTERNATE_COLOR_NAMES = Sass::Util.map_vals(
|
29
|
+
{
|
29
30
|
'aqua' => 0x00FFFFFF,
|
30
31
|
'darkgrey' => 0xA9A9A9FF,
|
31
32
|
'darkslategrey' => 0x2F4F4FFF,
|
@@ -35,10 +36,11 @@ module Sass::Script::Value
|
|
35
36
|
'lightgrey' => 0xD3D3D3FF,
|
36
37
|
'lightslategrey' => 0x778899FF,
|
37
38
|
'slategrey' => 0x708090FF,
|
38
|
-
|
39
|
+
}, &method(:int_to_rgba))
|
39
40
|
|
40
41
|
# A hash from color names to `[red, green, blue]` value arrays.
|
41
|
-
COLOR_NAMES = Sass::Util.map_vals(
|
42
|
+
COLOR_NAMES = Sass::Util.map_vals(
|
43
|
+
{
|
42
44
|
'aliceblue' => 0xF0F8FFFF,
|
43
45
|
'antiquewhite' => 0xFAEBD7FF,
|
44
46
|
'aquamarine' => 0x7FFFD4FF,
|
@@ -179,7 +181,7 @@ module Sass::Script::Value
|
|
179
181
|
'whitesmoke' => 0xF5F5F5FF,
|
180
182
|
'yellow' => 0xFFFF00FF,
|
181
183
|
'yellowgreen' => 0x9ACD32FF
|
182
|
-
|
184
|
+
}, &method(:int_to_rgba))
|
183
185
|
|
184
186
|
# A hash from `[red, green, blue, alpha]` value arrays to color names.
|
185
187
|
COLOR_NAMES_REVERSE = COLOR_NAMES.invert.freeze
|
@@ -252,14 +252,14 @@ module Sass::Script::Value
|
|
252
252
|
def parse_unit_string(unit_string)
|
253
253
|
denominator_units = numerator_units = Sass::Script::Value::Number::NO_UNITS
|
254
254
|
return numerator_units, denominator_units unless unit_string && unit_string.length > 0
|
255
|
-
num_over_denominator = unit_string.split(
|
255
|
+
num_over_denominator = unit_string.split(%r{ */ *})
|
256
256
|
unless (1..2).include?(num_over_denominator.size)
|
257
257
|
raise ArgumentError.new("Malformed unit string: #{unit_string}")
|
258
258
|
end
|
259
259
|
numerator_units = num_over_denominator[0].split(/ *\* */)
|
260
260
|
denominator_units = (num_over_denominator[1] || "").split(/ *\* */)
|
261
261
|
[[numerator_units, "numerator"], [denominator_units, "denominator"]].each do |units, name|
|
262
|
-
if unit_string =~
|
262
|
+
if unit_string =~ %r{/} && units.size == 0
|
263
263
|
raise ArgumentError.new("Malformed unit string: #{unit_string}")
|
264
264
|
end
|
265
265
|
if units.any? {|unit| unit !~ VALID_UNIT}
|
@@ -71,6 +71,7 @@ module Sass::Script::Value
|
|
71
71
|
super(value)
|
72
72
|
@numerator_units = numerator_units
|
73
73
|
@denominator_units = denominator_units
|
74
|
+
@options = nil
|
74
75
|
normalize!
|
75
76
|
end
|
76
77
|
|
@@ -469,11 +470,10 @@ module Sass::Script::Value
|
|
469
470
|
sans_common_units(@numerator_units, @denominator_units)
|
470
471
|
|
471
472
|
@denominator_units.each_with_index do |d, i|
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
end
|
473
|
+
next unless convertable?(d) && (u = @numerator_units.find(&method(:convertable?)))
|
474
|
+
@value /= conversion_factor(d, u)
|
475
|
+
@denominator_units.delete_at(i)
|
476
|
+
@numerator_units.delete_at(@numerator_units.index(u))
|
477
477
|
end
|
478
478
|
end
|
479
479
|
|
data/lib/sass/scss.rb
CHANGED
data/lib/sass/scss/css_parser.rb
CHANGED
@@ -50,8 +50,7 @@ module Sass
|
|
50
50
|
block(node(Sass::Tree::KeyframeRuleNode.new(selector.strip), start_pos), :ruleset)
|
51
51
|
end
|
52
52
|
|
53
|
-
@sass_script_parser =
|
54
|
-
@sass_script_parser.send(:include, ScriptParser)
|
53
|
+
@sass_script_parser = Sass::Script::CssParser
|
55
54
|
end
|
56
55
|
end
|
57
56
|
end
|
data/lib/sass/scss/parser.rb
CHANGED
@@ -28,6 +28,8 @@ module Sass
|
|
28
28
|
@line = line
|
29
29
|
@offset = offset
|
30
30
|
@strs = []
|
31
|
+
@expected = nil
|
32
|
+
@throw_error = false
|
31
33
|
end
|
32
34
|
|
33
35
|
# Parses an SCSS document.
|
@@ -509,7 +511,7 @@ module Sass
|
|
509
511
|
|
510
512
|
def moz_document_function
|
511
513
|
val = interp_uri || _interp_string(:url_prefix) ||
|
512
|
-
_interp_string(:domain) || function(
|
514
|
+
_interp_string(:domain) || function(false) || interpolation
|
513
515
|
return unless val
|
514
516
|
ss
|
515
517
|
val
|
@@ -638,7 +640,7 @@ module Sass
|
|
638
640
|
# are disallowed by the CSS spec,
|
639
641
|
# but they're included here for compatibility
|
640
642
|
# with some proprietary MS properties
|
641
|
-
str {ss if tok(
|
643
|
+
str {ss if tok(%r{[/,:.=]})}
|
642
644
|
end
|
643
645
|
|
644
646
|
def ruleset
|
@@ -764,7 +766,7 @@ module Sass
|
|
764
766
|
value_start_pos = source_position
|
765
767
|
value = nil
|
766
768
|
error = catch_error do
|
767
|
-
value = value!
|
769
|
+
value = value!(name.first.is_a?(String) && name.first.start_with?("--"))
|
768
770
|
if tok?(/\{/)
|
769
771
|
# Properties that are ambiguous with selectors can't have additional
|
770
772
|
# properties nested beneath them.
|
@@ -857,7 +859,7 @@ module Sass
|
|
857
859
|
tok!(/:/)
|
858
860
|
ss
|
859
861
|
value_start_pos = source_position
|
860
|
-
value = value!
|
862
|
+
value = value!(name.first.is_a?(String) && name.first.start_with?("--"))
|
861
863
|
value_end_pos = source_position
|
862
864
|
ss
|
863
865
|
require_block = tok?(/\{/)
|
@@ -871,7 +873,7 @@ module Sass
|
|
871
873
|
nested_properties! node
|
872
874
|
end
|
873
875
|
|
874
|
-
def value!
|
876
|
+
def value!(css_variable = false)
|
875
877
|
if tok?(/\{/)
|
876
878
|
str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
|
877
879
|
str.line = source_position.line
|
@@ -891,10 +893,19 @@ module Sass
|
|
891
893
|
str.source_range = range(start_pos)
|
892
894
|
return str
|
893
895
|
end
|
894
|
-
|
896
|
+
|
897
|
+
sass_script(:parse, css_variable)
|
895
898
|
end
|
896
899
|
|
897
900
|
def nested_properties!(node)
|
901
|
+
if node.name.first.is_a?(String) && node.name.first.start_with?("--")
|
902
|
+
Sass::Util.sass_warn(<<WARNING)
|
903
|
+
DEPRECATION WARNING on line #{@line}#{" of #{@filename}" if @filename}:
|
904
|
+
Sass 3.6 will change the way CSS variables are parsed. Instead of being parsed as
|
905
|
+
normal properties, they will not allow any Sass-specific behavior other than \#{}.
|
906
|
+
WARNING
|
907
|
+
end
|
908
|
+
|
898
909
|
@expected = 'expression (e.g. 1px, bold) or "{"'
|
899
910
|
block(node, :property)
|
900
911
|
end
|
@@ -1027,8 +1038,7 @@ module Sass
|
|
1027
1038
|
node
|
1028
1039
|
end
|
1029
1040
|
|
1030
|
-
@sass_script_parser =
|
1031
|
-
@sass_script_parser.send(:include, ScriptParser)
|
1041
|
+
@sass_script_parser = Sass::Script::Parser
|
1032
1042
|
|
1033
1043
|
class << self
|
1034
1044
|
# @private
|
@@ -1037,7 +1047,7 @@ module Sass
|
|
1037
1047
|
|
1038
1048
|
def sass_script(*args)
|
1039
1049
|
parser = self.class.sass_script_parser.new(@scanner, @line, @offset,
|
1040
|
-
|
1050
|
+
:filename => @filename, :importer => @importer, :allow_extra_text => true)
|
1041
1051
|
result = parser.send(*args)
|
1042
1052
|
unless @strs.empty?
|
1043
1053
|
# Convert to CSS manually so that comments are ignored.
|
@@ -1102,7 +1112,7 @@ module Sass
|
|
1102
1112
|
|
1103
1113
|
unless name
|
1104
1114
|
# Display basic regexps as plain old strings
|
1105
|
-
source = rx.source.gsub(
|
1115
|
+
source = rx.source.gsub(%r{\\/}, '/')
|
1106
1116
|
string = rx.source.gsub(/\\(.)/, '\1')
|
1107
1117
|
name = source == Regexp.escape(string) ? string.inspect : rx.inspect
|
1108
1118
|
end
|
data/lib/sass/scss/rx.rb
CHANGED
@@ -32,7 +32,7 @@ module Sass
|
|
32
32
|
# @return [String] The escaped character
|
33
33
|
# @private
|
34
34
|
def self.escape_char(c)
|
35
|
-
return "\\%06x" % (Sass::Util.ord(c)) unless c =~
|
35
|
+
return "\\%06x" % (Sass::Util.ord(c)) unless c =~ %r{[ -/:-~]}
|
36
36
|
"\\#{c}"
|
37
37
|
end
|
38
38
|
|
@@ -133,7 +133,7 @@ module Sass
|
|
133
133
|
STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
|
134
134
|
|
135
135
|
STATIC_COMPONENT = /#{IDENT}|#{STRING_NOINTERP}|#{HEXCOLOR}|[+-]?#{NUMBER}|\!important/i
|
136
|
-
STATIC_VALUE =
|
136
|
+
STATIC_VALUE = %r(#{STATIC_COMPONENT}(\s*[\s,/]\s*#{STATIC_COMPONENT})*([;}]))i
|
137
137
|
STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){1,50}([{])/i
|
138
138
|
end
|
139
139
|
end
|
@@ -62,7 +62,7 @@ module Sass
|
|
62
62
|
private
|
63
63
|
|
64
64
|
def moz_document_function
|
65
|
-
val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(
|
65
|
+
val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(false)
|
66
66
|
return unless val
|
67
67
|
ss
|
68
68
|
[val]
|
@@ -78,7 +78,7 @@ module Sass
|
|
78
78
|
def use_css_import?; true; end
|
79
79
|
|
80
80
|
def special_directive(name, start_pos)
|
81
|
-
return unless %w
|
81
|
+
return unless %w(media import charset -moz-document).include?(name)
|
82
82
|
super
|
83
83
|
end
|
84
84
|
|
@@ -89,13 +89,12 @@ module Sass
|
|
89
89
|
ws = ''
|
90
90
|
while tok(/,/)
|
91
91
|
ws << str {ss}
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
ws = ''
|
92
|
+
next unless (sel = selector)
|
93
|
+
selectors << sel
|
94
|
+
if ws.include?("\n")
|
95
|
+
selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members)
|
98
96
|
end
|
97
|
+
ws = ''
|
99
98
|
end
|
100
99
|
Selector::CommaSequence.new(selectors)
|
101
100
|
end
|
@@ -140,11 +139,11 @@ MESSAGE
|
|
140
139
|
end
|
141
140
|
|
142
141
|
def reference_combinator
|
143
|
-
return unless tok(
|
142
|
+
return unless tok(%r{/})
|
144
143
|
res = '/'
|
145
144
|
ns, name = expr!(:qualified_name)
|
146
145
|
res << ns << '|' if ns
|
147
|
-
res << name << tok!(
|
146
|
+
res << name << tok!(%r{/})
|
148
147
|
res
|
149
148
|
end
|
150
149
|
|
@@ -266,9 +265,9 @@ MESSAGE
|
|
266
265
|
return ns, name
|
267
266
|
end
|
268
267
|
|
269
|
-
SELECTOR_PSEUDO_CLASSES = %w
|
268
|
+
SELECTOR_PSEUDO_CLASSES = %w(not matches current any has host host-context).to_set
|
270
269
|
|
271
|
-
PREFIXED_SELECTOR_PSEUDO_CLASSES = %w
|
270
|
+
PREFIXED_SELECTOR_PSEUDO_CLASSES = %w(nth-child nth-last-child).to_set
|
272
271
|
|
273
272
|
def pseudo
|
274
273
|
s = tok(/::?/)
|
@@ -362,7 +361,6 @@ MESSAGE
|
|
362
361
|
end
|
363
362
|
|
364
363
|
@sass_script_parser = Class.new(Sass::Script::CssParser)
|
365
|
-
@sass_script_parser.send(:include, ScriptParser)
|
366
364
|
end
|
367
365
|
end
|
368
366
|
end
|
data/lib/sass/selector/pseudo.rb
CHANGED
@@ -9,7 +9,7 @@ module Sass
|
|
9
9
|
# selectors.
|
10
10
|
#
|
11
11
|
# @return [Set<String>]
|
12
|
-
ACTUALLY_ELEMENTS = %w
|
12
|
+
ACTUALLY_ELEMENTS = %w(after before first-line first-letter).to_set
|
13
13
|
|
14
14
|
# Like \{#type}, but returns the type of selector this looks like, rather
|
15
15
|
# than the type it is semantically. This only differs from type for
|
@@ -395,10 +395,10 @@ module Sass
|
|
395
395
|
([merged, '+'] if merged)
|
396
396
|
].compact
|
397
397
|
end
|
398
|
-
elsif op1 == '>' && %w
|
398
|
+
elsif op1 == '>' && %w(~ +).include?(op2)
|
399
399
|
res.unshift sel2, op2
|
400
400
|
seq1.push sel1, op1
|
401
|
-
elsif op2 == '>' && %w
|
401
|
+
elsif op2 == '>' && %w(~ +).include?(op1)
|
402
402
|
res.unshift sel1, op1
|
403
403
|
seq2.push sel2, op2
|
404
404
|
elsif op1 == op2
|
@@ -88,7 +88,7 @@ module Sass
|
|
88
88
|
def resolve_parent_refs(super_cseq)
|
89
89
|
resolved_members = @members.map do |sel|
|
90
90
|
next sel unless sel.is_a?(Pseudo) && sel.selector
|
91
|
-
sel.with_selector(sel.selector.resolve_parent_refs(super_cseq,
|
91
|
+
sel.with_selector(sel.selector.resolve_parent_refs(super_cseq, false))
|
92
92
|
end.flatten
|
93
93
|
|
94
94
|
# Parent selector only appears as the first selector in the sequence
|
@@ -161,7 +161,7 @@ module Sass
|
|
161
161
|
members = self.members.map do |sel|
|
162
162
|
next sel unless sel.is_a?(Pseudo) && sel.selector
|
163
163
|
next sel if seen.include?([sel])
|
164
|
-
extended = sel.selector.do_extend(extends, parent_directives, replace, seen,
|
164
|
+
extended = sel.selector.do_extend(extends, parent_directives, replace, seen, false)
|
165
165
|
next sel if extended == sel.selector
|
166
166
|
extended.members.reject! {|seq| seq.has_placeholder?}
|
167
167
|
|
@@ -204,7 +204,7 @@ module Sass
|
|
204
204
|
groups.map! do |sels, seq|
|
205
205
|
next [] if seen.include?(sels)
|
206
206
|
seq.do_extend(
|
207
|
-
extends, parent_directives,
|
207
|
+
extends, parent_directives, false, seen_with_pseudo_selectors + [sels], false)
|
208
208
|
end
|
209
209
|
groups.flatten!
|
210
210
|
|
@@ -260,7 +260,7 @@ module Sass
|
|
260
260
|
|
261
261
|
# Some psuedo-selectors can be subselectors of non-pseudo selectors.
|
262
262
|
# Pull those out here so we can efficiently check against them below.
|
263
|
-
their_subselector_pseudos = %w
|
263
|
+
their_subselector_pseudos = %w(matches any nth-child nth-last-child).
|
264
264
|
map {|name| their_spcs[name] || []}.flatten
|
265
265
|
|
266
266
|
# If `self`'s non-pseudo simple selectors aren't a subset of `their_sseq`'s,
|
data/lib/sass/stack.rb
CHANGED
@@ -101,8 +101,8 @@ module Sass
|
|
101
101
|
def to_s
|
102
102
|
Sass::Util.enum_with_index(Sass::Util.enum_cons(frames.reverse + [nil], 2)).
|
103
103
|
map do |(frame, caller), i|
|
104
|
-
"#{i == 0 ?
|
105
|
-
" of #{frame.filename ||
|
104
|
+
"#{i == 0 ? 'on' : 'from'} line #{frame.line}" +
|
105
|
+
" of #{frame.filename || 'an unknown file'}" +
|
106
106
|
(caller && caller.name ? ", in `#{caller.name}'" : "")
|
107
107
|
end.join("\n")
|
108
108
|
end
|