sass 3.1.0.alpha.48 → 3.1.0.alpha.49

Sign up to get free protection for your applications and to get access to all the features.
@@ -13,7 +13,7 @@ module Sass::Tree
13
13
 
14
14
  # The name of the property
15
15
  # after any interpolated SassScript has been resolved.
16
- # Only set once \{Tree::Node#perform} has been called.
16
+ # Only set once \{Tree::Visitors::Perform} has been run.
17
17
  #
18
18
  # @return [String]
19
19
  attr_accessor :resolved_name
@@ -25,7 +25,7 @@ module Sass::Tree
25
25
 
26
26
  # The value of the property
27
27
  # after any interpolated SassScript has been resolved.
28
- # Only set once \{Tree::Node#perform} has been called.
28
+ # Only set once \{Tree::Visitors::Perform} has been run.
29
29
  #
30
30
  # @return [String]
31
31
  attr_accessor :resolved_value
@@ -74,73 +74,22 @@ module Sass::Tree
74
74
  "\nIf #{declaration.dump} should be a selector, use \"\\#{declaration}\" instead."
75
75
  end
76
76
 
77
- protected
78
-
79
- # @see Node#to_src
80
- def to_src(tabs, opts, fmt)
81
- res = declaration(tabs, opts, fmt)
82
- return res + "#{semi fmt}\n" if children.empty?
83
- res + children_to_src(tabs, opts, fmt).rstrip + semi(fmt) + "\n"
84
- end
85
-
86
- # Computes the CSS for the property.
87
- #
88
- # @param tabs [Fixnum] The level of indentation for the CSS
89
- # @return [String] The resulting CSS
90
- def _to_s(tabs)
91
- tab_str = ' ' * (tabs - 1 + self.tabs)
92
- if style == :compressed
93
- "#{tab_str}#{resolved_name}:#{resolved_value}"
94
- else
95
- "#{tab_str}#{resolved_name}: #{resolved_value};"
96
- end
97
- end
98
-
99
- # Converts nested properties into flat properties.
77
+ # Computes the Sass or SCSS code for the variable declaration.
78
+ # This is like \{#to\_scss} or \{#to\_sass},
79
+ # except it doesn't print any child properties or a trailing semicolon.
100
80
  #
101
- # @param extends [Sass::Util::SubsetMap{Selector::Simple => Selector::Sequence}]
102
- # The extensions defined for this tree
103
- # @param parent [PropNode, nil] The parent node of this node,
104
- # or nil if the parent isn't a {PropNode}
105
- # @raise [Sass::SyntaxError] if the property uses invalid syntax
106
- def _cssize(extends, parent)
107
- node = super
108
- result = node.children.dup
109
- if !node.resolved_value.empty? || node.children.empty?
110
- node.send(:check!)
111
- result.unshift(node)
81
+ # @param opts [{Symbol => Object}] The options hash for the tree.
82
+ # @param fmt [Symbol] `:scss` or `:sass`.
83
+ def declaration(opts = {:old => @prop_syntax == :old}, fmt = :sass)
84
+ name = self.name.map {|n| n.is_a?(String) ? n : "\#{#{n.to_sass(opts)}}"}.join
85
+ if name[0] == ?:
86
+ raise Sass::SyntaxError.new("The \"#{name}: #{self.class.val_to_sass(value, opts)}\" hack is not allowed in the Sass indented syntax")
112
87
  end
113
- result
114
- end
115
88
 
116
- # Updates the name and indentation of this node based on the parent name
117
- # and nesting level.
118
- #
119
- # @param extends [Sass::Util::SubsetMap{Selector::Simple => Selector::Sequence}]
120
- # The extensions defined for this tree
121
- # @param parent [PropNode, nil] The parent node of this node,
122
- # or nil if the parent isn't a {PropNode}
123
- def cssize!(extends, parent)
124
- self.resolved_name = "#{parent.resolved_name}-#{resolved_name}" if parent
125
- self.tabs = parent.tabs + (parent.resolved_value.empty? ? 0 : 1) if parent && style == :nested
126
- super
127
- end
128
-
129
- # Runs any SassScript that may be embedded in the property,
130
- # and invludes the parent property, if any.
131
- #
132
- # @param environment [Sass::Environment] The lexical environment containing
133
- # variable and mixin values
134
- def perform!(environment)
135
- @resolved_name = run_interp(@name, environment)
136
- val = @value.perform(environment)
137
- @resolved_value =
138
- if @value.context == :equals && val.is_a?(Sass::Script::String)
139
- val.value
140
- else
141
- val.to_s
142
- end
143
- super
89
+ old = opts[:old] && fmt == :sass
90
+ initial = old ? ':' : ''
91
+ mid = old ? '' : ':'
92
+ "#{initial}#{name}#{mid} #{self.class.val_to_sass(value, opts)}".rstrip
144
93
  end
