Repository: gatsbyjs/gatsby
File: packages/gatsby/src/bootstrap/load-plugins/validate.ts (TypeScript)

Code before:
        Joi,
      })

      // Validate correct usage of pluginOptionsSchema
      if (!Joi.isSchema(optionsSchema) || optionsSchema.type !== `object`) {
        reporter.warn(
          `Plugin "${plugin.resolve}" has an invalid options schema so we cannot verify your configuration for it.`
        )
        return plugin
      }

      try {
        if (!optionsSchema.describe().keys.plugins) {
          // All plugins have "plugins: []"" added to their options in load.ts, even if they
          // do not have subplugins. We add plugins to the schema if it does not exist already
          // to make sure they pass validation.
          optionsSchema = optionsSchema.append({
            plugins: Joi.array().length(0),
          })
        }

        plugin.options = await validateOptionsSchema(
          optionsSchema,
          (plugin.options as IPluginInfoOptions) || {}
        )
      } catch (error) {
        if (error instanceof Joi.ValidationError) {
          reporter.error({
            id: `11331`,
            context: {
              validationErrors: error.details,
              pluginName: plugin.resolve,
            },
          })
          errors++

          return plugin
        }

        throw error
      }

      return plugin
    })
  )

  if (errors > 0) {
    process.exit(1)
  }
}


Review comment (refactor):
We're missing sub plugin validation for things like gatsby-transform-remark. So we probably have to split this function so we can put it all in one errors array.

Now it short circuits when a subplugin throws an error

```suggestion
        plugin.options = await validateOptionsSchema(
          optionsSchema,
          (plugin.options as IPluginInfoOptions) || {}
        )

        if (plugin.options.plugins) {
          await validatePluginOptions({ plugins: plugin.options.plugins })
        }
```

Code after:
      >)({
        Joi,
      })

      // Validate correct usage of pluginOptionsSchema
      if (!Joi.isSchema(optionsSchema) || optionsSchema.type !== `object`) {
        reporter.warn(
          `Plugin "${plugin.resolve}" has an invalid options schema so we cannot verify your configuration for it.`
        )
        return plugin
      }

      try {
        if (!optionsSchema.describe().keys.plugins) {
          // All plugins have "plugins: []"" added to their options in load.ts, even if they
          // do not have subplugins. We add plugins to the schema if it does not exist already
          // to make sure they pass validation.
          optionsSchema = optionsSchema.append({
            plugins: Joi.array().length(0),
          })
        }

        plugin.options = await validateOptionsSchema(
          optionsSchema,
          (plugin.options as IPluginInfoOptions) || {}
        )

        if (plugin.options?.plugins) {
          const {
            errors: subErrors,
            plugins: subPlugins,
          } = await validatePluginsOptions(
            plugin.options.plugins as Array<IPluginRefObject>
          )
          plugin.options.plugins = subPlugins
          errors += subErrors
        }
      } catch (error) {
        if (error instanceof Joi.ValidationError) {
          reporter.error({
            id: `11331`,
            context: {
              validationErrors: error.details,
              pluginName: plugin.resolve,
            },
          })
          errors++

          return plugin
        }