sass 3.1.0.alpha.221 → 3.1.0.alpha.246

Sign up to get free protection for your applications and to get access to all the features.
@@ -61,7 +61,6 @@ module Sass::Script
61
61
  value.map {|e| e.perform(environment)},
62
62
  separator)
63
63
  list.options = self.options
64
- list.context = self.context
65
64
  list
66
65
  end
67
66
 
@@ -8,18 +8,6 @@ module Sass::Script
8
8
  # @return [{Symbol => Object}]
9
9
  attr_reader :options
10
10
 
11
- # The context in which this node was parsed,
12
- # which determines how some operations are performed.
13
- #
14
- # Can be `:equals`, which means it's part of a `$var = val` or `prop = val` assignment,
15
- # or `:default`, which means it's anywhere else
16
- # (including `$var: val` and `prop: val` assignments,
17
- # `#{}`-interpolations,
18
- # and other script contexts such as `@if` conditions).
19
- #
20
- # @return [Symbol]
21
- attr_reader :context
22
-
23
11
  # The line of the document on which this node appeared.
24
12
  #
25
13
  # @return [Fixnum]
@@ -41,21 +29,6 @@ module Sass::Script
41
29
  end
42
30
  end
43
31
 
44
- # Sets the context for this node,
45
- # as well as for all child nodes.
46
- #
47
- # @param context [Symbol]
48
- # @see #context
49
- def context=(context)
50
- @context = context
51
- children.each {|c| c.context = context}
52
- end
53
-
54
- # Creates a new script node.
55
- def initialize
56
- @context = :default
57
- end
58
-
59
32
  # Evaluates the node.
60
33
  #
61
34
  # \{#perform} shouldn't be overridden directly;
@@ -149,7 +149,7 @@ module Sass::Script
149
149
  def div(other)
150
150
  if other.is_a? Number
151
151
  res = operate(other, :/)
152
- if self.original && other.original && context != :equals
152
+ if self.original && other.original
153
153
  res.original = "#{self.original}/#{other.original}"
154
154
  end
155
155
  res
@@ -66,11 +66,6 @@ module Sass::Script
66
66
  literal1 = @operand1.perform(environment)
67
67
  literal2 = @operand2.perform(environment)
68
68
 
69
- if @operator == :space && context == :equals
70
- literal1 = Sass::Script::String.new(literal1.value) if literal1.is_a?(Sass::Script::String)
71
- literal2 = Sass::Script::String.new(literal2.value) if literal2.is_a?(Sass::Script::String)
72
- end
73
-
74
69
  begin
75
70
  opts(literal1.send(@operator, literal2))
76
71
  rescue NoMethodError => e
@@ -316,15 +316,8 @@ RUBY
316
316
  offset = @lexer.offset + 1
317
317
  c = assert_tok(:const)
318
318
  var = Script::Variable.new(c.value)
319
- if tok = (try_tok(:colon) || try_tok(:single_eq))
319
+ if tok = try_tok(:colon)
320
320
  val = assert_expr(:space)
321
-
322
- if tok.type == :single_eq
323
- val.context = :equals
324
- val.options = @options
325
- Script.equals_warning("mixin argument defaults", "$#{c.value}",
326
- val.to_sass, false, line, offset, @options[:filename])
327
- end
328
321
  must_have_default = true
329
322
  elsif must_have_default
330
323
  raise SyntaxError.new("Required argument #{var.inspect} must come before any optional arguments.")
@@ -15,15 +15,6 @@ module Sass::Script
15
15
  # @return [Symbol] `:string` or `:identifier`
16
16
  attr_reader :type
17
17
 
18
- # In addition to setting the \{#context} of the string,
19
- # this sets the string to be an identifier if the context is `:equals`.
20
- #
21
- # @see Node#context=
22
- def context=(context)
23
- super
24
- @type = :identifier if context == :equals
25
- end
26
-
27
18
  # Creates a new string.
28
19
  #
29
20
  # @param value [String] See \{#value}
@@ -42,7 +33,7 @@ module Sass::Script
42
33
  # @see Node#to_s
43
34
  def to_s(opts = {})
44
35
  if @type == :identifier
45
- return @context == :equals && @value.empty? ? %q{""} : @value.tr("\n", " ")
36
+ return @value.tr("\n", " ")
46
37
  end
