Repository navigation
Expand file tree
/
Copy pathmarkdown.ts
More file actions
112 lines (92 loc) · 3.01 KB
/
Copy pathmarkdown.ts
File metadata and controls
112 lines (92 loc) · 3.01 KB
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
import marked from 'marked';
import hljs from 'highlight.js';
import { current } from './versions';
import { apiMap } from './components/docs-menu/docs-api-map';
const components = apiMap[current] || [];
export interface HeadingStruc {
text: string;
level: number;
anchorId: string;
}
export interface MarkedStruc {
headings: HeadingStruc[];
body: string;
}
export const toCodeBlock = (code: string, lang = '') =>
`<code-block language="${lang}">${hljs.highlightAuto(code, [lang]).value}</code-block>`;
const toPreviewBlock = (code: string, lang = '', options: RenderOptions = {}) => `
<tab-group tabs="markup preview" initial="${options.initialTab || ''}">
<code-block slot="markup" language="${lang}">${hljs.highlightAuto(code, [lang]).value}</code-block>
<code-preview slot="preview" markup="${escape(code)}" inline="${!!options.inlineHtmlPreviews}"></code-preview>
</tab-group>
`;
const generateHeadingID = (inText: string) => {
let text = inText;
text = text.toLowerCase()
.replace(/&#?[a-z0-9]+;/i, '')
.replace(/([a-z\xE0-\xFF])([A-Z\xC0\xDF])/g, '$1 $2')
.replace(/[^0-9a-zA-Z\xC0-\xFF \-]/g, '')
.replace(/ +/g, '-');
return text;
};
interface RenderOptions {
disableHtmlPreviews?: boolean;
initialTab?: string;
inlineHtmlPreviews?: boolean;
}
export function renderMarkdown(markdown: string, options: RenderOptions): MarkedStruc {
const renderer = new marked.Renderer();
const headings: HeadingStruc[] = [];
renderer.image = (href = '', title) => `
<img-zoom>
<img src="${href}" ${title && `title="${title}"`} />
</img-zoom>
`;
renderer.heading = (text: string, level: number) => {
const hasNestedTags = /<.+>(.+)<\/.+>/.test(text);
if (level > 3 || hasNestedTags) {
return `<h${level}>${text}</h${level}>`;
}
const anchorId = generateHeadingID(text);
headings.push({ text, level, anchorId });
return `
<h${level} id="${anchorId}">
<a href="#${anchorId}" class="linked">${text}</a>
</h${level}>
`;
};
renderer.code = (code: string, lang: string) => {
if (lang === 'html' && options.disableHtmlPreviews !== true) {
return toPreviewBlock(code, lang, options);
}
return toCodeBlock(code, lang);
};
renderer.codespan = code => {
// quick out if not an ionic component or menu is empty
if (code.indexOf('ion-') !== -1) {
// link to ionic component if possible
const converted = code.replace(/([a-zA-Z])(?=[A-Z])/g, '$1-')
.toLowerCase()
.replace('ion-', '');
if (components[converted]) {
code = `<a href="${components[converted]}" class="auto-link">${code}</a>`;
}
}
return `<code>${code}</code>`;
};
renderer.table = (thead: string, tbody: string) =>
`<div class="table-wrap">
<table>
<thead>
${thead}
</thead>
<tbody>
${tbody}
</tbody>
</table>
</div>`;
return {
headings,
body: marked(markdown, { renderer })
};
}