sass 3.4.0 → 3.4.25
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +3 -1
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +148 -0
- data/MIT-LICENSE +1 -1
- data/README.md +26 -20
- data/Rakefile +103 -20
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/extra/sass-spec-ref.sh +32 -0
- data/extra/update_watch.rb +1 -1
- data/lib/sass/cache_stores/filesystem.rb +7 -7
- data/lib/sass/cache_stores/memory.rb +4 -5
- data/lib/sass/callbacks.rb +2 -2
- data/lib/sass/css.rb +11 -10
- data/lib/sass/deprecation.rb +55 -0
- data/lib/sass/engine.rb +83 -38
- data/lib/sass/environment.rb +26 -2
- data/lib/sass/error.rb +12 -12
- data/lib/sass/exec/base.rb +15 -3
- data/lib/sass/exec/sass_convert.rb +34 -15
- data/lib/sass/exec/sass_scss.rb +23 -7
- data/lib/sass/features.rb +2 -2
- data/lib/sass/importers/base.rb +1 -1
- data/lib/sass/importers/deprecated_path.rb +51 -0
- data/lib/sass/importers/filesystem.rb +24 -16
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +8 -2
- data/lib/sass/logger/delayed.rb +50 -0
- data/lib/sass/logger.rb +8 -3
- data/lib/sass/plugin/compiler.rb +42 -25
- data/lib/sass/plugin/configuration.rb +38 -22
- data/lib/sass/plugin/merb.rb +2 -2
- data/lib/sass/plugin/rack.rb +3 -3
- data/lib/sass/plugin/rails.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +3 -3
- data/lib/sass/plugin.rb +3 -2
- data/lib/sass/script/css_parser.rb +2 -3
- data/lib/sass/script/css_variable_warning.rb +52 -0
- data/lib/sass/script/functions.rb +140 -73
- data/lib/sass/script/lexer.rb +37 -22
- data/lib/sass/script/parser.rb +235 -40
- data/lib/sass/script/tree/funcall.rb +12 -5
- data/lib/sass/script/tree/interpolation.rb +109 -4
- data/lib/sass/script/tree/list_literal.rb +31 -4
- data/lib/sass/script/tree/literal.rb +4 -0
- data/lib/sass/script/tree/node.rb +21 -3
- data/lib/sass/script/tree/operation.rb +54 -1
- data/lib/sass/script/tree/string_interpolation.rb +58 -37
- data/lib/sass/script/tree/variable.rb +1 -1
- data/lib/sass/script/value/base.rb +10 -9
- data/lib/sass/script/value/color.rb +42 -24
- data/lib/sass/script/value/helpers.rb +16 -6
- data/lib/sass/script/value/map.rb +1 -1
- data/lib/sass/script/value/number.rb +52 -19
- data/lib/sass/script/value/string.rb +46 -5
- data/lib/sass/script.rb +3 -3
- data/lib/sass/scss/css_parser.rb +16 -2
- data/lib/sass/scss/parser.rb +120 -75
- data/lib/sass/scss/rx.rb +9 -10
- data/lib/sass/scss/static_parser.rb +19 -14
- data/lib/sass/scss.rb +0 -2
- data/lib/sass/selector/abstract_sequence.rb +8 -6
- data/lib/sass/selector/comma_sequence.rb +25 -9
- data/lib/sass/selector/pseudo.rb +45 -35
- data/lib/sass/selector/sequence.rb +54 -18
- data/lib/sass/selector/simple.rb +11 -11
- data/lib/sass/selector/simple_sequence.rb +34 -15
- data/lib/sass/selector.rb +7 -10
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/source/map.rb +7 -4
- data/lib/sass/source/position.rb +4 -4
- data/lib/sass/stack.rb +2 -2
- data/lib/sass/supports.rb +8 -10
- data/lib/sass/tree/comment_node.rb +1 -1
- data/lib/sass/tree/css_import_node.rb +9 -1
- data/lib/sass/tree/function_node.rb +8 -3
- data/lib/sass/tree/import_node.rb +6 -5
- data/lib/sass/tree/node.rb +5 -3
- data/lib/sass/tree/prop_node.rb +5 -6
- data/lib/sass/tree/rule_node.rb +14 -4
- data/lib/sass/tree/visitors/check_nesting.rb +18 -22
- data/lib/sass/tree/visitors/convert.rb +43 -26
- data/lib/sass/tree/visitors/cssize.rb +5 -1
- data/lib/sass/tree/visitors/deep_copy.rb +1 -1
- data/lib/sass/tree/visitors/extend.rb +15 -13
- data/lib/sass/tree/visitors/perform.rb +42 -17
- data/lib/sass/tree/visitors/set_options.rb +1 -1
- data/lib/sass/tree/visitors/to_css.rb +58 -30
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/normalized_map.rb +0 -1
- data/lib/sass/util/subset_map.rb +1 -2
- data/lib/sass/util.rb +125 -68
- data/lib/sass/version.rb +2 -2
- data/lib/sass.rb +10 -3
- data/test/sass/compiler_test.rb +6 -2
- data/test/sass/conversion_test.rb +187 -53
- data/test/sass/css2sass_test.rb +50 -1
- data/test/sass/css_variable_test.rb +132 -0
- data/test/sass/engine_test.rb +207 -61
- data/test/sass/exec_test.rb +10 -0
- data/test/sass/extend_test.rb +101 -29
- data/test/sass/functions_test.rb +60 -9
- data/test/sass/importer_test.rb +9 -0
- data/test/sass/more_templates/more1.sass +10 -10
- data/test/sass/more_templates/more_import.sass +2 -2
- data/test/sass/plugin_test.rb +10 -8
- data/test/sass/results/script.css +3 -3
- data/test/sass/script_conversion_test.rb +58 -29
- data/test/sass/script_test.rb +430 -53
- data/test/sass/scss/css_test.rb +73 -7
- data/test/sass/scss/rx_test.rb +4 -0
- data/test/sass/scss/scss_test.rb +309 -4
- data/test/sass/source_map_test.rb +152 -74
- data/test/sass/superselector_test.rb +19 -0
- data/test/sass/templates/_partial.sass +1 -1
- data/test/sass/templates/basic.sass +10 -10
- data/test/sass/templates/bork1.sass +1 -1
- data/test/sass/templates/bork5.sass +1 -1
- data/test/sass/templates/compact.sass +10 -10
- data/test/sass/templates/complex.sass +187 -187
- data/test/sass/templates/compressed.sass +10 -10
- data/test/sass/templates/expanded.sass +10 -10
- data/test/sass/templates/import.sass +2 -2
- data/test/sass/templates/importee.sass +3 -3
- data/test/sass/templates/mixins.sass +22 -22
- data/test/sass/templates/multiline.sass +4 -4
- data/test/sass/templates/nested.sass +13 -13
- data/test/sass/templates/parent_ref.sass +12 -12
- data/test/sass/templates/script.sass +70 -70
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
- data/test/sass/templates/subdir/subdir.sass +3 -3
- data/test/sass/templates/units.sass +10 -10
- data/test/sass/util/multibyte_string_scanner_test.rb +10 -2
- data/test/sass/util_test.rb +15 -44
- data/test/sass-spec.yml +3 -0
- data/test/test_helper.rb +5 -4
- metadata +302 -295
- data/CONTRIBUTING +0 -3
- data/lib/sass/scss/script_lexer.rb +0 -15
- data/lib/sass/scss/script_parser.rb +0 -25
@@ -12,8 +12,10 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
12
12
|
@tabs = 0
|
13
13
|
@line = 1
|
14
14
|
@offset = 1
|
15
|
-
@result = ""
|
16
|
-
@source_mapping = Sass::Source::Map.new
|
15
|
+
@result = String.new("")
|
16
|
+
@source_mapping = build_source_mapping ? Sass::Source::Map.new : nil
|
17
|
+
@lstrip = nil
|
18
|
+
@in_directive = false
|
17
19
|
end
|
18
20
|
|
19
21
|
# Runs the visitor on `node`.
|
@@ -51,6 +53,10 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
51
53
|
@source_mapping.add(source_range, target_range)
|
52
54
|
end
|
53
55
|
|
56
|
+
def trailing_semicolon?
|
57
|
+
@result.end_with?(";") && !@result.end_with?('\;')
|
58
|
+
end
|
59
|
+
|
54
60
|
# Move the output cursor back `chars` characters.
|
55
61
|
def erase!(chars)
|
56
62
|
return if chars == 0
|
@@ -98,7 +104,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
98
104
|
@lstrip = true
|
99
105
|
yield
|
100
106
|
ensure
|
101
|
-
@lstrip
|
107
|
+
@lstrip &&= old_lstrip
|
102
108
|
end
|
103
109
|
|
104
110
|
# Prepend `prefix` to the output string.
|
@@ -116,14 +122,15 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
116
122
|
node.children.each do |child|
|
117
123
|
next if child.invisible?
|
118
124
|
visit(child)
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
end
|
124
|
-
end
|
125
|
+
next if node.style == :compressed
|
126
|
+
output "\n"
|
127
|
+
next unless child.is_a?(Sass::Tree::DirectiveNode) && child.has_children && !child.bubbles?
|
128
|
+
output "\n"
|
125
129
|
end
|
126
130
|
rstrip!
|
131
|
+
if node.style == :compressed && trailing_semicolon?
|
132
|
+
erase! 1
|
133
|
+
end
|
127
134
|
return "" if @result.empty?
|
128
135
|
|
129
136
|
output "\n"
|
@@ -152,13 +159,14 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
152
159
|
def visit_comment(node)
|
153
160
|
return if node.invisible?
|
154
161
|
spaces = (' ' * [@tabs - node.resolved_value[/^ */].size, 0].max)
|
162
|
+
output(spaces)
|
155
163
|
|
156
|
-
content = node.resolved_value.
|
164
|
+
content = node.resolved_value.split("\n").join("\n" + spaces)
|
157
165
|
if node.type == :silent
|
158
|
-
content.gsub!(%r{^(\s*)//(.*)$}) {
|
166
|
+
content.gsub!(%r{^(\s*)//(.*)$}) {"#{$1}/*#{$2} */"}
|
159
167
|
end
|
160
168
|
if (node.style == :compact || node.style == :compressed) && node.type != :loud
|
161
|
-
content.gsub!(
|
169
|
+
content.gsub!(%r{\n +(\* *(?!/))?}, ' ')
|
162
170
|
end
|
163
171
|
for_node(node) {output(content)}
|
164
172
|
end
|
@@ -171,28 +179,32 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
171
179
|
if !node.has_children || node.children.empty?
|
172
180
|
output(tab_str)
|
173
181
|
for_node(node) {output(node.resolved_value)}
|
174
|
-
|
182
|
+
if node.has_children
|
183
|
+
output("#{' ' unless node.style == :compressed}{}")
|
184
|
+
elsif node.children.empty?
|
185
|
+
output(";")
|
186
|
+
end
|
175
187
|
return
|
176
188
|
end
|
177
189
|
|
178
|
-
@in_directive
|
190
|
+
@in_directive ||= !node.is_a?(Sass::Tree::MediaNode)
|
179
191
|
output(tab_str) if node.style != :compressed
|
180
192
|
for_node(node) {output(node.resolved_value)}
|
181
193
|
output(node.style == :compressed ? "{" : " {")
|
182
194
|
output(node.style == :compact ? ' ' : "\n") if node.style != :compressed
|
183
195
|
|
184
|
-
|
196
|
+
had_children = true
|
185
197
|
first = true
|
186
198
|
node.children.each do |child|
|
187
199
|
next if child.invisible?
|
188
200
|
if node.style == :compact
|
189
201
|
if child.is_a?(Sass::Tree::PropNode)
|
190
|
-
with_tabs(first ||
|
202
|
+
with_tabs(first || !had_children ? 0 : @tabs + 1) do
|
191
203
|
visit(child)
|
192
204
|
output(' ')
|
193
205
|
end
|
194
206
|
else
|
195
|
-
|
207
|
+
unless had_children
|
196
208
|
erase! 1
|
197
209
|
output "\n"
|
198
210
|
end
|
@@ -206,18 +218,23 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
206
218
|
rstrip!
|
207
219
|
output "\n"
|
208
220
|
end
|
209
|
-
|
221
|
+
had_children = child.has_children
|
210
222
|
first = false
|
211
223
|
elsif node.style == :compressed
|
212
|
-
|
224
|
+
unless had_children
|
225
|
+
output(";") unless trailing_semicolon?
|
226
|
+
end
|
213
227
|
with_tabs(0) {visit(child)}
|
214
|
-
|
228
|
+
had_children = child.has_children
|
215
229
|
else
|
216
230
|
with_tabs(@tabs + 1) {visit(child)}
|
217
231
|
output "\n"
|
218
232
|
end
|
219
233
|
end
|
220
234
|
rstrip!
|
235
|
+
if node.style == :compressed && trailing_semicolon?
|
236
|
+
erase! 1
|
237
|
+
end
|
221
238
|
if node.style == :expanded
|
222
239
|
output("\n#{tab_str}")
|
223
240
|
elsif node.style != :compressed
|
@@ -278,10 +295,13 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
278
295
|
|
279
296
|
joined_rules = node.resolved_rules.members.map do |seq|
|
280
297
|
next if seq.has_placeholder?
|
281
|
-
rule_part = seq.to_s
|
298
|
+
rule_part = seq.to_s(:style => node.style)
|
282
299
|
if node.style == :compressed
|
283
300
|
rule_part.gsub!(/([^,])\s*\n\s*/m, '\1 ')
|
284
|
-
rule_part.gsub!(/\s*([
|
301
|
+
rule_part.gsub!(/\s*([+>])\s*/m, '\1')
|
302
|
+
rule_part.gsub!(/nth([^( ]*)\(([^)]*)\)/m) do |match|
|
303
|
+
match.tr(" \t\n", "")
|
304
|
+
end
|
285
305
|
rule_part.strip!
|
286
306
|
end
|
287
307
|
rule_part
|
@@ -306,8 +326,8 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
306
326
|
relative_filename =
|
307
327
|
if node.options[:css_filename]
|
308
328
|
begin
|
309
|
-
Sass::Util.
|
310
|
-
|
329
|
+
Sass::Util.relative_path_from(
|
330
|
+
node.filename, File.dirname(node.options[:css_filename])).to_s
|
311
331
|
rescue ArgumentError
|
312
332
|
nil
|
313
333
|
end
|
@@ -320,7 +340,7 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
320
340
|
end
|
321
341
|
end
|
322
342
|
|
323
|
-
end_props, trailer, tabs
|
343
|
+
end_props, trailer, tabs = '', '', 0
|
324
344
|
if node.style == :compact
|
325
345
|
separator, end_props, bracket = ' ', ' ', ' { '
|
326
346
|
trailer = "\n" if node.group_end
|
@@ -338,10 +358,18 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
338
358
|
|
339
359
|
with_tabs(tabs) do
|
340
360
|
node.children.each_with_index do |child, i|
|
341
|
-
|
361
|
+
if i > 0
|
362
|
+
if separator.start_with?(";") && trailing_semicolon?
|
363
|
+
erase! 1
|
364
|
+
end
|
365
|
+
output(separator)
|
366
|
+
end
|
342
367
|
visit(child)
|
343
368
|
end
|
344
369
|
end
|
370
|
+
if node.style == :compressed && trailing_semicolon?
|
371
|
+
erase! 1
|
372
|
+
end
|
345
373
|
|
346
374
|
output(end_props)
|
347
375
|
output("}" + trailer)
|
@@ -362,10 +390,10 @@ class Sass::Tree::Visitors::ToCss < Sass::Tree::Visitors::Base
|
|
362
390
|
rule = Sass::Tree::RuleNode.new([""])
|
363
391
|
rule.resolved_rules = Sass::Selector::CommaSequence.new(
|
364
392
|
[Sass::Selector::Sequence.new(
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
393
|
+
[Sass::Selector::SimpleSequence.new(
|
394
|
+
[Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)],
|
395
|
+
false)
|
396
|
+
])
|
369
397
|
])
|
370
398
|
prop = Sass::Tree::PropNode.new([""], Sass::Script::Value::String.new(''), :new)
|
371
399
|
prop.resolved_name = "font-family"
|
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'strscan'
|
2
2
|
|
3
3
|
if Sass::Util.ruby1_8?
|
4
|
-
# rubocop:disable ConstantName
|
5
4
|
Sass::Util::MultibyteStringScanner = StringScanner
|
6
|
-
# rubocop:enable ConstantName
|
7
5
|
else
|
8
6
|
if Sass::Util.rbx?
|
9
7
|
# Rubinius's StringScanner class implements some of its methods in terms of
|
data/lib/sass/util/subset_map.rb
CHANGED
data/lib/sass/util.rb
CHANGED
@@ -13,6 +13,8 @@ require 'sass/util/subset_map'
|
|
13
13
|
|
14
14
|
module Sass
|
15
15
|
# A module containing various useful functions.
|
16
|
+
# @comment
|
17
|
+
# rubocop:disable ModuleLength
|
16
18
|
module Util
|
17
19
|
extend self
|
18
20
|
|
@@ -138,6 +140,18 @@ module Sass
|
|
138
140
|
[[value, range.first].max, range.last].min
|
139
141
|
end
|
140
142
|
|
143
|
+
# Like [Fixnum.round], but leaves rooms for slight floating-point
|
144
|
+
# differences.
|
145
|
+
#
|
146
|
+
# @param value [Numeric]
|
147
|
+
# @return [Numeric]
|
148
|
+
def round(value)
|
149
|
+
# If the number is within epsilon of X.5, round up (or down for negative
|
150
|
+
# numbers).
|
151
|
+
return value.round if (value % 1) - 0.5 <= -1 * Script::Value::Number.epsilon
|
152
|
+
value > 0 ? value.ceil : value.floor
|
153
|
+
end
|
154
|
+
|
141
155
|
# Concatenates all strings that are adjacent in an array,
|
142
156
|
# while leaving other elements as they are.
|
143
157
|
#
|
@@ -265,7 +279,7 @@ module Sass
|
|
265
279
|
# # [2, 4, 5]]
|
266
280
|
def paths(arrs)
|
267
281
|
arrs.inject([[]]) do |paths, arr|
|
268
|
-
|
282
|
+
arr.map {|e| paths.map {|path| path + [e]}}.flatten(1)
|
269
283
|
end
|
270
284
|
end
|
271
285
|
|
@@ -298,7 +312,7 @@ module Sass
|
|
298
312
|
# @return [Array]
|
299
313
|
def hash_to_a(hash)
|
300
314
|
return hash.to_a unless ruby1_8? || defined?(Test::Unit)
|
301
|
-
hash.sort_by {|k,
|
315
|
+
hash.sort_by {|k, _v| k}
|
302
316
|
end
|
303
317
|
|
304
318
|
# Performs the equivalent of `enum.group_by.to_a`, but with a guaranteed
|
@@ -325,6 +339,18 @@ module Sass
|
|
325
339
|
arr
|
326
340
|
end
|
327
341
|
|
342
|
+
# Like `String.upcase`, but only ever upcases ASCII letters.
|
343
|
+
def upcase(string)
|
344
|
+
return string.upcase unless ruby2_4?
|
345
|
+
string.upcase(:ascii)
|
346
|
+
end
|
347
|
+
|
348
|
+
# Like `String.downcase`, but only ever downcases ASCII letters.
|
349
|
+
def downcase(string)
|
350
|
+
return string.downcase unless ruby2_4?
|
351
|
+
string.downcase(:ascii)
|
352
|
+
end
|
353
|
+
|
328
354
|
# Returns a sub-array of `minuend` containing only elements that are also in
|
329
355
|
# `subtrahend`. Ensures that the return value has the same order as
|
330
356
|
# `minuend`, even on Rubinius where that's not guaranteed by `Array#-`.
|
@@ -404,13 +430,13 @@ module Sass
|
|
404
430
|
# Returns information about the caller of the previous method.
|
405
431
|
#
|
406
432
|
# @param entry [String] An entry in the `#caller` list, or a similarly formatted string
|
407
|
-
# @return [[String,
|
433
|
+
# @return [[String, Integer, (String, nil)]]
|
408
434
|
# An array containing the filename, line, and method name of the caller.
|
409
435
|
# The method name may be nil
|
410
436
|
def caller_info(entry = nil)
|
411
437
|
# JRuby evaluates `caller` incorrectly when it's in an actual default argument.
|
412
438
|
entry ||= caller[1]
|
413
|
-
info = entry.scan(/^(
|
439
|
+
info = entry.scan(/^((?:[A-Za-z]:)?.*?):(-?.*?)(?::.*`(.+)')?$/).first
|
414
440
|
info[1] = info[1].to_i
|
415
441
|
# This is added by Rubinius to designate a block, but we don't care about it.
|
416
442
|
info[2].sub!(/ \{\}\Z/, '') if info[2]
|
@@ -498,7 +524,7 @@ module Sass
|
|
498
524
|
#
|
499
525
|
# @param msg [String]
|
500
526
|
def sass_warn(msg)
|
501
|
-
msg
|
527
|
+
msg += "\n" unless ruby1?
|
502
528
|
Sass.logger.warn(msg)
|
503
529
|
end
|
504
530
|
|
@@ -557,9 +583,12 @@ module Sass
|
|
557
583
|
#
|
558
584
|
# @return [Boolean]
|
559
585
|
def listen_geq_2?
|
560
|
-
return @listen_geq_2
|
586
|
+
return @listen_geq_2 if defined?(@listen_geq_2)
|
561
587
|
@listen_geq_2 =
|
562
588
|
begin
|
589
|
+
# Make sure we're loading listen/version from the same place that
|
590
|
+
# we're loading listen itself.
|
591
|
+
load_listen!
|
563
592
|
require 'listen/version'
|
564
593
|
version_geq(::Listen::VERSION, '2.0.0')
|
565
594
|
rescue LoadError
|
@@ -619,7 +648,7 @@ module Sass
|
|
619
648
|
|
620
649
|
# Returns an array of ints representing the JRuby version number.
|
621
650
|
#
|
622
|
-
# @return [Array<
|
651
|
+
# @return [Array<Integer>]
|
623
652
|
def jruby_version
|
624
653
|
@jruby_version ||= ::JRUBY_VERSION.split(".").map {|s| s.to_i}
|
625
654
|
end
|
@@ -628,7 +657,7 @@ module Sass
|
|
628
657
|
#
|
629
658
|
# @param path [String]
|
630
659
|
def glob(path)
|
631
|
-
path = path.
|
660
|
+
path = path.tr('\\', '/') if windows?
|
632
661
|
if block_given?
|
633
662
|
Dir.glob(path) {|f| yield(f)}
|
634
663
|
else
|
@@ -661,19 +690,77 @@ module Sass
|
|
661
690
|
pathname(path.cleanpath.to_s)
|
662
691
|
end
|
663
692
|
|
693
|
+
# Returns `path` with all symlinks resolved.
|
694
|
+
#
|
695
|
+
# @param path [String, Pathname]
|
696
|
+
# @return [Pathname]
|
697
|
+
def realpath(path)
|
698
|
+
path = Pathname.new(path) unless path.is_a?(Pathname)
|
699
|
+
|
700
|
+
# Explicitly DON'T run #pathname here. We don't want to convert
|
701
|
+
# to Windows directory separators because we're comparing these
|
702
|
+
# against the paths returned by Listen, which use forward
|
703
|
+
# slashes everywhere.
|
704
|
+
begin
|
705
|
+
path.realpath
|
706
|
+
rescue SystemCallError
|
707
|
+
# If [path] doesn't actually exist, don't bail, just
|
708
|
+
# return the original.
|
709
|
+
path
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
# Returns `path` relative to `from`.
|
714
|
+
#
|
715
|
+
# This is like `Pathname#relative_path_from` except it accepts both strings
|
716
|
+
# and pathnames, it handles Windows path separators correctly, and it throws
|
717
|
+
# an error rather than crashing if the paths use different encodings
|
718
|
+
# (https://github.com/ruby/ruby/pull/713).
|
719
|
+
#
|
720
|
+
# @param path [String, Pathname]
|
721
|
+
# @param from [String, Pathname]
|
722
|
+
# @return [Pathname?]
|
723
|
+
def relative_path_from(path, from)
|
724
|
+
pathname(path.to_s).relative_path_from(pathname(from.to_s))
|
725
|
+
rescue NoMethodError => e
|
726
|
+
raise e unless e.name == :zero?
|
727
|
+
|
728
|
+
# Work around https://github.com/ruby/ruby/pull/713.
|
729
|
+
path = path.to_s
|
730
|
+
from = from.to_s
|
731
|
+
raise ArgumentError("Incompatible path encodings: #{path.inspect} is #{path.encoding}, " +
|
732
|
+
"#{from.inspect} is #{from.encoding}")
|
733
|
+
end
|
734
|
+
|
664
735
|
# Converts `path` to a "file:" URI. This handles Windows paths correctly.
|
665
736
|
#
|
666
737
|
# @param path [String, Pathname]
|
667
738
|
# @return [String]
|
668
739
|
def file_uri_from_path(path)
|
669
740
|
path = path.to_s if path.is_a?(Pathname)
|
741
|
+
path = path.tr('\\', '/') if windows?
|
670
742
|
path = Sass::Util.escape_uri(path)
|
671
743
|
return path.start_with?('/') ? "file://" + path : path unless windows?
|
672
|
-
return "file:///" + path.tr("\\", "/") if path =~
|
673
|
-
return "file
|
744
|
+
return "file:///" + path.tr("\\", "/") if path =~ %r{^[a-zA-Z]:[/\\]}
|
745
|
+
return "file:" + path.tr("\\", "/") if path =~ %r{\\\\[^\\]+\\[^\\/]+}
|
674
746
|
path.tr("\\", "/")
|
675
747
|
end
|
676
748
|
|
749
|
+
# Retries a filesystem operation if it fails on Windows. Windows
|
750
|
+
# has weird and flaky locking rules that can cause operations to fail.
|
751
|
+
#
|
752
|
+
# @yield [] The filesystem operation.
|
753
|
+
def retry_on_windows
|
754
|
+
return yield unless windows?
|
755
|
+
|
756
|
+
begin
|
757
|
+
yield
|
758
|
+
rescue SystemCallError
|
759
|
+
sleep 0.1
|
760
|
+
yield
|
761
|
+
end
|
762
|
+
end
|
763
|
+
|
677
764
|
# Prepare a value for a destructuring assignment (e.g. `a, b =
|
678
765
|
# val`). This works around a performance bug when using
|
679
766
|
# ActiveSupport, and only needs to be called when `val` is likely
|
@@ -711,15 +798,6 @@ module Sass
|
|
711
798
|
(RUBY_VERSION_COMPONENTS[0] == 1 && RUBY_VERSION_COMPONENTS[1] < 9)
|
712
799
|
end
|
713
800
|
|
714
|
-
# Whether or not this is running under Ruby 1.8.6 or lower.
|
715
|
-
# Note that lower versions are not officially supported.
|
716
|
-
#
|
717
|
-
# @return [Boolean]
|
718
|
-
def ruby1_8_6?
|
719
|
-
return @ruby1_8_6 if defined?(@ruby1_8_6)
|
720
|
-
@ruby1_8_6 = ruby1_8? && RUBY_VERSION_COMPONENTS[2] < 7
|
721
|
-
end
|
722
|
-
|
723
801
|
# Whether or not this is running under Ruby 1.9.2 exactly.
|
724
802
|
#
|
725
803
|
# @return [Boolean]
|
@@ -728,6 +806,19 @@ module Sass
|
|
728
806
|
@ruby1_9_2 = RUBY_VERSION_COMPONENTS == [1, 9, 2]
|
729
807
|
end
|
730
808
|
|
809
|
+
# Whether or not this is running under Ruby 2.4 or higher.
|
810
|
+
#
|
811
|
+
# @return [Boolean]
|
812
|
+
def ruby2_4?
|
813
|
+
return @ruby2_4 if defined?(@ruby2_4)
|
814
|
+
@ruby2_4 =
|
815
|
+
if RUBY_VERSION_COMPONENTS[0] == 2
|
816
|
+
RUBY_VERSION_COMPONENTS[1] >= 4
|
817
|
+
else
|
818
|
+
RUBY_VERSION_COMPONENTS[0] > 2
|
819
|
+
end
|
820
|
+
end
|
821
|
+
|
731
822
|
# Wehter or not this is running under JRuby 1.6 or lower.
|
732
823
|
def jruby1_6?
|
733
824
|
return @jruby1_6 if defined?(@jruby1_6)
|
@@ -769,14 +860,15 @@ module Sass
|
|
769
860
|
end
|
770
861
|
|
771
862
|
return Hash[pairs_or_hash] unless ruby1_8?
|
772
|
-
(pairs_or_hash.is_a?(NormalizedMap) ? NormalizedMap : OrderedHash)[*flatten(
|
863
|
+
(pairs_or_hash.is_a?(NormalizedMap) ? NormalizedMap : OrderedHash)[*pairs_or_hash.flatten(1)]
|
773
864
|
end
|
774
865
|
|
775
866
|
unless ruby1_8?
|
776
867
|
CHARSET_REGEXP = /\A@charset "([^"]+)"/
|
777
|
-
|
778
|
-
|
779
|
-
|
868
|
+
bom = "\uFEFF"
|
869
|
+
UTF_8_BOM = bom.encode("UTF-8").force_encoding('BINARY')
|
870
|
+
UTF_16BE_BOM = bom.encode("UTF-16BE").force_encoding('BINARY')
|
871
|
+
UTF_16LE_BOM = bom.encode("UTF-16LE").force_encoding('BINARY')
|
780
872
|
end
|
781
873
|
|
782
874
|
# Like {\#check\_encoding}, but also checks for a `@charset` declaration
|
@@ -874,7 +966,7 @@ module Sass
|
|
874
966
|
# A version of `Enumerable#enum_cons` that works in Ruby 1.8 and 1.9.
|
875
967
|
#
|
876
968
|
# @param enum [Enumerable] The enumerable to get the enumerator for
|
877
|
-
# @param n [
|
969
|
+
# @param n [Integer] The size of each cons
|
878
970
|
# @return [Enumerator] The consed enumerator
|
879
971
|
def enum_cons(enum, n)
|
880
972
|
ruby1_8? ? enum.enum_cons(n) : enum.each_cons(n)
|
@@ -883,7 +975,7 @@ module Sass
|
|
883
975
|
# A version of `Enumerable#enum_slice` that works in Ruby 1.8 and 1.9.
|
884
976
|
#
|
885
977
|
# @param enum [Enumerable] The enumerable to get the enumerator for
|
886
|
-
# @param n [
|
978
|
+
# @param n [Integer] The size of each slice
|
887
979
|
# @return [Enumerator] The consed enumerator
|
888
980
|
def enum_slice(enum, n)
|
889
981
|
ruby1_8? ? enum.enum_slice(n) : enum.each_slice(n)
|
@@ -910,22 +1002,11 @@ module Sass
|
|
910
1002
|
# Returns the ASCII code of the given character.
|
911
1003
|
#
|
912
1004
|
# @param c [String] All characters but the first are ignored.
|
913
|
-
# @return [
|
1005
|
+
# @return [Integer] The ASCII code of `c`.
|
914
1006
|
def ord(c)
|
915
1007
|
ruby1_8? ? c[0] : c.ord
|
916
1008
|
end
|
917
1009
|
|
918
|
-
# Flattens the first `n` nested arrays in a cross-version manner.
|
919
|
-
#
|
920
|
-
# @param arr [Array] The array to flatten
|
921
|
-
# @param n [Fixnum] The number of levels to flatten
|
922
|
-
# @return [Array] The flattened array
|
923
|
-
def flatten(arr, n)
|
924
|
-
return arr.flatten(n) unless ruby1_8_6?
|
925
|
-
return arr if n == 0
|
926
|
-
arr.inject([]) {|res, e| e.is_a?(Array) ? res.concat(flatten(e, n - 1)) : res << e}
|
927
|
-
end
|
928
|
-
|
929
1010
|
# Flattens the first level of nested arrays in `arrs`. Unlike
|
930
1011
|
# `Array#flatten`, this orders the result by taking the first
|
931
1012
|
# values from each array in order, then the second, and so on.
|
@@ -944,27 +1025,6 @@ module Sass
|
|
944
1025
|
result
|
945
1026
|
end
|
946
1027
|
|
947
|
-
# Returns the hash code for a set in a cross-version manner.
|
948
|
-
# Aggravatingly, this is order-dependent in Ruby 1.8.6.
|
949
|
-
#
|
950
|
-
# @param set [Set]
|
951
|
-
# @return [Fixnum] The order-independent hashcode of `set`
|
952
|
-
def set_hash(set)
|
953
|
-
return set.hash unless ruby1_8_6?
|
954
|
-
set.map {|e| e.hash}.uniq.sort.hash
|
955
|
-
end
|
956
|
-
|
957
|
-
# Tests the hash-equality of two sets in a cross-version manner.
|
958
|
-
# Aggravatingly, this is order-dependent in Ruby 1.8.6.
|
959
|
-
#
|
960
|
-
# @param set1 [Set]
|
961
|
-
# @param set2 [Set]
|
962
|
-
# @return [Boolean] Whether or not the sets are hashcode equal
|
963
|
-
def set_eql?(set1, set2)
|
964
|
-
return set1.eql?(set2) unless ruby1_8_6?
|
965
|
-
set1.to_a.uniq.sort_by {|e| e.hash}.eql?(set2.to_a.uniq.sort_by {|e| e.hash})
|
966
|
-
end
|
967
|
-
|
968
1028
|
# Like `Object#inspect`, but preserves non-ASCII characters rather than
|
969
1029
|
# escaping them under Ruby 1.9.2. This is necessary so that the
|
970
1030
|
# precompiled Haml template can be `#encode`d into `@options[:encoding]`
|
@@ -1067,11 +1127,11 @@ module Sass
|
|
1067
1127
|
|
1068
1128
|
# Converts the argument into a valid JSON value.
|
1069
1129
|
#
|
1070
|
-
# @param v [
|
1130
|
+
# @param v [Integer, String, Array, Boolean, nil]
|
1071
1131
|
# @return [String]
|
1072
1132
|
def json_value_of(v)
|
1073
1133
|
case v
|
1074
|
-
when
|
1134
|
+
when Integer
|
1075
1135
|
v.to_s
|
1076
1136
|
when String
|
1077
1137
|
"\"" + json_escape_string(v) + "\""
|
@@ -1093,7 +1153,7 @@ module Sass
|
|
1093
1153
|
VLQ_BASE_MASK = VLQ_BASE - 1
|
1094
1154
|
VLQ_CONTINUATION_BIT = VLQ_BASE
|
1095
1155
|
|
1096
|
-
BASE64_DIGITS = ('A'..'Z').to_a
|
1156
|
+
BASE64_DIGITS = ('A'..'Z').to_a + ('a'..'z').to_a + ('0'..'9').to_a + ['+', '/']
|
1097
1157
|
BASE64_DIGIT_MAP = begin
|
1098
1158
|
map = {}
|
1099
1159
|
Sass::Util.enum_with_index(BASE64_DIGITS).map do |digit, i|
|
@@ -1104,7 +1164,7 @@ module Sass
|
|
1104
1164
|
|
1105
1165
|
# Encodes `value` as VLQ (http://en.wikipedia.org/wiki/VLQ).
|
1106
1166
|
#
|
1107
|
-
# @param value [
|
1167
|
+
# @param value [Integer]
|
1108
1168
|
# @return [String] The encoded value
|
1109
1169
|
def encode_vlq(value)
|
1110
1170
|
if value < 0
|
@@ -1223,7 +1283,7 @@ module Sass
|
|
1223
1283
|
require 'listen'
|
1224
1284
|
rescue LoadError => e
|
1225
1285
|
if version_geq(RUBY_VERSION, "1.9.3")
|
1226
|
-
version_constraint = "~>
|
1286
|
+
version_constraint = "~> 3.0"
|
1227
1287
|
else
|
1228
1288
|
version_constraint = "~> 1.1"
|
1229
1289
|
end
|
@@ -1272,13 +1332,10 @@ module Sass
|
|
1272
1332
|
return str, str.encoding
|
1273
1333
|
end
|
1274
1334
|
|
1275
|
-
# rubocop:disable LineLength
|
1276
|
-
|
1277
1335
|
# Calculates the memoization table for the Least Common Subsequence algorithm.
|
1278
1336
|
# Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Computing_the_length_of_the_LCS)
|
1279
1337
|
def lcs_table(x, y)
|
1280
1338
|
# This method does not take a block as an explicit parameter for performance reasons.
|
1281
|
-
# rubocop:enable LineLength
|
1282
1339
|
c = Array.new(x.size) {[]}
|
1283
1340
|
x.size.times {|i| c[i][0] = 0}
|
1284
1341
|
y.size.times {|j| c[0][j] = 0}
|
@@ -1294,12 +1351,12 @@ module Sass
|
|
1294
1351
|
end
|
1295
1352
|
c
|
1296
1353
|
end
|
1297
|
-
# rubocop:disable ParameterLists
|
1354
|
+
# rubocop:disable ParameterLists
|
1298
1355
|
|
1299
1356
|
# Computes a single longest common subsequence for arrays x and y.
|
1300
1357
|
# Algorithm from [Wikipedia](http://en.wikipedia.org/wiki/Longest_common_subsequence_problem#Reading_out_an_LCS)
|
1301
1358
|
def lcs_backtrace(c, x, y, i, j, &block)
|
1302
|
-
# rubocop:enable ParameterList
|
1359
|
+
# rubocop:enable ParameterList
|
1303
1360
|
return [] if i == 0 || j == 0
|
1304
1361
|
if (v = yield(x[i], y[j]))
|
1305
1362
|
return lcs_backtrace(c, x, y, i - 1, j - 1, &block) << v
|
data/lib/sass/version.rb
CHANGED
@@ -8,7 +8,7 @@ module Sass
|
|
8
8
|
# if it was installed from Git.
|
9
9
|
module Version
|
10
10
|
# Returns a hash representing the version of Sass.
|
11
|
-
# The `:major`, `:minor`, and `:teeny` keys have their respective numbers as
|
11
|
+
# The `:major`, `:minor`, and `:teeny` keys have their respective numbers as Integers.
|
12
12
|
# The `:name` key has the name of the version.
|
13
13
|
# The `:string` key contains a human-readable string representation of the version.
|
14
14
|
# The `:number` key is the major, minor, and teeny keys separated by periods.
|
@@ -41,7 +41,7 @@ module Sass
|
|
41
41
|
# :prerelease_number => 1
|
42
42
|
# }
|
43
43
|
#
|
44
|
-
# @return [{Symbol => String/
|
44
|
+
# @return [{Symbol => String/Integer}] The version hash
|
45
45
|
# @comment
|
46
46
|
# rubocop:disable ClassVars
|
47
47
|
def version
|
data/lib/sass.rb
CHANGED
@@ -47,7 +47,7 @@ module Sass
|
|
47
47
|
#
|
48
48
|
# @param contents [String] The contents of the Sass file.
|
49
49
|
# @param options [{Symbol => Object}] An options hash;
|
50
|
-
# see {file:SASS_REFERENCE.md#
|
50
|
+
# see {file:SASS_REFERENCE.md#Options the Sass options documentation}
|
51
51
|
# @raise [Sass::SyntaxError] if there's an error in the document
|
52
52
|
# @raise [Encoding::UndefinedConversionError] if the source encoding
|
53
53
|
# cannot be converted to UTF-8
|
@@ -69,7 +69,7 @@ module Sass
|
|
69
69
|
#
|
70
70
|
# @param filename [String] The path to the Sass, SCSS, or CSS file on disk.
|
71
71
|
# @param options [{Symbol => Object}] An options hash;
|
72
|
-
# see {file:SASS_REFERENCE.md#
|
72
|
+
# see {file:SASS_REFERENCE.md#Options the Sass options documentation}
|
73
73
|
# @return [String] The compiled CSS.
|
74
74
|
#
|
75
75
|
# @overload compile_file(filename, css_filename, options = {})
|
@@ -77,7 +77,7 @@ module Sass
|
|
77
77
|
#
|
78
78
|
# @param filename [String] The path to the Sass, SCSS, or CSS file on disk.
|
79
79
|
# @param options [{Symbol => Object}] An options hash;
|
80
|
-
# see {file:SASS_REFERENCE.md#
|
80
|
+
# see {file:SASS_REFERENCE.md#Options the Sass options documentation}
|
81
81
|
# @param css_filename [String] The location to which to write the compiled CSS.
|
82
82
|
def self.compile_file(filename, *args)
|
83
83
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
@@ -100,3 +100,10 @@ require 'sass/engine'
|
|
100
100
|
require 'sass/plugin' if defined?(Merb::Plugins)
|
101
101
|
require 'sass/railtie'
|
102
102
|
require 'sass/features'
|
103
|
+
|
104
|
+
if Sass::Util.ruby1?
|
105
|
+
Sass::Util.sass_warn(
|
106
|
+
"DEPRECATION WARNING:\n" +
|
107
|
+
"Sass 3.5 will no longer support Ruby #{RUBY_VERSION}.\n" +
|
108
|
+
"Please upgrade to Ruby 2.0.0 or greater as soon as possible.\n")
|
109
|
+
end
|