haml 3.1.0 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of haml might be problematic. Click here for more details.
- data/VERSION +1 -1
- data/vendor/sass/Rakefile +22 -46
- data/vendor/sass/VERSION +1 -1
- data/vendor/sass/VERSION_NAME +1 -1
- data/vendor/sass/bin/scss +8 -0
- data/vendor/sass/doc-src/SASS_CHANGELOG.md +125 -9
- data/vendor/sass/doc-src/SASS_REFERENCE.md +84 -8
- data/vendor/sass/lib/sass.rb +0 -3
- data/vendor/sass/lib/sass/cache_stores.rb +1 -0
- data/vendor/sass/lib/sass/cache_stores/base.rb +2 -2
- data/vendor/sass/lib/sass/cache_stores/chain.rb +33 -0
- data/vendor/sass/lib/sass/cache_stores/filesystem.rb +6 -4
- data/vendor/sass/lib/sass/cache_stores/memory.rb +8 -12
- data/vendor/sass/lib/sass/engine.rb +65 -56
- data/vendor/sass/lib/sass/environment.rb +5 -2
- data/vendor/sass/lib/sass/exec.rb +52 -21
- data/vendor/sass/lib/sass/importers/filesystem.rb +32 -9
- data/vendor/sass/lib/sass/less.rb +1 -1
- data/vendor/sass/lib/sass/plugin.rb +11 -1
- data/vendor/sass/lib/sass/plugin/compiler.rb +21 -12
- data/vendor/sass/lib/sass/plugin/rails.rb +8 -82
- data/vendor/sass/lib/sass/plugin/staleness_checker.rb +10 -10
- data/vendor/sass/lib/sass/railtie.rb +3 -2
- data/vendor/sass/lib/sass/script.rb +2 -25
- data/vendor/sass/lib/sass/script/color.rb +4 -15
- data/vendor/sass/lib/sass/script/funcall.rb +63 -19
- data/vendor/sass/lib/sass/script/functions.rb +257 -19
- data/vendor/sass/lib/sass/script/lexer.rb +1 -4
- data/vendor/sass/lib/sass/script/list.rb +2 -2
- data/vendor/sass/lib/sass/script/node.rb +0 -27
- data/vendor/sass/lib/sass/script/number.rb +1 -1
- data/vendor/sass/lib/sass/script/operation.rb +0 -5
- data/vendor/sass/lib/sass/script/parser.rb +30 -12
- data/vendor/sass/lib/sass/script/string.rb +2 -17
- data/vendor/sass/lib/sass/script/string_interpolation.rb +1 -0
- data/vendor/sass/lib/sass/scss/parser.rb +58 -18
- data/vendor/sass/lib/sass/scss/rx.rb +2 -1
- data/vendor/sass/lib/sass/scss/script_lexer.rb +1 -1
- data/vendor/sass/lib/sass/selector/comma_sequence.rb +2 -3
- data/vendor/sass/lib/sass/selector/sequence.rb +3 -6
- data/vendor/sass/lib/sass/selector/simple_sequence.rb +2 -3
- data/vendor/sass/lib/sass/tree/charset_node.rb +0 -15
- data/vendor/sass/lib/sass/tree/comment_node.rb +20 -71
- data/vendor/sass/lib/sass/tree/debug_node.rb +4 -22
- data/vendor/sass/lib/sass/tree/directive_node.rb +0 -52
- data/vendor/sass/lib/sass/tree/each_node.rb +8 -38
- data/vendor/sass/lib/sass/tree/extend_node.rb +12 -48
- data/vendor/sass/lib/sass/tree/for_node.rb +20 -51
- data/vendor/sass/lib/sass/tree/function_node.rb +27 -0
- data/vendor/sass/lib/sass/tree/if_node.rb +22 -57
- data/vendor/sass/lib/sass/tree/import_node.rb +0 -56
- data/vendor/sass/lib/sass/tree/media_node.rb +0 -43
- data/vendor/sass/lib/sass/tree/mixin_def_node.rb +12 -45
- data/vendor/sass/lib/sass/tree/mixin_node.rb +13 -124
- data/vendor/sass/lib/sass/tree/node.rb +18 -304
- data/vendor/sass/lib/sass/tree/prop_node.rb +24 -92
- data/vendor/sass/lib/sass/tree/return_node.rb +18 -0
- data/vendor/sass/lib/sass/tree/root_node.rb +4 -133
- data/vendor/sass/lib/sass/tree/rule_node.rb +21 -164
- data/vendor/sass/lib/sass/tree/variable_node.rb +14 -23
- data/vendor/sass/lib/sass/tree/visitors/base.rb +75 -0
- data/vendor/sass/lib/sass/tree/visitors/check_nesting.rb +134 -0
- data/vendor/sass/lib/sass/tree/visitors/convert.rb +255 -0
- data/vendor/sass/lib/sass/tree/visitors/cssize.rb +175 -0
- data/vendor/sass/lib/sass/tree/visitors/perform.rb +301 -0
- data/vendor/sass/lib/sass/tree/visitors/to_css.rb +216 -0
- data/vendor/sass/lib/sass/tree/warn_node.rb +4 -28
- data/vendor/sass/lib/sass/tree/while_node.rb +5 -35
- data/vendor/sass/lib/sass/util.rb +0 -50
- data/vendor/sass/sass.gemspec +1 -1
- data/vendor/sass/test/sass/conversion_test.rb +53 -102
- data/vendor/sass/test/sass/engine_test.rb +416 -540
- data/vendor/sass/test/sass/functions_test.rb +306 -4
- data/vendor/sass/test/sass/importer_test.rb +0 -22
- data/vendor/sass/test/sass/plugin_test.rb +51 -21
- data/vendor/sass/test/sass/results/if.css +3 -0
- data/vendor/sass/test/sass/script_conversion_test.rb +0 -38
- data/vendor/sass/test/sass/script_test.rb +19 -4
- data/vendor/sass/test/sass/scss/scss_test.rb +32 -11
- data/vendor/sass/test/sass/templates/if.sass +11 -0
- data/vendor/sass/test/sass/templates/nested_import.sass +2 -0
- data/vendor/sass/test/sass/util_test.rb +0 -21
- data/vendor/sass/test/test_helper.rb +0 -3
- metadata +268 -258
- data/vendor/sass/bin/css2sass +0 -13
- data/vendor/sass/lib/sass/cache_stores/active_support.rb +0 -28
- data/vendor/sass/lib/sass/importers/rails.rb +0 -75
data/vendor/sass/lib/sass.rb
CHANGED
@@ -48,7 +48,7 @@ module Sass
|
|
48
48
|
# @param sha [String] The checksum for the contents that are being stored.
|
49
49
|
# @param obj [Object] The object to cache.
|
50
50
|
def store(key, sha, root)
|
51
|
-
_store(key, Sass::VERSION, sha,
|
51
|
+
_store(key, Sass::VERSION, sha, Marshal.dump(root))
|
52
52
|
end
|
53
53
|
|
54
54
|
# Retrieve a {Sass::Tree::RootNode}.
|
@@ -58,7 +58,7 @@ module Sass
|
|
58
58
|
# @return [Object] The cached object.
|
59
59
|
def retrieve(key, sha)
|
60
60
|
contents = _retrieve(key, Sass::VERSION, sha)
|
61
|
-
|
61
|
+
Marshal.load(contents) if contents
|
62
62
|
rescue EOFError, TypeError, ArgumentError => e
|
63
63
|
Sass::Util.sass_warn "Warning. Error encountered while reading cache #{path_to(key)}: #{e}"
|
64
64
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Sass
|
2
|
+
module CacheStores
|
3
|
+
# A meta-cache that chains multiple caches together.
|
4
|
+
# Specifically:
|
5
|
+
#
|
6
|
+
# * All `#store`s are passed to all caches.
|
7
|
+
# * `#retrieve`s are passed to each cache until one has a hit.
|
8
|
+
# * When one cache has a hit, the value is `#store`d in all earlier caches.
|
9
|
+
class Chain < Base
|
10
|
+
# Create a new cache chaining the given caches.
|
11
|
+
#
|
12
|
+
# @param caches [Array<Sass::CacheStores::Base>] The caches to chain.
|
13
|
+
def initialize(*caches)
|
14
|
+
@caches = caches
|
15
|
+
end
|
16
|
+
|
17
|
+
# @see Base#store
|
18
|
+
def store(key, sha, obj)
|
19
|
+
@caches.each {|c| c.store(key, sha, obj)}
|
20
|
+
end
|
21
|
+
|
22
|
+
# @see Base#retrieve
|
23
|
+
def retrieve(key, sha)
|
24
|
+
@caches.each_with_index do |c, i|
|
25
|
+
next unless obj = c.retrieve(key, sha)
|
26
|
+
@caches[0...i].each {|c| c.store(key, sha, obj)}
|
27
|
+
return obj
|
28
|
+
end
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -29,17 +29,19 @@ module Sass
|
|
29
29
|
|
30
30
|
# @see Base#\_store
|
31
31
|
def _store(key, version, sha, contents)
|
32
|
-
return unless File.writable?(File.dirname(@cache_location))
|
33
|
-
return if File.exists?(@cache_location) && !File.writable?(@cache_location)
|
32
|
+
# return unless File.writable?(File.dirname(@cache_location))
|
33
|
+
# return if File.exists?(@cache_location) && !File.writable?(@cache_location)
|
34
34
|
compiled_filename = path_to(key)
|
35
|
-
return if File.exists?(File.dirname(compiled_filename)) && !File.writable?(File.dirname(compiled_filename))
|
36
|
-
return if File.exists?(compiled_filename) && !File.writable?(compiled_filename)
|
35
|
+
# return if File.exists?(File.dirname(compiled_filename)) && !File.writable?(File.dirname(compiled_filename))
|
36
|
+
# return if File.exists?(compiled_filename) && !File.writable?(compiled_filename)
|
37
37
|
FileUtils.mkdir_p(File.dirname(compiled_filename))
|
38
38
|
File.open(compiled_filename, "wb") do |f|
|
39
39
|
f.puts(version)
|
40
40
|
f.puts(sha)
|
41
41
|
f.write(contents)
|
42
42
|
end
|
43
|
+
rescue Errno::EACCES
|
44
|
+
#pass
|
43
45
|
end
|
44
46
|
|
45
47
|
private
|
@@ -24,22 +24,18 @@ module Sass
|
|
24
24
|
@contents = {}
|
25
25
|
end
|
26
26
|
|
27
|
-
# @see Base#
|
28
|
-
def
|
27
|
+
# @see Base#retrieve
|
28
|
+
def retrieve(key, sha)
|
29
29
|
if @contents.has_key?(key)
|
30
|
-
return unless @contents[key][:version] == version
|
31
30
|
return unless @contents[key][:sha] == sha
|
32
|
-
|
31
|
+
obj = @contents[key][:obj]
|
32
|
+
obj.respond_to?(:deep_copy) ? obj.deep_copy : obj.dup
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
|
-
# @see Base#
|
37
|
-
def
|
38
|
-
@contents[key] = {
|
39
|
-
:version => version,
|
40
|
-
:sha => sha,
|
41
|
-
:contents => contents
|
42
|
-
}
|
35
|
+
|
36
|
+
# @see Base#store
|
37
|
+
def store(key, sha, obj)
|
38
|
+
@contents[key] = {:sha => sha, :obj => obj}
|
43
39
|
end
|
44
40
|
|
45
41
|
# Destructively clear the cache.
|
@@ -12,6 +12,8 @@ require 'sass/tree/media_node'
|
|
12
12
|
require 'sass/tree/variable_node'
|
13
13
|
require 'sass/tree/mixin_def_node'
|
14
14
|
require 'sass/tree/mixin_node'
|
15
|
+
require 'sass/tree/function_node'
|
16
|
+
require 'sass/tree/return_node'
|
15
17
|
require 'sass/tree/extend_node'
|
16
18
|
require 'sass/tree/if_node'
|
17
19
|
require 'sass/tree/while_node'
|
@@ -21,6 +23,12 @@ require 'sass/tree/debug_node'
|
|
21
23
|
require 'sass/tree/warn_node'
|
22
24
|
require 'sass/tree/import_node'
|
23
25
|
require 'sass/tree/charset_node'
|
26
|
+
require 'sass/tree/visitors/base'
|
27
|
+
require 'sass/tree/visitors/perform'
|
28
|
+
require 'sass/tree/visitors/cssize'
|
29
|
+
require 'sass/tree/visitors/convert'
|
30
|
+
require 'sass/tree/visitors/to_css'
|
31
|
+
require 'sass/tree/visitors/check_nesting'
|
24
32
|
require 'sass/selector'
|
25
33
|
require 'sass/environment'
|
26
34
|
require 'sass/script'
|
@@ -31,24 +39,24 @@ require 'sass/shared'
|
|
31
39
|
|
32
40
|
module Sass
|
33
41
|
|
34
|
-
# A Sass mixin.
|
42
|
+
# A Sass mixin or function.
|
35
43
|
#
|
36
44
|
# `name`: `String`
|
37
|
-
# : The name of the mixin.
|
45
|
+
# : The name of the mixin/function.
|
38
46
|
#
|
39
47
|
# `args`: `Array<(String, Script::Node)>`
|
40
|
-
# : The arguments for the mixin.
|
48
|
+
# : The arguments for the mixin/function.
|
41
49
|
# Each element is a tuple containing the name of the argument
|
42
50
|
# and the parse tree for the default value of the argument.
|
43
51
|
#
|
44
52
|
# `environment`: {Sass::Environment}
|
45
|
-
# : The environment in which the mixin was defined.
|
46
|
-
# This is captured so that the mixin can have access
|
53
|
+
# : The environment in which the mixin/function was defined.
|
54
|
+
# This is captured so that the mixin/function can have access
|
47
55
|
# to local variables defined in its scope.
|
48
56
|
#
|
49
|
-
# `tree`:
|
50
|
-
# : The parse tree for the mixin.
|
51
|
-
|
57
|
+
# `tree`: `Array<Tree::Node>`
|
58
|
+
# : The parse tree for the mixin/function.
|
59
|
+
Callable = Struct.new(:name, :args, :environment, :tree)
|
52
60
|
|
53
61
|
# This class handles the parsing and compilation of the Sass template.
|
54
62
|
# Example usage:
|
@@ -89,10 +97,6 @@ module Sass
|
|
89
97
|
# The character that begins a CSS property.
|
90
98
|
PROPERTY_CHAR = ?:
|
91
99
|
|
92
|
-
# The character that designates that
|
93
|
-
# a property should be assigned to a SassScript expression.
|
94
|
-
SCRIPT_CHAR = ?=
|
95
|
-
|
96
100
|
# The character that designates the beginning of a comment,
|
97
101
|
# either Sass or CSS.
|
98
102
|
COMMENT_CHAR = ?/
|
@@ -117,16 +121,9 @@ module Sass
|
|
117
121
|
# Includes named mixin declared using MIXIN_DEFINITION_CHAR
|
118
122
|
MIXIN_INCLUDE_CHAR = ?+
|
119
123
|
|
120
|
-
# The regex that matches properties of the form `name: prop`.
|
121
|
-
PROPERTY_NEW_MATCHER = /^[^\s:"\[]+\s*[=:](\s|$)/
|
122
|
-
|
123
|
-
# The regex that matches and extracts data from
|
124
|
-
# properties of the form `name: prop`.
|
125
|
-
PROPERTY_NEW = /^([^\s=:"]+)\s*(=|:)(?:\s+|$)(.*)/
|
126
|
-
|
127
124
|
# The regex that matches and extracts data from
|
128
125
|
# properties of the form `:name prop`.
|
129
|
-
PROPERTY_OLD = /^:([^\s=:"]+)\s*(
|
126
|
+
PROPERTY_OLD = /^:([^\s=:"]+)\s*(?:\s+|$)(.*)/
|
130
127
|
|
131
128
|
# The default options for Sass::Engine.
|
132
129
|
# @api public
|
@@ -154,9 +151,10 @@ module Sass
|
|
154
151
|
options[:importer] ||= options[:filesystem_importer].new(".") if options[:filename]
|
155
152
|
|
156
153
|
# Tracks the original filename of the top-level Sass file
|
157
|
-
options[:original_filename]
|
154
|
+
options[:original_filename] ||= options[:filename]
|
158
155
|
|
159
|
-
options[:cache_store] ||= Sass::CacheStores::
|
156
|
+
options[:cache_store] ||= Sass::CacheStores::Chain.new(
|
157
|
+
Sass::CacheStores::Memory.new, Sass::CacheStores::Filesystem.new(options[:cache_location]))
|
160
158
|
# Support both, because the docs said one and the other actually worked
|
161
159
|
# for quite a long time.
|
162
160
|
options[:line_comments] ||= options[:line_numbers]
|
@@ -325,7 +323,15 @@ module Sass
|
|
325
323
|
end
|
326
324
|
|
327
325
|
root.options = @options
|
328
|
-
|
326
|
+
if @options[:cache] && key && sha
|
327
|
+
begin
|
328
|
+
old_options = root.options
|
329
|
+
root.options = {:importer => root.options[:importer]}
|
330
|
+
@options[:cache_store].store(key, sha, root)
|
331
|
+
ensure
|
332
|
+
root.options = old_options
|
333
|
+
end
|
334
|
+
end
|
329
335
|
root
|
330
336
|
rescue SyntaxError => e
|
331
337
|
e.modify_backtrace(:filename => @options[:filename], :line => @line)
|
@@ -516,19 +522,19 @@ WARNING
|
|
516
522
|
when PROPERTY_CHAR
|
517
523
|
if line.text[1] == PROPERTY_CHAR ||
|
518
524
|
(@options[:property_syntax] == :new &&
|
519
|
-
line.text =~ PROPERTY_OLD && $
|
525
|
+
line.text =~ PROPERTY_OLD && $2.empty?)
|
520
526
|
# Support CSS3-style pseudo-elements,
|
521
527
|
# which begin with ::,
|
522
528
|
# as well as pseudo-classes
|
523
529
|
# if we're using the new property syntax
|
524
530
|
Tree::RuleNode.new(parse_interp(line.text))
|
525
531
|
else
|
526
|
-
name,
|
532
|
+
name, value = line.text.scan(PROPERTY_OLD)[0]
|
527
533
|
raise SyntaxError.new("Invalid property: \"#{line.text}\".",
|
528
534
|
:line => @line) if name.nil? || value.nil?
|
529
|
-
parse_property(name, parse_interp(name),
|
535
|
+
parse_property(name, parse_interp(name), value, :old, line)
|
530
536
|
end
|
531
|
-
when
|
537
|
+
when ?$
|
532
538
|
parse_variable(line)
|
533
539
|
when COMMENT_CHAR
|
534
540
|
parse_comment(line.text)
|
@@ -563,48 +569,39 @@ WARNING
|
|
563
569
|
end
|
564
570
|
|
565
571
|
name = line.text[0...scanner.pos]
|
566
|
-
if scanner.scan(/\s
|
567
|
-
parse_property(name, res, scanner
|
572
|
+
if scanner.scan(/\s*:(?:\s|$)/)
|
573
|
+
parse_property(name, res, scanner.rest, :new, line)
|
568
574
|
else
|
569
575
|
res.pop if comment
|
570
576
|
Tree::RuleNode.new(res + parse_interp(scanner.rest))
|
571
577
|
end
|
572
578
|
end
|
573
579
|
|
574
|
-
def parse_property(name, parsed_name,
|
580
|
+
def parse_property(name, parsed_name, value, prop, line)
|
575
581
|
if value.strip.empty?
|
576
582
|
expr = Sass::Script::String.new("")
|
577
583
|
else
|
584
|
+
important = false
|
585
|
+
if value =~ Sass::SCSS::RX::IMPORTANT
|
586
|
+
important = true
|
587
|
+
value = value.gsub(Sass::SCSS::RX::IMPORTANT,"")
|
588
|
+
end
|
578
589
|
expr = parse_script(value, :offset => line.offset + line.text.index(value))
|
579
590
|
|
580
|
-
if eq.strip[0] == SCRIPT_CHAR
|
581
|
-
expr.context = :equals
|
582
|
-
Script.equals_warning("properties", name,
|
583
|
-
Sass::Tree::PropNode.val_to_sass(expr, @options), false,
|
584
|
-
@line, line.offset + 1, @options[:filename])
|
585
|
-
end
|
586
591
|
end
|
587
|
-
Tree::PropNode.new(parse_interp(name), expr, prop)
|
592
|
+
Tree::PropNode.new(parse_interp(name), expr, important, prop)
|
588
593
|
end
|
589
594
|
|
590
595
|
def parse_variable(line)
|
591
|
-
name,
|
592
|
-
guarded = op =~ /^\|\|/
|
596
|
+
name, value, default = line.text.scan(Script::MATCH)[0]
|
593
597
|
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath variable declarations.",
|
594
598
|
:line => @line + 1) unless line.children.empty?
|
595
599
|
raise SyntaxError.new("Invalid variable: \"#{line.text}\".",
|
596
600
|
:line => @line) unless name && value
|
597
|
-
Script.var_warning(name, @line, line.offset + 1, @options[:filename]) if line.text[0] == ?!
|
598
601
|
|
599
602
|
expr = parse_script(value, :offset => line.offset + line.text.index(value))
|
600
|
-
if op =~ /=$/
|
601
|
-
expr.context = :equals
|
602
|
-
type = guarded ? "variable defaults" : "variables"
|
603
|
-
Script.equals_warning(type, "$#{name}", expr.to_sass,
|
604
|
-
guarded, @line, line.offset + 1, @options[:filename])
|
605
|
-
end
|
606
603
|
|
607
|
-
Tree::VariableNode.new(name, expr, default
|
604
|
+
Tree::VariableNode.new(name, expr, default)
|
608
605
|
end
|
609
606
|
|
610
607
|
def parse_comment(line)
|
@@ -630,6 +627,8 @@ WARNING
|
|
630
627
|
parse_mixin_definition(line)
|
631
628
|
elsif directive == "include"
|
632
629
|
parse_mixin_include(line, root)
|
630
|
+
elsif directive == "function"
|
631
|
+
parse_function(line, root)
|
633
632
|
elsif directive == "for"
|
634
633
|
parse_for(line, root, value)
|
635
634
|
elsif directive == "each"
|
@@ -660,6 +659,12 @@ WARNING
|
|
660
659
|
:line => @line + 1) unless line.children.empty?
|
661
660
|
offset = line.offset + line.text.index(value).to_i
|
662
661
|
Tree::WarnNode.new(parse_script(value, :offset => offset))
|
662
|
+
elsif directive == "return"
|
663
|
+
raise SyntaxError.new("Invalid @return: expected expression.") unless value
|
664
|
+
raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath return directives.",
|
665
|
+
:line => @line + 1) unless line.children.empty?
|
666
|
+
offset = line.offset + line.text.index(value).to_i
|
667
|
+
Tree::ReturnNode.new(parse_script(value, :offset => offset))
|
663
668
|
elsif directive == "charset"
|
664
669
|
name = value && value[/\A(["'])(.*)\1\Z/, 2] #"
|
665
670
|
raise SyntaxError.new("Invalid charset directive '@charset': expected string.") unless name
|
@@ -687,11 +692,8 @@ WARNING
|
|
687
692
|
raise SyntaxError.new("Invalid for directive '@for #{text}': expected #{expected}.")
|
688
693
|
end
|
689
694
|
raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
|
690
|
-
if var.slice!(0) == ?!
|
691
|
-
offset = line.offset + line.text.index("!" + var) + 1
|
692
|
-
Script.var_warning(var, @line, offset, @options[:filename])
|
693
|
-
end
|
694
695
|
|
696
|
+
var = var[1..-1]
|
695
697
|
parsed_from = parse_script(from_expr, :offset => line.offset + line.text.index(from_expr))
|
696
698
|
parsed_to = parse_script(to_expr, :offset => line.offset + line.text.index(to_expr))
|
697
699
|
Tree::ForNode.new(var, parsed_from, parsed_to, to_name == 'to')
|
@@ -709,11 +711,8 @@ WARNING
|
|
709
711
|
raise SyntaxError.new("Invalid for directive '@each #{text}': expected #{expected}.")
|
710
712
|
end
|
711
713
|
raise SyntaxError.new("Invalid variable \"#{var}\".") unless var =~ Script::VALIDATE
|
712
|
-
if var.slice!(0) == ?!
|
713
|
-
offset = line.offset + line.text.index("!" + var) + 1
|
714
|
-
Script.var_warning(var, @line, offset, @options[:filename])
|
715
|
-
end
|
716
714
|
|
715
|
+
var = var[1..-1]
|
717
716
|
parsed_list = parse_script(list_expr, :offset => line.offset + line.text.index(list_expr))
|
718
717
|
Tree::EachNode.new(var, parsed_list)
|
719
718
|
end
|
@@ -782,7 +781,6 @@ WARNING
|
|
782
781
|
offset = line.offset + line.text.size - arg_string.size
|
783
782
|
args = Script::Parser.new(arg_string.strip, @line, offset, @options).
|
784
783
|
parse_mixin_definition_arglist
|
785
|
-
default_arg_found = false
|
786
784
|
Tree::MixinDefNode.new(name, args)
|
787
785
|
end
|
788
786
|
|
@@ -799,6 +797,17 @@ WARNING
|
|
799
797
|
Tree::MixinNode.new(name, args, keywords)
|
800
798
|
end
|
801
799
|
|
800
|
+
FUNCTION_RE = /^@function\s*(#{Sass::SCSS::RX::IDENT})(.*)$/
|
801
|
+
def parse_function(line, root)
|
802
|
+
name, arg_string = line.text.scan(FUNCTION_RE).first
|
803
|
+
raise SyntaxError.new("Invalid function definition \"#{line.text}\".") if name.nil?
|
804
|
+
|
805
|
+
offset = line.offset + line.text.size - arg_string.size
|
806
|
+
args = Script::Parser.new(arg_string.strip, @line, offset, @options).
|
807
|
+
parse_function_definition_arglist
|
808
|
+
Tree::FunctionNode.new(name, args)
|
809
|
+
end
|
810
|
+
|
802
811
|
def parse_script(script, options = {})
|
803
812
|
line = options[:line] || @line
|
804
813
|
offset = options[:offset] || 0
|
@@ -2,7 +2,7 @@ require 'set'
|
|
2
2
|
|
3
3
|
module Sass
|
4
4
|
# The lexical environment for SassScript.
|
5
|
-
# This keeps track of variable and
|
5
|
+
# This keeps track of variable, mixin, and function definitions.
|
6
6
|
#
|
7
7
|
# A new environment is created for each level of Sass nesting.
|
8
8
|
# This allows variables to be lexically scoped.
|
@@ -146,7 +146,10 @@ RUBY
|
|
146
146
|
# Script::Literal
|
147
147
|
inherited_hash :var
|
148
148
|
# mixin
|
149
|
-
#
|
149
|
+
# Sass::Callable
|
150
150
|
inherited_hash :mixin
|
151
|
+
# function
|
152
|
+
# Sass::Callable
|
153
|
+
inherited_hash :function
|
151
154
|
end
|
152
155
|
end
|
@@ -176,12 +176,15 @@ MESSAGE
|
|
176
176
|
|
177
177
|
# The `sass` executable.
|
178
178
|
class Sass < Generic
|
179
|
+
attr_reader :default_syntax
|
180
|
+
|
179
181
|
# @param args [Array<String>] The command-line arguments
|
180
182
|
def initialize(args)
|
181
183
|
super
|
182
184
|
@options[:for_engine] = {
|
183
185
|
:load_paths => ['.'] + (ENV['SASSPATH'] || '').split(File::PATH_SEPARATOR)
|
184
186
|
}
|
187
|
+
@default_syntax = :sass
|
185
188
|
end
|
186
189
|
|
187
190
|
protected
|
@@ -193,7 +196,7 @@ MESSAGE
|
|
193
196
|
super
|
194
197
|
|
195
198
|
opts.banner = <<END
|
196
|
-
Usage:
|
199
|
+
Usage: #{default_syntax} [options] [INPUT] [OUTPUT]
|
197
200
|
|
198
201
|
Description:
|
199
202
|
Converts SCSS or Sass files to CSS.
|
@@ -201,14 +204,21 @@ Description:
|
|
201
204
|
Options:
|
202
205
|
END
|
203
206
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
+
if @default_syntax == :sass
|
208
|
+
opts.on('--scss',
|
209
|
+
'Use the CSS-superset SCSS syntax.') do
|
210
|
+
@options[:for_engine][:syntax] = :scss
|
211
|
+
end
|
212
|
+
else
|
213
|
+
opts.on('--sass',
|
214
|
+
'Use the Indented syntax.') do
|
215
|
+
@options[:for_engine][:syntax] = :sass
|
216
|
+
end
|
207
217
|
end
|
208
218
|
opts.on('--watch', 'Watch files or directories for changes.',
|
209
219
|
'The location of the generated CSS can be set using a colon:',
|
210
|
-
|
211
|
-
|
220
|
+
" #{@default_syntax} --watch input.#{@default_syntax}:output.css",
|
221
|
+
" #{@default_syntax} --watch input-dir:output-dir") do
|
212
222
|
@options[:watch] = true
|
213
223
|
end
|
214
224
|
opts.on('--update', 'Compile files or directories to CSS.',
|
@@ -231,12 +241,15 @@ END
|
|
231
241
|
opts.on('-q', '--quiet', 'Silence warnings and status messages during compilation.') do
|
232
242
|
@options[:for_engine][:quiet] = true
|
233
243
|
end
|
244
|
+
opts.on('--compass', 'Make Compass imports available and load project configuration.') do
|
245
|
+
@options[:compass] = true
|
246
|
+
end
|
234
247
|
opts.on('-g', '--debug-info',
|
235
248
|
'Emit extra information in the generated CSS that can be used by the FireSass Firebug plugin.') do
|
236
249
|
@options[:for_engine][:debug_info] = true
|
237
250
|
end
|
238
251
|
opts.on('-l', '--line-numbers', '--line-comments',
|
239
|
-
'Emit comments in the generated CSS indicating the corresponding
|
252
|
+
'Emit comments in the generated CSS indicating the corresponding source line.') do
|
240
253
|
@options[:for_engine][:line_numbers] = true
|
241
254
|
end
|
242
255
|
opts.on('-i', '--interactive',
|
@@ -276,7 +289,7 @@ END
|
|
276
289
|
@options[:update] = true
|
277
290
|
end
|
278
291
|
end
|
279
|
-
|
292
|
+
load_compass if @options[:compass]
|
280
293
|
return interactive if @options[:interactive]
|
281
294
|
return watch_or_update if @options[:watch] || @options[:update]
|
282
295
|
super
|
@@ -287,6 +300,7 @@ END
|
|
287
300
|
output = @options[:output]
|
288
301
|
|
289
302
|
@options[:for_engine][:syntax] ||= :scss if input.is_a?(File) && input.path =~ /\.scss$/
|
303
|
+
@options[:for_engine][:syntax] ||= @default_syntax
|
290
304
|
engine =
|
291
305
|
if input.is_a?(File) && !@options[:check_syntax]
|
292
306
|
::Sass::Engine.for_file(input.path, @options[:for_engine])
|
@@ -309,6 +323,23 @@ END
|
|
309
323
|
|
310
324
|
private
|
311
325
|
|
326
|
+
def load_compass
|
327
|
+
begin
|
328
|
+
require 'compass'
|
329
|
+
rescue LoadError
|
330
|
+
require 'rubygems'
|
331
|
+
begin
|
332
|
+
require 'compass'
|
333
|
+
rescue LoadError
|
334
|
+
puts "ERROR: Cannot load compass."
|
335
|
+
exit 1
|
336
|
+
end
|
337
|
+
end
|
338
|
+
Compass.add_project_configuration
|
339
|
+
Compass.configuration.project_path ||= Dir.pwd
|
340
|
+
@options[:for_engine][:load_paths] += Compass.configuration.sass_load_paths
|
341
|
+
end
|
342
|
+
|
312
343
|
def interactive
|
313
344
|
require 'sass/repl'
|
314
345
|
::Sass::Repl.new(@options).run
|
@@ -321,8 +352,8 @@ END
|
|
321
352
|
|
322
353
|
raise <<MSG if @args.empty?
|
323
354
|
What files should I watch? Did you mean something like:
|
324
|
-
|
325
|
-
|
355
|
+
#{@default_syntax} --watch input.#{@default_syntax}:output.css
|
356
|
+
#{@default_syntax} --watch input-dir:output-dir
|
326
357
|
MSG
|
327
358
|
|
328
359
|
if !colon_path?(@args[0]) && probably_dest_dir?(@args[1])
|
@@ -335,7 +366,7 @@ MSG
|
|
335
366
|
end
|
336
367
|
raise <<MSG if err
|
337
368
|
File #{@args[1]} #{err}.
|
338
|
-
Did you mean:
|
369
|
+
Did you mean: #{@default_syntax} #{flag} #{@args[0]}:#{@args[1]}
|
339
370
|
MSG
|
340
371
|
end
|
341
372
|
|
@@ -402,6 +433,14 @@ MSG
|
|
402
433
|
end
|
403
434
|
end
|
404
435
|
|
436
|
+
class Scss < Sass
|
437
|
+
# @param args [Array<String>] The command-line arguments
|
438
|
+
def initialize(args)
|
439
|
+
super
|
440
|
+
@default_syntax = :scss
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
405
444
|
# The `sass-convert` executable.
|
406
445
|
class SassConvert < Generic
|
407
446
|
# @param args [Array<String>] The command-line arguments
|
@@ -428,12 +467,11 @@ Options:
|
|
428
467
|
END
|
429
468
|
|
430
469
|
opts.on('-F', '--from FORMAT',
|
431
|
-
'The format to convert from. Can be css, scss, sass, less
|
432
|
-
'sass2 is the same as sass, but updates more old syntax to new.',
|
470
|
+
'The format to convert from. Can be css, scss, sass, less.',
|
433
471
|
'By default, this is inferred from the input filename.',
|
434
472
|
'If there is none, defaults to css.') do |name|
|
435
473
|
@options[:from] = name.downcase.to_sym
|
436
|
-
unless [:css, :scss, :sass, :less
|
474
|
+
unless [:css, :scss, :sass, :less].include?(@options[:from])
|
437
475
|
raise "Unknown format for sass-convert --from: #{name}"
|
438
476
|
end
|
439
477
|
try_less_note if @options[:from] == :less
|
@@ -517,14 +555,12 @@ END
|
|
517
555
|
@options[:output] ||= @options[:input]
|
518
556
|
|
519
557
|
from = @options[:from]
|
520
|
-
from = :sass if from == :sass2
|
521
558
|
if @options[:to] == @options[:from] && !@options[:in_place]
|
522
559
|
fmt = @options[:from]
|
523
560
|
raise "Error: converting from #{fmt} to #{fmt} without --in-place"
|
524
561
|
end
|
525
562
|
|
526
563
|
ext = @options[:from]
|
527
|
-
ext = :sass if ext == :sass2
|
528
564
|
Dir.glob("#{@options[:input]}/**/*.#{ext}") do |f|
|
529
565
|
output =
|
530
566
|
if @options[:in_place]
|
@@ -575,11 +611,6 @@ END
|
|
575
611
|
end
|
576
612
|
end
|
577
613
|
|
578
|
-
if @options[:from] == :sass2
|
579
|
-
@options[:from] = :sass
|
580
|
-
@options[:for_engine][:sass2] = true
|
581
|
-
end
|
582
|
-
|
583
614
|
@options[:from] ||= :css
|
584
615
|
@options[:to] ||= :sass
|
585
616
|
@options[:for_engine][:syntax] = @options[:from]
|