From d6a6752b3f802373011a1fe245e3448ce1c1da53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 10:55:53 +0200 Subject: [PATCH 001/149] WIP - initial schema generation --- .../src/generate-schema.js | 211 ++++++++++++++++++ .../gatsby-source-contentful/src/normalize.js | 7 +- .../src/source-nodes.js | 19 +- 3 files changed, 231 insertions(+), 6 deletions(-) create mode 100644 packages/gatsby-source-contentful/src/generate-schema.js diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js new file mode 100644 index 0000000000000..5abc7241baab4 --- /dev/null +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -0,0 +1,211 @@ +const fs = require(`fs`) + +import { makeTypeName } from "./normalize" + +const types = [] + +function generateAssetSchemas({ createTypes }) { + createTypes(` + type ContentfulAsset implements ContentfulReference & Node @derivedTypes @dontInfer { + contentful_id: String! + spaceId: String + createdAt: Date @dateformat + updatedAt: Date @dateformat + file: ContentfulAssetFile + title: String + description: String + node_locale: String + sys: ContentfulAssetSys + } + `) + + createTypes(` + type ContentfulAssetFile @derivedTypes { + url: String + details: ContentfulAssetFileDetails + fileName: String + contentType: String + } + `) + + createTypes(` + type ContentfulAssetFileDetails @derivedTypes { + size: Int + image: ContentfulAssetFileDetailsImage + } + `) + + createTypes(` + type ContentfulAssetFileDetailsImage { + width: Int + height: Int + } + `) + + createTypes(` + type ContentfulAssetSys { + type: String + revision: Int + } + `) +} + +export function generateSchemas({ + createTypes, + schema, + pluginConfig, + contentTypeItems, +}) { + // logger @todo remove it + const origTypes = createTypes + createTypes = (...all) => { + types.push(all) + origTypes(...all) + } + + createTypes(` + interface ContentfulEntry implements Node { + contentful_id: String! + id: ID! + node_locale: String! + } + `) + + createTypes(` + interface ContentfulReference { + contentful_id: String! + id: ID! + } + `) + + generateAssetSchemas({ createTypes }) + + // Contentful specific types + + if (pluginConfig.get(`enableTags`)) { + createTypes( + schema.buildObjectType({ + name: `ContentfulTag`, + fields: { + name: { type: `String!` }, + contentful_id: { type: `String!` }, + id: { type: `ID!` }, + }, + interfaces: [`Node`], + extensions: { dontInfer: {} }, + }) + ) + } + + createTypes( + schema.buildObjectType({ + name: `ContentfulRichTextNode`, + fields: { + raw: { type: `String!` }, + references: { type: `ContentfulReference` }, + }, + interfaces: [`Node`], + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulLocationNode`, + fields: { + lat: { type: `Float!` }, + lon: { type: `Float!` }, + }, + interfaces: [`Node`], + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulJSONNode`, + fields: {}, + interfaces: [`Node`], + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulTextNode`, + fields: {}, + interfaces: [`Node`], + }) + ) + + // Contentful content type schemas + const ContentfulDataTypes = new Map([ + [`Symbol`, `String`], + [`Text`, `String`], + [`Integer`, `Int`], + [`Number`, `Float`], + [`Date`, `Date`], + [`Object`, `JSON`], + [`Boolean`, `Boolean`], + [`Location`, `ContentfulLocationNode`], + [`RichText`, `ContentfulRichTextNode`], + ]) + const getLinkFieldType = linkType => `Contentful${linkType}` + + const translateFieldType = field => { + let id + if (field.type === `Array`) { + id = `[${ + field.items.type === `Link` + ? getLinkFieldType(field.items.linkType) + : translateFieldType(field.items) + }]` + } else if (field.type === `Link`) { + id = getLinkFieldType(field.linkType) + } else { + id = ContentfulDataTypes.get(field.type) + } + + return [id, field.required && `!`].filter(Boolean).join(``) + } + + contentTypeItems.forEach(contentTypeItem => { + try { + const fields = {} + contentTypeItem.fields.forEach(field => { + if (field.disabled || field.omitted) { + return + } + const type = translateFieldType(field) + fields[field.id] = { type } + }) + + // console.log(contentTypeItem.sys.id, { fields }) + + const type = pluginConfig.get(`useNameForId`) + ? contentTypeItem.name + : contentTypeItem.sys.id + + createTypes( + schema.buildObjectType({ + name: makeTypeName(type), + fields: { + contentful_id: { type: `String!` }, + id: { type: `ID!` }, + node_locale: { type: `String!` }, + ...fields, + }, + interfaces: [`ContentfulReference`, `ContentfulEntry`, `Node`], + }) + ) + } catch (err) { + err.message = `Unable to create schema for Contentful Content Type ${ + contentTypeItem.name || contentTypeItem.sys.id + }:\n${err.message}` + throw err + } + }) + + fs.writeFileSync( + process.cwd() + `/generated-types.json`, + JSON.stringify(types, null, 2) + ) + createTypes = origTypes +} diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index dbb6ef7e0a4ab..c79f218421060 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -5,7 +5,8 @@ import { getGatsbyVersion } from "gatsby-core-utils" import { lt, prerelease } from "semver" const typePrefix = `Contentful` -const makeTypeName = type => _.upperFirst(_.camelCase(`${typePrefix} ${type}`)) +export const makeTypeName = type => + _.upperFirst(_.camelCase(`${typePrefix} ${type}`)) const GATSBY_VERSION_MANIFEST_V2 = `4.3.0` const gatsbyVersion = @@ -192,7 +193,7 @@ function prepareTextNode(id, node, key, text) { children: [], [key]: str, internal: { - type: _.camelCase(`${node.internal.type} ${key} TextNode`), + type: `ContentfulTextNode`, mediaType: `text/markdown`, content: str, // entryItem.sys.updatedAt is source of truth from contentful @@ -216,7 +217,7 @@ function prepareJSONNode(id, node, key, content) { parent: node.id, children: [], internal: { - type: _.camelCase(`${node.internal.type} ${key} JSONNode`), + type: `ContentfulJSONNode`, mediaType: `application/json`, content: str, // entryItem.sys.updatedAt is source of truth from contentful diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index be473a0c50e7a..b01165700c143 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -4,6 +4,7 @@ import _ from "lodash" import { downloadContentfulAssets } from "./download-contentful-assets" import { fetchContent } from "./fetch" +import { generateSchemas } from "./generate-schema" import { buildEntryList, buildForeignReferenceMap, @@ -51,11 +52,17 @@ export async function sourceNodes( getCache, reporter, parentSpan, + schema, }, pluginOptions ) { - const { createNode, touchNode, deleteNode, unstable_createNodeManifest } = - actions + const { + createNode, + touchNode, + deleteNode, + unstable_createNodeManifest, + createTypes, + } = actions const online = await isOnline() getNodes().forEach(node => { @@ -179,6 +186,9 @@ export async function sourceNodes( ) processingActivity.start() + // Generate schemas based on Contentful content model + generateSchemas({ createTypes, schema, pluginConfig, contentTypeItems }) + // Array of all existing Contentful nodes const existingNodes = getNodes().filter( n => @@ -222,7 +232,10 @@ export async function sourceNodes( reporter.verbose(`Building Contentful reference map`) - const entryList = buildEntryList({ contentTypeItems, currentSyncData }) + const entryList = buildEntryList({ + currentSyncData, + contentTypeItems, + }) const { assets } = currentSyncData // Create map of resolvable ids so we can check links against them while creating From 38f1f2a174a75a59527569d25918297b03317651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 11:11:12 +0200 Subject: [PATCH 002/149] allow complex field types and add date formatter for date fields --- .../src/generate-schema.js | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 5abc7241baab4..94c7f50eea71d 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -141,7 +141,15 @@ export function generateSchemas({ [`Text`, `String`], [`Integer`, `Int`], [`Number`, `Float`], - [`Date`, `Date`], + [ + `Date`, + { + type: `Date`, + extensions: { + dateformat: {}, + }, + }, + ], [`Object`, `JSON`], [`Boolean`, `Boolean`], [`Location`, `ContentfulLocationNode`], @@ -152,18 +160,30 @@ export function generateSchemas({ const translateFieldType = field => { let id if (field.type === `Array`) { - id = `[${ + const fieldData = field.items.type === `Link` ? getLinkFieldType(field.items.linkType) : translateFieldType(field.items) - }]` + + id = + typeof fieldData === `string` + ? `[${fieldData}]` + : { ...fieldData, type: `[${fieldData.type}]` } } else if (field.type === `Link`) { id = getLinkFieldType(field.linkType) } else { id = ContentfulDataTypes.get(field.type) } - return [id, field.required && `!`].filter(Boolean).join(``) + if (typeof id === `string`) { + return [id, field.required && `!`].filter(Boolean).join(``) + } + + if (field.required) { + id.type = `${id.type}!` + } + + return id } contentTypeItems.forEach(contentTypeItem => { @@ -174,7 +194,7 @@ export function generateSchemas({ return } const type = translateFieldType(field) - fields[field.id] = { type } + fields[field.id] = typeof type === `string` ? { type } : type }) // console.log(contentTypeItem.sys.id, { fields }) From e6b8be1c7b12cef673e70d7cfd2a0cf6b3612c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 11:17:34 +0200 Subject: [PATCH 003/149] move generic fields to reference type --- packages/gatsby-source-contentful/src/generate-schema.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 94c7f50eea71d..b1c8ba35cc524 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -7,10 +7,6 @@ const types = [] function generateAssetSchemas({ createTypes }) { createTypes(` type ContentfulAsset implements ContentfulReference & Node @derivedTypes @dontInfer { - contentful_id: String! - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat file: ContentfulAssetFile title: String description: String @@ -75,6 +71,9 @@ export function generateSchemas({ interface ContentfulReference { contentful_id: String! id: ID! + spaceId: String!, + createdAt: Date @dateform, + updatedAt: Date @dateform, } `) From 9a647e86ad483ea0e07f28d12094e1a6695337a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 13:21:15 +0200 Subject: [PATCH 004/149] use generic types for entry sys and content types --- .../src/generate-schema.js | 41 +++++++++++++++---- .../gatsby-source-contentful/src/normalize.js | 35 ++++++++++++---- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index b1c8ba35cc524..b70c7ee2ad4c0 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -6,12 +6,17 @@ const types = [] function generateAssetSchemas({ createTypes }) { createTypes(` - type ContentfulAsset implements ContentfulReference & Node @derivedTypes @dontInfer { + type ContentfulAsset implements ContentfulReference & Node { file: ContentfulAssetFile title: String description: String node_locale: String sys: ContentfulAssetSys + contentful_id: String! + id: ID! + spaceId: String! + createdAt: String! # Date @dateform, + updatedAt: String! # Date @dateform, } `) @@ -60,20 +65,36 @@ export function generateSchemas({ } createTypes(` - interface ContentfulEntry implements Node { + interface ContentfulReference implements Node { contentful_id: String! id: ID! - node_locale: String! } `) createTypes(` - interface ContentfulReference { + type ContentfulContentType implements Node { + id: ID! + name: String! + displayField: String! + description: String! + } + `) + + createTypes(` + type ContentfulSys implements Node { + id: ID! + type: String + revision: Int + contentType: ContentfulContentType @link(by: "id", from: "contentType___NODE") + } + `) + + createTypes(` + interface ContentfulEntry implements Node { contentful_id: String! id: ID! - spaceId: String!, - createdAt: Date @dateform, - updatedAt: Date @dateform, + spaceId: String! + sys: ContentfulSys @link(by: "id", from: "sys___NODE") } `) @@ -196,8 +217,6 @@ export function generateSchemas({ fields[field.id] = typeof type === `string` ? { type } : type }) - // console.log(contentTypeItem.sys.id, { fields }) - const type = pluginConfig.get(`useNameForId`) ? contentTypeItem.name : contentTypeItem.sys.id @@ -209,6 +228,10 @@ export function generateSchemas({ contentful_id: { type: `String!` }, id: { type: `ID!` }, node_locale: { type: `String!` }, + spaceId: { type: `String!` }, + // @todo these should be real dates and in sys + createdAt: { type: `String!` }, // { type: `Date`, extensions: { dateform: {} } }, + updatedAt: { type: `String!` }, // { type: `Date`, extensions: { dateform: {} } }, ...fields, }, interfaces: [`ContentfulReference`, `ContentfulEntry`, `Node`], diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index c79f218421060..8099a80cab6b9 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -336,8 +336,6 @@ export const createNodesForContentType = ({ // Create a node for the content type const contentTypeNode = { id: createNodeId(contentTypeItemId), - parent: null, - children: [], name: contentTypeItem.name, displayField: contentTypeItem.displayField, description: contentTypeItem.description, @@ -345,9 +343,6 @@ export const createNodesForContentType = ({ type: `${makeTypeName(`ContentType`)}`, contentDigest: contentTypeItem.sys.updatedAt, }, - sys: { - type: contentTypeItem.sys.type, - }, } createNodePromises.push(createNode(contentTypeNode)) @@ -498,6 +493,32 @@ export const createNodesForContentType = ({ }) } + // Create sys node + const sysId = createNodeId(`${entryNodeId}.sys`) + + const sys = { + id: sysId, + // parent___NODE: entryNodeId, + type: entryItem.sys.type, + internal: { + type: `ContentfulSys`, + contentDigest: entryItem.sys.updatedAt, + }, + } + + // 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) + } + + childrenNodes.push(sys) + + // Create actual entry node let entryNode = { id: entryNodeId, spaceId: space.sys.id, @@ -509,9 +530,7 @@ export const createNodesForContentType = ({ internal: { type: `${makeTypeName(contentTypeItemId)}`, }, - sys: { - type: entryItem.sys.type, - }, + sys___NODE: sysId, } contentfulCreateNodeManifest({ From 608f26f83ad55f89630095528313056750980c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 13:53:35 +0200 Subject: [PATCH 005/149] use generic types for rich text fields --- .../src/generate-schema.js | 16 ++++++++++++++-- .../gatsby-source-contentful/src/normalize.js | 18 ++++++++++++++++-- .../src/source-nodes.js | 2 ++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index b70c7ee2ad4c0..716fd1f099ebd 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -119,7 +119,7 @@ export function generateSchemas({ createTypes( schema.buildObjectType({ - name: `ContentfulRichTextNode`, + name: `ContentfulNodeTypeRichText`, fields: { raw: { type: `String!` }, references: { type: `ContentfulReference` }, @@ -173,7 +173,15 @@ export function generateSchemas({ [`Object`, `JSON`], [`Boolean`, `Boolean`], [`Location`, `ContentfulLocationNode`], - [`RichText`, `ContentfulRichTextNode`], + [ + `RichText`, + { + type: `ContentfulNodeTypeRichText`, + extensions: { + link: { by: `id` }, + }, + }, + ], ]) const getLinkFieldType = linkType => `Contentful${linkType}` @@ -203,6 +211,10 @@ export function generateSchemas({ id.type = `${id.type}!` } + if (id.extensions.link) { + id.extensions.link.from = `${field.id}___NODE` + } + return id } diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index 8099a80cab6b9..f45618a331feb 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -312,6 +312,7 @@ export const createNodesForContentType = ({ unstable_createNodeManifest, createNode, createNodeId, + createContentDigest, getNode, resolvable, foreignReferenceMap, @@ -625,10 +626,23 @@ export const createNodesForContentType = ({ ) }) - entryItemFields[entryItemFieldKey] = { - raw: stringify(fieldValue), + const richTextNodeId = createNodeId( + `${entryNodeId}.${entryItemFieldKey}.richText` + ) + + const raw = stringify(fieldValue) + const richTextNode = { + id: richTextNodeId, + raw, references___NODE: [...resolvableReferenceIds], + internal: { + type: `ContentfulNodeTypeRichText`, + contentDigest: createContentDigest(raw), + }, } + childrenNodes.push(richTextNode) + delete entryItemFields[entryItemFieldKey] + entryItemFields[`${entryItemFieldKey}___NODE`] = richTextNodeId } else if ( fieldType === `Object` && _.isPlainObject(entryItemFields[entryItemFieldKey]) diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index b01165700c143..e772527f1b0c0 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -53,6 +53,7 @@ export async function sourceNodes( reporter, parentSpan, schema, + createContentDigest, }, pluginOptions ) { @@ -478,6 +479,7 @@ export async function sourceNodes( useNameForId: pluginConfig.get(`useNameForId`), pluginConfig, unstable_createNodeManifest, + createContentDigest, }) ) } From 09b4ac917f203ddf8ca385764e7ce42c7f394fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 14:06:57 +0200 Subject: [PATCH 006/149] use generic types for location fields --- .../src/generate-schema.js | 12 +++++- .../gatsby-source-contentful/src/normalize.js | 42 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 716fd1f099ebd..f504bde16f0fe 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -130,7 +130,7 @@ export function generateSchemas({ createTypes( schema.buildObjectType({ - name: `ContentfulLocationNode`, + name: `ContentfulNodeTypeLocation`, fields: { lat: { type: `Float!` }, lon: { type: `Float!` }, @@ -172,7 +172,15 @@ export function generateSchemas({ ], [`Object`, `JSON`], [`Boolean`, `Boolean`], - [`Location`, `ContentfulLocationNode`], + [ + `Location`, + { + type: `ContentfulNodeTypeLocation`, + extensions: { + link: { by: `id` }, + }, + }, + ], [ `RichText`, { diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index f45618a331feb..80897eba71577 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -209,6 +209,23 @@ function prepareTextNode(id, node, key, text) { return textNode } +function prepareLocationNode(id, node, key, data) { + const { lat, lon } = data + const LocationNode = { + id, + parent: node.id, + lat, + lon, + internal: { + type: `ContentfulNodeTypeLocation`, + // entryItem.sys.updatedAt is source of truth from contentful + contentDigest: node.updatedAt, + }, + } + + return LocationNode +} + function prepareJSONNode(id, node, key, content) { const str = JSON.stringify(content) const JSONNode = { @@ -695,6 +712,31 @@ export const createNodesForContentType = ({ entryItemFields[`${entryItemFieldKey}___NODE`].push(jsonNodeId) }) + delete entryItemFields[entryItemFieldKey] + } else if (fieldType === `Location`) { + const locationNodeId = createNodeId( + `${entryNodeId}${entryItemFieldKey}Location` + ) + + // The Contentful model has `.sys.updatedAt` leading for an entry. If the updatedAt value + // of an entry did not change, then we can trust that none of its children were changed either. + // (That's why child nodes use the updatedAt of the parent node as their digest, too) + const existingNode = getNode(locationNodeId) + if ( + existingNode?.internal?.contentDigest !== entryItem.sys.updatedAt + ) { + const textNode = prepareLocationNode( + locationNodeId, + entryNode, + entryItemFieldKey, + entryItemFields[entryItemFieldKey], + createNodeId + ) + + childrenNodes.push(textNode) + } + + entryItemFields[`${entryItemFieldKey}___NODE`] = locationNodeId delete entryItemFields[entryItemFieldKey] } }) From 45f5cce0edf7bba38e8c3cbffc69b3069f598645 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 14:17:33 +0200 Subject: [PATCH 007/149] use generic types for JSON fields --- .../gatsby-source-contentful/src/generate-schema.js | 12 ++++++++++-- packages/gatsby-source-contentful/src/normalize.js | 2 +- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index f504bde16f0fe..61635fecdf390 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -141,7 +141,7 @@ export function generateSchemas({ createTypes( schema.buildObjectType({ - name: `ContentfulJSONNode`, + name: `ContentfulNodeTypeJSON`, fields: {}, interfaces: [`Node`], }) @@ -170,7 +170,15 @@ export function generateSchemas({ }, }, ], - [`Object`, `JSON`], + [ + `Object`, + { + type: `ContentfulNodeTypeJSON`, + extensions: { + link: { by: `id` }, + }, + }, + ], [`Boolean`, `Boolean`], [ `Location`, diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index 80897eba71577..aa05010789540 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -234,7 +234,7 @@ function prepareJSONNode(id, node, key, content) { parent: node.id, children: [], internal: { - type: `ContentfulJSONNode`, + type: `ContentfulNodeTypeJSON`, mediaType: `application/json`, content: str, // entryItem.sys.updatedAt is source of truth from contentful From b546b4f6510489490b6508690fe298eb457be917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 14:41:13 +0200 Subject: [PATCH 008/149] use generic types for Text fields --- packages/gatsby-source-contentful/README.md | 2 +- .../src/generate-schema.js | 16 +++++++++++++--- .../gatsby-source-contentful/src/normalize.js | 7 ++----- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/packages/gatsby-source-contentful/README.md b/packages/gatsby-source-contentful/README.md index 146182c5013fa..7261fd2fe5618 100644 --- a/packages/gatsby-source-contentful/README.md +++ b/packages/gatsby-source-contentful/README.md @@ -263,7 +263,7 @@ On Contentful, a "Long text" field uses Markdown by default. The field is expose { contentfulCaseStudy { body { - body + raw } } } diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 61635fecdf390..f7b85776ca270 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -149,8 +149,10 @@ export function generateSchemas({ createTypes( schema.buildObjectType({ - name: `ContentfulTextNode`, - fields: {}, + name: `ContentfulNodeTypeText`, + fields: { + raw: `String!`, + }, interfaces: [`Node`], }) ) @@ -158,7 +160,15 @@ export function generateSchemas({ // Contentful content type schemas const ContentfulDataTypes = new Map([ [`Symbol`, `String`], - [`Text`, `String`], + [ + `Text`, + { + type: `ContentfulNodeTypeText`, + extensions: { + link: { by: `id` }, + }, + }, + ], [`Integer`, `Int`], [`Number`, `Float`], [ diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index aa05010789540..bb74f9c340c59 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -190,10 +190,9 @@ function prepareTextNode(id, node, key, text) { const textNode = { id, parent: node.id, - children: [], - [key]: str, + raw: str, internal: { - type: `ContentfulTextNode`, + type: `ContentfulNodeTypeText`, mediaType: `text/markdown`, content: str, // entryItem.sys.updatedAt is source of truth from contentful @@ -204,8 +203,6 @@ function prepareTextNode(id, node, key, text) { }, } - node.children = node.children.concat([id]) - return textNode } From a049f87bb81c4a0608030c8cbd5ae3f9e0a5b5ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 15:02:53 +0200 Subject: [PATCH 009/149] fix: ensure links from is set properly --- packages/gatsby-source-contentful/src/generate-schema.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index f7b85776ca270..37ecf956a02e9 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -1,4 +1,5 @@ const fs = require(`fs`) +const { cloneDeep } = require(`lodash`) import { makeTypeName } from "./normalize" @@ -233,6 +234,8 @@ export function generateSchemas({ return [id, field.required && `!`].filter(Boolean).join(``) } + id = cloneDeep(id) + if (field.required) { id.type = `${id.type}!` } From 509c7ce2fafa1b8c7246c851840482511e8e46eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 15:12:59 +0200 Subject: [PATCH 010/149] rename internal interfaces to avoid name collisions --- .../src/generate-schema.js | 16 ++++++++++------ .../gatsby-source-contentful/src/normalize.js | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 37ecf956a02e9..ec1fd673544e3 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -7,7 +7,7 @@ const types = [] function generateAssetSchemas({ createTypes }) { createTypes(` - type ContentfulAsset implements ContentfulReference & Node { + type ContentfulAsset implements ContentfulInternalReference & Node { file: ContentfulAssetFile title: String description: String @@ -66,7 +66,7 @@ export function generateSchemas({ } createTypes(` - interface ContentfulReference implements Node { + interface ContentfulInternalReference implements Node { contentful_id: String! id: ID! } @@ -82,7 +82,7 @@ export function generateSchemas({ `) createTypes(` - type ContentfulSys implements Node { + type ContentfulInternalSys implements Node { id: ID! type: String revision: Int @@ -95,7 +95,7 @@ export function generateSchemas({ contentful_id: String! id: ID! spaceId: String! - sys: ContentfulSys @link(by: "id", from: "sys___NODE") + sys: ContentfulInternalSys @link(by: "id", from: "sys___NODE") } `) @@ -123,7 +123,7 @@ export function generateSchemas({ name: `ContentfulNodeTypeRichText`, fields: { raw: { type: `String!` }, - references: { type: `ContentfulReference` }, + references: { type: `ContentfulInternalReference` }, }, interfaces: [`Node`], }) @@ -275,7 +275,11 @@ export function generateSchemas({ updatedAt: { type: `String!` }, // { type: `Date`, extensions: { dateform: {} } }, ...fields, }, - interfaces: [`ContentfulReference`, `ContentfulEntry`, `Node`], + interfaces: [ + `ContentfulInternalReference`, + `ContentfulEntry`, + `Node`, + ], }) ) } catch (err) { diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index bb74f9c340c59..e1be5c6e2cd7a 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -516,7 +516,7 @@ export const createNodesForContentType = ({ // parent___NODE: entryNodeId, type: entryItem.sys.type, internal: { - type: `ContentfulSys`, + type: `ContentfulInternalSys`, contentDigest: entryItem.sys.updatedAt, }, } From c0bcaa7d1ef05a428527975ff77fde805d0aa5c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Apr 2021 15:17:31 +0200 Subject: [PATCH 011/149] properly set links for references to new generic types --- .../gatsby-source-contentful/src/generate-schema.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index ec1fd673544e3..65cb90c1c9a17 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -210,7 +210,15 @@ export function generateSchemas({ }, ], ]) - const getLinkFieldType = linkType => `Contentful${linkType}` + + const getLinkFieldType = linkType => { + return { + type: `Contentful${linkType}`, + extensions: { + link: { by: `id` }, + }, + } + } const translateFieldType = field => { let id From 4915a3fbc029b67ec5101d2b9831e0f59bb0ce12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 13 Apr 2021 15:35:52 +0200 Subject: [PATCH 012/149] no more create nodes for JSON, RichText and Location --- e2e-tests/contentful/src/pages/json.js | 21 +- e2e-tests/contentful/src/pages/text.js | 4 +- .../src/generate-schema.js | 119 ++++++----- .../gatsby-source-contentful/src/normalize.js | 196 +----------------- .../src/source-nodes.js | 4 +- 5 files changed, 80 insertions(+), 264 deletions(-) diff --git a/e2e-tests/contentful/src/pages/json.js b/e2e-tests/contentful/src/pages/json.js index b41d1bf54501e..45172e184fb0d 100644 --- a/e2e-tests/contentful/src/pages/json.js +++ b/e2e-tests/contentful/src/pages/json.js @@ -62,27 +62,10 @@ export default JSONPage export const pageQuery = graphql` query JSONQuery { simple: contentfulJson(contentful_id: { eq: "2r6tNjP8brkyy5yLR39hhh" }) { - json { - name - city - age - } + json } complex: contentfulJson(contentful_id: { eq: "2y71nV0cpW9vzTmJybq571" }) { - json { - Actors { - name - photo - Birthdate - Born_At - weight - age - wife - children - hasChildren - hasGreyHair - } - } + json } english: contentfulJson( node_locale: { eq: "en-US" } diff --git a/e2e-tests/contentful/src/pages/text.js b/e2e-tests/contentful/src/pages/text.js index bc39dd5ddfa6e..360a154201c5b 100644 --- a/e2e-tests/contentful/src/pages/text.js +++ b/e2e-tests/contentful/src/pages/text.js @@ -33,7 +33,7 @@ const TextPage = ({ data }) => {

Long (Plain):

-

{longPlain.longPlain.longPlain}

+

{longPlain.longPlain.raw}

Markdown (Simple):

{ + // eslint-disable-next-line guard-for-in + for (const k in obj) { + const v = obj[k] + if (v && v.sys && v.sys.type === `Link`) { + if (v.sys.linkType === `Asset`) { + console.log(`adding asset`, v) + referencedAssets.add(v.sys.id) + } + if (v.sys.linkType === `Entry`) { + console.log(`adding entry`, v) + referencedEntries.add(v.sys.id) + } + } else if (v && typeof v === `object`) { + traverse(v) + } + } + } + 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) + ) + }, + }, }, - interfaces: [`Node`], + extensions: { dontInfer: {} }, }) ) @@ -136,18 +176,13 @@ export function generateSchemas({ lat: { type: `Float!` }, lon: { type: `Float!` }, }, - interfaces: [`Node`], - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulNodeTypeJSON`, - fields: {}, - interfaces: [`Node`], + extensions: { + dontInfer: {}, + }, }) ) + // Is there a way to have this as string and let transformer-remark replace it with an object? createTypes( schema.buildObjectType({ name: `ContentfulNodeTypeText`, @@ -155,6 +190,9 @@ export function generateSchemas({ raw: `String!`, }, interfaces: [`Node`], + extensions: { + dontInfer: {}, + }, }) ) @@ -181,34 +219,10 @@ export function generateSchemas({ }, }, ], - [ - `Object`, - { - type: `ContentfulNodeTypeJSON`, - extensions: { - link: { by: `id` }, - }, - }, - ], + [`Object`, `JSON`], [`Boolean`, `Boolean`], - [ - `Location`, - { - type: `ContentfulNodeTypeLocation`, - extensions: { - link: { by: `id` }, - }, - }, - ], - [ - `RichText`, - { - type: `ContentfulNodeTypeRichText`, - extensions: { - link: { by: `id` }, - }, - }, - ], + [`Location`, `ContentfulNodeTypeLocation`], + [`RichText`, `ContentfulNodeTypeRichText`], ]) const getLinkFieldType = linkType => { @@ -248,14 +262,14 @@ export function generateSchemas({ id.type = `${id.type}!` } - if (id.extensions.link) { + if (id?.extensions?.link) { id.extensions.link.from = `${field.id}___NODE` } return id } - contentTypeItems.forEach(contentTypeItem => { + for (const contentTypeItem of contentTypeItems) { try { const fields = {} contentTypeItem.fields.forEach(field => { @@ -276,11 +290,14 @@ export function generateSchemas({ fields: { contentful_id: { type: `String!` }, id: { type: `ID!` }, + // @todo reconsider the node per locale workflow node_locale: { type: `String!` }, - spaceId: { type: `String!` }, // @todo these should be real dates and in sys + spaceId: { type: `String!` }, createdAt: { type: `String!` }, // { type: `Date`, extensions: { dateform: {} } }, updatedAt: { type: `String!` }, // { type: `Date`, extensions: { dateform: {} } }, + // @todo add metadata + sys: { type: `ContentfulInternalSys` }, ...fields, }, interfaces: [ @@ -296,7 +313,7 @@ export function generateSchemas({ }:\n${err.message}` throw err } - }) + } fs.writeFileSync( process.cwd() + `/generated-types.json`, diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index e1be5c6e2cd7a..ce4cc2601cc89 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -1,5 +1,4 @@ // @ts-check -import stringify from "json-stringify-safe" import _ from "lodash" import { getGatsbyVersion } from "gatsby-core-utils" import { lt, prerelease } from "semver" @@ -206,47 +205,6 @@ function prepareTextNode(id, node, key, text) { return textNode } -function prepareLocationNode(id, node, key, data) { - const { lat, lon } = data - const LocationNode = { - id, - parent: node.id, - lat, - lon, - internal: { - type: `ContentfulNodeTypeLocation`, - // entryItem.sys.updatedAt is source of truth from contentful - contentDigest: node.updatedAt, - }, - } - - return LocationNode -} - -function prepareJSONNode(id, node, key, content) { - const str = JSON.stringify(content) - const JSONNode = { - ...(_.isPlainObject(content) ? { ...content } : { content: content }), - id, - parent: node.id, - children: [], - internal: { - type: `ContentfulNodeTypeJSON`, - mediaType: `application/json`, - content: str, - // entryItem.sys.updatedAt is source of truth from contentful - contentDigest: node.updatedAt, - }, - sys: { - type: `JsonNode`, - }, - } - - node.children = node.children.concat([id]) - - return JSONNode -} - let numberOfContentSyncDebugLogs = 0 const maxContentSyncDebugLogTimes = 50 @@ -326,7 +284,6 @@ export const createNodesForContentType = ({ unstable_createNodeManifest, createNode, createNodeId, - createContentDigest, getNode, resolvable, foreignReferenceMap, @@ -508,17 +465,8 @@ export const createNodesForContentType = ({ }) } - // Create sys node - const sysId = createNodeId(`${entryNodeId}.sys`) - const sys = { - id: sysId, - // parent___NODE: entryNodeId, type: entryItem.sys.type, - internal: { - type: `ContentfulInternalSys`, - contentDigest: entryItem.sys.updatedAt, - }, } // Revision applies to entries, assets, and content types @@ -531,8 +479,6 @@ export const createNodesForContentType = ({ sys.contentType___NODE = createNodeId(contentTypeItemId) } - childrenNodes.push(sys) - // Create actual entry node let entryNode = { id: entryNodeId, @@ -544,8 +490,10 @@ export const createNodesForContentType = ({ children: [], internal: { type: `${makeTypeName(contentTypeItemId)}`, + // The content of an entry is guaranteed to be updated if and only if the .sys.updatedAt field changed + contentDigest: entryItem.sys.updatedAt, }, - sys___NODE: sysId, + sys, } contentfulCreateNodeManifest({ @@ -603,138 +551,6 @@ export const createNodesForContentType = ({ entryItemFields[`${entryItemFieldKey}___NODE`] = textNodeId delete entryItemFields[entryItemFieldKey] - } else if ( - fieldType === `RichText` && - _.isPlainObject(entryItemFields[entryItemFieldKey]) - ) { - const fieldValue = entryItemFields[entryItemFieldKey] - - const rawReferences = [] - - // Locate all Contentful Links within the rich text data - const traverse = obj => { - // eslint-disable-next-line guard-for-in - for (const k in obj) { - const v = obj[k] - if (v && v.sys && v.sys.type === `Link`) { - rawReferences.push(v) - } else if (v && typeof v === `object`) { - traverse(v) - } - } - } - - traverse(fieldValue) - - // Build up resolvable reference list - const resolvableReferenceIds = new Set() - rawReferences - .filter(function (v) { - return resolvable.has( - `${v.sys.id}___${v.sys.linkType || v.sys.type}` - ) - }) - .forEach(function (v) { - resolvableReferenceIds.add( - mId(space.sys.id, v.sys.id, v.sys.linkType || v.sys.type) - ) - }) - - const richTextNodeId = createNodeId( - `${entryNodeId}.${entryItemFieldKey}.richText` - ) - - const raw = stringify(fieldValue) - const richTextNode = { - id: richTextNodeId, - raw, - references___NODE: [...resolvableReferenceIds], - internal: { - type: `ContentfulNodeTypeRichText`, - contentDigest: createContentDigest(raw), - }, - } - childrenNodes.push(richTextNode) - delete entryItemFields[entryItemFieldKey] - entryItemFields[`${entryItemFieldKey}___NODE`] = richTextNodeId - } else if ( - fieldType === `Object` && - _.isPlainObject(entryItemFields[entryItemFieldKey]) - ) { - const jsonNodeId = createNodeId( - `${entryNodeId}${entryItemFieldKey}JSONNode` - ) - - // The Contentful model has `.sys.updatedAt` leading for an entry. If the updatedAt value - // of an entry did not change, then we can trust that none of its children were changed either. - // (That's why child nodes use the updatedAt of the parent node as their digest, too) - const existingNode = getNode(jsonNodeId) - if (existingNode?.updatedAt !== entryItem.sys.updatedAt) { - const jsonNode = prepareJSONNode( - jsonNodeId, - entryNode, - entryItemFieldKey, - entryItemFields[entryItemFieldKey] - ) - childrenNodes.push(jsonNode) - } - - entryItemFields[`${entryItemFieldKey}___NODE`] = jsonNodeId - delete entryItemFields[entryItemFieldKey] - } else if ( - fieldType === `Object` && - _.isArray(entryItemFields[entryItemFieldKey]) - ) { - entryItemFields[`${entryItemFieldKey}___NODE`] = [] - - entryItemFields[entryItemFieldKey].forEach((obj, i) => { - const jsonNodeId = createNodeId( - `${entryNodeId}${entryItemFieldKey}${i}JSONNode` - ) - - // The Contentful model has `.sys.updatedAt` leading for an entry. If the updatedAt value - // of an entry did not change, then we can trust that none of its children were changed either. - // (That's why child nodes use the updatedAt of the parent node as their digest, too) - const existingNode = getNode(jsonNodeId) - if (existingNode?.updatedAt !== entryItem.sys.updatedAt) { - const jsonNode = prepareJSONNode( - jsonNodeId, - entryNode, - entryItemFieldKey, - obj - ) - childrenNodes.push(jsonNode) - } - - entryItemFields[`${entryItemFieldKey}___NODE`].push(jsonNodeId) - }) - - delete entryItemFields[entryItemFieldKey] - } else if (fieldType === `Location`) { - const locationNodeId = createNodeId( - `${entryNodeId}${entryItemFieldKey}Location` - ) - - // The Contentful model has `.sys.updatedAt` leading for an entry. If the updatedAt value - // of an entry did not change, then we can trust that none of its children were changed either. - // (That's why child nodes use the updatedAt of the parent node as their digest, too) - const existingNode = getNode(locationNodeId) - if ( - existingNode?.internal?.contentDigest !== entryItem.sys.updatedAt - ) { - const textNode = prepareLocationNode( - locationNodeId, - entryNode, - entryItemFieldKey, - entryItemFields[entryItemFieldKey], - createNodeId - ) - - childrenNodes.push(textNode) - } - - entryItemFields[`${entryItemFieldKey}___NODE`] = locationNodeId - delete entryItemFields[entryItemFieldKey] } }) @@ -744,9 +560,6 @@ export const createNodesForContentType = ({ node_locale: locale.code, } - // The content of an entry is guaranteed to be updated if and only if the .sys.updatedAt field changed - entryNode.internal.contentDigest = entryItem.sys.updatedAt - // Link tags if (pluginConfig.get(`enableTags`)) { entryNode.metadata = { @@ -816,7 +629,10 @@ export const createAssetNodes = ({ 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 sys: { type: assetItem.sys.type, }, diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index e772527f1b0c0..edeea3f6aa5e8 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -4,7 +4,7 @@ import _ from "lodash" import { downloadContentfulAssets } from "./download-contentful-assets" import { fetchContent } from "./fetch" -import { generateSchemas } from "./generate-schema" +import { generateSchema } from "./generate-schema" import { buildEntryList, buildForeignReferenceMap, @@ -188,7 +188,7 @@ export async function sourceNodes( processingActivity.start() // Generate schemas based on Contentful content model - generateSchemas({ createTypes, schema, pluginConfig, contentTypeItems }) + generateSchema({ createTypes, schema, pluginConfig, contentTypeItems }) // Array of all existing Contentful nodes const existingNodes = getNodes().filter( From 8bfd1a9de40ee3f0da1a2f5e269110670cd94eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 13 Apr 2021 17:08:53 +0200 Subject: [PATCH 013/149] refactor: clean up code --- .../references/content-reference.js | 13 +- .../contentful/src/pages/content-reference.js | 7 +- e2e-tests/contentful/src/pages/rich-text.js | 28 ++- .../src/generate-schema.js | 208 +++++++++--------- .../gatsby-source-contentful/src/rich-text.js | 2 +- 5 files changed, 134 insertions(+), 124 deletions(-) diff --git a/e2e-tests/contentful/src/components/references/content-reference.js b/e2e-tests/contentful/src/components/references/content-reference.js index f32ca3a656dde..d3b0e02d24cf3 100644 --- a/e2e-tests/contentful/src/components/references/content-reference.js +++ b/e2e-tests/contentful/src/components/references/content-reference.js @@ -1,16 +1,7 @@ import React from "react" -export const ContentfulContentReference = ({ - one, - many, - content_reference, - title, -}) => { - const references = [ - one, - ...(many || []), - ...(content_reference || []), - ].filter(Boolean) +export const ContentfulContentReference = ({ one, many, title }) => { + const references = [one, ...(many || [])].filter(Boolean) return (

[ContentfulReference] {title}: [ diff --git a/e2e-tests/contentful/src/pages/content-reference.js b/e2e-tests/contentful/src/pages/content-reference.js index 642722e2a92d6..9dfb892765136 100644 --- a/e2e-tests/contentful/src/pages/content-reference.js +++ b/e2e-tests/contentful/src/pages/content-reference.js @@ -104,13 +104,12 @@ export const pageQuery = graphql` contentful_id one { __typename + contentful_id ... on ContentfulText { - contentful_id title short } ... on ContentfulContentReference { - contentful_id title one { ... on ContentfulText { @@ -138,18 +137,16 @@ export const pageQuery = graphql` } many { __typename + contentful_id ... on ContentfulText { - contentful_id title short } ... on ContentfulNumber { - contentful_id title integer } ... on ContentfulContentReference { - contentful_id title one { ... on ContentfulText { diff --git a/e2e-tests/contentful/src/pages/rich-text.js b/e2e-tests/contentful/src/pages/rich-text.js index b064694b7469b..d9d5b34d0586a 100644 --- a/e2e-tests/contentful/src/pages/rich-text.js +++ b/e2e-tests/contentful/src/pages/rich-text.js @@ -148,34 +148,46 @@ export const pageQuery = graphql` contentful_id title one { + __typename + contentful_id + ... on ContentfulText { + title + short + } ... on ContentfulContentReference { - contentful_id title - content_reference { + one { + ... on ContentfulContentReference { + title + } + } + many { ... on ContentfulContentReference { - contentful_id title } } } } many { + __typename + contentful_id ... on ContentfulText { - contentful_id title short } ... on ContentfulNumber { - contentful_id title integer } ... on ContentfulContentReference { - contentful_id title - content_reference { + one { + ... on ContentfulContentReference { + title + } + } + many { ... on ContentfulContentReference { - id title } } diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index c4544118b4299..141d7fbfeab6f 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -1,9 +1,106 @@ -const fs = require(`fs`) -const { cloneDeep } = require(`lodash`) - import { makeTypeName } from "./normalize" -const types = [] +// Contentful content type schemas +const ContentfulDataTypes = new Map([ + [ + `Symbol`, + () => { + return { type: `String` } + }, + ], + [ + `Text`, + field => { + return { + type: `ContentfulNodeTypeText`, + extensions: { + link: { by: `id`, from: `${field.id}___NODE` }, + }, + } + }, + ], + [ + `Integer`, + () => { + return { type: `Int` } + }, + ], + [ + `Number`, + () => { + return { type: `Float` } + }, + ], + [ + `Date`, + () => { + return { + type: `Date`, + extensions: { + dateformat: {}, + }, + } + }, + ], + [ + `Object`, + () => { + return { type: `JSON` } + }, + ], + [ + `Boolean`, + () => { + return { type: `Boolean` } + }, + ], + [ + `Location`, + () => { + return { type: `ContentfulNodeTypeLocation` } + }, + ], + [ + `RichText`, + () => { + return { type: `ContentfulNodeTypeRichText` } + }, + ], +]) + +const getLinkFieldType = (linkType, field) => { + return { + type: `Contentful${linkType}`, + extensions: { + link: { by: `id`, from: `${field.id}___NODE` }, + }, + } +} + +const translateFieldType = field => { + let fieldType + if (field.type === `Array`) { + // Arrays of Contentful Links or primitive types + const fieldData = + field.items.type === `Link` + ? getLinkFieldType(field.items.linkType, field) + : translateFieldType(field.items) + + fieldType = { ...fieldData, type: `[${fieldData.type}]` } + } else if (field.type === `Link`) { + // Contentful Link (reference) field types + fieldType = getLinkFieldType(field.linkType, field) + } else { + // Primitive field types + fieldType = ContentfulDataTypes.get(field.type)(field) + } + + if (field.required) { + fieldType.type = `${fieldType.type}!` + } + + return fieldType +} function generateAssetTypes({ createTypes }) { createTypes(` @@ -16,8 +113,8 @@ function generateAssetTypes({ createTypes }) { contentful_id: String! id: ID! spaceId: String! - createdAt: String! # Date @dateform, - updatedAt: String! # Date @dateform, + createdAt: Date @dateformat + updatedAt: Date @dateformat } `) @@ -58,13 +155,6 @@ export function generateSchema({ pluginConfig, contentTypeItems, }) { - // logger @todo remove it - const origTypes = createTypes - createTypes = (...all) => { - types.push(all) - origTypes(...all) - } - createTypes(` interface ContentfulInternalReference implements Node { contentful_id: String! @@ -140,11 +230,9 @@ export function generateSchema({ const v = obj[k] if (v && v.sys && v.sys.type === `Link`) { if (v.sys.linkType === `Asset`) { - console.log(`adding asset`, v) referencedAssets.add(v.sys.id) } if (v.sys.linkType === `Entry`) { - console.log(`adding entry`, v) referencedEntries.add(v.sys.id) } } else if (v && typeof v === `object`) { @@ -182,7 +270,7 @@ export function generateSchema({ }) ) - // Is there a way to have this as string and let transformer-remark replace it with an object? + // @todo Is there a way to have this as string and let transformer-remark replace it with an object? createTypes( schema.buildObjectType({ name: `ContentfulNodeTypeText`, @@ -196,79 +284,6 @@ export function generateSchema({ }) ) - // Contentful content type schemas - const ContentfulDataTypes = new Map([ - [`Symbol`, `String`], - [ - `Text`, - { - type: `ContentfulNodeTypeText`, - extensions: { - link: { by: `id` }, - }, - }, - ], - [`Integer`, `Int`], - [`Number`, `Float`], - [ - `Date`, - { - type: `Date`, - extensions: { - dateformat: {}, - }, - }, - ], - [`Object`, `JSON`], - [`Boolean`, `Boolean`], - [`Location`, `ContentfulNodeTypeLocation`], - [`RichText`, `ContentfulNodeTypeRichText`], - ]) - - const getLinkFieldType = linkType => { - return { - type: `Contentful${linkType}`, - extensions: { - link: { by: `id` }, - }, - } - } - - const translateFieldType = field => { - let id - if (field.type === `Array`) { - const fieldData = - field.items.type === `Link` - ? getLinkFieldType(field.items.linkType) - : translateFieldType(field.items) - - id = - typeof fieldData === `string` - ? `[${fieldData}]` - : { ...fieldData, type: `[${fieldData.type}]` } - } else if (field.type === `Link`) { - id = getLinkFieldType(field.linkType) - } else { - id = ContentfulDataTypes.get(field.type) - } - - if (typeof id === `string`) { - return [id, field.required && `!`].filter(Boolean).join(``) - } - - id = cloneDeep(id) - - if (field.required) { - id.type = `${id.type}!` - } - - if (id?.extensions?.link) { - id.extensions.link.from = `${field.id}___NODE` - } - - return id - } - for (const contentTypeItem of contentTypeItems) { try { const fields = {} @@ -276,8 +291,7 @@ export function generateSchema({ if (field.disabled || field.omitted) { return } - const type = translateFieldType(field) - fields[field.id] = typeof type === `string` ? { type } : type + fields[field.id] = translateFieldType(field) }) const type = pluginConfig.get(`useNameForId`) @@ -294,8 +308,8 @@ export function generateSchema({ node_locale: { type: `String!` }, // @todo these should be real dates and in sys spaceId: { type: `String!` }, - createdAt: { type: `String!` }, // { type: `Date`, extensions: { dateform: {} } }, - updatedAt: { type: `String!` }, // { type: `Date`, extensions: { dateform: {} } }, + createdAt: { type: `Date`, extensions: { dateformat: {} } }, + updatedAt: { type: `Date`, extensions: { dateformat: {} } }, // @todo add metadata sys: { type: `ContentfulInternalSys` }, ...fields, @@ -305,19 +319,15 @@ export function generateSchema({ `ContentfulEntry`, `Node`, ], + extensions: { dontInfer: {} }, }) ) } catch (err) { err.message = `Unable to create schema for Contentful Content Type ${ contentTypeItem.name || contentTypeItem.sys.id }:\n${err.message}` + console.log(err.stack) throw err } } - - fs.writeFileSync( - process.cwd() + `/generated-types.json`, - JSON.stringify(types, null, 2) - ) - createTypes = origTypes } diff --git a/packages/gatsby-source-contentful/src/rich-text.js b/packages/gatsby-source-contentful/src/rich-text.js index bed7d4ca7b6fd..662914b6013f3 100644 --- a/packages/gatsby-source-contentful/src/rich-text.js +++ b/packages/gatsby-source-contentful/src/rich-text.js @@ -3,7 +3,7 @@ import { documentToReactComponents } from "@contentful/rich-text-react-renderer" import resolveResponse from "contentful-resolve-response" export function renderRichText({ raw, references }, options = {}) { - const richText = JSON.parse(raw) + const richText = raw // If no references are given, there is no need to resolve them if (!references || !references.length) { From 1fcdb65d9f226d023ef601e42c0df9bec4adc5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 29 Apr 2021 12:31:37 +0200 Subject: [PATCH 014/149] refactor: reintroduce contentful sys common resource attribute #31007 --- .../src/components/references/text.js | 2 +- e2e-tests/contentful/src/pages/boolean.js | 21 +- .../contentful/src/pages/content-reference.js | 79 +++- e2e-tests/contentful/src/pages/date.js | 12 +- .../src/pages/gatsby-plugin-image.js | 28 +- e2e-tests/contentful/src/pages/json.js | 24 +- e2e-tests/contentful/src/pages/location.js | 21 +- .../contentful/src/pages/media-reference.js | 39 +- e2e-tests/contentful/src/pages/number.js | 21 +- e2e-tests/contentful/src/pages/rich-text.js | 26 +- e2e-tests/contentful/src/pages/text.js | 35 +- .../gatsby-source-contentful/package.json | 1 + .../__snapshots__/gatsby-node.js.snap | 404 +++++++++++++++++- .../__tests__/download-contentful-assets.js | 40 +- .../src/__tests__/gatsby-node.js | 10 +- .../src/__tests__/normalize.js | 26 +- .../src/__tests__/rich-text.js | 24 +- .../gatsby-source-contentful/src/config.js | 12 + .../src/download-contentful-assets.js | 5 +- .../src/generate-schema.js | 58 ++- .../gatsby-source-contentful/src/normalize.js | 128 +++--- .../gatsby-source-contentful/src/rich-text.js | 4 +- .../src/source-nodes.js | 32 +- 23 files changed, 725 insertions(+), 327 deletions(-) create mode 100644 packages/gatsby-source-contentful/src/config.js 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 ead492f1fb965..d75e0761cfafc 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.16.0-next.0", "gatsby-plugin-utils": "^3.10.0-next.0", 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, }) ) } From 4c843b93ff51b4bb562a53d58e9e8a09b0a93db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 5 May 2021 17:47:27 +0200 Subject: [PATCH 015/149] refactor: align Rich Text field structure to Contentful GraphQL API (#31122) --- e2e-tests/contentful/src/pages/rich-text.js | 122 +- .../gatsby-source-contentful/package.json | 1 + .../src/__tests__/rich-text.js | 191 +- .../src/generate-schema.js | 129 +- .../gatsby-source-contentful/src/rich-text.js | 78 +- yarn.lock | 2552 ++++++++++------- 6 files changed, 1794 insertions(+), 1279 deletions(-) diff --git a/e2e-tests/contentful/src/pages/rich-text.js b/e2e-tests/contentful/src/pages/rich-text.js index 0cd2a3eca6127..12c792bc4eea2 100644 --- a/e2e-tests/contentful/src/pages/rich-text.js +++ b/e2e-tests/contentful/src/pages/rich-text.js @@ -20,13 +20,13 @@ function renderReferencedComponent(ref) { return } -const options = { +const makeOptions = ({ assetBlockMap, entryBlockMap, entryInlineMap }) => ({ renderMark: { [MARKS.BOLD]: text => {text}, }, renderNode: { [BLOCKS.EMBEDDED_ASSET]: node => { - const asset = node.data.target + const asset = assetBlockMap.get(node?.data?.target?.sys.id) if (asset.gatsbyImageData) { return } @@ -40,7 +40,7 @@ const options = { ) }, [BLOCKS.EMBEDDED_ENTRY]: node => { - const entry = node?.data?.target + const entry = entryBlockMap.get(node?.data?.target?.sys.id) if (!entry) { throw new Error( `Entity not available for node:\n${JSON.stringify(node, null, 2)}` @@ -49,7 +49,7 @@ const options = { return renderReferencedComponent(entry) }, [INLINES.EMBEDDED_ENTRY]: node => { - const entry = node.data.target + const entry = entryInlineMap.get(node?.data?.target?.sys.id) if (entry.__typename === "ContentfulText") { return ( @@ -64,7 +64,7 @@ const options = { ) }, }, -} +}) const RichTextPage = ({ data }) => { const defaultEntries = data.default.nodes @@ -77,7 +77,7 @@ const RichTextPage = ({ data }) => { return (

{title}

- {renderRichText(richText, options)} + {renderRichText(richText, makeOptions)}
) @@ -89,7 +89,7 @@ const RichTextPage = ({ data }) => { return (

{title}

- {renderRichText(richTextLocalized, options)} + {renderRichText(richTextLocalized, makeOptions)}
) @@ -101,7 +101,7 @@ const RichTextPage = ({ data }) => { return (

{title}

- {renderRichText(richTextLocalized, options)} + {renderRichText(richTextLocalized, makeOptions)}
) @@ -125,76 +125,92 @@ export const pageQuery = graphql` id title richText { - raw - references { - __typename - sys { - id - } - ... on ContentfulAsset { - contentful_id - gatsbyImageData(width: 200) - } - ... on ContentfulText { - title - short - } - ... on ContentfulLocation { - location { - lat - lon + json + links { + assets { + block { + sys { + id + } + gatsbyImageData(width: 200) } } - ... on ContentfulContentReference { - title - one { + entries { + block { __typename sys { id + type } ... on ContentfulText { title short } + ... on ContentfulLocation { + location { + lat + lon + } + } ... on ContentfulContentReference { title one { + __typename + sys { + id + } + ... on ContentfulText { + title + short + } ... on ContentfulContentReference { title + one { + ... on ContentfulContentReference { + title + } + } + many { + ... on ContentfulContentReference { + title + } + } } } many { + __typename + sys { + id + } + ... on ContentfulText { + title + short + } + ... on ContentfulNumber { + title + integer + } ... on ContentfulContentReference { title + one { + ... on ContentfulContentReference { + title + } + } + many { + ... on ContentfulContentReference { + title + } + } } } } } - many { + inline { __typename sys { id - } - ... on ContentfulText { - title - short - } - ... on ContentfulNumber { - title - integer - } - ... on ContentfulContentReference { - title - one { - ... on ContentfulContentReference { - title - } - } - many { - ... on ContentfulContentReference { - title - } - } + type } } } @@ -213,7 +229,7 @@ export const pageQuery = graphql` id title richTextLocalized { - raw + json } } } @@ -228,7 +244,7 @@ export const pageQuery = graphql` id title richTextLocalized { - raw + json } } } diff --git a/packages/gatsby-source-contentful/package.json b/packages/gatsby-source-contentful/package.json index d75e0761cfafc..1319275ca0623 100644 --- a/packages/gatsby-source-contentful/package.json +++ b/packages/gatsby-source-contentful/package.json @@ -9,6 +9,7 @@ "dependencies": { "@babel/runtime": "^7.15.4", "@contentful/rich-text-react-renderer": "^15.12.1", + "@contentful/rich-text-links": "^15.12.1", "@contentful/rich-text-types": "^15.12.1", "@hapi/joi": "^15.1.1", "@vercel/fetch-retry": "^5.0.3", diff --git a/packages/gatsby-source-contentful/src/__tests__/rich-text.js b/packages/gatsby-source-contentful/src/__tests__/rich-text.js index 54207938a4543..9df80a17a5a7a 100644 --- a/packages/gatsby-source-contentful/src/__tests__/rich-text.js +++ b/packages/gatsby-source-contentful/src/__tests__/rich-text.js @@ -5,12 +5,13 @@ // @ts-check import React from "react" import { render } from "@testing-library/react" -import { renderRichText } from "gatsby-source-contentful/rich-text" +import { renderRichText } from "../rich-text" import { BLOCKS, INLINES } from "@contentful/rich-text-types" +import { getRichTextEntityLinks } from "@contentful/rich-text-links" import { initialSync } from "../__fixtures__/rich-text-data" import { cloneDeep } from "lodash" -const raw = { +const json = { nodeType: `document`, data: {}, content: [ @@ -409,107 +410,129 @@ const raw = { } const fixtures = initialSync().currentSyncData +const fixturesEntriesMap = new Map() +const fixturesAssetsMap = new Map() -const references = [ - ...fixtures.entries.map(entity => { - return { - sys: entity.sys, - __typename: `ContentfulContent`, - ...entity.fields, - } - }), - ...fixtures.assets.map(entity => { - return { - sys: entity.sys, - __typename: `ContentfulAsset`, - ...entity.fields, - } - }), -] +fixtures.entries.forEach(entity => + fixturesEntriesMap.set(entity.sys.id, { sys: entity.sys, ...entity.fields }) +) +fixtures.assets.forEach(entity => + fixturesAssetsMap.set(entity.sys.id, { sys: entity.sys, ...entity.fields }) +) + +const links = { + assets: { + block: getRichTextEntityLinks(json, `embedded-asset-block`)[`Asset`].map( + entity => fixturesAssetsMap.get(entity.id) + ), + hyperlink: getRichTextEntityLinks(json, `asset-hyperlink`)[`Asset`].map( + entity => fixturesAssetsMap.get(entity.id) + ), + }, + entries: { + inline: getRichTextEntityLinks(json, `embedded-entry-inline`)[`Entry`].map( + entity => fixturesEntriesMap.get(entity.id) + ), + block: getRichTextEntityLinks(json, `embedded-entry-block`)[`Entry`].map( + entity => fixturesEntriesMap.get(entity.id) + ), + hyperlink: getRichTextEntityLinks(json, `entry-hyperlink`)[`Entry`].map( + entity => fixturesEntriesMap.get(entity.id) + ), + }, +} describe(`rich text`, () => { test(`renders with default options`, () => { const { container } = render( - <> - {renderRichText({ - raw: cloneDeep(raw), - references: cloneDeep(references), - })} - + <>{renderRichText({ json: cloneDeep(json), links: cloneDeep(links) })} ) expect(container).toMatchSnapshot() }) test(`renders with custom options`, () => { - const options = { - renderNode: { - [INLINES.EMBEDDED_ENTRY]: node => { - if (!node.data.target) { - return ( - - Unresolved INLINE ENTRY: {JSON.stringify(node, null, 2)} - - ) - } - return Resolved inline Entry ({node.data.target.sys.id}) - }, - [INLINES.ENTRY_HYPERLINK]: node => { - if (!node.data.target) { - return ( - - Unresolved ENTRY HYPERLINK: {JSON.stringify(node, null, 2)} - - ) - } - return ( - Resolved entry Hyperlink ({node.data.target.sys.id}) - ) - }, - [INLINES.ASSET_HYPERLINK]: node => { - if (!node.data.target) { - return ( - - Unresolved ASSET HYPERLINK: {JSON.stringify(node, null, 2)} - - ) - } - return ( - Resolved asset Hyperlink ({node.data.target.sys.id}) - ) - }, - [BLOCKS.EMBEDDED_ENTRY]: node => { - if (!node.data.target) { + const makeOptions = ({ + assetBlockMap, + assetHyperlinkMap, + entryBlockMap, + entryInlineMap, + entryHyperlinkMap, + }) => { + return { + renderNode: { + [INLINES.EMBEDDED_ENTRY]: node => { + const entry = entryInlineMap.get(node?.data?.target?.sys.id) + if (!entry) { + return ( + + Unresolved INLINE ENTRY:{` `} + {JSON.stringify({ node, entryInlineMap }, null, 2)} + + ) + } + return Resolved inline Entry ({entry.sys.id}) + }, + [INLINES.ENTRY_HYPERLINK]: node => { + const entry = entryHyperlinkMap.get(node?.data?.target?.sys.id) + if (!entry) { + return ( + + Unresolved ENTRY HYPERLINK: {JSON.stringify(node, null, 2)} + + ) + } + return Resolved entry Hyperlink ({entry.sys.id}) + }, + [INLINES.ASSET_HYPERLINK]: node => { + const entry = assetHyperlinkMap.get(node?.data?.target?.sys.id) + if (!entry) { + return ( + + Unresolved ASSET HYPERLINK: {JSON.stringify(node, null, 2)} + + ) + } + return Resolved asset Hyperlink ({entry.sys.id}) + }, + [BLOCKS.EMBEDDED_ENTRY]: node => { + const entry = entryBlockMap.get(node?.data?.target?.sys.id) + if (!entry) { + return ( +
+ Unresolved ENTRY !!!!": {JSON.stringify(node, null, 2)} +
+ ) + } return ( -
Unresolved ENTRY !!!!": {JSON.stringify(node, null, 2)}
+

+ Resolved embedded Entry: {entry.title[`en-US`]} ({entry.sys.id}) +

) - } - return ( -

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

- ) - }, - [BLOCKS.EMBEDDED_ASSET]: node => { - if (!node.data.target) { + }, + [BLOCKS.EMBEDDED_ASSET]: node => { + const entry = assetBlockMap.get(node?.data?.target?.sys.id) + if (!entry) { + return ( +
+ Unresolved ASSET !!!!": {JSON.stringify(node, null, 2)} +
+ ) + } return ( -
Unresolved ASSET !!!!": {JSON.stringify(node, null, 2)}
+

+ Resolved embedded Asset: {entry.title[`en-US`]} ({entry.sys.id}) +

) - } - return ( -

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

- ) + }, }, - }, + } } + const { container } = render( <> {renderRichText( - { raw: cloneDeep(raw), references: cloneDeep(references) }, - options + { json: cloneDeep(json), links: cloneDeep(links) }, + makeOptions )} ) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index a10bc19538cae..b55d701cf99e3 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -1,3 +1,5 @@ +import { getRichTextEntityLinks } from "@contentful/rich-text-links" + import { makeTypeName } from "./normalize" // Contentful content type schemas @@ -143,6 +145,7 @@ export function generateSchema({ pluginConfig, contentTypeItems, }) { + // Generic Types createTypes(` interface ContentfulInternalReference implements Node { id: ID! @@ -180,8 +183,29 @@ export function generateSchema({ } `) + // Assets generateAssetTypes({ createTypes }) + // Rich Text + const makeRichTextLinksResolver = (nodeType, entityType) => ( + source, + args, + context + ) => { + const links = getRichTextEntityLinks(source, nodeType)[entityType].map( + ({ id }) => id + ) + + return context.nodeModel.getAllNodes().filter( + node => + node.internal.owner === `gatsby-source-contentful` && + node?.sys?.id && + node?.sys?.type === entityType && + links.includes(node.sys.id) + // @todo how can we check for correct space and environment? We need to access the sys field of the fields parent entry. + ) + } + // Contentful specific types if (pluginConfig.get(`enableTags`)) { createTypes( @@ -198,56 +222,76 @@ export function generateSchema({ ) } + createTypes( + schema.buildObjectType({ + name: `ContentfulNodeTypeRichTextAssets`, + fields: { + block: { + type: `[ContentfulAsset]!`, + resolve: makeRichTextLinksResolver(`embedded-asset-block`, `Asset`), + }, + hyperlink: { + type: `[ContentfulAsset]!`, + resolve: makeRichTextLinksResolver(`asset-hyperlink`, `Asset`), + }, + }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulNodeTypeRichTextEntries`, + fields: { + inline: { + type: `[ContentfulEntry]!`, + resolve: makeRichTextLinksResolver(`embedded-entry-inline`, `Entry`), + }, + block: { + type: `[ContentfulEntry]!`, + resolve: makeRichTextLinksResolver(`embedded-entry-block`, `Entry`), + }, + hyperlink: { + type: `[ContentfulEntry]!`, + resolve: makeRichTextLinksResolver(`entry-hyperlink`, `Entry`), + }, + }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulNodeTypeRichTextLinks`, + fields: { + assets: { + type: `ContentfulNodeTypeRichTextAssets`, + resolve(source) { + return source + }, + }, + entries: { + type: `ContentfulNodeTypeRichTextEntries`, + resolve(source) { + return source + }, + }, + }, + }) + ) + createTypes( schema.buildObjectType({ name: `ContentfulNodeTypeRichText`, fields: { - raw: { + json: { type: `JSON`, resolve(source) { return source }, }, - references: { - type: `[ContentfulInternalReference]`, - resolve(source, args, context) { - const referencedEntries = new Set() - const referencedAssets = new Set() - - // Locate all Contentful Links within the rich text data - // Traverse logic based on https://github.com/contentful/contentful-resolve-response - const traverse = obj => { - // eslint-disable-next-line guard-for-in - for (const k in obj) { - const v = obj[k] - if (v && v.sys && v.sys.type === `Link`) { - if (v.sys.linkType === `Asset`) { - referencedAssets.add(v.sys.id) - } - if (v.sys.linkType === `Entry`) { - referencedEntries.add(v.sys.id) - } - } else if (v && typeof v === `object`) { - traverse(v) - } - } - } - traverse(source) - - // 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) - }) + links: { + type: `ContentfulNodeTypeRichTextLinks`, + resolve(source) { + return source }, }, }, @@ -255,6 +299,7 @@ export function generateSchema({ }) ) + // Location createTypes( schema.buildObjectType({ name: `ContentfulNodeTypeLocation`, @@ -268,6 +313,7 @@ export function generateSchema({ }) ) + // Text // @todo Is there a way to have this as string and let transformer-remark replace it with an object? createTypes( schema.buildObjectType({ @@ -282,6 +328,7 @@ export function generateSchema({ }) ) + // Content types for (const contentTypeItem of contentTypeItems) { try { const fields = {} diff --git a/packages/gatsby-source-contentful/src/rich-text.js b/packages/gatsby-source-contentful/src/rich-text.js index 45e8753193aea..0019e715e59fc 100644 --- a/packages/gatsby-source-contentful/src/rich-text.js +++ b/packages/gatsby-source-contentful/src/rich-text.js @@ -1,46 +1,52 @@ // @ts-check import { documentToReactComponents } from "@contentful/rich-text-react-renderer" -import resolveResponse from "contentful-resolve-response" -export function renderRichText({ raw, references }, options = {}) { - const richText = raw +export function renderRichText({ json, links }, makeOptions = {}) { + const options = + typeof makeOptions === `function` + ? makeOptions(generateLinkMaps(links)) + : makeOptions - // If no references are given, there is no need to resolve them - if (!references || !references.length) { - return documentToReactComponents(richText, options) + return documentToReactComponents(json, options) +} + +exports.renderRichText = renderRichText + +/** + * Helper function to simplify Rich Text rendering. Based on: + * https://www.contentful.com/blog/2021/04/14/rendering-linked-assets-entries-in-contentful/ + */ +function generateLinkMaps(links) { + const assetBlockMap = new Map() + for (const asset of links.assets.block || []) { + assetBlockMap.set(asset.sys.id, asset) } - // Create dummy response so we can use official libraries for resolving the entries - const dummyResponse = { - items: [ - { - sys: { type: `Entry` }, - richText, - }, - ], - includes: { - Entry: references - .filter(({ __typename }) => __typename !== `ContentfulAsset`) - .map(reference => { - return { - ...reference, - sys: { type: `Entry`, id: reference.sys.id }, - } - }), - Asset: references - .filter(({ __typename }) => __typename === `ContentfulAsset`) - .map(reference => { - return { - ...reference, - sys: { type: `Asset`, id: reference.sys.id }, - } - }), - }, + const assetHyperlinkMap = new Map() + for (const asset of links.assets.hyperlink || []) { + assetHyperlinkMap.set(asset.sys.id, asset) } - const resolved = resolveResponse(dummyResponse, { - removeUnresolved: true, - }) + const entryBlockMap = new Map() + for (const entry of links.entries.block || []) { + entryBlockMap.set(entry.sys.id, entry) + } - return documentToReactComponents(resolved[0].richText, options) + const entryInlineMap = new Map() + for (const entry of links.entries.inline || []) { + entryInlineMap.set(entry.sys.id, entry) + } + + const entryHyperlinkMap = new Map() + for (const entry of links.entries.hyperlink || []) { + entryHyperlinkMap.set(entry.sys.id, entry) + } + + return { + assetBlockMap, + assetHyperlinkMap, + entryBlockMap, + entryInlineMap, + entryHyperlinkMap, + } } diff --git a/yarn.lock b/yarn.lock index 9b4290aed3408..0d2738ca6a900 100644 --- a/yarn.lock +++ b/yarn.lock @@ -107,15 +107,16 @@ "@algolia/requester-common" "4.9.1" "@ampproject/remapping@^2.1.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" - integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== + version "2.2.0" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d" + integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w== dependencies: - "@jridgewell/trace-mapping" "^0.3.0" + "@jridgewell/gen-mapping" "^0.1.0" + "@jridgewell/trace-mapping" "^0.3.9" "@apollo/client@^3.5.10": version "3.5.10" - resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.5.10.tgz#43463108a6e07ae602cca0afc420805a19339a71" + resolved "https://registry.npmjs.org/@apollo/client/-/client-3.5.10.tgz#43463108a6e07ae602cca0afc420805a19339a71" integrity sha512-tL3iSpFe9Oldq7gYikZK1dcYxp1c01nlSwtsMz75382HcI6fvQXyFXUCJTTK3wgO2/ckaBvRGw7VqjFREdVoRw== dependencies: "@graphql-typed-document-node/core" "^3.0.0" @@ -176,7 +177,7 @@ "@babel/cli@^7.17.10": version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.17.10.tgz#5ea0bf6298bb78f3b59c7c06954f9bd1c79d5943" + resolved "https://registry.npmjs.org/@babel/cli/-/cli-7.17.10.tgz#5ea0bf6298bb78f3b59c7c06954f9bd1c79d5943" integrity sha512-OygVO1M2J4yPMNOW9pb+I6kFGpQK77HmG44Oz3hg8xQIl5L/2zq+ZohwAdSaqYgVwM0SfmPHZHphH4wR8qzVYw== dependencies: "@jridgewell/trace-mapping" "^0.3.8" @@ -204,19 +205,14 @@ dependencies: "@babel/highlight" "^7.16.7" -"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.15.0": - version "7.15.0" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.15.0.tgz#2dbaf8b85334796cafbb0f5793a90a2fc010b176" - integrity sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA== - -"@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" - integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== +"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.14.7", "@babel/compat-data@^7.15.0", "@babel/compat-data@^7.16.4": + version "7.16.4" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" + integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== "@babel/compat-data@^7.17.10": version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab" integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw== "@babel/core@7.10.5": @@ -285,20 +281,20 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.12.10", "@babel/core@^7.13.16", "@babel/core@^7.14.5", "@babel/core@^7.15.5", "@babel/core@^7.7.2", "@babel/core@^7.7.5": - version "7.15.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.15.5.tgz#f8ed9ace730722544609f90c9bb49162dc3bf5b9" - integrity sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg== +"@babel/core@^7.1.0", "@babel/core@^7.12.10", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.14.5", "@babel/core@^7.15.5", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.8.0": + version "7.16.7" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf" + integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA== dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" - "@babel/helper-compilation-targets" "^7.15.4" - "@babel/helper-module-transforms" "^7.15.4" - "@babel/helpers" "^7.15.4" - "@babel/parser" "^7.15.5" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.7" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -307,20 +303,20 @@ source-map "^0.5.0" "@babel/core@^7.14.0": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.9.tgz#6bae81a06d95f4d0dec5bb9d74bbc1f58babdcfe" - integrity sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.17.12.tgz#b4eb2d7ebc3449b062381644c93050db545b70ee" + integrity sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.9" - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-module-transforms" "^7.17.7" + "@babel/generator" "^7.17.12" + "@babel/helper-compilation-targets" "^7.17.10" + "@babel/helper-module-transforms" "^7.17.12" "@babel/helpers" "^7.17.9" - "@babel/parser" "^7.17.9" + "@babel/parser" "^7.17.12" "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.9" - "@babel/types" "^7.17.0" + "@babel/traverse" "^7.17.12" + "@babel/types" "^7.17.12" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -329,7 +325,7 @@ "@babel/core@^7.18.0": version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.0.tgz#c58d04d7c6fbfb58ea7681e2b9145cfb62726756" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.0.tgz#c58d04d7c6fbfb58ea7681e2b9145cfb62726756" integrity sha512-Xyw74OlJwDijToNi0+6BBI5mLLR5+5R3bcSH80LXzjzEGEUlvNzujEE71BaD/ApEZHAvFI/Mlmp4M5lIkdeeWw== dependencies: "@ampproject/remapping" "^2.1.0" @@ -373,36 +369,43 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.10.5", "@babel/generator@^7.12.1", "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.15.4", "@babel/generator@^7.16.8", "@babel/generator@^7.17.3", "@babel/generator@^7.7.2": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.3.tgz#a2c30b0c4f89858cb87050c3ffdfd36bdf443200" - integrity sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg== +"@babel/generator@^7.10.5", "@babel/generator@^7.12.1", "@babel/generator@^7.12.11", "@babel/generator@^7.12.5", "@babel/generator@^7.15.4", "@babel/generator@^7.16.7", "@babel/generator@^7.16.8", "@babel/generator@^7.7.2": + version "7.16.8" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz#359d44d966b8cd059d543250ce79596f792f2ebe" + integrity sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw== dependencies: - "@babel/types" "^7.17.0" + "@babel/types" "^7.16.8" jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.14.0", "@babel/generator@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.9.tgz#f4af9fd38fa8de143c29fce3f71852406fc1e2fc" - integrity sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ== +"@babel/generator@^7.14.0", "@babel/generator@^7.17.12": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.17.12.tgz#5970e6160e9be0428e02f4aba62d8551ec366cc8" + integrity sha512-V49KtZiiiLjH/CnIW6OjJdrenrGoyh6AmKQ3k2AZFKozC1h846Q4NYlZ5nqAigPDUXfGzC88+LOUuG8yKd2kCw== dependencies: - "@babel/types" "^7.17.0" + "@babel/types" "^7.17.12" + "@jridgewell/gen-mapping" "^0.3.0" jsesc "^2.5.1" - source-map "^0.5.0" "@babel/generator@^7.18.0": version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.0.tgz#46d28e8a18fc737b028efb25ab105d74473af43f" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.18.0.tgz#46d28e8a18fc737b028efb25ab105d74473af43f" integrity sha512-81YO9gGx6voPXlvYdZBliFXAZU8vZ9AZ6z+CjlmcnaeOcYSFbMTpdeDUO9xD9dh/68Vq03I8ZspfUTPfitcDHg== dependencies: "@babel/types" "^7.18.0" "@jridgewell/gen-mapping" "^0.3.0" jsesc "^2.5.1" -"@babel/helper-annotate-as-pure@^7.14.5", "@babel/helper-annotate-as-pure@^7.15.4", "@babel/helper-annotate-as-pure@^7.16.7": +"@babel/helper-annotate-as-pure@^7.14.5", "@babel/helper-annotate-as-pure@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz#3d0e43b00c5e49fdb6c57e421601a7a658d5f835" + integrity sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-annotate-as-pure@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== dependencies: "@babel/types" "^7.16.7" @@ -415,29 +418,19 @@ "@babel/helper-explode-assignable-expression" "^7.14.5" "@babel/types" "^7.14.5" -"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz#cf6d94f30fbefc139123e27dd6b02f65aeedb7b9" - integrity sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ== - dependencies: - "@babel/compat-data" "^7.15.0" - "@babel/helper-validator-option" "^7.14.5" - browserslist "^4.16.6" - semver "^6.3.0" - -"@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" - integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== +"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.14.5", "@babel/helper-compilation-targets@^7.15.4", "@babel/helper-compilation-targets@^7.16.7": + version "7.16.7" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz#06e66c5f299601e6c7da350049315e83209d551b" + integrity sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA== dependencies: - "@babel/compat-data" "^7.17.7" + "@babel/compat-data" "^7.16.4" "@babel/helper-validator-option" "^7.16.7" browserslist "^4.17.5" semver "^6.3.0" "@babel/helper-compilation-targets@^7.17.10": version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz#09c63106d47af93cf31803db6bc49fef354e2ebe" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz#09c63106d47af93cf31803db6bc49fef354e2ebe" integrity sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ== dependencies: "@babel/compat-data" "^7.17.10" @@ -445,15 +438,40 @@ browserslist "^4.20.2" semver "^6.3.0" -"@babel/helper-create-class-features-plugin@^7.12.1", "@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.15.4", "@babel/helper-create-class-features-plugin@^7.16.7": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9" - integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg== +"@babel/helper-create-class-features-plugin@^7.12.1", "@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz#7f977c17bd12a5fba363cb19bea090394bf37d2e" + integrity sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.15.4" + "@babel/helper-function-name" "^7.15.4" + "@babel/helper-member-expression-to-functions" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/helper-replace-supers" "^7.15.4" + "@babel/helper-split-export-declaration" "^7.15.4" + +"@babel/helper-create-class-features-plugin@^7.16.7": + version "7.17.9" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz#71835d7fb9f38bd9f1378e40a4c0902fdc2ea49d" + integrity sha512-kUjip3gruz6AJKOq5i3nC6CoCEEF/oHH3cp6tOZhB+IyyyPyW0g1Gfsxn3mkk6S08pIA2y8GQh609v9G/5sHVQ== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-function-name" "^7.17.9" + "@babel/helper-member-expression-to-functions" "^7.17.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + +"@babel/helper-create-class-features-plugin@^7.17.12": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.12.tgz#d4f8393fc4838cbff6b7c199af5229aee16d07cf" + integrity sha512-sZoOeUTkFJMyhqCei2+Z+wtH/BehW8NVKQt7IRUQlRiOARuXymJYfN/FCcI8CvVbR0XVyDM6eLFOlR7YtiXnew== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.17.9" + "@babel/helper-member-expression-to-functions" "^7.17.7" "@babel/helper-optimise-call-expression" "^7.16.7" "@babel/helper-replace-supers" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" @@ -482,7 +500,7 @@ "@babel/helper-environment-visitor@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== dependencies: "@babel/types" "^7.16.7" @@ -503,7 +521,7 @@ "@babel/helper-function-name@^7.14.5", "@babel/helper-function-name@^7.15.4", "@babel/helper-function-name@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== dependencies: "@babel/helper-get-function-arity" "^7.16.7" @@ -512,7 +530,7 @@ "@babel/helper-function-name@^7.17.9": version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== dependencies: "@babel/template" "^7.16.7" @@ -520,57 +538,57 @@ "@babel/helper-get-function-arity@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== dependencies: "@babel/types" "^7.16.7" "@babel/helper-hoist-variables@^7.15.4", "@babel/helper-hoist-variables@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== dependencies: "@babel/types" "^7.16.7" -"@babel/helper-member-expression-to-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz#42b9ca4b2b200123c3b7e726b0ae5153924905b0" - integrity sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q== - dependencies: - "@babel/types" "^7.16.7" - -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.0.0-beta.49", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.15.4": +"@babel/helper-member-expression-to-functions@^7.15.4": version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz#e18007d230632dea19b47853b984476e7b4e103f" - integrity sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA== + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz#bfd34dc9bba9824a4658b0317ec2fd571a51e6ef" + integrity sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA== dependencies: "@babel/types" "^7.15.4" -"@babel/helper-module-imports@^7.16.7": +"@babel/helper-member-expression-to-functions@^7.16.7", "@babel/helper-member-expression-to-functions@^7.17.7": + version "7.17.7" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" + integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== + dependencies: + "@babel/types" "^7.17.0" + +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.0.0-beta.49", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.14.5", "@babel/helper-module-imports@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== dependencies: "@babel/types" "^7.16.7" -"@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz#962cc629a7f7f9a082dd62d0307fa75fe8788d7c" - integrity sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw== +"@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.12.1", "@babel/helper-module-transforms@^7.14.5", "@babel/helper-module-transforms@^7.15.4", "@babel/helper-module-transforms@^7.16.7": + version "7.16.7" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz#7665faeb721a01ca5327ddc6bba15a5cb34b6a41" + integrity sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng== dependencies: - "@babel/helper-module-imports" "^7.15.4" - "@babel/helper-replace-supers" "^7.15.4" - "@babel/helper-simple-access" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/helper-validator-identifier" "^7.14.9" - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" -"@babel/helper-module-transforms@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" - integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== +"@babel/helper-module-transforms@^7.17.12": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz#bec00139520cb3feb078ef7a4578562480efb77e" + integrity sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA== dependencies: "@babel/helper-environment-visitor" "^7.16.7" "@babel/helper-module-imports" "^7.16.7" @@ -578,12 +596,12 @@ "@babel/helper-split-export-declaration" "^7.16.7" "@babel/helper-validator-identifier" "^7.16.7" "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" + "@babel/traverse" "^7.17.12" + "@babel/types" "^7.17.12" "@babel/helper-module-transforms@^7.18.0": version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz#baf05dec7a5875fb9235bd34ca18bad4e21221cd" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz#baf05dec7a5875fb9235bd34ca18bad4e21221cd" integrity sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA== dependencies: "@babel/helper-environment-visitor" "^7.16.7" @@ -595,9 +613,16 @@ "@babel/traverse" "^7.18.0" "@babel/types" "^7.18.0" -"@babel/helper-optimise-call-expression@^7.15.4", "@babel/helper-optimise-call-expression@^7.16.7": +"@babel/helper-optimise-call-expression@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz#f310a5121a3b9cc52d9ab19122bd729822dee171" + integrity sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw== + dependencies: + "@babel/types" "^7.15.4" + +"@babel/helper-optimise-call-expression@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== dependencies: "@babel/types" "^7.16.7" @@ -619,6 +644,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== +"@babel/helper-plugin-utils@^7.17.12": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz#86c2347da5acbf5583ba0a10aed4c9bf9da9cf96" + integrity sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA== + "@babel/helper-remap-async-to-generator@^7.14.5", "@babel/helper-remap-async-to-generator@^7.15.4": version "7.15.4" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz#2637c0731e4c90fbf58ac58b50b2b5a192fc970f" @@ -628,9 +658,19 @@ "@babel/helper-wrap-function" "^7.15.4" "@babel/types" "^7.15.4" -"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.4", "@babel/helper-replace-supers@^7.16.7": +"@babel/helper-replace-supers@^7.14.5", "@babel/helper-replace-supers@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz#52a8ab26ba918c7f6dee28628b07071ac7b7347a" + integrity sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.15.4" + "@babel/helper-optimise-call-expression" "^7.15.4" + "@babel/traverse" "^7.15.4" + "@babel/types" "^7.15.4" + +"@babel/helper-replace-supers@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== dependencies: "@babel/helper-environment-visitor" "^7.16.7" @@ -639,16 +679,16 @@ "@babel/traverse" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/helper-simple-access@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz#ac368905abf1de8e9781434b635d8f8674bcc13b" - integrity sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg== +"@babel/helper-simple-access@^7.15.4", "@babel/helper-simple-access@^7.16.7": + version "7.16.7" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz#d656654b9ea08dbb9659b69d61063ccd343ff0f7" + integrity sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g== dependencies: - "@babel/types" "^7.15.4" + "@babel/types" "^7.16.7" "@babel/helper-simple-access@^7.17.7": version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== dependencies: "@babel/types" "^7.17.0" @@ -662,14 +702,14 @@ "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== dependencies: "@babel/types" "^7.16.0" "@babel/helper-split-export-declaration@^7.15.4", "@babel/helper-split-export-declaration@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== dependencies: "@babel/types" "^7.16.7" @@ -694,7 +734,7 @@ "@babel/helper-validator-option@^7.14.5", "@babel/helper-validator-option@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== "@babel/helper-wrap-function@^7.10.4", "@babel/helper-wrap-function@^7.15.4": @@ -707,18 +747,18 @@ "@babel/traverse" "^7.15.4" "@babel/types" "^7.15.4" -"@babel/helpers@^7.10.4", "@babel/helpers@^7.12.1", "@babel/helpers@^7.12.5", "@babel/helpers@^7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.15.4.tgz#5f40f02050a3027121a3cf48d497c05c555eaf43" - integrity sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ== +"@babel/helpers@^7.10.4", "@babel/helpers@^7.12.1", "@babel/helpers@^7.12.5", "@babel/helpers@^7.16.7": + version "7.16.7" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc" + integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw== dependencies: - "@babel/template" "^7.15.4" - "@babel/traverse" "^7.15.4" - "@babel/types" "^7.15.4" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" "@babel/helpers@^7.17.9": version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.9.tgz#b2af120821bfbe44f9907b1826e168e819375a1a" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz#b2af120821bfbe44f9907b1826e168e819375a1a" integrity sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q== dependencies: "@babel/template" "^7.16.7" @@ -727,7 +767,7 @@ "@babel/helpers@^7.18.0": version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.0.tgz#aff37c3590de42102b54842446146d0205946370" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.0.tgz#aff37c3590de42102b54842446146d0205946370" integrity sha512-AE+HMYhmlMIbho9nbvicHyxFwhrO+xhKB6AhRxzl8w46Yj0VXTZjEsAoBVC7rB2I0jzX+yWyVybnO08qkfx6kg== dependencies: "@babel/template" "^7.16.7" @@ -760,19 +800,19 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.3.tgz#a305415ebe7a6c7023b40b5122a0662d928334cd" integrity sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw== -"@babel/parser@^7.1.0", "@babel/parser@^7.10.5", "@babel/parser@^7.12.3", "@babel/parser@^7.12.7", "@babel/parser@^7.13.16", "@babel/parser@^7.15.5", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.3.3", "@babel/parser@^7.7.2": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" - integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== +"@babel/parser@^7.1.0", "@babel/parser@^7.10.5", "@babel/parser@^7.12.3", "@babel/parser@^7.12.7", "@babel/parser@^7.13.16", "@babel/parser@^7.14.7", "@babel/parser@^7.15.5", "@babel/parser@^7.16.10", "@babel/parser@^7.16.7", "@babel/parser@^7.3.3": + version "7.16.12" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.16.12.tgz#9474794f9a650cf5e2f892444227f98e28cdf8b6" + integrity sha512-VfaV15po8RiZssrkPweyvbGVSe4x2y+aciFCgn0n0/SJMR22cwofRV1mtnJQYcSB1wUTaA/X1LnA3es66MCO5A== -"@babel/parser@^7.14.0", "@babel/parser@^7.16.8", "@babel/parser@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.9.tgz#9c94189a6062f0291418ca021077983058e171ef" - integrity sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg== +"@babel/parser@^7.14.0", "@babel/parser@^7.16.8", "@babel/parser@^7.17.12": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.17.12.tgz#36c2ed06944e3691ba82735fc4cf62d12d491a23" + integrity sha512-FLzHmN9V3AJIrWfOpvRlZCeVg/WLdicSnTMsLur6uDj9TT8ymUlG9XxURdW/XvuygK+2CW0poOJABdA4m/YKxA== "@babel/parser@^7.18.0": version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.0.tgz#10a8d4e656bc01128d299a787aa006ce1a91e112" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz#10a8d4e656bc01128d299a787aa006ce1a91e112" integrity sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg== "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.15.4": @@ -802,12 +842,12 @@ "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-proposal-class-properties@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" - integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz#84f65c0cc247d46f40a6da99aadd6438315d80a4" + integrity sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.17.12" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-proposal-class-properties@^7.12.1", "@babel/plugin-proposal-class-properties@^7.13.0", "@babel/plugin-proposal-class-properties@^7.14.0", "@babel/plugin-proposal-class-properties@^7.14.5": version "7.14.5" @@ -935,15 +975,15 @@ "@babel/plugin-transform-parameters" "^7.12.1" "@babel/plugin-proposal-object-rest-spread@^7.0.0": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz#d9eb649a54628a51701aef7e0ea3d17e2b9dd390" - integrity sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.12.tgz#f94a91715a7f2f8cfb3c06af820c776440bc0148" + integrity sha512-6l9cO3YXXRh4yPCPRA776ZyJ3RobG4ZKJZhp7NDRbKIOeV3dBPG8FXCF7ZtiO2RTCIOkQOph1xDDcc01iWVNjQ== dependencies: - "@babel/compat-data" "^7.17.0" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/compat-data" "^7.17.10" + "@babel/helper-compilation-targets" "^7.17.10" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.16.7" + "@babel/plugin-transform-parameters" "^7.17.12" "@babel/plugin-proposal-object-rest-spread@^7.14.7": version "7.14.7" @@ -1078,12 +1118,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.16.7.tgz#202b147e5892b8452bbb0bb269c7ed2539ab8832" - integrity sha512-UDo3YGQO0jH6ytzVwgSLv9i/CzMcUjbKenL67dTrAZPPv6GFAtDhe6jqnvmoKzC/7htNTohhos+onPtDMqJwaQ== +"@babel/plugin-syntax-flow@^7.0.0", "@babel/plugin-syntax-flow@^7.17.12": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.17.12.tgz#23d852902acd19f42923fca9d0f196984d124e73" + integrity sha512-B8QIgBvkIG6G2jgsOHQUist7Sm0EBLDCx8sen072IwqNuzMegZNXrYnSv77cYzA8mLDZAfQYqsLIhimiP1s2HQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-flow@^7.14.5": version "7.14.5" @@ -1134,12 +1174,12 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" - integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== +"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.17.12": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.17.12.tgz#834035b45061983a491f60096f61a2e7c5674a47" + integrity sha512-spyY3E3AURfxh/RHtjx5j6hs8am5NbUBGfcZ2vB3uShSpZdQyXSf5rR5Mk76vbtlAZOelyVQ71Fg0x9SG4fsog== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-syntax-jsx@^7.12.1", "@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.14.0", "@babel/plugin-syntax-jsx@^7.14.5", "@babel/plugin-syntax-jsx@^7.2.0": version "7.14.5" @@ -1218,19 +1258,19 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.14.0", "@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.7.2": +"@babel/plugin-syntax-typescript@^7.14.0", "@babel/plugin-syntax-typescript@^7.14.5", "@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.7.2": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== dependencies: "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-transform-arrow-functions@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" - integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz#dddd783b473b1b1537ef46423e3944ff24898c45" + integrity sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-arrow-functions@^7.14.5": version "7.14.5" @@ -1250,7 +1290,7 @@ "@babel/plugin-transform-block-scoped-functions@^7.0.0": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -1263,11 +1303,11 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-block-scoping@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" - integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.17.12.tgz#68fc3c4b3bb7dfd809d97b7ed19a584052a2725c" + integrity sha512-jw8XW/B1i7Lqwqj2CbrViPcZijSxfguBWZP2aN59NHgxUyO/OcO1mfdCxH13QhN5LbWhPkX+f+brKGhZTiqtZQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-block-scoping@^7.15.3": version "7.15.3" @@ -1277,15 +1317,15 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-classes@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" - integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.17.12.tgz#da889e89a4d38375eeb24985218edeab93af4f29" + integrity sha512-cvO7lc7pZat6BsvH6l/EGaI8zpl8paICaoGk+7x7guvtfak/TbIf66nYmJOH13EuG0H+Xx3M+9LQDtSvZFKXKw== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" + "@babel/helper-function-name" "^7.17.9" "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-replace-supers" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" globals "^11.1.0" @@ -1304,11 +1344,11 @@ globals "^11.1.0" "@babel/plugin-transform-computed-properties@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" - integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz#bca616a83679698f3258e892ed422546e531387f" + integrity sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-computed-properties@^7.14.5": version "7.14.5" @@ -1318,11 +1358,11 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-destructuring@^7.0.0": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" - integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.12.tgz#0861d61e75e2401aca30f2570d46dfc85caacf35" + integrity sha512-P8pt0YiKtX5UMUL5Xzsc9Oyij+pJE6JuC+F1k0/brq/OOGs5jDa1If3OY0LRWGvJsJhI+8tsiecL3nJLc0WTlg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-destructuring@^7.14.7": version "7.14.7" @@ -1355,12 +1395,12 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-flow-strip-types@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.16.7.tgz#291fb140c78dabbf87f2427e7c7c332b126964b8" - integrity sha512-mzmCq3cNsDpZZu9FADYYyfZJIOrSONmHcop2XEKPdBNMa4PDC4eEvcOvzZaCNcjKu72v0XQlA5y1g58aLRXdYg== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.17.12.tgz#5e070f99a4152194bd9275de140e83a92966cab3" + integrity sha512-g8cSNt+cHCpG/uunPQELdq/TeV3eg1OLJYwxypwHtAWo9+nErH3lQx9CSO2uI9lF74A0mR0t4KoMjs1snSgnTw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-flow" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" + "@babel/plugin-syntax-flow" "^7.17.12" "@babel/plugin-transform-flow-strip-types@^7.12.10", "@babel/plugin-transform-flow-strip-types@^7.14.5": version "7.14.5" @@ -1371,11 +1411,11 @@ "@babel/plugin-syntax-flow" "^7.14.5" "@babel/plugin-transform-for-of@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" - integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.17.12.tgz#5397c22554ec737a27918e7e7e0e7b679b05f5ec" + integrity sha512-76lTwYaCxw8ldT7tNmye4LLwSoKDbRCBzu6n/DcK/P3FOR29+38CIIaVIZfwol9By8W/QHORYEnYSLuvcQKrsg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-for-of@^7.15.4": version "7.15.4" @@ -1386,7 +1426,7 @@ "@babel/plugin-transform-function-name@^7.0.0": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" + resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== dependencies: "@babel/helper-compilation-targets" "^7.16.7" @@ -1402,11 +1442,11 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-literals@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" - integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz#97131fbc6bbb261487105b4b3edbf9ebf9c830ae" + integrity sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-literals@^7.14.5": version "7.14.5" @@ -1417,7 +1457,7 @@ "@babel/plugin-transform-member-expression-literals@^7.0.0": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" + resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -1439,12 +1479,12 @@ babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-commonjs@^7.0.0": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz#274be1a2087beec0254d4abd4d86e52442e1e5b6" - integrity sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.12.tgz#37691c7404320d007288edd5a2d8600bcef61c34" + integrity sha512-tVPs6MImAJz+DiX8Y1xXEMdTk5Lwxu9jiPjlS+nv5M2A59R7+/d1+9A8C/sbuY0b3QjIxqClkj6KAplEtRvzaA== dependencies: - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.12" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-simple-access" "^7.17.7" babel-plugin-dynamic-import-node "^2.3.3" @@ -1493,7 +1533,7 @@ "@babel/plugin-transform-object-super@^7.0.0": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" + resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -1507,12 +1547,12 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/helper-replace-supers" "^7.14.5" -"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" - integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw== +"@babel/plugin-transform-parameters@^7.0.0", "@babel/plugin-transform-parameters@^7.17.12": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz#eb467cd9586ff5ff115a9880d6fdbd4a846b7766" + integrity sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-parameters@^7.10.4", "@babel/plugin-transform-parameters@^7.12.1", "@babel/plugin-transform-parameters@^7.14.5", "@babel/plugin-transform-parameters@^7.15.4": version "7.15.4" @@ -1523,7 +1563,7 @@ "@babel/plugin-transform-property-literals@^7.0.0": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" + resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -1537,7 +1577,7 @@ "@babel/plugin-transform-react-display-name@^7.0.0": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz#7b6d40d232f4c0f550ea348593db3b21e2404340" integrity sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -1557,15 +1597,15 @@ "@babel/plugin-transform-react-jsx" "^7.14.5" "@babel/plugin-transform-react-jsx@^7.0.0": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.3.tgz#eac1565da176ccb1a715dae0b4609858808008c1" - integrity sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.17.12.tgz#2aa20022709cd6a3f40b45d60603d5f269586dba" + integrity sha512-Lcaw8bxd1DKht3thfD4A12dqo1X16he1Lm8rIv8sTwjAYNInRS1qHa9aJoqvzpscItXvftKDCfaEQzwoVyXpEQ== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-jsx" "^7.16.7" - "@babel/types" "^7.17.0" + "@babel/helper-plugin-utils" "^7.17.12" + "@babel/plugin-syntax-jsx" "^7.17.12" + "@babel/types" "^7.17.12" "@babel/plugin-transform-react-jsx@^7.12.1", "@babel/plugin-transform-react-jsx@^7.12.11", "@babel/plugin-transform-react-jsx@^7.14.5": version "7.14.9" @@ -1614,7 +1654,7 @@ "@babel/plugin-transform-shorthand-properties@^7.0.0": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" + resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -1627,11 +1667,11 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-spread@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" - integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz#c112cad3064299f03ea32afed1d659223935d1f5" + integrity sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" "@babel/plugin-transform-spread@^7.14.6": @@ -1650,11 +1690,11 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-transform-template-literals@^7.0.0": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" - integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA== + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.17.12.tgz#4aec0a18f39dd86c442e1d077746df003e362c6e" + integrity sha512-kAKJ7DX1dSRa2s7WN1xUAuaQmkTpN+uig4wCKWivVXIObqGbVTUlSavHyfI2iZvz89GFAMGm9p2DBJ4Y1Tp0hw== dependencies: - "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-template-literals@^7.14.5": version "7.14.5" @@ -1670,9 +1710,18 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-transform-typescript@^7.15.4", "@babel/plugin-transform-typescript@^7.16.7": +"@babel/plugin-transform-typescript@^7.15.0", "@babel/plugin-transform-typescript@^7.15.4": + version "7.15.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.15.4.tgz#db7a062dcf8be5fc096bc0eeb40a13fbfa1fa251" + integrity sha512-sM1/FEjwYjXvMwu1PJStH11kJ154zd/lpY56NQJ5qH2D0mabMv1CAy/kdvS9RP4Xgfj9fBBA3JiSLdDHgXdzOA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.15.4" + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-syntax-typescript" "^7.14.5" + +"@babel/plugin-transform-typescript@^7.16.7": version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" + resolved "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ== dependencies: "@babel/helper-create-class-features-plugin" "^7.16.7" @@ -1818,9 +1867,18 @@ resolved "https://registry.yarnpkg.com/@babel/preset-stage-0/-/preset-stage-0-7.8.3.tgz#b6a0eca1a3b72e07f9caf58f998e97568028f6f5" integrity sha512-+l6FlG1j73t4wh78W41StbcCz0/9a1/y+vxfnjtHl060kSmcgMfGzK9MEkLvrCOXfhp9RCX+d88sm6rOqxEIEQ== -"@babel/preset-typescript@^7.13.0", "@babel/preset-typescript@^7.15.0", "@babel/preset-typescript@^7.16.7": +"@babel/preset-typescript@^7.13.0", "@babel/preset-typescript@^7.15.0": + version "7.15.0" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.15.0.tgz#e8fca638a1a0f64f14e1119f7fe4500277840945" + integrity sha512-lt0Y/8V3y06Wq/8H/u0WakrqciZ7Fz7mwPDHWUJAXlABL5hiUG42BNlRXiELNjeWjO5rWmnNKlx+yzJvxezHow== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-validator-option" "^7.14.5" + "@babel/plugin-transform-typescript" "^7.15.0" + +"@babel/preset-typescript@^7.16.7": version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" + resolved "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== dependencies: "@babel/helper-plugin-utils" "^7.16.7" @@ -1848,21 +1906,21 @@ "@babel/runtime@^7.0.0": version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz#d19fbf802d01a8cb6cf053a64e472d42c434ba72" integrity sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg== dependencies: regenerator-runtime "^0.13.4" "@babel/runtime@^7.10.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.4", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": - version "7.16.3" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.3.tgz#b86f0db02a04187a3c17caa77de69840165d42d5" - integrity sha512-WBwekcqacdY2e9AF/Q7WLFUWmdJGJTkbjqTjoMDgXkVZ3ZRUvOPsLb5KdwISoQVsbP+DQzVZW4Zhci0DvpbNTQ== + version "7.16.7" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" + integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ== dependencies: regenerator-runtime "^0.13.4" "@babel/runtime@^7.18.0": version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.0.tgz#6d77142a19cb6088f0af662af1ada37a604d34ae" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.0.tgz#6d77142a19cb6088f0af662af1ada37a604d34ae" integrity sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg== dependencies: regenerator-runtime "^0.13.4" @@ -1876,41 +1934,41 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.10.5", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.16.7", "@babel/traverse@^7.7.2": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" - integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== +"@babel/traverse@^7.1.6", "@babel/traverse@^7.10.5", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.9", "@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.16.7", "@babel/traverse@^7.7.2": + version "7.16.10" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.10.tgz#448f940defbe95b5a8029975b051f75993e8239f" + integrity sha512-yzuaYXoRJBGMlBhsMJoUW7G1UmSb/eXr/JHYM/MsOJgavJibLwASijW7oXBdw3NQ6T0bW7Ty5P/VarOs9cHmqw== dependencies: "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" + "@babel/generator" "^7.16.8" "@babel/helper-environment-visitor" "^7.16.7" "@babel/helper-function-name" "^7.16.7" "@babel/helper-hoist-variables" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.3" - "@babel/types" "^7.17.0" + "@babel/parser" "^7.16.10" + "@babel/types" "^7.16.8" debug "^4.1.0" globals "^11.1.0" -"@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.9.tgz#1f9b207435d9ae4a8ed6998b2b82300d83c37a0d" - integrity sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw== +"@babel/traverse@^7.14.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.12", "@babel/traverse@^7.17.9": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.12.tgz#011874d2abbca0ccf1adbe38f6f7a4ff1747599c" + integrity sha512-zULPs+TbCvOkIFd4FrG53xrpxvCBwLIgo6tO0tJorY7YV2IWFxUfS/lXDJbGgfyYt9ery/Gxj2niwttNnB0gIw== dependencies: "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.9" + "@babel/generator" "^7.17.12" "@babel/helper-environment-visitor" "^7.16.7" "@babel/helper-function-name" "^7.17.9" "@babel/helper-hoist-variables" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.9" - "@babel/types" "^7.17.0" + "@babel/parser" "^7.17.12" + "@babel/types" "^7.17.12" debug "^4.1.0" globals "^11.1.0" "@babel/traverse@^7.18.0": version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.0.tgz#0e5ec6db098660b2372dd63d096bf484e32d27ba" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.0.tgz#0e5ec6db098660b2372dd63d096bf484e32d27ba" integrity sha512-oNOO4vaoIQoGjDQ84LgtF/IAlxlyqL4TUuoQ7xLkQETFaHkY1F7yazhB4Kt3VcZGL0ZF/jhrEpnXqUb0M7V3sw== dependencies: "@babel/code-frame" "^7.16.7" @@ -1924,9 +1982,25 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.5", "@babel/types@^7.12.1", "@babel/types@^7.12.7", "@babel/types@^7.14.5", "@babel/types@^7.14.9", "@babel/types@^7.15.4", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": +"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.5", "@babel/types@^7.12.1", "@babel/types@^7.12.7", "@babel/types@^7.14.5", "@babel/types@^7.14.9", "@babel/types@^7.15.4", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.2.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.8.tgz#0ba5da91dd71e0a4e7781a30f22770831062e3c1" + integrity sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@babel/types@^7.16.0", "@babel/types@^7.17.12": + version "7.17.12" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.17.12.tgz#1210690a516489c0200f355d87619157fbbd69a0" + integrity sha512-rH8i29wcZ6x9xjzI5ILHL/yZkbQnCERdHlogKuIb4PUr7do4iT8DPekrTbBLWTnRQm6U0GYABbTMSzijmEqlAg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + to-fast-properties "^2.0.0" + +"@babel/types@^7.17.0": version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== dependencies: "@babel/helper-validator-identifier" "^7.16.7" @@ -1934,7 +2008,7 @@ "@babel/types@^7.18.0": version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.0.tgz#ef523ea349722849cb4bf806e9342ede4d071553" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz#ef523ea349722849cb4bf806e9342ede4d071553" integrity sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw== dependencies: "@babel/helper-validator-identifier" "^7.16.7" @@ -1947,19 +2021,26 @@ "@builder.io/partytown@^0.5.2": version "0.5.4" - resolved "https://registry.yarnpkg.com/@builder.io/partytown/-/partytown-0.5.4.tgz#1a89069978734e132fa4a59414ddb64e4b94fde7" + resolved "https://registry.npmjs.org/@builder.io/partytown/-/partytown-0.5.4.tgz#1a89069978734e132fa4a59414ddb64e4b94fde7" integrity sha512-qnikpQgi30AS01aFlNQV6l8/qdZIcP76mp90ti+u4rucXHsn4afSKivQXApqxvrQG9+Ibv45STyvHizvxef/7A== +"@contentful/rich-text-links@^15.12.1": + version "15.12.1" + resolved "https://registry.npmjs.org/@contentful/rich-text-links/-/rich-text-links-15.12.1.tgz#b4c00a155d0847712a2d981ae4fc4cda841d0b49" + integrity sha512-kfn3lzFJHMH10LNYOh2A0XVDd7wdXnMzmFMnfflzKCbVLGQpLxLGLbzFC4CyeFrItyJpHEp/2FtKeerARakUnA== + dependencies: + "@contentful/rich-text-types" "^15.12.1" + "@contentful/rich-text-react-renderer@^15.12.1": version "15.12.1" - resolved "https://registry.yarnpkg.com/@contentful/rich-text-react-renderer/-/rich-text-react-renderer-15.12.1.tgz#978c335e7ad5284dc6790a6a8c0ec16878b957b0" + resolved "https://registry.npmjs.org/@contentful/rich-text-react-renderer/-/rich-text-react-renderer-15.12.1.tgz#978c335e7ad5284dc6790a6a8c0ec16878b957b0" integrity sha512-bQ69cN51iGBTF3/nYi5MGUaDJ/lnrEXtCUBCxulIZ0fLS/AAEledZTJcEKs+PKeYYgDqiUVDsmx2xZP2QsJJ+Q== dependencies: "@contentful/rich-text-types" "^15.12.1" "@contentful/rich-text-types@^15.12.1": version "15.12.1" - resolved "https://registry.yarnpkg.com/@contentful/rich-text-types/-/rich-text-types-15.12.1.tgz#3b131f03fc55b6001f6eb5f5615aefb22678b3d3" + resolved "https://registry.npmjs.org/@contentful/rich-text-types/-/rich-text-types-15.12.1.tgz#3b131f03fc55b6001f6eb5f5615aefb22678b3d3" integrity sha512-WQJic0fnAbTa8xzO3Z+aVqDmA5+JMNQlATQMVJ40GoOrnM8YoJZsKGf6xX/O6Y6Eq10T1LrpxIOslODFI9qFgg== "@discoveryjs/json-ext@^0.5.0": @@ -2124,7 +2205,7 @@ "@gatsbyjs/potrace@^2.2.0": version "2.2.0" - resolved "https://registry.yarnpkg.com/@gatsbyjs/potrace/-/potrace-2.2.0.tgz#56e88e420c65bb3065caa27772c6acd1c16c4ec4" + resolved "https://registry.npmjs.org/@gatsbyjs/potrace/-/potrace-2.2.0.tgz#56e88e420c65bb3065caa27772c6acd1c16c4ec4" integrity sha512-/RiLVFJA+CIYhceb6XL1kD1GZ5E2JBX38pld0fiGNiNwLl+Bb7TYZR72aQvcs3v+NOrSjbagUiCnIHYmEW4F7w== dependencies: jimp "^0.16.1" @@ -2138,9 +2219,19 @@ prop-types "^15.6.1" react-lifecycles-compat "^3.0.4" -"@gatsbyjs/webpack-hot-middleware@^2.25.2", "@gatsbyjs/webpack-hot-middleware@^2.25.3": +"@gatsbyjs/webpack-hot-middleware@^2.25.2": + version "2.25.2" + resolved "https://registry.yarnpkg.com/@gatsbyjs/webpack-hot-middleware/-/webpack-hot-middleware-2.25.2.tgz#bad1a8bfacc2a0ff4f2c991f8aee488e2f38294a" + integrity sha512-IFxleSfFQlvEXho2sDRa0PM+diTI+6tlb38jeUo/Lsi+mDzyjPte5Cj4aWL6PR8FpKGMl+DYfq1jxNvjH2gqkA== + dependencies: + ansi-html "0.0.7" + html-entities "^2.1.0" + querystring "^0.2.0" + strip-ansi "^6.0.0" + +"@gatsbyjs/webpack-hot-middleware@^2.25.3": version "2.25.3" - resolved "https://registry.yarnpkg.com/@gatsbyjs/webpack-hot-middleware/-/webpack-hot-middleware-2.25.3.tgz#a00c5f526cbe178330b967f7ed6a487751ffd795" + resolved "https://registry.npmjs.org/@gatsbyjs/webpack-hot-middleware/-/webpack-hot-middleware-2.25.3.tgz#a00c5f526cbe178330b967f7ed6a487751ffd795" integrity sha512-ul17OZ8Dlw+ATRbnuU+kwxuAlq9lKbYz/2uBS1FLCdgoPTF1H2heP7HbUbgfMZbfRQNcCG2rMscMnr32ritCDw== dependencies: ansi-html-community "0.0.8" @@ -2159,7 +2250,7 @@ "@graphql-codegen/add@^3.1.1": version "3.1.1" - resolved "https://registry.yarnpkg.com/@graphql-codegen/add/-/add-3.1.1.tgz#e161ff1c7cdf74ce20b32f75f640f9592b9a18ca" + resolved "https://registry.npmjs.org/@graphql-codegen/add/-/add-3.1.1.tgz#e161ff1c7cdf74ce20b32f75f640f9592b9a18ca" integrity sha512-XkVwcqosa0CVBlL1HaQT0gp+EUfhuQE3LzrEpzMQLwchxaj/NPVYtOJL6MUHaYDsHzLqxWrufjfbeB3y2NQgRw== dependencies: "@graphql-codegen/plugin-helpers" "^2.3.2" @@ -2167,7 +2258,7 @@ "@graphql-codegen/core@^2.5.1": version "2.5.1" - resolved "https://registry.yarnpkg.com/@graphql-codegen/core/-/core-2.5.1.tgz#e3d50d3449b8c58b74ea08e97faf656a1b7fc8a1" + resolved "https://registry.npmjs.org/@graphql-codegen/core/-/core-2.5.1.tgz#e3d50d3449b8c58b74ea08e97faf656a1b7fc8a1" integrity sha512-alctBVl2hMnBXDLwkgmnFPrZVIiBDsWJSmxJcM4GKg1PB23+xuov35GE47YAyAhQItE1B1fbYnbb1PtGiDZ4LA== dependencies: "@graphql-codegen/plugin-helpers" "^2.4.1" @@ -2177,7 +2268,7 @@ "@graphql-codegen/plugin-helpers@^2.3.2", "@graphql-codegen/plugin-helpers@^2.4.0", "@graphql-codegen/plugin-helpers@^2.4.1", "@graphql-codegen/plugin-helpers@^2.4.2": version "2.4.2" - resolved "https://registry.yarnpkg.com/@graphql-codegen/plugin-helpers/-/plugin-helpers-2.4.2.tgz#e4f6b74dddcf8a9974fef5ce48562ae0980f9fed" + resolved "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-2.4.2.tgz#e4f6b74dddcf8a9974fef5ce48562ae0980f9fed" integrity sha512-LJNvwAPv/sKtI3RnRDm+nPD+JeOfOuSOS4FFIpQCMUCyMnFcchV/CPTTv7tT12fLUpEg6XjuFfDBvOwndti30Q== dependencies: "@graphql-tools/utils" "^8.5.2" @@ -2189,7 +2280,7 @@ "@graphql-codegen/schema-ast@^2.4.1": version "2.4.1" - resolved "https://registry.yarnpkg.com/@graphql-codegen/schema-ast/-/schema-ast-2.4.1.tgz#ad742b53e32f7a2fbff8ea8a91ba7e617e6ef236" + resolved "https://registry.npmjs.org/@graphql-codegen/schema-ast/-/schema-ast-2.4.1.tgz#ad742b53e32f7a2fbff8ea8a91ba7e617e6ef236" integrity sha512-bIWlKk/ShoVJfghA4Rt1OWnd34/dQmZM/vAe6fu6QKyOh44aAdqPtYQ2dbTyFXoknmu504etKJGEDllYNUJRfg== dependencies: "@graphql-codegen/plugin-helpers" "^2.3.2" @@ -2197,31 +2288,31 @@ tslib "~2.3.0" "@graphql-codegen/typescript-operations@^2.3.5": - version "2.3.5" - resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript-operations/-/typescript-operations-2.3.5.tgz#1e77b96da0949f9e0ecd6054eb28b582936e35e8" - integrity sha512-GCZQW+O+cIF62ioPkQMoSJGzjJhtr7ttZGJOAoN/Q/oolG8ph9jNFePKO67tSQ/POAs5HLqfat4kAlCK8OPV3Q== + version "2.4.0" + resolved "https://registry.npmjs.org/@graphql-codegen/typescript-operations/-/typescript-operations-2.4.0.tgz#07f371bcda31ecb8edc4c742442014b21c11d53b" + integrity sha512-vJ15FLyWchuO2Xkp6uz7jJOdChiay7P9KJKFDILx/JTwjinU1fFa7iOvyeTvslqiUPxgsXthR5izdY+E5IyLkQ== dependencies: "@graphql-codegen/plugin-helpers" "^2.4.0" - "@graphql-codegen/typescript" "^2.4.8" - "@graphql-codegen/visitor-plugin-common" "2.7.4" + "@graphql-codegen/typescript" "^2.4.11" + "@graphql-codegen/visitor-plugin-common" "2.8.0" auto-bind "~4.0.0" - tslib "~2.3.0" + tslib "~2.4.0" -"@graphql-codegen/typescript@^2.4.8": - version "2.4.8" - resolved "https://registry.yarnpkg.com/@graphql-codegen/typescript/-/typescript-2.4.8.tgz#e8110baba9713cde72d57a5c95aa27400363ed9a" - integrity sha512-tVsHIkuyenBany7c5IMU1yi4S1er2hgyXJGNY7PcyhpJMx0eChmbqz1VTiZxDEwi8mDBS2mn3TaSJMh6xuJM5g== +"@graphql-codegen/typescript@^2.4.11", "@graphql-codegen/typescript@^2.4.8": + version "2.4.11" + resolved "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-2.4.11.tgz#b9d8bddaeb79ff4a85e1d0f9c774afba7423177c" + integrity sha512-K3oDLPJRH9Wgpg9TOvb7L+xrJZ8HxkIzV2umqGn54c+8DQjvnRFBIYRO0THgUBMnEauE2sEy6RZkGHGfgQUruA== dependencies: "@graphql-codegen/plugin-helpers" "^2.4.0" "@graphql-codegen/schema-ast" "^2.4.1" - "@graphql-codegen/visitor-plugin-common" "2.7.4" + "@graphql-codegen/visitor-plugin-common" "2.8.0" auto-bind "~4.0.0" - tslib "~2.3.0" + tslib "~2.4.0" -"@graphql-codegen/visitor-plugin-common@2.7.4": - version "2.7.4" - resolved "https://registry.yarnpkg.com/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-2.7.4.tgz#fbc8aec9df0035b8f29fa64a6356cbb02062da5d" - integrity sha512-aaDoEudDD+B7DK/UwDSL2Fzej75N9hNJ3N8FQuTIeDyw6FNGWUxmkjVBLQGlzfnYfK8IYkdfYkrPn3Skq0pVxA== +"@graphql-codegen/visitor-plugin-common@2.8.0": + version "2.8.0" + resolved "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-2.8.0.tgz#f1de3bd5ee123e6f72c06423912a3a83a6044938" + integrity sha512-29MOaxBog7qaEhmeCzJn2mONSbcA+slCTzHN4nJ3aZl4KrC9V32rXlQpG5x0qHbFQ1LaG1f5gPO83xbiAeMBIw== dependencies: "@graphql-codegen/plugin-helpers" "^2.4.0" "@graphql-tools/optimize" "^1.0.1" @@ -2232,42 +2323,65 @@ dependency-graph "^0.11.0" graphql-tag "^2.11.0" parse-filepath "^1.0.2" - tslib "~2.3.0" + tslib "~2.4.0" -"@graphql-tools/batch-execute@8.4.6": - version "8.4.6" - resolved "https://registry.yarnpkg.com/@graphql-tools/batch-execute/-/batch-execute-8.4.6.tgz#6033cbf0b7d30c901ae4a1a7de7501aedf5a6a10" - integrity sha512-8O42fReZMssrA4HCkpK68RlRQz/QAvLfOkz+/6dDX2X7VgZtRx3VvFiJd2hFaGdNbLzklBWXF9E6hJdJGkEO5g== +"@graphql-tools/batch-execute@8.4.4": + version "8.4.4" + resolved "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.4.4.tgz#12bb8b87f27491a0b38e2172f49b6445c2dc5079" + integrity sha512-5B3srfrNh7qqaH4FWysiZXPDVD7snwM+qsW3Bkq8M0iRAZVUb3P9o23xJbBwS32g678TuCjKy113K0PSqHyeCw== dependencies: - "@graphql-tools/utils" "8.6.9" + "@graphql-tools/utils" "8.6.7" dataloader "2.1.0" tslib "~2.3.0" value-or-promise "1.0.11" +"@graphql-tools/batch-execute@8.4.7": + version "8.4.7" + resolved "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.4.7.tgz#199d0ec7fbe6539056fdfd28e015c612926a7932" + integrity sha512-+ZXikTo8kJ1hJAQrT94sUrwmdL8EcvoDz4HULbb4B8hIFw0PPBaGkEaN8u5ylsCLOEoWIQNe1SwHx9yDhlvnJg== + dependencies: + "@graphql-tools/utils" "8.6.10" + dataloader "2.1.0" + tslib "~2.4.0" + value-or-promise "1.0.11" + "@graphql-tools/code-file-loader@^7.2.14": - version "7.2.14" - resolved "https://registry.yarnpkg.com/@graphql-tools/code-file-loader/-/code-file-loader-7.2.14.tgz#b43ce0c682040b3969f1f785b18fc33c79341084" - integrity sha512-ajNET8XO2e3SgIXXAskc/Dv/M/+Z35TgXopf3axt1e9TboG/KkQxIE0Mi84XqCYDMtF5UqmIWqQ2gVdwFPfjiw== + version "7.2.15" + resolved "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-7.2.15.tgz#2307741bec6987c88a1a53695cb17dc59c8ba7a0" + integrity sha512-tqViC0MEXadcGofqDU4mL7eA/+TyM4iCP+XRkL/mdAMYWp1JdzMYUJcCH47ZK1+EvNctYx8sJOpSGlvLR4ZFFg== dependencies: - "@graphql-tools/graphql-tag-pluck" "7.2.6" - "@graphql-tools/utils" "8.6.9" + "@graphql-tools/graphql-tag-pluck" "7.2.7" + "@graphql-tools/utils" "8.6.10" globby "^11.0.3" - tslib "~2.3.0" + tslib "~2.4.0" unixify "^1.0.0" -"@graphql-tools/delegate@8.7.7", "@graphql-tools/delegate@^8.4.2": - version "8.7.7" - resolved "https://registry.yarnpkg.com/@graphql-tools/delegate/-/delegate-8.7.7.tgz#8626e5734eff1643f99b10202bb324c8a4a8c210" - integrity sha512-Yb9UHG+Upm0M+5FgtWipXM0/Q8Vuuh1Ieod7hFDmAwHGHbmwG0YpcS/NMdxrQAZYWnli9EdnSPgDAFnWLFN+ZQ== +"@graphql-tools/delegate@8.7.4": + version "8.7.4" + resolved "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-8.7.4.tgz#388f656f03d2029f13aa8a1877721649d1e305f0" + integrity sha512-OXdIHRqqUDFvBebSZ/MQAvQOJ1Kvl7gjD78ClG4bPts6qDfFHwzlX0V8QESFCo8H67VDRzB4nnqlDyOIzjVNlQ== dependencies: - "@graphql-tools/batch-execute" "8.4.6" - "@graphql-tools/schema" "8.3.10" - "@graphql-tools/utils" "8.6.9" + "@graphql-tools/batch-execute" "8.4.4" + "@graphql-tools/schema" "8.3.8" + "@graphql-tools/utils" "8.6.7" dataloader "2.1.0" graphql-executor "0.0.23" tslib "~2.3.0" value-or-promise "1.0.11" +"@graphql-tools/delegate@8.7.8": + version "8.7.8" + resolved "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-8.7.8.tgz#c7e94d66825286615f738367665aa3036d79eff0" + integrity sha512-QRpk0B0VD+23mC3ePBLM542TvCXbQhdr0V/AmcnpxQLsV27/NA6fDxxN/zjjjs15M5v9/M2DaBT4rwY9NMMlQA== + dependencies: + "@graphql-tools/batch-execute" "8.4.7" + "@graphql-tools/schema" "8.3.11" + "@graphql-tools/utils" "8.6.10" + dataloader "2.1.0" + graphql-executor "0.0.23" + tslib "~2.4.0" + value-or-promise "1.0.11" + "@graphql-tools/delegate@^6.2.4": version "6.2.4" resolved "https://registry.yarnpkg.com/@graphql-tools/delegate/-/delegate-6.2.4.tgz#db553b63eb9512d5eb5bbfdfcd8cb1e2b534699c" @@ -2290,16 +2404,16 @@ fs-extra "9.0.1" tslib "~2.0.1" -"@graphql-tools/graphql-tag-pluck@7.2.6": - version "7.2.6" - resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-7.2.6.tgz#0bddc23b354c2912e17b15209ad1e7117f9fa4da" - integrity sha512-TWF+0MTdWIfETYt2Pm1+jg608aIavgGkjJuN3f2Z4iWhPNvupHkHexAzV4GNkrQa0yXzIl6bQF8uNRjz4v31SA== +"@graphql-tools/graphql-tag-pluck@7.2.7": + version "7.2.7" + resolved "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-7.2.7.tgz#c137a3460898c7f82fcab20b958010637009a9b1" + integrity sha512-leh6rVHNoGXjmbOtTaKNXQtFw4Gu7PokTlEOweNKYMssbH6L1zrKA0G4cE55s60JBo9SF4hjg8X7Gkech5t+mQ== dependencies: "@babel/parser" "^7.16.8" "@babel/traverse" "^7.16.8" "@babel/types" "^7.16.8" - "@graphql-tools/utils" "8.6.9" - tslib "~2.3.0" + "@graphql-tools/utils" "8.6.10" + tslib "~2.4.0" "@graphql-tools/import@^6.2.4": version "6.2.4" @@ -2320,16 +2434,16 @@ tslib "~2.0.1" "@graphql-tools/links@^8.2.14": - version "8.2.14" - resolved "https://registry.yarnpkg.com/@graphql-tools/links/-/links-8.2.14.tgz#028c7e8bd5897e5788fe16a7872ab2bbd6c5bce9" - integrity sha512-n6bNPwjRdJdVEASFbGPSWFGWX29QKEnboZKZaIIp89zKnpjvlZZQQodavjTzTUCfZtp4xcdW8UaZhdu4QEPJWw== + version "8.2.15" + resolved "https://registry.npmjs.org/@graphql-tools/links/-/links-8.2.15.tgz#b7ddcd7356a0108436cfc21e56a1b15a77dc8c20" + integrity sha512-zstH+BrZbeOkqMq/cWiPV7jcF/lyGj7ctIVHwyLw0ntMgxcowLX4vZj2icuEd956pauhddFo/7k/IDNNiNiYRw== dependencies: - "@graphql-tools/delegate" "8.7.7" - "@graphql-tools/utils" "8.6.9" + "@graphql-tools/delegate" "8.7.8" + "@graphql-tools/utils" "8.6.10" apollo-upload-client "17.0.0" form-data "^4.0.0" node-fetch "^2.6.5" - tslib "~2.3.0" + tslib "~2.4.0" "@graphql-tools/load@^6.0.0": version "6.2.4" @@ -2347,29 +2461,29 @@ valid-url "1.0.9" "@graphql-tools/load@^7.5.10": - version "7.5.10" - resolved "https://registry.yarnpkg.com/@graphql-tools/load/-/load-7.5.10.tgz#6e53dd62ec081b3a2966ab9d93e8b991f06501b3" - integrity sha512-I9b9Md1DdB7Du//+x8CtBAKUW21jyuENCPssvlBjHZjvmx5cIGrTftqwGzuDBgR0Zm72tkmat/FTu6/SQPiyeQ== + version "7.5.11" + resolved "https://registry.npmjs.org/@graphql-tools/load/-/load-7.5.11.tgz#0309054298b912321d6822e3f73c5f7ba0c84ea4" + integrity sha512-a8sD3iHfxcbIwP0nSxF+DUAVg+/MuLNOizVJHcZGGS8AdDoezUsnWRkNDT6FlVqRoxHNbkpq8+6B55JKtqHSxg== dependencies: - "@graphql-tools/schema" "8.3.10" - "@graphql-tools/utils" "8.6.9" + "@graphql-tools/schema" "8.3.11" + "@graphql-tools/utils" "8.6.10" p-limit "3.1.0" - tslib "~2.3.0" + tslib "~2.4.0" -"@graphql-tools/merge@8.2.10": - version "8.2.10" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.2.10.tgz#fe2fe5ad33dc2d1b0af8751c0c08d18bb6bb6d88" - integrity sha512-wpg22seOTNfkIO8jFAgo8w1BsT3IS2OTMpkCNf+dvcKSP09SVidYCOliyWHgjDCmpCrvvSjOX855NUKDx/Biew== +"@graphql-tools/merge@8.2.11": + version "8.2.11" + resolved "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.2.11.tgz#0cdc6c9feb32e3392bf0c633881a78ccc1d24368" + integrity sha512-fsjJVdsk9GV1jj1Ed2AKLlHYlsf0ZadTK8X5KxFRE1ZSnKqh56BLVX93JrtOIAnsiHkwOK2TC43HGhApF1swpQ== dependencies: - "@graphql-tools/utils" "8.6.9" - tslib "~2.3.0" + "@graphql-tools/utils" "8.6.10" + tslib "~2.4.0" -"@graphql-tools/merge@8.2.9": - version "8.2.9" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.2.9.tgz#f4bb6ca58d0d89dbfa4fded6a1457bb359de1450" - integrity sha512-mHRrqMc1NTL6MALBQK1DmAzSxJIKoaCaW7ZCk5bRGzVj/MNQz3OsqlDb/+t9/ONT0V+WI/uxBFsrLMwa4p6L7A== +"@graphql-tools/merge@8.2.8": + version "8.2.8" + resolved "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.2.8.tgz#6ed65c29b963b4d76b59a9d329fdf20ecef19a42" + integrity sha512-e4kpzgEIlA0sC0NjJlMwUL73Iz/HoP2OgAUReDDsupvWCqW3PMxjNoviS8xmcklVnv1w8Vmr8U2tao+x40ypLA== dependencies: - "@graphql-tools/utils" "8.6.8" + "@graphql-tools/utils" "8.6.7" tslib "~2.3.0" "@graphql-tools/merge@^6.0.0", "@graphql-tools/merge@^6.2.4": @@ -2383,27 +2497,37 @@ "@graphql-tools/optimize@^1.0.1": version "1.2.0" - resolved "https://registry.yarnpkg.com/@graphql-tools/optimize/-/optimize-1.2.0.tgz#292d0a269f95d04bc6d822c034569bb7e591fb26" + resolved "https://registry.npmjs.org/@graphql-tools/optimize/-/optimize-1.2.0.tgz#292d0a269f95d04bc6d822c034569bb7e591fb26" integrity sha512-l0PTqgHeorQdeOizUor6RB49eOAng9+abSxiC5/aHRo6hMmXVaqv5eqndlmxCpx9BkgNb3URQbK+ZZHVktkP/g== dependencies: tslib "~2.3.0" "@graphql-tools/relay-operation-optimizer@^6.3.7": - version "6.4.8" - resolved "https://registry.yarnpkg.com/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.4.8.tgz#b8e7fa3507d3a75546e96d66a0e32e2276a4efd6" - integrity sha512-20W1uTVHfDrDM3FIVcLuLmY6gkYUBCvqvuPU5WFth+BumacW09bNYk3+MP5fTQYhscZc0+nu4QjxmX0WGs/VAQ== + version "6.4.10" + resolved "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.4.10.tgz#30bafaf6f35708784dceace430c793181efcef8e" + integrity sha512-a5wDdXP7MmwZDy9R8+RZ0ajJBWX1Lk9sIG6uSIo5G/LnGpXncgBhKpJf5r6rOf0zsFLWnAkYm/dCDMpFaGE/Yw== dependencies: - "@graphql-tools/utils" "8.6.8" + "@graphql-tools/utils" "8.6.10" relay-compiler "12.0.0" - tslib "~2.3.0" + tslib "~2.4.0" -"@graphql-tools/schema@8.3.10", "@graphql-tools/schema@^8.3.1": - version "8.3.10" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.3.10.tgz#c3e373e6ad854f533fc7e55859dd8f9e81de30dd" - integrity sha512-tfhjSTi3OzheDrVzG7rkPZg2BbQjmZRLM2vvQoM2b1TnUwgUIbpAgcnf+AWDLRsoCOWlezeLgij1BLeAR0Q0jg== +"@graphql-tools/schema@8.3.11", "@graphql-tools/schema@^8.1.2": + version "8.3.11" + resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.3.11.tgz#c0606b301852820a46042ebb888fd09cc402518a" + integrity sha512-esMEnbyXbp8B5VEI4o395+x0G7Qmz3JSX5onFBF8HeLYcqWJasY5vBuWkO18VxrZpEnvnryodP6Y00bVag9O3Q== dependencies: - "@graphql-tools/merge" "8.2.10" - "@graphql-tools/utils" "8.6.9" + "@graphql-tools/merge" "8.2.11" + "@graphql-tools/utils" "8.6.10" + tslib "~2.4.0" + value-or-promise "1.0.11" + +"@graphql-tools/schema@8.3.8": + version "8.3.8" + resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.3.8.tgz#68f35d733487732c522a1b47d27faf8809cce95a" + integrity sha512-Bba60ali4fLOKJz/Kk39RcBrDUBtu0Wy7pjpIOmFIKQKwUBNNB0eAmfpvrjnFhRAVdO2kOkPpc8DQY+SCG+lWw== + dependencies: + "@graphql-tools/merge" "8.2.8" + "@graphql-tools/utils" "8.6.7" tslib "~2.3.0" value-or-promise "1.0.11" @@ -2415,16 +2539,6 @@ "@graphql-tools/utils" "^6.2.4" tslib "~2.0.1" -"@graphql-tools/schema@^8.1.2": - version "8.3.9" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.3.9.tgz#2b83464a0ef083c92d7076da0fa5939f2f5a1e34" - integrity sha512-9YFCzn0sYAGTWhZrVYY/neK5cie3s0dNm7Qq38tkhOh2ME5BtHW/8ZIq+UrLGKsBYwa+Qjb/UojGWUm2yG/z6Q== - dependencies: - "@graphql-tools/merge" "8.2.9" - "@graphql-tools/utils" "8.6.8" - tslib "~2.3.0" - value-or-promise "1.0.11" - "@graphql-tools/url-loader@^6.0.0": version "6.3.0" resolved "https://registry.yarnpkg.com/@graphql-tools/url-loader/-/url-loader-6.3.0.tgz#75b82bdf0983d3e389c75948a7abff20fa45a630" @@ -2440,17 +2554,17 @@ valid-url "1.0.9" websocket "1.0.32" -"@graphql-tools/utils@8.6.8", "@graphql-tools/utils@^8.1.1", "@graphql-tools/utils@^8.3.0", "@graphql-tools/utils@^8.5.2": - version "8.6.8" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.6.8.tgz#a0824ed5810f66c504df4e97c5900786ac0c260e" - integrity sha512-EdUUeKi/wp/UvuknyINpQ/uXDqTM3qxPPPDIq5RpfW0zQOeCvbZcx8xHoMox0TYKvKtg3zoB7aprUtoW+iZLxw== +"@graphql-tools/utils@8.6.10", "@graphql-tools/utils@^8.1.1", "@graphql-tools/utils@^8.3.0", "@graphql-tools/utils@^8.5.2", "@graphql-tools/utils@^8.6.9": + version "8.6.10" + resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.6.10.tgz#38e42a97a74ffcf5a21e816401e2ca1647194f6a" + integrity sha512-bJH9qwuyM3BP0PTU6/lvBDkk6jdEIOn+dbyk4pHMVNnvbJ1gZQwo62To8SHxxaUTus8OMhhVPSh9ApWXREURcg== dependencies: - tslib "~2.3.0" + tslib "~2.4.0" -"@graphql-tools/utils@8.6.9", "@graphql-tools/utils@^8.5.3", "@graphql-tools/utils@^8.6.9": - version "8.6.9" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.6.9.tgz#fe1b81df29c9418b41b7a1ffe731710b93d3a1fe" - integrity sha512-Z1X4d4GCT81+8CSt6SgU4t1w1UAUsAIRb67mI90k/zAs+ArkB95iE3bWXuJCUmd1+r8DGGtmUNOArtd6wkt+OQ== +"@graphql-tools/utils@8.6.7": + version "8.6.7" + resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.6.7.tgz#0e21101233743eb67a5782a5a40919d85ddb1021" + integrity sha512-Qi3EN95Rt3hb8CyDKpPKFWOPrnc00P18cpVTXEgtKxetSP39beJBeEEtLB0R53eP/6IolsyTZOTgkET1EaERaw== dependencies: tslib "~2.3.0" @@ -2475,13 +2589,13 @@ tslib "~2.0.1" "@graphql-tools/wrap@^8.3.3": - version "8.3.3" - resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-8.3.3.tgz#014aa04a6cf671ffe477516255d1134777da056a" - integrity sha512-TpXN1S4Cv+oMA1Zsg9Nu4N9yrFxLuJkX+CTtSRrrdfETGHIxqfyDkm5slPDCckxP+RILA00g8ny2jzsYyNvX1w== + version "8.4.13" + resolved "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-8.4.13.tgz#a488d341b8ba3f1f3d9d69e30d6e78dca40a1e9e" + integrity sha512-q0Fa0CVgcaqm4FI4GXAVLjz8TQaF6lpFOm/rlgEkMzW9wFY/ZvDs+K3fVh9BgNvpudJArnVzAZgl2+FHNdY9CA== dependencies: - "@graphql-tools/delegate" "^8.4.2" - "@graphql-tools/schema" "^8.3.1" - "@graphql-tools/utils" "^8.5.3" + "@graphql-tools/delegate" "8.7.4" + "@graphql-tools/schema" "8.3.8" + "@graphql-tools/utils" "8.6.7" tslib "~2.3.0" value-or-promise "1.0.11" @@ -2611,27 +2725,27 @@ chalk "^2.0.1" slash "^2.0.0" -"@jest/console@^27.4.2": - version "27.4.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.4.2.tgz#7a95612d38c007ddb528ee446fe5e5e785e685ce" - integrity sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg== +"@jest/console@^27.4.6": + version "27.4.6" + resolved "https://registry.npmjs.org/@jest/console/-/console-27.4.6.tgz#0742e6787f682b22bdad56f9db2a8a77f6a86107" + integrity sha512-jauXyacQD33n47A44KrlOVeiXHEXDqapSdfb9kTekOchH/Pd18kBIO1+xxJQRLuG+LUuljFCwTG92ra4NW7SpA== dependencies: "@jest/types" "^27.4.2" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^27.4.2" + jest-message-util "^27.4.6" jest-util "^27.4.2" slash "^3.0.0" -"@jest/core@^27.4.4": - version "27.4.4" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.4.4.tgz#f2ba293235ca23fb48b4b923ccfe67c17e791a92" - integrity sha512-xBNPVqYAdAiAMXnb4ugx9Cdmr0S52lBsLbQMR/sGBRO0810VSPKiuSDtuup6qdkK1e9vxbv3KK3IAP1QFAp8mw== +"@jest/core@^27.4.7": + version "27.4.7" + resolved "https://registry.npmjs.org/@jest/core/-/core-27.4.7.tgz#84eabdf42a25f1fa138272ed229bcf0a1b5e6913" + integrity sha512-n181PurSJkVMS+kClIFSX/LLvw9ExSb+4IMtD6YnfxZVerw9ANYtW0bPrm0MJu2pfe9SY9FJ9FtQ+MdZkrZwjg== dependencies: - "@jest/console" "^27.4.2" - "@jest/reporters" "^27.4.4" - "@jest/test-result" "^27.4.2" - "@jest/transform" "^27.4.4" + "@jest/console" "^27.4.6" + "@jest/reporters" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" "@jest/types" "^27.4.2" "@types/node" "*" ansi-escapes "^4.2.1" @@ -2640,63 +2754,63 @@ exit "^0.1.2" graceful-fs "^4.2.4" jest-changed-files "^27.4.2" - jest-config "^27.4.4" - jest-haste-map "^27.4.4" - jest-message-util "^27.4.2" + jest-config "^27.4.7" + jest-haste-map "^27.4.6" + jest-message-util "^27.4.6" jest-regex-util "^27.4.0" - jest-resolve "^27.4.4" - jest-resolve-dependencies "^27.4.4" - jest-runner "^27.4.4" - jest-runtime "^27.4.4" - jest-snapshot "^27.4.4" + jest-resolve "^27.4.6" + jest-resolve-dependencies "^27.4.6" + jest-runner "^27.4.6" + jest-runtime "^27.4.6" + jest-snapshot "^27.4.6" jest-util "^27.4.2" - jest-validate "^27.4.2" - jest-watcher "^27.4.2" + jest-validate "^27.4.6" + jest-watcher "^27.4.6" micromatch "^4.0.4" rimraf "^3.0.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^27.4.4": - version "27.4.4" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.4.4.tgz#66ebebc79673d84aad29d2bb70a8c51e6c29bb4d" - integrity sha512-q+niMx7cJgt/t/b6dzLOh4W8Ef/8VyKG7hxASK39jakijJzbFBGpptx3RXz13FFV7OishQ9lTbv+dQ5K3EhfDQ== +"@jest/environment@^27.4.6": + version "27.4.6" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-27.4.6.tgz#1e92885d64f48c8454df35ed9779fbcf31c56d8b" + integrity sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg== dependencies: - "@jest/fake-timers" "^27.4.2" + "@jest/fake-timers" "^27.4.6" "@jest/types" "^27.4.2" "@types/node" "*" - jest-mock "^27.4.2" + jest-mock "^27.4.6" -"@jest/fake-timers@^27.4.2": - version "27.4.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.4.2.tgz#d217f86c3ba2027bf29e0b731fd0cb761a72d093" - integrity sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg== +"@jest/fake-timers@^27.4.6": + version "27.4.6" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.6.tgz#e026ae1671316dbd04a56945be2fa251204324e8" + integrity sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A== dependencies: "@jest/types" "^27.4.2" "@sinonjs/fake-timers" "^8.0.1" "@types/node" "*" - jest-message-util "^27.4.2" - jest-mock "^27.4.2" + jest-message-util "^27.4.6" + jest-mock "^27.4.6" jest-util "^27.4.2" -"@jest/globals@^27.4.4": - version "27.4.4" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.4.4.tgz#fe501a80c23ea2dab585c42be2a519bb5e38530d" - integrity sha512-bqpqQhW30BOreXM8bA8t8JbOQzsq/WnPTnBl+It3UxAD9J8yxEAaBEylHx1dtBapAr/UBk8GidXbzmqnee8tYQ== +"@jest/globals@^27.4.6": + version "27.4.6" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-27.4.6.tgz#3f09bed64b0fd7f5f996920258bd4be8f52f060a" + integrity sha512-kAiwMGZ7UxrgPzu8Yv9uvWmXXxsy0GciNejlHvfPIfWkSxChzv6bgTS3YqBkGuHcis+ouMFI2696n2t+XYIeFw== dependencies: - "@jest/environment" "^27.4.4" + "@jest/environment" "^27.4.6" "@jest/types" "^27.4.2" - expect "^27.4.2" + expect "^27.4.6" -"@jest/reporters@^27.4.4": - version "27.4.4" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.4.4.tgz#9e809829f602cd6e68bd058d1ea528f4b7482365" - integrity sha512-ssyJSw9B9Awb1QaxDhIPSs4de1b7SE2kv7tqFehQL13xpn5HUkMYZK/ufTOXiCAnXFOZS+XDl1GaQ/LmJAzI1A== +"@jest/reporters@^27.4.6": + version "27.4.6" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.6.tgz#b53dec3a93baf9b00826abf95b932de919d6d8dd" + integrity sha512-+Zo9gV81R14+PSq4wzee4GC2mhAN9i9a7qgJWL90Gpx7fHYkWpTBvwWNZUXvJByYR9tAVBdc8VxDWqfJyIUrIQ== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^27.4.2" - "@jest/test-result" "^27.4.2" - "@jest/transform" "^27.4.4" + "@jest/console" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" "@jest/types" "^27.4.2" "@types/node" "*" chalk "^4.0.0" @@ -2705,14 +2819,14 @@ glob "^7.1.2" graceful-fs "^4.2.4" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.3" + istanbul-lib-instrument "^5.1.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - jest-haste-map "^27.4.4" - jest-resolve "^27.4.4" + istanbul-reports "^3.1.3" + jest-haste-map "^27.4.6" + jest-resolve "^27.4.6" jest-util "^27.4.2" - jest-worker "^27.4.4" + jest-worker "^27.4.6" slash "^3.0.0" source-map "^0.6.0" string-length "^4.0.1" @@ -2730,7 +2844,7 @@ "@jest/source-map@^27.4.0": version "27.4.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.4.0.tgz#2f0385d0d884fb3e2554e8f71f8fa957af9a74b6" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz#2f0385d0d884fb3e2554e8f71f8fa957af9a74b6" integrity sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ== dependencies: callsites "^3.0.0" @@ -2746,43 +2860,43 @@ "@jest/types" "^24.9.0" "@types/istanbul-lib-coverage" "^2.0.0" -"@jest/test-result@^27.4.2": - version "27.4.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.4.2.tgz#05fd4a5466ec502f3eae0b39dff2b93ea4d5d9ec" - integrity sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA== +"@jest/test-result@^27.4.6": + version "27.4.6" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.6.tgz#b3df94c3d899c040f602cea296979844f61bdf69" + integrity sha512-fi9IGj3fkOrlMmhQqa/t9xum8jaJOOAi/lZlm6JXSc55rJMXKHxNDN1oCP39B0/DhNOa2OMupF9BcKZnNtXMOQ== dependencies: - "@jest/console" "^27.4.2" + "@jest/console" "^27.4.6" "@jest/types" "^27.4.2" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^27.4.4": - version "27.4.4" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.4.4.tgz#60be14369b2702e42d6042e71b8ab3fc69f5ce68" - integrity sha512-mCh+d4JTGTtX7vr13d7q2GHJy33nAobEwtEJ8X3u7R8+0ImVO2eAsQzsLfX8lyvdYHBxYABhqbYuaUNo42/pQw== +"@jest/test-sequencer@^27.4.6": + version "27.4.6" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.6.tgz#447339b8a3d7b5436f50934df30854e442a9d904" + integrity sha512-3GL+nsf6E1PsyNsJuvPyIz+DwFuCtBdtvPpm/LMXVkBJbdFvQYCDpccYT56qq5BGniXWlE81n2qk1sdXfZebnw== dependencies: - "@jest/test-result" "^27.4.2" + "@jest/test-result" "^27.4.6" graceful-fs "^4.2.4" - jest-haste-map "^27.4.4" - jest-runtime "^27.4.4" + jest-haste-map "^27.4.6" + jest-runtime "^27.4.6" -"@jest/transform@^27.4.4": - version "27.4.4" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.4.4.tgz#347e39402730879ba88c6ea6982db0d88640aa78" - integrity sha512-7U/nDSrGsGzL7+X8ScNFV71w8u8knJQWSa9C2xsrrKLMOgb+rWuCG4VAyWke/53BU96GnT+Ka81xCAHA5gk6zA== +"@jest/transform@^27.4.6": + version "27.4.6" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-27.4.6.tgz#153621940b1ed500305eacdb31105d415dc30231" + integrity sha512-9MsufmJC8t5JTpWEQJ0OcOOAXaH5ioaIX6uHVBLBMoCZPfKKQF+EqP8kACAvCZ0Y1h2Zr3uOccg8re+Dr5jxyw== dependencies: "@babel/core" "^7.1.0" "@jest/types" "^27.4.2" - babel-plugin-istanbul "^6.0.0" + babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" graceful-fs "^4.2.4" - jest-haste-map "^27.4.4" + jest-haste-map "^27.4.6" jest-regex-util "^27.4.0" jest-util "^27.4.2" micromatch "^4.0.4" - pirates "^4.0.1" + pirates "^4.0.4" slash "^3.0.0" source-map "^0.6.1" write-file-atomic "^3.0.0" @@ -2809,7 +2923,7 @@ "@jest/types@^27.4.2": version "27.4.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5" + resolved "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5" integrity sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" @@ -2820,7 +2934,7 @@ "@jimp/bmp@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.16.1.tgz#6e2da655b2ba22e721df0795423f34e92ef13768" + resolved "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.16.1.tgz#6e2da655b2ba22e721df0795423f34e92ef13768" integrity sha512-iwyNYQeBawrdg/f24x3pQ5rEx+/GwjZcCXd3Kgc+ZUd+Ivia7sIqBsOnDaMZdKCBPlfW364ekexnlOqyVa0NWg== dependencies: "@babel/runtime" "^7.7.2" @@ -2829,7 +2943,7 @@ "@jimp/core@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/core/-/core-0.16.1.tgz#68c4288f6ef7f31a0f6b859ba3fb28dae930d39d" + resolved "https://registry.npmjs.org/@jimp/core/-/core-0.16.1.tgz#68c4288f6ef7f31a0f6b859ba3fb28dae930d39d" integrity sha512-la7kQia31V6kQ4q1kI/uLimu8FXx7imWVajDGtwUG8fzePLWDFJyZl0fdIXVCL1JW2nBcRHidUot6jvlRDi2+g== dependencies: "@babel/runtime" "^7.7.2" @@ -2846,7 +2960,7 @@ "@jimp/custom@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/custom/-/custom-0.16.1.tgz#28b659c59e20a1d75a0c46067bd3f4bd302cf9c5" + resolved "https://registry.npmjs.org/@jimp/custom/-/custom-0.16.1.tgz#28b659c59e20a1d75a0c46067bd3f4bd302cf9c5" integrity sha512-DNUAHNSiUI/j9hmbatD6WN/EBIyeq4AO0frl5ETtt51VN1SvE4t4v83ZA/V6ikxEf3hxLju4tQ5Pc3zmZkN/3A== dependencies: "@babel/runtime" "^7.7.2" @@ -2854,7 +2968,7 @@ "@jimp/gif@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/gif/-/gif-0.16.1.tgz#d1f7c3a58f4666482750933af8b8f4666414f3ca" + resolved "https://registry.npmjs.org/@jimp/gif/-/gif-0.16.1.tgz#d1f7c3a58f4666482750933af8b8f4666414f3ca" integrity sha512-r/1+GzIW1D5zrP4tNrfW+3y4vqD935WBXSc8X/wm23QTY9aJO9Lw6PEdzpYCEY+SOklIFKaJYUAq/Nvgm/9ryw== dependencies: "@babel/runtime" "^7.7.2" @@ -2864,7 +2978,7 @@ "@jimp/jpeg@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/jpeg/-/jpeg-0.16.1.tgz#3b7bb08a4173f2f6d81f3049b251df3ee2ac8175" + resolved "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.16.1.tgz#3b7bb08a4173f2f6d81f3049b251df3ee2ac8175" integrity sha512-8352zrdlCCLFdZ/J+JjBslDvml+fS3Z8gttdml0We759PnnZGqrnPRhkOEOJbNUlE+dD4ckLeIe6NPxlS/7U+w== dependencies: "@babel/runtime" "^7.7.2" @@ -2873,7 +2987,7 @@ "@jimp/plugin-blit@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-blit/-/plugin-blit-0.16.1.tgz#09ea919f9d326de3b9c2826fe4155da37dde8edb" + resolved "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.16.1.tgz#09ea919f9d326de3b9c2826fe4155da37dde8edb" integrity sha512-fKFNARm32RoLSokJ8WZXHHH2CGzz6ire2n1Jh6u+XQLhk9TweT1DcLHIXwQMh8oR12KgjbgsMGvrMVlVknmOAg== dependencies: "@babel/runtime" "^7.7.2" @@ -2881,7 +2995,7 @@ "@jimp/plugin-blur@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-blur/-/plugin-blur-0.16.1.tgz#e614fa002797dcd662e705d4cea376e7db968bf5" + resolved "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.16.1.tgz#e614fa002797dcd662e705d4cea376e7db968bf5" integrity sha512-1WhuLGGj9MypFKRcPvmW45ht7nXkOKu+lg3n2VBzIB7r4kKNVchuI59bXaCYQumOLEqVK7JdB4glaDAbCQCLyw== dependencies: "@babel/runtime" "^7.7.2" @@ -2889,7 +3003,7 @@ "@jimp/plugin-circle@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-circle/-/plugin-circle-0.16.1.tgz#20e3194a67ca29740aba2630fd4d0a89afa27491" + resolved "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.16.1.tgz#20e3194a67ca29740aba2630fd4d0a89afa27491" integrity sha512-JK7yi1CIU7/XL8hdahjcbGA3V7c+F+Iw+mhMQhLEi7Q0tCnZ69YJBTamMiNg3fWPVfMuvWJJKOBRVpwNTuaZRg== dependencies: "@babel/runtime" "^7.7.2" @@ -2897,7 +3011,7 @@ "@jimp/plugin-color@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-color/-/plugin-color-0.16.1.tgz#0f298ba74dee818b663834cd80d53e56f3755233" + resolved "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.16.1.tgz#0f298ba74dee818b663834cd80d53e56f3755233" integrity sha512-9yQttBAO5SEFj7S6nJK54f+1BnuBG4c28q+iyzm1JjtnehjqMg6Ljw4gCSDCvoCQ3jBSYHN66pmwTV74SU1B7A== dependencies: "@babel/runtime" "^7.7.2" @@ -2906,7 +3020,7 @@ "@jimp/plugin-contain@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-contain/-/plugin-contain-0.16.1.tgz#3c5f5c495fd9bb08a970739d83694934f58123f2" + resolved "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.16.1.tgz#3c5f5c495fd9bb08a970739d83694934f58123f2" integrity sha512-44F3dUIjBDHN+Ym/vEfg+jtjMjAqd2uw9nssN67/n4FdpuZUVs7E7wadKY1RRNuJO+WgcD5aDQcsvurXMETQTg== dependencies: "@babel/runtime" "^7.7.2" @@ -2914,7 +3028,7 @@ "@jimp/plugin-cover@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-cover/-/plugin-cover-0.16.1.tgz#0e8caec16a40abe15b1b32e5383a603a3306dc41" + resolved "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.16.1.tgz#0e8caec16a40abe15b1b32e5383a603a3306dc41" integrity sha512-YztWCIldBAVo0zxcQXR+a/uk3/TtYnpKU2CanOPJ7baIuDlWPsG+YE4xTsswZZc12H9Kl7CiziEbDtvF9kwA/Q== dependencies: "@babel/runtime" "^7.7.2" @@ -2922,7 +3036,7 @@ "@jimp/plugin-crop@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-crop/-/plugin-crop-0.16.1.tgz#b362497c873043fe47ba881ab08604bf7226f50f" + resolved "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.16.1.tgz#b362497c873043fe47ba881ab08604bf7226f50f" integrity sha512-UQdva9oQzCVadkyo3T5Tv2CUZbf0klm2cD4cWMlASuTOYgaGaFHhT9st+kmfvXjKL8q3STkBu/zUPV6PbuV3ew== dependencies: "@babel/runtime" "^7.7.2" @@ -2930,7 +3044,7 @@ "@jimp/plugin-displace@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-displace/-/plugin-displace-0.16.1.tgz#4dd9db518c3e78de9d723f86a234bf98922afe8d" + resolved "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.16.1.tgz#4dd9db518c3e78de9d723f86a234bf98922afe8d" integrity sha512-iVAWuz2+G6Heu8gVZksUz+4hQYpR4R0R/RtBzpWEl8ItBe7O6QjORAkhxzg+WdYLL2A/Yd4ekTpvK0/qW8hTVw== dependencies: "@babel/runtime" "^7.7.2" @@ -2938,7 +3052,7 @@ "@jimp/plugin-dither@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-dither/-/plugin-dither-0.16.1.tgz#b47de2c0bb09608bed228b41c3cd01a85ec2d45b" + resolved "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.16.1.tgz#b47de2c0bb09608bed228b41c3cd01a85ec2d45b" integrity sha512-tADKVd+HDC9EhJRUDwMvzBXPz4GLoU6s5P7xkVq46tskExYSptgj5713J5Thj3NMgH9Rsqu22jNg1H/7tr3V9Q== dependencies: "@babel/runtime" "^7.7.2" @@ -2946,7 +3060,7 @@ "@jimp/plugin-fisheye@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-fisheye/-/plugin-fisheye-0.16.1.tgz#f625047b6cdbe1b83b89e9030fd025ab19cdb1a4" + resolved "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.16.1.tgz#f625047b6cdbe1b83b89e9030fd025ab19cdb1a4" integrity sha512-BWHnc5hVobviTyIRHhIy9VxI1ACf4CeSuCfURB6JZm87YuyvgQh5aX5UDKtOz/3haMHXBLP61ZBxlNpMD8CG4A== dependencies: "@babel/runtime" "^7.7.2" @@ -2954,7 +3068,7 @@ "@jimp/plugin-flip@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-flip/-/plugin-flip-0.16.1.tgz#7a99ea22bde802641017ed0f2615870c144329bb" + resolved "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.16.1.tgz#7a99ea22bde802641017ed0f2615870c144329bb" integrity sha512-KdxTf0zErfZ8DyHkImDTnQBuHby+a5YFdoKI/G3GpBl3qxLBvC+PWkS2F/iN3H7wszP7/TKxTEvWL927pypT0w== dependencies: "@babel/runtime" "^7.7.2" @@ -2962,7 +3076,7 @@ "@jimp/plugin-gaussian@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-gaussian/-/plugin-gaussian-0.16.1.tgz#0845e314085ccd52e34fad9a83949bc0d81a68e8" + resolved "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.16.1.tgz#0845e314085ccd52e34fad9a83949bc0d81a68e8" integrity sha512-u9n4wjskh3N1mSqketbL6tVcLU2S5TEaFPR40K6TDv4phPLZALi1Of7reUmYpVm8mBDHt1I6kGhuCJiWvzfGyg== dependencies: "@babel/runtime" "^7.7.2" @@ -2970,7 +3084,7 @@ "@jimp/plugin-invert@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-invert/-/plugin-invert-0.16.1.tgz#7e6f5a15707256f3778d06921675bbcf18545c97" + resolved "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.16.1.tgz#7e6f5a15707256f3778d06921675bbcf18545c97" integrity sha512-2DKuyVXANH8WDpW9NG+PYFbehzJfweZszFYyxcaewaPLN0GxvxVLOGOPP1NuUTcHkOdMFbE0nHDuB7f+sYF/2w== dependencies: "@babel/runtime" "^7.7.2" @@ -2978,7 +3092,7 @@ "@jimp/plugin-mask@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-mask/-/plugin-mask-0.16.1.tgz#e7f2460e05c3cda7af5e76f33ccb0579f66f90df" + resolved "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.16.1.tgz#e7f2460e05c3cda7af5e76f33ccb0579f66f90df" integrity sha512-snfiqHlVuj4bSFS0v96vo2PpqCDMe4JB+O++sMo5jF5mvGcGL6AIeLo8cYqPNpdO6BZpBJ8MY5El0Veckhr39Q== dependencies: "@babel/runtime" "^7.7.2" @@ -2986,7 +3100,7 @@ "@jimp/plugin-normalize@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-normalize/-/plugin-normalize-0.16.1.tgz#032dfd88eefbc4dedc8b1b2d243832e4f3af30c8" + resolved "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.16.1.tgz#032dfd88eefbc4dedc8b1b2d243832e4f3af30c8" integrity sha512-dOQfIOvGLKDKXPU8xXWzaUeB0nvkosHw6Xg1WhS1Z5Q0PazByhaxOQkSKgUryNN/H+X7UdbDvlyh/yHf3ITRaw== dependencies: "@babel/runtime" "^7.7.2" @@ -2994,7 +3108,7 @@ "@jimp/plugin-print@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-print/-/plugin-print-0.16.1.tgz#66b803563f9d109825970714466e6ab9ae639ff6" + resolved "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.16.1.tgz#66b803563f9d109825970714466e6ab9ae639ff6" integrity sha512-ceWgYN40jbN4cWRxixym+csyVymvrryuKBQ+zoIvN5iE6OyS+2d7Mn4zlNgumSczb9GGyZZESIgVcBDA1ezq0Q== dependencies: "@babel/runtime" "^7.7.2" @@ -3003,7 +3117,7 @@ "@jimp/plugin-resize@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-resize/-/plugin-resize-0.16.1.tgz#65e39d848ed13ba2d6c6faf81d5d590396571d10" + resolved "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.16.1.tgz#65e39d848ed13ba2d6c6faf81d5d590396571d10" integrity sha512-u4JBLdRI7dargC04p2Ha24kofQBk3vhaf0q8FwSYgnCRwxfvh2RxvhJZk9H7Q91JZp6wgjz/SjvEAYjGCEgAwQ== dependencies: "@babel/runtime" "^7.7.2" @@ -3011,7 +3125,7 @@ "@jimp/plugin-rotate@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-rotate/-/plugin-rotate-0.16.1.tgz#53fb5d51a4b3d05af9c91c2a8fffe5d7a1a47c8c" + resolved "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.16.1.tgz#53fb5d51a4b3d05af9c91c2a8fffe5d7a1a47c8c" integrity sha512-ZUU415gDQ0VjYutmVgAYYxC9Og9ixu2jAGMCU54mSMfuIlmohYfwARQmI7h4QB84M76c9hVLdONWjuo+rip/zg== dependencies: "@babel/runtime" "^7.7.2" @@ -3019,7 +3133,7 @@ "@jimp/plugin-scale@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-scale/-/plugin-scale-0.16.1.tgz#89f6ba59feed3429847ed226aebda33a240cc647" + resolved "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.16.1.tgz#89f6ba59feed3429847ed226aebda33a240cc647" integrity sha512-jM2QlgThIDIc4rcyughD5O7sOYezxdafg/2Xtd1csfK3z6fba3asxDwthqPZAgitrLgiKBDp6XfzC07Y/CefUw== dependencies: "@babel/runtime" "^7.7.2" @@ -3027,7 +3141,7 @@ "@jimp/plugin-shadow@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-shadow/-/plugin-shadow-0.16.1.tgz#a7af892a740febf41211e10a5467c3c5c521a04c" + resolved "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.16.1.tgz#a7af892a740febf41211e10a5467c3c5c521a04c" integrity sha512-MeD2Is17oKzXLnsphAa1sDstTu6nxscugxAEk3ji0GV1FohCvpHBcec0nAq6/czg4WzqfDts+fcPfC79qWmqrA== dependencies: "@babel/runtime" "^7.7.2" @@ -3035,7 +3149,7 @@ "@jimp/plugin-threshold@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-threshold/-/plugin-threshold-0.16.1.tgz#34f3078f9965145b7ae26c53a32ad74b1195bbf5" + resolved "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.16.1.tgz#34f3078f9965145b7ae26c53a32ad74b1195bbf5" integrity sha512-iGW8U/wiCSR0+6syrPioVGoSzQFt4Z91SsCRbgNKTAk7D+XQv6OI78jvvYg4o0c2FOlwGhqz147HZV5utoSLxA== dependencies: "@babel/runtime" "^7.7.2" @@ -3043,7 +3157,7 @@ "@jimp/plugins@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugins/-/plugins-0.16.1.tgz#9f08544c97226d6460a16ced79f57e85bec3257b" + resolved "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.16.1.tgz#9f08544c97226d6460a16ced79f57e85bec3257b" integrity sha512-c+lCqa25b+4q6mJZSetlxhMoYuiltyS+ValLzdwK/47+aYsq+kcJNl+TuxIEKf59yr9+5rkbpsPkZHLF/V7FFA== dependencies: "@babel/runtime" "^7.7.2" @@ -3072,7 +3186,7 @@ "@jimp/png@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/png/-/png-0.16.1.tgz#f24cfc31529900b13a2dd9d4fdb4460c1e4d814e" + resolved "https://registry.npmjs.org/@jimp/png/-/png-0.16.1.tgz#f24cfc31529900b13a2dd9d4fdb4460c1e4d814e" integrity sha512-iyWoCxEBTW0OUWWn6SveD4LePW89kO7ZOy5sCfYeDM/oTPLpR8iMIGvZpZUz1b8kvzFr27vPst4E5rJhGjwsdw== dependencies: "@babel/runtime" "^7.7.2" @@ -3081,7 +3195,7 @@ "@jimp/tiff@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/tiff/-/tiff-0.16.1.tgz#0e8756695687d7574b6bc73efab0acd4260b7a12" + resolved "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.16.1.tgz#0e8756695687d7574b6bc73efab0acd4260b7a12" integrity sha512-3K3+xpJS79RmSkAvFMgqY5dhSB+/sxhwTFA9f4AVHUK0oKW+u6r52Z1L0tMXHnpbAdR9EJ+xaAl2D4x19XShkQ== dependencies: "@babel/runtime" "^7.7.2" @@ -3089,7 +3203,7 @@ "@jimp/types@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/types/-/types-0.16.1.tgz#0dbab37b3202315c91010f16c31766d35a2322cc" + resolved "https://registry.npmjs.org/@jimp/types/-/types-0.16.1.tgz#0dbab37b3202315c91010f16c31766d35a2322cc" integrity sha512-g1w/+NfWqiVW4CaXSJyD28JQqZtm2eyKMWPhBBDCJN9nLCN12/Az0WFF3JUAktzdsEC2KRN2AqB1a2oMZBNgSQ== dependencies: "@babel/runtime" "^7.7.2" @@ -3102,15 +3216,23 @@ "@jimp/utils@^0.16.1": version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/utils/-/utils-0.16.1.tgz#2f51e6f14ff8307c4aa83d5e1a277da14a9fe3f7" + resolved "https://registry.npmjs.org/@jimp/utils/-/utils-0.16.1.tgz#2f51e6f14ff8307c4aa83d5e1a277da14a9fe3f7" integrity sha512-8fULQjB0x4LzUSiSYG6ZtQl355sZjxbv8r9PPAuYHzS9sGiSHJQavNqK/nKnpDsVkU88/vRGcE7t3nMU0dEnVw== dependencies: "@babel/runtime" "^7.7.2" regenerator-runtime "^0.13.3" +"@jridgewell/gen-mapping@^0.1.0": + version "0.1.1" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" + integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w== + dependencies: + "@jridgewell/set-array" "^1.0.0" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/gen-mapping@^0.3.0": version "0.3.1" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz#cf92a983c83466b8c0ce9124fadeaf09f7c66ea9" integrity sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg== dependencies: "@jridgewell/set-array" "^1.0.0" @@ -3118,31 +3240,23 @@ "@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/resolve-uri@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" - integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + version "3.0.7" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz#30cd49820a962aff48c8fffc5cd760151fca61fe" + integrity sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA== "@jridgewell/set-array@^1.0.0": version "1.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.11" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" - integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== - -"@jridgewell/trace-mapping@^0.3.0": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" - integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" + version "1.4.13" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" + integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== "@jridgewell/trace-mapping@^0.3.8", "@jridgewell/trace-mapping@^0.3.9": version "0.3.13" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== dependencies: "@jridgewell/resolve-uri" "^3.0.3" @@ -3835,12 +3949,12 @@ "@lezer/common@^0.15.0", "@lezer/common@^0.15.7": version "0.15.12" - resolved "https://registry.yarnpkg.com/@lezer/common/-/common-0.15.12.tgz#2f21aec551dd5fd7d24eb069f90f54d5bc6ee5e9" + resolved "https://registry.npmjs.org/@lezer/common/-/common-0.15.12.tgz#2f21aec551dd5fd7d24eb069f90f54d5bc6ee5e9" integrity sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig== "@lezer/lr@^0.15.4": version "0.15.8" - resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-0.15.8.tgz#1564a911e62b0a0f75ca63794a6aa8c5dc63db21" + resolved "https://registry.npmjs.org/@lezer/lr/-/lr-0.15.8.tgz#1564a911e62b0a0f75ca63794a6aa8c5dc63db21" integrity sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg== dependencies: "@lezer/common" "^0.15.0" @@ -3899,7 +4013,7 @@ "@mischnic/json-sourcemap@^0.1.0": version "0.1.0" - resolved "https://registry.yarnpkg.com/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz#38af657be4108140a548638267d02a2ea3336507" + resolved "https://registry.npmjs.org/@mischnic/json-sourcemap/-/json-sourcemap-0.1.0.tgz#38af657be4108140a548638267d02a2ea3336507" integrity sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA== dependencies: "@lezer/common" "^0.15.7" @@ -3923,7 +4037,7 @@ "@mswjs/interceptors@^0.13.5": version "0.13.6" - resolved "https://registry.yarnpkg.com/@mswjs/interceptors/-/interceptors-0.13.6.tgz#db46ba29c9ec118aefcf6ef61ecc38b25837967f" + resolved "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.13.6.tgz#db46ba29c9ec118aefcf6ef61ecc38b25837967f" integrity sha512-28FzF44Q84h9vxQ0XBpEz940KC/q3fzlo+TtaIyfilnJ7+HeIcnVfRM4hkp0/q2Uh466PmgpD4BH7A0F0kCBbQ== dependencies: "@open-draft/until" "^1.0.3" @@ -4088,7 +4202,7 @@ "@parcel/bundler-default@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.5.0.tgz#1f0b6d4893bb1a24f49fc7254a423134fb03741e" + resolved "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.5.0.tgz#1f0b6d4893bb1a24f49fc7254a423134fb03741e" integrity sha512-7CJzE17SirCXjcRgBcnqWO/5EOA1raq/3OIKtT4cxbjpDQGHZpjpEEZiMNRpEpdNMxDSlsG8mAkXTYGL2VVWRw== dependencies: "@parcel/diagnostic" "2.5.0" @@ -4099,7 +4213,7 @@ "@parcel/cache@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.5.0.tgz#957620b1b26bfd4f9bd7256ea25ef86e7d6f2816" + resolved "https://registry.npmjs.org/@parcel/cache/-/cache-2.5.0.tgz#957620b1b26bfd4f9bd7256ea25ef86e7d6f2816" integrity sha512-3kOO3cZQv0FAKhrMHGLdb4Qtzpmy78Q6jPN3u8eCY4yqeDTnyQBZvWNHoyCm5WlmL8y6Q6REYMbETLxSH1ggAQ== dependencies: "@parcel/fs" "2.5.0" @@ -4109,21 +4223,21 @@ "@parcel/codeframe@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.5.0.tgz#de73dcd69a36e9d0fed1f4361cabfd83df13244a" + resolved "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.5.0.tgz#de73dcd69a36e9d0fed1f4361cabfd83df13244a" integrity sha512-qafqL8Vu2kr932cCWESoDEEoAeKVi7/xdzTBuhzEJng1AfmRT0rCbt/P4ao3RjiDyozPSjXsHOqM6GDZcto4eQ== dependencies: chalk "^4.1.0" "@parcel/compressor-raw@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.5.0.tgz#8675d7474b84920e1e4682a5bbd9b417ebfc0bc5" + resolved "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.5.0.tgz#8675d7474b84920e1e4682a5bbd9b417ebfc0bc5" integrity sha512-I5Zs+2f1ue4sTPdfT8BNsLfTZl48sMWLk2Io3elUJjH/SS9kO7ut5ChkuJtt77ZS35m0OF+ZCt3ICTJdnDG8eA== dependencies: "@parcel/plugin" "2.5.0" "@parcel/core@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.5.0.tgz#13f60be9124a6a3e33aff32715acfc5ebade9dd2" + resolved "https://registry.npmjs.org/@parcel/core/-/core-2.5.0.tgz#13f60be9124a6a3e33aff32715acfc5ebade9dd2" integrity sha512-dygDmPsfAYJKTnUftcbEzjCik7AAaPbFvJW8ETYz8diyjkAG9y6hvCAZIrJE5pNOjFzg32en4v4UWv8Sqlzl9g== dependencies: "@mischnic/json-sourcemap" "^0.1.0" @@ -4153,7 +4267,7 @@ "@parcel/diagnostic@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.5.0.tgz#8c6891924e04b625d50176aae141d24dc8dddf87" + resolved "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.5.0.tgz#8c6891924e04b625d50176aae141d24dc8dddf87" integrity sha512-KiMGGRpEV7wl5gjcxBKcgX84a+cG+IEn94gwy5LK3lENR09nuKShqqgKGAmj/17CobJgw1QNP94/H4Md+oxIWg== dependencies: "@mischnic/json-sourcemap" "^0.1.0" @@ -4161,19 +4275,19 @@ "@parcel/events@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.5.0.tgz#5e108a01a5aa3075038d2a2081fde0432d2559e7" + resolved "https://registry.npmjs.org/@parcel/events/-/events-2.5.0.tgz#5e108a01a5aa3075038d2a2081fde0432d2559e7" integrity sha512-Gc2LPwL1H34Ony5MENbKZg7wvCscZ4x9y7Fu92sfbdWpLo3K13hVtsX3TMIIgYt3B7R7OmO8yR880U2T+JfVkQ== "@parcel/fs-search@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.5.0.tgz#d96b7c46c2326398e52c9c14cdd07559d598436d" + resolved "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.5.0.tgz#d96b7c46c2326398e52c9c14cdd07559d598436d" integrity sha512-uBONkz9ZCNSOqbPGWJY3MNl+pqBTfvzHH9+4UhzHEHPArvK2oD0+syYPVE60+zGrxybXTESYMCJp4bHvH6Z2hA== dependencies: detect-libc "^1.0.3" "@parcel/fs@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.5.0.tgz#2bcb6ccf43826f2bfca9e1ca644be3bf5252c400" + resolved "https://registry.npmjs.org/@parcel/fs/-/fs-2.5.0.tgz#2bcb6ccf43826f2bfca9e1ca644be3bf5252c400" integrity sha512-YYr14BWtx/bJ+hu6PPQQ6G/3omOTWgVqEw+UFI3iQH3P6+e0LRXW/Ja1yAcJeepGcTwIP0opnXZBQOm8PBQ2SA== dependencies: "@parcel/fs-search" "2.5.0" @@ -4184,7 +4298,7 @@ "@parcel/graph@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.5.0.tgz#bd8898d555366a4b261766e22c8652ad869efaff" + resolved "https://registry.npmjs.org/@parcel/graph/-/graph-2.5.0.tgz#bd8898d555366a4b261766e22c8652ad869efaff" integrity sha512-qa2VtG08dJyTaWrxYAkMIlkoDRSPoiqLDNxxHKplkcxAjXBUw0/AkWaz82VO5r1G6jfOj+nM30ajH9uygZYwbw== dependencies: "@parcel/utils" "2.5.0" @@ -4192,7 +4306,7 @@ "@parcel/hash@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.5.0.tgz#f2a05f7090f8f27ce8b53afd6272183763101ba7" + resolved "https://registry.npmjs.org/@parcel/hash/-/hash-2.5.0.tgz#f2a05f7090f8f27ce8b53afd6272183763101ba7" integrity sha512-47JL0XpB7UvIW6Ijf8vv+yVMt9dLvB/lRlBHFmAkmovisueVMVbYD7smxVZnCSehD8UH8BcymKbMzyL5dimgoQ== dependencies: detect-libc "^1.0.3" @@ -4200,7 +4314,7 @@ "@parcel/logger@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.5.0.tgz#c618b780b80984d821c5bc53f27527fd540f4d0f" + resolved "https://registry.npmjs.org/@parcel/logger/-/logger-2.5.0.tgz#c618b780b80984d821c5bc53f27527fd540f4d0f" integrity sha512-pT1L3ceH6trL1N3I3r2HawPjz/PCubOo/Kazu7IeXsMsKVjj1a6AeieZHzkNZIbhiGPtm/cHbBNLz2zTWDLeOA== dependencies: "@parcel/diagnostic" "2.5.0" @@ -4208,14 +4322,14 @@ "@parcel/markdown-ansi@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.5.0.tgz#e0751d6c8fcd0aa4c8ee0a08d27e9d4d64705410" + resolved "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.5.0.tgz#e0751d6c8fcd0aa4c8ee0a08d27e9d4d64705410" integrity sha512-ixkNF3KWIqxMlfxTe9Gb2cp/uNmklQev8VEUxujMVxmUfGyQs4859zdJIQlIinabWYhArhsXATkVf3MzCUN6TQ== dependencies: chalk "^4.1.0" "@parcel/namer-default@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.5.0.tgz#1e1950a74aca825a753c9aa8e8c37dfb46ef7ef3" + resolved "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.5.0.tgz#1e1950a74aca825a753c9aa8e8c37dfb46ef7ef3" integrity sha512-ahGQqHJzsWE5Qux8zXMAU+lyNBOl+ZpcOFzRGE2DWOsmAlytsHl7DBVCQvzUyNBFg1/HmIj+7D4efv2kjR7rTg== dependencies: "@parcel/diagnostic" "2.5.0" @@ -4224,7 +4338,7 @@ "@parcel/node-resolver-core@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.5.0.tgz#4aaf5c8eb57b56d1257ca02cae5b88be790be6bd" + resolved "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-2.5.0.tgz#4aaf5c8eb57b56d1257ca02cae5b88be790be6bd" integrity sha512-XQvpguiIwQcu75cscLDFOVhjsjuPzXbuMaaZ7XxxUEl0PscIgu/GfKYxTfTruN3cRl+CaQH6qBAMfjLaFng6lQ== dependencies: "@parcel/diagnostic" "2.5.0" @@ -4233,7 +4347,7 @@ "@parcel/optimizer-terser@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.5.0.tgz#16b3320b34135edac69751ab2f3537a346133086" + resolved "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.5.0.tgz#16b3320b34135edac69751ab2f3537a346133086" integrity sha512-PZ3UHBGfjE49/Jloopsd38Hxg4qzsrdepWP53mCuVP7Aw605Y4QtYuB1ho3VV0oXfKQVq+uI7lVIBsuW4K6vqA== dependencies: "@parcel/diagnostic" "2.5.0" @@ -4245,7 +4359,7 @@ "@parcel/package-manager@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.5.0.tgz#9c82236e4e0fa158008b5bc5298def1085913b30" + resolved "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.5.0.tgz#9c82236e4e0fa158008b5bc5298def1085913b30" integrity sha512-zTuF55/lITUjw9dUU/X0HiF++589xbPXw/zUiG9T6s8BQThLvrxAhYP89S719pw7cTqDimGkTxnIuK+a0djEkg== dependencies: "@parcel/diagnostic" "2.5.0" @@ -4258,7 +4372,7 @@ "@parcel/packager-js@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.5.0.tgz#3a696207587f57bf5e0c93b2e36db0758f896bea" + resolved "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.5.0.tgz#3a696207587f57bf5e0c93b2e36db0758f896bea" integrity sha512-aJAKOTgXdxO3V9O7+2DCVOtne128WwXmUAOVThnMRo7f3zMVSAR7Mxc9pEsuTzPfj8UBXgFBRfdJUSCgsMxiSw== dependencies: "@parcel/diagnostic" "2.5.0" @@ -4271,21 +4385,21 @@ "@parcel/packager-raw@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.5.0.tgz#ce0103c26667c93e5c04eda92691363e93aecb1a" + resolved "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.5.0.tgz#ce0103c26667c93e5c04eda92691363e93aecb1a" integrity sha512-aHV0oogeiqxhxS1lsttw15EvG3DDWK3FV7+F+7hoaAy+xg89K56NTp6j43Jtw9iyU1/HnZRGBE2hF3C7N73oKw== dependencies: "@parcel/plugin" "2.5.0" "@parcel/plugin@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.5.0.tgz#ae24d9a709581483e0d494a9e09100f0e40956cf" + resolved "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.5.0.tgz#ae24d9a709581483e0d494a9e09100f0e40956cf" integrity sha512-obtb6/Gql6YFQ86bdv75A2Noabx8679reFZeyfKKf0L7Lppx4DFQetXwM9XVy7Gx6hJ1Ekm3UMuuIyVJk33YHQ== dependencies: "@parcel/types" "2.5.0" "@parcel/reporter-dev-server@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.5.0.tgz#043daa2116358d8f806a89d4a7385fe9555a089f" + resolved "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.5.0.tgz#043daa2116358d8f806a89d4a7385fe9555a089f" integrity sha512-wvxAiW42AxJ3B8jtvowJcP4/cTV8zY48SfKg61YKYu1yUO+TtyJIjHQzDW2XuT34cIGFY97Gr0i+AVu44RyUuQ== dependencies: "@parcel/plugin" "2.5.0" @@ -4293,7 +4407,7 @@ "@parcel/resolver-default@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.5.0.tgz#b107c59b4f8bbb013091916f349f5fc58e5dfab9" + resolved "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.5.0.tgz#b107c59b4f8bbb013091916f349f5fc58e5dfab9" integrity sha512-39PkZpVr/+iYS11u+lA84vIsKm/yisltTVmUjlYsDnExiuV1c8OSbSdYZ3JMx+7CYPE0bWbosX2AGilIwIMWpQ== dependencies: "@parcel/node-resolver-core" "2.5.0" @@ -4301,7 +4415,7 @@ "@parcel/runtime-browser-hmr@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.5.0.tgz#5da8b803cc6bd8a0aac143521ea709f2d13a403f" + resolved "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.5.0.tgz#5da8b803cc6bd8a0aac143521ea709f2d13a403f" integrity sha512-oPAo8Zf06gXCpt41nyvK7kv2HH1RrHAGgOqttyjStwAFlm5MZKs7BgtJzO58LfJN8g3sMY0cNdG17fB/4f8q6Q== dependencies: "@parcel/plugin" "2.5.0" @@ -4309,7 +4423,7 @@ "@parcel/runtime-js@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.5.0.tgz#270369beef008f72e2c0814022f573817a12dba1" + resolved "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.5.0.tgz#270369beef008f72e2c0814022f573817a12dba1" integrity sha512-gPC2PbNAiooULP71wF5twe4raekuXsR1Hw/ahITDoqsZdXHzG3CkoCjYL3CkmBGiKQgMMocCyN1E2oBzAH8Kyw== dependencies: "@parcel/plugin" "2.5.0" @@ -4318,7 +4432,7 @@ "@parcel/runtime-react-refresh@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.5.0.tgz#fc74342d77848ea61f364246df70673e83b5430f" + resolved "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.5.0.tgz#fc74342d77848ea61f364246df70673e83b5430f" integrity sha512-+8RuDKFdFYIQTrXG4MRhG9XqkkYEHn0zxKyOJ/IkDDfSEhY0na+EyhrneFUwIvDX63gLPkxceXAg0gwBqXPK/Q== dependencies: "@parcel/plugin" "2.5.0" @@ -4327,7 +4441,7 @@ "@parcel/runtime-service-worker@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.5.0.tgz#609ea02b27cae378f7d9f54820384f7e3494a749" + resolved "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.5.0.tgz#609ea02b27cae378f7d9f54820384f7e3494a749" integrity sha512-STuDlU0fPXeWpAmbayY7o04F0eHy6FTOFeT5KQ0PTxtdEa3Ey8QInP/NVE52Yv0aVQtesWukGrNEFCERlkbFRw== dependencies: "@parcel/plugin" "2.5.0" @@ -4343,7 +4457,7 @@ "@parcel/transformer-js@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.5.0.tgz#268a6d34898d7c6515c5a64bae535d2c1a7f57a0" + resolved "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.5.0.tgz#268a6d34898d7c6515c5a64bae535d2c1a7f57a0" integrity sha512-Cp8Ic+Au3OcskCRZszmo47z3bqcZ7rfPv2xZYXpXY2TzEc3IV0bKje57bZektoY8LW9LkYM9iBO/WhkVoT6LIg== dependencies: "@parcel/diagnostic" "2.5.0" @@ -4360,7 +4474,7 @@ "@parcel/transformer-json@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.5.0.tgz#9406b8f0cdd58e65f20fd381a75ece64d346858d" + resolved "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.5.0.tgz#9406b8f0cdd58e65f20fd381a75ece64d346858d" integrity sha512-661sByA7TkR6Lmxt+hqV4h2SAt+7lgc58DzmUYArpEl1fQnMuQuaB0kQeHzi6fDD2+2G6o7EC+DuwBZKa479TA== dependencies: "@parcel/plugin" "2.5.0" @@ -4368,14 +4482,14 @@ "@parcel/transformer-raw@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.5.0.tgz#5561945e2fd220ac38c0a21aad72175377d048bc" + resolved "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.5.0.tgz#5561945e2fd220ac38c0a21aad72175377d048bc" integrity sha512-I3zjE1u9+Wj90Qqs1V2FTm6iC6SAyOVUthwVZkZey+qbQG/ok682Ez2XjLu7MyQCo9BJNwF/nfOa1hHr3MaJEQ== dependencies: "@parcel/plugin" "2.5.0" "@parcel/transformer-react-refresh-wrap@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.5.0.tgz#e1ef71218efb21a78677e8770fb6bcf753caf35c" + resolved "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.5.0.tgz#e1ef71218efb21a78677e8770fb6bcf753caf35c" integrity sha512-VPqVBxhTN4OQwcjsdyxrv+smjAm4s6dbSWAplgPwdOITMv+a0tjhhJU37WnRC+xxTrbEqRcOt96JvGOkPb8i7g== dependencies: "@parcel/plugin" "2.5.0" @@ -4384,7 +4498,7 @@ "@parcel/types@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.5.0.tgz#e3818d4358f849ac2593605b98366b8e156ab533" + resolved "https://registry.npmjs.org/@parcel/types/-/types-2.5.0.tgz#e3818d4358f849ac2593605b98366b8e156ab533" integrity sha512-bA0fhG6aXSGYEVo5Dt96x6lseUQHeVZVzgmiRdZsvb614Gvx22ItfaKhPmAVbM9vzbObZDHl9l9G2Ovw8Xve4g== dependencies: "@parcel/cache" "2.5.0" @@ -4397,7 +4511,7 @@ "@parcel/utils@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.5.0.tgz#96d2c7e7226128cc84418ba41770b38aff23ca20" + resolved "https://registry.npmjs.org/@parcel/utils/-/utils-2.5.0.tgz#96d2c7e7226128cc84418ba41770b38aff23ca20" integrity sha512-kaLGXtQuOOH55KZqXdYDvczhh3mk2eeTVqrrXuuihGjbLKYFlUW2tFDm+5r2s9nCPwTQxOO43ZEOCKSnia+e4w== dependencies: "@parcel/codeframe" "2.5.0" @@ -4418,7 +4532,7 @@ "@parcel/workers@2.5.0": version "2.5.0" - resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.5.0.tgz#c7f1a4bcd491c7422212724dedbcf7d1e980146e" + resolved "https://registry.npmjs.org/@parcel/workers/-/workers-2.5.0.tgz#c7f1a4bcd491c7422212724dedbcf7d1e980146e" integrity sha512-/Ow5OKJWs+9OzV3Jy4J++VnbNx0j3ls/M1CGVBLiBWyCada9DMtquYoBQ4Sk6Uam50BKkIFYetGOeXPNQyyMjg== dependencies: "@parcel/diagnostic" "2.5.0" @@ -4442,22 +4556,22 @@ "@prefresh/babel-plugin@^0.4.3": version "0.4.3" - resolved "https://registry.yarnpkg.com/@prefresh/babel-plugin/-/babel-plugin-0.4.3.tgz#175ecf6f7a038d06a83d1806503283c98c7d9865" + resolved "https://registry.npmjs.org/@prefresh/babel-plugin/-/babel-plugin-0.4.3.tgz#175ecf6f7a038d06a83d1806503283c98c7d9865" integrity sha512-fYAWbU1WDSLn108kKY4eDaaeUcnszFqXjgaGKYXNZ5NLulpRTpsrY+Sbfo9q8LDpWrBpqIgzjrwNnvglWI1xNQ== "@prefresh/core@^1.3.3": version "1.3.4" - resolved "https://registry.yarnpkg.com/@prefresh/core/-/core-1.3.4.tgz#90fdf865538e99362db1b352b61d22c2ebc21065" + resolved "https://registry.npmjs.org/@prefresh/core/-/core-1.3.4.tgz#90fdf865538e99362db1b352b61d22c2ebc21065" integrity sha512-s7iNsnyJ3lZEUrYIgmVIB/hKtp4U6mdD91a31Zg7Q8M49O0x2KThrbrMQYraoDDrs4STdFB8Zv6bceUguOoX1A== "@prefresh/utils@^1.1.2": version "1.1.3" - resolved "https://registry.yarnpkg.com/@prefresh/utils/-/utils-1.1.3.tgz#c764c6c8f0917f0a72ae14ec57ed8befde3f9bac" + resolved "https://registry.npmjs.org/@prefresh/utils/-/utils-1.1.3.tgz#c764c6c8f0917f0a72ae14ec57ed8befde3f9bac" integrity sha512-Mb9abhJTOV4yCfkXrMrcgFiFT7MfNOw8sDa+XyZBdq/Ai2p4Zyxqsb3EgHLOEdHpMj6J9aiZ54W8H6FTam1u+A== "@prefresh/webpack@^3.3.3": version "3.3.3" - resolved "https://registry.yarnpkg.com/@prefresh/webpack/-/webpack-3.3.3.tgz#6090d5b7081ad39e926efaae4c344441949b7d0b" + resolved "https://registry.npmjs.org/@prefresh/webpack/-/webpack-3.3.3.tgz#6090d5b7081ad39e926efaae4c344441949b7d0b" integrity sha512-uT+A7ZuA7fuuUPNEde6Gmzr4oFnzreW9xw6iqw01nPpDiv46o6YWq1j0oGCbdffzHl3fBpcgkPuY07vIfmZ9Lg== dependencies: "@prefresh/core" "^1.3.3" @@ -4611,14 +4725,14 @@ "@sinonjs/fake-timers@^8.0.1": version "8.1.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== dependencies: "@sinonjs/commons" "^1.7.0" "@soda/friendly-errors-webpack-plugin@1.8.1": version "1.8.1" - resolved "https://registry.yarnpkg.com/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz#4d4fbb1108993aaa362116247c3d18188a2c6c85" + resolved "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz#4d4fbb1108993aaa362116247c3d18188a2c6c85" integrity sha512-h2ooWqP8XuFqTXT+NyAFbrArzfQA7R6HTezADrvD9Re8fxMLTPPniLdqVTdDaO0eIoLaAwKT+d6w+5GeTk7Vbg== dependencies: chalk "^3.0.0" @@ -4637,7 +4751,7 @@ "@swc/helpers@^0.3.6": version "0.3.8" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.3.8.tgz#5b9ecf4ee480ca00f1ffbc2d1a5d4eed0d1afe81" + resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.8.tgz#5b9ecf4ee480ca00f1ffbc2d1a5d4eed0d1afe81" integrity sha512-aWItSZvJj4+GI6FWkjZR13xPNPctq2RRakzo+O6vN7bC2yjwdg5EFpgaSAUn95b7BGSgcflvzVDPoKmJv24IOg== "@szmarczak/http-timer@^1.1.2": @@ -4691,9 +4805,14 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@trysound/sax@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.1.1.tgz#3348564048e7a2d7398c935d466c0414ebb6a669" + integrity sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow== + "@trysound/sax@0.2.0": version "0.2.0" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== "@turist/fetch@^7.1.7": @@ -4724,9 +4843,9 @@ integrity sha512-imO+jT/yjOKOAS5GQZ8SDtwiIloAGGr6OaZDKB0V5JVaSfGZLat5K5/ZRtyKW6R60XHV3RHYPTFfhYb+wDKyKg== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.12", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.15": - version "7.1.16" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.16.tgz#bc12c74b7d65e82d29876b5d0baf5c625ac58702" - integrity sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ== + version "7.1.18" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" + integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -4750,9 +4869,9 @@ "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6", "@types/babel__traverse@^7.11.1": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" - integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + version "7.11.1" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.11.1.tgz#654f6c4f67568e24c23b367e947098c6206fa639" + integrity sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw== dependencies: "@babel/types" "^7.3.0" @@ -4857,7 +4976,7 @@ "@types/eslint@*", "@types/eslint@^8.2.1": version "8.2.1" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.2.1.tgz#13f3d69bac93c2ae008019c28783868d0a1d6605" + resolved "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz#13f3d69bac93c2ae008019c28783868d0a1d6605" integrity sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ== dependencies: "@types/estree" "*" @@ -4865,7 +4984,7 @@ "@types/eslint@^7.28.2": version "7.29.0" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.29.0.tgz#e56ddc8e542815272720bb0b4ccc2aff9c3e1c78" + resolved "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz#e56ddc8e542815272720bb0b4ccc2aff9c3e1c78" integrity sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng== dependencies: "@types/estree" "*" @@ -4886,7 +5005,7 @@ "@types/express-http-proxy@^1.6.3": version "1.6.3" - resolved "https://registry.yarnpkg.com/@types/express-http-proxy/-/express-http-proxy-1.6.3.tgz#35fc0fb32e7741bc50619869de381ef759621fd0" + resolved "https://registry.npmjs.org/@types/express-http-proxy/-/express-http-proxy-1.6.3.tgz#35fc0fb32e7741bc50619869de381ef759621fd0" integrity sha512-dX3+Cb0HNPtqhC5JUWzzuODHRlgJRZx7KvwKVVwkOvm+8vOtpsh3qy8+qLv5X1hs4vdVHWKyXf86DwJot5H8pg== dependencies: "@types/express" "*" @@ -5018,9 +5137,9 @@ prom-client "~11.3.0 || ^12.0.0 || ^13.0.0" "@types/jest@^27.0.2": - version "27.0.2" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.0.2.tgz#ac383c4d4aaddd29bbf2b916d8d105c304a5fcd7" - integrity sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA== + version "27.4.0" + resolved "https://registry.npmjs.org/@types/jest/-/jest-27.4.0.tgz#037ab8b872067cae842a320841693080f9cb84ed" + integrity sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ== dependencies: jest-diff "^27.0.0" pretty-format "^27.0.0" @@ -5035,9 +5154,14 @@ resolved "https://registry.yarnpkg.com/@types/js-levenshtein/-/js-levenshtein-1.1.1.tgz#ba05426a43f9e4e30b631941e0aa17bf0c890ed5" integrity sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g== -"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8": +"@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8": + version "7.0.9" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== + +"@types/json-schema@^7.0.4": version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== "@types/json5@^0.0.29": @@ -5111,9 +5235,9 @@ integrity sha512-sRVq8d+ApGslmkE9e3i+D3gFGk7aZHAT+G4cIpIEdLJYPsWiSPwcAnJEjddLQQDqV3Ra2jOclX/Sv6YrvGYiWA== "@types/node@^14.10.2", "@types/node@^14.17.34": - version "14.17.34" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.34.tgz#fe4b38b3f07617c0fa31ae923fca9249641038f0" - integrity sha512-USUftMYpmuMzeWobskoPfzDi+vkpe0dvcOBRNOscFrGxVp4jomnRxWuVohgqBow2xyIPC0S3gjxV/5079jhmDg== + version "14.18.5" + resolved "https://registry.npmjs.org/@types/node/-/node-14.18.5.tgz#0dd636fe7b2c6055cbed0d4ca3b7fb540f130a96" + integrity sha512-LMy+vDDcQR48EZdEx5wRX1q/sEl6NdGuHXPnfeL8ixkwCOSZ2qnIyIZmcCbdX0MeRqHhAcHmX+haCbrS8Run+A== "@types/node@^15.0.1": version "15.0.1" @@ -5145,9 +5269,9 @@ integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw== "@types/prettier@^2.1.5": - version "2.3.2" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.3.2.tgz#fc8c2825e4ed2142473b4a81064e6e081463d1b3" - integrity sha512-eI5Yrz3Qv4KPUa/nSIAi0h+qX0XyewOliug5F2QAtuRg6Kjg6jfmxe1GIwoIRhZspD1A0RP8ANrPwvEXXtRFog== + version "2.4.2" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz#4c62fae93eb479660c3bd93f9d24d561597a8281" + integrity sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA== "@types/prop-types@*", "@types/prop-types@^15.7.3": version "15.7.3" @@ -5175,26 +5299,33 @@ dependencies: "@types/react" "*" -"@types/react-dom@^17.0.13", "@types/react-dom@^17.0.9": - version "17.0.13" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.13.tgz#a3323b974ee4280070982b3112351bb1952a7809" - integrity sha512-wEP+B8hzvy6ORDv1QBhcQia4j6ea4SFIBttHYpXKPFZRviBvknq0FRh3VrIxeXUmsPkwuXVZrVGG7KUVONmXCQ== +"@types/react-dom@^17.0.13": + version "17.0.15" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.15.tgz#f2c8efde11521a4b7991e076cb9c70ba3bb0d156" + integrity sha512-Tr9VU9DvNoHDWlmecmcsE5ZZiUkYx+nKBzum4Oxe1K0yJVyBlfbq7H3eXjxXqJczBKqPGq3EgfTru4MgKb9+Yw== + dependencies: + "@types/react" "^17" + +"@types/react-dom@^17.0.9": + version "17.0.9" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.9.tgz#441a981da9d7be117042e1a6fd3dac4b30f55add" + integrity sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg== dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^17.0.40": - version "17.0.40" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.40.tgz#dc010cee6254d5239a138083f3799a16638e6bad" - integrity sha512-UrXhD/JyLH+W70nNSufXqMZNuUD2cXHu6UjCllC6pmOQgBX4SGXOH8fjRka0O0Ee0HrFxapDD8Bwn81Kmiz6jQ== +"@types/react@*", "@types/react@^16.14.8": + version "16.14.8" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.8.tgz#4aee3ab004cb98451917c9b7ada3c7d7e52db3fe" + integrity sha512-QN0/Qhmx+l4moe7WJuTxNiTsjBwlBGHqKGvInSQCBdo7Qio0VtOqwsC0Wq7q3PbJlB0cR4Y4CVo1OOe6BOsOmA== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@^16.14.8": - version "16.14.8" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.8.tgz#4aee3ab004cb98451917c9b7ada3c7d7e52db3fe" - integrity sha512-QN0/Qhmx+l4moe7WJuTxNiTsjBwlBGHqKGvInSQCBdo7Qio0VtOqwsC0Wq7q3PbJlB0cR4Y4CVo1OOe6BOsOmA== +"@types/react@^17", "@types/react@^17.0.40": + version "17.0.44" + resolved "https://registry.npmjs.org/@types/react/-/react-17.0.44.tgz#c3714bd34dd551ab20b8015d9d0dbec812a51ec7" + integrity sha512-Ye0nlw09GeMp2Suh8qoOv0odfgCoowfM/9MG6WeRD60Gq9wS90bdkdRtYbRkNhXOpG4H+YXGvj4wOWhAC0LJ1g== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -5263,9 +5394,9 @@ "@types/node" "*" "@types/sharp@^0.30.0": - version "0.30.0" - resolved "https://registry.yarnpkg.com/@types/sharp/-/sharp-0.30.0.tgz#58cb016c8fdc558b4c5771ad1f3668336685c843" - integrity sha512-bZ0Y/JVlrOyqwlBMJ2taEgnwFavjLnyZmLOLecmOesuG5kR2Lx9b2fM4osgfVjLJi8UlE+t3R1JzRVMxF6MbfA== + version "0.30.2" + resolved "https://registry.npmjs.org/@types/sharp/-/sharp-0.30.2.tgz#df5ff34140b3bad165482e6f3d26b08e42a0503a" + integrity sha512-uLCBwjDg/BTcQit0dpNGvkIjvH3wsb8zpaJePCjvONBBSfaKHoxXBIuq1MT8DMQEfk2fKYnpC9QExCgFhkGkMQ== dependencies: "@types/node" "*" @@ -5289,9 +5420,9 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" "@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" + integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw== "@types/string-similarity@^4.0.0": version "4.0.0" @@ -5421,7 +5552,7 @@ "@typescript-eslint/eslint-plugin@^4.33.0": version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== dependencies: "@typescript-eslint/experimental-utils" "4.33.0" @@ -5435,7 +5566,7 @@ "@typescript-eslint/experimental-utils@4.33.0": version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" + resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== dependencies: "@types/json-schema" "^7.0.7" @@ -5447,7 +5578,7 @@ "@typescript-eslint/parser@^4.33.0": version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== dependencies: "@typescript-eslint/scope-manager" "4.33.0" @@ -5457,7 +5588,7 @@ "@typescript-eslint/scope-manager@4.33.0": version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== dependencies: "@typescript-eslint/types" "4.33.0" @@ -5465,12 +5596,12 @@ "@typescript-eslint/types@4.33.0": version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== "@typescript-eslint/typescript-estree@4.33.0": version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== dependencies: "@typescript-eslint/types" "4.33.0" @@ -5483,7 +5614,7 @@ "@typescript-eslint/visitor-keys@4.33.0": version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== dependencies: "@typescript-eslint/types" "4.33.0" @@ -5696,7 +5827,7 @@ "@wry/equality@^0.5.0": version "0.5.2" - resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.2.tgz#72c8a7a7d884dff30b612f4f8464eba26c080e73" + resolved "https://registry.npmjs.org/@wry/equality/-/equality-0.5.2.tgz#72c8a7a7d884dff30b612f4f8464eba26c080e73" integrity sha512-oVMxbUXL48EV/C0/M7gLVsoK6qRHPS85x8zECofEZOVvxGmIPLA9o5Z27cc2PoAyZz1S2VoM2A7FLAnpfGlneA== dependencies: tslib "^2.3.0" @@ -5795,7 +5926,7 @@ accepts@^1.3.7, accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: accessible-nprogress@^2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/accessible-nprogress/-/accessible-nprogress-2.1.2.tgz#8e65ebf4936db1752638e1cd2e8730f9bef311e9" + resolved "https://registry.npmjs.org/accessible-nprogress/-/accessible-nprogress-2.1.2.tgz#8e65ebf4936db1752638e1cd2e8730f9bef311e9" integrity sha512-reIwMbbt+ZGOmQLWPXGcPf5X1F4fzsZAekY9alCxpekxizRhQMAd/QInaA8k7WtwTcGMzD9hnYswGLcaJDRY/A== acorn-globals@^4.3.2: @@ -5867,11 +5998,16 @@ add-stream@^1.0.0: resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= -address@1.1.2, address@^1.0.1, address@^1.1.2: +address@1.1.2, address@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== +address@^1.1.2: + version "1.2.0" + resolved "https://registry.npmjs.org/address/-/address-1.2.0.tgz#d352a62c92fee90f89a693eccd2a8b2139ab02d9" + integrity sha512-tNEZYz5G/zYunxFm7sfhAxkXEuLj3K6BKwv6ZURlsF6yiUQ65z0Q2wZW9L5cPUl9ocofGvXOdFYbFHp0+6MOig== + adjust-sourcemap-loader@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz#5ae12fb5b7b1c585e80bbb5a63ec163a1a45e61e" @@ -5930,7 +6066,7 @@ agentkeepalive@^3.4.1: agentkeepalive@^4.2.1: version "4.2.1" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717" integrity sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA== dependencies: debug "^4.1.0" @@ -6033,10 +6169,10 @@ ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: ansi-html-community@0.0.8: version "0.0.8" - resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + resolved "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== -ansi-html@^0.0.7: +ansi-html@0.0.7, ansi-html@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" @@ -6060,7 +6196,7 @@ ansi-regex@^4.0.0, ansi-regex@^4.1.0: ansi-regex@^5.0.0, ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^2.2.1: @@ -6120,7 +6256,7 @@ apache-md5@1.1.2: apollo-upload-client@17.0.0: version "17.0.0" - resolved "https://registry.yarnpkg.com/apollo-upload-client/-/apollo-upload-client-17.0.0.tgz#d9baaff8d14e54510de9f2855b487e75ca63b392" + resolved "https://registry.npmjs.org/apollo-upload-client/-/apollo-upload-client-17.0.0.tgz#d9baaff8d14e54510de9f2855b487e75ca63b392" integrity sha512-pue33bWVbdlXAGFPkgz53TTmxVMrKeQr0mdRcftNY+PoHIdbGZD0hoaXHvO6OePJAkFz7OiCFUf98p1G/9+Ykw== dependencies: extract-files "^11.0.0" @@ -6280,7 +6416,7 @@ array.prototype.flat@^1.2.5: array.prototype.flatmap@^1.2.5: version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" + resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== dependencies: call-bind "^1.0.0" @@ -6495,9 +6631,21 @@ autolinker@~0.28.0: dependencies: gulp-header "^1.7.1" -autoprefixer@^10.1.0, autoprefixer@^10.4.0, autoprefixer@^10.4.4: +autoprefixer@^10.1.0, autoprefixer@^10.4.0: + version "10.4.2" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.2.tgz#25e1df09a31a9fba5c40b578936b90d35c9d4d3b" + integrity sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ== + dependencies: + browserslist "^4.19.1" + caniuse-lite "^1.0.30001297" + fraction.js "^4.1.2" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + +autoprefixer@^10.4.4: version "10.4.4" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" + resolved "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== dependencies: browserslist "^4.20.2" @@ -6517,7 +6665,7 @@ aws4@^1.8.0: axe-core@^4.3.5: version "4.3.5" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5" + resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.3.5.tgz#78d6911ba317a8262bfee292aeafcc1e04b49cc5" integrity sha512-WKTW1+xAzhMS5dJsxWkliixlO/PqC4VhmO9T4juNYcaTg9jzWiJsou6m5pxWYGfigWbwzJWeFY6z47a+4neRXA== axios-rate-limit@^1.3.0: @@ -6552,15 +6700,15 @@ babel-extract-comments@^1.0.0: dependencies: babylon "^6.18.0" -babel-jest@^27.2.1, babel-jest@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.4.4.tgz#a012441f8a155df909839543a09510ab3477aa11" - integrity sha512-+6RVutZxOQgJkt4svgTHPFtOQlVe9dUg3wrimIAM38pY6hL/nsL8glfFSUjD9jNVjaVjzkCzj6loFFecrjr9Qw== +babel-jest@^27.2.1, babel-jest@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.6.tgz#4d024e69e241cdf4f396e453a07100f44f7ce314" + integrity sha512-qZL0JT0HS1L+lOuH+xC2DVASR3nunZi/ozGhpgauJHgmI7f8rudxf6hUjEHympdQ/J64CdKmPkgfJ+A3U6QCrg== dependencies: - "@jest/transform" "^27.4.4" + "@jest/transform" "^27.4.6" "@jest/types" "^27.4.2" "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.0.0" + babel-plugin-istanbul "^6.1.1" babel-preset-jest "^27.4.0" chalk "^4.0.0" graceful-fs "^4.2.4" @@ -6629,20 +6777,20 @@ babel-plugin-import-globals@^2.0.0: dependencies: "@babel/helper-module-imports" "^7.0.0" -babel-plugin-istanbul@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" - integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@istanbuljs/load-nyc-config" "^1.0.0" "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" babel-plugin-jest-hoist@^27.4.0: version "27.4.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz#d7831fc0f93573788d80dee7e682482da4c730d6" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz#d7831fc0f93573788d80dee7e682482da4c730d6" integrity sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw== dependencies: "@babel/template" "^7.3.3" @@ -6670,9 +6818,18 @@ babel-plugin-macros@^2.6.1, babel-plugin-macros@^2.8.0: cosmiconfig "^6.0.0" resolve "^1.12.0" -babel-plugin-macros@^3.0.1, babel-plugin-macros@^3.1.0: +babel-plugin-macros@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.0.1.tgz#0d412d68f5b3d1b64358f24ab099bd148724e2a9" + integrity sha512-CKt4+Oy9k2wiN+hT1uZzOw7d8zb1anbQpf7KLwaaXRCi/4pzKdFKHf7v5mvoPmjkmxshh7eKZQuRop06r5WP4w== + dependencies: + "@babel/runtime" "^7.12.5" + cosmiconfig "^7.0.0" + resolve "^1.19.0" + +babel-plugin-macros@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" + resolved "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== dependencies: "@babel/runtime" "^7.12.5" @@ -6756,7 +6913,7 @@ babel-plugin-syntax-object-rest-spread@^6.8.0: babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0: version "7.0.0-beta.0" - resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" + resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf" integrity sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ== babel-plugin-transform-async-to-promises@^0.8.15: @@ -6803,7 +6960,7 @@ babel-preset-current-node-syntax@^1.0.0: babel-preset-fbjs@^3.4.0: version "3.4.0" - resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz#38a14e5a7a3b285a3f3a86552d650dca5cf6111c" + resolved "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz#38a14e5a7a3b285a3f3a86552d650dca5cf6111c" integrity sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow== dependencies: "@babel/plugin-proposal-class-properties" "^7.0.0" @@ -6836,7 +6993,7 @@ babel-preset-fbjs@^3.4.0: babel-preset-jest@^27.4.0: version "27.4.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz#70d0e676a282ccb200fbabd7f415db5fdf393bca" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz#70d0e676a282ccb200fbabd7f415db5fdf393bca" integrity sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg== dependencies: babel-plugin-jest-hoist "^27.4.0" @@ -7011,9 +7168,25 @@ body-parser@1.19.0: raw-body "2.4.0" type-is "~1.6.17" -body-parser@^1.19.0, body-parser@^1.20.0: +body-parser@^1.19.0: + version "1.19.1" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" + integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA== + dependencies: + bytes "3.1.1" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.9.6" + raw-body "2.4.2" + type-is "~1.6.18" + +body-parser@^1.20.0: version "1.20.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.0.tgz#3de69bd89011c11573d7bfee6a64f11b6bd27cc5" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz#3de69bd89011c11573d7bfee6a64f11b6bd27cc5" integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== dependencies: bytes "3.1.2" @@ -7104,7 +7277,7 @@ braces@^2.3.1: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.2, braces@~3.0.2: +braces@^3.0.1, braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -7152,9 +7325,20 @@ browserify-optional@^1.0.0: ast-types "^0.7.0" browser-resolve "^1.8.1" -browserslist@^4.0.0, browserslist@^4.13.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.3, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.18.1, browserslist@^4.20.2, browserslist@^4.6.6: +browserslist@^4.0.0, browserslist@^4.13.0, browserslist@^4.14.5, browserslist@^4.16.0, browserslist@^4.16.3, browserslist@^4.16.6, browserslist@^4.17.5, browserslist@^4.19.1, browserslist@^4.6.6: + version "4.19.1" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz#4ac0435b35ab655896c31d53018b6dd5e9e4c9a3" + integrity sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A== + dependencies: + caniuse-lite "^1.0.30001286" + electron-to-chromium "^1.4.17" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + +browserslist@^4.18.1: version "4.20.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.3.tgz#eb7572f49ec430e054f56d52ff0ebe9be915f8bf" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz#eb7572f49ec430e054f56d52ff0ebe9be915f8bf" integrity sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg== dependencies: caniuse-lite "^1.0.30001332" @@ -7163,6 +7347,17 @@ browserslist@^4.0.0, browserslist@^4.13.0, browserslist@^4.14.5, browserslist@^4 node-releases "^2.0.3" picocolors "^1.0.0" +browserslist@^4.20.2: + version "4.20.2" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" + integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== + dependencies: + caniuse-lite "^1.0.30001317" + electron-to-chromium "^1.4.84" + escalade "^3.1.1" + node-releases "^2.0.2" + picocolors "^1.0.0" + bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -7278,9 +7473,14 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== +bytes@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" + integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== + bytes@3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== c8@^7.6.0: @@ -7354,7 +7554,7 @@ cache-manager@^2.11.1: cache-manager@^3.6.1: version "3.6.1" - resolved "https://registry.yarnpkg.com/cache-manager/-/cache-manager-3.6.1.tgz#44f93b7a42265cb653cdebcffc311b5bdfb62596" + resolved "https://registry.npmjs.org/cache-manager/-/cache-manager-3.6.1.tgz#44f93b7a42265cb653cdebcffc311b5bdfb62596" integrity sha512-jxJvGYhN5dUgpriAdsDnnYbKse4dEXI5i3XpwTfPq5utPtXH1uYXWyGLHGlbSlh9Vq4ytrgAUVwY+IodNeKigA== dependencies: async "3.2.3" @@ -7381,7 +7581,7 @@ cacheable-request@^6.0.0: cacheable-request@^7.0.2: version "7.0.2" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" + resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== dependencies: clone-response "^1.0.2" @@ -7523,14 +7723,24 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001317, caniuse-lite@^1.0.30001332: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001286, caniuse-lite@^1.0.30001297: + version "1.0.30001304" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001304.tgz#38af55ed3fc8220cb13e35e6e7309c8c65a05559" + integrity sha512-bdsfZd6K6ap87AGqSHJP/s1V+U6Z5lyrcbBu3ovbCCf8cSYpwTtGrCBObMpJqwxfTbLW6YTIdbb1jEeTelcpYQ== + +caniuse-lite@^1.0.30001317: version "1.0.30001332" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz#39476d3aa8d83ea76359c70302eafdd4a1d727dd" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz#39476d3aa8d83ea76359c70302eafdd4a1d727dd" integrity sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw== +caniuse-lite@^1.0.30001332: + version "1.0.30001341" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz#59590c8ffa8b5939cf4161f00827b8873ad72498" + integrity sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA== + capital-case@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" + resolved "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" integrity sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A== dependencies: no-case "^3.0.4" @@ -7569,7 +7779,7 @@ cfb@~1.2.1: chalk@4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz#c80b3fab28bf6371e6863325eee67e618b77e6ad" integrity sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg== dependencies: ansi-styles "^4.1.0" @@ -7612,7 +7822,7 @@ chalk@^4.0, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: change-case-all@1.0.14: version "1.0.14" - resolved "https://registry.yarnpkg.com/change-case-all/-/change-case-all-1.0.14.tgz#bac04da08ad143278d0ac3dda7eccd39280bfba1" + resolved "https://registry.npmjs.org/change-case-all/-/change-case-all-1.0.14.tgz#bac04da08ad143278d0ac3dda7eccd39280bfba1" integrity sha512-CWVm2uT7dmSHdO/z1CXT/n47mWonyypzBbuCy5tN7uMg22BsfkhwT6oHmFCAk+gL1LOOxhdbB9SZz3J1KTY3gA== dependencies: change-case "^4.1.2" @@ -7652,7 +7862,7 @@ change-case@^3.0.1, change-case@^3.1.0: change-case@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" + resolved "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz#fedfc5f136045e2398c0410ee441f95704641e12" integrity sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A== dependencies: camel-case "^4.1.2" @@ -7790,12 +8000,12 @@ ci-info@^1.5.0: ci-info@^3.2.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== cjs-module-lexer@^1.0.0: version "1.2.2" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== clap@^1.0.9: @@ -8034,7 +8244,7 @@ coffee-script@^1.12.4: coffeescript@^2.7.0: version "2.7.0" - resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-2.7.0.tgz#a43ec03be6885d6d1454850ea70b9409c391279c" + resolved "https://registry.npmjs.org/coffeescript/-/coffeescript-2.7.0.tgz#a43ec03be6885d6d1454850ea70b9409c391279c" integrity sha512-hzWp6TUE2d/jCcN67LrW1eh5b/rSDKQK6oD6VMLlggYVUUFexgTH9z3dNYihzX4RMhze5FTUsUmOXViJKFQR/A== collapse-white-space@^1.0.0, collapse-white-space@^1.0.2, collapse-white-space@^1.0.4: @@ -8093,9 +8303,9 @@ color@^3.0.0, color@^3.1.1: color-string "^1.5.4" color@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/color/-/color-4.2.1.tgz#498aee5fce7fc982606c8875cab080ac0547c884" - integrity sha512-MFJr0uY4RvTQUKvPq7dh9grVOTYSFeXja2mBXioCGjnjJoXrAp9jJ1NQTDR73c9nwBSAQiNKloKl5zq9WB9UPw== + version "4.2.3" + resolved "https://registry.npmjs.org/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a" + integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A== dependencies: color-convert "^2.0.1" color-string "^1.9.0" @@ -8158,7 +8368,7 @@ commander@^6.0.0, commander@^6.1.0, commander@^6.2.0: resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== -commander@^7.0.0, commander@^7.2.0: +commander@^7.0.0, commander@^7.1.0, commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== @@ -8173,7 +8383,7 @@ common-path-prefix@^1.0.0: common-tags@1.8.2, common-tags@^1.8.0, common-tags@^1.8.2: version "1.8.2" - resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" + resolved "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== commondir@^1.0.1: @@ -8318,7 +8528,7 @@ constant-case@^2.0.0: constant-case@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" + resolved "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz#3b84a9aeaf4cf31ec45e6bf5de91bdfb0589faf1" integrity sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ== dependencies: no-case "^3.0.4" @@ -8344,9 +8554,9 @@ contentful-resolve-response@^1.3.0: fast-copy "^2.1.0" contentful-sdk-core@^6.8.5: - version "6.10.3" - resolved "https://registry.yarnpkg.com/contentful-sdk-core/-/contentful-sdk-core-6.10.3.tgz#983fd69257c239881c43cb83e3ce9f501acfbe4a" - integrity sha512-IUBkAU1sJuVaEa2Nv1NKK5ImqpBZ5Q3EmaCFmMZx/UHKa+i98nDCSTUBOL1aJnpZ/s3AaSramsh73VQ4aK2kyA== + version "6.10.4" + resolved "https://registry.npmjs.org/contentful-sdk-core/-/contentful-sdk-core-6.10.4.tgz#3a077bd1017e107224101551d44834e77e62175e" + integrity sha512-vnivU13pKqFzs/eEugqOaDkKce6ZljBkpp6l25MsG8LA1HPCQNBnIkqP5VUbwk/ub7tkHteV9HtoTnmpdvB+Zg== dependencies: fast-copy "^2.1.0" lodash.isplainobject "^4.0.6" @@ -8356,7 +8566,7 @@ contentful-sdk-core@^6.8.5: contentful@^8.5.8: version "8.5.8" - resolved "https://registry.yarnpkg.com/contentful/-/contentful-8.5.8.tgz#ad2f3549d1795310e104a6c33325352524f7bd77" + resolved "https://registry.npmjs.org/contentful/-/contentful-8.5.8.tgz#ad2f3549d1795310e104a6c33325352524f7bd77" integrity sha512-6YyE95uDJYTyGKQYtqYrMzdDZe3sLkrC0UEnpXuIOeciGACRQP9ouTjRJnLMa5ONUPt0+UJh7JH3epNouPZWIw== dependencies: axios "^0.21.1" @@ -8698,10 +8908,15 @@ core-js@^2.4.0, core-js@^2.4.1, core-js@^2.6.5: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== -core-js@^3.16.0, core-js@^3.22.3: - version "3.22.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.3.tgz#498c41d997654cb00e81c7a54b44f0ab21ab01d5" - integrity sha512-1t+2a/d2lppW1gkLXx3pKPVGbBdxXAkqztvWb1EJ8oF8O2gIGiytzflNiFEehYwVK/t2ryUsGBoOFFvNx95mbg== +core-js@^3.16.0: + version "3.17.2" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.17.2.tgz#f960eae710dc62c29cca93d5332e3660e289db10" + integrity sha512-XkbXqhcXeMHPRk2ItS+zQYliAMilea2euoMsnpRRdDad6b2VY6CQQcwz1K8AnWesfw4p165RzY0bTnr3UrbYiA== + +core-js@^3.22.3: + version "3.22.5" + resolved "https://registry.npmjs.org/core-js/-/core-js-3.22.5.tgz#a5f5a58e663d5c0ebb4e680cd7be37536fb2a9cf" + integrity sha512-VP/xYuvJ0MJWRAobcmQ8F2H6Bsn+s7zqAAjFaHGBMc5AQm7zaelhD1LGduFn2EehEcQcU+br6t+fwbpQ5d1ZWA== core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" @@ -8784,7 +8999,14 @@ cpy@^8.0.0: p-filter "^2.1.0" p-map "^3.0.0" -crc-32@~1.2.0, crc-32@~1.2.1: +crc-32@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.0.tgz#cb2db6e29b88508e32d9dd0ec1693e7b41a18208" + dependencies: + exit-on-epipe "~1.0.1" + printj "~1.1.0" + +crc-32@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.1.tgz#436d2bcaad27bcb6bd073a2587139d3024a16460" integrity sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w== @@ -8833,7 +9055,7 @@ cross-fetch@3.0.6: cross-fetch@^3.1.5: version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== dependencies: node-fetch "2.6.7" @@ -8927,7 +9149,7 @@ css-list-helpers@^2.0.0: css-loader@^5.2.7: version "5.2.7" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.7.tgz#9b9f111edf6fb2be5dc62525644cbc9c232064ae" + resolved "https://registry.npmjs.org/css-loader/-/css-loader-5.2.7.tgz#9b9f111edf6fb2be5dc62525644cbc9c232064ae" integrity sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg== dependencies: icss-utils "^5.1.0" @@ -8999,6 +9221,17 @@ css-select@^2.0.0: domutils "^1.7.0" nth-check "^1.0.1" +css-select@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-3.1.2.tgz#d52cbdc6fee379fba97fb0d3925abbd18af2d9d8" + integrity sha512-qmss1EihSuBNWNNhHjxzxSfJoFBM/lERB/Q4EnsJQQC62R2evJDW481091oAdOr9uh46/0n4nrg0It5cAnj1RA== + dependencies: + boolbase "^1.0.0" + css-what "^4.0.0" + domhandler "^4.0.0" + domutils "^2.4.3" + nth-check "^2.0.0" + css-select@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" @@ -9056,6 +9289,11 @@ css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" +css-what@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-4.0.0.tgz#35e73761cab2eeb3d3661126b23d7aa0e8432233" + integrity sha512-teijzG7kwYfNVsUh2H/YN62xW3KK9YhXEgSlbxMlcyjPNvdKJqFx5lrwlJgoFP1ZHlB89iGDlo/JyshKeRhv5A== + css-what@^5.0.0, css-what@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" @@ -9241,7 +9479,7 @@ cssstyle@^2.0.0, cssstyle@^2.3.0: csstype@^3.0.2: version "3.0.10" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== csvtojson@^2.0.10: @@ -9282,7 +9520,7 @@ d@1, d@^1.0.1: damerau-levenshtein@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d" + resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.7.tgz#64368003512a1a6992593741a09a9d31a836f55d" integrity sha512-VvdQIPGdWP0SqFXghj79Wf/5LArmreyMsGLa6FG6iC4t3j7j5s71TrwWmT/4akbDQIqjfACkLZmjXhA7g2oUZw== danger@^10.6.4: @@ -9361,14 +9599,14 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -dataloader@2.0.0: +dataloader@2.0.0, dataloader@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.0.0.tgz#41eaf123db115987e21ca93c005cd7753c55fe6f" integrity sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ== -dataloader@2.1.0, dataloader@^2.0.0: +dataloader@2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/dataloader/-/dataloader-2.1.0.tgz#c69c538235e85e7ac6c6c444bae8ecabf5de9df7" + resolved "https://registry.npmjs.org/dataloader/-/dataloader-2.1.0.tgz#c69c538235e85e7ac6c6c444bae8ecabf5de9df7" integrity sha512-qTcEYLen3r7ojZNgVUaRggOI+KM7jrKxXeSHhogh/TWxYMeONEMqY+hmkobiYQozsGIyg9OYVzO4ZIfoB4I0pQ== dataloader@^1.4.0: @@ -9383,7 +9621,7 @@ date-fns@^1.30.1: date-fns@^2.25.0, date-fns@^2.28.0: version "2.28.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" + resolved "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== dateformat@^3.0.0: @@ -9411,10 +9649,10 @@ debug@3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.3, debug@~4.3.1: + version "4.3.3" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== dependencies: ms "2.1.2" @@ -9425,6 +9663,13 @@ debug@^3.0.0, debug@^3.0.1, debug@^3.1.0, debug@^3.2.6, debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" @@ -9446,9 +9691,9 @@ decamelize@^5.0.0: integrity sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA== decimal.js@^10.2.1: - version "10.3.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" - integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + version "10.2.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" + integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw== decode-uri-component@^0.2.0: version "0.2.0" @@ -9546,7 +9791,7 @@ deferred-leveldown@~5.2.1: define-lazy-prop@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + resolved "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== define-properties@^1.1.2, define-properties@^1.1.3: @@ -9661,7 +9906,7 @@ depd@^1.1.2, depd@~1.1.2: dependency-graph@^0.11.0: version "0.11.0" - resolved "https://registry.yarnpkg.com/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" + resolved "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz#ac0ce7ed68a54da22165a85e97a01d53f5eb2e27" integrity sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg== deprecation@^2.0.0, deprecation@^2.3.1: @@ -9671,7 +9916,7 @@ deprecation@^2.0.0, deprecation@^2.3.1: destroy@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== destroy@~1.0.4: @@ -9703,9 +9948,14 @@ detect-libc@^1.0.3: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= -detect-libc@^2.0.0, detect-libc@^2.0.1: +detect-libc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.0.tgz#c528bc09bc6d1aa30149228240917c225448f204" + integrity sha512-S55LzUl8HUav8l9E2PBTlC5PAJrHK7tkM+XXFGD+fbsbkTzhCpG6K05LxJcUOEWzMa4v6ptcMZ9s3fOdJDu0Zw== + +detect-libc@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== detect-newline@^3.0.0, detect-newline@^3.1.0: @@ -9715,7 +9965,7 @@ detect-newline@^3.0.0, detect-newline@^3.1.0: detect-port-alt@^1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" + resolved "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275" integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q== dependencies: address "^1.0.1" @@ -9808,7 +10058,7 @@ diff-sequences@^24.9.0: diff-sequences@^27.4.0: version "27.4.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" integrity sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww== diff@^4.0.1: @@ -10069,7 +10319,7 @@ domutils@^1.5.1, domutils@^1.7.0: dom-serializer "0" domelementtype "1" -domutils@^2.0.0, domutils@^2.5.2, domutils@^2.6.0, domutils@^2.7.0: +domutils@^2.0.0, domutils@^2.4.3, domutils@^2.5.2, domutils@^2.6.0, domutils@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.7.0.tgz#8ebaf0c41ebafcf55b0b72ec31c56323712c5442" integrity sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg== @@ -10204,13 +10454,23 @@ ejs@^3.1.6: jake "^10.6.1" electron-to-chromium@^1.4.118: - version "1.4.118" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.118.tgz#2d917c71712dac9652cc01af46c7d0bd51552974" - integrity sha512-maZIKjnYDvF7Fs35nvVcyr44UcKNwybr93Oba2n3HkKDFAtk0svERkLN/HyczJDS3Fo4wU9th9fUQd09ZLtj1w== + version "1.4.137" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz#186180a45617283f1c012284458510cd99d6787f" + integrity sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA== + +electron-to-chromium@^1.4.17: + version "1.4.36" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.36.tgz#446c6184dbe5baeb5eae9a875490831e4bc5319a" + integrity sha512-MbLlbF39vKrXWlFEFpCgDHwdlz4O3LmHM5W4tiLRHjSmEUXjJjz8sZkMgWgvYxlZw3N1iDTmCEtOkkESb5TMCg== + +electron-to-chromium@^1.4.84: + version "1.4.107" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.107.tgz#564257014ab14033b4403a309c813123c58a3fb9" + integrity sha512-Huen6taaVrUrSy8o7mGStByba8PfOWWluHNxSHGBrCgEdFVLtvdQDBr9LBCF9Uci8SYxh28QNNMO0oC17wbGAg== emittery@^0.8.1: version "0.8.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== "emoji-regex@>=6.0.0 <=6.1.1": @@ -10228,7 +10488,7 @@ emoji-regex@^8.0.0: emoji-regex@^9.0.0, emoji-regex@^9.2.2: version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== emojis-list@^2.0.0: @@ -10445,7 +10705,7 @@ es6-promise@^4.0.3, es6-promise@^4.0.5: es6-promise@^4.1.1: version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== es6-promisify@^5.0.0: @@ -10559,7 +10819,7 @@ eslint-config-google@^0.14.0: eslint-config-prettier@^8.5.0: version "8.5.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== eslint-config-react-app@^6.0.0: @@ -10579,7 +10839,7 @@ eslint-import-resolver-node@^0.3.6: eslint-module-utils@^2.7.3: version "2.7.3" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== dependencies: debug "^3.2.7" @@ -10622,7 +10882,7 @@ eslint-plugin-graphql@^4.0.0: eslint-plugin-import@^2.26.0: version "2.26.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz#f812dc47be4f2b72b478a021605a59fc6fe8b88b" integrity sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA== dependencies: array-includes "^3.1.4" @@ -10641,7 +10901,7 @@ eslint-plugin-import@^2.26.0: eslint-plugin-jsx-a11y@^6.5.1: version "6.5.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8" + resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8" integrity sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g== dependencies: "@babel/runtime" "^7.16.3" @@ -10666,12 +10926,12 @@ eslint-plugin-prettier@^4.0.0: eslint-plugin-react-hooks@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.5.0.tgz#5f762dfedf8b2cf431c689f533c9d3fa5dcf25ad" + resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.5.0.tgz#5f762dfedf8b2cf431c689f533c9d3fa5dcf25ad" integrity sha512-8k1gRt7D7h03kd+SAAlzXkQwWK22BnK6GKZG+FJA6BAGy22CFvl8kCIXKpVux0cCxMWDQUPqSok0LKaZ0aOcCw== eslint-plugin-react@^7.29.4: version "7.29.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz#4717de5227f55f3801a5fd51a16a4fa22b5914d2" + resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz#4717de5227f55f3801a5fd51a16a4fa22b5914d2" integrity sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ== dependencies: array-includes "^3.1.4" @@ -10728,7 +10988,7 @@ eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0: eslint-webpack-plugin@^2.6.0: version "2.6.0" - resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-2.6.0.tgz#3bd4ada4e539cb1f6687d2f619073dbb509361cd" + resolved "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-2.6.0.tgz#3bd4ada4e539cb1f6687d2f619073dbb509361cd" integrity sha512-V+LPY/T3kur5QO3u+1s34VDTcRxjXWPUGM4hlmTb5DwVD0OQz631yGTxJZf4SpAqAjdbBVe978S8BJeHpAdOhQ== dependencies: "@types/eslint" "^7.28.2" @@ -10839,7 +11099,7 @@ estraverse@^4.1.1, estraverse@^4.2.0: estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== estraverse@~1.5.0: @@ -10899,7 +11159,7 @@ event-emitter@^0.3.5: event-source-polyfill@1.0.25: version "1.0.25" - resolved "https://registry.yarnpkg.com/event-source-polyfill/-/event-source-polyfill-1.0.25.tgz#d8bb7f99cb6f8119c2baf086d9f6ee0514b6d9c8" + resolved "https://registry.npmjs.org/event-source-polyfill/-/event-source-polyfill-1.0.25.tgz#d8bb7f99cb6f8119c2baf086d9f6ee0514b6d9c8" integrity sha512-hQxu6sN1Eq4JjoI7ITdQeGGUN193A2ra83qC0Ltm9I2UJVAten3OFVN6k5RX4YWeCS0BoC8xg/5czOCIHVosQg== event-stream@=3.3.4: @@ -11067,17 +11327,15 @@ expect@^24.1.0: jest-message-util "^24.9.0" jest-regex-util "^24.9.0" -expect@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.4.2.tgz#4429b0f7e307771d176de9bdf23229b101db6ef6" - integrity sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg== +expect@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/expect/-/expect-27.4.6.tgz#f335e128b0335b6ceb4fcab67ece7cbd14c942e6" + integrity sha512-1M/0kAALIaj5LaG66sFJTbRsWTADnylly82cu4bspI0nl+pgP4E6Bh/aqdHlTUjul06K7xQnnrAoqfxVU0+/ag== dependencies: "@jest/types" "^27.4.2" - ansi-styles "^5.0.0" jest-get-type "^27.4.0" - jest-matcher-utils "^27.4.2" - jest-message-util "^27.4.2" - jest-regex-util "^27.4.0" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" express-graphql@^0.12.0: version "0.12.0" @@ -11091,7 +11349,7 @@ express-graphql@^0.12.0: express-http-proxy@^1.6.3: version "1.6.3" - resolved "https://registry.yarnpkg.com/express-http-proxy/-/express-http-proxy-1.6.3.tgz#f3ef139ffd49a7962e7af0462bbcca557c913175" + resolved "https://registry.npmjs.org/express-http-proxy/-/express-http-proxy-1.6.3.tgz#f3ef139ffd49a7962e7af0462bbcca557c913175" integrity sha512-/l77JHcOUrDUX8V67E287VEUQT0lbm71gdGVoodnlWBziarYKgMcpqT7xvh/HM8Jv52phw8Bd8tY+a7QjOr7Yg== dependencies: debug "^3.0.1" @@ -11189,7 +11447,7 @@ extglob@^2.0.4: extract-files@^11.0.0: version "11.0.0" - resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-11.0.0.tgz#b72d428712f787eef1f5193aff8ab5351ca8469a" + resolved "https://registry.npmjs.org/extract-files/-/extract-files-11.0.0.tgz#b72d428712f787eef1f5193aff8ab5351ca8469a" integrity sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ== extract-zip@^2.0.0: @@ -11252,7 +11510,7 @@ fast-glob@^2.2.6: fast-glob@^3.0.3, fast-glob@^3.1.1, fast-glob@^3.2.11, fast-glob@^3.2.4, fast-glob@^3.2.9: version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== dependencies: "@nodelib/fs.stat" "^2.0.2" @@ -11312,12 +11570,12 @@ fb-watchman@^2.0.0: fbjs-css-vars@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" + resolved "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== fbjs@^3.0.0: version "3.0.4" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6" + resolved "https://registry.npmjs.org/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6" integrity sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ== dependencies: cross-fetch "^3.1.5" @@ -11429,7 +11687,7 @@ filesize@^6.1.0, filesize@^6.4.0: filesize@^8.0.6: version "8.0.7" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8" + resolved "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8" integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ== fill-range@^2.1.0: @@ -11692,9 +11950,9 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" fork-ts-checker-webpack-plugin@^6.5.0: - version "6.5.1" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.1.tgz#fd689e2d9de6ac76abb620909eea56438cd0f232" - integrity sha512-x1wumpHOEf4gDROmKTaB6i4/Q6H3LwmjVO7fIX47vBwlZbtPjU33hgoMuD/Q/y6SU8bnuYSoN6ZQOLshGp0T/g== + version "6.5.2" + resolved "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz#4f67183f2f9eb8ba7df7177ce3cf3e75cdafb340" + integrity sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA== dependencies: "@babel/code-frame" "^7.8.3" "@types/json-schema" "^7.0.5" @@ -11738,7 +11996,7 @@ form-data@^3.0.0: form-data@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" @@ -11766,9 +12024,14 @@ frac@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/frac/-/frac-1.1.2.tgz#3d74f7f6478c88a1b5020306d747dc6313c74d0b" +fraction.js@^4.1.2: + version "4.1.2" + resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz#13e420a92422b6cf244dff8690ed89401029fbe8" + integrity sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA== + fraction.js@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" + resolved "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== fragment-cache@^0.2.1: @@ -11842,7 +12105,7 @@ fs-extra@^1.0.0: fs-extra@^10.1.0: version "10.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== dependencies: graceful-fs "^4.2.0" @@ -11859,7 +12122,7 @@ fs-extra@^4.0.2: fs-extra@^9.0.0: version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== dependencies: at-least-node "^1.0.0" @@ -11904,7 +12167,7 @@ fs.realpath@^1.0.0: fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== function-bind@^1.0.2, function-bind@^1.1.1: @@ -12240,9 +12503,21 @@ glob@^6.0.1: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0, glob@^7.2.3: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.2.3: version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -12275,7 +12550,7 @@ global-modules@^1.0.0: global-modules@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + resolved "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== dependencies: global-prefix "^3.0.0" @@ -12363,7 +12638,7 @@ globby@^10.0.1: globby@^11.0.1, globby@^11.0.3, globby@^11.0.4, globby@^11.1.0: version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" @@ -12410,7 +12685,7 @@ good-listener@^1.2.2: got@^11.8.2, got@^11.8.3: version "11.8.3" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.3.tgz#f496c8fdda5d729a90b4905d2b07dbd148170770" + resolved "https://registry.npmjs.org/got/-/got-11.8.3.tgz#f496c8fdda5d729a90b4905d2b07dbd148170770" integrity sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg== dependencies: "@sindresorhus/is" "^4.0.0" @@ -12514,7 +12789,7 @@ graphql-config@^3.0.2: graphql-executor@0.0.23: version "0.0.23" - resolved "https://registry.yarnpkg.com/graphql-executor/-/graphql-executor-0.0.23.tgz#205c1764b39ee0fcf611553865770f37b45851a2" + resolved "https://registry.npmjs.org/graphql-executor/-/graphql-executor-0.0.23.tgz#205c1764b39ee0fcf611553865770f37b45851a2" integrity sha512-3Ivlyfjaw3BWmGtUSnMpP/a4dcXCp0mJtj0PiPG14OKUizaMKlSEX+LX2Qed0LrxwniIwvU6B4w/koVjEPyWJg== graphql-language-service-interface@^2.8.2: @@ -12577,7 +12852,7 @@ graphql-request@^1.8.2: graphql-tag@^2.11.0, graphql-tag@^2.12.3: version "2.12.6" - resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" + resolved "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1" integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== dependencies: tslib "^2.1.0" @@ -12594,7 +12869,7 @@ graphql-ws@^4.1.0: graphql@^15.7.2, graphql@^15.8.0: version "15.8.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" + resolved "https://registry.npmjs.org/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== graphql@^16.3.0: @@ -12629,7 +12904,6 @@ gray-percentage@^2.0.0: growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= gulp-header@^1.7.1: version "1.8.12" @@ -12940,7 +13214,7 @@ header-case@^1.0.0: header-case@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" + resolved "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz#5a42e63b55177349cf405beb8d775acabb92c063" integrity sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q== dependencies: capital-case "^1.0.4" @@ -13044,9 +13318,14 @@ html-entities@^1.2.1: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== +html-entities@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.1.0.tgz#f5de1f8d5e1f16859a74aa73a90f0db502ca723a" + integrity sha512-u+OHVGMH5P1HlaTFp3M4HolRnWepgx5rAnYBo+7/TrBZahuJjgQ4TMv2GjQ4IouGDzkgXYeOI/NQuF95VOUOsQ== + html-entities@^2.3.3: version "2.3.3" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" + resolved "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz#117d7626bece327fc8baace8868fa6f5ef856e46" integrity sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA== html-escaper@^2.0.0: @@ -13181,9 +13460,20 @@ http-errors@1.8.0: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" +http-errors@1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + http-errors@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== dependencies: depd "2.0.0" @@ -13260,7 +13550,7 @@ http2-wrapper@^1.0.0-beta.5.2: http2-wrapper@^2.1.11: version "2.1.11" - resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.1.11.tgz#d7c980c7ffb85be3859b6a96c800b2951ae257ef" + resolved "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz#d7c980c7ffb85be3859b6a96c800b2951ae257ef" integrity sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ== dependencies: quick-lru "^5.1.1" @@ -13404,7 +13694,7 @@ ignore@^4.0.3, ignore@^4.0.6: ignore@^5.0.0, ignore@^5.1.1, ignore@^5.1.4, ignore@^5.1.8, ignore@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== image-q@^1.1.1: @@ -13436,13 +13726,13 @@ immer@^4.0.0: integrity sha512-Q/tm+yKqnKy4RIBmmtISBlhXuSDrB69e9EKTYiIenIKQkXBQir43w+kN/eGiax3wt1J0O1b2fYcNqLSbEcXA7w== immer@^9.0.7: - version "9.0.12" - resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.12.tgz#2d33ddf3ee1d247deab9d707ca472c8c942a0f20" - integrity sha512-lk7UNmSbAukB5B6dh9fnh5D0bJTOFKxVg2cyJWTYrWRfhLrLMBquONcUs3aFq507hNoIZEDDh8lb8UtOizSMhA== + version "9.0.14" + resolved "https://registry.npmjs.org/immer/-/immer-9.0.14.tgz#e05b83b63999d26382bb71676c9d827831248a48" + integrity sha512-ubBeqQutOSLIFCUBN03jGeOS6a3DoYlSYwYJTa+gSKEZKU5redJIqkIdZ3JVv/4RZpfcXdAWH5zCNLWPRv2WDw== immutable@~3.7.6: version "3.7.6" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" + resolved "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" integrity sha1-E7TTyxK++hVIKib+Gy665kAHHks= import-cwd@^3.0.0: @@ -13677,7 +13967,7 @@ inquirer@^7.0.0: inquirer@^8.2.0: version "8.2.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a" + resolved "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz#f44f008dd344bbfc4b30031f45d984e034a3ac3a" integrity sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ== dependencies: ansi-escapes "^4.2.1" @@ -13851,9 +14141,16 @@ is-color-stop@^1.0.0, is-color-stop@^1.1.0: rgb-regex "^1.0.1" rgba-regex "^1.0.0" -is-core-module@^2.2.0, is-core-module@^2.5.0, is-core-module@^2.8.1: +is-core-module@^2.2.0, is-core-module@^2.5.0: + version "2.8.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + +is-core-module@^2.8.1: version "2.9.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== dependencies: has "^1.0.3" @@ -14031,7 +14328,7 @@ is-lower-case@^1.1.0: is-lower-case@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-2.0.2.tgz#1c0884d3012c841556243483aa5d522f47396d2a" + resolved "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz#1c0884d3012c841556243483aa5d522f47396d2a" integrity sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ== dependencies: tslib "^2.0.3" @@ -14221,7 +14518,7 @@ is-retry-allowed@^1.0.0: is-root@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" + resolved "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c" integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg== is-shared-array-buffer@^1.0.1: @@ -14294,7 +14591,7 @@ is-upper-case@^1.1.0: is-upper-case@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-2.0.2.tgz#f1105ced1fe4de906a5f39553e7d3803fd804649" + resolved "https://registry.npmjs.org/is-upper-case/-/is-upper-case-2.0.2.tgz#f1105ced1fe4de906a5f39553e7d3803fd804649" integrity sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ== dependencies: tslib "^2.0.3" @@ -14383,19 +14680,20 @@ isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" -istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== dependencies: - "@babel/core" "^7.7.5" + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" + istanbul-lib-coverage "^3.2.0" semver "^6.3.0" istanbul-lib-report@^3.0.0: @@ -14416,10 +14714,10 @@ istanbul-lib-source-maps@^4.0.0: istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== +istanbul-reports@^3.0.2, istanbul-reports@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.3.tgz#4bcae3103b94518117930d51283690960b50d3c2" + integrity sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -14441,82 +14739,82 @@ jake@^10.6.1: jest-changed-files@^27.4.2: version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.4.2.tgz#da2547ea47c6e6a5f6ed336151bd2075736eb4a5" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz#da2547ea47c6e6a5f6ed336151bd2075736eb4a5" integrity sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A== dependencies: "@jest/types" "^27.4.2" execa "^5.0.0" throat "^6.0.1" -jest-circus@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.4.4.tgz#8bf89aa604b914ecc10e3d895aae283b529f965d" - integrity sha512-4DWhvQerDq5X4GaqhEUoZiBhuNdKDGr0geW0iJwarbDljAmGaGOErKQG+z2PBr0vgN05z7tsGSY51mdWr8E4xg== +jest-circus@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.6.tgz#d3af34c0eb742a967b1919fbb351430727bcea6c" + integrity sha512-UA7AI5HZrW4wRM72Ro80uRR2Fg+7nR0GESbSI/2M+ambbzVuA63mn5T1p3Z/wlhntzGpIG1xx78GP2YIkf6PhQ== dependencies: - "@jest/environment" "^27.4.4" - "@jest/test-result" "^27.4.2" + "@jest/environment" "^27.4.6" + "@jest/test-result" "^27.4.6" "@jest/types" "^27.4.2" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" dedent "^0.7.0" - expect "^27.4.2" + expect "^27.4.6" is-generator-fn "^2.0.0" - jest-each "^27.4.2" - jest-matcher-utils "^27.4.2" - jest-message-util "^27.4.2" - jest-runtime "^27.4.4" - jest-snapshot "^27.4.4" + jest-each "^27.4.6" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" + jest-runtime "^27.4.6" + jest-snapshot "^27.4.6" jest-util "^27.4.2" - pretty-format "^27.4.2" + pretty-format "^27.4.6" slash "^3.0.0" stack-utils "^2.0.3" throat "^6.0.1" -jest-cli@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.4.4.tgz#7115ff01f605c2c848314141b1ac144099ddeed5" - integrity sha512-+MfsHnZPUOBigCBURuQFRpgYoPCgmIFkICkqt4SrramZCUp/UAuWcst4pMZb84O3VU8JyKJmnpGG4qH8ClQloA== +jest-cli@^27.4.7: + version "27.4.7" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.7.tgz#d00e759e55d77b3bcfea0715f527c394ca314e5a" + integrity sha512-zREYhvjjqe1KsGV15mdnxjThKNDgza1fhDT+iUsXWLCq3sxe9w5xnvyctcYVT5PcdLSjv7Y5dCwTS3FCF1tiuw== dependencies: - "@jest/core" "^27.4.4" - "@jest/test-result" "^27.4.2" + "@jest/core" "^27.4.7" + "@jest/test-result" "^27.4.6" "@jest/types" "^27.4.2" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.4" import-local "^3.0.2" - jest-config "^27.4.4" + jest-config "^27.4.7" jest-util "^27.4.2" - jest-validate "^27.4.2" + jest-validate "^27.4.6" prompts "^2.0.1" yargs "^16.2.0" -jest-config@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.4.4.tgz#0e3615392361baae0e29dbf64c296d5563d7e28b" - integrity sha512-6lxg0ugO6KS2zKEbpdDwBzu1IT0Xg4/VhxXMuBu+z/5FvBjLCEMTaWQm3bCaGCZUR9j9FK4DzUIxyhIgn6kVEg== +jest-config@^27.4.7: + version "27.4.7" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-27.4.7.tgz#4f084b2acbd172c8b43aa4cdffe75d89378d3972" + integrity sha512-xz/o/KJJEedHMrIY9v2ParIoYSrSVY6IVeE4z5Z3i101GoA5XgfbJz+1C8EYPsv7u7f39dS8F9v46BHDhn0vlw== dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^27.4.4" + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.4.6" "@jest/types" "^27.4.2" - babel-jest "^27.4.4" + babel-jest "^27.4.6" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.1" graceful-fs "^4.2.4" - jest-circus "^27.4.4" - jest-environment-jsdom "^27.4.4" - jest-environment-node "^27.4.4" + jest-circus "^27.4.6" + jest-environment-jsdom "^27.4.6" + jest-environment-node "^27.4.6" jest-get-type "^27.4.0" - jest-jasmine2 "^27.4.4" + jest-jasmine2 "^27.4.6" jest-regex-util "^27.4.0" - jest-resolve "^27.4.4" - jest-runner "^27.4.4" + jest-resolve "^27.4.6" + jest-runner "^27.4.6" jest-util "^27.4.2" - jest-validate "^27.4.2" + jest-validate "^27.4.6" micromatch "^4.0.4" - pretty-format "^27.4.2" + pretty-format "^27.4.6" slash "^3.0.0" jest-diff@^24.9.0: @@ -14529,57 +14827,57 @@ jest-diff@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" -jest-diff@^27.0.0, jest-diff@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.4.2.tgz#786b2a5211d854f848e2dcc1e324448e9481f36f" - integrity sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q== +jest-diff@^27.0.0, jest-diff@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.6.tgz#93815774d2012a2cbb6cf23f84d48c7a2618f98d" + integrity sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w== dependencies: chalk "^4.0.0" diff-sequences "^27.4.0" jest-get-type "^27.4.0" - pretty-format "^27.4.2" + pretty-format "^27.4.6" jest-docblock@^27.4.0: version "27.4.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.4.0.tgz#06c78035ca93cbbb84faf8fce64deae79a59f69f" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz#06c78035ca93cbbb84faf8fce64deae79a59f69f" integrity sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg== dependencies: detect-newline "^3.0.0" -jest-each@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.4.2.tgz#19364c82a692d0d26557642098d1f4619c9ee7d3" - integrity sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg== +jest-each@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-27.4.6.tgz#e7e8561be61d8cc6dbf04296688747ab186c40ff" + integrity sha512-n6QDq8y2Hsmn22tRkgAk+z6MCX7MeVlAzxmZDshfS2jLcaBlyhpF3tZSJLR+kXmh23GEvS0ojMR8i6ZeRvpQcA== dependencies: "@jest/types" "^27.4.2" chalk "^4.0.0" jest-get-type "^27.4.0" jest-util "^27.4.2" - pretty-format "^27.4.2" + pretty-format "^27.4.6" -jest-environment-jsdom@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.4.4.tgz#94f738e99514d7a880e8ed8e03e3a321d43b49db" - integrity sha512-cYR3ndNfHBqQgFvS1RL7dNqSvD//K56j/q1s2ygNHcfTCAp12zfIromO1w3COmXrxS8hWAh7+CmZmGCIoqGcGA== +jest-environment-jsdom@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.6.tgz#c23a394eb445b33621dfae9c09e4c8021dea7b36" + integrity sha512-o3dx5p/kHPbUlRvSNjypEcEtgs6LmvESMzgRFQE6c+Prwl2JLA4RZ7qAnxc5VM8kutsGRTB15jXeeSbJsKN9iA== dependencies: - "@jest/environment" "^27.4.4" - "@jest/fake-timers" "^27.4.2" + "@jest/environment" "^27.4.6" + "@jest/fake-timers" "^27.4.6" "@jest/types" "^27.4.2" "@types/node" "*" - jest-mock "^27.4.2" + jest-mock "^27.4.6" jest-util "^27.4.2" jsdom "^16.6.0" -jest-environment-node@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.4.4.tgz#42fe5e3b224cb69b99811ebf6f5eaa5a59618514" - integrity sha512-D+v3lbJ2GjQTQR23TK0kY3vFVmSeea05giInI41HHOaJnAwOnmUHTZgUaZL+VxUB43pIzoa7PMwWtCVlIUoVoA== +jest-environment-node@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.6.tgz#ee8cd4ef458a0ef09d087c8cd52ca5856df90242" + integrity sha512-yfHlZ9m+kzTKZV0hVfhVu6GuDxKAYeFHrfulmy7Jxwsq4V7+ZK7f+c0XP/tbVDMQW7E4neG2u147hFkuVz0MlQ== dependencies: - "@jest/environment" "^27.4.4" - "@jest/fake-timers" "^27.4.2" + "@jest/environment" "^27.4.6" + "@jest/fake-timers" "^27.4.6" "@jest/types" "^27.4.2" "@types/node" "*" - jest-mock "^27.4.2" + jest-mock "^27.4.6" jest-util "^27.4.2" jest-extended@^0.11.5: @@ -14602,13 +14900,13 @@ jest-get-type@^24.9.0: jest-get-type@^27.4.0: version "27.4.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ== -jest-haste-map@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.4.4.tgz#ec6013845368a155372e25e42e2b77e6ecc5019f" - integrity sha512-kvspmHmgPIZoDaqUsvsJFTaspuxhATvdO6wsFNGNSi8kfdiOCEEvECNbht8xG+eE5Ol88JyJmp2D7RF4dYo85Q== +jest-haste-map@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.6.tgz#c60b5233a34ca0520f325b7e2cc0a0140ad0862a" + integrity sha512-0tNpgxg7BKurZeFkIOvGCkbmOHbLFf4LUQOxrQSMjvrQaQe3l6E8x6jYC1NuWkGo5WDdbr8FEzUxV2+LWNawKQ== dependencies: "@jest/types" "^27.4.2" "@types/graceful-fs" "^4.1.2" @@ -14619,53 +14917,52 @@ jest-haste-map@^27.4.4: jest-regex-util "^27.4.0" jest-serializer "^27.4.0" jest-util "^27.4.2" - jest-worker "^27.4.4" + jest-worker "^27.4.6" micromatch "^4.0.4" walker "^1.0.7" optionalDependencies: fsevents "^2.3.2" -jest-jasmine2@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.4.4.tgz#1fcdc64de932913366e7d5f2960c375e1145176e" - integrity sha512-ygk2tUgtLeN3ouj4KEYw9p81GLI1EKrnvourPULN5gdgB482PH5op9gqaRG0IenbJhBbbRwiSvh5NoBoQZSqdA== +jest-jasmine2@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.6.tgz#109e8bc036cb455950ae28a018f983f2abe50127" + integrity sha512-uAGNXF644I/whzhsf7/qf74gqy9OuhvJ0XYp8SDecX2ooGeaPnmJMjXjKt0mqh1Rl5dtRGxJgNrHlBQIBfS5Nw== dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^27.4.4" + "@jest/environment" "^27.4.6" "@jest/source-map" "^27.4.0" - "@jest/test-result" "^27.4.2" + "@jest/test-result" "^27.4.6" "@jest/types" "^27.4.2" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - expect "^27.4.2" + expect "^27.4.6" is-generator-fn "^2.0.0" - jest-each "^27.4.2" - jest-matcher-utils "^27.4.2" - jest-message-util "^27.4.2" - jest-runtime "^27.4.4" - jest-snapshot "^27.4.4" + jest-each "^27.4.6" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" + jest-runtime "^27.4.6" + jest-snapshot "^27.4.6" jest-util "^27.4.2" - pretty-format "^27.4.2" + pretty-format "^27.4.6" throat "^6.0.1" jest-junit@^12.2.0: - version "12.2.0" - resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-12.2.0.tgz#cff7f9516e84f8e30f6bdea04cd84db6b095a376" - integrity sha512-ecGzF3KEQwLbMP5xMO7wqmgmyZlY/5yWDvgE/vFa+/uIT0KsU5nluf0D2fjIlOKB+tb6DiuSSpZuGpsmwbf7Fw== + version "12.3.0" + resolved "https://registry.npmjs.org/jest-junit/-/jest-junit-12.3.0.tgz#ee41a74e439eecdc8965f163f83035cce5998d6d" + integrity sha512-+NmE5ogsEjFppEl90GChrk7xgz8xzvF0f+ZT5AnhW6suJC93gvQtmQjfyjDnE0Z2nXJqEkxF0WXlvjG/J+wn/g== dependencies: mkdirp "^1.0.4" strip-ansi "^5.2.0" uuid "^8.3.2" xml "^1.0.1" -jest-leak-detector@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.4.2.tgz#7fc3120893a7a911c553f3f2bdff9faa4454abbb" - integrity sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw== +jest-leak-detector@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.6.tgz#ed9bc3ce514b4c582637088d9faf58a33bd59bf4" + integrity sha512-kkaGixDf9R7CjHm2pOzfTxZTQQQ2gHTIWKY/JZSiYTc90bZp8kSZnUMS3uLAfwTZwc0tcMRoEX74e14LG1WapA== dependencies: jest-get-type "^27.4.0" - pretty-format "^27.4.2" + pretty-format "^27.4.6" jest-matcher-utils@^22.0.0: version "22.4.3" @@ -14686,15 +14983,15 @@ jest-matcher-utils@^24.9.0: jest-get-type "^24.9.0" pretty-format "^24.9.0" -jest-matcher-utils@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.4.2.tgz#d17c5038607978a255e0a9a5c32c24e984b6c60b" - integrity sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ== +jest-matcher-utils@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.6.tgz#53ca7f7b58170638590e946f5363b988775509b8" + integrity sha512-XD4PKT3Wn1LQnRAq7ZsTI0VRuEc9OrCPFiO1XL7bftTGmfNF0DcEwMHRgqiu7NGf8ZoZDREpGrCniDkjt79WbA== dependencies: chalk "^4.0.0" - jest-diff "^27.4.2" + jest-diff "^27.4.6" jest-get-type "^27.4.0" - pretty-format "^27.4.2" + pretty-format "^27.4.6" jest-message-util@^24.9.0: version "24.9.0" @@ -14710,10 +15007,10 @@ jest-message-util@^24.9.0: slash "^2.0.0" stack-utils "^1.0.1" -jest-message-util@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.4.2.tgz#07f3f1bf207d69cf798ce830cc57f1a849f99388" - integrity sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w== +jest-message-util@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.6.tgz#9fdde41a33820ded3127465e1a5896061524da31" + integrity sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA== dependencies: "@babel/code-frame" "^7.12.13" "@jest/types" "^27.4.2" @@ -14721,14 +15018,14 @@ jest-message-util@^27.4.2: chalk "^4.0.0" graceful-fs "^4.2.4" micromatch "^4.0.4" - pretty-format "^27.4.2" + pretty-format "^27.4.6" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.4.2.tgz#184ff197a25491bfe4570c286daa5d62eb760b88" - integrity sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA== +jest-mock@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.6.tgz#77d1ba87fbd33ccb8ef1f061697e7341b7635195" + integrity sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw== dependencies: "@jest/types" "^27.4.2" "@types/node" "*" @@ -14745,43 +15042,43 @@ jest-regex-util@^24.9.0: jest-regex-util@^27.4.0: version "27.4.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.4.0.tgz#e4c45b52653128843d07ad94aec34393ea14fbca" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz#e4c45b52653128843d07ad94aec34393ea14fbca" integrity sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg== -jest-resolve-dependencies@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.4.tgz#dae11e067a6d6a9553f1386a0ea1efe5be0e2332" - integrity sha512-iAnpCXh81sd9nbyqySvm5/aV9X6JZKE0dQyFXTC8tptXcdrgS0vjPFy+mEgzPHxXw+tq4TQupuTa0n8OXwRIxw== +jest-resolve-dependencies@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.6.tgz#fc50ee56a67d2c2183063f6a500cc4042b5e2327" + integrity sha512-W85uJZcFXEVZ7+MZqIPCscdjuctruNGXUZ3OHSXOfXR9ITgbUKeHj+uGcies+0SsvI5GtUfTw4dY7u9qjTvQOw== dependencies: "@jest/types" "^27.4.2" jest-regex-util "^27.4.0" - jest-snapshot "^27.4.4" + jest-snapshot "^27.4.6" -jest-resolve@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.4.4.tgz#5b690662f54f38f7cfaffc0adcdb341ff7724408" - integrity sha512-Yh5jK3PBmDbm01Rc8pT0XqpBlTPEGwWp7cN61ijJuwony/tR2Taof3TLy6yfNiuRS8ucUOPO7NBYm3ei38kkcg== +jest-resolve@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.6.tgz#2ec3110655e86d5bfcfa992e404e22f96b0b5977" + integrity sha512-SFfITVApqtirbITKFAO7jOVN45UgFzcRdQanOFzjnbd+CACDoyeX7206JyU92l4cRr73+Qy/TlW51+4vHGt+zw== dependencies: "@jest/types" "^27.4.2" chalk "^4.0.0" graceful-fs "^4.2.4" - jest-haste-map "^27.4.4" + jest-haste-map "^27.4.6" jest-pnp-resolver "^1.2.2" jest-util "^27.4.2" - jest-validate "^27.4.2" + jest-validate "^27.4.6" resolve "^1.20.0" resolve.exports "^1.1.0" slash "^3.0.0" -jest-runner@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.4.4.tgz#0b40cdcbac293ebc4c19c2d7805d17ab1072f1fd" - integrity sha512-AXv/8Q0Xf1puWnDf52m7oLrK7sXcv6re0V/kItwTSVHJbX7Oebm07oGFQqGmq0R0mhO1zpmB3OpqRuaCN2elPA== +jest-runner@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.6.tgz#1d390d276ec417e9b4d0d081783584cbc3e24773" + integrity sha512-IDeFt2SG4DzqalYBZRgbbPmpwV3X0DcntjezPBERvnhwKGWTW7C5pbbA5lVkmvgteeNfdd/23gwqv3aiilpYPg== dependencies: - "@jest/console" "^27.4.2" - "@jest/environment" "^27.4.4" - "@jest/test-result" "^27.4.2" - "@jest/transform" "^27.4.4" + "@jest/console" "^27.4.6" + "@jest/environment" "^27.4.6" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" "@jest/types" "^27.4.2" "@types/node" "*" chalk "^4.0.0" @@ -14789,49 +15086,45 @@ jest-runner@^27.4.4: exit "^0.1.2" graceful-fs "^4.2.4" jest-docblock "^27.4.0" - jest-environment-jsdom "^27.4.4" - jest-environment-node "^27.4.4" - jest-haste-map "^27.4.4" - jest-leak-detector "^27.4.2" - jest-message-util "^27.4.2" - jest-resolve "^27.4.4" - jest-runtime "^27.4.4" + jest-environment-jsdom "^27.4.6" + jest-environment-node "^27.4.6" + jest-haste-map "^27.4.6" + jest-leak-detector "^27.4.6" + jest-message-util "^27.4.6" + jest-resolve "^27.4.6" + jest-runtime "^27.4.6" jest-util "^27.4.2" - jest-worker "^27.4.4" + jest-worker "^27.4.6" source-map-support "^0.5.6" throat "^6.0.1" -jest-runtime@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.4.4.tgz#0d486735e8a1c8bbcdbb9285b3155ed94c5e3670" - integrity sha512-tZGay6P6vXJq8t4jVFAUzYHx+lzIHXjz+rj1XBk6mAR1Lwtf5kz0Uun7qNuU+oqpZu4+hhuxpUfXb6j30bEPqA== +jest-runtime@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.6.tgz#83ae923818e3ea04463b22f3597f017bb5a1cffa" + integrity sha512-eXYeoR/MbIpVDrjqy5d6cGCFOYBFFDeKaNWqTp0h6E74dK0zLHzASQXJpl5a2/40euBmKnprNLJ0Kh0LCndnWQ== dependencies: - "@jest/console" "^27.4.2" - "@jest/environment" "^27.4.4" - "@jest/globals" "^27.4.4" + "@jest/environment" "^27.4.6" + "@jest/fake-timers" "^27.4.6" + "@jest/globals" "^27.4.6" "@jest/source-map" "^27.4.0" - "@jest/test-result" "^27.4.2" - "@jest/transform" "^27.4.4" + "@jest/test-result" "^27.4.6" + "@jest/transform" "^27.4.6" "@jest/types" "^27.4.2" - "@types/yargs" "^16.0.0" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" execa "^5.0.0" - exit "^0.1.2" glob "^7.1.3" graceful-fs "^4.2.4" - jest-haste-map "^27.4.4" - jest-message-util "^27.4.2" - jest-mock "^27.4.2" + jest-haste-map "^27.4.6" + jest-message-util "^27.4.6" + jest-mock "^27.4.6" jest-regex-util "^27.4.0" - jest-resolve "^27.4.4" - jest-snapshot "^27.4.4" + jest-resolve "^27.4.6" + jest-snapshot "^27.4.6" jest-util "^27.4.2" - jest-validate "^27.4.2" slash "^3.0.0" strip-bom "^4.0.0" - yargs "^16.2.0" jest-serializer-path@^0.1.15: version "0.1.15" @@ -14843,7 +15136,7 @@ jest-serializer-path@^0.1.15: jest-serializer@^27.4.0: version "27.4.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.4.0.tgz#34866586e1cae2388b7d12ffa2c7819edef5958a" + resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz#34866586e1cae2388b7d12ffa2c7819edef5958a" integrity sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ== dependencies: "@types/node" "*" @@ -14857,34 +15150,32 @@ jest-silent-reporter@^0.5.0: chalk "^4.0.0" jest-util "^26.0.0" -jest-snapshot@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.4.4.tgz#fc0a2cd22f742fe66621c5359c9cd64f88260c6b" - integrity sha512-yy+rpCvYMOjTl7IMuaMI9OP9WT229zi8BhdNHm6e6mttAOIzvIiCxFoZ6yRxaV3HDPPgMryi+ReX2b8+IQJdPA== +jest-snapshot@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.6.tgz#e2a3b4fff8bdce3033f2373b2e525d8b6871f616" + integrity sha512-fafUCDLQfzuNP9IRcEqaFAMzEe7u5BF7mude51wyWv7VRex60WznZIC7DfKTgSIlJa8aFzYmXclmN328aqSDmQ== dependencies: "@babel/core" "^7.7.2" "@babel/generator" "^7.7.2" - "@babel/parser" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" "@babel/traverse" "^7.7.2" "@babel/types" "^7.0.0" - "@jest/transform" "^27.4.4" + "@jest/transform" "^27.4.6" "@jest/types" "^27.4.2" "@types/babel__traverse" "^7.0.4" "@types/prettier" "^2.1.5" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^27.4.2" + expect "^27.4.6" graceful-fs "^4.2.4" - jest-diff "^27.4.2" + jest-diff "^27.4.6" jest-get-type "^27.4.0" - jest-haste-map "^27.4.4" - jest-matcher-utils "^27.4.2" - jest-message-util "^27.4.2" - jest-resolve "^27.4.4" + jest-haste-map "^27.4.6" + jest-matcher-utils "^27.4.6" + jest-message-util "^27.4.6" jest-util "^27.4.2" natural-compare "^1.4.0" - pretty-format "^27.4.2" + pretty-format "^27.4.6" semver "^7.3.2" jest-util@^26.0.0: @@ -14901,7 +15192,7 @@ jest-util@^26.0.0: jest-util@^27.4.2: version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.4.2.tgz#ed95b05b1adfd761e2cda47e0144c6a58e05a621" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz#ed95b05b1adfd761e2cda47e0144c6a58e05a621" integrity sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA== dependencies: "@jest/types" "^27.4.2" @@ -14911,24 +15202,24 @@ jest-util@^27.4.2: graceful-fs "^4.2.4" picomatch "^2.2.3" -jest-validate@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.4.2.tgz#eecfcc1b1c9429aa007da08a2bae4e32a81bbbc3" - integrity sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A== +jest-validate@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz#efc000acc4697b6cf4fa68c7f3f324c92d0c4f1f" + integrity sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ== dependencies: "@jest/types" "^27.4.2" camelcase "^6.2.0" chalk "^4.0.0" jest-get-type "^27.4.0" leven "^3.1.0" - pretty-format "^27.4.2" + pretty-format "^27.4.6" -jest-watcher@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.4.2.tgz#c9037edfd80354c9fe90de4b6f8b6e2b8e736744" - integrity sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg== +jest-watcher@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.6.tgz#673679ebeffdd3f94338c24f399b85efc932272d" + integrity sha512-yKQ20OMBiCDigbD0quhQKLkBO+ObGN79MO4nT7YaCuQ5SM+dkBNWE8cZX0FjU6czwMvWw6StWbe+Wv4jJPJ+fw== dependencies: - "@jest/test-result" "^27.4.2" + "@jest/test-result" "^27.4.6" "@jest/types" "^27.4.2" "@types/node" "*" ansi-escapes "^4.2.1" @@ -14945,27 +15236,27 @@ jest-worker@^26.2.1, jest-worker@^26.3.0: merge-stream "^2.0.0" supports-color "^7.0.0" -jest-worker@^27.0.6, jest-worker@^27.3.1, jest-worker@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.4.tgz#9390a97c013a54d07f5c2ad2b5f6109f30c4966d" - integrity sha512-jfwxYJvfua1b1XkyuyPh01ATmgg4e5fPM/muLmhy9Qc6dmiwacQB0MLHaU6IjEsv/+nAixHGxTn8WllA27Pn0w== +jest-worker@^27.0.6, jest-worker@^27.3.1, jest-worker@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz#5d2d93db419566cb680752ca0792780e71b3273e" + integrity sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw== dependencies: "@types/node" "*" merge-stream "^2.0.0" supports-color "^8.0.0" jest@^27.4.4: - version "27.4.4" - resolved "https://registry.yarnpkg.com/jest/-/jest-27.4.4.tgz#9b1aa1db25d0b13477a49d18e22ba7cdff97105b" - integrity sha512-AXwEIFa58Uf1Jno3/KSo5HZZ0/2Xwqvfrz0/3bmTwImkFlbOvz5vARAW9nTrxRLkojjkitaZ1KNKAtw3JRFAaA== + version "27.4.7" + resolved "https://registry.npmjs.org/jest/-/jest-27.4.7.tgz#87f74b9026a1592f2da05b4d258e57505f28eca4" + integrity sha512-8heYvsx7nV/m8m24Vk26Y87g73Ba6ueUd0MWed/NXMhSZIm62U/llVbS0PJe1SHunbyXjJ/BqG1z9bFjGUIvTg== dependencies: - "@jest/core" "^27.4.4" + "@jest/core" "^27.4.7" import-local "^3.0.2" - jest-cli "^27.4.4" + jest-cli "^27.4.7" jimp@^0.16.1: version "0.16.1" - resolved "https://registry.yarnpkg.com/jimp/-/jimp-0.16.1.tgz#192f851a30e5ca11112a3d0aa53137659a78ca7a" + resolved "https://registry.npmjs.org/jimp/-/jimp-0.16.1.tgz#192f851a30e5ca11112a3d0aa53137659a78ca7a" integrity sha512-+EKVxbR36Td7Hfd23wKGIeEyHbxShZDX6L8uJkgVW3ESA9GiTEPK08tG1XI2r/0w5Ch0HyJF5kPqF9K7EmGjaw== dependencies: "@babel/runtime" "^7.7.2" @@ -14996,7 +15287,7 @@ joi@^17.4.2: jpeg-js@0.4.2: version "0.4.2" - resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.2.tgz#8b345b1ae4abde64c2da2fe67ea216a114ac279d" + resolved "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.2.tgz#8b345b1ae4abde64c2da2fe67ea216a114ac279d" integrity sha512-+az2gi/hvex7eLTMTlbRLOhH6P6WFdk2ITI8HJsaH2VqYO0I594zXSYEP+tf4FW+8Cy68ScDXoAsQdyQanv3sw== js-base64@^2.1.9: @@ -15096,7 +15387,7 @@ jsdom@15.2.1, jsdom@^15.0.0: jsdom@^16.6.0: version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + resolved "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== dependencies: abab "^2.0.5" @@ -15204,9 +15495,16 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" -json5@^2.0.0, json5@^2.1.0, json5@^2.1.2, json5@^2.1.3, json5@^2.2.0, json5@^2.2.1: +json5@^2.0.0, json5@^2.1.0, json5@^2.1.2, json5@^2.1.3, json5@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + +json5@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== jsonfile@^2.1.0: @@ -15270,7 +15568,7 @@ jsprim@^1.2.2: "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" + resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== dependencies: array-includes "^3.1.3" @@ -15677,32 +15975,32 @@ livereload-js@^2.3.0: lmdb-darwin-arm64@2.3.10: version "2.3.10" - resolved "https://registry.yarnpkg.com/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.3.10.tgz#4e20f75770eeedc60af3d4630975fd105a89ffe8" + resolved "https://registry.npmjs.org/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.3.10.tgz#4e20f75770eeedc60af3d4630975fd105a89ffe8" integrity sha512-LVXbH2MYu7/ZuQ8+P9rv+SwNyBKltxo7vHAGJS94HWyfwnCbKEYER9PImBvNBwzvgtaYk6x0RMX3oor6e6KdDQ== lmdb-darwin-x64@2.3.10: version "2.3.10" - resolved "https://registry.yarnpkg.com/lmdb-darwin-x64/-/lmdb-darwin-x64-2.3.10.tgz#e53637a6735488eaa15feb7c0e9da142015b9476" + resolved "https://registry.npmjs.org/lmdb-darwin-x64/-/lmdb-darwin-x64-2.3.10.tgz#e53637a6735488eaa15feb7c0e9da142015b9476" integrity sha512-gAc/1b/FZOb9yVOT+o0huA+hdW82oxLo5r22dFTLoRUFG1JMzxdTjmnW6ONVOHdqC9a5bt3vBCEY3jmXNqV26A== lmdb-linux-arm64@2.3.10: version "2.3.10" - resolved "https://registry.yarnpkg.com/lmdb-linux-arm64/-/lmdb-linux-arm64-2.3.10.tgz#ac7db8bdfe0e9dbf2be1cc3362d6f2b79e2a9722" + resolved "https://registry.npmjs.org/lmdb-linux-arm64/-/lmdb-linux-arm64-2.3.10.tgz#ac7db8bdfe0e9dbf2be1cc3362d6f2b79e2a9722" integrity sha512-Ihr8mdICTK3jA4GXHxrXGK2oekn0mY6zuDSXQDNtyRSH19j3D2Y04A7SEI9S0EP/t5sjKSudYgZbiHDxRCsI5A== lmdb-linux-arm@2.3.10: version "2.3.10" - resolved "https://registry.yarnpkg.com/lmdb-linux-arm/-/lmdb-linux-arm-2.3.10.tgz#74235418bbe7bf41e8ea5c9d52365c4ff5ca4b49" + resolved "https://registry.npmjs.org/lmdb-linux-arm/-/lmdb-linux-arm-2.3.10.tgz#74235418bbe7bf41e8ea5c9d52365c4ff5ca4b49" integrity sha512-Rb8+4JjsThuEcJ7GLLwFkCFnoiwv/3hAAbELWITz70buQFF+dCZvCWWgEgmDTxwn5r+wIkdUjmFv4dqqiKQFmQ== lmdb-linux-x64@2.3.10: version "2.3.10" - resolved "https://registry.yarnpkg.com/lmdb-linux-x64/-/lmdb-linux-x64-2.3.10.tgz#d790b95061d03c5c99a57b3ad5126f7723c60a2f" + resolved "https://registry.npmjs.org/lmdb-linux-x64/-/lmdb-linux-x64-2.3.10.tgz#d790b95061d03c5c99a57b3ad5126f7723c60a2f" integrity sha512-E3l3pDiCA9uvnLf+t3qkmBGRO01dp1EHD0x0g0iRnfpAhV7wYbayJGfG93BUt22Tj3fnq4HDo4dQ6ZWaDI1nuw== lmdb-win32-x64@2.3.10: version "2.3.10" - resolved "https://registry.yarnpkg.com/lmdb-win32-x64/-/lmdb-win32-x64-2.3.10.tgz#bff73d12d94084343c569b16069d8d38626eb2d6" + resolved "https://registry.npmjs.org/lmdb-win32-x64/-/lmdb-win32-x64-2.3.10.tgz#bff73d12d94084343c569b16069d8d38626eb2d6" integrity sha512-gspWk34tDANhjn+brdqZstJMptGiwj4qFNVg0Zey9ds+BUlif+Lgf5szrfOVzZ8gVRkk1Lgbz7i78+V7YK7SCA== lmdb@2.2.4: @@ -15718,7 +16016,7 @@ lmdb@2.2.4: lmdb@2.3.10: version "2.3.10" - resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.3.10.tgz#640fc60815846babcbe088d7f8ed0a51da857f6a" + resolved "https://registry.npmjs.org/lmdb/-/lmdb-2.3.10.tgz#640fc60815846babcbe088d7f8ed0a51da857f6a" integrity sha512-GtH+nStn9V59CfYeQ5ddx6YTfuFCmu86UJojIjJAweG+/Fm0PDknuk3ovgYDtY/foMeMdZa8/P7oSljW/d5UPw== dependencies: msgpackr "^1.5.4" @@ -15830,7 +16128,7 @@ loader-utils@^2.0.0: loader-utils@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.2.0.tgz#bcecc51a7898bee7473d4bc6b845b23af8304d4f" + resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz#bcecc51a7898bee7473d4bc6b845b23af8304d4f" integrity sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ== locate-path@^2.0.0: @@ -15862,7 +16160,7 @@ locate-path@^6.0.0: lock@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/lock/-/lock-1.1.0.tgz#53157499d1653b136ca66451071fca615703fa55" + resolved "https://registry.npmjs.org/lock/-/lock-1.1.0.tgz#53157499d1653b136ca66451071fca615703fa55" integrity sha1-UxV0mdFlOxNspmRRBx/KYVcD+lU= lockfile@1.0.4, lockfile@^1.0, lockfile@^1.0.4: @@ -16197,7 +16495,7 @@ lower-case-first@^1.0.0: lower-case-first@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-2.0.2.tgz#64c2324a2250bf7c37c5901e76a5b5309301160b" + resolved "https://registry.npmjs.org/lower-case-first/-/lower-case-first-2.0.2.tgz#64c2324a2250bf7c37c5901e76a5b5309301160b" integrity sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg== dependencies: tslib "^2.0.3" @@ -16772,13 +17070,20 @@ memfs-or-file-map-to-github-branch@^1.1.0: resolved "https://registry.yarnpkg.com/memfs-or-file-map-to-github-branch/-/memfs-or-file-map-to-github-branch-1.1.2.tgz#9d46c02481b7eca8e5ee8a94f170b7e0138cad67" integrity sha512-D2JKK2DTuVYQqquBWco3K6UfSVyVwmd58dgNqh+TgxHOZdTmR8I130gjMbVCkemDl/EzqDA62417cJxKL3/FFA== -memfs@^3.1.2, memfs@^3.2.2: +memfs@^3.1.2: version "3.4.1" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.1.tgz#b78092f466a0dce054d63d39275b24c71d3f1305" + resolved "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz#b78092f466a0dce054d63d39275b24c71d3f1305" integrity sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw== dependencies: fs-monkey "1.0.3" +memfs@^3.2.2: + version "3.3.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.3.0.tgz#4da2d1fc40a04b170a56622c7164c6be2c4cbef2" + integrity sha512-BEE62uMfKOavX3iG7GYX43QJ+hAeeWnwIAuJ/R6q96jaMtiLzhsxHJC8B1L7fK7Pt/vXDRwb3SG/yBpNGDPqzg== + dependencies: + fs-monkey "1.0.3" + memoizee@^0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72" @@ -16906,7 +17211,7 @@ merge-stream@^2.0.0: merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== meros@^1.1.2: @@ -16966,7 +17271,7 @@ microbundle@^0.13.0: microbundle@^0.14.2: version "0.14.2" - resolved "https://registry.yarnpkg.com/microbundle/-/microbundle-0.14.2.tgz#2db869c8145bd159aa55058ead47223f58f93bf2" + resolved "https://registry.npmjs.org/microbundle/-/microbundle-0.14.2.tgz#2db869c8145bd159aa55058ead47223f58f93bf2" integrity sha512-jODALfU3w7jnJAqw7Tou9uU8e8zH0GRVWzOd/V7eAvD1fsfb9pyMbmzhFZqnX6SCb54eP1EF5oRyNlSxBAxoag== dependencies: "@babel/core" "^7.12.10" @@ -17104,9 +17409,17 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.5: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5: +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + +micromatch@^4.0.5: version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: braces "^3.0.2" @@ -17184,7 +17497,7 @@ min-indent@^1.0.0, min-indent@^1.0.1: mini-css-extract-plugin@1.6.2: version "1.6.2" - resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz#83172b4fd812f8fc4a09d6f6d16f924f53990ca8" + resolved "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.6.2.tgz#83172b4fd812f8fc4a09d6f6d16f924f53990ca8" integrity sha512-WhDvO3SjGm40oV5y26GjMJYjd2UMqrLAGKy5YS2/3QKJy2F7jgynuHTir/tgUUOiNQu5saXHdc8reo7YuhhT4Q== dependencies: loader-utils "^2.0.0" @@ -17193,7 +17506,7 @@ mini-css-extract-plugin@1.6.2: mini-svg-data-uri@^1.4.4: version "1.4.4" - resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" + resolved "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== "minimatch@2 || 3", minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: @@ -17225,9 +17538,14 @@ minimist-options@^3.0.1: arrify "^1.0.1" is-plain-obj "^1.1.0" -minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: +minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +minimist@^1.2.6: version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== minipass@^2.2.1, minipass@^2.3.5: @@ -17390,7 +17708,7 @@ msgpackr@^1.5.4: msw@^0.38.2: version "0.38.2" - resolved "https://registry.yarnpkg.com/msw/-/msw-0.38.2.tgz#0c3637b392b65d5cc781468036c4be5965382c58" + resolved "https://registry.npmjs.org/msw/-/msw-0.38.2.tgz#0c3637b392b65d5cc781468036c4be5965382c58" integrity sha512-gD2vkV/ol3+zaC6AHKlPxB4zvl5mTV1uzhcv+0H6kwlbaiTZe/vVwiEGPeE9mQroAFvh0c8uJmltDebEys28qA== dependencies: "@mswjs/cookies" "^0.1.7" @@ -17636,7 +17954,7 @@ nock@^13.2.4: node-abi@^3.3.0: version "3.5.0" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.5.0.tgz#26e8b7b251c3260a5ac5ba5aef3b4345a0229248" + resolved "https://registry.npmjs.org/node-abi/-/node-abi-3.5.0.tgz#26e8b7b251c3260a5ac5ba5aef3b4345a0229248" integrity sha512-LtHvNIBgOy5mO8mPEUtkCW/YCRWYEKshIvqhe1GHHyXEHEB5mgICyYnAcl4qan3uFeRROErKGzatFHPf6kDxWw== dependencies: semver "^7.3.5" @@ -17700,7 +18018,7 @@ node-fetch@2.6.7, node-fetch@^2.5.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node- node-gyp-build-optional-packages@^4.3.2: version "4.3.2" - resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-4.3.2.tgz#82de9bdf9b1ad042457533afb2f67469dc2264bb" + resolved "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-4.3.2.tgz#82de9bdf9b1ad042457533afb2f67469dc2264bb" integrity sha512-P5Ep3ISdmwcCkZIaBaQamQtWAG0facC89phWZgi5Z3hBU//J6S48OIvyZWSPPf6yQMklLZiqoosWAZUj7N+esA== node-gyp-build@^4.2.3, node-gyp-build@^4.3.0: @@ -17739,13 +18057,9 @@ node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" -node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - node-notifier@^10.0.0: version "10.0.0" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-10.0.0.tgz#93c154055b07b550a33a1966a1b11291c2113e69" + resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-10.0.0.tgz#93c154055b07b550a33a1966a1b11291c2113e69" integrity sha512-ZTqP90y1eyb2xAZTa7j4AlAayTwh6cL8mn0nlJhLDq8itXGnJUmQGYOnpaMUvqZVfGo0vhU7KZ3HtDW6CT2SiQ== dependencies: growly "^1.3.0" @@ -17777,11 +18091,21 @@ node-plop@=0.9.0: pify "^3.0.0" resolve "^1.2.0" -node-releases@^2.0.3: +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== + +node-releases@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.3.tgz#225ee7488e4a5e636da8da52854844f9d716ca96" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.3.tgz#225ee7488e4a5e636da8da52854844f9d716ca96" integrity sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw== +node-releases@^2.0.3: + version "2.0.4" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz#f38252370c43854dc48aa431c766c6c398f40476" + integrity sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ== + noms@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" @@ -18082,7 +18406,7 @@ object.defaults@^1.1.0: object.entries@^1.1.5: version "1.1.5" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" + resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== dependencies: call-bind "^1.0.2" @@ -18091,7 +18415,7 @@ object.entries@^1.1.5: object.fromentries@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" + resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== dependencies: call-bind "^1.0.2" @@ -18108,7 +18432,7 @@ object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0 object.hasown@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" + resolved "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== dependencies: define-properties "^1.1.3" @@ -18151,14 +18475,14 @@ omggif@^1.0.10, omggif@^1.0.9: resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19" integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw== -on-finished@2.4.1, on-finished@^2.3.0: +on-finished@2.4.1: version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== dependencies: ee-first "1.1.1" -on-finished@~2.3.0: +on-finished@^2.3.0, on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: @@ -18198,7 +18522,7 @@ open@^7.0.3: open@^8.4.0: version "8.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + resolved "https://registry.npmjs.org/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== dependencies: define-lazy-prop "^2.0.0" @@ -18217,7 +18541,7 @@ opentracing@^0.14.5, opentracing@^0.14.7, opentracing@~0.14.3: optimism@^0.16.1: version "0.16.1" - resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.16.1.tgz#7c8efc1f3179f18307b887e18c15c5b7133f6e7d" + resolved "https://registry.npmjs.org/optimism/-/optimism-0.16.1.tgz#7c8efc1f3179f18307b887e18c15c5b7133f6e7d" integrity sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg== dependencies: "@wry/context" "^0.6.0" @@ -18256,7 +18580,7 @@ optionator@^0.9.1: ora@^5.4.1: version "5.4.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" + resolved "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== dependencies: bl "^4.1.0" @@ -18480,7 +18804,7 @@ p-some@^4.0.0: p-throttle@^4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/p-throttle/-/p-throttle-4.1.1.tgz#80b1fbd358af40a8bfa1667f9dc8b72b714ad692" + resolved "https://registry.npmjs.org/p-throttle/-/p-throttle-4.1.1.tgz#80b1fbd358af40a8bfa1667f9dc8b72b714ad692" integrity sha512-TuU8Ato+pRTPJoDzYD4s7ocJYcNSEZRvlxoq3hcPI2kZDZ49IQ1Wkj7/gDJc3X7XiEAAvRGtDzdXJI0tC3IL1g== p-timeout@^3.0.0, p-timeout@^3.1.0, p-timeout@^3.2.0: @@ -18795,7 +19119,7 @@ path-case@^2.1.0: path-case@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" + resolved "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz#9168645334eb942658375c56f80b4c0cb5f82c6f" integrity sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg== dependencies: dot-case "^3.0.4" @@ -18837,9 +19161,13 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-parse@^1.0.6, path-parse@^1.0.7: +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + +path-parse@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-root-regex@^0.1.0: @@ -18864,7 +19192,7 @@ path-to-regexp@^1.0.1: path-to-regexp@^6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38" integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg== path-type@^1.0.0: @@ -18944,9 +19272,14 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pidtree@^0.3.0: @@ -18985,12 +19318,10 @@ pinpoint@^1.1.0: resolved "https://registry.yarnpkg.com/pinpoint/-/pinpoint-1.1.0.tgz#0cf7757a6977f1bf7f6a32207b709e377388e874" integrity sha1-DPd1eml38b9/ajIge3CeN3OI6HQ= -pirates@^4.0.0, pirates@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" - integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== - dependencies: - node-modules-regexp "^1.0.0" +pirates@^4.0.0, pirates@^4.0.4: + version "4.0.4" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz#07df81e61028e402735cdd49db701e4885b4e6e6" + integrity sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw== pixelmatch@^4.0.2: version "4.0.2" @@ -19687,7 +20018,7 @@ postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.0, postcss-value-parser@^ postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== postcss@6.0.1: @@ -19735,7 +20066,7 @@ postcss@^8.2.1, postcss@^8.2.15, postcss@^8.2.9, postcss@^8.3.11: preact@^10.6.4: version "10.6.4" - resolved "https://registry.yarnpkg.com/preact/-/preact-10.6.4.tgz#ad12c409ff1b4316158486e0a7b8d43636f7ced8" + resolved "https://registry.npmjs.org/preact/-/preact-10.6.4.tgz#ad12c409ff1b4316158486e0a7b8d43636f7ced8" integrity sha512-WyosM7pxGcndU8hY0OQlLd54tOU+qmG45QXj2dAYrL11HoyU/EzOSTlpJsirbBr1QW7lICxSsVJJmcmUglovHQ== prebuild-install@^7.0.1: @@ -19787,9 +20118,14 @@ prettier-linter-helpers@^1.0.0: dependencies: fast-diff "^1.1.2" -prettier@^2.5.1, prettier@^2.6.2: +prettier@^2.5.1: + version "2.5.1" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" + integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== + +prettier@^2.6.2: version "2.6.2" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032" integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew== pretty-bytes@^3.0.0: @@ -19866,12 +20202,11 @@ pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" -pretty-format@^27.0.0, pretty-format@^27.4.2: - version "27.4.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.4.2.tgz#e4ce92ad66c3888423d332b40477c87d1dac1fb8" - integrity sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw== +pretty-format@^27.0.0, pretty-format@^27.4.6: + version "27.4.6" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz#1b784d2f53c68db31797b2348fa39b49e31846b7" + integrity sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g== dependencies: - "@jest/types" "^27.4.2" ansi-regex "^5.0.1" ansi-styles "^5.0.0" react-is "^17.0.1" @@ -19890,12 +20225,21 @@ preval.macro@^5.0.0: dependencies: babel-plugin-preval "^5.0.0" +printj@~1.1.0: + version "1.1.2" + resolved "http://registry.npmjs.org/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222" + printj@~1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/printj/-/printj-1.2.3.tgz#2cfb2b192a1e5385dbbe5b46658ac34aa828508a" integrity sha512-sanczS6xOJOg7IKDvi4sGOUOe7c1tsEzjwlLFH/zgwx/uyImVM9/rgBkc8AfiQa/Vg54nRd8mkm9yI7WV/O+WA== -printj@~1.3.0, printj@~1.3.1: +printj@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.0.tgz#9018a918a790e43707f10625d6e10187a367cff6" + integrity sha512-017o8YIaz8gLhaNxRB9eBv2mWXI2CtzhPJALnQTP+OPpuUfP0RMWqr/mHCzqVeu1AQxfzSfAtAq66vKB8y7Lzg== + +printj@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb" integrity sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg== @@ -19913,7 +20257,7 @@ private@^0.1.8: probe-image-size@^7.2.3: version "7.2.3" - resolved "https://registry.yarnpkg.com/probe-image-size/-/probe-image-size-7.2.3.tgz#d49c64be540ec8edea538f6f585f65a9b3ab4309" + resolved "https://registry.npmjs.org/probe-image-size/-/probe-image-size-7.2.3.tgz#d49c64be540ec8edea538f6f585f65a9b3ab4309" integrity sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w== dependencies: lodash.merge "^4.6.2" @@ -20154,9 +20498,9 @@ q@^1.1.2, q@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" -qs@6.10.3, qs@^6.1.0, qs@^6.4.0, qs@^6.5.2, qs@^6.9.4: +qs@6.10.3: version "6.10.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" + resolved "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== dependencies: side-channel "^1.0.4" @@ -20166,6 +20510,18 @@ qs@6.7.0: resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@6.9.6: + version "6.9.6" + resolved "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" + integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== + +qs@^6.1.0, qs@^6.4.0, qs@^6.5.2, qs@^6.9.4: + version "6.10.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.1.tgz#4931482fa8d647a5aab799c5271d2133b981fb6a" + integrity sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg== + dependencies: + side-channel "^1.0.4" + qs@~6.5.2: version "6.5.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" @@ -20246,9 +20602,19 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -raw-body@2.5.1, raw-body@^2.3.0, raw-body@^2.4.1: +raw-body@2.4.2, raw-body@^2.4.1: + version "2.4.2" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" + integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== + dependencies: + bytes "3.1.1" + http-errors "1.8.1" + iconv-lite "0.4.24" + unpipe "1.0.0" + +raw-body@2.5.1, raw-body@^2.3.0: version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== dependencies: bytes "3.1.2" @@ -20282,7 +20648,7 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8: react-dev-utils@^12.0.1: version "12.0.1" - resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73" + resolved "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73" integrity sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ== dependencies: "@babel/code-frame" "^7.16.0" @@ -20346,7 +20712,7 @@ react-dom@^16.12.0: react-error-overlay@^6.0.11: version "6.0.11" - resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" + resolved "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb" integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg== react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.4, react-is@^16.8.6: @@ -20837,7 +21203,7 @@ relateurl@^0.2.7: relay-compiler@12.0.0: version "12.0.0" - resolved "https://registry.yarnpkg.com/relay-compiler/-/relay-compiler-12.0.0.tgz#9f292d483fb871976018704138423a96c8a45439" + resolved "https://registry.npmjs.org/relay-compiler/-/relay-compiler-12.0.0.tgz#9f292d483fb871976018704138423a96c8a45439" integrity sha512-SWqeSQZ+AMU/Cr7iZsHi1e78Z7oh00I5SvR092iCJq79aupqJ6Ds+I1Pz/Vzo5uY5PY0jvC4rBJXzlIN5g9boQ== dependencies: "@babel/core" "^7.14.0" @@ -20860,7 +21226,7 @@ relay-compiler@12.0.0: relay-runtime@12.0.0: version "12.0.0" - resolved "https://registry.yarnpkg.com/relay-runtime/-/relay-runtime-12.0.0.tgz#1e039282bdb5e0c1b9a7dc7f6b9a09d4f4ff8237" + resolved "https://registry.npmjs.org/relay-runtime/-/relay-runtime-12.0.0.tgz#1e039282bdb5e0c1b9a7dc7f6b9a09d4f4ff8237" integrity sha512-QU6JKr1tMsry22DXNy9Whsq5rmvwr3LSZiiWV/9+DFpuTWvp+WFhobWMc8TC4OjKFfNhEZy7mOiqUAn5atQtug== dependencies: "@babel/runtime" "^7.0.0" @@ -21956,7 +22322,7 @@ resolve-options@^1.1.0: resolve-url-loader@^3.1.4: version "3.1.4" - resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.1.4.tgz#3c16caebe0b9faea9c7cc252fa49d2353c412320" + resolved "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.4.tgz#3c16caebe0b9faea9c7cc252fa49d2353c412320" integrity sha512-D3sQ04o0eeQEySLrcz4DsX3saHfsr8/N6tfhblxgZKXxMT2Louargg12oGNfoTRLV09GXhVUe5/qgA5vdgNigg== dependencies: adjust-sourcemap-loader "3.0.0" @@ -21976,7 +22342,7 @@ resolve-url@^0.2.1: resolve.exports@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== resolve@1.1.7: @@ -21990,9 +22356,17 @@ resolve@1.17.0: dependencies: path-parse "^1.0.6" -resolve@^1.1.3, resolve@^1.1.5, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.2.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.3.2, resolve@^1.8.1, resolve@^1.9.0: +resolve@^1.1.3, resolve@^1.1.5, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.2.0, resolve@^1.20.0, resolve@^1.3.2, resolve@^1.8.1, resolve@^1.9.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +resolve@^1.22.0: version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== dependencies: is-core-module "^2.8.1" @@ -22196,7 +22570,7 @@ reusify@^1.0.4: rewire@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/rewire/-/rewire-6.0.0.tgz#54f4fcda4df9928d28af1eb54a318bc51ca9aa99" + resolved "https://registry.npmjs.org/rewire/-/rewire-6.0.0.tgz#54f4fcda4df9928d28af1eb54a318bc51ca9aa99" integrity sha512-7sZdz5dptqBCapJYocw9EcppLU62KMEqDLIILJnNET2iqzXHaQfaVP5SOJ06XvjX+dNIDJbzjw0ZWzrgDhtjYg== dependencies: eslint "^7.32.0" @@ -22507,7 +22881,7 @@ scheduler@^0.20.2: schema-utils@2.7.0: version "2.7.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" + resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7" integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A== dependencies: "@types/json-schema" "^7.0.4" @@ -22588,9 +22962,16 @@ semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7: +semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + +semver@^7.3.7: version "7.3.7" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== dependencies: lru-cache "^6.0.0" @@ -22627,7 +23008,7 @@ sentence-case@^2.1.0: sentence-case@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" + resolved "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz#3645a7b8c117c787fde8702056225bb62a45131f" integrity sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg== dependencies: no-case "^3.0.4" @@ -22696,7 +23077,7 @@ set-value@^2.0.0, set-value@^2.0.1: setimmediate@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= setprototypeof@1.1.1: @@ -22725,7 +23106,7 @@ shallow-copy@~0.0.1: sharp@^0.30.3: version "0.30.3" - resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.30.3.tgz#315a1817423a4d1cde5119a21c99c234a7a6fb37" + resolved "https://registry.npmjs.org/sharp/-/sharp-0.30.3.tgz#315a1817423a4d1cde5119a21c99c234a7a6fb37" integrity sha512-rjpfJFK58ZOFSG8sxYSo3/JQb4ej095HjXp9X7gVu7gEn1aqSG8TCW29h/Rr31+PXrFADo1H/vKfw0uhMQWFtg== dependencies: color "^4.2.1" @@ -22759,9 +23140,14 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.6.1, shell-quote@^1.7.3: +shell-quote@^1.6.1: + version "1.7.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + +shell-quote@^1.7.3: version "1.7.3" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" + resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== shelljs@^0.8.3: @@ -22776,7 +23162,6 @@ shelljs@^0.8.3: shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== shift-left@^0.1.5: version "0.1.5" @@ -22797,14 +23182,19 @@ sift@^7.0.1: resolved "https://registry.yarnpkg.com/sift/-/sift-7.0.1.tgz#47d62c50b159d316f1372f8b53f9c10cd21a4b08" integrity sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g== -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.5, signal-exit@^3.0.6, signal-exit@^3.0.7: +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.5, signal-exit@^3.0.6: + version "3.0.6" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== + +signal-exit@^3.0.7: version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== signedsource@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/signedsource/-/signedsource-1.0.0.tgz#1ddace4981798f93bd833973803d80d52e93ad6a" + resolved "https://registry.npmjs.org/signedsource/-/signedsource-1.0.0.tgz#1ddace4981798f93bd833973803d80d52e93ad6a" integrity sha1-HdrOSYF5j5O9gzlzgD2A1S6TrWo= simple-concat@^1.0.0: @@ -22899,7 +23289,7 @@ snake-case@^2.1.0: snake-case@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + resolved "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== dependencies: dot-case "^3.0.4" @@ -23010,7 +23400,7 @@ source-list-map@^1.1.1: source-list-map@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== source-map-js@^0.6.2: @@ -23140,7 +23530,7 @@ split@^1.0.0: sponge-case@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/sponge-case/-/sponge-case-1.0.1.tgz#260833b86453883d974f84854cdb63aecc5aef4c" + resolved "https://registry.npmjs.org/sponge-case/-/sponge-case-1.0.1.tgz#260833b86453883d974f84854cdb63aecc5aef4c" integrity sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA== dependencies: tslib "^2.0.3" @@ -23218,7 +23608,7 @@ stack-utils@^1.0.1: stack-utils@^2.0.2, stack-utils@^2.0.3: version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== dependencies: escape-string-regexp "^2.0.0" @@ -23435,7 +23825,7 @@ string-width@^3.0.0, string-width@^3.1.0: string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" @@ -23444,7 +23834,7 @@ string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2 string.prototype.matchall@^4.0.6: version "4.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" + resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== dependencies: call-bind "^1.0.2" @@ -23554,7 +23944,7 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" @@ -23872,7 +24262,7 @@ supports-hyperlinks@^2.0.0: supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== svgo@1.3.2, svgo@^1.0.0: @@ -23906,9 +24296,22 @@ svgo@^0.7.2: sax "~1.2.1" whet.extend "~0.9.9" -svgo@^2.3.0, svgo@^2.8.0: +svgo@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.3.0.tgz#6b3af81d0cbd1e19c83f5f63cec2cb98c70b5373" + integrity sha512-fz4IKjNO6HDPgIQxu4IxwtubtbSfGEAJUq/IXyTPIkGhWck/faiiwfkvsB8LnBkKLvSoyNNIY6d13lZprJMc9Q== + dependencies: + "@trysound/sax" "0.1.1" + chalk "^4.1.0" + commander "^7.1.0" + css-select "^3.1.2" + css-tree "^1.1.2" + csso "^4.2.0" + stable "^0.1.8" + +svgo@^2.8.0: version "2.8.0" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" + resolved "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg== dependencies: "@trysound/sax" "0.2.0" @@ -23950,7 +24353,7 @@ swap-case@^1.1.0: swap-case@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-2.0.2.tgz#671aedb3c9c137e2985ef51c51f9e98445bf70d9" + resolved "https://registry.npmjs.org/swap-case/-/swap-case-2.0.2.tgz#671aedb3c9c137e2985ef51c51f9e98445bf70d9" integrity sha512-kc6S2YS/2yXbtkSMunBtKdah4VFETZ8Oh6ONSmSd9bRxhqTrtARUCBUiWXH3xVPpvR7tz2CSnkuXVE42EcGnMw== dependencies: tslib "^2.0.3" @@ -23961,7 +24364,7 @@ symbol-observable@^1.0.4: symbol-observable@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" + resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== symbol-tree@^3.2.2, symbol-tree@^3.2.4: @@ -24174,7 +24577,7 @@ thenify-all@^1.0.0: throat@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + resolved "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== through2-filter@^2.0.0: @@ -24232,7 +24635,7 @@ timsort@^0.3.0: tiny-async-pool@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz#c013e1b369095e7005db5595f95e646cca6ef8a5" + resolved "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz#c013e1b369095e7005db5595f95e646cca6ef8a5" integrity sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA== dependencies: semver "^5.5.0" @@ -24283,7 +24686,7 @@ title-case@^2.1.0: title-case@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/title-case/-/title-case-3.0.3.tgz#bc689b46f02e411f1d1e1d081f7c3deca0489982" + resolved "https://registry.npmjs.org/title-case/-/title-case-3.0.3.tgz#bc689b46f02e411f1d1e1d081f7c3deca0489982" integrity sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA== dependencies: tslib "^2.0.3" @@ -24379,7 +24782,7 @@ toidentifier@1.0.0: toidentifier@1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== token-types@^2.0.0: @@ -24448,10 +24851,10 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" -tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== +tr46@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479" + integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== dependencies: punycode "^2.1.1" @@ -24516,7 +24919,7 @@ trough@^1.0.0: ts-invariant@^0.9.4: version "0.9.4" - resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.9.4.tgz#42ac6c791aade267dd9dc65276549df5c5d71cac" + resolved "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.9.4.tgz#42ac6c791aade267dd9dc65276549df5c5d71cac" integrity sha512-63jtX/ZSwnUNi/WhXjnK8kz4cHHpYS60AnmA6ixz17l7E12a5puCWFlNpkne5Rl0J8TBPVHpGjsj4fxs8ObVLQ== dependencies: tslib "^2.1.0" @@ -24534,7 +24937,7 @@ tsc-watch@^4.5.0: tsconfig-paths@^3.14.1: version "3.14.1" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== dependencies: "@types/json5" "^0.0.29" @@ -24552,9 +24955,14 @@ tslib@^1.10.0, tslib@^1.6.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== -tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@~2.3.0: +tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.2.0.tgz#fb2c475977e35e241311ede2693cee1ec6698f5c" + integrity sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w== + +tslib@^2.3.0, tslib@~2.3.0: version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== tslib@~2.0.1: @@ -24567,6 +24975,11 @@ tslib@~2.1.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a" integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A== +tslib@~2.4.0: + version "2.4.0" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + tsscmp@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb" @@ -24689,9 +25102,14 @@ typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@^4.1.3, typescript@^4.6.3, typescript@^4.6.4: +typescript@^4.1.3: + version "4.5.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3" + integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA== + +typescript@^4.6.3, typescript@^4.6.4: version "4.6.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9" integrity sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg== typography-normalize@^0.16.19: @@ -24714,7 +25132,7 @@ typography@^0.16.21: ua-parser-js@^0.7.30: version "0.7.31" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" + resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz#649a656b191dffab4f21d5e053e27ca17cbff5c6" integrity sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ== uc.micro@^1.0.1, uc.micro@^1.0.5: @@ -25188,7 +25606,6 @@ universal-user-agent@^6.0.0: universalify@^0.1.0, universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== universalify@^1.0.0: version "1.0.0" @@ -25284,7 +25701,7 @@ upper-case-first@^1.1.0, upper-case-first@^1.1.2: upper-case-first@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" + resolved "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz#992c3273f882abd19d1e02894cc147117f844324" integrity sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg== dependencies: tslib "^2.0.3" @@ -25295,7 +25712,7 @@ upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1, upper-case@^1.1.3: upper-case@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" + resolved "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz#d89810823faab1df1549b7d97a76f8662bae6f7a" integrity sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg== dependencies: tslib "^2.0.3" @@ -25306,9 +25723,14 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -urijs@^1.16.1, urijs@^1.18.2, urijs@^1.19.11: +urijs@^1.16.1, urijs@^1.18.2: + version "1.19.8" + resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.8.tgz#ee0407a18528934d3c383e691912f47043a58feb" + integrity sha512-iIXHrjomQ0ZCuDRy44wRbyTZVnfVNLVo3Ksz1yxNyE5wV1IDZW2S5Jszy45DTlw/UdsnRT7DyDhIz7Gy+vJumw== + +urijs@^1.19.11: version "1.19.11" - resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.11.tgz#204b0d6b605ae80bea54bea39280cdb7c9f923cc" + resolved "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz#204b0d6b605ae80bea54bea39280cdb7c9f923cc" integrity sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ== urix@^0.1.0: @@ -25436,7 +25858,7 @@ v8-to-istanbul@^7.1.0: v8-to-istanbul@^8.1.0: version "8.1.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz#0aeb763894f1a0a1676adf8a8b7612a38902446c" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz#0aeb763894f1a0a1676adf8a8b7612a38902446c" integrity sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" @@ -25478,7 +25900,7 @@ value-or-function@^3.0.0: value-or-promise@1.0.11: version "1.0.11" - resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" + resolved "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg== vary@^1, vary@~1.1.2: @@ -25852,7 +26274,7 @@ webpack-sources@^0.2.0: webpack-sources@^1.1.0: version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== dependencies: source-list-map "^2.0.0" @@ -25966,12 +26388,12 @@ whatwg-url@^7.0.0: webidl-conversions "^4.0.2" whatwg-url@^8.0.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + version "8.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.5.0.tgz#7752b8464fc0903fec89aa9846fc9efe07351fd3" + integrity sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg== dependencies: lodash "^4.7.0" - tr46 "^2.1.0" + tr46 "^2.0.2" webidl-conversions "^6.1.0" when@~3.6.x: @@ -26409,9 +26831,9 @@ xss@^1.0.6: cssfilter "0.0.10" xstate@^4.26.0, xstate@^4.26.1: - version "4.26.1" - resolved "https://registry.yarnpkg.com/xstate/-/xstate-4.26.1.tgz#4fc1afd153f88cf302a9ee2b758f6629e6a829b6" - integrity sha512-JLofAEnN26l/1vbODgsDa+Phqa61PwDlxWu8+2pK+YbXf+y9pQSDLRvcYH2H1kkeUBA5fGp+xFL/zfE8jNMw4g== + version "4.27.0" + resolved "https://registry.npmjs.org/xstate/-/xstate-4.27.0.tgz#f3c918ac4229bd5e6dec2231e991ba55c6bfa559" + integrity sha512-ohOwDM9tViC/zSSmY9261CHblDPqiaAk5vyjVbi69uJv9fGWMzlm0VDQwM2OvC61GKfXVBeuWSMkL7LPUsTpfA== xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" @@ -26495,7 +26917,7 @@ yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^20.2.7, yargs-parser@^ yargs-parser@^21.0.0: version "21.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz#a485d3966be4317426dd56bdb6a30131b281dc55" integrity sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA== yargs@16.2.0, yargs@^16.2.0: @@ -26563,7 +26985,7 @@ yargs@^15.3.1, yargs@^15.4.0, yargs@^15.4.1: yargs@^17.0.1, yargs@^17.3.1: version "17.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== dependencies: cliui "^7.0.2" @@ -26615,14 +27037,14 @@ yurnalist@^2.1.0: zen-observable-ts@^1.2.0: version "1.2.3" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.2.3.tgz#c2f5ccebe812faf0cfcde547e6004f65b1a6d769" + resolved "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.3.tgz#c2f5ccebe812faf0cfcde547e6004f65b1a6d769" integrity sha512-hc/TGiPkAWpByykMwDcem3SdUgA4We+0Qb36bItSuJC9xD0XVBZoFHYoadAomDSNf64CG8Ydj0Qb8Od8BUWz5g== dependencies: zen-observable "0.8.15" zen-observable@0.8.15: version "0.8.15" - resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + resolved "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== zipkin-javascript-opentracing@^3.0.0: From 78904aa750cfab6109ba221440f32d62d235c308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 5 May 2021 18:57:16 +0200 Subject: [PATCH 016/149] refactor: flatten Contentful asset data structure to match GraphQL API schema (#31115) --- .../src/pages/gatsby-plugin-image.js | 54 +++++------ .../contentful/src/pages/media-reference.js | 90 +++++-------------- .../src/__tests__/gatsby-node.js | 7 +- .../src/gatsby-plugin-image.js | 25 +++--- .../src/generate-schema.js | 57 ++++-------- .../src/image-helpers.js | 2 +- .../gatsby-source-contentful/src/normalize.js | 12 +-- 7 files changed, 86 insertions(+), 161 deletions(-) diff --git a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js index e5ef0b60f9e41..deb54a7640138 100644 --- a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js +++ b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js @@ -16,14 +16,14 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.file.fileName.split(".").pop()}) + {node.title} ({node.fileName.split(".").pop()})

{node.description &&

{node.description}

} {node.constrained ? ( ) : ( - + )}
))} @@ -34,14 +34,14 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.file.fileName.split(".").pop()}) + {node.title} ({node.fileName.split(".").pop()})

{node.description &&

{node.description}

} {node.fullWidth ? ( ) : ( - + )}
))} @@ -53,14 +53,14 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.file.fileName.split(".").pop()}) + {node.title} ({node.fileName.split(".").pop()})

{node.description &&

{node.description}

} {node.fixed ? ( ) : ( - + )}
))} @@ -72,14 +72,14 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.file.fileName.split(".").pop()}) + {node.title} ({node.fileName.split(".").pop()})

{node.description &&

{node.description}

} {node.dominantColor ? ( ) : ( - + )}
))} @@ -91,14 +91,14 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.file.fileName.split(".").pop()}) + {node.title} ({node.fileName.split(".").pop()})

{node.description &&

{node.description}

} {node.traced ? ( ) : ( - + )}
))} @@ -110,14 +110,14 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.file.fileName.split(".").pop()}) + {node.title} ({node.fileName.split(".").pop()})

{node.description &&

{node.description}

} {node.blurred ? ( ) : ( - + )}
))} @@ -148,7 +148,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.file.fileName.split(".").pop()}) + {node.title} ({node.fileName.split(".").pop()})

{node.description &&

{node.description}

} @@ -162,7 +162,7 @@ const GatsbyPluginImagePage = ({ data }) => { }} /> ) : ( - + )}
))} @@ -174,14 +174,14 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.file.fileName.split(".").pop()}) + {node.title} ({node.fileName.split(".").pop()})

{node.description &&

{node.description}

} {node.constrained ? ( ) : ( - + )}
))} @@ -193,14 +193,14 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.file.fileName.split(".").pop()}) + {node.title} ({node.fileName.split(".").pop()})

{node.description &&

{node.description}

} {node.constrained ? ( ) : ( - + )}
))} @@ -231,10 +231,8 @@ export const pageQuery = graphql` nodes { title description - file { - fileName - url - } + fileName + url constrained: gatsbyImageData(width: 420) fullWidth: gatsbyImageData(width: 200, layout: FIXED) fixed: gatsbyImageData(width: 200, layout: FIXED) @@ -268,10 +266,8 @@ export const pageQuery = graphql` nodes { title description - file { - fileName - url - } + fileName + url constrained: gatsbyImageData(width: 420) } } @@ -284,10 +280,8 @@ export const pageQuery = graphql` nodes { title description - file { - fileName - url - } + fileName + url constrained: gatsbyImageData(width: 420) } } diff --git a/e2e-tests/contentful/src/pages/media-reference.js b/e2e-tests/contentful/src/pages/media-reference.js index 9361b6b641bc0..dfd9402cfeb8a 100644 --- a/e2e-tests/contentful/src/pages/media-reference.js +++ b/e2e-tests/contentful/src/pages/media-reference.js @@ -16,14 +16,12 @@ const MediaReferencePage = ({ data }) => { let content = null if (many) { content = many.map(imageData => ( - {title} + {title} )) } if (one) { - content = ( - {title} - ) + content = {title} } return ( @@ -41,38 +39,24 @@ const MediaReferencePage = ({ data }) => { let content = null if (manyLocalized) { content = manyLocalized.map(imageData => ( - {title} + {title} )) } if (oneLocalized) { content = ( - {title} + {title} ) } if (many) { content = many.map(imageData => ( - {title} + {title} )) } if (one) { - content = ( - {title} - ) + content = {title} } return ( @@ -92,38 +76,24 @@ const MediaReferencePage = ({ data }) => { let content = null if (manyLocalized) { content = manyLocalized.map(imageData => ( - {title} + {title} )) } if (oneLocalized) { content = ( - {title} + {title} ) } if (many) { content = many.map(imageData => ( - {title} + {title} )) } if (one) { - content = ( - {title} - ) + content = {title} } return ( @@ -155,14 +125,10 @@ export const pageQuery = graphql` id } one { - file { - url - } + url } many { - file { - url - } + url } } } @@ -179,24 +145,16 @@ export const pageQuery = graphql` id } one { - file { - url - } + url } many { - file { - url - } + url } oneLocalized { - file { - url - } + url } manyLocalized { - file { - url - } + url } } } @@ -213,24 +171,16 @@ export const pageQuery = graphql` id } one { - file { - url - } + url } many { - file { - url - } + url } oneLocalized { - file { - url - } + url } manyLocalized { - file { - url - } + url } } } diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index b23a4052c2767..e864a4bb5dbe0 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -376,7 +376,12 @@ describe(`gatsby-node`, () => { true, noLocaleFallback ) || ``, - file, + contentType: file.contentType, + fileName: file.fileName, + url: file.url, + size: file.details.size, + width: file.details?.image?.width || null, + height: file.details?.image?.height || null, }) }) }) diff --git a/packages/gatsby-source-contentful/src/gatsby-plugin-image.js b/packages/gatsby-source-contentful/src/gatsby-plugin-image.js index d642aff4ffc7a..8dd086291d89e 100644 --- a/packages/gatsby-source-contentful/src/gatsby-plugin-image.js +++ b/packages/gatsby-source-contentful/src/gatsby-plugin-image.js @@ -82,10 +82,7 @@ const getBase64Image = (imageProps, cache) => { const getTracedSVG = async ({ image, options, cache }) => { const { traceSVG } = await import(`gatsby-plugin-sharp`) - - const { - file: { contentType, url: imgUrl, fileName }, - } = image + const { url: imgUrl, fileName, contentType } = image if (contentType.indexOf(`image/`) !== 0) { return null @@ -106,7 +103,7 @@ const getTracedSVG = async ({ image, options, cache }) => { return traceSVG({ file: { internal: image.internal, - name: image.file.fileName, + name: fileName, extension, absolutePath, }, @@ -173,20 +170,18 @@ const getDominantColor = async ({ image, options, cache }) => { } function getBasicImageProps(image, args) { - let aspectRatio + let { width, height } = image if (args.width && args.height) { - aspectRatio = args.width / args.height - } else { - aspectRatio = - image.file.details.image.width / image.file.details.image.height + width = args.width + height = args.height } return { - baseUrl: image.file.url, - contentType: image.file.contentType, - aspectRatio, - width: image.file.details.image.width, - height: image.file.details.image.height, + baseUrl: image.url, + contentType: image.contentType, + aspectRatio: width / height, + width, + height, } } diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index b55d701cf99e3..27cef28b4c103 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -107,32 +107,14 @@ const translateFieldType = field => { function generateAssetTypes({ createTypes }) { createTypes(` type ContentfulAsset implements ContentfulInternalReference & Node { - file: ContentfulAssetFile - title: String - description: String sys: ContentfulInternalSys id: ID! - } - `) - - createTypes(` - type ContentfulAssetFile @derivedTypes { - url: String - details: ContentfulAssetFileDetails - fileName: String + title: String + description: String contentType: String - } - `) - - createTypes(` - type ContentfulAssetFileDetails @derivedTypes { + fileName: String + url: String size: Int - image: ContentfulAssetFileDetailsImage - } - `) - - createTypes(` - type ContentfulAssetFileDetailsImage { width: Int height: Int } @@ -187,24 +169,21 @@ export function generateSchema({ generateAssetTypes({ createTypes }) // Rich Text - const makeRichTextLinksResolver = (nodeType, entityType) => ( - source, - args, - context - ) => { - const links = getRichTextEntityLinks(source, nodeType)[entityType].map( - ({ id }) => id - ) + const makeRichTextLinksResolver = + (nodeType, entityType) => (source, args, context) => { + const links = getRichTextEntityLinks(source, nodeType)[entityType].map( + ({ id }) => id + ) - return context.nodeModel.getAllNodes().filter( - node => - node.internal.owner === `gatsby-source-contentful` && - node?.sys?.id && - node?.sys?.type === entityType && - links.includes(node.sys.id) - // @todo how can we check for correct space and environment? We need to access the sys field of the fields parent entry. - ) - } + return context.nodeModel.getAllNodes().filter( + node => + node.internal.owner === `gatsby-source-contentful` && + node?.sys?.id && + node?.sys?.type === entityType && + links.includes(node.sys.id) + // @todo how can we check for correct space and environment? We need to access the sys field of the fields parent entry. + ) + } // Contentful specific types if (pluginConfig.get(`enableTags`)) { diff --git a/packages/gatsby-source-contentful/src/image-helpers.js b/packages/gatsby-source-contentful/src/image-helpers.js index 7bfe412e93f69..dcfc5ecde2836 100644 --- a/packages/gatsby-source-contentful/src/image-helpers.js +++ b/packages/gatsby-source-contentful/src/image-helpers.js @@ -20,7 +20,7 @@ export const mimeTypeExtensions = new Map([ // Check if Contentful asset is actually an image export function isImage(image) { - return mimeTypeExtensions.has(image?.file?.contentType) + return mimeTypeExtensions.has(image?.contentType) } // Create a Contentful Image API url diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index 6d2a93a3ddfb4..b1869b9db8e4d 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -601,10 +601,6 @@ export const createAssetNodes = ({ parent: null, children: [], file, - title: assetItem.fields.title ? getField(assetItem.fields.title) : ``, - description: assetItem.fields.description - ? getField(assetItem.fields.description) - : ``, internal: { type: `${makeTypeName(`Asset`)}`, // The content of an asset is guaranteed to be updated if and only if the .sys.updatedAt field changed @@ -622,7 +618,6 @@ export const createAssetNodes = ({ publishedAt: assetItem.sys.updatedAt, publishedVersion: assetItem.sys.revision, }, - url: `https:${file.url}`, placeholderUrl: `https:${file.url}?w=%width%&h=%height%`, // These fields are optional for edge cases in the Preview API and Contentfuls asset processing mimeType: file.contentType, @@ -630,6 +625,13 @@ export const createAssetNodes = ({ width: file.details?.image?.width ?? null, height: file.details?.image?.height ?? null, size: file.details?.size ?? null, + title: assetItem.fields.title ? getField(assetItem.fields.title) : ``, + description: assetItem.fields.description + ? getField(assetItem.fields.description) + : ``, + contentType: file.contentType, + fileName: file.fileName, + url: `https:${file.url}`, } // Link tags From 90f5b591f84be1a3159e9d53f13b523b0f649a00 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Thu, 20 May 2021 16:10:29 +0200 Subject: [PATCH 017/149] update e2e snapshots --- e2e-tests/contentful/snapshots.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index c7626ba18be77..1cdc53a9fd32e 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -45,14 +45,17 @@ module.exports = { "rich-text: Embedded Entry With Reference Loop": { "1": "
\n

Rich Text: Embedded entry with reference loop

\n

Embedded entry with reference loop

\n

[ContentfulReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n

\n
\n
" }, + "rich-text: All Features": { + "1": "
\n

Rich Text: All Features

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n
\"\"\n\n \n \n \n
\n

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
  7. \n

    [Inline-ContentfulText]\n :

    \n
  8. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n

[ContentfulLocation] Lat:\n 52.51627\n , Long:\n 13.3777

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
" + }, "rich-text: Inline Entry": { - "1": "
\n

Rich Text: Inline entry

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-ContentfulText]\n Text: Short\n :\n The quick brown fox jumps over the lazy dog. and before\n that

\n

\n

\n
\n
" + "1": "
\n

Rich Text: Inline entry

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-ContentfulText]\n : and before that

\n

\n

\n
\n
" }, "rich-text: Inline Entry With Deep Reference Loop": { - "1": "
\n

Rich Text: Inline entry with deep reference loop

\n

Inline entry with deep reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ]\n Content Reference: Many (2nd level loop) and before that\n

\n

\n

\n
\n
" + "1": "
\n

Rich Text: Inline entry with deep reference loop

\n

Inline entry with deep reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ] and before that

\n

\n

\n
\n
" }, "rich-text: Inline Entry With Reference Loop": { - "1": "
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ]\n Content Reference: One (Loop A -> B) and before that

\n

\n

\n
\n
" + "1": "
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ] and before that

\n

\n

\n
\n
", }, "rich-text: Localized": { "1": "
\n

Rich Text: Localized

\n

Rich Text in English

\n
\n
", From 15fd737130c61f75ce96fc687147cd783947eebf Mon Sep 17 00:00:00 2001 From: axe312ger Date: Fri, 11 Jun 2021 10:18:28 +0200 Subject: [PATCH 018/149] fix: render RichText without links --- packages/gatsby-source-contentful/src/rich-text.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/gatsby-source-contentful/src/rich-text.js b/packages/gatsby-source-contentful/src/rich-text.js index 0019e715e59fc..26e3e19fe4a76 100644 --- a/packages/gatsby-source-contentful/src/rich-text.js +++ b/packages/gatsby-source-contentful/src/rich-text.js @@ -18,27 +18,27 @@ exports.renderRichText = renderRichText */ function generateLinkMaps(links) { const assetBlockMap = new Map() - for (const asset of links.assets.block || []) { + for (const asset of links?.assets.block || []) { assetBlockMap.set(asset.sys.id, asset) } const assetHyperlinkMap = new Map() - for (const asset of links.assets.hyperlink || []) { + for (const asset of links?.assets.hyperlink || []) { assetHyperlinkMap.set(asset.sys.id, asset) } const entryBlockMap = new Map() - for (const entry of links.entries.block || []) { + for (const entry of links?.entries.block || []) { entryBlockMap.set(entry.sys.id, entry) } const entryInlineMap = new Map() - for (const entry of links.entries.inline || []) { + for (const entry of links?.entries.inline || []) { entryInlineMap.set(entry.sys.id, entry) } const entryHyperlinkMap = new Map() - for (const entry of links.entries.hyperlink || []) { + for (const entry of links?.entries.hyperlink || []) { entryHyperlinkMap.set(entry.sys.id, entry) } From ce6ce57477dde7d4dbdaa13e1d5b608f1e7d403b Mon Sep 17 00:00:00 2001 From: axe312ger Date: Fri, 11 Jun 2021 10:27:42 +0200 Subject: [PATCH 019/149] test(e2e): update snapshots --- .../gatsby-plugin-image.js/german-0.snap.png | Bin 4168 -> 2570 bytes e2e-tests/contentful/snapshots.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/contentful/cypress/snapshots/gatsby-plugin-image.js/german-0.snap.png b/e2e-tests/contentful/cypress/snapshots/gatsby-plugin-image.js/german-0.snap.png index e6f13231933f9e761eda1ea416b7ef7fcf8c6632..95de3c6a3c374eb622afd9bc6324232b9664610d 100644 GIT binary patch literal 2570 zcmds3VNeri8cwzeT@qmeCdMPQBsSGx<|x%eaLQ>&jLpiSX^?Oz3(_+byp#*Y$0q5IfNH z=mxC#ljPm5$FD%?r^c=%AF`6hRYHDcEUEoBC!=xVa;K%3W#c4vB1uRJ;BXmjCK z3u=$m^n15T+Jp)}Lf2*nEJZ1!M9K z_Ipd1Lo|Jn9My$t-Yv+L>O!LQS!(IL9PE+fpDt;7t=n2|Y!4!ao* z2zG4NI(^?HfOyqUtfUY8Pf;K=u~eDy?S$L3O|OrB(u!))kted%<(qTgFEzEpuW zx(EOG!JdBa2qR%#4{RkAUxVT&OAf=T(UVWgbfJ~32MRrG>8ap!DNm@-OQVQO)91aL zwL=kUi;To!OAGw&c+ELNitT(0?nld1PCJ*BMSJA$%uj3Cu!0-zV-?O*5B?^BE{-d@ zP~Oj87D*ci`{%=Ldtp5C)EiBi4Mz*y8?f4=odWp}GvTrvb;6i9Sm<2-t)$InJ{#NL z$~aV(BUN>q*UEpex7frNqSQQ`gs=!bue6(eL2}aai_ON8i;azm&0K^{(v`!igExg# z(U*se?OaNhf+iNNZ#UJpvorkTN_}=3oO&eDdT>-Eh>faA5UoOZ5yC5uv3vqYUNCBqd+ z^E`s~$i^r++Lw}%mjC7SlSkrxT!R5EkPBM(yqZv$49}CJg64=U$ZIk_Ps;xr@pnI& zVnPZZ2A{fBxjO0G1=Truc}Y0~;7ZH|`^mVzVDS7dcPMX&0dTWp51bRm_2Y&5jhXwh z_Avl%0&hEqaXlbZoUvVe?;-<02VOqHxQ_E&7+HP0ngO5#FWU;P(?wiLPG6!682~!) z>?&~Gd=@b|WA{OZ$!P{U@HA3zeWKF31?zYdWNg7EfDSwv<9b^DSjCB)JA|f8+)USZ zh#H8xUuw2+{R;}8b=y^80-q?H5t1d$pe4*zR0&~zO;&%#QYEY3kIs1Ot5LD&Ka`P{ zLc6L%Ay^=*!WSM-#TxpTABE92cPUvl;9lex5P1LcE8kKQT5E-SySmQPxvy{eV%S-n zSy>Y7_0He_I(EstR_B?!)>$JhcO3&4MugZGm#)x7b1pGAcZlc0yOF~A8V{{U_1P7n z#ltU@zo?g*#Gc0nF6qnf@y`Es`q_wVN)d>E-|O9ZZ(71dT!XRwdpQb!aiMedHwVi& z3V0n(<#?hbJPiiT;#MB?X{|gb*L&DJS^)Wx_psY|*r5h(>)|=v9uX+~F-P2JMIsJ_ z3p!_a4-j=8g2m=}J1@_1$Y%+2wLB@?cE@#t)S7bT$u}}KkwvP+%j_QS&hMr-k*8zE z?)Y;Rp@P?Ay9c=F3dwHJkJSXS<-jill?pyvF2^)QUeEjJ-Z?b)SUJ3)}xBXrQ_Kf^4;^TwG(BGsM zh+kU1O8xkuUuZ0R^uSwfkUsQRxUkSA?JL_)>`qPi{^8f{zaAUD;CcRsU2yZ|`t@7Q zVfd1k6f+cB(IPlw3ai+AAO*O%|9Ab163@$lGR2pZ-!X?RZFI>}%$GkcZ%H9v46A5S z%-2-4q>R7o>0O)gMm=jYt9dWZmObtnpk|2O<+(reN<|B4zSHAYq1C*ldPO#WvbmTS zE}t`UPf&sM2rIS5l?nw3 zRY81z8w-xJ5RChOHkcbcx4w5oy0UOZ>}MbbWPeuGHfJP@NQ68GOSM@9(IRZ>H0mSy z)?Bt~*7Odvlo(kRWE`*5(6+&GGM>&%uL{!7o~ztuq8)CW4e=Msq;tMH(j5x@a5-Kd zq8t`$m{@(kI=~BOBE)N%kIFCgJAyHj8_J7QVWJnVWGQB{nfItDwdV!fsSKkR?oii2 znohAGH*>sfpR=T1xN>D194FH4`CKgbvJnuh7j8_@I%m9R??e(KFxbux4P!uk9aycHLwTVMMGIFOnC4qX1k=AV-?TfY846tI>M2tjY zO4q$E2z@+QY9xd8$2(rDY@QG&JEKJcnKYxhn7XseRIkPB6hI65)W+Smq{W>E8Sk>5 zy|z0LJ|99odOoYz*LetH-5tFdLPeb}q!wb$6!|(0&-VUgisZ`k4`*Ro!-oTD+)Puw zb3_C+oEJflklLT~w9`Jl(cfRm48+6=bFO3BS4!7*cW>=s#|!Vw4&)+Zj`j@ggqed3 zSO_YZ{?CY*(G7De+J21WY1=XmRiicD$Wo$^%~vwf8gFFVAOOpr6Z+0yM|%2R#sh!Fu%zTVCi$6aSdzfiWo)wdAnL!aM+VZ9 zdXW9G*;C)u0LK9nl61L#MA{mqXe0 z3wEqm3tGjW&!z@Ynm$2=WhufE85^NY?9sRn4;f**xud>S*TBTNY z#gwL|DQT?oTDV(eb^4j>$kj#@{Y+EFp{dGupY$*K8GfU{L!sbT(0}!YLbBzD zdr76iT+M`8@p5`HqP(S=5a%CITL{U7`6*5M_8N-~`p=8q52neBj5R)@Xd;(3EjGmc zaBm9_wQs1?qaN6R?cHE_nuAB}uJ3NVb!7!u{`Q)z+a}ZoNuHb`qxS4A)%!;rz}`H$ z*f5~D`+8PzMT_J9ydh8@9mzOtC6gF|e5aXF)#7md&b5QFl<2N>78u7D|BQMjR?gxu z;H6cjn6DcgwL(pbd4*#?77hA)cCCw}R?u{Wik7^EwO#o6ZNkAw0F!d;TYJUT8$+b0 z`&&|`Yh5~)9&8h3yU}gcK3y0Oc9JOl^Rugcqr-h7Ex_y0KOX3jgPivl3>>hwD1H5w zNPy$sq9{v5k00ri+4@%UMe?yP3p%3!HK(r3s=jKgJIFo!#|}8GqT#;1&e?uyM?;9@ ziT<7xU|KRKN3TgHN{qI;LNuW&A66T)O~ru#pFh7geugZfF57ympnNv)km@|G1!jX)&jSnCZ?d-vi@?s8C33C5F~Sv66Usa1tRQ-O zA!_i-KDB!=P02(hK!4*qg=#f%kQh6;33#T3d}n)ArG^)nio#d8gioczpko8|j(-Ij z^Dsblcj?pFs#9=W?Bpo8he6Y;+BSF`mHac_Y5}UmVVAicVu2OceDb_mj7BcK4$z_% zU{C$*#~nH8-?*|0LDlfQ;S73H*%wzj&|{wddGsXdLG(jg9aD%tt}LOeFoKYDtn&lw z5SI=fdYyeShqh&Uqv0v<$u+Og-Ok_YWTwX>C^>9}d5|>oZ9lzi{ zF&FI5t44?-=WC_bddEm9XxBf}S&!Xw-?J~sNRAC4$tTA&ybJBK)^Qy-qH#}Vh!ZQ% zNGd_JmDTdObvv7R%LJ8`c-hLy$EY>e8V7si=Ar-Q0)eN@^U!0{=4hq;qQS_KbLTH+ zD40uQ1D5hHDD-^3?qJseVW`T?rFWZ#1g-t3`#O@8rkrR+^I{;c+sdsb@MFp? zotRCvFwnfVV6VFfMe2Y-UVNh0J%%EYv>-2+?R9feq#`z&H=se?=t3%LJ&tU5lshpe zvmhAC$Ke`{fIUEvfMEHkky7?_n}`8Wge?g*SpMh)#i-WMy1@8G3%6AZL#32pp=<&* zw61d&8&=vMAP7Z`Y{JS72X7YY2Yi#3;U zMPSTvZI56-HVug!teV&{Fv~n{${1KwFqduWMMeo2@fJ4;a}0RZoQY=WxB!MP10Fdo zNlu$oNF}8GV5XBK!$fCkbrl}tEcz5oTh3Aq4Kd8VSU`wt<(murCnYi(gMn!Ms_=PE ztQ6eO)Cdi{5&;lP4>n^84DPouqMU;fBs9*MIGIK@(BnLURe`!dnA`(0fnMT5DHwUe z<$WSY0Y;z!dX8oohazn(-$^h8$Y?%x40E46+jVq2tGHKt(|R9y16=MsIs`69Z^HLM^eng>&*Ff~4pXtC z;5gRX)l8gaLNY>(u^?ZTw>Z*|;PaZ9dxs;-+Xxk_O$%R|;y??=x1T)OFDyczE~A2j znM`DZ)Z!!Ok8enXY)LTfpoWK?VfntTZ0n;cQ{0XAP$|xccfc!`f|X2K6-R$+^H%f9 zChjVgwzhZeRWFY#$eFAbIhB1P0UHimdVFtMY(0HjOtQ$uGG@1xIN6+HE?dYPZQJL6 zsJgNJR9{Z!I%t`YH+iV~gH{~q{i}rwM?a(n<_Tmx79U!Iy4C>>(v{~ssyMz{W<$P_ zzRZr-@|FP`UgRol7J({@?Fn9fse-kmRI-u?|$ccFeRju@9oduYz6-i_|T!; KH^;Z{Yy1ba0{?9Q diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index 1cdc53a9fd32e..4e7fd8d4c68b8 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -55,7 +55,7 @@ module.exports = { "1": "
\n

Rich Text: Inline entry with deep reference loop

\n

Inline entry with deep reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ] and before that

\n

\n

\n
\n
" }, "rich-text: Inline Entry With Reference Loop": { - "1": "
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ] and before that

\n

\n

\n
\n
", + "1": "
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ] and before that

\n

\n

\n
\n
" }, "rich-text: Localized": { "1": "
\n

Rich Text: Localized

\n

Rich Text in English

\n
\n
", From f44c518245bee35e57daad8e120227d928137728 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Fri, 11 Jun 2021 11:18:51 +0200 Subject: [PATCH 020/149] Revert "test(e2e): update snapshots" This reverts commit 8d94396a4d35e7c52c61a64a9f4d1c2100d18008. --- .../gatsby-plugin-image.js/german-0.snap.png | Bin 2570 -> 4168 bytes e2e-tests/contentful/snapshots.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/contentful/cypress/snapshots/gatsby-plugin-image.js/german-0.snap.png b/e2e-tests/contentful/cypress/snapshots/gatsby-plugin-image.js/german-0.snap.png index 95de3c6a3c374eb622afd9bc6324232b9664610d..e6f13231933f9e761eda1ea416b7ef7fcf8c6632 100644 GIT binary patch literal 4168 zcmeHLYfw{X8m2Q?Q3n#jB{bz?kZVK3vPH-;0u$3?Ni+}=ZczgYc7uqeSxm?V)G3My z3E3)_GH$qqa!CNuNU7EkSZk80vtzXO#Ih8y4O^{8iJRJNP$Ajx#GU@xo$1U@JF~O1 zf8KM>dwHJkJSXS<-jill?pyvF2^)QUeEjJ-Z?b)SUJ3)}xBXrQ_Kf^4;^TwG(BGsM zh+kU1O8xkuUuZ0R^uSwfkUsQRxUkSA?JL_)>`qPi{^8f{zaAUD;CcRsU2yZ|`t@7Q zVfd1k6f+cB(IPlw3ai+AAO*O%|9Ab163@$lGR2pZ-!X?RZFI>}%$GkcZ%H9v46A5S z%-2-4q>R7o>0O)gMm=jYt9dWZmObtnpk|2O<+(reN<|B4zSHAYq1C*ldPO#WvbmTS zE}t`UPf&sM2rIS5l?nw3 zRY81z8w-xJ5RChOHkcbcx4w5oy0UOZ>}MbbWPeuGHfJP@NQ68GOSM@9(IRZ>H0mSy z)?Bt~*7Odvlo(kRWE`*5(6+&GGM>&%uL{!7o~ztuq8)CW4e=Msq;tMH(j5x@a5-Kd zq8t`$m{@(kI=~BOBE)N%kIFCgJAyHj8_J7QVWJnVWGQB{nfItDwdV!fsSKkR?oii2 znohAGH*>sfpR=T1xN>D194FH4`CKgbvJnuh7j8_@I%m9R??e(KFxbux4P!uk9aycHLwTVMMGIFOnC4qX1k=AV-?TfY846tI>M2tjY zO4q$E2z@+QY9xd8$2(rDY@QG&JEKJcnKYxhn7XseRIkPB6hI65)W+Smq{W>E8Sk>5 zy|z0LJ|99odOoYz*LetH-5tFdLPeb}q!wb$6!|(0&-VUgisZ`k4`*Ro!-oTD+)Puw zb3_C+oEJflklLT~w9`Jl(cfRm48+6=bFO3BS4!7*cW>=s#|!Vw4&)+Zj`j@ggqed3 zSO_YZ{?CY*(G7De+J21WY1=XmRiicD$Wo$^%~vwf8gFFVAOOpr6Z+0yM|%2R#sh!Fu%zTVCi$6aSdzfiWo)wdAnL!aM+VZ9 zdXW9G*;C)u0LK9nl61L#MA{mqXe0 z3wEqm3tGjW&!z@Ynm$2=WhufE85^NY?9sRn4;f**xud>S*TBTNY z#gwL|DQT?oTDV(eb^4j>$kj#@{Y+EFp{dGupY$*K8GfU{L!sbT(0}!YLbBzD zdr76iT+M`8@p5`HqP(S=5a%CITL{U7`6*5M_8N-~`p=8q52neBj5R)@Xd;(3EjGmc zaBm9_wQs1?qaN6R?cHE_nuAB}uJ3NVb!7!u{`Q)z+a}ZoNuHb`qxS4A)%!;rz}`H$ z*f5~D`+8PzMT_J9ydh8@9mzOtC6gF|e5aXF)#7md&b5QFl<2N>78u7D|BQMjR?gxu z;H6cjn6DcgwL(pbd4*#?77hA)cCCw}R?u{Wik7^EwO#o6ZNkAw0F!d;TYJUT8$+b0 z`&&|`Yh5~)9&8h3yU}gcK3y0Oc9JOl^Rugcqr-h7Ex_y0KOX3jgPivl3>>hwD1H5w zNPy$sq9{v5k00ri+4@%UMe?yP3p%3!HK(r3s=jKgJIFo!#|}8GqT#;1&e?uyM?;9@ ziT<7xU|KRKN3TgHN{qI;LNuW&A66T)O~ru#pFh7geugZfF57ympnNv)km@|G1!jX)&jSnCZ?d-vi@?s8C33C5F~Sv66Usa1tRQ-O zA!_i-KDB!=P02(hK!4*qg=#f%kQh6;33#T3d}n)ArG^)nio#d8gioczpko8|j(-Ij z^Dsblcj?pFs#9=W?Bpo8he6Y;+BSF`mHac_Y5}UmVVAicVu2OceDb_mj7BcK4$z_% zU{C$*#~nH8-?*|0LDlfQ;S73H*%wzj&|{wddGsXdLG(jg9aD%tt}LOeFoKYDtn&lw z5SI=fdYyeShqh&Uqv0v<$u+Og-Ok_YWTwX>C^>9}d5|>oZ9lzi{ zF&FI5t44?-=WC_bddEm9XxBf}S&!Xw-?J~sNRAC4$tTA&ybJBK)^Qy-qH#}Vh!ZQ% zNGd_JmDTdObvv7R%LJ8`c-hLy$EY>e8V7si=Ar-Q0)eN@^U!0{=4hq;qQS_KbLTH+ zD40uQ1D5hHDD-^3?qJseVW`T?rFWZ#1g-t3`#O@8rkrR+^I{;c+sdsb@MFp? zotRCvFwnfVV6VFfMe2Y-UVNh0J%%EYv>-2+?R9feq#`z&H=se?=t3%LJ&tU5lshpe zvmhAC$Ke`{fIUEvfMEHkky7?_n}`8Wge?g*SpMh)#i-WMy1@8G3%6AZL#32pp=<&* zw61d&8&=vMAP7Z`Y{JS72X7YY2Yi#3;U zMPSTvZI56-HVug!teV&{Fv~n{${1KwFqduWMMeo2@fJ4;a}0RZoQY=WxB!MP10Fdo zNlu$oNF}8GV5XBK!$fCkbrl}tEcz5oTh3Aq4Kd8VSU`wt<(murCnYi(gMn!Ms_=PE ztQ6eO)Cdi{5&;lP4>n^84DPouqMU;fBs9*MIGIK@(BnLURe`!dnA`(0fnMT5DHwUe z<$WSY0Y;z!dX8oohazn(-$^h8$Y?%x40E46+jVq2tGHKt(|R9y16=MsIs`69Z^HLM^eng>&*Ff~4pXtC z;5gRX)l8gaLNY>(u^?ZTw>Z*|;PaZ9dxs;-+Xxk_O$%R|;y??=x1T)OFDyczE~A2j znM`DZ)Z!!Ok8enXY)LTfpoWK?VfntTZ0n;cQ{0XAP$|xccfc!`f|X2K6-R$+^H%f9 zChjVgwzhZeRWFY#$eFAbIhB1P0UHimdVFtMY(0HjOtQ$uGG@1xIN6+HE?dYPZQJL6 zsJgNJR9{Z!I%t`YH+iV~gH{~q{i}rwM?a(n<_Tmx79U!Iy4C>>(v{~ssyMz{W<$P_ zzRZr-@|FP`UgRol7J({@?Fn9fse-kmRI-u?|$ccFeRju@9oduYz6-i_|T!; KH^;Z{Yy1ba0{?9Q literal 2570 zcmds3VNeri8cwzeT@qmeCdMPQBsSGx<|x%eaLQ>&jLpiSX^?Oz3(_+byp#*Y$0q5IfNH z=mxC#ljPm5$FD%?r^c=%AF`6hRYHDcEUEoBC!=xVa;K%3W#c4vB1uRJ;BXmjCK z3u=$m^n15T+Jp)}Lf2*nEJZ1!M9K z_Ipd1Lo|Jn9My$t-Yv+L>O!LQS!(IL9PE+fpDt;7t=n2|Y!4!ao* z2zG4NI(^?HfOyqUtfUY8Pf;K=u~eDy?S$L3O|OrB(u!))kted%<(qTgFEzEpuW zx(EOG!JdBa2qR%#4{RkAUxVT&OAf=T(UVWgbfJ~32MRrG>8ap!DNm@-OQVQO)91aL zwL=kUi;To!OAGw&c+ELNitT(0?nld1PCJ*BMSJA$%uj3Cu!0-zV-?O*5B?^BE{-d@ zP~Oj87D*ci`{%=Ldtp5C)EiBi4Mz*y8?f4=odWp}GvTrvb;6i9Sm<2-t)$InJ{#NL z$~aV(BUN>q*UEpex7frNqSQQ`gs=!bue6(eL2}aai_ON8i;azm&0K^{(v`!igExg# z(U*se?OaNhf+iNNZ#UJpvorkTN_}=3oO&eDdT>-Eh>faA5UoOZ5yC5uv3vqYUNCBqd+ z^E`s~$i^r++Lw}%mjC7SlSkrxT!R5EkPBM(yqZv$49}CJg64=U$ZIk_Ps;xr@pnI& zVnPZZ2A{fBxjO0G1=Truc}Y0~;7ZH|`^mVzVDS7dcPMX&0dTWp51bRm_2Y&5jhXwh z_Avl%0&hEqaXlbZoUvVe?;-<02VOqHxQ_E&7+HP0ngO5#FWU;P(?wiLPG6!682~!) z>?&~Gd=@b|WA{OZ$!P{U@HA3zeWKF31?zYdWNg7EfDSwv<9b^DSjCB)JA|f8+)USZ zh#H8xUuw2+{R;}8b=y^80-q?H5t1d$pe4*zR0&~zO;&%#QYEY3kIs1Ot5LD&Ka`P{ zLc6L%Ay^=*!WSM-#TxpTABE92cPUvl;9lex5P1LcE8kKQT5E-SySmQPxvy{eV%S-n zSy>Y7_0He_I(EstR_B?!)>$JhcO3&4MugZGm#)x7b1pGAcZlc0yOF~A8V{{U_1P7n z#ltU@zo?g*#Gc0nF6qnf@y`Es`q_wVN)d>E-|O9ZZ(71dT!XRwdpQb!aiMedHwVi& z3V0n(<#?hbJPiiT;#MB?X{|gb*L&DJS^)Wx_psY|*r5h(>)|=v9uX+~F-P2JMIsJ_ z3p!_a4-j=8g2m=}J1@_1$Y%+2wLB@?cE@#t)S7bT$u}}KkwvP+%j_QS&hMr-k*8zE z?)Y;Rp@P?Ay9c=F3\n

Rich Text: Inline entry with deep reference loop

\n

Inline entry with deep reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ] and before that

\n

\n

\n
\n
" }, "rich-text: Inline Entry With Reference Loop": { - "1": "
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ] and before that

\n

\n

\n
\n
" + "1": "
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ] and before that

\n

\n

\n
\n
", }, "rich-text: Localized": { "1": "
\n

Rich Text: Localized

\n

Rich Text in English

\n
\n
", From 02860a6db6f65828da25db87f95df23d6b0e7689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 11 Jun 2021 13:30:00 +0200 Subject: [PATCH 021/149] refactor: rename schema types to avoid conflicts --- e2e-tests/contentful/schema.gql | 810 ++++++++++-------- e2e-tests/contentful/snapshots.js | 39 +- .../references/content-reference.js | 4 +- .../src/components/references/index.js | 8 +- .../src/components/references/location.js | 4 +- .../src/components/references/number.js | 4 +- .../src/components/references/text.js | 4 +- e2e-tests/contentful/src/pages/boolean.js | 6 +- .../contentful/src/pages/content-reference.js | 54 +- e2e-tests/contentful/src/pages/date.js | 14 +- .../contentful/src/pages/download-local.js | 4 +- e2e-tests/contentful/src/pages/json.js | 12 +- e2e-tests/contentful/src/pages/location.js | 6 +- .../contentful/src/pages/media-reference.js | 6 +- e2e-tests/contentful/src/pages/number.js | 6 +- e2e-tests/contentful/src/pages/rich-text.js | 30 +- e2e-tests/contentful/src/pages/tags.js | 13 +- e2e-tests/contentful/src/pages/text.js | 18 +- .../__tests__/download-contentful-assets.js | 10 +- .../src/__tests__/gatsby-node.js | 1 - .../src/create-schema-customization.js | 159 +--- .../src/download-contentful-assets.js | 21 +- .../src/generate-schema.js | 150 ++-- .../gatsby-source-contentful/src/normalize.js | 8 +- 24 files changed, 695 insertions(+), 696 deletions(-) diff --git a/e2e-tests/contentful/schema.gql b/e2e-tests/contentful/schema.gql index 7a501577d38cb..5f4ef8d58f623 100644 --- a/e2e-tests/contentful/schema.gql +++ b/e2e-tests/contentful/schema.gql @@ -1,4 +1,4 @@ -### Type definitions saved at 2021-09-25T11:33:25.217Z ### +### Type definitions saved at 2021-11-18T12:37:07.683Z ### type File implements Node @dontInfer { sourceInstanceName: String! @@ -32,6 +32,9 @@ type File implements Node @dontInfer { ctime: Date! @dateformat birthtime: Date @deprecated(reason: "Use `birthTime` instead") birthtimeMs: Float @deprecated(reason: "Use `birthTime` instead") + blksize: Int + blocks: Int + url: String } type Directory implements Node @dontInfer { @@ -71,8 +74,11 @@ type Directory implements Node @dontInfer { type Site implements Node @dontInfer { buildTime: Date @dateformat siteMetadata: SiteSiteMetadata + port: Int + host: String polyfill: Boolean pathPrefix: String + jsxRuntime: String } type SiteSiteMetadata { @@ -96,7 +102,8 @@ type SitePage implements Node @dontInfer { internalComponentName: String! componentChunkName: String! matchPath: String - pageContext: JSON + pageContext: JSON @proxy(from: "context", fromNode: false) + pluginCreator: SitePlugin @link(by: "id", from: "pluginCreatorId") } type SitePlugin implements Node @dontInfer { @@ -115,429 +122,172 @@ type SiteBuildMetadata implements Node @dontInfer { buildTime: Date @dateformat } -interface ContentfulEntry implements Node { - contentful_id: String! +interface ContentfulReference implements Node { id: ID! - node_locale: String! + sys: ContentfulSys } -interface ContentfulReference { - contentful_id: String! - id: ID! +type ContentfulSys { + type: String! + id: String! + spaceId: String! + environmentId: String! + contentType: ContentfulContentType @link(by: "id", from: "contentType___NODE") + firstPublishedAt: Date! + publishedAt: Date! + publishedVersion: Int! + locale: String! } -type ContentfulAsset implements ContentfulReference & Node @derivedTypes @dontInfer { - contentful_id: String! - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat - file: ContentfulAssetFile - title: String - description: String - node_locale: String - sys: ContentfulAssetSys +type ContentfulContentType implements Node @dontInfer { + name: String! + displayField: String! + description: String! } -type ContentfulAssetFile @derivedTypes { - url: String - details: ContentfulAssetFileDetails - fileName: String - contentType: String +interface ContentfulEntry implements Node { + id: ID! + sys: ContentfulSys } -type ContentfulAssetFileDetails @derivedTypes { +type ContentfulAsset implements ContentfulReference & Node @dontInfer { + sys: ContentfulSys + title: String + description: String + contentType: String + fileName: String + url: String size: Int - image: ContentfulAssetFileDetailsImage -} - -type ContentfulAssetFileDetailsImage { width: Int height: Int + fields: ContentfulAssetFields } -type ContentfulAssetSys { - type: String - revision: Int +type ContentfulAssetFields { + localFile: String } -type ContentfulNumber implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { +type ContentfulTag implements Node @dontInfer { + name: String! contentful_id: String! - node_locale: String! - title: String - integerLocalized: Int - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat - sys: ContentfulNumberSys - metadata: ContentfulNumberMetadata - decimal: Float - integer: Int - content_reference: [ContentfulContentReference] @link(by: "id", from: "content reference___NODE") @proxy(from: "content reference___NODE") - decimalLocalized: Float } -type ContentfulNumberSys @derivedTypes { - type: String - revision: Int - contentType: ContentfulNumberSysContentType +type ContentfulRichTextAssets { + block: [ContentfulAsset]! + hyperlink: [ContentfulAsset]! } -type ContentfulNumberSysContentType @derivedTypes { - sys: ContentfulNumberSysContentTypeSys +type ContentfulRichTextEntries { + inline: [ContentfulEntry]! + block: [ContentfulEntry]! + hyperlink: [ContentfulEntry]! } -type ContentfulNumberSysContentTypeSys { - type: String - linkType: String - id: String +type ContentfulRichTextLinks { + assets: ContentfulRichTextAssets + entries: ContentfulRichTextEntries } -type ContentfulNumberMetadata { - tags: [ContentfulTag] @link(by: "id", from: "tags___NODE") +type ContentfulRichText @dontInfer { + json: JSON + links: ContentfulRichTextLinks } -type ContentfulTag implements Node @dontInfer { - name: String! - contentful_id: String! +type ContentfulLocation @dontInfer { + lat: Float! + lon: Float! } -type ContentfulContentReference implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { - contentful_id: String! - node_locale: String! - title: String - one: ContentfulContentReferenceContentfulTextUnion @link(by: "id", from: "one___NODE") - content_reference: [ContentfulContentReference] @link(by: "id", from: "content reference___NODE") @proxy(from: "content reference___NODE") - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat - sys: ContentfulContentReferenceSys - oneLocalized: ContentfulNumber @link(by: "id", from: "oneLocalized___NODE") - many: [ContentfulContentReferenceContentfulNumberContentfulTextUnion] @link(by: "id", from: "many___NODE") - manyLocalized: [ContentfulNumberContentfulTextUnion] @link(by: "id", from: "manyLocalized___NODE") -} - -union ContentfulContentReferenceContentfulTextUnion = ContentfulContentReference | ContentfulText - -type ContentfulContentReferenceSys @derivedTypes { - type: String - revision: Int - contentType: ContentfulContentReferenceSysContentType -} - -type ContentfulContentReferenceSysContentType @derivedTypes { - sys: ContentfulContentReferenceSysContentTypeSys +type ContentfulText implements Node @dontInfer { + raw: String! } -type ContentfulContentReferenceSysContentTypeSys { - type: String - linkType: String - id: String +type ContentfulContentTypeNumber implements ContentfulReference & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys + title: String + integer: Int + integerLocalized: Int + decimal: Float + decimalLocalized: Float } -union ContentfulContentReferenceContentfulNumberContentfulTextUnion = ContentfulContentReference | ContentfulNumber | ContentfulText - -union ContentfulNumberContentfulTextUnion = ContentfulNumber | ContentfulText - -type ContentfulText implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { - contentful_id: String! - node_locale: String! +type ContentfulContentTypeText implements ContentfulReference & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys title: String - longLocalized: contentfulTextLongLocalizedTextNode @link(by: "id", from: "longLocalized___NODE") - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat - sys: ContentfulTextSys - longMarkdown: contentfulTextLongMarkdownTextNode @link(by: "id", from: "longMarkdown___NODE") + short: String shortLocalized: String - longPlain: contentfulTextLongPlainTextNode @link(by: "id", from: "longPlain___NODE") shortList: [String] - short: String - content_reference: [ContentfulContentReference] @link(by: "id", from: "content reference___NODE") @proxy(from: "content reference___NODE") -} - -type contentfulTextLongLocalizedTextNode implements Node @derivedTypes @childOf(types: ["ContentfulText"]) @dontInfer { - longLocalized: String - sys: contentfulTextLongLocalizedTextNodeSys -} - -type contentfulTextLongLocalizedTextNodeSys { - type: String + shortListLocalized: [String] + longPlain: ContentfulText @link(by: "id", from: "longPlain___NODE") + longMarkdown: ContentfulText @link(by: "id", from: "longMarkdown___NODE") + longLocalized: ContentfulText @link(by: "id", from: "longLocalized___NODE") } -type ContentfulTextSys @derivedTypes { - type: String - revision: Int - contentType: ContentfulTextSysContentType -} - -type ContentfulTextSysContentType @derivedTypes { - sys: ContentfulTextSysContentTypeSys -} - -type ContentfulTextSysContentTypeSys { - type: String - linkType: String - id: String -} - -type contentfulTextLongMarkdownTextNode implements Node @derivedTypes @childOf(types: ["ContentfulText"]) @dontInfer { - longMarkdown: String - sys: contentfulTextLongMarkdownTextNodeSys -} - -type contentfulTextLongMarkdownTextNodeSys { - type: String -} - -type contentfulTextLongPlainTextNode implements Node @derivedTypes @childOf(types: ["ContentfulText"]) @dontInfer { - longPlain: String - sys: contentfulTextLongPlainTextNodeSys -} - -type contentfulTextLongPlainTextNodeSys { - type: String -} - -type ContentfulMediaReference implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { - contentful_id: String! - node_locale: String! +type ContentfulContentTypeMediaReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys title: String one: ContentfulAsset @link(by: "id", from: "one___NODE") - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat - sys: ContentfulMediaReferenceSys oneLocalized: ContentfulAsset @link(by: "id", from: "oneLocalized___NODE") many: [ContentfulAsset] @link(by: "id", from: "many___NODE") manyLocalized: [ContentfulAsset] @link(by: "id", from: "manyLocalized___NODE") } -type ContentfulMediaReferenceSys @derivedTypes { - type: String - revision: Int - contentType: ContentfulMediaReferenceSysContentType -} - -type ContentfulMediaReferenceSysContentType @derivedTypes { - sys: ContentfulMediaReferenceSysContentTypeSys -} - -type ContentfulMediaReferenceSysContentTypeSys { - type: String - linkType: String - id: String -} - -type ContentfulBoolean implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { - contentful_id: String! - node_locale: String! +type ContentfulContentTypeBoolean implements ContentfulReference & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys title: String - booleanLocalized: Boolean - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat - sys: ContentfulBooleanSys boolean: Boolean + booleanLocalized: Boolean } -type ContentfulBooleanSys @derivedTypes { - type: String - revision: Int - contentType: ContentfulBooleanSysContentType -} - -type ContentfulBooleanSysContentType @derivedTypes { - sys: ContentfulBooleanSysContentTypeSys -} - -type ContentfulBooleanSysContentTypeSys { - type: String - linkType: String - id: String -} - -type ContentfulDate implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { - contentful_id: String! - node_locale: String! +type ContentfulContentTypeDate implements ContentfulReference & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys title: String - dateTimeTimezone: Date @dateformat - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat - sys: ContentfulDateSys date: Date @dateformat - dateLocalized: Date @dateformat dateTime: Date @dateformat + dateTimeTimezone: Date @dateformat + dateLocalized: Date @dateformat } -type ContentfulDateSys @derivedTypes { - type: String - revision: Int - contentType: ContentfulDateSysContentType -} - -type ContentfulDateSysContentType @derivedTypes { - sys: ContentfulDateSysContentTypeSys -} - -type ContentfulDateSysContentTypeSys { - type: String - linkType: String - id: String -} - -type ContentfulLocation implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { - contentful_id: String! - node_locale: String! +type ContentfulContentTypeLocation implements ContentfulReference & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys title: String - locationLocalized: ContentfulLocationLocationLocalized - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat - sys: ContentfulLocationSys - location: ContentfulLocationLocation -} - -type ContentfulLocationLocationLocalized { - lon: Float - lat: Float + location: ContentfulLocation + locationLocalized: ContentfulLocation } -type ContentfulLocationSys @derivedTypes { - type: String - revision: Int - contentType: ContentfulLocationSysContentType -} - -type ContentfulLocationSysContentType @derivedTypes { - sys: ContentfulLocationSysContentTypeSys -} - -type ContentfulLocationSysContentTypeSys { - type: String - linkType: String - id: String -} - -type ContentfulLocationLocation { - lat: Float - lon: Float -} - -type ContentfulJson implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { - contentful_id: String! - node_locale: String! +type ContentfulContentTypeJson implements ContentfulReference & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys title: String - json: contentfulJsonJsonJsonNode @link(by: "id", from: "json___NODE") - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat - sys: ContentfulJsonSys - jsonLocalized: contentfulJsonJsonLocalizedJsonNode @link(by: "id", from: "jsonLocalized___NODE") -} - -type contentfulJsonJsonJsonNode implements Node @derivedTypes @childOf(types: ["ContentfulJson"]) @dontInfer { - age: Int - city: String - name: String - sys: contentfulJsonJsonJsonNodeSys - Actors: [contentfulJsonJsonJsonNodeActors] -} - -type contentfulJsonJsonJsonNodeSys { - type: String -} - -type contentfulJsonJsonJsonNodeActors { - age: Int - name: String - wife: String - photo: String - weight: Float - Born_At: String @proxy(from: "Born At") - children: [String] - Birthdate: String - hasChildren: Boolean - hasGreyHair: Boolean -} - -type ContentfulJsonSys @derivedTypes { - type: String - revision: Int - contentType: ContentfulJsonSysContentType -} - -type ContentfulJsonSysContentType @derivedTypes { - sys: ContentfulJsonSysContentTypeSys + json: JSON + jsonLocalized: JSON } -type ContentfulJsonSysContentTypeSys { - type: String - linkType: String - id: String -} - -type contentfulJsonJsonLocalizedJsonNode implements Node @derivedTypes @childOf(types: ["ContentfulJson"]) @dontInfer { - name: String - age: Int - city: String - sys: contentfulJsonJsonLocalizedJsonNodeSys -} - -type contentfulJsonJsonLocalizedJsonNodeSys { - type: String -} - -type ContentfulRichText implements ContentfulReference & ContentfulEntry & Node @derivedTypes @dontInfer { - contentful_id: String! - node_locale: String! +type ContentfulContentTypeRichText implements ContentfulReference & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys title: String - richText: ContentfulRichTextRichText - spaceId: String - createdAt: Date @dateformat - updatedAt: Date @dateformat - sys: ContentfulRichTextSys - richTextValidated: ContentfulRichTextRichTextValidated - richTextLocalized: ContentfulRichTextRichTextLocalized -} - -type ContentfulRichTextRichText { - raw: String - references: [ContentfulAssetContentfulContentReferenceContentfulLocationContentfulTextUnion] @link(by: "id", from: "references___NODE") -} - -union ContentfulAssetContentfulContentReferenceContentfulLocationContentfulTextUnion = ContentfulAsset | ContentfulContentReference | ContentfulLocation | ContentfulText - -type ContentfulRichTextSys @derivedTypes { - type: String - revision: Int - contentType: ContentfulRichTextSysContentType -} - -type ContentfulRichTextSysContentType @derivedTypes { - sys: ContentfulRichTextSysContentTypeSys -} - -type ContentfulRichTextSysContentTypeSys { - type: String - linkType: String - id: String -} - -type ContentfulRichTextRichTextValidated { - raw: String - references: [ContentfulAssetContentfulLocationContentfulNumberContentfulTextUnion] @link(by: "id", from: "references___NODE") + richText: ContentfulRichText + richTextLocalized: ContentfulRichText + richTextValidated: ContentfulRichText } -union ContentfulAssetContentfulLocationContentfulNumberContentfulTextUnion = ContentfulAsset | ContentfulLocation | ContentfulNumber | ContentfulText - -type ContentfulRichTextRichTextLocalized { - raw: String +type ContentfulContentTypeContentReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys + title: String + one: ContentfulEntry @link(by: "id", from: "one___NODE") + oneLocalized: ContentfulEntry @link(by: "id", from: "oneLocalized___NODE") + many: [ContentfulEntry] @link(by: "id", from: "many___NODE") + manyLocalized: [ContentfulEntry] @link(by: "id", from: "manyLocalized___NODE") } -type ContentfulValidatedContentReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { - contentful_id: String! - node_locale: String! +type ContentfulContentTypeValidatedContentReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys + title: String + oneItemSingleType: ContentfulEntry @link(by: "id", from: "oneItemSingleType___NODE") + oneItemManyTypes: ContentfulEntry @link(by: "id", from: "oneItemManyTypes___NODE") + oneItemAllTypes: ContentfulEntry @link(by: "id", from: "oneItemAllTypes___NODE") + multipleItemsSingleType: [ContentfulEntry] @link(by: "id", from: "multipleItemsSingleType___NODE") + multipleItemsManyTypes: [ContentfulEntry] @link(by: "id", from: "multipleItemsManyTypes___NODE") + multipleItemsAllTypes: [ContentfulEntry] @link(by: "id", from: "multipleItemsAllTypes___NODE") } type MarkdownHeading { @@ -567,7 +317,7 @@ type MarkdownWordCount { words: Int } -type MarkdownRemark implements Node @childOf(mimeTypes: ["text/markdown", "text/x-markdown"], types: ["contentfulTextLongPlainTextNode", "contentfulTextLongMarkdownTextNode", "contentfulTextLongLocalizedTextNode"]) @derivedTypes @dontInfer { +type MarkdownRemark implements Node @childOf(mimeTypes: ["text/markdown", "text/x-markdown"], types: ["ContentfulText"]) @dontInfer { frontmatter: MarkdownRemarkFrontmatter excerpt: String rawMarkdownBody: String @@ -577,13 +327,345 @@ type MarkdownRemarkFrontmatter { title: String } -type ContentfulContentType implements Node @derivedTypes @dontInfer { +enum ImageFormat { + NO_CHANGE + AUTO + JPG + PNG + WEBP + AVIF +} + +enum ImageFit { + COVER + CONTAIN + FILL + INSIDE + OUTSIDE +} + +enum ImageLayout { + FIXED + FULL_WIDTH + CONSTRAINED +} + +enum ImageCropFocus { + CENTER + NORTH + NORTHEAST + EAST + SOUTHEAST + SOUTH + SOUTHWEST + WEST + NORTHWEST + ENTROPY + ATTENTION +} + +input DuotoneGradient { + highlight: String! + shadow: String! + opacity: Int +} + +enum PotraceTurnPolicy { + TURNPOLICY_BLACK + TURNPOLICY_WHITE + TURNPOLICY_LEFT + TURNPOLICY_RIGHT + TURNPOLICY_MINORITY + TURNPOLICY_MAJORITY +} + +input Potrace { + turnPolicy: PotraceTurnPolicy + turdSize: Float + alphaMax: Float + optCurve: Boolean + optTolerance: Float + threshold: Int + blackOnWhite: Boolean + color: String + background: String +} + +type ImageSharpFixed { + base64: String + tracedSVG: String + aspectRatio: Float + width: Float! + height: Float! + src: String! + srcSet: String! + srcWebp: String + srcSetWebp: String + originalName: String +} + +type ImageSharpFluid { + base64: String + tracedSVG: String + aspectRatio: Float! + src: String! + srcSet: String! + srcWebp: String + srcSetWebp: String + sizes: String! + originalImg: String + originalName: String + presentationWidth: Int! + presentationHeight: Int! +} + +enum ImagePlaceholder { + DOMINANT_COLOR + TRACED_SVG + BLURRED + NONE +} + +input BlurredOptions { + """Width of the generated low-res preview. Default is 20px""" + width: Int + + """ + Force the output format for the low-res preview. Default is to use the same + format as the input. You should rarely need to change this + """ + toFormat: ImageFormat +} + +input JPGOptions { + quality: Int + progressive: Boolean = true +} + +input PNGOptions { + quality: Int + compressionSpeed: Int = 4 +} + +input WebPOptions { + quality: Int +} + +input AVIFOptions { + quality: Int + lossless: Boolean + speed: Int +} + +input TransformOptions { + grayscale: Boolean = false + duotone: DuotoneGradient + rotate: Int = 0 + trim: Float = 0 + cropFocus: ImageCropFocus = ATTENTION + fit: ImageFit = COVER +} + +type ImageSharpOriginal { + width: Float + height: Float + src: String +} + +type ImageSharpResize { + src: String + tracedSVG: String + width: Int + height: Int + aspectRatio: Float + originalName: String +} + +type ImageSharp implements Node @childOf(mimeTypes: [], types: ["File"]) @dontInfer { + fixed(width: Int, height: Int, base64Width: Int, jpegProgressive: Boolean = true, pngCompressionSpeed: Int = 4, grayscale: Boolean = false, duotone: DuotoneGradient, traceSVG: Potrace, quality: Int, jpegQuality: Int, pngQuality: Int, webpQuality: Int, toFormat: ImageFormat = AUTO, toFormatBase64: ImageFormat = AUTO, cropFocus: ImageCropFocus = ATTENTION, fit: ImageFit = COVER, background: String = "rgba(0,0,0,1)", rotate: Int = 0, trim: Float = 0): ImageSharpFixed + fluid( + maxWidth: Int + maxHeight: Int + base64Width: Int + grayscale: Boolean = false + jpegProgressive: Boolean = true + pngCompressionSpeed: Int = 4 + duotone: DuotoneGradient + traceSVG: Potrace + quality: Int + jpegQuality: Int + pngQuality: Int + webpQuality: Int + toFormat: ImageFormat = AUTO + toFormatBase64: ImageFormat = AUTO + cropFocus: ImageCropFocus = ATTENTION + fit: ImageFit = COVER + background: String = "rgba(0,0,0,1)" + rotate: Int = 0 + trim: Float = 0 + sizes: String = "" + + """ + A list of image widths to be generated. Example: [ 200, 340, 520, 890 ] + """ + srcSetBreakpoints: [Int] = [] + ): ImageSharpFluid + gatsbyImageData( + """ + The layout for the image. + FIXED: A static image sized, that does not resize according to the screen width + FULL_WIDTH: The image resizes to fit its container. Pass a "sizes" option if + it isn't going to be the full width of the screen. + CONSTRAINED: Resizes to fit its container, up to a maximum width, at which point it will remain fixed in size. + """ + layout: ImageLayout = CONSTRAINED + + """ + The display width of the generated image for layout = FIXED, and the maximum + display width of the largest image for layout = CONSTRAINED. + Ignored if layout = FLUID. + """ + width: Int + + """ + The display height of the generated image for layout = FIXED, and the + maximum display height of the largest image for layout = CONSTRAINED. + The image will be cropped if the aspect ratio does not match the source + image. If omitted, it is calculated from the supplied width, + matching the aspect ratio of the source image. + """ + height: Int + + """ + If set along with width or height, this will set the value of the other + dimension to match the provided aspect ratio, cropping the image if needed. + If neither width or height is provided, height will be set based on the intrinsic width of the source image. + """ + aspectRatio: Float + + """ + Format of generated placeholder image, displayed while the main image loads. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. + TRACED_SVG: a low-resolution traced SVG of the image. + NONE: no placeholder. Set "background" to use a fixed background color. + """ + placeholder: ImagePlaceholder + + """ + Options for the low-resolution placeholder image. Set placeholder to "BLURRED" to use this + """ + blurredOptions: BlurredOptions + + """ + Options for traced placeholder SVGs. You also should set placeholder to "TRACED_SVG". + """ + tracedSVGOptions: Potrace + + """ + The image formats to generate. Valid values are "AUTO" (meaning the same + format as the source image), "JPG", "PNG", "WEBP" and "AVIF". + The default value is [AUTO, WEBP], and you should rarely need to change + this. Take care if you specify JPG or PNG when you do + not know the formats of the source images, as this could lead to unwanted + results such as converting JPEGs to PNGs. Specifying + both PNG and JPG is not supported and will be ignored. + """ + formats: [ImageFormat] + + """ + A list of image pixel densities to generate. It will never generate images + larger than the source, and will always include a 1x image. + Default is [ 1, 2 ] for FIXED images, meaning 1x and 2x and [0.25, 0.5, 1, + 2] for CONSTRAINED. In this case, an image with a constrained layout + and width = 400 would generate images at 100, 200, 400 and 800px wide. + Ignored for FULL_WIDTH images, which use breakpoints instead + """ + outputPixelDensities: [Float] + + """ + Specifies the image widths to generate. For FIXED and CONSTRAINED images it + is better to allow these to be determined automatically, + based on the image size. For FULL_WIDTH images this can be used to override + the default, which is [750, 1080, 1366, 1920]. + It will never generate any images larger than the source. + """ + breakpoints: [Int] + + """ + The "sizes" property, passed to the img tag. This describes the display size of the image. + This does not affect the generated images, but is used by the browser to decide which images to download. + You should usually leave this blank, and a suitable value will be calculated. The exception is if a FULL_WIDTH image + does not actually span the full width of the screen, in which case you should pass the correct size here. + """ + sizes: String + + """The default quality. This is overridden by any format-specific options""" + quality: Int + + """Options to pass to sharp when generating JPG images.""" + jpgOptions: JPGOptions + + """Options to pass to sharp when generating PNG images.""" + pngOptions: PNGOptions + + """Options to pass to sharp when generating WebP images.""" + webpOptions: WebPOptions + + """Options to pass to sharp when generating AVIF images.""" + avifOptions: AVIFOptions + + """ + Options to pass to sharp to control cropping and other image manipulations. + """ + transformOptions: TransformOptions + + """ + Background color applied to the wrapper. Also passed to sharp to use as a + background when "letterboxing" an image to another aspect ratio. + """ + backgroundColor: String + ): JSON! + original: ImageSharpOriginal + resize(width: Int, height: Int, quality: Int, jpegQuality: Int, pngQuality: Int, webpQuality: Int, jpegProgressive: Boolean = true, pngCompressionLevel: Int = 9, pngCompressionSpeed: Int = 4, grayscale: Boolean = false, duotone: DuotoneGradient, base64: Boolean = false, traceSVG: Potrace, toFormat: ImageFormat = AUTO, cropFocus: ImageCropFocus = ATTENTION, fit: ImageFit = COVER, background: String = "rgba(0,0,0,1)", rotate: Int = 0, trim: Float = 0): ImageSharpResize +} + +enum GatsbyImageFormat { + NO_CHANGE + AUTO + JPG + PNG + WEBP + AVIF +} + +enum GatsbyImageLayout { + FIXED + FULL_WIDTH + CONSTRAINED +} + +enum GatsbyImagePlaceholder { + DOMINANT_COLOR + TRACED_SVG + BLURRED + NONE +} + +type ContentfulContentTypeContentType implements Node @dontInfer { name: String displayField: String description: String - sys: ContentfulContentTypeSys + sys: ContentfulContentTypeContentTypeSys } -type ContentfulContentTypeSys { +type ContentfulContentTypeContentTypeSys { type: String + id: String + locale: String + spaceId: String + environmentId: String + firstPublishedAt: Date @dateformat + publishedAt: Date @dateformat + publishedVersion: Int } \ No newline at end of file diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index 1cdc53a9fd32e..863033c7e4524 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -2,28 +2,28 @@ module.exports = { "__version": "9.5.4", "content-reference": { "content-reference-many-2nd-level-loop": { - "1": "
\n

Content Reference: Many (2nd level loop)

\n

[ContentfulNumber]\n 42

\n

[ContentfulText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" + "1": "
\n

Content Reference: Many (2nd level loop)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" }, "content-reference-many-loop-a-greater-b": { - "1": "
\n

Content Reference: Many (Loop A -> B)

\n

[ContentfulNumber]\n 42

\n

[ContentfulText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulReference]\n Content Reference: Many (Loop B -> A)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop A ->\n B)\n ]

\n
" + "1": "
\n

Content Reference: Many (Loop A -> B)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop B -> A)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop A ->\n B)\n ]

\n
" }, "content-reference-many-loop-b-greater-a": { - "1": "
\n

Content Reference: Many (Loop B -> A)

\n

[ContentfulNumber]\n 42

\n

[ContentfulText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulReference]\n Content Reference: Many (Loop A -> B)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop B ->\n A)\n ]

\n
" + "1": "
\n

Content Reference: Many (Loop B -> A)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop A -> B)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop B ->\n A)\n ]

\n
" }, "content-reference-many-self-reference": { - "1": "
\n

Content Reference: Many (Self Reference)

\n

[ContentfulNumber]\n 42

\n

[ContentfulText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulReference]\n Content Reference: Many (Self Reference)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Self\n Reference)\n ]

\n
" + "1": "
\n

Content Reference: Many (Self Reference)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Self Reference)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Self\n Reference)\n ]

\n
" }, "content-reference-one": { - "1": "
\n

Content Reference: One

\n

[ContentfulText]\n The quick brown fox jumps over the lazy dog.

\n
" + "1": "
\n

Content Reference: One

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n
" }, "content-reference-one-loop-a-greater-b": { - "1": "
\n

Content Reference: One (Loop A -> B)

\n

[ContentfulReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n
" + "1": "
\n

Content Reference: One (Loop A -> B)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n
" }, "content-reference-one-loop-b-greater-a": { - "1": "
\n

Content Reference: One (Loop B -> A)

\n

[ContentfulReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" + "1": "
\n

Content Reference: One (Loop B -> A)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" }, "content-reference-one-self-reference": { - "1": "
\n

Content Reference: One (Self Reference)

\n

[ContentfulReference]\n Content Reference: One (Self Reference)\n : [\n Content Reference: One (Self Reference)\n ]

\n
" + "1": "
\n

Content Reference: One (Self Reference)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Self Reference)\n : [\n Content Reference: One (Self Reference)\n ]

\n
" } }, "rich-text": { @@ -34,28 +34,25 @@ module.exports = { "1": "
\n

Rich Text: Basic

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
" }, "rich-text: Embedded Entry": { - "1": "
\n

Rich Text: Embedded Entry

\n

Embedded Entry

\n

[ContentfulText]\n The quick brown fox jumps over the lazy dog.

\n

\n

\n
\n
" + "1": "
\n

Rich Text: Embedded Entry

\n

Embedded Entry

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

\n

\n
\n
" }, "rich-text: Embedded Asset": { "1": "
\n

Rich Text: Embedded asset

\n

Embedded Asset

\n
\n
\"\"\n\n
\n
\n \n \n \"\"\n\n \n \n
\n

\n

\n

\n
\n
" }, "rich-text: Embedded Entry With Deep Reference Loop": { - "1": "
\n

Rich Text: Embedded entry with deep reference loop

\n

Embedded entry with deep reference loop

\n

[ContentfulReference]\n Content Reference: Many (2nd level loop)\n : [\n Number: Integer, Text: Short, Content Reference: One (Loop A ->\n B)\n ]

\n

\n

\n
\n
" + "1": "
\n

Rich Text: Embedded entry with deep reference loop

\n

Embedded entry with deep reference loop

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (2nd level loop)\n : [\n Number: Integer, Text: Short, Content Reference: One (Loop A ->\n B)\n ]

\n

\n

\n
\n
" }, "rich-text: Embedded Entry With Reference Loop": { - "1": "
\n

Rich Text: Embedded entry with reference loop

\n

Embedded entry with reference loop

\n

[ContentfulReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n

\n
\n
" - }, - "rich-text: All Features": { - "1": "
\n

Rich Text: All Features

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n
\"\"\n\n \n \n \n
\n

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
  7. \n

    [Inline-ContentfulText]\n :

    \n
  8. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n

[ContentfulLocation] Lat:\n 52.51627\n , Long:\n 13.3777

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
" + "1": "
\n

Rich Text: Embedded entry with reference loop

\n

Embedded entry with reference loop

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n

\n
\n
" }, "rich-text: Inline Entry": { - "1": "
\n

Rich Text: Inline entry

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-ContentfulText]\n : and before that

\n

\n

\n
\n
" + "1": "
\n

Rich Text: Inline entry

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeText\n ] and before that

\n

\n

\n
\n
" }, "rich-text: Inline Entry With Deep Reference Loop": { - "1": "
\n

Rich Text: Inline entry with deep reference loop

\n

Inline entry with deep reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ] and before that

\n

\n

\n
\n
" + "1": "
\n

Rich Text: Inline entry with deep reference loop

\n

Inline entry with deep reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeContentReference\n ] and before that

\n

\n

\n
\n
" }, "rich-text: Inline Entry With Reference Loop": { - "1": "
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentReference\n ] and before that

\n

\n

\n
\n
", + "1": "
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeContentReference\n ] and before that

\n

\n

\n
\n
" }, "rich-text: Localized": { "1": "
\n

Rich Text: Localized

\n

Rich Text in English

\n
\n
", @@ -88,16 +85,16 @@ module.exports = { }, "content-reference localized": { "english-content-reference-one-localized": { - "1": "
\n

Content Reference: One Localized

\n

[ContentfulNumber]\n 42

\n
" + "1": "
\n

Content Reference: One Localized

\n

[ContentfulContentTypeNumber]\n 42

\n
" }, "english-content-reference-many-localized": { - "1": "
\n

Content Reference: Many Localized

\n

[ContentfulText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulNumber]\n 42

\n
" + "1": "
\n

Content Reference: Many Localized

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeNumber]\n 42

\n
" }, "german-content-reference-one-localized": { - "1": "
\n

Content Reference: One Localized

\n

[ContentfulNumber]\n 4.2

\n
" + "1": "
\n

Content Reference: One Localized

\n

[ContentfulContentTypeNumber]\n 4.2

\n
" }, "german-content-reference-many-localized": { - "1": "
\n

Content Reference: Many Localized

\n

[ContentfulNumber]\n 4.2

\n

[ContentfulText]\n The European languages are members of the same family. Their\n separate existence is a myth. For science, music, sport, etc, Europe uses\n the same vocabulary.\n\n The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.\n\n To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
" + "1": "
\n

Content Reference: Many Localized

\n

[ContentfulContentTypeNumber]\n 4.2

\n

[ContentfulContentTypeText]\n The European languages are members of the same family. Their\n separate existence is a myth. For science, music, sport, etc, Europe uses\n the same vocabulary.\n\n The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.\n\n To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
" } }, "media-reference localized": { diff --git a/e2e-tests/contentful/src/components/references/content-reference.js b/e2e-tests/contentful/src/components/references/content-reference.js index d3b0e02d24cf3..60dcacd74512e 100644 --- a/e2e-tests/contentful/src/components/references/content-reference.js +++ b/e2e-tests/contentful/src/components/references/content-reference.js @@ -1,10 +1,10 @@ import React from "react" -export const ContentfulContentReference = ({ one, many, title }) => { +export const ContentfulContentTypeContentReference = ({ one, many, title }) => { const references = [one, ...(many || [])].filter(Boolean) return (

- [ContentfulReference] {title}: [ + [ContentfulContentTypeContentReference] {title}: [ {references.map(ref => ref.title).join(", ")}]

) diff --git a/e2e-tests/contentful/src/components/references/index.js b/e2e-tests/contentful/src/components/references/index.js index a9d0675bb1577..f9e79b30222d6 100644 --- a/e2e-tests/contentful/src/components/references/index.js +++ b/e2e-tests/contentful/src/components/references/index.js @@ -1,4 +1,4 @@ -export { ContentfulContentReference } from "./content-reference" -export { ContentfulLocation } from "./location" -export { ContentfulNumber } from "./number" -export { ContentfulText } from "./text" +export { ContentfulContentTypeContentReference } from "./content-reference" +export { ContentfulContentTypeLocation } from "./location" +export { ContentfulContentTypeNumber } from "./number" +export { ContentfulContentTypeText } from "./text" diff --git a/e2e-tests/contentful/src/components/references/location.js b/e2e-tests/contentful/src/components/references/location.js index d25a79e529402..2f67d64026e2a 100644 --- a/e2e-tests/contentful/src/components/references/location.js +++ b/e2e-tests/contentful/src/components/references/location.js @@ -1,7 +1,7 @@ import React from "react" -export const ContentfulLocation = ({ location }) => ( +export const ContentfulContentTypeLocation = ({ location }) => (

- [ContentfulLocation] Lat: {location.lat}, Long: {location.lon} + [ContentfulContentTypeLocation] Lat: {location.lat}, Long: {location.lon}

) diff --git a/e2e-tests/contentful/src/components/references/number.js b/e2e-tests/contentful/src/components/references/number.js index db7e048b14636..9d728fe93f554 100644 --- a/e2e-tests/contentful/src/components/references/number.js +++ b/e2e-tests/contentful/src/components/references/number.js @@ -1,5 +1,5 @@ import React from "react" -export const ContentfulNumber = ({ integer, decimal }) => ( -

[ContentfulNumber] {integer || decimal}

+export const ContentfulContentTypeNumber = ({ integer, decimal }) => ( +

[ContentfulContentTypeNumber] {integer || decimal}

) diff --git a/e2e-tests/contentful/src/components/references/text.js b/e2e-tests/contentful/src/components/references/text.js index a8647ece05b1d..eb4ac609836e8 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?.raw}

+export const ContentfulContentTypeText = ({ short, longPlain }) => ( +

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

) diff --git a/e2e-tests/contentful/src/pages/boolean.js b/e2e-tests/contentful/src/pages/boolean.js index d4bd20c11b096..a1392f06d065d 100644 --- a/e2e-tests/contentful/src/pages/boolean.js +++ b/e2e-tests/contentful/src/pages/boolean.js @@ -49,7 +49,7 @@ export default BooleanPage export const pageQuery = graphql` query BooleanQuery { - default: allContentfulBoolean( + default: allContentfulContentTypeBoolean( sort: { fields: sys___id } filter: { sys: { locale: { eq: "en-US" } } @@ -61,7 +61,7 @@ export const pageQuery = graphql` boolean } } - english: allContentfulBoolean( + english: allContentfulContentTypeBoolean( sort: { fields: sys___id } filter: { sys: { locale: { eq: "en-US" } } @@ -73,7 +73,7 @@ export const pageQuery = graphql` booleanLocalized } } - german: allContentfulBoolean( + german: allContentfulContentTypeBoolean( sort: { fields: sys___id } filter: { sys: { locale: { eq: "de-DE" } } diff --git a/e2e-tests/contentful/src/pages/content-reference.js b/e2e-tests/contentful/src/pages/content-reference.js index cc33294438c0d..af6400da98f3b 100644 --- a/e2e-tests/contentful/src/pages/content-reference.js +++ b/e2e-tests/contentful/src/pages/content-reference.js @@ -95,7 +95,7 @@ export default ContentReferencePage export const pageQuery = graphql` query ContentReferenceQuery { - default: allContentfulContentReference( + default: allContentfulContentTypeContentReference( sort: { fields: title } filter: { sys: { locale: { eq: "en-US" } } @@ -112,39 +112,39 @@ export const pageQuery = graphql` sys { id } - ... on ContentfulText { + ... on ContentfulContentTypeText { title short } - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title integer } - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title one { - ... on ContentfulText { + ... on ContentfulContentTypeText { title short } - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title integer } - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title } } many { - ... on ContentfulText { + ... on ContentfulContentTypeText { title short } - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title integer } - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title } } @@ -155,39 +155,39 @@ export const pageQuery = graphql` sys { id } - ... on ContentfulText { + ... on ContentfulContentTypeText { title short } - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title integer } - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title one { - ... on ContentfulText { + ... on ContentfulContentTypeText { title short } - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title integer } - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title } } many { - ... on ContentfulText { + ... on ContentfulContentTypeText { title short } - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title integer } - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title } } @@ -195,7 +195,7 @@ export const pageQuery = graphql` } } } - english: allContentfulContentReference( + english: allContentfulContentTypeContentReference( sort: { fields: title } filter: { sys: { locale: { eq: "en-US" } } @@ -209,7 +209,7 @@ export const pageQuery = graphql` } oneLocalized { __typename - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title decimal integer @@ -217,12 +217,12 @@ export const pageQuery = graphql` } manyLocalized { __typename - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title decimal integer } - ... on ContentfulText { + ... on ContentfulContentTypeText { title short longPlain { @@ -232,7 +232,7 @@ export const pageQuery = graphql` } } } - german: allContentfulContentReference( + german: allContentfulContentTypeContentReference( sort: { fields: title } filter: { sys: { locale: { eq: "de-DE" } } @@ -246,7 +246,7 @@ export const pageQuery = graphql` } oneLocalized { __typename - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title decimal integer @@ -254,12 +254,12 @@ export const pageQuery = graphql` } manyLocalized { __typename - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title decimal integer } - ... on ContentfulText { + ... on ContentfulContentTypeText { title short longPlain { diff --git a/e2e-tests/contentful/src/pages/date.js b/e2e-tests/contentful/src/pages/date.js index ef8cb42c32b86..81a2c72d0990e 100644 --- a/e2e-tests/contentful/src/pages/date.js +++ b/e2e-tests/contentful/src/pages/date.js @@ -32,31 +32,35 @@ export default DatePage export const pageQuery = graphql` query DateQuery { - dateTime: contentfulDate(sys: { id: { eq: "38akBjGb3T1t4AjB87wQjo" } }) { + dateTime: contentfulContentTypeDate( + sys: { id: { eq: "38akBjGb3T1t4AjB87wQjo" } } + ) { title date: dateTime formatted: dateTime(formatString: "D.M.YYYY - hh:mm") } - dateTimeTimezone: contentfulDate( + dateTimeTimezone: contentfulContentTypeDate( sys: { id: { eq: "6dZ8pK4tFWZDZPHgSC0tNS" } } ) { title date: dateTimeTimezone formatted: dateTimeTimezone(formatString: "D.M.YYYY - hh:mm (z)") } - date: contentfulDate(sys: { id: { eq: "5FuULz0jl0rKoKUKp2rshf" } }) { + date: contentfulContentTypeDate( + sys: { id: { eq: "5FuULz0jl0rKoKUKp2rshf" } } + ) { title date formatted: date(formatString: "D.M.YYYY") } - dateEnglish: contentfulDate( + dateEnglish: contentfulContentTypeDate( sys: { id: { eq: "1ERWZvDiYELryAZEP1dmKG" }, locale: { eq: "en-US" } } ) { title date: dateLocalized formatted: dateLocalized(formatString: "D.M.YYYY - HH:mm:ss") } - dateGerman: contentfulDate( + dateGerman: contentfulContentTypeDate( sys: { id: { eq: "1ERWZvDiYELryAZEP1dmKG" }, locale: { eq: "de-DE" } } ) { title diff --git a/e2e-tests/contentful/src/pages/download-local.js b/e2e-tests/contentful/src/pages/download-local.js index a5bdddb8a18f2..e5401942fb130 100644 --- a/e2e-tests/contentful/src/pages/download-local.js +++ b/e2e-tests/contentful/src/pages/download-local.js @@ -20,9 +20,7 @@ export default DownloadLocalPage export const pageQuery = graphql` query DownloadLocalQuery { - contentfulAsset(contentful_id: { eq: "3BSI9CgDdAn1JchXmY5IJi" }) { - contentful_id - title + contentfulAsset(sys: { id: { eq: "3BSI9CgDdAn1JchXmY5IJi" } }) { localFile { absolutePath childImageSharp { diff --git a/e2e-tests/contentful/src/pages/json.js b/e2e-tests/contentful/src/pages/json.js index bce1cb1edd3a1..548bce9c30608 100644 --- a/e2e-tests/contentful/src/pages/json.js +++ b/e2e-tests/contentful/src/pages/json.js @@ -61,19 +61,23 @@ export default JSONPage export const pageQuery = graphql` query JSONQuery { - simple: contentfulJson(sys: { id: { eq: "2r6tNjP8brkyy5yLR39hhh" } }) { + simple: contentfulContentTypeJson( + sys: { id: { eq: "2r6tNjP8brkyy5yLR39hhh" } } + ) { json } - complex: contentfulJson(sys: { id: { eq: "2y71nV0cpW9vzTmJybq571" } }) { + complex: contentfulContentTypeJson( + sys: { id: { eq: "2y71nV0cpW9vzTmJybq571" } } + ) { json } - english: contentfulJson( + english: contentfulContentTypeJson( sys: { id: { eq: "7DvTBEPg5P6TRC7dI9zXuO" }, locale: { eq: "en-US" } } ) { title jsonLocalized } - german: contentfulJson( + german: contentfulContentTypeJson( sys: { id: { eq: "7DvTBEPg5P6TRC7dI9zXuO" }, locale: { eq: "de-DE" } } ) { title diff --git a/e2e-tests/contentful/src/pages/location.js b/e2e-tests/contentful/src/pages/location.js index f9757a987d661..9314b17fabdc4 100644 --- a/e2e-tests/contentful/src/pages/location.js +++ b/e2e-tests/contentful/src/pages/location.js @@ -56,7 +56,7 @@ export default LocationPage export const pageQuery = graphql` query LocationQuery { - default: allContentfulLocation( + default: allContentfulContentTypeLocation( sort: { fields: sys___id } filter: { title: { glob: "!*Localized*" } @@ -71,7 +71,7 @@ export const pageQuery = graphql` } } } - english: allContentfulLocation( + english: allContentfulContentTypeLocation( sort: { fields: sys___id } filter: { title: { glob: "*Localized*" } @@ -86,7 +86,7 @@ export const pageQuery = graphql` } } } - german: allContentfulLocation( + german: allContentfulContentTypeLocation( sort: { fields: sys___id } filter: { title: { glob: "*Localized*" } diff --git a/e2e-tests/contentful/src/pages/media-reference.js b/e2e-tests/contentful/src/pages/media-reference.js index dfd9402cfeb8a..f521c3747450c 100644 --- a/e2e-tests/contentful/src/pages/media-reference.js +++ b/e2e-tests/contentful/src/pages/media-reference.js @@ -112,7 +112,7 @@ export default MediaReferencePage export const pageQuery = graphql` query MediaReferenceQuery { - default: allContentfulMediaReference( + default: allContentfulContentTypeMediaReference( sort: { fields: title } filter: { title: { glob: "!*Localized*" } @@ -132,7 +132,7 @@ export const pageQuery = graphql` } } } - english: allContentfulMediaReference( + english: allContentfulContentTypeMediaReference( sort: { fields: title } filter: { title: { glob: "*Localized*" } @@ -158,7 +158,7 @@ export const pageQuery = graphql` } } } - german: allContentfulMediaReference( + german: allContentfulContentTypeMediaReference( sort: { fields: title } filter: { title: { glob: "*Localized*" } diff --git a/e2e-tests/contentful/src/pages/number.js b/e2e-tests/contentful/src/pages/number.js index 946e9b71d3be1..e5d5dc2cc8066 100644 --- a/e2e-tests/contentful/src/pages/number.js +++ b/e2e-tests/contentful/src/pages/number.js @@ -53,7 +53,7 @@ export default NumberPage export const pageQuery = graphql` query NumberQuery { - default: allContentfulNumber( + default: allContentfulContentTypeNumber( sort: { fields: sys___id } filter: { title: { glob: "!*Localized*" } @@ -66,7 +66,7 @@ export const pageQuery = graphql` decimal } } - english: allContentfulNumber( + english: allContentfulContentTypeNumber( sort: { fields: sys___id } filter: { title: { glob: "*Localized*" } @@ -79,7 +79,7 @@ export const pageQuery = graphql` decimalLocalized } } - german: allContentfulNumber( + german: allContentfulContentTypeNumber( sort: { fields: sys___id } filter: { title: { glob: "*Localized*" } diff --git a/e2e-tests/contentful/src/pages/rich-text.js b/e2e-tests/contentful/src/pages/rich-text.js index 12c792bc4eea2..c3488ad37f63a 100644 --- a/e2e-tests/contentful/src/pages/rich-text.js +++ b/e2e-tests/contentful/src/pages/rich-text.js @@ -114,7 +114,7 @@ export default RichTextPage export const pageQuery = graphql` query RichTextQuery { - default: allContentfulRichText( + default: allContentfulContentTypeRichText( sort: { fields: title } filter: { title: { glob: "!*Localized*|*Validated*" } @@ -142,36 +142,36 @@ export const pageQuery = graphql` id type } - ... on ContentfulText { + ... on ContentfulContentTypeText { title short } - ... on ContentfulLocation { + ... on ContentfulContentTypeLocation { location { lat lon } } - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title one { __typename sys { id } - ... on ContentfulText { + ... on ContentfulContentTypeText { title short } - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title one { - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title } } many { - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title } } @@ -182,23 +182,23 @@ export const pageQuery = graphql` sys { id } - ... on ContentfulText { + ... on ContentfulContentTypeText { title short } - ... on ContentfulNumber { + ... on ContentfulContentTypeNumber { title integer } - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title one { - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title } } many { - ... on ContentfulContentReference { + ... on ContentfulContentTypeContentReference { title } } @@ -218,7 +218,7 @@ export const pageQuery = graphql` } } } - english: allContentfulRichText( + english: allContentfulContentTypeRichText( sort: { fields: title } filter: { title: { glob: "*Localized*" } @@ -233,7 +233,7 @@ export const pageQuery = graphql` } } } - german: allContentfulRichText( + german: allContentfulContentTypeRichText( sort: { fields: title } filter: { title: { glob: "*Localized*" } diff --git a/e2e-tests/contentful/src/pages/tags.js b/e2e-tests/contentful/src/pages/tags.js index 9d752ee279ba8..7367b97b9f471 100644 --- a/e2e-tests/contentful/src/pages/tags.js +++ b/e2e-tests/contentful/src/pages/tags.js @@ -88,7 +88,6 @@ const TagsPage = ({ data }) => {
) } - export default TagsPage export const pageQuery = graphql` @@ -99,13 +98,13 @@ export const pageQuery = graphql` contentful_id } } - integers: allContentfulNumber( - sort: { fields: contentful_id } + integers: allContentfulContentTypeNumber( + sort: { fields: sys___id } filter: { metadata: { tags: { elemMatch: { contentful_id: { eq: "numberInteger" } } } } - node_locale: { eq: "en-US" } + sys: { locale: { eq: "en-US" } } } ) { nodes { @@ -113,13 +112,13 @@ export const pageQuery = graphql` integer } } - decimals: allContentfulNumber( - sort: { fields: contentful_id } + decimals: allContentfulContentTypeNumber( + sort: { fields: sys___id } filter: { metadata: { tags: { elemMatch: { contentful_id: { eq: "numberDecimal" } } } } - node_locale: { eq: "en-US" } + sys: { locale: { eq: "en-US" } } } ) { nodes { diff --git a/e2e-tests/contentful/src/pages/text.js b/e2e-tests/contentful/src/pages/text.js index 923c86e743da5..b2e10ceeef546 100644 --- a/e2e-tests/contentful/src/pages/text.js +++ b/e2e-tests/contentful/src/pages/text.js @@ -77,24 +77,24 @@ export default TextPage export const pageQuery = graphql` query TextQuery { - short: contentfulText( + short: contentfulContentTypeText( sys: { id: { eq: "5ZtcN1o7KpN7J7xgiTyaXo" }, locale: { eq: "en-US" } } ) { short } - shortList: contentfulText( + shortList: contentfulContentTypeText( sys: { id: { eq: "7b5U927WTFcQXO2Gewwa2k" }, locale: { eq: "en-US" } } ) { shortList } - longPlain: contentfulText( + longPlain: contentfulContentTypeText( sys: { id: { eq: "6ru8cSC9hZi3Ekvtw7P77S" }, locale: { eq: "en-US" } } ) { longPlain { raw } } - longMarkdownSimple: contentfulText( + longMarkdownSimple: contentfulContentTypeText( sys: { id: { eq: "NyPJw0mcSuCwY2gV0zYny" }, locale: { eq: "en-US" } } ) { longMarkdown { @@ -103,7 +103,7 @@ export const pageQuery = graphql` } } } - longMarkdownComplex: contentfulText( + longMarkdownComplex: contentfulContentTypeText( sys: { id: { eq: "3pwKS9UWsYmOguo4UdE1EB" }, locale: { eq: "en-US" } } ) { longMarkdown { @@ -112,24 +112,24 @@ export const pageQuery = graphql` } } } - shortEnglish: contentfulText( + shortEnglish: contentfulContentTypeText( sys: { id: { eq: "2sQRyOLUexvWZj9nkzS3nN" }, locale: { eq: "en-US" } } ) { shortLocalized } - shortGerman: contentfulText( + shortGerman: contentfulContentTypeText( sys: { id: { eq: "2sQRyOLUexvWZj9nkzS3nN" }, locale: { eq: "de-DE" } } ) { shortLocalized } - longEnglish: contentfulText( + longEnglish: contentfulContentTypeText( sys: { id: { eq: "5csovkwdDBqTKwSblAOHvd" }, locale: { eq: "en-US" } } ) { longLocalized { raw } } - longGerman: contentfulText( + longGerman: contentfulContentTypeText( sys: { id: { eq: "5csovkwdDBqTKwSblAOHvd" }, locale: { eq: "de-DE" } } ) { longLocalized { 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 f3f6c21fdf6ee..401d85f409d72 100644 --- a/packages/gatsby-source-contentful/src/__tests__/download-contentful-assets.js +++ b/packages/gatsby-source-contentful/src/__tests__/download-contentful-assets.js @@ -38,8 +38,14 @@ const fixtures = [ fields: { title: { "en-US": `TundraUS`, fr: `TundraFR` }, file: { - "en-US": { url: `//images.ctfassets.net/testing/us-image.jpeg` }, - fr: { url: `//images.ctfassets.net/testing/fr-image.jpg` }, + "en-US": { + url: `//images.ctfassets.net/testing/us-image.jpeg`, + details: { size: 123, image: { width: 123, height: 123 } }, + }, + fr: { + url: `//images.ctfassets.net/testing/fr-image.jpg`, + details: { size: 123, image: { width: 123, height: 123 } }, + }, }, }, sys: { diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index e864a4bb5dbe0..88af2de45f7c7 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -160,7 +160,6 @@ describe(`gatsby-node`, () => { getCache, reporter, parentSpan, - schema, }, pluginOptions ) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.js b/packages/gatsby-source-contentful/src/create-schema-customization.js index 9100de4ccbefc..1a636469ed118 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.js +++ b/packages/gatsby-source-contentful/src/create-schema-customization.js @@ -1,12 +1,9 @@ // @ts-check import _ from "lodash" import { fetchContentTypes } from "./fetch" +import { generateSchema } from "./generate-schema" import { createPluginConfig } from "./plugin-options" import { CODES } from "./report" -import { resolveGatsbyImageData } from "./gatsby-plugin-image" -import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" -import { stripIndent } from "common-tags" -import { addRemoteFilePolyfillInterface } from "gatsby-plugin-utils/polyfill-remote-file" async function getContentTypesFromContentful({ cache, @@ -32,33 +29,6 @@ async function getContentTypesFromContentful({ }) } - // Check for restricted content type names and set id based on useNameForId - const useNameForId = pluginConfig.get(`useNameForId`) - const restrictedContentTypes = [`entity`, `reference`, `asset`] - - if (pluginConfig.get(`enableTags`)) { - restrictedContentTypes.push(`tag`) - } - - contentTypeItems.forEach(contentTypeItem => { - // Establish identifier for content type - // Use `name` if specified, otherwise, use internal id (usually a natural-language constant, - // but sometimes a base62 uuid generated by Contentful, hence the option) - let contentTypeItemId = contentTypeItem.sys.id - if (useNameForId) { - contentTypeItemId = contentTypeItem.name.toLowerCase() - } - - if (restrictedContentTypes.includes(contentTypeItemId)) { - reporter.panic({ - id: CODES.FetchContentTypes, - context: { - sourceMessage: `Restricted ContentType name found. The name "${contentTypeItemId}" is not allowed.`, - }, - }) - } - }) - // Store processed content types in cache for sourceNodes const sourceId = `${pluginConfig.get(`spaceId`)}-${pluginConfig.get( `environment` @@ -90,123 +60,14 @@ export async function createSchemaCustomization( pluginConfig, }) } - const { getGatsbyImageFieldConfig } = await import( - `gatsby-plugin-image/graphql-utils` - ) - const contentfulTypes = [ - schema.buildInterfaceType({ - name: `ContentfulEntry`, - fields: { - contentful_id: { type: `String!` }, - id: { type: `ID!` }, - node_locale: { type: `String!` }, - }, - extensions: { infer: false }, - interfaces: [`Node`], - }), - schema.buildInterfaceType({ - name: `ContentfulReference`, - fields: { - contentful_id: { type: `String!` }, - id: { type: `ID!` }, - }, - extensions: { infer: false }, - }), - ] - - contentfulTypes.push( - addRemoteFilePolyfillInterface( - schema.buildObjectType({ - name: `ContentfulAsset`, - fields: { - contentful_id: { type: `String!` }, - id: { type: `ID!` }, - gatsbyImageData: getGatsbyImageFieldConfig( - async (...args) => resolveGatsbyImageData(...args, { cache }), - { - jpegProgressive: { - type: `Boolean`, - defaultValue: true, - }, - resizingBehavior: { - type: ImageResizingBehavior, - }, - cropFocus: { - type: ImageCropFocusType, - }, - cornerRadius: { - type: `Int`, - defaultValue: 0, - description: stripIndent` - Desired corner radius in pixels. Results in an image with rounded corners. - Pass \`-1\` for a full circle/ellipse.`, - }, - quality: { - type: `Int`, - defaultValue: 50, - }, - } - ), - ...(pluginConfig.get(`downloadLocal`) - ? { - localFile: { - type: `File`, - extensions: { - link: { - from: `fields.localFile`, - }, - }, - }, - } - : {}), - }, - interfaces: [`ContentfulReference`, `Node`, `RemoteFile`], - }), - { - schema, - actions, - } - ) - ) - - // Create types for each content type - contentTypeItems.forEach(contentTypeItem => - contentfulTypes.push( - schema.buildObjectType({ - name: _.upperFirst( - _.camelCase( - `Contentful ${ - pluginConfig.get(`useNameForId`) - ? contentTypeItem.name - : contentTypeItem.sys.id - }` - ) - ), - fields: { - contentful_id: { type: `String!` }, - id: { type: `ID!` }, - node_locale: { type: `String!` }, - }, - interfaces: [`ContentfulReference`, `ContentfulEntry`, `Node`], - }) - ) - ) - - if (pluginConfig.get(`enableTags`)) { - contentfulTypes.push( - schema.buildObjectType({ - name: `ContentfulTag`, - fields: { - name: { type: `String!` }, - contentful_id: { type: `String!` }, - id: { type: `ID!` }, - }, - interfaces: [`Node`], - extensions: { infer: false }, - }) - ) - } - - createTypes(contentfulTypes) + // Generate schemas based on Contentful content model + generateSchema({ + createTypes, + schema, + pluginConfig, + contentTypeItems, + cache, + actions, + }) } diff --git a/packages/gatsby-source-contentful/src/download-contentful-assets.js b/packages/gatsby-source-contentful/src/download-contentful-assets.js index f6d7f6f82ca0d..e6da9cfc0c5e1 100644 --- a/packages/gatsby-source-contentful/src/download-contentful-assets.js +++ b/packages/gatsby-source-contentful/src/download-contentful-assets.js @@ -48,26 +48,21 @@ export async function downloadContentfulAssets(gatsbyFunctions) { ) bar.start() await distributeWorkload( - assetNodes.map(node => async () => { + assetNodes.map(assetNode => async () => { let fileNodeID const { sys: { id, locale }, - } = node + } = assetNode 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.`) - return Promise.resolve() - } - if (!node.file.url) { + if (!assetNode.url) { reporter.warn( `The asset with id: ${id} has a file but the file contains no url.` ) return Promise.resolve() } - const url = createUrl(node.file.url) + const url = createUrl(assetNode.url) // Avoid downloading the asset again if it's been cached // Note: Contentful Assets do not provide useful metadata @@ -97,10 +92,14 @@ export async function downloadContentfulAssets(gatsbyFunctions) { } if (fileNodeID) { - createNodeField({ node, name: `localFile`, value: fileNodeID }) + createNodeField({ + node: assetNode, + name: `localFile`, + value: fileNodeID, + }) } - return node + return assetNode }), assetDownloadWorkers ) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 27cef28b4c103..4224797a80137 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -1,6 +1,13 @@ import { getRichTextEntityLinks } from "@contentful/rich-text-links" +import { stripIndent } from "common-tags" +import { addRemoteFilePolyfillInterface } from "gatsby-plugin-utils/polyfill-remote-file" +import { + getGatsbyImageFieldConfig, + resolveGatsbyImageData, +} from "./gatsby-plugin-image" import { makeTypeName } from "./normalize" +import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" // Contentful content type schemas const ContentfulDataTypes = new Map([ @@ -14,7 +21,7 @@ const ContentfulDataTypes = new Map([ `Text`, field => { return { - type: `ContentfulNodeTypeText`, + type: `ContentfulText`, extensions: { link: { by: `id`, from: `${field.id}___NODE` }, }, @@ -59,13 +66,13 @@ const ContentfulDataTypes = new Map([ [ `Location`, () => { - return { type: `ContentfulNodeTypeLocation` } + return { type: `ContentfulLocation` } }, ], [ `RichText`, () => { - return { type: `ContentfulNodeTypeRichText` } + return { type: `ContentfulRichText` } }, ], ]) @@ -104,34 +111,19 @@ const translateFieldType = field => { return fieldType } -function generateAssetTypes({ createTypes }) { - createTypes(` - type ContentfulAsset implements ContentfulInternalReference & Node { - sys: ContentfulInternalSys - id: ID! - title: String - description: String - contentType: String - fileName: String - url: String - size: Int - width: Int - height: Int - } - `) -} - export function generateSchema({ createTypes, schema, pluginConfig, contentTypeItems, + cache, + actions, }) { // Generic Types createTypes(` - interface ContentfulInternalReference implements Node { + interface ContentfulReference implements Node { id: ID! - sys: ContentfulInternalSys + sys: ContentfulSys } `) @@ -145,7 +137,7 @@ export function generateSchema({ `) createTypes(` - type ContentfulInternalSys @dontInfer { + type ContentfulSys @dontInfer { type: String! id: String! spaceId: String! @@ -161,12 +153,74 @@ export function generateSchema({ createTypes(` interface ContentfulEntry implements Node @dontInfer { id: ID! - sys: ContentfulInternalSys + sys: ContentfulSys } `) // Assets - generateAssetTypes({ createTypes }) + createTypes( + ...addRemoteFilePolyfillInterface( + schema.buildObjectType({ + name: `ContentfulAsset`, + fields: { + contentful_id: { type: `String!` }, + id: { type: `ID!` }, + gatsbyImageData: getGatsbyImageFieldConfig( + async (...args) => resolveGatsbyImageData(...args, { cache }), + { + jpegProgressive: { + type: `Boolean`, + defaultValue: true, + }, + resizingBehavior: { + type: ImageResizingBehavior, + }, + cropFocus: { + type: ImageCropFocusType, + }, + cornerRadius: { + type: `Int`, + defaultValue: 0, + description: stripIndent` + Desired corner radius in pixels. Results in an image with rounded corners. + Pass \`-1\` for a full circle/ellipse.`, + }, + quality: { + type: `Int`, + defaultValue: 50, + }, + } + ), + ...(pluginConfig.get(`downloadLocal`) + ? { + localFile: { + type: `File`, + extensions: { + link: { + from: `fields.localFile`, + }, + }, + }, + } + : {}), + sys: { type: `ContentfulSys` }, + title: { type: `String` }, + description: { type: `String` }, + contentType: { type: `String` }, + fileName: { type: `String` }, + url: { type: `String` }, + size: { type: `Int` }, + width: { type: `Int` }, + height: { type: `Int` }, + }, + interfaces: [`ContentfulReference`, `Node`], + }), + { + schema, + actions, + } + ) + ) // Rich Text const makeRichTextLinksResolver = @@ -203,7 +257,7 @@ export function generateSchema({ createTypes( schema.buildObjectType({ - name: `ContentfulNodeTypeRichTextAssets`, + name: `ContentfulRichTextAssets`, fields: { block: { type: `[ContentfulAsset]!`, @@ -219,7 +273,7 @@ export function generateSchema({ createTypes( schema.buildObjectType({ - name: `ContentfulNodeTypeRichTextEntries`, + name: `ContentfulRichTextEntries`, fields: { inline: { type: `[ContentfulEntry]!`, @@ -239,16 +293,16 @@ export function generateSchema({ createTypes( schema.buildObjectType({ - name: `ContentfulNodeTypeRichTextLinks`, + name: `ContentfulRichTextLinks`, fields: { assets: { - type: `ContentfulNodeTypeRichTextAssets`, + type: `ContentfulRichTextAssets`, resolve(source) { return source }, }, entries: { - type: `ContentfulNodeTypeRichTextEntries`, + type: `ContentfulRichTextEntries`, resolve(source) { return source }, @@ -259,7 +313,7 @@ export function generateSchema({ createTypes( schema.buildObjectType({ - name: `ContentfulNodeTypeRichText`, + name: `ContentfulRichText`, fields: { json: { type: `JSON`, @@ -268,7 +322,7 @@ export function generateSchema({ }, }, links: { - type: `ContentfulNodeTypeRichTextLinks`, + type: `ContentfulRichTextLinks`, resolve(source) { return source }, @@ -281,7 +335,7 @@ export function generateSchema({ // Location createTypes( schema.buildObjectType({ - name: `ContentfulNodeTypeLocation`, + name: `ContentfulLocation`, fields: { lat: { type: `Float!` }, lon: { type: `Float!` }, @@ -296,7 +350,7 @@ export function generateSchema({ // @todo Is there a way to have this as string and let transformer-remark replace it with an object? createTypes( schema.buildObjectType({ - name: `ContentfulNodeTypeText`, + name: `ContentfulText`, fields: { raw: `String!`, }, @@ -322,22 +376,18 @@ export function generateSchema({ ? contentTypeItem.name : contentTypeItem.sys.id - createTypes( - schema.buildObjectType({ - name: makeTypeName(type), - fields: { - id: { type: `ID!` }, - sys: { type: `ContentfulInternalSys` }, - ...fields, - }, - interfaces: [ - `ContentfulInternalReference`, - `ContentfulEntry`, - `Node`, - ], - extensions: { dontInfer: {} }, - }) - ) + const contentTypeType = { + name: makeTypeName(type), + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys` }, + ...fields, + }, + interfaces: [`ContentfulReference`, `ContentfulEntry`, `Node`], + extensions: { dontInfer: {} }, + } + + createTypes(schema.buildObjectType(contentTypeType)) } catch (err) { err.message = `Unable to create schema for Contentful Content Type ${ contentTypeItem.name || contentTypeItem.sys.id diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index b1869b9db8e4d..6226e9b4be9a3 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -5,7 +5,7 @@ import { lt, prerelease } from "semver" import { restrictedNodeFields, conflictFieldPrefix } from "./config" -const typePrefix = `Contentful` +const typePrefix = `ContentfulContentType` export const makeTypeName = type => _.upperFirst(_.camelCase(`${typePrefix} ${type}`)) @@ -193,7 +193,7 @@ function prepareTextNode(id, node, key, text) { parent: node.id, raw: str, internal: { - type: `ContentfulNodeTypeText`, + type: `ContentfulText`, mediaType: `text/markdown`, content: str, // entryItem.sys.publishedAt is source of truth from contentful @@ -544,7 +544,7 @@ export const createNodesForContentType = ({ } // Link tags - if (pluginConfig.get(`enableTags`)) { + if (pluginConfig.get(`enableTags`) && entryItem.metadata.tags.length) { entryNode.metadata = { tags___NODE: entryItem.metadata.tags.map(tag => createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) @@ -602,7 +602,7 @@ export const createAssetNodes = ({ children: [], file, internal: { - type: `${makeTypeName(`Asset`)}`, + type: `ContentfulAsset`, // The content of an asset is guaranteed to be updated if and only if the .sys.updatedAt field changed contentDigest: assetItem.sys.updatedAt, }, From d4716a4e760423a23a566afa33a0c2bb837e04ff Mon Sep 17 00:00:00 2001 From: axe312ger Date: Wed, 21 Jul 2021 11:37:00 +0100 Subject: [PATCH 022/149] feat: tags are now enabled by default --- e2e-tests/contentful/src/pages/tags.js | 2 +- packages/gatsby-source-contentful/README.md | 9 +-- .../src/__fixtures__/rich-text-data.js | 2 + .../src/__fixtures__/starter-blog-data.js | 6 ++ .../src/__tests__/fetch-backoff.js | 11 +++ .../src/__tests__/fetch-network-errors.js | 5 ++ .../src/__tests__/fetch.js | 2 +- .../gatsby-source-contentful/src/fetch.js | 30 ++++---- .../src/generate-schema.js | 72 +++++++++++-------- .../gatsby-source-contentful/src/normalize.js | 9 +-- .../src/plugin-options.js | 1 - 11 files changed, 85 insertions(+), 64 deletions(-) diff --git a/e2e-tests/contentful/src/pages/tags.js b/e2e-tests/contentful/src/pages/tags.js index 7367b97b9f471..0e0a430e1b6f3 100644 --- a/e2e-tests/contentful/src/pages/tags.js +++ b/e2e-tests/contentful/src/pages/tags.js @@ -92,7 +92,7 @@ export default TagsPage export const pageQuery = graphql` query TagsQuery { - tags: allContentfulTag(sort: { fields: contentful_id }) { + tags: allContentfulTag(sort: { fields: id }) { nodes { name contentful_id diff --git a/packages/gatsby-source-contentful/README.md b/packages/gatsby-source-contentful/README.md index 7261fd2fe5618..c3e99468097d6 100644 --- a/packages/gatsby-source-contentful/README.md +++ b/packages/gatsby-source-contentful/README.md @@ -11,6 +11,7 @@ - [gatsby-source-contentful](#gatsby-source-contentful) - [Install](#install) + - [Setup Instructions](#setup-instructions) - [How to use](#how-to-use) - [Restrictions and limitations](#restrictions-and-limitations) - [Using Delivery API](#using-delivery-api) @@ -174,12 +175,6 @@ Additional config which will get passed to [Contentfuls JS SDK](https://github.c Use this with caution, you might override values this plugin does set for you to connect to Contentful. -**`enableTags`** [boolean][optional] [default: `false`] - -Enable the new [tags feature](https://www.contentful.com/blog/2021/04/08/governance-tagging-metadata/). This will disallow the content type name `tags` till the next major version of this plugin. - -Learn how to use them at the [Contentful Tags](#contentful-tags) section. - **`contentTypeFilter`** [function][optional] [default: () => true] Possibility to limit how many contentType/nodes are created in GraphQL. This can limit the memory usage by reducing the amount of nodes created. Useful if you have a large space in Contentful and only want to get the data from certain content types. @@ -393,8 +388,6 @@ Check the [Reference Guide of gatsby-plugin-image](https://www.gatsbyjs.com/docs ## [Contentful Tags](https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/content-tags) -You need to set the `enableTags` flag to `true` to use this new feature. - ### List available tags This example lists all available tags. The sorting is optional. diff --git a/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js b/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js index 0be1eaa13ee55..02ea0d1a342da 100644 --- a/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js +++ b/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js @@ -496,6 +496,7 @@ exports.initialSync = () => { }, }, }, + metadata: { tags: [] }, }, { sys: { @@ -658,6 +659,7 @@ exports.initialSync = () => { }, }, }, + metadata: { tags: [] }, }, ], assets: [ diff --git a/packages/gatsby-source-contentful/src/__fixtures__/starter-blog-data.js b/packages/gatsby-source-contentful/src/__fixtures__/starter-blog-data.js index 60dc97f683950..b2d94d44dde96 100644 --- a/packages/gatsby-source-contentful/src/__fixtures__/starter-blog-data.js +++ b/packages/gatsby-source-contentful/src/__fixtures__/starter-blog-data.js @@ -289,6 +289,7 @@ exports.initialSync = () => { publishDate: { "en-US": `2017-05-12T00:00+02:00` }, tags: { "en-US": [`javascript`] }, }, + metadata: { tags: [] }, }, { sys: { @@ -349,6 +350,7 @@ exports.initialSync = () => { publishDate: { "en-US": `2017-05-15T00:00+02:00` }, tags: { "en-US": [`general`] }, }, + metadata: { tags: [] }, }, { sys: { @@ -409,6 +411,7 @@ exports.initialSync = () => { publishDate: { "en-US": `2017-05-16T00:00+02:00` }, tags: { "en-US": [`javascript`, `static-sites`] }, }, + metadata: { tags: [] }, }, { sys: { @@ -461,6 +464,7 @@ exports.initialSync = () => { }, }, }, + metadata: { tags: [] }, }, ], assets: [ @@ -734,6 +738,7 @@ exports.createBlogPost = () => { }, publishDate: { "en-US": `2020-04-01T00:00+02:00` }, }, + metadata: { tags: [] }, }, ], assets: [ @@ -887,6 +892,7 @@ exports.updateBlogPost = () => { }, publishDate: { "en-US": `2020-05-15T00:00+02:00` }, }, + metadata: { tags: [] }, }, ], assets: [], diff --git a/packages/gatsby-source-contentful/src/__tests__/fetch-backoff.js b/packages/gatsby-source-contentful/src/__tests__/fetch-backoff.js index f9c951e172bd6..f9a10c5e40317 100644 --- a/packages/gatsby-source-contentful/src/__tests__/fetch-backoff.js +++ b/packages/gatsby-source-contentful/src/__tests__/fetch-backoff.js @@ -83,6 +83,12 @@ describe(`fetch-backoff`, () => { `/spaces/${options.spaceId}/environments/master/sync?initial=true&limit=444` ) .reply(200, { items: [] }) + // Tags + .get( + `/spaces/${options.spaceId}/environments/master/tags?skip=0&limit=1000&order=sys.createdAt` + ) + .reply(200, { items: [] }) + await fetchContent({ pluginConfig, reporter, syncToken: null }) expect(reporter.panic).not.toBeCalled() @@ -120,6 +126,11 @@ describe(`fetch-backoff`, () => { `/spaces/${options.spaceId}/environments/master/sync?initial=true&limit=1000` ) .reply(200, { items: [] }) + // Tags + .get( + `/spaces/${options.spaceId}/environments/master/tags?skip=0&limit=1000&order=sys.createdAt` + ) + .reply(200, { items: [] }) await fetchContent({ pluginConfig, reporter, syncToken: null }) diff --git a/packages/gatsby-source-contentful/src/__tests__/fetch-network-errors.js b/packages/gatsby-source-contentful/src/__tests__/fetch-network-errors.js index d629c5966cbce..abdda891b617b 100644 --- a/packages/gatsby-source-contentful/src/__tests__/fetch-network-errors.js +++ b/packages/gatsby-source-contentful/src/__tests__/fetch-network-errors.js @@ -66,6 +66,11 @@ describe(`fetch-retry`, () => { `/spaces/${options.spaceId}/environments/master/sync?initial=true&limit=1000` ) .reply(200, { items: [] }) + // Tags + .get( + `/spaces/${options.spaceId}/environments/master/tags?skip=0&limit=1000&order=sys.createdAt` + ) + .reply(200, { items: [] }) await fetchContent({ pluginConfig, reporter, syncToken: null }) diff --git a/packages/gatsby-source-contentful/src/__tests__/fetch.js b/packages/gatsby-source-contentful/src/__tests__/fetch.js index ee3da2e893090..a89034629a73d 100644 --- a/packages/gatsby-source-contentful/src/__tests__/fetch.js +++ b/packages/gatsby-source-contentful/src/__tests__/fetch.js @@ -194,7 +194,7 @@ it(`calls contentful.getContentTypes with custom plugin option page limit`, asyn }) describe(`Tags feature`, () => { - it(`tags are disabled by default`, async () => { + it(`calls contentful.getTags`, async () => { await fetchContent({ pluginConfig: createPluginConfig({ accessToken: `6f35edf0db39085e9b9c19bd92943e4519c77e72c852d961968665f1324bfc94`, diff --git a/packages/gatsby-source-contentful/src/fetch.js b/packages/gatsby-source-contentful/src/fetch.js index 209153198fefa..6815e6abb73c6 100644 --- a/packages/gatsby-source-contentful/src/fetch.js +++ b/packages/gatsby-source-contentful/src/fetch.js @@ -325,22 +325,20 @@ export async function fetchContent({ syncToken, pluginConfig, reporter }) { } // We need to fetch tags with the non-sync API as the sync API doesn't support this. - let tagItems = [] - if (pluginConfig.get(`enableTags`)) { - try { - const tagsResult = await pagedGet(client, `getTags`, pageLimit) - tagItems = tagsResult.items - reporter.verbose(`Tags fetched ${tagItems.length}`) - } catch (e) { - reporter.panic({ - id: CODES.FetchTags, - context: { - sourceMessage: `Error fetching tags: ${createContentfulErrorMessage( - e - )}`, - }, - }) - } + let tagItems + try { + const tagsResult = await pagedGet(client, `getTags`, pageLimit) + tagItems = tagsResult.items + reporter.verbose(`Tags fetched ${tagItems.length}`) + } catch (e) { + reporter.panic({ + id: CODES.FetchTags, + context: { + sourceMessage: `Error fetching tags: ${createContentfulErrorMessage( + e + )}`, + }, + }) } const result = { diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 4224797a80137..c73e5b4242b67 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -123,7 +123,7 @@ export function generateSchema({ createTypes(` interface ContentfulReference implements Node { id: ID! - sys: ContentfulSys + sys: ContentfulSys! } `) @@ -151,12 +151,36 @@ export function generateSchema({ `) createTypes(` - interface ContentfulEntry implements Node @dontInfer { + interface ContentfulEntry implements ContentfulReference & Node @dontInfer { id: ID! - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! } `) + createTypes( + schema.buildObjectType({ + name: `ContentfulMetadata`, + fields: { + tags: { type: `[ContentfulTag]!` }, + }, + extensions: { dontInfer: {} }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulTag`, + fields: { + name: { type: `String!` }, + contentful_id: { type: `String!` }, + id: { type: `ID!` }, + }, + interfaces: [`Node`], + extensions: { dontInfer: {} }, + }) + ) + // Assets createTypes( ...addRemoteFilePolyfillInterface( @@ -212,6 +236,7 @@ export function generateSchema({ size: { type: `Int` }, width: { type: `Int` }, height: { type: `Int` }, + metadata: { type: `ContentfulMetadata!` }, }, interfaces: [`ContentfulReference`, `Node`], }), @@ -240,21 +265,6 @@ export function generateSchema({ } // Contentful specific types - if (pluginConfig.get(`enableTags`)) { - createTypes( - schema.buildObjectType({ - name: `ContentfulTag`, - fields: { - name: { type: `String!` }, - contentful_id: { type: `String!` }, - id: { type: `ID!` }, - }, - interfaces: [`Node`], - extensions: { dontInfer: {} }, - }) - ) - } - createTypes( schema.buildObjectType({ name: `ContentfulRichTextAssets`, @@ -354,6 +364,7 @@ export function generateSchema({ fields: { raw: `String!`, }, + // @todo do we need a node interface here? interfaces: [`Node`], extensions: { dontInfer: {}, @@ -376,18 +387,19 @@ export function generateSchema({ ? contentTypeItem.name : contentTypeItem.sys.id - const contentTypeType = { - name: makeTypeName(type), - fields: { - id: { type: `ID!` }, - sys: { type: `ContentfulSys` }, - ...fields, - }, - interfaces: [`ContentfulReference`, `ContentfulEntry`, `Node`], - extensions: { dontInfer: {} }, - } - - createTypes(schema.buildObjectType(contentTypeType)) + createTypes( + schema.buildObjectType({ + name: makeTypeName(type), + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, + ...fields, + }, + interfaces: [`ContentfulReference`, `ContentfulEntry`, `Node`], + extensions: { dontInfer: {} }, + }) + ) } catch (err) { err.message = `Unable to create schema for Contentful Content Type ${ contentTypeItem.name || contentTypeItem.sys.id diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index 6226e9b4be9a3..b6ed9bfe85708 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -541,17 +541,12 @@ export const createNodesForContentType = ({ entryNode = { ...entryItemFields, ...entryNode, - } - - // Link tags - if (pluginConfig.get(`enableTags`) && entryItem.metadata.tags.length) { - entryNode.metadata = { + metadata: { tags___NODE: entryItem.metadata.tags.map(tag => createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) ), - } + }, } - return entryNode }) .filter(Boolean) diff --git a/packages/gatsby-source-contentful/src/plugin-options.js b/packages/gatsby-source-contentful/src/plugin-options.js index 23003a0b79932..67ed7770a0393 100644 --- a/packages/gatsby-source-contentful/src/plugin-options.js +++ b/packages/gatsby-source-contentful/src/plugin-options.js @@ -12,7 +12,6 @@ const defaultOptions = { contentTypeFilter: () => true, pageLimit: DEFAULT_PAGE_LIMIT, useNameForId: true, - enableTags: false, } const createPluginConfig = pluginOptions => { From 06ab362e73ea415e28816b19d22eee02c507ee55 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Tue, 27 Jul 2021 16:55:33 +0100 Subject: [PATCH 023/149] fix: tags schema --- e2e-tests/contentful/gatsby-config.js | 1 - packages/gatsby-source-contentful/src/generate-schema.js | 7 ++++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/e2e-tests/contentful/gatsby-config.js b/e2e-tests/contentful/gatsby-config.js index afb02a147b78e..530941cdf4464 100644 --- a/e2e-tests/contentful/gatsby-config.js +++ b/e2e-tests/contentful/gatsby-config.js @@ -11,7 +11,6 @@ module.exports = { // Use: https://www.gatsbyjs.com/docs/how-to/local-development/environment-variables/ spaceId: `k8iqpp6u0ior`, accessToken: `hO_7N0bLaCJFbu5nL3QVekwNeB_TNtg6tOCB_9qzKUw`, - enableTags: true, downloadLocal: true, }, }, diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index c73e5b4242b67..cb897357c5522 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -162,7 +162,12 @@ export function generateSchema({ schema.buildObjectType({ name: `ContentfulMetadata`, fields: { - tags: { type: `[ContentfulTag]!` }, + tags: { + type: `[ContentfulTag]!`, + extensions: { + link: { by: `id`, from: `tags___NODE` }, + }, + }, }, extensions: { dontInfer: {} }, }) From 3c2307e8ddf045086828cfba1b12ba2a12e48492 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Tue, 27 Jul 2021 16:55:53 +0100 Subject: [PATCH 024/149] refactor: clean up code and improve comments --- packages/gatsby-source-contentful/src/source-nodes.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index 12530f33a8226..d8c81e993a70d 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -431,6 +431,7 @@ export async function sourceNodes( }) creationActivity.start() + // Create nodes for each entry of each content type for (let i = 0; i < contentTypeItems.length; i++) { const contentTypeItem = contentTypeItems[i] From 2c728280ac34a366a27e1c08a06e5888c297ed2c Mon Sep 17 00:00:00 2001 From: axe312ger Date: Thu, 18 Nov 2021 17:50:42 +0100 Subject: [PATCH 025/149] clean up, fix tests, get downloadAssets working again --- .../contentful/src/pages/download-local.js | 10 ++- .../__fixtures__/restricted-content-type.js | 80 ------------------- .../__tests__/download-contentful-assets.js | 2 + .../src/__tests__/fetch.js | 15 ---- .../src/__tests__/gatsby-node.js | 52 +----------- .../src/download-contentful-assets.js | 4 +- 6 files changed, 10 insertions(+), 153 deletions(-) delete mode 100644 packages/gatsby-source-contentful/src/__fixtures__/restricted-content-type.js diff --git a/e2e-tests/contentful/src/pages/download-local.js b/e2e-tests/contentful/src/pages/download-local.js index e5401942fb130..bd75f86a3d911 100644 --- a/e2e-tests/contentful/src/pages/download-local.js +++ b/e2e-tests/contentful/src/pages/download-local.js @@ -21,10 +21,12 @@ export default DownloadLocalPage export const pageQuery = graphql` query DownloadLocalQuery { contentfulAsset(sys: { id: { eq: "3BSI9CgDdAn1JchXmY5IJi" } }) { - localFile { - absolutePath - childImageSharp { - gatsbyImageData + fields { + localFile { + absolutePath + childImageSharp { + gatsbyImageData + } } } } diff --git a/packages/gatsby-source-contentful/src/__fixtures__/restricted-content-type.js b/packages/gatsby-source-contentful/src/__fixtures__/restricted-content-type.js deleted file mode 100644 index 8adda16238442..0000000000000 --- a/packages/gatsby-source-contentful/src/__fixtures__/restricted-content-type.js +++ /dev/null @@ -1,80 +0,0 @@ -exports.contentTypeItems = () => [ - { - sys: { - space: { - sys: { - type: `Link`, - linkType: `Space`, - id: `uzfinxahlog0`, - contentful_id: `uzfinxahlog0`, - }, - }, - id: `reference`, - type: `ContentType`, - createdAt: `2020-06-03T14:17:18.696Z`, - updatedAt: `2020-06-03T14:17:18.696Z`, - environment: { - sys: { - id: `master`, - type: `Link`, - linkType: `Environment`, - }, - }, - revision: 1, - contentful_id: `person`, - }, - displayField: `name`, - name: `Reference`, - description: ``, - fields: [ - { - id: `name`, - name: `Name`, - type: `Symbol`, - localized: false, - required: true, - disabled: false, - omitted: false, - }, - ], - }, -] - -exports.initialSync = () => { - return { - currentSyncData: { - entries: [], - assets: [], - deletedEntries: [], - deletedAssets: [], - nextSyncToken: `12345`, - }, - defaultLocale: `en-US`, - locales: [ - { - code: `en-US`, - name: `English (United States)`, - default: true, - fallbackCode: null, - sys: { - id: `1uSElBQA68GRKF30tpTxxT`, - type: `Locale`, - version: 1, - }, - }, - ], - space: { - sys: { type: `Space`, id: `uzfinxahlog0` }, - name: `Starter Gatsby Blog`, - locales: [ - { - code: `en-US`, - default: true, - name: `English (United States)`, - fallbackCode: null, - }, - ], - }, - tagItems: [], - } -} 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 401d85f409d72..f9a018efb303e 100644 --- a/packages/gatsby-source-contentful/src/__tests__/download-contentful-assets.js +++ b/packages/gatsby-source-contentful/src/__tests__/download-contentful-assets.js @@ -16,6 +16,8 @@ jest.mock(`gatsby-source-filesystem`, () => { }) const reporter = { + info: jest.fn(), + warn: jest.fn(), createProgress: jest.fn(() => { return { start: jest.fn(), diff --git a/packages/gatsby-source-contentful/src/__tests__/fetch.js b/packages/gatsby-source-contentful/src/__tests__/fetch.js index a89034629a73d..b7541b0c94af7 100644 --- a/packages/gatsby-source-contentful/src/__tests__/fetch.js +++ b/packages/gatsby-source-contentful/src/__tests__/fetch.js @@ -205,21 +205,6 @@ describe(`Tags feature`, () => { syncToken: null, }) - expect(reporter.panic).not.toBeCalled() - expect(mockClient.getTags).not.toBeCalled() - }) - it(`calls contentful.getTags when enabled`, async () => { - await fetchContent({ - pluginConfig: createPluginConfig({ - accessToken: `6f35edf0db39085e9b9c19bd92943e4519c77e72c852d961968665f1324bfc94`, - spaceId: `rocybtov1ozk`, - pageLimit: 50, - enableTags: true, - }), - reporter, - syncToken: null, - }) - expect(reporter.panic).not.toBeCalled() expect(mockClient.getTags).toHaveBeenCalledWith({ limit: 50, diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 88af2de45f7c7..ba430ff2d5aff 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -11,7 +11,6 @@ import { makeId } from "../normalize" import startersBlogFixture from "../__fixtures__/starter-blog-data" import richTextFixture from "../__fixtures__/rich-text-data" -import restrictedContentTypeFixture from "../__fixtures__/restricted-content-type" import unpublishedFieldDelivery from "../__fixtures__/unpublished-fields-delivery" import unpublishedFieldPreview from "../__fixtures__/unpublished-fields-preview" @@ -160,6 +159,7 @@ describe(`gatsby-node`, () => { getCache, reporter, parentSpan, + schema, }, pluginOptions ) @@ -1259,54 +1259,4 @@ describe(`gatsby-node`, () => { }) ) }) - - it(`panics when response contains restricted content types`, async () => { - // @ts-ignore - fetchContent.mockImplementationOnce( - restrictedContentTypeFixture.initialSync - ) - // @ts-ignore - fetchContentTypes.mockImplementationOnce( - restrictedContentTypeFixture.contentTypeItems - ) - - await simulateGatsbyBuild() - - expect(reporter.panic).toBeCalledWith( - expect.objectContaining({ - context: { - sourceMessage: `Restricted ContentType name found. The name "reference" is not allowed.`, - }, - }) - ) - }) - - it(`panics when response contains content type Tag while enableTags is true`, async () => { - // @ts-ignore - fetchContent.mockImplementationOnce( - restrictedContentTypeFixture.initialSync - ) - const contentTypesWithTag = () => { - const manipulatedContentTypeItems = - restrictedContentTypeFixture.contentTypeItems() - manipulatedContentTypeItems[0].name = `Tag` - return manipulatedContentTypeItems - } - // @ts-ignore - fetchContentTypes.mockImplementationOnce(contentTypesWithTag) - - await simulateGatsbyBuild({ - spaceId: `mocked`, - enableTags: true, - useNameForId: true, - }) - - expect(reporter.panic).toBeCalledWith( - expect.objectContaining({ - context: { - sourceMessage: `Restricted ContentType name found. The name "tag" is not allowed.`, - }, - }) - ) - }) }) diff --git a/packages/gatsby-source-contentful/src/download-contentful-assets.js b/packages/gatsby-source-contentful/src/download-contentful-assets.js index e6da9cfc0c5e1..c15c162a9168f 100644 --- a/packages/gatsby-source-contentful/src/download-contentful-assets.js +++ b/packages/gatsby-source-contentful/src/download-contentful-assets.js @@ -57,9 +57,7 @@ export async function downloadContentfulAssets(gatsbyFunctions) { const cacheRemoteData = await cache.get(remoteDataCacheKey) if (!assetNode.url) { - reporter.warn( - `The asset with id: ${id} has a file but the file contains no url.` - ) + reporter.warn(`The asset with id: ${id} has no url.`) return Promise.resolve() } const url = createUrl(assetNode.url) From cde8173e1ecb259e7a2aeac2d84b17c74554edbd Mon Sep 17 00:00:00 2001 From: axe312ger Date: Fri, 19 Nov 2021 11:10:33 +0100 Subject: [PATCH 026/149] more small fixes --- e2e-tests/contentful/src/pages/gatsby-plugin-image.js | 4 ++-- packages/gatsby-transformer-sqip/src/extend-node-type.js | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js index deb54a7640138..0330f8f106ebf 100644 --- a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js +++ b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js @@ -129,14 +129,14 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.file.fileName.split(".").pop()}) + {node.title} ({node.fileName.split(".").pop()})

{node.description &&

{node.description}

} {node.customImageFormats ? ( ) : ( - + )}
))} diff --git a/packages/gatsby-transformer-sqip/src/extend-node-type.js b/packages/gatsby-transformer-sqip/src/extend-node-type.js index b64bef2e3e501..5033b66c54c65 100644 --- a/packages/gatsby-transformer-sqip/src/extend-node-type.js +++ b/packages/gatsby-transformer-sqip/src/extend-node-type.js @@ -194,9 +194,7 @@ async function sqipContentful({ type, cache, store }) { mimeTypeExtensions, } = require(`gatsby-source-contentful/image-helpers`) - const { - file: { contentType, url: imgUrl, fileName }, - } = asset + const { contentType, url: imgUrl, fileName } = asset if (!contentType.includes(`image/`)) { return null From cefa3fa9a0816f410195aa1f1d187051a49fbad7 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Fri, 26 Nov 2021 13:59:14 +0100 Subject: [PATCH 027/149] fix: align downloadLocal scheme and gatsby-plugin-image --- e2e-tests/contentful/src/pages/download-local.js | 4 +++- .../src/gatsby-plugin-image.js | 10 +++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/e2e-tests/contentful/src/pages/download-local.js b/e2e-tests/contentful/src/pages/download-local.js index bd75f86a3d911..564302b009891 100644 --- a/e2e-tests/contentful/src/pages/download-local.js +++ b/e2e-tests/contentful/src/pages/download-local.js @@ -10,7 +10,9 @@ const DownloadLocalPage = ({ data }) => {

Test downloadLocal feature

) diff --git a/packages/gatsby-source-contentful/src/gatsby-plugin-image.js b/packages/gatsby-source-contentful/src/gatsby-plugin-image.js index 8dd086291d89e..5582e20c51ddc 100644 --- a/packages/gatsby-source-contentful/src/gatsby-plugin-image.js +++ b/packages/gatsby-source-contentful/src/gatsby-plugin-image.js @@ -29,7 +29,7 @@ const getBase64Image = (imageProps, cache) => { // Keep aspect ratio, image format and other transform options const { aspectRatio } = imageProps - const originalFormat = imageProps.image.file.contentType.split(`/`)[1] + const originalFormat = imageProps.image.contentType.split(`/`)[1] const toFormat = imageProps.options.toFormat const imageOptions = { ...imageProps.options, @@ -53,9 +53,7 @@ const getBase64Image = (imageProps, cache) => { } const loadImage = async () => { - const { - file: { contentType }, - } = imageProps.image + const { contentType } = imageProps.image const extension = mimeTypeExtensions.get(contentType) @@ -126,9 +124,7 @@ const getDominantColor = async ({ image, options, cache }) => { } try { - const { - file: { contentType, url: imgUrl, fileName }, - } = image + const { contentType, url: imgUrl, fileName } = image if (contentType.indexOf(`image/`) !== 0) { return null From c5349f57dbcbc0d158981acea7623265a75f2d6b Mon Sep 17 00:00:00 2001 From: axe312ger Date: Fri, 26 Nov 2021 14:11:22 +0100 Subject: [PATCH 028/149] style: use object syntax everywhere to define schema --- .../src/generate-schema.js | 91 ++++++++++++------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index cb897357c5522..8a87d40e2c8a3 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -120,43 +120,66 @@ export function generateSchema({ actions, }) { // Generic Types - createTypes(` - interface ContentfulReference implements Node { - id: ID! - sys: ContentfulSys! - } - `) + createTypes( + schema.buildInterfaceType({ + name: `ContentfulReference`, + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + }, + interfaces: [`Node`], + }) + ) - createTypes(` - type ContentfulContentType implements Node { - id: ID! - name: String! - displayField: String! - description: String! - } - `) + createTypes( + schema.buildInterfaceType({ + name: `ContentfulEntry`, + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, + }, + interfaces: [`ContentfulReference`, `Node`], + }) + ) - createTypes(` - type ContentfulSys @dontInfer { - 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( + schema.buildObjectType({ + name: `ContentfulContentType`, + fields: { + id: { type: `ID!` }, + name: { type: `String!` }, + displayField: { type: `String!` }, + description: { type: `String!` }, + }, + interfaces: [`Node`], + extensions: { dontInfer: {} }, + }) + ) - createTypes(` - interface ContentfulEntry implements ContentfulReference & Node @dontInfer { - id: ID! - sys: ContentfulSys! - metadata: ContentfulMetadata! - } - `) + createTypes( + schema.buildObjectType({ + name: `ContentfulSys`, + fields: { + id: { type: ` String!` }, + type: { type: ` String!` }, + spaceId: { type: ` String!` }, + environmentId: { type: ` String!` }, + contentType: { + type: `ContentfulContentType`, + extensions: { + link: { by: `id`, from: `contentType___NODE` }, + }, + }, + firstPublishedAt: { type: ` Date!` }, + publishedAt: { type: ` Date!` }, + publishedVersion: { type: ` Int!` }, + locale: { type: ` String!` }, + }, + interfaces: [`Node`], + extensions: { dontInfer: {} }, + }) + ) createTypes( schema.buildObjectType({ From 9656127d2155f8e4836a53848510e62e1e6e7b10 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Mon, 29 Nov 2021 14:08:13 +0100 Subject: [PATCH 029/149] fix: make unit tests pass. Solution for deleted entries still needs work --- .../__snapshots__/gatsby-node.js.snap | 16 +++++++-------- .../src/__tests__/gatsby-plugin-image.js | 20 ++++++++----------- 2 files changed, 16 insertions(+), 20 deletions(-) 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 4e62cb24f807d..c8fa86145953f 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 @@ -1,13 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`gatsby-node stores rich text as raw with references attached 1`] = ` -Array [ - "ahntqop9oi7x___7oHxo6bs0us9wIkq27qdyK___Entry", - "ahntqop9oi7x___6KpLS2NZyB3KAvDzWf4Ukh___Entry", - "ahntqop9oi7x___4ZQrqcrTunWiuNaavhGYNT___Asset", -] -`; - exports[`gatsby-node stores rich text as JSON 2`] = ` Object { "content": Array [ @@ -407,3 +399,11 @@ Object { "nodeType": "document", } `; + +exports[`gatsby-node stores rich text as raw with references attached 1`] = ` +Array [ + "ahntqop9oi7x___7oHxo6bs0us9wIkq27qdyK___Entry", + "ahntqop9oi7x___6KpLS2NZyB3KAvDzWf4Ukh___Entry", + "ahntqop9oi7x___4ZQrqcrTunWiuNaavhGYNT___Asset", +] +`; diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js index b60b7139e628d..e9803ea9f210a 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js @@ -38,19 +38,15 @@ const createMockCache = () => { const cache = createMockCache() const exampleImage = { - defaultLocale: `en-US`, - file: { - url: `//images.ctfassets.net:443/k8iqpp6u0ior/3ljGfnpegOnBTFGhV07iC1/94257340bda15ad4ca8462da3a8afa07/347966-contentful-logo-wordmark-dark__1_-4cd185-original-1582664935__1_.png`, - fileName: `347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png`, - contentType: `image/png`, - details: { - size: 123456, - image: { - width: `1646`, - height: `338`, - }, - }, + sys: { + locale: `en-US`, }, + url: `https://images.ctfassets.net:443/k8iqpp6u0ior/3ljGfnpegOnBTFGhV07iC1/94257340bda15ad4ca8462da3a8afa07/347966-contentful-logo-wordmark-dark__1_-4cd185-original-1582664935__1_.png`, + fileName: `347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png`, + contentType: `image/png`, + size: 123456, + width: `1646`, + height: `338`, internal: { contentDigest: `unique`, }, From 5e435174c038f5b4ebfeffdf187b2500c7e03322 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 29 Nov 2021 16:38:41 +0100 Subject: [PATCH 030/149] feat: use union for reference fields with validation (#31395) Also: * test: add unit tests for schema customization * fix: rich text inline rendering * test: update e2e test schema dump --- e2e-tests/contentful/schema.gql | 88 +- e2e-tests/contentful/snapshots.js | 98 +- .../contentful/src/pages/content-reference.js | 17 +- e2e-tests/contentful/src/pages/rich-text.js | 20 +- .../src/__fixtures__/content-types.js | 786 ++++++++++++++++ .../create-schema-customization.js.snap | 843 ++++++++++++++++++ .../__tests__/create-schema-customization.js | 46 + .../src/generate-schema.js | 69 +- .../gatsby-source-contentful/src/normalize.js | 3 +- 9 files changed, 1867 insertions(+), 103 deletions(-) create mode 100644 packages/gatsby-source-contentful/src/__fixtures__/content-types.js create mode 100644 packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap create mode 100644 packages/gatsby-source-contentful/src/__tests__/create-schema-customization.js diff --git a/e2e-tests/contentful/schema.gql b/e2e-tests/contentful/schema.gql index 5f4ef8d58f623..86b7511083dd6 100644 --- a/e2e-tests/contentful/schema.gql +++ b/e2e-tests/contentful/schema.gql @@ -74,8 +74,6 @@ type Directory implements Node @dontInfer { type Site implements Node @dontInfer { buildTime: Date @dateformat siteMetadata: SiteSiteMetadata - port: Int - host: String polyfill: Boolean pathPrefix: String jsxRuntime: String @@ -124,12 +122,11 @@ type SiteBuildMetadata implements Node @dontInfer { interface ContentfulReference implements Node { id: ID! - sys: ContentfulSys + sys: ContentfulSys! } -type ContentfulSys { +type ContentfulSys implements Node @dontInfer { type: String! - id: String! spaceId: String! environmentId: String! contentType: ContentfulContentType @link(by: "id", from: "contentType___NODE") @@ -145,13 +142,27 @@ type ContentfulContentType implements Node @dontInfer { description: String! } -interface ContentfulEntry implements Node { +interface ContentfulEntry implements ContentfulReference & Node { id: ID! - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! +} + +type ContentfulMetadata @dontInfer { + tags: [ContentfulTag]! @link(by: "id", from: "tags___NODE") +} + +type ContentfulTag implements Node @dontInfer { + name: String! + contentful_id: String! +} + +type ContentfulAssetFields @dontInfer { + localFile: File @link(by: "id") } type ContentfulAsset implements ContentfulReference & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! title: String description: String contentType: String @@ -163,15 +174,6 @@ type ContentfulAsset implements ContentfulReference & Node @dontInfer { fields: ContentfulAssetFields } -type ContentfulAssetFields { - localFile: String -} - -type ContentfulTag implements Node @dontInfer { - name: String! - contentful_id: String! -} - type ContentfulRichTextAssets { block: [ContentfulAsset]! hyperlink: [ContentfulAsset]! @@ -203,7 +205,8 @@ type ContentfulText implements Node @dontInfer { } type ContentfulContentTypeNumber implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String integer: Int integerLocalized: Int @@ -212,7 +215,8 @@ type ContentfulContentTypeNumber implements ContentfulReference & ContentfulEntr } type ContentfulContentTypeText implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String short: String shortLocalized: String @@ -224,7 +228,8 @@ type ContentfulContentTypeText implements ContentfulReference & ContentfulEntry } type ContentfulContentTypeMediaReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String one: ContentfulAsset @link(by: "id", from: "one___NODE") oneLocalized: ContentfulAsset @link(by: "id", from: "oneLocalized___NODE") @@ -233,14 +238,16 @@ type ContentfulContentTypeMediaReference implements ContentfulReference & Conten } type ContentfulContentTypeBoolean implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String boolean: Boolean booleanLocalized: Boolean } type ContentfulContentTypeDate implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String date: Date @dateformat dateTime: Date @dateformat @@ -249,44 +256,53 @@ type ContentfulContentTypeDate implements ContentfulReference & ContentfulEntry } type ContentfulContentTypeLocation implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String location: ContentfulLocation locationLocalized: ContentfulLocation } type ContentfulContentTypeJson implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String json: JSON jsonLocalized: JSON } type ContentfulContentTypeRichText implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String richText: ContentfulRichText richTextLocalized: ContentfulRichText richTextValidated: ContentfulRichText } -type ContentfulContentTypeContentReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys +type ContentfulContentTypeContentReference implements ContentfulReference & ContentfulEntry & Node @isPlaceholder @dontInfer { + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String one: ContentfulEntry @link(by: "id", from: "one___NODE") oneLocalized: ContentfulEntry @link(by: "id", from: "oneLocalized___NODE") - many: [ContentfulEntry] @link(by: "id", from: "many___NODE") + many: [UnionContentfulContentReferenceNumberText] @link(by: "id", from: "many___NODE") manyLocalized: [ContentfulEntry] @link(by: "id", from: "manyLocalized___NODE") } +union UnionContentfulContentReferenceNumberText = ContentfulContentTypeContentReference | ContentfulContentTypeNumber | ContentfulContentTypeText + +union UnionContentfulNumberText = ContentfulContentTypeNumber | ContentfulContentTypeText + type ContentfulContentTypeValidatedContentReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { - sys: ContentfulSys + sys: ContentfulSys! + metadata: ContentfulMetadata! title: String - oneItemSingleType: ContentfulEntry @link(by: "id", from: "oneItemSingleType___NODE") - oneItemManyTypes: ContentfulEntry @link(by: "id", from: "oneItemManyTypes___NODE") + oneItemSingleType: ContentfulContentTypeText @link(by: "id", from: "oneItemSingleType___NODE") + oneItemManyTypes: UnionContentfulNumberText @link(by: "id", from: "oneItemManyTypes___NODE") oneItemAllTypes: ContentfulEntry @link(by: "id", from: "oneItemAllTypes___NODE") - multipleItemsSingleType: [ContentfulEntry] @link(by: "id", from: "multipleItemsSingleType___NODE") - multipleItemsManyTypes: [ContentfulEntry] @link(by: "id", from: "multipleItemsManyTypes___NODE") + multipleItemsSingleType: [ContentfulContentTypeText] @link(by: "id", from: "multipleItemsSingleType___NODE") + multipleItemsManyTypes: [UnionContentfulNumberText] @link(by: "id", from: "multipleItemsManyTypes___NODE") multipleItemsAllTypes: [ContentfulEntry] @link(by: "id", from: "multipleItemsAllTypes___NODE") } @@ -317,7 +333,7 @@ type MarkdownWordCount { words: Int } -type MarkdownRemark implements Node @childOf(mimeTypes: ["text/markdown", "text/x-markdown"], types: ["ContentfulText"]) @dontInfer { +type MarkdownRemark implements Node @childOf(mimeTypes: ["text/markdown", "text/x-markdown"], types: ["ContentfulText"]) @derivedTypes @dontInfer { frontmatter: MarkdownRemarkFrontmatter excerpt: String rawMarkdownBody: String @@ -481,7 +497,7 @@ type ImageSharpResize { originalName: String } -type ImageSharp implements Node @childOf(mimeTypes: [], types: ["File"]) @dontInfer { +type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { fixed(width: Int, height: Int, base64Width: Int, jpegProgressive: Boolean = true, pngCompressionSpeed: Int = 4, grayscale: Boolean = false, duotone: DuotoneGradient, traceSVG: Potrace, quality: Int, jpegQuality: Int, pngQuality: Int, webpQuality: Int, toFormat: ImageFormat = AUTO, toFormatBase64: ImageFormat = AUTO, cropFocus: ImageCropFocus = ATTENTION, fit: ImageFit = COVER, background: String = "rgba(0,0,0,1)", rotate: Int = 0, trim: Float = 0): ImageSharpFixed fluid( maxWidth: Int @@ -652,7 +668,7 @@ enum GatsbyImagePlaceholder { NONE } -type ContentfulContentTypeContentType implements Node @dontInfer { +type ContentfulContentTypeContentType implements Node @derivedTypes @dontInfer { name: String displayField: String description: String diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index 863033c7e4524..ac0209ef252bb 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -1,118 +1,118 @@ module.exports = { - "__version": "9.5.4", + __version: "9.5.4", "content-reference": { "content-reference-many-2nd-level-loop": { - "1": "
\n

Content Reference: Many (2nd level loop)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" + 1: '
\n

Content Reference: Many (2nd level loop)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
', }, "content-reference-many-loop-a-greater-b": { - "1": "
\n

Content Reference: Many (Loop A -> B)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop B -> A)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop A ->\n B)\n ]

\n
" + 1: '
\n

Content Reference: Many (Loop A -> B)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop B -> A)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop A ->\n B)\n ]

\n
', }, "content-reference-many-loop-b-greater-a": { - "1": "
\n

Content Reference: Many (Loop B -> A)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop A -> B)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop B ->\n A)\n ]

\n
" + 1: '
\n

Content Reference: Many (Loop B -> A)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop A -> B)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop B ->\n A)\n ]

\n
', }, "content-reference-many-self-reference": { - "1": "
\n

Content Reference: Many (Self Reference)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Self Reference)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Self\n Reference)\n ]

\n
" + 1: '
\n

Content Reference: Many (Self Reference)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Self Reference)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Self\n Reference)\n ]

\n
', }, "content-reference-one": { - "1": "
\n

Content Reference: One

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n
" + 1: '
\n

Content Reference: One

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n
', }, "content-reference-one-loop-a-greater-b": { - "1": "
\n

Content Reference: One (Loop A -> B)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n
" + 1: '
\n

Content Reference: One (Loop A -> B)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n
', }, "content-reference-one-loop-b-greater-a": { - "1": "
\n

Content Reference: One (Loop B -> A)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" + 1: '
\n

Content Reference: One (Loop B -> A)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
', }, "content-reference-one-self-reference": { - "1": "
\n

Content Reference: One (Self Reference)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Self Reference)\n : [\n Content Reference: One (Self Reference)\n ]

\n
" - } + 1: '
\n

Content Reference: One (Self Reference)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Self Reference)\n : [\n Content Reference: One (Self Reference)\n ]

\n
', + }, }, "rich-text": { "rich-text: All Features": { - "1": "
\n

Rich Text: All Features

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n
\"\"\n\n
\n
\n \n \n \"\"\n\n \n \n
\n

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
  7. \n

    [Inline-ContentfulText]\n Text: Short\n :\n The quick brown fox jumps over the lazy dog.

    \n
  8. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n

[ContentfulLocation] Lat:\n 52.51627\n , Long:\n 13.3777

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
" + 1: '
\n

Rich Text: All Features

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n
\n
\n \n \n \n \n \n \n
\n

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
  7. \n

    [Inline-ContentfulText]\n Text: Short\n :\n The quick brown fox jumps over the lazy dog.

    \n
  8. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n "userId": 1,\n "id": 1,\n "title": "delectus aut autem",\n "completed": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n

[ContentfulLocation] Lat:\n 52.51627\n , Long:\n 13.3777

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
', }, "rich-text: Basic": { - "1": "
\n

Rich Text: Basic

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
" + 1: '
\n

Rich Text: Basic

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n "userId": 1,\n "id": 1,\n "title": "delectus aut autem",\n "completed": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
', }, "rich-text: Embedded Entry": { - "1": "
\n

Rich Text: Embedded Entry

\n

Embedded Entry

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

\n

\n
\n
" + 1: '
\n

Rich Text: Embedded Entry

\n

Embedded Entry

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

\n

\n
\n
', }, "rich-text: Embedded Asset": { - "1": "
\n

Rich Text: Embedded asset

\n

Embedded Asset

\n
\n
\"\"\n\n
\n
\n \n \n \"\"\n\n \n \n
\n

\n

\n

\n
\n
" + 1: '
\n

Rich Text: Embedded asset

\n

Embedded Asset

\n
\n
\n
\n \n \n \n \n \n \n
\n

\n

\n

\n
\n
', }, "rich-text: Embedded Entry With Deep Reference Loop": { - "1": "
\n

Rich Text: Embedded entry with deep reference loop

\n

Embedded entry with deep reference loop

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (2nd level loop)\n : [\n Number: Integer, Text: Short, Content Reference: One (Loop A ->\n B)\n ]

\n

\n

\n
\n
" + 1: '
\n

Rich Text: Embedded entry with deep reference loop

\n

Embedded entry with deep reference loop

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (2nd level loop)\n : [\n Number: Integer, Text: Short, Content Reference: One (Loop A ->\n B)\n ]

\n

\n

\n
\n
', }, "rich-text: Embedded Entry With Reference Loop": { - "1": "
\n

Rich Text: Embedded entry with reference loop

\n

Embedded entry with reference loop

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n

\n
\n
" + 1: '
\n

Rich Text: Embedded entry with reference loop

\n

Embedded entry with reference loop

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n

\n
\n
', }, "rich-text: Inline Entry": { - "1": "
\n

Rich Text: Inline entry

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeText\n ] and before that

\n

\n

\n
\n
" + 1: '
\n

Rich Text: Inline entry

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog. and before\n that

\n

\n

\n
\n
', }, "rich-text: Inline Entry With Deep Reference Loop": { - "1": "
\n

Rich Text: Inline entry with deep reference loop

\n

Inline entry with deep reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeContentReference\n ] and before that

\n

\n

\n
\n
" + 1: '
\n

Rich Text: Inline entry with deep reference loop

\n

Inline entry with deep reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeContentReference\n ] and before that

\n

\n

\n
\n
', }, "rich-text: Inline Entry With Reference Loop": { - "1": "
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeContentReference\n ] and before that

\n

\n

\n
\n
" + 1: '
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeContentReference\n ] and before that

\n

\n

\n
\n
', }, "rich-text: Localized": { - "1": "
\n

Rich Text: Localized

\n

Rich Text in English

\n
\n
", - "2": "
\n

Rich Text: Localized

\n

Reichhaltiger Text in deutscher\n Sprache

\n
\n
" + 1: '
\n

Rich Text: Localized

\n

Rich Text in English

\n
\n
', + 2: '
\n

Rich Text: Localized

\n

Reichhaltiger Text in deutscher\n Sprache

\n
\n
', }, "rich-text: Tables": { - "1": "
\n

Rich Text: Tables

\n

Table test

\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n

Heading One

\n
\n

Heading Two

\n
\n

Heading Three

\n
\n

\n
\n

This should be fat

\n
\n

Baz

\n
\n

\n
\n
" - } + 1: '
\n

Rich Text: Tables

\n

Table test

\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n

Heading One

\n
\n

Heading Two

\n
\n

Heading Three

\n
\n

\n
\n

This should be fat

\n
\n

Baz

\n
\n

\n
\n
', + }, }, - "text": { + text: { "text: Short List": { - "1": "
\n
    \n
  • The quick brown fox
  • \n
  • jumps over the lazy dog
  • \n
\n
" + 1: '
\n
    \n
  • The quick brown fox
  • \n
  • jumps over the lazy dog
  • \n
\n
', }, "text: Long Markdown Simple": { - "1": "
\n

Headline

\n

The European languages are members of the same family.\n Their separate existence is a myth. For:

\n
    \n
  • science
  • \n
  • music
  • \n
  • sport
  • \n
  • etc
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.

\n
\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
" + 1: '
\n

Headline

\n

The European languages are members of the same family.\n Their separate existence is a myth. For:

\n
    \n
  • science
  • \n
  • music
  • \n
  • sport
  • \n
  • etc
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.

\n
\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
', }, "text: Long Markdown Complex": { - "1": "
\n

Headline Complex

\n

The European languages are members of the same family. Their\n separate existence is a myth. For:

\n
    \n
  • science
  • \n
  • music
  • \n
  • sport
  • \n
  • etc
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.

\n
\n

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
{\n\t\"userId\": 1,\n\t\"id\": 1,\n\t\"title\": \"delectus aut autem\",\n\t\"completed\": false\n}\n
\n
" + 1: '
\n

Headline Complex

\n

The European languages are members of the same family. Their\n separate existence is a myth. For:

\n
    \n
  • science
  • \n
  • music
  • \n
  • sport
  • \n
  • etc
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.

\n
\n

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
{\n\t"userId": 1,\n\t"id": 1,\n\t"title": "delectus aut autem",\n\t"completed": false\n}\n
\n
', }, "text: Long Localized": { - "1": "
\n

One morning, when Gregor Samsa woke from troubled\n dreams, he found himself transformed in his bed into a horrible vermin. He\n lay on his armour-like back, and if he lifted his head a little he could see\n his brown belly, slightly domed and divided by arches into stiff sections.\n The bedding was hardly able to cover it and seemed ready to slide off any\n moment. His many legs, pitifully thin compared with the size of the rest of\n him, waved about helplessly as he looked. \"What's happened to me?\" he\n thought.\n\n It wasn't a dream. His room, a proper human room although a little too\n small, lay peacefully between its four familiar walls. A collection of\n textile samples lay spread out on the table - Samsa was a travelling\n salesman - and above it there hung a picture that he had recently cut out of\n an illustrated magazine and housed in a nice, gilded frame. It showed a lady\n fitted out with a fur hat and fur boa who sat upright, raising a heavy fur\n muff that covered the whole of her lower arm towards the viewer. Gregor then\n turned to look out the window at the dull weather.

\n
", - "2": "
\n

Jemand musste Josef K. verleumdet haben, denn ohne\n dass er etwas Böses getan hätte, wurde er eines Morgens verhaftet. »Wie ein\n Hund!« sagte er, es war, als sollte die Scham ihn überleben. Als Gregor\n Samsa eines Morgens aus unruhigen Träumen erwachte, fand er sich in seinem\n Bett zu einem ungeheueren Ungeziefer verwandelt. Und es war ihnen wie eine\n Bestätigung ihrer neuen Träume und guten Absichten, als am Ziele ihrer Fahrt\n die Tochter als erste sich erhob und ihren jungen Körper dehnte.\n\n »Es ist ein eigentümlicher Apparat«, sagte der Offizier zu dem\n Forschungsreisenden und überblickte mit einem gewissermaßen bewundernden\n Blick den ihm doch wohlbekannten Apparat. Sie hätten noch ins Boot springen\n können, aber der Reisende hob ein schweres, geknotetes Tau vom Boden, drohte\n ihnen damit und hielt sie dadurch von dem Sprunge ab. In den letzten\n Jahrzehnten ist das Interesse an Hungerkünstlern sehr zurückgegangen. Aber\n sie überwanden sich, umdrängten den Käfig und wollten sich gar nicht\n fortrühren.Jemand musste Josef K. verleumdet haben, denn ohne dass er etwas\n Böses getan hätte, wurde er eines Morgens verhaftet. »Wie ein Hund!« sagte\n er, es war, als sollte die Scham ihn überleben. Als Gregor Samsa eines\n Morgens aus unruhigen Träumen erwachte, fand er sich

\n
" - } + 1: '
\n

One morning, when Gregor Samsa woke from troubled\n dreams, he found himself transformed in his bed into a horrible vermin. He\n lay on his armour-like back, and if he lifted his head a little he could see\n his brown belly, slightly domed and divided by arches into stiff sections.\n The bedding was hardly able to cover it and seemed ready to slide off any\n moment. His many legs, pitifully thin compared with the size of the rest of\n him, waved about helplessly as he looked. "What\'s happened to me?" he\n thought.\n\n It wasn\'t a dream. His room, a proper human room although a little too\n small, lay peacefully between its four familiar walls. A collection of\n textile samples lay spread out on the table - Samsa was a travelling\n salesman - and above it there hung a picture that he had recently cut out of\n an illustrated magazine and housed in a nice, gilded frame. It showed a lady\n fitted out with a fur hat and fur boa who sat upright, raising a heavy fur\n muff that covered the whole of her lower arm towards the viewer. Gregor then\n turned to look out the window at the dull weather.

\n
', + 2: '
\n

Jemand musste Josef K. verleumdet haben, denn ohne\n dass er etwas Böses getan hätte, wurde er eines Morgens verhaftet. »Wie ein\n Hund!« sagte er, es war, als sollte die Scham ihn überleben. Als Gregor\n Samsa eines Morgens aus unruhigen Träumen erwachte, fand er sich in seinem\n Bett zu einem ungeheueren Ungeziefer verwandelt. Und es war ihnen wie eine\n Bestätigung ihrer neuen Träume und guten Absichten, als am Ziele ihrer Fahrt\n die Tochter als erste sich erhob und ihren jungen Körper dehnte.\n\n »Es ist ein eigentümlicher Apparat«, sagte der Offizier zu dem\n Forschungsreisenden und überblickte mit einem gewissermaßen bewundernden\n Blick den ihm doch wohlbekannten Apparat. Sie hätten noch ins Boot springen\n können, aber der Reisende hob ein schweres, geknotetes Tau vom Boden, drohte\n ihnen damit und hielt sie dadurch von dem Sprunge ab. In den letzten\n Jahrzehnten ist das Interesse an Hungerkünstlern sehr zurückgegangen. Aber\n sie überwanden sich, umdrängten den Käfig und wollten sich gar nicht\n fortrühren.Jemand musste Josef K. verleumdet haben, denn ohne dass er etwas\n Böses getan hätte, wurde er eines Morgens verhaftet. »Wie ein Hund!« sagte\n er, es war, als sollte die Scham ihn überleben. Als Gregor Samsa eines\n Morgens aus unruhigen Träumen erwachte, fand er sich

\n
', + }, }, - "json": { + json: { "json: Complex": { - "1": "
\n

Name:\n Tom Cruise

\n

Photo:\n https://jsonformatter.org/img/tom-cruise.jpg

\n

Birthdate:\n 1962-7-3T00:12:34.000Z

\n

Born at:\n Syracuse, NY

\n

Weight:\n 67.5

\n

Age:\n 56

\n

Wife:

\n

Children:\n Suri, Isabella Jane, Connor

\n

Has children:\n true

\n

Has grey hair:\n false

\n
", - "2": "
\n

Name:\n Robert Downey Jr.

\n

Photo:\n https://jsonformatter.org/img/Robert-Downey-Jr.jpg

\n

Birthdate:\n 1965-4-4T00:12:34.000Z

\n

Born at:\n New York City, NY

\n

Weight:\n 77.1

\n

Age:\n 53

\n

Wife:\n Susan Downey

\n

Children:\n Indio Falconer, Avri Roel, Exton Elias

\n

Has children:\n true

\n

Has grey hair:\n false

\n
" - } + 1: '
\n

Name:\n Tom Cruise

\n

Photo:\n https://jsonformatter.org/img/tom-cruise.jpg

\n

Birthdate:\n 1962-7-3T00:12:34.000Z

\n

Born at:\n Syracuse, NY

\n

Weight:\n 67.5

\n

Age:\n 56

\n

Wife:

\n

Children:\n Suri, Isabella Jane, Connor

\n

Has children:\n true

\n

Has grey hair:\n false

\n
', + 2: '
\n

Name:\n Robert Downey Jr.

\n

Photo:\n https://jsonformatter.org/img/Robert-Downey-Jr.jpg

\n

Birthdate:\n 1965-4-4T00:12:34.000Z

\n

Born at:\n New York City, NY

\n

Weight:\n 77.1

\n

Age:\n 53

\n

Wife:\n Susan Downey

\n

Children:\n Indio Falconer, Avri Roel, Exton Elias

\n

Has children:\n true

\n

Has grey hair:\n false

\n
', + }, }, "content-reference localized": { "english-content-reference-one-localized": { - "1": "
\n

Content Reference: One Localized

\n

[ContentfulContentTypeNumber]\n 42

\n
" + 1: '
\n

Content Reference: One Localized

\n

[ContentfulContentTypeNumber]\n 42

\n
', }, "english-content-reference-many-localized": { - "1": "
\n

Content Reference: Many Localized

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeNumber]\n 42

\n
" + 1: '
\n

Content Reference: Many Localized

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeNumber]\n 42

\n
', }, "german-content-reference-one-localized": { - "1": "
\n

Content Reference: One Localized

\n

[ContentfulContentTypeNumber]\n 4.2

\n
" + 1: '
\n

Content Reference: One Localized

\n

[ContentfulContentTypeNumber]\n 4.2

\n
', }, "german-content-reference-many-localized": { - "1": "
\n

Content Reference: Many Localized

\n

[ContentfulContentTypeNumber]\n 4.2

\n

[ContentfulContentTypeText]\n The European languages are members of the same family. Their\n separate existence is a myth. For science, music, sport, etc, Europe uses\n the same vocabulary.\n\n The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.\n\n To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
" - } + 1: '
\n

Content Reference: Many Localized

\n

[ContentfulContentTypeNumber]\n 4.2

\n

[ContentfulContentTypeText]\n The European languages are members of the same family. Their\n separate existence is a myth. For science, music, sport, etc, Europe uses\n the same vocabulary.\n\n The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.\n\n To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
', + }, }, "media-reference localized": { "media-reference: many with localized field": { - "1": "
\n

Media Reference: Many Localized Field

\n
", - "2": "
\n

Media Reference: Many Localized Field

\n
" + 1: '
\n

Media Reference: Many Localized Field

\n
', + 2: '
\n

Media Reference: Many Localized Field

\n
', }, "media-reference: many with localized asset": { - "1": "
\n

Media Reference: Many With Localized Asset

\n
", - "2": "
\n

Media Reference: Many With Localized Asset

\n
" + 1: '
\n

Media Reference: Many With Localized Asset

\n
', + 2: '
\n

Media Reference: Many With Localized Asset

\n
', }, "media-reference: one with localized asset": { - "1": "
\n

Media Reference: One Localized Asset

\n
", - "2": "
\n

Media Reference: One Localized Asset

\n
" + 1: '
\n

Media Reference: One Localized Asset

\n
', + 2: '
\n

Media Reference: One Localized Asset

\n
', }, "media-reference: one with localized field": { - "1": "
\n

Media Reference: One Localized Field

\n
", - "2": "
\n

Media Reference: One Localized Field

\n
" - } - } + 1: '
\n

Media Reference: One Localized Field

\n
', + 2: '
\n

Media Reference: One Localized Field

\n
', + }, + }, } diff --git a/e2e-tests/contentful/src/pages/content-reference.js b/e2e-tests/contentful/src/pages/content-reference.js index af6400da98f3b..d31fdb8f8b14b 100644 --- a/e2e-tests/contentful/src/pages/content-reference.js +++ b/e2e-tests/contentful/src/pages/content-reference.js @@ -109,8 +109,10 @@ export const pageQuery = graphql` } one { __typename - sys { - id + ... on ContentfulEntry { + sys { + id + } } ... on ContentfulContentTypeText { title @@ -152,8 +154,10 @@ export const pageQuery = graphql` } many { __typename - sys { - id + ... on ContentfulEntry { + sys { + id + } } ... on ContentfulContentTypeText { title @@ -165,6 +169,11 @@ export const pageQuery = graphql` } ... on ContentfulContentTypeContentReference { title + ... on ContentfulEntry { + sys { + id + } + } one { ... on ContentfulContentTypeText { title diff --git a/e2e-tests/contentful/src/pages/rich-text.js b/e2e-tests/contentful/src/pages/rich-text.js index c3488ad37f63a..33c360059c08f 100644 --- a/e2e-tests/contentful/src/pages/rich-text.js +++ b/e2e-tests/contentful/src/pages/rich-text.js @@ -50,10 +50,10 @@ const makeOptions = ({ assetBlockMap, entryBlockMap, entryInlineMap }) => ({ }, [INLINES.EMBEDDED_ENTRY]: node => { const entry = entryInlineMap.get(node?.data?.target?.sys.id) - if (entry.__typename === "ContentfulText") { + if (entry.__typename === "ContentfulContentTypeText") { return ( - [Inline-ContentfulText] {entry.title}: {entry.short} + [Inline-ContentfulContentTypeText] {entry.short} ) } @@ -156,8 +156,10 @@ export const pageQuery = graphql` title one { __typename - sys { - id + ... on ContentfulEntry { + sys { + id + } } ... on ContentfulContentTypeText { title @@ -179,8 +181,10 @@ export const pageQuery = graphql` } many { __typename - sys { - id + ... on ContentfulEntry { + sys { + id + } } ... on ContentfulContentTypeText { title @@ -212,6 +216,10 @@ export const pageQuery = graphql` id type } + ... on ContentfulContentTypeText { + title + short + } } } } diff --git a/packages/gatsby-source-contentful/src/__fixtures__/content-types.js b/packages/gatsby-source-contentful/src/__fixtures__/content-types.js new file mode 100644 index 0000000000000..d3e4a10105aa7 --- /dev/null +++ b/packages/gatsby-source-contentful/src/__fixtures__/content-types.js @@ -0,0 +1,786 @@ +export const contentTypes = [ + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `k8iqpp6u0ior`, + }, + }, + id: `number`, + type: `ContentType`, + createdAt: `2021-03-01T16:59:23.010Z`, + updatedAt: `2021-05-21T11:20:58.851Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 5, + }, + displayField: `title`, + name: `Number`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `integer`, + name: `Integer`, + type: `Integer`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `integerLocalized`, + name: `Integer Localized`, + type: `Integer`, + localized: true, + required: false, + disabled: false, + omitted: false, + }, + { + id: `decimal`, + name: `Decimal`, + type: `Number`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `decimalLocalized`, + name: `Decimal Localized`, + type: `Number`, + localized: true, + required: false, + disabled: false, + omitted: false, + }, + ], + }, + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `k8iqpp6u0ior`, + }, + }, + id: `text`, + type: `ContentType`, + createdAt: `2021-03-01T17:02:35.612Z`, + updatedAt: `2021-05-21T10:48:06.210Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 3, + }, + displayField: `title`, + name: `Text`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `short`, + name: `Short`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `shortLocalized`, + name: `Short Localized`, + type: `Symbol`, + localized: true, + required: false, + disabled: false, + omitted: false, + }, + { + id: `shortList`, + name: `Short List`, + type: `Array`, + localized: false, + required: false, + disabled: false, + omitted: false, + items: { + type: `Symbol`, + validations: [], + }, + }, + { + id: `shortListLocalized`, + name: `Short List Localized`, + type: `Array`, + localized: true, + required: false, + disabled: false, + omitted: false, + items: { + type: `Symbol`, + validations: [], + }, + }, + { + id: `longPlain`, + name: `Long Plain`, + type: `Text`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `longMarkdown`, + name: `Long Markdown`, + type: `Text`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `longLocalized`, + name: `Long Localized`, + type: `Text`, + localized: true, + required: false, + disabled: false, + omitted: false, + }, + ], + }, + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `k8iqpp6u0ior`, + }, + }, + id: `mediaReference`, + type: `ContentType`, + createdAt: `2021-03-01T17:03:21.639Z`, + updatedAt: `2021-05-21T11:11:20.265Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 8, + }, + displayField: `title`, + name: `Media Reference`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `one`, + name: `One`, + type: `Link`, + localized: false, + required: false, + disabled: false, + omitted: false, + linkType: `Asset`, + }, + { + id: `oneLocalized`, + name: `One Localized`, + type: `Link`, + localized: true, + required: false, + disabled: false, + omitted: false, + linkType: `Asset`, + }, + { + id: `many`, + name: `Many`, + type: `Array`, + localized: false, + required: false, + disabled: false, + omitted: false, + items: { + type: `Link`, + validations: [], + linkType: `Asset`, + }, + }, + { + id: `manyLocalized`, + name: `Many Localized`, + type: `Array`, + localized: true, + required: false, + disabled: false, + omitted: false, + items: { + type: `Link`, + validations: [], + linkType: `Asset`, + }, + }, + ], + }, + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `k8iqpp6u0ior`, + }, + }, + id: `boolean`, + type: `ContentType`, + createdAt: `2021-03-01T17:05:40.030Z`, + updatedAt: `2021-05-21T10:32:45.505Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 3, + }, + displayField: `title`, + name: `Boolean`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `boolean`, + name: `Boolean`, + type: `Boolean`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `booleanLocalized`, + name: `Boolean Localized`, + type: `Boolean`, + localized: true, + required: false, + disabled: false, + omitted: false, + }, + ], + }, + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `k8iqpp6u0ior`, + }, + }, + id: `date`, + type: `ContentType`, + createdAt: `2021-03-01T17:07:02.629Z`, + updatedAt: `2021-05-20T18:16:28.584Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 2, + }, + displayField: `title`, + name: `Date`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `date`, + name: `Date`, + type: `Date`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `dateTime`, + name: `Date Time`, + type: `Date`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `dateTimeTimezone`, + name: `Date Time Timezone`, + type: `Date`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `dateLocalized`, + name: `Date Localized`, + type: `Date`, + localized: true, + required: false, + disabled: false, + omitted: false, + }, + ], + }, + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `k8iqpp6u0ior`, + }, + }, + id: `location`, + type: `ContentType`, + createdAt: `2021-03-01T17:09:20.579Z`, + updatedAt: `2021-05-21T10:37:52.205Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 2, + }, + displayField: `title`, + name: `Location`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `location`, + name: `Location`, + type: `Location`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `locationLocalized`, + name: `Location Localized`, + type: `Location`, + localized: true, + required: false, + disabled: false, + omitted: false, + }, + ], + }, + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `k8iqpp6u0ior`, + }, + }, + id: `json`, + type: `ContentType`, + createdAt: `2021-03-01T17:09:56.970Z`, + updatedAt: `2021-05-21T10:36:57.432Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 2, + }, + displayField: `title`, + name: `JSON`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `json`, + name: `JSON`, + type: `Object`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `jsonLocalized`, + name: `JSON Localized`, + type: `Object`, + localized: true, + required: false, + disabled: false, + omitted: false, + }, + ], + }, + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `k8iqpp6u0ior`, + }, + }, + id: `richText`, + type: `ContentType`, + createdAt: `2021-03-01T17:11:01.406Z`, + updatedAt: `2021-11-05T12:56:39.942Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 7, + }, + displayField: `title`, + name: `Rich Text`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `richText`, + name: `Rich Text`, + type: `RichText`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `richTextLocalized`, + name: `Rich Text Localized`, + type: `RichText`, + localized: true, + required: false, + disabled: false, + omitted: false, + }, + { + id: `richTextValidated`, + name: `Rich Text Validated`, + type: `RichText`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + ], + }, + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `k8iqpp6u0ior`, + }, + }, + id: `contentReference`, + type: `ContentType`, + createdAt: `2021-03-02T09:17:08.210Z`, + updatedAt: `2021-05-21T10:36:34.506Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 7, + }, + displayField: `title`, + name: `Content Reference`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `one`, + name: `One`, + type: `Link`, + localized: false, + required: false, + disabled: false, + omitted: false, + linkType: `Entry`, + }, + { + id: `oneLocalized`, + name: `One Localized`, + type: `Link`, + localized: true, + required: false, + disabled: false, + omitted: false, + linkType: `Entry`, + }, + { + id: `many`, + name: `Many`, + type: `Array`, + localized: false, + required: false, + disabled: false, + omitted: false, + items: { + type: `Link`, + validations: [ + { + linkContentType: [`contentReference`, `number`, `text`], + }, + ], + linkType: `Entry`, + }, + }, + { + id: `manyLocalized`, + name: `Many Localized`, + type: `Array`, + localized: true, + required: false, + disabled: false, + omitted: false, + items: { + type: `Link`, + validations: [], + linkType: `Entry`, + }, + }, + ], + }, + { + sys: { + space: { + sys: { + type: `Link`, + linkType: `Space`, + id: `k8iqpp6u0ior`, + }, + }, + id: `validatedContentReference`, + type: `ContentType`, + createdAt: `2021-05-20T15:29:49.734Z`, + updatedAt: `2021-05-20T15:33:26.620Z`, + environment: { + sys: { + id: `master`, + type: `Link`, + linkType: `Environment`, + }, + }, + revision: 4, + }, + displayField: `title`, + name: `ValidatedContentReference`, + description: ``, + fields: [ + { + id: `title`, + name: `Title`, + type: `Symbol`, + localized: false, + required: false, + disabled: false, + omitted: false, + }, + { + id: `oneItemSingleType`, + name: `One Item: Single Type`, + type: `Link`, + localized: false, + required: false, + disabled: false, + omitted: false, + linkType: `Entry`, + validations: [ + { + linkContentType: [`text`], + }, + ], + }, + { + id: `oneItemManyTypes`, + name: `One Item: Many Types`, + type: `Link`, + localized: false, + required: false, + disabled: false, + omitted: false, + linkType: `Entry`, + validations: [ + { + linkContentType: [`number`, `text`], + }, + ], + }, + { + id: `oneItemAllTypes`, + name: `One Item: All Types`, + type: `Link`, + localized: false, + required: false, + disabled: false, + omitted: false, + linkType: `Entry`, + }, + { + id: `multipleItemsSingleType`, + name: `Multiple Items: Single Type`, + type: `Array`, + localized: false, + required: false, + disabled: false, + omitted: false, + items: { + type: `Link`, + validations: [ + { + linkContentType: [`text`], + }, + ], + linkType: `Entry`, + }, + }, + { + id: `multipleItemsManyTypes`, + name: `Multiple Items: Many Types`, + type: `Array`, + localized: false, + required: false, + disabled: false, + omitted: false, + items: { + type: `Link`, + validations: [ + { + linkContentType: [`number`, `text`], + }, + ], + linkType: `Entry`, + }, + }, + { + id: `multipleItemsAllTypes`, + name: `Multiple Items: All Types`, + type: `Array`, + localized: false, + required: false, + disabled: false, + omitted: false, + items: { + type: `Link`, + validations: [], + linkType: `Entry`, + }, + }, + ], + }, +] diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap new file mode 100644 index 0000000000000..711739fd0aec2 --- /dev/null +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -0,0 +1,843 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`create-schema-customization builds schema based on Contentful Content Model 1`] = ` +Array [ + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "description": Object { + "type": "String!", + }, + "displayField": Object { + "type": "String!", + }, + "id": Object { + "type": "ID!", + }, + "name": Object { + "type": "String!", + }, + }, + "interfaces": Array [ + "Node", + ], + "name": "ContentfulContentType", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "contentType": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "contentType___NODE", + }, + }, + "type": "ContentfulContentType", + }, + "environmentId": Object { + "type": " String!", + }, + "firstPublishedAt": Object { + "type": " Date!", + }, + "id": Object { + "type": " String!", + }, + "locale": Object { + "type": " String!", + }, + "publishedAt": Object { + "type": " Date!", + }, + "publishedVersion": Object { + "type": " Int!", + }, + "spaceId": Object { + "type": " String!", + }, + "type": Object { + "type": " String!", + }, + }, + "interfaces": Array [ + "Node", + ], + "name": "ContentfulSys", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "tags": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "tags___NODE", + }, + }, + "type": "[ContentfulTag]!", + }, + }, + "name": "ContentfulMetadata", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "contentful_id": Object { + "type": "String!", + }, + "id": Object { + "type": "ID!", + }, + "name": Object { + "type": "String!", + }, + }, + "interfaces": Array [ + "Node", + ], + "name": "ContentfulTag", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "localFile": Object { + "extensions": Object { + "link": Object { + "by": "id", + }, + }, + "type": "File", + }, + }, + "name": "ContentfulAssetFields", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "contentType": Object { + "type": "String", + }, + "description": Object { + "type": "String", + }, + "fields": Object { + "type": "ContentfulAssetFields", + }, + "fileName": Object { + "type": "String", + }, + "height": Object { + "type": "Int", + }, + "id": Object { + "type": "ID!", + }, + "size": Object { + "type": "Int", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + "url": Object { + "type": "String", + }, + "width": Object { + "type": "Int", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "Node", + ], + "name": "ContentfulAsset", + }, + ], + Array [ + Object { + "fields": Object { + "block": Object { + "resolve": [Function], + "type": "[ContentfulAsset]!", + }, + "hyperlink": Object { + "resolve": [Function], + "type": "[ContentfulAsset]!", + }, + }, + "name": "ContentfulRichTextAssets", + }, + ], + Array [ + Object { + "fields": Object { + "block": Object { + "resolve": [Function], + "type": "[ContentfulEntry]!", + }, + "hyperlink": Object { + "resolve": [Function], + "type": "[ContentfulEntry]!", + }, + "inline": Object { + "resolve": [Function], + "type": "[ContentfulEntry]!", + }, + }, + "name": "ContentfulRichTextEntries", + }, + ], + Array [ + Object { + "fields": Object { + "assets": Object { + "resolve": [Function], + "type": "ContentfulRichTextAssets", + }, + "entries": Object { + "resolve": [Function], + "type": "ContentfulRichTextEntries", + }, + }, + "name": "ContentfulRichTextLinks", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "json": Object { + "resolve": [Function], + "type": "JSON", + }, + "links": Object { + "resolve": [Function], + "type": "ContentfulRichTextLinks", + }, + }, + "name": "ContentfulRichText", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "lat": Object { + "type": "Float!", + }, + "lon": Object { + "type": "Float!", + }, + }, + "name": "ContentfulLocation", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "raw": "String!", + }, + "interfaces": Array [ + "Node", + ], + "name": "ContentfulText", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "decimal": Object { + "type": "Float", + }, + "decimalLocalized": Object { + "type": "Float", + }, + "id": Object { + "type": "ID!", + }, + "integer": Object { + "type": "Int", + }, + "integerLocalized": Object { + "type": "Int", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "ContentfulEntry", + "Node", + ], + "name": "ContentfulContentTypeNumber", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "id": Object { + "type": "ID!", + }, + "longLocalized": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "longLocalized___NODE", + }, + }, + "type": "ContentfulText", + }, + "longMarkdown": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "longMarkdown___NODE", + }, + }, + "type": "ContentfulText", + }, + "longPlain": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "longPlain___NODE", + }, + }, + "type": "ContentfulText", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "short": Object { + "type": "String", + }, + "shortList": Object { + "type": "[String]", + }, + "shortListLocalized": Object { + "type": "[String]", + }, + "shortLocalized": Object { + "type": "String", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "ContentfulEntry", + "Node", + ], + "name": "ContentfulContentTypeText", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "id": Object { + "type": "ID!", + }, + "many": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "many___NODE", + }, + }, + "type": "[ContentfulAsset]", + }, + "manyLocalized": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "manyLocalized___NODE", + }, + }, + "type": "[ContentfulAsset]", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "one": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "one___NODE", + }, + }, + "type": "ContentfulAsset", + }, + "oneLocalized": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "oneLocalized___NODE", + }, + }, + "type": "ContentfulAsset", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "ContentfulEntry", + "Node", + ], + "name": "ContentfulContentTypeMediaReference", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "boolean": Object { + "type": "Boolean", + }, + "booleanLocalized": Object { + "type": "Boolean", + }, + "id": Object { + "type": "ID!", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "ContentfulEntry", + "Node", + ], + "name": "ContentfulContentTypeBoolean", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "date": Object { + "extensions": Object { + "dateformat": Object {}, + }, + "type": "Date", + }, + "dateLocalized": Object { + "extensions": Object { + "dateformat": Object {}, + }, + "type": "Date", + }, + "dateTime": Object { + "extensions": Object { + "dateformat": Object {}, + }, + "type": "Date", + }, + "dateTimeTimezone": Object { + "extensions": Object { + "dateformat": Object {}, + }, + "type": "Date", + }, + "id": Object { + "type": "ID!", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "ContentfulEntry", + "Node", + ], + "name": "ContentfulContentTypeDate", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "id": Object { + "type": "ID!", + }, + "location": Object { + "type": "ContentfulLocation", + }, + "locationLocalized": Object { + "type": "ContentfulLocation", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "ContentfulEntry", + "Node", + ], + "name": "ContentfulContentTypeLocation", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "id": Object { + "type": "ID!", + }, + "json": Object { + "type": "JSON", + }, + "jsonLocalized": Object { + "type": "JSON", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "ContentfulEntry", + "Node", + ], + "name": "ContentfulContentTypeJson", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "id": Object { + "type": "ID!", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "richText": Object { + "type": "ContentfulRichText", + }, + "richTextLocalized": Object { + "type": "ContentfulRichText", + }, + "richTextValidated": Object { + "type": "ContentfulRichText", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "ContentfulEntry", + "Node", + ], + "name": "ContentfulContentTypeRichText", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "id": Object { + "type": "ID!", + }, + "many": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "many___NODE", + }, + }, + "type": "[UnionContentfulContentReferenceNumberText]", + }, + "manyLocalized": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "manyLocalized___NODE", + }, + }, + "type": "[ContentfulEntry]", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "one": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "one___NODE", + }, + }, + "type": "ContentfulEntry", + }, + "oneLocalized": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "oneLocalized___NODE", + }, + }, + "type": "ContentfulEntry", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "ContentfulEntry", + "Node", + ], + "name": "ContentfulContentTypeContentReference", + }, + ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "id": Object { + "type": "ID!", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "multipleItemsAllTypes": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "multipleItemsAllTypes___NODE", + }, + }, + "type": "[ContentfulEntry]", + }, + "multipleItemsManyTypes": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "multipleItemsManyTypes___NODE", + }, + }, + "type": "[UnionContentfulNumberText]", + }, + "multipleItemsSingleType": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "multipleItemsSingleType___NODE", + }, + }, + "type": "[ContentfulContentTypeText]", + }, + "oneItemAllTypes": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "oneItemAllTypes___NODE", + }, + }, + "type": "ContentfulEntry", + }, + "oneItemManyTypes": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "oneItemManyTypes___NODE", + }, + }, + "type": "UnionContentfulNumberText", + }, + "oneItemSingleType": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "oneItemSingleType___NODE", + }, + }, + "type": "ContentfulContentTypeText", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + "title": Object { + "type": "String", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "ContentfulEntry", + "Node", + ], + "name": "ContentfulContentTypeValidatedContentReference", + }, + ], +] +`; + +exports[`create-schema-customization builds schema based on Contentful Content Model 2`] = ` +Array [ + Array [ + Object { + "fields": Object { + "id": Object { + "type": "ID!", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + }, + "interfaces": Array [ + "Node", + ], + "name": "ContentfulReference", + }, + ], + Array [ + Object { + "fields": Object { + "id": Object { + "type": "ID!", + }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, + "sys": Object { + "type": "ContentfulSys!", + }, + }, + "interfaces": Array [ + "ContentfulReference", + "Node", + ], + "name": "ContentfulEntry", + }, + ], +] +`; + +exports[`create-schema-customization builds schema based on Contentful Content Model 3`] = ` +Array [ + Array [ + Object { + "name": "UnionContentfulContentReferenceNumberText", + "types": Array [ + "ContentfulContentTypeContentReference", + "ContentfulContentTypeNumber", + "ContentfulContentTypeText", + ], + }, + ], + Array [ + Object { + "name": "UnionContentfulNumberText", + "types": Array [ + "ContentfulContentTypeNumber", + "ContentfulContentTypeText", + ], + }, + ], +] +`; diff --git a/packages/gatsby-source-contentful/src/__tests__/create-schema-customization.js b/packages/gatsby-source-contentful/src/__tests__/create-schema-customization.js new file mode 100644 index 0000000000000..9ae3027eddacc --- /dev/null +++ b/packages/gatsby-source-contentful/src/__tests__/create-schema-customization.js @@ -0,0 +1,46 @@ +// @ts-check +import { createSchemaCustomization } from "../create-schema-customization" +import { contentTypes } from "../__fixtures__/content-types" + +const createMockCache = () => { + return { + get: jest.fn(key => contentTypes), + } +} + +describe(`create-schema-customization`, () => { + const actions = { createTypes: jest.fn() } + const schema = { + buildObjectType: jest.fn(), + buildInterfaceType: jest.fn(), + buildUnionType: jest.fn(), + } + const cache = createMockCache() + const reporter = { + info: jest.fn(), + verbose: jest.fn(), + panic: jest.fn(), + activityTimer: () => { + return { start: jest.fn(), end: jest.fn() } + }, + } + + beforeEach(() => { + cache.get.mockClear() + process.env.GATSBY_WORKER_ID = `mocked` + }) + + it(`builds schema based on Contentful Content Model`, async () => { + await createSchemaCustomization( + { schema, actions, reporter, cache }, + { spaceId: `testSpaceId` } + ) + + expect(schema.buildObjectType).toHaveBeenCalled() + expect(schema.buildObjectType.mock.calls).toMatchSnapshot() + expect(schema.buildInterfaceType).toHaveBeenCalled() + expect(schema.buildInterfaceType.mock.calls).toMatchSnapshot() + expect(schema.buildUnionType).toHaveBeenCalled() + expect(schema.buildUnionType.mock.calls).toMatchSnapshot() + }) +}) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 8a87d40e2c8a3..ba68bec289603 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -77,7 +77,64 @@ const ContentfulDataTypes = new Map([ ], ]) -const getLinkFieldType = (linkType, field) => { +const unionsNameSet = new Set() + +const getLinkFieldType = (linkType, field, schema, createTypes) => { + // Check for validations + const validations = + field.type === `Array` ? field.items?.validations : field?.validations + + if (validations) { + // We only handle content type validations + const linkContentTypeValidation = validations.find( + ({ linkContentType }) => !!linkContentType + ) + if (linkContentTypeValidation) { + const { linkContentType } = linkContentTypeValidation + const contentTypes = Array.isArray(linkContentType) + ? linkContentType + : [linkContentType] + + // Full type names for union members, shorter variant for the union type name + const translatedTypeNames = contentTypes.map(typeName => + makeTypeName(typeName) + ) + const shortTypeNames = contentTypes.map(typeName => + makeTypeName(typeName, ``) + ) + + // Single content type + if (translatedTypeNames.length === 1) { + return { + type: translatedTypeNames.shift(), + extensions: { + link: { by: `id`, from: `${field.id}___NODE` }, + }, + } + } + + // Multiple content types + const unionName = [`UnionContentful`, ...shortTypeNames].join(``) + + if (!unionsNameSet.has(unionName)) { + unionsNameSet.add(unionName) + createTypes( + schema.buildUnionType({ + name: unionName, + types: translatedTypeNames, + }) + ) + } + + return { + type: unionName, + extensions: { + link: { by: `id`, from: `${field.id}___NODE` }, + }, + } + } + } + return { type: `Contentful${linkType}`, extensions: { @@ -86,19 +143,19 @@ const getLinkFieldType = (linkType, field) => { } } -const translateFieldType = field => { +const translateFieldType = (field, schema, createTypes) => { let fieldType if (field.type === `Array`) { // Arrays of Contentful Links or primitive types const fieldData = field.items.type === `Link` - ? getLinkFieldType(field.items.linkType, field) - : translateFieldType(field.items) + ? getLinkFieldType(field.items.linkType, field, schema, createTypes) + : translateFieldType(field.items, schema, createTypes) fieldType = { ...fieldData, type: `[${fieldData.type}]` } } else if (field.type === `Link`) { // Contentful Link (reference) field types - fieldType = getLinkFieldType(field.linkType, field) + fieldType = getLinkFieldType(field.linkType, field, schema, createTypes) } else { // Primitive field types fieldType = ContentfulDataTypes.get(field.type)(field) @@ -408,7 +465,7 @@ export function generateSchema({ if (field.disabled || field.omitted) { return } - fields[field.id] = translateFieldType(field) + fields[field.id] = translateFieldType(field, schema, createTypes) }) const type = pluginConfig.get(`useNameForId`) diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index b6ed9bfe85708..5ca5e5c754461 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -5,8 +5,7 @@ import { lt, prerelease } from "semver" import { restrictedNodeFields, conflictFieldPrefix } from "./config" -const typePrefix = `ContentfulContentType` -export const makeTypeName = type => +export const makeTypeName = (type, typePrefix = `ContentfulContentType`) => _.upperFirst(_.camelCase(`${typePrefix} ${type}`)) const GATSBY_VERSION_MANIFEST_V2 = `4.3.0` From 9cae6f8f468fb3b64bd686722ee6e897c05f50f5 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Fri, 14 Jan 2022 16:16:33 +0100 Subject: [PATCH 031/149] style: rename ContentfulReference interface to ContentfulEntity --- e2e-tests/contentful/schema.gql | 145 ++++++++++++++---- .../create-schema-customization.js.snap | 26 ++-- .../src/generate-schema.js | 9 +- 3 files changed, 130 insertions(+), 50 deletions(-) diff --git a/e2e-tests/contentful/schema.gql b/e2e-tests/contentful/schema.gql index 86b7511083dd6..7118ffb9ac47c 100644 --- a/e2e-tests/contentful/schema.gql +++ b/e2e-tests/contentful/schema.gql @@ -120,7 +120,7 @@ type SiteBuildMetadata implements Node @dontInfer { buildTime: Date @dateformat } -interface ContentfulReference implements Node { +interface ContentfulEntity implements Node { id: ID! sys: ContentfulSys! } @@ -142,7 +142,7 @@ type ContentfulContentType implements Node @dontInfer { description: String! } -interface ContentfulEntry implements ContentfulReference & Node { +interface ContentfulEntry implements ContentfulEntity & Node { id: ID! sys: ContentfulSys! metadata: ContentfulMetadata! @@ -161,7 +161,7 @@ type ContentfulAssetFields @dontInfer { localFile: File @link(by: "id") } -type ContentfulAsset implements ContentfulReference & Node @dontInfer { +type ContentfulAsset implements ContentfulEntity & Node @dontInfer { sys: ContentfulSys! title: String description: String @@ -204,7 +204,8 @@ type ContentfulText implements Node @dontInfer { raw: String! } -type ContentfulContentTypeNumber implements ContentfulReference & ContentfulEntry & Node @dontInfer { +type ContentfulContentTypeNumber implements ContentfulEntity & ContentfulEntry & Node + @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String @@ -214,7 +215,8 @@ type ContentfulContentTypeNumber implements ContentfulReference & ContentfulEntr decimalLocalized: Float } -type ContentfulContentTypeText implements ContentfulReference & ContentfulEntry & Node @dontInfer { +type ContentfulContentTypeText implements ContentfulEntity & ContentfulEntry & Node + @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String @@ -227,7 +229,8 @@ type ContentfulContentTypeText implements ContentfulReference & ContentfulEntry longLocalized: ContentfulText @link(by: "id", from: "longLocalized___NODE") } -type ContentfulContentTypeMediaReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { +type ContentfulContentTypeMediaReference implements ContentfulEntity & ContentfulEntry & Node + @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String @@ -237,7 +240,8 @@ type ContentfulContentTypeMediaReference implements ContentfulReference & Conten manyLocalized: [ContentfulAsset] @link(by: "id", from: "manyLocalized___NODE") } -type ContentfulContentTypeBoolean implements ContentfulReference & ContentfulEntry & Node @dontInfer { +type ContentfulContentTypeBoolean implements ContentfulEntity & ContentfulEntry & Node + @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String @@ -245,7 +249,8 @@ type ContentfulContentTypeBoolean implements ContentfulReference & ContentfulEnt booleanLocalized: Boolean } -type ContentfulContentTypeDate implements ContentfulReference & ContentfulEntry & Node @dontInfer { +type ContentfulContentTypeDate implements ContentfulEntity & ContentfulEntry & Node + @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String @@ -255,7 +260,8 @@ type ContentfulContentTypeDate implements ContentfulReference & ContentfulEntry dateLocalized: Date @dateformat } -type ContentfulContentTypeLocation implements ContentfulReference & ContentfulEntry & Node @dontInfer { +type ContentfulContentTypeLocation implements ContentfulEntity & ContentfulEntry & Node + @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String @@ -263,7 +269,8 @@ type ContentfulContentTypeLocation implements ContentfulReference & ContentfulEn locationLocalized: ContentfulLocation } -type ContentfulContentTypeJson implements ContentfulReference & ContentfulEntry & Node @dontInfer { +type ContentfulContentTypeJson implements ContentfulEntity & ContentfulEntry & Node + @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String @@ -271,7 +278,8 @@ type ContentfulContentTypeJson implements ContentfulReference & ContentfulEntry jsonLocalized: JSON } -type ContentfulContentTypeRichText implements ContentfulReference & ContentfulEntry & Node @dontInfer { +type ContentfulContentTypeRichText implements ContentfulEntity & ContentfulEntry & Node + @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String @@ -280,30 +288,45 @@ type ContentfulContentTypeRichText implements ContentfulReference & ContentfulEn richTextValidated: ContentfulRichText } -type ContentfulContentTypeContentReference implements ContentfulReference & ContentfulEntry & Node @isPlaceholder @dontInfer { +type ContentfulContentTypeContentReference implements ContentfulEntity & ContentfulEntry & Node + @isPlaceholder + @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String one: ContentfulEntry @link(by: "id", from: "one___NODE") oneLocalized: ContentfulEntry @link(by: "id", from: "oneLocalized___NODE") - many: [UnionContentfulContentReferenceNumberText] @link(by: "id", from: "many___NODE") + many: [UnionContentfulContentReferenceNumberText] + @link(by: "id", from: "many___NODE") manyLocalized: [ContentfulEntry] @link(by: "id", from: "manyLocalized___NODE") } -union UnionContentfulContentReferenceNumberText = ContentfulContentTypeContentReference | ContentfulContentTypeNumber | ContentfulContentTypeText +union UnionContentfulContentReferenceNumberText = + ContentfulContentTypeContentReference + | ContentfulContentTypeNumber + | ContentfulContentTypeText -union UnionContentfulNumberText = ContentfulContentTypeNumber | ContentfulContentTypeText +union UnionContentfulNumberText = + ContentfulContentTypeNumber + | ContentfulContentTypeText -type ContentfulContentTypeValidatedContentReference implements ContentfulReference & ContentfulEntry & Node @dontInfer { +type ContentfulContentTypeValidatedContentReference implements ContentfulEntity & ContentfulEntry & Node + @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String - oneItemSingleType: ContentfulContentTypeText @link(by: "id", from: "oneItemSingleType___NODE") - oneItemManyTypes: UnionContentfulNumberText @link(by: "id", from: "oneItemManyTypes___NODE") - oneItemAllTypes: ContentfulEntry @link(by: "id", from: "oneItemAllTypes___NODE") - multipleItemsSingleType: [ContentfulContentTypeText] @link(by: "id", from: "multipleItemsSingleType___NODE") - multipleItemsManyTypes: [UnionContentfulNumberText] @link(by: "id", from: "multipleItemsManyTypes___NODE") - multipleItemsAllTypes: [ContentfulEntry] @link(by: "id", from: "multipleItemsAllTypes___NODE") + oneItemSingleType: ContentfulContentTypeText + @link(by: "id", from: "oneItemSingleType___NODE") + oneItemManyTypes: UnionContentfulNumberText + @link(by: "id", from: "oneItemManyTypes___NODE") + oneItemAllTypes: ContentfulEntry + @link(by: "id", from: "oneItemAllTypes___NODE") + multipleItemsSingleType: [ContentfulContentTypeText] + @link(by: "id", from: "multipleItemsSingleType___NODE") + multipleItemsManyTypes: [UnionContentfulNumberText] + @link(by: "id", from: "multipleItemsManyTypes___NODE") + multipleItemsAllTypes: [ContentfulEntry] + @link(by: "id", from: "multipleItemsAllTypes___NODE") } type MarkdownHeading { @@ -333,7 +356,13 @@ type MarkdownWordCount { words: Int } -type MarkdownRemark implements Node @childOf(mimeTypes: ["text/markdown", "text/x-markdown"], types: ["ContentfulText"]) @derivedTypes @dontInfer { +type MarkdownRemark implements Node + @childOf( + mimeTypes: ["text/markdown", "text/x-markdown"] + types: ["ContentfulText"] + ) + @derivedTypes + @dontInfer { frontmatter: MarkdownRemarkFrontmatter excerpt: String rawMarkdownBody: String @@ -443,7 +472,9 @@ enum ImagePlaceholder { } input BlurredOptions { - """Width of the generated low-res preview. Default is 20px""" + """ + Width of the generated low-res preview. Default is 20px + """ width: Int """ @@ -498,7 +529,27 @@ type ImageSharpResize { } type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { - fixed(width: Int, height: Int, base64Width: Int, jpegProgressive: Boolean = true, pngCompressionSpeed: Int = 4, grayscale: Boolean = false, duotone: DuotoneGradient, traceSVG: Potrace, quality: Int, jpegQuality: Int, pngQuality: Int, webpQuality: Int, toFormat: ImageFormat = AUTO, toFormatBase64: ImageFormat = AUTO, cropFocus: ImageCropFocus = ATTENTION, fit: ImageFit = COVER, background: String = "rgba(0,0,0,1)", rotate: Int = 0, trim: Float = 0): ImageSharpFixed + fixed( + width: Int + height: Int + base64Width: Int + jpegProgressive: Boolean = true + pngCompressionSpeed: Int = 4 + grayscale: Boolean = false + duotone: DuotoneGradient + traceSVG: Potrace + quality: Int + jpegQuality: Int + pngQuality: Int + webpQuality: Int + toFormat: ImageFormat = AUTO + toFormatBase64: ImageFormat = AUTO + cropFocus: ImageCropFocus = ATTENTION + fit: ImageFit = COVER + background: String = "rgba(0,0,0,1)" + rotate: Int = 0 + trim: Float = 0 + ): ImageSharpFixed fluid( maxWidth: Int maxHeight: Int @@ -616,19 +667,29 @@ type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { """ sizes: String - """The default quality. This is overridden by any format-specific options""" + """ + The default quality. This is overridden by any format-specific options + """ quality: Int - """Options to pass to sharp when generating JPG images.""" + """ + Options to pass to sharp when generating JPG images. + """ jpgOptions: JPGOptions - """Options to pass to sharp when generating PNG images.""" + """ + Options to pass to sharp when generating PNG images. + """ pngOptions: PNGOptions - """Options to pass to sharp when generating WebP images.""" + """ + Options to pass to sharp when generating WebP images. + """ webpOptions: WebPOptions - """Options to pass to sharp when generating AVIF images.""" + """ + Options to pass to sharp when generating AVIF images. + """ avifOptions: AVIFOptions """ @@ -643,7 +704,27 @@ type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { backgroundColor: String ): JSON! original: ImageSharpOriginal - resize(width: Int, height: Int, quality: Int, jpegQuality: Int, pngQuality: Int, webpQuality: Int, jpegProgressive: Boolean = true, pngCompressionLevel: Int = 9, pngCompressionSpeed: Int = 4, grayscale: Boolean = false, duotone: DuotoneGradient, base64: Boolean = false, traceSVG: Potrace, toFormat: ImageFormat = AUTO, cropFocus: ImageCropFocus = ATTENTION, fit: ImageFit = COVER, background: String = "rgba(0,0,0,1)", rotate: Int = 0, trim: Float = 0): ImageSharpResize + resize( + width: Int + height: Int + quality: Int + jpegQuality: Int + pngQuality: Int + webpQuality: Int + jpegProgressive: Boolean = true + pngCompressionLevel: Int = 9 + pngCompressionSpeed: Int = 4 + grayscale: Boolean = false + duotone: DuotoneGradient + base64: Boolean = false + traceSVG: Potrace + toFormat: ImageFormat = AUTO + cropFocus: ImageCropFocus = ATTENTION + fit: ImageFit = COVER + background: String = "rgba(0,0,0,1)" + rotate: Int = 0 + trim: Float = 0 + ): ImageSharpResize } enum GatsbyImageFormat { @@ -684,4 +765,4 @@ type ContentfulContentTypeContentTypeSys { firstPublishedAt: Date @dateformat publishedAt: Date @dateformat publishedVersion: Int -} \ No newline at end of file +} diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index 711739fd0aec2..d735907275681 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -173,7 +173,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "Node", ], "name": "ContentfulAsset", @@ -308,7 +308,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "ContentfulEntry", "Node", ], @@ -374,7 +374,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "ContentfulEntry", "Node", ], @@ -437,7 +437,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "ContentfulEntry", "Node", ], @@ -470,7 +470,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "ContentfulEntry", "Node", ], @@ -521,7 +521,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "ContentfulEntry", "Node", ], @@ -554,7 +554,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "ContentfulEntry", "Node", ], @@ -587,7 +587,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "ContentfulEntry", "Node", ], @@ -623,7 +623,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "ContentfulEntry", "Node", ], @@ -686,7 +686,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "ContentfulEntry", "Node", ], @@ -767,7 +767,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "ContentfulEntry", "Node", ], @@ -792,7 +792,7 @@ Array [ "interfaces": Array [ "Node", ], - "name": "ContentfulReference", + "name": "ContentfulEntity", }, ], Array [ @@ -809,7 +809,7 @@ Array [ }, }, "interfaces": Array [ - "ContentfulReference", + "ContentfulEntity", "Node", ], "name": "ContentfulEntry", diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index ba68bec289603..08c36ef2ecf5a 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -179,7 +179,7 @@ export function generateSchema({ // Generic Types createTypes( schema.buildInterfaceType({ - name: `ContentfulReference`, + name: `ContentfulEntity`, fields: { id: { type: `ID!` }, sys: { type: `ContentfulSys!` }, @@ -196,7 +196,7 @@ export function generateSchema({ sys: { type: `ContentfulSys!` }, metadata: { type: `ContentfulMetadata!` }, }, - interfaces: [`ContentfulReference`, `Node`], + interfaces: [`ContentfulEntity`, `Node`], }) ) @@ -321,9 +321,8 @@ export function generateSchema({ size: { type: `Int` }, width: { type: `Int` }, height: { type: `Int` }, - metadata: { type: `ContentfulMetadata!` }, }, - interfaces: [`ContentfulReference`, `Node`], + interfaces: [`ContentfulEntity`, `Node`], }), { schema, @@ -481,7 +480,7 @@ export function generateSchema({ metadata: { type: `ContentfulMetadata!` }, ...fields, }, - interfaces: [`ContentfulReference`, `ContentfulEntry`, `Node`], + interfaces: [`ContentfulEntity`, `ContentfulEntry`, `Node`], extensions: { dontInfer: {} }, }) ) From 69e2688be38cf868fca30c72221b55ac46fe25a3 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Thu, 20 Jan 2022 15:50:04 +0100 Subject: [PATCH 032/149] fix: readd tag support for assets --- e2e-tests/contentful/src/pages/tags.js | 12 +++++------- .../src/generate-schema.js | 5 ++++- .../gatsby-source-contentful/src/normalize.js | 17 +++++------------ 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/e2e-tests/contentful/src/pages/tags.js b/e2e-tests/contentful/src/pages/tags.js index 0e0a430e1b6f3..7af26c1113330 100644 --- a/e2e-tests/contentful/src/pages/tags.js +++ b/e2e-tests/contentful/src/pages/tags.js @@ -55,13 +55,13 @@ const TagsPage = ({ data }) => { data-cy-assets style={{ display: "flex", justifyContent: "space-between" }} > - {assets.map(({ title, file, metadata }) => { + {assets.map(({ title, url, metadata }) => { const slug = slugify(title, { strict: true, lower: true }) return (

{title}

{title} @@ -127,17 +127,15 @@ export const pageQuery = graphql` } } assets: allContentfulAsset( - sort: { fields: contentful_id } + sort: { fields: sys___id } filter: { metadata: { tags: { elemMatch: { contentful_id: { eq: "animal" } } } } - node_locale: { eq: "en-US" } + sys: { locale: { eq: "en-US" } } } ) { nodes { title - file { - url - } + url metadata { tags { name diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 08c36ef2ecf5a..7fa07e8961498 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -183,6 +183,7 @@ export function generateSchema({ fields: { id: { type: `ID!` }, sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, }, interfaces: [`Node`], }) @@ -274,6 +275,8 @@ export function generateSchema({ fields: { contentful_id: { type: `String!` }, id: { type: `ID!` }, + sys: { type: `ContentfulSys` }, + metadata: { type: `ContentfulMetadata!` }, gatsbyImageData: getGatsbyImageFieldConfig( async (...args) => resolveGatsbyImageData(...args, { cache }), { @@ -312,7 +315,6 @@ export function generateSchema({ }, } : {}), - sys: { type: `ContentfulSys` }, title: { type: `String` }, description: { type: `String` }, contentType: { type: `String` }, @@ -323,6 +325,7 @@ export function generateSchema({ height: { type: `Int` }, }, interfaces: [`ContentfulEntity`, `Node`], + extensions: { dontInfer: {} }, }), { schema, diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index 5ca5e5c754461..6d06cedaf4219 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -568,7 +568,6 @@ export const createAssetNodes = ({ defaultLocale, locales, space, - pluginConfig, }) => { const createNodePromises = [] locales.forEach(locale => { @@ -619,24 +618,18 @@ export const createAssetNodes = ({ width: file.details?.image?.width ?? null, height: file.details?.image?.height ?? null, size: file.details?.size ?? null, + metadata: { + tags___NODE: assetItem.metadata.tags.map(tag => + createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) + ), + }, title: assetItem.fields.title ? getField(assetItem.fields.title) : ``, description: assetItem.fields.description ? getField(assetItem.fields.description) : ``, - contentType: file.contentType, - fileName: file.fileName, url: `https:${file.url}`, } - // Link tags - if (pluginConfig.get(`enableTags`)) { - assetNode.metadata = { - tags___NODE: assetItem.metadata.tags.map(tag => - createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) - ), - } - } - // if the node hasn't changed, createNode may return `undefined` instead of a Promise on some versions of Gatsby const maybePromise = createNode(assetNode) From e47612e3704f0334ae4a49ace8a4a8bcefd47d40 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Wed, 2 Feb 2022 14:04:01 +0100 Subject: [PATCH 033/149] fix reference resolving and adjust tests --- .../src/__fixtures__/rich-text-data.js | 2 + .../create-schema-customization.js.snap | 6 + .../__snapshots__/gatsby-node.js.snap | 409 ------------------ .../__tests__/download-contentful-assets.js | 5 +- .../src/__tests__/gatsby-node.js | 33 +- .../src/__tests__/normalize.js | 83 ++-- .../src/generate-schema.js | 11 +- .../gatsby-source-contentful/src/normalize.js | 2 +- .../src/source-nodes.js | 71 ++- 9 files changed, 119 insertions(+), 503 deletions(-) delete mode 100644 packages/gatsby-source-contentful/src/__tests__/__snapshots__/gatsby-node.js.snap diff --git a/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js b/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js index 02ea0d1a342da..98ee4aa277268 100644 --- a/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js +++ b/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js @@ -704,6 +704,7 @@ exports.initialSync = () => { }, }, }, + metadata: { tags: [] }, }, { sys: { @@ -746,6 +747,7 @@ exports.initialSync = () => { }, }, }, + metadata: { tags: [] }, }, ], deletedEntries: [], diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index d735907275681..23204abdcac9b 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -156,6 +156,9 @@ Array [ "id": Object { "type": "ID!", }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, "size": Object { "type": "Int", }, @@ -785,6 +788,9 @@ Array [ "id": Object { "type": "ID!", }, + "metadata": Object { + "type": "ContentfulMetadata!", + }, "sys": Object { "type": "ContentfulSys!", }, 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 deleted file mode 100644 index c8fa86145953f..0000000000000 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/gatsby-node.js.snap +++ /dev/null @@ -1,409 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -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", -} -`; - -exports[`gatsby-node stores rich text as raw with references attached 1`] = ` -Array [ - "ahntqop9oi7x___7oHxo6bs0us9wIkq27qdyK___Entry", - "ahntqop9oi7x___6KpLS2NZyB3KAvDzWf4Ukh___Entry", - "ahntqop9oi7x___4ZQrqcrTunWiuNaavhGYNT___Asset", -] -`; 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 f9a018efb303e..5412ba7461c13 100644 --- a/packages/gatsby-source-contentful/src/__tests__/download-contentful-assets.js +++ b/packages/gatsby-source-contentful/src/__tests__/download-contentful-assets.js @@ -1,9 +1,6 @@ // @ts-check import { downloadContentfulAssets } from "../download-contentful-assets" import { createAssetNodes } from "../normalize" -import { createPluginConfig } from "../plugin-options" - -const pluginConfig = createPluginConfig({}) jest.mock(`gatsby-source-filesystem`, () => { return { @@ -59,6 +56,7 @@ const fixtures = [ environment: mockedContentfulEntity, revision: 123, }, + metadata: { tags: [] }, }, ] @@ -86,7 +84,6 @@ describe(`downloadContentfulAssets`, () => { defaultLocale, locales, space, - pluginConfig, }) )) ) diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index ba430ff2d5aff..68c74bd37cc6b 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -86,21 +86,33 @@ describe(`gatsby-node`, () => { }), touchNode: jest.fn(), } + + const schemaCustomizationTypes = [] const schema = { - buildObjectType: jest.fn(() => { - return { - config: { - interfaces: [], - }, - } + buildObjectType: jest.fn(config => { + schemaCustomizationTypes.push({ + typeOrTypeDef: { config }, + plugin: { name: `gatsby-source-contentful` }, + }) + }), + buildInterfaceType: jest.fn(config => { + schemaCustomizationTypes.push({ + typeOrTypeDef: { config }, + plugin: { name: `gatsby-source-contentful` }, + }) }), - buildInterfaceType: jest.fn(), } + const store = { getState: jest.fn(() => { - return { program: { directory: process.cwd() }, status: {} } + return { + program: { directory: process.cwd() }, + status: {}, + schemaCustomization: { types: schemaCustomizationTypes }, + } }), } + const cache = createMockCache() const getCache = jest.fn(() => cache) const reporter = { @@ -424,6 +436,7 @@ describe(`gatsby-node`, () => { cache.set.mockClear() reporter.info.mockClear() reporter.panic.mockClear() + schemaCustomizationTypes.length = 0 }) let hasImported = false @@ -888,7 +901,7 @@ describe(`gatsby-node`, () => { expect(actions.createNode).toHaveBeenCalledTimes(52) expect(actions.deleteNode).toHaveBeenCalledTimes(2) - expect(actions.touchNode).toHaveBeenCalledTimes(74) + expect(actions.touchNode).toHaveBeenCalledTimes(72) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` Array [ Array [ @@ -974,7 +987,7 @@ describe(`gatsby-node`, () => { expect(actions.createNode).toHaveBeenCalledTimes(54) expect(actions.deleteNode).toHaveBeenCalledTimes(2) - expect(actions.touchNode).toHaveBeenCalledTimes(74) + expect(actions.touchNode).toHaveBeenCalledTimes(72) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` Array [ Array [ diff --git a/packages/gatsby-source-contentful/src/__tests__/normalize.js b/packages/gatsby-source-contentful/src/__tests__/normalize.js index 58318589a3902..fa111c9876907 100644 --- a/packages/gatsby-source-contentful/src/__tests__/normalize.js +++ b/packages/gatsby-source-contentful/src/__tests__/normalize.js @@ -205,35 +205,28 @@ describe(`Process contentful data (by name)`, () => { const nodeTypeCounts = countCreatedNodeTypesFromMock(createNode.mock) - expect(Object.keys(nodeTypeCounts)).toHaveLength(15) - expect(nodeTypeCounts).toEqual( expect.objectContaining({ + ContentfulContentType: contentTypeItems.length, + // Generated child entities + ContentfulText: 38, // 3 Brand Contentful entries - ContentfulBrand: 6, - contentfulBrandCompanyDescriptionTextNode: 6, - contentfulBrandCompanyNameTextNode: 6, + ContentfulContentTypeBrand: 6, // 2 Category Contentful entries - ContentfulCategory: 4, - contentfulCategoryCategoryDescriptionTextNode: 4, - contentfulCategoryTitleTextNode: 4, - ContentfulContentType: contentTypeItems.length, + ContentfulContentTypeCategory: 4, // 1 JSON Test Contentful entry - ContentfulJsonTest: 2, - contentfulJsonTestJsonStringTestJsonNode: 2, - contentfulJsonTestJsonTestJsonNode: 2, + ContentfulContentTypeJsonTest: 2, // 4 Product Contentful entries - ContentfulProduct: 8, - contentfulProductProductDescriptionTextNode: 8, - contentfulProductProductNameTextNode: 8, + ContentfulContentTypeProduct: 8, // 1 Remark Test Contentful entry - ContentfulRemarkTest: 2, - contentfulRemarkTestContentTextNode: 2, + ContentfulContentTypeRemarkTest: 2, }) ) + expect(Object.keys(nodeTypeCounts)).toHaveLength(7) + // Relevant to compare to compare warm and cold situation - expect(createNode.mock.calls.length).toBe(69) // "cold build entries" count + expect(createNode.mock.calls.length).toBe(65) // "cold build entries" count }) it(`creates nodes for each asset`, () => { @@ -248,7 +241,6 @@ describe(`Process contentful data (by name)`, () => { defaultLocale, locales, space, - pluginConfig, }) }) const nodeTypeCounts = countCreatedNodeTypesFromMock(createNode.mock) @@ -318,36 +310,28 @@ describe(`Process existing mutated nodes in warm build`, () => { const nodeTypeCounts = countCreatedNodeTypesFromMock(createNode.mock) - expect(Object.keys(nodeTypeCounts)).toHaveLength(15) - expect(nodeTypeCounts).toEqual( expect.objectContaining({ + ContentfulContentType: contentTypeItems.length, + // Child entities + ContentfulText: 38, // 3 Brand Contentful entries - ContentfulBrand: 6, - contentfulBrandCompanyDescriptionTextNode: 6, - contentfulBrandCompanyNameTextNode: 6, + ContentfulContentTypeBrand: 6, // 2 Category Contentful entries - ContentfulCategory: 4, - contentfulCategoryCategoryDescriptionTextNode: 4, - contentfulCategoryTitleTextNode: 4, - ContentfulContentType: contentTypeItems.length, + ContentfulContentTypeCategory: 4, // 1 JSON Test Contentful entry - ContentfulJsonTest: 2, - contentfulJsonTestJsonStringTestJsonNode: 2, - contentfulJsonTestJsonTestJsonNode: 2, + ContentfulContentTypeJsonTest: 2, // 4 Product Contentful entries - ContentfulProduct: 8, - contentfulProductProductDescriptionTextNode: 8, - contentfulProductProductNameTextNode: 8, + ContentfulContentTypeProduct: 8, // 1 Remark Test Contentful entry - ContentfulRemarkTest: 2, - contentfulRemarkTestContentTextNode: 2, + ContentfulContentTypeRemarkTest: 2, }) ) + expect(Object.keys(nodeTypeCounts)).toHaveLength(7) // Relevant to compare to compare warm and cold situation // This number ought to be the same as the cold build - expect(createNode.mock.calls.length).toBe(69) // "warm build where entry was changed" count + expect(createNode.mock.calls.length).toBe(65) // "warm build where entry was changed" count }) }) @@ -419,32 +403,23 @@ describe(`Process contentful data (by id)`, () => { }) const nodeTypeCounts = countCreatedNodeTypesFromMock(createNode.mock) - expect(Object.keys(nodeTypeCounts)).toHaveLength(15) - expect(nodeTypeCounts).toEqual( expect.objectContaining({ + ContentfulContentType: contentTypeItems.length, // 3 Brand Contentful entries - ContentfulSFzTZbSuM8CoEwygeUYes: 6, - contentfulSFzTZbSuM8CoEwygeUYesCompanyDescriptionTextNode: 6, - contentfulSFzTZbSuM8CoEwygeUYesCompanyNameTextNode: 6, + ContentfulContentTypeSFzTZbSuM8CoEwygeUYes: 6, // 2 Category Contentful entries - Contentful6XwpTaSiiI2Ak2Ww0Oi6Qa: 4, - contentful6XwpTaSiiI2Ak2Ww0Oi6QaCategoryDescriptionTextNode: 4, - contentful6XwpTaSiiI2Ak2Ww0Oi6QaTitleTextNode: 4, - ContentfulContentType: contentTypeItems.length, + ContentfulContentType6XwpTaSiiI2Ak2Ww0Oi6Qa: 4, // 1 JSON Test Contentful entry - ContentfulJsonTest: 2, - contentfulJsonTestJsonStringTestJsonNode: 2, - contentfulJsonTestJsonTestJsonNode: 2, + ContentfulContentTypeJsonTest: 2, // 4 Product Contentful entries - Contentful2PqfXuJwE8QSyKuM0U6W8M: 8, - contentful2PqfXuJwE8QSyKuM0U6W8MProductDescriptionTextNode: 8, - contentful2PqfXuJwE8QSyKuM0U6W8MProductNameTextNode: 8, + ContentfulContentType2PqfXuJwE8QSyKuM0U6W8M: 8, // 1 Remark Test Contentful entry - ContentfulRemarkTest: 2, - contentfulRemarkTestContentTextNode: 2, + ContentfulContentTypeRemarkTest: 2, }) ) + + expect(Object.keys(nodeTypeCounts)).toHaveLength(7) }) }) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 7fa07e8961498..47a5c4c372ba2 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -2,10 +2,7 @@ import { getRichTextEntityLinks } from "@contentful/rich-text-links" import { stripIndent } from "common-tags" import { addRemoteFilePolyfillInterface } from "gatsby-plugin-utils/polyfill-remote-file" -import { - getGatsbyImageFieldConfig, - resolveGatsbyImageData, -} from "./gatsby-plugin-image" +import { resolveGatsbyImageData } from "./gatsby-plugin-image" import { makeTypeName } from "./normalize" import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" @@ -168,7 +165,7 @@ const translateFieldType = (field, schema, createTypes) => { return fieldType } -export function generateSchema({ +export async function generateSchema({ createTypes, schema, pluginConfig, @@ -176,6 +173,10 @@ export function generateSchema({ cache, actions, }) { + const { getGatsbyImageFieldConfig } = await import( + `gatsby-plugin-image/graphql-utils` + ) + // Generic Types createTypes( schema.buildInterfaceType({ diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index 6d06cedaf4219..11e1aa529f8d0 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -311,7 +311,7 @@ export const createNodesForContentType = ({ displayField: contentTypeItem.displayField, description: contentTypeItem.description, internal: { - type: `${makeTypeName(`ContentType`)}`, + type: `ContentfulContentType`, contentDigest: contentTypeItem.sys.updatedAt, }, // https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/common-resource-attributes diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index d8c81e993a70d..9207c65bf8899 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -4,7 +4,7 @@ import _ from "lodash" import { downloadContentfulAssets } from "./download-contentful-assets" import { fetchContent } from "./fetch" -import { generateSchema } from "./generate-schema" + import { buildEntryList, buildForeignReferenceMap, @@ -41,17 +41,11 @@ export async function sourceNodes( getCache, reporter, parentSpan, - schema, }, pluginOptions ) { - const { - createNode, - touchNode, - deleteNode, - unstable_createNodeManifest, - createTypes, - } = actions + const { createNode, touchNode, deleteNode, unstable_createNodeManifest } = + actions const online = await isOnline() getNodes().forEach(node => { @@ -175,16 +169,12 @@ export async function sourceNodes( ) processingActivity.start() - // Generate schemas based on Contentful content model - generateSchema({ createTypes, schema, pluginConfig, contentTypeItems }) - - // Array of all existing Contentful nodes + // Array of all existing Contentful entry and asset nodes const existingNodes = getNodes().filter( n => - n.internal.owner === `gatsby-source-contentful` && - (pluginConfig.get(`enableTags`) - ? n.internal.type !== `ContentfulTag` - : true) + (n.internal.owner === `gatsby-source-contentful` && + n.internal.type.indexOf(`ContentfulContentType`) === 0) || + n.internal.type === `ContentfulAsset` ) // Report existing, new and updated nodes @@ -198,6 +188,7 @@ export async function sourceNodes( deletedEntry: currentSyncData.deletedEntries.length, deletedAsset: currentSyncData.deletedAssets.length, } + existingNodes.forEach(node => nodeCounts[`existing${node.sys.type}`]++) currentSyncData.entries.forEach(entry => entry.sys.revision === 1 ? nodeCounts.newEntry++ : nodeCounts.updatedEntry++ @@ -253,8 +244,51 @@ export async function sourceNodes( newOrUpdatedEntries.add(generateReferenceId(entry)) }) }) + // const state = store.getState() + // console.log( + // { schema, keys: Object.keys(schema) }, + // state + // ) + + // const typeMap = await schema.getTypeMap() + + // console.log({ typeMap }) + + // const contentfulTypeDefinitions = new Map() + // store + // .getState() + // .schemaCustomization.types.filter( + // ({ plugin }) => plugin.name === `gatsby-source-contentful` + // ) + // .forEach(({ typeOrTypeDef }) => { + // contentfulTypeDefinitions.set( + // typeOrTypeDef.config.name, + // typeOrTypeDef.config + // ) + // // console.log(typeOrTypeDef.config.fields) + // }) + + // console.log(contentfulTypeDefinitions) const { deletedEntries, deletedAssets } = currentSyncData + + const allDeletedNodes = [...deletedEntries, ...deletedAssets] + const deletedNodeIds = [] + + locales.forEach(locale => { + allDeletedNodes.forEach(n => { + deletedNodeIds.push( + makeId({ + spaceId: n.sys.space.sys.id, + id: n.sys.id, + type: n.sys.type, + currentLocale: locale.code, + defaultLocale, + }) + ) + }) + }) + const deletedEntryGatsbyReferenceIds = new Set() function deleteContentfulNode(node) { @@ -280,8 +314,6 @@ export async function sourceNodes( .filter(node => node) localizedNodes.forEach(node => { - // touchNode first, to populate typeOwners & avoid erroring - touchNode(node) deleteNode(node) }) } @@ -483,7 +515,6 @@ export async function sourceNodes( defaultLocale, locales, space, - pluginConfig, }) )) ) From dee4ae2ea9af22b4a4a47d392b712a8e369ca78c Mon Sep 17 00:00:00 2001 From: axe312ger Date: Wed, 9 Mar 2022 15:31:32 +0100 Subject: [PATCH 034/149] fix merge issues and make unit tests pass --- .../create-schema-customization.js.snap | 113 ++++++++++++++---- .../__tests__/create-schema-customization.js | 6 +- .../src/__tests__/gatsby-node.js | 3 +- .../src/create-schema-customization.js | 2 +- .../src/gatsby-node.js | 1 - .../src/generate-schema.js | 9 +- 6 files changed, 106 insertions(+), 28 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index 23204abdcac9b..6a64eb82b4a98 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -114,24 +114,6 @@ Array [ "name": "ContentfulTag", }, ], - Array [ - Object { - "extensions": Object { - "dontInfer": Object {}, - }, - "fields": Object { - "localFile": Object { - "extensions": Object { - "link": Object { - "by": "id", - }, - }, - "type": "File", - }, - }, - "name": "ContentfulAssetFields", - }, - ], Array [ Object { "extensions": Object { @@ -141,15 +123,103 @@ Array [ "contentType": Object { "type": "String", }, + "contentful_id": Object { + "type": "String!", + }, "description": Object { "type": "String", }, - "fields": Object { - "type": "ContentfulAssetFields", - }, "fileName": Object { "type": "String", }, + "gatsbyImageData": Object { + "args": Object { + "aspectRatio": Object { + "description": "If set along with width or height, this will set the value of the other dimension to match the provided aspect ratio, cropping the image if needed. +If neither width or height is provided, height will be set based on the intrinsic width of the source image.", + "type": "Float", + }, + "backgroundColor": Object { + "description": "Background color applied to the wrapper, or when \\"letterboxing\\" an image to another aspect ratio.", + "type": "String", + }, + "breakpoints": Object { + "description": "Specifies the image widths to generate. You should rarely need to change this. For FIXED and CONSTRAINED images it is better to allow these to be determined automatically, +based on the image size. For FULL_WIDTH images this can be used to override the default, which is [750, 1080, 1366, 1920]. +It will never generate any images larger than the source.", + "type": "[Int]", + }, + "cornerRadius": Object { + "defaultValue": 0, + "description": "Desired corner radius in pixels. Results in an image with rounded corners. +Pass \`-1\` for a full circle/ellipse.", + "type": "Int", + }, + "cropFocus": Object { + "type": "ContentfulImageCropFocus", + }, + "formats": Object { + "defaultValue": Array [ + "", + "webp", + ], + "description": "The image formats to generate. Valid values are AUTO (meaning the same format as the source image), JPG, PNG, WEBP and AVIF. +The default value is [AUTO, WEBP], and you should rarely need to change this. Take care if you specify JPG or PNG when you do +not know the formats of the source images, as this could lead to unwanted results such as converting JPEGs to PNGs. Specifying +both PNG and JPG is not supported and will be ignored.", + "type": "[GatsbyImageFormat]", + }, + "height": Object { + "description": "If set, the height of the generated image. If omitted, it is calculated from the supplied width, matching the aspect ratio of the source image.", + "type": "Int", + }, + "jpegProgressive": Object { + "defaultValue": true, + "type": "Boolean", + }, + "layout": Object { + "description": "The layout for the image. +FIXED: A static image sized, that does not resize according to the screen width +FULL_WIDTH: The image resizes to fit its container. Pass a \\"sizes\\" option if it isn't going to be the full width of the screen. +CONSTRAINED: Resizes to fit its container, up to a maximum width, at which point it will remain fixed in size.", + "type": "GatsbyImageLayout", + }, + "outputPixelDensities": Object { + "description": "A list of image pixel densities to generate for FIXED and CONSTRAINED images. You should rarely need to change this. It will never generate images larger than the source, and will always include a 1x image. +Default is [ 1, 2 ] for fixed images, meaning 1x, 2x, 3x, and [0.25, 0.5, 1, 2] for fluid. In this case, an image with a fluid layout and width = 400 would generate images at 100, 200, 400 and 800px wide.", + "type": "[Float]", + }, + "placeholder": Object { + "description": "Format of generated placeholder image, displayed while the main image loads. +BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) +DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. +TRACED_SVG: a low-resolution traced SVG of the image. +NONE: no placeholder. Set the argument \\"backgroundColor\\" to use a fixed background color.", + "type": "GatsbyImagePlaceholder", + }, + "quality": Object { + "defaultValue": 50, + "type": "Int", + }, + "resizingBehavior": Object { + "type": "ImageResizingBehavior", + }, + "sizes": Object { + "description": "The \\"sizes\\" property, passed to the img tag. This describes the display size of the image. +This does not affect the generated images, but is used by the browser to decide which images to download. You can leave this blank for fixed images, or if the responsive image +container will be the full width of the screen. In these cases we will generate an appropriate value.", + "type": "String", + }, + "width": Object { + "description": "The display width of the generated image for layout = FIXED, and the display width of the largest image for layout = CONSTRAINED. +The actual largest image resolution will be this value multiplied by the largest value in outputPixelDensities +Ignored if layout = FLUID.", + "type": "Int", + }, + }, + "resolve": [Function], + "type": "JSON!", + }, "height": Object { "type": "Int", }, @@ -178,6 +248,7 @@ Array [ "interfaces": Array [ "ContentfulEntity", "Node", + "RemoteFile", ], "name": "ContentfulAsset", }, diff --git a/packages/gatsby-source-contentful/src/__tests__/create-schema-customization.js b/packages/gatsby-source-contentful/src/__tests__/create-schema-customization.js index 9ae3027eddacc..1473c1f84c077 100644 --- a/packages/gatsby-source-contentful/src/__tests__/create-schema-customization.js +++ b/packages/gatsby-source-contentful/src/__tests__/create-schema-customization.js @@ -11,7 +11,11 @@ const createMockCache = () => { describe(`create-schema-customization`, () => { const actions = { createTypes: jest.fn() } const schema = { - buildObjectType: jest.fn(), + buildObjectType: jest.fn(config => { + return { + config, + } + }), buildInterfaceType: jest.fn(), buildUnionType: jest.fn(), } diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 68c74bd37cc6b..c78a9a13e77fd 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -94,6 +94,7 @@ describe(`gatsby-node`, () => { typeOrTypeDef: { config }, plugin: { name: `gatsby-source-contentful` }, }) + return { config } }), buildInterfaceType: jest.fn(config => { schemaCustomizationTypes.push({ @@ -389,7 +390,7 @@ describe(`gatsby-node`, () => { ) || ``, contentType: file.contentType, fileName: file.fileName, - url: file.url, + url: `https:` + file.url, size: file.details.size, width: file.details?.image?.width || null, height: file.details?.image?.height || null, diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.js b/packages/gatsby-source-contentful/src/create-schema-customization.js index 1a636469ed118..7764aab499cdc 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.js +++ b/packages/gatsby-source-contentful/src/create-schema-customization.js @@ -62,7 +62,7 @@ export async function createSchemaCustomization( } // Generate schemas based on Contentful content model - generateSchema({ + return generateSchema({ createTypes, schema, pluginConfig, diff --git a/packages/gatsby-source-contentful/src/gatsby-node.js b/packages/gatsby-source-contentful/src/gatsby-node.js index 8dc140b377c0c..95c5610d815d8 100644 --- a/packages/gatsby-source-contentful/src/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/gatsby-node.js @@ -3,7 +3,6 @@ import _ from "lodash" import origFetch from "node-fetch" import fetchRetry from "@vercel/fetch-retry" import { polyfillImageServiceDevRoutes } from "gatsby-plugin-utils/polyfill-remote-file" -export { setFieldsOnGraphQLNodeType } from "./extend-node-type" import { CODES } from "./report" import { maskText } from "./plugin-options" diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 47a5c4c372ba2..0b7d32d917230 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -268,15 +268,19 @@ export async function generateSchema({ }) ) + const { getGatsbyImageFieldConfig } = await import( + `gatsby-plugin-image/graphql-utils` + ) + // Assets createTypes( - ...addRemoteFilePolyfillInterface( + addRemoteFilePolyfillInterface( schema.buildObjectType({ name: `ContentfulAsset`, fields: { contentful_id: { type: `String!` }, id: { type: `ID!` }, - sys: { type: `ContentfulSys` }, + sys: { type: `ContentfulSys!` }, metadata: { type: `ContentfulMetadata!` }, gatsbyImageData: getGatsbyImageFieldConfig( async (...args) => resolveGatsbyImageData(...args, { cache }), @@ -300,7 +304,6 @@ export async function generateSchema({ }, quality: { type: `Int`, - defaultValue: 50, }, } ), From a4fba1837bb0e999453fcf5bea3f15278284428c Mon Sep 17 00:00:00 2001 From: axe312ger Date: Fri, 11 Mar 2022 10:29:06 +0100 Subject: [PATCH 035/149] cleanup --- .../src/generate-schema.js | 7 +++--- .../src/source-nodes.js | 25 ------------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index 0b7d32d917230..e80c1e1c0ab6c 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -158,9 +158,10 @@ const translateFieldType = (field, schema, createTypes) => { fieldType = ContentfulDataTypes.get(field.type)(field) } - if (field.required) { - fieldType.type = `${fieldType.type}!` - } + // @todo what do we do when preview is enabled? Emptry required fields are valid for Contentfuls CP-API + // if (field.required) { + // fieldType.type = `${fieldType.type}!` + // } return fieldType } diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index 9207c65bf8899..6ff3fa6fe0799 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -244,31 +244,6 @@ export async function sourceNodes( newOrUpdatedEntries.add(generateReferenceId(entry)) }) }) - // const state = store.getState() - // console.log( - // { schema, keys: Object.keys(schema) }, - // state - // ) - - // const typeMap = await schema.getTypeMap() - - // console.log({ typeMap }) - - // const contentfulTypeDefinitions = new Map() - // store - // .getState() - // .schemaCustomization.types.filter( - // ({ plugin }) => plugin.name === `gatsby-source-contentful` - // ) - // .forEach(({ typeOrTypeDef }) => { - // contentfulTypeDefinitions.set( - // typeOrTypeDef.config.name, - // typeOrTypeDef.config - // ) - // // console.log(typeOrTypeDef.config.fields) - // }) - - // console.log(contentfulTypeDefinitions) const { deletedEntries, deletedAssets } = currentSyncData From e9b1ee182a17941f5eb0454842328d678dae1893 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Wed, 16 Mar 2022 14:53:12 +0100 Subject: [PATCH 036/149] fix: remove asset url protocol duplication --- packages/gatsby-source-contentful/src/image-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/image-helpers.js b/packages/gatsby-source-contentful/src/image-helpers.js index dcfc5ecde2836..230bc85364255 100644 --- a/packages/gatsby-source-contentful/src/image-helpers.js +++ b/packages/gatsby-source-contentful/src/image-helpers.js @@ -52,5 +52,5 @@ export function createUrl(imgUrl, options = {}) { } } - return `https:${imgUrl}?${searchParams.toString()}` + return `${imgUrl}?${searchParams.toString()}` } From 0909aa3fceb8313a80538f483b6eb46617298069 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Thu, 14 Apr 2022 11:54:51 +0200 Subject: [PATCH 037/149] update code and tests from rebase --- .../src/__tests__/gatsby-node.js | 8 +++--- .../src/image-helpers.js | 2 +- .../src/source-nodes.js | 25 +++---------------- 3 files changed, 9 insertions(+), 26 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index c78a9a13e77fd..6187cf1b11921 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -657,7 +657,7 @@ describe(`gatsby-node`, () => { expect(getNode(blogEntry[`author___NODE`])).toBeTruthy() }) - expect(actions.createNode).toHaveBeenCalledTimes(46) + expect(actions.createNode).toHaveBeenCalledTimes(44) expect(actions.deleteNode).toHaveBeenCalledTimes(0) expect(actions.touchNode).toHaveBeenCalledTimes(32) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` @@ -747,7 +747,7 @@ describe(`gatsby-node`, () => { expect(getNode(blogEntry[`author___NODE`])).toBeTruthy() }) - expect(actions.createNode).toHaveBeenCalledTimes(54) + expect(actions.createNode).toHaveBeenCalledTimes(52) expect(actions.deleteNode).toHaveBeenCalledTimes(0) expect(actions.touchNode).toHaveBeenCalledTimes(72) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` @@ -900,7 +900,7 @@ describe(`gatsby-node`, () => { ) }) - expect(actions.createNode).toHaveBeenCalledTimes(52) + expect(actions.createNode).toHaveBeenCalledTimes(48) expect(actions.deleteNode).toHaveBeenCalledTimes(2) expect(actions.touchNode).toHaveBeenCalledTimes(72) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` @@ -986,7 +986,7 @@ describe(`gatsby-node`, () => { locales ) - expect(actions.createNode).toHaveBeenCalledTimes(54) + expect(actions.createNode).toHaveBeenCalledTimes(48) expect(actions.deleteNode).toHaveBeenCalledTimes(2) expect(actions.touchNode).toHaveBeenCalledTimes(72) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` diff --git a/packages/gatsby-source-contentful/src/image-helpers.js b/packages/gatsby-source-contentful/src/image-helpers.js index 230bc85364255..dcfc5ecde2836 100644 --- a/packages/gatsby-source-contentful/src/image-helpers.js +++ b/packages/gatsby-source-contentful/src/image-helpers.js @@ -52,5 +52,5 @@ export function createUrl(imgUrl, options = {}) { } } - return `${imgUrl}?${searchParams.toString()}` + return `https:${imgUrl}?${searchParams.toString()}` } diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index 6ff3fa6fe0799..f8eb5f92d700e 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -246,24 +246,6 @@ export async function sourceNodes( }) const { deletedEntries, deletedAssets } = currentSyncData - - const allDeletedNodes = [...deletedEntries, ...deletedAssets] - const deletedNodeIds = [] - - locales.forEach(locale => { - allDeletedNodes.forEach(n => { - deletedNodeIds.push( - makeId({ - spaceId: n.sys.space.sys.id, - id: n.sys.id, - type: n.sys.type, - currentLocale: locale.code, - defaultLocale, - }) - ) - }) - }) - const deletedEntryGatsbyReferenceIds = new Set() function deleteContentfulNode(node) { @@ -316,7 +298,7 @@ export async function sourceNodes( !deletedEntryGatsbyReferenceIds.has(n.id) ) .forEach(n => { - if (n.contentful_id && foreignReferenceMap[generateReferenceId(n)]) { + if (n.sys.id && foreignReferenceMap[generateReferenceId(n)]) { foreignReferenceMap[generateReferenceId(n)].forEach( foreignReference => { const { name, id, type, spaceId } = foreignReference @@ -326,7 +308,7 @@ export async function sourceNodes( spaceId, id, type, - currentLocale: n.node_locale, + currentLocale: n.sys.locale, defaultLocale, }) ) @@ -348,7 +330,7 @@ export async function sourceNodes( } // Remove references to deleted nodes - if (n.contentful_id && deletedEntryGatsbyReferenceIds.size) { + if (n.sys.id && deletedEntryGatsbyReferenceIds.size) { Object.keys(n).forEach(name => { // @todo Detect reference fields based on schema. Should be easier to achieve in the upcoming version. if (!name.endsWith(`___NODE`)) { @@ -503,6 +485,7 @@ export async function sourceNodes( await createNode({ id: createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`), name: tag.name, + // @todo update the structure of tags contentful_id: tag.sys.id, internal: { type: `ContentfulTag`, From e22b3105e7a7e29cb58a62b72e2ad28c54c6311a Mon Sep 17 00:00:00 2001 From: axe312ger Date: Thu, 14 Apr 2022 14:09:48 +0200 Subject: [PATCH 038/149] refactor asset data structure to satisfy tests and imageCDN from rebase --- e2e-tests/contentful/src/pages/download-local.js | 14 +++++--------- e2e-tests/contentful/src/pages/gatsby-image-cdn.js | 9 +++------ .../create-schema-customization.js.snap | 10 +++++----- .../src/__tests__/gatsby-plugin-image.js | 8 ++++---- .../src/__tests__/image-helpers.js | 6 ++---- .../src/download-contentful-assets.js | 5 ++--- .../src/generate-schema.js | 8 ++++---- .../gatsby-source-contentful/src/image-helpers.js | 2 +- packages/gatsby-source-contentful/src/normalize.js | 7 ++++--- 9 files changed, 30 insertions(+), 39 deletions(-) diff --git a/e2e-tests/contentful/src/pages/download-local.js b/e2e-tests/contentful/src/pages/download-local.js index 564302b009891..e5401942fb130 100644 --- a/e2e-tests/contentful/src/pages/download-local.js +++ b/e2e-tests/contentful/src/pages/download-local.js @@ -10,9 +10,7 @@ const DownloadLocalPage = ({ data }) => {

Test downloadLocal feature

) @@ -23,12 +21,10 @@ export default DownloadLocalPage export const pageQuery = graphql` query DownloadLocalQuery { contentfulAsset(sys: { id: { eq: "3BSI9CgDdAn1JchXmY5IJi" } }) { - fields { - localFile { - absolutePath - childImageSharp { - gatsbyImageData - } + localFile { + absolutePath + childImageSharp { + gatsbyImageData } } } diff --git a/e2e-tests/contentful/src/pages/gatsby-image-cdn.js b/e2e-tests/contentful/src/pages/gatsby-image-cdn.js index 873f7155826ba..967a30cf6dd79 100644 --- a/e2e-tests/contentful/src/pages/gatsby-image-cdn.js +++ b/e2e-tests/contentful/src/pages/gatsby-image-cdn.js @@ -22,15 +22,12 @@ export default GatsbyPluginImagePage export const pageQuery = graphql` query GatsbyImageCDNQuery { default: contentfulAsset( - contentful_id: { eq: "3BSI9CgDdAn1JchXmY5IJi" } - node_locale: { eq: "en-US" } + sys: { id: { eq: "3BSI9CgDdAn1JchXmY5IJi" }, locale: { eq: "en-US" } } ) { title description - file { - fileName - url - } + fileName + url gatsbyImage(width: 420) } } diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index 6a64eb82b4a98..d5bc0eb7c84cb 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -121,16 +121,13 @@ Array [ }, "fields": Object { "contentType": Object { - "type": "String", - }, - "contentful_id": Object { "type": "String!", }, "description": Object { "type": "String", }, "fileName": Object { - "type": "String", + "type": "String!", }, "gatsbyImageData": Object { "args": Object { @@ -229,6 +226,9 @@ Ignored if layout = FLUID.", "metadata": Object { "type": "ContentfulMetadata!", }, + "mimeType": Object { + "type": "String!", + }, "size": Object { "type": "Int", }, @@ -239,7 +239,7 @@ Ignored if layout = FLUID.", "type": "String", }, "url": Object { - "type": "String", + "type": "String!", }, "width": Object { "type": "Int", diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js index e9803ea9f210a..176963bcbddda 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js @@ -72,7 +72,7 @@ describe(`gatsby-plugin-image`, () => { Object { "format": "webp", "height": 210, - "src": "https://test.png?w=420&h=210&fm=webp", + "src": "//test.png?w=420&h=210&fm=webp", "width": 420, } `) @@ -86,7 +86,7 @@ describe(`gatsby-plugin-image`, () => { Object { "format": "webp", "height": 210, - "src": "https://test.png?w=420&h=210&fm=webp&r=10", + "src": "//test.png?w=420&h=210&fm=webp&r=10", "width": 420, } `) @@ -100,7 +100,7 @@ describe(`gatsby-plugin-image`, () => { Object { "format": "webp", "height": 210, - "src": "https://test.png?w=420&h=210&fm=webp&r=max", + "src": "//test.png?w=420&h=210&fm=webp&r=max", "width": 420, } `) @@ -112,7 +112,7 @@ describe(`gatsby-plugin-image`, () => { Object { "format": "webp", "height": 210, - "src": "https://test.png?w=420&h=210&fm=webp", + "src": "//test.png?w=420&h=210&fm=webp", "width": 420, } `) diff --git a/packages/gatsby-source-contentful/src/__tests__/image-helpers.js b/packages/gatsby-source-contentful/src/__tests__/image-helpers.js index 80b58997348f4..71d0ed6081202 100644 --- a/packages/gatsby-source-contentful/src/__tests__/image-helpers.js +++ b/packages/gatsby-source-contentful/src/__tests__/image-helpers.js @@ -9,14 +9,12 @@ describe(`Contentful Image API helpers`, () => { it(`allows you to create URls`, () => { expect( createUrl(`//images.contentful.com/dsf/bl.jpg`, { width: 100 }) - ).toMatchInlineSnapshot( - `"https://images.contentful.com/dsf/bl.jpg?w=100"` - ) + ).toMatchInlineSnapshot(`"//images.contentful.com/dsf/bl.jpg?w=100"`) }) it(`ignores options it doesn't understand`, () => { expect( createUrl(`//images.contentful.com/dsf/bl.jpg`, { happiness: 100 }) - ).toMatchInlineSnapshot(`"https://images.contentful.com/dsf/bl.jpg?"`) + ).toMatchInlineSnapshot(`"//images.contentful.com/dsf/bl.jpg?"`) }) }) }) diff --git a/packages/gatsby-source-contentful/src/download-contentful-assets.js b/packages/gatsby-source-contentful/src/download-contentful-assets.js index c15c162a9168f..dbb486dc2498b 100644 --- a/packages/gatsby-source-contentful/src/download-contentful-assets.js +++ b/packages/gatsby-source-contentful/src/download-contentful-assets.js @@ -1,6 +1,5 @@ // @ts-check import { createRemoteFileNode } from "gatsby-source-filesystem" -import { createUrl } from "./image-helpers" /** * @name distributeWorkload @@ -52,15 +51,15 @@ export async function downloadContentfulAssets(gatsbyFunctions) { let fileNodeID const { sys: { id, locale }, + url, } = assetNode const remoteDataCacheKey = `contentful-asset-${id}-${locale}` const cacheRemoteData = await cache.get(remoteDataCacheKey) - if (!assetNode.url) { + if (!url) { reporter.warn(`The asset with id: ${id} has no url.`) return Promise.resolve() } - const url = createUrl(assetNode.url) // Avoid downloading the asset again if it's been cached // Note: Contentful Assets do not provide useful metadata diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js index e80c1e1c0ab6c..eccc7d6b0b99a 100644 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ b/packages/gatsby-source-contentful/src/generate-schema.js @@ -279,7 +279,6 @@ export async function generateSchema({ schema.buildObjectType({ name: `ContentfulAsset`, fields: { - contentful_id: { type: `String!` }, id: { type: `ID!` }, sys: { type: `ContentfulSys!` }, metadata: { type: `ContentfulMetadata!` }, @@ -322,9 +321,10 @@ export async function generateSchema({ : {}), title: { type: `String` }, description: { type: `String` }, - contentType: { type: `String` }, - fileName: { type: `String` }, - url: { type: `String` }, + contentType: { type: `String!` }, + mimeType: { type: `String!` }, + fileName: { type: `String!` }, + url: { type: `String!` }, size: { type: `Int` }, width: { type: `Int` }, height: { type: `Int` }, diff --git a/packages/gatsby-source-contentful/src/image-helpers.js b/packages/gatsby-source-contentful/src/image-helpers.js index dcfc5ecde2836..230bc85364255 100644 --- a/packages/gatsby-source-contentful/src/image-helpers.js +++ b/packages/gatsby-source-contentful/src/image-helpers.js @@ -52,5 +52,5 @@ export function createUrl(imgUrl, options = {}) { } } - return `https:${imgUrl}?${searchParams.toString()}` + return `${imgUrl}?${searchParams.toString()}` } diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index 11e1aa529f8d0..d4e0063bf474c 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -612,9 +612,8 @@ export const createAssetNodes = ({ publishedVersion: assetItem.sys.revision, }, placeholderUrl: `https:${file.url}?w=%width%&h=%height%`, + url: `https:${file.url}`, // These fields are optional for edge cases in the Preview API and Contentfuls asset processing - mimeType: file.contentType, - filename: file.fileName, width: file.details?.image?.width ?? null, height: file.details?.image?.height ?? null, size: file.details?.size ?? null, @@ -627,7 +626,9 @@ export const createAssetNodes = ({ description: assetItem.fields.description ? getField(assetItem.fields.description) : ``, - url: `https:${file.url}`, + // Satisfy the Gatsby ImageCDN feature + mimeType: file.contentType, + filename: file.fileName, } // if the node hasn't changed, createNode may return `undefined` instead of a Promise on some versions of Gatsby From e05902eaf22b53f6cd23749d658453f7a641139f Mon Sep 17 00:00:00 2001 From: axe312ger Date: Thu, 14 Apr 2022 14:14:17 +0200 Subject: [PATCH 039/149] update e2e test schema file --- e2e-tests/contentful/schema.gql | 438 ++++++++++++++++++++++++++------ 1 file changed, 365 insertions(+), 73 deletions(-) diff --git a/e2e-tests/contentful/schema.gql b/e2e-tests/contentful/schema.gql index 7118ffb9ac47c..ed86a1fdc54f3 100644 --- a/e2e-tests/contentful/schema.gql +++ b/e2e-tests/contentful/schema.gql @@ -1,4 +1,172 @@ -### Type definitions saved at 2021-11-18T12:37:07.683Z ### +### Type definitions saved at 2022-04-14T12:11:45.168Z ### + +enum RemoteFileFit { + COVER + FILL + OUTSIDE + CONTAIN +} + +enum RemoteFileFormat { + AUTO + JPG + PNG + WEBP + AVIF +} + +enum RemoteFileLayout { + FIXED + FULL_WIDTH + CONSTRAINED +} + +enum RemoteFilePlaceholder { + DOMINANT_COLOR + BLURRED + NONE +} + +enum RemoteFileCropFocus { + CENTER + TOP + RIGHT + BOTTOM + LEFT + ENTROPY + EDGES + FACES +} + +type RemoteFileResize { + width: Int + height: Int + src: String +} + +""" +Remote Interface +""" +interface RemoteFile { + id: ID! + mimeType: String! + filename: String! + filesize: Int + width: Int + height: Int + publicUrl: String! + resize( + width: Int + height: Int + aspectRatio: Float + fit: RemoteFileFit = COVER + + """ + The image formats to generate. Valid values are AUTO (meaning the same + format as the source image), JPG, PNG, WEBP and AVIF. + The default value is [AUTO, WEBP, AVIF], and you should rarely need to + change this. Take care if you specify JPG or PNG when you do + not know the formats of the source images, as this could lead to unwanted + results such as converting JPEGs to PNGs. Specifying + both PNG and JPG is not supported and will be ignored. + """ + format: RemoteFileFormat = AUTO + cropFocus: [RemoteFileCropFocus] + quality: Int = 75 + ): RemoteFileResize + + """ + Data used in the component. See https://gatsby.dev/img for more info. + """ + gatsbyImage( + """ + The layout for the image. + FIXED: A static image sized, that does not resize according to the screen width + FULL_WIDTH: The image resizes to fit its container. Pass a "sizes" option if + it isn't going to be the full width of the screen. + CONSTRAINED: Resizes to fit its container, up to a maximum width, at which point it will remain fixed in size. + """ + layout: RemoteFileLayout = CONSTRAINED + + """ + The display width of the generated image for layout = FIXED, and the display + width of the largest image for layout = CONSTRAINED. + The actual largest image resolution will be this value multiplied by the largest value in outputPixelDensities + Ignored if layout = FLUID. + """ + width: Int + + """ + If set, the height of the generated image. If omitted, it is calculated from + the supplied width, matching the aspect ratio of the source image. + """ + height: Int + + """ + Format of generated placeholder image, displayed while the main image loads. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. + TRACED_SVG: a low-resolution traced SVG of the image. + NONE: no placeholder. Set the argument "backgroundColor" to use a fixed background color. + """ + placeholder: RemoteFilePlaceholder = DOMINANT_COLOR + + """ + If set along with width or height, this will set the value of the other + dimension to match the provided aspect ratio, cropping the image if needed. + If neither width or height is provided, height will be set based on the intrinsic width of the source image. + """ + aspectRatio: Float + + """ + The image formats to generate. Valid values are AUTO (meaning the same + format as the source image), JPG, PNG, WEBP and AVIF. + The default value is [AUTO, WEBP, AVIF], and you should rarely need to + change this. Take care if you specify JPG or PNG when you do + not know the formats of the source images, as this could lead to unwanted + results such as converting JPEGs to PNGs. Specifying + both PNG and JPG is not supported and will be ignored. + """ + formats: [RemoteFileFormat!] = [AUTO, WEBP, AVIF] + + """ + A list of image pixel densities to generate for FIXED and CONSTRAINED + images. You should rarely need to change this. It will never generate images + larger than the source, and will always include a 1x image. + Default is [ 1, 2 ] for fixed images, meaning 1x, 2x, and [0.25, 0.5, 1, 2] + for fluid. In this case, an image with a fluid layout and width = 400 would + generate images at 100, 200, 400 and 800px wide. + """ + outputPixelDensities: [Float] = [0.25, 0.5, 1, 2] + + """ + Specifies the image widths to generate. You should rarely need to change + this. For FIXED and CONSTRAINED images it is better to allow these to be + determined automatically, + based on the image size. For FULL_WIDTH images this can be used to override + the default, which is [750, 1080, 1366, 1920]. + It will never generate any images larger than the source. + """ + breakpoints: [Int] = [750, 1080, 1366, 1920] + + """ + The "sizes" property, passed to the img tag. This describes the display size of the image. + This does not affect the generated images, but is used by the browser to + decide which images to download. You can leave this blank for fixed images, + or if the responsive image + container will be the full width of the screen. In these cases we will generate an appropriate value. + """ + sizes: String + + """ + Background color applied to the wrapper, or when "letterboxing" an image to another aspect ratio. + """ + backgroundColor: String + fit: RemoteFileFit = COVER + cropFocus: [RemoteFileCropFocus] + quality: Int = 75 + ): JSON +} type File implements Node @dontInfer { sourceInstanceName: String! @@ -74,9 +242,12 @@ type Directory implements Node @dontInfer { type Site implements Node @dontInfer { buildTime: Date @dateformat siteMetadata: SiteSiteMetadata + port: Int + host: String polyfill: Boolean pathPrefix: String jsxRuntime: String + trailingSlash: String } type SiteSiteMetadata { @@ -123,6 +294,7 @@ type SiteBuildMetadata implements Node @dontInfer { interface ContentfulEntity implements Node { id: ID! sys: ContentfulSys! + metadata: ContentfulMetadata! } type ContentfulSys implements Node @dontInfer { @@ -142,12 +314,6 @@ type ContentfulContentType implements Node @dontInfer { description: String! } -interface ContentfulEntry implements ContentfulEntity & Node { - id: ID! - sys: ContentfulSys! - metadata: ContentfulMetadata! -} - type ContentfulMetadata @dontInfer { tags: [ContentfulTag]! @link(by: "id", from: "tags___NODE") } @@ -157,21 +323,187 @@ type ContentfulTag implements Node @dontInfer { contentful_id: String! } -type ContentfulAssetFields @dontInfer { - localFile: File @link(by: "id") +interface ContentfulEntry implements ContentfulEntity & Node { + id: ID! + sys: ContentfulSys! + metadata: ContentfulMetadata! +} + +enum ImageResizingBehavior { + NO_CHANGE + + """ + Same as the default resizing, but adds padding so that the generated image has the specified dimensions. + """ + PAD + + """ + Crop a part of the original image to match the specified size. + """ + CROP + + """ + Crop the image to the specified dimensions, if the original image is smaller + than these dimensions, then the image will be upscaled. + """ + FILL + + """ + When used in association with the f parameter below, creates a thumbnail from the image based on a focus area. + """ + THUMB + + """ + Scale the image regardless of the original aspect ratio. + """ + SCALE +} + +enum ContentfulImageCropFocus { + TOP + TOP_LEFT + TOP_RIGHT + BOTTOM + BOTTOM_RIGHT + BOTTOM_LEFT + RIGHT + LEFT + FACE + FACES + CENTER } -type ContentfulAsset implements ContentfulEntity & Node @dontInfer { +type ContentfulAsset implements ContentfulEntity & Node & RemoteFile + @dontInfer { sys: ContentfulSys! + metadata: ContentfulMetadata! + gatsbyImageData( + """ + The layout for the image. + FIXED: A static image sized, that does not resize according to the screen width + FULL_WIDTH: The image resizes to fit its container. Pass a "sizes" option if + it isn't going to be the full width of the screen. + CONSTRAINED: Resizes to fit its container, up to a maximum width, at which point it will remain fixed in size. + """ + layout: GatsbyImageLayout + + """ + The display width of the generated image for layout = FIXED, and the display + width of the largest image for layout = CONSTRAINED. + The actual largest image resolution will be this value multiplied by the largest value in outputPixelDensities + Ignored if layout = FLUID. + """ + width: Int + + """ + If set, the height of the generated image. If omitted, it is calculated from + the supplied width, matching the aspect ratio of the source image. + """ + height: Int + + """ + If set along with width or height, this will set the value of the other + dimension to match the provided aspect ratio, cropping the image if needed. + If neither width or height is provided, height will be set based on the intrinsic width of the source image. + """ + aspectRatio: Float + + """ + Format of generated placeholder image, displayed while the main image loads. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. + TRACED_SVG: a low-resolution traced SVG of the image. + NONE: no placeholder. Set the argument "backgroundColor" to use a fixed background color. + """ + placeholder: GatsbyImagePlaceholder + + """ + The image formats to generate. Valid values are AUTO (meaning the same + format as the source image), JPG, PNG, WEBP and AVIF. + The default value is [AUTO, WEBP], and you should rarely need to change + this. Take care if you specify JPG or PNG when you do + not know the formats of the source images, as this could lead to unwanted + results such as converting JPEGs to PNGs. Specifying + both PNG and JPG is not supported and will be ignored. + """ + formats: [GatsbyImageFormat] = [NO_CHANGE, WEBP] + + """ + A list of image pixel densities to generate for FIXED and CONSTRAINED + images. You should rarely need to change this. It will never generate images + larger than the source, and will always include a 1x image. + Default is [ 1, 2 ] for fixed images, meaning 1x, 2x, 3x, and [0.25, 0.5, 1, + 2] for fluid. In this case, an image with a fluid layout and width = 400 + would generate images at 100, 200, 400 and 800px wide. + """ + outputPixelDensities: [Float] + + """ + Specifies the image widths to generate. You should rarely need to change + this. For FIXED and CONSTRAINED images it is better to allow these to be + determined automatically, + based on the image size. For FULL_WIDTH images this can be used to override + the default, which is [750, 1080, 1366, 1920]. + It will never generate any images larger than the source. + """ + breakpoints: [Int] + + """ + The "sizes" property, passed to the img tag. This describes the display size of the image. + This does not affect the generated images, but is used by the browser to + decide which images to download. You can leave this blank for fixed images, + or if the responsive image + container will be the full width of the screen. In these cases we will generate an appropriate value. + """ + sizes: String + + """ + Background color applied to the wrapper, or when "letterboxing" an image to another aspect ratio. + """ + backgroundColor: String + jpegProgressive: Boolean = true + resizingBehavior: ImageResizingBehavior + cropFocus: ContentfulImageCropFocus + + """ + Desired corner radius in pixels. Results in an image with rounded corners. + Pass `-1` for a full circle/ellipse. + """ + cornerRadius: Int + quality: Int = 50 + ): JSON! + localFile: File @link(from: "fields.localFile", by: "id") title: String description: String - contentType: String - fileName: String - url: String + contentType: String! + mimeType: String! + fileName: String! + url: String! size: Int width: Int height: Int - fields: ContentfulAssetFields +} + +enum GatsbyImageLayout { + FIXED + FULL_WIDTH + CONSTRAINED +} + +enum GatsbyImagePlaceholder { + DOMINANT_COLOR + TRACED_SVG + BLURRED + NONE +} + +enum GatsbyImageFormat { + NO_CHANGE + AUTO + JPG + PNG + WEBP + AVIF } type ContentfulRichTextAssets { @@ -505,10 +837,10 @@ input AVIFOptions { } input TransformOptions { - grayscale: Boolean = false + grayscale: Boolean duotone: DuotoneGradient - rotate: Int = 0 - trim: Float = 0 + rotate: Int + trim: Float cropFocus: ImageCropFocus = ATTENTION fit: ImageFit = COVER } @@ -535,26 +867,26 @@ type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { base64Width: Int jpegProgressive: Boolean = true pngCompressionSpeed: Int = 4 - grayscale: Boolean = false + grayscale: Boolean duotone: DuotoneGradient traceSVG: Potrace quality: Int jpegQuality: Int pngQuality: Int webpQuality: Int - toFormat: ImageFormat = AUTO - toFormatBase64: ImageFormat = AUTO + toFormat: ImageFormat + toFormatBase64: ImageFormat cropFocus: ImageCropFocus = ATTENTION fit: ImageFit = COVER background: String = "rgba(0,0,0,1)" - rotate: Int = 0 - trim: Float = 0 + rotate: Int + trim: Float ): ImageSharpFixed fluid( maxWidth: Int maxHeight: Int base64Width: Int - grayscale: Boolean = false + grayscale: Boolean jpegProgressive: Boolean = true pngCompressionSpeed: Int = 4 duotone: DuotoneGradient @@ -563,14 +895,14 @@ type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { jpegQuality: Int pngQuality: Int webpQuality: Int - toFormat: ImageFormat = AUTO - toFormatBase64: ImageFormat = AUTO + toFormat: ImageFormat + toFormatBase64: ImageFormat cropFocus: ImageCropFocus = ATTENTION fit: ImageFit = COVER background: String = "rgba(0,0,0,1)" - rotate: Int = 0 - trim: Float = 0 - sizes: String = "" + rotate: Int + trim: Float + sizes: String """ A list of image widths to be generated. Example: [ 200, 340, 520, 890 ] @@ -714,55 +1046,15 @@ type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { jpegProgressive: Boolean = true pngCompressionLevel: Int = 9 pngCompressionSpeed: Int = 4 - grayscale: Boolean = false + grayscale: Boolean duotone: DuotoneGradient - base64: Boolean = false + base64: Boolean traceSVG: Potrace - toFormat: ImageFormat = AUTO + toFormat: ImageFormat cropFocus: ImageCropFocus = ATTENTION fit: ImageFit = COVER background: String = "rgba(0,0,0,1)" - rotate: Int = 0 - trim: Float = 0 + rotate: Int + trim: Float ): ImageSharpResize } - -enum GatsbyImageFormat { - NO_CHANGE - AUTO - JPG - PNG - WEBP - AVIF -} - -enum GatsbyImageLayout { - FIXED - FULL_WIDTH - CONSTRAINED -} - -enum GatsbyImagePlaceholder { - DOMINANT_COLOR - TRACED_SVG - BLURRED - NONE -} - -type ContentfulContentTypeContentType implements Node @derivedTypes @dontInfer { - name: String - displayField: String - description: String - sys: ContentfulContentTypeContentTypeSys -} - -type ContentfulContentTypeContentTypeSys { - type: String - id: String - locale: String - spaceId: String - environmentId: String - firstPublishedAt: Date @dateformat - publishedAt: Date @dateformat - publishedVersion: Int -} From 7813794ffb438b09f70acc4b0ab45e7f92c87fca Mon Sep 17 00:00:00 2001 From: axe312ger Date: Thu, 14 Apr 2022 14:17:33 +0200 Subject: [PATCH 040/149] style: rename generateReferenceId to createRefId --- .../gatsby-source-contentful/src/normalize.js | 19 +++--- .../src/source-nodes.js | 58 +++++++++---------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index d4e0063bf474c..8cb0b5bf6bf63 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -62,7 +62,7 @@ const makeMakeId = createNodeId(makeId({ spaceId, id, currentLocale, defaultLocale, type })) // Generates an unique id per space for reference resolving -export const generateReferenceId = nodeOrLink => +export const createRefId = nodeOrLink => `${nodeOrLink.sys.id}___${nodeOrLink.sys.linkType || nodeOrLink.sys.type}` export const buildEntryList = ({ contentTypeItems, currentSyncData }) => { @@ -91,15 +91,15 @@ export const buildResolvableSet = ({ 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)) + resolvable.add(createRefId(node)) } }) entryList.forEach(entries => { - entries.forEach(entry => resolvable.add(generateReferenceId(entry))) + entries.forEach(entry => resolvable.add(createRefId(entry))) }) - assets.forEach(assetItem => resolvable.add(generateReferenceId(assetItem))) + assets.forEach(assetItem => resolvable.add(createRefId(assetItem))) return resolvable } @@ -140,7 +140,7 @@ export const buildForeignReferenceMap = ({ entryItemFieldValue[0].sys.id ) { entryItemFieldValue.forEach(v => { - const key = generateReferenceId(v) + const key = createRefId(v) // Don't create link to an unresolvable field. if (!resolvable.has(key)) { return @@ -161,7 +161,7 @@ export const buildForeignReferenceMap = ({ entryItemFieldValue?.sys?.type && entryItemFieldValue.sys.id ) { - const key = generateReferenceId(entryItemFieldValue) + const key = createRefId(entryItemFieldValue) // Don't create link to an unresolvable field. if (!resolvable.has(key)) { return @@ -402,7 +402,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(v => resolvable.has(generateReferenceId(v))) + .filter(v => resolvable.has(createRefId(v))) .map(function (v) { return mId( space.sys.id, @@ -418,7 +418,7 @@ export const createNodesForContentType = ({ delete entryItemFields[entryItemFieldKey] } } else if (entryItemFieldValue?.sys?.type === `Link`) { - if (resolvable.has(generateReferenceId(entryItemFieldValue))) { + if (resolvable.has(createRefId(entryItemFieldValue))) { entryItemFields[`${entryItemFieldKey}___NODE`] = mId( space.sys.id, entryItemFieldValue.sys.id, @@ -432,8 +432,7 @@ export const createNodesForContentType = ({ }) // Add reverse linkages if there are any for this node - const foreignReferences = - foreignReferenceMap[generateReferenceId(entryItem)] + const foreignReferences = foreignReferenceMap[createRefId(entryItem)] if (foreignReferences) { foreignReferences.forEach(foreignReference => { const existingReference = entryItemFields[foreignReference.name] diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index f8eb5f92d700e..38cd4cabe09b9 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -11,7 +11,7 @@ import { buildResolvableSet, createAssetNodes, createNodesForContentType, - generateReferenceId, + createRefId, makeId, } from "./normalize" import { createPluginConfig } from "./plugin-options" @@ -241,7 +241,7 @@ export async function sourceNodes( const newOrUpdatedEntries = new Set() entryList.forEach(entries => { entries.forEach(entry => { - newOrUpdatedEntries.add(generateReferenceId(entry)) + newOrUpdatedEntries.add(createRefId(entry)) }) }) @@ -294,39 +294,37 @@ export async function sourceNodes( .filter( n => n.sys.type === `Entry` && - !newOrUpdatedEntries.has(generateReferenceId(n)) && + !newOrUpdatedEntries.has(createRefId(n)) && !deletedEntryGatsbyReferenceIds.has(n.id) ) .forEach(n => { - if (n.sys.id && foreignReferenceMap[generateReferenceId(n)]) { - foreignReferenceMap[generateReferenceId(n)].forEach( - foreignReference => { - const { name, id, type, spaceId } = foreignReference - - const nodeId = createNodeId( - makeId({ - spaceId, - id, - type, - currentLocale: n.sys.locale, - defaultLocale, - }) - ) - - // Create new reference field when none exists - if (!n[name]) { - existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) - n[name] = [nodeId] - return - } + if (n.sys.id && foreignReferenceMap[createRefId(n)]) { + foreignReferenceMap[createRefId(n)].forEach(foreignReference => { + const { name, id, type, spaceId } = foreignReference + + const nodeId = createNodeId( + makeId({ + spaceId, + id, + type, + currentLocale: n.sys.locale, + defaultLocale, + }) + ) - // Add non existing references to reference field - if (n[name] && !n[name].includes(nodeId)) { - existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) - n[name].push(nodeId) - } + // Create new reference field when none exists + if (!n[name]) { + existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) + n[name] = [nodeId] + return } - ) + + // Add non existing references to reference field + if (n[name] && !n[name].includes(nodeId)) { + existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) + n[name].push(nodeId) + } + }) } // Remove references to deleted nodes From 71bb38a1c4d49ebea986e6de203fc054e267eab3 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Thu, 14 Apr 2022 14:25:34 +0200 Subject: [PATCH 041/149] style: move all schema customization related code back to original file --- .../src/create-schema-customization.js | 503 +++++++++++++++++- .../src/generate-schema.js | 503 ------------------ 2 files changed, 493 insertions(+), 513 deletions(-) delete mode 100644 packages/gatsby-source-contentful/src/generate-schema.js diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.js b/packages/gatsby-source-contentful/src/create-schema-customization.js index 7764aab499cdc..21648b7bec966 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.js +++ b/packages/gatsby-source-contentful/src/create-schema-customization.js @@ -1,10 +1,179 @@ // @ts-check import _ from "lodash" import { fetchContentTypes } from "./fetch" -import { generateSchema } from "./generate-schema" import { createPluginConfig } from "./plugin-options" import { CODES } from "./report" +import { getRichTextEntityLinks } from "@contentful/rich-text-links" +import { stripIndent } from "common-tags" +import { addRemoteFilePolyfillInterface } from "gatsby-plugin-utils/polyfill-remote-file" + +import { resolveGatsbyImageData } from "./gatsby-plugin-image" +import { makeTypeName } from "./normalize" +import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" + +// Contentful content type schemas +/** @type {Map { type: string; }>} */ +const ContentfulDataTypes = new Map([ + [ + `Symbol`, + () => { + return { type: `String` } + }, + ], + [ + `Text`, + field => { + return { + type: `ContentfulText`, + extensions: { + link: { by: `id`, from: `${field.id}___NODE` }, + }, + } + }, + ], + [ + `Integer`, + () => { + return { type: `Int` } + }, + ], + [ + `Number`, + () => { + return { type: `Float` } + }, + ], + [ + `Date`, + () => { + return { + type: `Date`, + extensions: { + dateformat: {}, + }, + } + }, + ], + [ + `Object`, + () => { + return { type: `JSON` } + }, + ], + [ + `Boolean`, + () => { + return { type: `Boolean` } + }, + ], + [ + `Location`, + () => { + return { type: `ContentfulLocation` } + }, + ], + [ + `RichText`, + () => { + return { type: `ContentfulRichText` } + }, + ], +]) + +const unionsNameSet = new Set() + +const getLinkFieldType = (linkType, field, schema, createTypes) => { + // Check for validations + const validations = + field.type === `Array` ? field.items?.validations : field?.validations + + if (validations) { + // We only handle content type validations + const linkContentTypeValidation = validations.find( + ({ linkContentType }) => !!linkContentType + ) + if (linkContentTypeValidation) { + const { linkContentType } = linkContentTypeValidation + const contentTypes = Array.isArray(linkContentType) + ? linkContentType + : [linkContentType] + + // Full type names for union members, shorter variant for the union type name + const translatedTypeNames = contentTypes.map(typeName => + makeTypeName(typeName) + ) + const shortTypeNames = contentTypes.map(typeName => + makeTypeName(typeName, ``) + ) + + // Single content type + if (translatedTypeNames.length === 1) { + return { + type: translatedTypeNames.shift(), + extensions: { + link: { by: `id`, from: `${field.id}___NODE` }, + }, + } + } + + // Multiple content types + const unionName = [`UnionContentful`, ...shortTypeNames].join(``) + + if (!unionsNameSet.has(unionName)) { + unionsNameSet.add(unionName) + createTypes( + schema.buildUnionType({ + name: unionName, + types: translatedTypeNames, + }) + ) + } + + return { + type: unionName, + extensions: { + link: { by: `id`, from: `${field.id}___NODE` }, + }, + } + } + } + + return { + type: `Contentful${linkType}`, + extensions: { + link: { by: `id`, from: `${field.id}___NODE` }, + }, + } +} + +// Translate Contentful field types to GraphQL field types +const translateFieldType = (field, schema, createTypes) => { + let fieldType + if (field.type === `Array`) { + // Arrays of Contentful Links or primitive types + const fieldData = + field.items.type === `Link` + ? getLinkFieldType(field.items.linkType, field, schema, createTypes) + : translateFieldType(field.items, schema, createTypes) + + fieldType = { ...fieldData, type: `[${fieldData.type}]` } + } else if (field.type === `Link`) { + // Contentful Link (reference) field types + fieldType = getLinkFieldType(field.linkType, field, schema, createTypes) + } else { + // Primitive field types + fieldType = ContentfulDataTypes.get(field.type)(field) + } + + // @todo what do we do when preview is enabled? Emptry required fields are valid for Contentfuls CP-API + // if (field.required) { + // fieldType.type = `${fieldType.type}!` + // } + + return fieldType +} + async function getContentTypesFromContentful({ cache, reporter, @@ -61,13 +230,327 @@ export async function createSchemaCustomization( }) } - // Generate schemas based on Contentful content model - return generateSchema({ - createTypes, - schema, - pluginConfig, - contentTypeItems, - cache, - actions, - }) + // Generic Types + createTypes( + schema.buildInterfaceType({ + name: `ContentfulEntity`, + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, + }, + interfaces: [`Node`], + }) + ) + + createTypes( + schema.buildInterfaceType({ + name: `ContentfulEntry`, + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, + }, + interfaces: [`ContentfulEntity`, `Node`], + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulContentType`, + fields: { + id: { type: `ID!` }, + name: { type: `String!` }, + displayField: { type: `String!` }, + description: { type: `String!` }, + }, + interfaces: [`Node`], + extensions: { dontInfer: {} }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulSys`, + fields: { + id: { type: ` String!` }, + type: { type: ` String!` }, + spaceId: { type: ` String!` }, + environmentId: { type: ` String!` }, + contentType: { + type: `ContentfulContentType`, + extensions: { + link: { by: `id`, from: `contentType___NODE` }, + }, + }, + firstPublishedAt: { type: ` Date!` }, + publishedAt: { type: ` Date!` }, + publishedVersion: { type: ` Int!` }, + locale: { type: ` String!` }, + }, + interfaces: [`Node`], + extensions: { dontInfer: {} }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulMetadata`, + fields: { + tags: { + type: `[ContentfulTag]!`, + extensions: { + link: { by: `id`, from: `tags___NODE` }, + }, + }, + }, + extensions: { dontInfer: {} }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulTag`, + fields: { + name: { type: `String!` }, + contentful_id: { type: `String!` }, + id: { type: `ID!` }, + }, + interfaces: [`Node`], + extensions: { dontInfer: {} }, + }) + ) + + const { getGatsbyImageFieldConfig } = await import( + `gatsby-plugin-image/graphql-utils` + ) + + // Assets + createTypes( + addRemoteFilePolyfillInterface( + schema.buildObjectType({ + name: `ContentfulAsset`, + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, + gatsbyImageData: getGatsbyImageFieldConfig( + async (...args) => resolveGatsbyImageData(...args, { cache }), + { + jpegProgressive: { + type: `Boolean`, + defaultValue: true, + }, + resizingBehavior: { + type: ImageResizingBehavior, + }, + cropFocus: { + type: ImageCropFocusType, + }, + cornerRadius: { + type: `Int`, + defaultValue: 0, + description: stripIndent` + Desired corner radius in pixels. Results in an image with rounded corners. + Pass \`-1\` for a full circle/ellipse.`, + }, + quality: { + type: `Int`, + defaultValue: 50, + }, + } + ), + ...(pluginConfig.get(`downloadLocal`) + ? { + localFile: { + type: `File`, + extensions: { + link: { + from: `fields.localFile`, + }, + }, + }, + } + : {}), + title: { type: `String` }, + description: { type: `String` }, + contentType: { type: `String!` }, + mimeType: { type: `String!` }, + fileName: { type: `String!` }, + url: { type: `String!` }, + size: { type: `Int` }, + width: { type: `Int` }, + height: { type: `Int` }, + }, + interfaces: [`ContentfulEntity`, `Node`], + extensions: { dontInfer: {} }, + }), + { + schema, + actions, + } + ) + ) + + // Rich Text + const makeRichTextLinksResolver = + (nodeType, entityType) => (source, args, context) => { + const links = getRichTextEntityLinks(source, nodeType)[entityType].map( + ({ id }) => id + ) + + return context.nodeModel.getAllNodes().filter( + node => + node.internal.owner === `gatsby-source-contentful` && + node?.sys?.id && + node?.sys?.type === entityType && + links.includes(node.sys.id) + // @todo how can we check for correct space and environment? We need to access the sys field of the fields parent entry. + ) + } + + // Contentful specific types + createTypes( + schema.buildObjectType({ + name: `ContentfulRichTextAssets`, + fields: { + block: { + type: `[ContentfulAsset]!`, + resolve: makeRichTextLinksResolver(`embedded-asset-block`, `Asset`), + }, + hyperlink: { + type: `[ContentfulAsset]!`, + resolve: makeRichTextLinksResolver(`asset-hyperlink`, `Asset`), + }, + }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulRichTextEntries`, + fields: { + inline: { + type: `[ContentfulEntry]!`, + resolve: makeRichTextLinksResolver(`embedded-entry-inline`, `Entry`), + }, + block: { + type: `[ContentfulEntry]!`, + resolve: makeRichTextLinksResolver(`embedded-entry-block`, `Entry`), + }, + hyperlink: { + type: `[ContentfulEntry]!`, + resolve: makeRichTextLinksResolver(`entry-hyperlink`, `Entry`), + }, + }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulRichTextLinks`, + fields: { + assets: { + type: `ContentfulRichTextAssets`, + resolve(source) { + return source + }, + }, + entries: { + type: `ContentfulRichTextEntries`, + resolve(source) { + return source + }, + }, + }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulRichText`, + fields: { + json: { + type: `JSON`, + resolve(source) { + return source + }, + }, + links: { + type: `ContentfulRichTextLinks`, + resolve(source) { + return source + }, + }, + }, + extensions: { dontInfer: {} }, + }) + ) + + // Location + createTypes( + schema.buildObjectType({ + name: `ContentfulLocation`, + fields: { + lat: { type: `Float!` }, + lon: { type: `Float!` }, + }, + extensions: { + dontInfer: {}, + }, + }) + ) + + // Text + // @todo Is there a way to have this as string and let transformer-remark replace it with an object? + createTypes( + schema.buildObjectType({ + name: `ContentfulText`, + fields: { + raw: `String!`, + }, + // @todo do we need a node interface here? + interfaces: [`Node`], + extensions: { + dontInfer: {}, + }, + }) + ) + + // Content types + for (const contentTypeItem of contentTypeItems) { + try { + const fields = {} + contentTypeItem.fields.forEach(field => { + if (field.disabled || field.omitted) { + return + } + fields[field.id] = translateFieldType(field, schema, createTypes) + }) + + const type = pluginConfig.get(`useNameForId`) + ? contentTypeItem.name + : contentTypeItem.sys.id + + createTypes( + schema.buildObjectType({ + name: makeTypeName(type), + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, + ...fields, + }, + interfaces: [`ContentfulEntity`, `ContentfulEntry`, `Node`], + extensions: { dontInfer: {} }, + }) + ) + } catch (err) { + err.message = `Unable to create schema for Contentful Content Type ${ + contentTypeItem.name || contentTypeItem.sys.id + }:\n${err.message}` + console.log(err.stack) + throw err + } + } } diff --git a/packages/gatsby-source-contentful/src/generate-schema.js b/packages/gatsby-source-contentful/src/generate-schema.js deleted file mode 100644 index eccc7d6b0b99a..0000000000000 --- a/packages/gatsby-source-contentful/src/generate-schema.js +++ /dev/null @@ -1,503 +0,0 @@ -import { getRichTextEntityLinks } from "@contentful/rich-text-links" -import { stripIndent } from "common-tags" -import { addRemoteFilePolyfillInterface } from "gatsby-plugin-utils/polyfill-remote-file" - -import { resolveGatsbyImageData } from "./gatsby-plugin-image" -import { makeTypeName } from "./normalize" -import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" - -// Contentful content type schemas -const ContentfulDataTypes = new Map([ - [ - `Symbol`, - () => { - return { type: `String` } - }, - ], - [ - `Text`, - field => { - return { - type: `ContentfulText`, - extensions: { - link: { by: `id`, from: `${field.id}___NODE` }, - }, - } - }, - ], - [ - `Integer`, - () => { - return { type: `Int` } - }, - ], - [ - `Number`, - () => { - return { type: `Float` } - }, - ], - [ - `Date`, - () => { - return { - type: `Date`, - extensions: { - dateformat: {}, - }, - } - }, - ], - [ - `Object`, - () => { - return { type: `JSON` } - }, - ], - [ - `Boolean`, - () => { - return { type: `Boolean` } - }, - ], - [ - `Location`, - () => { - return { type: `ContentfulLocation` } - }, - ], - [ - `RichText`, - () => { - return { type: `ContentfulRichText` } - }, - ], -]) - -const unionsNameSet = new Set() - -const getLinkFieldType = (linkType, field, schema, createTypes) => { - // Check for validations - const validations = - field.type === `Array` ? field.items?.validations : field?.validations - - if (validations) { - // We only handle content type validations - const linkContentTypeValidation = validations.find( - ({ linkContentType }) => !!linkContentType - ) - if (linkContentTypeValidation) { - const { linkContentType } = linkContentTypeValidation - const contentTypes = Array.isArray(linkContentType) - ? linkContentType - : [linkContentType] - - // Full type names for union members, shorter variant for the union type name - const translatedTypeNames = contentTypes.map(typeName => - makeTypeName(typeName) - ) - const shortTypeNames = contentTypes.map(typeName => - makeTypeName(typeName, ``) - ) - - // Single content type - if (translatedTypeNames.length === 1) { - return { - type: translatedTypeNames.shift(), - extensions: { - link: { by: `id`, from: `${field.id}___NODE` }, - }, - } - } - - // Multiple content types - const unionName = [`UnionContentful`, ...shortTypeNames].join(``) - - if (!unionsNameSet.has(unionName)) { - unionsNameSet.add(unionName) - createTypes( - schema.buildUnionType({ - name: unionName, - types: translatedTypeNames, - }) - ) - } - - return { - type: unionName, - extensions: { - link: { by: `id`, from: `${field.id}___NODE` }, - }, - } - } - } - - return { - type: `Contentful${linkType}`, - extensions: { - link: { by: `id`, from: `${field.id}___NODE` }, - }, - } -} - -const translateFieldType = (field, schema, createTypes) => { - let fieldType - if (field.type === `Array`) { - // Arrays of Contentful Links or primitive types - const fieldData = - field.items.type === `Link` - ? getLinkFieldType(field.items.linkType, field, schema, createTypes) - : translateFieldType(field.items, schema, createTypes) - - fieldType = { ...fieldData, type: `[${fieldData.type}]` } - } else if (field.type === `Link`) { - // Contentful Link (reference) field types - fieldType = getLinkFieldType(field.linkType, field, schema, createTypes) - } else { - // Primitive field types - fieldType = ContentfulDataTypes.get(field.type)(field) - } - - // @todo what do we do when preview is enabled? Emptry required fields are valid for Contentfuls CP-API - // if (field.required) { - // fieldType.type = `${fieldType.type}!` - // } - - return fieldType -} - -export async function generateSchema({ - createTypes, - schema, - pluginConfig, - contentTypeItems, - cache, - actions, -}) { - const { getGatsbyImageFieldConfig } = await import( - `gatsby-plugin-image/graphql-utils` - ) - - // Generic Types - createTypes( - schema.buildInterfaceType({ - name: `ContentfulEntity`, - fields: { - id: { type: `ID!` }, - sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, - }, - interfaces: [`Node`], - }) - ) - - createTypes( - schema.buildInterfaceType({ - name: `ContentfulEntry`, - fields: { - id: { type: `ID!` }, - sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, - }, - interfaces: [`ContentfulEntity`, `Node`], - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulContentType`, - fields: { - id: { type: `ID!` }, - name: { type: `String!` }, - displayField: { type: `String!` }, - description: { type: `String!` }, - }, - interfaces: [`Node`], - extensions: { dontInfer: {} }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulSys`, - fields: { - id: { type: ` String!` }, - type: { type: ` String!` }, - spaceId: { type: ` String!` }, - environmentId: { type: ` String!` }, - contentType: { - type: `ContentfulContentType`, - extensions: { - link: { by: `id`, from: `contentType___NODE` }, - }, - }, - firstPublishedAt: { type: ` Date!` }, - publishedAt: { type: ` Date!` }, - publishedVersion: { type: ` Int!` }, - locale: { type: ` String!` }, - }, - interfaces: [`Node`], - extensions: { dontInfer: {} }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulMetadata`, - fields: { - tags: { - type: `[ContentfulTag]!`, - extensions: { - link: { by: `id`, from: `tags___NODE` }, - }, - }, - }, - extensions: { dontInfer: {} }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulTag`, - fields: { - name: { type: `String!` }, - contentful_id: { type: `String!` }, - id: { type: `ID!` }, - }, - interfaces: [`Node`], - extensions: { dontInfer: {} }, - }) - ) - - const { getGatsbyImageFieldConfig } = await import( - `gatsby-plugin-image/graphql-utils` - ) - - // Assets - createTypes( - addRemoteFilePolyfillInterface( - schema.buildObjectType({ - name: `ContentfulAsset`, - fields: { - id: { type: `ID!` }, - sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, - gatsbyImageData: getGatsbyImageFieldConfig( - async (...args) => resolveGatsbyImageData(...args, { cache }), - { - jpegProgressive: { - type: `Boolean`, - defaultValue: true, - }, - resizingBehavior: { - type: ImageResizingBehavior, - }, - cropFocus: { - type: ImageCropFocusType, - }, - cornerRadius: { - type: `Int`, - defaultValue: 0, - description: stripIndent` - Desired corner radius in pixels. Results in an image with rounded corners. - Pass \`-1\` for a full circle/ellipse.`, - }, - quality: { - type: `Int`, - }, - } - ), - ...(pluginConfig.get(`downloadLocal`) - ? { - localFile: { - type: `File`, - extensions: { - link: { - from: `fields.localFile`, - }, - }, - }, - } - : {}), - title: { type: `String` }, - description: { type: `String` }, - contentType: { type: `String!` }, - mimeType: { type: `String!` }, - fileName: { type: `String!` }, - url: { type: `String!` }, - size: { type: `Int` }, - width: { type: `Int` }, - height: { type: `Int` }, - }, - interfaces: [`ContentfulEntity`, `Node`], - extensions: { dontInfer: {} }, - }), - { - schema, - actions, - } - ) - ) - - // Rich Text - const makeRichTextLinksResolver = - (nodeType, entityType) => (source, args, context) => { - const links = getRichTextEntityLinks(source, nodeType)[entityType].map( - ({ id }) => id - ) - - return context.nodeModel.getAllNodes().filter( - node => - node.internal.owner === `gatsby-source-contentful` && - node?.sys?.id && - node?.sys?.type === entityType && - links.includes(node.sys.id) - // @todo how can we check for correct space and environment? We need to access the sys field of the fields parent entry. - ) - } - - // Contentful specific types - createTypes( - schema.buildObjectType({ - name: `ContentfulRichTextAssets`, - fields: { - block: { - type: `[ContentfulAsset]!`, - resolve: makeRichTextLinksResolver(`embedded-asset-block`, `Asset`), - }, - hyperlink: { - type: `[ContentfulAsset]!`, - resolve: makeRichTextLinksResolver(`asset-hyperlink`, `Asset`), - }, - }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulRichTextEntries`, - fields: { - inline: { - type: `[ContentfulEntry]!`, - resolve: makeRichTextLinksResolver(`embedded-entry-inline`, `Entry`), - }, - block: { - type: `[ContentfulEntry]!`, - resolve: makeRichTextLinksResolver(`embedded-entry-block`, `Entry`), - }, - hyperlink: { - type: `[ContentfulEntry]!`, - resolve: makeRichTextLinksResolver(`entry-hyperlink`, `Entry`), - }, - }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulRichTextLinks`, - fields: { - assets: { - type: `ContentfulRichTextAssets`, - resolve(source) { - return source - }, - }, - entries: { - type: `ContentfulRichTextEntries`, - resolve(source) { - return source - }, - }, - }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulRichText`, - fields: { - json: { - type: `JSON`, - resolve(source) { - return source - }, - }, - links: { - type: `ContentfulRichTextLinks`, - resolve(source) { - return source - }, - }, - }, - extensions: { dontInfer: {} }, - }) - ) - - // Location - createTypes( - schema.buildObjectType({ - name: `ContentfulLocation`, - fields: { - lat: { type: `Float!` }, - lon: { type: `Float!` }, - }, - extensions: { - dontInfer: {}, - }, - }) - ) - - // Text - // @todo Is there a way to have this as string and let transformer-remark replace it with an object? - createTypes( - schema.buildObjectType({ - name: `ContentfulText`, - fields: { - raw: `String!`, - }, - // @todo do we need a node interface here? - interfaces: [`Node`], - extensions: { - dontInfer: {}, - }, - }) - ) - - // Content types - for (const contentTypeItem of contentTypeItems) { - try { - const fields = {} - contentTypeItem.fields.forEach(field => { - if (field.disabled || field.omitted) { - return - } - fields[field.id] = translateFieldType(field, schema, createTypes) - }) - - const type = pluginConfig.get(`useNameForId`) - ? contentTypeItem.name - : contentTypeItem.sys.id - - createTypes( - schema.buildObjectType({ - name: makeTypeName(type), - fields: { - id: { type: `ID!` }, - sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, - ...fields, - }, - interfaces: [`ContentfulEntity`, `ContentfulEntry`, `Node`], - extensions: { dontInfer: {} }, - }) - ) - } catch (err) { - err.message = `Unable to create schema for Contentful Content Type ${ - contentTypeItem.name || contentTypeItem.sys.id - }:\n${err.message}` - console.log(err.stack) - throw err - } - } -} From b591950482a5c47def26eaade37ebd26ef343f2e Mon Sep 17 00:00:00 2001 From: axe312ger Date: Tue, 17 May 2022 12:56:32 +0200 Subject: [PATCH 042/149] fix: change contentType to mimeType and fileName to filename in assets to mirror Gatsby Image CDN config --- .../cypress/integration/media-reference.js | 4 +- e2e-tests/contentful/snapshots.js | 98 +++++++++---------- .../contentful/src/pages/gatsby-image-cdn.js | 2 +- .../src/pages/gatsby-plugin-image.js | 26 ++--- .../create-schema-customization.js.snap | 2 +- .../src/__tests__/gatsby-node.js | 4 +- .../src/__tests__/gatsby-plugin-image.js | 4 +- .../src/create-schema-customization.js | 2 +- .../src/gatsby-plugin-image.js | 30 +++--- .../src/image-helpers.js | 2 +- .../src/extend-node-type.js | 8 +- 11 files changed, 91 insertions(+), 91 deletions(-) diff --git a/e2e-tests/contentful/cypress/integration/media-reference.js b/e2e-tests/contentful/cypress/integration/media-reference.js index 7f0a38496e25c..4cf2e785c064d 100644 --- a/e2e-tests/contentful/cypress/integration/media-reference.js +++ b/e2e-tests/contentful/cypress/integration/media-reference.js @@ -7,7 +7,7 @@ describe(`media-reference`, () => { cy.get("img") .should("have.length", 2) .should("have.attr", "src") - .should("match", /^\/\/images\.ctfassets\.net/) + .should("match", /^https:\/\/images\.ctfassets\.net/) }) }) @@ -15,7 +15,7 @@ describe(`media-reference`, () => { cy.get('[data-cy-id="media-reference-one"]').within(() => { cy.get("img") .should("have.attr", "src") - .should("match", /^\/\/images\.ctfassets\.net/) + .should("match", /^https:\/\/images\.ctfassets\.net/) }) }) }) diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index ac0209ef252bb..3b7eff60852f7 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -1,118 +1,118 @@ module.exports = { - __version: "9.5.4", + "__version": "9.6.1", "content-reference": { "content-reference-many-2nd-level-loop": { - 1: '
\n

Content Reference: Many (2nd level loop)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
', + "1": "
\n

Content Reference: Many (2nd level loop)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" }, "content-reference-many-loop-a-greater-b": { - 1: '
\n

Content Reference: Many (Loop A -> B)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop B -> A)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop A ->\n B)\n ]

\n
', + "1": "
\n

Content Reference: Many (Loop A -> B)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop B -> A)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop A ->\n B)\n ]

\n
" }, "content-reference-many-loop-b-greater-a": { - 1: '
\n

Content Reference: Many (Loop B -> A)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop A -> B)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop B ->\n A)\n ]

\n
', + "1": "
\n

Content Reference: Many (Loop B -> A)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop A -> B)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop B ->\n A)\n ]

\n
" }, "content-reference-many-self-reference": { - 1: '
\n

Content Reference: Many (Self Reference)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Self Reference)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Self\n Reference)\n ]

\n
', + "1": "
\n

Content Reference: Many (Self Reference)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Self Reference)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Self\n Reference)\n ]

\n
" }, "content-reference-one": { - 1: '
\n

Content Reference: One

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n
', + "1": "
\n

Content Reference: One

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n
" }, "content-reference-one-loop-a-greater-b": { - 1: '
\n

Content Reference: One (Loop A -> B)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n
', + "1": "
\n

Content Reference: One (Loop A -> B)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n
" }, "content-reference-one-loop-b-greater-a": { - 1: '
\n

Content Reference: One (Loop B -> A)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
', + "1": "
\n

Content Reference: One (Loop B -> A)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" }, "content-reference-one-self-reference": { - 1: '
\n

Content Reference: One (Self Reference)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Self Reference)\n : [\n Content Reference: One (Self Reference)\n ]

\n
', - }, + "1": "
\n

Content Reference: One (Self Reference)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Self Reference)\n : [\n Content Reference: One (Self Reference)\n ]

\n
" + } }, "rich-text": { "rich-text: All Features": { - 1: '
\n

Rich Text: All Features

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n
\n
\n \n \n \n \n \n \n
\n

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
  7. \n

    [Inline-ContentfulText]\n Text: Short\n :\n The quick brown fox jumps over the lazy dog.

    \n
  8. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n "userId": 1,\n "id": 1,\n "title": "delectus aut autem",\n "completed": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n

[ContentfulLocation] Lat:\n 52.51627\n , Long:\n 13.3777

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
', + "1": "
\n

Rich Text: All Features

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n
\"\"\n\n
\n
\n \n \n \"\"\n\n \n \n
\n

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
  7. \n

    [Inline-ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

    \n
  8. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n

[ContentfulContentTypeLocation] Lat:\n 52.51627\n , Long:\n 13.3777

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
" }, "rich-text: Basic": { - 1: '
\n

Rich Text: Basic

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n "userId": 1,\n "id": 1,\n "title": "delectus aut autem",\n "completed": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
', + "1": "
\n

Rich Text: Basic

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
" }, "rich-text: Embedded Entry": { - 1: '
\n

Rich Text: Embedded Entry

\n

Embedded Entry

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

\n

\n
\n
', + "1": "
\n

Rich Text: Embedded Entry

\n

Embedded Entry

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

\n

\n
\n
" }, "rich-text: Embedded Asset": { - 1: '
\n

Rich Text: Embedded asset

\n

Embedded Asset

\n
\n
\n
\n \n \n \n \n \n \n
\n

\n

\n

\n
\n
', + "1": "
\n

Rich Text: Embedded asset

\n

Embedded Asset

\n
\n
\"\"\n\n
\n
\n \n \n \"\"\n\n \n \n
\n

\n

\n

\n
\n
" }, "rich-text: Embedded Entry With Deep Reference Loop": { - 1: '
\n

Rich Text: Embedded entry with deep reference loop

\n

Embedded entry with deep reference loop

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (2nd level loop)\n : [\n Number: Integer, Text: Short, Content Reference: One (Loop A ->\n B)\n ]

\n

\n

\n
\n
', + "1": "
\n

Rich Text: Embedded entry with deep reference loop

\n

Embedded entry with deep reference loop

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (2nd level loop)\n : [\n Number: Integer, Text: Short, Content Reference: One (Loop A ->\n B)\n ]

\n

\n

\n
\n
" }, "rich-text: Embedded Entry With Reference Loop": { - 1: '
\n

Rich Text: Embedded entry with reference loop

\n

Embedded entry with reference loop

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n

\n
\n
', + "1": "
\n

Rich Text: Embedded entry with reference loop

\n

Embedded entry with reference loop

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n

\n
\n
" }, "rich-text: Inline Entry": { - 1: '
\n

Rich Text: Inline entry

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog. and before\n that

\n

\n

\n
\n
', + "1": "
\n

Rich Text: Inline entry

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog. and before\n that

\n

\n

\n
\n
" }, "rich-text: Inline Entry With Deep Reference Loop": { - 1: '
\n

Rich Text: Inline entry with deep reference loop

\n

Inline entry with deep reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeContentReference\n ] and before that

\n

\n

\n
\n
', + "1": "
\n

Rich Text: Inline entry with deep reference loop

\n

Inline entry with deep reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeContentReference\n ] and before that

\n

\n

\n
\n
" }, "rich-text: Inline Entry With Reference Loop": { - 1: '
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeContentReference\n ] and before that

\n

\n

\n
\n
', + "1": "
\n

Rich Text: Inline entry with reference loop

\n

Inline entry with reference loop

\n

Should be rendered after this [Inline-\n ContentfulContentTypeContentReference\n ] and before that

\n

\n

\n
\n
" }, "rich-text: Localized": { - 1: '
\n

Rich Text: Localized

\n

Rich Text in English

\n
\n
', - 2: '
\n

Rich Text: Localized

\n

Reichhaltiger Text in deutscher\n Sprache

\n
\n
', + "1": "
\n

Rich Text: Localized

\n

Rich Text in English

\n
\n
", + "2": "
\n

Rich Text: Localized

\n

Reichhaltiger Text in deutscher\n Sprache

\n
\n
" }, "rich-text: Tables": { - 1: '
\n

Rich Text: Tables

\n

Table test

\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n

Heading One

\n
\n

Heading Two

\n
\n

Heading Three

\n
\n

\n
\n

This should be fat

\n
\n

Baz

\n
\n

\n
\n
', - }, + "1": "
\n

Rich Text: Tables

\n

Table test

\n

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n

Heading One

\n
\n

Heading Two

\n
\n

Heading Three

\n
\n

\n
\n

This should be fat

\n
\n

Baz

\n
\n

\n
\n
" + } }, - text: { + "text": { "text: Short List": { - 1: '
\n
    \n
  • The quick brown fox
  • \n
  • jumps over the lazy dog
  • \n
\n
', + "1": "
\n
    \n
  • The quick brown fox
  • \n
  • jumps over the lazy dog
  • \n
\n
" }, "text: Long Markdown Simple": { - 1: '
\n

Headline

\n

The European languages are members of the same family.\n Their separate existence is a myth. For:

\n
    \n
  • science
  • \n
  • music
  • \n
  • sport
  • \n
  • etc
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.

\n
\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
', + "1": "
\n

Headline

\n

The European languages are members of the same family.\n Their separate existence is a myth. For:

\n
    \n
  • science
  • \n
  • music
  • \n
  • sport
  • \n
  • etc
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.

\n
\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
" }, "text: Long Markdown Complex": { - 1: '
\n

Headline Complex

\n

The European languages are members of the same family. Their\n separate existence is a myth. For:

\n
    \n
  • science
  • \n
  • music
  • \n
  • sport
  • \n
  • etc
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.

\n
\n

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
{\n\t"userId": 1,\n\t"id": 1,\n\t"title": "delectus aut autem",\n\t"completed": false\n}\n
\n
', + "1": "
\n

Headline Complex

\n

The European languages are members of the same family. Their\n separate existence is a myth. For:

\n
    \n
  • science
  • \n
  • music
  • \n
  • sport
  • \n
  • etc
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.

\n
\n

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
{\n\t\"userId\": 1,\n\t\"id\": 1,\n\t\"title\": \"delectus aut autem\",\n\t\"completed\": false\n}\n
\n
" }, "text: Long Localized": { - 1: '
\n

One morning, when Gregor Samsa woke from troubled\n dreams, he found himself transformed in his bed into a horrible vermin. He\n lay on his armour-like back, and if he lifted his head a little he could see\n his brown belly, slightly domed and divided by arches into stiff sections.\n The bedding was hardly able to cover it and seemed ready to slide off any\n moment. His many legs, pitifully thin compared with the size of the rest of\n him, waved about helplessly as he looked. "What\'s happened to me?" he\n thought.\n\n It wasn\'t a dream. His room, a proper human room although a little too\n small, lay peacefully between its four familiar walls. A collection of\n textile samples lay spread out on the table - Samsa was a travelling\n salesman - and above it there hung a picture that he had recently cut out of\n an illustrated magazine and housed in a nice, gilded frame. It showed a lady\n fitted out with a fur hat and fur boa who sat upright, raising a heavy fur\n muff that covered the whole of her lower arm towards the viewer. Gregor then\n turned to look out the window at the dull weather.

\n
', - 2: '
\n

Jemand musste Josef K. verleumdet haben, denn ohne\n dass er etwas Böses getan hätte, wurde er eines Morgens verhaftet. »Wie ein\n Hund!« sagte er, es war, als sollte die Scham ihn überleben. Als Gregor\n Samsa eines Morgens aus unruhigen Träumen erwachte, fand er sich in seinem\n Bett zu einem ungeheueren Ungeziefer verwandelt. Und es war ihnen wie eine\n Bestätigung ihrer neuen Träume und guten Absichten, als am Ziele ihrer Fahrt\n die Tochter als erste sich erhob und ihren jungen Körper dehnte.\n\n »Es ist ein eigentümlicher Apparat«, sagte der Offizier zu dem\n Forschungsreisenden und überblickte mit einem gewissermaßen bewundernden\n Blick den ihm doch wohlbekannten Apparat. Sie hätten noch ins Boot springen\n können, aber der Reisende hob ein schweres, geknotetes Tau vom Boden, drohte\n ihnen damit und hielt sie dadurch von dem Sprunge ab. In den letzten\n Jahrzehnten ist das Interesse an Hungerkünstlern sehr zurückgegangen. Aber\n sie überwanden sich, umdrängten den Käfig und wollten sich gar nicht\n fortrühren.Jemand musste Josef K. verleumdet haben, denn ohne dass er etwas\n Böses getan hätte, wurde er eines Morgens verhaftet. »Wie ein Hund!« sagte\n er, es war, als sollte die Scham ihn überleben. Als Gregor Samsa eines\n Morgens aus unruhigen Träumen erwachte, fand er sich

\n
', - }, + "1": "
\n

One morning, when Gregor Samsa woke from troubled\n dreams, he found himself transformed in his bed into a horrible vermin. He\n lay on his armour-like back, and if he lifted his head a little he could see\n his brown belly, slightly domed and divided by arches into stiff sections.\n The bedding was hardly able to cover it and seemed ready to slide off any\n moment. His many legs, pitifully thin compared with the size of the rest of\n him, waved about helplessly as he looked. \"What's happened to me?\" he\n thought.\n\n It wasn't a dream. His room, a proper human room although a little too\n small, lay peacefully between its four familiar walls. A collection of\n textile samples lay spread out on the table - Samsa was a travelling\n salesman - and above it there hung a picture that he had recently cut out of\n an illustrated magazine and housed in a nice, gilded frame. It showed a lady\n fitted out with a fur hat and fur boa who sat upright, raising a heavy fur\n muff that covered the whole of her lower arm towards the viewer. Gregor then\n turned to look out the window at the dull weather.

\n
", + "2": "
\n

Jemand musste Josef K. verleumdet haben, denn ohne\n dass er etwas Böses getan hätte, wurde er eines Morgens verhaftet. »Wie ein\n Hund!« sagte er, es war, als sollte die Scham ihn überleben. Als Gregor\n Samsa eines Morgens aus unruhigen Träumen erwachte, fand er sich in seinem\n Bett zu einem ungeheueren Ungeziefer verwandelt. Und es war ihnen wie eine\n Bestätigung ihrer neuen Träume und guten Absichten, als am Ziele ihrer Fahrt\n die Tochter als erste sich erhob und ihren jungen Körper dehnte.\n\n »Es ist ein eigentümlicher Apparat«, sagte der Offizier zu dem\n Forschungsreisenden und überblickte mit einem gewissermaßen bewundernden\n Blick den ihm doch wohlbekannten Apparat. Sie hätten noch ins Boot springen\n können, aber der Reisende hob ein schweres, geknotetes Tau vom Boden, drohte\n ihnen damit und hielt sie dadurch von dem Sprunge ab. In den letzten\n Jahrzehnten ist das Interesse an Hungerkünstlern sehr zurückgegangen. Aber\n sie überwanden sich, umdrängten den Käfig und wollten sich gar nicht\n fortrühren.Jemand musste Josef K. verleumdet haben, denn ohne dass er etwas\n Böses getan hätte, wurde er eines Morgens verhaftet. »Wie ein Hund!« sagte\n er, es war, als sollte die Scham ihn überleben. Als Gregor Samsa eines\n Morgens aus unruhigen Träumen erwachte, fand er sich

\n
" + } }, - json: { + "json": { "json: Complex": { - 1: '
\n

Name:\n Tom Cruise

\n

Photo:\n https://jsonformatter.org/img/tom-cruise.jpg

\n

Birthdate:\n 1962-7-3T00:12:34.000Z

\n

Born at:\n Syracuse, NY

\n

Weight:\n 67.5

\n

Age:\n 56

\n

Wife:

\n

Children:\n Suri, Isabella Jane, Connor

\n

Has children:\n true

\n

Has grey hair:\n false

\n
', - 2: '
\n

Name:\n Robert Downey Jr.

\n

Photo:\n https://jsonformatter.org/img/Robert-Downey-Jr.jpg

\n

Birthdate:\n 1965-4-4T00:12:34.000Z

\n

Born at:\n New York City, NY

\n

Weight:\n 77.1

\n

Age:\n 53

\n

Wife:\n Susan Downey

\n

Children:\n Indio Falconer, Avri Roel, Exton Elias

\n

Has children:\n true

\n

Has grey hair:\n false

\n
', - }, + "1": "
\n

Name:\n Tom Cruise

\n

Photo:\n https://jsonformatter.org/img/tom-cruise.jpg

\n

Birthdate:\n 1962-7-3T00:12:34.000Z

\n

Born at:\n Syracuse, NY

\n

Weight:\n 67.5

\n

Age:\n 56

\n

Wife:

\n

Children:\n Suri, Isabella Jane, Connor

\n

Has children:\n true

\n

Has grey hair:\n false

\n
", + "2": "
\n

Name:\n Robert Downey Jr.

\n

Photo:\n https://jsonformatter.org/img/Robert-Downey-Jr.jpg

\n

Birthdate:\n 1965-4-4T00:12:34.000Z

\n

Born at:\n New York City, NY

\n

Weight:\n 77.1

\n

Age:\n 53

\n

Wife:\n Susan Downey

\n

Children:\n Indio Falconer, Avri Roel, Exton Elias

\n

Has children:\n true

\n

Has grey hair:\n false

\n
" + } }, "content-reference localized": { "english-content-reference-one-localized": { - 1: '
\n

Content Reference: One Localized

\n

[ContentfulContentTypeNumber]\n 42

\n
', + "1": "
\n

Content Reference: One Localized

\n

[ContentfulContentTypeNumber]\n 42

\n
" }, "english-content-reference-many-localized": { - 1: '
\n

Content Reference: Many Localized

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeNumber]\n 42

\n
', + "1": "
\n

Content Reference: Many Localized

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeNumber]\n 42

\n
" }, "german-content-reference-one-localized": { - 1: '
\n

Content Reference: One Localized

\n

[ContentfulContentTypeNumber]\n 4.2

\n
', + "1": "
\n

Content Reference: One Localized

\n

[ContentfulContentTypeNumber]\n 4.2

\n
" }, "german-content-reference-many-localized": { - 1: '
\n

Content Reference: Many Localized

\n

[ContentfulContentTypeNumber]\n 4.2

\n

[ContentfulContentTypeText]\n The European languages are members of the same family. Their\n separate existence is a myth. For science, music, sport, etc, Europe uses\n the same vocabulary.\n\n The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.\n\n To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
', - }, + "1": "
\n

Content Reference: Many Localized

\n

[ContentfulContentTypeNumber]\n 4.2

\n

[ContentfulContentTypeText]\n The European languages are members of the same family. Their\n separate existence is a myth. For science, music, sport, etc, Europe uses\n the same vocabulary.\n\n The languages only differ in their grammar, their pronunciation and their\n most common words. Everyone realizes why a new common language would be\n desirable: one could refuse to pay expensive translators.\n\n To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words. If several languages coalesce, the\n grammar of the resulting language is more simple and regular than that of\n the individual languages. The new common language will be more simple and\n regular than the existing European languages. It will be as simple as\n Occidental; in fact, it will be.

\n
" + } }, "media-reference localized": { "media-reference: many with localized field": { - 1: '
\n

Media Reference: Many Localized Field

\n
', - 2: '
\n

Media Reference: Many Localized Field

\n
', + "1": "
\n

Media Reference: Many Localized Field

\n
", + "2": "
\n

Media Reference: Many Localized Field

\n
" }, "media-reference: many with localized asset": { - 1: '
\n

Media Reference: Many With Localized Asset

\n
', - 2: '
\n

Media Reference: Many With Localized Asset

\n
', + "1": "
\n

Media Reference: Many With Localized Asset

\n
", + "2": "
\n

Media Reference: Many With Localized Asset

\n
" }, "media-reference: one with localized asset": { - 1: '
\n

Media Reference: One Localized Asset

\n
', - 2: '
\n

Media Reference: One Localized Asset

\n
', + "1": "
\n

Media Reference: One Localized Asset

\n
", + "2": "
\n

Media Reference: One Localized Asset

\n
" }, "media-reference: one with localized field": { - 1: '
\n

Media Reference: One Localized Field

\n
', - 2: '
\n

Media Reference: One Localized Field

\n
', - }, - }, + "1": "
\n

Media Reference: One Localized Field

\n
", + "2": "
\n

Media Reference: One Localized Field

\n
" + } + } } diff --git a/e2e-tests/contentful/src/pages/gatsby-image-cdn.js b/e2e-tests/contentful/src/pages/gatsby-image-cdn.js index 967a30cf6dd79..d207507f02baf 100644 --- a/e2e-tests/contentful/src/pages/gatsby-image-cdn.js +++ b/e2e-tests/contentful/src/pages/gatsby-image-cdn.js @@ -26,7 +26,7 @@ export const pageQuery = graphql` ) { title description - fileName + filename url gatsbyImage(width: 420) } diff --git a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js index 0330f8f106ebf..f9dfc6768ceb7 100644 --- a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js +++ b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js @@ -16,7 +16,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.fileName.split(".").pop()}) + {node.title} ({node.filename.split(".").pop()})

{node.description &&

{node.description}

} @@ -34,7 +34,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.fileName.split(".").pop()}) + {node.title} ({node.filename.split(".").pop()})

{node.description &&

{node.description}

} @@ -53,7 +53,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.fileName.split(".").pop()}) + {node.title} ({node.filename.split(".").pop()})

{node.description &&

{node.description}

} @@ -72,7 +72,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.fileName.split(".").pop()}) + {node.title} ({node.filename.split(".").pop()})

{node.description &&

{node.description}

} @@ -91,7 +91,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.fileName.split(".").pop()}) + {node.title} ({node.filename.split(".").pop()})

{node.description &&

{node.description}

} @@ -110,7 +110,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.fileName.split(".").pop()}) + {node.title} ({node.filename.split(".").pop()})

{node.description &&

{node.description}

} @@ -129,7 +129,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.fileName.split(".").pop()}) + {node.title} ({node.filename.split(".").pop()})

{node.description &&

{node.description}

} @@ -148,7 +148,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.fileName.split(".").pop()}) + {node.title} ({node.filename.split(".").pop()})

{node.description &&

{node.description}

} @@ -174,7 +174,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.fileName.split(".").pop()}) + {node.title} ({node.filename.split(".").pop()})

{node.description &&

{node.description}

} @@ -193,7 +193,7 @@ const GatsbyPluginImagePage = ({ data }) => {

- {node.title} ({node.fileName.split(".").pop()}) + {node.title} ({node.filename.split(".").pop()})

{node.description &&

{node.description}

} @@ -231,7 +231,7 @@ export const pageQuery = graphql` nodes { title description - fileName + filename url constrained: gatsbyImageData(width: 420) fullWidth: gatsbyImageData(width: 200, layout: FIXED) @@ -266,7 +266,7 @@ export const pageQuery = graphql` nodes { title description - fileName + filename url constrained: gatsbyImageData(width: 420) } @@ -280,7 +280,7 @@ export const pageQuery = graphql` nodes { title description - fileName + filename url constrained: gatsbyImageData(width: 420) } diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index d5bc0eb7c84cb..96b783fd4e6de 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -126,7 +126,7 @@ Array [ "description": Object { "type": "String", }, - "fileName": Object { + "filename": Object { "type": "String!", }, "gatsbyImageData": Object { diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 6187cf1b11921..73f09497ba93d 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -388,8 +388,8 @@ describe(`gatsby-node`, () => { true, noLocaleFallback ) || ``, - contentType: file.contentType, - fileName: file.fileName, + mimeType: file.contentType, + filename: file.fileName, url: `https:` + file.url, size: file.details.size, width: file.details?.image?.width || null, diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js index 176963bcbddda..c9f7b88521092 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js @@ -42,8 +42,8 @@ const exampleImage = { locale: `en-US`, }, url: `https://images.ctfassets.net:443/k8iqpp6u0ior/3ljGfnpegOnBTFGhV07iC1/94257340bda15ad4ca8462da3a8afa07/347966-contentful-logo-wordmark-dark__1_-4cd185-original-1582664935__1_.png`, - fileName: `347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png`, - contentType: `image/png`, + filename: `347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png`, + mimeType: `image/png`, size: 123456, width: `1646`, height: `338`, diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.js b/packages/gatsby-source-contentful/src/create-schema-customization.js index 21648b7bec966..fecba72ebcd57 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.js +++ b/packages/gatsby-source-contentful/src/create-schema-customization.js @@ -376,7 +376,7 @@ export async function createSchemaCustomization( description: { type: `String` }, contentType: { type: `String!` }, mimeType: { type: `String!` }, - fileName: { type: `String!` }, + filename: { type: `String!` }, url: { type: `String!` }, size: { type: `Int` }, width: { type: `Int` }, diff --git a/packages/gatsby-source-contentful/src/gatsby-plugin-image.js b/packages/gatsby-source-contentful/src/gatsby-plugin-image.js index 5582e20c51ddc..d5c31cd6a8709 100644 --- a/packages/gatsby-source-contentful/src/gatsby-plugin-image.js +++ b/packages/gatsby-source-contentful/src/gatsby-plugin-image.js @@ -29,7 +29,7 @@ const getBase64Image = (imageProps, cache) => { // Keep aspect ratio, image format and other transform options const { aspectRatio } = imageProps - const originalFormat = imageProps.image.contentType.split(`/`)[1] + const originalFormat = imageProps.image.mimeType.split(`/`)[1] const toFormat = imageProps.options.toFormat const imageOptions = { ...imageProps.options, @@ -53,9 +53,9 @@ const getBase64Image = (imageProps, cache) => { } const loadImage = async () => { - const { contentType } = imageProps.image + const { mimeType } = imageProps.image - const extension = mimeTypeExtensions.get(contentType) + const extension = mimeTypeExtensions.get(mimeType) const absolutePath = await fetchRemoteFile({ url: requestUrl, @@ -80,15 +80,15 @@ const getBase64Image = (imageProps, cache) => { const getTracedSVG = async ({ image, options, cache }) => { const { traceSVG } = await import(`gatsby-plugin-sharp`) - const { url: imgUrl, fileName, contentType } = image + const { url: imgUrl, filename, mimeType } = image - if (contentType.indexOf(`image/`) !== 0) { + if (mimeType.indexOf(`image/`) !== 0) { return null } - const extension = mimeTypeExtensions.get(contentType) + const extension = mimeTypeExtensions.get(mimeType) const url = createUrl(imgUrl, options) - const name = path.basename(fileName, extension) + const name = path.basename(filename, extension) const absolutePath = await fetchRemoteFile({ url, @@ -101,7 +101,7 @@ const getTracedSVG = async ({ image, options, cache }) => { return traceSVG({ file: { internal: image.internal, - name: fileName, + name: filename, extension, absolutePath, }, @@ -124,9 +124,9 @@ const getDominantColor = async ({ image, options, cache }) => { } try { - const { contentType, url: imgUrl, fileName } = image + const { mimeType, url: imgUrl, filename } = image - if (contentType.indexOf(`image/`) !== 0) { + if (mimeType.indexOf(`image/`) !== 0) { return null } @@ -135,9 +135,9 @@ const getDominantColor = async ({ image, options, cache }) => { options.width = 256 } - const extension = mimeTypeExtensions.get(contentType) + const extension = mimeTypeExtensions.get(mimeType) const url = createUrl(imgUrl, options) - const name = path.basename(fileName, extension) + const name = path.basename(filename, extension) const absolutePath = await fetchRemoteFile({ url, @@ -174,7 +174,7 @@ function getBasicImageProps(image, args) { return { baseUrl: image.url, - contentType: image.contentType, + mimeType: image.mimeType, aspectRatio: width / height, width, height, @@ -277,11 +277,11 @@ export async function resolveGatsbyImageData( options = doMergeDefaults(options, defaults) - const { baseUrl, contentType, width, height } = getBasicImageProps( + const { baseUrl, mimeType, width, height } = getBasicImageProps( image, options ) - let [, format] = contentType.split(`/`) + let [, format] = mimeType.split(`/`) if (format === `jpeg`) { format = `jpg` } diff --git a/packages/gatsby-source-contentful/src/image-helpers.js b/packages/gatsby-source-contentful/src/image-helpers.js index 230bc85364255..92bdcb7c3ddc6 100644 --- a/packages/gatsby-source-contentful/src/image-helpers.js +++ b/packages/gatsby-source-contentful/src/image-helpers.js @@ -20,7 +20,7 @@ export const mimeTypeExtensions = new Map([ // Check if Contentful asset is actually an image export function isImage(image) { - return mimeTypeExtensions.has(image?.contentType) + return mimeTypeExtensions.has(image?.mimeType) } // Create a Contentful Image API url diff --git a/packages/gatsby-transformer-sqip/src/extend-node-type.js b/packages/gatsby-transformer-sqip/src/extend-node-type.js index 5033b66c54c65..5e5fbf36454aa 100644 --- a/packages/gatsby-transformer-sqip/src/extend-node-type.js +++ b/packages/gatsby-transformer-sqip/src/extend-node-type.js @@ -194,9 +194,9 @@ async function sqipContentful({ type, cache, store }) { mimeTypeExtensions, } = require(`gatsby-source-contentful/image-helpers`) - const { contentType, url: imgUrl, fileName } = asset + const { mimeType, url: imgUrl, filename } = asset - if (!contentType.includes(`image/`)) { + if (!mimeType.includes(`image/`)) { return null } @@ -224,9 +224,9 @@ async function sqipContentful({ type, cache, store }) { background, } - const extension = mimeTypeExtensions.get(contentType) + const extension = mimeTypeExtensions.get(mimeType) const url = createUrl(imgUrl, options) - const name = path.basename(fileName, extension) + const name = path.basename(filename, extension) const absolutePath = await fetchRemoteFile({ url, From bdfcdd470f7af7e99e74bf7b9f4fa0bae189b5f8 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Fri, 25 Mar 2022 15:21:50 +0100 Subject: [PATCH 043/149] fix: allow assets without files for preview --- .../create-schema-customization.js.snap | 2 +- .../src/create-schema-customization.js | 54 ++++++++++--------- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index 96b783fd4e6de..fdf69748fd88a 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -215,7 +215,7 @@ Ignored if layout = FLUID.", }, }, "resolve": [Function], - "type": "JSON!", + "type": "JSON", }, "height": Object { "type": "Int", diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.js b/packages/gatsby-source-contentful/src/create-schema-customization.js index fecba72ebcd57..155a34a553dbf 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.js +++ b/packages/gatsby-source-contentful/src/create-schema-customization.js @@ -326,6 +326,33 @@ export async function createSchemaCustomization( ) // Assets + const gatsbyImageData = getGatsbyImageFieldConfig( + async (...args) => resolveGatsbyImageData(...args, { cache }), + { + jpegProgressive: { + type: `Boolean`, + defaultValue: true, + }, + resizingBehavior: { + type: ImageResizingBehavior, + }, + cropFocus: { + type: ImageCropFocusType, + }, + cornerRadius: { + type: `Int`, + defaultValue: 0, + description: stripIndent` + Desired corner radius in pixels. Results in an image with rounded corners. + Pass \`-1\` for a full circle/ellipse.`, + }, + quality: { + type: `Int`, + defaultValue: 50, + }, + } + ) + gatsbyImageData.type = `JSON` createTypes( addRemoteFilePolyfillInterface( schema.buildObjectType({ @@ -334,32 +361,7 @@ export async function createSchemaCustomization( id: { type: `ID!` }, sys: { type: `ContentfulSys!` }, metadata: { type: `ContentfulMetadata!` }, - gatsbyImageData: getGatsbyImageFieldConfig( - async (...args) => resolveGatsbyImageData(...args, { cache }), - { - jpegProgressive: { - type: `Boolean`, - defaultValue: true, - }, - resizingBehavior: { - type: ImageResizingBehavior, - }, - cropFocus: { - type: ImageCropFocusType, - }, - cornerRadius: { - type: `Int`, - defaultValue: 0, - description: stripIndent` - Desired corner radius in pixels. Results in an image with rounded corners. - Pass \`-1\` for a full circle/ellipse.`, - }, - quality: { - type: `Int`, - defaultValue: 50, - }, - } - ), + gatsbyImageData, ...(pluginConfig.get(`downloadLocal`) ? { localFile: { From 7ea4514ecbc7935726c83a0b6cc88a8029427d23 Mon Sep 17 00:00:00 2001 From: axe312ger Date: Fri, 25 Mar 2022 15:46:28 +0100 Subject: [PATCH 044/149] feat: throw error on reservated field names --- .../src/create-schema-customization.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.js b/packages/gatsby-source-contentful/src/create-schema-customization.js index 155a34a553dbf..084d5210059c2 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.js +++ b/packages/gatsby-source-contentful/src/create-schema-customization.js @@ -527,6 +527,13 @@ export async function createSchemaCustomization( if (field.disabled || field.omitted) { return } + if ([`id`, `sys`, `contentfulMetadata`].includes(field.id)) { + // Throw error on reserved field names as the Contenful GraphQL API does: + // https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/fields + throw new Error( + `Unfortunately the field name ${field.id} is reserved. ${contentTypeItem.name}@${contentTypeItem.sys.id}` + ) + } fields[field.id] = translateFieldType(field, schema, createTypes) }) From 414d2b66569f6d8e6ae2c838f1ff3ad0a9002f21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 9 Nov 2022 15:59:54 +0100 Subject: [PATCH 045/149] style: update contentful e2e test filter syntax --- e2e-tests/contentful/src/pages/boolean.js | 6 +++--- e2e-tests/contentful/src/pages/content-reference.js | 6 +++--- e2e-tests/contentful/src/pages/gatsby-plugin-image.js | 6 +++--- e2e-tests/contentful/src/pages/location.js | 6 +++--- e2e-tests/contentful/src/pages/media-reference.js | 6 +++--- e2e-tests/contentful/src/pages/number.js | 6 +++--- e2e-tests/contentful/src/pages/rich-text.js | 6 +++--- e2e-tests/contentful/src/pages/tags.js | 8 ++++---- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/e2e-tests/contentful/src/pages/boolean.js b/e2e-tests/contentful/src/pages/boolean.js index a1392f06d065d..f3cd3ee6cb3cf 100644 --- a/e2e-tests/contentful/src/pages/boolean.js +++ b/e2e-tests/contentful/src/pages/boolean.js @@ -50,7 +50,7 @@ export default BooleanPage export const pageQuery = graphql` query BooleanQuery { default: allContentfulContentTypeBoolean( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { sys: { locale: { eq: "en-US" } } booleanLocalized: { eq: null } @@ -62,7 +62,7 @@ export const pageQuery = graphql` } } english: allContentfulContentTypeBoolean( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { sys: { locale: { eq: "en-US" } } booleanLocalized: { ne: null } @@ -74,7 +74,7 @@ export const pageQuery = graphql` } } german: allContentfulContentTypeBoolean( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { sys: { locale: { eq: "de-DE" } } booleanLocalized: { ne: null } diff --git a/e2e-tests/contentful/src/pages/content-reference.js b/e2e-tests/contentful/src/pages/content-reference.js index d31fdb8f8b14b..d6eafd04803c8 100644 --- a/e2e-tests/contentful/src/pages/content-reference.js +++ b/e2e-tests/contentful/src/pages/content-reference.js @@ -96,7 +96,7 @@ export default ContentReferencePage export const pageQuery = graphql` query ContentReferenceQuery { default: allContentfulContentTypeContentReference( - sort: { fields: title } + sort: { title: ASC } filter: { sys: { locale: { eq: "en-US" } } title: { glob: "!*Localized*" } @@ -205,7 +205,7 @@ export const pageQuery = graphql` } } english: allContentfulContentTypeContentReference( - sort: { fields: title } + sort: { title: ASC } filter: { sys: { locale: { eq: "en-US" } } title: { glob: "*Localized*" } @@ -242,7 +242,7 @@ export const pageQuery = graphql` } } german: allContentfulContentTypeContentReference( - sort: { fields: title } + sort: { title: ASC } filter: { sys: { locale: { eq: "de-DE" } } title: { glob: "*Localized*" } diff --git a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js index 405967ac1e0d8..287fada23c589 100644 --- a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js +++ b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js @@ -244,7 +244,7 @@ export const pageQuery = graphql` locale: { eq: "en-US" } } } - sort: { fields: sys___id } + sort: { sys: { id: ASC } } ) { nodes { title @@ -279,7 +279,7 @@ export const pageQuery = graphql` filter: { sys: { id: { in: ["4FwygYxkL3rAteERtoxxNC"] }, locale: { eq: "en-US" } } } - sort: { fields: sys___id } + sort: { sys: { id: ASC } } ) { nodes { title @@ -293,7 +293,7 @@ export const pageQuery = graphql` filter: { sys: { id: { in: ["4FwygYxkL3rAteERtoxxNC"] }, locale: { eq: "de-DE" } } } - sort: { fields: sys___id } + sort: { sys: { id: ASC } } ) { nodes { title diff --git a/e2e-tests/contentful/src/pages/location.js b/e2e-tests/contentful/src/pages/location.js index 9314b17fabdc4..a6e2d79cc2678 100644 --- a/e2e-tests/contentful/src/pages/location.js +++ b/e2e-tests/contentful/src/pages/location.js @@ -57,7 +57,7 @@ export default LocationPage export const pageQuery = graphql` query LocationQuery { default: allContentfulContentTypeLocation( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { title: { glob: "!*Localized*" } sys: { locale: { eq: "en-US" } } @@ -72,7 +72,7 @@ export const pageQuery = graphql` } } english: allContentfulContentTypeLocation( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { title: { glob: "*Localized*" } sys: { locale: { eq: "en-US" } } @@ -87,7 +87,7 @@ export const pageQuery = graphql` } } german: allContentfulContentTypeLocation( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { title: { glob: "*Localized*" } sys: { locale: { eq: "de-DE" } } diff --git a/e2e-tests/contentful/src/pages/media-reference.js b/e2e-tests/contentful/src/pages/media-reference.js index f521c3747450c..ba42852411f3f 100644 --- a/e2e-tests/contentful/src/pages/media-reference.js +++ b/e2e-tests/contentful/src/pages/media-reference.js @@ -113,7 +113,7 @@ export default MediaReferencePage export const pageQuery = graphql` query MediaReferenceQuery { default: allContentfulContentTypeMediaReference( - sort: { fields: title } + sort: { title: ASC } filter: { title: { glob: "!*Localized*" } sys: { locale: { eq: "en-US" } } @@ -133,7 +133,7 @@ export const pageQuery = graphql` } } english: allContentfulContentTypeMediaReference( - sort: { fields: title } + sort: { title: ASC } filter: { title: { glob: "*Localized*" } sys: { locale: { eq: "en-US" } } @@ -159,7 +159,7 @@ export const pageQuery = graphql` } } german: allContentfulContentTypeMediaReference( - sort: { fields: title } + sort: { title: ASC } filter: { title: { glob: "*Localized*" } sys: { locale: { eq: "de-DE" } } diff --git a/e2e-tests/contentful/src/pages/number.js b/e2e-tests/contentful/src/pages/number.js index e5d5dc2cc8066..57af867470887 100644 --- a/e2e-tests/contentful/src/pages/number.js +++ b/e2e-tests/contentful/src/pages/number.js @@ -54,7 +54,7 @@ export default NumberPage export const pageQuery = graphql` query NumberQuery { default: allContentfulContentTypeNumber( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { title: { glob: "!*Localized*" } sys: { locale: { eq: "en-US" } } @@ -67,7 +67,7 @@ export const pageQuery = graphql` } } english: allContentfulContentTypeNumber( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { title: { glob: "*Localized*" } sys: { locale: { eq: "en-US" } } @@ -80,7 +80,7 @@ export const pageQuery = graphql` } } german: allContentfulContentTypeNumber( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { title: { glob: "*Localized*" } sys: { locale: { eq: "de-DE" } } diff --git a/e2e-tests/contentful/src/pages/rich-text.js b/e2e-tests/contentful/src/pages/rich-text.js index 33c360059c08f..0ce1fdadf460d 100644 --- a/e2e-tests/contentful/src/pages/rich-text.js +++ b/e2e-tests/contentful/src/pages/rich-text.js @@ -115,7 +115,7 @@ export default RichTextPage export const pageQuery = graphql` query RichTextQuery { default: allContentfulContentTypeRichText( - sort: { fields: title } + sort: { title: ASC } filter: { title: { glob: "!*Localized*|*Validated*" } sys: { locale: { eq: "en-US" } } @@ -227,7 +227,7 @@ export const pageQuery = graphql` } } english: allContentfulContentTypeRichText( - sort: { fields: title } + sort: { title: ASC } filter: { title: { glob: "*Localized*" } sys: { locale: { eq: "en-US" } } @@ -242,7 +242,7 @@ export const pageQuery = graphql` } } german: allContentfulContentTypeRichText( - sort: { fields: title } + sort: { title: ASC } filter: { title: { glob: "*Localized*" } sys: { locale: { eq: "de-DE" } } diff --git a/e2e-tests/contentful/src/pages/tags.js b/e2e-tests/contentful/src/pages/tags.js index 7af26c1113330..376c07540b324 100644 --- a/e2e-tests/contentful/src/pages/tags.js +++ b/e2e-tests/contentful/src/pages/tags.js @@ -92,14 +92,14 @@ export default TagsPage export const pageQuery = graphql` query TagsQuery { - tags: allContentfulTag(sort: { fields: id }) { + tags: allContentfulTag(sort: { id: ASC }) { nodes { name contentful_id } } integers: allContentfulContentTypeNumber( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { metadata: { tags: { elemMatch: { contentful_id: { eq: "numberInteger" } } } @@ -113,7 +113,7 @@ export const pageQuery = graphql` } } decimals: allContentfulContentTypeNumber( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { metadata: { tags: { elemMatch: { contentful_id: { eq: "numberDecimal" } } } @@ -127,7 +127,7 @@ export const pageQuery = graphql` } } assets: allContentfulAsset( - sort: { fields: sys___id } + sort: { sys: { id: ASC } } filter: { metadata: { tags: { elemMatch: { contentful_id: { eq: "animal" } } } } sys: { locale: { eq: "en-US" } } From 12f3a7e65902ad5d4ecfdf2b06d8153c58f2a1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 9 Nov 2022 16:38:34 +0100 Subject: [PATCH 046/149] test(e2e): update snapshot version --- e2e-tests/contentful/snapshots.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index 3b7eff60852f7..bf42f490030b7 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -1,5 +1,5 @@ module.exports = { - "__version": "9.6.1", + "__version": "9.7.0", "content-reference": { "content-reference-many-2nd-level-loop": { "1": "
\n

Content Reference: Many (2nd level loop)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" From 5f02b04298d0060203fbbeed1f319f773687dfbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 9 Nov 2022 16:39:02 +0100 Subject: [PATCH 047/149] test(e2e): fix path to SVG files in gatsby plugin image test --- .../src/pages/gatsby-plugin-image.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js index 287fada23c589..731147e50620b 100644 --- a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js +++ b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js @@ -32,7 +32,7 @@ const GatsbyPluginImagePage = ({ data }) => { {node.constrained ? ( ) : ( - + )}
))} @@ -50,7 +50,7 @@ const GatsbyPluginImagePage = ({ data }) => { {node.fullWidth ? ( ) : ( - + )}
))} @@ -69,7 +69,7 @@ const GatsbyPluginImagePage = ({ data }) => { {node.fixed ? ( ) : ( - + )}
))} @@ -88,7 +88,7 @@ const GatsbyPluginImagePage = ({ data }) => { {node.dominantColor ? ( ) : ( - + )}
))} @@ -107,7 +107,7 @@ const GatsbyPluginImagePage = ({ data }) => { {node.traced ? ( ) : ( - + )}
))} @@ -126,7 +126,7 @@ const GatsbyPluginImagePage = ({ data }) => { {node.blurred ? ( ) : ( - + )}
))} @@ -145,7 +145,7 @@ const GatsbyPluginImagePage = ({ data }) => { {node.customImageFormats ? ( ) : ( - + )}
))} @@ -172,7 +172,7 @@ const GatsbyPluginImagePage = ({ data }) => { alt={node.title} /> ) : ( - + )}
))} @@ -191,7 +191,7 @@ const GatsbyPluginImagePage = ({ data }) => { {node.constrained ? ( ) : ( - + )}
))} @@ -210,7 +210,7 @@ const GatsbyPluginImagePage = ({ data }) => { {node.constrained ? ( ) : ( - + )}
))} From 6997bb1dacdc2a68b0e7b640fbde65b344ed6a47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 9 Nov 2022 16:39:44 +0100 Subject: [PATCH 048/149] feat: resolve Rich Text links only from within the same space --- .../src/create-schema-customization.js | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.js b/packages/gatsby-source-contentful/src/create-schema-customization.js index 7a2bb3df38369..5bc1dc91ed6a4 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.js +++ b/packages/gatsby-source-contentful/src/create-schema-customization.js @@ -397,19 +397,27 @@ export async function createSchemaCustomization( // Rich Text const makeRichTextLinksResolver = - (nodeType, entityType) => (source, args, context) => { + (nodeType, entityType) => async (source, _args, context) => { const links = getRichTextEntityLinks(source, nodeType)[entityType].map( ({ id }) => id ) - return context.nodeModel.getAllNodes().filter( - node => - node.internal.owner === `gatsby-source-contentful` && - node?.sys?.id && - node?.sys?.type === entityType && - links.includes(node.sys.id) - // @todo how can we check for correct space and environment? We need to access the sys field of the fields parent entry. - ) + const node = context.nodeModel.findRootNodeAncestor(source) + if (!node) return null + + const res = await context.nodeModel.findAll({ + query: { + sys: { + id: { + in: links, + }, + spaceId: { eq: node.sys.spaceId }, + }, + }, + type: `Contentful${entityType}`, + }) + + return res.entries } // Contentful specific types From 684a13d78595493b8598ca91ad210b15b0416d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 17 Nov 2022 11:08:55 +0100 Subject: [PATCH 049/149] tre: use link extension instead of adding ___NODE to field names (#37021) * refactor: use link extension instead of adding ___NODE to field names * refactor: use content type field definitions to clean up stale references --- .../create-schema-customization.js.snap | 38 +++++------ .../src/__tests__/gatsby-node.js | 28 ++++---- .../src/__tests__/normalize.js | 8 +-- .../src/create-schema-customization.js | 12 ++-- .../gatsby-source-contentful/src/normalize.js | 33 ++++------ .../src/source-nodes.js | 66 ++++++++++++++----- 6 files changed, 105 insertions(+), 80 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index fdf69748fd88a..6ba9e274c6887 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -37,7 +37,7 @@ Array [ "extensions": Object { "link": Object { "by": "id", - "from": "contentType___NODE", + "from": "sys.contentType", }, }, "type": "ContentfulContentType", @@ -83,7 +83,7 @@ Array [ "extensions": Object { "link": Object { "by": "id", - "from": "tags___NODE", + "from": "tags", }, }, "type": "[ContentfulTag]!", @@ -402,7 +402,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "longLocalized___NODE", + "from": "longLocalized", }, }, "type": "ContentfulText", @@ -411,7 +411,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "longMarkdown___NODE", + "from": "longMarkdown", }, }, "type": "ContentfulText", @@ -420,7 +420,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "longPlain___NODE", + "from": "longPlain", }, }, "type": "ContentfulText", @@ -468,7 +468,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "many___NODE", + "from": "many", }, }, "type": "[ContentfulAsset]", @@ -477,7 +477,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "manyLocalized___NODE", + "from": "manyLocalized", }, }, "type": "[ContentfulAsset]", @@ -489,7 +489,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "one___NODE", + "from": "one", }, }, "type": "ContentfulAsset", @@ -498,7 +498,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "oneLocalized___NODE", + "from": "oneLocalized", }, }, "type": "ContentfulAsset", @@ -717,7 +717,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "many___NODE", + "from": "many", }, }, "type": "[UnionContentfulContentReferenceNumberText]", @@ -726,7 +726,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "manyLocalized___NODE", + "from": "manyLocalized", }, }, "type": "[ContentfulEntry]", @@ -738,7 +738,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "one___NODE", + "from": "one", }, }, "type": "ContentfulEntry", @@ -747,7 +747,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "oneLocalized___NODE", + "from": "oneLocalized", }, }, "type": "ContentfulEntry", @@ -783,7 +783,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "multipleItemsAllTypes___NODE", + "from": "multipleItemsAllTypes", }, }, "type": "[ContentfulEntry]", @@ -792,7 +792,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "multipleItemsManyTypes___NODE", + "from": "multipleItemsManyTypes", }, }, "type": "[UnionContentfulNumberText]", @@ -801,7 +801,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "multipleItemsSingleType___NODE", + "from": "multipleItemsSingleType", }, }, "type": "[ContentfulContentTypeText]", @@ -810,7 +810,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "oneItemAllTypes___NODE", + "from": "oneItemAllTypes", }, }, "type": "ContentfulEntry", @@ -819,7 +819,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "oneItemManyTypes___NODE", + "from": "oneItemManyTypes", }, }, "type": "UnionContentfulNumberText", @@ -828,7 +828,7 @@ Ignored if layout = FLUID.", "extensions": Object { "link": Object { "by": "id", - "from": "oneItemSingleType___NODE", + "from": "oneItemSingleType", }, }, "type": "ContentfulContentTypeText", diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 5677339c8af7e..8673145e99fb6 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -240,7 +240,7 @@ describe(`gatsby-node`, () => { type: value.sys.linkType || value.sys.type, }) ) - matchedObject[`${field}___NODE`] = linkId + matchedObject[field] = linkId if ( value.sys.type !== `Asset` && @@ -250,7 +250,7 @@ describe(`gatsby-node`, () => { references.set(linkId, {}) } - const referenceKey = `${currentContentType.name.toLowerCase()}___NODE` + const referenceKey = currentContentType.name.toLowerCase() const reference = references.get(linkId) const linkedNode = getNode(linkId) reference[referenceKey] = @@ -264,7 +264,7 @@ describe(`gatsby-node`, () => { } case `Text`: { const linkId = createNodeId(`${nodeId}${field}TextNode`) - matchedObject[`${field}___NODE`] = linkId + matchedObject[field] = linkId break } default: @@ -313,7 +313,7 @@ describe(`gatsby-node`, () => { // check if all references got removed references should be removed for (const value of currentNodeMap.values()) { Object.keys(value).forEach(field => { - if (field.endsWith(`___NODE`)) { + if (![`id`, `parent`].includes(field)) { expect([].concat(value[field])).not.toContain(nodeId) } }) @@ -654,7 +654,7 @@ describe(`gatsby-node`, () => { createdBlogEntryIds.forEach(blogEntryId => { const blogEntry = getNode(blogEntryId) - expect(getNode(blogEntry[`author___NODE`])).toBeTruthy() + expect(getNode(blogEntry[`author`])).toBeTruthy() }) expect(actions.createNode).toHaveBeenCalledTimes(44) @@ -744,7 +744,7 @@ describe(`gatsby-node`, () => { updatedBlogEntryIds.forEach(blogEntryId => { const blogEntry = getNode(blogEntryId) expect(blogEntry.title).toBe(`Hello world 1234`) - expect(getNode(blogEntry[`author___NODE`])).toBeTruthy() + expect(getNode(blogEntry[`author`])).toBeTruthy() }) expect(actions.createNode).toHaveBeenCalledTimes(52) @@ -812,8 +812,8 @@ describe(`gatsby-node`, () => { for (const author of getNodes().filter( n => n.internal.type === `ContentfulPerson` )) { - expect(author[`blog post___NODE`].length).toEqual(3) - expect(author[`blog post___NODE`]).toEqual( + expect(author[`blog post`].length).toEqual(3) + expect(author[`blog post`]).toEqual( expect.not.arrayContaining([ makeId({ spaceId: removedBlogEntry.sys.space.sys.id, @@ -833,15 +833,15 @@ describe(`gatsby-node`, () => { // check if blog post exists removedBlogEntryIds.forEach(entryId => { const blogEntry = getNode(entryId) - authorIds.push(blogEntry[`author___NODE`]) + authorIds.push(blogEntry[`author`]) expect(blogEntry).not.toBeUndefined() }) for (const author of getNodes().filter( n => n.internal.type === `ContentfulPerson` )) { - expect(author[`blog post___NODE`].length).toEqual(4) - expect(author[`blog post___NODE`]).toEqual( + expect(author[`blog post`].length).toEqual(4) + expect(author[`blog post`]).toEqual( expect.arrayContaining([ makeId({ spaceId: removedBlogEntry.sys.space.sys.id, @@ -879,8 +879,8 @@ describe(`gatsby-node`, () => { for (const author of getNodes().filter( n => n.internal.type === `ContentfulPerson` )) { - expect(author[`blog post___NODE`].length).toEqual(3) - expect(author[`blog post___NODE`]).toEqual( + expect(author[`blog post`].length).toEqual(3) + expect(author[`blog post`]).toEqual( expect.not.arrayContaining([ makeId({ spaceId: removedBlogEntry.sys.space.sys.id, @@ -895,7 +895,7 @@ describe(`gatsby-node`, () => { // check if references are gone authorIds.forEach(authorId => { - expect(getNode(authorId)[`blog post___NODE`]).toEqual( + expect(getNode(authorId)[`blog post`]).toEqual( expect.not.arrayContaining(deletedEntryIds) ) }) diff --git a/packages/gatsby-source-contentful/src/__tests__/normalize.js b/packages/gatsby-source-contentful/src/__tests__/normalize.js index fa111c9876907..8e2ea86a80fb1 100644 --- a/packages/gatsby-source-contentful/src/__tests__/normalize.js +++ b/packages/gatsby-source-contentful/src/__tests__/normalize.js @@ -154,11 +154,11 @@ describe(`Process contentful data (by name)`, () => { }) expect(foreignReferenceMap[`24DPGBDeGEaYy8ms4Y8QMQ___Entry`][0].name).toBe( - `product___NODE` + `product` ) expect(foreignReferenceMap[`2Y8LhXLnYAYqKCGEWG4EKI___Asset`][0].name).toBe( - `brand___NODE` + `brand` ) }) @@ -355,11 +355,11 @@ describe(`Process contentful data (by id)`, () => { }) expect(foreignReferenceMap[`24DPGBDeGEaYy8ms4Y8QMQ___Entry`][0].name).toBe( - `2pqfxujwe8qsykum0u6w8m___NODE` + `2pqfxujwe8qsykum0u6w8m` ) expect(foreignReferenceMap[`2Y8LhXLnYAYqKCGEWG4EKI___Asset`][0].name).toBe( - `sfztzbsum8coewygeuyes___NODE` + `sfztzbsum8coewygeuyes` ) }) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.js b/packages/gatsby-source-contentful/src/create-schema-customization.js index 5bc1dc91ed6a4..2df57f0045acd 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.js +++ b/packages/gatsby-source-contentful/src/create-schema-customization.js @@ -27,7 +27,7 @@ const ContentfulDataTypes = new Map([ return { type: `ContentfulText`, extensions: { - link: { by: `id`, from: `${field.id}___NODE` }, + link: { by: `id`, from: field.id }, }, } }, @@ -112,7 +112,7 @@ const getLinkFieldType = (linkType, field, schema, createTypes) => { return { type: translatedTypeNames.shift(), extensions: { - link: { by: `id`, from: `${field.id}___NODE` }, + link: { by: `id`, from: field.id }, }, } } @@ -133,7 +133,7 @@ const getLinkFieldType = (linkType, field, schema, createTypes) => { return { type: unionName, extensions: { - link: { by: `id`, from: `${field.id}___NODE` }, + link: { by: `id`, from: field.id }, }, } } @@ -142,7 +142,7 @@ const getLinkFieldType = (linkType, field, schema, createTypes) => { return { type: `Contentful${linkType}`, extensions: { - link: { by: `id`, from: `${field.id}___NODE` }, + link: { by: `id`, from: field.id }, }, } } @@ -280,7 +280,7 @@ export async function createSchemaCustomization( contentType: { type: `ContentfulContentType`, extensions: { - link: { by: `id`, from: `contentType___NODE` }, + link: { by: `id`, from: `sys.contentType` }, }, }, firstPublishedAt: { type: ` Date!` }, @@ -300,7 +300,7 @@ export async function createSchemaCustomization( tags: { type: `[ContentfulTag]!`, extensions: { - link: { by: `id`, from: `tags___NODE` }, + link: { by: `id`, from: `tags` }, }, }, }, diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.js index 8cb0b5bf6bf63..e9ca355b9421e 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.js @@ -150,7 +150,7 @@ export const buildForeignReferenceMap = ({ foreignReferenceMap[key] = [] } foreignReferenceMap[key].push({ - name: `${contentTypeItemId}___NODE`, + name: contentTypeItemId, id: entryItem.sys.id, spaceId: space.sys.id, type: entryItem.sys.type, @@ -171,7 +171,7 @@ export const buildForeignReferenceMap = ({ foreignReferenceMap[key] = [] } foreignReferenceMap[key].push({ - name: `${contentTypeItemId}___NODE`, + name: contentTypeItemId, id: entryItem.sys.id, spaceId: space.sys.id, type: entryItem.sys.type, @@ -411,22 +411,19 @@ export const createNodesForContentType = ({ ) }) if (resolvableEntryItemFieldValue.length !== 0) { - entryItemFields[`${entryItemFieldKey}___NODE`] = + entryItemFields[entryItemFieldKey] = resolvableEntryItemFieldValue } - - delete entryItemFields[entryItemFieldKey] } } else if (entryItemFieldValue?.sys?.type === `Link`) { if (resolvable.has(createRefId(entryItemFieldValue))) { - entryItemFields[`${entryItemFieldKey}___NODE`] = mId( + entryItemFields[entryItemFieldKey] = mId( space.sys.id, entryItemFieldValue.sys.id, entryItemFieldValue.sys.linkType || entryItemFieldValue.sys.type ) } - delete entryItemFields[entryItemFieldKey] } } }) @@ -481,7 +478,7 @@ export const createNodesForContentType = ({ locale: locale.code, spaceId: entryItem.sys.space.sys.id, environmentId: entryItem.sys.environment.sys.id, - contentType___NODE: createNodeId(contentTypeItemId), + contentType: createNodeId(contentTypeItemId), firstPublishedAt: entryItem.sys.createdAt, publishedAt: entryItem.sys.updatedAt, publishedVersion: entryItem.sys.revision, @@ -499,19 +496,14 @@ export const createNodesForContentType = ({ // Replace text fields with text nodes so we can process their markdown // into HTML. Object.keys(entryItemFields).forEach(entryItemFieldKey => { - // Ignore fields with "___node" as they're already handled - // and won't be a text field. - if (entryItemFieldKey.includes(`___`)) { - return - } - - const fieldType = contentTypeItem.fields.find( + // @todo: how expensive is this? + const field = contentTypeItem.fields.find( f => (restrictedNodeFields.includes(f.id) ? `${conflictFieldPrefix}${f.id}` : f.id) === entryItemFieldKey - ).type - if (fieldType === `Text`) { + ) + if (field?.type === `Text`) { const textNodeId = createNodeId( `${entryNodeId}${entryItemFieldKey}TextNode` ) @@ -531,8 +523,7 @@ export const createNodesForContentType = ({ childrenNodes.push(textNode) } - entryItemFields[`${entryItemFieldKey}___NODE`] = textNodeId - delete entryItemFields[entryItemFieldKey] + entryItemFields[entryItemFieldKey] = textNodeId } }) @@ -540,7 +531,7 @@ export const createNodesForContentType = ({ ...entryItemFields, ...entryNode, metadata: { - tags___NODE: entryItem.metadata.tags.map(tag => + tags: entryItem.metadata.tags.map(tag => createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) ), }, @@ -617,7 +608,7 @@ export const createAssetNodes = ({ height: file.details?.image?.height ?? null, size: file.details?.size ?? null, metadata: { - tags___NODE: assetItem.metadata.tags.map(tag => + tags: assetItem.metadata.tags.map(tag => createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) ), }, diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js index 34de5b84f02f2..353d466c47635 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ b/packages/gatsby-source-contentful/src/source-nodes.js @@ -4,7 +4,7 @@ import _ from "lodash" import { downloadContentfulAssets } from "./download-contentful-assets" import { fetchContent } from "./fetch" - +import { SourceNodesArgs } from "gatsby" import { buildEntryList, buildForeignReferenceMap, @@ -32,6 +32,7 @@ const CONTENT_DIGEST_COUNTER_SEPARATOR = `_COUNT_` let isFirstSource = true export async function sourceNodes( + /** @type {SourceNodesArgs} */ { actions, getNode, @@ -234,13 +235,14 @@ export async function sourceNodes( }) // Build foreign reference map before starting to insert any nodes + const useNameForId = pluginConfig.get(`useNameForId`) const foreignReferenceMap = buildForeignReferenceMap({ contentTypeItems, entryList, resolvable, defaultLocale, space, - useNameForId: pluginConfig.get(`useNameForId`), + useNameForId, }) reporter.verbose(`Resolving Contentful references`) @@ -278,6 +280,7 @@ export async function sourceNodes( .filter(node => node) localizedNodes.forEach(node => { + // @todo nodes of text fields should be deleted as well deleteNode(node) }) } @@ -295,6 +298,34 @@ export async function sourceNodes( deletionActivity.end() } + // Create map of reference fields to properly delete stale references + const referenceFieldMap = new Map() + for (const contentTypeItem of contentTypeItems) { + const referenceFields = contentTypeItem.fields.filter(field => { + if (field.disabled || field.omitted) { + return false + } + + return ( + field.type === `Link` || + (field.type === `Array` && field.items.type === `Link`) + ) + }) + if (referenceFields.length) { + referenceFieldMap.set( + contentTypeItem.name, + referenceFields.map(field => field.id) + ) + } + } + + // @todo mirror structure of Contentful GraphQL API, as it prevents field name overlaps + const reverseReferenceFields = contentTypeItems.map(contentTypeItem => + useNameForId + ? contentTypeItem.name.toLowerCase() + : contentTypeItem.sys.id.toLowerCase() + ) + // Update existing entry nodes that weren't updated but that need reverse links added or removed. const existingNodesThatNeedReverseLinksUpdateInDatastore = new Set() existingNodes @@ -335,14 +366,20 @@ export async function sourceNodes( } // Remove references to deleted nodes - if (n.sys.id && deletedEntryGatsbyReferenceIds.size) { - Object.keys(n).forEach(name => { - // @todo Detect reference fields based on schema. Should be easier to achieve in the upcoming version. - if (!name.endsWith(`___NODE`)) { - return - } - if (Array.isArray(n[name])) { - n[name] = n[name].filter(referenceId => { + if ( + n.sys.id && + deletedEntryGatsbyReferenceIds.size && + referenceFieldMap.has(n.sys.contentType) + ) { + const referenceFields = [ + ...referenceFieldMap.get(n.sys.contentType), + ...reverseReferenceFields, + ] + + referenceFields.forEach(name => { + const fieldValue = n[name] + if (Array.isArray(fieldValue)) { + n[name] = fieldValue.filter(referenceId => { const shouldRemove = deletedEntryGatsbyReferenceIds.has(referenceId) if (shouldRemove) { @@ -351,8 +388,7 @@ export async function sourceNodes( return !shouldRemove }) } else { - const referenceId = n[name] - if (deletedEntryGatsbyReferenceIds.has(referenceId)) { + if (deletedEntryGatsbyReferenceIds.has(fieldValue)) { existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) n[name] = null } @@ -432,9 +468,7 @@ export async function sourceNodes( if (entryList[i].length) { reporter.info( `Creating ${entryList[i].length} Contentful ${ - pluginConfig.get(`useNameForId`) - ? contentTypeItem.name - : contentTypeItem.sys.id + useNameForId ? contentTypeItem.name : contentTypeItem.sys.id } nodes` ) } @@ -454,7 +488,7 @@ export async function sourceNodes( defaultLocale, locales, space, - useNameForId: pluginConfig.get(`useNameForId`), + useNameForId, pluginConfig, unstable_createNodeManifest, }) From 8ca82f7d9ff95ce2735b76c1441021eb6b526b5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 17 Mar 2023 09:50:54 +0100 Subject: [PATCH 050/149] chore: rewrite to TypeScript (#37123) --- .eslintignore | 1 + e2e-tests/contentful/package.json | 1 - .../src/pages/gatsby-plugin-image.js | 2 +- e2e-tests/contentful/src/pages/rich-text.js | 2 +- packages/gatsby-source-contentful/.babelrc | 3 - packages/gatsby-source-contentful/.babelrc.js | 4 + packages/gatsby-source-contentful/.gitignore | 35 +- .../gatsby-source-contentful/gatsby-node.js | 2 + packages/gatsby-source-contentful/index.d.ts | 1 - packages/gatsby-source-contentful/index.js | 2 +- .../gatsby-source-contentful/package.json | 22 +- .../gatsby-source-contentful/rich-text.d.ts | 19 - .../src/__fixtures__/rich-text-data.js | 2 +- ...ark (1)-4cd185-original-1582664935 (1).png | Bin 4104 -> 0 bytes ...ark (1)-4cd185-original-1582664935 (1).png | Bin 4104 -> 0 bytes ...ark (1)-4cd185-original-1582664935 (1).png | Bin 4104 -> 0 bytes .../create-schema-customization.js.snap | 38 +- ...ark__1_-4cd185-original-1582664935__1_.png | Bin 355 -> 0 bytes ...ark__1_-4cd185-original-1582664935__1_.png | Bin 371 -> 0 bytes ...ark (1)-4cd185-original-1582664935 (1).png | Bin 6935 -> 0 bytes .../__tests__/download-contentful-assets.js | 18 +- ...ark__1_-4cd185-original-1582664935__1_.png | Bin 356 -> 0 bytes ...ark (1)-4cd185-original-1582664935 (1).png | Bin 13713 -> 0 bytes .../src/__tests__/fetch.js | 23 +- .../src/__tests__/gatsby-plugin-image.js | 109 +-- .../src/__tests__/normalize.js | 5 +- .../src/{config.js => config.ts} | 0 .../src/create-schema-customization.js | 574 --------------- .../src/create-schema-customization.ts | 660 ++++++++++++++++++ ...ssets.js => download-contentful-assets.ts} | 46 +- .../src/extend-node-type.js | 58 -- .../src/{fetch.js => fetch.ts} | 133 +++- .../src/{gatsby-node.js => gatsby-node.ts} | 31 +- ...plugin-image.js => gatsby-plugin-image.ts} | 147 ++-- .../src/{hooks.js => hooks.ts} | 19 +- .../{image-helpers.js => image-helpers.ts} | 12 +- .../gatsby-source-contentful/src/index.ts | 7 + .../src/{normalize.js => normalize.ts} | 545 +++++++++------ .../{plugin-options.js => plugin-options.ts} | 74 +- .../src/{report.js => report.ts} | 18 +- .../src/{rich-text.js => rich-text.ts} | 48 +- .../src/{schemes.js => schemes.ts} | 1 - .../src/source-nodes.js | 565 --------------- .../src/source-nodes.ts | 571 +++++++++++++++ .../src/types/contentful-js-sdk/asset-key.ts | 4 + .../src/types/contentful-js-sdk/asset.ts | 50 ++ .../src/types/contentful-js-sdk/collection.ts | 6 + .../types/contentful-js-sdk/content-type.ts | 86 +++ .../src/types/contentful-js-sdk/entry.ts | 221 ++++++ .../src/types/contentful-js-sdk/index.ts | 12 + .../src/types/contentful-js-sdk/link.ts | 14 + .../src/types/contentful-js-sdk/locale.ts | 22 + .../src/types/contentful-js-sdk/metadata.ts | 5 + .../types/contentful-js-sdk/query/equality.ts | 29 + .../contentful-js-sdk/query/existence.ts | 17 + .../types/contentful-js-sdk/query/index.ts | 1 + .../types/contentful-js-sdk/query/location.ts | 68 ++ .../types/contentful-js-sdk/query/query.ts | 66 ++ .../types/contentful-js-sdk/query/range.ts | 18 + .../types/contentful-js-sdk/query/search.ts | 17 + .../types/contentful-js-sdk/query/select.ts | 13 + .../types/contentful-js-sdk/query/subset.ts | 19 + .../src/types/contentful-js-sdk/query/util.ts | 29 + .../src/types/contentful-js-sdk/space.ts | 15 + .../src/types/contentful-js-sdk/sync.ts | 10 + .../src/types/contentful-js-sdk/sys.ts | 16 + .../src/types/contentful-js-sdk/tag.ts | 18 + .../src/types/contentful.ts | 128 ++++ .../src/types/plugin.ts | 18 + .../gatsby-source-contentful/tsconfig.json | 11 + packages/gatsby/index.d.ts | 2 +- 71 files changed, 2999 insertions(+), 1714 deletions(-) delete mode 100644 packages/gatsby-source-contentful/.babelrc create mode 100644 packages/gatsby-source-contentful/.babelrc.js create mode 100644 packages/gatsby-source-contentful/gatsby-node.js delete mode 100644 packages/gatsby-source-contentful/index.d.ts delete mode 100644 packages/gatsby-source-contentful/rich-text.d.ts delete mode 100644 packages/gatsby-source-contentful/src/__tests__/23df7612602d69edfc3eaf89c8c02248/347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png delete mode 100644 packages/gatsby-source-contentful/src/__tests__/47098b484f55425af2625391283f7f32/347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png delete mode 100644 packages/gatsby-source-contentful/src/__tests__/85c405f72e68f1e90176d3220d41c5bf/347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png delete mode 100644 packages/gatsby-source-contentful/src/__tests__/a578a7a05e25c710a5d1ec09ab5469c5/347966-contentful-logo-wordmark-dark__1_-4cd185-original-1582664935__1_.png delete mode 100644 packages/gatsby-source-contentful/src/__tests__/baec3798e6d3e16f3183ed0feb8a4023/347966-contentful-logo-wordmark-dark__1_-4cd185-original-1582664935__1_.png delete mode 100644 packages/gatsby-source-contentful/src/__tests__/df7930af6b8c743c76c43b86ffe5af75/347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png delete mode 100644 packages/gatsby-source-contentful/src/__tests__/e97c003d47d50d52c7e2759a2e4712b2/347966-contentful-logo-wordmark-dark__1_-4cd185-original-1582664935__1_.png delete mode 100644 packages/gatsby-source-contentful/src/__tests__/f6853f3e258800aa68463fa9565a9d80/347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png rename packages/gatsby-source-contentful/src/{config.js => config.ts} (100%) delete mode 100644 packages/gatsby-source-contentful/src/create-schema-customization.js create mode 100644 packages/gatsby-source-contentful/src/create-schema-customization.ts rename packages/gatsby-source-contentful/src/{download-contentful-assets.js => download-contentful-assets.ts} (68%) delete mode 100644 packages/gatsby-source-contentful/src/extend-node-type.js rename packages/gatsby-source-contentful/src/{fetch.js => fetch.ts} (81%) rename packages/gatsby-source-contentful/src/{gatsby-node.js => gatsby-node.ts} (92%) rename packages/gatsby-source-contentful/src/{gatsby-plugin-image.js => gatsby-plugin-image.ts} (75%) rename packages/gatsby-source-contentful/src/{hooks.js => hooks.ts} (58%) rename packages/gatsby-source-contentful/src/{image-helpers.js => image-helpers.ts} (88%) create mode 100644 packages/gatsby-source-contentful/src/index.ts rename packages/gatsby-source-contentful/src/{normalize.js => normalize.ts} (55%) rename packages/gatsby-source-contentful/src/{plugin-options.js => plugin-options.ts} (61%) rename packages/gatsby-source-contentful/src/{report.js => report.ts} (80%) rename packages/gatsby-source-contentful/src/{rich-text.js => rich-text.ts} (53%) rename packages/gatsby-source-contentful/src/{schemes.js => schemes.ts} (99%) delete mode 100644 packages/gatsby-source-contentful/src/source-nodes.js create mode 100644 packages/gatsby-source-contentful/src/source-nodes.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset-key.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/collection.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/content-type.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/entry.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/index.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/link.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/locale.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/metadata.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/equality.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/existence.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/index.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/location.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/query.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/range.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/search.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/select.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/subset.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/util.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/space.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/sync.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/sys.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/tag.ts create mode 100644 packages/gatsby-source-contentful/src/types/contentful.ts create mode 100644 packages/gatsby-source-contentful/src/types/plugin.ts create mode 100644 packages/gatsby-source-contentful/tsconfig.json diff --git a/.eslintignore b/.eslintignore index b97b3a4bfc442..8b999d9c690ad 100644 --- a/.eslintignore +++ b/.eslintignore @@ -24,6 +24,7 @@ packages/gatsby-source-shopify/**/*.js packages/gatsby-plugin-preload-fonts/prepare/*.js packages/gatsby/cache-dir/commonjs/**/* packages/gatsby-codemods/transforms +packages/gatsby-source-contentful/src/types/contentful-js-sdk packages/gatsby-source-graphql/batching packages/gatsby-plugin-gatsby-cloud/components packages/gatsby-plugin-gatsby-cloud/context diff --git a/e2e-tests/contentful/package.json b/e2e-tests/contentful/package.json index 3fc79c85429dd..f5e925c058ff4 100644 --- a/e2e-tests/contentful/package.json +++ b/e2e-tests/contentful/package.json @@ -4,7 +4,6 @@ "version": "1.0.0", "author": "Kyle Mathews ", "dependencies": { - "@contentful/rich-text-types": "^16.0.2", "gatsby": "next", "gatsby-plugin-image": "next", "gatsby-plugin-sharp": "next", diff --git a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js index cf3bc6ad7dff5..3f8ff91b579b7 100644 --- a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js +++ b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js @@ -1,7 +1,7 @@ import { graphql } from "gatsby" import { GatsbyImage } from "gatsby-plugin-image" import * as React from "react" -import { useContentfulImage } from "gatsby-source-contentful/hooks" +import { useContentfulImage } from "gatsby-source-contentful" import Layout from "../components/layout" import Grid from "../components/grid" diff --git a/e2e-tests/contentful/src/pages/rich-text.js b/e2e-tests/contentful/src/pages/rich-text.js index 0ce1fdadf460d..a8bd18af36031 100644 --- a/e2e-tests/contentful/src/pages/rich-text.js +++ b/e2e-tests/contentful/src/pages/rich-text.js @@ -4,7 +4,7 @@ import * as React from "react" import slugify from "slugify" import { BLOCKS, MARKS, INLINES } from "@contentful/rich-text-types" -import { renderRichText } from "gatsby-source-contentful/rich-text" +import { renderRichText } from "gatsby-source-contentful" import Layout from "../components/layout" diff --git a/packages/gatsby-source-contentful/.babelrc b/packages/gatsby-source-contentful/.babelrc deleted file mode 100644 index ac0ad292bb087..0000000000000 --- a/packages/gatsby-source-contentful/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": [["babel-preset-gatsby-package"]] -} diff --git a/packages/gatsby-source-contentful/.babelrc.js b/packages/gatsby-source-contentful/.babelrc.js new file mode 100644 index 0000000000000..1e7ab4a86bfca --- /dev/null +++ b/packages/gatsby-source-contentful/.babelrc.js @@ -0,0 +1,4 @@ +module.exports = { + presets: [["babel-preset-gatsby-package", { esm: true }]], + plugins: ["@babel/plugin-transform-modules-commonjs"], +} diff --git a/packages/gatsby-source-contentful/.gitignore b/packages/gatsby-source-contentful/.gitignore index 1a46274e77c91..63b7d144560b3 100644 --- a/packages/gatsby-source-contentful/.gitignore +++ b/packages/gatsby-source-contentful/.gitignore @@ -1,4 +1,33 @@ -/__tests__ -/yarn.lock -/*.js +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git +node_modules + +decls +dist +*.js +!gatsby-node.js !index.js diff --git a/packages/gatsby-source-contentful/gatsby-node.js b/packages/gatsby-source-contentful/gatsby-node.js new file mode 100644 index 0000000000000..2a15db4534328 --- /dev/null +++ b/packages/gatsby-source-contentful/gatsby-node.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +module.exports = require("./dist/gatsby-node"); diff --git a/packages/gatsby-source-contentful/index.d.ts b/packages/gatsby-source-contentful/index.d.ts deleted file mode 100644 index 542b1609adf03..0000000000000 --- a/packages/gatsby-source-contentful/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module "gatsby-source-contentful" {} diff --git a/packages/gatsby-source-contentful/index.js b/packages/gatsby-source-contentful/index.js index c3b803dbe9304..d21b571a9a46c 100644 --- a/packages/gatsby-source-contentful/index.js +++ b/packages/gatsby-source-contentful/index.js @@ -1 +1 @@ -module.exports.schemes = require(`./schemes.js`) +module.exports = require(`./dist/index.js`) diff --git a/packages/gatsby-source-contentful/package.json b/packages/gatsby-source-contentful/package.json index 3becf33041cb6..0066e19bcc596 100644 --- a/packages/gatsby-source-contentful/package.json +++ b/packages/gatsby-source-contentful/package.json @@ -2,7 +2,9 @@ "name": "gatsby-source-contentful", "description": "Gatsby source plugin for building websites using the Contentful CMS as a data source", "version": "8.8.0-next.0", - "author": "Marcus Ericsson (mericsson.com)", + "author": "Marcus Ericsson (mericsson.com), Benedikt Rötsch (hashbite.net)", + "main": "index.js", + "types": "dist/index.d.ts", "bugs": { "url": "https://github.com/gatsbyjs/gatsby/issues" }, @@ -32,7 +34,10 @@ "@babel/core": "^7.20.12", "babel-preset-gatsby-package": "^3.8.0-next.0", "cross-env": "^7.0.3", - "nock": "^13.3.0" + "del-cli": "^5.0.0", + "gatsby-plugin-sharp": "^5.8.0-next.0", + "nock": "^13.3.0", + "typescript": "^4.9.4" }, "homepage": "https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-source-contentful#readme", "keywords": [ @@ -44,7 +49,6 @@ "peerDependencies": { "gatsby": "^5.0.0-next", "gatsby-plugin-image": "^3.0.0-next", - "gatsby-plugin-sharp": "^5.0.0-next", "sharp": "^0.30.1" }, "repository": { @@ -53,12 +57,14 @@ "directory": "packages/gatsby-source-contentful" }, "scripts": { - "build": "babel src --out-dir . --ignore **/__tests__ --ignore **/__fixtures__", - "prepare": "cross-env NODE_ENV=production npm run build", - "watch": "babel -w src --out-dir . --ignore **/__tests__ --ignore **/__fixtures__" + "build": "babel src --out-dir dist/ --ignore \"**/__tests__\" --ignore \"**/__mocks__\" --extensions \".ts\"", + "typegen": "tsc --emitDeclarationOnly --declaration --declarationDir dist/", + "prepare": "cross-env NODE_ENV=production npm run clean && npm run build && npm run typegen", + "watch": "babel -w src --out-dir dist/ --ignore \"**/__tests__\" --extensions \".ts\"", + "test": "jest", + "clean": "del-cli dist/*" }, "engines": { "node": ">=18.0.0" - }, - "types": "index.d.ts" + } } diff --git a/packages/gatsby-source-contentful/rich-text.d.ts b/packages/gatsby-source-contentful/rich-text.d.ts deleted file mode 100644 index fb43b376ecbcd..0000000000000 --- a/packages/gatsby-source-contentful/rich-text.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ReactNode } from "react" -import { Options } from "@contentful/rich-text-react-renderer" - -interface ContentfulRichTextGatsbyReference { - /** - * Either ContentfulAsset for assets or ContentfulYourContentTypeName for content types - */ - __typename: string - contentful_id: string -} - -interface RenderRichTextData { - raw: string - references: T[] -} - -export function renderRichText< - TReference extends ContentfulRichTextGatsbyReference ->(data: RenderRichTextData, options?: Options): ReactNode diff --git a/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js b/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js index 98ee4aa277268..9526668a6a859 100644 --- a/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js +++ b/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js @@ -799,7 +799,7 @@ exports.initialSync = () => { } } -// @todo this fixture is unused +// TODO: this fixture is unused exports.deleteLinkedPage = () => { return { currentSyncData: { diff --git a/packages/gatsby-source-contentful/src/__tests__/23df7612602d69edfc3eaf89c8c02248/347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png b/packages/gatsby-source-contentful/src/__tests__/23df7612602d69edfc3eaf89c8c02248/347966-contentful-logo-wordmark-dark (1)-4cd185-original-1582664935 (1).png deleted file mode 100644 index ca8c789fbe0a14ec6f8af18bd7e851206ca52995..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4104 zcmV+j5cltiP)~`$Q74Ug+Kxb ziX@yX2pAwq@4tB8_{z4cx~ivVGK2NK_j^8^sp_tp{{CI{)mN2b#eB5ZALLvNI)D*i zCRh%>0eitdkOkI)`Cts_0jhzxV#bUai#>z$Rsuu7Qg8}bniPPo;8}33=}}|GqTlHm zwZRndvj?Xakq?%ETg|Azn6c<|{;FUSIP0V1JMjf*VtU+|vFLg0_XUT-?D#xPWX6Ls z<`*z#tmvG-90m0XBk24*TRb$Cm`BdnhqpLL09O*FOs{D7;lql~&&Z7G##lQ7Wyiet#(FpBKhKM6tyby#BP{|M zW|`2p2e$%PYkNTVg1UdOeyGca=3qDRH3$HevX_Gs8UpZK5wx!}_z-+SyalQ|Ie#3O z-uv|>mXZK~7PEI2MPM+|xUVk{#$driI_VGA51%{q!C5vUQYia(iL?IzUZ4@eaBvrh zk8s=AsP44Gy?y2+0KM}wQ>->GeW5G>&8B}Va?(6X1KtQWfJ|`QCjsbb+}D?f<1xX5 zJNFOP54!~Y&{U!920_`api&gHt%KnH4%?l-3OHB*0cbl>LjY#{MgVfbi{K_uf#nbI zhJTj=^}wUxDQjKZ*+IvD0F+j} zF*c6}ZNO>|0#M($uMq$r`(ckq0k~RF?iWx#$_3yMF93DGnVFEDxfcz2;K*) zzzVPcjA3sCP*$V9E5MDQC8*^Tki!4F3iJn~!7J3JVW1&fnhHSx7E*h7%4^(rKQIBz z2TQ>x;2kgy^kIQBpC9sz!1drZkPO<>eW;c{;86e)1?7%Mdamz50QT_$Fg57>jQq?2 z)}R>+Tm_)%lub|j6_H0ht-%o&=RX75dF+U?;7Q4kZHI}%{h)+G1bH^8zFVC~!FW*B zrOrOKp=CbHE~C$ik%OmGpvvhwg)|54A#(zW02I5^S48+;cw4#9`>iLD!gs-r%ybV zp6;t!!MPiOJp$)H!Ojry=={wMkW!=v-xq4A)I_{w3(IVZ$A*;`_y(@>q>JofMB(Oc8Y zwLWwj$#@U|Ms2Qqb+A3eez53GSk`uLbp+pK(}_hMuE9nSt$h-J_dN=LMWdEPKVk>8 zrtehG5G4Vi;NJ?700_ut$wDy_+-WIT1J&hYu1=QrImL%MgZ$OuzO#I+|JOIC!*!nU zP)~I#dx=lZA7nN!h7th?1-3EgDjx)3aR>rXGnxe8Qjn)909|9m`O8sOm+Z&Lr_48& z`E^J#d`#f#?McHdx1sU@8uI14eD@q^5di_nJ-xm3vTk@hOwEg0N3gFB6kN6g7_{XQ>9Bq9LeoiovfsC+81s#+KJ4`SU?1X`nF5dc?k5OZRsTiHWG}ONs)J=+cgcf^sKijvP$_uu#MK z3qZ9P5r8f_b8d}#KNr+_z-?)d$~TcX=Nv@=ct+tmvY~yO5Cx#JWGFvMqc5M5ZI;1* zlU$|?16}H`N-HN$<+FVffTpo70Gl)fU{|piF*NQ)$>xkw9_uVG2`K(qqn@dv)J$&p zD-wWxD)&$8!=fq2!yyVl4?&rqXh|?$k!u9gh@}bw@QGrgQ>sKjs$KvBuqFfn*uezg zfQA61$B+PgCTR4;5bA8Ex;E}oPYYRu*hK)wYFuZDTOW87fYD(J&ixukQ4oMGihYnk z@gAo-T3rAFAX)_&pdbL5OaM-52*7JGBmg@EjlL&@I=cy#R6jl;n*X+S5r8{=7zMo< zq5!-VW&t=!0of#p;8sxVgE$)XIn~pZ`%caUCII)S3cx810hka&0`Q$%pv^;_0Z}yG zLtT3Xb#-zPfaV(47!@V~NDs3B{6b5(A_2(J%$Ca()YFSw{W%h00ca450uW0h0MYt? z_YmsrFQ_v^vmV(S=N9@-wk$$k!~(D&%mR={@s=dlO)Rl108M=ofEA$%K+Xjk16V6) z^s^z!{Xjf7}!n?#Nwqb(&9 z*=ZF_g^dycxXz;h{3LtMC^@W9usTskv0arVFA`n=ddUP}k!Bu1jTjMtev;*%ZXWAo zOIP0u>RqI`ELB{Rpt3%gKoda$7$f-3bV(@aTl$IS%0l1SB_FOL`JFfyjW!DSJ?sl67&`HF(eh5IarT}~mipPiu zye#RUV{{^J8Ha~^D5cB>hjPui&+AEY;0tJt{9=cDxr`2yuq45s%M}D5Nu&K^6$Id3 zNn380oLBIg%VwJ@F89XH(tD6bLoYaq2JPewy8zI4wg|p6!(}KRiU5p~^x?arLrf^Q zVS`H?MMVHM2M+>0qbUO2V?+QhlkD*019&W}>}@*6>##s9I&g3CSqg`Jyhq1hji){Q zCv~>!N(7*uM*CIr0P4ByIaon`GcA~-K;`PVY`8f_Tc+=(xIlFZe6gLBlN?q-UbTxr zgau%hWMr34FNJ&Qs4>3o8$%EP*~`SD9ja{aNo{(TlW4?tP$7`2A^@9$=K-wJ6o5UT ze2j=dSB34ks>vyJsm`jBSb!I{IE+LhB>?e)!$(AO{F+?ZXEaa#ar@3Fn{!1{0D5Y) zqwyAT9GmaS>;y8_K;N=*Qm!I>WtIeWp@fOT|gz}lM{u(JCFtla|wR?et^buv9= zMz~G{I@*6&X>c!?4VHnqU=S$hQ3O&wbfD9a_*UEe^q3FM|DE8tv4{wOOTg5LySZ`~ z(WuEUAw0()))8R=C?(0gu=9-{0zl;xeK@VkiEcUqz@`DG?aqH@C7iy0z}nXF_iXPR zD9rAW@{hx*gZ*~?>%n$lIj{$`@F)VkUH0R<9VOM*;Sh-=g#$-quv3Vy7Tj+*1z?6l zV$$o1_uSoKF7H=j(3||RWfB3{xX^)45byF{bCLj~6#Az0#kSh5@z?2kl2*;FoYs>@EAs@dzkR^S-xG=KN? zZkvI)A$ccBmS&K(T$zTUiWFUUkmfVAna-COCiuLwLL$&=UI4D;gMqo@+?}7X`+ zd)fW=_wZcSrzzDrNxywh_g0GQbNj}(b$m>TwuW!DeTR*7dh-Inm~vhKwg;@8J=Fw& zaiG@_i{9K1viZA)k{}U03ck{Ge4Z}Fj2ScLubuzvz#H`h;D_G|08bv+2R4EYAQK!9 z!RdLrnqSM9G5-Z14pV^XS$)(6Ag9+*%O|JSp|1J0j2R1$2$bFbL|~m#5U_KKbtLl6 z&qfn*=9e;NEKHU=E|9Rjb6~f705IZj|8tN| za`PvH!XgOvF|t6C`6Y}QD_SAA3;Y;C$Ik~-K?T$M#*9UW2vnj(pS&~`$Q74Ug+Kxb ziX@yX2pAwq@4tB8_{z4cx~ivVGK2NK_j^8^sp_tp{{CI{)mN2b#eB5ZALLvNI)D*i zCRh%>0eitdkOkI)`Cts_0jhzxV#bUai#>z$Rsuu7Qg8}bniPPo;8}33=}}|GqTlHm zwZRndvj?Xakq?%ETg|Azn6c<|{;FUSIP0V1JMjf*VtU+|vFLg0_XUT-?D#xPWX6Ls z<`*z#tmvG-90m0XBk24*TRb$Cm`BdnhqpLL09O*FOs{D7;lql~&&Z7G##lQ7Wyiet#(FpBKhKM6tyby#BP{|M zW|`2p2e$%PYkNTVg1UdOeyGca=3qDRH3$HevX_Gs8UpZK5wx!}_z-+SyalQ|Ie#3O z-uv|>mXZK~7PEI2MPM+|xUVk{#$driI_VGA51%{q!C5vUQYia(iL?IzUZ4@eaBvrh zk8s=AsP44Gy?y2+0KM}wQ>->GeW5G>&8B}Va?(6X1KtQWfJ|`QCjsbb+}D?f<1xX5 zJNFOP54!~Y&{U!920_`api&gHt%KnH4%?l-3OHB*0cbl>LjY#{MgVfbi{K_uf#nbI zhJTj=^}wUxDQjKZ*+IvD0F+j} zF*c6}ZNO>|0#M($uMq$r`(ckq0k~RF?iWx#$_3yMF93DGnVFEDxfcz2;K*) zzzVPcjA3sCP*$V9E5MDQC8*^Tki!4F3iJn~!7J3JVW1&fnhHSx7E*h7%4^(rKQIBz z2TQ>x;2kgy^kIQBpC9sz!1drZkPO<>eW;c{;86e)1?7%Mdamz50QT_$Fg57>jQq?2 z)}R>+Tm_)%lub|j6_H0ht-%o&=RX75dF+U?;7Q4kZHI}%{h)+G1bH^8zFVC~!FW*B zrOrOKp=CbHE~C$ik%OmGpvvhwg)|54A#(zW02I5^S48+;cw4#9`>iLD!gs-r%ybV zp6;t!!MPiOJp$)H!Ojry=={wMkW!=v-xq4A)I_{w3(IVZ$A*;`_y(@>q>JofMB(Oc8Y zwLWwj$#@U|Ms2Qqb+A3eez53GSk`uLbp+pK(}_hMuE9nSt$h-J_dN=LMWdEPKVk>8 zrtehG5G4Vi;NJ?700_ut$wDy_+-WIT1J&hYu1=QrImL%MgZ$OuzO#I+|JOIC!*!nU zP)~I#dx=lZA7nN!h7th?1-3EgDjx)3aR>rXGnxe8Qjn)909|9m`O8sOm+Z&Lr_48& z`E^J#d`#f#?McHdx1sU@8uI14eD@q^5di_nJ-xm3vTk@hOwEg0N3gFB6kN6g7_{XQ>9Bq9LeoiovfsC+81s#+KJ4`SU?1X`nF5dc?k5OZRsTiHWG}ONs)J=+cgcf^sKijvP$_uu#MK z3qZ9P5r8f_b8d}#KNr+_z-?)d$~TcX=Nv@=ct+tmvY~yO5Cx#JWGFvMqc5M5ZI;1* zlU$|?16}H`N-HN$<+FVffTpo70Gl)fU{|piF*NQ)$>xkw9_uVG2`K(qqn@dv)J$&p zD-wWxD)&$8!=fq2!yyVl4?&rqXh|?$k!u9gh@}bw@QGrgQ>sKjs$KvBuqFfn*uezg zfQA61$B+PgCTR4;5bA8Ex;E}oPYYRu*hK)wYFuZDTOW87fYD(J&ixukQ4oMGihYnk z@gAo-T3rAFAX)_&pdbL5OaM-52*7JGBmg@EjlL&@I=cy#R6jl;n*X+S5r8{=7zMo< zq5!-VW&t=!0of#p;8sxVgE$)XIn~pZ`%caUCII)S3cx810hka&0`Q$%pv^;_0Z}yG zLtT3Xb#-zPfaV(47!@V~NDs3B{6b5(A_2(J%$Ca()YFSw{W%h00ca450uW0h0MYt? z_YmsrFQ_v^vmV(S=N9@-wk$$k!~(D&%mR={@s=dlO)Rl108M=ofEA$%K+Xjk16V6) z^s^z!{Xjf7}!n?#Nwqb(&9 z*=ZF_g^dycxXz;h{3LtMC^@W9usTskv0arVFA`n=ddUP}k!Bu1jTjMtev;*%ZXWAo zOIP0u>RqI`ELB{Rpt3%gKoda$7$f-3bV(@aTl$IS%0l1SB_FOL`JFfyjW!DSJ?sl67&`HF(eh5IarT}~mipPiu zye#RUV{{^J8Ha~^D5cB>hjPui&+AEY;0tJt{9=cDxr`2yuq45s%M}D5Nu&K^6$Id3 zNn380oLBIg%VwJ@F89XH(tD6bLoYaq2JPewy8zI4wg|p6!(}KRiU5p~^x?arLrf^Q zVS`H?MMVHM2M+>0qbUO2V?+QhlkD*019&W}>}@*6>##s9I&g3CSqg`Jyhq1hji){Q zCv~>!N(7*uM*CIr0P4ByIaon`GcA~-K;`PVY`8f_Tc+=(xIlFZe6gLBlN?q-UbTxr zgau%hWMr34FNJ&Qs4>3o8$%EP*~`SD9ja{aNo{(TlW4?tP$7`2A^@9$=K-wJ6o5UT ze2j=dSB34ks>vyJsm`jBSb!I{IE+LhB>?e)!$(AO{F+?ZXEaa#ar@3Fn{!1{0D5Y) zqwyAT9GmaS>;y8_K;N=*Qm!I>WtIeWp@fOT|gz}lM{u(JCFtla|wR?et^buv9= zMz~G{I@*6&X>c!?4VHnqU=S$hQ3O&wbfD9a_*UEe^q3FM|DE8tv4{wOOTg5LySZ`~ z(WuEUAw0()))8R=C?(0gu=9-{0zl;xeK@VkiEcUqz@`DG?aqH@C7iy0z}nXF_iXPR zD9rAW@{hx*gZ*~?>%n$lIj{$`@F)VkUH0R<9VOM*;Sh-=g#$-quv3Vy7Tj+*1z?6l zV$$o1_uSoKF7H=j(3||RWfB3{xX^)45byF{bCLj~6#Az0#kSh5@z?2kl2*;FoYs>@EAs@dzkR^S-xG=KN? zZkvI)A$ccBmS&K(T$zTUiWFUUkmfVAna-COCiuLwLL$&=UI4D;gMqo@+?}7X`+ zd)fW=_wZcSrzzDrNxywh_g0GQbNj}(b$m>TwuW!DeTR*7dh-Inm~vhKwg;@8J=Fw& zaiG@_i{9K1viZA)k{}U03ck{Ge4Z}Fj2ScLubuzvz#H`h;D_G|08bv+2R4EYAQK!9 z!RdLrnqSM9G5-Z14pV^XS$)(6Ag9+*%O|JSp|1J0j2R1$2$bFbL|~m#5U_KKbtLl6 z&qfn*=9e;NEKHU=E|9Rjb6~f705IZj|8tN| za`PvH!XgOvF|t6C`6Y}QD_SAA3;Y;C$Ik~-K?T$M#*9UW2vnj(pS&~`$Q74Ug+Kxb ziX@yX2pAwq@4tB8_{z4cx~ivVGK2NK_j^8^sp_tp{{CI{)mN2b#eB5ZALLvNI)D*i zCRh%>0eitdkOkI)`Cts_0jhzxV#bUai#>z$Rsuu7Qg8}bniPPo;8}33=}}|GqTlHm zwZRndvj?Xakq?%ETg|Azn6c<|{;FUSIP0V1JMjf*VtU+|vFLg0_XUT-?D#xPWX6Ls z<`*z#tmvG-90m0XBk24*TRb$Cm`BdnhqpLL09O*FOs{D7;lql~&&Z7G##lQ7Wyiet#(FpBKhKM6tyby#BP{|M zW|`2p2e$%PYkNTVg1UdOeyGca=3qDRH3$HevX_Gs8UpZK5wx!}_z-+SyalQ|Ie#3O z-uv|>mXZK~7PEI2MPM+|xUVk{#$driI_VGA51%{q!C5vUQYia(iL?IzUZ4@eaBvrh zk8s=AsP44Gy?y2+0KM}wQ>->GeW5G>&8B}Va?(6X1KtQWfJ|`QCjsbb+}D?f<1xX5 zJNFOP54!~Y&{U!920_`api&gHt%KnH4%?l-3OHB*0cbl>LjY#{MgVfbi{K_uf#nbI zhJTj=^}wUxDQjKZ*+IvD0F+j} zF*c6}ZNO>|0#M($uMq$r`(ckq0k~RF?iWx#$_3yMF93DGnVFEDxfcz2;K*) zzzVPcjA3sCP*$V9E5MDQC8*^Tki!4F3iJn~!7J3JVW1&fnhHSx7E*h7%4^(rKQIBz z2TQ>x;2kgy^kIQBpC9sz!1drZkPO<>eW;c{;86e)1?7%Mdamz50QT_$Fg57>jQq?2 z)}R>+Tm_)%lub|j6_H0ht-%o&=RX75dF+U?;7Q4kZHI}%{h)+G1bH^8zFVC~!FW*B zrOrOKp=CbHE~C$ik%OmGpvvhwg)|54A#(zW02I5^S48+;cw4#9`>iLD!gs-r%ybV zp6;t!!MPiOJp$)H!Ojry=={wMkW!=v-xq4A)I_{w3(IVZ$A*;`_y(@>q>JofMB(Oc8Y zwLWwj$#@U|Ms2Qqb+A3eez53GSk`uLbp+pK(}_hMuE9nSt$h-J_dN=LMWdEPKVk>8 zrtehG5G4Vi;NJ?700_ut$wDy_+-WIT1J&hYu1=QrImL%MgZ$OuzO#I+|JOIC!*!nU zP)~I#dx=lZA7nN!h7th?1-3EgDjx)3aR>rXGnxe8Qjn)909|9m`O8sOm+Z&Lr_48& z`E^J#d`#f#?McHdx1sU@8uI14eD@q^5di_nJ-xm3vTk@hOwEg0N3gFB6kN6g7_{XQ>9Bq9LeoiovfsC+81s#+KJ4`SU?1X`nF5dc?k5OZRsTiHWG}ONs)J=+cgcf^sKijvP$_uu#MK z3qZ9P5r8f_b8d}#KNr+_z-?)d$~TcX=Nv@=ct+tmvY~yO5Cx#JWGFvMqc5M5ZI;1* zlU$|?16}H`N-HN$<+FVffTpo70Gl)fU{|piF*NQ)$>xkw9_uVG2`K(qqn@dv)J$&p zD-wWxD)&$8!=fq2!yyVl4?&rqXh|?$k!u9gh@}bw@QGrgQ>sKjs$KvBuqFfn*uezg zfQA61$B+PgCTR4;5bA8Ex;E}oPYYRu*hK)wYFuZDTOW87fYD(J&ixukQ4oMGihYnk z@gAo-T3rAFAX)_&pdbL5OaM-52*7JGBmg@EjlL&@I=cy#R6jl;n*X+S5r8{=7zMo< zq5!-VW&t=!0of#p;8sxVgE$)XIn~pZ`%caUCII)S3cx810hka&0`Q$%pv^;_0Z}yG zLtT3Xb#-zPfaV(47!@V~NDs3B{6b5(A_2(J%$Ca()YFSw{W%h00ca450uW0h0MYt? z_YmsrFQ_v^vmV(S=N9@-wk$$k!~(D&%mR={@s=dlO)Rl108M=ofEA$%K+Xjk16V6) z^s^z!{Xjf7}!n?#Nwqb(&9 z*=ZF_g^dycxXz;h{3LtMC^@W9usTskv0arVFA`n=ddUP}k!Bu1jTjMtev;*%ZXWAo zOIP0u>RqI`ELB{Rpt3%gKoda$7$f-3bV(@aTl$IS%0l1SB_FOL`JFfyjW!DSJ?sl67&`HF(eh5IarT}~mipPiu zye#RUV{{^J8Ha~^D5cB>hjPui&+AEY;0tJt{9=cDxr`2yuq45s%M}D5Nu&K^6$Id3 zNn380oLBIg%VwJ@F89XH(tD6bLoYaq2JPewy8zI4wg|p6!(}KRiU5p~^x?arLrf^Q zVS`H?MMVHM2M+>0qbUO2V?+QhlkD*019&W}>}@*6>##s9I&g3CSqg`Jyhq1hji){Q zCv~>!N(7*uM*CIr0P4ByIaon`GcA~-K;`PVY`8f_Tc+=(xIlFZe6gLBlN?q-UbTxr zgau%hWMr34FNJ&Qs4>3o8$%EP*~`SD9ja{aNo{(TlW4?tP$7`2A^@9$=K-wJ6o5UT ze2j=dSB34ks>vyJsm`jBSb!I{IE+LhB>?e)!$(AO{F+?ZXEaa#ar@3Fn{!1{0D5Y) zqwyAT9GmaS>;y8_K;N=*Qm!I>WtIeWp@fOT|gz}lM{u(JCFtla|wR?et^buv9= zMz~G{I@*6&X>c!?4VHnqU=S$hQ3O&wbfD9a_*UEe^q3FM|DE8tv4{wOOTg5LySZ`~ z(WuEUAw0()))8R=C?(0gu=9-{0zl;xeK@VkiEcUqz@`DG?aqH@C7iy0z}nXF_iXPR zD9rAW@{hx*gZ*~?>%n$lIj{$`@F)VkUH0R<9VOM*;Sh-=g#$-quv3Vy7Tj+*1z?6l zV$$o1_uSoKF7H=j(3||RWfB3{xX^)45byF{bCLj~6#Az0#kSh5@z?2kl2*;FoYs>@EAs@dzkR^S-xG=KN? zZkvI)A$ccBmS&K(T$zTUiWFUUkmfVAna-COCiuLwLL$&=UI4D;gMqo@+?}7X`+ zd)fW=_wZcSrzzDrNxywh_g0GQbNj}(b$m>TwuW!DeTR*7dh-Inm~vhKwg;@8J=Fw& zaiG@_i{9K1viZA)k{}U03ck{Ge4Z}Fj2ScLubuzvz#H`h;D_G|08bv+2R4EYAQK!9 z!RdLrnqSM9G5-Z14pV^XS$)(6Ag9+*%O|JSp|1J0j2R1$2$bFbL|~m#5U_KKbtLl6 z&qfn*=9e;NEKHU=E|9Rjb6~f705IZj|8tN| za`PvH!XgOvF|t6C`6Y}QD_SAA3;Y;C$Ik~-K?T$M#*9UW2vnj(pS&0b&ssKJO?5z z14}r%eY((P#z9PRxB^VZ_kHnq!V=!bWB?JSESkve(1cf!=@7+BnUw5-PSGt1@(X4N zx_{G5MbSe4wwRo3TVCtjC3P!jbj_UAx$%yetV~DQa@7?LwsYFUHU-_kW%h%`*#M}K zv%n*=n1O*?2!t6g-L3lr6l5>)^mS!_%E8O2s`!}4V>eL9%+tj&gyVX03QLnckHdjq z(jFTOjs7JhKTK$8*sl|CEILul(cp12gU64x79CI0udoD#O9U`5Y?I{*luP{h5@-U0 Mr>mdKI;Vst010VvmjD0& diff --git a/packages/gatsby-source-contentful/src/__tests__/baec3798e6d3e16f3183ed0feb8a4023/347966-contentful-logo-wordmark-dark__1_-4cd185-original-1582664935__1_.png b/packages/gatsby-source-contentful/src/__tests__/baec3798e6d3e16f3183ed0feb8a4023/347966-contentful-logo-wordmark-dark__1_-4cd185-original-1582664935__1_.png deleted file mode 100644 index 52be92e660e53d2968531d61b4e89f7de145dd4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^B0$W-!3-pKHojj1q^1Sn5$NUJENzdkd+cX4ZHW%fGXI}gID zw=Yr!>gFu)h%9Dc;1&X5#!GkW{s0BpOFVsD*`IMrF~}O%9qifYS*k;wDzb~dn86}|I{pslpt2@trS&7RqR?- zRE1hKi>gn*-}Bsa&U4Ru&iUQ{cGl zE7<+I{tQ_3fcD>QLb5T_>ZZeZSb27wtLsn8! zYqO*;Bn|l-ag2sw1S5Z7R4J=~ReV(t394a8GDrp3cEy-GoxT6VzYwIs8R9IFe2B+U zDNzZ?oO`U86m%x$1v&>~*itg{%HK)!Tu$n5hoqilmS^)*QiIEm%aFh%lX)%o%cx~4azkE6(-u*y zYph0TL=O5UUd~e6#}hY(92pl?-;X~+2V+uODE}?|hpA9;&((5=kC|iSRc0h{Y3k{d zCr|dJlBC1Q=A;J&J*es^91$1jX|AB4AXR00UJ{Snz}etxaVI!dTm+Xq_XO;Hh9js* z8=3gbqCwNG$@Z3W)|C5_XV<-Tamx7;Z@T*0+8{t-Dy|bZiIaotB7~65-di!!X#M0* zOie%J!&ii=y1(o+oEDk79%_ac-DE$nn)2##ts1c8YAo3gIOWi3i7`vD%t=nxWr;JW zLfnpImUU%~3wV~4dGeu+3#fF)jL4)w-OO%6w!19xbg8Xt8bF#Axwvw*+54jM(;u;9 zufqxS(}FXvSyz@l^AGONL8^(Lnqyw-F+8>m@l+luHJGI@|5P>d;lmGm2YGhmO$rS{ zFRsq2$ab~_F&{O4chLP{W13P{nznrOeIsZ7%@deb5H7KW?eg{9MvuOwwSA8mo2z9A zbMp@j8vqJj;s)k!hpQUpq-<}wyDNYU7)ZW28HfsH+iN%Bjajjmvz7UJzc12YDi=N^ zUP@^-4?`2luId!Y5gS$eL@xF`-@w2_%PRAxXU*Hvre(m3=oxWHfdY;q5$JG>Y(Xp| zxK`&i1k1Q86B;8YN7e63_sAap^0v+b>fTT+n4}q*@Ifx9+ojW59FdclfaxJmaC!sIi ze?ZtLGGk|{RU__ImV$gJ`2hwuoL!hTkPLbInNYaH=h>@PE;>hhO5TC~H%ZsDGB-k` zl$|S|`s9gg_C)9O;5w$Z9ae5Ev)E=0^eh2Slb_ch?F zp|=d&6gS+C*EAE4++#53)k`hQz(u5G&>8DH0`-Kj4nv&edlQ5?P6U?$WAl!)Qlldm zM1ZP*Z|OEP3m)v^?zrGIaGHp564wi;`Zi86MIya5kdYi@U`Y}vw|%gyO=XQY%K5lo zCMky51~U}OUsM}~el#!u7_%AoIB*m}Q1U@#kPTok`mx72N4kRg+W*%6X` z&p$TJ*yPO5CmHyDu_so&mSed!R9?Q)a*(zRd#}9 zILKA0rwR;3{$js7cPAwJFO@cEnNPk&NyLrCI^ER7F-8c;pIrgbqG5z4J2(1jES*hb zls>+H_l-7DGQEBy&Fs~|E%15>?ng6(9h>i6qo*%C9sAweD57tPaax{oa48>Bl3y`?ICa-~ zNK91?p{8QHuXjiD^*67Z5~5bCrqIeLRf>^ZXf#!;Mwd<$aSjX!j>=b4(BPUfuxJeky5XlMwUykr(%6+`ZAVk&pO)FP zsQa5>`=o&IO9#}#kAXz~Wp25BBta73=^^kjgy!`3z=V@M27Ng^*n+ID&JVUf-u+XW z`%SKbB=?`Fq??R27xQ&qcydGFV-F>|u^#xHicc^?)Gcs+hUQvuBiOX7u4i)QJ_`j@ zk5)7o%s+91sw*)l;X`>~cf3vQjN%Fm1yZ-gPhWlu8Yzb~ouiy|r+Gp{@~2jYPb?M# zez@|fzAmr&y?5J>?J-kC7Edyj2Q??D2zLS6qTmLeGg?q`rgXRP6tEo{b@bV{n|a8+ z`thPxyhY+D9l`BDqx!6=SMJI~VHF1|ga6R-g74dNL_fhLM5Dv#a+O{Q1`b$-#N!?c zS>`$10Pq{Xh((;59&dIfQdqo6n+)y_XfmM0?>Jzd7Ny~WN4J4$n8sg9F}*+Wny>8q zB)@jsJEU{{r~^}-_PcMazoAYa()nV#RRl!s?&Jh2zM5M{Pi9uYu?fATW45`xFd1wi zI|`6eA>)*14`+yfBIh=*6U%{KAXl0TS|{*YTpfP zU`%utyQeP@uTY1`DP~8haNI3nI4kV!9dm#cj7En3{W+%k$6&8etPVXY=NP;9eIaWH zcc&}L5zPZxKzg%V3ky0o_I7)k#>tigpuzNiQMD3u>q$!iY>XTk))ZwQne`ne>|A$F z8M*Hy?V9WH7!H%e^JQU08Ay*~DT~984O~jgR##UMYHzP>Z0gHky${851ktKExnj|I48R4DtIy-1dhm8pAq3*jE9p!WCvUk%cdg z>5bpasMds^gH^y+MA(m#COUN|LExTIXi825>rVCmkz|1IM&!N$+@M>Bd*&2}j#{y622 zI?p5h7lVq3ipufSIhINO!Bn+XsnlzT6;?o5+}KGe-Ct6$R{pvN1B)9kE#8VMOw+L` zEXQ;_p7EOEX3-pVwCNjWdwJH&`$u7US0W@|84LS>>3F|iT z-^L1=Yp>=5;yqCVI?ziJ<3$!qa z?{qR?$M_|`*VAdLzC#wm;yeEcZ(amX=I-~(t3bHQXM_&~??Q_?P+IA4 zK*nmjPu@Ik5oh3sw7m3`^B+eCTiO2NDWpg)Zr`LC=PbHn$fya8GHV!5*Mno>< z*OO%4|8Vr!aHdsjkw+hp(4CFXh&@VdXM$Y&*~ge*nQ$F0zZl!7(3L|6Yba=5q{3t!Y+4DRE z&C|D#F(+#LAuYy_Z>8VQ-`k)D$wPB5NS$h-k9ILzq*ipu4}e$WD5XpE`O3F+^m_Xy zmayXZ=zsgP81tF>=4;#8L2ITi%>@LD!;H2ho+b#gO{2BHL1Q0x^J!`A@IS6H)dY0;nF zmB#i!@NJ$LKXn%DUx0NFwNkar1~rlKGohpFec_#4O6C6HgvEB_DLVuOsvedhqf442 zk^*g3Sg?|bKJ0Il6aizt39~=_Y0S>Sy-xkISbHv1moK8y<%z;o_aqgYg6j{17^&Ns zrVammEsH$dO$EWt1wNy8_hi&sSeIQoyrP$WCbh;*tend3Xi8JqId`ENIw(p3|H-zYY zjt@nw8fORFbM$zE@;!?}LcX>Zeo7W(7{CFSSbO(qgtzA5jq0pvhiu_TnHjW;L22q6 zcnf;`MNW1C(OKs1(gGgfS$vz+>!)g0DnwRF8lqoyfDeFNGNYUVUVaQLAdrtMS^B-Sgk>2<;!%ZHjdzIg>B_jGxbHmcBO7)YN~f3 zs9UFlsPumE+^A4o)0xS)XKdCeCu*rdLeZOXE_Qt+D^ zRZSc2Z`c5g&+kIm8=lnk2F$~2+uzWmXkZiNv?#KMP0r=nR3x9dYfQ6!v5dCT^4i_8 zgFb2aM6Z?pc&A0(+za~|s_PLQ^p#BH%1-%H!V(NcaB@;2v|fHRZ$bU2F~70R|Hah$ zwaqT!=k>sq9VWkiL(1-vunj(VJS1!Tc_6ZQ8WD{0shif?J2~WU-Y^D;oXt}K;QKHN zn#lr|r)_`27LlNpnRi`?!vO}xY{^dT;MyJ$1g`dT#+lzhQ=|>ST z9oV0^ty_cm^C|RTA3JtddqRk)AsH_Vw-%5Aju9>ndKb%vebYYbp4mz`y#aWlo9a}qxBoj+)QZ1xYn-Q!oWZ!r8RaQL_W7^Z=UORJH1{)ubkn*S&9rBc zMz#ly1^^|%Pi&V4jXkBpF5cgYKTUzu!O{jk?K5t$7F?)U3oO29^3xtY7Qe?R6fo-Q z+^8GTvu2#Y3pc@f(Nh!CYr-y&+rOAbbxHA(W{r9nn0}h>jB0J>piSN>lJ@-B&766n zKSyo}7-cfRixfzIArq;iY#2a;CBQy^9pW7HDfs^17~Lwz&ec5`>})%_&gO}3la%(@ z)Aw8Ti2@Xj$vxd0h3r5>3SGeblvC5p%}wZ)xOK_S3kk`g@Kn!jl{dS`n>;9R@gxzD zUNL@g(QbtM5Dx5nvwhx6i4Tl#e`M^|^1$3C5uW5#Y%)?v`~$(md}RDBrG!42@?HMs zMe1n=Qpk+hyN%vL6pq|2C+I=csZlh3de?Mkl!<1PcuXDh;0U90dn~x2Y5`>7X-V1w zN>m$VHtpA<{hzvK`ulISw&3d?(&AtSR3tZCM3gBeGx9^!_PdL1-t<&{;uC|iX*K%7 z85UtW#x@U+jR7-6p%WNZl`4DhPFFy*>6c)s?p%8?s@O&BvqzqI92iShc@C@gnx~Fn zGcf^*fcy->>ZPho&Rs`z&Rmw3V%1L&bI0~mJ>zsCg7;bCmXRt5Wn@mwZkH1VdMA3! z`F>PZoGMe}f*R;orL_P26MyMTZlSEe&axQaPiSg28m6(I{nXfHVan7wr4z+SL_(2V zmDfALPz3a_Nm=!}sT%jD9e(+^g+zg5<~WoQ9^ezE zj1pZ7mi}oic4b1#;e^gPPgCyaFVom%!PWIuhfbNaV}Z2kT-4{ch6*D+>0;H|Rx0+D z74(?BDI-5=DOr+^3`8?Xa6!j?$v1w{afp8}u5;t|P@K7* zkx!9-yHH0yg?U~HeK+H8Kry%XTp68kOC8ZYMKzkOim=&1HO{KX2r1Kgs^t;Pr>pSP zRL)31kfrQ9vAq|>oL3T9qH)86DqP^Pp3~bx_d1g!yg%~%x z&=yPPdaphwDq)V=qFFYC$$Qd4OAe&Y-F}#uvADF{j86R*%Or1cNi+H{*&jx4QWwqz zy*ee!k)FKr_@WzWddm9=4_L}m@+h)&t~Ri`h=3m733|WJCUlwevepU6?Ved?BH!^I*VuOvX!}-M^9;1 zo|vt$Gc3cP3i-_+nYnIf{Q3&1$)S}B>biIy=Itc~*8Szv2p;K#$kX|m0+S*+VQh{? zzpr#WKQgsAyo0||66b=E?6L84Pm{oim0dd*`Qn4uiz1_2WUAad0wWUi9@zcvEN0L$ z{gVRj4bU>!{q!xmgv*12SO}9o5sVrT;rzssB1h1l^xs!mKYvcPDe=S;C!P%kPM9LU z1jrF$hIUf5!c?zJFiw~syZ;HFHV5X;HdC&qT&or?!FeW`0d1o`hZxh9p46MSwATz_wV+=I? zNuA_EsUN5~L9}`qdRLzT9?f~-)Gq zD_?yT%RKfIMgSi(UXE(oy;sIckdAnx1V4A}RNG5TK^wL@{nPkkuA_dv;y?U!yzva$^o{Y~cfa2`HcQWr zb(R*`MZ11_i%CvSmgw={8%HE}gn+1C_Xw{wp__I(JHua$#%}HnUpfa@xhwE3kAoc? zel*a)gyZh+0ei!i+D z$?|V~$d!DV1!QwC&k?&`pP#Bc*947mswMi8*klRV>%X+YFFnIlwxI^UXDCQoq#@iC z&d_T7pY!5ght?|b<+d88r_cot7ytYu { const cache = { get: jest.fn(() => Promise.resolve(null)), set: jest.fn(() => Promise.resolve(null)), + directory: __dirname, + name: `mocked`, + del: jest.fn(() => Promise.resolve()), } const assetNodes = [] @@ -89,13 +96,12 @@ describe(`downloadContentfulAssets`, () => { ) } - await downloadContentfulAssets({ - actions: { touchNode: jest.fn() }, + await downloadContentfulAssets( + { createNodeId, cache, reporter, getNode }, + { createNode, touchNode, createNodeField }, assetNodes, - cache, - assetDownloadWorkers: 50, - reporter, - }) + 50 + ) assetNodes.forEach(n => { expect(cache.get).toHaveBeenCalledWith( diff --git a/packages/gatsby-source-contentful/src/__tests__/e97c003d47d50d52c7e2759a2e4712b2/347966-contentful-logo-wordmark-dark__1_-4cd185-original-1582664935__1_.png b/packages/gatsby-source-contentful/src/__tests__/e97c003d47d50d52c7e2759a2e4712b2/347966-contentful-logo-wordmark-dark__1_-4cd185-original-1582664935__1_.png deleted file mode 100644 index aa5c716ab32d707ad364105257ac1339818ec78f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 356 zcmex=>J?kdP3hOJJxW6$C*-Kstx+PN|`#BnF4h zp&5qmu6O zL)3<@#sB_TwlzAfHk^5Hv=eT$?PolpV7O*wG6^$0>(SpzHdu5pm{d2|&eESyHNgAp zCd~*ILu^J-acYq$yZArAa-tzOCIW z=vV67#O8$R82zlO^S}B#i3T_qg9R(YDGh@uHN$xmqa{1TtuVu*a>I>CgE>>fF-3!6 z8T~PNgX#B%t6vRIYYo9rZ^jzTd^DU?He7W#I&C&s{%SBHYj99tI4Z9{qhqv_WiSpi zShhF1#2Cz)8%!t|>?RrR7a5Gc)n7z_L&Nn*gZ&Eq85QGE1^p!r(-{-}wGZZ7Y5G$z zqviKzD?$3F9r}yvrpw>-Clw5*bPQIt&F583HsbWh-x^LE>Ce40o;EPRYnhF!7|eb$ zSPj+R&DWn+G8%uUkNc{>=&XO#pg;Z5V8PztXC2NAEPX44s*)OnOY+ejuheGDwn12_ z-K@$ZNw4NGJ1&FS?bJJ%(vjr@`Ah3d7i$%HvCBKhE91?nVFr?1+n7=>l}EF7XBQVD zFD}oI9!cKuDs5J=!-V~(cqVqKVRR{fSvj|T%6X}2bot_f@nEzp*O%J{G)rnHr|k%V zklp?FAsE1Vo`b|22zl6>8#vMjBv7cp`=A^Mgu7i{`jxut#72@!;yzh`XjO1{Gg~4J-2^C8Tf=nVlxBSg~ zW5V^w@cxTGuV0f;N}tCniHKmgG=?dbr%~0@TW9_fjGx7@!`1MlEwSZf)RJJf<05|V z0f-O+q5sJ!CJX>grFKTf&x6Rw$Q&J6LK#}*2q2I6$$zTaT zaQ@rxk@#kf}Z8+-FbD41sv%$)l%!6F)Y`DL+Aj8g^U-X&Pve z?pHD3Uy(uR0?RTDFjQ9RTg4B7#JT-^@xq#QxtERh1_WX@!OtSVN3Z~aGzUAJX9|oq z3ql}V1&Lw}{RAvA7$FdBMQfQ_5LAylG!m3I5D=^_?PoI&n}X5t10|}m1abh5MI!NLaPYqDSB)V{4u%JG<1iBhG2%c>3My;; z9&e{Ww%q!68a|OYUHV{s7L4M_1EC5-u^@$-PzWTtCVBbH^UkS1tt&0`Jx;*A#S%dd zfkfSDHw+_Rljo)JY4bvh5#nhfklgp^M{@ofzCwQaAxuHg3j#*a(J&OVqF*qzoSlx= z1peM0Yc2sKz|O;Lbp8EM*bJZj7tajy#OBAJAds8&)_>%^Us;u+14E|E0=9|?Ad99{ z;`EbDW#jY7u zN&PYBXDIP36yilYr$WdlrR?zKa@cHKi}OMK4k_eL%L@~0-Zp!I$f}cfFKx=Ve^frJ zd~-|;X@*6;9VbQtAU$7GfX;1vB%6Rw`WnPF&|eDgHzFY69+{-+$xEM304b$FFg0sl z#lbi~`r3l&qCm8wLoX6wN{s}K1dwI{3cppB2`zi ze;aH%Tp|UsTq!4k)L2)lS*;m5rqpsY7s#-iLjup-B)TnAZ5MZjy<1RleO1!83wC!%oJD(9Rz zD=ULfahBGy&sAu+m&8x_#Yrq0ITs?wJ2p!SH0Dh5^`p3tP;0w#;Fel<^wP~d(ytXhje!wbV;h8gWbZ2uoaVpz=AJ;n zx6B})c}%mdGA7a;!pIGCJKgBhgN8H)z6M^-aX>Lp;*GhCHdZGkLG?tRfoDKoLr-KC z(-)&d#)ID$`-V3stvwrxP}R@1EwZ64kO9 zauP&XOMkzAhd+LD@7=99&w-GF$tt&y4uQjD6Q57?f&o4E-xvj}=WuNlkehh=V7v)M zN-ji|O%KX_ZH|8A>CH|kIqca;qsD(7h*&{g?OFKgC8qIdncV(S6n3Mx;}l3FDd$w2x*VHXkWV)a-J*9E$TlP_To%muPHogt zZj?v>f+9#TC`8Ef-Er{Hc=2%GAxbU%-88ml99ONj(lJru-nYFs^BVM?1)uu7$)+Dag1XXtU=Ia*{aXG64Hw$;fo-r1g(LL~Jaj7Dw z??1L4o;l^DnC}U8%C%1*BQ#<>`!cw%{iMR^>v~xh)jyP8&R8y&oBOAAvP3AMt9tlQ z6OL__-lL->gDe$_$3Y4i8Rgu?{_LV^5zPV_wwmq%=)lO%tgA()oT0;8v+4v8tR(O{ z(t!3g07D769Hhe48Ty63`r=E(^LW~YLS$(q0Subp?a%-#!f_|nMrI~$^%_x-V<+j= zX2z<{Fm4-9h$lu-p6s-G-YzeM7e6RR<39}XWhXt3M&Ihh-CMzNFzEd=azl=blmy{; zSqc{~Oy{_e?MM8NFln8O6mceJwBoRiSYWXao=`>;~9vir}ckN7EvQzgx zh?F_K;Du5}x3v}uC%0aiJ@m`d?-QRQf@#4fOR`>Y<}rRV&b(L2>uN`UxP}dAA5Xqr z&cfT>Gic3wsz;4-yP9U_==?<|Oss2p$10!gCxt(Tvv@pQ5Aa+od{@RgOt5?d3RDkfj+YQvIak1^<>cks9Hr*+pq zij5Cj$iZjvf=wOlY=oLC@v{v{%1dwc*TgYj5avWe7 zmm}+ZK~WPXFb6BjdBfvF>-uobZxB$oBFt-Qa??=xy4POL)Bl5Mj`d#nbFAXUxJV?* zGFSEbvgfJM^;hq(y7ZOXWn0u0=+Q4uolEU*YJYK=!P^n`$-+PGy|x<2=jT)A{N*st z{t^p!;#J)3gGbKl)ZUqRNb{252h6I{iZFE3T=`@zKZZQ!w1W7B>Gvl&Bj}TG`kC|K zl<^bik@|2kOs#~v*Vw0F<&~Gxj}~l0WvP~ad7npD?>}N4g$*WCTahaK2y^tw+~66o zlqh+NP+m(@opJS*`0^Wgw^qo2{{{20C313f8|q^`_VTi69Pv5~bh|c5RBvJ-vmF*f zbigLK^p0~jTcNZJE8BZnp@aJ@tzJhhk;CX(N-D-PpD$G>+Gb-N_PE~sOg06Z zWA-|Y{N2|zF`1+@KJrl$+xLD&;hFod*xSFaIVel!kAKAJtukxmB7K&A=@t^QG#;9g z5?CtbB25Lb!5`10M5|6v>_6EOb@_4?B%Ri2?-vGXXiO6PCA5@&z^JNGne}9A`?50R zZl3nD0uAmQ3DO+eQS0;(blR~}0rDF#J{I#*TkyxTedcT=lIgwpZb)JIN%LQUPJy3} zz6%)xL2vb`yRRLT`IObYm!jPZT)3tom7vJMG#WBGT#WV(>lA<}9=e*>QaxLJ-S`n} za?{B%_52SlBj4uK(AG4`3hp!@N#fjIVDda%!hM`Oa3M#_CgV_wG(2XkWfA$dGpjUK zQt&Q8HQwUS5I(!?FY8}FcZ11?hBuX>^V7OfgRnGJfcxru3`PA^^+%wEA@D9q^x+1awRlDwZN>yvPs0Y;aA3EH9k8STj~e$N=ooXLUY9L z?xNm`S*|J|zBNLD#f1!wk36|Lo(hP(T}iUM@YRS9H5=F2b@*c?+56esH`d}f^5f}GIHPdtU~b}Dp*}8 z>Gnj*C9m4Yv-7^K%ZieX^HJpT11TY4{n5-SJJo|x8=j)HjGdbC*K1jACOa*f!U5Ke z{W(b2Tx75`K;Y;TEj%L$n62VED?+F#SDu!;M4-Kap@|5J%58a5E(Ir;0%PXoBAdEL6v8{RvF-j$09_1wo? z&BYiCc7}4IU#vTR+Fa*;*u=}lY-dqTp%C2xO@Jt{4rU>1A}LAO5E;8;c!B$+4yDF;)YxseY2SU6g!KpY2_QaW=d-Y!bIB^e5}{5A<9z1S~Ccqze${0 zX84;N%T>Qff~CzvS`AgX5jb!g<|V{2iDwJKgW)>Wwg^1)TZ)GSQi#FnK>}=CE)vR` zmB+F=>s_cg@pYPvviKg#(k6pR`8G?+qUZ*Kh-blRaGDeHPx8YMs+OouktkI9YC+4< zsIaWS%m*>}KJRg8P59$UD~?GZ8=viTMvUTq2aIB(N9yk5PyZylKs$Lv5Nh~_q?I;X zk~#+OQ=MpTl;xx`^m&5#cW-7yn3C+N_e4i$k7b0M?VC_|Tr$XM#v4 z!Z;E^g&&5cI#iwVrXv;Fs%lBWk>#wVXQeu2s!&!e+NKXmyU@Kns_yp{;&IO-pp^mNm-q^-$Q^EcPqlfn!zFO> zS~_-)U!-38wjKStiSMMZx2_3dcrANBmsye94!LZ|us2iO`vn`NgNW>SP9y98F?_8I zUYz;@-7N0?6mDH>ehO&S-#LYzkIgpF@MWfh$y=|3 zsmf^|pFv{zBkpUD0#6OsDMv?n4JT|Pwl})fSF-<{k4>7-_N?D9%Xf-YauJG#4|rSK zmc2oxVNtIfm{O)PuT`b2n|-OGB%!jlSCkecIJuVS2Wx*iO0yCXAcCQ|^6heH)Nkg$ zTT6(go{OTAFHlq$s?CJgo9SkSyl9DfrW)!bb^7=(87637r_$s$L;s@B%r*nz)xtYe z@YhVq7EFeR*JOJf8A%SN1iDG8CSBk3duivpauG7qQ+qb>Vds-MJ{inYFQj()To-_6{o7)r52 zvODN_%4K=s$5*E6iFrN>nb6|6zO%}dw-xZaSqg-YXBMSVhBGGfN_GzTj$2rj#>ErD z{U`SpzK`a+C0^H7Ncy%V>8)i$R1nzy8Z}oxRG*0{evY*Zk!0ov;ZH0(4EjrFs|FE@(slm$3)RXHtk}uv_i9z5Bv8M?lVb~l zB*t=N#F)Je4vqSFQ<;=arO7C{k@+A>wyfbUi!v(|KLjgua*ALv^5F>c*;R&%&$MAe zC{VRtItj0NR!U{A|1B5l;=kykvQmX(Nj$eRBAiQ}V58hMS%MeB8T9O+KnBRtMQFrKlV>8B>hJxjV5OA=aBF_$ z+#5XS4gu0fM$u3H?(%&vwbZz;+>;)^_e8-1^=?L(H5;oc1LU!PaeBZWdl$v655$r< zU2Ay2$-WZ2gEkSqM%M{Q@seWy3^R^@)yRhd(S9VHzZ&AY@!1hI!iOQvL?~`ufYOq2 z-|hHKjR93|BlV$Z&+zkV_18ez)SLUNQt8q_Z~JH%+{}bfDm5pnL+G(CzQYvAgryq~ks^8%>wr0#cp z=?vNYbJd$zZw{&oVt@FeNGDUgWcF*IQDD&F13)<(vOk%7E&kvJB4h5zDIJQq88A)U z9ird$oI?AN@sSK?F7(@|Q9Mmw0z%E1N8jl3F{a9~HJVil$X>(UOoDU%e)+9mYG*uA z^j+ensTxjYGjPQ(eKnRY8``%OY}HORNYP>w(bby<%|J*U$FMX)Uz{dB?JhA%wRzFq z#62IhlKrHn;uGb?5ymy}nEtrzU^$DqT;J4dJ7w?v2-5;Sd}`?MzK?BVUSp;nfaUIS zz5;kNp~r6!WeMy}QPO+sOZnNPA#|`cS2l(})c6iS8}JT;KS^?7^Mb2)KJTQ)PWkE+ zS@nHCRiMlFSYH&7aiGLvta(mkR>G$;0RDi5$Z_;1*jzw|2Pq>V2 z7cb+@8&de}98`-HkRGI=d=g#CId3Vk({cJf=q1;NN4gc?TcCA%g?Yd|HWfMEPtoUd ze>g* zho>U7vw|+%WF5p2X~>9A69r@@I*5e>B_JMmB0~8^?>`W90=QMbGRri)CnOaqzS6O! z127;4)v&YV&=!ji`Are2(4D+N7$J5n6-f*3=%s?WT{wCVj)Zd6)h1kwMWWk|p44r-{C~Wb8zfKV z_$8utBV!M%QH1v7|Cf=XsdleBpwY)V87_*?Rz?M;Aum^%M>3FP7}zpuC%B(tBf5Y;GX z!4=|^J?fC^YfG^a&X2@LC^CppbA=X&S2#)FVi?9*$v}a^P<*VXM6(UqP7@{2D2S9g zza_#@nD4K8VZ7mrLlp1u+k7jyDUu{i(hawApNT9fi6zn-d2&yYmRNFfC)i!oEkuR} zP`DzK>f&YUw18Q`JwJa!yBG)!GtH*Lvgh=syk?LD?%s>~LzTX(9oV2NXzLI6{aQbb z9g&QM7pL>X=z0q@mU0m8ugmm9t;Fztj`AOz#VgXFY6z;8`jlN%nn=4D;^8+Tk~6FM z{J&*}(>F529IQBrqW%*4M<+xE$8Zvp!uQpcwP@`6KI1fo9BbcQ| zC)Amw{^5~5|Bp~}!sV(}za9Nu{(K(WvS%2IG&s4nui48xPZNk^WdPqKOa{#(+MQ1c z^A0*`%3mIQMXc=W0*RUlab<$>+*sP<1Q!46i#&SCNl-%U9nT%&A`Fk|vv#bd=(2>& zgs0k+3)U|CNAJt2EKbCr6}Hrcr6&u>`iNDj$`0Xt#dY_4|LZJU*Z16kz2Bup2Z60R zxL^J^MF>Rw zfBoS)UsDQj%qtj*&w3in4P9zjl#s-0+XUg7k<ZT8Y7yKLMys_kC!bxVIs4l8__nn<_ zvmem29H`UqugxzDpvpIv>(7TN{+boc7TfX-l|TnR5+ov-sU)1uZ`qP}Daa_>DHTV2 zy;=9AD!yFGDij{4OgC5mKG~(dZZ|{>WfMBn3{0WNO z^Q?G#c(K9PZS{KM{KCfQj$n>0uJ;>Ua1g3Fr<->c?UQ6kGEX-GGfaioI+qo41Ab$=cEs_4BJHy6(a>&?gQ?}95p zZ>^DOGW^&*%J^Yb8V1di2j`UJDmQeED=*fVk7B21x!F#0uUY))glM! z@z-3yTe7!Y7HCZ8_r8S{l!|VoET{Mm=Zst>W+D5N158$=nC`ZbnjhH|Dt>Y6xB}dX z@!5B1h-L5pjt#cwyr~*keLkhgY6f1&%Kc&k=}6Ty+vkrbRq!2Y!xZjmw|Vc>mUTU% ziH2PaDGUX?Ji5+oJ4>4i4YXPsA6%XwUie5L++74-HHFSAj1^24cBgiRW1RpCw5E#rIhRt@)mK12i|TKQx0{+2OzN+iZNvvFuVnp!st zg}dHVy*7ww6{FOu(>WoVi9%`1xM#$?-QT>`(_*6DSHMN7w@T7i!BZR*(=WL#OZ;;Q zHMh>L+!`SK<6(_d;)SgzmfC11vy)DT&ZD83fNG?t z16uX8v08a4ws20Y=NVypQ~^mrtAd4X*t6dfe=GHXTP}AaqC5`{L-y%+!*wmxBMGd2 zEC_H?(ta@x2a_x#DwGSZnW9BSm0MrJZq*G_?BFO82ALV{;y-Y31n7F6?QDmVzy2D^ zBbVu^iU(Ii)x%3)&f!h;q(pd&;K#A5kCsROKyq+oYDXh8plQ#)7;j7-EIpwNgnxW= zNHN{;c;$ZBA9naY`1w3x&2o}BpJD3*oiIgHtUc3 zs8*Q}-aRen@6s8_4{fLxO)<+J%XGyLIk$o_u%)pQXzcv0c6E)YYq7|a;k{wu(SmcX zSuKmUhW-#WxtFB%o8W9OZ(X}G*qAK({mq~;0*@mugUiIu(J+<&uxunHFNLk_O9D!- zxv2-4KFjm=$={*&)ilk3zy3C!;F1OPHuILMmKe+Xe1mk@MLg5`kCuLQuY89; zNf242uNd!Kg(49PnX58V4RGNf^go;&zv}?_`*FIZ_mdREB(<|-;xH@z@COMZ3GtwG zl($YcQUz;afeD$E#R>v>PCmCO6*>Lt*uoSWIg(hCl*WIr1i=GtW)=r7{mPy+iH2J^ zV9J@Wv@z3nR{ZJ{1W?zT9%QeY_+{oNOAgG3N24CAzP7+v8@_#AG(Z89?HuBbMc_L& zGT`_EOU;tzmuA1n+Ol=!E*!1$;15zvq(AKjl&+1b9!LRvkqzr|fV5*T2Nt6_C^MQ$ z!^^XP$yK>8A~rzr&V3TVOY1*c_8eo_? zioNRA_c&zaoJjMUbb%jD0^ah^=6Y8m;Q=wp{CWltx5|cN2iFHE`eD1m1F)PdlI&$k zNx*3Mm-2aK)8)knf7c7!b2Q`FS;=U~NH11|{pfwCZH2q-(k0gOv;(kMNff#mpg<1{ z@)p!)@;8(z0(?N%)>}ZPJ`Pq04gWN8`?9Er{_=3?tuTe#{LkN&tL90=u1zJPd3)y7)j*zvJ=sD<8@XmqW5C zo{UQnOD@E2#M^#4dU$is+BgL+S1$c`==G18+t@JmXLW-ikCz`rtm24sti@}GJ0y+? zm?YlVxtMxP{TZC}*oD12LnS-Um?+(Ll6tqjtN3E-NE&zwTY9*fy+>2A;?#O@@7veo z&?;Kj1;#6?z3E2FNOZB?keOf_WmW$svUeo|&Ki@PoCj@xr;L!IEU6oUEyI}hQMGN! z6X%03WG=@gnoMG>H$~|xN*lBHpYMMU;{cfZyAwTE{S5AiNkJnCb6%nzMj zku=b!Av1X%#5iHJynL=3xoUB{v#{`aQSQnoA^NyT3yQ?XRT**l{Rd1QYKsm16t9Ge z)Ud26MDgIW>qhrIpAWj{^(nSWA`?E`B5R=zN=#KHM0J^3)xmiLolN#xQQdC*ePSXeLe2L_VF;<^jQ^m z8*pAl7s|+b04pwU2p3ARi>f}z;dV3VFG7yYu+a3>ACe7!`J*>hBe~r+uTYH&KLBs> z-wn$pxc7EZ<-sSE@82m8p=_iq3;8s|s%UpSZ=dPF!e;l-VXs}?B{h}4Pd9tSP?D!N zc|xlI+U1I^g;SrHeKlNN8-;y%x!*K>cacV-YCvFNN31e7+8-->+|ZT%JdS&GzlKm- z+UXiCRqv0!sNZjLbSLXPJvaAN0S778VrY4K`VY44!&_UDO>iCeG>OV*y*YIU=)p49 z+xPUfrS+qg-;7)qCm3`zT2(0LADo!l^cq{C?&y8-E2JrS)NM3 zA-nqJ#i<*1L`Gf{bEgfZ4gXTNHxsaCw&u_H!4kQ1+_)N45HR`kx9+;I=;>ij^Frgz zY?e6dHNTw$iIEziJ9`9<#o3Qr0mZ1#5MVy+8KQ% z_YV`T-r8Ok`Px)XyY5+Pme-z1{uWqpI?!(oB)#T=OR#?^;;7BqVp@p37 zB{qgSg|1|JqfH<*IXFve*e-^!k=etY>ynbWZVL4&V!>X z;b+f2$?DU1tKeh8oqKwcbQg5_>>Gx`FLf8Mi9g={sa~90Rghq9 zI2(!5Or>E7`{!?=Di;#PB3(EMYxzBGija@~H5Ueo%|D8J4tV;%TghuP_TAuNQ=(K5 z*GEI=7p>Z3{GU;(nJ@Bw_f_9+Z2$FHkj@3%I)E#``W&fa{MZ~8p*G%#=i=IAwJdg5 zPI4|{Gx5;&HWU~+Ur4|r8N)}>YjrP`RylI9`Z=W`#rtL@RaCpmnMSj!`hM&d4-ype zwvJ)yqV+H|KFwD|tjW4I-uu|%4V?z8h&JFn<a@=kc9H$PRf{onz}SXx7Xo*$^n__c0as z$36M^JA!*LeXHK(T#uh8`iY^mY67q^OT#6^G53CDZR`j=Oo>QSvO(kkXVounO&ZIG zw}(&kjD1YW3C`aU`-FA#|1*4oO${`ar zLKYv$-l)M7U7zPzbE>Ga(-%}zY+4KHH=ba2{f3)|_Hh!bc(b*=v;GfKRdz^@%5kv4 zNL}ymk&k6$EeX%Af!5c1(fR_{D^vH`M+qK=cgCwclt_~cDhOysD^mfw1?I_z)b>+k2=u5(CZ1qOc^4R4}9g5zLORkM>^!=o>PVjZYmBDu>RCs!$ zkr%m7P2N^cbuq+#D+<_9Dp9P0Qz$WzU!+(d_S#(tkJX~@Rf;Hgv`uv|UGM$rI{nD1 zq%aG7(!-@C#qWHFf#Pq{iL3qtQtY`oJ=VJ6WXki;k9>-7*#ct+24kgb?3rpC z)Zc$}?XEfV=sc#`u=f*bz$Fo-*`C@+eANP^tH#%0YV3)V%AGfB{7=ZO$s~QnNSkA% zJ12|Wx9+2CY7aE=jiPp8FCVTRKcV?aKW?qh#tinjvd*SQ6d}!vF!{cY%hOu-#_GX_ z+v^WL`CU>z$JUEK3zNtaHlN+`DHGl_2H#fjBIIOSp&pw^pzmfBjZwB|5YuHWFuCqX z2!W{ErGA)g3R}VT@b{nRsUO;X-e}R{R_1;NcKu%0ROidy__Ckv%zL@wQT9OA#|rhe zp9%tT?)i?m~hmcKxZ)(FpDBn%d7_O`QrU@L+2$wS5*9 zcKzU%s9x=0)bdnqlfzb**2}m%V0UxCQXitCGjjMdJG+%jvbl|^sgsk()b+UAAn%72 zcC~|5MG@?4HWg*hxzGgn%|IueIM&?IRN$Exo%xmN-z#G5EWa`YqVgxCpZ&VFHLGTV2YNW1?udxK$B+n*j7(r3Vh|Up*Z_FWXd7 zh?js^e~e=rPxM#CU5sxWyYhiP;e@d`bWYJQ+PD`4qJr+51SB%|t$?wASY`!Z2FqN1 zuClUp?E<61XSX?lzf!^D6mqjbuElJ}aQ{_wH5zKGGa2hl^RFKqVQ0FZr|sEEB@4bw z;>FC_l>;0y0~XXE%ZB6YCubKp!~Eejh?fB8xkOhL-})5DFqn<~)9~4N!+*HLs^$oc zOt@ncLf|%avj_kV#(^fqDFOXo)lq)ppi#^QQlE1w+H7lw-?bIQ^lOjZbE(&6YBr-E zWD+#3M)DqN@LPlPO0t}ZD=ib>EnI#GtN zhe0;wZi7aXvp!(=v%wGB4qK0`wBW<*NK>CkE3n0zmZ2!L)7JBlcMwI~c)ap*ay?<^ z)MM%+*q7c3+;%qJ`=Ec^?RX|w@^w=|;{2oxE9&NpBm-Z*v3EI0x^uBq?d<9}bqxan zi!Xb}Zb||Z0j3bQQ{z(A5(_pXH%l{!twdXoY|X}iJ?G(~P2N5>P!M{z)=G#C!@LRKw`C$-?Q55F!XONr)+nDy4 z0)fX}-z;`I5=vyr1>*uyeem>O3Il4tDj#tthL#zF6IJ}dcAf_B8Bn|d0eIQZf;9p8 zQG2DbG%2`tq#^}Mly+`ZetxTS#)v_sJ321 tb-BaUE&3!7pvn%uk3fYNGzvYrid6mCqWrZTEOrP){*97!@oR%`{|EIR@yq}K diff --git a/packages/gatsby-source-contentful/src/__tests__/fetch.js b/packages/gatsby-source-contentful/src/__tests__/fetch.js index b7541b0c94af7..6165b6991f32e 100644 --- a/packages/gatsby-source-contentful/src/__tests__/fetch.js +++ b/packages/gatsby-source-contentful/src/__tests__/fetch.js @@ -60,10 +60,6 @@ jest.mock(`../plugin-options`, () => { } }) -// jest so test output is not filled with contentful plugin logs -// @ts-ignore -global.console = { log: jest.fn(), time: jest.fn(), timeEnd: jest.fn() } - const proxyOption = { host: `localhost`, port: 9001, @@ -113,6 +109,9 @@ beforeEach(() => { global.process.exit.mockClear() reporter.panic.mockClear() mockClient.getLocales.mockClear() + mockClient.getContentTypes.mockClear() + mockClient.getSpace.mockClear() + mockClient.getTags.mockClear() // @ts-ignore formatPluginOptionsForCLI.mockClear() // @ts-ignore @@ -124,7 +123,7 @@ afterAll(() => { }) it(`calls contentful.createClient with expected params`, async () => { - await fetchContent({ pluginConfig, reporter, syncToken: null }) + await fetchContent({ pluginConfig, reporter, syncToken: `` }) expect(reporter.panic).not.toBeCalled() expect(createClient).toBeCalledWith( expect.objectContaining({ @@ -144,7 +143,7 @@ it(`calls contentful.createClient with expected params and default fallbacks`, a spaceId: `rocybtov1ozk`, }), reporter, - syncToken: null, + syncToken: ``, }) expect(reporter.panic).not.toBeCalled() @@ -202,7 +201,7 @@ describe(`Tags feature`, () => { pageLimit: 50, }), reporter, - syncToken: null, + syncToken: ``, }) expect(reporter.panic).not.toBeCalled() @@ -220,7 +219,7 @@ describe(`Displays troubleshooting tips and detailed plugin options on contentfu throw new Error(`error`) }) - await fetchContent({ pluginConfig, reporter, syncToken: null }) + await fetchContent({ pluginConfig, reporter, syncToken: `` }) expect(reporter.panic).toBeCalledWith( expect.objectContaining({ @@ -258,7 +257,7 @@ describe(`Displays troubleshooting tips and detailed plugin options on contentfu throw err }) - await fetchContent({ pluginConfig, reporter, syncToken: null }) + await fetchContent({ pluginConfig, reporter, syncToken: `` }) expect(reporter.panic).toBeCalledWith( expect.objectContaining({ @@ -299,7 +298,7 @@ describe(`Displays troubleshooting tips and detailed plugin options on contentfu await fetchContent({ pluginConfig: masterConfig, reporter, - syncToken: null, + syncToken: ``, }) expect(reporter.panic).toBeCalledWith( @@ -339,7 +338,7 @@ describe(`Displays troubleshooting tips and detailed plugin options on contentfu throw err }) - await fetchContent({ pluginConfig, reporter, syncToken: null }) + await fetchContent({ pluginConfig, reporter, syncToken: `` }) expect(reporter.panic).toBeCalledWith( expect.objectContaining({ @@ -380,7 +379,7 @@ describe(`Displays troubleshooting tips and detailed plugin options on contentfu throw err }) - await fetchContent({ pluginConfig, reporter, syncToken: null }) + await fetchContent({ pluginConfig, reporter, syncToken: `` }) expect(reporter.panic).toBeCalledWith( expect.objectContaining({ diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js index d43b9b13ca4c7..9f75d655e25a2 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js @@ -1,12 +1,12 @@ +// @ts-check /** * @jest-environment node */ -// @ts-check import fs from "fs-extra" import { setPluginOptions } from "gatsby-plugin-sharp/plugin-options" import _ from "lodash" import { resolve } from "path" -import { setFieldsOnGraphQLNodeType } from "../extend-node-type" +import { createSchemaCustomization } from "../create-schema-customization" import { generateImageSource } from "../gatsby-plugin-image" import * as gatsbyCoreUtils from "gatsby-core-utils" import * as pluginSharp from "gatsby-plugin-sharp" @@ -53,12 +53,38 @@ const exampleImage = { } describe(`gatsby-plugin-image`, () => { - let extendedNodeType + let contentfulAsset beforeAll(async () => { - extendedNodeType = await setFieldsOnGraphQLNodeType({ - type: { name: `ContentfulAsset` }, - cache, + const actions = { createTypes: jest.fn() } + const schema = { + buildObjectType: jest.fn(config => { + return { + config, + } + }), + buildInterfaceType: jest.fn(), + buildUnionType: jest.fn(), + } + const cache = createMockCache() + const reporter = { + info: jest.fn(), + verbose: jest.fn(), + panic: jest.fn(), + activityTimer: () => { + return { start: jest.fn(), end: jest.fn() } + }, + } + + await createSchemaCustomization( + { schema, actions, reporter, cache }, + { spaceId: `testSpaceId`, accessToken: `mocked` } + ) + + schema.buildObjectType.mock.calls.forEach(call => { + if (call[0].name === `ContentfulAsset`) { + contentfulAsset = call[0].fields + } }) }) @@ -125,12 +151,9 @@ describe(`gatsby-plugin-image`, () => { }) it(`default`, async () => { - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, - // @ts-ignore - {}, - null, - null + {} ) expect(resp.images.sources[0].srcSet).toContain(`q=50`) expect(resp.images.sources[0].srcSet).toContain(`fm=webp`) @@ -141,7 +164,7 @@ describe(`gatsby-plugin-image`, () => { }) it(`force format`, async () => { - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore { @@ -158,7 +181,7 @@ describe(`gatsby-plugin-image`, () => { }) it(`custom width`, async () => { - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore { @@ -176,14 +199,12 @@ describe(`gatsby-plugin-image`, () => { expect(resp).toMatchSnapshot() }) it(`custom quality`, async () => { - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore { quality: 90, - }, - null, - null + } ) expect(resp.images.sources[0].srcSet).toContain(`q=90`) expect(resp.images.sources[0].srcSet).toContain(`fm=webp`) @@ -192,14 +213,12 @@ describe(`gatsby-plugin-image`, () => { expect(resp).toMatchSnapshot() }) it(`layout fixed`, async () => { - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore { layout: `fixed`, - }, - null, - null + } ) expect(resp.images.sources[0].srcSet).not.toContain(`,`) expect(resp.images.sources[0].sizes).not.toContain(`,`) @@ -208,14 +227,12 @@ describe(`gatsby-plugin-image`, () => { expect(resp).toMatchSnapshot() }) it(`layout full width`, async () => { - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore { layout: `fullWidth`, - }, - null, - null + } ) expect(resp.images.sources[0].srcSet).toContain(`,`) expect(resp.images.sources[0].sizes).toEqual(`100vw`) @@ -225,28 +242,24 @@ describe(`gatsby-plugin-image`, () => { }) it(`placeholder blurred`, async () => { - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore { placeholder: `blurred`, - }, - null, - null + } ) expect(resp.backgroundColor).toEqual(undefined) expect(resp.placeholder.fallback).toMatch(/^data:image\/png;base64,.+/) expect(resp).toMatchSnapshot() }) it(`placeholder traced svg (falls back to DOMINANT_COLOR)`, async () => { - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore { placeholder: `tracedSVG`, - }, - null, - null + } ) expect(resp.backgroundColor).toEqual(`#080808`) expect(resp.placeholder).not.toBeDefined() @@ -262,12 +275,10 @@ describe(`gatsby-plugin-image`, () => { }, }) - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore - {}, - null, - null + {} ) expect(resp.images.sources[0].srcSet).toContain(`q=42`) expect(resp.images.fallback.srcSet).toContain(`q=42`) @@ -285,12 +296,10 @@ describe(`gatsby-plugin-image`, () => { }, }) - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore - {}, - null, - null + {} ) expect(resp.images.sources[0].srcSet).toContain(`q=42`) expect(resp.images.fallback.srcSet).toContain(`q=60`) @@ -307,12 +316,10 @@ describe(`gatsby-plugin-image`, () => { }, }) - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore - {}, - null, - null + {} ) expect(resp.backgroundColor).toEqual(`#080808`) expect(resp.placeholder).not.toBeDefined() @@ -329,12 +336,10 @@ describe(`gatsby-plugin-image`, () => { }, }) - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore - {}, - null, - null + {} ) expect(resp.placeholder.fallback).toMatch(/^data:image\/png;base64,.+/) expect(resp).toMatchSnapshot() @@ -348,12 +353,10 @@ describe(`gatsby-plugin-image`, () => { }, }) - const resp = await extendedNodeType.gatsbyImageData.resolve( + const resp = await contentfulAsset.gatsbyImageData.resolve( exampleImage, // @ts-ignore - {}, - null, - null + {} ) expect(resp.backgroundColor).toEqual(`#663399`) expect(resp).toMatchSnapshot() diff --git a/packages/gatsby-source-contentful/src/__tests__/normalize.js b/packages/gatsby-source-contentful/src/__tests__/normalize.js index 70e3a39ac12dd..37d372d1ed04c 100644 --- a/packages/gatsby-source-contentful/src/__tests__/normalize.js +++ b/packages/gatsby-source-contentful/src/__tests__/normalize.js @@ -19,7 +19,10 @@ const { space, } = require(`./data.json`) -const pluginConfig = createPluginConfig({}) +const pluginConfig = createPluginConfig({ + accessToken: `mocked`, + spaceId: `mocked`, +}) const unstable_createNodeManifest = jest.fn() // Counts the created nodes per node type diff --git a/packages/gatsby-source-contentful/src/config.js b/packages/gatsby-source-contentful/src/config.ts similarity index 100% rename from packages/gatsby-source-contentful/src/config.js rename to packages/gatsby-source-contentful/src/config.ts diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.js b/packages/gatsby-source-contentful/src/create-schema-customization.js deleted file mode 100644 index 2df57f0045acd..0000000000000 --- a/packages/gatsby-source-contentful/src/create-schema-customization.js +++ /dev/null @@ -1,574 +0,0 @@ -// @ts-check -import _ from "lodash" -import { fetchContentTypes } from "./fetch" -import { createPluginConfig } from "./plugin-options" -import { CODES } from "./report" - -import { getRichTextEntityLinks } from "@contentful/rich-text-links" -import { stripIndent } from "common-tags" -import { addRemoteFilePolyfillInterface } from "gatsby-plugin-utils/polyfill-remote-file" - -import { resolveGatsbyImageData } from "./gatsby-plugin-image" -import { makeTypeName } from "./normalize" -import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" - -// Contentful content type schemas -/** @type {Map { type: string; }>} */ -const ContentfulDataTypes = new Map([ - [ - `Symbol`, - () => { - return { type: `String` } - }, - ], - [ - `Text`, - field => { - return { - type: `ContentfulText`, - extensions: { - link: { by: `id`, from: field.id }, - }, - } - }, - ], - [ - `Integer`, - () => { - return { type: `Int` } - }, - ], - [ - `Number`, - () => { - return { type: `Float` } - }, - ], - [ - `Date`, - () => { - return { - type: `Date`, - extensions: { - dateformat: {}, - }, - } - }, - ], - [ - `Object`, - () => { - return { type: `JSON` } - }, - ], - [ - `Boolean`, - () => { - return { type: `Boolean` } - }, - ], - [ - `Location`, - () => { - return { type: `ContentfulLocation` } - }, - ], - [ - `RichText`, - () => { - return { type: `ContentfulRichText` } - }, - ], -]) - -const unionsNameSet = new Set() - -const getLinkFieldType = (linkType, field, schema, createTypes) => { - // Check for validations - const validations = - field.type === `Array` ? field.items?.validations : field?.validations - - if (validations) { - // We only handle content type validations - const linkContentTypeValidation = validations.find( - ({ linkContentType }) => !!linkContentType - ) - if (linkContentTypeValidation) { - const { linkContentType } = linkContentTypeValidation - const contentTypes = Array.isArray(linkContentType) - ? linkContentType - : [linkContentType] - - // Full type names for union members, shorter variant for the union type name - const translatedTypeNames = contentTypes.map(typeName => - makeTypeName(typeName) - ) - const shortTypeNames = contentTypes.map(typeName => - makeTypeName(typeName, ``) - ) - - // Single content type - if (translatedTypeNames.length === 1) { - return { - type: translatedTypeNames.shift(), - extensions: { - link: { by: `id`, from: field.id }, - }, - } - } - - // Multiple content types - const unionName = [`UnionContentful`, ...shortTypeNames].join(``) - - if (!unionsNameSet.has(unionName)) { - unionsNameSet.add(unionName) - createTypes( - schema.buildUnionType({ - name: unionName, - types: translatedTypeNames, - }) - ) - } - - return { - type: unionName, - extensions: { - link: { by: `id`, from: field.id }, - }, - } - } - } - - return { - type: `Contentful${linkType}`, - extensions: { - link: { by: `id`, from: field.id }, - }, - } -} - -// Translate Contentful field types to GraphQL field types -const translateFieldType = (field, schema, createTypes) => { - let fieldType - if (field.type === `Array`) { - // Arrays of Contentful Links or primitive types - const fieldData = - field.items.type === `Link` - ? getLinkFieldType(field.items.linkType, field, schema, createTypes) - : translateFieldType(field.items, schema, createTypes) - - fieldType = { ...fieldData, type: `[${fieldData.type}]` } - } else if (field.type === `Link`) { - // Contentful Link (reference) field types - fieldType = getLinkFieldType(field.linkType, field, schema, createTypes) - } else { - // Primitive field types - fieldType = ContentfulDataTypes.get(field.type)(field) - } - - // @todo what do we do when preview is enabled? Emptry required fields are valid for Contentfuls CP-API - // if (field.required) { - // fieldType.type = `${fieldType.type}!` - // } - - return fieldType -} - -async function getContentTypesFromContentful({ - cache, - reporter, - pluginConfig, -}) { - // Get content type items from Contentful - const allContentTypeItems = await fetchContentTypes({ - pluginConfig, - reporter, - }) - - const contentTypeFilter = pluginConfig.get(`contentTypeFilter`) - - const contentTypeItems = allContentTypeItems.filter(contentTypeFilter) - - if (contentTypeItems.length === 0) { - reporter.panic({ - id: CODES.ContentTypesMissing, - context: { - sourceMessage: `Please check if your contentTypeFilter is configured properly. Content types were filtered down to none.`, - }, - }) - } - - // Store processed content types in cache for sourceNodes - const sourceId = `${pluginConfig.get(`spaceId`)}-${pluginConfig.get( - `environment` - )}` - const CACHE_CONTENT_TYPES = `contentful-content-types-${sourceId}` - await cache.set(CACHE_CONTENT_TYPES, contentTypeItems) - - return contentTypeItems -} - -export async function createSchemaCustomization( - { schema, actions, store, reporter, cache }, - pluginOptions -) { - const { createTypes } = actions - - const pluginConfig = createPluginConfig(pluginOptions) - - let contentTypeItems - if (process.env.GATSBY_WORKER_ID) { - const sourceId = `${pluginConfig.get(`spaceId`)}-${pluginConfig.get( - `environment` - )}` - contentTypeItems = await cache.get(`contentful-content-types-${sourceId}`) - } else { - contentTypeItems = await getContentTypesFromContentful({ - cache, - reporter, - pluginConfig, - }) - } - - // Generic Types - createTypes( - schema.buildInterfaceType({ - name: `ContentfulEntity`, - fields: { - id: { type: `ID!` }, - sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, - }, - interfaces: [`Node`], - }) - ) - - createTypes( - schema.buildInterfaceType({ - name: `ContentfulEntry`, - fields: { - id: { type: `ID!` }, - sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, - }, - interfaces: [`ContentfulEntity`, `Node`], - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulContentType`, - fields: { - id: { type: `ID!` }, - name: { type: `String!` }, - displayField: { type: `String!` }, - description: { type: `String!` }, - }, - interfaces: [`Node`], - extensions: { dontInfer: {} }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulSys`, - fields: { - id: { type: ` String!` }, - type: { type: ` String!` }, - spaceId: { type: ` String!` }, - environmentId: { type: ` String!` }, - contentType: { - type: `ContentfulContentType`, - extensions: { - link: { by: `id`, from: `sys.contentType` }, - }, - }, - firstPublishedAt: { type: ` Date!` }, - publishedAt: { type: ` Date!` }, - publishedVersion: { type: ` Int!` }, - locale: { type: ` String!` }, - }, - interfaces: [`Node`], - extensions: { dontInfer: {} }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulMetadata`, - fields: { - tags: { - type: `[ContentfulTag]!`, - extensions: { - link: { by: `id`, from: `tags` }, - }, - }, - }, - extensions: { dontInfer: {} }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulTag`, - fields: { - name: { type: `String!` }, - contentful_id: { type: `String!` }, - id: { type: `ID!` }, - }, - interfaces: [`Node`], - extensions: { dontInfer: {} }, - }) - ) - - const { getGatsbyImageFieldConfig } = await import( - `gatsby-plugin-image/graphql-utils` - ) - - // Assets - const gatsbyImageData = getGatsbyImageFieldConfig( - async (...args) => resolveGatsbyImageData(...args, { cache }), - { - jpegProgressive: { - type: `Boolean`, - defaultValue: true, - }, - resizingBehavior: { - type: ImageResizingBehavior, - }, - cropFocus: { - type: ImageCropFocusType, - }, - cornerRadius: { - type: `Int`, - defaultValue: 0, - description: stripIndent` - Desired corner radius in pixels. Results in an image with rounded corners. - Pass \`-1\` for a full circle/ellipse.`, - }, - quality: { - type: `Int`, - defaultValue: 50, - }, - } - ) - gatsbyImageData.type = `JSON` - createTypes( - addRemoteFilePolyfillInterface( - schema.buildObjectType({ - name: `ContentfulAsset`, - fields: { - id: { type: `ID!` }, - sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, - gatsbyImageData, - ...(pluginConfig.get(`downloadLocal`) - ? { - localFile: { - type: `File`, - extensions: { - link: { - from: `fields.localFile`, - }, - }, - }, - } - : {}), - title: { type: `String` }, - description: { type: `String` }, - contentType: { type: `String!` }, - mimeType: { type: `String!` }, - filename: { type: `String!` }, - url: { type: `String!` }, - size: { type: `Int` }, - width: { type: `Int` }, - height: { type: `Int` }, - }, - interfaces: [`ContentfulEntity`, `Node`], - extensions: { dontInfer: {} }, - }), - { - schema, - actions, - store, - } - ) - ) - - // Rich Text - const makeRichTextLinksResolver = - (nodeType, entityType) => async (source, _args, context) => { - const links = getRichTextEntityLinks(source, nodeType)[entityType].map( - ({ id }) => id - ) - - const node = context.nodeModel.findRootNodeAncestor(source) - if (!node) return null - - const res = await context.nodeModel.findAll({ - query: { - sys: { - id: { - in: links, - }, - spaceId: { eq: node.sys.spaceId }, - }, - }, - type: `Contentful${entityType}`, - }) - - return res.entries - } - - // Contentful specific types - createTypes( - schema.buildObjectType({ - name: `ContentfulRichTextAssets`, - fields: { - block: { - type: `[ContentfulAsset]!`, - resolve: makeRichTextLinksResolver(`embedded-asset-block`, `Asset`), - }, - hyperlink: { - type: `[ContentfulAsset]!`, - resolve: makeRichTextLinksResolver(`asset-hyperlink`, `Asset`), - }, - }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulRichTextEntries`, - fields: { - inline: { - type: `[ContentfulEntry]!`, - resolve: makeRichTextLinksResolver(`embedded-entry-inline`, `Entry`), - }, - block: { - type: `[ContentfulEntry]!`, - resolve: makeRichTextLinksResolver(`embedded-entry-block`, `Entry`), - }, - hyperlink: { - type: `[ContentfulEntry]!`, - resolve: makeRichTextLinksResolver(`entry-hyperlink`, `Entry`), - }, - }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulRichTextLinks`, - fields: { - assets: { - type: `ContentfulRichTextAssets`, - resolve(source) { - return source - }, - }, - entries: { - type: `ContentfulRichTextEntries`, - resolve(source) { - return source - }, - }, - }, - }) - ) - - createTypes( - schema.buildObjectType({ - name: `ContentfulRichText`, - fields: { - json: { - type: `JSON`, - resolve(source) { - return source - }, - }, - links: { - type: `ContentfulRichTextLinks`, - resolve(source) { - return source - }, - }, - }, - extensions: { dontInfer: {} }, - }) - ) - - // Location - createTypes( - schema.buildObjectType({ - name: `ContentfulLocation`, - fields: { - lat: { type: `Float!` }, - lon: { type: `Float!` }, - }, - extensions: { - dontInfer: {}, - }, - }) - ) - - // Text - // @todo Is there a way to have this as string and let transformer-remark replace it with an object? - createTypes( - schema.buildObjectType({ - name: `ContentfulText`, - fields: { - raw: `String!`, - }, - // @todo do we need a node interface here? - interfaces: [`Node`], - extensions: { - dontInfer: {}, - }, - }) - ) - - // Content types - for (const contentTypeItem of contentTypeItems) { - try { - const fields = {} - contentTypeItem.fields.forEach(field => { - if (field.disabled || field.omitted) { - return - } - if ([`id`, `sys`, `contentfulMetadata`].includes(field.id)) { - // Throw error on reserved field names as the Contenful GraphQL API does: - // https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/fields - throw new Error( - `Unfortunately the field name ${field.id} is reserved. ${contentTypeItem.name}@${contentTypeItem.sys.id}` - ) - } - fields[field.id] = translateFieldType(field, schema, createTypes) - }) - - const type = pluginConfig.get(`useNameForId`) - ? contentTypeItem.name - : contentTypeItem.sys.id - - createTypes( - schema.buildObjectType({ - name: makeTypeName(type), - fields: { - id: { type: `ID!` }, - sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, - ...fields, - }, - interfaces: [`ContentfulEntity`, `ContentfulEntry`, `Node`], - extensions: { dontInfer: {} }, - }) - ) - } catch (err) { - err.message = `Unable to create schema for Contentful Content Type ${ - contentTypeItem.name || contentTypeItem.sys.id - }:\n${err.message}` - console.log(err.stack) - throw err - } - } -} diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts new file mode 100644 index 0000000000000..1461206af6ecc --- /dev/null +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -0,0 +1,660 @@ +import type { + GatsbyNode, + NodePluginSchema, + CreateSchemaCustomizationArgs, +} from "gatsby" +import { + GraphQLFieldConfig, + GraphQLFloat, + GraphQLInt, + GraphQLString, + GraphQLType, +} from "gatsby/graphql" +import { getRichTextEntityLinks } from "@contentful/rich-text-links" +import { stripIndent } from "common-tags" +import { addRemoteFilePolyfillInterface } from "gatsby-plugin-utils/polyfill-remote-file" + +import { fetchContentTypes } from "./fetch" +import { createPluginConfig } from "./plugin-options" +import { CODES } from "./report" +import { resolveGatsbyImageData } from "./gatsby-plugin-image" +import { makeTypeName } from "./normalize" +import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" +import type { IPluginOptions } from "./types/plugin" +import type { + ContentType, + ContentTypeField, + FieldItem, +} from "./types/contentful-js-sdk/content-type" + +import type { + IContentfulAsset, + IContentfulEntry, + IContentfulImageAPITransformerOptions, +} from "./types/contentful" + +type CreateTypes = CreateSchemaCustomizationArgs["actions"]["createTypes"] + +interface IContentfulGraphQLField + extends Omit>, "type"> { + type: string | GraphQLType + id?: string +} + +// Contentful content type schemas +const ContentfulDataTypes: Map< + string, + (field: IContentfulGraphQLField) => IContentfulGraphQLField +> = new Map([ + [ + `Symbol`, + (): IContentfulGraphQLField => { + return { type: GraphQLString } + }, + ], + [ + `Text`, + (field): IContentfulGraphQLField => { + return { + type: `ContentfulText`, + extensions: { + link: { by: `id`, from: field.id }, + }, + } + }, + ], + [ + `Integer`, + (): IContentfulGraphQLField => { + return { type: GraphQLInt } + }, + ], + [ + `Number`, + (): IContentfulGraphQLField => { + return { type: GraphQLFloat } + }, + ], + [ + `Date`, + (): IContentfulGraphQLField => { + return { + type: `Date`, + extensions: { + dateformat: {}, + }, + } + }, + ], + [ + `Object`, + (): IContentfulGraphQLField => { + return { type: `JSON` } + }, + ], + [ + `Boolean`, + (): IContentfulGraphQLField => { + return { type: `Boolean` } + }, + ], + [ + `Location`, + (): IContentfulGraphQLField => { + return { type: `ContentfulLocation` } + }, + ], + [ + `RichText`, + (): IContentfulGraphQLField => { + return { type: `ContentfulRichText` } + }, + ], +]) + +const unionsNameSet = new Set() + +const getLinkFieldType = ( + linkType: string | undefined, + field: ContentTypeField, + schema: NodePluginSchema, + createTypes: CreateTypes +): IContentfulGraphQLField => { + // Check for validations + const validations = + field.type === `Array` ? field.items?.validations : field?.validations + + if (validations) { + // We only handle content type validations + const linkContentTypeValidation = validations.find( + ({ linkContentType }) => !!linkContentType + ) + if (linkContentTypeValidation) { + const { linkContentType } = linkContentTypeValidation + const contentTypes = Array.isArray(linkContentType) + ? linkContentType + : [linkContentType] + + // Full type names for union members, shorter variant for the union type name + const translatedTypeNames = contentTypes.map(typeName => + makeTypeName(typeName) + ) + const shortTypeNames = contentTypes.map(typeName => + makeTypeName(typeName, ``) + ) + + // Single content type + if (translatedTypeNames.length === 1) { + const typeName = translatedTypeNames.shift() + if (!typeName || !field.id) { + throw new Error( + `Translated type name can not be empty. A field id is required as well. ${JSON.stringify( + { typeName, field, translatedTypeNames, shortTypeNames }, + null, + 2 + )}` + ) + } + return { + type: typeName, + extensions: { + link: { by: `id`, from: field.id }, + }, + } + } + + // Multiple content types + const unionName = [`UnionContentful`, ...shortTypeNames].join(``) + + if (!unionsNameSet.has(unionName)) { + unionsNameSet.add(unionName) + createTypes( + schema.buildUnionType({ + name: unionName, + types: translatedTypeNames, + }) + ) + } + + return { + type: unionName, + extensions: { + link: { by: `id`, from: field.id }, + }, + } + } + } + + return { + type: `Contentful${linkType}`, + extensions: { + link: { by: `id`, from: field.id }, + }, + } +} + +// Translate Contentful field types to GraphQL field types +const translateFieldType = ( + field: ContentTypeField | FieldItem, + schema: NodePluginSchema, + createTypes: CreateTypes +): GraphQLFieldConfig => { + let fieldType + if (field.type === `Array`) { + if (!field.items) { + throw new Error( + `Invalid content type field definition:\n${JSON.stringify( + field, + null, + 2 + )}` + ) + } + // Arrays of Contentful Links or primitive types + const fieldData = + field.items?.type === `Link` + ? getLinkFieldType(field.items.linkType, field, schema, createTypes) + : translateFieldType(field.items, schema, createTypes) + + fieldType = { ...fieldData, type: `[${fieldData.type}]` } + } else if (field.type === `Link`) { + // Contentful Link (reference) field types + fieldType = getLinkFieldType( + field.linkType, + field as ContentTypeField, + schema, + createTypes + ) + } else { + // Primitive field types + const primitiveType = ContentfulDataTypes.get(field.type) + if (!primitiveType) { + throw new Error(`Contentful field type ${field.type} is not supported.`) + } + fieldType = primitiveType(field) + } + + // TODO: what do we do when preview is enabled? Emptry required fields are valid for Contentfuls CP-API + // if (field.required) { + // fieldType.type = `${fieldType.type}!` + // } + + return fieldType +} + +async function getContentTypesFromContentful({ + cache, + reporter, + pluginConfig, +}): Promise> { + // Get content type items from Contentful + const allContentTypeItems = await fetchContentTypes({ + pluginConfig, + reporter, + }) + + if (!allContentTypeItems) { + throw new Error( + `Could not locate any content types in Contentful space ${pluginConfig.get( + `spaceId` + )}.` + ) + } + const contentTypeFilter = pluginConfig.get(`contentTypeFilter`) + + const contentTypeItems = allContentTypeItems.filter(contentTypeFilter) + + if (contentTypeItems.length === 0) { + reporter.panic({ + id: CODES.ContentTypesMissing, + context: { + sourceMessage: `Please check if your contentTypeFilter is configured properly. Content types were filtered down to none.`, + }, + }) + } + + // Store processed content types in cache for sourceNodes + const sourceId = `${pluginConfig.get(`spaceId`)}-${pluginConfig.get( + `environment` + )}` + const CACHE_CONTENT_TYPES = `contentful-content-types-${sourceId}` + await cache.set(CACHE_CONTENT_TYPES, contentTypeItems) + + return contentTypeItems +} + +export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] = + async function ({ schema, actions, store, reporter, cache }, pluginOptions) { + const { createTypes } = actions + + const pluginConfig = createPluginConfig(pluginOptions as IPluginOptions) + + let contentTypeItems + if (process.env.GATSBY_WORKER_ID) { + const sourceId = `${pluginConfig.get(`spaceId`)}-${pluginConfig.get( + `environment` + )}` + contentTypeItems = await cache.get(`contentful-content-types-${sourceId}`) + } else { + contentTypeItems = await getContentTypesFromContentful({ + cache, + reporter, + pluginConfig, + }) + } + + // Generic Types + createTypes( + schema.buildInterfaceType({ + name: `ContentfulEntity`, + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, + }, + interfaces: [`Node`], + }) + ) + + createTypes( + schema.buildInterfaceType({ + name: `ContentfulEntry`, + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, + }, + interfaces: [`ContentfulEntity`, `Node`], + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulContentType`, + fields: { + id: { type: `ID!` }, + name: { type: `String!` }, + displayField: { type: `String!` }, + description: { type: `String!` }, + }, + interfaces: [`Node`], + extensions: { dontInfer: {} }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulSys`, + fields: { + id: { type: ` String!` }, + type: { type: ` String!` }, + spaceId: { type: ` String!` }, + environmentId: { type: ` String!` }, + contentType: { + type: `ContentfulContentType`, + extensions: { + link: { by: `id`, from: `sys.contentType` }, + }, + }, + firstPublishedAt: { type: ` Date!` }, + publishedAt: { type: ` Date!` }, + publishedVersion: { type: ` Int!` }, + locale: { type: ` String!` }, + }, + interfaces: [`Node`], + extensions: { dontInfer: {} }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulTag`, + fields: { + name: { type: `String!` }, + contentful_id: { type: `String!` }, + id: { type: `ID!` }, + }, + interfaces: [`Node`], + extensions: { dontInfer: {} }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulMetadata`, + fields: { + tags: { + type: `[ContentfulTag]!`, + extensions: { + link: { by: `id`, from: `tags` }, + }, + }, + }, + extensions: { dontInfer: {} }, + }) + ) + + const { getGatsbyImageFieldConfig } = await import( + `gatsby-plugin-image/graphql-utils.js` + ) + + // Assets + const gatsbyImageData = getGatsbyImageFieldConfig( + async ( + image: IContentfulAsset, + options: IContentfulImageAPITransformerOptions + ) => resolveGatsbyImageData(image, options, { cache }), + { + jpegProgressive: { + type: `Boolean`, + defaultValue: true, + }, + resizingBehavior: { + type: ImageResizingBehavior, + }, + cropFocus: { + type: ImageCropFocusType, + }, + cornerRadius: { + type: `Int`, + defaultValue: 0, + description: stripIndent` + Desired corner radius in pixels. Results in an image with rounded corners. + Pass \`-1\` for a full circle/ellipse.`, + }, + quality: { + type: `Int`, + defaultValue: 50, + }, + // TODO: fix the type for extraArgs in gatsby-plugin-iomage so we dont have to cast to any here + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any + ) + gatsbyImageData.type = `JSON` + createTypes( + addRemoteFilePolyfillInterface( + schema.buildObjectType({ + name: `ContentfulAsset`, + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, + gatsbyImageData, + ...(pluginConfig.get(`downloadLocal`) + ? { + localFile: { + type: `File`, + extensions: { + link: { + from: `fields.localFile`, + }, + }, + }, + } + : {}), + title: { type: `String` }, + description: { type: `String` }, + contentType: { type: `String!` }, + mimeType: { type: `String!` }, + filename: { type: `String!` }, + url: { type: `String!` }, + size: { type: `Int` }, + width: { type: `Int` }, + height: { type: `Int` }, + }, + interfaces: [`ContentfulEntity`, `Node`], + extensions: { dontInfer: {} }, + }), + { + schema, + actions, + store, + } + ) + ) + + // Rich Text + const makeRichTextLinksResolver = + (nodeType, entityType) => + async ( + source, + _args, + context + ): Promise | null> => { + const links = getRichTextEntityLinks(source, nodeType)[entityType].map( + ({ id }) => id + ) + + const node = context.nodeModel.findRootNodeAncestor(source) + if (!node) return null + + const res = await context.nodeModel.findAll({ + query: { + sys: { + id: { + in: links, + }, + spaceId: { eq: node.sys.spaceId }, + }, + }, + type: `Contentful${entityType}`, + }) + + return res.entries + } + + // Contentful specific types + createTypes( + schema.buildObjectType({ + name: `ContentfulRichTextAssets`, + fields: { + block: { + type: `[ContentfulAsset]!`, + resolve: makeRichTextLinksResolver(`embedded-asset-block`, `Asset`), + }, + hyperlink: { + type: `[ContentfulAsset]!`, + resolve: makeRichTextLinksResolver(`asset-hyperlink`, `Asset`), + }, + }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulRichTextEntries`, + fields: { + inline: { + type: `[ContentfulEntry]!`, + resolve: makeRichTextLinksResolver( + `embedded-entry-inline`, + `Entry` + ), + }, + block: { + type: `[ContentfulEntry]!`, + resolve: makeRichTextLinksResolver(`embedded-entry-block`, `Entry`), + }, + hyperlink: { + type: `[ContentfulEntry]!`, + resolve: makeRichTextLinksResolver(`entry-hyperlink`, `Entry`), + }, + }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulRichTextLinks`, + fields: { + assets: { + type: `ContentfulRichTextAssets`, + resolve(source) { + return source + }, + }, + entries: { + type: `ContentfulRichTextEntries`, + resolve(source) { + return source + }, + }, + }, + }) + ) + + createTypes( + schema.buildObjectType({ + name: `ContentfulRichText`, + fields: { + json: { + type: `JSON`, + resolve(source) { + return source + }, + }, + links: { + type: `ContentfulRichTextLinks`, + resolve(source) { + return source + }, + }, + }, + extensions: { dontInfer: {} }, + }) + ) + + // Location + createTypes( + schema.buildObjectType({ + name: `ContentfulLocation`, + fields: { + lat: { type: `Float!` }, + lon: { type: `Float!` }, + }, + extensions: { + dontInfer: {}, + }, + }) + ) + + // Text + // TODO: Is there a way to have this as string and let transformer-remark replace it with an object? + createTypes( + schema.buildObjectType({ + name: `ContentfulText`, + fields: { + raw: `String!`, + }, + // TODO: do we need a node interface here? + interfaces: [`Node`], + extensions: { + dontInfer: {}, + }, + }) + ) + + // Content types + for (const contentTypeItem of contentTypeItems) { + try { + const fields = {} + contentTypeItem.fields.forEach(field => { + if (field.disabled || field.omitted) { + return + } + if ([`id`, `sys`, `contentfulMetadata`].includes(field.id)) { + // Throw error on reserved field names as the Contenful GraphQL API does: + // https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/fields + throw new Error( + `Unfortunately the field name ${field.id} is reserved. ${contentTypeItem.name}@${contentTypeItem.sys.id}` + ) + } + fields[field.id] = translateFieldType(field, schema, createTypes) + }) + + const type = pluginConfig.get(`useNameForId`) + ? contentTypeItem.name + : contentTypeItem.sys.id + + createTypes( + schema.buildObjectType({ + name: makeTypeName(type), + fields: { + id: { type: `ID!` }, + sys: { type: `ContentfulSys!` }, + metadata: { type: `ContentfulMetadata!` }, + ...fields, + }, + interfaces: [`ContentfulEntity`, `ContentfulEntry`, `Node`], + extensions: { dontInfer: {} }, + }) + ) + } catch (err) { + err.message = `Unable to create schema for Contentful Content Type ${ + contentTypeItem.name || contentTypeItem.sys.id + }:\n${err.message}` + console.log(err.stack) + throw err + } + } + } diff --git a/packages/gatsby-source-contentful/src/download-contentful-assets.js b/packages/gatsby-source-contentful/src/download-contentful-assets.ts similarity index 68% rename from packages/gatsby-source-contentful/src/download-contentful-assets.js rename to packages/gatsby-source-contentful/src/download-contentful-assets.ts index 288b0d57995c6..955bf91967325 100644 --- a/packages/gatsby-source-contentful/src/download-contentful-assets.js +++ b/packages/gatsby-source-contentful/src/download-contentful-assets.ts @@ -1,16 +1,16 @@ -// @ts-check +import type { Actions, SourceNodesArgs } from "gatsby" import { createRemoteFileNode } from "gatsby-source-filesystem" +import type { IContentfulAsset } from "./types/contentful" /** * @name distributeWorkload * @param workers A list of async functions to complete * @param {number} count The number of task runners to use (see assetDownloadWorkers in config) */ - -async function distributeWorkload(workers, count = 50) { +async function distributeWorkload(workers, count = 50): Promise { const methods = workers.slice() - async function task() { + async function task(): Promise { while (methods.length > 0) { await methods.pop()() } @@ -19,24 +19,24 @@ async function distributeWorkload(workers, count = 50) { await Promise.all(new Array(count).fill(undefined).map(() => task())) } +interface IRemoteData { + fileNodeID: string +} + /** * @name downloadContentfulAssets * @description Downloads Contentful assets to the local filesystem. * The asset files will be downloaded and cached. Use `localFile` to link to them * @param gatsbyFunctions - Gatsby's internal helper functions */ - -export async function downloadContentfulAssets(gatsbyFunctions) { - const { - actions: { createNode, touchNode, createNodeField }, - createNodeId, - store, - cache, - reporter, - assetDownloadWorkers, - getNode, - assetNodes, - } = gatsbyFunctions +export async function downloadContentfulAssets( + gatsbyFunctions: SourceNodesArgs, + actions: Actions, + assetNodes: Array, + assetDownloadWorkers: number +): Promise { + const { createNodeId, cache, reporter, getNode } = gatsbyFunctions + const { createNode, touchNode, createNodeField } = actions // Any ContentfulAsset nodes will be downloaded, cached and copied to public/static // regardless of if you use `localFile` to link an asset or not. @@ -47,14 +47,14 @@ export async function downloadContentfulAssets(gatsbyFunctions) { ) bar.start() await distributeWorkload( - assetNodes.map(assetNode => async () => { + assetNodes.map(assetNode => async (): Promise => { let fileNodeID const { sys: { id, locale }, url, } = assetNode const remoteDataCacheKey = `contentful-asset-${id}-${locale}` - const cacheRemoteData = await cache.get(remoteDataCacheKey) + const cacheRemoteData: IRemoteData = await cache.get(remoteDataCacheKey) if (!url) { reporter.warn(`The asset with id: ${id} has no url.`) @@ -65,8 +65,11 @@ export async function downloadContentfulAssets(gatsbyFunctions) { // Note: Contentful Assets do not provide useful metadata // to compare a modified asset to a cached version? if (cacheRemoteData) { - fileNodeID = cacheRemoteData.fileNodeID // eslint-disable-line prefer-destructuring - touchNode(getNode(cacheRemoteData.fileNodeID)) + fileNodeID = cacheRemoteData.fileNodeID + const existingNode = getNode(cacheRemoteData.fileNodeID) + if (existingNode) { + touchNode(existingNode) + } } // If we don't have cached data, download the file @@ -93,8 +96,7 @@ export async function downloadContentfulAssets(gatsbyFunctions) { value: fileNodeID, }) } - - return assetNode + return Promise.resolve() }), assetDownloadWorkers ) diff --git a/packages/gatsby-source-contentful/src/extend-node-type.js b/packages/gatsby-source-contentful/src/extend-node-type.js deleted file mode 100644 index 2acfc6a835462..0000000000000 --- a/packages/gatsby-source-contentful/src/extend-node-type.js +++ /dev/null @@ -1,58 +0,0 @@ -// @ts-check -import { stripIndent } from "common-tags" -import { GraphQLBoolean, GraphQLInt } from "gatsby/graphql" -import { hasFeature } from "gatsby-plugin-utils" - -import { resolveGatsbyImageData } from "./gatsby-plugin-image" -import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" - -export async function setFieldsOnGraphQLNodeType({ type, cache }) { - if (type.name !== `ContentfulAsset`) { - return {} - } - - // gatsby-plugin-image - const getGatsbyImageData = async () => { - const { getGatsbyImageFieldConfig } = await import( - `gatsby-plugin-image/graphql-utils` - ) - - const fieldConfig = getGatsbyImageFieldConfig( - async (...args) => resolveGatsbyImageData(...args, { cache }), - { - jpegProgressive: { - type: GraphQLBoolean, - defaultValue: true, - }, - resizingBehavior: { - type: ImageResizingBehavior, - }, - cropFocus: { - type: ImageCropFocusType, - }, - cornerRadius: { - type: GraphQLInt, - defaultValue: 0, - description: stripIndent` - Desired corner radius in pixels. Results in an image with rounded corners. - Pass \`-1\` for a full circle/ellipse.`, - }, - quality: { - type: GraphQLInt, - }, - } - ) - - fieldConfig.type = hasFeature(`graphql-typegen`) - ? `GatsbyImageData` - : `JSON` - - return fieldConfig - } - - const gatsbyImageData = await getGatsbyImageData() - - return { - gatsbyImageData, - } -} diff --git a/packages/gatsby-source-contentful/src/fetch.js b/packages/gatsby-source-contentful/src/fetch.ts similarity index 81% rename from packages/gatsby-source-contentful/src/fetch.js rename to packages/gatsby-source-contentful/src/fetch.ts index 0e141c2780856..ac9825dd61824 100644 --- a/packages/gatsby-source-contentful/src/fetch.js +++ b/packages/gatsby-source-contentful/src/fetch.ts @@ -1,20 +1,35 @@ -// @ts-check import chalk from "chalk" -import { createClient } from "contentful" +import { + ContentfulClientApi, + ContentTypeCollection, + createClient, + CreateClientParams, +} from "contentful" +import type { Reporter } from "gatsby" import _ from "lodash" + import { formatPluginOptionsForCLI } from "./plugin-options" import { CODES } from "./report" +import type { + ContentType, + EntryCollection, + Locale, + Space, + SyncCollection, + Tag, +} from "./types/contentful-js-sdk" +import type { IProcessedPluginOptions } from "./types/plugin" /** * Generate a user friendly error message. * * Contentful's API has its own error message structure, which might change depending of internal server or authentification errors. */ -const createContentfulErrorMessage = e => { +const createContentfulErrorMessage = (e: any): string => { // Handle axios error messages if (e.isAxiosError) { const axiosErrorMessage = [e.code, e.status] - const axiosErrorDetails = [] + const axiosErrorDetails: Array = [] if (e.response) { axiosErrorMessage.push(e.response.status) @@ -50,13 +65,13 @@ const createContentfulErrorMessage = e => { // If it is not an axios error, we assume that we got a Contentful SDK error and try to parse it const errorMessage = [e.name] - const errorDetails = [] + const errorDetails: Array = [] try { /** * Parse stringified error data from message * https://github.com/contentful/contentful-sdk-core/blob/4cfcd452ba0752237a26ce6b79d72a50af84d84e/src/error-handler.ts#L71-L75 * - * @todo properly type this with TS + * TODO: properly type this with TS * type { * status?: number * statusText?: string @@ -99,10 +114,14 @@ function createContentfulClientOptions({ pluginConfig, reporter, syncProgress = { total: 0, tick: a => a }, -}) { +}: { + pluginConfig: IProcessedPluginOptions + reporter: Reporter + syncProgress?: { total: number; tick: (a: number) => unknown } +}): CreateClientParams { let syncItemCount = 0 - const contentfulClientOptions = { + const contentfulClientOptions: CreateClientParams = { space: pluginConfig.get(`spaceId`), accessToken: pluginConfig.get(`accessToken`), host: pluginConfig.get(`host`), @@ -110,7 +129,7 @@ function createContentfulClientOptions({ proxy: pluginConfig.get(`proxy`), integration: `gatsby-source-contentful`, responseLogger: response => { - function createMetadataLog(response) { + function createMetadataLog(response): string | null { if (!response.headers) { return null } @@ -162,7 +181,12 @@ function handleContentfulError({ reporter, contentfulClientOptions, pluginConfig, -}) { +}: { + e: any + reporter: Reporter + contentfulClientOptions: CreateClientParams + pluginConfig: IProcessedPluginOptions +}): void { let details let errors if (e.code === `ENOTFOUND`) { @@ -214,6 +238,7 @@ function handleContentfulError({ } reporter.panic({ + id: CODES.GenericContentfulError, context: { sourceMessage: `Accessing your Contentful space failed: ${createContentfulErrorMessage( e @@ -227,13 +252,29 @@ ${formatPluginOptionsForCLI(pluginConfig.getOriginalPluginOptions(), errors)}`, }) } +interface IFetchResult { + currentSyncData: SyncCollection + tagItems: Array + defaultLocale: string + locales: Array + space: Space +} + /** * Fetches: * * Locales with default locale * * Entries and assets * * Tags */ -export async function fetchContent({ syncToken, pluginConfig, reporter }) { +export async function fetchContent({ + syncToken, + pluginConfig, + reporter, +}: { + syncToken: string + pluginConfig: IProcessedPluginOptions + reporter: Reporter +}): Promise { // Fetch locales and check connectivity const contentfulClientOptions = createContentfulClientOptions({ pluginConfig, @@ -264,7 +305,7 @@ export async function fetchContent({ syncToken, pluginConfig, reporter }) { } // Fetch entries and assets via Contentful CDA sync API - const pageLimit = pluginConfig.get(`pageLimit`) + const pageLimit = pluginConfig.get(`pageLimit`) || 100 reporter.verbose(`Contentful: Sync ${pageLimit} items per page.`) const syncProgress = reporter.createProgress( `Contentful: ${syncToken ? `Sync changed items` : `Sync all items`}`, @@ -279,9 +320,9 @@ export async function fetchContent({ syncToken, pluginConfig, reporter }) { }) const syncClient = createClient(contentfulSyncClientOptions) - let currentSyncData + let currentSyncData: SyncCollection | undefined let currentPageLimit = pageLimit - let lastCurrentPageLimit + let lastCurrentPageLimit = 0 let syncSuccess = false try { while (!syncSuccess) { @@ -293,7 +334,7 @@ export async function fetchContent({ syncToken, pluginConfig, reporter }) { const query = syncToken ? { nextSyncToken: syncToken, ...basicSyncConfig } : { initial: true, ...basicSyncConfig } - currentSyncData = await syncClient.sync(query) + currentSyncData = (await syncClient.sync(query)) as SyncCollection syncSuccess = true } catch (e) { // Back off page limit if responses content length exceeds Contentfuls limits. @@ -333,11 +374,12 @@ export async function fetchContent({ syncToken, pluginConfig, reporter }) { } finally { // Fix output when there was no new data in Contentful if ( + currentSyncData && currentSyncData?.entries.length + currentSyncData?.assets.length + currentSyncData?.deletedEntries.length + currentSyncData?.deletedAssets.length === - 0 + 0 ) { syncProgress.tick() syncProgress.total = 1 @@ -349,7 +391,10 @@ export async function fetchContent({ syncToken, pluginConfig, reporter }) { // We need to fetch tags with the non-sync API as the sync API doesn't support this. let tagItems try { - const tagsResult = await pagedGet(client, `getTags`, pageLimit) + const tagsResult = await pagedGet(client, `getTags`, pageLimit) + if (!tagsResult) { + throw new Error() + } tagItems = tagsResult.items reporter.verbose(`Tags fetched ${tagItems.length}`) } catch (e) { @@ -363,7 +408,11 @@ export async function fetchContent({ syncToken, pluginConfig, reporter }) { }) } - const result = { + if (!currentSyncData) { + throw new Error(`Unable to sync data from Contentful API`) + } + + const result: IFetchResult = { currentSyncData, tagItems, defaultLocale, @@ -378,24 +427,41 @@ export async function fetchContent({ syncToken, pluginConfig, reporter }) { * Fetches: * * Content types */ -export async function fetchContentTypes({ pluginConfig, reporter }) { +export async function fetchContentTypes({ + pluginConfig, + reporter, +}: { + pluginConfig: IProcessedPluginOptions + reporter: Reporter +}): Promise | null> { const contentfulClientOptions = createContentfulClientOptions({ pluginConfig, reporter, }) const client = createClient(contentfulClientOptions) - const pageLimit = pluginConfig.get(`pageLimit`) + const pageLimit = pluginConfig.get(`pageLimit`) || 100 const sourceId = `${pluginConfig.get(`spaceId`)}-${pluginConfig.get( `environment` )}` - let contentTypes = null + + let contentTypes: Array = [] try { reporter.verbose(`Fetching content types (${sourceId})`) // Fetch content types from CDA API try { - contentTypes = await pagedGet(client, `getContentTypes`, pageLimit) + const contentTypeCollection = await pagedGet( + client, + `getContentTypes`, + pageLimit + ) + if (contentTypeCollection) { + reporter.verbose( + `Content types fetched ${contentTypeCollection.items.length} (${sourceId})` + ) + contentTypes = contentTypeCollection.items as Array + } } catch (e) { reporter.panic({ id: CODES.FetchContentTypes, @@ -406,11 +472,6 @@ export async function fetchContentTypes({ pluginConfig, reporter }) { }, }) } - reporter.verbose( - `Content types fetched ${contentTypes.items.length} (${sourceId})` - ) - - contentTypes = contentTypes.items } catch (e) { handleContentfulError(e) } @@ -423,14 +484,18 @@ export async function fetchContentTypes({ pluginConfig, reporter }) { * The first call will have no aggregated response. Subsequent calls will * concatenate the new responses to the original one. */ -function pagedGet( - client, - method, - pageLimit, +function pagedGet( + client: ContentfulClientApi, + method: keyof ContentfulClientApi, + pageLimit: number, query = {}, skip = 0, - aggregatedResponse = null -) { + aggregatedResponse?: EntryCollection +): Promise | ContentTypeCollection | undefined> { + if (!client[method]) { + throw new Error(`Contentful Client does not support the method ${method}`) + } + return client[method]({ ...query, skip: skip, @@ -443,7 +508,7 @@ function pagedGet( aggregatedResponse.items = aggregatedResponse.items.concat(response.items) } if (skip + pageLimit <= response.total) { - return pagedGet( + return pagedGet( client, method, pageLimit, diff --git a/packages/gatsby-source-contentful/src/gatsby-node.js b/packages/gatsby-source-contentful/src/gatsby-node.ts similarity index 92% rename from packages/gatsby-source-contentful/src/gatsby-node.js rename to packages/gatsby-source-contentful/src/gatsby-node.ts index cbc2ebef5fc05..49b9e2b14ffbf 100644 --- a/packages/gatsby-source-contentful/src/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/gatsby-node.ts @@ -1,18 +1,19 @@ -// @ts-check -import _ from "lodash" +import type { GatsbyNode } from "gatsby" import origFetch from "node-fetch" import fetchRetry from "@vercel/fetch-retry" import { polyfillImageServiceDevRoutes } from "gatsby-plugin-utils/polyfill-remote-file" -import { CODES } from "./report" +import { CODES } from "./report" import { maskText } from "./plugin-options" - +import type { IPluginOptions } from "./types/plugin" export { createSchemaCustomization } from "./create-schema-customization" export { sourceNodes } from "./source-nodes" const fetch = fetchRetry(origFetch) -const validateContentfulAccess = async pluginOptions => { +const validateContentfulAccess = async ( + pluginOptions: IPluginOptions +): Promise => { if (process.env.NODE_ENV === `test`) return undefined await fetch( @@ -42,11 +43,15 @@ const validateContentfulAccess = async pluginOptions => { return undefined } -export const onPreInit = async ({ store, reporter }) => { +export const onPreInit: GatsbyNode["onPreInit"] = async ({ + store, + reporter, +}) => { // if gatsby-plugin-image is not installed try { - await import(`gatsby-plugin-image/graphql-utils`) + await import(`gatsby-plugin-image/graphql-utils.js`) } catch (err) { + console.log(err) reporter.panic({ id: CODES.GatsbyPluginMissing, context: { @@ -70,7 +75,9 @@ export const onPreInit = async ({ store, reporter }) => { } } -export const pluginOptionsSchema = ({ Joi }) => +export const pluginOptionsSchema: GatsbyNode["pluginOptionsSchema"] = ({ + Joi, +}) => Joi.object() .keys({ accessToken: Joi.string() @@ -108,7 +115,7 @@ For example, to filter locales on only germany \`localeFilter: locale => locale. List of locales and their codes can be found in Contentful app -> Settings -> Locales` ) - .default(() => () => true), + .default(() => (): boolean => true), contentTypeFilter: Joi.func() .description( `Possibility to limit how many contentType/nodes are created in GraphQL. This can limit the memory usage by reducing the amount of nodes created. Useful if you have a large space in Contentful and only want to get the data from certain content types. @@ -168,7 +175,9 @@ For example, to exclude content types starting with "page" \`contentTypeFilter: }) .external(validateContentfulAccess) -/** @type {import('gatsby').GatsbyNode["onCreateDevServer"]} */ -export const onCreateDevServer = ({ app, store }) => { +export const onCreateDevServer: GatsbyNode["onCreateDevServer"] = ({ + app, + store, +}) => { polyfillImageServiceDevRoutes(app, store) } diff --git a/packages/gatsby-source-contentful/src/gatsby-plugin-image.js b/packages/gatsby-source-contentful/src/gatsby-plugin-image.ts similarity index 75% rename from packages/gatsby-source-contentful/src/gatsby-plugin-image.js rename to packages/gatsby-source-contentful/src/gatsby-plugin-image.ts index 91eea40f8cf90..319cf58bde38d 100644 --- a/packages/gatsby-source-contentful/src/gatsby-plugin-image.js +++ b/packages/gatsby-source-contentful/src/gatsby-plugin-image.ts @@ -1,7 +1,15 @@ -// @ts-check import fs from "fs-extra" +import type { GatsbyCache } from "gatsby" import { fetchRemoteFile } from "gatsby-core-utils/fetch-remote-file" +import { + Fit, + IGatsbyImageData, + IGatsbyImageHelperArgs, + ImageFormat, +} from "gatsby-plugin-image" +import type { ImageFit } from "gatsby-plugin-utils/polyfill-remote-file/types" import path from "path" + import { createUrl, isImage, @@ -9,6 +17,11 @@ import { validImageFormats, CONTENTFUL_IMAGE_MAX_SIZE, } from "./image-helpers" +import type { + contentfulImageApiBackgroundColor, + IContentfulAsset, + IContentfulImageAPITransformerOptions, +} from "./types/contentful" // Promises that rejected should stay in this map. Otherwise remove promise and put their data in resolvedBase64Cache const inFlightBase64Cache = new Map() @@ -17,7 +30,15 @@ const inFlightBase64Cache = new Map() const resolvedBase64Cache = new Map() // Note: this may return a Promise, body (sync), or null -const getBase64Image = (imageProps, cache) => { +const getBase64Image = ( + imageProps: { + image: IContentfulAsset + baseUrl: string + options: IContentfulImageAPITransformerOptions + aspectRatio: number + }, + cache: GatsbyCache +): string | null | Promise => { if (!imageProps) { return null } @@ -27,15 +48,18 @@ const getBase64Image = (imageProps, cache) => { return null } + const placeholderWidth = imageProps.options.blurredOptions?.width || 20 // Keep aspect ratio, image format and other transform options const { aspectRatio } = imageProps const originalFormat = imageProps.image.mimeType.split(`/`)[1] - const toFormat = imageProps.options.toFormat + const toFormat = + imageProps.options.blurredOptions?.toFormat || imageProps.options.toFormat + const imageOptions = { ...imageProps.options, toFormat, - width: 20, - height: Math.floor(20 / aspectRatio), + width: placeholderWidth, + height: Math.floor(placeholderWidth / aspectRatio), } const requestUrl = createUrl(imageProps.baseUrl, imageOptions) @@ -52,7 +76,7 @@ const getBase64Image = (imageProps, cache) => { return inFlight } - const loadImage = async () => { + const loadImage = async (): Promise => { const { mimeType } = imageProps.image const extension = mimeTypeExtensions.get(mimeType) @@ -78,39 +102,15 @@ const getBase64Image = (imageProps, cache) => { }) } -const getTracedSVG = async ({ image, options, cache }) => { - const { traceSVG } = await import(`gatsby-plugin-sharp`) - const { url: imgUrl, filename, mimeType } = image - - if (mimeType.indexOf(`image/`) !== 0) { - return null - } - - const extension = mimeTypeExtensions.get(mimeType) - const url = createUrl(imgUrl, options) - const name = path.basename(filename, extension) - - const absolutePath = await fetchRemoteFile({ - url, - name, - directory: cache.directory, - ext: extension, - cacheKey: image.internal.contentDigest, - }) - - return traceSVG({ - file: { - internal: image.internal, - name: filename, - extension, - absolutePath, - }, - args: { toFormat: ``, ...options.tracedSVGOptions }, - fileArgs: options, - }) -} - -const getDominantColor = async ({ image, options, cache }) => { +const getDominantColor = async ({ + image, + options, + cache, +}: { + image: IContentfulAsset + options: IContentfulImageAPITransformerOptions + cache: GatsbyCache +}): Promise => { let pluginSharp try { @@ -127,7 +127,7 @@ const getDominantColor = async ({ image, options, cache }) => { const { mimeType, url: imgUrl, filename } = image if (mimeType.indexOf(`image/`) !== 0) { - return null + return `rgba(0,0,0,0.5)` } // 256px should be enough to properly detect the dominant color @@ -165,7 +165,16 @@ const getDominantColor = async ({ image, options, cache }) => { } } -function getBasicImageProps(image, args) { +function getBasicImageProps( + image, + args +): { + baseUrl: string + mimeType: string + aspectRatio: number + height: number + width: number +} { let { width, height } = image if (args.width && args.height) { width = args.width @@ -180,16 +189,15 @@ function getBasicImageProps(image, args) { height, } } - // Generate image source data for gatsby-plugin-image export function generateImageSource( - filename, - width, - height, - toFormat, - _fit, // We use resizingBehavior instead - imageTransformOptions -) { + filename: string, + width: number, + height: number, + toFormat: "gif" | ImageFormat, + _fit: ImageFit | null, + imageTransformOptions: IContentfulImageAPITransformerOptions +): { width: number; height: number; format: string; src: string } | undefined { const imageFormatDefaults = imageTransformOptions[`${toFormat}Options`] if ( @@ -222,7 +230,7 @@ export function generateImageSource( height = CONTENTFUL_IMAGE_MAX_SIZE } - if (!validImageFormats.has(toFormat)) { + if (toFormat && !validImageFormats.has(toFormat)) { console.warn( `[gatsby-source-contentful] Invalid image format "${toFormat}". Supported types are jpg, png, webp and avif"` ) @@ -234,7 +242,10 @@ export function generateImageSource( height, toFormat, resizingBehavior, - background: backgroundColor?.replace(`#`, `rgb:`), + background: backgroundColor?.replace( + `#`, + `rgb:` + ) as contentfulImageApiBackgroundColor, quality, jpegProgressive, cropFocus, @@ -245,12 +256,10 @@ export function generateImageSource( let didShowTraceSVGRemovalWarning = false export async function resolveGatsbyImageData( - image, - options, - context, - info, - { cache } -) { + image: IContentfulAsset, + options: IContentfulImageAPITransformerOptions, + { cache }: { cache: GatsbyCache } +): Promise { if (!isImage(image)) return null const { generateImageData } = await import(`gatsby-plugin-image`) @@ -288,17 +297,19 @@ export async function resolveGatsbyImageData( options.placeholder = `dominantColor` } - const { baseUrl, mimeType, width, height } = getBasicImageProps( + const { baseUrl, mimeType, width, height, aspectRatio } = getBasicImageProps( image, options ) - let [, format] = mimeType.split(`/`) - if (format === `jpeg`) { - format = `jpg` + let [, fileFormat] = mimeType.split(`/`) + if (fileFormat === `jpeg`) { + fileFormat = `jpg` } + const format: ImageFormat = fileFormat as ImageFormat + // Translate Contentful resize parameter to gatsby-plugin-image css object fit - const fitMap = new Map([ + const fitMap: Map = new Map([ [`pad`, `contain`], [`fill`, `cover`], [`scale`, `fill`], @@ -311,12 +322,13 @@ export async function resolveGatsbyImageData( pluginName: `gatsby-source-contentful`, sourceMetadata: { width, height, format }, filename: baseUrl, - generateImageSource, + generateImageSource: + generateImageSource as unknown as IGatsbyImageHelperArgs["generateImageSource"], fit: fitMap.get(options.resizingBehavior), - options, + options: options as unknown as Record, }) - let placeholderDataURI = null + let placeholderDataURI: string | null = null if (options.placeholder === `dominantColor`) { imageProps.backgroundColor = await getDominantColor({ @@ -332,15 +344,12 @@ export async function resolveGatsbyImageData( baseUrl, image, options, + aspectRatio, }, cache ) } - if (options.placeholder === `tracedSVG`) { - console.error(`this shouldn't happen`) - } - if (placeholderDataURI) { imageProps.placeholder = { fallback: placeholderDataURI } } diff --git a/packages/gatsby-source-contentful/src/hooks.js b/packages/gatsby-source-contentful/src/hooks.ts similarity index 58% rename from packages/gatsby-source-contentful/src/hooks.js rename to packages/gatsby-source-contentful/src/hooks.ts index cd31d5a851448..9866f324affa2 100644 --- a/packages/gatsby-source-contentful/src/hooks.js +++ b/packages/gatsby-source-contentful/src/hooks.ts @@ -1,13 +1,24 @@ -// @ts-check -import { getImageData } from "gatsby-plugin-image" +import { getImageData, IGatsbyImageData } from "gatsby-plugin-image" import { useMemo } from "react" import { createUrl } from "./image-helpers" +import type { + IContentfulAsset, + IContentfulImageAPITransformerOptions, +} from "./types/contentful" -export function useContentfulImage({ image, ...props }) { +interface IUseContentfulImageArgs { + image: IContentfulAsset + [key: string]: unknown +} + +export function useContentfulImage({ + image, + ...props +}: IUseContentfulImageArgs): IGatsbyImageData { return useMemo( () => - getImageData({ + getImageData({ baseUrl: image.url, sourceWidth: image.width, sourceHeight: image.height, diff --git a/packages/gatsby-source-contentful/src/image-helpers.js b/packages/gatsby-source-contentful/src/image-helpers.ts similarity index 88% rename from packages/gatsby-source-contentful/src/image-helpers.js rename to packages/gatsby-source-contentful/src/image-helpers.ts index d1070a573860d..79e2995cf4bab 100644 --- a/packages/gatsby-source-contentful/src/image-helpers.js +++ b/packages/gatsby-source-contentful/src/image-helpers.ts @@ -1,5 +1,8 @@ -// @ts-check import { URLSearchParams } from "url" +import type { + IContentfulAsset, + IContentfulImageAPIUrlBuilderOptions, +} from "./types/contentful" // Maximum value for size parameters in Contentful Image API // @see https://www.contentful.com/developers/docs/references/images-api/#/reference/resizing-&-cropping/specify-width-&-height @@ -19,12 +22,15 @@ export const mimeTypeExtensions = new Map([ ]) // Check if Contentful asset is actually an image -export function isImage(image) { +export function isImage(image: IContentfulAsset): boolean { return mimeTypeExtensions.has(image?.mimeType) } // Create a Contentful Image API url -export function createUrl(imgUrl, options = {}) { +export function createUrl( + imgUrl: string, + options: IContentfulImageAPIUrlBuilderOptions = {} +): string { // If radius is -1, we need to pass `max` to the API const cornerRadius = options.cornerRadius === -1 ? `max` : options.cornerRadius diff --git a/packages/gatsby-source-contentful/src/index.ts b/packages/gatsby-source-contentful/src/index.ts new file mode 100644 index 0000000000000..85b67a5e99023 --- /dev/null +++ b/packages/gatsby-source-contentful/src/index.ts @@ -0,0 +1,7 @@ +import * as importedSchemes from "./schemes" +export * from "./hooks" +export * from "./rich-text" +export * from "./types/contentful" +export type { IPluginOptions, IProcessedPluginOptions } from "./types/plugin" + +export const schemes = importedSchemes diff --git a/packages/gatsby-source-contentful/src/normalize.js b/packages/gatsby-source-contentful/src/normalize.ts similarity index 55% rename from packages/gatsby-source-contentful/src/normalize.js rename to packages/gatsby-source-contentful/src/normalize.ts index 9daa065ab1c53..ce8fef219bea8 100644 --- a/packages/gatsby-source-contentful/src/normalize.js +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -1,12 +1,33 @@ -// @ts-check +import type { Actions, Node, SourceNodesArgs } from "gatsby" import _ from "lodash" import { getGatsbyVersion } from "gatsby-core-utils" import { lt, prerelease } from "semver" import { restrictedNodeFields, conflictFieldPrefix } from "./config" - -export const makeTypeName = (type, typePrefix = `ContentfulContentType`) => - _.upperFirst(_.camelCase(`${typePrefix} ${type}`)) +import type { + IContentfulAsset, + IContentfulEntry, + IContentfulLink, + IContentfulSys, + ILocalizedField, +} from "./types/contentful" +import type { + SyncCollection, + Asset, + ContentType, + Space, + Locale, + LocaleCode, + AssetFile, + EntryWithAllLocalesAndWithoutLinkResolution, +} from "./types/contentful-js-sdk" +import type { IProcessedPluginOptions } from "./types/plugin" +import type { FieldsType } from "./types/contentful-js-sdk/query/util" + +export const makeTypeName = ( + type: string, + typePrefix = `ContentfulContentType` +): string => _.upperFirst(_.camelCase(`${typePrefix} ${type}`)) const GATSBY_VERSION_MANIFEST_V2 = `4.3.0` const gatsbyVersion = @@ -15,7 +36,19 @@ const gatsbyVersionIsPrerelease = prerelease(gatsbyVersion) const shouldUpgradeGatsbyVersion = lt(gatsbyVersion, GATSBY_VERSION_MANIFEST_V2) && !gatsbyVersionIsPrerelease -export const getLocalizedField = ({ field, locale, localesFallback }) => { +interface IContententfulLocaleFallback { + [key: string]: LocaleCode +} + +export const getLocalizedField = ({ + field, + locale, + localesFallback, +}: { + field: ILocalizedField + locale: Locale + localesFallback: IContententfulLocaleFallback +}): unknown => { if (!field) { return null } @@ -27,14 +60,16 @@ export const getLocalizedField = ({ field, locale, localesFallback }) => { ) { return getLocalizedField({ field, - locale: { code: localesFallback[locale.code] }, + locale: { ...locale, code: localesFallback[locale.code] }, localesFallback, }) } else { return null } } -export const buildFallbackChain = locales => { +export const buildFallbackChain = ( + locales: Array +): IContententfulLocaleFallback => { const localesFallback = {} _.each( locales, @@ -44,10 +79,22 @@ export const buildFallbackChain = locales => { } const makeGetLocalizedField = ({ locale, localesFallback }) => - field => + (field: ILocalizedField): unknown => getLocalizedField({ field, locale, localesFallback }) -export const makeId = ({ spaceId, id, currentLocale, defaultLocale, type }) => { +export const makeId = ({ + spaceId, + id, + currentLocale, + defaultLocale, + type, +}: { + spaceId: string + id: string + currentLocale: string + defaultLocale: string + type: string +}): string => { const normalizedType = type.startsWith(`Deleted`) ? type.substring(`Deleted`.length) : type @@ -58,18 +105,35 @@ export const makeId = ({ spaceId, id, currentLocale, defaultLocale, type }) => { const makeMakeId = ({ currentLocale, defaultLocale, createNodeId }) => - (spaceId, id, type) => + (spaceId, id, type): string => createNodeId(makeId({ spaceId, id, currentLocale, defaultLocale, type })) // Generates an unique id per space for reference resolving -export const createRefId = nodeOrLink => - `${nodeOrLink.sys.id}___${nodeOrLink.sys.linkType || nodeOrLink.sys.type}` - -export const buildEntryList = ({ contentTypeItems, currentSyncData }) => { +// TODO: space id is actually not factored in here! +export const createRefId = ( + node: + | EntryWithAllLocalesAndWithoutLinkResolution + | IContentfulEntry + | Asset +): string => `${node.sys.id}___${node.sys.type}` + +export const createLinkRefId = (link: IContentfulLink): string => + `${link.sys.id}___${link.sys.linkType}` + +export const buildEntryList = ({ + contentTypeItems, + currentSyncData, +}: { + contentTypeItems: Array + currentSyncData: SyncCollection +}): Array< + Array> +> => { // 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( - contentTypeItems.map(contentType => [contentType.sys.id, []]) - ) + const map: Map< + string, + Array> + > = new Map(contentTypeItems.map(contentType => [contentType.sys.id, []])) // Now fill the buckets. Ignore entries for which there exists no bucket. (This happens when filterContentType is used) currentSyncData.entries.map(entry => { const arr = map.get(entry.sys.contentType.sys.id) @@ -78,15 +142,21 @@ export const buildEntryList = ({ contentTypeItems, currentSyncData }) => { } }) // Order is relevant, must map 1:1 to contentTypeItems array - return contentTypeItems.map(contentType => map.get(contentType.sys.id)) + return contentTypeItems.map(contentType => map.get(contentType.sys.id) || []) } export const buildResolvableSet = ({ entryList, existingNodes = [], assets = [], -}) => { - const resolvable = new Set() +}: { + entryList: Array< + Array> + > + existingNodes: Array + assets: Array +}): Set => { + const resolvable: Set = new Set() existingNodes.forEach(node => { if (node.internal.owner === `gatsby-source-contentful` && node?.sys?.id) { // We need to add only root level resolvable (assets and entries) @@ -104,7 +174,26 @@ export const buildResolvableSet = ({ return resolvable } -function cleanupReferencesFromEntry(foreignReferenceMapState, entry) { +interface IForeignReference { + name: string + id: string + spaceId: string + type: string // Could be based on constances? +} + +interface IForeignReferenceMap { + [key: string]: Array +} + +interface IForeignReferenceMapState { + links: Array + backLinks: IForeignReferenceMap +} + +function cleanupReferencesFromEntry( + foreignReferenceMapState: IForeignReferenceMapState, + entry: EntryWithAllLocalesAndWithoutLinkResolution +): void { const { links, backLinks } = foreignReferenceMapState const entryId = entry.sys.id @@ -114,7 +203,7 @@ function cleanupReferencesFromEntry(foreignReferenceMapState, entry) { const backLinksForLink = backLinks[link] if (backLinksForLink) { const newBackLinks = backLinksForLink.filter(({ id }) => id !== entryId) - if (newBackLinks.lenth > 0) { + if (newBackLinks.length > 0) { backLinks[link] = newBackLinks } else { delete backLinks[link] @@ -135,11 +224,25 @@ export const buildForeignReferenceMap = ({ useNameForId, previousForeignReferenceMapState, deletedEntries, -}) => { - const foreignReferenceMapState = previousForeignReferenceMapState || { - links: {}, - backLinks: {}, - } +}: { + contentTypeItems: Array + entryList: Array< + Array> + > + resolvable: Set + defaultLocale: string + space: Space + useNameForId: boolean + previousForeignReferenceMapState?: IForeignReferenceMapState + deletedEntries: Array< + EntryWithAllLocalesAndWithoutLinkResolution + > +}): IForeignReferenceMapState => { + const foreignReferenceMapState: IForeignReferenceMapState = + previousForeignReferenceMapState || { + links: [], + backLinks: {}, + } const { links, backLinks } = foreignReferenceMapState @@ -178,7 +281,7 @@ export const buildForeignReferenceMap = ({ entryItemFieldValue[0].sys.id ) { entryItemFieldValue.forEach(v => { - const key = createRefId(v) + const key = createLinkRefId(v) // Don't create link to an unresolvable field. if (!resolvable.has(key)) { return @@ -205,7 +308,7 @@ export const buildForeignReferenceMap = ({ entryItemFieldValue?.sys?.type && entryItemFieldValue.sys.id ) { - const key = createRefId(entryItemFieldValue) + const key = createLinkRefId(entryItemFieldValue) // Don't create link to an unresolvable field. if (!resolvable.has(key)) { return @@ -235,9 +338,18 @@ export const buildForeignReferenceMap = ({ return foreignReferenceMapState } -function prepareTextNode(id, node, key, text) { +interface IContentfulTextNode extends Node { + sys: Partial +} + +function prepareTextNode( + id: string, + node: IContentfulEntry, + _key: string, + text: unknown +): IContentfulTextNode { const str = _.isString(text) ? text : `` - const textNode = { + const textNode: IContentfulTextNode = { id, parent: node.id, raw: str, @@ -248,6 +360,7 @@ function prepareTextNode(id, node, key, text) { // entryItem.sys.publishedAt is source of truth from contentful contentDigest: node.sys.publishedAt, }, + children: [], sys: { type: `TextNode`, }, @@ -272,8 +385,15 @@ function contentfulCreateNodeManifest({ entryItem, entryNode, space, + // eslint-disable-next-line @typescript-eslint/naming-convention unstable_createNodeManifest, -}) { +}: { + pluginConfig: IProcessedPluginOptions + entryItem: EntryWithAllLocalesAndWithoutLinkResolution + entryNode: IContentfulEntry + space: Space + unstable_createNodeManifest: SourceNodesArgs["unstable_createNodeManifest"] +}): void { const isPreview = pluginConfig.get(`host`) === `preview.contentful.com` const createNodeManifestIsSupported = @@ -327,9 +447,24 @@ function contentfulCreateNodeManifest({ } } +interface ICreateNodesForContentTypeArgs extends Actions, SourceNodesArgs { + contentTypeItem: ContentType + entries: Array< + EntryWithAllLocalesAndWithoutLinkResolution + > + resolvable: Set + foreignReferenceMap: IForeignReferenceMap + defaultLocale: string + locales: Array + space: Space + useNameForId: boolean + pluginConfig: IProcessedPluginOptions +} + export const createNodesForContentType = ({ contentTypeItem, entries, + // eslint-disable-next-line @typescript-eslint/naming-convention unstable_createNodeManifest, createNode, createNodeId, @@ -341,7 +476,7 @@ export const createNodesForContentType = ({ space, useNameForId, pluginConfig, -}) => { +}: ICreateNodesForContentTypeArgs): Array> => { // Establish identifier for content type // Use `name` if specified, otherwise, use internal id (usually a natural-language constant, // but sometimes a base62 uuid generated by Contentful, hence the option) @@ -352,7 +487,7 @@ export const createNodesForContentType = ({ contentTypeItemId = contentTypeItem.sys.id } - const createNodePromises = [] + const createNodePromises: Array> = [] // Create a node for the content type const contentTypeNode = { @@ -392,7 +527,7 @@ export const createNodesForContentType = ({ }) // Warn about any field conflicts - const conflictFields = [] + const conflictFields: Array = [] contentTypeItem.fields.forEach(contentTypeItemField => { const fieldName = contentTypeItemField.id if (restrictedNodeFields.includes(fieldName)) { @@ -403,194 +538,197 @@ export const createNodesForContentType = ({ } }) - const childrenNodes = [] + const childrenNodes: Array = [] // First create nodes for each of the entries of that content type - const entryNodes = entries - .map(entryItem => { - const entryNodeId = mId( - space.sys.id, - entryItem.sys.id, - entryItem.sys.type - ) + const entryNodes = entries.map(entryItem => { + const entryNodeId = mId( + space.sys.id, + entryItem.sys.id, + entryItem.sys.type + ) - const existingNode = getNode(entryNodeId) - if (existingNode?.updatedAt === entryItem.sys.updatedAt) { - // The Contentful model has `.sys.updatedAt` leading for an entry. If the updatedAt value - // of an entry did not change, then we can trust that none of its children were changed either. - return null - } + const existingNode = getNode(entryNodeId) + if (existingNode?.updatedAt === entryItem.sys.updatedAt) { + // The Contentful model has `.sys.updatedAt` leading for an entry. If the updatedAt value + // of an entry did not change, then we can trust that none of its children were changed either. + return null + } - // Get localized fields. - const entryItemFields = _.mapValues(entryItem.fields, (v, k) => { - const fieldProps = contentTypeItem.fields.find( - field => field.id === k - ) + // Get localized fields. + const entryItemFields = _.mapValues(entryItem.fields, (v, k) => { + const fieldProps = contentTypeItem.fields.find(field => field.id === k) - const localizedField = fieldProps.localized - ? getField(v) - : v[defaultLocale] + if (!fieldProps) { + throw new Error(`Unable to translate field ${k}`) + } - return localizedField - }) + const localizedField = fieldProps.localized + ? getField(v) + : v[defaultLocale] - // Prefix any conflicting fields - // https://github.com/gatsbyjs/gatsby/pull/1084#pullrequestreview-41662888 - conflictFields.forEach(conflictField => { - entryItemFields[`${conflictFieldPrefix}${conflictField}`] = - entryItemFields[conflictField] - delete entryItemFields[conflictField] - }) + return localizedField + }) - // Add linkages to other nodes based on foreign references - Object.keys(entryItemFields).forEach(entryItemFieldKey => { - if (entryItemFields[entryItemFieldKey]) { - const entryItemFieldValue = entryItemFields[entryItemFieldKey] - if (Array.isArray(entryItemFieldValue)) { - if (entryItemFieldValue[0]?.sys?.type === `Link`) { - // Check if there are any values in entryItemFieldValue to prevent - // creating an empty node field in case when original key field value - // is empty due to links to missing entities - const resolvableEntryItemFieldValue = entryItemFieldValue - .filter(v => resolvable.has(createRefId(v))) - .map(function (v) { - return mId( - space.sys.id, - v.sys.id, - v.sys.linkType || v.sys.type - ) - }) - if (resolvableEntryItemFieldValue.length !== 0) { - entryItemFields[entryItemFieldKey] = - resolvableEntryItemFieldValue - } - } - } else if (entryItemFieldValue?.sys?.type === `Link`) { - if (resolvable.has(createRefId(entryItemFieldValue))) { - entryItemFields[entryItemFieldKey] = mId( - space.sys.id, - entryItemFieldValue.sys.id, - entryItemFieldValue.sys.linkType || - entryItemFieldValue.sys.type - ) + // Prefix any conflicting fields + // https://github.com/gatsbyjs/gatsby/pull/1084#pullrequestreview-41662888 + conflictFields.forEach(conflictField => { + entryItemFields[`${conflictFieldPrefix}${conflictField}`] = + entryItemFields[conflictField] + delete entryItemFields[conflictField] + }) + + // Add linkages to other nodes based on foreign references + Object.keys(entryItemFields).forEach(entryItemFieldKey => { + if (entryItemFields[entryItemFieldKey]) { + const entryItemFieldValue = entryItemFields[entryItemFieldKey] + if (Array.isArray(entryItemFieldValue)) { + if (entryItemFieldValue[0]?.sys?.type === `Link`) { + // Check if there are any values in entryItemFieldValue to prevent + // creating an empty node field in case when original key field value + // is empty due to links to missing entities + const resolvableEntryItemFieldValue = entryItemFieldValue + .filter(v => resolvable.has(createLinkRefId(v))) + .map(function (v) { + return mId( + space.sys.id, + v.sys.id, + v.sys.linkType || v.sys.type + ) + }) + if (resolvableEntryItemFieldValue.length !== 0) { + entryItemFields[entryItemFieldKey] = + resolvableEntryItemFieldValue } } + } else if (entryItemFieldValue?.sys?.type === `Link`) { + if (resolvable.has(createLinkRefId(entryItemFieldValue))) { + entryItemFields[entryItemFieldKey] = mId( + space.sys.id, + entryItemFieldValue.sys.id, + entryItemFieldValue.sys.linkType || entryItemFieldValue.sys.type + ) + } } - }) + } + }) - // Add reverse linkages if there are any for this node - const foreignReferences = foreignReferenceMap[createRefId(entryItem)] - if (foreignReferences) { - foreignReferences.forEach(foreignReference => { - const existingReference = entryItemFields[foreignReference.name] - if (existingReference) { - // If the existing reference is a string, we're dealing with a - // many-to-one reference which has already been recorded, so we can - // skip it. However, if it is an array, add it: - if (Array.isArray(existingReference)) { - entryItemFields[foreignReference.name].push( - mId( - foreignReference.spaceId, - foreignReference.id, - foreignReference.type - ) - ) - } - } else { - // If there is one foreign reference, there can be many. - // Best to be safe and put it in an array to start with. - entryItemFields[foreignReference.name] = [ + // Add reverse linkages if there are any for this node + const foreignReferences = foreignReferenceMap[createRefId(entryItem)] + if (foreignReferences) { + foreignReferences.forEach(foreignReference => { + const existingReference = entryItemFields[foreignReference.name] + if (existingReference) { + // If the existing reference is a string, we're dealing with a + // many-to-one reference which has already been recorded, so we can + // skip it. However, if it is an array, add it: + if (Array.isArray(existingReference)) { + entryItemFields[foreignReference.name].push( mId( foreignReference.spaceId, foreignReference.id, foreignReference.type - ), - ] + ) + ) } - }) - } + } else { + // If there is one foreign reference, there can be many. + // Best to be safe and put it in an array to start with. + entryItemFields[foreignReference.name] = [ + mId( + foreignReference.spaceId, + foreignReference.id, + foreignReference.type + ), + ] + } + }) + } - // Create actual entry node - let entryNode = { - id: entryNodeId, - parent: contentTypeItemId, - children: [], - internal: { - type: `${makeTypeName(contentTypeItemId)}`, - // The content of an entry is guaranteed to be updated if and only if the .sys.updatedAt field changed - contentDigest: entryItem.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: entryItem.sys.type, - id: entryItem.sys.id, - locale: locale.code, - spaceId: entryItem.sys.space.sys.id, - environmentId: entryItem.sys.environment.sys.id, - contentType: createNodeId(contentTypeItemId), - firstPublishedAt: entryItem.sys.createdAt, - publishedAt: entryItem.sys.updatedAt, - publishedVersion: entryItem.sys.revision, - }, - } + // Create actual entry node + let entryNode: IContentfulEntry = { + id: entryNodeId, + parent: contentTypeItemId, + children: [], + internal: { + type: makeTypeName(contentTypeItemId), + // The content of an entry is guaranteed to be updated if and only if the .sys.updatedAt field changed + contentDigest: entryItem.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: entryItem.sys.type, + id: entryItem.sys.id, + locale: locale.code, + spaceId: entryItem.sys.space.sys.id, + environmentId: entryItem.sys.environment.sys.id, + contentType: createNodeId(contentTypeItemId), + firstPublishedAt: entryItem.sys.createdAt, + publishedAt: entryItem.sys.updatedAt, + publishedVersion: entryItem.sys.revision, + }, + metadata: { + tags: entryItem.metadata.tags.map(tag => + createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) + ), + }, + } - contentfulCreateNodeManifest({ - pluginConfig, - entryItem, - entryNode, - space, - unstable_createNodeManifest, - }) + contentfulCreateNodeManifest({ + pluginConfig, + entryItem, + entryNode, + space, + // eslint-disable-next-line @typescript-eslint/naming-convention + unstable_createNodeManifest, + }) - // Replace text fields with text nodes so we can process their markdown - // into HTML. - Object.keys(entryItemFields).forEach(entryItemFieldKey => { - // @todo: how expensive is this? - const field = contentTypeItem.fields.find( - f => - (restrictedNodeFields.includes(f.id) - ? `${conflictFieldPrefix}${f.id}` - : f.id) === entryItemFieldKey + // Replace text fields with text nodes so we can process their markdown + // into HTML. + Object.keys(entryItemFields).forEach(entryItemFieldKey => { + // TODO:: how expensive is this? + const field = contentTypeItem.fields.find( + f => + (restrictedNodeFields.includes(f.id) + ? `${conflictFieldPrefix}${f.id}` + : f.id) === entryItemFieldKey + ) + if (field?.type === `Text`) { + const textNodeId = createNodeId( + `${entryNodeId}${entryItemFieldKey}TextNode` ) - if (field?.type === `Text`) { - const textNodeId = createNodeId( - `${entryNodeId}${entryItemFieldKey}TextNode` - ) - - // The Contentful model has `.sys.updatedAt` leading for an entry. If the updatedAt value - // of an entry did not change, then we can trust that none of its children were changed either. - // (That's why child nodes use the updatedAt of the parent node as their digest, too) - const existingNode = getNode(textNodeId) - if (existingNode?.updatedAt !== entryItem.sys.updatedAt) { - const textNode = prepareTextNode( - textNodeId, - entryNode, - entryItemFieldKey, - entryItemFields[entryItemFieldKey] - ) - childrenNodes.push(textNode) - } + // The Contentful model has `.sys.updatedAt` leading for an entry. If the updatedAt value + // of an entry did not change, then we can trust that none of its children were changed either. + // (That's why child nodes use the updatedAt of the parent node as their digest, too) + const existingNode = getNode(textNodeId) + if (existingNode?.updatedAt !== entryItem.sys.updatedAt) { + const textNode = prepareTextNode( + textNodeId, + entryNode, + entryItemFieldKey, + entryItemFields[entryItemFieldKey] + ) - entryItemFields[entryItemFieldKey] = textNodeId + childrenNodes.push(textNode) } - }) - entryNode = { - ...entryItemFields, - ...entryNode, - metadata: { - tags: entryItem.metadata.tags.map(tag => - createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) - ), - }, + entryItemFields[entryItemFieldKey] = textNodeId } - return entryNode }) - .filter(Boolean) + + entryNode = { + ...entryItemFields, + ...entryNode, + } + return entryNode + }) entryNodes.forEach(entryNode => { + if (!entryNode) { + return + } createNodePromises.push(createNode(entryNode)) }) childrenNodes.forEach(entryNode => { @@ -608,8 +746,15 @@ export const createAssetNodes = ({ defaultLocale, locales, space, -}) => { - const createNodePromises = [] +}: { + assetItem + createNode + createNodeId + defaultLocale + locales: Array + space: Space +}): Array> => { + const createNodePromises: Array> = [] locales.forEach(locale => { const localesFallback = buildFallbackChain(locales) const mId = makeMakeId({ @@ -622,7 +767,13 @@ export const createAssetNodes = ({ localesFallback, }) - const file = getField(assetItem.fields?.file) ?? null + const fileRes = getField(assetItem.fields?.file) + + if (!fileRes) { + return + } + + const file = fileRes as unknown as AssetFile // Skip empty and unprocessed assets in Preview API if (!file || !file.url || !file.contentType || !file.fileName) { diff --git a/packages/gatsby-source-contentful/src/plugin-options.js b/packages/gatsby-source-contentful/src/plugin-options.ts similarity index 61% rename from packages/gatsby-source-contentful/src/plugin-options.js rename to packages/gatsby-source-contentful/src/plugin-options.ts index 67ed7770a0393..459a6a1fff9de 100644 --- a/packages/gatsby-source-contentful/src/plugin-options.js +++ b/packages/gatsby-source-contentful/src/plugin-options.ts @@ -1,10 +1,11 @@ -// @ts-check import chalk from "chalk" import _ from "lodash" +import type { IPluginOptions, IProcessedPluginOptions } from "./types/plugin" + const DEFAULT_PAGE_LIMIT = 1000 -const defaultOptions = { +const defaultOptions: Omit = { host: `cdn.contentful.com`, environment: `master`, downloadLocal: false, @@ -14,26 +15,46 @@ const defaultOptions = { useNameForId: true, } -const createPluginConfig = pluginOptions => { +/** + * Mask majority of input to not leak any secrets + * @param {string} input + * @returns {string} masked text + */ +const maskText = (input: string): string => { + // show just 25% of string up to 4 characters + const hiddenCharactersLength = + input.length - Math.min(4, Math.floor(input.length * 0.25)) + + return `${`*`.repeat(hiddenCharactersLength)}${input.substring( + hiddenCharactersLength + )}` +} + +const createPluginConfig = ( + pluginOptions: IPluginOptions +): IProcessedPluginOptions => { const conf = { ...defaultOptions, ...pluginOptions } return { - get: key => conf[key], - getOriginalPluginOptions: () => pluginOptions, + get: (key): unknown => conf[key], + getOriginalPluginOptions: (): IPluginOptions => pluginOptions, } } const maskedFields = [`accessToken`, `spaceId`] -const formatPluginOptionsForCLI = (pluginOptions, errors = {}) => { +const formatPluginOptionsForCLI = ( + pluginOptions: IPluginOptions, + errors = {} +): string => { const optionKeys = new Set( Object.keys(pluginOptions) .concat(Object.keys(defaultOptions)) .concat(Object.keys(errors)) ) - const getDisplayValue = key => { - const formatValue = value => { + const getDisplayValue = (key: string): string => { + const formatValue = (value: unknown): string => { if (_.isFunction(value)) { return `[Function]` } else if (maskedFields.includes(key) && typeof value === `string`) { @@ -51,42 +72,27 @@ const formatPluginOptionsForCLI = (pluginOptions, errors = {}) => { return chalk.dim(`undefined`) } - const lines = [] + const lines: Array = [] optionKeys.forEach(key => { if (key === `plugins`) { // skip plugins field automatically added by gatsby return } - lines.push( - `${key}${ - typeof pluginOptions[key] === `undefined` && - typeof defaultOptions[key] !== `undefined` - ? chalk.dim(` (default value)`) - : `` - }: ${getDisplayValue(key)}${ - typeof errors[key] !== `undefined` ? ` - ${chalk.red(errors[key])}` : `` - }` - ) + const defaultValue = + typeof pluginOptions[key] === `undefined` && + typeof defaultOptions[key] !== `undefined` + ? chalk.dim(` (default value)`) + : `` + const displayValue = getDisplayValue(key) + const errorValue = + typeof errors[key] !== `undefined` ? ` - ${chalk.red(errors[key])}` : `` + + lines.push(`${key}${defaultValue}: ${displayValue}${errorValue}`) }) return lines.join(`\n`) } -/** - * Mask majority of input to not leak any secrets - * @param {string} input - * @returns {string} masked text - */ -const maskText = input => { - // show just 25% of string up to 4 characters - const hiddenCharactersLength = - input.length - Math.min(4, Math.floor(input.length * 0.25)) - - return `${`*`.repeat(hiddenCharactersLength)}${input.substring( - hiddenCharactersLength - )}` -} - export { defaultOptions, formatPluginOptionsForCLI, diff --git a/packages/gatsby-source-contentful/src/report.js b/packages/gatsby-source-contentful/src/report.ts similarity index 80% rename from packages/gatsby-source-contentful/src/report.js rename to packages/gatsby-source-contentful/src/report.ts index afffe7faa83d3..1de95e68dde21 100644 --- a/packages/gatsby-source-contentful/src/report.js +++ b/packages/gatsby-source-contentful/src/report.ts @@ -1,4 +1,4 @@ -// @ts-check +import type { IErrorMapEntry } from "gatsby-cli/lib/structured-errors/error-map" export const CODES = { /* Fetch errors */ @@ -8,9 +8,15 @@ export const CODES = { FetchContentTypes: `111004`, GatsbyPluginMissing: `111005`, ContentTypesMissing: `111006`, + FetchTags: `111007`, + GenericContentfulError: `111008`, } -export const ERROR_MAP = { +interface IErrorMap { + [code: string]: Omit +} + +export const ERROR_MAP: IErrorMap = { [CODES.LocalesMissing]: { text: context => context.sourceMessage, level: `ERROR`, @@ -41,14 +47,14 @@ export const ERROR_MAP = { level: `ERROR`, category: `THIRD_PARTY`, }, - [CODES.FetchTags]: { + [CODES.GatsbyPluginMissing]: { text: context => context.sourceMessage, level: `ERROR`, - category: `THIRD_PARTY`, + category: `USER`, }, - [CODES.GatsbyPluginMissing]: { + [CODES.GenericContentfulError]: { text: context => context.sourceMessage, level: `ERROR`, - category: `USER`, + category: `THIRD_PARTY`, }, } diff --git a/packages/gatsby-source-contentful/src/rich-text.js b/packages/gatsby-source-contentful/src/rich-text.ts similarity index 53% rename from packages/gatsby-source-contentful/src/rich-text.js rename to packages/gatsby-source-contentful/src/rich-text.ts index 26e3e19fe4a76..03418aa7d457b 100644 --- a/packages/gatsby-source-contentful/src/rich-text.js +++ b/packages/gatsby-source-contentful/src/rich-text.ts @@ -1,7 +1,41 @@ -// @ts-check import { documentToReactComponents } from "@contentful/rich-text-react-renderer" +import { + AssetHyperlink, + AssetLinkBlock, + Document, + EntryHyperlink, + EntryLinkBlock, + EntryLinkInline, +} from "@contentful/rich-text-types" +import React from "react" +import type { IContentfulEntry, IContentfulAsset } from "./types/contentful" -export function renderRichText({ json, links }, makeOptions = {}) { +interface IContentfulRichTextLinksAssets { + block: Array + hyperlink: Array +} + +interface IContentfulRichTextLinksEntries { + inline: Array + block: Array + hyperlink: Array +} + +interface IContentfulRichTextLinks { + assets: IContentfulRichTextLinksAssets + entries: IContentfulRichTextLinksEntries +} + +export function renderRichText( + { + json, + links, + }: { + json: Document + links: IContentfulRichTextLinks + }, + makeOptions = {} +): React.ReactNode { const options = typeof makeOptions === `function` ? makeOptions(generateLinkMaps(links)) @@ -10,13 +44,17 @@ export function renderRichText({ json, links }, makeOptions = {}) { return documentToReactComponents(json, options) } -exports.renderRichText = renderRichText - /** * Helper function to simplify Rich Text rendering. Based on: * https://www.contentful.com/blog/2021/04/14/rendering-linked-assets-entries-in-contentful/ */ -function generateLinkMaps(links) { +function generateLinkMaps(links): { + assetBlockMap: Map + assetHyperlinkMap: Map + entryBlockMap: Map + entryInlineMap: Map + entryHyperlinkMap: Map +} { const assetBlockMap = new Map() for (const asset of links?.assets.block || []) { assetBlockMap.set(asset.sys.id, asset) diff --git a/packages/gatsby-source-contentful/src/schemes.js b/packages/gatsby-source-contentful/src/schemes.ts similarity index 99% rename from packages/gatsby-source-contentful/src/schemes.js rename to packages/gatsby-source-contentful/src/schemes.ts index abc4db100761a..a297e4d4c5094 100644 --- a/packages/gatsby-source-contentful/src/schemes.js +++ b/packages/gatsby-source-contentful/src/schemes.ts @@ -1,4 +1,3 @@ -// @ts-check import { GraphQLEnumType } from "gatsby/graphql" export const ImageFormatType = new GraphQLEnumType({ diff --git a/packages/gatsby-source-contentful/src/source-nodes.js b/packages/gatsby-source-contentful/src/source-nodes.js deleted file mode 100644 index 7e2e230e06f3e..0000000000000 --- a/packages/gatsby-source-contentful/src/source-nodes.js +++ /dev/null @@ -1,565 +0,0 @@ -// @ts-check -import isOnline from "is-online" -import _ from "lodash" - -import { downloadContentfulAssets } from "./download-contentful-assets" -import { fetchContent } from "./fetch" -import { SourceNodesArgs } from "gatsby" -import { - buildEntryList, - buildForeignReferenceMap, - buildResolvableSet, - createAssetNodes, - createNodesForContentType, - createRefId, - makeId, -} from "./normalize" -import { createPluginConfig } from "./plugin-options" -import { CODES } from "./report" - -const CONTENT_DIGEST_COUNTER_SEPARATOR = `_COUNT_` - -/*** - * Localization algorithm - * - * 1. Make list of all resolvable IDs worrying just about the default ids not - * localized ids - * 2. Make mapping between ids, again not worrying about localization. - * 3. When creating entries and assets, make the most localized version - * possible for each localized node i.e. get the localized field if it exists - * or the fallback field or the default field. - */ - -let isFirstSource = true -export async function sourceNodes( - /** @type {SourceNodesArgs} */ - { - actions, - getNode, - getNodes, - createNodeId, - store, - cache, - getCache, - reporter, - parentSpan, - }, - pluginOptions -) { - const { createNode, touchNode, deleteNode, unstable_createNodeManifest } = - actions - const online = await isOnline() - - // Gatsby only checks if a node has been touched on the first sourcing. - // As iterating and touching nodes can grow quite expensive on larger sites with - // 1000s of nodes, we'll skip doing this on subsequent sources. - if (isFirstSource) { - getNodes().forEach(node => { - if (node.internal.owner !== `gatsby-source-contentful`) { - return - } - touchNode(node) - if (node?.fields?.localFile) { - // Prevent GraphQL type inference from crashing on this property - touchNode(getNode(node.fields.localFile)) - } - }) - isFirstSource = false - } - - if ( - !online && - process.env.GATSBY_CONTENTFUL_OFFLINE === `true` && - process.env.NODE_ENV !== `production` - ) { - return - } - - const pluginConfig = createPluginConfig(pluginOptions) - const sourceId = `${pluginConfig.get(`spaceId`)}-${pluginConfig.get( - `environment` - )}` - - const fetchActivity = reporter.activityTimer(`Contentful: Fetch data`, { - parentSpan, - }) - - // If the user knows they are offline, serve them cached result - // For prod builds though always fail if we can't get the latest data - if ( - !online && - process.env.GATSBY_CONTENTFUL_OFFLINE === `true` && - process.env.NODE_ENV !== `production` - ) { - reporter.info(`Using Contentful Offline cache ⚠️`) - reporter.info( - `Cache may be invalidated if you edit package.json, gatsby-node.js or gatsby-config.js files` - ) - - return - } - if (process.env.GATSBY_CONTENTFUL_OFFLINE) { - reporter.info( - `Note: \`GATSBY_CONTENTFUL_OFFLINE\` was set but it either was not \`true\`, we _are_ online, or we are in production mode, so the flag is ignored.` - ) - } - - fetchActivity.start() - - const CACHE_SYNC_TOKEN = `contentful-sync-token-${sourceId}` - const CACHE_CONTENT_TYPES = `contentful-content-types-${sourceId}` - const CACHE_FOREIGN_REFERENCE_MAP_STATE = `contentful-foreign-reference-map-state-${sourceId}` - - /* - * Subsequent calls of Contentfuls sync API return only changed data. - * - * In some cases, especially when using rich-text fields, there can be data - * missing from referenced entries. This breaks the reference matching. - * - * To workround this, we cache the initial sync data and merge it - * with all data from subsequent syncs. Afterwards the references get - * resolved via the Contentful JS SDK. - */ - const syncToken = - store.getState().status.plugins?.[`gatsby-source-contentful`]?.[ - CACHE_SYNC_TOKEN - ] - - // Actual fetch of data from Contentful - const { - currentSyncData, - tagItems, - defaultLocale, - locales: allLocales, - space, - } = await fetchContent({ syncToken, pluginConfig, reporter }) - - const contentTypeItems = await cache.get(CACHE_CONTENT_TYPES) - - const locales = allLocales.filter(pluginConfig.get(`localeFilter`)) - reporter.verbose( - `Default locale: ${defaultLocale}. All locales: ${allLocales - .map(({ code }) => code) - .join(`, `)}` - ) - if (allLocales.length !== locales.length) { - reporter.verbose( - `After plugin.options.localeFilter: ${locales - .map(({ code }) => code) - .join(`, `)}` - ) - } - if (locales.length === 0) { - reporter.panic({ - id: CODES.LocalesMissing, - context: { - sourceMessage: `Please check if your localeFilter is configured properly. Locales '${allLocales - .map(item => item.code) - .join(`,`)}' were found but were filtered down to none.`, - }, - }) - } - - // Update syncToken - const nextSyncToken = currentSyncData.nextSyncToken - - actions.setPluginStatus({ - [CACHE_SYNC_TOKEN]: nextSyncToken, - }) - - fetchActivity.end() - - // Process data fetch results and turn them into GraphQL entities - const processingActivity = reporter.activityTimer( - `Contentful: Process data`, - { - parentSpan, - } - ) - processingActivity.start() - - // Array of all existing Contentful entry and asset nodes - const existingNodes = getNodes().filter( - n => - (n.internal.owner === `gatsby-source-contentful` && - n.internal.type.indexOf(`ContentfulContentType`) === 0) || - n.internal.type === `ContentfulAsset` - ) - - // Report existing, new and updated nodes - const nodeCounts = { - newEntry: 0, - newAsset: 0, - updatedEntry: 0, - updatedAsset: 0, - existingEntry: 0, - existingAsset: 0, - deletedEntry: currentSyncData.deletedEntries.length, - deletedAsset: currentSyncData.deletedAssets.length, - } - - existingNodes.forEach(node => nodeCounts[`existing${node.sys.type}`]++) - currentSyncData.entries.forEach(entry => - entry.sys.revision === 1 ? nodeCounts.newEntry++ : nodeCounts.updatedEntry++ - ) - currentSyncData.assets.forEach(asset => - asset.sys.revision === 1 ? nodeCounts.newAsset++ : nodeCounts.updatedAsset++ - ) - - reporter.info(`Contentful: ${nodeCounts.newEntry} new entries`) - reporter.info(`Contentful: ${nodeCounts.updatedEntry} updated entries`) - reporter.info(`Contentful: ${nodeCounts.deletedEntry} deleted entries`) - reporter.info( - `Contentful: ${nodeCounts.existingEntry / locales.length} cached entries` - ) - reporter.info(`Contentful: ${nodeCounts.newAsset} new assets`) - reporter.info(`Contentful: ${nodeCounts.updatedAsset} updated assets`) - reporter.info( - `Contentful: ${nodeCounts.existingAsset / locales.length} cached assets` - ) - reporter.info(`Contentful: ${nodeCounts.deletedAsset} deleted assets`) - - reporter.verbose(`Building Contentful reference map`) - - const entryList = buildEntryList({ - currentSyncData, - contentTypeItems, - }) - const { assets } = currentSyncData || { assets: [] } - - // Create map of resolvable ids so we can check links against them while creating - // links. - const resolvable = buildResolvableSet({ - existingNodes, - entryList, - assets, - }) - - const previousForeignReferenceMapState = await cache.get( - CACHE_FOREIGN_REFERENCE_MAP_STATE - ) - const useNameForId = pluginConfig.get(`useNameForId`) - // Build foreign reference map before starting to insert any nodes - const foreignReferenceMapState = buildForeignReferenceMap({ - contentTypeItems, - entryList, - resolvable, - defaultLocale, - space, - useNameForId, - previousForeignReferenceMapState, - deletedEntries: currentSyncData?.deletedEntries, - }) - - await cache.set(CACHE_FOREIGN_REFERENCE_MAP_STATE, foreignReferenceMapState) - const foreignReferenceMap = foreignReferenceMapState.backLinks - - reporter.verbose(`Resolving Contentful references`) - - const newOrUpdatedEntries = new Set() - entryList.forEach(entries => { - entries.forEach(entry => { - newOrUpdatedEntries.add(createRefId(entry)) - }) - }) - - const { deletedEntries, deletedAssets } = currentSyncData || { - deletedEntries: [], - deletedAssets: [], - } - const deletedEntryGatsbyReferenceIds = new Set() - - function deleteContentfulNode(node) { - const normalizedType = node.sys.type.startsWith(`Deleted`) - ? node.sys.type.substring(`Deleted`.length) - : node.sys.type - - const localizedNodes = locales - .map(locale => { - const nodeId = createNodeId( - makeId({ - spaceId: space.sys.id, - id: node.sys.id, - type: normalizedType, - currentLocale: locale.code, - defaultLocale, - }) - ) - // Gather deleted node ids to remove them later on - deletedEntryGatsbyReferenceIds.add(nodeId) - return getNode(nodeId) - }) - .filter(node => node) - - localizedNodes.forEach(node => { - // @todo nodes of text fields should be deleted as well - deleteNode(node) - }) - } - - if (deletedEntries.length || deletedAssets.length) { - const deletionActivity = reporter.activityTimer( - `Contentful: Deleting nodes and assets`, - { - parentSpan, - } - ) - deletionActivity.start() - deletedEntries.forEach(deleteContentfulNode) - deletedAssets.forEach(deleteContentfulNode) - deletionActivity.end() - } - - // Create map of reference fields to properly delete stale references - const referenceFieldMap = new Map() - for (const contentTypeItem of contentTypeItems) { - const referenceFields = contentTypeItem.fields.filter(field => { - if (field.disabled || field.omitted) { - return false - } - - return ( - field.type === `Link` || - (field.type === `Array` && field.items.type === `Link`) - ) - }) - if (referenceFields.length) { - referenceFieldMap.set( - contentTypeItem.name, - referenceFields.map(field => field.id) - ) - } - } - - // @todo mirror structure of Contentful GraphQL API, as it prevents field name overlaps - const reverseReferenceFields = contentTypeItems.map(contentTypeItem => - useNameForId - ? contentTypeItem.name.toLowerCase() - : contentTypeItem.sys.id.toLowerCase() - ) - - // Update existing entry nodes that weren't updated but that need reverse links added or removed. - const existingNodesThatNeedReverseLinksUpdateInDatastore = new Set() - existingNodes - .filter( - n => - n.sys.type === `Entry` && - !newOrUpdatedEntries.has(createRefId(n)) && - !deletedEntryGatsbyReferenceIds.has(n.id) - ) - .forEach(n => { - if (n.sys.id && foreignReferenceMap[createRefId(n)]) { - foreignReferenceMap[createRefId(n)].forEach(foreignReference => { - const { name, id, type, spaceId } = foreignReference - - const nodeId = createNodeId( - makeId({ - spaceId, - id, - type, - currentLocale: n.sys.locale, - defaultLocale, - }) - ) - - // Create new reference field when none exists - if (!n[name]) { - existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) - n[name] = [nodeId] - return - } - - // Add non existing references to reference field - if (n[name] && !n[name].includes(nodeId)) { - existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) - n[name].push(nodeId) - } - }) - } - - // Remove references to deleted nodes - if ( - n.sys.id && - deletedEntryGatsbyReferenceIds.size && - referenceFieldMap.has(n.sys.contentType) - ) { - const referenceFields = [ - ...referenceFieldMap.get(n.sys.contentType), - ...reverseReferenceFields, - ] - - referenceFields.forEach(name => { - const fieldValue = n[name] - if (Array.isArray(fieldValue)) { - n[name] = fieldValue.filter(referenceId => { - const shouldRemove = - deletedEntryGatsbyReferenceIds.has(referenceId) - if (shouldRemove) { - existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) - } - return !shouldRemove - }) - } else { - if (deletedEntryGatsbyReferenceIds.has(fieldValue)) { - existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) - n[name] = null - } - } - }) - } - }) - - // We need to call `createNode` on nodes we modified reverse links on, - // otherwise changes won't actually persist - if (existingNodesThatNeedReverseLinksUpdateInDatastore.size) { - for (const node of existingNodesThatNeedReverseLinksUpdateInDatastore) { - function addChildrenToList(node, nodeList = [node]) { - for (const childNodeId of node?.children ?? []) { - const childNode = getNode(childNodeId) - if ( - childNode && - childNode.internal.owner === `gatsby-source-contentful` - ) { - nodeList.push(childNode) - addChildrenToList(childNode) - } - } - return nodeList - } - - const nodeAndDescendants = addChildrenToList(node) - for (const nodeToUpdateOriginal of nodeAndDescendants) { - // We should not mutate original node as Gatsby will still - // compare against what's in in-memory weak cache, so we - // clone original node to ensure reference identity is not possible - const nodeToUpdate = _.cloneDeep(nodeToUpdateOriginal) - // We need to remove properties from existing fields - // that are reserved and managed by Gatsby (`.internal.owner`, `.fields`). - // Gatsby automatically will set `.owner` it back - delete nodeToUpdate.internal.owner - // `.fields` need to be created with `createNodeField` action, we can't just re-add them. - // Other plugins (or site itself) will have opportunity to re-generate them in `onCreateNode` lifecycle. - // Contentful content nodes are not using `createNodeField` so it's safe to delete them. - // (Asset nodes DO use `createNodeField` for `localFile` and if we were updating those, then - // we would also need to restore that field ourselves after re-creating a node) - delete nodeToUpdate.fields // plugin adds node field on asset nodes which don't have reverse links - - // We add or modify counter postfix to contentDigest - // to make sure Gatsby treat this as data update - let counter - const [initialContentDigest, counterStr] = - nodeToUpdate.internal.contentDigest.split( - CONTENT_DIGEST_COUNTER_SEPARATOR - ) - - if (counterStr) { - counter = parseInt(counterStr, 10) - } - - if (!counter || isNaN(counter)) { - counter = 1 - } else { - counter++ - } - - nodeToUpdate.internal.contentDigest = `${initialContentDigest}${CONTENT_DIGEST_COUNTER_SEPARATOR}${counter}` - createNode(nodeToUpdate) - } - } - } - - const creationActivity = reporter.activityTimer(`Contentful: Create nodes`, { - parentSpan, - }) - creationActivity.start() - - // Create nodes for each entry of each content type - for (let i = 0; i < contentTypeItems.length; i++) { - const contentTypeItem = contentTypeItems[i] - - if (entryList[i].length) { - reporter.info( - `Creating ${entryList[i].length} Contentful ${ - useNameForId ? contentTypeItem.name : contentTypeItem.sys.id - } nodes` - ) - } - - // A contentType can hold lots of entries which create nodes - // We wait until all nodes are created and processed until we handle the next one - // TODO add batching in gatsby-core - await Promise.all( - createNodesForContentType({ - contentTypeItem, - entries: entryList[i], - createNode, - createNodeId, - getNode, - resolvable, - foreignReferenceMap, - defaultLocale, - locales, - space, - useNameForId, - pluginConfig, - unstable_createNodeManifest, - }) - ) - } - - if (assets.length) { - reporter.info(`Creating ${assets.length} Contentful asset nodes`) - } - - const assetNodes = [] - for (let i = 0; i < assets.length; i++) { - // We wait for each asset to be process until handling the next one. - assetNodes.push( - ...(await Promise.all( - createAssetNodes({ - assetItem: assets[i], - createNode, - createNodeId, - defaultLocale, - locales, - space, - }) - )) - ) - } - - // Create tags entities - if (tagItems.length) { - reporter.info(`Creating ${tagItems.length} Contentful Tag nodes`) - - for (const tag of tagItems) { - await createNode({ - id: createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`), - name: tag.name, - // @todo update the structure of tags - contentful_id: tag.sys.id, - internal: { - type: `ContentfulTag`, - contentDigest: tag.sys.updatedAt, - }, - }) - } - } - - creationActivity.end() - - // Download asset files to local fs - if (pluginConfig.get(`downloadLocal`)) { - await downloadContentfulAssets({ - assetNodes, - actions, - createNodeId, - store, - cache, - getCache, - getNode, - reporter, - assetDownloadWorkers: pluginConfig.get(`assetDownloadWorkers`), - }) - } -} diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts new file mode 100644 index 0000000000000..24743e73c985a --- /dev/null +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -0,0 +1,571 @@ +import type { GatsbyNode, Node } from "gatsby" +import isOnline from "is-online" +import _ from "lodash" + +import { downloadContentfulAssets } from "./download-contentful-assets" +import { fetchContent } from "./fetch" +import { + buildEntryList, + buildForeignReferenceMap, + buildResolvableSet, + createAssetNodes, + createNodesForContentType, + createRefId, + makeId, +} from "./normalize" +import { createPluginConfig } from "./plugin-options" +import { CODES } from "./report" +import type { IPluginOptions } from "./types/plugin" +import type { IContentfulAsset, IContentfulEntry } from "./types/contentful" +import type { ContentType } from "./types/contentful-js-sdk" + +const CONTENT_DIGEST_COUNTER_SEPARATOR = `_COUNT_` + +/*** + * Localization algorithm + * + * 1. Make list of all resolvable IDs worrying just about the default ids not + * localized ids + * 2. Make mapping between ids, again not worrying about localization. + * 3. When creating entries and assets, make the most localized version + * possible for each localized node i.e. get the localized field if it exists + * or the fallback field or the default field. + */ + +let isFirstSource = true +export const sourceNodes: GatsbyNode["sourceNodes"] = + async function sourceNodes(args, pluginOptions) { + const { + actions, + getNode, + getNodes, + createNodeId, + store, + cache, + reporter, + parentSpan, + } = args + const { createNode, touchNode, deleteNode } = actions + const online = await isOnline() + + // Gatsby only checks if a node has been touched on the first sourcing. + // As iterating and touching nodes can grow quite expensive on larger sites with + // 1000s of nodes, we'll skip doing this on subsequent sources. + if (isFirstSource) { + getNodes().forEach(node => { + if (node.internal.owner !== `gatsby-source-contentful`) { + return + } + touchNode(node) + const assetNode = node as IContentfulAsset + if (!assetNode.fields.localFile) { + return + } + const localFileNode = getNode(assetNode.fields.localFile) + if (localFileNode) { + touchNode(localFileNode) + } + }) + isFirstSource = false + } + + if ( + !online && + process.env.GATSBY_CONTENTFUL_OFFLINE === `true` && + process.env.NODE_ENV !== `production` + ) { + return + } + + const pluginConfig = createPluginConfig(pluginOptions as IPluginOptions) + const sourceId = `${pluginConfig.get(`spaceId`)}-${pluginConfig.get( + `environment` + )}` + + const fetchActivity = reporter.activityTimer(`Contentful: Fetch data`, { + parentSpan, + }) + + // If the user knows they are offline, serve them cached result + // For prod builds though always fail if we can't get the latest data + if ( + !online && + process.env.GATSBY_CONTENTFUL_OFFLINE === `true` && + process.env.NODE_ENV !== `production` + ) { + reporter.info(`Using Contentful Offline cache ⚠️`) + reporter.info( + `Cache may be invalidated if you edit package.json, gatsby-node.js or gatsby-config.js files` + ) + + return + } + if (process.env.GATSBY_CONTENTFUL_OFFLINE) { + reporter.info( + `Note: \`GATSBY_CONTENTFUL_OFFLINE\` was set but it either was not \`true\`, we _are_ online, or we are in production mode, so the flag is ignored.` + ) + } + + fetchActivity.start() + + const CACHE_SYNC_TOKEN = `contentful-sync-token-${sourceId}` + const CACHE_CONTENT_TYPES = `contentful-content-types-${sourceId}` + const CACHE_FOREIGN_REFERENCE_MAP_STATE = `contentful-foreign-reference-map-state-${sourceId}` + + /* + * Subsequent calls of Contentfuls sync API return only changed data. + * + * In some cases, especially when using rich-text fields, there can be data + * missing from referenced entries. This breaks the reference matching. + * + * To workround this, we cache the initial sync data and merge it + * with all data from subsequent syncs. Afterwards the references get + * resolved via the Contentful JS SDK. + */ + const syncToken = + store.getState().status.plugins?.[`gatsby-source-contentful`]?.[ + CACHE_SYNC_TOKEN + ] + + // Actual fetch of data from Contentful + const { + currentSyncData, + tagItems, + defaultLocale, + locales: allLocales, + space, + } = await fetchContent({ syncToken, pluginConfig, reporter }) + + const contentTypeItems = (await cache.get( + CACHE_CONTENT_TYPES + )) as Array + + const locales = allLocales.filter(pluginConfig.get(`localeFilter`)) + reporter.verbose( + `Default locale: ${defaultLocale}. All locales: ${allLocales + .map(({ code }) => code) + .join(`, `)}` + ) + if (allLocales.length !== locales.length) { + reporter.verbose( + `After plugin.options.localeFilter: ${locales + .map(({ code }) => code) + .join(`, `)}` + ) + } + if (locales.length === 0) { + reporter.panic({ + id: CODES.LocalesMissing, + context: { + sourceMessage: `Please check if your localeFilter is configured properly. Locales '${allLocales + .map(item => item.code) + .join(`,`)}' were found but were filtered down to none.`, + }, + }) + } + + // Update syncToken + const nextSyncToken = currentSyncData.nextSyncToken + + actions.setPluginStatus({ + [CACHE_SYNC_TOKEN]: nextSyncToken, + }) + + fetchActivity.end() + + // Process data fetch results and turn them into GraphQL entities + const processingActivity = reporter.activityTimer( + `Contentful: Process data`, + { + parentSpan, + } + ) + processingActivity.start() + + // Array of all existing Contentful entry and asset nodes + const existingNodes = getNodes().filter( + n => + (n.internal.owner === `gatsby-source-contentful` && + n.internal.type.indexOf(`ContentfulContentType`) === 0) || + n.internal.type === `ContentfulAsset` + ) as Array + + // Report existing, new and updated nodes + const nodeCounts = { + newEntry: 0, + newAsset: 0, + updatedEntry: 0, + updatedAsset: 0, + existingEntry: 0, + existingAsset: 0, + deletedEntry: currentSyncData.deletedEntries.length, + deletedAsset: currentSyncData.deletedAssets.length, + } + + existingNodes.forEach(node => nodeCounts[`existing${node.sys.type}`]++) + currentSyncData.entries.forEach(entry => + entry.sys.revision === 1 + ? nodeCounts.newEntry++ + : nodeCounts.updatedEntry++ + ) + currentSyncData.assets.forEach(asset => + asset.sys.revision === 1 + ? nodeCounts.newAsset++ + : nodeCounts.updatedAsset++ + ) + + reporter.info(`Contentful: ${nodeCounts.newEntry} new entries`) + reporter.info(`Contentful: ${nodeCounts.updatedEntry} updated entries`) + reporter.info(`Contentful: ${nodeCounts.deletedEntry} deleted entries`) + reporter.info( + `Contentful: ${nodeCounts.existingEntry / locales.length} cached entries` + ) + reporter.info(`Contentful: ${nodeCounts.newAsset} new assets`) + reporter.info(`Contentful: ${nodeCounts.updatedAsset} updated assets`) + reporter.info( + `Contentful: ${nodeCounts.existingAsset / locales.length} cached assets` + ) + reporter.info(`Contentful: ${nodeCounts.deletedAsset} deleted assets`) + + reporter.verbose(`Building Contentful reference map`) + + const entryList = buildEntryList({ + currentSyncData, + contentTypeItems, + }) + const { assets } = currentSyncData + + // Create map of resolvable ids so we can check links against them while creating + // links. + const resolvable = buildResolvableSet({ + existingNodes, + entryList, + assets, + }) + + // Build foreign reference map before starting to insert any nodes + const previousForeignReferenceMapState = await cache.get( + CACHE_FOREIGN_REFERENCE_MAP_STATE + ) + const useNameForId = pluginConfig.get(`useNameForId`) + + const foreignReferenceMapState = buildForeignReferenceMap({ + contentTypeItems, + entryList, + resolvable, + defaultLocale, + space, + useNameForId, + previousForeignReferenceMapState, + deletedEntries: currentSyncData?.deletedEntries, + }) + await cache.set(CACHE_FOREIGN_REFERENCE_MAP_STATE, foreignReferenceMapState) + const foreignReferenceMap = foreignReferenceMapState.backLinks + + reporter.verbose(`Resolving Contentful references`) + + const newOrUpdatedEntries = new Set() + entryList.forEach(entries => { + entries.forEach(entry => { + newOrUpdatedEntries.add(createRefId(entry)) + }) + }) + + const { deletedEntries, deletedAssets } = currentSyncData + const deletedEntryGatsbyReferenceIds = new Set() + + function deleteContentfulNode(node): void { + const normalizedType = node.sys.type.startsWith(`Deleted`) + ? node.sys.type.substring(`Deleted`.length) + : node.sys.type + + const localizedNodes = locales.map(locale => { + const nodeId = createNodeId( + makeId({ + spaceId: space.sys.id, + id: node.sys.id, + type: normalizedType, + currentLocale: locale.code, + defaultLocale, + }) + ) + // Gather deleted node ids to remove them later on + deletedEntryGatsbyReferenceIds.add(nodeId) + return getNode(nodeId) + }) + + localizedNodes.forEach(node => { + // TODO: nodes of text fields should be deleted as well + if (node) { + deleteNode(node) + } + }) + } + + if (deletedEntries.length || deletedAssets.length) { + const deletionActivity = reporter.activityTimer( + `Contentful: Deleting nodes and assets`, + { + parentSpan, + } + ) + deletionActivity.start() + deletedEntries.forEach(deleteContentfulNode) + deletedAssets.forEach(deleteContentfulNode) + deletionActivity.end() + } + + // Create map of reference fields to properly delete stale references + const referenceFieldMap = new Map() + for (const contentTypeItem of contentTypeItems) { + const referenceFields = contentTypeItem.fields.filter(field => { + if (field.disabled || field.omitted) { + return false + } + + return ( + field.type === `Link` || + (field.type === `Array` && field.items?.type === `Link`) + ) + }) + if (referenceFields.length) { + referenceFieldMap.set( + contentTypeItem.name, + referenceFields.map(field => field.id) + ) + } + } + + // TODO: mirror structure of Contentful GraphQL API, as it prevents field name overlaps + const reverseReferenceFields = contentTypeItems.map(contentTypeItem => + useNameForId + ? contentTypeItem.name.toLowerCase() + : contentTypeItem.sys.id.toLowerCase() + ) + + // Update existing entry nodes that weren't updated but that need reverse links added or removed. + const existingNodesThatNeedReverseLinksUpdateInDatastore = new Set() + existingNodes + .filter( + n => + n.sys.type === `Entry` && + !newOrUpdatedEntries.has(createRefId(n)) && + !deletedEntryGatsbyReferenceIds.has(n.id) + ) + .forEach(n => { + if (n.sys.id && foreignReferenceMap[createRefId(n)]) { + foreignReferenceMap[createRefId(n)].forEach(foreignReference => { + const { name, id, type, spaceId } = foreignReference + + const nodeId = createNodeId( + makeId({ + spaceId, + id, + type, + currentLocale: n.sys.locale, + defaultLocale, + }) + ) + + // Create new reference field when none exists + if (!n[name]) { + existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) + n[name] = [nodeId] + return + } + + // Add non existing references to reference field + const field = n[name] + if (field && Array.isArray(field) && !field.includes(nodeId)) { + existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) + field.push(nodeId) + } + }) + } + + // Remove references to deleted nodes + if ( + n.sys.id && + deletedEntryGatsbyReferenceIds.size && + referenceFieldMap.has(n.sys.contentType) + ) { + const referenceFields = [ + ...referenceFieldMap.get(n.sys.contentType), + ...reverseReferenceFields, + ] + + referenceFields.forEach(name => { + const fieldValue = n[name] + if (Array.isArray(fieldValue)) { + n[name] = fieldValue.filter(referenceId => { + const shouldRemove = + deletedEntryGatsbyReferenceIds.has(referenceId) + if (shouldRemove) { + existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) + } + return !shouldRemove + }) + } else { + if (deletedEntryGatsbyReferenceIds.has(fieldValue)) { + existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) + n[name] = null + } + } + }) + } + }) + + // We need to call `createNode` on nodes we modified reverse links on, + // otherwise changes won't actually persist + if (existingNodesThatNeedReverseLinksUpdateInDatastore.size) { + for (const node of existingNodesThatNeedReverseLinksUpdateInDatastore) { + function addChildrenToList( + node, + nodeList: Array = [node] + ): Array { + for (const childNodeId of node?.children ?? []) { + const childNode = getNode(childNodeId) + if ( + childNode && + childNode.internal.owner === `gatsby-source-contentful` + ) { + nodeList.push(childNode) + addChildrenToList(childNode) + } + } + return nodeList + } + + const nodeAndDescendants = addChildrenToList(node) + for (const nodeToUpdateOriginal of nodeAndDescendants) { + // We should not mutate original node as Gatsby will still + // compare against what's in in-memory weak cache, so we + // clone original node to ensure reference identity is not possible + const nodeToUpdate = _.cloneDeep(nodeToUpdateOriginal) + // We need to remove properties from existing fields + // that are reserved and managed by Gatsby (`.internal.owner`, `.fields`). + // Gatsby automatically will set `.owner` it back + delete nodeToUpdate.internal.owner + // `.fields` need to be created with `createNodeField` action, we can't just re-add them. + // Other plugins (or site itself) will have opportunity to re-generate them in `onCreateNode` lifecycle. + // Contentful content nodes are not using `createNodeField` so it's safe to delete them. + // (Asset nodes DO use `createNodeField` for `localFile` and if we were updating those, then + // we would also need to restore that field ourselves after re-creating a node) + delete nodeToUpdate.fields // plugin adds node field on asset nodes which don't have reverse links + + // We add or modify counter postfix to contentDigest + // to make sure Gatsby treat this as data update + let counter + const [initialContentDigest, counterStr] = + nodeToUpdate.internal.contentDigest.split( + CONTENT_DIGEST_COUNTER_SEPARATOR + ) + + if (counterStr) { + counter = parseInt(counterStr, 10) + } + + if (!counter || isNaN(counter)) { + counter = 1 + } else { + counter++ + } + + nodeToUpdate.internal.contentDigest = `${initialContentDigest}${CONTENT_DIGEST_COUNTER_SEPARATOR}${counter}` + createNode(nodeToUpdate) + } + } + } + + const creationActivity = reporter.activityTimer( + `Contentful: Create nodes`, + { + parentSpan, + } + ) + creationActivity.start() + + // Create nodes for each entry of each content type + for (let i = 0; i < contentTypeItems.length; i++) { + const contentTypeItem = contentTypeItems[i] + + if (entryList[i].length) { + reporter.info( + `Creating ${entryList[i].length} Contentful ${ + useNameForId ? contentTypeItem.name : contentTypeItem.sys.id + } nodes` + ) + } + + // A contentType can hold lots of entries which create nodes + // We wait until all nodes are created and processed until we handle the next one + // TODO add batching in gatsby-core + await Promise.all( + createNodesForContentType({ + contentTypeItem, + entries: entryList[i], + resolvable, + foreignReferenceMap, + defaultLocale, + locales, + space, + useNameForId, + pluginConfig, + ...actions, + ...args, + }) + ) + } + + if (assets.length) { + reporter.info(`Creating ${assets.length} Contentful asset nodes`) + } + + const assetNodes: Array = [] + for (let i = 0; i < assets.length; i++) { + // We wait for each asset to be process until handling the next one. + assetNodes.push( + ...(await Promise.all( + createAssetNodes({ + assetItem: assets[i], + createNode, + createNodeId, + defaultLocale, + locales, + space, + }) + )) + ) + } + + // Create tags entities + if (tagItems.length) { + reporter.info(`Creating ${tagItems.length} Contentful Tag nodes`) + + for (const tag of tagItems) { + await createNode({ + id: createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`), + name: tag.name, + // TODO: update the structure of tags + contentful_id: tag.sys.id, + internal: { + type: `ContentfulTag`, + contentDigest: tag.sys.updatedAt, + }, + }) + } + } + + creationActivity.end() + + // Download asset files to local fs + if (pluginConfig.get(`downloadLocal`)) { + const assetDownloadWorkers = pluginConfig.get(`assetDownloadWorkers`) + await downloadContentfulAssets( + args, + actions, + assetNodes, + assetDownloadWorkers + ) + } + } diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset-key.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset-key.ts new file mode 100644 index 0000000000000..b4690874bc338 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset-key.ts @@ -0,0 +1,4 @@ +export type AssetKey = { + secret: string + policy: string +} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset.ts new file mode 100644 index 0000000000000..c7093233189b8 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset.ts @@ -0,0 +1,50 @@ +import { ContentfulCollection } from './collection' +import { Metadata } from './metadata' +import { EntitySys } from './sys' + +export interface AssetDetails { + size: number + image?: { + width: number + height: number + } +} + +export interface AssetFile { + url: string + details: AssetDetails + fileName: string + contentType: string +} + +export interface AssetFields { + title?: string + description?: string + file?: AssetFile +} + +/** + * @category Entities + */ +export interface Asset { + sys: AssetSys + fields: AssetFields + metadata: Metadata +} + +export type AssetMimeType = + | 'attachment' + | 'plaintext' + | 'image' + | 'audio' + | 'video' + | 'richtext' + | 'presentation' + | 'spreadsheet' + | 'pdfdocument' + | 'archive' + | 'code' + | 'markup' + +export type AssetCollection = ContentfulCollection +export type AssetSys = EntitySys diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/collection.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/collection.ts new file mode 100644 index 0000000000000..50471afacd2cd --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/collection.ts @@ -0,0 +1,6 @@ +export interface ContentfulCollection { + total: number + skip: number + limit: number + items: Array +} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/content-type.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/content-type.ts new file mode 100644 index 0000000000000..424074b38d80e --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/content-type.ts @@ -0,0 +1,86 @@ +import { ContentfulCollection } from './collection' +import { EntryFields } from './entry' +import { SpaceLink, EnvironmentLink } from './link' +import { BaseSys } from './sys' + +export interface ContentTypeSys extends BaseSys { + createdAt: EntryFields.Date + updatedAt: EntryFields.Date + revision: number + space: { sys: SpaceLink } + environment: { sys: EnvironmentLink } +} + +export interface ContentTypeField { + disabled: boolean + id: string + linkType?: string + localized: boolean + name: string + omitted: boolean + required: boolean + type: ContentTypeFieldType + validations: ContentTypeFieldValidation[] + items?: FieldItem + allowedResources?: ContentTypeAllowedResources[] +} + +interface ContentTypeAllowedResources { + type: string + source: string + contentTypes: string[] +} + +export type ContentTypeFieldType = + | 'Symbol' + | 'Text' + | 'Integer' + | 'Number' + | 'Date' + | 'Boolean' + | 'Location' + | 'Link' + | 'Array' + | 'Object' + | 'RichText' + | 'ResourceLink' + +export interface ContentTypeFieldValidation { + unique?: boolean + size?: { + min?: number + max?: number + } + regexp?: { + pattern: string + } + linkMimetypeGroup?: string[] + in?: string[] + linkContentType?: string[] + message?: string + nodes?: { + 'entry-hyperlink'?: ContentTypeFieldValidation[] + 'embedded-entry-block'?: ContentTypeFieldValidation[] + 'embedded-entry-inline'?: ContentTypeFieldValidation[] + } + enabledNodeTypes?: string[] +} + +export interface FieldItem { + type: 'Link' | 'Symbol' | 'ResourceLink' + validations: ContentTypeFieldValidation[] + linkType?: 'Entry' | 'Asset' +} + +/** + * @category Entities + */ +export interface ContentType { + sys: ContentTypeSys + name: string + description: string + displayField: string + fields: Array +} + +export type ContentTypeCollection = ContentfulCollection diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/entry.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/entry.ts new file mode 100644 index 0000000000000..3337101d09576 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/entry.ts @@ -0,0 +1,221 @@ +import { Document as RichTextDocument } from "@contentful/rich-text-types" +import { Asset } from "./asset" +import { ContentfulCollection } from "./collection" +import { ContentTypeLink, EntryLink } from "./link" +import { LocaleCode } from "./locale" +import { Metadata } from "./metadata" +import { FieldsType } from "./query/util" +import { EntitySys } from "./sys" + +export interface EntrySys extends EntitySys { + contentType: { sys: ContentTypeLink } +} + +export declare namespace EntryFields { + type Symbol = string + type Text = string + type Integer = number + type Number = number + type Date = `${number}-${number}-${number}T${number}:${number}:${number}Z` + type Boolean = boolean + + type Location = { + lat: number + lon: number + } + + type Link = Asset | Entry + type Array = symbol[] | Entry[] | Asset[] + type Object = Record> = T + type RichText = RichTextDocument +} + +export type BasicEntryField = + | EntryFields.Symbol + | EntryFields.Text + | EntryFields.Integer + | EntryFields.Number + | EntryFields.Date + | EntryFields.Boolean + | EntryFields.Location + | EntryFields.RichText + | EntryFields.Object + +/** + * @category Entities + */ +export interface Entry { + sys: EntrySys + metadata: Metadata + fields: T +} + +export interface EntryWithAllLocalesAndWithoutLinkResolution< + Fields extends FieldsType, + Locales extends LocaleCode +> { + sys: EntrySys + metadata: Metadata + fields: { + [FieldName in keyof Fields]: { + [LocaleName in Locales]?: Fields[FieldName] extends EntryFields.Link + ? EntryLink + : Fields[FieldName] extends EntryFields.Link[] + ? EntryLink[] + : Fields[FieldName] + } + } +} + +export type EntryWithLinkResolutionAndWithUnresolvableLinks< + Fields extends FieldsType +> = { + sys: EntrySys + metadata: Metadata + fields: { + [FieldName in keyof Fields]: Fields[FieldName] extends EntryFields.Link< + infer LinkedEntryFields + > + ? + | EntryWithLinkResolutionAndWithUnresolvableLinks + | EntryLink + : Fields[FieldName] extends EntryFields.Link[] + ? ( + | EntryWithLinkResolutionAndWithUnresolvableLinks + | EntryLink + )[] + : Fields[FieldName] + } +} + +export type EntryWithAllLocalesAndWithLinkResolutionAndWithUnresolvableLinks< + Fields extends FieldsType, + Locales extends LocaleCode +> = { + sys: EntrySys + metadata: Metadata + fields: { + [FieldName in keyof Fields]: { + [LocaleName in Locales]?: Fields[FieldName] extends EntryFields.Link< + infer LinkedEntryFields + > + ? + | EntryWithAllLocalesAndWithLinkResolutionAndWithUnresolvableLinks< + LinkedEntryFields, + Locales + > + | undefined + : Fields[FieldName] extends Array< + EntryFields.Link + > + ? + | EntryWithAllLocalesAndWithLinkResolutionAndWithUnresolvableLinks< + LinkedEntryFields, + Locales + >[] + | undefined + : Fields[FieldName] + } + } +} + +export type EntryWithLinkResolutionAndWithoutUnresolvableLinks< + Fields extends FieldsType +> = { + sys: EntrySys + metadata: Metadata + fields: { + [FieldName in keyof Fields]: Fields[FieldName] extends EntryFields.Link< + infer LinkedEntryFields + > + ? + | EntryWithLinkResolutionAndWithoutUnresolvableLinks + | undefined + : Fields[FieldName] extends EntryFields.Link[] + ? + | EntryWithLinkResolutionAndWithoutUnresolvableLinks[] + | undefined + : Fields[FieldName] + } +} + +export type EntryWithAllLocalesAndWithLinkResolutionAndWithoutUnresolvableLinks< + Fields extends FieldsType, + Locales extends LocaleCode +> = { + sys: EntrySys + metadata: Metadata + fields: { + [FieldName in keyof Fields]: { + [LocaleName in Locales]?: Fields[FieldName] extends EntryFields.Link< + infer LinkedEntryFields + > + ? + | EntryWithAllLocalesAndWithLinkResolutionAndWithoutUnresolvableLinks< + LinkedEntryFields, + Locales + > + | undefined + : Fields[FieldName] extends EntryFields.Link[] + ? + | EntryWithAllLocalesAndWithLinkResolutionAndWithoutUnresolvableLinks< + LinkedEntryFields, + Locales + >[] + | undefined + : Fields[FieldName] + } + } +} + +export interface AbstractEntryCollection + extends ContentfulCollection { + errors?: Array + includes?: { + Entry?: any[] + Asset?: any[] + } +} + +export type EntryCollection = AbstractEntryCollection> + +export type EntryWithoutLinkResolution = Entry + +export type EntryCollectionWithoutLinkResolution = EntryCollection + +export type EntryCollectionWithLinkResolutionAndWithUnresolvableLinks< + T extends FieldsType +> = AbstractEntryCollection> + +export type EntryCollectionWithAllLocalesAndWithoutLinkResolution< + Fields extends FieldsType, + Locales extends LocaleCode +> = AbstractEntryCollection< + EntryWithAllLocalesAndWithoutLinkResolution +> + +export type EntryCollectionWithAllLocalesAndWithLinkResolutionAndWithUnresolvableLinks< + Fields extends FieldsType, + Locales extends LocaleCode +> = AbstractEntryCollection< + EntryWithAllLocalesAndWithLinkResolutionAndWithUnresolvableLinks< + Fields, + Locales + > +> + +export type EntryCollectionWithLinkResolutionAndWithoutUnresolvableLinks< + Fields extends FieldsType +> = AbstractEntryCollection< + EntryWithLinkResolutionAndWithoutUnresolvableLinks +> + +export type EntryCollectionWithAllLocalesAndWithLinkResolutionAndWithoutUnresolvableLinks< + Fields extends FieldsType, + Locales extends LocaleCode +> = AbstractEntryCollection< + EntryWithAllLocalesAndWithLinkResolutionAndWithoutUnresolvableLinks< + Fields, + Locales + > +> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/index.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/index.ts new file mode 100644 index 0000000000000..a4b25a56b8e57 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/index.ts @@ -0,0 +1,12 @@ +export * from './asset' +export * from './asset-key' +export * from './collection' +export * from './content-type' +export * from './entry' +export * from './link' +export * from './locale' +export * from './metadata' +export * from './query' +export * from './space' +export * from './sync' +export * from './tag' diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/link.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/link.ts new file mode 100644 index 0000000000000..72d52b9581888 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/link.ts @@ -0,0 +1,14 @@ +export type LinkType = 'Space' | 'ContentType' | 'Environment' | 'Entry' | 'Tag' | 'User' + +export interface Link { + type: 'Link' + linkType: T + id: string +} + +export type SpaceLink = Link<'Space'> +export type ContentTypeLink = Link<'ContentType'> +export type EnvironmentLink = Link<'Environment'> +export type EntryLink = Link<'Entry'> +export type TagLink = Link<'Tag'> +export type UserLink = Link<'User'> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/locale.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/locale.ts new file mode 100644 index 0000000000000..1e08526699116 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/locale.ts @@ -0,0 +1,22 @@ +import { ContentfulCollection } from './collection' +import { BaseSys } from './sys' + +export type LocaleCode = string + +export interface LocaleSys extends BaseSys { + type: 'Locale' + version: number +} + +/** + * @category Entities + */ +export interface Locale { + code: string + name: string + default: boolean + fallbackCode: string | null + sys: LocaleSys +} + +export type LocaleCollection = ContentfulCollection diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/metadata.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/metadata.ts new file mode 100644 index 0000000000000..1035de0f84916 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/metadata.ts @@ -0,0 +1,5 @@ +import { TagLink } from './link' + +export type Metadata = { + tags: { sys: TagLink }[] +} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/equality.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/equality.ts new file mode 100644 index 0000000000000..f3c943589b726 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/equality.ts @@ -0,0 +1,29 @@ +import { BasicEntryField, EntryFields } from '../entry' +import { ConditionalQueries } from './util' + +// TODO: Note: Equality and inequality operators are not supported for text fields +// What types do we hav to exclude here? +type SupportedTypes = Exclude | undefined +/** + * @desc equality - search for exact matches + * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/equality-operator} + */ +export type EqualityFilter = ConditionalQueries< + Fields, + SupportedTypes, + Prefix, + '' +> + +/** + * @desc inequality - exclude matching items + * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/inequality-operator} + */ +export type InequalityFilter = ConditionalQueries< + Fields, + SupportedTypes, + Prefix, + '[ne]' +> + +// TODO: it still includes 'Link' fields diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/existence.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/existence.ts new file mode 100644 index 0000000000000..e7b5bef5650f1 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/existence.ts @@ -0,0 +1,17 @@ +import { BasicEntryField } from '../entry' +import { ConditionalFixedQueries } from './util' + +/** + * @name exists + * @desc check for existence + * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/existence} + */ +export type ExistenceFilter = ConditionalFixedQueries< + Fields, + BasicEntryField | undefined, + boolean, + Prefix, + '[exists]' +> + +// TODO: it still includes 'Link' fields diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/index.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/index.ts new file mode 100644 index 0000000000000..d310624b62380 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/index.ts @@ -0,0 +1 @@ +export { type AssetQueries, type EntriesQueries } from './query' diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/location.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/location.ts new file mode 100644 index 0000000000000..f8b6b9d90a56e --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/location.ts @@ -0,0 +1,68 @@ +import { ConditionalPick } from 'type-fest' +import { EntryFields } from '../entry' +import { NonEmpty } from './util' + +type Types = EntryFields.Location + +export type ProximitySearchFilterInput = [number, number] | undefined +export type BoundingBoxSearchFilterInput = [number, number, number, number] | undefined +export type BoundingCircleSearchFilterInput = [number, number, number] | undefined + +type BaseLocationFilter< + Fields, + SupportedTypes, + ValueType, + Prefix extends string, + QueryFilter extends string = '' +> = NonEmpty< + NonNullable<{ + [FieldName in keyof ConditionalPick as `${Prefix}.${string & + FieldName}[${QueryFilter}]`]?: ValueType + }> +> + +/** + * @desc near - location proximity search + * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/location-proximity-search} + */ +export type ProximitySearchFilter = BaseLocationFilter< + Fields, + Types, + ProximitySearchFilterInput, + Prefix, + 'near' +> + +/** + * @desc within - location in a bounding rectangle + * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/locations-in-a-bounding-object} + */ +type BoundingBoxSearchFilter = BaseLocationFilter< + Fields, + Types, + BoundingBoxSearchFilterInput, + Prefix, + 'within' +> +/** + * @desc within - location in a bounding circle + * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/locations-in-a-bounding-object} + */ +type BoundingCircleSearchFilter = BaseLocationFilter< + Fields, + Types, + BoundingCircleSearchFilterInput, + Prefix, + 'within' +> + +/** + * @desc location search + * @see [proximity]{@link ProximitySearchFilter} + * @see [bounding rectangle]{@link BoundingBoxSearchFilter} + * @see [bounding circle]{@link BoundingCircleSearchFilter} + */ +export type LocationSearchFilters = + | ProximitySearchFilter + | BoundingBoxSearchFilter + | BoundingCircleSearchFilter diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/query.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/query.ts new file mode 100644 index 0000000000000..49a7a7624fe85 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/query.ts @@ -0,0 +1,66 @@ +import { AssetMimeType, AssetSys } from '../asset' +import { EntrySys } from '../entry' +import { EqualityFilter, InequalityFilter } from './equality' +import { ExistenceFilter } from './existence' +import { LocationSearchFilters } from './location' +import { RangeFilters } from './range' +import { FullTextSearchFilters } from './search' +import { SelectFilter } from './select' +import { SubsetFilters } from './subset' +import { FieldsType } from './util' + +type FixedPagedOptions = { + skip?: number + limit?: number +} + +type FixedQueryOptions = { + include?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 + locale?: string + query?: string +} + +export type SysQueries = ExistenceFilter & + EqualityFilter & + InequalityFilter & + SubsetFilters & + RangeFilters & + SelectFilter + +export type EntryFieldsQueries = + | (ExistenceFilter & + EqualityFilter & + InequalityFilter & + FullTextSearchFilters & + SelectFilter) + | SubsetFilters + | LocationSearchFilters + | RangeFilters + +// TODO: create-contentful-api complained about non-optional fields when initialized with {} +export type EntriesQueries = Partial< + EntryFieldsQueries & + SysQueries> & + FixedQueryOptions & + FixedPagedOptions & { content_type?: string } & Record & { + resolveLinks?: never + } +> + +export type EntryQueries = Omit + +export type AssetFieldsQueries = + | (ExistenceFilter & + EqualityFilter & + InequalityFilter & + FullTextSearchFilters & + SelectFilter) + | RangeFilters + | SubsetFilters + +export type AssetQueries = Partial< + AssetFieldsQueries & + SysQueries> & + FixedQueryOptions & + FixedPagedOptions & { mimetype_group?: AssetMimeType } & Record +> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/range.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/range.ts new file mode 100644 index 0000000000000..2c5d35b3d9881 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/range.ts @@ -0,0 +1,18 @@ +import { EntryFields } from '../entry' +import { ConditionalQueries, NonEmpty } from './util' + +type RangeFilterTypes = 'lt' | 'lte' | 'gt' | 'gte' + +type SupportedTypes = EntryFields.Date | EntryFields.Number | EntryFields.Integer | undefined + +/** + * @desc Range operators are available that you can apply to date and number fields + * {string} lt: Less than. + * {string} lte: Less than or equal to. + * {string} gt: Greater than. + * {string} gte: Greater than or equal to. + * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/select-operator} + */ +export type RangeFilters = NonEmpty< + ConditionalQueries +> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/search.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/search.ts new file mode 100644 index 0000000000000..edada827dd065 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/search.ts @@ -0,0 +1,17 @@ +import { BasicEntryField, EntryFields } from '../entry' +import { ConditionalFixedQueries } from './util' + +// TODO: should Boolean field type be excluded +type SupportedTypes = Exclude | undefined + +/** + * @desc match - full text search + * @see [documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/full-text-search} + */ +export type FullTextSearchFilters = ConditionalFixedQueries< + Fields, + SupportedTypes, + string, + Prefix, + '[match]' +> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/select.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/select.ts new file mode 100644 index 0000000000000..a818d18636a00 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/select.ts @@ -0,0 +1,13 @@ +import { FieldsType } from './util' + +/** + * @desc select + * @see [documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/select-operator} + */ +export type SelectFilter = { + select?: ( + | `${string}.${string}` + | `${Prefix}.${keyof Fields & string}` + | `${Prefix}.${keyof Fields & string}.${string}` + )[] +} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/subset.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/subset.ts new file mode 100644 index 0000000000000..667b43c1b5956 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/subset.ts @@ -0,0 +1,19 @@ +import { BasicEntryField, EntryFields } from '..' +import { ConditionalQueries, NonEmpty } from './util' + +type SubsetFilterTypes = 'in' | 'nin' +type SupportedTypes = + | Exclude + | undefined + +/** + * @desc inclusion & exclusion + * @see [inclusion documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/inclusion} + * @see [exclusion documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/exclusion} + * @example + * // {'fields.myField', 'singleValue'} + * // {'fields.myField', 'firstValue,secondValue'} + */ +export type SubsetFilters = NonEmpty< + NonNullable> +> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/util.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/util.ts new file mode 100644 index 0000000000000..069b7c0430f85 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/util.ts @@ -0,0 +1,29 @@ +import { ConditionalPick } from 'type-fest' + +export type FieldsType = Record + +export type BaseOrArrayType = T extends Array ? U : T + +export type NonEmpty = T extends Record ? never : T + +//TODO: should we also allow ValueType[] for array types +export type ConditionalFixedQueries< + Fields, + SupportedTypes, + ValueType, + Prefix extends string, + QueryFilter extends string = '' +> = { + [FieldName in keyof ConditionalPick as `${Prefix}.${string & + FieldName}${QueryFilter}`]?: ValueType +} + +export type ConditionalQueries< + Fields, + SupportedTypes, + Prefix extends string, + QueryFilter extends string = '' +> = { + [FieldName in keyof ConditionalPick as `${Prefix}.${string & + FieldName}${QueryFilter}`]?: Fields[FieldName] extends Array ? T[] : Fields[FieldName] +} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/space.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/space.ts new file mode 100644 index 0000000000000..5964bbe737bf4 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/space.ts @@ -0,0 +1,15 @@ +import { Locale } from './locale' +import { BaseSys } from './sys' + +export interface SpaceSys extends BaseSys { + type: 'Space' +} + +/** + * @category Entities + */ +export interface Space { + sys: SpaceSys + name: string + locales: Array> +} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sync.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sync.ts new file mode 100644 index 0000000000000..c3ddb546ab4be --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sync.ts @@ -0,0 +1,10 @@ +import { Asset } from './asset' +import { Entry } from './entry' + +export interface SyncCollection { + entries: Array> + assets: Array + deletedEntries: Array> + deletedAssets: Array + nextSyncToken: string +} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sys.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sys.ts new file mode 100644 index 0000000000000..9da264f19a4d1 --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sys.ts @@ -0,0 +1,16 @@ +import { EntryFields } from './entry' +import { SpaceLink, EnvironmentLink } from './link' + +export interface BaseSys { + type: string + id: string +} + +export interface EntitySys extends BaseSys { + createdAt: EntryFields.Date + updatedAt: EntryFields.Date + revision: number + space: { sys: SpaceLink } + environment: { sys: EnvironmentLink } + locale?: string +} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/tag.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/tag.ts new file mode 100644 index 0000000000000..10be14800e97a --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/tag.ts @@ -0,0 +1,18 @@ +import { EntitySys } from './sys' +import { ContentfulCollection } from './collection' +import { UserLink } from './link' + +export interface TagSys extends Omit { + type: 'Tag' + version: number + visibility: 'public' + createdBy: { sys: UserLink } + updatedBy: { sys: UserLink } +} + +export type Tag = { + name: string + sys: TagSys +} + +export type TagCollection = ContentfulCollection diff --git a/packages/gatsby-source-contentful/src/types/contentful.ts b/packages/gatsby-source-contentful/src/types/contentful.ts new file mode 100644 index 0000000000000..a8550a7823d9a --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/contentful.ts @@ -0,0 +1,128 @@ +import { Node } from "gatsby" +import { ImageFormat } from "gatsby-plugin-image" + +// Generic Types +export interface IContentfulContentType { + id: string + name: string + displayField: string + description: string +} +export interface IContentfulSys { + id: string + type: string + spaceId: string + environmentId: string + contentType: string + firstPublishedAt: string + publishedAt: string + publishedVersion: number + locale: string +} + +export interface ILocalizedField { + [locale: string]: unknown +} + +// export interface IContentfulTag { +// name: string +// contentful_id: string +// id: string +// } + +interface IContentfulMetadata { + tags: Array +} + +interface IContentfulLinkSys { + id: string + linkType: string +} +export interface IContentfulLink { + sys: IContentfulLinkSys +} + +// type UContentfulField = string | boolean | Array + +interface IContentfulEntity extends Node { + id: string + sys: IContentfulSys + metadata: IContentfulMetadata +} + +export type IContentfulEntry = IContentfulEntity +// & { +// [fieldName: string]: UContentfulField +// } + +export interface IContentfulAsset extends IContentfulEntity { + // TODO: this field type might be defined by Gatsby already? + gatsbyImageData: unknown + // TODO: this field type might be defined by Gatsby already? + downloadLocal?: string + title?: string + description?: string + contentType: string + mimeType: string + filename: string + url: string + size: number + width: number + height: number + fields: { localFile?: string } +} + +// Image API +type Enumerate< + N extends number, + Acc extends Array = [] +> = Acc["length"] extends N + ? Acc[number] + : Enumerate + +type IntRange = Exclude< + Enumerate, + Enumerate +> + +export type contentfulImageApiBackgroundColor = `rgb:${string}` + +type contentfulCropFocus = + | "top" + | "top_left" + | "top_right" + | "bottom" + | "bottom_left" + | "bottom_right" + | "right" + | "left" + | "face" + | "faces" + | "center" + +export interface IContentfulImageAPITransformerOptions { + cornerRadius?: number | "max" + width?: number + height?: number + toFormat?: ImageFormat | "auto" | "jpg" | "png" | "webp" | "gif" | "avif" + jpegProgressive?: number + quality?: IntRange<0, 100> + resizingBehavior?: "pad" | "fill" | "scale" | "crop" | "thumb" + cropFocus?: contentfulCropFocus + backgroundColor?: string + placeholder?: "dominantColor" | "blurred" | "tracedSVG" + blurredOptions?: { width?: number; toFormat: ImageFormat } + tracedSVGOptions?: { [key: string]: unknown } +} + +export interface IContentfulImageAPIUrlBuilderOptions { + width?: number + height?: number + toFormat?: ImageFormat | "auto" | "jpg" | "png" | "webp" | "gif" | "avif" + resizingBehavior?: "pad" | "fill" | "scale" | "crop" | "thumb" + background?: contentfulImageApiBackgroundColor + quality?: IntRange<0, 100> + jpegProgressive?: number + cropFocus?: contentfulCropFocus + cornerRadius?: number | "max" +} diff --git a/packages/gatsby-source-contentful/src/types/plugin.ts b/packages/gatsby-source-contentful/src/types/plugin.ts new file mode 100644 index 0000000000000..31f1b37b990ea --- /dev/null +++ b/packages/gatsby-source-contentful/src/types/plugin.ts @@ -0,0 +1,18 @@ +import { PluginOptions } from "gatsby" + +export interface IPluginOptions extends Partial { + accessToken: string + spaceId: string + host?: string + environment?: string + downloadLocal?: boolean + localeFilter?: () => boolean + contentTypeFilter?: () => boolean + pageLimit?: number + useNameForId?: boolean +} + +export interface IProcessedPluginOptions { + get: (key: keyof IPluginOptions) => any + getOriginalPluginOptions: () => IPluginOptions +} diff --git a/packages/gatsby-source-contentful/tsconfig.json b/packages/gatsby-source-contentful/tsconfig.json new file mode 100644 index 0000000000000..185104ef5de84 --- /dev/null +++ b/packages/gatsby-source-contentful/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src"], + "exclude": [ + "node_modules", + "src/__tests__", + "src/__mocks__", + "dist", + "./node.d.ts" + ] +} diff --git a/packages/gatsby/index.d.ts b/packages/gatsby/index.d.ts index 62f1852d6a8da..27b7e314ff6d1 100644 --- a/packages/gatsby/index.d.ts +++ b/packages/gatsby/index.d.ts @@ -1727,7 +1727,7 @@ export interface Node extends NodeInput { parent: string | null children: string[] internal: NodeInput["internal"] & { - owner: string + owner?: string } [key: string]: unknown } From f089bf471a68a2a362ce3d206ee3eb21ecebf805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 17 Mar 2023 11:10:05 +0100 Subject: [PATCH 051/149] fix: align imports to match new export pattern of the plugin --- packages/gatsby-source-contentful/README.md | 6 +++--- .../gatsby-source-contentful/src/gatsby-plugin-image.ts | 2 +- packages/gatsby-source-contentful/src/index.ts | 1 + packages/gatsby-transformer-sqip/src/extend-node-type.js | 9 +++------ 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/gatsby-source-contentful/README.md b/packages/gatsby-source-contentful/README.md index e64052dd6666b..a7b25645ef976 100644 --- a/packages/gatsby-source-contentful/README.md +++ b/packages/gatsby-source-contentful/README.md @@ -393,7 +393,7 @@ With `useContentfulImage` and the URL to the image on the Contentful Image API y ```js import { GatsbyImage } from "gatsby-plugin-image" import * as React from "react" -import { useContentfulImage } from "gatsby-source-contentful/hooks" +import { useContentfulImage } from "gatsby-source-contentful" const MyComponent = () => { const dynamicImage = useContentfulImage({ @@ -507,7 +507,7 @@ query pageQuery($id: String!) { ```jsx import { BLOCKS, MARKS } from "@contentful/rich-text-types" -import { renderRichText } from "gatsby-source-contentful/rich-text" +import { renderRichText } from "gatsby-source-contentful" const Bold = ({ children }) => {children} const Text = ({ children }) =>

{children}

@@ -545,7 +545,7 @@ function BlogPostTemplate({ data }) { **Import** ```js -import { renderRichText } from "gatsby-source-contentful/rich-text" +import { renderRichText } from "gatsby-source-contentful" ``` **GraphQL** diff --git a/packages/gatsby-source-contentful/src/gatsby-plugin-image.ts b/packages/gatsby-source-contentful/src/gatsby-plugin-image.ts index 319cf58bde38d..5f30b9aee8fc4 100644 --- a/packages/gatsby-source-contentful/src/gatsby-plugin-image.ts +++ b/packages/gatsby-source-contentful/src/gatsby-plugin-image.ts @@ -265,7 +265,7 @@ export async function resolveGatsbyImageData( const { generateImageData } = await import(`gatsby-plugin-image`) const { getPluginOptions, doMergeDefaults } = await import( - `gatsby-plugin-sharp/plugin-options` + `gatsby-plugin-sharp/plugin-options.js` ) const sharpOptions = getPluginOptions() diff --git a/packages/gatsby-source-contentful/src/index.ts b/packages/gatsby-source-contentful/src/index.ts index 85b67a5e99023..cc861147de119 100644 --- a/packages/gatsby-source-contentful/src/index.ts +++ b/packages/gatsby-source-contentful/src/index.ts @@ -2,6 +2,7 @@ import * as importedSchemes from "./schemes" export * from "./hooks" export * from "./rich-text" export * from "./types/contentful" +export * from "./image-helpers" export type { IPluginOptions, IProcessedPluginOptions } from "./types/plugin" export const schemes = importedSchemes diff --git a/packages/gatsby-transformer-sqip/src/extend-node-type.js b/packages/gatsby-transformer-sqip/src/extend-node-type.js index 5e5fbf36454aa..d968a6477d13e 100644 --- a/packages/gatsby-transformer-sqip/src/extend-node-type.js +++ b/packages/gatsby-transformer-sqip/src/extend-node-type.js @@ -135,9 +135,11 @@ async function sqipSharp({ type, cache, getNodeAndSavePathDependency, store }) { } } -async function sqipContentful({ type, cache, store }) { +async function sqipContentful({ cache, store }) { const { schemes: { ImageResizingBehavior, ImageCropFocusType }, + createUrl, + mimeTypeExtensions, } = require(`gatsby-source-contentful`) const program = store.getState().program @@ -189,11 +191,6 @@ async function sqipContentful({ type, cache, store }) { }, }, async resolve(asset, fieldArgs) { - const { - createUrl, - mimeTypeExtensions, - } = require(`gatsby-source-contentful/image-helpers`) - const { mimeType, url: imgUrl, filename } = asset if (!mimeType.includes(`image/`)) { From 55cdb648ed78eb9bbb85b66b935eacfa191c01d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 17 Mar 2023 11:10:32 +0100 Subject: [PATCH 052/149] fix: remove duplication of https in image generation hook --- packages/gatsby-source-contentful/src/__tests__/hooks.js | 2 +- packages/gatsby-source-contentful/src/hooks.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/hooks.js b/packages/gatsby-source-contentful/src/__tests__/hooks.js index 1f184dbe1d6bf..f3d325231c389 100644 --- a/packages/gatsby-source-contentful/src/__tests__/hooks.js +++ b/packages/gatsby-source-contentful/src/__tests__/hooks.js @@ -10,7 +10,7 @@ jest.mock(`react`, () => { describe(`useContentfulImage`, () => { const consoleWarnSpy = jest.spyOn(console, `warn`) - const image = { url: `//images.ctfassets.net/foo/bar/baz/image.jpg` } + const image = { url: `https://images.ctfassets.net/foo/bar/baz/image.jpg` } beforeEach(() => { consoleWarnSpy.mockClear() diff --git a/packages/gatsby-source-contentful/src/hooks.ts b/packages/gatsby-source-contentful/src/hooks.ts index 9866f324affa2..939500bfc4b7b 100644 --- a/packages/gatsby-source-contentful/src/hooks.ts +++ b/packages/gatsby-source-contentful/src/hooks.ts @@ -24,7 +24,7 @@ export function useContentfulImage({ sourceHeight: image.height, backgroundColor: undefined, urlBuilder: ({ baseUrl, width, height, options, format }) => - createUrl(`https:${baseUrl}`, { + createUrl(baseUrl, { ...options, height, width, From 0848e820fa295649651406212f07c0d51c80d527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 30 Mar 2023 11:02:21 +0200 Subject: [PATCH 053/149] fix: small performance improvements and cleanups --- packages/gatsby-source-contentful/src/normalize.ts | 12 ++---------- .../gatsby-source-contentful/src/source-nodes.ts | 5 +++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index ce8fef219bea8..494c68a7b7afa 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -8,7 +8,6 @@ import type { IContentfulAsset, IContentfulEntry, IContentfulLink, - IContentfulSys, ILocalizedField, } from "./types/contentful" import type { @@ -338,18 +337,14 @@ export const buildForeignReferenceMap = ({ return foreignReferenceMapState } -interface IContentfulTextNode extends Node { - sys: Partial -} - function prepareTextNode( id: string, node: IContentfulEntry, _key: string, text: unknown -): IContentfulTextNode { +): Node { const str = _.isString(text) ? text : `` - const textNode: IContentfulTextNode = { + const textNode: Node = { id, parent: node.id, raw: str, @@ -361,9 +356,6 @@ function prepareTextNode( contentDigest: node.sys.publishedAt, }, children: [], - sys: { - type: `TextNode`, - }, } return textNode diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index 24743e73c985a..47b289f57f08a 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -353,8 +353,9 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = !deletedEntryGatsbyReferenceIds.has(n.id) ) .forEach(n => { - if (n.sys.id && foreignReferenceMap[createRefId(n)]) { - foreignReferenceMap[createRefId(n)].forEach(foreignReference => { + const refId = createRefId(n) + if (n.sys.id && foreignReferenceMap[refId]) { + foreignReferenceMap[refId].forEach(foreignReference => { const { name, id, type, spaceId } = foreignReference const nodeId = createNodeId( From edc9039ec94de21444a548071e3dde7a7ed087db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 3 Apr 2023 11:44:35 +0200 Subject: [PATCH 054/149] build: update yarn.lock --- yarn.lock | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index 9352f8a4957d3..37af7ab10d6ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11268,7 +11268,7 @@ fs-extra@^10.0.0, fs-extra@^10.1.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^11.1.1: +fs-extra@^11.1.0, fs-extra@^11.1.1: version "11.1.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== @@ -11372,6 +11372,69 @@ gather-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" +gatsby-core-utils@^4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/gatsby-core-utils/-/gatsby-core-utils-4.8.0.tgz#b9baac9f9434d0c789e470e8caf8003edf91d7ac" + integrity sha512-C2uOZBd9j6AYIyiB+DdxRtbQgAa3kMDRsKR5eCwALp0Bkg3W5I/YiXhSF7zQxVckaqNXzXvmedJESKCJNIvO7w== + dependencies: + "@babel/runtime" "^7.20.13" + ci-info "2.0.0" + configstore "^5.0.1" + fastq "^1.13.0" + file-type "^16.5.3" + fs-extra "^11.1.0" + got "^11.8.5" + hash-wasm "^4.9.0" + import-from "^4.0.0" + lmdb "2.5.3" + lock "^1.1.0" + node-object-hash "^2.3.10" + proper-lockfile "^4.1.2" + resolve-from "^5.0.0" + tmp "^0.2.1" + xdg-basedir "^4.0.0" + +gatsby-plugin-sharp@^5.8.0-next.0: + version "5.8.1" + resolved "https://registry.yarnpkg.com/gatsby-plugin-sharp/-/gatsby-plugin-sharp-5.8.1.tgz#148d155dd16310b6ca18340c4b856eda525ed2ea" + integrity sha512-HPRINGFWjBahYW0lMzo68sKYKArUXKl0yqhCtzsK51Km/R8Mpw+uL+7q4r/sQJ8VQ8HZUNH+ik+2rbzR1nKe2Q== + dependencies: + "@babel/runtime" "^7.20.13" + async "^3.2.4" + bluebird "^3.7.2" + debug "^4.3.4" + filenamify "^4.3.0" + fs-extra "^11.1.0" + gatsby-core-utils "^4.8.0" + gatsby-plugin-utils "^4.8.0" + lodash "^4.17.21" + probe-image-size "^7.2.3" + semver "^7.3.8" + sharp "^0.31.3" + +gatsby-plugin-utils@^4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/gatsby-plugin-utils/-/gatsby-plugin-utils-4.8.0.tgz#d88824bec89cef1192246358a9b1c0171f7f4432" + integrity sha512-zRdqP2t2W+j8ujHYtXFYnXKUS1JkjjM59Lh39bl6u9opgAByfK3jab1NpmxFQ220TAmqHrDSwOqiiB7GyuJQ/w== + dependencies: + "@babel/runtime" "^7.20.13" + fastq "^1.13.0" + fs-extra "^11.1.0" + gatsby-core-utils "^4.8.0" + gatsby-sharp "^1.8.0" + graphql-compose "^9.0.10" + import-from "^4.0.0" + joi "^17.7.0" + mime "^3.0.0" + +gatsby-sharp@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/gatsby-sharp/-/gatsby-sharp-1.8.0.tgz#2f8016a560383d06b0dd25f7c0ce61477b922631" + integrity sha512-68y/KH5Z7aU8EGgATTgZsr7qYnE/M34oPoDDA1seXWx3gvE0yXctuXNrRKGS89M94/aEu2WotKoX3Gjb2JQzVQ== + dependencies: + "@types/sharp" "^0.31.1" + sharp "^0.31.3" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -23088,7 +23151,7 @@ typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@^4.1.3: +typescript@^4.1.3, typescript@^4.9.4: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== From f44d61683618061833e7cde6c5e07d8bec6d49a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 3 Apr 2023 11:57:16 +0200 Subject: [PATCH 055/149] build: fix dependency version --- packages/gatsby-source-contentful/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/package.json b/packages/gatsby-source-contentful/package.json index 2d3604102d0fc..a0016d686c704 100644 --- a/packages/gatsby-source-contentful/package.json +++ b/packages/gatsby-source-contentful/package.json @@ -35,7 +35,7 @@ "babel-preset-gatsby-package": "^3.9.0-next.0", "cross-env": "^7.0.3", "del-cli": "^5.0.0", - "gatsby-plugin-sharp": "^5.8.0-next.0", + "gatsby-plugin-sharp": "^5.9.0-next.0", "nock": "^13.3.0", "typescript": "^4.9.4" }, From 64c0fb7f8df66e48684a36f87f97972ad67ed0bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 3 Apr 2023 12:05:32 +0200 Subject: [PATCH 056/149] build: undirty lock file --- yarn.lock | 65 +------------------------------------------------------ 1 file changed, 1 insertion(+), 64 deletions(-) diff --git a/yarn.lock b/yarn.lock index 37af7ab10d6ce..cbb024f936cc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11268,7 +11268,7 @@ fs-extra@^10.0.0, fs-extra@^10.1.0: jsonfile "^6.0.1" universalify "^2.0.0" -fs-extra@^11.1.0, fs-extra@^11.1.1: +fs-extra@^11.1.1: version "11.1.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.1.1.tgz#da69f7c39f3b002378b0954bb6ae7efdc0876e2d" integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== @@ -11372,69 +11372,6 @@ gather-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" -gatsby-core-utils@^4.8.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/gatsby-core-utils/-/gatsby-core-utils-4.8.0.tgz#b9baac9f9434d0c789e470e8caf8003edf91d7ac" - integrity sha512-C2uOZBd9j6AYIyiB+DdxRtbQgAa3kMDRsKR5eCwALp0Bkg3W5I/YiXhSF7zQxVckaqNXzXvmedJESKCJNIvO7w== - dependencies: - "@babel/runtime" "^7.20.13" - ci-info "2.0.0" - configstore "^5.0.1" - fastq "^1.13.0" - file-type "^16.5.3" - fs-extra "^11.1.0" - got "^11.8.5" - hash-wasm "^4.9.0" - import-from "^4.0.0" - lmdb "2.5.3" - lock "^1.1.0" - node-object-hash "^2.3.10" - proper-lockfile "^4.1.2" - resolve-from "^5.0.0" - tmp "^0.2.1" - xdg-basedir "^4.0.0" - -gatsby-plugin-sharp@^5.8.0-next.0: - version "5.8.1" - resolved "https://registry.yarnpkg.com/gatsby-plugin-sharp/-/gatsby-plugin-sharp-5.8.1.tgz#148d155dd16310b6ca18340c4b856eda525ed2ea" - integrity sha512-HPRINGFWjBahYW0lMzo68sKYKArUXKl0yqhCtzsK51Km/R8Mpw+uL+7q4r/sQJ8VQ8HZUNH+ik+2rbzR1nKe2Q== - dependencies: - "@babel/runtime" "^7.20.13" - async "^3.2.4" - bluebird "^3.7.2" - debug "^4.3.4" - filenamify "^4.3.0" - fs-extra "^11.1.0" - gatsby-core-utils "^4.8.0" - gatsby-plugin-utils "^4.8.0" - lodash "^4.17.21" - probe-image-size "^7.2.3" - semver "^7.3.8" - sharp "^0.31.3" - -gatsby-plugin-utils@^4.8.0: - version "4.8.0" - resolved "https://registry.yarnpkg.com/gatsby-plugin-utils/-/gatsby-plugin-utils-4.8.0.tgz#d88824bec89cef1192246358a9b1c0171f7f4432" - integrity sha512-zRdqP2t2W+j8ujHYtXFYnXKUS1JkjjM59Lh39bl6u9opgAByfK3jab1NpmxFQ220TAmqHrDSwOqiiB7GyuJQ/w== - dependencies: - "@babel/runtime" "^7.20.13" - fastq "^1.13.0" - fs-extra "^11.1.0" - gatsby-core-utils "^4.8.0" - gatsby-sharp "^1.8.0" - graphql-compose "^9.0.10" - import-from "^4.0.0" - joi "^17.7.0" - mime "^3.0.0" - -gatsby-sharp@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/gatsby-sharp/-/gatsby-sharp-1.8.0.tgz#2f8016a560383d06b0dd25f7c0ce61477b922631" - integrity sha512-68y/KH5Z7aU8EGgATTgZsr7qYnE/M34oPoDDA1seXWx3gvE0yXctuXNrRKGS89M94/aEu2WotKoX3Gjb2JQzVQ== - dependencies: - "@types/sharp" "^0.31.1" - sharp "^0.31.3" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" From c8edd7e3ba6e62147b2cd51822a349fae15a001d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 3 Apr 2023 13:52:08 +0200 Subject: [PATCH 057/149] test: align content type names in rich text e2e test --- e2e-tests/contentful/snapshots.js | 2 +- e2e-tests/contentful/src/pages/index.js | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index c5af11be15ee3..430ed87a4a88c 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -28,7 +28,7 @@ module.exports = { }, "rich-text": { "rich-text: All Features": { - "1": "
\n

Rich Text: All Features

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n
\"\"\n\n
\n
\n \n \n \"\"\n\n \n \n
\n

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
  7. \n

    [Inline-ContentfulText]\n Text: Short\n :\n The quick brown fox jumps over the lazy dog.

    \n
  8. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n

[ContentfulLocation] Lat:\n 52.51627\n , Long:\n 13.3777

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
" + "1": "
\n

Rich Text: All Features

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n
\"\"\n\n
\n
\n \n \n \"\"\n\n \n \n
\n

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
  7. \n

    [Inline-ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

    \n
  8. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n

[ContentfulContentTypeLocation] Lat:\n 52.51627\n , Long:\n 13.3777

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
" }, "rich-text: Basic": { "1": "
\n

Rich Text: Basic

\n

The European languages

\n

are members of the same family. Their separate existence is a myth. For:

\n
    \n
  • \n

    science

    \n
  • \n
  • \n

    music

    \n
  • \n
  • \n

    sport

    \n
  • \n
  • \n

    etc

    \n
  • \n
\n

Europe uses the same vocabulary.

\n
\n

The languages only differ in:

\n
    \n
  1. \n

    their grammar

    \n
  2. \n
  3. \n

    their pronunciation

    \n
  4. \n
  5. \n

    their most common words

    \n
  6. \n
\n

Everyone realizes why a new common language would be desirable: one could\n refuse to pay expensive translators.

\n

{\n \"userId\": 1,\n \"id\": 1,\n \"title\": \"delectus aut autem\",\n \"completed\": false\n }

\n

To achieve this, it would be necessary to have uniform grammar,\n pronunciation and more common words.

\n
\n

If several languages coalesce, the grammar of the resulting language is\n more simple and regular than that of the individual languages.

\n
\n

The new common language will be more simple and regular than the existing\n European languages. It will be as simple as Occidental; in fact, it will be\n

\n
\n
" diff --git a/e2e-tests/contentful/src/pages/index.js b/e2e-tests/contentful/src/pages/index.js index 8a097000793b4..f216240c58633 100644 --- a/e2e-tests/contentful/src/pages/index.js +++ b/e2e-tests/contentful/src/pages/index.js @@ -54,6 +54,12 @@ const IndexPage = () => ( /tags +

Gatsby

+
    +
  • + SSR +
  • +
) From 689c035b079062aa6af29f69ddb96f558a2192dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 12 Apr 2023 10:39:31 +0200 Subject: [PATCH 058/149] fix: move typing for enableStatefulSourceNodes into Actions --- packages/gatsby/index.d.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/gatsby/index.d.ts b/packages/gatsby/index.d.ts index 4d2d5ebe0f24e..37f6bc1c0f2d3 100644 --- a/packages/gatsby/index.d.ts +++ b/packages/gatsby/index.d.ts @@ -434,11 +434,6 @@ export interface GatsbyNode< calllback: PluginCallback ): void | Promise - /** - * Marks the source plugin that called this function as stateful. Gatsby will not check for stale nodes for any plugin that calls this. - */ - enableStatefulSourceNodes?(this: void, plugin?: ActionPlugin) - /** * Called when a new node is created. Plugins wishing to extend or * transform nodes created by other plugins should implement this API. @@ -1476,6 +1471,11 @@ export interface Actions { plugin?: ActionPlugin, traceId?: string ): void + + /** + * Marks the source plugin that called this function as stateful. Gatsby will not check for stale nodes for any plugin that calls this. + */ + enableStatefulSourceNodes?(this: void, plugin?: ActionPlugin) } export interface Store { From a45b3a7be20f894ec431ea4fef88d8d6ee58056e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 12 Apr 2023 10:46:12 +0200 Subject: [PATCH 059/149] metadata is now a reserved field name as well --- packages/gatsby-source-contentful/src/config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gatsby-source-contentful/src/config.ts b/packages/gatsby-source-contentful/src/config.ts index 2ed916b36e560..9f26a987ead34 100644 --- a/packages/gatsby-source-contentful/src/config.ts +++ b/packages/gatsby-source-contentful/src/config.ts @@ -9,4 +9,5 @@ export const restrictedNodeFields = [ `internal`, // Contentful Common resource attributes: https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/common-resource-attributes `sys`, + `metadata`, ] From 51d7d0bbb6afd7c5b0217b7f84fe3b788ed7cbfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 12 Apr 2023 14:16:00 +0200 Subject: [PATCH 060/149] refactor: reverse references via linkedFrom field (#37811) * refactor: reverse references are now stored in a linkedFrom field, like in CTF GraphQL API * linkedFrom is now also a reserved field * add jest config to allow tests to pass whithin the plugin folder * test: update snapshots for linkedFrom change --- e2e-tests/contentful/snapshots.js | 18 +++--- .../contentful/src/pages/content-reference.js | 17 +++++- .../gatsby-source-contentful/jest.config.js | 10 +++ .../create-schema-customization.js.snap | 53 ++++++++++++++++ .../src/__tests__/gatsby-node.js | 34 ++++++++--- .../src/__tests__/normalize.js | 23 ++++--- .../gatsby-source-contentful/src/config.ts | 1 + .../src/create-schema-customization.ts | 42 ++++++++++++- .../gatsby-source-contentful/src/normalize.ts | 13 ++-- .../src/source-nodes.ts | 61 ++++++++++--------- .../src/types/contentful.ts | 9 +-- 11 files changed, 213 insertions(+), 68 deletions(-) create mode 100644 packages/gatsby-source-contentful/jest.config.js diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index 430ed87a4a88c..58abb43a966a8 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -1,29 +1,29 @@ module.exports = { - "__version": "9.7.0", + "__version": "12.9.0", "content-reference": { "content-reference-many-2nd-level-loop": { - "1": "
\n

Content Reference: Many (2nd level loop)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" + "1": "
\n

Content Reference: Many (2nd level loop)\n (\n 4R29nQaAkgJFB5pkruYW9i\n )

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": null\n}
\n
" }, "content-reference-many-loop-a-greater-b": { - "1": "
\n

Content Reference: Many (Loop A -> B)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop B -> A)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop A ->\n B)\n ]

\n
" + "1": "
\n

Content Reference: Many (Loop A -> B)\n (\n 4NHKxzHnMwSjjMLSdUrcFo\n )

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop B -> A)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop A ->\n B)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"7IrXy5KcEujLUsaWVJAK69\"\n      }\n    }\n  ]\n}
\n
" }, "content-reference-many-loop-b-greater-a": { - "1": "
\n

Content Reference: Many (Loop B -> A)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop A -> B)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop B ->\n A)\n ]

\n
" + "1": "
\n

Content Reference: Many (Loop B -> A)\n (\n 7IrXy5KcEujLUsaWVJAK69\n )

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop A -> B)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop B ->\n A)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"4NHKxzHnMwSjjMLSdUrcFo\"\n      }\n    }\n  ]\n}
\n
" }, "content-reference-many-self-reference": { - "1": "
\n

Content Reference: Many (Self Reference)

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Self Reference)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Self\n Reference)\n ]

\n
" + "1": "
\n

Content Reference: Many (Self Reference)\n (\n 50SBswk2hZU4G4ITVIPuuU\n )

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Self Reference)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Self\n Reference)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"50SBswk2hZU4G4ITVIPuuU\"\n      }\n    }\n  ]\n}
\n
" }, "content-reference-one": { - "1": "
\n

Content Reference: One

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n
" + "1": "
\n

Content Reference: One\n (\n 77UBlVUq3oeVidhtAhrByt\n )

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": null\n}
\n
" }, "content-reference-one-loop-a-greater-b": { - "1": "
\n

Content Reference: One (Loop A -> B)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n
" + "1": "
\n

Content Reference: One (Loop A -> B)\n (\n LkOtAXoxqqX8Y9cRRPjRb\n )

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"4R29nQaAkgJFB5pkruYW9i\"\n      }\n    },\n    {\n      \"sys\": {\n        \"id\": \"37m4vschoGYmwUMlgxAa74\"\n      }\n    }\n  ]\n}
\n
" }, "content-reference-one-loop-b-greater-a": { - "1": "
\n

Content Reference: One (Loop B -> A)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" + "1": "
\n

Content Reference: One (Loop B -> A)\n (\n 37m4vschoGYmwUMlgxAa74\n )

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"LkOtAXoxqqX8Y9cRRPjRb\"\n      }\n    }\n  ]\n}
\n
" }, "content-reference-one-self-reference": { - "1": "
\n

Content Reference: One (Self Reference)

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Self Reference)\n : [\n Content Reference: One (Self Reference)\n ]

\n
" + "1": "
\n

Content Reference: One (Self Reference)\n (\n 3Lq0a8ymtbGueurkbuM2xN\n )

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Self Reference)\n : [\n Content Reference: One (Self Reference)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"3Lq0a8ymtbGueurkbuM2xN\"\n      }\n    }\n  ]\n}
\n
" } }, "rich-text": { diff --git a/e2e-tests/contentful/src/pages/content-reference.js b/e2e-tests/contentful/src/pages/content-reference.js index d6eafd04803c8..129c9406bff02 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(({ sys: { id }, title, one, many }) => { + {defaultEntries.map(({ sys: { id }, title, one, many, linkedFrom }) => { const slug = slugify(title, { strict: true, lower: true }) let content = null @@ -38,8 +38,14 @@ const ContentReferencePage = ({ data }) => { return (
-

{title}

+

+ {title} ({id}) +

{content} +

Linked from:

+
+              {JSON.stringify(linkedFrom, null, 2)}
+            
) })} @@ -107,6 +113,13 @@ export const pageQuery = graphql` sys { id } + linkedFrom { + ContentfulContentTypeContentReference { + sys { + id + } + } + } one { __typename ... on ContentfulEntry { diff --git a/packages/gatsby-source-contentful/jest.config.js b/packages/gatsby-source-contentful/jest.config.js new file mode 100644 index 0000000000000..afbc44fb86c08 --- /dev/null +++ b/packages/gatsby-source-contentful/jest.config.js @@ -0,0 +1,10 @@ +/** @type {import('jest').Config} */ +const config = { + snapshotFormat: { + escapeString: true, + printBasicPrototype: true, + }, + snapshotSerializers: [`jest-serializer-path`], +} + +module.exports = config \ No newline at end of file diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index cd817828c9349..a491346b0619d 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -114,6 +114,43 @@ Array [ "name": "ContentfulMetadata", }, ], + Array [ + Object { + "extensions": Object { + "dontInfer": Object {}, + }, + "fields": Object { + "ContentfulContentTypeContentReference": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "ContentfulContentTypeContentReference", + }, + }, + "type": "[ContentfulContentTypeContentReference]", + }, + "ContentfulContentTypeMediaReference": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "ContentfulContentTypeMediaReference", + }, + }, + "type": "[ContentfulContentTypeMediaReference]", + }, + "ContentfulContentTypeValidatedContentReference": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "ContentfulContentTypeValidatedContentReference", + }, + }, + "type": "[ContentfulContentTypeValidatedContentReference]", + }, + }, + "name": "ContentfulLinkedFrom", + }, + ], Array [ Object { "extensions": Object { @@ -223,6 +260,9 @@ Ignored if layout = FLUID.", "id": Object { "type": "ID!", }, + "linkedFrom": Object { + "type": "ContentfulLinkedFrom", + }, "metadata": Object { "type": "ContentfulMetadata!", }, @@ -371,6 +411,7 @@ Ignored if layout = FLUID.", "integerLocalized": Object { "type": "Int", }, + "linkedFrom": "ContentfulLinkedFrom", "metadata": Object { "type": "ContentfulMetadata!", }, @@ -398,6 +439,7 @@ Ignored if layout = FLUID.", "id": Object { "type": "ID!", }, + "linkedFrom": "ContentfulLinkedFrom", "longLocalized": Object { "extensions": Object { "link": Object { @@ -464,6 +506,7 @@ Ignored if layout = FLUID.", "id": Object { "type": "ID!", }, + "linkedFrom": "ContentfulLinkedFrom", "many": Object { "extensions": Object { "link": Object { @@ -533,6 +576,7 @@ Ignored if layout = FLUID.", "id": Object { "type": "ID!", }, + "linkedFrom": "ContentfulLinkedFrom", "metadata": Object { "type": "ContentfulMetadata!", }, @@ -584,6 +628,7 @@ Ignored if layout = FLUID.", "id": Object { "type": "ID!", }, + "linkedFrom": "ContentfulLinkedFrom", "metadata": Object { "type": "ContentfulMetadata!", }, @@ -611,6 +656,7 @@ Ignored if layout = FLUID.", "id": Object { "type": "ID!", }, + "linkedFrom": "ContentfulLinkedFrom", "location": Object { "type": "ContentfulLocation", }, @@ -650,6 +696,7 @@ Ignored if layout = FLUID.", "jsonLocalized": Object { "type": "JSON", }, + "linkedFrom": "ContentfulLinkedFrom", "metadata": Object { "type": "ContentfulMetadata!", }, @@ -677,6 +724,7 @@ Ignored if layout = FLUID.", "id": Object { "type": "ID!", }, + "linkedFrom": "ContentfulLinkedFrom", "metadata": Object { "type": "ContentfulMetadata!", }, @@ -713,6 +761,7 @@ Ignored if layout = FLUID.", "id": Object { "type": "ID!", }, + "linkedFrom": "ContentfulLinkedFrom", "many": Object { "extensions": Object { "link": Object { @@ -776,6 +825,7 @@ Ignored if layout = FLUID.", "id": Object { "type": "ID!", }, + "linkedFrom": "ContentfulLinkedFrom", "metadata": Object { "type": "ContentfulMetadata!", }, @@ -878,6 +928,9 @@ Array [ "id": Object { "type": "ID!", }, + "linkedFrom": Object { + "type": "ContentfulLinkedFrom", + }, "metadata": Object { "type": "ContentfulMetadata!", }, diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 290296ed39c6a..d465cd3537c01 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -7,7 +7,7 @@ import { onPreInit, } from "../gatsby-node" import { fetchContent, fetchContentTypes } from "../fetch" -import { makeId } from "../normalize" +import { makeId, makeTypeName } from "../normalize" import startersBlogFixture from "../__fixtures__/starter-blog-data" import richTextFixture from "../__fixtures__/rich-text-data" @@ -278,13 +278,23 @@ describe(`gatsby-node`, () => { }) // update all matchedObjets with our backreferences - for (const [nodeId, value] of references) { - const matchedObject = { - ...nodeMap.get(nodeId), - ...value, + if (references.size) { + for (const [nodeId, value] of references) { + const matchedObject = nodeMap.get(nodeId) + if (matchedObject) { + matchedObject.linkedFrom = {} + + for (const k of Object.keys(value)) { + const typeName = makeTypeName(k) + if (matchedObject[`linkedFrom`][typeName]) { + matchedObject[`linkedFrom`][typeName].push(...value[k]) + } else { + matchedObject[`linkedFrom`][typeName] = value[k] + } + } + nodeMap.set(nodeId, matchedObject) + } } - - nodeMap.set(nodeId, matchedObject) } // match all entry nodes @@ -906,7 +916,7 @@ describe(`gatsby-node`, () => { ) }) - expect(actions.createNode).toHaveBeenCalledTimes(48) + expect(actions.createNode).toHaveBeenCalledTimes(46) expect(actions.deleteNode).toHaveBeenCalledTimes(2) expect(actions.touchNode).toHaveBeenCalledTimes(0) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` @@ -1301,7 +1311,9 @@ describe(`gatsby-node`, () => { expect(blogPostNodes.length).toEqual(1) expect(blogCategoryNodes.length).toEqual(1) - expect(blogCategoryNodes[0][`blog post`]).toEqual([blogPostNodes[0].id]) + expect( + blogCategoryNodes[0][`linkedFrom`][`ContentfulContentTypeBlogPost`] + ).toEqual([blogPostNodes[0].id]) expect(blogCategoryNodes[0][`title`]).toEqual(`CMS`) await simulateGatsbyBuild() @@ -1315,7 +1327,9 @@ describe(`gatsby-node`, () => { expect(blogPostNodes.length).toEqual(1) expect(blogCategoryNodes.length).toEqual(1) - expect(blogCategoryNodes[0][`blog post`]).toEqual([blogPostNodes[0].id]) + expect( + blogCategoryNodes[0][`linkedFrom`][`ContentfulContentTypeBlogPost`] + ).toEqual([blogPostNodes[0].id]) expect(blogCategoryNodes[0][`title`]).toEqual(`CMS edit #1`) }) }) diff --git a/packages/gatsby-source-contentful/src/__tests__/normalize.js b/packages/gatsby-source-contentful/src/__tests__/normalize.js index 37d372d1ed04c..0c86ae2c957c8 100644 --- a/packages/gatsby-source-contentful/src/__tests__/normalize.js +++ b/packages/gatsby-source-contentful/src/__tests__/normalize.js @@ -39,7 +39,12 @@ function countCreatedNodeTypesFromMock(mock) { return nodeTypeCounts } +const createNodeId = jest.fn(id => id) + describe(`generic`, () => { + beforeEach(() => { + createNodeId.mockClear() + }) it(`builds entry list`, () => { const entryList = buildEntryList({ currentSyncData, @@ -101,6 +106,7 @@ describe(`generic`, () => { useNameForId: true, previousForeignReferenceMapState: undefined, deletedEntries: [], + createNodeId, }) const referenceKeys = Object.keys(foreignReferenceMapState.backLinks) const expectedReferenceKeys = [ @@ -160,17 +166,18 @@ describe(`Process contentful data (by name)`, () => { useNameForId: true, previousForeignReferenceMapState: undefined, deletedEntries: [], + createNodeId, }) expect( foreignReferenceMapState.backLinks[`24DPGBDeGEaYy8ms4Y8QMQ___Entry`][0] .name - ).toBe(`product`) + ).toBe(`ContentfulContentTypeProduct`) expect( foreignReferenceMapState.backLinks[`2Y8LhXLnYAYqKCGEWG4EKI___Asset`][0] .name - ).toBe(`brand`) + ).toBe(`ContentfulContentTypeBrand`) }) it(`creates nodes for each entry`, () => { @@ -193,10 +200,10 @@ describe(`Process contentful data (by name)`, () => { useNameForId: true, previousForeignReferenceMapState: undefined, deletedEntries: [], + createNodeId, }) const createNode = jest.fn() - const createNodeId = jest.fn(id => id) const getNode = jest.fn(() => undefined) // All nodes are new contentTypeItems.forEach((contentTypeItem, i) => { createNodesForContentType({ @@ -244,7 +251,6 @@ describe(`Process contentful data (by name)`, () => { it(`creates nodes for each asset`, () => { const createNode = jest.fn(() => Promise.resolve()) - const createNodeId = jest.fn(id => id) const assets = currentSyncData.assets assets.forEach(assetItem => { createAssetNodes({ @@ -284,10 +290,10 @@ describe(`Process existing mutated nodes in warm build`, () => { useNameForId: true, previousForeignReferenceMapState: undefined, deletedEntries: [], + createNodeId, }) const createNode = jest.fn() - const createNodeId = jest.fn(id => id) let doReturn = true const getNode = jest.fn(id => { if (doReturn) { @@ -369,17 +375,18 @@ describe(`Process contentful data (by id)`, () => { useNameForId: false, previousForeignReferenceMapState: undefined, deletedEntries: [], + createNodeId, }) expect( foreignReferenceMapState.backLinks[`24DPGBDeGEaYy8ms4Y8QMQ___Entry`][0] .name - ).toBe(`2pqfxujwe8qsykum0u6w8m`) + ).toBe(`ContentfulContentType2PqfXuJwE8QSyKuM0U6W8M`) expect( foreignReferenceMapState.backLinks[`2Y8LhXLnYAYqKCGEWG4EKI___Asset`][0] .name - ).toBe(`sfztzbsum8coewygeuyes`) + ).toBe(`ContentfulContentTypeSFzTZbSuM8CoEwygeUYes`) }) it(`creates nodes for each entry`, () => { @@ -400,10 +407,10 @@ describe(`Process contentful data (by id)`, () => { useNameForId: false, previousForeignReferenceMapState: undefined, deletedEntries: [], + createNodeId, }) const createNode = jest.fn() - const createNodeId = jest.fn(id => id) const getNode = jest.fn(() => undefined) // All nodes are new contentTypeItems.forEach((contentTypeItem, i) => { createNodesForContentType({ diff --git a/packages/gatsby-source-contentful/src/config.ts b/packages/gatsby-source-contentful/src/config.ts index 9f26a987ead34..12309659ba558 100644 --- a/packages/gatsby-source-contentful/src/config.ts +++ b/packages/gatsby-source-contentful/src/config.ts @@ -10,4 +10,5 @@ export const restrictedNodeFields = [ // Contentful Common resource attributes: https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/common-resource-attributes `sys`, `metadata`, + `linkedFrom`, ] diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index 1461206af6ecc..72118e7268d51 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -289,7 +289,9 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] const pluginConfig = createPluginConfig(pluginOptions as IPluginOptions) - let contentTypeItems + const useNameForId = pluginConfig.get(`useNameForId`) + + let contentTypeItems: Array if (process.env.GATSBY_WORKER_ID) { const sourceId = `${pluginConfig.get(`spaceId`)}-${pluginConfig.get( `environment` @@ -323,6 +325,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] id: { type: `ID!` }, sys: { type: `ContentfulSys!` }, metadata: { type: `ContentfulMetadata!` }, + linkedFrom: { type: `ContentfulLinkedFrom` }, }, interfaces: [`ContentfulEntity`, `Node`], }) @@ -398,6 +401,39 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] `gatsby-plugin-image/graphql-utils.js` ) + const reverseLinkFields = {} + + contentTypeItems.forEach(contentType => { + let contentTypeItemId + if (useNameForId) { + contentTypeItemId = makeTypeName(contentType.name) + } else { + contentTypeItemId = makeTypeName(contentType.sys.id) + } + + if ( + contentType.fields.some( + field => field.linkType || field.items?.linkType + ) + ) { + reverseLinkFields[contentTypeItemId] = { + type: `[${contentTypeItemId}]`, + extensions: { + link: { by: `id`, from: contentTypeItemId }, + }, + } + } + }) + + const linkedFromName = `ContentfulLinkedFrom` + createTypes( + schema.buildObjectType({ + name: linkedFromName, + fields: reverseLinkFields, + extensions: { dontInfer: {} }, + }) + ) + // Assets const gatsbyImageData = getGatsbyImageFieldConfig( async ( @@ -461,6 +497,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] size: { type: `Int` }, width: { type: `Int` }, height: { type: `Int` }, + linkedFrom: { type: linkedFromName }, }, interfaces: [`ContentfulEntity`, `Node`], extensions: { dontInfer: {} }, @@ -632,7 +669,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] fields[field.id] = translateFieldType(field, schema, createTypes) }) - const type = pluginConfig.get(`useNameForId`) + const type = useNameForId ? contentTypeItem.name : contentTypeItem.sys.id @@ -644,6 +681,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] sys: { type: `ContentfulSys!` }, metadata: { type: `ContentfulMetadata!` }, ...fields, + linkedFrom: linkedFromName, }, interfaces: [`ContentfulEntity`, `ContentfulEntry`, `Node`], extensions: { dontInfer: {} }, diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index 494c68a7b7afa..31a8698a43010 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -236,6 +236,7 @@ export const buildForeignReferenceMap = ({ deletedEntries: Array< EntryWithAllLocalesAndWithoutLinkResolution > + createNodeId }): IForeignReferenceMapState => { const foreignReferenceMapState: IForeignReferenceMapState = previousForeignReferenceMapState || { @@ -256,9 +257,9 @@ export const buildForeignReferenceMap = ({ // but sometimes a base62 uuid generated by Contentful, hence the option) let contentTypeItemId if (useNameForId) { - contentTypeItemId = contentTypeItem.name.toLowerCase() + contentTypeItemId = makeTypeName(contentTypeItem.name) } else { - contentTypeItemId = contentTypeItem.sys.id.toLowerCase() + contentTypeItemId = makeTypeName(contentTypeItem.sys.id) } entryList[i].forEach(entryItem => { @@ -607,15 +608,16 @@ export const createNodesForContentType = ({ // Add reverse linkages if there are any for this node const foreignReferences = foreignReferenceMap[createRefId(entryItem)] + const linkedFromFields = {} if (foreignReferences) { foreignReferences.forEach(foreignReference => { - const existingReference = entryItemFields[foreignReference.name] + const existingReference = linkedFromFields[foreignReference.name] if (existingReference) { // If the existing reference is a string, we're dealing with a // many-to-one reference which has already been recorded, so we can // skip it. However, if it is an array, add it: if (Array.isArray(existingReference)) { - entryItemFields[foreignReference.name].push( + linkedFromFields[foreignReference.name].push( mId( foreignReference.spaceId, foreignReference.id, @@ -626,7 +628,7 @@ export const createNodesForContentType = ({ } else { // If there is one foreign reference, there can be many. // Best to be safe and put it in an array to start with. - entryItemFields[foreignReference.name] = [ + linkedFromFields[foreignReference.name] = [ mId( foreignReference.spaceId, foreignReference.id, @@ -665,6 +667,7 @@ export const createNodesForContentType = ({ createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) ), }, + linkedFrom: linkedFromFields, } contentfulCreateNodeManifest({ diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index 928c15678fa45..fac62a07650ec 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -269,6 +269,7 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = useNameForId, previousForeignReferenceMapState, deletedEntries: currentSyncData?.deletedEntries, + createNodeId, }) await cache.set(CACHE_FOREIGN_REFERENCE_MAP_STATE, foreignReferenceMapState) const foreignReferenceMap = foreignReferenceMapState.backLinks @@ -349,13 +350,33 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = // TODO: mirror structure of Contentful GraphQL API, as it prevents field name overlaps const reverseReferenceFields = contentTypeItems.map(contentTypeItem => - useNameForId - ? contentTypeItem.name.toLowerCase() - : contentTypeItem.sys.id.toLowerCase() + createNodeId( + useNameForId + ? contentTypeItem.name.toLowerCase() + : contentTypeItem.sys.id.toLowerCase() + ) ) // Update existing entry nodes that weren't updated but that need reverse links added or removed. const existingNodesThatNeedReverseLinksUpdateInDatastore = new Set() + + const removeReferencesToDeletedNodes = (fieldValue, node): void => { + if (Array.isArray(fieldValue)) { + fieldValue = fieldValue.filter(referenceId => { + const shouldRemove = deletedEntryGatsbyReferenceIds.has(referenceId) + if (shouldRemove) { + existingNodesThatNeedReverseLinksUpdateInDatastore.add(node) + } + return !shouldRemove + }) + } else { + if (deletedEntryGatsbyReferenceIds.has(fieldValue)) { + existingNodesThatNeedReverseLinksUpdateInDatastore.add(node) + fieldValue = null + } + } + } + existingNodes .filter( n => @@ -380,14 +401,14 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = ) // Create new reference field when none exists - if (!n[name]) { + if (!n.linkedFrom[name]) { existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) - n[name] = [nodeId] + n.linkedFrom[name] = [nodeId] return } // Add non existing references to reference field - const field = n[name] + const field = n.linkedFrom[name] if (field && Array.isArray(field) && !field.includes(nodeId)) { existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) field.push(nodeId) @@ -401,28 +422,12 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = deletedEntryGatsbyReferenceIds.size && referenceFieldMap.has(n.sys.contentType) ) { - const referenceFields = [ - ...referenceFieldMap.get(n.sys.contentType), - ...reverseReferenceFields, - ] - - referenceFields.forEach(name => { - const fieldValue = n[name] - if (Array.isArray(fieldValue)) { - n[name] = fieldValue.filter(referenceId => { - const shouldRemove = - deletedEntryGatsbyReferenceIds.has(referenceId) - if (shouldRemove) { - existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) - } - return !shouldRemove - }) - } else { - if (deletedEntryGatsbyReferenceIds.has(fieldValue)) { - existingNodesThatNeedReverseLinksUpdateInDatastore.add(n) - n[name] = null - } - } + referenceFieldMap.get(n.sys.contentType).forEach(name => { + removeReferencesToDeletedNodes(n[name], n) + }) + + reverseReferenceFields.forEach(name => { + removeReferencesToDeletedNodes(n.linkedFrom[name], n) }) } }) diff --git a/packages/gatsby-source-contentful/src/types/contentful.ts b/packages/gatsby-source-contentful/src/types/contentful.ts index a8550a7823d9a..f6b1127e17690 100644 --- a/packages/gatsby-source-contentful/src/types/contentful.ts +++ b/packages/gatsby-source-contentful/src/types/contentful.ts @@ -50,10 +50,11 @@ interface IContentfulEntity extends Node { metadata: IContentfulMetadata } -export type IContentfulEntry = IContentfulEntity -// & { -// [fieldName: string]: UContentfulField -// } +export interface IContentfulEntry extends IContentfulEntity { + linkedFrom: { + [referenceId: string]: Array + } +} export interface IContentfulAsset extends IContentfulEntity { // TODO: this field type might be defined by Gatsby already? From fed60ee96de0aaa4ca894020c2b90dddb13dcbb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 2 May 2023 16:53:17 +0200 Subject: [PATCH 061/149] fix: caching with back references should work out fine now --- .../src/__tests__/gatsby-node.js | 4 +- .../src/backreferences.ts | 147 ++++++++++++++++++ .../gatsby-source-contentful/src/normalize.ts | 49 +++--- .../src/source-nodes.ts | 3 +- 4 files changed, 178 insertions(+), 25 deletions(-) create mode 100644 packages/gatsby-source-contentful/src/backreferences.ts diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index bf22917eba53c..638e2b178f390 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -643,7 +643,7 @@ describe(`gatsby-node`, () => { `) }) - it.only(`should add a new blogpost and update linkedNodes`, async () => { + it(`should add a new blogpost and update linkedNodes`, async () => { const locales = [`en-US`, `nl`] fetchContent @@ -1020,7 +1020,7 @@ describe(`gatsby-node`, () => { locales ) - expect(actions.createNode).toHaveBeenCalledTimes(48) + expect(actions.createNode).toHaveBeenCalledTimes(46) expect(actions.deleteNode).toHaveBeenCalledTimes(2) expect(actions.touchNode).toHaveBeenCalledTimes(0) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts new file mode 100644 index 0000000000000..b8636d535b6a8 --- /dev/null +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -0,0 +1,147 @@ +// @ts-check +import { hasFeature } from "gatsby-plugin-utils/index" +import { getDataStore } from "gatsby/dist/datastore" +import { untilNextEventLoopTick } from "./utils" +import { IContentfulEntry } from "./types/contentful" + +// Array of all existing Contentful nodes. Make it global and incrementally update it because it's hella slow to recreate this on every data update for large sites. +export const existingNodes = new Map() + +let allNodesLoopCount = 0 + +// "is" === object so it can be overridden by tests +export const is = { + firstSourceNodesCallOfCurrentNodeProcess: true, +} + +interface IMemoryNodesCountsBySysType { + Asset: number + Entry: number +} + +const memoryNodeCountsBySysType: IMemoryNodesCountsBySysType = { + Asset: 0, + Entry: 0, +} + +export async function getExistingCachedNodes({ actions, getNode }): Promise<{ + existingNodes: Map + memoryNodeCountsBySysType: IMemoryNodesCountsBySysType +}> { + const { touchNode } = actions + + const needToTouchNodes = + !hasFeature(`stateful-source-nodes`) && + is.firstSourceNodesCallOfCurrentNodeProcess + + if (existingNodes.size === 0) { + memoryNodeCountsBySysType.Asset = 0 + memoryNodeCountsBySysType.Entry = 0 + + const dataStore = getDataStore() + const allNodeTypeNames = Array.from(dataStore.getTypes()) + + for (const typeName of allNodeTypeNames) { + const typeNodes = dataStore.iterateNodesByType(typeName) + + const firstNodeOfType = Array.from(typeNodes.slice(0, 1))[0] + + if ( + !firstNodeOfType || + firstNodeOfType.internal.owner !== `gatsby-source-contentful` + ) { + continue + } + + for (const node of typeNodes) { + if (needToTouchNodes) { + touchNode(node) + + if (node?.fields?.includes(`localFile`)) { + // Prevent GraphQL type inference from crashing on this property + const fullNode = getNode(node.id) + const localFileNode = getNode(fullNode.fields.localFile) + touchNode(localFileNode) + } + } + + if (++allNodesLoopCount % 5000 === 0) { + // dont block the event loop + await untilNextEventLoopTick() + } + + addNodeToExistingNodesCache(node as unknown as IContentfulEntry) + } + + // dont block the event loop + await untilNextEventLoopTick() + } + } + + is.firstSourceNodesCallOfCurrentNodeProcess = false + + return { + existingNodes, + memoryNodeCountsBySysType, + } +} + +// store only the fields we need to compare to reduce memory usage. if a node is updated we'll use getNode to grab the whole node before updating it +export function addNodeToExistingNodesCache(node: IContentfulEntry): void { + if (!node.sys?.type) { + return + } + + if ( + node.sys.type in memoryNodeCountsBySysType && + !existingNodes.has(node.id) + ) { + memoryNodeCountsBySysType[node.sys.type] ||= 0 + memoryNodeCountsBySysType[node.sys.type]++ + } + + const cacheNode = { + id: node.id, + sys: { + id: node.sys.id, + type: node.sys.type, + locale: node.sys.locale, + spaceId: node.sys.spaceId, + }, + node_locale: node.node_locale, + children: node.children, + internal: { + owner: `gatsby-source-contentful`, + }, + linkedFrom: node.linkedFrom, + __memcache: true, + } + + for (const key of Object.keys(node)) { + if (key.endsWith(`___NODE`)) { + cacheNode[key] = node[key] + } + } + + existingNodes.set(node.id, cacheNode as unknown as IContentfulEntry) +} + +export function removeNodeFromExistingNodesCache(node): void { + if (node.internal.type === `ContentfulTag`) { + return + } + + if ( + node.sys.type in memoryNodeCountsBySysType && + existingNodes.has(node.id) + ) { + memoryNodeCountsBySysType[node.sys.type] ||= 0 + memoryNodeCountsBySysType[node.sys.type]-- + + if (memoryNodeCountsBySysType[node.sys.type] < 0) { + memoryNodeCountsBySysType[node.sys.type] = 0 + } + } + + existingNodes.delete(node.id) +} diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index f03400db55a1c..efc65e1f7fdd8 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -442,7 +442,9 @@ function contentfulCreateNodeManifest({ } } -interface ICreateNodesForContentTypeArgs extends Actions, SourceNodesArgs { +interface ICreateNodesForContentTypeArgs + extends Omit, + SourceNodesArgs { contentTypeItem: ContentType entries: Array< EntryWithAllLocalesAndWithoutLinkResolution @@ -454,6 +456,7 @@ interface ICreateNodesForContentTypeArgs extends Actions, SourceNodesArgs { space: Space useNameForId: boolean pluginConfig: IProcessedPluginOptions + createNode: (node: Node) => void | Promise } function makeQueuedCreateNode({ nodeCount, createNode }): { @@ -637,13 +640,19 @@ export const createNodesForContentType = ({ Object.keys(entryItemFields).forEach(entryItemFieldKey => { if (entryItemFields[entryItemFieldKey]) { const entryItemFieldValue = entryItemFields[entryItemFieldKey] - if (Array.isArray(entryItemFieldValue)) { - console.log( - `found link field`, - entryItemFieldKey, - entryItemFieldValue - ) - if (entryItemFieldValue[0]?.sys?.type === `Link`) { + + // TODO:: how expensive is this? + const field = contentTypeItem.fields.find( + f => + (restrictedNodeFields.includes(f.id) + ? `${conflictFieldPrefix}${f.id}` + : f.id) === entryItemFieldKey + ) + if ( + field?.type === `Link` || + (field?.type === `Array` && field.items?.type === `Link`) + ) { + if (Array.isArray(entryItemFieldValue)) { // Check if there are any values in entryItemFieldValue to prevent // creating an empty node field in case when original key field value // is empty due to links to missing entities @@ -656,24 +665,20 @@ export const createNodesForContentType = ({ v.sys.linkType || v.sys.type ) }) + if (resolvableEntryItemFieldValue.length !== 0) { entryItemFields[entryItemFieldKey] = resolvableEntryItemFieldValue } - } - } else if (entryItemFieldValue?.sys?.type === `Link`) { - console.log( - `found array link field`, - entryItemFieldKey, - entryItemFieldValue - ) - if (resolvable.has(createLinkRefId(entryItemFieldValue))) { - entryItemFields[entryItemFieldKey] = mId( - space.sys.id, - entryItemFieldValue.sys.id, - entryItemFieldValue.sys.linkType || - entryItemFieldValue.sys.type - ) + } else { + if (resolvable.has(createLinkRefId(entryItemFieldValue))) { + entryItemFields[entryItemFieldKey] = mId( + space.sys.id, + entryItemFieldValue.sys.id, + entryItemFieldValue.sys.linkType || + entryItemFieldValue.sys.type + ) + } } } } diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index 65d07849b507c..22eada868fb41 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -527,7 +527,7 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = } } - createNode(newNode) + await createNode(newNode) if (existingNodesLoopCount++ % 2000 === 0) { // dont block the event loop @@ -577,6 +577,7 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = pluginConfig, ...actions, ...args, + createNode, }) // allow node to garbage collect these items if it needs to From 37ba20c04ac7ce2cf6ffd1667c257a21802a83a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 2 May 2023 16:55:00 +0200 Subject: [PATCH 062/149] build: update yarn.lock --- yarn.lock | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/yarn.lock b/yarn.lock index 0aa04207c473b..95eafad60369e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11548,6 +11548,69 @@ gather-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" +gatsby-core-utils@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/gatsby-core-utils/-/gatsby-core-utils-4.9.0.tgz#1134d9a119f49b90d3b5107210dfdd17a4231463" + integrity sha512-diCAmlr42YQpSKapD374JVF+ojDXTHxnrNoS907jNGgT4J35t2az9GsEQFgrEou3Td5TLuUl/8yJM2Hpwn4gyg== + dependencies: + "@babel/runtime" "^7.20.13" + ci-info "2.0.0" + configstore "^5.0.1" + fastq "^1.15.0" + file-type "^16.5.4" + fs-extra "^11.1.1" + got "^11.8.6" + hash-wasm "^4.9.0" + import-from "^4.0.0" + lmdb "2.5.3" + lock "^1.1.0" + node-object-hash "^2.3.10" + proper-lockfile "^4.1.2" + resolve-from "^5.0.0" + tmp "^0.2.1" + xdg-basedir "^4.0.0" + +gatsby-plugin-sharp@^5.9.0-next.0: + version "5.9.0" + resolved "https://registry.yarnpkg.com/gatsby-plugin-sharp/-/gatsby-plugin-sharp-5.9.0.tgz#72b97bb27a4d4c936621a0c7f1eda77f4715b4da" + integrity sha512-RXiRmuAwRZf7uqzoqBoG+7qbWWXCuf359Td+yKBLC7M+ktsfw9FMfivS6PpY6v+XmEztO8so1n+Sx+nOU5FScw== + dependencies: + "@babel/runtime" "^7.20.13" + async "^3.2.4" + bluebird "^3.7.2" + debug "^4.3.4" + filenamify "^4.3.0" + fs-extra "^11.1.1" + gatsby-core-utils "^4.9.0" + gatsby-plugin-utils "^4.9.0" + lodash "^4.17.21" + probe-image-size "^7.2.3" + semver "^7.3.8" + sharp "^0.31.3" + +gatsby-plugin-utils@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/gatsby-plugin-utils/-/gatsby-plugin-utils-4.9.0.tgz#d0b7c72964ef6c4dee7d81f4e6217e5e677c7352" + integrity sha512-JGd6FNjoj2ceb4eCw7xzIELlPwSBxGGkJpy+iQTnLT32aPT0vidjGmiytXpNDvktLrxpmuTDPVfMJTjopu+y2A== + dependencies: + "@babel/runtime" "^7.20.13" + fastq "^1.15.0" + fs-extra "^11.1.1" + gatsby-core-utils "^4.9.0" + gatsby-sharp "^1.9.0" + graphql-compose "^9.0.10" + import-from "^4.0.0" + joi "^17.9.1" + mime "^3.0.0" + +gatsby-sharp@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/gatsby-sharp/-/gatsby-sharp-1.9.0.tgz#96f085dba28dcae44f67b99cf503757c63bac1e3" + integrity sha512-R5uahYWf1vWZJs97n6DMC+yMByWcDFZiYCkghdS4qvFz4MsbtS/jzU8qz/mcgwxQW3G10VlFa2XuxTsKGYdzzQ== + dependencies: + "@types/sharp" "^0.31.1" + sharp "^0.31.3" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" From 47273d27f0ac7fe3c42fce26808f9f4b2a268625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 2 May 2023 18:20:47 +0200 Subject: [PATCH 063/149] build: update yarn.lock --- .../gatsby-source-contentful/package.json | 2 +- yarn.lock | 63 ------------------- 2 files changed, 1 insertion(+), 64 deletions(-) diff --git a/packages/gatsby-source-contentful/package.json b/packages/gatsby-source-contentful/package.json index 9672d5bd9468c..6e29fb7aac493 100644 --- a/packages/gatsby-source-contentful/package.json +++ b/packages/gatsby-source-contentful/package.json @@ -35,7 +35,7 @@ "babel-preset-gatsby-package": "^3.10.0-next.0", "cross-env": "^7.0.3", "del-cli": "^5.0.0", - "gatsby-plugin-sharp": "^5.9.0-next.0", + "gatsby-plugin-sharp": "^5.10.0-next.0", "nock": "^13.3.0", "typescript": "^4.9.4" }, diff --git a/yarn.lock b/yarn.lock index 95eafad60369e..0aa04207c473b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11548,69 +11548,6 @@ gather-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" -gatsby-core-utils@^4.9.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/gatsby-core-utils/-/gatsby-core-utils-4.9.0.tgz#1134d9a119f49b90d3b5107210dfdd17a4231463" - integrity sha512-diCAmlr42YQpSKapD374JVF+ojDXTHxnrNoS907jNGgT4J35t2az9GsEQFgrEou3Td5TLuUl/8yJM2Hpwn4gyg== - dependencies: - "@babel/runtime" "^7.20.13" - ci-info "2.0.0" - configstore "^5.0.1" - fastq "^1.15.0" - file-type "^16.5.4" - fs-extra "^11.1.1" - got "^11.8.6" - hash-wasm "^4.9.0" - import-from "^4.0.0" - lmdb "2.5.3" - lock "^1.1.0" - node-object-hash "^2.3.10" - proper-lockfile "^4.1.2" - resolve-from "^5.0.0" - tmp "^0.2.1" - xdg-basedir "^4.0.0" - -gatsby-plugin-sharp@^5.9.0-next.0: - version "5.9.0" - resolved "https://registry.yarnpkg.com/gatsby-plugin-sharp/-/gatsby-plugin-sharp-5.9.0.tgz#72b97bb27a4d4c936621a0c7f1eda77f4715b4da" - integrity sha512-RXiRmuAwRZf7uqzoqBoG+7qbWWXCuf359Td+yKBLC7M+ktsfw9FMfivS6PpY6v+XmEztO8so1n+Sx+nOU5FScw== - dependencies: - "@babel/runtime" "^7.20.13" - async "^3.2.4" - bluebird "^3.7.2" - debug "^4.3.4" - filenamify "^4.3.0" - fs-extra "^11.1.1" - gatsby-core-utils "^4.9.0" - gatsby-plugin-utils "^4.9.0" - lodash "^4.17.21" - probe-image-size "^7.2.3" - semver "^7.3.8" - sharp "^0.31.3" - -gatsby-plugin-utils@^4.9.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/gatsby-plugin-utils/-/gatsby-plugin-utils-4.9.0.tgz#d0b7c72964ef6c4dee7d81f4e6217e5e677c7352" - integrity sha512-JGd6FNjoj2ceb4eCw7xzIELlPwSBxGGkJpy+iQTnLT32aPT0vidjGmiytXpNDvktLrxpmuTDPVfMJTjopu+y2A== - dependencies: - "@babel/runtime" "^7.20.13" - fastq "^1.15.0" - fs-extra "^11.1.1" - gatsby-core-utils "^4.9.0" - gatsby-sharp "^1.9.0" - graphql-compose "^9.0.10" - import-from "^4.0.0" - joi "^17.9.1" - mime "^3.0.0" - -gatsby-sharp@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/gatsby-sharp/-/gatsby-sharp-1.9.0.tgz#96f085dba28dcae44f67b99cf503757c63bac1e3" - integrity sha512-R5uahYWf1vWZJs97n6DMC+yMByWcDFZiYCkghdS4qvFz4MsbtS/jzU8qz/mcgwxQW3G10VlFa2XuxTsKGYdzzQ== - dependencies: - "@types/sharp" "^0.31.1" - sharp "^0.31.3" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" From f00f2ab56af3a59e3beece7f97f447cd65b23b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 8 May 2023 10:51:56 +0200 Subject: [PATCH 064/149] make typegen happy for now --- packages/gatsby-source-contentful/src/source-nodes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index 22eada868fb41..a599e54f18489 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -63,7 +63,7 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = const pluginConfig = createPluginConfig(pluginOptions as IPluginOptions) // wrap createNode so we can cache them in memory for faster lookups when finding backreferences - const createNode = (node: Node): void | Promise => { + const createNode = (node): void | Promise => { addNodeToExistingNodesCache(node) return originalCreateNode(node) From 272097bae3fd37048960f52aaf7c2cb4c0c2cf5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 8 May 2023 10:59:40 +0200 Subject: [PATCH 065/149] tests: make sure temp images are not comitted to git --- packages/gatsby-source-contentful/src/__tests__/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/gatsby-source-contentful/src/__tests__/.gitignore diff --git a/packages/gatsby-source-contentful/src/__tests__/.gitignore b/packages/gatsby-source-contentful/src/__tests__/.gitignore new file mode 100644 index 0000000000000..c94e3760cc971 --- /dev/null +++ b/packages/gatsby-source-contentful/src/__tests__/.gitignore @@ -0,0 +1 @@ +*/*.png \ No newline at end of file From 73dcd5a551b0383e129481b0020467444eb976c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 8 May 2023 11:04:25 +0200 Subject: [PATCH 066/149] refactor: rewrite typeing to make CI happy --- packages/gatsby-source-contentful/src/backreferences.ts | 4 ++-- packages/gatsby-source-contentful/src/source-nodes.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index b8636d535b6a8..0246e3a9a59e8 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -1,6 +1,6 @@ // @ts-check import { hasFeature } from "gatsby-plugin-utils/index" -import { getDataStore } from "gatsby/dist/datastore" +import { getDataStore } from "gatsby/src/datastore" import { untilNextEventLoopTick } from "./utils" import { IContentfulEntry } from "./types/contentful" @@ -126,7 +126,7 @@ export function addNodeToExistingNodesCache(node: IContentfulEntry): void { existingNodes.set(node.id, cacheNode as unknown as IContentfulEntry) } -export function removeNodeFromExistingNodesCache(node): void { +export function removeNodeFromExistingNodesCache(node: IContentfulEntry): void { if (node.internal.type === `ContentfulTag`) { return } diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index a599e54f18489..1b76ce27eaca2 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -69,7 +69,7 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = return originalCreateNode(node) } - const deleteNode = (node: Node): void | Promise => { + const deleteNode = (node): void | Promise => { removeNodeFromExistingNodesCache(node) return originalDeleteNode(node) From 4b1fed2f6b395162c40d8bc117a5ebcbd9babacc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 8 May 2023 11:37:10 +0200 Subject: [PATCH 067/149] fix import --- packages/gatsby-source-contentful/src/backreferences.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index 0246e3a9a59e8..dd899dfc3e43b 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -1,6 +1,6 @@ // @ts-check import { hasFeature } from "gatsby-plugin-utils/index" -import { getDataStore } from "gatsby/src/datastore" +import { getDataStore } from "gatsby/dist/datastore" import { untilNextEventLoopTick } from "./utils" import { IContentfulEntry } from "./types/contentful" From bae4fa2a4d8472e9e04c3a6870d0cd50769ff8fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 8 May 2023 12:27:02 +0200 Subject: [PATCH 068/149] load data store async as its not available on initial typegen --- packages/gatsby-source-contentful/src/backreferences.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index dd899dfc3e43b..82961d92b9df7 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -1,6 +1,5 @@ // @ts-check import { hasFeature } from "gatsby-plugin-utils/index" -import { getDataStore } from "gatsby/dist/datastore" import { untilNextEventLoopTick } from "./utils" import { IContentfulEntry } from "./types/contentful" @@ -30,6 +29,8 @@ export async function getExistingCachedNodes({ actions, getNode }): Promise<{ }> { const { touchNode } = actions + const { getDataStore } = await import(`gatsby/dist/datastore`) + const needToTouchNodes = !hasFeature(`stateful-source-nodes`) && is.firstSourceNodesCallOfCurrentNodeProcess From 895973626aef8a8045909b361626998552d6d71c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 8 May 2023 13:43:36 +0200 Subject: [PATCH 069/149] tell typegen to hush for the not yet type exposed getDataStore --- packages/gatsby-source-contentful/src/backreferences.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index 82961d92b9df7..32f6e3f950e1a 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -3,6 +3,9 @@ import { hasFeature } from "gatsby-plugin-utils/index" import { untilNextEventLoopTick } from "./utils" import { IContentfulEntry } from "./types/contentful" +// @ts-ignore this is not available (yet) in typegen phase +import { getDataStore } from "gatsby/dist/datastore" + // Array of all existing Contentful nodes. Make it global and incrementally update it because it's hella slow to recreate this on every data update for large sites. export const existingNodes = new Map() @@ -29,8 +32,6 @@ export async function getExistingCachedNodes({ actions, getNode }): Promise<{ }> { const { touchNode } = actions - const { getDataStore } = await import(`gatsby/dist/datastore`) - const needToTouchNodes = !hasFeature(`stateful-source-nodes`) && is.firstSourceNodesCallOfCurrentNodeProcess @@ -45,7 +46,7 @@ export async function getExistingCachedNodes({ actions, getNode }): Promise<{ for (const typeName of allNodeTypeNames) { const typeNodes = dataStore.iterateNodesByType(typeName) - const firstNodeOfType = Array.from(typeNodes.slice(0, 1))[0] + const firstNodeOfType = Array.from(typeNodes.slice(0, 1))[0] as any if ( !firstNodeOfType || From e48c01c64cf91caa8f77cde62903e41b5fcae48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 17 May 2023 10:17:51 +0200 Subject: [PATCH 070/149] rewrite utils.js to ts --- packages/gatsby-source-contentful/src/{utils.js => utils.ts} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename packages/gatsby-source-contentful/src/{utils.js => utils.ts} (84%) diff --git a/packages/gatsby-source-contentful/src/utils.js b/packages/gatsby-source-contentful/src/utils.ts similarity index 84% rename from packages/gatsby-source-contentful/src/utils.js rename to packages/gatsby-source-contentful/src/utils.ts index ff33ce49aed33..d2af8783c6ff3 100644 --- a/packages/gatsby-source-contentful/src/utils.js +++ b/packages/gatsby-source-contentful/src/utils.ts @@ -1,6 +1,6 @@ // When iterating on tons of objects, we don't want to block the event loop // this helper function returns a promise that resolves on the next tick so that the event loop can continue before we continue running blocking code -export function untilNextEventLoopTick() { +export function untilNextEventLoopTick(): Promise { return new Promise(res => { setImmediate(() => { res(null) From 6aa0f5ceabe7f76f1540107801c996cd1fa80be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 23 May 2023 14:12:53 +0200 Subject: [PATCH 071/149] build: migrate to latest Contentful JS SDK --- .../gatsby-source-contentful/package.json | 2 +- .../src/__tests__/fetch-backoff.js | 4 +- .../src/__tests__/fetch-network-errors.js | 4 +- .../src/__tests__/fetch.js | 6 +- .../src/create-schema-customization.ts | 6 +- .../gatsby-source-contentful/src/fetch.ts | 44 ++-- .../gatsby-source-contentful/src/normalize.ts | 34 +-- .../src/source-nodes.ts | 2 +- .../src/types/contentful-js-sdk/asset-key.ts | 4 - .../src/types/contentful-js-sdk/asset.ts | 50 ---- .../src/types/contentful-js-sdk/collection.ts | 6 - .../types/contentful-js-sdk/content-type.ts | 86 ------- .../src/types/contentful-js-sdk/entry.ts | 221 ------------------ .../src/types/contentful-js-sdk/index.ts | 12 - .../src/types/contentful-js-sdk/link.ts | 14 -- .../src/types/contentful-js-sdk/locale.ts | 22 -- .../src/types/contentful-js-sdk/metadata.ts | 5 - .../types/contentful-js-sdk/query/equality.ts | 29 --- .../contentful-js-sdk/query/existence.ts | 17 -- .../types/contentful-js-sdk/query/index.ts | 1 - .../types/contentful-js-sdk/query/location.ts | 68 ------ .../types/contentful-js-sdk/query/query.ts | 66 ------ .../types/contentful-js-sdk/query/range.ts | 18 -- .../types/contentful-js-sdk/query/search.ts | 17 -- .../types/contentful-js-sdk/query/select.ts | 13 -- .../types/contentful-js-sdk/query/subset.ts | 19 -- .../src/types/contentful-js-sdk/query/util.ts | 29 --- .../src/types/contentful-js-sdk/space.ts | 15 -- .../src/types/contentful-js-sdk/sync.ts | 10 - .../src/types/contentful-js-sdk/sys.ts | 16 -- .../src/types/contentful-js-sdk/tag.ts | 18 -- .../src/types/contentful.ts | 33 ++- yarn.lock | 55 +++-- 33 files changed, 113 insertions(+), 833 deletions(-) delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset-key.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/collection.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/content-type.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/entry.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/index.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/link.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/locale.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/metadata.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/equality.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/existence.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/index.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/location.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/query.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/range.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/search.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/select.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/subset.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/util.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/space.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/sync.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/sys.ts delete mode 100644 packages/gatsby-source-contentful/src/types/contentful-js-sdk/tag.ts diff --git a/packages/gatsby-source-contentful/package.json b/packages/gatsby-source-contentful/package.json index 7b940caaee4f8..e023118070cff 100644 --- a/packages/gatsby-source-contentful/package.json +++ b/packages/gatsby-source-contentful/package.json @@ -17,7 +17,7 @@ "@vercel/fetch-retry": "^5.1.3", "chalk": "^4.1.2", "common-tags": "^1.8.2", - "contentful": "^9.3.5", + "contentful": "^10.2.1", "fs-extra": "^11.1.1", "gatsby-core-utils": "^4.11.0-next.0", "gatsby-plugin-utils": "^4.11.0-next.0", diff --git a/packages/gatsby-source-contentful/src/__tests__/fetch-backoff.js b/packages/gatsby-source-contentful/src/__tests__/fetch-backoff.js index f9a10c5e40317..6ca289df23b9a 100644 --- a/packages/gatsby-source-contentful/src/__tests__/fetch-backoff.js +++ b/packages/gatsby-source-contentful/src/__tests__/fetch-backoff.js @@ -85,7 +85,7 @@ describe(`fetch-backoff`, () => { .reply(200, { items: [] }) // Tags .get( - `/spaces/${options.spaceId}/environments/master/tags?skip=0&limit=1000&order=sys.createdAt` + `/spaces/${options.spaceId}/environments/master/tags?skip=0&limit=1000` ) .reply(200, { items: [] }) @@ -128,7 +128,7 @@ describe(`fetch-backoff`, () => { .reply(200, { items: [] }) // Tags .get( - `/spaces/${options.spaceId}/environments/master/tags?skip=0&limit=1000&order=sys.createdAt` + `/spaces/${options.spaceId}/environments/master/tags?skip=0&limit=1000` ) .reply(200, { items: [] }) diff --git a/packages/gatsby-source-contentful/src/__tests__/fetch-network-errors.js b/packages/gatsby-source-contentful/src/__tests__/fetch-network-errors.js index 189322d4669f2..9bd7a8741eb83 100644 --- a/packages/gatsby-source-contentful/src/__tests__/fetch-network-errors.js +++ b/packages/gatsby-source-contentful/src/__tests__/fetch-network-errors.js @@ -68,7 +68,7 @@ describe(`fetch-retry`, () => { .reply(200, { items: [] }) // Tags .get( - `/spaces/${options.spaceId}/environments/master/tags?skip=0&limit=1000&order=sys.createdAt` + `/spaces/${options.spaceId}/environments/master/tags?skip=0&limit=1000` ) .reply(200, { items: [] }) @@ -113,7 +113,7 @@ describe(`fetch-retry`, () => { const msg = expect(e.context.sourceMessage) msg.toEqual( expect.stringContaining( - `Fetching contentful data failed: ERR_BAD_RESPONSE 500 MockedContentfulError` + `Fetching contentful data failed: 500 MockedContentfulError Mocked message of Contentful error` ) ) msg.toEqual(expect.stringContaining(`Request ID: 123abc`)) diff --git a/packages/gatsby-source-contentful/src/__tests__/fetch.js b/packages/gatsby-source-contentful/src/__tests__/fetch.js index 6165b6991f32e..21c383d343cf6 100644 --- a/packages/gatsby-source-contentful/src/__tests__/fetch.js +++ b/packages/gatsby-source-contentful/src/__tests__/fetch.js @@ -47,6 +47,9 @@ const mockClient = { }), } +mockClient.withAllLocales = mockClient +mockClient.withoutLinkResolution = mockClient + jest.mock(`contentful`, () => { return { createClient: jest.fn(() => mockClient), @@ -169,7 +172,6 @@ it(`calls contentful.getContentTypes with default page limit`, async () => { expect(reporter.panic).not.toBeCalled() expect(mockClient.getContentTypes).toHaveBeenCalledWith({ limit: 1000, - order: `sys.createdAt`, skip: 0, }) }) @@ -187,7 +189,6 @@ it(`calls contentful.getContentTypes with custom plugin option page limit`, asyn expect(reporter.panic).not.toBeCalled() expect(mockClient.getContentTypes).toHaveBeenCalledWith({ limit: 50, - order: `sys.createdAt`, skip: 0, }) }) @@ -207,7 +208,6 @@ describe(`Tags feature`, () => { expect(reporter.panic).not.toBeCalled() expect(mockClient.getTags).toHaveBeenCalledWith({ limit: 50, - order: `sys.createdAt`, skip: 0, }) }) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index b8b0b398eb532..41fb597f4c93c 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -21,11 +21,7 @@ import { resolveGatsbyImageData } from "./gatsby-plugin-image" import { makeTypeName } from "./normalize" import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" import type { IPluginOptions } from "./types/plugin" -import type { - ContentType, - ContentTypeField, - FieldItem, -} from "./types/contentful-js-sdk/content-type" +import type { ContentType, ContentTypeField, FieldItem } from "contentful" import type { IContentfulAsset, diff --git a/packages/gatsby-source-contentful/src/fetch.ts b/packages/gatsby-source-contentful/src/fetch.ts index 7d5db1dbd387b..284628b3c611f 100644 --- a/packages/gatsby-source-contentful/src/fetch.ts +++ b/packages/gatsby-source-contentful/src/fetch.ts @@ -12,12 +12,13 @@ import { formatPluginOptionsForCLI } from "./plugin-options" import { CODES } from "./report" import type { ContentType, - EntryCollection, Locale, Space, SyncCollection, Tag, -} from "./types/contentful-js-sdk" + EntrySkeletonType, + ContentfulCollection, +} from "contentful" import type { IProcessedPluginOptions } from "./types/plugin" /** @@ -253,7 +254,10 @@ ${formatPluginOptionsForCLI(pluginConfig.getOriginalPluginOptions(), errors)}`, } interface IFetchResult { - currentSyncData: SyncCollection + currentSyncData: SyncCollection< + EntrySkeletonType, + "WITH_ALL_LOCALES" | "WITHOUT_LINK_RESOLUTION" + > tagItems: Array defaultLocale: string locales: Array @@ -280,7 +284,8 @@ export async function fetchContent({ pluginConfig, reporter, }) - const client = createClient(contentfulClientOptions) + const client = createClient(contentfulClientOptions).withAllLocales + .withoutLinkResolution // The sync API puts the locale in all fields in this format { fieldName: // {'locale': value} } so we need to get the space and its default local. @@ -320,21 +325,26 @@ export async function fetchContent({ }) const syncClient = createClient(contentfulSyncClientOptions) - let currentSyncData: SyncCollection | undefined + let currentSyncData: + | SyncCollection< + EntrySkeletonType, + "WITH_ALL_LOCALES" | "WITHOUT_LINK_RESOLUTION" + > + | undefined let currentPageLimit = pageLimit let lastCurrentPageLimit = 0 let syncSuccess = false try { while (!syncSuccess) { try { - const basicSyncConfig = { - limit: currentPageLimit, - resolveLinks: false, - } const query = syncToken ? { nextSyncToken: syncToken } - : { initial: true, ...basicSyncConfig } - currentSyncData = (await syncClient.sync(query)) as SyncCollection + : { initial: true as const, limit: currentPageLimit } + + currentSyncData = (await syncClient.sync(query)) as SyncCollection< + EntrySkeletonType, + "WITH_ALL_LOCALES" | "WITHOUT_LINK_RESOLUTION" + > syncSuccess = true } catch (e) { // Back off page limit if responses content length exceeds Contentfuls limits. @@ -437,7 +447,8 @@ export async function fetchContentTypes({ pluginConfig, reporter, }) - const client = createClient(contentfulClientOptions) + const client = createClient(contentfulClientOptions).withAllLocales + .withoutLinkResolution const pageLimit = pluginConfig.get(`pageLimit`) || 100 const sourceId = `${pluginConfig.get(`spaceId`)}-${pluginConfig.get( `environment` @@ -484,13 +495,13 @@ export async function fetchContentTypes({ * concatenate the new responses to the original one. */ function pagedGet( - client: ContentfulClientApi, - method: keyof ContentfulClientApi, + client: ContentfulClientApi<"WITH_ALL_LOCALES" | "WITHOUT_LINK_RESOLUTION">, + method: "getContentTypes" | "getTags", pageLimit: number, query = {}, skip = 0, - aggregatedResponse?: EntryCollection -): Promise | ContentTypeCollection | undefined> { + aggregatedResponse?: ContentfulCollection +): Promise | ContentTypeCollection | undefined> { if (!client[method]) { throw new Error(`Contentful Client does not support the method ${method}`) } @@ -499,7 +510,6 @@ function pagedGet( ...query, skip: skip, limit: pageLimit, - order: `sys.createdAt`, }).then(response => { if (!aggregatedResponse) { aggregatedResponse = response diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index adc9373d62920..fd023500f62df 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -11,6 +11,7 @@ import type { IContentfulEntry, IContentfulLink, ILocalizedField, + IEntryWithAllLocalesAndWithoutLinkResolution, } from "./types/contentful" import type { SyncCollection, @@ -20,10 +21,12 @@ import type { Locale, LocaleCode, AssetFile, - EntryWithAllLocalesAndWithoutLinkResolution, -} from "./types/contentful-js-sdk" + FieldsType, + EntrySkeletonType, + DeletedEntry, + EntitySys, +} from "contentful" import type { IProcessedPluginOptions } from "./types/plugin" -import type { FieldsType } from "./types/contentful-js-sdk/query/util" export const makeTypeName = ( type: string, @@ -113,7 +116,7 @@ const makeMakeId = // TODO: space id is actually not factored in here! export const createRefId = ( node: - | EntryWithAllLocalesAndWithoutLinkResolution + | IEntryWithAllLocalesAndWithoutLinkResolution | IContentfulEntry | Asset ): string => `${node.sys.id}___${node.sys.type}` @@ -126,14 +129,17 @@ export const buildEntryList = ({ currentSyncData, }: { contentTypeItems: Array - currentSyncData: SyncCollection + currentSyncData: SyncCollection< + EntrySkeletonType, + "WITH_ALL_LOCALES" | "WITHOUT_LINK_RESOLUTION" + > }): Array< - Array> + Array> > => { // 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: Map< string, - Array> + Array> > = new Map(contentTypeItems.map(contentType => [contentType.sys.id, []])) // Now fill the buckets. Ignore entries for which there exists no bucket. (This happens when filterContentType is used) currentSyncData.entries.map(entry => { @@ -152,7 +158,7 @@ export const buildResolvableSet = ({ assets = [], }: { entryList: Array< - Array> + Array> > existingNodes: Map assets: Array @@ -193,7 +199,7 @@ interface IForeignReferenceMapState { function cleanupReferencesFromEntry( foreignReferenceMapState: IForeignReferenceMapState, - entry: EntryWithAllLocalesAndWithoutLinkResolution + entry: { sys: EntitySys } ): void { const { links, backLinks } = foreignReferenceMapState const entryId = entry.sys.id @@ -229,7 +235,7 @@ export const buildForeignReferenceMap = ({ }: { contentTypeItems: Array entryList: Array< - Array> + Array> > resolvable: Set defaultLocale: string @@ -237,9 +243,7 @@ export const buildForeignReferenceMap = ({ useNameForId: boolean contentTypePrefix: string previousForeignReferenceMapState?: IForeignReferenceMapState - deletedEntries: Array< - EntryWithAllLocalesAndWithoutLinkResolution - > + deletedEntries: Array createNodeId }): IForeignReferenceMapState => { const foreignReferenceMapState: IForeignReferenceMapState = @@ -389,7 +393,7 @@ function contentfulCreateNodeManifest({ unstable_createNodeManifest, }: { pluginConfig: IProcessedPluginOptions - entryItem: EntryWithAllLocalesAndWithoutLinkResolution + entryItem: IEntryWithAllLocalesAndWithoutLinkResolution entryNode: IContentfulEntry space: Space unstable_createNodeManifest: SourceNodesArgs["unstable_createNodeManifest"] @@ -452,7 +456,7 @@ interface ICreateNodesForContentTypeArgs SourceNodesArgs { contentTypeItem: ContentType entries: Array< - EntryWithAllLocalesAndWithoutLinkResolution + IEntryWithAllLocalesAndWithoutLinkResolution > resolvable: Set foreignReferenceMap: IForeignReferenceMap diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index 65fef1ac44c23..d38452a5710b9 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -18,12 +18,12 @@ import { getExistingCachedNodes, removeNodeFromExistingNodesCache, } from "./backreferences" +import type { ContentType } from "contentful" import { createPluginConfig } from "./plugin-options" import { CODES } from "./report" import { untilNextEventLoopTick } from "./utils" import type { IPluginOptions } from "./types/plugin" import type { IContentfulAsset } from "./types/contentful" -import type { ContentType } from "./types/contentful-js-sdk" const CONTENT_DIGEST_COUNTER_SEPARATOR = `_COUNT_` diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset-key.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset-key.ts deleted file mode 100644 index b4690874bc338..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset-key.ts +++ /dev/null @@ -1,4 +0,0 @@ -export type AssetKey = { - secret: string - policy: string -} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset.ts deleted file mode 100644 index c7093233189b8..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/asset.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { ContentfulCollection } from './collection' -import { Metadata } from './metadata' -import { EntitySys } from './sys' - -export interface AssetDetails { - size: number - image?: { - width: number - height: number - } -} - -export interface AssetFile { - url: string - details: AssetDetails - fileName: string - contentType: string -} - -export interface AssetFields { - title?: string - description?: string - file?: AssetFile -} - -/** - * @category Entities - */ -export interface Asset { - sys: AssetSys - fields: AssetFields - metadata: Metadata -} - -export type AssetMimeType = - | 'attachment' - | 'plaintext' - | 'image' - | 'audio' - | 'video' - | 'richtext' - | 'presentation' - | 'spreadsheet' - | 'pdfdocument' - | 'archive' - | 'code' - | 'markup' - -export type AssetCollection = ContentfulCollection -export type AssetSys = EntitySys diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/collection.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/collection.ts deleted file mode 100644 index 50471afacd2cd..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/collection.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface ContentfulCollection { - total: number - skip: number - limit: number - items: Array -} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/content-type.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/content-type.ts deleted file mode 100644 index 424074b38d80e..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/content-type.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { ContentfulCollection } from './collection' -import { EntryFields } from './entry' -import { SpaceLink, EnvironmentLink } from './link' -import { BaseSys } from './sys' - -export interface ContentTypeSys extends BaseSys { - createdAt: EntryFields.Date - updatedAt: EntryFields.Date - revision: number - space: { sys: SpaceLink } - environment: { sys: EnvironmentLink } -} - -export interface ContentTypeField { - disabled: boolean - id: string - linkType?: string - localized: boolean - name: string - omitted: boolean - required: boolean - type: ContentTypeFieldType - validations: ContentTypeFieldValidation[] - items?: FieldItem - allowedResources?: ContentTypeAllowedResources[] -} - -interface ContentTypeAllowedResources { - type: string - source: string - contentTypes: string[] -} - -export type ContentTypeFieldType = - | 'Symbol' - | 'Text' - | 'Integer' - | 'Number' - | 'Date' - | 'Boolean' - | 'Location' - | 'Link' - | 'Array' - | 'Object' - | 'RichText' - | 'ResourceLink' - -export interface ContentTypeFieldValidation { - unique?: boolean - size?: { - min?: number - max?: number - } - regexp?: { - pattern: string - } - linkMimetypeGroup?: string[] - in?: string[] - linkContentType?: string[] - message?: string - nodes?: { - 'entry-hyperlink'?: ContentTypeFieldValidation[] - 'embedded-entry-block'?: ContentTypeFieldValidation[] - 'embedded-entry-inline'?: ContentTypeFieldValidation[] - } - enabledNodeTypes?: string[] -} - -export interface FieldItem { - type: 'Link' | 'Symbol' | 'ResourceLink' - validations: ContentTypeFieldValidation[] - linkType?: 'Entry' | 'Asset' -} - -/** - * @category Entities - */ -export interface ContentType { - sys: ContentTypeSys - name: string - description: string - displayField: string - fields: Array -} - -export type ContentTypeCollection = ContentfulCollection diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/entry.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/entry.ts deleted file mode 100644 index 3337101d09576..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/entry.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { Document as RichTextDocument } from "@contentful/rich-text-types" -import { Asset } from "./asset" -import { ContentfulCollection } from "./collection" -import { ContentTypeLink, EntryLink } from "./link" -import { LocaleCode } from "./locale" -import { Metadata } from "./metadata" -import { FieldsType } from "./query/util" -import { EntitySys } from "./sys" - -export interface EntrySys extends EntitySys { - contentType: { sys: ContentTypeLink } -} - -export declare namespace EntryFields { - type Symbol = string - type Text = string - type Integer = number - type Number = number - type Date = `${number}-${number}-${number}T${number}:${number}:${number}Z` - type Boolean = boolean - - type Location = { - lat: number - lon: number - } - - type Link = Asset | Entry - type Array = symbol[] | Entry[] | Asset[] - type Object = Record> = T - type RichText = RichTextDocument -} - -export type BasicEntryField = - | EntryFields.Symbol - | EntryFields.Text - | EntryFields.Integer - | EntryFields.Number - | EntryFields.Date - | EntryFields.Boolean - | EntryFields.Location - | EntryFields.RichText - | EntryFields.Object - -/** - * @category Entities - */ -export interface Entry { - sys: EntrySys - metadata: Metadata - fields: T -} - -export interface EntryWithAllLocalesAndWithoutLinkResolution< - Fields extends FieldsType, - Locales extends LocaleCode -> { - sys: EntrySys - metadata: Metadata - fields: { - [FieldName in keyof Fields]: { - [LocaleName in Locales]?: Fields[FieldName] extends EntryFields.Link - ? EntryLink - : Fields[FieldName] extends EntryFields.Link[] - ? EntryLink[] - : Fields[FieldName] - } - } -} - -export type EntryWithLinkResolutionAndWithUnresolvableLinks< - Fields extends FieldsType -> = { - sys: EntrySys - metadata: Metadata - fields: { - [FieldName in keyof Fields]: Fields[FieldName] extends EntryFields.Link< - infer LinkedEntryFields - > - ? - | EntryWithLinkResolutionAndWithUnresolvableLinks - | EntryLink - : Fields[FieldName] extends EntryFields.Link[] - ? ( - | EntryWithLinkResolutionAndWithUnresolvableLinks - | EntryLink - )[] - : Fields[FieldName] - } -} - -export type EntryWithAllLocalesAndWithLinkResolutionAndWithUnresolvableLinks< - Fields extends FieldsType, - Locales extends LocaleCode -> = { - sys: EntrySys - metadata: Metadata - fields: { - [FieldName in keyof Fields]: { - [LocaleName in Locales]?: Fields[FieldName] extends EntryFields.Link< - infer LinkedEntryFields - > - ? - | EntryWithAllLocalesAndWithLinkResolutionAndWithUnresolvableLinks< - LinkedEntryFields, - Locales - > - | undefined - : Fields[FieldName] extends Array< - EntryFields.Link - > - ? - | EntryWithAllLocalesAndWithLinkResolutionAndWithUnresolvableLinks< - LinkedEntryFields, - Locales - >[] - | undefined - : Fields[FieldName] - } - } -} - -export type EntryWithLinkResolutionAndWithoutUnresolvableLinks< - Fields extends FieldsType -> = { - sys: EntrySys - metadata: Metadata - fields: { - [FieldName in keyof Fields]: Fields[FieldName] extends EntryFields.Link< - infer LinkedEntryFields - > - ? - | EntryWithLinkResolutionAndWithoutUnresolvableLinks - | undefined - : Fields[FieldName] extends EntryFields.Link[] - ? - | EntryWithLinkResolutionAndWithoutUnresolvableLinks[] - | undefined - : Fields[FieldName] - } -} - -export type EntryWithAllLocalesAndWithLinkResolutionAndWithoutUnresolvableLinks< - Fields extends FieldsType, - Locales extends LocaleCode -> = { - sys: EntrySys - metadata: Metadata - fields: { - [FieldName in keyof Fields]: { - [LocaleName in Locales]?: Fields[FieldName] extends EntryFields.Link< - infer LinkedEntryFields - > - ? - | EntryWithAllLocalesAndWithLinkResolutionAndWithoutUnresolvableLinks< - LinkedEntryFields, - Locales - > - | undefined - : Fields[FieldName] extends EntryFields.Link[] - ? - | EntryWithAllLocalesAndWithLinkResolutionAndWithoutUnresolvableLinks< - LinkedEntryFields, - Locales - >[] - | undefined - : Fields[FieldName] - } - } -} - -export interface AbstractEntryCollection - extends ContentfulCollection { - errors?: Array - includes?: { - Entry?: any[] - Asset?: any[] - } -} - -export type EntryCollection = AbstractEntryCollection> - -export type EntryWithoutLinkResolution = Entry - -export type EntryCollectionWithoutLinkResolution = EntryCollection - -export type EntryCollectionWithLinkResolutionAndWithUnresolvableLinks< - T extends FieldsType -> = AbstractEntryCollection> - -export type EntryCollectionWithAllLocalesAndWithoutLinkResolution< - Fields extends FieldsType, - Locales extends LocaleCode -> = AbstractEntryCollection< - EntryWithAllLocalesAndWithoutLinkResolution -> - -export type EntryCollectionWithAllLocalesAndWithLinkResolutionAndWithUnresolvableLinks< - Fields extends FieldsType, - Locales extends LocaleCode -> = AbstractEntryCollection< - EntryWithAllLocalesAndWithLinkResolutionAndWithUnresolvableLinks< - Fields, - Locales - > -> - -export type EntryCollectionWithLinkResolutionAndWithoutUnresolvableLinks< - Fields extends FieldsType -> = AbstractEntryCollection< - EntryWithLinkResolutionAndWithoutUnresolvableLinks -> - -export type EntryCollectionWithAllLocalesAndWithLinkResolutionAndWithoutUnresolvableLinks< - Fields extends FieldsType, - Locales extends LocaleCode -> = AbstractEntryCollection< - EntryWithAllLocalesAndWithLinkResolutionAndWithoutUnresolvableLinks< - Fields, - Locales - > -> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/index.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/index.ts deleted file mode 100644 index a4b25a56b8e57..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export * from './asset' -export * from './asset-key' -export * from './collection' -export * from './content-type' -export * from './entry' -export * from './link' -export * from './locale' -export * from './metadata' -export * from './query' -export * from './space' -export * from './sync' -export * from './tag' diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/link.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/link.ts deleted file mode 100644 index 72d52b9581888..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/link.ts +++ /dev/null @@ -1,14 +0,0 @@ -export type LinkType = 'Space' | 'ContentType' | 'Environment' | 'Entry' | 'Tag' | 'User' - -export interface Link { - type: 'Link' - linkType: T - id: string -} - -export type SpaceLink = Link<'Space'> -export type ContentTypeLink = Link<'ContentType'> -export type EnvironmentLink = Link<'Environment'> -export type EntryLink = Link<'Entry'> -export type TagLink = Link<'Tag'> -export type UserLink = Link<'User'> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/locale.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/locale.ts deleted file mode 100644 index 1e08526699116..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/locale.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { ContentfulCollection } from './collection' -import { BaseSys } from './sys' - -export type LocaleCode = string - -export interface LocaleSys extends BaseSys { - type: 'Locale' - version: number -} - -/** - * @category Entities - */ -export interface Locale { - code: string - name: string - default: boolean - fallbackCode: string | null - sys: LocaleSys -} - -export type LocaleCollection = ContentfulCollection diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/metadata.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/metadata.ts deleted file mode 100644 index 1035de0f84916..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/metadata.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { TagLink } from './link' - -export type Metadata = { - tags: { sys: TagLink }[] -} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/equality.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/equality.ts deleted file mode 100644 index f3c943589b726..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/equality.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { BasicEntryField, EntryFields } from '../entry' -import { ConditionalQueries } from './util' - -// TODO: Note: Equality and inequality operators are not supported for text fields -// What types do we hav to exclude here? -type SupportedTypes = Exclude | undefined -/** - * @desc equality - search for exact matches - * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/equality-operator} - */ -export type EqualityFilter = ConditionalQueries< - Fields, - SupportedTypes, - Prefix, - '' -> - -/** - * @desc inequality - exclude matching items - * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/inequality-operator} - */ -export type InequalityFilter = ConditionalQueries< - Fields, - SupportedTypes, - Prefix, - '[ne]' -> - -// TODO: it still includes 'Link' fields diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/existence.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/existence.ts deleted file mode 100644 index e7b5bef5650f1..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/existence.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { BasicEntryField } from '../entry' -import { ConditionalFixedQueries } from './util' - -/** - * @name exists - * @desc check for existence - * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/existence} - */ -export type ExistenceFilter = ConditionalFixedQueries< - Fields, - BasicEntryField | undefined, - boolean, - Prefix, - '[exists]' -> - -// TODO: it still includes 'Link' fields diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/index.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/index.ts deleted file mode 100644 index d310624b62380..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { type AssetQueries, type EntriesQueries } from './query' diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/location.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/location.ts deleted file mode 100644 index f8b6b9d90a56e..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/location.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { ConditionalPick } from 'type-fest' -import { EntryFields } from '../entry' -import { NonEmpty } from './util' - -type Types = EntryFields.Location - -export type ProximitySearchFilterInput = [number, number] | undefined -export type BoundingBoxSearchFilterInput = [number, number, number, number] | undefined -export type BoundingCircleSearchFilterInput = [number, number, number] | undefined - -type BaseLocationFilter< - Fields, - SupportedTypes, - ValueType, - Prefix extends string, - QueryFilter extends string = '' -> = NonEmpty< - NonNullable<{ - [FieldName in keyof ConditionalPick as `${Prefix}.${string & - FieldName}[${QueryFilter}]`]?: ValueType - }> -> - -/** - * @desc near - location proximity search - * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/location-proximity-search} - */ -export type ProximitySearchFilter = BaseLocationFilter< - Fields, - Types, - ProximitySearchFilterInput, - Prefix, - 'near' -> - -/** - * @desc within - location in a bounding rectangle - * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/locations-in-a-bounding-object} - */ -type BoundingBoxSearchFilter = BaseLocationFilter< - Fields, - Types, - BoundingBoxSearchFilterInput, - Prefix, - 'within' -> -/** - * @desc within - location in a bounding circle - * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/locations-in-a-bounding-object} - */ -type BoundingCircleSearchFilter = BaseLocationFilter< - Fields, - Types, - BoundingCircleSearchFilterInput, - Prefix, - 'within' -> - -/** - * @desc location search - * @see [proximity]{@link ProximitySearchFilter} - * @see [bounding rectangle]{@link BoundingBoxSearchFilter} - * @see [bounding circle]{@link BoundingCircleSearchFilter} - */ -export type LocationSearchFilters = - | ProximitySearchFilter - | BoundingBoxSearchFilter - | BoundingCircleSearchFilter diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/query.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/query.ts deleted file mode 100644 index 49a7a7624fe85..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/query.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { AssetMimeType, AssetSys } from '../asset' -import { EntrySys } from '../entry' -import { EqualityFilter, InequalityFilter } from './equality' -import { ExistenceFilter } from './existence' -import { LocationSearchFilters } from './location' -import { RangeFilters } from './range' -import { FullTextSearchFilters } from './search' -import { SelectFilter } from './select' -import { SubsetFilters } from './subset' -import { FieldsType } from './util' - -type FixedPagedOptions = { - skip?: number - limit?: number -} - -type FixedQueryOptions = { - include?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 - locale?: string - query?: string -} - -export type SysQueries = ExistenceFilter & - EqualityFilter & - InequalityFilter & - SubsetFilters & - RangeFilters & - SelectFilter - -export type EntryFieldsQueries = - | (ExistenceFilter & - EqualityFilter & - InequalityFilter & - FullTextSearchFilters & - SelectFilter) - | SubsetFilters - | LocationSearchFilters - | RangeFilters - -// TODO: create-contentful-api complained about non-optional fields when initialized with {} -export type EntriesQueries = Partial< - EntryFieldsQueries & - SysQueries> & - FixedQueryOptions & - FixedPagedOptions & { content_type?: string } & Record & { - resolveLinks?: never - } -> - -export type EntryQueries = Omit - -export type AssetFieldsQueries = - | (ExistenceFilter & - EqualityFilter & - InequalityFilter & - FullTextSearchFilters & - SelectFilter) - | RangeFilters - | SubsetFilters - -export type AssetQueries = Partial< - AssetFieldsQueries & - SysQueries> & - FixedQueryOptions & - FixedPagedOptions & { mimetype_group?: AssetMimeType } & Record -> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/range.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/range.ts deleted file mode 100644 index 2c5d35b3d9881..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/range.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { EntryFields } from '../entry' -import { ConditionalQueries, NonEmpty } from './util' - -type RangeFilterTypes = 'lt' | 'lte' | 'gt' | 'gte' - -type SupportedTypes = EntryFields.Date | EntryFields.Number | EntryFields.Integer | undefined - -/** - * @desc Range operators are available that you can apply to date and number fields - * {string} lt: Less than. - * {string} lte: Less than or equal to. - * {string} gt: Greater than. - * {string} gte: Greater than or equal to. - * @see [Documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/select-operator} - */ -export type RangeFilters = NonEmpty< - ConditionalQueries -> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/search.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/search.ts deleted file mode 100644 index edada827dd065..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/search.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { BasicEntryField, EntryFields } from '../entry' -import { ConditionalFixedQueries } from './util' - -// TODO: should Boolean field type be excluded -type SupportedTypes = Exclude | undefined - -/** - * @desc match - full text search - * @see [documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/full-text-search} - */ -export type FullTextSearchFilters = ConditionalFixedQueries< - Fields, - SupportedTypes, - string, - Prefix, - '[match]' -> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/select.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/select.ts deleted file mode 100644 index a818d18636a00..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/select.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { FieldsType } from './util' - -/** - * @desc select - * @see [documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/select-operator} - */ -export type SelectFilter = { - select?: ( - | `${string}.${string}` - | `${Prefix}.${keyof Fields & string}` - | `${Prefix}.${keyof Fields & string}.${string}` - )[] -} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/subset.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/subset.ts deleted file mode 100644 index 667b43c1b5956..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/subset.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { BasicEntryField, EntryFields } from '..' -import { ConditionalQueries, NonEmpty } from './util' - -type SubsetFilterTypes = 'in' | 'nin' -type SupportedTypes = - | Exclude - | undefined - -/** - * @desc inclusion & exclusion - * @see [inclusion documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/inclusion} - * @see [exclusion documentation]{@link https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/search-parameters/exclusion} - * @example - * // {'fields.myField', 'singleValue'} - * // {'fields.myField', 'firstValue,secondValue'} - */ -export type SubsetFilters = NonEmpty< - NonNullable> -> diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/util.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/util.ts deleted file mode 100644 index 069b7c0430f85..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/query/util.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ConditionalPick } from 'type-fest' - -export type FieldsType = Record - -export type BaseOrArrayType = T extends Array ? U : T - -export type NonEmpty = T extends Record ? never : T - -//TODO: should we also allow ValueType[] for array types -export type ConditionalFixedQueries< - Fields, - SupportedTypes, - ValueType, - Prefix extends string, - QueryFilter extends string = '' -> = { - [FieldName in keyof ConditionalPick as `${Prefix}.${string & - FieldName}${QueryFilter}`]?: ValueType -} - -export type ConditionalQueries< - Fields, - SupportedTypes, - Prefix extends string, - QueryFilter extends string = '' -> = { - [FieldName in keyof ConditionalPick as `${Prefix}.${string & - FieldName}${QueryFilter}`]?: Fields[FieldName] extends Array ? T[] : Fields[FieldName] -} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/space.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/space.ts deleted file mode 100644 index 5964bbe737bf4..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/space.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Locale } from './locale' -import { BaseSys } from './sys' - -export interface SpaceSys extends BaseSys { - type: 'Space' -} - -/** - * @category Entities - */ -export interface Space { - sys: SpaceSys - name: string - locales: Array> -} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sync.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sync.ts deleted file mode 100644 index c3ddb546ab4be..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sync.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Asset } from './asset' -import { Entry } from './entry' - -export interface SyncCollection { - entries: Array> - assets: Array - deletedEntries: Array> - deletedAssets: Array - nextSyncToken: string -} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sys.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sys.ts deleted file mode 100644 index 9da264f19a4d1..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/sys.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { EntryFields } from './entry' -import { SpaceLink, EnvironmentLink } from './link' - -export interface BaseSys { - type: string - id: string -} - -export interface EntitySys extends BaseSys { - createdAt: EntryFields.Date - updatedAt: EntryFields.Date - revision: number - space: { sys: SpaceLink } - environment: { sys: EnvironmentLink } - locale?: string -} diff --git a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/tag.ts b/packages/gatsby-source-contentful/src/types/contentful-js-sdk/tag.ts deleted file mode 100644 index 10be14800e97a..0000000000000 --- a/packages/gatsby-source-contentful/src/types/contentful-js-sdk/tag.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { EntitySys } from './sys' -import { ContentfulCollection } from './collection' -import { UserLink } from './link' - -export interface TagSys extends Omit { - type: 'Tag' - version: number - visibility: 'public' - createdBy: { sys: UserLink } - updatedBy: { sys: UserLink } -} - -export type Tag = { - name: string - sys: TagSys -} - -export type TagCollection = ContentfulCollection diff --git a/packages/gatsby-source-contentful/src/types/contentful.ts b/packages/gatsby-source-contentful/src/types/contentful.ts index 92482bca85808..44f971ec97294 100644 --- a/packages/gatsby-source-contentful/src/types/contentful.ts +++ b/packages/gatsby-source-contentful/src/types/contentful.ts @@ -1,5 +1,13 @@ import { Node } from "gatsby" import { ImageFormat } from "gatsby-plugin-image" +import { + FieldsType, + LocaleCode, + EntrySys, + Metadata, + EntryLink, + EntryFields, +} from "contentful" // Generic Types export interface IContentfulContentType { @@ -24,12 +32,6 @@ export interface ILocalizedField { [locale: string]: unknown } -// export interface IContentfulTag { -// name: string -// contentful_id: string -// id: string -// } - interface IContentfulMetadata { tags: Array } @@ -42,8 +44,6 @@ export interface IContentfulLink { sys: IContentfulLinkSys } -// type UContentfulField = string | boolean | Array - interface IContentfulEntity extends Node { id: string sys: IContentfulSys @@ -127,3 +127,20 @@ export interface IContentfulImageAPIUrlBuilderOptions { cropFocus?: contentfulCropFocus cornerRadius?: number | "max" } + +export interface IEntryWithAllLocalesAndWithoutLinkResolution< + Fields extends FieldsType, + Locales extends LocaleCode +> { + sys: EntrySys + metadata: Metadata + fields: { + [FieldName in keyof Fields]: { + [LocaleName in Locales]?: Fields[FieldName] extends EntryFields.Link + ? EntryLink + : Fields[FieldName] extends Array> + ? Array + : Fields[FieldName] + } + } +} diff --git a/yarn.lock b/yarn.lock index cc300cb917b52..499d3023cb1fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6176,13 +6176,12 @@ axios@^0.21.1: dependencies: follow-redirects "^1.10.0" -axios@^0.27.0: - version "0.27.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" - integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== +axios@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.26.1.tgz#1ede41c51fcf51bbbd6fd43669caaa4f0495aaa9" + integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== dependencies: - follow-redirects "^1.14.9" - form-data "^4.0.0" + follow-redirects "^1.14.8" axobject-query@^3.1.1: version "3.1.1" @@ -7968,17 +7967,17 @@ content-type@~1.0.4, content-type@~1.0.5: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== -contentful-resolve-response@^1.3.12: - version "1.3.12" - resolved "https://registry.yarnpkg.com/contentful-resolve-response/-/contentful-resolve-response-1.3.12.tgz#8d1c37e4c084d87eba825a1f376e3562cb834385" - integrity sha512-fe2dsACyV3jzRjHcoeAa4bBt06YwkdsY+kdQwFCcdETyBQIxifuyGamIF4NmKcDqvZ9Yhw7ujjPCadzHb9jmKw== +contentful-resolve-response@^1.3.6: + version "1.7.0" + resolved "https://registry.yarnpkg.com/contentful-resolve-response/-/contentful-resolve-response-1.7.0.tgz#0431d222a474e60a397b050a883bb3df61d9a378" + integrity sha512-NIaQkXAdNWf/1wp13aqtrmHWHy71oCIIbynojGs9ONDtA7hBXC2yCEf2IjzfgOkrkEfOMvwDQHizD0WmL6FR8w== dependencies: fast-copy "^2.1.7" -contentful-sdk-core@^7.0.5: - version "7.0.6" - resolved "https://registry.yarnpkg.com/contentful-sdk-core/-/contentful-sdk-core-7.0.6.tgz#bd6be54f166b5cddf7a5132f8087b22d8bb8d477" - integrity sha512-xG4+a4p7VGCuxxUWh8t3O3V6gEcPP/aSE/KkvPRMYkm8PbxWYTAYG3c5pn5lmtj1QKcsY7yjiLWRXtP4qzem3Q== +contentful-sdk-core@^7.0.2: + version "7.1.0" + resolved "https://registry.yarnpkg.com/contentful-sdk-core/-/contentful-sdk-core-7.1.0.tgz#74d3ef8b167c5ac390fbb5db2d6e433731e05115" + integrity sha512-RzTPnRsbCdVAhyka3wa9sDsAu9YsxoerNgaMqd63Ljb7qpG2zkdHcP7NTfyIbuHDJNJdAQdifyafxfEEwP+q/w== dependencies: fast-copy "^2.1.7" lodash.isplainobject "^4.0.6" @@ -7986,17 +7985,17 @@ contentful-sdk-core@^7.0.5: p-throttle "^4.1.1" qs "^6.9.4" -contentful@^9.3.5: - version "9.3.5" - resolved "https://registry.yarnpkg.com/contentful/-/contentful-9.3.5.tgz#4644461f7b34a99ed64a10511743e7c278a71a00" - integrity sha512-QVXHwD9nxREBpcemC6Po2LUYStmBBHPyVbN3SKzkR+WmIZhflF6x+TDmmz2jcCg/RSN+INDZbhe8FQ1S/zTE8w== +contentful@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/contentful/-/contentful-10.2.1.tgz#b48fe6ee28ffa7bd28026e45d69d12f8856dba26" + integrity sha512-mo2tWKaoirRwiqECoJyi6Zt/IVr/wG4ECRCJBdGaOoxIM2Al+9Y0GAGRg4M1jF+EBYsTQPKUq5KCI1snVkIKBA== dependencies: "@contentful/rich-text-types" "^16.0.2" - axios "^0.27.0" - contentful-resolve-response "^1.3.12" - contentful-sdk-core "^7.0.5" - fast-copy "^2.1.7" + axios "^0.26.1" + contentful-resolve-response "^1.3.6" + contentful-sdk-core "^7.0.2" json-stringify-safe "^5.0.1" + type-fest "^3.1.0" continuable-cache@^0.3.1: version "0.3.1" @@ -11248,11 +11247,16 @@ focus-lock@^0.11.2: dependencies: tslib "^2.0.3" -follow-redirects@^1.10.0, follow-redirects@^1.14.9: +follow-redirects@^1.10.0: version "1.14.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.9.tgz#dd4ea157de7bfaf9ea9b3fbd85aa16951f78d8d7" integrity sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w== +follow-redirects@^1.14.8: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + font-family-papandreou@^0.2.0-patch1, font-family-papandreou@^0.2.0-patch2: version "0.2.0-patch2" resolved "https://registry.yarnpkg.com/font-family-papandreou/-/font-family-papandreou-0.2.0-patch2.tgz#c75b659e96ffbc7ab2af651cf7b4910b334e8dd2" @@ -23360,6 +23364,11 @@ type-fest@^2.19.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== +type-fest@^3.1.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.11.0.tgz#e78ea6b50d6a6b1e4609035fb9ea8f1e3c328194" + integrity sha512-JaPw5U9ixP0XcpUbQoVSbxSDcK/K4nww20C3kjm9yE6cDRRhptU28AH60VWf9ltXmCrIfIbtt9J+2OUk2Uqiaw== + type-is@^1.6.4, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" From 71cfc3f97b171619b06524c982a2c2a322e2a800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 5 Jun 2023 12:50:46 +0200 Subject: [PATCH 072/149] fix: ensure sync results are not resolved --- packages/gatsby-source-contentful/src/fetch.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gatsby-source-contentful/src/fetch.ts b/packages/gatsby-source-contentful/src/fetch.ts index 284628b3c611f..e3925b07ac830 100644 --- a/packages/gatsby-source-contentful/src/fetch.ts +++ b/packages/gatsby-source-contentful/src/fetch.ts @@ -324,6 +324,7 @@ export async function fetchContent({ syncProgress, }) const syncClient = createClient(contentfulSyncClientOptions) + .withoutLinkResolution.withAllLocales let currentSyncData: | SyncCollection< From 14964d1d28f643117dfd7cc45be826abe06a1f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 5 Jun 2023 15:03:12 +0200 Subject: [PATCH 073/149] build: migrate dependencies to latest or most fitting version --- .../gatsby-source-contentful/package.json | 12 ++++----- yarn.lock | 25 ++++++++----------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/packages/gatsby-source-contentful/package.json b/packages/gatsby-source-contentful/package.json index 6eb421e0a4c6e..469cf7448d057 100644 --- a/packages/gatsby-source-contentful/package.json +++ b/packages/gatsby-source-contentful/package.json @@ -11,18 +11,18 @@ "dependencies": { "@babel/runtime": "^7.20.13", "@contentful/rich-text-react-renderer": "^15.16.5", - "@contentful/rich-text-links": "^15.15.1", - "@contentful/rich-text-types": "^15.15.1", - "@hapi/joi": "^15.1.1", + "@contentful/rich-text-links": "^16.1.1", + "@contentful/rich-text-types": "^16.2.0", "@vercel/fetch-retry": "^5.1.3", "chalk": "^4.1.2", "common-tags": "^1.8.2", - "contentful": "^10.2.1", + "contentful": "^10.2.3", "fs-extra": "^11.1.1", "gatsby-core-utils": "^4.11.0-next.1", "gatsby-plugin-utils": "^4.11.0-next.1", "gatsby-source-filesystem": "^5.11.0-next.1", "is-online": "^9.0.1", + "joi": "^17.9.2", "json-stringify-safe": "^5.0.1", "lodash": "^4.17.21", "node-fetch": "^2.6.11", @@ -37,7 +37,7 @@ "del-cli": "^5.0.0", "gatsby-plugin-sharp": "^5.11.0-next.0", "nock": "^13.3.1", - "typescript": "^4.9.4" + "typescript": "^5.0.4" }, "homepage": "https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-source-contentful#readme", "keywords": [ @@ -49,7 +49,7 @@ "peerDependencies": { "gatsby": "^5.0.0-next", "gatsby-plugin-image": "^3.0.0-next", - "sharp": "^0.30.1" + "sharp": "^0.32.1" }, "repository": { "type": "git", diff --git a/yarn.lock b/yarn.lock index 1da309b9f4759..4213958e3a7e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1404,12 +1404,12 @@ resolved "https://registry.yarnpkg.com/@builder.io/partytown/-/partytown-0.7.5.tgz#f501e3db37a5ac659f21ba0c2e61b278e58b64b9" integrity sha512-Zbr2Eo0AQ4yzmQr/36/h+6LKjmdVBB3Q5cGzO6rtlIKB/IOpbQVUZW+XAnhpJmJr9sIF97OZjgbhG9k7Sjn4yw== -"@contentful/rich-text-links@^15.15.1": - version "15.15.1" - resolved "https://registry.yarnpkg.com/@contentful/rich-text-links/-/rich-text-links-15.15.1.tgz#c28825cb3aa77b75a07cfee225a987f2e384d9ba" - integrity sha512-s9DqKy7eoOXXDzaeA3NeOjD62TlBbtD1TqmQPHjpEHVJLBjulI/NJzTL9j2fELmbCVSZJxXh45c8FQQ3Y1IrbQ== +"@contentful/rich-text-links@^16.1.1": + version "16.1.1" + resolved "https://registry.yarnpkg.com/@contentful/rich-text-links/-/rich-text-links-16.1.1.tgz#d4fe5d77d0fc7c7b8a1185613910c11b6a1400ff" + integrity sha512-WSxtDeq1maWGSGJ5f8psRdERmXzvIhJn7jQB+H1QIfP7C50dh/67CV6ABSB2GdfcXQxVX21f4KptS+5IpBetUA== dependencies: - "@contentful/rich-text-types" "^15.15.1" + "@contentful/rich-text-types" "^16.2.0" "@contentful/rich-text-react-renderer@^15.16.5": version "15.16.5" @@ -1418,11 +1418,6 @@ dependencies: "@contentful/rich-text-types" "^16.2.0" -"@contentful/rich-text-types@^15.15.1": - version "15.15.1" - resolved "https://registry.yarnpkg.com/@contentful/rich-text-types/-/rich-text-types-15.15.1.tgz#96835cf0d0eba9e54f92ee43a4a1ce2a74014b53" - integrity sha512-oheW0vkxWDuKBIIXDeJfZaRYo+NzKbC4gETMhH+MGJd4nfL9cqrOvtRxZBgnhICN4vDpH4my/zUIZGKcFqGSjQ== - "@contentful/rich-text-types@^16.0.2", "@contentful/rich-text-types@^16.2.0": version "16.2.0" resolved "https://registry.yarnpkg.com/@contentful/rich-text-types/-/rich-text-types-16.2.0.tgz#5a98cb119340f4da46555216913e96d7ce58df70" @@ -7991,10 +7986,10 @@ contentful-sdk-core@^7.0.2: p-throttle "^4.1.1" qs "^6.9.4" -contentful@^10.2.1: - version "10.2.1" - resolved "https://registry.yarnpkg.com/contentful/-/contentful-10.2.1.tgz#b48fe6ee28ffa7bd28026e45d69d12f8856dba26" - integrity sha512-mo2tWKaoirRwiqECoJyi6Zt/IVr/wG4ECRCJBdGaOoxIM2Al+9Y0GAGRg4M1jF+EBYsTQPKUq5KCI1snVkIKBA== +contentful@^10.2.3: + version "10.2.3" + resolved "https://registry.yarnpkg.com/contentful/-/contentful-10.2.3.tgz#b29ef8a71f75eb19ff66fa98e74dcf2400b86daf" + integrity sha512-1GqJYwuQBl744ssyadZjeHrQAKBlOG3dxhcYBxfPi4iMzfGjMh+WiN0WeH0yIunKfOn5aIxEeYxZ6yexbP08zA== dependencies: "@contentful/rich-text-types" "^16.0.2" axios "^0.26.1" @@ -23426,7 +23421,7 @@ typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@^4.1.3, typescript@^4.9.4: +typescript@^4.1.3: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== From cb0e093f0435544c121fbde1a1db034cdaaf72f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 5 Jun 2023 15:12:28 +0200 Subject: [PATCH 074/149] chore: remove unused test fixture --- .../src/__fixtures__/rich-text-data.js | 79 ------------------- 1 file changed, 79 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js b/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js index 9526668a6a859..d26d3c97acc6c 100644 --- a/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js +++ b/packages/gatsby-source-contentful/src/__fixtures__/rich-text-data.js @@ -798,82 +798,3 @@ exports.initialSync = () => { tagItems: [], } } - -// TODO: this fixture is unused -exports.deleteLinkedPage = () => { - return { - currentSyncData: { - entries: [], - assets: [], - deletedEntries: [ - { - sys: { - type: `DeletedEntry`, - id: `7oHxo6bs0us9wIkq27qdyK`, - space: { - sys: { - type: `Link`, - linkType: `Space`, - id: `ahntqop9oi7x`, - }, - }, - environment: { - sys: { - id: `master`, - type: `Link`, - linkType: `Environment`, - }, - }, - revision: 1, - createdAt: `2020-10-16T12:29:38.094Z`, - updatedAt: `2020-10-16T12:29:38.094Z`, - deletedAt: `2020-10-16T12:29:38.094Z`, - }, - }, - ], - deletedAssets: [], - nextSyncToken: `FEnChMOBwr1Yw4TCqsK2LcKpCH3CjsORIyLDrGbDtgozw6xreMKCwpjCtlxATw3CqcO3w6XCrMKuITDDiEoQSMKvIMOYwrzCn3sHPH3CvsK3w4A9w6LCjsOVwrjCjGwbw4rCl0fDl8OhU8Oqw67DhMOCwozDmxrChsOtRD4`, - }, - defaultLocale: `en-US`, - locales: [ - { - code: `en-US`, - name: `English (United States)`, - default: true, - fallbackCode: null, - sys: { - id: `1uSElBQA68GRKF30tpTxxT`, - type: `Locale`, - version: 1, - }, - }, - { - code: `nl`, - name: `Dutch`, - default: false, - fallbackCode: `en-US`, - sys: { - id: `2T7M2OzIrvE8cOCOF1HMuY`, - type: `Locale`, - version: 1, - }, - }, - ], - space: { - sys: { - type: `Space`, - id: `ahntqop9oi7x`, - }, - name: `Rich Text`, - locales: [ - { - code: `en-US`, - default: true, - name: `English (United States)`, - fallbackCode: null, - }, - ], - }, - tagItems: [], - } -} From 9285b11bcc7b5a5b29b32ad5c8b4fbda84b742de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 5 Jun 2023 15:17:01 +0200 Subject: [PATCH 075/149] refactor: use proper types for localFile and gatsbyImageData --- .../gatsby-source-contentful/src/types/contentful.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/gatsby-source-contentful/src/types/contentful.ts b/packages/gatsby-source-contentful/src/types/contentful.ts index 44f971ec97294..a9e9265c9d5fa 100644 --- a/packages/gatsby-source-contentful/src/types/contentful.ts +++ b/packages/gatsby-source-contentful/src/types/contentful.ts @@ -1,5 +1,5 @@ import { Node } from "gatsby" -import { ImageFormat } from "gatsby-plugin-image" +import { IGatsbyImageData, ImageFormat } from "gatsby-plugin-image" import { FieldsType, LocaleCode, @@ -57,10 +57,12 @@ export interface IContentfulEntry extends IContentfulEntity { } export interface IContentfulAsset extends IContentfulEntity { - // TODO: this field type might be defined by Gatsby already? - gatsbyImageData?: unknown - // TODO: this field type might be defined by Gatsby already? - downloadLocal?: string + gatsbyImageData?: IGatsbyImageData + localFile?: { + excludeByMimeTypes?: Array + maxFileSizeBytes?: number + requestConcurrency?: number + } title: string description: string contentType: string From 1c8c37f6c9e146b4e051dc42be217ba33183d8f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 12 Jun 2023 10:33:06 +0200 Subject: [PATCH 076/149] build: fix yarn.lock --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 4213958e3a7e7..e22001212e445 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1998,7 +1998,7 @@ resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.1.0.tgz#6c9eafc78c1529248f8f4d92b0799a712b6052c6" integrity sha512-i9YbZPN3QgfighY/1X1Pu118VUz2Fmmhd6b2n0/O8YVgGGfw0FbUYoA97k7FkpGJ+pLCFEDLUmAPPV4D1kpeFw== -"@hapi/joi@^15.0.0", "@hapi/joi@^15.1.1": +"@hapi/joi@^15.0.0": version "15.1.1" resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7" integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== From fdd331a4ea11d7bc7cb1795888eb668f82501ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 16 Jun 2023 10:36:21 +0200 Subject: [PATCH 077/149] build: clean up lock file --- yarn.lock | 62 ------------------------------------------------------- 1 file changed, 62 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7d0b20c0a4b62..a4af5b4001da4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11590,68 +11590,6 @@ gather-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" -gatsby-core-utils@^4.11.0: - version "4.11.0" - resolved "https://registry.yarnpkg.com/gatsby-core-utils/-/gatsby-core-utils-4.11.0.tgz#16d300129d0d143a79ad32816b8837630d7e7fae" - integrity sha512-W7pfrKgBchdk19g802IuPkCA2iJ69lRR1GzkfYjB8d1TuIQqf0l1z0lv7e+2kQqO+uQ5Yt3sGMMN2qMYMWfLXg== - dependencies: - "@babel/runtime" "^7.20.13" - ci-info "2.0.0" - configstore "^5.0.1" - fastq "^1.15.0" - file-type "^16.5.4" - fs-extra "^11.1.1" - got "^11.8.6" - hash-wasm "^4.9.0" - import-from "^4.0.0" - lmdb "2.5.3" - lock "^1.1.0" - node-object-hash "^2.3.10" - proper-lockfile "^4.1.2" - resolve-from "^5.0.0" - tmp "^0.2.1" - xdg-basedir "^4.0.0" - -gatsby-plugin-sharp@^5.11.0-next.0: - version "5.11.0" - resolved "https://registry.yarnpkg.com/gatsby-plugin-sharp/-/gatsby-plugin-sharp-5.11.0.tgz#4a030293278bf7f3869e55536aed011f6008e45b" - integrity sha512-/7so6DUiDbTKEwQ/lTzJRIw8wPYLoFkmVOZ8ACXhVQ/2Gq/pDc8ToLgDF1MyPQ40BZcfN2nmsPgHYdq5lFsCTg== - dependencies: - "@babel/runtime" "^7.20.13" - async "^3.2.4" - bluebird "^3.7.2" - debug "^4.3.4" - filenamify "^4.3.0" - fs-extra "^11.1.1" - gatsby-core-utils "^4.11.0" - gatsby-plugin-utils "^4.11.0" - lodash "^4.17.21" - probe-image-size "^7.2.3" - semver "^7.5.1" - sharp "^0.32.1" - -gatsby-plugin-utils@^4.11.0: - version "4.11.0" - resolved "https://registry.yarnpkg.com/gatsby-plugin-utils/-/gatsby-plugin-utils-4.11.0.tgz#f92852a9d938a428c8b2f99fea153c1bd995dfde" - integrity sha512-Eegg3BScq7vKYeJoWo6sduBwgM4DsKhYKXGIAVR9rRsGOiR1nNIWfFzT9I6OOcob9KHICeFyNgqyqpENL7odEA== - dependencies: - "@babel/runtime" "^7.20.13" - fastq "^1.15.0" - fs-extra "^11.1.1" - gatsby-core-utils "^4.11.0" - gatsby-sharp "^1.11.0" - graphql-compose "^9.0.10" - import-from "^4.0.0" - joi "^17.9.2" - mime "^3.0.0" - -gatsby-sharp@^1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/gatsby-sharp/-/gatsby-sharp-1.11.0.tgz#dcf43d0bbd3a45c079256ddc474798753aeedfe2" - integrity sha512-zJbN3JVCFur8Ilwn1scf7o8AN69//shpJhYqt3uhuwhhkU6ZMCMmVVNKHSiUiWkVqhwSRJ4y7c/I3Ys9xMxsIw== - dependencies: - sharp "^0.32.1" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" From 3d01f477a43c14545244c124a753519c8d5a5693 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 16 Jun 2023 12:36:28 +0200 Subject: [PATCH 078/149] feat: support CPA by nulling unresolvable linked nodes --- .../src/create-schema-customization.ts | 2 +- .../gatsby-source-contentful/src/normalize.ts | 41 ++++++++++++++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index 41fb597f4c93c..e30d8c6795537 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -242,7 +242,7 @@ const translateFieldType = ( fieldType = primitiveType(field) } - // TODO: what do we do when preview is enabled? Emptry required fields are valid for Contentfuls CP-API + // To support Contentful's CPA (Content Preview API), we have to allow empty required fields. // if (field.required) { // fieldType.type = `${fieldType.type}!` // } diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index fd023500f62df..4ece8b971e06b 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -535,6 +535,7 @@ export const createNodesForContentType = ({ space, useNameForId, pluginConfig, + reporter, }: ICreateNodesForContentTypeArgs): Promise => { const { create, createNodesPromise } = makeQueuedCreateNode({ nodeCount: entries.length, @@ -604,6 +605,25 @@ export const createNodesForContentType = ({ const childrenNodes: Array = [] + const warnForUnresolvableLink = ( + entryItem: IEntryWithAllLocalesAndWithoutLinkResolution< + FieldsType, + string + >, + fieldName: string, + fieldValue: unknown + ): void => { + reporter.warn( + `Unable to find linked content in ${entryItem.sys.id}!\nContent Type: ${ + contentTypeItem.name + }, Field: ${fieldName}, Locale: ${locale.code}\n${JSON.stringify( + fieldValue, + null, + 2 + )}` + ) + } + // First create nodes for each of the entries of that content type const entryNodes: Array = entries.map( entryItem => { @@ -666,7 +686,13 @@ 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(v => resolvable.has(createLinkRefId(v))) + .filter(v => { + const isResolvable = resolvable.has(createLinkRefId(v)) + if (!isResolvable) { + warnForUnresolvableLink(entryItem, entryItemFieldKey, v) + } + return isResolvable + }) .map(function (v) { return mId( space.sys.id, @@ -675,10 +701,8 @@ export const createNodesForContentType = ({ ) }) - if (resolvableEntryItemFieldValue.length !== 0) { - entryItemFields[entryItemFieldKey] = - resolvableEntryItemFieldValue - } + entryItemFields[entryItemFieldKey] = + resolvableEntryItemFieldValue } else { if (resolvable.has(createLinkRefId(entryItemFieldValue))) { entryItemFields[entryItemFieldKey] = mId( @@ -687,6 +711,13 @@ export const createNodesForContentType = ({ entryItemFieldValue.sys.linkType || entryItemFieldValue.sys.type ) + } else { + entryItemFields[entryItemFieldKey] = null + warnForUnresolvableLink( + entryItem, + entryItemFieldKey, + entryItemFieldValue + ) } } } From a0bd9754bbac636d3b394ca0d9fa86666054dc9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 16 Jun 2023 12:45:43 +0200 Subject: [PATCH 079/149] chore: remove no more supported traced_svg placeholder --- .../integration/gatsby-plugin-image.js | 3 - e2e-tests/contentful/schema.gql | 395 ++++++++---------- e2e-tests/contentful/snapshots.js | 2 +- .../src/pages/gatsby-plugin-image.js | 26 -- 4 files changed, 177 insertions(+), 249 deletions(-) diff --git a/e2e-tests/contentful/cypress/integration/gatsby-plugin-image.js b/e2e-tests/contentful/cypress/integration/gatsby-plugin-image.js index 1678cea7af2d2..eba57e3049717 100644 --- a/e2e-tests/contentful/cypress/integration/gatsby-plugin-image.js +++ b/e2e-tests/contentful/cypress/integration/gatsby-plugin-image.js @@ -77,9 +77,6 @@ describe(`gatsby-plugin-image`, () => { it(`dominant-color`, testConfig, () => testGatsbyPluginImage(`dominant-color`, hasColorPlaceholder) ) - it(`traced`, testConfig, () => - testGatsbyPluginImage(`traced`, hasColorPlaceholder) - ) it(`blurred`, testConfig, () => testGatsbyPluginImage(`blurred`, hasBase64Placeholder) ) diff --git a/e2e-tests/contentful/schema.gql b/e2e-tests/contentful/schema.gql index ed86a1fdc54f3..ee6b281d3c8da 100644 --- a/e2e-tests/contentful/schema.gql +++ b/e2e-tests/contentful/schema.gql @@ -1,4 +1,4 @@ -### Type definitions saved at 2022-04-14T12:11:45.168Z ### +### Type definitions saved at 2023-06-16T10:42:44.280Z ### enum RemoteFileFit { COVER @@ -24,6 +24,7 @@ enum RemoteFileLayout { enum RemoteFilePlaceholder { DOMINANT_COLOR BLURRED + TRACED_SVG NONE } @@ -44,9 +45,7 @@ type RemoteFileResize { src: String } -""" -Remote Interface -""" +"""Remote Interface""" interface RemoteFile { id: ID! mimeType: String! @@ -62,6 +61,7 @@ interface RemoteFile { fit: RemoteFileFit = COVER """ + The image formats to generate. Valid values are AUTO (meaning the same format as the source image), JPG, PNG, WEBP and AVIF. The default value is [AUTO, WEBP, AVIF], and you should rarely need to @@ -80,45 +80,54 @@ interface RemoteFile { """ gatsbyImage( """ + The layout for the image. FIXED: A static image sized, that does not resize according to the screen width FULL_WIDTH: The image resizes to fit its container. Pass a "sizes" option if it isn't going to be the full width of the screen. CONSTRAINED: Resizes to fit its container, up to a maximum width, at which point it will remain fixed in size. + """ layout: RemoteFileLayout = CONSTRAINED """ + The display width of the generated image for layout = FIXED, and the display width of the largest image for layout = CONSTRAINED. The actual largest image resolution will be this value multiplied by the largest value in outputPixelDensities Ignored if layout = FLUID. + """ width: Int """ + If set, the height of the generated image. If omitted, it is calculated from the supplied width, matching the aspect ratio of the source image. """ height: Int """ + Format of generated placeholder image, displayed while the main image loads. - BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) - DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. - TRACED_SVG: a low-resolution traced SVG of the image. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). + TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set the argument "backgroundColor" to use a fixed background color. """ placeholder: RemoteFilePlaceholder = DOMINANT_COLOR """ + If set along with width or height, this will set the value of the other dimension to match the provided aspect ratio, cropping the image if needed. If neither width or height is provided, height will be set based on the intrinsic width of the source image. + """ aspectRatio: Float """ + The image formats to generate. Valid values are AUTO (meaning the same format as the source image), JPG, PNG, WEBP and AVIF. The default value is [AUTO, WEBP, AVIF], and you should rarely need to @@ -126,35 +135,42 @@ interface RemoteFile { not know the formats of the source images, as this could lead to unwanted results such as converting JPEGs to PNGs. Specifying both PNG and JPG is not supported and will be ignored. + """ formats: [RemoteFileFormat!] = [AUTO, WEBP, AVIF] """ + A list of image pixel densities to generate for FIXED and CONSTRAINED images. You should rarely need to change this. It will never generate images larger than the source, and will always include a 1x image. Default is [ 1, 2 ] for fixed images, meaning 1x, 2x, and [0.25, 0.5, 1, 2] for fluid. In this case, an image with a fluid layout and width = 400 would generate images at 100, 200, 400 and 800px wide. + """ outputPixelDensities: [Float] = [0.25, 0.5, 1, 2] """ + Specifies the image widths to generate. You should rarely need to change this. For FIXED and CONSTRAINED images it is better to allow these to be determined automatically, based on the image size. For FULL_WIDTH images this can be used to override the default, which is [750, 1080, 1366, 1920]. It will never generate any images larger than the source. + """ breakpoints: [Int] = [750, 1080, 1366, 1920] """ + The "sizes" property, passed to the img tag. This describes the display size of the image. This does not affect the generated images, but is used by the browser to decide which images to download. You can leave this blank for fixed images, or if the responsive image container will be the full width of the screen. In these cases we will generate an appropriate value. + """ sizes: String @@ -165,7 +181,7 @@ interface RemoteFile { fit: RemoteFileFit = COVER cropFocus: [RemoteFileCropFocus] quality: Int = 75 - ): JSON + ): GatsbyImageData } type File implements Node @dontInfer { @@ -248,6 +264,7 @@ type Site implements Node @dontInfer { pathPrefix: String jsxRuntime: String trailingSlash: String + graphqlTypegen: Boolean } type SiteSiteMetadata { @@ -301,7 +318,7 @@ type ContentfulSys implements Node @dontInfer { type: String! spaceId: String! environmentId: String! - contentType: ContentfulContentType @link(by: "id", from: "contentType___NODE") + contentType: ContentfulContentType @link(by: "id", from: "sys.contentType") firstPublishedAt: Date! publishedAt: Date! publishedVersion: Int! @@ -315,7 +332,7 @@ type ContentfulContentType implements Node @dontInfer { } type ContentfulMetadata @dontInfer { - tags: [ContentfulTag]! @link(by: "id", from: "tags___NODE") + tags: [ContentfulTag]! @link(by: "id", from: "tags") } type ContentfulTag implements Node @dontInfer { @@ -327,54 +344,27 @@ interface ContentfulEntry implements ContentfulEntity & Node { id: ID! sys: ContentfulSys! metadata: ContentfulMetadata! + linkedFrom: ContentfulLinkedFrom } -enum ImageResizingBehavior { - NO_CHANGE - - """ - Same as the default resizing, but adds padding so that the generated image has the specified dimensions. - """ - PAD - - """ - Crop a part of the original image to match the specified size. - """ - CROP - - """ - Crop the image to the specified dimensions, if the original image is smaller - than these dimensions, then the image will be upscaled. - """ - FILL - - """ - When used in association with the f parameter below, creates a thumbnail from the image based on a focus area. - """ - THUMB - - """ - Scale the image regardless of the original aspect ratio. - """ - SCALE +type ContentfulLinkedFrom @dontInfer { + ContentfulContentTypeMediaReference: [ContentfulContentTypeMediaReference] @link(by: "id", from: "ContentfulContentTypeMediaReference") + ContentfulContentTypeContentReference: [ContentfulContentTypeContentReference] @link(by: "id", from: "ContentfulContentTypeContentReference") + ContentfulContentTypeValidatedContentReference: [ContentfulContentTypeValidatedContentReference] @link(by: "id", from: "ContentfulContentTypeValidatedContentReference") } -enum ContentfulImageCropFocus { - TOP - TOP_LEFT - TOP_RIGHT - BOTTOM - BOTTOM_RIGHT - BOTTOM_LEFT - RIGHT - LEFT - FACE - FACES - CENTER +type ContentfulContentTypeMediaReference implements ContentfulEntity & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys! + metadata: ContentfulMetadata! + title: String + one: ContentfulAsset @link(by: "id", from: "one") + oneLocalized: ContentfulAsset @link(by: "id", from: "oneLocalized") + many: [ContentfulAsset] @link(by: "id", from: "many") + manyLocalized: [ContentfulAsset] @link(by: "id", from: "manyLocalized") + linkedFrom: ContentfulLinkedFrom } -type ContentfulAsset implements ContentfulEntity & Node & RemoteFile - @dontInfer { +type ContentfulAsset implements ContentfulEntity & Node & RemoteFile @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! gatsbyImageData( @@ -410,9 +400,9 @@ type ContentfulAsset implements ContentfulEntity & Node & RemoteFile """ Format of generated placeholder image, displayed while the main image loads. - BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) - DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. - TRACED_SVG: a low-resolution traced SVG of the image. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI. + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). + TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set the argument "backgroundColor" to use a fixed background color. """ placeholder: GatsbyImagePlaceholder @@ -471,17 +461,18 @@ type ContentfulAsset implements ContentfulEntity & Node & RemoteFile """ cornerRadius: Int quality: Int = 50 - ): JSON! + ): JSON localFile: File @link(from: "fields.localFile", by: "id") title: String description: String contentType: String! mimeType: String! - fileName: String! + filename: String! url: String! size: Int width: Int height: Int + linkedFrom: ContentfulLinkedFrom } enum GatsbyImageLayout { @@ -506,6 +497,92 @@ enum GatsbyImageFormat { AVIF } +enum ImageResizingBehavior { + NO_CHANGE + + """ + Same as the default resizing, but adds padding so that the generated image has the specified dimensions. + """ + PAD + + """Crop a part of the original image to match the specified size.""" + CROP + + """ + Crop the image to the specified dimensions, if the original image is smaller + than these dimensions, then the image will be upscaled. + """ + FILL + + """ + When used in association with the f parameter below, creates a thumbnail from the image based on a focus area. + """ + THUMB + + """Scale the image regardless of the original aspect ratio.""" + SCALE +} + +enum ContentfulImageCropFocus { + TOP + TOP_LEFT + TOP_RIGHT + BOTTOM + BOTTOM_RIGHT + BOTTOM_LEFT + RIGHT + LEFT + FACE + FACES + CENTER +} + +type ContentfulContentTypeContentReference implements ContentfulEntity & ContentfulEntry & Node @isPlaceholder @dontInfer { + sys: ContentfulSys! + metadata: ContentfulMetadata! + title: String + one: ContentfulEntry @link(by: "id", from: "one") + oneLocalized: ContentfulEntry @link(by: "id", from: "oneLocalized") + many: [UnionContentfulContentReferenceNumberText] @link(by: "id", from: "many") + manyLocalized: [ContentfulEntry] @link(by: "id", from: "manyLocalized") + linkedFrom: ContentfulLinkedFrom +} + +union UnionContentfulContentReferenceNumberText = ContentfulContentTypeContentReference | ContentfulContentTypeNumber | ContentfulContentTypeText + +type ContentfulContentTypeValidatedContentReference implements ContentfulEntity & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys! + metadata: ContentfulMetadata! + title: String + oneItemSingleType: ContentfulContentTypeText @link(by: "id", from: "oneItemSingleType") + oneItemManyTypes: UnionContentfulNumberText @link(by: "id", from: "oneItemManyTypes") + oneItemAllTypes: ContentfulEntry @link(by: "id", from: "oneItemAllTypes") + multipleItemsSingleType: [ContentfulContentTypeText] @link(by: "id", from: "multipleItemsSingleType") + multipleItemsManyTypes: [UnionContentfulNumberText] @link(by: "id", from: "multipleItemsManyTypes") + multipleItemsAllTypes: [ContentfulEntry] @link(by: "id", from: "multipleItemsAllTypes") + linkedFrom: ContentfulLinkedFrom +} + +type ContentfulContentTypeText implements ContentfulEntity & ContentfulEntry & Node @dontInfer { + sys: ContentfulSys! + metadata: ContentfulMetadata! + title: String + short: String + shortLocalized: String + shortList: [String] + shortListLocalized: [String] + longPlain: ContentfulText @link(by: "id", from: "longPlain") + longMarkdown: ContentfulText @link(by: "id", from: "longMarkdown") + longLocalized: ContentfulText @link(by: "id", from: "longLocalized") + linkedFrom: ContentfulLinkedFrom +} + +type ContentfulText implements Node @dontInfer { + raw: String! +} + +union UnionContentfulNumberText = ContentfulContentTypeNumber | ContentfulContentTypeText + type ContentfulRichTextAssets { block: [ContentfulAsset]! hyperlink: [ContentfulAsset]! @@ -532,133 +609,71 @@ type ContentfulLocation @dontInfer { lon: Float! } -type ContentfulText implements Node @dontInfer { - raw: String! -} - -type ContentfulContentTypeNumber implements ContentfulEntity & ContentfulEntry & Node - @dontInfer { - sys: ContentfulSys! - metadata: ContentfulMetadata! - title: String - integer: Int - integerLocalized: Int - decimal: Float - decimalLocalized: Float -} - -type ContentfulContentTypeText implements ContentfulEntity & ContentfulEntry & Node - @dontInfer { +type ContentfulContentTypeRequiredFields implements ContentfulEntity & ContentfulEntry & Node @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String - short: String - shortLocalized: String - shortList: [String] - shortListLocalized: [String] - longPlain: ContentfulText @link(by: "id", from: "longPlain___NODE") - longMarkdown: ContentfulText @link(by: "id", from: "longMarkdown___NODE") - longLocalized: ContentfulText @link(by: "id", from: "longLocalized___NODE") + fillMe: String + linkedFrom: ContentfulLinkedFrom } -type ContentfulContentTypeMediaReference implements ContentfulEntity & ContentfulEntry & Node - @dontInfer { +type ContentfulContentTypeRichText implements ContentfulEntity & ContentfulEntry & Node @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String - one: ContentfulAsset @link(by: "id", from: "one___NODE") - oneLocalized: ContentfulAsset @link(by: "id", from: "oneLocalized___NODE") - many: [ContentfulAsset] @link(by: "id", from: "many___NODE") - manyLocalized: [ContentfulAsset] @link(by: "id", from: "manyLocalized___NODE") -} - -type ContentfulContentTypeBoolean implements ContentfulEntity & ContentfulEntry & Node - @dontInfer { - sys: ContentfulSys! - metadata: ContentfulMetadata! - title: String - boolean: Boolean - booleanLocalized: Boolean + richText: ContentfulRichText + richTextLocalized: ContentfulRichText + richTextValidated: ContentfulRichText + linkedFrom: ContentfulLinkedFrom } -type ContentfulContentTypeDate implements ContentfulEntity & ContentfulEntry & Node - @dontInfer { +type ContentfulContentTypeNumber implements ContentfulEntity & ContentfulEntry & Node @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String - date: Date @dateformat - dateTime: Date @dateformat - dateTimeTimezone: Date @dateformat - dateLocalized: Date @dateformat + integer: Int + integerLocalized: Int + decimal: Float + decimalLocalized: Float + linkedFrom: ContentfulLinkedFrom } -type ContentfulContentTypeLocation implements ContentfulEntity & ContentfulEntry & Node - @dontInfer { +type ContentfulContentTypeLocation implements ContentfulEntity & ContentfulEntry & Node @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String location: ContentfulLocation locationLocalized: ContentfulLocation + linkedFrom: ContentfulLinkedFrom } -type ContentfulContentTypeJson implements ContentfulEntity & ContentfulEntry & Node - @dontInfer { +type ContentfulContentTypeJson implements ContentfulEntity & ContentfulEntry & Node @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String json: JSON jsonLocalized: JSON + linkedFrom: ContentfulLinkedFrom } -type ContentfulContentTypeRichText implements ContentfulEntity & ContentfulEntry & Node - @dontInfer { - sys: ContentfulSys! - metadata: ContentfulMetadata! - title: String - richText: ContentfulRichText - richTextLocalized: ContentfulRichText - richTextValidated: ContentfulRichText -} - -type ContentfulContentTypeContentReference implements ContentfulEntity & ContentfulEntry & Node - @isPlaceholder - @dontInfer { +type ContentfulContentTypeBoolean implements ContentfulEntity & ContentfulEntry & Node @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String - one: ContentfulEntry @link(by: "id", from: "one___NODE") - oneLocalized: ContentfulEntry @link(by: "id", from: "oneLocalized___NODE") - many: [UnionContentfulContentReferenceNumberText] - @link(by: "id", from: "many___NODE") - manyLocalized: [ContentfulEntry] @link(by: "id", from: "manyLocalized___NODE") + boolean: Boolean + booleanLocalized: Boolean + linkedFrom: ContentfulLinkedFrom } -union UnionContentfulContentReferenceNumberText = - ContentfulContentTypeContentReference - | ContentfulContentTypeNumber - | ContentfulContentTypeText - -union UnionContentfulNumberText = - ContentfulContentTypeNumber - | ContentfulContentTypeText - -type ContentfulContentTypeValidatedContentReference implements ContentfulEntity & ContentfulEntry & Node - @dontInfer { +type ContentfulContentTypeDate implements ContentfulEntity & ContentfulEntry & Node @dontInfer { sys: ContentfulSys! metadata: ContentfulMetadata! title: String - oneItemSingleType: ContentfulContentTypeText - @link(by: "id", from: "oneItemSingleType___NODE") - oneItemManyTypes: UnionContentfulNumberText - @link(by: "id", from: "oneItemManyTypes___NODE") - oneItemAllTypes: ContentfulEntry - @link(by: "id", from: "oneItemAllTypes___NODE") - multipleItemsSingleType: [ContentfulContentTypeText] - @link(by: "id", from: "multipleItemsSingleType___NODE") - multipleItemsManyTypes: [UnionContentfulNumberText] - @link(by: "id", from: "multipleItemsManyTypes___NODE") - multipleItemsAllTypes: [ContentfulEntry] - @link(by: "id", from: "multipleItemsAllTypes___NODE") + date: Date @dateformat + dateTime: Date @dateformat + dateTimeTimezone: Date @dateformat + dateLocalized: Date @dateformat + linkedFrom: ContentfulLinkedFrom } type MarkdownHeading { @@ -688,13 +703,7 @@ type MarkdownWordCount { words: Int } -type MarkdownRemark implements Node - @childOf( - mimeTypes: ["text/markdown", "text/x-markdown"] - types: ["ContentfulText"] - ) - @derivedTypes - @dontInfer { +type MarkdownRemark implements Node @childOf(mimeTypes: ["text/markdown", "text/x-markdown"], types: ["ContentfulText"]) @derivedTypes @dontInfer { frontmatter: MarkdownRemarkFrontmatter excerpt: String rawMarkdownBody: String @@ -804,9 +813,7 @@ enum ImagePlaceholder { } input BlurredOptions { - """ - Width of the generated low-res preview. Default is 20px - """ + """Width of the generated low-res preview. Default is 20px""" width: Int """ @@ -861,27 +868,7 @@ type ImageSharpResize { } type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { - fixed( - width: Int - height: Int - base64Width: Int - jpegProgressive: Boolean = true - pngCompressionSpeed: Int = 4 - grayscale: Boolean - duotone: DuotoneGradient - traceSVG: Potrace - quality: Int - jpegQuality: Int - pngQuality: Int - webpQuality: Int - toFormat: ImageFormat - toFormatBase64: ImageFormat - cropFocus: ImageCropFocus = ATTENTION - fit: ImageFit = COVER - background: String = "rgba(0,0,0,1)" - rotate: Int - trim: Float - ): ImageSharpFixed + fixed(width: Int, height: Int, base64Width: Int, jpegProgressive: Boolean = true, pngCompressionSpeed: Int = 4, grayscale: Boolean, duotone: DuotoneGradient, traceSVG: Potrace, quality: Int, jpegQuality: Int, pngQuality: Int, webpQuality: Int, toFormat: ImageFormat, toFormatBase64: ImageFormat, cropFocus: ImageCropFocus = ATTENTION, fit: ImageFit = COVER, background: String = "rgba(0,0,0,1)", rotate: Int, trim: Float): ImageSharpFixed fluid( maxWidth: Int maxHeight: Int @@ -944,9 +931,9 @@ type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { """ Format of generated placeholder image, displayed while the main image loads. - BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) - DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. - TRACED_SVG: a low-resolution traced SVG of the image. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). + TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set "background" to use a fixed background color. """ placeholder: ImagePlaceholder @@ -999,29 +986,19 @@ type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { """ sizes: String - """ - The default quality. This is overridden by any format-specific options - """ + """The default quality. This is overridden by any format-specific options""" quality: Int - """ - Options to pass to sharp when generating JPG images. - """ + """Options to pass to sharp when generating JPG images.""" jpgOptions: JPGOptions - """ - Options to pass to sharp when generating PNG images. - """ + """Options to pass to sharp when generating PNG images.""" pngOptions: PNGOptions - """ - Options to pass to sharp when generating WebP images. - """ + """Options to pass to sharp when generating WebP images.""" webpOptions: WebPOptions - """ - Options to pass to sharp when generating AVIF images. - """ + """Options to pass to sharp when generating AVIF images.""" avifOptions: AVIFOptions """ @@ -1034,27 +1011,7 @@ type ImageSharp implements Node @childOf(types: ["File"]) @dontInfer { background when "letterboxing" an image to another aspect ratio. """ backgroundColor: String - ): JSON! + ): GatsbyImageData! original: ImageSharpOriginal - resize( - width: Int - height: Int - quality: Int - jpegQuality: Int - pngQuality: Int - webpQuality: Int - jpegProgressive: Boolean = true - pngCompressionLevel: Int = 9 - pngCompressionSpeed: Int = 4 - grayscale: Boolean - duotone: DuotoneGradient - base64: Boolean - traceSVG: Potrace - toFormat: ImageFormat - cropFocus: ImageCropFocus = ATTENTION - fit: ImageFit = COVER - background: String = "rgba(0,0,0,1)" - rotate: Int - trim: Float - ): ImageSharpResize -} + resize(width: Int, height: Int, quality: Int, jpegQuality: Int, pngQuality: Int, webpQuality: Int, jpegProgressive: Boolean = true, pngCompressionLevel: Int = 9, pngCompressionSpeed: Int = 4, grayscale: Boolean, duotone: DuotoneGradient, base64: Boolean, traceSVG: Potrace, toFormat: ImageFormat, cropFocus: ImageCropFocus = ATTENTION, fit: ImageFit = COVER, background: String = "rgba(0,0,0,1)", rotate: Int, trim: Float): ImageSharpResize +} \ No newline at end of file diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index 58abb43a966a8..0a27dd40b8f34 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -1,5 +1,5 @@ module.exports = { - "__version": "12.9.0", + "__version": "12.14.0", "content-reference": { "content-reference-many-2nd-level-loop": { "1": "
\n

Content Reference: Many (2nd level loop)\n (\n 4R29nQaAkgJFB5pkruYW9i\n )

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": null\n}
\n
" diff --git a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js index 3f8ff91b579b7..7b1c78db99c7b 100644 --- a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js +++ b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js @@ -94,27 +94,6 @@ const GatsbyPluginImagePage = ({ data }) => { ))} -

- gatsby-plugin-image: Traced SVG Placeholder (fallback to DOMINANT_COLOR) -

- - {data.default.nodes.map(node => ( -
-

- - {node.title} ({node.filename.split(".").pop()}) - -

- {node.description &&

{node.description}

} - {node.traced ? ( - - ) : ( - - )} -
- ))} -
-

gatsby-plugin-image: Blurred Placeholder

{data.default.nodes.map(node => ( @@ -261,11 +240,6 @@ export const pageQuery = graphql` layout: FIXED placeholder: DOMINANT_COLOR ) - traced: gatsbyImageData( - width: 200 - layout: FIXED - placeholder: TRACED_SVG - ) blurred: gatsbyImageData( width: 200 layout: FIXED From c6a3aa2086b3c0e4290d65141ad96ecfccdf93cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 16 Jun 2023 13:14:16 +0200 Subject: [PATCH 080/149] chore: remove no more used snapshots --- .../gatsby-plugin-image.js/traced-0.snap.png | Bin 25071 -> 0 bytes .../gatsby-plugin-image.js/traced-1.snap.png | Bin 7024 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/traced-0.snap.png delete mode 100644 e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/traced-1.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/traced-0.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/traced-0.snap.png deleted file mode 100644 index 93d687d8b98fb4668910812a52f976257d40b95d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25071 zcmW(-cRbYpA2*JUsB@t+GtSB$T~;!4c1T9(a7ga5XUJZeXK%^qE199}aalP+8C@bo zq7XvX@9pgd_M2j`!$}g=j-_vciT{#k)EBNf`Wok2d!xW{vQDUqM)?kmAkN6 zjDo_hNk>!djz8sk_iC1-x!v;WT&acwy_ewXSMsPbNAHh z`^Kj`HCJ14wK?>WQRzb>GO~S21&>E&4)Hc|p_ZjR4MjOdA09TAOs#Eg ze$(hUoZa|Sun`m^8T9S^5ozv-@&10#W#M=#@^l}HqiH5Z6B-7iY6{52pL|3w9OE4F z_R@$I8TgYMxNR|V&>cdp0lBGa$`v`bwk!OeaM3<5F&)k!B4B7}=>KPl&S2uh+U}d+ zL)2w@6+12C6feQZF0725vvbThceG{ZwBSkt9_Piol7K|k+2!eFoxqUB%rs_Zc6pVR zFDm2D(-iUO5D}{_NieFz!^1Ccy<&d-!dF)IpcI@@o+H!C;Yf-0Y~kSxxShZo(Y?G4GYNy(p2jH%!J!udO4Gr6n0oP=BFa92Ij9G@RkiA^3k|yn zS678|5T;Xz(MXA4MfAcRlluJL*`2`eBEhm-rv>{4q7eMjw@^sqO>I745OCMdL?qH< zb-ceD7)%A-Erjet>(Y_Ijd~+tXJ6xu12+Gl4n;47gB{?F3pY~GL94?#n%;V^Uetku z{f|VRU5_q}*nr$3gO3O)#B+6|vYQe*M4|#{s z5#a^4;Lri~ElZ9#vrk(Qo?hiUa2y@$mYo3~n{6H3$Hz#Nt$&on`W5{nGEtOJ%Bi$viXc;hbe#W~L`TN3t79l=Ie z*Cygs63%QpTA44~q$9%QfbB(fg1x~tfZe|I#(Q<#&1_RTm3TOF3*PjW2RwRECis5S z0Uqf=cXmMpf9FM=(sU^AW>r_&oZbi)d#Z~d>m^dn_Xi>;^k z5h6V<>cyG>zO@fETAzpq;lW5&)&oWYw)I$DEcKTP*$HtUdpkKTH zOG|KCcX7$w6$&859PlyurvX&5?4tl|oCQF5n`WC#0;eGhV$$ZSw#OXinzrKES z(jQ(kt~i#?lAV<~?T0IJD01d7T??|^C|*cQ^>Z;j31;g+L)rvvf?AHP*qhU|>;7wx z=bQshQ(o4M4z5b~_iHDt4F_(}vTqcRrHG{vH~8qlwk+~QihVU&z6^m%^j$VDU^94EPBW@;E`)+lW%_u2p z-{^GpX1#4l#JP)CYON)wXLH=Q|52JhvUX7BgfnDzEgVOtCXi~TaZnhBgMog*(n%w9 z{}%&-H?mfdx2Ny5pvbjLvuQq0!>9w3opOnL7!g8+fkQ$^r`ZQPtu*n!^z zBSe^5&PAbG*n(Du35ad~&TzdeI>wrs#jZ+8NlE_OubM5millBTm5K57c89k5ZFqS4 zj(EEzACI;VpZvMdJ{Gx$kiy{jBN%9x^nIiA>qyZ^7<%CbRV0IaC?5pmNk*Nve$`t; z1AK}l6f?E9Q%l0M$MIhp(;ew#3?^XeJke;~oP4!PRVEmZEz)Mnj^qD<`{uU$Dt{^! zt$G4(16SL< ze8WkDmq#BgN02A(qEom*if}yP>R;g!5Mr%K^{$%_4SjpouDx_(q~H0cv4Dwm2-ASX zT{fHY0d9dT1R+;PIzK2FsoHsSe*W{dj^kHu9;X#Izn{#u=8ue^`^DkYg5NKoAsjd) zKQUSs^EH*yA)&xyXr5sR%DXKAJX~E0-D4?Fv2Ymz=?Z1KH3A*5vA31fVH&d4u?!z| z&Yul_s_nP&XMU5{W@>zGH`}lx=w$mo*7MM7cmNwFMc980GAG_d7e_=Kyzm@3i}2gb zH2?Q6$bdQ$T`6n>5o~a7RlMGXY0qbqX>%Yz_n4NKM3k6^M=gp${#edWyD}R$3ulpIah5 zIp)4-dnz5!UjB=HcZBkfD~1 zGQ_Y@#5Jy=xI&qi@7P2dIjv{x+HJk|{YNRn_IkTTj|HMH;}Sle;P}={_gZi?l&r`w|a#z>RbQyYl~Z!EqQvT&^<7u zCqnyT!2Tw$+gxk^;1*q2l8dF(kKwywGjnqq;Ys>>!~XmC5Cxkr9H zY|fS%#-M47Y?>KR;6E!V>fL244!nHou?)}$9#VBs>-PHhwdN+0(O)`3(m2jdWjBid zr>Dsl1A*i|BDJ5}J8(Pwb^1N#=0DzKZZ6N=Ar_U>p%r2K`JodDC9)}%y)tLGQlW}U z>CcR+EU%H#(YH@d#ksF=k2f)To3rgvrwwKcdmL>_I44uLt0faO+q1X+=G|Ng3K=Qj zn3^Gfwe$5K9y~}`YkkZRt?_R{JbHqzQnzr}DIaz1`tL8_e(sKXDBm+?6nrrtjM!Q@ zbAJ1TNEliKfY&phx2>!Mcb;}?f7IpFSgD{?B>k1_=&Fo-dVfe{d;7_uLNfOad%wpq z=Pq*p+3eQ%{pAg%R;jJTn0NSK>Bq4urMvG18V(e81K*9MRd8Opl4iOv)~j)H@{Rh@ zY+K)x6LRPG?V7gXkq2EzxLcOA7s~nXn(yuFbQarOUQg0qYI2y~kS@S&uiW3~yO$=? zI4mQy{GTI?{#FF#b=!~}*JfL%`t}$H$_uffr1S4kO>_W!l9gZ1k8h`T)1}`Y5O$`L z;>1ZK65KC{tqB-9sT6JR|B#-t?I2+vbBJQJRr3pq>@aUF#y*OkB)f&A1vc6@W?yQK zzN1AH`IaB1|BxehH@+JG;3rGF`p)^S`7KlXfgte2ALO`B|Fu7{dkOv05)iRftEsy~ zWj#k;E)zA6v$2Pr|5sPS{x^H)oc=A-JG(Bev{|WR4~W09M0dBWtrL~rK@>BKygh`K z$5!qPm*NY}+*keTd8ldA4Vvh>5yFANm6gddr7ir3&n-@Gt)&VR*phA`pC+VenccZl zhf(JI^RN9e=gr`u;yH&WelbmA7Q>hIg)VtMqzi{(faOXiR71q|A;AB%1isd6(v2vq-iG%=j@#&Df80s6`%%k^u}Atk=1)UUQ5;~ca4 zmHT-C7x0y5=HFmwI)+%kY(Iof&|LtsBxY_Q&eh8DF-a@L2ii2q=4_6SNC@?7=aZb7 zpA|o1XC<*`+^D6Ce&?yxZZ#$h1uU_$z9@5AN@~W9-;M|O6 zW(x@|(SePnc=mV%V&@PtJn_7O^Tv&Zxv%~apBkzAp7SnlW$T9h>W-apC!YM3xL(6q zt9;*6{^n9*^TwZlTbHVz9A7)xa67$e{WdTWcK(j0K7`%`#Y9cDB>~z4`(6|Wz|{5} z%uB8VBC_`K2^9{8IF!v`sK8Xng?(W|4!scUzFZ?TpXS+3zMQ`s-?+3 zPuQ;#1^}^C)mXD$i+rtWjU~pY@U|ICZvj`lkG6S@MWZWi1aI%RY>V9=>O=@`Yv)Hc zz+0Z)p2IJuDz2Uv*27(L;E7gEla+T6s+V1JGMF&KF&-vp-(xrzJTf{G5af?0H?8B6 zSIzF>K%x4vOEGbc>*Xi*dY3#_YUig4D^CTqYL zFcmR2&BRK>)#m{^FDx<`VdK!GWSu+A+Sp#+donO>-+UcYf34&`#4E> z_KTaFDHYn<>2;;HH93-(ag68E0j~a8&I_(dj7o>&$plZqzHnPJna}JdL;{S8tfZ8# zhRtIj!lcE0CQ?jFY^Ri!Lxu)d6`sD!EgoomIThgEG2iD}6a2I6VOfNwnar)cLVI}Kzt?j*bo!YYZ+$RO;i5O+UKB_2HXzBxgDr5T&3p*M? zC2~GDm&e{oFt>6b@qW%@obMr4L2n8O;zp^W;yjrI}`})h9fV7AR z>boxmgMm;3Up}RX;=#Cs7N;>()nLNk^5WRX0#o-xqQ*uf(9HA}G&2hgM9@Zq zE|HFGedc%S(DY|~(W+;Tmn&*svzgerf3@xr0{KkPtH}bcu36W`MxOy?q7GWin_K!u z-t#|9Eb=<+GoX)4OXE*6GTcA8_=Jf0uribp{JF`lBj0pNZ(YCrk^i5a*zcb29=JZ; zdZ5`k^&HRc)Sy71i{;bovVPE-dGPRE3*H@y`=vj_ZgB7=t8=(us$*bsM8Z{wiYgL{ zjXST7u|=HO4VUHx2oiND=&Sz^{dqLi@^lQ&DR>=!rX2zxDnCn!rz;ol(^_iR`c_oE!&TehpH&5SpnwZf%*?r|!-*^q<=A5-IA|i12 zJA9Km&+J=o zr)(Ep=Z;W^Q*Nr3Ce2)eo7|M@s_TPyGEiIg;`H}5nqhxSc*2WhnXGJHO92w3#A9v%+ZDor_Me+!Y zGt)UudedxD_l_xBC+HM<%{#ZQo%}mJQfm5pQMmcmYc>Mu7Set7I*au`bi4%|vfEOI zSHe-#ofi{+O32!1>p97I8EH`hGd8paEp3tjc|xQncuQ~C(CFYKkTkZ%WT2aFM)Q)z zr=3>DZ)0|4x2Ur_2(|L>Q*g&YV$Gin$&j#!m*$ASqV~ejXB5r=cDHC|S$RGjR4~2H zC=;~Caeqa!^B7Ot%iDVr>O&=#qRMwEh1fvF^Yn5Ya7oZZo~6YNokl^;o1m4!HtTV^ZQj=U%b~*L9NPtbMXefB$IwvgNSzFsp2m zVY1H1P9O{BR<8!|J&nn=Yp2IgPN>tySX;@azU8KsB}9c(6YVJ_SxO(A;k0h=!`3s_MIvyZyO;vi9Wr z{mxVBa06J?l(>kWn7JtHQ-ymG+`O@C<~33U`fvPBDgEX;`u}3X83u?vmG#&UYhy3@ z6a*%1G$yKynR4_ihFc>w!kBne+uon$9D@l=UWxE@EpRzNQ=qYFpOdOrALM2N9Px;q zAp0zqp`Snc9)EO%xV`WLubvrf0?s}*R5~ZI`@z7>Al*go8zrlXpxM*oka9Hs@baoX z@8m8au)W;eZ1}R?Uth%w)wbXE_aWOC!u+FoSZN&DjG2rR#4`1w-%?-Yq3VepRU{J; zXL+UWAM#Q)djEqP;e?{l`iJ#X*rYS6;p!QNv zo8I#NQug;CwNGo(_r?4@chYUm#$R4_U*0)N|NijZ2$q;}Z1dO8??pVJY3)V)07j|{ zb%huj-&H#$l$pBNAS-x|>%aBX2sAyG&N7y9OO$rlSt}v+qRA$mu1FnV7nMZ;7kI|p z8F8?APL02E^}M&}q-9?7VA9n-;Z8euyKQpG)j^bk(0U}`7jo`PVNmfU^Xu#Rt!|y9 zK7ZGz-|f{*^q8k}BpNx33TrJ!;&_3N2N&kU|8xDXlF-n=b~!(>K#f)(n%a#~jZOXT zsWavCMv8V=iIXCXGDojdVw0}n|I8mCBEx|T_1kL-Vu&?Z&HmLf{@iW;KR@%Ub5h51 z8@5f$)1(g{x2717ej0Fm9>t8rFv6FJP;5~GJ%z3#3F2ssNWD=RPU??mPs)KpH-ksX!UJrtFk-&V6F z_5)6C-0SLonGFY-S8TkRV^@;ra&l9tz=zH0FSPnbBThXy}C`=dBVtB+t+?nC< z25ozMxh20^LJz73(mgpD+CIw#7_Wn%k-)viB3g*LfRHdws^Rq{5A z+z@jwt9lpQq$^hJs{n({hICelfcvTfLW(N4#i`xuTYiotYt>y*bp{4n>T)I1zzFV6 zY#QJ~B2p;%^}AyCAVjR|@UOM&ZvuXWhFGSUmdB3=+cXe@^)1!1UC`+)=T9EYc=sERO5XKbANd5XG`YZJ!)FAMFD= z@7(DhYSwLq6`_i@-AS9jzU9`lbBjT~eV&aaF6@yOH5@}F7qfdSVgTi#G$E2U7`gjU zM=I8DT8=lRmFPKJi*x<`B_yNf^xc#TS<^7Q>zvd;sK4>|{8Zw(K|mAefF2c)8yvh4 z6?*a!ug*d*^wNObO9AcVE3$bc9UJYbrk(eyHB%06bD8YJ)YWv0)gcj7M2e+hPZfs% z&xEyWpz+w>8VwoB1F`?G4%1#`DUnrm_nOUw`&u96bG4%F83pGCg~6Qfo`aKjlfSul z;hN@mi`u*Onjh77Hfxj`bq&B^c&7g@pP%$GpwDr=UgL2*>GRW&xvrESvweXdvS72o zg~|*_1#=BR#+*xyM1HLS%>SL5yPRBCJbZn1O(h2nBJ8nsR&|fyHW!#Z(6^%+=ti)S zWX%b|pWhQIVlFC#9K{L&USMg=!D(B;rLF|>Ppf;i<=fzxY0GOT<)0qALn`L~4tW4; ztZOqRpBM7U;Xjt`Z8jtBD>B@7^_!Yfco8L3jhe962E98!S*m}}F73Q=YV(S!{9@lR zG|;9UBsg8ZrdV0I5CNVN5O-00WyB5szJYBt7>WIVYIMdUC8X{(kig6*2Ak)sW3Pd* z8>+`%Gs-XEZpa>WpJJj=DEYu&CctBFDaDzT{rmSKO#Z&Ow(NXnbaS>6>4<;F%D}<(1VcVYwjyEdqjl}(idP8LRE)AwDXbj;t zHcXjm49KwE^Rw%HB8qSu zX1J{0Ej0Z9F)UHrF7GDtY)&Q-t3OdaV59deRD*(UkXc46(rLCXzrf4ee;`n$AO19O zu-t%`9^Xa^DKShUOqP8Kf2tZ-*~OWOVB~)N|!n`?sDcC z1&s!?RukPjW?EA|xYsryE$)eeq6o%)px3Af`#)a|<_?+^_E4A>x;DSyS-xd~@;B#x zqaS@ zW_dX=PY(aSDgw2WU858ahxV~9Skl5_lv{lD2D))2!UGBs!x;JEpI3jjfLeu2^^6I3 zmm!>WoKumo0fjU#r{~q?ph~pt(qF&ET#P|FiHY8dP%(^~!Kt<5Qe_EHJM>ll z8M+E$V7pUYZbMa8)z92D^F21B{^3kLr}qNwl~~1`KiiM@elXIu{TmYHEEw58XphMs znaU?+ew^if?_;lQiz)tThD&UE6ZoBevD~h)GT{4n4$dzDQC}YrakCgI%-8Q-tq>~u ztqa@S5&qJ`{Ay6aR{jYl>PWm|MYdWLfrS3vXnoL+R8@p7>A^2i5T17AH%|7v$XQUpus0 zTyOdabbLl#r*zNfnvGo2CgLzDfWvJ^M?@V7G1YiTalKQtmiD|5c`$Wu`Ip2Pg!Qz2AQQXevuZc z3t50fr`3@&=v`lroDfQWU|0w%nECoMwL#}U{z%oaHR)+~X-=aQHB~U=A8U*g6!={J z-1I2}Ri!Ofp1rm~R!f?v_?P0(ayywEclTdc7grNcLWX ztS{d!4^Ph?&$mnK>j_QxnOLnZ6alSp<};EyKq2uUH~RT=ho8Ib3TY;K_iBv6df6TU z_HfTwET?8NG?o|cQ2O4!qY_MwurhVA!m){bnGD(*7pi|Xv^E3niNmZM=anLp-9Y{R zOYsQHS4w@0(ls4_WVB`$y-_Q_&LztS1!|ICmp(Kw(;DK|@8_?+KjYx$mX~L~r!ZY8 zQ%PSHN@txyjN)NpNuk&h(gt#lvl%k-8N~>#0E#)XHL`%xW8;Yx`cT z+ya=l9G_5dQb=@ID&$t#GUPzM?#q*Uv zoJx&S2Q>IbsQ|A4A=L0KV`jiYP<1Y;ro8buW<7WAT+r#^&H1IJ>?_AVp2!yHi`eVL zhNa7nRJ;3m$^c=8bKoFP3znVXHK0@iJBCp#kjW$YgL#~@v$NP5|456%uZP_& zE;$MP3H=Tdpt`c{(7sM|X&oM1WqbKOer86Y!dZ6Y@=CfH=CR+&?e&wM3?6c0~ITL*eG&M0_X7nm2T8> zL`%nZpWlyG#`iP%-|Z=*@dkY1vBmg%g1;iinVSsM=$P6ha1)&prRtar?kSoj^G2$G?WFx|V`Fdo9iC{5uMqNI|JCZy>==cA&hhlk@eQ=rVIpBF><@Oa2a= zmrbfyUTTM{!FS}f$ZM@(Ax6CHJD<`kkKN(S48ma#?=T|XM^XR|>V!9qcydBHv6|j~ ze8V<)*UT5W<-vZE`S4ZS07|l+l!U~2kx*C6T)zvkFrgPJTvUo2@*WojWIW#ct$tjA z<)YaBF~;AqMRNN?atnIeuz2ZjrmQ`u!cC=bt7+$$pK49~8Sxw$`=;{rn6BX<5~zm0 zc2nN+4o=2L%HMnSqi+a@(&81%))xeUu#=5%c5KR)&Ku1htq{wUWu0I%03>nw4E$;- z`>n==*O9ywl*^8Ao{(qgg_t^05?*Bp)tICzfbYR1*u3GZ&c2-J;OXnDCK5#o>>V3p zGN&ScTyjG)J~@Zmes2hWX!XDfqmvSP@a5YL+v9OS<{e)b3fibSiFZ3$y}$Y6m)`@S z8+YV`|0X!UytX}+>{)@K z3pu*uZVBFExLj<-%c+4b%~xFs?~)r`#WKaiY{94{{w&k?^M@w!PmI^-GoI}5(=jhB z$~7IxA?qCSxO6}Uo5F4L>7e;!XTXw>A(q&?66RUZ?J}U_xc~V0yt4ncc*lYBlcBwi z?J2CmPh41k>aE+Zj;+69bw23dTV~Q^u1z797D&0+Nf(*sVyfbhZkZUgV@htFIk#)sp7Sn`Z9)mQA{`;#{%5v9XmgcVeKj z_u1M1=r5S&pKciKk2IgeFA5nc+`lh#zj?TY?la_eJ4? zCi0)1C1(CdU*$_R-2rs=Z7HMW0t@W0KE0faR7t|~g%4x3;e>rhyS&$fikQ6i2c%^r& zbCq-R_N`76dpo^duMH7>sZ|--^t=fQoo_TDd%x%2#lFMcnt1)uuGF3?77CLa`yj`N z`uHq7t%?pciKe-w#--ioQA%YJL4VpsGlhKfctz!OeeX2XEqLu7g9gpH5;c0B0OQ`9 z|L%xMnVY0gL9YLv`__3B@uctFPeMh%(SvgFF-V!XoPmbsW=SkY#s&CpLgV<}jVl7h zns(!;bd#>W9Kf~EF_fs&E7ch|YQKhVCHo>lMZU58R3R%XYk0*A_Z&tD?J@*=fENjf zBlVw00;<#cJ!fj9I`C}I%`}~^BmV{M^QvuVcoq>}~>Nsu^SnP+%<14vUq4u~6SLkQF^ zgfn6|S*Uj3Q7G=6efPI-yrYFG4vkhG2E362L+8RfGnV=RG*};cDs!pTKCg(8nhuGn zMxc4ZAaJRoSegs&7@FJYa9^2smIuSmzqd0aPp@9TaPh(C%qIK;ax}c#3uX5pFB<$% zBIUxa%j}C(W1o>LgT?0RkV-$7cEK}iyB30Jlc!nEi%~Ab$POH7*yoX)B7it`_R*l6 z;kF06O5KvSo-cEE2C{*QhHU*GIuwo`=ZO$^=c9pH>r_KVMFK{;jru|Z3~3oyc~aDZ z1{UHeDX9peVIN`Hauz&cQYn~Ati0f9W~#pRku*?imo$ygk?*?g;~1S+R!WJlb5srb z?7FV~ry_wsnTw%Y-uQTIcc-&D_ zhEh^4T&efA&r6=zY|d;G3y8Zq9h6>xRwJbf^IWsmvCXum3-P37kiisFEjv=iic(Q7 zy8&{=mKlyAXhMyl8fuX4hwTgd`*gw0T5Y4D2A{o;Rp&0^n(iTuOYB-_#tq6pdSDwY zO)p*e%c@^4D`-H;fRM`3d6nV8`Ckr$54K_E!y7pAzn+gQQO1b#u$$qO+q~4v8ng^h z*iARW8z&Bq%1gWcdgRx;Rs^LSTkiCPDi$hMwhQ+H%hTc$|3@?7YbTYMLWA%_*X9sU| zeaAc4C@JF+IW05{c%d#vs4ts{T9gMAM%oDVqP+b@X7f8%k(6Ok6G1Yx0zB>%XD^#i zHNhm>K=D9MCanP8-8dYNwEej0qTp}1tmSLZA*E#K^-7VgUw3MkVKK9*KnlP2;0{a& zL?A}SQ>%A>pP}h(a#krwZS?dFQM(sD`la)|x8gI;S1CF2nzVNkvnj%>;-tz{=lpQZ z9DfB8Qi&JgJYAs&t7z5GH-u0MaJ!oWX8{r4bxkK(wcfM@NX(Dq`$|QXOg6th-jL2C zy?MMRQMO5lF5)9k&&v&1Gf5JNBl1X%&SiJEA}%2;GJ7u$c7;D|enlv3o|={th0Prp z+S-!t7ZR#!zSp-)|0xw(dx?x|O*#wF&rQ5Y8G}jeaJ+QR;JbGM&f5xyF^|*BZ|m~J zaVga$7KFyZ&=4LDnN*_T=h#kdi2AgkEZbTvjBq;^-kt1-=77-GU848JZG)Yc(SfxY ztxpFP1BDBwDx;-(XEqb${cgQ+T88CdK4i#O9JSyCRGAJdDb%| zaHvXTU3_I41M)`i_lH{Lbq1u;7bz&iG?#yN#aAAG)}f{moXFHsdL|Neg(rf63YVaE zTOF+|L`Oaf=7CUwafuM%t$>s<9j}rEl=XZ-(P-5>dV8|er9!irCeJF(n_$RCVrk&d zx$o`NA1d9~<=aqBegyV^?jm#7GPMK1hE3u-8b(t-!xgeJqB(<73<-5%})?CP3e_3?RN~!E(~lc7M27HGwndD8+o%cgdx- z#G&q?EhH{~tV&qylD{BK?A2b$FD&rd8^JeCB+cM@aEgvHE+PgRB2nWIUe$1YxD+iV zdn$cXDg?q)jgT^D(5*(?IZ#`smN93@1_=?|-YKNQ9D>c0ZdFg!IeKa3aPtX8u zTIh@p2N_gvvadfO-6U36&VYxG=;dPSO2}ECcKSgpwIORW#~((O53K$=jV`T8U>uWX zIcOyvr-R%cM5G7FEXM=utn|#wO+CEJ7txuRB5XWeM{0~Ns=u9rR08edQ?Ti0M-wFL z>JCDQqXqb`paJWKOF%_UPdvo^>u~0v>L#i(F>k{;$k^O+m+2WC>NWm+>@VM^1=*!d z;`mo!yDzJO$4fcS#CQ!zQ$m3zU6P9&I^)3}^~Q<7MP7$8!I`4qG)g)uSPt@$JYoL@ zxW6}0T&=$mluY$Eo+Ju{&1+@CI`?t4pnPe;=u@PWoDkX{eb$HbqD{h~si=`sr?N?1 zCpa&kCTR#M7`obWLCROaRe+pX$E+(N43QDwfmV{TGsgH=m$J0dRb#D0b6Ci#o}^Fc za0-q-E05e^-PkLbJT5Z0WjqudwHO{U{0suNUzbaCiXE+DxS0l$-dVj*<#Lcob2VnP z9Q2q!TFCD`7DzKmfot(p3zPIpJhg(l!XmPSsfhi6ici@`GSjkEbX(V{(GtpI555u( zf^+-A zzt{YzuA^_C!^yo zBq3+|))AksFA^HZMFt49X=6Y?*CZtYo-!Q=;p^&i$?rqKZ+4-STpaQ)C;DJtWK@IN zl|*iKlg=@;s4>UB(iE|F9Ue$xZX*VXhj0*RL{{@8BO*vil$4&1KbrH4 zxY7;+LO97O%2|}WTWRj>INMSf`V53DXr~gB)DgT9_(%%gxPn+7br3lHUGhl@y{fPH z8s4D^h z7%N0S4a)qRwl+YDrE^@rP$$aci@P0rMYk9Z){omZUd8sK@<`F7K$25~UHc3ylo`GJ zoSnQrodK|YX#kKmytH(=qndFMty}@&c%iC}xH^C-&K8ZfpMj4dXDn8Y{@)(KJzFETZ!)WF9?_P-p= zfShmmL6=i&nG5aTOg-I+lxuYc<%79*u099;O{}zFd4VxCL(|_arVu%JXMg(-JT5oG z1M%Zup|mKKdKl7|ej)8e&UD|k1G{{HXaJzNeosPD5=8!&Hy%XLy$AeVXPaVg{ljOe zEVN}Us3cOG_Q@&AE7C+*02=rGMCCYJSt+0ghjMspZ30_yc9tu%`{Il1Pc12yyVSJC zIQL{*ynI_^?Gw$p$3T>>h7b+~rP+l2yS+X;aF z2`N#?YMma{yJ@JqJYA}vIk~y&ti=NMk2e}-aBrQ2)^?*kUM!`)_3$3}`jyaeW%^Nb zLZf}&jJGbi2`!cLdgoa6RmLzmlPOYuCy&*LN72sh&`xVM;pR@}b_iQx!m9 z?tl)NUne%IJ$$00KEb00?`S4gBUinFO6xhEqluhkhj?Kb2iF(8)Mv%E zhK}nplu6THlwXwRl^tZ zqSYlItTwN2kCQe%jG5>~i~Fo&*KS#-*okelZLpSrW&HXVzMbZv9=;m6D3rYawB|{H z+mn^nqp8l*!=T-lorCg%W%&KiQztjH&pi%0Y1ji~M1hoWSg2Gn!rtHtr%c6@kVz0M>!b6A^k*lH3K?s#kXGwUi3#n)5Fi*wr-`PXZ*Y2}xHK5H91T5Q&BI!J}a6te{iTr`6E= z=I%C>$kA*mu@?u;kDHdJj1-lDQqr&k2y=o4*&}A(>kUg&@BPoSZsiccF z300?ut^e8>^WjpslfIlQ!0<5_n_VzmI*F8}(?Im78dS{-rK!RVHQ}IXZsUPNRbbJ? z$jD)@%g!s-`Gs5StEMB862f??1nP_29sPN8hulSnUtS(9KiT52&ad%bBQ+yh3r~N| z9V?yGoF1NjYn-xue&t-pUialRXcwv08T7m=3wHMN51+{)}Msd>od9?4RS;WNBSX1L@=p$$r6e?!w z7*U1|4qbo{Vq!|aH7&)!--o`XieTo8Pa!7Z>+e>VrEyhwK&hGdV&ccq>b&{Ua!op_ z{O02fo*q^Wbc^1>E*R; z*^+H1inAZK)|c`(+P7$5?#AD)wXNA-b9<6!x2~X~u)H}R+TI=v4#A~BT+j|eqdMyr z;c{#`rtEhhaEF__0hC!HdjeInT)?N-^30P`dl_nt>@e^i_r8%32eDAECiVT>iu0Ciyn#FSpPc&f9EVeI46gx}hjx?%L;pRmrPwwy15+mMt>0 zw6XoOK0|jbFI7MiHmC*1cg;I?v^qAUM)?WuQRDU;b~spHDDjY(R1kU~{Bj{u4v=+* z5n3+neBo9GuXISMP-q-+Ks|bR$Sc}}ifo-0NhQYL6YQ)A;Am3O){k%0|46K}PzgziI+CHH%j6o% z6n4OBwVA8gZPrP#Kq`S>cLLvJU3lNUws~Ii^oYwa$>@QZh0l#ddd&}brGJm~oa)nZ z+O7wnuV1K|ymyx@KAM!wwg!bCK7O2ERJb`a8Wb)0RB^6PaEN5BBMHDm7r$GN<6 zd0pHIO!e}0NK2cWP`c=6&MJA&pb`>yy={_Z4@Tz>PhSzb$L7Qy)XAWqxvMvL3Qtp!56VAqi6K2wc7(m#f%9)oN z6!w09T^=bQ%cnhkug6SH63Y?KR1MX)fzB378j`-YEBSFLd&RO(I~7Y8u7f|APjKSu=8 zSmr@c81jsa4Z3ra0mQ*_cSOvRyc7d<@3d?JHB)yIKDYB^^8QxI=?=-wBQS8N^Iz5} z;c)M_*WxlGSjf+#aA%=@hCK0&_QTNU?LhYZ?4Fyvg&192^_t}?Ne{v5xZEDlU?&xq z)5URIPx^6Kh@aw(yMMY{u~_H5@r!DQ~B zqG+rYgkDC=Y8{b!?Z4SjaRLV2u=@COIWJ!=>D|M3&xJ;7(`HH?Q90uVv`!Pc>1WJm z6NqeGFwzY|fwMsEeQrm6=JIcRvaAFX=qowK!|+(xEhKz^3J(5!0Tg+uS~x;fP#OcY z|GJJpv|I36@G-eaqM=W?=m-(%gFwjU$T4mo;bIAas^tcxY(hi?FLSTHk=Y^y`g9se0R2mNwON;oA-8)w{vCcz!eGojsT> zFRI?$LECG?O} z*3RHkh|MPx&GOUa#pOh5Zhax}mF(dm@%1D z^_hshbP-5`w{_Lv&oC&^{r~>|&BrfTw}fk?%uP*0j$h7EB;>w=Gd|z)20HSuOj5Z+aL8cM$zaiVllatyi+f-` zFSd8lLM#)IT`Jo%qf&W5^jhF2KRxFRWCg$ezEb*VrJ$nnZD;-L$hZu{jWRh+NawLq zC+TcU!0}t!>uz7?i%$R7(Y41j{r&$i*QA+CLfK|66Q5kx47n|2b5|ck?rXv(QZBh` znEPcaw-6zpTysmwJ(qGRce#af`KA!%&hPmB>G5EX_s;vA*Ll63HyfG`lOBFsPkjO4 z=X^MCAN;VtarXv(Zf+&6Vut}bwv7#Mi!;X}vKDgH?A`ke?_YJXvdm*i;ZfCCbFxBB^ZUbR5Gh>-0@$0%8m&L7`okUF5OErm*f{d(IG<=-;3w*@+cLaOzz$;P(vowI6+{qgf%%7=3ox4(pJ3!k0|PIMIA zwmE7p55!`yH6v$I?2;rGh z`A&W3)PyqV^PNLN#MC&$pJJH_sZbuX3^?ns9!w^}JX}huGb=0W?(a<+!0Z4274?!o z)_lL)Qu_m^`SzPrjgxAo*T%@HjKX7l_WND!K}^@>x=A%S72I|c9tJv}Qt{}BT55FR zSBx5CnHJ!CM+uxN4+kN(1QQdWmIs3u1yDb?^Wa)Aqe1y}!`no89+tLGjC2mrZ$Gox zEh}0L7$SP?x+tH$dtG`*A%sc_b^U`P#2_2y=6;wNsDh8GQefzq_%PBoeiU zF_H%n1-^?|-#ar%_qz}7ewZ)nPrJC~|L4yr?nbHq+UD6B*J3k$Rts&88=+~&k}Glx zD`S#Xa~Q6$_Lf=RoRFXQo8d}4;y?a8c8}f3vivnQYdwes?p`nIAk}~Ko5KAU;4aqO z9I8Y{)0?rG!!aK}8uS_WgP|Bm(gAfixXh0RU_q(C1WEFFcL^>Yl~G%e+FDg);=lG4 zQQokt61?Rb5~WtRTJf`1XRxBKu9N(3?p~ecu0}xqroOb7fg+_nCMeV6_KiDvU5K2~kW0!y-N+I;jII z!HlLOrIEy>P$~y#j?Kq3Ri6hGI0w~}Ypgd+LRPm<@I_{HA2cpC*;ORrIZo(j!NXi zP{2di-+YzUucEG&KayMvcr3@v67h+${0X0ue=e$kL4T`p&lZH>2z4f7I9TvJE4f@R z2s2wa20b@AJVqd=`EH11?izvjNFz4Ep1Gux-mpBK9({#sP#5?8T9eO-UA zh;j=)5{#kKce`uGDSe+mBaC>>LywbN1bpy#5Ngru4W=`EI8rMQbMo(2aD=4r@hgD4 zD~=E~H*t*Gr=G#Veap+}HhIsjUsN&!4FWE1TjP<`vWWH?x1Ftp0H|s7ULtWB_je_wJ%*=khrE%##b# zfg5tWjZ$1CBToz^uMU-9e*B4Xzrg@c-O|ETHJDUTa>u$w`Noyk3bjT!e) z`!(HYq~jpsqWIq&##vHLfDe6KFDhXL;5lstV_Bu7iiW&&v_=3TsPGw+%AqGU^@)M~ z`TUk*`llCg_)`a7z}&I|S{x}|0Lb%87k*H$k`*(J(+wrR;a*Mo+?#srIw4Pea=e`b z1AF50#qllU%jm_$#p4+p*f?lbvVyc+G-&9qMTM13yc+)t{$#K2&hHh6?zg9>=UePU zGEe;7dhCE;Vs7`2$(^v+{rPz39zLD*g+qHn7{AqJ7pZj4$U;}Ee;$)s?L0GzrrqXz+LIFR!+#Uoy%QmL?s+5eAU~!3f|+M1eOz!%Ndbn^*La z#49>&X^$M2&UVJ27BgoEwH;h49+oRt`T#g&p^9M<0pYm zOcNLx%-j{zF%5?i7d_{f=*RX}P?IB76^D|+@HA?-cX`oeQS{vT^$X?iBJqJ*gmaA5 zz^#dfodp}ytLGcHj!kF3)j(!}VbQgWwgVO)ywg=KAH23J*OQk9k-?mZ-;c_9 z?4HP~t-ehN2{~H4;r{d8TVLOP!a!GTI8Uu}`qwkFY+WL`G2w4R=dxeiWaC#(q9yTr zb+r_Y8I$5M16gkZ-fT^~mo6STj~H4DpS)=q!%+oypUo0?AV?lX3pO^B$@o}d_!(R8U z_>7A31ibm;<$wSEnD7rrT{P>2EZBhNLc7_|Ud9c!zaQpV$78XX&dgSSfREWT#*mR- zJ(5DK|VarnnPM2YLtX2oVe?*CkiIg1A8hgTpt;mO?B;a2*{ z!LewnATyqf&?#npgvZ#uxHp_?{i47j6QCE(g0asP`r>tGEGN?;lq#I)-~HbHV7-~G zz_r6YQpS6qw*}y0d1TI97ya{d1_SKM*?eFZ`Ay3?_~x?T9kRz)=)cf*T9fqF7EA(C zMMZ(T-BQv$2YYumW}{{nfj-eh!@v3ON~(R(@6h85kz4&yh*m8rLwFD~Ylt+IQ!jv= zoahRBDoc)|3Kl?=6^-1Zsn!PEkS1eB)+JOi)GeDKlL2AVH%_+!uBo zo3V0y1~lC&g0P~!C%qcM=s|f)+K4N;rjLEPe~uMF8?2^~P$^J7Awq*On~HyM(EE8H zj@ak{;|*w+HCO7Vf4Y_;qRT8m5YY%8t&P^!9L6R)5GD1hxO+Sbo9OMInMZdo* zS(*ofn%`R$M%FC@zUGUjc57~JV^4_;;g9_+S;7u*P zW8T()vg3q5&287JJ=-7OlYW4^`>qLz8d$jRgNM{ufc;@z8H%ZOl}oQmrh>0KD2r@I z=0SOf%+Uq8`ljKqWLg|5+kSNovyt+!_ z8PMjNpQy4c?>1BvNe8gIYw0tNk*SzJZtuH&KE4as8Wa0_*>5fMJKLxqPciefEBB zy~24to_RwZQ-j&1+ij}{(@kHmYVPue{B=2cD0cL%C~&o|>7&iosxxR%HRckJwwpFu z*u~aNnvM`#zowi+aBJf(IhC4*Lpl53iW+_$Y#nieb687y_iOxT%HrFOKZhy7gP(oX z0la3-wLx0IinH>V8GNGLj#puXTahHA+PWsm*SY#gpSfe;MAO|5Ki~R7D<*#8;>3OX z`nn$9w6(3Au;r5gW1=n@|B&7avH*X`P(7+g;0%mT1ihIf!c*8KC6u~?qEf1o+A&5e zz5yLxCdfihho9PRjIa89~k`p-^}!)=p^X^^ZcaJ z${d#k^A|Pd5^!GfurD}v9y1!ws-j~*|DwntIC$(cF~7rol|+pYeBsVtxA)7tJiU4i z4p)RzrL_=1C-Y1TMt{ARz&MblxBF~yZZ6zQ6r{aqYUmwb5TBTb&BO>u+iv!=-mB28V5HC`}Zx2ccvMd!xYk|!+Wo$ z!j8HWm4NN9HtcY95_Zuz_;yW^QGZEM3)PYQG7T}M4b8j33sm?2es*7-)_gE({iWc~e)S^2xc z{)AdRs}i?Pa*ZT3>0V8~OqXF6K^t;hoP^$dAP*~Tp5uV&XI2xguncr?zWs47QA~Xy zUil)fF-Q-aOe{G8q8K++Iq|Kb)Wb?4=gf=rkn1T+ZxZbH=br5E9POVx+*v*RCs9n3 zSqCkk3#~EFH+Oqh(~%gm?@Xy$+D*{hn?1b)baCQ`^C8!u#ASqcpMF%)laO1Lq z7?0t6*ui0jmuMy9&l{I4wwPx`N@O;2%=eM2Fj``XC}9IeQmrBDvylmZ{&QC6zGqut z;V8lqO=u1UQdNyFp9<5bg8Pe3i@mB3YVCff7Rtm(*N>)p(3sJtoTT}024E}OU(tfE zZ*ilVqEWP@c1yxsB-I0SgDI~aGcW4jv+V?x&|ZBz?cVSBJAn*ca>{rbS*b3P8X5c* zjNIZ?3MPCryCZ6W+p}BSOZoQemLUh?*_Zu4M2Q6_{+HlbGxy+~bHKfx_%FWa${GIM z9|&YeXuk>;hfXLXM+b0UQ-F1#so>hTj&iDTz)@d?7G zhEquuOd?sK=?g4TUXVD5U{9$+g7~~6X^EYbgitaIJs~dtDNZT9D1BL8@p#(~41f6V zhtQh@rz)98!T;jUvjOBi!-dF6Qb&3D>AO3nAz@6GOO z0Dk6$nQIpyISJL2$?5ZzGpm)1pXa2aiYd9JyGm(?vH?9n=GKq zG3HbLpW`H`fJkBml&sLl_gTPW=1uQUn>v5ccO$le$@Mt3IqLng=xlsZ^>v~ zy%}CVqQ19*A4%1hU+~1q_bYX5+Jd?wSTOF92+$cvE5KpJww@G(^CN8l^3fgKhrt1!tyQ?auf5;k;Bd8v5F~CM4O}U*X#-ibBpkr&ui3?sKPEwl?r{**!rW6>;NE!45u|5ob>y zem%X@=iAtOQ1?rm75+-1v^Vt&kRI{9`C|63w5_9hiO^|r-#b$aw`&%b2aEPWUWdKk z(ZN=|_nx3w;2O2iYtGGA_xlCPM$C=LcfN_EggL!rPs?b*Bqj4)C~pfA(j`lzk8<)d zS!m%SqhXW;tiBU(B-~T-Wn+G7IR6-dEN(L}KvGKYo)k_epdSS zi#izVjEL(MB0hixH_*iyMLRfVMxX||Kd-YX4-VrkWqJwjr*7W3dGn@%iPA|#ZKqA- zza~RGNO^e^zNqzPoKY7+f5=)IVK{IXZ+3!(@IVh@zILDTkkN*DHSu%o=hn(rzykKT zw2xDkUaV}fgF39X9F;wvf5{u5NhT`l>fayK&Aa*b%5PGz?#T88ONt#-2;8n!)}ISI zJes6rQI*1M$37%g4W$2j=JqobrMmQK=B{cM_0L#LCS3Z~n zW#bLz;yC&En|O?YRSo6?dJOC10M2nrg5O#*iz_S02QS8HMr|C*DFtN3fnvN(Y0GWUW8iNJI+RP9D=bo#Hp;6TrmV+UspXKR10j&f?3sW-OF;mxFXb?QYm~jE80(j|DNqLwf~09m)$xsMxy7+E89Klipn4Lx&gy$H714E$+4LeuitQ; zSTGXi|3$$_33{(aar4}ddGW~M7`EpO*X#-|Tg#TD^f5N!TJ3OX0c2xRT0*N8>x9tK za)6^qjSe)8LxJ;_Pjd(g)(Fa{+;XbQ`ckI1J!n%*^2^{{786!5_X?6*U~$%zOjoY+y^LSje&6 z4|f9jMvIr@1(&Illrc*OLNKZ=TgoKo_x@aX@KUm};h@gwzq^h3*9uCw1~Fb~r$z77 zQ4$iy#CUX`qH8``oAZCetS>E#8ylO9WmD1@N!cRh^xg&faK(bB5ctu9pkESos_xFr z-0gP@^6@KD*V^tCMa|m#w%DdQfUdcNM)>iU$hgSG$ zC*fh}N)Ee9IQ1J!iD^Bh9S_3-?Zsr$_9aDrPHtO%x6-kN(tta6gS_7N2k)G$?G!01 zyIB0MehUy-IcLHaw*7k7*E8B?n-9k?QAPcK9I7YOU7dUv5bHa=!}h2g5iP9!D2XfP zTft+Jq&`h2#WX{jTC=vD<(EdoGZ3fnhzz*!AUWNxBs9xOZlW2dq7%1=JV5}Z5bvI zeej@Wp>ImfG(2a2v#8;|KY_OG(zL{IjPXtTRq2`vVK#t;LP1Aq5?>uHIMy*&KnH2w zL^P-Yfaww};1}f8Mze}a(@=sbRx}#4T*;x?SoY!9Z<`RN9L?P;b$+K~AuX*dE^iG@5*n<+vEn3J*K>$Y6J?f-WOTadY{^=C-BYAjf|fK zDD3mzyuNGB&!Djb0!cVgo@z`sS+LtM+F|Jdkw2#0$%9bKR$%&;IO;n_&T!$0V!6b{ ztL=V@08VHv4GCyr|7>)DX4O>pZJx(xYGGH0Y5-M?9Gh z-jkaSII8p8T)U>Rw~xr|jbRKb(P=N9v#{7o#u_q=n=vBY9DKZR&=umEaEtrDQ>?kR zJf3<5Ry%t6dug9}G~dfxBSDRrl4tO^MMFs`V8DT}^L!S`myt<|e;4_q&%reO_(@}^nos}iJ@lb3(6f~=9 z9%JOsuV%>u*E-CFWc%sA=bn9=Bah|I6N*3+aYv3(12MHGa+~@b40$ zbAqqY>&H3cT9<0t^*Ly%1eS@rNC&>Zrt^iB)bu0Z2t*YB{+S;in$j!%5 z_F8k1OfF7wq4M_nz(pHPMRK7oN4}2whdq=&4~4`wEQjO}k60 zxM@-E26a3PGym9u;c?S8;d=D@9flN`1){@4k607hviSHEvqZr^ayUWIHP$J^JB0rq DN-dw# diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/traced-1.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/traced-1.snap.png deleted file mode 100644 index 953dab32137ee1acdf39fe70b3d957fb9fcc9945..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7024 zcmXY02RK~M*G5DOva4ma=xh+3tf+~)>gp}(TEAVL5WTm>iV`K3=mbIZ8oeYTI??L} zi7rGB|IPP&_j&HU&)k_gGjqkH|>yPj^L! z76Jn1Cs5^QhQ5S*-K2p=8-LG_M$e?T7L!$;gTer?XJ)l}-IkRF=m6??=57Xt% zr1afOorR4M_eLRDd1LqjLqq7Uc9QL!Z8U()e$ivZFNf{PiDR?2dbRoP2fxn#-To#R za7J+cq3ux>9Y>mUN=V{L_VU4X;C#S*_-a3RCI_(l>fATMTx;vWuA0)R}Cm-%%l z0yt%^OU3HfjpB-`6CjYNpqd^{Mj=x4Tko7$_H@FxV{?*9ucS(#SeG^?*T+fa?7NwS z1h^0=p>Y+e8gJL_n#(g82Wih^eDcQy zY79e8l?tV$r6FC^)pd219`$#|4-%L*pbieE zF=X-hdI3h2a+;FDXFfRy+v1MT>u z#h5-DfN`OENS5_cyV0^0oH&j(boyR_*kAO! zK0lc}_km5Vk4|>3=QJ?@|MblAh>FF3_##-v{>kP3$OymTlo~0WtKu3Q;4+)27uxfn zl=5?#)(6i0zVQMeJik6+;+bVy@L&AZP1n#s2zy z#_x1)Yg`phj0pvb5UF;tU(3uD%~sc?nEY3vJi!v4iF(Tl6r@TwMvgbv@L%&s>5O(! zfQdS~C-UxM2#7#;Rg?2DM1ox;bR>68!Ic16SQpJ{@$u&H*0!~k zrUVUFzUIt`mTwTtYusTjFHNi`Zn&w|{wod5YuVa6x(d?KySvVg2CXmo;5mWVd1Ped zX$;#)&F7PiD-pz?VUGVLW5GB$OcDJd9V=7>fTHjU*M?$4R+6}J1 zI~ZGtruDS!Gl&dS3U>W z*v3qT+e+S$Q^s+1Owq=Wakay+`BU%hFCkd7ItS6e@xQnqzo3us!dc{m^d%+a>=m{)t<}Co@TAoy6%yrJPiIJ>U`4;8cw&w)nKTC zMQ0z!`cuHA!GzWlrqt=hWN4KxAK1CqH#!}mFL_RNUcV>qK+*xn5(|THL4nxA3x{4T zx;t;ouCTw`<_-f1sYy5)#ZiQfApZ-t>T|c^AZ`9i$=lc$GhAs~EmMg7Pj`#_f8GQ@ zjv{ZaWekmt^bCxQ=%sD}3zDP(XAaMKsWe?kCs`6Act|Qh8g}f@QonYc_If$dY|bxh z|D5B*pp(iiU%kaq)V364*p8%=>C&gyw6dhu9Q8lL^q>=@q%YSZ9Z^)Pqz7$JFX1@a(DoNQ%8I1-ie*Hl{TQZEnn;r$63i5I{9LxPG?n~=?28Tj ze!4QXA@E=vlTv*pqO9aHU!NIEyYk-v#;n4s?ln>(4$Z+rJy~X;HX?g0F(TswFf+@X zLM&ZUeY)C@`Iaf3_-E${AXd3XF#h^`<S5K}w@J zON_p!ncTiPpSMD?2DWmwZU0~!`U-%xFFhfxPXCcmF{#f~y+f6rDV!&@9B(GGbDr!^ z$Ga}Q<~5RFLi~Q8E9$*1VO(_`my$vwYw{*1S?Ad^X8+TlBcX)tgVw?i^KteH2eYrnPLd0D9w!8|IS>)^V#eL>gulW^MQdkgvI;!=)~`&pSqIH>}rMMOpaNXM|YsYrQly zHm>y>GN!?9Y);gpsJ%T{NVD4QXSA}_8O>fj<$IW^Y3}-R*{tYdXz@AsmHUf5nnq2O zV+>=^_pBYVx6UAGr7(dd3VjGvt#?(;2h z{@7`MlH$q+c3&AIghnhlvfAyoupaG}5YvXF4MSd-vjdk!&mrH&yYjBVZ zxjb(3+7F~VTNY2*Uux4gfI`VltY32F>?Df>U$cE3b)y;(ahwXOuxd~LTM6&JzW8)G z?@K~08y}#W$Sp1&@s}L5=49vlXWC=x2QiEM<*MB8V~aO7n6-DY2VxH23{v;OJVx9! zwrXFg86Lm*HYD7s+IjQYW2LnL#NjQ(XWO} zERM+zf{X@QmxRp1_+LLJ6FV$rAbuQwxjR=EWBo!dn@5uZ3W&T@2L8A@b6-vs46>W8 z?&fx$uaEjr)tW=a97muXWL$ABlVNq!xfrsdPGapY1eNhgUu$`2EiUqE_ujW0xd)>O z27K`IpS_8X`1#j2GOXC;vSY@sqlh)kD(WW7*A73&q^! zb|f0#c91^9^4kex9pPOhP08q6m7sJX%YoM^tla$tdjHCa50}c~D{(S<{^F2dtH#f{ zbw1c+yMqVEf1xN*tUXT{x=UD5DGN~tJ$jFO7Qb_T>;5g9xb|dmFoh?Ig>tA7Imw$F zIXI|M)v`$<61%LE@b1Dk;!6v=TAePvz6?4`9Qqv9q)98X2#LZ?JfAeoG%-+ zV{04_CEDt~=gBJ~sP%wr@&2$~A%U&d9XE${nUEsXB#WcC&%P{Ec`1_X$&!~0?sF%` zWua)|d1WdgepqlZ-83ejH$pe4Uh0|_4gts**Q5f%OChTfM_r)W2#;!k@dcl}dHU7& zxe;i0u=d+ShL>9-d`7NyFaFtuRmPi}rp#`dpAcj*lQYd_cB$ zzF}uh?M> z-*yC5v&N(em{ji$Z4_Z8egy@;x+wPA^`#^4_+GTVT*$lzLlf)8;jaD^YG#al!%D_K zS@wNnXr_&Izq#0&s8jP16BnOt_<(6SW;k4nVWUk@hR$2*_e_q;4*hI9DBv*PY~X(K zBx8NuPQxcPrM%kx(Hq|O&(*d{rJDZ!PrDUEi=-|prG3T}x8IYKD80CT!?6n|pele? zyJTJV;XJ7Oym3XfdvPBDw4?$gwu&glJbogL!imQPMlnFgU{FlTPV1-hYfZH1)YQQ_ zobkAAB`GZpI#Hb;(Xz3*hGD&8X~##qvAjAcSV(BIvgwu>>BuDeLsm8MlD^v}sp$6a ziop3{VW<1nm+|JRd#cIRgJ;yYNdME_*XX|WyzcZTn~!KgQqE*h^V!iaKp&AG;m7JUz?Ay&z+teM*u>k@i_d6%Zb)MU zZg#g&4=I8r=822e+tpQ{AXBA-swztFs~*B_`Z-o3iU~8gtx;dLhw`QH4*M!KUEg4c zVc5^^8_phqNa4quYrIfR3^_K(9dvSJ?T!<=LMl$S`RMLVFiL;F{UH*CcpB%>ncs=QkM+6)N*{^MbkU zZfXh$p@%&Og=os%0}47vF6#`mV>eGO|C z*0|DqcpxDQ0suZ!1^^vBEi>cT(09^5oGWsiOZv z*0>;3o5L3BxIh1_o+V`Y^tjMK7xDXt?gds<(4sLsJX~tZKGHGz zAQriegHV%ltwLs-5r%cn+nhQ=G3Mg~2}MtD&Tm*S_(TO}0A?w0Tajl$yDVe}PLON) z9RrM)VgX@xiN4~mgv%BcM z2SO!Sy(!guDr* zh_K==P4YbsIw?m02}H3Rq|XBA%frs+UFm z%`S`LzYm-=v2Oq`aiK(X_=AK8JJYkmF>orO=oHi`m$;i9BoZi0ry8bjC{BX04IzQs zu{gfQ!L%iy2t=DS=rwI#Nx3@x0BGC5%nVv?!yft_YpC(4LtK?GZXOawutJZ|?#PLW z0tI@`bgr-w8~*Z=jQLhl#=NE*d6J+zsuB7&=U5NT?!i^q;HaBQdDOiJn{zRl8MZsL|nzbz^pTk_jNwqxq@9TV}7%q3q z`vComj>MgSDfR_Obfzi*+~XS*peGvvf(OA#Nw;ZOXoR+<6sGj z;a~4_l-U7_1PDb&m}(&guQuB4lynB(X{_Xq`gD`7@WjOAITk5@{S#giBpPvYM^<_@GS3fjE1>6)9rEHkgxyl zF*lMXGWN|fe6E)Mh1XZzpA%)YoN@h8Q5a^0u!JnBLdw*%J%{r@Gh^?4gj;Z>z|R<@#Ws8gT4 zaZ|-E3q<;Im$Pn!N(+s5C5FFp2!G^3p-|Z&%hFnJ52c_T2QQcYG>qSXA~6j`c1Hwbvr=T;3I8?q zOFdQJG`+vcWAG85_*%k~GSpyd*`nOGm22A{2T#vhC|b4fll+?Y!;p0pwJ|%Oi?@;w zOh_A+7lDul(4w0GP3-APFa%CGh<5r)N;y(#V@shkMOPuKXE4n=x#+HO)s4)V+#x_U z5*rzm6SS`)yMjy4iWc`jAropjp|Gpc3@52S@;$C>y1*^C)v*-y=u2cJAr-isQDx%jZ{i(WVeN_Ul@`qx=?l1=ajFF}g; z0#F#(aJ6nzmF1T&lm>cw&~Om=(WA|tcwsIO1r23%vs0hTKecoB6?y=MpGbKBTDgT# z%T%!L%(&&1#M1H|t*Np7LyTR;&}padweJhU9f|OhPN@gs&+|w1I>;k}`@8H(bnXgC%hb>I0c4$efnq1P-#zZ0dh!@*g!R6$T(f-Z;GVTcVJ>a^v^(K)5Z1&qib<0 zyYo{@a(q;Y4;G_CC{kX zU=KuBiCL+YYcf!t3`Xl=#)`D1j>C};C@xkL8d9r#W*fyuUaO=DGW{W2;MHBTUh7bx zuL=Q4{xYcWi}!f1U3gu?7b|-x<0Y#TWZp0c?};>FbRR%*gYOKIv7>=~p&&r70$BuU z?r0tSbCTD7Uf3s*Q*u1!#)(lN=<)!CfID`Il+&r>=&s@nt8bIKe_t!IE2bdK*h%`5 z>}90>)VMIixXIWRyFAqW55vY!w&(7MGKu1A@sjVPBa){&Llmq6Z&03D8=i^<&m_V2^gB;DAzI>5)_foYfM!#O`M&(jF(V zO2sQ!Ml5G)=kdp!_%hilBv2}7nSUF|sv-W|Nd7R0j`O(^YKH4{A~)INfKaI8_t;>6 z!#b##+?Bs%B7t^)`rTz@FUN>{0KwlYR!v!k_r3w-Au z^y9*%T$(RRn7@pSY${^y5n_mWufWmXT4xeU$U6?D5jACXvZ(OvkQ?^-MyL3#R^Jmi?4Qu>z(Jq@oD}AC9^*vS%tN=GB-`W5Mw4|w$HM(?CF<}(#PK>^)&Dd zN`-Y(7`=e8zP8QJYL1fw9~M#?>ZrFT%K?4sLijz2W{$DejNcrFy0c`xBz>nX01;5s51~YRn%5ex(i9_(b6DtlOe(NMD2#=I&ZqLffu6i7cOTa8C6jhxdDm zopTTQD*j}VpW7s_u02XD-2?v4S5XGuFMcDs&uA#}rTb7e@v%iyZDBnfoV^W7OELcg zZzE(Wo->l7b15n)AX;erI^+axYuv-H`Lel6E&Ly`Mz!Ym&|^j=7C;eIns{)9bg6c^ z2h10$+R<-5(M%V%?*8twP+C#J`S`IG{(x=y)VnC)%#}FenPXvt!!Xvn&rWn=vX>?J zd`+ScAA6nWKV?RKN`H)8{v_QXIsh{_*FgQ!!SjfZWdHmraq^Md52N5z{q2k?aPC)zNa^M^y2#?ZbHqSu~eHu-^3 zZLVBL4Jv(eYWMJ78BWxwDR~!d%SISTh5~efqUb5c@q(fXN?_E%D+0&@tWEyd)7PaC z4V7o>kU^U{DU=S`xYPitg@E&&M#6>A;_e9>RJ8<}P*bTZCiH&e{dAHc#V(VgfVjN( zBD2c#^m*n#CjLp}RQXwI<<+sRGcg&y8<$p)b`O*qinfVQKuCiTaEuKm6rZ|)?t&G^ z0fTsoJz;{dz!-2oaCrY;s=Y>X8k?#G=kU9Z}(#O9s~hYOty)oGRM_roFhd;ORNgY9O$4`;Oi1? z@+A){lx1RpULhM(KVf9RtHL?jGx*uBXOe|us$=HoGmi{AJM85>?*D%y&Mbe^7HRwC z0J;6_=jB!b4-5=@>A@mCJ(SD+u_zmQBAu7*B^~> z^e)dcb`>*BLboDZ^2Nkq!&$ZsP7zDL)bWnTxh9gp^q22K;d{~%eXSFKhX8*;RdkfA Ip4)`~4>_hndH?_b From 6f2b8ea6d840d4cdc41a3a8016b607b7ff369a54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 16 Jun 2023 13:14:30 +0200 Subject: [PATCH 081/149] test: add missing reporter.warn mock --- packages/gatsby-source-contentful/src/__tests__/gatsby-node.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 2fa0d0ef2941f..d69ebf3f5f04f 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -138,6 +138,7 @@ describe(`gatsby-node`, () => { const getCache = jest.fn(() => cache) const reporter = { info: jest.fn(), + warn: jest.fn(), verbose: jest.fn(), panic: jest.fn(), activityTimer: () => { From 8f01f62b882a99bb27e7d45421a412154ed942a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 19 Jun 2023 12:32:20 +0200 Subject: [PATCH 082/149] test(e2e): introduce a second e2e run that tests Contentfuls preview API --- e2e-tests/contentful/cypress.config.ts | 23 +++--- .../integration/{ => delivery}/boolean.js | 0 .../integration/delivery/content-reference.js | 68 ++++++++++++++++++ .../integration/{ => delivery}/date.js | 0 .../{ => delivery}/download-local.js | 0 .../integration/{ => delivery}/engines.js | 0 .../{ => delivery}/gatsby-image-cdn.js | 0 .../{ => delivery}/gatsby-plugin-image.js | 0 .../integration/{ => delivery}/json.js | 0 .../integration/{ => delivery}/location.js | 0 .../{ => delivery}/media-reference.js | 0 .../integration/{ => delivery}/number.js | 0 .../integration/{ => delivery}/rich-text.js | 0 .../integration/{ => delivery}/tags.js | 0 .../integration/{ => delivery}/text.js | 0 .../{ => preview}/content-reference.js | 8 ++- .../gatsby-image-cdn-0.snap.png | Bin .../gatsby-plugin-image.js/blurred-0.snap.png | Bin .../gatsby-plugin-image.js/blurred-1.snap.png | Bin .../constrained-0.snap.png | Bin .../constrained-1.snap.png | Bin .../dominant-color-0.snap.png | Bin .../dominant-color-1.snap.png | Bin .../gatsby-plugin-image.js/english-0.snap.png | Bin .../gatsby-plugin-image.js/fixed-0.snap.png | Bin .../gatsby-plugin-image.js/fixed-1.snap.png | Bin .../full-width-0.snap.png | Bin .../full-width-1.snap.png | Bin .../gatsby-plugin-image.js/german-0.snap.png | Bin .../gatsby-plugin-image.js/sqip-0.snap.png | Bin .../gatsby-plugin-image.js/sqip-1.snap.png | Bin e2e-tests/contentful/gatsby-config.js | 23 +++--- e2e-tests/contentful/package.json | 5 +- e2e-tests/contentful/snapshots.js | 29 ++++++++ 34 files changed, 137 insertions(+), 19 deletions(-) rename e2e-tests/contentful/cypress/integration/{ => delivery}/boolean.js (100%) create mode 100644 e2e-tests/contentful/cypress/integration/delivery/content-reference.js rename e2e-tests/contentful/cypress/integration/{ => delivery}/date.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/download-local.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/engines.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/gatsby-image-cdn.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/gatsby-plugin-image.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/json.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/location.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/media-reference.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/number.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/rich-text.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/tags.js (100%) rename e2e-tests/contentful/cypress/integration/{ => delivery}/text.js (100%) rename e2e-tests/contentful/cypress/integration/{ => preview}/content-reference.js (87%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-image-cdn.js/gatsby-image-cdn-0.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/blurred-0.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/blurred-1.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/constrained-0.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/constrained-1.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/dominant-color-0.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/dominant-color-1.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/english-0.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/fixed-0.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/fixed-1.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/full-width-0.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/full-width-1.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/german-0.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/sqip-0.snap.png (100%) rename e2e-tests/contentful/cypress/snapshots/cypress/integration/{ => delivery}/gatsby-plugin-image.js/sqip-1.snap.png (100%) diff --git a/e2e-tests/contentful/cypress.config.ts b/e2e-tests/contentful/cypress.config.ts index 47dfbf5428ffe..653fe79a4f7bf 100644 --- a/e2e-tests/contentful/cypress.config.ts +++ b/e2e-tests/contentful/cypress.config.ts @@ -1,30 +1,35 @@ import { defineConfig } from "cypress" import { addMatchImageSnapshotPlugin } from "@simonsmith/cypress-image-snapshot/plugin" +const specFolder = process.env.CTF_API === "preview" ? "preview" : "delivery" + export default defineConfig({ e2e: { baseUrl: `http://localhost:9000`, - specPattern: `cypress/integration/**/*.{js,ts}`, + specPattern: `cypress/integration/${specFolder}/**/*.{js,ts}`, projectId: `2193cm`, viewportWidth: 1440, viewportHeight: 900, retries: { runMode: 0, - openMode: 0 + openMode: 0, }, videoUploadOnPasses: false, setupNodeEvents(on, config) { addMatchImageSnapshotPlugin(on, config) - on("before:browser:launch", (browser = {} as Cypress.Browser, launchOptions) => { - if (browser.family === "chromium" || browser.name === "chrome") { - // Make retina screens run at 1x density so they match the versions in CI - launchOptions.args.push("--force-device-scale-factor=1") + on( + "before:browser:launch", + (browser = {} as Cypress.Browser, launchOptions) => { + if (browser.family === "chromium" || browser.name === "chrome") { + // Make retina screens run at 1x density so they match the versions in CI + launchOptions.args.push("--force-device-scale-factor=1") + } + return launchOptions } - return launchOptions - }) + ) }, }, env: { requireSnapshots: true, - } + }, }) \ No newline at end of file diff --git a/e2e-tests/contentful/cypress/integration/boolean.js b/e2e-tests/contentful/cypress/integration/delivery/boolean.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/boolean.js rename to e2e-tests/contentful/cypress/integration/delivery/boolean.js diff --git a/e2e-tests/contentful/cypress/integration/delivery/content-reference.js b/e2e-tests/contentful/cypress/integration/delivery/content-reference.js new file mode 100644 index 0000000000000..f3edfa5c44056 --- /dev/null +++ b/e2e-tests/contentful/cypress/integration/delivery/content-reference.js @@ -0,0 +1,68 @@ +// Make sure to keep test from this file in sync with previews/content-reverence.js +describe(`content-reference`, () => { + beforeEach(() => { + cy.visit("/content-reference").waitForRouteChange() + }) + it(`content-reference-many-2nd-level-loop`, () => { + cy.get( + '[data-cy-id="default-content-reference-many-2nd-level-loop"]' + ).snapshot() + }) + it(`content-reference-many-loop-a-greater-b`, () => { + cy.get( + '[data-cy-id="default-content-reference-many-loop-a-greater-b"]' + ).snapshot() + }) + it(`content-reference-many-loop-b-greater-a`, () => { + cy.get( + '[data-cy-id="default-content-reference-many-loop-b-greater-a"]' + ).snapshot() + }) + it(`content-reference-many-self-reference`, () => { + cy.get( + '[data-cy-id="default-content-reference-many-self-reference"]' + ).snapshot() + }) + it(`content-reference-one`, () => { + cy.get('[data-cy-id="default-content-reference-one"]').snapshot() + }) + it(`content-reference-one-loop-a-greater-b`, () => { + cy.get( + '[data-cy-id="default-content-reference-one-loop-a-greater-b"]' + ).snapshot() + }) + it(`content-reference-one-loop-b-greater-a`, () => { + cy.get( + '[data-cy-id="default-content-reference-one-loop-b-greater-a"]' + ).snapshot() + }) + it(`content-reference-one-self-reference`, () => { + cy.get( + '[data-cy-id="default-content-reference-one-self-reference"]' + ).snapshot() + }) + // Previe api test. Content should not exist on delivery + it(`content-reference-preview-api-test`, () => { + cy.get( + '[data-cy-id="default-preview-api-test-unpublished-and-linking-to-non-existing-entry"]' + ).should("not.exist") + }) +}) + +describe(`content-reference localized`, () => { + beforeEach(() => { + cy.visit("/content-reference").waitForRouteChange() + }) + it(`english-content-reference-one-localized`, () => { + cy.get('[data-cy-id="english-content-reference-one-localized"]').snapshot() + }) + it(`english-content-reference-many-localized`, () => { + cy.get('[data-cy-id="english-content-reference-many-localized"]').snapshot() + }) + it(`german-content-reference-one-localized`, () => { + cy.get('[data-cy-id="german-content-reference-one-localized"]').snapshot() + }) + it(`german-content-reference-many-localized`, () => { + cy.get('[data-cy-id="german-content-reference-many-localized"]').snapshot() + }) +}) diff --git a/e2e-tests/contentful/cypress/integration/date.js b/e2e-tests/contentful/cypress/integration/delivery/date.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/date.js rename to e2e-tests/contentful/cypress/integration/delivery/date.js diff --git a/e2e-tests/contentful/cypress/integration/download-local.js b/e2e-tests/contentful/cypress/integration/delivery/download-local.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/download-local.js rename to e2e-tests/contentful/cypress/integration/delivery/download-local.js diff --git a/e2e-tests/contentful/cypress/integration/engines.js b/e2e-tests/contentful/cypress/integration/delivery/engines.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/engines.js rename to e2e-tests/contentful/cypress/integration/delivery/engines.js diff --git a/e2e-tests/contentful/cypress/integration/gatsby-image-cdn.js b/e2e-tests/contentful/cypress/integration/delivery/gatsby-image-cdn.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/gatsby-image-cdn.js rename to e2e-tests/contentful/cypress/integration/delivery/gatsby-image-cdn.js diff --git a/e2e-tests/contentful/cypress/integration/gatsby-plugin-image.js b/e2e-tests/contentful/cypress/integration/delivery/gatsby-plugin-image.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/gatsby-plugin-image.js rename to e2e-tests/contentful/cypress/integration/delivery/gatsby-plugin-image.js diff --git a/e2e-tests/contentful/cypress/integration/json.js b/e2e-tests/contentful/cypress/integration/delivery/json.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/json.js rename to e2e-tests/contentful/cypress/integration/delivery/json.js diff --git a/e2e-tests/contentful/cypress/integration/location.js b/e2e-tests/contentful/cypress/integration/delivery/location.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/location.js rename to e2e-tests/contentful/cypress/integration/delivery/location.js diff --git a/e2e-tests/contentful/cypress/integration/media-reference.js b/e2e-tests/contentful/cypress/integration/delivery/media-reference.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/media-reference.js rename to e2e-tests/contentful/cypress/integration/delivery/media-reference.js diff --git a/e2e-tests/contentful/cypress/integration/number.js b/e2e-tests/contentful/cypress/integration/delivery/number.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/number.js rename to e2e-tests/contentful/cypress/integration/delivery/number.js diff --git a/e2e-tests/contentful/cypress/integration/rich-text.js b/e2e-tests/contentful/cypress/integration/delivery/rich-text.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/rich-text.js rename to e2e-tests/contentful/cypress/integration/delivery/rich-text.js diff --git a/e2e-tests/contentful/cypress/integration/tags.js b/e2e-tests/contentful/cypress/integration/delivery/tags.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/tags.js rename to e2e-tests/contentful/cypress/integration/delivery/tags.js diff --git a/e2e-tests/contentful/cypress/integration/text.js b/e2e-tests/contentful/cypress/integration/delivery/text.js similarity index 100% rename from e2e-tests/contentful/cypress/integration/text.js rename to e2e-tests/contentful/cypress/integration/delivery/text.js diff --git a/e2e-tests/contentful/cypress/integration/content-reference.js b/e2e-tests/contentful/cypress/integration/preview/content-reference.js similarity index 87% rename from e2e-tests/contentful/cypress/integration/content-reference.js rename to e2e-tests/contentful/cypress/integration/preview/content-reference.js index a7b476d2e98f5..ba104cdfdf889 100644 --- a/e2e-tests/contentful/cypress/integration/content-reference.js +++ b/e2e-tests/contentful/cypress/integration/preview/content-reference.js @@ -1,4 +1,4 @@ -describe(`content-reference`, () => { +describe(`prewview-content-reference`, () => { beforeEach(() => { cy.visit("/content-reference").waitForRouteChange() }) @@ -40,6 +40,12 @@ describe(`content-reference`, () => { '[data-cy-id="default-content-reference-one-self-reference"]' ).snapshot() }) + // Most relevant preview api test (the others are still good to test!) + it(`content-reference-preview-api-test`, () => { + cy.get( + '[data-cy-id="default-preview-api-test-unpublished-and-linking-to-non-existing-entry"]' + ).snapshot() + }) }) describe(`content-reference localized`, () => { diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-image-cdn.js/gatsby-image-cdn-0.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-image-cdn.js/gatsby-image-cdn-0.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-image-cdn.js/gatsby-image-cdn-0.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-image-cdn.js/gatsby-image-cdn-0.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/blurred-0.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/blurred-0.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/blurred-0.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/blurred-0.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/blurred-1.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/blurred-1.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/blurred-1.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/blurred-1.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/constrained-0.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/constrained-0.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/constrained-0.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/constrained-0.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/constrained-1.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/constrained-1.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/constrained-1.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/constrained-1.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/dominant-color-0.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/dominant-color-0.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/dominant-color-0.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/dominant-color-0.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/dominant-color-1.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/dominant-color-1.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/dominant-color-1.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/dominant-color-1.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/english-0.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/english-0.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/english-0.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/english-0.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/fixed-0.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/fixed-0.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/fixed-0.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/fixed-0.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/fixed-1.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/fixed-1.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/fixed-1.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/fixed-1.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/full-width-0.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/full-width-0.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/full-width-0.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/full-width-0.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/full-width-1.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/full-width-1.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/full-width-1.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/full-width-1.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/german-0.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/german-0.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/german-0.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/german-0.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/sqip-0.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/sqip-0.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/sqip-0.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/sqip-0.snap.png diff --git a/e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/sqip-1.snap.png b/e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/sqip-1.snap.png similarity index 100% rename from e2e-tests/contentful/cypress/snapshots/cypress/integration/gatsby-plugin-image.js/sqip-1.snap.png rename to e2e-tests/contentful/cypress/snapshots/cypress/integration/delivery/gatsby-plugin-image.js/sqip-1.snap.png diff --git a/e2e-tests/contentful/gatsby-config.js b/e2e-tests/contentful/gatsby-config.js index 530941cdf4464..cddc47663dfa4 100644 --- a/e2e-tests/contentful/gatsby-config.js +++ b/e2e-tests/contentful/gatsby-config.js @@ -1,3 +1,17 @@ +const ctfOptions = { + // This space is for testing purposes only. + // Never store your Contentful credentials in your projects config file. + // Use: https://www.gatsbyjs.com/docs/how-to/local-development/environment-variables/ + spaceId: `k8iqpp6u0ior`, + accessToken: `hO_7N0bLaCJFbu5nL3QVekwNeB_TNtg6tOCB_9qzKUw`, + downloadLocal: true, +} + +if (process.env.CTF_API === "preview") { + ctfOptions.host = `preview.contentful.com` + ctfOptions.accessToken = `IkSw3qEFt8NHKQUko2hIVDgu6x3AMtAkNecQZvg2034` +} + module.exports = { siteMetadata: { title: `Gatsby Contentful e2e`, @@ -5,14 +19,7 @@ module.exports = { plugins: [ { resolve: `gatsby-source-contentful`, - options: { - // This space is for testing purposes only. - // Never store your Contentful credentials in your projects config file. - // Use: https://www.gatsbyjs.com/docs/how-to/local-development/environment-variables/ - spaceId: `k8iqpp6u0ior`, - accessToken: `hO_7N0bLaCJFbu5nL3QVekwNeB_TNtg6tOCB_9qzKUw`, - downloadLocal: true, - }, + options: ctfOptions, }, `gatsby-transformer-remark`, `gatsby-transformer-sharp`, diff --git a/e2e-tests/contentful/package.json b/e2e-tests/contentful/package.json index acf002ba68d82..1f43b9f5ad4e2 100644 --- a/e2e-tests/contentful/package.json +++ b/e2e-tests/contentful/package.json @@ -24,6 +24,7 @@ "cross-env": "^7.0.3", "cypress": "^12.13.0", "gatsby-cypress": "next", + "npm-run-all": "^4.1.5", "prettier": "^2.8.8", "srcset": "^5.0.0", "start-server-and-test": "^2.0.0", @@ -38,7 +39,9 @@ "build": "gatsby build", "develop": "gatsby develop", "format": "prettier --write '**/*.js'", - "test": "cross-env CYPRESS_SUPPORT=y npm run build && npm run start-server-and-test", + "test": "npm-run-all -c -s test:delivery test:preview", + "test:delivery": "gatsby clean && cross-env CYPRESS_SUPPORT=y CTF_API=delivery npm run build && CTF_API=delivery npm run start-server-and-test", + "test:preview": "gatsby clean && cross-env CYPRESS_SUPPORT=y CTF_API=preview npm run build && CTF_API=preview npm run start-server-and-test", "start-server-and-test": "start-server-and-test serve http://localhost:9000 cy:run", "serve": "gatsby serve", "cy:open": "cypress open --browser chrome --e2e", diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index 0a27dd40b8f34..3ab7f26d0f4cd 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -114,5 +114,34 @@ module.exports = { "1": "
\n

Media Reference: One Localized Field

\n
", "2": "
\n

Media Reference: One Localized Field

\n
" } + }, + "prewview-content-reference": { + "content-reference-many-2nd-level-loop": { + "1": "
\n

Content Reference: Many (2nd level loop)\n (\n 4R29nQaAkgJFB5pkruYW9i\n )

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": null\n}
\n
" + }, + "content-reference-many-loop-a-greater-b": { + "1": "
\n

Content Reference: Many (Loop A -> B)\n (\n 4NHKxzHnMwSjjMLSdUrcFo\n )

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop B -> A)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop A ->\n B)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"7IrXy5KcEujLUsaWVJAK69\"\n      }\n    }\n  ]\n}
\n
" + }, + "content-reference-many-loop-b-greater-a": { + "1": "
\n

Content Reference: Many (Loop B -> A)\n (\n 7IrXy5KcEujLUsaWVJAK69\n )

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Loop A -> B)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Loop B ->\n A)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"4NHKxzHnMwSjjMLSdUrcFo\"\n      }\n    }\n  ]\n}
\n
" + }, + "content-reference-many-self-reference": { + "1": "
\n

Content Reference: Many (Self Reference)\n (\n 50SBswk2hZU4G4ITVIPuuU\n )

\n

[ContentfulContentTypeNumber]\n 42

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulContentTypeContentReference]\n Content Reference: Many (Self Reference)\n : [\n Number: Integer, Text: Short, Content Reference: Many (Self\n Reference)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"50SBswk2hZU4G4ITVIPuuU\"\n      }\n    }\n  ]\n}
\n
" + }, + "content-reference-one": { + "1": "
\n

Content Reference: One\n (\n 77UBlVUq3oeVidhtAhrByt\n )

\n

[ContentfulContentTypeText]\n The quick brown fox jumps over the lazy dog.

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": null\n}
\n
" + }, + "content-reference-one-loop-a-greater-b": { + "1": "
\n

Content Reference: One (Loop A -> B)\n (\n LkOtAXoxqqX8Y9cRRPjRb\n )

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop B -> A)\n : [\n Content Reference: One (Loop A -> B)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"4R29nQaAkgJFB5pkruYW9i\"\n      }\n    },\n    {\n      \"sys\": {\n        \"id\": \"37m4vschoGYmwUMlgxAa74\"\n      }\n    }\n  ]\n}
\n
" + }, + "content-reference-one-loop-b-greater-a": { + "1": "
\n

Content Reference: One (Loop B -> A)\n (\n 37m4vschoGYmwUMlgxAa74\n )

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"LkOtAXoxqqX8Y9cRRPjRb\"\n      }\n    }\n  ]\n}
\n
" + }, + "content-reference-one-self-reference": { + "1": "
\n

Content Reference: One (Self Reference)\n (\n 3Lq0a8ymtbGueurkbuM2xN\n )

\n

[ContentfulContentTypeContentReference]\n Content Reference: One (Self Reference)\n : [\n Content Reference: One (Self Reference)\n ]

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": [\n    {\n      \"sys\": {\n        \"id\": \"3Lq0a8ymtbGueurkbuM2xN\"\n      }\n    }\n  ]\n}
\n
" + }, + "content-reference-preview-api-test": { + "1": "\n

Preview API Test - Unpublished and linking to non-existing entry\n (\n 6XvKge4VlNLkgTWZTXbwvh\n )

\n

Linked from:

\n
{\n  \"ContentfulContentTypeContentReference\": null\n}
\n
" + } } } From 2b7d726d8fe74fa4989375bd61b5ea872a5895f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 19 Jun 2023 14:28:48 +0200 Subject: [PATCH 083/149] chore: type CTF API error message --- packages/gatsby-source-contentful/src/fetch.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/fetch.ts b/packages/gatsby-source-contentful/src/fetch.ts index e3925b07ac830..72a9b59905fad 100644 --- a/packages/gatsby-source-contentful/src/fetch.ts +++ b/packages/gatsby-source-contentful/src/fetch.ts @@ -64,6 +64,15 @@ const createContentfulErrorMessage = (e: any): string => { return axiosErrorMessage.filter(Boolean).join(` `) } + interface IContentfulAPIError { + status?: number + statusText?: string + requestId?: string + message: string + details: Record + request?: Record + } + // If it is not an axios error, we assume that we got a Contentful SDK error and try to parse it const errorMessage = [e.name] const errorDetails: Array = [] @@ -82,7 +91,7 @@ const createContentfulErrorMessage = (e: any): string => { * !request?: Record * } */ - const errorData = JSON.parse(e.message) + const errorData: IContentfulAPIError = JSON.parse(e.message) errorMessage.push(errorData.status && String(errorData.status)) errorMessage.push(errorData.statusText) errorMessage.push(errorData.message) From 44142a9f852b275b01f94e79695a1ea9499aef6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 20 Jun 2023 14:07:42 +0200 Subject: [PATCH 084/149] feat: integrate space id into reference linking to prepare for cross space links --- .../src/__tests__/normalize.js | 63 +++++++++++-------- .../gatsby-source-contentful/src/normalize.ts | 36 +++++++---- .../src/source-nodes.ts | 5 +- 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/normalize.js b/packages/gatsby-source-contentful/src/__tests__/normalize.js index 0c86ae2c957c8..8298d9609dd2c 100644 --- a/packages/gatsby-source-contentful/src/__tests__/normalize.js +++ b/packages/gatsby-source-contentful/src/__tests__/normalize.js @@ -78,12 +78,15 @@ describe(`generic`, () => { const resolvable = buildResolvableSet({ assets: currentSyncData.assets, entryList, + spaceId: space.sys.id, }) const allNodes = [...currentSyncData.entries, ...currentSyncData.assets] allNodes.forEach(node => - expect(resolvable).toContain(`${node.sys.id}___${node.sys.type}`) + expect(resolvable).toContain( + `${space.sys.id}___${node.sys.id}___${node.sys.type}` + ) ) }) it(`builds foreignReferenceMap`, () => { @@ -95,6 +98,7 @@ describe(`generic`, () => { const resolvable = buildResolvableSet({ assets: currentSyncData.assets, entryList, + spaceId: space.sys.id, }) const foreignReferenceMapState = buildForeignReferenceMap({ @@ -110,20 +114,20 @@ describe(`generic`, () => { }) const referenceKeys = Object.keys(foreignReferenceMapState.backLinks) const expectedReferenceKeys = [ - `2Y8LhXLnYAYqKCGEWG4EKI___Asset`, - `3wtvPBbBjiMKqKKga8I2Cu___Asset`, - `4LgMotpNF6W20YKmuemW0a___Entry`, - `4zj1ZOfHgQ8oqgaSKm4Qo2___Asset`, - `6m5AJ9vMPKc8OUoQeoCS4o___Asset`, - `6t4HKjytPi0mYgs240wkG___Asset`, - `7LAnCobuuWYSqks6wAwY2a___Entry`, - `10TkaLheGeQG6qQGqWYqUI___Asset`, - `24DPGBDeGEaYy8ms4Y8QMQ___Entry`, - `651CQ8rLoIYCeY6G0QG22q___Entry`, - `JrePkDVYomE8AwcuCUyMi___Entry`, - `KTRF62Q4gg60q6WCsWKw8___Asset`, - `wtrHxeu3zEoEce2MokCSi___Asset`, - `Xc0ny7GWsMEMCeASWO2um___Asset`, + `rocybtov1ozk___2Y8LhXLnYAYqKCGEWG4EKI___Asset`, + `rocybtov1ozk___3wtvPBbBjiMKqKKga8I2Cu___Asset`, + `rocybtov1ozk___4LgMotpNF6W20YKmuemW0a___Entry`, + `rocybtov1ozk___4zj1ZOfHgQ8oqgaSKm4Qo2___Asset`, + `rocybtov1ozk___6m5AJ9vMPKc8OUoQeoCS4o___Asset`, + `rocybtov1ozk___6t4HKjytPi0mYgs240wkG___Asset`, + `rocybtov1ozk___7LAnCobuuWYSqks6wAwY2a___Entry`, + `rocybtov1ozk___10TkaLheGeQG6qQGqWYqUI___Asset`, + `rocybtov1ozk___24DPGBDeGEaYy8ms4Y8QMQ___Entry`, + `rocybtov1ozk___651CQ8rLoIYCeY6G0QG22q___Entry`, + `rocybtov1ozk___JrePkDVYomE8AwcuCUyMi___Entry`, + `rocybtov1ozk___KTRF62Q4gg60q6WCsWKw8___Asset`, + `rocybtov1ozk___wtrHxeu3zEoEce2MokCSi___Asset`, + `rocybtov1ozk___Xc0ny7GWsMEMCeASWO2um___Asset`, ] expect(referenceKeys).toHaveLength(expectedReferenceKeys.length) expect(referenceKeys).toEqual(expect.arrayContaining(expectedReferenceKeys)) @@ -132,10 +136,10 @@ describe(`generic`, () => { expect(resolvable).toContain(referenceId) let expectedLength = 1 - if (referenceId === `651CQ8rLoIYCeY6G0QG22q___Entry`) { + if (referenceId === `rocybtov1ozk___651CQ8rLoIYCeY6G0QG22q___Entry`) { expectedLength = 2 } - if (referenceId === `7LAnCobuuWYSqks6wAwY2a___Entry`) { + if (referenceId === `rocybtov1ozk___7LAnCobuuWYSqks6wAwY2a___Entry`) { expectedLength = 3 } expect(foreignReferenceMapState.backLinks[referenceId]).toHaveLength( @@ -155,6 +159,7 @@ describe(`Process contentful data (by name)`, () => { const resolvable = buildResolvableSet({ assets: currentSyncData.assets, entryList, + spaceId: space.sys.id, }) const foreignReferenceMapState = buildForeignReferenceMap({ @@ -170,13 +175,15 @@ describe(`Process contentful data (by name)`, () => { }) expect( - foreignReferenceMapState.backLinks[`24DPGBDeGEaYy8ms4Y8QMQ___Entry`][0] - .name + foreignReferenceMapState.backLinks[ + `rocybtov1ozk___24DPGBDeGEaYy8ms4Y8QMQ___Entry` + ][0].name ).toBe(`ContentfulContentTypeProduct`) expect( - foreignReferenceMapState.backLinks[`2Y8LhXLnYAYqKCGEWG4EKI___Asset`][0] - .name + foreignReferenceMapState.backLinks[ + `rocybtov1ozk___2Y8LhXLnYAYqKCGEWG4EKI___Asset` + ][0].name ).toBe(`ContentfulContentTypeBrand`) }) @@ -189,6 +196,7 @@ describe(`Process contentful data (by name)`, () => { const resolvable = buildResolvableSet({ assets: currentSyncData.assets, entryList, + spaceId: space.sys.id, }) const foreignReferenceMap = buildForeignReferenceMap({ @@ -279,6 +287,7 @@ describe(`Process existing mutated nodes in warm build`, () => { const resolvable = buildResolvableSet({ assets: currentSyncData.assets, entryList, + spaceId: space.sys.id, }) const foreignReferenceMap = buildForeignReferenceMap({ @@ -365,6 +374,7 @@ describe(`Process contentful data (by id)`, () => { const resolvable = buildResolvableSet({ assets: currentSyncData.assets, entryList, + spaceId: space.sys.id, }) const foreignReferenceMapState = buildForeignReferenceMap({ contentTypeItems, @@ -379,13 +389,15 @@ describe(`Process contentful data (by id)`, () => { }) expect( - foreignReferenceMapState.backLinks[`24DPGBDeGEaYy8ms4Y8QMQ___Entry`][0] - .name + foreignReferenceMapState.backLinks[ + `rocybtov1ozk___24DPGBDeGEaYy8ms4Y8QMQ___Entry` + ][0].name ).toBe(`ContentfulContentType2PqfXuJwE8QSyKuM0U6W8M`) expect( - foreignReferenceMapState.backLinks[`2Y8LhXLnYAYqKCGEWG4EKI___Asset`][0] - .name + foreignReferenceMapState.backLinks[ + `rocybtov1ozk___2Y8LhXLnYAYqKCGEWG4EKI___Asset` + ][0].name ).toBe(`ContentfulContentTypeSFzTZbSuM8CoEwygeUYes`) }) @@ -397,6 +409,7 @@ describe(`Process contentful data (by id)`, () => { const resolvable = buildResolvableSet({ assets: currentSyncData.assets, entryList, + spaceId: space.sys.id, }) const foreignReferenceMap = buildForeignReferenceMap({ contentTypeItems, diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index 4ece8b971e06b..15a92721544d4 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -118,11 +118,14 @@ export const createRefId = ( node: | IEntryWithAllLocalesAndWithoutLinkResolution | IContentfulEntry - | Asset -): string => `${node.sys.id}___${node.sys.type}` + | Asset, + spaceId: string +): string => `${spaceId}___${node.sys.id}___${node.sys.type}` -export const createLinkRefId = (link: IContentfulLink): string => - `${link.sys.id}___${link.sys.linkType}` +export const createLinkRefId = ( + link: IContentfulLink, + spaceId: string +): string => `${spaceId}___${link.sys.id}___${link.sys.linkType}` export const buildEntryList = ({ contentTypeItems, @@ -156,27 +159,29 @@ export const buildResolvableSet = ({ entryList, existingNodes = new Map(), assets = [], + spaceId, }: { entryList: Array< Array> > existingNodes: Map assets: Array + spaceId: string }): Set => { const resolvable: Set = new Set() existingNodes.forEach(node => { 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(createRefId(node)) + resolvable.add(createRefId(node, spaceId)) } }) entryList.forEach(entries => { - entries.forEach(entry => resolvable.add(createRefId(entry))) + entries.forEach(entry => resolvable.add(createRefId(entry, spaceId))) }) - assets.forEach(assetItem => resolvable.add(createRefId(assetItem))) + assets.forEach(assetItem => resolvable.add(createRefId(assetItem, spaceId))) return resolvable } @@ -292,7 +297,7 @@ export const buildForeignReferenceMap = ({ entryItemFieldValue[0].sys.id ) { entryItemFieldValue.forEach(v => { - const key = createLinkRefId(v) + const key = createLinkRefId(v, space.sys.id) // Don't create link to an unresolvable field. if (!resolvable.has(key)) { return @@ -319,7 +324,7 @@ export const buildForeignReferenceMap = ({ entryItemFieldValue?.sys?.type && entryItemFieldValue.sys.id ) { - const key = createLinkRefId(entryItemFieldValue) + const key = createLinkRefId(entryItemFieldValue, space.sys.id) // Don't create link to an unresolvable field. if (!resolvable.has(key)) { return @@ -687,7 +692,9 @@ export const createNodesForContentType = ({ // is empty due to links to missing entities const resolvableEntryItemFieldValue = entryItemFieldValue .filter(v => { - const isResolvable = resolvable.has(createLinkRefId(v)) + const isResolvable = resolvable.has( + createLinkRefId(v, space.sys.id) + ) if (!isResolvable) { warnForUnresolvableLink(entryItem, entryItemFieldKey, v) } @@ -704,7 +711,11 @@ export const createNodesForContentType = ({ entryItemFields[entryItemFieldKey] = resolvableEntryItemFieldValue } else { - if (resolvable.has(createLinkRefId(entryItemFieldValue))) { + if ( + resolvable.has( + createLinkRefId(entryItemFieldValue, space.sys.id) + ) + ) { entryItemFields[entryItemFieldKey] = mId( space.sys.id, entryItemFieldValue.sys.id, @@ -725,7 +736,8 @@ export const createNodesForContentType = ({ }) // Add reverse linkages if there are any for this node - const foreignReferences = foreignReferenceMap[createRefId(entryItem)] + const foreignReferences = + foreignReferenceMap[createRefId(entryItem, space.sys.id)] const linkedFromFields = {} if (foreignReferences) { foreignReferences.forEach(foreignReference => { diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index d38452a5710b9..1d94c0d994197 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -238,6 +238,7 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = existingNodes, entryList, assets, + spaceId: space.sys.id, }) // Build foreign reference map before starting to insert any nodes @@ -268,7 +269,7 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = entryList.forEach(entries => { entries.forEach(entry => { if (entry) { - newOrUpdatedEntries?.add(createRefId(entry)) + newOrUpdatedEntries?.add(createRefId(entry, space.sys.id)) } }) }) @@ -380,7 +381,7 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = ) { return } - const refId = createRefId(n) + const refId = createRefId(n, space.sys.id) if (n.sys.id && foreignReferenceMap[refId]) { foreignReferenceMap[refId].forEach(foreignReference => { const { name, id, type, spaceId } = foreignReference From cdede37fce42dcad01f4e0e3507465f75eb481cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 29 Jun 2023 16:13:17 +0200 Subject: [PATCH 085/149] feat: large projects now can decide which text fields are turned into markdown nodes --- .../create-schema-customization.js.snap | 8 +-- .../src/__tests__/gatsby-node.js | 44 +++++++++++++- .../src/__tests__/normalize.js | 8 +-- .../src/create-schema-customization.ts | 47 ++++++++++++--- .../src/gatsby-node.ts | 14 +++++ .../gatsby-source-contentful/src/normalize.ts | 60 ++++++++++++------- .../src/plugin-options.ts | 4 +- .../src/source-nodes.ts | 4 +- .../src/types/plugin.ts | 2 + .../gatsby-source-contentful/src/utils.ts | 24 ++++++++ 10 files changed, 174 insertions(+), 41 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index a491346b0619d..f4037db343a99 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -387,7 +387,7 @@ Ignored if layout = FLUID.", "interfaces": Array [ "Node", ], - "name": "ContentfulText", + "name": "ContentfulMarkdown", }, ], Array [ @@ -447,7 +447,7 @@ Ignored if layout = FLUID.", "from": "longLocalized", }, }, - "type": "ContentfulText", + "type": "ContentfulMarkdown", }, "longMarkdown": Object { "extensions": Object { @@ -456,7 +456,7 @@ Ignored if layout = FLUID.", "from": "longMarkdown", }, }, - "type": "ContentfulText", + "type": "ContentfulMarkdown", }, "longPlain": Object { "extensions": Object { @@ -465,7 +465,7 @@ Ignored if layout = FLUID.", "from": "longPlain", }, }, - "type": "ContentfulText", + "type": "ContentfulMarkdown", }, "metadata": Object { "type": "ContentfulMetadata!", diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index d69ebf3f5f04f..8f56532b1726d 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -26,6 +26,7 @@ jest.mock(`gatsby-core-utils`, () => { } }) +/** @type {import("gatsby-plugin-utils/types").IPluginInfoOptions} */ const defaultPluginOptions = { ...defaultOptions, spaceId: `testSpaceId`, @@ -284,7 +285,7 @@ describe(`gatsby-node`, () => { break } case `Text`: { - const linkId = createNodeId(`${nodeId}${field}TextNode`) + const linkId = createNodeId(`${nodeId}${field}MarkdownNode`) matchedObject[field] = linkId break } @@ -1114,6 +1115,47 @@ describe(`gatsby-node`, () => { }) }) + it(`should ignore markdown conversion when disabled in config`, async () => { + // @ts-ignore + fetchContent.mockImplementationOnce(startersBlogFixture.initialSync) + schema.buildObjectType.mockClear() + + await simulateGatsbyBuild({ + ...defaultPluginOptions, + enableMarkdownDetection: false, + }) + expect(actions.createNode).toHaveBeenCalledTimes(18) + expect(actions.deleteNode).toHaveBeenCalledTimes(0) + expect(actions.touchNode).toHaveBeenCalledTimes(0) + + expect( + actions.createNode.mock.calls.filter( + call => call[0].internal.type == `ContentfulMarkdown` + ) + ).toHaveLength(0) + }) + + it(`should be able to create markdown nodes from a predefined list in config`, async () => { + // @ts-ignore + fetchContent.mockImplementationOnce(startersBlogFixture.initialSync) + schema.buildObjectType.mockClear() + + await simulateGatsbyBuild({ + ...defaultPluginOptions, + enableMarkdownDetection: false, + markdownFields: [[`blogPost`, [`body`]]], + }) + expect(actions.createNode).toHaveBeenCalledTimes(24) + expect(actions.deleteNode).toHaveBeenCalledTimes(0) + expect(actions.touchNode).toHaveBeenCalledTimes(0) + + expect( + actions.createNode.mock.calls.filter( + call => call[0].internal.type == `ContentfulMarkdown` + ) + ).toHaveLength(6) + }) + it(`is able to render unpublished fields in Delivery API`, async () => { const locales = [`en-US`, `nl`] diff --git a/packages/gatsby-source-contentful/src/__tests__/normalize.js b/packages/gatsby-source-contentful/src/__tests__/normalize.js index 8298d9609dd2c..102727a43b652 100644 --- a/packages/gatsby-source-contentful/src/__tests__/normalize.js +++ b/packages/gatsby-source-contentful/src/__tests__/normalize.js @@ -236,8 +236,8 @@ describe(`Process contentful data (by name)`, () => { expect(nodeTypeCounts).toEqual( expect.objectContaining({ ContentfulContentType: contentTypeItems.length, - // Generated child entities - ContentfulText: 38, + // Generated markdown child entities + ContentfulMarkdown: 38, // 3 Brand Contentful entries ContentfulContentTypeBrand: 6, // 2 Category Contentful entries @@ -343,8 +343,8 @@ describe(`Process existing mutated nodes in warm build`, () => { expect(nodeTypeCounts).toEqual( expect.objectContaining({ ContentfulContentType: contentTypeItems.length, - // Child entities - ContentfulText: 38, + // Markdown child entities + ContentfulMarkdown: 38, // 3 Brand Contentful entries ContentfulContentTypeBrand: 6, // 2 Category Contentful entries diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index e30d8c6795537..a328f1d59fa94 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -20,7 +20,7 @@ import { CODES } from "./report" import { resolveGatsbyImageData } from "./gatsby-plugin-image" import { makeTypeName } from "./normalize" import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" -import type { IPluginOptions } from "./types/plugin" +import type { IPluginOptions, MarkdownFieldDefinition } from "./types/plugin" import type { ContentType, ContentTypeField, FieldItem } from "contentful" import type { @@ -28,6 +28,7 @@ import type { IContentfulEntry, IContentfulImageAPITransformerOptions, } from "./types/contentful" +import { detectMarkdownField } from "./utils" type CreateTypes = CreateSchemaCustomizationArgs["actions"]["createTypes"] @@ -50,9 +51,15 @@ const ContentfulDataTypes: Map< ], [ `Text`, + (): IContentfulGraphQLField => { + return { type: GraphQLString } + }, + ], + [ + `Markdown`, (field): IContentfulGraphQLField => { return { - type: `ContentfulText`, + type: `ContentfulMarkdown`, extensions: { link: { by: `id`, from: field.id }, }, @@ -191,9 +198,12 @@ const getLinkFieldType = ( // Translate Contentful field types to GraphQL field types const translateFieldType = ( field: ContentTypeField | FieldItem, + contentTypeItem: ContentType, schema: NodePluginSchema, createTypes: CreateTypes, - contentTypePrefix: string + contentTypePrefix: string, + enableMarkdownDetection: boolean, + markdownFields: MarkdownFieldDefinition ): GraphQLFieldConfig => { let fieldType if (field.type === `Array`) { @@ -218,9 +228,12 @@ const translateFieldType = ( ) : translateFieldType( field.items, + contentTypeItem, schema, createTypes, - contentTypePrefix + contentTypePrefix, + enableMarkdownDetection, + markdownFields ) fieldType = { ...fieldData, type: `[${fieldData.type}]` } @@ -234,8 +247,16 @@ const translateFieldType = ( contentTypePrefix ) } else { + // Detect markdown in text fields + const typeName = detectMarkdownField( + field as ContentTypeField, + contentTypeItem, + enableMarkdownDetection, + markdownFields + ) + // Primitive field types - const primitiveType = ContentfulDataTypes.get(field.type) + const primitiveType = ContentfulDataTypes.get(typeName) if (!primitiveType) { throw new Error(`Contentful field type ${field.type} is not supported.`) } @@ -299,6 +320,12 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] const contentTypePrefix = pluginConfig.get(`contentTypePrefix`) const useNameForId = pluginConfig.get(`useNameForId`) + const enableMarkdownDetection: boolean = pluginConfig.get( + `enableMarkdownDetection` + ) + const markdownFields: MarkdownFieldDefinition = new Map( + pluginConfig.get(`markdownFields`) + ) let contentTypeItems: Array if (process.env.GATSBY_WORKER_ID) { @@ -644,11 +671,10 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] }) ) - // Text - // TODO: Is there a way to have this as string and let transformer-remark replace it with an object? + // Text (Markdown, as text is a pure string) createTypes( schema.buildObjectType({ - name: `ContentfulText`, + name: `ContentfulMarkdown`, fields: { raw: `String!`, }, @@ -677,9 +703,12 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] } fields[field.id] = translateFieldType( field, + contentTypeItem, schema, createTypes, - contentTypePrefix + contentTypePrefix, + enableMarkdownDetection, + markdownFields ) }) diff --git a/packages/gatsby-source-contentful/src/gatsby-node.ts b/packages/gatsby-source-contentful/src/gatsby-node.ts index 32bc1e4c19532..2db889a7a2d1f 100644 --- a/packages/gatsby-source-contentful/src/gatsby-node.ts +++ b/packages/gatsby-source-contentful/src/gatsby-node.ts @@ -125,6 +125,20 @@ List of locales and their codes can be found in Contentful app -> Settings -> Lo For example, to exclude content types starting with "page" \`contentTypeFilter: contentType => !contentType.sys.id.startsWith('page')\`` ) .default(() => (): boolean => true), + enableMarkdownDetection: Joi.boolean() + .description( + `Assumes that every long text field in Contentful is a markdown field. Can be a performance bottle-neck on big projects. Requires gatsby-transformer-remark.` + ) + .default(true), + markdownFields: Joi.array() + .description( + `List of text fields that contain markdown content. Needs gatsby-transformer-remark.` + ) + .default([]) + .example([ + [`product`, [`description`, `summary`]], + [`otherContentTypeId`, [`someMarkdownFieldId`]], + ]), pageLimit: Joi.number() .integer() .description( diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index 15a92721544d4..9cfdd08382758 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -26,7 +26,11 @@ import type { DeletedEntry, EntitySys, } from "contentful" -import type { IProcessedPluginOptions } from "./types/plugin" +import type { + IProcessedPluginOptions, + MarkdownFieldDefinition, +} from "./types/plugin" +import { detectMarkdownField } from "./utils" export const makeTypeName = ( type: string, @@ -354,19 +358,19 @@ export const buildForeignReferenceMap = ({ return foreignReferenceMapState } -function prepareTextNode( +function prepareMarkdownNode( id: string, node: IContentfulEntry, _key: string, text: unknown ): Node { const str = _.isString(text) ? text : `` - const textNode: Node = { + const markdownNode: Node = { id, parent: node.id, raw: str, internal: { - type: `ContentfulText`, + type: `ContentfulMarkdown`, mediaType: `text/markdown`, content: str, // entryItem.sys.publishedAt is source of truth from contentful @@ -375,7 +379,7 @@ function prepareTextNode( children: [], } - return textNode + return markdownNode } let numberOfContentSyncDebugLogs = 0 @@ -547,6 +551,13 @@ export const createNodesForContentType = ({ createNode, }) + const enableMarkdownDetection: boolean = pluginConfig.get( + `enableMarkdownDetection` + ) + const markdownFields: MarkdownFieldDefinition = new Map( + pluginConfig.get(`markdownFields`) + ) + // Establish identifier for content type // Use `name` if specified, otherwise, use internal id (usually a natural-language constant, // but sometimes a base62 uuid generated by Contentful, hence the option) @@ -820,26 +831,35 @@ export const createNodesForContentType = ({ : f.id) === entryItemFieldKey ) if (field?.type === `Text`) { - const textNodeId = createNodeId( - `${entryNodeId}${entryItemFieldKey}TextNode` + const fieldType = detectMarkdownField( + field, + contentTypeItem, + enableMarkdownDetection, + markdownFields ) - // The Contentful model has `.sys.updatedAt` leading for an entry. If the updatedAt value - // of an entry did not change, then we can trust that none of its children were changed either. - // (That's why child nodes use the updatedAt of the parent node as their digest, too) - const existingNode = getNode(textNodeId) - if (existingNode?.updatedAt !== entryItem.sys.updatedAt) { - const textNode = prepareTextNode( - textNodeId, - entryNode, - entryItemFieldKey, - entryItemFields[entryItemFieldKey] + if (fieldType == `Markdown`) { + const textNodeId = createNodeId( + `${entryNodeId}${entryItemFieldKey}${fieldType}Node` ) - childrenNodes.push(textNode) - } + // The Contentful model has `.sys.updatedAt` leading for an entry. If the updatedAt value + // of an entry did not change, then we can trust that none of its children were changed either. + // (That's why child nodes use the updatedAt of the parent node as their digest, too) + const existingNode = getNode(textNodeId) + if (existingNode?.updatedAt !== entryItem.sys.updatedAt) { + const textNode = prepareMarkdownNode( + textNodeId, + entryNode, + entryItemFieldKey, + entryItemFields[entryItemFieldKey] + ) + + childrenNodes.push(textNode) + } - entryItemFields[entryItemFieldKey] = textNodeId + entryItemFields[entryItemFieldKey] = textNodeId + } } }) diff --git a/packages/gatsby-source-contentful/src/plugin-options.ts b/packages/gatsby-source-contentful/src/plugin-options.ts index 8101b93984df7..ecd9ba42c3cff 100644 --- a/packages/gatsby-source-contentful/src/plugin-options.ts +++ b/packages/gatsby-source-contentful/src/plugin-options.ts @@ -14,6 +14,8 @@ const defaultOptions: Omit = { pageLimit: DEFAULT_PAGE_LIMIT, useNameForId: true, contentTypePrefix: `ContentfulContentType`, + enableMarkdownDetection: true, + markdownFields: [], } /** @@ -32,7 +34,7 @@ const maskText = (input: string): string => { } const createPluginConfig = ( - pluginOptions: IPluginOptions + pluginOptions: Partial ): IProcessedPluginOptions => { const conf = { ...defaultOptions, ...pluginOptions } diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index 1d94c0d994197..f5e96ede85017 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -245,8 +245,8 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = const previousForeignReferenceMapState = await cache.get( CACHE_FOREIGN_REFERENCE_MAP_STATE ) - const useNameForId = pluginConfig.get(`useNameForId`) - const contentTypePrefix = pluginConfig.get(`contentTypePrefix`) + const useNameForId: boolean = pluginConfig.get(`useNameForId`) + const contentTypePrefix: string = pluginConfig.get(`contentTypePrefix`) const foreignReferenceMapState = buildForeignReferenceMap({ contentTypeItems, diff --git a/packages/gatsby-source-contentful/src/types/plugin.ts b/packages/gatsby-source-contentful/src/types/plugin.ts index 3de051c9ade3a..8625fab893400 100644 --- a/packages/gatsby-source-contentful/src/types/plugin.ts +++ b/packages/gatsby-source-contentful/src/types/plugin.ts @@ -17,3 +17,5 @@ export interface IProcessedPluginOptions { get: (key: keyof IPluginOptions) => any getOriginalPluginOptions: () => IPluginOptions } + +export type MarkdownFieldDefinition = Map diff --git a/packages/gatsby-source-contentful/src/utils.ts b/packages/gatsby-source-contentful/src/utils.ts index d2af8783c6ff3..b0c573929144e 100644 --- a/packages/gatsby-source-contentful/src/utils.ts +++ b/packages/gatsby-source-contentful/src/utils.ts @@ -1,3 +1,6 @@ +import { ContentType, ContentTypeField } from "contentful" +import { MarkdownFieldDefinition } from "./types/plugin" + // When iterating on tons of objects, we don't want to block the event loop // this helper function returns a promise that resolves on the next tick so that the event loop can continue before we continue running blocking code export function untilNextEventLoopTick(): Promise { @@ -7,3 +10,24 @@ export function untilNextEventLoopTick(): Promise { }) }) } + +export function detectMarkdownField( + field: ContentTypeField, + contentTypeItem: ContentType, + enableMarkdownDetection: boolean, + markdownFields: MarkdownFieldDefinition +): string { + let typeName = field.type as string + + if (typeName == `Text` && enableMarkdownDetection) { + typeName = `Markdown` + } + + // Detect markdown based on given field ids + const markdownFieldDefinitions = markdownFields.get(contentTypeItem.sys.id) + if (markdownFieldDefinitions && markdownFieldDefinitions.includes(field.id)) { + typeName = `Markdown` + } + + return typeName +} From bc218a23ea2255cf5d6a978dfb71c7ca8edc5b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 29 Jun 2023 16:41:21 +0200 Subject: [PATCH 086/149] chore: remove TODO comment about already solved issue --- packages/gatsby-source-contentful/src/source-nodes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index f5e96ede85017..dd7c75d371235 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -342,7 +342,6 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = } } - // TODO: mirror structure of Contentful GraphQL API, as it prevents field name overlaps const reverseReferenceFields = contentTypeItems.map(contentTypeItem => useNameForId ? contentTypeItem?.name.toLowerCase() From ed5990c0939e923f2c4023bde7ba7a751226e28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 29 Jun 2023 16:42:31 +0200 Subject: [PATCH 087/149] chore: remove TODO comment about already solved issue #2 --- .../gatsby-source-contentful/src/create-schema-customization.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index a328f1d59fa94..bd937d086e245 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -678,7 +678,6 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] fields: { raw: `String!`, }, - // TODO: do we need a node interface here? interfaces: [`Node`], extensions: { dontInfer: {}, From 83105bedb9af6828ec1eb66fe2a433694ea13be5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 13 Jul 2023 11:17:48 +0200 Subject: [PATCH 088/149] chore: fix type error --- packages/gatsby-source-contentful/src/plugin-options.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/plugin-options.ts b/packages/gatsby-source-contentful/src/plugin-options.ts index ecd9ba42c3cff..d0555c25a428e 100644 --- a/packages/gatsby-source-contentful/src/plugin-options.ts +++ b/packages/gatsby-source-contentful/src/plugin-options.ts @@ -40,7 +40,8 @@ const createPluginConfig = ( return { get: (key): unknown => conf[key], - getOriginalPluginOptions: (): IPluginOptions => pluginOptions, + getOriginalPluginOptions: (): IPluginOptions => + pluginOptions as IPluginOptions, } } From 134404ec884afa102af5d59cc6702bd761948994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 13 Jul 2023 11:36:31 +0200 Subject: [PATCH 089/149] chore: improve typing of gatsby-plugin-image implementation --- .../src/create-schema-customization.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index bd937d086e245..f50477883ce09 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -10,6 +10,7 @@ import { GraphQLString, GraphQLType, } from "gatsby/graphql" +import type { ObjectTypeComposerArgumentConfigMapDefinition } from "graphql-compose" import { getRichTextEntityLinks } from "@contentful/rich-text-links" import { stripIndent } from "common-tags" import { addRemoteFilePolyfillInterface } from "gatsby-plugin-utils/polyfill-remote-file" @@ -471,11 +472,13 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] ) // Assets - const gatsbyImageData = getGatsbyImageFieldConfig( - async ( - image: IContentfulAsset, - options: IContentfulImageAPITransformerOptions - ) => resolveGatsbyImageData(image, options, { cache }), + const gatsbyImageData = getGatsbyImageFieldConfig< + IContentfulAsset, + null, + IContentfulImageAPITransformerOptions + >( + async (image, options) => + resolveGatsbyImageData(image, options, { cache }), { jpegProgressive: { type: `Boolean`, @@ -498,9 +501,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] type: `Int`, defaultValue: 50, }, - // TODO: fix the type for extraArgs in gatsby-plugin-iomage so we dont have to cast to any here - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any + } as unknown as ObjectTypeComposerArgumentConfigMapDefinition ) gatsbyImageData.type = `JSON` createTypes( From 5c1208a085cb7defaeb9b2a3cafc3965cd6ed6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 13 Jul 2023 11:38:27 +0200 Subject: [PATCH 090/149] chore: remove outdated TODO comment --- packages/gatsby-source-contentful/src/fetch.ts | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/gatsby-source-contentful/src/fetch.ts b/packages/gatsby-source-contentful/src/fetch.ts index 72a9b59905fad..845087538f0e2 100644 --- a/packages/gatsby-source-contentful/src/fetch.ts +++ b/packages/gatsby-source-contentful/src/fetch.ts @@ -80,17 +80,7 @@ const createContentfulErrorMessage = (e: any): string => { /** * Parse stringified error data from message * https://github.com/contentful/contentful-sdk-core/blob/4cfcd452ba0752237a26ce6b79d72a50af84d84e/src/error-handler.ts#L71-L75 - * - * TODO: properly type this with TS - * type { - * status?: number - * statusText?: string - * requestId?: string - * message: string - * !details: Record - * !request?: Record - * } - */ + **/ const errorData: IContentfulAPIError = JSON.parse(e.message) errorMessage.push(errorData.status && String(errorData.status)) errorMessage.push(errorData.statusText) From 51e28a304a182b7fcc39a966fee445577965afff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 13 Jul 2023 11:51:01 +0200 Subject: [PATCH 091/149] chore: removed obsolete TODO suggestion\ndelete node should take care of deleting child nodes on its own --- packages/gatsby-source-contentful/src/source-nodes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index dd7c75d371235..1c0cc1aa9339a 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -298,7 +298,6 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = }) localizedNodes.forEach(node => { - // TODO: nodes of text fields should be deleted as well if (node) { deleteNode(node) } From 01df3bb7ac604cf233516f46fb0546c2dac4ad1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 13 Jul 2023 11:54:31 +0200 Subject: [PATCH 092/149] chore: removed obsolete TODO suggestion\nGatsby drastically improved its performance when creating nodes --- packages/gatsby-source-contentful/src/source-nodes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index 1c0cc1aa9339a..e83dfd63e334b 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -565,7 +565,6 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = // A contentType can hold lots of entries which create nodes // We wait until all nodes are created and processed until we handle the next one - // TODO add batching in gatsby-core await createNodesForContentType({ contentTypeItem, entries: entryList[i], From 641832799327ecbb9c6be0b3e52a2c3e90ac38f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 13 Jul 2023 12:00:36 +0200 Subject: [PATCH 093/149] perf: create a map of field configurations instead of getting it multiple times in every node creation loop --- .../gatsby-source-contentful/src/normalize.ts | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index 9cfdd08382758..0fb6bdc0cd10c 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -25,6 +25,7 @@ import type { EntrySkeletonType, DeletedEntry, EntitySys, + ContentTypeField, } from "contentful" import type { IProcessedPluginOptions, @@ -595,6 +596,14 @@ export const createNodesForContentType = ({ create(contentTypeNode) + const fieldMap: Map = new Map() + contentTypeItem.fields.forEach(f => { + const fieldName = restrictedNodeFields.includes(f.id) + ? `${conflictFieldPrefix}${f.id}` + : f.id + fieldMap.set(fieldName, f) + }) + locales.forEach(locale => { const localesFallback = buildFallbackChain(locales) const mId = makeMakeId({ @@ -685,14 +694,7 @@ export const createNodesForContentType = ({ Object.keys(entryItemFields).forEach(entryItemFieldKey => { if (entryItemFields[entryItemFieldKey]) { const entryItemFieldValue = entryItemFields[entryItemFieldKey] - - // TODO:: how expensive is this? - const field = contentTypeItem.fields.find( - f => - (restrictedNodeFields.includes(f.id) - ? `${conflictFieldPrefix}${f.id}` - : f.id) === entryItemFieldKey - ) + const field = fieldMap.get(entryItemFieldKey) if ( field?.type === `Link` || (field?.type === `Array` && field.items?.type === `Link`) @@ -823,13 +825,7 @@ export const createNodesForContentType = ({ // Replace text fields with text nodes so we can process their markdown // into HTML. Object.keys(entryItemFields).forEach(entryItemFieldKey => { - // TODO:: how expensive is this? - const field = contentTypeItem.fields.find( - f => - (restrictedNodeFields.includes(f.id) - ? `${conflictFieldPrefix}${f.id}` - : f.id) === entryItemFieldKey - ) + const field = fieldMap.get(entryItemFieldKey) if (field?.type === `Text`) { const fieldType = detectMarkdownField( field, From 44bfc632ce5893942e7e86e6ef7e5972f7244247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 13 Jul 2023 12:33:57 +0200 Subject: [PATCH 094/149] chore: remove obsolete TODO comment --- packages/gatsby-source-contentful/src/normalize.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index 0fb6bdc0cd10c..28bab0a15f9b1 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -118,7 +118,6 @@ const makeMakeId = createNodeId(makeId({ spaceId, id, currentLocale, defaultLocale, type })) // Generates an unique id per space for reference resolving -// TODO: space id is actually not factored in here! export const createRefId = ( node: | IEntryWithAllLocalesAndWithoutLinkResolution From f1313152c0780a69ae8ea451882d83efac117f71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 13 Jul 2023 12:34:26 +0200 Subject: [PATCH 095/149] chore: remove obsolete TODO comment - we can not fully replicate Contentful structures here without colliding with Gatsby --- packages/gatsby-source-contentful/src/source-nodes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index e83dfd63e334b..db580b572ffee 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -623,7 +623,6 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = await createNode({ id: createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`), name: tag.name, - // TODO: update the structure of tags contentful_id: tag.sys.id, parent: null, children: [], From 62ccc7d9f130937ea4f93ccf64916b5869dc68a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 26 Jul 2023 10:33:44 +0200 Subject: [PATCH 096/149] fix: prevent local file nodes from being flagged as stale --- .../src/backreferences.ts | 44 +++++++++++++++---- .../src/source-nodes.ts | 1 + 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index 32f6e3f950e1a..d5087d72de8c2 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -1,10 +1,11 @@ -// @ts-check import { hasFeature } from "gatsby-plugin-utils/index" import { untilNextEventLoopTick } from "./utils" import { IContentfulEntry } from "./types/contentful" // @ts-ignore this is not available (yet) in typegen phase import { getDataStore } from "gatsby/dist/datastore" +import { Actions, Node, NodePluginArgs } from "gatsby" +import { IProcessedPluginOptions } from "./types/plugin" // Array of all existing Contentful nodes. Make it global and incrementally update it because it's hella slow to recreate this on every data update for large sites. export const existingNodes = new Map() @@ -26,7 +27,15 @@ const memoryNodeCountsBySysType: IMemoryNodesCountsBySysType = { Entry: 0, } -export async function getExistingCachedNodes({ actions, getNode }): Promise<{ +export async function getExistingCachedNodes({ + actions, + getNode, + pluginConfig, +}: { + actions: Actions + getNode: NodePluginArgs["getNode"] + pluginConfig: IProcessedPluginOptions +}): Promise<{ existingNodes: Map memoryNodeCountsBySysType: IMemoryNodesCountsBySysType }> { @@ -36,6 +45,8 @@ export async function getExistingCachedNodes({ actions, getNode }): Promise<{ !hasFeature(`stateful-source-nodes`) && is.firstSourceNodesCallOfCurrentNodeProcess + const needToTouchLocalFileNodes = pluginConfig.get(`downloadLocal`) + if (existingNodes.size === 0) { memoryNodeCountsBySysType.Asset = 0 memoryNodeCountsBySysType.Entry = 0 @@ -46,7 +57,7 @@ export async function getExistingCachedNodes({ actions, getNode }): Promise<{ for (const typeName of allNodeTypeNames) { const typeNodes = dataStore.iterateNodesByType(typeName) - const firstNodeOfType = Array.from(typeNodes.slice(0, 1))[0] as any + const firstNodeOfType = Array.from(typeNodes.slice(0, 1))[0] if ( !firstNodeOfType || @@ -58,12 +69,27 @@ export async function getExistingCachedNodes({ actions, getNode }): Promise<{ for (const node of typeNodes) { if (needToTouchNodes) { touchNode(node) - - if (node?.fields?.includes(`localFile`)) { - // Prevent GraphQL type inference from crashing on this property - const fullNode = getNode(node.id) - const localFileNode = getNode(fullNode.fields.localFile) - touchNode(localFileNode) + } + // Handle nodes created by downloadLocal + if ( + needToTouchLocalFileNodes && + node?.fields && + Object.keys(node?.fields).includes(`localFile`) + ) { + // Prevent GraphQL type inference from crashing on this property + interface INodeWithLocalFile extends Node { + fields: { + localFile: string + [key: string]: unknown + } + } + const fullNode = getNode(node.id) + if (fullNode) { + const localFileFullNode = fullNode as INodeWithLocalFile + const localFileNode = getNode(localFileFullNode.fields.localFile) + if (localFileNode) { + touchNode(localFileNode) + } } } diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index db580b572ffee..b5b5423462ea8 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -80,6 +80,7 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = await getExistingCachedNodes({ actions, getNode, + pluginConfig, }) // If the user knows they are offline, serve them cached result From d37d98de4aa062c8303a891d2d948f487b060128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 26 Jul 2023 11:18:36 +0200 Subject: [PATCH 097/149] build: clean up lock file --- yarn.lock | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/yarn.lock b/yarn.lock index 736204c98c8a1..0c3d799f43914 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11910,6 +11910,68 @@ gather-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" +gatsby-core-utils@^4.12.0-next.1: + version "4.12.0-next.1" + resolved "https://registry.yarnpkg.com/gatsby-core-utils/-/gatsby-core-utils-4.12.0-next.1.tgz#808becbfbf6707402c67e84548e1af7c45c4b2f1" + integrity sha512-KsYDrt+D1j3xSp7GbrvcZ3LBbVd3jjUTh3G1JyrT6aq1qeLXuQx6SBAwMKYdB8oFMGQXz/Zd5dWMimK2MDN0aw== + dependencies: + "@babel/runtime" "^7.20.13" + ci-info "2.0.0" + configstore "^5.0.1" + fastq "^1.15.0" + file-type "^16.5.4" + fs-extra "^11.1.1" + got "^11.8.6" + hash-wasm "^4.9.0" + import-from "^4.0.0" + lmdb "2.5.3" + lock "^1.1.0" + node-object-hash "^2.3.10" + proper-lockfile "^4.1.2" + resolve-from "^5.0.0" + tmp "^0.2.1" + xdg-basedir "^4.0.0" + +gatsby-plugin-sharp@^5.12.0-next.0: + version "5.12.0-next.1" + resolved "https://registry.yarnpkg.com/gatsby-plugin-sharp/-/gatsby-plugin-sharp-5.12.0-next.1.tgz#ae15aca241d9fcd415efeedf9167a155948bb36f" + integrity sha512-JK6tk2XiEtqVFQh3gLByEVChnHHwBKxi4lqU4ir0nq3itUUKORcUy/hH3yqNKUkFQyB/dv0C1wqVXzE92LC8nw== + dependencies: + "@babel/runtime" "^7.20.13" + async "^3.2.4" + bluebird "^3.7.2" + debug "^4.3.4" + filenamify "^4.3.0" + fs-extra "^11.1.1" + gatsby-core-utils "^4.12.0-next.1" + gatsby-plugin-utils "^4.12.0-next.1" + lodash "^4.17.21" + probe-image-size "^7.2.3" + semver "^7.5.3" + sharp "^0.32.1" + +gatsby-plugin-utils@^4.12.0-next.1: + version "4.12.0-next.1" + resolved "https://registry.yarnpkg.com/gatsby-plugin-utils/-/gatsby-plugin-utils-4.12.0-next.1.tgz#a693694f465eaa9db18a5c9c0593622ba5b6fbf2" + integrity sha512-xALBnAiQSUu7FH95LjkGutGwJhczMYG1QMuSkWhNgCy73bhJvZPihwgwFBNH808unypP6e8xNFjmjul109Alxg== + dependencies: + "@babel/runtime" "^7.20.13" + fastq "^1.15.0" + fs-extra "^11.1.1" + gatsby-core-utils "^4.12.0-next.1" + gatsby-sharp "^1.12.0-next.1" + graphql-compose "^9.0.10" + import-from "^4.0.0" + joi "^17.9.2" + mime "^3.0.0" + +gatsby-sharp@^1.12.0-next.1: + version "1.12.0-next.1" + resolved "https://registry.yarnpkg.com/gatsby-sharp/-/gatsby-sharp-1.12.0-next.1.tgz#2243ac0ee65b8590fa245c0f4b252e65a3c3dd8d" + integrity sha512-q7+rYMk3eOh/Wm+hvhJxsXxjLp6OIMH1lAs7+pORvyjsuwxtU29s7txT/3b71xsQTld/QxW79Ed5FHjtTDN9lw== + dependencies: + sharp "^0.32.1" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" From 4ecd4f07dbe2c5d06c0adf040b5f3421b84ddcc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 26 Jul 2023 12:25:55 +0200 Subject: [PATCH 098/149] build: fix version requirement --- packages/gatsby-source-contentful/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/package.json b/packages/gatsby-source-contentful/package.json index a993bea73ff78..c7e720e9f37e7 100644 --- a/packages/gatsby-source-contentful/package.json +++ b/packages/gatsby-source-contentful/package.json @@ -35,7 +35,7 @@ "babel-preset-gatsby-package": "^3.13.0-next.0", "cross-env": "^7.0.3", "del-cli": "^5.0.0", - "gatsby-plugin-sharp": "^5.12.0-next.0", + "gatsby-plugin-sharp": "^5.13.0-next.0", "nock": "^13.3.1", "typescript": "^5.0.4" }, From f1a338e04981c7aa067798249a04d8e38bc35d90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 26 Jul 2023 17:25:00 +0200 Subject: [PATCH 099/149] build: update yarn.lock --- yarn.lock | 62 ------------------------------------------------------- 1 file changed, 62 deletions(-) diff --git a/yarn.lock b/yarn.lock index 0c3d799f43914..736204c98c8a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -11910,68 +11910,6 @@ gather-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" -gatsby-core-utils@^4.12.0-next.1: - version "4.12.0-next.1" - resolved "https://registry.yarnpkg.com/gatsby-core-utils/-/gatsby-core-utils-4.12.0-next.1.tgz#808becbfbf6707402c67e84548e1af7c45c4b2f1" - integrity sha512-KsYDrt+D1j3xSp7GbrvcZ3LBbVd3jjUTh3G1JyrT6aq1qeLXuQx6SBAwMKYdB8oFMGQXz/Zd5dWMimK2MDN0aw== - dependencies: - "@babel/runtime" "^7.20.13" - ci-info "2.0.0" - configstore "^5.0.1" - fastq "^1.15.0" - file-type "^16.5.4" - fs-extra "^11.1.1" - got "^11.8.6" - hash-wasm "^4.9.0" - import-from "^4.0.0" - lmdb "2.5.3" - lock "^1.1.0" - node-object-hash "^2.3.10" - proper-lockfile "^4.1.2" - resolve-from "^5.0.0" - tmp "^0.2.1" - xdg-basedir "^4.0.0" - -gatsby-plugin-sharp@^5.12.0-next.0: - version "5.12.0-next.1" - resolved "https://registry.yarnpkg.com/gatsby-plugin-sharp/-/gatsby-plugin-sharp-5.12.0-next.1.tgz#ae15aca241d9fcd415efeedf9167a155948bb36f" - integrity sha512-JK6tk2XiEtqVFQh3gLByEVChnHHwBKxi4lqU4ir0nq3itUUKORcUy/hH3yqNKUkFQyB/dv0C1wqVXzE92LC8nw== - dependencies: - "@babel/runtime" "^7.20.13" - async "^3.2.4" - bluebird "^3.7.2" - debug "^4.3.4" - filenamify "^4.3.0" - fs-extra "^11.1.1" - gatsby-core-utils "^4.12.0-next.1" - gatsby-plugin-utils "^4.12.0-next.1" - lodash "^4.17.21" - probe-image-size "^7.2.3" - semver "^7.5.3" - sharp "^0.32.1" - -gatsby-plugin-utils@^4.12.0-next.1: - version "4.12.0-next.1" - resolved "https://registry.yarnpkg.com/gatsby-plugin-utils/-/gatsby-plugin-utils-4.12.0-next.1.tgz#a693694f465eaa9db18a5c9c0593622ba5b6fbf2" - integrity sha512-xALBnAiQSUu7FH95LjkGutGwJhczMYG1QMuSkWhNgCy73bhJvZPihwgwFBNH808unypP6e8xNFjmjul109Alxg== - dependencies: - "@babel/runtime" "^7.20.13" - fastq "^1.15.0" - fs-extra "^11.1.1" - gatsby-core-utils "^4.12.0-next.1" - gatsby-sharp "^1.12.0-next.1" - graphql-compose "^9.0.10" - import-from "^4.0.0" - joi "^17.9.2" - mime "^3.0.0" - -gatsby-sharp@^1.12.0-next.1: - version "1.12.0-next.1" - resolved "https://registry.yarnpkg.com/gatsby-sharp/-/gatsby-sharp-1.12.0-next.1.tgz#2243ac0ee65b8590fa245c0f4b252e65a3c3dd8d" - integrity sha512-q7+rYMk3eOh/Wm+hvhJxsXxjLp6OIMH1lAs7+pORvyjsuwxtU29s7txT/3b71xsQTld/QxW79Ed5FHjtTDN9lw== - dependencies: - sharp "^0.32.1" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" From 37af2ba8bd9ca253bc1e001bb6086ae5d3e2955c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 28 Jul 2023 10:22:19 +0200 Subject: [PATCH 100/149] chore: fix type error --- packages/gatsby-source-contentful/src/backreferences.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index d5087d72de8c2..dcf55c2d290ab 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -61,7 +61,7 @@ export async function getExistingCachedNodes({ if ( !firstNodeOfType || - firstNodeOfType.internal.owner !== `gatsby-source-contentful` + firstNodeOfType.internal?.owner !== `gatsby-source-contentful` ) { continue } From 935d13245ce9da39f58b262d579f3235fde7fd7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 28 Jul 2023 10:36:27 +0200 Subject: [PATCH 101/149] chore: fix typing issue --- packages/gatsby-source-contentful/src/backreferences.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index dcf55c2d290ab..1fd6293e24d3a 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -55,13 +55,13 @@ export async function getExistingCachedNodes({ const allNodeTypeNames = Array.from(dataStore.getTypes()) for (const typeName of allNodeTypeNames) { - const typeNodes = dataStore.iterateNodesByType(typeName) + const typeNodes: Array = dataStore.iterateNodesByType(typeName) const firstNodeOfType = Array.from(typeNodes.slice(0, 1))[0] if ( !firstNodeOfType || - firstNodeOfType.internal?.owner !== `gatsby-source-contentful` + firstNodeOfType.internal.owner !== `gatsby-source-contentful` ) { continue } From feab1d9047fbbe48d8800bea941d3af4ef21274c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 28 Jul 2023 11:02:57 +0200 Subject: [PATCH 102/149] chore: fix typing issue #2 --- packages/gatsby-source-contentful/src/backreferences.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index 1fd6293e24d3a..c337562c4a675 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -55,7 +55,9 @@ export async function getExistingCachedNodes({ const allNodeTypeNames = Array.from(dataStore.getTypes()) for (const typeName of allNodeTypeNames) { - const typeNodes: Array = dataStore.iterateNodesByType(typeName) + const typeNodes = dataStore.iterateNodesByType( + typeName + ) as Array as Array const firstNodeOfType = Array.from(typeNodes.slice(0, 1))[0] From 4305f700392cf6276c973df670c245ef95669b94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 11 Aug 2023 13:11:38 +0200 Subject: [PATCH 103/149] fix: typing issue --- packages/gatsby-source-contentful/src/backreferences.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index c337562c4a675..d5087d72de8c2 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -55,9 +55,7 @@ export async function getExistingCachedNodes({ const allNodeTypeNames = Array.from(dataStore.getTypes()) for (const typeName of allNodeTypeNames) { - const typeNodes = dataStore.iterateNodesByType( - typeName - ) as Array as Array + const typeNodes = dataStore.iterateNodesByType(typeName) const firstNodeOfType = Array.from(typeNodes.slice(0, 1))[0] From 1847bb8703fe4a2ca1a5d15824181bd0c84e7f05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 31 Aug 2023 14:08:28 +0200 Subject: [PATCH 104/149] chore: improve typing to satisfy typegen on CI --- .../gatsby-source-contentful/src/backreferences.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index d5087d72de8c2..bcc5aa28885a0 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -1,11 +1,12 @@ import { hasFeature } from "gatsby-plugin-utils/index" import { untilNextEventLoopTick } from "./utils" -import { IContentfulEntry } from "./types/contentful" +import type { IContentfulEntry } from "./types/contentful" // @ts-ignore this is not available (yet) in typegen phase import { getDataStore } from "gatsby/dist/datastore" -import { Actions, Node, NodePluginArgs } from "gatsby" -import { IProcessedPluginOptions } from "./types/plugin" +import type { Actions, Node, NodePluginArgs } from "gatsby" +import type { IProcessedPluginOptions } from "./types/plugin" +import type { IGatsbyNode } from "gatsby/dist/redux/types" // Array of all existing Contentful nodes. Make it global and incrementally update it because it's hella slow to recreate this on every data update for large sites. export const existingNodes = new Map() @@ -57,7 +58,9 @@ export async function getExistingCachedNodes({ for (const typeName of allNodeTypeNames) { const typeNodes = dataStore.iterateNodesByType(typeName) - const firstNodeOfType = Array.from(typeNodes.slice(0, 1))[0] + const firstNodeOfType = Array.from( + typeNodes.slice(0, 1) + )[0] as unknown as IGatsbyNode if ( !firstNodeOfType || From 24c07bd257512b43bff7b0548e10f49dafabb152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 31 Aug 2023 14:34:52 +0200 Subject: [PATCH 105/149] fix: improve reporter progress (bar) implementation --- .../gatsby-source-contentful/src/fetch.ts | 22 +++++++++++++------ .../src/source-nodes.ts | 2 +- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/gatsby-source-contentful/src/fetch.ts b/packages/gatsby-source-contentful/src/fetch.ts index bc0b700eae757..42e1472026091 100644 --- a/packages/gatsby-source-contentful/src/fetch.ts +++ b/packages/gatsby-source-contentful/src/fetch.ts @@ -7,6 +7,7 @@ import { } from "contentful" import type { Reporter } from "gatsby" import _ from "lodash" +import type { Span } from "opentracing" import { formatPluginOptionsForCLI } from "./plugin-options" import { CODES } from "./report" @@ -20,6 +21,7 @@ import type { ContentfulCollection, } from "contentful" import type { IProcessedPluginOptions } from "./types/plugin" +import type { IProgressReporter } from "gatsby-cli/lib/reporter/reporter-progress" /** * Generate a user friendly error message. @@ -113,11 +115,11 @@ const createContentfulErrorMessage = (e: any): string => { function createContentfulClientOptions({ pluginConfig, reporter, - syncProgress = { total: 0, tick: a => a }, + syncProgress, }: { pluginConfig: IProcessedPluginOptions reporter: Reporter - syncProgress?: { total: number; tick: (a: number) => unknown } + syncProgress?: IProgressReporter }): CreateClientParams { let syncItemCount = 0 @@ -149,7 +151,8 @@ function createContentfulClientOptions({ if ( response.config.url === `sync` && !response.isAxiosError && - response?.data.items + response?.data.items && + syncProgress ) { syncItemCount += response.data.items.length syncProgress.total = syncItemCount @@ -273,10 +276,12 @@ export async function fetchContent({ syncToken, pluginConfig, reporter, + parentSpan, }: { syncToken: string pluginConfig: IProcessedPluginOptions reporter: Reporter + parentSpan?: Span }): Promise { // Fetch locales and check connectivity const contentfulClientOptions = createContentfulClientOptions({ @@ -314,7 +319,10 @@ export async function fetchContent({ const syncProgress = reporter.createProgress( `Contentful: ${syncToken ? `Sync changed items` : `Sync all items`}`, pageLimit, - 0 + 0, + { + parentSpan, + } ) syncProgress.start() const contentfulSyncClientOptions = createContentfulClientOptions({ @@ -388,13 +396,13 @@ export async function fetchContent({ currentSyncData?.entries.length + currentSyncData?.assets.length + currentSyncData?.deletedEntries.length + - currentSyncData?.deletedAssets.length + currentSyncData?.deletedAssets.length === + 0 ) { syncProgress.tick() syncProgress.total = 1 } - - syncProgress.done() + syncProgress.end() } // We need to fetch tags with the non-sync API as the sync API doesn't support this. diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index b5b5423462ea8..70580964c6eb0 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -139,7 +139,7 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = defaultLocale, locales: allLocales = [], space, - } = await fetchContent({ syncToken, pluginConfig, reporter }) + } = await fetchContent({ syncToken, pluginConfig, reporter, parentSpan }) const contentTypeItems = (await cache.get( CACHE_CONTENT_TYPES From 96772cd270523defafa4b2856d72835e3aba1160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 31 Aug 2023 14:36:25 +0200 Subject: [PATCH 106/149] chore: another tryo to fix CI typegen --- packages/gatsby-source-contentful/src/backreferences.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/backreferences.ts b/packages/gatsby-source-contentful/src/backreferences.ts index bcc5aa28885a0..f505920ad0bc5 100644 --- a/packages/gatsby-source-contentful/src/backreferences.ts +++ b/packages/gatsby-source-contentful/src/backreferences.ts @@ -4,9 +4,10 @@ import type { IContentfulEntry } from "./types/contentful" // @ts-ignore this is not available (yet) in typegen phase import { getDataStore } from "gatsby/dist/datastore" +// @ts-ignore this is not available (yet) in typegen phase +import type { IGatsbyNode } from "gatsby/dist/redux/types" import type { Actions, Node, NodePluginArgs } from "gatsby" import type { IProcessedPluginOptions } from "./types/plugin" -import type { IGatsbyNode } from "gatsby/dist/redux/types" // Array of all existing Contentful nodes. Make it global and incrementally update it because it's hella slow to recreate this on every data update for large sites. export const existingNodes = new Map() From 4dc79b47ae3241c2dd6de673c2fb5e51eda519f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 31 Aug 2023 15:17:04 +0200 Subject: [PATCH 107/149] test: adjust fetch test for last merge --- packages/gatsby-source-contentful/src/__tests__/fetch.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/fetch.js b/packages/gatsby-source-contentful/src/__tests__/fetch.js index 7fa6294cb047f..bba516bf061a7 100644 --- a/packages/gatsby-source-contentful/src/__tests__/fetch.js +++ b/packages/gatsby-source-contentful/src/__tests__/fetch.js @@ -416,7 +416,6 @@ describe(`Displays troubleshooting tips and detailed plugin options on contentfu expect(mockClient.sync).toHaveBeenCalledWith({ initial: true, limit: 1000, - resolveLinks: false, }) mockClient.sync.mockClear() @@ -424,7 +423,6 @@ describe(`Displays troubleshooting tips and detailed plugin options on contentfu expect(mockClient.sync).toHaveBeenCalledWith({ nextSyncToken: `mocked`, - resolveLinks: false, }) }) }) From 00c047c93571c6c66581c7677a72fbb8189fef5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 15 Aug 2023 11:35:13 +0200 Subject: [PATCH 108/149] fix: add linkedFrom field to restricted/reserved field names --- .../src/create-schema-customization.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index f50477883ce09..b9a963a7141ea 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -694,7 +694,9 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] if (field.disabled || field.omitted) { return } - if ([`id`, `sys`, `contentfulMetadata`].includes(field.id)) { + if ( + [`id`, `sys`, `contentfulMetadata`, `linkedFrom`].includes(field.id) + ) { // Throw error on reserved field names as the Contenful GraphQL API does: // https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/fields throw new Error( From ff71a2748deacf4f3ed10b5795a9a433e268b0e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 15 Aug 2023 13:28:51 +0200 Subject: [PATCH 109/149] fix: use same list of restricted node fields everywhere --- packages/gatsby-source-contentful/src/config.ts | 2 +- .../src/create-schema-customization.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/gatsby-source-contentful/src/config.ts b/packages/gatsby-source-contentful/src/config.ts index 12309659ba558..1bcec72be805b 100644 --- a/packages/gatsby-source-contentful/src/config.ts +++ b/packages/gatsby-source-contentful/src/config.ts @@ -9,6 +9,6 @@ export const restrictedNodeFields = [ `internal`, // Contentful Common resource attributes: https://www.contentful.com/developers/docs/references/content-delivery-api/#/introduction/common-resource-attributes `sys`, - `metadata`, + `contentfulMetadata`, `linkedFrom`, ] diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index b9a963a7141ea..c4e30247d673e 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -30,6 +30,7 @@ import type { IContentfulImageAPITransformerOptions, } from "./types/contentful" import { detectMarkdownField } from "./utils" +import { restrictedNodeFields } from "./config" type CreateTypes = CreateSchemaCustomizationArgs["actions"]["createTypes"] @@ -694,9 +695,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] if (field.disabled || field.omitted) { return } - if ( - [`id`, `sys`, `contentfulMetadata`, `linkedFrom`].includes(field.id) - ) { + if (restrictedNodeFields.includes(field.id)) { // Throw error on reserved field names as the Contenful GraphQL API does: // https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/fields throw new Error( From cd15a05d2afde15a10131415c4a8bc73a75fed0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 15 Aug 2023 11:34:52 +0200 Subject: [PATCH 110/149] fix: rename metadata field to contentfulMetadata --- .../src/create-schema-customization.ts | 8 ++++---- packages/gatsby-source-contentful/src/normalize.ts | 4 ++-- packages/gatsby-source-contentful/src/types/contentful.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index c4e30247d673e..16f8d683ff944 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -350,7 +350,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] fields: { id: { type: `ID!` }, sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, + contentfulMetadata: { type: `ContentfulMetadata!` }, }, interfaces: [`Node`], }) @@ -362,7 +362,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] fields: { id: { type: `ID!` }, sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, + contentfulMetadata: { type: `ContentfulMetadata!` }, linkedFrom: { type: `ContentfulLinkedFrom` }, }, interfaces: [`ContentfulEntity`, `Node`], @@ -512,7 +512,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] fields: { id: { type: `ID!` }, sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, + contentfulMetadata: { type: `ContentfulMetadata!` }, gatsbyImageData, ...(pluginConfig.get(`downloadLocal`) ? { @@ -723,7 +723,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] fields: { id: { type: `ID!` }, sys: { type: `ContentfulSys!` }, - metadata: { type: `ContentfulMetadata!` }, + contentfulMetadata: { type: `ContentfulMetadata!` }, ...fields, linkedFrom: linkedFromName, }, diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index 28bab0a15f9b1..a231fa0395cb4 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -804,7 +804,7 @@ export const createNodesForContentType = ({ publishedAt: entryItem.sys.updatedAt, publishedVersion: entryItem.sys.revision, }, - metadata: { + contentfulMetadata: { tags: entryItem.metadata.tags.map(tag => createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) ), @@ -963,7 +963,7 @@ export const createAssetNodes = async ({ width: file.details?.image?.width ?? undefined, height: file.details?.image?.height ?? undefined, size: file.details?.size ?? null, - metadata: { + contentfulMetadata: { tags: assetItem.metadata.tags.map(tag => createNodeId(`ContentfulTag__${space.sys.id}__${tag.sys.id}`) ), diff --git a/packages/gatsby-source-contentful/src/types/contentful.ts b/packages/gatsby-source-contentful/src/types/contentful.ts index a9e9265c9d5fa..df62864685797 100644 --- a/packages/gatsby-source-contentful/src/types/contentful.ts +++ b/packages/gatsby-source-contentful/src/types/contentful.ts @@ -47,7 +47,7 @@ export interface IContentfulLink { interface IContentfulEntity extends Node { id: string sys: IContentfulSys - metadata: IContentfulMetadata + contentfulMetadata: IContentfulMetadata } export interface IContentfulEntry extends IContentfulEntity { From ddd8396e01d823747fb8a0cc8ce5eadfec300741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 15 Aug 2023 11:30:31 +0200 Subject: [PATCH 111/149] fix: take useNameForId into account when creating reference fields --- .../src/create-schema-customization.ts | 46 ++++++++++--------- .../gatsby-source-contentful/src/normalize.ts | 23 ++++------ .../gatsby-source-contentful/src/utils.ts | 23 ++++++++++ 3 files changed, 58 insertions(+), 34 deletions(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index 16f8d683ff944..a34a6673c10e1 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -29,7 +29,7 @@ import type { IContentfulEntry, IContentfulImageAPITransformerOptions, } from "./types/contentful" -import { detectMarkdownField } from "./utils" +import { detectMarkdownField, makeContentTypeIdMap } from "./utils" import { restrictedNodeFields } from "./config" type CreateTypes = CreateSchemaCustomizationArgs["actions"]["createTypes"] @@ -123,7 +123,7 @@ const getLinkFieldType = ( field: ContentTypeField, schema: NodePluginSchema, createTypes: CreateTypes, - contentTypePrefix: string + contentTypeIdMap: Map ): IContentfulGraphQLField => { // Check for validations const validations = @@ -141,8 +141,8 @@ const getLinkFieldType = ( : [linkContentType] // Full type names for union members, shorter variant for the union type name - const translatedTypeNames = contentTypes.map(typeName => - makeTypeName(typeName, contentTypePrefix) + const translatedTypeNames = contentTypes.map( + typeId => contentTypeIdMap.get(typeId) as string ) const shortTypeNames = contentTypes.map(typeName => makeTypeName(typeName, ``) @@ -203,9 +203,9 @@ const translateFieldType = ( contentTypeItem: ContentType, schema: NodePluginSchema, createTypes: CreateTypes, - contentTypePrefix: string, enableMarkdownDetection: boolean, - markdownFields: MarkdownFieldDefinition + markdownFields: MarkdownFieldDefinition, + contentTypeIdMap: Map ): GraphQLFieldConfig => { let fieldType if (field.type === `Array`) { @@ -226,16 +226,16 @@ const translateFieldType = ( field, schema, createTypes, - contentTypePrefix + contentTypeIdMap ) : translateFieldType( field.items, contentTypeItem, schema, createTypes, - contentTypePrefix, enableMarkdownDetection, - markdownFields + markdownFields, + contentTypeIdMap ) fieldType = { ...fieldData, type: `[${fieldData.type}]` } @@ -246,7 +246,7 @@ const translateFieldType = ( field as ContentTypeField, schema, createTypes, - contentTypePrefix + contentTypeIdMap ) } else { // Detect markdown in text fields @@ -440,13 +440,19 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] ) const reverseLinkFields = {} + const contentTypeIdMap = makeContentTypeIdMap( + contentTypeItems, + contentTypePrefix, + useNameForId + ) contentTypeItems.forEach(contentType => { - let contentTypeItemId - if (useNameForId) { - contentTypeItemId = makeTypeName(contentType.name, contentTypePrefix) - } else { - contentTypeItemId = makeTypeName(contentType.sys.id, contentTypePrefix) + const contentTypeItemId = contentTypeIdMap.get(contentType.sys.id) + + if (!contentTypeItemId) { + throw new Error( + `Could not locate id for content type ${contentType.sys.id} (${contentType.name})` + ) } if ( @@ -707,19 +713,17 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] contentTypeItem, schema, createTypes, - contentTypePrefix, enableMarkdownDetection, - markdownFields + markdownFields, + contentTypeIdMap ) }) - const type = useNameForId - ? contentTypeItem.name - : contentTypeItem.sys.id + const type = contentTypeIdMap.get(contentTypeItem.sys.id) as string createTypes( schema.buildObjectType({ - name: makeTypeName(type, contentTypePrefix), + name: type, fields: { id: { type: `ID!` }, sys: { type: `ContentfulSys!` }, diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index a231fa0395cb4..e0e9d8ce5f221 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -31,7 +31,7 @@ import type { IProcessedPluginOptions, MarkdownFieldDefinition, } from "./types/plugin" -import { detectMarkdownField } from "./utils" +import { detectMarkdownField, makeContentTypeIdMap } from "./utils" export const makeTypeName = ( type: string, @@ -268,19 +268,16 @@ export const buildForeignReferenceMap = ({ cleanupReferencesFromEntry(foreignReferenceMapState, deletedEntry) } + const contentTypeIdMap = makeContentTypeIdMap( + contentTypeItems, + contentTypePrefix, + useNameForId + ) + contentTypeItems.forEach((contentTypeItem, i) => { - // Establish identifier for content type - // Use `name` if specified, otherwise, use internal id (usually a natural-language constant, - // but sometimes a base62 uuid generated by Contentful, hence the option) - let contentTypeItemId - if (useNameForId) { - contentTypeItemId = makeTypeName(contentTypeItem.name, contentTypePrefix) - } else { - contentTypeItemId = makeTypeName( - contentTypeItem.sys.id, - contentTypePrefix - ) - } + const contentTypeItemId = contentTypeIdMap.get( + contentTypeItem.sys.id + ) as string entryList[i].forEach(entryItem => { // clear links added in previous runs for given entry, as we will recreate them anyway diff --git a/packages/gatsby-source-contentful/src/utils.ts b/packages/gatsby-source-contentful/src/utils.ts index b0c573929144e..10a9df7ae1903 100644 --- a/packages/gatsby-source-contentful/src/utils.ts +++ b/packages/gatsby-source-contentful/src/utils.ts @@ -1,5 +1,6 @@ import { ContentType, ContentTypeField } from "contentful" import { MarkdownFieldDefinition } from "./types/plugin" +import { makeTypeName } from "./normalize" // When iterating on tons of objects, we don't want to block the event loop // this helper function returns a promise that resolves on the next tick so that the event loop can continue before we continue running blocking code @@ -31,3 +32,25 @@ export function detectMarkdownField( return typeName } + +// Establish identifier for content type based on plugin options +// Use `name` if specified, otherwise, use internal id (usually a natural-language constant, +// but sometimes a base62 uuid generated by Contentful, hence the option) +export function makeContentTypeIdMap( + contentTypeItems: Array, + contentTypePrefix: string, + useNameForId: boolean +): Map { + const contentTypeIdMap: Map = new Map() + + contentTypeItems.forEach(contentType => { + let contentTypeItemId + if (useNameForId) { + contentTypeItemId = makeTypeName(contentType.name, contentTypePrefix) + } else { + contentTypeItemId = makeTypeName(contentType.sys.id, contentTypePrefix) + } + contentTypeIdMap.set(contentType.sys.id, contentTypeItemId) + }) + return contentTypeIdMap +} From fcf39305c70ea36aacf024105cf7beb2e043d217 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 31 Aug 2023 16:54:28 +0200 Subject: [PATCH 112/149] test: update test snapshots to reflect metadata rename --- .../create-schema-customization.js.snap | 78 +++++++++---------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index f4037db343a99..4d09a149ad6d2 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -160,6 +160,9 @@ Array [ "contentType": Object { "type": "String!", }, + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "description": Object { "type": "String", }, @@ -263,9 +266,6 @@ Ignored if layout = FLUID.", "linkedFrom": Object { "type": "ContentfulLinkedFrom", }, - "metadata": Object { - "type": "ContentfulMetadata!", - }, "mimeType": Object { "type": "String!", }, @@ -396,6 +396,9 @@ Ignored if layout = FLUID.", "dontInfer": Object {}, }, "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "decimal": Object { "type": "Float", }, @@ -412,9 +415,6 @@ Ignored if layout = FLUID.", "type": "Int", }, "linkedFrom": "ContentfulLinkedFrom", - "metadata": Object { - "type": "ContentfulMetadata!", - }, "sys": Object { "type": "ContentfulSys!", }, @@ -436,6 +436,9 @@ Ignored if layout = FLUID.", "dontInfer": Object {}, }, "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "id": Object { "type": "ID!", }, @@ -467,9 +470,6 @@ Ignored if layout = FLUID.", }, "type": "ContentfulMarkdown", }, - "metadata": Object { - "type": "ContentfulMetadata!", - }, "short": Object { "type": "String", }, @@ -503,6 +503,9 @@ Ignored if layout = FLUID.", "dontInfer": Object {}, }, "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "id": Object { "type": "ID!", }, @@ -525,9 +528,6 @@ Ignored if layout = FLUID.", }, "type": "[ContentfulAsset]", }, - "metadata": Object { - "type": "ContentfulMetadata!", - }, "one": Object { "extensions": Object { "link": Object { @@ -573,13 +573,13 @@ Ignored if layout = FLUID.", "booleanLocalized": Object { "type": "Boolean", }, + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "id": Object { "type": "ID!", }, "linkedFrom": "ContentfulLinkedFrom", - "metadata": Object { - "type": "ContentfulMetadata!", - }, "sys": Object { "type": "ContentfulSys!", }, @@ -601,6 +601,9 @@ Ignored if layout = FLUID.", "dontInfer": Object {}, }, "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "date": Object { "extensions": Object { "dateformat": Object {}, @@ -629,9 +632,6 @@ Ignored if layout = FLUID.", "type": "ID!", }, "linkedFrom": "ContentfulLinkedFrom", - "metadata": Object { - "type": "ContentfulMetadata!", - }, "sys": Object { "type": "ContentfulSys!", }, @@ -653,6 +653,9 @@ Ignored if layout = FLUID.", "dontInfer": Object {}, }, "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "id": Object { "type": "ID!", }, @@ -663,9 +666,6 @@ Ignored if layout = FLUID.", "locationLocalized": Object { "type": "ContentfulLocation", }, - "metadata": Object { - "type": "ContentfulMetadata!", - }, "sys": Object { "type": "ContentfulSys!", }, @@ -687,6 +687,9 @@ Ignored if layout = FLUID.", "dontInfer": Object {}, }, "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "id": Object { "type": "ID!", }, @@ -697,9 +700,6 @@ Ignored if layout = FLUID.", "type": "JSON", }, "linkedFrom": "ContentfulLinkedFrom", - "metadata": Object { - "type": "ContentfulMetadata!", - }, "sys": Object { "type": "ContentfulSys!", }, @@ -721,13 +721,13 @@ Ignored if layout = FLUID.", "dontInfer": Object {}, }, "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "id": Object { "type": "ID!", }, "linkedFrom": "ContentfulLinkedFrom", - "metadata": Object { - "type": "ContentfulMetadata!", - }, "richText": Object { "type": "ContentfulRichText", }, @@ -758,6 +758,9 @@ Ignored if layout = FLUID.", "dontInfer": Object {}, }, "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "id": Object { "type": "ID!", }, @@ -780,9 +783,6 @@ Ignored if layout = FLUID.", }, "type": "[ContentfulEntry]", }, - "metadata": Object { - "type": "ContentfulMetadata!", - }, "one": Object { "extensions": Object { "link": Object { @@ -822,13 +822,13 @@ Ignored if layout = FLUID.", "dontInfer": Object {}, }, "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "id": Object { "type": "ID!", }, "linkedFrom": "ContentfulLinkedFrom", - "metadata": Object { - "type": "ContentfulMetadata!", - }, "multipleItemsAllTypes": Object { "extensions": Object { "link": Object { @@ -906,12 +906,12 @@ Array [ Array [ Object { "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "id": Object { "type": "ID!", }, - "metadata": Object { - "type": "ContentfulMetadata!", - }, "sys": Object { "type": "ContentfulSys!", }, @@ -925,15 +925,15 @@ Array [ Array [ Object { "fields": Object { + "contentfulMetadata": Object { + "type": "ContentfulMetadata!", + }, "id": Object { "type": "ID!", }, "linkedFrom": Object { "type": "ContentfulLinkedFrom", }, - "metadata": Object { - "type": "ContentfulMetadata!", - }, "sys": Object { "type": "ContentfulSys!", }, From b892878c346fd909740f4d9c2d60fb6cc5cea200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 4 Sep 2023 10:26:56 +0200 Subject: [PATCH 113/149] test: fix e2e test to reflect metadata rename --- e2e-tests/contentful/src/pages/tags.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/e2e-tests/contentful/src/pages/tags.js b/e2e-tests/contentful/src/pages/tags.js index 376c07540b324..ab4ee7d44a68c 100644 --- a/e2e-tests/contentful/src/pages/tags.js +++ b/e2e-tests/contentful/src/pages/tags.js @@ -55,7 +55,7 @@ const TagsPage = ({ data }) => { data-cy-assets style={{ display: "flex", justifyContent: "space-between" }} > - {assets.map(({ title, url, metadata }) => { + {assets.map(({ title, url, contentfulMetadata }) => { const slug = slugify(title, { strict: true, lower: true }) return (
@@ -66,7 +66,7 @@ const TagsPage = ({ data }) => { alt={title} />
- {metadata.tags.map(({ name }) => ( + {contentfulMetadata.tags.map(({ name }) => ( Date: Mon, 4 Sep 2023 16:02:50 +0200 Subject: [PATCH 114/149] fix: big projects no more break due to vaulty foreign reference map --- packages/gatsby-source-contentful/src/normalize.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index e0e9d8ce5f221..00de62f18fc4f 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -202,7 +202,7 @@ interface IForeignReferenceMap { } interface IForeignReferenceMapState { - links: Array + links: { [key: string]: Array } backLinks: IForeignReferenceMap } @@ -257,7 +257,7 @@ export const buildForeignReferenceMap = ({ }): IForeignReferenceMapState => { const foreignReferenceMapState: IForeignReferenceMapState = previousForeignReferenceMapState || { - links: [], + links: {}, backLinks: {}, } From e72da87cacedcebb0da279bb4db65f3b3db0c0c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 4 Sep 2023 16:44:30 +0200 Subject: [PATCH 115/149] fix: ensure unions do not point on no more existing content types --- .../src/create-schema-customization.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index a34a6673c10e1..3ce807324db21 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -134,19 +134,27 @@ const getLinkFieldType = ( const linkContentTypeValidation = validations.find( ({ linkContentType }) => !!linkContentType ) - if (linkContentTypeValidation) { + if ( + linkContentTypeValidation && + linkContentTypeValidation.linkContentType + ) { const { linkContentType } = linkContentTypeValidation const contentTypes = Array.isArray(linkContentType) ? linkContentType : [linkContentType] + // We need to remove non existant content types from outdated validations to avoid broken unions + const filteredTypes = contentTypes.filter(typeId => + contentTypeIdMap.has(typeId) + ) + // Full type names for union members, shorter variant for the union type name - const translatedTypeNames = contentTypes.map( + const translatedTypeNames = filteredTypes.map( typeId => contentTypeIdMap.get(typeId) as string ) - const shortTypeNames = contentTypes.map(typeName => - makeTypeName(typeName, ``) - ) + const shortTypeNames = filteredTypes + .map(typeName => makeTypeName(typeName, ``)) + .sort() // Single content type if (translatedTypeNames.length === 1) { From 0d4f3c70d06c1bb212befd5d324f57a839acff91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 14 Sep 2023 11:57:26 +0200 Subject: [PATCH 116/149] fix: sys.contentType is now properly linked --- .../gatsby-source-contentful/src/create-schema-customization.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index 3ce807324db21..e0f9602136fd9 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -402,7 +402,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] contentType: { type: `ContentfulContentType`, extensions: { - link: { by: `id`, from: `sys.contentType` }, + link: { by: `id`, from: `contentType` }, }, }, firstPublishedAt: { type: ` Date!` }, From 36a29335fdf5e7bc3cbbf532d295e2cb8f8744f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 14 Sep 2023 12:39:00 +0200 Subject: [PATCH 117/149] test: update snapshot --- .../__tests__/__snapshots__/create-schema-customization.js.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index 4d09a149ad6d2..babe093df8330 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -37,7 +37,7 @@ Array [ "extensions": Object { "link": Object { "by": "id", - "from": "sys.contentType", + "from": "contentType", }, }, "type": "ContentfulContentType", From 6e68121c7416bc41db45ac627a07008d23f9647a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Mon, 18 Sep 2023 10:52:25 +0200 Subject: [PATCH 118/149] CTF-next: codemods to help for migration (#35113) * WIP - first codemods for graphql changes * feat: add name subfield for new contentType sys field * tell user about manual required changes and transform some content type selectors in code * feat: flatten asset filters * fix: all Contentful content type selectors within a query will now replaced * feat: apply changes to sys structure to js and improve sys.type edge-case handling * fix: take useNameForId into account when creating reference fields * fix: rename metadata field to contentfulMetadata * fix: add linkedFrom field to restricted/reserved field names * fix: use same list of restricted node fields everywhere * refactor: cleanup codemods * fix: avoid endless loop when transforming spaceId for sys * fix: avoid endless loop when transforming spaceId for sys * feat: basic support for fragments * test: initial fixtures for most yet implemented codemods * test: ensure fragments also support asset flattening * test: extend codemod test for fragments * feat: support inline fragments as well * feat: support flattening of single target contentful asset queries * feat: transform sys fields in single entity and collection queries * feat: add more tests and almost working asset object transform * feat: properly merge existing fields in sys and fix contentType transform * feat: add support for tags and rename metadata to contentfulMetadata * feat: support new sys and asset structures when sorting * feat: warn when using schema customizations or identifiers that match old sys field names * feat: properly restructure object destructure code with new sys structure * feat: flatten asset structure in js object selectors * feat: rename content type names within custom resolvers defined in a createResolvers implementation * chore: cleanup * feat: support typescript interfaces and improve content type selector renaming * fix: make codemods more reliable * chore: format using-contentful * refactor: migrate using-contentful example code via codemods * WIP - manual migrations * build: fix versions in using-contentful example * build: update yarn.lock --- examples/using-contentful/package.json | 17 +- .../using-contentful/src/layouts/index.js | 2 +- ... => {ContentfulContentTypeCategory.id}.js} | 30 +- .../using-contentful/src/pages/image-api.js | 4 +- examples/using-contentful/src/pages/index.js | 18 +- ...s => {ContentfulContentTypeProduct.id}.js} | 20 +- package.json | 3 +- packages/gatsby-codemods/src/bin/cli.js | 1 + .../content-types-typescript.input.ts | 3 + .../content-types-typescript.output.ts | 3 + .../content-types.input.js | 10 + .../content-types.output.js | 10 + .../contentful-asset.input.js | 7 + .../contentful-asset.output.js | 7 + .../contentful-sys.input.js | 11 + .../contentful-sys.output.js | 17 + .../gatsby-node.input.js | 14 + .../gatsby-node.output.js | 14 + .../graphql-content-type-all.input.js | 9 + .../graphql-content-type-all.output.js | 7 + .../graphql-content-type-fragment.input.js | 34 + .../graphql-content-type-fragment.output.js | 29 + .../graphql-content-type-single.input.js | 7 + .../graphql-content-type-single.output.js | 5 + .../graphql-contentful-assets.input.js | 37 + .../graphql-contentful-assets.output.js | 29 + .../graphql-contentful-metadata.input.js | 29 + .../graphql-contentful-metadata.output.js | 23 + .../graphql-contentful-sys.input.js | 45 ++ .../graphql-contentful-sys.output.js | 43 + .../__tests__/gatsby-source-contentful.js | 27 + .../transforms/gatsby-source-contentful.js | 734 ++++++++++++++++++ yarn.lock | 20 +- 33 files changed, 1223 insertions(+), 46 deletions(-) rename examples/using-contentful/src/pages/categories/{{ContentfulCategory.id}.js => {ContentfulContentTypeCategory.id}.js} (67%) rename examples/using-contentful/src/pages/products/{{ContentfulProduct.id}.js => {ContentfulContentTypeProduct.id}.js} (82%) create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types-typescript.input.ts create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types-typescript.output.ts create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types.input.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types.output.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-asset.input.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-asset.output.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-sys.input.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-sys.output.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/gatsby-node.input.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/gatsby-node.output.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-all.input.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-all.output.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-fragment.input.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-fragment.output.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-single.input.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-single.output.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-assets.input.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-assets.output.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-metadata.input.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-metadata.output.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-sys.input.js create mode 100644 packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-sys.output.js create mode 100644 packages/gatsby-codemods/src/transforms/__tests__/gatsby-source-contentful.js create mode 100644 packages/gatsby-codemods/src/transforms/gatsby-source-contentful.js diff --git a/examples/using-contentful/package.json b/examples/using-contentful/package.json index f1a66f4698077..1dff4a8fba838 100644 --- a/examples/using-contentful/package.json +++ b/examples/using-contentful/package.json @@ -5,13 +5,13 @@ "version": "1.0.0", "author": "Marcus Ericsson (mericsson.com)", "dependencies": { - "gatsby": "next", - "gatsby-core-utils": "next", - "gatsby-plugin-image": "next", - "gatsby-plugin-sharp": "next", - "gatsby-plugin-typography": "next", - "gatsby-source-contentful": "next", - "gatsby-transformer-remark": "next", + "gatsby": "^5.13.0-next.1", + "gatsby-core-utils": "^4.13.0-next.0", + "gatsby-plugin-image": "^3.13.0-next.0", + "gatsby-plugin-sharp": "^5.13.0-next.0", + "gatsby-plugin-typography": "^5.13.0-next.0", + "gatsby-source-contentful": "^8.13.0-next.1", + "gatsby-transformer-remark": "^6.13.0-next.0", "prop-types": "^15.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -24,9 +24,6 @@ ], "license": "MIT", "main": "n/a", - "resolutions": { - "contentful": "6.1.3" - }, "scripts": { "develop": "gatsby develop", "build": "gatsby build", diff --git a/examples/using-contentful/src/layouts/index.js b/examples/using-contentful/src/layouts/index.js index d8dfe39dd2a82..4608bb54abe5b 100644 --- a/examples/using-contentful/src/layouts/index.js +++ b/examples/using-contentful/src/layouts/index.js @@ -12,7 +12,7 @@ const DefaultLayout = ({ children }) => ( <>

Products

    - {product && - product.map((p, i) => ( + {ContentfulContentTypeProduct.length && + ContentfulContentTypeProduct.map((p, i) => (
  • - {p.productName.productName} + {p.productName.raw}
  • ))}
@@ -60,19 +60,21 @@ CategoryTemplate.propTypes = propTypes export default CategoryTemplate export const pageQuery = graphql` - query($id: String!) { - contentfulCategory(id: { eq: $id }) { + query ($id: String!) { + contentfulContentTypeCategory(id: { eq: $id }) { title { - title + raw } icon { gatsbyImageData(layout: FIXED, width: 75) } - product { - gatsbyPath(filePath: "/products/{ContentfulProduct.id}") - id - productName { - productName + linkedFrom { + ContentfulContentTypeProduct { + gatsbyPath(filePath: "/products/{ContentfulContentTypeProduct.id}") + id + productName { + raw + } } } } diff --git a/examples/using-contentful/src/pages/image-api.js b/examples/using-contentful/src/pages/image-api.js index fb1104abe76ad..2641241d03335 100644 --- a/examples/using-contentful/src/pages/image-api.js +++ b/examples/using-contentful/src/pages/image-api.js @@ -316,8 +316,8 @@ const ImageAPI = props => { export default ImageAPI export const pageQuery = graphql` - query { - allContentfulAsset(filter: { node_locale: { eq: "en-US" } }) { + { + allContentfulAsset(filter: { sys: { locale: { eq: "en-US" } } }) { edges { node { title diff --git a/examples/using-contentful/src/pages/index.js b/examples/using-contentful/src/pages/index.js index 3f9ef900e998c..e4c4fc9966c2c 100644 --- a/examples/using-contentful/src/pages/index.js +++ b/examples/using-contentful/src/pages/index.js @@ -85,14 +85,16 @@ IndexPage.propTypes = propTypes export default IndexPage export const pageQuery = graphql` - query { - us: allContentfulProduct(filter: { node_locale: { eq: "en-US" } }) { + { + us: allContentfulContentTypeProduct( + filter: { sys: { locale: { eq: "en-US" } } } + ) { edges { node { id - gatsbyPath(filePath: "/products/{ContentfulProduct.id}") + gatsbyPath(filePath: "/products/{ContentfulContentTypeProduct.id}") productName { - productName + raw } image { gatsbyImageData(layout: FIXED, width: 75) @@ -100,13 +102,15 @@ export const pageQuery = graphql` } } } - german: allContentfulProduct(filter: { node_locale: { eq: "de" } }) { + german: allContentfulContentTypeProduct( + filter: { sys: { locale: { eq: "de" } } } + ) { edges { node { id - gatsbyPath(filePath: "/products/{ContentfulProduct.id}") + gatsbyPath(filePath: "/products/{ContentfulContentTypeProduct.id}") productName { - productName + raw } image { gatsbyImageData(layout: FIXED, width: 75) diff --git a/examples/using-contentful/src/pages/products/{ContentfulProduct.id}.js b/examples/using-contentful/src/pages/products/{ContentfulContentTypeProduct.id}.js similarity index 82% rename from examples/using-contentful/src/pages/products/{ContentfulProduct.id}.js rename to examples/using-contentful/src/pages/products/{ContentfulContentTypeProduct.id}.js index 14f574714916d..8a46b44cad269 100644 --- a/examples/using-contentful/src/pages/products/{ContentfulProduct.id}.js +++ b/examples/using-contentful/src/pages/products/{ContentfulContentTypeProduct.id}.js @@ -13,9 +13,9 @@ const propTypes = { class ProductTemplate extends React.Component { render() { - const product = this.props.data.contentfulProduct + const product = this.props.data.contentfulContentTypeProduct const { - productName: { productName }, + productName: { raw: productName }, productDescription, price, image, @@ -39,7 +39,7 @@ class ProductTemplate extends React.Component { )}

{productName}

-

Made by {brand.companyName.companyName}

+

Made by {brand.companyName.raw}

Price: ${price}
(
  • - {category.title.title} + {category.title.raw}
  • ))} @@ -70,10 +70,10 @@ ProductTemplate.propTypes = propTypes export default ProductTemplate export const pageQuery = graphql` - query($id: String!) { - contentfulProduct(id: { eq: $id }) { + query ($id: String!) { + contentfulContentTypeProduct(id: { eq: $id }) { productName { - productName + raw } productDescription { childMarkdownRemark { @@ -86,14 +86,14 @@ export const pageQuery = graphql` } brand { companyName { - companyName + raw } } categories { id - gatsbyPath(filePath: "/categories/{ContentfulCategory.id}") + gatsbyPath(filePath: "/categories/{ContentfulContentTypeCategory.id}") title { - title + raw } } } diff --git a/package.json b/package.json index a858da92766a5..47a6d4485ef3d 100644 --- a/package.json +++ b/package.json @@ -126,7 +126,8 @@ "watch": "lerna run watch --no-sort --stream --concurrency 999" }, "workspaces": [ - "packages/*" + "packages/*", + "examples/using-contentful" ], "resolutions": { "@babel/plugin-transform-modules-commonjs": "7.18.6" diff --git a/packages/gatsby-codemods/src/bin/cli.js b/packages/gatsby-codemods/src/bin/cli.js index 4ca2827d31e89..ff851282408cc 100644 --- a/packages/gatsby-codemods/src/bin/cli.js +++ b/packages/gatsby-codemods/src/bin/cli.js @@ -2,6 +2,7 @@ import path from "path" import execa from "execa" const codemods = [ + `gatsby-source-contentful`, `gatsby-plugin-image`, `global-graphql-calls`, `import-link`, diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types-typescript.input.ts b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types-typescript.input.ts new file mode 100644 index 0000000000000..d06d64244e704 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types-typescript.input.ts @@ -0,0 +1,3 @@ +interface Data { + allContentfulTemplatePage: FooConnection +} \ No newline at end of file diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types-typescript.output.ts b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types-typescript.output.ts new file mode 100644 index 0000000000000..cf15eeef36404 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types-typescript.output.ts @@ -0,0 +1,3 @@ +interface Data { + allContentfulContentTypeTemplatePage: FooConnection +} \ No newline at end of file diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types.input.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types.input.js new file mode 100644 index 0000000000000..c4e29d055ab67 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types.input.js @@ -0,0 +1,10 @@ +const demo = [ + ...data.allContentfulFoo.nodes, + ...data.allContentfulBar.nodes, +] +const content = data.contentfulPage.content +const { + data: { + allContentfulTemplatePage: { nodes: templatePages }, + }, +} = await graphql(``) \ No newline at end of file diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types.output.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types.output.js new file mode 100644 index 0000000000000..97d0afc1e4848 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/content-types.output.js @@ -0,0 +1,10 @@ +const demo = [ + ...data.allContentfulContentTypeFoo.nodes, + ...data.allContentfulContentTypeBar.nodes, +] +const content = data.contentfulContentTypePage.content +const { + data: { + allContentfulContentTypeTemplatePage: { nodes: templatePages }, + }, +} = await graphql(``) \ No newline at end of file diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-asset.input.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-asset.input.js new file mode 100644 index 0000000000000..34b8bac2c5301 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-asset.input.js @@ -0,0 +1,7 @@ +import React from "react" + +export default () => ( + +) \ No newline at end of file diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-asset.output.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-asset.output.js new file mode 100644 index 0000000000000..330c083d93f19 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-asset.output.js @@ -0,0 +1,7 @@ +import React from "react" + +export default () => ( + +) \ No newline at end of file diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-sys.input.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-sys.input.js new file mode 100644 index 0000000000000..e6e4e4696953a --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-sys.input.js @@ -0,0 +1,11 @@ +const res1 = allContentfulPage.nodes.contentful_id +const res2 = allContentfulPage.nodes.sys.contentType.__typename +const { contentful_id, createdAt, updatedAt } = allContentfulPage.nodes +const { title, metaDescription, metaImage, content } = data.contentfulPage +const { foo } = result.data.allContentfulPage.nodes[0] +const { + revision, + sys: { + contentType: { __typename }, + }, +} = allContentfulPage.nodes diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-sys.output.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-sys.output.js new file mode 100644 index 0000000000000..3162c4b43f8b1 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/contentful-sys.output.js @@ -0,0 +1,17 @@ +const res1 = allContentfulPage.nodes.sys.id +const res2 = allContentfulPage.nodes.sys.contentType.name +const { + sys: { + id: contentful_id, + firstPublishedAt: createdAt, + publishedAt: updatedAt + } +} = allContentfulPage.nodes +const { title, metaDescription, metaImage, content } = data.contentfulContentTypePage +const { foo } = result.data.allContentfulContentTypePage.nodes[0] +const { + sys: { + publishedVersion: revision, + contentType: { name } + } +} = allContentfulPage.nodes diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/gatsby-node.input.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/gatsby-node.input.js new file mode 100644 index 0000000000000..0c603f87e12d8 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/gatsby-node.input.js @@ -0,0 +1,14 @@ +exports.createSchemaCustomization = null +export const createSchemaCustomization = null + +// export function createResolvers(actions) { +// actions.createResolvers({ +// ContentfulFoo: {}, +// }) +// } + +export const createResolvers = (actions) => { + actions.createResolvers({ + ContentfulFoo: {}, + }) +} \ No newline at end of file diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/gatsby-node.output.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/gatsby-node.output.js new file mode 100644 index 0000000000000..b4b44cc19fab2 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/gatsby-node.output.js @@ -0,0 +1,14 @@ +exports.createSchemaCustomization = null +export const createSchemaCustomization = null + +// export function createResolvers(actions) { +// actions.createResolvers({ +// ContentfulFoo: {}, +// }) +// } + +export const createResolvers = (actions) => { + actions.createResolvers({ + ContentfulContentTypeFoo: {}, + }) +} \ No newline at end of file diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-all.input.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-all.input.js new file mode 100644 index 0000000000000..c66bf5eaf0890 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-all.input.js @@ -0,0 +1,9 @@ +const result = await graphql` + { + allContentfulPage(limit: 1000) { + nodes { + id + } + } + } +` diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-all.output.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-all.output.js new file mode 100644 index 0000000000000..10a770abaddc4 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-all.output.js @@ -0,0 +1,7 @@ +const result = await graphql`{ + allContentfulContentTypePage(limit: 1000) { + nodes { + id + } + } +}` diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-fragment.input.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-fragment.input.js new file mode 100644 index 0000000000000..a368562c6f3ca --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-fragment.input.js @@ -0,0 +1,34 @@ +export const ExampleFragment = graphql` + fragment Example on ContentfulExample { + title + contentful_id + logo { + file { + url + fileName + contentType + details { + size + image { + width + height + } + } + } + } + } + { + allContentfulFoo { + nodes { + ... on ContentfulExample { + contentful_id + logo { + file { + url + } + } + } + } + } + } +` \ No newline at end of file diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-fragment.output.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-fragment.output.js new file mode 100644 index 0000000000000..2fedb08a9113a --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-fragment.output.js @@ -0,0 +1,29 @@ +export const ExampleFragment = graphql`fragment Example on ContentfulContentTypeExample { + title + sys { + id + } + logo { + url + fileName + contentType + size + width + height + } +} + +{ + allContentfulContentTypeFoo { + nodes { + ... on ContentfulContentTypeExample { + sys { + id + } + logo { + url + } + } + } + } +}` diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-single.input.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-single.input.js new file mode 100644 index 0000000000000..6f24e1c68328e --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-single.input.js @@ -0,0 +1,7 @@ +const result = await graphql(` + { + contentfulPage { + id + } + } +`) diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-single.output.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-single.output.js new file mode 100644 index 0000000000000..799e641992d3e --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-content-type-single.output.js @@ -0,0 +1,5 @@ +const result = await graphql(`{ + contentfulContentTypePage { + id + } +}`) diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-assets.input.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-assets.input.js new file mode 100644 index 0000000000000..248f80f3c80e5 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-assets.input.js @@ -0,0 +1,37 @@ +const result = await graphql(` + { + allContentfulPage( + filter: { logo: { file: { url: { ne: null } } } }, + sort: [{createdAt: ASC}, {logo: {file: {fileName: ASC}}}] + ) { + nodes { + id + logo { + file { + url + fileName + contentType + details { + size + image { + width + height + } + } + } + } + } + } + allContentfulAsset( + filter: {file: { url: { ne: null } }}, + sort: [{createdAt: ASC}, {file: {fileName: ASC}}] + ) { + nodes { + id + } + } + contentfulAsset(file: { url: { ne: null } }) { + id + } + } +`) diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-assets.output.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-assets.output.js new file mode 100644 index 0000000000000..98f4790628c6e --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-assets.output.js @@ -0,0 +1,29 @@ +const result = await graphql(`{ + allContentfulContentTypePage( + filter: {logo: {url: {ne: null}}} + sort: [{sys: {firstPublishedAt: ASC}}, {logo: {fileName: ASC}}] + ) { + nodes { + id + logo { + url + fileName + contentType + size + width + height + } + } + } + allContentfulAsset( + filter: {url: {ne: null}} + sort: [{sys: {firstPublishedAt: ASC}}, {fileName: ASC}] + ) { + nodes { + id + } + } + contentfulAsset(url: {ne: null}) { + id + } +}`) diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-metadata.input.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-metadata.input.js new file mode 100644 index 0000000000000..a946df7fd715a --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-metadata.input.js @@ -0,0 +1,29 @@ +const result = await graphql(` + { + allContentfulTag(sort: { fields: contentful_id }) { + nodes { + name + contentful_id + } + } + allContentfulNumber( + sort: { fields: contentful_id } + filter: { + metadata: { + tags: { elemMatch: { contentful_id: { eq: "numberInteger" } } } + } + } + ) { + nodes { + title + integer + metadata { + tags { + name + contentful_id + } + } + } + } + } +`) diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-metadata.output.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-metadata.output.js new file mode 100644 index 0000000000000..e9e6e1b952b4c --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-metadata.output.js @@ -0,0 +1,23 @@ +const result = await graphql(`{ + allContentfulTag(sort: {fields: contentful_id}) { + nodes { + name + contentful_id + } + } + allContentfulContentTypeNumber( + sort: {fields: contentful_id} + filter: {contentfulMetadata: {tags: {elemMatch: {contentful_id: {eq: "numberInteger"}}}}} + ) { + nodes { + title + integer + contentfulMetadata { + tags { + name + contentful_id + } + } + } + } +}`) diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-sys.input.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-sys.input.js new file mode 100644 index 0000000000000..6a2dbc9d3103e --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-sys.input.js @@ -0,0 +1,45 @@ +const result = await graphql(` + { + allContentfulPage(limit: 1000) { + nodes { + contentful_id + customName: node_locale + createdAt + updatedAt + revision + spaceId + sys { + type + contentType { + __typename + } + } + } + } + contentfulPage { + contentful_id + node_locale + createdAt + updatedAt + revision + spaceId + sys { + type + contentType { + __typename + } + } + } + allContentfulPage( + filter: { slug: { eq: "blog" }, node_locale: { eq: $locale } } + sort: { updatedAt: DESC } + ) { + nodes { + id + } + } + contentfulPage(slug: { eq: "blog" }, node_locale: { eq: $locale }) { + id + } + } +`) diff --git a/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-sys.output.js b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-sys.output.js new file mode 100644 index 0000000000000..a12f1e1e4998c --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__testfixtures__/gatsby-source-contentful/graphql-contentful-sys.output.js @@ -0,0 +1,43 @@ +const result = await graphql(`{ + allContentfulContentTypePage(limit: 1000) { + nodes { + sys { + id + customName: locale + firstPublishedAt + publishedAt + publishedVersion + spaceId + type + contentType { + name + } + } + } + } + contentfulContentTypePage { + sys { + id + locale + firstPublishedAt + publishedAt + publishedVersion + spaceId + type + contentType { + name + } + } + } + allContentfulContentTypePage( + filter: {slug: {eq: "blog"}, sys: {locale: {eq: $locale}}} + sort: {sys: {publishedAt: DESC}} + ) { + nodes { + id + } + } + contentfulContentTypePage(slug: {eq: "blog"}, sys: {locale: {eq: $locale}}) { + id + } +}`) diff --git a/packages/gatsby-codemods/src/transforms/__tests__/gatsby-source-contentful.js b/packages/gatsby-codemods/src/transforms/__tests__/gatsby-source-contentful.js new file mode 100644 index 0000000000000..f9a7c86eb4d56 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/__tests__/gatsby-source-contentful.js @@ -0,0 +1,27 @@ +const tests = [ + `content-types`, + `content-types-typescript`, + `contentful-asset`, + `contentful-sys`, + `gatsby-node`, + `graphql-content-type-all`, + `graphql-content-type-fragment`, + `graphql-content-type-single`, + `graphql-contentful-assets`, + `graphql-contentful-metadata`, + `graphql-contentful-sys`, +] + +const defineTest = require(`jscodeshift/dist/testUtils`).defineTest + +describe(`codemods`, () => { + tests.forEach(test => + defineTest( + __dirname, + `gatsby-source-contentful`, + null, + `gatsby-source-contentful/${test}`, + { parser: test.indexOf(`typescript`) !== -1 ? `ts` : `js` } + ) + ) +}) diff --git a/packages/gatsby-codemods/src/transforms/gatsby-source-contentful.js b/packages/gatsby-codemods/src/transforms/gatsby-source-contentful.js new file mode 100644 index 0000000000000..9e77eeba1b580 --- /dev/null +++ b/packages/gatsby-codemods/src/transforms/gatsby-source-contentful.js @@ -0,0 +1,734 @@ +import * as graphql from "graphql" +import { parse, print } from "recast" +import { transformFromAstSync, parseSync } from "@babel/core" +import { cloneDeep } from "lodash" + +export default function jsCodeShift(file) { + if ( + file.path.includes(`node_modules`) || + file.path.includes(`.cache`) || + file.path.includes(`public`) + ) { + return file.source + } + const transformedSource = babelRecast(file.source, file.path) + return transformedSource +} + +export function babelRecast(code, filePath) { + const transformedAst = parse(code, { + parser: { + parse: source => runParseSync(source, filePath), + }, + }) + + const changedTracker = { hasChanged: false, filename: filePath } // recast adds extra semicolons that mess with diffs and we want to avoid them + + const options = { + cloneInputAst: false, + code: false, + ast: true, + plugins: [[updateImport, changedTracker]], + } + + const { ast } = transformFromAstSync(transformedAst, code, options) + + if (changedTracker.hasChanged) { + return print(ast, { lineTerminator: `\n` }).code + } + return code +} + +const CONTENT_TYPE_SELECTOR_REGEX = /^(allContentful|[cC]ontentful)([A-Z0-9].+)/ +const CONTENT_TYPE_SELECTOR_BLACKLIST = [`Asset`, `Reference`, `Id`, `Tag`] +const SYS_FIELDS_TRANSFORMS = new Map([ + [`node_locale`, `locale`], + [`contentful_id`, `id`], + [`spaceId`, `spaceId`], + [`createdAt`, `firstPublishedAt`], + [`updatedAt`, `publishedAt`], + [`revision`, `publishedVersion`], +]) + +const isContentTypeSelector = selector => { + if (!selector) { + return false + } + const res = selector.match(CONTENT_TYPE_SELECTOR_REGEX) + return res && !CONTENT_TYPE_SELECTOR_BLACKLIST.includes(res[2]) +} +const updateContentfulSelector = selector => + selector.replace(`ontentful`, `ontentfulContentType`) + +const renderFilename = (path, state) => + `${state.opts.filename} (Line ${path.node.loc.start.line})` + +const injectNewFields = (selections, newFields, fieldToReplace) => { + if (!fieldToReplace) { + return [...selections, ...newFields] + } + + const fieldIndex = selections.findIndex( + ({ name }) => name?.value === fieldToReplace + ) + + return [ + ...selections.slice(0, fieldIndex), + ...newFields, + ...selections.slice(fieldIndex + 1), + ] +} + +function getNestedMemberExpressionProperties(node, t) { + const properties = [] + let current = node + while (t.isMemberExpression(current)) { + if (t.isIdentifier(current.property)) { + properties.push(current.property.name) + } + current = current.object + } + return properties.reverse() +} + +export function updateImport(babel) { + const { types: t } = babel + // Stack to keep track of nesting + const stack = [] + // Flag to indicate whether we are inside createResolvers function + let insideCreateResolvers = false + return { + visitor: { + Identifier(path, state) { + if ( + path.node.name === `createSchemaCustomization` && + state.opts.filename.match(/gatsby-node/) + ) { + console.log( + `${renderFilename( + path, + state + )}: Check your custom schema customizations if you patch or adjust schema related to Contentful. You probably can remove it now.` + ) + } + + // Rename content type identifiers within createResolvers + if (insideCreateResolvers) { + const variableName = path.node.name + + // Check if the variable name matches the regex + if (isContentTypeSelector(variableName)) { + path.node.name = updateContentfulSelector(variableName) + state.opts.hasChanged = true + } + } + }, + ObjectPattern: { + enter(path) { + // Push this ObjectPattern onto the stack as we enter it + stack.push(path.node.properties.map(prop => prop.key?.name)) + }, + exit(path, state) { + // Check if the variable name matches the regex + path.node.properties.forEach(prop => { + if (isContentTypeSelector(prop.key?.name)) { + prop.key.name = updateContentfulSelector(prop.key.name) + state.opts.hasChanged = true + } + }) + + // Rename contentType.__typename to contentType.name + if ( + JSON.stringify([[`sys`], [`contentType`], [`__typename`]]) === + JSON.stringify(stack) + ) { + const typenameProp = path.node.properties.find( + prop => prop.key.name === `__typename` + ) + if (typenameProp) { + typenameProp.key = t.identifier(`name`) + typenameProp.value = t.identifier(`name`) + } + // Merge old sys fields into new structure + } else { + const transformedSysProperties = [] + path.node.properties.forEach(property => { + if (SYS_FIELDS_TRANSFORMS.has(property.key?.name)) { + const transformedProp = { + ...property, + key: { + ...property.key, + name: SYS_FIELDS_TRANSFORMS.get(property.key.name), + }, + } + transformedSysProperties.push(transformedProp) + } + }) + if (transformedSysProperties.length) { + const sysField = { + type: `Property`, + key: { + type: `Identifier`, + name: `sys`, + }, + value: { + type: `ObjectPattern`, + properties: transformedSysProperties, + }, + } + path.node.properties = injectSysField( + sysField, + path.node.properties + ) + + state.opts.hasChanged = true + } + } + + // Pop this ObjectPattern off the stack as we exit it + stack.pop() + }, + }, + MemberExpression(path, state) { + const nestedProperties = getNestedMemberExpressionProperties( + path.node, + t + ) + + const assetFlatStructure = new Map([ + [`url`, [`url`, `file`]], + [`fileName`, [`fileName`, `file`]], + [`contentType`, [`contentType`, `file`]], + [`size`, [`size`, `details`, `file`]], + [`width`, [`width`, `image`, `details`, `file`]], + [`height`, [`height`, `image`, `details`, `file`]], + ]) + + for (const [newProp, oldProps] of assetFlatStructure) { + if ( + nestedProperties.slice(-oldProps.length).join(`.`) === + oldProps.reverse().join(`.`) + ) { + // We found a matching nested property. + // Rebuild the MemberExpression with the new structure. + let baseExpression = path.node + for (let i = 0; i < oldProps.length; i++) { + baseExpression = baseExpression.object + } + const newExpression = t.memberExpression( + baseExpression, + t.identifier(newProp) + ) + path.replaceWith(newExpression) + state.opts.hasChanged = true + return + } + } + + // Identify MemberExpression for `allContentfulPage.nodes.contentfulId` + const propName = path.node.property.name + const replacement = SYS_FIELDS_TRANSFORMS.get(propName) + + if (replacement) { + // Rewrite the MemberExpression with the new property + path.node.property = t.identifier(replacement) + + // Also rewrite the parent node to `.sys.` if it's not already + if (path.node.object.property?.name !== `sys`) { + path.node.object = t.memberExpression( + path.node.object, + t.identifier(`sys`) + ) + } + state.opts.hasChanged = true + } + + // Rename sys.contentType.__typename to sys.contentType.name + if ( + propName === `__typename` && + t.isMemberExpression(path.node.object) && + t.isIdentifier(path.node.object.property, { name: `contentType` }) && + t.isMemberExpression(path.node.object.object) && + t.isIdentifier(path.node.object.object.property, { name: `sys` }) + ) { + path.node.property = t.identifier(`name`) + return + } + + if (isContentTypeSelector(path.node.property?.name)) { + if ( + path.node.object?.name === `data` || + path.node.object.property?.name === `data` + ) { + path.node.property.name = updateContentfulSelector( + path.node.property.name + ) + state.opts.hasChanged = true + } else { + console.log( + `${renderFilename(path, state)}: You might need to change "${ + path.node.property?.name + }" to "${updateContentfulSelector(path.node.property.name)}"` + ) + } + } + }, + ExportNamedDeclaration: { + enter(path) { + const declaration = path.node.declaration + + // For "export function createResolvers() {}" + if ( + t.isFunctionDeclaration(declaration) && + t.isIdentifier(declaration.id, { name: `createResolvers` }) + ) { + insideCreateResolvers = true + } + + // For "export const createResolvers = function() {}" or "export const createResolvers = () => {}" + else if (t.isVariableDeclaration(declaration)) { + const declarators = declaration.declarations + for (const declarator of declarators) { + if ( + t.isIdentifier(declarator.id, { name: `createResolvers` }) && + (t.isFunctionExpression(declarator.init) || + t.isArrowFunctionExpression(declarator.init)) + ) { + insideCreateResolvers = true + } + } + } + }, + exit() { + insideCreateResolvers = false + }, + }, + TSInterfaceDeclaration(path, state) { + path.node.body.body.forEach(property => { + if ( + t.isTSPropertySignature(property) && + isContentTypeSelector(property.key.name) + ) { + property.key.name = updateContentfulSelector(property.key.name) + state.opts.hasChanged = true + } + }) + }, + TaggedTemplateExpression({ node }, state) { + if (node.tag.name !== `graphql`) { + return + } + const query = node.quasi?.quasis?.[0]?.value?.raw + if (query) { + const { ast: transformedGraphQLQuery, hasChanged } = + processGraphQLQuery(query, state) + + if (hasChanged) { + node.quasi.quasis[0].value.raw = graphql.print( + transformedGraphQLQuery + ) + state.opts.hasChanged = true + } + } + }, + CallExpression({ node }, state) { + if (node.callee.name !== `graphql`) { + return + } + const query = node.arguments?.[0].quasis?.[0]?.value?.raw + + if (query) { + const { ast: transformedGraphQLQuery, hasChanged } = + processGraphQLQuery(query, state) + + if (hasChanged) { + node.arguments[0].quasis[0].value.raw = graphql.print( + transformedGraphQLQuery + ) + state.opts.hasChanged = true + } + } + }, + }, + } +} + +// Locate a subfield within a selection set or fields +function locateSubfield(node, fieldName) { + const subFields = Array.isArray(node) + ? node + : node.selectionSet?.selections || node.value?.fields + if (!subFields) { + return null + } + return subFields.find(({ name }) => name?.value === fieldName) +} + +// Replace first old field occurence with new sys field +const injectSysField = (sysField, selections) => { + let sysInjected = false + + selections = selections + .map(field => { + const fieldName = field.name?.value || field.key?.name + if (fieldName === `sys`) { + const existingSysFields = ( + field.selectionSet?.selections || field.value.properties + ).map(subField => { + const kind = subField.kind || subField.type + // handle contentType rename + if ( + (kind === `ObjectProperty` + ? subField.key.name + : subField.name.value) === `contentType` + ) { + const subfields = + kind === `ObjectProperty` + ? subField.value.properties + : subField.selectionSet.selections + + subfields.map(contentTypeField => { + const fieldName = + kind === `ObjectProperty` + ? contentTypeField.key.name + : contentTypeField.name.value + + if (fieldName === `__typename`) { + if (kind === `ObjectProperty`) { + contentTypeField.key.name = `name` + } else { + contentTypeField.name.value = `name` + } + } + }) + } + return subField + }) + if (sysField?.type === `Property`) { + sysField.value.properties.push(...existingSysFields) + } else { + sysField.selectionSet.selections.push(...existingSysFields) + } + return null + } + return field + }) + .filter(Boolean) + + // Replace first old field occurence with new sys field + return selections + .map(field => { + const fieldName = field.name?.value || field.key?.name + if (SYS_FIELDS_TRANSFORMS.has(fieldName)) { + if (!sysInjected) { + // Inject for first occurence of a sys field + sysInjected = true + return sysField + } + // Remove all later fields + return null + } + // Keep non-sys fields as they are + return field + }) + .filter(Boolean) +} + +// Flatten the old deeply nested Contentful asset structure +const flattenAssetFields = node => { + const flatAssetFields = [] + + // Flatten asset file field + const fileField = locateSubfield(node, `file`) + + if (fileField) { + // Top level file fields + const urlField = locateSubfield(fileField, `url`) + if (urlField) { + flatAssetFields.push(urlField) + } + const fileNameField = locateSubfield(fileField, `fileName`) + if (fileNameField) { + flatAssetFields.push(fileNameField) + } + const contentTypeField = locateSubfield(fileField, `contentType`) + if (contentTypeField) { + flatAssetFields.push(contentTypeField) + } + + // details subfield with size and dimensions + const detailsField = locateSubfield(fileField, `details`) + if (detailsField) { + const sizeField = locateSubfield(detailsField, `size`) + if (sizeField) { + flatAssetFields.push(sizeField) + } + // width & height from image subfield + const imageField = locateSubfield(detailsField, `image`) + if (imageField) { + const widthField = locateSubfield(imageField, `width`) + if (widthField) { + flatAssetFields.push(widthField) + } + const heightField = locateSubfield(imageField, `height`) + if (heightField) { + flatAssetFields.push(heightField) + } + } + } + } + return flatAssetFields +} + +function createNewSysField(fields, fieldType = `Field`) { + const kind = fieldType === `Argument` ? `Argument` : `Field` + const subKindValue = fieldType === `Argument` ? `ObjectValue` : `SelectionSet` + const subKindIndex = fieldType === `Argument` ? `value` : `selectionSet` + const subKindIndex2 = fieldType === `Argument` ? `fields` : `selections` + + const contentfulSysFields = fields.filter(({ name }) => + SYS_FIELDS_TRANSFORMS.has(name?.value) + ) + + if (contentfulSysFields.length) { + const transformedSysFields = cloneDeep(contentfulSysFields).map(field => { + return { + ...field, + name: { + ...field.name, + value: SYS_FIELDS_TRANSFORMS.get(field.name.value), + }, + } + }) + + const sysField = { + kind: kind, + name: { + kind: `Name`, + value: `sys`, + }, + [subKindIndex]: { + kind: subKindValue, + [subKindIndex2]: transformedSysFields, + }, + } + return sysField + } + return null +} + +function processGraphQLQuery(query) { + try { + let hasChanged = false // this is sort of a hack, but print changes formatting and we only want to use it when we have to + const ast = graphql.parse(query) + + function processArguments(node) { + // flatten Contentful Asset filters + // Queries directly on allContentfulAssets + const flatAssetFields = flattenAssetFields(node) + if (flatAssetFields.length) { + node.value.fields = injectNewFields( + node.value.fields, + flatAssetFields, + `file` + ) + hasChanged = true + } + // Subfields that might be asset fields + node.value.fields.forEach((field, fieldIndex) => { + const flatAssetFields = flattenAssetFields(field) + if (flatAssetFields.length) { + node.value.fields[fieldIndex].value.fields = injectNewFields( + node.value.fields[fieldIndex].value.fields, + flatAssetFields, + `file` + ) + hasChanged = true + } + }) + + // Rename metadata -> contentfulMetadata + node.value.fields.forEach(field => { + if (field.name.value === `metadata`) { + field.name.value = `contentfulMetadata` + hasChanged = true + } + }) + + const sysField = createNewSysField(node.value.fields, `Argument`) + if (sysField) { + node.value.fields = injectSysField(sysField, node.value.fields) + hasChanged = true + } + } + + graphql.visit(ast, { + Argument(node) { + // Update filters and sort of collection endpoints + if ([`filter`, `sort`].includes(node.name.value)) { + if (node.value.kind === `ListValue`) { + node.value.values.forEach(node => processArguments({ value: node })) + return + } + processArguments(node) + } + }, + SelectionSet(node) { + // Rename content type node selectors + node.selections.forEach(field => { + if (isContentTypeSelector(field.name?.value)) { + field.name.value = updateContentfulSelector(field.name.value) + hasChanged = true + } + }) + }, + InlineFragment(node) { + if (isContentTypeSelector(node.typeCondition.name?.value)) { + node.typeCondition.name.value = updateContentfulSelector( + node.typeCondition.name.value + ) + hasChanged = true + + const sysField = createNewSysField(node.selectionSet.selections) + if (sysField) { + node.selectionSet.selections = injectSysField( + sysField, + node.selectionSet.selections + ) + hasChanged = true + } + } + }, + FragmentDefinition(node) { + if (isContentTypeSelector(node.typeCondition.name?.value)) { + node.typeCondition.name.value = updateContentfulSelector( + node.typeCondition.name.value + ) + hasChanged = true + + const sysField = createNewSysField(node.selectionSet.selections) + if (sysField) { + node.selectionSet.selections = injectSysField( + sysField, + node.selectionSet.selections + ) + hasChanged = true + } + } + }, + Field(node) { + // Flatten asset fields + if (node.name.value === `contentfulAsset`) { + const flatAssetFields = flattenAssetFields({ + value: { fields: node.arguments }, + }) + + node.arguments = injectNewFields( + node.arguments, + flatAssetFields, + `file` + ) + + hasChanged = true + } + + // Rename metadata -> contentfulMetadata + if (node.name.value === `metadata`) { + const tagsField = locateSubfield(node, `tags`) + if (tagsField) { + node.name.value = `contentfulMetadata` + hasChanged = true + } + } + + if (isContentTypeSelector(node.name.value)) { + // Move sys properties into new sys property + const nodesField = + node.name.value.indexOf(`all`) === 0 && + locateSubfield(node, `nodes`) + const rootNode = nodesField || node + + const sysField = createNewSysField(rootNode.selectionSet.selections) + if (sysField) { + rootNode.selectionSet.selections = injectSysField( + sysField, + rootNode.selectionSet.selections + ) + hasChanged = true + } + + const filterNode = + node.name.value.indexOf(`all`) === 0 && + locateSubfield(node.arguments, `filter`) + + const filterFields = filterNode?.value?.fields || node.arguments + + if (filterFields && filterFields.length) { + const sysField = createNewSysField(filterFields, `Argument`) + // Inject the new sys at the first occurence of any old sys field + if (sysField) { + if (node.name.value.indexOf(`all`) === 0) { + const filterFieldIndex = node.arguments.findIndex( + field => field.name?.value === `filter` + ) + node.arguments[filterFieldIndex].value.fields = injectSysField( + sysField, + node.arguments[filterFieldIndex].value.fields + ) + } else { + node.arguments = injectSysField(sysField, filterFields) + } + hasChanged = true + } + } + } + + // Flatten asset file field + const flatAssetFields = flattenAssetFields(node) + if (flatAssetFields.length) { + node.selectionSet.selections = injectNewFields( + node.selectionSet.selections, + flatAssetFields, + `file` + ) + hasChanged = true + } + }, + }) + return { ast, hasChanged } + } catch (err) { + throw new Error( + `GatsbySourceContentfulCodemod: GraphQL syntax error in query:\n\n${query}\n\nmessage:\n\n${err}` + ) + } +} + +function runParseSync(source, filePath) { + let ast + try { + ast = parseSync(source, { + plugins: [ + `@babel/plugin-syntax-jsx`, + `@babel/plugin-proposal-class-properties`, + ], + overrides: [ + { + test: [`**/*.ts`, `**/*.tsx`], + plugins: [[`@babel/plugin-syntax-typescript`, { isTSX: true }]], + }, + ], + filename: filePath, + parserOpts: { + tokens: true, // recast uses this + }, + }) + } catch (e) { + console.error(e) + } + if (!ast) { + console.log( + `The codemod was unable to parse ${filePath}. If you're running against the '/src' directory and your project has a custom babel config, try running from the root of the project so the codemod can pick it up.` + ) + } + return ast +} diff --git a/yarn.lock b/yarn.lock index 736204c98c8a1..48560fe05d3a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20334,7 +20334,7 @@ react-test-renderer@^16.14.0: react-is "^16.8.6" scheduler "^0.19.1" -react-typography@^0.16.23: +react-typography@^0.16.19, react-typography@^0.16.23: version "0.16.23" resolved "https://registry.yarnpkg.com/react-typography/-/react-typography-0.16.23.tgz#68c0af17ed876a30fcea256ef0dbbf0bc01b63b3" integrity sha512-nOl1/VDhqYSp5XktW/xmeLgE2S4L0LIWKAq2lNtc6Tq+3ZgvSX2Q0r0vlLKyOVq0hjsOYubE1TLoz/Wu/W8GLg== @@ -23771,11 +23771,29 @@ typescript@^5.0.4, typescript@^5.1.6: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== +typography-breakpoint-constants@^0.16.19: + version "0.16.19" + resolved "https://registry.yarnpkg.com/typography-breakpoint-constants/-/typography-breakpoint-constants-0.16.19.tgz#e0e89147749562cbb46ce76c47ff0f73372765e7" + integrity sha512-vXjfV9hwAXIOf5+U5GN137ahBkK+sj1TJu/5ksmP+8XB/D80lmGb/m0nKviWaQ3t7HLrK848VGrFS+6E2vcmVg== + typography-normalize@^0.16.19: version "0.16.19" resolved "https://registry.yarnpkg.com/typography-normalize/-/typography-normalize-0.16.19.tgz#58e0cf12466870c5b27006daa051fe7307780660" integrity sha512-vtnSv/uGBZVbd4e/ZhZB9HKBgKKlWQUXw74+ADIHHxzKp27CEf8PSR8TX1zF2qSyQ9/qMdqLwXYz8yRQFq9JLQ== +typography@^0.16.19: + version "0.16.24" + resolved "https://registry.yarnpkg.com/typography/-/typography-0.16.24.tgz#7bcbe3921367ca74168d0acce969749a0546fd4d" + integrity sha512-o5jNctzGoJm2XgdqivJdpkF6lQkcQo8v1biMGY+rLSpBHhpCKdQv5em9S3R6igApxVYtbhNBJbV95vK9oPwRKQ== + dependencies: + compass-vertical-rhythm "^1.4.5" + decamelize "^1.2.0" + gray-percentage "^2.0.0" + lodash "^4.13.1" + modularscale "^1.0.2" + object-assign "^4.1.0" + typography-normalize "^0.16.19" + typography@^0.16.21: version "0.16.21" resolved "https://registry.yarnpkg.com/typography/-/typography-0.16.21.tgz#2cd177f20c64d0b762389464688811f980ade682" From d0a381ea907a1dfb2a839f02decaf33065384073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 27 Sep 2023 11:35:05 +0200 Subject: [PATCH 119/149] Update .gitignore Co-authored-by: Michal Piechowiak --- packages/gatsby-source-contentful/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/gatsby-source-contentful/.gitignore b/packages/gatsby-source-contentful/.gitignore index 63b7d144560b3..e69787c28dfd7 100644 --- a/packages/gatsby-source-contentful/.gitignore +++ b/packages/gatsby-source-contentful/.gitignore @@ -30,4 +30,6 @@ decls dist *.js !gatsby-node.js +!.babelrc.js +!jest.config.js !index.js From ad31c926e8451d48b91f703f7e67e2218156011c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 27 Sep 2023 11:28:54 +0200 Subject: [PATCH 120/149] test: fix codemods test by adding new test name to expect --- .../gatsby-codemods/src/bin/__tests__/gatsby-codemods-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-codemods/src/bin/__tests__/gatsby-codemods-test.js b/packages/gatsby-codemods/src/bin/__tests__/gatsby-codemods-test.js index f65ad483dd485..6cf8c28ee3980 100644 --- a/packages/gatsby-codemods/src/bin/__tests__/gatsby-codemods-test.js +++ b/packages/gatsby-codemods/src/bin/__tests__/gatsby-codemods-test.js @@ -66,7 +66,7 @@ describe("transform", () => { run() expect(console.log).toBeCalledWith( - `You have passed in invalid codemod name: does-not-exist. Please pass in one of the following: gatsby-plugin-image, global-graphql-calls, import-link, navigate-calls, rename-bound-action-creators, sort-and-aggr-graphql.` + `You have passed in invalid codemod name: does-not-exist. Please pass in one of the following: gatsby-source-contentful, gatsby-plugin-image, global-graphql-calls, import-link, navigate-calls, rename-bound-action-creators, sort-and-aggr-graphql.` ) }) }) From 8cfe2539c0e1148ad9fac4cec2a1ac09b00105da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 27 Sep 2023 13:26:36 +0200 Subject: [PATCH 121/149] build: add missing lodash to gatsby-codemods for ctf codemod --- packages/gatsby-codemods/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gatsby-codemods/package.json b/packages/gatsby-codemods/package.json index 9e6d2ada80979..e99d62061ea00 100644 --- a/packages/gatsby-codemods/package.json +++ b/packages/gatsby-codemods/package.json @@ -32,6 +32,7 @@ "execa": "^5.1.1", "graphql": "^16.6.0", "jscodeshift": "0.13.1", + "lodash": "^4.17.21", "recast": "0.20.5" }, "devDependencies": { From c0a0ba5f6c4edf4271979f8cfb3cc24bb2b1bc81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 13 Oct 2023 12:07:23 +0200 Subject: [PATCH 122/149] fix: custom content type prefix option now actually affects the generated content type names and not only the schema --- .../src/__tests__/gatsby-node.js | 20 +++++++++++++++++-- .../gatsby-source-contentful/src/normalize.ts | 3 ++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 8f56532b1726d..512fa9807ba0f 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -674,13 +674,29 @@ describe(`gatsby-node`, () => { expect(schema.buildObjectType).not.toHaveBeenCalledWith( expect.objectContaining({ - name: `ContentfulPerson`, + name: `ContentfulContentTypePerson`, }) ) expect(schema.buildObjectType).not.toHaveBeenCalledWith( expect.objectContaining({ - name: `ContentfulBlogPost`, + name: `ContentfulContentTypeBlogPost`, + }) + ) + + expect(actions.createNode).not.toHaveBeenCalledWith( + expect.objectContaining({ + internal: expect.objectContaining({ + type: `ContentfulContentTypeBlogPost`, + }), + }) + ) + + expect(actions.createNode).not.toHaveBeenCalledWith( + expect.objectContaining({ + internal: expect.objectContaining({ + type: `ContentfulContentTypePerson`, + }), }) ) }) diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index 00de62f18fc4f..606effdcfd055 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -554,6 +554,7 @@ export const createNodesForContentType = ({ const markdownFields: MarkdownFieldDefinition = new Map( pluginConfig.get(`markdownFields`) ) + const contentTypePrefix: string = pluginConfig.get(`contentTypePrefix`) // Establish identifier for content type // Use `name` if specified, otherwise, use internal id (usually a natural-language constant, @@ -784,7 +785,7 @@ export const createNodesForContentType = ({ parent: contentTypeItemId, children: [], internal: { - type: makeTypeName(contentTypeItemId), + type: makeTypeName(contentTypeItemId, contentTypePrefix), // The content of an entry is guaranteed to be updated if and only if the .sys.updatedAt field changed contentDigest: entryItem.sys.updatedAt, }, From 27cb57cab6614222970e3738052986ccc0e3133c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 13 Oct 2023 15:35:02 +0200 Subject: [PATCH 123/149] test(e2e): add tests for custom fields and custom resolvers --- .../integration/delivery/custom-fields.js | 19 +++++++++ e2e-tests/contentful/gatsby-node.js | 39 +++++++++++++++++++ .../contentful/src/pages/custom-fields.js | 35 +++++++++++++++++ e2e-tests/contentful/src/pages/index.js | 3 ++ 4 files changed, 96 insertions(+) create mode 100644 e2e-tests/contentful/cypress/integration/delivery/custom-fields.js create mode 100644 e2e-tests/contentful/gatsby-node.js create mode 100644 e2e-tests/contentful/src/pages/custom-fields.js diff --git a/e2e-tests/contentful/cypress/integration/delivery/custom-fields.js b/e2e-tests/contentful/cypress/integration/delivery/custom-fields.js new file mode 100644 index 0000000000000..337d5964eb097 --- /dev/null +++ b/e2e-tests/contentful/cypress/integration/delivery/custom-fields.js @@ -0,0 +1,19 @@ +describe(`custom-fields`, () => { + beforeEach(() => { + cy.visit("/custom-fields").waitForRouteChange() + }) + + it(`custom-fields: custom field`, () => { + cy.get(`[data-cy-id="field"] [data-cy-value]`).should( + `have.text`, + `customFieldValue` + ) + }) + + it(`custom-fields: custom resolver`, () => { + cy.get(`[data-cy-id="resolver"] [data-cy-value]`).should( + `have.text`, + `customResolverResult` + ) + }) +}) diff --git a/e2e-tests/contentful/gatsby-node.js b/e2e-tests/contentful/gatsby-node.js new file mode 100644 index 0000000000000..4a90b408c7c57 --- /dev/null +++ b/e2e-tests/contentful/gatsby-node.js @@ -0,0 +1,39 @@ +exports.onCreateNode = ({ node, actions }) => { + const { createNodeField } = actions + + if (node.internal.type === "ContentfulContentTypeText") { + createNodeField({ + node, + name: "customField", + value: "customFieldValue", + }) + } +} + +exports.createSchemaCustomization = ({ actions, schema }) => { + const { createTypes } = actions + + const typeDefs = ` + type ContentfulContentTypeTextFields { + customField: String! + } + type ContentfulContentTypeText { + fields: ContentfulContentTypeTextFields! + } + ` + + createTypes(typeDefs) +} + +exports.createResolvers = ({ createResolvers }) => { + createResolvers({ + ContentfulContentTypeText: { + customResolver: { + type: 'String!', + resolve(source, args, context, info) { + return "customResolverResult" + }, + }, + }, + }) +} \ No newline at end of file diff --git a/e2e-tests/contentful/src/pages/custom-fields.js b/e2e-tests/contentful/src/pages/custom-fields.js new file mode 100644 index 0000000000000..7d665ec629973 --- /dev/null +++ b/e2e-tests/contentful/src/pages/custom-fields.js @@ -0,0 +1,35 @@ +import { graphql } from "gatsby" +import * as React from "react" + +import Layout from "../components/layout" + +const CustomFieldsPage = ({ data }) => { + const { + contentfulContentTypeText + } = data + return ( + +

    Custom Field:

    +
    +

    {contentfulContentTypeText.fields.customField}

    +
    +

    Custom Resolver:

    +
    +

    {contentfulContentTypeText.customResolver}

    +
    +
    + ) +} + +export default CustomFieldsPage + +export const pageQuery = graphql` + query TextQuery { + contentfulContentTypeText { + fields { + customField + } + customResolver + } + } +` diff --git a/e2e-tests/contentful/src/pages/index.js b/e2e-tests/contentful/src/pages/index.js index f216240c58633..867dccd3922b0 100644 --- a/e2e-tests/contentful/src/pages/index.js +++ b/e2e-tests/contentful/src/pages/index.js @@ -59,6 +59,9 @@ const IndexPage = () => (
  • SSR
  • +
  • + Custom Fields & Resolver +
  • ) From 8d58c397b317b725c0e9e8a99908aa348f4c48ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 22 Nov 2023 17:23:30 +0100 Subject: [PATCH 124/149] fix: no more skip fields that are hidden from editing --- .../gatsby-source-contentful/src/create-schema-customization.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index e0f9602136fd9..35da58ebf4322 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -706,7 +706,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] try { const fields = {} contentTypeItem.fields.forEach(field => { - if (field.disabled || field.omitted) { + if (field.omitted) { return } if (restrictedNodeFields.includes(field.id)) { From 9e61200a48e84c8334151a6dfa62d77d430cd9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frivalszky-Mayer=20P=C3=A9ter?= Date: Wed, 6 Dec 2023 10:35:12 +0100 Subject: [PATCH 125/149] fix(contentful): rich text linked asset filter (#38716) --- .../src/create-schema-customization.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index e0f9602136fd9..0ace98a95372d 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -579,11 +579,13 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] const res = await context.nodeModel.findAll({ query: { - sys: { - id: { - in: links, + filter: { + sys: { + id: { + in: links, + }, + spaceId: { eq: node.sys.spaceId }, }, - spaceId: { eq: node.sys.spaceId }, }, }, type: `Contentful${entityType}`, From c4903b990c84348b9b903aee143f6321955aa301 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 6 Dec 2023 11:50:21 +0100 Subject: [PATCH 126/149] fix(gatsby-source-contentful): don't apply parent node links to child nodes --- packages/gatsby-source-contentful/src/source-nodes.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index 70580964c6eb0..6d807fcb874a0 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -519,13 +519,13 @@ export const sourceNodes: GatsbyNode["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] } } From 9fa54baf24401c0c494baf9fa911d8ba56eb3982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 6 Dec 2023 13:54:49 +0100 Subject: [PATCH 127/149] fix: set children on entries for markdown fields so Gatsby can automatically clean them on node deletion --- .../src/__tests__/gatsby-node.js | 22 +++++++++---------- .../gatsby-source-contentful/src/normalize.ts | 3 +++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 52cc1be666961..5cc93e9bf0acd 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -1469,10 +1469,10 @@ describe(`gatsby-node`, () => { await simulateGatsbyBuild() blogPostNodes = getNodes().filter( - node => node.internal.type === `ContentfulBlogPost` + node => node.internal.type === `ContentfulContentTypeBlogPost` ) blogCategoryNodes = getNodes().filter( - node => node.internal.type === `ContentfulBlogCategory` + node => node.internal.type === `ContentfulContentTypeBlogCategory` ) blogCategoryChildNodes = blogCategoryNodes.flatMap(node => node.children.map(childId => getNode(childId)) @@ -1486,16 +1486,16 @@ describe(`gatsby-node`, () => { 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() + expect(blogCategoryChildNodes[0][`raw`]).toEqual(`cms`) + expect(blogCategoryChildNodes[0][`raw___NODE`]).toBeUndefined() await simulateGatsbyBuild() blogPostNodes = getNodes().filter( - node => node.internal.type === `ContentfulBlogPost` + node => node.internal.type === `ContentfulContentTypeBlogPost` ) blogCategoryNodes = getNodes().filter( - node => node.internal.type === `ContentfulBlogCategory` + node => node.internal.type === `ContentfulContentTypeBlogCategory` ) blogCategoryChildNodes = blogCategoryNodes.flatMap(node => node.children.map(childId => getNode(childId)) @@ -1505,13 +1505,13 @@ describe(`gatsby-node`, () => { 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].linkedFrom.ContentfulContentTypeBlogPost + ).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() + expect(blogCategoryChildNodes[0][`raw`]).toEqual(`cms`) + expect(blogCategoryChildNodes[0][`raw___NODE`]).toBeUndefined() }) }) diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index 606effdcfd055..cd396f415f034 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -821,6 +821,7 @@ export const createNodesForContentType = ({ // Replace text fields with text nodes so we can process their markdown // into HTML. + const children: Array = [] Object.keys(entryItemFields).forEach(entryItemFieldKey => { const field = fieldMap.get(entryItemFieldKey) if (field?.type === `Text`) { @@ -849,6 +850,7 @@ export const createNodesForContentType = ({ ) childrenNodes.push(textNode) + children.push(textNodeId) } entryItemFields[entryItemFieldKey] = textNodeId @@ -859,6 +861,7 @@ export const createNodesForContentType = ({ entryNode = { ...entryItemFields, ...entryNode, + children, } return entryNode } From 4975e7e47117c550101541c57c7a0ee18f6af5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 6 Dec 2023 13:55:53 +0100 Subject: [PATCH 128/149] build: ensure e2e test points on correct version (bumped for X.99.0 cus of version overlap with current branch and this rewrite) --- examples/using-contentful/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/using-contentful/package.json b/examples/using-contentful/package.json index 1dff4a8fba838..e1fbe69e5f867 100644 --- a/examples/using-contentful/package.json +++ b/examples/using-contentful/package.json @@ -10,7 +10,7 @@ "gatsby-plugin-image": "^3.13.0-next.0", "gatsby-plugin-sharp": "^5.13.0-next.0", "gatsby-plugin-typography": "^5.13.0-next.0", - "gatsby-source-contentful": "^8.13.0-next.1", + "gatsby-source-contentful": "^8.99.0-next.0", "gatsby-transformer-remark": "^6.13.0-next.0", "prop-types": "^15.7.2", "react": "^18.2.0", From 075284a9a418dda6a273922e6f36054eb78c0872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 6 Dec 2023 14:01:52 +0100 Subject: [PATCH 129/149] build: remove gatsby-plugin-sharp and sharp from peer dependenceis as they are now dev dependencies already --- packages/gatsby-source-contentful/package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/gatsby-source-contentful/package.json b/packages/gatsby-source-contentful/package.json index e1a332441f218..508a74ff63496 100644 --- a/packages/gatsby-source-contentful/package.json +++ b/packages/gatsby-source-contentful/package.json @@ -48,9 +48,7 @@ "license": "MIT", "peerDependencies": { "gatsby": "^5.0.0-next", - "gatsby-plugin-image": "^3.0.0-next", - "gatsby-plugin-sharp": "^5.0.0-next", - "sharp": "^0.32.6" + "gatsby-plugin-image": "^3.0.0-next" }, "repository": { "type": "git", From 7cae5fc69623efba670898f6866ebb39711de36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 14 Dec 2023 15:19:11 +0100 Subject: [PATCH 130/149] docs: revamp README.md and add MIGRATION.md --- .../gatsby-source-contentful/MIGRATION.md | 391 ++++++ packages/gatsby-source-contentful/README.md | 1089 ++++++++++------- 2 files changed, 1052 insertions(+), 428 deletions(-) create mode 100644 packages/gatsby-source-contentful/MIGRATION.md diff --git a/packages/gatsby-source-contentful/MIGRATION.md b/packages/gatsby-source-contentful/MIGRATION.md new file mode 100644 index 0000000000000..88738934eaff9 --- /dev/null +++ b/packages/gatsby-source-contentful/MIGRATION.md @@ -0,0 +1,391 @@ +# Migration Guide for `gatsby-source-contentful` v9 + +The v9 release of `gatsby-source-contentful` brings significant improvements, focusing on stability and enhancing the developer experience. + +
    +Table of contents + +- [Migration Guide for `gatsby-source-contentful` v9](#migration-guide-for-gatsby-source-contentful-v9) + - [Core Changes, Updates and new Features](#core-changes-updates-and-new-features) + - [1. Introduction](#1-introduction) + - [2. Automated Migration with Codemods](#2-automated-migration-with-codemods) + - [3. Manual Changes and Additional Updates](#3-manual-changes-and-additional-updates) + - [Breaking Changes](#breaking-changes) + - [1. Remove Your Workarounds](#1-remove-your-workarounds) + - [2. New content type naming pattern](#2-new-content-type-naming-pattern) + - [3. Metadata / Data from Contentful's `sys` field](#3-metadata--data-from-contentfuls-sys-field) + - [Sorting by `sys`](#sorting-by-sys) + - [Filtering by `sys`](#filtering-by-sys) + - [4. Fields](#4-fields) + - [Text fields](#text-fields) + - [JSON fields](#json-fields) + - [Rich Text field](#rich-text-field) + - [Schema Comparison](#schema-comparison) + - [Query Updates](#query-updates) + - [Rendering changes for Rich Text](#rendering-changes-for-rich-text) + - [5. Assets](#5-assets) + - [Old GraphlQL schema for assets](#old-graphlql-schema-for-assets) + - [New GraphlQL schema for assets](#new-graphlql-schema-for-assets) + - [Conclusion and Support](#conclusion-and-support) + +
    + +## Core Changes, Updates and new Features + +- **Dynamic Schema Generation**: Schema types are now dynamically generated based on the Contentful content model, eliminating site breakages due to empty content fields. +- **Rich Text and JSON Field Enhancements**: Improved handling of Rich Text and JSON fields for more accurate processing, querying, and rendering. +- **Schema and Performance Optimizations**: An optimized, leaner schema reduces node count and improves build times, especially for larger projects. +- **Contentful GraphQL API Alignment**: Enhanced alignment with Contentful's GraphQL API enables more intuitive and consistent querying. +- **Removed Content Type Name Restrictions**: New naming patterns now allow all content type names, including previously restricted names like `entity` and `reference`. +- **Updated Field Name Restrictions**: Fields can now be named `contentful_id`, with restrictions now applied to names like `sys`, `contentfulMetadata`, and `linkedFrom`. +- **Refined Backlinks**: Backlinks/references are now located in the `linkedFrom` field, aligning with Contentful's GraphQL API structure. +- **Expanded Configuration Options**: Additional [configuration options](#advanced-configuration) provide greater control and customization for your specific project needs. + +## 1. Introduction + +Version 9 of the `gatsby-source-contentful` plugin marks a significant evolution, introducing changes mainly in the structure of GraphQL queries. + +This guide helps you to navigate through these updates, ensuring a straightforward migration to the latest version. We'll cover both automated and manual steps to adapt your project seamlessly to v9's advancements. + +## 2. Automated Migration with Codemods + +Before you start manual updates, take advantage of our codemods that automate most of the transition process. You can use one of the following options to apply the codemods to your project: + +**Option A:** (Direct Execution) + +```bash +npx gatsby-codemods@ctf-next gatsby-source-contentful gatsby-*.js src +``` + +**Option B:** (Install, Execute, Uninstall) + +```bash +# Install codemods +npm install -D jscodeshift gatsby-codemods@ctf-next + +# Execute codemods +npx jscodeshift -t ./node_modules/gatsby-codemods/transforms/gatsby-source-contentful.js gatsby-*.js src/**/*.js + +# Uninstall codemods +npm remove jscodeshift gatsby-codemods +``` + +**For TypeScript projects:** Include `.ts` and `.tsx` files in the transformation: + +```bash +npx ... gatsby-*.js gatsby-*.ts src/**/*.js src/**/*.ts src/**/*.tsx +``` + +**Handling Large Codebases:** If your project is particularly large, you may need to increase the maximum memory allocation for the process: + +```bash +NODE_OPTIONS=--max_old_space_size=10240 npx ... +``` + +## 3. Manual Changes and Additional Updates + +After applying the codemods, review your project for any additional changes that need to be made manually. The following sections detail specific areas that require attention. + +## Breaking Changes + +With v9, the schema generated by `gatsby-source-contentful` is now closely aligned with Contentful's GraphQL API. This significant alignment means several changes in how you structure your GraphQL queries: + +### 1. Remove Your Workarounds + +If you previously implemented workarounds, such as freezing your schema with `gatsby-plugin-schema-snapshot` or using `createSchemaCustomization` to address issues in your Contentful GraphQL schema, you can safely remove these. + +The enhancements in v9 have been designed to eliminate the need for such workarounds, offering a more reliable schema generation process that mirrors the structure and functionality of Contentful's native GraphQL API. + +### 2. New content type naming pattern + +The old naming pattern for generated node types based on your Contentful content model was pretty simple. This gave us shorter queries, but came with restrictions for content type names. Content type names like `entity`, `reference`, `tag`, `asset` did cause problems or simply did not work. + +1. Generated GraphQL node types are now prefixed with `ContentfulContentType` instead of `Contentful` +2. Hardcoded types and interfaces stay short. For example: `ContentfulEntry`, `ContentfulAsset`, `ContentfulLocation` or + `ContentfulRichText` + +This is close to the [behaviour of the Contentful GraphQL API](https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/types): + +> If the generated name starts with a number or collides with a reserved type name, it gets prefixed with 'ContentType' + +Instead of doing this on a collision, we always prefix for consistency. + +```diff +export const pageQuery = graphql` + query { +- allContentfulProduct { ++ allContentfulContentTypeProduct { + ... + } + } +` +``` + +### 3. Metadata / Data from Contentful's `sys` field + +The `sys` field now reflects the structure of the sys field in the Contentful [GraphQL API](https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/sys-field) + +| Old Path | New Path | Comment | +| --------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| node_locale | sys.locale | this does not exists in Contentful's sys but we need it (for now) [as Contentful GraphQL handles locales different](https://www.contentful.com/developers/docs/references/graphql/#/reference/locale-handling) | +| contentful_id | sys.id | +| spaceId | sys.spaceId | +| createdAt | sys.firstPublishedAt | +| updatedAt | sys.publishedAt | +| revision | sys.publishedVersion | +| | sys.environmentId | This is **new** | +| sys.contentType | sys.contentType | This is now a real reference to the Content Type node. If you used this field, you will probably need to change the`__typename` subfield to `name` | + +#### Sorting by `sys` + +```graphql +allContentfulPage(sort: { fields: contentful_id }) { ... } +``` + +becomes + +```graphql +allContentfulContentTypePage(sort: { fields: sys___id }) { ... } +``` + +#### Filtering by `sys` + +```graphql +contentfulPage( + contentful_id: { + eq: "38akBjGb3T1t4AjB87wQjo" + } +) { ... } +``` + +becomes + +```graphql +contentfulContentTypePage( + sys: { + id: { + eq: "38akBjGb3T1t4AjB87wQjo" + } + } +) { ... } +``` + +### 4. Fields + +#### Text fields + +- The raw field value is now stored in `FIELD_NAME { raw }` instead of `FIELD_NAME { FIELD_NAME }` +- This helps for consistency on your side, while reducing node type bload in the Gatsby backend + +#### JSON fields + +1. You can no more queries sub-fields, which ensures your queries won't break on changed content. This means you now have to check if the results have a value on your own. + - You can achieve this with a [custom Field Editor](https://www.contentful.com/blog/apps-and-open-source-guide-to-making-contentful-truly-yours/) in Contentful. +2. Spaces within keys of JSON fields are now kept, means your data is accessible in you code the same way it is entered in contentful. + +```jsx +

    Born at: {actor.Born_At}

    +``` + +becomes + +```jsx +

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

    +``` + +#### Rich Text field + +The schema for Rich Text fields in `gatsby-source-contentful` v9 has been updated to align with Contentful's GraphQL API. This change enhances the flexibility and consistency of querying Rich Text content. You will need to adjust your GraphQL queries and rendering code accordingly. + +Key Changes: + +1. **Unified Link Subfield**: You can now query all linked Contentful content types within the `links` subfield of Rich Text, irrespective of whether they are directly linked in the current content or not. +2. **Direct Entry ID Querying**: Instead of navigating through various fields, the entry ID can now be queried directly as a child field of `links`. This simplification makes your queries more concise. + +##### Schema Comparison + +**Old Schema:** + +```graphql +type ContentfulRichTextRichText { + raw: String + references: [ContentfulAssetContentfulContentReferenceContentfulLocationContentfulTextUnion] + @link(by: "id", from: "references___NODE") +} +union ContentfulAssetContentfulContentReferenceContentfulLocationContentfulTextUnion = + ContentfulAsset + | ContentfulContentReference + | ContentfulLocation + | ContentfulText +``` + +**New Schema:** + +```graphql +type ContentfulNodeTypeRichText @dontInfer { + json: JSON + links: ContentfulNodeTypeRichTextLinks +} + +type ContentfulNodeTypeRichTextLinks { + assets: ContentfulNodeTypeRichTextAssets + entries: ContentfulNodeTypeRichTextEntries +} + +type ContentfulNodeTypeRichTextAssets { + block: [ContentfulAsset]! + hyperlink: [ContentfulAsset]! +} + +type ContentfulNodeTypeRichTextEntries { + inline: [ContentfulEntry]! + block: [ContentfulEntry]! + hyperlink: [ContentfulEntry]! +} +``` + +##### Query Updates + +Update your Rich Text queries to reflect the new schema: + +**Old Example Query:** + +```graphql +query pageQuery { + allContentfulRichText { + nodes { + richText { + raw + references { + ... on ContentfulAsset { + url + } + ... on ContentfulText { + id + } + } + } + } + } +} +``` + +**New Example Query:** + +```graphql +query pageQuery { + allContentfulContentTypeRichText { + nodes { + richText { + json + links { + assets { + block { + url + } + } + entries { + block { + ... on ContentfulContentTypeText { + id + } + } + } + } + } + } + } +} +``` + +**Notes**: + +- The `raw` field is now `json`. +- The `references` field is replaced by `links`, providing a more structured and granular approach to handling linked content. + +##### Rendering changes for Rich Text + +Instead of passing your option object into `renderRichText()` you now pass a option factory. This allows you to access the data you queried for all the linked entities (`assetBlockMap`, `entryBlockMap`, `entryInlineMap`). + +**Old rendering logic:** + +```jsx +const options = { + // options for rendering different node types +} + +;
    {renderRichText(richText, options)}
    +``` + +**New rendering logic:** + +```jsx +const makeOptions = ({ assetBlockMap, entryBlockMap, entryInlineMap }) => { + return { + // updated options based on the new schema + } +} + +;
    {renderRichText(richText, makeOptions)}
    +``` + +Find more details abour [rendering Rich Text in our README file section](./README.md#leveraging-contentful-rich-text-with-gatsby). + +### 5. Assets + +Assets got simplified a lot and aligned to the [Contentful GraphQL API](https://www.contentful.com/developers/docs/references/graphql/#/reference/schema-generation/assets). + +#### Old GraphlQL schema for assets + +```graphql +type ContentfulAsset implements ContentfulInternalReference & Node @dontInfer { + file: ContentfulAssetFile + title: String + description: String + sys: ContentfulInternalSys +} + +type ContentfulAssetFile { + url: String + details: ContentfulAssetFileDetails + fileName: String + contentType: String +} + +type ContentfulAssetFileDetails { + size: Int + image: ContentfulAssetFileDetailsImage +} + +type ContentfulAssetFileDetailsImage { + width: Int + height: Int +} +``` + +#### New GraphlQL schema for assets + +```graphql +type ContentfulAsset implements ContentfulInternalReference & Node @dontInfer { + sys: ContentfulInternalSys + title: String + description: String + mimeType: String + fileName: String + url: String + size: Int + width: Int + height: Int +} +``` + +## Conclusion and Support + +We understand that the changes introduced in `gatsby-source-contentful` v9 are significant. These updates were necessary to resolve architectural issues from the early stages of the plugin and to align it more closely with the evolving capabilities of Contentful and Gatsby. + +As we step into this new era, our focus is on ensuring that you experience the most stable, efficient, and future-proof integration when using Contentful with Gatsby. While we've made every effort to simplify the migration process, we also recognize that transitions like these can be challenging. + +If you encounter any difficulties or have questions, we encourage you to reach out for support: + +- For detailed discussions and sharing experiences: [Join our GitHub Discussion](https://github.com/gatsbyjs/gatsby/discussions/38585). +- To report bugs or specific issues: [Submit an Issue on GitHub](https://github.com/gatsbyjs/gatsby/issues). diff --git a/packages/gatsby-source-contentful/README.md b/packages/gatsby-source-contentful/README.md index 24f3759edb622..dddc7f0bc2499 100644 --- a/packages/gatsby-source-contentful/README.md +++ b/packages/gatsby-source-contentful/README.md @@ -1,207 +1,413 @@ -# gatsby-source-contentful +# gatsby-source-contentful v9 + +`gatsby-source-contentful` is a powerful Gatsby plugin that brings [Contentful's rich content management capabilities](https://www.contentful.com/) into the Gatsby ecosystem. It enables developers to seamlessly integrate Contentful's Content Delivery API with their Gatsby sites, allowing for efficient content retrieval and dynamic site generation based on Contentful's structured content.
    Table of contents -- [gatsby-source-contentful](#gatsby-source-contentful) - - [Install](#install) - - [Setup Instructions](#setup-instructions) - - [How to use](#how-to-use) - - [Restrictions and limitations](#restrictions-and-limitations) +- [gatsby-source-contentful v9](#gatsby-source-contentful-v9) + - [Core Features](#core-features) + - [What's New in Version v9](#whats-new-in-version-v9) + - [Restrictions and Limitations](#restrictions-and-limitations) + - [Installation](#installation) + - [Migration](#migration) + - [Configuration Instructions](#configuration-instructions) - [Using Delivery API](#using-delivery-api) - [Using Preview API](#using-preview-api) - - [Offline](#offline) - - [Configuration options](#configuration-options) - - [How to query for nodes](#how-to-query-for-nodes) - - [Query for all nodes](#query-for-all-nodes) - - [Query for a single node](#query-for-a-single-node) - - [A note about LongText fields](#a-note-about-longtext-fields) - - [Duplicated entries](#duplicated-entries) - - [Query for Assets in ContentType nodes](#query-for-assets-in-contenttype-nodes) - - [More on Queries with Contentful and Gatsby](#more-on-queries-with-contentful-and-gatsby) - - [Displaying responsive image with gatsby-plugin-image](#displaying-responsive-image-with-gatsby-plugin-image) - - [Building images on the fly via `useContentfulImage`](#building-images-on-the-fly-via-usecontentfulimage) - - [On-the-fly image options:](#on-the-fly-image-options) - - [Contentful Tags](#contentful-tags) - - [List available tags](#list-available-tags) - - [Filter content by tags](#filter-content-by-tags) - - [Contentful Rich Text](#contentful-rich-text) - - [Query Rich Text content and references](#query-rich-text-content-and-references) - - [Rendering](#rendering) - - [Embedding an image in a Rich Text field](#embedding-an-image-in-a-rich-text-field) - - [Download assets for static distribution](#download-assets-for-static-distribution) - - [Enable the feature with the `downloadLocal: true` option.](#enable-the-feature-with-the-downloadlocal-true-option) - - [Updating Queries for downloadLocal](#updating-queries-for-downloadlocal) - - [Sourcing From Multiple Contentful Spaces](#sourcing-from-multiple-contentful-spaces) + - [Get Started Guide](#get-started-guide) + - [Step 0: Our Contentful Data Model](#step-0-our-contentful-data-model) + - [Step 1: Creating a Gatsby Page with Contentful Data](#step-1-creating-a-gatsby-page-with-contentful-data) + - [Step 2: Dynamic Page Creation with `gatsby-node.js`](#step-2-dynamic-page-creation-with-gatsby-nodejs) + - [Step 3: Using Markdown to Render the Content](#step-3-using-markdown-to-render-the-content) + - [Further Tutorials and Documentation](#further-tutorials-and-documentation) + - [Advanced configuration](#advanced-configuration) + - [Offline Mode](#offline-mode) + - [Querying Contentful Data in Gatsby](#querying-contentful-data-in-gatsby) + - [Overview of Querying Nodes](#overview-of-querying-nodes) + - [Querying All Nodes](#querying-all-nodes) + - [Querying Single Nodes](#querying-single-nodes) + - [Handling Long Text Fields](#handling-long-text-fields) + - [Addressing Duplicated Entries Caused by Internationalization](#addressing-duplicated-entries-caused-by-internationalization) + - [Querying Assets and Tags within ContentType Nodes](#querying-assets-and-tags-within-contenttype-nodes) + - [Advanced Queries with Contentful and Gatsby](#advanced-queries-with-contentful-and-gatsby) + - [Working with Images and Contentful](#working-with-images-and-contentful) + - [Displaying Responsive Images with `gatsby-plugin-image`](#displaying-responsive-images-with-gatsby-plugin-image) + - [Building Images on the Fly with `useContentfulImage`](#building-images-on-the-fly-with-usecontentfulimage) + - [Leveraging Contentful Rich Text with Gatsby](#leveraging-contentful-rich-text-with-gatsby) + - [Querying Rich Text Content](#querying-rich-text-content) + - [Basic Rich Text Rendering](#basic-rich-text-rendering) + - [Embedding Images in Rich Text with Gatsby Plugin Image](#embedding-images-in-rich-text-with-gatsby-plugin-image) + - [Embedding Entries in Rich Text](#embedding-entries-in-rich-text) + - [Further Contentful Rich Text resources](#further-contentful-rich-text-resources) + - [Downloading Assets for Static Distribution](#downloading-assets-for-static-distribution) + - [Benefits of `downloadLocal`](#benefits-of-downloadlocal) + - [Trade-offs](#trade-offs) + - [Enabling `downloadLocal`](#enabling-downloadlocal) + - [Updating GraphQL Queries](#updating-graphql-queries) + - [Troubleshooting](#troubleshooting) + - [Multi-Space Sourcing: Example for Sourcing from Multiple Contentful Spaces](#multi-space-sourcing-example-for-sourcing-from-multiple-contentful-spaces) + - [Current Limitations](#current-limitations)
    -## Install +## Core Features -```shell -npm install gatsby-source-contentful gatsby-plugin-image -``` +- **Comprehensive Content Integration**: Easily connect your Contentful space with Gatsby, ensuring all content types, references, and custom fields are handled effectively. +- **Advanced Contentful Features Support**: Harness the full power of Contentful's offerings, including the Image API for creating responsive images and the comprehensive Rich Text feature for versatile content representation. +- **Efficient Content Synchronization**: Utilizes Contentful's Sync API for incremental updates, significantly speeding up build times. +- **Aligned Data Structure**: Data in Gatsby closely mirrors the structure of Contentful's GraphQL API, with minimal discrepancies, for a consistent development experience. +- **Preview API Support**: Leverage Contentful's Preview API for content previews before publishing, with some limitations due to incremental sync constraints. Refer to [Restrictions & Limitations](#restrictions-and-limitations) for more details. -## Setup Instructions +### What's New in Version v9 -To get setup quickly with a new site and have Netlify do the heavy lifting, [deploy a new Gatsby Contentful site with just a few clicks on netlify.com](https://app.netlify.com/start/deploy?repository=https://github.com/contentful/starter-gatsby-blog). +The v9 release of `gatsby-source-contentful` brings significant improvements, focusing on stability and enhancing the developer experience. -## How to use +- **Dynamic Schema Generation**: Schema types are now dynamically generated based on the Contentful content model, eliminating site breakages due to empty content fields. +- **Rich Text and JSON Field Enhancements**: Improved handling of Rich Text and JSON fields for more accurate processing, querying, and rendering. +- **Schema and Performance Optimizations**: An optimized, leaner schema reduces node count and improves build times, especially for larger projects. +- **Contentful GraphQL API Alignment**: Enhanced alignment with Contentful's GraphQL API enables more intuitive and consistent querying. +- **Removed Content Type Name Restrictions**: New naming patterns now allow all content type names, including previously restricted names like `entity` and `reference`. +- **Updated Field Name Restrictions**: Fields can now be named `contentful_id`, with restrictions now applied to names like `sys`, `contentfulMetadata`, and `linkedFrom`. +- **Refined Backlinks**: Backlinks/references are now located in the `linkedFrom` field, aligning with Contentful's GraphQL API structure. +- **Expanded Configuration Options**: Additional [configuration options](#advanced-configuration) provide greater control and customization for your specific project needs. -First, you need a way to pass environment variables to the build process, so secrets and other secured data aren't committed to source control. We recommend using [`dotenv`][dotenv] which will then expose environment variables. [Read more about `dotenv` and using environment variables here][envvars]. Then we can _use_ these environment variables and configure our plugin. +For a detailed migration guide and to leverage these improvements, refer to the [Migration Guide](./MIGRATION.md) section. -## Restrictions and limitations +## Restrictions and Limitations -This plugin has several limitations, please be aware of these: +Please note the following limitations when using `gatsby-source-contentful`: -1. At the moment, fields that do not have at least one populated instance will not be created in the GraphQL schema. This can break your site when field values get removed. You may workaround with an extra content entry with all fields filled out. +1. **Environment Access**: Your access token must have permissions for both your desired environment and the `master` environment. +2. **Preview API Usage**: While using Contentful's Preview API, content may become out-of-sync over time as incremental syncing is not officially supported. Regular cache clearing is recommended. +3. **Restricted Content Type Names**: Content type names such as `entity` and `reference` are not allowed. +4. **Field Name Prefixes**: Certain field names are restricted and will be automatically prefixed for consistency, including `id`, `children`, `parent`, `fields`, `internal`, `sys`, `contentfulMetadata`, and `linkedFrom`. -2. When using reference fields, be aware that this source plugin will automatically create the reverse reference. You do not need to create references on both content types. +Your revisions to the installation section are clear and informative, effectively guiding users through the initial setup process. The emphasis on `gatsby-plugin-image` for leveraging Gatsby and Contentful's image capabilities is a valuable recommendation. Here's a slightly refined version for clarity and flow: -3. When working with environments, your access token has to have access to your desired environment and the `master` environment. +## Installation + +To install the plugin, run the following command in your Gatsby project: + +```shell +npm install gatsby-source-contentful gatsby-plugin-image +``` -4. Using the preview functionality might result in broken content over time, as syncing data on preview is not officially supported by Contentful. Make sure to regularly clean your cache when using Contentful's preview API. +While `gatsby-plugin-image` is optional, it is highly recommended to fully utilize the benefits of [Gatsby's Image Plugin](https://www.gatsbyjs.com/plugins/gatsby-plugin-image/) and [Contentful's Images API](https://www.contentful.com/developers/docs/references/images-api/), enhancing your site's image handling and performance. -5. The following content type names are not allowed: `entity`, `reference` +## Migration -6. The following field names are restricted and will be prefixed: `children`, `contentful_id`, `fields`, `id`, `internal`, `parent`, +Please see our [Migration Guide](./MIGRATION.md) -7. The Plugin has a dependency on `gatsby-plugin-image` which itself has dependencies. Check [Displaying responsive image with gatsby-plugin-image](#displaying-responsive-image-with-gatsby-plugin-image) to determine which additional plugins you'll need to install. +## Configuration Instructions ### Using Delivery API +To use Contentful's Delivery API, which retrieves published content, follow these steps: + +1. **Set Environment Variables**: Create a file named `.env.development` in your project's root with the following variables: + +```sh +# .env.development +CONTENTFUL_SPACE_ID=your_space_id +CONTENTFUL_ACCESS_TOKEN=your_delivery_api_access_token +CONTENTFUL_ENVIRONMENT=master # or your custom environment +``` + +Replace `your_space_id` and `your_delivery_api_access_token` with your actual Contentful Space ID and Delivery API access token. To create access tokens, open the Contentful [UI](https://app.contentful.com/), click `Settings` in the top right corner, and select `API keys`. 2. **Production Environment Variables**: Duplicate the `.env.development` file and rename it to `.env.production`. This ensures your Gatsby site connects to Contentful's Delivery API in both development and production builds. + +3. **Plugin Configuration**: In your `gatsby-config.js`, add the `gatsby-source-contentful` plugin with the necessary options: + ```javascript -// In your gatsby-config.js +// gatsby-config.js +require("dotenv").config({ + path: `.env.${process.env.NODE_ENV}`, +}) + module.exports = { plugins: [ { resolve: `gatsby-source-contentful`, options: { - spaceId: `your_space_id`, - // Learn about environment variables: https://gatsby.dev/env-vars + spaceId: process.env.CONTENTFUL_SPACE_ID, accessToken: process.env.CONTENTFUL_ACCESS_TOKEN, + environment: process.env.CONTENTFUL_ENVIRONMENT, }, }, `gatsby-plugin-image`, + // ... other plugins ... ], } ``` ### Using Preview API +To configure the plugin for Contentful's Preview API, which allows you to see unpublished content. This will configure the plugin for Contentful's Preview API for development mode, while maintaining the Contentful Content API for production builds. + +1. **Update Environment Variables**: In your `.env.development` file, update `CONTENTFUL_ACCESS_TOKEN` to use an access token for the Contentful Preview API. + +2. **Adjust Plugin Configuration**: Modify your `gatsby-config.js` to conditionally set the host based on the environment: + ```javascript -// In your gatsby-config.js +// gatsby-config.js module.exports = { plugins: [ { resolve: `gatsby-source-contentful`, options: { - spaceId: `your_space_id`, - // Learn about environment variables: https://gatsby.dev/env-vars - accessToken: process.env.CONTENTFUL_ACCESS_TOKEN, - host: `preview.contentful.com`, + // ... other plugin options ... + host: + process.env.NODE_ENV === `production` + ? `cdn.contentful.com` + : `preview.contentful.com`, }, }, - `gatsby-plugin-image`, + // ... other plugins ... ], } ``` -### Offline - -If you don't have internet connection you can add `export GATSBY_CONTENTFUL_OFFLINE=true` to tell the plugin to fallback to the cached data, if there is any. - -### Configuration options - -**`spaceId`** [string][required] - -Contentful space ID - -**`accessToken`** [string][required] - -Contentful delivery API key, when using the Preview API use your Preview API key - -**`host`** [string][optional] [default: `'cdn.contentful.com'`] - -The base host for all the API requests, by default it's `'cdn.contentful.com'`, if you want to use the Preview API set it to `'preview.contentful.com'`. You can use your own host for debugging/testing purposes as long as you respect the same Contentful JSON structure. - -**`environment`** [string][optional] [default: 'master'] - -The environment to pull the content from, for more info on environments check out this [Guide](https://www.contentful.com/developers/docs/concepts/multiple-environments/). - -**`downloadLocal`** [boolean][optional] [default: `false`] - -Downloads and caches `ContentfulAsset`'s to the local filesystem. Allows you to query a `ContentfulAsset`'s `localFile` field, which is not linked to Contentful's CDN. See [Download assets for static distribution](#download-assets-for-static-distribution) for more information on when and how to use this feature. - -**`localeFilter`** [function][optional] [default: `() => true`] - -Possibility to limit how many locales/nodes are created in GraphQL. This can limit the memory usage by reducing the amount of nodes created. Useful if you have a large space in Contentful and only want to get the data from one selected locale. - -For example, to filter locales on only germany `localeFilter: locale => locale.code === 'de-DE'` - -List of locales and their codes can be found in Contentful app -> Settings -> Locales - -**`forceFullSync`** [boolean][optional] [default: `false`] - -Prevents the use of sync tokens when accessing the Contentful API. - -**`proxy`** [object][optional] [default: `undefined`] - -Axios proxy configuration. See the [axios request config documentation](https://github.com/mzabriskie/axios#request-config) for further information about the supported values. - -**`useNameForId`** [boolean][optional] [default: `true`] - -Use the content's `name` when generating the GraphQL schema e.g. a content type called `[Component] Navigation bar` will be named `contentfulComponentNavigationBar`. - -When set to `false`, the content's internal ID will be used instead e.g. a content type with the ID `navigationBar` will be called `contentfulNavigationBar`. - -Using the ID is a much more stable property to work with as it will change less often. However, in some scenarios, content types' IDs will be auto-generated (e.g. when creating a new content type without specifying an ID) which means the name in the GraphQL schema will be something like `contentfulC6XwpTaSiiI2Ak2Ww0oi6qa`. This won't change and will still function perfectly as a valid field name but it is obviously pretty ugly to work with. - -If you are confident your content types will have natural-language IDs (e.g. `blogPost`), then you should set this option to `false`. If you are unable to ensure this, then you should leave this option set to `true` (the default). - -**`pageLimit`** [number][optional] [default: `1000`] - -Number of entries to retrieve from Contentful at a time. Due to some technical limitations, the response payload should not be greater than 7MB when pulling content from Contentful. If you encounter this issue you can set this param to a lower number than 100, e.g `50`. - -**`assetDownloadWorkers`** [number][optional] [default: `50`] - -Number of workers to use when downloading Contentful assets. Due to technical limitations, opening too many concurrent requests can cause stalled downloads. If you encounter this issue you can set this param to a lower number than 50, e.g 25. - -**`contentfulClientConfig`** [object][optional] [default: `{}`] - -Additional config which will get passed to [Contentfuls JS SDK](https://github.com/contentful/contentful.js#configuration). +## Get Started Guide -Use this with caution, you might override values this plugin does set for you to connect to Contentful. +This guide is a straightforward path to see how Gatsby and Contentful can bring your content to life, ideal for those just starting out. + +### Step 0: Our Contentful Data Model + +Before we jump into Gatsby, let's define our Contentful data model. We're working with a Page content type, which includes the following fields: + +- **Title**: The headline of your page. +- **Slug**: A unique URL segment based on the page's title. +- **Content**: The primary content or body of your page. + +### Step 1: Creating a Gatsby Page with Contentful Data + +Begin by fetching data from a single entry of our `Page` content type and displaying it on a Gatsby page. + +1. **Create a Page Component**: In your `src/pages` directory, add a new file, such as `contentful-page.js`. +2. **Load data with GraphQL**: Use Gatsby's page query to retrieve data from Contentful. For a `Page` content type with `title`, `slug`, and `content` fields. +3. **Render data with Gatsby**: The result of the page query is available through the `data` prop. + + Your file should look like this: + + ```jsx + // src/pages/contentful-page.js + import React from "react" + import { graphql } from "gatsby" + + export default function ContentfulPage({ data }) { + return ( +
    +

    {data.contentfulPage.title}

    +

    {data.contentfulPage.content.raw}

    +
    + ) + } + + export const pageQuery = graphql` + query { + contentfulPage(slug: { eq: "your-slug" }) { + title + content { + raw + } + } + } + ` + ``` + + **Important:** Replace `"your-slug"` with the actual slug of the page you want to display. At this stage, the content will be displayed as raw text. + +### Step 2: Dynamic Page Creation with `gatsby-node.js` + +Now, create a subpage for each `Page` content type entry. + +1. **Rename and Move Page Component**: Rename `src/pages/contentful-page.js` to `src/templates/contentful-page-template.js`. This file becomes your template for dynamically created pages. + +2. **Implement Dynamic Page Creation**: In your `gatsby-node.js`, use the `createPages` API to dynamically generate pages for each entry of the `Page` content type from Contentful. + + ```javascript + // gatsby-node.js + const path = require("path") + + exports.createPages = async ({ graphql, actions }) => { + const { createPage } = actions + + // Query data of all Contentful pages + const result = await graphql(` + query { + allContentfulPage { + edges { + node { + slug + } + } + } + } + `) + + // Dynamically create a page for each Contentful entry, passing the slug for URL generation + result.data.allContentfulPage.edges.forEach(({ node }) => { + createPage({ + path: node.slug, + component: path.resolve(`./src/templates/contentful-page-template.js`), + context: { + slug: node.slug, + }, + }) + }) + } + ``` + + This code will create a new page for each `Page` entry in Contentful, using the slug as the page path. + +3. **Update Template with Slug Filter**: In your template file (`src/templates/contentful-page-template.js`), update the GraphQL query to filter by the provided slug. + + ```jsx + // src/templates/contentful-page-template.js + import React from "react" + import { graphql } from "gatsby" + + export default function ContentfulPageTemplate({ data }) { + return ( +
    +

    {data.contentfulPage.title}

    +

    {data.contentfulPage.content.raw}

    +
    + ) + } + + export const pageQuery = graphql` + query contentfulPageQuery($slug: String!) { + contentfulPage(slug: { eq: $slug }) { + title + content { + raw + } + } + } + ` + ``` + + **Hint:** The `$slug` variable is provided via the context in `gatsby-node.js`. + +### Step 3: Using Markdown to Render the Content + +> **Note on Markdown**: Markdown is a lightweight markup language that allows you to write content using an easy-to-read, easy-to-write plain text format, which is then converted into HTML. The `gatsby-transformer-remark` plugin enables this transformation within Gatsby. [Learn more about Markdown](https://www.markdownguide.org/getting-started/). + +To add Markdown rendering to your Contentful content: + +1. **Install `gatsby-transformer-remark`**: Run `npm install gatsby-transformer-remark`. + +2. **Update Gatsby Config**: Add the `gatsby-transformer-remark` plugin to your `gatsby-config.js`. + + ```javascript + // gatsby-config.js + module.exports = { + plugins: [ + // ... other plugins ... + `gatsby-transformer-remark`, + ], + } + ``` + +3. **Adjust the Template for Markdown**: Modify your template (`src/templates/contentful-page-template.js`) to render the markdown content. Update the GraphQL query and rendering logic to handle the transformed markdown. + + ```jsx + // src/templates/contentful-page-template.js + import React from "react" + import { graphql } from "gatsby" + + export default function ContentfulPageTemplate({ data }) { + return ( +
    +

    {data.contentfulPage.title}

    + {/* Here we render the generated HTML */} +
    +
    + ) + } + + export const pageQuery = graphql` + query contentfulPageQuery($slug: String!) { + contentfulPage(slug: { eq: $slug }) { + title + content { + # The childMarkdownRemark is created by gatsby-transformer-remark + childMarkdownRemark { + html + } + } + } + } + ` + ``` + +You now have a foundational grasp of `gatsby-source-contentful` and its potential to power your Gatsby projects with Contentful's dynamic content. + +### Further Tutorials and Documentation + +For more in-depth exploration and advanced concepts, check out these valuable resources: + +- **Contentful Gatsby Starter Guide**: A comprehensive guide to kickstart your Gatsby projects with Contentful. [Explore the guide](https://www.contentful.com/gatsby-starter-guide/). +- **Contentful Blog Example**: An example Gatsby project integrated with Contentful, ideal for blog-like websites. [View on GitHub](https://github.com/contentful/starter-gatsby-blog). +- **Contentful & Gatsby in 5 Minutes**: A quick tutorial for setting up a Gatsby site with Contentful. [Start learning](https://www.contentful.com/help/gatsbyjs-and-contentful-in-five-minutes/). +- **Gatsby's Quick Guide to Contentful**: Gatsby's own guide to integrating Contentful for content management. [Read the guide](https://www.gatsbyjs.com/blog/a-quick-start-guide-to-gatsby-and-contentful/). +- **Video Tutorial by Khaled and Jason**: Though a bit dated, this informative video remains a great resource for understanding Gatsby and Contentful integration. [Watch on YouTube](https://www.youtube.com/watch?v=T9hLWjIN-pY). + +## Advanced configuration + +Here's the revised table for the `gatsby-source-contentful` configuration options, including the suggested updates and corrections: + +| Option | Type | Default Value | Description | +| ------------------------------------- | -------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `spaceId` | string | (required) | Your Contentful space ID. | +| `accessToken` | string | (required) | Access token for the Content Delivery API. Use the Preview API key for the Contentful Preview API. | +| `host` | string | `cdn.contentful.com` | Base host for API requests. Default is for the Delivery API; use `preview.contentful.com` for the Preview API. Custom hosts can be used for debugging/testing. | +| `environment` | string | `master` | The environment in Contentful to pull content from. [Guide](https://www.contentful.com/developers/docs/concepts/multiple-environments/) | +| `downloadLocal` | boolean | `false` | Downloads and caches `ContentfulAsset` to the local filesystem. Use `localFile` to access the local files. See [Download assets for static distribution](#download-assets-for-static-distribution) | +| `useNameForId` | boolean | `true` | Determines whether the content's `name` or internal ID is used for generating GraphQL schema types. Using `name` can make type names more readable but can be unstable if names change. Using the internal ID ensures stability as IDs are less likely to change, but may result in less readable types, especially when auto-generated. | +| `enableMarkdownDetection` (New in v9) | boolean | `true` | Assumes all long text fields in Contentful are markdown fields. Requires `gatsby-transformer-remark`. Can be a performance issue in large projects. Set to `false` and use `markdownFields` to specify markdown fields. | +| `markdownFields` (New in v9) | array | `[]` | Specify which fields contain markdown content. Effective only when `enableMarkdownDetection` is `false`. Format: array of pairs (content type ID and array of field IDs). Example: `[["product", ["description", "summary"]], ["otherContentTypeId", ["someMarkdownFieldId"]]]` | +| `contentTypePrefix` (Renamed in v9) | string | `ContentfulContentType` | Prefix for the generated GraphQL types. Formerly known as `typePrefix`. | +| `localeFilter` | function | `() => true` | Function to filter which locales/nodes are created in GraphQL, reducing memory usage by limiting nodes. | +| `contentTypeFilter` | function | `() => true` | Function to filter which contentType/nodes are created in GraphQL, reducing memory usage by limiting nodes. | +| `pageLimit` | number | `1000` | Number of entries to retrieve from Contentful at a time. Adjust if the payload size exceeds 7MB. | +| `assetDownloadWorkers` | number | `50` | Number of workers to use when downloading Contentful assets. Adjust to prevent stalled downloads due to too many concurrent requests. | +| `proxy` | object | (none) | Axios proxy configuration. See the [axios request config documentation](https://github.com/mzabriskie/axios#request-config) for further information about the supported values. | +| `contentfulClientConfig` | object | `{}` | Additional config passed to Contentful's JS SDK. Use with caution to avoid overriding plugin-set values. | + +### Offline Mode + +For development without internet access, you can enable the Offline Mode of `gatsby-source-contentful`. Simply set the environment variable `GATSBY_CONTENTFUL_OFFLINE`, for example by adding `GATSBY_CONTENTFUL_OFFLINE=true` to your `.env.development`. This mode uses cached data from previous builds. -**`contentTypeFilter`** [function][optional] [default: () => true] +**Note:** Changing `gatsby-config.js` or `package.json` will clear the cache, requiring internet access for the next build. -Possibility to limit how many contentType/nodes are created in GraphQL. This can limit the memory usage by reducing the amount of nodes created. Useful if you have a large space in Contentful and only want to get the data from certain content types. +## Querying Contentful Data in Gatsby -For example, to exclude content types starting with "page" `contentTypeFilter: contentType => !contentType.sys.id.startsWith('page')` +### Overview of Querying Nodes -**`typePrefix`** [string][optional] [default: `Contentful`] +In Gatsby, Contentful provides three primary node types for querying: `Asset`, `ContentType`, and `Tag`. These nodes allow you to access various types of content from your Contentful space: -Prefix for the type names created in GraphQL. This can be used to avoid conflicts with other plugins, or if you want more than one instance of this plugin in your project. For example, if you set this to `Blog`, the type names will be `BlogAsset` and `allBlogAsset`. - -## How to query for nodes - -Two standard node types are available from Contentful: `Asset` and `ContentType`. - -`Asset` nodes will be created in your site's GraphQL schema under `contentfulAsset` and `allContentfulAsset`. - -`ContentType` nodes are a little different - their exact name depends on what you called them in your Contentful data models. The nodes will be created in your site's GraphQL schema under `contentful${entryTypeName}` and `allContentful${entryTypeName}`. - -In all cases querying for nodes like `contentfulX` will return a single node, and nodes like `allContentfulX` will return all nodes of that type. - -### Query for all nodes - -You might query for **all** of a type of node: +- `Asset` nodes are accessible under `contentfulAsset` and `allContentfulAsset`. +- `ContentType` nodes, following the new naming pattern, are available as `contentfulContentType${entryTypeName}` and `allContentfulContentType${entryTypeName}`. +- `Tag` nodes are found under `contentfulTag` and `allContentfulTag`. + +Querying `contentfulX` retrieves a single node, while `allContentfulX` fetches all nodes of that type. + +### Querying All Nodes + +To query all nodes of a specific type: ```graphql { allContentfulAsset { nodes { - contentful_id + sys { + id + } title description } @@ -209,133 +415,91 @@ You might query for **all** of a type of node: } ``` -You might do this in your `gatsby-node.js` using Gatsby's [`createPages`](https://gatsbyjs.com/docs/node-apis/#createPages) Node API. +### Querying Single Nodes -### Query for a single node - -To query for a single `image` asset with the title `'foo'` and a width of 1600px: - -```javascript -export const assetQuery = graphql` - { - contentfulAsset(title: { eq: "foo" }) { - contentful_id - title - description - file { - fileName - url - contentType - details { - size - image { - height - width - } - } - } - } - } -` -``` - -To query for a single `CaseStudy` node with the short text properties `title` and `subtitle`: +For querying a single node: ```graphql - { - contentfulCaseStudy(filter: { title: { eq: 'bar' } }) { - title - subtitle +{ + contentfulAsset(title: { eq: "foo" }) { + sys { + id } + title + description + // ... other fields ... } -``` - -You might query for a **single** node inside a component in your `src/components` folder, using [Gatsby's `StaticQuery` component](https://www.gatsbyjs.com/docs/static-query/). - -#### A note about LongText fields - -On Contentful, a "Long text" field uses Markdown by default. The field is exposed as an object, while the raw Markdown is exposed as a child node. +} -```graphql { - contentfulCaseStudy { - body { - raw - } + contentfulContentTypeCaseStudy(slug: { eq: "example-slug" }) { + title + slug + // ... other fields ... } } ``` -Unless the text is Markdown-free, you cannot use the returned value directly. In order to handle the Markdown content, you must use a transformer plugin such as [`gatsby-transformer-remark`](https://www.gatsbyjs.com/plugins/gatsby-transformer-remark/). The transformer will create a `childMarkdownRemark` on the "Long text" field and expose the generated html as a child node: +### Handling Long Text Fields + +Long text fields often use Markdown. For Markdown processing, use `gatsby-transformer-remark`. See [Step 3 in the Getting Started Guide](#step-3-using-markdown-to-render-the-content). ```graphql { - contentfulCaseStudy { + contentfulContentTypeCaseStudy { body { + raw # Raw Markdown childMarkdownRemark { - html + html # HTML from Markdown } } } } ``` -You can then insert the returned HTML inline in your JSX: - -```jsx -
    -``` - -#### Duplicated entries +### Addressing Duplicated Entries Caused by Internationalization -When Contentful pulls the data, all localizations will be pulled. Therefore, if you have a localization active, it will duplicate the entries. Narrow the search by filtering the query with `node_locale` filter: +Due to Contentful's data retrieval process, each localization creates a new node, potentially leading to duplicates. Include the `node_locale` in queries to avoid this: ```graphql { - allContentfulCaseStudy(filter: { node_locale: { eq: "en-US" } }) { - edges { - node { - id - slug - title - subtitle - body { - body - } - } - } + allContentfulContentTypeCaseStudy( + filter: { node_locale: { eq: "en-US" } } + ) { + # ... query fields ... } } ``` -### Query for Assets in ContentType nodes - -More typically your `Asset` nodes will be mixed inside of your `ContentType` nodes, so you'll query them together. All the same formatting rules for `Asset` and `ContentType` nodes apply. +### Querying Assets and Tags within ContentType Nodes -To get **all** the `CaseStudy` nodes with `ShortText` fields `id`, `slug`, `title`, `subtitle`, `LongText` field `body` and `heroImage` asset field, we use `allContentful${entryTypeName}` to return all instances of that `ContentType`: +Assets and tags are typically queried alongside ContentType nodes: ```graphql { - allContentfulCaseStudy { + allContentfulContentTypeCaseStudy { edges { node { - id + sys { + id + } slug title subtitle body { body } + # Asset heroImage { title description gatsbyImageData(layout: CONSTRAINED) - # Further below in this doc you can learn how to use these response images + } + # Tags + contentfulMetadata { + tags { + name + } } } } @@ -343,161 +507,156 @@ To get **all** the `CaseStudy` nodes with `ShortText` fields `id`, `slug`, `titl } ``` -### More on Queries with Contentful and Gatsby +### Advanced Queries with Contentful and Gatsby -It is strongly recommended that you take a look at how data flows in a real Contentful and Gatsby application to fully understand how the queries, Node.js functions and React components all come together. Check out the example site at -[using-contentful.gatsbyjs.org](https://using-contentful.gatsbyjs.org/). +Explore your GraphQL schema and data with GraphiQL, a browser-based IDE available at http://localhost:8000/\_\_\_graphql during Gatsby development. This tool is essential for experimenting with queries and understanding the Contentful data structure in your project. -## Displaying responsive image with gatsby-plugin-image +## Working with Images and Contentful -To use it: +Contentful and Gatsby together provide a powerful combination for managing and displaying images. Leveraging Contentful's Images API and Gatsby's image handling capabilities, you can create responsive, optimized images for your site. Here's how to get the most out of this integration: -1. Install the required plugins: +Please check out the [Readme](https://www.gatsbyjs.com/plugins/gatsby-plugin-image/) and [Reference Guide](https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-plugin-image/) of `gatsby-plugin-image` for more detailed information about the possibilities of it. -```shell -npm install gatsby-plugin-image gatsby-plugin-sharp -``` +### Displaying Responsive Images with `gatsby-plugin-image` -2. Add the plugins to your `gatsby-config.js`: +1. **Install Required Plugins**: If you haven't already, install `gatsby-plugin-image`: -```javascript -module.exports = { - plugins: [ - `gatsby-plugin-sharp`, - `gatsby-plugin-image`, - // ...etc - ], -} -``` + ```shell + npm install gatsby-plugin-image + ``` -3. You can then query for image data using the new `gatsbyImageData` resolver: +2. **Configure Gatsby**: If you haven't already, add it to your `gatsby-config.js`: -```graphql -{ - allContentfulBlogPost { - nodes { - heroImage { - gatsbyImageData(layout: FULL_WIDTH) + ```javascript + module.exports = { + plugins: [ + `gatsby-plugin-image`, + // ... other plugins ... + ], + } + ``` + +3. **Querying Images**: Use the `gatsbyImageData` resolver in your GraphQL queries to fetch image data on any Contentful Asset you have linked in a Contentful Field: + + ```graphql + query contentfulPageQuery($slug: String!) { + contentfulPage(slug: { eq: $slug }) { + # Your other fields + heroImage { + gatsbyImageData(layout: FULL_WIDTH) + } } } - } -} -``` + ``` + +4. **Rendering Images**: Use the `` component from `gatsby-plugin-image` to display the images in your components: + + ```jsx + export default function ContentfulPageTemplate({ data }) { + return ( +
    + {/* Render logic of the rest of your content type */} + +
    + ) + } + ``` -4. Your query will return a dynamic image. Check the [documentation of gatsby-plugin-image](https://www.gatsbyjs.com/plugins/gatsby-plugin-image/#dynamic-images) to learn how to render it on your website. + Replace `imageData` with the image data fetched from your GraphQL query. -Check the [Reference Guide of gatsby-plugin-image](https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-plugin-image/) to get a deeper insight on how this works. + Certainly! Here's a rephrased version of the fifth step for using images with `gatsby-plugin-image`, aligned with the style and tone of the other steps: -### Building images on the fly via `useContentfulImage` +5. **Optimize Image Delivery Speed**: To enhance the performance of images served from Contentful's Image CDN, consider adding `preconnect` and `dns-prefetch` metatags to your website. These tags help accelerate the process of connecting to the CDN, leading to faster image rendering. -With `useContentfulImage` and the URL to the image on the Contentful Image API you can create dynamic images on the fly: + Implement this optimization using Gatsby's [Head API](https://www.gatsbyjs.com/docs/reference/built-in-components/gatsby-head/) in your global layout component: -```js -import { GatsbyImage } from "gatsby-plugin-image" -import * as React from "react" -import { useContentfulImage } from "gatsby-source-contentful" - -const MyComponent = () => { - const dynamicImage = useContentfulImage({ - image: { - url: "//images.ctfassets.net/k8iqpp6u0ior/3BSI9CgDdAn1JchXmY5IJi/f97a2185b3395591b98008647ad6fd3c/camylla-battani-AoqgGAqrLpU-unsplash.jpg", - width: 2000, - height: 1000, - }, - }) + ```jsx + export const Head = () => ( + <> + + + + ) + ``` - return -} -``` + By incorporating these tags, you ensure a quicker DNS resolution and connection establishment with the Contentful Image CDN. -#### On-the-fly image options: +### Building Images on the Fly with `useContentfulImage` -This hook accepts the same parameters as the `gatsbyImageData` field in your GraphQL queries. They are automatically translated to the proper Contentful Image API parameters. +For more dynamic image handling, `useContentfulImage` allows you to build images on the fly using Contentful's Image API: -Here are the most relevant ones: +1. **Use the Hook**: In your component, use the `useContentfulImage` hook to create an image dynamically: -- width: maximum 4000 -- height: maximum 4000 -- toFormat: defaults to the actual image format -- jpegProgressive: set to `progressive` to enable -- quality: between 1 and 100 -- resizingBehavior: https://www.contentful.com/developers/docs/references/images-api/#/reference/resizing-&-cropping/change-the-resizing-behavior -- cropFocus: https://www.contentful.com/developers/docs/references/images-api/#/reference/resizing-&-cropping/specify-focus-area -- background: background color in format `rgb:9090ff` -- cornerRadius: https://www.contentful.com/developers/docs/references/images-api/#/reference/resizing-&-cropping/crop-rounded-corners-&-circle-elipsis + ```jsx + import { useContentfulImage } from "gatsby-source-contentful" -## [Contentful Tags](https://www.contentful.com/developers/docs/references/content-delivery-api/#/reference/content-tags) + const MyComponent = () => { + const dynamicImage = useContentfulImage({ + image: { + url: "URL_of_the_image_on_Contentful", + width: 800, + height: 600, + }, + }) -### List available tags + return + } + ``` -This example lists all available tags. The sorting is optional. + Replace `URL_of_the_image_on_Contentful` with the actual URL of the image you want to display. The hook accepts the same parameters as the `gatsbyImageData` field in your GraphQL queries. -```graphql -query TagsQuery { - allContentfulTag(sort: { fields: contentful_id }) { - nodes { - name - contentful_id - } - } -} -``` +2. **Customizing Images**: You can customize the images using various options such as `width`, `height`, `format`, `quality`, etc. These options align with [Contentful's Image API parameters](https://www.contentful.com/developers/docs/references/images-api/#/reference). -### Filter content by tags +Can you help me to improve this section of my readme for a new version of the gatsby plugin gatsby-source-contentful? -This filters content entries that are tagged with the `numberInteger` tag. +## Leveraging Contentful Rich Text with Gatsby -```graphql -query FilterByTagsQuery { - allContentfulNumber( - sort: { fields: contentful_id } - filter: { - metadata: { - tags: { elemMatch: { contentful_id: { eq: "numberInteger" } } } - } - } - ) { - nodes { - title - integer - } - } -} -``` +The integration of Contentful's Rich Text fields in the `gatsby-source-contentful` plugin allows for a dynamic and rich content experience in Gatsby projects. This feature supports a variety of content compositions, including text, assets, and embedded entries, offering a powerful tool for developers and content creators alike. -## [Contentful Rich Text](https://www.contentful.com/developers/docs/concepts/rich-text/) +The latest `gatsby-source-contentful` updates enhance this integration, closely aligning with Contentful's GraphQL API and the `@contentful/rich-text-react-renderer`. -Rich Text feature is supported in this source plugin, you can use the following query to get the JSON output: +### Querying Rich Text Content -**Note:** In our example Content Model the field containing the Rich Text data is called `bodyRichText`. Make sure to use your field name within the Query instead of `bodyRichText` +The Rich Text field in Gatsby reflects the structure provided by Contentful's API. -### Query Rich Text content and references +Example GraphQL query for a Rich Text field: ```graphql -query pageQuery($id: String!) { - contentfulBlogPost(id: { eq: $id }) { - title - slug - # This is the rich text field, the name depends on your field configuration in Contentful - bodyRichText { - raw - references { - ... on ContentfulAsset { - # You'll need to query contentful_id in each reference - contentful_id - __typename - fixed(width: 1600) { - width - height - src - srcSet +# This is a extended example, see below for a step-by-step introduction +{ + allContentfulContentTypePage { + nodes { + content { + json + links { + assets { + block { + sys { + id + } # Required for link resolution + gatsbyImageData(width: 200) + } + # There is also hyperlink {} + } + entries { + block { + # Generic props and fields + __typename + sys { + id + type + } # Required for link resolution + # Content Type specific fields + ... on ContentfulContentTypeSomethingElse { + body + } + } + # Include inline and hyperlink as needed } - } - ... on ContentfulBlogPost { - contentful_id - __typename - title - slug } } } @@ -505,143 +664,215 @@ query pageQuery($id: String!) { } ``` -### Rendering +This query retrieves Rich Text JSON content (`json`) along with linked assets and entries, now organized under `assets` and `entries` within the `links` object. + +### Basic Rich Text Rendering + +To render Rich Text, use `gatsby-source-contentful`'s `renderRichText` function with a custom rendering setup for various embedded entries and assets: ```jsx -import { BLOCKS, MARKS } from "@contentful/rich-text-types" +// src/templates/contentful-page-template.js import { renderRichText } from "gatsby-source-contentful" +import { BLOCKS, MARKS } from "@contentful/rich-text-types" -const Bold = ({ children }) => {children} -const Text = ({ children }) =>

    {children}

    - -const options = { +// This factory provides a dynamic configuration for each rich text rendering +const makeOptions = ({ assetBlockMap, entryBlockMap, entryInlineMap }) => ({ renderMark: { - [MARKS.BOLD]: text => {text}, + [MARKS.BOLD]: text => {text}, }, renderNode: { - [BLOCKS.PARAGRAPH]: (node, children) => {children}, - [BLOCKS.EMBEDDED_ASSET]: node => { - return ( - <> -

    Embedded Asset

    -
    -            {JSON.stringify(node, null, 2)}
    -          
    - - ) - }, + [BLOCKS.PARAGRAPH]: (node, children) =>

    {children}

    , }, +}) + +export default function ContentfulPageTemplate({ data }) { + return ( +
    + {/* Your other fields */} +
    {renderRichText(data.content, makeOptions)}
    +
    + ) } -function BlogPostTemplate({ data }) { - const { bodyRichText } = data.contentfulBlogPost - - return
    {bodyRichText && renderRichText(bodyRichText, options)}
    -} +export const pageQuery = graphql` + query contentfulPageQuery($slug: String!) { + contentfulPage(slug: { eq: $slug }) { + title + content { + json + } + } + } +` ``` -**Note:** The `contentful_id` and `__typename` fields must be queried on rich-text references in order for the `renderNode` to receive the correct data. +### Embedding Images in Rich Text with Gatsby Plugin Image -### Embedding an image in a Rich Text field +For optimal image display, use `gatsby-plugin-image` to render embedded images: -**Import** +```jsx +// src/templates/contentful-page-template.js +import { GatsbyImage } from "gatsby-plugin-image" -```js -import { renderRichText } from "gatsby-source-contentful" -``` +const makeOptions = ({ assetBlockMap, entryBlockMap, entryInlineMap }) => ({ + renderNode: { + [BLOCKS.EMBEDDED_ASSET]: node => { + const asset = assetBlockMap.get(node?.data?.target?.sys.id) + if (asset.gatsbyImageData) { + return + } + }, + }, +}) -**GraphQL** +// No changes are required to the ContentfulPageTemplate page component -```graphql -mainContent { - raw - references { - ... on ContentfulAsset { - contentful_id - __typename - gatsbyImageData +export const pageQuery = graphql` + query contentfulPageQuery($slug: String!) { + contentfulPage(slug: { eq: $slug }) { + title + content { + json + links { + assets { + block { + sys { + # Make sure to query the id for link resolution + id + } + # You have full access to gatsby-plugin-image + gatsbyImageData(width: 200) + } + } + } + } } } -} +` ``` -**Options** +### Embedding Entries in Rich Text + +Enhance the renderer to include other entries within Rich Text: ```jsx -const options = { +// src/templates/contentful-page-template.js +import { GatsbyImage } from "gatsby-plugin-image" + +const makeOptions = ({ assetBlockMap, entryBlockMap, entryInlineMap }) => ({ renderNode: { - "embedded-asset-block": node => { - const { gatsbyImageData } = node.data.target - if (!gatsbyImageData) { - // asset is not an image - return null + [BLOCKS.EMBEDDED_ASSET]: node => { + const asset = assetBlockMap.get(node?.data?.target?.sys.id) + if (asset.gatsbyImageData) { + return + } + }, + [BLOCKS.EMBEDDED_ENTRY]: node => { + const entry = entryBlockMap.get(node?.data?.target?.sys.id) + if (entry.__typename === "ContentfulContentTypeSomethingElse") { + return } - return + // Add more conditions for other content types }, }, -} -``` +}) -**Render** +// No changes are required to the ContentfulPageTemplate page component -```jsx -
    - {blogPost.mainContent && renderRichText(blogPost.mainContent, options)} -
    +export const pageQuery = graphql` + query contentfulPageQuery($slug: String!) { + contentfulPage(slug: { eq: $slug }) { + title + content { + json + links { + assets { + block { + sys { + id + } + gatsbyImageData(width: 200) + } + } + entries { + block { + __typename + sys { + # These two fields are required, + # make sure to include them in your sys + id + type + } + ... on ContentfulContentTypeSomethingElse { + body + } + } + } + } + } + } + } +` ``` -Check out the examples at [@contentful/rich-text-react-renderer](https://github.com/contentful/rich-text/tree/master/packages/rich-text-react-renderer). +### Further Contentful Rich Text resources + +1. [Contentful Rich Text Field Documentation](https://www.contentful.com/developers/docs/concepts/rich-text/): A comprehensive guide to understanding and utilizing Rich Text fields in Contentful. +2. [Contentful Rich Text Rendering Library](https://github.com/contentful/rich-text): Explore the official Contentful library for rendering Rich Text content. +3. [Using Rich Text Fields in Gatsby](https://www.contentful.com/developers/docs/javascript/tutorials/rendering-contentful-rich-text-with-javascript/): An in-depth tutorial on rendering Rich Text fields with JavaScript, easily adaptable for Gatsby projects. + +## Downloading Assets for Static Distribution -## Download assets for static distribution +The `downloadLocal` feature is a valuable addition for managing Contentful assets, enabling local storage and access. This option can significantly enhance your project’s performance and flexibility in handling media files. -When you set `downloadLocal: true` in your config, the plugin will download and cache Contentful assets to the local filesystem. +### Benefits of `downloadLocal` -There are two main reasons you might want to use this option: +1. **Improved Performance**: By caching assets locally, you reduce the dependency on external network requests to Contentful's CDN, potentially speeding up load times. +2. **Enhanced Image Processing**: Local assets allow for more control over image processing, enabling the use of advanced features in `gatsby-plugin-image`, such as generating AVIF formats. -- Avoiding the extra network handshake required to the Contentful CDN for images hosted there -- Gain more control over how images are processed or rendered (ie, providing AVIF with gatsby-plugin-image) +### Trade-offs -The default setting for this feature is `false`, as there are certain tradeoffs for using this feature: +However, consider the following trade-offs when enabling this feature: -- All assets in your Contentful space will be downloaded during builds -- Your build times and build output size will increase -- Bandwidth going through your CDN will increase (since images are no longer being served from the Contentful CDN) -- You will have to change how you query images and which image fragments you use. +- **Increased Build Times**: Downloading all assets during build time can increase the duration of your build process. +- **Larger Build Output Size**: The local storage of assets will increase the size of your build output. +- **Higher Bandwidth Usage**: Since images are not served from Contentful's CDN, your CDN might experience increased bandwidth usage. -### Enable the feature with the `downloadLocal: true` option. +### Enabling `downloadLocal` + +To activate this feature, set the `downloadLocal` option to `true` in your `gatsby-config.js`: ```javascript -// In your gatsby-config.js +// gatsby-config.js module.exports = { plugins: [ { resolve: `gatsby-source-contentful`, options: { spaceId: `your_space_id`, - // Learn about environment variables: https://gatsby.app/env-vars accessToken: process.env.CONTENTFUL_ACCESS_TOKEN, downloadLocal: true, }, }, + // ... other plugins ... ], } ``` -### Updating Queries for downloadLocal +### Updating GraphQL Queries + +Once `downloadLocal` is enabled, your GraphQL queries will need adjustment to work with the locally downloaded assets: + +- Query the `localFile` field on `ContentfulAsset` to access the local file. +- Utilize `gatsby-plugin-image` to process and display images. -When using the `downloadLocal` setting, you'll need to update your codebase to be working with the locally downloaded images, rather than the default Contentful Nodes. Query a `ContentfulAsset`'s `localFile` field in GraphQL to gain access to the common fields of the `gatsby-source-filesystem` `File` node. This is not a Contentful node, so usage for `gatsby-plugin-image` is different: +Example Query: ```graphql query MyQuery { - # Example is for a `ContentType` with a `ContentfulAsset` field - # You could also query an asset directly via - # `allContentfulAsset { edges{ node { } } }` - # or `contentfulAsset(contentful_id: { eq: "contentful_id here" } ) { }` - contentfulMyContentType { + contentfulContentTypePage { myContentfulAssetField { - # Query for locally stored file(e.g. An image) - `File` node localFile { - # Use `gatsby-plugin-image` to create the image data childImageSharp { gatsbyImageData(formats: AVIF) } @@ -651,35 +882,37 @@ query MyQuery { } ``` -Note: This feature downloads any file from a `ContentfulAsset` node that `gatsby-source-contentful` provides. They are all copied over from `./cache/gatsby-source-filesystem/` to the sites build location `./public/static/`. +### Troubleshooting -For any troubleshooting related to this feature, first try clearing your `./cache/` directory. `gatsby-source-contentful` will acquire fresh data, and all `ContentfulAsset`s will be downloaded and cached again. +- **Cache Clearing**: If you encounter issues with this feature, start by clearing the Gatsby cache by executing `npx gatsby clear` in your root directory. This ensures fresh data from Contentful and re-downloads assets. -## Sourcing From Multiple Contentful Spaces +## Multi-Space Sourcing: Example for Sourcing from Multiple Contentful Spaces -To source from multiple Contentful environments/spaces, add another configuration for `gatsby-source-contentful` in `gatsby-config.js`: +To source content from multiple Contentful spaces within a Gatsby project, you can define multiple instances of the `gatsby-source-contentful` plugin in your `gatsby-config.js`. Each instance should be configured with its respective Contentful space ID and access token. Here's an example: ```javascript -// In your gatsby-config.js +// gatsby-config.js module.exports = { plugins: [ { resolve: `gatsby-source-contentful`, options: { - spaceId: `your_space_id`, - accessToken: process.env.CONTENTFUL_ACCESS_TOKEN, + spaceId: `first_space_id`, + accessToken: process.env.FIRST_SPACE_ACCESS_TOKEN, }, }, { resolve: `gatsby-source-contentful`, options: { - spaceId: `your_second_space_id`, - accessToken: process.env.SECONDARY_CONTENTFUL_ACCESS_TOKEN, + spaceId: `second_space_id`, + accessToken: process.env.SECOND_SPACE_ACCESS_TOKEN, }, }, + // ... additional plugin instances for other spaces ... ], } ``` -[dotenv]: https://github.com/motdotla/dotenv -[envvars]: https://gatsby.dev/env-vars +### Current Limitations + +As of now, the `gatsby-source-contentful` plugin does not support the [Contentful feature for linking content across multiple spaces](https://www.contentful.com/help/link-content-across-multiple-spaces/). This means that while you can source content from different spaces, any links or references to content residing in separate spaces won't be resolved automatically. It's important to plan your content architecture accordingly, keeping this limitation in mind. From b229a5f55e6044166c5e746346a0947fb533e221 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 21 Dec 2023 13:30:23 +0100 Subject: [PATCH 131/149] chore: fix tests and typing --- .../gatsby-source-contentful/src/__tests__/gatsby-node.js | 8 ++++---- packages/gatsby-source-contentful/src/normalize.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js index 5cc93e9bf0acd..a2d90a773dcf3 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-node.js @@ -750,7 +750,7 @@ describe(`gatsby-node`, () => { expect(getNode(blogEntry[`author`])).toBeTruthy() }) - expect(actions.createNode).toHaveBeenCalledTimes(44) + expect(actions.createNode).toHaveBeenCalledTimes(46) expect(actions.deleteNode).toHaveBeenCalledTimes(0) expect(actions.touchNode).toHaveBeenCalledTimes(0) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` @@ -840,7 +840,7 @@ describe(`gatsby-node`, () => { expect(getNode(blogEntry[`author`])).toBeTruthy() }) - expect(actions.createNode).toHaveBeenCalledTimes(52) + expect(actions.createNode).toHaveBeenCalledTimes(54) expect(actions.deleteNode).toHaveBeenCalledTimes(0) expect(actions.touchNode).toHaveBeenCalledTimes(0) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` @@ -993,7 +993,7 @@ describe(`gatsby-node`, () => { ) }) - expect(actions.createNode).toHaveBeenCalledTimes(46) + expect(actions.createNode).toHaveBeenCalledTimes(48) expect(actions.deleteNode).toHaveBeenCalledTimes(2) expect(actions.touchNode).toHaveBeenCalledTimes(0) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` @@ -1079,7 +1079,7 @@ describe(`gatsby-node`, () => { locales ) - expect(actions.createNode).toHaveBeenCalledTimes(46) + expect(actions.createNode).toHaveBeenCalledTimes(48) expect(actions.deleteNode).toHaveBeenCalledTimes(2) expect(actions.touchNode).toHaveBeenCalledTimes(0) expect(reporter.info.mock.calls).toMatchInlineSnapshot(` diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index cd396f415f034..45b7a29af6937 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -787,7 +787,7 @@ export const createNodesForContentType = ({ internal: { type: makeTypeName(contentTypeItemId, contentTypePrefix), // The content of an entry is guaranteed to be updated if and only if the .sys.updatedAt field changed - contentDigest: entryItem.sys.updatedAt, + contentDigest: entryItem.sys.updatedAt as string, }, // 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 From e084c3d7ecd574bbc4fec08a9703d673e6caae7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 21 Dec 2023 13:54:00 +0100 Subject: [PATCH 132/149] chore: adjust package versions to make build process happy --- examples/using-contentful/package.json | 12 ++++++------ packages/gatsby-source-contentful/package.json | 2 +- packages/gatsby-source-contentful/src/gatsby-node.ts | 5 +---- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/examples/using-contentful/package.json b/examples/using-contentful/package.json index e1fbe69e5f867..a063844460597 100644 --- a/examples/using-contentful/package.json +++ b/examples/using-contentful/package.json @@ -5,13 +5,13 @@ "version": "1.0.0", "author": "Marcus Ericsson (mericsson.com)", "dependencies": { - "gatsby": "^5.13.0-next.1", - "gatsby-core-utils": "^4.13.0-next.0", - "gatsby-plugin-image": "^3.13.0-next.0", - "gatsby-plugin-sharp": "^5.13.0-next.0", - "gatsby-plugin-typography": "^5.13.0-next.0", + "gatsby": "^5.14.0-next.0", + "gatsby-core-utils": "^4.14.0-next.0", + "gatsby-plugin-image": "^3.14.0-next.0", + "gatsby-plugin-sharp": "^5.14.0-next.0", + "gatsby-plugin-typography": "^5.14.0-next.0", "gatsby-source-contentful": "^8.99.0-next.0", - "gatsby-transformer-remark": "^6.13.0-next.0", + "gatsby-transformer-remark": "^6.14.0-next.0", "prop-types": "^15.7.2", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/packages/gatsby-source-contentful/package.json b/packages/gatsby-source-contentful/package.json index 40bb0a268b83c..695cffd568c86 100644 --- a/packages/gatsby-source-contentful/package.json +++ b/packages/gatsby-source-contentful/package.json @@ -35,7 +35,7 @@ "babel-preset-gatsby-package": "^3.14.0-next.0", "cross-env": "^7.0.3", "del-cli": "^5.0.0", - "gatsby-plugin-sharp": "^5.13.0-next.0", + "gatsby-plugin-sharp": "^5.14.0-next.0", "nock": "^13.3.1", "typescript": "^5.0.4" }, diff --git a/packages/gatsby-source-contentful/src/gatsby-node.ts b/packages/gatsby-source-contentful/src/gatsby-node.ts index 3bf691fa1fa8b..de198c55a9466 100644 --- a/packages/gatsby-source-contentful/src/gatsby-node.ts +++ b/packages/gatsby-source-contentful/src/gatsby-node.ts @@ -74,10 +74,7 @@ export const onPreInit: GatsbyNode["onPreInit"] = async ( }) } - if ( - actions?.addRemoteFileAllowedUrl && - typeof actions?.addRemoteFileAllowedUrl === `function` - ) { + if (typeof actions?.addRemoteFileAllowedUrl === `function`) { actions.addRemoteFileAllowedUrl( `https://images.ctfassets.net/${pluginOptions.spaceId}/*` ) From 384a825cabcc1bb1078d9a62897f40070297fe2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 21 Dec 2023 14:33:56 +0100 Subject: [PATCH 133/149] docs: simplify codemods --- packages/gatsby-source-contentful/MIGRATION.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/packages/gatsby-source-contentful/MIGRATION.md b/packages/gatsby-source-contentful/MIGRATION.md index 88738934eaff9..a746fe30e608d 100644 --- a/packages/gatsby-source-contentful/MIGRATION.md +++ b/packages/gatsby-source-contentful/MIGRATION.md @@ -54,7 +54,7 @@ Before you start manual updates, take advantage of our codemods that automate mo **Option A:** (Direct Execution) ```bash -npx gatsby-codemods@ctf-next gatsby-source-contentful gatsby-*.js src +npx gatsby-codemods@ctf-next gatsby-source-contentful --extensions=js,ts,tsx gatsby-* src ``` **Option B:** (Install, Execute, Uninstall) @@ -64,18 +64,12 @@ npx gatsby-codemods@ctf-next gatsby-source-contentful gatsby-*.js src npm install -D jscodeshift gatsby-codemods@ctf-next # Execute codemods -npx jscodeshift -t ./node_modules/gatsby-codemods/transforms/gatsby-source-contentful.js gatsby-*.js src/**/*.js +npx jscodeshift -t ./node_modules/gatsby-codemods/transforms/gatsby-source-contentful.js --extensions=js,ts,tsx gatsby-* src # Uninstall codemods npm remove jscodeshift gatsby-codemods ``` -**For TypeScript projects:** Include `.ts` and `.tsx` files in the transformation: - -```bash -npx ... gatsby-*.js gatsby-*.ts src/**/*.js src/**/*.ts src/**/*.tsx -``` - **Handling Large Codebases:** If your project is particularly large, you may need to increase the maximum memory allocation for the process: ```bash From 3105a7a71be11a7bbe34c0aec51ae21464d77a53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 21 Dec 2023 14:43:01 +0100 Subject: [PATCH 134/149] docs: add hint that we now no more have a spam of @link directive warnings --- packages/gatsby-source-contentful/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/gatsby-source-contentful/README.md b/packages/gatsby-source-contentful/README.md index dddc7f0bc2499..e9e640dfa60fa 100644 --- a/packages/gatsby-source-contentful/README.md +++ b/packages/gatsby-source-contentful/README.md @@ -70,6 +70,7 @@ The v9 release of `gatsby-source-contentful` brings significant improvements, fo - **Updated Field Name Restrictions**: Fields can now be named `contentful_id`, with restrictions now applied to names like `sys`, `contentfulMetadata`, and `linkedFrom`. - **Refined Backlinks**: Backlinks/references are now located in the `linkedFrom` field, aligning with Contentful's GraphQL API structure. - **Expanded Configuration Options**: Additional [configuration options](#advanced-configuration) provide greater control and customization for your specific project needs. +- **Updated @link Directive Usage**: The new version of the "gatsby-source-contentful" plugin adopts the @link directive, eliminating the warnings in the build log about the deprecated \_\_\_NODE convention in Gatsby v5. For a detailed migration guide and to leverage these improvements, refer to the [Migration Guide](./MIGRATION.md) section. From 5e719c27046aab708163091b60c104db6011a41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 21 Dec 2023 14:48:58 +0100 Subject: [PATCH 135/149] fix: avoid deletion of node properties" --- packages/gatsby-source-contentful/src/source-nodes.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/packages/gatsby-source-contentful/src/source-nodes.ts b/packages/gatsby-source-contentful/src/source-nodes.ts index 6d807fcb874a0..18192f332e325 100644 --- a/packages/gatsby-source-contentful/src/source-nodes.ts +++ b/packages/gatsby-source-contentful/src/source-nodes.ts @@ -468,17 +468,6 @@ export const sourceNodes: GatsbyNode["sourceNodes"] = continue } - // We need to remove properties from existing fields - // that are reserved and managed by Gatsby (`.internal.owner`, `.fields`). - // Gatsby automatically will set `.owner` it back - delete nodeToUpdate.internal.owner - // `.fields` need to be created with `createNodeField` action, we can't just re-add them. - // Other plugins (or site itself) will have opportunity to re-generate them in `onCreateNode` lifecycle. - // Contentful content nodes are not using `createNodeField` so it's safe to delete them. - // (Asset nodes DO use `createNodeField` for `localFile` and if we were updating those, then - // we would also need to restore that field ourselves after re-creating a node) - delete nodeToUpdate.fields // plugin adds node field on asset nodes which don't have reverse links - // We add or modify counter postfix to contentDigest // to make sure Gatsby treat this as data update let counter From ced0cb08df3a4db2c2174cce5a71bf13152b4443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 21 Dec 2023 18:13:34 +0100 Subject: [PATCH 136/149] chore: clean up package.json/workspace --- package.json | 3 +-- yarn.lock | 20 +------------------- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 47a6d4485ef3d..a858da92766a5 100644 --- a/package.json +++ b/package.json @@ -126,8 +126,7 @@ "watch": "lerna run watch --no-sort --stream --concurrency 999" }, "workspaces": [ - "packages/*", - "examples/using-contentful" + "packages/*" ], "resolutions": { "@babel/plugin-transform-modules-commonjs": "7.18.6" diff --git a/yarn.lock b/yarn.lock index 1cfde98ef7784..6321f6e9bef92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20570,7 +20570,7 @@ react-test-renderer@^16.14.0: react-is "^16.8.6" scheduler "^0.19.1" -react-typography@^0.16.19, react-typography@^0.16.23: +react-typography@^0.16.23: version "0.16.23" resolved "https://registry.yarnpkg.com/react-typography/-/react-typography-0.16.23.tgz#68c0af17ed876a30fcea256ef0dbbf0bc01b63b3" integrity sha512-nOl1/VDhqYSp5XktW/xmeLgE2S4L0LIWKAq2lNtc6Tq+3ZgvSX2Q0r0vlLKyOVq0hjsOYubE1TLoz/Wu/W8GLg== @@ -24069,29 +24069,11 @@ typescript@^5.0.4, typescript@^5.1.6: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== -typography-breakpoint-constants@^0.16.19: - version "0.16.19" - resolved "https://registry.yarnpkg.com/typography-breakpoint-constants/-/typography-breakpoint-constants-0.16.19.tgz#e0e89147749562cbb46ce76c47ff0f73372765e7" - integrity sha512-vXjfV9hwAXIOf5+U5GN137ahBkK+sj1TJu/5ksmP+8XB/D80lmGb/m0nKviWaQ3t7HLrK848VGrFS+6E2vcmVg== - typography-normalize@^0.16.19: version "0.16.19" resolved "https://registry.yarnpkg.com/typography-normalize/-/typography-normalize-0.16.19.tgz#58e0cf12466870c5b27006daa051fe7307780660" integrity sha512-vtnSv/uGBZVbd4e/ZhZB9HKBgKKlWQUXw74+ADIHHxzKp27CEf8PSR8TX1zF2qSyQ9/qMdqLwXYz8yRQFq9JLQ== -typography@^0.16.19: - version "0.16.24" - resolved "https://registry.yarnpkg.com/typography/-/typography-0.16.24.tgz#7bcbe3921367ca74168d0acce969749a0546fd4d" - integrity sha512-o5jNctzGoJm2XgdqivJdpkF6lQkcQo8v1biMGY+rLSpBHhpCKdQv5em9S3R6igApxVYtbhNBJbV95vK9oPwRKQ== - dependencies: - compass-vertical-rhythm "^1.4.5" - decamelize "^1.2.0" - gray-percentage "^2.0.0" - lodash "^4.13.1" - modularscale "^1.0.2" - object-assign "^4.1.0" - typography-normalize "^0.16.19" - typography@^0.16.21: version "0.16.21" resolved "https://registry.yarnpkg.com/typography/-/typography-0.16.21.tgz#2cd177f20c64d0b762389464688811f980ade682" From 329566cfebbd1a6a619d748ce700a08c671d7d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 28 Dec 2023 12:33:45 +0100 Subject: [PATCH 137/149] fix: improve typings for rich text rendering --- .../gatsby-source-contentful/src/rich-text.ts | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/packages/gatsby-source-contentful/src/rich-text.ts b/packages/gatsby-source-contentful/src/rich-text.ts index 03418aa7d457b..af689141e478a 100644 --- a/packages/gatsby-source-contentful/src/rich-text.ts +++ b/packages/gatsby-source-contentful/src/rich-text.ts @@ -1,4 +1,7 @@ -import { documentToReactComponents } from "@contentful/rich-text-react-renderer" +import { + documentToReactComponents, + Options, +} from "@contentful/rich-text-react-renderer" import { AssetHyperlink, AssetLinkBlock, @@ -26,6 +29,20 @@ interface IContentfulRichTextLinks { entries: IContentfulRichTextLinksEntries } +type AssetBlockMap = Map +type AssetHyperlinkMap = Map +type EntryBlockMap = Map +type EntryInlineMap = Map +type EntryHyperlinkMap = Map +interface IMakeOptions { + assetBlockMap: AssetBlockMap + assetHyperlinkMap: AssetHyperlinkMap + entryBlockMap: EntryBlockMap + entryInlineMap: EntryInlineMap + entryHyperlinkMap: EntryHyperlinkMap +} +export type MakeOptions = (referenceMaps: IMakeOptions) => Options + export function renderRichText( { json, @@ -34,7 +51,7 @@ export function renderRichText( json: Document links: IContentfulRichTextLinks }, - makeOptions = {} + makeOptions: MakeOptions | Options ): React.ReactNode { const options = typeof makeOptions === `function` @@ -49,11 +66,11 @@ export function renderRichText( * https://www.contentful.com/blog/2021/04/14/rendering-linked-assets-entries-in-contentful/ */ function generateLinkMaps(links): { - assetBlockMap: Map - assetHyperlinkMap: Map - entryBlockMap: Map - entryInlineMap: Map - entryHyperlinkMap: Map + assetBlockMap: AssetBlockMap + assetHyperlinkMap: AssetHyperlinkMap + entryBlockMap: EntryBlockMap + entryInlineMap: EntryInlineMap + entryHyperlinkMap: EntryHyperlinkMap } { const assetBlockMap = new Map() for (const asset of links?.assets.block || []) { From cfd7b29643c7bdfcfff223766cca8ef9af147f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 28 Dec 2023 13:28:10 +0100 Subject: [PATCH 138/149] fix: further improve rich text types --- .../gatsby-source-contentful/src/rich-text.ts | 76 ++++++++++--------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/packages/gatsby-source-contentful/src/rich-text.ts b/packages/gatsby-source-contentful/src/rich-text.ts index af689141e478a..bf8fc064c7d5c 100644 --- a/packages/gatsby-source-contentful/src/rich-text.ts +++ b/packages/gatsby-source-contentful/src/rich-text.ts @@ -2,38 +2,32 @@ import { documentToReactComponents, Options, } from "@contentful/rich-text-react-renderer" -import { - AssetHyperlink, - AssetLinkBlock, - Document, - EntryHyperlink, - EntryLinkBlock, - EntryLinkInline, -} from "@contentful/rich-text-types" +import { Document } from "@contentful/rich-text-types" import React from "react" import type { IContentfulEntry, IContentfulAsset } from "./types/contentful" interface IContentfulRichTextLinksAssets { - block: Array - hyperlink: Array + block?: Array + hyperlink?: Array } interface IContentfulRichTextLinksEntries { - inline: Array - block: Array - hyperlink: Array + inline?: Array + block?: Array + hyperlink?: Array } interface IContentfulRichTextLinks { - assets: IContentfulRichTextLinksAssets - entries: IContentfulRichTextLinksEntries + assets?: IContentfulRichTextLinksAssets + entries?: IContentfulRichTextLinksEntries } -type AssetBlockMap = Map -type AssetHyperlinkMap = Map -type EntryBlockMap = Map -type EntryInlineMap = Map -type EntryHyperlinkMap = Map +type AssetBlockMap = Map> +type AssetHyperlinkMap = Map> +type EntryBlockMap = Map> +type EntryInlineMap = Map> +type EntryHyperlinkMap = Map> + interface IMakeOptions { assetBlockMap: AssetBlockMap assetHyperlinkMap: AssetHyperlinkMap @@ -48,24 +42,24 @@ export function renderRichText( json, links, }: { - json: Document - links: IContentfulRichTextLinks + json: unknown + links?: unknown }, - makeOptions: MakeOptions | Options + makeOptions?: MakeOptions | Options ): React.ReactNode { const options = typeof makeOptions === `function` - ? makeOptions(generateLinkMaps(links)) + ? makeOptions(generateLinkMaps(links as IContentfulRichTextLinks)) : makeOptions - return documentToReactComponents(json, options) + return documentToReactComponents(json as Document, options) } /** * Helper function to simplify Rich Text rendering. Based on: * https://www.contentful.com/blog/2021/04/14/rendering-linked-assets-entries-in-contentful/ */ -function generateLinkMaps(links): { +function generateLinkMaps(links: IContentfulRichTextLinks): { assetBlockMap: AssetBlockMap assetHyperlinkMap: AssetHyperlinkMap entryBlockMap: EntryBlockMap @@ -73,28 +67,38 @@ function generateLinkMaps(links): { entryHyperlinkMap: EntryHyperlinkMap } { const assetBlockMap = new Map() - for (const asset of links?.assets.block || []) { - assetBlockMap.set(asset.sys.id, asset) + if (links?.assets?.block) { + for (const asset of links.assets.block) { + assetBlockMap.set(asset.sys.id, asset) + } } const assetHyperlinkMap = new Map() - for (const asset of links?.assets.hyperlink || []) { - assetHyperlinkMap.set(asset.sys.id, asset) + if (links?.assets?.hyperlink) { + for (const asset of links.assets.hyperlink) { + assetHyperlinkMap.set(asset.sys.id, asset) + } } const entryBlockMap = new Map() - for (const entry of links?.entries.block || []) { - entryBlockMap.set(entry.sys.id, entry) + if (links?.entries?.block) { + for (const entry of links.entries.block) { + entryBlockMap.set(entry.sys.id, entry) + } } const entryInlineMap = new Map() - for (const entry of links?.entries.inline || []) { - entryInlineMap.set(entry.sys.id, entry) + if (links?.entries?.inline) { + for (const entry of links.entries.inline) { + entryInlineMap.set(entry.sys.id, entry) + } } const entryHyperlinkMap = new Map() - for (const entry of links?.entries.hyperlink || []) { - entryHyperlinkMap.set(entry.sys.id, entry) + if (links?.entries?.hyperlink) { + for (const entry of links.entries.hyperlink) { + entryHyperlinkMap.set(entry.sys.id, entry) + } } return { From e96c389c680e6b3058a8d13df98053afb862c050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 28 Dec 2023 13:42:50 +0100 Subject: [PATCH 139/149] fix: schema building no more fails when Content Model has none or only Rich Text references --- .../src/create-schema-customization.ts | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index bba05feadedb4..265e3a7fbbac7 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -465,7 +465,8 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] if ( contentType.fields.some( - field => field.linkType || field.items?.linkType + field => + field.linkType || field.items?.linkType || field.type === `RichText` ) ) { reverseLinkFields[contentTypeItemId] = { @@ -477,6 +478,23 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] } }) + // When nothing is set up to be linked in the Contentful Content Model, schema building fails + // as empty fields get removed by graphql-compose + if (Object.keys(reverseLinkFields).length === 0) { + contentTypeItems.forEach(contentType => { + const contentTypeItemId = contentTypeIdMap.get(contentType.sys.id) + + if (contentTypeItemId) { + reverseLinkFields[contentTypeItemId] = { + type: `[${contentTypeItemId}]`, + extensions: { + link: { by: `id`, from: contentTypeItemId }, + }, + } + } + }) + } + const linkedFromName = `ContentfulLinkedFrom` createTypes( schema.buildObjectType({ From 42540e9a4551c02fc2a386ed05d936451f8ba276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 28 Dec 2023 13:44:27 +0100 Subject: [PATCH 140/149] test: update snapshots --- .../__snapshots__/create-schema-customization.js.snap | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index babe093df8330..d8dc2396e549f 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -138,6 +138,15 @@ Array [ }, "type": "[ContentfulContentTypeMediaReference]", }, + "ContentfulContentTypeRichText": Object { + "extensions": Object { + "link": Object { + "by": "id", + "from": "ContentfulContentTypeRichText", + }, + }, + "type": "[ContentfulContentTypeRichText]", + }, "ContentfulContentTypeValidatedContentReference": Object { "extensions": Object { "link": Object { From d53b2cf746a687e92d7e700bc69ddd8820fcfe9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 28 Dec 2023 13:54:56 +0100 Subject: [PATCH 141/149] docs: improve Rich Text rendering section for migration --- .../gatsby-source-contentful/MIGRATION.md | 46 +++++++++++++++---- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/gatsby-source-contentful/MIGRATION.md b/packages/gatsby-source-contentful/MIGRATION.md index a746fe30e608d..0b78ece12ef4f 100644 --- a/packages/gatsby-source-contentful/MIGRATION.md +++ b/packages/gatsby-source-contentful/MIGRATION.md @@ -303,9 +303,20 @@ Instead of passing your option object into `renderRichText()` you now pass a opt **Old rendering logic:** -```jsx -const options = { - // options for rendering different node types +```tsx +import { renderRichText } from "gatsby-source-contentful/rich-text" +import { Options } from "@contentful/rich-text-react-renderer" +import { BLOCKS, MARKS } from "@contentful/rich-text-types" + +const options: Options = { + renderNode: { + [BLOCKS.EMBEDDED_ASSET]: node => { + const image = getImage(node.data.target) + return image ? ( + + ) : null + }, + }, } ;
    {renderRichText(richText, options)}
    @@ -313,12 +324,29 @@ const options = { **New rendering logic:** -```jsx -const makeOptions = ({ assetBlockMap, entryBlockMap, entryInlineMap }) => { - return { - // updated options based on the new schema - } -} +```tsx +import { renderRichText, MakeOptions } from "gatsby-source-contentful" +import { BLOCKS, MARKS } from "@contentful/rich-text-types" + +const makeOptions: MakeOptions = ({ + assetBlockMap, + assetHyperlinkMap, + entryBlockMap, + entryInlineMap, + entryHyperlinkMap, +}) => ({ + renderNode: { + [BLOCKS.EMBEDDED_ASSET]: node => { + const image = assetBlockMap.get(node.data.target.sys.id) + return (image && image.gatsbyImageData )? ( + + ) : null + }, + }, +}) ;
    {renderRichText(richText, makeOptions)}
    ``` From 7bef97a6265667c5a1897f428b6c8d5ee708199e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 28 Dec 2023 15:20:45 +0100 Subject: [PATCH 142/149] docs: format migration.md to make linting happy --- packages/gatsby-source-contentful/MIGRATION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/MIGRATION.md b/packages/gatsby-source-contentful/MIGRATION.md index 0b78ece12ef4f..a051a668c4688 100644 --- a/packages/gatsby-source-contentful/MIGRATION.md +++ b/packages/gatsby-source-contentful/MIGRATION.md @@ -338,7 +338,7 @@ const makeOptions: MakeOptions = ({ renderNode: { [BLOCKS.EMBEDDED_ASSET]: node => { const image = assetBlockMap.get(node.data.target.sys.id) - return (image && image.gatsbyImageData )? ( + return image && image.gatsbyImageData ? ( Date: Wed, 31 Jan 2024 11:16:36 +0100 Subject: [PATCH 143/149] docs: improve codemod instructions --- packages/gatsby-source-contentful/MIGRATION.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/MIGRATION.md b/packages/gatsby-source-contentful/MIGRATION.md index a051a668c4688..4434f45fe6b94 100644 --- a/packages/gatsby-source-contentful/MIGRATION.md +++ b/packages/gatsby-source-contentful/MIGRATION.md @@ -54,9 +54,11 @@ Before you start manual updates, take advantage of our codemods that automate mo **Option A:** (Direct Execution) ```bash -npx gatsby-codemods@ctf-next gatsby-source-contentful --extensions=js,ts,tsx gatsby-* src +npx gatsby-codemods@ctf-next gatsby-source-contentful gatsby-* src ``` +**Hint:** If you use `.mjs` files, rename them to `.js` or `.ts` first. + **Option B:** (Install, Execute, Uninstall) ```bash From bf2b92ff37a7e26226965539fdc9078941a3b598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 31 Jan 2024 11:19:08 +0100 Subject: [PATCH 144/149] docs: further improve codemod instructions --- packages/gatsby-source-contentful/MIGRATION.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/gatsby-source-contentful/MIGRATION.md b/packages/gatsby-source-contentful/MIGRATION.md index 4434f45fe6b94..3ffcf583c1012 100644 --- a/packages/gatsby-source-contentful/MIGRATION.md +++ b/packages/gatsby-source-contentful/MIGRATION.md @@ -54,7 +54,7 @@ Before you start manual updates, take advantage of our codemods that automate mo **Option A:** (Direct Execution) ```bash -npx gatsby-codemods@ctf-next gatsby-source-contentful gatsby-* src +npx gatsby-codemods@ctf-next gatsby-source-contentful . ``` **Hint:** If you use `.mjs` files, rename them to `.js` or `.ts` first. @@ -66,7 +66,7 @@ npx gatsby-codemods@ctf-next gatsby-source-contentful gatsby-* src npm install -D jscodeshift gatsby-codemods@ctf-next # Execute codemods -npx jscodeshift -t ./node_modules/gatsby-codemods/transforms/gatsby-source-contentful.js --extensions=js,ts,tsx gatsby-* src +npx jscodeshift -t ./node_modules/gatsby-codemods/transforms/gatsby-source-contentful.js . # Uninstall codemods npm remove jscodeshift gatsby-codemods From 343a9efbfd83ad14cb744e3121420e1a1221b310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Wed, 31 Jan 2024 11:26:49 +0100 Subject: [PATCH 145/149] fix: add missing date format extension/directive to sys properties of type date --- .../src/create-schema-customization.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index 265e3a7fbbac7..d0bea35a72d14 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -405,8 +405,18 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] link: { by: `id`, from: `contentType` }, }, }, - firstPublishedAt: { type: ` Date!` }, - publishedAt: { type: ` Date!` }, + firstPublishedAt: { + type: ` Date!`, + extensions: { + dateformat: {}, + }, + }, + publishedAt: { + type: ` Date!`, + extensions: { + dateformat: {}, + }, + }, publishedVersion: { type: ` Int!` }, locale: { type: ` String!` }, }, From 798006b6dd3084c6e186ebd4890a893d7efa9228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 2 Feb 2024 11:32:37 +0100 Subject: [PATCH 146/149] chore: remove joi config for old and removed config option enableTags --- packages/gatsby-source-contentful/src/gatsby-node.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/gatsby-source-contentful/src/gatsby-node.ts b/packages/gatsby-source-contentful/src/gatsby-node.ts index de198c55a9466..e7e0f5c8428f8 100644 --- a/packages/gatsby-source-contentful/src/gatsby-node.ts +++ b/packages/gatsby-source-contentful/src/gatsby-node.ts @@ -170,11 +170,6 @@ For example, to exclude content types starting with "page" \`contentTypeFilter: .description( `Axios proxy configuration. See the [axios request config documentation](https://github.com/mzabriskie/axios#request-config) for further information about the supported values.` ), - enableTags: Joi.boolean() - .description( - `Enable the new tags feature. This will disallow the content type name "tags" till the next major version of this plugin.` - ) - .default(false), useNameForId: Joi.boolean() .description( `Use the content's \`name\` when generating the GraphQL schema e.g. a Content Type called \`[Component] Navigation bar\` will be named \`contentfulComponentNavigationBar\`. From aa63a1688110fcb861cbf0066f7546ffd6275d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Fri, 2 Feb 2024 11:57:57 +0100 Subject: [PATCH 147/149] feat: support required Contentful fields while giving CPA users an option to disable --- .../gatsby-source-contentful/MIGRATION.md | 25 +++++++++++++ packages/gatsby-source-contentful/README.md | 36 ++++++++++--------- .../src/__fixtures__/content-types.js | 8 ++--- .../create-schema-customization.js.snap | 14 +++++--- .../src/create-schema-customization.ts | 20 +++++++---- .../src/gatsby-node.ts | 5 +++ .../src/plugin-options.ts | 1 + 7 files changed, 77 insertions(+), 32 deletions(-) diff --git a/packages/gatsby-source-contentful/MIGRATION.md b/packages/gatsby-source-contentful/MIGRATION.md index 3ffcf583c1012..3e6b44c4b3a3b 100644 --- a/packages/gatsby-source-contentful/MIGRATION.md +++ b/packages/gatsby-source-contentful/MIGRATION.md @@ -26,6 +26,7 @@ The v9 release of `gatsby-source-contentful` brings significant improvements, fo - [5. Assets](#5-assets) - [Old GraphlQL schema for assets](#old-graphlql-schema-for-assets) - [New GraphlQL schema for assets](#new-graphlql-schema-for-assets) + - [6. Using the Contentful Preview API (CPA)](#6-using-the-contentful-preview-api-cpa) - [Conclusion and Support](#conclusion-and-support) @@ -403,6 +404,30 @@ type ContentfulAsset implements ContentfulInternalReference & Node @dontInfer { } ``` +### 6. Using the Contentful Preview API (CPA) + +In version 9, fields marked as required in Contentful are automatically treated as non-nullable in Gatsby's GraphQL schema. This aligns the GraphQL schema more closely with your Contentful content model, enhancing type safety and predictability in your Gatsby project. + +However, when using the Contentful Preview API (CPA), you might encounter scenarios where unpublished content doesn't yet fulfill all required fields. To accommodate this, `gatsby-source-contentful` introduces the `enforceRequiredFields` configuration option. + +- **Configuration**: By default, `enforceRequiredFields` is `true`, enforcing the non-nullability of required fields. To override this behavior, particularly in development or preview environments, set `enforceRequiredFields` to `false`: + +```javascript +// In your gatsby-config.js +{ + resolve: `gatsby-source-contentful`, + options: { + spaceId: process.env.CONTENTFUL_SPACE_ID, + accessToken: process.env.CONTENTFUL_ACCESS_TOKEN, + enforceRequiredFields: process.env.NODE_ENV !== 'production', // Example condition + }, +} +``` + +- **Environment Variables**: You can control this setting through environment variables, enabling non-nullable enforcement in production while disabling it in development or preview environments where you might be working with incomplete content. + +- **Impact on TypeScript**: For projects using TypeScript, changing the `enforceRequiredFields` setting will alter the generated types. With `enforceRequiredFields` set to `false`, fields that are required in Contentful but may be missing in the preview content will be nullable in the GraphQL schema. As a result, TypeScript users should ensure their code can handle potentially null values in these fields. + ## Conclusion and Support We understand that the changes introduced in `gatsby-source-contentful` v9 are significant. These updates were necessary to resolve architectural issues from the early stages of the plugin and to align it more closely with the evolving capabilities of Contentful and Gatsby. diff --git a/packages/gatsby-source-contentful/README.md b/packages/gatsby-source-contentful/README.md index e9e640dfa60fa..eaaaa34557445 100644 --- a/packages/gatsby-source-contentful/README.md +++ b/packages/gatsby-source-contentful/README.md @@ -362,23 +362,25 @@ For more in-depth exploration and advanced concepts, check out these valuable re Here's the revised table for the `gatsby-source-contentful` configuration options, including the suggested updates and corrections: -| Option | Type | Default Value | Description | -| ------------------------------------- | -------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `spaceId` | string | (required) | Your Contentful space ID. | -| `accessToken` | string | (required) | Access token for the Content Delivery API. Use the Preview API key for the Contentful Preview API. | -| `host` | string | `cdn.contentful.com` | Base host for API requests. Default is for the Delivery API; use `preview.contentful.com` for the Preview API. Custom hosts can be used for debugging/testing. | -| `environment` | string | `master` | The environment in Contentful to pull content from. [Guide](https://www.contentful.com/developers/docs/concepts/multiple-environments/) | -| `downloadLocal` | boolean | `false` | Downloads and caches `ContentfulAsset` to the local filesystem. Use `localFile` to access the local files. See [Download assets for static distribution](#download-assets-for-static-distribution) | -| `useNameForId` | boolean | `true` | Determines whether the content's `name` or internal ID is used for generating GraphQL schema types. Using `name` can make type names more readable but can be unstable if names change. Using the internal ID ensures stability as IDs are less likely to change, but may result in less readable types, especially when auto-generated. | -| `enableMarkdownDetection` (New in v9) | boolean | `true` | Assumes all long text fields in Contentful are markdown fields. Requires `gatsby-transformer-remark`. Can be a performance issue in large projects. Set to `false` and use `markdownFields` to specify markdown fields. | -| `markdownFields` (New in v9) | array | `[]` | Specify which fields contain markdown content. Effective only when `enableMarkdownDetection` is `false`. Format: array of pairs (content type ID and array of field IDs). Example: `[["product", ["description", "summary"]], ["otherContentTypeId", ["someMarkdownFieldId"]]]` | -| `contentTypePrefix` (Renamed in v9) | string | `ContentfulContentType` | Prefix for the generated GraphQL types. Formerly known as `typePrefix`. | -| `localeFilter` | function | `() => true` | Function to filter which locales/nodes are created in GraphQL, reducing memory usage by limiting nodes. | -| `contentTypeFilter` | function | `() => true` | Function to filter which contentType/nodes are created in GraphQL, reducing memory usage by limiting nodes. | -| `pageLimit` | number | `1000` | Number of entries to retrieve from Contentful at a time. Adjust if the payload size exceeds 7MB. | -| `assetDownloadWorkers` | number | `50` | Number of workers to use when downloading Contentful assets. Adjust to prevent stalled downloads due to too many concurrent requests. | -| `proxy` | object | (none) | Axios proxy configuration. See the [axios request config documentation](https://github.com/mzabriskie/axios#request-config) for further information about the supported values. | -| `contentfulClientConfig` | object | `{}` | Additional config passed to Contentful's JS SDK. Use with caution to avoid overriding plugin-set values. | +| Option | Type | Default Value | Description | +| ---------------------------------- | ------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `spaceId` | string | (required) | Your Contentful space ID. | +| `accessToken` | string | (required) | Access token for the Content Delivery API. Use the Preview API key for the Contentful Preview API. | +| `host` | string | `cdn.contentful.com` | Base host for API requests. Default is for the Delivery API; use `preview.contentful.com` for the Preview API. Custom hosts can be used for debugging/testing. | +| `environment` | string | `master` | The environment in Contentful to pull content from. [Guide](https://www.contentful.com/developers/docs/concepts/multiple-environments/) | +| `downloadLocal` | boolean | `false` | Downloads and caches `ContentfulAsset` to the local filesystem. Use `localFile` to access the local files. See [Download assets for static distribution](#download-assets-for-static-distribution) | +| `useNameForId` | boolean | `true` | Determines whether the content's `name` or internal ID is used for generating GraphQL schema types. Using `name` can make type names more readable but can be unstable if names change. Using the internal ID ensures stability as IDs are less likely to change, but may result in less readable types, especially when auto-generated. | +| `enforeRequiredFields` (New in v9) | boolean | `true` | Fields required in Contentful will also be required in Gatsby. If you are using Contentfuls Preview API (CPA), you may want to disable this conditionally. | + +| `enableMarkdownDetection` (New in v9) | boolean | `true` | Assumes all long text fields in Contentful are markdown fields. Requires `gatsby-transformer-remark`. Can be a performance issue in large projects. Set to `false` and use `markdownFields` to specify markdown fields. | +| `markdownFields` (New in v9) | array | `[]` | Specify which fields contain markdown content. Effective only when `enableMarkdownDetection` is `false`. Format: array of pairs (content type ID and array of field IDs). Example: `[["product", ["description", "summary"]], ["otherContentTypeId", ["someMarkdownFieldId"]]]` | +| `contentTypePrefix` (Renamed in v9) | string | `ContentfulContentType` | Prefix for the generated GraphQL types. Formerly known as `typePrefix`. | +| `localeFilter` | function | `() => true` | Function to filter which locales/nodes are created in GraphQL, reducing memory usage by limiting nodes. | +| `contentTypeFilter` | function | `() => true` | Function to filter which contentType/nodes are created in GraphQL, reducing memory usage by limiting nodes. | +| `pageLimit` | number | `1000` | Number of entries to retrieve from Contentful at a time. Adjust if the payload size exceeds 7MB. | +| `assetDownloadWorkers` | number | `50` | Number of workers to use when downloading Contentful assets. Adjust to prevent stalled downloads due to too many concurrent requests. | +| `proxy` | object | (none) | Axios proxy configuration. See the [axios request config documentation](https://github.com/mzabriskie/axios#request-config) for further information about the supported values. | +| `contentfulClientConfig` | object | `{}` | Additional config passed to Contentful's JS SDK. Use with caution to avoid overriding plugin-set values. | ### Offline Mode diff --git a/packages/gatsby-source-contentful/src/__fixtures__/content-types.js b/packages/gatsby-source-contentful/src/__fixtures__/content-types.js index d3e4a10105aa7..0687d22eb19a8 100644 --- a/packages/gatsby-source-contentful/src/__fixtures__/content-types.js +++ b/packages/gatsby-source-contentful/src/__fixtures__/content-types.js @@ -30,7 +30,7 @@ export const contentTypes = [ name: `Title`, type: `Symbol`, localized: false, - required: false, + required: true, disabled: false, omitted: false, }, @@ -103,7 +103,7 @@ export const contentTypes = [ name: `Title`, type: `Symbol`, localized: false, - required: false, + required: true, disabled: false, omitted: false, }, @@ -211,7 +211,7 @@ export const contentTypes = [ name: `Title`, type: `Symbol`, localized: false, - required: false, + required: true, disabled: false, omitted: false, }, @@ -424,7 +424,7 @@ export const contentTypes = [ name: `Title`, type: `Symbol`, localized: false, - required: false, + required: true, disabled: false, omitted: false, }, diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index d8dc2396e549f..ab797c737fa7f 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -46,6 +46,9 @@ Array [ "type": " String!", }, "firstPublishedAt": Object { + "extensions": Object { + "dateformat": Object {}, + }, "type": " Date!", }, "id": Object { @@ -55,6 +58,9 @@ Array [ "type": " String!", }, "publishedAt": Object { + "extensions": Object { + "dateformat": Object {}, + }, "type": " Date!", }, "publishedVersion": Object { @@ -428,7 +434,7 @@ Ignored if layout = FLUID.", "type": "ContentfulSys!", }, "title": Object { - "type": "String", + "type": "String!", }, }, "interfaces": Array [ @@ -495,7 +501,7 @@ Ignored if layout = FLUID.", "type": "ContentfulSys!", }, "title": Object { - "type": "String", + "type": "String!", }, }, "interfaces": Array [ @@ -559,7 +565,7 @@ Ignored if layout = FLUID.", "type": "ContentfulSys!", }, "title": Object { - "type": "String", + "type": "String!", }, }, "interfaces": Array [ @@ -679,7 +685,7 @@ Ignored if layout = FLUID.", "type": "ContentfulSys!", }, "title": Object { - "type": "String", + "type": "String!", }, }, "interfaces": Array [ diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index d0bea35a72d14..5a01ebeefa76b 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -22,7 +22,7 @@ import { resolveGatsbyImageData } from "./gatsby-plugin-image" import { makeTypeName } from "./normalize" import { ImageCropFocusType, ImageResizingBehavior } from "./schemes" import type { IPluginOptions, MarkdownFieldDefinition } from "./types/plugin" -import type { ContentType, ContentTypeField, FieldItem } from "contentful" +import type { ContentType, ContentTypeField } from "contentful" import type { IContentfulAsset, @@ -207,11 +207,12 @@ const getLinkFieldType = ( } // Translate Contentful field types to GraphQL field types const translateFieldType = ( - field: ContentTypeField | FieldItem, + field: ContentTypeField, contentTypeItem: ContentType, schema: NodePluginSchema, createTypes: CreateTypes, enableMarkdownDetection: boolean, + enforceRequiredFields: boolean, markdownFields: MarkdownFieldDefinition, contentTypeIdMap: Map ): GraphQLFieldConfig => { @@ -237,11 +238,12 @@ const translateFieldType = ( contentTypeIdMap ) : translateFieldType( - field.items, + field.items as ContentTypeField, contentTypeItem, schema, createTypes, enableMarkdownDetection, + enforceRequiredFields, markdownFields, contentTypeIdMap ) @@ -273,10 +275,10 @@ const translateFieldType = ( fieldType = primitiveType(field) } - // To support Contentful's CPA (Content Preview API), we have to allow empty required fields. - // if (field.required) { - // fieldType.type = `${fieldType.type}!` - // } + // To support Contentful's CPA (Content Preview API), required fields can be disabled by config. + if (enforceRequiredFields && field.required) { + fieldType.type = `${fieldType.type}!` + } return fieldType } @@ -333,6 +335,9 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] const enableMarkdownDetection: boolean = pluginConfig.get( `enableMarkdownDetection` ) + const enforceRequiredFields: boolean = pluginConfig.get( + `enforceRequiredFields` + ) const markdownFields: MarkdownFieldDefinition = new Map( pluginConfig.get(`markdownFields`) ) @@ -752,6 +757,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] schema, createTypes, enableMarkdownDetection, + enforceRequiredFields, markdownFields, contentTypeIdMap ) diff --git a/packages/gatsby-source-contentful/src/gatsby-node.ts b/packages/gatsby-source-contentful/src/gatsby-node.ts index e7e0f5c8428f8..462493bdee73b 100644 --- a/packages/gatsby-source-contentful/src/gatsby-node.ts +++ b/packages/gatsby-source-contentful/src/gatsby-node.ts @@ -170,6 +170,11 @@ For example, to exclude content types starting with "page" \`contentTypeFilter: .description( `Axios proxy configuration. See the [axios request config documentation](https://github.com/mzabriskie/axios#request-config) for further information about the supported values.` ), + enforceRequiredFields: Joi.boolean() + .description( + `Fields required in Contentful will also be required in Gatsby. If you are using Contentfuls Preview API (CPA), you may want to disable this conditionally.` + ) + .default(true), useNameForId: Joi.boolean() .description( `Use the content's \`name\` when generating the GraphQL schema e.g. a Content Type called \`[Component] Navigation bar\` will be named \`contentfulComponentNavigationBar\`. diff --git a/packages/gatsby-source-contentful/src/plugin-options.ts b/packages/gatsby-source-contentful/src/plugin-options.ts index d0555c25a428e..1e34dc781c1a8 100644 --- a/packages/gatsby-source-contentful/src/plugin-options.ts +++ b/packages/gatsby-source-contentful/src/plugin-options.ts @@ -16,6 +16,7 @@ const defaultOptions: Omit = { contentTypePrefix: `ContentfulContentType`, enableMarkdownDetection: true, markdownFields: [], + enforceRequiredFields: true, } /** From 2c364df8cc052b6ef040c787ff096b248f14aba4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Tue, 20 Feb 2024 17:27:02 +0100 Subject: [PATCH 148/149] feat: log to console from which CTF environment the data is loaded --- packages/gatsby-source-contentful/src/fetch.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/gatsby-source-contentful/src/fetch.ts b/packages/gatsby-source-contentful/src/fetch.ts index 42e1472026091..c68e7ad1e72f2 100644 --- a/packages/gatsby-source-contentful/src/fetch.ts +++ b/packages/gatsby-source-contentful/src/fetch.ts @@ -315,7 +315,10 @@ export async function fetchContent({ // Fetch entries and assets via Contentful CDA sync API const pageLimit = pluginConfig.get(`pageLimit`) || 100 - reporter.verbose(`Contentful: Sync ${pageLimit} items per page.`) + const ctfEnvironment = pluginConfig.get(`environment`) || `master` + reporter.verbose( + `Contentful: Sync ${pageLimit} items per page from environment ${ctfEnvironment}.` + ) const syncProgress = reporter.createProgress( `Contentful: ${syncToken ? `Sync changed items` : `Sync all items`}`, pageLimit, From 1ce2026978244e1cac81426732823ea73e868440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20R=C3=B6tsch?= Date: Thu, 29 Feb 2024 14:53:55 +0100 Subject: [PATCH 149/149] perf(gatsby): add a way to skip tracking inline objects (#38805) add new flag for nodes from external sources to prevent unnecessary data loops --------- Co-authored-by: Michal Piechowiak --- .circleci/config.yml | 2 +- .../create-schema-customization.js.snap | 3 ++ .../src/create-schema-customization.ts | 47 ++++++++++++++----- .../src/gatsby-node.ts | 12 +++++ .../gatsby-source-contentful/src/normalize.ts | 2 + .../gatsby-source-contentful/src/report.ts | 6 +++ packages/gatsby/index.d.ts | 4 ++ packages/gatsby/scripts/__tests__/api.js | 1 + packages/gatsby/scripts/output-api-file.js | 2 +- packages/gatsby/src/joi-schemas/joi.ts | 1 + .../__snapshots__/build-schema.js.snap | 4 ++ .../__snapshots__/rebuild-schema.js.snap | 4 ++ packages/gatsby/src/schema/node-model.js | 3 ++ .../gatsby/src/schema/types/node-interface.ts | 1 + 14 files changed, 78 insertions(+), 14 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b9d39a3f86996..320c3de5f3488 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -518,7 +518,7 @@ jobs: nvm install 18.0.0 nvm alias default 18.0.0 nvm use 18.0.0 - choco install yarn + choco install yarn -y - run: name: Rebuild packages for windows command: | diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap index ab797c737fa7f..95097fbf722d4 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/create-schema-customization.js.snap @@ -744,12 +744,15 @@ Ignored if layout = FLUID.", }, "linkedFrom": "ContentfulLinkedFrom", "richText": Object { + "resolve": [Function], "type": "ContentfulRichText", }, "richTextLocalized": Object { + "resolve": [Function], "type": "ContentfulRichText", }, "richTextValidated": Object { + "resolve": [Function], "type": "ContentfulRichText", }, "sys": Object { diff --git a/packages/gatsby-source-contentful/src/create-schema-customization.ts b/packages/gatsby-source-contentful/src/create-schema-customization.ts index 5a01ebeefa76b..f5343924629a6 100644 --- a/packages/gatsby-source-contentful/src/create-schema-customization.ts +++ b/packages/gatsby-source-contentful/src/create-schema-customization.ts @@ -2,6 +2,7 @@ import type { GatsbyNode, NodePluginSchema, CreateSchemaCustomizationArgs, + IGatsbyResolverContext, } from "gatsby" import { GraphQLFieldConfig, @@ -31,15 +32,29 @@ import type { } from "./types/contentful" import { detectMarkdownField, makeContentTypeIdMap } from "./utils" import { restrictedNodeFields } from "./config" +import { Document } from "@contentful/rich-text-types" type CreateTypes = CreateSchemaCustomizationArgs["actions"]["createTypes"] interface IContentfulGraphQLField - extends Omit>, "type"> { + extends Omit< + Partial< + GraphQLFieldConfig< + IContentfulEntry, + IGatsbyResolverContext + > + >, + "type" + > { type: string | GraphQLType id?: string } +interface IRichTextFieldStructure { + richTextData: Document + spaceId: string +} + // Contentful content type schemas const ContentfulDataTypes: Map< string, @@ -112,7 +127,18 @@ const ContentfulDataTypes: Map< [ `RichText`, (): IContentfulGraphQLField => { - return { type: `ContentfulRichText` } + return { + type: `ContentfulRichText`, + resolve: (source, args, context, info): IRichTextFieldStructure => { + const richTextData = context.defaultFieldResolver( + source, + args, + context, + info + ) + return { richTextData, spaceId: source.sys.spaceId } + }, + } }, ], ]) @@ -599,16 +625,13 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] const makeRichTextLinksResolver = (nodeType, entityType) => async ( - source, + source: IRichTextFieldStructure, _args, context ): Promise | null> => { - const links = getRichTextEntityLinks(source, nodeType)[entityType].map( - ({ id }) => id - ) - - const node = context.nodeModel.findRootNodeAncestor(source) - if (!node) return null + const links = getRichTextEntityLinks(source.richTextData, nodeType)[ + entityType + ].map(({ id }) => id) const res = await context.nodeModel.findAll({ query: { @@ -617,7 +640,7 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] id: { in: links, }, - spaceId: { eq: node.sys.spaceId }, + spaceId: { eq: source.spaceId }, }, }, }, @@ -693,8 +716,8 @@ export const createSchemaCustomization: GatsbyNode["createSchemaCustomization"] fields: { json: { type: `JSON`, - resolve(source) { - return source + resolve(source: IRichTextFieldStructure) { + return source.richTextData }, }, links: { diff --git a/packages/gatsby-source-contentful/src/gatsby-node.ts b/packages/gatsby-source-contentful/src/gatsby-node.ts index 462493bdee73b..f9d2ae97a2d45 100644 --- a/packages/gatsby-source-contentful/src/gatsby-node.ts +++ b/packages/gatsby-source-contentful/src/gatsby-node.ts @@ -2,6 +2,7 @@ import type { GatsbyNode } from "gatsby" import origFetch from "node-fetch" import fetchRetry from "@vercel/fetch-retry" import { polyfillImageServiceDevRoutes } from "gatsby-plugin-utils/polyfill-remote-file" +import { hasFeature } from "gatsby-plugin-utils/has-feature" import { CODES } from "./report" import { maskText } from "./plugin-options" @@ -47,6 +48,17 @@ export const onPreInit: GatsbyNode["onPreInit"] = async ( { store, reporter, actions }, pluginOptions ) => { + // gatsby version is too old + if (!hasFeature(`track-inline-object-opt-out`)) { + reporter.panic({ + id: CODES.GatsbyPluginMissing, + context: { + // TODO update message to reflect the actual version with track-inline-object-opt-out support + sourceMessage: `Used gatsby version is too old and doesn't support required features. Please update to gatsby@>=5.X.0`, + }, + }) + } + // if gatsby-plugin-image is not installed try { await import(`gatsby-plugin-image/graphql-utils.js`) diff --git a/packages/gatsby-source-contentful/src/normalize.ts b/packages/gatsby-source-contentful/src/normalize.ts index 45b7a29af6937..31c1eaf39f74e 100644 --- a/packages/gatsby-source-contentful/src/normalize.ts +++ b/packages/gatsby-source-contentful/src/normalize.ts @@ -788,6 +788,7 @@ export const createNodesForContentType = ({ type: makeTypeName(contentTypeItemId, contentTypePrefix), // The content of an entry is guaranteed to be updated if and only if the .sys.updatedAt field changed contentDigest: entryItem.sys.updatedAt as string, + trackInlineObjects: false, }, // 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 @@ -944,6 +945,7 @@ export const createAssetNodes = async ({ type: `ContentfulAsset`, // The content of an asset is guaranteed to be updated if and only if the .sys.updatedAt field changed contentDigest: assetItem.sys.updatedAt, + trackInlineObjects: false, }, // 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 diff --git a/packages/gatsby-source-contentful/src/report.ts b/packages/gatsby-source-contentful/src/report.ts index 1de95e68dde21..dbd796ae78c3e 100644 --- a/packages/gatsby-source-contentful/src/report.ts +++ b/packages/gatsby-source-contentful/src/report.ts @@ -10,6 +10,7 @@ export const CODES = { ContentTypesMissing: `111006`, FetchTags: `111007`, GenericContentfulError: `111008`, + GatsbyTooOld: `111009`, } interface IErrorMap { @@ -57,4 +58,9 @@ export const ERROR_MAP: IErrorMap = { level: `ERROR`, category: `THIRD_PARTY`, }, + [CODES.GatsbyTooOld]: { + text: context => context.sourceMessage, + level: `ERROR`, + category: `USER`, + }, } diff --git a/packages/gatsby/index.d.ts b/packages/gatsby/index.d.ts index ca252cbf48bc9..7e33201c4c329 100644 --- a/packages/gatsby/index.d.ts +++ b/packages/gatsby/index.d.ts @@ -23,6 +23,7 @@ export type AvailableFeatures = | "content-file-path" | "stateful-source-nodes" | "adapters" + | "track-inline-object-opt-out" export { Link, @@ -34,6 +35,8 @@ export { export * from "gatsby-script" +export { IGatsbyResolverContext } from "./dist/schema/type-definitions" + export { AdapterInit, IAdapter, @@ -1777,6 +1780,7 @@ export interface NodeInput { contentDigest: string description?: string contentFilePath?: string + trackInlineObjects?: boolean } [key: string]: unknown } diff --git a/packages/gatsby/scripts/__tests__/api.js b/packages/gatsby/scripts/__tests__/api.js index dc1c6ce7ca41e..665dd8db02cb0 100644 --- a/packages/gatsby/scripts/__tests__/api.js +++ b/packages/gatsby/scripts/__tests__/api.js @@ -37,6 +37,7 @@ it("generates the expected api output", done => { "slices", "stateful-source-nodes", "adapters", + "track-inline-object-opt-out", ], "node": Object { "createPages": Object {}, diff --git a/packages/gatsby/scripts/output-api-file.js b/packages/gatsby/scripts/output-api-file.js index 8f3cf1b5f7c32..826a04429c123 100644 --- a/packages/gatsby/scripts/output-api-file.js +++ b/packages/gatsby/scripts/output-api-file.js @@ -41,7 +41,7 @@ async function outputFile() { }, {}) /** @type {Array} */ - output.features = ["image-cdn", "graphql-typegen", "content-file-path", "slices", "stateful-source-nodes", "adapters"]; + output.features = ["image-cdn", "graphql-typegen", "content-file-path", "slices", "stateful-source-nodes", "adapters", "track-inline-object-opt-out"]; return fs.writeFile( path.resolve(OUTPUT_FILE_NAME), diff --git a/packages/gatsby/src/joi-schemas/joi.ts b/packages/gatsby/src/joi-schemas/joi.ts index cb5402fd55295..352e31ee49899 100644 --- a/packages/gatsby/src/joi-schemas/joi.ts +++ b/packages/gatsby/src/joi-schemas/joi.ts @@ -177,6 +177,7 @@ export const nodeSchema: Joi.ObjectSchema = Joi.object() ignoreType: Joi.boolean(), counter: Joi.number(), contentFilePath: Joi.string(), + trackInlineObjects: Joi.boolean(), }) .unknown(false), // Don't allow non-standard fields }) diff --git a/packages/gatsby/src/schema/__tests__/__snapshots__/build-schema.js.snap b/packages/gatsby/src/schema/__tests__/__snapshots__/build-schema.js.snap index afeb90d39d48f..1cbf2b5b40dcd 100644 --- a/packages/gatsby/src/schema/__tests__/__snapshots__/build-schema.js.snap +++ b/packages/gatsby/src/schema/__tests__/__snapshots__/build-schema.js.snap @@ -2016,6 +2016,7 @@ type Internal { owner: String! type: String! contentFilePath: String + trackInlineObjects: Boolean } \\"\\"\\" @@ -2356,6 +2357,7 @@ input InternalFilterInput { owner: StringQueryOperatorInput type: StringQueryOperatorInput contentFilePath: StringQueryOperatorInput + trackInlineObjects: BooleanQueryOperatorInput } input BooleanQueryOperatorInput { @@ -2452,6 +2454,7 @@ input InternalFieldSelector { owner: FieldSelectorEnum type: FieldSelectorEnum contentFilePath: FieldSelectorEnum + trackInlineObjects: FieldSelectorEnum } type FileGroupConnection { @@ -2566,6 +2569,7 @@ input InternalSortInput { owner: SortOrderEnum type: SortOrderEnum contentFilePath: SortOrderEnum + trackInlineObjects: SortOrderEnum } type DirectoryConnection { diff --git a/packages/gatsby/src/schema/__tests__/__snapshots__/rebuild-schema.js.snap b/packages/gatsby/src/schema/__tests__/__snapshots__/rebuild-schema.js.snap index e8ca70911a884..a59ab4f0debc2 100644 --- a/packages/gatsby/src/schema/__tests__/__snapshots__/rebuild-schema.js.snap +++ b/packages/gatsby/src/schema/__tests__/__snapshots__/rebuild-schema.js.snap @@ -215,6 +215,7 @@ type Internal { owner: String! type: String! contentFilePath: String + trackInlineObjects: Boolean } \\"\\"\\" @@ -555,6 +556,7 @@ input InternalFilterInput { owner: StringQueryOperatorInput type: StringQueryOperatorInput contentFilePath: StringQueryOperatorInput + trackInlineObjects: BooleanQueryOperatorInput } input BooleanQueryOperatorInput { @@ -651,6 +653,7 @@ input InternalFieldSelector { owner: FieldSelectorEnum type: FieldSelectorEnum contentFilePath: FieldSelectorEnum + trackInlineObjects: FieldSelectorEnum } type FileGroupConnection { @@ -765,6 +768,7 @@ input InternalSortInput { owner: SortOrderEnum type: SortOrderEnum contentFilePath: SortOrderEnum + trackInlineObjects: SortOrderEnum } type DirectoryConnection { diff --git a/packages/gatsby/src/schema/node-model.js b/packages/gatsby/src/schema/node-model.js index b7e5824745a03..649137161b74d 100644 --- a/packages/gatsby/src/schema/node-model.js +++ b/packages/gatsby/src/schema/node-model.js @@ -498,6 +498,9 @@ class LocalNodeModel { * @param {Node} node Root Node */ trackInlineObjectsInRootNode(node) { + if (node.internal.trackInlineObjects === false) { + return + } if (!this._trackedRootNodes.has(node)) { addRootNodeToInlineObject( this._rootNodeMap, diff --git a/packages/gatsby/src/schema/types/node-interface.ts b/packages/gatsby/src/schema/types/node-interface.ts index 5769947f3381e..4f5f6019a2b99 100644 --- a/packages/gatsby/src/schema/types/node-interface.ts +++ b/packages/gatsby/src/schema/types/node-interface.ts @@ -27,6 +27,7 @@ const getOrCreateNodeInterface = ( owner: `String!`, type: `String!`, contentFilePath: `String`, + trackInlineObjects: `Boolean`, }) // TODO: Can be removed with graphql-compose 5.11 tc.getInputTypeComposer()