haml 7.2.1 → 7.2.2
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 +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile +1 -1
- data/lib/haml/attribute_parser.rb +1 -2
- data/lib/haml/compiler/script_compiler.rb +0 -4
- data/lib/haml/compiler/tag_compiler.rb +2 -4
- data/lib/haml/string_splitter.rb +90 -100
- data/lib/haml/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: def36fc38e0b0116356b085a4120ea0564c5624c766e03f705ec91d3657e2e8c
|
|
4
|
+
data.tar.gz: 937230d9bbf1ad0cbad38457d985bd964a5edd49137f31398fafad0aa474a8bf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f57d6abe6fdac34effcac8e52c889142828bf405f915239526fe6540ccb2fe138e79f972536e79a1c5dc7ab4de1871030900d0b2a0118325049d316bd5e534f7
|
|
7
|
+
data.tar.gz: b9135ee6741e0105df6e5f4a92c5c3ea660e10be525aca983d2b0d7f509f80d61216fcc32d340f678c3e1ca7ab91da70d4a436a6c45ce6b956d48cf8105097c8
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
|
@@ -8,8 +8,7 @@ module Haml
|
|
|
8
8
|
|
|
9
9
|
# @return [TrueClass, FalseClass] - return true if AttributeParser.parse can be used.
|
|
10
10
|
def self.available?
|
|
11
|
-
|
|
12
|
-
defined?(Ripper) && Ripper.respond_to?(:lex) && Temple::StaticAnalyzer.available?
|
|
11
|
+
Temple::StaticAnalyzer.available?
|
|
13
12
|
end
|
|
14
13
|
|
|
15
14
|
def self.parse(text)
|
|
@@ -21,10 +21,6 @@ module Haml
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
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
24
|
no_children = node.children.empty?
|
|
29
25
|
case
|
|
30
26
|
when no_children && node.value[:escape_interpolation]
|
|
@@ -28,10 +28,8 @@ module Haml
|
|
|
28
28
|
nil
|
|
29
29
|
when node.value[:parse]
|
|
30
30
|
return compile_interpolated_plain(node) if node.value[:escape_interpolation]
|
|
31
|
-
if
|
|
32
|
-
|
|
33
|
-
return delegate_optimization(node) if Temple::StaticAnalyzer.static?(node.value[:value])
|
|
34
|
-
end
|
|
31
|
+
return delegate_optimization(node) if RubyExpression.string_literal?(node.value[:value])
|
|
32
|
+
return delegate_optimization(node) if Temple::StaticAnalyzer.static?(node.value[:value])
|
|
35
33
|
|
|
36
34
|
var = @identity.generate
|
|
37
35
|
[:multi,
|
data/lib/haml/string_splitter.rb
CHANGED
|
@@ -1,139 +1,129 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require 'ripper'
|
|
4
|
-
rescue LoadError
|
|
5
|
-
end
|
|
2
|
+
require 'ripper'
|
|
6
3
|
|
|
7
4
|
module Haml
|
|
8
5
|
# Compile [:dynamic, "foo#{bar}"] to [:multi, [:static, 'foo'], [:dynamic, 'bar']]
|
|
9
6
|
class StringSplitter < Temple::Filter
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
raise(Haml::InternalError, "Expected token size >= 2 but got: #{tokens.size}")
|
|
20
|
-
end
|
|
21
|
-
compile_tokens!(exps, tokens)
|
|
7
|
+
class << self
|
|
8
|
+
# `code` param must be valid string literal
|
|
9
|
+
def compile(code)
|
|
10
|
+
[].tap do |exps|
|
|
11
|
+
tokens = Ripper.lex(code.strip)
|
|
12
|
+
tokens.pop while tokens.last && [:on_comment, :on_sp].include?(tokens.last[1])
|
|
13
|
+
|
|
14
|
+
if tokens.size < 2
|
|
15
|
+
raise(Haml::InternalError, "Expected token size >= 2 but got: #{tokens.size}")
|
|
22
16
|
end
|
|
17
|
+
compile_tokens!(exps, tokens)
|
|
23
18
|
end
|
|
19
|
+
end
|
|
24
20
|
|
|
25
|
-
|
|
21
|
+
private
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
def strip_quotes!(tokens)
|
|
24
|
+
_, type, beg_str = tokens.shift
|
|
25
|
+
if type != :on_tstring_beg
|
|
26
|
+
raise(Haml::InternalError, "Expected :on_tstring_beg but got: #{type}")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
_, type, end_str = tokens.pop
|
|
30
|
+
if type != :on_tstring_end
|
|
31
|
+
raise(Haml::InternalError, "Expected :on_tstring_end but got: #{type}")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
[beg_str, end_str]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def compile_tokens!(exps, tokens)
|
|
38
|
+
beg_str, end_str = strip_quotes!(tokens)
|
|
39
|
+
|
|
40
|
+
until tokens.empty?
|
|
41
|
+
_, type, str = tokens.shift
|
|
32
42
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
case type
|
|
44
|
+
when :on_tstring_content
|
|
45
|
+
beg_str, end_str = escape_quotes(beg_str, end_str)
|
|
46
|
+
exps << [:static, eval("#{beg_str}#{str}#{end_str}").to_s]
|
|
47
|
+
when :on_embexpr_beg
|
|
48
|
+
embedded = shift_balanced_embexpr(tokens)
|
|
49
|
+
exps << [:dynamic, embedded] unless embedded.empty?
|
|
36
50
|
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
37
53
|
|
|
54
|
+
# Some quotes are split-unsafe. Replace such quotes with null characters.
|
|
55
|
+
def escape_quotes(beg_str, end_str)
|
|
56
|
+
case [beg_str[-1], end_str]
|
|
57
|
+
when ['(', ')'], ['[', ']'], ['{', '}']
|
|
58
|
+
[beg_str.sub(/.\z/) { "\0" }, "\0"]
|
|
59
|
+
else
|
|
38
60
|
[beg_str, end_str]
|
|
39
61
|
end
|
|
62
|
+
end
|
|
40
63
|
|
|
41
|
-
|
|
42
|
-
|
|
64
|
+
def shift_balanced_embexpr(tokens)
|
|
65
|
+
String.new.tap do |embedded|
|
|
66
|
+
embexpr_open = 1
|
|
43
67
|
|
|
44
68
|
until tokens.empty?
|
|
45
69
|
_, type, str = tokens.shift
|
|
46
|
-
|
|
47
70
|
case type
|
|
48
|
-
when :on_tstring_content
|
|
49
|
-
beg_str, end_str = escape_quotes(beg_str, end_str)
|
|
50
|
-
exps << [:static, eval("#{beg_str}#{str}#{end_str}").to_s]
|
|
51
71
|
when :on_embexpr_beg
|
|
52
|
-
|
|
53
|
-
|
|
72
|
+
embexpr_open += 1
|
|
73
|
+
when :on_embexpr_end
|
|
74
|
+
embexpr_open -= 1
|
|
75
|
+
break if embexpr_open == 0
|
|
54
76
|
end
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
77
|
|
|
58
|
-
|
|
59
|
-
def escape_quotes(beg_str, end_str)
|
|
60
|
-
case [beg_str[-1], end_str]
|
|
61
|
-
when ['(', ')'], ['[', ']'], ['{', '}']
|
|
62
|
-
[beg_str.sub(/.\z/) { "\0" }, "\0"]
|
|
63
|
-
else
|
|
64
|
-
[beg_str, end_str]
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def shift_balanced_embexpr(tokens)
|
|
69
|
-
String.new.tap do |embedded|
|
|
70
|
-
embexpr_open = 1
|
|
71
|
-
|
|
72
|
-
until tokens.empty?
|
|
73
|
-
_, type, str = tokens.shift
|
|
74
|
-
case type
|
|
75
|
-
when :on_embexpr_beg
|
|
76
|
-
embexpr_open += 1
|
|
77
|
-
when :on_embexpr_end
|
|
78
|
-
embexpr_open -= 1
|
|
79
|
-
break if embexpr_open == 0
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
embedded << str
|
|
83
|
-
end
|
|
78
|
+
embedded << str
|
|
84
79
|
end
|
|
85
80
|
end
|
|
86
81
|
end
|
|
82
|
+
end
|
|
87
83
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
end
|
|
84
|
+
def on_dynamic(code)
|
|
85
|
+
return [:dynamic, code] unless string_literal?(code)
|
|
86
|
+
return [:dynamic, code] if code.include?("\n")
|
|
87
|
+
|
|
88
|
+
temple = [:multi]
|
|
89
|
+
StringSplitter.compile(code).each do |type, content|
|
|
90
|
+
case type
|
|
91
|
+
when :static
|
|
92
|
+
temple << [:static, content]
|
|
93
|
+
when :dynamic
|
|
94
|
+
temple << on_dynamic(content)
|
|
100
95
|
end
|
|
101
|
-
temple
|
|
102
96
|
end
|
|
97
|
+
temple
|
|
98
|
+
end
|
|
103
99
|
|
|
104
|
-
|
|
100
|
+
private
|
|
105
101
|
|
|
106
|
-
|
|
107
|
-
|
|
102
|
+
def string_literal?(code)
|
|
103
|
+
return false if SyntaxChecker.syntax_error?(code)
|
|
108
104
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
105
|
+
type, instructions = Ripper.sexp(code)
|
|
106
|
+
return false if type != :program
|
|
107
|
+
return false if instructions.size > 1
|
|
112
108
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
109
|
+
type, _ = instructions.first
|
|
110
|
+
type == :string_literal
|
|
111
|
+
end
|
|
116
112
|
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
class SyntaxChecker < Ripper
|
|
114
|
+
class ParseError < StandardError; end
|
|
119
115
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
116
|
+
def self.syntax_error?(code)
|
|
117
|
+
self.new(code).parse
|
|
118
|
+
false
|
|
119
|
+
rescue ParseError
|
|
120
|
+
true
|
|
121
|
+
end
|
|
126
122
|
|
|
127
|
-
|
|
123
|
+
private
|
|
128
124
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
else
|
|
134
|
-
# Do nothing if ripper is unavailable
|
|
135
|
-
def call(ast)
|
|
136
|
-
ast
|
|
125
|
+
def on_parse_error(*)
|
|
126
|
+
raise ParseError
|
|
137
127
|
end
|
|
138
128
|
end
|
|
139
129
|
end
|
data/lib/haml/version.rb
CHANGED