repo_description: The React Framework
repo_topics: blog browser compiler components hybrid nextjs node react server-rendering ssg static static-site-generator universal vercel
code: // section -> label
  const sectionLabelMap = {
    'Core Changes': 'type: next',
    'Documentation Changes': 'documentation',
    'Example Changes': 'examples',
  }
  
  const fallbackSection = 'Misc Changes'
  
  // --------------------------------------------------
  
  const prNumberRegex = /\(#([-0-9]+)\)$/
  
  const getCommitPullRequest = async (commit, github) => {
    const match = prNumberRegex.exec(commit.title)
  
    if (!match) {
      return null
    }
  
    const number = parseInt(match[1], 10)
  
    if (!number) {
      return null
    }
  
    const { data } = await github.connection.pullRequests.get({
      owner: github.repoDetails.user,
      repo: github.repoDetails.repo,
      number,
    })
  
    return data
  }
  
  const getSectionForPullRequest = (pullRequest) => {
    const { labels } = pullRequest
  
    // sections defined first will take priority
    for (const [section, label] of Object.entries(sectionLabelMap)) {
      if (labels.some((prLabel) => prLabel.name === label)) {
        return section
      }
    }
  
    return null
  }
  
  const groupByLabels = async (commits, github) => {
    // Initialize the sections object with empty arrays
    const sections = Object.keys(sectionLabelMap).reduce((sections, section) => {
      sections[section] = []
      return sections
    }, {})
    sections.__fallback = []
  
    for (const commit of commits) {
      const pullRequest = await getCommitPullRequest(commit, github)
  
      if (pullRequest) {
        const section = getSectionForPullRequest(pullRequest)
  
        if (section) {
          // Add the change to the respective section
          sections[section].push({
            title: pullRequest.title,
            number: pullRequest.number,
          })
  
          continue
        }
  
        // No section found, add it to the fallback section
        sections.__fallback.push({
          title: pullRequest.title,
          number: pullRequest.number,
        })
  
        continue
      }
  
      // No Pull Request found, add it to the fallback section but without the number
      sections.__fallback.push({
        title: commit.title,
      })
    }
  
    return sections
  }
  
  function cleanupPRTitle(title) {
    if (title.startsWith('[Docs] ')) {
      return title.replace('[Docs] ', '')
    }
  
    return title
  }
  
  const buildChangelog = (sections, authors) => {
    let text = ''
  
    for (const section in sections) {
      const changes = sections[section]
  
      // No changes in this section? Don't render it
      if (changes.length === 0) {
        continue
      }
  
      const title = section === '__fallback' ? fallbackSection : section
      text += `### ${title}\n\n`
  
      for (const change of changes) {
        const numberText = change.number != null ? `: #${change.number}` : ''
  
        text += `- ${cleanupPRTitle(change.title)}${numberText}\n`
      }
  
      text += '\n'
    }
  
    if (authors.size > 0) {
      text += '### Credits \n\n'
      text += 'Huge thanks to '
  
      let index = 1
      authors.forEach((author) => {
        // GitHub links usernames if prefixed with @
        text += `@${author}`
  
        const penultimate = index === authors.size - 1
        const notLast = index !== authors.size
  
        if (penultimate) {
          // Oxford comma is applied when list is bigger than 2 names
          if (authors.size > 2) {
            text += ','
          }
  
          text += ' and '
        } else if (notLast) {
          text += ', '
        }
  
        index += 1
      })
  
      text += ' for helping!'
      text += '\n'
    }
  
    return text
  }
  
  module.exports = async (markdown, metadata) => {
    const { commits, authors, githubConnection, repoDetails } = metadata
  
    const github = { connection: githubConnection, repoDetails }
  
    const sections = await groupByLabels(commits.all, github)
    const changelog = buildChangelog(sections, authors)
  
    return changelog
  }
  