@financial-times/cp-content-pipeline-schema 2.15.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/lib/datasources/capi.d.ts +2 -2
  3. package/lib/datasources/capi.js +4 -2
  4. package/lib/datasources/capi.js.map +1 -1
  5. package/lib/datasources/capi.test.js +2 -2
  6. package/lib/fixtures/capiObject.d.ts +2 -2
  7. package/lib/fixtures/capiObject.js +2 -0
  8. package/lib/fixtures/capiObject.js.map +1 -1
  9. package/lib/fixtures/capiPerson.d.ts +1 -1
  10. package/lib/generated/index.d.ts +296 -131
  11. package/lib/helpers/decorateHeadshotUrl.d.ts +1 -2
  12. package/lib/helpers/decorateHeadshotUrl.js +2 -3
  13. package/lib/helpers/decorateHeadshotUrl.js.map +1 -1
  14. package/lib/model/Byline.d.ts +8 -10
  15. package/lib/model/Byline.js +34 -33
  16. package/lib/model/Byline.js.map +1 -1
  17. package/lib/model/Byline.test.js +105 -52
  18. package/lib/model/Byline.test.js.map +1 -1
  19. package/lib/model/CapiResponse.d.ts +12 -16
  20. package/lib/model/CapiResponse.js +38 -41
  21. package/lib/model/CapiResponse.js.map +1 -1
  22. package/lib/model/CapiResponse.test.js +7 -18
  23. package/lib/model/CapiResponse.test.js.map +1 -1
  24. package/lib/model/Clip.d.ts +1 -1
  25. package/lib/model/Concept.d.ts +1 -1
  26. package/lib/model/Concept.js +1 -2
  27. package/lib/model/Concept.js.map +1 -1
  28. package/lib/model/FlourishSource.d.ts +1 -1
  29. package/lib/model/FlourishSource.js.map +1 -1
  30. package/lib/model/Image.d.ts +1 -1
  31. package/lib/model/LeadFlourish.test.js +1 -0
  32. package/lib/model/LeadFlourish.test.js.map +1 -1
  33. package/lib/model/Person.d.ts +6 -12
  34. package/lib/model/Person.js +39 -66
  35. package/lib/model/Person.js.map +1 -1
  36. package/lib/model/Person.test.js +7 -60
  37. package/lib/model/Person.test.js.map +1 -1
  38. package/lib/model/Picture.d.ts +1 -1
  39. package/lib/model/RichText.d.ts +1 -2
  40. package/lib/model/Topper.d.ts +1 -1
  41. package/lib/model/Topper.js +10 -8
  42. package/lib/model/Topper.js.map +1 -1
  43. package/lib/model/Topper.test.js +9 -10
  44. package/lib/model/Topper.test.js.map +1 -1
  45. package/lib/model/schemas/capi/article.d.ts +7 -4
  46. package/lib/model/schemas/capi/article.js +1 -0
  47. package/lib/model/schemas/capi/article.js.map +1 -1
  48. package/lib/model/schemas/capi/audio.d.ts +7 -4
  49. package/lib/model/schemas/capi/audio.js +1 -0
  50. package/lib/model/schemas/capi/audio.js.map +1 -1
  51. package/lib/model/schemas/capi/base-schema.d.ts +14 -123
  52. package/lib/model/schemas/capi/base-schema.js +7 -6
  53. package/lib/model/schemas/capi/base-schema.js.map +1 -1
  54. package/lib/model/schemas/capi/content-package.d.ts +10 -5
  55. package/lib/model/schemas/capi/content-package.js +2 -0
  56. package/lib/model/schemas/capi/content-package.js.map +1 -1
  57. package/lib/model/schemas/capi/index.d.ts +41 -22
  58. package/lib/model/schemas/capi/internal-content.d.ts +24 -0
  59. package/lib/model/schemas/capi/internal-content.js +3 -0
  60. package/lib/model/schemas/capi/internal-content.js.map +1 -0
  61. package/lib/model/schemas/capi/live-blog-package.d.ts +7 -4
  62. package/lib/model/schemas/capi/live-blog-package.js +1 -0
  63. package/lib/model/schemas/capi/live-blog-package.js.map +1 -1
  64. package/lib/model/schemas/capi/placeholder.d.ts +7 -4
  65. package/lib/model/schemas/capi/placeholder.js +1 -0
  66. package/lib/model/schemas/capi/placeholder.js.map +1 -1
  67. package/lib/model/schemas/capi/video.d.ts +10 -5
  68. package/lib/model/schemas/capi/video.js +2 -0
  69. package/lib/model/schemas/capi/video.js.map +1 -1
  70. package/lib/resolvers/concept.d.ts +37 -2
  71. package/lib/resolvers/concept.js +17 -10
  72. package/lib/resolvers/concept.js.map +1 -1
  73. package/lib/resolvers/content-tree/Workarounds.d.ts +19 -11
  74. package/lib/resolvers/content-tree/references/Author.d.ts +4 -0
  75. package/lib/resolvers/content-tree/references/Author.js +14 -0
  76. package/lib/resolvers/content-tree/references/Author.js.map +1 -0
  77. package/lib/resolvers/content-tree/references/ClipSet.d.ts +1 -1
  78. package/lib/resolvers/content-tree/references/ClipSet.js +1 -1
  79. package/lib/resolvers/content-tree/references/ClipSet.js.map +1 -1
  80. package/lib/resolvers/content-tree/references/Flourish.d.ts +1 -1
  81. package/lib/resolvers/content-tree/references/Reference.d.ts +1 -1
  82. package/lib/resolvers/content-tree/references/index.d.ts +4 -2
  83. package/lib/resolvers/content-tree/references/index.js +4 -1
  84. package/lib/resolvers/content-tree/references/index.js.map +1 -1
  85. package/lib/resolvers/content-tree/updateTreeWithReferenceIds.d.ts +3 -3
  86. package/lib/resolvers/content-tree/updateTreeWithReferenceIds.js +2 -3
  87. package/lib/resolvers/content-tree/updateTreeWithReferenceIds.js.map +1 -1
  88. package/lib/resolvers/content.d.ts +27 -18
  89. package/lib/resolvers/content.js +4 -2
  90. package/lib/resolvers/content.js.map +1 -1
  91. package/lib/resolvers/image.d.ts +12 -12
  92. package/lib/resolvers/index.d.ts +89 -42
  93. package/lib/resolvers/leadFlourish.d.ts +2 -1
  94. package/lib/resolvers/leadFlourish.js +1 -0
  95. package/lib/resolvers/leadFlourish.js.map +1 -1
  96. package/lib/resolvers/person.d.ts +1 -1
  97. package/lib/resolvers/person.js +1 -1
  98. package/lib/resolvers/person.js.map +1 -1
  99. package/lib/resolvers/picture.d.ts +4 -4
  100. package/lib/resolvers/richText.d.ts +1 -1
  101. package/lib/resolvers/teaser.d.ts +1 -1
  102. package/lib/resolvers/topper.d.ts +3 -3
  103. package/package.json +1 -1
  104. package/queries/article.graphql +35 -13
  105. package/src/datasources/capi.test.ts +3 -3
  106. package/src/datasources/capi.ts +5 -3
  107. package/src/fixtures/capiObject.ts +4 -2
  108. package/src/fixtures/capiPerson.ts +1 -1
  109. package/src/generated/index.ts +321 -132
  110. package/src/helpers/decorateHeadshotUrl.ts +2 -2
  111. package/src/model/Byline.test.ts +136 -55
  112. package/src/model/Byline.ts +49 -39
  113. package/src/model/CapiResponse.test.ts +9 -25
  114. package/src/model/CapiResponse.ts +83 -56
  115. package/src/model/Clip.ts +1 -1
  116. package/src/model/Concept.ts +3 -3
  117. package/src/model/FlourishSource.ts +1 -1
  118. package/src/model/Image.test.ts +1 -1
  119. package/src/model/Image.ts +1 -1
  120. package/src/model/LeadFlourish.test.ts +1 -0
  121. package/src/model/Person.test.ts +11 -62
  122. package/src/model/Person.ts +47 -51
  123. package/src/model/Picture.test.ts +1 -1
  124. package/src/model/Picture.ts +1 -1
  125. package/src/model/Topper.test.ts +22 -18
  126. package/src/model/Topper.ts +10 -9
  127. package/src/model/__snapshots__/Byline.test.ts.snap +166 -27
  128. package/src/model/schemas/capi/article.ts +1 -0
  129. package/src/model/schemas/capi/audio.ts +1 -0
  130. package/src/model/schemas/capi/base-schema.ts +5 -4
  131. package/src/model/schemas/capi/content-package.ts +2 -0
  132. package/src/model/schemas/capi/internal-content.ts +45 -0
  133. package/src/model/schemas/capi/live-blog-package.ts +1 -0
  134. package/src/model/schemas/capi/placeholder.ts +1 -0
  135. package/src/model/schemas/capi/video.ts +2 -0
  136. package/src/resolvers/concept.ts +29 -12
  137. package/src/resolvers/content-tree/Workarounds.ts +39 -20
  138. package/src/resolvers/content-tree/references/Author.ts +18 -0
  139. package/src/resolvers/content-tree/references/ClipSet.ts +6 -8
  140. package/src/resolvers/content-tree/references/ImageSet.ts +1 -1
  141. package/src/resolvers/content-tree/references/ScrollyImage.ts +1 -1
  142. package/src/resolvers/content-tree/references/index.ts +6 -1
  143. package/src/resolvers/content-tree/updateTreeWithReferenceIds.ts +6 -8
  144. package/src/resolvers/content.ts +4 -2
  145. package/src/resolvers/leadFlourish.ts +1 -0
  146. package/src/resolvers/person.ts +1 -1
  147. package/src/types/n-display-metadata.d.ts +1 -1
  148. package/tsconfig.tsbuildinfo +1 -1
  149. package/typedefs/clip.graphql +2 -2
  150. package/typedefs/concept.graphql +64 -2
  151. package/typedefs/content.graphql +63 -39
  152. package/typedefs/image.graphql +12 -12
  153. package/typedefs/leadFlourish.graphql +32 -0
  154. package/typedefs/person.graphql +2 -2
  155. package/typedefs/picture.graphql +6 -6
  156. package/typedefs/references/author.graphql +7 -0
  157. package/typedefs/references/clipSet.graphql +14 -2
  158. package/typedefs/references/tweet.graphql +1 -1
  159. package/typedefs/teaser.graphql +10 -10
  160. package/src/types/internal-content.d.ts +0 -55
  161. package/typedefs/leadFlouish.graphql +0 -29
