diff options
Diffstat (limited to 'src/background/completion')
-rw-r--r-- | src/background/completion/BookmarkRepository.ts | 6 | ||||
-rw-r--r-- | src/background/completion/HistoryRepository.ts | 6 | ||||
-rw-r--r-- | src/background/completion/OpenCompletionUseCase.ts | 48 | ||||
-rw-r--r-- | src/background/completion/PropertyCompletionUseCase.ts | 8 | ||||
-rw-r--r-- | src/background/completion/TabCompletionUseCase.ts | 27 | ||||
-rw-r--r-- | src/background/completion/TabItem.ts | 14 | ||||
-rw-r--r-- | src/background/completion/TabRepository.ts | 16 | ||||
-rw-r--r-- | src/background/completion/impl/BookmarkRepositoryImpl.ts | 29 | ||||
-rw-r--r-- | src/background/completion/impl/HistoryRepositoryImpl.ts | 49 | ||||
-rw-r--r-- | src/background/completion/impl/PrefetchAndCache.ts | 37 | ||||
-rw-r--r-- | src/background/completion/impl/TabRepositoryImpl.ts | 27 | ||||
-rw-r--r-- | src/background/completion/impl/filters.ts | 45 |
12 files changed, 172 insertions, 140 deletions
diff --git a/src/background/completion/BookmarkRepository.ts b/src/background/completion/BookmarkRepository.ts index 14105c8..4dec12e 100644 --- a/src/background/completion/BookmarkRepository.ts +++ b/src/background/completion/BookmarkRepository.ts @@ -1,7 +1,7 @@ export type BookmarkItem = { - title: string - url: string -} + title: string; + url: string; +}; export default interface BookmarkRepository { queryBookmarks(query: string): Promise<BookmarkItem[]>; diff --git a/src/background/completion/HistoryRepository.ts b/src/background/completion/HistoryRepository.ts index 5eb3a2b..446d110 100644 --- a/src/background/completion/HistoryRepository.ts +++ b/src/background/completion/HistoryRepository.ts @@ -1,7 +1,7 @@ export type HistoryItem = { - title: string - url: string -} + title: string; + url: string; +}; export default interface HistoryRepository { queryHistories(keywords: string): Promise<HistoryItem[]>; diff --git a/src/background/completion/OpenCompletionUseCase.ts b/src/background/completion/OpenCompletionUseCase.ts index 1b63e7c..e678c2f 100644 --- a/src/background/completion/OpenCompletionUseCase.ts +++ b/src/background/completion/OpenCompletionUseCase.ts @@ -5,38 +5,39 @@ import BookmarkRepository from "./BookmarkRepository"; import HistoryRepository from "./HistoryRepository"; export type BookmarkItem = { - title: string - url: string -} + title: string; + url: string; +}; export type HistoryItem = { - title: string - url: string -} + title: string; + url: string; +}; @injectable() export default class OpenCompletionUseCase { constructor( - @inject('BookmarkRepository') private bookmarkRepository: BookmarkRepository, - @inject('HistoryRepository') private historyRepository: HistoryRepository, - @inject("CachedSettingRepository") private cachedSettingRepository: CachedSettingRepository, - ) { - } + @inject("BookmarkRepository") + private bookmarkRepository: BookmarkRepository, + @inject("HistoryRepository") private historyRepository: HistoryRepository, + @inject("CachedSettingRepository") + private cachedSettingRepository: CachedSettingRepository + ) {} async getCompletionTypes(): Promise<CompletionType[]> { const settings = await this.cachedSettingRepository.get(); const types: CompletionType[] = []; for (const c of settings.properties.complete) { switch (c) { - case 's': - types.push(CompletionType.SearchEngines); - break; - case 'h': - types.push(CompletionType.History); - break; - case 'b': - types.push(CompletionType.Bookmarks); - break; + case "s": + types.push(CompletionType.SearchEngines); + break; + case "h": + types.push(CompletionType.History); + break; + case "b": + types.push(CompletionType.Bookmarks); + break; } // ignore invalid characters in the complete property } @@ -45,8 +46,9 @@ export default class OpenCompletionUseCase { async requestSearchEngines(query: string): Promise<string[]> { const settings = await this.cachedSettingRepository.get(); - return Object.keys(settings.search.engines) - .filter(key => key.startsWith(query)) + return Object.keys(settings.search.engines).filter((key) => + key.startsWith(query) + ); } requestBookmarks(query: string): Promise<BookmarkItem[]> { @@ -56,4 +58,4 @@ export default class OpenCompletionUseCase { requestHistory(query: string): Promise<HistoryItem[]> { return this.historyRepository.queryHistories(query); } -}
\ No newline at end of file +} diff --git a/src/background/completion/PropertyCompletionUseCase.ts b/src/background/completion/PropertyCompletionUseCase.ts index 049cfb8..7b72259 100644 --- a/src/background/completion/PropertyCompletionUseCase.ts +++ b/src/background/completion/PropertyCompletionUseCase.ts @@ -3,14 +3,14 @@ import Properties from "../../shared/settings/Properties"; type Property = { name: string; - type: 'string' | 'boolean' | 'number'; -} + type: "string" | "boolean" | "number"; +}; @injectable() export default class PropertyCompletionUseCase { async getProperties(): Promise<Property[]> { - return Properties.defs().map(def => ({ + return Properties.defs().map((def) => ({ name: def.name, type: def.type, })); } -}
\ No newline at end of file +} diff --git a/src/background/completion/TabCompletionUseCase.ts b/src/background/completion/TabCompletionUseCase.ts index dec86e9..d0d3bb7 100644 --- a/src/background/completion/TabCompletionUseCase.ts +++ b/src/background/completion/TabCompletionUseCase.ts @@ -7,10 +7,9 @@ import TabFlag from "../../shared/TabFlag"; @injectable() export default class TabCompletionUseCase { constructor( - @inject('TabRepository') private tabRepository: TabRepository, - @inject('TabPresenter') private tabPresenter: TabPresenter, - ) { - } + @inject("TabRepository") private tabRepository: TabRepository, + @inject("TabPresenter") private tabPresenter: TabPresenter + ) {} async queryTabs(query: string, excludePinned: boolean): Promise<TabItem[]> { const lastTabId = await this.tabPresenter.getLastSelectedId(); @@ -18,17 +17,17 @@ export default class TabCompletionUseCase { const num = parseInt(query, 10); let tabs: Tab[] = []; if (!isNaN(num)) { - const tab = allTabs.find(t => t.index === num - 1); + const tab = allTabs.find((t) => t.index === num - 1); if (tab) { tabs = [tab]; } - } else if (query == '%') { - const tab = allTabs.find(t => t.active); + } else if (query == "%") { + const tab = allTabs.find((t) => t.active); if (tab) { tabs = [tab]; } - } else if (query == '#') { - const tab = allTabs.find(t => t.id === lastTabId); + } else if (query == "#") { + const tab = allTabs.find((t) => t.id === lastTabId); if (tab) { tabs = [tab]; } @@ -36,20 +35,20 @@ export default class TabCompletionUseCase { tabs = await this.tabRepository.queryTabs(query, excludePinned); } - return tabs.map(tab => { + return tabs.map((tab) => { let flag = TabFlag.None; if (tab.active) { - flag = TabFlag.CurrentTab + flag = TabFlag.CurrentTab; } else if (tab.id == lastTabId) { - flag = TabFlag.LastTab + flag = TabFlag.LastTab; } return { index: tab.index + 1, flag: flag, title: tab.title, url: tab.url, - faviconUrl : tab.faviconUrl - } + faviconUrl: tab.faviconUrl, + }; }); } } diff --git a/src/background/completion/TabItem.ts b/src/background/completion/TabItem.ts index 630855a..eb7b657 100644 --- a/src/background/completion/TabItem.ts +++ b/src/background/completion/TabItem.ts @@ -1,11 +1,11 @@ import TabFlag from "../../shared/TabFlag"; type TabItem = { - index: number - flag: TabFlag - title: string - url: string - faviconUrl?: string -} + index: number; + flag: TabFlag; + title: string; + url: string; + faviconUrl?: string; +}; -export default TabItem;
\ No newline at end of file +export default TabItem; diff --git a/src/background/completion/TabRepository.ts b/src/background/completion/TabRepository.ts index fe1b601..57dbf21 100644 --- a/src/background/completion/TabRepository.ts +++ b/src/background/completion/TabRepository.ts @@ -1,14 +1,14 @@ export type Tab = { - id: number - index: number - active: boolean - title: string - url: string - faviconUrl?: string -} + id: number; + index: number; + active: boolean; + title: string; + url: string; + faviconUrl?: string; +}; export default interface TabRepository { queryTabs(query: string, excludePinned: boolean): Promise<Tab[]>; - getAllTabs(excludePinned: boolean): Promise<Tab[]> + getAllTabs(excludePinned: boolean): Promise<Tab[]>; } diff --git a/src/background/completion/impl/BookmarkRepositoryImpl.ts b/src/background/completion/impl/BookmarkRepositoryImpl.ts index 3b80b93..2bc779d 100644 --- a/src/background/completion/impl/BookmarkRepositoryImpl.ts +++ b/src/background/completion/impl/BookmarkRepositoryImpl.ts @@ -1,5 +1,5 @@ -import BookmarkRepository, {BookmarkItem} from "../BookmarkRepository"; -import {HistoryItem} from "../HistoryRepository"; +import BookmarkRepository, { BookmarkItem } from "../BookmarkRepository"; +import { HistoryItem } from "../HistoryRepository"; import PrefetchAndCache from "./PrefetchAndCache"; const COMPLETION_ITEM_LIMIT = 10; @@ -8,7 +8,7 @@ export default class CachedBookmarkRepository implements BookmarkRepository { private bookmarkCache: PrefetchAndCache<BookmarkItem>; constructor() { - this.bookmarkCache = new PrefetchAndCache(this.getter, this.filter, 10,); + this.bookmarkCache = new PrefetchAndCache(this.getter, this.filter, 10); } queryBookmarks(query: string): Promise<BookmarkItem[]> { @@ -16,10 +16,10 @@ export default class CachedBookmarkRepository implements BookmarkRepository { } private async getter(query: string): Promise<BookmarkItem[]> { - const items = await browser.bookmarks.search({query}); + const items = await browser.bookmarks.search({ query }); return items - .filter(item => item.title && item.title.length > 0) - .filter(item => item.type === 'bookmark' && item.url) + .filter((item) => item.title && item.title.length > 0) + .filter((item) => item.type === "bookmark" && item.url) .filter((item) => { let url = undefined; try { @@ -27,20 +27,23 @@ export default class CachedBookmarkRepository implements BookmarkRepository { } catch (e) { return false; } - return url.protocol !== 'place:'; + return url.protocol !== "place:"; }) .slice(0, COMPLETION_ITEM_LIMIT) - .map(item => ({ + .map((item) => ({ title: item.title!!, url: item.url!!, })); } private filter(items: HistoryItem[], query: string) { - return items.filter(item => { - return query.split(' ').every(keyword => { - return item.title.toLowerCase().includes(keyword.toLowerCase()) || item.url!!.includes(keyword) + return items.filter((item) => { + return query.split(" ").every((keyword) => { + return ( + item.title.toLowerCase().includes(keyword.toLowerCase()) || + item.url!!.includes(keyword) + ); }); - }) - }; + }); + } } diff --git a/src/background/completion/impl/HistoryRepositoryImpl.ts b/src/background/completion/impl/HistoryRepositoryImpl.ts index cd55cd0..b1992a4 100644 --- a/src/background/completion/impl/HistoryRepositoryImpl.ts +++ b/src/background/completion/impl/HistoryRepositoryImpl.ts @@ -1,5 +1,5 @@ import * as filters from "./filters"; -import HistoryRepository, {HistoryItem} from "../HistoryRepository"; +import HistoryRepository, { HistoryItem } from "../HistoryRepository"; import PrefetchAndCache from "./PrefetchAndCache"; const COMPLETION_ITEM_LIMIT = 10; @@ -8,13 +8,17 @@ export default class CachedHistoryRepository implements HistoryRepository { private historyCache: PrefetchAndCache<browser.history.HistoryItem>; constructor() { - this.historyCache = new PrefetchAndCache(this.getter, this.filter, 10) + this.historyCache = new PrefetchAndCache(this.getter, this.filter, 10); } async queryHistories(keywords: string): Promise<HistoryItem[]> { const items = await this.historyCache.get(keywords); - const filterOrKeep = <T>(source: T[], filter: (items: T[]) => T[], min: number): T[] => { + const filterOrKeep = <T>( + source: T[], + filter: (items: T[]) => T[], + min: number + ): T[] => { const filtered = filter(source); if (filtered.length < min) { return source; @@ -23,17 +27,23 @@ export default class CachedHistoryRepository implements HistoryRepository { }; return [items] - .map(items => filterOrKeep(items, filters.filterByPathname, COMPLETION_ITEM_LIMIT)) - .map(items => filterOrKeep(items, filters.filterByOrigin, COMPLETION_ITEM_LIMIT))[0] - .sort((x, y) => Number(y.visitCount) - Number(x.visitCount)) - .slice(0, COMPLETION_ITEM_LIMIT) - .map(item => ({ - title: item.title!!, - url: item.url!!, - })); + .map((items) => + filterOrKeep(items, filters.filterByPathname, COMPLETION_ITEM_LIMIT) + ) + .map((items) => + filterOrKeep(items, filters.filterByOrigin, COMPLETION_ITEM_LIMIT) + )[0] + .sort((x, y) => Number(y.visitCount) - Number(x.visitCount)) + .slice(0, COMPLETION_ITEM_LIMIT) + .map((item) => ({ + title: item.title!!, + url: item.url!!, + })); } - private async getter (keywords: string): Promise<browser.history.HistoryItem[]> { + private async getter( + keywords: string + ): Promise<browser.history.HistoryItem[]> { const items = await browser.history.search({ text: keywords, startTime: 0, @@ -42,14 +52,17 @@ export default class CachedHistoryRepository implements HistoryRepository { return [items] .map(filters.filterBlankTitle) .map(filters.filterHttp) - .map(filters.filterByTailingSlash)[0] + .map(filters.filterByTailingSlash)[0]; } private filter(items: browser.history.HistoryItem[], query: string) { - return items.filter(item => { - return query.split(' ').every(keyword => { - return item.title!!.toLowerCase().includes(keyword.toLowerCase()) || item.url!!.includes(keyword) + return items.filter((item) => { + return query.split(" ").every((keyword) => { + return ( + item.title!!.toLowerCase().includes(keyword.toLowerCase()) || + item.url!!.includes(keyword) + ); }); - }) - }; + }); + } } diff --git a/src/background/completion/impl/PrefetchAndCache.ts b/src/background/completion/impl/PrefetchAndCache.ts index 3c074c2..d2889b0 100644 --- a/src/background/completion/impl/PrefetchAndCache.ts +++ b/src/background/completion/impl/PrefetchAndCache.ts @@ -5,14 +5,14 @@ const WHITESPACE = /\s/; // `shortKey` returns a shorten key to pre-fetch completions and store in the // cache. The shorten key is generated by the following rules: -// +// // 1. If the query contains a space in the middle: i.e. the query consists of // multiple words, the method removes the last word from the query, and // returns joined remaining words with space. -// +// // 2. If the query is a single word and it's an URL, the method returns a new // URL excluding search query with the upper path of the original URL. -// +// // 3. If the query is a single word and it's not an URL, the method returns a // word with the half-length of the original query. // @@ -29,11 +29,15 @@ const WHITESPACE = /\s/; // export const shortKey = (query: string): string => { if (WHITESPACE.test(query)) { - return query.split(WHITESPACE).filter(word => word.length > 0).slice(0, -1).join(' '); + return query + .split(WHITESPACE) + .filter((word) => word.length > 0) + .slice(0, -1) + .join(" "); } let url; try { - url = new URL(query) + url = new URL(query); } catch (e) { return query.slice(0, query.length / 2); } @@ -42,12 +46,12 @@ export const shortKey = (query: string): string => { // may be on typing or removing URLs such as "such as https://goog" return query.slice(0, query.length / 2); } - if (url.pathname.endsWith('/')) { + if (url.pathname.endsWith("/")) { // remove parameters and move to upper path - return new URL('..', url).href; + return new URL("..", url).href; } // remove parameters - return new URL('.', url).href; + return new URL(".", url).href; }; export default class PrefetchAndCache<T> { @@ -58,9 +62,8 @@ export default class PrefetchAndCache<T> { constructor( private getter: Getter<T>, private filter: Filter<T>, - private prefetchThrethold: number = 1, - ) { - } + private prefetchThrethold: number = 1 + ) {} async get(query: string): Promise<T[]> { query = query.trim(); @@ -79,7 +82,7 @@ export default class PrefetchAndCache<T> { private needToRefresh(query: string): boolean { if (!this.shortKey) { // no cache - return true + return true; } if (query.length < this.shortKey.length) { @@ -89,17 +92,17 @@ export default class PrefetchAndCache<T> { } if (!query.startsWith(this.shortKey)) { - // queyr: "hello_w" - // shorten: "hello_morning" - return true + // queyr: "hello_w" + // shorten: "hello_morning" + return true; } - if (query.slice(this.shortKey.length).includes(' ')) { + if (query.slice(this.shortKey.length).includes(" ")) { // queyr: "hello x" // shorten: "hello" return true; } - return false + return false; } } diff --git a/src/background/completion/impl/TabRepositoryImpl.ts b/src/background/completion/impl/TabRepositoryImpl.ts index adcaba7..d16d4c3 100644 --- a/src/background/completion/impl/TabRepositoryImpl.ts +++ b/src/background/completion/impl/TabRepositoryImpl.ts @@ -7,28 +7,31 @@ export default class TabRepositoryImpl implements TabRepository { const tabs = await browser.tabs.query({ currentWindow: true }); return tabs .filter((t) => { - return t.url && t.url.toLowerCase().includes(query.toLowerCase()) || - t.title && t.title.toLowerCase().includes(query.toLowerCase()); + return ( + (t.url && t.url.toLowerCase().includes(query.toLowerCase())) || + (t.title && t.title.toLowerCase().includes(query.toLowerCase())) + ); }) .filter((t) => { return !(excludePinned && t.pinned); }) - .filter(item => item.id && item.title && item.url) + .filter((item) => item.id && item.title && item.url) .slice(0, COMPLETION_ITEM_LIMIT) .map(TabRepositoryImpl.toEntity); } async getAllTabs(excludePinned: boolean): Promise<Tab[]> { - if (excludePinned) { - return (await browser.tabs.query({ currentWindow: true, pinned: true })) - .map(TabRepositoryImpl.toEntity) - - } - return (await browser.tabs.query({ currentWindow: true })) - .map(TabRepositoryImpl.toEntity) + if (excludePinned) { + return ( + await browser.tabs.query({ currentWindow: true, pinned: true }) + ).map(TabRepositoryImpl.toEntity); + } + return (await browser.tabs.query({ currentWindow: true })).map( + TabRepositoryImpl.toEntity + ); } - private static toEntity(tab: browser.tabs.Tab,): Tab { + private static toEntity(tab: browser.tabs.Tab): Tab { return { id: tab.id!!, url: tab.url!!, @@ -36,6 +39,6 @@ export default class TabRepositoryImpl implements TabRepository { title: tab.title!!, faviconUrl: tab.favIconUrl, index: tab.index, - } + }; } } diff --git a/src/background/completion/impl/filters.ts b/src/background/completion/impl/filters.ts index 3aa56e4..523491d 100644 --- a/src/background/completion/impl/filters.ts +++ b/src/background/completion/impl/filters.ts @@ -1,32 +1,36 @@ type Item = browser.history.HistoryItem; const filterHttp = (items: Item[]): Item[] => { - const httpsHosts = items.map(x => new URL(x.url as string)) - .filter(x => x.protocol === 'https:') - .map(x => x.host); + const httpsHosts = items + .map((x) => new URL(x.url as string)) + .filter((x) => x.protocol === "https:") + .map((x) => x.host); const hostsSet = new Set(httpsHosts); return items.filter((item: Item) => { const url = new URL(item.url as string); - return url.protocol === 'https:' || !hostsSet.has(url.host); + return url.protocol === "https:" || !hostsSet.has(url.host); }); }; const filterBlankTitle = (items: Item[]): Item[] => { - return items.filter(item => item.title && item.title !== ''); + return items.filter((item) => item.title && item.title !== ""); }; const filterByTailingSlash = (items: Item[]): Item[] => { - const urls = items.map(item => new URL(item.url as string)); + const urls = items.map((item) => new URL(item.url as string)); const simplePaths = urls - .filter(url => url.hash === '' && url.search === '') - .map(url => url.origin + url.pathname); + .filter((url) => url.hash === "" && url.search === "") + .map((url) => url.origin + url.pathname); const pathsSet = new Set(simplePaths); return items.filter((item) => { const url = new URL(item.url as string); - if (url.hash !== '' || url.search !== '' || - url.pathname.slice(-1) !== '/') { + if ( + url.hash !== "" || + url.search !== "" || + url.pathname.slice(-1) !== "/" + ) { return true; } return !pathsSet.has(url.origin + url.pathname.slice(0, -1)); @@ -34,14 +38,15 @@ const filterByTailingSlash = (items: Item[]): Item[] => { }; const filterByPathname = (items: Item[]): Item[] => { - const hash: {[key: string]: Item} = {}; + const hash: { [key: string]: Item } = {}; for (const item of items) { const url = new URL(item.url as string); const pathname = url.origin + url.pathname; if (!hash[pathname]) { hash[pathname] = item; - } else if ((hash[pathname].url as string).length > - (item.url as string).length) { + } else if ( + (hash[pathname].url as string).length > (item.url as string).length + ) { hash[pathname] = item; } } @@ -49,13 +54,14 @@ const filterByPathname = (items: Item[]): Item[] => { }; const filterByOrigin = (items: Item[]): Item[] => { - const hash: {[key: string]: Item} = {}; + const hash: { [key: string]: Item } = {}; for (const item of items) { const origin = new URL(item.url as string).origin; if (!hash[origin]) { hash[origin] = item; - } else if ((hash[origin].url as string).length > - (item.url as string).length) { + } else if ( + (hash[origin].url as string).length > (item.url as string).length + ) { hash[origin] = item; } } @@ -63,6 +69,9 @@ const filterByOrigin = (items: Item[]): Item[] => { }; export { - filterHttp, filterBlankTitle, filterByTailingSlash, - filterByPathname, filterByOrigin + filterHttp, + filterBlankTitle, + filterByTailingSlash, + filterByPathname, + filterByOrigin, }; |