@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 +14 -0
- package/lib/generated/index.d.ts +3 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.js.map +1 -1
- package/lib/resolvers/content-tree/Workarounds.d.ts +4 -1
- package/lib/resolvers/content-tree/bodyXMLToTree.js +15 -0
- package/lib/resolvers/content-tree/bodyXMLToTree.js.map +1 -1
- package/lib/resolvers/content-tree/bodyXMLToTree.test.js +30 -2
- package/lib/resolvers/content-tree/bodyXMLToTree.test.js.map +1 -1
- package/lib/resolvers/content-tree/nodePredicates.d.ts +1 -1
- package/lib/resolvers/content-tree/nodePredicates.js +21 -28
- package/lib/resolvers/content-tree/nodePredicates.js.map +1 -1
- package/lib/resolvers/content-tree/references/Recommended.d.ts +1 -0
- package/lib/resolvers/content-tree/references/Recommended.js +5 -0
- package/lib/resolvers/content-tree/references/Recommended.js.map +1 -1
- package/package.json +1 -1
- package/queries/article.graphql +1 -0
- package/src/generated/index.ts +3 -0
- package/src/index.ts +8 -0
- package/src/resolvers/content-tree/Workarounds.ts +5 -1
- package/src/resolvers/content-tree/bodyXMLToTree.test.ts +32 -3
- package/src/resolvers/content-tree/bodyXMLToTree.ts +18 -0
- package/src/resolvers/content-tree/nodePredicates.ts +24 -21
- package/src/resolvers/content-tree/references/Recommended.ts +8 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/typedefs/references/recommended.graphql +3 -0
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
|
|
package/lib/generated/index.d.ts
CHANGED
|
@@ -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;
|
|
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
|
|
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;
|
|
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":
|
|
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":
|
|
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":";;;;;AACA,oEAA4D;AAC5D,gEAAgC;AAChC,2DAAuD;
|
|
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" | "
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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":";;;
|
|
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
package/queries/article.graphql
CHANGED
package/src/generated/index.ts
CHANGED
|
@@ -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
|
-
|
|
|
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":
|
|
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":
|
|
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
|
-
|
|
29
|
-
|
|
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
|
-
|
|
53
|
-
|
|
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
|
-
|
|
78
|
-
|
|
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
|