sass 3.3.0 → 3.4.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +3 -1
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +148 -0
- data/MIT-LICENSE +1 -1
- data/README.md +76 -62
- data/Rakefile +104 -24
- 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/extra/sass-spec-ref.sh +32 -0
- data/extra/update_watch.rb +1 -1
- data/lib/sass/cache_stores/filesystem.rb +9 -5
- data/lib/sass/cache_stores/memory.rb +4 -5
- data/lib/sass/callbacks.rb +2 -2
- data/lib/sass/css.rb +12 -13
- data/lib/sass/deprecation.rb +55 -0
- data/lib/sass/engine.rb +106 -70
- data/lib/sass/environment.rb +39 -19
- data/lib/sass/error.rb +17 -20
- data/lib/sass/exec/base.rb +199 -0
- data/lib/sass/exec/sass_convert.rb +283 -0
- data/lib/sass/exec/sass_scss.rb +440 -0
- data/lib/sass/exec.rb +5 -771
- data/lib/sass/features.rb +9 -2
- data/lib/sass/importers/base.rb +8 -3
- data/lib/sass/importers/filesystem.rb +30 -38
- data/lib/sass/logger/base.rb +8 -2
- data/lib/sass/logger/delayed.rb +50 -0
- data/lib/sass/logger.rb +8 -3
- data/lib/sass/media.rb +1 -4
- data/lib/sass/plugin/compiler.rb +224 -90
- data/lib/sass/plugin/configuration.rb +38 -22
- data/lib/sass/plugin/merb.rb +2 -2
- data/lib/sass/plugin/rack.rb +3 -3
- data/lib/sass/plugin/rails.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +4 -4
- data/lib/sass/plugin.rb +6 -5
- data/lib/sass/script/css_lexer.rb +1 -1
- data/lib/sass/script/css_parser.rb +2 -3
- data/lib/sass/script/css_variable_warning.rb +52 -0
- data/lib/sass/script/functions.rb +739 -318
- data/lib/sass/script/lexer.rb +134 -54
- data/lib/sass/script/parser.rb +252 -56
- data/lib/sass/script/tree/funcall.rb +13 -6
- data/lib/sass/script/tree/interpolation.rb +127 -4
- data/lib/sass/script/tree/list_literal.rb +31 -4
- data/lib/sass/script/tree/literal.rb +4 -0
- data/lib/sass/script/tree/node.rb +21 -3
- data/lib/sass/script/tree/operation.rb +54 -1
- data/lib/sass/script/tree/selector.rb +26 -0
- data/lib/sass/script/tree/string_interpolation.rb +59 -38
- data/lib/sass/script/tree/variable.rb +1 -1
- data/lib/sass/script/tree.rb +1 -0
- data/lib/sass/script/value/base.rb +17 -14
- data/lib/sass/script/value/bool.rb +0 -5
- data/lib/sass/script/value/color.rb +78 -42
- data/lib/sass/script/value/helpers.rb +119 -2
- data/lib/sass/script/value/list.rb +0 -15
- data/lib/sass/script/value/map.rb +1 -1
- data/lib/sass/script/value/null.rb +0 -5
- data/lib/sass/script/value/number.rb +112 -31
- data/lib/sass/script/value/string.rb +102 -13
- data/lib/sass/script/value.rb +0 -1
- data/lib/sass/script.rb +3 -3
- data/lib/sass/scss/css_parser.rb +24 -4
- data/lib/sass/scss/parser.rb +290 -383
- data/lib/sass/scss/rx.rb +17 -9
- data/lib/sass/scss/static_parser.rb +306 -4
- data/lib/sass/scss.rb +0 -2
- data/lib/sass/selector/abstract_sequence.rb +35 -18
- data/lib/sass/selector/comma_sequence.rb +114 -19
- data/lib/sass/selector/pseudo.rb +266 -0
- data/lib/sass/selector/sequence.rb +146 -40
- data/lib/sass/selector/simple.rb +22 -33
- data/lib/sass/selector/simple_sequence.rb +122 -39
- data/lib/sass/selector.rb +57 -197
- data/lib/sass/shared.rb +2 -2
- data/lib/sass/source/map.rb +31 -14
- data/lib/sass/source/position.rb +4 -4
- data/lib/sass/stack.rb +2 -8
- data/lib/sass/supports.rb +10 -13
- data/lib/sass/tree/at_root_node.rb +1 -0
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +1 -1
- data/lib/sass/tree/css_import_node.rb +9 -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 +9 -0
- data/lib/sass/tree/import_node.rb +6 -5
- data/lib/sass/tree/keyframe_rule_node.rb +15 -0
- data/lib/sass/tree/node.rb +5 -3
- data/lib/sass/tree/prop_node.rb +6 -7
- data/lib/sass/tree/rule_node.rb +26 -11
- data/lib/sass/tree/visitors/check_nesting.rb +56 -32
- data/lib/sass/tree/visitors/convert.rb +59 -44
- data/lib/sass/tree/visitors/cssize.rb +34 -30
- data/lib/sass/tree/visitors/deep_copy.rb +6 -1
- data/lib/sass/tree/visitors/extend.rb +15 -13
- data/lib/sass/tree/visitors/perform.rb +87 -50
- data/lib/sass/tree/visitors/set_options.rb +15 -1
- data/lib/sass/tree/visitors/to_css.rb +72 -43
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/normalized_map.rb +0 -1
- data/lib/sass/util/subset_map.rb +2 -3
- data/lib/sass/util.rb +334 -154
- data/lib/sass/version.rb +7 -7
- data/lib/sass.rb +10 -8
- data/test/sass/cache_test.rb +62 -20
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/compiler_test.rb +24 -11
- data/test/sass/conversion_test.rb +241 -50
- data/test/sass/css2sass_test.rb +73 -5
- data/test/sass/css_variable_test.rb +132 -0
- data/test/sass/encoding_test.rb +219 -0
- data/test/sass/engine_test.rb +343 -260
- data/test/sass/exec_test.rb +12 -2
- data/test/sass/extend_test.rb +333 -44
- data/test/sass/functions_test.rb +353 -260
- data/test/sass/importer_test.rb +40 -21
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/more_templates/more1.sass +10 -10
- data/test/sass/more_templates/more_import.sass +2 -2
- data/test/sass/plugin_test.rb +24 -21
- 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 +5 -5
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +71 -39
- data/test/sass/script_test.rb +714 -123
- data/test/sass/scss/css_test.rb +213 -30
- data/test/sass/scss/rx_test.rb +8 -4
- data/test/sass/scss/scss_test.rb +766 -22
- data/test/sass/source_map_test.rb +263 -95
- data/test/sass/superselector_test.rb +210 -0
- data/test/sass/templates/_partial.sass +1 -1
- data/test/sass/templates/basic.sass +10 -10
- data/test/sass/templates/bork1.sass +1 -1
- data/test/sass/templates/bork5.sass +1 -1
- data/test/sass/templates/compact.sass +10 -10
- data/test/sass/templates/complex.sass +187 -187
- data/test/sass/templates/compressed.sass +10 -10
- data/test/sass/templates/expanded.sass +10 -10
- data/test/sass/templates/import.sass +2 -2
- data/test/sass/templates/importee.sass +3 -3
- data/test/sass/templates/mixins.sass +22 -22
- data/test/sass/templates/multiline.sass +4 -4
- data/test/sass/templates/nested.sass +13 -13
- data/test/sass/templates/parent_ref.sass +12 -12
- data/test/sass/templates/script.sass +70 -70
- data/test/sass/templates/scss_import.scss +2 -1
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
- data/test/sass/templates/subdir/subdir.sass +3 -3
- data/test/sass/templates/units.sass +10 -10
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +11 -3
- 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 +46 -45
- data/test/sass/value_helpers_test.rb +5 -7
- data/test/sass-spec.yml +3 -0
- data/test/test_helper.rb +7 -6
- 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 +310 -300
- data/CONTRIBUTING +0 -3
- data/ext/mkrf_conf.rb +0 -27
- data/lib/sass/script/value/deprecated_false.rb +0 -55
- data/lib/sass/scss/script_lexer.rb +0 -15
- data/lib/sass/scss/script_parser.rb +0 -25
- 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/scss/parser.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'set'
|
2
3
|
|
3
4
|
module Sass
|
@@ -15,21 +16,20 @@ module Sass
|
|
15
16
|
# warnings and source maps.
|
16
17
|
# @param importer [Sass::Importers::Base] The importer used to import the
|
17
18
|
# file being parsed. Used for source maps.
|
18
|
-
# @param line [
|
19
|
+
# @param line [Integer] The 1-based line on which the source string appeared,
|
19
20
|
# if it's part of another document.
|
20
|
-
# @param offset [
|
21
|
+
# @param offset [Integer] The 1-based character (not byte) offset in the line on
|
21
22
|
# which the source string starts. Used for error reporting and sourcemap
|
22
23
|
# building.
|
23
|
-
# @comment
|
24
|
-
# rubocop:disable ParameterLists
|
25
24
|
def initialize(str, filename, importer, line = 1, offset = 1)
|
26
|
-
# rubocop:enable ParameterLists
|
27
25
|
@template = str
|
28
26
|
@filename = filename
|
29
27
|
@importer = importer
|
30
28
|
@line = line
|
31
29
|
@offset = offset
|
32
30
|
@strs = []
|
31
|
+
@expected = nil
|
32
|
+
@throw_error = false
|
33
33
|
end
|
34
34
|
|
35
35
|
# Parses an SCSS document.
|
@@ -39,7 +39,7 @@ module Sass
|
|
39
39
|
def parse
|
40
40
|
init_scanner!
|
41
41
|
root = stylesheet
|
42
|
-
expected("selector or at-rule") unless @scanner.eos?
|
42
|
+
expected("selector or at-rule") unless root && @scanner.eos?
|
43
43
|
root
|
44
44
|
end
|
45
45
|
|
@@ -54,6 +54,15 @@ module Sass
|
|
54
54
|
interp_ident
|
55
55
|
end
|
56
56
|
|
57
|
+
# Parses a supports clause for an @import directive
|
58
|
+
def parse_supports_clause
|
59
|
+
init_scanner!
|
60
|
+
ss
|
61
|
+
clause = supports_clause
|
62
|
+
ss
|
63
|
+
clause
|
64
|
+
end
|
65
|
+
|
57
66
|
# Parses a media query list.
|
58
67
|
#
|
59
68
|
# @return [Sass::Media::QueryList] The parsed query list
|
@@ -62,7 +71,7 @@ module Sass
|
|
62
71
|
def parse_media_query_list
|
63
72
|
init_scanner!
|
64
73
|
ql = media_query_list
|
65
|
-
expected("media query list") unless @scanner.eos?
|
74
|
+
expected("media query list") unless ql && @scanner.eos?
|
66
75
|
ql
|
67
76
|
end
|
68
77
|
|
@@ -74,7 +83,7 @@ module Sass
|
|
74
83
|
def parse_at_root_query
|
75
84
|
init_scanner!
|
76
85
|
query = at_root_query
|
77
|
-
expected("@at-root query list") unless @scanner.eos?
|
86
|
+
expected("@at-root query list") unless query && @scanner.eos?
|
78
87
|
query
|
79
88
|
end
|
80
89
|
|
@@ -86,7 +95,7 @@ module Sass
|
|
86
95
|
def parse_supports_condition
|
87
96
|
init_scanner!
|
88
97
|
condition = supports_condition
|
89
|
-
expected("supports condition") unless @scanner.eos?
|
98
|
+
expected("supports condition") unless condition && @scanner.eos?
|
90
99
|
condition
|
91
100
|
end
|
92
101
|
|
@@ -107,7 +116,7 @@ module Sass
|
|
107
116
|
if @template.is_a?(StringScanner)
|
108
117
|
@template
|
109
118
|
else
|
110
|
-
Sass::Util::MultibyteStringScanner.new(@template.
|
119
|
+
Sass::Util::MultibyteStringScanner.new(@template.tr("\r", ""))
|
111
120
|
end
|
112
121
|
end
|
113
122
|
|
@@ -149,16 +158,16 @@ module Sass
|
|
149
158
|
silent = text =~ %r{\A//}
|
150
159
|
loud = !silent && text =~ %r{\A/[/*]!}
|
151
160
|
line = @line - text.count("\n")
|
161
|
+
comment_start = @scanner.pos - text.length
|
162
|
+
index_before_line = @scanner.string.rindex("\n", comment_start) || -1
|
163
|
+
offset = comment_start - index_before_line
|
152
164
|
|
153
165
|
if silent
|
154
166
|
value = [text.sub(%r{\A\s*//}, '/*').gsub(%r{^\s*//}, ' *') + ' */']
|
155
167
|
else
|
156
|
-
value = Sass::Engine.parse_interp(
|
157
|
-
|
158
|
-
value.unshift(
|
159
|
-
string[0...@scanner.pos].
|
160
|
-
reverse[/.*?\*\/(.*?)($|\Z)/, 1].
|
161
|
-
reverse.gsub(/[^\s]/, ' '))
|
168
|
+
value = Sass::Engine.parse_interp(text, line, offset, :filename => @filename)
|
169
|
+
line_before_comment = @scanner.string[index_before_line + 1...comment_start]
|
170
|
+
value.unshift(line_before_comment.gsub(/[^\s]/, ' '))
|
162
171
|
end
|
163
172
|
|
164
173
|
type = if silent
|
@@ -168,14 +177,14 @@ module Sass
|
|
168
177
|
else
|
169
178
|
:normal
|
170
179
|
end
|
171
|
-
|
172
|
-
comment
|
180
|
+
start_pos = Sass::Source::Position.new(line, offset)
|
181
|
+
comment = node(Sass::Tree::CommentNode.new(value, type), start_pos)
|
173
182
|
node << comment
|
174
183
|
end
|
175
184
|
|
176
185
|
DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
|
177
186
|
:each, :while, :if, :else, :extend, :import, :media, :charset, :content,
|
178
|
-
:_moz_document, :at_root]
|
187
|
+
:_moz_document, :at_root, :error]
|
179
188
|
|
180
189
|
PREFIXED_DIRECTIVES = Set[:supports]
|
181
190
|
|
@@ -191,10 +200,7 @@ module Sass
|
|
191
200
|
return dir
|
192
201
|
end
|
193
202
|
|
194
|
-
|
195
|
-
# but some (e.g. @page) take selector-like arguments.
|
196
|
-
# Some take no arguments at all.
|
197
|
-
val = expr || selector
|
203
|
+
val = almost_any_value
|
198
204
|
val = val ? ["@#{name} "] + Sass::Util.strip_string_array(val) : ["@#{name}"]
|
199
205
|
directive_body(val, start_pos)
|
200
206
|
end
|
@@ -212,12 +218,12 @@ module Sass
|
|
212
218
|
end
|
213
219
|
|
214
220
|
def special_directive(name, start_pos)
|
215
|
-
sym = name.
|
221
|
+
sym = name.tr('-', '_').to_sym
|
216
222
|
DIRECTIVES.include?(sym) && send("#{sym}_directive", start_pos)
|
217
223
|
end
|
218
224
|
|
219
225
|
def prefixed_directive(name, start_pos)
|
220
|
-
sym = name
|
226
|
+
sym = deprefix(name).tr('-', '_').to_sym
|
221
227
|
PREFIXED_DIRECTIVES.include?(sym) && send("#{sym}_directive", name, start_pos)
|
222
228
|
end
|
223
229
|
|
@@ -350,10 +356,12 @@ module Sass
|
|
350
356
|
end
|
351
357
|
|
352
358
|
def extend_directive(start_pos)
|
353
|
-
|
359
|
+
selector_start_pos = source_position
|
360
|
+
@expected = "selector"
|
361
|
+
selector = Sass::Util.strip_string_array(expr!(:almost_any_value))
|
354
362
|
optional = tok(OPTIONAL)
|
355
363
|
ss
|
356
|
-
node(Sass::Tree::ExtendNode.new(selector, !!optional,
|
364
|
+
node(Sass::Tree::ExtendNode.new(selector, !!optional, range(selector_start_pos)), start_pos)
|
357
365
|
end
|
358
366
|
|
359
367
|
def import_directive(start_pos)
|
@@ -371,24 +379,28 @@ module Sass
|
|
371
379
|
|
372
380
|
def import_arg
|
373
381
|
start_pos = source_position
|
374
|
-
return unless (str =
|
382
|
+
return unless (str = string) || (uri = tok?(/url\(/i))
|
375
383
|
if uri
|
376
384
|
str = sass_script(:parse_string)
|
377
385
|
ss
|
386
|
+
supports = supports_clause
|
387
|
+
ss
|
378
388
|
media = media_query_list
|
379
389
|
ss
|
380
|
-
return node(Tree::CssImportNode.new(str, media.to_a), start_pos)
|
390
|
+
return node(Tree::CssImportNode.new(str, media.to_a, supports), start_pos)
|
381
391
|
end
|
382
|
-
|
383
|
-
path = @scanner[1] || @scanner[2]
|
384
392
|
ss
|
385
393
|
|
394
|
+
supports = supports_clause
|
395
|
+
ss
|
386
396
|
media = media_query_list
|
387
|
-
if
|
388
|
-
return node(
|
397
|
+
if str =~ %r{^(https?:)?//} || media || supports || use_css_import?
|
398
|
+
return node(
|
399
|
+
Sass::Tree::CssImportNode.new(
|
400
|
+
Sass::Script::Value::String.quote(str), media.to_a, supports), start_pos)
|
389
401
|
end
|
390
402
|
|
391
|
-
node(Sass::Tree::ImportNode.new(
|
403
|
+
node(Sass::Tree::ImportNode.new(str.strip), start_pos)
|
392
404
|
end
|
393
405
|
|
394
406
|
def use_css_import?; false; end
|
@@ -471,8 +483,7 @@ module Sass
|
|
471
483
|
alias_method :at_root_query, :query_expr
|
472
484
|
|
473
485
|
def charset_directive(start_pos)
|
474
|
-
|
475
|
-
name = @scanner[1] || @scanner[2]
|
486
|
+
name = expr!(:string)
|
476
487
|
ss
|
477
488
|
node(Sass::Tree::CharsetNode.new(name), start_pos)
|
478
489
|
end
|
@@ -500,7 +511,7 @@ module Sass
|
|
500
511
|
|
501
512
|
def moz_document_function
|
502
513
|
val = interp_uri || _interp_string(:url_prefix) ||
|
503
|
-
_interp_string(:domain) || function(
|
514
|
+
_interp_string(:domain) || function(false) || interpolation
|
504
515
|
return unless val
|
505
516
|
ss
|
506
517
|
val
|
@@ -529,6 +540,10 @@ module Sass
|
|
529
540
|
arr
|
530
541
|
end
|
531
542
|
|
543
|
+
def error_directive(start_pos)
|
544
|
+
node(Sass::Tree::ErrorNode.new(sass_script(:parse)), start_pos)
|
545
|
+
end
|
546
|
+
|
532
547
|
# http://www.w3.org/TR/css3-conditional/
|
533
548
|
def supports_directive(name, start_pos)
|
534
549
|
condition = expr!(:supports_condition)
|
@@ -542,10 +557,23 @@ module Sass
|
|
542
557
|
node(node, start_pos)
|
543
558
|
end
|
544
559
|
|
560
|
+
def supports_clause
|
561
|
+
return unless tok(/supports\(/i)
|
562
|
+
ss
|
563
|
+
supports = import_supports_condition
|
564
|
+
ss
|
565
|
+
tok!(/\)/)
|
566
|
+
supports
|
567
|
+
end
|
568
|
+
|
545
569
|
def supports_condition
|
546
570
|
supports_negation || supports_operator || supports_interpolation
|
547
571
|
end
|
548
572
|
|
573
|
+
def import_supports_condition
|
574
|
+
supports_condition || supports_declaration
|
575
|
+
end
|
576
|
+
|
549
577
|
def supports_negation
|
550
578
|
return unless tok(/not/i)
|
551
579
|
ss
|
@@ -555,7 +583,9 @@ module Sass
|
|
555
583
|
def supports_operator
|
556
584
|
cond = supports_condition_in_parens
|
557
585
|
return unless cond
|
558
|
-
|
586
|
+
re = /and|or/i
|
587
|
+
while (op = tok(re))
|
588
|
+
re = /#{op}/i
|
559
589
|
ss
|
560
590
|
cond = Sass::Supports::Operator.new(
|
561
591
|
cond, expr!(:supports_condition_in_parens), op)
|
@@ -563,6 +593,13 @@ module Sass
|
|
563
593
|
cond
|
564
594
|
end
|
565
595
|
|
596
|
+
def supports_declaration
|
597
|
+
name = sass_script(:parse)
|
598
|
+
tok!(/:/); ss
|
599
|
+
value = sass_script(:parse)
|
600
|
+
Sass::Supports::Declaration.new(name, value)
|
601
|
+
end
|
602
|
+
|
566
603
|
def supports_condition_in_parens
|
567
604
|
interp = supports_interpolation
|
568
605
|
return interp if interp
|
@@ -571,19 +608,12 @@ module Sass
|
|
571
608
|
tok!(/\)/); ss
|
572
609
|
cond
|
573
610
|
else
|
574
|
-
|
575
|
-
tok!(/:/); ss
|
576
|
-
value = sass_script(:parse)
|
611
|
+
decl = supports_declaration
|
577
612
|
tok!(/\)/); ss
|
578
|
-
|
613
|
+
decl
|
579
614
|
end
|
580
615
|
end
|
581
616
|
|
582
|
-
def supports_declaration_condition
|
583
|
-
return unless tok(/\(/); ss
|
584
|
-
supports_declaration_body
|
585
|
-
end
|
586
|
-
|
587
617
|
def supports_interpolation
|
588
618
|
interp = interpolation
|
589
619
|
return unless interp
|
@@ -619,15 +649,15 @@ module Sass
|
|
619
649
|
# are disallowed by the CSS spec,
|
620
650
|
# but they're included here for compatibility
|
621
651
|
# with some proprietary MS properties
|
622
|
-
str {ss if tok(
|
652
|
+
str {ss if tok(%r{[/,:.=]})}
|
623
653
|
end
|
624
654
|
|
625
655
|
def ruleset
|
626
656
|
start_pos = source_position
|
627
|
-
rules
|
628
|
-
|
629
|
-
|
630
|
-
|
657
|
+
return unless (rules = almost_any_value)
|
658
|
+
block(
|
659
|
+
node(
|
660
|
+
Sass::Tree::RuleNode.new(rules, range(start_pos)), start_pos), :ruleset)
|
631
661
|
end
|
632
662
|
|
633
663
|
def block(node, context)
|
@@ -661,315 +691,177 @@ module Sass
|
|
661
691
|
child_or_array.has_children
|
662
692
|
end
|
663
693
|
|
664
|
-
#
|
665
|
-
#
|
666
|
-
#
|
667
|
-
#
|
668
|
-
#
|
669
|
-
#
|
694
|
+
# When parsing the contents of a ruleset, it can be difficult to tell
|
695
|
+
# declarations apart from nested rulesets. Since we don't thoroughly parse
|
696
|
+
# selectors until after resolving interpolation, we can share a bunch of
|
697
|
+
# the parsing of the two, but we need to disambiguate them first. We use
|
698
|
+
# the following criteria:
|
699
|
+
#
|
700
|
+
# * If the entity doesn't start with an identifier followed by a colon,
|
701
|
+
# it's a selector. There are some additional mostly-unimportant cases
|
702
|
+
# here to support various declaration hacks.
|
703
|
+
#
|
704
|
+
# * If the colon is followed by another colon, it's a selector.
|
670
705
|
#
|
671
|
-
#
|
672
|
-
#
|
673
|
-
#
|
706
|
+
# * Otherwise, if the colon is followed by anything other than
|
707
|
+
# interpolation or a character that's valid as the beginning of an
|
708
|
+
# identifier, it's a declaration.
|
674
709
|
#
|
675
|
-
#
|
676
|
-
#
|
677
|
-
#
|
678
|
-
#
|
710
|
+
# * If the colon is followed by interpolation or a valid identifier, try
|
711
|
+
# parsing it as a declaration value. If this fails, backtrack and parse
|
712
|
+
# it as a selector.
|
713
|
+
#
|
714
|
+
# * If the declaration value value valid but is followed by "{", backtrack
|
715
|
+
# and parse it as a selector anyway. This ensures that ".foo:bar {" is
|
716
|
+
# always parsed as a selector and never as a property with nested
|
717
|
+
# properties beneath it.
|
679
718
|
def declaration_or_ruleset
|
680
|
-
old_use_property_exception, @use_property_exception =
|
681
|
-
@use_property_exception, false
|
682
|
-
decl_err = catch_error do
|
683
|
-
decl = declaration
|
684
|
-
unless decl && decl.has_children
|
685
|
-
# We want an exception if it's not there,
|
686
|
-
# but we don't want to consume if it is
|
687
|
-
tok!(/[;}]/) unless tok?(/[;}]/)
|
688
|
-
end
|
689
|
-
return decl
|
690
|
-
end
|
691
|
-
|
692
|
-
ruleset_err = catch_error {return ruleset}
|
693
|
-
rethrow(@use_property_exception ? decl_err : ruleset_err)
|
694
|
-
ensure
|
695
|
-
@use_property_exception = old_use_property_exception
|
696
|
-
end
|
697
|
-
|
698
|
-
def selector_sequence
|
699
719
|
start_pos = source_position
|
700
|
-
|
701
|
-
return [sel], range(start_pos)
|
702
|
-
end
|
703
|
-
|
704
|
-
rules = []
|
705
|
-
v = selector
|
706
|
-
return unless v
|
707
|
-
rules.concat v
|
708
|
-
|
709
|
-
ws = ''
|
710
|
-
while tok(/,/)
|
711
|
-
ws << str {ss}
|
712
|
-
if (v = selector)
|
713
|
-
rules << ',' << ws
|
714
|
-
rules.concat v
|
715
|
-
ws = ''
|
716
|
-
end
|
717
|
-
end
|
718
|
-
return rules, range(start_pos)
|
719
|
-
end
|
720
|
-
|
721
|
-
def selector
|
722
|
-
sel = _selector
|
723
|
-
return unless sel
|
724
|
-
sel.to_a
|
725
|
-
end
|
720
|
+
declaration = try_declaration
|
726
721
|
|
727
|
-
|
728
|
-
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
if (sel = _selector)
|
735
|
-
selectors << sel
|
736
|
-
if ws.include?("\n")
|
737
|
-
selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members)
|
738
|
-
end
|
739
|
-
ws = ''
|
740
|
-
end
|
722
|
+
if declaration.nil?
|
723
|
+
return unless (selector = almost_any_value)
|
724
|
+
elsif declaration.is_a?(Array)
|
725
|
+
selector = declaration
|
726
|
+
else
|
727
|
+
# Declaration should be a PropNode.
|
728
|
+
return declaration
|
741
729
|
end
|
742
|
-
Selector::CommaSequence.new(selectors)
|
743
|
-
end
|
744
|
-
|
745
|
-
def _selector
|
746
|
-
# The combinator here allows the "> E" hack
|
747
|
-
val = combinator || simple_selector_sequence
|
748
|
-
return unless val
|
749
|
-
nl = str {ss}.include?("\n")
|
750
|
-
res = []
|
751
|
-
res << val
|
752
|
-
res << "\n" if nl
|
753
730
|
|
754
|
-
|
755
|
-
|
756
|
-
res << "\n" if str {ss}.include?("\n")
|
731
|
+
if (additional_selector = almost_any_value)
|
732
|
+
selector << additional_selector
|
757
733
|
end
|
758
|
-
Selector::Sequence.new(res.compact)
|
759
|
-
end
|
760
734
|
|
761
|
-
|
762
|
-
|
735
|
+
block(
|
736
|
+
node(
|
737
|
+
Sass::Tree::RuleNode.new(merge(selector), range(start_pos)), start_pos), :ruleset)
|
763
738
|
end
|
764
739
|
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
res = [e]
|
786
|
-
|
787
|
-
# The tok(/\*/) allows the "E*" hack
|
788
|
-
while (v = id_selector || class_selector || placeholder_selector ||
|
789
|
-
attrib || pseudo || interpolation_selector ||
|
790
|
-
(tok(/\*/) && Selector::Universal.new(nil)))
|
791
|
-
res << v
|
740
|
+
# Tries to parse a declaration, and returns the value parsed so far if it
|
741
|
+
# fails.
|
742
|
+
#
|
743
|
+
# This has three possible return types. It can return `nil`, indicating
|
744
|
+
# that parsing failed completely and the scanner hasn't moved forward at
|
745
|
+
# all. It can return an Array, indicating that parsing failed after
|
746
|
+
# consuming some text (possibly containing interpolation), which is
|
747
|
+
# returned. Or it can return a PropNode, indicating that parsing
|
748
|
+
# succeeded.
|
749
|
+
def try_declaration
|
750
|
+
# This allows the "*prop: val", ":prop: val", "#prop: val", and ".prop:
|
751
|
+
# val" hacks.
|
752
|
+
name_start_pos = source_position
|
753
|
+
if (s = tok(/[:\*\.]|\#(?!\{)/))
|
754
|
+
name = [s, str {ss}]
|
755
|
+
return name unless (ident = interp_ident)
|
756
|
+
name << ident
|
757
|
+
else
|
758
|
+
return unless (name = interp_ident)
|
759
|
+
name = Array(name)
|
792
760
|
end
|
793
761
|
|
794
|
-
|
795
|
-
|
796
|
-
if (sel = str? {simple_selector_sequence})
|
797
|
-
@scanner.pos = pos
|
798
|
-
@line = line
|
799
|
-
begin
|
800
|
-
# If we see "*E", don't force a throw because this could be the
|
801
|
-
# "*prop: val" hack.
|
802
|
-
expected('"{"') if res.length == 1 && res[0].is_a?(Selector::Universal)
|
803
|
-
throw_error {expected('"{"')}
|
804
|
-
rescue Sass::SyntaxError => e
|
805
|
-
e.message << "\n\n\"#{sel}\" may only be used at the beginning of a compound selector."
|
806
|
-
raise e
|
807
|
-
end
|
762
|
+
if (comment = tok(COMMENT))
|
763
|
+
name << comment
|
808
764
|
end
|
765
|
+
name_end_pos = source_position
|
809
766
|
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
def class_selector
|
819
|
-
return unless tok(/\./)
|
820
|
-
@expected = "class name"
|
821
|
-
Selector::Class.new(merge(expr!(:interp_ident)))
|
822
|
-
end
|
823
|
-
|
824
|
-
def id_selector
|
825
|
-
return unless tok(/#(?!\{)/)
|
826
|
-
@expected = "id name"
|
827
|
-
Selector::Id.new(merge(expr!(:interp_name)))
|
828
|
-
end
|
829
|
-
|
830
|
-
def placeholder_selector
|
831
|
-
return unless tok(/%/)
|
832
|
-
@expected = "placeholder name"
|
833
|
-
Selector::Placeholder.new(merge(expr!(:interp_ident)))
|
834
|
-
end
|
835
|
-
|
836
|
-
def element_name
|
837
|
-
ns, name = Sass::Util.destructure(qualified_name(:allow_star_name))
|
838
|
-
return unless ns || name
|
767
|
+
mid = [str {ss}]
|
768
|
+
return name + mid unless tok(/:/)
|
769
|
+
mid << ':'
|
770
|
+
return name + mid + [':'] if tok(/:/)
|
771
|
+
mid << str {ss}
|
772
|
+
post_colon_whitespace = !mid.last.empty?
|
773
|
+
could_be_selector = !post_colon_whitespace && (tok?(IDENT_START) || tok?(INTERP_START))
|
839
774
|
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
775
|
+
value_start_pos = source_position
|
776
|
+
value = nil
|
777
|
+
error = catch_error do
|
778
|
+
value = value!(name.first.is_a?(String) && name.first.start_with?("--"))
|
779
|
+
if tok?(/\{/)
|
780
|
+
# Properties that are ambiguous with selectors can't have additional
|
781
|
+
# properties nested beneath them.
|
782
|
+
tok!(/;/) if could_be_selector
|
783
|
+
elsif !tok?(/[;{}]/)
|
784
|
+
# We want an exception if there's no valid end-of-property character
|
785
|
+
# exists, but we don't want to consume it if it does.
|
786
|
+
tok!(/[;{}]/)
|
787
|
+
end
|
844
788
|
end
|
845
|
-
end
|
846
789
|
|
847
|
-
|
848
|
-
|
849
|
-
return unless name
|
850
|
-
return nil, name unless tok(/\|/)
|
790
|
+
if error
|
791
|
+
rethrow error unless could_be_selector
|
851
792
|
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
793
|
+
# If the value would be followed by a semicolon, it's definitely
|
794
|
+
# supposed to be a property, not a selector.
|
795
|
+
additional_selector = almost_any_value
|
796
|
+
rethrow error if tok?(/;/)
|
856
797
|
|
857
|
-
|
858
|
-
if (script = interpolation)
|
859
|
-
Selector::Interpolation.new(script)
|
798
|
+
return name + mid + (additional_selector || [])
|
860
799
|
end
|
861
|
-
end
|
862
800
|
|
863
|
-
|
864
|
-
return unless tok(/\[/)
|
865
|
-
ss
|
866
|
-
ns, name = attrib_name!
|
801
|
+
value_end_pos = source_position
|
867
802
|
ss
|
803
|
+
require_block = tok?(/\{/)
|
868
804
|
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
tok(SUFFIXMATCH) ||
|
874
|
-
tok(SUBSTRINGMATCH)
|
875
|
-
if op
|
876
|
-
@expected = "identifier or string"
|
877
|
-
ss
|
878
|
-
val = interp_ident || expr!(:interp_string)
|
879
|
-
ss
|
880
|
-
end
|
881
|
-
flags = interp_ident || interp_string
|
882
|
-
tok!(/\]/)
|
883
|
-
|
884
|
-
Selector::Attribute.new(merge(name), merge(ns), op, merge(val), merge(flags))
|
885
|
-
end
|
886
|
-
|
887
|
-
def attrib_name!
|
888
|
-
if (name_or_ns = interp_ident)
|
889
|
-
# E, E|E
|
890
|
-
if tok(/\|(?!=)/)
|
891
|
-
ns = name_or_ns
|
892
|
-
name = interp_ident
|
893
|
-
else
|
894
|
-
name = name_or_ns
|
895
|
-
end
|
896
|
-
else
|
897
|
-
# *|E or |E
|
898
|
-
ns = [tok(/\*/) || ""]
|
899
|
-
tok!(/\|/)
|
900
|
-
name = expr!(:interp_ident)
|
901
|
-
end
|
902
|
-
return ns, name
|
903
|
-
end
|
904
|
-
|
905
|
-
def pseudo
|
906
|
-
s = tok(/::?/)
|
907
|
-
return unless s
|
908
|
-
@expected = "pseudoclass or pseudoelement"
|
909
|
-
name = expr!(:interp_ident)
|
910
|
-
if tok(/\(/)
|
911
|
-
ss
|
912
|
-
arg = expr!(:pseudo_arg)
|
913
|
-
while tok(/,/)
|
914
|
-
arg << ',' << str {ss}
|
915
|
-
arg.concat expr!(:pseudo_arg)
|
916
|
-
end
|
917
|
-
tok!(/\)/)
|
918
|
-
end
|
919
|
-
Selector::Pseudo.new(s == ':' ? :class : :element, merge(name), merge(arg))
|
920
|
-
end
|
921
|
-
|
922
|
-
def pseudo_arg
|
923
|
-
# In the CSS spec, every pseudo-class/element either takes a pseudo
|
924
|
-
# expression or a selector comma sequence as an argument. However, we
|
925
|
-
# don't want to have to know which takes which, so we handle both at
|
926
|
-
# once.
|
927
|
-
#
|
928
|
-
# However, there are some ambiguities between the two. For instance, "n"
|
929
|
-
# could start a pseudo expression like "n+1", or it could start a
|
930
|
-
# selector like "n|m". In order to handle this, we must regrettably
|
931
|
-
# backtrack.
|
932
|
-
expr, sel = nil, nil
|
933
|
-
pseudo_err = catch_error do
|
934
|
-
expr = pseudo_expr
|
935
|
-
next if tok?(/[,)]/)
|
936
|
-
expr = nil
|
937
|
-
expected '")"'
|
938
|
-
end
|
939
|
-
|
940
|
-
return expr if expr
|
941
|
-
sel_err = catch_error {sel = selector}
|
942
|
-
return sel if sel
|
943
|
-
rethrow pseudo_err if pseudo_err
|
944
|
-
rethrow sel_err if sel_err
|
945
|
-
nil
|
946
|
-
end
|
805
|
+
node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new),
|
806
|
+
name_start_pos, value_end_pos)
|
807
|
+
node.name_source_range = range(name_start_pos, name_end_pos)
|
808
|
+
node.value_source_range = range(value_start_pos, value_end_pos)
|
947
809
|
|
948
|
-
|
949
|
-
|
810
|
+
return node unless require_block
|
811
|
+
nested_properties! node
|
950
812
|
end
|
951
813
|
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
814
|
+
# This production is similar to the CSS [`<any-value>`][any-value]
|
815
|
+
# production, but as the name implies, not quite the same. It's meant to
|
816
|
+
# consume values that could be a selector, an expression, or a combination
|
817
|
+
# of both. It respects strings and comments and supports interpolation. It
|
818
|
+
# will consume up to "{", "}", ";", or "!".
|
819
|
+
#
|
820
|
+
# [any-value]: http://dev.w3.org/csswg/css-variables/#typedef-any-value
|
821
|
+
#
|
822
|
+
# Values consumed by this production will usually be parsed more
|
823
|
+
# thoroughly once interpolation has been resolved.
|
824
|
+
def almost_any_value
|
825
|
+
return unless (tok = almost_any_value_token)
|
826
|
+
sel = [tok]
|
827
|
+
while (tok = almost_any_value_token)
|
828
|
+
sel << tok
|
958
829
|
end
|
959
|
-
|
830
|
+
merge(sel)
|
831
|
+
end
|
832
|
+
|
833
|
+
def almost_any_value_token
|
834
|
+
tok(%r{
|
835
|
+
(
|
836
|
+
\\.
|
837
|
+
|
|
838
|
+
(?!url\()
|
839
|
+
[^"'/\#!;\{\}] # "
|
840
|
+
|
|
841
|
+
# interp_uri will handle most url() calls, but not ones that take strings
|
842
|
+
url\(#{W}(?=")
|
843
|
+
|
|
844
|
+
/(?![/*])
|
845
|
+
|
|
846
|
+
\#(?!\{)
|
847
|
+
|
|
848
|
+
!(?![a-z]) # TODO: never consume "!" when issue 1126 is fixed.
|
849
|
+
)+
|
850
|
+
}xi) || tok(COMMENT) || tok(SINGLE_LINE_COMMENT) || interp_string || interp_uri ||
|
851
|
+
interpolation(:warn_for_color)
|
960
852
|
end
|
961
853
|
|
962
854
|
def declaration
|
963
|
-
# This allows the "*prop: val", ":prop: val",
|
855
|
+
# This allows the "*prop: val", ":prop: val", "#prop: val", and ".prop:
|
856
|
+
# val" hacks.
|
964
857
|
name_start_pos = source_position
|
965
858
|
if (s = tok(/[:\*\.]|\#(?!\{)/))
|
966
|
-
@use_property_exception = s !~ /[\.\#]/
|
967
859
|
name = [s, str {ss}, *expr!(:interp_ident)]
|
968
860
|
else
|
969
|
-
name = interp_ident
|
970
|
-
|
971
|
-
name = [name] if name.is_a?(String)
|
861
|
+
return unless (name = interp_ident)
|
862
|
+
name = Array(name)
|
972
863
|
end
|
864
|
+
|
973
865
|
if (comment = tok(COMMENT))
|
974
866
|
name << comment
|
975
867
|
end
|
@@ -977,7 +869,9 @@ module Sass
|
|
977
869
|
ss
|
978
870
|
|
979
871
|
tok!(/:/)
|
980
|
-
|
872
|
+
ss
|
873
|
+
value_start_pos = source_position
|
874
|
+
value = value!(name.first.is_a?(String) && name.first.start_with?("--"))
|
981
875
|
value_end_pos = source_position
|
982
876
|
ss
|
983
877
|
require_block = tok?(/\{/)
|
@@ -988,19 +882,15 @@ module Sass
|
|
988
882
|
node.value_source_range = range(value_start_pos, value_end_pos)
|
989
883
|
|
990
884
|
return node unless require_block
|
991
|
-
nested_properties! node
|
885
|
+
nested_properties! node
|
992
886
|
end
|
993
887
|
|
994
|
-
def value!
|
995
|
-
space = !str {ss}.empty?
|
996
|
-
value_start_pos = source_position
|
997
|
-
@use_property_exception ||= space || !tok?(IDENT)
|
998
|
-
|
888
|
+
def value!(css_variable = false)
|
999
889
|
if tok?(/\{/)
|
1000
890
|
str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
|
1001
891
|
str.line = source_position.line
|
1002
892
|
str.source_range = range(source_position)
|
1003
|
-
return
|
893
|
+
return str
|
1004
894
|
end
|
1005
895
|
|
1006
896
|
start_pos = source_position
|
@@ -1013,18 +903,21 @@ module Sass
|
|
1013
903
|
str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(val.strip))
|
1014
904
|
str.line = start_pos.line
|
1015
905
|
str.source_range = range(start_pos)
|
1016
|
-
return
|
906
|
+
return str
|
1017
907
|
end
|
1018
|
-
|
908
|
+
|
909
|
+
sass_script(:parse, css_variable)
|
1019
910
|
end
|
1020
911
|
|
1021
|
-
def nested_properties!(node
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
912
|
+
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
|
1026
920
|
|
1027
|
-
@use_property_exception = true
|
1028
921
|
@expected = 'expression (e.g. 1px, bold) or "{"'
|
1029
922
|
block(node, :property)
|
1030
923
|
end
|
@@ -1078,9 +971,14 @@ MESSAGE
|
|
1078
971
|
var
|
1079
972
|
end
|
1080
973
|
|
1081
|
-
def interpolation
|
974
|
+
def interpolation(warn_for_color = false)
|
1082
975
|
return unless tok(INTERP_START)
|
1083
|
-
sass_script(:parse_interpolated)
|
976
|
+
sass_script(:parse_interpolated, warn_for_color)
|
977
|
+
end
|
978
|
+
|
979
|
+
def string
|
980
|
+
return unless tok(STRING)
|
981
|
+
Sass::Script::Value::String.value(@scanner[1] || @scanner[2])
|
1084
982
|
end
|
1085
983
|
|
1086
984
|
def interp_string
|
@@ -1107,10 +1005,10 @@ MESSAGE
|
|
1107
1005
|
end
|
1108
1006
|
|
1109
1007
|
def interp_ident(start = IDENT)
|
1110
|
-
val = tok(start) || interpolation || tok(IDENT_HYPHEN_INTERP, true)
|
1008
|
+
val = tok(start) || interpolation(:warn_for_color) || tok(IDENT_HYPHEN_INTERP, true)
|
1111
1009
|
return unless val
|
1112
1010
|
res = [val]
|
1113
|
-
while (val = tok(NAME) || interpolation)
|
1011
|
+
while (val = tok(NAME) || interpolation(:warn_for_color))
|
1114
1012
|
res << val
|
1115
1013
|
end
|
1116
1014
|
res
|
@@ -1123,12 +1021,8 @@ MESSAGE
|
|
1123
1021
|
return [var] if var
|
1124
1022
|
end
|
1125
1023
|
|
1126
|
-
def interp_name
|
1127
|
-
interp_ident NAME
|
1128
|
-
end
|
1129
|
-
|
1130
1024
|
def str
|
1131
|
-
@strs.push ""
|
1025
|
+
@strs.push String.new("")
|
1132
1026
|
yield
|
1133
1027
|
@strs.last
|
1134
1028
|
ensure
|
@@ -1156,8 +1050,7 @@ MESSAGE
|
|
1156
1050
|
node
|
1157
1051
|
end
|
1158
1052
|
|
1159
|
-
@sass_script_parser =
|
1160
|
-
@sass_script_parser.send(:include, ScriptParser)
|
1053
|
+
@sass_script_parser = Sass::Script::Parser
|
1161
1054
|
|
1162
1055
|
class << self
|
1163
1056
|
# @private
|
@@ -1166,7 +1059,7 @@ MESSAGE
|
|
1166
1059
|
|
1167
1060
|
def sass_script(*args)
|
1168
1061
|
parser = self.class.sass_script_parser.new(@scanner, @line, @offset,
|
1169
|
-
|
1062
|
+
:filename => @filename, :importer => @importer, :allow_extra_text => true)
|
1170
1063
|
result = parser.send(*args)
|
1171
1064
|
unless @strs.empty?
|
1172
1065
|
# Convert to CSS manually so that comments are ignored.
|
@@ -1191,25 +1084,26 @@ MESSAGE
|
|
1191
1084
|
:media_expr => "media expression (e.g. (min-device-width: 800px))",
|
1192
1085
|
:at_root_query => "@at-root query (e.g. (without: media))",
|
1193
1086
|
:at_root_directive_list => '* or identifier',
|
1194
|
-
:
|
1087
|
+
:pseudo_args => "expression (e.g. fr, 2n+1)",
|
1195
1088
|
:interp_ident => "identifier",
|
1196
|
-
:interp_name => "identifier",
|
1197
1089
|
:qualified_name => "identifier",
|
1198
1090
|
:expr => "expression (e.g. 1px, bold)",
|
1199
|
-
:_selector => "selector",
|
1200
1091
|
:selector_comma_sequence => "selector",
|
1201
|
-
:
|
1092
|
+
:string => "string",
|
1202
1093
|
:import_arg => "file to import (string or url())",
|
1203
1094
|
:moz_document_function => "matching function (e.g. url-prefix(), domain())",
|
1204
1095
|
:supports_condition => "@supports condition (e.g. (display: flexbox))",
|
1205
1096
|
:supports_condition_in_parens => "@supports condition (e.g. (display: flexbox))",
|
1097
|
+
:a_n_plus_b => "An+B expression",
|
1098
|
+
:keyframes_selector_component => "from, to, or a percentage",
|
1099
|
+
:keyframes_selector => "keyframes selector (e.g. 10%)"
|
1206
1100
|
}
|
1207
1101
|
|
1208
1102
|
TOK_NAMES = Sass::Util.to_hash(Sass::SCSS::RX.constants.map do |c|
|
1209
1103
|
[Sass::SCSS::RX.const_get(c), c.downcase]
|
1210
1104
|
end).merge(
|
1211
1105
|
IDENT => "identifier",
|
1212
|
-
/[;}]/ => '";"',
|
1106
|
+
/[;{}]/ => '";"',
|
1213
1107
|
/\b(without|with)\b/ => '"with" or "without"'
|
1214
1108
|
)
|
1215
1109
|
|
@@ -1230,8 +1124,9 @@ MESSAGE
|
|
1230
1124
|
|
1231
1125
|
unless name
|
1232
1126
|
# Display basic regexps as plain old strings
|
1127
|
+
source = rx.source.gsub(%r{\\/}, '/')
|
1233
1128
|
string = rx.source.gsub(/\\(.)/, '\1')
|
1234
|
-
name =
|
1129
|
+
name = source == Regexp.escape(string) ? string.inspect : rx.inspect
|
1235
1130
|
end
|
1236
1131
|
|
1237
1132
|
expected(name)
|
@@ -1260,14 +1155,20 @@ MESSAGE
|
|
1260
1155
|
line = @line
|
1261
1156
|
offset = @offset
|
1262
1157
|
expected = @expected
|
1158
|
+
|
1159
|
+
logger = Sass::Logger::Delayed.install!
|
1263
1160
|
if catch(:_sass_parser_error) {yield; false}
|
1264
1161
|
@scanner.pos = pos
|
1265
1162
|
@line = line
|
1266
1163
|
@offset = offset
|
1267
1164
|
@expected = expected
|
1268
1165
|
{:pos => pos, :line => line, :expected => @expected, :block => block}
|
1166
|
+
else
|
1167
|
+
logger.flush
|
1168
|
+
nil
|
1269
1169
|
end
|
1270
1170
|
ensure
|
1171
|
+
logger.uninstall! if logger
|
1271
1172
|
@throw_error = old_throw_error
|
1272
1173
|
end
|
1273
1174
|
|
@@ -1314,33 +1215,39 @@ MESSAGE
|
|
1314
1215
|
|
1315
1216
|
def tok(rx, last_group_lookahead = false)
|
1316
1217
|
res = @scanner.scan(rx)
|
1317
|
-
if res
|
1318
|
-
# This fixes https://github.com/nex3/sass/issues/104, which affects
|
1319
|
-
# Ruby 1.8.7 and REE. This fix is to replace the ?= zero-width
|
1320
|
-
# positive lookahead operator in the Regexp (which matches without
|
1321
|
-
# consuming the matched group), with a match that does consume the
|
1322
|
-
# group, but then rewinds the scanner and removes the group from the
|
1323
|
-
# end of the matched string. This fix makes the assumption that the
|
1324
|
-
# matched group will always occur at the end of the match.
|
1325
|
-
if last_group_lookahead && @scanner[-1]
|
1326
|
-
@scanner.pos -= @scanner[-1].length
|
1327
|
-
res.slice!(-@scanner[-1].length..-1)
|
1328
|
-
end
|
1329
1218
|
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
|
1335
|
-
|
1336
|
-
|
1219
|
+
return unless res
|
1220
|
+
|
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
|
1337
1232
|
|
1338
|
-
|
1339
|
-
|
1340
|
-
|
1341
|
-
|
1342
|
-
|
1233
|
+
newline_count = res.count(NEWLINE)
|
1234
|
+
if newline_count > 0
|
1235
|
+
@line += newline_count
|
1236
|
+
@offset = res[res.rindex(NEWLINE)..-1].size
|
1237
|
+
else
|
1238
|
+
@offset += res.size
|
1343
1239
|
end
|
1240
|
+
|
1241
|
+
@expected = nil
|
1242
|
+
if !@strs.empty? && rx != COMMENT && rx != SINGLE_LINE_COMMENT
|
1243
|
+
@strs.each {|s| s << res}
|
1244
|
+
end
|
1245
|
+
res
|
1246
|
+
end
|
1247
|
+
|
1248
|
+
# Remove a vendor prefix from `str`.
|
1249
|
+
def deprefix(str)
|
1250
|
+
str.gsub(/^-[a-zA-Z0-9]+-/, '')
|
1344
1251
|
end
|
1345
1252
|
end
|
1346
1253
|
end
|