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

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.
@@ -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