diff --git a/integration-tests/gatsby-cli/__tests__/new.js b/integration-tests/gatsby-cli/__tests__/new.js index 6cf61330aff15..82988dbab2899 100644 --- a/integration-tests/gatsby-cli/__tests__/new.js +++ b/integration-tests/gatsby-cli/__tests__/new.js @@ -29,7 +29,11 @@ describe(`gatsby new`, () => { }) it(`creates a gatsby site with the default starter`, () => { - const [code, logs] = GatsbyCLI.from(cwd).invoke([`new`, `gatsby-default`]) + const [code, logs] = GatsbyCLI.from(cwd).invoke([ + `new`, + `gatsby-default`, + `gatsbyjs/gatsby-starter-default#v4`, + ]) logs.should.contain( `info Creating new site from git: https://github.com/gatsbyjs/gatsby-starter-default.git` @@ -48,7 +52,7 @@ describe(`gatsby new`, () => { const [code, logs] = GatsbyCLI.from(cwd).invoke([ `new`, `gatsby-blog`, - `gatsbyjs/gatsby-starter-blog`, + `gatsbyjs/gatsby-starter-blog#v4`, ]) logs.should.contain( diff --git a/integration-tests/gatsby-source-wordpress/__tests__/__snapshots__/index.js.snap b/integration-tests/gatsby-source-wordpress/__tests__/__snapshots__/index.js.snap index 800914e7f2a1b..b2defcb6067e2 100644 --- a/integration-tests/gatsby-source-wordpress/__tests__/__snapshots__/index.js.snap +++ b/integration-tests/gatsby-source-wordpress/__tests__/__snapshots__/index.js.snap @@ -95,7 +95,6 @@ Object { "databaseId": 564, "id": "cG9zdDo1NjQ=", "label": "Activity", - "nodeType": "MenuItem", "target": null, "title": null, "url": "/activity/", @@ -132,7 +131,6 @@ Object { "databaseId": 565, "id": "cG9zdDo1NjU=", "label": "Sample Page", - "nodeType": "MenuItem", "target": null, "title": null, "url": "/sample-page/", @@ -154,7 +152,6 @@ Object { "databaseId": 566, "id": "cG9zdDo1NjY=", "label": "Hello world!", - "nodeType": "MenuItem", "target": null, "title": null, "url": "/2020/02/25/hello-world/", @@ -166,7 +163,6 @@ Object { "databaseId": 567, "id": "cG9zdDo1Njc=", "label": "test custom link", - "nodeType": "MenuItem", "target": null, "title": null, "url": "https://google.com", @@ -218,7 +214,6 @@ Object { "databaseId": 564, "id": "cG9zdDo1NjQ=", "label": "Activity", - "nodeType": "MenuItem", "target": null, "title": null, "url": "/activity/", @@ -255,7 +250,6 @@ Object { "databaseId": 565, "id": "cG9zdDo1NjU=", "label": "Sample Page", - "nodeType": "MenuItem", "target": null, "title": null, "url": "/sample-page/", @@ -277,7 +271,6 @@ Object { "databaseId": 566, "id": "cG9zdDo1NjY=", "label": "Hello world!", - "nodeType": "MenuItem", "target": null, "title": null, "url": "/2020/02/25/hello-world/", @@ -289,7 +282,6 @@ Object { "databaseId": 567, "id": "cG9zdDo1Njc=", "label": "test custom link", - "nodeType": "MenuItem", "target": null, "title": null, "url": "https://google.com", @@ -783,7 +775,6 @@ Object { "writingSettingsDefaultPostFormat": "", "writingSettingsUseSmilies": true, }, - "nodeType": null, "writingSettings": Object { "defaultCategory": 23, "defaultPostFormat": "0", @@ -960,7 +951,6 @@ Array [ "seo", "viewer", "writingSettings", - "nodeType", "id", "parent", "children", @@ -1074,7 +1064,6 @@ Array [ "termGroupId", "termTaxonomyId", "uri", - "nodeType", "parent", "children", "internal", @@ -1212,7 +1201,6 @@ Array [ "parentId", "replies", "type", - "nodeType", "parent", "children", "internal", @@ -1227,7 +1215,6 @@ Array [ "id", "name", "url", - "nodeType", "parent", "children", "internal", @@ -1424,7 +1411,6 @@ Array [ "slug", "status", "uri", - "nodeType", "parent", "children", "internal", @@ -1556,7 +1542,6 @@ Array [ "showInRest", "showUi", "uri", - "nodeType", "parent", "children", "internal", @@ -5575,7 +5560,6 @@ Array [ "status", "title", "uri", - "nodeType", "localFile", "parent", "children", @@ -5704,7 +5688,6 @@ Array [ "menuItems", "name", "slug", - "nodeType", "parent", "children", "internal", @@ -5776,7 +5759,6 @@ Array [ "target", "title", "url", - "nodeType", "parent", "children", "internal", @@ -5971,9 +5953,62 @@ Array [ "status", "template", "uri", + "parent", + "children", + "internal", ], "name": "WpNodeWithFeaturedImage", }, + Object { + "fields": Array [ + "totalCount", + "edges", + "nodes", + "pageInfo", + "distinct", + "max", + "min", + "sum", + "group", + ], + "name": "WpNodeWithFeaturedImageConnection", + }, + Object { + "fields": Array [ + "next", + "node", + "previous", + ], + "name": "WpNodeWithFeaturedImageEdge", + }, + Object { + "fields": null, + "name": "WpNodeWithFeaturedImageFieldsEnum", + }, + Object { + "fields": null, + "name": "WpNodeWithFeaturedImageFilterInput", + }, + Object { + "fields": Array [ + "totalCount", + "edges", + "nodes", + "pageInfo", + "distinct", + "max", + "min", + "sum", + "group", + "field", + "fieldValue", + ], + "name": "WpNodeWithFeaturedImageGroupConnection", + }, + Object { + "fields": null, + "name": "WpNodeWithFeaturedImageSortInput", + }, Object { "fields": Array [ "node", @@ -6063,7 +6098,6 @@ Array [ "template", "title", "uri", - "nodeType", "beforeChangeNodeTest", "parent", "children", @@ -6288,7 +6322,6 @@ Array [ "title", "toPing", "uri", - "nodeType", "beforeChangeNodeTest", "parent", "children", @@ -6349,7 +6382,6 @@ Array [ "termGroupId", "termTaxonomyId", "uri", - "nodeType", "parent", "children", "internal", @@ -6620,7 +6652,6 @@ Array [ "template", "title", "uri", - "nodeType", "parent", "children", "internal", @@ -7090,7 +7121,6 @@ Array [ "termGroupId", "termTaxonomyId", "uri", - "nodeType", "parent", "children", "internal", @@ -7203,7 +7233,6 @@ Array [ "showInQuickEdit", "showInRest", "showUi", - "nodeType", "parent", "children", "internal", @@ -7322,7 +7351,6 @@ Array [ "termGroupId", "termTaxonomyId", "uri", - "nodeType", "parent", "children", "internal", @@ -7417,7 +7445,6 @@ Array [ "template", "title", "uri", - "nodeType", "parent", "children", "internal", @@ -7512,7 +7539,6 @@ Array [ "template", "title", "uri", - "nodeType", "parent", "children", "internal", @@ -7607,7 +7633,6 @@ Array [ "template", "title", "uri", - "nodeType", "parent", "children", "internal", @@ -7704,7 +7729,6 @@ Array [ "uri", "url", "username", - "nodeType", "parent", "children", "internal", @@ -7763,7 +7787,6 @@ Array [ "displayName", "id", "name", - "nodeType", "parent", "children", "internal", diff --git a/integration-tests/gatsby-source-wordpress/__tests__/index.js b/integration-tests/gatsby-source-wordpress/__tests__/index.js index f87165d0c675a..b5ae4b61b9e56 100644 --- a/integration-tests/gatsby-source-wordpress/__tests__/index.js +++ b/integration-tests/gatsby-source-wordpress/__tests__/index.js @@ -18,8 +18,45 @@ const { resetSchema, } = require(`../test-fns/test-utils/increment-remote-data`) +const { + default: fetchGraphql, +} = require("gatsby-source-wordpress/dist/utils/fetch-graphql") + jest.setTimeout(100000) +const pluginsAreReady = async () => { + let pluginsAreReady = false + let tryCount = 0 + + while (!pluginsAreReady && tryCount < 20) { + try { + tryCount++ + + const response = await fetchGraphql({ + url: `http://localhost:8001/graphql`, + query: /* GraphQL */ ` + { + __type(name: "AttachFeaturedImageToNodeByIdPayload") { + name + } + } + `, + }) + + if ( + response?.data?.__type?.name === `AttachFeaturedImageToNodeByIdPayload` + ) { + pluginsAreReady = true + } + } catch (e) { + console.error(e) + await new Promise(resolve => setTimeout(resolve, 1000)) + } + } + + return pluginsAreReady +} + // we run these tests twice in a row // to make sure everything passes on a warm cache build // we don't need to re-run some tests the second time, @@ -34,6 +71,9 @@ describe(`[gatsby-source-wordpress] Build default options`, () => { console.log(`Waiting for WPGraphQL to be ready...`) await urling({ url: `http://localhost:8001/graphql`, retry: 100 }) console.log(`WPGraphQL is ready`) + console.log(`Waiting for plugins to be ready...`) + await pluginsAreReady() + console.log(`Plugins are ready`) if (isWarmCache) { done() diff --git a/integration-tests/gatsby-source-wordpress/test-fns/test-utils/queries.js b/integration-tests/gatsby-source-wordpress/test-fns/test-utils/queries.js index 92766fa6cba0f..88c83d0fc2f05 100644 --- a/integration-tests/gatsby-source-wordpress/test-fns/test-utils/queries.js +++ b/integration-tests/gatsby-source-wordpress/test-fns/test-utils/queries.js @@ -530,7 +530,6 @@ exports.queries = { id label databaseId - nodeType target title url @@ -670,7 +669,6 @@ exports.queries = { writingSettingsDefaultPostFormat writingSettingsUseSmilies } - nodeType writingSettings { defaultCategory defaultPostFormat diff --git a/packages/gatsby-source-wordpress/src/models/remoteSchema.ts b/packages/gatsby-source-wordpress/src/models/remoteSchema.ts index a1c3a4ae1c8c0..cab71e6d57c03 100644 --- a/packages/gatsby-source-wordpress/src/models/remoteSchema.ts +++ b/packages/gatsby-source-wordpress/src/models/remoteSchema.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { findTypeName } from "~/steps/create-schema-customization/helpers" +import { findNamedTypeName } from "~/steps/create-schema-customization/helpers" interface IRemoteSchemaState { wpUrl: string @@ -130,7 +130,7 @@ const remoteSchema: IRemoteSchemaStore = { }, addFetchedType(state, type) { - const key = findTypeName(type) + const key = findNamedTypeName(type) if (!key) { return state diff --git a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/build-types.js b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/build-types.js index 87966d6171be6..62fdb1d5e4fff 100644 --- a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/build-types.js +++ b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/build-types.js @@ -3,8 +3,6 @@ import { transformFields } from "./transform-fields" import { typeIsExcluded } from "~/steps/ingest-remote-schema/is-excluded" import { buildTypeName, - fieldOfTypeWasFetched, - getTypeSettingsByType, filterTypeDefinition, getTypesThatImplementInterfaceType, } from "./helpers" @@ -72,34 +70,20 @@ const interfaceType = typeBuilderApi => { extensions: { infer: false }, } - // if this is a node interface type - if (nodeInterfaceTypes.includes(type.name)) { - // we add nodeType (post type) to all nodes as they're fetched - // so we can add them to node interfaces as well in order to filter - // by a couple different content types - typeDef.fields[`nodeType`] = `String` - typeDef.interfaces = [`Node`] - } else { - // otherwise this is a regular interface type so we need to resolve the type name + // this is a regular interface type, not a node interface type so we need to resolve the type name + if (!nodeInterfaceTypes.includes(type.name)) { typeDef.resolveType = node => node?.__typename ? buildTypeName(node.__typename) : null } - // @todo add this as a plugin option typeDef = filterTypeDefinition(typeDef, typeBuilderApi, `INTERFACE`) return schema.buildInterfaceType(typeDef) } const objectType = typeBuilderApi => { - const { - type, - gatsbyNodeTypes, - fieldAliases, - fieldBlacklist, - schema, - isAGatsbyNode, - } = typeBuilderApi + const { type, gatsbyNodeTypes, fieldAliases, fieldBlacklist, schema } = + typeBuilderApi const transformedFields = transformFields({ fields: type.fields, @@ -126,35 +110,8 @@ const objectType = typeBuilderApi => { }, } - if (type.interfaces) { - objectType.interfaces = type.interfaces - .filter(interfaceType => { - const interfaceTypeSettings = getTypeSettingsByType(interfaceType) - - return ( - !interfaceTypeSettings.exclude && - fieldOfTypeWasFetched(type) && - fieldOfTypeWasFetched(interfaceType) - ) - }) - .map(({ name }) => buildTypeName(name)) - } - - if ( - gatsbyNodeTypes.includes(type.name) || - isAGatsbyNode || - // this accounts for Node types that weren't fetched because - // they have no root field to fetch a single node of this type - // removing them from the schema breaks the build though - // @todo instead, if a node type isn't fetched, remove it - // from the entire schema - type?.interfaces?.find(({ name }) => name === `Node`) - ) { - // this is used to filter the node interfaces - // by different content types (post types) - objectType.fields[`nodeType`] = `String` - - objectType.interfaces = [`Node`, ...objectType.interfaces] + if (type.interfaces?.includes(`Node`)) { + objectType.interfaces = [`Node`] } // @todo add this as a plugin option diff --git a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/helpers.js b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/helpers.js index d16c6dd836be1..440e2b319f57b 100644 --- a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/helpers.js +++ b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/helpers.js @@ -3,6 +3,49 @@ import { typeDefinitionFilters } from "./type-filters" import { getPluginOptions } from "~/utils/get-gatsby-api" import { cloneDeep, merge } from "lodash" +export const buildInterfacesListForType = type => { + let shouldAddNodeType = false + + const list = (type?.interfaces || []) + .filter(interfaceType => { + const interfaceTypeSettings = getTypeSettingsByType(interfaceType) + + return ( + !interfaceTypeSettings.exclude && fieldOfTypeWasFetched(interfaceType) + ) + }) + .map(({ name }) => { + if (name === `Node`) { + shouldAddNodeType = true + } + return buildTypeName(name) + }) + + if (shouldAddNodeType) { + list.push(`Node`) + } + + return list +} + +let ceIntCache = null +const isWpgqlOneThirteenZeroPlus = () => { + if (ceIntCache !== null) { + return ceIntCache + } + + const { typeMap } = store.getState().remoteSchema + + const connectionInterface = !!typeMap.get(`Connection`) + const edgeInterface = !!typeMap.get(`Edge`) + + const isWpgqlOneThirteenZeroPlus = connectionInterface || edgeInterface + + ceIntCache = isWpgqlOneThirteenZeroPlus + + return isWpgqlOneThirteenZeroPlus +} + /** * This function namespaces typenames with a prefix */ @@ -20,10 +63,22 @@ export const buildTypeName = name => { return name } + // Gatsby makes the same type, so we need to rename it to prevent conflicts if (name === `Filter`) { name = `FilterType` } + if ( + // Starting in WPGraphQL 1.13.0, Gatsby and WPGraphQL both generate types ending in these strings for every node type in the schema, so we need to rename types to prevent conflicts. + // for users on older versions of WPGraphQL we should try to keep the schema how it was before + isWpgqlOneThirteenZeroPlus() && + (name.endsWith(`Connection`) || + name.endsWith(`Edge`) || + name.endsWith(`PageInfo`)) + ) { + name += `Type` + } + if (name.startsWith(prefix)) { return name } @@ -31,29 +86,43 @@ export const buildTypeName = name => { return prefix + name } -/** - * Find the first type name of a Type definition pulled via introspection - * @param {object} type - */ -export const findTypeName = type => - type?.name || - type?.ofType?.name || - type?.ofType?.ofType?.name || - type?.ofType?.ofType?.ofType?.name - /** * Find the first type kind of a Type definition pulled via introspection * @param {object} type */ -export const findTypeKind = type => - type?.kind || - type?.ofType?.kind || - type?.ofType?.ofType?.kind || - type?.ofType?.ofType?.ofType?.kind +export const findTypeKind = type => { + if (type?.kind) { + return type.kind + } + + if (type?.ofType) { + return findTypeKind(type.ofType) + } + + return null +} + +export const findNamedType = type => { + if (!type) { + return null + } + + if (type.ofType) { + return findNamedType(type.ofType) + } + + return type +} + +export const findNamedTypeName = type => { + const namedType = findNamedType(type) + + return namedType?.name +} export const fieldOfTypeWasFetched = type => { const { fetchedTypes } = store.getState().remoteSchema - const typeName = findTypeName(type) + const typeName = findNamedTypeName(type) const typeWasFetched = !!fetchedTypes.get(typeName) return typeWasFetched @@ -104,7 +173,7 @@ const supportedScalars = [ export const typeIsABuiltInScalar = type => // @todo the next function and this one are redundant. // see the next todo on how to fix the issue. If that todo is resolved, these functions will be identical. :( - supportedScalars.includes(findTypeName(type)) + supportedScalars.includes(findNamedTypeName(type)) export const typeIsASupportedScalar = type => { if (findTypeKind(type) !== `SCALAR`) { @@ -113,7 +182,7 @@ export const typeIsASupportedScalar = type => { return true } - return supportedScalars.includes(findTypeName(type)) + return supportedScalars.includes(findNamedTypeName(type)) } const typeSettingCache = new Map() @@ -124,7 +193,7 @@ export const getTypeSettingsByType = type => { return {} } - const typeName = findTypeName(type) + const typeName = findNamedTypeName(type) if (!typeName) { return {} @@ -188,3 +257,44 @@ export const filterTypeDefinition = ( return typeDefinition } + +// we should be using graphql-js for this kind of thing, but unfortunately this project didn't use it from the beginning so it would be a huge lift to refactor to use it now. In the future we will be rewriting this plugin using a new Gatsby source plugin toolkit, and at that time we'll use graphql-js. +// from introspection field types this will return a value like: +// `String` or `[String]` or `[String!]!` or `[String]!` or `[[String]]` or `[[String]!]!` or `[[String]!]`, etc +export const introspectionFieldTypeToSDL = fieldType => { + const openingTagsList = [] + const closingTagsList = [] + + let reference = fieldType + + while (reference) { + switch (reference.kind) { + case `SCALAR`: { + const normalizedTypeName = supportedScalars.includes(reference.name) + ? reference.name + : `JSON` + + openingTagsList.push(normalizedTypeName) + break + } + case `OBJECT`: + case `INTERFACE`: + case `UNION`: + openingTagsList.push(buildTypeName(reference.name)) + break + case `NON_NULL`: + closingTagsList.push(`!`) + break + case `LIST`: + openingTagsList.push(`[`) + closingTagsList.push(`]`) + break + default: + break + } + + reference = reference.ofType + } + + return openingTagsList.join(``) + closingTagsList.reverse().join(``) +} diff --git a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/index.js b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/index.js index eb181e3db5015..88ced3038a379 100644 --- a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/index.js +++ b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/index.js @@ -1,6 +1,6 @@ import store from "~/store" -import { fieldOfTypeWasFetched } from "./helpers" +import { buildInterfacesListForType, fieldOfTypeWasFetched } from "./helpers" import buildType from "./build-types" import { getGatsbyNodeTypeNames } from "../source-nodes/fetch-nodes/fetch-nodes" @@ -67,6 +67,11 @@ const customizeSchema = async ({ actions, schema, store: gatsbyStore }) => { break } + if (type.interfaces && builtType?.config) { + builtType.config.interfaces ||= [] + builtType.config.interfaces.push(...buildInterfacesListForType(type)) + } + if (builtType) { typeDefs.push(builtType) } @@ -86,9 +91,10 @@ const customizeSchema = async ({ actions, schema, store: gatsbyStore }) => { fields: nonNodeRootFields, interfaces: [`Node`], }, - isAGatsbyNode: true, }) + typeDefs.push(wpType) + typeDefs.push( addRemoteFilePolyfillInterface( schema.buildObjectType({ @@ -104,8 +110,6 @@ const customizeSchema = async ({ actions, schema, store: gatsbyStore }) => { ) ) - typeDefs.push(wpType) - actions.createTypes(typeDefs) } diff --git a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/default-resolver.js b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/default-resolver.js index 1c3c8e55ad8ec..6976cc9f1a8fe 100644 --- a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/default-resolver.js +++ b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/default-resolver.js @@ -1,4 +1,4 @@ -import { findTypeName } from "~/steps/create-schema-customization/helpers" +import { findNamedTypeName } from "~/steps/create-schema-customization/helpers" import { buildGatsbyNodeObjectResolver } from "~/steps/create-schema-customization/transform-fields/transform-object" import { buildTypeName } from "../helpers" @@ -25,7 +25,7 @@ export const buildDefaultResolver = transformerApi => (source, _, context) => { finalFieldValue = aliasedField } - // the findTypeName helpers was written after this resolver + // the findNamedTypeName helpers was written after this resolver // had been in production for a while. // so we don't know if in all cases it will find the right typename // for this resolver.. @@ -34,7 +34,7 @@ export const buildDefaultResolver = transformerApi => (source, _, context) => { // using many different WPGraphQL extensions // then come back and remove the `return aliasedField` line and // see if this still resolves everything properly - const typeName = findTypeName(field.type) + const typeName = findNamedTypeName(field.type) const autoAliasedFieldName = `${fieldName}__typename_${typeName}` const aliasedField2 = source[autoAliasedFieldName] diff --git a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/field-transformers.js b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/field-transformers.js index e9ce4739090d6..bde1e189d4f8a 100644 --- a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/field-transformers.js +++ b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/field-transformers.js @@ -1,8 +1,10 @@ -import { buildTypeName, findTypeName, findTypeKind } from "../helpers" +import { buildTypeName, findNamedTypeName, findTypeKind } from "../helpers" import { transformUnion, transformListOfUnions } from "./transform-union" -import { transformGatsbyNodeObject } from "~/steps/create-schema-customization/transform-fields/transform-object" -import { transformListOfGatsbyNodes } from "./transform-object" -import { getGatsbyNodeTypeNames } from "~/steps/source-nodes/fetch-nodes/fetch-nodes" +import { + transformListOfGatsbyNodes, + transformGatsbyNodeObject, +} from "./transform-object" +import { getGatsbyNodeTypeNames } from "../../source-nodes/fetch-nodes/fetch-nodes" import { typeIsABuiltInScalar } from "~/steps/create-schema-customization/helpers" import store from "~/store" import { typeIsExcluded } from "~/steps/ingest-remote-schema/is-excluded" @@ -16,7 +18,7 @@ export const fieldTransformers = [ transform: ({ field }) => { if (typeIsABuiltInScalar(field.type)) { - return `${field.type.ofType.name}!` + return `${findNamedTypeName(field.type.ofType)}!` } else { return `JSON!` } @@ -31,7 +33,7 @@ export const fieldTransformers = [ (field.type.ofType.name || field.type.ofType?.ofType?.name), transform: ({ field }) => { - const typeName = findTypeName(field.type) + const typeName = findNamedTypeName(field.type) const normalizedTypeName = typeIsABuiltInScalar(field.type) ? typeName : buildTypeName(typeName) @@ -40,6 +42,24 @@ export const fieldTransformers = [ }, }, + { + description: `Lists of Gatsby node interfaces`, + test: field => { + const implementsNodeInterface = store + .getState() + .remoteSchema.typeMap.get(findNamedTypeName(field.type)) + ?.interfaces?.some(i => i.name === `Node`) + + const isAListOfGatsbyNodeInterfaces = + (field.type.kind === `LIST` || field.type.ofType?.kind === `LIST`) && + implementsNodeInterface + + return isAListOfGatsbyNodeInterfaces + }, + + transform: transformListOfGatsbyNodes, + }, + { description: `NON_NULL lists of NON_NULL types`, test: field => @@ -48,16 +68,16 @@ export const fieldTransformers = [ field.type.ofType?.ofType?.kind === `NON_NULL`, transform: ({ field, fieldName }) => { - const originalTypeName = findTypeName(field.type) + const originalTypeName = findNamedTypeName(field.type) const typeKind = findTypeKind(field.type) - const normalizedType = + const normalizedTypeName = typeKind === `SCALAR` && typeIsABuiltInScalar(field.type) ? originalTypeName : buildTypeName(originalTypeName) return { - type: `[${normalizedType}!]!`, + type: `[${normalizedTypeName}!]!`, resolve: source => { const resolvedField = source[fieldName] @@ -83,7 +103,7 @@ export const fieldTransformers = [ (field.type.ofType.name ?? field.type.ofType?.ofType?.name) && typeIsABuiltInScalar(field.type), - transform: ({ field }) => `[${findTypeName(field.type)}!]`, + transform: ({ field }) => `[${findNamedTypeName(field.type)}!]`, }, { @@ -93,7 +113,8 @@ export const fieldTransformers = [ field.type.ofType.kind === `NON_NULL` && (field.type.ofType.name ?? field.type.ofType?.ofType?.name), - transform: ({ field }) => `[${buildTypeName(findTypeName(field.type))}!]`, + transform: ({ field }) => + `[${buildTypeName(findNamedTypeName(field.type))}!]`, }, { @@ -131,7 +152,7 @@ export const fieldTransformers = [ store .getState() // get the full type for this interface - .remoteSchema.typeMap.get(findTypeName(field.type)) + .remoteSchema.typeMap.get(findNamedTypeName(field.type)) // filter out any excluded types .possibleTypes?.filter( possibleType => @@ -225,7 +246,8 @@ export const fieldTransformers = [ test: field => field.type.kind === `LIST` && field.type.ofType.kind === `INTERFACE`, - transform: ({ field }) => `[${buildTypeName(field.type.ofType.name)}]`, + transform: ({ field }) => + `[${buildTypeName(findNamedTypeName(field.type))}]`, }, { @@ -244,7 +266,8 @@ export const fieldTransformers = [ description: `Lists of NON_NULL types`, test: field => findTypeKind(field.type) !== `LIST` && field.type.kind === `NON_NULL`, - transform: ({ field }) => `${buildTypeName(findTypeName(field.type))}!`, + transform: ({ field }) => + `${buildTypeName(findNamedTypeName(field.type))}!`, }, // for finding unhandled types diff --git a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/index.js b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/index.js index c16c7037196e5..74671b9fa77ce 100644 --- a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/index.js +++ b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/index.js @@ -6,8 +6,8 @@ import { fieldOfTypeWasFetched, typeIsASupportedScalar, getTypeSettingsByType, - findTypeName, -} from "~/steps/create-schema-customization/helpers" + findNamedTypeName, +} from "../helpers" import { buildDefaultResolver } from "./default-resolver" @@ -47,7 +47,7 @@ export const returnAliasedFieldName = ({ fieldAliases, field }) => ? `${fieldAliases[field.name]}: ${field.name}` : field.name -const excludeField = ({ +const fieldIsExcluded = ({ field, fieldName, thisTypeSettings, @@ -57,8 +57,8 @@ const excludeField = ({ }) => // this field wasn't previously fetched, so we shouldn't // add it to our schema - !fieldOfTypeWasFetched(field.type) || - // this field was excluded on it's parent fields Type + (!fieldOfTypeWasFetched(field.type) && fieldName !== `id`) || + // this field was excluded on its parent fields Type (parentTypeSettings.excludeFieldNames && parentTypeSettings.excludeFieldNames.includes(fieldName)) || // this field is on an interface type and one of the implementing types has this field excluded on it. @@ -77,12 +77,7 @@ const excludeField = ({ // this field has required input args (field.args && field.args.find(arg => arg.type.kind === `NON_NULL`)) || // this field has no typeName - !findTypeName(field.type) || - // field is a non null object - // @todo this looks unnecessary. Need to look into why non null object types are excluded - (field.type.kind === `NON_NULL` && field.type.ofType.kind === `OBJECT`) || - // field is a non null enum - (field.type.kind === `NON_NULL` && field.type.ofType.kind === `ENUM`) + !findNamedTypeName(field.type) /** * Transforms fields from the WPGQL schema to work in the Gatsby schema @@ -93,6 +88,7 @@ export const transformFields = ({ fields, parentType, parentInterfacesImplementingTypes, + peek = false, }) => { if (!fields || !fields.length) { return null @@ -122,7 +118,7 @@ export const transformFields = ({ const fieldName = getAliasedFieldName({ fieldAliases, field }) if ( - excludeField({ + fieldIsExcluded({ field, fieldName, thisTypeSettings, @@ -136,12 +132,12 @@ export const transformFields = ({ const { typeMap } = store.getState().remoteSchema - const type = typeMap.get(findTypeName(field.type)) + const type = typeMap.get(findNamedTypeName(field.type)) const includedChildFields = type?.fields?.filter(field => { const childFieldTypeSettings = getTypeSettingsByType(field.type) const fieldName = getAliasedFieldName({ fieldAliases, field }) - return !excludeField({ + return !fieldIsExcluded({ field, fieldName, thisTypeSettings: childFieldTypeSettings, @@ -163,9 +159,11 @@ export const transformFields = ({ field = handleCustomScalars(field) const { transform, description } = - fieldTransformers.find(({ test }) => test(field)) || {} + peek === false + ? fieldTransformers.find(({ test }) => test(field)) || {} + : {} - if (transform && typeof transform === `function`) { + if (transform && typeof transform === `function` && peek === false) { const transformerApi = { field, fieldsObject, @@ -193,6 +191,8 @@ export const transformFields = ({ } fieldsObject[fieldName] = transformedField + } else if (peek) { + fieldsObject[fieldName] = true } return fieldsObject diff --git a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/transform-object.js b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/transform-object.js index 3062662e4531e..329ff90cd2301 100644 --- a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/transform-object.js +++ b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/transform-object.js @@ -5,13 +5,15 @@ import { getGatsbyApi } from "~/utils/get-gatsby-api" import { inPreviewMode } from "~/steps/preview/index" import { getPluginOptions } from "../../../utils/get-gatsby-api" import { usingGatsbyV4OrGreater } from "~/utils/gatsby-version" +import { findNamedTypeName, introspectionFieldTypeToSDL } from "../helpers" export const transformListOfGatsbyNodes = ({ field, fieldName }) => { - const typeName = buildTypeName(field.type.ofType.name) + const typeSDLString = introspectionFieldTypeToSDL(field.type) + const typeName = buildTypeName(findNamedTypeName(field.type)) return { - type: `[${typeName}]`, - resolve: (source, args, context) => { + type: typeSDLString, + resolve: (source, _args, context) => { let nodes = null const field = source[fieldName] @@ -36,7 +38,7 @@ export const transformListOfGatsbyNodes = ({ field, fieldName }) => { export const buildGatsbyNodeObjectResolver = ({ field, fieldName }) => - async (source, _, context) => { + async (source, _args, context) => { const typeName = buildTypeName(field.type.name) const nodeField = source[fieldName] diff --git a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/transform-union.js b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/transform-union.js index 1483928f38387..8748cae2e38e5 100644 --- a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/transform-union.js +++ b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/transform-fields/transform-union.js @@ -1,4 +1,5 @@ import { buildTypeName } from "~/steps/create-schema-customization/helpers" +import { findNamedTypeName, introspectionFieldTypeToSDL } from "../helpers" export const transformUnion = ({ field, fieldName }) => { return { @@ -25,10 +26,10 @@ export const transformUnion = ({ field, fieldName }) => { } export const transformListOfUnions = ({ field, fieldName }) => { - const typeName = buildTypeName(field.type.ofType.name) + const typeSDLString = introspectionFieldTypeToSDL(field.type) return { - type: `[${typeName}]`, + type: typeSDLString, resolve: (source, _, context) => { const resolvedField = source[fieldName] ?? diff --git a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/type-filters.js b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/type-filters.js index a4aa5ba83e6d3..17f23ea92c7f8 100644 --- a/packages/gatsby-source-wordpress/src/steps/create-schema-customization/type-filters.js +++ b/packages/gatsby-source-wordpress/src/steps/create-schema-customization/type-filters.js @@ -1,6 +1,3 @@ -import { createLocalFileNode } from "~/steps/source-nodes/create-nodes/create-local-file-node" - -// @todo move this to plugin options export const typeDefinitionFilters = [ { typeName: `__all`, @@ -64,17 +61,6 @@ export const typeDefinitionFilters = [ { typeName: `MediaItem`, typeDef: objectType => { - // @todo: this field is deprecated as of 0.1.8, remove this when we get to beta - objectType.fields.remoteFile = { - type: `File`, - deprecationReason: `MediaItem.remoteFile was renamed to localFile`, - resolve: () => { - throw new Error( - `MediaItem.remoteFile is deprecated and has been renamed to MediaItem.localFile. Please update your code.` - ) - }, - } - objectType.fields.localFile = { type: `File`, extensions: { diff --git a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/build-node-queries.js b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/build-node-queries.js index 311c1a627162f..1f32d6266b973 100644 --- a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/build-node-queries.js +++ b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/build-node-queries.js @@ -1,6 +1,6 @@ import store from "~/store" import { getGatsbyApi } from "~/utils/get-gatsby-api" -import generateNodeQueriesFromIngestibleFields from "~/steps/ingest-remote-schema/build-queries-from-introspection/generate-queries-from-ingestable-types" +import generateNodeQueriesFromIngestibleFields from "./generate-queries-from-ingestable-types" import { getPersistentCache, setPersistentCache } from "~/utils/cache" /** diff --git a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/build-query-on-field-name.js b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/build-query-on-field-name.js index 73f159594c673..f74970264f39b 100644 --- a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/build-query-on-field-name.js +++ b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/build-query-on-field-name.js @@ -1,5 +1,5 @@ import store from "~/store" -import { findTypeName } from "~/steps/create-schema-customization/helpers" +import { findNamedTypeName } from "~/steps/create-schema-customization/helpers" const buildReusableFragments = ({ fragments }) => Object.values(fragments) @@ -159,7 +159,7 @@ export const buildSelectionSet = ( } ` } else if (fieldName) { - const fullFieldType = typeMap.get(findTypeName(fieldType)) + const fullFieldType = typeMap.get(findNamedTypeName(fieldType)) // if this field has subfields but we didn't build a selection set for it // we shouldn't fetch this field. This can happen when we have self referencing types that are limited by the schema.circularQueryLimit plugin option. diff --git a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/generate-queries-from-ingestable-types.js b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/generate-queries-from-ingestable-types.js index d5f3deffbd3b6..7fba7552c708c 100644 --- a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/generate-queries-from-ingestable-types.js +++ b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/generate-queries-from-ingestable-types.js @@ -15,6 +15,7 @@ import store from "~/store" import { getTypeSettingsByType } from "~/steps/create-schema-customization/helpers" import prettier from "prettier" import { formatLogMessage } from "~/utils/format-log-message" +import { findNamedTypeName } from "../../create-schema-customization/helpers" const recursivelyAliasFragments = field => field.inlineFragments.map(fragment => { @@ -150,7 +151,15 @@ const generateNodeQueriesFromIngestibleFields = async () => { const nodesField = fieldFields.find(nodeListFilter) // the type of this query - const nodesType = typeMap.get(nodesField.type.ofType.name) + const nodesType = typeMap.get(findNamedTypeName(nodesField.type)) + + if (!nodesType) { + reporter.panic( + formatLogMessage( + `Couldn't infer node type in the remote schema from the ${name} root field.` + ) + ) + } const { fields, possibleTypes } = nodesType diff --git a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/recursively-transform-fields.js b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/recursively-transform-fields.js index acf2bcc549228..18847d1de5834 100644 --- a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/recursively-transform-fields.js +++ b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/build-queries-from-introspection/recursively-transform-fields.js @@ -1,7 +1,7 @@ import store from "~/store" import { getTypeSettingsByType, - findTypeName, + findNamedTypeName, findTypeKind, } from "~/steps/create-schema-customization/helpers" import { @@ -165,7 +165,7 @@ export function transformField({ // count the number of times this type has appeared as an ancestor of itself // somewhere up the tree - const typeName = findTypeName(field.type) + const typeName = findNamedTypeName(field.type) const typeKind = findTypeKind(field.type) const typeIncarnationCount = countIncarnations({ @@ -219,15 +219,15 @@ export function transformField({ return false } - const fieldType = typeMap.get(findTypeName(field.type)) || {} - const ofType = typeMap.get(findTypeName(fieldType.ofType)) || {} + const fieldType = typeMap.get(findNamedTypeName(field.type)) || {} + const ofType = typeMap.get(findNamedTypeName(fieldType.ofType)) || {} if ( fieldType.kind === `SCALAR` || fieldType.kind === `ENUM` || (fieldType.kind === `NON_NULL` && ofType.kind === `SCALAR`) || (fieldType.kind === `LIST` && fieldType.ofType.kind === `SCALAR`) || - // a list of enums has no type name, so findTypeName above finds the enum type + // a list of enums has no type name, so findNamedTypeName above finds the enum type // instead of the field type. Need to explicitly check here // instead of using helpers (field.type.kind === `LIST` && field.type?.ofType?.kind === `ENUM`) @@ -252,7 +252,7 @@ export function transformField({ ) { return { fieldName: fieldName, - fields: [`id`], + fields: [`__typename`, `id`], fieldType, } } else if (fieldType.kind === `LIST` && isListOfMediaItems && hasIdField) { @@ -262,7 +262,7 @@ export function transformField({ fieldType, } } else if (fieldType.kind === `LIST`) { - const listOfType = typeMap.get(findTypeName(fieldType)) + const listOfType = typeMap.get(findNamedTypeName(fieldType)) const transformedFields = recursivelyTransformFields({ fields: listOfType.fields, @@ -313,32 +313,15 @@ export function transformField({ gatsbyNodesInfo.typeNames.includes(possibleType.name) ) - const isAMediaItemNode = isAGatsbyNode && typeName === `MediaItem` - - // pull the id and __typename for connections to media item gatsby nodes - if (isAMediaItemNode && hasIdField) { + if (isAGatsbyNode && hasIdField) { return { fieldName: fieldName, fields: [`__typename`, `id`], fieldType, } - } else if (isAGatsbyNode && hasIdField) { - const isAnInterfaceType = - // if this is an interface - typeKind === `INTERFACE` || fieldType.kind === `INTERFACE` - - return { - fieldName: fieldName, - fields: isAnInterfaceType - ? // we need the typename for interfaces - [`id`, `__typename`] - : // or just the id for 1:1 connections to gatsby nodes - [`id`], - fieldType, - } } - const typeInfo = typeMap.get(findTypeName(fieldType)) + const typeInfo = typeMap.get(findNamedTypeName(fieldType)) const { fields } = typeInfo || {} @@ -440,7 +423,7 @@ const createFragment = ({ mainType, buildingFragment = false, }) => { - const typeName = findTypeName(type) + const typeName = findNamedTypeName(type) if (buildingFragment) { // this fragment is inside a fragment that's already being built so we should exit @@ -454,7 +437,7 @@ const createFragment = ({ } const fragmentFields = fields.reduce((fragmentFields, field) => { - const fieldTypeName = findTypeName(field.type) + const fieldTypeName = findNamedTypeName(field.type) const fieldType = typeMap.get(fieldTypeName) if ( @@ -462,7 +445,7 @@ const createFragment = ({ // we need to skip this field in the fragment to prevent nesting this type in itself a level down fieldType.name !== typeName && fieldType?.fields?.find( - innerFieldField => findTypeName(innerFieldField.type) === typeName + innerFieldField => findNamedTypeName(innerFieldField.type) === typeName ) ) { return fragmentFields @@ -483,7 +466,7 @@ const createFragment = ({ buildingFragment: typeName, }) - if (findTypeName(field.type) !== typeName && !!transformedField) { + if (findNamedTypeName(field.type) !== typeName && !!transformedField) { fragmentFields.push(transformedField) } @@ -572,7 +555,7 @@ const transformFields = ({ store.dispatch.remoteSchema.addFetchedType(field.type) } - const typeName = findTypeName(field.type) + const typeName = findNamedTypeName(field.type) const fragment = fragments?.[typeName] // @todo add any adjacent fields and inline fragments directly to the stored fragment object so this logic can be changed to if (fragment) useTheFragment() @@ -677,7 +660,7 @@ const recursivelyTransformFields = ({ return null } - const typeName = findTypeName(parentType) + const typeName = findNamedTypeName(parentType) const grandParentTypeName = ancestorTypeNames.length ? ancestorTypeNames[ancestorTypeNames.length - 1] @@ -691,7 +674,7 @@ const recursivelyTransformFields = ({ // that only an id needs to be fetched. // @todo maybe move this into transformFields() instead of here fields = fields.filter(field => { - const fieldTypeName = findTypeName(field.type) + const fieldTypeName = findNamedTypeName(field.type) return fieldTypeName !== grandParentTypeName }) } diff --git a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/identify-and-store-ingestable-types.js b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/identify-and-store-ingestable-types.js index b551dcc58c986..6f15eed33ad81 100644 --- a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/identify-and-store-ingestable-types.js +++ b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/identify-and-store-ingestable-types.js @@ -2,10 +2,11 @@ import store from "~/store" import { typeIsExcluded } from "~/steps/ingest-remote-schema/is-excluded" import { typeIsABuiltInScalar } from "../create-schema-customization/helpers" import { - findTypeName, + findNamedTypeName, getTypesThatImplementInterfaceType, + findNamedType, } from "~/steps/create-schema-customization/helpers" -import { transformFields } from "~/steps/create-schema-customization/transform-fields" +import { transformFields } from "../create-schema-customization/transform-fields" import { getPersistentCache } from "~/utils/cache" const identifyAndStoreIngestableFieldsAndTypes = async () => { @@ -27,6 +28,11 @@ const identifyAndStoreIngestableFieldsAndTypes = async () => { }) } + const nodeInterfaceTypes = [] + const nodeListRootFields = [] + const nonNodeRootFields = [] + const nodeInterfacePossibleTypeNames = [] + if (pluginOptions.type) { Object.entries(pluginOptions.type).forEach(([typeName, typeSettings]) => { // our lazy types won't initially be fetched, @@ -38,53 +44,15 @@ const identifyAndStoreIngestableFieldsAndTypes = async () => { const lazyType = typeMap.get(typeName) store.dispatch.remoteSchema.addFetchedType(lazyType) } - }) - } - - const interfaces = introspectionData.__schema.types.filter( - type => type.kind === `INTERFACE` - ) - - for (const interfaceType of interfaces) { - if (typeIsExcluded({ pluginOptions, typeName: interfaceType.name })) { - continue - } - - if (!interfaceType.fields) { - continue - } - - const typesThatImplementInterface = - getTypesThatImplementInterfaceType(interfaceType) - const shouldSkipInterfaceType = !transformFields({ - fields: interfaceType.fields, - parentType: interfaceType, - parentInterfacesImplementingTypes: typesThatImplementInterface, - }) - - if (shouldSkipInterfaceType && interfaceType.name !== `Node`) { - continue - } - - store.dispatch.remoteSchema.addFetchedType(interfaceType) - - if (interfaceType.fields) { - for (const interfaceField of interfaceType.fields) { - if (interfaceField.type) { - store.dispatch.remoteSchema.addFetchedType(interfaceField.type) - } + if (typeSettings.nodeInterface) { + nodeInterfaceTypes.push(typeName) } - } + }) } const rootFields = typeMap.get(`RootQuery`).fields - const nodeInterfaceTypes = [] - const nodeListRootFields = [] - const nonNodeRootFields = [] - const nodeInterfacePossibleTypeNames = [] - for (const field of rootFields) { const fieldHasNonNullArgs = field.args.some( arg => arg.type.kind === `NON_NULL` @@ -104,15 +72,17 @@ const identifyAndStoreIngestableFieldsAndTypes = async () => { const nodeField = type?.fields?.find(nodeListFilter) - if (nodeField && nodeField.type.ofType.kind === `INTERFACE`) { + if (nodeField && findNamedType(nodeField.type).kind === `INTERFACE`) { const nodeListField = type.fields.find(nodeListFilter) if (nodeListField) { - nodeInterfaceTypes.push(nodeListField.type.ofType.name) + nodeInterfaceTypes.push(findNamedTypeName(nodeListField.type)) store.dispatch.remoteSchema.addFetchedType(nodeListField.type) - const nodeListFieldType = typeMap.get(nodeListField.type.ofType.name) + const nodeListFieldType = typeMap.get( + findNamedTypeName(nodeListField.type) + ) for (const innerField of nodeListFieldType.fields) { store.dispatch.remoteSchema.addFetchedType(innerField.type) @@ -124,11 +94,11 @@ const identifyAndStoreIngestableFieldsAndTypes = async () => { // In Gatsby nodeInterface means the node data is pulled from a different type. On the WP side we can also have nodes that are of an interface type, but we only pull them from a single root field // the problem is that if we don't mark them as a node list root field // we don't know to identify them later as being a node type that will have been fetched and we also wont try to fetch this type during node sourcing. - !pluginOptions?.type?.[nodeListField.type.ofType.name] + !pluginOptions?.type?.[findNamedTypeName(nodeListField.type)] ?.nodeInterface ) { const nodeInterfaceType = typeMap.get( - findTypeName(nodeListField.type) + findNamedTypeName(nodeListField.type) ) // we need to mark all the possible types as being fetched @@ -184,6 +154,44 @@ const identifyAndStoreIngestableFieldsAndTypes = async () => { nonNodeRootFields.push(field) } + const interfaces = introspectionData.__schema.types.filter( + type => type.kind === `INTERFACE` + ) + + for (const interfaceType of interfaces) { + if (typeIsExcluded({ pluginOptions, typeName: interfaceType.name })) { + continue + } + + if (!interfaceType.fields) { + continue + } + + const typesThatImplementInterface = + getTypesThatImplementInterfaceType(interfaceType) + + const shouldSkipInterfaceType = !transformFields({ + fields: interfaceType.fields, + parentType: interfaceType, + parentInterfacesImplementingTypes: typesThatImplementInterface, + peek: true, + }) + + if (shouldSkipInterfaceType && interfaceType.name !== `Node`) { + continue + } + + store.dispatch.remoteSchema.addFetchedType(interfaceType) + + if (interfaceType.fields) { + for (const interfaceField of interfaceType.fields) { + if (interfaceField.type) { + store.dispatch.remoteSchema.addFetchedType(interfaceField.type) + } + } + } + } + const nodeListFieldNames = nodeListRootFields.map(field => field.name) const nodeListTypeNames = [ @@ -192,7 +200,7 @@ const identifyAndStoreIngestableFieldsAndTypes = async () => { const connectionType = typeMap.get(field.type.name) const nodesField = connectionType.fields.find(nodeListFilter) - return nodesField.type.ofType.name + return findNamedType(nodesField.type).name }), ] diff --git a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/is-excluded.js b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/is-excluded.js index 42edad258f958..4837d6eb31916 100644 --- a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/is-excluded.js +++ b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/is-excluded.js @@ -1,6 +1,6 @@ import store from "~/store" import { - findTypeName, + findNamedTypeName, getTypeSettingsByType, } from "~/steps/create-schema-customization/helpers" @@ -22,7 +22,7 @@ const fieldIsExcludedOnParentType = ({ field, parentType }) => { const state = store.getState() const { typeMap } = state.remoteSchema - const fullType = typeMap.get(findTypeName(parentType)) + const fullType = typeMap.get(findNamedTypeName(parentType)) const parentTypeNodesField = fullType?.fields?.find( field => field.name === `nodes` diff --git a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/write-queries-to-disk.js b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/write-queries-to-disk.js index dec94c0fd21f2..2cf0c3aeee749 100644 --- a/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/write-queries-to-disk.js +++ b/packages/gatsby-source-wordpress/src/steps/ingest-remote-schema/write-queries-to-disk.js @@ -24,7 +24,15 @@ export const writeQueriesToDisk = async ({ reporter }, pluginOptions) => { const wordPressGraphQLDirectory = `${process.cwd()}/WordPress/GraphQL` // remove before writing in case there are old types - await fs.remove(wordPressGraphQLDirectory) + try { + fs.rmSync(wordPressGraphQLDirectory, { + recursive: true, + }) + } catch (e) { + if (!e.message.includes(`no such file or directory, stat`)) { + throw e + } + } for (const { nodeListQueries, diff --git a/packages/gatsby-source-wordpress/src/steps/source-nodes/fetch-nodes/fetch-nodes.js b/packages/gatsby-source-wordpress/src/steps/source-nodes/fetch-nodes/fetch-nodes.js index 5d0a79b01ec54..b2ae702860479 100644 --- a/packages/gatsby-source-wordpress/src/steps/source-nodes/fetch-nodes/fetch-nodes.js +++ b/packages/gatsby-source-wordpress/src/steps/source-nodes/fetch-nodes/fetch-nodes.js @@ -14,6 +14,7 @@ import { setHardCachedNodes, setPersistentCache, } from "~/utils/cache" +import { buildTypeName } from "../../create-schema-customization/helpers" /** * fetchWPGQLContentNodes @@ -85,7 +86,13 @@ export const getContentTypeQueryInfos = () => { return queryInfos } +let cachedGatsbyNodeTypeNames = null + export const getGatsbyNodeTypeNames = () => { + if (cachedGatsbyNodeTypeNames) { + return cachedGatsbyNodeTypeNames + } + const { typeMap } = store.getState().remoteSchema const queryableTypenames = getContentTypeQueryInfos().map( @@ -108,7 +115,21 @@ export const getGatsbyNodeTypeNames = () => { [] ) - return [...new Set([...queryableTypenames, ...implementingNodeTypes])] + const allTypeNames = [ + ...new Set([...queryableTypenames, ...implementingNodeTypes]), + ] + + const allBuiltTypeNames = allTypeNames.map(typename => + buildTypeName(typename) + ) + + const typeNameList = [...allTypeNames, ...allBuiltTypeNames] + + if (typeNameList.length) { + cachedGatsbyNodeTypeNames = typeNameList + } + + return typeNameList } /** diff --git a/packages/gatsby-source-wordpress/src/steps/source-nodes/helpers.js b/packages/gatsby-source-wordpress/src/steps/source-nodes/helpers.js index 9d6faad5d2870..ddc604474df0c 100644 --- a/packages/gatsby-source-wordpress/src/steps/source-nodes/helpers.js +++ b/packages/gatsby-source-wordpress/src/steps/source-nodes/helpers.js @@ -1,4 +1,5 @@ import store from "~/store" +import { findNamedTypeName } from "../create-schema-customization/helpers" export const getTypeInfoBySingleName = singleName => { const { typeMap } = store.getState().remoteSchema @@ -7,7 +8,7 @@ export const getTypeInfoBySingleName = singleName => { .get(`RootQuery`) .fields.find(field => field.name === singleName) - const typeName = rootField.type.name || rootField.type.ofType.name + const typeName = rootField.type.name || findNamedTypeName(rootField.type) const type = typeMap.get(typeName)