145
94
 
146
95
  # Returns an error message if the given child node is invalid,
@@ -167,18 +116,6 @@ module Sass::Tree
167
116
  end
168
117
  end
169
118
 
170
- def declaration(tabs = 0, opts = {:old => @prop_syntax == :old}, fmt = :sass)
171
- name = self.name.map {|n| n.is_a?(String) ? n : "\#{#{n.to_sass(opts)}}"}.join
172
- if name[0] == ?:
173
- raise Sass::SyntaxError.new("The \"#{name}: #{self.class.val_to_sass(value, opts)}\" hack is not allowed in the Sass indented syntax")
174
- end
175
-
176
- old = opts[:old] && fmt == :sass
177
- initial = old ? ':' : ''
178
- mid = old ? '' : ':'
179
- "#{' ' * tabs}#{initial}#{name}#{mid} #{self.class.val_to_sass(value, opts)}".rstrip
180
- end
181
-
182
119
  class << self
183
120
  # @private
184
121
  def val_to_sass(value, opts)
@@ -13,134 +13,14 @@ module Sass
13
13
  @template = template
14
14
  end
15
15
 
16
- # @see Node#to_s
17
- def to_s(*args)
18
- super
19
- rescue Sass::SyntaxError => e
20
- e.sass_template ||= @template
21
- raise e
22
- end
23
-
24
16
  # Runs the dynamic Sass code *and* computes the CSS for the tree.
25
- #
26
- # @see #perform
27
17
  # @see #to_s
28
18
  def render
29
- result, extends = perform(Environment.new).cssize
19
+ result, extends = Visitors::Cssize.visit(Visitors::Perform.visit(self))
30
20
  result = result.do_extend(extends) unless extends.empty?
31
21
  result.to_s
32
22
  end
33
23
 
