forked from leo-buneev/vuepress-plugin-fulltext-search
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
126 lines (111 loc) · 3.93 KB
/
index.js
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
const { path } = require('@vuepress/shared-utils')
const { htmlToText } = require('html-to-text')
const _ = require('lodash')
let customTitles = null
module.exports = (options, ctx, globalCtx) => ({
extendPageData($page) {
try {
const { html } = $page._context.markdown.render($page._strippedContent || '')
if (!customTitles) customTitles = getCustomTitles(globalCtx)
const plaintext = htmlToText(html, {
wordwrap: null,
hideLinkHrefIfSameAsText: true,
ignoreImage: true,
ignoreHref: true,
uppercaseHeadings: false,
tables: true,
})
for (const h of $page.headers || []) {
const titlePlaintext = $page._context.markdown.renderInline(h.title)
h.normalizedTitle = normalizeText(titlePlaintext)
h.charIndex = plaintext.indexOf(titlePlaintext)
if (h.charIndex === -1) h.charIndex = null
}
$page.headersStr = $page.headers ? $page.headers.map(h => h.title).join(' ') : null
$page.content = plaintext
$page.normalizedContent = normalizeText(plaintext)
$page.charsets = getCharsets(plaintext)
// Take title from sidebar if it's missing on the page itself
if (!$page.title) $page.title = customTitles[normalizePath($page.path)]
} catch (e) {
// incorrect markdown
console.error('Error when applying fulltext-search plugin:', e)
}
},
alias: {
'@SearchBox': path.resolve(__dirname, 'components/SearchBox.vue'),
},
clientDynamicModules() {
return {
name: 'hooks.js',
content: options.hooks || 'export default {}',
}
},
define() {
return {
OPTIONS: options,
}
},
})
function normalizeText(text) {
return text
.toLowerCase()
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '')
}
function getCustomTitles(globalCtx) {
try {
const sidebarConfig = _.get(globalCtx, '_pluginContext.themeConfig.sidebar')
if (!sidebarConfig) return {}
let sidebars = [sidebarConfig]
if (_.isPlainObject(sidebarConfig)) sidebars = _.values(sidebarConfig)
sidebars = sidebars.filter(sb => _.isArray(sb))
const result = {}
for (const sb of sidebars) {
for (const page of sb) {
if (_.isArray(page)) {
const [pathWithExtension, title] = page
const normalizedPath = normalizePath(pathWithExtension)
if (normalizedPath && title) result[normalizedPath] = title
continue
}
if (!_.isObjectLike(page)) continue
if (page.path && page.title) {
const normalizedPath = normalizePath(page.path)
if (normalizedPath) result[normalizedPath] = page.title
}
if (page.children) {
for (const c of page.children) {
if (_.isArray(c)) {
const [pathWithExtension, title] = c
const normalizedPath = normalizePath(pathWithExtension)
if (normalizedPath && title) result[normalizedPath] = title
}
}
}
}
}
return result
} catch (e) {
console.error('[fulltext-search] Error while getting sidebar paths:', e)
return {}
}
}
function normalizePath(rawPath) {
if (!rawPath) return null
try {
const parsedPath = path.parse(rawPath)
return path.join(parsedPath.dir, parsedPath.name)
} catch (e) {
console.error(`[fulltext-search] Error while normalizing path ${rawPath}:`, e)
return null
}
}
function getCharsets(text) {
const cyrillicRegex = /[\u0400-\u04FF]/iu
const cjkRegex = /[\u3131-\u314e|\u314f-\u3163|\uac00-\ud7a3]|[\u4E00-\u9FCC\u3400-\u4DB5\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\ud840-\ud868][\udc00-\udfff]|\ud869[\udc00-\uded6\udf00-\udfff]|[\ud86a-\ud86c][\udc00-\udfff]|\ud86d[\udc00-\udf34\udf40-\udfff]|\ud86e[\udc00-\udc1d]|[\u3041-\u3096]|[\u30A1-\u30FA]/iu
const result = {}
if (cyrillicRegex.test(text)) result.cyrillic = true
if (cjkRegex.test(text)) result.cjk = true
return result
}