lib/erb/formatter.rb in erb-formatter-0.6.0 vs lib/erb/formatter.rb in erb-formatter-0.7.0
- old
+ new
@@ -46,14 +46,21 @@
HTML_TAG_OPEN = %r{<(#{TAG_NAME})((?:#{HTML_ATTR})*)(\s*?)(/>|>)}m
HTML_TAG_CLOSE = %r{</\s*(#{TAG_NAME})\s*>}
SELF_CLOSING_TAG = /\A(area|base|br|col|command|embed|hr|img|input|keygen|link|menuitem|meta|param|source|track|wbr)\z/i
- RUBY_OPEN_BLOCK = ->(code) do
- # is nil when the parsing is broken, meaning it's an open expression
- Ripper.sexp(code).nil?
- end.freeze
+ begin
+ require 'prism' # ruby 3.3
+ RUBY_OPEN_BLOCK = Prism.method(:parse_failure?)
+ rescue LoadError
+ require 'ripper'
+ RUBY_OPEN_BLOCK = ->(code) do
+ # is nil when the parsing is broken, meaning it's an open expression
+ Ripper.sexp(code).nil?
+ end.freeze
+ end
+
RUBY_CLOSE_BLOCK = /\Aend\z/
RUBY_REOPEN_BLOCK = /\A(else|elsif\b(.*)|when\b(.*))\z/
RUBOCOP_STDIN_MARKER = "===================="
@@ -66,18 +73,19 @@
def self.format(source, filename: nil)
new(source, filename: filename).html
end
- def initialize(source, line_width: 80, single_class_per_line: false, filename: nil, debug: $DEBUG)
+ def initialize(source, line_width: 80, single_class_per_line: false, filename: nil, css_class_sorter: nil, debug: $DEBUG)
@original_source = source
@filename = filename || '(erb)'
@line_width = line_width
@source = remove_front_matter source.dup
@html = +""
@debug = debug
@single_class_per_line = single_class_per_line
+ @css_class_sorter = css_class_sorter
html.extend DebugShovel if @debug
@tag_stack = []
@pre_pos = 0
@@ -116,12 +124,14 @@
def format_attributes(tag_name, attrs, tag_closing)
return "" if attrs.strip.empty?
plain_attrs = attrs.tr("\n", " ").squeeze(" ").gsub(erb_tags_regexp, erb_tags)
- return " #{plain_attrs}" if "<#{tag_name} #{plain_attrs}#{tag_closing}".size <= line_width
+ within_line_width = "<#{tag_name} #{plain_attrs}#{tag_closing}".size <= line_width
+ return " #{plain_attrs}" if within_line_width && !@css_class_sorter && !plain_attrs.match?(/ class=/)
+
attr_html = ""
tag_stack_push(['attr='], attrs)
attrs.scan(ATTR).flatten.each do |attr|
attr.strip!
@@ -131,12 +141,14 @@
attr_html << indented("#{name}")
next
end
value_parts = value[1...-1].strip.split(/\s+/)
+ value_parts.sort_by!(&@css_class_sorter) if name == 'class' && @css_class_sorter
- full_attr = indented("#{name}=#{value[0]}#{value_parts.join(" ")}#{value[-1]}")
+ full_attr = "#{name}=#{value[0]}#{value_parts.join(" ")}#{value[-1]}"
+ full_attr = within_line_width ? " #{full_attr}" : indented(full_attr)
if full_attr.size > line_width && MULTILINE_ATTR_NAMES.include?(name) && attr.match?(QUOTED_ATTR)
attr_html << indented("#{name}=#{value[0]}")
tag_stack_push('attr"', value)
@@ -156,17 +168,17 @@
attr_html << indented(value_part)
end
end
tag_stack_pop('attr"', value)
- attr_html << indented(value[-1])
+ attr_html << (within_line_width ? value[-1] : indented(value[-1]))
else
attr_html << full_attr
end
end
tag_stack_pop(['attr='], attrs)
- attr_html << indented("")
+ attr_html << indented("") unless within_line_width
attr_html
end
def tag_stack_push(tag_name, code)
tag_stack << [tag_name, code]