oreorenasass 3.4.4 → 3.4.5
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/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
|