createFSMachine = (
  {
    actions: { createNode, deleteNode },
    getNode,
    createNodeId,
    reporter,
    cache,
  },
  pluginOptions
) => {
  const createAndProcessNode = path => {
    const fileNodePromise = createFileNode(
      path,
      createNodeId,
      pluginOptions,
      cache
    ).then(fileNode => {
      createNode(fileNode)
      return null
    })
    return fileNodePromise
  }

  const deletePathNode = path => {
    const node = getNode(createNodeId(path))
    // It's possible the node was never created as sometimes tools will
    // write and then immediately delete temporary files to the file system.
    if (node) {
      deleteNode(node)
    }
  }

  // For every path that is reported before the 'ready' event, we throw them
  // into a queue and then flush the queue when 'ready' event arrives.
  // After 'ready', we handle the 'add' event without putting it into a queue.
  let pathQueue = []
  const flushPathQueue = () => {
    const queue = pathQueue.slice()
    pathQueue = null
    return Promise.all(
      // eslint-disable-next-line consistent-return
      queue.map(({ op, path }) => {
        switch (op) {
          case `delete`:
            return deletePathNode(path)
          case `upsert`:
            return createAndProcessNode(path)
        }
      })
    )
  }

  const log = expr => (ctx, action, meta) => {
    if (ctx.bootstrapped) {
      reporter.info(expr(ctx, action, meta))
    }
  }

  const fsMachine = createMachine(
    {
      predictableActionArguments: true,
      context: {
        bootstrapped: false,
      },
      id: `fs`,
      type: `parallel`,
      states: {
        BOOTSTRAP: {
          initial: `BOOTSTRAPPING`,
          states: {
            BOOTSTRAPPING: {
              on: {
                BOOTSTRAP_FINISHED: `BOOTSTRAPPED`,
              },
            },
            BOOTSTRAPPED: {
              type: `final`,
              entry: assign({ bootstrapped: true }),
            },
          },
        },
        CHOKIDAR: {
          initial: `NOT_READY`,
          states: {
            NOT_READY: {
              on: {
                CHOKIDAR_READY: `READY`,
                CHOKIDAR_ADD: { actions: `queueNodeProcessing` },
                CHOKIDAR_CHANGE: { actions: `queueNodeProcessing` },
                CHOKIDAR_UNLINK: { actions: `queueNodeDeleting` },
              },
              exit: `flushPathQueue`,
            },
            READY: {
              on: {
                CHOKIDAR_ADD: {
                  actions: [
                    `createAndProcessNode`,
                    log(
                      (_, { pathType, path }) => `added ${pathType} at ${path}`
                    ),
                  ],
                },
                CHOKIDAR_CHANGE: {
                  actions: [
                    `createAndProcessNode`,
                    log(
                      (_, { pathType, path }) =>
                        `changed ${pathType} at ${path}`
                    ),
                  ],
                },
                CHOKIDAR_UNLINK: {
                  actions: [
                    `deletePathNode`,
                    log(
                      (_, { pathType, path }) =>
                        `deleted ${pathType} at ${path}`
                    ),
                  ],
                },
              },
            },
          },
        },
      },
    },
    {
      actions: {
        createAndProcessNode(_, { pathType, path }) {
          createAndProcessNode(path).catch(err => reporter.error(err))
        },
        deletePathNode(_, { pathType, path }, { state }) {
          deletePathNode(path)
        },
        flushPathQueue(_, { resolve, reject }) {
          flushPathQueue().then(resolve, reject)
        },
        queueNodeDeleting(_, { path }) {
          pathQueue.push({ op: `delete`, path })
        },
        queueNodeProcessing(_, { path }) {
          pathQueue.push({ op: `upsert`, path })
        },
      },
    }
  )
  return interpret(fsMachine).start()
}
Create a state machine to manage Chokidar's not-ready/ready states.