47
38
 
48
39
  return "\"#{value.gsub('"', "\\\"")}\"" if opts[:quote] == %q{"}
@@ -54,13 +45,7 @@ module Sass::Script
54
45
 
55
46
  # @see Node#to_sass
56
47
  def to_sass(opts = {})
57
- if self.type == :identifier && context == :equals &&
58
- self.value !~ Sass::SCSS::RX::URI &&
59
- Sass::SCSS::RX.escape_ident(self.value).include?(?\\)
60
- return "unquote(#{Sass::Script::String.new(self.value, :string).to_sass})"
61
- else
62
- return to_s
63
- end
48
+ to_s
64
49
  end
65
50
  end
66
51
  end
@@ -23,6 +23,7 @@ module Sass::Script
23
23
  # @see Node#to_sass
24
24
  def to_sass(opts = {})
25
25
  # We can get rid of all of this when we remove the deprecated :equals context
26
+ # XXX CE: It's gone now but I'm not sure what can be removed now.
26
27
  before_unquote, before_quote_char, before_str = parse_str(@before.to_sass(opts))
27
28
  after_unquote, after_quote_char, after_str = parse_str(@after.to_sass(opts))
28
29
  unquote = before_unquote || after_unquote ||
@@ -638,9 +638,11 @@ MESSAGE
638
638
  tok!(/:/)
639
639
  space, value = value!
640
640
  ss
641
+ important = tok(IMPORTANT)
642
+ ss
641
643
  require_block = tok?(/\{/)
642
644
 
643
- node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, :new))
645
+ node = node(Sass::Tree::PropNode.new(name.flatten.compact, value, !!important, :new))
644
646
 
645
647
  return node unless require_block
646
648
  nested_properties! node, space
