Class: Sass::Tree::Visitors::Convert

Inherits:
Base
  • Object
show all
Defined in:
lib/sass/tree/visitors/convert.rb

Overview

A visitor for converting a Sass tree into a source string.

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

node_name, #visit

Constructor Details

#initialize(options, format) ⇒ Convert (protected)

Returns a new instance of Convert.



15
16
17
18
19
20
21
22
# File 'lib/sass/tree/visitors/convert.rb', line 15

def initialize(options, format)
  @options = options
  @format = format
  @tabs = 0
  # 2 spaces by default
  @tab_chars = @options[:indent] || "  "
  @is_else = false
end

Class Method Details

.visit(root, options, format) ⇒ String

Runs the visitor on a tree.

Parameters:

  • root (Tree::Node)

    The root node of the Sass tree.

  • options ({Symbol => Object})

    An options hash (see CSS#initialize).

  • format (Symbol)

    :sass or :scss.

Returns:

  • (String)

    The Sass or SCSS source for the tree.



9
10
11
# File 'lib/sass/tree/visitors/convert.rb', line 9

def self.visit(root, options, format)
  new(options, format).send(:visit, root)
end

Instance Method Details

#visit_atroot(node) (protected)



263
264
265
266
267
268
269
270
271
272
# File 'lib/sass/tree/visitors/convert.rb', line 263

def visit_atroot(node)
  if node.query
    "#{tab_str}@at-root #{query_interp_to_src(node.query)}#{yield}"
  elsif node.children.length == 1 && node.children.first.is_a?(Sass::Tree::RuleNode)
    rule = node.children.first
    "#{tab_str}@at-root #{selector_to_src(rule.rule).lstrip}#{visit_children(rule)}"
  else
    "#{tab_str}@at-root#{yield}"
  end
end

#visit_charset(node) (protected)



44
45
46
# File 'lib/sass/tree/visitors/convert.rb', line 44

def visit_charset(node)
  "#{tab_str}@charset \"#{node.name}\"#{semi}\n"
end

#visit_children(parent) (protected)



24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/sass/tree/visitors/convert.rb', line 24

def visit_children(parent)
  @tabs += 1
  return @format == :sass ? "\n" : " {}\n" if parent.children.empty?

  res = visit_rule_level(parent.children)

  if @format == :sass
    "\n" + res.rstrip + "\n"
  else
    " {\n" + res.rstrip + "\n#{@tab_chars * (@tabs - 1)}}\n"
  end
ensure
  @tabs -= 1
end

#visit_comment(node) (protected)



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/sass/tree/visitors/convert.rb', line 48

def visit_comment(node)
  value = interp_to_src(node.value)
  if @format == :sass
    content = value.gsub(%r{\*/$}, '').rstrip
    if content =~ /\A[ \t]/
      # Re-indent SCSS comments like this:
      #     /* foo
      #   bar
      #       baz */
      content.gsub!(/^/, '   ')
      content.sub!(%r{\A([ \t]*)/\*}, '/*\1')
    end

    if content.include?("\n")
      content.gsub!(/\n \*/, "\n  ")
      spaces = content.scan(/\n( *)/).map {|s| s.first.size}.min
      sep = node.type == :silent ? "\n//" : "\n *"
      if spaces >= 2
        content.gsub!(/\n  /, sep)
      else
        content.gsub!(/\n#{' ' * spaces}/, sep)
      end
    end

    content.gsub!(%r{\A/\*}, '//') if node.type == :silent
    content.gsub!(/^/, tab_str)
    content = content.rstrip + "\n"
  else
    spaces = (@tab_chars * [@tabs - value[/^ */].size, 0].max)
    content = if node.type == :silent
                value.gsub(%r{^[/ ]\*}, '//').gsub(%r{ *\*/$}, '')
              else
                value
              end.gsub(/^/, spaces) + "\n"
  end
  content
end

#visit_content(node) (protected)



219
220
221
# File 'lib/sass/tree/visitors/convert.rb', line 219

def visit_content(node)
  "#{tab_str}@content#{semi}\n"
end

#visit_cssimport(node) (protected)



161
162
163
164
165
166
167
168
169
170
# File 'lib/sass/tree/visitors/convert.rb', line 161

def visit_cssimport(node)
  if node.uri.is_a?(Sass::Script::Tree::Node)
    str = "#{tab_str}@import #{node.uri.to_sass(@options)}"
  else
    str = "#{tab_str}@import #{node.uri}"
  end
  str << " supports(#{node.supports_condition.to_src(@options)})" if node.supports_condition
  str << " #{interp_to_src(node.query)}" unless node.query.empty?
  "#{str}#{semi}\n"
end

#visit_debug(node) (protected)



86
87
88
# File 'lib/sass/tree/visitors/convert.rb', line 86

def visit_debug(node)
  "#{tab_str}@debug #{node.expr.to_sass(@options)}#{semi}\n"
end

#visit_directive(node) (protected)



94
95
96
97
98
99
# File 'lib/sass/tree/visitors/convert.rb', line 94

def visit_directive(node)
  res = "#{tab_str}#{interp_to_src(node.value)}"
  res.gsub!(/^@import \#\{(.*)\}([^}]*)$/, '@import \1\2')
  return res + "#{semi}\n" unless node.has_children
  res + yield
end

#visit_each(node) (protected)



101
102
103
104
# File 'lib/sass/tree/visitors/convert.rb', line 101

def visit_each(node)
  vars = node.vars.map {|var| "$#{dasherize(var)}"}.join(", ")
  "#{tab_str}@each #{vars} in #{node.list.to_sass(@options)}#{yield}"
end

#visit_error(node) (protected)



90
91
92
# File 'lib/sass/tree/visitors/convert.rb', line 90

def visit_error(node)
  "#{tab_str}@error #{node.expr.to_sass(@options)}#{semi}\n"
end

#visit_extend(node) (protected)



106
107
108
109
# File 'lib/sass/tree/visitors/convert.rb', line 106

def visit_extend(node)
  "#{tab_str}@extend #{selector_to_src(node.selector).lstrip}" +
    "#{' !optional' if node.optional?}#{semi}\n"
end

#visit_for(node) (protected)



111
112
113
114
# File 'lib/sass/tree/visitors/convert.rb', line 111

def visit_for(node)
  "#{tab_str}@for $#{dasherize(node.var)} from #{node.from.to_sass(@options)} " +
    "#{node.exclusive ? 'to' : 'through'} #{node.to.to_sass(@options)}#{yield}"
end

#visit_function(node) (protected)



116
117
118
119
120
121
122
123
124
125
126
# File 'lib/sass/tree/visitors/convert.rb', line 116

def visit_function(node)
  args = node.args.map do |v, d|
    d ? "#{v.to_sass(@options)}: #{d.to_sass(@options)}" : v.to_sass(@options)
  end.join(", ")
  if node.splat
    args << ", " unless node.args.empty?
    args << node.splat.to_sass(@options) << "..."
  end

  "#{tab_str}@function #{dasherize(node.name)}(#{args})#{yield}"
end

#visit_if(node) (protected)



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/sass/tree/visitors/convert.rb', line 128

def visit_if(node)
  name =
    if !@is_else
      "if"
    elsif node.expr
      "else if"
    else
      "else"
    end
  @is_else = false
  str = "#{tab_str}@#{name}"
  str << " #{node.expr.to_sass(@options)}" if node.expr
  str << yield
  @is_else = true
  str << visit(node.else) if node.else
  str
ensure
  @is_else = false
end

#visit_import(node) (protected)



148
149
150
151
# File 'lib/sass/tree/visitors/convert.rb', line 148

def visit_import(node)
  quote = @format == :scss ? '"' : ''
  "#{tab_str}@import #{quote}#{node.imported_filename}#{quote}#{semi}\n"
end

#visit_keyframerule(node) (protected)



274
275
276
# File 'lib/sass/tree/visitors/convert.rb', line 274

def visit_keyframerule(node)
  "#{tab_str}#{node.resolved_value}#{yield}"
end

#visit_media(node) (protected)



153
154
155
# File 'lib/sass/tree/visitors/convert.rb', line 153

def visit_media(node)
  "#{tab_str}@media #{query_interp_to_src(node.query)}#{yield}"
end

#visit_mixin(node) (protected)



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/sass/tree/visitors/convert.rb', line 197

def visit_mixin(node)
  arg_to_sass = lambda do |arg|
    sass = arg.to_sass(@options)
    sass = "(#{sass})" if arg.is_a?(Sass::Script::Tree::ListLiteral) && arg.separator == :comma
    sass
  end

  unless node.args.empty? && node.keywords.empty? && node.splat.nil?
    args = node.args.map(&arg_to_sass)
    keywords = node.keywords.as_stored.to_a.map {|k, v| "$#{dasherize(k)}: #{arg_to_sass[v]}"}

    if node.splat
      splat = "#{arg_to_sass[node.splat]}..."
      kwarg_splat = "#{arg_to_sass[node.kwarg_splat]}..." if node.kwarg_splat
    end

    arglist = "(#{[args, splat, keywords, kwarg_splat].flatten.compact.join(', ')})"
  end
  "#{tab_str}#{@format == :sass ? '+' : '@include '}" +
    "#{dasherize(node.name)}#{arglist}#{node.has_children ? yield : semi}\n"
end

#visit_mixindef(node) (protected)



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/sass/tree/visitors/convert.rb', line 172

def visit_mixindef(node)
  args =
    if node.args.empty? && node.splat.nil?
      ""
    else
      str = '('
      str << node.args.map do |v, d|
        if d
          "#{v.to_sass(@options)}: #{d.to_sass(@options)}"
        else
          v.to_sass(@options)
        end
      end.join(", ")

      if node.splat
        str << ", " unless node.args.empty?
        str << node.splat.to_sass(@options) << '...'
      end

      str << ')'
    end

  "#{tab_str}#{@format == :sass ? '=' : '@mixin '}#{dasherize(node.name)}#{args}#{yield}"
end

#visit_prop(node) (protected)



223
224
225
226
227
# File 'lib/sass/tree/visitors/convert.rb', line 223

def visit_prop(node)
  res = tab_str + node.declaration(@options, @format)
  return res + semi + "\n" if node.children.empty?
  res + yield.rstrip + semi + "\n"
end

#visit_return(node) (protected)



229
230
231
# File 'lib/sass/tree/visitors/convert.rb', line 229

def visit_return(node)
  "#{tab_str}@return #{node.expr.to_sass(@options)}#{semi}\n"
end

#visit_root(node) (protected)

Ensures proper spacing between top-level nodes.



40
41
42
# File 'lib/sass/tree/visitors/convert.rb', line 40

def visit_root(node)
  visit_rule_level(node.children)
end

#visit_rule(node) (protected)



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/sass/tree/visitors/convert.rb', line 233

def visit_rule(node)
  rule = node.parsed_rules ? [node.parsed_rules.to_s] : node.rule
  if @format == :sass
    name = selector_to_sass(rule)
    name = "\\" + name if name[0] == ?:
    name.gsub(/^/, tab_str) + yield
  elsif @format == :scss
    name = selector_to_scss(rule)
    res = name + yield
    if node.children.last.is_a?(Sass::Tree::CommentNode) && node.children.last.type == :silent
      res.slice!(-3..-1)
      res << "\n" << tab_str << "}\n"
    end
    res
  end
end

#visit_supports(node) (protected)



157
158
159
# File 'lib/sass/tree/visitors/convert.rb', line 157

def visit_supports(node)
  "#{tab_str}@#{node.name} #{node.condition.to_src(@options)}#{yield}"
end

#visit_variable(node) (protected)



250
251
252
253
# File 'lib/sass/tree/visitors/convert.rb', line 250

def visit_variable(node)
  "#{tab_str}$#{dasherize(node.name)}: #{node.expr.to_sass(@options)}" +
    "#{' !global' if node.global}#{' !default' if node.guarded}#{semi}\n"
end

#visit_warn(node) (protected)



255
256
257
# File 'lib/sass/tree/visitors/convert.rb', line 255

def visit_warn(node)
  "#{tab_str}@warn #{node.expr.to_sass(@options)}#{semi}\n"
end

#visit_while(node) (protected)



259
260
261
# File 'lib/sass/tree/visitors/convert.rb', line 259

def visit_while(node)
  "#{tab_str}@while #{node.expr.to_sass(@options)}#{yield}"
end