sass 3.4.0 → 3.4.25
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/.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
|