@financial-times/cp-content-pipeline-schema 1.3.8 → 1.3.9
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 +7 -0
- package/lib/model/CapiResponse.js +4 -5
- package/lib/model/CapiResponse.js.map +1 -1
- package/lib/model/Concept.js +4 -5
- package/lib/model/Concept.js.map +1 -1
- package/lib/model/Concept.test.js +2 -0
- package/lib/model/Concept.test.js.map +1 -1
- package/lib/model/Image.js +4 -4
- package/lib/model/Image.js.map +1 -1
- package/lib/resolvers/content-tree/bodyXMLToTree.test.js +20 -42
- package/lib/resolvers/content-tree/bodyXMLToTree.test.js.map +1 -1
- package/lib/resolvers/content-tree/nodePredicates.js +8 -9
- package/lib/resolvers/content-tree/nodePredicates.js.map +1 -1
- package/lib/resolvers/content-tree/references/Flourish.js +2 -3
- package/lib/resolvers/content-tree/references/Flourish.js.map +1 -1
- package/lib/resolvers/content-tree/references/RawImage.js +2 -3
- package/lib/resolvers/content-tree/references/RawImage.js.map +1 -1
- package/lib/resolvers/content-tree/references/Recommended.js +2 -3
- package/lib/resolvers/content-tree/references/Recommended.js.map +1 -1
- package/lib/resolvers/content-tree/references/Tweet.js +2 -3
- package/lib/resolvers/content-tree/references/Tweet.js.map +1 -1
- package/package.json +1 -1
- package/src/model/CapiResponse.ts +4 -5
- package/src/model/Concept.test.ts +2 -0
- package/src/model/Concept.ts +4 -5
- package/src/model/Image.ts +4 -4
- package/src/resolvers/content-tree/bodyXMLToTree.test.ts +22 -20
- package/src/resolvers/content-tree/nodePredicates.ts +8 -9
- package/src/resolvers/content-tree/references/Flourish.ts +2 -3
- package/src/resolvers/content-tree/references/RawImage.ts +2 -3
- package/src/resolvers/content-tree/references/Recommended.ts +2 -3
- package/src/resolvers/content-tree/references/Tweet.ts +2 -3
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -8,7 +8,6 @@ import conceptIds from '@financial-times/n-concept-ids'
|
|
|
8
8
|
import metadata, { TeaserMetadata } from '@financial-times/n-display-metadata'
|
|
9
9
|
import cloneDeep from 'clone-deep'
|
|
10
10
|
import { ConditionalKeys } from 'type-fest'
|
|
11
|
-
import { logRecoverableError } from '@dotcom-reliability-kit/log-error'
|
|
12
11
|
import { OperationalError } from '@dotcom-reliability-kit/errors'
|
|
13
12
|
|
|
14
13
|
import type { QueryContext } from '..'
|
|
@@ -138,8 +137,8 @@ export class CapiResponse {
|
|
|
138
137
|
* Don't let this failure block this system from continuing to try and handle the request
|
|
139
138
|
*/
|
|
140
139
|
if (!schemaResponse.success) {
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
context.logger.error({
|
|
141
|
+
event: 'RECOVERABLE_ERROR',
|
|
143
142
|
error: new OperationalError({
|
|
144
143
|
message:
|
|
145
144
|
'The data received from the CAPI data source does not match our data source schema. It is likely that our schema will require updating to handle all possible responses from CAPI.',
|
|
@@ -219,8 +218,8 @@ export class CapiResponse {
|
|
|
219
218
|
return vanityUrl ?? url
|
|
220
219
|
} catch (error) {
|
|
221
220
|
if (isError(error)) {
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
this.context.logger.error({
|
|
222
|
+
event: 'RECOVERABLE_ERROR',
|
|
224
223
|
error,
|
|
225
224
|
})
|
|
226
225
|
}
|
|
@@ -4,6 +4,7 @@ import type { QueryContext } from '..'
|
|
|
4
4
|
import { capiPerson } from '../fixtures/capiPerson'
|
|
5
5
|
import { URLManagementDataSource } from '../datasources/url-management'
|
|
6
6
|
import { CapiDataSource } from '../datasources/capi'
|
|
7
|
+
import { Logger } from '@dotcom-reliability-kit/logger'
|
|
7
8
|
|
|
8
9
|
const vanityMock = jest.fn<URLManagementDataSource['get']>()
|
|
9
10
|
const getPersonMock = jest.fn<CapiDataSource['getPerson']>()
|
|
@@ -14,6 +15,7 @@ const context = {
|
|
|
14
15
|
vanityUrls: { get: vanityMock },
|
|
15
16
|
},
|
|
16
17
|
systemCode: 'image-test',
|
|
18
|
+
logger: new Logger(),
|
|
17
19
|
} as unknown as QueryContext
|
|
18
20
|
|
|
19
21
|
const topic = {
|
package/src/model/Concept.ts
CHANGED
|
@@ -3,7 +3,6 @@ import type { QueryContext } from '..'
|
|
|
3
3
|
import { uuidFromUrl } from '../helpers/metadata'
|
|
4
4
|
import imageServiceUrl from '../helpers/imageService'
|
|
5
5
|
import isError from '../helpers/isError'
|
|
6
|
-
import { logRecoverableError } from '@dotcom-reliability-kit/log-error'
|
|
7
6
|
import conceptIds from '@financial-times/n-concept-ids'
|
|
8
7
|
import decorateHeadshotUrl, { UUID_REGEX } from '../helpers/decorateHeadshotUrl'
|
|
9
8
|
|
|
@@ -151,8 +150,8 @@ export class Concept {
|
|
|
151
150
|
}
|
|
152
151
|
} catch (error) {
|
|
153
152
|
if (isError(error)) {
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
this.context.logger.error({
|
|
154
|
+
event: 'RECOVERABLE_ERROR',
|
|
156
155
|
error,
|
|
157
156
|
})
|
|
158
157
|
}
|
|
@@ -184,8 +183,8 @@ export class Concept {
|
|
|
184
183
|
: null
|
|
185
184
|
} catch (error) {
|
|
186
185
|
if (isError(error)) {
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
this.context.logger.error({
|
|
187
|
+
event: 'RECOVERABLE_ERROR',
|
|
189
188
|
error,
|
|
190
189
|
})
|
|
191
190
|
}
|
package/src/model/Image.ts
CHANGED
|
@@ -6,7 +6,6 @@ import type {
|
|
|
6
6
|
LeadImage,
|
|
7
7
|
} from '../types/internal-content'
|
|
8
8
|
import type { QueryContext } from '..'
|
|
9
|
-
import { logRecoverableError } from '@dotcom-reliability-kit/log-error/lib'
|
|
10
9
|
import {
|
|
11
10
|
LiteralUnionScalarValues,
|
|
12
11
|
validLiteralUnionValue,
|
|
@@ -60,7 +59,8 @@ export class CAPIImage implements Image {
|
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
// we shouldn't be here. but just in case,
|
|
63
|
-
|
|
62
|
+
this.context.logger.error({
|
|
63
|
+
event: 'RECOVERABLE_ERROR',
|
|
64
64
|
error: new BaseError({
|
|
65
65
|
code: 'INVALID_IMAGE_TYPE',
|
|
66
66
|
type: this.capiImage['type'], // capiImage is `never` here because we've exhausted all the "possible" types in the switch
|
|
@@ -169,9 +169,9 @@ export class CAPIImage implements Image {
|
|
|
169
169
|
return imageMetadata
|
|
170
170
|
} catch (error) {
|
|
171
171
|
if (isError(error)) {
|
|
172
|
-
|
|
172
|
+
this.context.logger.error({
|
|
173
|
+
event: 'RECOVERABLE_ERROR',
|
|
173
174
|
error,
|
|
174
|
-
logger: this.context.logger,
|
|
175
175
|
})
|
|
176
176
|
}
|
|
177
177
|
return null
|
|
@@ -1,18 +1,20 @@
|
|
|
1
|
-
jest.mock('@dotcom-reliability-kit/log-error', () => ({
|
|
2
|
-
logRecoverableError: jest.fn(),
|
|
3
|
-
}))
|
|
4
|
-
|
|
5
1
|
import { ContentTree } from '@financial-times/content-tree'
|
|
6
2
|
import bodyXMLToTree, { TagMappings } from './bodyXMLToTree'
|
|
7
3
|
import tags from './tagMappings'
|
|
4
|
+
import { Logger } from '@dotcom-reliability-kit/logger'
|
|
5
|
+
import { QueryContext } from '../..'
|
|
6
|
+
|
|
7
|
+
const mockLogger = new Logger()
|
|
8
|
+
const mockLogError = jest.spyOn(mockLogger, 'error')
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
const mockContext = {
|
|
11
|
+
logger: mockLogger,
|
|
12
|
+
} as QueryContext
|
|
11
13
|
|
|
12
14
|
describe('bodyXMLToTree', () => {
|
|
13
15
|
it('converts XML to tree', () => {
|
|
14
16
|
const xml = `<body><p>Hello world</p></body>`
|
|
15
|
-
expect(bodyXMLToTree(xml, tags)).toMatchInlineSnapshot(`
|
|
17
|
+
expect(bodyXMLToTree(xml, tags, mockContext)).toMatchInlineSnapshot(`
|
|
16
18
|
Object {
|
|
17
19
|
"children": Array [
|
|
18
20
|
Object {
|
|
@@ -218,14 +220,14 @@ describe('bodyXMLToTree', () => {
|
|
|
218
220
|
"version": 1,
|
|
219
221
|
}
|
|
220
222
|
`)
|
|
221
|
-
expect(
|
|
223
|
+
expect(mockLogError).not.toBeCalled()
|
|
222
224
|
})
|
|
223
225
|
|
|
224
226
|
it('should handle heading and slots', () => {
|
|
225
227
|
const xml =
|
|
226
228
|
'<body><div class="n-content-layout"><h3></h3><div class="n-content-layout__slot"></div><div class="n-content-layout__slot"></div></body>'
|
|
227
229
|
|
|
228
|
-
expect(bodyXMLToTree(xml, tags)).toMatchInlineSnapshot(`
|
|
230
|
+
expect(bodyXMLToTree(xml, tags, mockContext)).toMatchInlineSnapshot(`
|
|
229
231
|
Object {
|
|
230
232
|
"children": Array [
|
|
231
233
|
Object {
|
|
@@ -253,14 +255,14 @@ describe('bodyXMLToTree', () => {
|
|
|
253
255
|
"version": 1,
|
|
254
256
|
}
|
|
255
257
|
`)
|
|
256
|
-
expect(
|
|
258
|
+
expect(mockLogError).not.toBeCalled()
|
|
257
259
|
})
|
|
258
260
|
|
|
259
261
|
it('should log an error on unexpected child after heading', () => {
|
|
260
262
|
const xml =
|
|
261
263
|
'<body><div class="n-content-layout"><h3></h3><div class="n-content-layout__slot"></div><p></p></body>'
|
|
262
264
|
|
|
263
|
-
expect(bodyXMLToTree(xml, tags)).toMatchInlineSnapshot(`
|
|
265
|
+
expect(bodyXMLToTree(xml, tags, mockContext)).toMatchInlineSnapshot(`
|
|
264
266
|
Object {
|
|
265
267
|
"children": Array [
|
|
266
268
|
Object {
|
|
@@ -288,12 +290,12 @@ describe('bodyXMLToTree', () => {
|
|
|
288
290
|
"version": 1,
|
|
289
291
|
}
|
|
290
292
|
`)
|
|
291
|
-
expect(
|
|
292
|
-
expect(
|
|
293
|
+
expect(mockLogError).toBeCalled()
|
|
294
|
+
expect(mockLogError.mock.lastCall).toMatchInlineSnapshot(`
|
|
293
295
|
Array [
|
|
294
296
|
Object {
|
|
295
297
|
"error": [OperationalError: Unexpected children types for layout],
|
|
296
|
-
"
|
|
298
|
+
"event": "RECOVERABLE_ERROR",
|
|
297
299
|
},
|
|
298
300
|
]
|
|
299
301
|
`)
|
|
@@ -303,7 +305,7 @@ describe('bodyXMLToTree', () => {
|
|
|
303
305
|
const xml =
|
|
304
306
|
'<body><div class="n-content-layout"><div class="n-content-layout__slot"></div><p></p></body>'
|
|
305
307
|
|
|
306
|
-
expect(bodyXMLToTree(xml, tags)).toMatchInlineSnapshot(`
|
|
308
|
+
expect(bodyXMLToTree(xml, tags, mockContext)).toMatchInlineSnapshot(`
|
|
307
309
|
Object {
|
|
308
310
|
"children": Array [
|
|
309
311
|
Object {
|
|
@@ -326,12 +328,12 @@ describe('bodyXMLToTree', () => {
|
|
|
326
328
|
"version": 1,
|
|
327
329
|
}
|
|
328
330
|
`)
|
|
329
|
-
expect(
|
|
330
|
-
expect(
|
|
331
|
+
expect(mockLogError).toBeCalled()
|
|
332
|
+
expect(mockLogError.mock.lastCall).toMatchInlineSnapshot(`
|
|
331
333
|
Array [
|
|
332
334
|
Object {
|
|
333
335
|
"error": [OperationalError: Unexpected children types for layout],
|
|
334
|
-
"
|
|
336
|
+
"event": "RECOVERABLE_ERROR",
|
|
335
337
|
},
|
|
336
338
|
]
|
|
337
339
|
`)
|
|
@@ -343,7 +345,7 @@ describe('bodyXMLToTree', () => {
|
|
|
343
345
|
const xml =
|
|
344
346
|
'<table class="data-table" data-table-collapse-rownum="" data-table-layout-largescreen="auto" data-table-layout-smallscreen="auto" data-table-theme="auto"><caption>Nulla iaculis tempus augue</caption><thead><tr><th data-column-hidden="none" data-column-sortable="false" data-column-type="string">libero mollis</th><th data-column-hidden="none" data-column-sortable="false" data-column-type="string">pretium nunc</th><th data-column-hidden="none" data-column-sortable="false" data-column-type="string">euismod nunc</th></tr></thead><tbody><tr><td>Aenean </td><td>14134</td><td>dfdsfd</td></tr><tr><td>lobortis </td><td>3434</td><td>fdsf dsf </td></tr><tr><td>volutpat </td><td>234234</td><td>sd fsd</td></tr><tr><td>vitae </td><td>2423</td><td>s fsdf</td></tr><tr><td>elementumus</td><td>23423</td><td>f sdf</td></tr></tbody><tfoot><tr><td colspan="1000">Aenean sodales sapien</td></tr></tfoot></table>'
|
|
345
347
|
|
|
346
|
-
expect(bodyXMLToTree(xml, tags)).toMatchInlineSnapshot(`
|
|
348
|
+
expect(bodyXMLToTree(xml, tags, mockContext)).toMatchInlineSnapshot(`
|
|
347
349
|
Object {
|
|
348
350
|
"children": Array [
|
|
349
351
|
Object {
|
|
@@ -602,7 +604,7 @@ describe('bodyXMLToTree', () => {
|
|
|
602
604
|
const xml =
|
|
603
605
|
'<table class="data-table" id="U1140244733565W0C"><caption>Emerging markets outlook for 2017</caption><tbody><tr><td colspan="2"><p>Brazil</p><p>Brazilian shares were the best-performing asset globally over the 12 months to the end of January, returning 121 per cent, according to data from BofA Merrill Lynch. Brazilian stocks did very well through January, but investors including Lazard and Eastspring have scaled back their exposure after strong growth last year.</p></td></tr></tbody></table>'
|
|
604
606
|
|
|
605
|
-
expect(bodyXMLToTree(xml, tags)).toMatchInlineSnapshot(`
|
|
607
|
+
expect(bodyXMLToTree(xml, tags, mockContext)).toMatchInlineSnapshot(`
|
|
606
608
|
Object {
|
|
607
609
|
"children": Array [
|
|
608
610
|
Object {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { logRecoverableError } from '@dotcom-reliability-kit/log-error'
|
|
2
1
|
import { OperationalError } from '@dotcom-reliability-kit/errors'
|
|
3
2
|
import { AnyNode } from './Workarounds'
|
|
4
3
|
import { QueryContext } from '../..'
|
|
@@ -30,8 +29,8 @@ export const findChildOftype = <NodeType extends AnyNode>(
|
|
|
30
29
|
const child = nodes.find(predicate)
|
|
31
30
|
|
|
32
31
|
if (!child) {
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
context?.logger.error({
|
|
33
|
+
event: 'RECOVERABLE_ERROR',
|
|
35
34
|
error: new OperationalError({
|
|
36
35
|
code: 'BODY_XML_UNEXPECTED_STRUCTURE',
|
|
37
36
|
message: `Didn't find expected child type in ${parentType}`,
|
|
@@ -54,8 +53,8 @@ export const everyChildIsType = <NodeType extends AnyNode>(
|
|
|
54
53
|
const allChildrenAreType = nodes.every(predicate)
|
|
55
54
|
|
|
56
55
|
if (!allChildrenAreType) {
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
context?.logger.error({
|
|
57
|
+
event: 'RECOVERABLE_ERROR',
|
|
59
58
|
error: new OperationalError({
|
|
60
59
|
code: 'BODY_XML_UNEXPECTED_STRUCTURE',
|
|
61
60
|
message: `Unexpected children types for ${parentType}`,
|
|
@@ -79,8 +78,8 @@ export const childrenOfTypes = <Types extends readonly AnyNode['type'][]>(
|
|
|
79
78
|
const allChildrenAreType = nodes.every(predicate)
|
|
80
79
|
|
|
81
80
|
if (!allChildrenAreType) {
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
context?.logger.error({
|
|
82
|
+
event: 'RECOVERABLE_ERROR',
|
|
84
83
|
error: new OperationalError({
|
|
85
84
|
code: 'BODY_XML_UNEXPECTED_STRUCTURE',
|
|
86
85
|
message: `Unexpected ordered children types for ${parentType}`,
|
|
@@ -118,8 +117,8 @@ export const childrenOfOrderedTypes = <
|
|
|
118
117
|
return nodes
|
|
119
118
|
}
|
|
120
119
|
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
context?.logger.error({
|
|
121
|
+
event: 'RECOVERABLE_ERROR',
|
|
123
122
|
error: new OperationalError({
|
|
124
123
|
code: 'BODY_XML_UNEXPECTED_STRUCTURE',
|
|
125
124
|
message: `Unexpected children types for ${parentType}`,
|
|
@@ -2,7 +2,6 @@ import imageServiceUrl from '../../../helpers/imageService'
|
|
|
2
2
|
import { FlourishResolvers } from '../../../generated'
|
|
3
3
|
import { QueryContext } from '../../..'
|
|
4
4
|
import isError from '../../../helpers/isError'
|
|
5
|
-
import { logRecoverableError } from '@dotcom-reliability-kit/log-error/lib'
|
|
6
5
|
|
|
7
6
|
export const Flourish = {
|
|
8
7
|
async fallbackImage(parent, _args, context) {
|
|
@@ -61,9 +60,9 @@ const getImageMetadata = async (
|
|
|
61
60
|
}
|
|
62
61
|
} catch (error) {
|
|
63
62
|
if (isError(error)) {
|
|
64
|
-
|
|
63
|
+
context.logger.error({
|
|
64
|
+
event: 'RECOVERABLE_ERROR',
|
|
65
65
|
error,
|
|
66
|
-
logger: context.logger,
|
|
67
66
|
})
|
|
68
67
|
}
|
|
69
68
|
return {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Image, ImageSourceArgs } from '../../../model/Image'
|
|
2
2
|
import type { QueryContext } from '../../..'
|
|
3
|
-
import { logRecoverableError } from '@dotcom-reliability-kit/log-error/lib'
|
|
4
3
|
import imageServiceUrl from '../../../helpers/imageService'
|
|
5
4
|
import { RawImage as RawImageNode } from '../Workarounds'
|
|
6
5
|
import { RawImageResolvers } from '../../../generated'
|
|
@@ -47,9 +46,9 @@ class RawImageModel implements Image {
|
|
|
47
46
|
return imageMetadata
|
|
48
47
|
} catch (error) {
|
|
49
48
|
if (isError(error)) {
|
|
50
|
-
|
|
49
|
+
this.context.logger.error({
|
|
50
|
+
event: 'RECOVERABLE_ERROR',
|
|
51
51
|
error,
|
|
52
|
-
logger: this.context.logger,
|
|
53
52
|
})
|
|
54
53
|
}
|
|
55
54
|
return null
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { uuidFromUrl } from '../../../helpers/metadata'
|
|
2
2
|
import { RecommendedResolvers } from '../../../generated'
|
|
3
|
-
import { logRecoverableError } from '@dotcom-reliability-kit/log-error'
|
|
4
3
|
import { OperationalError } from '@dotcom-reliability-kit/errors'
|
|
5
4
|
|
|
6
5
|
export const Recommended = {
|
|
@@ -16,8 +15,8 @@ export const Recommended = {
|
|
|
16
15
|
return content
|
|
17
16
|
} catch (error) {
|
|
18
17
|
if (error instanceof Error) {
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
context.logger.error({
|
|
19
|
+
event: 'RECOVERABLE_ERROR',
|
|
21
20
|
error: new OperationalError({
|
|
22
21
|
code: 'RECOMMENDED_TEASER_ERROR',
|
|
23
22
|
message: `Couldn't load teaser for recommended article ${parent.reference.id}`,
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { logRecoverableError } from '@dotcom-reliability-kit/log-error'
|
|
2
1
|
import { TweetResolvers } from '../../../generated'
|
|
3
2
|
import isError from '../../../helpers/isError'
|
|
4
3
|
|
|
@@ -11,9 +10,9 @@ export const Tweet = {
|
|
|
11
10
|
return tweet.html
|
|
12
11
|
} catch (error) {
|
|
13
12
|
if (isError(error)) {
|
|
14
|
-
|
|
13
|
+
context.logger.error({
|
|
14
|
+
event: 'RECOVERABLE_ERROR',
|
|
15
15
|
error,
|
|
16
|
-
logger: context.logger,
|
|
17
16
|
})
|
|
18
17
|
}
|
|
19
18
|
return null
|