@financial-times/cp-content-pipeline-schema 2.3.0 → 2.4.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 +19 -0
- package/lib/generated/index.d.ts +2 -0
- package/lib/model/CapiResponse.d.ts +2 -1
- package/lib/model/CapiResponse.js +11 -5
- package/lib/model/CapiResponse.js.map +1 -1
- package/lib/model/Concept.test.js +0 -9
- package/lib/model/Concept.test.js.map +1 -1
- package/lib/model/RichText.d.ts +1 -1
- package/lib/model/RichText.js +20 -34
- package/lib/model/RichText.js.map +1 -1
- package/lib/model/RichText.test.js +0 -9
- package/lib/model/RichText.test.js.map +1 -1
- package/lib/resolvers/content-tree/bodyXMLToTree.d.ts +4 -3
- package/lib/resolvers/content-tree/bodyXMLToTree.js +2 -2
- package/lib/resolvers/content-tree/bodyXMLToTree.js.map +1 -1
- package/lib/resolvers/content-tree/bodyXMLToTree.test.js +20 -32
- package/lib/resolvers/content-tree/bodyXMLToTree.test.js.map +1 -1
- package/lib/resolvers/content-tree/nodePredicates.d.ts +6 -13
- package/lib/resolvers/content-tree/nodePredicates.js +33 -33
- package/lib/resolvers/content-tree/nodePredicates.js.map +1 -1
- package/lib/resolvers/content-tree/references/Reference.d.ts +1 -1
- package/lib/resolvers/content-tree/tagMappings.d.ts +2 -1
- package/lib/resolvers/content-tree/tagMappings.js +60 -60
- package/lib/resolvers/content-tree/tagMappings.js.map +1 -1
- package/lib/resolvers/content.d.ts +1 -0
- package/lib/resolvers/content.js +1 -0
- package/lib/resolvers/content.js.map +1 -1
- package/lib/resolvers/index.d.ts +1 -0
- package/package.json +1 -2
- package/queries/article.graphql +2 -1
- package/src/generated/index.ts +2 -0
- package/src/model/CapiResponse.ts +14 -7
- package/src/model/Concept.test.ts +0 -9
- package/src/model/RichText.test.ts +0 -10
- package/src/model/RichText.ts +27 -39
- package/src/resolvers/content-tree/bodyXMLToTree.test.ts +22 -32
- package/src/resolvers/content-tree/bodyXMLToTree.ts +11 -6
- package/src/resolvers/content-tree/nodePredicates.ts +39 -45
- package/src/resolvers/content-tree/tagMappings.ts +102 -60
- package/src/resolvers/content.ts +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/typedefs/content.graphql +2 -1
- package/__mocks__/worker_threads.ts +0 -3
- package/lib/resolvers/content-tree/bodyXMLToTreeWorker.d.ts +0 -9
- package/lib/resolvers/content-tree/bodyXMLToTreeWorker.js +0 -18
- package/lib/resolvers/content-tree/bodyXMLToTreeWorker.js.map +0 -1
- package/src/resolvers/content-tree/bodyXMLToTreeWorker.ts +0 -31
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
|
|
20
20
|
import * as scrollytelling from '@financial-times/n-scrollytelling-image/server'
|
|
21
21
|
import { LiteralToPrimitiveDeep } from 'type-fest'
|
|
22
|
+
import { CapiResponse } from '../../model/CapiResponse'
|
|
22
23
|
|
|
23
24
|
const tableResponsiveStyleMap: Record<string, Table['responsiveStyle']> = {
|
|
24
25
|
stacked: 'flat',
|
|
@@ -81,10 +82,10 @@ const validScrollytellingOption = <
|
|
|
81
82
|
: false
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
const articleTagMappings = (
|
|
85
|
+
const articleTagMappings = (capiData?: CapiResponse): TagMappings => ({
|
|
85
86
|
'body > ft-content[type="http://www.ft.com/ontology/content/ImageSet"]:first-child':
|
|
86
87
|
($el) => ({
|
|
87
|
-
type: topperHasImage ? 'image-set' : 'main-image',
|
|
88
|
+
type: capiData?.topperHasImage() ? 'image-set' : 'main-image',
|
|
88
89
|
id: $el.attr('url') || '',
|
|
89
90
|
}),
|
|
90
91
|
'body > ft-content[type="http://www.ft.com/ontology/content/ImageSet"]:not(:first-child),:not(body) > ft-content[type="http://www.ft.com/ontology/content/ImageSet"]':
|
|
@@ -103,55 +104,60 @@ const liveBlogPostTagMappings: TagMappings = {
|
|
|
103
104
|
|
|
104
105
|
const commonTagMappings: TagMappings = {
|
|
105
106
|
body: ($el, traverse) => ({ type: 'body', version: 1, children: traverse() }),
|
|
106
|
-
'a:not([data-asset-type])': ($el, traverse) => ({
|
|
107
|
+
'a:not([data-asset-type])': ($el, traverse, context) => ({
|
|
107
108
|
type: 'link',
|
|
108
109
|
url: $el.attr('href') || '',
|
|
109
110
|
title: '',
|
|
110
|
-
children: childrenOfTypes(phrasingTypes, traverse(), 'link'),
|
|
111
|
+
children: childrenOfTypes(phrasingTypes, traverse(), 'link', context),
|
|
111
112
|
}),
|
|
112
|
-
strong: ($el, traverse) => ({
|
|
113
|
+
strong: ($el, traverse, context) => ({
|
|
113
114
|
type: 'strong',
|
|
114
|
-
children: childrenOfTypes(phrasingTypes, traverse(), 'strong'),
|
|
115
|
+
children: childrenOfTypes(phrasingTypes, traverse(), 'strong', context),
|
|
115
116
|
}),
|
|
116
|
-
em: ($el, traverse) => ({
|
|
117
|
+
em: ($el, traverse, context) => ({
|
|
117
118
|
type: 'emphasis',
|
|
118
|
-
children: childrenOfTypes(phrasingTypes, traverse(), 'emphasis'),
|
|
119
|
+
children: childrenOfTypes(phrasingTypes, traverse(), 'emphasis', context),
|
|
119
120
|
}),
|
|
120
|
-
blockquote: ($el, traverse) => ({
|
|
121
|
+
blockquote: ($el, traverse, context) => ({
|
|
121
122
|
type: 'blockquote',
|
|
122
|
-
children: childrenOfTypes(phrasingTypes, traverse(), 'blockquote'),
|
|
123
|
+
children: childrenOfTypes(phrasingTypes, traverse(), 'blockquote', context),
|
|
123
124
|
}),
|
|
124
125
|
// strip any (redundant) line breaks in between two paragraphs
|
|
125
126
|
'p + br': ($el) => ($el.next()[0]?.tagName === 'p' ? [] : { type: 'break' }),
|
|
126
127
|
br: () => ({ type: 'break' }),
|
|
127
128
|
hr: () => ({ type: 'thematic-break' }),
|
|
128
|
-
s: ($el, traverse) => ({
|
|
129
|
+
s: ($el, traverse, context) => ({
|
|
129
130
|
type: 'strikethrough',
|
|
130
|
-
children: childrenOfTypes(
|
|
131
|
+
children: childrenOfTypes(
|
|
132
|
+
phrasingTypes,
|
|
133
|
+
traverse(),
|
|
134
|
+
'strikethrough',
|
|
135
|
+
context
|
|
136
|
+
),
|
|
131
137
|
}),
|
|
132
|
-
ul: ($el, traverse) => ({
|
|
138
|
+
ul: ($el, traverse, context) => ({
|
|
133
139
|
type: 'list',
|
|
134
|
-
children: everyChildIsType('list-item', traverse(), 'list'),
|
|
140
|
+
children: everyChildIsType('list-item', traverse(), 'list', context),
|
|
135
141
|
ordered: false,
|
|
136
142
|
}),
|
|
137
|
-
ol: ($el, traverse) => ({
|
|
143
|
+
ol: ($el, traverse, context) => ({
|
|
138
144
|
type: 'list',
|
|
139
|
-
children: everyChildIsType('list-item', traverse(), 'list'),
|
|
145
|
+
children: everyChildIsType('list-item', traverse(), 'list', context),
|
|
140
146
|
ordered: true,
|
|
141
147
|
}),
|
|
142
|
-
li: ($el, traverse) => ({
|
|
148
|
+
li: ($el, traverse, context) => ({
|
|
143
149
|
type: 'list-item',
|
|
144
|
-
children: childrenOfTypes(phrasingTypes, traverse(), 'list-item'),
|
|
150
|
+
children: childrenOfTypes(phrasingTypes, traverse(), 'list-item', context),
|
|
145
151
|
}),
|
|
146
152
|
'a[data-asset-type="tweet"]': ($el) => ({
|
|
147
153
|
type: 'tweet',
|
|
148
154
|
id: $el.attr('href') || '',
|
|
149
155
|
}),
|
|
150
156
|
|
|
151
|
-
'h4,h5,h6': ($el, traverse) => ({
|
|
157
|
+
'h4,h5,h6': ($el, traverse, context) => ({
|
|
152
158
|
type: 'heading',
|
|
153
159
|
level: 'label',
|
|
154
|
-
children: everyChildIsType('text', traverse(), 'heading'),
|
|
160
|
+
children: everyChildIsType('text', traverse(), 'heading', context),
|
|
155
161
|
}),
|
|
156
162
|
'pull-quote': ($el) => ({
|
|
157
163
|
type: 'pullquote',
|
|
@@ -230,7 +236,7 @@ const commonTagMappings: TagMappings = {
|
|
|
230
236
|
description: $description.text(),
|
|
231
237
|
}
|
|
232
238
|
},
|
|
233
|
-
'.n-content-layout': ($el, traverse) => {
|
|
239
|
+
'.n-content-layout': ($el, traverse, context) => {
|
|
234
240
|
//TODO: this is a bit gross??
|
|
235
241
|
const isValidWidth = (
|
|
236
242
|
str: string
|
|
@@ -254,14 +260,16 @@ const commonTagMappings: TagMappings = {
|
|
|
254
260
|
...everyChildIsType<ContentTree.LayoutSlot>(
|
|
255
261
|
'layout-slot',
|
|
256
262
|
otherChildren,
|
|
257
|
-
'layout'
|
|
263
|
+
'layout',
|
|
264
|
+
context
|
|
258
265
|
),
|
|
259
266
|
]
|
|
260
267
|
} else {
|
|
261
268
|
return everyChildIsType<ContentTree.LayoutSlot>(
|
|
262
269
|
'layout-slot',
|
|
263
270
|
children,
|
|
264
|
-
'layout'
|
|
271
|
+
'layout',
|
|
272
|
+
context
|
|
265
273
|
)
|
|
266
274
|
}
|
|
267
275
|
}
|
|
@@ -273,7 +281,7 @@ const commonTagMappings: TagMappings = {
|
|
|
273
281
|
children: getChildren(traverse()),
|
|
274
282
|
}
|
|
275
283
|
},
|
|
276
|
-
'.n-content-layout__slot': ($el, traverse) => ({
|
|
284
|
+
'.n-content-layout__slot': ($el, traverse, context) => ({
|
|
277
285
|
type: 'layout-slot',
|
|
278
286
|
children: childrenOfTypes(
|
|
279
287
|
['heading', 'paragraph', 'layout-image'],
|
|
@@ -283,7 +291,8 @@ const commonTagMappings: TagMappings = {
|
|
|
283
291
|
.flatMap((node) =>
|
|
284
292
|
node.type === 'layout-slot' ? node.children : [node]
|
|
285
293
|
),
|
|
286
|
-
'layout-slot'
|
|
294
|
+
'layout-slot',
|
|
295
|
+
context
|
|
287
296
|
),
|
|
288
297
|
}),
|
|
289
298
|
'.n-content-layout img': ($el) => ({
|
|
@@ -294,7 +303,7 @@ const commonTagMappings: TagMappings = {
|
|
|
294
303
|
credit: $el.attr('data-copyright') || '',
|
|
295
304
|
}),
|
|
296
305
|
|
|
297
|
-
table: ($el, traverse): Table | ContentTree.Layout => {
|
|
306
|
+
table: ($el, traverse, context): Table | ContentTree.Layout => {
|
|
298
307
|
const layoutSmallscreen = $el.attr('data-table-layout-smallscreen')
|
|
299
308
|
const responsiveStyle: Table['responsiveStyle'] =
|
|
300
309
|
layoutSmallscreen && layoutSmallscreen in tableResponsiveStyleMap
|
|
@@ -309,12 +318,14 @@ const commonTagMappings: TagMappings = {
|
|
|
309
318
|
const caption = findChildOftype<TableCaption>(
|
|
310
319
|
'table-caption',
|
|
311
320
|
children,
|
|
312
|
-
'table'
|
|
321
|
+
'table',
|
|
322
|
+
context
|
|
313
323
|
)
|
|
314
324
|
const footer = findChildOftype<TableFooter>(
|
|
315
325
|
'table-footer',
|
|
316
326
|
children,
|
|
317
|
-
'table'
|
|
327
|
+
'table',
|
|
328
|
+
context
|
|
318
329
|
)
|
|
319
330
|
|
|
320
331
|
// HACK:KB:20230523 transform single-cell tables into infoboxes, for legacy articles
|
|
@@ -328,7 +339,8 @@ const commonTagMappings: TagMappings = {
|
|
|
328
339
|
children: childrenOfTypes(
|
|
329
340
|
['paragraph', 'heading'],
|
|
330
341
|
bodies[0].children[0].children[0].children,
|
|
331
|
-
'layout-slot'
|
|
342
|
+
'layout-slot',
|
|
343
|
+
context
|
|
332
344
|
),
|
|
333
345
|
}
|
|
334
346
|
|
|
@@ -337,7 +349,12 @@ const commonTagMappings: TagMappings = {
|
|
|
337
349
|
{
|
|
338
350
|
type: 'heading',
|
|
339
351
|
level: 'subheading',
|
|
340
|
-
children: everyChildIsType(
|
|
352
|
+
children: everyChildIsType(
|
|
353
|
+
'text',
|
|
354
|
+
caption.children,
|
|
355
|
+
'heading',
|
|
356
|
+
context
|
|
357
|
+
),
|
|
341
358
|
},
|
|
342
359
|
slot,
|
|
343
360
|
]
|
|
@@ -417,34 +434,44 @@ const commonTagMappings: TagMappings = {
|
|
|
417
434
|
// HACK needs to come before tr. TODO sort by selector specificity
|
|
418
435
|
'tfoot > tr': ($el, traverse) => traverse(),
|
|
419
436
|
// HACK needs to come before td. TODO sort by selector specificity
|
|
420
|
-
'tfoot > tr > td': ($el, traverse) => ({
|
|
437
|
+
'tfoot > tr > td': ($el, traverse, context) => ({
|
|
421
438
|
type: 'table-footer',
|
|
422
|
-
children: childrenOfTypes(
|
|
439
|
+
children: childrenOfTypes(
|
|
440
|
+
phrasingTypes,
|
|
441
|
+
traverse(),
|
|
442
|
+
'table-footer',
|
|
443
|
+
context
|
|
444
|
+
),
|
|
423
445
|
}),
|
|
424
|
-
tr: ($el, traverse) => ({
|
|
446
|
+
tr: ($el, traverse, context) => ({
|
|
425
447
|
type: 'table-row',
|
|
426
|
-
children: everyChildIsType('table-cell', traverse(), 'table-row'),
|
|
448
|
+
children: everyChildIsType('table-cell', traverse(), 'table-row', context),
|
|
427
449
|
}),
|
|
428
|
-
td: ($el, traverse) => ({
|
|
450
|
+
td: ($el, traverse, context) => ({
|
|
429
451
|
type: 'table-cell',
|
|
430
|
-
children: childrenOfTypes(phrasingTypes, traverse(), 'table-cell'),
|
|
452
|
+
children: childrenOfTypes(phrasingTypes, traverse(), 'table-cell', context),
|
|
431
453
|
}),
|
|
432
|
-
th: ($el, traverse) => ({
|
|
454
|
+
th: ($el, traverse, context) => ({
|
|
433
455
|
type: 'table-cell',
|
|
434
456
|
heading: true,
|
|
435
|
-
children: childrenOfTypes(phrasingTypes, traverse(), 'table-cell'),
|
|
457
|
+
children: childrenOfTypes(phrasingTypes, traverse(), 'table-cell', context),
|
|
436
458
|
}),
|
|
437
|
-
thead: ($el, traverse) => ({
|
|
459
|
+
thead: ($el, traverse, context) => ({
|
|
438
460
|
type: 'table-body',
|
|
439
|
-
children: everyChildIsType('table-row', traverse(), 'table-body'),
|
|
461
|
+
children: everyChildIsType('table-row', traverse(), 'table-body', context),
|
|
440
462
|
}),
|
|
441
|
-
tbody: ($el, traverse) => ({
|
|
463
|
+
tbody: ($el, traverse, context) => ({
|
|
442
464
|
type: 'table-body',
|
|
443
|
-
children: everyChildIsType('table-row', traverse(), 'table-body'),
|
|
465
|
+
children: everyChildIsType('table-row', traverse(), 'table-body', context),
|
|
444
466
|
}),
|
|
445
|
-
caption: ($el, traverse) => ({
|
|
467
|
+
caption: ($el, traverse, context) => ({
|
|
446
468
|
type: 'table-caption',
|
|
447
|
-
children: childrenOfTypes(
|
|
469
|
+
children: childrenOfTypes(
|
|
470
|
+
phrasingTypes,
|
|
471
|
+
traverse(),
|
|
472
|
+
'table-caption',
|
|
473
|
+
context
|
|
474
|
+
),
|
|
448
475
|
}),
|
|
449
476
|
|
|
450
477
|
// HACK needs to come after LayoutImage. TODO sort by selector specificity
|
|
@@ -468,14 +495,15 @@ const commonTagMappings: TagMappings = {
|
|
|
468
495
|
format: 'standard',
|
|
469
496
|
}),
|
|
470
497
|
|
|
471
|
-
'scrollable-block': ($el, traverse) => {
|
|
498
|
+
'scrollable-block': ($el, traverse, context) => {
|
|
472
499
|
return {
|
|
473
500
|
type: 'scrolly-block',
|
|
474
501
|
theme: $el.attr('theme') === '2' ? 'serif' : 'sans',
|
|
475
502
|
children: everyChildIsType(
|
|
476
503
|
'scrolly-section',
|
|
477
504
|
traverse(),
|
|
478
|
-
'scrolly-block'
|
|
505
|
+
'scrolly-block',
|
|
506
|
+
context
|
|
479
507
|
),
|
|
480
508
|
}
|
|
481
509
|
},
|
|
@@ -486,7 +514,7 @@ const commonTagMappings: TagMappings = {
|
|
|
486
514
|
id: $el.attr('url') ?? '',
|
|
487
515
|
}),
|
|
488
516
|
|
|
489
|
-
'scrollable-section': ($el, traverse) => {
|
|
517
|
+
'scrollable-section': ($el, traverse, context) => {
|
|
490
518
|
const [firstChild, ...restChildren] = traverse()
|
|
491
519
|
|
|
492
520
|
const display = $el.attr('theme-display')
|
|
@@ -510,29 +538,33 @@ const commonTagMappings: TagMappings = {
|
|
|
510
538
|
...everyChildIsType<ContentTree.ScrollyImage>(
|
|
511
539
|
'scrolly-image',
|
|
512
540
|
[firstChild],
|
|
513
|
-
'scrolly-section'
|
|
541
|
+
'scrolly-section',
|
|
542
|
+
context
|
|
514
543
|
),
|
|
515
544
|
...everyChildIsType<ContentTree.ScrollyCopy>(
|
|
516
545
|
'scrolly-copy',
|
|
517
546
|
restChildren,
|
|
518
|
-
'scrolly-section'
|
|
547
|
+
'scrolly-section',
|
|
548
|
+
context
|
|
519
549
|
),
|
|
520
550
|
] as [ContentTree.ScrollyImage, ...ContentTree.ScrollyCopy[]],
|
|
521
551
|
}
|
|
522
552
|
},
|
|
523
553
|
|
|
524
|
-
'scrollable-text': ($el, traverse) => ({
|
|
554
|
+
'scrollable-text': ($el, traverse, context) => ({
|
|
525
555
|
type: 'scrolly-copy',
|
|
526
556
|
children: childrenOfTypes(
|
|
527
557
|
['scrolly-heading', 'paragraph'],
|
|
528
558
|
traverse(),
|
|
529
|
-
'scrolly-copy'
|
|
559
|
+
'scrolly-copy',
|
|
560
|
+
context
|
|
530
561
|
),
|
|
531
562
|
}),
|
|
532
563
|
|
|
533
564
|
'scrollable-text > p, scrollable-text > h1, scrollable-text > h2': (
|
|
534
565
|
$el,
|
|
535
|
-
traverse
|
|
566
|
+
traverse,
|
|
567
|
+
context
|
|
536
568
|
) => {
|
|
537
569
|
const textStyle = $el.attr('theme-style')
|
|
538
570
|
|
|
@@ -540,31 +572,41 @@ const commonTagMappings: TagMappings = {
|
|
|
540
572
|
return {
|
|
541
573
|
type: 'scrolly-heading',
|
|
542
574
|
level: scrollytellingOptionsToContentTree.textStyle[textStyle],
|
|
543
|
-
children: everyChildIsType(
|
|
575
|
+
children: everyChildIsType(
|
|
576
|
+
'text',
|
|
577
|
+
traverse(),
|
|
578
|
+
'scrolly-heading',
|
|
579
|
+
context
|
|
580
|
+
),
|
|
544
581
|
}
|
|
545
582
|
}
|
|
546
583
|
|
|
547
584
|
return {
|
|
548
585
|
type: 'paragraph',
|
|
549
|
-
children: childrenOfTypes(
|
|
586
|
+
children: childrenOfTypes(
|
|
587
|
+
phrasingTypes,
|
|
588
|
+
traverse(),
|
|
589
|
+
'paragraph',
|
|
590
|
+
context
|
|
591
|
+
),
|
|
550
592
|
}
|
|
551
593
|
},
|
|
552
594
|
|
|
553
595
|
// HACK:KB:20230703 needs to come after `scrollable-text > X`. todo sort by specificity
|
|
554
|
-
p: ($el, traverse) => ({
|
|
596
|
+
p: ($el, traverse, context) => ({
|
|
555
597
|
type: 'paragraph',
|
|
556
|
-
children: childrenOfTypes(phrasingTypes, traverse(), 'paragraph'),
|
|
598
|
+
children: childrenOfTypes(phrasingTypes, traverse(), 'paragraph', context),
|
|
557
599
|
}),
|
|
558
600
|
|
|
559
|
-
h1: ($el, traverse) => ({
|
|
601
|
+
h1: ($el, traverse, context) => ({
|
|
560
602
|
type: 'heading',
|
|
561
603
|
level: 'chapter',
|
|
562
|
-
children: everyChildIsType('text', traverse(), 'heading'),
|
|
604
|
+
children: everyChildIsType('text', traverse(), 'heading', context),
|
|
563
605
|
}),
|
|
564
|
-
'h2,h3': ($el, traverse) => ({
|
|
606
|
+
'h2,h3': ($el, traverse, context) => ({
|
|
565
607
|
type: 'heading',
|
|
566
608
|
level: 'subheading',
|
|
567
|
-
children: everyChildIsType('text', traverse(), 'heading'),
|
|
609
|
+
children: everyChildIsType('text', traverse(), 'heading', context),
|
|
568
610
|
}),
|
|
569
611
|
'ft-content[type="http://www.ft.com/ontology/content/ClipSet"]': ($el) => ({
|
|
570
612
|
type: 'clip-set',
|