Skip to content

Commit

Permalink
feat: support fuzzy search across all bookmarks 🥷
Browse files Browse the repository at this point in the history
  • Loading branch information
Avivbens committed Jun 8, 2024
1 parent 6139472 commit ec33acb
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 26 deletions.
16 changes: 15 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"test": "jest"
},
"dependencies": {
"fast-alfred": "^2.0.0"
"fast-alfred": "^2.0.0",
"fuse.js": "^7.0.0"
},
"devDependencies": {
"@commitlint/cli": "^18.4.3",
Expand Down
39 changes: 19 additions & 20 deletions src/main/bookmarks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { CACHE_BOOKMARKS_KEY, CACHE_TTL } from '@common/constants'
import { Variables } from '@common/variables'
import type { IUIBookmark } from '@models/bookmark.model'
import { getBookmarks } from '@services/fetch-bookmarks'
import { searchBookmarks } from '@services/search.service'

;(async () => {
const alfredClient = new FastAlfred()
Expand All @@ -13,27 +14,25 @@ import { getBookmarks } from '@services/fetch-bookmarks'

const profiles: string[] = profilesConfig.split(',')

const data: IUIBookmark[] =
alfredClient.cache.get<IUIBookmark[]>(CACHE_BOOKMARKS_KEY) ?? (await getBookmarks(profiles))

alfredClient.cache.setWithTTL(CACHE_BOOKMARKS_KEY, data, { maxAge: CACHE_TTL })

const items: AlfredScriptFilter['items'] = alfredClient
.inputMatches(
data.map(({ name, url, profile }) => ({ name, url, profile })),
({ name }) => name,
)
.map(({ name, url, profile }) => ({
title: name,
subtitle: `[${profile}] - ${url}`,
arg: JSON.stringify({ url, profile }),
mods: {
cmd: {
subtitle: `Open in Incognito Mode`,
arg: JSON.stringify({ url, profile, incognito: true }),
},
let bookmarks: IUIBookmark[] | null = alfredClient.cache.get<IUIBookmark[]>(CACHE_BOOKMARKS_KEY)
if (!bookmarks) {
bookmarks = await getBookmarks(profiles)
alfredClient.cache.setWithTTL(CACHE_BOOKMARKS_KEY, bookmarks, { maxAge: CACHE_TTL })
}

const filteredBookmarks = await searchBookmarks(bookmarks, alfredClient.input, sliceAmount)

const items: AlfredScriptFilter['items'] = filteredBookmarks.map(({ name, url, profile }) => ({
title: name,
subtitle: `[${profile}] - ${url}`,
arg: JSON.stringify({ url, profile }),
mods: {
cmd: {
subtitle: `Open in Incognito Mode`,
arg: JSON.stringify({ url, profile, incognito: true }),
},
}))
},
}))

const sliced = items.slice(0, sliceAmount)

Expand Down
7 changes: 3 additions & 4 deletions src/services/fetch-bookmarks.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { readFile } from 'fs/promises'
import { join } from 'path'
import type { IBookmark, IBookmarkRes, IUIBookmark } from '../models/bookmark.model'
import { Type } from '../models/bookmark.model'
import { readFile } from 'node:fs/promises'
import { join } from 'node:path'
import { type IBookmark, type IBookmarkRes, type IUIBookmark, Type } from '@models/bookmark.model'

const BOOKMARKS_PATH = (profiles: string[]): string[] =>
profiles.map((profileName) =>
Expand Down
4 changes: 4 additions & 0 deletions src/services/search.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import type { IUIBookmark } from '@models/bookmark.model'

type SearchField = keyof IUIBookmark
export const SEARCH_FIELDS_CONFIG: SearchField[] = ['name', 'url']
21 changes: 21 additions & 0 deletions src/services/search.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { IUIBookmark } from '@models/bookmark.model.js'
import { SEARCH_FIELDS_CONFIG } from './search.config.js'

export async function searchBookmarks(
bookmarks: IUIBookmark[],
searchTerm: string,
limit: number,
): Promise<IUIBookmark[]> {
const Fuse = (await import('fuse.js/min-basic')).default

const fuse = new Fuse(bookmarks, {
keys: SEARCH_FIELDS_CONFIG,
isCaseSensitive: false,
shouldSort: true,
threshold: 0.4,
})

const res = fuse.search(searchTerm, { limit })

return res.map((item) => item.item)
}

0 comments on commit ec33acb

Please sign in to comment.