Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions packages/create-gatsby/src/__tests__/plugin-options-form.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import { makePluginConfigQuestions } from "../plugin-options-form"
import pluginSchemas from "../plugin-schemas.json"

describe(`plugin-options-form`, () => {
it(`returns an empty array when nothing is passed`, () => {
const plugins = []
expect(makePluginConfigQuestions(plugins)).toEqual([])
})

it(`returns an empty array when the plugin is not available for config`, () => {
const plugins = [`not-valid-plugin`]
expect(makePluginConfigQuestions(plugins)).toEqual([])
})

it(`returns an array containing only the wordpress options (choices are included)`, () => {
const plugins = [`gatsby-source-wordpress-experimental`]
expect(makePluginConfigQuestions(plugins)).toEqual([
{
type: `forminput`,
name: `gatsby-source-wordpress-experimental`,
multiple: true,
message: `Configure the WordPress plugin.\nSee \u001b[94mhttps://www.gatsbyjs.com/plugins/gatsby-source-wordpress-experimental/\u001b[39m for help.`,
choices: [
{
name: `url`,
message: `url`,
hint: `This should be the full url of your GraphQL endpoint set up by WP GraphQL`,
},
],
},
])
})

it(`returns an array with all the plugins schemas`, () => {
expect(makePluginConfigQuestions(Object.keys(pluginSchemas))).toEqual([
{
type: `forminput`,
name: `gatsby-source-wordpress-experimental`,
multiple: true,
message: `Configure the WordPress plugin.\nSee \u001b[94mhttps://www.gatsbyjs.com/plugins/gatsby-source-wordpress-experimental/\u001b[39m for help.`,
choices: [
{
name: `url`,
message: `url`,
hint: `This should be the full url of your GraphQL endpoint set up by WP GraphQL`,
},
],
},
{
type: `forminput`,
name: `gatsby-source-contentful`,
multiple: true,
message: `Configure the Contentful plugin.\nSee \u001b[94mhttps://www.gatsbyjs.com/plugins/gatsby-source-contentful/\u001b[39m for help.\n\u001b[32mUse arrow keys to move between fields, and enter to finish\u001b[39m`,
choices: [
{
name: `accessToken`,
message: `accessToken`,
hint: `Contentful delivery api key, when using the Preview API use your Preview API key`,
},
{ name: `spaceId`, message: `spaceId`, hint: `Contentful spaceId` },
],
},
{
type: `forminput`,
name: `gatsby-source-sanity`,
multiple: true,
message: `Configure the Sanity plugin.\nSee \u001b[94mhttps://www.gatsbyjs.com/plugins/gatsby-source-sanity/\u001b[39m for help.\n\u001b[32mUse arrow keys to move between fields, and enter to finish\u001b[39m`,
choices: [
{
name: `projectId`,
message: `projectId`,
hint: `Your Sanity project's ID`,
},
{
name: `dataset`,
message: `dataset`,
hint: `The dataset to fetch from`,
},
],
},
{
type: `forminput`,
name: `gatsby-source-shopify`,
multiple: true,
message: `Configure the Shopify plugin.\nSee \u001b[94mhttps://www.gatsbyjs.com/plugins/gatsby-source-shopify/\u001b[39m for help.\n\u001b[32mUse arrow keys to move between fields, and enter to finish\u001b[39m`,
choices: [
{
name: `shopName`,
message: `shopName`,
hint: `The domain name of your Shopify shop`,
},
{
name: `accessToken`,
message: `accessToken`,
hint: `An API access token to your Shopify shop`,
},
],
},
{
type: `forminput`,
name: `gatsby-source-datocms`,
multiple: true,
message: `Configure the DatoCMS plugin.\nSee \u001b[94mhttps://www.gatsbyjs.com/plugins/gatsby-source-datocms/\u001b[39m for help.`,
choices: [
{
name: `apiToken`,
message: `apiToken`,
hint: `Your read-only API token under the Settings > API tokens section of your administrative area in DatoCMS`,
},
],
},
{
type: `forminput`,
name: `gatsby-source-agility`,
multiple: true,
message: `Configure the gatsby-source-agility plugin.\nSee \u001b[94mhttps://www.gatsbyjs.com/plugins/gatsby-source-agility/\u001b[39m for help.`,
choices: [
{
name: `guid`,
message: `guid`,
hint: `your Agility Content Fetch API Guid`,
},
],
},
{
type: `forminput`,
name: `gatsby-plugin-google-analytics`,
multiple: true,
message: `Configure the gatsby-plugin-google-analytics plugin.\nSee \u001b[94mhttps://www.gatsbyjs.com/plugins/gatsby-plugin-google-analytics/\u001b[39m for help.`,
choices: [
{
name: `trackingId`,
message: `trackingId`,
hint: `The property ID; the tracking code won't be generated without it`,
},
],
},
])
})
})
65 changes: 35 additions & 30 deletions packages/create-gatsby/src/plugin-options-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,22 @@ type Schema = Joi.Description & {

type PluginName = keyof typeof pluginSchemas

interface IChoice {
name: string
initial: unknown
message: string
hint?: string
}
type Choices = Array<IChoice>

type Option = Record<string, Schema> | undefined

interface IFormPrompt {
type: string
name: string
multiple: boolean
message: string
choices: Array<{
name: string
initial: unknown
message: string
hint?: string
}>
choices: Choices
}

function getName(key: string): string | undefined {
Expand All @@ -49,51 +54,50 @@ function docsLink(pluginName: string): string {
)
}

const isOptionRequired = ([_, option]: [string, Schema]): boolean =>
option?.flags?.presence === `required`

const schemaToChoice = ([name, option]: [string, Schema]): IChoice => {
const hasDefaultValue =
option.flags?.default &&
supportedOptionTypes.includes(typeof option.flags?.default)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realise this was how it was before, but I do wonder if there's a better way to do this, using the schema rather than checking the type of the default value

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a side note on that: right now, IIRC, none of the elements that are required have a default value 🤔 . This is a computation that lives there "for nothing" for now I would say :/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Most of them aren't likely to either, because if there's a default it won't need to be required


return {
name,
initial: hasDefaultValue ? option.flags?.default.toString() : undefined,
message: name,
hint: option.flags?.description,
}
}

export const makePluginConfigQuestions = (
selectedPlugins: Array<string>
): Array<IFormPrompt> => {
const formPrompts: Array<IFormPrompt> = []

selectedPlugins.forEach((pluginName: string): void => {
const schema = pluginSchemas[pluginName as PluginName]

if (!schema || typeof schema === `string` || !(`keys` in schema)) {
return
}
const options: Record<string, Schema> | undefined = schema?.keys
const choices: Array<{
name: string
initial: string
message: string
hint?: string
}> = []
const options: Option = schema?.keys

if (!options) {
return
}

Object.entries(options).forEach(([name, option]) => {
if (option?.flags?.presence !== `required`) {
return
}
choices.push({
name,
initial:
option.flags?.default &&
supportedOptionTypes.includes(typeof option.flags?.default)
? option.flags?.default.toString()
: undefined,
message: name,
hint: option.flags?.description,
})
})
const choices: Choices = Object.entries(options)
.filter(isOptionRequired)
.map(schemaToChoice)

if (choices.length) {
if (choices.length > 0) {
formPrompts.push({
type: `forminput`,
name: pluginName,
multiple: true,
message: stripIndent`
Configure the ${getName(pluginName)} plugin.
Configure the ${getName(pluginName)} plugin.
See ${docsLink(pluginName)} for help.
${
choices.length > 1
Expand All @@ -107,5 +111,6 @@ export const makePluginConfigQuestions = (
})
}
})

return formPrompts
}