{#
  MACRO: format a post-paragraph link reference in RST
#}{%  macro format_link_reference(link, label)
%}{{    ".. _%s: %s" | format(label, link)
}}{%  endmacro
%}


{#
  MACRO: format commit summary line
#}{%  macro format_commit_summary_line(commit)
%}{#    # Check for Parsing Error
#}{%    if commit.error is undefined
%}{#
   #      # Add any message links to the commit summary line
#}{%      set summary_line = commit_msg_links(commit)
%}{#
#}{%      if commit.scope
%}{%        set summary_line = "**%s**: %s" | format(commit.scope, summary_line)
%}{%      endif
%}{#
   #      # Return the modified summary_line
#}{{      summary_line
}}{#
#}{%    else
%}{#      # Return the first line of the commit if there was a Parsing Error
#}{{      (commit.commit.message | string).split("\n", maxsplit=1)[0]
}}{%    endif
%}{%  endmacro
%}


{#
  MACRO: Create & return an non-inline RST link from a commit message
  - Returns empty string if no PR/MR identifier is found
#}{%  macro extract_pr_link_reference(commit)
%}{%    if commit.error is undefined
%}{%      set summary_line = commit.descriptions[0]
%}{#
#}{%      if commit.linked_merge_request != ""
%}{#        # Create a PR/MR reference url
#}{{        format_link_reference(
              commit.linked_merge_request | pull_request_url,
              commit.linked_merge_request,
            )
}}{%      endif
%}{%    endif
%}{%  endmacro
%}


{#
  MACRO: formats a commit message for a non-inline RST link for a commit hash and/or PR/MR
#}{%  macro commit_msg_links(commit, hvcs_type)
%}{%    if commit.error is undefined
%}{%      set commit_hash_link = "`%s`_" | format(commit.short_hash)
%}{#
#}{%      set summary_line = commit.descriptions[0] | safe
%}{%      set summary_line = [
            summary_line.split(" ", maxsplit=1)[0] | capitalize,
            summary_line.split(" ", maxsplit=1)[1]
          ] | join(" ")
%}{#
#}{%      if commit.linked_merge_request != ""
%}{#        # Add PR references with a link to the PR
#}{%        set pr_link = "`%s`_" | format(commit.linked_merge_request)
%}{#
   #        TODO: breaking change v10, remove summary line replacers as PSR will do it for us
#}{%        set summary_line = summary_line | replace("(pull request ", "(") | replace("(" ~ commit.linked_merge_request ~ ")", "") | trim
%}{%        set summary_line = "%s (%s, %s)" | format(
              summary_line,
              pr_link,
              commit_hash_link,
            )
%}{#
          # DEFAULT: No PR identifier found, so just append a commit hash as url to the commit summary_line
#}{%      else
%}{%        set summary_line = "%s (%s)" | format(summary_line, commit_hash_link)
%}{%      endif
%}{#
          # Return the modified summary_line
#}{{      summary_line
}}{%    endif
%}{%  endmacro
%}


{# MACRO: generate a heading underline that matches the exact length of the header #}
{%    macro generate_heading_underline(header, underline_char)
%}{%    set header_underline = []
%}{%    for _ in header
%}{{      header_underline.append(underline_char) | default("", true)
}}{%    endfor
%}{#    # Print out the header underline
#}{{    header_underline | join
}}{%  endmacro
%}


{#
  MACRO: format the breaking changes description by:
  - Capitalizing the description
  - Adding an optional scope prefix
#}{%  macro format_breaking_changes_description(commit)
%}{%    set ns = namespace(full_description="")
%}{#
#}{%    if commit.error is undefined
%}{%      for paragraph in commit.breaking_descriptions
%}{%        if paragraph | trim | length > 0
%}{#
#}{%          set paragraph_text = [
                paragraph.split(" ", maxsplit=1)[0] | capitalize,
                paragraph.split(" ", maxsplit=1)[1]
              ] | join(" ") | trim | safe
%}{#
#}{%          set ns.full_description = [
                ns.full_description,
                paragraph_text
              ] | join("\n\n")
%}{#
#}{%        endif
%}{%      endfor
%}{#
#}{%      set ns.full_description = ns.full_description | trim
%}{#
#}{%      if commit.scope
%}{%        set ns.full_description = "**%s**: %s" | format(
              commit.scope, ns.full_description
            )
%}{%      endif
%}{%    endif
%}{#
#}{{    ns.full_description
}}{%  endmacro
%}


