readConfigFile = async root => {
  let src
  try {
    src = await fs.readFile(getConfigPath(root), `utf8`)
  } catch (e) {
    if (e.code === `ENOENT`) {
      src = defaultConfig
    } else {
      throw e
    }
  }

  if (src === ``) {
    src = defaultConfig
  }

  return src
}
/*.*`, {
    follow: true,
  })

  const toShadowPath = filePath => {
    const relativeFilePath = slash(filePath).replace(slash(themeSrcPath), ``)
    return path.join(`src`, theme, relativeFilePath)
  }

  const shadowPaths = shadowableThemeFiles.map(toShadowPath)

  const shadowedFiles = shadowPaths.filter(fileExists)
  const shadowableFiles = shadowPaths.filter(filePath => !fileExists(filePath))

  return { shadowedFiles, shadowableFiles }
}

const getOptionsForPlugin = node => {
  if (!t.isObjectExpression(node) && !t.isLogicalExpression(node)) {
    return undefined
  }

  let options

  // When a plugin is added conditionally with && {}
  if (t.isLogicalExpression(node)) {
    options = node.right.properties.find(
      property => property.key.name === `options`
    )
  } else {
    options = node.properties.find(property => property.key.name === `options`)
  }

  if (options) {
    return getObjectFromNode(options.value)
  }

  return undefined
}

const getPlugin = node => {
  const plugin = {
    name: getNameForPlugin(node),
    options: getOptionsForPlugin(node),
  }

  const key = getKeyForPlugin(node)

  if (key) {
    return { ...plugin, key }
  }

  return plugin
}

const getKeyForPlugin = node => {
  if (t.isObjectExpression(node)) {
    const key = node.properties.find(p => p.key.name === `__key`)

    return key ? getValueFromNode(key.value) : null
  }

  // When a plugin is added conditionally with && {}
  if (t.isLogicalExpression(node)) {
    const key = node.right.properties.find(p => p.key.name === `__key`)

    return key ? getValueFromNode(key.value) : null
  }

  return null
}

const getNameForPlugin = node => {
  if (t.isStringLiteral(node) || t.isTemplateLiteral(node)) {
    return getValueFromNode(node)
  }

  if (t.isObjectExpression(node)) {
    const resolve = node.properties.find(p => p.key.name === `resolve`)

    return resolve ? getValueFromNode(resolve.value) : null
  }

  // When a plugin is added conditionally with && {}
  if (t.isLogicalExpression(node)) {
    const resolve = node.right.properties.find(p => p.key.name === `resolve`)

    return resolve ? getValueFromNode(resolve.value) : null
  }

  return null
}

const getDescriptionForPlugin = async (root, name) => {
  const pkg = await readPackageJSON(root, name)

  return pkg?.description || ``
}

const readmeCache = new Map()

const getPath = (module, file, root) => {
  try {
    return require.resolve(`${module}/${file}`, { paths: [root] })
  } catch (e) {
    return undefined
  }
}

const getReadmeForPlugin = async (root, name) => {
  if (readmeCache.has(name)) {
    return readmeCache.get(name)
  }

  let readmePath

  const readmes = [`readme.txt`, `readme`, `readme.md`, `README`, `README.md`]
  while (!readmePath && readmes.length) {
    readmePath = getPath(name, readmes.pop(), root)
  }

  try {
    if (readmePath) {
      const readme = await fs.readFile(readmePath, `utf8`)
      if (readme) {
        readmeCache.set(name, readme)
      }
      return readme
    }

    const readme = await fetch(`https://unpkg.com/${name}/README.md`)
      .then(res => res.text())
      .catch(() => null)

    if (readme) {
      readmeCache.set(name, readme)
    }
    return readme || ``
  } catch (err) {
    return ``
  }
}

const addPluginToConfig = (src, { name, options, key }) => {
  const addPlugins = new BabelPluginAddPluginsToGatsbyConfig({
    pluginOrThemeName: name,
    options,
    shouldAdd: true,
    key,
  })

  const { code } = transform(src, {
    plugins: [addPlugins.plugin],
    configFile: false,
  })

  return code
}

const removePluginFromConfig = (src, { id, name, key }) => {
  const addPlugins = new BabelPluginAddPluginsToGatsbyConfig({
    pluginOrThemeName: name || id,
    key,
    shouldAdd: false,
  })

  const { code } = transform(src, {
    plugins: [addPlugins.plugin],
    configFile: false,
  })

  return code
}

const getPluginsFromConfig = src => {
  const getPlugins = new BabelPluginGetPluginsFromGatsbyConfig()

  transform(src, {
    plugins: [getPlugins.plugin],
    configFile: false,
  })

  return getPlugins.state
}

const getConfigPath = root => path.join(root, `gatsby-config.js`)

const defaultConfig = `/**
Configure your Gatsby site with this file.

See: https://www.gatsbyjs.com/docs/gatsby-config/