<commit_before>module ComponentFactory
  def component_factory(elem)
    inner = elem.children.map(&:to_s).join
    # TODO:  Handle changed names
    transform_method = :"_transform_#{component_lookup[elem.name]}"
    return unless respond_to?(transform_method)
    Nokogiri::XML(send(transform_method, elem, inner)).root
  end

  def _pass_through_attributes(elem)
    ignored = ['class', 'id', 'href', 'size', 'large', 'no-expander', 'small', 'target']
    elem.attributes.reject { |e| ignored.include?(e.downcase) }.map do |name, value|
      %{#{name}="#{value}" }
    end.join
  end

  def _has_class(elem, klass)
    elem.attribute('class') && elem.attribute('class').value.include?(klass)
  end

  def _class_array(elem, defaults = [])
    attribute = elem.attribute('class')
    defaults.concat(attribute.value.split(' ')) if attribute
    defaults
  end

  def _target_attribute(elem)
    elem.attributes['target'] ? %{ target="#{elem.attributes['target']}"} : ''
  end

  def _transform_button(component, inner)
    expand = _has_class(component, 'expand')
    if component.attr('href')
      target = _target_attribute(component)
      inner = if expand
                %{<a href="#{component.attr('href')}"#{target} align="center" class="float-center">#{inner}</a>}
              else
                %{<a href="#{component.attr('href')}"#{target}>#{inner}</a>}
              end
    end
    inner = "<center>#{inner}</center>" if expand

    classes = _class_array(component, ['button'])
    if expand
      %{<table class="#{classes.join(' ')}"><tr><td><table><tr><td>#{inner}</td></tr></table></td><td class="expander"></td></tr></table>}
    else
      %{<table class="#{classes.join(' ')}"><tr><td><table><tr><td>#{inner}</td></tr></table></td></tr></table>}
    end
  end

  def _transform_menu(component, inner)
    classes = _class_array(component, ['menu'])
    %{<table class="#{classes.join(' ')}"><tr><td><table><tr>#{inner}</tr></table></td></tr></table>}
  end

  def _transform_menu_item(component, inner)
    target = _target_attribute(component)
    %{<th class="menu-item"><a href="#{component.attr('href')}"#{target}>#{inner}</a></th>}
  end

  def _transform_container(component, inner)
    classes = _class_array(component, ['container'])
    %{<table class="#{classes.join(' ')}"><tbody><tr><td>#{inner}</td></tr></tbody></table>}
  end

  def _transform_row(component, inner)
    classes = _class_array(component, ['row'])
    attrs = _pass_through_attributes(component)
    %{<table #{attrs}class="#{classes.join(' ')}"><tbody><tr>#{inner}</tr></tbody></table>}
  end

  # in inky.js this is factored out into makeClumn.  TBD if we need that here.
  def _transform_columns(component, inner)
    col_count = component.parent.elements.size

    small_val = component.attr('small') if component.attribute('small')
    large_val = component.attr('large') if component.attribute('large')

    small_size = small_val || column_count
    large_size = large_val || small_val || (column_count / col_count).to_i

    classes = _class_array(component, ["small-#{small_size}", "large-#{large_size}", "columns"])

    classes.push('first') unless component.previous_element
    classes.push('last') unless component.next_element

    subrows = component.elements.css(".row").to_a.concat(component.elements.css("row").to_a)
    expander = %{<th class="expander"></th>} if large_size.to_i == column_count && subrows.empty?

    %{<th class="#{classes.join(' ')}" #{_pass_through_attributes(component)}><table><tr><th>#{inner}</th>#{expander}</tr></table></th>}
  end

  def _transform_block_grid(component, inner)
    classes = _class_array(component, ['block-grid', "up-#{component.attr('up')}"])
    %{<table class="#{classes.join(' ')}"><tr>#{inner}</tr></table>}
  end

  def _transform_center(component, _inner)
    # NOTE:  Using children instead of elements because elements.to_a
    # sometimes appears to miss elements that show up in size
    component.elements.to_a.each do |child|
      child['align'] = 'center'
      child_classes = _class_array(child, ['float-center'])
      child['class'] = child_classes.join(' ')
      items = component.elements.css(".menu-item").to_a.concat(component.elements.css("item").to_a)
      items.each do |item|
        item_classes = _class_array(item, ['float-center'])
        item['class'] = item_classes.join(' ')
      end
    end
    component.to_s
  end

  def _transform_callout(component, inner)
    classes = _class_array(component, ['callout-inner'])
    %{<table class="callout"><tr><th class="#{classes.join(' ')}">#{inner}</th><th class="expander"></th></tr></table>}
  end

  def _transform_spacer(component, _inner)
    classes = _class_array(component, ['spacer'])
    size = component.attr('size')
    size_sm = component.attr('size-sm')
    size_lg = component.attr('size-lg')
    if size_sm || size_lg
      html = ''
      if size_sm
        html += %{<table class="#{classes.join(' ')} hide-for-large"><tbody><tr><td height="#{size_sm}px" style="font-size:#{size_sm}px;line-height:#{size_sm}px;">&#xA0;</td></tr></tbody></table>}
      end
      if size_lg
        html += %{<table class="#{classes.join(' ')} show-for-large"><tbody><tr><td height="#{size_lg}px" style="font-size:#{size_lg}px;line-height:#{size_lg}px;">&#xA0;</td></tr></tbody></table>}
      end
      if size_sm && size_lg
        html = "<span>#{html}</span>"<commit_msg>Prefer << to += when possible<commit_after>module ComponentFactory
  def component_factory(elem)
    inner = elem.children.map(&:to_s).join
    # TODO:  Handle changed names
    transform_method = :"_transform_#{component_lookup[elem.name]}"
    return unless respond_to?(transform_method)
    Nokogiri::XML(send(transform_method, elem, inner)).root
  end

  def _pass_through_attributes(elem)
    ignored = ['class', 'id', 'href', 'size', 'large', 'no-expander', 'small', 'target']
    elem.attributes.reject { |e| ignored.include?(e.downcase) }.map do |name, value|
      %{#{name}="#{value}" }
    end.join
  end

  def _has_class(elem, klass)
    elem.attribute('class') && elem.attribute('class').value.include?(klass)
  end

  def _class_array(elem, defaults = [])
    attribute = elem.attribute('class')
    defaults.concat(attribute.value.split(' ')) if attribute
    defaults
  end

  def _target_attribute(elem)
    elem.attributes['target'] ? %{ target="#{elem.attributes['target']}"} : ''
  end

  def _transform_button(component, inner)
    expand = _has_class(component, 'expand')
    if component.attr('href')
      target = _target_attribute(component)
      inner = if expand
                %{<a href="#{component.attr('href')}"#{target} align="center" class="float-center">#{inner}</a>}
              else
                %{<a href="#{component.attr('href')}"#{target}>#{inner}</a>}
              end
    end
    inner = "<center>#{inner}</center>" if expand

    classes = _class_array(component, ['button'])
    if expand
      %{<table class="#{classes.join(' ')}"><tr><td><table><tr><td>#{inner}</td></tr></table></td><td class="expander"></td></tr></table>}
    else
      %{<table class="#{classes.join(' ')}"><tr><td><table><tr><td>#{inner}</td></tr></table></td></tr></table>}
    end
  end

  def _transform_menu(component, inner)
    classes = _class_array(component, ['menu'])
    %{<table class="#{classes.join(' ')}"><tr><td><table><tr>#{inner}</tr></table></td></tr></table>}
  end

  def _transform_menu_item(component, inner)
    target = _target_attribute(component)
    %{<th class="menu-item"><a href="#{component.attr('href')}"#{target}>#{inner}</a></th>}
  end

  def _transform_container(component, inner)
    classes = _class_array(component, ['container'])
    %{<table class="#{classes.join(' ')}"><tbody><tr><td>#{inner}</td></tr></tbody></table>}
  end

  def _transform_row(component, inner)
    classes = _class_array(component, ['row'])
    attrs = _pass_through_attributes(component)
    %{<table #{attrs}class="#{classes.join(' ')}"><tbody><tr>#{inner}</tr></tbody></table>}
  end

  # in inky.js this is factored out into makeClumn.  TBD if we need that here.
  def _transform_columns(component, inner)
    col_count = component.parent.elements.size

    small_val = component.attr('small') if component.attribute('small')
    large_val = component.attr('large') if component.attribute('large')

    small_size = small_val || column_count
    large_size = large_val || small_val || (column_count / col_count).to_i

    classes = _class_array(component, ["small-#{small_size}", "large-#{large_size}", "columns"])

    classes.push('first') unless component.previous_element
    classes.push('last') unless component.next_element

    subrows = component.elements.css(".row").to_a.concat(component.elements.css("row").to_a)
    expander = %{<th class="expander"></th>} if large_size.to_i == column_count && subrows.empty?

    %{<th class="#{classes.join(' ')}" #{_pass_through_attributes(component)}><table><tr><th>#{inner}</th>#{expander}</tr></table></th>}
  end

  def _transform_block_grid(component, inner)
    classes = _class_array(component, ['block-grid', "up-#{component.attr('up')}"])
    %{<table class="#{classes.join(' ')}"><tr>#{inner}</tr></table>}
  end

  def _transform_center(component, _inner)
    # NOTE:  Using children instead of elements because elements.to_a
    # sometimes appears to miss elements that show up in size
    component.elements.to_a.each do |child|
      child['align'] = 'center'
      child_classes = _class_array(child, ['float-center'])
      child['class'] = child_classes.join(' ')
      items = component.elements.css(".menu-item").to_a.concat(component.elements.css("item").to_a)
      items.each do |item|
        item_classes = _class_array(item, ['float-center'])
        item['class'] = item_classes.join(' ')
      end
    end
    component.to_s
  end

  def _transform_callout(component, inner)
    classes = _class_array(component, ['callout-inner'])
    %{<table class="callout"><tr><th class="#{classes.join(' ')}">#{inner}</th><th class="expander"></th></tr></table>}
  end

  def _transform_spacer(component, _inner)
    classes = _class_array(component, ['spacer'])
    size = component.attr('size')
    size_sm = component.attr('size-sm')
    size_lg = component.attr('size-lg')
    if size_sm || size_lg
      html = ''
      if size_sm
        html << %{<table class="#{classes.join(' ')} hide-for-large"><tbody><tr><td height="#{size_sm}px" style="font-size:#{size_sm}px;line-height:#{size_sm}px;">&#xA0;</td></tr></tbody></table>}
      end
      if size_lg
        html << %{<table class="#{classes.join(' ')} show-for-large"><tbody><tr><td height="#{size_lg}px" style="font-size:#{size_lg}px;line-height:#{size_lg}px;">&#xA0;</td></tr></tbody></table>}
      end
      if size_sm && size_lg
        html = "<span>#{html}</span>"
{'fraction_non_alphanumeric': 0.19669117647058823, 'fraction_numerical': 0.0003676470588235294, 'mean_word_length': 4.256521739130434, 'pattern_counts': {'":': 0, '<': 209, '<?xml version=': 0, '>': 203, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6310380', 'n_tokens_mistral': 3543, 'n_tokens_neox': 3544, 'n_words': 620}