-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconvertMarkdownToRedditFlavor.ts
157 lines (142 loc) · 4.37 KB
/
convertMarkdownToRedditFlavor.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import iterator from "markdown-it-for-inline";
import lazyHeaders from "markdown-it-lazy-headers";
import MarkdownIt, { Options } from "markdown-it";
import { escapeHtml } from "markdown-it/lib/common/utils";
import Token from "markdown-it/lib/token";
import * as entities from "entities";
import { transformCss } from "./transformCss";
import Renderer from "markdown-it/lib/renderer";
export type MutatedToken = Token & { transformAttrs?: boolean };
const configuredMd = MarkdownIt({ xhtmlOut: true })
.use(lazyHeaders)
.use(iterator, "lazy-link", "text", lazyLinkTransform);
const defaultTdOpenRender =
configuredMd.renderer.rules.td_open ||
function (tokens, idx, options, env, self) {
return self.renderToken(tokens, idx, options);
};
const defaultThOpenRender =
configuredMd.renderer.rules.th_open ||
function (tokens, idx, options, env, self) {
return self.renderToken(tokens, idx, options);
};
const TdOpenHandler = function (
tokens: MutatedToken[],
idx: number,
options: Options,
env: any,
self: Renderer
) {
if (tokens[idx].attrs?.[0]) {
const flatAttrs = tokens[idx].attrs?.flat();
if (flatAttrs?.includes("style")) {
const newAttrs = tokens[idx].attrs?.reduce((acc: any, [key, value]) => {
if (key === "style") {
return [...acc, [key, transformCss(value)]];
}
return [...acc, [key, value]];
}, []);
tokens[idx].attrs = newAttrs;
tokens[idx].transformAttrs = true;
}
}
return defaultTdOpenRender(tokens, idx, options, env, self);
};
const ThOpenHandler = function (
tokens: MutatedToken[],
idx: number,
options: Options,
env: any,
self: Renderer
) {
if (tokens[idx].attrs?.[0]) {
const flatAttrs = tokens[idx].attrs?.flat();
if (flatAttrs?.includes("style")) {
const newAttrs = tokens[idx].attrs?.reduce((acc: any, [key, value]) => {
if (key === "style") {
return [...acc, [key, transformCss(value)]];
}
return [...acc, [key, value]];
}, []);
tokens[idx].attrs = newAttrs;
tokens[idx].transformAttrs = true;
}
}
return defaultThOpenRender(tokens, idx, options, env, self);
};
configuredMd.renderer.rules.td_open = TdOpenHandler;
configuredMd.renderer.rules.th_open = ThOpenHandler;
configuredMd.renderer.renderAttrs = function renderAttrs(token: MutatedToken) {
if (!token.attrs) {
return "";
}
let result = "";
for (let i = 0; i < token.attrs.length; i++) {
if (token.transformAttrs) {
result +=
" " +
escapeHtml(token.attrs[i][0]) +
"={" +
JSON.stringify(token.attrs[i][1]) +
"}";
} else {
result +=
" " +
escapeHtml(token.attrs[i][0]) +
'="' +
escapeHtml(token.attrs[i][1]) +
'"';
}
}
return result;
};
function lazyLinkTransform(): any {
return function (tokens: Token[], idx: number) {
// this whole block is 100% code smell but whatcha gonna do about it
if (/(?<=])\s+(?=\()/.test(tokens[idx].content) === true) {
const href = tokens[idx].content.match(/(?<=\().+(?=\))/)?.[0] ?? "";
const text = tokens[idx].content.match(/(?<=\[).+(?=\])/)?.[0] ?? "";
const closingToken = new Token("text", "", 0);
closingToken.content = text;
tokens.push(closingToken);
tokens[idx].type = "link_open";
tokens[idx].tag = "a";
tokens[idx].attrs = [["href", href]];
const anchorClose = new Token("link_close", "/a", 0);
anchorClose.content = "";
tokens.push(anchorClose);
}
};
}
function reducer(
acc: string,
token: MutatedToken,
i: number,
arr: MutatedToken[]
): string {
if (token.type === "softbreak") {
return acc + " ";
}
if (Array.isArray(token.children)) {
return acc + token.children.reduce(reducer, "");
}
if (/_close$/.test(token.type)) {
return acc;
} else {
return acc + entities.decodeHTML(token.content);
}
}
const configuredTextToContentRenderer = MarkdownIt({
xhtmlOut: true,
})
.use(lazyHeaders)
.use(iterator, "lazy-link", "text", lazyLinkTransform);
configuredTextToContentRenderer.renderer.render = function (tokens) {
return tokens.reduce(reducer, "");
};
export default function convertMarkdownToRedditFlavor(vanillaMarkdown: string) {
return {
convertedMarkdown: configuredMd.render(vanillaMarkdown),
textContent: configuredTextToContentRenderer.render(vanillaMarkdown),
};
}