haml 6.0.0.beta.1-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/test.yml +40 -0
- data/.gitignore +19 -0
- data/CHANGELOG.md +1515 -0
- data/FAQ.md +147 -0
- data/Gemfile +23 -0
- data/MIT-LICENSE +20 -0
- data/README.md +210 -0
- data/REFERENCE.md +1380 -0
- data/Rakefile +116 -0
- data/bin/bench +66 -0
- data/bin/console +11 -0
- data/bin/ruby +3 -0
- data/bin/setup +7 -0
- data/bin/stackprof +27 -0
- data/bin/test +24 -0
- data/exe/haml +6 -0
- data/ext/haml/extconf.rb +10 -0
- data/ext/haml/haml.c +537 -0
- data/ext/haml/hescape.c +108 -0
- data/ext/haml/hescape.h +20 -0
- data/haml.gemspec +47 -0
- data/lib/haml/ambles.rb +20 -0
- data/lib/haml/attribute_builder.rb +175 -0
- data/lib/haml/attribute_compiler.rb +128 -0
- data/lib/haml/attribute_parser.rb +110 -0
- data/lib/haml/cli.rb +154 -0
- data/lib/haml/compiler/children_compiler.rb +126 -0
- data/lib/haml/compiler/comment_compiler.rb +39 -0
- data/lib/haml/compiler/doctype_compiler.rb +46 -0
- data/lib/haml/compiler/script_compiler.rb +116 -0
- data/lib/haml/compiler/silent_script_compiler.rb +24 -0
- data/lib/haml/compiler/tag_compiler.rb +76 -0
- data/lib/haml/compiler.rb +97 -0
- data/lib/haml/dynamic_merger.rb +67 -0
- data/lib/haml/engine.rb +53 -0
- data/lib/haml/error.rb +16 -0
- data/lib/haml/escapable.rb +13 -0
- data/lib/haml/filters/base.rb +12 -0
- data/lib/haml/filters/cdata.rb +20 -0
- data/lib/haml/filters/coffee.rb +17 -0
- data/lib/haml/filters/css.rb +33 -0
- data/lib/haml/filters/erb.rb +10 -0
- data/lib/haml/filters/escaped.rb +22 -0
- data/lib/haml/filters/javascript.rb +33 -0
- data/lib/haml/filters/less.rb +20 -0
- data/lib/haml/filters/markdown.rb +11 -0
- data/lib/haml/filters/plain.rb +29 -0
- data/lib/haml/filters/preserve.rb +22 -0
- data/lib/haml/filters/ruby.rb +10 -0
- data/lib/haml/filters/sass.rb +15 -0
- data/lib/haml/filters/scss.rb +15 -0
- data/lib/haml/filters/text_base.rb +25 -0
- data/lib/haml/filters/tilt_base.rb +49 -0
- data/lib/haml/filters.rb +75 -0
- data/lib/haml/force_escapable.rb +29 -0
- data/lib/haml/haml_error.rb +66 -0
- data/lib/haml/helpers.rb +15 -0
- data/lib/haml/html.rb +22 -0
- data/lib/haml/identity.rb +13 -0
- data/lib/haml/object_ref.rb +30 -0
- data/lib/haml/parser.rb +986 -0
- data/lib/haml/rails_helpers.rb +51 -0
- data/lib/haml/rails_template.rb +55 -0
- data/lib/haml/railtie.rb +15 -0
- data/lib/haml/ruby_expression.rb +32 -0
- data/lib/haml/string_splitter.rb +20 -0
- data/lib/haml/template.rb +20 -0
- data/lib/haml/temple_line_counter.rb +31 -0
- data/lib/haml/util.rb +260 -0
- data/lib/haml/version.rb +4 -0
- data/lib/haml.rb +13 -0
- metadata +359 -0
@@ -0,0 +1,39 @@
|
|
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, [:static, " #{node.value[:text]} "]]
|
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
|
+
[:static, " #{node.value[:text]} "]
|
32
|
+
else
|
33
|
+
yield(node)
|
34
|
+
end
|
35
|
+
[:html, :condcomment, condition, content, node.value[:revealed]]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,46 @@
|
|
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 'xml'
|
12
|
+
xml_doctype
|
13
|
+
when ''
|
14
|
+
html_doctype(node)
|
15
|
+
else
|
16
|
+
[:html, :doctype, node.value[:type]]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def html_doctype(node)
|
23
|
+
version = node.value[:version] || :transitional
|
24
|
+
case @format
|
25
|
+
when :xhtml
|
26
|
+
[:html, :doctype, version]
|
27
|
+
when :html4
|
28
|
+
[:html, :doctype, :transitional]
|
29
|
+
when :html5
|
30
|
+
[:html, :doctype, :html]
|
31
|
+
else
|
32
|
+
[:html, :doctype, @format]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def xml_doctype
|
37
|
+
case @format
|
38
|
+
when :xhtml
|
39
|
+
[:static, "<?xml version='1.0' encoding='utf-8' ?>\n"]
|
40
|
+
else
|
41
|
+
[:multi]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,116 @@
|
|
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
|
+
else
|
102
|
+
result = "(#{result}).to_s"
|
103
|
+
end
|
104
|
+
[:escape, node.value[:escape_html], [:dynamic, result]]
|
105
|
+
end
|
106
|
+
|
107
|
+
def find_and_preserve(code)
|
108
|
+
%Q[::Haml::Compiler::ScriptCompiler.find_and_preserve(#{code}, %w(textarea pre code))]
|
109
|
+
end
|
110
|
+
|
111
|
+
def escape_html(temple)
|
112
|
+
[:escape, true, temple]
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
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
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'haml/compiler/children_compiler'
|
3
|
+
require 'haml/compiler/comment_compiler'
|
4
|
+
require 'haml/compiler/doctype_compiler'
|
5
|
+
require 'haml/compiler/script_compiler'
|
6
|
+
require 'haml/compiler/silent_script_compiler'
|
7
|
+
require 'haml/compiler/tag_compiler'
|
8
|
+
require 'haml/filters'
|
9
|
+
require 'haml/identity'
|
10
|
+
|
11
|
+
module Haml
|
12
|
+
class Compiler
|
13
|
+
def initialize(options = {})
|
14
|
+
identity = Identity.new
|
15
|
+
@children_compiler = ChildrenCompiler.new
|
16
|
+
@comment_compiler = CommentCompiler.new
|
17
|
+
@doctype_compiler = DoctypeCompiler.new(options)
|
18
|
+
@filter_compiler = Filters.new(options)
|
19
|
+
@script_compiler = ScriptCompiler.new(identity, options)
|
20
|
+
@silent_script_compiler = SilentScriptCompiler.new
|
21
|
+
@tag_compiler = TagCompiler.new(identity, options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def call(ast)
|
25
|
+
return runtime_error(ast) if ast.is_a?(HamlError)
|
26
|
+
compile(ast)
|
27
|
+
rescue Error => e
|
28
|
+
runtime_error(e)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def compile(node)
|
34
|
+
case node.type
|
35
|
+
when :root
|
36
|
+
compile_children(node)
|
37
|
+
when :comment
|
38
|
+
compile_comment(node)
|
39
|
+
when :doctype
|
40
|
+
compile_doctype(node)
|
41
|
+
when :filter
|
42
|
+
compile_filter(node)
|
43
|
+
when :plain
|
44
|
+
compile_plain(node)
|
45
|
+
when :script
|
46
|
+
compile_script(node)
|
47
|
+
when :silent_script
|
48
|
+
compile_silent_script(node)
|
49
|
+
when :tag
|
50
|
+
compile_tag(node)
|
51
|
+
when :haml_comment
|
52
|
+
[:multi]
|
53
|
+
else
|
54
|
+
raise InternalError.new("Unexpected node type: #{node.type}")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def compile_children(node)
|
59
|
+
@children_compiler.compile(node) { |n| compile(n) }
|
60
|
+
end
|
61
|
+
|
62
|
+
def compile_comment(node)
|
63
|
+
@comment_compiler.compile(node) { |n| compile_children(n) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def compile_doctype(node)
|
67
|
+
@doctype_compiler.compile(node)
|
68
|
+
end
|
69
|
+
|
70
|
+
def compile_filter(node)
|
71
|
+
@filter_compiler.compile(node)
|
72
|
+
end
|
73
|
+
|
74
|
+
def compile_plain(node)
|
75
|
+
[:static, node.value[:text]]
|
76
|
+
end
|
77
|
+
|
78
|
+
def compile_script(node)
|
79
|
+
@script_compiler.compile(node) { |n| compile_children(n) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def compile_silent_script(node)
|
83
|
+
@silent_script_compiler.compile(node) { |n| compile_children(n) }
|
84
|
+
end
|
85
|
+
|
86
|
+
def compile_tag(node)
|
87
|
+
@tag_compiler.compile(node) { |n| compile_children(n) }
|
88
|
+
end
|
89
|
+
|
90
|
+
def runtime_error(error)
|
91
|
+
[:multi].tap do |temple|
|
92
|
+
error.line.times { temple << [:newline] } if error.line
|
93
|
+
temple << [:code, %Q[raise #{error.class}.new(%q[#{error.message}], #{error.line.inspect})]]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Haml
|
3
|
+
# Compile [:multi, [:static, 'foo'], [:dynamic, 'bar']] to [:dynamic, '"foo#{bar}"']
|
4
|
+
class DynamicMerger < Temple::Filter
|
5
|
+
def on_multi(*exps)
|
6
|
+
exps = exps.dup
|
7
|
+
result = [:multi]
|
8
|
+
buffer = []
|
9
|
+
|
10
|
+
until exps.empty?
|
11
|
+
type, arg = exps.first
|
12
|
+
if type == :dynamic && arg.count("\n") == 0
|
13
|
+
buffer << exps.shift
|
14
|
+
elsif type == :static && exps.size > (count = arg.count("\n")) &&
|
15
|
+
exps[1, count].all? { |e| e == [:newline] }
|
16
|
+
(1 + count).times { buffer << exps.shift }
|
17
|
+
elsif type == :newline && exps.size > (count = count_newline(exps)) &&
|
18
|
+
exps[count].first == :static && count == exps[count].last.count("\n")
|
19
|
+
(count + 1).times { buffer << exps.shift }
|
20
|
+
else
|
21
|
+
result.concat(merge_dynamic(buffer))
|
22
|
+
buffer = []
|
23
|
+
result << compile(exps.shift)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
result.concat(merge_dynamic(buffer))
|
27
|
+
|
28
|
+
result.size == 2 ? result[1] : result
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def merge_dynamic(exps)
|
34
|
+
# Merge exps only when they have both :static and :dynamic
|
35
|
+
unless exps.any? { |type,| type == :static } && exps.any? { |type,| type == :dynamic }
|
36
|
+
return exps
|
37
|
+
end
|
38
|
+
|
39
|
+
strlit_body = String.new
|
40
|
+
exps.each do |type, arg|
|
41
|
+
case type
|
42
|
+
when :static
|
43
|
+
strlit_body << arg.dump.sub!(/\A"/, '').sub!(/"\z/, '').gsub('\n', "\n")
|
44
|
+
when :dynamic
|
45
|
+
strlit_body << "\#{#{arg}}"
|
46
|
+
when :newline
|
47
|
+
# newline is added by `gsub('\n', "\n")`
|
48
|
+
else
|
49
|
+
raise "unexpected type #{type.inspect} is given to #merge_dynamic"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
[[:dynamic, "%Q\0#{strlit_body}\0"]]
|
53
|
+
end
|
54
|
+
|
55
|
+
def count_newline(exps)
|
56
|
+
count = 0
|
57
|
+
exps.each do |exp|
|
58
|
+
if exp == [:newline]
|
59
|
+
count += 1
|
60
|
+
else
|
61
|
+
return count
|
62
|
+
end
|
63
|
+
end
|
64
|
+
return count
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/haml/engine.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'temple'
|
3
|
+
require 'haml/parser'
|
4
|
+
require 'haml/compiler'
|
5
|
+
require 'haml/html'
|
6
|
+
require 'haml/escapable'
|
7
|
+
require 'haml/force_escapable'
|
8
|
+
require 'haml/dynamic_merger'
|
9
|
+
require 'haml/ambles'
|
10
|
+
|
11
|
+
module Haml
|
12
|
+
class Engine < Temple::Engine
|
13
|
+
define_options(
|
14
|
+
:buffer_class,
|
15
|
+
generator: Temple::Generators::ArrayBuffer,
|
16
|
+
format: :html,
|
17
|
+
attr_quote: "'",
|
18
|
+
escape_html: true,
|
19
|
+
escape_attrs: true,
|
20
|
+
autoclose: %w(area base basefont br col command embed frame
|
21
|
+
hr img input isindex keygen link menuitem meta
|
22
|
+
param source track wbr),
|
23
|
+
filename: "",
|
24
|
+
disable_capture: false,
|
25
|
+
)
|
26
|
+
|
27
|
+
use Parser
|
28
|
+
use Compiler
|
29
|
+
use HTML
|
30
|
+
filter :StringSplitter
|
31
|
+
filter :StaticAnalyzer
|
32
|
+
use Escapable
|
33
|
+
use ForceEscapable
|
34
|
+
filter :ControlFlow
|
35
|
+
use Ambles
|
36
|
+
filter :MultiFlattener
|
37
|
+
filter :StaticMerger
|
38
|
+
use DynamicMerger
|
39
|
+
use :Generator, -> { options[:generator] }
|
40
|
+
end
|
41
|
+
|
42
|
+
# For backward compatibility of Tilt integration. TODO: We should deprecate this
|
43
|
+
# and let Tilt have a native support of Haml 6. At least it generates warnings now.
|
44
|
+
class TempleEngine < Engine
|
45
|
+
def compile(template)
|
46
|
+
@precompiled = call(template)
|
47
|
+
end
|
48
|
+
|
49
|
+
def precompiled_with_ambles(_local_names, after_preamble:)
|
50
|
+
"#{after_preamble.tr("\n", ';')}#{@precompiled}".dup
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/haml/error.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Haml
|
3
|
+
# TODO: unify Haml::Error (former Hamlit::Error) and Haml::HamlError (former Haml::Error)
|
4
|
+
class Error < StandardError
|
5
|
+
attr_reader :line
|
6
|
+
|
7
|
+
def initialize(message = nil, line = nil)
|
8
|
+
super(message)
|
9
|
+
@line = line
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class SyntaxError < Error; end
|
14
|
+
class InternalError < Error; end
|
15
|
+
class FilterNotFound < Error; end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'haml/util'
|
3
|
+
|
4
|
+
module Haml
|
5
|
+
class Escapable < Temple::Filters::Escapable
|
6
|
+
def initialize(opts = {})
|
7
|
+
super
|
8
|
+
@escape_code = options[:escape_code] ||
|
9
|
+
"::Haml::Util.escape_html#{options[:use_html_safe] ? '_safe' : ''}((%s))"
|
10
|
+
@escaper = eval("proc {|v| #{@escape_code % 'v'} }")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Haml
|
3
|
+
class Filters
|
4
|
+
class Cdata < TextBase
|
5
|
+
def compile(node)
|
6
|
+
compile_cdata(node)
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def compile_cdata(node)
|
12
|
+
temple = [:multi]
|
13
|
+
temple << [:static, "<![CDATA[\n"]
|
14
|
+
compile_text!(temple, node, ' ')
|
15
|
+
temple << [:static, "\n]]>"]
|
16
|
+
temple
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Haml
|
3
|
+
class Filters
|
4
|
+
class Coffee < TiltBase
|
5
|
+
def compile(node)
|
6
|
+
require 'tilt/coffee' if explicit_require?('coffee')
|
7
|
+
temple = [:multi]
|
8
|
+
temple << [:static, "<script>\n"]
|
9
|
+
temple << compile_with_tilt(node, 'coffee', indent_width: 2)
|
10
|
+
temple << [:static, "</script>"]
|
11
|
+
temple
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
CoffeeScript = Coffee
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Haml
|
3
|
+
class Filters
|
4
|
+
class Css < TextBase
|
5
|
+
def compile(node)
|
6
|
+
case @format
|
7
|
+
when :xhtml
|
8
|
+
compile_xhtml(node)
|
9
|
+
else
|
10
|
+
compile_html(node)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def compile_html(node)
|
17
|
+
temple = [:multi]
|
18
|
+
temple << [:static, "<style>\n"]
|
19
|
+
compile_text!(temple, node, ' ')
|
20
|
+
temple << [:static, "\n</style>"]
|
21
|
+
temple
|
22
|
+
end
|
23
|
+
|
24
|
+
def compile_xhtml(node)
|
25
|
+
temple = [:multi]
|
26
|
+
temple << [:static, "<style type='text/css'>\n /*<![CDATA[*/\n"]
|
27
|
+
compile_text!(temple, node, ' ')
|
28
|
+
temple << [:static, "\n /*]]>*/\n</style>"]
|
29
|
+
temple
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Haml
|
3
|
+
class Filters
|
4
|
+
class Escaped < Base
|
5
|
+
def compile(node)
|
6
|
+
text = node.value[:text].rstrip
|
7
|
+
temple = compile_text(text)
|
8
|
+
[:escape, true, temple]
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def compile_text(text)
|
14
|
+
if ::Haml::Util.contains_interpolation?(text)
|
15
|
+
[:dynamic, ::Haml::Util.unescape_interpolation(text)]
|
16
|
+
else
|
17
|
+
[:static, text]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|