sass 3.1.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CONTRIBUTING +1 -1
- data/MIT-LICENSE +2 -2
- data/README.md +29 -17
- data/Rakefile +43 -9
- data/VERSION +1 -1
- data/VERSION_DATE +1 -0
- data/VERSION_NAME +1 -1
- data/bin/sass +6 -1
- data/bin/sass-convert +6 -1
- data/bin/scss +6 -1
- data/ext/mkrf_conf.rb +27 -0
- data/lib/sass/cache_stores/base.rb +7 -3
- data/lib/sass/cache_stores/chain.rb +3 -2
- data/lib/sass/cache_stores/filesystem.rb +5 -7
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +2 -1
- data/lib/sass/css.rb +168 -53
- data/lib/sass/engine.rb +502 -174
- data/lib/sass/environment.rb +151 -111
- data/lib/sass/error.rb +7 -7
- data/lib/sass/exec.rb +176 -60
- data/lib/sass/features.rb +40 -0
- data/lib/sass/importers/base.rb +46 -7
- data/lib/sass/importers/deprecated_path.rb +51 -0
- data/lib/sass/importers/filesystem.rb +113 -30
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +30 -0
- data/lib/sass/logger/log_level.rb +45 -0
- data/lib/sass/logger.rb +12 -0
- data/lib/sass/media.rb +213 -0
- data/lib/sass/plugin/compiler.rb +194 -104
- data/lib/sass/plugin/configuration.rb +18 -25
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +37 -11
- data/lib/sass/plugin.rb +10 -13
- data/lib/sass/railtie.rb +2 -1
- data/lib/sass/repl.rb +5 -6
- data/lib/sass/script/css_lexer.rb +8 -4
- data/lib/sass/script/css_parser.rb +5 -2
- data/lib/sass/script/functions.rb +1547 -618
- data/lib/sass/script/lexer.rb +122 -72
- data/lib/sass/script/parser.rb +304 -135
- data/lib/sass/script/tree/funcall.rb +306 -0
- data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
- data/lib/sass/script/tree/list_literal.rb +77 -0
- data/lib/sass/script/tree/literal.rb +45 -0
- data/lib/sass/script/tree/map_literal.rb +64 -0
- data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
- data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
- data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
- data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
- data/lib/sass/script/tree/variable.rb +57 -0
- data/lib/sass/script/tree.rb +15 -0
- data/lib/sass/script/value/arg_list.rb +36 -0
- data/lib/sass/script/value/base.rb +238 -0
- data/lib/sass/script/value/bool.rb +40 -0
- data/lib/sass/script/{color.rb → value/color.rb} +256 -74
- data/lib/sass/script/value/deprecated_false.rb +55 -0
- data/lib/sass/script/value/helpers.rb +155 -0
- data/lib/sass/script/value/list.rb +128 -0
- data/lib/sass/script/value/map.rb +70 -0
- data/lib/sass/script/value/null.rb +49 -0
- data/lib/sass/script/{number.rb → value/number.rb} +115 -62
- data/lib/sass/script/{string.rb → value/string.rb} +9 -11
- data/lib/sass/script/value.rb +12 -0
- data/lib/sass/script.rb +35 -9
- data/lib/sass/scss/css_parser.rb +2 -12
- data/lib/sass/scss/parser.rb +657 -230
- data/lib/sass/scss/rx.rb +17 -12
- data/lib/sass/scss/static_parser.rb +37 -6
- data/lib/sass/scss.rb +0 -1
- data/lib/sass/selector/abstract_sequence.rb +35 -3
- data/lib/sass/selector/comma_sequence.rb +29 -14
- data/lib/sass/selector/sequence.rb +371 -74
- data/lib/sass/selector/simple.rb +28 -13
- data/lib/sass/selector/simple_sequence.rb +163 -36
- data/lib/sass/selector.rb +138 -36
- data/lib/sass/shared.rb +3 -5
- data/lib/sass/source/map.rb +196 -0
- data/lib/sass/source/position.rb +39 -0
- data/lib/sass/source/range.rb +41 -0
- data/lib/sass/stack.rb +126 -0
- data/lib/sass/supports.rb +228 -0
- data/lib/sass/tree/at_root_node.rb +82 -0
- data/lib/sass/tree/comment_node.rb +34 -29
- data/lib/sass/tree/content_node.rb +9 -0
- data/lib/sass/tree/css_import_node.rb +60 -0
- data/lib/sass/tree/debug_node.rb +3 -3
- data/lib/sass/tree/directive_node.rb +33 -3
- data/lib/sass/tree/each_node.rb +9 -9
- data/lib/sass/tree/extend_node.rb +20 -6
- data/lib/sass/tree/for_node.rb +6 -6
- data/lib/sass/tree/function_node.rb +12 -4
- data/lib/sass/tree/if_node.rb +2 -15
- data/lib/sass/tree/import_node.rb +11 -5
- data/lib/sass/tree/media_node.rb +27 -11
- data/lib/sass/tree/mixin_def_node.rb +15 -4
- data/lib/sass/tree/mixin_node.rb +27 -7
- data/lib/sass/tree/node.rb +69 -35
- data/lib/sass/tree/prop_node.rb +47 -31
- data/lib/sass/tree/return_node.rb +4 -3
- data/lib/sass/tree/root_node.rb +20 -4
- data/lib/sass/tree/rule_node.rb +37 -26
- data/lib/sass/tree/supports_node.rb +38 -0
- data/lib/sass/tree/trace_node.rb +33 -0
- data/lib/sass/tree/variable_node.rb +10 -4
- data/lib/sass/tree/visitors/base.rb +5 -8
- data/lib/sass/tree/visitors/check_nesting.rb +67 -52
- data/lib/sass/tree/visitors/convert.rb +134 -53
- data/lib/sass/tree/visitors/cssize.rb +245 -51
- data/lib/sass/tree/visitors/deep_copy.rb +102 -0
- data/lib/sass/tree/visitors/extend.rb +68 -0
- data/lib/sass/tree/visitors/perform.rb +331 -105
- data/lib/sass/tree/visitors/set_options.rb +125 -0
- data/lib/sass/tree/visitors/to_css.rb +259 -95
- data/lib/sass/tree/warn_node.rb +3 -3
- data/lib/sass/tree/while_node.rb +3 -3
- data/lib/sass/util/cross_platform_random.rb +19 -0
- data/lib/sass/util/multibyte_string_scanner.rb +157 -0
- data/lib/sass/util/normalized_map.rb +130 -0
- data/lib/sass/util/ordered_hash.rb +192 -0
- data/lib/sass/util/subset_map.rb +11 -2
- data/lib/sass/util/test.rb +9 -0
- data/lib/sass/util.rb +565 -39
- data/lib/sass/version.rb +27 -15
- data/lib/sass.rb +39 -4
- data/test/sass/cache_test.rb +15 -0
- data/test/sass/compiler_test.rb +223 -0
- data/test/sass/conversion_test.rb +901 -107
- data/test/sass/css2sass_test.rb +94 -0
- data/test/sass/engine_test.rb +1059 -164
- data/test/sass/exec_test.rb +86 -0
- data/test/sass/extend_test.rb +933 -837
- data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
- data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
- data/test/sass/functions_test.rb +995 -136
- data/test/sass/importer_test.rb +338 -18
- data/test/sass/logger_test.rb +58 -0
- data/test/sass/more_results/more_import.css +2 -2
- data/test/sass/plugin_test.rb +114 -30
- data/test/sass/results/cached_import_option.css +3 -0
- data/test/sass/results/filename_fn.css +3 -0
- data/test/sass/results/import.css +2 -2
- data/test/sass/results/import_charset.css +1 -0
- data/test/sass/results/import_charset_1_8.css +1 -0
- data/test/sass/results/import_charset_ibm866.css +1 -0
- data/test/sass/results/import_content.css +1 -0
- data/test/sass/results/script.css +1 -1
- data/test/sass/results/scss_import.css +2 -2
- data/test/sass/results/units.css +2 -2
- data/test/sass/script_conversion_test.rb +43 -1
- data/test/sass/script_test.rb +380 -36
- data/test/sass/scss/css_test.rb +257 -75
- data/test/sass/scss/scss_test.rb +2322 -110
- data/test/sass/source_map_test.rb +887 -0
- data/test/sass/templates/_cached_import_option_partial.scss +1 -0
- data/test/sass/templates/_double_import_loop2.sass +1 -0
- data/test/sass/templates/_filename_fn_import.scss +11 -0
- data/test/sass/templates/_imported_content.sass +3 -0
- data/test/sass/templates/_same_name_different_partiality.scss +1 -0
- data/test/sass/templates/bork5.sass +3 -0
- data/test/sass/templates/cached_import_option.scss +3 -0
- data/test/sass/templates/double_import_loop1.sass +1 -0
- data/test/sass/templates/filename_fn.scss +18 -0
- data/test/sass/templates/import_charset.sass +2 -0
- data/test/sass/templates/import_charset_1_8.sass +2 -0
- data/test/sass/templates/import_charset_ibm866.sass +2 -0
- data/test/sass/templates/import_content.sass +4 -0
- data/test/sass/templates/same_name_different_ext.sass +2 -0
- data/test/sass/templates/same_name_different_ext.scss +1 -0
- data/test/sass/templates/same_name_different_partiality.scss +1 -0
- data/test/sass/templates/single_import_loop.sass +1 -0
- data/test/sass/templates/subdir/import_up1.scss +1 -0
- data/test/sass/templates/subdir/import_up2.scss +1 -0
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
- data/test/sass/util/normalized_map_test.rb +51 -0
- data/test/sass/util_test.rb +183 -0
- data/test/sass/value_helpers_test.rb +181 -0
- data/test/test_helper.rb +45 -5
- data/vendor/listen/CHANGELOG.md +228 -0
- data/vendor/listen/CONTRIBUTING.md +38 -0
- data/vendor/listen/Gemfile +30 -0
- data/vendor/listen/Guardfile +8 -0
- data/vendor/{fssm → listen}/LICENSE +1 -1
- data/vendor/listen/README.md +315 -0
- data/vendor/listen/Rakefile +47 -0
- data/vendor/listen/Vagrantfile +96 -0
- data/vendor/listen/lib/listen/adapter.rb +214 -0
- data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
- data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
- data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
- data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
- data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
- data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
- data/vendor/listen/lib/listen/directory_record.rb +371 -0
- data/vendor/listen/lib/listen/listener.rb +225 -0
- data/vendor/listen/lib/listen/multi_listener.rb +143 -0
- data/vendor/listen/lib/listen/turnstile.rb +28 -0
- data/vendor/listen/lib/listen/version.rb +3 -0
- data/vendor/listen/lib/listen.rb +40 -0
- data/vendor/listen/listen.gemspec +22 -0
- data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
- data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
- data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
- data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
- data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
- data/vendor/listen/spec/listen/listener_spec.rb +169 -0
- data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
- data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
- data/vendor/listen/spec/listen_spec.rb +73 -0
- data/vendor/listen/spec/spec_helper.rb +21 -0
- data/vendor/listen/spec/support/adapter_helper.rb +629 -0
- data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
- data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
- data/vendor/listen/spec/support/listeners_helper.rb +156 -0
- data/vendor/listen/spec/support/platform_helper.rb +15 -0
- metadata +344 -271
- data/lib/sass/less.rb +0 -382
- data/lib/sass/script/bool.rb +0 -18
- data/lib/sass/script/funcall.rb +0 -162
- data/lib/sass/script/list.rb +0 -76
- data/lib/sass/script/literal.rb +0 -245
- data/lib/sass/script/variable.rb +0 -54
- data/lib/sass/scss/sass_parser.rb +0 -11
- data/test/sass/less_conversion_test.rb +0 -653
- data/vendor/fssm/README.markdown +0 -55
- data/vendor/fssm/Rakefile +0 -59
- data/vendor/fssm/VERSION.yml +0 -5
- data/vendor/fssm/example.rb +0 -9
- data/vendor/fssm/fssm.gemspec +0 -77
- data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
- data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
- data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
- data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
- data/vendor/fssm/lib/fssm/monitor.rb +0 -26
- data/vendor/fssm/lib/fssm/path.rb +0 -91
- data/vendor/fssm/lib/fssm/pathname.rb +0 -502
- data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
- data/vendor/fssm/lib/fssm/state/file.rb +0 -24
- data/vendor/fssm/lib/fssm/support.rb +0 -63
- data/vendor/fssm/lib/fssm/tree.rb +0 -176
- data/vendor/fssm/lib/fssm.rb +0 -33
- data/vendor/fssm/profile/prof-cache.rb +0 -40
- data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
- data/vendor/fssm/profile/prof-pathname.rb +0 -68
- data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
- data/vendor/fssm/profile/prof.html +0 -2379
- data/vendor/fssm/spec/path_spec.rb +0 -75
- data/vendor/fssm/spec/root/duck/quack.txt +0 -0
- data/vendor/fssm/spec/root/file.css +0 -0
- data/vendor/fssm/spec/root/file.rb +0 -0
- data/vendor/fssm/spec/root/file.yml +0 -0
- data/vendor/fssm/spec/root/moo/cow.txt +0 -0
- data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -0,0 +1,306 @@
|
|
1
|
+
require 'sass/script/functions'
|
2
|
+
require 'sass/util/normalized_map'
|
3
|
+
|
4
|
+
module Sass::Script::Tree
|
5
|
+
# A SassScript parse node representing a function call.
|
6
|
+
#
|
7
|
+
# A function call either calls one of the functions in
|
8
|
+
# {Sass::Script::Functions}, or if no function with the given name exists it
|
9
|
+
# returns a string representation of the function call.
|
10
|
+
class Funcall < Node
|
11
|
+
# The name of the function.
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
attr_reader :name
|
15
|
+
|
16
|
+
# The arguments to the function.
|
17
|
+
#
|
18
|
+
# @return [Array<Node>]
|
19
|
+
attr_reader :args
|
20
|
+
|
21
|
+
# The keyword arguments to the function.
|
22
|
+
#
|
23
|
+
# @return [Sass::Util::NormalizedMap<Node>]
|
24
|
+
attr_reader :keywords
|
25
|
+
|
26
|
+
# The first splat argument for this function, if one exists.
|
27
|
+
#
|
28
|
+
# This could be a list of positional arguments, a map of keyword
|
29
|
+
# arguments, or an arglist containing both.
|
30
|
+
#
|
31
|
+
# @return [Node?]
|
32
|
+
attr_accessor :splat
|
33
|
+
|
34
|
+
# The second splat argument for this function, if one exists.
|
35
|
+
#
|
36
|
+
# If this exists, it's always a map of keyword arguments, and
|
37
|
+
# \{#splat} is always either a list or an arglist.
|
38
|
+
#
|
39
|
+
# @return [Node?]
|
40
|
+
attr_accessor :kwarg_splat
|
41
|
+
|
42
|
+
# @param name [String] See \{#name}
|
43
|
+
# @param args [Array<Node>] See \{#args}
|
44
|
+
# @param keywords [Sass::Util::NormalizedMap<Node>] See \{#keywords}
|
45
|
+
# @param splat [Node] See \{#splat}
|
46
|
+
# @param kwarg_splat [Node] See \{#kwarg_splat}
|
47
|
+
def initialize(name, args, keywords, splat, kwarg_splat)
|
48
|
+
@name = name
|
49
|
+
@args = args
|
50
|
+
@keywords = keywords
|
51
|
+
@splat = splat
|
52
|
+
@kwarg_splat = kwarg_splat
|
53
|
+
super()
|
54
|
+
end
|
55
|
+
|
56
|
+
# @return [String] A string representation of the function call
|
57
|
+
def inspect
|
58
|
+
args = @args.map {|a| a.inspect}.join(', ')
|
59
|
+
keywords = Sass::Util.hash_to_a(@keywords.as_stored).
|
60
|
+
map {|k, v| "$#{k}: #{v.inspect}"}.join(', ')
|
61
|
+
# rubocop:disable RedundantSelf
|
62
|
+
if self.splat
|
63
|
+
splat = args.empty? && keywords.empty? ? "" : ", "
|
64
|
+
splat = "#{splat}#{self.splat.inspect}..."
|
65
|
+
splat = "#{splat}, #{kwarg_splat.inspect}..." if kwarg_splat
|
66
|
+
end
|
67
|
+
# rubocop:enable RedundantSelf
|
68
|
+
"#{name}(#{args}#{', ' unless args.empty? || keywords.empty?}#{keywords}#{splat})"
|
69
|
+
end
|
70
|
+
|
71
|
+
# @see Node#to_sass
|
72
|
+
def to_sass(opts = {})
|
73
|
+
arg_to_sass = lambda do |arg|
|
74
|
+
sass = arg.to_sass(opts)
|
75
|
+
sass = "(#{sass})" if arg.is_a?(Sass::Script::Tree::ListLiteral) && arg.separator == :comma
|
76
|
+
sass
|
77
|
+
end
|
78
|
+
|
79
|
+
args = @args.map(&arg_to_sass)
|
80
|
+
keywords = Sass::Util.hash_to_a(@keywords.as_stored).
|
81
|
+
map {|k, v| "$#{dasherize(k, opts)}: #{arg_to_sass[v]}"}
|
82
|
+
|
83
|
+
# rubocop:disable RedundantSelf
|
84
|
+
if self.splat
|
85
|
+
splat = "#{arg_to_sass[self.splat]}..."
|
86
|
+
kwarg_splat = "#{arg_to_sass[self.kwarg_splat]}..." if self.kwarg_splat
|
87
|
+
end
|
88
|
+
# rubocop:enable RedundantSelf
|
89
|
+
|
90
|
+
arglist = [args, splat, keywords, kwarg_splat].flatten.compact.join(', ')
|
91
|
+
"#{dasherize(name, opts)}(#{arglist})"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns the arguments to the function.
|
95
|
+
#
|
96
|
+
# @return [Array<Node>]
|
97
|
+
# @see Node#children
|
98
|
+
def children
|
99
|
+
res = @args + @keywords.values
|
100
|
+
res << @splat if @splat
|
101
|
+
res << @kwarg_splat if @kwarg_splat
|
102
|
+
res
|
103
|
+
end
|
104
|
+
|
105
|
+
# @see Node#deep_copy
|
106
|
+
def deep_copy
|
107
|
+
node = dup
|
108
|
+
node.instance_variable_set('@args', args.map {|a| a.deep_copy})
|
109
|
+
copied_keywords = Sass::Util::NormalizedMap.new
|
110
|
+
@keywords.as_stored.each {|k, v| copied_keywords[k] = v.deep_copy}
|
111
|
+
node.instance_variable_set('@keywords', copied_keywords)
|
112
|
+
node
|
113
|
+
end
|
114
|
+
|
115
|
+
protected
|
116
|
+
|
117
|
+
# Evaluates the function call.
|
118
|
+
#
|
119
|
+
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
120
|
+
# @return [Sass::Script::Value] The SassScript object that is the value of the function call
|
121
|
+
# @raise [Sass::SyntaxError] if the function call raises an ArgumentError
|
122
|
+
def _perform(environment)
|
123
|
+
args = Sass::Util.enum_with_index(@args).
|
124
|
+
map {|a, i| perform_arg(a, environment, signature && signature.args[i])}
|
125
|
+
keywords = Sass::Util.map_hash(@keywords) do |k, v|
|
126
|
+
[k, perform_arg(v, environment, k.tr('-', '_'))]
|
127
|
+
end
|
128
|
+
splat = Sass::Tree::Visitors::Perform.perform_splat(
|
129
|
+
@splat, keywords, @kwarg_splat, environment)
|
130
|
+
if (fn = environment.function(@name))
|
131
|
+
return without_original(perform_sass_fn(fn, args, splat, environment))
|
132
|
+
end
|
133
|
+
|
134
|
+
args = construct_ruby_args(ruby_name, args, splat, environment)
|
135
|
+
|
136
|
+
if Sass::Script::Functions.callable?(ruby_name)
|
137
|
+
local_environment = Sass::Environment.new(environment.global_env, environment.options)
|
138
|
+
local_environment.caller = Sass::ReadOnlyEnvironment.new(environment, environment.options)
|
139
|
+
result = opts(Sass::Script::Functions::EvaluationContext.new(
|
140
|
+
local_environment).send(ruby_name, *args))
|
141
|
+
without_original(result)
|
142
|
+
else
|
143
|
+
opts(to_literal(args))
|
144
|
+
end
|
145
|
+
rescue ArgumentError => e
|
146
|
+
reformat_argument_error(e)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Compass historically overrode this before it changed name to {Funcall#to_value}.
|
150
|
+
# We should get rid of it in the future.
|
151
|
+
def to_literal(args)
|
152
|
+
to_value(args)
|
153
|
+
end
|
154
|
+
|
155
|
+
# This method is factored out from `_perform` so that compass can override
|
156
|
+
# it with a cross-browser implementation for functions that require vendor prefixes
|
157
|
+
# in the generated css.
|
158
|
+
def to_value(args)
|
159
|
+
Sass::Script::Value::String.new("#{name}(#{args.join(', ')})")
|
160
|
+
end
|
161
|
+
|
162
|
+
private
|
163
|
+
|
164
|
+
def ruby_name
|
165
|
+
@ruby_name ||= @name.tr('-', '_')
|
166
|
+
end
|
167
|
+
|
168
|
+
def perform_arg(argument, environment, name)
|
169
|
+
return argument if signature && signature.delayed_args.include?(name)
|
170
|
+
argument.perform(environment)
|
171
|
+
end
|
172
|
+
|
173
|
+
def signature
|
174
|
+
@signature ||= Sass::Script::Functions.signature(name.to_sym, @args.size, @keywords.size)
|
175
|
+
end
|
176
|
+
|
177
|
+
def without_original(value)
|
178
|
+
return value unless value.is_a?(Sass::Script::Value::Number)
|
179
|
+
value = value.dup
|
180
|
+
value.original = nil
|
181
|
+
value
|
182
|
+
end
|
183
|
+
|
184
|
+
def construct_ruby_args(name, args, splat, environment)
|
185
|
+
args += splat.to_a if splat
|
186
|
+
|
187
|
+
# All keywords are contained in splat.keywords for consistency,
|
188
|
+
# even if there were no splats passed in.
|
189
|
+
old_keywords_accessed = splat.keywords_accessed
|
190
|
+
keywords = splat.keywords
|
191
|
+
splat.keywords_accessed = old_keywords_accessed
|
192
|
+
|
193
|
+
unless (signature = Sass::Script::Functions.signature(name.to_sym, args.size, keywords.size))
|
194
|
+
return args if keywords.empty?
|
195
|
+
raise Sass::SyntaxError.new("Function #{name} doesn't support keyword arguments")
|
196
|
+
end
|
197
|
+
|
198
|
+
# If the user passes more non-keyword args than the function expects,
|
199
|
+
# but it does expect keyword args, Ruby's arg handling won't raise an error.
|
200
|
+
# Since we don't want to make functions think about this,
|
201
|
+
# we'll handle it for them here.
|
202
|
+
if signature.var_kwargs && !signature.var_args && args.size > signature.args.size
|
203
|
+
raise Sass::SyntaxError.new(
|
204
|
+
"#{args[signature.args.size].inspect} is not a keyword argument for `#{name}'")
|
205
|
+
elsif keywords.empty?
|
206
|
+
return args
|
207
|
+
end
|
208
|
+
|
209
|
+
argnames = signature.args[args.size..-1] || []
|
210
|
+
deprecated_argnames = (signature.deprecated && signature.deprecated[args.size..-1]) || []
|
211
|
+
args = args + argnames.zip(deprecated_argnames).map do |(argname, deprecated_argname)|
|
212
|
+
if keywords.has_key?(argname)
|
213
|
+
keywords.delete(argname)
|
214
|
+
elsif deprecated_argname && keywords.has_key?(deprecated_argname)
|
215
|
+
deprecated_argname = keywords.denormalize(deprecated_argname)
|
216
|
+
Sass::Util.sass_warn("DEPRECATION WARNING: The `$#{deprecated_argname}' argument for " +
|
217
|
+
"`#{name}()' has been renamed to `$#{argname}'.")
|
218
|
+
keywords.delete(deprecated_argname)
|
219
|
+
else
|
220
|
+
raise Sass::SyntaxError.new("Function #{name} requires an argument named $#{argname}")
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
if keywords.size > 0
|
225
|
+
if signature.var_kwargs
|
226
|
+
# Don't pass a NormalizedMap to a Ruby function.
|
227
|
+
args << keywords.to_hash
|
228
|
+
else
|
229
|
+
argname = keywords.keys.sort.first
|
230
|
+
if signature.args.include?(argname)
|
231
|
+
raise Sass::SyntaxError.new(
|
232
|
+
"Function #{name} was passed argument $#{argname} both by position and by name")
|
233
|
+
else
|
234
|
+
raise Sass::SyntaxError.new(
|
235
|
+
"Function #{name} doesn't have an argument named $#{argname}")
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
args
|
241
|
+
end
|
242
|
+
|
243
|
+
def perform_sass_fn(function, args, splat, environment)
|
244
|
+
Sass::Tree::Visitors::Perform.perform_arguments(function, args, splat) do |env|
|
245
|
+
env.caller = Sass::Environment.new(environment)
|
246
|
+
|
247
|
+
val = catch :_sass_return do
|
248
|
+
function.tree.each {|c| Sass::Tree::Visitors::Perform.visit(c, env)}
|
249
|
+
raise Sass::SyntaxError.new("Function #{@name} finished without @return")
|
250
|
+
end
|
251
|
+
val
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def reformat_argument_error(e)
|
256
|
+
message = e.message
|
257
|
+
|
258
|
+
# If this is a legitimate Ruby-raised argument error, re-raise it.
|
259
|
+
# Otherwise, it's an error in the user's stylesheet, so wrap it.
|
260
|
+
if Sass::Util.rbx?
|
261
|
+
# Rubinius has a different error report string than vanilla Ruby. It
|
262
|
+
# also doesn't put the actual method for which the argument error was
|
263
|
+
# thrown in the backtrace, nor does it include `send`, so we look for
|
264
|
+
# `_perform`.
|
265
|
+
if e.message =~ /^method '([^']+)': given (\d+), expected (\d+)/
|
266
|
+
error_name, given, expected = $1, $2, $3
|
267
|
+
raise e if error_name != ruby_name || e.backtrace[0] !~ /:in `_perform'$/
|
268
|
+
message = "wrong number of arguments (#{given} for #{expected})"
|
269
|
+
end
|
270
|
+
elsif Sass::Util.jruby?
|
271
|
+
if Sass::Util.jruby1_6?
|
272
|
+
should_maybe_raise = e.message =~ /^wrong number of arguments \((\d+) for (\d+)\)/ &&
|
273
|
+
# The one case where JRuby does include the Ruby name of the function
|
274
|
+
# is manually-thrown ArgumentErrors, which are indistinguishable from
|
275
|
+
# legitimate ArgumentErrors. We treat both of these as
|
276
|
+
# Sass::SyntaxErrors even though it can hide Ruby errors.
|
277
|
+
e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
|
278
|
+
else
|
279
|
+
should_maybe_raise =
|
280
|
+
e.message =~ /^wrong number of arguments calling `[^`]+` \((\d+) for (\d+)\)/
|
281
|
+
given, expected = $1, $2
|
282
|
+
end
|
283
|
+
|
284
|
+
if should_maybe_raise
|
285
|
+
# JRuby 1.7 includes __send__ before send and _perform.
|
286
|
+
trace = e.backtrace.dup
|
287
|
+
raise e if !Sass::Util.jruby1_6? && trace.shift !~ /:in `__send__'$/
|
288
|
+
|
289
|
+
# JRuby (as of 1.7.2) doesn't put the actual method
|
290
|
+
# for which the argument error was thrown in the backtrace, so we
|
291
|
+
# detect whether our send threw an argument error.
|
292
|
+
if !(trace[0] =~ /:in `send'$/ && trace[1] =~ /:in `_perform'$/)
|
293
|
+
raise e
|
294
|
+
elsif !Sass::Util.jruby1_6?
|
295
|
+
# JRuby 1.7 doesn't use standard formatting for its ArgumentErrors.
|
296
|
+
message = "wrong number of arguments (#{given} for #{expected})"
|
297
|
+
end
|
298
|
+
end
|
299
|
+
elsif e.message =~ /^wrong number of arguments \(\d+ for \d+\)/ &&
|
300
|
+
e.backtrace[0] !~ /:in `(block in )?#{ruby_name}'$/
|
301
|
+
raise e
|
302
|
+
end
|
303
|
+
raise Sass::SyntaxError.new("#{message} for `#{name}'")
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
@@ -1,20 +1,40 @@
|
|
1
|
-
module Sass::Script
|
1
|
+
module Sass::Script::Tree
|
2
2
|
# A SassScript object representing `#{}` interpolation outside a string.
|
3
3
|
#
|
4
4
|
# @see StringInterpolation
|
5
5
|
class Interpolation < Node
|
6
|
+
# @return [Node] The SassScript before the interpolation
|
7
|
+
attr_reader :before
|
8
|
+
|
9
|
+
# @return [Node] The SassScript within the interpolation
|
10
|
+
attr_reader :mid
|
11
|
+
|
12
|
+
# @return [Node] The SassScript after the interpolation
|
13
|
+
attr_reader :after
|
14
|
+
|
15
|
+
# @return [Boolean] Whether there was whitespace between `before` and `#{`
|
16
|
+
attr_reader :whitespace_before
|
17
|
+
|
18
|
+
# @return [Boolean] Whether there was whitespace between `}` and `after`
|
19
|
+
attr_reader :whitespace_after
|
20
|
+
|
21
|
+
# @return [Boolean] Whether the original format of the interpolation was
|
22
|
+
# plain text, not an interpolation. This is used when converting back to
|
23
|
+
# SassScript.
|
24
|
+
attr_reader :originally_text
|
25
|
+
|
6
26
|
# Interpolation in a property is of the form `before #{mid} after`.
|
7
27
|
#
|
8
|
-
# @param before [Node]
|
9
|
-
# @param mid [Node]
|
10
|
-
# @param after [Node]
|
11
|
-
# @param wb [Boolean]
|
12
|
-
# @param wa [Boolean]
|
13
|
-
# @param originally_text [Boolean]
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# This is used when converting back to SassScript.
|
28
|
+
# @param before [Node] See {Interpolation#before}
|
29
|
+
# @param mid [Node] See {Interpolation#mid}
|
30
|
+
# @param after [Node] See {Interpolation#after}
|
31
|
+
# @param wb [Boolean] See {Interpolation#whitespace_before}
|
32
|
+
# @param wa [Boolean] See {Interpolation#whitespace_after}
|
33
|
+
# @param originally_text [Boolean] See {Interpolation#originally_text}
|
34
|
+
# @comment
|
35
|
+
# rubocop:disable ParameterLists
|
17
36
|
def initialize(before, mid, after, wb, wa, originally_text = false)
|
37
|
+
# rubocop:enable ParameterLists
|
18
38
|
@before = before
|
19
39
|
@mid = mid
|
20
40
|
@after = after
|
@@ -50,21 +70,31 @@ module Sass::Script
|
|
50
70
|
[@before, @mid, @after].compact
|
51
71
|
end
|
52
72
|
|
73
|
+
# @see Node#deep_copy
|
74
|
+
def deep_copy
|
75
|
+
node = dup
|
76
|
+
node.instance_variable_set('@before', @before.deep_copy) if @before
|
77
|
+
node.instance_variable_set('@mid', @mid.deep_copy)
|
78
|
+
node.instance_variable_set('@after', @after.deep_copy) if @after
|
79
|
+
node
|
80
|
+
end
|
81
|
+
|
53
82
|
protected
|
54
83
|
|
55
84
|
# Evaluates the interpolation.
|
56
85
|
#
|
57
86
|
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
58
|
-
# @return [Sass::Script::String]
|
87
|
+
# @return [Sass::Script::Value::String]
|
88
|
+
# The SassScript string that is the value of the interpolation
|
59
89
|
def _perform(environment)
|
60
90
|
res = ""
|
61
91
|
res << @before.perform(environment).to_s if @before
|
62
92
|
res << " " if @before && @whitespace_before
|
63
93
|
val = @mid.perform(environment)
|
64
|
-
res << (val.is_a?(Sass::Script::String) ? val.value : val.to_s)
|
94
|
+
res << (val.is_a?(Sass::Script::Value::String) ? val.value : val.to_s)
|
65
95
|
res << " " if @after && @whitespace_after
|
66
96
|
res << @after.perform(environment).to_s if @after
|
67
|
-
opts(Sass::Script::String.new(res))
|
97
|
+
opts(Sass::Script::Value::String.new(res))
|
68
98
|
end
|
69
99
|
end
|
70
100
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Sass::Script::Tree
|
2
|
+
# A parse tree node representing a list literal. When resolved, this returns a
|
3
|
+
# {Sass::Tree::Value::List}.
|
4
|
+
class ListLiteral < Node
|
5
|
+
# The parse nodes for members of this list.
|
6
|
+
#
|
7
|
+
# @return [Array<Node>]
|
8
|
+
attr_reader :elements
|
9
|
+
|
10
|
+
# The operator separating the values of the list. Either `:comma` or
|
11
|
+
# `:space`.
|
12
|
+
#
|
13
|
+
# @return [Symbol]
|
14
|
+
attr_reader :separator
|
15
|
+
|
16
|
+
# Creates a new list literal.
|
17
|
+
#
|
18
|
+
# @param elements [Array<Node>] See \{#elements}
|
19
|
+
# @param separator [Symbol] See \{#separator}
|
20
|
+
def initialize(elements, separator)
|
21
|
+
@elements = elements
|
22
|
+
@separator = separator
|
23
|
+
end
|
24
|
+
|
25
|
+
# @see Node#children
|
26
|
+
def children; elements; end
|
27
|
+
|
28
|
+
# @see Value#to_sass
|
29
|
+
def to_sass(opts = {})
|
30
|
+
return "()" if elements.empty?
|
31
|
+
precedence = Sass::Script::Parser.precedence_of(separator)
|
32
|
+
members = elements.map do |v|
|
33
|
+
if v.is_a?(ListLiteral) && Sass::Script::Parser.precedence_of(v.separator) <= precedence ||
|
34
|
+
separator == :space && v.is_a?(UnaryOperation) &&
|
35
|
+
(v.operator == :minus || v.operator == :plus)
|
36
|
+
"(#{v.to_sass(opts)})"
|
37
|
+
else
|
38
|
+
v.to_sass(opts)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
return "(#{members.first},)" if separator == :comma && members.length == 1
|
43
|
+
|
44
|
+
members.join(sep_str(nil))
|
45
|
+
end
|
46
|
+
|
47
|
+
# @see Node#deep_copy
|
48
|
+
def deep_copy
|
49
|
+
node = dup
|
50
|
+
node.instance_variable_set('@elements', elements.map {|e| e.deep_copy})
|
51
|
+
node
|
52
|
+
end
|
53
|
+
|
54
|
+
def inspect
|
55
|
+
"(#{elements.map {|e| e.inspect}.join(separator == :space ? ' ' : ', ')})"
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def _perform(environment)
|
61
|
+
list = Sass::Script::Value::List.new(
|
62
|
+
elements.map {|e| e.perform(environment)},
|
63
|
+
separator)
|
64
|
+
list.source_range = source_range
|
65
|
+
list.options = options
|
66
|
+
list
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def sep_str(opts = options)
|
72
|
+
return ' ' if separator == :space
|
73
|
+
return ',' if opts && opts[:style] == :compressed
|
74
|
+
', '
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Sass::Script::Tree
|
2
|
+
# The parse tree node for a literal scalar value. This wraps an instance of
|
3
|
+
# {Sass::Script::Value::Base}.
|
4
|
+
#
|
5
|
+
# List literals should use {ListLiteral} instead.
|
6
|
+
class Literal < Node
|
7
|
+
# The wrapped value.
|
8
|
+
#
|
9
|
+
# @return [Sass::Script::Value::Base]
|
10
|
+
attr_reader :value
|
11
|
+
|
12
|
+
# Creates a new literal value.
|
13
|
+
#
|
14
|
+
# @param value [Sass::Script::Value::Base]
|
15
|
+
# @see #value
|
16
|
+
def initialize(value)
|
17
|
+
@value = value
|
18
|
+
end
|
19
|
+
|
20
|
+
# @see Node#children
|
21
|
+
def children; []; end
|
22
|
+
|
23
|
+
# @see Node#to_sass
|
24
|
+
def to_sass(opts = {}); value.to_sass(opts); end
|
25
|
+
|
26
|
+
# @see Node#deep_copy
|
27
|
+
def deep_copy; dup; end
|
28
|
+
|
29
|
+
# @see Node#options=
|
30
|
+
def options=(options)
|
31
|
+
value.options = options
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect
|
35
|
+
value.inspect
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def _perform(environment)
|
41
|
+
value.source_range = source_range
|
42
|
+
value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Sass::Script::Tree
|
2
|
+
# A class representing a map literal. When resolved, this returns a
|
3
|
+
# {Sass::Script::Node::Map}.
|
4
|
+
class MapLiteral < Node
|
5
|
+
# The key/value pairs that make up this map node. This isn't a Hash so that
|
6
|
+
# we can detect key collisions once all the keys have been performed.
|
7
|
+
#
|
8
|
+
# @return [Array<(Node, Node)>]
|
9
|
+
attr_reader :pairs
|
10
|
+
|
11
|
+
# Creates a new map literal.
|
12
|
+
#
|
13
|
+
# @param pairs [Array<(Node, Node)>] See \{#pairs}
|
14
|
+
def initialize(pairs)
|
15
|
+
@pairs = pairs
|
16
|
+
end
|
17
|
+
|
18
|
+
# @see Node#children
|
19
|
+
def children
|
20
|
+
@pairs.flatten
|
21
|
+
end
|
22
|
+
|
23
|
+
# @see Node#to_sass
|
24
|
+
def to_sass(opts = {})
|
25
|
+
return "()" if pairs.empty?
|
26
|
+
|
27
|
+
to_sass = lambda do |value|
|
28
|
+
if value.is_a?(ListLiteral) && value.separator == :comma
|
29
|
+
"(#{value.to_sass(opts)})"
|
30
|
+
else
|
31
|
+
value.to_sass(opts)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
"(" + pairs.map {|(k, v)| "#{to_sass[k]}: #{to_sass[v]}"}.join(', ') + ")"
|
36
|
+
end
|
37
|
+
alias_method :inspect, :to_sass
|
38
|
+
|
39
|
+
# @see Node#deep_copy
|
40
|
+
def deep_copy
|
41
|
+
node = dup
|
42
|
+
node.instance_variable_set('@pairs',
|
43
|
+
pairs.map {|(k, v)| [k.deep_copy, v.deep_copy]})
|
44
|
+
node
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
# @see Node#_perform
|
50
|
+
def _perform(environment)
|
51
|
+
keys = Set.new
|
52
|
+
map = Sass::Script::Value::Map.new(Sass::Util.to_hash(pairs.map do |(k, v)|
|
53
|
+
k, v = k.perform(environment), v.perform(environment)
|
54
|
+
if keys.include?(k)
|
55
|
+
raise Sass::SyntaxError.new("Duplicate key #{k.inspect} in map #{to_sass}.")
|
56
|
+
end
|
57
|
+
keys << k
|
58
|
+
[k, v]
|
59
|
+
end))
|
60
|
+
map.options = options
|
61
|
+
map
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Sass::Script
|
1
|
+
module Sass::Script::Tree
|
2
2
|
# The abstract superclass for SassScript parse tree nodes.
|
3
3
|
#
|
4
4
|
# Use \{#perform} to evaluate a parse tree.
|
@@ -13,6 +13,16 @@ module Sass::Script
|
|
13
13
|
# @return [Fixnum]
|
14
14
|
attr_accessor :line
|
15
15
|
|
16
|
+
# The source range in the document on which this node appeared.
|
17
|
+
#
|
18
|
+
# @return [Sass::Source::Range]
|
19
|
+
attr_accessor :source_range
|
20
|
+
|
21
|
+
# The file name of the document on which this node appeared.
|
22
|
+
#
|
23
|
+
# @return [String]
|
24
|
+
attr_accessor :filename
|
25
|
+
|
16
26
|
# Sets the options hash for this node,
|
17
27
|
# as well as for all child nodes.
|
18
28
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
@@ -22,7 +32,7 @@ module Sass::Script
|
|
22
32
|
@options = options
|
23
33
|
children.each do |c|
|
24
34
|
if c.is_a? Hash
|
25
|
-
c.values.each {|v| v.options = options
|
35
|
+
c.values.each {|v| v.options = options}
|
26
36
|
else
|
27
37
|
c.options = options
|
28
38
|
end
|
@@ -35,7 +45,7 @@ module Sass::Script
|
|
35
45
|
# instead, override \{#\_perform}.
|
36
46
|
#
|
37
47
|
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
38
|
-
# @return [
|
48
|
+
# @return [Sass::Script::Value] The SassScript object that is the value of the SassScript
|
39
49
|
def perform(environment)
|
40
50
|
_perform(environment)
|
41
51
|
rescue Sass::SyntaxError => e
|
@@ -57,35 +67,43 @@ module Sass::Script
|
|
57
67
|
Sass::Util.abstract(self)
|
58
68
|
end
|
59
69
|
|
70
|
+
# Returns a deep clone of this node.
|
71
|
+
# The child nodes are cloned, but options are not.
|
72
|
+
#
|
73
|
+
# @return [Node]
|
74
|
+
def deep_copy
|
75
|
+
Sass::Util.abstract(self)
|
76
|
+
end
|
77
|
+
|
60
78
|
protected
|
61
79
|
|
62
80
|
# Converts underscores to dashes if the :dasherize option is set.
|
63
81
|
def dasherize(s, opts)
|
64
82
|
if opts[:dasherize]
|
65
|
-
s.gsub(/_/,'-')
|
83
|
+
s.gsub(/_/, '-')
|
66
84
|
else
|
67
85
|
s
|
68
86
|
end
|
69
87
|
end
|
70
88
|
|
71
89
|
# Evaluates this node.
|
72
|
-
# Note that all {
|
90
|
+
# Note that all {Sass::Script::Value} objects created within this method
|
73
91
|
# should have their \{#options} attribute set, probably via \{#opts}.
|
74
92
|
#
|
75
93
|
# @param environment [Sass::Environment] The environment in which to evaluate the SassScript
|
76
|
-
# @return [
|
94
|
+
# @return [Sass::Script::Value] The SassScript object that is the value of the SassScript
|
77
95
|
# @see #perform
|
78
96
|
def _perform(environment)
|
79
97
|
Sass::Util.abstract(self)
|
80
98
|
end
|
81
99
|
|
82
|
-
# Sets the \{#options} field on the given
|
100
|
+
# Sets the \{#options} field on the given value and returns it.
|
83
101
|
#
|
84
|
-
# @param
|
85
|
-
# @return [
|
86
|
-
def opts(
|
87
|
-
|
88
|
-
|
102
|
+
# @param value [Sass::Script::Value]
|
103
|
+
# @return [Sass::Script::Value]
|
104
|
+
def opts(value)
|
105
|
+
value.options = options
|
106
|
+
value
|
89
107
|
end
|
90
108
|
end
|
91
109
|
end
|