Skip to content

Commit

Permalink
feat(gatsby-source-wordpress): allow path to js file for beforeChange…
Browse files Browse the repository at this point in the history
…Node option (#32901)

* Allow path to js file for beforeChangeNode option

* ensure Joi doesn't fail the build for inline beforeChangeNode fn's

* Create gatsby-version.ts

* Panic on Gatsby v4+ if beforeChangeNode is a function.
  • Loading branch information
TylerBarnes committed Aug 26, 2021
1 parent 1a87a8a commit ac7bd4e
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 5 deletions.
Expand Up @@ -4380,6 +4380,7 @@ Array [
"title",
"uri",
"nodeType",
"beforeChangeNodeTest",
"parent",
"children",
"internal",
Expand Down Expand Up @@ -4596,6 +4597,7 @@ Array [
"toPing",
"uri",
"nodeType",
"beforeChangeNodeTest",
"parent",
"children",
"internal",
Expand Down
8 changes: 8 additions & 0 deletions integration-tests/gatsby-source-wordpress/gatsby-config.js
Expand Up @@ -40,6 +40,7 @@ const wpPluginOptions = !process.env.DEFAULT_PLUGIN_OPTIONS
},
Page: {
excludeFieldNames: [`enclosure`],
beforeChangeNode: `./src/before-change-page.js`,
},
DatabaseIdentifier: {
exclude: true,
Expand All @@ -66,6 +67,13 @@ const wpPluginOptions = !process.env.DEFAULT_PLUGIN_OPTIONS
50
: // and we don't actually need more than 1000 in production
1000,

beforeChangeNode: ({ remoteNode }) => {
console.log(`Hi from an inline fn!`)
remoteNode.beforeChangeNodeTest = `TEST-${remoteNode.id}`

return remoteNode
},
},
// excluding this because it causes Gatsby to throw errors
BlockEditorContentNode: { exclude: true },
Expand Down
12 changes: 12 additions & 0 deletions integration-tests/gatsby-source-wordpress/gatsby-node.js
@@ -0,0 +1,12 @@
exports.createSchemaCustomization = ({ actions }) => {
const { createTypes } = actions
const typeDefs = `
type WpPage {
beforeChangeNodeTest: String
}
type WpPost {
beforeChangeNodeTest: String
}
`
createTypes(typeDefs)
}
@@ -0,0 +1,5 @@
module.exports = ({ remoteNode }) => {
remoteNode.beforeChangeNodeTest = `TEST-${remoteNode.id}`

return remoteNode
}
Expand Up @@ -219,6 +219,38 @@ describe(`data resolution`, () => {
expect(result.data.testUser.name).toEqual(`admin`)
})

it(`resolves data added via a fn file in onBeforeChangeNode type option`, async () => {
const result = await fetchGraphql({
url,
query: /* GraphQL */ `
{
# fn as a file path
allWpPage {
nodes {
id
beforeChangeNodeTest
}
}
# inline fn in gatsby-config.js
# support for this will be removed in future versions
allWpPost {
nodes {
id
beforeChangeNodeTest
}
}
}
`,
})

result.data.allWpPage.nodes.forEach(node => {
expect(node.beforeChangeNodeTest).toBe(`TEST-${node.id}`)
})
result.data.allWpPost.nodes.forEach(node => {
expect(node.beforeChangeNodeTest).toBe(`TEST-${node.id}`)
})
})

it(`resolves root fields`, async () => {
const result = await fetchGraphql({
url,
Expand Down
Expand Up @@ -96,6 +96,14 @@ describe(`pluginOptionsSchema`, () => {
MenuItem: {
beforeChangeNode: null,
},
Page: {
beforeChangeNode: `./docs-generation.test.js`,
},
Post: {
beforeChangeNode: () => {
console.log(`Hi from an inline fn!`)
},
},
EnqueuedScript: {
exclude: true,
},
Expand Down
4 changes: 2 additions & 2 deletions packages/gatsby-source-wordpress/docs/plugin-options.md
Expand Up @@ -1107,9 +1107,9 @@ Determines whether or not this type will be treated as an interface comprised en

#### type.\_\_all.beforeChangeNode

A function which is invoked before a node is created, updated, or deleted. This is a hook in point to modify the node or perform side-effects related to it.
A function which is invoked before a node is created, updated, or deleted. This is a hook in point to modify the node or perform side-effects related to it. This option should be a path to a JS file where the default export is the beforeChangeNode function. The path can be relative to your gatsby-node.js or absolute. Currently you can inline a function by writing it out directly in this option but starting from Gatsby v4 only a path to a function file will work.

**Field type**: `Function`
**Field type**: `String | Function`

### type.RootQuery

Expand Down
Expand Up @@ -60,7 +60,10 @@ function joiKeysToMD({
(value.meta && value.meta.find(meta => `trueType` in meta)) || {}

mdString += `\n\n`
mdString += `**Field type**: \`${_.startCase(trueType || value.type)}\``
mdString += `**Field type**: \`${(trueType || value.type)
.split(`|`)
.map(typename => _.startCase(typename))
.join(` | `)}\``
}

if (
Expand Down
Expand Up @@ -88,10 +88,10 @@ const pluginOptionsSchema = ({ Joi }) => {
.allow(null)
.allow(false)
.meta({
trueType: `function`,
trueType: `string|function`,
})
.description(
`A function which is invoked before a node is created, updated, or deleted. This is a hook in point to modify the node or perform side-effects related to it.`
`A function which is invoked before a node is created, updated, or deleted. This is a hook in point to modify the node or perform side-effects related to it. This option should be a path to a JS file where the default export is the beforeChangeNode function. The path can be relative to your gatsby-node.js or absolute. Currently you can inline a function by writing it out directly in this option but starting from Gatsby v4 only a path to a function file will work.`
),
})

Expand Down
@@ -1,7 +1,9 @@
import path from "path"
import { formatLogMessage } from "~/utils/format-log-message"
import isInteger from "lodash/isInteger"
import { IPluginOptions } from "~/models/gatsby-api"
import { GatsbyNodeApiHelpers } from "~/utils/gatsby-types"
import { usingGatsbyV4OrGreater } from "~/utils/gatsby-version"
interface IProcessorOptions {
userPluginOptions: IPluginOptions
helpers: GatsbyNodeApiHelpers
Expand Down Expand Up @@ -46,6 +48,60 @@ const optionsProcessors: Array<IOptionsProcessor> = [

delete userPluginOptions.schema.queryDepth

return userPluginOptions
},
},
{
name: `Require beforeChangeNode type setting functions by absolute or relative path`,
test: ({ userPluginOptions }: IProcessorOptions): boolean =>
!!userPluginOptions?.type,
processor: ({
helpers,
userPluginOptions,
}: IProcessorOptions): IPluginOptions => {
const gatsbyStore = helpers.store.getState()
const typeSettings = Object.entries(userPluginOptions.type)

typeSettings.forEach(([typeName, settings]) => {
const beforeChangeNodePath = settings?.beforeChangeNode

if (
usingGatsbyV4OrGreater &&
typeof beforeChangeNodePath === `function`
) {
helpers.reporter.panic(
`Since Gatsby v4+ you cannot use the ${typeName}.beforeChangeNode option as a function. Please make the option a relative or absolute path to a JS file where the beforeChangeNode fn is the default export.`
)
}

if (!beforeChangeNodePath || typeof beforeChangeNodePath !== `string`) {
return
}

try {
const absoluteRequirePath: string | undefined = path.isAbsolute(
beforeChangeNodePath
)
? beforeChangeNodePath
: require.resolve(
path.join(gatsbyStore.program.directory, beforeChangeNodePath)
)

const beforeChangeNodeFn = require(absoluteRequirePath)

if (beforeChangeNodeFn) {
userPluginOptions.type[typeName].beforeChangeNode =
beforeChangeNodeFn
}
} catch (e) {
helpers.reporter.panic(
formatLogMessage(
`beforeChangeNode type setting for ${typeName} threw error:\n${e.message}`
)
)
}
})

return userPluginOptions
},
},
Expand Down
5 changes: 5 additions & 0 deletions packages/gatsby-source-wordpress/src/utils/gatsby-version.ts
@@ -0,0 +1,5 @@
import semver from "semver"
const gatsbyVersion = require(`gatsby/package.json`)?.version

// gt = greater than
export const usingGatsbyV4OrGreater = semver.gt(gatsbyVersion, `4.0.0`)

0 comments on commit ac7bd4e

Please sign in to comment.