34
- # @see Node#perform
35
- def perform(environment)
36
- environment.options = @options if environment.options.nil? || environment.options.empty?
37
- super
38
- rescue Sass::SyntaxError => e
39
- e.sass_template ||= @template
40
- raise e
41
- end
42
-
43
- # Like {Node#cssize}, except that this method
44
- # will create its own `extends` map if necessary,
45
- # and it returns that map along with the cssized tree.
46
- #
47
- # @return [(Tree::Node, Sass::Util::SubsetMap)] The resulting tree of static nodes
48
- # *and* the extensions defined for this tree
49
- def cssize(extends = Sass::Util::SubsetMap.new, parent = nil)
50
- return super(extends, parent), extends
51
- rescue Sass::SyntaxError => e
52
- e.sass_template ||= @template
53
- raise e
54
- end
55
-
56
- # @see \{Node#perform!}
57
- def perform!(environment)
58
- environment.options = @options if environment.options.nil? || environment.options.empty?
59
- super
60
- end
61
-
62
- # Converts a node to Sass code that will generate it.
63
- #
64
- # @param opts [{Symbol => Object}] An options hash (see {Sass::CSS#initialize})
65
- # @return [String] The Sass code corresponding to the node
66
- def to_sass(opts = {})
67
- to_src(opts, :sass)
68
- end
69
-
70
- # Converts a node to SCSS code that will generate it.
71
- #
72
- # @param opts [{Symbol => Object}] An options hash (see {Sass::CSS#initialize})
73
- # @return [String] The SCSS code corresponding to the node
74
- def to_scss(opts = {})
75
- to_src(opts, :scss)
76
- end
77
-
78
- protected
79
-
80
- # @see Node#to_src
81
- def to_src(opts, fmt)
82
- Sass::Util.enum_cons(children + [nil], 2).map do |child, nxt|
83
- child.send("to_#{fmt}", 0, opts) +
84
- if nxt &&
85
- (child.is_a?(CommentNode) && child.line + child.value.count("\n") + 1 == nxt.line) ||
86
- (child.is_a?(ImportNode) && nxt.is_a?(ImportNode) && child.line + 1 == nxt.line) ||
87
- (child.is_a?(VariableNode) && nxt.is_a?(VariableNode) && child.line + 1 == nxt.line)
88
- ""
89
- else
90
- "\n"
91
- end
92
- end.join.rstrip + "\n"
93
- end
94
-
95
- # Computes the CSS corresponding to this Sass tree.
96
- #
97
- # @param args [Array] ignored
98
- # @return [String] The resulting CSS
99
- # @see Sass::Tree
100
- def _to_s(*args)
101
- result = String.new
102
- children.each do |child|
103
- next if child.invisible?
104
- child_str = child.to_s(1)
105
- result << child_str + (style == :compressed ? '' : "\n")
106
- end
107
- result.rstrip!
108
- return "" if result.empty?
109
- result << "\n"
110
- unless Sass::Util.ruby1_8? || result.ascii_only?
111
- if children.first.is_a?(CharsetNode)
112
- begin
113
- encoding = children.first.name
114
- # Default to big-endian encoding, because we have to decide somehow
115
- encoding << 'BE' if encoding =~ /\Autf-(16|32)\Z/i
116
- result = result.encode(Encoding.find(encoding))
117
- rescue EncodingError
118
- end
119
- end
120
-
121
- result = "@charset \"#{result.encoding.name}\";#{
122
- style == :compressed ? '' : "\n"
123
- }".encode(result.encoding) + result
124
- end
125
- result
126
- end
127
-
128
- # In Ruby 1.8, ensures that there's only one @charset directive
129
- # and that it's at the top of the document.
130
- #
131
- # @see Node#cssize
132
- def cssize!(extends, parent)
133
- super
134
-
135
- # In Ruby 1.9 we can make all @charset nodes invisible
136
- # and infer the final @charset from the encoding of the final string.
137
- if Sass::Util.ruby1_8? && parent.nil?
138
- charset = self.children.find {|c| c.is_a?(CharsetNode)}
139
- self.children.reject! {|c| c.is_a?(CharsetNode)}
140
- self.children.unshift charset if charset
141
- end
142
- end
143
-
144
24
  # Returns an error message if the given child node is invalid,
145
25
  # and false otherwise.
146
26
  #
@@ -27,7 +27,7 @@ module Sass::Tree
27
27
 
28
28
  # The CSS selector for this rule,
29
29
  # without any unresolved interpolation or parent references.
30
- # It's only set once {Tree::Node#cssize} has been called.
30
+ # It's only set once {Tree::Visitors::Cssize} has been run.
31
31
  #
32
32
  # @return [Selector::CommaSequence]
33
33
  attr_accessor :resolved_rules
@@ -82,26 +82,6 @@ module Sass::Tree
82
82
  last.is_a?(String) && last[-1] == ?,
83
83
  end
84
84
 
85
- # @see Node#to_sass
86
- def to_sass(tabs, opts = {})
87
- name = selector_to_sass(rule, opts)
88
- name = "\\" + name if name[0] == ?:
89
- name.gsub(/^/, ' ' * tabs) + children_to_src(tabs, opts, :sass)
90
- end
91
-
92
- # @see Node#to_scss
93
- def to_scss(tabs, opts = {})
94
- name = selector_to_scss(rule, tabs, opts)
95
- res = name + children_to_src(tabs, opts, :scss)
96
-
97
- if children.last.is_a?(CommentNode) && children.last.silent
98
- res.slice!(-3..-1)
99
- res << "\n" << (' ' * tabs) << "}\n"
100
- end
101
-
102
- res
103
- end
104
-
105
85
  # Extends this Rule's selector with the given `extends`.
106
86
  #
107
87
  # @see Node#do_extend
