sass4 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.yardopts +13 -0
- data/AGENTS.md +534 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/CONTRIBUTING.md +148 -0
- data/MIT-LICENSE +20 -0
- data/README.md +242 -0
- data/VERSION +1 -0
- data/VERSION_NAME +1 -0
- data/bin/sass +13 -0
- data/bin/sass-convert +12 -0
- data/bin/scss +13 -0
- data/extra/sass-spec-ref.sh +40 -0
- data/extra/update_watch.rb +13 -0
- data/init.rb +18 -0
- data/lib/sass/cache_stores/base.rb +88 -0
- data/lib/sass/cache_stores/chain.rb +34 -0
- data/lib/sass/cache_stores/filesystem.rb +60 -0
- data/lib/sass/cache_stores/memory.rb +46 -0
- data/lib/sass/cache_stores/null.rb +25 -0
- data/lib/sass/cache_stores.rb +15 -0
- data/lib/sass/callbacks.rb +67 -0
- data/lib/sass/css.rb +407 -0
- data/lib/sass/deprecation.rb +55 -0
- data/lib/sass/engine.rb +1236 -0
- data/lib/sass/environment.rb +236 -0
- data/lib/sass/error.rb +198 -0
- data/lib/sass/exec/base.rb +188 -0
- data/lib/sass/exec/sass_convert.rb +283 -0
- data/lib/sass/exec/sass_scss.rb +436 -0
- data/lib/sass/exec.rb +9 -0
- data/lib/sass/features.rb +48 -0
- data/lib/sass/importers/base.rb +182 -0
- data/lib/sass/importers/deprecated_path.rb +51 -0
- data/lib/sass/importers/filesystem.rb +221 -0
- data/lib/sass/importers.rb +23 -0
- data/lib/sass/logger/base.rb +47 -0
- data/lib/sass/logger/delayed.rb +50 -0
- data/lib/sass/logger/log_level.rb +45 -0
- data/lib/sass/logger.rb +17 -0
- data/lib/sass/media.rb +210 -0
- data/lib/sass/plugin/compiler.rb +552 -0
- data/lib/sass/plugin/configuration.rb +134 -0
- data/lib/sass/plugin/generic.rb +15 -0
- data/lib/sass/plugin/merb.rb +48 -0
- data/lib/sass/plugin/rack.rb +60 -0
- data/lib/sass/plugin/rails.rb +47 -0
- data/lib/sass/plugin/staleness_checker.rb +199 -0
- data/lib/sass/plugin.rb +134 -0
- data/lib/sass/railtie.rb +10 -0
- data/lib/sass/repl.rb +57 -0
- data/lib/sass/root.rb +7 -0
- data/lib/sass/script/css_lexer.rb +33 -0
- data/lib/sass/script/css_parser.rb +36 -0
- data/lib/sass/script/functions.rb +3103 -0
- data/lib/sass/script/lexer.rb +518 -0
- data/lib/sass/script/parser.rb +1164 -0
- data/lib/sass/script/tree/funcall.rb +314 -0
- data/lib/sass/script/tree/interpolation.rb +220 -0
- data/lib/sass/script/tree/list_literal.rb +119 -0
- data/lib/sass/script/tree/literal.rb +49 -0
- data/lib/sass/script/tree/map_literal.rb +64 -0
- data/lib/sass/script/tree/node.rb +119 -0
- data/lib/sass/script/tree/operation.rb +149 -0
- data/lib/sass/script/tree/selector.rb +26 -0
- data/lib/sass/script/tree/string_interpolation.rb +125 -0
- data/lib/sass/script/tree/unary_operation.rb +69 -0
- data/lib/sass/script/tree/variable.rb +57 -0
- data/lib/sass/script/tree.rb +16 -0
- data/lib/sass/script/value/arg_list.rb +36 -0
- data/lib/sass/script/value/base.rb +258 -0
- data/lib/sass/script/value/bool.rb +35 -0
- data/lib/sass/script/value/callable.rb +25 -0
- data/lib/sass/script/value/color.rb +704 -0
- data/lib/sass/script/value/function.rb +19 -0
- data/lib/sass/script/value/helpers.rb +298 -0
- data/lib/sass/script/value/list.rb +135 -0
- data/lib/sass/script/value/map.rb +70 -0
- data/lib/sass/script/value/null.rb +44 -0
- data/lib/sass/script/value/number.rb +564 -0
- data/lib/sass/script/value/string.rb +138 -0
- data/lib/sass/script/value.rb +13 -0
- data/lib/sass/script.rb +66 -0
- data/lib/sass/scss/css_parser.rb +61 -0
- data/lib/sass/scss/parser.rb +1343 -0
- data/lib/sass/scss/rx.rb +134 -0
- data/lib/sass/scss/static_parser.rb +351 -0
- data/lib/sass/scss.rb +14 -0
- data/lib/sass/selector/abstract_sequence.rb +112 -0
- data/lib/sass/selector/comma_sequence.rb +195 -0
- data/lib/sass/selector/pseudo.rb +291 -0
- data/lib/sass/selector/sequence.rb +661 -0
- data/lib/sass/selector/simple.rb +124 -0
- data/lib/sass/selector/simple_sequence.rb +348 -0
- data/lib/sass/selector.rb +327 -0
- data/lib/sass/shared.rb +76 -0
- data/lib/sass/source/map.rb +209 -0
- data/lib/sass/source/position.rb +39 -0
- data/lib/sass/source/range.rb +41 -0
- data/lib/sass/stack.rb +140 -0
- data/lib/sass/supports.rb +225 -0
- data/lib/sass/tree/at_root_node.rb +83 -0
- data/lib/sass/tree/charset_node.rb +22 -0
- data/lib/sass/tree/comment_node.rb +82 -0
- data/lib/sass/tree/content_node.rb +9 -0
- data/lib/sass/tree/css_import_node.rb +68 -0
- data/lib/sass/tree/debug_node.rb +18 -0
- data/lib/sass/tree/directive_node.rb +59 -0
- data/lib/sass/tree/each_node.rb +24 -0
- data/lib/sass/tree/error_node.rb +18 -0
- data/lib/sass/tree/extend_node.rb +43 -0
- data/lib/sass/tree/for_node.rb +36 -0
- data/lib/sass/tree/function_node.rb +44 -0
- data/lib/sass/tree/if_node.rb +52 -0
- data/lib/sass/tree/import_node.rb +75 -0
- data/lib/sass/tree/keyframe_rule_node.rb +15 -0
- data/lib/sass/tree/media_node.rb +48 -0
- data/lib/sass/tree/mixin_def_node.rb +38 -0
- data/lib/sass/tree/mixin_node.rb +52 -0
- data/lib/sass/tree/node.rb +240 -0
- data/lib/sass/tree/prop_node.rb +162 -0
- data/lib/sass/tree/return_node.rb +19 -0
- data/lib/sass/tree/root_node.rb +44 -0
- data/lib/sass/tree/rule_node.rb +153 -0
- data/lib/sass/tree/supports_node.rb +38 -0
- data/lib/sass/tree/trace_node.rb +33 -0
- data/lib/sass/tree/variable_node.rb +36 -0
- data/lib/sass/tree/visitors/base.rb +72 -0
- data/lib/sass/tree/visitors/check_nesting.rb +173 -0
- data/lib/sass/tree/visitors/convert.rb +350 -0
- data/lib/sass/tree/visitors/cssize.rb +362 -0
- data/lib/sass/tree/visitors/deep_copy.rb +107 -0
- data/lib/sass/tree/visitors/extend.rb +64 -0
- data/lib/sass/tree/visitors/perform.rb +572 -0
- data/lib/sass/tree/visitors/set_options.rb +139 -0
- data/lib/sass/tree/visitors/to_css.rb +440 -0
- data/lib/sass/tree/warn_node.rb +18 -0
- data/lib/sass/tree/while_node.rb +18 -0
- data/lib/sass/util/multibyte_string_scanner.rb +151 -0
- data/lib/sass/util/normalized_map.rb +122 -0
- data/lib/sass/util/subset_map.rb +109 -0
- data/lib/sass/util/test.rb +9 -0
- data/lib/sass/util.rb +1137 -0
- data/lib/sass/version.rb +120 -0
- data/lib/sass.rb +102 -0
- data/rails/init.rb +1 -0
- metadata +283 -0
data/lib/sass/scss/rx.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Sass
|
3
|
+
module SCSS
|
4
|
+
# A module containing regular expressions used
|
5
|
+
# for lexing tokens in an SCSS document.
|
6
|
+
# Most of these are taken from [the CSS3 spec](http://www.w3.org/TR/css3-syntax/#lexical),
|
7
|
+
# although some have been modified for various reasons.
|
8
|
+
module RX
|
9
|
+
# Takes a string and returns a CSS identifier
|
10
|
+
# that will have the value of the given string.
|
11
|
+
#
|
12
|
+
# @param str [String] The string to escape
|
13
|
+
# @return [String] The escaped string
|
14
|
+
def self.escape_ident(str)
|
15
|
+
return "" if str.empty?
|
16
|
+
return "\\#{str}" if str == '-' || str == '_'
|
17
|
+
out = ""
|
18
|
+
value = str.dup
|
19
|
+
out << value.slice!(0...1) if value =~ /^[-_]/
|
20
|
+
if value[0...1] =~ NMSTART
|
21
|
+
out << value.slice!(0...1)
|
22
|
+
else
|
23
|
+
out << escape_char(value.slice!(0...1))
|
24
|
+
end
|
25
|
+
out << value.gsub(/[^a-zA-Z0-9_-]/) {|c| escape_char c}
|
26
|
+
out
|
27
|
+
end
|
28
|
+
|
29
|
+
# Escapes a single character for a CSS identifier.
|
30
|
+
#
|
31
|
+
# @param c [String] The character to escape. Should have length 1
|
32
|
+
# @return [String] The escaped character
|
33
|
+
# @private
|
34
|
+
def self.escape_char(c)
|
35
|
+
return "\\%06x" % c.ord unless c =~ %r{[ -/:-~]}
|
36
|
+
"\\#{c}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Creates a Regexp from a plain text string,
|
40
|
+
# escaping all significant characters.
|
41
|
+
#
|
42
|
+
# @param str [String] The text of the regexp
|
43
|
+
# @param flags [Integer] Flags for the created regular expression
|
44
|
+
# @return [Regexp]
|
45
|
+
# @private
|
46
|
+
def self.quote(str, flags = 0)
|
47
|
+
Regexp.new(Regexp.quote(str), flags)
|
48
|
+
end
|
49
|
+
|
50
|
+
H = /[0-9a-fA-F]/
|
51
|
+
NL = /\n|\r\n|\r|\f/
|
52
|
+
UNICODE = /\\#{H}{1,6}[ \t\r\n\f]?/
|
53
|
+
s = '\u{80}-\u{D7FF}\u{E000}-\u{FFFD}\u{10000}-\u{10FFFF}'
|
54
|
+
NONASCII = /[#{s}]/
|
55
|
+
ESCAPE = /#{UNICODE}|\\[^0-9a-fA-F\r\n\f]/
|
56
|
+
NMSTART = /[_a-zA-Z]|#{NONASCII}|#{ESCAPE}/
|
57
|
+
NMCHAR = /[a-zA-Z0-9_-]|#{NONASCII}|#{ESCAPE}/
|
58
|
+
STRING1 = /\"((?:[^\n\r\f\\"]|\\#{NL}|#{ESCAPE})*)\"/
|
59
|
+
STRING2 = /\'((?:[^\n\r\f\\']|\\#{NL}|#{ESCAPE})*)\'/
|
60
|
+
|
61
|
+
IDENT = /-*#{NMSTART}#{NMCHAR}*/
|
62
|
+
NAME = /#{NMCHAR}+/
|
63
|
+
STRING = /#{STRING1}|#{STRING2}/
|
64
|
+
URLCHAR = /[#%&*-~]|#{NONASCII}|#{ESCAPE}/
|
65
|
+
URL = /(#{URLCHAR}*)/
|
66
|
+
W = /[ \t\r\n\f]*/
|
67
|
+
VARIABLE = /(\$)(#{Sass::SCSS::RX::IDENT})/
|
68
|
+
|
69
|
+
# This is more liberal than the spec's definition,
|
70
|
+
# but that definition didn't work well with the greediness rules
|
71
|
+
RANGE = /(?:#{H}|\?){1,6}/
|
72
|
+
|
73
|
+
##
|
74
|
+
|
75
|
+
S = /[ \t\r\n\f]+/
|
76
|
+
|
77
|
+
COMMENT = %r{/\*([^*]|\*+[^/*])*\**\*/}
|
78
|
+
SINGLE_LINE_COMMENT = %r{//.*(\n[ \t]*//.*)*}
|
79
|
+
|
80
|
+
CDO = quote("<!--")
|
81
|
+
CDC = quote("-->")
|
82
|
+
INCLUDES = quote("~=")
|
83
|
+
DASHMATCH = quote("|=")
|
84
|
+
PREFIXMATCH = quote("^=")
|
85
|
+
SUFFIXMATCH = quote("$=")
|
86
|
+
SUBSTRINGMATCH = quote("*=")
|
87
|
+
|
88
|
+
HASH = /##{NAME}/
|
89
|
+
|
90
|
+
IMPORTANT = /!#{W}important/i
|
91
|
+
|
92
|
+
# A unit is like an IDENT, but disallows a hyphen followed by a digit.
|
93
|
+
# This allows "1px-2px" to be interpreted as subtraction rather than "1"
|
94
|
+
# with the unit "px-2px". It also allows "%".
|
95
|
+
UNIT = /-?#{NMSTART}(?:[a-zA-Z0-9_]|#{NONASCII}|#{ESCAPE}|-(?!\.?\d))*|%/
|
96
|
+
|
97
|
+
UNITLESS_NUMBER = /(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?\d+)?/
|
98
|
+
NUMBER = /#{UNITLESS_NUMBER}(?:#{UNIT})?/
|
99
|
+
PERCENTAGE = /#{UNITLESS_NUMBER}%/
|
100
|
+
|
101
|
+
URI = /url\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
|
102
|
+
FUNCTION = /#{IDENT}\(/
|
103
|
+
|
104
|
+
UNICODERANGE = /u\+(?:#{H}{1,6}-#{H}{1,6}|#{RANGE})/i
|
105
|
+
|
106
|
+
# Defined in http://www.w3.org/TR/css3-selectors/#lex
|
107
|
+
PLUS = /#{W}\+/
|
108
|
+
GREATER = /#{W}>/
|
109
|
+
TILDE = /#{W}~/
|
110
|
+
NOT = quote(":not(", Regexp::IGNORECASE)
|
111
|
+
|
112
|
+
# Defined in https://developer.mozilla.org/en/CSS/@-moz-document as a
|
113
|
+
# non-standard version of http://www.w3.org/TR/css3-conditional/
|
114
|
+
URL_PREFIX = /url-prefix\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
|
115
|
+
DOMAIN = /domain\(#{W}(?:#{STRING}|#{URL})#{W}\)/i
|
116
|
+
|
117
|
+
# Custom
|
118
|
+
HEXCOLOR = /\#[0-9a-fA-F]+/
|
119
|
+
INTERP_START = /#\{/
|
120
|
+
ANY = /:(-[-\w]+-)?any\(/i
|
121
|
+
OPTIONAL = /!#{W}optional/i
|
122
|
+
IDENT_START = /-|#{NMSTART}/
|
123
|
+
|
124
|
+
IDENT_HYPHEN_INTERP = /-+(?=#\{)/
|
125
|
+
STRING1_NOINTERP = /\"((?:[^\n\r\f\\"#]|#(?!\{)|#{ESCAPE})*)\"/
|
126
|
+
STRING2_NOINTERP = /\'((?:[^\n\r\f\\'#]|#(?!\{)|#{ESCAPE})*)\'/
|
127
|
+
STRING_NOINTERP = /#{STRING1_NOINTERP}|#{STRING2_NOINTERP}/
|
128
|
+
|
129
|
+
STATIC_COMPONENT = /#{IDENT}|#{STRING_NOINTERP}|#{HEXCOLOR}|[+-]?#{NUMBER}|\!important/i
|
130
|
+
STATIC_VALUE = %r(#{STATIC_COMPONENT}(\s*[\s,\/]\s*#{STATIC_COMPONENT})*(?=[;}]))i
|
131
|
+
STATIC_SELECTOR = /(#{NMCHAR}|[ \t]|[,>+*]|[:#.]#{NMSTART}){1,50}([{])/i
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,351 @@
|
|
1
|
+
require 'sass/script/css_parser'
|
2
|
+
|
3
|
+
module Sass
|
4
|
+
module SCSS
|
5
|
+
# A parser for a static SCSS tree.
|
6
|
+
# Parses with SCSS extensions, like nested rules and parent selectors,
|
7
|
+
# but without dynamic SassScript.
|
8
|
+
# This is useful for e.g. \{#parse\_selector parsing selectors}
|
9
|
+
# after resolving the interpolation.
|
10
|
+
class StaticParser < Parser
|
11
|
+
# Parses the text as a selector.
|
12
|
+
#
|
13
|
+
# @param filename [String, nil] The file in which the selector appears,
|
14
|
+
# or nil if there is no such file.
|
15
|
+
# Used for error reporting.
|
16
|
+
# @return [Selector::CommaSequence] The parsed selector
|
17
|
+
# @raise [Sass::SyntaxError] if there's a syntax error in the selector
|
18
|
+
def parse_selector
|
19
|
+
init_scanner!
|
20
|
+
seq = expr!(:selector_comma_sequence)
|
21
|
+
expected("selector") unless @scanner.eos?
|
22
|
+
seq.line = @line
|
23
|
+
seq.filename = @filename
|
24
|
+
seq
|
25
|
+
end
|
26
|
+
|
27
|
+
# Parses a static at-root query.
|
28
|
+
#
|
29
|
+
# @return [(Symbol, Array<String>)] The type of the query
|
30
|
+
# (`:with` or `:without`) and the values that are being filtered.
|
31
|
+
# @raise [Sass::SyntaxError] if there's a syntax error in the query,
|
32
|
+
# or if it doesn't take up the entire input string.
|
33
|
+
def parse_static_at_root_query
|
34
|
+
init_scanner!
|
35
|
+
tok!(/\(/); ss
|
36
|
+
type = tok!(/\b(without|with)\b/).to_sym; ss
|
37
|
+
tok!(/:/); ss
|
38
|
+
directives = expr!(:at_root_directive_list); ss
|
39
|
+
tok!(/\)/)
|
40
|
+
expected("@at-root query list") unless @scanner.eos?
|
41
|
+
return type, directives
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_keyframes_selector
|
45
|
+
init_scanner!
|
46
|
+
sel = expr!(:keyframes_selector)
|
47
|
+
expected("keyframes selector") unless @scanner.eos?
|
48
|
+
sel
|
49
|
+
end
|
50
|
+
|
51
|
+
# @see Parser#initialize
|
52
|
+
# @param allow_parent_ref [Boolean] Whether to allow the
|
53
|
+
# parent-reference selector, `&`, when parsing the document.
|
54
|
+
def initialize(str, filename, importer, line = 1, offset = 1, allow_parent_ref = true)
|
55
|
+
super(str, filename, importer, line, offset)
|
56
|
+
@allow_parent_ref = allow_parent_ref
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def moz_document_function
|
62
|
+
val = tok(URI) || tok(URL_PREFIX) || tok(DOMAIN) || function(false)
|
63
|
+
return unless val
|
64
|
+
ss
|
65
|
+
[val]
|
66
|
+
end
|
67
|
+
|
68
|
+
def variable; nil; end
|
69
|
+
def script_value; nil; end
|
70
|
+
def interpolation(warn_for_color = false); nil; end
|
71
|
+
def var_expr; nil; end
|
72
|
+
def interp_string; (s = tok(STRING)) && [s]; end
|
73
|
+
def interp_uri; (s = tok(URI)) && [s]; end
|
74
|
+
def interp_ident; (s = ident) && [s]; end
|
75
|
+
def use_css_import?; true; end
|
76
|
+
|
77
|
+
def special_directive(name, start_pos)
|
78
|
+
return unless %w(media import charset -moz-document).include?(name)
|
79
|
+
super
|
80
|
+
end
|
81
|
+
|
82
|
+
def selector_comma_sequence
|
83
|
+
sel = selector
|
84
|
+
return unless sel
|
85
|
+
selectors = [sel]
|
86
|
+
ws = ''
|
87
|
+
while tok(/,/)
|
88
|
+
ws << str {ss}
|
89
|
+
next unless (sel = selector)
|
90
|
+
selectors << sel
|
91
|
+
if ws.include?("\n")
|
92
|
+
selectors[-1] = Selector::Sequence.new(["\n"] + selectors.last.members)
|
93
|
+
end
|
94
|
+
ws = ''
|
95
|
+
end
|
96
|
+
Selector::CommaSequence.new(selectors)
|
97
|
+
end
|
98
|
+
|
99
|
+
def selector_string
|
100
|
+
sel = selector
|
101
|
+
return unless sel
|
102
|
+
sel.to_s
|
103
|
+
end
|
104
|
+
|
105
|
+
def selector
|
106
|
+
start_pos = source_position
|
107
|
+
# The combinator here allows the "> E" hack
|
108
|
+
val = combinator || simple_selector_sequence
|
109
|
+
return unless val
|
110
|
+
nl = str {ss}.include?("\n")
|
111
|
+
res = []
|
112
|
+
res << val
|
113
|
+
res << "\n" if nl
|
114
|
+
|
115
|
+
while (val = combinator || simple_selector_sequence)
|
116
|
+
res << val
|
117
|
+
res << "\n" if str {ss}.include?("\n")
|
118
|
+
end
|
119
|
+
seq = Selector::Sequence.new(res.compact)
|
120
|
+
|
121
|
+
if seq.members.any? {|sseq| sseq.is_a?(Selector::SimpleSequence) && sseq.subject?}
|
122
|
+
location = " of #{@filename}" if @filename
|
123
|
+
Sass::Util.sass_warn <<MESSAGE
|
124
|
+
DEPRECATION WARNING on line #{start_pos.line}, column #{start_pos.offset}#{location}:
|
125
|
+
The subject selector operator "!" is deprecated and will be removed in a future release.
|
126
|
+
This operator has been replaced by ":has()" in the CSS spec.
|
127
|
+
For example: #{seq.subjectless}
|
128
|
+
MESSAGE
|
129
|
+
end
|
130
|
+
|
131
|
+
seq
|
132
|
+
end
|
133
|
+
|
134
|
+
def combinator
|
135
|
+
tok(PLUS) || tok(GREATER) || tok(TILDE) || reference_combinator
|
136
|
+
end
|
137
|
+
|
138
|
+
def reference_combinator
|
139
|
+
return unless tok(%r{/})
|
140
|
+
res = '/'
|
141
|
+
ns, name = expr!(:qualified_name)
|
142
|
+
res << ns << '|' if ns
|
143
|
+
res << name << tok!(%r{/})
|
144
|
+
|
145
|
+
location = " of #{@filename}" if @filename
|
146
|
+
Sass::Util.sass_warn <<MESSAGE
|
147
|
+
DEPRECATION WARNING on line #{@line}, column #{@offset}#{location}:
|
148
|
+
The reference combinator #{res} is deprecated and will be removed in a future release.
|
149
|
+
MESSAGE
|
150
|
+
|
151
|
+
res
|
152
|
+
end
|
153
|
+
|
154
|
+
def simple_selector_sequence
|
155
|
+
start_pos = source_position
|
156
|
+
e = element_name || id_selector || class_selector || placeholder_selector || attrib ||
|
157
|
+
pseudo || parent_selector
|
158
|
+
return unless e
|
159
|
+
res = [e]
|
160
|
+
|
161
|
+
# The tok(/\*/) allows the "E*" hack
|
162
|
+
while (v = id_selector || class_selector || placeholder_selector ||
|
163
|
+
attrib || pseudo || (tok(/\*/) && Selector::Universal.new(nil)))
|
164
|
+
res << v
|
165
|
+
end
|
166
|
+
|
167
|
+
pos = @scanner.pos
|
168
|
+
line = @line
|
169
|
+
if (sel = str? {simple_selector_sequence})
|
170
|
+
@scanner.pos = pos
|
171
|
+
@line = line
|
172
|
+
begin
|
173
|
+
# If we see "*E", don't force a throw because this could be the
|
174
|
+
# "*prop: val" hack.
|
175
|
+
expected('"{"') if res.length == 1 && res[0].is_a?(Selector::Universal)
|
176
|
+
throw_error {expected('"{"')}
|
177
|
+
rescue Sass::SyntaxError => e
|
178
|
+
e.message << "\n\n\"#{sel}\" may only be used at the beginning of a compound selector."
|
179
|
+
raise e
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
Selector::SimpleSequence.new(res, tok(/!/), range(start_pos))
|
184
|
+
end
|
185
|
+
|
186
|
+
def parent_selector
|
187
|
+
return unless @allow_parent_ref && tok(/&/)
|
188
|
+
Selector::Parent.new(name)
|
189
|
+
end
|
190
|
+
|
191
|
+
def class_selector
|
192
|
+
return unless tok(/\./)
|
193
|
+
@expected = "class name"
|
194
|
+
Selector::Class.new(ident!)
|
195
|
+
end
|
196
|
+
|
197
|
+
def id_selector
|
198
|
+
return unless tok(/#(?!\{)/)
|
199
|
+
@expected = "id name"
|
200
|
+
Selector::Id.new(name!)
|
201
|
+
end
|
202
|
+
|
203
|
+
def placeholder_selector
|
204
|
+
return unless tok(/%/)
|
205
|
+
@expected = "placeholder name"
|
206
|
+
Selector::Placeholder.new(ident!)
|
207
|
+
end
|
208
|
+
|
209
|
+
def element_name
|
210
|
+
ns, name = Sass::Util.destructure(qualified_name(:allow_star_name))
|
211
|
+
return unless ns || name
|
212
|
+
|
213
|
+
if name == '*'
|
214
|
+
Selector::Universal.new(ns)
|
215
|
+
else
|
216
|
+
Selector::Element.new(name, ns)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def qualified_name(allow_star_name = false)
|
221
|
+
name = ident || tok(/\*/) || (tok?(/\|/) && "")
|
222
|
+
return unless name
|
223
|
+
return nil, name unless tok(/\|/)
|
224
|
+
|
225
|
+
return name, ident! unless allow_star_name
|
226
|
+
@expected = "identifier or *"
|
227
|
+
return name, ident || tok!(/\*/)
|
228
|
+
end
|
229
|
+
|
230
|
+
def attrib
|
231
|
+
return unless tok(/\[/)
|
232
|
+
ss
|
233
|
+
ns, name = attrib_name!
|
234
|
+
ss
|
235
|
+
|
236
|
+
op = tok(/=/) ||
|
237
|
+
tok(INCLUDES) ||
|
238
|
+
tok(DASHMATCH) ||
|
239
|
+
tok(PREFIXMATCH) ||
|
240
|
+
tok(SUFFIXMATCH) ||
|
241
|
+
tok(SUBSTRINGMATCH)
|
242
|
+
if op
|
243
|
+
@expected = "identifier or string"
|
244
|
+
ss
|
245
|
+
val = ident || tok!(STRING)
|
246
|
+
ss
|
247
|
+
end
|
248
|
+
flags = ident || tok(STRING)
|
249
|
+
tok!(/\]/)
|
250
|
+
|
251
|
+
Selector::Attribute.new(name, ns, op, val, flags)
|
252
|
+
end
|
253
|
+
|
254
|
+
def attrib_name!
|
255
|
+
if (name_or_ns = ident)
|
256
|
+
# E, E|E
|
257
|
+
if tok(/\|(?!=)/)
|
258
|
+
ns = name_or_ns
|
259
|
+
name = ident
|
260
|
+
else
|
261
|
+
name = name_or_ns
|
262
|
+
end
|
263
|
+
else
|
264
|
+
# *|E or |E
|
265
|
+
ns = tok(/\*/) || ""
|
266
|
+
tok!(/\|/)
|
267
|
+
name = ident!
|
268
|
+
end
|
269
|
+
return ns, name
|
270
|
+
end
|
271
|
+
|
272
|
+
SELECTOR_PSEUDO_CLASSES = %w(not matches current any has host host-context).to_set
|
273
|
+
|
274
|
+
PREFIXED_SELECTOR_PSEUDO_CLASSES = %w(nth-child nth-last-child).to_set
|
275
|
+
|
276
|
+
SELECTOR_PSEUDO_ELEMENTS = %w(slotted).to_set
|
277
|
+
|
278
|
+
def pseudo
|
279
|
+
s = tok(/::?/)
|
280
|
+
return unless s
|
281
|
+
@expected = "pseudoclass or pseudoelement"
|
282
|
+
name = ident!
|
283
|
+
if tok(/\(/)
|
284
|
+
ss
|
285
|
+
deprefixed = deprefix(name)
|
286
|
+
if s == ':' && SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
|
287
|
+
sel = selector_comma_sequence
|
288
|
+
elsif s == ':' && PREFIXED_SELECTOR_PSEUDO_CLASSES.include?(deprefixed)
|
289
|
+
arg, sel = prefixed_selector_pseudo
|
290
|
+
elsif s == '::' && SELECTOR_PSEUDO_ELEMENTS.include?(deprefixed)
|
291
|
+
sel = selector_comma_sequence
|
292
|
+
else
|
293
|
+
arg = expr!(:declaration_value).join
|
294
|
+
end
|
295
|
+
|
296
|
+
tok!(/\)/)
|
297
|
+
end
|
298
|
+
Selector::Pseudo.new(s == ':' ? :class : :element, name, arg, sel)
|
299
|
+
end
|
300
|
+
|
301
|
+
def prefixed_selector_pseudo
|
302
|
+
prefix = str do
|
303
|
+
expr = str {expr!(:a_n_plus_b)}
|
304
|
+
ss
|
305
|
+
return expr, nil unless tok(/of/)
|
306
|
+
ss
|
307
|
+
end
|
308
|
+
return prefix, expr!(:selector_comma_sequence)
|
309
|
+
end
|
310
|
+
|
311
|
+
def a_n_plus_b
|
312
|
+
if (parity = tok(/even|odd/i))
|
313
|
+
return parity
|
314
|
+
end
|
315
|
+
|
316
|
+
if tok(/[+-]?[0-9]+/)
|
317
|
+
ss
|
318
|
+
return true unless tok(/n/)
|
319
|
+
else
|
320
|
+
return unless tok(/[+-]?n/i)
|
321
|
+
end
|
322
|
+
ss
|
323
|
+
|
324
|
+
return true unless tok(/[+-]/)
|
325
|
+
ss
|
326
|
+
@expected = "number"
|
327
|
+
tok!(/[0-9]+/)
|
328
|
+
true
|
329
|
+
end
|
330
|
+
|
331
|
+
def keyframes_selector
|
332
|
+
ss
|
333
|
+
str do
|
334
|
+
return unless keyframes_selector_component
|
335
|
+
ss
|
336
|
+
while tok(/,/)
|
337
|
+
ss
|
338
|
+
expr!(:keyframes_selector_component)
|
339
|
+
ss
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
def keyframes_selector_component
|
345
|
+
ident || tok(PERCENTAGE)
|
346
|
+
end
|
347
|
+
|
348
|
+
@sass_script_parser = Class.new(Sass::Script::CssParser)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
data/lib/sass/scss.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'sass/scss/rx'
|
2
|
+
require 'sass/scss/parser'
|
3
|
+
require 'sass/scss/static_parser'
|
4
|
+
require 'sass/scss/css_parser'
|
5
|
+
|
6
|
+
module Sass
|
7
|
+
# SCSS is the CSS syntax for Sass.
|
8
|
+
# It parses into the same syntax tree as Sass,
|
9
|
+
# and generates the same sort of output CSS.
|
10
|
+
#
|
11
|
+
# This module contains code for the parsing of SCSS.
|
12
|
+
# The evaluation is handled by the broader {Sass} module.
|
13
|
+
module SCSS; end
|
14
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Sass
|
2
|
+
module Selector
|
3
|
+
# The abstract parent class of the various selector sequence classes.
|
4
|
+
#
|
5
|
+
# All subclasses should implement a `members` method that returns an array
|
6
|
+
# of object that respond to `#line=` and `#filename=`, as well as a `to_s`
|
7
|
+
# method that returns the string representation of the selector.
|
8
|
+
class AbstractSequence
|
9
|
+
# The line of the Sass template on which this selector was declared.
|
10
|
+
#
|
11
|
+
# @return [Integer]
|
12
|
+
attr_reader :line
|
13
|
+
|
14
|
+
# The name of the file in which this selector was declared.
|
15
|
+
#
|
16
|
+
# @return [String, nil]
|
17
|
+
attr_reader :filename
|
18
|
+
|
19
|
+
# Sets the line of the Sass template on which this selector was declared.
|
20
|
+
# This also sets the line for all child selectors.
|
21
|
+
#
|
22
|
+
# @param line [Integer]
|
23
|
+
# @return [Integer]
|
24
|
+
def line=(line)
|
25
|
+
members.each {|m| m.line = line}
|
26
|
+
@line = line
|
27
|
+
end
|
28
|
+
|
29
|
+
# Sets the name of the file in which this selector was declared,
|
30
|
+
# or `nil` if it was not declared in a file (e.g. on stdin).
|
31
|
+
# This also sets the filename for all child selectors.
|
32
|
+
#
|
33
|
+
# @param filename [String, nil]
|
34
|
+
# @return [String, nil]
|
35
|
+
def filename=(filename)
|
36
|
+
members.each {|m| m.filename = filename}
|
37
|
+
@filename = filename
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a hash code for this sequence.
|
41
|
+
#
|
42
|
+
# Subclasses should define `#_hash` rather than overriding this method,
|
43
|
+
# which automatically handles memoizing the result.
|
44
|
+
#
|
45
|
+
# @return [Integer]
|
46
|
+
def hash
|
47
|
+
@_hash ||= _hash
|
48
|
+
end
|
49
|
+
|
50
|
+
# Checks equality between this and another object.
|
51
|
+
#
|
52
|
+
# Subclasses should define `#_eql?` rather than overriding this method,
|
53
|
+
# which handles checking class equality and hash equality.
|
54
|
+
#
|
55
|
+
# @param other [Object] The object to test equality against
|
56
|
+
# @return [Boolean] Whether or not this is equal to `other`
|
57
|
+
def eql?(other)
|
58
|
+
other.class == self.class && other.hash == hash && _eql?(other)
|
59
|
+
end
|
60
|
+
alias_method :==, :eql?
|
61
|
+
|
62
|
+
# Whether or not this selector should be hidden due to containing a
|
63
|
+
# placeholder.
|
64
|
+
def invisible?
|
65
|
+
@invisible ||= members.any? do |m|
|
66
|
+
next m.invisible? if m.is_a?(AbstractSequence) || m.is_a?(Pseudo)
|
67
|
+
m.is_a?(Placeholder)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns the selector string.
|
72
|
+
#
|
73
|
+
# @param opts [Hash] rendering options.
|
74
|
+
# @option opts [Symbol] :style The css rendering style.
|
75
|
+
# @option placeholders [Boolean] :placeholders
|
76
|
+
# Whether to include placeholder selectors. Defaults to `true`.
|
77
|
+
# @return [String]
|
78
|
+
def to_s(opts = {})
|
79
|
+
Sass::Util.abstract(self)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns the specificity of the selector.
|
83
|
+
#
|
84
|
+
# The base is given by {Sass::Selector::SPECIFICITY_BASE}. This can be a
|
85
|
+
# number or a range representing possible specificities.
|
86
|
+
#
|
87
|
+
# @return [Integer, Range]
|
88
|
+
def specificity
|
89
|
+
_specificity(members)
|
90
|
+
end
|
91
|
+
|
92
|
+
protected
|
93
|
+
|
94
|
+
def _specificity(arr)
|
95
|
+
min = 0
|
96
|
+
max = 0
|
97
|
+
arr.each do |m|
|
98
|
+
next if m.is_a?(String)
|
99
|
+
spec = m.specificity
|
100
|
+
if spec.is_a?(Range)
|
101
|
+
min += spec.begin
|
102
|
+
max += spec.end
|
103
|
+
else
|
104
|
+
min += spec
|
105
|
+
max += spec
|
106
|
+
end
|
107
|
+
end
|
108
|
+
min == max ? min : (min..max)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|