(searchUrl, queryTerms)
| 93 | // engine's URL. This is only used as a key for determining the relevant completion engine. |
| 94 | // - queryTerms are the query terms. |
| 95 | export async function complete(searchUrl, queryTerms) { |
| 96 | const query = queryTerms.join(" ").toLowerCase(); |
| 97 | |
| 98 | // We don't complete queries which are too short: the results are usually useless. |
| 99 | if (query.length < 4) return []; |
| 100 | |
| 101 | // We don't complete regular URLs or Javascript URLs. |
| 102 | if (queryTerms.length == 1 && await UrlUtils.isUrl(query)) return []; |
| 103 | if (UrlUtils.hasJavascriptProtocol(query)) return []; |
| 104 | |
| 105 | const engine = lookupEngine(searchUrl); |
| 106 | if (!engine) return []; |
| 107 | |
| 108 | const completionCacheKey = JSON.stringify([searchUrl, queryTerms]); |
| 109 | if (completionCache.has(completionCacheKey)) { |
| 110 | if (debug) console.log("hit", completionCacheKey); |
| 111 | return completionCache.get(completionCacheKey); |
| 112 | } |
| 113 | |
| 114 | const createTimeoutPromise = (ms) => { |
| 115 | return new Promise((resolve) => { |
| 116 | setTimeout(() => { |
| 117 | resolve(); |
| 118 | }, ms); |
| 119 | }); |
| 120 | }; |
| 121 | |
| 122 | requestId++; |
| 123 | const lastRequestId = requestId; |
| 124 | |
| 125 | // We delay sending a completion request in case the user is still typing. |
| 126 | await createTimeoutPromise(DELAY); |
| 127 | |
| 128 | // If the user has issued a new query while we were waiting, then this query is old; abort it. |
| 129 | if (lastRequestId != requestId) return []; |
| 130 | |
| 131 | const engineWrapper = new EnginePrefixWrapper(searchUrl, engine); |
| 132 | const url = engineWrapper.getUrl(queryTerms); |
| 133 | |
| 134 | if (debug) console.log("GET", url); |
| 135 | const responseText = await get(url); |
| 136 | |
| 137 | // Parsing the response may fail if we receive an unexpectedly-formatted response. In all cases, |
| 138 | // we fall back to the catch clause, below. Therefore, we "fail safe" in the case of incorrect |
| 139 | // or out-of-date completion engine implementations. |
| 140 | let suggestions = []; |
| 141 | let isError = responseText == null; |
| 142 | if (!isError) { |
| 143 | try { |
| 144 | suggestions = engineWrapper.parse(responseText) |
| 145 | // Make all suggestions lower case. It looks odd when suggestions from one |
| 146 | // completion engine are upper case, and those from another are lower case. |
| 147 | .map((s) => s.toLowerCase()) |
| 148 | // Filter out the query itself. It's not adding anything. |
| 149 | .filter((s) => s !== query); |
| 150 | } catch (error) { |
| 151 | if (debug) console.log("error:", error); |
| 152 | isError = true; |
nothing calls this directly
no test coverage detected