1 | function escapeMarkdownPart(input) {
|
2 | return [
|
3 |
|
4 |
|
5 | [/([\#\*\(\)\[\]\_\`\\])/g, '\\$1'],
|
6 |
|
7 |
|
8 | [/\</g, '<'],
|
9 | [/\>/g, '>'],
|
10 |
|
11 |
|
12 | [/\n/g, '<br />']
|
13 |
|
14 | ].reduce((input, [replaceFrom, replaceTo]) => input.replace(replaceFrom, replaceTo), input);
|
15 | }
|
16 |
|
17 | function escapeMarkdown(input) {
|
18 | return escapeMarkdownPart(input)
|
19 |
|
20 | .replace(/^(\d+)\./, '$1\\.');
|
21 | }
|
22 |
|
23 | function renderEntityMention(data) {
|
24 | return `[@${escapeMarkdownPart(data.screen_name)}](https://twitter.com/${data.screen_name} "${data.name}")`;
|
25 | }
|
26 |
|
27 | function renderEntityMedia(data) {
|
28 | return `[${escapeMarkdownPart(data.display_url)}](${data.url})`;
|
29 | }
|
30 |
|
31 | function renderEntityHashtag(data) {
|
32 | return `[#${escapeMarkdownPart(data.text)}](https://twitter.com/search?q=%23${data.text})`;
|
33 | }
|
34 |
|
35 | function renderEntityUrl(data) {
|
36 | return `[${escapeMarkdownPart(data.display_url)}](${data.url} "${data.expanded_url}")`;
|
37 | }
|
38 |
|
39 | function renderEntity(type, data) {
|
40 | switch (type) {
|
41 | case 'user_mentions':
|
42 | return renderEntityMention(data);
|
43 | case 'media':
|
44 | return renderEntityMedia(data);
|
45 | case 'hashtags':
|
46 | return renderEntityHashtag(data);
|
47 | case 'urls':
|
48 | return renderEntityUrl(data);
|
49 | default:
|
50 | return null;
|
51 | }
|
52 | }
|
53 |
|
54 | export default function render(tweet) {
|
55 | const { text, entities = { } } = tweet;
|
56 | const replacements = [];
|
57 |
|
58 | Object.keys(entities).forEach(entityKey => {
|
59 | replacements.push(
|
60 | ...entities[entityKey].map(entity => [
|
61 | renderEntity(entityKey, entity),
|
62 | entity.indices[0],
|
63 | entity.indices[1]
|
64 | ])
|
65 | );
|
66 | });
|
67 |
|
68 | if (0 === replacements.length) {
|
69 | return escapeMarkdown(tweet.text);
|
70 | }
|
71 |
|
72 | let lastPos = text.length;
|
73 | const parts = replacements.sort((a, b) => b[1] - a[1]).map(replacement => {
|
74 | let output = [replacement[0]];
|
75 |
|
76 | if (replacement[2] < lastPos) {
|
77 | output.push(
|
78 | escapeMarkdownPart(
|
79 | text.substr(
|
80 | replacement[2],
|
81 | lastPos - replacement[2]
|
82 | )
|
83 | )
|
84 | );
|
85 | }
|
86 |
|
87 | lastPos = replacement[1];
|
88 |
|
89 | return output.join('');
|
90 | });
|
91 |
|
92 | if (lastPos > 0) {
|
93 | parts.push(
|
94 | escapeMarkdown(
|
95 | text.substr(0, lastPos)
|
96 | )
|
97 | );
|
98 | }
|
99 |
|
100 | return parts.reverse().join('');
|
101 | }
|