{#
  MACRO: format the release notice by:
  - Capitalizing the description
  - Adding an optional scope prefix
#}{%  macro format_release_notice(commit)
%}{%    set ns = namespace(full_description="")
%}{#
#}{%    if commit.error is undefined
%}{%      for paragraph in commit.release_notices
%}{%        if paragraph | trim | length > 0
%}{#
#}{%          set paragraph_text = [
                paragraph.split(" ", maxsplit=1)[0] | capitalize,
                paragraph.split(" ", maxsplit=1)[1]
              ] | join(" ") | trim | safe
%}{#
#}{%          set ns.full_description = [
                ns.full_description,
                paragraph_text
              ] | join("\n\n")
%}{#
#}{%        endif
%}{%      endfor
%}{#
#}{%      set ns.full_description = ns.full_description | trim
%}{#
#}{%      if commit.scope
%}{%        set ns.full_description = "**%s**: %s" | format(
              commit.scope, ns.full_description
            )
%}{%      endif
%}{%    endif
%}{#
#}{{    ns.full_description
}}{%  endmacro
%}


{#
  MACRO: apply smart ordering of commits objects based on alphabetized summaries and then scopes
  - Commits are sorted based on the commit type and the commit message
  - Commits are grouped by the commit type
  - parameter: ns (namespace) object with a commits list
  - returns None but modifies the ns.commits list in place
#}{%  macro apply_alphabetical_ordering_by_descriptions(ns)
%}{%    set ordered_commits = []
%}{#
   #    # Eliminate any ParseError commits from input set
#}{%    set filtered_commits = ns.commits | rejectattr("error", "defined") | list
%}{#
   #    # grab all commits with no scope and sort alphabetically by the first line of the commit message
#}{%    for commit in filtered_commits | rejectattr("scope") | sort(attribute='descriptions.0')
%}{{      ordered_commits.append(commit) | default("", true)
}}{%     endfor
%}{#
   #    # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
#}{%    for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,descriptions.0')
%}{{      ordered_commits.append(commit) | default("", true)
}}{%    endfor
%}{#
   #    # Return the ordered commits
#}{%    set ns.commits = ordered_commits
%}{%  endmacro
%}


{#
  MACRO: apply smart ordering of commits objects based on alphabetized breaking changes and then scopes
  - Commits are sorted based on the commit type and the commit message
  - Commits are grouped by the commit type
  - parameter: ns (namespace) object with a commits list
  - returns None but modifies the ns.commits list in place
#}{%  macro apply_alphabetical_ordering_by_brk_descriptions(ns)
%}{%    set ordered_commits = []
%}{#
   #    # Eliminate any ParseError commits from input set
#}{%    set filtered_commits = ns.commits | rejectattr("error", "defined") | list
%}{#
   #    # grab all commits with no scope and sort alphabetically by the first line of the commit message
#}{%    for commit in filtered_commits | rejectattr("scope") | sort(attribute='breaking_descriptions.0')
%}{{      ordered_commits.append(commit) | default("", true)
}}{%     endfor
%}{#
   #    # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
#}{%    for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,breaking_descriptions.0')
%}{{      ordered_commits.append(commit) | default("", true)
}}{%    endfor
%}{#
   #    # Return the ordered commits
#}{%    set ns.commits = ordered_commits
%}{%  endmacro
%}


{#
  MACRO: apply smart ordering of commits objects based on alphabetized release notices and then scopes
  - Commits are sorted based on the commit type and the commit message
  - Commits are grouped by the commit type
  - parameter: ns (namespace) object with a commits list
  - returns None but modifies the ns.commits list in place
#}{%  macro apply_alphabetical_ordering_by_release_notices(ns)
%}{%    set ordered_commits = []
%}{#
   #    # Eliminate any ParseError commits from input set
#}{%    set filtered_commits = ns.commits | rejectattr("error", "defined") | list
%}{#
   #    # grab all commits with no scope and sort alphabetically by the first line of the commit message
#}{%    for commit in filtered_commits | rejectattr("scope") | sort(attribute='release_notices.0')
%}{{      ordered_commits.append(commit) | default("", true)
}}{%     endfor
%}{#
   #    # grab all commits with a scope and sort alphabetically by the scope and then the first line of the commit message
#}{%    for commit in filtered_commits | selectattr("scope") | sort(attribute='scope,release_notices.0')
%}{{      ordered_commits.append(commit) | default("", true)
}}{%    endfor
%}{#
   #    # Return the ordered commits
#}{%    set ns.commits = ordered_commits
%}{%  endmacro
%}
