@financial-times/cp-content-pipeline-schema 2.6.1 → 2.7.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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.7.0](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-schema-v2.6.2...cp-content-pipeline-schema-v2.7.0) (2024-04-26)
4
+
5
+
6
+ ### Features
7
+
8
+ * further reading in live blogs - productionisation ([e5ecfe1](https://github.com/Financial-Times/cp-content-pipeline/commit/e5ecfe1ff81389d660d8ed9caa4623f5e4122d03))
9
+
10
+ ## [2.6.2](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-schema-v2.6.1...cp-content-pipeline-schema-v2.6.2) (2024-04-24)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * consolidate bodyXMLToTree errors ([64f082d](https://github.com/Financial-Times/cp-content-pipeline/commit/64f082d6031f589268c98f923aab43044424f97b))
16
+
3
17
  ## [2.6.1](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-schema-v2.6.0...cp-content-pipeline-schema-v2.6.1) (2024-04-23)
4
18
 
5
19
 
@@ -1257,6 +1257,8 @@ export type RawImage = Reference & {
1257
1257
  readonly type: Scalars['String']['output'];
1258
1258
  };
1259
1259
  export type Recommended = Reference & {
1260
+ /** Indicates if its inside a live blog */
1261
+ readonly isInLiveBlog?: Maybe<Scalars['Boolean']['output']>;
1260
1262
  /** Recommended references contain teaser thumbnails of related articles. */
1261
1263
  readonly teaser?: Maybe<Teaser>;
1262
1264
  /** The type of the reference, eg. 'recommended'. */
@@ -2341,6 +2343,7 @@ export type RawImageResolvers<ContextType = QueryContext, ParentType extends Res
2341
2343
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
2342
2344
  }>;
2343
2345
  export type RecommendedResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['Recommended'] = ResolversParentTypes['Recommended']> = ResolversObject<{
2346
+ isInLiveBlog: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
2344
2347
  teaser: Resolver<Maybe<ResolversTypes['Teaser']>, ParentType, ContextType>;
2345
2348
  type: Resolver<ResolversTypes['String'], ParentType, ContextType>;
2346
2349
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
package/lib/index.d.ts CHANGED
@@ -1,9 +1,15 @@
1
1
  import { initDataSources, DataSources } from './datasources';
2
2
  import type { KeyValueCache } from '@apollo/utils.keyvaluecache';
3
3
  import type { Logger } from '@dotcom-reliability-kit/logger';
4
+ import { AnyNode } from './resolvers/content-tree/Workarounds';
4
5
  interface Metrics {
5
6
  count(metric: string | string[], count?: number): void;
6
7
  }
8
+ export type BodyXMLToTreeError = {
9
+ message: string;
10
+ expected: AnyNode['type'] | readonly AnyNode['type'][];
11
+ actual: AnyNode['type'] | AnyNode['type'][];
12
+ };
7
13
  export interface QueryContext {
8
14
  redisAdapter: KeyValueCache;
9
15
  metrics: Metrics;
@@ -16,6 +22,9 @@ export interface QueryContext {
16
22
  api: string;
17
23
  schema: string;
18
24
  };
25
+ aggregatedErrors?: {
26
+ bodyXMLToTree: BodyXMLToTreeError[];
27
+ };
19
28
  addSurrogateKeys(keys: string[]): void;
20
29
  }
21
30
  export declare const articleDocumentQuery: string;
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAA4D;AAuCnD,gGAvCA,6BAAe,OAuCA;AApCxB,8CAAoD;AACpD,4EAAsE;AACtE,2CAA4B;AAC5B,2BAAiC;AAqBpB,QAAA,oBAAoB,GAAG,IAAA,iBAAY,EAC9C,OAAO,CAAC,OAAO,CAAC,4BAA4B,CAAC,EAC7C,OAAO,CACR,CAAA;AAEY,QAAA,QAAQ,GAAG,IAAA,qBAAc,EACpC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,0BAA0B,CAAC,EAChD;IACE,OAAO,EAAE,CAAC,IAAI,uCAAiB,EAAE,CAAC;CACnC,CACF,CAAA;AAGD,yCAAkD;AAAzC,uHAAA,OAAO,OAAa;AAC7B,+CAAwD;AAA/C,mHAAA,OAAO,OAAW;AAC3B,yCAA0C;AAAjC,+FAAA,OAAO,OAAA;AAEhB,+FAA8E"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,+CAA4D;AA+CnD,gGA/CA,6BAAe,OA+CA;AA5CxB,8CAAoD;AACpD,4EAAsE;AACtE,2CAA4B;AAC5B,2BAAiC;AA6BpB,QAAA,oBAAoB,GAAG,IAAA,iBAAY,EAC9C,OAAO,CAAC,OAAO,CAAC,4BAA4B,CAAC,EAC7C,OAAO,CACR,CAAA;AAEY,QAAA,QAAQ,GAAG,IAAA,qBAAc,EACpC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,0BAA0B,CAAC,EAChD;IACE,OAAO,EAAE,CAAC,IAAI,uCAAiB,EAAE,CAAC;CACnC,CACF,CAAA;AAGD,yCAAkD;AAAzC,uHAAA,OAAO,OAAa;AAC7B,+CAAwD;AAA/C,mHAAA,OAAO,OAAW;AAC3B,yCAA0C;AAAjC,+FAAA,OAAO,OAAA;AAEhB,+FAA8E"}
@@ -95,4 +95,7 @@ export interface TableCell extends ContentTree.Parent {
95
95
  heading?: boolean;
96
96
  children: ContentTree.Phrasing[];
97
97
  }
98
- export type AnyNode = ContentTree.Root | ContentTree.Body | ContentTree.Text | ContentTree.Break | ContentTree.ThematicBreak | ContentTree.Paragraph | ContentTree.Heading | ContentTree.Strong | ContentTree.Emphasis | ContentTree.Strikethrough | ContentTree.Link | ContentTree.List | ContentTree.ListItem | ContentTree.Blockquote | ContentTree.Pullquote | ContentTree.ImageSet | ClipSet | OldClip | ContentTree.Recommended | ContentTree.Tweet | ContentTree.Flourish | ContentTree.BigNumber | ContentTree.ScrollyBlock | ContentTree.ScrollySection | ContentTree.ScrollyCopy | ContentTree.ScrollyHeading | ContentTree.ScrollyImage | ContentTree.Layout | ContentTree.LayoutSlot | ContentTree.LayoutImage | Table | TableCaption | TableFooter | TableBody | TableRow | TableCell | Video | YoutubeVideo | MainImage | MainImageRaw | RawImage | AuthorLink | Cite;
98
+ export interface Recommended extends ContentTree.Recommended {
99
+ isInLiveBlog?: boolean;
100
+ }
101
+ export type AnyNode = ContentTree.Root | ContentTree.Body | ContentTree.Text | ContentTree.Break | ContentTree.ThematicBreak | ContentTree.Paragraph | ContentTree.Heading | ContentTree.Strong | ContentTree.Emphasis | ContentTree.Strikethrough | ContentTree.Link | ContentTree.List | ContentTree.ListItem | ContentTree.Blockquote | ContentTree.Pullquote | ContentTree.ImageSet | ClipSet | OldClip | Recommended | ContentTree.Tweet | ContentTree.Flourish | ContentTree.BigNumber | ContentTree.ScrollyBlock | ContentTree.ScrollySection | ContentTree.ScrollyCopy | ContentTree.ScrollyHeading | ContentTree.ScrollyImage | ContentTree.Layout | ContentTree.LayoutSlot | ContentTree.LayoutImage | Table | TableCaption | TableFooter | TableBody | TableRow | TableCell | Video | YoutubeVideo | MainImage | MainImageRaw | RawImage | AuthorLink | Cite;
@@ -25,6 +25,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  const cheerio = __importStar(require("cheerio"));
27
27
  const domhandler_1 = require("domhandler");
28
+ const errors_1 = require("@dotcom-reliability-kit/errors");
28
29
  function isNode(node) {
29
30
  return Boolean(node && 'type' in node);
30
31
  }
@@ -53,6 +54,7 @@ function bodyXMLToTree(xml, tagMappings, context) {
53
54
  return [];
54
55
  }
55
56
  const body = traverse($('body')[0]);
57
+ logErrors(context);
56
58
  if (Array.isArray(body) || !isNode(body)) {
57
59
  throw new Error(`Unexpected mapping result for body node, received ${JSON.stringify(body)}`);
58
60
  }
@@ -62,4 +64,17 @@ function bodyXMLToTree(xml, tagMappings, context) {
62
64
  return body;
63
65
  }
64
66
  exports.default = bodyXMLToTree;
67
+ function logErrors(context) {
68
+ if (!context?.aggregatedErrors?.bodyXMLToTree.length)
69
+ return;
70
+ context.logger.error({
71
+ event: 'RECOVERABLE_ERROR',
72
+ message: 'Unexpected structure in bodyXMLToTree',
73
+ error: new errors_1.OperationalError({
74
+ code: 'AGGREGATED_BODY_XML_UNEXPECTED_STRUCTURE',
75
+ errors: context.aggregatedErrors?.bodyXMLToTree,
76
+ }),
77
+ });
78
+ context.aggregatedErrors.bodyXMLToTree = [];
79
+ }
65
80
  //# sourceMappingURL=bodyXMLToTree.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bodyXMLToTree.js","sourceRoot":"","sources":["../../../src/resolvers/content-tree/bodyXMLToTree.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAkC;AAKlC,2CAA0C;AAE1C,SAAS,MAAM,CAAC,IAAkC;IAChD,OAAO,OAAO,CAAC,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC,CAAA;AACxC,CAAC;AAUD;;;EAGE;AACF,SAAwB,aAAa,CACnC,GAAW,EACX,WAAwB,EACxB,OAAsB;IAEtB,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAE3B,MAAM,0BAA0B,GAAG,CAAC,QAAwB,EAAa,EAAE,CACzE,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAE5B,SAAS,QAAQ,CAAC,IAAkB;QAClC,IAAI,IAAA,mBAAM,EAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE;YAC7B,OAAO;gBACL,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,IAAI,CAAC,IAAI;aACjB,CAAA;SACF;aAAM,IAAI,IAAA,kBAAK,EAAC,IAAI,CAAC,EAAE;YACtB,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CACnD,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAC7D,CAAA;YAED,IAAI,eAAe,EAAE;gBACnB,MAAM,oBAAoB,GAAG,WAAW,CAAC,eAAe,CAAC,CAAA;gBACzD,OAAO,oBAAoB,CACzB,CAAC,CAAC,IAAI,CAAC,EACP,GAAG,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAC/C,OAAO,CACR,CAAA;aACF;YAED,OAAO,0BAA0B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;SACjD;QAED,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAEnC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;QACxC,MAAM,IAAI,KAAK,CACb,qDAAqD,IAAI,CAAC,SAAS,CACjE,IAAI,CACL,EAAE,CACJ,CAAA;KACF;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;KACzE;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AAnDD,gCAmDC"}
1
+ {"version":3,"file":"bodyXMLToTree.js","sourceRoot":"","sources":["../../../src/resolvers/content-tree/bodyXMLToTree.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA,iDAAkC;AAKlC,2CAA0C;AAC1C,2DAAiE;AAEjE,SAAS,MAAM,CAAC,IAAkC;IAChD,OAAO,OAAO,CAAC,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC,CAAA;AACxC,CAAC;AAUD;;;EAGE;AACF,SAAwB,aAAa,CACnC,GAAW,EACX,WAAwB,EACxB,OAAsB;IAEtB,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IAE3B,MAAM,0BAA0B,GAAG,CAAC,QAAwB,EAAa,EAAE,CACzE,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAE5B,SAAS,QAAQ,CAAC,IAAkB;QAClC,IAAI,IAAA,mBAAM,EAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE;YAC7B,OAAO;gBACL,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,IAAI,CAAC,IAAI;aACjB,CAAA;SACF;aAAM,IAAI,IAAA,kBAAK,EAAC,IAAI,CAAC,EAAE;YACtB,MAAM,eAAe,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CACnD,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAC7D,CAAA;YAED,IAAI,eAAe,EAAE;gBACnB,MAAM,oBAAoB,GAAG,WAAW,CAAC,eAAe,CAAC,CAAA;gBACzD,OAAO,oBAAoB,CACzB,CAAC,CAAC,IAAI,CAAC,EACP,GAAG,EAAE,CAAC,0BAA0B,CAAC,IAAI,CAAC,QAAQ,CAAC,EAC/C,OAAO,CACR,CAAA;aACF;YAED,OAAO,0BAA0B,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;SACjD;QAED,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAEnC,SAAS,CAAC,OAAO,CAAC,CAAA;IAElB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;QACxC,MAAM,IAAI,KAAK,CACb,qDAAqD,IAAI,CAAC,SAAS,CACjE,IAAI,CACL,EAAE,CACJ,CAAA;KACF;IAED,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE;QACxB,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;KACzE;IAED,OAAO,IAAI,CAAA;AACb,CAAC;AArDD,gCAqDC;AAED,SAAS,SAAS,CAAC,OAAsB;IACvC,IAAI,CAAC,OAAO,EAAE,gBAAgB,EAAE,aAAa,CAAC,MAAM;QAAE,OAAM;IAE5D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;QACnB,KAAK,EAAE,mBAAmB;QAC1B,OAAO,EAAE,uCAAuC;QAChD,KAAK,EAAE,IAAI,yBAAgB,CAAC;YAC1B,IAAI,EAAE,0CAA0C;YAChD,MAAM,EAAE,OAAO,CAAC,gBAAgB,EAAE,aAAa;SAChD,CAAC;KACH,CAAC,CAAA;IAEF,OAAO,CAAC,gBAAgB,CAAC,aAAa,GAAG,EAAE,CAAA;AAC7C,CAAC"}
@@ -6,11 +6,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const bodyXMLToTree_1 = __importDefault(require("./bodyXMLToTree"));
7
7
  const tagMappings_1 = __importDefault(require("./tagMappings"));
8
8
  const logger_1 = require("@dotcom-reliability-kit/logger");
9
+ const errors_1 = require("@dotcom-reliability-kit/errors");
9
10
  const mockLogger = new logger_1.Logger();
10
11
  const mockLogError = jest.spyOn(mockLogger, 'error');
11
12
  const mockContext = {
12
13
  logger: mockLogger,
13
14
  };
15
+ expect.addSnapshotSerializer({
16
+ test(value) {
17
+ return value instanceof errors_1.OperationalError;
18
+ },
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ print(value, serialize) {
21
+ return value.data.errors
22
+ .map((error) => serialize(error))
23
+ .join(', ');
24
+ },
25
+ });
14
26
  describe('bodyXMLToTree', () => {
15
27
  it('converts XML to tree', () => {
16
28
  const xml = `<body><p>Hello world</p></body>`;
@@ -269,8 +281,16 @@ describe('bodyXMLToTree', () => {
269
281
  expect(mockLogError.mock.lastCall).toMatchInlineSnapshot(`
270
282
  Array [
271
283
  Object {
272
- "error": [OperationalError: Unexpected children types for layout],
284
+ "error": Object {
285
+ "actual": Array [
286
+ "layout-slot",
287
+ "paragraph",
288
+ ],
289
+ "expected": "layout-slot",
290
+ "message": "Unexpected children types for layout",
291
+ },
273
292
  "event": "RECOVERABLE_ERROR",
293
+ "message": "Unexpected structure in bodyXMLToTree",
274
294
  },
275
295
  ]
276
296
  `);
@@ -304,8 +324,16 @@ describe('bodyXMLToTree', () => {
304
324
  expect(mockLogError.mock.lastCall).toMatchInlineSnapshot(`
305
325
  Array [
306
326
  Object {
307
- "error": [OperationalError: Unexpected children types for layout],
327
+ "error": Object {
328
+ "actual": Array [
329
+ "layout-slot",
330
+ "paragraph",
331
+ ],
332
+ "expected": "layout-slot",
333
+ "message": "Unexpected children types for layout",
334
+ },
308
335
  "event": "RECOVERABLE_ERROR",
336
+ "message": "Unexpected structure in bodyXMLToTree",
309
337
  },
310
338
  ]
311
339
  `);
@@ -1 +1 @@
1
- {"version":3,"file":"bodyXMLToTree.test.js","sourceRoot":"","sources":["../../../src/resolvers/content-tree/bodyXMLToTree.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bodyXMLToTree.test.js","sourceRoot":"","sources":["../../../src/resolvers/content-tree/bodyXMLToTree.test.ts"],"names":[],"mappings":"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"}
@@ -7,5 +7,5 @@ type NodeOfType<Type extends AnyNode['type']> = Extract<AnyNode, {
7
7
  export declare const phrasingTypes: readonly ["text", "break", "strong", "emphasis", "strikethrough", "link"];
8
8
  export declare const findChildOftype: <NodeType extends AnyNode>(type: NodeType["type"], nodes: AnyNode[], parentType: AnyNode['type'], context?: QueryContext) => NodeType | undefined;
9
9
  export declare const everyChildIsType: <NodeType extends AnyNode>(type: NodeType["type"], nodes: AnyNode[], parentType: AnyNode['type'], context?: QueryContext) => NodeType[];
10
- export declare const childrenOfTypes: <Types extends readonly ("layout" | "clip" | "text" | "author-link" | "cite" | "raw-image" | "main-image" | "main-image-raw" | "video" | "youtube-video" | "clip-set" | "table-caption" | "table-body" | "table-footer" | "table" | "break" | "strong" | "emphasis" | "strikethrough" | "link" | "table-row" | "table-cell" | "pullquote" | "image-set" | "root" | "body" | "thematic-break" | "paragraph" | "heading" | "list" | "list-item" | "blockquote" | "recommended" | "tweet" | "flourish" | "big-number" | "scrolly-block" | "scrolly-section" | "scrolly-copy" | "scrolly-heading" | "scrolly-image" | "layout-slot" | "layout-image")[]>(types: Types, nodes: AnyNode[], parentType: AnyNode['type'], context?: QueryContext) => NodeOfType<ValuesOfTuple<Types>>[];
10
+ export declare const childrenOfTypes: <Types extends readonly ("layout" | "clip" | "text" | "author-link" | "cite" | "raw-image" | "main-image" | "main-image-raw" | "video" | "youtube-video" | "clip-set" | "table-caption" | "table-body" | "table-footer" | "table" | "break" | "strong" | "emphasis" | "strikethrough" | "link" | "table-row" | "table-cell" | "pullquote" | "image-set" | "recommended" | "root" | "body" | "thematic-break" | "paragraph" | "heading" | "list" | "list-item" | "blockquote" | "tweet" | "flourish" | "big-number" | "scrolly-block" | "scrolly-section" | "scrolly-copy" | "scrolly-heading" | "scrolly-image" | "layout-slot" | "layout-image")[]>(types: Types, nodes: AnyNode[], parentType: AnyNode['type'], context?: QueryContext) => NodeOfType<ValuesOfTuple<Types>>[];
11
11
  export {};
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.childrenOfTypes = exports.everyChildIsType = exports.findChildOftype = exports.phrasingTypes = void 0;
4
- const errors_1 = require("@dotcom-reliability-kit/errors");
5
4
  exports.phrasingTypes = [
6
5
  'text',
7
6
  'break',
@@ -14,15 +13,11 @@ const findChildOftype = (type, nodes, parentType, context) => {
14
13
  const predicate = (node) => node.type === type;
15
14
  const child = nodes.find(predicate);
16
15
  if (!child) {
17
- context?.logger.error({
18
- event: 'RECOVERABLE_ERROR',
19
- error: new errors_1.OperationalError({
20
- code: 'BODY_XML_UNEXPECTED_STRUCTURE',
21
- message: `Didn't find expected child type in ${parentType}`,
22
- expected: type,
23
- actual: nodes.map((node) => node.type),
24
- }),
25
- });
16
+ recordError({
17
+ message: `Didn't find expected child type in ${parentType}`,
18
+ expected: type,
19
+ actual: nodes.map((node) => node.type),
20
+ }, context);
26
21
  }
27
22
  return child;
28
23
  };
@@ -31,15 +26,11 @@ const everyChildIsType = (type, nodes, parentType, context) => {
31
26
  const predicate = (node) => node.type === type;
32
27
  const allChildrenAreType = nodes.every(predicate);
33
28
  if (!allChildrenAreType) {
34
- context?.logger.error({
35
- event: 'RECOVERABLE_ERROR',
36
- error: new errors_1.OperationalError({
37
- code: 'BODY_XML_UNEXPECTED_STRUCTURE',
38
- message: `Unexpected children types for ${parentType}`,
39
- expected: type,
40
- actual: nodes.map((node) => node.type),
41
- }),
42
- });
29
+ recordError({
30
+ message: `Unexpected children types for ${parentType}`,
31
+ expected: type,
32
+ actual: nodes.map((node) => node.type),
33
+ }, context);
43
34
  }
44
35
  return nodes;
45
36
  };
@@ -48,17 +39,19 @@ const childrenOfTypes = (types, nodes, parentType, context) => {
48
39
  const predicate = (node) => types.includes(node.type);
49
40
  const allChildrenAreType = nodes.every(predicate);
50
41
  if (!allChildrenAreType) {
51
- context?.logger.error({
52
- event: 'RECOVERABLE_ERROR',
53
- error: new errors_1.OperationalError({
54
- code: 'BODY_XML_UNEXPECTED_STRUCTURE',
55
- message: `Unexpected ordered children types for ${parentType}`,
56
- expected: types,
57
- actual: nodes.map((node) => node.type),
58
- }),
59
- });
42
+ recordError({
43
+ message: `Unexpected ordered children types for ${parentType}`,
44
+ expected: types,
45
+ actual: nodes.map((node) => node.type),
46
+ }, context);
60
47
  }
61
48
  return nodes;
62
49
  };
63
50
  exports.childrenOfTypes = childrenOfTypes;
51
+ const recordError = (error, context) => {
52
+ if (!context)
53
+ return;
54
+ context.aggregatedErrors ??= { bodyXMLToTree: [] };
55
+ context.aggregatedErrors.bodyXMLToTree.push(error);
56
+ };
64
57
  //# sourceMappingURL=nodePredicates.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"nodePredicates.js","sourceRoot":"","sources":["../../../src/resolvers/content-tree/nodePredicates.ts"],"names":[],"mappings":";;;AAAA,2DAAiE;AAQpD,QAAA,aAAa,GAAG;IAC3B,MAAM;IACN,OAAO;IACP,QAAQ;IACR,UAAU;IACV,eAAe;IACf,MAAM;CACE,CAAA;AAEH,MAAM,eAAe,GAAG,CAC7B,IAAsB,EACtB,KAAgB,EAChB,UAA2B,EAC3B,OAAsB,EACA,EAAE;IACxB,MAAM,SAAS,GAAG,CAAC,IAAa,EAAoB,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAA;IACzE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAEnC,IAAI,CAAC,KAAK,EAAE;QACV,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;YACpB,KAAK,EAAE,mBAAmB;YAC1B,KAAK,EAAE,IAAI,yBAAgB,CAAC;gBAC1B,IAAI,EAAE,+BAA+B;gBACrC,OAAO,EAAE,sCAAsC,UAAU,EAAE;gBAC3D,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;aACvC,CAAC;SACH,CAAC,CAAA;KACH;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AAtBY,QAAA,eAAe,mBAsB3B;AAEM,MAAM,gBAAgB,GAAG,CAC9B,IAAsB,EACtB,KAAgB,EAChB,UAA2B,EAC3B,OAAsB,EACV,EAAE;IACd,MAAM,SAAS,GAAG,CAAC,IAAa,EAAoB,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAA;IACzE,MAAM,kBAAkB,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IAEjD,IAAI,CAAC,kBAAkB,EAAE;QACvB,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;YACpB,KAAK,EAAE,mBAAmB;YAC1B,KAAK,EAAE,IAAI,yBAAgB,CAAC;gBAC1B,IAAI,EAAE,+BAA+B;gBACrC,OAAO,EAAE,iCAAiC,UAAU,EAAE;gBACtD,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;aACvC,CAAC;SACH,CAAC,CAAA;KACH;IAED,OAAO,KAAmB,CAAA;AAC5B,CAAC,CAAA;AAtBY,QAAA,gBAAgB,oBAsB5B;AAEM,MAAM,eAAe,GAAG,CAC7B,KAAY,EACZ,KAAgB,EAChB,UAA2B,EAC3B,OAAsB,EACc,EAAE;IACtC,MAAM,SAAS,GAAG,CAAC,IAAa,EAA4C,EAAE,CAC5E,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC3B,MAAM,kBAAkB,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IAEjD,IAAI,CAAC,kBAAkB,EAAE;QACvB,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC;YACpB,KAAK,EAAE,mBAAmB;YAC1B,KAAK,EAAE,IAAI,yBAAgB,CAAC;gBAC1B,IAAI,EAAE,+BAA+B;gBACrC,OAAO,EAAE,yCAAyC,UAAU,EAAE;gBAC9D,QAAQ,EAAE,KAAK;gBACf,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;aACvC,CAAC;SACH,CAAC,CAAA;KACH;IAED,OAAO,KAA2C,CAAA;AACpD,CAAC,CAAA;AAvBY,QAAA,eAAe,mBAuB3B"}
1
+ {"version":3,"file":"nodePredicates.js","sourceRoot":"","sources":["../../../src/resolvers/content-tree/nodePredicates.ts"],"names":[],"mappings":";;;AAOa,QAAA,aAAa,GAAG;IAC3B,MAAM;IACN,OAAO;IACP,QAAQ;IACR,UAAU;IACV,eAAe;IACf,MAAM;CACE,CAAA;AAEH,MAAM,eAAe,GAAG,CAC7B,IAAsB,EACtB,KAAgB,EAChB,UAA2B,EAC3B,OAAsB,EACA,EAAE;IACxB,MAAM,SAAS,GAAG,CAAC,IAAa,EAAoB,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAA;IACzE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAEnC,IAAI,CAAC,KAAK,EAAE;QACV,WAAW,CACT;YACE,OAAO,EAAE,sCAAsC,UAAU,EAAE;YAC3D,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;SACvC,EACD,OAAO,CACR,CAAA;KACF;IAED,OAAO,KAAK,CAAA;AACd,CAAC,CAAA;AArBY,QAAA,eAAe,mBAqB3B;AAEM,MAAM,gBAAgB,GAAG,CAC9B,IAAsB,EACtB,KAAgB,EAChB,UAA2B,EAC3B,OAAsB,EACV,EAAE;IACd,MAAM,SAAS,GAAG,CAAC,IAAa,EAAoB,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAA;IACzE,MAAM,kBAAkB,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IAEjD,IAAI,CAAC,kBAAkB,EAAE;QACvB,WAAW,CACT;YACE,OAAO,EAAE,iCAAiC,UAAU,EAAE;YACtD,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;SACvC,EACD,OAAO,CACR,CAAA;KACF;IAED,OAAO,KAAmB,CAAA;AAC5B,CAAC,CAAA;AArBY,QAAA,gBAAgB,oBAqB5B;AAEM,MAAM,eAAe,GAAG,CAC7B,KAAY,EACZ,KAAgB,EAChB,UAA2B,EAC3B,OAAsB,EACc,EAAE;IACtC,MAAM,SAAS,GAAG,CAAC,IAAa,EAA4C,EAAE,CAC5E,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IAC3B,MAAM,kBAAkB,GAAG,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAA;IAEjD,IAAI,CAAC,kBAAkB,EAAE;QACvB,WAAW,CACT;YACE,OAAO,EAAE,yCAAyC,UAAU,EAAE;YAC9D,QAAQ,EAAE,KAAK;YACf,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC;SACvC,EACD,OAAO,CACR,CAAA;KACF;IACD,OAAO,KAA2C,CAAA;AACpD,CAAC,CAAA;AArBY,QAAA,eAAe,mBAqB3B;AAED,MAAM,WAAW,GAAG,CAAC,KAAyB,EAAE,OAAsB,EAAE,EAAE;IACxE,IAAI,CAAC,OAAO;QAAE,OAAM;IAEpB,OAAO,CAAC,gBAAgB,KAAK,EAAE,aAAa,EAAE,EAAE,EAAE,CAAA;IAElD,OAAO,CAAC,gBAAgB,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AACpD,CAAC,CAAA"}
@@ -1,4 +1,5 @@
1
1
  export declare const Recommended: {
2
2
  teaser(parent: import(".").ReferenceWithCAPIData<import("@financial-times/content-tree").ContentTree.Recommended>, _args: {}, context: import("../../..").QueryContext): Promise<import("../../../model/CapiResponse").CapiResponse | null>;
3
3
  type(parent: import(".").ReferenceWithCAPIData<import("@financial-times/content-tree").ContentTree.Recommended>): "recommended";
4
+ isInLiveBlog(parent: import(".").ReferenceWithCAPIData<import("@financial-times/content-tree").ContentTree.Recommended>): boolean;
4
5
  };
@@ -29,5 +29,10 @@ exports.Recommended = {
29
29
  type(parent) {
30
30
  return parent.reference.type;
31
31
  },
32
+ isInLiveBlog(parent) {
33
+ return Boolean(parent?.contentApiData
34
+ ?.types()
35
+ ?.includes('http://www.ft.com/ontology/content/LiveBlogPost'));
36
+ },
32
37
  };
33
38
  //# sourceMappingURL=Recommended.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Recommended.js","sourceRoot":"","sources":["../../../../src/resolvers/content-tree/references/Recommended.ts"],"names":[],"mappings":";;;AAAA,wDAAuD;AAEvD,2DAAiE;AAEpD,QAAA,WAAW,GAAG;IACzB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO;QACjC,IAAI;YACF,IAAI,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CACrD,IAAA,sBAAW,EAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CACjC,CAAA;YAED,IAAI,MAAM,CAAC,SAAS,CAAC,mBAAmB,EAAE;gBACxC,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAA;aACtE;YACD,OAAO,OAAO,CAAA;SACf;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,KAAK,YAAY,KAAK,EAAE;gBAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;oBACnB,KAAK,EAAE,mBAAmB;oBAC1B,KAAK,EAAE,IAAI,yBAAgB,CAAC;wBAC1B,IAAI,EAAE,0BAA0B;wBAChC,OAAO,EAAE,gDAAgD,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE;wBAC9E,KAAK,EAAE,KAAK;qBACb,CAAC;iBACH,CAAC,CAAA;aACH;YAED,OAAO,IAAI,CAAA;SACZ;IACH,CAAC;IAED,IAAI,CAAC,MAAM;QACT,OAAO,MAAM,CAAC,SAAS,CAAC,IAAI,CAAA;IAC9B,CAAC;CAC6B,CAAA"}
1
+ {"version":3,"file":"Recommended.js","sourceRoot":"","sources":["../../../../src/resolvers/content-tree/references/Recommended.ts"],"names":[],"mappings":";;;AAAA,wDAAuD;AAEvD,2DAAiE;AAEpD,QAAA,WAAW,GAAG;IACzB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO;QACjC,IAAI;YACF,IAAI,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CACrD,IAAA,sBAAW,EAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CACjC,CAAA;YAED,IAAI,MAAM,CAAC,SAAS,CAAC,mBAAmB,EAAE;gBACxC,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,SAAS,CAAC,mBAAmB,CAAC,CAAA;aACtE;YACD,OAAO,OAAO,CAAA;SACf;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,KAAK,YAAY,KAAK,EAAE;gBAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;oBACnB,KAAK,EAAE,mBAAmB;oBAC1B,KAAK,EAAE,IAAI,yBAAgB,CAAC;wBAC1B,IAAI,EAAE,0BAA0B;wBAChC,OAAO,EAAE,gDAAgD,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE;wBAC9E,KAAK,EAAE,KAAK;qBACb,CAAC;iBACH,CAAC,CAAA;aACH;YAED,OAAO,IAAI,CAAA;SACZ;IACH,CAAC;IAED,IAAI,CAAC,MAAM;QACT,OAAO,MAAM,CAAC,SAAS,CAAC,IAAI,CAAA;IAC9B,CAAC;IAED,YAAY,CAAC,MAAM;QACjB,OAAO,OAAO,CACZ,MAAM,EAAE,cAAc;YACpB,EAAE,KAAK,EAAE;YACT,EAAE,QAAQ,CAAC,iDAAiD,CAAC,CAChE,CAAA;IACH,CAAC;CAC6B,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@financial-times/cp-content-pipeline-schema",
3
- "version": "2.6.1",
3
+ "version": "2.7.0",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -363,6 +363,7 @@ fragment LayoutImage on LayoutImage {
363
363
  }
364
364
 
365
365
  fragment Recommended on Recommended {
366
+ isInLiveBlog
366
367
  teaser {
367
368
  ...Teaser
368
369
  }
@@ -1307,6 +1307,8 @@ export type RawImage = Reference & {
1307
1307
  };
1308
1308
 
1309
1309
  export type Recommended = Reference & {
1310
+ /** Indicates if its inside a live blog */
1311
+ readonly isInLiveBlog?: Maybe<Scalars['Boolean']['output']>;
1310
1312
  /** Recommended references contain teaser thumbnails of related articles. */
1311
1313
  readonly teaser?: Maybe<Teaser>;
1312
1314
  /** The type of the reference, eg. 'recommended'. */
@@ -2510,6 +2512,7 @@ export type RawImageResolvers<ContextType = QueryContext, ParentType extends Res
2510
2512
  }>;
2511
2513
 
2512
2514
  export type RecommendedResolvers<ContextType = QueryContext, ParentType extends ResolversParentTypes['Recommended'] = ResolversParentTypes['Recommended']> = ResolversObject<{
2515
+ isInLiveBlog: Resolver<Maybe<ResolversTypes['Boolean']>, ParentType, ContextType>;
2513
2516
  teaser: Resolver<Maybe<ResolversTypes['Teaser']>, ParentType, ContextType>;
2514
2517
  type: Resolver<ResolversTypes['String'], ParentType, ContextType>;
2515
2518
  __isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
package/src/index.ts CHANGED
@@ -5,11 +5,18 @@ import { loadSchemaSync } from '@graphql-tools/load'
5
5
  import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'
6
6
  import * as path from 'path'
7
7
  import { readFileSync } from 'fs'
8
+ import { AnyNode } from './resolvers/content-tree/Workarounds'
8
9
 
9
10
  interface Metrics {
10
11
  count(metric: string | string[], count?: number): void
11
12
  }
12
13
 
14
+ export type BodyXMLToTreeError = {
15
+ message: string
16
+ expected: AnyNode['type'] | readonly AnyNode['type'][]
17
+ actual: AnyNode['type'] | AnyNode['type'][]
18
+ }
19
+
13
20
  export interface QueryContext {
14
21
  redisAdapter: KeyValueCache
15
22
  metrics: Metrics
@@ -22,6 +29,7 @@ export interface QueryContext {
22
29
  api: string
23
30
  schema: string
24
31
  }
32
+ aggregatedErrors?: { bodyXMLToTree: BodyXMLToTreeError[] }
25
33
  addSurrogateKeys(keys: string[]): void
26
34
  }
27
35
 
@@ -156,6 +156,10 @@ export interface TableCell extends ContentTree.Parent {
156
156
  children: ContentTree.Phrasing[]
157
157
  }
158
158
 
159
+ export interface Recommended extends ContentTree.Recommended {
160
+ isInLiveBlog?: boolean
161
+ }
162
+
159
163
  export type AnyNode =
160
164
  | ContentTree.Root
161
165
  | ContentTree.Body
@@ -175,7 +179,7 @@ export type AnyNode =
175
179
  | ContentTree.ImageSet
176
180
  | ClipSet
177
181
  | OldClip
178
- | ContentTree.Recommended
182
+ | Recommended
179
183
  | ContentTree.Tweet
180
184
  | ContentTree.Flourish
181
185
  | ContentTree.BigNumber
@@ -2,7 +2,8 @@ import { ContentTree } from '@financial-times/content-tree'
2
2
  import bodyXMLToTree, { TagMappings } from './bodyXMLToTree'
3
3
  import tags from './tagMappings'
4
4
  import { Logger } from '@dotcom-reliability-kit/logger'
5
- import { QueryContext } from '../..'
5
+ import { QueryContext, BodyXMLToTreeError } from '../..'
6
+ import { OperationalError } from '@dotcom-reliability-kit/errors'
6
7
 
7
8
  const mockLogger = new Logger()
8
9
  const mockLogError = jest.spyOn(mockLogger, 'error')
@@ -11,6 +12,18 @@ const mockContext = {
11
12
  logger: mockLogger,
12
13
  } as QueryContext
13
14
 
15
+ expect.addSnapshotSerializer({
16
+ test(value: unknown) {
17
+ return value instanceof OperationalError
18
+ },
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ print(value: any, serialize) {
21
+ return value.data.errors
22
+ .map((error: BodyXMLToTreeError) => serialize(error))
23
+ .join(', ')
24
+ },
25
+ })
26
+
14
27
  describe('bodyXMLToTree', () => {
15
28
  it('converts XML to tree', () => {
16
29
  const xml = `<body><p>Hello world</p></body>`
@@ -294,8 +307,16 @@ describe('bodyXMLToTree', () => {
294
307
  expect(mockLogError.mock.lastCall).toMatchInlineSnapshot(`
295
308
  Array [
296
309
  Object {
297
- "error": [OperationalError: Unexpected children types for layout],
310
+ "error": Object {
311
+ "actual": Array [
312
+ "layout-slot",
313
+ "paragraph",
314
+ ],
315
+ "expected": "layout-slot",
316
+ "message": "Unexpected children types for layout",
317
+ },
298
318
  "event": "RECOVERABLE_ERROR",
319
+ "message": "Unexpected structure in bodyXMLToTree",
299
320
  },
300
321
  ]
301
322
  `)
@@ -332,8 +353,16 @@ describe('bodyXMLToTree', () => {
332
353
  expect(mockLogError.mock.lastCall).toMatchInlineSnapshot(`
333
354
  Array [
334
355
  Object {
335
- "error": [OperationalError: Unexpected children types for layout],
356
+ "error": Object {
357
+ "actual": Array [
358
+ "layout-slot",
359
+ "paragraph",
360
+ ],
361
+ "expected": "layout-slot",
362
+ "message": "Unexpected children types for layout",
363
+ },
336
364
  "event": "RECOVERABLE_ERROR",
365
+ "message": "Unexpected structure in bodyXMLToTree",
337
366
  },
338
367
  ]
339
368
  `)
@@ -4,6 +4,7 @@ import type { ContentTree } from '@financial-times/content-tree'
4
4
  import { AnyNode } from './Workarounds'
5
5
  import { QueryContext } from '../..'
6
6
  import { isTag, isText } from 'domhandler'
7
+ import { OperationalError } from '@dotcom-reliability-kit/errors'
7
8
 
8
9
  function isNode(node: ContentTree.Node | undefined): node is ContentTree.Node {
9
10
  return Boolean(node && 'type' in node)
@@ -59,6 +60,8 @@ export default function bodyXMLToTree(
59
60
 
60
61
  const body = traverse($('body')[0])
61
62
 
63
+ logErrors(context)
64
+
62
65
  if (Array.isArray(body) || !isNode(body)) {
63
66
  throw new Error(
64
67
  `Unexpected mapping result for body node, received ${JSON.stringify(
@@ -73,3 +76,18 @@ export default function bodyXMLToTree(
73
76
 
74
77
  return body
75
78
  }
79
+
80
+ function logErrors(context?: QueryContext) {
81
+ if (!context?.aggregatedErrors?.bodyXMLToTree.length) return
82
+
83
+ context.logger.error({
84
+ event: 'RECOVERABLE_ERROR',
85
+ message: 'Unexpected structure in bodyXMLToTree',
86
+ error: new OperationalError({
87
+ code: 'AGGREGATED_BODY_XML_UNEXPECTED_STRUCTURE',
88
+ errors: context.aggregatedErrors?.bodyXMLToTree,
89
+ }),
90
+ })
91
+
92
+ context.aggregatedErrors.bodyXMLToTree = []
93
+ }
@@ -1,6 +1,5 @@
1
- import { OperationalError } from '@dotcom-reliability-kit/errors'
2
1
  import { AnyNode } from './Workarounds'
3
- import { QueryContext } from '../..'
2
+ import { QueryContext, BodyXMLToTreeError } from '../..'
4
3
 
5
4
  type ValuesOfTuple<Tuple extends readonly string[]> = Tuple[number]
6
5
 
@@ -25,15 +24,14 @@ export const findChildOftype = <NodeType extends AnyNode>(
25
24
  const child = nodes.find(predicate)
26
25
 
27
26
  if (!child) {
28
- context?.logger.error({
29
- event: 'RECOVERABLE_ERROR',
30
- error: new OperationalError({
31
- code: 'BODY_XML_UNEXPECTED_STRUCTURE',
27
+ recordError(
28
+ {
32
29
  message: `Didn't find expected child type in ${parentType}`,
33
30
  expected: type,
34
31
  actual: nodes.map((node) => node.type),
35
- }),
36
- })
32
+ },
33
+ context
34
+ )
37
35
  }
38
36
 
39
37
  return child
@@ -49,15 +47,14 @@ export const everyChildIsType = <NodeType extends AnyNode>(
49
47
  const allChildrenAreType = nodes.every(predicate)
50
48
 
51
49
  if (!allChildrenAreType) {
52
- context?.logger.error({
53
- event: 'RECOVERABLE_ERROR',
54
- error: new OperationalError({
55
- code: 'BODY_XML_UNEXPECTED_STRUCTURE',
50
+ recordError(
51
+ {
56
52
  message: `Unexpected children types for ${parentType}`,
57
53
  expected: type,
58
54
  actual: nodes.map((node) => node.type),
59
- }),
60
- })
55
+ },
56
+ context
57
+ )
61
58
  }
62
59
 
63
60
  return nodes as NodeType[]
@@ -74,16 +71,22 @@ export const childrenOfTypes = <Types extends readonly AnyNode['type'][]>(
74
71
  const allChildrenAreType = nodes.every(predicate)
75
72
 
76
73
  if (!allChildrenAreType) {
77
- context?.logger.error({
78
- event: 'RECOVERABLE_ERROR',
79
- error: new OperationalError({
80
- code: 'BODY_XML_UNEXPECTED_STRUCTURE',
74
+ recordError(
75
+ {
81
76
  message: `Unexpected ordered children types for ${parentType}`,
82
77
  expected: types,
83
78
  actual: nodes.map((node) => node.type),
84
- }),
85
- })
79
+ },
80
+ context
81
+ )
86
82
  }
87
-
88
83
  return nodes as NodeOfType<ValuesOfTuple<Types>>[]
89
84
  }
85
+
86
+ const recordError = (error: BodyXMLToTreeError, context?: QueryContext) => {
87
+ if (!context) return
88
+
89
+ context.aggregatedErrors ??= { bodyXMLToTree: [] }
90
+
91
+ context.aggregatedErrors.bodyXMLToTree.push(error)
92
+ }
@@ -32,4 +32,12 @@ export const Recommended = {
32
32
  type(parent) {
33
33
  return parent.reference.type
34
34
  },
35
+
36
+ isInLiveBlog(parent) {
37
+ return Boolean(
38
+ parent?.contentApiData
39
+ ?.types()
40
+ ?.includes('http://www.ft.com/ontology/content/LiveBlogPost')
41
+ )
42
+ },
35
43
  } satisfies RecommendedResolvers