oreorenasass 3.4.4 → 3.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +50 -70
- data/Rakefile +5 -26
- data/VERSION +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/lib/sass.rb +12 -19
- data/lib/sass/cache_stores/base.rb +2 -2
- data/lib/sass/cache_stores/chain.rb +1 -2
- data/lib/sass/cache_stores/filesystem.rb +5 -1
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +0 -1
- data/lib/sass/css.rb +13 -11
- data/lib/sass/engine.rb +173 -424
- data/lib/sass/environment.rb +58 -148
- data/lib/sass/error.rb +14 -11
- data/lib/sass/exec.rb +703 -5
- data/lib/sass/importers/base.rb +6 -49
- data/lib/sass/importers/filesystem.rb +19 -44
- data/lib/sass/logger.rb +4 -1
- data/lib/sass/logger/base.rb +4 -2
- data/lib/sass/logger/log_level.rb +7 -3
- data/lib/sass/media.rb +23 -20
- data/lib/sass/plugin.rb +7 -7
- data/lib/sass/plugin/compiler.rb +145 -304
- data/lib/sass/plugin/configuration.rb +23 -18
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +3 -3
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script.rb +8 -35
- data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
- data/lib/sass/script/bool.rb +18 -0
- data/lib/sass/script/color.rb +606 -0
- data/lib/sass/script/css_lexer.rb +4 -8
- data/lib/sass/script/css_parser.rb +2 -5
- data/lib/sass/script/funcall.rb +245 -0
- data/lib/sass/script/functions.rb +408 -1491
- data/lib/sass/script/interpolation.rb +79 -0
- data/lib/sass/script/lexer.rb +68 -172
- data/lib/sass/script/list.rb +85 -0
- data/lib/sass/script/literal.rb +221 -0
- data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
- data/lib/sass/script/{value/null.rb → null.rb} +7 -14
- data/lib/sass/script/{value/number.rb → number.rb} +75 -152
- data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
- data/lib/sass/script/parser.rb +110 -245
- data/lib/sass/script/string.rb +51 -0
- data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
- data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
- data/lib/sass/script/variable.rb +58 -0
- data/lib/sass/scss/css_parser.rb +3 -9
- data/lib/sass/scss/parser.rb +421 -450
- data/lib/sass/scss/rx.rb +11 -19
- data/lib/sass/scss/static_parser.rb +7 -321
- data/lib/sass/selector.rb +194 -68
- data/lib/sass/selector/abstract_sequence.rb +14 -29
- data/lib/sass/selector/comma_sequence.rb +25 -108
- data/lib/sass/selector/sequence.rb +66 -159
- data/lib/sass/selector/simple.rb +25 -23
- data/lib/sass/selector/simple_sequence.rb +63 -173
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/supports.rb +15 -13
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +3 -3
- data/lib/sass/tree/css_import_node.rb +11 -11
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +4 -21
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/extend_node.rb +7 -14
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +4 -9
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +5 -4
- data/lib/sass/tree/media_node.rb +14 -4
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +8 -21
- data/lib/sass/tree/node.rb +12 -54
- data/lib/sass/tree/prop_node.rb +20 -39
- data/lib/sass/tree/return_node.rb +2 -3
- data/lib/sass/tree/root_node.rb +3 -19
- data/lib/sass/tree/rule_node.rb +22 -35
- data/lib/sass/tree/supports_node.rb +13 -0
- data/lib/sass/tree/trace_node.rb +1 -2
- data/lib/sass/tree/variable_node.rb +3 -9
- data/lib/sass/tree/visitors/base.rb +8 -5
- data/lib/sass/tree/visitors/check_nesting.rb +19 -49
- data/lib/sass/tree/visitors/convert.rb +56 -74
- data/lib/sass/tree/visitors/cssize.rb +74 -202
- data/lib/sass/tree/visitors/deep_copy.rb +5 -10
- data/lib/sass/tree/visitors/extend.rb +7 -7
- data/lib/sass/tree/visitors/perform.rb +185 -278
- data/lib/sass/tree/visitors/set_options.rb +6 -20
- data/lib/sass/tree/visitors/to_css.rb +81 -234
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util.rb +152 -522
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/subset_map.rb +3 -4
- data/lib/sass/util/test.rb +1 -0
- data/lib/sass/version.rb +22 -20
- data/test/Gemfile +3 -0
- data/test/Gemfile.lock +10 -0
- data/test/sass/cache_test.rb +20 -62
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/conversion_test.rb +2 -296
- data/test/sass/css2sass_test.rb +4 -23
- data/test/sass/engine_test.rb +354 -411
- data/test/sass/exec_test.rb +2 -2
- data/test/sass/extend_test.rb +145 -324
- data/test/sass/functions_test.rb +86 -873
- data/test/sass/importer_test.rb +21 -241
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/plugin_test.rb +26 -16
- 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 +3 -3
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +7 -36
- data/test/sass/script_test.rb +53 -485
- data/test/sass/scss/css_test.rb +28 -143
- data/test/sass/scss/rx_test.rb +4 -4
- data/test/sass/scss/scss_test.rb +325 -2119
- data/test/sass/templates/scss_import.scss +1 -2
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +1 -86
- data/test/test_helper.rb +8 -37
- metadata +19 -66
- data/lib/sass/exec/base.rb +0 -187
- data/lib/sass/exec/sass_convert.rb +0 -264
- data/lib/sass/exec/sass_scss.rb +0 -424
- data/lib/sass/features.rb +0 -47
- data/lib/sass/script/tree.rb +0 -16
- data/lib/sass/script/tree/funcall.rb +0 -306
- data/lib/sass/script/tree/interpolation.rb +0 -118
- data/lib/sass/script/tree/list_literal.rb +0 -77
- data/lib/sass/script/tree/literal.rb +0 -45
- data/lib/sass/script/tree/map_literal.rb +0 -64
- data/lib/sass/script/tree/selector.rb +0 -26
- data/lib/sass/script/tree/variable.rb +0 -57
- data/lib/sass/script/value.rb +0 -11
- data/lib/sass/script/value/base.rb +0 -240
- data/lib/sass/script/value/bool.rb +0 -35
- data/lib/sass/script/value/color.rb +0 -680
- data/lib/sass/script/value/helpers.rb +0 -262
- data/lib/sass/script/value/list.rb +0 -113
- data/lib/sass/script/value/map.rb +0 -70
- data/lib/sass/script/value/string.rb +0 -97
- data/lib/sass/selector/pseudo.rb +0 -256
- data/lib/sass/source/map.rb +0 -210
- data/lib/sass/source/position.rb +0 -39
- data/lib/sass/source/range.rb +0 -41
- data/lib/sass/stack.rb +0 -120
- data/lib/sass/tree/at_root_node.rb +0 -83
- data/lib/sass/tree/error_node.rb +0 -18
- data/lib/sass/tree/keyframe_rule_node.rb +0 -15
- data/lib/sass/util/cross_platform_random.rb +0 -19
- data/lib/sass/util/normalized_map.rb +0 -130
- data/lib/sass/util/ordered_hash.rb +0 -192
- data/test/sass/compiler_test.rb +0 -232
- data/test/sass/encoding_test.rb +0 -219
- data/test/sass/source_map_test.rb +0 -977
- data/test/sass/superselector_test.rb +0 -191
- data/test/sass/util/normalized_map_test.rb +0 -51
- data/test/sass/value_helpers_test.rb +0 -179
@@ -0,0 +1,79 @@
|
|
1
|
+
module Sass::Script
|
2
|
+
# A SassScript object representing `#{}` interpolation outside a string.
|
3
|
+
#
|
4
|
+
# @see StringInterpolation
|
5
|
+
class Interpolation < Node
|
6
|
+
# Interpolation in a property is of the form `before #{mid} after`.
|
7
|
+
#
|
8
|
+
# @param before [Node] The SassScript before the interpolation
|
9
|
+
# @param mid [Node] The SassScript within the interpolation
|
10
|
+
# @param after [Node] The SassScript after the interpolation
|
11
|
+
# @param wb [Boolean] Whether there was whitespace between `before` and `#{`
|
12
|
+
# @param wa [Boolean] Whether there was whitespace between `}` and `after`
|
13
|
+
# @param originally_text [Boolean]
|
14
|
+
# Whether the original format of the interpolation was plain text,
|
15
|
+
# not an interpolation.
|
16
|
+
# This is used when converting back to SassScript.
|
17
|
+
def initialize(before, mid, after, wb, wa, originally_text = false)
|
18
|
+
@before = before
|
19
|
+
@mid = mid
|
20
|
+
@after = after
|
21
|
+
@whitespace_before = wb
|
22
|
+
@whitespace_after = wa
|
23
|
+
@originally_text = originally_text
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [String] A human-readable s-expression representation of the interpolation
|
27
|
+
def inspect
|
28
|
+
"(interpolation #{@before.inspect} #{@mid.inspect} #{@after.inspect})"
|
29
|
+
end
|
30
|
+
|
31
|
+
# @see Node#to_sass
|
32
|
+
def to_sass(opts = {})
|
33
|
+
res = ""
|
34
|
+
res << @before.to_sass(opts) if @before
|
35
|
+
res << ' ' if @before && @whitespace_before
|
36
|
+
res << '#{' unless @originally_text
|
37
|
+
res << @mid.to_sass(opts)
|
38
|
+
res << '}' unless @originally_text
|
39
|
+
res << ' ' if @after && @whitespace_after
|
40
|
+
res << @after.to_sass(opts) if @after
|
41
|
+
res
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the three components of the interpolation, `before`, `mid`, and `after`.
|
45
|
+
#
|
46
|
+
# @return [Array<Node>]
|
47
|
+
# @see #initialize
|
48
|
+
# @see Node#children
|
49
|
+
def children
|
50
|
+
[@before, @mid, @after].compact
|
51
|
+
end
|
52
|
+
|
53
|
+
# @see Node#deep_copy
|
54
|
+
def deep_copy
|
55
|
+
node = dup
|
56
|
+
node.instance_variable_set('@before', @before.deep_copy) if @before
|
57
|
+
node.instance_variable_set('@mid', @mid.deep_copy)
|
58
|
+
node.instance_variable_set('@after', @after.deep_copy) if @after
|
59
|
+
node
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
# Evaluates the interpolation.
|
65
|
+
#
|
66
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
67
|
+
# @return [Sass::Script::String] The SassScript string that is the value of the interpolation
|
68
|
+
def _perform(environment)
|
69
|
+
res = ""
|
70
|
+
res << @before.perform(environment).to_s if @before
|
71
|
+
res << " " if @before && @whitespace_before
|
72
|
+
val = @mid.perform(environment)
|
73
|
+
res << (val.is_a?(Sass::Script::String) ? val.value : val.to_s)
|
74
|
+
res << " " if @after && @whitespace_after
|
75
|
+
res << @after.perform(environment).to_s if @after
|
76
|
+
opts(Sass::Script::String.new(res))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/lib/sass/script/lexer.rb
CHANGED
@@ -16,29 +16,26 @@ module Sass
|
|
16
16
|
# `value`: \[`Object`\]
|
17
17
|
# : The Ruby object corresponding to the value of the token.
|
18
18
|
#
|
19
|
-
# `
|
20
|
-
# : The
|
19
|
+
# `line`: \[`Fixnum`\]
|
20
|
+
# : The line of the source file on which the token appears.
|
21
|
+
#
|
22
|
+
# `offset`: \[`Fixnum`\]
|
23
|
+
# : The number of bytes into the line the SassScript token appeared.
|
21
24
|
#
|
22
25
|
# `pos`: \[`Fixnum`\]
|
23
26
|
# : The scanner position at which the SassScript token appeared.
|
24
|
-
Token = Struct.new(:type, :value, :
|
27
|
+
Token = Struct.new(:type, :value, :line, :offset, :pos)
|
25
28
|
|
26
29
|
# The line number of the lexer's current position.
|
27
30
|
#
|
28
31
|
# @return [Fixnum]
|
29
|
-
|
30
|
-
return @line unless @tok
|
31
|
-
@tok.source_range.start_pos.line
|
32
|
-
end
|
32
|
+
attr_reader :line
|
33
33
|
|
34
34
|
# The number of bytes into the current line
|
35
|
-
# of the lexer's current position
|
35
|
+
# of the lexer's current position.
|
36
36
|
#
|
37
37
|
# @return [Fixnum]
|
38
|
-
|
39
|
-
return @offset unless @tok
|
40
|
-
@tok.source_range.start_pos.offset
|
41
|
-
end
|
38
|
+
attr_reader :offset
|
42
39
|
|
43
40
|
# A hash from operator strings to the corresponding token types.
|
44
41
|
OPERATORS = {
|
@@ -70,9 +67,10 @@ module Sass
|
|
70
67
|
|
71
68
|
OPERATORS_REVERSE = Sass::Util.map_hash(OPERATORS) {|k, v| [v, k]}
|
72
69
|
|
73
|
-
TOKEN_NAMES = Sass::Util.map_hash(OPERATORS_REVERSE) {|k, v| [k, v.inspect]}.merge(
|
70
|
+
TOKEN_NAMES = Sass::Util.map_hash(OPERATORS_REVERSE) {|k, v| [k, v.inspect]}.merge({
|
74
71
|
:const => "variable (e.g. $foo)",
|
75
|
-
:ident => "identifier (e.g. middle)"
|
72
|
+
:ident => "identifier (e.g. middle)"
|
73
|
+
})
|
76
74
|
|
77
75
|
# A list of operator strings ordered with longer names first
|
78
76
|
# so that `>` and `<` don't clobber `>=` and `<=`.
|
@@ -82,8 +80,6 @@ module Sass
|
|
82
80
|
# with identifier names.
|
83
81
|
IDENT_OP_NAMES = OP_NAMES.select {|k, v| k =~ /^\w+/}
|
84
82
|
|
85
|
-
PARSEABLE_NUMBER = /(?:(\d*\.\d+)|(\d+))(?:[eE]([+-]?\d+))?(#{UNIT})?/
|
86
|
-
|
87
83
|
# A hash of regular expressions that are used for tokenizing.
|
88
84
|
REGULAR_EXPRESSIONS = {
|
89
85
|
:whitespace => /\s+/,
|
@@ -91,22 +87,16 @@ module Sass
|
|
91
87
|
:single_line_comment => SINGLE_LINE_COMMENT,
|
92
88
|
:variable => /(\$)(#{IDENT})/,
|
93
89
|
:ident => /(#{IDENT})(\()?/,
|
94
|
-
:number =>
|
95
|
-
:unary_minus_number => /-#{PARSEABLE_NUMBER}/,
|
90
|
+
:number => /(-)?(?:(\d*\.\d+)|(\d+))([a-zA-Z%]+)?/,
|
96
91
|
:color => HEXCOLOR,
|
97
|
-
:
|
98
|
-
:
|
99
|
-
:ident_op => /(#{Regexp.union(*IDENT_OP_NAMES.map do |s|
|
100
|
-
Regexp.new(Regexp.escape(s) + "(?!#{NMCHAR}|\Z)")
|
101
|
-
end)})/,
|
102
|
-
:op => /(#{Regexp.union(*OP_NAMES)})/,
|
92
|
+
:ident_op => %r{(#{Regexp.union(*IDENT_OP_NAMES.map{|s| Regexp.new(Regexp.escape(s) + "(?!#{NMCHAR}|\Z)")})})},
|
93
|
+
:op => %r{(#{Regexp.union(*OP_NAMES)})},
|
103
94
|
}
|
104
95
|
|
105
96
|
class << self
|
106
97
|
private
|
107
|
-
|
108
98
|
def string_re(open, close)
|
109
|
-
/#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/
|
99
|
+
/#{open}((?:\\.|\#(?!\{)|[^#{close}\\#])*)(#{close}|#\{)/
|
110
100
|
end
|
111
101
|
end
|
112
102
|
|
@@ -142,10 +132,10 @@ module Sass
|
|
142
132
|
}
|
143
133
|
|
144
134
|
# @param str [String, StringScanner] The source text to lex
|
145
|
-
# @param line [Fixnum] The
|
146
|
-
# Used for error reporting
|
147
|
-
# @param offset [Fixnum] The
|
148
|
-
# Used for error reporting
|
135
|
+
# @param line [Fixnum] The line on which the SassScript appears.
|
136
|
+
# Used for error reporting
|
137
|
+
# @param offset [Fixnum] The number of characters in on which the SassScript appears.
|
138
|
+
# Used for error reporting
|
149
139
|
# @param options [{Symbol => Object}] An options hash;
|
150
140
|
# see {file:SASS_REFERENCE.md#sass_options the Sass options documentation}
|
151
141
|
def initialize(str, line, offset, options)
|
@@ -164,7 +154,7 @@ module Sass
|
|
164
154
|
@tok ||= read_token
|
165
155
|
@tok, tok = nil, @tok
|
166
156
|
@prev = tok
|
167
|
-
tok
|
157
|
+
return tok
|
168
158
|
end
|
169
159
|
|
170
160
|
# Returns whether or not there's whitespace before the next token.
|
@@ -189,11 +179,7 @@ module Sass
|
|
189
179
|
# Rewinds the underlying StringScanner
|
190
180
|
# to before the token returned by \{#peek}.
|
191
181
|
def unpeek!
|
192
|
-
if @tok
|
193
|
-
@scanner.pos = @tok.pos
|
194
|
-
@line = @tok.source_range.start_pos.line
|
195
|
-
@offset = @tok.source_range.start_pos.offset
|
196
|
-
end
|
182
|
+
@scanner.pos = @tok.pos if @tok
|
197
183
|
end
|
198
184
|
|
199
185
|
# @return [Boolean] Whether or not there's more source text to lex.
|
@@ -236,11 +222,13 @@ module Sass
|
|
236
222
|
|
237
223
|
def read_token
|
238
224
|
return if done?
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
225
|
+
return unless value = token
|
226
|
+
type, val, size = value
|
227
|
+
size ||= @scanner.matched_size
|
228
|
+
|
229
|
+
val.line = @line if val.is_a?(Script::Node)
|
230
|
+
Token.new(type, val, @line,
|
231
|
+
current_position - size, @scanner.pos - size)
|
244
232
|
end
|
245
233
|
|
246
234
|
def whitespace
|
@@ -250,19 +238,13 @@ module Sass
|
|
250
238
|
end
|
251
239
|
|
252
240
|
def token
|
253
|
-
if after_interpolation? && (
|
254
|
-
interp_type,
|
255
|
-
if interp_type == :special_fun
|
256
|
-
return special_fun_body(interp_value)
|
257
|
-
else
|
258
|
-
raise "[BUG]: Unknown interp_type #{interp_type}" unless interp_type == :string
|
259
|
-
return string(interp_value, true)
|
260
|
-
end
|
241
|
+
if after_interpolation? && (interp_type = @interpolation_stack.pop)
|
242
|
+
return string(interp_type, true)
|
261
243
|
end
|
262
244
|
|
263
|
-
variable || string(:double, false) || string(:single, false) || number ||
|
264
|
-
|
265
|
-
|
245
|
+
variable || string(:double, false) || string(:single, false) || number || color ||
|
246
|
+
string(:uri, false) || raw(UNICODERANGE) || special_fun || special_val || ident_op ||
|
247
|
+
ident || op
|
266
248
|
end
|
267
249
|
|
268
250
|
def variable
|
@@ -281,168 +263,82 @@ module Sass
|
|
281
263
|
end
|
282
264
|
|
283
265
|
def string(re, open)
|
284
|
-
line, offset = @line, @offset
|
285
266
|
return unless scan(STRING_REGULAR_EXPRESSIONS[re][open])
|
286
|
-
if @scanner[
|
287
|
-
filename = @options[:filename]
|
288
|
-
Sass::Util.sass_warn <<MESSAGE
|
289
|
-
DEPRECATION WARNING on line #{line}, column #{offset}#{" of #{filename}" if filename}:
|
290
|
-
Unescaped multiline strings are deprecated and will be removed in a future version of Sass.
|
291
|
-
To include a newline in a string, use "\\a" or "\\a " as in CSS.
|
292
|
-
MESSAGE
|
293
|
-
end
|
294
|
-
|
295
|
-
if @scanner[2] == '#{' # '
|
267
|
+
if @scanner[2] == '#{' #'
|
296
268
|
@scanner.pos -= 2 # Don't actually consume the #{
|
297
|
-
@
|
298
|
-
@interpolation_stack << [:string, re]
|
269
|
+
@interpolation_stack << re
|
299
270
|
end
|
300
271
|
str =
|
301
272
|
if re == :uri
|
302
|
-
|
303
|
-
Script::Value::String.new(url)
|
273
|
+
Script::String.new("#{'url(' unless open}#{@scanner[1]}#{')' unless @scanner[2] == '#{'}")
|
304
274
|
else
|
305
|
-
Script::
|
275
|
+
Script::String.new(@scanner[1].gsub(/\\(['"]|\#\{)/, '\1'), :string)
|
306
276
|
end
|
307
277
|
[:string, str]
|
308
278
|
end
|
309
279
|
|
310
280
|
def number
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
# before and not after it. Cases like "(-2)" are handled by the unary
|
316
|
-
# minus logic in the parser instead.
|
317
|
-
if @scanner.peek(1) == '-'
|
318
|
-
return if @scanner.pos == 0
|
319
|
-
unary_minus_allowed =
|
320
|
-
case @scanner.string[@scanner.pos - 1, 1]
|
321
|
-
when /\s/; true
|
322
|
-
when '/'; @scanner.pos != 1 && @scanner.string[@scanner.pos - 2, 1] == '*'
|
323
|
-
else; false
|
324
|
-
end
|
325
|
-
|
326
|
-
return unless unary_minus_allowed
|
327
|
-
return unless scan(REGULAR_EXPRESSIONS[:unary_minus_number])
|
328
|
-
minus = true
|
329
|
-
else
|
330
|
-
return unless scan(REGULAR_EXPRESSIONS[:number])
|
331
|
-
minus = false
|
332
|
-
end
|
333
|
-
|
334
|
-
value = (@scanner[1] ? @scanner[1].to_f : @scanner[2].to_i) * (minus ? -1 : 1)
|
335
|
-
value *= 10**@scanner[3].to_i if @scanner[3]
|
336
|
-
script_number = Script::Value::Number.new(value, Array(@scanner[4]))
|
337
|
-
[:number, script_number]
|
338
|
-
end
|
339
|
-
|
340
|
-
def id
|
341
|
-
# Colors and ids are tough to tell apart, because they overlap but
|
342
|
-
# neither is a superset of the other. "#xyz" is an id but not a color,
|
343
|
-
# "#000" is a color but not an id, "#abc" is both, and "#0" is neither.
|
344
|
-
# We need to handle all these cases correctly.
|
345
|
-
#
|
346
|
-
# To do so, we first try to parse something as an id. If this works and
|
347
|
-
# the id is also a valid color, we return the color. Otherwise, we
|
348
|
-
# return the id. If it didn't parse as an id, we then try to parse it as
|
349
|
-
# a color. If *this* works, we return the color, and if it doesn't we
|
350
|
-
# give up and throw an error.
|
351
|
-
#
|
352
|
-
# IDs in properties are used in the Basic User Interface Module
|
353
|
-
# (http://www.w3.org/TR/css3-ui/).
|
354
|
-
return unless scan(REGULAR_EXPRESSIONS[:id])
|
355
|
-
if @scanner[0] =~ /^\#[0-9a-fA-F]+$/ && (@scanner[0].length == 4 || @scanner[0].length == 7)
|
356
|
-
return [:color, Script::Value::Color.from_hex(@scanner[0])]
|
357
|
-
end
|
358
|
-
[:ident, @scanner[0]]
|
281
|
+
return unless scan(REGULAR_EXPRESSIONS[:number])
|
282
|
+
value = @scanner[2] ? @scanner[2].to_f : @scanner[3].to_i
|
283
|
+
value = -value if @scanner[1]
|
284
|
+
[:number, Script::Number.new(value, Array(@scanner[4]))]
|
359
285
|
end
|
360
286
|
|
361
287
|
def color
|
362
|
-
return unless
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
start_pos = source_position
|
370
|
-
return unless scan(REGULAR_EXPRESSIONS[:selector])
|
371
|
-
script_selector = Script::Tree::Selector.new
|
372
|
-
script_selector.source_range = range(start_pos)
|
373
|
-
[:selector, script_selector]
|
288
|
+
return unless s = scan(REGULAR_EXPRESSIONS[:color])
|
289
|
+
raise Sass::SyntaxError.new(<<MESSAGE.rstrip) unless s.size == 4 || s.size == 7
|
290
|
+
Colors must have either three or six digits: '#{s}'
|
291
|
+
MESSAGE
|
292
|
+
value = s.scan(/^#(..?)(..?)(..?)$/).first.
|
293
|
+
map {|num| num.ljust(2, num).to_i(16)}
|
294
|
+
[:color, Script::Color.new(value)]
|
374
295
|
end
|
375
296
|
|
376
297
|
def special_fun
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
next
|
389
|
-
elsif scanned[-1] == ?)
|
390
|
-
parens -= 1
|
391
|
-
next unless parens == 0
|
392
|
-
else
|
393
|
-
raise "[BUG] Unreachable" unless @scanner[1] == '#{' # '
|
394
|
-
str.slice!(-2..-1)
|
395
|
-
@scanner.pos -= 2 # Don't actually consume the #{
|
396
|
-
@offset -= 2
|
397
|
-
@interpolation_stack << [:special_fun, parens]
|
398
|
-
end
|
399
|
-
|
400
|
-
return [:special_fun, Sass::Script::Value::String.new(str)]
|
401
|
-
end
|
402
|
-
|
403
|
-
scan(/.*/)
|
404
|
-
expected!('")"')
|
298
|
+
return unless str1 = scan(/((-[\w-]+-)?(calc|element)|expression|progid:[a-z\.]*)\(/i)
|
299
|
+
str2, _ = Sass::Shared.balance(@scanner, ?(, ?), 1)
|
300
|
+
c = str2.count("\n")
|
301
|
+
old_line = @line
|
302
|
+
old_offset = @offset
|
303
|
+
@line += c
|
304
|
+
@offset = (c == 0 ? @offset + str2.size : str2[/\n(.*)/, 1].size)
|
305
|
+
[:special_fun,
|
306
|
+
Sass::Util.merge_adjacent_strings(
|
307
|
+
[str1] + Sass::Engine.parse_interp(str2, old_line, old_offset, @options)),
|
308
|
+
str1.size + str2.size]
|
405
309
|
end
|
406
310
|
|
407
311
|
def special_val
|
408
312
|
return unless scan(/!important/i)
|
409
|
-
[:string, Script::
|
313
|
+
[:string, Script::String.new("!important")]
|
410
314
|
end
|
411
315
|
|
412
316
|
def ident_op
|
413
|
-
op = scan(REGULAR_EXPRESSIONS[:ident_op])
|
414
|
-
return unless op
|
317
|
+
return unless op = scan(REGULAR_EXPRESSIONS[:ident_op])
|
415
318
|
[OPERATORS[op]]
|
416
319
|
end
|
417
320
|
|
418
321
|
def op
|
419
|
-
op = scan(REGULAR_EXPRESSIONS[:op])
|
420
|
-
return unless op
|
322
|
+
return unless op = scan(REGULAR_EXPRESSIONS[:op])
|
421
323
|
@interpolation_stack << nil if op == :begin_interpolation
|
422
324
|
[OPERATORS[op]]
|
423
325
|
end
|
424
326
|
|
425
327
|
def raw(rx)
|
426
|
-
val = scan(rx)
|
427
|
-
return unless val
|
328
|
+
return unless val = scan(rx)
|
428
329
|
[:raw, val]
|
429
330
|
end
|
430
331
|
|
431
332
|
def scan(re)
|
432
|
-
str = @scanner.scan(re)
|
433
|
-
return unless str
|
333
|
+
return unless str = @scanner.scan(re)
|
434
334
|
c = str.count("\n")
|
435
335
|
@line += c
|
436
|
-
@offset = (c == 0 ? @offset + str.size : str.size
|
336
|
+
@offset = (c == 0 ? @offset + str.size : str[/\n(.*)/, 1].size)
|
437
337
|
str
|
438
338
|
end
|
439
339
|
|
440
|
-
def
|
441
|
-
|
442
|
-
end
|
443
|
-
|
444
|
-
def source_position
|
445
|
-
Sass::Source::Position.new(@line, @offset)
|
340
|
+
def current_position
|
341
|
+
@offset + 1
|
446
342
|
end
|
447
343
|
end
|
448
344
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Sass::Script
|
2
|
+
# A SassScript object representing a CSS list.
|
3
|
+
# This includes both comma-separated lists and space-separated lists.
|
4
|
+
class List < Literal
|
5
|
+
# The Ruby array containing the contents of the list.
|
6
|
+
#
|
7
|
+
# @return [Array<Literal>]
|
8
|
+
attr_reader :value
|
9
|
+
alias_method :children, :value
|
10
|
+
alias_method :to_a, :value
|
11
|
+
|
12
|
+
# The operator separating the values of the list.
|
13
|
+
# Either `:comma` or `:space`.
|
14
|
+
#
|
15
|
+
# @return [Symbol]
|
16
|
+
attr_reader :separator
|
17
|
+
|
18
|
+
# Creates a new list.
|
19
|
+
#
|
20
|
+
# @param value [Array<Literal>] See \{#value}
|
21
|
+
# @param separator [String] See \{#separator}
|
22
|
+
def initialize(value, separator)
|
23
|
+
super(value)
|
24
|
+
@separator = separator
|
25
|
+
end
|
26
|
+
|
27
|
+
# @see Node#deep_copy
|
28
|
+
def deep_copy
|
29
|
+
node = dup
|
30
|
+
node.instance_variable_set('@value', value.map {|c| c.deep_copy})
|
31
|
+
node
|
32
|
+
end
|
33
|
+
|
34
|
+
# @see Node#eq
|
35
|
+
def eq(other)
|
36
|
+
Sass::Script::Bool.new(
|
37
|
+
other.is_a?(List) && self.value == other.value &&
|
38
|
+
self.separator == other.separator)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @see Node#to_s
|
42
|
+
def to_s(opts = {})
|
43
|
+
raise Sass::SyntaxError.new("() isn't a valid CSS value.") if value.empty?
|
44
|
+
return value.reject {|e| e.is_a?(Null) || e.is_a?(List) && e.value.empty?}.map {|e| e.to_s(opts)}.join(sep_str)
|
45
|
+
end
|
46
|
+
|
47
|
+
# @see Node#to_sass
|
48
|
+
def to_sass(opts = {})
|
49
|
+
return "()" if value.empty?
|
50
|
+
precedence = Sass::Script::Parser.precedence_of(separator)
|
51
|
+
value.reject {|e| e.is_a?(Null)}.map do |v|
|
52
|
+
if v.is_a?(List) && Sass::Script::Parser.precedence_of(v.separator) <= precedence ||
|
53
|
+
separator == :space && v.is_a?(UnaryOperation) && (v.operator == :minus || v.operator == :plus)
|
54
|
+
"(#{v.to_sass(opts)})"
|
55
|
+
else
|
56
|
+
v.to_sass(opts)
|
57
|
+
end
|
58
|
+
end.join(sep_str(nil))
|
59
|
+
end
|
60
|
+
|
61
|
+
# @see Node#inspect
|
62
|
+
def inspect
|
63
|
+
"(#{to_sass})"
|
64
|
+
end
|
65
|
+
|
66
|
+
protected
|
67
|
+
|
68
|
+
# @see Node#_perform
|
69
|
+
def _perform(environment)
|
70
|
+
list = Sass::Script::List.new(
|
71
|
+
value.map {|e| e.perform(environment)},
|
72
|
+
separator)
|
73
|
+
list.options = self.options
|
74
|
+
list
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def sep_str(opts = self.options)
|
80
|
+
return ' ' if separator == :space
|
81
|
+
return ',' if opts && opts[:style] == :compressed
|
82
|
+
return ', '
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|