1 import FuseJs from 'fuse.js'
2 import debounce from 'lodash.debounce'
3
4 class Fuse {
5 constructor() {
6 this.allItems = null
7 this.cliVersion = null
8 this.instances = new Map()
9 // [MKT]: I landed on the debouce wait value of 50 based mostly on
10 // experimentation. With both `leading` and `trailing` set to `true`, this
11 // feels pretty snappy.
12 //
13 // From https://lodash.com/docs/#debounce:
14 //
15 // > Note: If `leading` and `trailing` options are `true`, `func` is invoked
16 // > on the trailing edge of the timeout only if the debounced function is
17 // > invoked more than once during the wait timeout.
18 this.search = debounce(this.search, 50, {leading: true, trailing: true})
19 }
20
21 search(query) {
22 postMessage({
23 query,
24 results: this.instances
25 .get(this.cliVersion.current)
26 .search(query)
27 .slice(0, 20)
28 .map(i => i.item),
29 })
30 }
31
32 createInstance() {
33 if (!this.allItems || !this.cliVersion) {
34 return
35 }
36 const items = this.allItems.filter(item =>
37 item.path.startsWith(this.cliVersion.root) ? item.path.startsWith(this.cliVersion.current) : true,
38 )
39 this.instances.set(
40 this.cliVersion.current,
41 new FuseJs(items, {
42 threshold: 0.2,
43 ignoreLocation: true,
44 keys: ['title', 'headings', 'body'],
45 }),
46 )
47 }
48
49 setItems(items) {
50 this.allItems = items
51 this.createInstance()
52 }
53
54 setCliVersion({root, current}) {
55 this.cliVersion = {root, current}
56 if (this.instances.has(this.cliVersion.current)) {
57 return
58 }
59 this.createInstance()
60 }
61 }
62
63 const fuse = new Fuse()
64
65 onmessage = function ({data: {items, query, cli}}) {
66 if (items) {
67 fuse.setItems(items)
68 }
69
70 if (cli) {
71 fuse.setCliVersion(cli)
72 }
73
74 if (query) {
75 fuse.search(query)
76 }
77 }