diff --git a/packages/gatsby-source-contentful/src/__fixtures__/editing-node-referencing-nodes-with-child-links.js b/packages/gatsby-source-contentful/src/__fixtures__/editing-node-referencing-nodes-with-child-links.js new file mode 100644 index 0000000000000..f23d2d18d9a54 --- /dev/null +++ b/packages/gatsby-source-contentful/src/__fixtures__/editing-node-referencing-nodes-with-child-links.js @@ -0,0 +1,339 @@ +exports.contentTypeItems = () => [ + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `8itggr1zebzx`, + }, + }, + id: `blogPost`, + type: `ContentType`, + createdAt: `2023-01-11T14:52:56.250Z`, + updatedAt: `2023-01-11T14:54:56.940Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 4, + }, + displayField: `title`, + name: `Blog Post`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: true, + disabled: false, + omitted: false, + }, + { + id: `slug`, + name: `Slug`, + type: `Symbol`, + localized: false, + required: true, + disabled: false, + omitted: false, + }, + { + id: `category`, + name: `Category`, + type: `Link`, + localized: false, + required: false, + disabled: false, + omitted: false, + linkType: `Entry`, + validations: [ + { + linkContentType: [`blogCategory`], + }, + ], + }, + ], + }, + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `8itggr1zebzx`, + }, + }, + id: `blogCategory`, + type: `ContentType`, + createdAt: `2023-01-11T14:54:22.680Z`, + updatedAt: `2023-01-11T14:54:22.680Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 1, + }, + displayField: `title`, + name: `Blog Category`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: true, + disabled: false, + omitted: false, + }, + { + id: `slug`, + name: `Slug`, + type: `Symbol`, + localized: false, + required: true, + disabled: false, + omitted: false, + }, + { + id: `body`, + name: `Body`, + type: `Text`, + localized: false, + required: true, + disabled: false, + omitted: false, + }, + ], + }, +] + +exports.initialSync = () => { + return { + currentSyncData: { + entries: [ + { + metadata: { + tags: [], + }, + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `8itggr1zebzx`, + }, + }, + id: `3jXBlUgXmubzPI3I6d9hLr`, + type: `Entry`, + createdAt: `2023-01-11T14:56:37.418Z`, + updatedAt: `2023-01-11T15:04:37.640Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 3, + contentType: { + sys: { + type: `Link`, + linkType: `ContentType`, + id: `blogCategory`, + }, + }, + }, + fields: { + title: { + "en-US": `CMS`, + }, + slug: { + "en-US": `cms`, + }, + body: { + "en-US": `cms`, + }, + }, + }, + { + metadata: { + tags: [], + }, + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `8itggr1zebzx`, + }, + }, + id: `3oTFYoNKoVZcp8svbn8P2z`, + type: `Entry`, + createdAt: `2023-01-11T14:56:42.655Z`, + updatedAt: `2023-01-11T14:56:42.655Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 1, + contentType: { + sys: { + type: `Link`, + linkType: `ContentType`, + id: `blogPost`, + }, + }, + }, + fields: { + title: { + "en-US": `Hello World`, + }, + slug: { + "en-US": `hello-world`, + }, + }, + }, + ], + assets: [], + deletedEntries: [], + deletedAssets: [], + nextSyncToken: `dDFSNcK6bMO7woHDuMK7A8O_KWQDPkhAwpF6w7ovw49fQjrDj2gKH0xvwofCkMKDJcKgBMKCYcK9wr3DoVozwqEUC8OwWlVJBBt-F8K0BMKTP8OAwr8Xw6bCkcO2w6MpwqBmVX7CmsOwM3DDvWZvw5Q`, + }, + tagItems: [], + defaultLocale: `en-US`, + locales: [ + { + code: `en-US`, + name: `English (United States)`, + default: true, + fallbackCode: null, + sys: { + id: `2jpGtQkqT01zpSIqC9UQOS`, + type: `Locale`, + version: 1, + }, + }, + ], + space: { + sys: { + type: `Space`, + id: `8itggr1zebzx`, + }, + name: `test`, + locales: [ + { + code: `en-US`, + default: true, + name: `English (United States)`, + fallbackCode: null, + }, + ], + }, + } +} + +exports.addALink = () => { + return { + currentSyncData: { + entries: [ + { + metadata: { + tags: [], + }, + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `8itggr1zebzx`, + }, + }, + id: `3oTFYoNKoVZcp8svbn8P2z`, + type: `Entry`, + createdAt: `2023-01-11T14:56:42.655Z`, + updatedAt: `2023-01-11T14:56:42.655Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 1, + contentType: { + sys: { + type: `Link`, + linkType: `ContentType`, + id: `blogPost`, + }, + }, + }, + fields: { + title: { + "en-US": `Hello World`, + }, + slug: { + "en-US": `hello-world`, + }, + category: { + "en-US": { + sys: { + type: `Link`, + linkType: `Entry`, + id: `3jXBlUgXmubzPI3I6d9hLr`, + }, + }, + }, + }, + }, + ], + assets: [], + deletedEntries: [], + deletedAssets: [], + nextSyncToken: `dDFSNcK6bMO7woHDuMK7A8O_KWQDPkhAwpF6w7ovw49fQjrDj2gKH0xvQMODwpLDkMK3Oj9Jw6jDkSoBMkc4woTCtMOFwoTDisKlT8O1w4AaKsOjasK1wrVSwrU3YsKVE8KPVMKyw4_CmVpwPsOew4IVwoA`, + }, + tagItems: [], + defaultLocale: `en-US`, + locales: [ + { + code: `en-US`, + name: `English (United States)`, + default: true, + fallbackCode: null, + sys: { + id: `2jpGtQkqT01zpSIqC9UQOS`, + type: `Locale`, + version: 1, + }, + }, + ], + space: { + sys: { + type: `Space`, + id: `8itggr1zebzx`, + }, + name: `test`, + locales: [ + { + code: `en-US`, + default: true, + name: `English (United States)`, + fallbackCode: null, + }, + ], + }, + } +} diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 3954599a0d238..b366f3902c5fb 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -16,6 +16,7 @@ import restrictedContentTypeFixture from "../__fixtures__/restricted-content-typ import unpublishedFieldDelivery from "../__fixtures__/unpublished-fields-delivery" import unpublishedFieldPreview from "../__fixtures__/unpublished-fields-preview" import preserveBackLinks from "../__fixtures__/preserve-back-links" +import editingNodeReferecingNodeWithChildLink from "../__fixtures__/editing-node-referencing-nodes-with-child-links" jest.mock(`../fetch`) jest.mock(`gatsby-core-utils`, () => { @@ -1422,4 +1423,68 @@ describe(`gatsby-node`, () => { ]) expect(blogCategoryNodes[0][`title`]).toEqual(`CMS edit #1`) }) + + it(`should not apply parent node links to child nodes`, async () => { + // @ts-ignore + fetchContentTypes.mockImplementation( + editingNodeReferecingNodeWithChildLink.contentTypeItems + ) + fetchContent + // @ts-ignore + .mockImplementationOnce( + editingNodeReferecingNodeWithChildLink.initialSync + ) + .mockImplementationOnce(editingNodeReferecingNodeWithChildLink.addALink) + + let blogPostNodes + let blogCategoryNodes + let blogCategoryChildNodes + await simulateGatsbyBuild() + + blogPostNodes = getNodes().filter( + node => node.internal.type === `ContentfulBlogPost` + ) + blogCategoryNodes = getNodes().filter( + node => node.internal.type === `ContentfulBlogCategory` + ) + blogCategoryChildNodes = blogCategoryNodes.flatMap(node => + node.children.map(childId => getNode(childId)) + ) + + expect(blogPostNodes.length).toEqual(1) + expect(blogCategoryNodes.length).toEqual(1) + expect(blogCategoryChildNodes.length).toEqual(1) + // no backref yet + expect(blogCategoryNodes[0][`blog post___NODE`]).toBeUndefined() + expect(blogCategoryNodes[0][`title`]).toEqual(`CMS`) + + // `body` field on child node is concrete value and not a link + expect(blogCategoryChildNodes[0][`body`]).toEqual(`cms`) + expect(blogCategoryChildNodes[0][`body___NODE`]).toBeUndefined() + + await simulateGatsbyBuild() + + blogPostNodes = getNodes().filter( + node => node.internal.type === `ContentfulBlogPost` + ) + blogCategoryNodes = getNodes().filter( + node => node.internal.type === `ContentfulBlogCategory` + ) + blogCategoryChildNodes = blogCategoryNodes.flatMap(node => + node.children.map(childId => getNode(childId)) + ) + + expect(blogPostNodes.length).toEqual(1) + expect(blogCategoryNodes.length).toEqual(1) + expect(blogCategoryChildNodes.length).toEqual(1) + // backref was added when entries were linked + expect(blogCategoryNodes[0][`blog post___NODE`]).toEqual([ + blogPostNodes[0].id, + ]) + expect(blogCategoryNodes[0][`title`]).toEqual(`CMS`) + + // `body` field on child node is concrete value and not a link + expect(blogCategoryChildNodes[0][`body`]).toEqual(`cms`) + expect(blogCategoryChildNodes[0][`body___NODE`]).toBeUndefined() + }) }) diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index d10b150542550..baea1ca1aa215 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -463,13 +463,13 @@ export async function sourceNodes( // memory cached nodes are mutated during back reference checks // so we need to carry over the changes to the updated node - if (node.__memcache) { - for (const key of Object.keys(node)) { + if (nodeToUpdateOriginal.__memcache) { + for (const key of Object.keys(nodeToUpdateOriginal)) { if (!key.endsWith(`___NODE`)) { continue } - newNode[key] = node[key] + newNode[key] = nodeToUpdateOriginal[key] } }