sass 3.3.0 → 3.4.0
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/MIT-LICENSE +1 -1
- data/README.md +58 -50
- data/Rakefile +1 -4
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/lib/sass/cache_stores/filesystem.rb +6 -2
- data/lib/sass/css.rb +1 -3
- data/lib/sass/engine.rb +37 -46
- data/lib/sass/environment.rb +13 -17
- data/lib/sass/error.rb +6 -9
- data/lib/sass/exec/base.rb +187 -0
- data/lib/sass/exec/sass_convert.rb +264 -0
- data/lib/sass/exec/sass_scss.rb +424 -0
- data/lib/sass/exec.rb +5 -771
- data/lib/sass/features.rb +7 -0
- data/lib/sass/importers/base.rb +7 -2
- data/lib/sass/importers/filesystem.rb +9 -25
- data/lib/sass/importers.rb +0 -1
- data/lib/sass/media.rb +1 -4
- data/lib/sass/plugin/compiler.rb +200 -83
- data/lib/sass/plugin/staleness_checker.rb +1 -1
- data/lib/sass/plugin.rb +3 -3
- data/lib/sass/script/css_lexer.rb +1 -1
- data/lib/sass/script/functions.rb +622 -268
- data/lib/sass/script/lexer.rb +99 -34
- data/lib/sass/script/parser.rb +24 -23
- data/lib/sass/script/tree/funcall.rb +1 -1
- data/lib/sass/script/tree/interpolation.rb +20 -2
- data/lib/sass/script/tree/selector.rb +26 -0
- data/lib/sass/script/tree/string_interpolation.rb +1 -1
- data/lib/sass/script/tree.rb +1 -0
- data/lib/sass/script/value/base.rb +7 -5
- data/lib/sass/script/value/bool.rb +0 -5
- data/lib/sass/script/value/color.rb +39 -21
- data/lib/sass/script/value/helpers.rb +107 -0
- data/lib/sass/script/value/list.rb +0 -15
- data/lib/sass/script/value/null.rb +0 -5
- data/lib/sass/script/value/number.rb +62 -14
- data/lib/sass/script/value/string.rb +59 -11
- data/lib/sass/script/value.rb +0 -1
- data/lib/sass/scss/css_parser.rb +8 -2
- data/lib/sass/scss/parser.rb +190 -328
- data/lib/sass/scss/rx.rb +15 -6
- data/lib/sass/scss/static_parser.rb +298 -1
- data/lib/sass/selector/abstract_sequence.rb +28 -13
- data/lib/sass/selector/comma_sequence.rb +92 -13
- data/lib/sass/selector/pseudo.rb +256 -0
- data/lib/sass/selector/sequence.rb +94 -24
- data/lib/sass/selector/simple.rb +14 -25
- data/lib/sass/selector/simple_sequence.rb +97 -33
- data/lib/sass/selector.rb +57 -194
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/source/map.rb +26 -12
- data/lib/sass/stack.rb +0 -6
- data/lib/sass/supports.rb +2 -3
- data/lib/sass/tree/at_root_node.rb +1 -0
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/directive_node.rb +8 -2
- data/lib/sass/tree/error_node.rb +18 -0
- data/lib/sass/tree/extend_node.rb +1 -1
- data/lib/sass/tree/function_node.rb +4 -0
- data/lib/sass/tree/keyframe_rule_node.rb +15 -0
- data/lib/sass/tree/prop_node.rb +1 -1
- data/lib/sass/tree/rule_node.rb +12 -7
- data/lib/sass/tree/visitors/check_nesting.rb +38 -10
- data/lib/sass/tree/visitors/convert.rb +16 -18
- data/lib/sass/tree/visitors/cssize.rb +29 -29
- data/lib/sass/tree/visitors/deep_copy.rb +5 -0
- data/lib/sass/tree/visitors/perform.rb +45 -33
- data/lib/sass/tree/visitors/set_options.rb +14 -0
- data/lib/sass/tree/visitors/to_css.rb +15 -14
- data/lib/sass/util/subset_map.rb +1 -1
- data/lib/sass/util.rb +222 -99
- data/lib/sass/version.rb +5 -5
- data/lib/sass.rb +0 -5
- data/test/sass/cache_test.rb +62 -20
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/compiler_test.rb +19 -10
- data/test/sass/conversion_test.rb +58 -1
- data/test/sass/css2sass_test.rb +23 -4
- data/test/sass/encoding_test.rb +219 -0
- data/test/sass/engine_test.rb +136 -199
- data/test/sass/exec_test.rb +2 -2
- data/test/sass/extend_test.rb +236 -19
- data/test/sass/functions_test.rb +295 -253
- data/test/sass/importer_test.rb +31 -21
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/plugin_test.rb +14 -13
- data/test/sass/results/compact.css +1 -1
- data/test/sass/results/complex.css +4 -4
- data/test/sass/results/expanded.css +1 -1
- data/test/sass/results/import.css +1 -1
- data/test/sass/results/import_charset_ibm866.css +2 -2
- data/test/sass/results/mixins.css +17 -17
- data/test/sass/results/nested.css +1 -1
- data/test/sass/results/parent_ref.css +2 -2
- data/test/sass/results/script.css +3 -3
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +10 -7
- data/test/sass/script_test.rb +288 -74
- data/test/sass/scss/css_test.rb +141 -24
- data/test/sass/scss/rx_test.rb +4 -4
- data/test/sass/scss/scss_test.rb +457 -18
- data/test/sass/source_map_test.rb +115 -25
- data/test/sass/superselector_test.rb +191 -0
- data/test/sass/templates/scss_import.scss +2 -1
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
- data/test/sass/util/normalized_map_test.rb +1 -1
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +31 -1
- data/test/sass/value_helpers_test.rb +5 -7
- data/test/test_helper.rb +2 -2
- data/vendor/listen/CHANGELOG.md +1 -228
- data/vendor/listen/Gemfile +5 -15
- data/vendor/listen/README.md +111 -77
- data/vendor/listen/Rakefile +0 -42
- data/vendor/listen/lib/listen/adapter.rb +195 -82
- data/vendor/listen/lib/listen/adapters/bsd.rb +27 -64
- data/vendor/listen/lib/listen/adapters/darwin.rb +21 -58
- data/vendor/listen/lib/listen/adapters/linux.rb +23 -55
- data/vendor/listen/lib/listen/adapters/polling.rb +25 -34
- data/vendor/listen/lib/listen/adapters/windows.rb +50 -46
- data/vendor/listen/lib/listen/directory_record.rb +96 -61
- data/vendor/listen/lib/listen/listener.rb +135 -37
- data/vendor/listen/lib/listen/turnstile.rb +9 -5
- data/vendor/listen/lib/listen/version.rb +1 -1
- data/vendor/listen/lib/listen.rb +33 -19
- data/vendor/listen/listen.gemspec +6 -0
- data/vendor/listen/spec/listen/adapter_spec.rb +43 -77
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +8 -8
- data/vendor/listen/spec/listen/directory_record_spec.rb +81 -56
- data/vendor/listen/spec/listen/listener_spec.rb +128 -39
- data/vendor/listen/spec/listen_spec.rb +15 -21
- data/vendor/listen/spec/spec_helper.rb +4 -0
- data/vendor/listen/spec/support/adapter_helper.rb +52 -15
- data/vendor/listen/spec/support/directory_record_helper.rb +7 -5
- data/vendor/listen/spec/support/listeners_helper.rb +30 -7
- metadata +25 -22
- data/ext/mkrf_conf.rb +0 -27
- data/lib/sass/importers/deprecated_path.rb +0 -51
- data/lib/sass/script/value/deprecated_false.rb +0 -55
- data/vendor/listen/lib/listen/dependency_manager.rb +0 -126
- data/vendor/listen/lib/listen/multi_listener.rb +0 -143
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +0 -107
- data/vendor/listen/spec/listen/multi_listener_spec.rb +0 -174
data/lib/sass/script/lexer.rb
CHANGED
@@ -82,6 +82,8 @@ module Sass
|
|
82
82
|
# with identifier names.
|
83
83
|
IDENT_OP_NAMES = OP_NAMES.select {|k, v| k =~ /^\w+/}
|
84
84
|
|
85
|
+
PARSEABLE_NUMBER = /(?:(\d*\.\d+)|(\d+))(?:[eE]([+-]?\d+))?(#{UNIT})?/
|
86
|
+
|
85
87
|
# A hash of regular expressions that are used for tokenizing.
|
86
88
|
REGULAR_EXPRESSIONS = {
|
87
89
|
:whitespace => /\s+/,
|
@@ -89,9 +91,11 @@ module Sass
|
|
89
91
|
:single_line_comment => SINGLE_LINE_COMMENT,
|
90
92
|
:variable => /(\$)(#{IDENT})/,
|
91
93
|
:ident => /(#{IDENT})(\()?/,
|
92
|
-
:number =>
|
93
|
-
:unary_minus_number =>
|
94
|
+
:number => PARSEABLE_NUMBER,
|
95
|
+
:unary_minus_number => /-#{PARSEABLE_NUMBER}/,
|
94
96
|
:color => HEXCOLOR,
|
97
|
+
:id => /##{IDENT}/,
|
98
|
+
:selector => /&/,
|
95
99
|
:ident_op => /(#{Regexp.union(*IDENT_OP_NAMES.map do |s|
|
96
100
|
Regexp.new(Regexp.escape(s) + "(?!#{NMCHAR}|\Z)")
|
97
101
|
end)})/,
|
@@ -102,7 +106,7 @@ module Sass
|
|
102
106
|
private
|
103
107
|
|
104
108
|
def string_re(open, close)
|
105
|
-
/#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/
|
109
|
+
/#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/m
|
106
110
|
end
|
107
111
|
end
|
108
112
|
|
@@ -246,13 +250,19 @@ module Sass
|
|
246
250
|
end
|
247
251
|
|
248
252
|
def token
|
249
|
-
if after_interpolation? && (
|
250
|
-
|
253
|
+
if after_interpolation? && (interp = @interpolation_stack.pop)
|
254
|
+
interp_type, interp_value = interp
|
255
|
+
if interp_type == :special_fun
|
256
|
+
return special_fun_body(interp_value)
|
257
|
+
else
|
258
|
+
raise "[BUG]: Unknown interp_type #{interp_type}" unless interp_type == :string
|
259
|
+
return string(interp_value, true)
|
260
|
+
end
|
251
261
|
end
|
252
262
|
|
253
|
-
variable || string(:double, false) || string(:single, false) || number || color ||
|
254
|
-
string(:uri, false) || raw(UNICODERANGE) || special_fun || special_val ||
|
255
|
-
ident || op
|
263
|
+
variable || string(:double, false) || string(:single, false) || number || id || color ||
|
264
|
+
selector || string(:uri, false) || raw(UNICODERANGE) || special_fun || special_val ||
|
265
|
+
ident_op || ident || op
|
256
266
|
end
|
257
267
|
|
258
268
|
def variable
|
@@ -271,18 +281,28 @@ module Sass
|
|
271
281
|
end
|
272
282
|
|
273
283
|
def string(re, open)
|
284
|
+
line, offset = @line, @offset
|
274
285
|
return unless scan(STRING_REGULAR_EXPRESSIONS[re][open])
|
286
|
+
if @scanner[0] =~ /([^\\]|^)\n/
|
287
|
+
filename = @options[:filename]
|
288
|
+
Sass::Util.sass_warn <<MESSAGE
|
289
|
+
DEPRECATION WARNING on line #{line}, column #{offset}#{" of #{filename}" if filename}:
|
290
|
+
Unescaped multiline strings are deprecated and will be removed in a future version of Sass.
|
291
|
+
To include a newline in a string, use "\\a" or "\\a " as in CSS.
|
292
|
+
MESSAGE
|
293
|
+
end
|
294
|
+
|
275
295
|
if @scanner[2] == '#{' # '
|
276
296
|
@scanner.pos -= 2 # Don't actually consume the #{
|
277
297
|
@offset -= 2
|
278
|
-
@interpolation_stack << re
|
298
|
+
@interpolation_stack << [:string, re]
|
279
299
|
end
|
280
300
|
str =
|
281
301
|
if re == :uri
|
282
302
|
url = "#{'url(' unless open}#{@scanner[1]}#{')' unless @scanner[2] == '#{'}"
|
283
303
|
Script::Value::String.new(url)
|
284
304
|
else
|
285
|
-
Script::Value::String.new(@scanner[1]
|
305
|
+
Script::Value::String.new(Sass::Script::Value::String.value(@scanner[1]), :string)
|
286
306
|
end
|
287
307
|
[:string, str]
|
288
308
|
end
|
@@ -296,10 +316,12 @@ module Sass
|
|
296
316
|
# minus logic in the parser instead.
|
297
317
|
if @scanner.peek(1) == '-'
|
298
318
|
return if @scanner.pos == 0
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
319
|
+
unary_minus_allowed =
|
320
|
+
case @scanner.string[@scanner.pos - 1, 1]
|
321
|
+
when /\s/; true
|
322
|
+
when '/'; @scanner.pos != 1 && @scanner.string[@scanner.pos - 2, 1] == '*'
|
323
|
+
else; false
|
324
|
+
end
|
303
325
|
|
304
326
|
return unless unary_minus_allowed
|
305
327
|
return unless scan(REGULAR_EXPRESSIONS[:unary_minus_number])
|
@@ -310,33 +332,76 @@ module Sass
|
|
310
332
|
end
|
311
333
|
|
312
334
|
value = (@scanner[1] ? @scanner[1].to_f : @scanner[2].to_i) * (minus ? -1 : 1)
|
313
|
-
|
335
|
+
value *= 10**@scanner[3].to_i if @scanner[3]
|
336
|
+
script_number = Script::Value::Number.new(value, Array(@scanner[4]))
|
314
337
|
[:number, script_number]
|
315
338
|
end
|
316
339
|
|
340
|
+
def id
|
341
|
+
# Colors and ids are tough to tell apart, because they overlap but
|
342
|
+
# neither is a superset of the other. "#xyz" is an id but not a color,
|
343
|
+
# "#000" is a color but not an id, "#abc" is both, and "#0" is neither.
|
344
|
+
# We need to handle all these cases correctly.
|
345
|
+
#
|
346
|
+
# To do so, we first try to parse something as an id. If this works and
|
347
|
+
# the id is also a valid color, we return the color. Otherwise, we
|
348
|
+
# return the id. If it didn't parse as an id, we then try to parse it as
|
349
|
+
# a color. If *this* works, we return the color, and if it doesn't we
|
350
|
+
# give up and throw an error.
|
351
|
+
#
|
352
|
+
# IDs in properties are used in the Basic User Interface Module
|
353
|
+
# (http://www.w3.org/TR/css3-ui/).
|
354
|
+
return unless scan(REGULAR_EXPRESSIONS[:id])
|
355
|
+
if @scanner[0] =~ /^\#[0-9a-fA-F]+$/ && (@scanner[0].length == 4 || @scanner[0].length == 7)
|
356
|
+
return [:color, Script::Value::Color.from_hex(@scanner[0])]
|
357
|
+
end
|
358
|
+
[:ident, @scanner[0]]
|
359
|
+
end
|
360
|
+
|
317
361
|
def color
|
318
|
-
|
319
|
-
return unless
|
320
|
-
|
321
|
-
Colors must have either three or six digits: '#{s}'
|
322
|
-
MESSAGE
|
323
|
-
script_color = Script::Value::Color.from_hex(s)
|
362
|
+
return unless @scanner.match?(REGULAR_EXPRESSIONS[:color])
|
363
|
+
return unless @scanner[0].length == 4 || @scanner[0].length == 7
|
364
|
+
script_color = Script::Value::Color.from_hex(scan(REGULAR_EXPRESSIONS[:color]))
|
324
365
|
[:color, script_color]
|
325
366
|
end
|
326
367
|
|
368
|
+
def selector
|
369
|
+
start_pos = source_position
|
370
|
+
return unless scan(REGULAR_EXPRESSIONS[:selector])
|
371
|
+
script_selector = Script::Tree::Selector.new
|
372
|
+
script_selector.source_range = range(start_pos)
|
373
|
+
[:selector, script_selector]
|
374
|
+
end
|
375
|
+
|
327
376
|
def special_fun
|
328
|
-
|
329
|
-
return unless
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
377
|
+
prefix = scan(/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
|
378
|
+
return unless prefix
|
379
|
+
special_fun_body(1, prefix)
|
380
|
+
end
|
381
|
+
|
382
|
+
def special_fun_body(parens, prefix = nil)
|
383
|
+
str = prefix || ''
|
384
|
+
while (scanned = scan(/.*?([()]|\#\{)/m))
|
385
|
+
str << scanned
|
386
|
+
if scanned[-1] == ?(
|
387
|
+
parens += 1
|
388
|
+
next
|
389
|
+
elsif scanned[-1] == ?)
|
390
|
+
parens -= 1
|
391
|
+
next unless parens == 0
|
392
|
+
else
|
393
|
+
raise "[BUG] Unreachable" unless @scanner[1] == '#{' # '
|
394
|
+
str.slice!(-2..-1)
|
395
|
+
@scanner.pos -= 2 # Don't actually consume the #{
|
396
|
+
@offset -= 2
|
397
|
+
@interpolation_stack << [:special_fun, parens]
|
398
|
+
end
|
399
|
+
|
400
|
+
return [:special_fun, Sass::Script::Value::String.new(str)]
|
401
|
+
end
|
402
|
+
|
403
|
+
scan(/.*/)
|
404
|
+
expected!('")"')
|
340
405
|
end
|
341
406
|
|
342
407
|
def special_val
|
@@ -368,7 +433,7 @@ MESSAGE
|
|
368
433
|
return unless str
|
369
434
|
c = str.count("\n")
|
370
435
|
@line += c
|
371
|
-
@offset = (c == 0 ? @offset + str.size : str.size - str.rindex("\n")
|
436
|
+
@offset = (c == 0 ? @offset + str.size : str.size - str.rindex("\n"))
|
372
437
|
str
|
373
438
|
end
|
374
439
|
|
data/lib/sass/script/parser.rb
CHANGED
@@ -36,13 +36,19 @@ module Sass
|
|
36
36
|
# which signals the end of an interpolated segment,
|
37
37
|
# it returns rather than throwing an error.
|
38
38
|
#
|
39
|
+
# @param warn_for_color [Boolean] Whether raw color values passed to
|
40
|
+
# interoplation should cause a warning.
|
39
41
|
# @return [Script::Tree::Node] The root node of the parse tree
|
40
42
|
# @raise [Sass::SyntaxError] if the expression isn't valid SassScript
|
41
|
-
def parse_interpolated
|
43
|
+
def parse_interpolated(warn_for_color = false)
|
44
|
+
# Start two characters back to compensate for #{
|
45
|
+
start_pos = Sass::Source::Position.new(line, offset - 2)
|
42
46
|
expr = assert_expr :expr
|
43
47
|
assert_tok :end_interpolation
|
48
|
+
expr = Sass::Script::Tree::Interpolation.new(
|
49
|
+
nil, expr, nil, !:wb, !:wa, !:originally_text, warn_for_color)
|
44
50
|
expr.options = @options
|
45
|
-
expr
|
51
|
+
node(expr, start_pos)
|
46
52
|
rescue Sass::SyntaxError => e
|
47
53
|
e.modify_backtrace :line => @lexer.line, :filename => @options[:filename]
|
48
54
|
raise e
|
@@ -226,8 +232,8 @@ module Sass
|
|
226
232
|
return other_interp
|
227
233
|
end
|
228
234
|
|
229
|
-
|
230
|
-
|
235
|
+
e = node(Tree::Operation.new(e, assert_expr(#{sub.inspect}), tok.type),
|
236
|
+
e.source_range.start_pos)
|
231
237
|
end
|
232
238
|
e
|
233
239
|
end
|
@@ -340,7 +346,8 @@ RUBY
|
|
340
346
|
e = first
|
341
347
|
while (interp = try_tok(:begin_interpolation))
|
342
348
|
wb = @lexer.whitespace?(interp)
|
343
|
-
mid =
|
349
|
+
mid = assert_expr :expr
|
350
|
+
assert_tok :end_interpolation
|
344
351
|
wa = @lexer.whitespace?
|
345
352
|
e = node(
|
346
353
|
Script::Tree::Interpolation.new(e, mid, space, wb, wa),
|
@@ -382,7 +389,7 @@ RUBY
|
|
382
389
|
|
383
390
|
name = @lexer.next
|
384
391
|
if (color = Sass::Script::Value::Color::COLOR_NAMES[name.value.downcase])
|
385
|
-
literal_node(Sass::Script::Value::Color.new(color), name.source_range)
|
392
|
+
literal_node(Sass::Script::Value::Color.new(color, name.value), name.source_range)
|
386
393
|
elsif name.value == "true"
|
387
394
|
literal_node(Sass::Script::Value::Bool.new(true), name.source_range)
|
388
395
|
elsif name.value == "false"
|
@@ -487,22 +494,14 @@ RUBY
|
|
487
494
|
end
|
488
495
|
|
489
496
|
def special_fun
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
node(
|
499
|
-
Script::Tree::Interpolation.new(
|
500
|
-
l, i,
|
501
|
-
r && literal_node(Script::Value::String.new(r),
|
502
|
-
i.source_range.end_pos, end_pos),
|
503
|
-
false, false),
|
504
|
-
start_pos, end_pos)
|
505
|
-
end
|
497
|
+
first = try_tok(:special_fun)
|
498
|
+
return paren unless first
|
499
|
+
str = literal_node(first.value, first.source_range)
|
500
|
+
return str unless try_tok(:begin_interpolation)
|
501
|
+
mid = parse_interpolated
|
502
|
+
last = assert_expr(:special_fun)
|
503
|
+
node(Tree::Interpolation.new(str, mid, last, false, false),
|
504
|
+
first.source_range.start_pos)
|
506
505
|
end
|
507
506
|
|
508
507
|
def paren
|
@@ -530,7 +529,8 @@ RUBY
|
|
530
529
|
return number unless first
|
531
530
|
str = literal_node(first.value, first.source_range)
|
532
531
|
return str unless try_tok(:begin_interpolation)
|
533
|
-
mid =
|
532
|
+
mid = assert_expr :expr
|
533
|
+
assert_tok :end_interpolation
|
534
534
|
last = assert_expr(:string)
|
535
535
|
node(Tree::StringInterpolation.new(str, mid, last), first.source_range.start_pos)
|
536
536
|
end
|
@@ -563,6 +563,7 @@ RUBY
|
|
563
563
|
:mixin_arglist => "mixin argument",
|
564
564
|
:fn_arglist => "function argument",
|
565
565
|
:splat => "...",
|
566
|
+
:special_fun => '")"',
|
566
567
|
}
|
567
568
|
|
568
569
|
def assert_expr(name, expected = nil)
|
@@ -214,7 +214,7 @@ module Sass::Script::Tree
|
|
214
214
|
elsif deprecated_argname && keywords.has_key?(deprecated_argname)
|
215
215
|
deprecated_argname = keywords.denormalize(deprecated_argname)
|
216
216
|
Sass::Util.sass_warn("DEPRECATION WARNING: The `$#{deprecated_argname}' argument for " +
|
217
|
-
"`#{name}()' has been renamed to `$#{argname}'.")
|
217
|
+
"`#{@name}()' has been renamed to `$#{argname}'.")
|
218
218
|
keywords.delete(deprecated_argname)
|
219
219
|
else
|
220
220
|
raise Sass::SyntaxError.new("Function #{name} requires an argument named $#{argname}")
|
@@ -23,6 +23,10 @@ module Sass::Script::Tree
|
|
23
23
|
# SassScript.
|
24
24
|
attr_reader :originally_text
|
25
25
|
|
26
|
+
# @return [Boolean] Whether a color value passed to the interpolation should
|
27
|
+
# generate a warning.
|
28
|
+
attr_reader :warn_for_color
|
29
|
+
|
26
30
|
# Interpolation in a property is of the form `before #{mid} after`.
|
27
31
|
#
|
28
32
|
# @param before [Node] See {Interpolation#before}
|
@@ -31,9 +35,10 @@ module Sass::Script::Tree
|
|
31
35
|
# @param wb [Boolean] See {Interpolation#whitespace_before}
|
32
36
|
# @param wa [Boolean] See {Interpolation#whitespace_after}
|
33
37
|
# @param originally_text [Boolean] See {Interpolation#originally_text}
|
38
|
+
# @param warn_for_color [Boolean] See {Interpolation#warn_for_color}
|
34
39
|
# @comment
|
35
40
|
# rubocop:disable ParameterLists
|
36
|
-
def initialize(before, mid, after, wb, wa, originally_text = false)
|
41
|
+
def initialize(before, mid, after, wb, wa, originally_text = false, warn_for_color = false)
|
37
42
|
# rubocop:enable ParameterLists
|
38
43
|
@before = before
|
39
44
|
@mid = mid
|
@@ -41,6 +46,7 @@ module Sass::Script::Tree
|
|
41
46
|
@whitespace_before = wb
|
42
47
|
@whitespace_after = wa
|
43
48
|
@originally_text = originally_text
|
49
|
+
@warn_for_color = warn_for_color
|
44
50
|
end
|
45
51
|
|
46
52
|
# @return [String] A human-readable s-expression representation of the interpolation
|
@@ -90,8 +96,20 @@ module Sass::Script::Tree
|
|
90
96
|
res = ""
|
91
97
|
res << @before.perform(environment).to_s if @before
|
92
98
|
res << " " if @before && @whitespace_before
|
99
|
+
|
93
100
|
val = @mid.perform(environment)
|
94
|
-
|
101
|
+
if @warn_for_color && val.is_a?(Sass::Script::Value::Color) && val.name
|
102
|
+
alternative = Operation.new(Sass::Script::Value::String.new("", :string), @mid, :plus)
|
103
|
+
Sass::Util.sass_warn <<MESSAGE
|
104
|
+
WARNING on line #{line}, column #{source_range.start_pos.offset}#{" of #{filename}" if filename}:
|
105
|
+
You probably don't mean to use the color value `#{val}' in interpolation here.
|
106
|
+
It may end up represented as #{val.inspect}, which will likely produce invalid CSS.
|
107
|
+
Always quote color names when using them as strings (for example, "#{val}").
|
108
|
+
If you really want to use the color value here, use `#{alternative.to_sass}'.
|
109
|
+
MESSAGE
|
110
|
+
end
|
111
|
+
|
112
|
+
res << val.to_s(:quote => :none)
|
95
113
|
res << " " if @after && @whitespace_after
|
96
114
|
res << @after.perform(environment).to_s if @after
|
97
115
|
opts(Sass::Script::Value::String.new(res))
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Sass::Script::Tree
|
2
|
+
# A SassScript node that will resolve to the current selector.
|
3
|
+
class Selector < Node
|
4
|
+
def initialize; end
|
5
|
+
|
6
|
+
def children
|
7
|
+
[]
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_sass(opts = {})
|
11
|
+
'&'
|
12
|
+
end
|
13
|
+
|
14
|
+
def deep_copy
|
15
|
+
dup
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def _perform(environment)
|
21
|
+
selector = environment.selector
|
22
|
+
return opts(Sass::Script::Value::Null.new) unless selector
|
23
|
+
opts(selector.to_sass_script)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -81,7 +81,7 @@ module Sass::Script::Tree
|
|
81
81
|
before = @before.perform(environment)
|
82
82
|
res << before.value
|
83
83
|
mid = @mid.perform(environment)
|
84
|
-
res << (mid.is_a?(Sass::Script::Value::String) ? mid.value : mid.to_s)
|
84
|
+
res << (mid.is_a?(Sass::Script::Value::String) ? mid.value : mid.to_s(:quote => :none))
|
85
85
|
res << @after.perform(environment).value
|
86
86
|
opts(Sass::Script::Value::String.new(res, before.type))
|
87
87
|
end
|
data/lib/sass/script/tree.rb
CHANGED
@@ -20,7 +20,8 @@ module Sass::Script::Value
|
|
20
20
|
#
|
21
21
|
# @param value [Object] The object for \{#value}
|
22
22
|
def initialize(value = nil)
|
23
|
-
|
23
|
+
value.freeze unless value.nil? || value == true || value == false
|
24
|
+
@value = value
|
24
25
|
end
|
25
26
|
|
26
27
|
# Sets the options hash for this node,
|
@@ -95,10 +96,8 @@ MSG
|
|
95
96
|
# @return [Script::Value::String] A string containing both values
|
96
97
|
# without any separation
|
97
98
|
def plus(other)
|
98
|
-
|
99
|
-
|
100
|
-
end
|
101
|
-
Sass::Script::Value::String.new(to_s + other.to_s)
|
99
|
+
type = other.is_a?(Sass::Script::Value::String) ? other.type : :identifier
|
100
|
+
Sass::Script::Value::String.new(to_s(:quote => :none) + other.to_s(:quote => :none), type)
|
102
101
|
end
|
103
102
|
|
104
103
|
# The SassScript `-` operation.
|
@@ -212,6 +211,9 @@ MSG
|
|
212
211
|
# Returns the string representation of this value
|
213
212
|
# as it would be output to the CSS document.
|
214
213
|
#
|
214
|
+
# @options opts :quote [String]
|
215
|
+
# The preferred quote style for quoted strings. If `:none`, strings are
|
216
|
+
# always emitted unquoted.
|
215
217
|
# @return [String]
|
216
218
|
def to_s(opts = {})
|
217
219
|
Sass::Util.abstract(self)
|
@@ -151,6 +151,7 @@ module Sass::Script::Value
|
|
151
151
|
'powderblue' => 0xB0E0E6FF,
|
152
152
|
'purple' => 0x800080FF,
|
153
153
|
'red' => 0xFF0000FF,
|
154
|
+
'rebeccapurple' => 0x663399FF,
|
154
155
|
'rosybrown' => 0xBC8F8FFF,
|
155
156
|
'royalblue' => 0x4169E1FF,
|
156
157
|
'saddlebrown' => 0x8B4513FF,
|
@@ -187,35 +188,43 @@ module Sass::Script::Value
|
|
187
188
|
# different ruby implementations and versions vary on the ordering of the result of invert.
|
188
189
|
COLOR_NAMES.update(ALTERNATE_COLOR_NAMES).freeze
|
189
190
|
|
191
|
+
# The user's original representation of the color.
|
192
|
+
#
|
193
|
+
# @return [String]
|
194
|
+
attr_reader :representation
|
195
|
+
|
190
196
|
# Constructs an RGB or HSL color object,
|
191
197
|
# optionally with an alpha channel.
|
192
198
|
#
|
193
|
-
#
|
194
|
-
#
|
195
|
-
# The alpha value
|
199
|
+
# RGB values are clipped within 0 and 255.
|
200
|
+
# Saturation and lightness values are clipped within 0 and 100.
|
201
|
+
# The alpha value is clipped within 0 and 1.
|
196
202
|
#
|
197
203
|
# @raise [Sass::SyntaxError] if any color value isn't in the specified range
|
198
204
|
#
|
199
205
|
# @overload initialize(attrs)
|
200
|
-
# The attributes are specified as a hash.
|
201
|
-
#
|
202
|
-
#
|
203
|
-
#
|
204
|
-
#
|
206
|
+
# The attributes are specified as a hash. This hash must contain either
|
207
|
+
# `:hue`, `:saturation`, and `:value` keys, or `:red`, `:green`, and
|
208
|
+
# `:blue` keys. It cannot contain both HSL and RGB keys. It may also
|
209
|
+
# optionally contain an `:alpha` key, and a `:representation` key
|
210
|
+
# indicating the original representation of the color that the user wrote
|
211
|
+
# in their stylesheet.
|
205
212
|
#
|
206
213
|
# @param attrs [{Symbol => Numeric}] A hash of color attributes to values
|
207
214
|
# @raise [ArgumentError] if not enough attributes are specified,
|
208
215
|
# or both RGB and HSL attributes are specified
|
209
216
|
#
|
210
|
-
# @overload initialize(rgba)
|
217
|
+
# @overload initialize(rgba, [representation])
|
211
218
|
# The attributes are specified as an array.
|
212
219
|
# This overload only supports RGB or RGBA colors.
|
213
220
|
#
|
214
221
|
# @param rgba [Array<Numeric>] A three- or four-element array
|
215
222
|
# of the red, green, blue, and optionally alpha values (respectively)
|
216
223
|
# of the color
|
224
|
+
# @param representation [String] The original representation of the color
|
225
|
+
# that the user wrote in their stylesheet.
|
217
226
|
# @raise [ArgumentError] if not enough attributes are specified
|
218
|
-
def initialize(attrs, allow_both_rgb_and_hsl = false)
|
227
|
+
def initialize(attrs, representation = nil, allow_both_rgb_and_hsl = false)
|
219
228
|
super(nil)
|
220
229
|
|
221
230
|
if attrs.is_a?(Array)
|
@@ -226,6 +235,7 @@ module Sass::Script::Value
|
|
226
235
|
red, green, blue = attrs[0...3].map {|c| c.to_i}
|
227
236
|
@attrs = {:red => red, :green => green, :blue => blue}
|
228
237
|
@attrs[:alpha] = attrs[3] ? attrs[3].to_f : 1
|
238
|
+
@representation = representation
|
229
239
|
else
|
230
240
|
attrs = attrs.reject {|k, v| v.nil?}
|
231
241
|
hsl = [:hue, :saturation, :lightness] & attrs.keys
|
@@ -243,21 +253,20 @@ module Sass::Script::Value
|
|
243
253
|
@attrs = attrs
|
244
254
|
@attrs[:hue] %= 360 if @attrs[:hue]
|
245
255
|
@attrs[:alpha] ||= 1
|
256
|
+
@representation = @attrs.delete(:representation)
|
246
257
|
end
|
247
258
|
|
248
259
|
[:red, :green, :blue].each do |k|
|
249
260
|
next if @attrs[k].nil?
|
250
|
-
@attrs[k] = @attrs[k].to_i
|
251
|
-
Sass::Util.check_range("#{k.to_s.capitalize} value", 0..255, @attrs[k])
|
261
|
+
@attrs[k] = Sass::Util.restrict(@attrs[k].to_i, 0..255)
|
252
262
|
end
|
253
263
|
|
254
264
|
[:saturation, :lightness].each do |k|
|
255
265
|
next if @attrs[k].nil?
|
256
|
-
|
257
|
-
@attrs[k] = Sass::Util.check_range("#{k.to_s.capitalize}", 0..100, value, '%')
|
266
|
+
@attrs[k] = Sass::Util.restrict(@attrs[k], 0..100)
|
258
267
|
end
|
259
268
|
|
260
|
-
@attrs[:alpha] = Sass::Util.
|
269
|
+
@attrs[:alpha] = Sass::Util.restrict(@attrs[:alpha], 0..1)
|
261
270
|
end
|
262
271
|
|
263
272
|
# Create a new color from a valid CSS hex string.
|
@@ -273,7 +282,9 @@ module Sass::Script::Value
|
|
273
282
|
red = $1.ljust(2, $1).to_i(16)
|
274
283
|
green = $2.ljust(2, $2).to_i(16)
|
275
284
|
blue = $3.ljust(2, $3).to_i(16)
|
276
|
-
|
285
|
+
|
286
|
+
hex_string = '##{hex_string}' unless hex_string[0] == ?#
|
287
|
+
attrs = {:red => red, :green => green, :blue => blue, :representation => hex_string}
|
277
288
|
attrs[:alpha] = alpha if alpha
|
278
289
|
new(attrs)
|
279
290
|
end
|
@@ -428,7 +439,7 @@ module Sass::Script::Value
|
|
428
439
|
end
|
429
440
|
attrs[:alpha] ||= alpha
|
430
441
|
|
431
|
-
Color.new(attrs, :allow_both_rgb_and_hsl)
|
442
|
+
Color.new(attrs, nil, :allow_both_rgb_and_hsl)
|
432
443
|
end
|
433
444
|
|
434
445
|
# The SassScript `+` operation.
|
@@ -549,7 +560,8 @@ module Sass::Script::Value
|
|
549
560
|
# @return [String] The string representation
|
550
561
|
def to_s(opts = {})
|
551
562
|
return smallest if options[:style] == :compressed
|
552
|
-
return
|
563
|
+
return representation if representation
|
564
|
+
return name if name
|
553
565
|
alpha? ? rgba_str : hex_str
|
554
566
|
end
|
555
567
|
alias_method :to_sass, :to_s
|
@@ -561,13 +573,19 @@ module Sass::Script::Value
|
|
561
573
|
alpha? ? rgba_str : hex_str
|
562
574
|
end
|
563
575
|
|
576
|
+
# Returns the color's name, if it has one.
|
577
|
+
#
|
578
|
+
# @return [String, nil]
|
579
|
+
def name
|
580
|
+
COLOR_NAMES_REVERSE[rgba]
|
581
|
+
end
|
582
|
+
|
564
583
|
private
|
565
584
|
|
566
585
|
def smallest
|
567
586
|
small_explicit_str = alpha? ? rgba_str : hex_str.gsub(/^#(.)\1(.)\2(.)\3$/, '#\1\2\3')
|
568
|
-
|
569
|
-
|
570
|
-
color
|
587
|
+
[representation, COLOR_NAMES_REVERSE[rgba], small_explicit_str].
|
588
|
+
compact.min_by {|str| str.size}
|
571
589
|
end
|
572
590
|
|
573
591
|
def rgba_str
|