syntax_tree-haml 1.0.1 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +11 -2
- data/CHANGELOG.md +22 -1
- data/Gemfile.lock +9 -3
- data/Rakefile +7 -0
- data/lib/syntax_tree/haml/format.rb +425 -0
- data/lib/syntax_tree/haml/pretty_print.rb +158 -0
- data/lib/syntax_tree/haml/version.rb +1 -1
- data/lib/syntax_tree/haml.rb +63 -58
- data/syntax_tree-haml.gemspec +15 -14
- metadata +19 -12
- data/lib/syntax_tree/haml/comment.rb +0 -52
- data/lib/syntax_tree/haml/doctype.rb +0 -64
- data/lib/syntax_tree/haml/filter.rb +0 -42
- data/lib/syntax_tree/haml/haml_comment.rb +0 -38
- data/lib/syntax_tree/haml/plain.rb +0 -40
- data/lib/syntax_tree/haml/root.rb +0 -30
- data/lib/syntax_tree/haml/script.rb +0 -53
- data/lib/syntax_tree/haml/silent_script.rb +0 -57
- data/lib/syntax_tree/haml/tag.rb +0 -306
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3ec66452fbab00bf664cbd1d86b9b351a039eb99ac70547dc2defd72003122da
|
4
|
+
data.tar.gz: 5e643711d3d79a8e7c37bc6f17afbb9d855eab2fbf7992f348014cd14ead9490
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a55f022617f25d7898f92ebdcca872cd3920e2177144dc63caa117a8a12bf4c15ee9ec9ad5dedd65312b64191fdf40725b6e83bf1733066e6055901bc374699
|
7
|
+
data.tar.gz: b06d3310d759f3b11fda480172d66253edc1843740f59aef360a7ca5e7d2130d171ee27d272e73a52038ac50b7f1345dcb0a8a4c89a85c3f4a98914a73aee1c9
|
data/.github/workflows/main.yml
CHANGED
@@ -4,6 +4,13 @@ on:
|
|
4
4
|
- pull_request_target
|
5
5
|
jobs:
|
6
6
|
ci:
|
7
|
+
strategy:
|
8
|
+
fail-fast: false
|
9
|
+
matrix:
|
10
|
+
ruby:
|
11
|
+
- '2.7'
|
12
|
+
- '3.0'
|
13
|
+
- '3.1'
|
7
14
|
name: CI
|
8
15
|
runs-on: ubuntu-latest
|
9
16
|
env:
|
@@ -13,9 +20,11 @@ jobs:
|
|
13
20
|
- uses: ruby/setup-ruby@v1
|
14
21
|
with:
|
15
22
|
bundler-cache: true
|
16
|
-
ruby-version:
|
23
|
+
ruby-version: ${{ matrix.ruby }}
|
17
24
|
- name: Test
|
18
|
-
run:
|
25
|
+
run: |
|
26
|
+
bundle exec rake test
|
27
|
+
bundle exec rake stree:check
|
19
28
|
automerge:
|
20
29
|
name: AutoMerge
|
21
30
|
needs: ci
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,24 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [1.2.1] - 2022-07-22
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
|
13
|
+
- Fix formatting for when empty `%div` or `%div` with no attributes and just children is present.
|
14
|
+
|
15
|
+
## [1.2.0] - 2022-05-13
|
16
|
+
|
17
|
+
### Added
|
18
|
+
|
19
|
+
- An optional `maxwidth` second argument to `SyntaxTree::Haml.format`.
|
20
|
+
|
21
|
+
## [1.1.0] - 2022-04-22
|
22
|
+
|
23
|
+
### Added
|
24
|
+
|
25
|
+
- Support for Ruby 2.7 added back.
|
26
|
+
|
9
27
|
## [1.0.1] - 2022-03-31
|
10
28
|
|
11
29
|
### Changed
|
@@ -24,7 +42,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
|
|
24
42
|
|
25
43
|
- 🎉 Initial release! 🎉
|
26
44
|
|
27
|
-
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree-haml/compare/v1.
|
45
|
+
[unreleased]: https://github.com/ruby-syntax-tree/syntax_tree-haml/compare/v1.2.1...HEAD
|
46
|
+
[1.2.1]: https://github.com/ruby-syntax-tree/syntax_tree-haml/compare/v1.2.0...v1.2.1
|
47
|
+
[1.2.0]: https://github.com/ruby-syntax-tree/syntax_tree-haml/compare/v1.1.0...v1.2.0
|
48
|
+
[1.1.0]: https://github.com/ruby-syntax-tree/syntax_tree-haml/compare/v1.0.1...v1.1.0
|
28
49
|
[1.0.1]: https://github.com/ruby-syntax-tree/syntax_tree-haml/compare/v1.0.0...v1.0.1
|
29
50
|
[1.0.0]: https://github.com/ruby-syntax-tree/syntax_tree-haml/compare/v0.1.0...v1.0.0
|
30
51
|
[0.1.0]: https://github.com/ruby-syntax-tree/syntax_tree-haml/compare/c1264c...v0.1.0
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
syntax_tree-haml (1.
|
4
|
+
syntax_tree-haml (1.2.1)
|
5
5
|
haml (>= 5.2)
|
6
|
+
prettier_print
|
6
7
|
syntax_tree (>= 2.0.1)
|
7
8
|
|
8
9
|
GEM
|
@@ -12,7 +13,8 @@ GEM
|
|
12
13
|
haml (5.2.2)
|
13
14
|
temple (>= 0.8.0)
|
14
15
|
tilt
|
15
|
-
minitest (5.
|
16
|
+
minitest (5.16.2)
|
17
|
+
prettier_print (0.1.0)
|
16
18
|
rake (13.0.6)
|
17
19
|
simplecov (0.21.2)
|
18
20
|
docile (~> 1.1)
|
@@ -20,11 +22,15 @@ GEM
|
|
20
22
|
simplecov_json_formatter (~> 0.1)
|
21
23
|
simplecov-html (0.12.3)
|
22
24
|
simplecov_json_formatter (0.1.4)
|
23
|
-
syntax_tree (2.0
|
25
|
+
syntax_tree (3.2.0)
|
26
|
+
prettier_print
|
24
27
|
temple (0.8.2)
|
25
28
|
tilt (2.0.10)
|
26
29
|
|
27
30
|
PLATFORMS
|
31
|
+
ruby
|
32
|
+
x86_64-darwin-19
|
33
|
+
x86_64-darwin-20
|
28
34
|
x86_64-darwin-21
|
29
35
|
x86_64-linux
|
30
36
|
|
data/Rakefile
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require "rake/testtask"
|
5
|
+
require "syntax_tree/rake_tasks"
|
5
6
|
|
6
7
|
Rake::TestTask.new(:test) do |t|
|
7
8
|
t.libs << "test"
|
@@ -9,4 +10,10 @@ Rake::TestTask.new(:test) do |t|
|
|
9
10
|
t.test_files = FileList["test/**/*_test.rb"]
|
10
11
|
end
|
11
12
|
|
13
|
+
SOURCE_FILES =
|
14
|
+
FileList[%w[Gemfile Rakefile syntax_tree-haml.gemspec lib/**/*.rb test/*.rb]]
|
15
|
+
|
16
|
+
SyntaxTree::Rake::CheckTask.new { |t| t.source_files = SOURCE_FILES }
|
17
|
+
SyntaxTree::Rake::WriteTask.new { |t| t.source_files = SOURCE_FILES }
|
18
|
+
|
12
19
|
task default: :test
|
@@ -0,0 +1,425 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SyntaxTree
|
4
|
+
module Haml
|
5
|
+
class Format < Visitor
|
6
|
+
attr_reader :q
|
7
|
+
|
8
|
+
def initialize(q)
|
9
|
+
@q = q
|
10
|
+
end
|
11
|
+
|
12
|
+
# https://haml.info/docs/yardoc/file.REFERENCE.html#html-comments-
|
13
|
+
def visit_comment(node)
|
14
|
+
with_children(node) do
|
15
|
+
q.text("/")
|
16
|
+
q.text("!") if node.value[:revealed]
|
17
|
+
|
18
|
+
if node.value[:conditional]
|
19
|
+
q.text(node.value[:conditional])
|
20
|
+
elsif node.value[:text]
|
21
|
+
q.text(" #{node.value[:text]}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# https://haml.info/docs/yardoc/file.REFERENCE.html#doctype-
|
27
|
+
def visit_doctype(node)
|
28
|
+
parts = ["!!!"]
|
29
|
+
|
30
|
+
parts << if DOCTYPE_TYPES.key?(node.value[:type])
|
31
|
+
DOCTYPE_TYPES[node.value[:type]]
|
32
|
+
elsif DOCTYPE_VERSIONS.include?(node.value[:version])
|
33
|
+
node.value[:version]
|
34
|
+
else
|
35
|
+
node.value[:type]
|
36
|
+
end
|
37
|
+
|
38
|
+
parts << node.value[:encoding] if node.value[:encoding]
|
39
|
+
q.text(parts.join(" "))
|
40
|
+
end
|
41
|
+
|
42
|
+
# https://haml.info/docs/yardoc/file.REFERENCE.html#filter
|
43
|
+
def visit_filter(node)
|
44
|
+
q.group do
|
45
|
+
q.text(":")
|
46
|
+
q.text(node.value[:name])
|
47
|
+
|
48
|
+
q.indent do
|
49
|
+
q.breakable(force: true)
|
50
|
+
|
51
|
+
segments = node.value[:text].strip.split("\n")
|
52
|
+
q.seplist(segments, -> { q.breakable(force: true) }) do |segment|
|
53
|
+
q.text(segment)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# https://haml.info/docs/yardoc/file.REFERENCE.html#haml-comments--
|
60
|
+
def visit_haml_comment(node)
|
61
|
+
q.text("-#")
|
62
|
+
text = node.value[:text].strip
|
63
|
+
|
64
|
+
if text.include?("\n")
|
65
|
+
q.indent do
|
66
|
+
q.breakable(force: true)
|
67
|
+
q.seplist(
|
68
|
+
text.split("\n"),
|
69
|
+
-> { q.breakable(force: true) }
|
70
|
+
) { |segment| q.text(segment) }
|
71
|
+
end
|
72
|
+
else
|
73
|
+
q.text(" #{text}")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# https://haml.info/docs/yardoc/file.REFERENCE.html#plain-text
|
78
|
+
def visit_plain(node)
|
79
|
+
text = node.value[:text]
|
80
|
+
q.text("\\") if escaped?(text)
|
81
|
+
q.text(text)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Visit the root node of the AST.
|
85
|
+
def visit_root(node)
|
86
|
+
node.children.each do |child|
|
87
|
+
visit(child)
|
88
|
+
q.breakable(force: true)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# https://haml.info/docs/yardoc/file.REFERENCE.html#inserting_ruby
|
93
|
+
def visit_script(node)
|
94
|
+
with_children(node) do
|
95
|
+
q.text("&") if node.value[:escape_html]
|
96
|
+
|
97
|
+
node.value[:preserve] ? q.text("~") : q.text("=")
|
98
|
+
|
99
|
+
q.text(" ")
|
100
|
+
q.text(node.value[:text].strip)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# https://haml.info/docs/yardoc/file.REFERENCE.html#running-ruby--
|
105
|
+
def visit_silent_script(node)
|
106
|
+
q.group do
|
107
|
+
q.text("- ")
|
108
|
+
q.text(node.value[:text].strip)
|
109
|
+
|
110
|
+
node.children.each do |child|
|
111
|
+
if continuation?(node, child)
|
112
|
+
q.breakable(force: true)
|
113
|
+
visit(child)
|
114
|
+
else
|
115
|
+
q.indent do
|
116
|
+
q.breakable(force: true)
|
117
|
+
visit(child)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
LiteralHashValue = Struct.new(:value)
|
125
|
+
|
126
|
+
# When formatting a tag, there are a lot of different kinds of things that
|
127
|
+
# can be printed out. There's the tag name, the attributes, the content,
|
128
|
+
# etc. This object is responsible for housing all of those parts.
|
129
|
+
class PartList
|
130
|
+
attr_reader :node, :parts
|
131
|
+
|
132
|
+
def initialize(node)
|
133
|
+
@node = node
|
134
|
+
@parts = []
|
135
|
+
end
|
136
|
+
|
137
|
+
def <<(part)
|
138
|
+
parts << part
|
139
|
+
end
|
140
|
+
|
141
|
+
def empty?
|
142
|
+
parts.empty?
|
143
|
+
end
|
144
|
+
|
145
|
+
def format(q)
|
146
|
+
if empty? && node.value[:name] == "div"
|
147
|
+
# If we don't have any other parts to print and the tag is a div
|
148
|
+
# then we need to make sure to add that to the beginning. Otherwise
|
149
|
+
# it's implied by the presence of other operators.
|
150
|
+
q.text("%div")
|
151
|
+
else
|
152
|
+
parts.inject(0) do |align, part|
|
153
|
+
part.format(q, align)
|
154
|
+
align + part.length
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
class PlainPart < Struct.new(:value)
|
161
|
+
def format(q, align)
|
162
|
+
q.text(value)
|
163
|
+
end
|
164
|
+
|
165
|
+
def length
|
166
|
+
value.length
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class PrefixPart < Struct.new(:prefix, :value)
|
171
|
+
def format(q, align)
|
172
|
+
q.text("#{prefix}#{value}")
|
173
|
+
end
|
174
|
+
|
175
|
+
def length
|
176
|
+
prefix.length + value.length
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
class HTMLAttributesPart
|
181
|
+
attr_reader :values
|
182
|
+
|
183
|
+
def initialize(raw)
|
184
|
+
@values =
|
185
|
+
raw[1...-1]
|
186
|
+
.split(",")
|
187
|
+
.to_h { |keypair| keypair[1..-1].split("\" => ") }
|
188
|
+
end
|
189
|
+
|
190
|
+
def format(q, align)
|
191
|
+
q.group do
|
192
|
+
q.text("(")
|
193
|
+
q.nest(align) do
|
194
|
+
q.seplist(
|
195
|
+
values,
|
196
|
+
-> { q.fill_breakable },
|
197
|
+
:each_pair
|
198
|
+
) { |key, value| q.text("#{key}=#{value}") }
|
199
|
+
end
|
200
|
+
q.text(")")
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def length
|
205
|
+
values.sum { |key, value| key.length + value.length + 3 }
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class HashAttributesPart < Struct.new(:values)
|
210
|
+
def format(q, align)
|
211
|
+
format_value(q, values)
|
212
|
+
end
|
213
|
+
|
214
|
+
def length
|
215
|
+
values.sum do |key, value|
|
216
|
+
key.length + (value.is_a?(String) ? value : value.to_s).length + 3
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
|
222
|
+
def format_value(q, hash, level = 0)
|
223
|
+
q.group do
|
224
|
+
q.text("{")
|
225
|
+
q.indent do
|
226
|
+
q.group do
|
227
|
+
q.breakable(level == 0 ? "" : " ")
|
228
|
+
q.seplist(hash, nil, :each_pair) do |key, value|
|
229
|
+
q.text(Format.hash_key(key))
|
230
|
+
q.text(" ")
|
231
|
+
|
232
|
+
if value.is_a?(Hash)
|
233
|
+
format_value(q, value, level + 1)
|
234
|
+
else
|
235
|
+
q.text(Format.hash_value(value))
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
q.breakable(level == 0 ? "" : " ")
|
242
|
+
q.text("}")
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
def self.hash_key(key)
|
248
|
+
key.match?(/^@|[-:]/) ? "\"#{key}\":" : "#{key}:"
|
249
|
+
end
|
250
|
+
|
251
|
+
def self.hash_value(value)
|
252
|
+
case value
|
253
|
+
when LiteralHashValue
|
254
|
+
value.value
|
255
|
+
when String
|
256
|
+
"\"#{Quotes.normalize(value, "\"")}\""
|
257
|
+
else
|
258
|
+
value.to_s
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
# Visit a tag node.
|
263
|
+
def visit_tag(node)
|
264
|
+
parts = PartList.new(node)
|
265
|
+
|
266
|
+
# If we have a tag that isn't a div, then we need to print out that
|
267
|
+
# name of that tag first. If it is a div, first we'll check if there
|
268
|
+
# are any other things that would force us to print out the div
|
269
|
+
# explicitly, and otherwise we'll leave it off.
|
270
|
+
if node.value[:name] != "div"
|
271
|
+
parts << PrefixPart.new("%", node.value[:name])
|
272
|
+
end
|
273
|
+
|
274
|
+
# If we have a class attribute, then we're going to print that here
|
275
|
+
# using the special class syntax.
|
276
|
+
if node.value[:attributes].key?("class")
|
277
|
+
parts << PrefixPart.new(
|
278
|
+
".",
|
279
|
+
node.value[:attributes]["class"].tr(" ", ".")
|
280
|
+
)
|
281
|
+
end
|
282
|
+
|
283
|
+
# If we have an id attribute, then we're going to print that here
|
284
|
+
# using the special id syntax.
|
285
|
+
if node.value[:attributes].key?("id")
|
286
|
+
parts << PrefixPart.new("#", node.value[:attributes]["id"])
|
287
|
+
end
|
288
|
+
|
289
|
+
# If we're using dynamic attributes on this tag, then they come in as
|
290
|
+
# a string that looks like the output of Hash#inspect from Ruby. So
|
291
|
+
# here we're going to split it all up and print it out nicely.
|
292
|
+
if node.value[:dynamic_attributes].new
|
293
|
+
parts << HTMLAttributesPart.new(node.value[:dynamic_attributes].new)
|
294
|
+
end
|
295
|
+
|
296
|
+
# If there are any static attributes that are not class or id (because
|
297
|
+
# we already took care of those), then we're going to print them out
|
298
|
+
# here.
|
299
|
+
static =
|
300
|
+
node.value[:attributes].reject do |key, _|
|
301
|
+
key == "class" || key == "id"
|
302
|
+
end
|
303
|
+
|
304
|
+
parts << HashAttributesPart.new(static) if static.any?
|
305
|
+
|
306
|
+
# If there are dynamic attributes that don't use the newer syntax, then
|
307
|
+
# we're going to print them out here.
|
308
|
+
if node.value[:dynamic_attributes].old
|
309
|
+
parts << PlainPart.new("%div") if parts.empty?
|
310
|
+
|
311
|
+
if ::Haml::AttributeParser.available?
|
312
|
+
dynamic = parse_attributes(node.value[:dynamic_attributes].old)
|
313
|
+
parts << if dynamic.is_a?(LiteralHashValue)
|
314
|
+
PlainPart.new(dynamic.value)
|
315
|
+
else
|
316
|
+
HashAttributesPart.new(dynamic)
|
317
|
+
end
|
318
|
+
else
|
319
|
+
parts << PlainPart.new(node.value[:dynamic_attributes].old)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
# https://haml.info/docs/yardoc/file.REFERENCE.html#object-reference-
|
324
|
+
if node.value[:object_ref] != :nil
|
325
|
+
parts << PlainPart.new("%div") if parts.empty?
|
326
|
+
parts << PlainPart.new(node.value[:object_ref])
|
327
|
+
end
|
328
|
+
|
329
|
+
# https://haml.info/docs/yardoc/file.REFERENCE.html#whitespace-removal--and-
|
330
|
+
parts << PlainPart.new(">") if node.value[:nuke_outer_whitespace]
|
331
|
+
parts << PlainPart.new("<") if node.value[:nuke_inner_whitespace]
|
332
|
+
|
333
|
+
# https://haml.info/docs/yardoc/file.REFERENCE.html#empty-void-tags-
|
334
|
+
parts << PlainPart.new("/") if node.value[:self_closing]
|
335
|
+
|
336
|
+
# If there is a value part, then we're going to print slightly
|
337
|
+
# differently as the value goes after the tag declaration.
|
338
|
+
if (value = node.value[:value]) && !value.empty?
|
339
|
+
with_children(node) do
|
340
|
+
q.group { parts.format(q) }
|
341
|
+
q.indent do
|
342
|
+
# Split between the declaration of the tag and the contents of the
|
343
|
+
# tag.
|
344
|
+
q.breakable("")
|
345
|
+
|
346
|
+
if node.value[:parse] && value.match?(/#[{$@]/)
|
347
|
+
# There's a weird case here where if the value includes
|
348
|
+
# interpolation and it's marked as { parse: true }, then we
|
349
|
+
# don't actually want the = prefix, and we want to remove extra
|
350
|
+
# escaping.
|
351
|
+
q.if_break { q.text("") }.if_flat { q.text(" ") }
|
352
|
+
q.text(value[1...-1].gsub(/\\"/, "\""))
|
353
|
+
elsif node.value[:parse]
|
354
|
+
q.text("= ")
|
355
|
+
q.text(value)
|
356
|
+
else
|
357
|
+
q.if_break { q.text("") }.if_flat { q.text(" ") }
|
358
|
+
q.text(value)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
else
|
363
|
+
with_children(node) { parts.format(q) }
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
private
|
368
|
+
|
369
|
+
# When printing out sequences of silent scripts, sometimes subsequent nodes
|
370
|
+
# will be continuations of previous nodes. In that case we want to dedent
|
371
|
+
# them to match.
|
372
|
+
def continuation?(node, child)
|
373
|
+
return false if child.type != :silent_script
|
374
|
+
|
375
|
+
case [node.value[:keyword], child.value[:keyword]]
|
376
|
+
in ["case", "in" | "when" | "else"]
|
377
|
+
true
|
378
|
+
in ["if" | "unless", "elsif" | "else"]
|
379
|
+
true
|
380
|
+
else
|
381
|
+
false
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
# If a node comes in as the plain type but starts with one of the special
|
386
|
+
# characters that haml parses, then we need to escape it with a \ when
|
387
|
+
# printing.
|
388
|
+
def escaped?(text)
|
389
|
+
::Haml::Parser::SPECIAL_CHARACTERS.any? do |special|
|
390
|
+
text.start_with?(special)
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
# Take a source string and attempt to parse it into a set of attributes that
|
395
|
+
# can be used to format the source.
|
396
|
+
def parse_attributes(source)
|
397
|
+
case Ripper.sexp(source)
|
398
|
+
in [:program, [[:hash, *], *]] if parsed =
|
399
|
+
::Haml::AttributeParser.parse(source)
|
400
|
+
parsed.to_h { |key, value| [key, parse_attributes(value)] }
|
401
|
+
in [:program, [[:string_literal, *], *]]
|
402
|
+
source[1...-1]
|
403
|
+
else
|
404
|
+
LiteralHashValue.new(source)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def with_children(node)
|
409
|
+
if node.children.empty?
|
410
|
+
q.group { yield }
|
411
|
+
else
|
412
|
+
q.group do
|
413
|
+
q.group { yield }
|
414
|
+
q.indent do
|
415
|
+
node.children.each do |child|
|
416
|
+
q.breakable(force: true)
|
417
|
+
visit(child)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
end
|