@@ -111,120 +91,6 @@ module Sass::Tree
111
91
  node
112
92
  end
113
93
 
114
- protected
115
-
116
- # Computes the CSS for the rule.
117
- #
118
- # @param tabs [Fixnum] The level of indentation for the CSS
119
- # @return [String] The resulting CSS
120
- def _to_s(tabs)
121
- output_style = style
122
- tabs = tabs + self.tabs
123
-
124
- rule_separator = output_style == :compressed ? ',' : ', '
125
- line_separator =
126
- case output_style
127
- when :nested, :expanded; "\n"
128
- when :compressed; ""
129
- else; " "
130
- end
131
- rule_indent = ' ' * (tabs - 1)
132
- per_rule_indent, total_indent = [:nested, :expanded].include?(output_style) ? [rule_indent, ''] : ['', rule_indent]
133
-
134
- total_rule = total_indent + resolved_rules.members.
135
- map {|seq| seq.to_a.join.gsub(/([^,])\n/m, style == :compressed ? '\1 ' : "\\1\n")}.
136
- join(rule_separator).split("\n").map do |line|
137
- per_rule_indent + line.strip
138
- end.join(line_separator)
139
-
140
- to_return = ''
141
- old_spaces = ' ' * (tabs - 1)
142
- spaces = ' ' * tabs
143
- if output_style != :compressed
144
- if @options[:debug_info]
145
- to_return << debug_info_rule.to_s(tabs) << "\n"
146
- elsif @options[:line_comments]
147
- to_return << "#{old_spaces}/* line #{line}"
148
-
149
- if filename
150
- relative_filename = if @options[:css_filename]
151
- begin
152
- Pathname.new(filename).relative_path_from(
153
- Pathname.new(File.dirname(@options[:css_filename]))).to_s
154
- rescue ArgumentError
155
- nil
156
- end
157
- end
158
- relative_filename ||= filename
159
- to_return << ", #{relative_filename}"
160
- end
161
-
162
- to_return << " */\n"
163
- end
164
- end
165
-
166
- if output_style == :compact
167
- properties = children.map { |a| a.to_s(1) }.join(' ')
168
- to_return << "#{total_rule} { #{properties} }#{"\n" if group_end}"
169
- elsif output_style == :compressed
170
- properties = children.map { |a| a.to_s(1) }.join(';')
171
- to_return << "#{total_rule}{#{properties}}"
172
- else
173
- properties = children.map { |a| a.to_s(tabs + 1) }.join("\n")
174
- end_props = (output_style == :expanded ? "\n" + old_spaces : ' ')
175
- to_return << "#{total_rule} {\n#{properties}#{end_props}}#{"\n" if group_end}"
176
- end
177
-
178
- to_return
179
- end
180
-
181
- # Runs SassScript interpolation in the selector,
182
- # and then parses the result into a {Sass::Selector::CommaSequence}.
183
- #
184
- # @param environment [Sass::Environment] The lexical environment containing
185
- # variable and mixin values
186
- def perform!(environment)
187
- @parsed_rules = Sass::SCSS::StaticParser.new(run_interp(@rule, environment), self.line).
188
- parse_selector(self.filename)
189
- super
190
- end
191
-
192
- # Converts nested rules into a flat list of rules.
193
- #
194
- # @param extends [Sass::Util::SubsetMap{Selector::Simple => Selector::Sequence}]
195
- # The extensions defined for this tree
196
- # @param parent [RuleNode, nil] The parent node of this node,
197
- # or nil if the parent isn't a {RuleNode}
198
- def _cssize(extends, parent)
199
- node = super
200
- rules = node.children.select {|c| c.is_a?(RuleNode) || c.is_a?(MediaNode)}
201
- props = node.children.reject {|c| c.is_a?(RuleNode) || c.is_a?(MediaNode) || c.invisible?}
202
-
203
- unless props.empty?
204
- node.children = props
205
- rules.each {|r| r.tabs += 1} if style == :nested
206
- rules.unshift(node)
207
- end
208
-
209
- rules.last.group_end = true unless parent || rules.empty?
210
-
211
- rules
212
- end
213
-
214
- # Resolves parent references and nested selectors,
215
- # and updates the indentation based on the parent's indentation.
216
- #
217
- # @param extends [Sass::Util::SubsetMap{Selector::Simple => Selector::Sequence}]
218
- # The extensions defined for this tree
219
- # @param parent [RuleNode, nil] The parent node of this node,
220
- # or nil if the parent isn't a {RuleNode}
221
- # @raise [Sass::SyntaxError] if the rule has no parents but uses `&`
222
- def cssize!(extends, parent)
223
- # It's possible for resolved_rules to be set if we've duplicated this node during @media bubbling
224
- self.resolved_rules ||= @parsed_rules.resolve_parent_refs(parent && parent.resolved_rules)
225
- super
226
- end
227
-
228
94
  # A hash that will be associated with this rule in the CSS document
