class TiptapService
# NOTE: node must be deep symbolized keys
def self.used_tags_and_libelle_for(node, tags = Set.new)
case node
in type: 'mention', attrs: { id:, label: }, **rest
tags << [id, label]
in { content:, **rest } if content.is_a?(Array)
content.each { used_tags_and_libelle_for(_1, tags) }
in type:, **rest
# noop
end
tags
end
def to_html(node, substitutions = {})
return '' if node.nil?
children(node[:content], substitutions, 0)
end
def to_path(node, substitutions = {})
return '' if node.nil?
children_path(node[:content], substitutions)
end
private
def initialize
@body_started = false
end
def children_path(content, substitutions)
content.map { node_to_path(_1, substitutions) }.join
end
def node_to_path(node, substitutions)
case node
in type: 'paragraph', content:
children_path(content, substitutions)
in type: 'text', text:, **rest
text.strip
in type: 'mention', attrs: { id: }, **rest
substitutions.fetch(id) { "--#{id}--" }
end
end
def children(content, substitutions, level)
content.map { node_to_html(_1, substitutions, level) }.join
end
def node_to_html(node, substitutions, level)
if level == 0 && !@body_started && node[:type].in?(['paragraph', 'heading']) && node.key?(:content)
@body_started = true
body_start_mark = " class=\"body-start\""
end
case node
in type: 'header', content:
"
#{children(content, substitutions, level + 1)}
" in type: 'title', content:, **rest "