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
@@ -1,11 +1,144 @@
|
|
1
1
|
# A visitor for converting a dynamic Sass tree into a static Sass tree.
|
2
2
|
class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
class << self
|
4
|
+
# @param root [Tree::Node] The root node of the tree to visit.
|
5
|
+
# @param environment [Sass::Environment] The lexical environment.
|
6
|
+
# @return [Tree::Node] The resulting tree of static nodes.
|
7
|
+
def visit(root, environment = nil)
|
8
|
+
new(environment).send(:visit, root)
|
9
|
+
end
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
# @comment
|
13
|
+
# rubocop:disable MethodLength
|
14
|
+
def perform_arguments(callable, args, splat)
|
15
|
+
desc = "#{callable.type.capitalize} #{callable.name}"
|
16
|
+
downcase_desc = "#{callable.type} #{callable.name}"
|
17
|
+
|
18
|
+
# All keywords are contained in splat.keywords for consistency,
|
19
|
+
# even if there were no splats passed in.
|
20
|
+
old_keywords_accessed = splat.keywords_accessed
|
21
|
+
keywords = splat.keywords
|
22
|
+
splat.keywords_accessed = old_keywords_accessed
|
23
|
+
|
24
|
+
begin
|
25
|
+
unless keywords.empty?
|
26
|
+
unknown_args = Sass::Util.array_minus(keywords.keys,
|
27
|
+
callable.args.map {|var| var.first.underscored_name})
|
28
|
+
if callable.splat && unknown_args.include?(callable.splat.underscored_name)
|
29
|
+
raise Sass::SyntaxError.new("Argument $#{callable.splat.name} of #{downcase_desc} " +
|
30
|
+
"cannot be used as a named argument.")
|
31
|
+
elsif unknown_args.any?
|
32
|
+
description = unknown_args.length > 1 ? 'the following arguments:' : 'an argument named'
|
33
|
+
raise Sass::SyntaxError.new("#{desc} doesn't have #{description} " +
|
34
|
+
"#{unknown_args.map {|name| "$#{name}"}.join ', '}.")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
rescue Sass::SyntaxError => keyword_exception
|
38
|
+
end
|
39
|
+
|
40
|
+
# If there's no splat, raise the keyword exception immediately. The actual
|
41
|
+
# raising happens in the ensure clause at the end of this function.
|
42
|
+
return if keyword_exception && !callable.splat
|
43
|
+
|
44
|
+
if args.size > callable.args.size && !callable.splat
|
45
|
+
takes = callable.args.size
|
46
|
+
passed = args.size
|
47
|
+
raise Sass::SyntaxError.new(
|
48
|
+
"#{desc} takes #{takes} argument#{'s' unless takes == 1} " +
|
49
|
+
"but #{passed} #{passed == 1 ? 'was' : 'were'} passed.")
|
50
|
+
end
|
51
|
+
|
52
|
+
splat_sep = :comma
|
53
|
+
if splat
|
54
|
+
args += splat.to_a
|
55
|
+
splat_sep = splat.separator
|
56
|
+
end
|
57
|
+
|
58
|
+
env = Sass::Environment.new(callable.environment)
|
59
|
+
callable.args.zip(args[0...callable.args.length]) do |(var, default), value|
|
60
|
+
if value && keywords.has_key?(var.name)
|
61
|
+
raise Sass::SyntaxError.new("#{desc} was passed argument $#{var.name} " +
|
62
|
+
"both by position and by name.")
|
63
|
+
end
|
64
|
+
|
65
|
+
value ||= keywords.delete(var.name)
|
66
|
+
value ||= default && default.perform(env)
|
67
|
+
raise Sass::SyntaxError.new("#{desc} is missing argument #{var.inspect}.") unless value
|
68
|
+
env.set_local_var(var.name, value)
|
69
|
+
end
|
70
|
+
|
71
|
+
if callable.splat
|
72
|
+
rest = args[callable.args.length..-1] || []
|
73
|
+
arg_list = Sass::Script::Value::ArgList.new(rest, keywords, splat_sep)
|
74
|
+
arg_list.options = env.options
|
75
|
+
env.set_local_var(callable.splat.name, arg_list)
|
76
|
+
end
|
77
|
+
|
78
|
+
yield env
|
79
|
+
rescue StandardError => e
|
80
|
+
ensure
|
81
|
+
# If there's a keyword exception, we don't want to throw it immediately,
|
82
|
+
# because the invalid keywords may be part of a glob argument that should be
|
83
|
+
# passed on to another function. So we only raise it if we reach the end of
|
84
|
+
# this function *and* the keywords attached to the argument list glob object
|
85
|
+
# haven't been accessed.
|
86
|
+
#
|
87
|
+
# The keyword exception takes precedence over any Sass errors, but not over
|
88
|
+
# non-Sass exceptions.
|
89
|
+
if keyword_exception &&
|
90
|
+
!(arg_list && arg_list.keywords_accessed) &&
|
91
|
+
(e.nil? || e.is_a?(Sass::SyntaxError))
|
92
|
+
raise keyword_exception
|
93
|
+
elsif e
|
94
|
+
raise e
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# @api private
|
99
|
+
# @return [Sass::Script::Value::ArgList]
|
100
|
+
def perform_splat(splat, performed_keywords, kwarg_splat, environment)
|
101
|
+
args, kwargs, separator = [], nil, :comma
|
102
|
+
|
103
|
+
if splat
|
104
|
+
splat = splat.perform(environment)
|
105
|
+
separator = splat.separator || separator
|
106
|
+
if splat.is_a?(Sass::Script::Value::ArgList)
|
107
|
+
args = splat.to_a
|
108
|
+
kwargs = splat.keywords
|
109
|
+
elsif splat.is_a?(Sass::Script::Value::Map)
|
110
|
+
kwargs = arg_hash(splat)
|
111
|
+
else
|
112
|
+
args = splat.to_a
|
113
|
+
end
|
114
|
+
end
|
115
|
+
kwargs ||= Sass::Util::NormalizedMap.new
|
116
|
+
kwargs.update(performed_keywords)
|
117
|
+
|
118
|
+
if kwarg_splat
|
119
|
+
kwarg_splat = kwarg_splat.perform(environment)
|
120
|
+
unless kwarg_splat.is_a?(Sass::Script::Value::Map)
|
121
|
+
raise Sass::SyntaxError.new("Variable keyword arguments must be a map " +
|
122
|
+
"(was #{kwarg_splat.inspect}).")
|
123
|
+
end
|
124
|
+
kwargs.update(arg_hash(kwarg_splat))
|
125
|
+
end
|
126
|
+
|
127
|
+
Sass::Script::Value::ArgList.new(args, kwargs, separator)
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def arg_hash(map)
|
133
|
+
Sass::Util.map_keys(map.to_h) do |key|
|
134
|
+
next key.value if key.is_a?(Sass::Script::Value::String)
|
135
|
+
raise Sass::SyntaxError.new("Variable keyword argument map must have string keys.\n" +
|
136
|
+
"#{key.inspect} is not a string in #{map.inspect}.")
|
137
|
+
end
|
138
|
+
end
|
8
139
|
end
|
140
|
+
# @comment
|
141
|
+
# rubocop:enable MethodLength
|
9
142
|
|
10
143
|
protected
|
11
144
|
|
@@ -13,9 +146,10 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
13
146
|
@environment = env
|
14
147
|
end
|
15
148
|
|
16
|
-
# If an exception is raised, this
|
149
|
+
# If an exception is raised, this adds proper metadata to the backtrace.
|
17
150
|
def visit(node)
|
18
|
-
super(node.dup)
|
151
|
+
return super(node.dup) unless @environment
|
152
|
+
@environment.stack.with_base(node.filename, node.line) {super(node.dup)}
|
19
153
|
rescue Sass::SyntaxError => e
|
20
154
|
e.modify_backtrace(:filename => node.filename, :line => node.line)
|
21
155
|
raise e
|
@@ -23,7 +157,7 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
23
157
|
|
24
158
|
# Keeps track of the current environment.
|
25
159
|
def visit_children(parent)
|
26
|
-
with_environment Sass::Environment.new(@environment) do
|
160
|
+
with_environment Sass::Environment.new(@environment, parent.options) do
|
27
161
|
parent.children = super.flatten
|
28
162
|
parent
|
29
163
|
end
|
@@ -43,7 +177,6 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
43
177
|
|
44
178
|
# Sets the options on the environment if this is the top-level root.
|
45
179
|
def visit_root(node)
|
46
|
-
@environment.options = node.options if @environment.options.nil? || @environment.options.empty?
|
47
180
|
yield
|
48
181
|
rescue Sass::SyntaxError => e
|
49
182
|
e.sass_template ||= node.template
|
@@ -53,23 +186,23 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
53
186
|
# Removes this node from the tree if it's a silent comment.
|
54
187
|
def visit_comment(node)
|
55
188
|
return [] if node.invisible?
|
56
|
-
|
57
|
-
|
58
|
-
$1+Sass::Script.parse($2, node.line, 0, node.options).perform(@environment).to_s
|
59
|
-
end
|
60
|
-
node.value = run_interp([Sass::Script::String.new(node.value)])
|
61
|
-
end
|
189
|
+
node.resolved_value = run_interp_no_strip(node.value)
|
190
|
+
node.resolved_value.gsub!(/\\([\\#])/, '\1')
|
62
191
|
node
|
63
192
|
end
|
64
193
|
|
65
194
|
# Prints the expression to STDERR.
|
66
195
|
def visit_debug(node)
|
67
196
|
res = node.expr.perform(@environment)
|
68
|
-
|
197
|
+
if res.is_a?(Sass::Script::Value::String)
|
198
|
+
res = res.value
|
199
|
+
else
|
200
|
+
res = res.to_sass
|
201
|
+
end
|
69
202
|
if node.filename
|
70
|
-
|
203
|
+
Sass::Util.sass_warn "#{node.filename}:#{node.line} DEBUG: #{res}"
|
71
204
|
else
|
72
|
-
|
205
|
+
Sass::Util.sass_warn "Line #{node.line} DEBUG: #{res}"
|
73
206
|
end
|
74
207
|
[]
|
75
208
|
end
|
@@ -79,8 +212,14 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
79
212
|
list = node.list.perform(@environment)
|
80
213
|
|
81
214
|
with_environment Sass::Environment.new(@environment) do
|
82
|
-
list.to_a.map do |
|
83
|
-
|
215
|
+
list.to_a.map do |value|
|
216
|
+
if node.vars.length == 1
|
217
|
+
@environment.set_local_var(node.vars.first, value)
|
218
|
+
else
|
219
|
+
node.vars.zip(value.to_a) do |(var, sub_value)|
|
220
|
+
@environment.set_local_var(var, sub_value || Sass::Script::Value::Null.new)
|
221
|
+
end
|
222
|
+
end
|
84
223
|
node.children.map {|c| visit(c)}
|
85
224
|
end.flatten
|
86
225
|
end
|
@@ -89,8 +228,9 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
89
228
|
# Runs SassScript interpolation in the selector,
|
90
229
|
# and then parses the result into a {Sass::Selector::CommaSequence}.
|
91
230
|
def visit_extend(node)
|
92
|
-
parser = Sass::SCSS::
|
93
|
-
|
231
|
+
parser = Sass::SCSS::StaticParser.new(run_interp(node.selector),
|
232
|
+
node.filename, node.options[:importer], node.line)
|
233
|
+
node.resolved_selector = parser.parse_selector
|
94
234
|
node
|
95
235
|
end
|
96
236
|
|
@@ -102,12 +242,14 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
102
242
|
to.assert_int!
|
103
243
|
|
104
244
|
to = to.coerce(from.numerator_units, from.denominator_units)
|
105
|
-
|
245
|
+
direction = from.to_i > to.to_i ? -1 : 1
|
246
|
+
range = Range.new(direction * from.to_i, direction * to.to_i, node.exclusive)
|
106
247
|
|
107
248
|
with_environment Sass::Environment.new(@environment) do
|
108
249
|
range.map do |i|
|
109
250
|
@environment.set_local_var(node.var,
|
110
|
-
Sass::Script::Number.new(i,
|
251
|
+
Sass::Script::Value::Number.new(direction * i,
|
252
|
+
from.numerator_units, from.denominator_units))
|
111
253
|
node.children.map {|c| visit(c)}
|
112
254
|
end.flatten
|
113
255
|
end
|
@@ -115,8 +257,10 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
115
257
|
|
116
258
|
# Loads the function into the environment.
|
117
259
|
def visit_function(node)
|
118
|
-
@environment
|
119
|
-
|
260
|
+
env = Sass::Environment.new(@environment, node.options)
|
261
|
+
@environment.set_local_function(node.name,
|
262
|
+
Sass::Callable.new(node.name, node.args, node.splat, env,
|
263
|
+
node.children, !:has_content, "function"))
|
120
264
|
[]
|
121
265
|
end
|
122
266
|
|
@@ -136,77 +280,84 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
|
|
136
280
|
# Returns a static DirectiveNode if this is importing a CSS file,
|
137
281
|
# or parses and includes the imported Sass file.
|
138
282
|
def visit_import(node)
|
139
|
-
if path = node.css_import?
|
140
|
-
|
283
|
+
if (path = node.css_import?)
|
284
|
+
resolved_node = Sass::Tree::CssImportNode.resolved("url(#{path})")
|
285
|
+
resolved_node.source_range = node.source_range
|
286
|
+
return resolved_node
|
287
|
+
end
|
288
|
+
file = node.imported_file
|
289
|
+
if @environment.stack.frames.any? {|f| f.is_import? && f.filename == file.options[:filename]}
|
290
|
+
handle_import_loop!(node)
|
141
291
|
end
|
142
292
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
293
|
+
begin
|
294
|
+
@environment.stack.with_import(node.filename, node.line) do
|
295
|
+
root = file.to_tree
|
296
|
+
Sass::Tree::Visitors::CheckNesting.visit(root)
|
297
|
+
node.children = root.children.map {|c| visit(c)}.flatten
|
298
|
+
node
|
299
|
+
end
|
300
|
+
rescue Sass::SyntaxError => e
|
301
|
+
e.modify_backtrace(:filename => node.imported_file.options[:filename])
|
302
|
+
e.add_backtrace(:filename => node.filename, :line => node.line)
|
303
|
+
raise e
|
304
|
+
end
|
153
305
|
end
|
154
306
|
|
155
307
|
# Loads a mixin into the environment.
|
156
308
|
def visit_mixindef(node)
|
157
|
-
@environment
|
158
|
-
|
309
|
+
env = Sass::Environment.new(@environment, node.options)
|
310
|
+
@environment.set_local_mixin(node.name,
|
311
|
+
Sass::Callable.new(node.name, node.args, node.splat, env,
|
312
|
+
node.children, node.has_content, "mixin"))
|
159
313
|
[]
|
160
314
|
end
|
161
315
|
|
162
316
|
# Runs a mixin.
|
163
317
|
def visit_mixin(node)
|
164
|
-
|
318
|
+
@environment.stack.with_mixin(node.filename, node.line, node.name) do
|
319
|
+
mixin = @environment.mixin(node.name)
|
320
|
+
raise Sass::SyntaxError.new("Undefined mixin '#{node.name}'.") unless mixin
|
165
321
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
raise Sass::SyntaxError.new("Undefined mixin '#{node.name}'.") unless mixin = @environment.mixin(node.name)
|
322
|
+
if node.children.any? && !mixin.has_content
|
323
|
+
raise Sass::SyntaxError.new(%Q{Mixin "#{node.name}" does not accept a content block.})
|
324
|
+
end
|
170
325
|
|
171
|
-
|
172
|
-
|
326
|
+
args = node.args.map {|a| a.perform(@environment)}
|
327
|
+
keywords = Sass::Util.map_vals(node.keywords) {|v| v.perform(@environment)}
|
328
|
+
splat = self.class.perform_splat(node.splat, keywords, node.kwarg_splat, @environment)
|
173
329
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
END
|
330
|
+
self.class.perform_arguments(mixin, args, splat) do |env|
|
331
|
+
env.caller = Sass::Environment.new(@environment)
|
332
|
+
env.content = [node.children, @environment] if node.has_children
|
178
333
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
raise Sass::SyntaxError.new("Mixin #{node.name} doesn't have an argument named $#{name}")
|
334
|
+
trace_node = Sass::Tree::TraceNode.from_node(node.name, node)
|
335
|
+
with_environment(env) {trace_node.children = mixin.tree.map {|c| visit(c)}.flatten}
|
336
|
+
trace_node
|
183
337
|
end
|
184
338
|
end
|
339
|
+
rescue Sass::SyntaxError => e
|
340
|
+
e.modify_backtrace(:mixin => node.name, :line => node.line)
|
341
|
+
e.add_backtrace(:line => node.line)
|
342
|
+
raise e
|
343
|
+
end
|
185
344
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
env
|
345
|
+
def visit_content(node)
|
346
|
+
content, content_env = @environment.content
|
347
|
+
return [] unless content
|
348
|
+
@environment.stack.with_mixin(node.filename, node.line, '@content') do
|
349
|
+
trace_node = Sass::Tree::TraceNode.from_node('@content', node)
|
350
|
+
content_env = Sass::Environment.new(content_env)
|
351
|
+
content_env.caller = Sass::Environment.new(@environment)
|
352
|
+
with_environment(content_env) do
|
353
|
+
trace_node.children = content.map {|c| visit(c.dup)}.flatten
|
354
|
+
end
|
355
|
+
trace_node
|
198
356
|
end
|
199
|
-
|
200
|
-
with_environment(environment) {node.children = mixin.tree.map {|c| visit(c)}.flatten}
|
201
|
-
node
|
202
357
|
rescue Sass::SyntaxError => e
|
203
|
-
|
204
|
-
|
205
|
-
e.add_backtrace(:line => node.line)
|
206
|
-
end
|
358
|
+
e.modify_backtrace(:mixin => '@content', :line => node.line)
|
359
|
+
e.add_backtrace(:line => node.line)
|
207
360
|
raise e
|
208
|
-
ensure
|
209
|
-
original_env.pop_frame if original_env
|
210
361
|
end
|
211
362
|
|
212
363
|
# Runs any SassScript that may be embedded in a property.
|
@@ -214,6 +365,7 @@ END
|
|
214
365
|
node.resolved_name = run_interp(node.name)
|
215
366
|
val = node.value.perform(@environment)
|
216
367
|
node.resolved_value = val.to_s
|
368
|
+
node.value_source_range = val.source_range if val.source_range
|
217
369
|
yield
|
218
370
|
end
|
219
371
|
|
@@ -225,35 +377,82 @@ END
|
|
225
377
|
# Runs SassScript interpolation in the selector,
|
226
378
|
# and then parses the result into a {Sass::Selector::CommaSequence}.
|
227
379
|
def visit_rule(node)
|
228
|
-
|
229
|
-
|
380
|
+
old_at_root_without_rule, @at_root_without_rule = @at_root_without_rule, false
|
381
|
+
parser = Sass::SCSS::StaticParser.new(run_interp(node.rule),
|
382
|
+
node.filename, node.options[:importer], node.line)
|
383
|
+
node.parsed_rules ||= parser.parse_selector
|
384
|
+
node.resolved_rules = node.parsed_rules.resolve_parent_refs(
|
385
|
+
@environment.selector, !old_at_root_without_rule)
|
386
|
+
node.stack_trace = @environment.stack.to_s if node.options[:trace_selectors]
|
387
|
+
with_environment Sass::Environment.new(@environment, node.options) do
|
388
|
+
@environment.selector = node.resolved_rules
|
389
|
+
node.children = node.children.map {|c| visit(c)}.flatten
|
390
|
+
end
|
391
|
+
node
|
392
|
+
ensure
|
393
|
+
@at_root_without_rule = old_at_root_without_rule
|
394
|
+
end
|
395
|
+
|
396
|
+
# Sets a variable that indicates that the first level of rule nodes
|
397
|
+
# shouldn't include the parent selector by default.
|
398
|
+
def visit_atroot(node)
|
399
|
+
if node.query
|
400
|
+
parser = Sass::SCSS::StaticParser.new(run_interp(node.query),
|
401
|
+
node.filename, node.options[:importer], node.line)
|
402
|
+
node.resolved_type, node.resolved_value = parser.parse_static_at_root_query
|
403
|
+
else
|
404
|
+
node.resolved_type, node.resolved_value = :without, ['rule']
|
405
|
+
end
|
406
|
+
|
407
|
+
old_at_root_without_rule = @at_root_without_rule
|
408
|
+
@at_root_without_rule = true if node.exclude?('rule')
|
230
409
|
yield
|
410
|
+
ensure
|
411
|
+
@at_root_without_rule = old_at_root_without_rule
|
231
412
|
end
|
232
413
|
|
233
414
|
# Loads the new variable value into the environment.
|
234
415
|
def visit_variable(node)
|
235
|
-
|
416
|
+
env = @environment
|
417
|
+
identifier = [node.name, node.filename, node.line]
|
418
|
+
if node.global
|
419
|
+
env = env.global_env
|
420
|
+
elsif env.parent && env.is_var_global?(node.name) &&
|
421
|
+
!env.global_env.global_warning_given.include?(identifier)
|
422
|
+
env.global_env.global_warning_given.add(identifier)
|
423
|
+
var_expr = "$#{node.name}: #{node.expr.to_sass(env.options)} !global"
|
424
|
+
var_expr << " !default" if node.guarded
|
425
|
+
location = "on line #{node.line}"
|
426
|
+
location << " of #{node.filename}" if node.filename
|
427
|
+
Sass::Util.sass_warn <<WARNING
|
428
|
+
DEPRECATION WARNING #{location}:
|
429
|
+
Assigning to global variable "$#{node.name}" by default is deprecated.
|
430
|
+
In future versions of Sass, this will create a new local variable.
|
431
|
+
If you want to assign to the global variable, use "#{var_expr}" instead.
|
432
|
+
Note that this will be incompatible with Sass 3.2.
|
433
|
+
WARNING
|
434
|
+
end
|
435
|
+
|
436
|
+
var = env.var(node.name)
|
437
|
+
return [] if node.guarded && var && !var.null?
|
236
438
|
val = node.expr.perform(@environment)
|
237
|
-
|
439
|
+
if node.expr.source_range
|
440
|
+
val.source_range = node.expr.source_range
|
441
|
+
else
|
442
|
+
val.source_range = node.source_range
|
443
|
+
end
|
444
|
+
env.set_var(node.name, val)
|
238
445
|
[]
|
239
446
|
end
|
240
447
|
|
241
448
|
# Prints the expression to STDERR with a stylesheet trace.
|
242
449
|
def visit_warn(node)
|
243
|
-
@environment.push_frame(:filename => node.filename, :line => node.line)
|
244
450
|
res = node.expr.perform(@environment)
|
245
|
-
res = res.value if res.is_a?(Sass::Script::String)
|
246
|
-
msg = "WARNING: #{res}\n"
|
247
|
-
@environment.stack.
|
248
|
-
msg << " #{i == 0 ? "on" : "from"} line #{entry[:line]}" <<
|
249
|
-
" of #{entry[:filename] || "an unknown file"}"
|
250
|
-
msg << ", in `#{entry[:mixin]}'" if entry[:mixin]
|
251
|
-
msg << "\n"
|
252
|
-
end
|
451
|
+
res = res.value if res.is_a?(Sass::Script::Value::String)
|
452
|
+
msg = "WARNING: #{res}\n "
|
453
|
+
msg << @environment.stack.to_s.gsub("\n", "\n ") << "\n"
|
253
454
|
Sass::Util.sass_warn msg
|
254
455
|
[]
|
255
|
-
ensure
|
256
|
-
@environment.pop_frame
|
257
456
|
end
|
258
457
|
|
259
458
|
# Runs the child nodes until the continuation expression becomes false.
|
@@ -266,35 +465,62 @@ END
|
|
266
465
|
end
|
267
466
|
|
268
467
|
def visit_directive(node)
|
269
|
-
|
270
|
-
|
468
|
+
node.resolved_value = run_interp(node.value)
|
469
|
+
with_environment Sass::Environment.new(@environment) do
|
470
|
+
node.children = node.children.map {|c| visit(c)}.flatten
|
471
|
+
node
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
def visit_media(node)
|
476
|
+
parser = Sass::SCSS::StaticParser.new(run_interp(node.query),
|
477
|
+
node.filename, node.options[:importer], node.line)
|
478
|
+
node.resolved_query ||= parser.parse_media_query_list
|
479
|
+
yield
|
480
|
+
end
|
481
|
+
|
482
|
+
def visit_supports(node)
|
483
|
+
node.condition = node.condition.deep_copy
|
484
|
+
node.condition.perform(@environment)
|
485
|
+
yield
|
486
|
+
end
|
487
|
+
|
488
|
+
def visit_cssimport(node)
|
489
|
+
node.resolved_uri = run_interp([node.uri])
|
490
|
+
if node.query
|
491
|
+
parser = Sass::SCSS::StaticParser.new(run_interp(node.query),
|
492
|
+
node.filename, node.options[:importer], node.line)
|
493
|
+
node.resolved_query ||= parser.parse_media_query_list
|
271
494
|
end
|
272
495
|
yield
|
273
|
-
node
|
274
496
|
end
|
275
497
|
|
276
498
|
private
|
277
499
|
|
278
|
-
def
|
500
|
+
def run_interp_no_strip(text)
|
279
501
|
text.map do |r|
|
280
502
|
next r if r.is_a?(String)
|
281
503
|
val = r.perform(@environment)
|
282
504
|
# Interpolated strings should never render with quotes
|
283
|
-
next val.value if val.is_a?(Sass::Script::String)
|
505
|
+
next val.value if val.is_a?(Sass::Script::Value::String)
|
284
506
|
val.to_s
|
285
|
-
end.join
|
507
|
+
end.join
|
508
|
+
end
|
509
|
+
|
510
|
+
def run_interp(text)
|
511
|
+
run_interp_no_strip(text).strip
|
286
512
|
end
|
287
513
|
|
288
|
-
def
|
289
|
-
msg = "An @
|
290
|
-
|
291
|
-
if
|
292
|
-
raise Sass::SyntaxError.new("#{msg} #{node.
|
514
|
+
def handle_import_loop!(node)
|
515
|
+
msg = "An @import loop has been found:"
|
516
|
+
files = @environment.stack.frames.select {|f| f.is_import?}.map {|f| f.filename}.compact
|
517
|
+
if node.filename == node.imported_file.options[:filename]
|
518
|
+
raise Sass::SyntaxError.new("#{msg} #{node.filename} imports itself")
|
293
519
|
end
|
294
520
|
|
295
|
-
|
296
|
-
msg << "\n" << Sass::Util.enum_cons(
|
297
|
-
" #{m1}
|
521
|
+
files << node.filename << node.imported_file.options[:filename]
|
522
|
+
msg << "\n" << Sass::Util.enum_cons(files, 2).map do |m1, m2|
|
523
|
+
" #{m1} imports #{m2}"
|
298
524
|
end.join("\n")
|
299
525
|
raise Sass::SyntaxError.new(msg)
|
300
526
|
end
|