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
data/lib/sass/exec.rb
CHANGED
@@ -17,6 +17,7 @@ module Sass
|
|
17
17
|
#
|
18
18
|
# @see #parse
|
19
19
|
def parse!
|
20
|
+
# rubocop:disable RescueException
|
20
21
|
begin
|
21
22
|
parse
|
22
23
|
rescue Exception => e
|
@@ -28,6 +29,7 @@ module Sass
|
|
28
29
|
exit 1
|
29
30
|
end
|
30
31
|
exit 0
|
32
|
+
# rubocop:enable RescueException
|
31
33
|
end
|
32
34
|
|
33
35
|
# Parses the command-line arguments and runs the executable.
|
@@ -58,7 +60,9 @@ module Sass
|
|
58
60
|
def get_line(exception)
|
59
61
|
# SyntaxErrors have weird line reporting
|
60
62
|
# when there's trailing whitespace
|
61
|
-
|
63
|
+
if exception.is_a?(::SyntaxError)
|
64
|
+
return (exception.message.scan(/:(\d+)/).first || ["??"]).first
|
65
|
+
end
|
62
66
|
(exception.backtrace[0].scan(/:(\d+)/).first || ["??"]).first
|
63
67
|
end
|
64
68
|
|
@@ -70,7 +74,8 @@ module Sass
|
|
70
74
|
#
|
71
75
|
# @param opts [OptionParser]
|
72
76
|
def set_opts(opts)
|
73
|
-
opts.on('-s', '--stdin', :NONE,
|
77
|
+
opts.on('-s', '--stdin', :NONE,
|
78
|
+
'Read input from standard input instead of an input file') do
|
74
79
|
@options[:input] = $stdin
|
75
80
|
end
|
76
81
|
|
@@ -95,6 +100,7 @@ module Sass
|
|
95
100
|
|
96
101
|
# Processes the options set by the command-line arguments.
|
97
102
|
# In particular, sets `@options[:input]` and `@options[:output]`
|
103
|
+
# (and `@options[:sourcemap]` if one has been specified)
|
98
104
|
# to appropriate IO streams.
|
99
105
|
#
|
100
106
|
# This is meant to be overridden by subclasses
|
@@ -108,12 +114,17 @@ module Sass
|
|
108
114
|
@options[:filename] = filename
|
109
115
|
open_file(filename) || $stdin
|
110
116
|
end
|
111
|
-
|
117
|
+
@options[:output_filename] = args.shift
|
118
|
+
output ||= @options[:output_filename] || $stdout
|
119
|
+
|
120
|
+
if @options[:sourcemap] && @options[:output_filename]
|
121
|
+
@options[:sourcemap_filename] = Util.sourcemap_name(@options[:output_filename])
|
122
|
+
end
|
112
123
|
|
113
124
|
@options[:input], @options[:output] = input, output
|
114
125
|
end
|
115
126
|
|
116
|
-
COLORS = {
|
127
|
+
COLORS = {:red => 31, :green => 32, :yellow => 33}
|
117
128
|
|
118
129
|
# Prints a status message about performing the given action,
|
119
130
|
# colored using the given color (via terminal escapes) if possible.
|
@@ -125,11 +136,12 @@ module Sass
|
|
125
136
|
def puts_action(name, color, arg)
|
126
137
|
return if @options[:for_engine][:quiet]
|
127
138
|
printf color(color, "%11s %s\n"), name, arg
|
139
|
+
STDOUT.flush
|
128
140
|
end
|
129
141
|
|
130
|
-
# Same as
|
142
|
+
# Same as `Kernel.puts`, but doesn't print anything if the `--quiet` option is set.
|
131
143
|
#
|
132
|
-
# @param args [Array] Passed on to
|
144
|
+
# @param args [Array] Passed on to `Kernel.puts`
|
133
145
|
def puts(*args)
|
134
146
|
return if @options[:for_engine][:quiet]
|
135
147
|
Kernel.puts(*args)
|
@@ -151,7 +163,15 @@ module Sass
|
|
151
163
|
# so we just filter for Windows terms (which don't set TERM)
|
152
164
|
# and not-real terminals, which aren't ttys.
|
153
165
|
return str if ENV["TERM"].nil? || ENV["TERM"].empty? || !STDOUT.tty?
|
154
|
-
|
166
|
+
"\e[#{COLORS[color]}m#{str}\e[0m"
|
167
|
+
end
|
168
|
+
|
169
|
+
def write_output(text, destination)
|
170
|
+
if destination.is_a?(String)
|
171
|
+
open_file(destination, 'w') {|file| file.write(text)}
|
172
|
+
else
|
173
|
+
destination.write(text)
|
174
|
+
end
|
155
175
|
end
|
156
176
|
|
157
177
|
private
|
@@ -159,7 +179,10 @@ module Sass
|
|
159
179
|
def open_file(filename, flag = 'r')
|
160
180
|
return if filename.nil?
|
161
181
|
flag = 'wb' if @options[:unix_newlines] && flag == 'w'
|
162
|
-
File.open(filename, flag)
|
182
|
+
file = File.open(filename, flag)
|
183
|
+
return file unless block_given?
|
184
|
+
yield file
|
185
|
+
file.close
|
163
186
|
end
|
164
187
|
|
165
188
|
def handle_load_error(err)
|
@@ -182,7 +205,7 @@ MESSAGE
|
|
182
205
|
def initialize(args)
|
183
206
|
super
|
184
207
|
@options[:for_engine] = {
|
185
|
-
:load_paths =>
|
208
|
+
:load_paths => default_sass_path
|
186
209
|
}
|
187
210
|
@default_syntax = :sass
|
188
211
|
end
|
@@ -192,6 +215,8 @@ MESSAGE
|
|
192
215
|
# Tells optparse how to parse the arguments.
|
193
216
|
#
|
194
217
|
# @param opts [OptionParser]
|
218
|
+
# @comment
|
219
|
+
# rubocop:disable MethodLength
|
195
220
|
def set_opts(opts)
|
196
221
|
super
|
197
222
|
|
@@ -229,15 +254,28 @@ END
|
|
229
254
|
'Only meaningful for --watch and --update.') do
|
230
255
|
@options[:stop_on_error] = true
|
231
256
|
end
|
257
|
+
opts.on('--poll', 'Check for file changes manually, rather than relying on the OS.',
|
258
|
+
'Only meaningful for --watch.') do
|
259
|
+
@options[:poll] = true
|
260
|
+
end
|
261
|
+
opts.on('-f', '--force', 'Recompile all Sass files, even if the CSS file is newer.',
|
262
|
+
'Only meaningful for --update.') do
|
263
|
+
@options[:force] = true
|
264
|
+
end
|
232
265
|
opts.on('-c', '--check', "Just check syntax, don't evaluate.") do
|
233
266
|
require 'stringio'
|
234
267
|
@options[:check_syntax] = true
|
235
268
|
@options[:output] = StringIO.new
|
236
269
|
end
|
237
|
-
|
238
|
-
|
270
|
+
style_desc = 'Output style. Can be nested (default), compact, compressed, or expanded.'
|
271
|
+
opts.on('-t', '--style NAME', style_desc) do |name|
|
239
272
|
@options[:for_engine][:style] = name.to_sym
|
240
273
|
end
|
274
|
+
opts.on('--precision NUMBER_OF_DIGITS', Integer,
|
275
|
+
"How many digits of precision to use when outputting decimal numbers." +
|
276
|
+
"Defaults to #{::Sass::Script::Value::Number.precision}.") do |precision|
|
277
|
+
::Sass::Script::Value::Number.precision = precision
|
278
|
+
end
|
241
279
|
opts.on('-q', '--quiet', 'Silence warnings and status messages during compilation.') do
|
242
280
|
@options[:for_engine][:quiet] = true
|
243
281
|
end
|
@@ -245,7 +283,7 @@ END
|
|
245
283
|
@options[:compass] = true
|
246
284
|
end
|
247
285
|
opts.on('-g', '--debug-info',
|
248
|
-
'Emit
|
286
|
+
'Emit output that can be used by the FireSass Firebug plugin.') do
|
249
287
|
@options[:for_engine][:debug_info] = true
|
250
288
|
end
|
251
289
|
opts.on('-l', '--line-numbers', '--line-comments',
|
@@ -262,19 +300,33 @@ END
|
|
262
300
|
opts.on('-r', '--require LIB', 'Require a Ruby library before running Sass.') do |lib|
|
263
301
|
require lib
|
264
302
|
end
|
265
|
-
opts.on('--cache-location PATH',
|
303
|
+
opts.on('--cache-location PATH',
|
304
|
+
'The path to put cached Sass files. Defaults to .sass-cache.') do |loc|
|
266
305
|
@options[:for_engine][:cache_location] = loc
|
267
306
|
end
|
268
307
|
opts.on('-C', '--no-cache', "Don't cache to sassc files.") do
|
269
308
|
@options[:for_engine][:cache] = false
|
270
309
|
end
|
310
|
+
opts.on('--sourcemap', 'Create sourcemap files next to the generated CSS files.') do
|
311
|
+
@options[:sourcemap] = true
|
312
|
+
end
|
271
313
|
|
272
|
-
|
273
|
-
|
314
|
+
encoding_desc = if ::Sass::Util.ruby1_8?
|
315
|
+
'Does not work in ruby 1.8.'
|
316
|
+
else
|
317
|
+
'Specify the default encoding for Sass files.'
|
318
|
+
end
|
319
|
+
opts.on('-E', '--default-encoding ENCODING', encoding_desc) do |encoding|
|
320
|
+
if ::Sass::Util.ruby1_8?
|
321
|
+
$stderr.puts "Specifying the encoding is not supported in ruby 1.8."
|
322
|
+
exit 1
|
323
|
+
else
|
274
324
|
Encoding.default_external = encoding
|
275
325
|
end
|
276
326
|
end
|
277
327
|
end
|
328
|
+
# @comment
|
329
|
+
# rubocop:enable MethodLength
|
278
330
|
|
279
331
|
# Processes the options set by the command-line arguments,
|
280
332
|
# and runs the Sass compiler appropriately.
|
@@ -294,6 +346,8 @@ END
|
|
294
346
|
return watch_or_update if @options[:watch] || @options[:update]
|
295
347
|
super
|
296
348
|
@options[:for_engine][:filename] = @options[:filename]
|
349
|
+
@options[:for_engine][:css_filename] = @options[:output] if @options[:output].is_a?(String)
|
350
|
+
@options[:for_engine][:sourcemap_filename] = @options[:sourcemap_filename]
|
297
351
|
|
298
352
|
begin
|
299
353
|
input = @options[:input]
|
@@ -308,16 +362,32 @@ END
|
|
308
362
|
# We don't need to do any special handling of @options[:check_syntax] here,
|
309
363
|
# because the Sass syntax checking happens alongside evaluation
|
310
364
|
# and evaluation doesn't actually evaluate any code anyway.
|
311
|
-
::Sass::Engine.new(input.read
|
365
|
+
::Sass::Engine.new(input.read, @options[:for_engine])
|
312
366
|
end
|
313
367
|
|
314
|
-
input.close
|
368
|
+
input.close if input.is_a?(File)
|
369
|
+
|
370
|
+
if @options[:sourcemap]
|
371
|
+
unless @options[:sourcemap_filename]
|
372
|
+
raise "Can't generate a sourcemap for an input without a path."
|
373
|
+
end
|
315
374
|
|
316
|
-
|
317
|
-
|
375
|
+
relative_sourcemap_path = ::Sass::Util.pathname(@options[:sourcemap_filename]).
|
376
|
+
relative_path_from(::Sass::Util.pathname(@options[:output_filename]).dirname)
|
377
|
+
rendered, mapping = engine.render_with_sourcemap(relative_sourcemap_path.to_s)
|
378
|
+
write_output(rendered, output)
|
379
|
+
write_output(mapping.to_json(
|
380
|
+
:css_path => @options[:output_filename],
|
381
|
+
:sourcemap_path => @options[:sourcemap_filename]) + "\n",
|
382
|
+
@options[:sourcemap_filename])
|
383
|
+
else
|
384
|
+
write_output(engine.render, output)
|
385
|
+
end
|
318
386
|
rescue ::Sass::SyntaxError => e
|
319
387
|
raise e if @options[:trace]
|
320
388
|
raise e.sass_backtrace_str("standard input")
|
389
|
+
ensure
|
390
|
+
output.close if output.is_a? File
|
321
391
|
end
|
322
392
|
end
|
323
393
|
|
@@ -345,10 +415,19 @@ END
|
|
345
415
|
::Sass::Repl.new(@options).run
|
346
416
|
end
|
347
417
|
|
418
|
+
# @comment
|
419
|
+
# rubocop:disable MethodLength
|
348
420
|
def watch_or_update
|
349
421
|
require 'sass/plugin'
|
350
422
|
::Sass::Plugin.options.merge! @options[:for_engine]
|
351
423
|
::Sass::Plugin.options[:unix_newlines] = @options[:unix_newlines]
|
424
|
+
::Sass::Plugin.options[:poll] = @options[:poll]
|
425
|
+
::Sass::Plugin.options[:sourcemap] = @options[:sourcemap]
|
426
|
+
|
427
|
+
if @options[:force]
|
428
|
+
raise "The --force flag may only be used with --update." unless @options[:update]
|
429
|
+
::Sass::Plugin.options[:always_update] = true
|
430
|
+
end
|
352
431
|
|
353
432
|
raise <<MSG if @args.empty?
|
354
433
|
What files should I watch? Did you mean something like:
|
@@ -372,25 +451,38 @@ MSG
|
|
372
451
|
|
373
452
|
dirs, files = @args.map {|name| split_colon_path(name)}.
|
374
453
|
partition {|i, _| File.directory? i}
|
375
|
-
files.map!
|
454
|
+
files.map! do |from, to|
|
455
|
+
to ||= from.gsub(/\.[^.]*?$/, '.css')
|
456
|
+
sourcemap = Util.sourcemap_name(to) if @options[:sourcemap]
|
457
|
+
[from, to, sourcemap]
|
458
|
+
end
|
376
459
|
dirs.map! {|from, to| [from, to || from]}
|
377
460
|
::Sass::Plugin.options[:template_location] = dirs
|
378
461
|
|
379
|
-
::Sass::Plugin.
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
puts_action :create, :green, css
|
462
|
+
::Sass::Plugin.on_updated_stylesheet do |_, css, sourcemap|
|
463
|
+
[css, sourcemap].each do |file|
|
464
|
+
next unless file
|
465
|
+
puts_action :write, :green, file
|
384
466
|
end
|
385
467
|
end
|
386
468
|
|
387
469
|
had_error = false
|
388
470
|
::Sass::Plugin.on_creating_directory {|dirname| puts_action :directory, :green, dirname}
|
389
471
|
::Sass::Plugin.on_deleting_css {|filename| puts_action :delete, :yellow, filename}
|
472
|
+
::Sass::Plugin.on_deleting_sourcemap {|filename| puts_action :delete, :yellow, filename}
|
390
473
|
::Sass::Plugin.on_compilation_error do |error, _, _|
|
474
|
+
if error.is_a?(SystemCallError) && !@options[:stop_on_error]
|
475
|
+
had_error = true
|
476
|
+
puts_action :error, :red, error.message
|
477
|
+
STDOUT.flush
|
478
|
+
next
|
479
|
+
end
|
480
|
+
|
391
481
|
raise error unless error.is_a?(::Sass::SyntaxError) && !@options[:stop_on_error]
|
392
482
|
had_error = true
|
393
|
-
puts_action :error, :red,
|
483
|
+
puts_action :error, :red,
|
484
|
+
"#{error.sass_filename} (Line #{error.sass_line}: #{error.message})"
|
485
|
+
STDOUT.flush
|
394
486
|
end
|
395
487
|
|
396
488
|
if @options[:update]
|
@@ -401,12 +493,23 @@ MSG
|
|
401
493
|
|
402
494
|
puts ">>> Sass is watching for changes. Press Ctrl-C to stop."
|
403
495
|
|
404
|
-
::Sass::Plugin.on_template_modified
|
405
|
-
|
406
|
-
|
496
|
+
::Sass::Plugin.on_template_modified do |template|
|
497
|
+
puts ">>> Change detected to: #{template}"
|
498
|
+
STDOUT.flush
|
499
|
+
end
|
500
|
+
::Sass::Plugin.on_template_created do |template|
|
501
|
+
puts ">>> New template detected: #{template}"
|
502
|
+
STDOUT.flush
|
503
|
+
end
|
504
|
+
::Sass::Plugin.on_template_deleted do |template|
|
505
|
+
puts ">>> Deleted template detected: #{template}"
|
506
|
+
STDOUT.flush
|
507
|
+
end
|
407
508
|
|
408
509
|
::Sass::Plugin.watch(files)
|
409
510
|
end
|
511
|
+
# @comment
|
512
|
+
# rubocop:enable MethodLength
|
410
513
|
|
411
514
|
def colon_path?(path)
|
412
515
|
!split_colon_path(path)[1].nil?
|
@@ -429,7 +532,17 @@ MSG
|
|
429
532
|
def probably_dest_dir?(path)
|
430
533
|
return false unless path
|
431
534
|
return false if colon_path?(path)
|
432
|
-
|
535
|
+
::Sass::Util.glob(File.join(path, "*.s[ca]ss")).empty?
|
536
|
+
end
|
537
|
+
|
538
|
+
def default_sass_path
|
539
|
+
if ENV['SASS_PATH']
|
540
|
+
# The select here prevents errors when the environment's
|
541
|
+
# load paths specified do not exist.
|
542
|
+
ENV['SASS_PATH'].split(File::PATH_SEPARATOR).select {|d| File.directory?(d)}
|
543
|
+
else
|
544
|
+
[::Sass::Importers::DeprecatedPath.new(".")]
|
545
|
+
end
|
433
546
|
end
|
434
547
|
end
|
435
548
|
|
@@ -454,6 +567,8 @@ MSG
|
|
454
567
|
# Tells optparse how to parse the arguments.
|
455
568
|
#
|
456
569
|
# @param opts [OptionParser]
|
570
|
+
# @comment
|
571
|
+
# rubocop:disable MethodLength
|
457
572
|
def set_opts(opts)
|
458
573
|
opts.banner = <<END
|
459
574
|
Usage: sass-convert [options] [INPUT] [OUTPUT]
|
@@ -467,14 +582,14 @@ Options:
|
|
467
582
|
END
|
468
583
|
|
469
584
|
opts.on('-F', '--from FORMAT',
|
470
|
-
'The format to convert from. Can be css, scss, sass
|
585
|
+
'The format to convert from. Can be css, scss, sass.',
|
471
586
|
'By default, this is inferred from the input filename.',
|
472
587
|
'If there is none, defaults to css.') do |name|
|
473
588
|
@options[:from] = name.downcase.to_sym
|
474
|
-
|
589
|
+
raise "sass-convert no longer supports LessCSS." if @options[:from] == :less
|
590
|
+
unless [:css, :scss, :sass].include?(@options[:from])
|
475
591
|
raise "Unknown format for sass-convert --from: #{name}"
|
476
592
|
end
|
477
|
-
try_less_note if @options[:from] == :less
|
478
593
|
end
|
479
594
|
|
480
595
|
opts.on('-T', '--to FORMAT',
|
@@ -502,6 +617,17 @@ END
|
|
502
617
|
@options[:for_tree][:dasherize] = true
|
503
618
|
end
|
504
619
|
|
620
|
+
opts.on('--indent NUM',
|
621
|
+
'How many spaces to use for each level of indentation. Defaults to 2.',
|
622
|
+
'"t" means use hard tabs.') do |indent|
|
623
|
+
|
624
|
+
if indent == 't'
|
625
|
+
@options[:for_tree][:indent] = "\t"
|
626
|
+
else
|
627
|
+
@options[:for_tree][:indent] = " " * indent.to_i
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
505
631
|
opts.on('--old', 'Output the old-style ":prop val" property syntax.',
|
506
632
|
'Only meaningful when generating Sass.') do
|
507
633
|
@options[:for_tree][:old] = true
|
@@ -512,13 +638,16 @@ END
|
|
512
638
|
end
|
513
639
|
|
514
640
|
unless ::Sass::Util.ruby1_8?
|
515
|
-
opts.on('-E encoding',
|
641
|
+
opts.on('-E encoding',
|
642
|
+
'Specify the default encoding for Sass and CSS files.') do |encoding|
|
516
643
|
Encoding.default_external = encoding
|
517
644
|
end
|
518
645
|
end
|
519
646
|
|
520
647
|
super
|
521
648
|
end
|
649
|
+
# @comment
|
650
|
+
# rubocop:enable MethodLength
|
522
651
|
|
523
652
|
# Processes the options set by the command-line arguments,
|
524
653
|
# and runs the CSS compiler appropriately.
|
@@ -532,7 +661,9 @@ END
|
|
532
661
|
|
533
662
|
super
|
534
663
|
input = @options[:input]
|
535
|
-
|
664
|
+
if File.directory?(input)
|
665
|
+
raise "Error: '#{input.path}' is a directory (did you mean to use --recursive?)"
|
666
|
+
end
|
536
667
|
output = @options[:output]
|
537
668
|
output = input if @options[:in_place]
|
538
669
|
process_file(input, output)
|
@@ -541,27 +672,29 @@ END
|
|
541
672
|
private
|
542
673
|
|
543
674
|
def process_directory
|
544
|
-
unless input = @options[:input] = @args.shift
|
675
|
+
unless (input = @options[:input] = @args.shift)
|
545
676
|
raise "Error: directory required when using --recursive."
|
546
677
|
end
|
547
678
|
|
548
679
|
output = @options[:output] = @args.shift
|
549
680
|
raise "Error: --from required when using --recursive." unless @options[:from]
|
550
681
|
raise "Error: --to required when using --recursive." unless @options[:to]
|
551
|
-
|
552
|
-
|
682
|
+
unless File.directory?(@options[:input])
|
683
|
+
raise "Error: '#{@options[:input]}' is not a directory"
|
684
|
+
end
|
685
|
+
if @options[:output] && File.exists?(@options[:output]) &&
|
686
|
+
!File.directory?(@options[:output])
|
553
687
|
raise "Error: '#{@options[:output]}' is not a directory"
|
554
688
|
end
|
555
689
|
@options[:output] ||= @options[:input]
|
556
690
|
|
557
|
-
from = @options[:from]
|
558
691
|
if @options[:to] == @options[:from] && !@options[:in_place]
|
559
692
|
fmt = @options[:from]
|
560
693
|
raise "Error: converting from #{fmt} to #{fmt} without --in-place"
|
561
694
|
end
|
562
695
|
|
563
696
|
ext = @options[:from]
|
564
|
-
|
697
|
+
::Sass::Util.glob("#{@options[:input]}/**/*.#{ext}") do |f|
|
565
698
|
output =
|
566
699
|
if @options[:in_place]
|
567
700
|
f
|
@@ -585,7 +718,6 @@ END
|
|
585
718
|
end
|
586
719
|
|
587
720
|
input = open_file(f)
|
588
|
-
output = @options[:in_place] ? input : open_file(output, "w")
|
589
721
|
process_file(input, output)
|
590
722
|
end
|
591
723
|
end
|
@@ -596,7 +728,7 @@ END
|
|
596
728
|
case input.path
|
597
729
|
when /\.scss$/; :scss
|
598
730
|
when /\.sass$/; :sass
|
599
|
-
when /\.less$/;
|
731
|
+
when /\.less$/; raise "sass-convert no longer supports LessCSS."
|
600
732
|
when /\.css$/; :css
|
601
733
|
end
|
602
734
|
elsif @options[:in_place]
|
@@ -620,11 +752,6 @@ END
|
|
620
752
|
if @options[:from] == :css
|
621
753
|
require 'sass/css'
|
622
754
|
::Sass::CSS.new(input.read, @options[:for_tree]).render(@options[:to])
|
623
|
-
elsif @options[:from] == :less
|
624
|
-
require 'sass/less'
|
625
|
-
try_less_note
|
626
|
-
input = input.read if input.is_a?(IO) && !input.is_a?(File) # Less is dumb
|
627
|
-
Less::Engine.new(input).to_tree.to_sass_tree.send("to_#{@options[:to]}", @options[:for_tree])
|
628
755
|
else
|
629
756
|
if input.is_a?(File)
|
630
757
|
::Sass::Engine.for_file(input.path, @options[:for_engine])
|
@@ -634,8 +761,8 @@ END
|
|
634
761
|
end
|
635
762
|
end
|
636
763
|
|
637
|
-
output =
|
638
|
-
|
764
|
+
output = input.path if @options[:in_place]
|
765
|
+
write_output(out, output)
|
639
766
|
rescue ::Sass::SyntaxError => e
|
640
767
|
raise e if @options[:trace]
|
641
768
|
file = " of #{e.sass_filename}" if e.sass_filename
|
@@ -643,17 +770,6 @@ END
|
|
643
770
|
rescue LoadError => err
|
644
771
|
handle_load_error(err)
|
645
772
|
end
|
646
|
-
|
647
|
-
@@less_note_printed = false
|
648
|
-
def try_less_note
|
649
|
-
return if @@less_note_printed
|
650
|
-
@@less_note_printed = true
|
651
|
-
warn <<NOTE
|
652
|
-
* NOTE: Sass and Less are different languages, and they work differently.
|
653
|
-
* I'll do my best to translate, but some features -- especially mixins --
|
654
|
-
* should be checked by hand.
|
655
|
-
NOTE
|
656
|
-
end
|
657
773
|
end
|
658
774
|
end
|
659
775
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'set'
|
2
|
+
module Sass
|
3
|
+
# Provides `Sass.has_feature?` which allows for simple feature detection
|
4
|
+
# by providing a feature name.
|
5
|
+
module Features
|
6
|
+
# This is the set of features that can be detected.
|
7
|
+
KNOWN_FEATURES = Set[*%w{
|
8
|
+
}]
|
9
|
+
|
10
|
+
# Check if a feature exists by name. This is used to implement
|
11
|
+
# the Sass function `feature-exists($feature)`
|
12
|
+
#
|
13
|
+
# @param feature_name [String] The case sensitive name of the feature to
|
14
|
+
# check if it exists in this version of Sass.
|
15
|
+
# @return [Boolean] whether the feature of that name exists.
|
16
|
+
def has_feature?(feature_name)
|
17
|
+
KNOWN_FEATURES.include?(feature_name)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Add a feature to Sass. Plugins can use this to easily expose their
|
21
|
+
# availability to end users. Plugins must prefix their feature
|
22
|
+
# names with a dash to distinguish them from official features.
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# Sass.add_feature("-import-globbing")
|
26
|
+
# Sass.add_feature("-math-cos")
|
27
|
+
#
|
28
|
+
#
|
29
|
+
# @param feature_name [String] The case sensitive name of the feature to
|
30
|
+
# to add to Sass. Must begin with a dash.
|
31
|
+
def add_feature(feature_name)
|
32
|
+
unless feature_name[0] == ?-
|
33
|
+
raise ArgumentError.new("Plugin feature names must begin with a dash")
|
34
|
+
end
|
35
|
+
KNOWN_FEATURES << feature_name
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
extend Features
|
40
|
+
end
|
data/lib/sass/importers/base.rb
CHANGED
@@ -15,13 +15,9 @@ module Sass
|
|
15
15
|
# They should also implement the \{#find\_relative} method.
|
16
16
|
#
|
17
17
|
# Importers should be serializable via `Marshal.dump`.
|
18
|
-
# In addition to the standard `_dump` and `_load` methods,
|
19
|
-
# importers can define `_before_dump`, `_after_dump`, `_around_dump`,
|
20
|
-
# and `_after_load` methods as per {Sass::Util#dump} and {Sass::Util#load}.
|
21
18
|
#
|
22
19
|
# @abstract
|
23
20
|
class Base
|
24
|
-
|
25
21
|
# Find a Sass file relative to another file.
|
26
22
|
# Importers without a notion of "relative paths"
|
27
23
|
# should just return nil here.
|
@@ -72,7 +68,8 @@ module Sass
|
|
72
68
|
# If no such files exist, it should return nil.
|
73
69
|
#
|
74
70
|
# The {Sass::Engine} to be returned should be passed `options`,
|
75
|
-
# with a few modifications. `:
|
71
|
+
# with a few modifications. `:syntax` should be set appropriately,
|
72
|
+
# `:filename` should be set to `uri`,
|
76
73
|
# and `:importer` should be set to this importer.
|
77
74
|
#
|
78
75
|
# @param uri [String] The URI to import.
|
@@ -121,6 +118,29 @@ module Sass
|
|
121
118
|
Sass::Util.abstract(self)
|
122
119
|
end
|
123
120
|
|
121
|
+
# Get the publicly-visible URL for an imported file. This URL is used by
|
122
|
+
# source maps to link to the source stylesheet. This may return `nil` to
|
123
|
+
# indicate that no public URL is available; however, this will cause
|
124
|
+
# sourcemap generation to fail if any CSS is generated from files imported
|
125
|
+
# from this importer.
|
126
|
+
#
|
127
|
+
# @param uri [String] A URI known to be valid for this importer.
|
128
|
+
# @param sourcemap_directory [String, NilClass] The absolute path to a
|
129
|
+
# directory on disk where the sourcemap will be saved. If uri refers to
|
130
|
+
# a file on disk that's accessible relative to sourcemap_directory, this
|
131
|
+
# may return a relative URL. This may be `nil` if the sourcemap's
|
132
|
+
# eventual location is unknown.
|
133
|
+
# @return [String?] The publicly-visible URL for this file, or `nil`
|
134
|
+
# indicating that no publicly-visible URL exists.
|
135
|
+
def public_url(uri, sourcemap_directory = nil)
|
136
|
+
return if @public_url_warning_issued
|
137
|
+
@public_url_warning_issued = true
|
138
|
+
Sass::Util.sass_warn <<WARNING
|
139
|
+
WARNING: #{self.class.name} should define the #public_url method.
|
140
|
+
WARNING
|
141
|
+
nil
|
142
|
+
end
|
143
|
+
|
124
144
|
# A string representation of the importer.
|
125
145
|
# Should be overridden by subclasses.
|
126
146
|
#
|
@@ -131,8 +151,27 @@ module Sass
|
|
131
151
|
def to_s
|
132
152
|
Sass::Util.abstract(self)
|
133
153
|
end
|
154
|
+
|
155
|
+
# If the importer is based on files on the local filesystem
|
156
|
+
# this method should return folders which should be watched
|
157
|
+
# for changes.
|
158
|
+
#
|
159
|
+
# @return [Array<String>] List of absolute paths of directories to watch
|
160
|
+
def directories_to_watch
|
161
|
+
[]
|
162
|
+
end
|
163
|
+
|
164
|
+
# If this importer is based on files on the local filesystem This method
|
165
|
+
# should return true if the file, when changed, should trigger a
|
166
|
+
# recompile.
|
167
|
+
#
|
168
|
+
# It is acceptable for non-sass files to be watched and trigger a recompile.
|
169
|
+
#
|
170
|
+
# @param filename [String] The absolute filename for a file that has changed.
|
171
|
+
# @return [Boolean] When the file changed should cause a recompile.
|
172
|
+
def watched_file?(filename)
|
173
|
+
false
|
174
|
+
end
|
134
175
|
end
|
135
176
|
end
|
136
177
|
end
|
137
|
-
|
138
|
-
|