diff --git a/e2e-tests/contentful/src/components/references/text.js b/e2e-tests/contentful/src/components/references/text.js index 8bcf361eb99c8..a8647ece05b1d 100644 --- a/e2e-tests/contentful/src/components/references/text.js +++ b/e2e-tests/contentful/src/components/references/text.js @@ -1,5 +1,5 @@ import React from "react" export const ContentfulText = ({ short, longPlain }) => ( -

[ContentfulText] {short || longPlain?.longPlain}

+

[ContentfulText] {short || longPlain?.raw}

) diff --git a/e2e-tests/contentful/src/pages/boolean.js b/e2e-tests/contentful/src/pages/boolean.js index 410065f7074bd..d4bd20c11b096 100644 --- a/e2e-tests/contentful/src/pages/boolean.js +++ b/e2e-tests/contentful/src/pages/boolean.js @@ -50,8 +50,11 @@ export default BooleanPage export const pageQuery = graphql` query BooleanQuery { default: allContentfulBoolean( - sort: { fields: contentful_id } - filter: { node_locale: { eq: "en-US" }, booleanLocalized: { eq: null } } + sort: { fields: sys___id } + filter: { + sys: { locale: { eq: "en-US" } } + booleanLocalized: { eq: null } + } ) { nodes { title @@ -59,8 +62,11 @@ export const pageQuery = graphql` } } english: allContentfulBoolean( - sort: { fields: contentful_id } - filter: { node_locale: { eq: "en-US" }, booleanLocalized: { ne: null } } + sort: { fields: sys___id } + filter: { + sys: { locale: { eq: "en-US" } } + booleanLocalized: { ne: null } + } ) { nodes { title @@ -68,8 +74,11 @@ export const pageQuery = graphql` } } german: allContentfulBoolean( - sort: { fields: contentful_id } - filter: { node_locale: { eq: "de-DE" }, booleanLocalized: { ne: null } } + sort: { fields: sys___id } + filter: { + sys: { locale: { eq: "de-DE" } } + booleanLocalized: { ne: null } + } ) { nodes { title diff --git a/e2e-tests/contentful/src/pages/content-reference.js b/e2e-tests/contentful/src/pages/content-reference.js index 9dfb892765136..cc33294438c0d 100644 --- a/e2e-tests/contentful/src/pages/content-reference.js +++ b/e2e-tests/contentful/src/pages/content-reference.js @@ -24,7 +24,7 @@ const ContentReferencePage = ({ data }) => { return (

Default

- {defaultEntries.map(({ contentful_id, title, one, many }) => { + {defaultEntries.map(({ sys: { id }, title, one, many }) => { const slug = slugify(title, { strict: true, lower: true }) let content = null @@ -37,7 +37,7 @@ const ContentReferencePage = ({ data }) => { } return ( -
+

{title}

{content}
@@ -45,7 +45,7 @@ const ContentReferencePage = ({ data }) => { })}

English Locale

{englishEntries.map( - ({ contentful_id, title, oneLocalized, manyLocalized }) => { + ({ sys: { id }, title, oneLocalized, manyLocalized }) => { const slug = slugify(title, { strict: true, lower: true }) let content = null @@ -58,7 +58,7 @@ const ContentReferencePage = ({ data }) => { } return ( -
+

{title}

{content}
@@ -67,7 +67,7 @@ const ContentReferencePage = ({ data }) => { )}

German Locale

{germanEntries.map( - ({ contentful_id, title, oneLocalized, manyLocalized }) => { + ({ sys: { id }, title, oneLocalized, manyLocalized }) => { const slug = slugify(title, { strict: true, lower: true }) let content = null @@ -80,7 +80,7 @@ const ContentReferencePage = ({ data }) => { } return ( -
+

{title}

{content}
@@ -97,18 +97,29 @@ export const pageQuery = graphql` query ContentReferenceQuery { default: allContentfulContentReference( sort: { fields: title } - filter: { node_locale: { eq: "en-US" }, title: { glob: "!*Localized*" } } + filter: { + sys: { locale: { eq: "en-US" } } + title: { glob: "!*Localized*" } + } ) { nodes { title - contentful_id + sys { + id + } one { __typename - contentful_id + sys { + id + } ... on ContentfulText { title short } + ... on ContentfulNumber { + title + integer + } ... on ContentfulContentReference { title one { @@ -116,6 +127,10 @@ export const pageQuery = graphql` title short } + ... on ContentfulNumber { + title + integer + } ... on ContentfulContentReference { title } @@ -137,7 +152,9 @@ export const pageQuery = graphql` } many { __typename - contentful_id + sys { + id + } ... on ContentfulText { title short @@ -153,6 +170,10 @@ export const pageQuery = graphql` title short } + ... on ContentfulNumber { + title + integer + } ... on ContentfulContentReference { title } @@ -176,16 +197,23 @@ export const pageQuery = graphql` } english: allContentfulContentReference( sort: { fields: title } - filter: { node_locale: { eq: "en-US" }, title: { glob: "*Localized*" } } + filter: { + sys: { locale: { eq: "en-US" } } + title: { glob: "*Localized*" } + } ) { nodes { title - contentful_id + sys { + id + } oneLocalized { __typename - title - decimal - integer + ... on ContentfulNumber { + title + decimal + integer + } } manyLocalized { __typename @@ -198,7 +226,7 @@ export const pageQuery = graphql` title short longPlain { - longPlain + raw } } } @@ -206,16 +234,23 @@ export const pageQuery = graphql` } german: allContentfulContentReference( sort: { fields: title } - filter: { node_locale: { eq: "de-DE" }, title: { glob: "*Localized*" } } + filter: { + sys: { locale: { eq: "de-DE" } } + title: { glob: "*Localized*" } + } ) { nodes { title - contentful_id + sys { + id + } oneLocalized { __typename - title - decimal - integer + ... on ContentfulNumber { + title + decimal + integer + } } manyLocalized { __typename @@ -228,7 +263,7 @@ export const pageQuery = graphql` title short longPlain { - longPlain + raw } } } diff --git a/e2e-tests/contentful/src/pages/date.js b/e2e-tests/contentful/src/pages/date.js index bb3a0ff554a38..ef8cb42c32b86 100644 --- a/e2e-tests/contentful/src/pages/date.js +++ b/e2e-tests/contentful/src/pages/date.js @@ -32,34 +32,32 @@ export default DatePage export const pageQuery = graphql` query DateQuery { - dateTime: contentfulDate(contentful_id: { eq: "38akBjGb3T1t4AjB87wQjo" }) { + dateTime: contentfulDate(sys: { id: { eq: "38akBjGb3T1t4AjB87wQjo" } }) { title date: dateTime formatted: dateTime(formatString: "D.M.YYYY - hh:mm") } dateTimeTimezone: contentfulDate( - contentful_id: { eq: "6dZ8pK4tFWZDZPHgSC0tNS" } + sys: { id: { eq: "6dZ8pK4tFWZDZPHgSC0tNS" } } ) { title date: dateTimeTimezone formatted: dateTimeTimezone(formatString: "D.M.YYYY - hh:mm (z)") } - date: contentfulDate(contentful_id: { eq: "5FuULz0jl0rKoKUKp2rshf" }) { + date: contentfulDate(sys: { id: { eq: "5FuULz0jl0rKoKUKp2rshf" } }) { title date formatted: date(formatString: "D.M.YYYY") } dateEnglish: contentfulDate( - contentful_id: { eq: "1ERWZvDiYELryAZEP1dmKG" } - node_locale: { eq: "en-US" } + sys: { id: { eq: "1ERWZvDiYELryAZEP1dmKG" }, locale: { eq: "en-US" } } ) { title date: dateLocalized formatted: dateLocalized(formatString: "D.M.YYYY - HH:mm:ss") } dateGerman: contentfulDate( - contentful_id: { eq: "1ERWZvDiYELryAZEP1dmKG" } - node_locale: { eq: "de-DE" } + sys: { id: { eq: "1ERWZvDiYELryAZEP1dmKG" }, locale: { eq: "de-DE" } } ) { title date: dateLocalized diff --git a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js index 98d3ea31eb993..e5ef0b60f9e41 100644 --- a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js +++ b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js @@ -215,16 +215,18 @@ export const pageQuery = graphql` query GatsbyPluginImageQuery { default: allContentfulAsset( filter: { - contentful_id: { - in: [ - "3ljGfnpegOnBTFGhV07iC1" - "3BSI9CgDdAn1JchXmY5IJi" - "65syuRuRVeKi03HvRsOkkb" - ] + sys: { + id: { + in: [ + "3ljGfnpegOnBTFGhV07iC1" + "3BSI9CgDdAn1JchXmY5IJi" + "65syuRuRVeKi03HvRsOkkb" + ] + } + locale: { eq: "en-US" } } - node_locale: { eq: "en-US" } } - sort: { fields: contentful_id } + sort: { fields: sys___id } ) { nodes { title @@ -259,10 +261,9 @@ export const pageQuery = graphql` } english: allContentfulAsset( filter: { - contentful_id: { in: ["4FwygYxkL3rAteERtoxxNC"] } - node_locale: { eq: "en-US" } + sys: { id: { in: ["4FwygYxkL3rAteERtoxxNC"] }, locale: { eq: "en-US" } } } - sort: { fields: contentful_id } + sort: { fields: sys___id } ) { nodes { title @@ -276,10 +277,9 @@ export const pageQuery = graphql` } german: allContentfulAsset( filter: { - contentful_id: { in: ["4FwygYxkL3rAteERtoxxNC"] } - node_locale: { eq: "de-DE" } + sys: { id: { in: ["4FwygYxkL3rAteERtoxxNC"] }, locale: { eq: "de-DE" } } } - sort: { fields: contentful_id } + sort: { fields: sys___id } ) { nodes { title diff --git a/e2e-tests/contentful/src/pages/json.js b/e2e-tests/contentful/src/pages/json.js index 45172e184fb0d..bce1cb1edd3a1 100644 --- a/e2e-tests/contentful/src/pages/json.js +++ b/e2e-tests/contentful/src/pages/json.js @@ -31,7 +31,7 @@ const JSONPage = ({ data }) => {

Name: {actor.name}

Photo: {actor.photo}

Birthdate: {actor.Birthdate}

-

Born at: {actor.Born_At}

+

Born at: {actor["Born At"]}

Weight: {actor.weight}

Age: {actor.age}

Wife: {actor.wife}

@@ -61,33 +61,23 @@ export default JSONPage export const pageQuery = graphql` query JSONQuery { - simple: contentfulJson(contentful_id: { eq: "2r6tNjP8brkyy5yLR39hhh" }) { + simple: contentfulJson(sys: { id: { eq: "2r6tNjP8brkyy5yLR39hhh" } }) { json } - complex: contentfulJson(contentful_id: { eq: "2y71nV0cpW9vzTmJybq571" }) { + complex: contentfulJson(sys: { id: { eq: "2y71nV0cpW9vzTmJybq571" } }) { json } english: contentfulJson( - node_locale: { eq: "en-US" } - jsonLocalized: { id: { ne: null } } + sys: { id: { eq: "7DvTBEPg5P6TRC7dI9zXuO" }, locale: { eq: "en-US" } } ) { title - jsonLocalized { - age - city - name - } + jsonLocalized } german: contentfulJson( - node_locale: { eq: "de-DE" } - jsonLocalized: { id: { ne: null } } + sys: { id: { eq: "7DvTBEPg5P6TRC7dI9zXuO" }, locale: { eq: "de-DE" } } ) { title - jsonLocalized { - age - city - name - } + jsonLocalized } } ` diff --git a/e2e-tests/contentful/src/pages/location.js b/e2e-tests/contentful/src/pages/location.js index 813f6cf9ed7dd..f9757a987d661 100644 --- a/e2e-tests/contentful/src/pages/location.js +++ b/e2e-tests/contentful/src/pages/location.js @@ -57,8 +57,11 @@ export default LocationPage export const pageQuery = graphql` query LocationQuery { default: allContentfulLocation( - sort: { fields: contentful_id } - filter: { title: { glob: "!*Localized*" }, node_locale: { eq: "en-US" } } + sort: { fields: sys___id } + filter: { + title: { glob: "!*Localized*" } + sys: { locale: { eq: "en-US" } } + } ) { nodes { title @@ -69,8 +72,11 @@ export const pageQuery = graphql` } } english: allContentfulLocation( - sort: { fields: contentful_id } - filter: { title: { glob: "*Localized*" }, node_locale: { eq: "en-US" } } + sort: { fields: sys___id } + filter: { + title: { glob: "*Localized*" } + sys: { locale: { eq: "en-US" } } + } ) { nodes { title @@ -81,8 +87,11 @@ export const pageQuery = graphql` } } german: allContentfulLocation( - sort: { fields: contentful_id } - filter: { title: { glob: "*Localized*" }, node_locale: { eq: "de-DE" } } + sort: { fields: sys___id } + filter: { + title: { glob: "*Localized*" } + sys: { locale: { eq: "de-DE" } } + } ) { nodes { title diff --git a/e2e-tests/contentful/src/pages/media-reference.js b/e2e-tests/contentful/src/pages/media-reference.js index f6bf077d006e1..9361b6b641bc0 100644 --- a/e2e-tests/contentful/src/pages/media-reference.js +++ b/e2e-tests/contentful/src/pages/media-reference.js @@ -10,7 +10,7 @@ const MediaReferencePage = ({ data }) => { const germanEntries = data.german.nodes return ( - {defaultEntries.map(({ contentful_id, title, one, many }) => { + {defaultEntries.map(({ sys: { id }, title, one, many }) => { const slug = slugify(title, { strict: true, lower: true }) let content = null @@ -27,7 +27,7 @@ const MediaReferencePage = ({ data }) => { } return ( -
+

{title}

{content}
@@ -35,7 +35,7 @@ const MediaReferencePage = ({ data }) => { })}

English Locale

{englishEntries.map( - ({ contentful_id, title, one, oneLocalized, many, manyLocalized }) => { + ({ sys: { id }, title, one, oneLocalized, many, manyLocalized }) => { const slug = slugify(title, { strict: true, lower: true }) let content = null @@ -76,7 +76,7 @@ const MediaReferencePage = ({ data }) => { } return ( -
+

{title}

{content}
@@ -86,7 +86,7 @@ const MediaReferencePage = ({ data }) => {

German Locale

{germanEntries.map( - ({ contentful_id, title, one, oneLocalized, many, manyLocalized }) => { + ({ sys: { id }, title, one, oneLocalized, many, manyLocalized }) => { const slug = slugify(title, { strict: true, lower: true }) let content = null @@ -127,7 +127,7 @@ const MediaReferencePage = ({ data }) => { } return ( -
+

{title}

{content}
@@ -144,11 +144,16 @@ export const pageQuery = graphql` query MediaReferenceQuery { default: allContentfulMediaReference( sort: { fields: title } - filter: { title: { glob: "!*Localized*" }, node_locale: { eq: "en-US" } } + filter: { + title: { glob: "!*Localized*" } + sys: { locale: { eq: "en-US" } } + } ) { nodes { title - contentful_id + sys { + id + } one { file { url @@ -163,11 +168,16 @@ export const pageQuery = graphql` } english: allContentfulMediaReference( sort: { fields: title } - filter: { title: { glob: "*Localized*" }, node_locale: { eq: "en-US" } } + filter: { + title: { glob: "*Localized*" } + sys: { locale: { eq: "en-US" } } + } ) { nodes { title - contentful_id + sys { + id + } one { file { url @@ -192,11 +202,16 @@ export const pageQuery = graphql` } german: allContentfulMediaReference( sort: { fields: title } - filter: { title: { glob: "*Localized*" }, node_locale: { eq: "de-DE" } } + filter: { + title: { glob: "*Localized*" } + sys: { locale: { eq: "de-DE" } } + } ) { nodes { title - contentful_id + sys { + id + } one { file { url diff --git a/e2e-tests/contentful/src/pages/number.js b/e2e-tests/contentful/src/pages/number.js index 5eff2ed704bba..946e9b71d3be1 100644 --- a/e2e-tests/contentful/src/pages/number.js +++ b/e2e-tests/contentful/src/pages/number.js @@ -54,8 +54,11 @@ export default NumberPage export const pageQuery = graphql` query NumberQuery { default: allContentfulNumber( - sort: { fields: contentful_id } - filter: { title: { glob: "!*Localized*" }, node_locale: { eq: "en-US" } } + sort: { fields: sys___id } + filter: { + title: { glob: "!*Localized*" } + sys: { locale: { eq: "en-US" } } + } ) { nodes { title @@ -64,8 +67,11 @@ export const pageQuery = graphql` } } english: allContentfulNumber( - sort: { fields: contentful_id } - filter: { title: { glob: "*Localized*" }, node_locale: { eq: "en-US" } } + sort: { fields: sys___id } + filter: { + title: { glob: "*Localized*" } + sys: { locale: { eq: "en-US" } } + } ) { nodes { title @@ -74,8 +80,11 @@ export const pageQuery = graphql` } } german: allContentfulNumber( - sort: { fields: contentful_id } - filter: { title: { glob: "*Localized*" }, node_locale: { eq: "de-DE" } } + sort: { fields: sys___id } + filter: { + title: { glob: "*Localized*" } + sys: { locale: { eq: "de-DE" } } + } ) { nodes { title diff --git a/e2e-tests/contentful/src/pages/rich-text.js b/e2e-tests/contentful/src/pages/rich-text.js index d9d5b34d0586a..0cd2a3eca6127 100644 --- a/e2e-tests/contentful/src/pages/rich-text.js +++ b/e2e-tests/contentful/src/pages/rich-text.js @@ -118,7 +118,7 @@ export const pageQuery = graphql` sort: { fields: title } filter: { title: { glob: "!*Localized*|*Validated*" } - node_locale: { eq: "en-US" } + sys: { locale: { eq: "en-US" } } } ) { nodes { @@ -128,28 +128,30 @@ export const pageQuery = graphql` raw references { __typename + sys { + id + } ... on ContentfulAsset { contentful_id gatsbyImageData(width: 200) } ... on ContentfulText { - contentful_id title short } ... on ContentfulLocation { - contentful_id location { lat lon } } ... on ContentfulContentReference { - contentful_id title one { __typename - contentful_id + sys { + id + } ... on ContentfulText { title short @@ -170,7 +172,9 @@ export const pageQuery = graphql` } many { __typename - contentful_id + sys { + id + } ... on ContentfulText { title short @@ -200,7 +204,10 @@ export const pageQuery = graphql` } english: allContentfulRichText( sort: { fields: title } - filter: { title: { glob: "*Localized*" }, node_locale: { eq: "en-US" } } + filter: { + title: { glob: "*Localized*" } + sys: { locale: { eq: "en-US" } } + } ) { nodes { id @@ -212,7 +219,10 @@ export const pageQuery = graphql` } german: allContentfulRichText( sort: { fields: title } - filter: { title: { glob: "*Localized*" }, node_locale: { eq: "de-DE" } } + filter: { + title: { glob: "*Localized*" } + sys: { locale: { eq: "de-DE" } } + } ) { nodes { id diff --git a/e2e-tests/contentful/src/pages/text.js b/e2e-tests/contentful/src/pages/text.js index 360a154201c5b..923c86e743da5 100644 --- a/e2e-tests/contentful/src/pages/text.js +++ b/e2e-tests/contentful/src/pages/text.js @@ -57,7 +57,7 @@ const TextPage = ({ data }) => {

Long (Plain):

-

{longEnglish.longLocalized.longLocalized}

+

{longEnglish.longLocalized.raw}

German Locale

@@ -67,7 +67,7 @@ const TextPage = ({ data }) => {

Long (Plain):

-

{longGerman.longLocalized.longLocalized}

+

{longGerman.longLocalized.raw}

) @@ -78,28 +78,24 @@ export default TextPage export const pageQuery = graphql` query TextQuery { short: contentfulText( - node_locale: { eq: "en-US" } - contentful_id: { eq: "5ZtcN1o7KpN7J7xgiTyaXo" } + sys: { id: { eq: "5ZtcN1o7KpN7J7xgiTyaXo" }, locale: { eq: "en-US" } } ) { short } shortList: contentfulText( - node_locale: { eq: "en-US" } - contentful_id: { eq: "7b5U927WTFcQXO2Gewwa2k" } + sys: { id: { eq: "7b5U927WTFcQXO2Gewwa2k" }, locale: { eq: "en-US" } } ) { shortList } longPlain: contentfulText( - node_locale: { eq: "en-US" } - contentful_id: { eq: "6ru8cSC9hZi3Ekvtw7P77S" } + sys: { id: { eq: "6ru8cSC9hZi3Ekvtw7P77S" }, locale: { eq: "en-US" } } ) { longPlain { raw } } longMarkdownSimple: contentfulText( - node_locale: { eq: "en-US" } - contentful_id: { eq: "NyPJw0mcSuCwY2gV0zYny" } + sys: { id: { eq: "NyPJw0mcSuCwY2gV0zYny" }, locale: { eq: "en-US" } } ) { longMarkdown { childMarkdownRemark { @@ -108,8 +104,7 @@ export const pageQuery = graphql` } } longMarkdownComplex: contentfulText( - node_locale: { eq: "en-US" } - contentful_id: { eq: "3pwKS9UWsYmOguo4UdE1EB" } + sys: { id: { eq: "3pwKS9UWsYmOguo4UdE1EB" }, locale: { eq: "en-US" } } ) { longMarkdown { childMarkdownRemark { @@ -118,31 +113,27 @@ export const pageQuery = graphql` } } shortEnglish: contentfulText( - node_locale: { eq: "en-US" } - contentful_id: { eq: "2sQRyOLUexvWZj9nkzS3nN" } + sys: { id: { eq: "2sQRyOLUexvWZj9nkzS3nN" }, locale: { eq: "en-US" } } ) { shortLocalized } shortGerman: contentfulText( - node_locale: { eq: "de-DE" } - contentful_id: { eq: "2sQRyOLUexvWZj9nkzS3nN" } + sys: { id: { eq: "2sQRyOLUexvWZj9nkzS3nN" }, locale: { eq: "de-DE" } } ) { shortLocalized } longEnglish: contentfulText( - node_locale: { eq: "en-US" } - contentful_id: { eq: "5csovkwdDBqTKwSblAOHvd" } + sys: { id: { eq: "5csovkwdDBqTKwSblAOHvd" }, locale: { eq: "en-US" } } ) { longLocalized { - longLocalized + raw } } longGerman: contentfulText( - node_locale: { eq: "de-DE" } - contentful_id: { eq: "5csovkwdDBqTKwSblAOHvd" } + sys: { id: { eq: "5csovkwdDBqTKwSblAOHvd" }, locale: { eq: "de-DE" } } ) { longLocalized { - longLocalized + raw } } } diff --git a/packages/gatsby-source-contentful/package.json b/packages/gatsby-source-contentful/package.json index 1f269caddfd44..7ad571b87a54d 100644 --- a/packages/gatsby-source-contentful/package.json +++ b/packages/gatsby-source-contentful/package.json @@ -16,6 +16,7 @@ "chalk": "^4.1.2", "common-tags": "^1.8.2", "contentful": "^8.5.8", + "contentful-resolve-response": "^1.3.0", "fs-extra": "^10.1.0", "gatsby-core-utils": "^3.15.0-next.1", "gatsby-plugin-utils": "^3.9.0-next.2", diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/gatsby-node.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/gatsby-node.js.snap index 4961649230900..4e62cb24f807d 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/gatsby-node.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/gatsby-node.js.snap @@ -8,10 +8,402 @@ Array [ ] `; -exports[`gatsby-node stores rich text as raw with references attached 2`] = ` -Array [ - "ahntqop9oi7x___7oHxo6bs0us9wIkq27qdyK___Entry___nl", - "ahntqop9oi7x___6KpLS2NZyB3KAvDzWf4Ukh___Entry___nl", - "ahntqop9oi7x___4ZQrqcrTunWiuNaavhGYNT___Asset___nl", -] +exports[`gatsby-node stores rich text as JSON 2`] = ` +Object { + "content": Array [ + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "This is the homepage", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Heading 1", + }, + ], + "data": Object {}, + "nodeType": "heading-1", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Heading 2", + }, + ], + "data": Object {}, + "nodeType": "heading-2", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Heading 3", + }, + ], + "data": Object {}, + "nodeType": "heading-3", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Heading 4", + }, + ], + "data": Object {}, + "nodeType": "heading-4", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Heading 5", + }, + ], + "data": Object {}, + "nodeType": "heading-5", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Heading 6", + }, + ], + "data": Object {}, + "nodeType": "heading-6", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "This is ", + }, + Object { + "data": Object {}, + "marks": Array [ + Object { + "type": "bold", + }, + ], + "nodeType": "text", + "value": "bold ", + }, + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "and ", + }, + Object { + "data": Object {}, + "marks": Array [ + Object { + "type": "italic", + }, + ], + "nodeType": "text", + "value": "italic", + }, + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": " and ", + }, + Object { + "data": Object {}, + "marks": Array [ + Object { + "type": "bold", + }, + Object { + "type": "italic", + }, + ], + "nodeType": "text", + "value": "both", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + Object { + "content": Array [ + Object { + "content": Array [ + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Very", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + ], + "data": Object {}, + "nodeType": "list-item", + }, + Object { + "content": Array [ + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "useful", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + ], + "data": Object {}, + "nodeType": "list-item", + }, + Object { + "content": Array [ + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "list", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + ], + "data": Object {}, + "nodeType": "list-item", + }, + ], + "data": Object {}, + "nodeType": "unordered-list", + }, + Object { + "content": Array [ + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "This is a quote", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + ], + "data": Object {}, + "nodeType": "blockquote", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Reference tests:", + }, + ], + "data": Object {}, + "nodeType": "heading-2", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Inline Link: ", + }, + Object { + "content": Array [], + "data": Object { + "target": Object { + "sys": Object { + "id": "7oHxo6bs0us9wIkq27qdyK", + "linkType": "Entry", + "type": "Link", + }, + }, + }, + "nodeType": "embedded-entry-inline", + }, + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Link in list:", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + Object { + "content": Array [ + Object { + "content": Array [ + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "", + }, + Object { + "content": Array [], + "data": Object { + "target": Object { + "sys": Object { + "id": "6KpLS2NZyB3KAvDzWf4Ukh", + "linkType": "Entry", + "type": "Link", + }, + }, + }, + "nodeType": "embedded-entry-inline", + }, + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + ], + "data": Object {}, + "nodeType": "list-item", + }, + ], + "data": Object {}, + "nodeType": "ordered-list", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Embedded Entity:", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + Object { + "content": Array [], + "data": Object { + "target": Object { + "sys": Object { + "id": "7oHxo6bs0us9wIkq27qdyK", + "linkType": "Entry", + "type": "Link", + }, + }, + }, + "nodeType": "embedded-entry-block", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "Embedded Asset:", + }, + ], + "data": Object {}, + "nodeType": "heading-2", + }, + Object { + "content": Array [], + "data": Object { + "target": Object { + "sys": Object { + "id": "4ZQrqcrTunWiuNaavhGYNT", + "linkType": "Asset", + "type": "Link", + }, + }, + }, + "nodeType": "embedded-asset-block", + }, + Object { + "content": Array [ + Object { + "data": Object {}, + "marks": Array [], + "nodeType": "text", + "value": "", + }, + ], + "data": Object {}, + "nodeType": "paragraph", + }, + ], + "data": Object {}, + "nodeType": "document", +} `; diff --git a/packages/gatsby-source-contentful/src/__tests__/download-contentful-assets.js b/packages/gatsby-source-contentful/src/__tests__/download-contentful-assets.js index 72484e5b5a344..f3f6c21fdf6ee 100644 --- a/packages/gatsby-source-contentful/src/__tests__/download-contentful-assets.js +++ b/packages/gatsby-source-contentful/src/__tests__/download-contentful-assets.js @@ -24,24 +24,32 @@ const reporter = { }), } +const mockedContentfulEntity = { + sys: { id: `mocked` }, +} + const fixtures = [ { - sys: { - id: `idJjXOxmNga8CSnQGEwTw`, - type: `Asset`, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), + id: `aa1beda4-b14a-50f5-89a8-222992a46a41`, + internal: { + owner: `gatsby-source-contentful`, + type: `ContentfulAsset`, }, fields: { + title: { "en-US": `TundraUS`, fr: `TundraFR` }, file: { - "en-US": { - url: `//images.ctfassets.net/testing/us-image.jpeg`, - }, + "en-US": { url: `//images.ctfassets.net/testing/us-image.jpeg` }, + fr: { url: `//images.ctfassets.net/testing/fr-image.jpg` }, }, }, - title: { - "en-US": `TundraUS`, - fr: `TundraFR`, + sys: { + id: `idJjXOxmNga8CSnQGEwTw`, + type: `Asset`, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + space: mockedContentfulEntity, + environment: mockedContentfulEntity, + revision: 123, }, }, ] @@ -52,11 +60,7 @@ describe(`downloadContentfulAssets`, () => { const createNodeId = jest.fn(id => id) const defaultLocale = `en-US` const locales = [{ code: `en-US` }, { code: `fr`, fallbackCode: `en-US` }] - const space = { - sys: { - id: `1234`, - }, - } + const space = mockedContentfulEntity const cache = { get: jest.fn(() => Promise.resolve(null)), @@ -90,10 +94,10 @@ describe(`downloadContentfulAssets`, () => { assetNodes.forEach(n => { expect(cache.get).toHaveBeenCalledWith( - `contentful-asset-${n.contentful_id}-${n.node_locale}` + `contentful-asset-${n.sys.id}-${n.sys.locale}` ) expect(cache.set).toHaveBeenCalledWith( - `contentful-asset-${n.contentful_id}-${n.node_locale}`, + `contentful-asset-${n.sys.id}-${n.sys.locale}`, expect.anything() ) }) diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 7505f1eb0dbc7..b23a4052c2767 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -160,6 +160,7 @@ describe(`gatsby-node`, () => { getCache, reporter, parentSpan, + schema, }, pluginOptions ) @@ -1000,7 +1001,7 @@ describe(`gatsby-node`, () => { `) }) - it(`stores rich text as raw with references attached`, async () => { + it(`stores rich text as JSON`, async () => { // @ts-ignore fetchContent.mockImplementationOnce(richTextFixture.initialSync) // @ts-ignore @@ -1012,14 +1013,11 @@ describe(`gatsby-node`, () => { const initNodes = getNodes() const homeNodes = initNodes.filter( - ({ contentful_id: id }) => id === `6KpLS2NZyB3KAvDzWf4Ukh` + ({ sys: { id } }) => id === `6KpLS2NZyB3KAvDzWf4Ukh` ) expect(homeNodes).toHaveLength(2) homeNodes.forEach(homeNode => { - expect(homeNode.content.references___NODE).toStrictEqual([ - ...new Set(homeNode.content.references___NODE), - ]) - expect(homeNode.content.references___NODE).toMatchSnapshot() + expect(homeNode.content).toMatchSnapshot() }) }) diff --git a/packages/gatsby-source-contentful/src/__tests__/normalize.js b/packages/gatsby-source-contentful/src/__tests__/normalize.js index 0f6ca5884f8ae..58318589a3902 100644 --- a/packages/gatsby-source-contentful/src/__tests__/normalize.js +++ b/packages/gatsby-source-contentful/src/__tests__/normalize.js @@ -1,11 +1,11 @@ // @ts-check import { buildEntryList, - buildResolvableSet, + buildFallbackChain, buildForeignReferenceMap, - createNodesForContentType, + buildResolvableSet, createAssetNodes, - buildFallbackChain, + createNodesForContentType, getLocalizedField, makeId, } from "../normalize" @@ -19,19 +19,7 @@ const { space, } = require(`./data.json`) -const conflictFieldPrefix = `contentful_test` -// restrictedNodeFields from here https://www.gatsbyjs.com/docs/node-interface/ -const restrictedNodeFields = [ - `id`, - `children`, - `contentful_id`, - `parent`, - `fields`, - `internal`, -] - const pluginConfig = createPluginConfig({}) - const unstable_createNodeManifest = jest.fn() // Counts the created nodes per node type @@ -200,8 +188,6 @@ describe(`Process contentful data (by name)`, () => { contentTypeItems.forEach((contentTypeItem, i) => { createNodesForContentType({ contentTypeItem, - restrictedNodeFields, - conflictFieldPrefix, entries: entryList[i], createNode, createNodeId, @@ -305,7 +291,7 @@ describe(`Process existing mutated nodes in warm build`, () => { return { id, internal: { - contentDigest: entryList[0][0].sys.updatedAt + `changed`, + contentDigest: entryList[0][0].sys.publishedAt + `changed`, }, } } @@ -315,8 +301,6 @@ describe(`Process existing mutated nodes in warm build`, () => { contentTypeItems.forEach((contentTypeItem, i) => { createNodesForContentType({ contentTypeItem, - restrictedNodeFields, - conflictFieldPrefix, entries: entryList[i], createNode, createNodeId, @@ -419,8 +403,6 @@ describe(`Process contentful data (by id)`, () => { contentTypeItems.forEach((contentTypeItem, i) => { createNodesForContentType({ contentTypeItem, - restrictedNodeFields, - conflictFieldPrefix, entries: entryList[i], createNode, createNodeId, diff --git a/packages/gatsby-source-contentful/src/__tests__/rich-text.js b/packages/gatsby-source-contentful/src/__tests__/rich-text.js index 46ad833a3bd55..54207938a4543 100644 --- a/packages/gatsby-source-contentful/src/__tests__/rich-text.js +++ b/packages/gatsby-source-contentful/src/__tests__/rich-text.js @@ -10,7 +10,7 @@ import { BLOCKS, INLINES } from "@contentful/rich-text-types" import { initialSync } from "../__fixtures__/rich-text-data" import { cloneDeep } from "lodash" -const raw = JSON.stringify({ +const raw = { nodeType: `document`, data: {}, content: [ @@ -406,7 +406,7 @@ const raw = JSON.stringify({ data: {}, }, ], -}) +} const fixtures = initialSync().currentSyncData @@ -414,7 +414,6 @@ const references = [ ...fixtures.entries.map(entity => { return { sys: entity.sys, - contentful_id: entity.sys.id, __typename: `ContentfulContent`, ...entity.fields, } @@ -422,7 +421,6 @@ const references = [ ...fixtures.assets.map(entity => { return { sys: entity.sys, - contentful_id: entity.sys.id, __typename: `ContentfulAsset`, ...entity.fields, } @@ -453,11 +451,7 @@ describe(`rich text`, () => { ) } - return ( - - Resolved inline Entry ({node.data.target.contentful_id}) - - ) + return Resolved inline Entry ({node.data.target.sys.id}) }, [INLINES.ENTRY_HYPERLINK]: node => { if (!node.data.target) { @@ -468,9 +462,7 @@ describe(`rich text`, () => { ) } return ( - - Resolved entry Hyperlink ({node.data.target.contentful_id}) - + Resolved entry Hyperlink ({node.data.target.sys.id}) ) }, [INLINES.ASSET_HYPERLINK]: node => { @@ -482,9 +474,7 @@ describe(`rich text`, () => { ) } return ( - - Resolved asset Hyperlink ({node.data.target.contentful_id}) - + Resolved asset Hyperlink ({node.data.target.sys.id}) ) }, [BLOCKS.EMBEDDED_ENTRY]: node => { @@ -496,7 +486,7 @@ describe(`rich text`, () => { return (

Resolved embedded Entry: {node.data.target.title[`en-US`]} ( - {node.data.target.contentful_id}) + {node.data.target.sys.id})

) }, @@ -509,7 +499,7 @@ describe(`rich text`, () => { return (

Resolved embedded Asset: {node.data.target.title[`en-US`]} ( - {node.data.target.contentful_id}) + {node.data.target.sys.id})

) }, diff --git a/packages/gatsby-source-contentful/src/config.js b/packages/gatsby-source-contentful/src/config.js new file mode 100644 index 0000000000000..2ed916b36e560 --- /dev/null +++ b/packages/gatsby-source-contentful/src/config.js @@ -0,0 +1,12 @@ +export const conflictFieldPrefix = `contentful` + +export const restrictedNodeFields = [ + // restrictedNodeFields from here https://www.gatsbyjs.org/docs/node-interface/ + `id`, + `children`, + `parent`, + `fields`, + `internal`, + // Contentful Common resource attributes: https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/common-resource-attributes + `sys`, +] diff --git a/packages/gatsby-source-contentful/src/download-contentful-assets.js b/packages/gatsby-source-contentful/src/download-contentful-assets.js index a6c0c28d0e653..f6d7f6f82ca0d 100644 --- a/packages/gatsby-source-contentful/src/download-contentful-assets.js +++ b/packages/gatsby-source-contentful/src/download-contentful-assets.js @@ -50,9 +50,12 @@ export async function downloadContentfulAssets(gatsbyFunctions) { await distributeWorkload( assetNodes.map(node => async () => { let fileNodeID - const { contentful_id: id, node_locale: locale } = node + const { + sys: { id, locale }, + } = node const remoteDataCacheKey = `contentful-asset-${id}-${locale}` const cacheRemoteData = await cache.get(remoteDataCacheKey) + if (!node.file) { reporter.log(id, locale) reporter.warn(`The asset with id: ${id}, contains no file.`) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 141d7fbfeab6f..a10bc19538cae 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -108,13 +108,8 @@ function generateAssetTypes({ createTypes }) { file: ContentfulAssetFile title: String description: String - node_locale: String - sys: ContentfulAssetSys - contentful_id: String! + sys: ContentfulInternalSys id: ID! - spaceId: String! - createdAt: Date @dateformat - updatedAt: Date @dateformat } `) @@ -140,13 +135,6 @@ function generateAssetTypes({ createTypes }) { height: Int } `) - - createTypes(` - type ContentfulAssetSys { - type: String - revision: Int - } - `) } export function generateSchema({ @@ -157,8 +145,8 @@ export function generateSchema({ }) { createTypes(` interface ContentfulInternalReference implements Node { - contentful_id: String! id: ID! + sys: ContentfulInternalSys } `) @@ -173,17 +161,21 @@ export function generateSchema({ createTypes(` type ContentfulInternalSys @dontInfer { - type: String - revision: Int + type: String! + id: String! + spaceId: String! + environmentId: String! contentType: ContentfulContentType @link(by: "id", from: "contentType___NODE") + firstPublishedAt: Date! + publishedAt: Date! + publishedVersion: Int! + locale: String! } `) createTypes(` interface ContentfulEntry implements Node @dontInfer { - contentful_id: String! id: ID! - spaceId: String! sys: ContentfulInternalSys } `) @@ -242,14 +234,20 @@ export function generateSchema({ } traverse(source) - return context.nodeModel - .getAllNodes() - .filter(node => - node.internal.owner === `gatsby-source-contentful` && - node.internal.type === `ContentfulAsset` - ? referencedAssets.has(node.contentful_id) - : referencedEntries.has(node.contentful_id) - ) + // Get all nodes and return all that got referenced in the rich text + return context.nodeModel.getAllNodes().filter(node => { + if ( + !( + node.internal.owner === `gatsby-source-contentful` && + node?.sys?.id + ) + ) { + return false + } + return node.internal.type === `ContentfulAsset` + ? referencedAssets.has(node.sys.id) + : referencedEntries.has(node.sys.id) + }) }, }, }, @@ -302,15 +300,7 @@ export function generateSchema({ schema.buildObjectType({ name: makeTypeName(type), fields: { - contentful_id: { type: `String!` }, id: { type: `ID!` }, - // @todo reconsider the node per locale workflow - node_locale: { type: `String!` }, - // @todo these should be real dates and in sys - spaceId: { type: `String!` }, - createdAt: { type: `Date`, extensions: { dateformat: {} } }, - updatedAt: { type: `Date`, extensions: { dateformat: {} } }, - // @todo add metadata sys: { type: `ContentfulInternalSys` }, ...fields, }, diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index ce4cc2601cc89..6d2a93a3ddfb4 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -3,6 +3,8 @@ import _ from "lodash" import { getGatsbyVersion } from "gatsby-core-utils" import { lt, prerelease } from "semver" +import { restrictedNodeFields, conflictFieldPrefix } from "./config" + const typePrefix = `Contentful` export const makeTypeName = type => _.upperFirst(_.camelCase(`${typePrefix} ${type}`)) @@ -60,6 +62,10 @@ const makeMakeId = (spaceId, id, type) => createNodeId(makeId({ spaceId, id, currentLocale, defaultLocale, type })) +// Generates an unique id per space for reference resolving +export const generateReferenceId = nodeOrLink => + `${nodeOrLink.sys.id}___${nodeOrLink.sys.linkType || nodeOrLink.sys.type}` + export const buildEntryList = ({ contentTypeItems, currentSyncData }) => { // Create buckets for each type sys.id that we care about (we will always want an array for each, even if its empty) const map = new Map( @@ -83,20 +89,18 @@ export const buildResolvableSet = ({ }) => { const resolvable = new Set() existingNodes.forEach(node => { - // We need to add only root level resolvable (assets and entries) - // Derived nodes (markdown or JSON) will be recreated if needed. - resolvable.add(`${node.contentful_id}___${node.sys.type}`) + if (node.internal.owner === `gatsby-source-contentful` && node?.sys?.id) { + // We need to add only root level resolvable (assets and entries) + // Derived nodes (markdown or JSON) will be recreated if needed. + resolvable.add(generateReferenceId(node)) + } }) entryList.forEach(entries => { - entries.forEach(entry => - resolvable.add(`${entry.sys.id}___${entry.sys.type}`) - ) + entries.forEach(entry => resolvable.add(generateReferenceId(entry))) }) - assets.forEach(assetItem => - resolvable.add(`${assetItem.sys.id}___${assetItem.sys.type}`) - ) + assets.forEach(assetItem => resolvable.add(generateReferenceId(assetItem))) return resolvable } @@ -137,7 +141,7 @@ export const buildForeignReferenceMap = ({ entryItemFieldValue[0].sys.id ) { entryItemFieldValue.forEach(v => { - const key = `${v.sys.id}___${v.sys.linkType || v.sys.type}` + const key = generateReferenceId(v) // Don't create link to an unresolvable field. if (!resolvable.has(key)) { return @@ -158,9 +162,7 @@ export const buildForeignReferenceMap = ({ entryItemFieldValue?.sys?.type && entryItemFieldValue.sys.id ) { - const key = `${entryItemFieldValue.sys.id}___${ - entryItemFieldValue.sys.linkType || entryItemFieldValue.sys.type - }` + const key = generateReferenceId(entryItemFieldValue) // Don't create link to an unresolvable field. if (!resolvable.has(key)) { return @@ -194,8 +196,8 @@ function prepareTextNode(id, node, key, text) { type: `ContentfulNodeTypeText`, mediaType: `text/markdown`, content: str, - // entryItem.sys.updatedAt is source of truth from contentful - contentDigest: node.updatedAt, + // entryItem.sys.publishedAt is source of truth from contentful + contentDigest: node.sys.publishedAt, }, sys: { type: `TextNode`, @@ -278,8 +280,6 @@ function contentfulCreateNodeManifest({ export const createNodesForContentType = ({ contentTypeItem, - restrictedNodeFields, - conflictFieldPrefix, entries, unstable_createNodeManifest, createNode, @@ -315,6 +315,17 @@ export const createNodesForContentType = ({ type: `${makeTypeName(`ContentType`)}`, contentDigest: contentTypeItem.sys.updatedAt, }, + // https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/common-resource-attributes + // https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/sys-field + sys: { + type: contentTypeItem.sys.type, + id: contentTypeItem.sys.id, + spaceId: contentTypeItem.sys.space.sys.id, + environmentId: contentTypeItem.sys.environment.sys.id, + firstPublishedAt: contentTypeItem.sys.createdAt, + publishedAt: contentTypeItem.sys.updatedAt, + publishedVersion: contentTypeItem.sys.revision, + }, } createNodePromises.push(createNode(contentTypeNode)) @@ -392,11 +403,7 @@ export const createNodesForContentType = ({ // creating an empty node field in case when original key field value // is empty due to links to missing entities const resolvableEntryItemFieldValue = entryItemFieldValue - .filter(function (v) { - return resolvable.has( - `${v.sys.id}___${v.sys.linkType || v.sys.type}` - ) - }) + .filter(v => resolvable.has(generateReferenceId(v))) .map(function (v) { return mId( space.sys.id, @@ -412,14 +419,7 @@ export const createNodesForContentType = ({ delete entryItemFields[entryItemFieldKey] } } else if (entryItemFieldValue?.sys?.type === `Link`) { - if ( - resolvable.has( - `${entryItemFieldValue.sys.id}___${ - entryItemFieldValue.sys.linkType || - entryItemFieldValue.sys.type - }` - ) - ) { + if (resolvable.has(generateReferenceId(entryItemFieldValue))) { entryItemFields[`${entryItemFieldKey}___NODE`] = mId( space.sys.id, entryItemFieldValue.sys.id, @@ -434,7 +434,7 @@ export const createNodesForContentType = ({ // Add reverse linkages if there are any for this node const foreignReferences = - foreignReferenceMap[`${entryItem.sys.id}___${entryItem.sys.type}`] + foreignReferenceMap[generateReferenceId(entryItem)] if (foreignReferences) { foreignReferences.forEach(foreignReference => { const existingReference = entryItemFields[foreignReference.name] @@ -465,27 +465,9 @@ export const createNodesForContentType = ({ }) } - const sys = { - type: entryItem.sys.type, - } - - // Revision applies to entries, assets, and content types - if (entryItem.sys.revision) { - sys.revision = entryItem.sys.revision - } - - // Content type applies to entries only - if (entryItem.sys.contentType) { - sys.contentType___NODE = createNodeId(contentTypeItemId) - } - // Create actual entry node let entryNode = { id: entryNodeId, - spaceId: space.sys.id, - contentful_id: entryItem.sys.id, - createdAt: entryItem.sys.createdAt, - updatedAt: entryItem.sys.updatedAt, parent: contentTypeItemId, children: [], internal: { @@ -493,7 +475,19 @@ export const createNodesForContentType = ({ // The content of an entry is guaranteed to be updated if and only if the .sys.updatedAt field changed contentDigest: entryItem.sys.updatedAt, }, - sys, + // https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/common-resource-attributes + // https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/sys-field + sys: { + type: entryItem.sys.type, + id: entryItem.sys.id, + locale: locale.code, + spaceId: entryItem.sys.space.sys.id, + environmentId: entryItem.sys.environment.sys.id, + contentType___NODE: createNodeId(contentTypeItemId), + firstPublishedAt: entryItem.sys.createdAt, + publishedAt: entryItem.sys.updatedAt, + publishedVersion: entryItem.sys.revision, + }, } contentfulCreateNodeManifest({ @@ -504,16 +498,6 @@ export const createNodesForContentType = ({ unstable_createNodeManifest, }) - // Revision applies to entries, assets, and content types - if (entryItem.sys.revision) { - entryNode.sys.revision = entryItem.sys.revision - } - - // Content type applies to entries only - if (entryItem.sys.contentType) { - entryNode.sys.contentType = entryItem.sys.contentType - } - // Replace text fields with text nodes so we can process their markdown // into HTML. Object.keys(entryItemFields).forEach(entryItemFieldKey => { @@ -557,7 +541,6 @@ export const createNodesForContentType = ({ entryNode = { ...entryItemFields, ...entryNode, - node_locale: locale.code, } // Link tags @@ -614,11 +597,7 @@ export const createAssetNodes = ({ } const assetNode = { - contentful_id: assetItem.sys.id, - spaceId: space.sys.id, id: mId(space.sys.id, assetItem.sys.id, assetItem.sys.type), - createdAt: assetItem.sys.createdAt, - updatedAt: assetItem.sys.updatedAt, parent: null, children: [], file, @@ -626,15 +605,22 @@ export const createAssetNodes = ({ description: assetItem.fields.description ? getField(assetItem.fields.description) : ``, - node_locale: locale.code, internal: { type: `${makeTypeName(`Asset`)}`, // The content of an asset is guaranteed to be updated if and only if the .sys.updatedAt field changed contentDigest: assetItem.sys.updatedAt, }, - // @todo we can probably remove this now + // https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/common-resource-attributes + // https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/sys-field sys: { type: assetItem.sys.type, + id: assetItem.sys.id, + locale: locale.code, + spaceId: assetItem.sys.space.sys.id, + environmentId: assetItem.sys.environment.sys.id, + firstPublishedAt: assetItem.sys.createdAt, + publishedAt: assetItem.sys.updatedAt, + publishedVersion: assetItem.sys.revision, }, url: `https:${file.url}`, placeholderUrl: `https:${file.url}?w=%width%&h=%height%`, @@ -655,14 +641,6 @@ export const createAssetNodes = ({ } } - // Revision applies to entries, assets, and content types - if (assetItem.sys.revision) { - assetNode.sys.revision = assetItem.sys.revision - } - - // The content of an entry is guaranteed to be updated if and only if the .sys.updatedAt field changed - assetNode.internal.contentDigest = assetItem.sys.updatedAt - // if the node hasn't changed, createNode may return `undefined` instead of a Promise on some versions of Gatsby const maybePromise = createNode(assetNode) diff --git a/packages/gatsby-source-contentful/src/rich-text.js b/packages/gatsby-source-contentful/src/rich-text.js index 662914b6013f3..45e8753193aea 100644 --- a/packages/gatsby-source-contentful/src/rich-text.js +++ b/packages/gatsby-source-contentful/src/rich-text.js @@ -24,7 +24,7 @@ export function renderRichText({ raw, references }, options = {}) { .map(reference => { return { ...reference, - sys: { type: `Entry`, id: reference.contentful_id }, + sys: { type: `Entry`, id: reference.sys.id }, } }), Asset: references @@ -32,7 +32,7 @@ export function renderRichText({ raw, references }, options = {}) { .map(reference => { return { ...reference, - sys: { type: `Asset`, id: reference.contentful_id }, + sys: { type: `Asset`, id: reference.sys.id }, } }), }, diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index edeea3f6aa5e8..12530f33a8226 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -11,23 +11,12 @@ import { buildResolvableSet, createAssetNodes, createNodesForContentType, + generateReferenceId, makeId, } from "./normalize" import { createPluginConfig } from "./plugin-options" import { CODES } from "./report" -const conflictFieldPrefix = `contentful` - -// restrictedNodeFields from here https://www.gatsbyjs.com/docs/node-interface/ -const restrictedNodeFields = [ - `children`, - `contentful_id`, - `fields`, - `id`, - `internal`, - `parent`, -] - const CONTENT_DIGEST_COUNTER_SEPARATOR = `_COUNT_` /*** @@ -53,7 +42,6 @@ export async function sourceNodes( reporter, parentSpan, schema, - createContentDigest, }, pluginOptions ) { @@ -262,7 +250,7 @@ export async function sourceNodes( const newOrUpdatedEntries = new Set() entryList.forEach(entries => { entries.forEach(entry => { - newOrUpdatedEntries.add(`${entry.sys.id}___${entry.sys.type}`) + newOrUpdatedEntries.add(generateReferenceId(entry)) }) }) @@ -317,22 +305,19 @@ export async function sourceNodes( .filter( n => n.sys.type === `Entry` && - !newOrUpdatedEntries.has(`${n.id}___${n.sys.type}`) && + !newOrUpdatedEntries.has(generateReferenceId(n)) && !deletedEntryGatsbyReferenceIds.has(n.id) ) .forEach(n => { - if ( - n.contentful_id && - foreignReferenceMap[`${n.contentful_id}___${n.sys.type}`] - ) { - foreignReferenceMap[`${n.contentful_id}___${n.sys.type}`].forEach( + if (n.contentful_id && foreignReferenceMap[generateReferenceId(n)]) { + foreignReferenceMap[generateReferenceId(n)].forEach( foreignReference => { - const { name, id: contentfulId, type, spaceId } = foreignReference + const { name, id, type, spaceId } = foreignReference const nodeId = createNodeId( makeId({ spaceId, - id: contentfulId, + id, type, currentLocale: n.node_locale, defaultLocale, @@ -465,8 +450,6 @@ export async function sourceNodes( await Promise.all( createNodesForContentType({ contentTypeItem, - restrictedNodeFields, - conflictFieldPrefix, entries: entryList[i], createNode, createNodeId, @@ -479,7 +462,6 @@ export async function sourceNodes( useNameForId: pluginConfig.get(`useNameForId`), pluginConfig, unstable_createNodeManifest, - createContentDigest, }) ) }