oreorenasass 3.4.4 → 3.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +50 -70
- data/Rakefile +5 -26
- data/VERSION +1 -1
- data/VERSION_NAME +1 -1
- data/bin/sass +1 -1
- data/bin/scss +1 -1
- data/lib/sass.rb +12 -19
- data/lib/sass/cache_stores/base.rb +2 -2
- data/lib/sass/cache_stores/chain.rb +1 -2
- data/lib/sass/cache_stores/filesystem.rb +5 -1
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +0 -1
- data/lib/sass/css.rb +13 -11
- data/lib/sass/engine.rb +173 -424
- data/lib/sass/environment.rb +58 -148
- data/lib/sass/error.rb +14 -11
- data/lib/sass/exec.rb +703 -5
- data/lib/sass/importers/base.rb +6 -49
- data/lib/sass/importers/filesystem.rb +19 -44
- data/lib/sass/logger.rb +4 -1
- data/lib/sass/logger/base.rb +4 -2
- data/lib/sass/logger/log_level.rb +7 -3
- data/lib/sass/media.rb +23 -20
- data/lib/sass/plugin.rb +7 -7
- data/lib/sass/plugin/compiler.rb +145 -304
- data/lib/sass/plugin/configuration.rb +23 -18
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +3 -3
- data/lib/sass/repl.rb +3 -3
- data/lib/sass/script.rb +8 -35
- data/lib/sass/script/{value/arg_list.rb → arg_list.rb} +25 -9
- data/lib/sass/script/bool.rb +18 -0
- data/lib/sass/script/color.rb +606 -0
- data/lib/sass/script/css_lexer.rb +4 -8
- data/lib/sass/script/css_parser.rb +2 -5
- data/lib/sass/script/funcall.rb +245 -0
- data/lib/sass/script/functions.rb +408 -1491
- data/lib/sass/script/interpolation.rb +79 -0
- data/lib/sass/script/lexer.rb +68 -172
- data/lib/sass/script/list.rb +85 -0
- data/lib/sass/script/literal.rb +221 -0
- data/lib/sass/script/{tree/node.rb → node.rb} +12 -22
- data/lib/sass/script/{value/null.rb → null.rb} +7 -14
- data/lib/sass/script/{value/number.rb → number.rb} +75 -152
- data/lib/sass/script/{tree/operation.rb → operation.rb} +24 -17
- data/lib/sass/script/parser.rb +110 -245
- data/lib/sass/script/string.rb +51 -0
- data/lib/sass/script/{tree/string_interpolation.rb → string_interpolation.rb} +4 -5
- data/lib/sass/script/{tree/unary_operation.rb → unary_operation.rb} +6 -6
- data/lib/sass/script/variable.rb +58 -0
- data/lib/sass/scss/css_parser.rb +3 -9
- data/lib/sass/scss/parser.rb +421 -450
- data/lib/sass/scss/rx.rb +11 -19
- data/lib/sass/scss/static_parser.rb +7 -321
- data/lib/sass/selector.rb +194 -68
- data/lib/sass/selector/abstract_sequence.rb +14 -29
- data/lib/sass/selector/comma_sequence.rb +25 -108
- data/lib/sass/selector/sequence.rb +66 -159
- data/lib/sass/selector/simple.rb +25 -23
- data/lib/sass/selector/simple_sequence.rb +63 -173
- data/lib/sass/shared.rb +1 -1
- data/lib/sass/supports.rb +15 -13
- data/lib/sass/tree/charset_node.rb +1 -1
- data/lib/sass/tree/comment_node.rb +3 -3
- data/lib/sass/tree/css_import_node.rb +11 -11
- data/lib/sass/tree/debug_node.rb +2 -2
- data/lib/sass/tree/directive_node.rb +4 -21
- data/lib/sass/tree/each_node.rb +8 -8
- data/lib/sass/tree/extend_node.rb +7 -14
- data/lib/sass/tree/for_node.rb +4 -4
- data/lib/sass/tree/function_node.rb +4 -9
- data/lib/sass/tree/if_node.rb +1 -1
- data/lib/sass/tree/import_node.rb +5 -4
- data/lib/sass/tree/media_node.rb +14 -4
- data/lib/sass/tree/mixin_def_node.rb +4 -4
- data/lib/sass/tree/mixin_node.rb +8 -21
- data/lib/sass/tree/node.rb +12 -54
- data/lib/sass/tree/prop_node.rb +20 -39
- data/lib/sass/tree/return_node.rb +2 -3
- data/lib/sass/tree/root_node.rb +3 -19
- data/lib/sass/tree/rule_node.rb +22 -35
- data/lib/sass/tree/supports_node.rb +13 -0
- data/lib/sass/tree/trace_node.rb +1 -2
- data/lib/sass/tree/variable_node.rb +3 -9
- data/lib/sass/tree/visitors/base.rb +8 -5
- data/lib/sass/tree/visitors/check_nesting.rb +19 -49
- data/lib/sass/tree/visitors/convert.rb +56 -74
- data/lib/sass/tree/visitors/cssize.rb +74 -202
- data/lib/sass/tree/visitors/deep_copy.rb +5 -10
- data/lib/sass/tree/visitors/extend.rb +7 -7
- data/lib/sass/tree/visitors/perform.rb +185 -278
- data/lib/sass/tree/visitors/set_options.rb +6 -20
- data/lib/sass/tree/visitors/to_css.rb +81 -234
- data/lib/sass/tree/warn_node.rb +2 -2
- data/lib/sass/tree/while_node.rb +2 -2
- data/lib/sass/util.rb +152 -522
- data/lib/sass/util/multibyte_string_scanner.rb +0 -2
- data/lib/sass/util/subset_map.rb +3 -4
- data/lib/sass/util/test.rb +1 -0
- data/lib/sass/version.rb +22 -20
- data/test/Gemfile +3 -0
- data/test/Gemfile.lock +10 -0
- data/test/sass/cache_test.rb +20 -62
- data/test/sass/callbacks_test.rb +1 -1
- data/test/sass/conversion_test.rb +2 -296
- data/test/sass/css2sass_test.rb +4 -23
- data/test/sass/engine_test.rb +354 -411
- data/test/sass/exec_test.rb +2 -2
- data/test/sass/extend_test.rb +145 -324
- data/test/sass/functions_test.rb +86 -873
- data/test/sass/importer_test.rb +21 -241
- data/test/sass/logger_test.rb +1 -1
- data/test/sass/more_results/more_import.css +1 -1
- data/test/sass/plugin_test.rb +26 -16
- data/test/sass/results/compact.css +1 -1
- data/test/sass/results/complex.css +4 -4
- data/test/sass/results/expanded.css +1 -1
- data/test/sass/results/import.css +1 -1
- data/test/sass/results/import_charset_ibm866.css +2 -2
- data/test/sass/results/mixins.css +17 -17
- data/test/sass/results/nested.css +1 -1
- data/test/sass/results/parent_ref.css +2 -2
- data/test/sass/results/script.css +3 -3
- data/test/sass/results/scss_import.css +1 -1
- data/test/sass/script_conversion_test.rb +7 -36
- data/test/sass/script_test.rb +53 -485
- data/test/sass/scss/css_test.rb +28 -143
- data/test/sass/scss/rx_test.rb +4 -4
- data/test/sass/scss/scss_test.rb +325 -2119
- data/test/sass/templates/scss_import.scss +1 -2
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +1 -1
- data/test/sass/util/subset_map_test.rb +2 -2
- data/test/sass/util_test.rb +1 -86
- data/test/test_helper.rb +8 -37
- metadata +19 -66
- data/lib/sass/exec/base.rb +0 -187
- data/lib/sass/exec/sass_convert.rb +0 -264
- data/lib/sass/exec/sass_scss.rb +0 -424
- data/lib/sass/features.rb +0 -47
- data/lib/sass/script/tree.rb +0 -16
- data/lib/sass/script/tree/funcall.rb +0 -306
- data/lib/sass/script/tree/interpolation.rb +0 -118
- data/lib/sass/script/tree/list_literal.rb +0 -77
- data/lib/sass/script/tree/literal.rb +0 -45
- data/lib/sass/script/tree/map_literal.rb +0 -64
- data/lib/sass/script/tree/selector.rb +0 -26
- data/lib/sass/script/tree/variable.rb +0 -57
- data/lib/sass/script/value.rb +0 -11
- data/lib/sass/script/value/base.rb +0 -240
- data/lib/sass/script/value/bool.rb +0 -35
- data/lib/sass/script/value/color.rb +0 -680
- data/lib/sass/script/value/helpers.rb +0 -262
- data/lib/sass/script/value/list.rb +0 -113
- data/lib/sass/script/value/map.rb +0 -70
- data/lib/sass/script/value/string.rb +0 -97
- data/lib/sass/selector/pseudo.rb +0 -256
- data/lib/sass/source/map.rb +0 -210
- data/lib/sass/source/position.rb +0 -39
- data/lib/sass/source/range.rb +0 -41
- data/lib/sass/stack.rb +0 -120
- data/lib/sass/tree/at_root_node.rb +0 -83
- data/lib/sass/tree/error_node.rb +0 -18
- data/lib/sass/tree/keyframe_rule_node.rb +0 -15
- data/lib/sass/util/cross_platform_random.rb +0 -19
- data/lib/sass/util/normalized_map.rb +0 -130
- data/lib/sass/util/ordered_hash.rb +0 -192
- data/test/sass/compiler_test.rb +0 -232
- data/test/sass/encoding_test.rb +0 -219
- data/test/sass/source_map_test.rb +0 -977
- data/test/sass/superselector_test.rb +0 -191
- data/test/sass/util/normalized_map_test.rb +0 -51
- data/test/sass/value_helpers_test.rb +0 -179
data/lib/sass/engine.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
require 'set'
|
2
2
|
require 'digest/sha1'
|
3
3
|
require 'sass/cache_stores'
|
4
|
-
require 'sass/source/position'
|
5
|
-
require 'sass/source/range'
|
6
|
-
require 'sass/source/map'
|
7
4
|
require 'sass/tree/node'
|
8
5
|
require 'sass/tree/root_node'
|
9
6
|
require 'sass/tree/rule_node'
|
@@ -29,9 +26,6 @@ require 'sass/tree/debug_node'
|
|
29
26
|
require 'sass/tree/warn_node'
|
30
27
|
require 'sass/tree/import_node'
|
31
28
|
require 'sass/tree/charset_node'
|
32
|
-
require 'sass/tree/at_root_node'
|
33
|
-
require 'sass/tree/keyframe_rule_node'
|
34
|
-
require 'sass/tree/error_node'
|
35
29
|
require 'sass/tree/visitors/base'
|
36
30
|
require 'sass/tree/visitors/perform'
|
37
31
|
require 'sass/tree/visitors/cssize'
|
@@ -45,7 +39,6 @@ require 'sass/selector'
|
|
45
39
|
require 'sass/environment'
|
46
40
|
require 'sass/script'
|
47
41
|
require 'sass/scss'
|
48
|
-
require 'sass/stack'
|
49
42
|
require 'sass/error'
|
50
43
|
require 'sass/importers'
|
51
44
|
require 'sass/shared'
|
@@ -53,17 +46,18 @@ require 'sass/media'
|
|
53
46
|
require 'sass/supports'
|
54
47
|
|
55
48
|
module Sass
|
49
|
+
|
56
50
|
# A Sass mixin or function.
|
57
51
|
#
|
58
52
|
# `name`: `String`
|
59
53
|
# : The name of the mixin/function.
|
60
54
|
#
|
61
|
-
# `args`: `Array<(Script::
|
55
|
+
# `args`: `Array<(Script::Node, Script::Node)>`
|
62
56
|
# : The arguments for the mixin/function.
|
63
57
|
# Each element is a tuple containing the variable node of the argument
|
64
58
|
# and the parse tree for the default value of the argument.
|
65
59
|
#
|
66
|
-
# `splat`: `Script::
|
60
|
+
# `splat`: `Script::Node?`
|
67
61
|
# : The variable node of the splat argument for this callable, or null.
|
68
62
|
#
|
69
63
|
# `environment`: {Sass::Environment}
|
@@ -89,6 +83,8 @@ module Sass
|
|
89
83
|
# output = sass_engine.render
|
90
84
|
# puts output
|
91
85
|
class Engine
|
86
|
+
include Sass::Util
|
87
|
+
|
92
88
|
# A line of Sass code.
|
93
89
|
#
|
94
90
|
# `text`: `String`
|
@@ -198,8 +194,6 @@ module Sass
|
|
198
194
|
when :alternate; options[:property_syntax] = :new
|
199
195
|
when :normal; options[:property_syntax] = :old
|
200
196
|
end
|
201
|
-
options[:sourcemap] = :auto if options[:sourcemap] == true
|
202
|
-
options[:sourcemap] = :none if options[:sourcemap] == false
|
203
197
|
|
204
198
|
options
|
205
199
|
end
|
@@ -252,7 +246,7 @@ module Sass
|
|
252
246
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
253
247
|
# @see {Sass::Engine.for_file}
|
254
248
|
# @see {Sass::Plugin}
|
255
|
-
def initialize(template, options
|
249
|
+
def initialize(template, options={})
|
256
250
|
@options = self.class.normalize_options(options)
|
257
251
|
@template = template
|
258
252
|
end
|
@@ -265,27 +259,9 @@ module Sass
|
|
265
259
|
# cannot be converted to UTF-8
|
266
260
|
# @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
|
267
261
|
def render
|
268
|
-
return
|
269
|
-
Sass::Util.silence_sass_warnings {
|
262
|
+
return _render unless @options[:quiet]
|
263
|
+
Sass::Util.silence_sass_warnings {_render}
|
270
264
|
end
|
271
|
-
|
272
|
-
# Render the template to CSS and return the source map.
|
273
|
-
#
|
274
|
-
# @param sourcemap_uri [String] The sourcemap URI to use in the
|
275
|
-
# `@sourceMappingURL` comment. If this is relative, it should be relative
|
276
|
-
# to the location of the CSS file.
|
277
|
-
# @return [(String, Sass::Source::Map)] The rendered CSS and the associated
|
278
|
-
# source map
|
279
|
-
# @raise [Sass::SyntaxError] if there's an error in the document, or if the
|
280
|
-
# public URL for this document couldn't be determined.
|
281
|
-
# @raise [Encoding::UndefinedConversionError] if the source encoding
|
282
|
-
# cannot be converted to UTF-8
|
283
|
-
# @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
|
284
|
-
def render_with_sourcemap(sourcemap_uri)
|
285
|
-
return _render_with_sourcemap(sourcemap_uri) unless @options[:quiet]
|
286
|
-
Sass::Util.silence_sass_warnings {_render_with_sourcemap(sourcemap_uri)}
|
287
|
-
end
|
288
|
-
|
289
265
|
alias_method :to_css, :render
|
290
266
|
|
291
267
|
# Parses the document into its parse tree. Memoized.
|
@@ -293,11 +269,9 @@ module Sass
|
|
293
269
|
# @return [Sass::Tree::Node] The root of the parse tree.
|
294
270
|
# @raise [Sass::SyntaxError] if there's an error in the document
|
295
271
|
def to_tree
|
296
|
-
@tree ||=
|
297
|
-
|
298
|
-
|
299
|
-
_to_tree
|
300
|
-
end
|
272
|
+
@tree ||= @options[:quiet] ?
|
273
|
+
Sass::Util.silence_sass_warnings {_to_tree} :
|
274
|
+
_to_tree
|
301
275
|
end
|
302
276
|
|
303
277
|
# Returns the original encoding of the document,
|
@@ -309,7 +283,7 @@ module Sass
|
|
309
283
|
# @raise [ArgumentError] if the document uses an unknown encoding with `@charset`
|
310
284
|
def source_encoding
|
311
285
|
check_encoding!
|
312
|
-
@
|
286
|
+
@original_encoding
|
313
287
|
end
|
314
288
|
|
315
289
|
# Gets a set of all the documents
|
@@ -326,8 +300,7 @@ module Sass
|
|
326
300
|
#
|
327
301
|
# @private
|
328
302
|
def _dependencies(seen, engines)
|
329
|
-
key = [@options[:filename], @options[:importer]]
|
330
|
-
return if seen.include?(key)
|
303
|
+
return if seen.include?(key = [@options[:filename], @options[:importer]])
|
331
304
|
seen << key
|
332
305
|
engines << self
|
333
306
|
to_tree.grep(Tree::ImportNode) do |n|
|
@@ -338,59 +311,35 @@ module Sass
|
|
338
311
|
|
339
312
|
private
|
340
313
|
|
341
|
-
def
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
No filename is available so there's nothing for the source map to link to.
|
350
|
-
ERR
|
351
|
-
elsif importer.nil?
|
352
|
-
raise Sass::SyntaxError.new(<<ERR)
|
353
|
-
Error generating source map: couldn't determine public URL for "#{filename}".
|
354
|
-
Without a public URL, there's nothing for the source map to link to.
|
355
|
-
An importer was not set for this file.
|
356
|
-
ERR
|
357
|
-
elsif Sass::Util.silence_warnings do
|
358
|
-
sourcemap_dir = nil if @options[:sourcemap] == :file
|
359
|
-
importer.public_url(filename, sourcemap_dir).nil?
|
360
|
-
end
|
361
|
-
raise Sass::SyntaxError.new(<<ERR)
|
362
|
-
Error generating source map: couldn't determine public URL for "#{filename}".
|
363
|
-
Without a public URL, there's nothing for the source map to link to.
|
364
|
-
Custom importers should define the #public_url method.
|
365
|
-
ERR
|
314
|
+
def _render
|
315
|
+
rendered = _to_tree.render
|
316
|
+
return rendered if ruby1_8?
|
317
|
+
begin
|
318
|
+
# Try to convert the result to the original encoding,
|
319
|
+
# but if that doesn't work fall back on UTF-8
|
320
|
+
rendered = rendered.encode(source_encoding)
|
321
|
+
rescue EncodingError
|
366
322
|
end
|
367
|
-
|
368
|
-
|
369
|
-
compressed = @options[:style] == :compressed
|
370
|
-
rendered << "\n" if rendered[-1] != ?\n
|
371
|
-
rendered << "\n" unless compressed
|
372
|
-
rendered << "/*# sourceMappingURL="
|
373
|
-
rendered << Sass::Util.escape_uri(sourcemap_uri)
|
374
|
-
rendered << " */\n"
|
375
|
-
return rendered, sourcemap
|
323
|
+
rendered.gsub(Regexp.new('\A@charset "(.*?)"'.encode(source_encoding)),
|
324
|
+
"@charset \"#{source_encoding.name}\"".encode(source_encoding))
|
376
325
|
end
|
377
326
|
|
378
327
|
def _to_tree
|
379
|
-
check_encoding!
|
380
|
-
|
381
328
|
if (@options[:cache] || @options[:read_cache]) &&
|
382
329
|
@options[:filename] && @options[:importer]
|
383
330
|
key = sassc_key
|
384
331
|
sha = Digest::SHA1.hexdigest(@template)
|
385
332
|
|
386
|
-
if
|
333
|
+
if root = @options[:cache_store].retrieve(key, sha)
|
387
334
|
root.options = @options
|
388
335
|
return root
|
389
336
|
end
|
390
337
|
end
|
391
338
|
|
339
|
+
check_encoding!
|
340
|
+
|
392
341
|
if @options[:syntax] == :scss
|
393
|
-
root = Sass::SCSS::Parser.new(@template, @options[:filename]
|
342
|
+
root = Sass::SCSS::Parser.new(@template, @options[:filename]).parse
|
394
343
|
else
|
395
344
|
root = Tree::RootNode.new(@template)
|
396
345
|
append_children(root, tree(tabulate(@template)).first, true)
|
@@ -420,7 +369,9 @@ ERR
|
|
420
369
|
def check_encoding!
|
421
370
|
return if @checked_encoding
|
422
371
|
@checked_encoding = true
|
423
|
-
@template, @
|
372
|
+
@template, @original_encoding = check_sass_encoding(@template) do |msg, line|
|
373
|
+
raise Sass::SyntaxError.new(msg, :line => line)
|
374
|
+
end
|
424
375
|
end
|
425
376
|
|
426
377
|
def tabulate(string)
|
@@ -428,7 +379,7 @@ ERR
|
|
428
379
|
comment_tab_str = nil
|
429
380
|
first = true
|
430
381
|
lines = []
|
431
|
-
string.scan(/^[^\n]*?$/).each_with_index do |line, index|
|
382
|
+
string.gsub(/\r\n|\r|\n/, "\n").scan(/^[^\n]*?$/).each_with_index do |line, index|
|
432
383
|
index += (@options[:line] || 1)
|
433
384
|
if line.strip.empty?
|
434
385
|
lines.last.text << "\n" if lines.last && lines.last.comment?
|
@@ -473,15 +424,12 @@ END
|
|
473
424
|
raise SyntaxError.new(message, :line => index)
|
474
425
|
end
|
475
426
|
|
476
|
-
lines << Line.new(line.strip, line_tabs, index,
|
427
|
+
lines << Line.new(line.strip, line_tabs, index, tab_str.size, @options[:filename], [])
|
477
428
|
end
|
478
429
|
lines
|
479
430
|
end
|
480
431
|
|
481
|
-
# @comment
|
482
|
-
# rubocop:disable ParameterLists
|
483
432
|
def try_comment(line, last, tab_str, comment_tab_str, index)
|
484
|
-
# rubocop:enable ParameterLists
|
485
433
|
return unless last && last.comment?
|
486
434
|
# Nested comment stuff must be at least one whitespace char deeper
|
487
435
|
# than the normal indentation
|
@@ -506,8 +454,7 @@ MSG
|
|
506
454
|
nodes = []
|
507
455
|
while (line = arr[i]) && line.tabs >= base
|
508
456
|
if line.tabs > base
|
509
|
-
raise SyntaxError.new(
|
510
|
-
"The line was indented #{line.tabs - base} levels deeper than the previous line.",
|
457
|
+
raise SyntaxError.new("The line was indented #{line.tabs - base} levels deeper than the previous line.",
|
511
458
|
:line => line.index) if line.tabs > base + 1
|
512
459
|
|
513
460
|
nodes.last.children, i = tree(arr, i)
|
@@ -521,7 +468,6 @@ MSG
|
|
521
468
|
|
522
469
|
def build_tree(parent, line, root = false)
|
523
470
|
@line = line.index
|
524
|
-
@offset = line.offset
|
525
471
|
node_or_nodes = parse_line(parent, line, root)
|
526
472
|
|
527
473
|
Array(node_or_nodes).each do |node|
|
@@ -564,8 +510,6 @@ MSG
|
|
564
510
|
if continued_comment &&
|
565
511
|
child.line == continued_comment.line +
|
566
512
|
continued_comment.lines + 1
|
567
|
-
continued_comment.value.last.sub!(/ \*\/\Z/, '')
|
568
|
-
child.value.first.gsub!(/\A\/\*/, ' *')
|
569
513
|
continued_comment.value += ["\n"] + child.value
|
570
514
|
next
|
571
515
|
end
|
@@ -607,25 +551,12 @@ WARNING
|
|
607
551
|
# which begin with ::,
|
608
552
|
# as well as pseudo-classes
|
609
553
|
# if we're using the new property syntax
|
610
|
-
Tree::RuleNode.new(parse_interp(line.text)
|
554
|
+
Tree::RuleNode.new(parse_interp(line.text))
|
611
555
|
else
|
612
|
-
name_start_offset = line.offset + 1 # +1 for the leading ':'
|
613
556
|
name, value = line.text.scan(PROPERTY_OLD)[0]
|
614
557
|
raise SyntaxError.new("Invalid property: \"#{line.text}\".",
|
615
558
|
:line => @line) if name.nil? || value.nil?
|
616
|
-
|
617
|
-
value_start_offset = name_end_offset = name_start_offset + name.length
|
618
|
-
unless value.empty?
|
619
|
-
# +1 and -1 both compensate for the leading ':', which is part of line.text
|
620
|
-
value_start_offset = name_start_offset + line.text.index(value, name.length + 1) - 1
|
621
|
-
end
|
622
|
-
|
623
|
-
property = parse_property(name, parse_interp(name), value, :old, line, value_start_offset)
|
624
|
-
property.name_source_range = Sass::Source::Range.new(
|
625
|
-
Sass::Source::Position.new(@line, to_parser_offset(name_start_offset)),
|
626
|
-
Sass::Source::Position.new(@line, to_parser_offset(name_end_offset)),
|
627
|
-
@options[:filename], @options[:importer])
|
628
|
-
property
|
559
|
+
parse_property(name, parse_interp(name), value, :old, line)
|
629
560
|
end
|
630
561
|
when ?$
|
631
562
|
parse_variable(line)
|
@@ -634,12 +565,12 @@ WARNING
|
|
634
565
|
when DIRECTIVE_CHAR
|
635
566
|
parse_directive(parent, line, root)
|
636
567
|
when ESCAPE_CHAR
|
637
|
-
Tree::RuleNode.new(parse_interp(line.text[1..-1])
|
568
|
+
Tree::RuleNode.new(parse_interp(line.text[1..-1]))
|
638
569
|
when MIXIN_DEFINITION_CHAR
|
639
570
|
parse_mixin_definition(line)
|
640
571
|
when MIXIN_INCLUDE_CHAR
|
641
572
|
if line.text[1].nil? || line.text[1] == ?\s
|
642
|
-
Tree::RuleNode.new(parse_interp(line.text)
|
573
|
+
Tree::RuleNode.new(parse_interp(line.text))
|
643
574
|
else
|
644
575
|
parse_mixin_include(line, root)
|
645
576
|
end
|
@@ -651,70 +582,32 @@ WARNING
|
|
651
582
|
def parse_property_or_rule(line)
|
652
583
|
scanner = Sass::Util::MultibyteStringScanner.new(line.text)
|
653
584
|
hack_char = scanner.scan(/[:\*\.]|\#(?!\{)/)
|
654
|
-
|
655
|
-
offset += hack_char.length if hack_char
|
656
|
-
parser = Sass::SCSS::Parser.new(scanner,
|
657
|
-
@options[:filename], @options[:importer],
|
658
|
-
@line, to_parser_offset(offset))
|
659
|
-
|
660
|
-
unless (res = parser.parse_interp_ident)
|
661
|
-
parsed = parse_interp(line.text, line.offset)
|
662
|
-
return Tree::RuleNode.new(parsed, full_line_range(line))
|
663
|
-
end
|
585
|
+
parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
|
664
586
|
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
@options[:filename], @options[:importer])
|
669
|
-
offset = parser.offset - 1
|
587
|
+
unless res = parser.parse_interp_ident
|
588
|
+
return Tree::RuleNode.new(parse_interp(line.text))
|
589
|
+
end
|
670
590
|
res.unshift(hack_char) if hack_char
|
671
|
-
|
672
|
-
# Handle comments after a property name but before the colon.
|
673
|
-
if (comment = scanner.scan(Sass::SCSS::RX::COMMENT))
|
591
|
+
if comment = scanner.scan(Sass::SCSS::RX::COMMENT)
|
674
592
|
res << comment
|
675
|
-
offset += comment.length
|
676
593
|
end
|
677
594
|
|
678
595
|
name = line.text[0...scanner.pos]
|
679
|
-
if
|
680
|
-
|
681
|
-
property = parse_property(name, res, scanner.rest, :new, line, offset)
|
682
|
-
property.name_source_range = ident_range
|
683
|
-
property
|
596
|
+
if scanner.scan(/\s*:(?:\s|$)/)
|
597
|
+
parse_property(name, res, scanner.rest, :new, line)
|
684
598
|
else
|
685
599
|
res.pop if comment
|
686
|
-
|
687
|
-
if (trailing = (scanner.scan(/\s*#{Sass::SCSS::RX::COMMENT}/) ||
|
688
|
-
scanner.scan(/\s*#{Sass::SCSS::RX::SINGLE_LINE_COMMENT}/)))
|
689
|
-
trailing.strip!
|
690
|
-
end
|
691
|
-
interp_parsed = parse_interp(scanner.rest)
|
692
|
-
selector_range = Sass::Source::Range.new(
|
693
|
-
ident_range.start_pos,
|
694
|
-
Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
|
695
|
-
@options[:filename], @options[:importer])
|
696
|
-
rule = Tree::RuleNode.new(res + interp_parsed, selector_range)
|
697
|
-
rule << Tree::CommentNode.new([trailing], :silent) if trailing
|
698
|
-
rule
|
600
|
+
Tree::RuleNode.new(res + parse_interp(scanner.rest))
|
699
601
|
end
|
700
602
|
end
|
701
603
|
|
702
|
-
|
703
|
-
# rubocop:disable ParameterLists
|
704
|
-
def parse_property(name, parsed_name, value, prop, line, start_offset)
|
705
|
-
# rubocop:enable ParameterLists
|
604
|
+
def parse_property(name, parsed_name, value, prop, line)
|
706
605
|
if value.strip.empty?
|
707
|
-
expr = Sass::Script::
|
708
|
-
end_offset = start_offset
|
606
|
+
expr = Sass::Script::String.new("")
|
709
607
|
else
|
710
|
-
expr = parse_script(value, :offset =>
|
711
|
-
end_offset = expr.source_range.end_pos.offset - 1
|
608
|
+
expr = parse_script(value, :offset => line.offset + line.text.index(value))
|
712
609
|
end
|
713
610
|
node = Tree::PropNode.new(parse_interp(name), expr, prop)
|
714
|
-
node.value_source_range = Sass::Source::Range.new(
|
715
|
-
Sass::Source::Position.new(line.index, to_parser_offset(start_offset)),
|
716
|
-
Sass::Source::Position.new(line.index, to_parser_offset(end_offset)),
|
717
|
-
@options[:filename], @options[:importer])
|
718
611
|
if value.strip.empty? && line.children.empty?
|
719
612
|
raise SyntaxError.new(
|
720
613
|
"Invalid property: \"#{node.declaration}\" (no value)." +
|
@@ -725,24 +618,15 @@ WARNING
|
|
725
618
|
end
|
726
619
|
|
727
620
|
def parse_variable(line)
|
728
|
-
name, value,
|
621
|
+
name, value, default = line.text.scan(Script::MATCH)[0]
|
729
622
|
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath variable declarations.",
|
730
623
|
:line => @line + 1) unless line.children.empty?
|
731
624
|
raise SyntaxError.new("Invalid variable: \"#{line.text}\".",
|
732
625
|
:line => @line) unless name && value
|
733
|
-
flags = flags ? flags.split(/\s+/) : []
|
734
|
-
if (invalid_flag = flags.find {|f| f != '!default' && f != '!global'})
|
735
|
-
raise SyntaxError.new("Invalid flag \"#{invalid_flag}\".", :line => @line)
|
736
|
-
end
|
737
626
|
|
738
|
-
|
739
|
-
# otherwise we end up with the offset equal to the value index inside the name:
|
740
|
-
# $red_color: red;
|
741
|
-
var_lhs_length = 1 + name.length # 1 stands for '$'
|
742
|
-
index = line.text.index(value, line.offset + var_lhs_length) || 0
|
743
|
-
expr = parse_script(value, :offset => to_parser_offset(line.offset + index))
|
627
|
+
expr = parse_script(value, :offset => line.offset + line.text.index(value))
|
744
628
|
|
745
|
-
Tree::VariableNode.new(name, expr,
|
629
|
+
Tree::VariableNode.new(name, expr, default)
|
746
630
|
end
|
747
631
|
|
748
632
|
def parse_comment(line)
|
@@ -752,171 +636,108 @@ WARNING
|
|
752
636
|
if silent
|
753
637
|
value = [line.text]
|
754
638
|
else
|
755
|
-
value = self.class.parse_interp(
|
756
|
-
line.text, line.index, to_parser_offset(line.offset), :filename => @filename)
|
639
|
+
value = self.class.parse_interp(line.text, line.index, line.offset, :filename => @filename)
|
757
640
|
end
|
758
|
-
value =
|
641
|
+
value = with_extracted_values(value) do |str|
|
759
642
|
str = str.gsub(/^#{line.comment_tab_str}/m, '')[2..-1] # get rid of // or /*
|
760
643
|
format_comment_text(str, silent)
|
761
644
|
end
|
762
|
-
type = if silent
|
763
|
-
:silent
|
764
|
-
elsif loud
|
765
|
-
:loud
|
766
|
-
else
|
767
|
-
:normal
|
768
|
-
end
|
645
|
+
type = if silent then :silent elsif loud then :loud else :normal end
|
769
646
|
Tree::CommentNode.new(value, type)
|
770
647
|
else
|
771
|
-
Tree::RuleNode.new(parse_interp(line.text)
|
648
|
+
Tree::RuleNode.new(parse_interp(line.text))
|
772
649
|
end
|
773
650
|
end
|
774
651
|
|
775
|
-
DIRECTIVES = Set[:mixin, :include, :function, :return, :debug, :warn, :for,
|
776
|
-
:each, :while, :if, :else, :extend, :import, :media, :charset, :content,
|
777
|
-
:at_root, :error]
|
778
|
-
|
779
|
-
# @comment
|
780
|
-
# rubocop:disable MethodLength
|
781
652
|
def parse_directive(parent, line, root)
|
782
653
|
directive, whitespace, value = line.text[1..-1].split(/(\s+)/, 2)
|
783
|
-
raise SyntaxError.new("Invalid directive: '@'.") unless directive
|
784
654
|
offset = directive.size + whitespace.size + 1 if whitespace
|
785
655
|
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
792
|
-
|
656
|
+
# If value begins with url( or ",
|
657
|
+
# it's a CSS @import rule and we don't want to touch it.
|
658
|
+
case directive
|
659
|
+
when 'import'
|
660
|
+
parse_import(line, value, offset)
|
661
|
+
when 'mixin'
|
662
|
+
parse_mixin_definition(line)
|
663
|
+
when 'content'
|
664
|
+
parse_content_directive(line)
|
665
|
+
when 'include'
|
666
|
+
parse_mixin_include(line, root)
|
667
|
+
when 'function'
|
668
|
+
parse_function(line, root)
|
669
|
+
when 'for'
|
670
|
+
parse_for(line, root, value)
|
671
|
+
when 'each'
|
672
|
+
parse_each(line, root, value)
|
673
|
+
when 'else'
|
674
|
+
parse_else(parent, line, value)
|
675
|
+
when 'while'
|
676
|
+
raise SyntaxError.new("Invalid while directive '@while': expected expression.") unless value
|
677
|
+
Tree::WhileNode.new(parse_script(value, :offset => offset))
|
678
|
+
when 'if'
|
679
|
+
raise SyntaxError.new("Invalid if directive '@if': expected expression.") unless value
|
680
|
+
Tree::IfNode.new(parse_script(value, :offset => offset))
|
681
|
+
when 'debug'
|
682
|
+
raise SyntaxError.new("Invalid debug directive '@debug': expected expression.") unless value
|
683
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath debug directives.",
|
684
|
+
:line => @line + 1) unless line.children.empty?
|
685
|
+
offset = line.offset + line.text.index(value).to_i
|
686
|
+
Tree::DebugNode.new(parse_script(value, :offset => offset))
|
687
|
+
when 'extend'
|
688
|
+
raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
|
689
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
|
690
|
+
:line => @line + 1) unless line.children.empty?
|
691
|
+
optional = !!value.gsub!(/\s+#{Sass::SCSS::RX::OPTIONAL}$/, '')
|
692
|
+
offset = line.offset + line.text.index(value).to_i
|
693
|
+
Tree::ExtendNode.new(parse_interp(value, offset), optional)
|
694
|
+
when 'warn'
|
695
|
+
raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
|
696
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath warn directives.",
|
697
|
+
:line => @line + 1) unless line.children.empty?
|
698
|
+
offset = line.offset + line.text.index(value).to_i
|
699
|
+
Tree::WarnNode.new(parse_script(value, :offset => offset))
|
700
|
+
when 'return'
|
701
|
+
raise SyntaxError.new("Invalid @return: expected expression.") unless value
|
702
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath return directives.",
|
703
|
+
:line => @line + 1) unless line.children.empty?
|
704
|
+
offset = line.offset + line.text.index(value).to_i
|
705
|
+
Tree::ReturnNode.new(parse_script(value, :offset => offset))
|
706
|
+
when 'charset'
|
707
|
+
name = value && value[/\A(["'])(.*)\1\Z/, 2] #"
|
708
|
+
raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
|
709
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath charset directives.",
|
710
|
+
:line => @line + 1) unless line.children.empty?
|
711
|
+
Tree::CharsetNode.new(name)
|
712
|
+
when 'media'
|
793
713
|
parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
Tree::WhileNode.new(parse_script(value, :offset => offset))
|
804
|
-
end
|
805
|
-
|
806
|
-
def parse_if_directive(parent, line, root, value, offset)
|
807
|
-
raise SyntaxError.new("Invalid if directive '@if': expected expression.") unless value
|
808
|
-
Tree::IfNode.new(parse_script(value, :offset => offset))
|
809
|
-
end
|
810
|
-
|
811
|
-
def parse_debug_directive(parent, line, root, value, offset)
|
812
|
-
raise SyntaxError.new("Invalid debug directive '@debug': expected expression.") unless value
|
813
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath debug directives.",
|
814
|
-
:line => @line + 1) unless line.children.empty?
|
815
|
-
offset = line.offset + line.text.index(value).to_i
|
816
|
-
Tree::DebugNode.new(parse_script(value, :offset => offset))
|
817
|
-
end
|
818
|
-
|
819
|
-
def parse_error_directive(parent, line, root, value, offset)
|
820
|
-
raise SyntaxError.new("Invalid error directive '@error': expected expression.") unless value
|
821
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath error directives.",
|
822
|
-
:line => @line + 1) unless line.children.empty?
|
823
|
-
offset = line.offset + line.text.index(value).to_i
|
824
|
-
Tree::ErrorNode.new(parse_script(value, :offset => offset))
|
825
|
-
end
|
826
|
-
|
827
|
-
def parse_extend_directive(parent, line, root, value, offset)
|
828
|
-
raise SyntaxError.new("Invalid extend directive '@extend': expected expression.") unless value
|
829
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath extend directives.",
|
830
|
-
:line => @line + 1) unless line.children.empty?
|
831
|
-
optional = !!value.gsub!(/\s+#{Sass::SCSS::RX::OPTIONAL}$/, '')
|
832
|
-
offset = line.offset + line.text.index(value).to_i
|
833
|
-
interp_parsed = parse_interp(value, offset)
|
834
|
-
selector_range = Sass::Source::Range.new(
|
835
|
-
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
836
|
-
Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
|
837
|
-
@options[:filename], @options[:importer]
|
838
|
-
)
|
839
|
-
Tree::ExtendNode.new(interp_parsed, optional, selector_range)
|
840
|
-
end
|
841
|
-
# @comment
|
842
|
-
# rubocop:enable MethodLength
|
843
|
-
|
844
|
-
def parse_warn_directive(parent, line, root, value, offset)
|
845
|
-
raise SyntaxError.new("Invalid warn directive '@warn': expected expression.") unless value
|
846
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath warn directives.",
|
847
|
-
:line => @line + 1) unless line.children.empty?
|
848
|
-
offset = line.offset + line.text.index(value).to_i
|
849
|
-
Tree::WarnNode.new(parse_script(value, :offset => offset))
|
850
|
-
end
|
851
|
-
|
852
|
-
def parse_return_directive(parent, line, root, value, offset)
|
853
|
-
raise SyntaxError.new("Invalid @return: expected expression.") unless value
|
854
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath return directives.",
|
855
|
-
:line => @line + 1) unless line.children.empty?
|
856
|
-
offset = line.offset + line.text.index(value).to_i
|
857
|
-
Tree::ReturnNode.new(parse_script(value, :offset => offset))
|
858
|
-
end
|
859
|
-
|
860
|
-
def parse_charset_directive(parent, line, root, value, offset)
|
861
|
-
name = value && value[/\A(["'])(.*)\1\Z/, 2] # "
|
862
|
-
raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
|
863
|
-
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath charset directives.",
|
864
|
-
:line => @line + 1) unless line.children.empty?
|
865
|
-
Tree::CharsetNode.new(name)
|
866
|
-
end
|
867
|
-
|
868
|
-
def parse_media_directive(parent, line, root, value, offset)
|
869
|
-
parser = Sass::SCSS::Parser.new(value,
|
870
|
-
@options[:filename], @options[:importer],
|
871
|
-
@line, to_parser_offset(@offset))
|
872
|
-
offset = line.offset + line.text.index('media').to_i - 1
|
873
|
-
parsed_media_query_list = parser.parse_media_query_list.to_a
|
874
|
-
node = Tree::MediaNode.new(parsed_media_query_list)
|
875
|
-
node.source_range = Sass::Source::Range.new(
|
876
|
-
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
877
|
-
Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
|
878
|
-
@options[:filename], @options[:importer])
|
879
|
-
node
|
880
|
-
end
|
881
|
-
|
882
|
-
def parse_at_root_directive(parent, line, root, value, offset)
|
883
|
-
return Sass::Tree::AtRootNode.new unless value
|
714
|
+
Tree::MediaNode.new(parser.parse_media_query_list.to_a)
|
715
|
+
when nil
|
716
|
+
raise SyntaxError.new("Invalid directive: '@'.")
|
717
|
+
else
|
718
|
+
unprefixed_directive = directive.gsub(/^-[a-z0-9]+-/i, '')
|
719
|
+
if unprefixed_directive == 'supports'
|
720
|
+
parser = Sass::SCSS::Parser.new(value, @options[:filename], @line)
|
721
|
+
return Tree::SupportsNode.new(directive, parser.parse_supports_condition)
|
722
|
+
end
|
884
723
|
|
885
|
-
|
886
|
-
|
887
|
-
@options[:filename], @options[:importer],
|
888
|
-
@line, to_parser_offset(@offset))
|
889
|
-
offset = line.offset + line.text.index('at-root').to_i - 1
|
890
|
-
return Tree::AtRootNode.new(parser.parse_at_root_query)
|
724
|
+
Tree::DirectiveNode.new(
|
725
|
+
value.nil? ? ["@#{directive}"] : ["@#{directive} "] + parse_interp(value, offset))
|
891
726
|
end
|
892
|
-
|
893
|
-
at_root_node = Tree::AtRootNode.new
|
894
|
-
parsed = parse_interp(value, offset)
|
895
|
-
rule_node = Tree::RuleNode.new(parsed, full_line_range(line))
|
896
|
-
|
897
|
-
# The caller expects to automatically add children to the returned node
|
898
|
-
# and we want it to add children to the rule node instead, so we
|
899
|
-
# manually handle the wiring here and return nil so the caller doesn't
|
900
|
-
# duplicate our efforts.
|
901
|
-
append_children(rule_node, line.children, false)
|
902
|
-
at_root_node << rule_node
|
903
|
-
parent << at_root_node
|
904
|
-
nil
|
905
727
|
end
|
906
728
|
|
907
|
-
def
|
908
|
-
var, from_expr, to_name, to_expr =
|
909
|
-
value.scan(/^([^\s]+)\s+from\s+(.+)\s+(to|through)\s+(.+)$/).first
|
729
|
+
def parse_for(line, root, text)
|
730
|
+
var, from_expr, to_name, to_expr = text.scan(/^([^\s]+)\s+from\s+(.+)\s+(to|through)\s+(.+)$/).first
|
910
731
|
|
911
732
|
if var.nil? # scan failed, try to figure out why for error message
|
912
|
-
if
|
733
|
+
if text !~ /^[^\s]+/
|
913
734
|
expected = "variable name"
|
914
|
-
elsif
|
735
|
+
elsif text !~ /^[^\s]+\s+from\s+.+/
|
915
736
|
expected = "'from <expr>'"
|
916
737
|
else
|
917
738
|
expected = "'to <expr>' or 'through <expr>'"
|
918
739
|
end
|
919
|
-
raise SyntaxError.new("Invalid for directive '@for #{
|
740
|
+
raise SyntaxError.new("Invalid for directive '@for #{text}': expected #{expected}.")
|
920
741
|
end
|
921
742
|
raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
|
922
743
|
|
@@ -926,35 +747,31 @@ WARNING
|
|
926
747
|
Tree::ForNode.new(var, parsed_from, parsed_to, to_name == 'to')
|
927
748
|
end
|
928
749
|
|
929
|
-
def
|
930
|
-
|
750
|
+
def parse_each(line, root, text)
|
751
|
+
var, list_expr = text.scan(/^([^\s]+)\s+in\s+(.+)$/).first
|
931
752
|
|
932
|
-
if
|
933
|
-
if
|
753
|
+
if var.nil? # scan failed, try to figure out why for error message
|
754
|
+
if text !~ /^[^\s]+/
|
934
755
|
expected = "variable name"
|
935
|
-
elsif
|
756
|
+
elsif text !~ /^[^\s]+\s+from\s+.+/
|
936
757
|
expected = "'in <expr>'"
|
937
758
|
end
|
938
|
-
raise SyntaxError.new("Invalid
|
939
|
-
end
|
940
|
-
|
941
|
-
vars = vars.split(',').map do |var|
|
942
|
-
var.strip!
|
943
|
-
raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
|
944
|
-
var[1..-1]
|
759
|
+
raise SyntaxError.new("Invalid for directive '@each #{text}': expected #{expected}.")
|
945
760
|
end
|
761
|
+
raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
|
946
762
|
|
763
|
+
var = var[1..-1]
|
947
764
|
parsed_list = parse_script(list_expr, :offset => line.offset + line.text.index(list_expr))
|
948
|
-
Tree::EachNode.new(
|
765
|
+
Tree::EachNode.new(var, parsed_list)
|
949
766
|
end
|
950
767
|
|
951
|
-
def
|
768
|
+
def parse_else(parent, line, text)
|
952
769
|
previous = parent.children.last
|
953
770
|
raise SyntaxError.new("@else must come after @if.") unless previous.is_a?(Tree::IfNode)
|
954
771
|
|
955
|
-
if
|
956
|
-
if
|
957
|
-
raise SyntaxError.new("Invalid else directive '@else #{
|
772
|
+
if text
|
773
|
+
if text !~ /^if\s+(.+)/
|
774
|
+
raise SyntaxError.new("Invalid else directive '@else #{text}': expected 'if <expr>'.")
|
958
775
|
end
|
959
776
|
expr = parse_script($1, :offset => line.offset + line.text.index($1))
|
960
777
|
end
|
@@ -965,7 +782,7 @@ WARNING
|
|
965
782
|
nil
|
966
783
|
end
|
967
784
|
|
968
|
-
def
|
785
|
+
def parse_import(line, value, offset)
|
969
786
|
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath import directives.",
|
970
787
|
:line => @line + 1) unless line.children.empty?
|
971
788
|
|
@@ -973,9 +790,8 @@ WARNING
|
|
973
790
|
values = []
|
974
791
|
|
975
792
|
loop do
|
976
|
-
unless
|
977
|
-
raise SyntaxError.new(
|
978
|
-
"Invalid @import: expected file to import, was #{scanner.rest.inspect}",
|
793
|
+
unless node = parse_import_arg(scanner, offset + scanner.pos)
|
794
|
+
raise SyntaxError.new("Invalid @import: expected file to import, was #{scanner.rest.inspect}",
|
979
795
|
:line => @line)
|
980
796
|
end
|
981
797
|
values << node
|
@@ -987,81 +803,35 @@ WARNING
|
|
987
803
|
:line => @line)
|
988
804
|
end
|
989
805
|
|
990
|
-
values
|
806
|
+
return values
|
991
807
|
end
|
992
808
|
|
993
|
-
# @comment
|
994
|
-
# rubocop:disable MethodLength
|
995
809
|
def parse_import_arg(scanner, offset)
|
996
810
|
return if scanner.eos?
|
997
811
|
|
998
812
|
if scanner.match?(/url\(/i)
|
999
|
-
script_parser = Sass::Script::Parser.new(scanner, @line,
|
813
|
+
script_parser = Sass::Script::Parser.new(scanner, @line, offset, @options)
|
1000
814
|
str = script_parser.parse_string
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
node = Tree::CssImportNode.new(str)
|
1005
|
-
else
|
1006
|
-
media_parser = Sass::SCSS::Parser.new(scanner,
|
1007
|
-
@options[:filename], @options[:importer],
|
1008
|
-
@line, str.source_range.end_pos.offset)
|
1009
|
-
media = media_parser.parse_media_query_list
|
1010
|
-
end_pos = Sass::Source::Position.new(@line, media_parser.offset + 1)
|
1011
|
-
node = Tree::CssImportNode.new(str, media.to_a)
|
1012
|
-
end
|
1013
|
-
|
1014
|
-
node.source_range = Sass::Source::Range.new(
|
1015
|
-
str.source_range.start_pos, end_pos,
|
1016
|
-
@options[:filename], @options[:importer])
|
1017
|
-
return node
|
815
|
+
media_parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
|
816
|
+
media = media_parser.parse_media_query_list
|
817
|
+
return Tree::CssImportNode.new(str, media.to_a)
|
1018
818
|
end
|
1019
819
|
|
1020
|
-
unless
|
1021
|
-
|
1022
|
-
node = Tree::ImportNode.new(scanned)
|
1023
|
-
start_parser_offset = to_parser_offset(offset)
|
1024
|
-
node.source_range = Sass::Source::Range.new(
|
1025
|
-
Sass::Source::Position.new(@line, start_parser_offset),
|
1026
|
-
Sass::Source::Position.new(@line, start_parser_offset + scanned.length),
|
1027
|
-
@options[:filename], @options[:importer])
|
1028
|
-
return node
|
820
|
+
unless str = scanner.scan(Sass::SCSS::RX::STRING)
|
821
|
+
return Tree::ImportNode.new(scanner.scan(/[^,;]+/))
|
1029
822
|
end
|
1030
823
|
|
1031
|
-
|
1032
|
-
|
1033
|
-
val = Sass::Script::Value::String.value(scanner[1] || scanner[2])
|
1034
|
-
scanned = scanner.scan(/\s*/)
|
824
|
+
val = scanner[1] || scanner[2]
|
825
|
+
scanner.scan(/\s*/)
|
1035
826
|
if !scanner.match?(/[,;]|$/)
|
1036
|
-
|
1037
|
-
media_parser = Sass::SCSS::Parser.new(scanner,
|
1038
|
-
@options[:filename], @options[:importer], @line, offset)
|
827
|
+
media_parser = Sass::SCSS::Parser.new(scanner, @options[:filename], @line)
|
1039
828
|
media = media_parser.parse_media_query_list
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
Sass::Source::Position.new(@line, media_parser.offset),
|
1044
|
-
@options[:filename], @options[:importer])
|
1045
|
-
elsif val =~ %r{^(https?:)?//}
|
1046
|
-
node = Tree::CssImportNode.new(quoted_val)
|
1047
|
-
node.source_range = Sass::Source::Range.new(
|
1048
|
-
Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
|
1049
|
-
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
1050
|
-
@options[:filename], @options[:importer])
|
829
|
+
Tree::CssImportNode.new(str || uri, media.to_a)
|
830
|
+
elsif val =~ /^(https?:)?\/\//
|
831
|
+
Tree::CssImportNode.new("url(#{val})")
|
1051
832
|
else
|
1052
|
-
|
1053
|
-
node.source_range = Sass::Source::Range.new(
|
1054
|
-
Sass::Source::Position.new(@line, to_parser_offset(start_offset)),
|
1055
|
-
Sass::Source::Position.new(@line, to_parser_offset(offset)),
|
1056
|
-
@options[:filename], @options[:importer])
|
833
|
+
Tree::ImportNode.new(val)
|
1057
834
|
end
|
1058
|
-
node
|
1059
|
-
end
|
1060
|
-
# @comment
|
1061
|
-
# rubocop:enable MethodLength
|
1062
|
-
|
1063
|
-
def parse_mixin_directive(parent, line, root, value, offset)
|
1064
|
-
parse_mixin_definition(line)
|
1065
835
|
end
|
1066
836
|
|
1067
837
|
MIXIN_DEF_RE = /^(?:=|@mixin)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
|
@@ -1070,53 +840,45 @@ WARNING
|
|
1070
840
|
raise SyntaxError.new("Invalid mixin \"#{line.text[1..-1]}\".") if name.nil?
|
1071
841
|
|
1072
842
|
offset = line.offset + line.text.size - arg_string.size
|
1073
|
-
args, splat = Script::Parser.new(arg_string.strip, @line,
|
843
|
+
args, splat = Script::Parser.new(arg_string.strip, @line, offset, @options).
|
1074
844
|
parse_mixin_definition_arglist
|
1075
845
|
Tree::MixinDefNode.new(name, args, splat)
|
1076
846
|
end
|
1077
847
|
|
1078
848
|
CONTENT_RE = /^@content\s*(.+)?$/
|
1079
|
-
def parse_content_directive(
|
849
|
+
def parse_content_directive(line)
|
1080
850
|
trailing = line.text.scan(CONTENT_RE).first.first
|
1081
|
-
unless trailing.nil?
|
1082
|
-
raise SyntaxError.new(
|
1083
|
-
"Invalid content directive. Trailing characters found: \"#{trailing}\".")
|
1084
|
-
end
|
851
|
+
raise SyntaxError.new("Invalid content directive. Trailing characters found: \"#{trailing}\".") unless trailing.nil?
|
1085
852
|
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath @content directives.",
|
1086
853
|
:line => line.index + 1) unless line.children.empty?
|
1087
854
|
Tree::ContentNode.new
|
1088
855
|
end
|
1089
856
|
|
1090
|
-
def parse_include_directive(parent, line, root, value, offset)
|
1091
|
-
parse_mixin_include(line, root)
|
1092
|
-
end
|
1093
|
-
|
1094
857
|
MIXIN_INCLUDE_RE = /^(?:\+|@include)\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
|
1095
858
|
def parse_mixin_include(line, root)
|
1096
859
|
name, arg_string = line.text.scan(MIXIN_INCLUDE_RE).first
|
1097
860
|
raise SyntaxError.new("Invalid mixin include \"#{line.text}\".") if name.nil?
|
1098
861
|
|
1099
862
|
offset = line.offset + line.text.size - arg_string.size
|
1100
|
-
args, keywords, splat,
|
1101
|
-
|
1102
|
-
|
1103
|
-
Tree::MixinNode.new(name, args, keywords, splat, kwarg_splat)
|
863
|
+
args, keywords, splat = Script::Parser.new(arg_string.strip, @line, offset, @options).
|
864
|
+
parse_mixin_include_arglist
|
865
|
+
Tree::MixinNode.new(name, args, keywords, splat)
|
1104
866
|
end
|
1105
867
|
|
1106
868
|
FUNCTION_RE = /^@function\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
|
1107
|
-
def
|
869
|
+
def parse_function(line, root)
|
1108
870
|
name, arg_string = line.text.scan(FUNCTION_RE).first
|
1109
871
|
raise SyntaxError.new("Invalid function definition \"#{line.text}\".") if name.nil?
|
1110
872
|
|
1111
873
|
offset = line.offset + line.text.size - arg_string.size
|
1112
|
-
args, splat = Script::Parser.new(arg_string.strip, @line,
|
874
|
+
args, splat = Script::Parser.new(arg_string.strip, @line, offset, @options).
|
1113
875
|
parse_function_definition_arglist
|
1114
876
|
Tree::FunctionNode.new(name, args, splat)
|
1115
877
|
end
|
1116
878
|
|
1117
879
|
def parse_script(script, options = {})
|
1118
880
|
line = options[:line] || @line
|
1119
|
-
offset = options[:offset] ||
|
881
|
+
offset = options[:offset] || 0
|
1120
882
|
Script.parse(script, line, offset, @options)
|
1121
883
|
end
|
1122
884
|
|
@@ -1128,12 +890,12 @@ WARNING
|
|
1128
890
|
content.shift
|
1129
891
|
end
|
1130
892
|
|
1131
|
-
return "/* */" if content.empty?
|
1132
|
-
content.last.gsub!(
|
893
|
+
return silent ? "//" : "/* */" if content.empty?
|
894
|
+
content.last.gsub!(%r{ ?\*/ *$}, '')
|
1133
895
|
content.map! {|l| l.gsub!(/^\*( ?)/, '\1') || (l.empty? ? "" : " ") + l}
|
1134
896
|
content.first.gsub!(/^ /, '') unless removed_first
|
1135
897
|
if silent
|
1136
|
-
"
|
898
|
+
"//" + content.join("\n//")
|
1137
899
|
else
|
1138
900
|
# The #gsub fixes the case of a trailing */
|
1139
901
|
"/*" + content.join("\n *").gsub(/ \*\Z/, '') + " */"
|
@@ -1144,20 +906,8 @@ WARNING
|
|
1144
906
|
self.class.parse_interp(text, @line, offset, :filename => @filename)
|
1145
907
|
end
|
1146
908
|
|
1147
|
-
# Parser tracks 1-based line and offset, so our offset should be converted.
|
1148
|
-
def to_parser_offset(offset)
|
1149
|
-
offset + 1
|
1150
|
-
end
|
1151
|
-
|
1152
|
-
def full_line_range(line)
|
1153
|
-
Sass::Source::Range.new(
|
1154
|
-
Sass::Source::Position.new(@line, to_parser_offset(line.offset)),
|
1155
|
-
Sass::Source::Position.new(@line, to_parser_offset(line.offset) + line.text.length),
|
1156
|
-
@options[:filename], @options[:importer])
|
1157
|
-
end
|
1158
|
-
|
1159
909
|
# It's important that this have strings (at least)
|
1160
|
-
# at the beginning, the end, and between each Script::
|
910
|
+
# at the beginning, the end, and between each Script::Node.
|
1161
911
|
#
|
1162
912
|
# @private
|
1163
913
|
def self.parse_interp(text, line, offset, options)
|
@@ -1165,13 +915,12 @@ WARNING
|
|
1165
915
|
rest = Sass::Shared.handle_interpolation text do |scan|
|
1166
916
|
escapes = scan[2].size
|
1167
917
|
res << scan.matched[0...-2 - escapes]
|
1168
|
-
if escapes
|
918
|
+
if escapes % 2 == 1
|
1169
919
|
res << "\\" * (escapes - 1) << '#{'
|
1170
920
|
else
|
1171
921
|
res << "\\" * [0, escapes - 1].max
|
1172
|
-
# Add 1 to emulate to_parser_offset.
|
1173
922
|
res << Script::Parser.new(
|
1174
|
-
scan, line, offset + scan.pos - scan.matched_size
|
923
|
+
scan, line, offset + scan.pos - scan.matched_size, options).
|
1175
924
|
parse_interpolated
|
1176
925
|
end
|
1177
926
|
end
|