haml 6.0.0.beta.1-java
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.
- 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
|