haml 5.2.2 → 6.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/workflows/test.yml +15 -15
  4. data/.gitignore +16 -16
  5. data/.yardopts +0 -3
  6. data/CHANGELOG.md +168 -4
  7. data/FAQ.md +1 -1
  8. data/Gemfile +21 -10
  9. data/MIT-LICENSE +1 -1
  10. data/README.md +22 -34
  11. data/REFERENCE.md +95 -159
  12. data/Rakefile +15 -82
  13. data/bin/bench +66 -0
  14. data/bin/console +11 -0
  15. data/bin/ruby +3 -0
  16. data/bin/setup +7 -0
  17. data/bin/stackprof +27 -0
  18. data/bin/test +24 -0
  19. data/exe/haml +6 -0
  20. data/haml.gemspec +34 -36
  21. data/lib/haml/ambles.rb +20 -0
  22. data/lib/haml/attribute_builder.rb +127 -184
  23. data/lib/haml/attribute_compiler.rb +90 -194
  24. data/lib/haml/attribute_parser.rb +92 -126
  25. data/lib/haml/cli.rb +154 -0
  26. data/lib/haml/compiler/children_compiler.rb +155 -0
  27. data/lib/haml/compiler/comment_compiler.rb +51 -0
  28. data/lib/haml/compiler/doctype_compiler.rb +52 -0
  29. data/lib/haml/compiler/script_compiler.rb +114 -0
  30. data/lib/haml/compiler/silent_script_compiler.rb +24 -0
  31. data/lib/haml/compiler/tag_compiler.rb +76 -0
  32. data/lib/haml/compiler.rb +63 -296
  33. data/lib/haml/dynamic_merger.rb +67 -0
  34. data/lib/haml/engine.rb +48 -227
  35. data/lib/haml/error.rb +5 -4
  36. data/lib/haml/escape.rb +13 -0
  37. data/lib/haml/escape_any.rb +21 -0
  38. data/lib/haml/filters/base.rb +12 -0
  39. data/lib/haml/filters/cdata.rb +20 -0
  40. data/lib/haml/filters/coffee.rb +17 -0
  41. data/lib/haml/filters/css.rb +33 -0
  42. data/lib/haml/filters/erb.rb +10 -0
  43. data/lib/haml/filters/escaped.rb +22 -0
  44. data/lib/haml/filters/javascript.rb +33 -0
  45. data/lib/haml/filters/less.rb +20 -0
  46. data/lib/haml/filters/markdown.rb +11 -0
  47. data/lib/haml/filters/plain.rb +29 -0
  48. data/lib/haml/filters/preserve.rb +22 -0
  49. data/lib/haml/filters/ruby.rb +10 -0
  50. data/lib/haml/filters/sass.rb +15 -0
  51. data/lib/haml/filters/scss.rb +15 -0
  52. data/lib/haml/filters/text_base.rb +25 -0
  53. data/lib/haml/filters/tilt_base.rb +59 -0
  54. data/lib/haml/filters.rb +54 -378
  55. data/lib/haml/force_escape.rb +29 -0
  56. data/lib/haml/helpers.rb +3 -697
  57. data/lib/haml/html.rb +22 -0
  58. data/lib/haml/identity.rb +13 -0
  59. data/lib/haml/object_ref.rb +35 -0
  60. data/lib/haml/parser.rb +158 -23
  61. data/lib/haml/rails_helpers.rb +53 -0
  62. data/lib/haml/rails_template.rb +62 -0
  63. data/lib/haml/railtie.rb +3 -46
  64. data/lib/haml/ruby_expression.rb +32 -0
  65. data/lib/haml/string_splitter.rb +140 -0
  66. data/lib/haml/template.rb +15 -34
  67. data/lib/haml/temple_line_counter.rb +2 -1
  68. data/lib/haml/util.rb +19 -15
  69. data/lib/haml/version.rb +1 -2
  70. data/lib/haml/whitespace.rb +8 -0
  71. data/lib/haml.rb +8 -20
  72. metadata +188 -50
  73. data/.gitmodules +0 -3
  74. data/TODO +0 -24
  75. data/benchmark.rb +0 -70
  76. data/bin/haml +0 -9
  77. data/lib/haml/.gitattributes +0 -1
  78. data/lib/haml/buffer.rb +0 -182
  79. data/lib/haml/escapable.rb +0 -77
  80. data/lib/haml/exec.rb +0 -347
  81. data/lib/haml/generator.rb +0 -42
  82. data/lib/haml/helpers/action_view_extensions.rb +0 -60
  83. data/lib/haml/helpers/action_view_mods.rb +0 -132
  84. data/lib/haml/helpers/action_view_xss_mods.rb +0 -60
  85. data/lib/haml/helpers/safe_erubi_template.rb +0 -20
  86. data/lib/haml/helpers/safe_erubis_template.rb +0 -33
  87. data/lib/haml/helpers/xss_mods.rb +0 -114
  88. data/lib/haml/options.rb +0 -273
  89. data/lib/haml/plugin.rb +0 -54
  90. data/lib/haml/sass_rails_filter.rb +0 -47
  91. data/lib/haml/template/options.rb +0 -27
  92. data/lib/haml/temple_engine.rb +0 -124
  93. data/yard/default/.gitignore +0 -1
  94. data/yard/default/fulldoc/html/css/common.sass +0 -15
  95. data/yard/default/layout/html/footer.erb +0 -12
