@financial-times/cp-content-pipeline-schema 0.3.1 → 0.3.2
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/datasources/index.d.ts +2 -0
- package/lib/datasources/index.js +2 -0
- package/lib/datasources/index.js.map +1 -1
- package/lib/datasources/twitter.d.ts +5 -0
- package/lib/datasources/twitter.js +11 -0
- package/lib/datasources/twitter.js.map +1 -0
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/model/Byline.js +2 -0
- package/lib/model/Byline.js.map +1 -1
- package/lib/model/Byline.test.js +7 -0
- package/lib/model/Byline.test.js.map +1 -1
- package/lib/richText.d.ts +1 -2
- package/lib/tags/Link.js +1 -1
- package/lib/tags/Link.js.map +1 -1
- package/lib/tags/Tweet.d.ts +17 -0
- package/lib/tags/Tweet.js +40 -0
- package/lib/tags/Tweet.js.map +1 -0
- package/lib/tags/Tweet.test.d.ts +1 -0
- package/lib/tags/Tweet.test.js +71 -0
- package/lib/tags/Tweet.test.js.map +1 -0
- package/lib/tags/index.d.ts +2 -2
- package/lib/tags/index.js +9 -0
- package/lib/tags/index.js.map +1 -1
- package/package.json +1 -1
- package/src/datasources/index.ts +2 -0
- package/src/datasources/twitter.ts +9 -0
- package/src/index.ts +1 -1
- package/src/model/Byline.test.ts +9 -0
- package/src/model/Byline.ts +1 -0
- package/src/model/__snapshots__/Byline.test.ts.snap +14 -0
- package/src/richText.ts +1 -1
- package/src/tags/Link.ts +1 -1
- package/src/tags/Tweet.test.ts +82 -0
- package/src/tags/Tweet.ts +48 -0
- package/src/tags/index.ts +11 -2
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.2](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-schema-v0.3.1...cp-content-pipeline-schema-v0.3.2) (2022-10-18)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add simple html formatting tags ([7f5b229](https://github.com/Financial-Times/cp-content-pipeline/commit/7f5b229162d92f687ea16e1b4a34883179e337da))
|
|
9
|
+
* add tag class for Tweets and basic blockquote ([e5f525a](https://github.com/Financial-Times/cp-content-pipeline/commit/e5f525ac3c89128332852a79e1a580505f1741d0))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* handle bylines without any author data ([5458a1a](https://github.com/Financial-Times/cp-content-pipeline/commit/5458a1ac35749c1503d19ab8773ded9791fd214f))
|
|
15
|
+
* handle errors from twitter api gracefully ([2d285b3](https://github.com/Financial-Times/cp-content-pipeline/commit/2d285b30b1e8a0c7c3c344c97b5a7cbe10a3d304))
|
|
16
|
+
|
|
3
17
|
## [0.3.1](https://github.com/Financial-Times/cp-content-pipeline/compare/cp-content-pipeline-schema-v0.3.0...cp-content-pipeline-schema-v0.3.1) (2022-10-11)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { CapiDataSource } from './capi.js';
|
|
2
2
|
import { OrigamiImageDataSource } from './origami-image.js';
|
|
3
|
+
import { TwitterDataSource } from './twitter.js';
|
|
3
4
|
import { URLManagementDataSource } from './url-management.js';
|
|
4
5
|
export declare const dataSources: () => {
|
|
5
6
|
capi: CapiDataSource;
|
|
6
7
|
origami: OrigamiImageDataSource;
|
|
7
8
|
vanityUrls: URLManagementDataSource;
|
|
9
|
+
twitter: TwitterDataSource;
|
|
8
10
|
};
|
|
9
11
|
export declare type DataSources = ReturnType<typeof dataSources>;
|
package/lib/datasources/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { CapiDataSource } from './capi.js';
|
|
2
2
|
import { OrigamiImageDataSource } from './origami-image.js';
|
|
3
|
+
import { TwitterDataSource } from './twitter.js';
|
|
3
4
|
import { URLManagementDataSource } from './url-management.js';
|
|
4
5
|
export const dataSources = () => ({
|
|
5
6
|
capi: new CapiDataSource(),
|
|
6
7
|
origami: new OrigamiImageDataSource(),
|
|
7
8
|
vanityUrls: new URLManagementDataSource(),
|
|
9
|
+
twitter: new TwitterDataSource(),
|
|
8
10
|
});
|
|
9
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/datasources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAE7D,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,CAAC;IAChC,IAAI,EAAE,IAAI,cAAc,EAAE;IAC1B,OAAO,EAAE,IAAI,sBAAsB,EAAE;IACrC,UAAU,EAAE,IAAI,uBAAuB,EAAE;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/datasources/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAE7D,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,CAAC;IAChC,IAAI,EAAE,IAAI,cAAc,EAAE;IAC1B,OAAO,EAAE,IAAI,sBAAsB,EAAE;IACrC,UAAU,EAAE,IAAI,uBAAuB,EAAE;IACzC,OAAO,EAAE,IAAI,iBAAiB,EAAE;CACjC,CAAC,CAAA"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { InstrumentedRESTDataSource } from './instrumented.js';
|
|
2
|
+
export class TwitterDataSource extends InstrumentedRESTDataSource {
|
|
3
|
+
constructor() {
|
|
4
|
+
super(...arguments);
|
|
5
|
+
this.baseURL = 'https://publish.twitter.com';
|
|
6
|
+
}
|
|
7
|
+
async getTweet(tweetUrl) {
|
|
8
|
+
return this.get(`/oembed?url=${tweetUrl}&omit_script=true`);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=twitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twitter.js","sourceRoot":"","sources":["../../src/datasources/twitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,mBAAmB,CAAA;AAE9D,MAAM,OAAO,iBAAkB,SAAQ,0BAA0B;IAAjE;;QACE,YAAO,GAAG,6BAA6B,CAAA;IAKzC,CAAC;IAHC,KAAK,CAAC,QAAQ,CAAC,QAAgB;QAC7B,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe,QAAQ,mBAAmB,CAAC,CAAA;IAC7D,CAAC;CACF"}
|
package/lib/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { typeDef as RichText, resolvers as richTextResolvers, } from './richText
|
|
|
9
9
|
import { typeDef as Recommended, resolvers as recommendedResolvers, } from './teaser.js';
|
|
10
10
|
import tags from './tags/index.js';
|
|
11
11
|
const tagEntries = Object.entries(tags);
|
|
12
|
-
const tagsWithReferences = tagEntries.filter(([
|
|
12
|
+
const tagsWithReferences = tagEntries.filter(([, tag]) => tag.typeDef);
|
|
13
13
|
const tagTypeDefs = tagsWithReferences.flatMap(([_key, tag]) => tag.typeDef);
|
|
14
14
|
const Reference = gql `union Reference = ${tagsWithReferences
|
|
15
15
|
.flatMap(([key]) => key)
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEjC,OAAO,EAAE,WAAW,EAAe,MAAM,wBAAwB,CAAA;AAEjE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,SAAS,IAAI,cAAc,EAAE,MAAM,YAAY,CAAA;AAC1E,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,SAAS,IAAI,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,EACL,OAAO,IAAI,QAAQ,EACnB,SAAS,IAAI,iBAAiB,GAC/B,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,OAAO,IAAI,WAAW,EACtB,SAAS,IAAI,oBAAoB,GAClC,MAAM,aAAa,CAAA;AACpB,OAAO,IAAI,MAAM,iBAAiB,CAAA;AAGlC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AACvC,MAAM,kBAAkB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEjC,OAAO,EAAE,WAAW,EAAe,MAAM,wBAAwB,CAAA;AAEjE,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,SAAS,IAAI,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,SAAS,IAAI,cAAc,EAAE,MAAM,YAAY,CAAA;AAC1E,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,SAAS,IAAI,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,EACL,OAAO,IAAI,QAAQ,EACnB,SAAS,IAAI,iBAAiB,GAC/B,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,OAAO,IAAI,WAAW,EACtB,SAAS,IAAI,oBAAoB,GAClC,MAAM,aAAa,CAAA;AACpB,OAAO,IAAI,MAAM,iBAAiB,CAAA;AAGlC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AACvC,MAAM,kBAAkB,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;AACtE,MAAM,WAAW,GAAG,kBAAkB,CAAC,OAAO,CAC5C,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,OAAuB,CAC7C,CAAA;AACD,MAAM,SAAS,GAAG,GAAG,CAAA,qBAAqB,kBAAkB;KACzD,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC;KACvB,IAAI,CAAC,KAAK,CAAC,EAAE,CAAA;AAEhB,MAAM,YAAY,GAAG,MAAM,CAAC,WAAW,CACrC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAC9E,CAAA;AAED,MAAM,YAAY,GAAG,GAAG,CAAA;;;;;;;CAOvB,CAAA;AAQD,MAAM,CAAC,MAAM,SAAS,GAGlB;IACF,KAAK,EAAE;QACL,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO;YACjC,OAAO,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACvD,CAAC;QACD,eAAe,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE;YAC5B,OAAO,OAAO,CAAA;QAChB,CAAC;KACF;IAED,SAAS,EAAE;QACT,aAAa,CAAC,GAAsC;YAClD,OAAO,GAAG,CAAC,WAAW,CAAC,IAAI,CAAA;QAC7B,CAAC;KACF;IAED,GAAG,gBAAgB;IACnB,GAAG,gBAAgB;IACnB,GAAG,gBAAgB;IACnB,GAAG,cAAc;IACjB,GAAG,YAAY;IACf,GAAG,eAAe;IAClB,GAAG,iBAAiB;IACpB,GAAG,oBAAoB;CACxB,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,OAAO;IACP,OAAO;IACP,OAAO;IACP,KAAK;IACL,MAAM;IACN,QAAQ;IACR,WAAW;IACX,SAAS;IACT,WAAW;IACX,YAAY;CACb,CAAA;AAED,OAAO,EAAE,WAAW,EAAe,CAAA"}
|
package/lib/model/Byline.js
CHANGED
|
@@ -18,6 +18,8 @@ export class Byline {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
_Byline_instances = new WeakSet(), _Byline_splitBylineByName = function _Byline_splitBylineByName(byline, names) {
|
|
21
|
+
if (!names.length)
|
|
22
|
+
return [byline];
|
|
21
23
|
const regex = new RegExp(`(${names.join('|')})`, 'ig');
|
|
22
24
|
return byline.split(regex).filter((string) => string !== '');
|
|
23
25
|
}, _Byline_buildUrlTree = function _Byline_buildUrlTree(urlMapping, parts) {
|
package/lib/model/Byline.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Byline.js","sourceRoot":"","sources":["../../src/model/Byline.ts"],"names":[],"mappings":";;;;;;AAAA,MAAM,OAAO,MAAM;IACjB,YAAoB,MAAc,EAAU,gBAAqB;QAA7C,WAAM,GAAN,MAAM,CAAQ;QAAU,qBAAgB,GAAhB,gBAAgB,CAAK;;IAAG,CAAC;IAErE,eAAe;QACb,MAAM,KAAK,GAAG,uBAAA,IAAI,oDAAmB,MAAvB,IAAI,EAAoB,IAAI,CAAC,MAAM,EAAE;YACjD,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE;SAChC,CAAC,CAAA;QACF,OAAO,uBAAA,IAAI,+CAAc,MAAlB,IAAI,EAAe,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAA;IACzD,CAAC;
|
|
1
|
+
{"version":3,"file":"Byline.js","sourceRoot":"","sources":["../../src/model/Byline.ts"],"names":[],"mappings":";;;;;;AAAA,MAAM,OAAO,MAAM;IACjB,YAAoB,MAAc,EAAU,gBAAqB;QAA7C,WAAM,GAAN,MAAM,CAAQ;QAAU,qBAAgB,GAAhB,gBAAgB,CAAK;;IAAG,CAAC;IAErE,eAAe;QACb,MAAM,KAAK,GAAG,uBAAA,IAAI,oDAAmB,MAAvB,IAAI,EAAoB,IAAI,CAAC,MAAM,EAAE;YACjD,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE;SAChC,CAAC,CAAA;QACF,OAAO,uBAAA,IAAI,+CAAc,MAAlB,IAAI,EAAe,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAA;IACzD,CAAC;CA+BF;kGA7BoB,MAAc,EAAE,KAAe;IAChD,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IAClC,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACtD,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,CAAA;AAC9D,CAAC,uDAEa,UAA+B,EAAE,KAAe;IAC5D,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QAClC,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAEhC,IAAI,GAAG,EAAE;YACP,OAAO;gBACL,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,YAAY;gBACrB,UAAU,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE;gBACzB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;aAC1C,CAAA;SACF;aAAM;YACL,OAAO;gBACL,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,IAAI;aACZ,CAAA;SACF;IACH,CAAC,CAAC,CAAA;IAEF,OAAO;QACL,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE;KACjC,CAAA;AACH,CAAC"}
|
package/lib/model/Byline.test.js
CHANGED
|
@@ -56,5 +56,12 @@ describe('byline transformation', () => {
|
|
|
56
56
|
const result = byline.buildBylineTree();
|
|
57
57
|
expect(result).toMatchSnapshot();
|
|
58
58
|
});
|
|
59
|
+
test('handles bylines without any matching authors', async () => {
|
|
60
|
+
const bylineText = 'Chris Giles and Nick Ramsbottom in London';
|
|
61
|
+
const authorUrlMapping = new Map([]);
|
|
62
|
+
const byline = new Byline(bylineText, authorUrlMapping);
|
|
63
|
+
const result = byline.buildBylineTree();
|
|
64
|
+
expect(result).toMatchSnapshot();
|
|
65
|
+
});
|
|
59
66
|
});
|
|
60
67
|
//# sourceMappingURL=Byline.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Byline.test.js","sourceRoot":"","sources":["../../src/model/Byline.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,UAAU,GAAG,uBAAuB,CAAA;QAC1C,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;YAC/B;gBACE,aAAa;gBACb,qEAAqE;aACtE;SACF,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,UAAU,GAAG,uCAAuC,CAAA;QAC1D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;YAC/B;gBACE,aAAa;gBACb,qEAAqE;aACtE;YACD;gBACE,aAAa;gBACb,qEAAqE;aACtE;SACF,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,UAAU,GAAG,2CAA2C,CAAA;QAC9D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;YAC/B;gBACE,aAAa;gBACb,qEAAqE;aACtE;SACF,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,UAAU,GAAG,uBAAuB,CAAA;QAC1C,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;YAC/B;gBACE,aAAa;gBACb,qEAAqE;aACtE;YACD;gBACE,aAAa;gBACb,qEAAqE;aACtE;SACF,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
|
1
|
+
{"version":3,"file":"Byline.test.js","sourceRoot":"","sources":["../../src/model/Byline.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,UAAU,GAAG,uBAAuB,CAAA;QAC1C,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;YAC/B;gBACE,aAAa;gBACb,qEAAqE;aACtE;SACF,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,0CAA0C,EAAE,KAAK,IAAI,EAAE;QAC1D,MAAM,UAAU,GAAG,uCAAuC,CAAA;QAC1D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;YAC/B;gBACE,aAAa;gBACb,qEAAqE;aACtE;YACD;gBACE,aAAa;gBACb,qEAAqE;aACtE;SACF,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACxD,MAAM,UAAU,GAAG,2CAA2C,CAAA;QAC9D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;YAC/B;gBACE,aAAa;gBACb,qEAAqE;aACtE;SACF,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,4CAA4C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,UAAU,GAAG,uBAAuB,CAAA;QAC1C,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;YAC/B;gBACE,aAAa;gBACb,qEAAqE;aACtE;YACD;gBACE,aAAa;gBACb,qEAAqE;aACtE;SACF,CAAC,CAAA;QAEF,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,IAAI,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,UAAU,GAAG,2CAA2C,CAAA;QAC9D,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,CAAA;QAEpC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,gBAAgB,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,MAAM,CAAC,eAAe,EAAE,CAAA;QACvC,MAAM,CAAC,MAAM,CAAC,CAAC,eAAe,EAAE,CAAA;IAClC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
|
package/lib/richText.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CapiResponse } from './model/CapiResponse.js';
|
|
2
|
-
declare type RichTextResolverData = {
|
|
2
|
+
export declare type RichTextResolverData = {
|
|
3
3
|
source: string;
|
|
4
4
|
value: string;
|
|
5
5
|
contentApiData?: CapiResponse;
|
|
@@ -11,4 +11,3 @@ export declare const resolvers: {
|
|
|
11
11
|
structured(parent: RichTextResolverData): Promise<unknown>;
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
|
-
export {};
|
package/lib/tags/Link.js
CHANGED
package/lib/tags/Link.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/tags/Link.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAIjC,MAAM,CAAC,MAAM,IAAI,SAAmB,MAAM,IAAI;QAK5C,YAAY,IAAkB;;YAC5B,IAAI,OAAO,CAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,UAAU,0CAAE,IAAI,CAAA,KAAK,QAAQ,EAAE;gBAC9C,IAAI,CAAC,IAAI,GAAG,MAAA,IAAI,CAAC,UAAU,CAAC,IAAI,mCAAI,EAAE,CAAA;aACvC;iBAAM;gBACL,IAAI,CAAC,IAAI,GAAG,EAAE,CAAA;aACf;QACH,CAAC;KAOF;IAfQ,WAAQ,GAAG,
|
|
1
|
+
{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/tags/Link.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAIjC,MAAM,CAAC,MAAM,IAAI,SAAmB,MAAM,IAAI;QAK5C,YAAY,IAAkB;;YAC5B,IAAI,OAAO,CAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,UAAU,0CAAE,IAAI,CAAA,KAAK,QAAQ,EAAE;gBAC9C,IAAI,CAAC,IAAI,GAAG,MAAA,IAAI,CAAC,UAAU,CAAC,IAAI,mCAAI,EAAE,CAAA;aACvC;iBAAM;gBACL,IAAI,CAAC,IAAI,GAAG,EAAE,CAAA;aACf;QACH,CAAC;KAOF;IAfQ,WAAQ,GAAG,wBAAwB;IAUnC,UAAO,GAAG,GAAG,CAAA;;;;GAInB;OACF,CAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TagConstructor } from './index.js';
|
|
2
|
+
import type * as hast from 'hast';
|
|
3
|
+
import { QueryContext } from '../index.js';
|
|
4
|
+
import type { RichTextResolverData } from '../richText.js';
|
|
5
|
+
declare class Tweet {
|
|
6
|
+
tweetUrl: string;
|
|
7
|
+
static selector: string;
|
|
8
|
+
constructor(node: hast.Element);
|
|
9
|
+
embed(context: QueryContext): Promise<RichTextResolverData | null>;
|
|
10
|
+
static resolve: {
|
|
11
|
+
embed: (parent: Tweet, _args: any, context: QueryContext) => Promise<RichTextResolverData | null>;
|
|
12
|
+
tweetUrl: (parent: Tweet) => string;
|
|
13
|
+
};
|
|
14
|
+
static typeDef: import("graphql").DocumentNode;
|
|
15
|
+
}
|
|
16
|
+
declare const TweetClass: TagConstructor<Tweet>;
|
|
17
|
+
export { TweetClass as Tweet };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
import { gql } from 'graphql-tag';
|
|
3
|
+
class Tweet {
|
|
4
|
+
constructor(node) {
|
|
5
|
+
var _b;
|
|
6
|
+
if (((_b = node.properties) === null || _b === void 0 ? void 0 : _b.href) && typeof node.properties.href === 'string') {
|
|
7
|
+
this.tweetUrl = node.properties.href;
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
throw new Error('Embedded tweet is missing a href');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
async embed(context) {
|
|
14
|
+
try {
|
|
15
|
+
const tweet = await context.dataSources.twitter.getTweet(this.tweetUrl);
|
|
16
|
+
return {
|
|
17
|
+
source: 'twitter',
|
|
18
|
+
value: tweet.html,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
_a = Tweet;
|
|
27
|
+
Tweet.selector = 'a[dataAssetType="tweet"]';
|
|
28
|
+
Tweet.resolve = {
|
|
29
|
+
embed: async (parent, _args, context) => parent.embed(context),
|
|
30
|
+
tweetUrl: (parent) => parent.tweetUrl,
|
|
31
|
+
};
|
|
32
|
+
Tweet.typeDef = gql `
|
|
33
|
+
type Tweet {
|
|
34
|
+
tweetUrl: String
|
|
35
|
+
embed: RichText
|
|
36
|
+
}
|
|
37
|
+
`;
|
|
38
|
+
const TweetClass = Tweet;
|
|
39
|
+
export { TweetClass as Tweet };
|
|
40
|
+
//# sourceMappingURL=Tweet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tweet.js","sourceRoot":"","sources":["../../src/tags/Tweet.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAMjC,MAAM,KAAK;IAKT,YAAY,IAAkB;;QAC5B,IAAI,CAAA,MAAA,IAAI,CAAC,UAAU,0CAAE,IAAI,KAAI,OAAO,IAAI,CAAC,UAAU,CAAC,IAAI,KAAK,QAAQ,EAAE;YACrE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAA;SACrC;aAAM;YACL,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAA;SACpD;IACH,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAqB;QAC/B,IAAI;YACF,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YACvE,OAAO;gBACL,MAAM,EAAE,SAAS;gBACjB,KAAK,EAAE,KAAK,CAAC,IAAI;aAClB,CAAA;SACF;QAAC,OAAO,GAAG,EAAE;YACZ,OAAO,IAAI,CAAA;SACZ;IACH,CAAC;;;AApBM,cAAQ,GAAG,0BAA0B,CAAA;AAsBrC,aAAO,GAAG;IACf,KAAK,EAAE,KAAK,EAAE,MAAa,EAAE,KAAU,EAAE,OAAqB,EAAE,EAAE,CAChE,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;IACvB,QAAQ,EAAE,CAAC,MAAa,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ;CAC7C,CAAA;AAEM,aAAO,GAAG,GAAG,CAAA;;;;;GAKnB,CAAA;AAGH,MAAM,UAAU,GAA0B,KAAK,CAAA;AAE/C,OAAO,EAAE,UAAU,IAAI,KAAK,EAAE,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Tweet } from './Tweet.js';
|
|
2
|
+
import { select } from 'hast-util-select';
|
|
3
|
+
import { unified } from 'unified';
|
|
4
|
+
import rehypeParse from 'rehype-parse';
|
|
5
|
+
import { jest } from '@jest/globals';
|
|
6
|
+
async function createAST(input) {
|
|
7
|
+
const formatOutput = function formatOutput() {
|
|
8
|
+
this.Compiler = (tree) => tree;
|
|
9
|
+
};
|
|
10
|
+
const body = await unified()
|
|
11
|
+
.use(rehypeParse, { fragment: true })
|
|
12
|
+
.use([formatOutput])
|
|
13
|
+
.process(input);
|
|
14
|
+
return body.result;
|
|
15
|
+
}
|
|
16
|
+
describe('Embedded Tweets', () => {
|
|
17
|
+
let body;
|
|
18
|
+
const getTweetMock = jest.fn();
|
|
19
|
+
const context = {
|
|
20
|
+
dataSources: {
|
|
21
|
+
twitter: {
|
|
22
|
+
getTweet: getTweetMock,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
};
|
|
26
|
+
beforeAll(async () => {
|
|
27
|
+
const input = `<body><a href="https://www.twitter.com/blah" data-asset-type="tweet">Tweet</a></body>`;
|
|
28
|
+
body = await createAST(input);
|
|
29
|
+
});
|
|
30
|
+
afterEach(() => {
|
|
31
|
+
jest.resetAllMocks();
|
|
32
|
+
});
|
|
33
|
+
it('correctly matches the content API tag', () => {
|
|
34
|
+
const match = select(Tweet.selector, body);
|
|
35
|
+
expect(match).toBeTruthy();
|
|
36
|
+
});
|
|
37
|
+
it('provides the tweetUrl', () => {
|
|
38
|
+
const node = select(Tweet.selector, body);
|
|
39
|
+
if (!node) {
|
|
40
|
+
throw new Error('Expected a tweet node to be found');
|
|
41
|
+
}
|
|
42
|
+
const tweet = new Tweet(node);
|
|
43
|
+
expect(tweet).toEqual({
|
|
44
|
+
tweetUrl: 'https://www.twitter.com/blah',
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
it('provides the twitter embed code', async () => {
|
|
48
|
+
const node = select(Tweet.selector, body);
|
|
49
|
+
if (!node) {
|
|
50
|
+
throw new Error('Expected a tweet node to be found');
|
|
51
|
+
}
|
|
52
|
+
const tweet = new Tweet(node);
|
|
53
|
+
getTweetMock.mockReturnValue({
|
|
54
|
+
html: '<blockquote>this is an embed</blockquote>',
|
|
55
|
+
});
|
|
56
|
+
expect(await tweet.embed(context)).toEqual({
|
|
57
|
+
source: 'twitter',
|
|
58
|
+
value: '<blockquote>this is an embed</blockquote>',
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
it('handles errors fetching the tweet embed', async () => {
|
|
62
|
+
const node = select(Tweet.selector, body);
|
|
63
|
+
if (!node) {
|
|
64
|
+
throw new Error('Expected a tweet node to be found');
|
|
65
|
+
}
|
|
66
|
+
const tweet = new Tweet(node);
|
|
67
|
+
getTweetMock.mockRejectedValue(new Error('404'));
|
|
68
|
+
expect(await tweet.embed(context)).toEqual(null);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
//# sourceMappingURL=Tweet.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tweet.test.js","sourceRoot":"","sources":["../../src/tags/Tweet.test.ts"],"names":[],"mappings":"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"}
|
package/lib/tags/index.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type { IObjectTypeResolver } from '@graphql-tools/utils';
|
|
|
3
3
|
import type { DocumentNode } from 'graphql';
|
|
4
4
|
import type { CapiResponse } from '../model/CapiResponse.js';
|
|
5
5
|
export declare type Tag = object;
|
|
6
|
-
export interface TagConstructor {
|
|
7
|
-
new (node: hast.Element, contentApiData?: CapiResponse):
|
|
6
|
+
export interface TagConstructor<T = Tag> {
|
|
7
|
+
new (node: hast.Element, contentApiData?: CapiResponse): T;
|
|
8
8
|
selector: string;
|
|
9
9
|
typeDef?: DocumentNode;
|
|
10
10
|
resolve?: IObjectTypeResolver;
|
package/lib/tags/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { LayoutImage } from './LayoutImage.js';
|
|
|
3
3
|
import { ImageSet } from './ImageSet.js';
|
|
4
4
|
import { PullQuote } from './PullQuote.js';
|
|
5
5
|
import { Recommended } from './Recommended.js';
|
|
6
|
+
import { Tweet } from './Tweet.js';
|
|
6
7
|
function createTagWithoutReference(name, selector) {
|
|
7
8
|
var _a;
|
|
8
9
|
const tag = (_a = class {
|
|
@@ -20,6 +21,7 @@ const mapping = {
|
|
|
20
21
|
RecommendedTitle: createTagWithoutReference('RecommendedTitle', 'recommended-title'),
|
|
21
22
|
Paragraph: createTagWithoutReference('Paragraph', 'p'),
|
|
22
23
|
UnorderedList: createTagWithoutReference('UnorderedList', 'ul'),
|
|
24
|
+
OrderedList: createTagWithoutReference('OrderedList', 'ol'),
|
|
23
25
|
ListItem: createTagWithoutReference('ListItem', 'li'),
|
|
24
26
|
Layout: createTagWithoutReference('Layout', '.n-content-layout, .layout'),
|
|
25
27
|
LayoutContainer: createTagWithoutReference('LayoutContainer', '.n-content-layout__container, .layout-container'),
|
|
@@ -28,6 +30,13 @@ const mapping = {
|
|
|
28
30
|
PullQuote,
|
|
29
31
|
PullQuoteText: createTagWithoutReference('PullQuoteText', 'pull-quote-text'),
|
|
30
32
|
PullQuoteSource: createTagWithoutReference('PullQuoteText', 'pull-quote-source'),
|
|
33
|
+
Blockquote: createTagWithoutReference('Blockquote', 'blockquote'),
|
|
34
|
+
Tweet,
|
|
35
|
+
LineBreak: createTagWithoutReference('LineBreak', 'br'),
|
|
36
|
+
HorizontalRule: createTagWithoutReference('HorizontalRule', 'hr'),
|
|
37
|
+
Emphasis: createTagWithoutReference('Emphasis', 'em'),
|
|
38
|
+
Strong: createTagWithoutReference('Strong', 'strong'),
|
|
39
|
+
Strikethrough: createTagWithoutReference('Strikethrough', 's'),
|
|
31
40
|
};
|
|
32
41
|
export default mapping;
|
|
33
42
|
//# sourceMappingURL=index.js.map
|
package/lib/tags/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tags/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tags/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAWlC,SAAS,yBAAyB,CAChC,IAAY,EACZ,QAAgB;;IAEhB,MAAM,GAAG,SAAG;SAEX;QADQ,WAAQ,GAAG,QAAQ;WAC3B,CAAA;IAED,MAAM,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IAEnD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,OAAO,GAAmC;IAC9C,IAAI;IACJ,YAAY,EAAE,yBAAyB,CAAC,cAAc,EAAE,cAAc,CAAC;IACvE,QAAQ;IACR,WAAW;IACX,gBAAgB,EAAE,yBAAyB,CACzC,kBAAkB,EAClB,mBAAmB,CACpB;IACD,SAAS,EAAE,yBAAyB,CAAC,WAAW,EAAE,GAAG,CAAC;IACtD,aAAa,EAAE,yBAAyB,CAAC,eAAe,EAAE,IAAI,CAAC;IAC/D,WAAW,EAAE,yBAAyB,CAAC,aAAa,EAAE,IAAI,CAAC;IAC3D,QAAQ,EAAE,yBAAyB,CAAC,UAAU,EAAE,IAAI,CAAC;IACrD,MAAM,EAAE,yBAAyB,CAAC,QAAQ,EAAE,4BAA4B,CAAC;IACzE,eAAe,EAAE,yBAAyB,CACxC,iBAAiB,EACjB,iDAAiD,CAClD;IACD,UAAU,EAAE,yBAAyB,CACnC,YAAY,EACZ,uCAAuC,CACxC;IACD,WAAW;IACX,SAAS;IACT,aAAa,EAAE,yBAAyB,CAAC,eAAe,EAAE,iBAAiB,CAAC;IAC5E,eAAe,EAAE,yBAAyB,CACxC,eAAe,EACf,mBAAmB,CACpB;IACD,UAAU,EAAE,yBAAyB,CAAC,YAAY,EAAE,YAAY,CAAC;IACjE,KAAK;IACL,SAAS,EAAE,yBAAyB,CAAC,WAAW,EAAE,IAAI,CAAC;IACvD,cAAc,EAAE,yBAAyB,CAAC,gBAAgB,EAAE,IAAI,CAAC;IACjE,QAAQ,EAAE,yBAAyB,CAAC,UAAU,EAAE,IAAI,CAAC;IACrD,MAAM,EAAE,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,CAAC;IACrD,aAAa,EAAE,yBAAyB,CAAC,eAAe,EAAE,GAAG,CAAC;CAC/D,CAAA;AAED,eAAe,OAAO,CAAA"}
|
package/package.json
CHANGED
package/src/datasources/index.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { CapiDataSource } from './capi.js'
|
|
2
2
|
import { OrigamiImageDataSource } from './origami-image.js'
|
|
3
|
+
import { TwitterDataSource } from './twitter.js'
|
|
3
4
|
import { URLManagementDataSource } from './url-management.js'
|
|
4
5
|
|
|
5
6
|
export const dataSources = () => ({
|
|
6
7
|
capi: new CapiDataSource(),
|
|
7
8
|
origami: new OrigamiImageDataSource(),
|
|
8
9
|
vanityUrls: new URLManagementDataSource(),
|
|
10
|
+
twitter: new TwitterDataSource(),
|
|
9
11
|
})
|
|
10
12
|
|
|
11
13
|
export type DataSources = ReturnType<typeof dataSources>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { InstrumentedRESTDataSource } from './instrumented.js'
|
|
2
|
+
|
|
3
|
+
export class TwitterDataSource extends InstrumentedRESTDataSource {
|
|
4
|
+
baseURL = 'https://publish.twitter.com'
|
|
5
|
+
|
|
6
|
+
async getTweet(tweetUrl: string) {
|
|
7
|
+
return this.get(`/oembed?url=${tweetUrl}&omit_script=true`)
|
|
8
|
+
}
|
|
9
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -21,7 +21,7 @@ import tags from './tags/index.js'
|
|
|
21
21
|
import type { Metrics } from 'next-metrics'
|
|
22
22
|
|
|
23
23
|
const tagEntries = Object.entries(tags)
|
|
24
|
-
const tagsWithReferences = tagEntries.filter(([
|
|
24
|
+
const tagsWithReferences = tagEntries.filter(([, tag]) => tag.typeDef)
|
|
25
25
|
const tagTypeDefs = tagsWithReferences.flatMap(
|
|
26
26
|
([_key, tag]) => tag.typeDef as DocumentNode
|
|
27
27
|
)
|
package/src/model/Byline.test.ts
CHANGED
|
@@ -64,4 +64,13 @@ describe('byline transformation', () => {
|
|
|
64
64
|
const result = byline.buildBylineTree()
|
|
65
65
|
expect(result).toMatchSnapshot()
|
|
66
66
|
})
|
|
67
|
+
|
|
68
|
+
test('handles bylines without any matching authors', async () => {
|
|
69
|
+
const bylineText = 'Chris Giles and Nick Ramsbottom in London'
|
|
70
|
+
const authorUrlMapping = new Map([])
|
|
71
|
+
|
|
72
|
+
const byline = new Byline(bylineText, authorUrlMapping)
|
|
73
|
+
const result = byline.buildBylineTree()
|
|
74
|
+
expect(result).toMatchSnapshot()
|
|
75
|
+
})
|
|
67
76
|
})
|
package/src/model/Byline.ts
CHANGED
|
@@ -71,6 +71,20 @@ Object {
|
|
|
71
71
|
}
|
|
72
72
|
`;
|
|
73
73
|
|
|
74
|
+
exports[`byline transformation handles bylines without any matching authors 1`] = `
|
|
75
|
+
Object {
|
|
76
|
+
"tree": Object {
|
|
77
|
+
"children": Array [
|
|
78
|
+
Object {
|
|
79
|
+
"type": "text",
|
|
80
|
+
"value": "Chris Giles and Nick Ramsbottom in London",
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
"type": "root",
|
|
84
|
+
},
|
|
85
|
+
}
|
|
86
|
+
`;
|
|
87
|
+
|
|
74
88
|
exports[`byline transformation ignores extra authors in annotations array 1`] = `
|
|
75
89
|
Object {
|
|
76
90
|
"tree": Object {
|
package/src/richText.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { CapiResponse } from './model/CapiResponse.js'
|
|
|
6
6
|
import extractReferences from './unified-plugins/extract-references.js'
|
|
7
7
|
import mapToAbstractTypes from './unified-plugins/map-to-abstract-types.js'
|
|
8
8
|
|
|
9
|
-
type RichTextResolverData = {
|
|
9
|
+
export type RichTextResolverData = {
|
|
10
10
|
source: string
|
|
11
11
|
value: string
|
|
12
12
|
contentApiData?: CapiResponse
|
package/src/tags/Link.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type * as hast from 'hast'
|
|
|
5
5
|
export const Link: TagConstructor = class Link implements Tag {
|
|
6
6
|
href: string
|
|
7
7
|
|
|
8
|
-
static selector = 'a'
|
|
8
|
+
static selector = 'a:not([dataAssetType])'
|
|
9
9
|
|
|
10
10
|
constructor(node: hast.Element) {
|
|
11
11
|
if (typeof node?.properties?.href === 'string') {
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Tweet } from './Tweet.js'
|
|
2
|
+
import { HastNode, select } from 'hast-util-select'
|
|
3
|
+
import { unified, Plugin } from 'unified'
|
|
4
|
+
import rehypeParse from 'rehype-parse'
|
|
5
|
+
import { QueryContext } from '../index.js'
|
|
6
|
+
import { jest } from '@jest/globals'
|
|
7
|
+
|
|
8
|
+
async function createAST(input: string) {
|
|
9
|
+
const formatOutput: Plugin<[], Element, Element> = function formatOutput() {
|
|
10
|
+
this.Compiler = (tree) => tree
|
|
11
|
+
}
|
|
12
|
+
const body = await unified()
|
|
13
|
+
.use(rehypeParse, { fragment: true })
|
|
14
|
+
.use([formatOutput])
|
|
15
|
+
.process(input)
|
|
16
|
+
return body.result as HastNode
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe('Embedded Tweets', () => {
|
|
20
|
+
let body: HastNode
|
|
21
|
+
|
|
22
|
+
const getTweetMock = jest.fn()
|
|
23
|
+
const context = {
|
|
24
|
+
dataSources: {
|
|
25
|
+
twitter: {
|
|
26
|
+
getTweet: getTweetMock,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
} as unknown as QueryContext
|
|
30
|
+
|
|
31
|
+
beforeAll(async () => {
|
|
32
|
+
const input = `<body><a href="https://www.twitter.com/blah" data-asset-type="tweet">Tweet</a></body>`
|
|
33
|
+
body = await createAST(input)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
afterEach(() => {
|
|
37
|
+
jest.resetAllMocks()
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('correctly matches the content API tag', () => {
|
|
41
|
+
const match = select(Tweet.selector, body)
|
|
42
|
+
expect(match).toBeTruthy()
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('provides the tweetUrl', () => {
|
|
46
|
+
const node = select(Tweet.selector, body)
|
|
47
|
+
if (!node) {
|
|
48
|
+
throw new Error('Expected a tweet node to be found')
|
|
49
|
+
}
|
|
50
|
+
const tweet = new Tweet(node)
|
|
51
|
+
expect(tweet).toEqual({
|
|
52
|
+
tweetUrl: 'https://www.twitter.com/blah',
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('provides the twitter embed code', async () => {
|
|
57
|
+
const node = select(Tweet.selector, body)
|
|
58
|
+
if (!node) {
|
|
59
|
+
throw new Error('Expected a tweet node to be found')
|
|
60
|
+
}
|
|
61
|
+
const tweet = new Tweet(node)
|
|
62
|
+
getTweetMock.mockReturnValue({
|
|
63
|
+
html: '<blockquote>this is an embed</blockquote>',
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
expect(await tweet.embed(context)).toEqual({
|
|
67
|
+
source: 'twitter',
|
|
68
|
+
value: '<blockquote>this is an embed</blockquote>',
|
|
69
|
+
})
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('handles errors fetching the tweet embed', async () => {
|
|
73
|
+
const node = select(Tweet.selector, body)
|
|
74
|
+
if (!node) {
|
|
75
|
+
throw new Error('Expected a tweet node to be found')
|
|
76
|
+
}
|
|
77
|
+
const tweet = new Tweet(node)
|
|
78
|
+
getTweetMock.mockRejectedValue(new Error('404'))
|
|
79
|
+
|
|
80
|
+
expect(await tweet.embed(context)).toEqual(null)
|
|
81
|
+
})
|
|
82
|
+
})
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { gql } from 'graphql-tag'
|
|
2
|
+
import type { TagConstructor } from './index.js'
|
|
3
|
+
import type * as hast from 'hast'
|
|
4
|
+
import { QueryContext } from '../index.js'
|
|
5
|
+
import type { RichTextResolverData } from '../richText.js'
|
|
6
|
+
|
|
7
|
+
class Tweet {
|
|
8
|
+
tweetUrl: string
|
|
9
|
+
|
|
10
|
+
static selector = 'a[dataAssetType="tweet"]'
|
|
11
|
+
|
|
12
|
+
constructor(node: hast.Element) {
|
|
13
|
+
if (node.properties?.href && typeof node.properties.href === 'string') {
|
|
14
|
+
this.tweetUrl = node.properties.href
|
|
15
|
+
} else {
|
|
16
|
+
throw new Error('Embedded tweet is missing a href')
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async embed(context: QueryContext): Promise<RichTextResolverData | null> {
|
|
21
|
+
try {
|
|
22
|
+
const tweet = await context.dataSources.twitter.getTweet(this.tweetUrl)
|
|
23
|
+
return {
|
|
24
|
+
source: 'twitter',
|
|
25
|
+
value: tweet.html,
|
|
26
|
+
}
|
|
27
|
+
} catch (err) {
|
|
28
|
+
return null
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static resolve = {
|
|
33
|
+
embed: async (parent: Tweet, _args: any, context: QueryContext) =>
|
|
34
|
+
parent.embed(context),
|
|
35
|
+
tweetUrl: (parent: Tweet) => parent.tweetUrl,
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static typeDef = gql`
|
|
39
|
+
type Tweet {
|
|
40
|
+
tweetUrl: String
|
|
41
|
+
embed: RichText
|
|
42
|
+
}
|
|
43
|
+
`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const TweetClass: TagConstructor<Tweet> = Tweet
|
|
47
|
+
|
|
48
|
+
export { TweetClass as Tweet }
|