mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Add script to upgrade HAML syntax
[skip-ci]
This commit is contained in:
110
lib/haml_up.rb
Normal file
110
lib/haml_up.rb
Normal file
@@ -0,0 +1,110 @@
|
||||
# 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.map do |child|
|
||||
[child] + flatten_tree(child)
|
||||
end.flatten
|
||||
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
|
||||
|
||||
"#{key.inspect} => #{value}"
|
||||
end
|
||||
|
||||
"{ #{entries.join(', ')} }"
|
||||
end
|
||||
end
|
||||
22
script/haml-up.rb
Executable file
22
script/haml-up.rb
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env 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" }
|
||||
#
|
||||
# This script rewrites HAML files automatically. It may be used like:
|
||||
#
|
||||
# git ls-files '*.haml' | while read f; do ./haml-up.rb "$f"; done
|
||||
#
|
||||
require "haml_up"
|
||||
|
||||
puts ARGV[0]
|
||||
HamlUp.new.upgrade_file(ARGV[0])
|
||||
50
spec/lib/haml_up_spec.rb
Normal file
50
spec/lib/haml_up_spec.rb
Normal file
@@ -0,0 +1,50 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'haml_up'
|
||||
|
||||
describe HamlUp do
|
||||
describe "#rewrite_template" do
|
||||
it "preserves a simple template" do
|
||||
original = "%p This is a paragraph"
|
||||
template = call(original)
|
||||
expect(template).to eq original
|
||||
end
|
||||
|
||||
it "rewrites non-standard attribute hashes" do
|
||||
original = "%p{ng: {click: 'action', show: 'condition'}} label"
|
||||
template = call(original)
|
||||
expect(template).to eq "%p{ \"ng-click\" => 'action', \"ng-show\" => 'condition' } label"
|
||||
end
|
||||
|
||||
it "preserves standard attribute hashes" do
|
||||
original = "%p{data: {click: 'action', show: 'condition'}} label"
|
||||
template = call(original)
|
||||
expect(template).to eq original
|
||||
end
|
||||
|
||||
it "preserves standard attribute hashes while rewriting others" do
|
||||
original = "%p{data: {click: 'standard'}, ng: {click: 'not'}} label"
|
||||
template = call(original)
|
||||
expect(template).to eq "%p{ \"data\" => {click: 'standard'}, \"ng-click\" => 'not' } label"
|
||||
end
|
||||
|
||||
it "rewrites multi-line attributes" do
|
||||
original = <<~HAML
|
||||
%li{ ng: { class: "{active: selector.active}" } }
|
||||
%a{ "tooltip" => "{{selector.object.value}}", "tooltip-placement" => "bottom",
|
||||
ng: { transclude: true, class: "{active: selector.active, 'has-tip': selector.object.value}" } }
|
||||
HAML
|
||||
expected = <<~HAML
|
||||
%li{ "ng-class" => "{active: selector.active}" }
|
||||
%a{ "tooltip" => "{{selector.object.value}}", "tooltip-placement" => "bottom", "ng-transclude" => true, "ng-class" => "{active: selector.active, 'has-tip': selector.object.value}" }
|
||||
HAML
|
||||
template = call(original)
|
||||
expect(template).to eq expected
|
||||
end
|
||||
|
||||
def call(original)
|
||||
original.dup.tap { |t| subject.rewrite_template(t) }
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user