data/lib/haml/cli.rb ADDED
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+ require 'haml'
3
+ require 'thor'
4
+
5
+ module Haml
6
+ class CLI < Thor
7
+ class_option :escape_html, type: :boolean, default: true
8
+ class_option :escape_attrs, type: :boolean, default: true
9
+
10
+ desc 'render HAML', 'Render haml template'
11
+ option :load_path, type: :string, aliases: %w[-I]
12
+ option :require, type: :string, aliases: %w[-r]
13
+ def render(file)
14
+ process_load_options
15
+ code = generate_code(file)
16
+ puts eval(code, binding, file)
17
+ end
18
+
19
+ desc 'compile HAML', 'Show compile result'
20
+ option :actionview, type: :boolean, default: false, aliases: %w[-a]
21
+ option :color, type: :boolean, default: true
22
+ option :check, type: :boolean, default: false, aliases: %w[-c]
23
+ def compile(file)
24
+ code = generate_code(file)
25
+ if options[:check]
26
+ if error = validate_ruby(code, file)
27
+ abort error.message.split("\n").first
28
+ end
29
+ puts "Syntax OK"
30
+ return
31
+ end
32
+ puts_code(code, color: options[:color])
33
+ end
34
+
35
+ desc 'temple HAML', 'Show temple intermediate expression'
36
+ option :color, type: :boolean, default: true
37
+ def temple(file)
38
+ pp_object(generate_temple(file), color: options[:color])
39
+ end
40
+
41
+ desc 'parse HAML', 'Show parse result'
42
+ option :color, type: :boolean, default: true
43
+ def parse(file)
44
+ pp_object(generate_ast(file), color: options[:color])
45
+ end
46
+
47
+ desc 'version', 'Show the used haml version'
48
+ def version
49
+ puts Haml::VERSION
50
+ end
51
+
52
+ private
53
+
54
+ def process_load_options
55
+ if options[:load_path]
56
+ options[:load_path].split(':').each do |dir|
57
+ $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir)
58
+ end
59
+ end
60
+
61
+ if options[:require]
62
+ require options[:require]
63
+ end
64
+ end
65
+
66
+ def read_file(file)
67
+ if file == '-'
68
+ STDIN.read
69
+ else
70
+ File.read(file)
71
+ end
72
+ end
73
+
74
+ def generate_code(file)
75
+ template = read_file(file)
76
+ if options[:actionview]
77
+ require 'action_view'
78
+ require 'action_view/base'
79
+ require 'haml/rails_template'
80
+ handler = Haml::RailsTemplate.new
81
+ template = ActionView::Template.new(template, 'inline template', handler, { locals: [] })
82
+ code = handler.call(template)
83
+ <<-end_src
84
+ def _inline_template___2144273726781623612_70327218547300(local_assigns, output_buffer)
85
+ _old_virtual_path, @virtual_path = @virtual_path, nil;_old_output_buffer = @output_buffer;;#{code}
86
+ ensure
87
+ @virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
88
+ end
89
+ end_src
90
+ else
91
+ Haml::Engine.new(engine_options).call(template)
92
+ end
93
+ end
94
+
95
+ def generate_ast(file)
96
+ template = read_file(file)
97
+ Haml::Parser.new(engine_options).call(template)
98
+ end
99
+
100
+ def generate_temple(file)
101
+ ast = generate_ast(file)
102
+ Haml::Compiler.new(engine_options).call(ast)
103
+ end
104
+
105
+ def engine_options
106
+ Haml::Engine.options.to_h.merge(
107
+ escape_attrs: options[:escape_attrs],
108
+ escape_html: options[:escape_html],
109
+ )
110
+ end
111
+
112
+ # Flexible default_task, compatible with haml's CLI
113
+ def method_missing(*args)
114
+ return super(*args) if args.length > 1
115
+ render(args.first.to_s)
116
+ end
117
+
118
+ def puts_code(code, color: true)
119
+ begin
120
+ require 'irb/color'
121
+ rescue LoadError
122
+ color = false
123
+ end
124
+ if color
125
+ puts IRB::Color.colorize_code(code)
126
+ else
127
+ puts code
128
+ end
129
+ end
130
+
131
+ # Enable colored pretty printing only for development environment.
132
+ def pp_object(arg, color: true)
133
+ begin
134
+ require 'irb/color_printer'
135
+ rescue LoadError
136
+ color = false
137
+ end
138
+ if color
139
+ IRB::ColorPrinter.pp(arg)
140
+ else
141
+ require 'pp'
142
+ pp(arg)
143
+ end
144
+ end
145
+
146
+ def validate_ruby(code, file)
147
+ begin
148
+ eval("BEGIN {return nil}; #{code}", binding, file)
149
+ rescue ::SyntaxError # Not to be confused with Haml::SyntaxError
150
+ $!
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,155 @@
1
+ # frozen_string_literal: true
2
+ require 'haml/temple_line_counter'
3
+
4
+ module Haml
5
+ class Compiler
6
+ class ChildrenCompiler
7
+ def initialize
8
+ @lineno = 1
9
+ @multi_flattener = Temple::Filters::MultiFlattener.new
10
+ end
11
+
12
+ def compile(node, &block)
13
+ temple = [:multi]
14
+ return temple if node.children.empty?
15
+
16
+ temple << [:whitespace] if prepend_whitespace?(node)
17
+ node.children.each do |n|
18
+ rstrip_whitespace!(temple) if nuke_prev_whitespace?(n)
19
+ insert_newlines!(temple, n)
20
+ temple << moving_lineno(n) { block.call(n) }
21
+ temple << [:whitespace] if insert_whitespace?(n)
22
+ end
23
+ rstrip_whitespace!(temple) if nuke_inner_whitespace?(node)
24
+ temple
25
+ end
26
+
27
+ private
28
+
29
+ def insert_newlines!(temple, node)
30
+ (node.line - @lineno).times do
31
+ temple << [:newline]
32
+ end
33
+
34
+ @lineno = node.line
35
+ end
36
+
37
+ def moving_lineno(node, &block)
38
+ # before: As they may have children, we need to increment lineno before compilation.
39
+ case node.type
40
+ when :script, :silent_script
41
+ @lineno += 1
42
+ when :tag
43
+ [node.value[:dynamic_attributes].new, node.value[:dynamic_attributes].old].compact.each do |attribute_hash|
44
+ @lineno += attribute_hash.count("\n")
45
+ end
46
+ @lineno += 1 if node.children.empty? && node.value[:parse]
47
+ end
48
+
49
+ temple = block.call # compile
50
+
51
+ # after: filter may not have children, and for some dynamic filters we can't predict the number of lines.
52
+ case node.type
53
+ when :filter
54
+ @lineno += TempleLineCounter.count_lines(temple)
55
+ end
56
+
57
+ temple
58
+ end
59
+
60
+ def prepend_whitespace?(node)
61
+ return false unless %i[comment tag].include?(node.type)
62
+ !nuke_inner_whitespace?(node)
63
+ end
64
+
65
+ def nuke_inner_whitespace?(node)
66
+ case
67
+ when node.type == :tag
68
+ node.value[:nuke_inner_whitespace]
69
+ when node.parent.nil?
70
+ false
71
+ else
72
+ nuke_inner_whitespace?(node.parent)
73
+ end
74
+ end
75
+
76
+ def nuke_prev_whitespace?(node)
77
+ case node.type
78
+ when :tag
79
+ node.value[:nuke_outer_whitespace]
80
+ when :silent_script
81
+ !node.children.empty? && nuke_prev_whitespace?(node.children.first)
82
+ else
83
+ false
84
+ end
85
+ end
86
+
87
+ def nuke_outer_whitespace?(node)
88
+ return false if node.type != :tag
89
+ node.value[:nuke_outer_whitespace]
90
+ end
91
+
92
+ def rstrip_whitespace!(temple)
93
+ return if temple.size == 1
94
+
95
+ case temple[0]
96
+ when :multi
97
+ case temple[-1][0]
98
+ when :whitespace
99
+ temple.delete_at(-1)
100
+ when :multi, :block
101
+ rstrip_whitespace!(temple[-1])
102
+ end
103
+ when :block
104
+ _block, code, exp = temple
105
+ if code.start_with?(/\s*if\s/)
106
+ # Remove [:whitespace] before `end`
107
+ exp.replace(@multi_flattener.call(exp))
108
+ rstrip_whitespace!(exp)
109
+
110
+ # Remove [:whitespace] before `else` if exists
111
+ else_index = find_else_index(exp)
112
+ if else_index
113
+ whitespace_index = else_index - 1
114
+ while exp[whitespace_index] == [:newline]
115
+ whitespace_index -= 1
116
+ end
117
+ if exp[whitespace_index] == [:whitespace]
118
+ exp.delete_at(whitespace_index)
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ def find_else_index(temple)
126
+ multi, *args = temple
127
+ return nil if multi != :multi
128
+
129
+ args.each_with_index do |arg, index|
130
+ if arg[0] == :code && arg[1].match?(/\A\s*else\s*\z/)
131
+ return index + 1
132
+ end
133
+ end
134
+ nil
135
+ end
136
+
137
+ def insert_whitespace?(node)
138
+ return false if nuke_outer_whitespace?(node)
139
+
140
+ case node.type
141
+ when :doctype
142
+ node.value[:type] != 'xml'
143
+ when :comment, :plain, :tag
144
+ true
145
+ when :script
146
+ node.children.empty? && !nuke_inner_whitespace?(node)
147
+ when :filter
148
+ !%w[ruby].include?(node.value[:name])
149
+ else
150
+ false
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Compiler
4
+ class CommentCompiler
5
+ def compile(node, &block)
6
+ if node.value[:conditional]
7
+ compile_conditional_comment(node, &block)
8
+ else
9
+ compile_html_comment(node, &block)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def compile_html_comment(node, &block)
16
+ if node.children.empty?
17
+ [:html, :comment, compile_text(node)]
18
+ else
19
+ [:html, :comment, yield(node)]
20
+ end
21
+ end
22
+
23
+ def compile_conditional_comment(node, &block)
24
+ condition = node.value[:conditional]
25
+ if node.value[:conditional] =~ /\A\[(\[*[^\[\]]+\]*)\]/
26
+ condition = $1
27
+ end
28
+
29
+ content =
30
+ if node.children.empty?
31
+ compile_text(node)
32
+ else
33
+ yield(node)
34
+ end
35
+ [:html, :condcomment, condition, content, node.value[:revealed]]
36
+ end
37
+
38
+ def compile_text(node)
39
+ text =
40
+ if node.value[:parse]
41
+ # Just always escaping the result for safety. We could respect
42
+ # escape_html, but I don't see any use case for it.
43
+ [:escape, true, [:dynamic, node.value[:text]]]
44
+ else
45
+ [:static, node.value[:text]]
46
+ end
47
+ [:multi, [:static, ' '], text, [:static, ' ']]
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Compiler
4
+ class DoctypeCompiler
5
+ def initialize(options = {})
6
+ @format = options[:format]
7
+ end
8
+
9
+ def compile(node)
10
+ case node.value[:type]
11
+ when ''
12
+ html_doctype(node)
13
+ when 'xml'
14
+ xml_doctype
15
+ when 'rdfa'
16
+ rdfa_doctype
17
+ else
18
+ [:html, :doctype, node.value[:type]]
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def html_doctype(node)
25
+ version = node.value[:version] || :transitional
26
+ case @format
27
+ when :xhtml
28
+ [:html, :doctype, version]
29
+ when :html4
30
+ [:html, :doctype, :transitional]
31
+ when :html5
32
+ [:html, :doctype, :html]
33
+ else
34
+ [:html, :doctype, @format]
35
+ end
36
+ end
37
+
38
+ def xml_doctype
39
+ case @format
40
+ when :xhtml
41
+ [:static, "<?xml version='1.0' encoding='utf-8' ?>\n"]
42
+ else
43
+ [:multi]
44
+ end
45
+ end
46
+
47
+ def rdfa_doctype
48
+ [:static, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">']
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+ require 'temple/static_analyzer'
3
+ require 'haml/ruby_expression'
4
+ require 'haml/string_splitter'
5
+
6
+ module Haml
7
+ class Compiler
8
+ class ScriptCompiler
9
+ def self.find_and_preserve(input, tags)
10
+ tags = tags.map { |tag| Regexp.escape(tag) }.join('|')
11
+ re = /<(#{tags})([^>]*)>(.*?)(<\/\1>)/im
12
+ input.to_s.gsub(re) do |s|
13
+ s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
14
+ "<#{$1}#{$2}>#{Haml::Helpers.preserve($3)}</#{$1}>"
15
+ end
16
+ end
17
+
18
+ def initialize(identity, options)
19
+ @identity = identity
20
+ @disable_capture = options[:disable_capture]
21
+ end
22
+
23
+ def compile(node, &block)
24
+ unless Ripper.respond_to?(:lex) # No Ripper.lex in truffleruby
25
+ return dynamic_compile(node, &block)
26
+ end
27
+
28
+ no_children = node.children.empty?
29
+ case
30
+ when no_children && node.value[:escape_interpolation]
31
+ compile_interpolated_plain(node)
32
+ when no_children && RubyExpression.string_literal?(node.value[:text])
33
+ delegate_optimization(node)
34
+ when no_children && Temple::StaticAnalyzer.static?(node.value[:text])
35
+ static_compile(node)
36
+ else
37
+ dynamic_compile(node, &block)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ # String-interpolated plain text must be compiled with this method
44
+ # because we have to escape only interpolated values.
45
+ def compile_interpolated_plain(node)
46
+ temple = [:multi]
47
+ StringSplitter.compile(node.value[:text]).each do |type, value|
48
+ case type
49
+ when :static
50
+ temple << [:static, value]
51
+ when :dynamic
52
+ temple << [:escape, node.value[:escape_interpolation], [:dynamic, value]]
53
+ end
54
+ end
55
+ temple << [:newline]
56
+ end
57
+
58
+ # :dynamic is optimized in other filter: StringSplitter
59
+ def delegate_optimization(node)
60
+ [:multi,
61
+ [:escape, node.value[:escape_html], [:dynamic, node.value[:text]]],
62
+ [:newline],
63
+ ]
64
+ end
65
+
66
+ def static_compile(node)
67
+ str = eval(node.value[:text]).to_s
68
+ if node.value[:escape_html]
69
+ str = Haml::Util.escape_html(str)
70
+ elsif node.value[:preserve]
71
+ str = ScriptCompiler.find_and_preserve(str, %w(textarea pre code))
72
+ end
73
+ [:multi, [:static, str], [:newline]]
74
+ end
75
+
76
+ def dynamic_compile(node, &block)
77
+ var = @identity.generate
78
+ temple = compile_script_assign(var, node, &block)
79
+ temple << compile_script_result(var, node)
80
+ end
81
+
82
+ def compile_script_assign(var, node, &block)
83
+ if node.children.empty?
84
+ [:multi,
85
+ [:code, "#{var} = (#{node.value[:text]}"],
86
+ [:newline],
87
+ [:code, ')'],
88
+ ]
89
+ else
90
+ [:multi,
91
+ [:block, "#{var} = #{node.value[:text]}",
92
+ [:multi, [:newline], @disable_capture ? yield(node) : [:capture, Temple::Utils.unique_name, yield(node)]]
93
+ ],
94
+ ]
95
+ end
96
+ end
97
+
98
+ def compile_script_result(result, node)
99
+ if !node.value[:escape_html] && node.value[:preserve]
100
+ result = find_and_preserve(result)
101
+ end
102
+ [:escapeany, node.value[:escape_html], [:dynamic, result]]
103
+ end
104
+
105
+ def find_and_preserve(code)
106
+ %Q[::Haml::Compiler::ScriptCompiler.find_and_preserve(#{code}, %w(textarea pre code))]
107
+ end
108
+
109
+ def escape_html(temple)
110
+ [:escape, true, temple]
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Compiler
4
+ class SilentScriptCompiler
5
+ def compile(node, &block)
6
+ if node.children.empty?
7
+ [:multi, [:code, node.value[:text]], [:newline]]
8
+ else
9
+ compile_with_children(node, &block)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def compile_with_children(node, &block)
16
+ [:multi,
17
+ [:block, node.value[:text],
18
+ [:multi, [:newline], yield(node)],
19
+ ],
20
+ ]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+ require 'haml/util'
3
+ require 'haml/attribute_compiler'
4
+ require 'haml/string_splitter'
5
+
6
+ module Haml
7
+ class Compiler
8
+ class TagCompiler
9
+ def initialize(identity, options)
10
+ @autoclose = options[:autoclose]
11
+ @identity = identity
12
+ @attribute_compiler = AttributeCompiler.new(identity, options)
13
+ end
14
+
15
+ def compile(node, &block)
16
+ attrs = @attribute_compiler.compile(node)
17
+ contents = compile_contents(node, &block)
18
+ [:html, :tag, node.value[:name], attrs, contents]
19
+ end
20
+
21
+ private
22
+
23
+ def compile_contents(node, &block)
24
+ case
25
+ when !node.children.empty?
26
+ yield(node)
27
+ when node.value[:value].nil? && self_closing?(node)
28
+ nil
29
+ when node.value[:parse]
30
+ return compile_interpolated_plain(node) if node.value[:escape_interpolation]
31
+ if Ripper.respond_to?(:lex) # No Ripper.lex in truffleruby
32
+ return delegate_optimization(node) if RubyExpression.string_literal?(node.value[:value])
33
+ return delegate_optimization(node) if Temple::StaticAnalyzer.static?(node.value[:value])
34
+ end
35
+
36
+ var = @identity.generate
37
+ [:multi,
38
+ [:code, "#{var} = (#{node.value[:value]}"],
39
+ [:newline],
40
+ [:code, ')'],
41
+ [:escape, node.value[:escape_html], [:dynamic, var]]
42
+ ]
43
+ else
44
+ [:static, node.value[:value]]
45
+ end
46
+ end
47
+
48
+ # :dynamic is optimized in other filters: StringSplitter or StaticAnalyzer
49
+ def delegate_optimization(node)
50
+ [:multi,
51
+ [:escape, node.value[:escape_html], [:dynamic, node.value[:value]]],
52
+ [:newline],
53
+ ]
54
+ end
55
+
56
+ # We should handle interpolation here to escape only interpolated values.
57
+ def compile_interpolated_plain(node)
58
+ temple = [:multi]
59
+ StringSplitter.compile(node.value[:value]).each do |type, value|
60
+ case type
61
+ when :static
62
+ temple << [:static, value]
63
+ when :dynamic
64
+ temple << [:escape, node.value[:escape_interpolation], [:dynamic, value]]
65
+ end
66
+ end
67
+ temple << [:newline]
68
+ end
69
+
70
+ def self_closing?(node)
71
+ return true if @autoclose && @autoclose.include?(node.value[:name])
72
+ node.value[:self_closing]
73
+ end
74
+ end
75
+ end
76
+ end