@@ -68,6 +68,7 @@ module Sass
68
68
  URLCHAR = /[#%&*-~]|#{NONASCII}|#{ESCAPE}/
69
69
  URL = /(#{URLCHAR}*)/
70
70
  W = /[ \t\r\n\f]*/
71
+ VARIABLE = /(\$)(#{Sass::SCSS::RX::IDENT})/
71
72
 
72
73
  # This is more liberal than the spec's definition,
73
74
  # but that definition didn't work well with the greediness rules
@@ -118,7 +119,7 @@ module Sass
118
119
  # We could use it for 1.9 only, but I don't want to introduce a cross-version
119
120
  # behavior difference.
120
121
  # In any case, almost all CSS idents will be matched by this.
121
- STATIC_VALUE = /(-?#{NMSTART}|#{STRING_NOINTERP}|\s(?!%)|#[a-f0-9]|[,%]|#{NUM}|\!important)+(?=[;}])/i
122
+ STATIC_VALUE = /(-?#{NMSTART}|#{STRING_NOINTERP}|\s(?!%)|#[a-f0-9]|[,%]|#{NUM})+(?=[;}])/i
122
123
 
123
124
  STATIC_SELECTOR = /(#{NMCHAR}|\s|[,>+*]|[:#.]#{NMSTART})+(?=[{])/i
124
125
  end
@@ -8,7 +8,7 @@ module Sass
8
8
 
9
9
  def variable
10
10
  return [:raw, "!important"] if scan(Sass::SCSS::RX::IMPORTANT)
11
- _variable(/(\$)(#{Sass::SCSS::RX::IDENT})/)
11
+ _variable(Sass::SCSS::RX::VARIABLE)
12
12
  end
13
13
  end
14
14
  end
@@ -10,6 +10,14 @@ module Sass::Tree
10
10
  # @return [String]
11
11
  attr_accessor :value
12
12
 
13
+ # Whether the comment is loud.
14
+ #
15
+ # Loud comments start with ! and force the comment to be generated
16
+ # irrespective of compilation settings or the comment syntax used.
17
+ #
18
+ # @return [Boolean]
19
+ attr_accessor :loud
20
+
13
21
  # Whether or not the comment is silent (that is, doesn't output to CSS).
14
22
  #
15
23
  # @return [Boolean]
@@ -19,8 +27,10 @@ module Sass::Tree
19
27
  # @param silent [Boolean] See \{#silent}
20
28
  def initialize(value, silent)
21
29
  @lines = []
22
- @value = normalize_indentation value
23
30
  @silent = silent
31
+ @value = normalize_indentation value
32
+ @loud = @value =~ %r{^(/[\/\*])?!}
33
+ @value.sub!("#{$1}!", $1.to_s) if @loud
24
34
  super()
25
35
  end
26
36
 
@@ -36,9 +46,20 @@ module Sass::Tree
36
46
  # Returns `true` if this is a silent comment
37
47
  # or the current style doesn't render comments.
38
48
  #
49
+ # Comments starting with ! are never invisible (and the ! is removed from the output.)
50
+ #
39
51
  # @return [Boolean]
40
52
  def invisible?
41
- style == :compressed || @silent
53
+ if @loud
54
+ return false
55
+ else
56
+ @silent || (style == :compressed)
57
+ end
58
+ end
59
+
60
+ # Returns whether this comment should be interpolated for dynamic comment generation.
61
+ def evaluated?
62
+ @loud
42
63
  end
43
64
 
44
65
  private
@@ -19,13 +19,6 @@ module Sass::Tree
19
19
  # @return [{String => Script::Node}]
20
20
  attr_reader :keywords
21
21
 
22
- # @see Node#options=
23
- def options=(opts)
24
- super
25
- @args.each {|a| a.context = :equals} if opts[:sass2]
26
- @keywords.each {|k, v| v.context = :equals} if opts[:sass2]
27
- end
28
-
29
22
  # @param name [String] The name of the mixin
30
23
  # @param args [Array<Script::Node>] See \{#args}
31
24
  # @param keywords [{String => Script::Node}] See \{#keywords}
@@ -23,6 +23,11 @@ module Sass::Tree
23
23
  # @return [Sass::Script::Node]
24
24
  attr_accessor :value
25
25
 
26
+ # Whether the property was marked as !important.
27
+ #
28
+ # @return [Boolean]
29
+ attr_accessor :important
30
+
26
31
  # The value of the property
27
32
  # after any interpolated SassScript has been resolved.
28
33
  # Only set once \{Tree::Visitors::Perform} has been run.
@@ -44,14 +49,16 @@ module Sass::Tree
44
49
 
45
50
  # @param name [Array<String, Sass::Script::Node>] See \{#name}
46
51
  # @param value [Sass::Script::Node] See \{#value}
52
+ # @param important [Boolean] whether this is an !important property
47
53
  # @param prop_syntax [Symbol] `:new` if this property uses `a: b`-style syntax,
48
54
  # `:old` if it uses `:a b`-style syntax
49
- def initialize(name, value, prop_syntax)
55
+ def initialize(name, value, important, prop_syntax)
50
56
  @name = Sass::Util.strip_string_array(
51
57
  Sass::Util.merge_adjacent_strings(name))
52
58
  @value = value
53
59
  @tabs = 0
54
60
  @prop_syntax = prop_syntax
61
+ @important = important
55
62
  super()
56
63
  end
57
64
 
@@ -89,7 +96,7 @@ module Sass::Tree
89
96
  old = opts[:old] && fmt == :sass
90
97
  initial = old ? ':' : ''
91
98
  mid = old ? '' : ':'
92
- "#{initial}#{name}#{mid} #{self.class.val_to_sass(value, opts)}".rstrip
99
+ "#{initial}#{name}#{mid} #{self.class.val_to_sass(value, opts)}#{' !important' if important}".rstrip
93
100
  end
94
101
 
95
102
  private
@@ -136,7 +143,7 @@ module Sass::Tree
136
143
  unless node.is_a?(Sass::Script::Operation) && node.operator == :div &&
137
144
  node.operand1.is_a?(Sass::Script::Number) &&
138
145
  node.operand2.is_a?(Sass::Script::Number) &&
139
- (node.context == :equals || !node.operand1.original || !node.operand2.original)
146
+ (!node.operand1.original || !node.operand2.original)
140
147
  return node
141
148
  end
142
149
 
@@ -17,11 +17,11 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
17
17
  raise e
18
18
  end
19
19
 
20
+ PARENT_CLASSES = [ Sass::Tree::EachNode, Sass::Tree::ForNode, Sass::Tree::IfNode,
21
+ Sass::Tree::ImportNode, Sass::Tree::MixinNode, Sass::Tree::WhileNode]
20
22
  def visit_children(parent)
21
23
  old_parent = @parent
22
- @parent = parent unless is_any_of?(parent,
23
- Sass::Tree::EachNode, Sass::Tree::ForNode, Sass::Tree::IfNode,
24
- Sass::Tree::ImportNode, Sass::Tree::MixinNode, Sass::Tree::WhileNode)
24
+ @parent = parent unless is_any_of?(parent, PARENT_CLASSES)
25
25
  old_real_parent, @real_parent = @real_parent, parent
26
26
  super
27
27
  ensure
@@ -48,8 +48,9 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
48
48
  "@charset may only be used at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
49
49
  end
50
50
 
51
+ INVALID_EXTEND_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::MixinDefNode]
51
52
  def invalid_extend_parent?(parent, child)
52
- unless is_any_of?(parent, Sass::Tree::RuleNode, Sass::Tree::MixinDefNode)
53
+ unless is_any_of?(parent, INVALID_EXTEND_PARENTS)
53
54
  "Extend directives may only be used within rules."
54
55
  end
55
56
  end
@@ -58,18 +59,23 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
58
59
  "Functions may only be defined at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
59
60
  end
60
61
 
62
+ INVALID_FUNCTION_CHILDREN = [
63
+ Sass::Tree::CommentNode, Sass::Tree::DebugNode, Sass::Tree::EachNode,
64
+ Sass::Tree::ForNode, Sass::Tree::IfNode, Sass::Tree::ReturnNode,
65
+ Sass::Tree::VariableNode, Sass::Tree::WarnNode, Sass::Tree::WhileNode
66
+ ]
61
67
  def invalid_function_child?(parent, child)
62
- unless is_any_of?(child,
63
- Sass::Tree::CommentNode, Sass::Tree::DebugNode, Sass::Tree::EachNode,
64
- Sass::Tree::ForNode, Sass::Tree::IfNode, Sass::Tree::ReturnNode,
65
- Sass::Tree::VariableNode, Sass::Tree::WarnNode, Sass::Tree::WhileNode)
68
+ unless is_any_of?(child, INVALID_FUNCTION_CHILDREN)
66
69
  "Functions can only contain variable declarations and control directives."
67
70
  end
68
71
  end
69
72
 
73
+ INVALID_IMPORT_PARENTS = [
74
+ Sass::Tree::IfNode, Sass::Tree::ForNode, Sass::Tree::WhileNode,
75
+ Sass::Tree::EachNode, Sass::Tree::MixinDefNode
76
+ ]
70
77
  def invalid_import_parent?(parent, child)
71
- if is_any_of?(@real_parent, Sass::Tree::IfNode, Sass::Tree::ForNode, Sass::Tree::WhileNode,
72
- Sass::Tree::EachNode, Sass::Tree::MixinDefNode)
78
+ if is_any_of?(@real_parent, INVALID_IMPORT_PARENTS)
73
79
  return "Import directives may not be used within control directives or mixins."
74
80
  end
75
81
  return if parent.is_a?(Sass::Tree::RootNode)
@@ -92,16 +98,17 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
92
98
  "Mixins may only be defined at the root of a document." unless parent.is_a?(Sass::Tree::RootNode)
93
99
  end
94
100
 
101
+ INVALID_PROP_CHILDREN = [Sass::Tree::CommentNode, Sass::Tree::PropNode]
95
102
  def invalid_prop_child?(parent, child)
96
- unless is_any_of?(child, Sass::Tree::CommentNode, Sass::Tree::PropNode)
103
+ unless is_any_of?(child, INVALID_PROP_CHILDREN)
97
104
  "Illegal nesting: Only properties may be nested beneath properties."
98
105
  end
99
106
  end
100
107
 
108
+ INVALID_PROP_PARENTS = [Sass::Tree::RuleNode, Sass::Tree::PropNode,
109
+ Sass::Tree::MixinDefNode, Sass::Tree::DirectiveNode]
101
110
  def invalid_prop_parent?(parent, child)
102
- unless is_any_of?(parent,
103
- Sass::Tree::RuleNode, Sass::Tree::PropNode,
104
- Sass::Tree::MixinDefNode, Sass::Tree::DirectiveNode)
111
+ unless is_any_of?(parent, INVALID_PROP_PARENTS)
105
112
  "Properties are only allowed within rules, directives, or other properties." + child.pseudo_class_selector_message
106
113
  end
107
114
  end
@@ -112,8 +119,11 @@ class Sass::Tree::Visitors::CheckNesting < Sass::Tree::Visitors::Base
112
119
 
113
120
  private
114
121
 
115
- def is_any_of?(val, *classes)
116
- classes.any? {|c| val.is_a?(c)}
122
+ def is_any_of?(val, classes)
123
+ for c in classes
124
+ return true if val.is_a?(c)
125
+ end
126
+ return false
117
127
  end
118
128
 
119
129
  def try_send(method, *args, &block)
@@ -49,7 +49,7 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
49
49
  end
50
50
 
51
51
  def visit_comment(node)
52
- if @format == :sass
52
+ content = if @format == :sass
53
53
  content = node.value.gsub(/\*\/$/, '').rstrip
54
54
  if content =~ /\A[ \t]/
55
55
  # Re-indent SCSS comments like this:
@@ -79,12 +79,21 @@ class Sass::Tree::Visitors::Convert < Sass::Tree::Visitors::Base
79
79
  content.rstrip + "\n"
80
80
  else
81
81
  spaces = (' ' * [@tabs - node.value[/^ */].size, 0].max)
82
- if node.silent
82
+ content = if node.silent
83
83
  node.value.gsub(/^[\/ ]\*/, '//').gsub(/ *\*\/$/, '')
84
84
  else
85
85
  node.value
86
86
  end.gsub(/^/, spaces) + "\n"
87
+ content
88
+ end
89
+ if node.loud
90
+ if node.silent
91
+ content.gsub!(%r{^\s*(//!?)}, '//!')
92
+ else
93
+ content.sub!(%r{^\s*(/\*)}, '/*!')
94
+ end
87
95
  end
96
+ content
88
97
  end
89
98
 
90
99
  def visit_debug(node)
@@ -52,7 +52,14 @@ class Sass::Tree::Visitors::Perform < Sass::Tree::Visitors::Base
52
52
 
53
53
  # Removes this node from the tree if it's a silent comment.
54
54
  def visit_comment(node)
55
- node.silent ? [] : node
55
+ return [] if node.invisible?
56
+ if node.evaluated?
57
+ node.value.gsub!(/(^|[^\\])\#\{([^}]*)\}/) do |md|
58
+ $1+Sass::Script.parse($2, node.line, 0, node.options).perform(@environment).to_s
59
+ end
60
+ node.value = run_interp([Sass::Script::String.new(node.value)])
61
+ end
62
+ node
56
63
  end
57
64
 
58
65
  # Prints the expression to STDERR.
@@ -184,11 +191,7 @@ END
184
191
  elsif kv = passed_keywords[var.underscored_name]
185
192
  kv.perform(env)
186
193
  elsif default
187
- val = default.perform(env)
188
- if default.context == :equals && val.is_a?(Sass::Script::String)
189
- val = Sass::Script::String.new(val.value)
190
- end
191
- val
194
+ default.perform(env)
192
195
  end)
193
196
  raise Sass::SyntaxError.new("Mixin #{node.name} is missing parameter #{var.inspect}.") unless env.var(var.name)
194
197
  env
@@ -210,12 +213,7 @@ END
210
213
  def visit_prop(node)
211
214
  node.resolved_name = run_interp(node.name)
212
215
  val = node.value.perform(@environment)
213
- node.resolved_value =
214
- if node.value.context == :equals && val.is_a?(Sass::Script::String)
215
- val.value
216
- else
217
- val.to_s
218
- end
216
+ node.resolved_value = val.to_s
219
217
  yield
220
218
  end
221
219
 
@@ -236,7 +234,6 @@ END
236
234
  def visit_variable(node)
237
235
  return [] if node.guarded && !@environment.var(node.name).nil?
238
236
  val = node.expr.perform(@environment)
239
- val = Sass::Script::String.new(val.value) if node.expr.context == :equals && val.is_a?(Sass::Script::String)
240
237
  @environment.set_var(node.name, val)
241
238
  []
242
239
  end