sass 3.3.0.alpha.256 → 3.3.0.alpha.353
Sign up to get free protection for your applications and to get access to all the features.
- data/REVISION +1 -1
- data/Rakefile +21 -1
- data/VERSION +1 -1
- data/VERSION_DATE +1 -1
- data/lib/sass.rb +6 -3
- data/lib/sass/cache_stores/base.rb +1 -1
- data/lib/sass/cache_stores/chain.rb +2 -1
- data/lib/sass/cache_stores/filesystem.rb +2 -6
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +1 -0
- data/lib/sass/css.rb +6 -6
- data/lib/sass/engine.rb +60 -34
- data/lib/sass/environment.rb +3 -1
- data/lib/sass/error.rb +5 -5
- data/lib/sass/exec.rb +52 -25
- data/lib/sass/features.rb +0 -2
- data/lib/sass/importers/deprecated_path.rb +1 -1
- data/lib/sass/importers/filesystem.rb +8 -6
- data/lib/sass/logger/base.rb +3 -3
- data/lib/sass/logger/log_level.rb +4 -6
- data/lib/sass/media.rb +2 -2
- data/lib/sass/plugin.rb +4 -2
- data/lib/sass/plugin/compiler.rb +28 -15
- data/lib/sass/plugin/configuration.rb +15 -7
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +24 -8
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script.rb +2 -1
- data/lib/sass/script/css_lexer.rb +8 -3
- data/lib/sass/script/css_parser.rb +6 -2
- data/lib/sass/script/functions.rb +164 -109
- data/lib/sass/script/lexer.rb +30 -20
- data/lib/sass/script/parser.rb +66 -37
- data/lib/sass/script/tree/funcall.rb +23 -14
- data/lib/sass/script/tree/interpolation.rb +5 -1
- data/lib/sass/script/tree/list_literal.rb +5 -4
- data/lib/sass/script/tree/map_literal.rb +1 -1
- data/lib/sass/script/tree/node.rb +2 -2
- data/lib/sass/script/tree/operation.rb +2 -1
- data/lib/sass/script/tree/selector.rb +3 -2
- data/lib/sass/script/tree/string_interpolation.rb +2 -1
- data/lib/sass/script/tree/variable.rb +4 -3
- data/lib/sass/script/value/base.rb +12 -14
- data/lib/sass/script/value/color.rb +35 -16
- data/lib/sass/script/value/helpers.rb +146 -0
- data/lib/sass/script/value/list.rb +24 -5
- data/lib/sass/script/value/map.rb +1 -1
- data/lib/sass/script/value/null.rb +13 -3
- data/lib/sass/script/value/number.rb +44 -35
- data/lib/sass/script/value/string.rb +2 -2
- data/lib/sass/scss/css_parser.rb +2 -1
- data/lib/sass/scss/parser.rb +143 -93
- data/lib/sass/scss/rx.rb +4 -4
- data/lib/sass/scss/script_lexer.rb +1 -0
- data/lib/sass/scss/script_parser.rb +1 -0
- data/lib/sass/scss/static_parser.rb +5 -5
- data/lib/sass/selector.rb +5 -2
- data/lib/sass/selector/abstract_sequence.rb +1 -1
- data/lib/sass/selector/comma_sequence.rb +16 -14
- data/lib/sass/selector/sequence.rb +38 -24
- data/lib/sass/selector/simple.rb +4 -4
- data/lib/sass/selector/simple_sequence.rb +21 -11
- data/lib/sass/source/map.rb +7 -2
- data/lib/sass/source/range.rb +1 -1
- data/lib/sass/supports.rb +3 -3
- data/lib/sass/tree/debug_node.rb +1 -1
- data/lib/sass/tree/function_node.rb +2 -1
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +3 -4
- data/lib/sass/tree/prop_node.rb +4 -2
- data/lib/sass/tree/rule_node.rb +5 -2
- data/lib/sass/tree/visitors/base.rb +6 -6
- data/lib/sass/tree/visitors/check_nesting.rb +12 -9
- data/lib/sass/tree/visitors/convert.rb +34 -28
- data/lib/sass/tree/visitors/cssize.rb +4 -3
- data/lib/sass/tree/visitors/deep_copy.rb +1 -0
- data/lib/sass/tree/visitors/perform.rb +31 -16
- data/lib/sass/tree/visitors/to_css.rb +34 -16
- data/lib/sass/util.rb +88 -37
- data/lib/sass/util/multibyte_string_scanner.rb +2 -0
- data/lib/sass/util/ordered_hash.rb +20 -18
- data/lib/sass/util/subset_map.rb +3 -2
- data/lib/sass/util/test.rb +0 -1
- data/lib/sass/version.rb +9 -5
- data/test/rubocop_extensions.rb +70 -0
- data/test/sass/functions_test.rb +20 -1
- data/test/sass/importer_test.rb +2 -1
- data/test/sass/script_test.rb +4 -0
- data/test/sass/source_map_test.rb +1 -1
- data/test/sass/util_test.rb +49 -0
- data/test/sass/value_helpers_test.rb +181 -0
- metadata +13 -9
data/lib/sass/plugin/compiler.rb
CHANGED
@@ -33,10 +33,10 @@ module Sass::Plugin
|
|
33
33
|
|
34
34
|
# Creates a new compiler.
|
35
35
|
#
|
36
|
-
# @param
|
36
|
+
# @param opts [{Symbol => Object}]
|
37
37
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
38
|
-
def initialize(
|
39
|
-
|
38
|
+
def initialize(opts = {})
|
39
|
+
options.merge!(opts)
|
40
40
|
end
|
41
41
|
|
42
42
|
# Register a callback to be run after stylesheets are mass-updated.
|
@@ -159,7 +159,8 @@ module Sass::Plugin
|
|
159
159
|
|
160
160
|
# Updates out-of-date stylesheets.
|
161
161
|
#
|
162
|
-
# Checks each Sass/SCSS file in
|
162
|
+
# Checks each Sass/SCSS file in
|
163
|
+
# {file:SASS_REFERENCE.md#template_location-option `:template_location`}
|
163
164
|
# to see if it's been modified more recently than the corresponding CSS file
|
164
165
|
# in {file:SASS_REFERENCE.md#css_location-option `:css_location`}.
|
165
166
|
# If it has, it updates the CSS file.
|
@@ -230,7 +231,8 @@ module Sass::Plugin
|
|
230
231
|
|
231
232
|
# TODO: Keep better track of what depends on what
|
232
233
|
# so we don't have to run a global update every time anything changes.
|
233
|
-
|
234
|
+
listener_args = directories + [{:relative_paths => false}]
|
235
|
+
listener = create_listener(*listener_args) do |modified, added, removed|
|
234
236
|
recompile_required = false
|
235
237
|
|
236
238
|
modified.uniq.each do |f|
|
@@ -246,7 +248,7 @@ module Sass::Plugin
|
|
246
248
|
end
|
247
249
|
|
248
250
|
removed.uniq.each do |f|
|
249
|
-
if files = individual_files.find {|(source,_,_)| File.expand_path(source) == f}
|
251
|
+
if (files = individual_files.find {|(source, _, _)| File.expand_path(source) == f})
|
250
252
|
recompile_required = true
|
251
253
|
# This was a file we were watching explicitly and compiling to a particular location.
|
252
254
|
# Delete the corresponding file.
|
@@ -269,21 +271,24 @@ module Sass::Plugin
|
|
269
271
|
end
|
270
272
|
|
271
273
|
if recompile_required
|
272
|
-
# In case a file we're watching is removed and then recreated we
|
274
|
+
# In case a file we're watching is removed and then recreated we
|
275
|
+
# prune out the non-existant files here.
|
273
276
|
watched_files_remaining = individual_files.select {|(source, _, _)| File.exists?(source)}
|
274
277
|
update_stylesheets(watched_files_remaining)
|
275
278
|
end
|
276
279
|
end
|
277
280
|
|
278
|
-
# The native windows listener is much slower than the polling
|
279
|
-
#
|
281
|
+
# The native windows listener is much slower than the polling option, according to
|
282
|
+
# https://github.com/nex3/sass/commit/a3031856b22bc834a5417dedecb038b7be9b9e3e
|
280
283
|
listener.force_polling(true) if @options[:poll] || Sass::Util.windows?
|
281
284
|
|
285
|
+
# rubocop:disable RescueException
|
282
286
|
begin
|
283
287
|
listener.start!
|
284
288
|
rescue Exception => e
|
285
289
|
raise e unless e.is_a?(Interrupt)
|
286
290
|
end
|
291
|
+
# rubocop:enable RescueException
|
287
292
|
end
|
288
293
|
|
289
294
|
# Non-destructively modifies \{#options} so that default values are properly set,
|
@@ -313,9 +318,13 @@ module Sass::Plugin
|
|
313
318
|
dedupped = []
|
314
319
|
directories.each do |new_directory|
|
315
320
|
# no need to add a directory that is already watched.
|
316
|
-
next if dedupped.any?
|
321
|
+
next if dedupped.any? do |existing_directory|
|
322
|
+
child_of_directory?(existing_directory, new_directory)
|
323
|
+
end
|
317
324
|
# get rid of any sub directories of this new directory
|
318
|
-
dedupped.reject!
|
325
|
+
dedupped.reject! do |existing_directory|
|
326
|
+
child_of_directory?(new_directory, existing_directory)
|
327
|
+
end
|
319
328
|
dedupped << new_directory
|
320
329
|
end
|
321
330
|
dedupped
|
@@ -338,14 +347,16 @@ module Sass::Plugin
|
|
338
347
|
else
|
339
348
|
rendered = engine.render
|
340
349
|
end
|
341
|
-
rescue
|
350
|
+
rescue StandardError => e
|
342
351
|
compilation_error_occured = true
|
343
352
|
run_compilation_error e, filename, css, sourcemap
|
344
353
|
rendered = Sass::SyntaxError.exception_to_css(e, options)
|
345
354
|
end
|
346
355
|
|
347
356
|
write_file(css, rendered)
|
348
|
-
|
357
|
+
if mapping
|
358
|
+
write_file(sourcemap, mapping.to_json(:css_path => css, :sourcemap_path => sourcemap))
|
359
|
+
end
|
349
360
|
run_updated_stylesheet(filename, css, sourcemap) unless compilation_error_occured
|
350
361
|
end
|
351
362
|
|
@@ -379,7 +390,8 @@ module Sass::Plugin
|
|
379
390
|
end
|
380
391
|
|
381
392
|
def normalized_load_paths
|
382
|
-
@normalized_load_paths ||=
|
393
|
+
@normalized_load_paths ||=
|
394
|
+
Sass::Engine.normalize_options(:load_paths => load_paths)[:load_paths]
|
383
395
|
end
|
384
396
|
|
385
397
|
def load_paths(opts = options)
|
@@ -395,7 +407,8 @@ module Sass::Plugin
|
|
395
407
|
end
|
396
408
|
|
397
409
|
def css_filename(name, path)
|
398
|
-
"#{path}#{File::SEPARATOR unless path.end_with?(File::SEPARATOR)}#{name}".
|
410
|
+
"#{path}#{File::SEPARATOR unless path.end_with?(File::SEPARATOR)}#{name}".
|
411
|
+
gsub(/\.s[ac]ss$/, '.css')
|
399
412
|
end
|
400
413
|
|
401
414
|
def relative_to_pwd(f)
|
@@ -18,7 +18,8 @@ module Sass
|
|
18
18
|
}.freeze
|
19
19
|
end
|
20
20
|
|
21
|
-
# Resets the options and
|
21
|
+
# Resets the options and
|
22
|
+
# {Sass::Callbacks::InstanceMethods#clear_callbacks! clears all callbacks}.
|
22
23
|
def reset!
|
23
24
|
@options = nil
|
24
25
|
clear_callbacks!
|
@@ -36,7 +37,8 @@ module Sass
|
|
36
37
|
# This means that Sass/SCSS files in `template_location`
|
37
38
|
# will be compiled to CSS files in `css_location`.
|
38
39
|
#
|
39
|
-
# This is preferred over manually manipulating the
|
40
|
+
# This is preferred over manually manipulating the
|
41
|
+
# {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
|
40
42
|
# since the option can be in multiple formats.
|
41
43
|
#
|
42
44
|
# Note that this method will change `options[:template_location]`
|
@@ -56,7 +58,8 @@ module Sass
|
|
56
58
|
# This means that Sass/SCSS files in `template_location`
|
57
59
|
# will no longer be compiled to CSS files in `css_location`.
|
58
60
|
#
|
59
|
-
# This is preferred over manually manipulating the
|
61
|
+
# This is preferred over manually manipulating the
|
62
|
+
# {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
|
60
63
|
# since the option can be in multiple formats.
|
61
64
|
#
|
62
65
|
# Note that this method will change `options[:template_location]`
|
@@ -100,10 +103,15 @@ module Sass
|
|
100
103
|
options[:template_location] =
|
101
104
|
case options[:template_location]
|
102
105
|
when nil
|
103
|
-
options[:css_location]
|
104
|
-
[[File.join(options[:css_location], 'sass'), options[:css_location]]]
|
105
|
-
|
106
|
-
|
106
|
+
if options[:css_location]
|
107
|
+
[[File.join(options[:css_location], 'sass'), options[:css_location]]]
|
108
|
+
else
|
109
|
+
[]
|
110
|
+
end
|
111
|
+
when String
|
112
|
+
[[options[:template_location], options[:css_location]]]
|
113
|
+
else
|
114
|
+
options[:template_location].to_a
|
107
115
|
end
|
108
116
|
end
|
109
117
|
end
|
data/lib/sass/plugin/merb.rb
CHANGED
@@ -5,7 +5,7 @@ unless defined?(Sass::MERB_LOADED)
|
|
5
5
|
# Different default options in a m envirionment.
|
6
6
|
def default_options
|
7
7
|
@default_options ||= begin
|
8
|
-
version = Merb::VERSION.split('.').map {
|
8
|
+
version = Merb::VERSION.split('.').map {|n| n.to_i}
|
9
9
|
if version[0] <= 0 && version[1] < 5
|
10
10
|
root = MERB_ROOT
|
11
11
|
env = MERB_ENV
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
1
3
|
module Sass
|
2
4
|
module Plugin
|
3
5
|
# The class handles `.s[ca]ss` file staleness checks via their mtime timestamps.
|
@@ -24,11 +26,13 @@ module Sass
|
|
24
26
|
# as its instance-level caches are never explicitly expired.
|
25
27
|
class StalenessChecker
|
26
28
|
@dependencies_cache = {}
|
29
|
+
@dependency_cache_mutex = Mutex.new
|
27
30
|
|
28
31
|
class << self
|
29
32
|
# TODO: attach this to a compiler instance.
|
30
33
|
# @private
|
31
34
|
attr_accessor :dependencies_cache
|
35
|
+
attr_reader :dependency_cache_mutex
|
32
36
|
end
|
33
37
|
|
34
38
|
# Creates a new StalenessChecker
|
@@ -37,15 +41,13 @@ module Sass
|
|
37
41
|
# @param options [{Symbol => Object}]
|
38
42
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
39
43
|
def initialize(options)
|
40
|
-
@dependencies = self.class.dependencies_cache
|
41
|
-
|
42
44
|
# URIs that are being actively checked for staleness. Protects against
|
43
45
|
# import loops.
|
44
46
|
@actively_checking = Set.new
|
45
47
|
|
46
48
|
# Entries in the following instance-level caches are never explicitly expired.
|
47
|
-
# Instead they are supposed to automaticaly go out of scope when a series of staleness
|
48
|
-
# (this instance of StalenessChecker was created for) is finished.
|
49
|
+
# Instead they are supposed to automaticaly go out of scope when a series of staleness
|
50
|
+
# checks (this instance of StalenessChecker was created for) is finished.
|
49
51
|
@mtimes, @dependencies_stale, @parse_trees = {}, {}, {}
|
50
52
|
@options = Sass::Engine.normalize_options(options)
|
51
53
|
end
|
@@ -131,7 +133,7 @@ module Sass
|
|
131
133
|
begin
|
132
134
|
mtime = importer.mtime(uri, @options)
|
133
135
|
if mtime.nil?
|
134
|
-
|
136
|
+
with_dependency_cache {|cache| cache.delete([uri, importer])}
|
135
137
|
nil
|
136
138
|
else
|
137
139
|
mtime
|
@@ -140,18 +142,21 @@ module Sass
|
|
140
142
|
end
|
141
143
|
|
142
144
|
def dependencies(uri, importer)
|
143
|
-
stored_mtime, dependencies =
|
145
|
+
stored_mtime, dependencies =
|
146
|
+
with_dependency_cache {|cache| Sass::Util.destructure(cache[[uri, importer]])}
|
144
147
|
|
145
148
|
if !stored_mtime || stored_mtime < mtime(uri, importer)
|
146
149
|
dependencies = compute_dependencies(uri, importer)
|
147
|
-
|
150
|
+
with_dependency_cache do |cache|
|
151
|
+
cache[[uri, importer]] = [mtime(uri, importer), dependencies]
|
152
|
+
end
|
148
153
|
end
|
149
154
|
|
150
155
|
dependencies
|
151
156
|
end
|
152
157
|
|
153
158
|
def dependency_updated?(css_mtime)
|
154
|
-
|
159
|
+
proc do |uri, importer|
|
155
160
|
next true if @actively_checking.include?(uri)
|
156
161
|
begin
|
157
162
|
@actively_checking << uri
|
@@ -178,6 +183,17 @@ module Sass
|
|
178
183
|
def tree(uri, importer)
|
179
184
|
@parse_trees[[uri, importer]] ||= importer.find(uri, @options).to_tree
|
180
185
|
end
|
186
|
+
|
187
|
+
# Get access to the global dependency cache in a threadsafe manner.
|
188
|
+
# Inside the block, no other thread can access the dependency cache.
|
189
|
+
#
|
190
|
+
# @yieldparam cache [Hash] The hash that is the global dependency cache
|
191
|
+
# @return The value returned by the block to which this method yields
|
192
|
+
def with_dependency_cache
|
193
|
+
StalenessChecker.dependency_cache_mutex.synchronize do
|
194
|
+
yield StalenessChecker.dependencies_cache
|
195
|
+
end
|
196
|
+
end
|
181
197
|
end
|
182
198
|
end
|
183
199
|
end
|
data/lib/sass/repl.rb
CHANGED
@@ -18,7 +18,7 @@ module Sass
|
|
18
18
|
@line = 0
|
19
19
|
loop do
|
20
20
|
@line += 1
|
21
|
-
unless text = Readline.readline('>> ')
|
21
|
+
unless (text = Readline.readline('>> '))
|
22
22
|
puts
|
23
23
|
return
|
24
24
|
end
|
@@ -48,8 +48,8 @@ module Sass
|
|
48
48
|
rescue Sass::SyntaxError => e
|
49
49
|
puts "SyntaxError: #{e.message}"
|
50
50
|
if @options[:trace]
|
51
|
-
e.backtrace.each do |
|
52
|
-
puts "\tfrom #{
|
51
|
+
e.backtrace.each do |line|
|
52
|
+
puts "\tfrom #{line}"
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
data/lib/sass/script.rb
CHANGED
@@ -4,6 +4,7 @@ module Sass
|
|
4
4
|
#
|
5
5
|
# @see Sass::SCSS::CssParser
|
6
6
|
class CssLexer < Lexer
|
7
|
+
|
7
8
|
private
|
8
9
|
|
9
10
|
def token
|
@@ -12,16 +13,20 @@ module Sass
|
|
12
13
|
|
13
14
|
def string(re, *args)
|
14
15
|
if re == :uri
|
15
|
-
|
16
|
+
uri = scan(URI)
|
17
|
+
return unless uri
|
16
18
|
return [:string, Script::Value::String.new(uri)]
|
17
19
|
end
|
18
20
|
|
19
21
|
return unless scan(STRING)
|
20
|
-
|
22
|
+
string_value = (@scanner[1] || @scanner[2]).gsub(/\\(['"])/, '\1')
|
23
|
+
value = Script::Value::String.new(string_value, :string)
|
24
|
+
[:string, value]
|
21
25
|
end
|
22
26
|
|
23
27
|
def important
|
24
|
-
|
28
|
+
s = scan(IMPORTANT)
|
29
|
+
return unless s
|
25
30
|
[:raw, s]
|
26
31
|
end
|
27
32
|
end
|
@@ -7,6 +7,7 @@ module Sass
|
|
7
7
|
#
|
8
8
|
# @see Sass::SCSS::CssParser
|
9
9
|
class CssParser < Parser
|
10
|
+
|
10
11
|
private
|
11
12
|
|
12
13
|
# @private
|
@@ -17,8 +18,11 @@ module Sass
|
|
17
18
|
production :div, :unary_plus, :div
|
18
19
|
|
19
20
|
def string
|
20
|
-
|
21
|
-
return
|
21
|
+
tok = try_tok(:string)
|
22
|
+
return number unless tok
|
23
|
+
unless @lexer.peek && @lexer.peek.type == :begin_interpolation
|
24
|
+
return literal_node(tok.value, tok.source_range)
|
25
|
+
end
|
22
26
|
end
|
23
27
|
|
24
28
|
# Short-circuit all the SassScript-only productions
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'sass/script/value/helpers'
|
2
|
+
|
1
3
|
module Sass::Script
|
2
4
|
# Methods in this module are accessible from the SassScript context.
|
3
5
|
# For example, you can write
|
@@ -91,13 +93,16 @@ module Sass::Script
|
|
91
93
|
#
|
92
94
|
# ## Other Color Functions
|
93
95
|
#
|
94
|
-
# \{#adjust_color adjust-color($color, \[$red\], \[$green\], \[$blue\],
|
96
|
+
# \{#adjust_color adjust-color($color, \[$red\], \[$green\], \[$blue\],
|
97
|
+
# \[$hue\], \[$saturation\], \[$lightness\], \[$alpha\])}
|
95
98
|
# : Increases or decreases one or more components of a color.
|
96
99
|
#
|
97
|
-
# \{#scale_color scale-color($color, \[$red\], \[$green\], \[$blue\],
|
100
|
+
# \{#scale_color scale-color($color, \[$red\], \[$green\], \[$blue\],
|
101
|
+
# \[$saturation\], \[$lightness\], \[$alpha\])}
|
98
102
|
# : Fluidly scales one or more properties of a color.
|
99
103
|
#
|
100
|
-
# \{#change_color change-color($color, \[$red\], \[$green\], \[$blue\],
|
104
|
+
# \{#change_color change-color($color, \[$red\], \[$green\], \[$blue\],
|
105
|
+
# \[$hue\], \[$saturation\], \[$lightness\], \[$alpha\])}
|
101
106
|
# : Changes one or more properties of a color.
|
102
107
|
#
|
103
108
|
# \{#ie_hex_str ie-hex-str($color)}
|
@@ -342,22 +347,23 @@ module Sass::Script
|
|
342
347
|
def self.signature(method_name, arg_arity, kwarg_arity)
|
343
348
|
return unless @signatures[method_name]
|
344
349
|
@signatures[method_name].each do |signature|
|
345
|
-
|
346
|
-
|
350
|
+
sig_arity = signature.args.size
|
351
|
+
return signature if sig_arity == arg_arity + kwarg_arity
|
352
|
+
next unless sig_arity < arg_arity + kwarg_arity
|
347
353
|
|
348
354
|
# We have enough args.
|
349
355
|
# Now we need to figure out which args are varargs
|
350
356
|
# and if the signature allows them.
|
351
357
|
t_arg_arity, t_kwarg_arity = arg_arity, kwarg_arity
|
352
|
-
if
|
358
|
+
if sig_arity > t_arg_arity
|
353
359
|
# we transfer some kwargs arity to args arity
|
354
360
|
# if it does not have enough args -- assuming the names will work out.
|
355
|
-
t_kwarg_arity -= (
|
356
|
-
t_arg_arity =
|
361
|
+
t_kwarg_arity -= (sig_arity - t_arg_arity)
|
362
|
+
t_arg_arity = sig_arity
|
357
363
|
end
|
358
364
|
|
359
|
-
if
|
360
|
-
(t_kwarg_arity == 0
|
365
|
+
if (t_arg_arity == sig_arity || t_arg_arity > sig_arity && signature.var_args) &&
|
366
|
+
(t_kwarg_arity == 0 || t_kwarg_arity > 0 && signature.var_kwargs)
|
361
367
|
return signature
|
362
368
|
end
|
363
369
|
end
|
@@ -369,6 +375,7 @@ module Sass::Script
|
|
369
375
|
# are available to use in functions.
|
370
376
|
class EvaluationContext
|
371
377
|
include Functions
|
378
|
+
include Value::Helpers
|
372
379
|
|
373
380
|
# The human-readable names for [Sass::Script::Value::Base]. The default is
|
374
381
|
# just the downcased name of the type. The default is the downcased type
|
@@ -440,8 +447,10 @@ module Sass::Script
|
|
440
447
|
#
|
441
448
|
# @example
|
442
449
|
# assert_integer 2px
|
443
|
-
# assert_integer 2.5px
|
444
|
-
#
|
450
|
+
# assert_integer 2.5px
|
451
|
+
# => SyntaxError: "Expected 2.5px to be an integer"
|
452
|
+
# assert_integer 2.5px, "width"
|
453
|
+
# => SyntaxError: "Expected width to be an integer but got 2.5px"
|
445
454
|
# @param number [Sass::Script::Value::Base] The value to be validated.
|
446
455
|
# @param name [::String] The name of the parameter being validated.
|
447
456
|
# @raise [ArgumentError] if number is not an integer or is not a number.
|
@@ -464,6 +473,7 @@ module Sass::Script
|
|
464
473
|
alias_method :callable?, :public_method_defined?
|
465
474
|
|
466
475
|
private
|
476
|
+
|
467
477
|
def include(*args)
|
468
478
|
r = super
|
469
479
|
# We have to re-include ourselves into EvaluationContext to work around
|
@@ -494,17 +504,17 @@ module Sass::Script
|
|
494
504
|
assert_type green, :Number, :green
|
495
505
|
assert_type blue, :Number, :blue
|
496
506
|
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
507
|
+
color_attrs = [[red, :red], [green, :green], [blue, :blue]].map do |(c, name)|
|
508
|
+
if c.is_unit?("%")
|
509
|
+
v = Sass::Util.check_range("$#{name}: Color value", 0..100, c, '%')
|
510
|
+
v * 255 / 100.0
|
511
|
+
elsif c.unitless?
|
512
|
+
Sass::Util.check_range("$#{name}: Color value", 0..255, c)
|
513
|
+
else
|
514
|
+
raise ArgumentError.new("Expected #{c} to be unitless or have a unit of % but got #{c}")
|
515
|
+
end
|
516
|
+
end
|
517
|
+
Sass::Script::Value::Color.new(color_attrs)
|
508
518
|
end
|
509
519
|
declare :rgb, [:red, :green, :blue]
|
510
520
|
|
@@ -576,7 +586,7 @@ module Sass::Script
|
|
576
586
|
# @raise [ArgumentError] if `$saturation` or `$lightness` are out of bounds
|
577
587
|
# or any parameter is the wrong type
|
578
588
|
def hsl(hue, saturation, lightness)
|
579
|
-
hsla(hue, saturation, lightness,
|
589
|
+
hsla(hue, saturation, lightness, number(1))
|
580
590
|
end
|
581
591
|
declare :hsl, [:hue, :saturation, :lightness]
|
582
592
|
|
@@ -611,7 +621,8 @@ module Sass::Script
|
|
611
621
|
s = Sass::Util.check_range('Saturation', 0..100, saturation, '%')
|
612
622
|
l = Sass::Util.check_range('Lightness', 0..100, lightness, '%')
|
613
623
|
|
614
|
-
Sass::Script::Value::Color.new(
|
624
|
+
Sass::Script::Value::Color.new(
|
625
|
+
:hue => h, :saturation => s, :lightness => l, :alpha => alpha.value)
|
615
626
|
end
|
616
627
|
declare :hsla, [:hue, :saturation, :lightness, :alpha]
|
617
628
|
|
@@ -627,7 +638,7 @@ module Sass::Script
|
|
627
638
|
# @raise [ArgumentError] if `$color` isn't a color
|
628
639
|
def red(color)
|
629
640
|
assert_type color, :Color, :color
|
630
|
-
|
641
|
+
number(color.red)
|
631
642
|
end
|
632
643
|
declare :red, [:color]
|
633
644
|
|
@@ -643,7 +654,7 @@ module Sass::Script
|
|
643
654
|
# @raise [ArgumentError] if `$color` isn't a color
|
644
655
|
def green(color)
|
645
656
|
assert_type color, :Color, :color
|
646
|
-
|
657
|
+
number(color.green)
|
647
658
|
end
|
648
659
|
declare :green, [:color]
|
649
660
|
|
@@ -659,7 +670,7 @@ module Sass::Script
|
|
659
670
|
# @raise [ArgumentError] if `$color` isn't a color
|
660
671
|
def blue(color)
|
661
672
|
assert_type color, :Color, :color
|
662
|
-
|
673
|
+
number(color.blue)
|
663
674
|
end
|
664
675
|
declare :blue, [:color]
|
665
676
|
|
@@ -677,7 +688,8 @@ module Sass::Script
|
|
677
688
|
# @raise [ArgumentError] if `$color` isn't a color
|
678
689
|
def hue(color)
|
679
690
|
assert_type color, :Color, :color
|
680
|
-
|
691
|
+
assert_type color, :Color
|
692
|
+
number(color.hue, "deg")
|
681
693
|
end
|
682
694
|
declare :hue, [:color]
|
683
695
|
|
@@ -695,7 +707,7 @@ module Sass::Script
|
|
695
707
|
# @raise [ArgumentError] if `$color` isn't a color
|
696
708
|
def saturation(color)
|
697
709
|
assert_type color, :Color, :color
|
698
|
-
|
710
|
+
number(color.saturation, "%")
|
699
711
|
end
|
700
712
|
declare :saturation, [:color]
|
701
713
|
|
@@ -713,7 +725,7 @@ module Sass::Script
|
|
713
725
|
# @raise [ArgumentError] if `$color` isn't a color
|
714
726
|
def lightness(color)
|
715
727
|
assert_type color, :Color, :color
|
716
|
-
|
728
|
+
number(color.lightness, "%")
|
717
729
|
end
|
718
730
|
declare :lightness, [:color]
|
719
731
|
|
@@ -729,17 +741,17 @@ module Sass::Script
|
|
729
741
|
# @raise [ArgumentError] if `$color` isn't a color
|
730
742
|
def alpha(*args)
|
731
743
|
if args.all? do |a|
|
732
|
-
|
733
|
-
|
734
|
-
|
744
|
+
a.is_a?(Sass::Script::Value::String) && a.type == :identifier &&
|
745
|
+
a.value =~ /^[a-zA-Z]+\s*=/
|
746
|
+
end
|
735
747
|
# Support the proprietary MS alpha() function
|
736
|
-
return
|
748
|
+
return identifier("alpha(#{args.map {|a| a.to_s}.join(", ")})")
|
737
749
|
end
|
738
750
|
|
739
751
|
raise ArgumentError.new("wrong number of arguments (#{args.size} for 1)") if args.size != 1
|
740
752
|
|
741
753
|
assert_type args.first, :Color, :color
|
742
|
-
|
754
|
+
number(args.first.alpha)
|
743
755
|
end
|
744
756
|
declare :alpha, [:color]
|
745
757
|
|
@@ -752,10 +764,10 @@ module Sass::Script
|
|
752
764
|
# @raise [ArgumentError] if `$color` isn't a color
|
753
765
|
def opacity(color)
|
754
766
|
if color.is_a?(Sass::Script::Value::Number)
|
755
|
-
return
|
767
|
+
return identifier("opacity(#{color})")
|
756
768
|
end
|
757
769
|
assert_type color, :Color, :color
|
758
|
-
|
770
|
+
number(color.alpha)
|
759
771
|
end
|
760
772
|
declare :opacity, [:color]
|
761
773
|
|
@@ -858,7 +870,7 @@ module Sass::Script
|
|
858
870
|
def saturate(color, amount = nil)
|
859
871
|
# Support the filter effects definition of saturate.
|
860
872
|
# https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
|
861
|
-
return
|
873
|
+
return identifier("saturate(#{color})") if amount.nil?
|
862
874
|
_adjust(color, amount, :saturation, 0..100, :+, "%")
|
863
875
|
end
|
864
876
|
declare :saturate, [:color, :amount]
|
@@ -918,7 +930,7 @@ module Sass::Script
|
|
918
930
|
def ie_hex_str(color)
|
919
931
|
assert_type color, :Color, :color
|
920
932
|
alpha = (color.alpha * 255).round.to_s(16).rjust(2, '0')
|
921
|
-
|
933
|
+
identifier("##{alpha}#{color.send(:hex_str)[1..-1]}".upcase)
|
922
934
|
end
|
923
935
|
declare :ie_hex_str, [:color]
|
924
936
|
|
@@ -935,7 +947,8 @@ module Sass::Script
|
|
935
947
|
# adjust-color(#102030, $blue: 5) => #102035
|
936
948
|
# adjust-color(#102030, $red: -5, $blue: 5) => #0b2035
|
937
949
|
# adjust-color(hsl(25, 100%, 80%), $lightness: -30%, $alpha: -0.4) => hsla(25, 100%, 50%, 0.6)
|
938
|
-
# @overload adjust_color($color, [$red], [$green], [$blue],
|
950
|
+
# @overload adjust_color($color, [$red], [$green], [$blue],
|
951
|
+
# [$hue], [$saturation], [$lightness], [$alpha])
|
939
952
|
# @param $color [Sass::Script::Value::Color]
|
940
953
|
# @param $red [Sass::Script::Value::Number] The adjustment to make on the
|
941
954
|
# red component, between -255 and 255 inclusive
|
@@ -967,7 +980,8 @@ module Sass::Script
|
|
967
980
|
"alpha" => [-1..1, ""]
|
968
981
|
}) do |name, (range, units)|
|
969
982
|
|
970
|
-
|
983
|
+
val = kwargs.delete(name)
|
984
|
+
next unless val
|
971
985
|
assert_type val, :Number, name
|
972
986
|
Sass::Util.check_range("$#{name}: Amount", range, val, units) if range
|
973
987
|
adjusted = color.send(name) + val.value
|
@@ -1011,7 +1025,8 @@ module Sass::Script
|
|
1011
1025
|
# scale-color(hsl(120, 70%, 80%), $lightness: 50%) => hsl(120, 70%, 90%)
|
1012
1026
|
# scale-color(rgb(200, 150%, 170%), $green: -40%, $blue: 70%) => rgb(200, 90, 229)
|
1013
1027
|
# scale-color(hsl(200, 70%, 80%), $saturation: -90%, $alpha: -30%) => hsla(200, 7%, 80%, 0.7)
|
1014
|
-
# @overload scale_color($color, [$red], [$green], [$blue],
|
1028
|
+
# @overload scale_color($color, [$red], [$green], [$blue],
|
1029
|
+
# [$saturation], [$lightness], [$alpha])
|
1015
1030
|
# @param $color [Sass::Script::Value::Color]
|
1016
1031
|
# @param $red [Sass::Script::Value::Number]
|
1017
1032
|
# @param $green [Sass::Script::Value::Number]
|
@@ -1034,15 +1049,16 @@ module Sass::Script
|
|
1034
1049
|
"alpha" => 1
|
1035
1050
|
}) do |name, max|
|
1036
1051
|
|
1037
|
-
|
1052
|
+
val = kwargs.delete(name)
|
1053
|
+
next unless val
|
1038
1054
|
assert_type val, :Number, name
|
1039
1055
|
assert_unit val, '%', name
|
1040
1056
|
Sass::Util.check_range("$#{name}: Amount", -100..100, val, '%')
|
1041
1057
|
|
1042
1058
|
current = color.send(name)
|
1043
|
-
scale = val.value/100.0
|
1059
|
+
scale = val.value / 100.0
|
1044
1060
|
diff = scale > 0 ? max - current : current
|
1045
|
-
[name.to_sym, current + diff*scale]
|
1061
|
+
[name.to_sym, current + diff * scale]
|
1046
1062
|
end
|
1047
1063
|
|
1048
1064
|
unless kwargs.empty?
|
@@ -1067,7 +1083,8 @@ module Sass::Script
|
|
1067
1083
|
# change-color(#102030, $blue: 5) => #102005
|
1068
1084
|
# change-color(#102030, $red: 120, $blue: 5) => #782005
|
1069
1085
|
# change-color(hsl(25, 100%, 80%), $lightness: 40%, $alpha: 0.8) => hsla(25, 100%, 40%, 0.8)
|
1070
|
-
# @overload change_color($color, [$red], [$green], [$blue], [$hue],
|
1086
|
+
# @overload change_color($color, [$red], [$green], [$blue], [$hue],
|
1087
|
+
# [$saturation], [$lightness], [$alpha])
|
1071
1088
|
# @param $color [Sass::Script::Value::Color]
|
1072
1089
|
# @param $red [Sass::Script::Value::Number] The new red component for the
|
1073
1090
|
# color, within 0 and 255 inclusive
|
@@ -1090,7 +1107,8 @@ module Sass::Script
|
|
1090
1107
|
def change_color(color, kwargs)
|
1091
1108
|
assert_type color, :Color, :color
|
1092
1109
|
with = Sass::Util.map_hash(%w[red green blue hue saturation lightness alpha]) do |name, max|
|
1093
|
-
|
1110
|
+
val = kwargs.delete(name)
|
1111
|
+
next unless val
|
1094
1112
|
assert_type val, :Number, name
|
1095
1113
|
[name.to_sym, val.value]
|
1096
1114
|
end
|
@@ -1126,7 +1144,7 @@ module Sass::Script
|
|
1126
1144
|
# @return [Sass::Script::Value::Color]
|
1127
1145
|
# @raise [ArgumentError] if `$weight` is out of bounds or any parameter is
|
1128
1146
|
# the wrong type
|
1129
|
-
def mix(color_1, color_2, weight =
|
1147
|
+
def mix(color_1, color_2, weight = number(50))
|
1130
1148
|
assert_type color_1, :Color, :color_1
|
1131
1149
|
assert_type color_2, :Color, :color_2
|
1132
1150
|
assert_type weight, :Number, :weight
|
@@ -1152,16 +1170,16 @@ module Sass::Script
|
|
1152
1170
|
#
|
1153
1171
|
# Finally, the weight of color_1 is renormalized to be within [0, 1]
|
1154
1172
|
# and the weight of color_2 is given by 1 minus the weight of color_1.
|
1155
|
-
p = (weight.value/100.0).to_f
|
1156
|
-
w = p*2 - 1
|
1173
|
+
p = (weight.value / 100.0).to_f
|
1174
|
+
w = p * 2 - 1
|
1157
1175
|
a = color_1.alpha - color_2.alpha
|
1158
1176
|
|
1159
|
-
w1 = ((
|
1177
|
+
w1 = ((w * a == -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0
|
1160
1178
|
w2 = 1 - w1
|
1161
1179
|
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1180
|
+
rgba = color_1.rgb.zip(color_2.rgb).map {|v1, v2| v1 * w1 + v2 * w2}
|
1181
|
+
rgba << color_1.alpha * p + color_2.alpha * (1 - p)
|
1182
|
+
rgb_color(*rgba)
|
1165
1183
|
end
|
1166
1184
|
declare :mix, [:color_1, :color_2]
|
1167
1185
|
declare :mix, [:color_1, :color_2, :weight]
|
@@ -1176,9 +1194,9 @@ module Sass::Script
|
|
1176
1194
|
# @raise [ArgumentError] if `$color` isn't a color
|
1177
1195
|
def grayscale(color)
|
1178
1196
|
if color.is_a?(Sass::Script::Value::Number)
|
1179
|
-
return
|
1197
|
+
return identifier("grayscale(#{color})")
|
1180
1198
|
end
|
1181
|
-
desaturate color,
|
1199
|
+
desaturate color, number(100)
|
1182
1200
|
end
|
1183
1201
|
declare :grayscale, [:color]
|
1184
1202
|
|
@@ -1191,7 +1209,7 @@ module Sass::Script
|
|
1191
1209
|
# @return [Sass::Script::Value::Color]
|
1192
1210
|
# @raise [ArgumentError] if `$color` isn't a color
|
1193
1211
|
def complement(color)
|
1194
|
-
adjust_hue color,
|
1212
|
+
adjust_hue color, number(180)
|
1195
1213
|
end
|
1196
1214
|
declare :complement, [:color]
|
1197
1215
|
|
@@ -1204,7 +1222,7 @@ module Sass::Script
|
|
1204
1222
|
# @raise [ArgumentError] if `$color` isn't a color
|
1205
1223
|
def invert(color)
|
1206
1224
|
if color.is_a?(Sass::Script::Value::Number)
|
1207
|
-
return
|
1225
|
+
return identifier("invert(#{color})")
|
1208
1226
|
end
|
1209
1227
|
|
1210
1228
|
assert_type color, :Color, :color
|
@@ -1227,8 +1245,8 @@ module Sass::Script
|
|
1227
1245
|
# @return [Sass::Script::Value::String]
|
1228
1246
|
# @raise [ArgumentError] if `$string` isn't a string
|
1229
1247
|
def unquote(string)
|
1230
|
-
if string.is_a?(Sass::Script::Value::String)
|
1231
|
-
|
1248
|
+
if string.is_a?(Sass::Script::Value::String) && string.type != :identifier
|
1249
|
+
identifier(string.value)
|
1232
1250
|
else
|
1233
1251
|
string
|
1234
1252
|
end
|
@@ -1248,7 +1266,11 @@ module Sass::Script
|
|
1248
1266
|
# @raise [ArgumentError] if `$string` isn't a string
|
1249
1267
|
def quote(string)
|
1250
1268
|
assert_type string, :String, :string
|
1251
|
-
|
1269
|
+
if string.type != :string
|
1270
|
+
quoted_string(string.value)
|
1271
|
+
else
|
1272
|
+
string
|
1273
|
+
end
|
1252
1274
|
end
|
1253
1275
|
declare :quote, [:string]
|
1254
1276
|
|
@@ -1262,7 +1284,7 @@ module Sass::Script
|
|
1262
1284
|
# @raise [ArgumentError] if `$string` isn't a string
|
1263
1285
|
def str_length(string)
|
1264
1286
|
assert_type string, :String, :string
|
1265
|
-
|
1287
|
+
number(string.value.size)
|
1266
1288
|
end
|
1267
1289
|
declare :str_length, [:string]
|
1268
1290
|
|
@@ -1291,8 +1313,13 @@ module Sass::Script
|
|
1291
1313
|
assert_type insert, :String, :insert
|
1292
1314
|
assert_integer index, :index
|
1293
1315
|
assert_unit index, nil, :index
|
1294
|
-
insertion_point = index.value > 0
|
1295
|
-
|
1316
|
+
insertion_point = if index.value > 0
|
1317
|
+
[index.value - 1, original.value.size].min
|
1318
|
+
else
|
1319
|
+
[index.value, -original.value.size - 1].max
|
1320
|
+
end
|
1321
|
+
result = original.value.dup.insert(insertion_point, insert.value)
|
1322
|
+
Sass::Script::Value::String.new(result, original.type)
|
1296
1323
|
end
|
1297
1324
|
declare :str_insert, [:string, :insert, :index]
|
1298
1325
|
|
@@ -1317,11 +1344,10 @@ module Sass::Script
|
|
1317
1344
|
assert_type string, :String, :string
|
1318
1345
|
assert_type substring, :String, :substring
|
1319
1346
|
index = string.value.index(substring.value) || -1
|
1320
|
-
|
1347
|
+
number(index + 1)
|
1321
1348
|
end
|
1322
1349
|
declare :str_index, [:string, :substring]
|
1323
1350
|
|
1324
|
-
|
1325
1351
|
# Extracts a substring from `$string`. The substring will begin at index
|
1326
1352
|
# `$start-at` and ends at index `$end-at`.
|
1327
1353
|
#
|
@@ -1348,7 +1374,7 @@ module Sass::Script
|
|
1348
1374
|
assert_type string, :String, :string
|
1349
1375
|
assert_unit start_at, nil, "start-at"
|
1350
1376
|
|
1351
|
-
end_at =
|
1377
|
+
end_at = number(-1) if end_at.nil?
|
1352
1378
|
assert_unit end_at, nil, "end-at"
|
1353
1379
|
|
1354
1380
|
s = start_at.value > 0 ? start_at.value - 1 : start_at.value
|
@@ -1407,7 +1433,7 @@ module Sass::Script
|
|
1407
1433
|
# @return [Sass::Script::Value::String] The unquoted string name of the
|
1408
1434
|
# value's type
|
1409
1435
|
def type_of(value)
|
1410
|
-
|
1436
|
+
identifier(value.class.name.gsub(/Sass::Script::Value::/, '').downcase)
|
1411
1437
|
end
|
1412
1438
|
declare :type_of, [:value]
|
1413
1439
|
|
@@ -1423,7 +1449,7 @@ module Sass::Script
|
|
1423
1449
|
# @raise [ArgumentError] if `$feature` isn't a string
|
1424
1450
|
def feature_exists(feature)
|
1425
1451
|
assert_type feature, :String, :feature
|
1426
|
-
|
1452
|
+
bool(Sass.has_feature?(feature.value))
|
1427
1453
|
end
|
1428
1454
|
declare :feature_exists, [:feature]
|
1429
1455
|
|
@@ -1443,7 +1469,7 @@ module Sass::Script
|
|
1443
1469
|
# @raise [ArgumentError] if `$number` isn't a number
|
1444
1470
|
def unit(number)
|
1445
1471
|
assert_type number, :Number, :number
|
1446
|
-
|
1472
|
+
quoted_string(number.unit_str)
|
1447
1473
|
end
|
1448
1474
|
declare :unit, [:number]
|
1449
1475
|
|
@@ -1458,7 +1484,7 @@ module Sass::Script
|
|
1458
1484
|
# @raise [ArgumentError] if `$number` isn't a number
|
1459
1485
|
def unitless(number)
|
1460
1486
|
assert_type number, :Number, :number
|
1461
|
-
|
1487
|
+
bool(number.unitless?)
|
1462
1488
|
end
|
1463
1489
|
declare :unitless, [:number]
|
1464
1490
|
|
@@ -1476,7 +1502,7 @@ module Sass::Script
|
|
1476
1502
|
def comparable(number_1, number_2)
|
1477
1503
|
assert_type number_1, :Number, :number_1
|
1478
1504
|
assert_type number_2, :Number, :number_2
|
1479
|
-
|
1505
|
+
bool(number_1.comparable_to?(number_2))
|
1480
1506
|
end
|
1481
1507
|
declare :comparable, [:number_1, :number_2]
|
1482
1508
|
|
@@ -1493,7 +1519,7 @@ module Sass::Script
|
|
1493
1519
|
unless value.is_a?(Sass::Script::Value::Number) && value.unitless?
|
1494
1520
|
raise ArgumentError.new("$value: #{value.inspect} is not a unitless number")
|
1495
1521
|
end
|
1496
|
-
|
1522
|
+
number(value.value * 100, '%')
|
1497
1523
|
end
|
1498
1524
|
declare :percentage, [:value]
|
1499
1525
|
|
@@ -1599,10 +1625,40 @@ module Sass::Script
|
|
1599
1625
|
# @param $list [Sass::Script::Value::Base]
|
1600
1626
|
# @return [Sass::Script::Value::Number]
|
1601
1627
|
def length(list)
|
1602
|
-
|
1628
|
+
number(list.to_a.size)
|
1603
1629
|
end
|
1604
1630
|
declare :length, [:list]
|
1605
1631
|
|
1632
|
+
# Return a new list, based on the list provided, but with the nth
|
1633
|
+
# element changed to the value given.
|
1634
|
+
#
|
1635
|
+
# Note that unlike some languages, the first item in a Sass list is number
|
1636
|
+
# 1, the second number 2, and so forth.
|
1637
|
+
#
|
1638
|
+
# Negative index values address elements in reverse order, starting with the last element
|
1639
|
+
# in the list.
|
1640
|
+
#
|
1641
|
+
# @example
|
1642
|
+
# set-nth($list: 10px 20px 30px, $n: 2, $value: -20px) => 10px -20px 30px
|
1643
|
+
# @overload nth($list, $n, $value)
|
1644
|
+
# @param $list [Sass::Script::Value::Base] The list that will be copied, having the element
|
1645
|
+
# at index `$n` changed.
|
1646
|
+
# @param $n [Sass::Script::Value::Number] The index of the item to set.
|
1647
|
+
# Negative indices count from the end of the list.
|
1648
|
+
# @param $value [Sass::Script::Value::Base] The new value at index `$n`.
|
1649
|
+
# @return [Sass::Script::Value::List]
|
1650
|
+
# @raise [ArgumentError] if `$n` isn't an integer between 1 and the length
|
1651
|
+
# of `$list`
|
1652
|
+
def set_nth(list, n, value)
|
1653
|
+
assert_type n, :Number, :n
|
1654
|
+
Sass::Script::Value::List.assert_valid_index(list, n)
|
1655
|
+
index = n.to_i > 0 ? n.to_i - 1 : n.to_i
|
1656
|
+
new_list = list.to_a.dup
|
1657
|
+
new_list[index] = value
|
1658
|
+
Sass::Script::Value::List.new(new_list, list.separator)
|
1659
|
+
end
|
1660
|
+
declare :set_nth, [:list, :n, :value]
|
1661
|
+
|
1606
1662
|
# Gets the nth item in a list.
|
1607
1663
|
#
|
1608
1664
|
# Note that unlike some languages, the first item in a Sass list is number
|
@@ -1610,6 +1666,9 @@ module Sass::Script
|
|
1610
1666
|
#
|
1611
1667
|
# This can return the nth pair in a map as well.
|
1612
1668
|
#
|
1669
|
+
# Negative index values address elements in reverse order, starting with the last element in
|
1670
|
+
# the list.
|
1671
|
+
#
|
1613
1672
|
# @example
|
1614
1673
|
# nth(10px 20px 30px, 1) => 10px
|
1615
1674
|
# nth((Helvetica, Arial, sans-serif), 3) => sans-serif
|
@@ -1623,13 +1682,7 @@ module Sass::Script
|
|
1623
1682
|
# of `$list`
|
1624
1683
|
def nth(list, n)
|
1625
1684
|
assert_type n, :Number, :n
|
1626
|
-
|
1627
|
-
raise ArgumentError.new("List index #{n} must be a non-zero integer")
|
1628
|
-
elsif list.to_a.size == 0
|
1629
|
-
raise ArgumentError.new("List index is #{n} but list has no items")
|
1630
|
-
elsif n.to_i.abs > (size = list.to_a.size)
|
1631
|
-
raise ArgumentError.new("List index is #{n} but list is only #{size} item#{'s' if size != 1} long")
|
1632
|
-
end
|
1685
|
+
Sass::Script::Value::List.assert_valid_index(list, n)
|
1633
1686
|
|
1634
1687
|
index = n.to_i > 0 ? n.to_i - 1 : n.to_i
|
1635
1688
|
list.to_a[index]
|
@@ -1656,18 +1709,17 @@ module Sass::Script
|
|
1656
1709
|
# If this is `comma` or `space`, that separator will be used. If this is
|
1657
1710
|
# `auto` (the default), the separator is determined as explained above.
|
1658
1711
|
# @return [Sass::Script::Value::List]
|
1659
|
-
def join(list1, list2, separator =
|
1712
|
+
def join(list1, list2, separator = identifier("auto"))
|
1660
1713
|
assert_type separator, :String, :separator
|
1661
1714
|
unless %w[auto space comma].include?(separator.value)
|
1662
1715
|
raise ArgumentError.new("Separator name must be space, comma, or auto")
|
1663
1716
|
end
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
|
1668
|
-
|
1669
|
-
|
1670
|
-
end)
|
1717
|
+
sep = if separator.value == 'auto'
|
1718
|
+
list1.separator || list2.separator || :space
|
1719
|
+
else
|
1720
|
+
separator.value.to_sym
|
1721
|
+
end
|
1722
|
+
list(list1.to_a + list2.to_a, sep)
|
1671
1723
|
end
|
1672
1724
|
declare :join, [:list1, :list2]
|
1673
1725
|
declare :join, [:list1, :list2, :separator]
|
@@ -1690,18 +1742,17 @@ module Sass::Script
|
|
1690
1742
|
# If this is `comma` or `space`, that separator will be used. If this is
|
1691
1743
|
# `auto` (the default), the separator is determined as explained above.
|
1692
1744
|
# @return [Sass::Script::Value::List]
|
1693
|
-
def append(list, val, separator =
|
1745
|
+
def append(list, val, separator = identifier("auto"))
|
1694
1746
|
assert_type separator, :String, :separator
|
1695
1747
|
unless %w[auto space comma].include?(separator.value)
|
1696
1748
|
raise ArgumentError.new("Separator name must be space, comma, or auto")
|
1697
1749
|
end
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
end)
|
1750
|
+
sep = if separator.value == 'auto'
|
1751
|
+
list.separator || :space
|
1752
|
+
else
|
1753
|
+
separator.value.to_sym
|
1754
|
+
end
|
1755
|
+
list(list.to_a + [val], sep)
|
1705
1756
|
end
|
1706
1757
|
declare :append, [:list, :val]
|
1707
1758
|
declare :append, [:list, :val, :separator]
|
@@ -1731,11 +1782,10 @@ module Sass::Script
|
|
1731
1782
|
value.slice!(length)
|
1732
1783
|
end
|
1733
1784
|
new_list_value = values.first.zip(*values[1..-1])
|
1734
|
-
|
1785
|
+
list(new_list_value.map {|list| list(list, :space)}, :comma)
|
1735
1786
|
end
|
1736
1787
|
declare :zip, [], :var_args => true
|
1737
1788
|
|
1738
|
-
|
1739
1789
|
# Returns the position of a value within a list. If the value isn't found,
|
1740
1790
|
# returns false instead.
|
1741
1791
|
#
|
@@ -1754,11 +1804,11 @@ module Sass::Script
|
|
1754
1804
|
# @return [Sass::Script::Value::Number, Sass::Script::Value::Bool] The
|
1755
1805
|
# 1-based index of `$value` in `$list`, or `false`
|
1756
1806
|
def index(list, value)
|
1757
|
-
index = list.to_a.index {|e| e.eq(value).to_bool
|
1807
|
+
index = list.to_a.index {|e| e.eq(value).to_bool}
|
1758
1808
|
if index
|
1759
|
-
|
1809
|
+
number(index + 1)
|
1760
1810
|
else
|
1761
|
-
|
1811
|
+
bool(false)
|
1762
1812
|
end
|
1763
1813
|
end
|
1764
1814
|
declare :index, [:list, :value]
|
@@ -1774,7 +1824,7 @@ module Sass::Script
|
|
1774
1824
|
# @param $list [Sass::Script::Value::Base]
|
1775
1825
|
# @return [Sass::Script::Value::String] `comma` or `space`
|
1776
1826
|
def list_separator(list)
|
1777
|
-
|
1827
|
+
identifier((list.separator || :space).to_s)
|
1778
1828
|
end
|
1779
1829
|
declare :separator, [:list]
|
1780
1830
|
|
@@ -1883,7 +1933,8 @@ module Sass::Script
|
|
1883
1933
|
# @raise [ArgumentError] if `$args` isn't a variable argument list
|
1884
1934
|
def keywords(args)
|
1885
1935
|
assert_type args, :ArgList
|
1886
|
-
Sass::Script::Value::Map.new(
|
1936
|
+
Sass::Script::Value::Map.new(
|
1937
|
+
Sass::Util.map_keys(args.keywords) {|k| Sass::Script::String.new(k)})
|
1887
1938
|
end
|
1888
1939
|
declare :keywords, [:args]
|
1889
1940
|
|
@@ -1920,7 +1971,7 @@ module Sass::Script
|
|
1920
1971
|
# avoid the temptation of trying to guess the next unique value.
|
1921
1972
|
value = (Thread.current[:sass_last_unique_id] += (rand(10) + 1))
|
1922
1973
|
# the u makes this a legal identifier if it would otherwise start with a number.
|
1923
|
-
|
1974
|
+
identifier("u" + value.to_s(36).rjust(8, '0'))
|
1924
1975
|
end
|
1925
1976
|
declare :unique_id, []
|
1926
1977
|
|
@@ -1963,7 +2014,7 @@ module Sass::Script
|
|
1963
2014
|
# @overload counter($args...)
|
1964
2015
|
# @return [String]
|
1965
2016
|
def counter(*args)
|
1966
|
-
|
2017
|
+
identifier("counter(#{args.map {|a| a.to_s(options)}.join(',')})")
|
1967
2018
|
end
|
1968
2019
|
declare :counter, [], :var_args => true
|
1969
2020
|
|
@@ -1989,10 +2040,14 @@ module Sass::Script
|
|
1989
2040
|
# It yields a number to a block to perform the operation and return a number
|
1990
2041
|
def numeric_transformation(value)
|
1991
2042
|
assert_type value, :Number, :value
|
1992
|
-
Sass::Script::Value::Number.new(
|
2043
|
+
Sass::Script::Value::Number.new(
|
2044
|
+
yield(value.value), value.numerator_units, value.denominator_units)
|
1993
2045
|
end
|
1994
2046
|
|
2047
|
+
# @comment
|
2048
|
+
# rubocop:disable ParameterLists
|
1995
2049
|
def _adjust(color, amount, attr, range, op, units = "")
|
2050
|
+
# rubocop:enable ParameterLists
|
1996
2051
|
assert_type color, :Color, :color
|
1997
2052
|
assert_type amount, :Number, :amount
|
1998
2053
|
Sass::Util.check_range('Amount', range, amount, units)
|
@@ -2013,7 +2068,7 @@ DEPRECATION WARNING: Passing lists of pairs to #{fn_name} is deprecated and will
|
|
2013
2068
|
be removed in future versions of Sass. Use Sass maps instead. For details, see
|
2014
2069
|
http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#maps.
|
2015
2070
|
WARNING
|
2016
|
-
|
2071
|
+
obj.to_h
|
2017
2072
|
end
|
2018
2073
|
end
|
2019
2074
|
end
|