Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

lunr-search.js 2.6 KB

You have to be logged in to leave a comment. Sign In
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
  1. const path = require('path')
  2. const lunr = require('lunr')
  3. const { get } = require('lodash')
  4. const readFileAsync = require('../readfile-async')
  5. const { namePrefix } = require('./config')
  6. const { decompress } = require('./compress')
  7. const LUNR_DIR = './indexes'
  8. const lunrIndexes = new Map()
  9. const lunrRecords = new Map()
  10. module.exports = async function loadLunrResults ({ version, language, query, limit }) {
  11. const indexName = `${namePrefix}-${version}-${language}`
  12. if (!lunrIndexes.has(indexName) || !lunrRecords.has(indexName)) {
  13. lunrIndexes.set(indexName, await loadLunrIndex(indexName))
  14. lunrRecords.set(indexName, await loadLunrRecords(indexName))
  15. }
  16. const results = lunrIndexes.get(indexName)
  17. .search(query)
  18. .slice(0, limit)
  19. .map((result) => {
  20. const record = lunrRecords.get(indexName)[result.ref]
  21. return {
  22. url: result.ref,
  23. breadcrumbs: field(result, record, 'breadcrumbs'),
  24. heading: field(result, record, 'heading'),
  25. title: field(result, record, 'title'),
  26. content: field(result, record, 'content'),
  27. // don't highlight the topics array
  28. topics: record.topics
  29. }
  30. })
  31. return results
  32. }
  33. async function loadLunrIndex (indexName) {
  34. const filePath = path.posix.join(__dirname, LUNR_DIR, `${indexName}.json.br`)
  35. // Do not set to 'utf8' on file reads
  36. return readFileAsync(filePath)
  37. .then(decompress)
  38. .then(JSON.parse)
  39. .then(lunr.Index.load)
  40. }
  41. async function loadLunrRecords (indexName) {
  42. const filePath = path.posix.join(__dirname, LUNR_DIR, `${indexName}-records.json.br`)
  43. // Do not set to 'utf8' on file reads
  44. return readFileAsync(filePath)
  45. .then(decompress)
  46. .then(JSON.parse)
  47. }
  48. // Highlight a match within an attribute field
  49. function field (result, record, name) {
  50. const text = record[name]
  51. if (!text) return text
  52. // First, get a list of all the positions of the matching tokens
  53. const positions = Object.values(result.matchData.metadata)
  54. .map(fields => get(fields, [name, 'position']))
  55. .filter(Boolean)
  56. .flat()
  57. .sort((a, b) => a[0] - b[0])
  58. .map(([start, length]) => [start, start + length])
  59. .map(([start, end], i, a) => [i && a[i - 1][1], start, end])
  60. // If this field has no token matches, no highlighting
  61. if (!positions.length) return text
  62. // Highlight the text
  63. return positions
  64. .map(([prev, start, end], i) => [
  65. text.slice(prev, start),
  66. mark(text.slice(start, end)),
  67. i === positions.length - 1 && text.slice(end)
  68. ])
  69. .flat()
  70. .filter(Boolean)
  71. .join('')
  72. }
  73. function mark (text) {
  74. return `<mark>${text}</mark>`
  75. }
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...