cbillowes/curious-programmer-helium

View on GitHub
gatsby-node.js

Summary

Maintainability
A
35 mins
Test Coverage
const path = require("path")
const _ = require("lodash")
const moment = require("moment")
const siteConfig = require("./data/SiteConfig")

const postNodes = []
function addSiblingNodes(createNodeField) {
  postNodes.sort(
    ({ frontmatter: { date: date1 } }, { frontmatter: { date: date2 } }) => {
      const dateA = moment(date1, siteConfig.dateFromFormat)
      const dateB = moment(date2, siteConfig.dateFromFormat)

      if (dateA.isBefore(dateB)) return 1

      if (dateB.isBefore(dateA)) return -1

      return 0
    }
  )
  for (let i = 0; i < postNodes.length; i += 1) {
    const nextID = i + 1 < postNodes.length ? i + 1 : 0
    const prevID = i - 1 > 0 ? i - 1 : postNodes.length - 1
    const currNode = postNodes[i]
    const nextNode = postNodes[nextID]
    const prevNode = postNodes[prevID]
    createNodeField({
      node: currNode,
      name: "nextTitle",
      value: nextNode.frontmatter.title
    })
    createNodeField({
      node: currNode,
      name: "nextSlug",
      value: nextNode.fields.slug
    })
    createNodeField({
      node: currNode,
      name: "prevTitle",
      value: prevNode.frontmatter.title
    })
    createNodeField({
      node: currNode,
      name: "prevSlug",
      value: prevNode.fields.slug
    })
  }
}

exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions
  let slug
  if (node.internal.type === "MarkdownRemark") {
    const fileNode = getNode(node.parent)
    const parsedFilePath = path.parse(fileNode.relativePath)
    if (
      Object.prototype.hasOwnProperty.call(node, "frontmatter") &&
      Object.prototype.hasOwnProperty.call(node.frontmatter, "title")
    ) {
      slug = `/blog/${_.kebabCase(node.frontmatter.title)}`
    } else if (parsedFilePath.name !== "index" && parsedFilePath.dir !== "") {
      slug = `/${parsedFilePath.dir}/${parsedFilePath.name}/`
    } else if (parsedFilePath.dir === "") {
      slug = `/${parsedFilePath.name}/`
    } else {
      slug = `/${parsedFilePath.dir}/`
    }

    if (Object.prototype.hasOwnProperty.call(node, "frontmatter")) {
      if (Object.prototype.hasOwnProperty.call(node.frontmatter, "slug"))
        slug = `/blog/${_.kebabCase(node.frontmatter.slug)}`
      if (Object.prototype.hasOwnProperty.call(node.frontmatter, "date")) {
        const date = moment(node.frontmatter.date, siteConfig.dateFromFormat)
        if (!date.isValid)
          console.warn(`WARNING: Invalid date.`, node.frontmatter)

        createNodeField({
          node,
          name: "date",
          value: date.toISOString()
        })
      }
    }
    createNodeField({ node, name: "slug", value: slug })
    node.frontmatter.title = _.startCase(node.frontmatter.title)

    if (node.frontmatter.tags) {
      let tags = node.frontmatter.tags
      node.frontmatter.tags = []
      tags.forEach(tag => {
        if (tag) node.frontmatter.tags.push(_.toLower(tag))
      })
      postNodes.push(node)
    }
  }
}

exports.setFieldsOnGraphQLNodeType = ({ type, actions }) => {
  const { name } = type
  const { createNodeField } = actions
  if (name === "MarkdownRemark") {
    addSiblingNodes(createNodeField)
  }
}

exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions

  return new Promise((resolve, reject) => {
    const postPage = path.resolve("src/templates/post.jsx")
    const tagPage = path.resolve("src/templates/tag.jsx")
    resolve(
      graphql(
        `
          {
            allMarkdownRemark {
              edges {
                node {
                  excerpt
                  timeToRead
                  frontmatter {
                    tags
                    title
                    cover
                    ogImage
                  }
                  fields {
                    slug
                  }
                }
              }
            }
          }
        `
      ).then(result => {
        if (result.errors) {
          /* eslint no-console: "off" */
          console.log(result.errors)
          reject(result.errors)
        }

        let idx = 0
        postNodes.map(node => {
          let previous =
            idx - 1 < 0 ? postNodes[postNodes.length - 1] : postNodes[idx - 1]
          let next =
            idx + 1 >= postNodes.length ? postNodes[0] : postNodes[idx + 1]

          createPage({
            path: node.fields.slug,
            component: postPage,
            context: {
              slug: node.fields.slug,
              prev: previous.fields.slug,
              next: next.fields.slug
            }
          })
          idx += 1
        })

        const tagSet = new Set()
        let edges = result.data.allMarkdownRemark.edges
        edges.forEach(edge => {
          if (edge.node.frontmatter.tags) {
            edge.node.frontmatter.tags.forEach(tag => {
              tagSet.add(tag)
            })
          }
        })

        const tagList = Array.from(tagSet)
        tagList.forEach(tag => {
          createPage({
            path: `/tags/${_.kebabCase(tag)}/`,
            component: tagPage,
            context: {
              tag
            }
          })
        })
      })
    )
  })
}