229
95
  # if the {file:SASS_REFERENCE.md#debug_info-option `:debug_info` option} is enabled.
230
96
  # This data is used by e.g. [the FireSass Firebug extension](https://addons.mozilla.org/en-US/firefox/addon/103988).
@@ -234,27 +100,5 @@ module Sass::Tree
234
100
  {:filename => filename && ("file://" + URI.escape(File.expand_path(filename))),
235
101
  :line => self.line}
236
102
  end
237
-
238
- private
239
-
240
- def debug_info_rule
241
- node = DirectiveNode.new("@media -sass-debug-info")
242
- debug_info.map {|k, v| [k.to_s, v.to_s]}.sort.each do |k, v|
243
- rule = RuleNode.new([""])
244
- rule.resolved_rules = Sass::Selector::CommaSequence.new(
245
- [Sass::Selector::Sequence.new(
246
- [Sass::Selector::SimpleSequence.new(
247
- [Sass::Selector::Element.new(k.to_s.gsub(/[^\w-]/, "\\\\\\0"), nil)])
248
- ])
249
- ])
250
- prop = PropNode.new([""], "", :new)
251
- prop.resolved_name = "font-family"
252
- prop.resolved_value = Sass::SCSS::RX.escape_ident(v.to_s)
253
- rule << prop
254
- node << rule
255
- end
256
- node.options = @options.merge(:debug_info => false, :line_comments => false, :style => :compressed)
257
- node
258
- end
259
103
  end
260
104
  end
@@ -4,36 +4,27 @@ module Sass
4
4
  #
5
5
  # @see Sass::Tree
6
6
  class VariableNode < Node
7
+ # The name of the variable.
8
+ # @return [String]
9
+ attr_reader :name
10
+
11
+ # The parse tree for the variable value.
12
+ # @return [Script::Node]
13
+ attr_reader :expr
14
+
15
+ # Whether this is a guarded variable assignment (`!default`).
16
+ # @return [Boolean]
17
+ attr_reader :guarded
18
+
7
19
  # @param name [String] The name of the variable
8
- # @param expr [Script::Node] The parse tree for the initial variable value
9
- # @param guarded [Boolean] Whether this is a guarded variable assignment (`||=`)
20
+ # @param expr [Script::Node] See \{#expr}
21
+ # @param guarded [Boolean] See \{#guarded}
10
22
  def initialize(name, expr, guarded)
11
23
  @name = name
12
24
  @expr = expr
13
25
  @guarded = guarded
14
26
  super()
15
27
  end
16
-
17
- protected
18
-
19
- # @see Node#to_src
20
- def to_src(tabs, opts, fmt)
21
- "#{' ' * tabs}$#{dasherize(@name, opts)}: #{@expr.to_sass(opts)}#{' !default' if @guarded}#{semi fmt}\n"
22
- end
23
-
24
- # Loads the new variable value into the environment.
25
- #
26
- # @param environment [Sass::Environment] The lexical environment containing
27
- # variable and mixin values
28
- def _perform(environment)
29
- return [] if @guarded && !environment.var(@name).nil?
30
- val = @expr.perform(environment)
31
- if @expr.context == :equals && val.is_a?(Sass::Script::String)
32
- val = Sass::Script::String.new(val.value)
33
- end
34
- environment.set_var(@name, val)
35
- []
36
- end
37
28
  end
38
29
  end
39
30
  end