mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-25 20:46:48 +00:00
119 lines
2.9 KiB
Ruby
119 lines
2.9 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Upgrade HAML attribute syntax to prepare for HAML 6.
|
|
#
|
|
# HAML 6 stopped supporting nested hash attributes other than `data` and `aria`.
|
|
# We used to be able to write:
|
|
#
|
|
# %div{ ng: { class: "upper", bind: "model" } }
|
|
#
|
|
# This needs to be written in a flat structure now:
|
|
#
|
|
# %div{ "ng-class" => "upper", "ng-bind" => "model" }
|
|
#
|
|
require "fileutils"
|
|
require "haml"
|
|
|
|
class HamlUp
|
|
def upgrade_file(filename)
|
|
template = File.read(filename)
|
|
rewrite_template(template)
|
|
File.write(filename, template)
|
|
end
|
|
|
|
def rewrite_template(template)
|
|
haml_attributes(template).compact.each do |attributes|
|
|
rewrite_attributes(template, attributes)
|
|
end
|
|
end
|
|
|
|
def rewrite_attributes(template, original)
|
|
attributes = parse_attributes(original)
|
|
|
|
if attributes.nil? # parser failed
|
|
puts "Warning: failed to parse:\n" # rubocop:disable Rails/Output
|
|
puts original # rubocop:disable Rails/Output
|
|
return
|
|
end
|
|
|
|
parse_deprecated_hashes(attributes)
|
|
|
|
to_transform = attributes.select { |_k, v| v.is_a? Hash }
|
|
|
|
return if to_transform.empty?
|
|
|
|
to_transform.each do |key, hash|
|
|
add_full_keys(attributes, key, hash)
|
|
attributes.delete(key)
|
|
end
|
|
|
|
replace_attributes(template, original, attributes)
|
|
end
|
|
|
|
def haml_attributes(template)
|
|
options = Haml::Options.new
|
|
parsed_tree = Haml::Parser.new(options).call(template)
|
|
elements = flatten_tree(parsed_tree)
|
|
elements.map { |e| e.value[:dynamic_attributes]&.old }
|
|
end
|
|
|
|
def flatten_tree(parent)
|
|
parent.children.flat_map do |child|
|
|
[child, *flatten_tree(child)]
|
|
end
|
|
end
|
|
|
|
def parse_attributes(string)
|
|
Haml::AttributeParser.parse(string)
|
|
end
|
|
|
|
def parse_deprecated_hashes(hash)
|
|
hash.each do |key, value|
|
|
next if ["aria", "data"].include?(key)
|
|
|
|
parsed = parse_attributes(value)
|
|
next unless parsed.is_a? Hash
|
|
|
|
parse_deprecated_hashes(parsed)
|
|
hash[key] = parsed
|
|
end
|
|
end
|
|
|
|
def add_full_keys(attributes, key, hash)
|
|
hash.each do |subkey, value|
|
|
full_key = "#{key}-#{subkey}"
|
|
if value.is_a? Hash
|
|
add_full_keys(attributes, full_key, value)
|
|
else
|
|
attributes[full_key] = value
|
|
end
|
|
end
|
|
end
|
|
|
|
def replace_attributes(template, original, attributes)
|
|
parsed_lines = original.split("\n")
|
|
lines_as_regex = parsed_lines.map(&Regexp.method(:escape))
|
|
pattern = lines_as_regex.join("\n\s*")
|
|
|
|
template.gsub!(/#{pattern}/, stringify(attributes))
|
|
end
|
|
|
|
def stringify(hash)
|
|
entries = hash.map do |key, value|
|
|
value = stringify(value) if value.is_a? Hash
|
|
|
|
# We prefer the Ruby 1.9 hash syntax with symbols followed by a colon
|
|
# like this:
|
|
#
|
|
# %button{ disabled: true, "ng-class": "primary-button" }
|
|
#
|
|
# Symbols start with `:` which we slice off. It gets appended below.
|
|
key = key.to_sym.inspect.slice(1..-1)
|
|
|
|
"#{key}: #{value}"
|
|
end
|
|
|
|
"{ #{entries.join(', ')} }"
|
|
end
|
|
end
|