@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.
- package/CHANGELOG.md +39 -0
- package/lib/datasources/capi.d.ts +2 -2
- package/lib/datasources/capi.js +4 -2
- package/lib/datasources/capi.js.map +1 -1
- package/lib/datasources/capi.test.js +2 -2
- package/lib/fixtures/capiObject.d.ts +2 -2
- package/lib/fixtures/capiObject.js +2 -0
- package/lib/fixtures/capiObject.js.map +1 -1
- package/lib/fixtures/capiPerson.d.ts +1 -1
- package/lib/generated/index.d.ts +296 -131
- package/lib/helpers/decorateHeadshotUrl.d.ts +1 -2
- package/lib/helpers/decorateHeadshotUrl.js +2 -3
- package/lib/helpers/decorateHeadshotUrl.js.map +1 -1
- package/lib/model/Byline.d.ts +8 -10
- package/lib/model/Byline.js +34 -33
- package/lib/model/Byline.js.map +1 -1
- package/lib/model/Byline.test.js +105 -52
- package/lib/model/Byline.test.js.map +1 -1
- package/lib/model/CapiResponse.d.ts +12 -16
- package/lib/model/CapiResponse.js +38 -41
- package/lib/model/CapiResponse.js.map +1 -1
- package/lib/model/CapiResponse.test.js +7 -18
- package/lib/model/CapiResponse.test.js.map +1 -1
- package/lib/model/Clip.d.ts +1 -1
- package/lib/model/Concept.d.ts +1 -1
- package/lib/model/Concept.js +1 -2
- package/lib/model/Concept.js.map +1 -1
- package/lib/model/FlourishSource.d.ts +1 -1
- package/lib/model/FlourishSource.js.map +1 -1
- package/lib/model/Image.d.ts +1 -1
- package/lib/model/LeadFlourish.test.js +1 -0
- package/lib/model/LeadFlourish.test.js.map +1 -1
- package/lib/model/Person.d.ts +6 -12
- package/lib/model/Person.js +39 -66
- package/lib/model/Person.js.map +1 -1
- package/lib/model/Person.test.js +7 -60
- package/lib/model/Person.test.js.map +1 -1
- package/lib/model/Picture.d.ts +1 -1
- package/lib/model/RichText.d.ts +1 -2
- package/lib/model/Topper.d.ts +1 -1
- package/lib/model/Topper.js +10 -8
- package/lib/model/Topper.js.map +1 -1
- package/lib/model/Topper.test.js +9 -10
- package/lib/model/Topper.test.js.map +1 -1
- package/lib/model/schemas/capi/article.d.ts +7 -4
- package/lib/model/schemas/capi/article.js +1 -0
- package/lib/model/schemas/capi/article.js.map +1 -1
- package/lib/model/schemas/capi/audio.d.ts +7 -4
- package/lib/model/schemas/capi/audio.js +1 -0
- package/lib/model/schemas/capi/audio.js.map +1 -1
- package/lib/model/schemas/capi/base-schema.d.ts +14 -123
- package/lib/model/schemas/capi/base-schema.js +7 -6
- package/lib/model/schemas/capi/base-schema.js.map +1 -1
- package/lib/model/schemas/capi/content-package.d.ts +10 -5
- package/lib/model/schemas/capi/content-package.js +2 -0
- package/lib/model/schemas/capi/content-package.js.map +1 -1
- package/lib/model/schemas/capi/index.d.ts +41 -22
- package/lib/model/schemas/capi/internal-content.d.ts +24 -0
- package/lib/model/schemas/capi/internal-content.js +3 -0
- package/lib/model/schemas/capi/internal-content.js.map +1 -0
- package/lib/model/schemas/capi/live-blog-package.d.ts +7 -4
- package/lib/model/schemas/capi/live-blog-package.js +1 -0
- package/lib/model/schemas/capi/live-blog-package.js.map +1 -1
- package/lib/model/schemas/capi/placeholder.d.ts +7 -4
- package/lib/model/schemas/capi/placeholder.js +1 -0
- package/lib/model/schemas/capi/placeholder.js.map +1 -1
- package/lib/model/schemas/capi/video.d.ts +10 -5
- package/lib/model/schemas/capi/video.js +2 -0
- package/lib/model/schemas/capi/video.js.map +1 -1
- package/lib/resolvers/concept.d.ts +37 -2
- package/lib/resolvers/concept.js +17 -10
- package/lib/resolvers/concept.js.map +1 -1
- package/lib/resolvers/content-tree/Workarounds.d.ts +19 -11
- package/lib/resolvers/content-tree/references/Author.d.ts +4 -0
- package/lib/resolvers/content-tree/references/Author.js +14 -0
- package/lib/resolvers/content-tree/references/Author.js.map +1 -0
- package/lib/resolvers/content-tree/references/ClipSet.d.ts +1 -1
- package/lib/resolvers/content-tree/references/ClipSet.js +1 -1
- package/lib/resolvers/content-tree/references/ClipSet.js.map +1 -1
- package/lib/resolvers/content-tree/references/Flourish.d.ts +1 -1
- package/lib/resolvers/content-tree/references/Reference.d.ts +1 -1
- package/lib/resolvers/content-tree/references/index.d.ts +4 -2
- package/lib/resolvers/content-tree/references/index.js +4 -1
- package/lib/resolvers/content-tree/references/index.js.map +1 -1
- package/lib/resolvers/content-tree/updateTreeWithReferenceIds.d.ts +3 -3
- package/lib/resolvers/content-tree/updateTreeWithReferenceIds.js +2 -3
- package/lib/resolvers/content-tree/updateTreeWithReferenceIds.js.map +1 -1
- package/lib/resolvers/content.d.ts +27 -18
- package/lib/resolvers/content.js +4 -2
- package/lib/resolvers/content.js.map +1 -1
- package/lib/resolvers/image.d.ts +12 -12
- package/lib/resolvers/index.d.ts +89 -42
- package/lib/resolvers/leadFlourish.d.ts +2 -1
- package/lib/resolvers/leadFlourish.js +1 -0
- package/lib/resolvers/leadFlourish.js.map +1 -1
- package/lib/resolvers/person.d.ts +1 -1
- package/lib/resolvers/person.js +1 -1
- package/lib/resolvers/person.js.map +1 -1
- package/lib/resolvers/picture.d.ts +4 -4
- package/lib/resolvers/richText.d.ts +1 -1
- package/lib/resolvers/teaser.d.ts +1 -1
- package/lib/resolvers/topper.d.ts +3 -3
- package/package.json +1 -1
- package/queries/article.graphql +35 -13
- package/src/datasources/capi.test.ts +3 -3
- package/src/datasources/capi.ts +5 -3
- package/src/fixtures/capiObject.ts +4 -2
- package/src/fixtures/capiPerson.ts +1 -1
- package/src/generated/index.ts +321 -132
- package/src/helpers/decorateHeadshotUrl.ts +2 -2
- package/src/model/Byline.test.ts +136 -55
- package/src/model/Byline.ts +49 -39
- package/src/model/CapiResponse.test.ts +9 -25
- package/src/model/CapiResponse.ts +83 -56
- package/src/model/Clip.ts +1 -1
- package/src/model/Concept.ts +3 -3
- package/src/model/FlourishSource.ts +1 -1
- package/src/model/Image.test.ts +1 -1
- package/src/model/Image.ts +1 -1
- package/src/model/LeadFlourish.test.ts +1 -0
- package/src/model/Person.test.ts +11 -62
- package/src/model/Person.ts +47 -51
- package/src/model/Picture.test.ts +1 -1
- package/src/model/Picture.ts +1 -1
- package/src/model/Topper.test.ts +22 -18
- package/src/model/Topper.ts +10 -9
- package/src/model/__snapshots__/Byline.test.ts.snap +166 -27
- package/src/model/schemas/capi/article.ts +1 -0
- package/src/model/schemas/capi/audio.ts +1 -0
- package/src/model/schemas/capi/base-schema.ts +5 -4
- package/src/model/schemas/capi/content-package.ts +2 -0
- package/src/model/schemas/capi/internal-content.ts +45 -0
- package/src/model/schemas/capi/live-blog-package.ts +1 -0
- package/src/model/schemas/capi/placeholder.ts +1 -0
- package/src/model/schemas/capi/video.ts +2 -0
- package/src/resolvers/concept.ts +29 -12
- package/src/resolvers/content-tree/Workarounds.ts +39 -20
- package/src/resolvers/content-tree/references/Author.ts +18 -0
- package/src/resolvers/content-tree/references/ClipSet.ts +6 -8
- package/src/resolvers/content-tree/references/ImageSet.ts +1 -1
- package/src/resolvers/content-tree/references/ScrollyImage.ts +1 -1
- package/src/resolvers/content-tree/references/index.ts +6 -1
- package/src/resolvers/content-tree/updateTreeWithReferenceIds.ts +6 -8
- package/src/resolvers/content.ts +4 -2
- package/src/resolvers/leadFlourish.ts +1 -0
- package/src/resolvers/person.ts +1 -1
- package/src/types/n-display-metadata.d.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/typedefs/clip.graphql +2 -2
- package/typedefs/concept.graphql +64 -2
- package/typedefs/content.graphql +63 -39
- package/typedefs/image.graphql +12 -12
- package/typedefs/leadFlourish.graphql +32 -0
- package/typedefs/person.graphql +2 -2
- package/typedefs/picture.graphql +6 -6
- package/typedefs/references/author.graphql +7 -0
- package/typedefs/references/clipSet.graphql +14 -2
- package/typedefs/references/tweet.graphql +1 -1
- package/typedefs/teaser.graphql +10 -10
- package/src/types/internal-content.d.ts +0 -55
- package/typedefs/leadFlouish.graphql +0 -29
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { CapiPerson } from '../
|
|
1
|
+
import { CapiPerson } from '../model/schemas/capi/internal-content'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
const UUID_REGEX =
|
|
4
4
|
/\b[0-9a-f]{8}-[0-9a-f]{4}-[1-9][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/i
|
|
5
5
|
|
|
6
6
|
const IMAGESET_REGEX = /fthead(?:-v\d)?\:[^?]+/
|
package/src/model/Byline.test.ts
CHANGED
|
@@ -1,107 +1,188 @@
|
|
|
1
1
|
import { Byline } from './Byline'
|
|
2
2
|
import context from '../fixtures/dummyContext'
|
|
3
|
+
import { Concept } from './Concept'
|
|
4
|
+
|
|
3
5
|
const vanity = true
|
|
4
6
|
|
|
5
7
|
describe('byline transformation', () => {
|
|
6
8
|
test('adds a link around a single known author', async () => {
|
|
7
9
|
const bylineText = 'Chris Giles in London'
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const authors = [
|
|
11
|
+
new Concept(
|
|
12
|
+
{
|
|
13
|
+
id: 'https://api.ft.com/things/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
14
|
+
apiUrl:
|
|
15
|
+
'https://api.ft.com/people/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
16
|
+
prefLabel: 'Chris Giles',
|
|
17
|
+
directType: 'http://www.ft.com/ontology/person/Person',
|
|
18
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
19
|
+
types: [
|
|
20
|
+
'http://www.ft.com/ontology/core/Thing',
|
|
21
|
+
'http://www.ft.com/ontology/concept/Concept',
|
|
22
|
+
'http://www.ft.com/ontology/person/Person',
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
context
|
|
26
|
+
),
|
|
27
|
+
]
|
|
14
28
|
|
|
15
|
-
const byline = new Byline(bylineText, vanity,
|
|
29
|
+
const byline = new Byline(bylineText, vanity, authors)
|
|
16
30
|
const result = await byline.buildBylineTree()
|
|
17
31
|
expect(result).toMatchSnapshot()
|
|
18
32
|
})
|
|
19
33
|
|
|
20
34
|
test('adds links around multiple known authors', async () => {
|
|
21
35
|
const bylineText = 'Chris Giles and Martin Wolf in London'
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
36
|
+
const authors = [
|
|
37
|
+
new Concept(
|
|
38
|
+
{
|
|
39
|
+
id: 'https://api.ft.com/things/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
40
|
+
apiUrl:
|
|
41
|
+
'https://api.ft.com/people/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
42
|
+
prefLabel: 'Chris Giles',
|
|
43
|
+
directType: 'http://www.ft.com/ontology/person/Person',
|
|
44
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
45
|
+
types: [
|
|
46
|
+
'http://www.ft.com/ontology/core/Thing',
|
|
47
|
+
'http://www.ft.com/ontology/concept/Concept',
|
|
48
|
+
'http://www.ft.com/ontology/person/Person',
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
context
|
|
52
|
+
),
|
|
53
|
+
new Concept(
|
|
54
|
+
{
|
|
55
|
+
id: 'https://api.ft.com/things/7c1e1e72-57ae-4461-862a-f8d24dd42e22',
|
|
56
|
+
apiUrl:
|
|
57
|
+
'https://api.ft.com/people/7c1e1e72-57ae-4461-862a-f8d24dd42e22',
|
|
58
|
+
prefLabel: 'Martin Wolf',
|
|
59
|
+
directType: 'http://www.ft.com/ontology/person/Person',
|
|
60
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
61
|
+
types: [
|
|
62
|
+
'http://www.ft.com/ontology/core/Thing',
|
|
63
|
+
'http://www.ft.com/ontology/concept/Concept',
|
|
64
|
+
'http://www.ft.com/ontology/person/Person',
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
context
|
|
68
|
+
),
|
|
69
|
+
]
|
|
32
70
|
|
|
33
|
-
const byline = new Byline(bylineText, vanity,
|
|
71
|
+
const byline = new Byline(bylineText, vanity, authors)
|
|
34
72
|
const result = await byline.buildBylineTree()
|
|
35
73
|
expect(result).toMatchSnapshot()
|
|
36
74
|
})
|
|
37
75
|
|
|
38
76
|
test('ignores unknown authors in byline text', async () => {
|
|
39
77
|
const bylineText = 'Chris Giles and Nick Ramsbottom in London'
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
78
|
+
const authors = [
|
|
79
|
+
new Concept(
|
|
80
|
+
{
|
|
81
|
+
id: 'https://api.ft.com/things/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
82
|
+
apiUrl:
|
|
83
|
+
'https://api.ft.com/people/1d556016-ad16-4fe7-8724-42b3fb15ad28',
|
|
84
|
+
prefLabel: 'Chris Giles',
|
|
85
|
+
directType: 'http://www.ft.com/ontology/person/Person',
|
|
86
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
87
|
+
types: [
|
|
88
|
+
'http://www.ft.com/ontology/core/Thing',
|
|
89
|
+
'http://www.ft.com/ontology/concept/Concept',
|
|
90
|
+
'http://www.ft.com/ontology/person/Person',
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
context
|
|
94
|
+
),
|
|
95
|
+
]
|
|
46
96
|
|
|
47
|
-
const byline = new Byline(bylineText, vanity,
|
|
97
|
+
const byline = new Byline(bylineText, vanity, authors)
|
|
48
98
|
const result = await byline.buildBylineTree()
|
|
49
99
|
expect(result).toMatchSnapshot()
|
|
50
100
|
})
|
|
51
101
|
|
|
52
102
|
test('ignores extra authors in annotations array', async () => {
|
|
53
103
|
const bylineText = 'Martin Wolf in London'
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
104
|
+
const authors = [
|
|
105
|
+
new Concept(
|
|
106
|
+
{
|
|
107
|
+
id: 'https://api.ft.com/things/7c1e1e72-57ae-4461-862a-f8d24dd42e22',
|
|
108
|
+
apiUrl:
|
|
109
|
+
'https://api.ft.com/people/7c1e1e72-57ae-4461-862a-f8d24dd42e22',
|
|
110
|
+
prefLabel: 'Martin Wolf',
|
|
111
|
+
directType: 'http://www.ft.com/ontology/person/Person',
|
|
112
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
113
|
+
types: [
|
|
114
|
+
'http://www.ft.com/ontology/core/Thing',
|
|
115
|
+
'http://www.ft.com/ontology/concept/Concept',
|
|
116
|
+
'http://www.ft.com/ontology/person/Person',
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
context
|
|
120
|
+
),
|
|
121
|
+
]
|
|
64
122
|
|
|
65
|
-
const byline = new Byline(bylineText, vanity,
|
|
123
|
+
const byline = new Byline(bylineText, vanity, authors)
|
|
66
124
|
const result = await byline.buildBylineTree()
|
|
67
125
|
expect(result).toMatchSnapshot()
|
|
68
126
|
})
|
|
69
127
|
|
|
70
128
|
test('handles bylines without any matching authors', async () => {
|
|
71
129
|
const bylineText = 'Chris Giles and Nick Ramsbottom in London'
|
|
72
|
-
const
|
|
130
|
+
const authors: Concept[] = []
|
|
73
131
|
|
|
74
|
-
const byline = new Byline(bylineText, vanity,
|
|
132
|
+
const byline = new Byline(bylineText, vanity, authors)
|
|
75
133
|
const result = await byline.buildBylineTree()
|
|
76
|
-
|
|
77
134
|
expect(result).toMatchSnapshot()
|
|
78
135
|
})
|
|
79
136
|
|
|
80
137
|
test('converts straight apostrophes in byline', async () => {
|
|
81
138
|
const bylineText = "Sarah O'Connor in Bali"
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
139
|
+
const authors = [
|
|
140
|
+
new Concept(
|
|
141
|
+
{
|
|
142
|
+
id: 'https://api.ft.com/things/1d556016-ad16-4fe7-8724-eeeeeeeeeeee',
|
|
143
|
+
apiUrl:
|
|
144
|
+
'https://api.ft.com/people/1d556016-ad16-4fe7-8724-eeeeeeeeeeee',
|
|
145
|
+
prefLabel: 'Sarah O’Connor',
|
|
146
|
+
directType: 'http://www.ft.com/ontology/person/Person',
|
|
147
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
148
|
+
types: [
|
|
149
|
+
'http://www.ft.com/ontology/core/Thing',
|
|
150
|
+
'http://www.ft.com/ontology/concept/Concept',
|
|
151
|
+
'http://www.ft.com/ontology/person/Person',
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
context
|
|
155
|
+
),
|
|
156
|
+
]
|
|
90
157
|
|
|
158
|
+
const byline = new Byline(bylineText, vanity, authors)
|
|
159
|
+
const result = await byline.buildBylineTree()
|
|
91
160
|
expect(result).toMatchSnapshot()
|
|
92
161
|
})
|
|
93
162
|
|
|
94
163
|
test('leaves curly apostrophes in byline', async () => {
|
|
95
164
|
const bylineText = 'Sarah O’Connor in Bali'
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
165
|
+
const authors = [
|
|
166
|
+
new Concept(
|
|
167
|
+
{
|
|
168
|
+
id: 'https://api.ft.com/things/1d556016-ad16-4fe7-8724-eeeeeeeeeeee',
|
|
169
|
+
apiUrl:
|
|
170
|
+
'https://api.ft.com/people/1d556016-ad16-4fe7-8724-eeeeeeeeeeee',
|
|
171
|
+
prefLabel: 'Sarah O’Connor',
|
|
172
|
+
directType: 'http://www.ft.com/ontology/person/Person',
|
|
173
|
+
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
174
|
+
types: [
|
|
175
|
+
'http://www.ft.com/ontology/core/Thing',
|
|
176
|
+
'http://www.ft.com/ontology/concept/Concept',
|
|
177
|
+
'http://www.ft.com/ontology/person/Person',
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
context
|
|
181
|
+
),
|
|
182
|
+
]
|
|
104
183
|
|
|
184
|
+
const byline = new Byline(bylineText, vanity, authors)
|
|
185
|
+
const result = await byline.buildBylineTree()
|
|
105
186
|
expect(result).toMatchSnapshot()
|
|
106
187
|
})
|
|
107
188
|
})
|
package/src/model/Byline.ts
CHANGED
|
@@ -1,58 +1,68 @@
|
|
|
1
1
|
import { ContentTree } from '@financial-times/content-tree'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { Concept } from './Concept'
|
|
3
|
+
import {
|
|
4
|
+
Byline as BylineNode,
|
|
5
|
+
Author as AuthorNode,
|
|
6
|
+
} from '../resolvers/content-tree/Workarounds'
|
|
7
|
+
import updateTreeWithReferenceIds from '../resolvers/content-tree/updateTreeWithReferenceIds'
|
|
8
|
+
import { CapiResponse } from './CapiResponse'
|
|
4
9
|
|
|
5
10
|
export class Byline {
|
|
11
|
+
static normaliseQuotes(str: string) {
|
|
12
|
+
return str.replaceAll("'", '’')
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
constructor(
|
|
7
16
|
private byline: string,
|
|
8
17
|
private vanity: boolean,
|
|
9
|
-
private
|
|
10
|
-
private
|
|
18
|
+
private authors: Concept[],
|
|
19
|
+
private contentApiData?: CapiResponse
|
|
11
20
|
) {}
|
|
12
21
|
|
|
13
22
|
async buildBylineTree() {
|
|
14
23
|
// Normalise apostrophes in byline string
|
|
15
|
-
const
|
|
24
|
+
const normalisedByline = Byline.normaliseQuotes(this.byline)
|
|
25
|
+
|
|
26
|
+
const bylineParts = this.#splitBylineByName(
|
|
27
|
+
normalisedByline,
|
|
28
|
+
this.authors.map((author) => Byline.normaliseQuotes(author.prefLabel()))
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
const authorNameMapping = Object.fromEntries(
|
|
32
|
+
this.authors.map((author) => {
|
|
33
|
+
return [Byline.normaliseQuotes(author.prefLabel()), author] as const
|
|
34
|
+
})
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
const children = bylineParts.map((part): AuthorNode | ContentTree.Text => {
|
|
38
|
+
const author = authorNameMapping[part]
|
|
39
|
+
const text: ContentTree.Text = {
|
|
40
|
+
type: 'text',
|
|
41
|
+
value: part,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return author
|
|
45
|
+
? {
|
|
46
|
+
type: 'author',
|
|
47
|
+
id: author.uuid(),
|
|
48
|
+
children: [text],
|
|
49
|
+
}
|
|
50
|
+
: text
|
|
51
|
+
})
|
|
16
52
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
53
|
+
return updateTreeWithReferenceIds(
|
|
54
|
+
{
|
|
55
|
+
type: 'byline',
|
|
56
|
+
children,
|
|
57
|
+
} satisfies BylineNode,
|
|
58
|
+
this.contentApiData
|
|
59
|
+
)
|
|
21
60
|
}
|
|
22
61
|
|
|
23
62
|
#splitBylineByName(byline: string, names: string[]) {
|
|
24
63
|
if (!names.length) return [byline]
|
|
64
|
+
|
|
25
65
|
const regex = new RegExp(`(${names.join('|')})`, 'ig')
|
|
26
66
|
return byline.split(regex).filter((string) => string !== '')
|
|
27
67
|
}
|
|
28
|
-
|
|
29
|
-
async #buildUrlTree(urlMapping: Map<string, string>, parts: string[]) {
|
|
30
|
-
const children: (AuthorLink | ContentTree.Text)[] = await Promise.all(
|
|
31
|
-
parts.map(async (part) => {
|
|
32
|
-
const fullUrl = urlMapping.get(part)
|
|
33
|
-
const vanityUrl =
|
|
34
|
-
this.vanity && fullUrl
|
|
35
|
-
? await this.context.dataSources.vanityUrls.get(fullUrl)
|
|
36
|
-
: null
|
|
37
|
-
|
|
38
|
-
if (fullUrl) {
|
|
39
|
-
return {
|
|
40
|
-
type: 'author-link',
|
|
41
|
-
href: vanityUrl || fullUrl,
|
|
42
|
-
children: [{ type: 'text', value: part }],
|
|
43
|
-
}
|
|
44
|
-
} else {
|
|
45
|
-
return {
|
|
46
|
-
type: 'text',
|
|
47
|
-
value: part,
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
})
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
tree: { type: 'root', children },
|
|
55
|
-
references: [],
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
68
|
}
|
|
@@ -13,31 +13,6 @@ describe('CAPI response', () => {
|
|
|
13
13
|
})
|
|
14
14
|
})
|
|
15
15
|
|
|
16
|
-
describe('Author URL mapping', () => {
|
|
17
|
-
test('converts any straight quotes in the author name to curly quotes', () => {
|
|
18
|
-
const straighQuoteAuthorName = `Sinéad O'Connor`
|
|
19
|
-
const curlyQuoteAuthorName = `Sinéad O’Connor`
|
|
20
|
-
|
|
21
|
-
const article = cloneDeep(baseCapiObject)
|
|
22
|
-
delete article.annotations
|
|
23
|
-
article.annotations = [
|
|
24
|
-
{
|
|
25
|
-
id: 'http://api.ft.com/things/eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee',
|
|
26
|
-
predicate: 'http://www.ft.com/ontology/annotation/hasAuthor',
|
|
27
|
-
prefLabel: straighQuoteAuthorName,
|
|
28
|
-
},
|
|
29
|
-
]
|
|
30
|
-
const capiResponse = new CapiResponse(article, context)
|
|
31
|
-
|
|
32
|
-
expect(
|
|
33
|
-
capiResponse.getAuthorUrlMapping().get(curlyQuoteAuthorName)
|
|
34
|
-
).toBeDefined()
|
|
35
|
-
expect(
|
|
36
|
-
capiResponse.getAuthorUrlMapping().get(straighQuoteAuthorName)
|
|
37
|
-
).toBeUndefined()
|
|
38
|
-
})
|
|
39
|
-
})
|
|
40
|
-
|
|
41
16
|
describe('Content Type', () => {
|
|
42
17
|
test(`uses first entry in types if there's no type`, () => {
|
|
43
18
|
const article = cloneDeep(baseCapiObject)
|
|
@@ -84,6 +59,15 @@ describe('CAPI response', () => {
|
|
|
84
59
|
})
|
|
85
60
|
})
|
|
86
61
|
|
|
62
|
+
describe('Modified timestamp', () => {
|
|
63
|
+
test('generates a timestamp from the last modified date', () => {
|
|
64
|
+
const article = cloneDeep(baseCapiObject)
|
|
65
|
+
const capiResponse = new CapiResponse(article, context)
|
|
66
|
+
|
|
67
|
+
expect(capiResponse.modifiedTimestamp()).toEqual(1712061296789)
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
87
71
|
describe('liveBlogPosts', () => {
|
|
88
72
|
test('returns a resolved array of the articles contained sorted by most recently published', async () => {
|
|
89
73
|
const liveBlogPackage = cloneDeep({
|