sass 3.4.25 → 3.7.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CODE_OF_CONDUCT.md +1 -1
- data/CONTRIBUTING.md +3 -3
- data/README.md +17 -9
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/VERSION_NAME +1 -1
- data/extra/sass-spec-ref.sh +9 -1
- data/lib/sass.rb +0 -7
- data/lib/sass/cache_stores/filesystem.rb +1 -1
- data/lib/sass/css.rb +1 -2
- data/lib/sass/engine.rb +39 -29
- data/lib/sass/environment.rb +26 -5
- data/lib/sass/error.rb +2 -2
- data/lib/sass/exec/base.rb +2 -13
- data/lib/sass/exec/sass_scss.rb +1 -5
- data/lib/sass/features.rb +1 -0
- data/lib/sass/importers/filesystem.rb +6 -4
- data/lib/sass/logger/base.rb +11 -0
- 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/css_parser.rb +4 -1
- data/lib/sass/script/functions.rb +308 -81
- data/lib/sass/script/lexer.rb +63 -9
- data/lib/sass/script/parser.rb +287 -118
- data/lib/sass/script/tree/funcall.rb +35 -34
- data/lib/sass/script/tree/interpolation.rb +0 -3
- 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 +1 -8
- data/lib/sass/script/value.rb +2 -0
- 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 +8 -2
- data/lib/sass/script/value/function.rb +19 -0
- data/lib/sass/script/value/helpers.rb +37 -11
- 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 +3 -2
- data/lib/sass/scss/css_parser.rb +6 -1
- data/lib/sass/scss/parser.rb +145 -56
- data/lib/sass/scss/rx.rb +5 -11
- data/lib/sass/scss/static_parser.rb +20 -42
- data/lib/sass/selector.rb +4 -0
- data/lib/sass/selector/abstract_sequence.rb +7 -6
- data/lib/sass/selector/comma_sequence.rb +9 -5
- data/lib/sass/selector/pseudo.rb +20 -3
- data/lib/sass/selector/sequence.rb +35 -10
- data/lib/sass/selector/simple.rb +9 -2
- data/lib/sass/selector/simple_sequence.rb +8 -4
- data/lib/sass/source/map.rb +2 -6
- 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 +6 -8
- 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 +23 -15
- data/lib/sass/tree/visitors/set_options.rb +1 -1
- data/lib/sass/tree/visitors/to_css.rb +49 -22
- data/lib/sass/util.rb +72 -310
- data/lib/sass/util/multibyte_string_scanner.rb +127 -131
- data/lib/sass/util/normalized_map.rb +1 -8
- data/lib/sass/version.rb +0 -4
- metadata +55 -202
- data/Rakefile +0 -453
- 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-spec.yml +0 -3
- data/test/sass/cache_test.rb +0 -131
- data/test/sass/callbacks_test.rb +0 -61
- data/test/sass/compiler_test.rb +0 -236
- data/test/sass/conversion_test.rb +0 -2188
- data/test/sass/css2sass_test.rb +0 -526
- data/test/sass/css_variable_test.rb +0 -132
- data/test/sass/data/hsl-rgb.txt +0 -319
- data/test/sass/encoding_test.rb +0 -219
- data/test/sass/engine_test.rb +0 -3447
- data/test/sass/exec_test.rb +0 -96
- data/test/sass/extend_test.rb +0 -1733
- data/test/sass/fixtures/test_staleness_check_across_importers.css +0 -1
- data/test/sass/fixtures/test_staleness_check_across_importers.scss +0 -1
- data/test/sass/functions_test.rb +0 -1977
- data/test/sass/importer_test.rb +0 -421
- data/test/sass/logger_test.rb +0 -58
- data/test/sass/mock_importer.rb +0 -49
- data/test/sass/more_results/more1.css +0 -9
- data/test/sass/more_results/more1_with_line_comments.css +0 -26
- data/test/sass/more_results/more_import.css +0 -29
- data/test/sass/more_templates/_more_partial.sass +0 -2
- data/test/sass/more_templates/more1.sass +0 -23
- data/test/sass/more_templates/more_import.sass +0 -11
- data/test/sass/plugin_test.rb +0 -556
- data/test/sass/results/alt.css +0 -4
- data/test/sass/results/basic.css +0 -9
- data/test/sass/results/cached_import_option.css +0 -3
- data/test/sass/results/compact.css +0 -5
- data/test/sass/results/complex.css +0 -86
- data/test/sass/results/compressed.css +0 -1
- data/test/sass/results/expanded.css +0 -19
- data/test/sass/results/filename_fn.css +0 -3
- data/test/sass/results/if.css +0 -3
- data/test/sass/results/import.css +0 -31
- data/test/sass/results/import_charset.css +0 -5
- data/test/sass/results/import_charset_1_8.css +0 -5
- data/test/sass/results/import_charset_ibm866.css +0 -5
- data/test/sass/results/import_content.css +0 -1
- data/test/sass/results/line_numbers.css +0 -49
- data/test/sass/results/mixins.css +0 -95
- data/test/sass/results/multiline.css +0 -24
- data/test/sass/results/nested.css +0 -22
- data/test/sass/results/options.css +0 -1
- data/test/sass/results/parent_ref.css +0 -13
- data/test/sass/results/script.css +0 -16
- data/test/sass/results/scss_import.css +0 -31
- data/test/sass/results/scss_importee.css +0 -2
- data/test/sass/results/subdir/nested_subdir/nested_subdir.css +0 -1
- data/test/sass/results/subdir/subdir.css +0 -3
- data/test/sass/results/units.css +0 -11
- data/test/sass/results/warn.css +0 -0
- data/test/sass/results/warn_imported.css +0 -0
- data/test/sass/script_conversion_test.rb +0 -357
- data/test/sass/script_test.rb +0 -1431
- data/test/sass/scss/css_test.rb +0 -1281
- data/test/sass/scss/rx_test.rb +0 -160
- data/test/sass/scss/scss_test.rb +0 -4205
- data/test/sass/scss/test_helper.rb +0 -37
- data/test/sass/source_map_test.rb +0 -1055
- data/test/sass/superselector_test.rb +0 -210
- data/test/sass/templates/_cached_import_option_partial.scss +0 -1
- data/test/sass/templates/_double_import_loop2.sass +0 -1
- data/test/sass/templates/_filename_fn_import.scss +0 -11
- data/test/sass/templates/_imported_charset_ibm866.sass +0 -4
- data/test/sass/templates/_imported_charset_utf8.sass +0 -4
- data/test/sass/templates/_imported_content.sass +0 -3
- data/test/sass/templates/_partial.sass +0 -2
- data/test/sass/templates/_same_name_different_partiality.scss +0 -1
- data/test/sass/templates/alt.sass +0 -16
- data/test/sass/templates/basic.sass +0 -23
- data/test/sass/templates/bork1.sass +0 -2
- data/test/sass/templates/bork2.sass +0 -2
- data/test/sass/templates/bork3.sass +0 -2
- data/test/sass/templates/bork4.sass +0 -2
- data/test/sass/templates/bork5.sass +0 -3
- data/test/sass/templates/cached_import_option.scss +0 -3
- data/test/sass/templates/compact.sass +0 -17
- data/test/sass/templates/complex.sass +0 -305
- data/test/sass/templates/compressed.sass +0 -15
- data/test/sass/templates/double_import_loop1.sass +0 -1
- data/test/sass/templates/expanded.sass +0 -17
- data/test/sass/templates/filename_fn.scss +0 -18
- data/test/sass/templates/if.sass +0 -11
- data/test/sass/templates/import.sass +0 -12
- data/test/sass/templates/import_charset.sass +0 -9
- data/test/sass/templates/import_charset_1_8.sass +0 -6
- data/test/sass/templates/import_charset_ibm866.sass +0 -11
- data/test/sass/templates/import_content.sass +0 -4
- data/test/sass/templates/importee.less +0 -2
- data/test/sass/templates/importee.sass +0 -19
- data/test/sass/templates/line_numbers.sass +0 -13
- data/test/sass/templates/mixin_bork.sass +0 -5
- data/test/sass/templates/mixins.sass +0 -76
- data/test/sass/templates/multiline.sass +0 -20
- data/test/sass/templates/nested.sass +0 -25
- data/test/sass/templates/nested_bork1.sass +0 -2
- data/test/sass/templates/nested_bork2.sass +0 -2
- data/test/sass/templates/nested_bork3.sass +0 -2
- data/test/sass/templates/nested_bork4.sass +0 -2
- data/test/sass/templates/nested_import.sass +0 -2
- data/test/sass/templates/nested_mixin_bork.sass +0 -6
- data/test/sass/templates/options.sass +0 -2
- data/test/sass/templates/parent_ref.sass +0 -25
- data/test/sass/templates/same_name_different_ext.sass +0 -2
- data/test/sass/templates/same_name_different_ext.scss +0 -1
- data/test/sass/templates/same_name_different_partiality.scss +0 -1
- data/test/sass/templates/script.sass +0 -101
- data/test/sass/templates/scss_import.scss +0 -12
- data/test/sass/templates/scss_importee.scss +0 -1
- data/test/sass/templates/single_import_loop.sass +0 -1
- data/test/sass/templates/subdir/import_up1.scss +0 -1
- data/test/sass/templates/subdir/import_up2.scss +0 -1
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +0 -2
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +0 -3
- data/test/sass/templates/subdir/subdir.sass +0 -6
- data/test/sass/templates/units.sass +0 -11
- data/test/sass/templates/warn.sass +0 -3
- data/test/sass/templates/warn_imported.sass +0 -4
- data/test/sass/test_helper.rb +0 -8
- data/test/sass/util/multibyte_string_scanner_test.rb +0 -155
- data/test/sass/util/normalized_map_test.rb +0 -51
- data/test/sass/util/subset_map_test.rb +0 -91
- data/test/sass/util_test.rb +0 -438
- data/test/sass/value_helpers_test.rb +0 -179
- data/test/test_helper.rb +0 -110
- 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.rb +0 -54
- 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/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
@@ -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
|
@@ -189,6 +189,7 @@ module Sass::Script::Value
|
|
189
189
|
# @raise [Sass::UnitConversionError] if `other` has incompatible units
|
190
190
|
def mod(other)
|
191
191
|
if other.is_a?(Number)
|
192
|
+
return Number.new(Float::NAN) if other.value == 0
|
192
193
|
operate(other, :%)
|
193
194
|
else
|
194
195
|
raise NoMethodError.new(nil, :mod)
|
@@ -472,7 +473,7 @@ module Sass::Script::Value
|
|
472
473
|
sans_common_units(@numerator_units, @denominator_units)
|
473
474
|
|
474
475
|
@denominator_units.each_with_index do |d, i|
|
475
|
-
next unless convertable?(d) && (u = @numerator_units.find
|
476
|
+
next unless convertable?(d) && (u = @numerator_units.find {|n| convertable?([n, d])})
|
476
477
|
@value /= conversion_factor(d, u)
|
477
478
|
@denominator_units.delete_at(i)
|
478
479
|
@numerator_units.delete_at(@numerator_units.index(u))
|
data/lib/sass/scss/css_parser.rb
CHANGED
@@ -47,7 +47,12 @@ module Sass
|
|
47
47
|
def keyframes_ruleset
|
48
48
|
start_pos = source_position
|
49
49
|
return unless (selector = keyframes_selector)
|
50
|
-
block(
|
50
|
+
block(
|
51
|
+
node(
|
52
|
+
Sass::Tree::KeyframeRuleNode.new(
|
53
|
+
Sass::Util.strip_except_escapes(selector)),
|
54
|
+
start_pos),
|
55
|
+
:ruleset)
|
51
56
|
end
|
52
57
|
|
53
58
|
@sass_script_parser = Sass::Script::CssParser
|
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
|
@@ -191,7 +203,7 @@ module Sass
|
|
191
203
|
def directive
|
192
204
|
start_pos = source_position
|
193
205
|
return unless tok(/@/)
|
194
|
-
name =
|
206
|
+
name = ident!
|
195
207
|
ss
|
196
208
|
|
197
209
|
if (dir = special_directive(name, start_pos))
|
@@ -228,14 +240,14 @@ module Sass
|
|
228
240
|
end
|
229
241
|
|
230
242
|
def mixin_directive(start_pos)
|
231
|
-
name =
|
243
|
+
name = ident!
|
232
244
|
args, splat = sass_script(:parse_mixin_definition_arglist)
|
233
245
|
ss
|
234
246
|
block(node(Sass::Tree::MixinDefNode.new(name, args, splat), start_pos), :directive)
|
235
247
|
end
|
236
248
|
|
237
249
|
def include_directive(start_pos)
|
238
|
-
name =
|
250
|
+
name = ident!
|
239
251
|
args, keywords, splat, kwarg_splat = sass_script(:parse_mixin_include_arglist)
|
240
252
|
ss
|
241
253
|
include_node = node(
|
@@ -254,7 +266,7 @@ module Sass
|
|
254
266
|
end
|
255
267
|
|
256
268
|
def function_directive(start_pos)
|
257
|
-
name =
|
269
|
+
name = ident!
|
258
270
|
args, splat = sass_script(:parse_function_definition_arglist)
|
259
271
|
ss
|
260
272
|
block(node(Sass::Tree::FunctionNode.new(name, args, splat), start_pos), :function)
|
@@ -274,7 +286,7 @@ module Sass
|
|
274
286
|
|
275
287
|
def for_directive(start_pos)
|
276
288
|
tok!(/\$/)
|
277
|
-
var =
|
289
|
+
var = ident!
|
278
290
|
ss
|
279
291
|
|
280
292
|
tok!(/from/)
|
@@ -291,12 +303,12 @@ module Sass
|
|
291
303
|
|
292
304
|
def each_directive(start_pos)
|
293
305
|
tok!(/\$/)
|
294
|
-
vars = [
|
306
|
+
vars = [ident!]
|
295
307
|
ss
|
296
308
|
while tok(/,/)
|
297
309
|
ss
|
298
310
|
tok!(/\$/)
|
299
|
-
vars <<
|
311
|
+
vars << ident!
|
300
312
|
ss
|
301
313
|
end
|
302
314
|
|
@@ -465,12 +477,23 @@ module Sass
|
|
465
477
|
return unless tok(/\(/)
|
466
478
|
res = ['(']
|
467
479
|
ss
|
468
|
-
|
480
|
+
stop_at = Set[:single_eq, :lt, :lte, :gt, :gte]
|
481
|
+
res << sass_script(:parse_until, stop_at)
|
469
482
|
|
470
483
|
if tok(/:/)
|
471
484
|
res << ': '
|
472
485
|
ss
|
473
486
|
res << sass_script(:parse)
|
487
|
+
elsif comparison1 = tok(/=|[<>]=?/)
|
488
|
+
res << ' ' << comparison1 << ' '
|
489
|
+
ss
|
490
|
+
res << sass_script(:parse_until, stop_at)
|
491
|
+
if ((comparison1 == ">" || comparison1 == ">=") && comparison2 = tok(/>=?/)) ||
|
492
|
+
((comparison1 == "<" || comparison1 == "<=") && comparison2 = tok(/<=?/))
|
493
|
+
res << ' ' << comparison2 << ' '
|
494
|
+
ss
|
495
|
+
res << sass_script(:parse_until, stop_at)
|
496
|
+
end
|
474
497
|
end
|
475
498
|
res << tok!(/\)/)
|
476
499
|
ss
|
@@ -530,10 +553,10 @@ module Sass
|
|
530
553
|
end
|
531
554
|
|
532
555
|
def at_root_directive_list
|
533
|
-
return unless (first =
|
556
|
+
return unless (first = ident)
|
534
557
|
arr = [first]
|
535
558
|
ss
|
536
|
-
while (e =
|
559
|
+
while (e = ident)
|
537
560
|
arr << e
|
538
561
|
ss
|
539
562
|
end
|
@@ -624,12 +647,12 @@ module Sass
|
|
624
647
|
def variable
|
625
648
|
return unless tok(/\$/)
|
626
649
|
start_pos = source_position
|
627
|
-
name =
|
650
|
+
name = ident!
|
628
651
|
ss; tok!(/:/); ss
|
629
652
|
|
630
653
|
expr = sass_script(:parse)
|
631
654
|
while tok(/!/)
|
632
|
-
flag_name =
|
655
|
+
flag_name = ident!
|
633
656
|
if flag_name == 'default'
|
634
657
|
guarded ||= true
|
635
658
|
elsif flag_name == 'global'
|
@@ -767,6 +790,12 @@ module Sass
|
|
767
790
|
mid = [str {ss}]
|
768
791
|
return name + mid unless tok(/:/)
|
769
792
|
mid << ':'
|
793
|
+
|
794
|
+
# If this is a CSS variable, parse it as a property no matter what.
|
795
|
+
if name.first.is_a?(String) && name.first.start_with?("--")
|
796
|
+
return css_variable_declaration(name, name_start_pos, name_end_pos)
|
797
|
+
end
|
798
|
+
|
770
799
|
return name + mid + [':'] if tok(/:/)
|
771
800
|
mid << str {ss}
|
772
801
|
post_colon_whitespace = !mid.last.empty?
|
@@ -775,7 +804,7 @@ module Sass
|
|
775
804
|
value_start_pos = source_position
|
776
805
|
value = nil
|
777
806
|
error = catch_error do
|
778
|
-
value = value!
|
807
|
+
value = value!
|
779
808
|
if tok?(/\{/)
|
780
809
|
# Properties that are ambiguous with selectors can't have additional
|
781
810
|
# properties nested beneath them.
|
@@ -802,7 +831,7 @@ module Sass
|
|
802
831
|
ss
|
803
832
|
require_block = tok?(/\{/)
|
804
833
|
|
805
|
-
node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
|
834
|
+
node = node(Sass::Tree::PropNode.new(name.flatten.compact, [value], :new),
|
806
835
|
name_start_pos, value_end_pos)
|
807
836
|
node.name_source_range = range(name_start_pos, name_end_pos)
|
808
837
|
node.value_source_range = range(value_start_pos, value_end_pos)
|
@@ -811,13 +840,21 @@ module Sass
|
|
811
840
|
nested_properties! node
|
812
841
|
end
|
813
842
|
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
843
|
+
def css_variable_declaration(name, name_start_pos, name_end_pos)
|
844
|
+
value_start_pos = source_position
|
845
|
+
value = declaration_value
|
846
|
+
value_end_pos = source_position
|
847
|
+
|
848
|
+
node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
|
849
|
+
name_start_pos, value_end_pos)
|
850
|
+
node.name_source_range = range(name_start_pos, name_end_pos)
|
851
|
+
node.value_source_range = range(value_start_pos, value_end_pos)
|
852
|
+
node
|
853
|
+
end
|
854
|
+
|
855
|
+
# This production consumes values that could be a selector, an expression,
|
856
|
+
# or a combination of both. It respects strings and comments and supports
|
857
|
+
# interpolation. It will consume up to "{", "}", ";", or "!".
|
821
858
|
#
|
822
859
|
# Values consumed by this production will usually be parsed more
|
823
860
|
# thoroughly once interpolation has been resolved.
|
@@ -851,6 +888,60 @@ module Sass
|
|
851
888
|
interpolation(:warn_for_color)
|
852
889
|
end
|
853
890
|
|
891
|
+
def declaration_value(top_level: true)
|
892
|
+
return unless (tok = declaration_value_token(top_level))
|
893
|
+
value = [tok]
|
894
|
+
while (tok = declaration_value_token(top_level))
|
895
|
+
value << tok
|
896
|
+
end
|
897
|
+
merge(value)
|
898
|
+
end
|
899
|
+
|
900
|
+
def declaration_value_token(top_level)
|
901
|
+
# This comes, more or less, from the [token consumption algorithm][].
|
902
|
+
# However, since we don't have to worry about the token semantics, we
|
903
|
+
# just consume everything until we come across a token with special
|
904
|
+
# semantics.
|
905
|
+
#
|
906
|
+
# [token consumption algorithm]: https://drafts.csswg.org/css-syntax-3/#consume-token.
|
907
|
+
result = tok(%r{
|
908
|
+
(
|
909
|
+
(?!
|
910
|
+
url\(
|
911
|
+
)
|
912
|
+
[^()\[\]{}"'#/ \t\r\n\f#{top_level ? ";" : ""}]
|
913
|
+
|
|
914
|
+
\#(?!\{)
|
915
|
+
|
|
916
|
+
/(?!\*)
|
917
|
+
)+
|
918
|
+
}xi) || interp_string || interp_uri || interpolation || tok(COMMENT)
|
919
|
+
return result if result
|
920
|
+
|
921
|
+
# Fold together multiple characters of whitespace that don't include
|
922
|
+
# newlines. The value only cares about the tokenization, so this is safe
|
923
|
+
# as long as we don't delete whitespace entirely. It's important that we
|
924
|
+
# fold here rather than post-processing, since we aren't allowed to fold
|
925
|
+
# whitespace within strings and we lose that context later on.
|
926
|
+
if (ws = tok(S))
|
927
|
+
return ws.include?("\n") ? ws.gsub(/\A[^\n]*/, '') : ' '
|
928
|
+
end
|
929
|
+
|
930
|
+
if tok(/\(/)
|
931
|
+
value = declaration_value(top_level: false)
|
932
|
+
tok!(/\)/)
|
933
|
+
['(', *value, ')']
|
934
|
+
elsif tok(/\[/)
|
935
|
+
value = declaration_value(top_level: false)
|
936
|
+
tok!(/\]/)
|
937
|
+
['[', *value, ']']
|
938
|
+
elsif tok(/\{/)
|
939
|
+
value = declaration_value(top_level: false)
|
940
|
+
tok!(/\}/)
|
941
|
+
['{', *value, '}']
|
942
|
+
end
|
943
|
+
end
|
944
|
+
|
854
945
|
def declaration
|
855
946
|
# This allows the "*prop: val", ":prop: val", "#prop: val", and ".prop:
|
856
947
|
# val" hacks.
|
@@ -871,12 +962,12 @@ module Sass
|
|
871
962
|
tok!(/:/)
|
872
963
|
ss
|
873
964
|
value_start_pos = source_position
|
874
|
-
value = value!
|
965
|
+
value = value!
|
875
966
|
value_end_pos = source_position
|
876
967
|
ss
|
877
968
|
require_block = tok?(/\{/)
|
878
969
|
|
879
|
-
node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
|
970
|
+
node = node(Sass::Tree::PropNode.new(name.flatten.compact, [value], :new),
|
880
971
|
name_start_pos, value_end_pos)
|
881
972
|
node.name_source_range = range(name_start_pos, name_end_pos)
|
882
973
|
node.value_source_range = range(value_start_pos, value_end_pos)
|
@@ -885,7 +976,7 @@ module Sass
|
|
885
976
|
nested_properties! node
|
886
977
|
end
|
887
978
|
|
888
|
-
def value!
|
979
|
+
def value!
|
889
980
|
if tok?(/\{/)
|
890
981
|
str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
|
891
982
|
str.line = source_position.line
|
@@ -899,25 +990,19 @@ module Sass
|
|
899
990
|
# we don't parse it at all, and instead return a plain old string
|
900
991
|
# containing the value.
|
901
992
|
# This results in a dramatic speed increase.
|
902
|
-
if (val = tok(STATIC_VALUE
|
903
|
-
|
993
|
+
if (val = tok(STATIC_VALUE))
|
994
|
+
# If val ends with escaped whitespace, leave it be.
|
995
|
+
str = Sass::Script::Tree::Literal.new(
|
996
|
+
Sass::Script::Value::String.new(
|
997
|
+
Sass::Util.strip_except_escapes(val)))
|
904
998
|
str.line = start_pos.line
|
905
999
|
str.source_range = range(start_pos)
|
906
1000
|
return str
|
907
1001
|
end
|
908
|
-
|
909
|
-
sass_script(:parse, css_variable)
|
1002
|
+
sass_script(:parse)
|
910
1003
|
end
|
911
1004
|
|
912
1005
|
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
1006
|
@expected = 'expression (e.g. 1px, bold) or "{"'
|
922
1007
|
block(node, :property)
|
923
1008
|
end
|
@@ -966,7 +1051,7 @@ WARNING
|
|
966
1051
|
def var_expr
|
967
1052
|
return unless tok(/\$/)
|
968
1053
|
line = @line
|
969
|
-
var = Sass::Script::Tree::Variable.new(
|
1054
|
+
var = Sass::Script::Tree::Variable.new(ident!)
|
970
1055
|
var.line = line
|
971
1056
|
var
|
972
1057
|
end
|
@@ -1004,11 +1089,27 @@ WARNING
|
|
1004
1089
|
res
|
1005
1090
|
end
|
1006
1091
|
|
1007
|
-
def
|
1008
|
-
|
1092
|
+
def ident
|
1093
|
+
(ident = tok(IDENT)) && Sass::Util.normalize_ident_escapes(ident)
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
def ident!
|
1097
|
+
Sass::Util.normalize_ident_escapes(tok!(IDENT))
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
def name
|
1101
|
+
(name = tok(NAME)) && Sass::Util.normalize_ident_escapes(name)
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
def name!
|
1105
|
+
Sass::Util.normalize_ident_escapes(tok!(NAME))
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
def interp_ident
|
1109
|
+
val = ident || interpolation(:warn_for_color) || tok(IDENT_HYPHEN_INTERP)
|
1009
1110
|
return unless val
|
1010
1111
|
res = [val]
|
1011
|
-
while (val =
|
1112
|
+
while (val = name || interpolation(:warn_for_color))
|
1012
1113
|
res << val
|
1013
1114
|
end
|
1014
1115
|
res
|
@@ -1084,7 +1185,7 @@ WARNING
|
|
1084
1185
|
:media_expr => "media expression (e.g. (min-device-width: 800px))",
|
1085
1186
|
:at_root_query => "@at-root query (e.g. (without: media))",
|
1086
1187
|
:at_root_directive_list => '* or identifier',
|
1087
|
-
:
|
1188
|
+
:declaration_value => "expression (e.g. fr, 2n+1)",
|
1088
1189
|
:interp_ident => "identifier",
|
1089
1190
|
:qualified_name => "identifier",
|
1090
1191
|
:expr => "expression (e.g. 1px, bold)",
|
@@ -1099,9 +1200,9 @@ WARNING
|
|
1099
1200
|
:keyframes_selector => "keyframes selector (e.g. 10%)"
|
1100
1201
|
}
|
1101
1202
|
|
1102
|
-
TOK_NAMES = Sass::
|
1203
|
+
TOK_NAMES = Hash[Sass::SCSS::RX.constants.map do |c|
|
1103
1204
|
[Sass::SCSS::RX.const_get(c), c.downcase]
|
1104
|
-
end
|
1205
|
+
end].merge(
|
1105
1206
|
IDENT => "identifier",
|
1106
1207
|
/[;{}]/ => '";"',
|
1107
1208
|
/\b(without|with)\b/ => '"with" or "without"'
|
@@ -1213,23 +1314,11 @@ WARNING
|
|
1213
1314
|
# This is important because `#tok` is called all the time.
|
1214
1315
|
NEWLINE = "\n"
|
1215
1316
|
|
1216
|
-
def tok(rx
|
1317
|
+
def tok(rx)
|
1217
1318
|
res = @scanner.scan(rx)
|
1218
1319
|
|
1219
1320
|
return unless res
|
1220
1321
|
|
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
1322
|
newline_count = res.count(NEWLINE)
|
1234
1323
|
if newline_count > 0
|
1235
1324
|
@line += newline_count
|