@@ -6,14 +6,15 @@ This file contains type definitions for any node that are either specific to Cus
6
6
  or have yet to be modelled in the `content-tree` spec.
7
7
  */
8
8
 
9
- /*
10
- Bylines / Author links are not part of the body of an article, and so
11
- have not been modelled yet.
12
- */
13
- export interface AuthorLink extends ContentTree.Parent {
14
- type: 'author-link'
15
- href: string
16
- children: ContentTree.Text[]
9
+ export interface Byline extends ContentTree.Parent {
10
+ type: 'byline'
11
+ children: (ContentTree.Text | Author)[]
12
+ }
13
+
14
+ export interface Author extends ContentTree.Parent {
15
+ type: 'author'
16
+ id: string
17
+ children: [ContentTree.Text]
17
18
  }
18
19
 
19
20
  export interface Cite extends ContentTree.Node {
@@ -45,7 +46,7 @@ export interface RawImage extends ContentTree.Node {
45
46
  width?: number
46
47
  }
47
48
 
48
- export interface ContentTreePullquote extends ContentTree.Pullquote {
49
+ export interface Pullquote extends ContentTree.Pullquote {
49
50
  children: ContentTree.ImageSet[]
50
51
  }
51
52
 
@@ -70,14 +71,10 @@ export type MainImageRaw = Omit<RawImage, 'type'> & {
70
71
  export interface Video extends ContentTree.Node {
71
72
  type: 'video'
72
73
  id: string
74
+ title?: string
73
75
  embedded: boolean
74
76
  }
75
77
 
76
- export interface YoutubeVideo extends ContentTree.Node {
77
- type: 'youtube-video'
78
- url: string
79
- }
80
-
81
78
  export interface OldClip extends ContentTree.Node {
82
79
  type: 'clip'
83
80
  url: string
@@ -167,6 +164,27 @@ export interface Body extends ContentTree.Parent {
167
164
  children: BodyBlock[]
168
165
  }
169
166
 
167
+ export type Image = Omit<ContentTree.Image, 'format'> & {
168
+ format:
169
+ | 'standard'
170
+ | 'standard-inline'
171
+ | 'desktop'
172
+ | 'mobile'
173
+ | 'wide'
174
+ | 'square'
175
+ | 'square-ftedit'
176
+ | 'portrait'
177
+ | 'landscape'
178
+ }
179
+
180
+ export type Flourish = Omit<
181
+ ContentTree.Flourish,
182
+ 'layoutWidth' | 'fallbackImage'
183
+ > & {
184
+ layoutWidth?: string
185
+ fallbackImage?: Image
186
+ }
187
+
170
188
  export type BodyBlock =
171
189
  | ContentTree.Paragraph
172
190
  | ContentTree.Heading
@@ -176,14 +194,14 @@ export type BodyBlock =
176
194
  | ContentTree.Layout
177
195
  | ContentTree.List
178
196
  | ContentTree.Blockquote
179
- | ContentTree.Pullquote
197
+ | Pullquote
180
198
  | ContentTree.ScrollyBlock
181
199
  | ContentTree.ThematicBreak
182
200
  | Table
183
201
  | Recommended
184
202
  | ContentTree.Tweet
185
203
  | Video
186
- | YoutubeVideo
204
+ | ContentTree.YoutubeVideo
187
205
 
188
206
  export type AnyNode =
189
207
  | ContentTree.Text
@@ -198,7 +216,7 @@ export type AnyNode =
198
216
  | ContentTree.List
199
217
  | ContentTree.ListItem
200
218
  | ContentTree.Blockquote
201
- | ContentTree.Pullquote
219
+ | Pullquote
202
220
  | ContentTree.ImageSet
203
221
  | ContentTree.CustomCodeComponent
204
222
  | ContentTree.Root
@@ -207,7 +225,7 @@ export type AnyNode =
207
225
  | OldClip
208
226
  | Recommended
209
227
  | ContentTree.Tweet
210
- | ContentTree.Flourish
228
+ | Flourish
211
229
  | ContentTree.BigNumber
212
230
  | ContentTree.ScrollyBlock
213
231
  | ContentTree.ScrollySection
@@ -224,9 +242,10 @@ export type AnyNode =
224
242
  | TableRow
225
243
  | TableCell
226
244
  | Video
227
- | YoutubeVideo
245
+ | ContentTree.YoutubeVideo
228
246
  | MainImage
229
247
  | MainImageRaw
230
248
  | RawImage
231
- | AuthorLink
249
+ | Byline
250
+ | Author
232
251
  | Cite
@@ -0,0 +1,18 @@
1
+ import { AuthorReferenceResolvers } from '../../../generated'
2
+ import { predicates } from '../../../model/Concept'
3
+
4
+ export const Author = {
5
+ type: (parent) => parent.reference.type,
6
+ concept: (parent) => {
7
+ const authorAnnotations =
8
+ parent.contentApiData?.annotations({
9
+ byPredicate: predicates.hasAuthor,
10
+ }) ?? []
11
+
12
+ return (
13
+ authorAnnotations.find(
14
+ (concept) => concept.uuid() === parent.reference.id
15
+ ) ?? null
16
+ )
17
+ },
18
+ } satisfies AuthorReferenceResolvers
@@ -1,4 +1,3 @@
1
- import type { ClipSet as CAPIClipSet } from '../../../types/internal-content'
2
1
  import type {
3
2
  ClipSet as ClipSetWorkaroundContentTree,
4
3
  OldClip as OldClipContentTree,
@@ -20,20 +19,19 @@ function getClipSet(
20
19
  ) {
21
20
  const clipSets = parent.contentApiData
22
21
  ?.embeds()
23
- ?.filter((embedded) => embedded.type?.includes('ClipSet')) as
24
- | CAPIClipSet[]
25
- | []
22
+ ?.filter(
23
+ (embedded) =>
24
+ embedded.type === 'http://www.ft.com/ontology/content/ClipSet'
25
+ )
26
26
 
27
27
  const uuid = uuidFromUrl(
28
28
  parent.reference.type === 'clip-set'
29
29
  ? parent.reference.id
30
30
  : parent.reference.url
31
31
  )
32
- const clipSet = clipSets?.find(
33
- (embed: CAPIClipSet) => uuidFromUrl(embed.id) === uuid
34
- )
32
+ const clipSet = clipSets?.find((embed) => uuidFromUrl(embed.id) === uuid)
35
33
 
36
- return clipSet as CAPIClipSet
34
+ return clipSet
37
35
  }
38
36
 
39
37
  export const ClipSet = {
@@ -1,4 +1,4 @@
1
- import type { ImageSet as CAPIImageSet } from '../../../types/internal-content'
1
+ import type { ImageSet as CAPIImageSet } from '../../../model/schemas/capi/internal-content'
2
2
  import { uuidFromUrl } from '../../../helpers/metadata'
3
3
  import { Picture } from '../../../model/Picture'
4
4
  import { ImageSetResolvers } from '../../../generated'
@@ -1,4 +1,4 @@
1
- import type { ImageSet as CAPIImageSet } from '../../../types/internal-content'
1
+ import type { ImageSet as CAPIImageSet } from '../../../model/schemas/capi/internal-content'
2
2
  import { uuidFromUrl } from '../../../helpers/metadata'
3
3
  import { Picture } from '../../../model/Picture'
4
4
  import { ScrollyImageResolvers } from '../../../generated'
@@ -26,8 +26,10 @@ import {
26
26
  CaptionResolvers,
27
27
  AccessibilityResolvers,
28
28
  FlourishFallbackResolvers,
29
+ AuthorReferenceResolvers,
29
30
  } from '../../../generated'
30
31
  import { AnyNode } from '../Workarounds'
32
+ import { Author } from './Author'
31
33
 
32
34
  export type ReferenceWithCAPIData<ReferenceType = ContentTree.Node> = {
33
35
  reference: ReferenceType
@@ -49,6 +51,7 @@ export const resolvers: {
49
51
  Caption: CaptionResolvers
50
52
  Accessibility: AccessibilityResolvers
51
53
  FlourishFallback: FlourishFallbackResolvers
54
+ AuthorReference: AuthorReferenceResolvers
52
55
  } = {
53
56
  Reference,
54
57
  Tweet,
@@ -64,6 +67,7 @@ export const resolvers: {
64
67
  Caption,
65
68
  Accessibility,
66
69
  FlourishFallback,
70
+ AuthorReference: Author,
67
71
  }
68
72
 
69
73
  export const mapNodeToReference = {
@@ -77,6 +81,7 @@ export const mapNodeToReference = {
77
81
  'layout-image': 'LayoutImage',
78
82
  'scrolly-image': 'ScrollyImage',
79
83
  'raw-image': 'RawImage',
80
- 'main-image': 'ImageSet',
84
+ 'main-image': 'MainImage',
81
85
  'main-image-raw': 'RawImage',
86
+ author: 'AuthorReference',
82
87
  } as const satisfies Partial<Record<AnyNode['type'], keyof typeof resolvers>>
@@ -1,7 +1,6 @@
1
1
  import { ContentTree } from '@financial-times/content-tree'
2
2
  import { CapiResponse } from '../../model/CapiResponse'
3
3
  import { ReferenceWithCAPIData, mapNodeToReference } from './references'
4
- import { AnyNode, Body } from './Workarounds'
5
4
 
6
5
  function isParent(node: ContentTree.Node): node is ContentTree.Parent {
7
6
  return 'children' in node
@@ -12,26 +11,25 @@ const isValidReferenceType = (
12
11
  ): type is keyof typeof mapNodeToReference => type in mapNodeToReference
13
12
 
14
13
  export default function updateTreeWithReferenceIds(
15
- tree: Body,
14
+ tree: ContentTree.Parent,
16
15
  contentApiData?: CapiResponse
17
16
  ): {
18
- tree: Body
17
+ tree: ContentTree.Parent
19
18
  references: ReferenceWithCAPIData[]
20
19
  } {
21
20
  const references: ReferenceWithCAPIData[] = []
22
- let index = 0
23
21
 
24
- function traverse(node: AnyNode) {
22
+ function traverse(node: ContentTree.Node) {
25
23
  if (isValidReferenceType(node.type)) {
26
- references.push({
24
+ const referencesLength = references.push({
27
25
  reference: node,
28
26
  contentApiData,
29
27
  })
30
28
  node.data = node.data || {}
31
- node.data.referenceIndex = index++
29
+ node.data.referenceIndex = referencesLength - 1
32
30
  }
33
31
  if (isParent(node)) {
34
- node.children.forEach((node) => traverse(node as AnyNode))
32
+ node.children.forEach((node) => traverse(node))
35
33
  }
36
34
  }
37
35
 
@@ -20,7 +20,7 @@ const contentResolvers: ContentResolvers = {
20
20
  accessLevel: (parent) => parent.accessLevel(),
21
21
  altStandfirst: (parent) => parent.alternativeStandfirst(),
22
22
  altTitle: (parent) => parent.alternativeTitle(),
23
- annotations: (parent) => parent.annotations(),
23
+ annotations: (parent, args) => parent.annotations(args),
24
24
  body: (parent) => parent.body(),
25
25
  bodyXML: (parent) => parent.bodyXML(),
26
26
  byline: (parent, args) => parent.byline(args),
@@ -36,6 +36,7 @@ const contentResolvers: ContentResolvers = {
36
36
  originatingParty: (parent) => parent.originatingParty(),
37
37
  publishedDate: (parent) => parent.publishedDate(),
38
38
  publishedTimestamp: (parent) => parent.publishedTimestamp(),
39
+ modifiedTimestamp: (parent) => parent.modifiedTimestamp(),
39
40
  standfirst: (parent) => parent.standfirst(),
40
41
  teaser: (parent) => parent.teaser(),
41
42
  title: (parent) => parent.title(),
@@ -77,6 +78,7 @@ const resolvers = {
77
78
  containedIn: (parent) => parent.containedIn(),
78
79
  indicators(parent) {
79
80
  return {
81
+ accessLevel: parent.accessLevel(),
80
82
  isOpinion: parent.isOpinion(),
81
83
  }
82
84
  },
@@ -124,7 +126,7 @@ const resolvers = {
124
126
  },
125
127
 
126
128
  Indicators: {
127
- accessLevel: (parent) => parent.accessLevel ?? null,
129
+ accessLevel: (parent) => parent.accessLevel,
128
130
  isOpinion: (parent) => parent.isOpinion ?? null,
129
131
  isColumn: (parent) => parent.isColumn ?? null,
130
132
  isPodcast: (parent) => parent.isPodcast ?? null,
@@ -8,6 +8,7 @@ const resolvers = {
8
8
  fallbackImage: (flourish) => flourish.fallbackImage(),
9
9
  },
10
10
  FlourishSource: {
11
+ id: (parent) => parent.id(),
11
12
  url: async (parent) => {
12
13
  const url = await parent.url()
13
14
  return url
@@ -1,7 +1,7 @@
1
1
  import { PersonResolvers } from '../generated'
2
2
  const resolvers = {
3
3
  Person: {
4
- headshot: (parent) => parent.headshot(),
4
+ headshot: (parent, args) => parent.headshot(args),
5
5
  prefLabel: (parent) => parent.prefLabel(),
6
6
  streamPage: (parent) => parent.streamPage(),
7
7
  },
@@ -13,7 +13,7 @@ declare module '@financial-times/n-display-metadata' {
13
13
 
14
14
  export interface TeaserMetadata<ConceptType, ContainedInType> {
15
15
  flags: FlagsMetadata
16
- prefixText: string
16
+ prefixText?: string
17
17
  link: ConceptType | ContainedInType | null
18
18
  altLink: ConceptType | null
19
19
  }