sass 3.4.0 → 3.4.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +3 -1
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +148 -0
- data/MIT-LICENSE +1 -1
- data/README.md +26 -20
- data/Rakefile +103 -20
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/extra/sass-spec-ref.sh +32 -0
- data/extra/update_watch.rb +1 -1
- data/lib/sass/cache_stores/filesystem.rb +7 -7
- data/lib/sass/cache_stores/memory.rb +4 -5
- data/lib/sass/callbacks.rb +2 -2
- data/lib/sass/css.rb +11 -10
- data/lib/sass/deprecation.rb +55 -0
- data/lib/sass/engine.rb +83 -38
- data/lib/sass/environment.rb +26 -2
- data/lib/sass/error.rb +12 -12
- data/lib/sass/exec/base.rb +15 -3
- data/lib/sass/exec/sass_convert.rb +34 -15
- data/lib/sass/exec/sass_scss.rb +23 -7
- data/lib/sass/features.rb +2 -2
- data/lib/sass/importers/base.rb +1 -1
- data/lib/sass/importers/deprecated_path.rb +51 -0
- data/lib/sass/importers/filesystem.rb +24 -16
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +8 -2
- data/lib/sass/logger/delayed.rb +50 -0
- data/lib/sass/logger.rb +8 -3
- data/lib/sass/plugin/compiler.rb +42 -25
- data/lib/sass/plugin/configuration.rb +38 -22
- data/lib/sass/plugin/merb.rb +2 -2
- data/lib/sass/plugin/rack.rb +3 -3
- data/lib/sass/plugin/rails.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +3 -3
- data/lib/sass/plugin.rb +3 -2
- data/lib/sass/script/css_parser.rb +2 -3
- data/lib/sass/script/css_variable_warning.rb +52 -0
- data/lib/sass/script/functions.rb +140 -73
- data/lib/sass/script/lexer.rb +37 -22
- data/lib/sass/script/parser.rb +235 -40
- data/lib/sass/script/tree/funcall.rb +12 -5
- data/lib/sass/script/tree/interpolation.rb +109 -4
- data/lib/sass/script/tree/list_literal.rb +31 -4
- data/lib/sass/script/tree/literal.rb +4 -0
- data/lib/sass/script/tree/node.rb +21 -3
- data/lib/sass/script/tree/operation.rb +54 -1
- data/lib/sass/script/tree/string_interpolation.rb +58 -37
- data/lib/sass/script/tree/variable.rb +1 -1
- data/lib/sass/script/value/base.rb +10 -9
- data/lib/sass/script/value/color.rb +42 -24
- data/lib/sass/script/value/helpers.rb +16 -6
- data/lib/sass/script/value/map.rb +1 -1
- data/lib/sass/script/value/number.rb +52 -19
- data/lib/sass/script/value/string.rb +46 -5
- data/lib/sass/script.rb +3 -3
- data/lib/sass/scss/css_parser.rb +16 -2
- data/lib/sass/scss/parser.rb +120 -75
- data/lib/sass/scss/rx.rb +9 -10
- data/lib/sass/scss/static_parser.rb +19 -14
- data/lib/sass/scss.rb +0 -2
- data/lib/sass/selector/abstract_sequence.rb +8 -6
- data/lib/sass/selector/comma_sequence.rb +25 -9
- data/lib/sass/selector/pseudo.rb +45 -35
- data/lib/sass/selector/sequence.rb +54 -18
- data/lib/sass/selector/simple.rb +11 -11
- data/lib/sass/selector/simple_sequence.rb +34 -15
- data/lib/sass/selector.rb +7 -10
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/source/map.rb +7 -4
- data/lib/sass/source/position.rb +4 -4
- data/lib/sass/stack.rb +2 -2
- data/lib/sass/supports.rb +8 -10
- data/lib/sass/tree/comment_node.rb +1 -1
- data/lib/sass/tree/css_import_node.rb +9 -1
- data/lib/sass/tree/function_node.rb +8 -3
- data/lib/sass/tree/import_node.rb +6 -5
- data/lib/sass/tree/node.rb +5 -3
- data/lib/sass/tree/prop_node.rb +5 -6
- data/lib/sass/tree/rule_node.rb +14 -4
- data/lib/sass/tree/visitors/check_nesting.rb +18 -22
- data/lib/sass/tree/visitors/convert.rb +43 -26
- data/lib/sass/tree/visitors/cssize.rb +5 -1
- data/lib/sass/tree/visitors/deep_copy.rb +1 -1
- data/lib/sass/tree/visitors/extend.rb +15 -13
- data/lib/sass/tree/visitors/perform.rb +42 -17
- data/lib/sass/tree/visitors/set_options.rb +1 -1
- data/lib/sass/tree/visitors/to_css.rb +58 -30
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/normalized_map.rb +0 -1
- data/lib/sass/util/subset_map.rb +1 -2
- data/lib/sass/util.rb +125 -68
- data/lib/sass/version.rb +2 -2
- data/lib/sass.rb +10 -3
- data/test/sass/compiler_test.rb +6 -2
- data/test/sass/conversion_test.rb +187 -53
- data/test/sass/css2sass_test.rb +50 -1
- data/test/sass/css_variable_test.rb +132 -0
- data/test/sass/engine_test.rb +207 -61
- data/test/sass/exec_test.rb +10 -0
- data/test/sass/extend_test.rb +101 -29
- data/test/sass/functions_test.rb +60 -9
- data/test/sass/importer_test.rb +9 -0
- data/test/sass/more_templates/more1.sass +10 -10
- data/test/sass/more_templates/more_import.sass +2 -2
- data/test/sass/plugin_test.rb +10 -8
- data/test/sass/results/script.css +3 -3
- data/test/sass/script_conversion_test.rb +58 -29
- data/test/sass/script_test.rb +430 -53
- data/test/sass/scss/css_test.rb +73 -7
- data/test/sass/scss/rx_test.rb +4 -0
- data/test/sass/scss/scss_test.rb +309 -4
- data/test/sass/source_map_test.rb +152 -74
- data/test/sass/superselector_test.rb +19 -0
- data/test/sass/templates/_partial.sass +1 -1
- data/test/sass/templates/basic.sass +10 -10
- data/test/sass/templates/bork1.sass +1 -1
- data/test/sass/templates/bork5.sass +1 -1
- data/test/sass/templates/compact.sass +10 -10
- data/test/sass/templates/complex.sass +187 -187
- data/test/sass/templates/compressed.sass +10 -10
- data/test/sass/templates/expanded.sass +10 -10
- data/test/sass/templates/import.sass +2 -2
- data/test/sass/templates/importee.sass +3 -3
- data/test/sass/templates/mixins.sass +22 -22
- data/test/sass/templates/multiline.sass +4 -4
- data/test/sass/templates/nested.sass +13 -13
- data/test/sass/templates/parent_ref.sass +12 -12
- data/test/sass/templates/script.sass +70 -70
- data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +1 -1
- data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +2 -2
- data/test/sass/templates/subdir/subdir.sass +3 -3
- data/test/sass/templates/units.sass +10 -10
- data/test/sass/util/multibyte_string_scanner_test.rb +10 -2
- data/test/sass/util_test.rb +15 -44
- data/test/sass-spec.yml +3 -0
- data/test/test_helper.rb +5 -4
- metadata +302 -295
- data/CONTRIBUTING +0 -3
- data/lib/sass/scss/script_lexer.rb +0 -15
- data/lib/sass/scss/script_parser.rb +0 -25
data/lib/sass/scss/parser.rb
CHANGED
@@ -16,21 +16,20 @@ module Sass
|
|
16
16
|
# warnings and source maps.
|
17
17
|
# @param importer [Sass::Importers::Base] The importer used to import the
|
18
18
|
# file being parsed. Used for source maps.
|
19
|
-
# @param line [
|
19
|
+
# @param line [Integer] The 1-based line on which the source string appeared,
|
20
20
|
# if it's part of another document.
|
21
|
-
# @param offset [
|
21
|
+
# @param offset [Integer] The 1-based character (not byte) offset in the line on
|
22
22
|
# which the source string starts. Used for error reporting and sourcemap
|
23
23
|
# building.
|
24
|
-
# @comment
|
25
|
-
# rubocop:disable ParameterLists
|
26
24
|
def initialize(str, filename, importer, line = 1, offset = 1)
|
27
|
-
# rubocop:enable ParameterLists
|
28
25
|
@template = str
|
29
26
|
@filename = filename
|
30
27
|
@importer = importer
|
31
28
|
@line = line
|
32
29
|
@offset = offset
|
33
30
|
@strs = []
|
31
|
+
@expected = nil
|
32
|
+
@throw_error = false
|
34
33
|
end
|
35
34
|
|
36
35
|
# Parses an SCSS document.
|
@@ -55,6 +54,15 @@ module Sass
|
|
55
54
|
interp_ident
|
56
55
|
end
|
57
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
|
+
|
58
66
|
# Parses a media query list.
|
59
67
|
#
|
60
68
|
# @return [Sass::Media::QueryList] The parsed query list
|
@@ -108,7 +116,7 @@ module Sass
|
|
108
116
|
if @template.is_a?(StringScanner)
|
109
117
|
@template
|
110
118
|
else
|
111
|
-
Sass::Util::MultibyteStringScanner.new(@template.
|
119
|
+
Sass::Util::MultibyteStringScanner.new(@template.tr("\r", ""))
|
112
120
|
end
|
113
121
|
end
|
114
122
|
|
@@ -150,21 +158,16 @@ module Sass
|
|
150
158
|
silent = text =~ %r{\A//}
|
151
159
|
loud = !silent && text =~ %r{\A/[/*]!}
|
152
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
|
153
164
|
|
154
165
|
if silent
|
155
166
|
value = [text.sub(%r{\A\s*//}, '/*').gsub(%r{^\s*//}, ' *') + ' */']
|
156
167
|
else
|
157
|
-
value = Sass::Engine.parse_interp(
|
158
|
-
|
159
|
-
|
160
|
-
newline_before_comment = string_before_comment.rindex("\n")
|
161
|
-
last_line_before_comment =
|
162
|
-
if newline_before_comment
|
163
|
-
string_before_comment[newline_before_comment + 1..-1]
|
164
|
-
else
|
165
|
-
string_before_comment
|
166
|
-
end
|
167
|
-
value.unshift(last_line_before_comment.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]/, ' '))
|
168
171
|
end
|
169
172
|
|
170
173
|
type = if silent
|
@@ -174,8 +177,8 @@ module Sass
|
|
174
177
|
else
|
175
178
|
:normal
|
176
179
|
end
|
177
|
-
|
178
|
-
comment
|
180
|
+
start_pos = Sass::Source::Position.new(line, offset)
|
181
|
+
comment = node(Sass::Tree::CommentNode.new(value, type), start_pos)
|
179
182
|
node << comment
|
180
183
|
end
|
181
184
|
|
@@ -215,12 +218,12 @@ module Sass
|
|
215
218
|
end
|
216
219
|
|
217
220
|
def special_directive(name, start_pos)
|
218
|
-
sym = name.
|
221
|
+
sym = name.tr('-', '_').to_sym
|
219
222
|
DIRECTIVES.include?(sym) && send("#{sym}_directive", start_pos)
|
220
223
|
end
|
221
224
|
|
222
225
|
def prefixed_directive(name, start_pos)
|
223
|
-
sym = deprefix(name).
|
226
|
+
sym = deprefix(name).tr('-', '_').to_sym
|
224
227
|
PREFIXED_DIRECTIVES.include?(sym) && send("#{sym}_directive", name, start_pos)
|
225
228
|
end
|
226
229
|
|
@@ -380,16 +383,21 @@ module Sass
|
|
380
383
|
if uri
|
381
384
|
str = sass_script(:parse_string)
|
382
385
|
ss
|
386
|
+
supports = supports_clause
|
387
|
+
ss
|
383
388
|
media = media_query_list
|
384
389
|
ss
|
385
|
-
return node(Tree::CssImportNode.new(str, media.to_a), start_pos)
|
390
|
+
return node(Tree::CssImportNode.new(str, media.to_a, supports), start_pos)
|
386
391
|
end
|
387
392
|
ss
|
388
393
|
|
394
|
+
supports = supports_clause
|
395
|
+
ss
|
389
396
|
media = media_query_list
|
390
|
-
if str =~ %r{^(https?:)?//} || media || use_css_import?
|
391
|
-
return node(
|
392
|
-
|
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)
|
393
401
|
end
|
394
402
|
|
395
403
|
node(Sass::Tree::ImportNode.new(str.strip), start_pos)
|
@@ -503,7 +511,7 @@ module Sass
|
|
503
511
|
|
504
512
|
def moz_document_function
|
505
513
|
val = interp_uri || _interp_string(:url_prefix) ||
|
506
|
-
_interp_string(:domain) || function(
|
514
|
+
_interp_string(:domain) || function(false) || interpolation
|
507
515
|
return unless val
|
508
516
|
ss
|
509
517
|
val
|
@@ -549,10 +557,23 @@ module Sass
|
|
549
557
|
node(node, start_pos)
|
550
558
|
end
|
551
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
|
+
|
552
569
|
def supports_condition
|
553
570
|
supports_negation || supports_operator || supports_interpolation
|
554
571
|
end
|
555
572
|
|
573
|
+
def import_supports_condition
|
574
|
+
supports_condition || supports_declaration
|
575
|
+
end
|
576
|
+
|
556
577
|
def supports_negation
|
557
578
|
return unless tok(/not/i)
|
558
579
|
ss
|
@@ -562,7 +583,9 @@ module Sass
|
|
562
583
|
def supports_operator
|
563
584
|
cond = supports_condition_in_parens
|
564
585
|
return unless cond
|
565
|
-
|
586
|
+
re = /and|or/i
|
587
|
+
while (op = tok(re))
|
588
|
+
re = /#{op}/i
|
566
589
|
ss
|
567
590
|
cond = Sass::Supports::Operator.new(
|
568
591
|
cond, expr!(:supports_condition_in_parens), op)
|
@@ -570,6 +593,13 @@ module Sass
|
|
570
593
|
cond
|
571
594
|
end
|
572
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
|
+
|
573
603
|
def supports_condition_in_parens
|
574
604
|
interp = supports_interpolation
|
575
605
|
return interp if interp
|
@@ -578,19 +608,12 @@ module Sass
|
|
578
608
|
tok!(/\)/); ss
|
579
609
|
cond
|
580
610
|
else
|
581
|
-
|
582
|
-
tok!(/:/); ss
|
583
|
-
value = sass_script(:parse)
|
611
|
+
decl = supports_declaration
|
584
612
|
tok!(/\)/); ss
|
585
|
-
|
613
|
+
decl
|
586
614
|
end
|
587
615
|
end
|
588
616
|
|
589
|
-
def supports_declaration_condition
|
590
|
-
return unless tok(/\(/); ss
|
591
|
-
supports_declaration_body
|
592
|
-
end
|
593
|
-
|
594
617
|
def supports_interpolation
|
595
618
|
interp = interpolation
|
596
619
|
return unless interp
|
@@ -626,14 +649,15 @@ module Sass
|
|
626
649
|
# are disallowed by the CSS spec,
|
627
650
|
# but they're included here for compatibility
|
628
651
|
# with some proprietary MS properties
|
629
|
-
str {ss if tok(
|
652
|
+
str {ss if tok(%r{[/,:.=]})}
|
630
653
|
end
|
631
654
|
|
632
655
|
def ruleset
|
633
656
|
start_pos = source_position
|
634
657
|
return unless (rules = almost_any_value)
|
635
|
-
block(
|
636
|
-
|
658
|
+
block(
|
659
|
+
node(
|
660
|
+
Sass::Tree::RuleNode.new(rules, range(start_pos)), start_pos), :ruleset)
|
637
661
|
end
|
638
662
|
|
639
663
|
def block(node, context)
|
@@ -708,8 +732,9 @@ module Sass
|
|
708
732
|
selector << additional_selector
|
709
733
|
end
|
710
734
|
|
711
|
-
block(
|
712
|
-
|
735
|
+
block(
|
736
|
+
node(
|
737
|
+
Sass::Tree::RuleNode.new(merge(selector), range(start_pos)), start_pos), :ruleset)
|
713
738
|
end
|
714
739
|
|
715
740
|
# Tries to parse a declaration, and returns the value parsed so far if it
|
@@ -750,7 +775,7 @@ module Sass
|
|
750
775
|
value_start_pos = source_position
|
751
776
|
value = nil
|
752
777
|
error = catch_error do
|
753
|
-
value = value!
|
778
|
+
value = value!(name.first.is_a?(String) && name.first.start_with?("--"))
|
754
779
|
if tok?(/\{/)
|
755
780
|
# Properties that are ambiguous with selectors can't have additional
|
756
781
|
# properties nested beneath them.
|
@@ -808,8 +833,13 @@ module Sass
|
|
808
833
|
def almost_any_value_token
|
809
834
|
tok(%r{
|
810
835
|
(
|
836
|
+
\\.
|
837
|
+
|
|
811
838
|
(?!url\()
|
812
|
-
[^"/\#!;\{\}] # "
|
839
|
+
[^"'/\#!;\{\}] # "
|
840
|
+
|
|
841
|
+
# interp_uri will handle most url() calls, but not ones that take strings
|
842
|
+
url\(#{W}(?=")
|
813
843
|
|
|
814
844
|
/(?![/*])
|
815
845
|
|
|
@@ -841,7 +871,7 @@ module Sass
|
|
841
871
|
tok!(/:/)
|
842
872
|
ss
|
843
873
|
value_start_pos = source_position
|
844
|
-
value = value!
|
874
|
+
value = value!(name.first.is_a?(String) && name.first.start_with?("--"))
|
845
875
|
value_end_pos = source_position
|
846
876
|
ss
|
847
877
|
require_block = tok?(/\{/)
|
@@ -855,7 +885,7 @@ module Sass
|
|
855
885
|
nested_properties! node
|
856
886
|
end
|
857
887
|
|
858
|
-
def value!
|
888
|
+
def value!(css_variable = false)
|
859
889
|
if tok?(/\{/)
|
860
890
|
str = Sass::Script::Tree::Literal.new(Sass::Script::Value::String.new(""))
|
861
891
|
str.line = source_position.line
|
@@ -875,10 +905,19 @@ module Sass
|
|
875
905
|
str.source_range = range(start_pos)
|
876
906
|
return str
|
877
907
|
end
|
878
|
-
|
908
|
+
|
909
|
+
sass_script(:parse, css_variable)
|
879
910
|
end
|
880
911
|
|
881
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
|
920
|
+
|
882
921
|
@expected = 'expression (e.g. 1px, bold) or "{"'
|
883
922
|
block(node, :property)
|
884
923
|
end
|
@@ -983,7 +1022,7 @@ module Sass
|
|
983
1022
|
end
|
984
1023
|
|
985
1024
|
def str
|
986
|
-
@strs.push ""
|
1025
|
+
@strs.push String.new("")
|
987
1026
|
yield
|
988
1027
|
@strs.last
|
989
1028
|
ensure
|
@@ -1011,8 +1050,7 @@ module Sass
|
|
1011
1050
|
node
|
1012
1051
|
end
|
1013
1052
|
|
1014
|
-
@sass_script_parser =
|
1015
|
-
@sass_script_parser.send(:include, ScriptParser)
|
1053
|
+
@sass_script_parser = Sass::Script::Parser
|
1016
1054
|
|
1017
1055
|
class << self
|
1018
1056
|
# @private
|
@@ -1021,7 +1059,7 @@ module Sass
|
|
1021
1059
|
|
1022
1060
|
def sass_script(*args)
|
1023
1061
|
parser = self.class.sass_script_parser.new(@scanner, @line, @offset,
|
1024
|
-
|
1062
|
+
:filename => @filename, :importer => @importer, :allow_extra_text => true)
|
1025
1063
|
result = parser.send(*args)
|
1026
1064
|
unless @strs.empty?
|
1027
1065
|
# Convert to CSS manually so that comments are ignored.
|
@@ -1086,7 +1124,7 @@ module Sass
|
|
1086
1124
|
|
1087
1125
|
unless name
|
1088
1126
|
# Display basic regexps as plain old strings
|
1089
|
-
source = rx.source.gsub(
|
1127
|
+
source = rx.source.gsub(%r{\\/}, '/')
|
1090
1128
|
string = rx.source.gsub(/\\(.)/, '\1')
|
1091
1129
|
name = source == Regexp.escape(string) ? string.inspect : rx.inspect
|
1092
1130
|
end
|
@@ -1117,14 +1155,20 @@ module Sass
|
|
1117
1155
|
line = @line
|
1118
1156
|
offset = @offset
|
1119
1157
|
expected = @expected
|
1158
|
+
|
1159
|
+
logger = Sass::Logger::Delayed.install!
|
1120
1160
|
if catch(:_sass_parser_error) {yield; false}
|
1121
1161
|
@scanner.pos = pos
|
1122
1162
|
@line = line
|
1123
1163
|
@offset = offset
|
1124
1164
|
@expected = expected
|
1125
1165
|
{:pos => pos, :line => line, :expected => @expected, :block => block}
|
1166
|
+
else
|
1167
|
+
logger.flush
|
1168
|
+
nil
|
1126
1169
|
end
|
1127
1170
|
ensure
|
1171
|
+
logger.uninstall! if logger
|
1128
1172
|
@throw_error = old_throw_error
|
1129
1173
|
end
|
1130
1174
|
|
@@ -1171,33 +1215,34 @@ module Sass
|
|
1171
1215
|
|
1172
1216
|
def tok(rx, last_group_lookahead = false)
|
1173
1217
|
res = @scanner.scan(rx)
|
1174
|
-
if res
|
1175
|
-
# This fixes https://github.com/nex3/sass/issues/104, which affects
|
1176
|
-
# Ruby 1.8.7 and REE. This fix is to replace the ?= zero-width
|
1177
|
-
# positive lookahead operator in the Regexp (which matches without
|
1178
|
-
# consuming the matched group), with a match that does consume the
|
1179
|
-
# group, but then rewinds the scanner and removes the group from the
|
1180
|
-
# end of the matched string. This fix makes the assumption that the
|
1181
|
-
# matched group will always occur at the end of the match.
|
1182
|
-
if last_group_lookahead && @scanner[-1]
|
1183
|
-
@scanner.pos -= @scanner[-1].length
|
1184
|
-
res.slice!(-@scanner[-1].length..-1)
|
1185
|
-
end
|
1186
1218
|
|
1187
|
-
|
1188
|
-
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
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
|
1194
1232
|
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
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
|
1200
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
|
1201
1246
|
end
|
1202
1247
|
|
1203
1248
|
# Remove a vendor prefix from `str`.
|
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" % Sass::Util.ord(c) unless c =~
|
35
|
+
return "\\%06x" % (Sass::Util.ord(c)) unless c =~ %r{[ -/:-~]}
|
36
36
|
"\\#{c}"
|
37
37
|
end
|
38
38
|
|
@@ -40,7 +40,7 @@ module Sass
|
|
40
40
|
# escaping all significant characters.
|
41
41
|
#
|
42
42
|
# @param str [String] The text of the regexp
|
43
|
-
# @param flags [
|
43
|
+
# @param flags [Integer] Flags for the created regular expression
|
44
44
|
# @return [Regexp]
|
45
45
|
# @private
|
46
46
|
def self.quote(str, flags = 0)
|
@@ -66,7 +66,6 @@ module Sass
|
|
66
66
|
|
67
67
|
IDENT = /-*#{NMSTART}#{NMCHAR}*/
|
68
68
|
NAME = /#{NMCHAR}+/
|
69
|
-
NUM = //
|
70
69
|
STRING = /#{STRING1}|#{STRING2}/
|
71
70
|
URLCHAR = /[#%&*-~]|#{NONASCII}|#{ESCAPE}/
|
72
71
|
URL = /(#{URLCHAR}*)/
|
@@ -96,8 +95,13 @@ module Sass
|
|
96
95
|
|
97
96
|
IMPORTANT = /!#{W}important/i
|
98
97
|
|
98
|
+
# A unit is like an IDENT, but disallows a hyphen followed by a digit.
|
99
|
+
# This allows "1px-2px" to be interpreted as subtraction rather than "1"
|
100
|
+
# with the unit "px-2px". It also allows "%".
|
101
|
+
UNIT = /-?#{NMSTART}(?:[a-zA-Z0-9_]|#{NONASCII}|#{ESCAPE}|-(?!\.?\d))*|%/
|
102
|
+
|
99
103
|
UNITLESS_NUMBER = /(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?\d+)?/
|
100
|
-
NUMBER = /#{UNITLESS_NUMBER}(?:#{
|
104
|
+
NUMBER = /#{UNITLESS_NUMBER}(?:#{UNIT})?/
|
101
105
|
PERCENTAGE = /#{UNITLESS_NUMBER}%/
|
102
106
|
|
103
107
|
URI = /url\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
|
@@ -123,18 +127,13 @@ module Sass
|
|
123
127
|
OPTIONAL = /!#{W}optional/i
|
124
128
|
IDENT_START = /-|#{NMSTART}/
|
125
129
|
|
126
|
-
# A unit is like an IDENT, but disallows a hyphen followed by a digit.
|
127
|
-
# This allows "1px-2px" to be interpreted as subtraction rather than "1"
|
128
|
-
# with the unit "px-2px". It also allows "%".
|
129
|
-
UNIT = /-?#{NMSTART}(?:[a-zA-Z0-9_]|#{NONASCII}|#{ESCAPE}|-(?!\d))*|%/
|
130
|
-
|
131
130
|
IDENT_HYPHEN_INTERP = /-(#\{)/
|
132
131
|
STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|#{ESCAPE})*)\"/
|
133
132
|
STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|#{ESCAPE})*)\'/
|
134
133
|
STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
|
135
134
|
|
136
135
|
STATIC_COMPONENT = /#{IDENT}|#{STRING_NOINTERP}|#{HEXCOLOR}|[+-]?#{NUMBER}|\!important/i
|
137
|
-
STATIC_VALUE =
|
136
|
+
STATIC_VALUE = %r(#{STATIC_COMPONENT}(\s*[\s,/]\s*#{STATIC_COMPONENT})*([;}]))i
|
138
137
|
STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){1,50}([{])/i
|
139
138
|
end
|
140
139
|
end
|
@@ -62,7 +62,7 @@ module Sass
|
|
62
62
|
private
|
63
63
|
|
64
64
|
def moz_document_function
|
65
|
-
val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(
|
65
|
+
val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(false)
|
66
66
|
return unless val
|
67
67
|
ss
|
68
68
|
[val]
|
@@ -78,7 +78,7 @@ module Sass
|
|
78
78
|
def use_css_import?; true; end
|
79
79
|
|
80
80
|
def special_directive(name, start_pos)
|
81
|
-
return unless %w
|
81
|
+
return unless %w(media import charset -moz-document).include?(name)
|
82
82
|
super
|
83
83
|
end
|
84
84
|
|
@@ -89,13 +89,12 @@ module Sass
|
|
89
89
|
ws = ''
|
90
90
|
while tok(/,/)
|
91
91
|
ws << str {ss}
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
ws = ''
|
92
|
+
next unless (sel = selector)
|
93
|
+
selectors << sel
|
94
|
+
if ws.include?("\n")
|
95
|
+
selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members)
|
98
96
|
end
|
97
|
+
ws = ''
|
99
98
|
end
|
100
99
|
Selector::CommaSequence.new(selectors)
|
101
100
|
end
|
@@ -140,11 +139,18 @@ MESSAGE
|
|
140
139
|
end
|
141
140
|
|
142
141
|
def reference_combinator
|
143
|
-
return unless tok(
|
142
|
+
return unless tok(%r{/})
|
144
143
|
res = '/'
|
145
144
|
ns, name = expr!(:qualified_name)
|
146
145
|
res << ns << '|' if ns
|
147
|
-
res << name << tok!(
|
146
|
+
res << name << tok!(%r{/})
|
147
|
+
|
148
|
+
location = " of #{@filename}" if @filename
|
149
|
+
Sass::Util.sass_warn <<MESSAGE
|
150
|
+
DEPRECATION WARNING on line #{@line}, column #{@offset}#{location}:
|
151
|
+
The reference combinator #{res} is deprecated and will be removed in a future release.
|
152
|
+
MESSAGE
|
153
|
+
|
148
154
|
res
|
149
155
|
end
|
150
156
|
|
@@ -266,9 +272,9 @@ MESSAGE
|
|
266
272
|
return ns, name
|
267
273
|
end
|
268
274
|
|
269
|
-
SELECTOR_PSEUDO_CLASSES = %w
|
275
|
+
SELECTOR_PSEUDO_CLASSES = %w(not matches current any has host host-context).to_set
|
270
276
|
|
271
|
-
PREFIXED_SELECTOR_PSEUDO_CLASSES = %w
|
277
|
+
PREFIXED_SELECTOR_PSEUDO_CLASSES = %w(nth-child nth-last-child).to_set
|
272
278
|
|
273
279
|
def pseudo
|
274
280
|
s = tok(/::?/)
|
@@ -358,11 +364,10 @@ MESSAGE
|
|
358
364
|
end
|
359
365
|
|
360
366
|
def keyframes_selector_component
|
361
|
-
tok(
|
367
|
+
tok(IDENT) || tok(PERCENTAGE)
|
362
368
|
end
|
363
369
|
|
364
370
|
@sass_script_parser = Class.new(Sass::Script::CssParser)
|
365
|
-
@sass_script_parser.send(:include, ScriptParser)
|
366
371
|
end
|
367
372
|
end
|
368
373
|
end
|
data/lib/sass/scss.rb
CHANGED
@@ -8,7 +8,7 @@ module Sass
|
|
8
8
|
class AbstractSequence
|
9
9
|
# The line of the Sass template on which this selector was declared.
|
10
10
|
#
|
11
|
-
# @return [
|
11
|
+
# @return [Integer]
|
12
12
|
attr_reader :line
|
13
13
|
|
14
14
|
# The name of the file in which this selector was declared.
|
@@ -19,8 +19,8 @@ module Sass
|
|
19
19
|
# Sets the line of the Sass template on which this selector was declared.
|
20
20
|
# This also sets the line for all child selectors.
|
21
21
|
#
|
22
|
-
# @param line [
|
23
|
-
# @return [
|
22
|
+
# @param line [Integer]
|
23
|
+
# @return [Integer]
|
24
24
|
def line=(line)
|
25
25
|
members.each {|m| m.line = line}
|
26
26
|
@line = line
|
@@ -42,7 +42,7 @@ module Sass
|
|
42
42
|
# Subclasses should define `#_hash` rather than overriding this method,
|
43
43
|
# which automatically handles memoizing the result.
|
44
44
|
#
|
45
|
-
# @return [
|
45
|
+
# @return [Integer]
|
46
46
|
def hash
|
47
47
|
@_hash ||= _hash
|
48
48
|
end
|
@@ -71,8 +71,10 @@ module Sass
|
|
71
71
|
|
72
72
|
# Returns the selector string.
|
73
73
|
#
|
74
|
+
# @param opts [Hash] rendering options.
|
75
|
+
# @option opts [Symbol] :style The css rendering style.
|
74
76
|
# @return [String]
|
75
|
-
def to_s
|
77
|
+
def to_s(opts = {})
|
76
78
|
Sass::Util.abstract(self)
|
77
79
|
end
|
78
80
|
|
@@ -81,7 +83,7 @@ module Sass
|
|
81
83
|
# The base is given by {Sass::Selector::SPECIFICITY_BASE}. This can be a
|
82
84
|
# number or a range representing possible specificities.
|
83
85
|
#
|
84
|
-
# @return [
|
86
|
+
# @return [Integer, Range]
|
85
87
|
def specificity
|
86
88
|
_specificity(members)
|
87
89
|
end
|
@@ -2,6 +2,8 @@ module Sass
|
|
2
2
|
module Selector
|
3
3
|
# A comma-separated sequence of selectors.
|
4
4
|
class CommaSequence < AbstractSequence
|
5
|
+
@@compound_extend_deprecation = Sass::Deprecation.new
|
6
|
+
|
5
7
|
# The comma-separated selector sequences
|
6
8
|
# represented by this class.
|
7
9
|
#
|
@@ -25,12 +27,7 @@ module Sass
|
|
25
27
|
# @raise [Sass::SyntaxError] If a parent selector is invalid
|
26
28
|
def resolve_parent_refs(super_cseq, implicit_parent = true)
|
27
29
|
if super_cseq.nil?
|
28
|
-
if
|
29
|
-
sel.members.any? do |sel_or_op|
|
30
|
-
sel_or_op.is_a?(SimpleSequence) &&
|
31
|
-
sel_or_op.members.any? {|ssel| ssel.is_a?(Parent)}
|
32
|
-
end
|
33
|
-
end
|
30
|
+
if contains_parent_ref?
|
34
31
|
raise Sass::SyntaxError.new(
|
35
32
|
"Base-level rules cannot contain the parent-selector-referencing character '&'.")
|
36
33
|
end
|
@@ -42,6 +39,13 @@ module Sass
|
|
42
39
|
end))
|
43
40
|
end
|
44
41
|
|
42
|
+
# Returns whether there's a {Parent} selector anywhere in this sequence.
|
43
|
+
#
|
44
|
+
# @return [Boolean]
|
45
|
+
def contains_parent_ref?
|
46
|
+
@members.any? {|sel| sel.contains_parent_ref?}
|
47
|
+
end
|
48
|
+
|
45
49
|
# Non-destrucively extends this selector with the extensions specified in a hash
|
46
50
|
# (which should come from {Sass::Tree::Visitors::Cssize}).
|
47
51
|
#
|
@@ -94,8 +98,11 @@ module Sass
|
|
94
98
|
# The node that caused this extension.
|
95
99
|
# @param parent_directives [Array<Sass::Tree::DirectiveNode>]
|
96
100
|
# The parent directives containing `extend_node`.
|
101
|
+
# @param allow_compound_target [Boolean]
|
102
|
+
# Whether `extendee` is allowed to contain compound selectors.
|
97
103
|
# @raise [Sass::SyntaxError] if this extension is invalid.
|
98
|
-
def populate_extends(extends, extendee, extend_node = nil, parent_directives = []
|
104
|
+
def populate_extends(extends, extendee, extend_node = nil, parent_directives = [],
|
105
|
+
allow_compound_target = false)
|
99
106
|
extendee.members.each do |seq|
|
100
107
|
if seq.members.size > 1
|
101
108
|
raise Sass::SyntaxError.new("Can't extend #{seq}: can't extend nested selectors")
|
@@ -109,6 +116,13 @@ module Sass
|
|
109
116
|
end
|
110
117
|
|
111
118
|
sel = sseq.members
|
119
|
+
if !allow_compound_target && sel.length > 1
|
120
|
+
@@compound_extend_deprecation.warn(sseq.filename, sseq.line, <<WARNING)
|
121
|
+
Extending a compound selector, #{sseq}, is deprecated and will not be supported in a future release.
|
122
|
+
See https://github.com/sass/sass/issues/1599 for details.
|
123
|
+
WARNING
|
124
|
+
end
|
125
|
+
|
112
126
|
members.each do |member|
|
113
127
|
unless member.members.last.is_a?(Sass::Selector::SimpleSequence)
|
114
128
|
raise Sass::SyntaxError.new("#{member} can't extend: invalid selector")
|
@@ -157,8 +171,10 @@ module Sass
|
|
157
171
|
end
|
158
172
|
|
159
173
|
# @see AbstractSequence#to_s
|
160
|
-
def to_s
|
161
|
-
@members.
|
174
|
+
def to_s(opts = {})
|
175
|
+
@members.map {|m| m.to_s(opts)}.
|
176
|
+
join(opts[:style] == :compressed ? "," : ", ").
|
177
|
+
gsub(", \n", ",\n")
|
162
178
|
end
|
163
179
|
|
164
180
|
private
|