Skip to content

Commit

Permalink
feat: add support for external references (#2294)
Browse files Browse the repository at this point in the history
  • Loading branch information
veu authored Jul 31, 2024
1 parent cd70f15 commit 2b09a9b
Show file tree
Hide file tree
Showing 7 changed files with 336 additions and 16 deletions.
19 changes: 14 additions & 5 deletions lib/types/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,17 @@ export declare namespace EntryFieldTypes {
type: 'EntryResourceLink'
entry: EntrySkeleton
}
type ExternalResourceLink = {
type: 'ExternalResourceLink'
}
type AssetLink = { type: 'AssetLink' }
type Array<
Item extends
| EntryFieldTypes.Symbol
| EntryFieldTypes.AssetLink
| EntryFieldTypes.EntryLink<EntrySkeletonType>
| EntryFieldTypes.EntryResourceLink<EntrySkeletonType>,
| EntryFieldTypes.EntryResourceLink<EntrySkeletonType>
| EntryFieldTypes.ExternalResourceLink,
> = { type: 'Array'; item: Item }
type Object<Data extends JsonObject | JsonArray | null = JsonObject | JsonArray | null> = {
type: 'Object'
Expand Down Expand Up @@ -97,11 +101,14 @@ export type EntryFieldType<EntrySkeleton extends EntrySkeletonType> =
| EntryFieldTypes.Object
| EntryFieldTypes.EntryLink<EntrySkeleton>
| EntryFieldTypes.EntryResourceLink<EntrySkeleton>
| EntryFieldTypes.ExternalResourceLink
| EntryFieldTypes.AssetLink
| EntryFieldTypes.Array<EntryFieldTypes.Symbol>
| EntryFieldTypes.Array<EntryFieldTypes.AssetLink>
| EntryFieldTypes.Array<EntryFieldTypes.EntryLink<EntrySkeleton>>
| EntryFieldTypes.Array<EntryFieldTypes.EntryResourceLink<EntrySkeleton>>
| EntryFieldTypes.Array<
EntryFieldTypes.EntryResourceLink<EntrySkeleton> | EntryFieldTypes.ExternalResourceLink
>

/**
* All possible values for entry field types
Expand Down Expand Up @@ -243,9 +250,11 @@ export type ResolvedLink<
? ResolvedEntryLink<Modifiers, Locales, LinkedEntry>
: Field extends EntryFieldTypes.EntryResourceLink<infer LinkedEntry>
? ResolvedEntryResourceLink<Modifiers, Locales, LinkedEntry>
: Field extends EntryFieldTypes.AssetLink
? ResolvedAssetLink<Modifiers, Locales>
: BaseFieldMap<Field>
: Field extends EntryFieldTypes.ExternalResourceLink
? { sys: ResourceLink<string> }
: Field extends EntryFieldTypes.AssetLink
? ResolvedAssetLink<Modifiers, Locales>
: BaseFieldMap<Field>

/**
* A collection or single resolved link to another resource
Expand Down
4 changes: 2 additions & 2 deletions lib/types/resource-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
* Definition of an external resource link
* @category Link
*/
export interface ResourceLink {
export interface ResourceLink<LinkType extends string = 'Contentful:Entry'> {
type: 'ResourceLink'
linkType: 'Contentful:Entry'
linkType: LinkType
urn: string
}
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"@contentful/content-source-maps": "^0.6.0",
"@contentful/rich-text-types": "^16.0.2",
"axios": "~1.6.8",
"contentful-resolve-response": "^1.8.1",
"contentful-resolve-response": "^1.9.0",
"contentful-sdk-core": "^8.1.0",
"json-stringify-safe": "^5.0.1",
"type-fest": "^4.0.0"
Expand Down
89 changes: 88 additions & 1 deletion test/integration/parseEntries.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ interface TypeCatFields {
likes?: EntryFieldTypes.Array<EntryFieldTypes.Symbol>
color?: EntryFieldTypes.Symbol
bestFriend?: EntryFieldTypes.EntryLink<EntrySkeletonType>
otherFriends?: EntryFieldTypes.Array<
EntryFieldTypes.EntryResourceLink<EntrySkeletonType> | EntryFieldTypes.ExternalResourceLink
>
birthday?: EntryFieldTypes.Date
lifes?: EntryFieldTypes.Integer
lives?: EntryFieldTypes.Integer
Expand Down Expand Up @@ -58,6 +61,7 @@ const resolvedHappyCatEntry = {
likes: ['cheezburger'],
color: 'gray',
bestFriend: { sys: { type: 'Link', linkType: 'Entry', id: 'nyancat' } },
otherFriends: [],
birthday: '2003-10-28T23:00:00+00:00',
lives: 1,
image: { sys: { type: 'Link', linkType: 'Asset', id: 'happycat' } },
Expand Down Expand Up @@ -94,6 +98,9 @@ const resolvedHappyCatEntryAllLocales = {
bestFriend: {
'en-US': { sys: { type: 'Link', linkType: 'Entry', id: 'nyancat' } },
},
otherFriends: {
'en-US': [],
},
birthday: {
'en-US': '2003-10-28T23:00:00+00:00',
},
Expand Down Expand Up @@ -250,6 +257,22 @@ beforeEach(() => {
likes: ['rainbows', 'fish'],
color: 'rainbow',
bestFriend: { sys: { type: 'Link', linkType: 'Entry', id: 'happycat' } },
otherFriends: [
{
sys: {
type: 'ResourceLink',
linkType: 'Contentful:Entry',
urn: 'crn:contentful:::content:spaces/ezs1swce23xe/entries/happycat',
},
},
{
sys: {
type: 'ResourceLink',
linkType: 'AnotherProvider:SomeResourceType',
urn: 'external-id',
},
},
],
birthday: '2011-04-04T22:00:00Z',
lives: 1337,
image: { sys: { type: 'Link', linkType: 'Asset', id: 'nyancat' } },
Expand Down Expand Up @@ -303,6 +326,24 @@ beforeEach(() => {
},
},
},
otherFriends: {
'en-US': [
{
sys: {
type: 'ResourceLink',
linkType: 'Contentful:Entry',
urn: 'crn:contentful:::content:spaces/ezs1swce23xe/entries/happycat',
},
},
{
sys: {
type: 'ResourceLink',
linkType: 'AnotherProvider:SomeResourceType',
urn: 'external-id',
},
},
],
},
birthday: {
'en-US': '2020-07-02T00:00:00Z',
},
Expand Down Expand Up @@ -353,6 +394,22 @@ beforeEach(() => {
id: '6SiPbntBPYYjnVHmipxJBF',
},
},
otherFriends: [
{
sys: {
type: 'ResourceLink',
linkType: 'Contentful:Entry',
urn: 'crn:contentful:::content:spaces/ezs1swce23xe/entries/happycat',
},
},
{
sys: {
type: 'ResourceLink',
linkType: 'AnotherProvider:SomeResourceType',
urn: 'external-id',
},
},
],
birthday: '2020-07-02T00:00:00Z',
lives: 9,
image: { sys: { type: 'Link', linkType: 'Asset', id: 'happycat' } },
Expand Down Expand Up @@ -411,6 +468,24 @@ beforeEach(() => {
},
},
},
otherFriends: {
'en-US': [
{
sys: {
type: 'ResourceLink',
linkType: 'Contentful:Entry',
urn: 'crn:contentful:::content:spaces/ezs1swce23xe/entries/happycat',
},
},
{
sys: {
type: 'ResourceLink',
linkType: 'AnotherProvider:SomeResourceType',
urn: 'external-id',
},
},
],
},
birthday: {
'en-US': '2020-07-02T00:00:00Z',
},
Expand Down Expand Up @@ -442,6 +517,8 @@ describe('parseEntries via client chain modifiers', () => {

expect(response.items[0].fields).toBeDefined()
expect(response.items[0].fields.bestFriend?.sys.type).toBe('Entry')
expect(response.items[0].fields.otherFriends?.[0]?.sys.type).toBe('Entry')
expect(response.items[0].fields.otherFriends?.[1]?.sys.type).toBe('ResourceLink')
expect(response.items[0].fields.color).toBe('rainbow')
expect(response.items[0].fields.color?.['en-US']).not.toBeDefined()
})
Expand All @@ -453,6 +530,8 @@ describe('parseEntries via client chain modifiers', () => {

expect(response.items[0].fields).toBeDefined()
expect(response.items[0].fields.bestFriend).toBeUndefined()
expect(response.items[0].fields.otherFriends).toHaveLength(1)
expect(response.items[0].fields.otherFriends?.[0]?.sys.type).toBe('ResourceLink')
})
})

Expand All @@ -463,7 +542,9 @@ describe('parseEntries via client chain modifiers', () => {
expect(response.items[0].fields).toBeDefined()
expect(response.items[0].fields.name).toHaveProperty('en-US')
expect(response.items[0].fields.name).toHaveProperty('tlh')
expect(response.items[0].fields.bestFriend?.['en-US']?.sys.type).not.toBe('Link')
expect(response.items[0].fields.bestFriend?.['en-US']?.sys.type).toBe('Entry')
expect(response.items[0].fields.otherFriends?.['en-US']?.[0]?.sys.type).toBe('Entry')
expect(response.items[0].fields.otherFriends?.['en-US']?.[1]?.sys.type).toBe('ResourceLink')
})

test('client.withAllLocales.withoutLinkResolution', () => {
Expand All @@ -474,6 +555,8 @@ describe('parseEntries via client chain modifiers', () => {
expect(response.items[0].fields.name).toHaveProperty('en-US')
expect(response.items[0].fields.name).toHaveProperty('tlh')
expect(response.items[0].fields.bestFriend?.['en-US']?.sys.type).toBe('Link')
expect(response.items[0].fields.otherFriends?.['en-US']?.[0]?.sys.type).toBe('ResourceLink')
expect(response.items[0].fields.otherFriends?.['en-US']?.[1]?.sys.type).toBe('ResourceLink')
})

test('client.withAllLocales.withoutUnresolvableLinks', () => {
Expand All @@ -486,6 +569,8 @@ describe('parseEntries via client chain modifiers', () => {
expect(response.items[0].fields.name).toHaveProperty('tlh')
expect(response.items[0].fields.color).toHaveProperty('en-US')
expect(response.items[0].fields.bestFriend).toEqual({})
expect(response.items[0].fields.otherFriends?.['en-US']).toHaveLength(1)
expect(response.items[0].fields.otherFriends?.['en-US']?.[0]?.sys.type).toBe('ResourceLink')
})
})

Expand All @@ -495,6 +580,8 @@ describe('parseEntries via client chain modifiers', () => {

expect(response.items[0].fields).toBeDefined()
expect(response.items[0].fields.bestFriend?.sys.type).toBe('Link')
expect(response.items[0].fields.otherFriends?.[0]?.sys.type).toBe('ResourceLink')
expect(response.items[0].fields.otherFriends?.[1]?.sys.type).toBe('ResourceLink')
})
})
})
7 changes: 7 additions & 0 deletions test/types/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ export const entryResourceLink: { sys: ResourceLink } = {
urn: stringValue,
},
}
export const externalResourceLink: { sys: ResourceLink<string> } = {
sys: {
type: 'ResourceLink',
linkType: 'Provider1:ResourceTypeA',
urn: stringValue,
},
}

export const entrySys: EntrySys = {
contentType: { sys: { id: stringValue, type: 'Link', linkType: 'ContentType' } },
Expand Down
Loading

0 comments on commit 2b09a9b

Please sign in to comment.