-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathheading.ts
More file actions
64 lines (53 loc) · 1.69 KB
/
Copy pathheading.ts
File metadata and controls
64 lines (53 loc) · 1.69 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
const MARKDOWN_IMAGE_REGEX = /!\[([^\]]*)\]\([^)]*\)/g;
const MARKDOWN_LINK_REGEX = /\[([^\]]+)\]\([^)]*\)/g;
const INLINE_CODE_REGEX = /(`+)([^`]*?)\1/g;
const HTML_TAG_REGEX = /<\/?[A-Za-z][^>]*>/g;
const ESCAPED_CHARACTER_REGEX = /\\([\\`*_[\]{}()#+\-.!<>|])/g;
const TRAILING_HEADING_MARKER_REGEX = /\s+#+\s*$/;
export function normalizeHeadingText(text: string): string {
let normalizedText = text.trim();
if (!normalizedText) {
return '';
}
normalizedText = normalizedText
.replace(MARKDOWN_IMAGE_REGEX, '$1')
.replace(MARKDOWN_LINK_REGEX, '$1')
.replace(INLINE_CODE_REGEX, '$2')
.replace(HTML_TAG_REGEX, '')
.replace(TRAILING_HEADING_MARKER_REGEX, '');
let previousText: string | null = null;
while (normalizedText !== previousText) {
previousText = normalizedText;
normalizedText = normalizedText
.replace(/(\*\*|__)(.*?)\1/g, '$2')
.replace(/(\*|_)(.*?)\1/g, '$2')
.replace(/~~(.*?)~~/g, '$1');
}
return normalizedText
.replace(ESCAPED_CHARACTER_REGEX, '$1')
.replace(/\s+/g, ' ')
.trim();
}
function buildHeadingSlug(text: string): string {
return normalizeHeadingText(text)
.toLowerCase()
.replace(
/[^\w\uAC00-\uD7AF\u1100-\u11FF\u3130-\u318F\uA960-\uA97F\uD7B0-\uD7FF\s-]/g,
''
)
.trim()
.replace(/\s+/g, '-')
.replace(/-+/g, '-');
}
export function createHeadingIdGenerator() {
const idCounts: Record<string, number> = {};
return (text: string): string | null => {
const baseId = buildHeadingSlug(text);
if (!baseId) {
return null;
}
const count = idCounts[baseId] ?? 0;
idCounts[baseId] = count + 1;
return count === 0 ? baseId : `${baseId}-${count}`;
};
}