module Ariadne::Static::GenerateStructure
def call
def call components = Ariadne::BaseComponent.descendants.sort_by(&:name) - [Ariadne::BaseComponent] component_docs = components.each_with_object({}) do |component, memo| docs = registry.find(component) preview_data = previews.find do |preview| preview["component"] == docs.metadata[:title] end arg_data = args.find do |component_args| component_args["component"] == docs.metadata[:title] end slot_docs = docs.slot_methods.map do |slot_method| param_tags = slot_method.tags(:param) description = if slot_method.base_docstring.to_s.present? render_erb_ignoring_markdown_code_fences(slot_method.base_docstring).force_encoding("UTF-8") else "" end { "name" => slot_method.name, "description" => description, "parameters" => serialize_params(param_tags, component), } end mtds = docs.non_slot_methods.select do |mtd| next false if mtd.base_docstring.to_s.blank? next false if SKIP_METHODS.include?(mtd.name) method_location, = mtd.files.first class_location, = docs.docs.files.first method_location == class_location end method_docs = mtds.map do |mtd| param_tags = mtd.tags(:param) { "name" => mtd.name, "description" => render_erb_ignoring_markdown_code_fences(mtd.base_docstring), "parameters" => serialize_params(param_tags, component), } end description = if component == Ariadne::BaseComponent docs.base_docstring else render_erb_ignoring_markdown_code_fences(docs.base_docstring) end accessibility_docs = if (accessibility_tag_text = docs.tags(:accessibility)&.first&.text) render_erb_ignoring_markdown_code_fences(accessibility_tag_text) end behavior_docs = if (behavior_tag_text = docs.tags(:behaviors)&.first&.text) render_erb_ignoring_markdown_code_fences(behavior_tag_text) end memo[component.name] = { "fully_qualified_name" => component.name, "description" => description, "accessibility_docs" => accessibility_docs, "behavior_docs" => behavior_docs, "is_form_component" => docs.manifest_entry.form_component?, "requires_js" => docs.manifest_entry.requires_js?, **arg_data, "slots" => slot_docs, "methods" => method_docs, "previews" => (preview_data || {}).fetch("examples", []), "subcomponents" => [], } end Ariadne::BaseComponent.descendants.sort_by(&:name).each do |component| fq_class = component.name.to_s.split("::") fq_class.shift # remove Ariadne:: type = fq_class.shift # remove {UI,Form,*}:: parent, *child = *fq_class next if child.empty? || child.length < 2 parent_class = "Ariadne::#{type}".constantize parent_class = parent_class.const_get(parent) parent_docs = component_docs["#{parent_class}::Component"] next unless parent_docs if (child_docs = component_docs.delete(component.name)) parent_docs["subcomponents"] << child_docs end end toc_categories = { "UI" => [], "Form" => [], "Layout" => [], "Behaviors" => [], } component_docs.values.each do |component| type, name = component["short_name"].split("::", 2) next unless toc_categories[type] # not a required category # removes children from toc, like `Ariadne::UI::Accordion::Item`, # by not adding the component to the TOC if it has more than one level of nesting next if name.include?("::") slug = component["short_name"].gsub("::", "/").downcase toc_categories[type] << { "name" => name, "slug" => slug, } File.open(File.join(DEFAULT_STATIC_PATH, FILE_NAMES[:toc]), "w") do |f| f.write(JSON.pretty_generate(toc_categories)) f.write($INPUT_RECORD_SEPARATOR) end end component_docs.values end