sass 3.4.25 → 3.5.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/README.md +1 -1
- data/Rakefile +2 -117
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/lib/sass/cache_stores/filesystem.rb +1 -1
- data/lib/sass/css.rb +1 -2
- data/lib/sass/engine.rb +38 -20
- data/lib/sass/environment.rb +26 -5
- data/lib/sass/error.rb +2 -2
- data/lib/sass/exec/base.rb +2 -11
- data/lib/sass/features.rb +1 -0
- data/lib/sass/importers/filesystem.rb +2 -2
- data/lib/sass/plugin/compiler.rb +20 -50
- data/lib/sass/plugin/configuration.rb +2 -2
- data/lib/sass/railtie.rb +1 -1
- data/lib/sass/script/functions.rb +235 -43
- data/lib/sass/script/lexer.rb +13 -2
- data/lib/sass/script/parser.rb +69 -67
- data/lib/sass/script/tree/funcall.rb +35 -30
- data/lib/sass/script/tree/list_literal.rb +23 -8
- data/lib/sass/script/tree/map_literal.rb +2 -2
- data/lib/sass/script/tree/node.rb +0 -8
- data/lib/sass/script/tree/operation.rb +0 -7
- data/lib/sass/script/value/arg_list.rb +1 -1
- data/lib/sass/script/value/base.rb +17 -0
- data/lib/sass/script/value/callable.rb +25 -0
- data/lib/sass/script/value/color.rb +5 -0
- data/lib/sass/script/value/function.rb +19 -0
- data/lib/sass/script/value/helpers.rb +29 -9
- data/lib/sass/script/value/list.rb +35 -14
- data/lib/sass/script/value/map.rb +2 -2
- data/lib/sass/script/value/number.rb +1 -1
- data/lib/sass/script/value.rb +2 -0
- data/lib/sass/scss/parser.rb +99 -40
- data/lib/sass/scss/rx.rb +4 -10
- data/lib/sass/scss/static_parser.rb +5 -24
- data/lib/sass/selector/abstract_sequence.rb +7 -6
- data/lib/sass/selector/comma_sequence.rb +7 -4
- data/lib/sass/selector/pseudo.rb +19 -2
- data/lib/sass/selector/sequence.rb +35 -6
- data/lib/sass/selector/simple.rb +9 -2
- data/lib/sass/selector/simple_sequence.rb +8 -4
- data/lib/sass/selector.rb +4 -0
- data/lib/sass/source/map.rb +2 -2
- data/lib/sass/stack.rb +21 -1
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/prop_node.rb +45 -53
- data/lib/sass/tree/rule_node.rb +3 -2
- data/lib/sass/tree/visitors/check_nesting.rb +1 -1
- data/lib/sass/tree/visitors/convert.rb +2 -3
- data/lib/sass/tree/visitors/cssize.rb +4 -15
- data/lib/sass/tree/visitors/deep_copy.rb +1 -1
- data/lib/sass/tree/visitors/extend.rb +2 -8
- data/lib/sass/tree/visitors/perform.rb +21 -9
- data/lib/sass/tree/visitors/set_options.rb +1 -1
- data/lib/sass/tree/visitors/to_css.rb +47 -13
- data/lib/sass/util/multibyte_string_scanner.rb +127 -131
- data/lib/sass/util/normalized_map.rb +1 -8
- data/lib/sass/util.rb +12 -290
- data/lib/sass/version.rb +0 -2
- data/lib/sass.rb +0 -7
- data/test/sass/cache_test.rb +0 -1
- data/test/sass/callbacks_test.rb +0 -1
- data/test/sass/compiler_test.rb +4 -15
- data/test/sass/conversion_test.rb +113 -163
- data/test/sass/css2sass_test.rb +16 -19
- data/test/sass/css_variable_test.rb +176 -71
- data/test/sass/encoding_test.rb +2 -33
- data/test/sass/engine_test.rb +71 -19
- data/test/sass/exec_test.rb +0 -1
- data/test/sass/extend_test.rb +37 -92
- data/test/sass/functions_test.rb +58 -14
- data/test/sass/importer_test.rb +2 -3
- data/test/sass/logger_test.rb +0 -1
- data/test/sass/plugin_test.rb +6 -10
- data/test/sass/results/script.css +1 -1
- data/test/sass/results/units.css +2 -2
- data/test/sass/script_conversion_test.rb +10 -2
- data/test/sass/script_test.rb +22 -24
- data/test/sass/scss/css_test.rb +3 -18
- data/test/sass/scss/rx_test.rb +0 -1
- data/test/sass/scss/scss_test.rb +49 -16
- data/test/sass/source_map_test.rb +13 -16
- data/test/sass/superselector_test.rb +0 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +121 -124
- data/test/sass/util/normalized_map_test.rb +0 -1
- data/test/sass/util/subset_map_test.rb +0 -1
- data/test/sass/util_test.rb +4 -39
- data/test/sass/value_helpers_test.rb +0 -1
- data/test/sass-spec.yml +1 -1
- data/test/test_helper.rb +39 -0
- metadata +19 -44
- data/lib/sass/script/css_variable_warning.rb +0 -52
- data/lib/sass/util/cross_platform_random.rb +0 -19
- data/lib/sass/util/ordered_hash.rb +0 -192
- data/test/sass/results/import_charset_1_8.css +0 -5
- data/test/sass/templates/import_charset_1_8.sass +0 -6
- data/vendor/listen/CHANGELOG.md +0 -1
- data/vendor/listen/CONTRIBUTING.md +0 -38
- data/vendor/listen/Gemfile +0 -20
- data/vendor/listen/Guardfile +0 -8
- data/vendor/listen/LICENSE +0 -20
- data/vendor/listen/README.md +0 -349
- data/vendor/listen/Rakefile +0 -5
- data/vendor/listen/Vagrantfile +0 -96
- data/vendor/listen/lib/listen/adapter.rb +0 -327
- data/vendor/listen/lib/listen/adapters/bsd.rb +0 -75
- data/vendor/listen/lib/listen/adapters/darwin.rb +0 -48
- data/vendor/listen/lib/listen/adapters/linux.rb +0 -81
- data/vendor/listen/lib/listen/adapters/polling.rb +0 -58
- data/vendor/listen/lib/listen/adapters/windows.rb +0 -91
- data/vendor/listen/lib/listen/directory_record.rb +0 -406
- data/vendor/listen/lib/listen/listener.rb +0 -323
- data/vendor/listen/lib/listen/turnstile.rb +0 -32
- data/vendor/listen/lib/listen/version.rb +0 -3
- data/vendor/listen/lib/listen.rb +0 -54
- data/vendor/listen/listen.gemspec +0 -28
- data/vendor/listen/spec/listen/adapter_spec.rb +0 -149
- data/vendor/listen/spec/listen/adapters/bsd_spec.rb +0 -36
- data/vendor/listen/spec/listen/adapters/darwin_spec.rb +0 -37
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +0 -47
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +0 -68
- data/vendor/listen/spec/listen/adapters/windows_spec.rb +0 -30
- data/vendor/listen/spec/listen/directory_record_spec.rb +0 -1250
- data/vendor/listen/spec/listen/listener_spec.rb +0 -258
- data/vendor/listen/spec/listen/turnstile_spec.rb +0 -56
- data/vendor/listen/spec/listen_spec.rb +0 -67
- data/vendor/listen/spec/spec_helper.rb +0 -25
- data/vendor/listen/spec/support/adapter_helper.rb +0 -666
- data/vendor/listen/spec/support/directory_record_helper.rb +0 -57
- data/vendor/listen/spec/support/fixtures_helper.rb +0 -29
- data/vendor/listen/spec/support/listeners_helper.rb +0 -179
- data/vendor/listen/spec/support/platform_helper.rb +0 -15
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Sass::Script::Value
|
|
2
|
+
# A SassScript object representing a function.
|
|
3
|
+
class Function < Callable
|
|
4
|
+
# Constructs a Function value for use in SassScript.
|
|
5
|
+
#
|
|
6
|
+
# @param function [Sass::Callable] The callable to be used when the
|
|
7
|
+
# function is invoked.
|
|
8
|
+
def initialize(function)
|
|
9
|
+
unless function.type == "function"
|
|
10
|
+
raise ArgumentError.new("A callable of type function was expected.")
|
|
11
|
+
end
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def to_sass
|
|
16
|
+
%{get-function("#{value.name}")}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -68,26 +68,35 @@ module Sass::Script::Value
|
|
|
68
68
|
Number.new(number, *parse_unit_string(unit_string))
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
# @overload list(*elements, separator)
|
|
71
|
+
# @overload list(*elements, separator:, bracketed: false)
|
|
72
72
|
# Create a space-separated list from the arguments given.
|
|
73
73
|
# @param elements [Array<Sass::Script::Value::Base>] Each argument will be a list element.
|
|
74
74
|
# @param separator [Symbol] Either :space or :comma.
|
|
75
|
+
# @param bracketed [Boolean] Whether the list uses square brackets.
|
|
75
76
|
# @return [Sass::Script::Value::List] The space separated list.
|
|
76
77
|
#
|
|
77
|
-
# @overload list(array, separator)
|
|
78
|
+
# @overload list(array, separator:, bracketed: false)
|
|
78
79
|
# Create a space-separated list from the array given.
|
|
79
80
|
# @param array [Array<Sass::Script::Value::Base>] A ruby array of Sass values
|
|
80
81
|
# to make into a list.
|
|
82
|
+
# @param separator [Symbol] Either :space or :comma.
|
|
83
|
+
# @param bracketed [Boolean] Whether the list uses square brackets.
|
|
81
84
|
# @return [Sass::Script::Value::List] The space separated list.
|
|
82
|
-
def list(*elements)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
+
def list(*elements, separator: nil, bracketed: false)
|
|
86
|
+
# Support passing separator as the last value in elements for
|
|
87
|
+
# backwards-compatibility.
|
|
88
|
+
if separator.nil?
|
|
89
|
+
if elements.last.is_a?(Symbol)
|
|
90
|
+
separator = elements.pop
|
|
91
|
+
else
|
|
92
|
+
raise ArgumentError.new("A separator of :space or :comma must be specified.")
|
|
93
|
+
end
|
|
85
94
|
end
|
|
86
|
-
|
|
95
|
+
|
|
87
96
|
if elements.size == 1 && elements.first.is_a?(Array)
|
|
88
97
|
elements = elements.first
|
|
89
98
|
end
|
|
90
|
-
Sass::Script::Value::List.new(elements, separator)
|
|
99
|
+
Sass::Script::Value::List.new(elements, separator: separator, bracketed: bracketed)
|
|
91
100
|
end
|
|
92
101
|
|
|
93
102
|
# Construct a Sass map.
|
|
@@ -196,14 +205,25 @@ module Sass::Script::Value
|
|
|
196
205
|
raise ArgumentError.new(err)
|
|
197
206
|
end
|
|
198
207
|
|
|
199
|
-
# Returns true when the literal is a string containing a calc()
|
|
208
|
+
# Returns true when the literal is a string containing a calc().
|
|
209
|
+
#
|
|
210
|
+
# Use \{#special_number?} in preference to this.
|
|
200
211
|
#
|
|
201
212
|
# @param literal [Sass::Script::Value::Base] The value to check
|
|
202
|
-
# @return
|
|
213
|
+
# @return Boolean
|
|
203
214
|
def calc?(literal)
|
|
204
215
|
literal.is_a?(Sass::Script::Value::String) && literal.value =~ /calc\(/
|
|
205
216
|
end
|
|
206
217
|
|
|
218
|
+
# Returns whether the literal is a special CSS value that may evaluate to a
|
|
219
|
+
# number, such as `calc()` or `var()`.
|
|
220
|
+
#
|
|
221
|
+
# @param literal [Sass::Script::Value::Base] The value to check
|
|
222
|
+
# @return Boolean
|
|
223
|
+
def special_number?(literal)
|
|
224
|
+
literal.is_a?(Sass::Script::Value::String) && literal.value =~ /(calc|var)\(/
|
|
225
|
+
end
|
|
226
|
+
|
|
207
227
|
private
|
|
208
228
|
|
|
209
229
|
# Converts a user-provided selector into string form or throws an
|
|
@@ -14,13 +14,20 @@ module Sass::Script::Value
|
|
|
14
14
|
# @return [Symbol]
|
|
15
15
|
attr_reader :separator
|
|
16
16
|
|
|
17
|
+
# Whether the list is surrounded by square brackets.
|
|
18
|
+
#
|
|
19
|
+
# @return [Boolean]
|
|
20
|
+
attr_reader :bracketed
|
|
21
|
+
|
|
17
22
|
# Creates a new list.
|
|
18
23
|
#
|
|
19
24
|
# @param value [Array<Value>] See \{#value}
|
|
20
25
|
# @param separator [Symbol] See \{#separator}
|
|
21
|
-
|
|
26
|
+
# @param bracketed [Boolean] See \{#bracketed}
|
|
27
|
+
def initialize(value, separator: nil, bracketed: false)
|
|
22
28
|
super(value)
|
|
23
29
|
@separator = separator
|
|
30
|
+
@bracketed = bracketed
|
|
24
31
|
end
|
|
25
32
|
|
|
26
33
|
# @see Value#options=
|
|
@@ -33,24 +40,30 @@ module Sass::Script::Value
|
|
|
33
40
|
def eq(other)
|
|
34
41
|
Sass::Script::Value::Bool.new(
|
|
35
42
|
other.is_a?(List) && value == other.value &&
|
|
36
|
-
separator == other.separator)
|
|
43
|
+
separator == other.separator && bracketed == other.bracketed)
|
|
37
44
|
end
|
|
38
45
|
|
|
39
46
|
def hash
|
|
40
|
-
@hash ||= [value, separator].hash
|
|
47
|
+
@hash ||= [value, separator, bracketed].hash
|
|
41
48
|
end
|
|
42
49
|
|
|
43
50
|
# @see Value#to_s
|
|
44
51
|
def to_s(opts = {})
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
if !bracketed && value.empty?
|
|
53
|
+
raise Sass::SyntaxError.new("#{inspect} isn't a valid CSS value.")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
members = value.
|
|
47
57
|
reject {|e| e.is_a?(Null) || e.is_a?(List) && e.value.empty?}.
|
|
48
|
-
map {|e| e.to_s(opts)}
|
|
58
|
+
map {|e| e.to_s(opts)}
|
|
59
|
+
|
|
60
|
+
contents = members.join(sep_str)
|
|
61
|
+
bracketed ? "[#{contents}]" : contents
|
|
49
62
|
end
|
|
50
63
|
|
|
51
64
|
# @see Value#to_sass
|
|
52
65
|
def to_sass(opts = {})
|
|
53
|
-
return "()" if value.empty?
|
|
66
|
+
return bracketed ? "[]" : "()" if value.empty?
|
|
54
67
|
members = value.map do |v|
|
|
55
68
|
if element_needs_parens?(v)
|
|
56
69
|
"(#{v.to_sass(opts)})"
|
|
@@ -58,19 +71,26 @@ module Sass::Script::Value
|
|
|
58
71
|
v.to_sass(opts)
|
|
59
72
|
end
|
|
60
73
|
end
|
|
61
|
-
|
|
62
|
-
members.
|
|
74
|
+
|
|
75
|
+
if separator == :comma && members.length == 1
|
|
76
|
+
return "#{bracketed ? '[' : '('}#{members.first},#{bracketed ? ']' : ')'}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
contents = members.join(sep_str(nil))
|
|
80
|
+
bracketed ? "[#{contents}]" : contents
|
|
63
81
|
end
|
|
64
82
|
|
|
65
83
|
# @see Value#to_h
|
|
66
84
|
def to_h
|
|
67
|
-
return
|
|
85
|
+
return {} if value.empty?
|
|
68
86
|
super
|
|
69
87
|
end
|
|
70
88
|
|
|
71
89
|
# @see Value#inspect
|
|
72
90
|
def inspect
|
|
73
|
-
|
|
91
|
+
(bracketed ? '[' : '(') +
|
|
92
|
+
value.map {|e| e.inspect}.join(sep_str(nil)) +
|
|
93
|
+
(bracketed ? ']' : ')')
|
|
74
94
|
end
|
|
75
95
|
|
|
76
96
|
# Asserts an index is within the list.
|
|
@@ -94,9 +114,10 @@ module Sass::Script::Value
|
|
|
94
114
|
|
|
95
115
|
def element_needs_parens?(element)
|
|
96
116
|
if element.is_a?(List)
|
|
97
|
-
return false if element.value.
|
|
98
|
-
|
|
99
|
-
|
|
117
|
+
return false if element.value.length < 2
|
|
118
|
+
return false if element.bracketed
|
|
119
|
+
precedence = Sass::Script::Parser.precedence_of(separator || :space)
|
|
120
|
+
return Sass::Script::Parser.precedence_of(element.separator || :space) <= precedence
|
|
100
121
|
end
|
|
101
122
|
|
|
102
123
|
return false unless separator == :space
|
|
@@ -12,7 +12,7 @@ module Sass::Script::Value
|
|
|
12
12
|
#
|
|
13
13
|
# @param hash [Hash<Node, Node>]
|
|
14
14
|
def initialize(hash)
|
|
15
|
-
super(
|
|
15
|
+
super(hash)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
# @see Value#options=
|
|
@@ -32,7 +32,7 @@ module Sass::Script::Value
|
|
|
32
32
|
# @see Value#to_a
|
|
33
33
|
def to_a
|
|
34
34
|
value.map do |k, v|
|
|
35
|
-
list = List.new([k, v], :space)
|
|
35
|
+
list = List.new([k, v], separator: :space)
|
|
36
36
|
list.options = options
|
|
37
37
|
list
|
|
38
38
|
end
|
|
@@ -34,7 +34,7 @@ module Sass::Script::Value
|
|
|
34
34
|
attr_accessor :original
|
|
35
35
|
|
|
36
36
|
def self.precision
|
|
37
|
-
Thread.current[:sass_numeric_precision] || Thread.main[:sass_numeric_precision] ||
|
|
37
|
+
Thread.current[:sass_numeric_precision] || Thread.main[:sass_numeric_precision] || 10
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
# Sets the number of digits of precision
|
data/lib/sass/script/value.rb
CHANGED
data/lib/sass/scss/parser.rb
CHANGED
|
@@ -99,6 +99,18 @@ module Sass
|
|
|
99
99
|
condition
|
|
100
100
|
end
|
|
101
101
|
|
|
102
|
+
# Parses a custom property value.
|
|
103
|
+
#
|
|
104
|
+
# @return [Array<String, Sass::Script;:Tree::Node>] The interpolated value.
|
|
105
|
+
# @raise [Sass::SyntaxError] if there's a syntax error in the value,
|
|
106
|
+
# or if it doesn't take up the entire input string.
|
|
107
|
+
def parse_declaration_value
|
|
108
|
+
init_scanner!
|
|
109
|
+
value = declaration_value
|
|
110
|
+
expected('"}"') unless value && @scanner.eos?
|
|
111
|
+
value
|
|
112
|
+
end
|
|
113
|
+
|
|
102
114
|
private
|
|
103
115
|
|
|
104
116
|
include Sass::SCSS::RX
|
|
@@ -767,6 +779,12 @@ module Sass
|
|
|
767
779
|
mid = [str {ss}]
|
|
768
780
|
return name + mid unless tok(/:/)
|
|
769
781
|
mid << ':'
|
|
782
|
+
|
|
783
|
+
# If this is a CSS variable, parse it as a property no matter what.
|
|
784
|
+
if name.first.is_a?(String) && name.first.start_with?("--")
|
|
785
|
+
return css_variable_declaration(name, name_start_pos, name_end_pos)
|
|
786
|
+
end
|
|
787
|
+
|
|
770
788
|
return name + mid + [':'] if tok(/:/)
|
|
771
789
|
mid << str {ss}
|
|
772
790
|
post_colon_whitespace = !mid.last.empty?
|
|
@@ -775,7 +793,7 @@ module Sass
|
|
|
775
793
|
value_start_pos = source_position
|
|
776
794
|
value = nil
|
|
777
795
|
error = catch_error do
|
|
778
|
-
value = value!
|
|
796
|
+
value = value!
|
|
779
797
|
if tok?(/\{/)
|
|
780
798
|
# Properties that are ambiguous with selectors can't have additional
|
|
781
799
|
# properties nested beneath them.
|
|
@@ -802,7 +820,7 @@ module Sass
|
|
|
802
820
|
ss
|
|
803
821
|
require_block = tok?(/\{/)
|
|
804
822
|
|
|
805
|
-
node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
|
|
823
|
+
node = node(Sass::Tree::PropNode.new(name.flatten.compact, [value], :new),
|
|
806
824
|
name_start_pos, value_end_pos)
|
|
807
825
|
node.name_source_range = range(name_start_pos, name_end_pos)
|
|
808
826
|
node.value_source_range = range(value_start_pos, value_end_pos)
|
|
@@ -811,13 +829,21 @@ module Sass
|
|
|
811
829
|
nested_properties! node
|
|
812
830
|
end
|
|
813
831
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
832
|
+
def css_variable_declaration(name, name_start_pos, name_end_pos)
|
|
833
|
+
value_start_pos = source_position
|
|
834
|
+
value = declaration_value
|
|
835
|
+
value_end_pos = source_position
|
|
836
|
+
|
|
837
|
+
node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
|
|
838
|
+
name_start_pos, value_end_pos)
|
|
839
|
+
node.name_source_range = range(name_start_pos, name_end_pos)
|
|
840
|
+
node.value_source_range = range(value_start_pos, value_end_pos)
|
|
841
|
+
node
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
# This production consumes values that could be a selector, an expression,
|
|
845
|
+
# or a combination of both. It respects strings and comments and supports
|
|
846
|
+
# interpolation. It will consume up to "{", "}", ";", or "!".
|
|
821
847
|
#
|
|
822
848
|
# Values consumed by this production will usually be parsed more
|
|
823
849
|
# thoroughly once interpolation has been resolved.
|
|
@@ -851,6 +877,60 @@ module Sass
|
|
|
851
877
|
interpolation(:warn_for_color)
|
|
852
878
|
end
|
|
853
879
|
|
|
880
|
+
def declaration_value(top_level: true)
|
|
881
|
+
return unless (tok = declaration_value_token(top_level))
|
|
882
|
+
value = [tok]
|
|
883
|
+
while (tok = declaration_value_token(top_level))
|
|
884
|
+
value << tok
|
|
885
|
+
end
|
|
886
|
+
merge(value)
|
|
887
|
+
end
|
|
888
|
+
|
|
889
|
+
def declaration_value_token(top_level)
|
|
890
|
+
# This comes, more or less, from the [token consumption algorithm][].
|
|
891
|
+
# However, since we don't have to worry about the token semantics, we
|
|
892
|
+
# just consume everything until we come across a token with special
|
|
893
|
+
# semantics.
|
|
894
|
+
#
|
|
895
|
+
# [token consumption algorithm]: https://drafts.csswg.org/css-syntax-3/#consume-token.
|
|
896
|
+
result = tok(%r{
|
|
897
|
+
(
|
|
898
|
+
(?!
|
|
899
|
+
url\(
|
|
900
|
+
)
|
|
901
|
+
[^()\[\]{}"'#/ \t\r\n\f#{top_level ? ";!" : ""}]
|
|
902
|
+
|
|
|
903
|
+
\#(?!\{)
|
|
904
|
+
|
|
|
905
|
+
/(?!\*)
|
|
906
|
+
)+
|
|
907
|
+
}xi) || interp_string || interp_uri || interpolation || tok(COMMENT)
|
|
908
|
+
return result if result
|
|
909
|
+
|
|
910
|
+
# Fold together multiple characters of whitespace that don't include
|
|
911
|
+
# newlines. The value only cares about the tokenization, so this is safe
|
|
912
|
+
# as long as we don't delete whitespace entirely. It's important that we
|
|
913
|
+
# fold here rather than post-processing, since we aren't allowed to fold
|
|
914
|
+
# whitespace within strings and we lose that context later on.
|
|
915
|
+
if (ws = tok(S))
|
|
916
|
+
return ws.include?("\n") ? ws.gsub(/\A[^\n]*/, '') : ' '
|
|
917
|
+
end
|
|
918
|
+
|
|
919
|
+
if tok(/\(/)
|
|
920
|
+
value = declaration_value(top_level: false)
|
|
921
|
+
tok!(/\)/)
|
|
922
|
+
['(', *value, ')']
|
|
923
|
+
elsif tok(/\[/)
|
|
924
|
+
value = declaration_value(top_level: false)
|
|
925
|
+
tok!(/\]/)
|
|
926
|
+
['[', *value, ']']
|
|
927
|
+
elsif tok(/\{/)
|
|
928
|
+
value = declaration_value(top_level: false)
|
|
929
|
+
tok!(/\}/)
|
|
930
|
+
['{', *value, '}']
|
|
931
|
+
end
|
|
932
|
+
end
|
|
933
|
+
|
|
854
934
|
def declaration
|
|
855
935
|
# This allows the "*prop: val", ":prop: val", "#prop: val", and ".prop:
|
|
856
936
|
# val" hacks.
|
|
@@ -871,12 +951,12 @@ module Sass
|
|
|
871
951
|
tok!(/:/)
|
|
872
952
|
ss
|
|
873
953
|
value_start_pos = source_position
|
|
874
|
-
value = value!
|
|
954
|
+
value = value!
|
|
875
955
|
value_end_pos = source_position
|
|
876
956
|
ss
|
|
877
957
|
require_block = tok?(/\{/)
|
|
878
958
|
|
|
879
|
-
node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
|
|
959
|
+
node = node(Sass::Tree::PropNode.new(name.flatten.compact, [value], :new),
|
|
880
960
|
name_start_pos, value_end_pos)
|
|
881
961
|
node.name_source_range = range(name_start_pos, name_end_pos)
|
|
882
962
|
node.value_source_range = range(value_start_pos, value_end_pos)
|
|
@@ -885,7 +965,7 @@ module Sass
|
|
|
885
965
|
nested_properties! node
|
|
886
966
|
end
|
|
887
967
|
|
|
888
|
-
def value!
|
|
968
|
+
def value!
|
|
889
969
|
if tok?(/\{/)
|
|
890
970
|
str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
|
|
891
971
|
str.line = source_position.line
|
|
@@ -899,25 +979,16 @@ module Sass
|
|
|
899
979
|
# we don't parse it at all, and instead return a plain old string
|
|
900
980
|
# containing the value.
|
|
901
981
|
# This results in a dramatic speed increase.
|
|
902
|
-
if (val = tok(STATIC_VALUE
|
|
982
|
+
if (val = tok(STATIC_VALUE))
|
|
903
983
|
str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(val.strip))
|
|
904
984
|
str.line = start_pos.line
|
|
905
985
|
str.source_range = range(start_pos)
|
|
906
986
|
return str
|
|
907
987
|
end
|
|
908
|
-
|
|
909
|
-
sass_script(:parse, css_variable)
|
|
988
|
+
sass_script(:parse)
|
|
910
989
|
end
|
|
911
990
|
|
|
912
991
|
def nested_properties!(node)
|
|
913
|
-
if node.name.first.is_a?(String) && node.name.first.start_with?("--")
|
|
914
|
-
Sass::Util.sass_warn(<<WARNING)
|
|
915
|
-
DEPRECATION WARNING on line #{@line}#{" of #{@filename}" if @filename}:
|
|
916
|
-
Sass 3.6 will change the way CSS variables are parsed. Instead of being parsed as
|
|
917
|
-
normal properties, they will not allow any Sass-specific behavior other than \#{}.
|
|
918
|
-
WARNING
|
|
919
|
-
end
|
|
920
|
-
|
|
921
992
|
@expected = 'expression (e.g. 1px, bold) or "{"'
|
|
922
993
|
block(node, :property)
|
|
923
994
|
end
|
|
@@ -1005,7 +1076,7 @@ WARNING
|
|
|
1005
1076
|
end
|
|
1006
1077
|
|
|
1007
1078
|
def interp_ident(start = IDENT)
|
|
1008
|
-
val = tok(start) || interpolation(:warn_for_color) || tok(IDENT_HYPHEN_INTERP
|
|
1079
|
+
val = tok(start) || interpolation(:warn_for_color) || tok(IDENT_HYPHEN_INTERP)
|
|
1009
1080
|
return unless val
|
|
1010
1081
|
res = [val]
|
|
1011
1082
|
while (val = tok(NAME) || interpolation(:warn_for_color))
|
|
@@ -1084,7 +1155,7 @@ WARNING
|
|
|
1084
1155
|
:media_expr => "media expression (e.g. (min-device-width: 800px))",
|
|
1085
1156
|
:at_root_query => "@at-root query (e.g. (without: media))",
|
|
1086
1157
|
:at_root_directive_list => '* or identifier',
|
|
1087
|
-
:
|
|
1158
|
+
:declaration_value => "expression (e.g. fr, 2n+1)",
|
|
1088
1159
|
:interp_ident => "identifier",
|
|
1089
1160
|
:qualified_name => "identifier",
|
|
1090
1161
|
:expr => "expression (e.g. 1px, bold)",
|
|
@@ -1099,9 +1170,9 @@ WARNING
|
|
|
1099
1170
|
:keyframes_selector => "keyframes selector (e.g. 10%)"
|
|
1100
1171
|
}
|
|
1101
1172
|
|
|
1102
|
-
TOK_NAMES = Sass::
|
|
1173
|
+
TOK_NAMES = Hash[Sass::SCSS::RX.constants.map do |c|
|
|
1103
1174
|
[Sass::SCSS::RX.const_get(c), c.downcase]
|
|
1104
|
-
end
|
|
1175
|
+
end].merge(
|
|
1105
1176
|
IDENT => "identifier",
|
|
1106
1177
|
/[;{}]/ => '";"',
|
|
1107
1178
|
/\b(without|with)\b/ => '"with" or "without"'
|
|
@@ -1213,23 +1284,11 @@ WARNING
|
|
|
1213
1284
|
# This is important because `#tok` is called all the time.
|
|
1214
1285
|
NEWLINE = "\n"
|
|
1215
1286
|
|
|
1216
|
-
def tok(rx
|
|
1287
|
+
def tok(rx)
|
|
1217
1288
|
res = @scanner.scan(rx)
|
|
1218
1289
|
|
|
1219
1290
|
return unless res
|
|
1220
1291
|
|
|
1221
|
-
# This fixes https://github.com/nex3/sass/issues/104, which affects
|
|
1222
|
-
# Ruby 1.8.7 and REE. This fix is to replace the ?= zero-width
|
|
1223
|
-
# positive lookahead operator in the Regexp (which matches without
|
|
1224
|
-
# consuming the matched group), with a match that does consume the
|
|
1225
|
-
# group, but then rewinds the scanner and removes the group from the
|
|
1226
|
-
# end of the matched string. This fix makes the assumption that the
|
|
1227
|
-
# matched group will always occur at the end of the match.
|
|
1228
|
-
if last_group_lookahead && @scanner[-1]
|
|
1229
|
-
@scanner.pos -= @scanner[-1].length
|
|
1230
|
-
res.slice!(-@scanner[-1].length..-1)
|
|
1231
|
-
end
|
|
1232
|
-
|
|
1233
1292
|
newline_count = res.count(NEWLINE)
|
|
1234
1293
|
if newline_count > 0
|
|
1235
1294
|
@line += newline_count
|
data/lib/sass/scss/rx.rb
CHANGED
|
@@ -32,7 +32,7 @@ module Sass
|
|
|
32
32
|
# @return [String] The escaped character
|
|
33
33
|
# @private
|
|
34
34
|
def self.escape_char(c)
|
|
35
|
-
return "\\%06x" %
|
|
35
|
+
return "\\%06x" % c.ord unless c =~ %r{[ -/:-~]}
|
|
36
36
|
"\\#{c}"
|
|
37
37
|
end
|
|
38
38
|
|
|
@@ -50,13 +50,7 @@ module Sass
|
|
|
50
50
|
H = /[0-9a-fA-F]/
|
|
51
51
|
NL = /\n|\r\n|\r|\f/
|
|
52
52
|
UNICODE = /\\#{H}{1,6}[ \t\r\n\f]?/
|
|
53
|
-
s =
|
|
54
|
-
'\200-\377'
|
|
55
|
-
elsif Sass::Util.macruby?
|
|
56
|
-
'\u0080-\uD7FF\uE000-\uFFFD\U00010000-\U0010FFFF'
|
|
57
|
-
else
|
|
58
|
-
'\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
|
|
59
|
-
end
|
|
53
|
+
s = '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
|
|
60
54
|
NONASCII = /[#{s}]/
|
|
61
55
|
ESCAPE = /#{UNICODE}|\\[ -~#{s}]/
|
|
62
56
|
NMSTART = /[_a-zA-Z]|#{NONASCII}|#{ESCAPE}/
|
|
@@ -127,13 +121,13 @@ module Sass
|
|
|
127
121
|
OPTIONAL = /!#{W}optional/i
|
|
128
122
|
IDENT_START = /-|#{NMSTART}/
|
|
129
123
|
|
|
130
|
-
IDENT_HYPHEN_INTERP = /-(
|
|
124
|
+
IDENT_HYPHEN_INTERP = /-(?=#\{)/
|
|
131
125
|
STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|#{ESCAPE})*)\"/
|
|
132
126
|
STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|#{ESCAPE})*)\'/
|
|
133
127
|
STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
|
|
134
128
|
|
|
135
129
|
STATIC_COMPONENT = /#{IDENT}|#{STRING_NOINTERP}|#{HEXCOLOR}|[+-]?#{NUMBER}|\!important/i
|
|
136
|
-
STATIC_VALUE = %r(#{STATIC_COMPONENT}(\s*[\s
|
|
130
|
+
STATIC_VALUE = %r(#{STATIC_COMPONENT}(\s*[\s,\/]\s*#{STATIC_COMPONENT})*(?=[;}]))i
|
|
137
131
|
STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){1,50}([{])/i
|
|
138
132
|
end
|
|
139
133
|
end
|
|
@@ -276,6 +276,8 @@ MESSAGE
|
|
|
276
276
|
|
|
277
277
|
PREFIXED_SELECTOR_PSEUDO_CLASSES = %w(nth-child nth-last-child).to_set
|
|
278
278
|
|
|
279
|
+
SELECTOR_PSEUDO_ELEMENTS = %w(slotted).to_set
|
|
280
|
+
|
|
279
281
|
def pseudo
|
|
280
282
|
s = tok(/::?/)
|
|
281
283
|
return unless s
|
|
@@ -288,8 +290,10 @@ MESSAGE
|
|
|
288
290
|
sel = selector_comma_sequence
|
|
289
291
|
elsif s == ':' && PREFIXED_SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
|
|
290
292
|
arg, sel = prefixed_selector_pseudo
|
|
293
|
+
elsif s == '::' && SELECTOR_PSEUDO_ELEMENTS.include?(deprefixed)
|
|
294
|
+
sel = selector_comma_sequence
|
|
291
295
|
else
|
|
292
|
-
arg = expr!(:
|
|
296
|
+
arg = expr!(:declaration_value).join
|
|
293
297
|
end
|
|
294
298
|
|
|
295
299
|
tok!(/\)/)
|
|
@@ -297,29 +301,6 @@ MESSAGE
|
|
|
297
301
|
Selector::Pseudo.new(s == ':' ? :class : :element, name, arg, sel)
|
|
298
302
|
end
|
|
299
303
|
|
|
300
|
-
def pseudo_args
|
|
301
|
-
arg = expr!(:pseudo_expr)
|
|
302
|
-
while tok(/,/)
|
|
303
|
-
arg << ',' << str {ss}
|
|
304
|
-
arg.concat expr!(:pseudo_expr)
|
|
305
|
-
end
|
|
306
|
-
arg
|
|
307
|
-
end
|
|
308
|
-
|
|
309
|
-
def pseudo_expr
|
|
310
|
-
res = pseudo_expr_token
|
|
311
|
-
return unless res
|
|
312
|
-
res << str {ss}
|
|
313
|
-
while (e = pseudo_expr_token)
|
|
314
|
-
res << e << str {ss}
|
|
315
|
-
end
|
|
316
|
-
res
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
def pseudo_expr_token
|
|
320
|
-
tok(PLUS) || tok(/[-*]/) || tok(NUMBER) || tok(STRING) || tok(IDENT)
|
|
321
|
-
end
|
|
322
|
-
|
|
323
304
|
def prefixed_selector_pseudo
|
|
324
305
|
prefix = str do
|
|
325
306
|
expr = str {expr!(:a_n_plus_b)}
|
|
@@ -59,12 +59,11 @@ module Sass
|
|
|
59
59
|
end
|
|
60
60
|
alias_method :==, :eql?
|
|
61
61
|
|
|
62
|
-
# Whether or not this selector
|
|
63
|
-
#
|
|
64
|
-
def
|
|
65
|
-
@
|
|
66
|
-
next m.
|
|
67
|
-
next m.selector && m.selector.has_placeholder? if m.is_a?(Pseudo)
|
|
62
|
+
# Whether or not this selector should be hidden due to containing a
|
|
63
|
+
# placeholder.
|
|
64
|
+
def invisible?
|
|
65
|
+
@invisible ||= members.any? do |m|
|
|
66
|
+
next m.invisible? if m.is_a?(AbstractSequence) || m.is_a?(Pseudo)
|
|
68
67
|
m.is_a?(Placeholder)
|
|
69
68
|
end
|
|
70
69
|
end
|
|
@@ -73,6 +72,8 @@ module Sass
|
|
|
73
72
|
#
|
|
74
73
|
# @param opts [Hash] rendering options.
|
|
75
74
|
# @option opts [Symbol] :style The css rendering style.
|
|
75
|
+
# @option placeholders [Boolean] :placeholders
|
|
76
|
+
# Whether to include placeholder selectors. Defaults to `true`.
|
|
76
77
|
# @return [String]
|
|
77
78
|
def to_s(opts = {})
|
|
78
79
|
Sass::Util.abstract(self)
|
|
@@ -129,7 +129,7 @@ WARNING
|
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
extends[sel] = Sass::Tree::Visitors::Cssize::Extend.new(
|
|
132
|
-
member, sel, extend_node, parent_directives,
|
|
132
|
+
member, sel, extend_node, parent_directives, false)
|
|
133
133
|
end
|
|
134
134
|
end
|
|
135
135
|
end
|
|
@@ -158,8 +158,8 @@ WARNING
|
|
|
158
158
|
Sass::Script::Value::List.new(seq.members.map do |component|
|
|
159
159
|
next if component == "\n"
|
|
160
160
|
Sass::Script::Value::String.new(component.to_s)
|
|
161
|
-
end.compact, :space)
|
|
162
|
-
end, :comma)
|
|
161
|
+
end.compact, separator: :space)
|
|
162
|
+
end, separator: :comma)
|
|
163
163
|
end
|
|
164
164
|
|
|
165
165
|
# Returns a string representation of the sequence.
|
|
@@ -172,7 +172,10 @@ WARNING
|
|
|
172
172
|
|
|
173
173
|
# @see AbstractSequence#to_s
|
|
174
174
|
def to_s(opts = {})
|
|
175
|
-
@members.map
|
|
175
|
+
@members.map do |m|
|
|
176
|
+
next if opts[:placeholder] == false && m.invisible?
|
|
177
|
+
m.to_s(opts)
|
|
178
|
+
end.compact.
|
|
176
179
|
join(opts[:style] == :compressed ? "," : ", ").
|
|
177
180
|
gsub(", \n", ",\n")
|
|
178
181
|
end
|
data/lib/sass/selector/pseudo.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# coding: utf-8
|
|
1
2
|
module Sass
|
|
2
3
|
module Selector
|
|
3
4
|
# A pseudoclass (e.g. `:visited`) or pseudoelement (e.g. `::first-line`)
|
|
@@ -48,6 +49,18 @@ module Sass
|
|
|
48
49
|
@selector = selector
|
|
49
50
|
end
|
|
50
51
|
|
|
52
|
+
def unique?
|
|
53
|
+
type == :class && normalized_name == 'root'
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Whether or not this selector should be hidden due to containing a
|
|
57
|
+
# placeholder.
|
|
58
|
+
def invisible?
|
|
59
|
+
# :not() is a special case—if you eliminate all the placeholders from
|
|
60
|
+
# it, it should match anything.
|
|
61
|
+
name != 'not' && @selector && @selector.members.all? {|s| s.invisible?}
|
|
62
|
+
end
|
|
63
|
+
|
|
51
64
|
# Returns a copy of this with \{#selector} set to \{#new\_selector}.
|
|
52
65
|
#
|
|
53
66
|
# @param new_selector [CommaSequence]
|
|
@@ -77,7 +90,7 @@ module Sass
|
|
|
77
90
|
# more complex cases that likely aren't worth the pain.
|
|
78
91
|
next [] unless sel.name == name && sel.arg == arg
|
|
79
92
|
sel.selector.members
|
|
80
|
-
when 'has', 'host', 'host-context'
|
|
93
|
+
when 'has', 'host', 'host-context', 'slotted'
|
|
81
94
|
# We can't expand nested selectors here, because each layer adds an
|
|
82
95
|
# additional layer of semantics. For example, `:has(:has(img))`
|
|
83
96
|
# doesn't match `<div><img></div>` but `:has(img)` does.
|
|
@@ -114,6 +127,10 @@ module Sass
|
|
|
114
127
|
|
|
115
128
|
# @see Selector#to_s
|
|
116
129
|
def to_s(opts = {})
|
|
130
|
+
# :not() is a special case, because :not(<nothing>) should match
|
|
131
|
+
# everything.
|
|
132
|
+
return '' if name == 'not' && @selector && @selector.members.all? {|m| m.invisible?}
|
|
133
|
+
|
|
117
134
|
res = (syntactic_type == :class ? ":" : "::") + @name
|
|
118
135
|
if @arg || @selector
|
|
119
136
|
res << "("
|
|
@@ -161,7 +178,7 @@ module Sass
|
|
|
161
178
|
their_seq = Sequence.new(parents + [their_sseq])
|
|
162
179
|
our_seq.superselector?(their_seq)
|
|
163
180
|
end
|
|
164
|
-
when 'has', 'host', 'host-context'
|
|
181
|
+
when 'has', 'host', 'host-context', 'slotted'
|
|
165
182
|
# Like :matches, :has (et al) can be a superselector of another
|
|
166
183
|
# selector if its constituent selectors are a superset of those of
|
|
167
184
|
# another :has in the other selector. However, the :matches other case
|